Quoting Chen-Yu Tsai (2014-02-10 02:35:47)
The Allwinner A20/A31 clock module controls the transmit clock source
and interface type of the GMAC ethernet controller. Model this as
a single clock for GMAC drivers to use.
Signed-off-by: Chen-Yu Tsai w...@csie.org
Looks good to me.
Regards,
Mike
---
Documentation/devicetree/bindings/clock/sunxi.txt | 30 +++
drivers/clk/sunxi/clk-sunxi.c | 97
+++
2 files changed, 127 insertions(+)
diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt
b/Documentation/devicetree/bindings/clock/sunxi.txt
index 0cf679b..28421d2 100644
--- a/Documentation/devicetree/bindings/clock/sunxi.txt
+++ b/Documentation/devicetree/bindings/clock/sunxi.txt
@@ -37,6 +37,7 @@ Required properties:
allwinner,sun6i-a31-apb2-gates-clk - for the APB2 gates on A31
allwinner,sun4i-mod0-clk - for the module 0 family of clocks
allwinner,sun7i-a20-out-clk - for the external output clocks
+ allwinner,sun7i-a20-gmac-clk - for the GMAC clock module on A20/A31
Required properties for all clocks:
- reg : shall be the control register address for the clock.
@@ -50,6 +51,9 @@ Required properties for all clocks:
If the clock module only has one output, the name shall be the
module name.
+For allwinner,sun7i-a20-gmac-clk, the parent clocks shall be fixed rate
+dummy clocks at 25 MHz and 125 MHz, respectively. See example.
+
Clock consumers should specify the desired clocks they use with a
clocks phandle cell. Consumers that are using a gated clock should
provide an additional ID in their clock property. This ID is the
@@ -96,3 +100,29 @@ mmc0_clk: clk@01c20088 {
clocks = osc24M, pll6 1, pll5 1;
clock-output-names = mmc0;
};
+
+mii_phy_tx_clk: clk@2 {
+ #clock-cells = 0;
+ compatible = fixed-clock;
+ clock-frequency = 2500;
+ clock-output-names = mii_phy_tx;
+};
+
+gmac_int_tx_clk: clk@3 {
+ #clock-cells = 0;
+ compatible = fixed-clock;
+ clock-frequency = 12500;
+ clock-output-names = gmac_int_tx;
+};
+
+gmac_clk: clk@01c20164 {
+ #clock-cells = 0;
+ compatible = allwinner,sun7i-a20-gmac-clk;
+ reg = 0x01c20164 0x4;
+ /*
+* The first clock must be fixed at 25MHz;
+* the second clock must be fixed at 125MHz
+*/
+ clocks = mii_phy_tx_clk, gmac_int_tx_clk;
+ clock-output-names = gmac;
+};
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
index 736fb60..da1d5cc 100644
--- a/drivers/clk/sunxi/clk-sunxi.c
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -379,6 +379,103 @@ static void sun7i_a20_get_out_factors(u32 *freq, u32
parent_rate,
/**
+ * sun7i_a20_gmac_clk_setup - Setup function for A20/A31 GMAC clock module
+ *
+ * This clock looks something like this
+ *
+ * MII TX clock from PHY -|____| to GMAC core
+ * GMAC Int. RGMII TX clk |___\__/__gate---| to PHY
+ * Ext. 125MHz RGMII TX clk --|__divider__/|
+ * ||
+ *
+ * The external 125 MHz reference is optional, i.e. GMAC can use its
+ * internal TX clock just fine. The A31 GMAC clock module does not have
+ * the divider controls for the external reference.
+ *
+ * To keep it simple, let the GMAC use either the MII TX clock for MII mode,
+ * and its internal TX clock for GMII and RGMII modes. The GMAC driver should
+ * select the appropriate source and gate/ungate the output to the PHY.
+ *
+ * Only the GMAC should use this clock. Altering the clock so that it doesn't
+ * match the GMAC's operation parameters will result in the GMAC not being
+ * able to send traffic out. The GMAC driver should set the clock rate and
+ * enable/disable this clock to configure the required state. The clock
+ * driver then responds by auto-reparenting the clock.
+ */
+
+#define SUN7I_A20_GMAC_GPIT2
+#define SUN7I_A20_GMAC_MASK0x3
+#define SUN7I_A20_GMAC_PARENTS 2
+
+static void __init sun7i_a20_gmac_clk_setup(struct device_node *node)
+{
+ struct clk *clk;
+ struct clk_mux *mux;
+ struct clk_gate *gate;
+ const char *clk_name = node-name;
+ const char *parents[SUN7I_A20_GMAC_PARENTS];
+ void *reg;
+ int i = 0;
+
+ if (of_property_read_string(node, clock-output-names, clk_name))
+ return;
+
+ /* allocate mux and gate clock structs */
+ mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL);
+ if (!mux)
+ return;
+
+ gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
+ if (!gate)
+ goto free_mux;
+
+ /* gmac clock requires exactly 2 parents */
+ parents[0] = of_clk_get_parent_name(node, 0);
+