OpenWrt – Blame information for rev 4
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
4 | office | 1 | From patchwork Fri Dec 8 09:42:25 2017 |
2 | Content-Type: text/plain; charset="utf-8" |
||
3 | MIME-Version: 1.0 |
||
4 | Content-Transfer-Encoding: 7bit |
||
5 | Subject: [v4,07/12] clk: qcom: Add support for Krait clocks |
||
6 | From: Sricharan R <sricharan@codeaurora.org> |
||
7 | X-Patchwork-Id: 10102051 |
||
8 | Message-Id: <1512726150-7204-8-git-send-email-sricharan@codeaurora.org> |
||
9 | To: mturquette@baylibre.com, sboyd@codeaurora.org, |
||
10 | devicetree@vger.kernel.org, linux-pm@vger.kernel.org, |
||
11 | linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org, |
||
12 | viresh.kumar@linaro.org, linux-arm-kernel@lists.infradead.org |
||
13 | Cc: sricharan@codeaurora.org |
||
14 | Date: Fri, 8 Dec 2017 15:12:25 +0530 |
||
15 | |||
16 | From: Stephen Boyd <sboyd@codeaurora.org> |
||
17 | |||
18 | The Krait clocks are made up of a series of muxes and a divider |
||
19 | that choose between a fixed rate clock and dedicated HFPLLs for |
||
20 | each CPU. Instead of using mmio accesses to remux parents, the |
||
21 | Krait implementation exposes the remux control via cp15 |
||
22 | registers. Support these clocks. |
||
23 | |||
24 | Signed-off-by: Stephen Boyd <sboyd@codeaurora.org> |
||
25 | --- |
||
26 | drivers/clk/qcom/Kconfig | 4 ++ |
||
27 | drivers/clk/qcom/Makefile | 1 + |
||
28 | drivers/clk/qcom/clk-krait.c | 134 +++++++++++++++++++++++++++++++++++++++++++ |
||
29 | drivers/clk/qcom/clk-krait.h | 48 ++++++++++++++++ |
||
30 | 4 files changed, 187 insertions(+) |
||
31 | create mode 100644 drivers/clk/qcom/clk-krait.c |
||
32 | create mode 100644 drivers/clk/qcom/clk-krait.h |
||
33 | |||
34 | --- a/drivers/clk/qcom/Kconfig |
||
35 | +++ b/drivers/clk/qcom/Kconfig |
||
36 | @@ -204,3 +204,7 @@ config QCOM_HFPLL |
||
37 | Support for the high-frequency PLLs present on Qualcomm devices. |
||
38 | Say Y if you want to support CPU frequency scaling on devices |
||
39 | such as MSM8974, APQ8084, etc. |
||
40 | + |
||
41 | +config KRAIT_CLOCKS |
||
42 | + bool |
||
43 | + select KRAIT_L2_ACCESSORS |
||
44 | --- a/drivers/clk/qcom/Makefile |
||
45 | +++ b/drivers/clk/qcom/Makefile |
||
46 | @@ -10,6 +10,7 @@ clk-qcom-y += clk-rcg2.o |
||
47 | clk-qcom-y += clk-branch.o |
||
48 | clk-qcom-y += clk-regmap-divider.o |
||
49 | clk-qcom-y += clk-regmap-mux.o |
||
50 | +clk-qcom-$(CONFIG_KRAIT_CLOCKS) += clk-krait.o |
||
51 | clk-qcom-y += clk-hfpll.o |
||
52 | clk-qcom-y += reset.o |
||
53 | clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o |
||
54 | --- /dev/null |
||
55 | +++ b/drivers/clk/qcom/clk-krait.c |
||
56 | @@ -0,0 +1,134 @@ |
||
57 | +/* |
||
58 | + * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. |
||
59 | + * |
||
60 | + * This program is free software; you can redistribute it and/or modify |
||
61 | + * it under the terms of the GNU General Public License version 2 and |
||
62 | + * only version 2 as published by the Free Software Foundation. |
||
63 | + * |
||
64 | + * This program is distributed in the hope that it will be useful, |
||
65 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
66 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
67 | + * GNU General Public License for more details. |
||
68 | + */ |
||
69 | + |
||
70 | +#include <linux/kernel.h> |
||
71 | +#include <linux/module.h> |
||
72 | +#include <linux/init.h> |
||
73 | +#include <linux/io.h> |
||
74 | +#include <linux/delay.h> |
||
75 | +#include <linux/err.h> |
||
76 | +#include <linux/clk-provider.h> |
||
77 | +#include <linux/spinlock.h> |
||
78 | + |
||
79 | +#include <asm/krait-l2-accessors.h> |
||
80 | + |
||
81 | +#include "clk-krait.h" |
||
82 | + |
||
83 | +/* Secondary and primary muxes share the same cp15 register */ |
||
84 | +static DEFINE_SPINLOCK(krait_clock_reg_lock); |
||
85 | + |
||
86 | +#define LPL_SHIFT 8 |
||
87 | +static void __krait_mux_set_sel(struct krait_mux_clk *mux, int sel) |
||
88 | +{ |
||
89 | + unsigned long flags; |
||
90 | + u32 regval; |
||
91 | + |
||
92 | + spin_lock_irqsave(&krait_clock_reg_lock, flags); |
||
93 | + regval = krait_get_l2_indirect_reg(mux->offset); |
||
94 | + regval &= ~(mux->mask << mux->shift); |
||
95 | + regval |= (sel & mux->mask) << mux->shift; |
||
96 | + if (mux->lpl) { |
||
97 | + regval &= ~(mux->mask << (mux->shift + LPL_SHIFT)); |
||
98 | + regval |= (sel & mux->mask) << (mux->shift + LPL_SHIFT); |
||
99 | + } |
||
100 | + krait_set_l2_indirect_reg(mux->offset, regval); |
||
101 | + spin_unlock_irqrestore(&krait_clock_reg_lock, flags); |
||
102 | + |
||
103 | + /* Wait for switch to complete. */ |
||
104 | + mb(); |
||
105 | + udelay(1); |
||
106 | +} |
||
107 | + |
||
108 | +static int krait_mux_set_parent(struct clk_hw *hw, u8 index) |
||
109 | +{ |
||
110 | + struct krait_mux_clk *mux = to_krait_mux_clk(hw); |
||
111 | + u32 sel; |
||
112 | + |
||
113 | + sel = clk_mux_reindex(index, mux->parent_map, 0); |
||
114 | + mux->en_mask = sel; |
||
115 | + /* Don't touch mux if CPU is off as it won't work */ |
||
116 | + if (__clk_is_enabled(hw->clk)) |
||
117 | + __krait_mux_set_sel(mux, sel); |
||
118 | + |
||
119 | + return 0; |
||
120 | +} |
||
121 | + |
||
122 | +static u8 krait_mux_get_parent(struct clk_hw *hw) |
||
123 | +{ |
||
124 | + struct krait_mux_clk *mux = to_krait_mux_clk(hw); |
||
125 | + u32 sel; |
||
126 | + |
||
127 | + sel = krait_get_l2_indirect_reg(mux->offset); |
||
128 | + sel >>= mux->shift; |
||
129 | + sel &= mux->mask; |
||
130 | + mux->en_mask = sel; |
||
131 | + |
||
132 | + return clk_mux_get_parent(hw, sel, mux->parent_map, 0); |
||
133 | +} |
||
134 | + |
||
135 | +const struct clk_ops krait_mux_clk_ops = { |
||
136 | + .set_parent = krait_mux_set_parent, |
||
137 | + .get_parent = krait_mux_get_parent, |
||
138 | + .determine_rate = __clk_mux_determine_rate_closest, |
||
139 | +}; |
||
140 | +EXPORT_SYMBOL_GPL(krait_mux_clk_ops); |
||
141 | + |
||
142 | +/* The divider can divide by 2, 4, 6 and 8. But we only really need div-2. */ |
||
143 | +static long krait_div2_round_rate(struct clk_hw *hw, unsigned long rate, |
||
144 | + unsigned long *parent_rate) |
||
145 | +{ |
||
146 | + *parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), rate * 2); |
||
147 | + return DIV_ROUND_UP(*parent_rate, 2); |
||
148 | +} |
||
149 | + |
||
150 | +static int krait_div2_set_rate(struct clk_hw *hw, unsigned long rate, |
||
151 | + unsigned long parent_rate) |
||
152 | +{ |
||
153 | + struct krait_div2_clk *d = to_krait_div2_clk(hw); |
||
154 | + unsigned long flags; |
||
155 | + u32 val; |
||
156 | + u32 mask = BIT(d->width) - 1; |
||
157 | + |
||
158 | + if (d->lpl) |
||
159 | + mask = mask << (d->shift + LPL_SHIFT) | mask << d->shift; |
||
160 | + |
||
161 | + spin_lock_irqsave(&krait_clock_reg_lock, flags); |
||
162 | + val = krait_get_l2_indirect_reg(d->offset); |
||
163 | + val &= ~mask; |
||
164 | + krait_set_l2_indirect_reg(d->offset, val); |
||
165 | + spin_unlock_irqrestore(&krait_clock_reg_lock, flags); |
||
166 | + |
||
167 | + return 0; |
||
168 | +} |
||
169 | + |
||
170 | +static unsigned long |
||
171 | +krait_div2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) |
||
172 | +{ |
||
173 | + struct krait_div2_clk *d = to_krait_div2_clk(hw); |
||
174 | + u32 mask = BIT(d->width) - 1; |
||
175 | + u32 div; |
||
176 | + |
||
177 | + div = krait_get_l2_indirect_reg(d->offset); |
||
178 | + div >>= d->shift; |
||
179 | + div &= mask; |
||
180 | + div = (div + 1) * 2; |
||
181 | + |
||
182 | + return DIV_ROUND_UP(parent_rate, div); |
||
183 | +} |
||
184 | + |
||
185 | +const struct clk_ops krait_div2_clk_ops = { |
||
186 | + .round_rate = krait_div2_round_rate, |
||
187 | + .set_rate = krait_div2_set_rate, |
||
188 | + .recalc_rate = krait_div2_recalc_rate, |
||
189 | +}; |
||
190 | +EXPORT_SYMBOL_GPL(krait_div2_clk_ops); |
||
191 | --- /dev/null |
||
192 | +++ b/drivers/clk/qcom/clk-krait.h |
||
193 | @@ -0,0 +1,48 @@ |
||
194 | +/* |
||
195 | + * Copyright (c) 2013, The Linux Foundation. All rights reserved. |
||
196 | + * |
||
197 | + * This program is free software; you can redistribute it and/or modify |
||
198 | + * it under the terms of the GNU General Public License version 2 and |
||
199 | + * only version 2 as published by the Free Software Foundation. |
||
200 | + * |
||
201 | + * This program is distributed in the hope that it will be useful, |
||
202 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
203 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
204 | + * GNU General Public License for more details. |
||
205 | + */ |
||
206 | + |
||
207 | +#ifndef __QCOM_CLK_KRAIT_H |
||
208 | +#define __QCOM_CLK_KRAIT_H |
||
209 | + |
||
210 | +#include <linux/clk-provider.h> |
||
211 | + |
||
212 | +struct krait_mux_clk { |
||
213 | + unsigned int *parent_map; |
||
214 | + u32 offset; |
||
215 | + u32 mask; |
||
216 | + u32 shift; |
||
217 | + u32 en_mask; |
||
218 | + bool lpl; |
||
219 | + |
||
220 | + struct clk_hw hw; |
||
221 | + struct notifier_block clk_nb; |
||
222 | +}; |
||
223 | + |
||
224 | +#define to_krait_mux_clk(_hw) container_of(_hw, struct krait_mux_clk, hw) |
||
225 | + |
||
226 | +extern const struct clk_ops krait_mux_clk_ops; |
||
227 | + |
||
228 | +struct krait_div2_clk { |
||
229 | + u32 offset; |
||
230 | + u8 width; |
||
231 | + u32 shift; |
||
232 | + bool lpl; |
||
233 | + |
||
234 | + struct clk_hw hw; |
||
235 | +}; |
||
236 | + |
||
237 | +#define to_krait_div2_clk(_hw) container_of(_hw, struct krait_div2_clk, hw) |
||
238 | + |
||
239 | +extern const struct clk_ops krait_div2_clk_ops; |
||
240 | + |
||
241 | +#endif |