On 23-04-03 17:52:56, Peng Fan (OSS) wrote: > From: Peng Fan <peng.fan@xxxxxxx> > > 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@xxxxxxx> > --- Reviewed-by: Abel Vesa <abel.vesa@xxxxxxxxxx> > 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 >