1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright 2013 Emilio López |
4 | * Emilio López <emilio@elopez.com.ar> |
5 | * |
6 | * Copyright 2013 Chen-Yu Tsai |
7 | * Chen-Yu Tsai <wens@csie.org> |
8 | */ |
9 | |
10 | #include <linux/clk-provider.h> |
11 | #include <linux/io.h> |
12 | #include <linux/of.h> |
13 | #include <linux/of_address.h> |
14 | #include <linux/slab.h> |
15 | |
16 | static DEFINE_SPINLOCK(gmac_lock); |
17 | |
18 | |
19 | #define SUN7I_A20_GMAC_GPIT 2 |
20 | #define SUN7I_A20_GMAC_MASK 0x3 |
21 | #define SUN7I_A20_GMAC_PARENTS 2 |
22 | |
23 | static u32 sun7i_a20_gmac_mux_table[SUN7I_A20_GMAC_PARENTS] = { |
24 | 0x00, /* Select mii_phy_tx_clk */ |
25 | 0x02, /* Select gmac_int_tx_clk */ |
26 | }; |
27 | |
28 | /** |
29 | * sun7i_a20_gmac_clk_setup - Setup function for A20/A31 GMAC clock module |
30 | * @node: &struct device_node for the clock |
31 | * |
32 | * This clock looks something like this |
33 | * ________________________ |
34 | * MII TX clock from PHY >-----|___________ _________|----> to GMAC core |
35 | * GMAC Int. RGMII TX clk >----|___________\__/__gate---|----> to PHY |
36 | * Ext. 125MHz RGMII TX clk >--|__divider__/ | |
37 | * |________________________| |
38 | * |
39 | * The external 125 MHz reference is optional, i.e. GMAC can use its |
40 | * internal TX clock just fine. The A31 GMAC clock module does not have |
41 | * the divider controls for the external reference. |
42 | * |
43 | * To keep it simple, let the GMAC use either the MII TX clock for MII mode, |
44 | * and its internal TX clock for GMII and RGMII modes. The GMAC driver should |
45 | * select the appropriate source and gate/ungate the output to the PHY. |
46 | * |
47 | * Only the GMAC should use this clock. Altering the clock so that it doesn't |
48 | * match the GMAC's operation parameters will result in the GMAC not being |
49 | * able to send traffic out. The GMAC driver should set the clock rate and |
50 | * enable/disable this clock to configure the required state. The clock |
51 | * driver then responds by auto-reparenting the clock. |
52 | */ |
53 | static void __init sun7i_a20_gmac_clk_setup(struct device_node *node) |
54 | { |
55 | struct clk *clk; |
56 | struct clk_mux *mux; |
57 | struct clk_gate *gate; |
58 | const char *clk_name = node->name; |
59 | const char *parents[SUN7I_A20_GMAC_PARENTS]; |
60 | void __iomem *reg; |
61 | |
62 | if (of_property_read_string(np: node, propname: "clock-output-names" , out_string: &clk_name)) |
63 | return; |
64 | |
65 | /* allocate mux and gate clock structs */ |
66 | mux = kzalloc(size: sizeof(struct clk_mux), GFP_KERNEL); |
67 | if (!mux) |
68 | return; |
69 | |
70 | gate = kzalloc(size: sizeof(struct clk_gate), GFP_KERNEL); |
71 | if (!gate) |
72 | goto free_mux; |
73 | |
74 | /* gmac clock requires exactly 2 parents */ |
75 | if (of_clk_parent_fill(np: node, parents, size: 2) != 2) |
76 | goto free_gate; |
77 | |
78 | reg = of_iomap(node, index: 0); |
79 | if (!reg) |
80 | goto free_gate; |
81 | |
82 | /* set up gate and fixed rate properties */ |
83 | gate->reg = reg; |
84 | gate->bit_idx = SUN7I_A20_GMAC_GPIT; |
85 | gate->lock = &gmac_lock; |
86 | mux->reg = reg; |
87 | mux->mask = SUN7I_A20_GMAC_MASK; |
88 | mux->table = sun7i_a20_gmac_mux_table; |
89 | mux->lock = &gmac_lock; |
90 | |
91 | clk = clk_register_composite(NULL, name: clk_name, |
92 | parent_names: parents, SUN7I_A20_GMAC_PARENTS, |
93 | mux_hw: &mux->hw, mux_ops: &clk_mux_ops, |
94 | NULL, NULL, |
95 | gate_hw: &gate->hw, gate_ops: &clk_gate_ops, |
96 | flags: 0); |
97 | |
98 | if (IS_ERR(ptr: clk)) |
99 | goto iounmap_reg; |
100 | |
101 | of_clk_add_provider(np: node, clk_src_get: of_clk_src_simple_get, data: clk); |
102 | |
103 | return; |
104 | |
105 | iounmap_reg: |
106 | iounmap(addr: reg); |
107 | free_gate: |
108 | kfree(objp: gate); |
109 | free_mux: |
110 | kfree(objp: mux); |
111 | } |
112 | CLK_OF_DECLARE(sun7i_a20_gmac, "allwinner,sun7i-a20-gmac-clk" , |
113 | sun7i_a20_gmac_clk_setup); |
114 | |