Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e4c6d6c1 authored by Chen-Yu Tsai's avatar Chen-Yu Tsai Committed by Emilio López
Browse files

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: default avatarChen-Yu Tsai <wens@csie.org>
Acked-by: default avatarMaxime Ripard <maxime.ripard@free-electrons.com>
Signed-off-by: default avatarEmilio López <emilio@elopez.com.ar>
parent 92ef67c5
Loading
Loading
Loading
Loading
+30 −0
Original line number Diff line number Diff line
@@ -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";
};
+96 −0
Original line number Diff line number Diff line
@@ -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
 */