From: Leonard Crestez Date: Fri, 3 May 2019 15:47:01 +0000 (+0300) Subject: MLK-21700-1 clk: imx8mm: Rename int_pll to pll14xx for upstream alignment X-Git-Tag: rel_imx_4.19.35_1.1.0~521 X-Git-Url: https://git.somdevices.com/?a=commitdiff_plain;h=1c951d1122b5691fe322bb642f770eabd60b238b;p=linux.git MLK-21700-1 clk: imx8mm: Rename int_pll to pll14xx for upstream alignment Only cosmetic changes in this patch Signed-off-by: Leonard Crestez Reviewed-by: Abel Vesa --- diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 6be120dc8c4d..69120e47f12f 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -35,4 +35,4 @@ obj-$(CONFIG_SOC_VF610) += clk-vf610.o obj-$(CONFIG_ARCH_FSL_IMX8QM) += clk.o clk-imx8qm.o clk-imx8.o clk-divider-scu.o clk-gate-scu.o clk-mux-scu.o obj-$(CONFIG_ARCH_FSL_IMX8QXP) += clk.o clk-imx8qxp.o clk-imx8.o clk-divider-scu.o clk-gate-scu.o clk-mux-scu.o obj-$(CONFIG_ARCH_FSL_IMX8MQ) += clk.o clk-imx8mq.o clk-frac-pll.o clk-sccg-pll.o clk-gate2.o clk-composite-8m.o -obj-$(CONFIG_ARCH_FSL_IMX8MM) += clk.o clk-imx8mm.o clk-intpll.o clk-gate2.o clk-cpu.o +obj-$(CONFIG_ARCH_FSL_IMX8MM) += clk.o clk-imx8mm.o clk-pll14xx.o clk-gate2.o clk-cpu.o diff --git a/drivers/clk/imx/clk-imx8mm.c b/drivers/clk/imx/clk-imx8mm.c index 1af5814c8375..a1aca3f34230 100644 --- a/drivers/clk/imx/clk-imx8mm.c +++ b/drivers/clk/imx/clk-imx8mm.c @@ -65,7 +65,7 @@ enum { .kdiv = (_k), \ } -static const struct imx_int_pll_rate_table imx8mm_intpll_tbl[] = { +static const struct imx_pll14xx_rate_table imx8mm_pll1416x_tbl[] = { PLL_1416X_RATE(1800000000U, 225, 3, 0), PLL_1416X_RATE(1600000000U, 200, 3, 0), PLL_1416X_RATE(1200000000U, 300, 3, 1), @@ -76,53 +76,53 @@ static const struct imx_int_pll_rate_table imx8mm_intpll_tbl[] = { PLL_1416X_RATE(600000000U, 300, 3, 2), }; -static const struct imx_int_pll_rate_table imx8mm_audiopll_tbl[] = { +static const struct imx_pll14xx_rate_table imx8mm_audiopll_tbl[] = { PLL_1443X_RATE(786432000U, 262, 2, 2, 9437), PLL_1443X_RATE(722534400U, 361, 3, 2, 17511), }; -static const struct imx_int_pll_rate_table imx8mm_videopll_tbl[] = { +static const struct imx_pll14xx_rate_table imx8mm_videopll_tbl[] = { PLL_1443X_RATE(650000000U, 325, 3, 2, 0), PLL_1443X_RATE(594000000U, 198, 2, 2, 0), }; -static const struct imx_int_pll_rate_table imx8mm_drampll_tbl[] = { +static const struct imx_pll14xx_rate_table imx8mm_drampll_tbl[] = { PLL_1443X_RATE(650000000U, 325, 3, 2, 0), }; -static struct imx_int_pll_clk imx8mm_audio_pll __initdata = { +static struct imx_pll14xx_clk imx8mm_audio_pll __initdata = { .type = PLL_1443X, .rate_table = imx8mm_audiopll_tbl, }; -static struct imx_int_pll_clk imx8mm_video_pll __initdata = { +static struct imx_pll14xx_clk imx8mm_video_pll __initdata = { .type = PLL_1443X, .rate_table = imx8mm_videopll_tbl, }; -static struct imx_int_pll_clk imx8mm_dram_pll __initdata = { +static struct imx_pll14xx_clk imx8mm_dram_pll __initdata = { .type = PLL_1443X, .rate_table = imx8mm_drampll_tbl, }; -static struct imx_int_pll_clk imx8mm_arm_pll __initdata = { +static struct imx_pll14xx_clk imx8mm_arm_pll __initdata = { .type = PLL_1416X, - .rate_table = imx8mm_intpll_tbl, + .rate_table = imx8mm_pll1416x_tbl, }; -static struct imx_int_pll_clk imx8mm_gpu_pll __initdata = { +static struct imx_pll14xx_clk imx8mm_gpu_pll __initdata = { .type = PLL_1416X, - .rate_table = imx8mm_intpll_tbl, + .rate_table = imx8mm_pll1416x_tbl, }; -static struct imx_int_pll_clk imx8mm_vpu_pll __initdata = { +static struct imx_pll14xx_clk imx8mm_vpu_pll __initdata = { .type = PLL_1416X, - .rate_table = imx8mm_intpll_tbl, + .rate_table = imx8mm_pll1416x_tbl, }; -static struct imx_int_pll_clk imx8mm_sys_pll __initdata = { +static struct imx_pll14xx_clk imx8mm_sys_pll __initdata = { .type = PLL_1416X, - .rate_table = imx8mm_intpll_tbl, + .rate_table = imx8mm_pll1416x_tbl, }; static const char *pll_ref_sels[] = { "osc_24m", "dummy", "dummy", "dummy", }; @@ -461,16 +461,16 @@ static void __init imx8mm_clocks_init(struct device_node *ccm_node) clks[IMX8MM_SYS_PLL2_REF_SEL] = imx_clk_mux("sys_pll2_ref_sel", base + 0x104, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)); clks[IMX8MM_SYS_PLL3_REF_SEL] = imx_clk_mux("sys_pll3_ref_sel", base + 0x114, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)); - clks[IMX8MM_AUDIO_PLL1] = imx_clk_int_pll("audio_pll1", "audio_pll1_ref_sel", base, &imx8mm_audio_pll); - clks[IMX8MM_AUDIO_PLL2] = imx_clk_int_pll("audio_pll2", "audio_pll2_ref_sel", base + 0x14, &imx8mm_audio_pll); - clks[IMX8MM_VIDEO_PLL1] = imx_clk_int_pll("video_pll1", "video_pll1_ref_sel", base + 0x28, &imx8mm_video_pll); - clks[IMX8MM_DRAM_PLL] = imx_clk_int_pll("dram_pll", "dram_pll_ref_sel", base + 0x50, &imx8mm_dram_pll); - clks[IMX8MM_GPU_PLL] = imx_clk_int_pll("gpu_pll", "gpu_pll_ref_sel", base + 0x64, &imx8mm_gpu_pll); - clks[IMX8MM_VPU_PLL] = imx_clk_int_pll("vpu_pll", "vpu_pll_ref_sel", base + 0x74, &imx8mm_vpu_pll); - clks[IMX8MM_ARM_PLL] = imx_clk_int_pll("arm_pll", "arm_pll_ref_sel", base + 0x84, &imx8mm_arm_pll); - clks[IMX8MM_SYS_PLL1] = imx_clk_int_pll("sys_pll1", "sys_pll1_ref_sel", base + 0x94, &imx8mm_sys_pll); - clks[IMX8MM_SYS_PLL2] = imx_clk_int_pll("sys_pll2", "sys_pll2_ref_sel", base + 0x104, &imx8mm_sys_pll); - clks[IMX8MM_SYS_PLL3] = imx_clk_int_pll("sys_pll3", "sys_pll3_ref_sel", base + 0x114, &imx8mm_sys_pll); + clks[IMX8MM_AUDIO_PLL1] = imx_clk_pll14xx("audio_pll1", "audio_pll1_ref_sel", base, &imx8mm_audio_pll); + clks[IMX8MM_AUDIO_PLL2] = imx_clk_pll14xx("audio_pll2", "audio_pll2_ref_sel", base + 0x14, &imx8mm_audio_pll); + clks[IMX8MM_VIDEO_PLL1] = imx_clk_pll14xx("video_pll1", "video_pll1_ref_sel", base + 0x28, &imx8mm_video_pll); + clks[IMX8MM_DRAM_PLL] = imx_clk_pll14xx("dram_pll", "dram_pll_ref_sel", base + 0x50, &imx8mm_dram_pll); + clks[IMX8MM_GPU_PLL] = imx_clk_pll14xx("gpu_pll", "gpu_pll_ref_sel", base + 0x64, &imx8mm_gpu_pll); + clks[IMX8MM_VPU_PLL] = imx_clk_pll14xx("vpu_pll", "vpu_pll_ref_sel", base + 0x74, &imx8mm_vpu_pll); + clks[IMX8MM_ARM_PLL] = imx_clk_pll14xx("arm_pll", "arm_pll_ref_sel", base + 0x84, &imx8mm_arm_pll); + clks[IMX8MM_SYS_PLL1] = imx_clk_pll14xx("sys_pll1", "sys_pll1_ref_sel", base + 0x94, &imx8mm_sys_pll); + clks[IMX8MM_SYS_PLL2] = imx_clk_pll14xx("sys_pll2", "sys_pll2_ref_sel", base + 0x104, &imx8mm_sys_pll); + clks[IMX8MM_SYS_PLL3] = imx_clk_pll14xx("sys_pll3", "sys_pll3_ref_sel", base + 0x114, &imx8mm_sys_pll); /* PLL bypass out */ clks[IMX8MM_AUDIO_PLL1_BYPASS] = imx_clk_mux_flags("audio_pll1_bypass", base, 4, 1, audio_pll1_bypass_sels, ARRAY_SIZE(audio_pll1_bypass_sels), CLK_SET_RATE_PARENT); diff --git a/drivers/clk/imx/clk-intpll.c b/drivers/clk/imx/clk-intpll.c deleted file mode 100644 index 4c8e0685b8ba..000000000000 --- a/drivers/clk/imx/clk-intpll.c +++ /dev/null @@ -1,430 +0,0 @@ -/* - * Copyright 2017-2018 NXP. - * - * The code contained herein is licensed under the GNU General Public - * License. You may obtain a copy of the GNU General Public License - * Version 2 or later at the following locations: - * - * http://www.opensource.org/licenses/gpl-license.html - * http://www.gnu.org/copyleft/gpl.html - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "clk.h" - -#define GNRL_CTL 0x0 -#define DIV_CTL 0x4 -#define LOCK_STATUS BIT(31) -#define LOCK_SEL_MASK BIT(29) -#define CLKE_MASK BIT(11) -#define RST_MASK BIT(9) -#define BYPASS_MASK BIT(4) -#define MDIV_SHIFT 12 -#define MDIV_MASK GENMASK(21, 12) -#define PDIV_SHIFT 4 -#define PDIV_MASK GENMASK(9, 4) -#define SDIV_SHIFT 0 -#define SDIV_MASK GENMASK(2, 0) -#define KDIV_SHIFT 0 -#define KDIV_MASK GENMASK(15, 0) - -struct clk_int_pll { - struct clk_hw hw; - void __iomem *base; - enum imx_int_pll_type type; - struct imx_int_pll_rate_table *rate_table; - int rate_count; -}; - -#define to_clk_int_pll(_hw) container_of(_hw, struct clk_int_pll, hw) - -static const struct imx_int_pll_rate_table *imx_get_pll_settings( - struct clk_int_pll *pll, unsigned long rate) -{ - const struct imx_int_pll_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_int_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) -{ - struct clk_int_pll *pll = to_clk_int_pll(hw); - const struct imx_int_pll_rate_table *rate_table = pll->rate_table; - int i; - - /* Assumming rate_table is in descending order */ - for (i = 0; i < pll->rate_count; i++) { - if (rate >= rate_table[i].rate) - return rate_table[i].rate; - } - /* return minimum supported value */ - return rate_table[i - 1].rate; -} - -static unsigned long clk_int_pll1416x_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct clk_int_pll *pll = to_clk_int_pll(hw); - u32 mdiv, pdiv, sdiv, pll_gnrl, pll_div; - u64 fvco = parent_rate; - - pll_gnrl = readl_relaxed(pll->base); - pll_div = readl_relaxed(pll->base + 4); - mdiv = (pll_div & MDIV_MASK) >> MDIV_SHIFT; - pdiv = (pll_div & PDIV_MASK) >> PDIV_SHIFT; - sdiv = (pll_div & SDIV_MASK) >> SDIV_SHIFT; - - fvco *= mdiv; - do_div(fvco, pdiv << sdiv); - - return (unsigned long)fvco; -} - -static unsigned long clk_int_pll1443x_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct clk_int_pll *pll = to_clk_int_pll(hw); - const struct imx_int_pll_rate_table *rate_table = pll->rate_table; - u32 mdiv, pdiv, sdiv, pll_gnrl, pll_div_ctl0, pll_div_ctl1; - short int kdiv; - u64 fvco = parent_rate; - long rate = 0; - int i; - - pll_gnrl = readl_relaxed(pll->base); - pll_div_ctl0 = readl_relaxed(pll->base + 4); - pll_div_ctl1 = readl_relaxed(pll->base + 8); - mdiv = (pll_div_ctl0 & MDIV_MASK) >> MDIV_SHIFT; - pdiv = (pll_div_ctl0 & PDIV_MASK) >> PDIV_SHIFT; - sdiv = (pll_div_ctl0 & SDIV_MASK) >> SDIV_SHIFT; - kdiv = pll_div_ctl1 & KDIV_MASK; - - /* - * Sometimes, the recalculated rate has deviation due to - * the frac part. So find the accurate pll rate from the table - * first, if no match rate in the table, use the rate calculated - * from the equation below. - */ - for (i = 0; i < pll->rate_count; i++) { - if (rate_table[i].pdiv == pdiv && rate_table[i].mdiv == mdiv && - rate_table[i].sdiv == sdiv && rate_table[i].kdiv == kdiv) - rate = rate_table[i].rate; - } - - /* fvco = (m * 65536 + k) * Fin / (p * 65536) */ - fvco *= (mdiv * 65536 + kdiv); - pdiv *= 65536; - - do_div(fvco, pdiv << sdiv); - - return rate ? (unsigned long) rate : (unsigned long)fvco; -} - -static inline bool clk_int_pll1416x_mp_change(const struct imx_int_pll_rate_table *rate, - u32 pll_div) -{ - u32 old_mdiv, old_pdiv; - - old_mdiv = (pll_div >> MDIV_SHIFT) & MDIV_MASK; - old_pdiv = (pll_div >> PDIV_SHIFT) & PDIV_MASK; - - return (rate->mdiv != old_mdiv || rate->pdiv != old_pdiv); -} - -static inline bool clk_int_pll1443x_mpk_change(const struct imx_int_pll_rate_table *rate, - u32 pll_div_ctl0, u32 pll_div_ctl1) -{ - u32 old_mdiv, old_pdiv, old_kdiv; - - old_mdiv = (pll_div_ctl0 >> MDIV_SHIFT) & MDIV_MASK; - old_pdiv = (pll_div_ctl0 >> PDIV_SHIFT) & PDIV_MASK; - old_kdiv = (pll_div_ctl1 >> KDIV_SHIFT) & KDIV_MASK; - - return (rate->mdiv != old_mdiv || rate->pdiv != old_pdiv || - rate->kdiv != old_kdiv); -} - -static inline bool clk_int_pll1443x_mp_change(const struct imx_int_pll_rate_table *rate, - u32 pll_div_ctl0, u32 pll_div_ctl1) -{ - u32 old_mdiv, old_pdiv, old_kdiv; - - old_mdiv = (pll_div_ctl0 >> MDIV_SHIFT) & MDIV_MASK; - old_pdiv = (pll_div_ctl0 >> PDIV_SHIFT) & PDIV_MASK; - old_kdiv = (pll_div_ctl1 >> KDIV_SHIFT) & KDIV_MASK; - - return (rate->mdiv != old_mdiv || rate->pdiv != old_pdiv || - rate->kdiv != old_kdiv); -} - -static int clk_int_pll_wait_lock(struct clk_int_pll *pll) -{ - unsigned long timeout = jiffies + msecs_to_jiffies(10); - - /* Wait for PLL to lock */ - do { - if (readl_relaxed(pll->base) & LOCK_STATUS) - break; - if (time_after(jiffies, timeout)) - break; - } while (1); - - return readl_relaxed(pll->base) & LOCK_STATUS ? 0 : -ETIMEDOUT; -} - -static int clk_int_pll1416x_set_rate(struct clk_hw *hw, unsigned long drate, - unsigned long prate) -{ - struct clk_int_pll *pll = to_clk_int_pll(hw); - const struct imx_int_pll_rate_table *rate; - u32 tmp, div_val; - int ret; - - rate = imx_get_pll_settings(pll, drate); - if (!rate) { - pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__, - drate, clk_hw_get_name(hw)); - return -EINVAL; - } - - tmp = readl_relaxed(pll->base + 4); - - if (!clk_int_pll1416x_mp_change(rate, tmp)) { - tmp &= ~(SDIV_MASK) << SDIV_SHIFT; - tmp |= rate->sdiv << SDIV_SHIFT; - writel_relaxed(tmp, pll->base + 4); - - return 0; - } - - /* Bypass clock and set lock to pll output lock */ - tmp = readl_relaxed(pll->base); - tmp |= LOCK_SEL_MASK; - writel_relaxed(tmp, pll->base); - - /* Enable RST */ - tmp &= ~RST_MASK; - writel_relaxed(tmp, pll->base); - - div_val = (rate->mdiv << MDIV_SHIFT) | (rate->pdiv << PDIV_SHIFT) | - (rate->sdiv << SDIV_SHIFT); - writel_relaxed(div_val, pll->base + 0x4); - - /* - * According to SPEC, t3 - t2 need to be greater than - * 1us and 1/FREF, respectively. - * FREF is FIN / Prediv, the prediv is [1, 63], so choose - * 3us. - */ - udelay(3); - - /* Disable RST */ - tmp |= RST_MASK; - writel_relaxed(tmp, pll->base); - - /* Wait Lock */ - ret = clk_int_pll_wait_lock(pll); - if (ret) - return ret; - - /* Bypass */ - tmp &= ~BYPASS_MASK; - writel_relaxed(tmp, pll->base); - - return 0; -} - -static int clk_int_pll1443x_set_rate(struct clk_hw *hw, unsigned long drate, - unsigned long prate) -{ - struct clk_int_pll *pll = to_clk_int_pll(hw); - const struct imx_int_pll_rate_table *rate; - u32 tmp, div_val; - int ret; - - rate = imx_get_pll_settings(pll, drate); - if (!rate) { - pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__, - drate, clk_hw_get_name(hw)); - return -EINVAL; - } - - tmp = readl_relaxed(pll->base + 4); - div_val = readl_relaxed(pll->base + 8); - - if (!clk_int_pll1443x_mpk_change(rate, tmp, div_val)) { - tmp &= ~(SDIV_MASK) << SDIV_SHIFT; - tmp |= rate->sdiv << SDIV_SHIFT; - writel_relaxed(tmp, pll->base + 4); - - return 0; - } - - /* Enable RST */ - tmp = readl_relaxed(pll->base); - tmp &= ~RST_MASK; - writel_relaxed(tmp, pll->base); - - div_val = (rate->mdiv << MDIV_SHIFT) | (rate->pdiv << PDIV_SHIFT) | - (rate->sdiv << SDIV_SHIFT); - writel_relaxed(div_val, pll->base + 0x4); - writel_relaxed(rate->kdiv << KDIV_SHIFT, pll->base + 0x8); - - /* - * According to SPEC, t3 - t2 need to be greater than - * 1us and 1/FREF, respectively. - * FREF is FIN / Prediv, the prediv is [1, 63], so choose - * 3us. - */ - udelay(3); - - /* Disable RST */ - tmp |= RST_MASK; - writel_relaxed(tmp, pll->base); - - /* Wait Lock*/ - ret = clk_int_pll_wait_lock(pll); - if (ret) - return ret; - - /* Bypass */ - tmp &= ~BYPASS_MASK; - writel_relaxed(tmp, pll->base); - - return 0; -} - -static int clk_int_pll_prepare(struct clk_hw *hw) -{ - struct clk_int_pll *pll = to_clk_int_pll(hw); - u32 val; - - /* - * RESETB = 1 from 0, PLL starts its normal - * operation after lock time - */ - val = readl_relaxed(pll->base + GNRL_CTL); - val |= RST_MASK; - writel_relaxed(val, pll->base + GNRL_CTL); - - return clk_int_pll_wait_lock(pll); -} - -static int clk_int_pll_is_prepared(struct clk_hw *hw) -{ - struct clk_int_pll *pll = to_clk_int_pll(hw); - u32 val; - - val = readl_relaxed(pll->base + GNRL_CTL); - - return (val & RST_MASK) ? 1 : 0; -} - -static void clk_int_pll_unprepare(struct clk_hw *hw) -{ - struct clk_int_pll *pll = to_clk_int_pll(hw); - u32 val; - - /* - * Set RST to 0, power down mode is enabled and - * every digital block is reset - */ - val = readl_relaxed(pll->base + GNRL_CTL); - val &= ~RST_MASK; - writel_relaxed(val, pll->base + GNRL_CTL); -} - -static const struct clk_ops clk_pll1416x_ops = { - .prepare = clk_int_pll_prepare, - .unprepare = clk_int_pll_unprepare, - .is_prepared = clk_int_pll_is_prepared, - .recalc_rate = clk_int_pll1416x_recalc_rate, - .round_rate = clk_int_pll_round_rate, - .set_rate = clk_int_pll1416x_set_rate, -}; - -static const struct clk_ops clk_pll1416x_min_ops = { - .recalc_rate = clk_int_pll1416x_recalc_rate, -}; - -static const struct clk_ops clk_pll1443x_ops = { - .prepare = clk_int_pll_prepare, - .unprepare = clk_int_pll_unprepare, - .is_prepared = clk_int_pll_is_prepared, - .recalc_rate = clk_int_pll1443x_recalc_rate, - .round_rate = clk_int_pll_round_rate, - .set_rate = clk_int_pll1443x_set_rate, -}; - -struct clk *imx_clk_int_pll(const char *name, const char *parent_name, - void __iomem *base, - const struct imx_int_pll_clk *pll_clk) -{ - struct clk_int_pll *pll; - struct clk *clk; - struct clk_init_data init; - int len; - - pll = kzalloc(sizeof(*pll), GFP_KERNEL); - if (!pll) - return ERR_PTR(-ENOMEM); - - init.name = name; - init.flags = pll_clk->flags; - init.parent_names = &parent_name; - init.num_parents = 1; - - if (pll_clk->rate_table) { - for (len = 0; pll_clk->rate_table[len].rate != 0; ) - len++; - - pll->rate_count = len; - pll->rate_table = kmemdup(pll_clk->rate_table, - pll->rate_count * - sizeof(struct imx_int_pll_rate_table), - GFP_KERNEL); - WARN(!pll->rate_table, "%s : could not alloc rate table\n", __func__); - } - - switch (pll_clk->type) { - case PLL_1416X: - if (!pll->rate_table) - init.ops = &clk_pll1416x_min_ops; - else - init.ops = &clk_pll1416x_ops; - break; - case PLL_1443X: - init.ops = &clk_pll1443x_ops; - break; - default: - pr_err("%s: Unknown pll type for pll clk %s\n", - __func__, name); - }; - - pll->base = base; - pll->hw.init = &init; - pll->type = pll_clk->type; - - clk = clk_register(NULL, &pll->hw); - if (IS_ERR(clk)) { - pr_err("%s: failed to register pll %s %lu\n", - __func__, name, PTR_ERR(clk)); - kfree(pll); - } - - return clk; -} diff --git a/drivers/clk/imx/clk-pll14xx.c b/drivers/clk/imx/clk-pll14xx.c new file mode 100644 index 000000000000..f6d66581c085 --- /dev/null +++ b/drivers/clk/imx/clk-pll14xx.c @@ -0,0 +1,429 @@ +/* + * Copyright 2017-2018 NXP. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +#define GNRL_CTL 0x0 +#define DIV_CTL 0x4 +#define LOCK_STATUS BIT(31) +#define LOCK_SEL_MASK BIT(29) +#define CLKE_MASK BIT(11) +#define RST_MASK BIT(9) +#define BYPASS_MASK BIT(4) +#define MDIV_SHIFT 12 +#define MDIV_MASK GENMASK(21, 12) +#define PDIV_SHIFT 4 +#define PDIV_MASK GENMASK(9, 4) +#define SDIV_SHIFT 0 +#define SDIV_MASK GENMASK(2, 0) +#define KDIV_SHIFT 0 +#define KDIV_MASK GENMASK(15, 0) + +struct clk_pll14xx { + struct clk_hw hw; + void __iomem *base; + enum imx_pll14xx_type type; + const struct imx_pll14xx_rate_table *rate_table; + int rate_count; +}; + +#define to_clk_pll14xx(_hw) container_of(_hw, struct clk_pll14xx, hw) + +static const struct imx_pll14xx_rate_table *imx_get_pll_settings( + struct clk_pll14xx *pll, unsigned long rate) +{ + const struct imx_pll14xx_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_pll14xx_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct clk_pll14xx *pll = to_clk_pll14xx(hw); + const struct imx_pll14xx_rate_table *rate_table = pll->rate_table; + int i; + + /* Assumming rate_table is in descending order */ + for (i = 0; i < pll->rate_count; i++) + if (rate >= rate_table[i].rate) + return rate_table[i].rate; + + /* return minimum supported value */ + return rate_table[i - 1].rate; +} + +static unsigned long clk_pll1416x_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_pll14xx *pll = to_clk_pll14xx(hw); + u32 mdiv, pdiv, sdiv, pll_gnrl, pll_div; + u64 fvco = parent_rate; + + pll_gnrl = readl_relaxed(pll->base); + pll_div = readl_relaxed(pll->base + 4); + mdiv = (pll_div & MDIV_MASK) >> MDIV_SHIFT; + pdiv = (pll_div & PDIV_MASK) >> PDIV_SHIFT; + sdiv = (pll_div & SDIV_MASK) >> SDIV_SHIFT; + + fvco *= mdiv; + do_div(fvco, pdiv << sdiv); + + return fvco; +} + +static unsigned long clk_pll1443x_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_pll14xx *pll = to_clk_pll14xx(hw); + const struct imx_pll14xx_rate_table *rate_table = pll->rate_table; + u32 mdiv, pdiv, sdiv, pll_gnrl, pll_div_ctl0, pll_div_ctl1; + short int kdiv; + u64 fvco = parent_rate; + long rate = 0; + int i; + + pll_gnrl = readl_relaxed(pll->base); + pll_div_ctl0 = readl_relaxed(pll->base + 4); + pll_div_ctl1 = readl_relaxed(pll->base + 8); + mdiv = (pll_div_ctl0 & MDIV_MASK) >> MDIV_SHIFT; + pdiv = (pll_div_ctl0 & PDIV_MASK) >> PDIV_SHIFT; + sdiv = (pll_div_ctl0 & SDIV_MASK) >> SDIV_SHIFT; + kdiv = pll_div_ctl1 & KDIV_MASK; + + /* + * Sometimes, the recalculated rate has deviation due to + * the frac part. So find the accurate pll rate from the table + * first, if no match rate in the table, use the rate calculated + * from the equation below. + */ + for (i = 0; i < pll->rate_count; i++) { + if (rate_table[i].pdiv == pdiv && rate_table[i].mdiv == mdiv && + rate_table[i].sdiv == sdiv && rate_table[i].kdiv == kdiv) + rate = rate_table[i].rate; + } + + /* fvco = (m * 65536 + k) * Fin / (p * 65536) */ + fvco *= (mdiv * 65536 + kdiv); + pdiv *= 65536; + + do_div(fvco, pdiv << sdiv); + + return rate ? (unsigned long) rate : (unsigned long)fvco; +} + +static inline bool clk_pll1416x_mp_change(const struct imx_pll14xx_rate_table *rate, + u32 pll_div) +{ + u32 old_mdiv, old_pdiv; + + old_mdiv = (pll_div >> MDIV_SHIFT) & MDIV_MASK; + old_pdiv = (pll_div >> PDIV_SHIFT) & PDIV_MASK; + + return rate->mdiv != old_mdiv || rate->pdiv != old_pdiv; +} + +static inline bool clk_pll1443x_mpk_change(const struct imx_pll14xx_rate_table *rate, + u32 pll_div_ctl0, u32 pll_div_ctl1) +{ + u32 old_mdiv, old_pdiv, old_kdiv; + + old_mdiv = (pll_div_ctl0 >> MDIV_SHIFT) & MDIV_MASK; + old_pdiv = (pll_div_ctl0 >> PDIV_SHIFT) & PDIV_MASK; + old_kdiv = (pll_div_ctl1 >> KDIV_SHIFT) & KDIV_MASK; + + return rate->mdiv != old_mdiv || rate->pdiv != old_pdiv || + rate->kdiv != old_kdiv; +} + +static inline bool clk_pll1443x_mp_change(const struct imx_pll14xx_rate_table *rate, + u32 pll_div_ctl0, u32 pll_div_ctl1) +{ + u32 old_mdiv, old_pdiv, old_kdiv; + + old_mdiv = (pll_div_ctl0 >> MDIV_SHIFT) & MDIV_MASK; + old_pdiv = (pll_div_ctl0 >> PDIV_SHIFT) & PDIV_MASK; + old_kdiv = (pll_div_ctl1 >> KDIV_SHIFT) & KDIV_MASK; + + return rate->mdiv != old_mdiv || rate->pdiv != old_pdiv || + rate->kdiv != old_kdiv; +} + +static int clk_pll14xx_wait_lock(struct clk_pll14xx *pll) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(10); + + /* Wait for PLL to lock */ + do { + if (readl_relaxed(pll->base) & LOCK_STATUS) + break; + if (time_after(jiffies, timeout)) + break; + } while (1); + + return readl_relaxed(pll->base) & LOCK_STATUS ? 0 : -ETIMEDOUT; +} + +static int clk_pll1416x_set_rate(struct clk_hw *hw, unsigned long drate, + unsigned long prate) +{ + struct clk_pll14xx *pll = to_clk_pll14xx(hw); + const struct imx_pll14xx_rate_table *rate; + u32 tmp, div_val; + int ret; + + rate = imx_get_pll_settings(pll, drate); + if (!rate) { + pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__, + drate, clk_hw_get_name(hw)); + return -EINVAL; + } + + tmp = readl_relaxed(pll->base + 4); + + if (!clk_pll1416x_mp_change(rate, tmp)) { + tmp &= ~(SDIV_MASK) << SDIV_SHIFT; + tmp |= rate->sdiv << SDIV_SHIFT; + writel_relaxed(tmp, pll->base + 4); + + return 0; + } + + /* Bypass clock and set lock to pll output lock */ + tmp = readl_relaxed(pll->base); + tmp |= LOCK_SEL_MASK; + writel_relaxed(tmp, pll->base); + + /* Enable RST */ + tmp &= ~RST_MASK; + writel_relaxed(tmp, pll->base); + + div_val = (rate->mdiv << MDIV_SHIFT) | (rate->pdiv << PDIV_SHIFT) | + (rate->sdiv << SDIV_SHIFT); + writel_relaxed(div_val, pll->base + 0x4); + + /* + * According to SPEC, t3 - t2 need to be greater than + * 1us and 1/FREF, respectively. + * FREF is FIN / Prediv, the prediv is [1, 63], so choose + * 3us. + */ + udelay(3); + + /* Disable RST */ + tmp |= RST_MASK; + writel_relaxed(tmp, pll->base); + + /* Wait Lock */ + ret = clk_pll14xx_wait_lock(pll); + if (ret) + return ret; + + /* Bypass */ + tmp &= ~BYPASS_MASK; + writel_relaxed(tmp, pll->base); + + return 0; +} + +static int clk_pll1443x_set_rate(struct clk_hw *hw, unsigned long drate, + unsigned long prate) +{ + struct clk_pll14xx *pll = to_clk_pll14xx(hw); + const struct imx_pll14xx_rate_table *rate; + u32 tmp, div_val; + int ret; + + rate = imx_get_pll_settings(pll, drate); + if (!rate) { + pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__, + drate, clk_hw_get_name(hw)); + return -EINVAL; + } + + tmp = readl_relaxed(pll->base + 4); + div_val = readl_relaxed(pll->base + 8); + + if (!clk_pll1443x_mpk_change(rate, tmp, div_val)) { + tmp &= ~(SDIV_MASK) << SDIV_SHIFT; + tmp |= rate->sdiv << SDIV_SHIFT; + writel_relaxed(tmp, pll->base + 4); + + return 0; + } + + /* Enable RST */ + tmp = readl_relaxed(pll->base); + tmp &= ~RST_MASK; + writel_relaxed(tmp, pll->base); + + div_val = (rate->mdiv << MDIV_SHIFT) | (rate->pdiv << PDIV_SHIFT) | + (rate->sdiv << SDIV_SHIFT); + writel_relaxed(div_val, pll->base + 0x4); + writel_relaxed(rate->kdiv << KDIV_SHIFT, pll->base + 0x8); + + /* + * According to SPEC, t3 - t2 need to be greater than + * 1us and 1/FREF, respectively. + * FREF is FIN / Prediv, the prediv is [1, 63], so choose + * 3us. + */ + udelay(3); + + /* Disable RST */ + tmp |= RST_MASK; + writel_relaxed(tmp, pll->base); + + /* Wait Lock*/ + ret = clk_pll14xx_wait_lock(pll); + if (ret) + return ret; + + /* Bypass */ + tmp &= ~BYPASS_MASK; + writel_relaxed(tmp, pll->base); + + return 0; +} + +static int clk_pll14xx_prepare(struct clk_hw *hw) +{ + struct clk_pll14xx *pll = to_clk_pll14xx(hw); + u32 val; + + /* + * RESETB = 1 from 0, PLL starts its normal + * operation after lock time + */ + val = readl_relaxed(pll->base + GNRL_CTL); + val |= RST_MASK; + writel_relaxed(val, pll->base + GNRL_CTL); + + return clk_pll14xx_wait_lock(pll); +} + +static int clk_pll14xx_is_prepared(struct clk_hw *hw) +{ + struct clk_pll14xx *pll = to_clk_pll14xx(hw); + u32 val; + + val = readl_relaxed(pll->base + GNRL_CTL); + + return (val & RST_MASK) ? 1 : 0; +} + +static void clk_pll14xx_unprepare(struct clk_hw *hw) +{ + struct clk_pll14xx *pll = to_clk_pll14xx(hw); + u32 val; + + /* + * Set RST to 0, power down mode is enabled and + * every digital block is reset + */ + val = readl_relaxed(pll->base + GNRL_CTL); + val &= ~RST_MASK; + writel_relaxed(val, pll->base + GNRL_CTL); +} + +static const struct clk_ops clk_pll1416x_ops = { + .prepare = clk_pll14xx_prepare, + .unprepare = clk_pll14xx_unprepare, + .is_prepared = clk_pll14xx_is_prepared, + .recalc_rate = clk_pll1416x_recalc_rate, + .round_rate = clk_pll14xx_round_rate, + .set_rate = clk_pll1416x_set_rate, +}; + +static const struct clk_ops clk_pll1416x_min_ops = { + .recalc_rate = clk_pll1416x_recalc_rate, +}; + +static const struct clk_ops clk_pll1443x_ops = { + .prepare = clk_pll14xx_prepare, + .unprepare = clk_pll14xx_unprepare, + .is_prepared = clk_pll14xx_is_prepared, + .recalc_rate = clk_pll1443x_recalc_rate, + .round_rate = clk_pll14xx_round_rate, + .set_rate = clk_pll1443x_set_rate, +}; + +struct clk *imx_clk_pll14xx(const char *name, const char *parent_name, + void __iomem *base, + const struct imx_pll14xx_clk *pll_clk) +{ + struct clk_pll14xx *pll; + struct clk *clk; + struct clk_init_data init; + int len; + + pll = kzalloc(sizeof(*pll), GFP_KERNEL); + if (!pll) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.flags = pll_clk->flags; + init.parent_names = &parent_name; + init.num_parents = 1; + + if (pll_clk->rate_table) { + for (len = 0; pll_clk->rate_table[len].rate != 0; ) + len++; + + pll->rate_count = len; + pll->rate_table = kmemdup(pll_clk->rate_table, + pll->rate_count * + sizeof(struct imx_pll14xx_rate_table), + GFP_KERNEL); + WARN(!pll->rate_table, "%s : could not alloc rate table\n", __func__); + } + + switch (pll_clk->type) { + case PLL_1416X: + if (!pll->rate_table) + init.ops = &clk_pll1416x_min_ops; + else + init.ops = &clk_pll1416x_ops; + break; + case PLL_1443X: + init.ops = &clk_pll1443x_ops; + break; + default: + pr_err("%s: Unknown pll type for pll clk %s\n", + __func__, name); + }; + + pll->base = base; + pll->hw.init = &init; + pll->type = pll_clk->type; + + clk = clk_register(NULL, &pll->hw); + if (IS_ERR(clk)) { + pr_err("%s: failed to register pll %s %lu\n", + __func__, name, PTR_ERR(clk)); + kfree(pll); + } + + return clk; +} diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index d1ab0557ace5..f50226075230 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -27,13 +27,13 @@ enum imx_pllv1_type { IMX_PLLV1_IMX35, }; -enum imx_int_pll_type { +enum imx_pll14xx_type { PLL_1416X, PLL_1443X, }; /* NOTE: Rate table should be kept sorted in descending order. */ -struct imx_int_pll_rate_table { +struct imx_pll14xx_rate_table { unsigned int rate; unsigned int pdiv; unsigned int mdiv; @@ -41,13 +41,14 @@ struct imx_int_pll_rate_table { unsigned int kdiv; }; -struct imx_int_pll_clk { - enum imx_int_pll_type type; - const struct imx_int_pll_rate_table *rate_table; +struct imx_pll14xx_clk { + enum imx_pll14xx_type type; + const struct imx_pll14xx_rate_table *rate_table; int flags; }; -struct clk *imx_clk_int_pll(const char *name, const char *parent_name, void __iomem *base, const struct imx_int_pll_clk *pll_clk); +struct clk *imx_clk_pll14xx(const char *name, const char *parent_name, + void __iomem *base, const struct imx_pll14xx_clk *pll_clk); struct clk *imx_clk_pllv1(enum imx_pllv1_type type, const char *name, const char *parent, void __iomem *base);