kernel: update 3.14 to 3.14.18
[openwrt.git] / target / linux / ipq806x / patches / 0126-clk-Add-safe-switch-hook.patch
1 From b7b3ceec506179d59e46e3a8ea8b370872cc7fcb Mon Sep 17 00:00:00 2001
2 From: Stephen Boyd <sboyd@codeaurora.org>
3 Date: Mon, 31 Mar 2014 16:52:29 -0700
4 Subject: [PATCH 126/182] clk: Add safe switch hook
5
6 Sometimes clocks can't accept their parent source turning off
7 while the source is reprogrammed to a different rate. Most
8 notably CPU clocks require a way to switch away from the current
9 PLL they're running on, reprogram that PLL to a new rate, and
10 then switch back to the PLL with the new rate once they're done.
11 Add a hook that drivers can implement allowing them to return a
12 'safe parent' that they can switch their parent to while the
13 upstream source is reprogrammed to support this.
14
15 Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
16 ---
17  drivers/clk/clk.c            |   53 ++++++++++++++++++++++++++++++++++++------
18  include/linux/clk-private.h  |    2 ++
19  include/linux/clk-provider.h |    1 +
20  3 files changed, 49 insertions(+), 7 deletions(-)
21
22 --- a/drivers/clk/clk.c
23 +++ b/drivers/clk/clk.c
24 @@ -1356,6 +1356,7 @@ static void clk_calc_subtree(struct clk
25                              struct clk *new_parent, u8 p_index)
26  {
27         struct clk *child;
28 +       struct clk *parent;
29  
30         clk->new_rate = new_rate;
31         clk->new_parent = new_parent;
32 @@ -1365,6 +1366,17 @@ static void clk_calc_subtree(struct clk
33         if (new_parent && new_parent != clk->parent)
34                 new_parent->new_child = clk;
35  
36 +       if (clk->ops->get_safe_parent) {
37 +               parent = clk->ops->get_safe_parent(clk->hw);
38 +               if (parent) {
39 +                       p_index = clk_fetch_parent_index(clk, parent);
40 +                       clk->safe_parent_index = p_index;
41 +                       clk->safe_parent = parent;
42 +               }
43 +       } else {
44 +               clk->safe_parent = NULL;
45 +       }
46 +
47         hlist_for_each_entry(child, &clk->children, child_node) {
48                 if (child->ops->recalc_rate)
49                         child->new_rate = child->ops->recalc_rate(child->hw, new_rate);
50 @@ -1450,14 +1462,42 @@ out:
51  static struct clk *clk_propagate_rate_change(struct clk *clk, unsigned long event)
52  {
53         struct clk *child, *tmp_clk, *fail_clk = NULL;
54 +       struct clk *old_parent;
55         int ret = NOTIFY_DONE;
56  
57 -       if (clk->rate == clk->new_rate)
58 +       if (clk->rate == clk->new_rate && event != POST_RATE_CHANGE)
59                 return NULL;
60  
61 +       switch (event) {
62 +       case PRE_RATE_CHANGE:
63 +               if (clk->safe_parent)
64 +                       clk->ops->set_parent(clk->hw, clk->safe_parent_index);
65 +               break;
66 +       case POST_RATE_CHANGE:
67 +               if (clk->safe_parent) {
68 +                       old_parent = __clk_set_parent_before(clk,
69 +                                                            clk->new_parent);
70 +                       if (clk->ops->set_rate_and_parent) {
71 +                               clk->ops->set_rate_and_parent(clk->hw,
72 +                                               clk->new_rate,
73 +                                               clk->new_parent ?
74 +                                               clk->new_parent->rate : 0,
75 +                                               clk->new_parent_index);
76 +                       } else if (clk->ops->set_parent) {
77 +                               clk->ops->set_parent(clk->hw,
78 +                                               clk->new_parent_index);
79 +                       }
80 +                       __clk_set_parent_after(clk, clk->new_parent,
81 +                                              old_parent);
82 +               }
83 +               break;
84 +       }
85 +
86         if (clk->notifier_count) {
87 -               ret = __clk_notify(clk, event, clk->rate, clk->new_rate);
88 -               if (ret & NOTIFY_STOP_MASK)
89 +               if (event != POST_RATE_CHANGE)
90 +                       ret = __clk_notify(clk, event, clk->rate,
91 +                                          clk->new_rate);
92 +               if (ret & NOTIFY_STOP_MASK && event != POST_RATE_CHANGE)
93                         fail_clk = clk;
94         }
95  
96 @@ -1499,7 +1539,8 @@ static void clk_change_rate(struct clk *
97         else if (clk->parent)
98                 best_parent_rate = clk->parent->rate;
99  
100 -       if (clk->new_parent && clk->new_parent != clk->parent) {
101 +       if (clk->new_parent && clk->new_parent != clk->parent &&
102 +                       !clk->safe_parent) {
103                 old_parent = __clk_set_parent_before(clk, clk->new_parent);
104  
105                 if (clk->ops->set_rate_and_parent) {
106 @@ -1522,9 +1563,6 @@ static void clk_change_rate(struct clk *
107         else
108                 clk->rate = best_parent_rate;
109  
110 -       if (clk->notifier_count && old_rate != clk->rate)
111 -               __clk_notify(clk, POST_RATE_CHANGE, old_rate, clk->rate);
112 -
113         hlist_for_each_entry(child, &clk->children, child_node) {
114                 /* Skip children who will be reparented to another clock */
115                 if (child->new_parent && child->new_parent != clk)
116 @@ -1598,6 +1636,7 @@ int clk_set_rate(struct clk *clk, unsign
117         /* change the rates */
118         clk_change_rate(top);
119  
120 +       clk_propagate_rate_change(top, POST_RATE_CHANGE);
121  out:
122         clk_prepare_unlock();
123  
124 --- a/include/linux/clk-private.h
125 +++ b/include/linux/clk-private.h
126 @@ -38,8 +38,10 @@ struct clk {
127         struct clk              **parents;
128         u8                      num_parents;
129         u8                      new_parent_index;
130 +       u8                      safe_parent_index;
131         unsigned long           rate;
132         unsigned long           new_rate;
133 +       struct clk              *safe_parent;
134         struct clk              *new_parent;
135         struct clk              *new_child;
136         unsigned long           flags;
137 --- a/include/linux/clk-provider.h
138 +++ b/include/linux/clk-provider.h
139 @@ -157,6 +157,7 @@ struct clk_ops {
140                                         struct clk **best_parent_clk);
141         int             (*set_parent)(struct clk_hw *hw, u8 index);
142         u8              (*get_parent)(struct clk_hw *hw);
143 +       struct clk      *(*get_safe_parent)(struct clk_hw *hw);
144         int             (*set_rate)(struct clk_hw *hw, unsigned long,
145                                     unsigned long);
146         int             (*set_rate_and_parent)(struct clk_hw *hw,