1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * TI Divider Clock |
4 | * |
5 | * Copyright (C) 2013 Texas Instruments, Inc. |
6 | * |
7 | * Tero Kristo <t-kristo@ti.com> |
8 | */ |
9 | |
10 | #include <linux/clk-provider.h> |
11 | #include <linux/slab.h> |
12 | #include <linux/err.h> |
13 | #include <linux/of.h> |
14 | #include <linux/of_address.h> |
15 | #include <linux/clk/ti.h> |
16 | #include "clock.h" |
17 | |
18 | #undef pr_fmt |
19 | #define pr_fmt(fmt) "%s: " fmt, __func__ |
20 | |
21 | static unsigned int _get_table_div(const struct clk_div_table *table, |
22 | unsigned int val) |
23 | { |
24 | const struct clk_div_table *clkt; |
25 | |
26 | for (clkt = table; clkt->div; clkt++) |
27 | if (clkt->val == val) |
28 | return clkt->div; |
29 | return 0; |
30 | } |
31 | |
32 | static void _setup_mask(struct clk_omap_divider *divider) |
33 | { |
34 | u16 mask; |
35 | u32 max_val; |
36 | const struct clk_div_table *clkt; |
37 | |
38 | if (divider->table) { |
39 | max_val = 0; |
40 | |
41 | for (clkt = divider->table; clkt->div; clkt++) |
42 | if (clkt->val > max_val) |
43 | max_val = clkt->val; |
44 | } else { |
45 | max_val = divider->max; |
46 | |
47 | if (!(divider->flags & CLK_DIVIDER_ONE_BASED) && |
48 | !(divider->flags & CLK_DIVIDER_POWER_OF_TWO)) |
49 | max_val--; |
50 | } |
51 | |
52 | if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) |
53 | mask = fls(x: max_val) - 1; |
54 | else |
55 | mask = max_val; |
56 | |
57 | divider->mask = (1 << fls(x: mask)) - 1; |
58 | } |
59 | |
60 | static unsigned int _get_div(struct clk_omap_divider *divider, unsigned int val) |
61 | { |
62 | if (divider->flags & CLK_DIVIDER_ONE_BASED) |
63 | return val; |
64 | if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) |
65 | return 1 << val; |
66 | if (divider->table) |
67 | return _get_table_div(table: divider->table, val); |
68 | return val + 1; |
69 | } |
70 | |
71 | static unsigned int _get_table_val(const struct clk_div_table *table, |
72 | unsigned int div) |
73 | { |
74 | const struct clk_div_table *clkt; |
75 | |
76 | for (clkt = table; clkt->div; clkt++) |
77 | if (clkt->div == div) |
78 | return clkt->val; |
79 | return 0; |
80 | } |
81 | |
82 | static unsigned int _get_val(struct clk_omap_divider *divider, u8 div) |
83 | { |
84 | if (divider->flags & CLK_DIVIDER_ONE_BASED) |
85 | return div; |
86 | if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) |
87 | return __ffs(div); |
88 | if (divider->table) |
89 | return _get_table_val(table: divider->table, div); |
90 | return div - 1; |
91 | } |
92 | |
93 | static unsigned long ti_clk_divider_recalc_rate(struct clk_hw *hw, |
94 | unsigned long parent_rate) |
95 | { |
96 | struct clk_omap_divider *divider = to_clk_omap_divider(hw); |
97 | unsigned int div, val; |
98 | |
99 | val = ti_clk_ll_ops->clk_readl(÷r->reg) >> divider->shift; |
100 | val &= divider->mask; |
101 | |
102 | div = _get_div(divider, val); |
103 | if (!div) { |
104 | WARN(!(divider->flags & CLK_DIVIDER_ALLOW_ZERO), |
105 | "%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n" , |
106 | clk_hw_get_name(hw)); |
107 | return parent_rate; |
108 | } |
109 | |
110 | return DIV_ROUND_UP(parent_rate, div); |
111 | } |
112 | |
113 | /* |
114 | * The reverse of DIV_ROUND_UP: The maximum number which |
115 | * divided by m is r |
116 | */ |
117 | #define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1) |
118 | |
119 | static bool _is_valid_table_div(const struct clk_div_table *table, |
120 | unsigned int div) |
121 | { |
122 | const struct clk_div_table *clkt; |
123 | |
124 | for (clkt = table; clkt->div; clkt++) |
125 | if (clkt->div == div) |
126 | return true; |
127 | return false; |
128 | } |
129 | |
130 | static bool _is_valid_div(struct clk_omap_divider *divider, unsigned int div) |
131 | { |
132 | if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) |
133 | return is_power_of_2(n: div); |
134 | if (divider->table) |
135 | return _is_valid_table_div(table: divider->table, div); |
136 | return true; |
137 | } |
138 | |
139 | static int _div_round_up(const struct clk_div_table *table, |
140 | unsigned long parent_rate, unsigned long rate) |
141 | { |
142 | const struct clk_div_table *clkt; |
143 | int up = INT_MAX; |
144 | int div = DIV_ROUND_UP_ULL((u64)parent_rate, rate); |
145 | |
146 | for (clkt = table; clkt->div; clkt++) { |
147 | if (clkt->div == div) |
148 | return clkt->div; |
149 | else if (clkt->div < div) |
150 | continue; |
151 | |
152 | if ((clkt->div - div) < (up - div)) |
153 | up = clkt->div; |
154 | } |
155 | |
156 | return up; |
157 | } |
158 | |
159 | static int _div_round(const struct clk_div_table *table, |
160 | unsigned long parent_rate, unsigned long rate) |
161 | { |
162 | if (!table) |
163 | return DIV_ROUND_UP(parent_rate, rate); |
164 | |
165 | return _div_round_up(table, parent_rate, rate); |
166 | } |
167 | |
168 | static int ti_clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, |
169 | unsigned long *best_parent_rate) |
170 | { |
171 | struct clk_omap_divider *divider = to_clk_omap_divider(hw); |
172 | int i, bestdiv = 0; |
173 | unsigned long parent_rate, best = 0, now, maxdiv; |
174 | unsigned long parent_rate_saved = *best_parent_rate; |
175 | |
176 | if (!rate) |
177 | rate = 1; |
178 | |
179 | maxdiv = divider->max; |
180 | |
181 | if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) { |
182 | parent_rate = *best_parent_rate; |
183 | bestdiv = _div_round(table: divider->table, parent_rate, rate); |
184 | bestdiv = bestdiv == 0 ? 1 : bestdiv; |
185 | bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv; |
186 | return bestdiv; |
187 | } |
188 | |
189 | /* |
190 | * The maximum divider we can use without overflowing |
191 | * unsigned long in rate * i below |
192 | */ |
193 | maxdiv = min(ULONG_MAX / rate, maxdiv); |
194 | |
195 | for (i = 1; i <= maxdiv; i++) { |
196 | if (!_is_valid_div(divider, div: i)) |
197 | continue; |
198 | if (rate * i == parent_rate_saved) { |
199 | /* |
200 | * It's the most ideal case if the requested rate can be |
201 | * divided from parent clock without needing to change |
202 | * parent rate, so return the divider immediately. |
203 | */ |
204 | *best_parent_rate = parent_rate_saved; |
205 | return i; |
206 | } |
207 | parent_rate = clk_hw_round_rate(hw: clk_hw_get_parent(hw), |
208 | MULT_ROUND_UP(rate, i)); |
209 | now = DIV_ROUND_UP(parent_rate, i); |
210 | if (now <= rate && now > best) { |
211 | bestdiv = i; |
212 | best = now; |
213 | *best_parent_rate = parent_rate; |
214 | } |
215 | } |
216 | |
217 | if (!bestdiv) { |
218 | bestdiv = divider->max; |
219 | *best_parent_rate = |
220 | clk_hw_round_rate(hw: clk_hw_get_parent(hw), rate: 1); |
221 | } |
222 | |
223 | return bestdiv; |
224 | } |
225 | |
226 | static long ti_clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, |
227 | unsigned long *prate) |
228 | { |
229 | int div; |
230 | div = ti_clk_divider_bestdiv(hw, rate, best_parent_rate: prate); |
231 | |
232 | return DIV_ROUND_UP(*prate, div); |
233 | } |
234 | |
235 | static int ti_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, |
236 | unsigned long parent_rate) |
237 | { |
238 | struct clk_omap_divider *divider; |
239 | unsigned int div, value; |
240 | u32 val; |
241 | |
242 | if (!hw || !rate) |
243 | return -EINVAL; |
244 | |
245 | divider = to_clk_omap_divider(hw); |
246 | |
247 | div = DIV_ROUND_UP(parent_rate, rate); |
248 | |
249 | if (div > divider->max) |
250 | div = divider->max; |
251 | if (div < divider->min) |
252 | div = divider->min; |
253 | |
254 | value = _get_val(divider, div); |
255 | |
256 | val = ti_clk_ll_ops->clk_readl(÷r->reg); |
257 | val &= ~(divider->mask << divider->shift); |
258 | val |= value << divider->shift; |
259 | ti_clk_ll_ops->clk_writel(val, ÷r->reg); |
260 | |
261 | ti_clk_latch(reg: ÷r->reg, shift: divider->latch); |
262 | |
263 | return 0; |
264 | } |
265 | |
266 | /** |
267 | * clk_divider_save_context - Save the divider value |
268 | * @hw: pointer struct clk_hw |
269 | * |
270 | * Save the divider value |
271 | */ |
272 | static int clk_divider_save_context(struct clk_hw *hw) |
273 | { |
274 | struct clk_omap_divider *divider = to_clk_omap_divider(hw); |
275 | u32 val; |
276 | |
277 | val = ti_clk_ll_ops->clk_readl(÷r->reg) >> divider->shift; |
278 | divider->context = val & divider->mask; |
279 | |
280 | return 0; |
281 | } |
282 | |
283 | /** |
284 | * clk_divider_restore_context - restore the saved the divider value |
285 | * @hw: pointer struct clk_hw |
286 | * |
287 | * Restore the saved the divider value |
288 | */ |
289 | static void clk_divider_restore_context(struct clk_hw *hw) |
290 | { |
291 | struct clk_omap_divider *divider = to_clk_omap_divider(hw); |
292 | u32 val; |
293 | |
294 | val = ti_clk_ll_ops->clk_readl(÷r->reg); |
295 | val &= ~(divider->mask << divider->shift); |
296 | val |= divider->context << divider->shift; |
297 | ti_clk_ll_ops->clk_writel(val, ÷r->reg); |
298 | } |
299 | |
300 | const struct clk_ops ti_clk_divider_ops = { |
301 | .recalc_rate = ti_clk_divider_recalc_rate, |
302 | .round_rate = ti_clk_divider_round_rate, |
303 | .set_rate = ti_clk_divider_set_rate, |
304 | .save_context = clk_divider_save_context, |
305 | .restore_context = clk_divider_restore_context, |
306 | }; |
307 | |
308 | static struct clk *_register_divider(struct device_node *node, |
309 | u32 flags, |
310 | struct clk_omap_divider *div) |
311 | { |
312 | struct clk_init_data init; |
313 | const char *parent_name; |
314 | const char *name; |
315 | |
316 | parent_name = of_clk_get_parent_name(np: node, index: 0); |
317 | |
318 | name = ti_dt_clk_name(np: node); |
319 | init.name = name; |
320 | init.ops = &ti_clk_divider_ops; |
321 | init.flags = flags; |
322 | init.parent_names = (parent_name ? &parent_name : NULL); |
323 | init.num_parents = (parent_name ? 1 : 0); |
324 | |
325 | div->hw.init = &init; |
326 | |
327 | /* register the clock */ |
328 | return of_ti_clk_register(node, hw: &div->hw, con: name); |
329 | } |
330 | |
331 | int ti_clk_parse_divider_data(int *div_table, int num_dividers, int max_div, |
332 | u8 flags, struct clk_omap_divider *divider) |
333 | { |
334 | int valid_div = 0; |
335 | int i; |
336 | struct clk_div_table *tmp; |
337 | u16 min_div = 0; |
338 | |
339 | if (!div_table) { |
340 | divider->min = 1; |
341 | divider->max = max_div; |
342 | _setup_mask(divider); |
343 | return 0; |
344 | } |
345 | |
346 | i = 0; |
347 | |
348 | while (!num_dividers || i < num_dividers) { |
349 | if (div_table[i] == -1) |
350 | break; |
351 | if (div_table[i]) |
352 | valid_div++; |
353 | i++; |
354 | } |
355 | |
356 | num_dividers = i; |
357 | |
358 | tmp = kcalloc(n: valid_div + 1, size: sizeof(*tmp), GFP_KERNEL); |
359 | if (!tmp) |
360 | return -ENOMEM; |
361 | |
362 | valid_div = 0; |
363 | |
364 | for (i = 0; i < num_dividers; i++) |
365 | if (div_table[i] > 0) { |
366 | tmp[valid_div].div = div_table[i]; |
367 | tmp[valid_div].val = i; |
368 | valid_div++; |
369 | if (div_table[i] > max_div) |
370 | max_div = div_table[i]; |
371 | if (!min_div || div_table[i] < min_div) |
372 | min_div = div_table[i]; |
373 | } |
374 | |
375 | divider->min = min_div; |
376 | divider->max = max_div; |
377 | divider->table = tmp; |
378 | _setup_mask(divider); |
379 | |
380 | return 0; |
381 | } |
382 | |
383 | static int __init ti_clk_get_div_table(struct device_node *node, |
384 | struct clk_omap_divider *div) |
385 | { |
386 | struct clk_div_table *table; |
387 | const __be32 *divspec; |
388 | u32 val; |
389 | u32 num_div; |
390 | u32 valid_div; |
391 | int i; |
392 | |
393 | divspec = of_get_property(node, name: "ti,dividers" , lenp: &num_div); |
394 | |
395 | if (!divspec) |
396 | return 0; |
397 | |
398 | num_div /= 4; |
399 | |
400 | valid_div = 0; |
401 | |
402 | /* Determine required size for divider table */ |
403 | for (i = 0; i < num_div; i++) { |
404 | of_property_read_u32_index(np: node, propname: "ti,dividers" , index: i, out_value: &val); |
405 | if (val) |
406 | valid_div++; |
407 | } |
408 | |
409 | if (!valid_div) { |
410 | pr_err("no valid dividers for %pOFn table\n" , node); |
411 | return -EINVAL; |
412 | } |
413 | |
414 | table = kcalloc(n: valid_div + 1, size: sizeof(*table), GFP_KERNEL); |
415 | if (!table) |
416 | return -ENOMEM; |
417 | |
418 | valid_div = 0; |
419 | |
420 | for (i = 0; i < num_div; i++) { |
421 | of_property_read_u32_index(np: node, propname: "ti,dividers" , index: i, out_value: &val); |
422 | if (val) { |
423 | table[valid_div].div = val; |
424 | table[valid_div].val = i; |
425 | valid_div++; |
426 | } |
427 | } |
428 | |
429 | div->table = table; |
430 | |
431 | return 0; |
432 | } |
433 | |
434 | static int _populate_divider_min_max(struct device_node *node, |
435 | struct clk_omap_divider *divider) |
436 | { |
437 | u32 min_div = 0; |
438 | u32 max_div = 0; |
439 | u32 val; |
440 | const struct clk_div_table *clkt; |
441 | |
442 | if (!divider->table) { |
443 | /* Clk divider table not provided, determine min/max divs */ |
444 | if (of_property_read_u32(np: node, propname: "ti,min-div" , out_value: &min_div)) |
445 | min_div = 1; |
446 | |
447 | if (of_property_read_u32(np: node, propname: "ti,max-div" , out_value: &max_div)) { |
448 | pr_err("no max-div for %pOFn!\n" , node); |
449 | return -EINVAL; |
450 | } |
451 | } else { |
452 | |
453 | for (clkt = divider->table; clkt->div; clkt++) { |
454 | val = clkt->div; |
455 | if (val > max_div) |
456 | max_div = val; |
457 | if (!min_div || val < min_div) |
458 | min_div = val; |
459 | } |
460 | } |
461 | |
462 | divider->min = min_div; |
463 | divider->max = max_div; |
464 | _setup_mask(divider); |
465 | |
466 | return 0; |
467 | } |
468 | |
469 | static int __init ti_clk_divider_populate(struct device_node *node, |
470 | struct clk_omap_divider *div, |
471 | u32 *flags) |
472 | { |
473 | u32 val; |
474 | int ret; |
475 | |
476 | ret = ti_clk_get_reg_addr(node, index: 0, reg: &div->reg); |
477 | if (ret) |
478 | return ret; |
479 | |
480 | if (!of_property_read_u32(np: node, propname: "ti,bit-shift" , out_value: &val)) |
481 | div->shift = val; |
482 | else |
483 | div->shift = 0; |
484 | |
485 | if (!of_property_read_u32(np: node, propname: "ti,latch-bit" , out_value: &val)) |
486 | div->latch = val; |
487 | else |
488 | div->latch = -EINVAL; |
489 | |
490 | *flags = 0; |
491 | div->flags = 0; |
492 | |
493 | if (of_property_read_bool(np: node, propname: "ti,index-starts-at-one" )) |
494 | div->flags |= CLK_DIVIDER_ONE_BASED; |
495 | |
496 | if (of_property_read_bool(np: node, propname: "ti,index-power-of-two" )) |
497 | div->flags |= CLK_DIVIDER_POWER_OF_TWO; |
498 | |
499 | if (of_property_read_bool(np: node, propname: "ti,set-rate-parent" )) |
500 | *flags |= CLK_SET_RATE_PARENT; |
501 | |
502 | ret = ti_clk_get_div_table(node, div); |
503 | if (ret) |
504 | return ret; |
505 | |
506 | return _populate_divider_min_max(node, divider: div); |
507 | } |
508 | |
509 | /** |
510 | * of_ti_divider_clk_setup - Setup function for simple div rate clock |
511 | * @node: device node for this clock |
512 | * |
513 | * Sets up a basic divider clock. |
514 | */ |
515 | static void __init of_ti_divider_clk_setup(struct device_node *node) |
516 | { |
517 | struct clk *clk; |
518 | u32 flags = 0; |
519 | struct clk_omap_divider *div; |
520 | |
521 | div = kzalloc(size: sizeof(*div), GFP_KERNEL); |
522 | if (!div) |
523 | return; |
524 | |
525 | if (ti_clk_divider_populate(node, div, flags: &flags)) |
526 | goto cleanup; |
527 | |
528 | clk = _register_divider(node, flags, div); |
529 | if (!IS_ERR(ptr: clk)) { |
530 | of_clk_add_provider(np: node, clk_src_get: of_clk_src_simple_get, data: clk); |
531 | of_ti_clk_autoidle_setup(node); |
532 | return; |
533 | } |
534 | |
535 | cleanup: |
536 | kfree(objp: div->table); |
537 | kfree(objp: div); |
538 | } |
539 | CLK_OF_DECLARE(divider_clk, "ti,divider-clock" , of_ti_divider_clk_setup); |
540 | |
541 | static void __init of_ti_composite_divider_clk_setup(struct device_node *node) |
542 | { |
543 | struct clk_omap_divider *div; |
544 | u32 tmp; |
545 | |
546 | div = kzalloc(size: sizeof(*div), GFP_KERNEL); |
547 | if (!div) |
548 | return; |
549 | |
550 | if (ti_clk_divider_populate(node, div, flags: &tmp)) |
551 | goto cleanup; |
552 | |
553 | if (!ti_clk_add_component(node, hw: &div->hw, type: CLK_COMPONENT_TYPE_DIVIDER)) |
554 | return; |
555 | |
556 | cleanup: |
557 | kfree(objp: div->table); |
558 | kfree(objp: div); |
559 | } |
560 | CLK_OF_DECLARE(ti_composite_divider_clk, "ti,composite-divider-clock" , |
561 | of_ti_composite_divider_clk_setup); |
562 | |