ipq806x: add mangle bootargs options in config-4.4
[openwrt/staging/dedeckeh.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;