aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTony Lindgren <tony@atomide.com>2014-07-29 07:03:30 -0400
committerTony Lindgren <tony@atomide.com>2014-07-29 07:03:30 -0400
commitd40dbcd57b942528d7dbd17ace0b32136d848ecb (patch)
tree2a37983629948ff3086ad1d13d6d1612afa8478a
parent3965f5ba0489c01f419216c8909965b9a6a39388 (diff)
parent0a26344440b5f9940c99112fdc3804f073b1f5a7 (diff)
Merge tag 'for-v3.17/omap-clock-b' of git://git.kernel.org/pub/scm/linux/kernel/git/pjw/omap-pending into omap-for-v3.17/soc
Modify OMAP PLL rate rounding function to round to the exact rate requested or the next one below it. This is intended to resolve some DSS problems. Basic build, boot, and PM test results are available here: http://www.pwsan.com/omap/testlogs/clock-b-v3.17/20140725061121/
-rw-r--r--arch/arm/mach-omap2/clkt_dpll.c28
-rw-r--r--arch/arm/mach-omap2/dpll3xxx.c13
2 files changed, 32 insertions, 9 deletions
diff --git a/arch/arm/mach-omap2/clkt_dpll.c b/arch/arm/mach-omap2/clkt_dpll.c
index 3c34df0f1531..950308fa30d3 100644
--- a/arch/arm/mach-omap2/clkt_dpll.c
+++ b/arch/arm/mach-omap2/clkt_dpll.c
@@ -285,10 +285,13 @@ long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
285{ 285{
286 struct clk_hw_omap *clk = to_clk_hw_omap(hw); 286 struct clk_hw_omap *clk = to_clk_hw_omap(hw);
287 int m, n, r, scaled_max_m; 287 int m, n, r, scaled_max_m;
288 int min_delta_m = INT_MAX, min_delta_n = INT_MAX;
288 unsigned long scaled_rt_rp; 289 unsigned long scaled_rt_rp;
289 unsigned long new_rate = 0; 290 unsigned long new_rate = 0;
290 struct dpll_data *dd; 291 struct dpll_data *dd;
291 unsigned long ref_rate; 292 unsigned long ref_rate;
293 long delta;
294 long prev_min_delta = LONG_MAX;
292 const char *clk_name; 295 const char *clk_name;
293 296
294 if (!clk || !clk->dpll_data) 297 if (!clk || !clk->dpll_data)
@@ -334,23 +337,34 @@ long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
334 if (r == DPLL_MULT_UNDERFLOW) 337 if (r == DPLL_MULT_UNDERFLOW)
335 continue; 338 continue;
336 339
340 /* skip rates above our target rate */
341 delta = target_rate - new_rate;
342 if (delta < 0)
343 continue;
344
345 if (delta < prev_min_delta) {
346 prev_min_delta = delta;
347 min_delta_m = m;
348 min_delta_n = n;
349 }
350
337 pr_debug("clock: %s: m = %d: n = %d: new_rate = %lu\n", 351 pr_debug("clock: %s: m = %d: n = %d: new_rate = %lu\n",
338 clk_name, m, n, new_rate); 352 clk_name, m, n, new_rate);
339 353
340 if (target_rate == new_rate) { 354 if (delta == 0)
341 dd->last_rounded_m = m;
342 dd->last_rounded_n = n;
343 dd->last_rounded_rate = target_rate;
344 break; 355 break;
345 }
346 } 356 }
347 357
348 if (target_rate != new_rate) { 358 if (prev_min_delta == LONG_MAX) {
349 pr_debug("clock: %s: cannot round to rate %lu\n", 359 pr_debug("clock: %s: cannot round to rate %lu\n",
350 clk_name, target_rate); 360 clk_name, target_rate);
351 return ~0; 361 return ~0;
352 } 362 }
353 363
354 return target_rate; 364 dd->last_rounded_m = min_delta_m;
365 dd->last_rounded_n = min_delta_n;
366 dd->last_rounded_rate = target_rate - prev_min_delta;
367
368 return dd->last_rounded_rate;
355} 369}
356 370
diff --git a/arch/arm/mach-omap2/dpll3xxx.c b/arch/arm/mach-omap2/dpll3xxx.c
index cd5f3a0b97bd..ac3d789ac3cd 100644
--- a/arch/arm/mach-omap2/dpll3xxx.c
+++ b/arch/arm/mach-omap2/dpll3xxx.c
@@ -475,6 +475,7 @@ int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
475{ 475{
476 struct clk_hw_omap *clk = to_clk_hw_omap(hw); 476 struct clk_hw_omap *clk = to_clk_hw_omap(hw);
477 struct clk *new_parent = NULL; 477 struct clk *new_parent = NULL;
478 unsigned long rrate;
478 u16 freqsel = 0; 479 u16 freqsel = 0;
479 struct dpll_data *dd; 480 struct dpll_data *dd;
480 int ret; 481 int ret;
@@ -502,8 +503,16 @@ int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
502 __clk_prepare(dd->clk_ref); 503 __clk_prepare(dd->clk_ref);
503 clk_enable(dd->clk_ref); 504 clk_enable(dd->clk_ref);
504 505
505 if (dd->last_rounded_rate != rate) 506 /* XXX this check is probably pointless in the CCF context */
506 rate = __clk_round_rate(hw->clk, rate); 507 if (dd->last_rounded_rate != rate) {
508 rrate = __clk_round_rate(hw->clk, rate);
509 if (rrate != rate) {
510 pr_warn("%s: %s: final rate %lu does not match desired rate %lu\n",
511 __func__, __clk_get_name(hw->clk),
512 rrate, rate);
513 rate = rrate;
514 }
515 }
507 516
508 if (dd->last_rounded_rate == 0) 517 if (dd->last_rounded_rate == 0)
509 return -EINVAL; 518 return -EINVAL;