87a4bf108ed93cd6f24d415f5bd7c8e9b365d1a8
[openwrt/openwrt.git] /
1 From a8811ec764f95a04ba82f6f457e28c5e9e36e36b Mon Sep 17 00:00:00 2001
2 From: Ansuel Smith <ansuelsmth@gmail.com>
3 Date: Fri, 13 Mar 2020 18:52:13 +0100
4 Subject: cpufreq: qcom: Add support for krait based socs
5
6 In Certain QCOM SoCs like ipq8064, apq8064, msm8960, msm8974
7 that has KRAIT processors the voltage/current value of each OPP
8 varies based on the silicon variant in use.
9
10 The required OPP related data is determined based on
11 the efuse value. This is similar to the existing code for
12 kryo cores. So adding support for krait cores here.
13
14 Signed-off-by: Sricharan R <sricharan@codeaurora.org>
15 Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
16 Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
17 ---
18 .../devicetree/bindings/opp/qcom-nvmem-cpufreq.txt | 3 +-
19 drivers/cpufreq/Kconfig.arm | 2 +-
20 drivers/cpufreq/cpufreq-dt-platdev.c | 5 +
21 drivers/cpufreq/qcom-cpufreq-nvmem.c | 191 +++++++++++++++++++--
22 4 files changed, 183 insertions(+), 18 deletions(-)
23
24 --- a/Documentation/devicetree/bindings/opp/qcom-nvmem-cpufreq.txt
25 +++ b/Documentation/devicetree/bindings/opp/qcom-nvmem-cpufreq.txt
26 @@ -19,7 +19,8 @@ In 'cpu' nodes:
27
28 In 'operating-points-v2' table:
29 - compatible: Should be
30 - - 'operating-points-v2-kryo-cpu' for apq8096 and msm8996.
31 + - 'operating-points-v2-kryo-cpu' for apq8096, msm8996, msm8974,
32 + apq8064, ipq8064, msm8960 and ipq8074.
33
34 Optional properties:
35 --------------------
36 --- a/drivers/cpufreq/Kconfig.arm
37 +++ b/drivers/cpufreq/Kconfig.arm
38 @@ -135,7 +135,7 @@ config ARM_OMAP2PLUS_CPUFREQ
39
40 config ARM_QCOM_CPUFREQ_NVMEM
41 tristate "Qualcomm nvmem based CPUFreq"
42 - depends on ARM64
43 + depends on ARCH_QCOM
44 depends on QCOM_QFPROM
45 depends on QCOM_SMEM
46 select PM_OPP
47 --- a/drivers/cpufreq/cpufreq-dt-platdev.c
48 +++ b/drivers/cpufreq/cpufreq-dt-platdev.c
49 @@ -138,6 +138,11 @@ static const struct of_device_id blackli
50 { .compatible = "ti,am43", },
51 { .compatible = "ti,dra7", },
52
53 + { .compatible = "qcom,ipq8064", },
54 + { .compatible = "qcom,apq8064", },
55 + { .compatible = "qcom,msm8974", },
56 + { .compatible = "qcom,msm8960", },
57 +
58 { }
59 };
60
61 --- a/drivers/cpufreq/qcom-cpufreq-nvmem.c
62 +++ b/drivers/cpufreq/qcom-cpufreq-nvmem.c
63 @@ -49,12 +49,14 @@ struct qcom_cpufreq_drv;
64 struct qcom_cpufreq_match_data {
65 int (*get_version)(struct device *cpu_dev,
66 struct nvmem_cell *speedbin_nvmem,
67 + char **pvs_name,
68 struct qcom_cpufreq_drv *drv);
69 const char **genpd_names;
70 };
71
72 struct qcom_cpufreq_drv {
73 - struct opp_table **opp_tables;
74 + struct opp_table **names_opp_tables;
75 + struct opp_table **hw_opp_tables;
76 struct opp_table **genpd_opp_tables;
77 u32 versions;
78 const struct qcom_cpufreq_match_data *data;
79 @@ -62,6 +64,84 @@ struct qcom_cpufreq_drv {
80
81 static struct platform_device *cpufreq_dt_pdev, *cpufreq_pdev;
82
83 +static void get_krait_bin_format_a(struct device *cpu_dev,
84 + int *speed, int *pvs, int *pvs_ver,
85 + struct nvmem_cell *pvs_nvmem, u8 *buf)
86 +{
87 + u32 pte_efuse;
88 +
89 + pte_efuse = *((u32 *)buf);
90 +
91 + *speed = pte_efuse & 0xf;
92 + if (*speed == 0xf)
93 + *speed = (pte_efuse >> 4) & 0xf;
94 +
95 + if (*speed == 0xf) {
96 + *speed = 0;
97 + dev_warn(cpu_dev, "Speed bin: Defaulting to %d\n", *speed);
98 + } else {
99 + dev_dbg(cpu_dev, "Speed bin: %d\n", *speed);
100 + }
101 +
102 + *pvs = (pte_efuse >> 10) & 0x7;
103 + if (*pvs == 0x7)
104 + *pvs = (pte_efuse >> 13) & 0x7;
105 +
106 + if (*pvs == 0x7) {
107 + *pvs = 0;
108 + dev_warn(cpu_dev, "PVS bin: Defaulting to %d\n", *pvs);
109 + } else {
110 + dev_dbg(cpu_dev, "PVS bin: %d\n", *pvs);
111 + }
112 +}
113 +
114 +static void get_krait_bin_format_b(struct device *cpu_dev,
115 + int *speed, int *pvs, int *pvs_ver,
116 + struct nvmem_cell *pvs_nvmem, u8 *buf)
117 +{
118 + u32 pte_efuse, redundant_sel;
119 +
120 + pte_efuse = *((u32 *)buf);
121 + redundant_sel = (pte_efuse >> 24) & 0x7;
122 +
123 + *pvs_ver = (pte_efuse >> 4) & 0x3;
124 +
125 + switch (redundant_sel) {
126 + case 1:
127 + *pvs = ((pte_efuse >> 28) & 0x8) | ((pte_efuse >> 6) & 0x7);
128 + *speed = (pte_efuse >> 27) & 0xf;
129 + break;
130 + case 2:
131 + *pvs = (pte_efuse >> 27) & 0xf;
132 + *speed = pte_efuse & 0x7;
133 + break;
134 + default:
135 + /* 4 bits of PVS are in efuse register bits 31, 8-6. */
136 + *pvs = ((pte_efuse >> 28) & 0x8) | ((pte_efuse >> 6) & 0x7);
137 + *speed = pte_efuse & 0x7;
138 + }
139 +
140 + /* Check SPEED_BIN_BLOW_STATUS */
141 + if (pte_efuse & BIT(3)) {
142 + dev_dbg(cpu_dev, "Speed bin: %d\n", *speed);
143 + } else {
144 + dev_warn(cpu_dev, "Speed bin not set. Defaulting to 0!\n");
145 + *speed = 0;
146 + }
147 +
148 + /* Check PVS_BLOW_STATUS */
149 + pte_efuse = *(((u32 *)buf) + 4);
150 + pte_efuse &= BIT(21);
151 + if (pte_efuse) {
152 + dev_dbg(cpu_dev, "PVS bin: %d\n", *pvs);
153 + } else {
154 + dev_warn(cpu_dev, "PVS bin not set. Defaulting to 0!\n");
155 + *pvs = 0;
156 + }
157 +
158 + dev_dbg(cpu_dev, "PVS version: %d\n", *pvs_ver);
159 +}
160 +
161 static enum _msm8996_version qcom_cpufreq_get_msm_id(void)
162 {
163 size_t len;
164 @@ -93,11 +173,13 @@ static enum _msm8996_version qcom_cpufre
165
166 static int qcom_cpufreq_kryo_name_version(struct device *cpu_dev,
167 struct nvmem_cell *speedbin_nvmem,
168 + char **pvs_name,
169 struct qcom_cpufreq_drv *drv)
170 {
171 size_t len;
172 u8 *speedbin;
173 enum _msm8996_version msm8996_version;
174 + *pvs_name = NULL;
175
176 msm8996_version = qcom_cpufreq_get_msm_id();
177 if (NUM_OF_MSM8996_VERSIONS == msm8996_version) {
178 @@ -125,10 +207,51 @@ static int qcom_cpufreq_kryo_name_versio
179 return 0;
180 }
181
182 +static int qcom_cpufreq_krait_name_version(struct device *cpu_dev,
183 + struct nvmem_cell *speedbin_nvmem,
184 + char **pvs_name,
185 + struct qcom_cpufreq_drv *drv)
186 +{
187 + int speed = 0, pvs = 0, pvs_ver = 0;
188 + u8 *speedbin;
189 + size_t len;
190 +
191 + speedbin = nvmem_cell_read(speedbin_nvmem, &len);
192 +
193 + if (IS_ERR(speedbin))
194 + return PTR_ERR(speedbin);
195 +
196 + switch (len) {
197 + case 4:
198 + get_krait_bin_format_a(cpu_dev, &speed, &pvs, &pvs_ver,
199 + speedbin_nvmem, speedbin);
200 + break;
201 + case 8:
202 + get_krait_bin_format_b(cpu_dev, &speed, &pvs, &pvs_ver,
203 + speedbin_nvmem, speedbin);
204 + break;
205 + default:
206 + dev_err(cpu_dev, "Unable to read nvmem data. Defaulting to 0!\n");
207 + return -ENODEV;
208 + }
209 +
210 + snprintf(*pvs_name, sizeof("speedXX-pvsXX-vXX"), "speed%d-pvs%d-v%d",
211 + speed, pvs, pvs_ver);
212 +
213 + drv->versions = (1 << speed);
214 +
215 + kfree(speedbin);
216 + return 0;
217 +}
218 +
219 static const struct qcom_cpufreq_match_data match_data_kryo = {
220 .get_version = qcom_cpufreq_kryo_name_version,
221 };
222
223 +static const struct qcom_cpufreq_match_data match_data_krait = {
224 + .get_version = qcom_cpufreq_krait_name_version,
225 +};
226 +
227 static const char *qcs404_genpd_names[] = { "cpr", NULL };
228
229 static const struct qcom_cpufreq_match_data match_data_qcs404 = {
230 @@ -141,6 +264,7 @@ static int qcom_cpufreq_probe(struct pla
231 struct nvmem_cell *speedbin_nvmem;
232 struct device_node *np;
233 struct device *cpu_dev;
234 + char *pvs_name = "speedXX-pvsXX-vXX";
235 unsigned cpu;
236 const struct of_device_id *match;
237 int ret;
238 @@ -153,7 +277,7 @@ static int qcom_cpufreq_probe(struct pla
239 if (!np)
240 return -ENOENT;
241
242 - ret = of_device_is_compatible(np, "operating-points-v2-kryo-cpu");
243 + ret = of_device_is_compatible(np, "operating-points-v2-qcom-cpu");
244 if (!ret) {
245 of_node_put(np);
246 return -ENOENT;
247 @@ -181,7 +305,8 @@ static int qcom_cpufreq_probe(struct pla
248 goto free_drv;
249 }
250
251 - ret = drv->data->get_version(cpu_dev, speedbin_nvmem, drv);
252 + ret = drv->data->get_version(cpu_dev,
253 + speedbin_nvmem, &pvs_name, drv);
254 if (ret) {
255 nvmem_cell_put(speedbin_nvmem);
256 goto free_drv;
257 @@ -190,12 +315,20 @@ static int qcom_cpufreq_probe(struct pla
258 }
259 of_node_put(np);
260
261 - drv->opp_tables = kcalloc(num_possible_cpus(), sizeof(*drv->opp_tables),
262 + drv->names_opp_tables = kcalloc(num_possible_cpus(),
263 + sizeof(*drv->names_opp_tables),
264 GFP_KERNEL);
265 - if (!drv->opp_tables) {
266 + if (!drv->names_opp_tables) {
267 ret = -ENOMEM;
268 goto free_drv;
269 }
270 + drv->hw_opp_tables = kcalloc(num_possible_cpus(),
271 + sizeof(*drv->hw_opp_tables),
272 + GFP_KERNEL);
273 + if (!drv->hw_opp_tables) {
274 + ret = -ENOMEM;
275 + goto free_opp_names;
276 + }
277
278 drv->genpd_opp_tables = kcalloc(num_possible_cpus(),
279 sizeof(*drv->genpd_opp_tables),
280 @@ -213,11 +346,23 @@ static int qcom_cpufreq_probe(struct pla
281 }
282
283 if (drv->data->get_version) {
284 - drv->opp_tables[cpu] =
285 - dev_pm_opp_set_supported_hw(cpu_dev,
286 - &drv->versions, 1);
287 - if (IS_ERR(drv->opp_tables[cpu])) {
288 - ret = PTR_ERR(drv->opp_tables[cpu]);
289 +
290 + if (pvs_name) {
291 + drv->names_opp_tables[cpu] = dev_pm_opp_set_prop_name(
292 + cpu_dev,
293 + pvs_name);
294 + if (IS_ERR(drv->names_opp_tables[cpu])) {
295 + ret = PTR_ERR(drv->names_opp_tables[cpu]);
296 + dev_err(cpu_dev, "Failed to add OPP name %s\n",
297 + pvs_name);
298 + goto free_opp;
299 + }
300 + }
301 +
302 + drv->hw_opp_tables[cpu] = dev_pm_opp_set_supported_hw(
303 + cpu_dev, &drv->versions, 1);
304 + if (IS_ERR(drv->hw_opp_tables[cpu])) {
305 + ret = PTR_ERR(drv->hw_opp_tables[cpu]);
306 dev_err(cpu_dev,
307 "Failed to set supported hardware\n");
308 goto free_genpd_opp;
309 @@ -259,11 +404,18 @@ free_genpd_opp:
310 kfree(drv->genpd_opp_tables);
311 free_opp:
312 for_each_possible_cpu(cpu) {
313 - if (IS_ERR_OR_NULL(drv->opp_tables[cpu]))
314 + if (IS_ERR_OR_NULL(drv->names_opp_tables[cpu]))
315 + break;
316 + dev_pm_opp_put_prop_name(drv->names_opp_tables[cpu]);
317 + }
318 + for_each_possible_cpu(cpu) {
319 + if (IS_ERR_OR_NULL(drv->hw_opp_tables[cpu]))
320 break;
321 - dev_pm_opp_put_supported_hw(drv->opp_tables[cpu]);
322 + dev_pm_opp_put_supported_hw(drv->hw_opp_tables[cpu]);
323 }
324 - kfree(drv->opp_tables);
325 + kfree(drv->hw_opp_tables);
326 +free_opp_names:
327 + kfree(drv->names_opp_tables);
328 free_drv:
329 kfree(drv);
330
331 @@ -278,13 +430,16 @@ static int qcom_cpufreq_remove(struct pl
332 platform_device_unregister(cpufreq_dt_pdev);
333
334 for_each_possible_cpu(cpu) {
335 - if (drv->opp_tables[cpu])
336 - dev_pm_opp_put_supported_hw(drv->opp_tables[cpu]);
337 + if (drv->names_opp_tables[cpu])
338 + dev_pm_opp_put_supported_hw(drv->names_opp_tables[cpu]);
339 + if (drv->hw_opp_tables[cpu])
340 + dev_pm_opp_put_supported_hw(drv->hw_opp_tables[cpu]);
341 if (drv->genpd_opp_tables[cpu])
342 dev_pm_opp_detach_genpd(drv->genpd_opp_tables[cpu]);
343 }
344
345 - kfree(drv->opp_tables);
346 + kfree(drv->names_opp_tables);
347 + kfree(drv->hw_opp_tables);
348 kfree(drv->genpd_opp_tables);
349 kfree(drv);
350
351 @@ -303,6 +458,10 @@ static const struct of_device_id qcom_cp
352 { .compatible = "qcom,apq8096", .data = &match_data_kryo },
353 { .compatible = "qcom,msm8996", .data = &match_data_kryo },
354 { .compatible = "qcom,qcs404", .data = &match_data_qcs404 },
355 + { .compatible = "qcom,ipq8064", .data = &match_data_krait },
356 + { .compatible = "qcom,apq8064", .data = &match_data_krait },
357 + { .compatible = "qcom,msm8974", .data = &match_data_krait },
358 + { .compatible = "qcom,msm8960", .data = &match_data_krait },
359 {},
360 };
361