1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * TI DPLL clock support
4  *
5  * Copyright (C) 2020 Dario Binacchi <dariobin@libero.it>
6  *
7  * Loosely based on Linux kernel drivers/clk/ti/dpll.c
8  */
9 
10 #include <common.h>
11 #include <clk.h>
12 #include <clk-uclass.h>
13 #include <div64.h>
14 #include <dm.h>
15 #include <dm/device_compat.h>
16 #include <hang.h>
17 #include <asm/arch/clock.h>
18 #include <asm/arch/sys_proto.h>
19 #include <asm/io.h>
20 #include "clk.h"
21 
22 struct clk_ti_am3_dpll_drv_data {
23 	ulong max_rate;
24 };
25 
26 struct clk_ti_am3_dpll_priv {
27 	struct clk_ti_reg clkmode_reg;
28 	struct clk_ti_reg idlest_reg;
29 	struct clk_ti_reg clksel_reg;
30 	struct clk_ti_reg ssc_deltam_reg;
31 	struct clk_ti_reg ssc_modfreq_reg;
32 	struct clk clk_bypass;
33 	struct clk clk_ref;
34 	u16 last_rounded_mult;
35 	u8 last_rounded_div;
36 	u8 min_div;
37 	ulong max_rate;
38 	u32 ssc_modfreq;
39 	u32 ssc_deltam;
40 	bool ssc_downspread;
41 };
42 
clk_ti_am3_dpll_round_rate(struct clk * clk,ulong rate)43 static ulong clk_ti_am3_dpll_round_rate(struct clk *clk, ulong rate)
44 {
45 	struct clk_ti_am3_dpll_priv *priv = dev_get_priv(clk->dev);
46 	ulong ret, ref_rate, r;
47 	int m, d, err_min, err;
48 	int mult = INT_MAX, div = INT_MAX;
49 
50 	if (priv->max_rate && rate > priv->max_rate) {
51 		dev_warn(clk->dev, "%ld is to high a rate, lowered to %ld\n",
52 			 rate, priv->max_rate);
53 		rate = priv->max_rate;
54 	}
55 
56 	ret = -EFAULT;
57 	err = rate;
58 	err_min = rate;
59 	ref_rate = clk_get_rate(&priv->clk_ref);
60 	for (d = priv->min_div; err_min && d <= 128; d++) {
61 		for (m = 2; m <= 2047; m++) {
62 			r = (ref_rate * m) / d;
63 			err = abs(r - rate);
64 			if (err < err_min) {
65 				err_min = err;
66 				ret = r;
67 				mult = m;
68 				div = d;
69 
70 				if (err == 0)
71 					break;
72 			} else if (r > rate) {
73 				break;
74 			}
75 		}
76 	}
77 
78 	priv->last_rounded_mult = mult;
79 	priv->last_rounded_div = div;
80 	dev_dbg(clk->dev, "rate=%ld, min-div: %d, best_rate=%ld, mult=%d, div=%d\n",
81 		rate, priv->min_div, ret, mult, div);
82 	return ret;
83 }
84 
clk_ti_am3_dpll_clken(struct clk_ti_am3_dpll_priv * priv,u8 clken_bits)85 static void clk_ti_am3_dpll_clken(struct clk_ti_am3_dpll_priv *priv,
86 				  u8 clken_bits)
87 {
88 	u32 v;
89 
90 	v = clk_ti_readl(&priv->clkmode_reg);
91 	v &= ~CM_CLKMODE_DPLL_DPLL_EN_MASK;
92 	v |= clken_bits << CM_CLKMODE_DPLL_EN_SHIFT;
93 	clk_ti_writel(v, &priv->clkmode_reg);
94 }
95 
clk_ti_am3_dpll_state(struct clk * clk,u8 state)96 static int clk_ti_am3_dpll_state(struct clk *clk, u8 state)
97 {
98 	struct clk_ti_am3_dpll_priv *priv = dev_get_priv(clk->dev);
99 	u32 i = 0, v;
100 
101 	do {
102 		v = clk_ti_readl(&priv->idlest_reg) & ST_DPLL_CLK_MASK;
103 		if (v == state) {
104 			dev_dbg(clk->dev, "transition to '%s' in %d loops\n",
105 				state ? "locked" : "bypassed", i);
106 			return 1;
107 		}
108 
109 	} while (++i < LDELAY);
110 
111 	dev_err(clk->dev, "failed transition to '%s'\n",
112 		state ? "locked" : "bypassed");
113 	return 0;
114 }
115 
116 /**
117  * clk_ti_am3_dpll_ssc_program - set spread-spectrum clocking registers
118  * @clk:	struct clk * of DPLL to set
119  *
120  * Enable the DPLL spread spectrum clocking if frequency modulation and
121  * frequency spreading have been set, otherwise disable it.
122  */
clk_ti_am3_dpll_ssc_program(struct clk * clk)123 static void clk_ti_am3_dpll_ssc_program(struct clk *clk)
124 {
125 	struct clk_ti_am3_dpll_priv *priv = dev_get_priv(clk->dev);
126 	unsigned long ref_rate;
127 	u32 v, ctrl, mod_freq_divider, exponent, mantissa;
128 	u32 deltam_step, deltam_ceil;
129 
130 	ctrl = clk_ti_readl(&priv->clkmode_reg);
131 
132 	if (priv->ssc_modfreq && priv->ssc_deltam) {
133 		ctrl |= CM_CLKMODE_DPLL_SSC_EN_MASK;
134 
135 		if (priv->ssc_downspread)
136 			ctrl |= CM_CLKMODE_DPLL_SSC_DOWNSPREAD_MASK;
137 		else
138 			ctrl &= ~CM_CLKMODE_DPLL_SSC_DOWNSPREAD_MASK;
139 
140 		ref_rate = clk_get_rate(&priv->clk_ref);
141 		mod_freq_divider =
142 		    (ref_rate / priv->last_rounded_div) / (4 * priv->ssc_modfreq);
143 		if (priv->ssc_modfreq > (ref_rate / 70))
144 			dev_warn(clk->dev,
145 				 "clock: SSC modulation frequency of DPLL %s greater than %ld\n",
146 				 clk->dev->name, ref_rate / 70);
147 
148 		exponent = 0;
149 		mantissa = mod_freq_divider;
150 		while ((mantissa > 127) && (exponent < 7)) {
151 			exponent++;
152 			mantissa /= 2;
153 		}
154 		if (mantissa > 127)
155 			mantissa = 127;
156 
157 		v = clk_ti_readl(&priv->ssc_modfreq_reg);
158 		v &= ~(CM_SSC_MODFREQ_DPLL_MANT_MASK | CM_SSC_MODFREQ_DPLL_EXP_MASK);
159 		v |= mantissa << __ffs(CM_SSC_MODFREQ_DPLL_MANT_MASK);
160 		v |= exponent << __ffs(CM_SSC_MODFREQ_DPLL_EXP_MASK);
161 		clk_ti_writel(v, &priv->ssc_modfreq_reg);
162 		dev_dbg(clk->dev,
163 			"mod_freq_divider: %u, exponent: %u, mantissa: %u, modfreq_reg: 0x%x\n",
164 			mod_freq_divider, exponent, mantissa, v);
165 
166 		deltam_step = priv->last_rounded_mult * priv->ssc_deltam;
167 		deltam_step /= 10;
168 		if (priv->ssc_downspread)
169 			deltam_step /= 2;
170 
171 		deltam_step <<= __ffs(CM_SSC_DELTAM_DPLL_INT_MASK);
172 		deltam_step /= 100;
173 		deltam_step /= mod_freq_divider;
174 		if (deltam_step > 0xFFFFF)
175 			deltam_step = 0xFFFFF;
176 
177 		deltam_ceil = (deltam_step & CM_SSC_DELTAM_DPLL_INT_MASK) >>
178 			__ffs(CM_SSC_DELTAM_DPLL_INT_MASK);
179 		if (deltam_step & CM_SSC_DELTAM_DPLL_FRAC_MASK)
180 			deltam_ceil++;
181 
182 		if ((priv->ssc_downspread &&
183 		     ((priv->last_rounded_mult - (2 * deltam_ceil)) < 20 ||
184 		      priv->last_rounded_mult > 2045)) ||
185 		    ((priv->last_rounded_mult - deltam_ceil) < 20 ||
186 		     (priv->last_rounded_mult + deltam_ceil) > 2045))
187 			dev_warn(clk->dev,
188 				 "clock: SSC multiplier of DPLL %s is out of range\n",
189 				 clk->dev->name);
190 
191 		v = clk_ti_readl(&priv->ssc_deltam_reg);
192 		v &= ~(CM_SSC_DELTAM_DPLL_INT_MASK | CM_SSC_DELTAM_DPLL_FRAC_MASK);
193 		v |= deltam_step << __ffs(CM_SSC_DELTAM_DPLL_INT_MASK |
194 					  CM_SSC_DELTAM_DPLL_FRAC_MASK);
195 		clk_ti_writel(v, &priv->ssc_deltam_reg);
196 		dev_dbg(clk->dev,
197 			"deltam_step: %u, deltam_ceil: %u, deltam_reg: 0x%x\n",
198 			deltam_step, deltam_ceil, v);
199 	} else {
200 		ctrl &= ~CM_CLKMODE_DPLL_SSC_EN_MASK;
201 	}
202 
203 	clk_ti_writel(ctrl, &priv->clkmode_reg);
204 }
205 
clk_ti_am3_dpll_set_rate(struct clk * clk,ulong rate)206 static ulong clk_ti_am3_dpll_set_rate(struct clk *clk, ulong rate)
207 {
208 	struct clk_ti_am3_dpll_priv *priv = dev_get_priv(clk->dev);
209 	u32 v;
210 	ulong round_rate;
211 
212 	round_rate = clk_ti_am3_dpll_round_rate(clk, rate);
213 	if (IS_ERR_VALUE(round_rate))
214 		return round_rate;
215 
216 	v = clk_ti_readl(&priv->clksel_reg);
217 
218 	/* enter bypass mode */
219 	clk_ti_am3_dpll_clken(priv, DPLL_EN_MN_BYPASS);
220 
221 	/* wait for bypass mode */
222 	clk_ti_am3_dpll_state(clk, 0);
223 
224 	/* set M & N */
225 	v &= ~CM_CLKSEL_DPLL_M_MASK;
226 	v |= (priv->last_rounded_mult << CM_CLKSEL_DPLL_M_SHIFT) &
227 		CM_CLKSEL_DPLL_M_MASK;
228 
229 	v &= ~CM_CLKSEL_DPLL_N_MASK;
230 	v |= ((priv->last_rounded_div - 1) << CM_CLKSEL_DPLL_N_SHIFT) &
231 		CM_CLKSEL_DPLL_N_MASK;
232 
233 	clk_ti_writel(v, &priv->clksel_reg);
234 
235 	clk_ti_am3_dpll_ssc_program(clk);
236 
237 	/* lock dpll */
238 	clk_ti_am3_dpll_clken(priv, DPLL_EN_LOCK);
239 
240 	/* wait till the dpll locks */
241 	if (!clk_ti_am3_dpll_state(clk, ST_DPLL_CLK_MASK))
242 		hang();
243 
244 	return round_rate;
245 }
246 
clk_ti_am3_dpll_get_rate(struct clk * clk)247 static ulong clk_ti_am3_dpll_get_rate(struct clk *clk)
248 {
249 	struct clk_ti_am3_dpll_priv *priv = dev_get_priv(clk->dev);
250 	u64 rate;
251 	u32 m, n, v;
252 
253 	/* Return bypass rate if DPLL is bypassed */
254 	v = clk_ti_readl(&priv->clkmode_reg);
255 	v &= CM_CLKMODE_DPLL_EN_MASK;
256 	v >>= CM_CLKMODE_DPLL_EN_SHIFT;
257 
258 	switch (v) {
259 	case DPLL_EN_MN_BYPASS:
260 	case DPLL_EN_LOW_POWER_BYPASS:
261 	case DPLL_EN_FAST_RELOCK_BYPASS:
262 		rate = clk_get_rate(&priv->clk_bypass);
263 		dev_dbg(clk->dev, "rate=%lld\n", rate);
264 		return rate;
265 	}
266 
267 	v = clk_ti_readl(&priv->clksel_reg);
268 	m = v & CM_CLKSEL_DPLL_M_MASK;
269 	m >>= CM_CLKSEL_DPLL_M_SHIFT;
270 	n = v & CM_CLKSEL_DPLL_N_MASK;
271 	n >>= CM_CLKSEL_DPLL_N_SHIFT;
272 
273 	rate = clk_get_rate(&priv->clk_ref) * m;
274 	do_div(rate, n + 1);
275 	dev_dbg(clk->dev, "rate=%lld\n", rate);
276 	return rate;
277 }
278 
279 const struct clk_ops clk_ti_am3_dpll_ops = {
280 	.round_rate = clk_ti_am3_dpll_round_rate,
281 	.get_rate = clk_ti_am3_dpll_get_rate,
282 	.set_rate = clk_ti_am3_dpll_set_rate,
283 };
284 
clk_ti_am3_dpll_remove(struct udevice * dev)285 static int clk_ti_am3_dpll_remove(struct udevice *dev)
286 {
287 	struct clk_ti_am3_dpll_priv *priv = dev_get_priv(dev);
288 	int err;
289 
290 	err = clk_release_all(&priv->clk_bypass, 1);
291 	if (err) {
292 		dev_err(dev, "failed to release bypass clock\n");
293 		return err;
294 	}
295 
296 	err = clk_release_all(&priv->clk_ref, 1);
297 	if (err) {
298 		dev_err(dev, "failed to release reference clock\n");
299 		return err;
300 	}
301 
302 	return 0;
303 }
304 
clk_ti_am3_dpll_probe(struct udevice * dev)305 static int clk_ti_am3_dpll_probe(struct udevice *dev)
306 {
307 	struct clk_ti_am3_dpll_priv *priv = dev_get_priv(dev);
308 	int err;
309 
310 	err = clk_get_by_index(dev, 0, &priv->clk_ref);
311 	if (err) {
312 		dev_err(dev, "failed to get reference clock\n");
313 		return err;
314 	}
315 
316 	err = clk_get_by_index(dev, 1, &priv->clk_bypass);
317 	if (err) {
318 		dev_err(dev, "failed to get bypass clock\n");
319 		return err;
320 	}
321 
322 	return 0;
323 }
324 
clk_ti_am3_dpll_of_to_plat(struct udevice * dev)325 static int clk_ti_am3_dpll_of_to_plat(struct udevice *dev)
326 {
327 	struct clk_ti_am3_dpll_priv *priv = dev_get_priv(dev);
328 	struct clk_ti_am3_dpll_drv_data *data =
329 		(struct clk_ti_am3_dpll_drv_data *)dev_get_driver_data(dev);
330 	u32 min_div;
331 	int err;
332 
333 	priv->max_rate = data->max_rate;
334 
335 	err = clk_ti_get_reg_addr(dev, 0, &priv->clkmode_reg);
336 	if (err) {
337 		dev_err(dev, "failed to get clkmode register address\n");
338 		return err;
339 	}
340 
341 	err = clk_ti_get_reg_addr(dev, 1, &priv->idlest_reg);
342 	if (err) {
343 		dev_err(dev, "failed to get idlest register\n");
344 		return -EINVAL;
345 	}
346 
347 	err = clk_ti_get_reg_addr(dev, 2, &priv->clksel_reg);
348 	if (err) {
349 		dev_err(dev, "failed to get clksel register\n");
350 		return err;
351 	}
352 
353 	err = clk_ti_get_reg_addr(dev, 3, &priv->ssc_deltam_reg);
354 	if (err) {
355 		dev_err(dev, "failed to get SSC deltam register\n");
356 		return err;
357 	}
358 
359 	err = clk_ti_get_reg_addr(dev, 4, &priv->ssc_modfreq_reg);
360 	if (err) {
361 		dev_err(dev, "failed to get SSC modfreq register\n");
362 		return err;
363 	}
364 
365 	if (dev_read_u32(dev, "ti,ssc-modfreq-hz", &priv->ssc_modfreq))
366 		priv->ssc_modfreq = 0;
367 
368 	if (dev_read_u32(dev, "ti,ssc-deltam", &priv->ssc_deltam))
369 		priv->ssc_deltam = 0;
370 
371 	priv->ssc_downspread = dev_read_bool(dev, "ti,ssc-downspread");
372 
373 	if (dev_read_u32(dev, "ti,min-div", &min_div) || min_div == 0 ||
374 	    min_div > 128)
375 		priv->min_div = 1;
376 	else
377 		priv->min_div = min_div;
378 
379 	return 0;
380 }
381 
382 static const struct clk_ti_am3_dpll_drv_data dpll_no_gate_data = {
383 	.max_rate = 1000000000
384 };
385 
386 static const struct clk_ti_am3_dpll_drv_data dpll_no_gate_j_type_data = {
387 	.max_rate = 2000000000
388 };
389 
390 static const struct clk_ti_am3_dpll_drv_data dpll_core_data = {
391 	.max_rate = 1000000000
392 };
393 
394 static const struct udevice_id clk_ti_am3_dpll_of_match[] = {
395 	{.compatible = "ti,am3-dpll-core-clock",
396 	 .data = (ulong)&dpll_core_data},
397 	{.compatible = "ti,am3-dpll-no-gate-clock",
398 	 .data = (ulong)&dpll_no_gate_data},
399 	{.compatible = "ti,am3-dpll-no-gate-j-type-clock",
400 	 .data = (ulong)&dpll_no_gate_j_type_data},
401 	{}
402 };
403 
404 U_BOOT_DRIVER(clk_ti_am3_dpll) = {
405 	.name = "ti_am3_dpll_clock",
406 	.id = UCLASS_CLK,
407 	.of_match = clk_ti_am3_dpll_of_match,
408 	.of_to_plat = clk_ti_am3_dpll_of_to_plat,
409 	.probe = clk_ti_am3_dpll_probe,
410 	.remove = clk_ti_am3_dpll_remove,
411 	.priv_auto = sizeof(struct clk_ti_am3_dpll_priv),
412 	.ops = &clk_ti_am3_dpll_ops,
413 };
414