ipq806x: enable QCE hardware crypto inside the kernel
[oweals/openwrt.git] / target / linux / ipq806x / patches-4.9 / 0037-clk-Add-safe-switch-hook.patch
1 From a1adfb782789ae9b25c928dfe3d639288563a86c Mon Sep 17 00:00:00 2001
2 From: Stephen Boyd <sboyd@codeaurora.org>
3 Date: Fri, 20 Mar 2015 23:45:23 -0700
4 Subject: [PATCH 37/69] 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' and 'safe frequency' that they can switch their
13 parent to while the upstream source is reprogrammed to support
14 this.
15
16 Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
17 Signed-off-by: Georgi Djakov <georgi.djakov@linaro.org>
18 ---
19  drivers/clk/clk.c            | 73 +++++++++++++++++++++++++++++++++++++++++---
20  include/linux/clk-provider.h |  2 ++
21  2 files changed, 70 insertions(+), 5 deletions(-)
22
23 --- a/drivers/clk/clk.c
24 +++ b/drivers/clk/clk.c
25 @@ -51,9 +51,13 @@ struct clk_core {
26         struct clk_core         **parents;
27         u8                      num_parents;
28         u8                      new_parent_index;
29 +       u8                      safe_parent_index;
30         unsigned long           rate;
31         unsigned long           req_rate;
32 +       unsigned long           old_rate;
33         unsigned long           new_rate;
34 +       unsigned long           safe_freq;
35 +       struct clk_core         *safe_parent;
36         struct clk_core         *new_parent;
37         struct clk_core         *new_child;
38         unsigned long           flags;
39 @@ -1310,7 +1314,9 @@ out:
40  static void clk_calc_subtree(struct clk_core *core, unsigned long new_rate,
41                              struct clk_core *new_parent, u8 p_index)
42  {
43 -       struct clk_core *child;
44 +       struct clk_core *child, *parent;
45 +       struct clk_hw *parent_hw;
46 +       unsigned long safe_freq = 0;
47  
48         core->new_rate = new_rate;
49         core->new_parent = new_parent;
50 @@ -1320,6 +1326,23 @@ static void clk_calc_subtree(struct clk_
51         if (new_parent && new_parent != core->parent)
52                 new_parent->new_child = core;
53  
54 +       if (core->ops->get_safe_parent) {
55 +               parent_hw = core->ops->get_safe_parent(core->hw, &safe_freq);
56 +               if (parent_hw) {
57 +                       parent = parent_hw->core;
58 +                       p_index = clk_fetch_parent_index(core, parent);
59 +                       core->safe_parent_index = p_index;
60 +                       core->safe_parent = parent;
61 +                       if (safe_freq)
62 +                               core->safe_freq = safe_freq;
63 +                       else
64 +                               core->safe_freq = 0;
65 +               }
66 +       } else {
67 +               core->safe_parent = NULL;
68 +               core->safe_freq = 0;
69 +       }
70 +
71         hlist_for_each_entry(child, &core->children, child_node) {
72                 child->new_rate = clk_recalc(child, new_rate);
73                 clk_calc_subtree(child, child->new_rate, NULL, 0);
74 @@ -1432,14 +1455,51 @@ static struct clk_core *clk_propagate_ra
75                                                   unsigned long event)
76  {
77         struct clk_core *child, *tmp_clk, *fail_clk = NULL;
78 +       struct clk_core *old_parent;
79         int ret = NOTIFY_DONE;
80  
81 -       if (core->rate == core->new_rate)
82 +       if (core->rate == core->new_rate && event != POST_RATE_CHANGE)
83                 return NULL;
84  
85 +       switch (event) {
86 +       case PRE_RATE_CHANGE:
87 +               if (core->safe_parent) {
88 +                       if (core->safe_freq)
89 +                               core->ops->set_rate_and_parent(core->hw,
90 +                                               core->safe_freq,
91 +                                               core->safe_parent->rate,
92 +                                               core->safe_parent_index);
93 +                       else
94 +                               core->ops->set_parent(core->hw,
95 +                                               core->safe_parent_index);
96 +               }
97 +               core->old_rate = core->rate;
98 +               break;
99 +       case POST_RATE_CHANGE:
100 +               if (core->safe_parent) {
101 +                       old_parent = __clk_set_parent_before(core,
102 +                                                            core->new_parent);
103 +                       if (core->ops->set_rate_and_parent) {
104 +                               core->ops->set_rate_and_parent(core->hw,
105 +                                               core->new_rate,
106 +                                               core->new_parent ?
107 +                                               core->new_parent->rate : 0,
108 +                                               core->new_parent_index);
109 +                       } else if (core->ops->set_parent) {
110 +                               core->ops->set_parent(core->hw,
111 +                                               core->new_parent_index);
112 +                       }
113 +                       __clk_set_parent_after(core, core->new_parent,
114 +                                              old_parent);
115 +               }
116 +               break;
117 +       }
118 +
119         if (core->notifier_count) {
120 -               ret = __clk_notify(core, event, core->rate, core->new_rate);
121 -               if (ret & NOTIFY_STOP_MASK)
122 +               if (event != POST_RATE_CHANGE || core->old_rate != core->rate)
123 +                       ret = __clk_notify(core, event, core->old_rate,
124 +                                          core->new_rate);
125 +               if (ret & NOTIFY_STOP_MASK && event != POST_RATE_CHANGE)
126                         fail_clk = core;
127         }
128  
129 @@ -1495,7 +1555,8 @@ clk_change_rate(struct clk_core *core, u
130                 clk_enable_unlock(flags);
131         }
132  
133 -       if (core->new_parent && core->new_parent != core->parent) {
134 +       if (core->new_parent && core->new_parent != core->parent &&
135 +           !core->safe_parent) {
136                 old_parent = __clk_set_parent_before(core, core->new_parent);
137                 trace_clk_set_parent(core, core->new_parent);
138  
139 @@ -1601,6 +1662,8 @@ static int clk_core_set_rate_nolock(stru
140  
141         core->req_rate = req_rate;
142  
143 +       clk_propagate_rate_change(top, POST_RATE_CHANGE);
144 +
145         return 0;
146  }
147  
148 --- a/include/linux/clk-provider.h
149 +++ b/include/linux/clk-provider.h
150 @@ -206,6 +206,8 @@ struct clk_ops {
151                                           struct clk_rate_request *req);
152         int             (*set_parent)(struct clk_hw *hw, u8 index);
153         u8              (*get_parent)(struct clk_hw *hw);
154 +       struct clk_hw   *(*get_safe_parent)(struct clk_hw *hw,
155 +                                           unsigned long *safe_freq);
156         int             (*set_rate)(struct clk_hw *hw, unsigned long rate,
157                                     unsigned long parent_rate);
158         int             (*set_rate_and_parent)(struct clk_hw *hw,