1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Marvell Armada 37xx SoC Peripheral clocks
4  *
5  * Marek Behun <marek.behun@nic.cz>
6  *
7  * Based on Linux driver by:
8  *   Gregory CLEMENT <gregory.clement@free-electrons.com>
9  */
10 
11 #include <common.h>
12 #include <malloc.h>
13 #include <clk-uclass.h>
14 #include <clk.h>
15 #include <dm.h>
16 #include <asm/io.h>
17 #include <asm/arch/cpu.h>
18 #include <dm/device_compat.h>
19 #include <linux/bitops.h>
20 
21 #define TBG_SEL		0x0
22 #define DIV_SEL0	0x4
23 #define DIV_SEL1	0x8
24 #define DIV_SEL2	0xC
25 #define CLK_SEL		0x10
26 #define CLK_DIS		0x14
27 
28 enum a37xx_periph_parent {
29 	TBG_A_P		= 0,
30 	TBG_B_P		= 1,
31 	TBG_A_S		= 2,
32 	TBG_B_S		= 3,
33 	MAX_TBG_PARENTS	= 4,
34 	XTAL		= 4,
35 	MAX_PARENTS	= 5,
36 };
37 
38 static const struct {
39 	const char *name;
40 	enum a37xx_periph_parent parent;
41 } a37xx_periph_parent_names[] = {
42 	{ "TBG-A-P", TBG_A_P },
43 	{ "TBG-B-P", TBG_B_P },
44 	{ "TBG-A-S", TBG_A_S },
45 	{ "TBG-B-S", TBG_B_S },
46 	{ "xtal",    XTAL    },
47 };
48 
49 struct clk_periph;
50 
51 struct a37xx_periphclk {
52 	void __iomem *reg;
53 
54 	ulong parents[MAX_PARENTS];
55 
56 	const struct clk_periph *clks;
57 	bool clk_has_periph_parent[16];
58 	int clk_parent[16];
59 
60 	int count;
61 };
62 
63 struct clk_div_table {
64 	u32 div;
65 	u32 val;
66 };
67 
68 struct clk_periph {
69 	const char *name;
70 
71 	const char *parent_name;
72 
73 	u32 disable_bit;
74 	int mux_shift;
75 
76 	const struct clk_div_table *div_table[2];
77 	s32 div_reg_off[2];
78 	u32 div_mask[2];
79 	int div_shift[2];
80 
81 	unsigned can_gate : 1;
82 	unsigned can_mux : 1;
83 	unsigned dividers : 2;
84 };
85 
86 static const struct clk_div_table div_table1[] = {
87 	{ 1, 1 },
88 	{ 2, 2 },
89 	{ 0, 0 },
90 };
91 
92 static const struct clk_div_table div_table2[] = {
93 	{ 2, 0 },
94 	{ 4, 1 },
95 	{ 0, 0 },
96 };
97 
98 static const struct clk_div_table div_table6[] = {
99 	{ 1, 1 },
100 	{ 2, 2 },
101 	{ 3, 3 },
102 	{ 4, 4 },
103 	{ 5, 5 },
104 	{ 6, 6 },
105 	{ 0, 0 },
106 };
107 
108 #define CLK_FULL_DD(_n, _d, _mux, _r0, _r1, _s0, _s1)	\
109 	{						\
110 		.name = #_n,				\
111 		.disable_bit = BIT(_d),			\
112 		.mux_shift = _mux,			\
113 		.div_table[0] = div_table6,		\
114 		.div_table[1] = div_table6,		\
115 		.div_reg_off[0] = _r0,			\
116 		.div_reg_off[1] = _r1,			\
117 		.div_shift[0] = _s0,			\
118 		.div_shift[1] = _s1,			\
119 		.div_mask[0] = 7,			\
120 		.div_mask[1] = 7,			\
121 		.can_gate = 1,				\
122 		.can_mux = 1,				\
123 		.dividers = 2,				\
124 	}
125 
126 #define CLK_FULL(_n, _d, _mux, _r, _s, _m, _t)	\
127 	{					\
128 		.name = #_n,			\
129 		.disable_bit = BIT(_d),		\
130 		.mux_shift = _mux,		\
131 		.div_table[0] = _t,		\
132 		.div_reg_off[0] = _r,		\
133 		.div_shift[0] = _s,		\
134 		.div_mask[0] = _m,		\
135 		.can_gate = 1,			\
136 		.can_mux = 1,			\
137 		.dividers = 1,			\
138 	}
139 
140 #define CLK_GATE_DIV(_n, _d, _r, _s, _m, _t, _p)	\
141 	{						\
142 		.name = #_n,				\
143 		.parent_name = _p,			\
144 		.disable_bit = BIT(_d),			\
145 		.div_table[0] = _t,			\
146 		.div_reg_off[0] = _r,			\
147 		.div_shift[0] = _s,			\
148 		.div_mask[0] = _m,			\
149 		.can_gate = 1,				\
150 		.dividers = 1,				\
151 	}
152 
153 #define CLK_GATE(_n, _d, _p)		\
154 	{				\
155 		.name = #_n,		\
156 		.parent_name = _p,	\
157 		.disable_bit = BIT(_d),	\
158 		.can_gate = 1,		\
159 	}
160 
161 #define CLK_MUX_DIV(_n, _mux, _r, _s, _m, _t)	\
162 	{					\
163 		.name = #_n,			\
164 		.mux_shift = _mux,		\
165 		.div_table[0] = _t,		\
166 		.div_reg_off[0] = _r,		\
167 		.div_shift[0] = _s,		\
168 		.div_mask[0] = _m,		\
169 		.can_mux = 1,			\
170 		.dividers = 1,			\
171 	}
172 
173 #define CLK_MUX_DD(_n, _mux, _r0, _r1, _s0, _s1)	\
174 	{						\
175 		.name = #_n,				\
176 		.mux_shift = _mux,			\
177 		.div_table[0] = div_table6,		\
178 		.div_table[1] = div_table6,		\
179 		.div_reg_off[0] = _r0,			\
180 		.div_reg_off[1] = _r1,			\
181 		.div_shift[0] = _s0,			\
182 		.div_shift[1] = _s1,			\
183 		.div_mask[0] = 7,			\
184 		.div_mask[1] = 7,			\
185 		.can_mux = 1,				\
186 		.dividers = 2,				\
187 	}
188 
189 /* NB periph clocks */
190 static const struct clk_periph clks_nb[] = {
191 	CLK_FULL_DD(mmc, 2, 0, DIV_SEL2, DIV_SEL2, 16, 13),
192 	CLK_FULL_DD(sata_host, 3, 2, DIV_SEL2, DIV_SEL2, 10, 7),
193 	CLK_FULL_DD(sec_at, 6, 4, DIV_SEL1, DIV_SEL1, 3, 0),
194 	CLK_FULL_DD(sec_dap, 7, 6, DIV_SEL1, DIV_SEL1, 9, 6),
195 	CLK_FULL_DD(tscem, 8, 8, DIV_SEL1, DIV_SEL1, 15, 12),
196 	CLK_FULL(tscem_tmx, 10, 10, DIV_SEL1, 18, 7, div_table6),
197 	CLK_GATE(avs, 11, "xtal"),
198 	CLK_FULL_DD(sqf, 12, 12, DIV_SEL1, DIV_SEL1, 27, 24),
199 	CLK_FULL_DD(pwm, 13, 14, DIV_SEL0, DIV_SEL0, 3, 0),
200 	CLK_GATE(i2c_2, 16, "xtal"),
201 	CLK_GATE(i2c_1, 17, "xtal"),
202 	CLK_GATE_DIV(ddr_phy, 19, DIV_SEL0, 18, 1, div_table2, "TBG-A-S"),
203 	CLK_FULL_DD(ddr_fclk, 21, 16, DIV_SEL0, DIV_SEL0, 15, 12),
204 	CLK_FULL(trace, 22, 18, DIV_SEL0, 20, 7, div_table6),
205 	CLK_FULL(counter, 23, 20, DIV_SEL0, 23, 7, div_table6),
206 	CLK_FULL_DD(eip97, 24, 24, DIV_SEL2, DIV_SEL2, 22, 19),
207 	CLK_MUX_DIV(cpu, 22, DIV_SEL0, 28, 7, div_table6),
208 	{ },
209 };
210 
211 /* SB periph clocks */
212 static const struct clk_periph clks_sb[] = {
213 	CLK_MUX_DD(gbe_50, 6, DIV_SEL2, DIV_SEL2, 6, 9),
214 	CLK_MUX_DD(gbe_core, 8, DIV_SEL1, DIV_SEL1, 18, 21),
215 	CLK_MUX_DD(gbe_125, 10, DIV_SEL1, DIV_SEL1, 6, 9),
216 	CLK_GATE(gbe1_50, 0, "gbe_50"),
217 	CLK_GATE(gbe0_50, 1, "gbe_50"),
218 	CLK_GATE(gbe1_125, 2, "gbe_125"),
219 	CLK_GATE(gbe0_125, 3, "gbe_125"),
220 	CLK_GATE_DIV(gbe1_core, 4, DIV_SEL1, 13, 1, div_table1, "gbe_core"),
221 	CLK_GATE_DIV(gbe0_core, 5, DIV_SEL1, 14, 1, div_table1, "gbe_core"),
222 	CLK_GATE_DIV(gbe_bm, 12, DIV_SEL1, 0, 1, div_table1, "gbe_core"),
223 	CLK_FULL_DD(sdio, 11, 14, DIV_SEL0, DIV_SEL0, 3, 6),
224 	CLK_FULL_DD(usb32_usb2_sys, 16, 16, DIV_SEL0, DIV_SEL0, 9, 12),
225 	CLK_FULL_DD(usb32_ss_sys, 17, 18, DIV_SEL0, DIV_SEL0, 15, 18),
226 	{ },
227 };
228 
get_mux(struct a37xx_periphclk * priv,int shift)229 static int get_mux(struct a37xx_periphclk *priv, int shift)
230 {
231 	return (readl(priv->reg + TBG_SEL) >> shift) & 3;
232 }
233 
set_mux(struct a37xx_periphclk * priv,int shift,int val)234 static void set_mux(struct a37xx_periphclk *priv, int shift, int val)
235 {
236 	u32 reg;
237 
238 	reg = readl(priv->reg + TBG_SEL);
239 	reg &= ~(3 << shift);
240 	reg |= (val & 3) << shift;
241 	writel(reg, priv->reg + TBG_SEL);
242 }
243 
244 static ulong periph_clk_get_rate(struct a37xx_periphclk *priv, int id);
245 
get_parent_rate(struct a37xx_periphclk * priv,int id)246 static ulong get_parent_rate(struct a37xx_periphclk *priv, int id)
247 {
248 	const struct clk_periph *clk = &priv->clks[id];
249 	ulong res;
250 
251 	if (clk->can_mux) {
252 		/* parent is one of TBG clocks */
253 		int tbg = get_mux(priv, clk->mux_shift);
254 
255 		res = priv->parents[tbg];
256 	} else if (priv->clk_has_periph_parent[id]) {
257 		/* parent is one of other periph clocks */
258 
259 		if (priv->clk_parent[id] >= priv->count)
260 			return -EINVAL;
261 
262 		res = periph_clk_get_rate(priv, priv->clk_parent[id]);
263 	} else {
264 		/* otherwise parent is one of TBGs or XTAL */
265 
266 		if (priv->clk_parent[id] >= MAX_PARENTS)
267 			return -EINVAL;
268 
269 		res = priv->parents[priv->clk_parent[id]];
270 	}
271 
272 	return res;
273 }
274 
get_div(struct a37xx_periphclk * priv,const struct clk_periph * clk,int idx)275 static ulong get_div(struct a37xx_periphclk *priv,
276 		     const struct clk_periph *clk, int idx)
277 {
278 	const struct clk_div_table *i;
279 	u32 reg;
280 
281 	reg = readl(priv->reg + clk->div_reg_off[idx]);
282 	reg = (reg >> clk->div_shift[idx]) & clk->div_mask[idx];
283 
284 	/* find divisor for register value val */
285 	for (i = clk->div_table[idx]; i && i->div != 0; ++i)
286 		if (i->val == reg)
287 			return i->div;
288 
289 	return 0;
290 }
291 
set_div_val(struct a37xx_periphclk * priv,const struct clk_periph * clk,int idx,int val)292 static void set_div_val(struct a37xx_periphclk *priv,
293 			const struct clk_periph *clk, int idx, int val)
294 {
295 	u32 reg;
296 
297 	reg = readl(priv->reg + clk->div_reg_off[idx]);
298 	reg &= ~(clk->div_mask[idx] << clk->div_shift[idx]);
299 	reg |= (val & clk->div_mask[idx]) << clk->div_shift[idx];
300 	writel(reg, priv->reg + clk->div_reg_off[idx]);
301 }
302 
periph_clk_get_rate(struct a37xx_periphclk * priv,int id)303 static ulong periph_clk_get_rate(struct a37xx_periphclk *priv, int id)
304 {
305 	const struct clk_periph *clk = &priv->clks[id];
306 	ulong rate, div;
307 	int i;
308 
309 	rate = get_parent_rate(priv, id);
310 	if (rate == -EINVAL)
311 		return -EINVAL;
312 
313 	/* divide the parent rate by dividers */
314 	div = 1;
315 	for (i = 0; i < clk->dividers; ++i)
316 		div *= get_div(priv, clk, i);
317 
318 	if (!div)
319 		return 0;
320 
321 	return DIV_ROUND_UP(rate, div);
322 }
323 
armada_37xx_periph_clk_get_rate(struct clk * clk)324 static ulong armada_37xx_periph_clk_get_rate(struct clk *clk)
325 {
326 	struct a37xx_periphclk *priv = dev_get_priv(clk->dev);
327 
328 	if (clk->id >= priv->count)
329 		return -EINVAL;
330 
331 	return periph_clk_get_rate(priv, clk->id);
332 }
333 
periph_clk_enable(struct clk * clk,int enable)334 static int periph_clk_enable(struct clk *clk, int enable)
335 {
336 	struct a37xx_periphclk *priv = dev_get_priv(clk->dev);
337 	const struct clk_periph *periph_clk = &priv->clks[clk->id];
338 
339 	if (clk->id >= priv->count)
340 		return -EINVAL;
341 
342 	if (!periph_clk->can_gate)
343 		return -ENOTSUPP;
344 
345 	if (enable)
346 		clrbits_le32(priv->reg + CLK_DIS, periph_clk->disable_bit);
347 	else
348 		setbits_le32(priv->reg + CLK_DIS, periph_clk->disable_bit);
349 
350 	return 0;
351 }
352 
armada_37xx_periph_clk_enable(struct clk * clk)353 static int armada_37xx_periph_clk_enable(struct clk *clk)
354 {
355 	return periph_clk_enable(clk, 1);
356 }
357 
armada_37xx_periph_clk_disable(struct clk * clk)358 static int armada_37xx_periph_clk_disable(struct clk *clk)
359 {
360 	return periph_clk_enable(clk, 0);
361 }
362 
363 #define diff(a, b) abs((long)(a) - (long)(b))
364 
find_best_div(const struct clk_div_table * t0,const struct clk_div_table * t1,ulong parent_rate,ulong req_rate,int * v0,int * v1)365 static ulong find_best_div(const struct clk_div_table *t0,
366 			   const struct clk_div_table *t1, ulong parent_rate,
367 			   ulong req_rate, int *v0, int *v1)
368 {
369 	const struct clk_div_table *i, *j;
370 	ulong rate, best_rate = 0;
371 
372 	for (i = t0; i && i->div; ++i) {
373 		for (j = t1; j && j->div; ++j) {
374 			rate = DIV_ROUND_UP(parent_rate, i->div * j->div);
375 
376 			if (!best_rate ||
377 			    diff(rate, req_rate) < diff(best_rate, req_rate)) {
378 				best_rate = rate;
379 				*v0 = i->val;
380 				*v1 = j->val;
381 			}
382 		}
383 	}
384 
385 	return best_rate;
386 }
387 
armada_37xx_periph_clk_set_rate(struct clk * clk,ulong req_rate)388 static ulong armada_37xx_periph_clk_set_rate(struct clk *clk, ulong req_rate)
389 {
390 	struct a37xx_periphclk *priv = dev_get_priv(clk->dev);
391 	const struct clk_periph *periph_clk = &priv->clks[clk->id];
392 	ulong rate, old_rate, parent_rate;
393 	int div_val0 = 0, div_val1 = 0;
394 	const struct clk_div_table *t1;
395 	static const struct clk_div_table empty_table[2] = {
396 		{ 1, 0 },
397 		{ 0, 0 }
398 	};
399 
400 	if (clk->id > priv->count)
401 		return -EINVAL;
402 
403 	old_rate = periph_clk_get_rate(priv, clk->id);
404 	if (old_rate == -EINVAL)
405 		return -EINVAL;
406 
407 	if (old_rate == req_rate)
408 		return old_rate;
409 
410 	if (!periph_clk->can_gate || !periph_clk->dividers)
411 		return -ENOTSUPP;
412 
413 	parent_rate = get_parent_rate(priv, clk->id);
414 	if (parent_rate == -EINVAL)
415 		return -EINVAL;
416 
417 	t1 = empty_table;
418 	if (periph_clk->dividers > 1)
419 		t1 = periph_clk->div_table[1];
420 
421 	rate = find_best_div(periph_clk->div_table[0], t1, parent_rate,
422 			     req_rate, &div_val0, &div_val1);
423 
424 	periph_clk_enable(clk, 0);
425 
426 	set_div_val(priv, periph_clk, 0, div_val0);
427 	if (periph_clk->dividers > 1)
428 		set_div_val(priv, periph_clk, 1, div_val1);
429 
430 	periph_clk_enable(clk, 1);
431 
432 	return rate;
433 }
434 
armada_37xx_periph_clk_set_parent(struct clk * clk,struct clk * parent)435 static int armada_37xx_periph_clk_set_parent(struct clk *clk,
436 					     struct clk *parent)
437 {
438 	struct a37xx_periphclk *priv = dev_get_priv(clk->dev);
439 	const struct clk_periph *periph_clk = &priv->clks[clk->id];
440 	struct clk check_parent;
441 	int ret;
442 
443 	/* We also check if parent is our TBG clock */
444 	if (clk->id > priv->count || parent->id >= MAX_TBG_PARENTS)
445 		return -EINVAL;
446 
447 	if (!periph_clk->can_mux || !periph_clk->can_gate)
448 		return -ENOTSUPP;
449 
450 	ret = clk_get_by_index(clk->dev, 0, &check_parent);
451 	if (ret < 0)
452 		return ret;
453 
454 	if (parent->dev != check_parent.dev)
455 		ret = -EINVAL;
456 
457 	clk_free(&check_parent);
458 	if (ret < 0)
459 		return ret;
460 
461 	periph_clk_enable(clk, 0);
462 	set_mux(priv, periph_clk->mux_shift, parent->id);
463 	periph_clk_enable(clk, 1);
464 
465 	return 0;
466 }
467 
468 #if defined(CONFIG_CMD_CLK) && defined(CONFIG_CLK_ARMADA_3720)
armada_37xx_periph_clk_dump(struct udevice * dev)469 static int armada_37xx_periph_clk_dump(struct udevice *dev)
470 {
471 	struct a37xx_periphclk *priv = dev_get_priv(dev);
472 	const struct clk_periph *clks;
473 	int i;
474 
475 	if (!priv)
476 		return -ENODEV;
477 
478 	clks = priv->clks;
479 
480 	for (i = 0; i < priv->count; ++i)
481 		printf("  %s at %lu Hz\n", clks[i].name,
482 		       periph_clk_get_rate(priv, i));
483 	printf("\n");
484 
485 	return 0;
486 }
487 
clk_dump(const char * name,int (* func)(struct udevice *))488 static int clk_dump(const char *name, int (*func)(struct udevice *))
489 {
490 	struct udevice *dev;
491 
492 	if (uclass_get_device_by_name(UCLASS_CLK, name, &dev)) {
493 		printf("Cannot find device %s\n", name);
494 		return -ENODEV;
495 	}
496 
497 	return func(dev);
498 }
499 
500 int armada_37xx_tbg_clk_dump(struct udevice *);
501 
soc_clk_dump(void)502 int soc_clk_dump(void)
503 {
504 	printf("  xtal at %u000000 Hz\n\n", get_ref_clk());
505 
506 	if (clk_dump("tbg@13200", armada_37xx_tbg_clk_dump))
507 		return 1;
508 
509 	if (clk_dump("nb-periph-clk@13000",
510 		     armada_37xx_periph_clk_dump))
511 		return 1;
512 
513 	if (clk_dump("sb-periph-clk@18000",
514 		     armada_37xx_periph_clk_dump))
515 		return 1;
516 
517 	return 0;
518 }
519 #endif
520 
armada_37xx_periph_clk_probe(struct udevice * dev)521 static int armada_37xx_periph_clk_probe(struct udevice *dev)
522 {
523 	struct a37xx_periphclk *priv = dev_get_priv(dev);
524 	const struct clk_periph *clks;
525 	int ret, i;
526 
527 	clks = (const struct clk_periph *)dev_get_driver_data(dev);
528 	if (!clks)
529 		return -ENODEV;
530 
531 	priv->reg = dev_read_addr_ptr(dev);
532 	if (!priv->reg) {
533 		dev_err(dev, "no io address\n");
534 		return -ENODEV;
535 	}
536 
537 	/* count clk_periph nodes */
538 	priv->count = 0;
539 	while (clks[priv->count].name)
540 		priv->count++;
541 
542 	priv->clks = clks;
543 
544 	/* assign parent IDs to nodes which have non-NULL parent_name */
545 	for (i = 0; i < priv->count; ++i) {
546 		int j;
547 
548 		if (!clks[i].parent_name)
549 			continue;
550 
551 		/* first try if parent_name is one of TBGs or XTAL */
552 		for (j = 0; j < MAX_PARENTS; ++j)
553 			if (!strcmp(clks[i].parent_name,
554 				    a37xx_periph_parent_names[j].name))
555 				break;
556 
557 		if (j < MAX_PARENTS) {
558 			priv->clk_has_periph_parent[i] = false;
559 			priv->clk_parent[i] =
560 				a37xx_periph_parent_names[j].parent;
561 			continue;
562 		}
563 
564 		/* else parent_name should be one of other periph clocks */
565 		for (j = 0; j < priv->count; ++j) {
566 			if (!strcmp(clks[i].parent_name, clks[j].name))
567 				break;
568 		}
569 
570 		if (j < priv->count) {
571 			priv->clk_has_periph_parent[i] = true;
572 			priv->clk_parent[i] = j;
573 			continue;
574 		}
575 
576 		dev_err(dev, "undefined parent %s\n", clks[i].parent_name);
577 		return -EINVAL;
578 	}
579 
580 	for (i = 0; i < MAX_PARENTS; ++i) {
581 		struct clk clk;
582 
583 		if (i == XTAL) {
584 			priv->parents[i] = get_ref_clk() * 1000000;
585 			continue;
586 		}
587 
588 		ret = clk_get_by_index(dev, i, &clk);
589 		if (ret) {
590 			dev_err(dev, "one of parent clocks (%i) missing: %i\n",
591 				i, ret);
592 			return -ENODEV;
593 		}
594 
595 		priv->parents[i] = clk_get_rate(&clk);
596 		clk_free(&clk);
597 	}
598 
599 	return 0;
600 }
601 
602 static const struct clk_ops armada_37xx_periph_clk_ops = {
603 	.get_rate = armada_37xx_periph_clk_get_rate,
604 	.set_rate = armada_37xx_periph_clk_set_rate,
605 	.set_parent = armada_37xx_periph_clk_set_parent,
606 	.enable = armada_37xx_periph_clk_enable,
607 	.disable = armada_37xx_periph_clk_disable,
608 };
609 
610 static const struct udevice_id armada_37xx_periph_clk_ids[] = {
611 	{
612 		.compatible = "marvell,armada-3700-periph-clock-nb",
613 		.data = (ulong)clks_nb,
614 	},
615 	{
616 		.compatible = "marvell,armada-3700-periph-clock-sb",
617 		.data = (ulong)clks_sb,
618 	},
619 	{}
620 };
621 
622 U_BOOT_DRIVER(armada_37xx_periph_clk) = {
623 	.name		= "armada_37xx_periph_clk",
624 	.id		= UCLASS_CLK,
625 	.of_match	= armada_37xx_periph_clk_ids,
626 	.ops		= &armada_37xx_periph_clk_ops,
627 	.priv_auto	= sizeof(struct a37xx_periphclk),
628 	.probe		= armada_37xx_periph_clk_probe,
629 };
630