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