162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright 2017-2018 NXP. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#define pr_fmt(fmt) "pll14xx: " fmt 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/bitfield.h> 962306a36Sopenharmony_ci#include <linux/bits.h> 1062306a36Sopenharmony_ci#include <linux/clk-provider.h> 1162306a36Sopenharmony_ci#include <linux/err.h> 1262306a36Sopenharmony_ci#include <linux/export.h> 1362306a36Sopenharmony_ci#include <linux/io.h> 1462306a36Sopenharmony_ci#include <linux/iopoll.h> 1562306a36Sopenharmony_ci#include <linux/slab.h> 1662306a36Sopenharmony_ci#include <linux/jiffies.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include "clk.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define GNRL_CTL 0x0 2162306a36Sopenharmony_ci#define DIV_CTL0 0x4 2262306a36Sopenharmony_ci#define DIV_CTL1 0x8 2362306a36Sopenharmony_ci#define LOCK_STATUS BIT(31) 2462306a36Sopenharmony_ci#define LOCK_SEL_MASK BIT(29) 2562306a36Sopenharmony_ci#define CLKE_MASK BIT(11) 2662306a36Sopenharmony_ci#define RST_MASK BIT(9) 2762306a36Sopenharmony_ci#define BYPASS_MASK BIT(4) 2862306a36Sopenharmony_ci#define MDIV_MASK GENMASK(21, 12) 2962306a36Sopenharmony_ci#define PDIV_MASK GENMASK(9, 4) 3062306a36Sopenharmony_ci#define SDIV_MASK GENMASK(2, 0) 3162306a36Sopenharmony_ci#define KDIV_MASK GENMASK(15, 0) 3262306a36Sopenharmony_ci#define KDIV_MIN SHRT_MIN 3362306a36Sopenharmony_ci#define KDIV_MAX SHRT_MAX 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#define LOCK_TIMEOUT_US 10000 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistruct clk_pll14xx { 3862306a36Sopenharmony_ci struct clk_hw hw; 3962306a36Sopenharmony_ci void __iomem *base; 4062306a36Sopenharmony_ci enum imx_pll14xx_type type; 4162306a36Sopenharmony_ci const struct imx_pll14xx_rate_table *rate_table; 4262306a36Sopenharmony_ci int rate_count; 4362306a36Sopenharmony_ci}; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#define to_clk_pll14xx(_hw) container_of(_hw, struct clk_pll14xx, hw) 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic const struct imx_pll14xx_rate_table imx_pll1416x_tbl[] = { 4862306a36Sopenharmony_ci PLL_1416X_RATE(1800000000U, 225, 3, 0), 4962306a36Sopenharmony_ci PLL_1416X_RATE(1600000000U, 200, 3, 0), 5062306a36Sopenharmony_ci PLL_1416X_RATE(1500000000U, 375, 3, 1), 5162306a36Sopenharmony_ci PLL_1416X_RATE(1400000000U, 350, 3, 1), 5262306a36Sopenharmony_ci PLL_1416X_RATE(1200000000U, 300, 3, 1), 5362306a36Sopenharmony_ci PLL_1416X_RATE(1000000000U, 250, 3, 1), 5462306a36Sopenharmony_ci PLL_1416X_RATE(800000000U, 200, 3, 1), 5562306a36Sopenharmony_ci PLL_1416X_RATE(750000000U, 250, 2, 2), 5662306a36Sopenharmony_ci PLL_1416X_RATE(700000000U, 350, 3, 2), 5762306a36Sopenharmony_ci PLL_1416X_RATE(640000000U, 320, 3, 2), 5862306a36Sopenharmony_ci PLL_1416X_RATE(600000000U, 300, 3, 2), 5962306a36Sopenharmony_ci PLL_1416X_RATE(320000000U, 160, 3, 2), 6062306a36Sopenharmony_ci}; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic const struct imx_pll14xx_rate_table imx_pll1443x_tbl[] = { 6362306a36Sopenharmony_ci PLL_1443X_RATE(1039500000U, 173, 2, 1, 16384), 6462306a36Sopenharmony_ci PLL_1443X_RATE(650000000U, 325, 3, 2, 0), 6562306a36Sopenharmony_ci PLL_1443X_RATE(594000000U, 198, 2, 2, 0), 6662306a36Sopenharmony_ci PLL_1443X_RATE(519750000U, 173, 2, 2, 16384), 6762306a36Sopenharmony_ci}; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistruct imx_pll14xx_clk imx_1443x_pll = { 7062306a36Sopenharmony_ci .type = PLL_1443X, 7162306a36Sopenharmony_ci .rate_table = imx_pll1443x_tbl, 7262306a36Sopenharmony_ci .rate_count = ARRAY_SIZE(imx_pll1443x_tbl), 7362306a36Sopenharmony_ci}; 7462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(imx_1443x_pll); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistruct imx_pll14xx_clk imx_1443x_dram_pll = { 7762306a36Sopenharmony_ci .type = PLL_1443X, 7862306a36Sopenharmony_ci .rate_table = imx_pll1443x_tbl, 7962306a36Sopenharmony_ci .rate_count = ARRAY_SIZE(imx_pll1443x_tbl), 8062306a36Sopenharmony_ci .flags = CLK_GET_RATE_NOCACHE, 8162306a36Sopenharmony_ci}; 8262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(imx_1443x_dram_pll); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistruct imx_pll14xx_clk imx_1416x_pll = { 8562306a36Sopenharmony_ci .type = PLL_1416X, 8662306a36Sopenharmony_ci .rate_table = imx_pll1416x_tbl, 8762306a36Sopenharmony_ci .rate_count = ARRAY_SIZE(imx_pll1416x_tbl), 8862306a36Sopenharmony_ci}; 8962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(imx_1416x_pll); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic const struct imx_pll14xx_rate_table *imx_get_pll_settings( 9262306a36Sopenharmony_ci struct clk_pll14xx *pll, unsigned long rate) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci const struct imx_pll14xx_rate_table *rate_table = pll->rate_table; 9562306a36Sopenharmony_ci int i; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci for (i = 0; i < pll->rate_count; i++) 9862306a36Sopenharmony_ci if (rate == rate_table[i].rate) 9962306a36Sopenharmony_ci return &rate_table[i]; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci return NULL; 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic long pll14xx_calc_rate(struct clk_pll14xx *pll, int mdiv, int pdiv, 10562306a36Sopenharmony_ci int sdiv, int kdiv, unsigned long prate) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci u64 fvco = prate; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci /* fvco = (m * 65536 + k) * Fin / (p * 65536) */ 11062306a36Sopenharmony_ci fvco *= (mdiv * 65536 + kdiv); 11162306a36Sopenharmony_ci pdiv *= 65536; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci do_div(fvco, pdiv << sdiv); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci return fvco; 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistatic long pll1443x_calc_kdiv(int mdiv, int pdiv, int sdiv, 11962306a36Sopenharmony_ci unsigned long rate, unsigned long prate) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci long kdiv; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci /* calc kdiv = round(rate * pdiv * 65536 * 2^sdiv / prate) - (mdiv * 65536) */ 12462306a36Sopenharmony_ci kdiv = ((rate * ((pdiv * 65536) << sdiv) + prate / 2) / prate) - (mdiv * 65536); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci return clamp_t(short, kdiv, KDIV_MIN, KDIV_MAX); 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic void imx_pll14xx_calc_settings(struct clk_pll14xx *pll, unsigned long rate, 13062306a36Sopenharmony_ci unsigned long prate, struct imx_pll14xx_rate_table *t) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci u32 pll_div_ctl0, pll_div_ctl1; 13362306a36Sopenharmony_ci int mdiv, pdiv, sdiv, kdiv; 13462306a36Sopenharmony_ci long fvco, rate_min, rate_max, dist, best = LONG_MAX; 13562306a36Sopenharmony_ci const struct imx_pll14xx_rate_table *tt; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci /* 13862306a36Sopenharmony_ci * Fractional PLL constrains: 13962306a36Sopenharmony_ci * 14062306a36Sopenharmony_ci * a) 1 <= p <= 63 14162306a36Sopenharmony_ci * b) 64 <= m <= 1023 14262306a36Sopenharmony_ci * c) 0 <= s <= 6 14362306a36Sopenharmony_ci * d) -32768 <= k <= 32767 14462306a36Sopenharmony_ci * 14562306a36Sopenharmony_ci * fvco = (m * 65536 + k) * prate / (p * 65536) 14662306a36Sopenharmony_ci */ 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci /* First try if we can get the desired rate from one of the static entries */ 14962306a36Sopenharmony_ci tt = imx_get_pll_settings(pll, rate); 15062306a36Sopenharmony_ci if (tt) { 15162306a36Sopenharmony_ci pr_debug("%s: in=%ld, want=%ld, Using PLL setting from table\n", 15262306a36Sopenharmony_ci clk_hw_get_name(&pll->hw), prate, rate); 15362306a36Sopenharmony_ci t->rate = tt->rate; 15462306a36Sopenharmony_ci t->mdiv = tt->mdiv; 15562306a36Sopenharmony_ci t->pdiv = tt->pdiv; 15662306a36Sopenharmony_ci t->sdiv = tt->sdiv; 15762306a36Sopenharmony_ci t->kdiv = tt->kdiv; 15862306a36Sopenharmony_ci return; 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci pll_div_ctl0 = readl_relaxed(pll->base + DIV_CTL0); 16262306a36Sopenharmony_ci mdiv = FIELD_GET(MDIV_MASK, pll_div_ctl0); 16362306a36Sopenharmony_ci pdiv = FIELD_GET(PDIV_MASK, pll_div_ctl0); 16462306a36Sopenharmony_ci sdiv = FIELD_GET(SDIV_MASK, pll_div_ctl0); 16562306a36Sopenharmony_ci pll_div_ctl1 = readl_relaxed(pll->base + DIV_CTL1); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci /* Then see if we can get the desired rate by only adjusting kdiv (glitch free) */ 16862306a36Sopenharmony_ci rate_min = pll14xx_calc_rate(pll, mdiv, pdiv, sdiv, KDIV_MIN, prate); 16962306a36Sopenharmony_ci rate_max = pll14xx_calc_rate(pll, mdiv, pdiv, sdiv, KDIV_MAX, prate); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci if (rate >= rate_min && rate <= rate_max) { 17262306a36Sopenharmony_ci kdiv = pll1443x_calc_kdiv(mdiv, pdiv, sdiv, rate, prate); 17362306a36Sopenharmony_ci pr_debug("%s: in=%ld, want=%ld Only adjust kdiv %ld -> %d\n", 17462306a36Sopenharmony_ci clk_hw_get_name(&pll->hw), prate, rate, 17562306a36Sopenharmony_ci FIELD_GET(KDIV_MASK, pll_div_ctl1), kdiv); 17662306a36Sopenharmony_ci fvco = pll14xx_calc_rate(pll, mdiv, pdiv, sdiv, kdiv, prate); 17762306a36Sopenharmony_ci t->rate = (unsigned int)fvco; 17862306a36Sopenharmony_ci t->mdiv = mdiv; 17962306a36Sopenharmony_ci t->pdiv = pdiv; 18062306a36Sopenharmony_ci t->sdiv = sdiv; 18162306a36Sopenharmony_ci t->kdiv = kdiv; 18262306a36Sopenharmony_ci return; 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci /* Finally calculate best values */ 18662306a36Sopenharmony_ci for (pdiv = 1; pdiv <= 63; pdiv++) { 18762306a36Sopenharmony_ci for (sdiv = 0; sdiv <= 6; sdiv++) { 18862306a36Sopenharmony_ci /* calc mdiv = round(rate * pdiv * 2^sdiv) / prate) */ 18962306a36Sopenharmony_ci mdiv = DIV_ROUND_CLOSEST(rate * (pdiv << sdiv), prate); 19062306a36Sopenharmony_ci mdiv = clamp(mdiv, 64, 1023); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci kdiv = pll1443x_calc_kdiv(mdiv, pdiv, sdiv, rate, prate); 19362306a36Sopenharmony_ci fvco = pll14xx_calc_rate(pll, mdiv, pdiv, sdiv, kdiv, prate); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci /* best match */ 19662306a36Sopenharmony_ci dist = abs((long)rate - (long)fvco); 19762306a36Sopenharmony_ci if (dist < best) { 19862306a36Sopenharmony_ci best = dist; 19962306a36Sopenharmony_ci t->rate = (unsigned int)fvco; 20062306a36Sopenharmony_ci t->mdiv = mdiv; 20162306a36Sopenharmony_ci t->pdiv = pdiv; 20262306a36Sopenharmony_ci t->sdiv = sdiv; 20362306a36Sopenharmony_ci t->kdiv = kdiv; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci if (!dist) 20662306a36Sopenharmony_ci goto found; 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_cifound: 21162306a36Sopenharmony_ci pr_debug("%s: in=%ld, want=%ld got=%d (pdiv=%d sdiv=%d mdiv=%d kdiv=%d)\n", 21262306a36Sopenharmony_ci clk_hw_get_name(&pll->hw), prate, rate, t->rate, t->pdiv, t->sdiv, 21362306a36Sopenharmony_ci t->mdiv, t->kdiv); 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic long clk_pll1416x_round_rate(struct clk_hw *hw, unsigned long rate, 21762306a36Sopenharmony_ci unsigned long *prate) 21862306a36Sopenharmony_ci{ 21962306a36Sopenharmony_ci struct clk_pll14xx *pll = to_clk_pll14xx(hw); 22062306a36Sopenharmony_ci const struct imx_pll14xx_rate_table *rate_table = pll->rate_table; 22162306a36Sopenharmony_ci int i; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci /* Assuming rate_table is in descending order */ 22462306a36Sopenharmony_ci for (i = 0; i < pll->rate_count; i++) 22562306a36Sopenharmony_ci if (rate >= rate_table[i].rate) 22662306a36Sopenharmony_ci return rate_table[i].rate; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci /* return minimum supported value */ 22962306a36Sopenharmony_ci return rate_table[pll->rate_count - 1].rate; 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cistatic long clk_pll1443x_round_rate(struct clk_hw *hw, unsigned long rate, 23362306a36Sopenharmony_ci unsigned long *prate) 23462306a36Sopenharmony_ci{ 23562306a36Sopenharmony_ci struct clk_pll14xx *pll = to_clk_pll14xx(hw); 23662306a36Sopenharmony_ci struct imx_pll14xx_rate_table t; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci imx_pll14xx_calc_settings(pll, rate, *prate, &t); 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci return t.rate; 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_cistatic unsigned long clk_pll14xx_recalc_rate(struct clk_hw *hw, 24462306a36Sopenharmony_ci unsigned long parent_rate) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci struct clk_pll14xx *pll = to_clk_pll14xx(hw); 24762306a36Sopenharmony_ci u32 mdiv, pdiv, sdiv, kdiv, pll_div_ctl0, pll_div_ctl1; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci pll_div_ctl0 = readl_relaxed(pll->base + DIV_CTL0); 25062306a36Sopenharmony_ci mdiv = FIELD_GET(MDIV_MASK, pll_div_ctl0); 25162306a36Sopenharmony_ci pdiv = FIELD_GET(PDIV_MASK, pll_div_ctl0); 25262306a36Sopenharmony_ci sdiv = FIELD_GET(SDIV_MASK, pll_div_ctl0); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci if (pll->type == PLL_1443X) { 25562306a36Sopenharmony_ci pll_div_ctl1 = readl_relaxed(pll->base + DIV_CTL1); 25662306a36Sopenharmony_ci kdiv = (s16)FIELD_GET(KDIV_MASK, pll_div_ctl1); 25762306a36Sopenharmony_ci } else { 25862306a36Sopenharmony_ci kdiv = 0; 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci return pll14xx_calc_rate(pll, mdiv, pdiv, sdiv, kdiv, parent_rate); 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_cistatic inline bool clk_pll14xx_mp_change(const struct imx_pll14xx_rate_table *rate, 26562306a36Sopenharmony_ci u32 pll_div) 26662306a36Sopenharmony_ci{ 26762306a36Sopenharmony_ci u32 old_mdiv, old_pdiv; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci old_mdiv = FIELD_GET(MDIV_MASK, pll_div); 27062306a36Sopenharmony_ci old_pdiv = FIELD_GET(PDIV_MASK, pll_div); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci return rate->mdiv != old_mdiv || rate->pdiv != old_pdiv; 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_cistatic int clk_pll14xx_wait_lock(struct clk_pll14xx *pll) 27662306a36Sopenharmony_ci{ 27762306a36Sopenharmony_ci u32 val; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci return readl_poll_timeout(pll->base + GNRL_CTL, val, val & LOCK_STATUS, 0, 28062306a36Sopenharmony_ci LOCK_TIMEOUT_US); 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_cistatic int clk_pll1416x_set_rate(struct clk_hw *hw, unsigned long drate, 28462306a36Sopenharmony_ci unsigned long prate) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci struct clk_pll14xx *pll = to_clk_pll14xx(hw); 28762306a36Sopenharmony_ci const struct imx_pll14xx_rate_table *rate; 28862306a36Sopenharmony_ci u32 tmp, div_val; 28962306a36Sopenharmony_ci int ret; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci rate = imx_get_pll_settings(pll, drate); 29262306a36Sopenharmony_ci if (!rate) { 29362306a36Sopenharmony_ci pr_err("Invalid rate %lu for pll clk %s\n", drate, 29462306a36Sopenharmony_ci clk_hw_get_name(hw)); 29562306a36Sopenharmony_ci return -EINVAL; 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci tmp = readl_relaxed(pll->base + DIV_CTL0); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci if (!clk_pll14xx_mp_change(rate, tmp)) { 30162306a36Sopenharmony_ci tmp &= ~SDIV_MASK; 30262306a36Sopenharmony_ci tmp |= FIELD_PREP(SDIV_MASK, rate->sdiv); 30362306a36Sopenharmony_ci writel_relaxed(tmp, pll->base + DIV_CTL0); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci return 0; 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci /* Bypass clock and set lock to pll output lock */ 30962306a36Sopenharmony_ci tmp = readl_relaxed(pll->base + GNRL_CTL); 31062306a36Sopenharmony_ci tmp |= LOCK_SEL_MASK; 31162306a36Sopenharmony_ci writel_relaxed(tmp, pll->base + GNRL_CTL); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci /* Enable RST */ 31462306a36Sopenharmony_ci tmp &= ~RST_MASK; 31562306a36Sopenharmony_ci writel_relaxed(tmp, pll->base + GNRL_CTL); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci /* Enable BYPASS */ 31862306a36Sopenharmony_ci tmp |= BYPASS_MASK; 31962306a36Sopenharmony_ci writel(tmp, pll->base + GNRL_CTL); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci div_val = FIELD_PREP(MDIV_MASK, rate->mdiv) | FIELD_PREP(PDIV_MASK, rate->pdiv) | 32262306a36Sopenharmony_ci FIELD_PREP(SDIV_MASK, rate->sdiv); 32362306a36Sopenharmony_ci writel_relaxed(div_val, pll->base + DIV_CTL0); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci /* 32662306a36Sopenharmony_ci * According to SPEC, t3 - t2 need to be greater than 32762306a36Sopenharmony_ci * 1us and 1/FREF, respectively. 32862306a36Sopenharmony_ci * FREF is FIN / Prediv, the prediv is [1, 63], so choose 32962306a36Sopenharmony_ci * 3us. 33062306a36Sopenharmony_ci */ 33162306a36Sopenharmony_ci udelay(3); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci /* Disable RST */ 33462306a36Sopenharmony_ci tmp |= RST_MASK; 33562306a36Sopenharmony_ci writel_relaxed(tmp, pll->base + GNRL_CTL); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci /* Wait Lock */ 33862306a36Sopenharmony_ci ret = clk_pll14xx_wait_lock(pll); 33962306a36Sopenharmony_ci if (ret) 34062306a36Sopenharmony_ci return ret; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci /* Bypass */ 34362306a36Sopenharmony_ci tmp &= ~BYPASS_MASK; 34462306a36Sopenharmony_ci writel_relaxed(tmp, pll->base + GNRL_CTL); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci return 0; 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_cistatic int clk_pll1443x_set_rate(struct clk_hw *hw, unsigned long drate, 35062306a36Sopenharmony_ci unsigned long prate) 35162306a36Sopenharmony_ci{ 35262306a36Sopenharmony_ci struct clk_pll14xx *pll = to_clk_pll14xx(hw); 35362306a36Sopenharmony_ci struct imx_pll14xx_rate_table rate; 35462306a36Sopenharmony_ci u32 gnrl_ctl, div_ctl0; 35562306a36Sopenharmony_ci int ret; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci imx_pll14xx_calc_settings(pll, drate, prate, &rate); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci div_ctl0 = readl_relaxed(pll->base + DIV_CTL0); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci if (!clk_pll14xx_mp_change(&rate, div_ctl0)) { 36262306a36Sopenharmony_ci /* only sdiv and/or kdiv changed - no need to RESET PLL */ 36362306a36Sopenharmony_ci div_ctl0 &= ~SDIV_MASK; 36462306a36Sopenharmony_ci div_ctl0 |= FIELD_PREP(SDIV_MASK, rate.sdiv); 36562306a36Sopenharmony_ci writel_relaxed(div_ctl0, pll->base + DIV_CTL0); 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci writel_relaxed(FIELD_PREP(KDIV_MASK, rate.kdiv), 36862306a36Sopenharmony_ci pll->base + DIV_CTL1); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci return 0; 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci /* Enable RST */ 37462306a36Sopenharmony_ci gnrl_ctl = readl_relaxed(pll->base + GNRL_CTL); 37562306a36Sopenharmony_ci gnrl_ctl &= ~RST_MASK; 37662306a36Sopenharmony_ci writel_relaxed(gnrl_ctl, pll->base + GNRL_CTL); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci /* Enable BYPASS */ 37962306a36Sopenharmony_ci gnrl_ctl |= BYPASS_MASK; 38062306a36Sopenharmony_ci writel_relaxed(gnrl_ctl, pll->base + GNRL_CTL); 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci div_ctl0 = FIELD_PREP(MDIV_MASK, rate.mdiv) | 38362306a36Sopenharmony_ci FIELD_PREP(PDIV_MASK, rate.pdiv) | 38462306a36Sopenharmony_ci FIELD_PREP(SDIV_MASK, rate.sdiv); 38562306a36Sopenharmony_ci writel_relaxed(div_ctl0, pll->base + DIV_CTL0); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci writel_relaxed(FIELD_PREP(KDIV_MASK, rate.kdiv), pll->base + DIV_CTL1); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci /* 39062306a36Sopenharmony_ci * According to SPEC, t3 - t2 need to be greater than 39162306a36Sopenharmony_ci * 1us and 1/FREF, respectively. 39262306a36Sopenharmony_ci * FREF is FIN / Prediv, the prediv is [1, 63], so choose 39362306a36Sopenharmony_ci * 3us. 39462306a36Sopenharmony_ci */ 39562306a36Sopenharmony_ci udelay(3); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci /* Disable RST */ 39862306a36Sopenharmony_ci gnrl_ctl |= RST_MASK; 39962306a36Sopenharmony_ci writel_relaxed(gnrl_ctl, pll->base + GNRL_CTL); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci /* Wait Lock*/ 40262306a36Sopenharmony_ci ret = clk_pll14xx_wait_lock(pll); 40362306a36Sopenharmony_ci if (ret) 40462306a36Sopenharmony_ci return ret; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci /* Bypass */ 40762306a36Sopenharmony_ci gnrl_ctl &= ~BYPASS_MASK; 40862306a36Sopenharmony_ci writel_relaxed(gnrl_ctl, pll->base + GNRL_CTL); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci return 0; 41162306a36Sopenharmony_ci} 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_cistatic int clk_pll14xx_prepare(struct clk_hw *hw) 41462306a36Sopenharmony_ci{ 41562306a36Sopenharmony_ci struct clk_pll14xx *pll = to_clk_pll14xx(hw); 41662306a36Sopenharmony_ci u32 val; 41762306a36Sopenharmony_ci int ret; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci /* 42062306a36Sopenharmony_ci * RESETB = 1 from 0, PLL starts its normal 42162306a36Sopenharmony_ci * operation after lock time 42262306a36Sopenharmony_ci */ 42362306a36Sopenharmony_ci val = readl_relaxed(pll->base + GNRL_CTL); 42462306a36Sopenharmony_ci if (val & RST_MASK) 42562306a36Sopenharmony_ci return 0; 42662306a36Sopenharmony_ci val |= BYPASS_MASK; 42762306a36Sopenharmony_ci writel_relaxed(val, pll->base + GNRL_CTL); 42862306a36Sopenharmony_ci val |= RST_MASK; 42962306a36Sopenharmony_ci writel_relaxed(val, pll->base + GNRL_CTL); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci ret = clk_pll14xx_wait_lock(pll); 43262306a36Sopenharmony_ci if (ret) 43362306a36Sopenharmony_ci return ret; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci val &= ~BYPASS_MASK; 43662306a36Sopenharmony_ci writel_relaxed(val, pll->base + GNRL_CTL); 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci return 0; 43962306a36Sopenharmony_ci} 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_cistatic int clk_pll14xx_is_prepared(struct clk_hw *hw) 44262306a36Sopenharmony_ci{ 44362306a36Sopenharmony_ci struct clk_pll14xx *pll = to_clk_pll14xx(hw); 44462306a36Sopenharmony_ci u32 val; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci val = readl_relaxed(pll->base + GNRL_CTL); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci return (val & RST_MASK) ? 1 : 0; 44962306a36Sopenharmony_ci} 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_cistatic void clk_pll14xx_unprepare(struct clk_hw *hw) 45262306a36Sopenharmony_ci{ 45362306a36Sopenharmony_ci struct clk_pll14xx *pll = to_clk_pll14xx(hw); 45462306a36Sopenharmony_ci u32 val; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci /* 45762306a36Sopenharmony_ci * Set RST to 0, power down mode is enabled and 45862306a36Sopenharmony_ci * every digital block is reset 45962306a36Sopenharmony_ci */ 46062306a36Sopenharmony_ci val = readl_relaxed(pll->base + GNRL_CTL); 46162306a36Sopenharmony_ci val &= ~RST_MASK; 46262306a36Sopenharmony_ci writel_relaxed(val, pll->base + GNRL_CTL); 46362306a36Sopenharmony_ci} 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_cistatic const struct clk_ops clk_pll1416x_ops = { 46662306a36Sopenharmony_ci .prepare = clk_pll14xx_prepare, 46762306a36Sopenharmony_ci .unprepare = clk_pll14xx_unprepare, 46862306a36Sopenharmony_ci .is_prepared = clk_pll14xx_is_prepared, 46962306a36Sopenharmony_ci .recalc_rate = clk_pll14xx_recalc_rate, 47062306a36Sopenharmony_ci .round_rate = clk_pll1416x_round_rate, 47162306a36Sopenharmony_ci .set_rate = clk_pll1416x_set_rate, 47262306a36Sopenharmony_ci}; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_cistatic const struct clk_ops clk_pll1416x_min_ops = { 47562306a36Sopenharmony_ci .recalc_rate = clk_pll14xx_recalc_rate, 47662306a36Sopenharmony_ci}; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_cistatic const struct clk_ops clk_pll1443x_ops = { 47962306a36Sopenharmony_ci .prepare = clk_pll14xx_prepare, 48062306a36Sopenharmony_ci .unprepare = clk_pll14xx_unprepare, 48162306a36Sopenharmony_ci .is_prepared = clk_pll14xx_is_prepared, 48262306a36Sopenharmony_ci .recalc_rate = clk_pll14xx_recalc_rate, 48362306a36Sopenharmony_ci .round_rate = clk_pll1443x_round_rate, 48462306a36Sopenharmony_ci .set_rate = clk_pll1443x_set_rate, 48562306a36Sopenharmony_ci}; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_cistruct clk_hw *imx_dev_clk_hw_pll14xx(struct device *dev, const char *name, 48862306a36Sopenharmony_ci const char *parent_name, void __iomem *base, 48962306a36Sopenharmony_ci const struct imx_pll14xx_clk *pll_clk) 49062306a36Sopenharmony_ci{ 49162306a36Sopenharmony_ci struct clk_pll14xx *pll; 49262306a36Sopenharmony_ci struct clk_hw *hw; 49362306a36Sopenharmony_ci struct clk_init_data init; 49462306a36Sopenharmony_ci int ret; 49562306a36Sopenharmony_ci u32 val; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci pll = kzalloc(sizeof(*pll), GFP_KERNEL); 49862306a36Sopenharmony_ci if (!pll) 49962306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci init.name = name; 50262306a36Sopenharmony_ci init.flags = pll_clk->flags; 50362306a36Sopenharmony_ci init.parent_names = &parent_name; 50462306a36Sopenharmony_ci init.num_parents = 1; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci switch (pll_clk->type) { 50762306a36Sopenharmony_ci case PLL_1416X: 50862306a36Sopenharmony_ci if (!pll_clk->rate_table) 50962306a36Sopenharmony_ci init.ops = &clk_pll1416x_min_ops; 51062306a36Sopenharmony_ci else 51162306a36Sopenharmony_ci init.ops = &clk_pll1416x_ops; 51262306a36Sopenharmony_ci break; 51362306a36Sopenharmony_ci case PLL_1443X: 51462306a36Sopenharmony_ci init.ops = &clk_pll1443x_ops; 51562306a36Sopenharmony_ci break; 51662306a36Sopenharmony_ci default: 51762306a36Sopenharmony_ci pr_err("Unknown pll type for pll clk %s\n", name); 51862306a36Sopenharmony_ci kfree(pll); 51962306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci pll->base = base; 52362306a36Sopenharmony_ci pll->hw.init = &init; 52462306a36Sopenharmony_ci pll->type = pll_clk->type; 52562306a36Sopenharmony_ci pll->rate_table = pll_clk->rate_table; 52662306a36Sopenharmony_ci pll->rate_count = pll_clk->rate_count; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci val = readl_relaxed(pll->base + GNRL_CTL); 52962306a36Sopenharmony_ci val &= ~BYPASS_MASK; 53062306a36Sopenharmony_ci writel_relaxed(val, pll->base + GNRL_CTL); 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci hw = &pll->hw; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci ret = clk_hw_register(dev, hw); 53562306a36Sopenharmony_ci if (ret) { 53662306a36Sopenharmony_ci pr_err("failed to register pll %s %d\n", name, ret); 53762306a36Sopenharmony_ci kfree(pll); 53862306a36Sopenharmony_ci return ERR_PTR(ret); 53962306a36Sopenharmony_ci } 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci return hw; 54262306a36Sopenharmony_ci} 54362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(imx_dev_clk_hw_pll14xx); 544