Re: [PATCH 1/4] clk: meson: mpll: add init callback and regs

From: Stephen Boyd
Date: Tue Apr 23 2019 - 19:19:35 EST


Quoting Michael Turquette (2019-04-23 10:34:13)
> On Mon, Apr 8, 2019 at 9:38 AM Jerome Brunet <jbrunet@xxxxxxxxxxxx> wrote:
> >
> > If removing .init() is important for you, I would prefer to help guys. That
> > being said, we need a decent solution to some use case if this is going to
> > work.
> >
> > I'll illustrate with examples from the meson code but I think they represent
> > fairly common cases:
> >
> > 1) clk-pll: Without the work done init(), the pll just won't lock ...
> >
> > I agree that we would see the problem when the clock is finally enabled, so we
> > could do "init" sequence in .prepare() each time it is called. The sequence
> > might be "long" (with a couple of delays in it) so doing it on each call to
> > .prepare() is wasting time but it could work.
> >
> > Something like .prepare_once would help for this.
> >
> > 2) clk-mpll: Without the work done in .init(), the fractional part of the
> > divider will not work, only the integer part works => the rate calculated is
> > off by a significant margin. IOW, until the initial setup is done, the result
> > of .recalc_rate() is off and cannot be trusted.
> >
> > .prepare() (and .prepare_once() if called a the same stage) is too late. We
> > would need something that runs before any call to .recalc_rate() is made.
> >
> > We could also think about clocks with the ability to observe and feedback
> > (read-only) on the actual output signal. Such thing might need an initial()
> > setup as well.
> >
> > 3) sclk: This is a kind of divider which gates when the value is zero. We need
> > to save the divider value on .disable() to restore it on .enable(). In
> > .init(), if divider value is 0 (gated) we init cached value to the maximum
> > divider value. This done so a call to .enable() works, even without prior
> > calls to .set_rate().
> >
> > Here, again, I think .prepare() is a too late.
> >
> > Maybe it is a bit extreme but we could also think about weird muxes not
> > reporting the parent accurately until some prior setting is done. For those
> > you need something that runs before all the orphan mechanism in the clock
> > register.

Well I wonder if it would work to do something on clk_get() path. At
that point, we've decided that a consumer is going to be able to use the
clk and so we can clearly define that this is the last moment to do any
final setup/configuration before handing out a pointer to a consumer.
There are still the other cases you talk about though where
.recalc_rate() wouldn't work, and we would need to do this configuration
before we calculate the rate of this clk when registering it. Seems to
be an argument for .init or the rename of it sticking around.

> >
> > Whatever the name we give it, It think it would help if we had a (not
> > discouraged) callback that is guaranteed to run before anything else is called
> > on the clock. This is what I tried to do with 541debae0adf ("clk: call the
> > clock init() callback before any other ops callback").
> >
> > Having the counterpart callback, guaranteed to run last, would allow a clock
> > to allocate (and de-allocate) stuff. It would be an interesting addition IMO.
> > For clocks which needs to store things (such as sclk), it would allow to take
> > the runtime data out of the init data.
> >
> > What about .register() and .deregister() ? It would map nicely to the CCF API
> > ?
>
> I like .register & .deregister.
>
> I propose that we merge your .init to keep things moving BUT ONLY if
> you pinky swear to follow up with .register & .deregister conversion
> and convert all existing .init users over to .register. Deal?
>
> Stephen, thoughts?
>

Ok. I'd like to see the semantics of .register and .deregister
(.unregister?) be well defined, especially around what locks are held
when the op is called (do both prepare and enable locks need to be
held?) and what state the clk is in (can it be an orphan?).
Alternatively, we can retroactively do that for the .init op and then
introduce the other ops if drivers don't need this. Then we're just
making .init more official and not shunned, which is also fine.

This crude grep only finds a few clks that use the init op.

$ git grep -W 'struct clk_ops .*=' | grep "\.init ="
drivers/clk/mmp/clk-frac.c- .init = clk_factor_init,
drivers/clk/mmp/clk-mix.c- .init = mmp_clk_mix_init,
drivers/clk/qcom/clk-hfpll.c- .init = clk_hfpll_init,
drivers/clk/rockchip/clk-pll.c- .init = rockchip_rk3036_pll_init,
drivers/clk/rockchip/clk-pll.c- .init = rockchip_rk3066_pll_init,
drivers/clk/rockchip/clk-pll.c- .init = rockchip_rk3399_pll_init,
drivers/clk/rockchip/clk.c- frac_mux->hw.init = &init;