xref: /openbmc/linux/drivers/clk/sunxi/clk-a20-gmac.c (revision 75bf465f0bc33e9b776a46d6a1b9b990f5fb7c37)
1*c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
259cb10e3SMaxime Ripard /*
359cb10e3SMaxime Ripard  * Copyright 2013 Emilio López
459cb10e3SMaxime Ripard  * Emilio López <emilio@elopez.com.ar>
559cb10e3SMaxime Ripard  *
659cb10e3SMaxime Ripard  * Copyright 2013 Chen-Yu Tsai
759cb10e3SMaxime Ripard  * Chen-Yu Tsai <wens@csie.org>
859cb10e3SMaxime Ripard  */
959cb10e3SMaxime Ripard 
1059cb10e3SMaxime Ripard #include <linux/clk-provider.h>
1162e59c4eSStephen Boyd #include <linux/io.h>
1259cb10e3SMaxime Ripard #include <linux/of.h>
1359cb10e3SMaxime Ripard #include <linux/of_address.h>
1459cb10e3SMaxime Ripard #include <linux/slab.h>
1559cb10e3SMaxime Ripard 
1659cb10e3SMaxime Ripard static DEFINE_SPINLOCK(gmac_lock);
1759cb10e3SMaxime Ripard 
1859cb10e3SMaxime Ripard /**
1959cb10e3SMaxime Ripard  * sun7i_a20_gmac_clk_setup - Setup function for A20/A31 GMAC clock module
2059cb10e3SMaxime Ripard  *
2159cb10e3SMaxime Ripard  * This clock looks something like this
2259cb10e3SMaxime Ripard  *                               ________________________
2359cb10e3SMaxime Ripard  *  MII TX clock from PHY >-----|___________    _________|----> to GMAC core
2459cb10e3SMaxime Ripard  *  GMAC Int. RGMII TX clk >----|___________\__/__gate---|----> to PHY
2559cb10e3SMaxime Ripard  *  Ext. 125MHz RGMII TX clk >--|__divider__/            |
2659cb10e3SMaxime Ripard  *                              |________________________|
2759cb10e3SMaxime Ripard  *
2859cb10e3SMaxime Ripard  * The external 125 MHz reference is optional, i.e. GMAC can use its
2959cb10e3SMaxime Ripard  * internal TX clock just fine. The A31 GMAC clock module does not have
3059cb10e3SMaxime Ripard  * the divider controls for the external reference.
3159cb10e3SMaxime Ripard  *
3259cb10e3SMaxime Ripard  * To keep it simple, let the GMAC use either the MII TX clock for MII mode,
3359cb10e3SMaxime Ripard  * and its internal TX clock for GMII and RGMII modes. The GMAC driver should
3459cb10e3SMaxime Ripard  * select the appropriate source and gate/ungate the output to the PHY.
3559cb10e3SMaxime Ripard  *
3659cb10e3SMaxime Ripard  * Only the GMAC should use this clock. Altering the clock so that it doesn't
3759cb10e3SMaxime Ripard  * match the GMAC's operation parameters will result in the GMAC not being
3859cb10e3SMaxime Ripard  * able to send traffic out. The GMAC driver should set the clock rate and
3959cb10e3SMaxime Ripard  * enable/disable this clock to configure the required state. The clock
4059cb10e3SMaxime Ripard  * driver then responds by auto-reparenting the clock.
4159cb10e3SMaxime Ripard  */
4259cb10e3SMaxime Ripard 
4359cb10e3SMaxime Ripard #define SUN7I_A20_GMAC_GPIT	2
4459cb10e3SMaxime Ripard #define SUN7I_A20_GMAC_MASK	0x3
4559cb10e3SMaxime Ripard #define SUN7I_A20_GMAC_PARENTS	2
4659cb10e3SMaxime Ripard 
47c1ec5160SHans de Goede static u32 sun7i_a20_gmac_mux_table[SUN7I_A20_GMAC_PARENTS] = {
48c1ec5160SHans de Goede 	0x00, /* Select mii_phy_tx_clk */
49c1ec5160SHans de Goede 	0x02, /* Select gmac_int_tx_clk */
50c1ec5160SHans de Goede };
51c1ec5160SHans de Goede 
sun7i_a20_gmac_clk_setup(struct device_node * node)5259cb10e3SMaxime Ripard static void __init sun7i_a20_gmac_clk_setup(struct device_node *node)
5359cb10e3SMaxime Ripard {
5459cb10e3SMaxime Ripard 	struct clk *clk;
5559cb10e3SMaxime Ripard 	struct clk_mux *mux;
5659cb10e3SMaxime Ripard 	struct clk_gate *gate;
5759cb10e3SMaxime Ripard 	const char *clk_name = node->name;
5859cb10e3SMaxime Ripard 	const char *parents[SUN7I_A20_GMAC_PARENTS];
5989a9456dSEmilio López 	void __iomem *reg;
6059cb10e3SMaxime Ripard 
6159cb10e3SMaxime Ripard 	if (of_property_read_string(node, "clock-output-names", &clk_name))
6259cb10e3SMaxime Ripard 		return;
6359cb10e3SMaxime Ripard 
6459cb10e3SMaxime Ripard 	/* allocate mux and gate clock structs */
6559cb10e3SMaxime Ripard 	mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL);
6659cb10e3SMaxime Ripard 	if (!mux)
6759cb10e3SMaxime Ripard 		return;
6859cb10e3SMaxime Ripard 
6959cb10e3SMaxime Ripard 	gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
7059cb10e3SMaxime Ripard 	if (!gate)
7159cb10e3SMaxime Ripard 		goto free_mux;
7259cb10e3SMaxime Ripard 
7359cb10e3SMaxime Ripard 	/* gmac clock requires exactly 2 parents */
748a53fb2bSDinh Nguyen 	if (of_clk_parent_fill(node, parents, 2) != 2)
7559cb10e3SMaxime Ripard 		goto free_gate;
7659cb10e3SMaxime Ripard 
7759cb10e3SMaxime Ripard 	reg = of_iomap(node, 0);
7859cb10e3SMaxime Ripard 	if (!reg)
7959cb10e3SMaxime Ripard 		goto free_gate;
8059cb10e3SMaxime Ripard 
8159cb10e3SMaxime Ripard 	/* set up gate and fixed rate properties */
8259cb10e3SMaxime Ripard 	gate->reg = reg;
8359cb10e3SMaxime Ripard 	gate->bit_idx = SUN7I_A20_GMAC_GPIT;
8459cb10e3SMaxime Ripard 	gate->lock = &gmac_lock;
8559cb10e3SMaxime Ripard 	mux->reg = reg;
8659cb10e3SMaxime Ripard 	mux->mask = SUN7I_A20_GMAC_MASK;
87c1ec5160SHans de Goede 	mux->table = sun7i_a20_gmac_mux_table;
8859cb10e3SMaxime Ripard 	mux->lock = &gmac_lock;
8959cb10e3SMaxime Ripard 
9059cb10e3SMaxime Ripard 	clk = clk_register_composite(NULL, clk_name,
9159cb10e3SMaxime Ripard 			parents, SUN7I_A20_GMAC_PARENTS,
9259cb10e3SMaxime Ripard 			&mux->hw, &clk_mux_ops,
9359cb10e3SMaxime Ripard 			NULL, NULL,
9459cb10e3SMaxime Ripard 			&gate->hw, &clk_gate_ops,
9559cb10e3SMaxime Ripard 			0);
9659cb10e3SMaxime Ripard 
9759cb10e3SMaxime Ripard 	if (IS_ERR(clk))
9859cb10e3SMaxime Ripard 		goto iounmap_reg;
9959cb10e3SMaxime Ripard 
10059cb10e3SMaxime Ripard 	of_clk_add_provider(node, of_clk_src_simple_get, clk);
10159cb10e3SMaxime Ripard 
10259cb10e3SMaxime Ripard 	return;
10359cb10e3SMaxime Ripard 
10459cb10e3SMaxime Ripard iounmap_reg:
10559cb10e3SMaxime Ripard 	iounmap(reg);
10659cb10e3SMaxime Ripard free_gate:
10759cb10e3SMaxime Ripard 	kfree(gate);
10859cb10e3SMaxime Ripard free_mux:
10959cb10e3SMaxime Ripard 	kfree(mux);
11059cb10e3SMaxime Ripard }
11159cb10e3SMaxime Ripard CLK_OF_DECLARE(sun7i_a20_gmac, "allwinner,sun7i-a20-gmac-clk",
11259cb10e3SMaxime Ripard 		sun7i_a20_gmac_clk_setup);
113