1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com> |
4 | */ |
5 | |
6 | #include <linux/clk-provider.h> |
7 | #include <linux/clkdev.h> |
8 | #include <linux/clk/at91_pmc.h> |
9 | #include <linux/of.h> |
10 | #include <linux/mfd/syscon.h> |
11 | #include <linux/regmap.h> |
12 | |
13 | #include "pmc.h" |
14 | |
15 | #define PLL_STATUS_MASK(id) (1 << (1 + (id))) |
16 | #define PLL_REG(id) (AT91_CKGR_PLLAR + ((id) * 4)) |
17 | #define PLL_DIV_MASK 0xff |
18 | #define PLL_DIV_MAX PLL_DIV_MASK |
19 | #define PLL_DIV(reg) ((reg) & PLL_DIV_MASK) |
20 | #define PLL_MUL(reg, layout) (((reg) >> (layout)->mul_shift) & \ |
21 | (layout)->mul_mask) |
22 | #define PLL_MUL_MIN 2 |
23 | #define PLL_MUL_MASK(layout) ((layout)->mul_mask) |
24 | #define PLL_MUL_MAX(layout) (PLL_MUL_MASK(layout) + 1) |
25 | #define PLL_ICPR_SHIFT(id) ((id) * 16) |
26 | #define PLL_ICPR_MASK(id) (0xffff << PLL_ICPR_SHIFT(id)) |
27 | #define PLL_MAX_COUNT 0x3f |
28 | #define PLL_COUNT_SHIFT 8 |
29 | #define PLL_OUT_SHIFT 14 |
30 | #define PLL_MAX_ID 1 |
31 | |
32 | #define to_clk_pll(hw) container_of(hw, struct clk_pll, hw) |
33 | |
34 | struct clk_pll { |
35 | struct clk_hw hw; |
36 | struct regmap *regmap; |
37 | u8 id; |
38 | u8 div; |
39 | u8 range; |
40 | u16 mul; |
41 | const struct clk_pll_layout *layout; |
42 | const struct clk_pll_characteristics *characteristics; |
43 | struct at91_clk_pms pms; |
44 | }; |
45 | |
46 | static inline bool clk_pll_ready(struct regmap *regmap, int id) |
47 | { |
48 | unsigned int status; |
49 | |
50 | regmap_read(map: regmap, AT91_PMC_SR, val: &status); |
51 | |
52 | return status & PLL_STATUS_MASK(id) ? 1 : 0; |
53 | } |
54 | |
55 | static int clk_pll_prepare(struct clk_hw *hw) |
56 | { |
57 | struct clk_pll *pll = to_clk_pll(hw); |
58 | struct regmap *regmap = pll->regmap; |
59 | const struct clk_pll_layout *layout = pll->layout; |
60 | const struct clk_pll_characteristics *characteristics = |
61 | pll->characteristics; |
62 | u8 id = pll->id; |
63 | u32 mask = PLL_STATUS_MASK(id); |
64 | int offset = PLL_REG(id); |
65 | u8 out = 0; |
66 | unsigned int pllr; |
67 | unsigned int status; |
68 | u8 div; |
69 | u16 mul; |
70 | |
71 | regmap_read(map: regmap, reg: offset, val: &pllr); |
72 | div = PLL_DIV(pllr); |
73 | mul = PLL_MUL(pllr, layout); |
74 | |
75 | regmap_read(map: regmap, AT91_PMC_SR, val: &status); |
76 | if ((status & mask) && |
77 | (div == pll->div && mul == pll->mul)) |
78 | return 0; |
79 | |
80 | if (characteristics->out) |
81 | out = characteristics->out[pll->range]; |
82 | |
83 | if (characteristics->icpll) |
84 | regmap_update_bits(map: regmap, AT91_PMC_PLLICPR, PLL_ICPR_MASK(id), |
85 | val: characteristics->icpll[pll->range] << PLL_ICPR_SHIFT(id)); |
86 | |
87 | regmap_update_bits(map: regmap, reg: offset, mask: layout->pllr_mask, |
88 | val: pll->div | (PLL_MAX_COUNT << PLL_COUNT_SHIFT) | |
89 | (out << PLL_OUT_SHIFT) | |
90 | ((pll->mul & layout->mul_mask) << layout->mul_shift)); |
91 | |
92 | while (!clk_pll_ready(regmap, id: pll->id)) |
93 | cpu_relax(); |
94 | |
95 | return 0; |
96 | } |
97 | |
98 | static int clk_pll_is_prepared(struct clk_hw *hw) |
99 | { |
100 | struct clk_pll *pll = to_clk_pll(hw); |
101 | |
102 | return clk_pll_ready(regmap: pll->regmap, id: pll->id); |
103 | } |
104 | |
105 | static void clk_pll_unprepare(struct clk_hw *hw) |
106 | { |
107 | struct clk_pll *pll = to_clk_pll(hw); |
108 | unsigned int mask = pll->layout->pllr_mask; |
109 | |
110 | regmap_update_bits(map: pll->regmap, PLL_REG(pll->id), mask, val: ~mask); |
111 | } |
112 | |
113 | static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, |
114 | unsigned long parent_rate) |
115 | { |
116 | struct clk_pll *pll = to_clk_pll(hw); |
117 | |
118 | if (!pll->div || !pll->mul) |
119 | return 0; |
120 | |
121 | return (parent_rate / pll->div) * (pll->mul + 1); |
122 | } |
123 | |
124 | static long clk_pll_get_best_div_mul(struct clk_pll *pll, unsigned long rate, |
125 | unsigned long parent_rate, |
126 | u32 *div, u32 *mul, |
127 | u32 *index) { |
128 | const struct clk_pll_layout *layout = pll->layout; |
129 | const struct clk_pll_characteristics *characteristics = |
130 | pll->characteristics; |
131 | unsigned long bestremainder = ULONG_MAX; |
132 | unsigned long maxdiv, mindiv, tmpdiv; |
133 | long bestrate = -ERANGE; |
134 | unsigned long bestdiv; |
135 | unsigned long bestmul; |
136 | int i = 0; |
137 | |
138 | /* Check if parent_rate is a valid input rate */ |
139 | if (parent_rate < characteristics->input.min) |
140 | return -ERANGE; |
141 | |
142 | /* |
143 | * Calculate minimum divider based on the minimum multiplier, the |
144 | * parent_rate and the requested rate. |
145 | * Should always be 2 according to the input and output characteristics |
146 | * of the PLL blocks. |
147 | */ |
148 | mindiv = (parent_rate * PLL_MUL_MIN) / rate; |
149 | if (!mindiv) |
150 | mindiv = 1; |
151 | |
152 | if (parent_rate > characteristics->input.max) { |
153 | tmpdiv = DIV_ROUND_UP(parent_rate, characteristics->input.max); |
154 | if (tmpdiv > PLL_DIV_MAX) |
155 | return -ERANGE; |
156 | |
157 | if (tmpdiv > mindiv) |
158 | mindiv = tmpdiv; |
159 | } |
160 | |
161 | /* |
162 | * Calculate the maximum divider which is limited by PLL register |
163 | * layout (limited by the MUL or DIV field size). |
164 | */ |
165 | maxdiv = DIV_ROUND_UP(parent_rate * PLL_MUL_MAX(layout), rate); |
166 | if (maxdiv > PLL_DIV_MAX) |
167 | maxdiv = PLL_DIV_MAX; |
168 | |
169 | /* |
170 | * Iterate over the acceptable divider values to find the best |
171 | * divider/multiplier pair (the one that generates the closest |
172 | * rate to the requested one). |
173 | */ |
174 | for (tmpdiv = mindiv; tmpdiv <= maxdiv; tmpdiv++) { |
175 | unsigned long remainder; |
176 | unsigned long tmprate; |
177 | unsigned long tmpmul; |
178 | |
179 | /* |
180 | * Calculate the multiplier associated with the current |
181 | * divider that provide the closest rate to the requested one. |
182 | */ |
183 | tmpmul = DIV_ROUND_CLOSEST(rate, parent_rate / tmpdiv); |
184 | tmprate = (parent_rate / tmpdiv) * tmpmul; |
185 | if (tmprate > rate) |
186 | remainder = tmprate - rate; |
187 | else |
188 | remainder = rate - tmprate; |
189 | |
190 | /* |
191 | * Compare the remainder with the best remainder found until |
192 | * now and elect a new best multiplier/divider pair if the |
193 | * current remainder is smaller than the best one. |
194 | */ |
195 | if (remainder < bestremainder) { |
196 | bestremainder = remainder; |
197 | bestdiv = tmpdiv; |
198 | bestmul = tmpmul; |
199 | bestrate = tmprate; |
200 | } |
201 | |
202 | /* |
203 | * We've found a perfect match! |
204 | * Stop searching now and use this multiplier/divider pair. |
205 | */ |
206 | if (!remainder) |
207 | break; |
208 | } |
209 | |
210 | /* We haven't found any multiplier/divider pair => return -ERANGE */ |
211 | if (bestrate < 0) |
212 | return bestrate; |
213 | |
214 | /* Check if bestrate is a valid output rate */ |
215 | for (i = 0; i < characteristics->num_output; i++) { |
216 | if (bestrate >= characteristics->output[i].min && |
217 | bestrate <= characteristics->output[i].max) |
218 | break; |
219 | } |
220 | |
221 | if (i >= characteristics->num_output) |
222 | return -ERANGE; |
223 | |
224 | if (div) |
225 | *div = bestdiv; |
226 | if (mul) |
227 | *mul = bestmul - 1; |
228 | if (index) |
229 | *index = i; |
230 | |
231 | return bestrate; |
232 | } |
233 | |
234 | static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, |
235 | unsigned long *parent_rate) |
236 | { |
237 | struct clk_pll *pll = to_clk_pll(hw); |
238 | |
239 | return clk_pll_get_best_div_mul(pll, rate, parent_rate: *parent_rate, |
240 | NULL, NULL, NULL); |
241 | } |
242 | |
243 | static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, |
244 | unsigned long parent_rate) |
245 | { |
246 | struct clk_pll *pll = to_clk_pll(hw); |
247 | long ret; |
248 | u32 div; |
249 | u32 mul; |
250 | u32 index; |
251 | |
252 | ret = clk_pll_get_best_div_mul(pll, rate, parent_rate, |
253 | div: &div, mul: &mul, index: &index); |
254 | if (ret < 0) |
255 | return ret; |
256 | |
257 | pll->range = index; |
258 | pll->div = div; |
259 | pll->mul = mul; |
260 | |
261 | return 0; |
262 | } |
263 | |
264 | static int clk_pll_save_context(struct clk_hw *hw) |
265 | { |
266 | struct clk_pll *pll = to_clk_pll(hw); |
267 | struct clk_hw *parent_hw = clk_hw_get_parent(hw); |
268 | |
269 | pll->pms.parent_rate = clk_hw_get_rate(hw: parent_hw); |
270 | pll->pms.rate = clk_pll_recalc_rate(hw: &pll->hw, parent_rate: pll->pms.parent_rate); |
271 | pll->pms.status = clk_pll_ready(regmap: pll->regmap, PLL_REG(pll->id)); |
272 | |
273 | return 0; |
274 | } |
275 | |
276 | static void clk_pll_restore_context(struct clk_hw *hw) |
277 | { |
278 | struct clk_pll *pll = to_clk_pll(hw); |
279 | unsigned long calc_rate; |
280 | unsigned int pllr, pllr_out, pllr_count; |
281 | u8 out = 0; |
282 | |
283 | if (pll->characteristics->out) |
284 | out = pll->characteristics->out[pll->range]; |
285 | |
286 | regmap_read(map: pll->regmap, PLL_REG(pll->id), val: &pllr); |
287 | |
288 | calc_rate = (pll->pms.parent_rate / PLL_DIV(pllr)) * |
289 | (PLL_MUL(pllr, pll->layout) + 1); |
290 | pllr_count = (pllr >> PLL_COUNT_SHIFT) & PLL_MAX_COUNT; |
291 | pllr_out = (pllr >> PLL_OUT_SHIFT) & out; |
292 | |
293 | if (pll->pms.rate != calc_rate || |
294 | pll->pms.status != clk_pll_ready(regmap: pll->regmap, PLL_REG(pll->id)) || |
295 | pllr_count != PLL_MAX_COUNT || |
296 | (out && pllr_out != out)) |
297 | pr_warn("PLLAR was not configured properly by firmware\n" ); |
298 | } |
299 | |
300 | static const struct clk_ops pll_ops = { |
301 | .prepare = clk_pll_prepare, |
302 | .unprepare = clk_pll_unprepare, |
303 | .is_prepared = clk_pll_is_prepared, |
304 | .recalc_rate = clk_pll_recalc_rate, |
305 | .round_rate = clk_pll_round_rate, |
306 | .set_rate = clk_pll_set_rate, |
307 | .save_context = clk_pll_save_context, |
308 | .restore_context = clk_pll_restore_context, |
309 | }; |
310 | |
311 | struct clk_hw * __init |
312 | at91_clk_register_pll(struct regmap *regmap, const char *name, |
313 | const char *parent_name, u8 id, |
314 | const struct clk_pll_layout *layout, |
315 | const struct clk_pll_characteristics *characteristics) |
316 | { |
317 | struct clk_pll *pll; |
318 | struct clk_hw *hw; |
319 | struct clk_init_data init; |
320 | int offset = PLL_REG(id); |
321 | unsigned int pllr; |
322 | int ret; |
323 | |
324 | if (id > PLL_MAX_ID) |
325 | return ERR_PTR(error: -EINVAL); |
326 | |
327 | pll = kzalloc(size: sizeof(*pll), GFP_KERNEL); |
328 | if (!pll) |
329 | return ERR_PTR(error: -ENOMEM); |
330 | |
331 | init.name = name; |
332 | init.ops = &pll_ops; |
333 | init.parent_names = &parent_name; |
334 | init.num_parents = 1; |
335 | init.flags = CLK_SET_RATE_GATE; |
336 | |
337 | pll->id = id; |
338 | pll->hw.init = &init; |
339 | pll->layout = layout; |
340 | pll->characteristics = characteristics; |
341 | pll->regmap = regmap; |
342 | regmap_read(map: regmap, reg: offset, val: &pllr); |
343 | pll->div = PLL_DIV(pllr); |
344 | pll->mul = PLL_MUL(pllr, layout); |
345 | |
346 | hw = &pll->hw; |
347 | ret = clk_hw_register(NULL, hw: &pll->hw); |
348 | if (ret) { |
349 | kfree(objp: pll); |
350 | hw = ERR_PTR(error: ret); |
351 | } |
352 | |
353 | return hw; |
354 | } |
355 | |
356 | |
357 | const struct clk_pll_layout at91rm9200_pll_layout = { |
358 | .pllr_mask = 0x7FFFFFF, |
359 | .mul_shift = 16, |
360 | .mul_mask = 0x7FF, |
361 | }; |
362 | |
363 | const struct clk_pll_layout at91sam9g45_pll_layout = { |
364 | .pllr_mask = 0xFFFFFF, |
365 | .mul_shift = 16, |
366 | .mul_mask = 0xFF, |
367 | }; |
368 | |
369 | const struct clk_pll_layout at91sam9g20_pllb_layout = { |
370 | .pllr_mask = 0x3FFFFF, |
371 | .mul_shift = 16, |
372 | .mul_mask = 0x3F, |
373 | }; |
374 | |
375 | const struct clk_pll_layout sama5d3_pll_layout = { |
376 | .pllr_mask = 0x1FFFFFF, |
377 | .mul_shift = 18, |
378 | .mul_mask = 0x7F, |
379 | }; |
380 | |