Thread (15 messages) 15 messages, 3 authors, 2018-09-04

Re: [PATCH v6 3/5] clk: imx: add SCCG PLL type

From: Andrey Smirnov <hidden>
Date: 2018-09-04 19:31:00
Also in: linux-clk, lkml

On Tue, Sep 4, 2018 at 6:13 AM Abel Vesa [off-list ref] wrote:
On Tue, Aug 28, 2018 at 12:11:13PM -0700, Andrey Smirnov wrote:
quoted
On Tue, Aug 28, 2018 at 3:58 AM Abel Vesa [off-list ref] wrote:
quoted
On Fri, Aug 24, 2018 at 09:40:11AM +0200, Sascha Hauer wrote:
quoted
+Cc Andrey Smirnov who made me aware of this issue.

On Wed, Aug 22, 2018 at 04:48:21PM +0300, Abel Vesa wrote:
quoted
From: Lucas Stach <l.stach@pengutronix.de>

The SCCG is a new PLL type introduced on i.MX8. Add support for this.
The driver currently misses the PLL lock check, as the preliminary
documentation mentions lock configurations, but is quiet about where
to find the actual lock status signal.

Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
Signed-off-by: Abel Vesa <redacted>
---
+static int clk_pll1_set_rate(struct clk_hw *hw, unsigned long rate,
+                       unsigned long parent_rate)
+{
+   struct clk_sccg_pll *pll = to_clk_sccg_pll(hw);
+   u32 val;
+   u32 divf;
+
+   divf = rate / (parent_rate * 2);
+
+   val = readl_relaxed(pll->base + PLL_CFG2);
+   val &= ~(PLL_DIVF_MASK << PLL_DIVF1_SHIFT);
+   val |= (divf - 1) << PLL_DIVF1_SHIFT;
+   writel_relaxed(val, pll->base + PLL_CFG2);
+
+   /* FIXME: PLL lock check */
Shouldn't be too hard to add, no?
Added to the next version which I intend to send today.
quoted
quoted
+
+   return 0;
+}
+
+static int clk_pll1_prepare(struct clk_hw *hw)
+{
+   struct clk_sccg_pll *pll = to_clk_sccg_pll(hw);
+   u32 val;
+
+   val = readl_relaxed(pll->base);
+   val &= ~(1 << PLL_PD);
+   writel_relaxed(val, pll->base);
pll->base + PLL_CFG0 please.
Same as above.
quoted
quoted
+static const struct clk_ops clk_sccg_pll1_ops = {
+   .is_prepared    = clk_pll1_is_prepared,
+   .recalc_rate    = clk_pll1_recalc_rate,
+   .round_rate     = clk_pll1_round_rate,
+   .set_rate       = clk_pll1_set_rate,
+};
+
+static const struct clk_ops clk_sccg_pll2_ops = {
+   .prepare        = clk_pll1_prepare,
+   .unprepare      = clk_pll1_unprepare,
+   .recalc_rate    = clk_pll2_recalc_rate,
+   .round_rate     = clk_pll2_round_rate,
+   .set_rate       = clk_pll2_set_rate,
+};
So these are two PLLs that share the same enable register. Doing the
prepare/unprepare for only one PLL can lead to all kinds of trouble.
Finding a good abstraction the properly handles this case with the
clock framework is probably also not easy.

I could imagine we'll need to track the enable state on both PLLs and
only if both are disabled we disable it in hardware.

With the current code we disable the PLLs when all consumers are
reparented to pll1, which probably has bad effects.
So it took me a while to understand exactly why this needs to stay like it is.
IMHO this means that, if nothing else, all of the below should be
documented in code as a comment, otherwise simpletons like me are
going to continue stumbling over it and wondering what's going on.
Will try to add proper comment to explain what's happening.
quoted
quoted
The PLL1 is never used by any device, instead it is used as a source for PLL2.

But because the interlink between the two of them is too complicated,
the PLLs 1 and 2 need to be separate clocks.
Can you go a little bit more into detail as for why PLL1 needs to be
exposed in the first place and can't just be dealt with behind the
scenes as a part of PLL2 abstraction? Are there use-cases where the
rates of the two are going to be adjusted individually in Linux?
Here is the SCCG PLL Block Diagram:

https://www.nxp.com/docs/en/reference-manual/IMX8MDQLQRM.pdf#page=834

Now lets take the System PLL 2 for example. If you follow the hierarchy,
when you reach the sys2_pll1_out you can see that one of its selectors is
actually sys1_pll1_ref_sel. Same thing applies to sys3_pll2_out with
sys2_pll1_ref_sel. This means there is an input reference clock interlinking
between different System PLLs.
Hmm, I am not sure I see how this would prevent you from treating a
PLL pair as a black box, but OTOH, doing that probably wouldn't result
cleaner or simpler code. IMHO, it's unfortunate that PD bit is shared
between the two clocks, but if PLL1 could only be ever connected to
corresponding PLL2, then my concerns were probably misguided and
current implementation is good enough.

Thanks,
Andrey Smirnov
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help