Skip to content

Commit a8811ec

Browse files
Ansuelvireshk
authored andcommitted
cpufreq: qcom: Add support for krait based socs
In Certain QCOM SoCs like ipq8064, apq8064, msm8960, msm8974 that has KRAIT processors the voltage/current value of each OPP varies based on the silicon variant in use. The required OPP related data is determined based on the efuse value. This is similar to the existing code for kryo cores. So adding support for krait cores here. Signed-off-by: Sricharan R <[email protected]> Signed-off-by: Ansuel Smith <[email protected]> Signed-off-by: Viresh Kumar <[email protected]>
1 parent 74a189e commit a8811ec

File tree

4 files changed

+183
-18
lines changed

4 files changed

+183
-18
lines changed

Documentation/devicetree/bindings/opp/qcom-nvmem-cpufreq.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ In 'cpu' nodes:
1919

2020
In 'operating-points-v2' table:
2121
- compatible: Should be
22-
- 'operating-points-v2-kryo-cpu' for apq8096 and msm8996.
22+
- 'operating-points-v2-kryo-cpu' for apq8096, msm8996, msm8974,
23+
apq8064, ipq8064, msm8960 and ipq8074.
2324

2425
Optional properties:
2526
--------------------

drivers/cpufreq/Kconfig.arm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ config ARM_OMAP2PLUS_CPUFREQ
128128

129129
config ARM_QCOM_CPUFREQ_NVMEM
130130
tristate "Qualcomm nvmem based CPUFreq"
131-
depends on ARM64
131+
depends on ARCH_QCOM
132132
depends on QCOM_QFPROM
133133
depends on QCOM_SMEM
134134
select PM_OPP

drivers/cpufreq/cpufreq-dt-platdev.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,11 @@ static const struct of_device_id blacklist[] __initconst = {
141141
{ .compatible = "ti,dra7", },
142142
{ .compatible = "ti,omap3", },
143143

144+
{ .compatible = "qcom,ipq8064", },
145+
{ .compatible = "qcom,apq8064", },
146+
{ .compatible = "qcom,msm8974", },
147+
{ .compatible = "qcom,msm8960", },
148+
144149
{ }
145150
};
146151

drivers/cpufreq/qcom-cpufreq-nvmem.c

Lines changed: 175 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -49,19 +49,99 @@ struct qcom_cpufreq_drv;
4949
struct qcom_cpufreq_match_data {
5050
int (*get_version)(struct device *cpu_dev,
5151
struct nvmem_cell *speedbin_nvmem,
52+
char **pvs_name,
5253
struct qcom_cpufreq_drv *drv);
5354
const char **genpd_names;
5455
};
5556

5657
struct qcom_cpufreq_drv {
57-
struct opp_table **opp_tables;
58+
struct opp_table **names_opp_tables;
59+
struct opp_table **hw_opp_tables;
5860
struct opp_table **genpd_opp_tables;
5961
u32 versions;
6062
const struct qcom_cpufreq_match_data *data;
6163
};
6264

6365
static struct platform_device *cpufreq_dt_pdev, *cpufreq_pdev;
6466

67+
static void get_krait_bin_format_a(struct device *cpu_dev,
68+
int *speed, int *pvs, int *pvs_ver,
69+
struct nvmem_cell *pvs_nvmem, u8 *buf)
70+
{
71+
u32 pte_efuse;
72+
73+
pte_efuse = *((u32 *)buf);
74+
75+
*speed = pte_efuse & 0xf;
76+
if (*speed == 0xf)
77+
*speed = (pte_efuse >> 4) & 0xf;
78+
79+
if (*speed == 0xf) {
80+
*speed = 0;
81+
dev_warn(cpu_dev, "Speed bin: Defaulting to %d\n", *speed);
82+
} else {
83+
dev_dbg(cpu_dev, "Speed bin: %d\n", *speed);
84+
}
85+
86+
*pvs = (pte_efuse >> 10) & 0x7;
87+
if (*pvs == 0x7)
88+
*pvs = (pte_efuse >> 13) & 0x7;
89+
90+
if (*pvs == 0x7) {
91+
*pvs = 0;
92+
dev_warn(cpu_dev, "PVS bin: Defaulting to %d\n", *pvs);
93+
} else {
94+
dev_dbg(cpu_dev, "PVS bin: %d\n", *pvs);
95+
}
96+
}
97+
98+
static void get_krait_bin_format_b(struct device *cpu_dev,
99+
int *speed, int *pvs, int *pvs_ver,
100+
struct nvmem_cell *pvs_nvmem, u8 *buf)
101+
{
102+
u32 pte_efuse, redundant_sel;
103+
104+
pte_efuse = *((u32 *)buf);
105+
redundant_sel = (pte_efuse >> 24) & 0x7;
106+
107+
*pvs_ver = (pte_efuse >> 4) & 0x3;
108+
109+
switch (redundant_sel) {
110+
case 1:
111+
*pvs = ((pte_efuse >> 28) & 0x8) | ((pte_efuse >> 6) & 0x7);
112+
*speed = (pte_efuse >> 27) & 0xf;
113+
break;
114+
case 2:
115+
*pvs = (pte_efuse >> 27) & 0xf;
116+
*speed = pte_efuse & 0x7;
117+
break;
118+
default:
119+
/* 4 bits of PVS are in efuse register bits 31, 8-6. */
120+
*pvs = ((pte_efuse >> 28) & 0x8) | ((pte_efuse >> 6) & 0x7);
121+
*speed = pte_efuse & 0x7;
122+
}
123+
124+
/* Check SPEED_BIN_BLOW_STATUS */
125+
if (pte_efuse & BIT(3)) {
126+
dev_dbg(cpu_dev, "Speed bin: %d\n", *speed);
127+
} else {
128+
dev_warn(cpu_dev, "Speed bin not set. Defaulting to 0!\n");
129+
*speed = 0;
130+
}
131+
132+
/* Check PVS_BLOW_STATUS */
133+
pte_efuse = *(((u32 *)buf) + 4);
134+
pte_efuse &= BIT(21);
135+
if (pte_efuse) {
136+
dev_dbg(cpu_dev, "PVS bin: %d\n", *pvs);
137+
} else {
138+
dev_warn(cpu_dev, "PVS bin not set. Defaulting to 0!\n");
139+
*pvs = 0;
140+
}
141+
142+
dev_dbg(cpu_dev, "PVS version: %d\n", *pvs_ver);
143+
}
144+
65145
static enum _msm8996_version qcom_cpufreq_get_msm_id(void)
66146
{
67147
size_t len;
@@ -93,11 +173,13 @@ static enum _msm8996_version qcom_cpufreq_get_msm_id(void)
93173

94174
static int qcom_cpufreq_kryo_name_version(struct device *cpu_dev,
95175
struct nvmem_cell *speedbin_nvmem,
176+
char **pvs_name,
96177
struct qcom_cpufreq_drv *drv)
97178
{
98179
size_t len;
99180
u8 *speedbin;
100181
enum _msm8996_version msm8996_version;
182+
*pvs_name = NULL;
101183

102184
msm8996_version = qcom_cpufreq_get_msm_id();
103185
if (NUM_OF_MSM8996_VERSIONS == msm8996_version) {
@@ -125,10 +207,51 @@ static int qcom_cpufreq_kryo_name_version(struct device *cpu_dev,
125207
return 0;
126208
}
127209

210+
static int qcom_cpufreq_krait_name_version(struct device *cpu_dev,
211+
struct nvmem_cell *speedbin_nvmem,
212+
char **pvs_name,
213+
struct qcom_cpufreq_drv *drv)
214+
{
215+
int speed = 0, pvs = 0, pvs_ver = 0;
216+
u8 *speedbin;
217+
size_t len;
218+
219+
speedbin = nvmem_cell_read(speedbin_nvmem, &len);
220+
221+
if (IS_ERR(speedbin))
222+
return PTR_ERR(speedbin);
223+
224+
switch (len) {
225+
case 4:
226+
get_krait_bin_format_a(cpu_dev, &speed, &pvs, &pvs_ver,
227+
speedbin_nvmem, speedbin);
228+
break;
229+
case 8:
230+
get_krait_bin_format_b(cpu_dev, &speed, &pvs, &pvs_ver,
231+
speedbin_nvmem, speedbin);
232+
break;
233+
default:
234+
dev_err(cpu_dev, "Unable to read nvmem data. Defaulting to 0!\n");
235+
return -ENODEV;
236+
}
237+
238+
snprintf(*pvs_name, sizeof("speedXX-pvsXX-vXX"), "speed%d-pvs%d-v%d",
239+
speed, pvs, pvs_ver);
240+
241+
drv->versions = (1 << speed);
242+
243+
kfree(speedbin);
244+
return 0;
245+
}
246+
128247
static const struct qcom_cpufreq_match_data match_data_kryo = {
129248
.get_version = qcom_cpufreq_kryo_name_version,
130249
};
131250

251+
static const struct qcom_cpufreq_match_data match_data_krait = {
252+
.get_version = qcom_cpufreq_krait_name_version,
253+
};
254+
132255
static const char *qcs404_genpd_names[] = { "cpr", NULL };
133256

134257
static const struct qcom_cpufreq_match_data match_data_qcs404 = {
@@ -141,6 +264,7 @@ static int qcom_cpufreq_probe(struct platform_device *pdev)
141264
struct nvmem_cell *speedbin_nvmem;
142265
struct device_node *np;
143266
struct device *cpu_dev;
267+
char *pvs_name = "speedXX-pvsXX-vXX";
144268
unsigned cpu;
145269
const struct of_device_id *match;
146270
int ret;
@@ -153,7 +277,7 @@ static int qcom_cpufreq_probe(struct platform_device *pdev)
153277
if (!np)
154278
return -ENOENT;
155279

156-
ret = of_device_is_compatible(np, "operating-points-v2-kryo-cpu");
280+
ret = of_device_is_compatible(np, "operating-points-v2-qcom-cpu");
157281
if (!ret) {
158282
of_node_put(np);
159283
return -ENOENT;
@@ -181,7 +305,8 @@ static int qcom_cpufreq_probe(struct platform_device *pdev)
181305
goto free_drv;
182306
}
183307

184-
ret = drv->data->get_version(cpu_dev, speedbin_nvmem, drv);
308+
ret = drv->data->get_version(cpu_dev,
309+
speedbin_nvmem, &pvs_name, drv);
185310
if (ret) {
186311
nvmem_cell_put(speedbin_nvmem);
187312
goto free_drv;
@@ -190,12 +315,20 @@ static int qcom_cpufreq_probe(struct platform_device *pdev)
190315
}
191316
of_node_put(np);
192317

193-
drv->opp_tables = kcalloc(num_possible_cpus(), sizeof(*drv->opp_tables),
318+
drv->names_opp_tables = kcalloc(num_possible_cpus(),
319+
sizeof(*drv->names_opp_tables),
194320
GFP_KERNEL);
195-
if (!drv->opp_tables) {
321+
if (!drv->names_opp_tables) {
196322
ret = -ENOMEM;
197323
goto free_drv;
198324
}
325+
drv->hw_opp_tables = kcalloc(num_possible_cpus(),
326+
sizeof(*drv->hw_opp_tables),
327+
GFP_KERNEL);
328+
if (!drv->hw_opp_tables) {
329+
ret = -ENOMEM;
330+
goto free_opp_names;
331+
}
199332

200333
drv->genpd_opp_tables = kcalloc(num_possible_cpus(),
201334
sizeof(*drv->genpd_opp_tables),
@@ -213,11 +346,23 @@ static int qcom_cpufreq_probe(struct platform_device *pdev)
213346
}
214347

215348
if (drv->data->get_version) {
216-
drv->opp_tables[cpu] =
217-
dev_pm_opp_set_supported_hw(cpu_dev,
218-
&drv->versions, 1);
219-
if (IS_ERR(drv->opp_tables[cpu])) {
220-
ret = PTR_ERR(drv->opp_tables[cpu]);
349+
350+
if (pvs_name) {
351+
drv->names_opp_tables[cpu] = dev_pm_opp_set_prop_name(
352+
cpu_dev,
353+
pvs_name);
354+
if (IS_ERR(drv->names_opp_tables[cpu])) {
355+
ret = PTR_ERR(drv->names_opp_tables[cpu]);
356+
dev_err(cpu_dev, "Failed to add OPP name %s\n",
357+
pvs_name);
358+
goto free_opp;
359+
}
360+
}
361+
362+
drv->hw_opp_tables[cpu] = dev_pm_opp_set_supported_hw(
363+
cpu_dev, &drv->versions, 1);
364+
if (IS_ERR(drv->hw_opp_tables[cpu])) {
365+
ret = PTR_ERR(drv->hw_opp_tables[cpu]);
221366
dev_err(cpu_dev,
222367
"Failed to set supported hardware\n");
223368
goto free_genpd_opp;
@@ -259,11 +404,18 @@ static int qcom_cpufreq_probe(struct platform_device *pdev)
259404
kfree(drv->genpd_opp_tables);
260405
free_opp:
261406
for_each_possible_cpu(cpu) {
262-
if (IS_ERR_OR_NULL(drv->opp_tables[cpu]))
407+
if (IS_ERR_OR_NULL(drv->names_opp_tables[cpu]))
408+
break;
409+
dev_pm_opp_put_prop_name(drv->names_opp_tables[cpu]);
410+
}
411+
for_each_possible_cpu(cpu) {
412+
if (IS_ERR_OR_NULL(drv->hw_opp_tables[cpu]))
263413
break;
264-
dev_pm_opp_put_supported_hw(drv->opp_tables[cpu]);
414+
dev_pm_opp_put_supported_hw(drv->hw_opp_tables[cpu]);
265415
}
266-
kfree(drv->opp_tables);
416+
kfree(drv->hw_opp_tables);
417+
free_opp_names:
418+
kfree(drv->names_opp_tables);
267419
free_drv:
268420
kfree(drv);
269421

@@ -278,13 +430,16 @@ static int qcom_cpufreq_remove(struct platform_device *pdev)
278430
platform_device_unregister(cpufreq_dt_pdev);
279431

280432
for_each_possible_cpu(cpu) {
281-
if (drv->opp_tables[cpu])
282-
dev_pm_opp_put_supported_hw(drv->opp_tables[cpu]);
433+
if (drv->names_opp_tables[cpu])
434+
dev_pm_opp_put_supported_hw(drv->names_opp_tables[cpu]);
435+
if (drv->hw_opp_tables[cpu])
436+
dev_pm_opp_put_supported_hw(drv->hw_opp_tables[cpu]);
283437
if (drv->genpd_opp_tables[cpu])
284438
dev_pm_opp_detach_genpd(drv->genpd_opp_tables[cpu]);
285439
}
286440

287-
kfree(drv->opp_tables);
441+
kfree(drv->names_opp_tables);
442+
kfree(drv->hw_opp_tables);
288443
kfree(drv->genpd_opp_tables);
289444
kfree(drv);
290445

@@ -303,6 +458,10 @@ static const struct of_device_id qcom_cpufreq_match_list[] __initconst = {
303458
{ .compatible = "qcom,apq8096", .data = &match_data_kryo },
304459
{ .compatible = "qcom,msm8996", .data = &match_data_kryo },
305460
{ .compatible = "qcom,qcs404", .data = &match_data_qcs404 },
461+
{ .compatible = "qcom,ipq8064", .data = &match_data_krait },
462+
{ .compatible = "qcom,apq8064", .data = &match_data_krait },
463+
{ .compatible = "qcom,msm8974", .data = &match_data_krait },
464+
{ .compatible = "qcom,msm8960", .data = &match_data_krait },
306465
{},
307466
};
308467

0 commit comments

Comments
 (0)