1*82a248dfSMarek Behún // SPDX-License-Identifier: GPL-2.0+
2*82a248dfSMarek Behún /*
3*82a248dfSMarek Behún  * Marvell Armada 37xx SoC Peripheral clocks
4*82a248dfSMarek Behún  *
5*82a248dfSMarek Behún  * Marek Behun <marek.behun@nic.cz>
6*82a248dfSMarek Behún  *
7*82a248dfSMarek Behún  * Based on Linux driver by:
8*82a248dfSMarek Behún  *   Gregory CLEMENT <gregory.clement@free-electrons.com>
9*82a248dfSMarek Behún  */
10*82a248dfSMarek Behún 
11*82a248dfSMarek Behún #include <common.h>
12*82a248dfSMarek Behún #include <malloc.h>
13*82a248dfSMarek Behún #include <clk-uclass.h>
14*82a248dfSMarek Behún #include <clk.h>
15*82a248dfSMarek Behún #include <dm.h>
16*82a248dfSMarek Behún #include <asm/io.h>
17*82a248dfSMarek Behún #include <asm/arch/cpu.h>
18*82a248dfSMarek Behún 
19*82a248dfSMarek Behún #define TBG_SEL		0x0
20*82a248dfSMarek Behún #define DIV_SEL0	0x4
21*82a248dfSMarek Behún #define DIV_SEL1	0x8
22*82a248dfSMarek Behún #define DIV_SEL2	0xC
23*82a248dfSMarek Behún #define CLK_SEL		0x10
24*82a248dfSMarek Behún #define CLK_DIS		0x14
25*82a248dfSMarek Behún 
26*82a248dfSMarek Behún enum a37xx_periph_parent {
27*82a248dfSMarek Behún 	TBG_A_P		= 0,
28*82a248dfSMarek Behún 	TBG_B_P		= 1,
29*82a248dfSMarek Behún 	TBG_A_S		= 2,
30*82a248dfSMarek Behún 	TBG_B_S		= 3,
31*82a248dfSMarek Behún 	MAX_TBG_PARENTS	= 4,
32*82a248dfSMarek Behún 	XTAL		= 4,
33*82a248dfSMarek Behún 	MAX_PARENTS	= 5,
34*82a248dfSMarek Behún };
35*82a248dfSMarek Behún 
36*82a248dfSMarek Behún static const struct {
37*82a248dfSMarek Behún 	const char *name;
38*82a248dfSMarek Behún 	enum a37xx_periph_parent parent;
39*82a248dfSMarek Behún } a37xx_periph_parent_names[] = {
40*82a248dfSMarek Behún 	{ "TBG-A-P", TBG_A_P },
41*82a248dfSMarek Behún 	{ "TBG-B-P", TBG_B_P },
42*82a248dfSMarek Behún 	{ "TBG-A-S", TBG_A_S },
43*82a248dfSMarek Behún 	{ "TBG-B-S", TBG_B_S },
44*82a248dfSMarek Behún 	{ "xtal",    XTAL    },
45*82a248dfSMarek Behún };
46*82a248dfSMarek Behún 
47*82a248dfSMarek Behún struct clk_periph;
48*82a248dfSMarek Behún 
49*82a248dfSMarek Behún struct a37xx_periphclk {
50*82a248dfSMarek Behún 	void __iomem *reg;
51*82a248dfSMarek Behún 
52*82a248dfSMarek Behún 	ulong parents[MAX_PARENTS];
53*82a248dfSMarek Behún 
54*82a248dfSMarek Behún 	const struct clk_periph *clks;
55*82a248dfSMarek Behún 	bool clk_has_periph_parent[16];
56*82a248dfSMarek Behún 	int clk_parent[16];
57*82a248dfSMarek Behún 
58*82a248dfSMarek Behún 	int count;
59*82a248dfSMarek Behún };
60*82a248dfSMarek Behún 
61*82a248dfSMarek Behún struct clk_div_table {
62*82a248dfSMarek Behún 	u32 div;
63*82a248dfSMarek Behún 	u32 val;
64*82a248dfSMarek Behún };
65*82a248dfSMarek Behún 
66*82a248dfSMarek Behún struct clk_periph {
67*82a248dfSMarek Behún 	const char *name;
68*82a248dfSMarek Behún 
69*82a248dfSMarek Behún 	const char *parent_name;
70*82a248dfSMarek Behún 
71*82a248dfSMarek Behún 	u32 disable_bit;
72*82a248dfSMarek Behún 	int mux_shift;
73*82a248dfSMarek Behún 
74*82a248dfSMarek Behún 	const struct clk_div_table *div_table[2];
75*82a248dfSMarek Behún 	s32 div_reg_off[2];
76*82a248dfSMarek Behún 	u32 div_mask[2];
77*82a248dfSMarek Behún 	int div_shift[2];
78*82a248dfSMarek Behún 
79*82a248dfSMarek Behún 	unsigned can_gate : 1;
80*82a248dfSMarek Behún 	unsigned can_mux : 1;
81*82a248dfSMarek Behún 	unsigned dividers : 2;
82*82a248dfSMarek Behún };
83*82a248dfSMarek Behún 
84*82a248dfSMarek Behún static const struct clk_div_table div_table1[] = {
85*82a248dfSMarek Behún 	{ 1, 1 },
86*82a248dfSMarek Behún 	{ 2, 2 },
87*82a248dfSMarek Behún 	{ 0, 0 },
88*82a248dfSMarek Behún };
89*82a248dfSMarek Behún 
90*82a248dfSMarek Behún static const struct clk_div_table div_table2[] = {
91*82a248dfSMarek Behún 	{ 2, 1 },
92*82a248dfSMarek Behún 	{ 4, 2 },
93*82a248dfSMarek Behún 	{ 0, 0 },
94*82a248dfSMarek Behún };
95*82a248dfSMarek Behún 
96*82a248dfSMarek Behún static const struct clk_div_table div_table6[] = {
97*82a248dfSMarek Behún 	{ 1, 1 },
98*82a248dfSMarek Behún 	{ 2, 2 },
99*82a248dfSMarek Behún 	{ 3, 3 },
100*82a248dfSMarek Behún 	{ 4, 4 },
101*82a248dfSMarek Behún 	{ 5, 5 },
102*82a248dfSMarek Behún 	{ 6, 6 },
103*82a248dfSMarek Behún 	{ 0, 0 },
104*82a248dfSMarek Behún };
105*82a248dfSMarek Behún 
106*82a248dfSMarek Behún #define CLK_FULL_DD(_n, _d, _mux, _r0, _r1, _s0, _s1)	\
107*82a248dfSMarek Behún 	{						\
108*82a248dfSMarek Behún 		.name = #_n,				\
109*82a248dfSMarek Behún 		.disable_bit = BIT(_d),			\
110*82a248dfSMarek Behún 		.mux_shift = _mux,			\
111*82a248dfSMarek Behún 		.div_table[0] = div_table6,		\
112*82a248dfSMarek Behún 		.div_table[1] = div_table6,		\
113*82a248dfSMarek Behún 		.div_reg_off[0] = _r0,			\
114*82a248dfSMarek Behún 		.div_reg_off[1] = _r1,			\
115*82a248dfSMarek Behún 		.div_shift[0] = _s0,			\
116*82a248dfSMarek Behún 		.div_shift[1] = _s1,			\
117*82a248dfSMarek Behún 		.div_mask[0] = 7,			\
118*82a248dfSMarek Behún 		.div_mask[1] = 7,			\
119*82a248dfSMarek Behún 		.can_gate = 1,				\
120*82a248dfSMarek Behún 		.can_mux = 1,				\
121*82a248dfSMarek Behún 		.dividers = 2,				\
122*82a248dfSMarek Behún 	}
123*82a248dfSMarek Behún 
124*82a248dfSMarek Behún #define CLK_FULL(_n, _d, _mux, _r, _s, _m, _t)	\
125*82a248dfSMarek Behún 	{					\
126*82a248dfSMarek Behún 		.name = #_n,			\
127*82a248dfSMarek Behún 		.disable_bit = BIT(_d),		\
128*82a248dfSMarek Behún 		.mux_shift = _mux,		\
129*82a248dfSMarek Behún 		.div_table[0] = _t,		\
130*82a248dfSMarek Behún 		.div_reg_off[0] = _r,		\
131*82a248dfSMarek Behún 		.div_shift[0] = _s,		\
132*82a248dfSMarek Behún 		.div_mask[0] = _m,		\
133*82a248dfSMarek Behún 		.can_gate = 1,			\
134*82a248dfSMarek Behún 		.can_mux = 1,			\
135*82a248dfSMarek Behún 		.dividers = 1,			\
136*82a248dfSMarek Behún 	}
137*82a248dfSMarek Behún 
138*82a248dfSMarek Behún #define CLK_GATE_DIV(_n, _d, _r, _s, _m, _t, _p)	\
139*82a248dfSMarek Behún 	{						\
140*82a248dfSMarek Behún 		.name = #_n,				\
141*82a248dfSMarek Behún 		.parent_name = _p,			\
142*82a248dfSMarek Behún 		.disable_bit = BIT(_d),			\
143*82a248dfSMarek Behún 		.div_table[0] = _t,			\
144*82a248dfSMarek Behún 		.div_reg_off[0] = _r,			\
145*82a248dfSMarek Behún 		.div_shift[0] = _s,			\
146*82a248dfSMarek Behún 		.div_mask[0] = _m,			\
147*82a248dfSMarek Behún 		.can_gate = 1,				\
148*82a248dfSMarek Behún 		.dividers = 1,				\
149*82a248dfSMarek Behún 	}
150*82a248dfSMarek Behún 
151*82a248dfSMarek Behún #define CLK_GATE(_n, _d, _p)		\
152*82a248dfSMarek Behún 	{				\
153*82a248dfSMarek Behún 		.name = #_n,		\
154*82a248dfSMarek Behún 		.parent_name = _p,	\
155*82a248dfSMarek Behún 		.disable_bit = BIT(_d),	\
156*82a248dfSMarek Behún 		.can_gate = 1,		\
157*82a248dfSMarek Behún 	}
158*82a248dfSMarek Behún 
159*82a248dfSMarek Behún #define CLK_MUX_DIV(_n, _mux, _r, _s, _m, _t)	\
160*82a248dfSMarek Behún 	{					\
161*82a248dfSMarek Behún 		.name = #_n,			\
162*82a248dfSMarek Behún 		.mux_shift = _mux,		\
163*82a248dfSMarek Behún 		.div_table[0] = _t,		\
164*82a248dfSMarek Behún 		.div_reg_off[0] = _r,		\
165*82a248dfSMarek Behún 		.div_shift[0] = _s,		\
166*82a248dfSMarek Behún 		.div_mask[0] = _m,		\
167*82a248dfSMarek Behún 		.can_mux = 1,			\
168*82a248dfSMarek Behún 		.dividers = 1,			\
169*82a248dfSMarek Behún 	}
170*82a248dfSMarek Behún 
171*82a248dfSMarek Behún #define CLK_MUX_DD(_n, _mux, _r0, _r1, _s0, _s1)	\
172*82a248dfSMarek Behún 	{						\
173*82a248dfSMarek Behún 		.name = #_n,				\
174*82a248dfSMarek Behún 		.mux_shift = _mux,			\
175*82a248dfSMarek Behún 		.div_table[0] = div_table6,		\
176*82a248dfSMarek Behún 		.div_table[1] = div_table6,		\
177*82a248dfSMarek Behún 		.div_reg_off[0] = _r0,			\
178*82a248dfSMarek Behún 		.div_reg_off[1] = _r1,			\
179*82a248dfSMarek Behún 		.div_shift[0] = _s0,			\
180*82a248dfSMarek Behún 		.div_shift[1] = _s1,			\
181*82a248dfSMarek Behún 		.div_mask[0] = 7,			\
182*82a248dfSMarek Behún 		.div_mask[1] = 7,			\
183*82a248dfSMarek Behún 		.can_mux = 1,				\
184*82a248dfSMarek Behún 		.dividers = 2,				\
185*82a248dfSMarek Behún 	}
186*82a248dfSMarek Behún 
187*82a248dfSMarek Behún /* NB periph clocks */
188*82a248dfSMarek Behún static const struct clk_periph clks_nb[] = {
189*82a248dfSMarek Behún 	CLK_FULL_DD(mmc, 2, 0, DIV_SEL2, DIV_SEL2, 16, 13),
190*82a248dfSMarek Behún 	CLK_FULL_DD(sata_host, 3, 2, DIV_SEL2, DIV_SEL2, 10, 7),
191*82a248dfSMarek Behún 	CLK_FULL_DD(sec_at, 6, 4, DIV_SEL1, DIV_SEL1, 3, 0),
192*82a248dfSMarek Behún 	CLK_FULL_DD(sec_dap, 7, 6, DIV_SEL1, DIV_SEL1, 9, 6),
193*82a248dfSMarek Behún 	CLK_FULL_DD(tscem, 8, 8, DIV_SEL1, DIV_SEL1, 15, 12),
194*82a248dfSMarek Behún 	CLK_FULL(tscem_tmx, 10, 10, DIV_SEL1, 18, 7, div_table6),
195*82a248dfSMarek Behún 	CLK_GATE(avs, 11, "xtal"),
196*82a248dfSMarek Behún 	CLK_FULL_DD(sqf, 12, 12, DIV_SEL1, DIV_SEL1, 27, 24),
197*82a248dfSMarek Behún 	CLK_FULL_DD(pwm, 13, 14, DIV_SEL0, DIV_SEL0, 3, 0),
198*82a248dfSMarek Behún 	CLK_GATE(i2c_2, 16, "xtal"),
199*82a248dfSMarek Behún 	CLK_GATE(i2c_1, 17, "xtal"),
200*82a248dfSMarek Behún 	CLK_GATE_DIV(ddr_phy, 19, DIV_SEL0, 18, 1, div_table2, "TBG-A-S"),
201*82a248dfSMarek Behún 	CLK_FULL_DD(ddr_fclk, 21, 16, DIV_SEL0, DIV_SEL0, 15, 12),
202*82a248dfSMarek Behún 	CLK_FULL(trace, 22, 18, DIV_SEL0, 20, 7, div_table6),
203*82a248dfSMarek Behún 	CLK_FULL(counter, 23, 20, DIV_SEL0, 23, 7, div_table6),
204*82a248dfSMarek Behún 	CLK_FULL_DD(eip97, 24, 24, DIV_SEL2, DIV_SEL2, 22, 19),
205*82a248dfSMarek Behún 	CLK_MUX_DIV(cpu, 22, DIV_SEL0, 28, 7, div_table6),
206*82a248dfSMarek Behún 	{ },
207*82a248dfSMarek Behún };
208*82a248dfSMarek Behún 
209*82a248dfSMarek Behún /* SB periph clocks */
210*82a248dfSMarek Behún static const struct clk_periph clks_sb[] = {
211*82a248dfSMarek Behún 	CLK_MUX_DD(gbe_50, 6, DIV_SEL2, DIV_SEL2, 6, 9),
212*82a248dfSMarek Behún 	CLK_MUX_DD(gbe_core, 8, DIV_SEL1, DIV_SEL1, 18, 21),
213*82a248dfSMarek Behún 	CLK_MUX_DD(gbe_125, 10, DIV_SEL1, DIV_SEL1, 6, 9),
214*82a248dfSMarek Behún 	CLK_GATE(gbe1_50, 0, "gbe_50"),
215*82a248dfSMarek Behún 	CLK_GATE(gbe0_50, 1, "gbe_50"),
216*82a248dfSMarek Behún 	CLK_GATE(gbe1_125, 2, "gbe_125"),
217*82a248dfSMarek Behún 	CLK_GATE(gbe0_125, 3, "gbe_125"),
218*82a248dfSMarek Behún 	CLK_GATE_DIV(gbe1_core, 4, DIV_SEL1, 13, 1, div_table1, "gbe_core"),
219*82a248dfSMarek Behún 	CLK_GATE_DIV(gbe0_core, 5, DIV_SEL1, 14, 1, div_table1, "gbe_core"),
220*82a248dfSMarek Behún 	CLK_GATE_DIV(gbe_bm, 12, DIV_SEL1, 0, 1, div_table1, "gbe_core"),
221*82a248dfSMarek Behún 	CLK_FULL_DD(sdio, 11, 14, DIV_SEL0, DIV_SEL0, 3, 6),
222*82a248dfSMarek Behún 	CLK_FULL_DD(usb32_usb2_sys, 16, 16, DIV_SEL0, DIV_SEL0, 9, 12),
223*82a248dfSMarek Behún 	CLK_FULL_DD(usb32_ss_sys, 17, 18, DIV_SEL0, DIV_SEL0, 15, 18),
224*82a248dfSMarek Behún 	{ },
225*82a248dfSMarek Behún };
226*82a248dfSMarek Behún 
227*82a248dfSMarek Behún static inline int get_mux(struct a37xx_periphclk *priv, int shift)
228*82a248dfSMarek Behún {
229*82a248dfSMarek Behún 	return (readl(priv->reg + TBG_SEL) >> shift) & 3;
230*82a248dfSMarek Behún }
231*82a248dfSMarek Behún 
232*82a248dfSMarek Behún static ulong periph_clk_get_rate(struct a37xx_periphclk *priv, int id);
233*82a248dfSMarek Behún 
234*82a248dfSMarek Behún static ulong get_parent_rate(struct a37xx_periphclk *priv, int id)
235*82a248dfSMarek Behún {
236*82a248dfSMarek Behún 	const struct clk_periph *clk = &priv->clks[id];
237*82a248dfSMarek Behún 	ulong res;
238*82a248dfSMarek Behún 
239*82a248dfSMarek Behún 	if (clk->can_mux) {
240*82a248dfSMarek Behún 		/* parent is one of TBG clocks */
241*82a248dfSMarek Behún 		int tbg = get_mux(priv, clk->mux_shift);
242*82a248dfSMarek Behún 
243*82a248dfSMarek Behún 		res = priv->parents[tbg];
244*82a248dfSMarek Behún 	} else if (priv->clk_has_periph_parent[id]) {
245*82a248dfSMarek Behún 		/* parent is one of other periph clocks */
246*82a248dfSMarek Behún 
247*82a248dfSMarek Behún 		if (priv->clk_parent[id] >= priv->count)
248*82a248dfSMarek Behún 			return -EINVAL;
249*82a248dfSMarek Behún 
250*82a248dfSMarek Behún 		res = periph_clk_get_rate(priv, priv->clk_parent[id]);
251*82a248dfSMarek Behún 	} else {
252*82a248dfSMarek Behún 		/* otherwise parent is one of TBGs or XTAL */
253*82a248dfSMarek Behún 
254*82a248dfSMarek Behún 		if (priv->clk_parent[id] >= MAX_PARENTS)
255*82a248dfSMarek Behún 			return -EINVAL;
256*82a248dfSMarek Behún 
257*82a248dfSMarek Behún 		res = priv->parents[priv->clk_parent[id]];
258*82a248dfSMarek Behún 	}
259*82a248dfSMarek Behún 
260*82a248dfSMarek Behún 	return res;
261*82a248dfSMarek Behún }
262*82a248dfSMarek Behún 
263*82a248dfSMarek Behún static ulong get_div(struct a37xx_periphclk *priv,
264*82a248dfSMarek Behún 		     const struct clk_periph *clk, int idx)
265*82a248dfSMarek Behún {
266*82a248dfSMarek Behún 	const struct clk_div_table *i;
267*82a248dfSMarek Behún 	u32 reg;
268*82a248dfSMarek Behún 
269*82a248dfSMarek Behún 	reg = readl(priv->reg + clk->div_reg_off[idx]);
270*82a248dfSMarek Behún 	reg = (reg >> clk->div_shift[idx]) & clk->div_mask[idx];
271*82a248dfSMarek Behún 
272*82a248dfSMarek Behún 	/* find divisor for register value val */
273*82a248dfSMarek Behún 	for (i = clk->div_table[idx]; i && i->div != 0; ++i)
274*82a248dfSMarek Behún 		if (i->val == reg)
275*82a248dfSMarek Behún 			return i->div;
276*82a248dfSMarek Behún 
277*82a248dfSMarek Behún 	return 0;
278*82a248dfSMarek Behún }
279*82a248dfSMarek Behún 
280*82a248dfSMarek Behún static ulong periph_clk_get_rate(struct a37xx_periphclk *priv, int id)
281*82a248dfSMarek Behún {
282*82a248dfSMarek Behún 	const struct clk_periph *clk = &priv->clks[id];
283*82a248dfSMarek Behún 	ulong rate, div;
284*82a248dfSMarek Behún 	int i;
285*82a248dfSMarek Behún 
286*82a248dfSMarek Behún 	rate = get_parent_rate(priv, id);
287*82a248dfSMarek Behún 	if (rate == -EINVAL)
288*82a248dfSMarek Behún 		return -EINVAL;
289*82a248dfSMarek Behún 
290*82a248dfSMarek Behún 	/* divide the parent rate by dividers */
291*82a248dfSMarek Behún 	div = 1;
292*82a248dfSMarek Behún 	for (i = 0; i < clk->dividers; ++i)
293*82a248dfSMarek Behún 		div *= get_div(priv, clk, i);
294*82a248dfSMarek Behún 
295*82a248dfSMarek Behún 	if (!div)
296*82a248dfSMarek Behún 		return 0;
297*82a248dfSMarek Behún 
298*82a248dfSMarek Behún 	return DIV_ROUND_UP(rate, div);
299*82a248dfSMarek Behún }
300*82a248dfSMarek Behún 
301*82a248dfSMarek Behún static ulong armada_37xx_periph_clk_get_rate(struct clk *clk)
302*82a248dfSMarek Behún {
303*82a248dfSMarek Behún 	struct a37xx_periphclk *priv = dev_get_priv(clk->dev);
304*82a248dfSMarek Behún 
305*82a248dfSMarek Behún 	if (clk->id >= priv->count)
306*82a248dfSMarek Behún 		return -EINVAL;
307*82a248dfSMarek Behún 
308*82a248dfSMarek Behún 	return periph_clk_get_rate(priv, clk->id);
309*82a248dfSMarek Behún }
310*82a248dfSMarek Behún 
311*82a248dfSMarek Behún static int periph_clk_enable(struct clk *clk, int enable)
312*82a248dfSMarek Behún {
313*82a248dfSMarek Behún 	struct a37xx_periphclk *priv = dev_get_priv(clk->dev);
314*82a248dfSMarek Behún 	const struct clk_periph *periph_clk = &priv->clks[clk->id];
315*82a248dfSMarek Behún 
316*82a248dfSMarek Behún 	if (clk->id >= priv->count)
317*82a248dfSMarek Behún 		return -EINVAL;
318*82a248dfSMarek Behún 
319*82a248dfSMarek Behún 	if (!periph_clk->can_gate)
320*82a248dfSMarek Behún 		return -ENOTSUPP;
321*82a248dfSMarek Behún 
322*82a248dfSMarek Behún 	if (enable)
323*82a248dfSMarek Behún 		clrbits_le32(priv->reg + CLK_DIS, periph_clk->disable_bit);
324*82a248dfSMarek Behún 	else
325*82a248dfSMarek Behún 		setbits_le32(priv->reg + CLK_DIS, periph_clk->disable_bit);
326*82a248dfSMarek Behún 
327*82a248dfSMarek Behún 	return 0;
328*82a248dfSMarek Behún }
329*82a248dfSMarek Behún 
330*82a248dfSMarek Behún static int armada_37xx_periph_clk_enable(struct clk *clk)
331*82a248dfSMarek Behún {
332*82a248dfSMarek Behún 	return periph_clk_enable(clk, 1);
333*82a248dfSMarek Behún }
334*82a248dfSMarek Behún 
335*82a248dfSMarek Behún static int armada_37xx_periph_clk_disable(struct clk *clk)
336*82a248dfSMarek Behún {
337*82a248dfSMarek Behún 	return periph_clk_enable(clk, 0);
338*82a248dfSMarek Behún }
339*82a248dfSMarek Behún 
340*82a248dfSMarek Behún int armada_37xx_periph_clk_dump(struct udevice *dev)
341*82a248dfSMarek Behún {
342*82a248dfSMarek Behún 	struct a37xx_periphclk *priv = dev_get_priv(dev);
343*82a248dfSMarek Behún 	const struct clk_periph *clks;
344*82a248dfSMarek Behún 	int i;
345*82a248dfSMarek Behún 
346*82a248dfSMarek Behún 	if (!priv)
347*82a248dfSMarek Behún 		return -ENODEV;
348*82a248dfSMarek Behún 
349*82a248dfSMarek Behún 	clks = priv->clks;
350*82a248dfSMarek Behún 
351*82a248dfSMarek Behún 	for (i = 0; i < priv->count; ++i)
352*82a248dfSMarek Behún 		printf("  %s at %lu Hz\n", clks[i].name,
353*82a248dfSMarek Behún 		       periph_clk_get_rate(priv, i));
354*82a248dfSMarek Behún 	printf("\n");
355*82a248dfSMarek Behún 
356*82a248dfSMarek Behún 	return 0;
357*82a248dfSMarek Behún }
358*82a248dfSMarek Behún 
359*82a248dfSMarek Behún static int armada_37xx_periph_clk_probe(struct udevice *dev)
360*82a248dfSMarek Behún {
361*82a248dfSMarek Behún 	struct a37xx_periphclk *priv = dev_get_priv(dev);
362*82a248dfSMarek Behún 	const struct clk_periph *clks;
363*82a248dfSMarek Behún 	int ret, i;
364*82a248dfSMarek Behún 
365*82a248dfSMarek Behún 	clks = (const struct clk_periph *)dev_get_driver_data(dev);
366*82a248dfSMarek Behún 	if (!clks)
367*82a248dfSMarek Behún 		return -ENODEV;
368*82a248dfSMarek Behún 
369*82a248dfSMarek Behún 	priv->reg = dev_read_addr_ptr(dev);
370*82a248dfSMarek Behún 	if (!priv->reg) {
371*82a248dfSMarek Behún 		dev_err(dev, "no io address\n");
372*82a248dfSMarek Behún 		return -ENODEV;
373*82a248dfSMarek Behún 	}
374*82a248dfSMarek Behún 
375*82a248dfSMarek Behún 	/* count clk_periph nodes */
376*82a248dfSMarek Behún 	priv->count = 0;
377*82a248dfSMarek Behún 	while (clks[priv->count].name)
378*82a248dfSMarek Behún 		priv->count++;
379*82a248dfSMarek Behún 
380*82a248dfSMarek Behún 	priv->clks = clks;
381*82a248dfSMarek Behún 
382*82a248dfSMarek Behún 	/* assign parent IDs to nodes which have non-NULL parent_name */
383*82a248dfSMarek Behún 	for (i = 0; i < priv->count; ++i) {
384*82a248dfSMarek Behún 		int j;
385*82a248dfSMarek Behún 
386*82a248dfSMarek Behún 		if (!clks[i].parent_name)
387*82a248dfSMarek Behún 			continue;
388*82a248dfSMarek Behún 
389*82a248dfSMarek Behún 		/* first try if parent_name is one of TBGs or XTAL */
390*82a248dfSMarek Behún 		for (j = 0; j < MAX_PARENTS; ++j)
391*82a248dfSMarek Behún 			if (!strcmp(clks[i].parent_name,
392*82a248dfSMarek Behún 				    a37xx_periph_parent_names[j].name))
393*82a248dfSMarek Behún 				break;
394*82a248dfSMarek Behún 
395*82a248dfSMarek Behún 		if (j < MAX_PARENTS) {
396*82a248dfSMarek Behún 			priv->clk_has_periph_parent[i] = false;
397*82a248dfSMarek Behún 			priv->clk_parent[i] =
398*82a248dfSMarek Behún 				a37xx_periph_parent_names[j].parent;
399*82a248dfSMarek Behún 			continue;
400*82a248dfSMarek Behún 		}
401*82a248dfSMarek Behún 
402*82a248dfSMarek Behún 		/* else parent_name should be one of other periph clocks */
403*82a248dfSMarek Behún 		for (j = 0; j < priv->count; ++j) {
404*82a248dfSMarek Behún 			if (!strcmp(clks[i].parent_name, clks[j].name))
405*82a248dfSMarek Behún 				break;
406*82a248dfSMarek Behún 		}
407*82a248dfSMarek Behún 
408*82a248dfSMarek Behún 		if (j < priv->count) {
409*82a248dfSMarek Behún 			priv->clk_has_periph_parent[i] = true;
410*82a248dfSMarek Behún 			priv->clk_parent[i] = j;
411*82a248dfSMarek Behún 			continue;
412*82a248dfSMarek Behún 		}
413*82a248dfSMarek Behún 
414*82a248dfSMarek Behún 		dev_err(dev, "undefined parent %s\n", clks[i].parent_name);
415*82a248dfSMarek Behún 		return -EINVAL;
416*82a248dfSMarek Behún 	}
417*82a248dfSMarek Behún 
418*82a248dfSMarek Behún 	for (i = 0; i < MAX_PARENTS; ++i) {
419*82a248dfSMarek Behún 		struct clk clk;
420*82a248dfSMarek Behún 
421*82a248dfSMarek Behún 		if (i == XTAL) {
422*82a248dfSMarek Behún 			priv->parents[i] = get_ref_clk() * 1000000;
423*82a248dfSMarek Behún 			continue;
424*82a248dfSMarek Behún 		}
425*82a248dfSMarek Behún 
426*82a248dfSMarek Behún 		ret = clk_get_by_index(dev, i, &clk);
427*82a248dfSMarek Behún 		if (ret) {
428*82a248dfSMarek Behún 			dev_err(dev, "one of parent clocks (%i) missing: %i\n",
429*82a248dfSMarek Behún 				i, ret);
430*82a248dfSMarek Behún 			return -ENODEV;
431*82a248dfSMarek Behún 		}
432*82a248dfSMarek Behún 
433*82a248dfSMarek Behún 		priv->parents[i] = clk_get_rate(&clk);
434*82a248dfSMarek Behún 		clk_free(&clk);
435*82a248dfSMarek Behún 	}
436*82a248dfSMarek Behún 
437*82a248dfSMarek Behún 	return 0;
438*82a248dfSMarek Behún }
439*82a248dfSMarek Behún 
440*82a248dfSMarek Behún static const struct clk_ops armada_37xx_periph_clk_ops = {
441*82a248dfSMarek Behún 	.get_rate = armada_37xx_periph_clk_get_rate,
442*82a248dfSMarek Behún 	.enable = armada_37xx_periph_clk_enable,
443*82a248dfSMarek Behún 	.disable = armada_37xx_periph_clk_disable,
444*82a248dfSMarek Behún };
445*82a248dfSMarek Behún 
446*82a248dfSMarek Behún static const struct udevice_id armada_37xx_periph_clk_ids[] = {
447*82a248dfSMarek Behún 	{
448*82a248dfSMarek Behún 		.compatible = "marvell,armada-3700-periph-clock-nb",
449*82a248dfSMarek Behún 		.data = (ulong)clks_nb,
450*82a248dfSMarek Behún 	},
451*82a248dfSMarek Behún 	{
452*82a248dfSMarek Behún 		.compatible = "marvell,armada-3700-periph-clock-sb",
453*82a248dfSMarek Behún 		.data = (ulong)clks_sb,
454*82a248dfSMarek Behún 	},
455*82a248dfSMarek Behún 	{}
456*82a248dfSMarek Behún };
457*82a248dfSMarek Behún 
458*82a248dfSMarek Behún U_BOOT_DRIVER(armada_37xx_periph_clk) = {
459*82a248dfSMarek Behún 	.name		= "armada_37xx_periph_clk",
460*82a248dfSMarek Behún 	.id		= UCLASS_CLK,
461*82a248dfSMarek Behún 	.of_match	= armada_37xx_periph_clk_ids,
462*82a248dfSMarek Behún 	.ops		= &armada_37xx_periph_clk_ops,
463*82a248dfSMarek Behún 	.priv_auto_alloc_size = sizeof(struct a37xx_periphclk),
464*82a248dfSMarek Behún 	.probe		= armada_37xx_periph_clk_probe,
465*82a248dfSMarek Behún };
466