ipq806x: add & enable cpufreq support
[15.05/openwrt.git] / target / linux / ipq806x / patches-3.18 / 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 @@ -1350,7 +1350,8 @@ out:
38  static void clk_calc_subtree(struct clk *clk, unsigned long new_rate,
39                              struct clk *new_parent, u8 p_index)
40  {
41 -       struct clk *child;
42 +       struct clk *child, *parent;
43 +       struct clk_hw *parent_hw;
44  
45         clk->new_rate = new_rate;
46         clk->new_parent = new_parent;
47 @@ -1360,6 +1361,18 @@ static void clk_calc_subtree(struct clk
48         if (new_parent && new_parent != clk->parent)
49                 new_parent->new_child = clk;
50  
51 +       if (clk->ops->get_safe_parent) {
52 +               parent_hw = clk->ops->get_safe_parent(clk->hw);
53 +               if (parent_hw) {
54 +                       parent = parent_hw->clk;
55 +                       p_index = clk_fetch_parent_index(clk, parent);
56 +                       clk->safe_parent_index = p_index;
57 +                       clk->safe_parent = parent;
58 +               }
59 +       } else {
60 +               clk->safe_parent = NULL;
61 +       }
62 +
63         hlist_for_each_entry(child, &clk->children, child_node) {
64                 child->new_rate = clk_recalc(child, new_rate);
65                 clk_calc_subtree(child, child->new_rate, NULL, 0);
66 @@ -1439,17 +1452,47 @@ out:
67   * so that in case of an error we can walk down the whole tree again and
68   * abort the change.
69   */
70 -static struct clk *clk_propagate_rate_change(struct clk *clk, unsigned long event)
71 +static struct clk *clk_propagate_rate_change(struct clk *clk,
72 +                                            unsigned long event)
73  {
74         struct clk *child, *tmp_clk, *fail_clk = NULL;
75 +       struct clk *old_parent;
76         int ret = NOTIFY_DONE;
77  
78 -       if (clk->rate == clk->new_rate)
79 +       if (clk->rate == clk->new_rate && event != POST_RATE_CHANGE)
80                 return NULL;
81  
82 +       switch (event) {
83 +       case PRE_RATE_CHANGE:
84 +               if (clk->safe_parent)
85 +                       clk->ops->set_parent(clk->hw, clk->safe_parent_index);
86 +               clk->old_rate = clk->rate;
87 +               break;
88 +       case POST_RATE_CHANGE:
89 +               if (clk->safe_parent) {
90 +                       old_parent = __clk_set_parent_before(clk,
91 +                                                            clk->new_parent);
92 +                       if (clk->ops->set_rate_and_parent) {
93 +                               clk->ops->set_rate_and_parent(clk->hw,
94 +                                               clk->new_rate,
95 +                                               clk->new_parent ?
96 +                                               clk->new_parent->rate : 0,
97 +                                               clk->new_parent_index);
98 +                       } else if (clk->ops->set_parent) {
99 +                               clk->ops->set_parent(clk->hw,
100 +                                               clk->new_parent_index);
101 +                       }
102 +                       __clk_set_parent_after(clk, clk->new_parent,
103 +                                              old_parent);
104 +               }
105 +               break;
106 +       }
107 +
108         if (clk->notifier_count) {
109 -               ret = __clk_notify(clk, event, clk->rate, clk->new_rate);
110 -               if (ret & NOTIFY_STOP_MASK)
111 +               if (event != POST_RATE_CHANGE || clk->old_rate != clk->rate)
112 +                       ret = __clk_notify(clk, event, clk->old_rate,
113 +                                          clk->new_rate);
114 +               if (ret & NOTIFY_STOP_MASK && event != POST_RATE_CHANGE)
115                         fail_clk = clk;
116         }
117  
118 @@ -1494,7 +1537,8 @@ static void clk_change_rate(struct clk *
119  
120         old_rate = clk->rate;
121  
122 -       if (clk->new_parent && clk->new_parent != clk->parent) {
123 +       if (clk->new_parent && clk->new_parent != clk->parent &&
124 +                       !clk->safe_parent) {
125                 old_parent = __clk_set_parent_before(clk, clk->new_parent);
126  
127                 if (clk->ops->set_rate_and_parent) {
128 @@ -1514,9 +1558,6 @@ static void clk_change_rate(struct clk *
129  
130         clk->rate = clk->new_rate;
131  
132 -       if (clk->notifier_count && old_rate != clk->rate)
133 -               __clk_notify(clk, POST_RATE_CHANGE, old_rate, clk->rate);
134 -
135         /*
136          * Use safe iteration, as change_rate can actually swap parents
137          * for certain clock types.
138 @@ -1601,6 +1642,8 @@ int clk_set_rate(struct clk *clk, unsign
139         /* change the rates */
140         clk_change_rate(top, parent_rate);
141  
142 +       clk_propagate_rate_change(top, POST_RATE_CHANGE);
143 +
144  out:
145         clk_prepare_unlock();
146  
147 --- a/include/linux/clk-provider.h
148 +++ b/include/linux/clk-provider.h
149 @@ -179,6 +179,7 @@ struct clk_ops {
150                                         struct clk **best_parent_clk);
151         int             (*set_parent)(struct clk_hw *hw, u8 index);
152         u8              (*get_parent)(struct clk_hw *hw);
153 +       struct clk_hw   *(*get_safe_parent)(struct clk_hw *hw);
154         int             (*set_rate)(struct clk_hw *hw, unsigned long rate,
155                                     unsigned long parent_rate);
156         int             (*set_rate_and_parent)(struct clk_hw *hw,
157 --- a/include/linux/clk-private.h
158 +++ b/include/linux/clk-private.h
159 @@ -38,8 +38,11 @@ struct clk {
160         struct clk              **parents;
161         u8                      num_parents;
162         u8                      new_parent_index;
163 +       u8                      safe_parent_index;
164         unsigned long           rate;
165 +       unsigned long           old_rate;
166         unsigned long           new_rate;
167 +       struct clk              *safe_parent;
168         struct clk              *new_parent;
169         struct clk              *new_child;
170         unsigned long           flags;