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
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.
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.
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>
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(-)
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:
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.
36 --- a/drivers/cpufreq/Kconfig.arm
37 +++ b/drivers/cpufreq/Kconfig.arm
38 @@ -135,7 +135,7 @@ config ARM_OMAP2PLUS_CPUFREQ
40 config ARM_QCOM_CPUFREQ_NVMEM
41 tristate "Qualcomm nvmem based CPUFreq"
43 + depends on ARCH_QCOM
44 depends on QCOM_QFPROM
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", },
53 + { .compatible = "qcom,ipq8064", },
54 + { .compatible = "qcom,apq8064", },
55 + { .compatible = "qcom,msm8974", },
56 + { .compatible = "qcom,msm8960", },
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,
68 struct qcom_cpufreq_drv *drv);
69 const char **genpd_names;
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;
78 const struct qcom_cpufreq_match_data *data;
79 @@ -62,6 +64,84 @@ struct qcom_cpufreq_drv {
81 static struct platform_device *cpufreq_dt_pdev, *cpufreq_pdev;
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)
89 + pte_efuse = *((u32 *)buf);
91 + *speed = pte_efuse & 0xf;
93 + *speed = (pte_efuse >> 4) & 0xf;
95 + if (*speed == 0xf) {
97 + dev_warn(cpu_dev, "Speed bin: Defaulting to %d\n", *speed);
99 + dev_dbg(cpu_dev, "Speed bin: %d\n", *speed);
102 + *pvs = (pte_efuse >> 10) & 0x7;
104 + *pvs = (pte_efuse >> 13) & 0x7;
108 + dev_warn(cpu_dev, "PVS bin: Defaulting to %d\n", *pvs);
110 + dev_dbg(cpu_dev, "PVS bin: %d\n", *pvs);
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)
118 + u32 pte_efuse, redundant_sel;
120 + pte_efuse = *((u32 *)buf);
121 + redundant_sel = (pte_efuse >> 24) & 0x7;
123 + *pvs_ver = (pte_efuse >> 4) & 0x3;
125 + switch (redundant_sel) {
127 + *pvs = ((pte_efuse >> 28) & 0x8) | ((pte_efuse >> 6) & 0x7);
128 + *speed = (pte_efuse >> 27) & 0xf;
131 + *pvs = (pte_efuse >> 27) & 0xf;
132 + *speed = pte_efuse & 0x7;
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;
140 + /* Check SPEED_BIN_BLOW_STATUS */
141 + if (pte_efuse & BIT(3)) {
142 + dev_dbg(cpu_dev, "Speed bin: %d\n", *speed);
144 + dev_warn(cpu_dev, "Speed bin not set. Defaulting to 0!\n");
148 + /* Check PVS_BLOW_STATUS */
149 + pte_efuse = *(((u32 *)buf) + 4);
150 + pte_efuse &= BIT(21);
152 + dev_dbg(cpu_dev, "PVS bin: %d\n", *pvs);
154 + dev_warn(cpu_dev, "PVS bin not set. Defaulting to 0!\n");
158 + dev_dbg(cpu_dev, "PVS version: %d\n", *pvs_ver);
161 static enum _msm8996_version qcom_cpufreq_get_msm_id(void)
164 @@ -93,11 +173,13 @@ static enum _msm8996_version qcom_cpufre
166 static int qcom_cpufreq_kryo_name_version(struct device *cpu_dev,
167 struct nvmem_cell *speedbin_nvmem,
169 struct qcom_cpufreq_drv *drv)
173 enum _msm8996_version msm8996_version;
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
182 +static int qcom_cpufreq_krait_name_version(struct device *cpu_dev,
183 + struct nvmem_cell *speedbin_nvmem,
185 + struct qcom_cpufreq_drv *drv)
187 + int speed = 0, pvs = 0, pvs_ver = 0;
191 + speedbin = nvmem_cell_read(speedbin_nvmem, &len);
193 + if (IS_ERR(speedbin))
194 + return PTR_ERR(speedbin);
198 + get_krait_bin_format_a(cpu_dev, &speed, &pvs, &pvs_ver,
199 + speedbin_nvmem, speedbin);
202 + get_krait_bin_format_b(cpu_dev, &speed, &pvs, &pvs_ver,
203 + speedbin_nvmem, speedbin);
206 + dev_err(cpu_dev, "Unable to read nvmem data. Defaulting to 0!\n");
210 + snprintf(*pvs_name, sizeof("speedXX-pvsXX-vXX"), "speed%d-pvs%d-v%d",
211 + speed, pvs, pvs_ver);
213 + drv->versions = (1 << speed);
219 static const struct qcom_cpufreq_match_data match_data_kryo = {
220 .get_version = qcom_cpufreq_kryo_name_version,
223 +static const struct qcom_cpufreq_match_data match_data_krait = {
224 + .get_version = qcom_cpufreq_krait_name_version,
227 static const char *qcs404_genpd_names[] = { "cpr", NULL };
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";
236 const struct of_device_id *match;
238 @@ -153,7 +277,7 @@ static int qcom_cpufreq_probe(struct pla
242 - ret = of_device_is_compatible(np, "operating-points-v2-kryo-cpu");
243 + ret = of_device_is_compatible(np, "operating-points-v2-qcom-cpu");
247 @@ -181,7 +305,8 @@ static int qcom_cpufreq_probe(struct pla
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);
255 nvmem_cell_put(speedbin_nvmem);
257 @@ -190,12 +315,20 @@ static int qcom_cpufreq_probe(struct pla
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),
265 - if (!drv->opp_tables) {
266 + if (!drv->names_opp_tables) {
270 + drv->hw_opp_tables = kcalloc(num_possible_cpus(),
271 + sizeof(*drv->hw_opp_tables),
273 + if (!drv->hw_opp_tables) {
275 + goto free_opp_names;
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
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]);
291 + drv->names_opp_tables[cpu] = dev_pm_opp_set_prop_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",
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]);
307 "Failed to set supported hardware\n");
309 @@ -259,11 +404,18 @@ free_genpd_opp:
310 kfree(drv->genpd_opp_tables);
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]))
316 + dev_pm_opp_put_prop_name(drv->names_opp_tables[cpu]);
318 + for_each_possible_cpu(cpu) {
319 + if (IS_ERR_OR_NULL(drv->hw_opp_tables[cpu]))
321 - dev_pm_opp_put_supported_hw(drv->opp_tables[cpu]);
322 + dev_pm_opp_put_supported_hw(drv->hw_opp_tables[cpu]);
324 - kfree(drv->opp_tables);
325 + kfree(drv->hw_opp_tables);
327 + kfree(drv->names_opp_tables);
331 @@ -278,13 +430,16 @@ static int qcom_cpufreq_remove(struct pl
332 platform_device_unregister(cpufreq_dt_pdev);
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]);
345 - kfree(drv->opp_tables);
346 + kfree(drv->names_opp_tables);
347 + kfree(drv->hw_opp_tables);
348 kfree(drv->genpd_opp_tables);
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 },