mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-24 05:04:00 +08:00
clk: sunxi: Add Allwinner A20/A31 GMAC clock unit
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 <wens@csie.org> Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com> Signed-off-by: Emilio López <emilio@elopez.com.ar>
This commit is contained in:
parent
92ef67c53a
commit
e4c6d6c11b
@ -38,6 +38,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
|
||||
"allwinner,sun4i-a10-usb-clk" - for usb gates + resets on A10 / A20
|
||||
"allwinner,sun5i-a13-usb-clk" - for usb gates + resets on A13
|
||||
|
||||
@ -56,6 +57,9 @@ Required properties for all clocks:
|
||||
And "allwinner,*-usb-clk" clocks also require:
|
||||
- reset-cells : shall be set to 1
|
||||
|
||||
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
|
||||
@ -102,3 +106,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 = <25000000>;
|
||||
clock-output-names = "mii_phy_tx";
|
||||
};
|
||||
|
||||
gmac_int_tx_clk: clk@3 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "fixed-clock";
|
||||
clock-frequency = <125000000>;
|
||||
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";
|
||||
};
|
||||
|
@ -410,6 +410,102 @@ 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_GPIT 2
|
||||
#define SUN7I_A20_GMAC_MASK 0x3
|
||||
#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;
|
||||
|
||||
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);
|
||||
parents[1] = of_clk_get_parent_name(node, 1);
|
||||
if (!parents[0] || !parents[1])
|
||||
goto free_gate;
|
||||
|
||||
reg = of_iomap(node, 0);
|
||||
if (!reg)
|
||||
goto free_gate;
|
||||
|
||||
/* set up gate and fixed rate properties */
|
||||
gate->reg = reg;
|
||||
gate->bit_idx = SUN7I_A20_GMAC_GPIT;
|
||||
gate->lock = &clk_lock;
|
||||
mux->reg = reg;
|
||||
mux->mask = SUN7I_A20_GMAC_MASK;
|
||||
mux->flags = CLK_MUX_INDEX_BIT;
|
||||
mux->lock = &clk_lock;
|
||||
|
||||
clk = clk_register_composite(NULL, clk_name,
|
||||
parents, SUN7I_A20_GMAC_PARENTS,
|
||||
&mux->hw, &clk_mux_ops,
|
||||
NULL, NULL,
|
||||
&gate->hw, &clk_gate_ops,
|
||||
0);
|
||||
|
||||
if (IS_ERR(clk))
|
||||
goto iounmap_reg;
|
||||
|
||||
of_clk_add_provider(node, of_clk_src_simple_get, clk);
|
||||
clk_register_clkdev(clk, clk_name, NULL);
|
||||
|
||||
return;
|
||||
|
||||
iounmap_reg:
|
||||
iounmap(reg);
|
||||
free_gate:
|
||||
kfree(gate);
|
||||
free_mux:
|
||||
kfree(mux);
|
||||
}
|
||||
CLK_OF_DECLARE(sun7i_a20_gmac, "allwinner,sun7i-a20-gmac-clk",
|
||||
sun7i_a20_gmac_clk_setup);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* sunxi_factors_clk_setup() - Setup function for factor clocks
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user