aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRajendra Nayak <rnayak@ti.com>2013-03-31 22:22:23 -0400
committerPaul Walmsley <paul@pwsan.com>2013-03-31 22:43:06 -0400
commit469d633d20c774ecd34ac615c838193e1e150c62 (patch)
tree3a7688f595a54562e1099fcede018fe5df6fa6d3
parentbd70f6eb3e78b7c9c6bec2cf5be6423dd2b37f6f (diff)
ARM: OMAP: dpll: enable bypass clock only when attempting dpll bypass
omap3_noncore_dpll_set_rate() attempts an enable of bypass clk as well as ref clk for every .set_rate attempt on a noncore DPLL, regardless of whether the .set_rate results in the DPLL being locked or put in bypass. Early at boot, while some of these DPLLs are programmed and locked (using .set_rate for the DPLL), this causes an ordering issue. For instance, on OMAP5, the USB DPLL derives its bypass clk from ABE DPLL. If a .set_rate of USB DPLL which programmes the M,N and locks it is called before the one for ABE, the enable of USB bypass clk (derived from ABE DPLL) then attempts to lock the ABE DPLL and fails as the M,N values for ABE are yet to be programmed. To get rid of this ordering needs, enable bypass clk for a DPLL as part of its .set_rate only when its being put in bypass, and only enable the ref clk when its locked. Reported-by: Roger Quadros <rogerq@ti.com> Signed-off-by: Rajendra Nayak <rnayak@ti.com> Signed-off-by: Paul Walmsley <paul@pwsan.com>
-rw-r--r--arch/arm/mach-omap2/dpll3xxx.c19
1 files changed, 9 insertions, 10 deletions
diff --git a/arch/arm/mach-omap2/dpll3xxx.c b/arch/arm/mach-omap2/dpll3xxx.c
index 3aed4b0b9563..6e9873ff1844 100644
--- a/arch/arm/mach-omap2/dpll3xxx.c
+++ b/arch/arm/mach-omap2/dpll3xxx.c
@@ -480,20 +480,22 @@ int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
480 if (!dd) 480 if (!dd)
481 return -EINVAL; 481 return -EINVAL;
482 482
483 __clk_prepare(dd->clk_bypass);
484 clk_enable(dd->clk_bypass);
485 __clk_prepare(dd->clk_ref);
486 clk_enable(dd->clk_ref);
487
488 if (__clk_get_rate(dd->clk_bypass) == rate && 483 if (__clk_get_rate(dd->clk_bypass) == rate &&
489 (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) { 484 (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) {
490 pr_debug("%s: %s: set rate: entering bypass.\n", 485 pr_debug("%s: %s: set rate: entering bypass.\n",
491 __func__, __clk_get_name(hw->clk)); 486 __func__, __clk_get_name(hw->clk));
492 487
488 __clk_prepare(dd->clk_bypass);
489 clk_enable(dd->clk_bypass);
493 ret = _omap3_noncore_dpll_bypass(clk); 490 ret = _omap3_noncore_dpll_bypass(clk);
494 if (!ret) 491 if (!ret)
495 new_parent = dd->clk_bypass; 492 new_parent = dd->clk_bypass;
493 clk_disable(dd->clk_bypass);
494 __clk_unprepare(dd->clk_bypass);
496 } else { 495 } else {
496 __clk_prepare(dd->clk_ref);
497 clk_enable(dd->clk_ref);
498
497 if (dd->last_rounded_rate != rate) 499 if (dd->last_rounded_rate != rate)
498 rate = __clk_round_rate(hw->clk, rate); 500 rate = __clk_round_rate(hw->clk, rate);
499 501
@@ -514,6 +516,8 @@ int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
514 ret = omap3_noncore_dpll_program(clk, freqsel); 516 ret = omap3_noncore_dpll_program(clk, freqsel);
515 if (!ret) 517 if (!ret)
516 new_parent = dd->clk_ref; 518 new_parent = dd->clk_ref;
519 clk_disable(dd->clk_ref);
520 __clk_unprepare(dd->clk_ref);
517 } 521 }
518 /* 522 /*
519 * FIXME - this is all wrong. common code handles reparenting and 523 * FIXME - this is all wrong. common code handles reparenting and
@@ -525,11 +529,6 @@ int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
525 if (!ret) 529 if (!ret)
526 __clk_reparent(hw->clk, new_parent); 530 __clk_reparent(hw->clk, new_parent);
527 531
528 clk_disable(dd->clk_ref);
529 __clk_unprepare(dd->clk_ref);
530 clk_disable(dd->clk_bypass);
531 __clk_unprepare(dd->clk_bypass);
532
533 return 0; 532 return 0;
534} 533}
535 534