The PBL code needs to adjust the DDR PLL before setting up DDR. Factor out the PLL setup code as a static inline function for PBL usage.
Signed-off-by: Sascha Hauer <s.ha...@pengutronix.de> --- drivers/clk/imx/clk-fracn-gppll.c | 135 +++++----------------------- drivers/clk/imx/clk.h | 28 +----- include/soc/imx/clk-fracn-gppll.h | 144 ++++++++++++++++++++++++++++++ 3 files changed, 165 insertions(+), 142 deletions(-) create mode 100644 include/soc/imx/clk-fracn-gppll.h diff --git a/drivers/clk/imx/clk-fracn-gppll.c b/drivers/clk/imx/clk-fracn-gppll.c index 5fbc79f948..24e66fd65f 100644 --- a/drivers/clk/imx/clk-fracn-gppll.c +++ b/drivers/clk/imx/clk-fracn-gppll.c @@ -10,38 +10,10 @@ #include <of_address.h> #include <linux/iopoll.h> #include <linux/bitfield.h> +#include <soc/imx/clk-fracn-gppll.h> #include "clk.h" -#define PLL_CTRL 0x0 -#define HW_CTRL_SEL BIT(16) -#define CLKMUX_BYPASS BIT(2) -#define CLKMUX_EN BIT(1) -#define POWERUP_MASK BIT(0) - -#define PLL_ANA_PRG 0x10 -#define PLL_SPREAD_SPECTRUM 0x30 - -#define PLL_NUMERATOR 0x40 -#define PLL_MFN_MASK GENMASK(31, 2) - -#define PLL_DENOMINATOR 0x50 -#define PLL_MFD_MASK GENMASK(29, 0) - -#define PLL_DIV 0x60 -#define PLL_MFI_MASK GENMASK(24, 16) -#define PLL_RDIV_MASK GENMASK(15, 13) -#define PLL_ODIV_MASK GENMASK(7, 0) - -#define PLL_DFS_CTRL(x) (0x70 + (x) * 0x10) - -#define PLL_STATUS 0xF0 -#define LOCK_STATUS BIT(0) - -#define DFS_STATUS 0xF4 - -#define LOCK_TIMEOUT_US 200 - #define PLL_FRACN_GP(_rate, _mfi, _mfn, _mfd, _rdiv, _odiv) \ { \ .rate = (_rate), \ @@ -118,19 +90,6 @@ static inline struct clk_fracn_gppll *to_clk_fracn_gppll(struct clk_hw *hw) return container_of(hw, struct clk_fracn_gppll, hw); } -static const struct imx_fracn_gppll_rate_table * -imx_get_pll_settings(struct clk_fracn_gppll *pll, unsigned long rate) -{ - const struct imx_fracn_gppll_rate_table *rate_table = pll->rate_table; - int i; - - for (i = 0; i < pll->rate_count; i++) - if (rate == rate_table[i].rate) - return &rate_table[i]; - - return NULL; -} - static long clk_fracn_gppll_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *prate) { @@ -157,17 +116,17 @@ static unsigned long clk_fracn_gppll_recalc_rate(struct clk_hw *hw, unsigned lon long rate = 0; int i; - pll_numerator = readl_relaxed(pll->base + PLL_NUMERATOR); - mfn = FIELD_GET(PLL_MFN_MASK, pll_numerator); + pll_numerator = readl_relaxed(pll->base + GPPLL_NUMERATOR); + mfn = FIELD_GET(GPPLL_MFN_MASK, pll_numerator); - pll_denominator = readl_relaxed(pll->base + PLL_DENOMINATOR); - mfd = FIELD_GET(PLL_MFD_MASK, pll_denominator); + pll_denominator = readl_relaxed(pll->base + GPPLL_DENOMINATOR); + mfd = FIELD_GET(GPPLL_MFD_MASK, pll_denominator); - pll_div = readl_relaxed(pll->base + PLL_DIV); - mfi = FIELD_GET(PLL_MFI_MASK, pll_div); + pll_div = readl_relaxed(pll->base + GPPLL_DIV); + mfi = FIELD_GET(GPPLL_MFI_MASK, pll_div); - rdiv = FIELD_GET(PLL_RDIV_MASK, pll_div); - odiv = FIELD_GET(PLL_ODIV_MASK, pll_div); + rdiv = FIELD_GET(GPPLL_RDIV_MASK, pll_div); + odiv = FIELD_GET(GPPLL_ODIV_MASK, pll_div); /* * Sometimes, the recalculated rate has deviation due to @@ -214,70 +173,16 @@ static unsigned long clk_fracn_gppll_recalc_rate(struct clk_hw *hw, unsigned lon static int clk_fracn_gppll_wait_lock(struct clk_fracn_gppll *pll) { - u32 val; - - return readl_poll_timeout(pll->base + PLL_STATUS, val, - val & LOCK_STATUS, LOCK_TIMEOUT_US); + return fracn_gppll_wait_lock(pll->base); } static int clk_fracn_gppll_set_rate(struct clk_hw *hw, unsigned long drate, unsigned long prate) { struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw); - const struct imx_fracn_gppll_rate_table *rate; - u32 tmp, pll_div, ana_mfn; - int ret; - - rate = imx_get_pll_settings(pll, drate); - - /* Hardware control select disable. PLL is control by register */ - tmp = readl_relaxed(pll->base + PLL_CTRL); - tmp &= ~HW_CTRL_SEL; - writel_relaxed(tmp, pll->base + PLL_CTRL); - - /* Disable output */ - tmp = readl_relaxed(pll->base + PLL_CTRL); - tmp &= ~CLKMUX_EN; - writel_relaxed(tmp, pll->base + PLL_CTRL); - - /* Power Down */ - tmp &= ~POWERUP_MASK; - writel_relaxed(tmp, pll->base + PLL_CTRL); - - /* Disable BYPASS */ - tmp &= ~CLKMUX_BYPASS; - writel_relaxed(tmp, pll->base + PLL_CTRL); - - 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); - 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); - /* Enable Powerup */ - tmp |= POWERUP_MASK; - writel_relaxed(tmp, pll->base + PLL_CTRL); - - /* Wait Lock */ - ret = clk_fracn_gppll_wait_lock(pll); - if (ret) - return ret; - - /* Enable output */ - tmp |= CLKMUX_EN; - writel_relaxed(tmp, pll->base + PLL_CTRL); - - ana_mfn = readl_relaxed(pll->base + PLL_STATUS); - ana_mfn = FIELD_GET(PLL_MFN_MASK, ana_mfn); - - WARN(ana_mfn != rate->mfn, "ana_mfn != rate->mfn\n"); - - return 0; + return fracn_gppll_set_rate(pll->base, pll->flags, pll->rate_table, + pll->rate_count, drate); } static int clk_fracn_gppll_prepare(struct clk_hw *hw) @@ -286,25 +191,25 @@ static int clk_fracn_gppll_prepare(struct clk_hw *hw) u32 val; int ret; - val = readl_relaxed(pll->base + PLL_CTRL); + val = readl_relaxed(pll->base + GPPLL_CTRL); if (val & POWERUP_MASK) return 0; val |= CLKMUX_BYPASS; - writel_relaxed(val, pll->base + PLL_CTRL); + writel_relaxed(val, pll->base + GPPLL_CTRL); val |= POWERUP_MASK; - writel_relaxed(val, pll->base + PLL_CTRL); + writel_relaxed(val, pll->base + GPPLL_CTRL); val |= CLKMUX_EN; - writel_relaxed(val, pll->base + PLL_CTRL); + writel_relaxed(val, pll->base + GPPLL_CTRL); ret = clk_fracn_gppll_wait_lock(pll); if (ret) return ret; val &= ~CLKMUX_BYPASS; - writel_relaxed(val, pll->base + PLL_CTRL); + writel_relaxed(val, pll->base + GPPLL_CTRL); return 0; } @@ -314,7 +219,7 @@ static int clk_fracn_gppll_is_prepared(struct clk_hw *hw) struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw); u32 val; - val = readl_relaxed(pll->base + PLL_CTRL); + val = readl_relaxed(pll->base + GPPLL_CTRL); return (val & POWERUP_MASK) ? 1 : 0; } @@ -324,9 +229,9 @@ static void clk_fracn_gppll_unprepare(struct clk_hw *hw) struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw); u32 val; - val = readl_relaxed(pll->base + PLL_CTRL); + val = readl_relaxed(pll->base + GPPLL_CTRL); val &= ~POWERUP_MASK; - writel_relaxed(val, pll->base + PLL_CTRL); + writel_relaxed(val, pll->base + GPPLL_CTRL); } static const struct clk_ops clk_fracn_gppll_ops = { diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index 1d3316619f..9058f913d3 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -304,33 +304,7 @@ struct clk *imx8m_clk_composite_flags(const char *name, #define imx8m_clk_composite_critical(name, parent_names, reg) \ __imx8m_clk_composite(name, parent_names, reg, CLK_IS_CRITICAL) -#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; - unsigned int mfi; - unsigned int mfn; - unsigned int mfd; - unsigned int rdiv; - unsigned int odiv; -}; - -struct imx_fracn_gppll_clk { - const struct imx_fracn_gppll_rate_table *rate_table; - int rate_count; - int flags; -}; - -struct clk *imx_clk_fracn_gppll(const char *name, const char *parent_name, void __iomem *base, - const struct imx_fracn_gppll_clk *pll_clk); -struct clk *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; +#include <soc/imx/clk-fracn-gppll.h> struct clk *imx93_clk_composite_flags(const char *name, const char * const *parent_names, diff --git a/include/soc/imx/clk-fracn-gppll.h b/include/soc/imx/clk-fracn-gppll.h new file mode 100644 index 0000000000..15ab9e67ec --- /dev/null +++ b/include/soc/imx/clk-fracn-gppll.h @@ -0,0 +1,144 @@ +#ifndef __SOC_IMX_CLK_FRACN_GPGPPLL_H +#define __SOC_IMX_CLK_FRACN_GPGPPLL_H + +#include <linux/bitfield.h> +#include <linux/iopoll.h> + +#define GPPLL_CTRL 0x0 +#define HW_CTRL_SEL BIT(16) +#define CLKMUX_BYPASS BIT(2) +#define CLKMUX_EN BIT(1) +#define POWERUP_MASK BIT(0) + +#define GPPLL_ANA_PRG 0x10 +#define GPPLL_SPREAD_SPECTRUM 0x30 + +#define GPPLL_NUMERATOR 0x40 +#define GPPLL_MFN_MASK GENMASK(31, 2) + +#define GPPLL_DENOMINATOR 0x50 +#define GPPLL_MFD_MASK GENMASK(29, 0) + +#define GPPLL_DIV 0x60 +#define GPPLL_MFI_MASK GENMASK(24, 16) +#define GPPLL_RDIV_MASK GENMASK(15, 13) +#define GPPLL_ODIV_MASK GENMASK(7, 0) + +#define GPPLL_DFS_CTRL(x) (0x70 + (x) * 0x10) + +#define GPPLL_STATUS 0xF0 +#define GPPLL_LOCK_STATUS BIT(0) + +#define GPPLL_DFS_STATUS 0xF4 + +#define GPPLL_LOCK_TIMEOUT_US 200 + +#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; + unsigned int mfi; + unsigned int mfn; + unsigned int mfd; + unsigned int rdiv; + unsigned int odiv; +}; + +struct imx_fracn_gppll_clk { + const struct imx_fracn_gppll_rate_table *rate_table; + int rate_count; + int flags; +}; + +struct clk *imx_clk_fracn_gppll(const char *name, const char *parent_name, void __iomem *base, + const struct imx_fracn_gppll_clk *pll_clk); +struct clk *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; + +static inline int fracn_gppll_wait_lock(void __iomem *base) +{ + u32 val; + + return readl_poll_timeout(base + GPPLL_STATUS, val, + val & GPPLL_LOCK_STATUS, GPPLL_LOCK_TIMEOUT_US); +} + +static inline const struct imx_fracn_gppll_rate_table *imx_get_gppll_settings( + const struct imx_fracn_gppll_rate_table *rate_table, int n_table, unsigned long rate) +{ + int i; + + for (i = 0; i < n_table; i++) + if (rate == rate_table[i].rate) + return &rate_table[i]; + + return NULL; +} + +static inline int fracn_gppll_set_rate(void __iomem *base, unsigned int flags, + const struct imx_fracn_gppll_rate_table *table, int n_table, + unsigned long drate) +{ + const struct imx_fracn_gppll_rate_table *rate; + u32 tmp, pll_div, ana_mfn; + int ret; + + rate = imx_get_gppll_settings(table, n_table, drate); + + /* Hardware control select disable. PLL is control by register */ + tmp = readl_relaxed(base + GPPLL_CTRL); + tmp &= ~HW_CTRL_SEL; + writel_relaxed(tmp, base + GPPLL_CTRL); + + /* Disable output */ + tmp = readl_relaxed(base + GPPLL_CTRL); + tmp &= ~CLKMUX_EN; + writel_relaxed(tmp, base + GPPLL_CTRL); + + /* Power Down */ + tmp &= ~POWERUP_MASK; + writel_relaxed(tmp, base + GPPLL_CTRL); + + /* Disable BYPASS */ + tmp &= ~CLKMUX_BYPASS; + writel_relaxed(tmp, base + GPPLL_CTRL); + + pll_div = FIELD_PREP(GPPLL_RDIV_MASK, rate->rdiv) | rate->odiv | + FIELD_PREP(GPPLL_MFI_MASK, rate->mfi); + writel_relaxed(pll_div, base + GPPLL_DIV); + if (flags & CLK_FRACN_GPPLL_FRACN) { + writel_relaxed(rate->mfd, base + GPPLL_DENOMINATOR); + writel_relaxed(FIELD_PREP(GPPLL_MFN_MASK, rate->mfn), base + GPPLL_NUMERATOR); + } + + /* Wait for 5us according to fracn mode pll doc */ + udelay(5); + + /* Enable Powerup */ + tmp |= POWERUP_MASK; + writel_relaxed(tmp, base + GPPLL_CTRL); + + /* Wait Lock */ + ret = fracn_gppll_wait_lock(base); + if (ret) + return ret; + + /* Enable output */ + tmp |= CLKMUX_EN; + writel_relaxed(tmp, base + GPPLL_CTRL); + + ana_mfn = readl_relaxed(base + GPPLL_STATUS); + ana_mfn = FIELD_GET(GPPLL_MFN_MASK, ana_mfn); + + WARN(ana_mfn != rate->mfn, "ana_mfn != rate->mfn\n"); + + return 0; +} + +#endif /* __SOC_IMX_CLK_FRACN_GPGPPLL_H */ -- 2.39.2