[PATCH] ARM: OMAP: dpll: enable bypass clock only when attempting dpll bypass
Mike Turquette
mturquette at linaro.org
Fri Mar 29 13:24:28 EDT 2013
Quoting Rajendra Nayak (2013-03-28 22:26:05)
> On Thursday 28 March 2013 10:02 PM, Mike Turquette wrote:
> > Quoting Rajendra Nayak (2013-03-28 03:59:41)
> >> 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.
> >>
> >
> > Hi Rajendra,
> >
> > Another way to solve this problem would be to model the DPLLs as mux
> > clocks with a list of possible parents (e.g. clk->parents[2]). Then set
> > the CLK_SET_RATE_PARENT flag on the USB DPLL which will allow to
>
> But isn't this applicable only to the _current_ parent? The bypass_clk isn't
> the parent of DPLL USB when I try a .set_rate on it. Its the ref_clk.
>
Oops. Yeah, I got that one mixed up.
Another interesting idea is for the .prepare of a DPLL to check to see
if M/N values have been populated or not, and if they are not populated
then to put some known-good defaults in there.
But this is just kicking around ideas really and I'm not nacking this
patch based on the above idea.
Regards,
Mike
> > propagate the rate request up to the ABE DPLL. This should set the MN
> > dividers appropriately.
> >
> >> Reported-by: Roger Quadros <rogerq at ti.com>
> >> Signed-off-by: Rajendra Nayak <rnayak at ti.com>
> >> ---
> >> arch/arm/mach-omap2/dpll3xxx.c | 19 +++++++++----------
> >> 1 file changed, 9 insertions(+), 10 deletions(-)
> >>
> >> diff --git a/arch/arm/mach-omap2/dpll3xxx.c b/arch/arm/mach-omap2/dpll3xxx.c
> >> index 3aed4b0..6e9873f 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,
> >> if (!dd)
> >> return -EINVAL;
> >>
> >> - __clk_prepare(dd->clk_bypass);
> >> - clk_enable(dd->clk_bypass);
> >> - __clk_prepare(dd->clk_ref);
> >> - clk_enable(dd->clk_ref);
> >
> > Is this safe? I always thought that the programming sequence in the TRM
> > was to enable both the ref and bypass clocks during DPLL reprogramming.
> > Maybe I am misremembering or assuming that the code strictly followed
> > the TRM.
>
> hmm, I didn't bother to check either. Will check, it would be strange though
> if such a sequence is indeed needed.
>
> regards,
> Rajendra
>
> >
> > Regards,
> > Mike
> >
> >> -
> >> if (__clk_get_rate(dd->clk_bypass) == rate &&
> >> (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) {
> >> pr_debug("%s: %s: set rate: entering bypass.\n",
> >> __func__, __clk_get_name(hw->clk));
> >>
> >> + __clk_prepare(dd->clk_bypass);
> >> + clk_enable(dd->clk_bypass);
> >> ret = _omap3_noncore_dpll_bypass(clk);
> >> if (!ret)
> >> new_parent = dd->clk_bypass;
> >> + clk_disable(dd->clk_bypass);
> >> + __clk_unprepare(dd->clk_bypass);
> >> } else {
> >> + __clk_prepare(dd->clk_ref);
> >> + clk_enable(dd->clk_ref);
> >> +
> >> if (dd->last_rounded_rate != rate)
> >> rate = __clk_round_rate(hw->clk, rate);
> >>
> >> @@ -514,6 +516,8 @@ int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
> >> ret = omap3_noncore_dpll_program(clk, freqsel);
> >> if (!ret)
> >> new_parent = dd->clk_ref;
> >> + clk_disable(dd->clk_ref);
> >> + __clk_unprepare(dd->clk_ref);
> >> }
> >> /*
> >> * 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,
> >> if (!ret)
> >> __clk_reparent(hw->clk, new_parent);
> >>
> >> - clk_disable(dd->clk_ref);
> >> - __clk_unprepare(dd->clk_ref);
> >> - clk_disable(dd->clk_bypass);
> >> - __clk_unprepare(dd->clk_bypass);
> >> -
> >> return 0;
> >> }
> >>
> >> --
> >> 1.7.9.5
> >>
> >> --
> >> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> >> the body of a message to majordomo at vger.kernel.org
> >> More majordomo info at http://vger.kernel.org/majordomo-info.html
More information about the linux-arm-kernel
mailing list