Commit | Line | Data |
---|---|---|
df791b3e PW |
1 | /* |
2 | * clkt_clksel.c - OMAP2/3/4 clksel clock functions | |
3 | * | |
4 | * Copyright (C) 2005-2008 Texas Instruments, Inc. | |
5 | * Copyright (C) 2004-2010 Nokia Corporation | |
6 | * | |
7 | * Contacts: | |
8 | * Richard Woodruff <r-woodruff2@ti.com> | |
9 | * Paul Walmsley | |
10 | * | |
11 | * This program is free software; you can redistribute it and/or modify | |
12 | * it under the terms of the GNU General Public License version 2 as | |
13 | * published by the Free Software Foundation. | |
14 | * | |
435699db PW |
15 | * |
16 | * clksel clocks are clocks that do not have a fixed parent, or that | |
17 | * can divide their parent's rate, or possibly both at the same time, based | |
18 | * on the contents of a hardware register bitfield. | |
19 | * | |
20 | * All of the various mux and divider settings can be encoded into | |
21 | * struct clksel* data structures, and then these can be autogenerated | |
22 | * from some hardware database for each new chip generation. This | |
23 | * should avoid the need to write, review, and validate a lot of new | |
24 | * clock code for each new chip, since it can be exported from the SoC | |
25 | * design flow. This is now done on OMAP4. | |
26 | * | |
27 | * The fusion of mux and divider clocks is a software creation. In | |
28 | * hardware reality, the multiplexer (parent selection) and the | |
29 | * divider exist separately. XXX At some point these clksel clocks | |
30 | * should be split into "divider" clocks and "mux" clocks to better | |
31 | * match the hardware. | |
32 | * | |
33 | * (The name "clksel" comes from the name of the corresponding | |
34 | * register field in the OMAP2/3 family of SoCs.) | |
df791b3e PW |
35 | * |
36 | * XXX Currently these clocks are only used in the OMAP2/3/4 code, but | |
37 | * many of the OMAP1 clocks should be convertible to use this | |
38 | * mechanism. | |
39 | */ | |
40 | #undef DEBUG | |
41 | ||
42 | #include <linux/kernel.h> | |
43 | #include <linux/errno.h> | |
44 | #include <linux/clk.h> | |
45 | #include <linux/io.h> | |
46 | ||
47 | #include <plat/clock.h> | |
48 | ||
49 | #include "clock.h" | |
df791b3e PW |
50 | |
51 | /* Private functions */ | |
52 | ||
53 | /** | |
435699db | 54 | * _get_clksel_by_parent() - return clksel struct for a given clk & parent |
df791b3e PW |
55 | * @clk: OMAP struct clk ptr to inspect |
56 | * @src_clk: OMAP struct clk ptr of the parent clk to search for | |
57 | * | |
58 | * Scan the struct clksel array associated with the clock to find | |
59 | * the element associated with the supplied parent clock address. | |
60 | * Returns a pointer to the struct clksel on success or NULL on error. | |
61 | */ | |
435699db PW |
62 | static const struct clksel *_get_clksel_by_parent(struct clk *clk, |
63 | struct clk *src_clk) | |
df791b3e PW |
64 | { |
65 | const struct clksel *clks; | |
66 | ||
435699db | 67 | for (clks = clk->clksel; clks->parent; clks++) |
df791b3e PW |
68 | if (clks->parent == src_clk) |
69 | break; /* Found the requested parent */ | |
df791b3e PW |
70 | |
71 | if (!clks->parent) { | |
435699db PW |
72 | /* This indicates a data problem */ |
73 | WARN(1, "clock: Could not find parent clock %s in clksel array " | |
74 | "of clock %s\n", src_clk->name, clk->name); | |
df791b3e PW |
75 | return NULL; |
76 | } | |
77 | ||
78 | return clks; | |
79 | } | |
80 | ||
d74b4949 | 81 | /** |
435699db | 82 | * _get_div_and_fieldval() - find the new clksel divisor and field value to use |
d74b4949 PW |
83 | * @src_clk: planned new parent struct clk * |
84 | * @clk: struct clk * that is being reparented | |
85 | * @field_val: pointer to a u32 to contain the register data for the divisor | |
86 | * | |
87 | * Given an intended new parent struct clk * @src_clk, and the struct | |
88 | * clk * @clk to the clock that is being reparented, find the | |
89 | * appropriate rate divisor for the new clock (returned as the return | |
90 | * value), and the corresponding register bitfield data to program to | |
91 | * reach that divisor (returned in the u32 pointed to by @field_val). | |
92 | * Returns 0 on error, or returns the newly-selected divisor upon | |
93 | * success (in this latter case, the corresponding register bitfield | |
94 | * value is passed back in the variable pointed to by @field_val) | |
df791b3e | 95 | */ |
435699db PW |
96 | static u8 _get_div_and_fieldval(struct clk *src_clk, struct clk *clk, |
97 | u32 *field_val) | |
df791b3e PW |
98 | { |
99 | const struct clksel *clks; | |
405505c2 | 100 | const struct clksel_rate *clkr, *max_clkr = NULL; |
d74b4949 | 101 | u8 max_div = 0; |
df791b3e | 102 | |
435699db | 103 | clks = _get_clksel_by_parent(clk, src_clk); |
df791b3e PW |
104 | if (!clks) |
105 | return 0; | |
106 | ||
d74b4949 PW |
107 | /* |
108 | * Find the highest divisor (e.g., the one resulting in the | |
109 | * lowest rate) to use as the default. This should avoid | |
110 | * clock rates that are too high for the device. XXX A better | |
111 | * solution here would be to try to determine if there is a | |
112 | * divisor matching the original clock rate before the parent | |
113 | * switch, and if it cannot be found, to fall back to the | |
114 | * highest divisor. | |
115 | */ | |
df791b3e | 116 | for (clkr = clks->rates; clkr->div; clkr++) { |
d74b4949 PW |
117 | if (!(clkr->flags & cpu_mask)) |
118 | continue; | |
119 | ||
120 | if (clkr->div > max_div) { | |
121 | max_div = clkr->div; | |
122 | max_clkr = clkr; | |
123 | } | |
df791b3e PW |
124 | } |
125 | ||
d74b4949 | 126 | if (max_div == 0) { |
435699db PW |
127 | /* This indicates an error in the clksel data */ |
128 | WARN(1, "clock: Could not find divisor for clock %s parent %s" | |
129 | "\n", clk->name, src_clk->parent->name); | |
df791b3e PW |
130 | return 0; |
131 | } | |
132 | ||
d74b4949 | 133 | *field_val = max_clkr->val; |
df791b3e | 134 | |
d74b4949 | 135 | return max_div; |
df791b3e PW |
136 | } |
137 | ||
435699db PW |
138 | /** |
139 | * _write_clksel_reg() - program a clock's clksel register in hardware | |
140 | * @clk: struct clk * to program | |
141 | * @v: clksel bitfield value to program (with LSB at bit 0) | |
142 | * | |
143 | * Shift the clksel register bitfield value @v to its appropriate | |
144 | * location in the clksel register and write it in. This function | |
145 | * will ensure that the write to the clksel_reg reaches its | |
146 | * destination before returning -- important since PRM and CM register | |
147 | * accesses can be quite slow compared to ARM cycles -- but does not | |
148 | * take into account any time the hardware might take to switch the | |
149 | * clock source. | |
150 | */ | |
151 | static void _write_clksel_reg(struct clk *clk, u32 field_val) | |
152 | { | |
153 | u32 v; | |
df791b3e | 154 | |
435699db PW |
155 | v = __raw_readl(clk->clksel_reg); |
156 | v &= ~clk->clksel_mask; | |
157 | v |= field_val << __ffs(clk->clksel_mask); | |
158 | __raw_writel(v, clk->clksel_reg); | |
159 | ||
160 | v = __raw_readl(clk->clksel_reg); /* OCP barrier */ | |
161 | } | |
df791b3e PW |
162 | |
163 | /** | |
435699db PW |
164 | * _clksel_to_divisor() - turn clksel field value into integer divider |
165 | * @clk: OMAP struct clk to use | |
166 | * @field_val: register field value to find | |
df791b3e | 167 | * |
435699db PW |
168 | * Given a struct clk of a rate-selectable clksel clock, and a register field |
169 | * value to search for, find the corresponding clock divisor. The register | |
170 | * field value should be pre-masked and shifted down so the LSB is at bit 0 | |
171 | * before calling. Returns 0 on error or returns the actual integer divisor | |
172 | * upon success. | |
df791b3e | 173 | */ |
435699db | 174 | static u32 _clksel_to_divisor(struct clk *clk, u32 field_val) |
df791b3e PW |
175 | { |
176 | const struct clksel *clks; | |
177 | const struct clksel_rate *clkr; | |
df791b3e | 178 | |
435699db PW |
179 | clks = _get_clksel_by_parent(clk, clk->parent); |
180 | if (!clks) | |
181 | return 0; | |
df791b3e | 182 | |
435699db PW |
183 | for (clkr = clks->rates; clkr->div; clkr++) { |
184 | if (!(clkr->flags & cpu_mask)) | |
185 | continue; | |
df791b3e | 186 | |
435699db PW |
187 | if (clkr->val == field_val) |
188 | break; | |
df791b3e PW |
189 | } |
190 | ||
435699db PW |
191 | if (!clkr->div) { |
192 | /* This indicates a data error */ | |
193 | WARN(1, "clock: Could not find fieldval %d for clock %s parent " | |
194 | "%s\n", field_val, clk->name, clk->parent->name); | |
195 | return 0; | |
196 | } | |
df791b3e | 197 | |
435699db | 198 | return clkr->div; |
df791b3e PW |
199 | } |
200 | ||
435699db PW |
201 | /** |
202 | * _divisor_to_clksel() - turn clksel integer divisor into a field value | |
203 | * @clk: OMAP struct clk to use | |
204 | * @div: integer divisor to search for | |
205 | * | |
206 | * Given a struct clk of a rate-selectable clksel clock, and a clock | |
207 | * divisor, find the corresponding register field value. Returns the | |
208 | * register field value _before_ left-shifting (i.e., LSB is at bit | |
209 | * 0); or returns 0xFFFFFFFF (~0) upon error. | |
df791b3e | 210 | */ |
435699db | 211 | static u32 _divisor_to_clksel(struct clk *clk, u32 div) |
df791b3e | 212 | { |
435699db PW |
213 | const struct clksel *clks; |
214 | const struct clksel_rate *clkr; | |
df791b3e | 215 | |
435699db PW |
216 | /* should never happen */ |
217 | WARN_ON(div == 0); | |
df791b3e | 218 | |
435699db PW |
219 | clks = _get_clksel_by_parent(clk, clk->parent); |
220 | if (!clks) | |
221 | return ~0; | |
df791b3e | 222 | |
435699db PW |
223 | for (clkr = clks->rates; clkr->div; clkr++) { |
224 | if (!(clkr->flags & cpu_mask)) | |
225 | continue; | |
df791b3e | 226 | |
435699db PW |
227 | if (clkr->div == div) |
228 | break; | |
229 | } | |
df791b3e | 230 | |
435699db PW |
231 | if (!clkr->div) { |
232 | pr_err("clock: Could not find divisor %d for clock %s parent " | |
233 | "%s\n", div, clk->name, clk->parent->name); | |
234 | return ~0; | |
235 | } | |
236 | ||
237 | return clkr->val; | |
df791b3e PW |
238 | } |
239 | ||
240 | /** | |
435699db PW |
241 | * _read_divisor() - get current divisor applied to parent clock (from hdwr) |
242 | * @clk: OMAP struct clk to use. | |
243 | * | |
244 | * Read the current divisor register value for @clk that is programmed | |
245 | * into the hardware, convert it into the actual divisor value, and | |
246 | * return it; or return 0 on error. | |
247 | */ | |
248 | static u32 _read_divisor(struct clk *clk) | |
249 | { | |
250 | u32 v; | |
251 | ||
252 | if (!clk->clksel || !clk->clksel_mask) | |
253 | return 0; | |
254 | ||
255 | v = __raw_readl(clk->clksel_reg); | |
256 | v &= clk->clksel_mask; | |
257 | v >>= __ffs(clk->clksel_mask); | |
258 | ||
259 | return _clksel_to_divisor(clk, v); | |
260 | } | |
261 | ||
262 | /* Public functions */ | |
263 | ||
264 | /** | |
265 | * omap2_clksel_round_rate_div() - find divisor for the given clock and rate | |
df791b3e PW |
266 | * @clk: OMAP struct clk to use |
267 | * @target_rate: desired clock rate | |
268 | * @new_div: ptr to where we should store the divisor | |
269 | * | |
270 | * Finds 'best' divider value in an array based on the source and target | |
271 | * rates. The divider array must be sorted with smallest divider first. | |
435699db | 272 | * This function is also used by the DPLL3 M2 divider code. |
df791b3e PW |
273 | * |
274 | * Returns the rounded clock rate or returns 0xffffffff on error. | |
275 | */ | |
276 | u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate, | |
277 | u32 *new_div) | |
278 | { | |
279 | unsigned long test_rate; | |
280 | const struct clksel *clks; | |
281 | const struct clksel_rate *clkr; | |
282 | u32 last_div = 0; | |
283 | ||
435699db PW |
284 | if (!clk->clksel || !clk->clksel_mask) |
285 | return ~0; | |
286 | ||
df791b3e PW |
287 | pr_debug("clock: clksel_round_rate_div: %s target_rate %ld\n", |
288 | clk->name, target_rate); | |
289 | ||
290 | *new_div = 1; | |
291 | ||
435699db | 292 | clks = _get_clksel_by_parent(clk, clk->parent); |
df791b3e PW |
293 | if (!clks) |
294 | return ~0; | |
295 | ||
296 | for (clkr = clks->rates; clkr->div; clkr++) { | |
297 | if (!(clkr->flags & cpu_mask)) | |
298 | continue; | |
299 | ||
300 | /* Sanity check */ | |
301 | if (clkr->div <= last_div) | |
302 | pr_err("clock: clksel_rate table not sorted " | |
303 | "for clock %s", clk->name); | |
304 | ||
305 | last_div = clkr->div; | |
306 | ||
307 | test_rate = clk->parent->rate / clkr->div; | |
308 | ||
309 | if (test_rate <= target_rate) | |
310 | break; /* found it */ | |
311 | } | |
312 | ||
313 | if (!clkr->div) { | |
314 | pr_err("clock: Could not find divisor for target " | |
315 | "rate %ld for clock %s parent %s\n", target_rate, | |
316 | clk->name, clk->parent->name); | |
317 | return ~0; | |
318 | } | |
319 | ||
320 | *new_div = clkr->div; | |
321 | ||
322 | pr_debug("clock: new_div = %d, new_rate = %ld\n", *new_div, | |
323 | (clk->parent->rate / clkr->div)); | |
324 | ||
325 | return clk->parent->rate / clkr->div; | |
326 | } | |
327 | ||
435699db PW |
328 | /* |
329 | * Clocktype interface functions to the OMAP clock code | |
330 | * (i.e., those used in struct clk field function pointers, etc.) | |
df791b3e | 331 | */ |
df791b3e PW |
332 | |
333 | /** | |
435699db PW |
334 | * omap2_init_clksel_parent() - set a clksel clk's parent field from the hdwr |
335 | * @clk: OMAP clock struct ptr to use | |
df791b3e | 336 | * |
435699db PW |
337 | * Given a pointer @clk to a source-selectable struct clk, read the |
338 | * hardware register and determine what its parent is currently set | |
339 | * to. Update @clk's .parent field with the appropriate clk ptr. No | |
340 | * return value. | |
df791b3e | 341 | */ |
435699db | 342 | void omap2_init_clksel_parent(struct clk *clk) |
df791b3e PW |
343 | { |
344 | const struct clksel *clks; | |
345 | const struct clksel_rate *clkr; | |
435699db | 346 | u32 r, found = 0; |
df791b3e | 347 | |
435699db PW |
348 | if (!clk->clksel || !clk->clksel_mask) |
349 | return; | |
df791b3e | 350 | |
435699db PW |
351 | r = __raw_readl(clk->clksel_reg) & clk->clksel_mask; |
352 | r >>= __ffs(clk->clksel_mask); | |
df791b3e | 353 | |
435699db PW |
354 | for (clks = clk->clksel; clks->parent && !found; clks++) { |
355 | for (clkr = clks->rates; clkr->div && !found; clkr++) { | |
356 | if (!(clkr->flags & cpu_mask)) | |
357 | continue; | |
358 | ||
359 | if (clkr->val == r) { | |
360 | if (clk->parent != clks->parent) { | |
361 | pr_debug("clock: inited %s parent " | |
362 | "to %s (was %s)\n", | |
363 | clk->name, clks->parent->name, | |
364 | ((clk->parent) ? | |
365 | clk->parent->name : "NULL")); | |
366 | clk_reparent(clk, clks->parent); | |
367 | }; | |
368 | found = 1; | |
369 | } | |
370 | } | |
df791b3e PW |
371 | } |
372 | ||
435699db PW |
373 | /* This indicates a data error */ |
374 | WARN(!found, "clock: %s: init parent: could not find regval %0x\n", | |
375 | clk->name, r); | |
376 | ||
377 | return; | |
df791b3e PW |
378 | } |
379 | ||
380 | /** | |
435699db PW |
381 | * omap2_clksel_recalc() - function ptr to pass via struct clk .recalc field |
382 | * @clk: struct clk * | |
df791b3e | 383 | * |
435699db PW |
384 | * This function is intended to be called only by the clock framework. |
385 | * Each clksel clock should have its struct clk .recalc field set to this | |
386 | * function. Returns the clock's current rate, based on its parent's rate | |
387 | * and its current divisor setting in the hardware. | |
df791b3e | 388 | */ |
435699db | 389 | unsigned long omap2_clksel_recalc(struct clk *clk) |
df791b3e | 390 | { |
435699db PW |
391 | unsigned long rate; |
392 | u32 div = 0; | |
df791b3e | 393 | |
435699db PW |
394 | div = _read_divisor(clk); |
395 | if (div == 0) | |
396 | return clk->rate; | |
df791b3e | 397 | |
435699db | 398 | rate = clk->parent->rate / div; |
df791b3e | 399 | |
435699db PW |
400 | pr_debug("clock: %s: recalc'd rate is %ld (div %d)\n", clk->name, |
401 | rate, div); | |
df791b3e | 402 | |
435699db | 403 | return rate; |
df791b3e PW |
404 | } |
405 | ||
406 | /** | |
435699db PW |
407 | * omap2_clksel_round_rate() - find rounded rate for the given clock and rate |
408 | * @clk: OMAP struct clk to use | |
409 | * @target_rate: desired clock rate | |
410 | * | |
411 | * This function is intended to be called only by the clock framework. | |
412 | * Finds best target rate based on the source clock and possible dividers. | |
413 | * rates. The divider array must be sorted with smallest divider first. | |
df791b3e | 414 | * |
435699db | 415 | * Returns the rounded clock rate or returns 0xffffffff on error. |
df791b3e | 416 | */ |
435699db | 417 | long omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate) |
df791b3e | 418 | { |
435699db | 419 | u32 new_div; |
df791b3e | 420 | |
435699db | 421 | return omap2_clksel_round_rate_div(clk, target_rate, &new_div); |
df791b3e PW |
422 | } |
423 | ||
435699db PW |
424 | /** |
425 | * omap2_clksel_set_rate() - program clock rate in hardware | |
426 | * @clk: struct clk * to program rate | |
427 | * @rate: target rate to program | |
428 | * | |
429 | * This function is intended to be called only by the clock framework. | |
430 | * Program @clk's rate to @rate in the hardware. The clock can be | |
431 | * either enabled or disabled when this happens, although if the clock | |
432 | * is enabled, some downstream devices may glitch or behave | |
433 | * unpredictably when the clock rate is changed - this depends on the | |
434 | * hardware. This function does not currently check the usecount of | |
435 | * the clock, so if multiple drivers are using the clock, and the rate | |
436 | * is changed, they will all be affected without any notification. | |
437 | * Returns -EINVAL upon error, or 0 upon success. | |
438 | */ | |
df791b3e PW |
439 | int omap2_clksel_set_rate(struct clk *clk, unsigned long rate) |
440 | { | |
435699db | 441 | u32 field_val, validrate, new_div = 0; |
df791b3e | 442 | |
435699db | 443 | if (!clk->clksel || !clk->clksel_mask) |
df791b3e PW |
444 | return -EINVAL; |
445 | ||
446 | validrate = omap2_clksel_round_rate_div(clk, rate, &new_div); | |
447 | if (validrate != rate) | |
448 | return -EINVAL; | |
449 | ||
435699db | 450 | field_val = _divisor_to_clksel(clk, new_div); |
df791b3e PW |
451 | if (field_val == ~0) |
452 | return -EINVAL; | |
453 | ||
435699db | 454 | _write_clksel_reg(clk, field_val); |
df791b3e PW |
455 | |
456 | clk->rate = clk->parent->rate / new_div; | |
457 | ||
435699db PW |
458 | pr_debug("clock: %s: set rate to %ld\n", clk->name, clk->rate); |
459 | ||
df791b3e PW |
460 | return 0; |
461 | } | |
462 | ||
435699db PW |
463 | /* |
464 | * Clksel parent setting function - not passed in struct clk function | |
465 | * pointer - instead, the OMAP clock code currently assumes that any | |
466 | * parent-setting clock is a clksel clock, and calls | |
467 | * omap2_clksel_set_parent() by default | |
468 | */ | |
469 | ||
470 | /** | |
471 | * omap2_clksel_set_parent() - change a clock's parent clock | |
472 | * @clk: struct clk * of the child clock | |
473 | * @new_parent: struct clk * of the new parent clock | |
474 | * | |
475 | * This function is intended to be called only by the clock framework. | |
476 | * Change the parent clock of clock @clk to @new_parent. This is | |
477 | * intended to be used while @clk is disabled. This function does not | |
478 | * currently check the usecount of the clock, so if multiple drivers | |
479 | * are using the clock, and the parent is changed, they will all be | |
480 | * affected without any notification. Returns -EINVAL upon error, or | |
481 | * 0 upon success. | |
482 | */ | |
df791b3e PW |
483 | int omap2_clksel_set_parent(struct clk *clk, struct clk *new_parent) |
484 | { | |
435699db PW |
485 | u32 field_val = 0; |
486 | u32 parent_div; | |
df791b3e | 487 | |
d74b4949 | 488 | if (!clk->clksel || !clk->clksel_mask) |
df791b3e PW |
489 | return -EINVAL; |
490 | ||
435699db | 491 | parent_div = _get_div_and_fieldval(new_parent, clk, &field_val); |
df791b3e PW |
492 | if (!parent_div) |
493 | return -EINVAL; | |
494 | ||
435699db | 495 | _write_clksel_reg(clk, field_val); |
df791b3e | 496 | |
df791b3e PW |
497 | clk_reparent(clk, new_parent); |
498 | ||
499 | /* CLKSEL clocks follow their parents' rates, divided by a divisor */ | |
500 | clk->rate = new_parent->rate; | |
501 | ||
502 | if (parent_div > 0) | |
503 | clk->rate /= parent_div; | |
504 | ||
435699db | 505 | pr_debug("clock: %s: set parent to %s (new rate %ld)\n", |
df791b3e PW |
506 | clk->name, clk->parent->name, clk->rate); |
507 | ||
508 | return 0; | |
509 | } |