Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (c) 2015 Endless Mobile, Inc.
0004  * Author: Carlo Caione <carlo@endlessm.com>
0005  *
0006  * Copyright (c) 2018 Baylibre, SAS.
0007  * Author: Jerome Brunet <jbrunet@baylibre.com>
0008  */
0009 
0010 /*
0011  * In the most basic form, a Meson PLL is composed as follows:
0012  *
0013  *                     PLL
0014  *        +--------------------------------+
0015  *        |                                |
0016  *        |             +--+               |
0017  *  in >>-----[ /N ]--->|  |      +-----+  |
0018  *        |             |  |------| DCO |---->> out
0019  *        |  +--------->|  |      +--v--+  |
0020  *        |  |          +--+         |     |
0021  *        |  |                       |     |
0022  *        |  +--[ *(M + (F/Fmax) ]<--+     |
0023  *        |                                |
0024  *        +--------------------------------+
0025  *
0026  * out = in * (m + frac / frac_max) / n
0027  */
0028 
0029 #include <linux/clk-provider.h>
0030 #include <linux/delay.h>
0031 #include <linux/err.h>
0032 #include <linux/io.h>
0033 #include <linux/math64.h>
0034 #include <linux/module.h>
0035 #include <linux/rational.h>
0036 
0037 #include "clk-regmap.h"
0038 #include "clk-pll.h"
0039 
0040 static inline struct meson_clk_pll_data *
0041 meson_clk_pll_data(struct clk_regmap *clk)
0042 {
0043     return (struct meson_clk_pll_data *)clk->data;
0044 }
0045 
0046 static int __pll_round_closest_mult(struct meson_clk_pll_data *pll)
0047 {
0048     if ((pll->flags & CLK_MESON_PLL_ROUND_CLOSEST) &&
0049         !MESON_PARM_APPLICABLE(&pll->frac))
0050         return 1;
0051 
0052     return 0;
0053 }
0054 
0055 static unsigned long __pll_params_to_rate(unsigned long parent_rate,
0056                       unsigned int m, unsigned int n,
0057                       unsigned int frac,
0058                       struct meson_clk_pll_data *pll)
0059 {
0060     u64 rate = (u64)parent_rate * m;
0061 
0062     if (frac && MESON_PARM_APPLICABLE(&pll->frac)) {
0063         u64 frac_rate = (u64)parent_rate * frac;
0064 
0065         rate += DIV_ROUND_UP_ULL(frac_rate,
0066                      (1 << pll->frac.width));
0067     }
0068 
0069     return DIV_ROUND_UP_ULL(rate, n);
0070 }
0071 
0072 static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw,
0073                         unsigned long parent_rate)
0074 {
0075     struct clk_regmap *clk = to_clk_regmap(hw);
0076     struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
0077     unsigned int m, n, frac;
0078 
0079     n = meson_parm_read(clk->map, &pll->n);
0080 
0081     /*
0082      * On some HW, N is set to zero on init. This value is invalid as
0083      * it would result in a division by zero. The rate can't be
0084      * calculated in this case
0085      */
0086     if (n == 0)
0087         return 0;
0088 
0089     m = meson_parm_read(clk->map, &pll->m);
0090 
0091     frac = MESON_PARM_APPLICABLE(&pll->frac) ?
0092         meson_parm_read(clk->map, &pll->frac) :
0093         0;
0094 
0095     return __pll_params_to_rate(parent_rate, m, n, frac, pll);
0096 }
0097 
0098 static unsigned int __pll_params_with_frac(unsigned long rate,
0099                        unsigned long parent_rate,
0100                        unsigned int m,
0101                        unsigned int n,
0102                        struct meson_clk_pll_data *pll)
0103 {
0104     unsigned int frac_max = (1 << pll->frac.width);
0105     u64 val = (u64)rate * n;
0106 
0107     /* Bail out if we are already over the requested rate */
0108     if (rate < parent_rate * m / n)
0109         return 0;
0110 
0111     if (pll->flags & CLK_MESON_PLL_ROUND_CLOSEST)
0112         val = DIV_ROUND_CLOSEST_ULL(val * frac_max, parent_rate);
0113     else
0114         val = div_u64(val * frac_max, parent_rate);
0115 
0116     val -= m * frac_max;
0117 
0118     return min((unsigned int)val, (frac_max - 1));
0119 }
0120 
0121 static bool meson_clk_pll_is_better(unsigned long rate,
0122                     unsigned long best,
0123                     unsigned long now,
0124                     struct meson_clk_pll_data *pll)
0125 {
0126     if (__pll_round_closest_mult(pll)) {
0127         /* Round Closest */
0128         if (abs(now - rate) < abs(best - rate))
0129             return true;
0130     } else {
0131         /* Round down */
0132         if (now <= rate && best < now)
0133             return true;
0134     }
0135 
0136     return false;
0137 }
0138 
0139 static int meson_clk_get_pll_table_index(unsigned int index,
0140                      unsigned int *m,
0141                      unsigned int *n,
0142                      struct meson_clk_pll_data *pll)
0143 {
0144     if (!pll->table[index].n)
0145         return -EINVAL;
0146 
0147     *m = pll->table[index].m;
0148     *n = pll->table[index].n;
0149 
0150     return 0;
0151 }
0152 
0153 static unsigned int meson_clk_get_pll_range_m(unsigned long rate,
0154                           unsigned long parent_rate,
0155                           unsigned int n,
0156                           struct meson_clk_pll_data *pll)
0157 {
0158     u64 val = (u64)rate * n;
0159 
0160     if (__pll_round_closest_mult(pll))
0161         return DIV_ROUND_CLOSEST_ULL(val, parent_rate);
0162 
0163     return div_u64(val,  parent_rate);
0164 }
0165 
0166 static int meson_clk_get_pll_range_index(unsigned long rate,
0167                      unsigned long parent_rate,
0168                      unsigned int index,
0169                      unsigned int *m,
0170                      unsigned int *n,
0171                      struct meson_clk_pll_data *pll)
0172 {
0173     *n = index + 1;
0174 
0175     /* Check the predivider range */
0176     if (*n >= (1 << pll->n.width))
0177         return -EINVAL;
0178 
0179     if (*n == 1) {
0180         /* Get the boundaries out the way */
0181         if (rate <= pll->range->min * parent_rate) {
0182             *m = pll->range->min;
0183             return -ENODATA;
0184         } else if (rate >= pll->range->max * parent_rate) {
0185             *m = pll->range->max;
0186             return -ENODATA;
0187         }
0188     }
0189 
0190     *m = meson_clk_get_pll_range_m(rate, parent_rate, *n, pll);
0191 
0192     /* the pre-divider gives a multiplier too big - stop */
0193     if (*m >= (1 << pll->m.width))
0194         return -EINVAL;
0195 
0196     return 0;
0197 }
0198 
0199 static int meson_clk_get_pll_get_index(unsigned long rate,
0200                        unsigned long parent_rate,
0201                        unsigned int index,
0202                        unsigned int *m,
0203                        unsigned int *n,
0204                        struct meson_clk_pll_data *pll)
0205 {
0206     if (pll->range)
0207         return meson_clk_get_pll_range_index(rate, parent_rate,
0208                              index, m, n, pll);
0209     else if (pll->table)
0210         return meson_clk_get_pll_table_index(index, m, n, pll);
0211 
0212     return -EINVAL;
0213 }
0214 
0215 static int meson_clk_get_pll_settings(unsigned long rate,
0216                       unsigned long parent_rate,
0217                       unsigned int *best_m,
0218                       unsigned int *best_n,
0219                       struct meson_clk_pll_data *pll)
0220 {
0221     unsigned long best = 0, now = 0;
0222     unsigned int i, m, n;
0223     int ret;
0224 
0225     for (i = 0, ret = 0; !ret; i++) {
0226         ret = meson_clk_get_pll_get_index(rate, parent_rate,
0227                           i, &m, &n, pll);
0228         if (ret == -EINVAL)
0229             break;
0230 
0231         now = __pll_params_to_rate(parent_rate, m, n, 0, pll);
0232         if (meson_clk_pll_is_better(rate, best, now, pll)) {
0233             best = now;
0234             *best_m = m;
0235             *best_n = n;
0236 
0237             if (now == rate)
0238                 break;
0239         }
0240     }
0241 
0242     return best ? 0 : -EINVAL;
0243 }
0244 
0245 static int meson_clk_pll_determine_rate(struct clk_hw *hw,
0246                     struct clk_rate_request *req)
0247 {
0248     struct clk_regmap *clk = to_clk_regmap(hw);
0249     struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
0250     unsigned int m, n, frac;
0251     unsigned long round;
0252     int ret;
0253 
0254     ret = meson_clk_get_pll_settings(req->rate, req->best_parent_rate,
0255                      &m, &n, pll);
0256     if (ret)
0257         return ret;
0258 
0259     round = __pll_params_to_rate(req->best_parent_rate, m, n, 0, pll);
0260 
0261     if (!MESON_PARM_APPLICABLE(&pll->frac) || req->rate == round) {
0262         req->rate = round;
0263         return 0;
0264     }
0265 
0266     /*
0267      * The rate provided by the setting is not an exact match, let's
0268      * try to improve the result using the fractional parameter
0269      */
0270     frac = __pll_params_with_frac(req->rate, req->best_parent_rate, m, n, pll);
0271     req->rate = __pll_params_to_rate(req->best_parent_rate, m, n, frac, pll);
0272 
0273     return 0;
0274 }
0275 
0276 static int meson_clk_pll_wait_lock(struct clk_hw *hw)
0277 {
0278     struct clk_regmap *clk = to_clk_regmap(hw);
0279     struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
0280     int delay = 24000000;
0281 
0282     do {
0283         /* Is the clock locked now ? */
0284         if (meson_parm_read(clk->map, &pll->l))
0285             return 0;
0286 
0287         delay--;
0288     } while (delay > 0);
0289 
0290     return -ETIMEDOUT;
0291 }
0292 
0293 static int meson_clk_pll_init(struct clk_hw *hw)
0294 {
0295     struct clk_regmap *clk = to_clk_regmap(hw);
0296     struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
0297 
0298     if (pll->init_count) {
0299         meson_parm_write(clk->map, &pll->rst, 1);
0300         regmap_multi_reg_write(clk->map, pll->init_regs,
0301                        pll->init_count);
0302         meson_parm_write(clk->map, &pll->rst, 0);
0303     }
0304 
0305     return 0;
0306 }
0307 
0308 static int meson_clk_pll_is_enabled(struct clk_hw *hw)
0309 {
0310     struct clk_regmap *clk = to_clk_regmap(hw);
0311     struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
0312 
0313     if (meson_parm_read(clk->map, &pll->rst) ||
0314         !meson_parm_read(clk->map, &pll->en) ||
0315         !meson_parm_read(clk->map, &pll->l))
0316         return 0;
0317 
0318     return 1;
0319 }
0320 
0321 static int meson_clk_pcie_pll_enable(struct clk_hw *hw)
0322 {
0323     meson_clk_pll_init(hw);
0324 
0325     if (meson_clk_pll_wait_lock(hw))
0326         return -EIO;
0327 
0328     return 0;
0329 }
0330 
0331 static int meson_clk_pll_enable(struct clk_hw *hw)
0332 {
0333     struct clk_regmap *clk = to_clk_regmap(hw);
0334     struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
0335 
0336     /* do nothing if the PLL is already enabled */
0337     if (clk_hw_is_enabled(hw))
0338         return 0;
0339 
0340     /* Make sure the pll is in reset */
0341     meson_parm_write(clk->map, &pll->rst, 1);
0342 
0343     /* Enable the pll */
0344     meson_parm_write(clk->map, &pll->en, 1);
0345 
0346     /* Take the pll out reset */
0347     meson_parm_write(clk->map, &pll->rst, 0);
0348 
0349     if (meson_clk_pll_wait_lock(hw))
0350         return -EIO;
0351 
0352     return 0;
0353 }
0354 
0355 static void meson_clk_pll_disable(struct clk_hw *hw)
0356 {
0357     struct clk_regmap *clk = to_clk_regmap(hw);
0358     struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
0359 
0360     /* Put the pll is in reset */
0361     meson_parm_write(clk->map, &pll->rst, 1);
0362 
0363     /* Disable the pll */
0364     meson_parm_write(clk->map, &pll->en, 0);
0365 }
0366 
0367 static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
0368                   unsigned long parent_rate)
0369 {
0370     struct clk_regmap *clk = to_clk_regmap(hw);
0371     struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
0372     unsigned int enabled, m, n, frac = 0;
0373     unsigned long old_rate;
0374     int ret;
0375 
0376     if (parent_rate == 0 || rate == 0)
0377         return -EINVAL;
0378 
0379     old_rate = clk_hw_get_rate(hw);
0380 
0381     ret = meson_clk_get_pll_settings(rate, parent_rate, &m, &n, pll);
0382     if (ret)
0383         return ret;
0384 
0385     enabled = meson_parm_read(clk->map, &pll->en);
0386     if (enabled)
0387         meson_clk_pll_disable(hw);
0388 
0389     meson_parm_write(clk->map, &pll->n, n);
0390     meson_parm_write(clk->map, &pll->m, m);
0391 
0392     if (MESON_PARM_APPLICABLE(&pll->frac)) {
0393         frac = __pll_params_with_frac(rate, parent_rate, m, n, pll);
0394         meson_parm_write(clk->map, &pll->frac, frac);
0395     }
0396 
0397     /* If the pll is stopped, bail out now */
0398     if (!enabled)
0399         return 0;
0400 
0401     ret = meson_clk_pll_enable(hw);
0402     if (ret) {
0403         pr_warn("%s: pll did not lock, trying to restore old rate %lu\n",
0404             __func__, old_rate);
0405         /*
0406          * FIXME: Do we really need/want this HACK ?
0407          * It looks unsafe. what happens if the clock gets into a
0408          * broken state and we can't lock back on the old_rate ? Looks
0409          * like an infinite recursion is possible
0410          */
0411         meson_clk_pll_set_rate(hw, old_rate, parent_rate);
0412     }
0413 
0414     return ret;
0415 }
0416 
0417 /*
0418  * The Meson G12A PCIE PLL is fined tuned to deliver a very precise
0419  * 100MHz reference clock for the PCIe Analog PHY, and thus requires
0420  * a strict register sequence to enable the PLL.
0421  * To simplify, re-use the _init() op to enable the PLL and keep
0422  * the other ops except set_rate since the rate is fixed.
0423  */
0424 const struct clk_ops meson_clk_pcie_pll_ops = {
0425     .recalc_rate    = meson_clk_pll_recalc_rate,
0426     .determine_rate = meson_clk_pll_determine_rate,
0427     .is_enabled = meson_clk_pll_is_enabled,
0428     .enable     = meson_clk_pcie_pll_enable,
0429     .disable    = meson_clk_pll_disable
0430 };
0431 EXPORT_SYMBOL_GPL(meson_clk_pcie_pll_ops);
0432 
0433 const struct clk_ops meson_clk_pll_ops = {
0434     .init       = meson_clk_pll_init,
0435     .recalc_rate    = meson_clk_pll_recalc_rate,
0436     .determine_rate = meson_clk_pll_determine_rate,
0437     .set_rate   = meson_clk_pll_set_rate,
0438     .is_enabled = meson_clk_pll_is_enabled,
0439     .enable     = meson_clk_pll_enable,
0440     .disable    = meson_clk_pll_disable
0441 };
0442 EXPORT_SYMBOL_GPL(meson_clk_pll_ops);
0443 
0444 const struct clk_ops meson_clk_pll_ro_ops = {
0445     .recalc_rate    = meson_clk_pll_recalc_rate,
0446     .is_enabled = meson_clk_pll_is_enabled,
0447 };
0448 EXPORT_SYMBOL_GPL(meson_clk_pll_ro_ops);
0449 
0450 MODULE_DESCRIPTION("Amlogic PLL driver");
0451 MODULE_AUTHOR("Carlo Caione <carlo@endlessm.com>");
0452 MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
0453 MODULE_LICENSE("GPL v2");