Message ID | 20230403095300.3386988-4-peng.fan@oss.nxp.com (mailing list archive) |
---|---|
State | Awaiting Upstream, archived |
Headers | show |
Series | clk: imx: imx93: fix and update | expand |
On 23-04-03 17:52:56, Peng Fan (OSS) wrote: > From: Peng Fan <peng.fan@nxp.com> > > The fracn gppll could be configured in FRAC or INTEGER mode during > hardware design. The current driver only support FRAC mode, while > this patch introduces INTEGER support. When the PLL is INTEGER pll, > there is no mfn, mfd, the calculation is as below: > Fvco_clk = (Fref / DIV[RDIV] ) * DIV[MFI] > Fclko_odiv = Fvco_clk / DIV[ODIV] > > In this patch, we reuse the FRAC pll logic with some condition check to > simplify the driver > > Signed-off-by: Peng Fan <peng.fan@nxp.com> > --- Reviewed-by: Abel Vesa <abel.vesa@linaro.org> > drivers/clk/imx/clk-fracn-gppll.c | 68 +++++++++++++++++++++++++++---- > drivers/clk/imx/clk.h | 7 ++++ > 2 files changed, 68 insertions(+), 7 deletions(-) > > diff --git a/drivers/clk/imx/clk-fracn-gppll.c b/drivers/clk/imx/clk-fracn-gppll.c > index f6674110a88e..e2633ad94640 100644 > --- a/drivers/clk/imx/clk-fracn-gppll.c > +++ b/drivers/clk/imx/clk-fracn-gppll.c > @@ -53,11 +53,22 @@ > .odiv = (_odiv), \ > } > > +#define PLL_FRACN_GP_INTEGER(_rate, _mfi, _rdiv, _odiv) \ > + { \ > + .rate = (_rate), \ > + .mfi = (_mfi), \ > + .mfn = 0, \ > + .mfd = 0, \ > + .rdiv = (_rdiv), \ > + .odiv = (_odiv), \ > + } > + > struct clk_fracn_gppll { > struct clk_hw hw; > void __iomem *base; > const struct imx_fracn_gppll_rate_table *rate_table; > int rate_count; > + u32 flags; > }; > > /* > @@ -83,6 +94,24 @@ struct imx_fracn_gppll_clk imx_fracn_gppll = { > }; > EXPORT_SYMBOL_GPL(imx_fracn_gppll); > > +/* > + * Fvco = (Fref / rdiv) * MFI > + * Fout = Fvco / odiv > + * The (Fref / rdiv) should be in range 20MHz to 40MHz > + * The Fvco should be in range 2.5Ghz to 5Ghz > + */ > +static const struct imx_fracn_gppll_rate_table int_tbl[] = { > + PLL_FRACN_GP_INTEGER(1700000000U, 141, 1, 2), > + PLL_FRACN_GP_INTEGER(1400000000U, 175, 1, 3), > + PLL_FRACN_GP_INTEGER(900000000U, 150, 1, 4), > +}; > + > +struct imx_fracn_gppll_clk imx_fracn_gppll_integer = { > + .rate_table = int_tbl, > + .rate_count = ARRAY_SIZE(int_tbl), > +}; > +EXPORT_SYMBOL_GPL(imx_fracn_gppll_integer); > + > static inline struct clk_fracn_gppll *to_clk_fracn_gppll(struct clk_hw *hw) > { > return container_of(hw, struct clk_fracn_gppll, hw); > @@ -169,9 +198,15 @@ static unsigned long clk_fracn_gppll_recalc_rate(struct clk_hw *hw, unsigned lon > break; > } > > - /* Fvco = Fref * (MFI + MFN / MFD) */ > - fvco = fvco * mfi * mfd + fvco * mfn; > - do_div(fvco, mfd * rdiv * odiv); > + if (pll->flags & CLK_FRACN_GPPLL_INTEGER) { > + /* Fvco = (Fref / rdiv) * MFI */ > + fvco = fvco * mfi; > + do_div(fvco, rdiv * odiv); > + } else { > + /* Fvco = (Fref / rdiv) * (MFI + MFN / MFD) */ > + fvco = fvco * mfi * mfd + fvco * mfn; > + do_div(fvco, mfd * rdiv * odiv); > + } > > return (unsigned long)fvco; > } > @@ -215,8 +250,10 @@ static int clk_fracn_gppll_set_rate(struct clk_hw *hw, unsigned long drate, > pll_div = FIELD_PREP(PLL_RDIV_MASK, rate->rdiv) | rate->odiv | > FIELD_PREP(PLL_MFI_MASK, rate->mfi); > writel_relaxed(pll_div, pll->base + PLL_DIV); > - writel_relaxed(rate->mfd, pll->base + PLL_DENOMINATOR); > - writel_relaxed(FIELD_PREP(PLL_MFN_MASK, rate->mfn), pll->base + PLL_NUMERATOR); > + if (pll->flags & CLK_FRACN_GPPLL_FRACN) { > + writel_relaxed(rate->mfd, pll->base + PLL_DENOMINATOR); > + writel_relaxed(FIELD_PREP(PLL_MFN_MASK, rate->mfn), pll->base + PLL_NUMERATOR); > + } > > /* Wait for 5us according to fracn mode pll doc */ > udelay(5); > @@ -300,8 +337,10 @@ static const struct clk_ops clk_fracn_gppll_ops = { > .set_rate = clk_fracn_gppll_set_rate, > }; > > -struct clk_hw *imx_clk_fracn_gppll(const char *name, const char *parent_name, void __iomem *base, > - const struct imx_fracn_gppll_clk *pll_clk) > +static struct clk_hw *_imx_clk_fracn_gppll(const char *name, const char *parent_name, > + void __iomem *base, > + const struct imx_fracn_gppll_clk *pll_clk, > + u32 pll_flags) > { > struct clk_fracn_gppll *pll; > struct clk_hw *hw; > @@ -322,6 +361,7 @@ struct clk_hw *imx_clk_fracn_gppll(const char *name, const char *parent_name, vo > pll->hw.init = &init; > pll->rate_table = pll_clk->rate_table; > pll->rate_count = pll_clk->rate_count; > + pll->flags = pll_flags; > > hw = &pll->hw; > > @@ -334,4 +374,18 @@ struct clk_hw *imx_clk_fracn_gppll(const char *name, const char *parent_name, vo > > return hw; > } > + > +struct clk_hw *imx_clk_fracn_gppll(const char *name, const char *parent_name, void __iomem *base, > + const struct imx_fracn_gppll_clk *pll_clk) > +{ > + return _imx_clk_fracn_gppll(name, parent_name, base, pll_clk, CLK_FRACN_GPPLL_FRACN); > +} > EXPORT_SYMBOL_GPL(imx_clk_fracn_gppll); > + > +struct clk_hw *imx_clk_fracn_gppll_integer(const char *name, const char *parent_name, > + void __iomem *base, > + const struct imx_fracn_gppll_clk *pll_clk) > +{ > + return _imx_clk_fracn_gppll(name, parent_name, base, pll_clk, CLK_FRACN_GPPLL_INTEGER); > +} > +EXPORT_SYMBOL_GPL(imx_clk_fracn_gppll_integer); > diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h > index 055bc9197fb4..cb4e4c4b8278 100644 > --- a/drivers/clk/imx/clk.h > +++ b/drivers/clk/imx/clk.h > @@ -73,6 +73,9 @@ extern struct imx_pll14xx_clk imx_1416x_pll; > extern struct imx_pll14xx_clk imx_1443x_pll; > extern struct imx_pll14xx_clk imx_1443x_dram_pll; > > +#define CLK_FRACN_GPPLL_INTEGER BIT(0) > +#define CLK_FRACN_GPPLL_FRACN BIT(1) > + > /* NOTE: Rate table should be kept sorted in descending order. */ > struct imx_fracn_gppll_rate_table { > unsigned int rate; > @@ -91,8 +94,12 @@ struct imx_fracn_gppll_clk { > > struct clk_hw *imx_clk_fracn_gppll(const char *name, const char *parent_name, void __iomem *base, > const struct imx_fracn_gppll_clk *pll_clk); > +struct clk_hw *imx_clk_fracn_gppll_integer(const char *name, const char *parent_name, > + void __iomem *base, > + const struct imx_fracn_gppll_clk *pll_clk); > > extern struct imx_fracn_gppll_clk imx_fracn_gppll; > +extern struct imx_fracn_gppll_clk imx_fracn_gppll_integer; > > #define imx_clk_cpu(name, parent_name, div, mux, pll, step) \ > to_clk(imx_clk_hw_cpu(name, parent_name, div, mux, pll, step)) > -- > 2.37.1 >
diff --git a/drivers/clk/imx/clk-fracn-gppll.c b/drivers/clk/imx/clk-fracn-gppll.c index f6674110a88e..e2633ad94640 100644 --- a/drivers/clk/imx/clk-fracn-gppll.c +++ b/drivers/clk/imx/clk-fracn-gppll.c @@ -53,11 +53,22 @@ .odiv = (_odiv), \ } +#define PLL_FRACN_GP_INTEGER(_rate, _mfi, _rdiv, _odiv) \ + { \ + .rate = (_rate), \ + .mfi = (_mfi), \ + .mfn = 0, \ + .mfd = 0, \ + .rdiv = (_rdiv), \ + .odiv = (_odiv), \ + } + struct clk_fracn_gppll { struct clk_hw hw; void __iomem *base; const struct imx_fracn_gppll_rate_table *rate_table; int rate_count; + u32 flags; }; /* @@ -83,6 +94,24 @@ struct imx_fracn_gppll_clk imx_fracn_gppll = { }; EXPORT_SYMBOL_GPL(imx_fracn_gppll); +/* + * Fvco = (Fref / rdiv) * MFI + * Fout = Fvco / odiv + * The (Fref / rdiv) should be in range 20MHz to 40MHz + * The Fvco should be in range 2.5Ghz to 5Ghz + */ +static const struct imx_fracn_gppll_rate_table int_tbl[] = { + PLL_FRACN_GP_INTEGER(1700000000U, 141, 1, 2), + PLL_FRACN_GP_INTEGER(1400000000U, 175, 1, 3), + PLL_FRACN_GP_INTEGER(900000000U, 150, 1, 4), +}; + +struct imx_fracn_gppll_clk imx_fracn_gppll_integer = { + .rate_table = int_tbl, + .rate_count = ARRAY_SIZE(int_tbl), +}; +EXPORT_SYMBOL_GPL(imx_fracn_gppll_integer); + static inline struct clk_fracn_gppll *to_clk_fracn_gppll(struct clk_hw *hw) { return container_of(hw, struct clk_fracn_gppll, hw); @@ -169,9 +198,15 @@ static unsigned long clk_fracn_gppll_recalc_rate(struct clk_hw *hw, unsigned lon break; } - /* Fvco = Fref * (MFI + MFN / MFD) */ - fvco = fvco * mfi * mfd + fvco * mfn; - do_div(fvco, mfd * rdiv * odiv); + if (pll->flags & CLK_FRACN_GPPLL_INTEGER) { + /* Fvco = (Fref / rdiv) * MFI */ + fvco = fvco * mfi; + do_div(fvco, rdiv * odiv); + } else { + /* Fvco = (Fref / rdiv) * (MFI + MFN / MFD) */ + fvco = fvco * mfi * mfd + fvco * mfn; + do_div(fvco, mfd * rdiv * odiv); + } return (unsigned long)fvco; } @@ -215,8 +250,10 @@ static int clk_fracn_gppll_set_rate(struct clk_hw *hw, unsigned long drate, pll_div = FIELD_PREP(PLL_RDIV_MASK, rate->rdiv) | rate->odiv | FIELD_PREP(PLL_MFI_MASK, rate->mfi); writel_relaxed(pll_div, pll->base + PLL_DIV); - writel_relaxed(rate->mfd, pll->base + PLL_DENOMINATOR); - writel_relaxed(FIELD_PREP(PLL_MFN_MASK, rate->mfn), pll->base + PLL_NUMERATOR); + if (pll->flags & CLK_FRACN_GPPLL_FRACN) { + writel_relaxed(rate->mfd, pll->base + PLL_DENOMINATOR); + writel_relaxed(FIELD_PREP(PLL_MFN_MASK, rate->mfn), pll->base + PLL_NUMERATOR); + } /* Wait for 5us according to fracn mode pll doc */ udelay(5); @@ -300,8 +337,10 @@ static const struct clk_ops clk_fracn_gppll_ops = { .set_rate = clk_fracn_gppll_set_rate, }; -struct clk_hw *imx_clk_fracn_gppll(const char *name, const char *parent_name, void __iomem *base, - const struct imx_fracn_gppll_clk *pll_clk) +static struct clk_hw *_imx_clk_fracn_gppll(const char *name, const char *parent_name, + void __iomem *base, + const struct imx_fracn_gppll_clk *pll_clk, + u32 pll_flags) { struct clk_fracn_gppll *pll; struct clk_hw *hw; @@ -322,6 +361,7 @@ struct clk_hw *imx_clk_fracn_gppll(const char *name, const char *parent_name, vo pll->hw.init = &init; pll->rate_table = pll_clk->rate_table; pll->rate_count = pll_clk->rate_count; + pll->flags = pll_flags; hw = &pll->hw; @@ -334,4 +374,18 @@ struct clk_hw *imx_clk_fracn_gppll(const char *name, const char *parent_name, vo return hw; } + +struct clk_hw *imx_clk_fracn_gppll(const char *name, const char *parent_name, void __iomem *base, + const struct imx_fracn_gppll_clk *pll_clk) +{ + return _imx_clk_fracn_gppll(name, parent_name, base, pll_clk, CLK_FRACN_GPPLL_FRACN); +} EXPORT_SYMBOL_GPL(imx_clk_fracn_gppll); + +struct clk_hw *imx_clk_fracn_gppll_integer(const char *name, const char *parent_name, + void __iomem *base, + const struct imx_fracn_gppll_clk *pll_clk) +{ + return _imx_clk_fracn_gppll(name, parent_name, base, pll_clk, CLK_FRACN_GPPLL_INTEGER); +} +EXPORT_SYMBOL_GPL(imx_clk_fracn_gppll_integer); diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index 055bc9197fb4..cb4e4c4b8278 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -73,6 +73,9 @@ extern struct imx_pll14xx_clk imx_1416x_pll; extern struct imx_pll14xx_clk imx_1443x_pll; extern struct imx_pll14xx_clk imx_1443x_dram_pll; +#define CLK_FRACN_GPPLL_INTEGER BIT(0) +#define CLK_FRACN_GPPLL_FRACN BIT(1) + /* NOTE: Rate table should be kept sorted in descending order. */ struct imx_fracn_gppll_rate_table { unsigned int rate; @@ -91,8 +94,12 @@ struct imx_fracn_gppll_clk { struct clk_hw *imx_clk_fracn_gppll(const char *name, const char *parent_name, void __iomem *base, const struct imx_fracn_gppll_clk *pll_clk); +struct clk_hw *imx_clk_fracn_gppll_integer(const char *name, const char *parent_name, + void __iomem *base, + const struct imx_fracn_gppll_clk *pll_clk); extern struct imx_fracn_gppll_clk imx_fracn_gppll; +extern struct imx_fracn_gppll_clk imx_fracn_gppll_integer; #define imx_clk_cpu(name, parent_name, div, mux, pll, step) \ to_clk(imx_clk_hw_cpu(name, parent_name, div, mux, pll, step))