[linux-sunxi] [PATCH 1/3] clk: sunxi: Add a driver for the CCU
Jean-Francois Moine
moinejf at free.fr
Tue Jun 28 23:51:16 PDT 2016
On Tue, 28 Jun 2016 21:31:06 +0200
Ondřej Jirman <megi at xff.cz> wrote:
>
> On 28.6.2016 17:37, Jean-Francois Moine wrote:
> > Most of the clocks in the Allwinner's SoCs are configured in the CCU
> > (Clock Configuration Unit).
> >
> > The PLL clocks are driven from the main clock. Their rates are controlled
> > by a set of multiply and divide factors, named from the Allwinner's
> > documentation:
> > - multipliers: 'n' and 'k'
> > - dividers: 'd1', 'd2', 'm' and 'p'
> >
> > The peripheral clocks may receive their inputs from one or more parents,
> > thanks to a mux. Their rates are controlled by a set of divide factors
> > only, named 'm' and 'p'.
> >
> > This driver also handles:
> > - fixed clocks,
> > - the phase delays for the MMCs,
> > - the clock gates,
> > - the bus gates,
> > - and the resets.
> >
> > Signed-off-by: Jean-Francois Moine <moinejf at free.fr>
> > ---
> > drivers/clk/sunxi/Makefile | 2 +
> > drivers/clk/sunxi/ccu.c | 980 +++++++++++++++++++++++++++++++++++++++++++++
> > drivers/clk/sunxi/ccu.h | 153 +++++++
> > 3 files changed, 1135 insertions(+)
> > create mode 100644 drivers/clk/sunxi/ccu.c
> > create mode 100644 drivers/clk/sunxi/ccu.h
[snip]
> > diff --git a/drivers/clk/sunxi/ccu.c b/drivers/clk/sunxi/ccu.c
> > new file mode 100644
> > index 0000000..5749f9c
> > --- /dev/null
> > +++ b/drivers/clk/sunxi/ccu.c
[snip]
> > +static void ccu_pll_set_flat_factors(struct ccu *ccu, u32 mask, u32 val)
> > +{
> > + u32 reg, m_val, p_val;
> > + u32 m_mask = (1 << ccu->m_width) - 1;
> > + u32 p_mask = (1 << ccu->p_width) - 1;
>
> I see you have shifted the factor values to be set in the caller of this
> function, but then you have to shift masks too, to match. It might be
> clearer to do both shifts in this function.
Oops, yes. Thanks. (I did not test yet your patch about the CPU
frequency)
> > + reg = readl(ccu->base + ccu->reg);
> > + m_val = reg & m_mask;
> > + p_val = reg & p_mask;
> > +
> > + spin_lock(&ccu_lock);
> > +
> > + /* increase p, then m */
> > + if (ccu->p_width && p_val < (val & p_mask)) {
> > + reg &= ~p_mask;
> > + reg |= val & p_mask;
> > + writel(reg, ccu->base + ccu->reg);
> > + udelay(10);
> > + }
> > + if (ccu->m_width && m_val < (val & m_mask)) {
> > + reg &= ~m_mask;
> > + reg |= val & m_mask;
> > + writel(reg, ccu->base + ccu->reg);
> > + udelay(10);
> > + }
> > +
> > + /* set other factors */
> > + reg &= ~(mask & ~(p_mask | m_mask));
> > + reg |= val & ~(p_mask | m_mask);
> > + writel(reg, ccu->base + ccu->reg);
> > +
> > + /* decrease m */
> > + if (ccu->m_width && m_val > (val & m_mask)) {
> > + reg &= ~m_mask;
> > + reg |= val & m_mask;
> > + writel(reg, ccu->base + ccu->reg);
> > + udelay(10);
> > + }
> > +
> > + /* wait for PLL stable */
> > + if (ccu->lock_reg) {
> > + u32 lock;
> > +
> > + lock = BIT(ccu->lock_bit);
> > + WARN_ON(readl_relaxed_poll_timeout(ccu->base + ccu->lock_reg,
> > + reg, !(reg & lock),
> > + 100, 70000));
> > + }
[snip]
>
> Any reason why you're waiting for the lock after decreasing m and not
> before? PLL output may till run too fast before reducing the postdivider
> potentially causing a crash. But I might be misunderstanding what m is
> exactly.
I just followed what is done in the function
sunxi_clk_factors_set_flat_facotrs() from Allwinnertech:
1).try to increase factor p first
2).try to increase factor m first
3. write factor n & k
4. do pair things for 2). decease factor m
5. wait for PLL state stable
6.do pair things for 1). decease factor p
As this is written, it seems m is a pre-divider.
--
Ken ar c'hentañ | ** Breizh ha Linux atav! **
Jef | http://moinejf.free.fr/
More information about the linux-arm-kernel
mailing list