ipq: more v4.9 fixes
[openwrt/staging/blogic.git] / target / linux / ipq806x / patches-4.9 / 0043-clk-qcom-Add-Krait-clock-controller-driver.patch
1 From 7fb5976eb0231a06f484a6bde5e5fbfee7ee4f4a Mon Sep 17 00:00:00 2001
2 From: Stephen Boyd <sboyd@codeaurora.org>
3 Date: Fri, 20 Mar 2015 23:45:30 -0700
4 Subject: [PATCH 43/69] clk: qcom: Add Krait clock controller driver
5
6 The Krait CPU clocks are made up of a primary mux and secondary
7 mux for each CPU and the L2, controlled via cp15 accessors. For
8 Kraits within KPSSv1 each secondary mux accepts a different aux
9 source, but on KPSSv2 each secondary mux accepts the same aux
10 source.
11
12 Cc: <devicetree@vger.kernel.org>
13 Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
14 ---
15 .../devicetree/bindings/clock/qcom,krait-cc.txt | 22 ++
16 drivers/clk/qcom/Kconfig | 8 +
17 drivers/clk/qcom/Makefile | 1 +
18 drivers/clk/qcom/krait-cc.c | 352 +++++++++++++++++++++
19 4 files changed, 383 insertions(+)
20 create mode 100644 Documentation/devicetree/bindings/clock/qcom,krait-cc.txt
21 create mode 100644 drivers/clk/qcom/krait-cc.c
22
23 diff --git a/Documentation/devicetree/bindings/clock/qcom,krait-cc.txt b/Documentation/devicetree/bindings/clock/qcom,krait-cc.txt
24 new file mode 100644
25 index 000000000000..874138f88ec6
26 --- /dev/null
27 +++ b/Documentation/devicetree/bindings/clock/qcom,krait-cc.txt
28 @@ -0,0 +1,22 @@
29 +Krait Clock Controller
30 +
31 +PROPERTIES
32 +
33 +- compatible:
34 + Usage: required
35 + Value type: <string>
36 + Definition: must be one of:
37 + "qcom,krait-cc-v1"
38 + "qcom,krait-cc-v2"
39 +
40 +- #clock-cells:
41 + Usage: required
42 + Value type: <u32>
43 + Definition: must be 1
44 +
45 +Example:
46 +
47 + kraitcc: clock-controller {
48 + compatible = "qcom,krait-cc-v1";
49 + #clock-cells = <1>;
50 + };
51 diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
52 index 747d979f6be7..0484ce46009d 100644
53 --- a/drivers/clk/qcom/Kconfig
54 +++ b/drivers/clk/qcom/Kconfig
55 @@ -196,6 +196,14 @@ config KPSS_XCC
56 if you want to support CPU frequency scaling on devices such
57 as MSM8960, APQ8064, etc.
58
59 +config KRAITCC
60 + tristate "Krait Clock Controller"
61 + depends on COMMON_CLK_QCOM && ARM
62 + select KRAIT_CLOCKS
63 + help
64 + Support for the Krait CPU clocks on Qualcomm devices.
65 + Say Y if you want to support CPU frequency scaling.
66 +
67 config KRAIT_CLOCKS
68 bool
69 select KRAIT_L2_ACCESSORS
70 diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
71 index f3d5ae4fc6cd..5fec2aeb2f55 100644
72 --- a/drivers/clk/qcom/Makefile
73 +++ b/drivers/clk/qcom/Makefile
74 @@ -35,3 +35,4 @@ obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o
75 obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o
76 obj-$(CONFIG_KPSS_XCC) += kpss-xcc.o
77 obj-$(CONFIG_QCOM_HFPLL) += hfpll.o
78 +obj-$(CONFIG_KRAITCC) += krait-cc.o
79 diff --git a/drivers/clk/qcom/krait-cc.c b/drivers/clk/qcom/krait-cc.c
80 new file mode 100644
81 index 000000000000..f55b5ecd0df8
82 --- /dev/null
83 +++ b/drivers/clk/qcom/krait-cc.c
84 @@ -0,0 +1,352 @@
85 +/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
86 + *
87 + * This program is free software; you can redistribute it and/or modify
88 + * it under the terms of the GNU General Public License version 2 and
89 + * only version 2 as published by the Free Software Foundation.
90 + *
91 + * This program is distributed in the hope that it will be useful,
92 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
93 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
94 + * GNU General Public License for more details.
95 + */
96 +
97 +#include <linux/kernel.h>
98 +#include <linux/init.h>
99 +#include <linux/module.h>
100 +#include <linux/platform_device.h>
101 +#include <linux/err.h>
102 +#include <linux/io.h>
103 +#include <linux/of.h>
104 +#include <linux/of_device.h>
105 +#include <linux/clk.h>
106 +#include <linux/clk-provider.h>
107 +#include <linux/slab.h>
108 +
109 +#include "clk-krait.h"
110 +
111 +static unsigned int sec_mux_map[] = {
112 + 2,
113 + 0,
114 +};
115 +
116 +static unsigned int pri_mux_map[] = {
117 + 1,
118 + 2,
119 + 0,
120 +};
121 +
122 +static int
123 +krait_add_div(struct device *dev, int id, const char *s, unsigned offset)
124 +{
125 + struct krait_div2_clk *div;
126 + struct clk_init_data init = {
127 + .num_parents = 1,
128 + .ops = &krait_div2_clk_ops,
129 + .flags = CLK_SET_RATE_PARENT,
130 + };
131 + const char *p_names[1];
132 + struct clk *clk;
133 +
134 + div = devm_kzalloc(dev, sizeof(*div), GFP_KERNEL);
135 + if (!div)
136 + return -ENOMEM;
137 +
138 + div->width = 2;
139 + div->shift = 6;
140 + div->lpl = id >= 0;
141 + div->offset = offset;
142 + div->hw.init = &init;
143 +
144 + init.name = kasprintf(GFP_KERNEL, "hfpll%s_div", s);
145 + if (!init.name)
146 + return -ENOMEM;
147 +
148 + init.parent_names = p_names;
149 + p_names[0] = kasprintf(GFP_KERNEL, "hfpll%s", s);
150 + if (!p_names[0]) {
151 + kfree(init.name);
152 + return -ENOMEM;
153 + }
154 +
155 + clk = devm_clk_register(dev, &div->hw);
156 + kfree(p_names[0]);
157 + kfree(init.name);
158 +
159 + return PTR_ERR_OR_ZERO(clk);
160 +}
161 +
162 +static int
163 +krait_add_sec_mux(struct device *dev, int id, const char *s, unsigned offset,
164 + bool unique_aux)
165 +{
166 + struct krait_mux_clk *mux;
167 + static const char *sec_mux_list[] = {
168 + "acpu_aux",
169 + "qsb",
170 + };
171 + struct clk_init_data init = {
172 + .parent_names = sec_mux_list,
173 + .num_parents = ARRAY_SIZE(sec_mux_list),
174 + .ops = &krait_mux_clk_ops,
175 + .flags = CLK_SET_RATE_PARENT,
176 + };
177 + struct clk *clk;
178 +
179 + mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
180 + if (!mux)
181 + return -ENOMEM;
182 +
183 + mux->offset = offset;
184 + mux->lpl = id >= 0;
185 + mux->has_safe_parent = true;
186 + mux->safe_sel = 2;
187 + mux->mask = 0x3;
188 + mux->shift = 2;
189 + mux->parent_map = sec_mux_map;
190 + mux->hw.init = &init;
191 +
192 + init.name = kasprintf(GFP_KERNEL, "krait%s_sec_mux", s);
193 + if (!init.name)
194 + return -ENOMEM;
195 +
196 + if (unique_aux) {
197 + sec_mux_list[0] = kasprintf(GFP_KERNEL, "acpu%s_aux", s);
198 + if (!sec_mux_list[0]) {
199 + clk = ERR_PTR(-ENOMEM);
200 + goto err_aux;
201 + }
202 + }
203 +
204 + clk = devm_clk_register(dev, &mux->hw);
205 +
206 + if (unique_aux)
207 + kfree(sec_mux_list[0]);
208 +err_aux:
209 + kfree(init.name);
210 + return PTR_ERR_OR_ZERO(clk);
211 +}
212 +
213 +static struct clk *
214 +krait_add_pri_mux(struct device *dev, int id, const char *s, unsigned offset)
215 +{
216 + struct krait_mux_clk *mux;
217 + const char *p_names[3];
218 + struct clk_init_data init = {
219 + .parent_names = p_names,
220 + .num_parents = ARRAY_SIZE(p_names),
221 + .ops = &krait_mux_clk_ops,
222 + .flags = CLK_SET_RATE_PARENT,
223 + };
224 + struct clk *clk;
225 +
226 + mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
227 + if (!mux)
228 + return ERR_PTR(-ENOMEM);
229 +
230 + mux->has_safe_parent = true;
231 + mux->safe_sel = 0;
232 + mux->mask = 0x3;
233 + mux->shift = 0;
234 + mux->offset = offset;
235 + mux->lpl = id >= 0;
236 + mux->parent_map = pri_mux_map;
237 + mux->hw.init = &init;
238 +
239 + init.name = kasprintf(GFP_KERNEL, "krait%s_pri_mux", s);
240 + if (!init.name)
241 + return ERR_PTR(-ENOMEM);
242 +
243 + p_names[0] = kasprintf(GFP_KERNEL, "hfpll%s", s);
244 + if (!p_names[0]) {
245 + clk = ERR_PTR(-ENOMEM);
246 + goto err_p0;
247 + }
248 +
249 + p_names[1] = kasprintf(GFP_KERNEL, "hfpll%s_div", s);
250 + if (!p_names[1]) {
251 + clk = ERR_PTR(-ENOMEM);
252 + goto err_p1;
253 + }
254 +
255 + p_names[2] = kasprintf(GFP_KERNEL, "krait%s_sec_mux", s);
256 + if (!p_names[2]) {
257 + clk = ERR_PTR(-ENOMEM);
258 + goto err_p2;
259 + }
260 +
261 + clk = devm_clk_register(dev, &mux->hw);
262 +
263 + kfree(p_names[2]);
264 +err_p2:
265 + kfree(p_names[1]);
266 +err_p1:
267 + kfree(p_names[0]);
268 +err_p0:
269 + kfree(init.name);
270 + return clk;
271 +}
272 +
273 +/* id < 0 for L2, otherwise id == physical CPU number */
274 +static struct clk *krait_add_clks(struct device *dev, int id, bool unique_aux)
275 +{
276 + int ret;
277 + unsigned offset;
278 + void *p = NULL;
279 + const char *s;
280 + struct clk *clk;
281 +
282 + if (id >= 0) {
283 + offset = 0x4501 + (0x1000 * id);
284 + s = p = kasprintf(GFP_KERNEL, "%d", id);
285 + if (!s)
286 + return ERR_PTR(-ENOMEM);
287 + } else {
288 + offset = 0x500;
289 + s = "_l2";
290 + }
291 +
292 + ret = krait_add_div(dev, id, s, offset);
293 + if (ret) {
294 + clk = ERR_PTR(ret);
295 + goto err;
296 + }
297 +
298 + ret = krait_add_sec_mux(dev, id, s, offset, unique_aux);
299 + if (ret) {
300 + clk = ERR_PTR(ret);
301 + goto err;
302 + }
303 +
304 + clk = krait_add_pri_mux(dev, id, s, offset);
305 +err:
306 + kfree(p);
307 + return clk;
308 +}
309 +
310 +static struct clk *krait_of_get(struct of_phandle_args *clkspec, void *data)
311 +{
312 + unsigned int idx = clkspec->args[0];
313 + struct clk **clks = data;
314 +
315 + if (idx >= 5) {
316 + pr_err("%s: invalid clock index %d\n", __func__, idx);
317 + return ERR_PTR(-EINVAL);
318 + }
319 +
320 + return clks[idx] ? : ERR_PTR(-ENODEV);
321 +}
322 +
323 +static const struct of_device_id krait_cc_match_table[] = {
324 + { .compatible = "qcom,krait-cc-v1", (void *)1UL },
325 + { .compatible = "qcom,krait-cc-v2" },
326 + {}
327 +};
328 +MODULE_DEVICE_TABLE(of, krait_cc_match_table);
329 +
330 +static int krait_cc_probe(struct platform_device *pdev)
331 +{
332 + struct device *dev = &pdev->dev;
333 + const struct of_device_id *id;
334 + unsigned long cur_rate, aux_rate;
335 + int cpu;
336 + struct clk *clk;
337 + struct clk **clks;
338 + struct clk *l2_pri_mux_clk;
339 +
340 + id = of_match_device(krait_cc_match_table, dev);
341 + if (!id)
342 + return -ENODEV;
343 +
344 + /* Rate is 1 because 0 causes problems for __clk_mux_determine_rate */
345 + clk = clk_register_fixed_rate(dev, "qsb", NULL, CLK_IS_ROOT, 1);
346 + if (IS_ERR(clk))
347 + return PTR_ERR(clk);
348 +
349 + if (!id->data) {
350 + clk = clk_register_fixed_factor(dev, "acpu_aux",
351 + "gpll0_vote", 0, 1, 2);
352 + if (IS_ERR(clk))
353 + return PTR_ERR(clk);
354 + }
355 +
356 + /* Krait configurations have at most 4 CPUs and one L2 */
357 + clks = devm_kcalloc(dev, 5, sizeof(*clks), GFP_KERNEL);
358 + if (!clks)
359 + return -ENOMEM;
360 +
361 + for_each_possible_cpu(cpu) {
362 + clk = krait_add_clks(dev, cpu, id->data);
363 + if (IS_ERR(clk))
364 + return PTR_ERR(clk);
365 + clks[cpu] = clk;
366 + }
367 +
368 + l2_pri_mux_clk = krait_add_clks(dev, -1, id->data);
369 + if (IS_ERR(l2_pri_mux_clk))
370 + return PTR_ERR(l2_pri_mux_clk);
371 + clks[4] = l2_pri_mux_clk;
372 +
373 + /*
374 + * We don't want the CPU or L2 clocks to be turned off at late init
375 + * if CPUFREQ or HOTPLUG configs are disabled. So, bump up the
376 + * refcount of these clocks. Any cpufreq/hotplug manager can assume
377 + * that the clocks have already been prepared and enabled by the time
378 + * they take over.
379 + */
380 + for_each_online_cpu(cpu) {
381 + clk_prepare_enable(l2_pri_mux_clk);
382 + WARN(clk_prepare_enable(clks[cpu]),
383 + "Unable to turn on CPU%d clock", cpu);
384 + }
385 +
386 + /*
387 + * Force reinit of HFPLLs and muxes to overwrite any potential
388 + * incorrect configuration of HFPLLs and muxes by the bootloader.
389 + * While at it, also make sure the cores are running at known rates
390 + * and print the current rate.
391 + *
392 + * The clocks are set to aux clock rate first to make sure the
393 + * secondary mux is not sourcing off of QSB. The rate is then set to
394 + * two different rates to force a HFPLL reinit under all
395 + * circumstances.
396 + */
397 + cur_rate = clk_get_rate(l2_pri_mux_clk);
398 + aux_rate = 384000000;
399 + if (cur_rate == 1) {
400 + pr_info("L2 @ QSB rate. Forcing new rate.\n");
401 + cur_rate = aux_rate;
402 + }
403 + clk_set_rate(l2_pri_mux_clk, aux_rate);
404 + clk_set_rate(l2_pri_mux_clk, 2);
405 + clk_set_rate(l2_pri_mux_clk, cur_rate);
406 + pr_info("L2 @ %lu KHz\n", clk_get_rate(l2_pri_mux_clk) / 1000);
407 + for_each_possible_cpu(cpu) {
408 + clk = clks[cpu];
409 + cur_rate = clk_get_rate(clk);
410 + if (cur_rate == 1) {
411 + pr_info("CPU%d @ QSB rate. Forcing new rate.\n", cpu);
412 + cur_rate = aux_rate;
413 + }
414 + clk_set_rate(clk, aux_rate);
415 + clk_set_rate(clk, 2);
416 + clk_set_rate(clk, cur_rate);
417 + pr_info("CPU%d @ %lu KHz\n", cpu, clk_get_rate(clk) / 1000);
418 + }
419 +
420 + of_clk_add_provider(dev->of_node, krait_of_get, clks);
421 +
422 + return 0;
423 +}
424 +
425 +static struct platform_driver krait_cc_driver = {
426 + .probe = krait_cc_probe,
427 + .driver = {
428 + .name = "krait-cc",
429 + .of_match_table = krait_cc_match_table,
430 + },
431 +};
432 +module_platform_driver(krait_cc_driver);
433 +
434 +MODULE_DESCRIPTION("Krait CPU Clock Driver");
435 +MODULE_LICENSE("GPL v2");
436 +MODULE_ALIAS("platform:krait-cc");
437 --
438 2.11.0
439