Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'cpufreq/qcom-updates' into cpufreq/arm/linux-next

+566 -272
+121 -6
Documentation/devicetree/bindings/opp/kryo-cpufreq.txt Documentation/devicetree/bindings/opp/qcom-nvmem-cpufreq.txt
··· 1 - Qualcomm Technologies, Inc. KRYO CPUFreq and OPP bindings 1 + Qualcomm Technologies, Inc. NVMEM CPUFreq and OPP bindings 2 2 =================================== 3 3 4 - In Certain Qualcomm Technologies, Inc. SoCs like apq8096 and msm8996 5 - that have KRYO processors, the CPU ferequencies subset and voltage value 6 - of each OPP varies based on the silicon variant in use. 4 + In Certain Qualcomm Technologies, Inc. SoCs like apq8096 and msm8996, 5 + the CPU frequencies subset and voltage value of each OPP varies based on 6 + the silicon variant in use. 7 7 Qualcomm Technologies, Inc. Process Voltage Scaling Tables 8 8 defines the voltage and frequency value based on the msm-id in SMEM 9 9 and speedbin blown in the efuse combination. 10 - The qcom-cpufreq-kryo driver reads the msm-id and efuse value from the SoC 10 + The qcom-cpufreq-nvmem driver reads the msm-id and efuse value from the SoC 11 11 to provide the OPP framework with required information (existing HW bitmap). 12 12 This is used to determine the voltage and frequency value for each OPP of 13 13 operating-points-v2 table when it is parsed by the OPP framework. 14 14 15 15 Required properties: 16 16 -------------------- 17 - In 'cpus' nodes: 17 + In 'cpu' nodes: 18 18 - operating-points-v2: Phandle to the operating-points-v2 table to use. 19 19 20 20 In 'operating-points-v2' table: 21 21 - compatible: Should be 22 22 - 'operating-points-v2-kryo-cpu' for apq8096 and msm8996. 23 + 24 + Optional properties: 25 + -------------------- 26 + In 'cpu' nodes: 27 + - power-domains: A phandle pointing to the PM domain specifier which provides 28 + the performance states available for active state management. 29 + Please refer to the power-domains bindings 30 + Documentation/devicetree/bindings/power/power_domain.txt 31 + and also examples below. 32 + - power-domain-names: Should be 33 + - 'cpr' for qcs404. 34 + 35 + In 'operating-points-v2' table: 23 36 - nvmem-cells: A phandle pointing to a nvmem-cells node representing the 24 37 efuse registers that has information about the 25 38 speedbin that is used to select the right frequency/voltage ··· 689 676 reg = <0x133 0x1>; 690 677 bits = <5 3>; 691 678 }; 679 + }; 680 + }; 681 + 682 + Example 2: 683 + --------- 684 + 685 + cpus { 686 + #address-cells = <1>; 687 + #size-cells = <0>; 688 + 689 + CPU0: cpu@100 { 690 + device_type = "cpu"; 691 + compatible = "arm,cortex-a53"; 692 + reg = <0x100>; 693 + .... 694 + clocks = <&apcs_glb>; 695 + operating-points-v2 = <&cpu_opp_table>; 696 + power-domains = <&cpr>; 697 + power-domain-names = "cpr"; 698 + }; 699 + 700 + CPU1: cpu@101 { 701 + device_type = "cpu"; 702 + compatible = "arm,cortex-a53"; 703 + reg = <0x101>; 704 + .... 705 + clocks = <&apcs_glb>; 706 + operating-points-v2 = <&cpu_opp_table>; 707 + power-domains = <&cpr>; 708 + power-domain-names = "cpr"; 709 + }; 710 + 711 + CPU2: cpu@102 { 712 + device_type = "cpu"; 713 + compatible = "arm,cortex-a53"; 714 + reg = <0x102>; 715 + .... 716 + clocks = <&apcs_glb>; 717 + operating-points-v2 = <&cpu_opp_table>; 718 + power-domains = <&cpr>; 719 + power-domain-names = "cpr"; 720 + }; 721 + 722 + CPU3: cpu@103 { 723 + device_type = "cpu"; 724 + compatible = "arm,cortex-a53"; 725 + reg = <0x103>; 726 + .... 727 + clocks = <&apcs_glb>; 728 + operating-points-v2 = <&cpu_opp_table>; 729 + power-domains = <&cpr>; 730 + power-domain-names = "cpr"; 731 + }; 732 + }; 733 + 734 + cpu_opp_table: cpu-opp-table { 735 + compatible = "operating-points-v2-kryo-cpu"; 736 + opp-shared; 737 + 738 + opp-1094400000 { 739 + opp-hz = /bits/ 64 <1094400000>; 740 + required-opps = <&cpr_opp1>; 741 + }; 742 + opp-1248000000 { 743 + opp-hz = /bits/ 64 <1248000000>; 744 + required-opps = <&cpr_opp2>; 745 + }; 746 + opp-1401600000 { 747 + opp-hz = /bits/ 64 <1401600000>; 748 + required-opps = <&cpr_opp3>; 749 + }; 750 + }; 751 + 752 + cpr_opp_table: cpr-opp-table { 753 + compatible = "operating-points-v2-qcom-level"; 754 + 755 + cpr_opp1: opp1 { 756 + opp-level = <1>; 757 + qcom,opp-fuse-level = <1>; 758 + }; 759 + cpr_opp2: opp2 { 760 + opp-level = <2>; 761 + qcom,opp-fuse-level = <2>; 762 + }; 763 + cpr_opp3: opp3 { 764 + opp-level = <3>; 765 + qcom,opp-fuse-level = <3>; 766 + }; 767 + }; 768 + 769 + .... 770 + 771 + soc { 772 + .... 773 + cpr: power-controller@b018000 { 774 + compatible = "qcom,qcs404-cpr", "qcom,cpr"; 775 + reg = <0x0b018000 0x1000>; 776 + .... 777 + vdd-apc-supply = <&pms405_s3>; 778 + #power-domain-cells = <0>; 779 + operating-points-v2 = <&cpr_opp_table>; 780 + .... 692 781 }; 693 782 };
+19
Documentation/devicetree/bindings/opp/qcom-opp.txt
··· 1 + Qualcomm OPP bindings to describe OPP nodes 2 + 3 + The bindings are based on top of the operating-points-v2 bindings 4 + described in Documentation/devicetree/bindings/opp/opp.txt 5 + Additional properties are described below. 6 + 7 + * OPP Table Node 8 + 9 + Required properties: 10 + - compatible: Allow OPPs to express their compatibility. It should be: 11 + "operating-points-v2-qcom-level" 12 + 13 + * OPP Node 14 + 15 + Required properties: 16 + - qcom,opp-fuse-level: A positive value representing the fuse corner/level 17 + associated with this OPP node. Sometimes several corners/levels shares 18 + a certain fuse corner/level. A fuse corner/level contains e.g. ref uV, 19 + min uV, and max uV.
+2 -2
MAINTAINERS
··· 13292 13292 M: Ilia Lin <ilia.lin@kernel.org> 13293 13293 L: linux-pm@vger.kernel.org 13294 13294 S: Maintained 13295 - F: Documentation/devicetree/bindings/opp/kryo-cpufreq.txt 13296 - F: drivers/cpufreq/qcom-cpufreq-kryo.c 13295 + F: Documentation/devicetree/bindings/opp/qcom-nvmem-cpufreq.txt 13296 + F: drivers/cpufreq/qcom-cpufreq-nvmem.c 13297 13297 13298 13298 QUALCOMM EMAC GIGABIT ETHERNET DRIVER 13299 13299 M: Timur Tabi <timur@kernel.org>
+2 -2
drivers/cpufreq/Kconfig.arm
··· 132 132 depends on ARCH_OMAP2PLUS 133 133 default ARCH_OMAP2PLUS 134 134 135 - config ARM_QCOM_CPUFREQ_KRYO 136 - tristate "Qualcomm Kryo based CPUFreq" 135 + config ARM_QCOM_CPUFREQ_NVMEM 136 + tristate "Qualcomm nvmem based CPUFreq" 137 137 depends on ARM64 138 138 depends on QCOM_QFPROM 139 139 depends on QCOM_SMEM
+1 -1
drivers/cpufreq/Makefile
··· 64 64 obj-$(CONFIG_ARM_PXA2xx_CPUFREQ) += pxa2xx-cpufreq.o 65 65 obj-$(CONFIG_PXA3xx) += pxa3xx-cpufreq.o 66 66 obj-$(CONFIG_ARM_QCOM_CPUFREQ_HW) += qcom-cpufreq-hw.o 67 - obj-$(CONFIG_ARM_QCOM_CPUFREQ_KRYO) += qcom-cpufreq-kryo.o 67 + obj-$(CONFIG_ARM_QCOM_CPUFREQ_NVMEM) += qcom-cpufreq-nvmem.o 68 68 obj-$(CONFIG_ARM_RASPBERRYPI_CPUFREQ) += raspberrypi-cpufreq.o 69 69 obj-$(CONFIG_ARM_S3C2410_CPUFREQ) += s3c2410-cpufreq.o 70 70 obj-$(CONFIG_ARM_S3C2412_CPUFREQ) += s3c2412-cpufreq.o
+1
drivers/cpufreq/cpufreq-dt-platdev.c
··· 127 127 128 128 { .compatible = "qcom,apq8096", }, 129 129 { .compatible = "qcom,msm8996", }, 130 + { .compatible = "qcom,qcs404", }, 130 131 131 132 { .compatible = "st,stih407", }, 132 133 { .compatible = "st,stih410", },
-249
drivers/cpufreq/qcom-cpufreq-kryo.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 2 - /* 3 - * Copyright (c) 2018, The Linux Foundation. All rights reserved. 4 - */ 5 - 6 - /* 7 - * In Certain QCOM SoCs like apq8096 and msm8996 that have KRYO processors, 8 - * the CPU frequency subset and voltage value of each OPP varies 9 - * based on the silicon variant in use. Qualcomm Process Voltage Scaling Tables 10 - * defines the voltage and frequency value based on the msm-id in SMEM 11 - * and speedbin blown in the efuse combination. 12 - * The qcom-cpufreq-kryo driver reads the msm-id and efuse value from the SoC 13 - * to provide the OPP framework with required information. 14 - * This is used to determine the voltage and frequency value for each OPP of 15 - * operating-points-v2 table when it is parsed by the OPP framework. 16 - */ 17 - 18 - #include <linux/cpu.h> 19 - #include <linux/err.h> 20 - #include <linux/init.h> 21 - #include <linux/kernel.h> 22 - #include <linux/module.h> 23 - #include <linux/nvmem-consumer.h> 24 - #include <linux/of.h> 25 - #include <linux/platform_device.h> 26 - #include <linux/pm_opp.h> 27 - #include <linux/slab.h> 28 - #include <linux/soc/qcom/smem.h> 29 - 30 - #define MSM_ID_SMEM 137 31 - 32 - enum _msm_id { 33 - MSM8996V3 = 0xF6ul, 34 - APQ8096V3 = 0x123ul, 35 - MSM8996SG = 0x131ul, 36 - APQ8096SG = 0x138ul, 37 - }; 38 - 39 - enum _msm8996_version { 40 - MSM8996_V3, 41 - MSM8996_SG, 42 - NUM_OF_MSM8996_VERSIONS, 43 - }; 44 - 45 - static struct platform_device *cpufreq_dt_pdev, *kryo_cpufreq_pdev; 46 - 47 - static enum _msm8996_version qcom_cpufreq_kryo_get_msm_id(void) 48 - { 49 - size_t len; 50 - u32 *msm_id; 51 - enum _msm8996_version version; 52 - 53 - msm_id = qcom_smem_get(QCOM_SMEM_HOST_ANY, MSM_ID_SMEM, &len); 54 - if (IS_ERR(msm_id)) 55 - return NUM_OF_MSM8996_VERSIONS; 56 - 57 - /* The first 4 bytes are format, next to them is the actual msm-id */ 58 - msm_id++; 59 - 60 - switch ((enum _msm_id)*msm_id) { 61 - case MSM8996V3: 62 - case APQ8096V3: 63 - version = MSM8996_V3; 64 - break; 65 - case MSM8996SG: 66 - case APQ8096SG: 67 - version = MSM8996_SG; 68 - break; 69 - default: 70 - version = NUM_OF_MSM8996_VERSIONS; 71 - } 72 - 73 - return version; 74 - } 75 - 76 - static int qcom_cpufreq_kryo_probe(struct platform_device *pdev) 77 - { 78 - struct opp_table **opp_tables; 79 - enum _msm8996_version msm8996_version; 80 - struct nvmem_cell *speedbin_nvmem; 81 - struct device_node *np; 82 - struct device *cpu_dev; 83 - unsigned cpu; 84 - u8 *speedbin; 85 - u32 versions; 86 - size_t len; 87 - int ret; 88 - 89 - cpu_dev = get_cpu_device(0); 90 - if (!cpu_dev) 91 - return -ENODEV; 92 - 93 - msm8996_version = qcom_cpufreq_kryo_get_msm_id(); 94 - if (NUM_OF_MSM8996_VERSIONS == msm8996_version) { 95 - dev_err(cpu_dev, "Not Snapdragon 820/821!"); 96 - return -ENODEV; 97 - } 98 - 99 - np = dev_pm_opp_of_get_opp_desc_node(cpu_dev); 100 - if (!np) 101 - return -ENOENT; 102 - 103 - ret = of_device_is_compatible(np, "operating-points-v2-kryo-cpu"); 104 - if (!ret) { 105 - of_node_put(np); 106 - return -ENOENT; 107 - } 108 - 109 - speedbin_nvmem = of_nvmem_cell_get(np, NULL); 110 - of_node_put(np); 111 - if (IS_ERR(speedbin_nvmem)) { 112 - if (PTR_ERR(speedbin_nvmem) != -EPROBE_DEFER) 113 - dev_err(cpu_dev, "Could not get nvmem cell: %ld\n", 114 - PTR_ERR(speedbin_nvmem)); 115 - return PTR_ERR(speedbin_nvmem); 116 - } 117 - 118 - speedbin = nvmem_cell_read(speedbin_nvmem, &len); 119 - nvmem_cell_put(speedbin_nvmem); 120 - if (IS_ERR(speedbin)) 121 - return PTR_ERR(speedbin); 122 - 123 - switch (msm8996_version) { 124 - case MSM8996_V3: 125 - versions = 1 << (unsigned int)(*speedbin); 126 - break; 127 - case MSM8996_SG: 128 - versions = 1 << ((unsigned int)(*speedbin) + 4); 129 - break; 130 - default: 131 - BUG(); 132 - break; 133 - } 134 - kfree(speedbin); 135 - 136 - opp_tables = kcalloc(num_possible_cpus(), sizeof(*opp_tables), GFP_KERNEL); 137 - if (!opp_tables) 138 - return -ENOMEM; 139 - 140 - for_each_possible_cpu(cpu) { 141 - cpu_dev = get_cpu_device(cpu); 142 - if (NULL == cpu_dev) { 143 - ret = -ENODEV; 144 - goto free_opp; 145 - } 146 - 147 - opp_tables[cpu] = dev_pm_opp_set_supported_hw(cpu_dev, 148 - &versions, 1); 149 - if (IS_ERR(opp_tables[cpu])) { 150 - ret = PTR_ERR(opp_tables[cpu]); 151 - dev_err(cpu_dev, "Failed to set supported hardware\n"); 152 - goto free_opp; 153 - } 154 - } 155 - 156 - cpufreq_dt_pdev = platform_device_register_simple("cpufreq-dt", -1, 157 - NULL, 0); 158 - if (!IS_ERR(cpufreq_dt_pdev)) { 159 - platform_set_drvdata(pdev, opp_tables); 160 - return 0; 161 - } 162 - 163 - ret = PTR_ERR(cpufreq_dt_pdev); 164 - dev_err(cpu_dev, "Failed to register platform device\n"); 165 - 166 - free_opp: 167 - for_each_possible_cpu(cpu) { 168 - if (IS_ERR_OR_NULL(opp_tables[cpu])) 169 - break; 170 - dev_pm_opp_put_supported_hw(opp_tables[cpu]); 171 - } 172 - kfree(opp_tables); 173 - 174 - return ret; 175 - } 176 - 177 - static int qcom_cpufreq_kryo_remove(struct platform_device *pdev) 178 - { 179 - struct opp_table **opp_tables = platform_get_drvdata(pdev); 180 - unsigned int cpu; 181 - 182 - platform_device_unregister(cpufreq_dt_pdev); 183 - 184 - for_each_possible_cpu(cpu) 185 - dev_pm_opp_put_supported_hw(opp_tables[cpu]); 186 - 187 - kfree(opp_tables); 188 - 189 - return 0; 190 - } 191 - 192 - static struct platform_driver qcom_cpufreq_kryo_driver = { 193 - .probe = qcom_cpufreq_kryo_probe, 194 - .remove = qcom_cpufreq_kryo_remove, 195 - .driver = { 196 - .name = "qcom-cpufreq-kryo", 197 - }, 198 - }; 199 - 200 - static const struct of_device_id qcom_cpufreq_kryo_match_list[] __initconst = { 201 - { .compatible = "qcom,apq8096", }, 202 - { .compatible = "qcom,msm8996", }, 203 - {} 204 - }; 205 - 206 - /* 207 - * Since the driver depends on smem and nvmem drivers, which may 208 - * return EPROBE_DEFER, all the real activity is done in the probe, 209 - * which may be defered as well. The init here is only registering 210 - * the driver and the platform device. 211 - */ 212 - static int __init qcom_cpufreq_kryo_init(void) 213 - { 214 - struct device_node *np = of_find_node_by_path("/"); 215 - const struct of_device_id *match; 216 - int ret; 217 - 218 - if (!np) 219 - return -ENODEV; 220 - 221 - match = of_match_node(qcom_cpufreq_kryo_match_list, np); 222 - of_node_put(np); 223 - if (!match) 224 - return -ENODEV; 225 - 226 - ret = platform_driver_register(&qcom_cpufreq_kryo_driver); 227 - if (unlikely(ret < 0)) 228 - return ret; 229 - 230 - kryo_cpufreq_pdev = platform_device_register_simple( 231 - "qcom-cpufreq-kryo", -1, NULL, 0); 232 - ret = PTR_ERR_OR_ZERO(kryo_cpufreq_pdev); 233 - if (0 == ret) 234 - return 0; 235 - 236 - platform_driver_unregister(&qcom_cpufreq_kryo_driver); 237 - return ret; 238 - } 239 - module_init(qcom_cpufreq_kryo_init); 240 - 241 - static void __exit qcom_cpufreq_kryo_exit(void) 242 - { 243 - platform_device_unregister(kryo_cpufreq_pdev); 244 - platform_driver_unregister(&qcom_cpufreq_kryo_driver); 245 - } 246 - module_exit(qcom_cpufreq_kryo_exit); 247 - 248 - MODULE_DESCRIPTION("Qualcomm Technologies, Inc. Kryo CPUfreq driver"); 249 - MODULE_LICENSE("GPL v2");
+352
drivers/cpufreq/qcom-cpufreq-nvmem.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (c) 2018, The Linux Foundation. All rights reserved. 4 + */ 5 + 6 + /* 7 + * In Certain QCOM SoCs like apq8096 and msm8996 that have KRYO processors, 8 + * the CPU frequency subset and voltage value of each OPP varies 9 + * based on the silicon variant in use. Qualcomm Process Voltage Scaling Tables 10 + * defines the voltage and frequency value based on the msm-id in SMEM 11 + * and speedbin blown in the efuse combination. 12 + * The qcom-cpufreq-nvmem driver reads the msm-id and efuse value from the SoC 13 + * to provide the OPP framework with required information. 14 + * This is used to determine the voltage and frequency value for each OPP of 15 + * operating-points-v2 table when it is parsed by the OPP framework. 16 + */ 17 + 18 + #include <linux/cpu.h> 19 + #include <linux/err.h> 20 + #include <linux/init.h> 21 + #include <linux/kernel.h> 22 + #include <linux/module.h> 23 + #include <linux/nvmem-consumer.h> 24 + #include <linux/of.h> 25 + #include <linux/of_device.h> 26 + #include <linux/platform_device.h> 27 + #include <linux/pm_domain.h> 28 + #include <linux/pm_opp.h> 29 + #include <linux/slab.h> 30 + #include <linux/soc/qcom/smem.h> 31 + 32 + #define MSM_ID_SMEM 137 33 + 34 + enum _msm_id { 35 + MSM8996V3 = 0xF6ul, 36 + APQ8096V3 = 0x123ul, 37 + MSM8996SG = 0x131ul, 38 + APQ8096SG = 0x138ul, 39 + }; 40 + 41 + enum _msm8996_version { 42 + MSM8996_V3, 43 + MSM8996_SG, 44 + NUM_OF_MSM8996_VERSIONS, 45 + }; 46 + 47 + struct qcom_cpufreq_drv; 48 + 49 + struct qcom_cpufreq_match_data { 50 + int (*get_version)(struct device *cpu_dev, 51 + struct nvmem_cell *speedbin_nvmem, 52 + struct qcom_cpufreq_drv *drv); 53 + const char **genpd_names; 54 + }; 55 + 56 + struct qcom_cpufreq_drv { 57 + struct opp_table **opp_tables; 58 + struct opp_table **genpd_opp_tables; 59 + u32 versions; 60 + const struct qcom_cpufreq_match_data *data; 61 + }; 62 + 63 + static struct platform_device *cpufreq_dt_pdev, *cpufreq_pdev; 64 + 65 + static enum _msm8996_version qcom_cpufreq_get_msm_id(void) 66 + { 67 + size_t len; 68 + u32 *msm_id; 69 + enum _msm8996_version version; 70 + 71 + msm_id = qcom_smem_get(QCOM_SMEM_HOST_ANY, MSM_ID_SMEM, &len); 72 + if (IS_ERR(msm_id)) 73 + return NUM_OF_MSM8996_VERSIONS; 74 + 75 + /* The first 4 bytes are format, next to them is the actual msm-id */ 76 + msm_id++; 77 + 78 + switch ((enum _msm_id)*msm_id) { 79 + case MSM8996V3: 80 + case APQ8096V3: 81 + version = MSM8996_V3; 82 + break; 83 + case MSM8996SG: 84 + case APQ8096SG: 85 + version = MSM8996_SG; 86 + break; 87 + default: 88 + version = NUM_OF_MSM8996_VERSIONS; 89 + } 90 + 91 + return version; 92 + } 93 + 94 + static int qcom_cpufreq_kryo_name_version(struct device *cpu_dev, 95 + struct nvmem_cell *speedbin_nvmem, 96 + struct qcom_cpufreq_drv *drv) 97 + { 98 + size_t len; 99 + u8 *speedbin; 100 + enum _msm8996_version msm8996_version; 101 + 102 + msm8996_version = qcom_cpufreq_get_msm_id(); 103 + if (NUM_OF_MSM8996_VERSIONS == msm8996_version) { 104 + dev_err(cpu_dev, "Not Snapdragon 820/821!"); 105 + return -ENODEV; 106 + } 107 + 108 + speedbin = nvmem_cell_read(speedbin_nvmem, &len); 109 + if (IS_ERR(speedbin)) 110 + return PTR_ERR(speedbin); 111 + 112 + switch (msm8996_version) { 113 + case MSM8996_V3: 114 + drv->versions = 1 << (unsigned int)(*speedbin); 115 + break; 116 + case MSM8996_SG: 117 + drv->versions = 1 << ((unsigned int)(*speedbin) + 4); 118 + break; 119 + default: 120 + BUG(); 121 + break; 122 + } 123 + 124 + kfree(speedbin); 125 + return 0; 126 + } 127 + 128 + static const struct qcom_cpufreq_match_data match_data_kryo = { 129 + .get_version = qcom_cpufreq_kryo_name_version, 130 + }; 131 + 132 + static const char *qcs404_genpd_names[] = { "cpr", NULL }; 133 + 134 + static const struct qcom_cpufreq_match_data match_data_qcs404 = { 135 + .genpd_names = qcs404_genpd_names, 136 + }; 137 + 138 + static int qcom_cpufreq_probe(struct platform_device *pdev) 139 + { 140 + struct qcom_cpufreq_drv *drv; 141 + struct nvmem_cell *speedbin_nvmem; 142 + struct device_node *np; 143 + struct device *cpu_dev; 144 + unsigned cpu; 145 + const struct of_device_id *match; 146 + int ret; 147 + 148 + cpu_dev = get_cpu_device(0); 149 + if (!cpu_dev) 150 + return -ENODEV; 151 + 152 + np = dev_pm_opp_of_get_opp_desc_node(cpu_dev); 153 + if (!np) 154 + return -ENOENT; 155 + 156 + ret = of_device_is_compatible(np, "operating-points-v2-kryo-cpu"); 157 + if (!ret) { 158 + of_node_put(np); 159 + return -ENOENT; 160 + } 161 + 162 + drv = kzalloc(sizeof(*drv), GFP_KERNEL); 163 + if (!drv) 164 + return -ENOMEM; 165 + 166 + match = pdev->dev.platform_data; 167 + drv->data = match->data; 168 + if (!drv->data) { 169 + ret = -ENODEV; 170 + goto free_drv; 171 + } 172 + 173 + if (drv->data->get_version) { 174 + speedbin_nvmem = of_nvmem_cell_get(np, NULL); 175 + if (IS_ERR(speedbin_nvmem)) { 176 + if (PTR_ERR(speedbin_nvmem) != -EPROBE_DEFER) 177 + dev_err(cpu_dev, 178 + "Could not get nvmem cell: %ld\n", 179 + PTR_ERR(speedbin_nvmem)); 180 + ret = PTR_ERR(speedbin_nvmem); 181 + goto free_drv; 182 + } 183 + 184 + ret = drv->data->get_version(cpu_dev, speedbin_nvmem, drv); 185 + if (ret) { 186 + nvmem_cell_put(speedbin_nvmem); 187 + goto free_drv; 188 + } 189 + nvmem_cell_put(speedbin_nvmem); 190 + } 191 + of_node_put(np); 192 + 193 + drv->opp_tables = kcalloc(num_possible_cpus(), sizeof(*drv->opp_tables), 194 + GFP_KERNEL); 195 + if (!drv->opp_tables) { 196 + ret = -ENOMEM; 197 + goto free_drv; 198 + } 199 + 200 + drv->genpd_opp_tables = kcalloc(num_possible_cpus(), 201 + sizeof(*drv->genpd_opp_tables), 202 + GFP_KERNEL); 203 + if (!drv->genpd_opp_tables) { 204 + ret = -ENOMEM; 205 + goto free_opp; 206 + } 207 + 208 + for_each_possible_cpu(cpu) { 209 + cpu_dev = get_cpu_device(cpu); 210 + if (NULL == cpu_dev) { 211 + ret = -ENODEV; 212 + goto free_genpd_opp; 213 + } 214 + 215 + 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]); 221 + dev_err(cpu_dev, 222 + "Failed to set supported hardware\n"); 223 + goto free_genpd_opp; 224 + } 225 + } 226 + 227 + if (drv->data->genpd_names) { 228 + drv->genpd_opp_tables[cpu] = 229 + dev_pm_opp_attach_genpd(cpu_dev, 230 + drv->data->genpd_names, 231 + NULL); 232 + if (IS_ERR(drv->genpd_opp_tables[cpu])) { 233 + ret = PTR_ERR(drv->genpd_opp_tables[cpu]); 234 + if (ret != -EPROBE_DEFER) 235 + dev_err(cpu_dev, 236 + "Could not attach to pm_domain: %d\n", 237 + ret); 238 + goto free_genpd_opp; 239 + } 240 + } 241 + } 242 + 243 + cpufreq_dt_pdev = platform_device_register_simple("cpufreq-dt", -1, 244 + NULL, 0); 245 + if (!IS_ERR(cpufreq_dt_pdev)) { 246 + platform_set_drvdata(pdev, drv); 247 + return 0; 248 + } 249 + 250 + ret = PTR_ERR(cpufreq_dt_pdev); 251 + dev_err(cpu_dev, "Failed to register platform device\n"); 252 + 253 + free_genpd_opp: 254 + for_each_possible_cpu(cpu) { 255 + if (IS_ERR_OR_NULL(drv->genpd_opp_tables[cpu])) 256 + break; 257 + dev_pm_opp_detach_genpd(drv->genpd_opp_tables[cpu]); 258 + } 259 + kfree(drv->genpd_opp_tables); 260 + free_opp: 261 + for_each_possible_cpu(cpu) { 262 + if (IS_ERR_OR_NULL(drv->opp_tables[cpu])) 263 + break; 264 + dev_pm_opp_put_supported_hw(drv->opp_tables[cpu]); 265 + } 266 + kfree(drv->opp_tables); 267 + free_drv: 268 + kfree(drv); 269 + 270 + return ret; 271 + } 272 + 273 + static int qcom_cpufreq_remove(struct platform_device *pdev) 274 + { 275 + struct qcom_cpufreq_drv *drv = platform_get_drvdata(pdev); 276 + unsigned int cpu; 277 + 278 + platform_device_unregister(cpufreq_dt_pdev); 279 + 280 + for_each_possible_cpu(cpu) { 281 + if (drv->opp_tables[cpu]) 282 + dev_pm_opp_put_supported_hw(drv->opp_tables[cpu]); 283 + if (drv->genpd_opp_tables[cpu]) 284 + dev_pm_opp_detach_genpd(drv->genpd_opp_tables[cpu]); 285 + } 286 + 287 + kfree(drv->opp_tables); 288 + kfree(drv->genpd_opp_tables); 289 + kfree(drv); 290 + 291 + return 0; 292 + } 293 + 294 + static struct platform_driver qcom_cpufreq_driver = { 295 + .probe = qcom_cpufreq_probe, 296 + .remove = qcom_cpufreq_remove, 297 + .driver = { 298 + .name = "qcom-cpufreq-nvmem", 299 + }, 300 + }; 301 + 302 + static const struct of_device_id qcom_cpufreq_match_list[] __initconst = { 303 + { .compatible = "qcom,apq8096", .data = &match_data_kryo }, 304 + { .compatible = "qcom,msm8996", .data = &match_data_kryo }, 305 + { .compatible = "qcom,qcs404", .data = &match_data_qcs404 }, 306 + {}, 307 + }; 308 + 309 + /* 310 + * Since the driver depends on smem and nvmem drivers, which may 311 + * return EPROBE_DEFER, all the real activity is done in the probe, 312 + * which may be defered as well. The init here is only registering 313 + * the driver and the platform device. 314 + */ 315 + static int __init qcom_cpufreq_init(void) 316 + { 317 + struct device_node *np = of_find_node_by_path("/"); 318 + const struct of_device_id *match; 319 + int ret; 320 + 321 + if (!np) 322 + return -ENODEV; 323 + 324 + match = of_match_node(qcom_cpufreq_match_list, np); 325 + of_node_put(np); 326 + if (!match) 327 + return -ENODEV; 328 + 329 + ret = platform_driver_register(&qcom_cpufreq_driver); 330 + if (unlikely(ret < 0)) 331 + return ret; 332 + 333 + cpufreq_pdev = platform_device_register_data(NULL, "qcom-cpufreq-nvmem", 334 + -1, match, sizeof(*match)); 335 + ret = PTR_ERR_OR_ZERO(cpufreq_pdev); 336 + if (0 == ret) 337 + return 0; 338 + 339 + platform_driver_unregister(&qcom_cpufreq_driver); 340 + return ret; 341 + } 342 + module_init(qcom_cpufreq_init); 343 + 344 + static void __exit qcom_cpufreq_exit(void) 345 + { 346 + platform_device_unregister(cpufreq_pdev); 347 + platform_driver_unregister(&qcom_cpufreq_driver); 348 + } 349 + module_exit(qcom_cpufreq_exit); 350 + 351 + MODULE_DESCRIPTION("Qualcomm Technologies, Inc. CPUfreq driver"); 352 + MODULE_LICENSE("GPL v2");
+58 -10
drivers/opp/core.c
··· 401 401 } 402 402 EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_exact); 403 403 404 + /** 405 + * dev_pm_opp_find_level_exact() - search for an exact level 406 + * @dev: device for which we do this operation 407 + * @level: level to search for 408 + * 409 + * Return: Searches for exact match in the opp table and returns pointer to the 410 + * matching opp if found, else returns ERR_PTR in case of error and should 411 + * be handled using IS_ERR. Error return values can be: 412 + * EINVAL: for bad pointer 413 + * ERANGE: no match found for search 414 + * ENODEV: if device not found in list of registered devices 415 + * 416 + * The callers are required to call dev_pm_opp_put() for the returned OPP after 417 + * use. 418 + */ 419 + struct dev_pm_opp *dev_pm_opp_find_level_exact(struct device *dev, 420 + unsigned int level) 421 + { 422 + struct opp_table *opp_table; 423 + struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE); 424 + 425 + opp_table = _find_opp_table(dev); 426 + if (IS_ERR(opp_table)) { 427 + int r = PTR_ERR(opp_table); 428 + 429 + dev_err(dev, "%s: OPP table not found (%d)\n", __func__, r); 430 + return ERR_PTR(r); 431 + } 432 + 433 + mutex_lock(&opp_table->lock); 434 + 435 + list_for_each_entry(temp_opp, &opp_table->opp_list, node) { 436 + if (temp_opp->level == level) { 437 + opp = temp_opp; 438 + 439 + /* Increment the reference count of OPP */ 440 + dev_pm_opp_get(opp); 441 + break; 442 + } 443 + } 444 + 445 + mutex_unlock(&opp_table->lock); 446 + dev_pm_opp_put_opp_table(opp_table); 447 + 448 + return opp; 449 + } 450 + EXPORT_SYMBOL_GPL(dev_pm_opp_find_level_exact); 451 + 404 452 static noinline struct dev_pm_opp *_find_freq_ceil(struct opp_table *opp_table, 405 453 unsigned long *freq) 406 454 { ··· 1819 1771 * dev_pm_opp_attach_genpd - Attach genpd(s) for the device and save virtual device pointer 1820 1772 * @dev: Consumer device for which the genpd is getting attached. 1821 1773 * @names: Null terminated array of pointers containing names of genpd to attach. 1774 + * @virt_devs: Pointer to return the array of virtual devices. 1822 1775 * 1823 1776 * Multiple generic power domains for a device are supported with the help of 1824 1777 * virtual genpd devices, which are created for each consumer device - genpd ··· 1833 1784 * 1834 1785 * This helper needs to be called once with a list of all genpd to attach. 1835 1786 * Otherwise the original device structure will be used instead by the OPP core. 1787 + * 1788 + * The order of entries in the names array must match the order in which 1789 + * "required-opps" are added in DT. 1836 1790 */ 1837 - struct opp_table *dev_pm_opp_attach_genpd(struct device *dev, const char **names) 1791 + struct opp_table *dev_pm_opp_attach_genpd(struct device *dev, 1792 + const char **names, struct device ***virt_devs) 1838 1793 { 1839 1794 struct opp_table *opp_table; 1840 1795 struct device *virt_dev; 1841 - int index, ret = -EINVAL; 1796 + int index = 0, ret = -EINVAL; 1842 1797 const char **name = names; 1843 1798 1844 1799 opp_table = dev_pm_opp_get_opp_table(dev); ··· 1868 1815 goto unlock; 1869 1816 1870 1817 while (*name) { 1871 - index = of_property_match_string(dev->of_node, 1872 - "power-domain-names", *name); 1873 - if (index < 0) { 1874 - dev_err(dev, "Failed to find power domain: %s (%d)\n", 1875 - *name, index); 1876 - goto err; 1877 - } 1878 - 1879 1818 if (index >= opp_table->required_opp_count) { 1880 1819 dev_err(dev, "Index can't be greater than required-opp-count - 1, %s (%d : %d)\n", 1881 1820 *name, opp_table->required_opp_count, index); ··· 1888 1843 } 1889 1844 1890 1845 opp_table->genpd_virt_devs[index] = virt_dev; 1846 + index++; 1891 1847 name++; 1892 1848 } 1893 1849 1850 + if (virt_devs) 1851 + *virt_devs = opp_table->genpd_virt_devs; 1894 1852 mutex_unlock(&opp_table->genpd_virt_dev_lock); 1895 1853 1896 1854 return opp_table;
+10 -2
include/linux/pm_opp.h
··· 96 96 struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev, 97 97 unsigned long freq, 98 98 bool available); 99 + struct dev_pm_opp *dev_pm_opp_find_level_exact(struct device *dev, 100 + unsigned int level); 99 101 100 102 struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev, 101 103 unsigned long *freq); ··· 130 128 void dev_pm_opp_put_clkname(struct opp_table *opp_table); 131 129 struct opp_table *dev_pm_opp_register_set_opp_helper(struct device *dev, int (*set_opp)(struct dev_pm_set_opp_data *data)); 132 130 void dev_pm_opp_unregister_set_opp_helper(struct opp_table *opp_table); 133 - struct opp_table *dev_pm_opp_attach_genpd(struct device *dev, const char **names); 131 + struct opp_table *dev_pm_opp_attach_genpd(struct device *dev, const char **names, struct device ***virt_devs); 134 132 void dev_pm_opp_detach_genpd(struct opp_table *opp_table); 135 133 int dev_pm_opp_xlate_performance_state(struct opp_table *src_table, struct opp_table *dst_table, unsigned int pstate); 136 134 int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq); ··· 198 196 199 197 static inline struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev, 200 198 unsigned long freq, bool available) 199 + { 200 + return ERR_PTR(-ENOTSUPP); 201 + } 202 + 203 + static inline struct dev_pm_opp *dev_pm_opp_find_level_exact(struct device *dev, 204 + unsigned int level) 201 205 { 202 206 return ERR_PTR(-ENOTSUPP); 203 207 } ··· 300 292 301 293 static inline void dev_pm_opp_put_clkname(struct opp_table *opp_table) {} 302 294 303 - static inline struct opp_table *dev_pm_opp_attach_genpd(struct device *dev, const char **names) 295 + static inline struct opp_table *dev_pm_opp_attach_genpd(struct device *dev, const char **names, struct device ***virt_devs) 304 296 { 305 297 return ERR_PTR(-ENOTSUPP); 306 298 }