at91: kernel v5.15: remove upstreamed patches
[openwrt/openwrt.git] / target / linux / at91 / patches-5.15 / 244-clk-at91-clk-master-add-notifier-for-divider.patch
diff --git a/target/linux/at91/patches-5.15/244-clk-at91-clk-master-add-notifier-for-divider.patch b/target/linux/at91/patches-5.15/244-clk-at91-clk-master-add-notifier-for-divider.patch
deleted file mode 100644 (file)
index 35262db..0000000
+++ /dev/null
@@ -1,519 +0,0 @@
-From 75d5d1d584ae73ba0c36d1d7255db6153ca4d3f3 Mon Sep 17 00:00:00 2001
-From: Claudiu Beznea <claudiu.beznea@microchip.com>
-Date: Mon, 11 Oct 2021 14:27:16 +0300
-Subject: [PATCH 244/247] clk: at91: clk-master: add notifier for divider
-
-SAMA7G5 supports DVFS by changing cpuck. On SAMA7G5 mck0 shares the same
-parent with cpuck as seen in the following clock tree:
-
-                       +----------> cpuck
-                       |
-FRAC PLL ---> DIV PLL -+-> DIV ---> mck0
-
-mck0 could go b/w 32KHz and 200MHz on SAMA7G5. To avoid mck0 overclocking
-while changing FRAC PLL or DIV PLL the commit implements a notifier for
-mck0 which applies a safe divider to register (maximum value of the divider
-which is 5) on PRE_RATE_CHANGE events (such that changes on PLL to not
-overclock mck0) and sets the maximum allowed rate on POST_RATE_CHANGE
-events.
-
-Signed-off-by: Claudiu Beznea <claudiu.beznea@microchip.com>
-Link: https://lore.kernel.org/r/20211011112719.3951784-13-claudiu.beznea@microchip.com
-Acked-by: Nicolas Ferre <nicolas.ferre@microchip.com>
-Signed-off-by: Stephen Boyd <sboyd@kernel.org>
----
- drivers/clk/at91/at91rm9200.c  |   2 +-
- drivers/clk/at91/at91sam9260.c |   2 +-
- drivers/clk/at91/at91sam9g45.c |   2 +-
- drivers/clk/at91/at91sam9n12.c |   2 +-
- drivers/clk/at91/at91sam9rl.c  |   2 +-
- drivers/clk/at91/at91sam9x5.c  |   2 +-
- drivers/clk/at91/clk-master.c  | 244 +++++++++++++++++++++++----------
- drivers/clk/at91/dt-compat.c   |   2 +-
- drivers/clk/at91/pmc.h         |   2 +-
- drivers/clk/at91/sama5d2.c     |   2 +-
- drivers/clk/at91/sama5d3.c     |   2 +-
- drivers/clk/at91/sama5d4.c     |   2 +-
- drivers/clk/at91/sama7g5.c     |   2 +-
- 13 files changed, 186 insertions(+), 82 deletions(-)
-
---- a/drivers/clk/at91/at91rm9200.c
-+++ b/drivers/clk/at91/at91rm9200.c
-@@ -152,7 +152,7 @@ static void __init at91rm9200_pmc_setup(
-                                         "masterck_pres",
-                                         &at91rm9200_master_layout,
-                                         &rm9200_mck_characteristics,
--                                        &rm9200_mck_lock, CLK_SET_RATE_GATE);
-+                                        &rm9200_mck_lock, CLK_SET_RATE_GATE, 0);
-       if (IS_ERR(hw))
-               goto err_free;
---- a/drivers/clk/at91/at91sam9260.c
-+++ b/drivers/clk/at91/at91sam9260.c
-@@ -429,7 +429,7 @@ static void __init at91sam926x_pmc_setup
-                                         &at91rm9200_master_layout,
-                                         data->mck_characteristics,
-                                         &at91sam9260_mck_lock,
--                                        CLK_SET_RATE_GATE);
-+                                        CLK_SET_RATE_GATE, 0);
-       if (IS_ERR(hw))
-               goto err_free;
---- a/drivers/clk/at91/at91sam9g45.c
-+++ b/drivers/clk/at91/at91sam9g45.c
-@@ -164,7 +164,7 @@ static void __init at91sam9g45_pmc_setup
-                                         &at91rm9200_master_layout,
-                                         &mck_characteristics,
-                                         &at91sam9g45_mck_lock,
--                                        CLK_SET_RATE_GATE);
-+                                        CLK_SET_RATE_GATE, 0);
-       if (IS_ERR(hw))
-               goto err_free;
---- a/drivers/clk/at91/at91sam9n12.c
-+++ b/drivers/clk/at91/at91sam9n12.c
-@@ -191,7 +191,7 @@ static void __init at91sam9n12_pmc_setup
-                                         &at91sam9x5_master_layout,
-                                         &mck_characteristics,
-                                         &at91sam9n12_mck_lock,
--                                        CLK_SET_RATE_GATE);
-+                                        CLK_SET_RATE_GATE, 0);
-       if (IS_ERR(hw))
-               goto err_free;
---- a/drivers/clk/at91/at91sam9rl.c
-+++ b/drivers/clk/at91/at91sam9rl.c
-@@ -132,7 +132,7 @@ static void __init at91sam9rl_pmc_setup(
-                                         "masterck_pres",
-                                         &at91rm9200_master_layout,
-                                         &sam9rl_mck_characteristics,
--                                        &sam9rl_mck_lock, CLK_SET_RATE_GATE);
-+                                        &sam9rl_mck_lock, CLK_SET_RATE_GATE, 0);
-       if (IS_ERR(hw))
-               goto err_free;
---- a/drivers/clk/at91/at91sam9x5.c
-+++ b/drivers/clk/at91/at91sam9x5.c
-@@ -210,7 +210,7 @@ static void __init at91sam9x5_pmc_setup(
-                                         "masterck_pres",
-                                         &at91sam9x5_master_layout,
-                                         &mck_characteristics, &mck_lock,
--                                        CLK_SET_RATE_GATE);
-+                                        CLK_SET_RATE_GATE, 0);
-       if (IS_ERR(hw))
-               goto err_free;
---- a/drivers/clk/at91/clk-master.c
-+++ b/drivers/clk/at91/clk-master.c
-@@ -5,6 +5,7 @@
- #include <linux/clk-provider.h>
- #include <linux/clkdev.h>
-+#include <linux/clk.h>
- #include <linux/clk/at91_pmc.h>
- #include <linux/of.h>
- #include <linux/mfd/syscon.h>
-@@ -36,8 +37,12 @@ struct clk_master {
-       u8 id;
-       u8 parent;
-       u8 div;
-+      u32 safe_div;
- };
-+/* MCK div reference to be used by notifier. */
-+static struct clk_master *master_div;
-+
- static inline bool clk_master_ready(struct clk_master *master)
- {
-       unsigned int bit = master->id ? AT91_PMC_MCKXRDY : AT91_PMC_MCKRDY;
-@@ -153,107 +158,81 @@ static const struct clk_ops master_div_o
-       .restore_context = clk_master_div_restore_context,
- };
--static int clk_master_div_set_rate(struct clk_hw *hw, unsigned long rate,
--                                 unsigned long parent_rate)
-+/* This function must be called with lock acquired. */
-+static int clk_master_div_set(struct clk_master *master,
-+                            unsigned long parent_rate, int div)
- {
--      struct clk_master *master = to_clk_master(hw);
-       const struct clk_master_characteristics *characteristics =
-                                               master->characteristics;
--      unsigned long flags;
--      unsigned int mckr, tmp;
--      int div, i;
-+      unsigned long rate = parent_rate;
-+      unsigned int max_div = 0, div_index = 0, max_div_index = 0;
-+      unsigned int i, mckr, tmp;
-       int ret;
--      div = DIV_ROUND_CLOSEST(parent_rate, rate);
--      if (div > ARRAY_SIZE(characteristics->divisors))
--              return -EINVAL;
--
-       for (i = 0; i < ARRAY_SIZE(characteristics->divisors); i++) {
-               if (!characteristics->divisors[i])
-                       break;
--              if (div == characteristics->divisors[i]) {
--                      div = i;
--                      break;
-+              if (div == characteristics->divisors[i])
-+                      div_index = i;
-+
-+              if (max_div < characteristics->divisors[i]) {
-+                      max_div = characteristics->divisors[i];
-+                      max_div_index = i;
-               }
-       }
--      if (i == ARRAY_SIZE(characteristics->divisors))
--              return -EINVAL;
-+      if (div > max_div)
-+              div_index = max_div_index;
--      spin_lock_irqsave(master->lock, flags);
-       ret = regmap_read(master->regmap, master->layout->offset, &mckr);
-       if (ret)
--              goto unlock;
-+              return ret;
-       mckr &= master->layout->mask;
-       tmp = (mckr >> MASTER_DIV_SHIFT) & MASTER_DIV_MASK;
--      if (tmp == div)
--              goto unlock;
-+      if (tmp == div_index)
-+              return 0;
-+
-+      rate /= characteristics->divisors[div_index];
-+      if (rate < characteristics->output.min)
-+              pr_warn("master clk div is underclocked");
-+      else if (rate > characteristics->output.max)
-+              pr_warn("master clk div is overclocked");
-       mckr &= ~(MASTER_DIV_MASK << MASTER_DIV_SHIFT);
--      mckr |= (div << MASTER_DIV_SHIFT);
-+      mckr |= (div_index << MASTER_DIV_SHIFT);
-       ret = regmap_write(master->regmap, master->layout->offset, mckr);
-       if (ret)
--              goto unlock;
-+              return ret;
-       while (!clk_master_ready(master))
-               cpu_relax();
--unlock:
--      spin_unlock_irqrestore(master->lock, flags);
-+
-+      master->div = characteristics->divisors[div_index];
-       return 0;
- }
--static int clk_master_div_determine_rate(struct clk_hw *hw,
--                                       struct clk_rate_request *req)
-+static unsigned long clk_master_div_recalc_rate_chg(struct clk_hw *hw,
-+                                                  unsigned long parent_rate)
- {
-       struct clk_master *master = to_clk_master(hw);
--      const struct clk_master_characteristics *characteristics =
--                                              master->characteristics;
--      struct clk_hw *parent;
--      unsigned long parent_rate, tmp_rate, best_rate = 0;
--      int i, best_diff = INT_MIN, tmp_diff;
--
--      parent = clk_hw_get_parent(hw);
--      if (!parent)
--              return -EINVAL;
--
--      parent_rate = clk_hw_get_rate(parent);
--      if (!parent_rate)
--              return -EINVAL;
--      for (i = 0; i < ARRAY_SIZE(characteristics->divisors); i++) {
--              if (!characteristics->divisors[i])
--                      break;
--
--              tmp_rate = DIV_ROUND_CLOSEST_ULL(parent_rate,
--                                               characteristics->divisors[i]);
--              tmp_diff = abs(tmp_rate - req->rate);
--
--              if (!best_rate || best_diff > tmp_diff) {
--                      best_diff = tmp_diff;
--                      best_rate = tmp_rate;
--              }
--
--              if (!best_diff)
--                      break;
--      }
--
--      req->best_parent_rate = best_rate;
--      req->best_parent_hw = parent;
--      req->rate = best_rate;
--
--      return 0;
-+      return DIV_ROUND_CLOSEST_ULL(parent_rate, master->div);
- }
- static void clk_master_div_restore_context_chg(struct clk_hw *hw)
- {
-       struct clk_master *master = to_clk_master(hw);
-+      unsigned long flags;
-       int ret;
--      ret = clk_master_div_set_rate(hw, master->pms.rate,
--                                    master->pms.parent_rate);
-+      spin_lock_irqsave(master->lock, flags);
-+      ret = clk_master_div_set(master, master->pms.parent_rate,
-+                               DIV_ROUND_CLOSEST(master->pms.parent_rate,
-+                                                 master->pms.rate));
-+      spin_unlock_irqrestore(master->lock, flags);
-       if (ret)
-               pr_warn("Failed to restore MCK DIV clock\n");
- }
-@@ -261,13 +240,116 @@ static void clk_master_div_restore_conte
- static const struct clk_ops master_div_ops_chg = {
-       .prepare = clk_master_prepare,
-       .is_prepared = clk_master_is_prepared,
--      .recalc_rate = clk_master_div_recalc_rate,
--      .determine_rate = clk_master_div_determine_rate,
--      .set_rate = clk_master_div_set_rate,
-+      .recalc_rate = clk_master_div_recalc_rate_chg,
-       .save_context = clk_master_div_save_context,
-       .restore_context = clk_master_div_restore_context_chg,
- };
-+static int clk_master_div_notifier_fn(struct notifier_block *notifier,
-+                                    unsigned long code, void *data)
-+{
-+      const struct clk_master_characteristics *characteristics =
-+                                              master_div->characteristics;
-+      struct clk_notifier_data *cnd = data;
-+      unsigned long flags, new_parent_rate, new_rate;
-+      unsigned int mckr, div, new_div = 0;
-+      int ret, i;
-+      long tmp_diff;
-+      long best_diff = -1;
-+
-+      spin_lock_irqsave(master_div->lock, flags);
-+      switch (code) {
-+      case PRE_RATE_CHANGE:
-+              /*
-+               * We want to avoid any overclocking of MCK DIV domain. To do
-+               * this we set a safe divider (the underclocking is not of
-+               * interest as we can go as low as 32KHz). The relation
-+               * b/w this clock and its parents are as follows:
-+               *
-+               * FRAC PLL -> DIV PLL -> MCK DIV
-+               *
-+               * With the proper safe divider we should be good even with FRAC
-+               * PLL at its maximum value.
-+               */
-+              ret = regmap_read(master_div->regmap, master_div->layout->offset,
-+                                &mckr);
-+              if (ret) {
-+                      ret = NOTIFY_STOP_MASK;
-+                      goto unlock;
-+              }
-+
-+              mckr &= master_div->layout->mask;
-+              div = (mckr >> MASTER_DIV_SHIFT) & MASTER_DIV_MASK;
-+
-+              /* Switch to safe divider. */
-+              clk_master_div_set(master_div,
-+                                 cnd->old_rate * characteristics->divisors[div],
-+                                 master_div->safe_div);
-+              break;
-+
-+      case POST_RATE_CHANGE:
-+              /*
-+               * At this point we want to restore MCK DIV domain to its maximum
-+               * allowed rate.
-+               */
-+              ret = regmap_read(master_div->regmap, master_div->layout->offset,
-+                                &mckr);
-+              if (ret) {
-+                      ret = NOTIFY_STOP_MASK;
-+                      goto unlock;
-+              }
-+
-+              mckr &= master_div->layout->mask;
-+              div = (mckr >> MASTER_DIV_SHIFT) & MASTER_DIV_MASK;
-+              new_parent_rate = cnd->new_rate * characteristics->divisors[div];
-+
-+              for (i = 0; i < ARRAY_SIZE(characteristics->divisors); i++) {
-+                      if (!characteristics->divisors[i])
-+                              break;
-+
-+                      new_rate = DIV_ROUND_CLOSEST_ULL(new_parent_rate,
-+                                                       characteristics->divisors[i]);
-+
-+                      tmp_diff = characteristics->output.max - new_rate;
-+                      if (tmp_diff < 0)
-+                              continue;
-+
-+                      if (best_diff < 0 || best_diff > tmp_diff) {
-+                              new_div = characteristics->divisors[i];
-+                              best_diff = tmp_diff;
-+                      }
-+
-+                      if (!tmp_diff)
-+                              break;
-+              }
-+
-+              if (!new_div) {
-+                      ret = NOTIFY_STOP_MASK;
-+                      goto unlock;
-+              }
-+
-+              /* Update the div to preserve MCK DIV clock rate. */
-+              clk_master_div_set(master_div, new_parent_rate,
-+                                 new_div);
-+
-+              ret = NOTIFY_OK;
-+              break;
-+
-+      default:
-+              ret = NOTIFY_DONE;
-+              break;
-+      }
-+
-+unlock:
-+      spin_unlock_irqrestore(master_div->lock, flags);
-+
-+      return ret;
-+}
-+
-+static struct notifier_block clk_master_div_notifier = {
-+      .notifier_call = clk_master_div_notifier_fn,
-+};
-+
- static void clk_sama7g5_master_best_diff(struct clk_rate_request *req,
-                                        struct clk_hw *parent,
-                                        unsigned long parent_rate,
-@@ -496,6 +578,8 @@ at91_clk_register_master_internal(struct
-       struct clk_master *master;
-       struct clk_init_data init;
-       struct clk_hw *hw;
-+      unsigned int mckr;
-+      unsigned long irqflags;
-       int ret;
-       if (!name || !num_parents || !parent_names || !lock)
-@@ -518,6 +602,16 @@ at91_clk_register_master_internal(struct
-       master->chg_pid = chg_pid;
-       master->lock = lock;
-+      if (ops == &master_div_ops_chg) {
-+              spin_lock_irqsave(master->lock, irqflags);
-+              regmap_read(master->regmap, master->layout->offset, &mckr);
-+              spin_unlock_irqrestore(master->lock, irqflags);
-+
-+              mckr &= layout->mask;
-+              mckr = (mckr >> MASTER_DIV_SHIFT) & MASTER_DIV_MASK;
-+              master->div = characteristics->divisors[mckr];
-+      }
-+
-       hw = &master->hw;
-       ret = clk_hw_register(NULL, &master->hw);
-       if (ret) {
-@@ -554,19 +648,29 @@ at91_clk_register_master_div(struct regm
-               const char *name, const char *parent_name,
-               const struct clk_master_layout *layout,
-               const struct clk_master_characteristics *characteristics,
--              spinlock_t *lock, u32 flags)
-+              spinlock_t *lock, u32 flags, u32 safe_div)
- {
-       const struct clk_ops *ops;
-+      struct clk_hw *hw;
-       if (flags & CLK_SET_RATE_GATE)
-               ops = &master_div_ops;
-       else
-               ops = &master_div_ops_chg;
--      return at91_clk_register_master_internal(regmap, name, 1,
--                                               &parent_name, layout,
--                                               characteristics, ops,
--                                               lock, flags, -EINVAL);
-+      hw = at91_clk_register_master_internal(regmap, name, 1,
-+                                             &parent_name, layout,
-+                                             characteristics, ops,
-+                                             lock, flags, -EINVAL);
-+
-+      if (!IS_ERR(hw) && safe_div) {
-+              master_div = to_clk_master(hw);
-+              master_div->safe_div = safe_div;
-+              clk_notifier_register(hw->clk,
-+                                    &clk_master_div_notifier);
-+      }
-+
-+      return hw;
- }
- static unsigned long
---- a/drivers/clk/at91/dt-compat.c
-+++ b/drivers/clk/at91/dt-compat.c
-@@ -399,7 +399,7 @@ of_at91_clk_master_setup(struct device_n
-       hw = at91_clk_register_master_div(regmap, name, "masterck_pres",
-                                         layout, characteristics,
--                                        &mck_lock, CLK_SET_RATE_GATE);
-+                                        &mck_lock, CLK_SET_RATE_GATE, 0);
-       if (IS_ERR(hw))
-               goto out_free_characteristics;
---- a/drivers/clk/at91/pmc.h
-+++ b/drivers/clk/at91/pmc.h
-@@ -182,7 +182,7 @@ at91_clk_register_master_div(struct regm
-                            const char *parent_names,
-                            const struct clk_master_layout *layout,
-                            const struct clk_master_characteristics *characteristics,
--                           spinlock_t *lock, u32 flags);
-+                           spinlock_t *lock, u32 flags, u32 safe_div);
- struct clk_hw * __init
- at91_clk_sama7g5_register_master(struct regmap *regmap,
---- a/drivers/clk/at91/sama5d2.c
-+++ b/drivers/clk/at91/sama5d2.c
-@@ -249,7 +249,7 @@ static void __init sama5d2_pmc_setup(str
-                                         "masterck_pres",
-                                         &at91sam9x5_master_layout,
-                                         &mck_characteristics, &mck_lock,
--                                        CLK_SET_RATE_GATE);
-+                                        CLK_SET_RATE_GATE, 0);
-       if (IS_ERR(hw))
-               goto err_free;
---- a/drivers/clk/at91/sama5d3.c
-+++ b/drivers/clk/at91/sama5d3.c
-@@ -184,7 +184,7 @@ static void __init sama5d3_pmc_setup(str
-                                         "masterck_pres",
-                                         &at91sam9x5_master_layout,
-                                         &mck_characteristics, &mck_lock,
--                                        CLK_SET_RATE_GATE);
-+                                        CLK_SET_RATE_GATE, 0);
-       if (IS_ERR(hw))
-               goto err_free;
---- a/drivers/clk/at91/sama5d4.c
-+++ b/drivers/clk/at91/sama5d4.c
-@@ -199,7 +199,7 @@ static void __init sama5d4_pmc_setup(str
-                                         "masterck_pres",
-                                         &at91sam9x5_master_layout,
-                                         &mck_characteristics, &mck_lock,
--                                        CLK_SET_RATE_GATE);
-+                                        CLK_SET_RATE_GATE, 0);
-       if (IS_ERR(hw))
-               goto err_free;
---- a/drivers/clk/at91/sama7g5.c
-+++ b/drivers/clk/at91/sama7g5.c
-@@ -1003,7 +1003,7 @@ static void __init sama7g5_pmc_setup(str
-       hw = at91_clk_register_master_div(regmap, "mck0", "cpuck",
-                                         &mck0_layout, &mck0_characteristics,
--                                        &pmc_mck0_lock, 0);
-+                                        &pmc_mck0_lock, CLK_GET_RATE_NOCACHE, 5);
-       if (IS_ERR(hw))
-               goto err_free;