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 clk_bypass;
31 	struct clk clk_ref;
32 	u16 last_rounded_mult;
33 	u8 last_rounded_div;
34 	ulong max_rate;
35 };
36 
clk_ti_am3_dpll_round_rate(struct clk * clk,ulong rate)37 static ulong clk_ti_am3_dpll_round_rate(struct clk *clk, ulong rate)
38 {
39 	struct clk_ti_am3_dpll_priv *priv = dev_get_priv(clk->dev);
40 	ulong ret, ref_rate, r;
41 	int m, d, err_min, err;
42 	int mult = INT_MAX, div = INT_MAX;
43 
44 	if (priv->max_rate && rate > priv->max_rate) {
45 		dev_warn(clk->dev, "%ld is to high a rate, lowered to %ld\n",
46 			 rate, priv->max_rate);
47 		rate = priv->max_rate;
48 	}
49 
50 	ret = -EFAULT;
51 	err = rate;
52 	err_min = rate;
53 	ref_rate = clk_get_rate(&priv->clk_ref);
54 	for (d = 1; err_min && d <= 128; d++) {
55 		for (m = 2; m <= 2047; m++) {
56 			r = (ref_rate * m) / d;
57 			err = abs(r - rate);
58 			if (err < err_min) {
59 				err_min = err;
60 				ret = r;
61 				mult = m;
62 				div = d;
63 
64 				if (err == 0)
65 					break;
66 			} else if (r > rate) {
67 				break;
68 			}
69 		}
70 	}
71 
72 	priv->last_rounded_mult = mult;
73 	priv->last_rounded_div = div;
74 	dev_dbg(clk->dev, "rate=%ld, best_rate=%ld, mult=%d, div=%d\n", rate,
75 		ret, mult, div);
76 	return ret;
77 }
78 
clk_ti_am3_dpll_clken(struct clk_ti_am3_dpll_priv * priv,u8 clken_bits)79 static void clk_ti_am3_dpll_clken(struct clk_ti_am3_dpll_priv *priv,
80 				  u8 clken_bits)
81 {
82 	u32 v;
83 
84 	v = clk_ti_readl(&priv->clkmode_reg);
85 	v &= ~CM_CLKMODE_DPLL_DPLL_EN_MASK;
86 	v |= clken_bits << CM_CLKMODE_DPLL_EN_SHIFT;
87 	clk_ti_writel(v, &priv->clkmode_reg);
88 }
89 
clk_ti_am3_dpll_state(struct clk * clk,u8 state)90 static int clk_ti_am3_dpll_state(struct clk *clk, u8 state)
91 {
92 	struct clk_ti_am3_dpll_priv *priv = dev_get_priv(clk->dev);
93 	u32 i = 0, v;
94 
95 	do {
96 		v = clk_ti_readl(&priv->idlest_reg) & ST_DPLL_CLK_MASK;
97 		if (v == state) {
98 			dev_dbg(clk->dev, "transition to '%s' in %d loops\n",
99 				state ? "locked" : "bypassed", i);
100 			return 1;
101 		}
102 
103 	} while (++i < LDELAY);
104 
105 	dev_err(clk->dev, "failed transition to '%s'\n",
106 		state ? "locked" : "bypassed");
107 	return 0;
108 }
109 
clk_ti_am3_dpll_set_rate(struct clk * clk,ulong rate)110 static ulong clk_ti_am3_dpll_set_rate(struct clk *clk, ulong rate)
111 {
112 	struct clk_ti_am3_dpll_priv *priv = dev_get_priv(clk->dev);
113 	u32 v;
114 	ulong round_rate;
115 
116 	round_rate = clk_ti_am3_dpll_round_rate(clk, rate);
117 	if (IS_ERR_VALUE(round_rate))
118 		return round_rate;
119 
120 	v = clk_ti_readl(&priv->clksel_reg);
121 
122 	/* enter bypass mode */
123 	clk_ti_am3_dpll_clken(priv, DPLL_EN_MN_BYPASS);
124 
125 	/* wait for bypass mode */
126 	clk_ti_am3_dpll_state(clk, 0);
127 
128 	/* set M & N */
129 	v &= ~CM_CLKSEL_DPLL_M_MASK;
130 	v |= (priv->last_rounded_mult << CM_CLKSEL_DPLL_M_SHIFT) &
131 		CM_CLKSEL_DPLL_M_MASK;
132 
133 	v &= ~CM_CLKSEL_DPLL_N_MASK;
134 	v |= ((priv->last_rounded_div - 1) << CM_CLKSEL_DPLL_N_SHIFT) &
135 		CM_CLKSEL_DPLL_N_MASK;
136 
137 	clk_ti_writel(v, &priv->clksel_reg);
138 
139 	/* lock dpll */
140 	clk_ti_am3_dpll_clken(priv, DPLL_EN_LOCK);
141 
142 	/* wait till the dpll locks */
143 	if (!clk_ti_am3_dpll_state(clk, ST_DPLL_CLK_MASK))
144 		hang();
145 
146 	return round_rate;
147 }
148 
clk_ti_am3_dpll_get_rate(struct clk * clk)149 static ulong clk_ti_am3_dpll_get_rate(struct clk *clk)
150 {
151 	struct clk_ti_am3_dpll_priv *priv = dev_get_priv(clk->dev);
152 	u64 rate;
153 	u32 m, n, v;
154 
155 	/* Return bypass rate if DPLL is bypassed */
156 	v = clk_ti_readl(&priv->clkmode_reg);
157 	v &= CM_CLKMODE_DPLL_EN_MASK;
158 	v >>= CM_CLKMODE_DPLL_EN_SHIFT;
159 
160 	switch (v) {
161 	case DPLL_EN_MN_BYPASS:
162 	case DPLL_EN_LOW_POWER_BYPASS:
163 	case DPLL_EN_FAST_RELOCK_BYPASS:
164 		rate = clk_get_rate(&priv->clk_bypass);
165 		dev_dbg(clk->dev, "rate=%lld\n", rate);
166 		return rate;
167 	}
168 
169 	v = clk_ti_readl(&priv->clksel_reg);
170 	m = v & CM_CLKSEL_DPLL_M_MASK;
171 	m >>= CM_CLKSEL_DPLL_M_SHIFT;
172 	n = v & CM_CLKSEL_DPLL_N_MASK;
173 	n >>= CM_CLKSEL_DPLL_N_SHIFT;
174 
175 	rate = clk_get_rate(&priv->clk_ref) * m;
176 	do_div(rate, n + 1);
177 	dev_dbg(clk->dev, "rate=%lld\n", rate);
178 	return rate;
179 }
180 
181 const struct clk_ops clk_ti_am3_dpll_ops = {
182 	.round_rate = clk_ti_am3_dpll_round_rate,
183 	.get_rate = clk_ti_am3_dpll_get_rate,
184 	.set_rate = clk_ti_am3_dpll_set_rate,
185 };
186 
clk_ti_am3_dpll_remove(struct udevice * dev)187 static int clk_ti_am3_dpll_remove(struct udevice *dev)
188 {
189 	struct clk_ti_am3_dpll_priv *priv = dev_get_priv(dev);
190 	int err;
191 
192 	err = clk_release_all(&priv->clk_bypass, 1);
193 	if (err) {
194 		dev_err(dev, "failed to release bypass clock\n");
195 		return err;
196 	}
197 
198 	err = clk_release_all(&priv->clk_ref, 1);
199 	if (err) {
200 		dev_err(dev, "failed to release reference clock\n");
201 		return err;
202 	}
203 
204 	return 0;
205 }
206 
clk_ti_am3_dpll_probe(struct udevice * dev)207 static int clk_ti_am3_dpll_probe(struct udevice *dev)
208 {
209 	struct clk_ti_am3_dpll_priv *priv = dev_get_priv(dev);
210 	int err;
211 
212 	err = clk_get_by_index(dev, 0, &priv->clk_ref);
213 	if (err) {
214 		dev_err(dev, "failed to get reference clock\n");
215 		return err;
216 	}
217 
218 	err = clk_get_by_index(dev, 1, &priv->clk_bypass);
219 	if (err) {
220 		dev_err(dev, "failed to get bypass clock\n");
221 		return err;
222 	}
223 
224 	return 0;
225 }
226 
clk_ti_am3_dpll_of_to_plat(struct udevice * dev)227 static int clk_ti_am3_dpll_of_to_plat(struct udevice *dev)
228 {
229 	struct clk_ti_am3_dpll_priv *priv = dev_get_priv(dev);
230 	struct clk_ti_am3_dpll_drv_data *data =
231 		(struct clk_ti_am3_dpll_drv_data *)dev_get_driver_data(dev);
232 	int err;
233 
234 	priv->max_rate = data->max_rate;
235 
236 	err = clk_ti_get_reg_addr(dev, 0, &priv->clkmode_reg);
237 	if (err) {
238 		dev_err(dev, "failed to get clkmode register address\n");
239 		return err;
240 	}
241 
242 	err = clk_ti_get_reg_addr(dev, 1, &priv->idlest_reg);
243 	if (err) {
244 		dev_err(dev, "failed to get idlest register\n");
245 		return -EINVAL;
246 	}
247 
248 	err = clk_ti_get_reg_addr(dev, 2, &priv->clksel_reg);
249 	if (err) {
250 		dev_err(dev, "failed to get clksel register\n");
251 		return err;
252 	}
253 
254 	return 0;
255 }
256 
257 static const struct clk_ti_am3_dpll_drv_data dpll_no_gate_data = {
258 	.max_rate = 1000000000
259 };
260 
261 static const struct clk_ti_am3_dpll_drv_data dpll_no_gate_j_type_data = {
262 	.max_rate = 2000000000
263 };
264 
265 static const struct clk_ti_am3_dpll_drv_data dpll_core_data = {
266 	.max_rate = 1000000000
267 };
268 
269 static const struct udevice_id clk_ti_am3_dpll_of_match[] = {
270 	{.compatible = "ti,am3-dpll-core-clock",
271 	 .data = (ulong)&dpll_core_data},
272 	{.compatible = "ti,am3-dpll-no-gate-clock",
273 	 .data = (ulong)&dpll_no_gate_data},
274 	{.compatible = "ti,am3-dpll-no-gate-j-type-clock",
275 	 .data = (ulong)&dpll_no_gate_j_type_data},
276 	{}
277 };
278 
279 U_BOOT_DRIVER(clk_ti_am3_dpll) = {
280 	.name = "ti_am3_dpll_clock",
281 	.id = UCLASS_CLK,
282 	.of_match = clk_ti_am3_dpll_of_match,
283 	.of_to_plat = clk_ti_am3_dpll_of_to_plat,
284 	.probe = clk_ti_am3_dpll_probe,
285 	.remove = clk_ti_am3_dpll_remove,
286 	.priv_auto = sizeof(struct clk_ti_am3_dpll_priv),
287 	.ops = &clk_ti_am3_dpll_ops,
288 };
289