Merge branches 'clk-range', 'clk-uniphier', 'clk-apple' and 'clk-qcom' into clk-next
[linux-2.6-microblaze.git] / drivers / clk / imx / clk-pll14xx.c
index 2b5ed86..1d0f79e 100644 (file)
@@ -3,6 +3,9 @@
  * Copyright 2017-2018 NXP.
  */
 
+#define pr_fmt(fmt) "pll14xx: " fmt
+
+#include <linux/bitfield.h>
 #include <linux/bits.h>
 #include <linux/clk-provider.h>
 #include <linux/err.h>
 #include "clk.h"
 
 #define GNRL_CTL       0x0
-#define DIV_CTL                0x4
+#define DIV_CTL0       0x4
+#define DIV_CTL1       0x8
 #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)
+#define KDIV_MIN       SHRT_MIN
+#define KDIV_MAX       SHRT_MAX
 
 #define LOCK_TIMEOUT_US                10000
 
@@ -99,62 +101,165 @@ static const struct imx_pll14xx_rate_table *imx_get_pll_settings(
        return NULL;
 }
 
-static long clk_pll14xx_round_rate(struct clk_hw *hw, unsigned long rate,
+static long pll14xx_calc_rate(struct clk_pll14xx *pll, int mdiv, int pdiv,
+                             int sdiv, int kdiv, unsigned long prate)
+{
+       u64 fvco = prate;
+
+       /* fvco = (m * 65536 + k) * Fin / (p * 65536) */
+       fvco *= (mdiv * 65536 + kdiv);
+       pdiv *= 65536;
+
+       do_div(fvco, pdiv << sdiv);
+
+       return fvco;
+}
+
+static long pll1443x_calc_kdiv(int mdiv, int pdiv, int sdiv,
+               unsigned long rate, unsigned long prate)
+{
+       long kdiv;
+
+       /* calc kdiv = round(rate * pdiv * 65536 * 2^sdiv / prate) - (mdiv * 65536) */
+       kdiv = ((rate * ((pdiv * 65536) << sdiv) + prate / 2) / prate) - (mdiv * 65536);
+
+       return clamp_t(short, kdiv, KDIV_MIN, KDIV_MAX);
+}
+
+static void imx_pll14xx_calc_settings(struct clk_pll14xx *pll, unsigned long rate,
+                                     unsigned long prate, struct imx_pll14xx_rate_table *t)
+{
+       u32 pll_div_ctl0, pll_div_ctl1;
+       int mdiv, pdiv, sdiv, kdiv;
+       long fvco, rate_min, rate_max, dist, best = LONG_MAX;
+       const struct imx_pll14xx_rate_table *tt;
+
+       /*
+        * Fractional PLL constrains:
+        *
+        * a) 6MHz <= prate <= 25MHz
+        * b) 1 <= p <= 63 (1 <= p <= 4 prate = 24MHz)
+        * c) 64 <= m <= 1023
+        * d) 0 <= s <= 6
+        * e) -32768 <= k <= 32767
+        *
+        * fvco = (m * 65536 + k) * prate / (p * 65536)
+        */
+
+       /* First try if we can get the desired rate from one of the static entries */
+       tt = imx_get_pll_settings(pll, rate);
+       if (tt) {
+               pr_debug("%s: in=%ld, want=%ld, Using PLL setting from table\n",
+                        clk_hw_get_name(&pll->hw), prate, rate);
+               t->rate = tt->rate;
+               t->mdiv = tt->mdiv;
+               t->pdiv = tt->pdiv;
+               t->sdiv = tt->sdiv;
+               t->kdiv = tt->kdiv;
+               return;
+       }
+
+       pll_div_ctl0 = readl_relaxed(pll->base + DIV_CTL0);
+       mdiv = FIELD_GET(MDIV_MASK, pll_div_ctl0);
+       pdiv = FIELD_GET(PDIV_MASK, pll_div_ctl0);
+       sdiv = FIELD_GET(SDIV_MASK, pll_div_ctl0);
+       pll_div_ctl1 = readl_relaxed(pll->base + DIV_CTL1);
+
+       /* Then see if we can get the desired rate by only adjusting kdiv (glitch free) */
+       rate_min = pll14xx_calc_rate(pll, mdiv, pdiv, sdiv, KDIV_MIN, prate);
+       rate_max = pll14xx_calc_rate(pll, mdiv, pdiv, sdiv, KDIV_MAX, prate);
+
+       if (rate >= rate_min && rate <= rate_max) {
+               kdiv = pll1443x_calc_kdiv(mdiv, pdiv, sdiv, rate, prate);
+               pr_debug("%s: in=%ld, want=%ld Only adjust kdiv %ld -> %d\n",
+                        clk_hw_get_name(&pll->hw), prate, rate,
+                        FIELD_GET(KDIV_MASK, pll_div_ctl1), kdiv);
+               fvco = pll14xx_calc_rate(pll, mdiv, pdiv, sdiv, kdiv, prate);
+               t->rate = (unsigned int)fvco;
+               t->mdiv = mdiv;
+               t->pdiv = pdiv;
+               t->sdiv = sdiv;
+               t->kdiv = kdiv;
+               return;
+       }
+
+       /* Finally calculate best values */
+       for (pdiv = 1; pdiv <= 7; pdiv++) {
+               for (sdiv = 0; sdiv <= 6; sdiv++) {
+                       /* calc mdiv = round(rate * pdiv * 2^sdiv) / prate) */
+                       mdiv = DIV_ROUND_CLOSEST(rate * (pdiv << sdiv), prate);
+                       mdiv = clamp(mdiv, 64, 1023);
+
+                       kdiv = pll1443x_calc_kdiv(mdiv, pdiv, sdiv, rate, prate);
+                       fvco = pll14xx_calc_rate(pll, mdiv, pdiv, sdiv, kdiv, prate);
+
+                       /* best match */
+                       dist = abs((long)rate - (long)fvco);
+                       if (dist < best) {
+                               best = dist;
+                               t->rate = (unsigned int)fvco;
+                               t->mdiv = mdiv;
+                               t->pdiv = pdiv;
+                               t->sdiv = sdiv;
+                               t->kdiv = kdiv;
+
+                               if (!dist)
+                                       goto found;
+                       }
+               }
+       }
+found:
+       pr_debug("%s: in=%ld, want=%ld got=%d (pdiv=%d sdiv=%d mdiv=%d kdiv=%d)\n",
+                clk_hw_get_name(&pll->hw), prate, rate, t->rate, t->pdiv, t->sdiv,
+                t->mdiv, t->kdiv);
+}
+
+static long clk_pll1416x_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 */
+       /* Assuming 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;
+       return rate_table[pll->rate_count - 1].rate;
 }
 
-static unsigned long clk_pll1416x_recalc_rate(struct clk_hw *hw,
-                                                 unsigned long parent_rate)
+static long clk_pll1443x_round_rate(struct clk_hw *hw, unsigned long rate,
+                       unsigned long *prate)
 {
        struct clk_pll14xx *pll = to_clk_pll14xx(hw);
-       u32 mdiv, pdiv, sdiv, pll_div;
-       u64 fvco = parent_rate;
+       struct imx_pll14xx_rate_table t;
 
-       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;
+       imx_pll14xx_calc_settings(pll, rate, *prate, &t);
 
-       fvco *= mdiv;
-       do_div(fvco, pdiv << sdiv);
-
-       return fvco;
+       return t.rate;
 }
 
-static unsigned long clk_pll1443x_recalc_rate(struct clk_hw *hw,
+static unsigned long clk_pll14xx_recalc_rate(struct clk_hw *hw,
                                                  unsigned long parent_rate)
 {
        struct clk_pll14xx *pll = to_clk_pll14xx(hw);
-       u32 mdiv, pdiv, sdiv, pll_div_ctl0, pll_div_ctl1;
-       short int kdiv;
-       u64 fvco = parent_rate;
-
-       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;
-
-       /* fvco = (m * 65536 + k) * Fin / (p * 65536) */
-       fvco *= (mdiv * 65536 + kdiv);
-       pdiv *= 65536;
-
-       do_div(fvco, pdiv << sdiv);
+       u32 mdiv, pdiv, sdiv, kdiv, pll_div_ctl0, pll_div_ctl1;
+
+       pll_div_ctl0 = readl_relaxed(pll->base + DIV_CTL0);
+       mdiv = FIELD_GET(MDIV_MASK, pll_div_ctl0);
+       pdiv = FIELD_GET(PDIV_MASK, pll_div_ctl0);
+       sdiv = FIELD_GET(SDIV_MASK, pll_div_ctl0);
+
+       if (pll->type == PLL_1443X) {
+               pll_div_ctl1 = readl_relaxed(pll->base + DIV_CTL1);
+               kdiv = FIELD_GET(KDIV_MASK, pll_div_ctl1);
+       } else {
+               kdiv = 0;
+       }
 
-       return fvco;
+       return pll14xx_calc_rate(pll, mdiv, pdiv, sdiv, kdiv, parent_rate);
 }
 
 static inline bool clk_pll14xx_mp_change(const struct imx_pll14xx_rate_table *rate,
@@ -162,8 +267,8 @@ static inline bool clk_pll14xx_mp_change(const struct imx_pll14xx_rate_table *ra
 {
        u32 old_mdiv, old_pdiv;
 
-       old_mdiv = (pll_div & MDIV_MASK) >> MDIV_SHIFT;
-       old_pdiv = (pll_div & PDIV_MASK) >> PDIV_SHIFT;
+       old_mdiv = FIELD_GET(MDIV_MASK, pll_div);
+       old_pdiv = FIELD_GET(PDIV_MASK, pll_div);
 
        return rate->mdiv != old_mdiv || rate->pdiv != old_pdiv;
 }
@@ -172,7 +277,7 @@ static int clk_pll14xx_wait_lock(struct clk_pll14xx *pll)
 {
        u32 val;
 
-       return readl_poll_timeout(pll->base, val, val & LOCK_STATUS, 0,
+       return readl_poll_timeout(pll->base + GNRL_CTL, val, val & LOCK_STATUS, 0,
                        LOCK_TIMEOUT_US);
 }
 
@@ -186,37 +291,37 @@ static int clk_pll1416x_set_rate(struct clk_hw *hw, unsigned long drate,
 
        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));
+               pr_err("Invalid rate %lu for pll clk %s\n", drate,
+                      clk_hw_get_name(hw));
                return -EINVAL;
        }
 
-       tmp = readl_relaxed(pll->base + 4);
+       tmp = readl_relaxed(pll->base + DIV_CTL0);
 
        if (!clk_pll14xx_mp_change(rate, tmp)) {
-               tmp &= ~(SDIV_MASK) << SDIV_SHIFT;
-               tmp |= rate->sdiv << SDIV_SHIFT;
-               writel_relaxed(tmp, pll->base + 4);
+               tmp &= ~SDIV_MASK;
+               tmp |= FIELD_PREP(SDIV_MASK, rate->sdiv);
+               writel_relaxed(tmp, pll->base + DIV_CTL0);
 
                return 0;
        }
 
        /* Bypass clock and set lock to pll output lock */
-       tmp = readl_relaxed(pll->base);
+       tmp = readl_relaxed(pll->base + GNRL_CTL);
        tmp |= LOCK_SEL_MASK;
-       writel_relaxed(tmp, pll->base);
+       writel_relaxed(tmp, pll->base + GNRL_CTL);
 
        /* Enable RST */
        tmp &= ~RST_MASK;
-       writel_relaxed(tmp, pll->base);
+       writel_relaxed(tmp, pll->base + GNRL_CTL);
 
        /* Enable BYPASS */
        tmp |= BYPASS_MASK;
-       writel(tmp, pll->base);
+       writel(tmp, pll->base + GNRL_CTL);
 
-       div_val = (rate->mdiv << MDIV_SHIFT) | (rate->pdiv << PDIV_SHIFT) |
-               (rate->sdiv << SDIV_SHIFT);
-       writel_relaxed(div_val, pll->base + 0x4);
+       div_val = FIELD_PREP(MDIV_MASK, rate->mdiv) | FIELD_PREP(PDIV_MASK, rate->pdiv) |
+               FIELD_PREP(SDIV_MASK, rate->sdiv);
+       writel_relaxed(div_val, pll->base + DIV_CTL0);
 
        /*
         * According to SPEC, t3 - t2 need to be greater than
@@ -228,7 +333,7 @@ static int clk_pll1416x_set_rate(struct clk_hw *hw, unsigned long drate,
 
        /* Disable RST */
        tmp |= RST_MASK;
-       writel_relaxed(tmp, pll->base);
+       writel_relaxed(tmp, pll->base + GNRL_CTL);
 
        /* Wait Lock */
        ret = clk_pll14xx_wait_lock(pll);
@@ -237,7 +342,7 @@ static int clk_pll1416x_set_rate(struct clk_hw *hw, unsigned long drate,
 
        /* Bypass */
        tmp &= ~BYPASS_MASK;
-       writel_relaxed(tmp, pll->base);
+       writel_relaxed(tmp, pll->base + GNRL_CTL);
 
        return 0;
 }
@@ -246,43 +351,41 @@ 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;
+       struct imx_pll14xx_rate_table rate;
+       u32 gnrl_ctl, div_ctl0;
        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;
-       }
+       imx_pll14xx_calc_settings(pll, drate, prate, &rate);
 
-       tmp = readl_relaxed(pll->base + 4);
+       div_ctl0 = readl_relaxed(pll->base + DIV_CTL0);
 
-       if (!clk_pll14xx_mp_change(rate, tmp)) {
-               tmp &= ~(SDIV_MASK) << SDIV_SHIFT;
-               tmp |= rate->sdiv << SDIV_SHIFT;
-               writel_relaxed(tmp, pll->base + 4);
+       if (!clk_pll14xx_mp_change(&rate, div_ctl0)) {
+               /* only sdiv and/or kdiv changed - no need to RESET PLL */
+               div_ctl0 &= ~SDIV_MASK;
+               div_ctl0 |= FIELD_PREP(SDIV_MASK, rate.sdiv);
+               writel_relaxed(div_ctl0, pll->base + DIV_CTL0);
 
-               tmp = rate->kdiv << KDIV_SHIFT;
-               writel_relaxed(tmp, pll->base + 8);
+               writel_relaxed(FIELD_PREP(KDIV_MASK, rate.kdiv),
+                              pll->base + DIV_CTL1);
 
                return 0;
        }
 
        /* Enable RST */
-       tmp = readl_relaxed(pll->base);
-       tmp &= ~RST_MASK;
-       writel_relaxed(tmp, pll->base);
+       gnrl_ctl = readl_relaxed(pll->base + GNRL_CTL);
+       gnrl_ctl &= ~RST_MASK;
+       writel_relaxed(gnrl_ctl, pll->base + GNRL_CTL);
 
        /* Enable BYPASS */
-       tmp |= BYPASS_MASK;
-       writel_relaxed(tmp, pll->base);
+       gnrl_ctl |= BYPASS_MASK;
+       writel_relaxed(gnrl_ctl, pll->base + GNRL_CTL);
 
-       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);
+       div_ctl0 = FIELD_PREP(MDIV_MASK, rate.mdiv) |
+                  FIELD_PREP(PDIV_MASK, rate.pdiv) |
+                  FIELD_PREP(SDIV_MASK, rate.sdiv);
+       writel_relaxed(div_ctl0, pll->base + DIV_CTL0);
+
+       writel_relaxed(FIELD_PREP(KDIV_MASK, rate.kdiv), pll->base + DIV_CTL1);
 
        /*
         * According to SPEC, t3 - t2 need to be greater than
@@ -293,8 +396,8 @@ static int clk_pll1443x_set_rate(struct clk_hw *hw, unsigned long drate,
        udelay(3);
 
        /* Disable RST */
-       tmp |= RST_MASK;
-       writel_relaxed(tmp, pll->base);
+       gnrl_ctl |= RST_MASK;
+       writel_relaxed(gnrl_ctl, pll->base + GNRL_CTL);
 
        /* Wait Lock*/
        ret = clk_pll14xx_wait_lock(pll);
@@ -302,8 +405,8 @@ static int clk_pll1443x_set_rate(struct clk_hw *hw, unsigned long drate,
                return ret;
 
        /* Bypass */
-       tmp &= ~BYPASS_MASK;
-       writel_relaxed(tmp, pll->base);
+       gnrl_ctl &= ~BYPASS_MASK;
+       writel_relaxed(gnrl_ctl, pll->base + GNRL_CTL);
 
        return 0;
 }
@@ -364,21 +467,21 @@ 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,
+       .recalc_rate    = clk_pll14xx_recalc_rate,
+       .round_rate     = clk_pll1416x_round_rate,
        .set_rate       = clk_pll1416x_set_rate,
 };
 
 static const struct clk_ops clk_pll1416x_min_ops = {
-       .recalc_rate    = clk_pll1416x_recalc_rate,
+       .recalc_rate    = clk_pll14xx_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,
+       .recalc_rate    = clk_pll14xx_recalc_rate,
+       .round_rate     = clk_pll1443x_round_rate,
        .set_rate       = clk_pll1443x_set_rate,
 };
 
@@ -412,8 +515,7 @@ struct clk_hw *imx_dev_clk_hw_pll14xx(struct device *dev, const char *name,
                init.ops = &clk_pll1443x_ops;
                break;
        default:
-               pr_err("%s: Unknown pll type for pll clk %s\n",
-                      __func__, name);
+               pr_err("Unknown pll type for pll clk %s\n", name);
                kfree(pll);
                return ERR_PTR(-EINVAL);
        }
@@ -432,8 +534,7 @@ struct clk_hw *imx_dev_clk_hw_pll14xx(struct device *dev, const char *name,
 
        ret = clk_hw_register(dev, hw);
        if (ret) {
-               pr_err("%s: failed to register pll %s %d\n",
-                       __func__, name, ret);
+               pr_err("failed to register pll %s %d\n", name, ret);
                kfree(pll);
                return ERR_PTR(ret);
        }