1 From 7d12709544b8b3fb9727a34a664b8380e1e3493a Mon Sep 17 00:00:00 2001
2 From: Sricharan R <sricharan@codeaurora.org>
3 Date: Thu, 25 Jul 2019 12:41:31 +0200
4 Subject: [PATCH] cpufreq: qcom: Re-organise kryo cpufreq to use it for other
7 The kryo cpufreq driver reads the nvmem cell and uses that data to
8 populate the opps. There are other qcom cpufreq socs like krait which
9 does similar thing. Except for the interpretation of the read data,
10 rest of the driver is same for both the cases. So pull the common things
13 Signed-off-by: Sricharan R <sricharan@codeaurora.org>
14 [niklas.cassel@linaro.org: split dt-binding into a separate patch and
15 do not rename the compatible string. Update MAINTAINERS file.]
16 Signed-off-by: Niklas Cassel <niklas.cassel@linaro.org>
17 Reviewed-by: Ilia Lin <ilia.lin@kernel.org>
18 Reviewed-by: Stephen Boyd <sboyd@kernel.org>
19 Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
22 drivers/cpufreq/Kconfig.arm | 4 +-
23 drivers/cpufreq/Makefile | 2 +-
24 ...om-cpufreq-kryo.c => qcom-cpufreq-nvmem.c} | 122 +++++++++++-------
25 4 files changed, 78 insertions(+), 54 deletions(-)
26 rename drivers/cpufreq/{qcom-cpufreq-kryo.c => qcom-cpufreq-nvmem.c} (69%)
28 --- a/drivers/cpufreq/Kconfig.arm
29 +++ b/drivers/cpufreq/Kconfig.arm
30 @@ -110,8 +110,8 @@ config ARM_OMAP2PLUS_CPUFREQ
31 depends on ARCH_OMAP2PLUS
32 default ARCH_OMAP2PLUS
34 -config ARM_QCOM_CPUFREQ_KRYO
35 - tristate "Qualcomm Kryo based CPUFreq"
36 +config ARM_QCOM_CPUFREQ_NVMEM
37 + tristate "Qualcomm nvmem based CPUFreq"
39 depends on QCOM_QFPROM
41 --- a/drivers/cpufreq/Makefile
42 +++ b/drivers/cpufreq/Makefile
43 @@ -64,7 +64,7 @@ obj-$(CONFIG_MACH_MVEBU_V7) += mvebu-cp
44 obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ) += omap-cpufreq.o
45 obj-$(CONFIG_ARM_PXA2xx_CPUFREQ) += pxa2xx-cpufreq.o
46 obj-$(CONFIG_PXA3xx) += pxa3xx-cpufreq.o
47 -obj-$(CONFIG_ARM_QCOM_CPUFREQ_KRYO) += qcom-cpufreq-kryo.o
48 +obj-$(CONFIG_ARM_QCOM_CPUFREQ_NVMEM) += qcom-cpufreq-nvmem.o
49 obj-$(CONFIG_ARM_S3C2410_CPUFREQ) += s3c2410-cpufreq.o
50 obj-$(CONFIG_ARM_S3C2412_CPUFREQ) += s3c2412-cpufreq.o
51 obj-$(CONFIG_ARM_S3C2416_CPUFREQ) += s3c2416-cpufreq.o
52 --- a/drivers/cpufreq/qcom-cpufreq-kryo.c
55 -// SPDX-License-Identifier: GPL-2.0
57 - * Copyright (c) 2018, The Linux Foundation. All rights reserved.
61 - * In Certain QCOM SoCs like apq8096 and msm8996 that have KRYO processors,
62 - * the CPU frequency subset and voltage value of each OPP varies
63 - * based on the silicon variant in use. Qualcomm Process Voltage Scaling Tables
64 - * defines the voltage and frequency value based on the msm-id in SMEM
65 - * and speedbin blown in the efuse combination.
66 - * The qcom-cpufreq-kryo driver reads the msm-id and efuse value from the SoC
67 - * to provide the OPP framework with required information.
68 - * This is used to determine the voltage and frequency value for each OPP of
69 - * operating-points-v2 table when it is parsed by the OPP framework.
72 -#include <linux/cpu.h>
73 -#include <linux/err.h>
74 -#include <linux/init.h>
75 -#include <linux/kernel.h>
76 -#include <linux/module.h>
77 -#include <linux/nvmem-consumer.h>
78 -#include <linux/of.h>
79 -#include <linux/platform_device.h>
80 -#include <linux/pm_opp.h>
81 -#include <linux/slab.h>
82 -#include <linux/soc/qcom/smem.h>
84 -#define MSM_ID_SMEM 137
88 - APQ8096V3 = 0x123ul,
89 - MSM8996SG = 0x131ul,
90 - APQ8096SG = 0x138ul,
93 -enum _msm8996_version {
96 - NUM_OF_MSM8996_VERSIONS,
99 -static struct platform_device *cpufreq_dt_pdev, *kryo_cpufreq_pdev;
101 -static enum _msm8996_version qcom_cpufreq_kryo_get_msm_id(void)
105 - enum _msm8996_version version;
107 - msm_id = qcom_smem_get(QCOM_SMEM_HOST_ANY, MSM_ID_SMEM, &len);
108 - if (IS_ERR(msm_id))
109 - return NUM_OF_MSM8996_VERSIONS;
111 - /* The first 4 bytes are format, next to them is the actual msm-id */
114 - switch ((enum _msm_id)*msm_id) {
117 - version = MSM8996_V3;
121 - version = MSM8996_SG;
124 - version = NUM_OF_MSM8996_VERSIONS;
130 -static int qcom_cpufreq_kryo_probe(struct platform_device *pdev)
132 - struct opp_table **opp_tables;
133 - enum _msm8996_version msm8996_version;
134 - struct nvmem_cell *speedbin_nvmem;
135 - struct device_node *np;
136 - struct device *cpu_dev;
143 - cpu_dev = get_cpu_device(0);
147 - msm8996_version = qcom_cpufreq_kryo_get_msm_id();
148 - if (NUM_OF_MSM8996_VERSIONS == msm8996_version) {
149 - dev_err(cpu_dev, "Not Snapdragon 820/821!");
153 - np = dev_pm_opp_of_get_opp_desc_node(cpu_dev);
157 - ret = of_device_is_compatible(np, "operating-points-v2-kryo-cpu");
163 - speedbin_nvmem = of_nvmem_cell_get(np, NULL);
165 - if (IS_ERR(speedbin_nvmem)) {
166 - if (PTR_ERR(speedbin_nvmem) != -EPROBE_DEFER)
167 - dev_err(cpu_dev, "Could not get nvmem cell: %ld\n",
168 - PTR_ERR(speedbin_nvmem));
169 - return PTR_ERR(speedbin_nvmem);
172 - speedbin = nvmem_cell_read(speedbin_nvmem, &len);
173 - nvmem_cell_put(speedbin_nvmem);
174 - if (IS_ERR(speedbin))
175 - return PTR_ERR(speedbin);
177 - switch (msm8996_version) {
179 - versions = 1 << (unsigned int)(*speedbin);
182 - versions = 1 << ((unsigned int)(*speedbin) + 4);
190 - opp_tables = kcalloc(num_possible_cpus(), sizeof(*opp_tables), GFP_KERNEL);
194 - for_each_possible_cpu(cpu) {
195 - cpu_dev = get_cpu_device(cpu);
196 - if (NULL == cpu_dev) {
201 - opp_tables[cpu] = dev_pm_opp_set_supported_hw(cpu_dev,
203 - if (IS_ERR(opp_tables[cpu])) {
204 - ret = PTR_ERR(opp_tables[cpu]);
205 - dev_err(cpu_dev, "Failed to set supported hardware\n");
210 - cpufreq_dt_pdev = platform_device_register_simple("cpufreq-dt", -1,
212 - if (!IS_ERR(cpufreq_dt_pdev)) {
213 - platform_set_drvdata(pdev, opp_tables);
217 - ret = PTR_ERR(cpufreq_dt_pdev);
218 - dev_err(cpu_dev, "Failed to register platform device\n");
221 - for_each_possible_cpu(cpu) {
222 - if (IS_ERR_OR_NULL(opp_tables[cpu]))
224 - dev_pm_opp_put_supported_hw(opp_tables[cpu]);
231 -static int qcom_cpufreq_kryo_remove(struct platform_device *pdev)
233 - struct opp_table **opp_tables = platform_get_drvdata(pdev);
236 - platform_device_unregister(cpufreq_dt_pdev);
238 - for_each_possible_cpu(cpu)
239 - dev_pm_opp_put_supported_hw(opp_tables[cpu]);
246 -static struct platform_driver qcom_cpufreq_kryo_driver = {
247 - .probe = qcom_cpufreq_kryo_probe,
248 - .remove = qcom_cpufreq_kryo_remove,
250 - .name = "qcom-cpufreq-kryo",
254 -static const struct of_device_id qcom_cpufreq_kryo_match_list[] __initconst = {
255 - { .compatible = "qcom,apq8096", },
256 - { .compatible = "qcom,msm8996", },
261 - * Since the driver depends on smem and nvmem drivers, which may
262 - * return EPROBE_DEFER, all the real activity is done in the probe,
263 - * which may be defered as well. The init here is only registering
264 - * the driver and the platform device.
266 -static int __init qcom_cpufreq_kryo_init(void)
268 - struct device_node *np = of_find_node_by_path("/");
269 - const struct of_device_id *match;
275 - match = of_match_node(qcom_cpufreq_kryo_match_list, np);
280 - ret = platform_driver_register(&qcom_cpufreq_kryo_driver);
281 - if (unlikely(ret < 0))
284 - kryo_cpufreq_pdev = platform_device_register_simple(
285 - "qcom-cpufreq-kryo", -1, NULL, 0);
286 - ret = PTR_ERR_OR_ZERO(kryo_cpufreq_pdev);
290 - platform_driver_unregister(&qcom_cpufreq_kryo_driver);
293 -module_init(qcom_cpufreq_kryo_init);
295 -static void __exit qcom_cpufreq_kryo_exit(void)
297 - platform_device_unregister(kryo_cpufreq_pdev);
298 - platform_driver_unregister(&qcom_cpufreq_kryo_driver);
300 -module_exit(qcom_cpufreq_kryo_exit);
302 -MODULE_DESCRIPTION("Qualcomm Technologies, Inc. Kryo CPUfreq driver");
303 -MODULE_LICENSE("GPL v2");
305 +++ b/drivers/cpufreq/qcom-cpufreq-nvmem.c
307 +// SPDX-License-Identifier: GPL-2.0
309 + * Copyright (c) 2018, The Linux Foundation. All rights reserved.
313 + * In Certain QCOM SoCs like apq8096 and msm8996 that have KRYO processors,
314 + * the CPU frequency subset and voltage value of each OPP varies
315 + * based on the silicon variant in use. Qualcomm Process Voltage Scaling Tables
316 + * defines the voltage and frequency value based on the msm-id in SMEM
317 + * and speedbin blown in the efuse combination.
318 + * The qcom-cpufreq-nvmem driver reads the msm-id and efuse value from the SoC
319 + * to provide the OPP framework with required information.
320 + * This is used to determine the voltage and frequency value for each OPP of
321 + * operating-points-v2 table when it is parsed by the OPP framework.
324 +#include <linux/cpu.h>
325 +#include <linux/err.h>
326 +#include <linux/init.h>
327 +#include <linux/kernel.h>
328 +#include <linux/module.h>
329 +#include <linux/nvmem-consumer.h>
330 +#include <linux/of.h>
331 +#include <linux/of_device.h>
332 +#include <linux/platform_device.h>
333 +#include <linux/pm_opp.h>
334 +#include <linux/slab.h>
335 +#include <linux/soc/qcom/smem.h>
337 +#define MSM_ID_SMEM 137
340 + MSM8996V3 = 0xF6ul,
341 + APQ8096V3 = 0x123ul,
342 + MSM8996SG = 0x131ul,
343 + APQ8096SG = 0x138ul,
346 +enum _msm8996_version {
349 + NUM_OF_MSM8996_VERSIONS,
352 +static struct platform_device *cpufreq_dt_pdev, *cpufreq_pdev;
354 +static enum _msm8996_version qcom_cpufreq_get_msm_id(void)
358 + enum _msm8996_version version;
360 + msm_id = qcom_smem_get(QCOM_SMEM_HOST_ANY, MSM_ID_SMEM, &len);
361 + if (IS_ERR(msm_id))
362 + return NUM_OF_MSM8996_VERSIONS;
364 + /* The first 4 bytes are format, next to them is the actual msm-id */
367 + switch ((enum _msm_id)*msm_id) {
370 + version = MSM8996_V3;
374 + version = MSM8996_SG;
377 + version = NUM_OF_MSM8996_VERSIONS;
383 +static int qcom_cpufreq_kryo_name_version(struct device *cpu_dev,
384 + struct nvmem_cell *speedbin_nvmem,
389 + enum _msm8996_version msm8996_version;
391 + msm8996_version = qcom_cpufreq_get_msm_id();
392 + if (NUM_OF_MSM8996_VERSIONS == msm8996_version) {
393 + dev_err(cpu_dev, "Not Snapdragon 820/821!");
397 + speedbin = nvmem_cell_read(speedbin_nvmem, &len);
398 + if (IS_ERR(speedbin))
399 + return PTR_ERR(speedbin);
401 + switch (msm8996_version) {
403 + *versions = 1 << (unsigned int)(*speedbin);
406 + *versions = 1 << ((unsigned int)(*speedbin) + 4);
417 +static int qcom_cpufreq_probe(struct platform_device *pdev)
419 + struct opp_table **opp_tables;
420 + int (*get_version)(struct device *cpu_dev,
421 + struct nvmem_cell *speedbin_nvmem,
423 + struct nvmem_cell *speedbin_nvmem;
424 + struct device_node *np;
425 + struct device *cpu_dev;
428 + const struct of_device_id *match;
431 + cpu_dev = get_cpu_device(0);
435 + match = pdev->dev.platform_data;
436 + get_version = match->data;
440 + np = dev_pm_opp_of_get_opp_desc_node(cpu_dev);
444 + ret = of_device_is_compatible(np, "operating-points-v2-kryo-cpu");
450 + speedbin_nvmem = of_nvmem_cell_get(np, NULL);
452 + if (IS_ERR(speedbin_nvmem)) {
453 + if (PTR_ERR(speedbin_nvmem) != -EPROBE_DEFER)
454 + dev_err(cpu_dev, "Could not get nvmem cell: %ld\n",
455 + PTR_ERR(speedbin_nvmem));
456 + return PTR_ERR(speedbin_nvmem);
459 + ret = get_version(cpu_dev, speedbin_nvmem, &versions);
460 + nvmem_cell_put(speedbin_nvmem);
464 + opp_tables = kcalloc(num_possible_cpus(), sizeof(*opp_tables), GFP_KERNEL);
468 + for_each_possible_cpu(cpu) {
469 + cpu_dev = get_cpu_device(cpu);
470 + if (NULL == cpu_dev) {
475 + opp_tables[cpu] = dev_pm_opp_set_supported_hw(cpu_dev,
477 + if (IS_ERR(opp_tables[cpu])) {
478 + ret = PTR_ERR(opp_tables[cpu]);
479 + dev_err(cpu_dev, "Failed to set supported hardware\n");
484 + cpufreq_dt_pdev = platform_device_register_simple("cpufreq-dt", -1,
486 + if (!IS_ERR(cpufreq_dt_pdev)) {
487 + platform_set_drvdata(pdev, opp_tables);
491 + ret = PTR_ERR(cpufreq_dt_pdev);
492 + dev_err(cpu_dev, "Failed to register platform device\n");
495 + for_each_possible_cpu(cpu) {
496 + if (IS_ERR_OR_NULL(opp_tables[cpu]))
498 + dev_pm_opp_put_supported_hw(opp_tables[cpu]);
505 +static int qcom_cpufreq_remove(struct platform_device *pdev)
507 + struct opp_table **opp_tables = platform_get_drvdata(pdev);
510 + platform_device_unregister(cpufreq_dt_pdev);
512 + for_each_possible_cpu(cpu)
513 + dev_pm_opp_put_supported_hw(opp_tables[cpu]);
520 +static struct platform_driver qcom_cpufreq_driver = {
521 + .probe = qcom_cpufreq_probe,
522 + .remove = qcom_cpufreq_remove,
524 + .name = "qcom-cpufreq-nvmem",
528 +static const struct of_device_id qcom_cpufreq_match_list[] __initconst = {
529 + { .compatible = "qcom,apq8096",
530 + .data = qcom_cpufreq_kryo_name_version },
531 + { .compatible = "qcom,msm8996",
532 + .data = qcom_cpufreq_kryo_name_version },
537 + * Since the driver depends on smem and nvmem drivers, which may
538 + * return EPROBE_DEFER, all the real activity is done in the probe,
539 + * which may be defered as well. The init here is only registering
540 + * the driver and the platform device.
542 +static int __init qcom_cpufreq_init(void)
544 + struct device_node *np = of_find_node_by_path("/");
545 + const struct of_device_id *match;
551 + match = of_match_node(qcom_cpufreq_match_list, np);
556 + ret = platform_driver_register(&qcom_cpufreq_driver);
557 + if (unlikely(ret < 0))
560 + cpufreq_pdev = platform_device_register_data(NULL, "qcom-cpufreq-nvmem",
561 + -1, match, sizeof(*match));
562 + ret = PTR_ERR_OR_ZERO(cpufreq_pdev);
566 + platform_driver_unregister(&qcom_cpufreq_driver);
569 +module_init(qcom_cpufreq_init);
571 +static void __exit qcom_cpufreq_exit(void)
573 + platform_device_unregister(cpufreq_pdev);
574 + platform_driver_unregister(&qcom_cpufreq_driver);
576 +module_exit(qcom_cpufreq_exit);
578 +MODULE_DESCRIPTION("Qualcomm Technologies, Inc. CPUfreq driver");
579 +MODULE_LICENSE("GPL v2");