11b26cb8aSPeng Fan // SPDX-License-Identifier: GPL-2.0 21b26cb8aSPeng Fan /* 31b26cb8aSPeng Fan * Copyright 2021 NXP 41b26cb8aSPeng Fan */ 51b26cb8aSPeng Fan 61b26cb8aSPeng Fan #include <linux/bitfield.h> 71b26cb8aSPeng Fan #include <linux/clk-provider.h> 81b26cb8aSPeng Fan #include <linux/err.h> 91b26cb8aSPeng Fan #include <linux/export.h> 101b26cb8aSPeng Fan #include <linux/io.h> 111b26cb8aSPeng Fan #include <linux/iopoll.h> 121b26cb8aSPeng Fan #include <linux/slab.h> 131b26cb8aSPeng Fan #include <asm/div64.h> 141b26cb8aSPeng Fan 151b26cb8aSPeng Fan #include "clk.h" 161b26cb8aSPeng Fan 171b26cb8aSPeng Fan #define PLL_CTRL 0x0 181b26cb8aSPeng Fan #define CLKMUX_BYPASS BIT(2) 191b26cb8aSPeng Fan #define CLKMUX_EN BIT(1) 201b26cb8aSPeng Fan #define POWERUP_MASK BIT(0) 211b26cb8aSPeng Fan 221b26cb8aSPeng Fan #define PLL_ANA_PRG 0x10 231b26cb8aSPeng Fan #define PLL_SPREAD_SPECTRUM 0x30 241b26cb8aSPeng Fan 251b26cb8aSPeng Fan #define PLL_NUMERATOR 0x40 261b26cb8aSPeng Fan #define PLL_MFN_MASK GENMASK(31, 2) 271b26cb8aSPeng Fan 281b26cb8aSPeng Fan #define PLL_DENOMINATOR 0x50 291b26cb8aSPeng Fan #define PLL_MFD_MASK GENMASK(29, 0) 301b26cb8aSPeng Fan 311b26cb8aSPeng Fan #define PLL_DIV 0x60 321b26cb8aSPeng Fan #define PLL_MFI_MASK GENMASK(24, 16) 331b26cb8aSPeng Fan #define PLL_RDIV_MASK GENMASK(15, 13) 341b26cb8aSPeng Fan #define PLL_ODIV_MASK GENMASK(7, 0) 351b26cb8aSPeng Fan 361b26cb8aSPeng Fan #define PLL_DFS_CTRL(x) (0x70 + (x) * 0x10) 371b26cb8aSPeng Fan 381b26cb8aSPeng Fan #define PLL_STATUS 0xF0 391b26cb8aSPeng Fan #define LOCK_STATUS BIT(0) 401b26cb8aSPeng Fan 411b26cb8aSPeng Fan #define DFS_STATUS 0xF4 421b26cb8aSPeng Fan 431b26cb8aSPeng Fan #define LOCK_TIMEOUT_US 200 441b26cb8aSPeng Fan 451b26cb8aSPeng Fan #define PLL_FRACN_GP(_rate, _mfi, _mfn, _mfd, _rdiv, _odiv) \ 461b26cb8aSPeng Fan { \ 471b26cb8aSPeng Fan .rate = (_rate), \ 481b26cb8aSPeng Fan .mfi = (_mfi), \ 491b26cb8aSPeng Fan .mfn = (_mfn), \ 501b26cb8aSPeng Fan .mfd = (_mfd), \ 511b26cb8aSPeng Fan .rdiv = (_rdiv), \ 521b26cb8aSPeng Fan .odiv = (_odiv), \ 531b26cb8aSPeng Fan } 541b26cb8aSPeng Fan 551b26cb8aSPeng Fan struct clk_fracn_gppll { 561b26cb8aSPeng Fan struct clk_hw hw; 571b26cb8aSPeng Fan void __iomem *base; 581b26cb8aSPeng Fan const struct imx_fracn_gppll_rate_table *rate_table; 591b26cb8aSPeng Fan int rate_count; 601b26cb8aSPeng Fan }; 611b26cb8aSPeng Fan 621b26cb8aSPeng Fan /* 63*cf8dccfeSPeng Fan * Fvco = (Fref / rdiv) * (MFI + MFN / MFD) 64*cf8dccfeSPeng Fan * Fout = Fvco / odiv 65*cf8dccfeSPeng Fan * The (Fref / rdiv) should be in range 20MHz to 40MHz 66*cf8dccfeSPeng Fan * The Fvco should be in range 2.5Ghz to 5Ghz 671b26cb8aSPeng Fan */ 681b26cb8aSPeng Fan static const struct imx_fracn_gppll_rate_table fracn_tbl[] = { 69*cf8dccfeSPeng Fan PLL_FRACN_GP(650000000U, 162, 50, 100, 0, 6), 70044034efSPeng Fan PLL_FRACN_GP(594000000U, 198, 0, 1, 0, 8), 71*cf8dccfeSPeng Fan PLL_FRACN_GP(560000000U, 140, 0, 1, 0, 6), 72*cf8dccfeSPeng Fan PLL_FRACN_GP(498000000U, 166, 0, 1, 0, 8), 73c196175aSPeng Fan PLL_FRACN_GP(484000000U, 121, 0, 1, 0, 6), 74c196175aSPeng Fan PLL_FRACN_GP(445333333U, 167, 0, 1, 0, 9), 75*cf8dccfeSPeng Fan PLL_FRACN_GP(400000000U, 200, 0, 1, 0, 12), 76*cf8dccfeSPeng Fan PLL_FRACN_GP(393216000U, 163, 84, 100, 0, 10) 771b26cb8aSPeng Fan }; 781b26cb8aSPeng Fan 791b26cb8aSPeng Fan struct imx_fracn_gppll_clk imx_fracn_gppll = { 801b26cb8aSPeng Fan .rate_table = fracn_tbl, 811b26cb8aSPeng Fan .rate_count = ARRAY_SIZE(fracn_tbl), 821b26cb8aSPeng Fan }; 831b26cb8aSPeng Fan EXPORT_SYMBOL_GPL(imx_fracn_gppll); 841b26cb8aSPeng Fan 851b26cb8aSPeng Fan static inline struct clk_fracn_gppll *to_clk_fracn_gppll(struct clk_hw *hw) 861b26cb8aSPeng Fan { 871b26cb8aSPeng Fan return container_of(hw, struct clk_fracn_gppll, hw); 881b26cb8aSPeng Fan } 891b26cb8aSPeng Fan 901b26cb8aSPeng Fan static const struct imx_fracn_gppll_rate_table * 911b26cb8aSPeng Fan imx_get_pll_settings(struct clk_fracn_gppll *pll, unsigned long rate) 921b26cb8aSPeng Fan { 931b26cb8aSPeng Fan const struct imx_fracn_gppll_rate_table *rate_table = pll->rate_table; 941b26cb8aSPeng Fan int i; 951b26cb8aSPeng Fan 961b26cb8aSPeng Fan for (i = 0; i < pll->rate_count; i++) 971b26cb8aSPeng Fan if (rate == rate_table[i].rate) 981b26cb8aSPeng Fan return &rate_table[i]; 991b26cb8aSPeng Fan 1001b26cb8aSPeng Fan return NULL; 1011b26cb8aSPeng Fan } 1021b26cb8aSPeng Fan 1031b26cb8aSPeng Fan static long clk_fracn_gppll_round_rate(struct clk_hw *hw, unsigned long rate, 1041b26cb8aSPeng Fan unsigned long *prate) 1051b26cb8aSPeng Fan { 1061b26cb8aSPeng Fan struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw); 1071b26cb8aSPeng Fan const struct imx_fracn_gppll_rate_table *rate_table = pll->rate_table; 1081b26cb8aSPeng Fan int i; 1091b26cb8aSPeng Fan 1101b26cb8aSPeng Fan /* Assuming rate_table is in descending order */ 1111b26cb8aSPeng Fan for (i = 0; i < pll->rate_count; i++) 1121b26cb8aSPeng Fan if (rate >= rate_table[i].rate) 1131b26cb8aSPeng Fan return rate_table[i].rate; 1141b26cb8aSPeng Fan 1151b26cb8aSPeng Fan /* return minimum supported value */ 1161b26cb8aSPeng Fan return rate_table[pll->rate_count - 1].rate; 1171b26cb8aSPeng Fan } 1181b26cb8aSPeng Fan 1191b26cb8aSPeng Fan static unsigned long clk_fracn_gppll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) 1201b26cb8aSPeng Fan { 1211b26cb8aSPeng Fan struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw); 1221b26cb8aSPeng Fan const struct imx_fracn_gppll_rate_table *rate_table = pll->rate_table; 1231b26cb8aSPeng Fan u32 pll_numerator, pll_denominator, pll_div; 1241b26cb8aSPeng Fan u32 mfi, mfn, mfd, rdiv, odiv; 1251b26cb8aSPeng Fan u64 fvco = parent_rate; 1261b26cb8aSPeng Fan long rate = 0; 1271b26cb8aSPeng Fan int i; 1281b26cb8aSPeng Fan 1291b26cb8aSPeng Fan pll_numerator = readl_relaxed(pll->base + PLL_NUMERATOR); 1301b26cb8aSPeng Fan mfn = FIELD_GET(PLL_MFN_MASK, pll_numerator); 1311b26cb8aSPeng Fan 1321b26cb8aSPeng Fan pll_denominator = readl_relaxed(pll->base + PLL_DENOMINATOR); 1331b26cb8aSPeng Fan mfd = FIELD_GET(PLL_MFD_MASK, pll_denominator); 1341b26cb8aSPeng Fan 1351b26cb8aSPeng Fan pll_div = readl_relaxed(pll->base + PLL_DIV); 1361b26cb8aSPeng Fan mfi = FIELD_GET(PLL_MFI_MASK, pll_div); 1371b26cb8aSPeng Fan 1381b26cb8aSPeng Fan rdiv = FIELD_GET(PLL_RDIV_MASK, pll_div); 1391b26cb8aSPeng Fan odiv = FIELD_GET(PLL_ODIV_MASK, pll_div); 1401b26cb8aSPeng Fan 1411b26cb8aSPeng Fan /* 1421b26cb8aSPeng Fan * Sometimes, the recalculated rate has deviation due to 1431b26cb8aSPeng Fan * the frac part. So find the accurate pll rate from the table 1441b26cb8aSPeng Fan * first, if no match rate in the table, use the rate calculated 1451b26cb8aSPeng Fan * from the equation below. 1461b26cb8aSPeng Fan */ 1471b26cb8aSPeng Fan for (i = 0; i < pll->rate_count; i++) { 1481b26cb8aSPeng Fan if (rate_table[i].mfn == mfn && rate_table[i].mfi == mfi && 1491b26cb8aSPeng Fan rate_table[i].mfd == mfd && rate_table[i].rdiv == rdiv && 1501b26cb8aSPeng Fan rate_table[i].odiv == odiv) 1511b26cb8aSPeng Fan rate = rate_table[i].rate; 1521b26cb8aSPeng Fan } 1531b26cb8aSPeng Fan 1541b26cb8aSPeng Fan if (rate) 1551b26cb8aSPeng Fan return (unsigned long)rate; 1561b26cb8aSPeng Fan 157f300cb7fSPeng Fan if (!rdiv) 1585ebaf9f7SLiu Ying rdiv = rdiv + 1; 1595ebaf9f7SLiu Ying 1605ebaf9f7SLiu Ying switch (odiv) { 1615ebaf9f7SLiu Ying case 0: 1625ebaf9f7SLiu Ying odiv = 2; 1635ebaf9f7SLiu Ying break; 1645ebaf9f7SLiu Ying case 1: 1655ebaf9f7SLiu Ying odiv = 3; 1665ebaf9f7SLiu Ying break; 1675ebaf9f7SLiu Ying default: 1685ebaf9f7SLiu Ying break; 1695ebaf9f7SLiu Ying } 1705ebaf9f7SLiu Ying 1711b26cb8aSPeng Fan /* Fvco = Fref * (MFI + MFN / MFD) */ 1721b26cb8aSPeng Fan fvco = fvco * mfi * mfd + fvco * mfn; 1731b26cb8aSPeng Fan do_div(fvco, mfd * rdiv * odiv); 1741b26cb8aSPeng Fan 1751b26cb8aSPeng Fan return (unsigned long)fvco; 1761b26cb8aSPeng Fan } 1771b26cb8aSPeng Fan 1781b26cb8aSPeng Fan static int clk_fracn_gppll_wait_lock(struct clk_fracn_gppll *pll) 1791b26cb8aSPeng Fan { 1801b26cb8aSPeng Fan u32 val; 1811b26cb8aSPeng Fan 1821b26cb8aSPeng Fan return readl_poll_timeout(pll->base + PLL_STATUS, val, 1831b26cb8aSPeng Fan val & LOCK_STATUS, 0, LOCK_TIMEOUT_US); 1841b26cb8aSPeng Fan } 1851b26cb8aSPeng Fan 1861b26cb8aSPeng Fan static int clk_fracn_gppll_set_rate(struct clk_hw *hw, unsigned long drate, 1871b26cb8aSPeng Fan unsigned long prate) 1881b26cb8aSPeng Fan { 1891b26cb8aSPeng Fan struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw); 1901b26cb8aSPeng Fan const struct imx_fracn_gppll_rate_table *rate; 1911b26cb8aSPeng Fan u32 tmp, pll_div, ana_mfn; 1921b26cb8aSPeng Fan int ret; 1931b26cb8aSPeng Fan 1941b26cb8aSPeng Fan rate = imx_get_pll_settings(pll, drate); 1951b26cb8aSPeng Fan 1961b26cb8aSPeng Fan /* Disable output */ 1971b26cb8aSPeng Fan tmp = readl_relaxed(pll->base + PLL_CTRL); 1981b26cb8aSPeng Fan tmp &= ~CLKMUX_EN; 1991b26cb8aSPeng Fan writel_relaxed(tmp, pll->base + PLL_CTRL); 2001b26cb8aSPeng Fan 2011b26cb8aSPeng Fan /* Power Down */ 2021b26cb8aSPeng Fan tmp &= ~POWERUP_MASK; 2031b26cb8aSPeng Fan writel_relaxed(tmp, pll->base + PLL_CTRL); 2041b26cb8aSPeng Fan 2051b26cb8aSPeng Fan /* Disable BYPASS */ 2061b26cb8aSPeng Fan tmp &= ~CLKMUX_BYPASS; 2071b26cb8aSPeng Fan writel_relaxed(tmp, pll->base + PLL_CTRL); 2081b26cb8aSPeng Fan 2091b26cb8aSPeng Fan pll_div = FIELD_PREP(PLL_RDIV_MASK, rate->rdiv) | rate->odiv | 2101b26cb8aSPeng Fan FIELD_PREP(PLL_MFI_MASK, rate->mfi); 2111b26cb8aSPeng Fan writel_relaxed(pll_div, pll->base + PLL_DIV); 2121b26cb8aSPeng Fan writel_relaxed(rate->mfd, pll->base + PLL_DENOMINATOR); 2131b26cb8aSPeng Fan writel_relaxed(FIELD_PREP(PLL_MFN_MASK, rate->mfn), pll->base + PLL_NUMERATOR); 2141b26cb8aSPeng Fan 2151b26cb8aSPeng Fan /* Wait for 5us according to fracn mode pll doc */ 2161b26cb8aSPeng Fan udelay(5); 2171b26cb8aSPeng Fan 2181b26cb8aSPeng Fan /* Enable Powerup */ 2191b26cb8aSPeng Fan tmp |= POWERUP_MASK; 2201b26cb8aSPeng Fan writel_relaxed(tmp, pll->base + PLL_CTRL); 2211b26cb8aSPeng Fan 2221b26cb8aSPeng Fan /* Wait Lock */ 2231b26cb8aSPeng Fan ret = clk_fracn_gppll_wait_lock(pll); 2241b26cb8aSPeng Fan if (ret) 2251b26cb8aSPeng Fan return ret; 2261b26cb8aSPeng Fan 2271b26cb8aSPeng Fan /* Enable output */ 2281b26cb8aSPeng Fan tmp |= CLKMUX_EN; 2291b26cb8aSPeng Fan writel_relaxed(tmp, pll->base + PLL_CTRL); 2301b26cb8aSPeng Fan 2311b26cb8aSPeng Fan ana_mfn = readl_relaxed(pll->base + PLL_STATUS); 2321b26cb8aSPeng Fan ana_mfn = FIELD_GET(PLL_MFN_MASK, ana_mfn); 2331b26cb8aSPeng Fan 2341b26cb8aSPeng Fan WARN(ana_mfn != rate->mfn, "ana_mfn != rate->mfn\n"); 2351b26cb8aSPeng Fan 2361b26cb8aSPeng Fan return 0; 2371b26cb8aSPeng Fan } 2381b26cb8aSPeng Fan 2391b26cb8aSPeng Fan static int clk_fracn_gppll_prepare(struct clk_hw *hw) 2401b26cb8aSPeng Fan { 2411b26cb8aSPeng Fan struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw); 2421b26cb8aSPeng Fan u32 val; 2431b26cb8aSPeng Fan int ret; 2441b26cb8aSPeng Fan 2451b26cb8aSPeng Fan val = readl_relaxed(pll->base + PLL_CTRL); 2461b26cb8aSPeng Fan if (val & POWERUP_MASK) 2471b26cb8aSPeng Fan return 0; 2481b26cb8aSPeng Fan 2491b26cb8aSPeng Fan val |= CLKMUX_BYPASS; 2501b26cb8aSPeng Fan writel_relaxed(val, pll->base + PLL_CTRL); 2511b26cb8aSPeng Fan 2521b26cb8aSPeng Fan val |= POWERUP_MASK; 2531b26cb8aSPeng Fan writel_relaxed(val, pll->base + PLL_CTRL); 2541b26cb8aSPeng Fan 2551b26cb8aSPeng Fan val |= CLKMUX_EN; 2561b26cb8aSPeng Fan writel_relaxed(val, pll->base + PLL_CTRL); 2571b26cb8aSPeng Fan 2581b26cb8aSPeng Fan ret = clk_fracn_gppll_wait_lock(pll); 2591b26cb8aSPeng Fan if (ret) 2601b26cb8aSPeng Fan return ret; 2611b26cb8aSPeng Fan 2621b26cb8aSPeng Fan val &= ~CLKMUX_BYPASS; 2631b26cb8aSPeng Fan writel_relaxed(val, pll->base + PLL_CTRL); 2641b26cb8aSPeng Fan 2651b26cb8aSPeng Fan return 0; 2661b26cb8aSPeng Fan } 2671b26cb8aSPeng Fan 2681b26cb8aSPeng Fan static int clk_fracn_gppll_is_prepared(struct clk_hw *hw) 2691b26cb8aSPeng Fan { 2701b26cb8aSPeng Fan struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw); 2711b26cb8aSPeng Fan u32 val; 2721b26cb8aSPeng Fan 2731b26cb8aSPeng Fan val = readl_relaxed(pll->base + PLL_CTRL); 2741b26cb8aSPeng Fan 2751b26cb8aSPeng Fan return (val & POWERUP_MASK) ? 1 : 0; 2761b26cb8aSPeng Fan } 2771b26cb8aSPeng Fan 2781b26cb8aSPeng Fan static void clk_fracn_gppll_unprepare(struct clk_hw *hw) 2791b26cb8aSPeng Fan { 2801b26cb8aSPeng Fan struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw); 2811b26cb8aSPeng Fan u32 val; 2821b26cb8aSPeng Fan 2831b26cb8aSPeng Fan val = readl_relaxed(pll->base + PLL_CTRL); 2841b26cb8aSPeng Fan val &= ~POWERUP_MASK; 2851b26cb8aSPeng Fan writel_relaxed(val, pll->base + PLL_CTRL); 2861b26cb8aSPeng Fan } 2871b26cb8aSPeng Fan 2881b26cb8aSPeng Fan static const struct clk_ops clk_fracn_gppll_ops = { 2891b26cb8aSPeng Fan .prepare = clk_fracn_gppll_prepare, 2901b26cb8aSPeng Fan .unprepare = clk_fracn_gppll_unprepare, 2911b26cb8aSPeng Fan .is_prepared = clk_fracn_gppll_is_prepared, 2921b26cb8aSPeng Fan .recalc_rate = clk_fracn_gppll_recalc_rate, 2931b26cb8aSPeng Fan .round_rate = clk_fracn_gppll_round_rate, 2941b26cb8aSPeng Fan .set_rate = clk_fracn_gppll_set_rate, 2951b26cb8aSPeng Fan }; 2961b26cb8aSPeng Fan 2971b26cb8aSPeng Fan struct clk_hw *imx_clk_fracn_gppll(const char *name, const char *parent_name, void __iomem *base, 2981b26cb8aSPeng Fan const struct imx_fracn_gppll_clk *pll_clk) 2991b26cb8aSPeng Fan { 3001b26cb8aSPeng Fan struct clk_fracn_gppll *pll; 3011b26cb8aSPeng Fan struct clk_hw *hw; 3021b26cb8aSPeng Fan struct clk_init_data init; 3031b26cb8aSPeng Fan int ret; 3041b26cb8aSPeng Fan 3051b26cb8aSPeng Fan pll = kzalloc(sizeof(*pll), GFP_KERNEL); 3061b26cb8aSPeng Fan if (!pll) 3071b26cb8aSPeng Fan return ERR_PTR(-ENOMEM); 3081b26cb8aSPeng Fan 3091b26cb8aSPeng Fan init.name = name; 3101b26cb8aSPeng Fan init.flags = pll_clk->flags; 3111b26cb8aSPeng Fan init.parent_names = &parent_name; 3121b26cb8aSPeng Fan init.num_parents = 1; 3131b26cb8aSPeng Fan init.ops = &clk_fracn_gppll_ops; 3141b26cb8aSPeng Fan 3151b26cb8aSPeng Fan pll->base = base; 3161b26cb8aSPeng Fan pll->hw.init = &init; 3171b26cb8aSPeng Fan pll->rate_table = pll_clk->rate_table; 3181b26cb8aSPeng Fan pll->rate_count = pll_clk->rate_count; 3191b26cb8aSPeng Fan 3201b26cb8aSPeng Fan hw = &pll->hw; 3211b26cb8aSPeng Fan 3221b26cb8aSPeng Fan ret = clk_hw_register(NULL, hw); 3231b26cb8aSPeng Fan if (ret) { 3241b26cb8aSPeng Fan pr_err("%s: failed to register pll %s %d\n", __func__, name, ret); 3251b26cb8aSPeng Fan kfree(pll); 3261b26cb8aSPeng Fan return ERR_PTR(ret); 3271b26cb8aSPeng Fan } 3281b26cb8aSPeng Fan 3291b26cb8aSPeng Fan return hw; 3301b26cb8aSPeng Fan } 3311b26cb8aSPeng Fan EXPORT_SYMBOL_GPL(imx_clk_fracn_gppll); 332