361 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2023 Nuvoton Technology Corp.4 * Author: Chi-Fang Li <cfli0@nuvoton.com>5 */6 7#include <linux/bitfield.h>8#include <linux/clk-provider.h>9#include <linux/container_of.h>10#include <linux/device.h>11#include <linux/io.h>12#include <linux/kernel.h>13#include <linux/math64.h>14#include <linux/slab.h>15#include <linux/units.h>16#include <dt-bindings/clock/nuvoton,ma35d1-clk.h>17 18#include "clk-ma35d1.h"19 20/* PLL frequency limits */21#define PLL_FREF_MAX_FREQ (200 * HZ_PER_MHZ)22#define PLL_FREF_MIN_FREQ (1 * HZ_PER_MHZ)23#define PLL_FREF_M_MAX_FREQ (40 * HZ_PER_MHZ)24#define PLL_FREF_M_MIN_FREQ (10 * HZ_PER_MHZ)25#define PLL_FCLK_MAX_FREQ (2400 * HZ_PER_MHZ)26#define PLL_FCLK_MIN_FREQ (600 * HZ_PER_MHZ)27#define PLL_FCLKO_MAX_FREQ (2400 * HZ_PER_MHZ)28#define PLL_FCLKO_MIN_FREQ (85700 * HZ_PER_KHZ)29#define PLL_SS_RATE 0x7730#define PLL_SLOPE 0x58CFA31 32#define REG_PLL_CTL0_OFFSET 0x033#define REG_PLL_CTL1_OFFSET 0x434#define REG_PLL_CTL2_OFFSET 0x835 36/* bit fields for REG_CLK_PLL0CTL0, which is SMIC PLL design */37#define SPLL0_CTL0_FBDIV GENMASK(7, 0)38#define SPLL0_CTL0_INDIV GENMASK(11, 8)39#define SPLL0_CTL0_OUTDIV GENMASK(13, 12)40#define SPLL0_CTL0_PD BIT(16)41#define SPLL0_CTL0_BP BIT(17)42 43/* bit fields for REG_CLK_PLLxCTL0 ~ REG_CLK_PLLxCTL2, where x = 2 ~ 5 */44#define PLL_CTL0_FBDIV GENMASK(10, 0)45#define PLL_CTL0_INDIV GENMASK(17, 12)46#define PLL_CTL0_MODE GENMASK(19, 18)47#define PLL_CTL0_SSRATE GENMASK(30, 20)48#define PLL_CTL1_PD BIT(0)49#define PLL_CTL1_BP BIT(1)50#define PLL_CTL1_OUTDIV GENMASK(6, 4)51#define PLL_CTL1_FRAC GENMASK(31, 24)52#define PLL_CTL2_SLOPE GENMASK(23, 0)53 54#define INDIV_MIN 155#define INDIV_MAX 6356#define FBDIV_MIN 1657#define FBDIV_MAX 204758#define FBDIV_FRAC_MIN 160059#define FBDIV_FRAC_MAX 20470060#define OUTDIV_MIN 161#define OUTDIV_MAX 762 63#define PLL_MODE_INT 064#define PLL_MODE_FRAC 165#define PLL_MODE_SS 266 67struct ma35d1_clk_pll {68 struct clk_hw hw;69 u32 id;70 u8 mode;71 void __iomem *ctl0_base;72 void __iomem *ctl1_base;73 void __iomem *ctl2_base;74};75 76static inline struct ma35d1_clk_pll *to_ma35d1_clk_pll(struct clk_hw *_hw)77{78 return container_of(_hw, struct ma35d1_clk_pll, hw);79}80 81static unsigned long ma35d1_calc_smic_pll_freq(u32 pll0_ctl0,82 unsigned long parent_rate)83{84 u32 m, n, p, outdiv;85 u64 pll_freq;86 87 if (pll0_ctl0 & SPLL0_CTL0_BP)88 return parent_rate;89 90 n = FIELD_GET(SPLL0_CTL0_FBDIV, pll0_ctl0);91 m = FIELD_GET(SPLL0_CTL0_INDIV, pll0_ctl0);92 p = FIELD_GET(SPLL0_CTL0_OUTDIV, pll0_ctl0);93 outdiv = 1 << p;94 pll_freq = (u64)parent_rate * n;95 div_u64(pll_freq, m * outdiv);96 return pll_freq;97}98 99static unsigned long ma35d1_calc_pll_freq(u8 mode, u32 *reg_ctl, unsigned long parent_rate)100{101 unsigned long pll_freq, x;102 u32 m, n, p;103 104 if (reg_ctl[1] & PLL_CTL1_BP)105 return parent_rate;106 107 n = FIELD_GET(PLL_CTL0_FBDIV, reg_ctl[0]);108 m = FIELD_GET(PLL_CTL0_INDIV, reg_ctl[0]);109 p = FIELD_GET(PLL_CTL1_OUTDIV, reg_ctl[1]);110 111 if (mode == PLL_MODE_INT) {112 pll_freq = (u64)parent_rate * n;113 div_u64(pll_freq, m * p);114 } else {115 x = FIELD_GET(PLL_CTL1_FRAC, reg_ctl[1]);116 /* 2 decimal places floating to integer (ex. 1.23 to 123) */117 n = n * 100 + ((x * 100) / FIELD_MAX(PLL_CTL1_FRAC));118 pll_freq = div_u64(parent_rate * n, 100 * m * p);119 }120 return pll_freq;121}122 123static int ma35d1_pll_find_closest(struct ma35d1_clk_pll *pll, unsigned long rate,124 unsigned long parent_rate, u32 *reg_ctl,125 unsigned long *freq)126{127 unsigned long min_diff = ULONG_MAX;128 int fbdiv_min, fbdiv_max;129 int p, m, n;130 131 *freq = 0;132 if (rate < PLL_FCLKO_MIN_FREQ || rate > PLL_FCLKO_MAX_FREQ)133 return -EINVAL;134 135 if (pll->mode == PLL_MODE_INT) {136 fbdiv_min = FBDIV_MIN;137 fbdiv_max = FBDIV_MAX;138 } else {139 fbdiv_min = FBDIV_FRAC_MIN;140 fbdiv_max = FBDIV_FRAC_MAX;141 }142 143 for (m = INDIV_MIN; m <= INDIV_MAX; m++) {144 for (n = fbdiv_min; n <= fbdiv_max; n++) {145 for (p = OUTDIV_MIN; p <= OUTDIV_MAX; p++) {146 unsigned long tmp, fout, fclk, diff;147 148 tmp = div_u64(parent_rate, m);149 if (tmp < PLL_FREF_M_MIN_FREQ ||150 tmp > PLL_FREF_M_MAX_FREQ)151 continue; /* constrain */152 153 fclk = div_u64(parent_rate * n, m);154 /* for 2 decimal places */155 if (pll->mode != PLL_MODE_INT)156 fclk = div_u64(fclk, 100);157 158 if (fclk < PLL_FCLK_MIN_FREQ ||159 fclk > PLL_FCLK_MAX_FREQ)160 continue; /* constrain */161 162 fout = div_u64(fclk, p);163 if (fout < PLL_FCLKO_MIN_FREQ ||164 fout > PLL_FCLKO_MAX_FREQ)165 continue; /* constrain */166 167 diff = abs(rate - fout);168 if (diff < min_diff) {169 reg_ctl[0] = FIELD_PREP(PLL_CTL0_INDIV, m) |170 FIELD_PREP(PLL_CTL0_FBDIV, n);171 reg_ctl[1] = FIELD_PREP(PLL_CTL1_OUTDIV, p);172 *freq = fout;173 min_diff = diff;174 if (min_diff == 0)175 break;176 }177 }178 }179 }180 if (*freq == 0)181 return -EINVAL; /* cannot find even one valid setting */182 return 0;183}184 185static int ma35d1_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,186 unsigned long parent_rate)187{188 struct ma35d1_clk_pll *pll = to_ma35d1_clk_pll(hw);189 u32 reg_ctl[3] = { 0 };190 unsigned long pll_freq;191 int ret;192 193 if (parent_rate < PLL_FREF_MIN_FREQ || parent_rate > PLL_FREF_MAX_FREQ)194 return -EINVAL;195 196 ret = ma35d1_pll_find_closest(pll, rate, parent_rate, reg_ctl, &pll_freq);197 if (ret != 0)198 return ret;199 200 switch (pll->mode) {201 case PLL_MODE_INT:202 reg_ctl[0] |= FIELD_PREP(PLL_CTL0_MODE, PLL_MODE_INT);203 break;204 case PLL_MODE_FRAC:205 reg_ctl[0] |= FIELD_PREP(PLL_CTL0_MODE, PLL_MODE_FRAC);206 break;207 case PLL_MODE_SS:208 reg_ctl[0] |= FIELD_PREP(PLL_CTL0_MODE, PLL_MODE_SS) |209 FIELD_PREP(PLL_CTL0_SSRATE, PLL_SS_RATE);210 reg_ctl[2] = FIELD_PREP(PLL_CTL2_SLOPE, PLL_SLOPE);211 break;212 }213 reg_ctl[1] |= PLL_CTL1_PD;214 215 writel_relaxed(reg_ctl[0], pll->ctl0_base);216 writel_relaxed(reg_ctl[1], pll->ctl1_base);217 writel_relaxed(reg_ctl[2], pll->ctl2_base);218 return 0;219}220 221static unsigned long ma35d1_clk_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)222{223 struct ma35d1_clk_pll *pll = to_ma35d1_clk_pll(hw);224 u32 reg_ctl[3];225 unsigned long pll_freq;226 227 if (parent_rate < PLL_FREF_MIN_FREQ || parent_rate > PLL_FREF_MAX_FREQ)228 return 0;229 230 switch (pll->id) {231 case CAPLL:232 reg_ctl[0] = readl_relaxed(pll->ctl0_base);233 pll_freq = ma35d1_calc_smic_pll_freq(reg_ctl[0], parent_rate);234 return pll_freq;235 case DDRPLL:236 case APLL:237 case EPLL:238 case VPLL:239 reg_ctl[0] = readl_relaxed(pll->ctl0_base);240 reg_ctl[1] = readl_relaxed(pll->ctl1_base);241 pll_freq = ma35d1_calc_pll_freq(pll->mode, reg_ctl, parent_rate);242 return pll_freq;243 }244 return 0;245}246 247static long ma35d1_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,248 unsigned long *parent_rate)249{250 struct ma35d1_clk_pll *pll = to_ma35d1_clk_pll(hw);251 u32 reg_ctl[3] = { 0 };252 unsigned long pll_freq;253 long ret;254 255 if (*parent_rate < PLL_FREF_MIN_FREQ || *parent_rate > PLL_FREF_MAX_FREQ)256 return -EINVAL;257 258 ret = ma35d1_pll_find_closest(pll, rate, *parent_rate, reg_ctl, &pll_freq);259 if (ret < 0)260 return ret;261 262 switch (pll->id) {263 case CAPLL:264 reg_ctl[0] = readl_relaxed(pll->ctl0_base);265 pll_freq = ma35d1_calc_smic_pll_freq(reg_ctl[0], *parent_rate);266 return pll_freq;267 case DDRPLL:268 case APLL:269 case EPLL:270 case VPLL:271 reg_ctl[0] = readl_relaxed(pll->ctl0_base);272 reg_ctl[1] = readl_relaxed(pll->ctl1_base);273 pll_freq = ma35d1_calc_pll_freq(pll->mode, reg_ctl, *parent_rate);274 return pll_freq;275 }276 return 0;277}278 279static int ma35d1_clk_pll_is_prepared(struct clk_hw *hw)280{281 struct ma35d1_clk_pll *pll = to_ma35d1_clk_pll(hw);282 u32 val = readl_relaxed(pll->ctl1_base);283 284 return !(val & PLL_CTL1_PD);285}286 287static int ma35d1_clk_pll_prepare(struct clk_hw *hw)288{289 struct ma35d1_clk_pll *pll = to_ma35d1_clk_pll(hw);290 u32 val;291 292 val = readl_relaxed(pll->ctl1_base);293 val &= ~PLL_CTL1_PD;294 writel_relaxed(val, pll->ctl1_base);295 return 0;296}297 298static void ma35d1_clk_pll_unprepare(struct clk_hw *hw)299{300 struct ma35d1_clk_pll *pll = to_ma35d1_clk_pll(hw);301 u32 val;302 303 val = readl_relaxed(pll->ctl1_base);304 val |= PLL_CTL1_PD;305 writel_relaxed(val, pll->ctl1_base);306}307 308static const struct clk_ops ma35d1_clk_pll_ops = {309 .is_prepared = ma35d1_clk_pll_is_prepared,310 .prepare = ma35d1_clk_pll_prepare,311 .unprepare = ma35d1_clk_pll_unprepare,312 .set_rate = ma35d1_clk_pll_set_rate,313 .recalc_rate = ma35d1_clk_pll_recalc_rate,314 .round_rate = ma35d1_clk_pll_round_rate,315};316 317static const struct clk_ops ma35d1_clk_fixed_pll_ops = {318 .recalc_rate = ma35d1_clk_pll_recalc_rate,319 .round_rate = ma35d1_clk_pll_round_rate,320};321 322struct clk_hw *ma35d1_reg_clk_pll(struct device *dev, u32 id, u8 u8mode, const char *name,323 struct clk_hw *parent_hw, void __iomem *base)324{325 struct clk_parent_data pdata = { .index = 0 };326 struct clk_init_data init = {};327 struct ma35d1_clk_pll *pll;328 struct clk_hw *hw;329 int ret;330 331 pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL);332 if (!pll)333 return ERR_PTR(-ENOMEM);334 335 pll->id = id;336 pll->mode = u8mode;337 pll->ctl0_base = base + REG_PLL_CTL0_OFFSET;338 pll->ctl1_base = base + REG_PLL_CTL1_OFFSET;339 pll->ctl2_base = base + REG_PLL_CTL2_OFFSET;340 341 init.name = name;342 init.flags = 0;343 pdata.hw = parent_hw;344 init.parent_data = &pdata;345 init.num_parents = 1;346 347 if (id == CAPLL || id == DDRPLL)348 init.ops = &ma35d1_clk_fixed_pll_ops;349 else350 init.ops = &ma35d1_clk_pll_ops;351 352 pll->hw.init = &init;353 hw = &pll->hw;354 355 ret = devm_clk_hw_register(dev, hw);356 if (ret)357 return ERR_PTR(ret);358 return hw;359}360EXPORT_SYMBOL_GPL(ma35d1_reg_clk_pll);361