1 Content-Type: text/plain; charset="utf-8"
3 Content-Transfer-Encoding: 7bit
4 Subject: [v3, 03/13] clk: Avoid sending high rates to downstream clocks during
6 From: Stephen Boyd <sboyd@codeaurora.org>
7 X-Patchwork-Id: 6063271
8 Message-Id: <1426920332-9340-4-git-send-email-sboyd@codeaurora.org>
9 To: Mike Turquette <mturquette@linaro.org>, Stephen Boyd <sboyd@codeaurora.org>
10 Cc: linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org,
11 linux-pm@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
12 Viresh Kumar <viresh.kumar@linaro.org>
13 Date: Fri, 20 Mar 2015 23:45:22 -0700
15 If a clock is on and we call clk_set_rate() on it we may get into
16 a situation where the clock temporarily increases in rate
17 dramatically while we walk the tree and call .set_rate() ops. For
18 example, consider a case where a PLL feeds into a divider.
19 Initially the divider is set to divide by 1 and the PLL is
20 running fairly slow (100MHz). The downstream consumer of the
21 divider output can only handle rates =< 400 MHz, but the divider
22 can only choose between divisors of 1 and 4.
24 +-----+ +----------------+
25 | PLL |-->| div 1 or div 4 |---> consumer device
26 +-----+ +----------------+
28 To achieve a rate of 400MHz on the output of the divider, we
29 would have to set the rate of the PLL to 1.6 GHz and then divide
30 it by 4. The current code would set the PLL to 1.6GHz first while
31 the divider is still set to 1, thus causing the downstream
32 consumer of the clock to receive a few clock cycles of 1.6GHz
33 clock (far beyond it's maximum acceptable rate). We should be
34 changing the divider first before increasing the PLL rate to
37 Therefore, set the rate of any child clocks that are increasing
38 in rate from their current rate so that they can increase their
39 dividers if necessary. We assume that there isn't such a thing as
40 minimum rate requirements.
42 Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
45 drivers/clk/clk.c | 34 ++++++++++++++++++++++------------
46 1 file changed, 22 insertions(+), 12 deletions(-)
48 --- a/drivers/clk/clk.c
49 +++ b/drivers/clk/clk.c
50 @@ -1476,21 +1476,23 @@ static struct clk *clk_propagate_rate_ch
51 * walk down a subtree and set the new rates notifying the rate
54 -static void clk_change_rate(struct clk *clk)
55 +static void clk_change_rate(struct clk *clk, unsigned long best_parent_rate)
58 struct hlist_node *tmp;
59 unsigned long old_rate;
60 - unsigned long best_parent_rate = 0;
61 bool skip_set_rate = false;
62 struct clk *old_parent;
64 - old_rate = clk->rate;
65 + hlist_for_each_entry(child, &clk->children, child_node) {
66 + /* Skip children who will be reparented to another clock */
67 + if (child->new_parent && child->new_parent != clk)
69 + if (child->new_rate > child->rate)
70 + clk_change_rate(child, clk->new_rate);
73 - if (clk->new_parent)
74 - best_parent_rate = clk->new_parent->rate;
75 - else if (clk->parent)
76 - best_parent_rate = clk->parent->rate;
77 + old_rate = clk->rate;
79 if (clk->new_parent && clk->new_parent != clk->parent) {
80 old_parent = __clk_set_parent_before(clk, clk->new_parent);
81 @@ -1510,7 +1512,7 @@ static void clk_change_rate(struct clk *
82 if (!skip_set_rate && clk->ops->set_rate)
83 clk->ops->set_rate(clk->hw, clk->new_rate, best_parent_rate);
85 - clk->rate = clk_recalc(clk, best_parent_rate);
86 + clk->rate = clk->new_rate;
88 if (clk->notifier_count && old_rate != clk->rate)
89 __clk_notify(clk, POST_RATE_CHANGE, old_rate, clk->rate);
90 @@ -1523,12 +1525,13 @@ static void clk_change_rate(struct clk *
91 /* Skip children who will be reparented to another clock */
92 if (child->new_parent && child->new_parent != clk)
94 - clk_change_rate(child);
95 + if (child->new_rate != child->rate)
96 + clk_change_rate(child, clk->new_rate);
99 /* handle the new child who might not be in clk->children yet */
100 - if (clk->new_child)
101 - clk_change_rate(clk->new_child);
102 + if (clk->new_child && clk->new_child->new_rate != clk->new_child->rate)
103 + clk_change_rate(clk->new_child, clk->new_rate);
107 @@ -1556,6 +1559,7 @@ int clk_set_rate(struct clk *clk, unsign
109 struct clk *top, *fail_clk;
111 + unsigned long parent_rate;
115 @@ -1589,8 +1593,13 @@ int clk_set_rate(struct clk *clk, unsign
120 + parent_rate = top->parent->rate;
124 /* change the rates */
125 - clk_change_rate(top);
126 + clk_change_rate(top, parent_rate);
129 clk_prepare_unlock();