57d4afe3a58868c9d4c108d7a4ef2587645048a9
[openwrt/openwrt.git] / target / linux / ipq806x / patches-4.0 / 143-cpufreq-Add-module-to-register-cpufreq-on-Krait-CPUs.patch
1 Content-Type: text/plain; charset="utf-8"
2 MIME-Version: 1.0
3 Content-Transfer-Encoding: 7bit
4 Subject: [v3,12/13] cpufreq: Add module to register cpufreq on Krait CPUs
5 From: Stephen Boyd <sboyd@codeaurora.org>
6 X-Patchwork-Id: 6063191
7 Message-Id: <1426920332-9340-13-git-send-email-sboyd@codeaurora.org>
8 To: Mike Turquette <mturquette@linaro.org>, Stephen Boyd <sboyd@codeaurora.org>
9 Cc: linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org,
10 linux-pm@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
11 Viresh Kumar <viresh.kumar@linaro.org>, <devicetree@vger.kernel.org>
12 Date: Fri, 20 Mar 2015 23:45:31 -0700
13
14 Register a cpufreq-generic device whenever we detect that a
15 "qcom,krait" compatible CPU is present in DT.
16
17 Cc: <devicetree@vger.kernel.org>
18 Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
19
20 ---
21 .../devicetree/bindings/arm/msm/qcom,pvs.txt | 38 ++++
22 drivers/cpufreq/Kconfig.arm | 9 +
23 drivers/cpufreq/Makefile | 1 +
24 drivers/cpufreq/qcom-cpufreq.c | 204 +++++++++++++++++++++
25 4 files changed, 252 insertions(+)
26 create mode 100644 Documentation/devicetree/bindings/arm/msm/qcom,pvs.txt
27 create mode 100644 drivers/cpufreq/qcom-cpufreq.c
28
29 --- /dev/null
30 +++ b/Documentation/devicetree/bindings/arm/msm/qcom,pvs.txt
31 @@ -0,0 +1,38 @@
32 +Qualcomm Process Voltage Scaling Tables
33 +
34 +The node name is required to be "qcom,pvs". There shall only be one
35 +such node present in the root of the tree.
36 +
37 +PROPERTIES
38 +
39 +- qcom,pvs-format-a or qcom,pvs-format-b:
40 + Usage: required
41 + Value type: <empty>
42 + Definition: Indicates the format of qcom,speedX-pvsY-bin-vZ properties.
43 + If qcom,pvs-format-a is used the table is two columns
44 + (frequency and voltage in that order). If qcom,pvs-format-b is used the table is three columns (frequency, voltage,
45 + and current in that order).
46 +
47 +- qcom,speedX-pvsY-bin-vZ:
48 + Usage: required
49 + Value type: <prop-encoded-array>
50 + Definition: The PVS table corresponding to the speed bin X, pvs bin Y,
51 + and version Z.
52 +Example:
53 +
54 + qcom,pvs {
55 + qcom,pvs-format-a;
56 + qcom,speed0-pvs0-bin-v0 =
57 + < 384000000 950000 >,
58 + < 486000000 975000 >,
59 + < 594000000 1000000 >,
60 + < 702000000 1025000 >,
61 + < 810000000 1075000 >,
62 + < 918000000 1100000 >,
63 + < 1026000000 1125000 >,
64 + < 1134000000 1175000 >,
65 + < 1242000000 1200000 >,
66 + < 1350000000 1225000 >,
67 + < 1458000000 1237500 >,
68 + < 1512000000 1250000 >;
69 + };
70 --- a/drivers/cpufreq/Kconfig.arm
71 +++ b/drivers/cpufreq/Kconfig.arm
72 @@ -137,6 +137,15 @@ config ARM_OMAP2PLUS_CPUFREQ
73 depends on ARCH_OMAP2PLUS
74 default ARCH_OMAP2PLUS
75
76 +config ARM_QCOM_CPUFREQ
77 + tristate "Qualcomm based"
78 + depends on ARCH_QCOM
79 + select PM_OPP
80 + help
81 + This adds the CPUFreq driver for Qualcomm SoC based boards.
82 +
83 + If in doubt, say N.
84 +
85 config ARM_S3C_CPUFREQ
86 bool
87 help
88 --- a/drivers/cpufreq/Makefile
89 +++ b/drivers/cpufreq/Makefile
90 @@ -65,6 +65,7 @@ obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ) += ki
91 obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ) += omap-cpufreq.o
92 obj-$(CONFIG_ARM_PXA2xx_CPUFREQ) += pxa2xx-cpufreq.o
93 obj-$(CONFIG_PXA3xx) += pxa3xx-cpufreq.o
94 +obj-$(CONFIG_ARM_QCOM_CPUFREQ) += qcom-cpufreq.o
95 obj-$(CONFIG_ARM_S3C24XX_CPUFREQ) += s3c24xx-cpufreq.o
96 obj-$(CONFIG_ARM_S3C24XX_CPUFREQ_DEBUGFS) += s3c24xx-cpufreq-debugfs.o
97 obj-$(CONFIG_ARM_S3C2410_CPUFREQ) += s3c2410-cpufreq.o
98 --- /dev/null
99 +++ b/drivers/cpufreq/qcom-cpufreq.c
100 @@ -0,0 +1,204 @@
101 +/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
102 + *
103 + * This program is free software; you can redistribute it and/or modify
104 + * it under the terms of the GNU General Public License version 2 and
105 + * only version 2 as published by the Free Software Foundation.
106 + *
107 + * This program is distributed in the hope that it will be useful,
108 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
109 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
110 + * GNU General Public License for more details.
111 + */
112 +
113 +#include <linux/cpu.h>
114 +#include <linux/err.h>
115 +#include <linux/init.h>
116 +#include <linux/io.h>
117 +#include <linux/kernel.h>
118 +#include <linux/module.h>
119 +#include <linux/of.h>
120 +#include <linux/platform_device.h>
121 +#include <linux/pm_opp.h>
122 +#include <linux/slab.h>
123 +#include <linux/cpufreq-dt.h>
124 +
125 +static void __init get_krait_bin_format_a(int *speed, int *pvs, int *pvs_ver)
126 +{
127 + void __iomem *base;
128 + u32 pte_efuse;
129 +
130 + *speed = *pvs = *pvs_ver = 0;
131 +
132 + base = ioremap(0x007000c0, 4);
133 + if (!base) {
134 + pr_warn("Unable to read efuse data. Defaulting to 0!\n");
135 + return;
136 + }
137 +
138 + pte_efuse = readl_relaxed(base);
139 + iounmap(base);
140 +
141 + *speed = pte_efuse & 0xf;
142 + if (*speed == 0xf)
143 + *speed = (pte_efuse >> 4) & 0xf;
144 +
145 + if (*speed == 0xf) {
146 + *speed = 0;
147 + pr_warn("Speed bin: Defaulting to %d\n", *speed);
148 + } else {
149 + pr_info("Speed bin: %d\n", *speed);
150 + }
151 +
152 + *pvs = (pte_efuse >> 10) & 0x7;
153 + if (*pvs == 0x7)
154 + *pvs = (pte_efuse >> 13) & 0x7;
155 +
156 + if (*pvs == 0x7) {
157 + *pvs = 0;
158 + pr_warn("PVS bin: Defaulting to %d\n", *pvs);
159 + } else {
160 + pr_info("PVS bin: %d\n", *pvs);
161 + }
162 +}
163 +
164 +static void __init get_krait_bin_format_b(int *speed, int *pvs, int *pvs_ver)
165 +{
166 + u32 pte_efuse, redundant_sel;
167 + void __iomem *base;
168 +
169 + *speed = 0;
170 + *pvs = 0;
171 + *pvs_ver = 0;
172 +
173 + base = ioremap(0xfc4b80b0, 8);
174 + if (!base) {
175 + pr_warn("Unable to read efuse data. Defaulting to 0!\n");
176 + return;
177 + }
178 +
179 + pte_efuse = readl_relaxed(base);
180 + redundant_sel = (pte_efuse >> 24) & 0x7;
181 + *speed = pte_efuse & 0x7;
182 + /* 4 bits of PVS are in efuse register bits 31, 8-6. */
183 + *pvs = ((pte_efuse >> 28) & 0x8) | ((pte_efuse >> 6) & 0x7);
184 + *pvs_ver = (pte_efuse >> 4) & 0x3;
185 +
186 + switch (redundant_sel) {
187 + case 1:
188 + *speed = (pte_efuse >> 27) & 0xf;
189 + break;
190 + case 2:
191 + *pvs = (pte_efuse >> 27) & 0xf;
192 + break;
193 + }
194 +
195 + /* Check SPEED_BIN_BLOW_STATUS */
196 + if (pte_efuse & BIT(3)) {
197 + pr_info("Speed bin: %d\n", *speed);
198 + } else {
199 + pr_warn("Speed bin not set. Defaulting to 0!\n");
200 + *speed = 0;
201 + }
202 +
203 + /* Check PVS_BLOW_STATUS */
204 + pte_efuse = readl_relaxed(base + 0x4) & BIT(21);
205 + if (pte_efuse) {
206 + pr_info("PVS bin: %d\n", *pvs);
207 + } else {
208 + pr_warn("PVS bin not set. Defaulting to 0!\n");
209 + *pvs = 0;
210 + }
211 +
212 + pr_info("PVS version: %d\n", *pvs_ver);
213 + iounmap(base);
214 +}
215 +
216 +static int __init qcom_cpufreq_populate_opps(void)
217 +{
218 + int len, rows, cols, i, k, speed, pvs, pvs_ver;
219 + char table_name[] = "qcom,speedXX-pvsXX-bin-vXX";
220 + struct device_node *np;
221 + struct device *dev;
222 + int cpu = 0;
223 +
224 + np = of_find_node_by_name(NULL, "qcom,pvs");
225 + if (!np)
226 + return -ENODEV;
227 +
228 + if (of_property_read_bool(np, "qcom,pvs-format-a")) {
229 + get_krait_bin_format_a(&speed, &pvs, &pvs_ver);
230 + cols = 2;
231 + } else if (of_property_read_bool(np, "qcom,pvs-format-b")) {
232 + get_krait_bin_format_b(&speed, &pvs, &pvs_ver);
233 + cols = 3;
234 + } else {
235 + return -ENODEV;
236 + }
237 +
238 + snprintf(table_name, sizeof(table_name),
239 + "qcom,speed%d-pvs%d-bin-v%d", speed, pvs, pvs_ver);
240 +
241 + if (!of_find_property(np, table_name, &len))
242 + return -EINVAL;
243 +
244 + len /= sizeof(u32);
245 + if (len % cols || len == 0)
246 + return -EINVAL;
247 +
248 + rows = len / cols;
249 +
250 + for (i = 0, k = 0; i < rows; i++) {
251 + u32 freq, volt;
252 +
253 + of_property_read_u32_index(np, table_name, k++, &freq);
254 + of_property_read_u32_index(np, table_name, k++, &volt);
255 + while (k % cols)
256 + k++; /* Skip uA entries if present */
257 + for (cpu = 0; cpu < num_possible_cpus(); cpu++) {
258 + dev = get_cpu_device(cpu);
259 + if (!dev)
260 + return -ENODEV;
261 + if (dev_pm_opp_add(dev, freq, volt))
262 + pr_warn("failed to add OPP %u\n", freq);
263 + }
264 + }
265 +
266 + return 0;
267 +}
268 +
269 +static int __init qcom_cpufreq_driver_init(void)
270 +{
271 + struct cpufreq_dt_platform_data pdata = { .independent_clocks = true };
272 + struct platform_device_info devinfo = {
273 + .name = "cpufreq-dt",
274 + .data = &pdata,
275 + .size_data = sizeof(pdata),
276 + };
277 + struct device *cpu_dev;
278 + struct device_node *np;
279 + int ret;
280 +
281 + cpu_dev = get_cpu_device(0);
282 + if (!cpu_dev)
283 + return -ENODEV;
284 +
285 + np = of_node_get(cpu_dev->of_node);
286 + if (!np)
287 + return -ENOENT;
288 +
289 + if (!of_device_is_compatible(np, "qcom,krait")) {
290 + of_node_put(np);
291 + return -ENODEV;
292 + }
293 + of_node_put(np);
294 +
295 + ret = qcom_cpufreq_populate_opps();
296 + if (ret)
297 + return ret;
298 +
299 + return PTR_ERR_OR_ZERO(platform_device_register_full(&devinfo));
300 +}
301 +module_init(qcom_cpufreq_driver_init);
302 +
303 +MODULE_DESCRIPTION("Qualcomm CPUfreq driver");
304 +MODULE_LICENSE("GPL v2");