ar71xx: remove linux 3.18 support
[openwrt.git] / target / linux / ipq806x / patches-4.0 / 136-clk-Add-safe-switch-hook.patch
1 Content-Type: text/plain; charset="utf-8"
2 MIME-Version: 1.0
3 Content-Transfer-Encoding: 7bit
4 Subject: [v3,04/13] clk: Add safe switch hook
5 From: Stephen Boyd <sboyd@codeaurora.org>
6 X-Patchwork-Id: 6063211
7 Message-Id: <1426920332-9340-5-git-send-email-sboyd@codeaurora.org>
8 To: Mike Turquette <mturquette@linaro.org>, Stephen Boyd <sboyd@codeaurora.org>
9 Cc: linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org,
10         linux-pm@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
11         Viresh Kumar <viresh.kumar@linaro.org>
12 Date: Fri, 20 Mar 2015 23:45:23 -0700
13
14 Sometimes clocks can't accept their parent source turning off
15 while the source is reprogrammed to a different rate. Most
16 notably CPU clocks require a way to switch away from the current
17 PLL they're running on, reprogram that PLL to a new rate, and
18 then switch back to the PLL with the new rate once they're done.
19 Add a hook that drivers can implement allowing them to return a
20 'safe parent' that they can switch their parent to while the
21 upstream source is reprogrammed to support this.
22
23 Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
24
25 ---
26 This patch is good enough for Krait, but soon I'll need to 
27 support a "safe rate" where we ask a clock what rate it needs to be running
28 at to be sure it's within voltage constraints. Right now safe parent
29 handles that problem on Krait, but on other platforms it won't work.
30
31  drivers/clk/clk.c            | 61 ++++++++++++++++++++++++++++++++++++++------
32  include/linux/clk-provider.h |  1 +
33  2 files changed, 54 insertions(+), 8 deletions(-)
34
35 --- a/drivers/clk/clk.c
36 +++ b/drivers/clk/clk.c
37 @@ -56,9 +56,12 @@ struct clk_core {
38         struct clk_core         **parents;
39         u8                      num_parents;
40         u8                      new_parent_index;
41 +       u8                      safe_parent_index;
42         unsigned long           rate;
43         unsigned long           req_rate;
44 +       unsigned long           old_rate;
45         unsigned long           new_rate;
46 +       struct clk_core         *safe_parent;
47         struct clk_core         *new_parent;
48         struct clk_core         *new_child;
49         unsigned long           flags;
50 @@ -1557,7 +1560,8 @@ out:
51  static void clk_calc_subtree(struct clk_core *clk, unsigned long new_rate,
52                              struct clk_core *new_parent, u8 p_index)
53  {
54 -       struct clk_core *child;
55 +       struct clk_core *child, *parent;
56 +       struct clk_hw *parent_hw;
57  
58         clk->new_rate = new_rate;
59         clk->new_parent = new_parent;
60 @@ -1567,6 +1571,18 @@ static void clk_calc_subtree(struct clk_
61         if (new_parent && new_parent != clk->parent)
62                 new_parent->new_child = clk;
63  
64 +       if (clk->ops->get_safe_parent) {
65 +               parent_hw = clk->ops->get_safe_parent(clk->hw);
66 +               if (parent_hw) {
67 +                       parent = parent_hw->core;
68 +                       p_index = clk_fetch_parent_index(clk, parent);
69 +                       clk->safe_parent_index = p_index;
70 +                       clk->safe_parent = parent;
71 +               }
72 +       } else {
73 +               clk->safe_parent = NULL;
74 +       }
75 +
76         hlist_for_each_entry(child, &clk->children, child_node) {
77                 child->new_rate = clk_recalc(child, new_rate);
78                 clk_calc_subtree(child, child->new_rate, NULL, 0);
79 @@ -1662,14 +1678,43 @@ static struct clk_core *clk_propagate_ra
80                                                   unsigned long event)
81  {
82         struct clk_core *child, *tmp_clk, *fail_clk = NULL;
83 +       struct clk_core *old_parent;
84         int ret = NOTIFY_DONE;
85  
86 -       if (clk->rate == clk->new_rate)
87 +       if (clk->rate == clk->new_rate && event != POST_RATE_CHANGE)
88                 return NULL;
89  
90 +       switch (event) {
91 +       case PRE_RATE_CHANGE:
92 +               if (clk->safe_parent)
93 +                       clk->ops->set_parent(clk->hw, clk->safe_parent_index);
94 +               clk->old_rate = clk->rate;
95 +               break;
96 +       case POST_RATE_CHANGE:
97 +               if (clk->safe_parent) {
98 +                       old_parent = __clk_set_parent_before(clk,
99 +                                                            clk->new_parent);
100 +                       if (clk->ops->set_rate_and_parent) {
101 +                               clk->ops->set_rate_and_parent(clk->hw,
102 +                                               clk->new_rate,
103 +                                               clk->new_parent ?
104 +                                               clk->new_parent->rate : 0,
105 +                                               clk->new_parent_index);
106 +                       } else if (clk->ops->set_parent) {
107 +                               clk->ops->set_parent(clk->hw,
108 +                                               clk->new_parent_index);
109 +                       }
110 +                       __clk_set_parent_after(clk, clk->new_parent,
111 +                                              old_parent);
112 +               }
113 +               break;
114 +       }
115 +
116         if (clk->notifier_count) {
117 -               ret = __clk_notify(clk, event, clk->rate, clk->new_rate);
118 -               if (ret & NOTIFY_STOP_MASK)
119 +               if (event != POST_RATE_CHANGE || clk->old_rate != clk->rate)
120 +                       ret = __clk_notify(clk, event, clk->old_rate,
121 +                                          clk->new_rate);
122 +               if (ret & NOTIFY_STOP_MASK && event != POST_RATE_CHANGE)
123                         fail_clk = clk;
124         }
125  
126 @@ -1715,7 +1760,8 @@ clk_change_rate(struct clk_core *clk, un
127  
128         old_rate = clk->rate;
129  
130 -       if (clk->new_parent && clk->new_parent != clk->parent) {
131 +       if (clk->new_parent && clk->new_parent != clk->parent &&
132 +                       !clk->safe_parent) {
133                 old_parent = __clk_set_parent_before(clk, clk->new_parent);
134  
135                 if (clk->ops->set_rate_and_parent) {
136 @@ -1735,9 +1781,6 @@ clk_change_rate(struct clk_core *clk, un
137  
138         clk->rate = clk->new_rate;
139  
140 -       if (clk->notifier_count && old_rate != clk->rate)
141 -               __clk_notify(clk, POST_RATE_CHANGE, old_rate, clk->rate);
142 -
143         /*
144          * Use safe iteration, as change_rate can actually swap parents
145          * for certain clock types.
146 @@ -1797,6 +1840,8 @@ static int clk_core_set_rate_nolock(stru
147  
148         clk->req_rate = req_rate;
149  
150 +       clk_propagate_rate_change(top, POST_RATE_CHANGE);
151 +
152         return ret;
153  }
154  
155 --- a/include/linux/clk-provider.h
156 +++ b/include/linux/clk-provider.h
157 @@ -183,6 +183,7 @@ struct clk_ops {
158                                           struct clk_hw **best_parent_hw);
159         int             (*set_parent)(struct clk_hw *hw, u8 index);
160         u8              (*get_parent)(struct clk_hw *hw);
161 +       struct clk_hw   *(*get_safe_parent)(struct clk_hw *hw);
162         int             (*set_rate)(struct clk_hw *hw, unsigned long rate,
163                                     unsigned long parent_rate);
164         int             (*set_rate_and_parent)(struct clk_hw *hw,