diff options
36 files changed, 798 insertions, 303 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 078defa50bb7..d8db9ad441c3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
| @@ -1737,6 +1737,7 @@ F: arch/arm/configs/mvebu_*_defconfig | |||
| 1737 | F: arch/arm/mach-mvebu/ | 1737 | F: arch/arm/mach-mvebu/ |
| 1738 | F: arch/arm64/boot/dts/marvell/armada* | 1738 | F: arch/arm64/boot/dts/marvell/armada* |
| 1739 | F: drivers/cpufreq/armada-37xx-cpufreq.c | 1739 | F: drivers/cpufreq/armada-37xx-cpufreq.c |
| 1740 | F: drivers/cpufreq/armada-8k-cpufreq.c | ||
| 1740 | F: drivers/cpufreq/mvebu-cpufreq.c | 1741 | F: drivers/cpufreq/mvebu-cpufreq.c |
| 1741 | F: drivers/irqchip/irq-armada-370-xp.c | 1742 | F: drivers/irqchip/irq-armada-370-xp.c |
| 1742 | F: drivers/irqchip/irq-mvebu-* | 1743 | F: drivers/irqchip/irq-mvebu-* |
| @@ -3961,7 +3962,7 @@ M: Viresh Kumar <viresh.kumar@linaro.org> | |||
| 3961 | L: linux-pm@vger.kernel.org | 3962 | L: linux-pm@vger.kernel.org |
| 3962 | S: Maintained | 3963 | S: Maintained |
| 3963 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git | 3964 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git |
| 3964 | T: git git://git.linaro.org/people/vireshk/linux.git (For ARM Updates) | 3965 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm.git (For ARM Updates) |
| 3965 | B: https://bugzilla.kernel.org | 3966 | B: https://bugzilla.kernel.org |
| 3966 | F: Documentation/admin-guide/pm/cpufreq.rst | 3967 | F: Documentation/admin-guide/pm/cpufreq.rst |
| 3967 | F: Documentation/admin-guide/pm/intel_pstate.rst | 3968 | F: Documentation/admin-guide/pm/intel_pstate.rst |
| @@ -12605,11 +12606,11 @@ F: Documentation/media/v4l-drivers/qcom_camss.rst | |||
| 12605 | F: drivers/media/platform/qcom/camss/ | 12606 | F: drivers/media/platform/qcom/camss/ |
| 12606 | 12607 | ||
| 12607 | QUALCOMM CPUFREQ DRIVER MSM8996/APQ8096 | 12608 | QUALCOMM CPUFREQ DRIVER MSM8996/APQ8096 |
| 12608 | M: Ilia Lin <ilia.lin@gmail.com> | 12609 | M: Ilia Lin <ilia.lin@kernel.org> |
| 12609 | L: linux-pm@vger.kernel.org | 12610 | L: linux-pm@vger.kernel.org |
| 12610 | S: Maintained | 12611 | S: Maintained |
| 12611 | F: Documentation/devicetree/bindings/opp/kryo-cpufreq.txt | 12612 | F: Documentation/devicetree/bindings/opp/kryo-cpufreq.txt |
| 12612 | F: drivers/cpufreq/qcom-cpufreq-kryo.c | 12613 | F: drivers/cpufreq/qcom-cpufreq-kryo.c |
| 12613 | 12614 | ||
| 12614 | QUALCOMM EMAC GIGABIT ETHERNET DRIVER | 12615 | QUALCOMM EMAC GIGABIT ETHERNET DRIVER |
| 12615 | M: Timur Tabi <timur@kernel.org> | 12616 | M: Timur Tabi <timur@kernel.org> |
diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c index e7b78df2bfef..a02ff431ba47 100644 --- a/arch/arm/mach-davinci/da850.c +++ b/arch/arm/mach-davinci/da850.c | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include <linux/mfd/da8xx-cfgchip.h> | 21 | #include <linux/mfd/da8xx-cfgchip.h> |
| 22 | #include <linux/platform_data/clk-da8xx-cfgchip.h> | 22 | #include <linux/platform_data/clk-da8xx-cfgchip.h> |
| 23 | #include <linux/platform_data/clk-davinci-pll.h> | 23 | #include <linux/platform_data/clk-davinci-pll.h> |
| 24 | #include <linux/platform_data/davinci-cpufreq.h> | ||
| 24 | #include <linux/platform_data/gpio-davinci.h> | 25 | #include <linux/platform_data/gpio-davinci.h> |
| 25 | #include <linux/platform_device.h> | 26 | #include <linux/platform_device.h> |
| 26 | #include <linux/regmap.h> | 27 | #include <linux/regmap.h> |
| @@ -29,7 +30,6 @@ | |||
| 29 | #include <asm/mach/map.h> | 30 | #include <asm/mach/map.h> |
| 30 | 31 | ||
| 31 | #include <mach/common.h> | 32 | #include <mach/common.h> |
| 32 | #include <mach/cpufreq.h> | ||
| 33 | #include <mach/cputype.h> | 33 | #include <mach/cputype.h> |
| 34 | #include <mach/da8xx.h> | 34 | #include <mach/da8xx.h> |
| 35 | #include <mach/irqs.h> | 35 | #include <mach/irqs.h> |
diff --git a/arch/arm/mach-davinci/include/mach/cpufreq.h b/arch/arm/mach-davinci/include/mach/cpufreq.h deleted file mode 100644 index 3c089cfb6cd6..000000000000 --- a/arch/arm/mach-davinci/include/mach/cpufreq.h +++ /dev/null | |||
| @@ -1,26 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * TI DaVinci CPUFreq platform support. | ||
| 3 | * | ||
| 4 | * Copyright (C) 2009 Texas Instruments, Inc. http://www.ti.com/ | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public License as | ||
| 8 | * published by the Free Software Foundation version 2. | ||
| 9 | * | ||
| 10 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any | ||
| 11 | * kind, whether express or implied; without even the implied warranty | ||
| 12 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | */ | ||
| 15 | #ifndef _MACH_DAVINCI_CPUFREQ_H | ||
| 16 | #define _MACH_DAVINCI_CPUFREQ_H | ||
| 17 | |||
| 18 | #include <linux/cpufreq.h> | ||
| 19 | |||
| 20 | struct davinci_cpufreq_config { | ||
| 21 | struct cpufreq_frequency_table *freq_table; | ||
| 22 | int (*set_voltage) (unsigned int index); | ||
| 23 | int (*init) (void); | ||
| 24 | }; | ||
| 25 | |||
| 26 | #endif | ||
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index 217a782c3e55..1b207fca1420 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c | |||
| @@ -1051,6 +1051,48 @@ static int cpc_write(int cpu, struct cpc_register_resource *reg_res, u64 val) | |||
| 1051 | } | 1051 | } |
| 1052 | 1052 | ||
| 1053 | /** | 1053 | /** |
| 1054 | * cppc_get_desired_perf - Get the value of desired performance register. | ||
| 1055 | * @cpunum: CPU from which to get desired performance. | ||
| 1056 | * @desired_perf: address of a variable to store the returned desired performance | ||
| 1057 | * | ||
| 1058 | * Return: 0 for success, -EIO otherwise. | ||
| 1059 | */ | ||
| 1060 | int cppc_get_desired_perf(int cpunum, u64 *desired_perf) | ||
| 1061 | { | ||
| 1062 | struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpunum); | ||
| 1063 | int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpunum); | ||
| 1064 | struct cpc_register_resource *desired_reg; | ||
| 1065 | struct cppc_pcc_data *pcc_ss_data = NULL; | ||
| 1066 | |||
| 1067 | desired_reg = &cpc_desc->cpc_regs[DESIRED_PERF]; | ||
| 1068 | |||
| 1069 | if (CPC_IN_PCC(desired_reg)) { | ||
| 1070 | int ret = 0; | ||
| 1071 | |||
| 1072 | if (pcc_ss_id < 0) | ||
| 1073 | return -EIO; | ||
| 1074 | |||
| 1075 | pcc_ss_data = pcc_data[pcc_ss_id]; | ||
| 1076 | |||
| 1077 | down_write(&pcc_ss_data->pcc_lock); | ||
| 1078 | |||
| 1079 | if (send_pcc_cmd(pcc_ss_id, CMD_READ) >= 0) | ||
| 1080 | cpc_read(cpunum, desired_reg, desired_perf); | ||
| 1081 | else | ||
| 1082 | ret = -EIO; | ||
| 1083 | |||
| 1084 | up_write(&pcc_ss_data->pcc_lock); | ||
| 1085 | |||
| 1086 | return ret; | ||
| 1087 | } | ||
| 1088 | |||
| 1089 | cpc_read(cpunum, desired_reg, desired_perf); | ||
| 1090 | |||
| 1091 | return 0; | ||
| 1092 | } | ||
| 1093 | EXPORT_SYMBOL_GPL(cppc_get_desired_perf); | ||
| 1094 | |||
| 1095 | /** | ||
| 1054 | * cppc_get_perf_caps - Get a CPUs performance capabilities. | 1096 | * cppc_get_perf_caps - Get a CPUs performance capabilities. |
| 1055 | * @cpunum: CPU from which to get capabilities info. | 1097 | * @cpunum: CPU from which to get capabilities info. |
| 1056 | * @perf_caps: ptr to cppc_perf_caps. See cppc_acpi.h | 1098 | * @perf_caps: ptr to cppc_perf_caps. See cppc_acpi.h |
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index 608af20a3494..b22e6bba71f1 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig | |||
| @@ -207,8 +207,6 @@ comment "CPU frequency scaling drivers" | |||
| 207 | config CPUFREQ_DT | 207 | config CPUFREQ_DT |
| 208 | tristate "Generic DT based cpufreq driver" | 208 | tristate "Generic DT based cpufreq driver" |
| 209 | depends on HAVE_CLK && OF | 209 | depends on HAVE_CLK && OF |
| 210 | # if CPU_THERMAL is on and THERMAL=m, CPUFREQ_DT cannot be =y: | ||
| 211 | depends on !CPU_THERMAL || THERMAL | ||
| 212 | select CPUFREQ_DT_PLATDEV | 210 | select CPUFREQ_DT_PLATDEV |
| 213 | select PM_OPP | 211 | select PM_OPP |
| 214 | help | 212 | help |
| @@ -327,7 +325,6 @@ endif | |||
| 327 | config QORIQ_CPUFREQ | 325 | config QORIQ_CPUFREQ |
| 328 | tristate "CPU frequency scaling driver for Freescale QorIQ SoCs" | 326 | tristate "CPU frequency scaling driver for Freescale QorIQ SoCs" |
| 329 | depends on OF && COMMON_CLK && (PPC_E500MC || ARM || ARM64) | 327 | depends on OF && COMMON_CLK && (PPC_E500MC || ARM || ARM64) |
| 330 | depends on !CPU_THERMAL || THERMAL | ||
| 331 | select CLK_QORIQ | 328 | select CLK_QORIQ |
| 332 | help | 329 | help |
| 333 | This adds the CPUFreq driver support for Freescale QorIQ SoCs | 330 | This adds the CPUFreq driver support for Freescale QorIQ SoCs |
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 688f10227793..f08bb0075316 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm | |||
| @@ -25,12 +25,21 @@ config ARM_ARMADA_37XX_CPUFREQ | |||
| 25 | This adds the CPUFreq driver support for Marvell Armada 37xx SoCs. | 25 | This adds the CPUFreq driver support for Marvell Armada 37xx SoCs. |
| 26 | The Armada 37xx PMU supports 4 frequency and VDD levels. | 26 | The Armada 37xx PMU supports 4 frequency and VDD levels. |
| 27 | 27 | ||
| 28 | config ARM_ARMADA_8K_CPUFREQ | ||
| 29 | tristate "Armada 8K CPUFreq driver" | ||
| 30 | depends on ARCH_MVEBU && CPUFREQ_DT | ||
| 31 | help | ||
| 32 | This enables the CPUFreq driver support for Marvell | ||
| 33 | Armada8k SOCs. | ||
| 34 | Armada8K device has the AP806 which supports scaling | ||
| 35 | to any full integer divider. | ||
| 36 | |||
| 37 | If in doubt, say N. | ||
| 38 | |||
| 28 | # big LITTLE core layer and glue drivers | 39 | # big LITTLE core layer and glue drivers |
| 29 | config ARM_BIG_LITTLE_CPUFREQ | 40 | config ARM_BIG_LITTLE_CPUFREQ |
| 30 | tristate "Generic ARM big LITTLE CPUfreq driver" | 41 | tristate "Generic ARM big LITTLE CPUfreq driver" |
| 31 | depends on ARM_CPU_TOPOLOGY && HAVE_CLK | 42 | depends on ARM_CPU_TOPOLOGY && HAVE_CLK |
| 32 | # if CPU_THERMAL is on and THERMAL=m, ARM_BIT_LITTLE_CPUFREQ cannot be =y | ||
| 33 | depends on !CPU_THERMAL || THERMAL | ||
| 34 | select PM_OPP | 43 | select PM_OPP |
| 35 | help | 44 | help |
| 36 | This enables the Generic CPUfreq driver for ARM big.LITTLE platforms. | 45 | This enables the Generic CPUfreq driver for ARM big.LITTLE platforms. |
| @@ -38,7 +47,6 @@ config ARM_BIG_LITTLE_CPUFREQ | |||
| 38 | config ARM_SCPI_CPUFREQ | 47 | config ARM_SCPI_CPUFREQ |
| 39 | tristate "SCPI based CPUfreq driver" | 48 | tristate "SCPI based CPUfreq driver" |
| 40 | depends on ARM_SCPI_PROTOCOL && COMMON_CLK_SCPI | 49 | depends on ARM_SCPI_PROTOCOL && COMMON_CLK_SCPI |
| 41 | depends on !CPU_THERMAL || THERMAL | ||
| 42 | help | 50 | help |
| 43 | This adds the CPUfreq driver support for ARM platforms using SCPI | 51 | This adds the CPUfreq driver support for ARM platforms using SCPI |
| 44 | protocol for CPU power management. | 52 | protocol for CPU power management. |
| @@ -93,7 +101,6 @@ config ARM_KIRKWOOD_CPUFREQ | |||
| 93 | config ARM_MEDIATEK_CPUFREQ | 101 | config ARM_MEDIATEK_CPUFREQ |
| 94 | tristate "CPU Frequency scaling support for MediaTek SoCs" | 102 | tristate "CPU Frequency scaling support for MediaTek SoCs" |
| 95 | depends on ARCH_MEDIATEK && REGULATOR | 103 | depends on ARCH_MEDIATEK && REGULATOR |
| 96 | depends on !CPU_THERMAL || THERMAL | ||
| 97 | select PM_OPP | 104 | select PM_OPP |
| 98 | help | 105 | help |
| 99 | This adds the CPUFreq driver support for MediaTek SoCs. | 106 | This adds the CPUFreq driver support for MediaTek SoCs. |
| @@ -233,7 +240,6 @@ config ARM_SA1110_CPUFREQ | |||
| 233 | config ARM_SCMI_CPUFREQ | 240 | config ARM_SCMI_CPUFREQ |
| 234 | tristate "SCMI based CPUfreq driver" | 241 | tristate "SCMI based CPUfreq driver" |
| 235 | depends on ARM_SCMI_PROTOCOL || COMPILE_TEST | 242 | depends on ARM_SCMI_PROTOCOL || COMPILE_TEST |
| 236 | depends on !CPU_THERMAL || THERMAL | ||
| 237 | select PM_OPP | 243 | select PM_OPP |
| 238 | help | 244 | help |
| 239 | This adds the CPUfreq driver support for ARM platforms using SCMI | 245 | This adds the CPUfreq driver support for ARM platforms using SCMI |
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 08c071be2491..689b26c6f949 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile | |||
| @@ -50,6 +50,7 @@ obj-$(CONFIG_X86_SFI_CPUFREQ) += sfi-cpufreq.o | |||
| 50 | obj-$(CONFIG_ARM_BIG_LITTLE_CPUFREQ) += arm_big_little.o | 50 | obj-$(CONFIG_ARM_BIG_LITTLE_CPUFREQ) += arm_big_little.o |
| 51 | 51 | ||
| 52 | obj-$(CONFIG_ARM_ARMADA_37XX_CPUFREQ) += armada-37xx-cpufreq.o | 52 | obj-$(CONFIG_ARM_ARMADA_37XX_CPUFREQ) += armada-37xx-cpufreq.o |
| 53 | obj-$(CONFIG_ARM_ARMADA_8K_CPUFREQ) += armada-8k-cpufreq.o | ||
| 53 | obj-$(CONFIG_ARM_BRCMSTB_AVS_CPUFREQ) += brcmstb-avs-cpufreq.o | 54 | obj-$(CONFIG_ARM_BRCMSTB_AVS_CPUFREQ) += brcmstb-avs-cpufreq.o |
| 54 | obj-$(CONFIG_ACPI_CPPC_CPUFREQ) += cppc_cpufreq.o | 55 | obj-$(CONFIG_ACPI_CPPC_CPUFREQ) += cppc_cpufreq.o |
| 55 | obj-$(CONFIG_ARCH_DAVINCI) += davinci-cpufreq.o | 56 | obj-$(CONFIG_ARCH_DAVINCI) += davinci-cpufreq.o |
diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c index d62fd374d5c7..c72258a44ba4 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c | |||
| @@ -916,8 +916,10 @@ static void __init acpi_cpufreq_boost_init(void) | |||
| 916 | { | 916 | { |
| 917 | int ret; | 917 | int ret; |
| 918 | 918 | ||
| 919 | if (!(boot_cpu_has(X86_FEATURE_CPB) || boot_cpu_has(X86_FEATURE_IDA))) | 919 | if (!(boot_cpu_has(X86_FEATURE_CPB) || boot_cpu_has(X86_FEATURE_IDA))) { |
| 920 | pr_debug("Boost capabilities not present in the processor\n"); | ||
| 920 | return; | 921 | return; |
| 922 | } | ||
| 921 | 923 | ||
| 922 | acpi_cpufreq_driver.set_boost = set_boost; | 924 | acpi_cpufreq_driver.set_boost = set_boost; |
| 923 | acpi_cpufreq_driver.boost_enabled = boost_state(0); | 925 | acpi_cpufreq_driver.boost_enabled = boost_state(0); |
diff --git a/drivers/cpufreq/armada-8k-cpufreq.c b/drivers/cpufreq/armada-8k-cpufreq.c new file mode 100644 index 000000000000..b3f4bd647e9b --- /dev/null +++ b/drivers/cpufreq/armada-8k-cpufreq.c | |||
| @@ -0,0 +1,206 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0+ | ||
| 2 | /* | ||
| 3 | * CPUFreq support for Armada 8K | ||
| 4 | * | ||
| 5 | * Copyright (C) 2018 Marvell | ||
| 6 | * | ||
| 7 | * Omri Itach <omrii@marvell.com> | ||
| 8 | * Gregory Clement <gregory.clement@bootlin.com> | ||
| 9 | */ | ||
| 10 | |||
| 11 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
| 12 | |||
| 13 | #include <linux/clk.h> | ||
| 14 | #include <linux/cpu.h> | ||
| 15 | #include <linux/err.h> | ||
| 16 | #include <linux/init.h> | ||
| 17 | #include <linux/kernel.h> | ||
| 18 | #include <linux/module.h> | ||
| 19 | #include <linux/of.h> | ||
| 20 | #include <linux/platform_device.h> | ||
| 21 | #include <linux/pm_opp.h> | ||
| 22 | #include <linux/slab.h> | ||
| 23 | |||
| 24 | /* | ||
| 25 | * Setup the opps list with the divider for the max frequency, that | ||
| 26 | * will be filled at runtime. | ||
| 27 | */ | ||
| 28 | static const int opps_div[] __initconst = {1, 2, 3, 4}; | ||
| 29 | |||
| 30 | static struct platform_device *armada_8k_pdev; | ||
| 31 | |||
| 32 | struct freq_table { | ||
| 33 | struct device *cpu_dev; | ||
| 34 | unsigned int freq[ARRAY_SIZE(opps_div)]; | ||
| 35 | }; | ||
| 36 | |||
| 37 | /* If the CPUs share the same clock, then they are in the same cluster. */ | ||
| 38 | static void __init armada_8k_get_sharing_cpus(struct clk *cur_clk, | ||
| 39 | struct cpumask *cpumask) | ||
| 40 | { | ||
| 41 | int cpu; | ||
| 42 | |||
| 43 | for_each_possible_cpu(cpu) { | ||
| 44 | struct device *cpu_dev; | ||
| 45 | struct clk *clk; | ||
| 46 | |||
| 47 | cpu_dev = get_cpu_device(cpu); | ||
| 48 | if (!cpu_dev) { | ||
| 49 | pr_warn("Failed to get cpu%d device\n", cpu); | ||
| 50 | continue; | ||
| 51 | } | ||
| 52 | |||
| 53 | clk = clk_get(cpu_dev, 0); | ||
| 54 | if (IS_ERR(clk)) { | ||
| 55 | pr_warn("Cannot get clock for CPU %d\n", cpu); | ||
| 56 | } else { | ||
| 57 | if (clk_is_match(clk, cur_clk)) | ||
| 58 | cpumask_set_cpu(cpu, cpumask); | ||
| 59 | |||
| 60 | clk_put(clk); | ||
| 61 | } | ||
| 62 | } | ||
| 63 | } | ||
| 64 | |||
| 65 | static int __init armada_8k_add_opp(struct clk *clk, struct device *cpu_dev, | ||
| 66 | struct freq_table *freq_tables, | ||
| 67 | int opps_index) | ||
| 68 | { | ||
| 69 | unsigned int cur_frequency; | ||
| 70 | unsigned int freq; | ||
| 71 | int i, ret; | ||
| 72 | |||
| 73 | /* Get nominal (current) CPU frequency. */ | ||
| 74 | cur_frequency = clk_get_rate(clk); | ||
| 75 | if (!cur_frequency) { | ||
| 76 | dev_err(cpu_dev, "Failed to get clock rate for this CPU\n"); | ||
| 77 | return -EINVAL; | ||
| 78 | } | ||
| 79 | |||
| 80 | freq_tables[opps_index].cpu_dev = cpu_dev; | ||
| 81 | |||
| 82 | for (i = 0; i < ARRAY_SIZE(opps_div); i++) { | ||
| 83 | freq = cur_frequency / opps_div[i]; | ||
| 84 | |||
| 85 | ret = dev_pm_opp_add(cpu_dev, freq, 0); | ||
| 86 | if (ret) | ||
| 87 | return ret; | ||
| 88 | |||
| 89 | freq_tables[opps_index].freq[i] = freq; | ||
| 90 | } | ||
| 91 | |||
| 92 | return 0; | ||
| 93 | } | ||
| 94 | |||
| 95 | static void armada_8k_cpufreq_free_table(struct freq_table *freq_tables) | ||
| 96 | { | ||
| 97 | int opps_index, nb_cpus = num_possible_cpus(); | ||
| 98 | |||
| 99 | for (opps_index = 0 ; opps_index <= nb_cpus; opps_index++) { | ||
| 100 | int i; | ||
| 101 | |||
| 102 | /* If cpu_dev is NULL then we reached the end of the array */ | ||
| 103 | if (!freq_tables[opps_index].cpu_dev) | ||
| 104 | break; | ||
| 105 | |||
| 106 | for (i = 0; i < ARRAY_SIZE(opps_div); i++) { | ||
| 107 | /* | ||
| 108 | * A 0Hz frequency is not valid, this meant | ||
| 109 | * that it was not yet initialized so there is | ||
| 110 | * no more opp to free | ||
| 111 | */ | ||
| 112 | if (freq_tables[opps_index].freq[i] == 0) | ||
| 113 | break; | ||
| 114 | |||
| 115 | dev_pm_opp_remove(freq_tables[opps_index].cpu_dev, | ||
| 116 | freq_tables[opps_index].freq[i]); | ||
| 117 | } | ||
| 118 | } | ||
| 119 | |||
| 120 | kfree(freq_tables); | ||
| 121 | } | ||
| 122 | |||
| 123 | static int __init armada_8k_cpufreq_init(void) | ||
| 124 | { | ||
| 125 | int ret = 0, opps_index = 0, cpu, nb_cpus; | ||
| 126 | struct freq_table *freq_tables; | ||
| 127 | struct device_node *node; | ||
| 128 | struct cpumask cpus; | ||
| 129 | |||
| 130 | node = of_find_compatible_node(NULL, NULL, "marvell,ap806-cpu-clock"); | ||
| 131 | if (!node || !of_device_is_available(node)) { | ||
| 132 | of_node_put(node); | ||
| 133 | return -ENODEV; | ||
| 134 | } | ||
| 135 | |||
| 136 | nb_cpus = num_possible_cpus(); | ||
| 137 | freq_tables = kcalloc(nb_cpus, sizeof(*freq_tables), GFP_KERNEL); | ||
| 138 | cpumask_copy(&cpus, cpu_possible_mask); | ||
| 139 | |||
| 140 | /* | ||
| 141 | * For each CPU, this loop registers the operating points | ||
| 142 | * supported (which are the nominal CPU frequency and full integer | ||
| 143 | * divisions of it). | ||
| 144 | */ | ||
| 145 | for_each_cpu(cpu, &cpus) { | ||
| 146 | struct cpumask shared_cpus; | ||
| 147 | struct device *cpu_dev; | ||
| 148 | struct clk *clk; | ||
| 149 | |||
| 150 | cpu_dev = get_cpu_device(cpu); | ||
| 151 | |||
| 152 | if (!cpu_dev) { | ||
| 153 | pr_err("Cannot get CPU %d\n", cpu); | ||
| 154 | continue; | ||
| 155 | } | ||
| 156 | |||
| 157 | clk = clk_get(cpu_dev, 0); | ||
| 158 | |||
| 159 | if (IS_ERR(clk)) { | ||
| 160 | pr_err("Cannot get clock for CPU %d\n", cpu); | ||
| 161 | ret = PTR_ERR(clk); | ||
| 162 | goto remove_opp; | ||
| 163 | } | ||
| 164 | |||
| 165 | ret = armada_8k_add_opp(clk, cpu_dev, freq_tables, opps_index); | ||
| 166 | if (ret) { | ||
| 167 | clk_put(clk); | ||
| 168 | goto remove_opp; | ||
| 169 | } | ||
| 170 | |||
| 171 | opps_index++; | ||
| 172 | cpumask_clear(&shared_cpus); | ||
| 173 | armada_8k_get_sharing_cpus(clk, &shared_cpus); | ||
| 174 | dev_pm_opp_set_sharing_cpus(cpu_dev, &shared_cpus); | ||
| 175 | cpumask_andnot(&cpus, &cpus, &shared_cpus); | ||
| 176 | clk_put(clk); | ||
| 177 | } | ||
| 178 | |||
| 179 | armada_8k_pdev = platform_device_register_simple("cpufreq-dt", -1, | ||
| 180 | NULL, 0); | ||
| 181 | ret = PTR_ERR_OR_ZERO(armada_8k_pdev); | ||
| 182 | if (ret) | ||
| 183 | goto remove_opp; | ||
| 184 | |||
| 185 | platform_set_drvdata(armada_8k_pdev, freq_tables); | ||
| 186 | |||
| 187 | return 0; | ||
| 188 | |||
| 189 | remove_opp: | ||
| 190 | armada_8k_cpufreq_free_table(freq_tables); | ||
| 191 | return ret; | ||
| 192 | } | ||
| 193 | module_init(armada_8k_cpufreq_init); | ||
| 194 | |||
| 195 | static void __exit armada_8k_cpufreq_exit(void) | ||
| 196 | { | ||
| 197 | struct freq_table *freq_tables = platform_get_drvdata(armada_8k_pdev); | ||
| 198 | |||
| 199 | platform_device_unregister(armada_8k_pdev); | ||
| 200 | armada_8k_cpufreq_free_table(freq_tables); | ||
| 201 | } | ||
| 202 | module_exit(armada_8k_cpufreq_exit); | ||
| 203 | |||
| 204 | MODULE_AUTHOR("Gregory Clement <gregory.clement@bootlin.com>"); | ||
| 205 | MODULE_DESCRIPTION("Armada 8K cpufreq driver"); | ||
| 206 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c index fd25c21cee72..2ae978d27e61 100644 --- a/drivers/cpufreq/cppc_cpufreq.c +++ b/drivers/cpufreq/cppc_cpufreq.c | |||
| @@ -42,6 +42,66 @@ | |||
| 42 | */ | 42 | */ |
| 43 | static struct cppc_cpudata **all_cpu_data; | 43 | static struct cppc_cpudata **all_cpu_data; |
| 44 | 44 | ||
| 45 | struct cppc_workaround_oem_info { | ||
| 46 | char oem_id[ACPI_OEM_ID_SIZE +1]; | ||
| 47 | char oem_table_id[ACPI_OEM_TABLE_ID_SIZE + 1]; | ||
| 48 | u32 oem_revision; | ||
| 49 | }; | ||
| 50 | |||
| 51 | static bool apply_hisi_workaround; | ||
| 52 | |||
| 53 | static struct cppc_workaround_oem_info wa_info[] = { | ||
| 54 | { | ||
| 55 | .oem_id = "HISI ", | ||
| 56 | .oem_table_id = "HIP07 ", | ||
| 57 | .oem_revision = 0, | ||
| 58 | }, { | ||
| 59 | .oem_id = "HISI ", | ||
| 60 | .oem_table_id = "HIP08 ", | ||
| 61 | .oem_revision = 0, | ||
| 62 | } | ||
| 63 | }; | ||
| 64 | |||
| 65 | static unsigned int cppc_cpufreq_perf_to_khz(struct cppc_cpudata *cpu, | ||
| 66 | unsigned int perf); | ||
| 67 | |||
| 68 | /* | ||
| 69 | * HISI platform does not support delivered performance counter and | ||
| 70 | * reference performance counter. It can calculate the performance using the | ||
| 71 | * platform specific mechanism. We reuse the desired performance register to | ||
| 72 | * store the real performance calculated by the platform. | ||
| 73 | */ | ||
| 74 | static unsigned int hisi_cppc_cpufreq_get_rate(unsigned int cpunum) | ||
| 75 | { | ||
| 76 | struct cppc_cpudata *cpudata = all_cpu_data[cpunum]; | ||
| 77 | u64 desired_perf; | ||
| 78 | int ret; | ||
| 79 | |||
| 80 | ret = cppc_get_desired_perf(cpunum, &desired_perf); | ||
| 81 | if (ret < 0) | ||
| 82 | return -EIO; | ||
| 83 | |||
| 84 | return cppc_cpufreq_perf_to_khz(cpudata, desired_perf); | ||
| 85 | } | ||
| 86 | |||
| 87 | static void cppc_check_hisi_workaround(void) | ||
| 88 | { | ||
| 89 | struct acpi_table_header *tbl; | ||
| 90 | acpi_status status = AE_OK; | ||
| 91 | int i; | ||
| 92 | |||
| 93 | status = acpi_get_table(ACPI_SIG_PCCT, 0, &tbl); | ||
| 94 | if (ACPI_FAILURE(status) || !tbl) | ||
| 95 | return; | ||
| 96 | |||
| 97 | for (i = 0; i < ARRAY_SIZE(wa_info); i++) { | ||
| 98 | if (!memcmp(wa_info[i].oem_id, tbl->oem_id, ACPI_OEM_ID_SIZE) && | ||
| 99 | !memcmp(wa_info[i].oem_table_id, tbl->oem_table_id, ACPI_OEM_TABLE_ID_SIZE) && | ||
| 100 | wa_info[i].oem_revision == tbl->oem_revision) | ||
| 101 | apply_hisi_workaround = true; | ||
| 102 | } | ||
| 103 | } | ||
| 104 | |||
| 45 | /* Callback function used to retrieve the max frequency from DMI */ | 105 | /* Callback function used to retrieve the max frequency from DMI */ |
| 46 | static void cppc_find_dmi_mhz(const struct dmi_header *dm, void *private) | 106 | static void cppc_find_dmi_mhz(const struct dmi_header *dm, void *private) |
| 47 | { | 107 | { |
| @@ -334,6 +394,9 @@ static unsigned int cppc_cpufreq_get_rate(unsigned int cpunum) | |||
| 334 | struct cppc_cpudata *cpu = all_cpu_data[cpunum]; | 394 | struct cppc_cpudata *cpu = all_cpu_data[cpunum]; |
| 335 | int ret; | 395 | int ret; |
| 336 | 396 | ||
| 397 | if (apply_hisi_workaround) | ||
| 398 | return hisi_cppc_cpufreq_get_rate(cpunum); | ||
| 399 | |||
| 337 | ret = cppc_get_perf_ctrs(cpunum, &fb_ctrs_t0); | 400 | ret = cppc_get_perf_ctrs(cpunum, &fb_ctrs_t0); |
| 338 | if (ret) | 401 | if (ret) |
| 339 | return ret; | 402 | return ret; |
| @@ -386,6 +449,8 @@ static int __init cppc_cpufreq_init(void) | |||
| 386 | goto out; | 449 | goto out; |
| 387 | } | 450 | } |
| 388 | 451 | ||
| 452 | cppc_check_hisi_workaround(); | ||
| 453 | |||
| 389 | ret = cpufreq_register_driver(&cppc_cpufreq_driver); | 454 | ret = cpufreq_register_driver(&cppc_cpufreq_driver); |
| 390 | if (ret) | 455 | if (ret) |
| 391 | goto out; | 456 | goto out; |
diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c index e58bfcb1169e..1aefaa1b0ca2 100644 --- a/drivers/cpufreq/cpufreq-dt.c +++ b/drivers/cpufreq/cpufreq-dt.c | |||
| @@ -13,7 +13,6 @@ | |||
| 13 | 13 | ||
| 14 | #include <linux/clk.h> | 14 | #include <linux/clk.h> |
| 15 | #include <linux/cpu.h> | 15 | #include <linux/cpu.h> |
| 16 | #include <linux/cpu_cooling.h> | ||
| 17 | #include <linux/cpufreq.h> | 16 | #include <linux/cpufreq.h> |
| 18 | #include <linux/cpumask.h> | 17 | #include <linux/cpumask.h> |
| 19 | #include <linux/err.h> | 18 | #include <linux/err.h> |
| @@ -30,7 +29,6 @@ | |||
| 30 | struct private_data { | 29 | struct private_data { |
| 31 | struct opp_table *opp_table; | 30 | struct opp_table *opp_table; |
| 32 | struct device *cpu_dev; | 31 | struct device *cpu_dev; |
| 33 | struct thermal_cooling_device *cdev; | ||
| 34 | const char *reg_name; | 32 | const char *reg_name; |
| 35 | bool have_static_opps; | 33 | bool have_static_opps; |
| 36 | }; | 34 | }; |
| @@ -297,11 +295,25 @@ out_put_clk: | |||
| 297 | return ret; | 295 | return ret; |
| 298 | } | 296 | } |
| 299 | 297 | ||
| 298 | static int cpufreq_online(struct cpufreq_policy *policy) | ||
| 299 | { | ||
| 300 | /* We did light-weight tear down earlier, nothing to do here */ | ||
| 301 | return 0; | ||
| 302 | } | ||
| 303 | |||
| 304 | static int cpufreq_offline(struct cpufreq_policy *policy) | ||
| 305 | { | ||
| 306 | /* | ||
| 307 | * Preserve policy->driver_data and don't free resources on light-weight | ||
| 308 | * tear down. | ||
| 309 | */ | ||
| 310 | return 0; | ||
| 311 | } | ||
| 312 | |||
| 300 | static int cpufreq_exit(struct cpufreq_policy *policy) | 313 | static int cpufreq_exit(struct cpufreq_policy *policy) |
| 301 | { | 314 | { |
| 302 | struct private_data *priv = policy->driver_data; | 315 | struct private_data *priv = policy->driver_data; |
| 303 | 316 | ||
| 304 | cpufreq_cooling_unregister(priv->cdev); | ||
| 305 | dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table); | 317 | dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table); |
| 306 | if (priv->have_static_opps) | 318 | if (priv->have_static_opps) |
| 307 | dev_pm_opp_of_cpumask_remove_table(policy->related_cpus); | 319 | dev_pm_opp_of_cpumask_remove_table(policy->related_cpus); |
| @@ -314,21 +326,16 @@ static int cpufreq_exit(struct cpufreq_policy *policy) | |||
| 314 | return 0; | 326 | return 0; |
| 315 | } | 327 | } |
| 316 | 328 | ||
| 317 | static void cpufreq_ready(struct cpufreq_policy *policy) | ||
| 318 | { | ||
| 319 | struct private_data *priv = policy->driver_data; | ||
| 320 | |||
| 321 | priv->cdev = of_cpufreq_cooling_register(policy); | ||
| 322 | } | ||
| 323 | |||
| 324 | static struct cpufreq_driver dt_cpufreq_driver = { | 329 | static struct cpufreq_driver dt_cpufreq_driver = { |
| 325 | .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK, | 330 | .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK | |
| 331 | CPUFREQ_IS_COOLING_DEV, | ||
| 326 | .verify = cpufreq_generic_frequency_table_verify, | 332 | .verify = cpufreq_generic_frequency_table_verify, |
| 327 | .target_index = set_target, | 333 | .target_index = set_target, |
| 328 | .get = cpufreq_generic_get, | 334 | .get = cpufreq_generic_get, |
| 329 | .init = cpufreq_init, | 335 | .init = cpufreq_init, |
| 330 | .exit = cpufreq_exit, | 336 | .exit = cpufreq_exit, |
| 331 | .ready = cpufreq_ready, | 337 | .online = cpufreq_online, |
| 338 | .offline = cpufreq_offline, | ||
| 332 | .name = "cpufreq-dt", | 339 | .name = "cpufreq-dt", |
| 333 | .attr = cpufreq_dt_attr, | 340 | .attr = cpufreq_dt_attr, |
| 334 | .suspend = cpufreq_generic_suspend, | 341 | .suspend = cpufreq_generic_suspend, |
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index e35a886e00bc..0e626b00053b 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | 19 | ||
| 20 | #include <linux/cpu.h> | 20 | #include <linux/cpu.h> |
| 21 | #include <linux/cpufreq.h> | 21 | #include <linux/cpufreq.h> |
| 22 | #include <linux/cpu_cooling.h> | ||
| 22 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
| 23 | #include <linux/device.h> | 24 | #include <linux/device.h> |
| 24 | #include <linux/init.h> | 25 | #include <linux/init.h> |
| @@ -545,13 +546,13 @@ EXPORT_SYMBOL_GPL(cpufreq_policy_transition_delay_us); | |||
| 545 | * SYSFS INTERFACE * | 546 | * SYSFS INTERFACE * |
| 546 | *********************************************************************/ | 547 | *********************************************************************/ |
| 547 | static ssize_t show_boost(struct kobject *kobj, | 548 | static ssize_t show_boost(struct kobject *kobj, |
| 548 | struct attribute *attr, char *buf) | 549 | struct kobj_attribute *attr, char *buf) |
| 549 | { | 550 | { |
| 550 | return sprintf(buf, "%d\n", cpufreq_driver->boost_enabled); | 551 | return sprintf(buf, "%d\n", cpufreq_driver->boost_enabled); |
| 551 | } | 552 | } |
| 552 | 553 | ||
| 553 | static ssize_t store_boost(struct kobject *kobj, struct attribute *attr, | 554 | static ssize_t store_boost(struct kobject *kobj, struct kobj_attribute *attr, |
| 554 | const char *buf, size_t count) | 555 | const char *buf, size_t count) |
| 555 | { | 556 | { |
| 556 | int ret, enable; | 557 | int ret, enable; |
| 557 | 558 | ||
| @@ -1200,28 +1201,39 @@ static int cpufreq_online(unsigned int cpu) | |||
| 1200 | return -ENOMEM; | 1201 | return -ENOMEM; |
| 1201 | } | 1202 | } |
| 1202 | 1203 | ||
| 1203 | cpumask_copy(policy->cpus, cpumask_of(cpu)); | 1204 | if (!new_policy && cpufreq_driver->online) { |
| 1205 | ret = cpufreq_driver->online(policy); | ||
| 1206 | if (ret) { | ||
| 1207 | pr_debug("%s: %d: initialization failed\n", __func__, | ||
| 1208 | __LINE__); | ||
| 1209 | goto out_exit_policy; | ||
| 1210 | } | ||
| 1204 | 1211 | ||
| 1205 | /* call driver. From then on the cpufreq must be able | 1212 | /* Recover policy->cpus using related_cpus */ |
| 1206 | * to accept all calls to ->verify and ->setpolicy for this CPU | 1213 | cpumask_copy(policy->cpus, policy->related_cpus); |
| 1207 | */ | 1214 | } else { |
| 1208 | ret = cpufreq_driver->init(policy); | 1215 | cpumask_copy(policy->cpus, cpumask_of(cpu)); |
| 1209 | if (ret) { | ||
| 1210 | pr_debug("initialization failed\n"); | ||
| 1211 | goto out_free_policy; | ||
| 1212 | } | ||
| 1213 | 1216 | ||
| 1214 | ret = cpufreq_table_validate_and_sort(policy); | 1217 | /* |
| 1215 | if (ret) | 1218 | * Call driver. From then on the cpufreq must be able |
| 1216 | goto out_exit_policy; | 1219 | * to accept all calls to ->verify and ->setpolicy for this CPU. |
| 1220 | */ | ||
| 1221 | ret = cpufreq_driver->init(policy); | ||
| 1222 | if (ret) { | ||
| 1223 | pr_debug("%s: %d: initialization failed\n", __func__, | ||
| 1224 | __LINE__); | ||
| 1225 | goto out_free_policy; | ||
| 1226 | } | ||
| 1217 | 1227 | ||
| 1218 | down_write(&policy->rwsem); | 1228 | ret = cpufreq_table_validate_and_sort(policy); |
| 1229 | if (ret) | ||
| 1230 | goto out_exit_policy; | ||
| 1219 | 1231 | ||
| 1220 | if (new_policy) { | ||
| 1221 | /* related_cpus should at least include policy->cpus. */ | 1232 | /* related_cpus should at least include policy->cpus. */ |
| 1222 | cpumask_copy(policy->related_cpus, policy->cpus); | 1233 | cpumask_copy(policy->related_cpus, policy->cpus); |
| 1223 | } | 1234 | } |
| 1224 | 1235 | ||
| 1236 | down_write(&policy->rwsem); | ||
| 1225 | /* | 1237 | /* |
| 1226 | * affected cpus must always be the one, which are online. We aren't | 1238 | * affected cpus must always be the one, which are online. We aren't |
| 1227 | * managing offline cpus here. | 1239 | * managing offline cpus here. |
| @@ -1305,8 +1317,6 @@ static int cpufreq_online(unsigned int cpu) | |||
| 1305 | if (ret) { | 1317 | if (ret) { |
| 1306 | pr_err("%s: Failed to initialize policy for cpu: %d (%d)\n", | 1318 | pr_err("%s: Failed to initialize policy for cpu: %d (%d)\n", |
| 1307 | __func__, cpu, ret); | 1319 | __func__, cpu, ret); |
| 1308 | /* cpufreq_policy_free() will notify based on this */ | ||
| 1309 | new_policy = false; | ||
| 1310 | goto out_destroy_policy; | 1320 | goto out_destroy_policy; |
| 1311 | } | 1321 | } |
| 1312 | 1322 | ||
| @@ -1318,6 +1328,10 @@ static int cpufreq_online(unsigned int cpu) | |||
| 1318 | if (cpufreq_driver->ready) | 1328 | if (cpufreq_driver->ready) |
| 1319 | cpufreq_driver->ready(policy); | 1329 | cpufreq_driver->ready(policy); |
| 1320 | 1330 | ||
| 1331 | if (IS_ENABLED(CONFIG_CPU_THERMAL) && | ||
| 1332 | cpufreq_driver->flags & CPUFREQ_IS_COOLING_DEV) | ||
| 1333 | policy->cdev = of_cpufreq_cooling_register(policy); | ||
| 1334 | |||
| 1321 | pr_debug("initialization complete\n"); | 1335 | pr_debug("initialization complete\n"); |
| 1322 | 1336 | ||
| 1323 | return 0; | 1337 | return 0; |
| @@ -1405,6 +1419,12 @@ static int cpufreq_offline(unsigned int cpu) | |||
| 1405 | goto unlock; | 1419 | goto unlock; |
| 1406 | } | 1420 | } |
| 1407 | 1421 | ||
| 1422 | if (IS_ENABLED(CONFIG_CPU_THERMAL) && | ||
| 1423 | cpufreq_driver->flags & CPUFREQ_IS_COOLING_DEV) { | ||
| 1424 | cpufreq_cooling_unregister(policy->cdev); | ||
| 1425 | policy->cdev = NULL; | ||
| 1426 | } | ||
| 1427 | |||
| 1408 | if (cpufreq_driver->stop_cpu) | 1428 | if (cpufreq_driver->stop_cpu) |
| 1409 | cpufreq_driver->stop_cpu(policy); | 1429 | cpufreq_driver->stop_cpu(policy); |
| 1410 | 1430 | ||
| @@ -1412,11 +1432,12 @@ static int cpufreq_offline(unsigned int cpu) | |||
| 1412 | cpufreq_exit_governor(policy); | 1432 | cpufreq_exit_governor(policy); |
| 1413 | 1433 | ||
| 1414 | /* | 1434 | /* |
| 1415 | * Perform the ->exit() even during light-weight tear-down, | 1435 | * Perform the ->offline() during light-weight tear-down, as |
| 1416 | * since this is a core component, and is essential for the | 1436 | * that allows fast recovery when the CPU comes back. |
| 1417 | * subsequent light-weight ->init() to succeed. | ||
| 1418 | */ | 1437 | */ |
| 1419 | if (cpufreq_driver->exit) { | 1438 | if (cpufreq_driver->offline) { |
| 1439 | cpufreq_driver->offline(policy); | ||
| 1440 | } else if (cpufreq_driver->exit) { | ||
| 1420 | cpufreq_driver->exit(policy); | 1441 | cpufreq_driver->exit(policy); |
| 1421 | policy->freq_table = NULL; | 1442 | policy->freq_table = NULL; |
| 1422 | } | 1443 | } |
| @@ -1445,8 +1466,13 @@ static void cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif) | |||
| 1445 | cpumask_clear_cpu(cpu, policy->real_cpus); | 1466 | cpumask_clear_cpu(cpu, policy->real_cpus); |
| 1446 | remove_cpu_dev_symlink(policy, dev); | 1467 | remove_cpu_dev_symlink(policy, dev); |
| 1447 | 1468 | ||
| 1448 | if (cpumask_empty(policy->real_cpus)) | 1469 | if (cpumask_empty(policy->real_cpus)) { |
| 1470 | /* We did light-weight exit earlier, do full tear down now */ | ||
| 1471 | if (cpufreq_driver->offline) | ||
| 1472 | cpufreq_driver->exit(policy); | ||
| 1473 | |||
| 1449 | cpufreq_policy_free(policy); | 1474 | cpufreq_policy_free(policy); |
| 1475 | } | ||
| 1450 | } | 1476 | } |
| 1451 | 1477 | ||
| 1452 | /** | 1478 | /** |
| @@ -2192,12 +2218,25 @@ int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu) | |||
| 2192 | } | 2218 | } |
| 2193 | EXPORT_SYMBOL(cpufreq_get_policy); | 2219 | EXPORT_SYMBOL(cpufreq_get_policy); |
| 2194 | 2220 | ||
| 2195 | /* | 2221 | /** |
| 2196 | * policy : current policy. | 2222 | * cpufreq_set_policy - Modify cpufreq policy parameters. |
| 2197 | * new_policy: policy to be set. | 2223 | * @policy: Policy object to modify. |
| 2224 | * @new_policy: New policy data. | ||
| 2225 | * | ||
| 2226 | * Pass @new_policy to the cpufreq driver's ->verify() callback, run the | ||
| 2227 | * installed policy notifiers for it with the CPUFREQ_ADJUST value, pass it to | ||
| 2228 | * the driver's ->verify() callback again and run the notifiers for it again | ||
| 2229 | * with the CPUFREQ_NOTIFY value. Next, copy the min and max parameters | ||
| 2230 | * of @new_policy to @policy and either invoke the driver's ->setpolicy() | ||
| 2231 | * callback (if present) or carry out a governor update for @policy. That is, | ||
| 2232 | * run the current governor's ->limits() callback (if the governor field in | ||
| 2233 | * @new_policy points to the same object as the one in @policy) or replace the | ||
| 2234 | * governor for @policy with the new one stored in @new_policy. | ||
| 2235 | * | ||
| 2236 | * The cpuinfo part of @policy is not updated by this function. | ||
| 2198 | */ | 2237 | */ |
| 2199 | static int cpufreq_set_policy(struct cpufreq_policy *policy, | 2238 | static int cpufreq_set_policy(struct cpufreq_policy *policy, |
| 2200 | struct cpufreq_policy *new_policy) | 2239 | struct cpufreq_policy *new_policy) |
| 2201 | { | 2240 | { |
| 2202 | struct cpufreq_governor *old_gov; | 2241 | struct cpufreq_governor *old_gov; |
| 2203 | int ret; | 2242 | int ret; |
| @@ -2247,11 +2286,11 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy, | |||
| 2247 | if (cpufreq_driver->setpolicy) { | 2286 | if (cpufreq_driver->setpolicy) { |
| 2248 | policy->policy = new_policy->policy; | 2287 | policy->policy = new_policy->policy; |
| 2249 | pr_debug("setting range\n"); | 2288 | pr_debug("setting range\n"); |
| 2250 | return cpufreq_driver->setpolicy(new_policy); | 2289 | return cpufreq_driver->setpolicy(policy); |
| 2251 | } | 2290 | } |
| 2252 | 2291 | ||
| 2253 | if (new_policy->governor == policy->governor) { | 2292 | if (new_policy->governor == policy->governor) { |
| 2254 | pr_debug("cpufreq: governor limits update\n"); | 2293 | pr_debug("governor limits update\n"); |
| 2255 | cpufreq_governor_limits(policy); | 2294 | cpufreq_governor_limits(policy); |
| 2256 | return 0; | 2295 | return 0; |
| 2257 | } | 2296 | } |
| @@ -2272,7 +2311,7 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy, | |||
| 2272 | if (!ret) { | 2311 | if (!ret) { |
| 2273 | ret = cpufreq_start_governor(policy); | 2312 | ret = cpufreq_start_governor(policy); |
| 2274 | if (!ret) { | 2313 | if (!ret) { |
| 2275 | pr_debug("cpufreq: governor change\n"); | 2314 | pr_debug("governor change\n"); |
| 2276 | sched_cpufreq_governor_change(policy, old_gov); | 2315 | sched_cpufreq_governor_change(policy, old_gov); |
| 2277 | return 0; | 2316 | return 0; |
| 2278 | } | 2317 | } |
| @@ -2293,11 +2332,14 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy, | |||
| 2293 | } | 2332 | } |
| 2294 | 2333 | ||
| 2295 | /** | 2334 | /** |
| 2296 | * cpufreq_update_policy - re-evaluate an existing cpufreq policy | 2335 | * cpufreq_update_policy - Re-evaluate an existing cpufreq policy. |
| 2297 | * @cpu: CPU which shall be re-evaluated | 2336 | * @cpu: CPU to re-evaluate the policy for. |
| 2298 | * | 2337 | * |
| 2299 | * Useful for policy notifiers which have different necessities | 2338 | * Update the current frequency for the cpufreq policy of @cpu and use |
| 2300 | * at different times. | 2339 | * cpufreq_set_policy() to re-apply the min and max limits saved in the |
| 2340 | * user_policy sub-structure of that policy, which triggers the evaluation | ||
| 2341 | * of policy notifiers and the cpufreq driver's ->verify() callback for the | ||
| 2342 | * policy in question, among other things. | ||
| 2301 | */ | 2343 | */ |
| 2302 | void cpufreq_update_policy(unsigned int cpu) | 2344 | void cpufreq_update_policy(unsigned int cpu) |
| 2303 | { | 2345 | { |
| @@ -2312,23 +2354,18 @@ void cpufreq_update_policy(unsigned int cpu) | |||
| 2312 | if (policy_is_inactive(policy)) | 2354 | if (policy_is_inactive(policy)) |
| 2313 | goto unlock; | 2355 | goto unlock; |
| 2314 | 2356 | ||
| 2315 | pr_debug("updating policy for CPU %u\n", cpu); | ||
| 2316 | memcpy(&new_policy, policy, sizeof(*policy)); | ||
| 2317 | new_policy.min = policy->user_policy.min; | ||
| 2318 | new_policy.max = policy->user_policy.max; | ||
| 2319 | |||
| 2320 | /* | 2357 | /* |
| 2321 | * BIOS might change freq behind our back | 2358 | * BIOS might change freq behind our back |
| 2322 | * -> ask driver for current freq and notify governors about a change | 2359 | * -> ask driver for current freq and notify governors about a change |
| 2323 | */ | 2360 | */ |
| 2324 | if (cpufreq_driver->get && !cpufreq_driver->setpolicy) { | 2361 | if (cpufreq_driver->get && !cpufreq_driver->setpolicy && |
| 2325 | if (cpufreq_suspended) | 2362 | (cpufreq_suspended || WARN_ON(!cpufreq_update_current_freq(policy)))) |
| 2326 | goto unlock; | 2363 | goto unlock; |
| 2327 | 2364 | ||
| 2328 | new_policy.cur = cpufreq_update_current_freq(policy); | 2365 | pr_debug("updating policy for CPU %u\n", cpu); |
| 2329 | if (WARN_ON(!new_policy.cur)) | 2366 | memcpy(&new_policy, policy, sizeof(*policy)); |
| 2330 | goto unlock; | 2367 | new_policy.min = policy->user_policy.min; |
| 2331 | } | 2368 | new_policy.max = policy->user_policy.max; |
| 2332 | 2369 | ||
| 2333 | cpufreq_set_policy(policy, &new_policy); | 2370 | cpufreq_set_policy(policy, &new_policy); |
| 2334 | 2371 | ||
| @@ -2479,7 +2516,8 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) | |||
| 2479 | driver_data->target) || | 2516 | driver_data->target) || |
| 2480 | (driver_data->setpolicy && (driver_data->target_index || | 2517 | (driver_data->setpolicy && (driver_data->target_index || |
| 2481 | driver_data->target)) || | 2518 | driver_data->target)) || |
| 2482 | (!!driver_data->get_intermediate != !!driver_data->target_intermediate)) | 2519 | (!driver_data->get_intermediate != !driver_data->target_intermediate) || |
| 2520 | (!driver_data->online != !driver_data->offline)) | ||
| 2483 | return -EINVAL; | 2521 | return -EINVAL; |
| 2484 | 2522 | ||
| 2485 | pr_debug("trying to register driver %s\n", driver_data->name); | 2523 | pr_debug("trying to register driver %s\n", driver_data->name); |
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 1572129844a5..e2db5581489a 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c | |||
| @@ -31,26 +31,27 @@ static void cpufreq_stats_update(struct cpufreq_stats *stats) | |||
| 31 | { | 31 | { |
| 32 | unsigned long long cur_time = get_jiffies_64(); | 32 | unsigned long long cur_time = get_jiffies_64(); |
| 33 | 33 | ||
| 34 | spin_lock(&cpufreq_stats_lock); | ||
| 35 | stats->time_in_state[stats->last_index] += cur_time - stats->last_time; | 34 | stats->time_in_state[stats->last_index] += cur_time - stats->last_time; |
| 36 | stats->last_time = cur_time; | 35 | stats->last_time = cur_time; |
| 37 | spin_unlock(&cpufreq_stats_lock); | ||
| 38 | } | 36 | } |
| 39 | 37 | ||
| 40 | static void cpufreq_stats_clear_table(struct cpufreq_stats *stats) | 38 | static void cpufreq_stats_clear_table(struct cpufreq_stats *stats) |
| 41 | { | 39 | { |
| 42 | unsigned int count = stats->max_state; | 40 | unsigned int count = stats->max_state; |
| 43 | 41 | ||
| 42 | spin_lock(&cpufreq_stats_lock); | ||
| 44 | memset(stats->time_in_state, 0, count * sizeof(u64)); | 43 | memset(stats->time_in_state, 0, count * sizeof(u64)); |
| 45 | memset(stats->trans_table, 0, count * count * sizeof(int)); | 44 | memset(stats->trans_table, 0, count * count * sizeof(int)); |
| 46 | stats->last_time = get_jiffies_64(); | 45 | stats->last_time = get_jiffies_64(); |
| 47 | stats->total_trans = 0; | 46 | stats->total_trans = 0; |
| 47 | spin_unlock(&cpufreq_stats_lock); | ||
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | static ssize_t show_total_trans(struct cpufreq_policy *policy, char *buf) | 50 | static ssize_t show_total_trans(struct cpufreq_policy *policy, char *buf) |
| 51 | { | 51 | { |
| 52 | return sprintf(buf, "%d\n", policy->stats->total_trans); | 52 | return sprintf(buf, "%d\n", policy->stats->total_trans); |
| 53 | } | 53 | } |
| 54 | cpufreq_freq_attr_ro(total_trans); | ||
| 54 | 55 | ||
| 55 | static ssize_t show_time_in_state(struct cpufreq_policy *policy, char *buf) | 56 | static ssize_t show_time_in_state(struct cpufreq_policy *policy, char *buf) |
| 56 | { | 57 | { |
| @@ -61,7 +62,10 @@ static ssize_t show_time_in_state(struct cpufreq_policy *policy, char *buf) | |||
| 61 | if (policy->fast_switch_enabled) | 62 | if (policy->fast_switch_enabled) |
| 62 | return 0; | 63 | return 0; |
| 63 | 64 | ||
| 65 | spin_lock(&cpufreq_stats_lock); | ||
| 64 | cpufreq_stats_update(stats); | 66 | cpufreq_stats_update(stats); |
| 67 | spin_unlock(&cpufreq_stats_lock); | ||
| 68 | |||
| 65 | for (i = 0; i < stats->state_num; i++) { | 69 | for (i = 0; i < stats->state_num; i++) { |
| 66 | len += sprintf(buf + len, "%u %llu\n", stats->freq_table[i], | 70 | len += sprintf(buf + len, "%u %llu\n", stats->freq_table[i], |
| 67 | (unsigned long long) | 71 | (unsigned long long) |
| @@ -69,6 +73,7 @@ static ssize_t show_time_in_state(struct cpufreq_policy *policy, char *buf) | |||
| 69 | } | 73 | } |
| 70 | return len; | 74 | return len; |
| 71 | } | 75 | } |
| 76 | cpufreq_freq_attr_ro(time_in_state); | ||
| 72 | 77 | ||
| 73 | static ssize_t store_reset(struct cpufreq_policy *policy, const char *buf, | 78 | static ssize_t store_reset(struct cpufreq_policy *policy, const char *buf, |
| 74 | size_t count) | 79 | size_t count) |
| @@ -77,6 +82,7 @@ static ssize_t store_reset(struct cpufreq_policy *policy, const char *buf, | |||
| 77 | cpufreq_stats_clear_table(policy->stats); | 82 | cpufreq_stats_clear_table(policy->stats); |
| 78 | return count; | 83 | return count; |
| 79 | } | 84 | } |
| 85 | cpufreq_freq_attr_wo(reset); | ||
| 80 | 86 | ||
| 81 | static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf) | 87 | static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf) |
| 82 | { | 88 | { |
| @@ -126,10 +132,6 @@ static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf) | |||
| 126 | } | 132 | } |
| 127 | cpufreq_freq_attr_ro(trans_table); | 133 | cpufreq_freq_attr_ro(trans_table); |
| 128 | 134 | ||
| 129 | cpufreq_freq_attr_ro(total_trans); | ||
| 130 | cpufreq_freq_attr_ro(time_in_state); | ||
| 131 | cpufreq_freq_attr_wo(reset); | ||
| 132 | |||
| 133 | static struct attribute *default_attrs[] = { | 135 | static struct attribute *default_attrs[] = { |
| 134 | &total_trans.attr, | 136 | &total_trans.attr, |
| 135 | &time_in_state.attr, | 137 | &time_in_state.attr, |
| @@ -240,9 +242,11 @@ void cpufreq_stats_record_transition(struct cpufreq_policy *policy, | |||
| 240 | if (old_index == -1 || new_index == -1 || old_index == new_index) | 242 | if (old_index == -1 || new_index == -1 || old_index == new_index) |
| 241 | return; | 243 | return; |
| 242 | 244 | ||
| 245 | spin_lock(&cpufreq_stats_lock); | ||
| 243 | cpufreq_stats_update(stats); | 246 | cpufreq_stats_update(stats); |
| 244 | 247 | ||
| 245 | stats->last_index = new_index; | 248 | stats->last_index = new_index; |
| 246 | stats->trans_table[old_index * stats->max_state + new_index]++; | 249 | stats->trans_table[old_index * stats->max_state + new_index]++; |
| 247 | stats->total_trans++; | 250 | stats->total_trans++; |
| 251 | spin_unlock(&cpufreq_stats_lock); | ||
| 248 | } | 252 | } |
diff --git a/drivers/cpufreq/davinci-cpufreq.c b/drivers/cpufreq/davinci-cpufreq.c index d54a27c99121..940fe85db97a 100644 --- a/drivers/cpufreq/davinci-cpufreq.c +++ b/drivers/cpufreq/davinci-cpufreq.c | |||
| @@ -23,13 +23,10 @@ | |||
| 23 | #include <linux/init.h> | 23 | #include <linux/init.h> |
| 24 | #include <linux/err.h> | 24 | #include <linux/err.h> |
| 25 | #include <linux/clk.h> | 25 | #include <linux/clk.h> |
| 26 | #include <linux/platform_data/davinci-cpufreq.h> | ||
| 26 | #include <linux/platform_device.h> | 27 | #include <linux/platform_device.h> |
| 27 | #include <linux/export.h> | 28 | #include <linux/export.h> |
| 28 | 29 | ||
| 29 | #include <mach/hardware.h> | ||
| 30 | #include <mach/cpufreq.h> | ||
| 31 | #include <mach/common.h> | ||
| 32 | |||
| 33 | struct davinci_cpufreq { | 30 | struct davinci_cpufreq { |
| 34 | struct device *dev; | 31 | struct device *dev; |
| 35 | struct clk *armclk; | 32 | struct clk *armclk; |
diff --git a/drivers/cpufreq/e_powersaver.c b/drivers/cpufreq/e_powersaver.c index 60bea302abbe..2d3ef208dd70 100644 --- a/drivers/cpufreq/e_powersaver.c +++ b/drivers/cpufreq/e_powersaver.c | |||
| @@ -323,9 +323,8 @@ static int eps_cpu_init(struct cpufreq_policy *policy) | |||
| 323 | states = 2; | 323 | states = 2; |
| 324 | 324 | ||
| 325 | /* Allocate private data and frequency table for current cpu */ | 325 | /* Allocate private data and frequency table for current cpu */ |
| 326 | centaur = kzalloc(sizeof(*centaur) | 326 | centaur = kzalloc(struct_size(centaur, freq_table, states + 1), |
| 327 | + (states + 1) * sizeof(struct cpufreq_frequency_table), | 327 | GFP_KERNEL); |
| 328 | GFP_KERNEL); | ||
| 329 | if (!centaur) | 328 | if (!centaur) |
| 330 | return -ENOMEM; | 329 | return -ENOMEM; |
| 331 | eps_cpu[0] = centaur; | 330 | eps_cpu[0] = centaur; |
diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c index 9fedf627e000..ca955713e070 100644 --- a/drivers/cpufreq/imx6q-cpufreq.c +++ b/drivers/cpufreq/imx6q-cpufreq.c | |||
| @@ -9,7 +9,6 @@ | |||
| 9 | #include <linux/clk.h> | 9 | #include <linux/clk.h> |
| 10 | #include <linux/cpu.h> | 10 | #include <linux/cpu.h> |
| 11 | #include <linux/cpufreq.h> | 11 | #include <linux/cpufreq.h> |
| 12 | #include <linux/cpu_cooling.h> | ||
| 13 | #include <linux/err.h> | 12 | #include <linux/err.h> |
| 14 | #include <linux/module.h> | 13 | #include <linux/module.h> |
| 15 | #include <linux/nvmem-consumer.h> | 14 | #include <linux/nvmem-consumer.h> |
| @@ -52,7 +51,6 @@ static struct clk_bulk_data clks[] = { | |||
| 52 | }; | 51 | }; |
| 53 | 52 | ||
| 54 | static struct device *cpu_dev; | 53 | static struct device *cpu_dev; |
| 55 | static struct thermal_cooling_device *cdev; | ||
| 56 | static bool free_opp; | 54 | static bool free_opp; |
| 57 | static struct cpufreq_frequency_table *freq_table; | 55 | static struct cpufreq_frequency_table *freq_table; |
| 58 | static unsigned int max_freq; | 56 | static unsigned int max_freq; |
| @@ -193,16 +191,6 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index) | |||
| 193 | return 0; | 191 | return 0; |
| 194 | } | 192 | } |
| 195 | 193 | ||
| 196 | static void imx6q_cpufreq_ready(struct cpufreq_policy *policy) | ||
| 197 | { | ||
| 198 | cdev = of_cpufreq_cooling_register(policy); | ||
| 199 | |||
| 200 | if (!cdev) | ||
| 201 | dev_err(cpu_dev, | ||
| 202 | "running cpufreq without cooling device: %ld\n", | ||
| 203 | PTR_ERR(cdev)); | ||
| 204 | } | ||
| 205 | |||
| 206 | static int imx6q_cpufreq_init(struct cpufreq_policy *policy) | 194 | static int imx6q_cpufreq_init(struct cpufreq_policy *policy) |
| 207 | { | 195 | { |
| 208 | int ret; | 196 | int ret; |
| @@ -214,22 +202,14 @@ static int imx6q_cpufreq_init(struct cpufreq_policy *policy) | |||
| 214 | return ret; | 202 | return ret; |
| 215 | } | 203 | } |
| 216 | 204 | ||
| 217 | static int imx6q_cpufreq_exit(struct cpufreq_policy *policy) | ||
| 218 | { | ||
| 219 | cpufreq_cooling_unregister(cdev); | ||
| 220 | |||
| 221 | return 0; | ||
| 222 | } | ||
| 223 | |||
| 224 | static struct cpufreq_driver imx6q_cpufreq_driver = { | 205 | static struct cpufreq_driver imx6q_cpufreq_driver = { |
| 225 | .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK, | 206 | .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK | |
| 207 | CPUFREQ_IS_COOLING_DEV, | ||
| 226 | .verify = cpufreq_generic_frequency_table_verify, | 208 | .verify = cpufreq_generic_frequency_table_verify, |
| 227 | .target_index = imx6q_set_target, | 209 | .target_index = imx6q_set_target, |
| 228 | .get = cpufreq_generic_get, | 210 | .get = cpufreq_generic_get, |
| 229 | .init = imx6q_cpufreq_init, | 211 | .init = imx6q_cpufreq_init, |
| 230 | .exit = imx6q_cpufreq_exit, | ||
| 231 | .name = "imx6q-cpufreq", | 212 | .name = "imx6q-cpufreq", |
| 232 | .ready = imx6q_cpufreq_ready, | ||
| 233 | .attr = cpufreq_generic_attr, | 213 | .attr = cpufreq_generic_attr, |
| 234 | .suspend = cpufreq_generic_suspend, | 214 | .suspend = cpufreq_generic_suspend, |
| 235 | }; | 215 | }; |
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index dd66decf2087..002f5169d4eb 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c | |||
| @@ -50,6 +50,8 @@ | |||
| 50 | #define int_tofp(X) ((int64_t)(X) << FRAC_BITS) | 50 | #define int_tofp(X) ((int64_t)(X) << FRAC_BITS) |
| 51 | #define fp_toint(X) ((X) >> FRAC_BITS) | 51 | #define fp_toint(X) ((X) >> FRAC_BITS) |
| 52 | 52 | ||
| 53 | #define ONE_EIGHTH_FP ((int64_t)1 << (FRAC_BITS - 3)) | ||
| 54 | |||
| 53 | #define EXT_BITS 6 | 55 | #define EXT_BITS 6 |
| 54 | #define EXT_FRAC_BITS (EXT_BITS + FRAC_BITS) | 56 | #define EXT_FRAC_BITS (EXT_BITS + FRAC_BITS) |
| 55 | #define fp_ext_toint(X) ((X) >> EXT_FRAC_BITS) | 57 | #define fp_ext_toint(X) ((X) >> EXT_FRAC_BITS) |
| @@ -895,7 +897,7 @@ static void intel_pstate_update_policies(void) | |||
| 895 | /************************** sysfs begin ************************/ | 897 | /************************** sysfs begin ************************/ |
| 896 | #define show_one(file_name, object) \ | 898 | #define show_one(file_name, object) \ |
| 897 | static ssize_t show_##file_name \ | 899 | static ssize_t show_##file_name \ |
| 898 | (struct kobject *kobj, struct attribute *attr, char *buf) \ | 900 | (struct kobject *kobj, struct kobj_attribute *attr, char *buf) \ |
| 899 | { \ | 901 | { \ |
| 900 | return sprintf(buf, "%u\n", global.object); \ | 902 | return sprintf(buf, "%u\n", global.object); \ |
| 901 | } | 903 | } |
| @@ -904,7 +906,7 @@ static ssize_t intel_pstate_show_status(char *buf); | |||
| 904 | static int intel_pstate_update_status(const char *buf, size_t size); | 906 | static int intel_pstate_update_status(const char *buf, size_t size); |
| 905 | 907 | ||
| 906 | static ssize_t show_status(struct kobject *kobj, | 908 | static ssize_t show_status(struct kobject *kobj, |
| 907 | struct attribute *attr, char *buf) | 909 | struct kobj_attribute *attr, char *buf) |
| 908 | { | 910 | { |
| 909 | ssize_t ret; | 911 | ssize_t ret; |
| 910 | 912 | ||
| @@ -915,7 +917,7 @@ static ssize_t show_status(struct kobject *kobj, | |||
| 915 | return ret; | 917 | return ret; |
| 916 | } | 918 | } |
| 917 | 919 | ||
| 918 | static ssize_t store_status(struct kobject *a, struct attribute *b, | 920 | static ssize_t store_status(struct kobject *a, struct kobj_attribute *b, |
| 919 | const char *buf, size_t count) | 921 | const char *buf, size_t count) |
| 920 | { | 922 | { |
| 921 | char *p = memchr(buf, '\n', count); | 923 | char *p = memchr(buf, '\n', count); |
| @@ -929,7 +931,7 @@ static ssize_t store_status(struct kobject *a, struct attribute *b, | |||
| 929 | } | 931 | } |
| 930 | 932 | ||
| 931 | static ssize_t show_turbo_pct(struct kobject *kobj, | 933 | static ssize_t show_turbo_pct(struct kobject *kobj, |
| 932 | struct attribute *attr, char *buf) | 934 | struct kobj_attribute *attr, char *buf) |
| 933 | { | 935 | { |
| 934 | struct cpudata *cpu; | 936 | struct cpudata *cpu; |
| 935 | int total, no_turbo, turbo_pct; | 937 | int total, no_turbo, turbo_pct; |
| @@ -955,7 +957,7 @@ static ssize_t show_turbo_pct(struct kobject *kobj, | |||
| 955 | } | 957 | } |
| 956 | 958 | ||
| 957 | static ssize_t show_num_pstates(struct kobject *kobj, | 959 | static ssize_t show_num_pstates(struct kobject *kobj, |
| 958 | struct attribute *attr, char *buf) | 960 | struct kobj_attribute *attr, char *buf) |
| 959 | { | 961 | { |
| 960 | struct cpudata *cpu; | 962 | struct cpudata *cpu; |
| 961 | int total; | 963 | int total; |
| @@ -976,7 +978,7 @@ static ssize_t show_num_pstates(struct kobject *kobj, | |||
| 976 | } | 978 | } |
| 977 | 979 | ||
| 978 | static ssize_t show_no_turbo(struct kobject *kobj, | 980 | static ssize_t show_no_turbo(struct kobject *kobj, |
| 979 | struct attribute *attr, char *buf) | 981 | struct kobj_attribute *attr, char *buf) |
| 980 | { | 982 | { |
| 981 | ssize_t ret; | 983 | ssize_t ret; |
| 982 | 984 | ||
| @@ -998,7 +1000,7 @@ static ssize_t show_no_turbo(struct kobject *kobj, | |||
| 998 | return ret; | 1000 | return ret; |
| 999 | } | 1001 | } |
| 1000 | 1002 | ||
| 1001 | static ssize_t store_no_turbo(struct kobject *a, struct attribute *b, | 1003 | static ssize_t store_no_turbo(struct kobject *a, struct kobj_attribute *b, |
| 1002 | const char *buf, size_t count) | 1004 | const char *buf, size_t count) |
| 1003 | { | 1005 | { |
| 1004 | unsigned int input; | 1006 | unsigned int input; |
| @@ -1045,7 +1047,7 @@ static ssize_t store_no_turbo(struct kobject *a, struct attribute *b, | |||
| 1045 | return count; | 1047 | return count; |
| 1046 | } | 1048 | } |
| 1047 | 1049 | ||
| 1048 | static ssize_t store_max_perf_pct(struct kobject *a, struct attribute *b, | 1050 | static ssize_t store_max_perf_pct(struct kobject *a, struct kobj_attribute *b, |
| 1049 | const char *buf, size_t count) | 1051 | const char *buf, size_t count) |
| 1050 | { | 1052 | { |
| 1051 | unsigned int input; | 1053 | unsigned int input; |
| @@ -1075,7 +1077,7 @@ static ssize_t store_max_perf_pct(struct kobject *a, struct attribute *b, | |||
| 1075 | return count; | 1077 | return count; |
| 1076 | } | 1078 | } |
| 1077 | 1079 | ||
| 1078 | static ssize_t store_min_perf_pct(struct kobject *a, struct attribute *b, | 1080 | static ssize_t store_min_perf_pct(struct kobject *a, struct kobj_attribute *b, |
| 1079 | const char *buf, size_t count) | 1081 | const char *buf, size_t count) |
| 1080 | { | 1082 | { |
| 1081 | unsigned int input; | 1083 | unsigned int input; |
| @@ -1107,12 +1109,13 @@ static ssize_t store_min_perf_pct(struct kobject *a, struct attribute *b, | |||
| 1107 | } | 1109 | } |
| 1108 | 1110 | ||
| 1109 | static ssize_t show_hwp_dynamic_boost(struct kobject *kobj, | 1111 | static ssize_t show_hwp_dynamic_boost(struct kobject *kobj, |
| 1110 | struct attribute *attr, char *buf) | 1112 | struct kobj_attribute *attr, char *buf) |
| 1111 | { | 1113 | { |
| 1112 | return sprintf(buf, "%u\n", hwp_boost); | 1114 | return sprintf(buf, "%u\n", hwp_boost); |
| 1113 | } | 1115 | } |
| 1114 | 1116 | ||
| 1115 | static ssize_t store_hwp_dynamic_boost(struct kobject *a, struct attribute *b, | 1117 | static ssize_t store_hwp_dynamic_boost(struct kobject *a, |
| 1118 | struct kobj_attribute *b, | ||
| 1116 | const char *buf, size_t count) | 1119 | const char *buf, size_t count) |
| 1117 | { | 1120 | { |
| 1118 | unsigned int input; | 1121 | unsigned int input; |
| @@ -1444,12 +1447,6 @@ static int knl_get_turbo_pstate(void) | |||
| 1444 | return ret; | 1447 | return ret; |
| 1445 | } | 1448 | } |
| 1446 | 1449 | ||
| 1447 | static int intel_pstate_get_base_pstate(struct cpudata *cpu) | ||
| 1448 | { | ||
| 1449 | return global.no_turbo || global.turbo_disabled ? | ||
| 1450 | cpu->pstate.max_pstate : cpu->pstate.turbo_pstate; | ||
| 1451 | } | ||
| 1452 | |||
| 1453 | static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate) | 1450 | static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate) |
| 1454 | { | 1451 | { |
| 1455 | trace_cpu_frequency(pstate * cpu->pstate.scaling, cpu->cpu); | 1452 | trace_cpu_frequency(pstate * cpu->pstate.scaling, cpu->cpu); |
| @@ -1470,11 +1467,9 @@ static void intel_pstate_set_min_pstate(struct cpudata *cpu) | |||
| 1470 | 1467 | ||
| 1471 | static void intel_pstate_max_within_limits(struct cpudata *cpu) | 1468 | static void intel_pstate_max_within_limits(struct cpudata *cpu) |
| 1472 | { | 1469 | { |
| 1473 | int pstate; | 1470 | int pstate = max(cpu->pstate.min_pstate, cpu->max_perf_ratio); |
| 1474 | 1471 | ||
| 1475 | update_turbo_state(); | 1472 | update_turbo_state(); |
| 1476 | pstate = intel_pstate_get_base_pstate(cpu); | ||
| 1477 | pstate = max(cpu->pstate.min_pstate, cpu->max_perf_ratio); | ||
| 1478 | intel_pstate_set_pstate(cpu, pstate); | 1473 | intel_pstate_set_pstate(cpu, pstate); |
| 1479 | } | 1474 | } |
| 1480 | 1475 | ||
| @@ -1678,17 +1673,14 @@ static inline int32_t get_avg_pstate(struct cpudata *cpu) | |||
| 1678 | static inline int32_t get_target_pstate(struct cpudata *cpu) | 1673 | static inline int32_t get_target_pstate(struct cpudata *cpu) |
| 1679 | { | 1674 | { |
| 1680 | struct sample *sample = &cpu->sample; | 1675 | struct sample *sample = &cpu->sample; |
| 1681 | int32_t busy_frac, boost; | 1676 | int32_t busy_frac; |
| 1682 | int target, avg_pstate; | 1677 | int target, avg_pstate; |
| 1683 | 1678 | ||
| 1684 | busy_frac = div_fp(sample->mperf << cpu->aperf_mperf_shift, | 1679 | busy_frac = div_fp(sample->mperf << cpu->aperf_mperf_shift, |
| 1685 | sample->tsc); | 1680 | sample->tsc); |
| 1686 | 1681 | ||
| 1687 | boost = cpu->iowait_boost; | 1682 | if (busy_frac < cpu->iowait_boost) |
| 1688 | cpu->iowait_boost >>= 1; | 1683 | busy_frac = cpu->iowait_boost; |
| 1689 | |||
| 1690 | if (busy_frac < boost) | ||
| 1691 | busy_frac = boost; | ||
| 1692 | 1684 | ||
| 1693 | sample->busy_scaled = busy_frac * 100; | 1685 | sample->busy_scaled = busy_frac * 100; |
| 1694 | 1686 | ||
| @@ -1715,11 +1707,9 @@ static inline int32_t get_target_pstate(struct cpudata *cpu) | |||
| 1715 | 1707 | ||
| 1716 | static int intel_pstate_prepare_request(struct cpudata *cpu, int pstate) | 1708 | static int intel_pstate_prepare_request(struct cpudata *cpu, int pstate) |
| 1717 | { | 1709 | { |
| 1718 | int max_pstate = intel_pstate_get_base_pstate(cpu); | 1710 | int min_pstate = max(cpu->pstate.min_pstate, cpu->min_perf_ratio); |
| 1719 | int min_pstate; | 1711 | int max_pstate = max(min_pstate, cpu->max_perf_ratio); |
| 1720 | 1712 | ||
| 1721 | min_pstate = max(cpu->pstate.min_pstate, cpu->min_perf_ratio); | ||
| 1722 | max_pstate = max(min_pstate, cpu->max_perf_ratio); | ||
| 1723 | return clamp_t(int, pstate, min_pstate, max_pstate); | 1713 | return clamp_t(int, pstate, min_pstate, max_pstate); |
| 1724 | } | 1714 | } |
| 1725 | 1715 | ||
| @@ -1767,29 +1757,30 @@ static void intel_pstate_update_util(struct update_util_data *data, u64 time, | |||
| 1767 | if (smp_processor_id() != cpu->cpu) | 1757 | if (smp_processor_id() != cpu->cpu) |
| 1768 | return; | 1758 | return; |
| 1769 | 1759 | ||
| 1760 | delta_ns = time - cpu->last_update; | ||
| 1770 | if (flags & SCHED_CPUFREQ_IOWAIT) { | 1761 | if (flags & SCHED_CPUFREQ_IOWAIT) { |
| 1771 | cpu->iowait_boost = int_tofp(1); | 1762 | /* Start over if the CPU may have been idle. */ |
| 1772 | cpu->last_update = time; | 1763 | if (delta_ns > TICK_NSEC) { |
| 1773 | /* | 1764 | cpu->iowait_boost = ONE_EIGHTH_FP; |
| 1774 | * The last time the busy was 100% so P-state was max anyway | 1765 | } else if (cpu->iowait_boost) { |
| 1775 | * so avoid overhead of computation. | 1766 | cpu->iowait_boost <<= 1; |
| 1776 | */ | 1767 | if (cpu->iowait_boost > int_tofp(1)) |
| 1777 | if (fp_toint(cpu->sample.busy_scaled) == 100) | 1768 | cpu->iowait_boost = int_tofp(1); |
| 1778 | return; | 1769 | } else { |
| 1779 | 1770 | cpu->iowait_boost = ONE_EIGHTH_FP; | |
| 1780 | goto set_pstate; | 1771 | } |
| 1781 | } else if (cpu->iowait_boost) { | 1772 | } else if (cpu->iowait_boost) { |
| 1782 | /* Clear iowait_boost if the CPU may have been idle. */ | 1773 | /* Clear iowait_boost if the CPU may have been idle. */ |
| 1783 | delta_ns = time - cpu->last_update; | ||
| 1784 | if (delta_ns > TICK_NSEC) | 1774 | if (delta_ns > TICK_NSEC) |
| 1785 | cpu->iowait_boost = 0; | 1775 | cpu->iowait_boost = 0; |
| 1776 | else | ||
| 1777 | cpu->iowait_boost >>= 1; | ||
| 1786 | } | 1778 | } |
| 1787 | cpu->last_update = time; | 1779 | cpu->last_update = time; |
| 1788 | delta_ns = time - cpu->sample.time; | 1780 | delta_ns = time - cpu->sample.time; |
| 1789 | if ((s64)delta_ns < INTEL_PSTATE_SAMPLING_INTERVAL) | 1781 | if ((s64)delta_ns < INTEL_PSTATE_SAMPLING_INTERVAL) |
| 1790 | return; | 1782 | return; |
| 1791 | 1783 | ||
| 1792 | set_pstate: | ||
| 1793 | if (intel_pstate_sample(cpu, time)) | 1784 | if (intel_pstate_sample(cpu, time)) |
| 1794 | intel_pstate_adjust_pstate(cpu); | 1785 | intel_pstate_adjust_pstate(cpu); |
| 1795 | } | 1786 | } |
| @@ -1976,7 +1967,8 @@ static void intel_pstate_update_perf_limits(struct cpufreq_policy *policy, | |||
| 1976 | if (hwp_active) { | 1967 | if (hwp_active) { |
| 1977 | intel_pstate_get_hwp_max(cpu->cpu, &turbo_max, &max_state); | 1968 | intel_pstate_get_hwp_max(cpu->cpu, &turbo_max, &max_state); |
| 1978 | } else { | 1969 | } else { |
| 1979 | max_state = intel_pstate_get_base_pstate(cpu); | 1970 | max_state = global.no_turbo || global.turbo_disabled ? |
| 1971 | cpu->pstate.max_pstate : cpu->pstate.turbo_pstate; | ||
| 1980 | turbo_max = cpu->pstate.turbo_pstate; | 1972 | turbo_max = cpu->pstate.turbo_pstate; |
| 1981 | } | 1973 | } |
| 1982 | 1974 | ||
| @@ -2475,6 +2467,7 @@ static bool __init intel_pstate_no_acpi_pss(void) | |||
| 2475 | kfree(pss); | 2467 | kfree(pss); |
| 2476 | } | 2468 | } |
| 2477 | 2469 | ||
| 2470 | pr_debug("ACPI _PSS not found\n"); | ||
| 2478 | return true; | 2471 | return true; |
| 2479 | } | 2472 | } |
| 2480 | 2473 | ||
| @@ -2485,9 +2478,14 @@ static bool __init intel_pstate_no_acpi_pcch(void) | |||
| 2485 | 2478 | ||
| 2486 | status = acpi_get_handle(NULL, "\\_SB", &handle); | 2479 | status = acpi_get_handle(NULL, "\\_SB", &handle); |
| 2487 | if (ACPI_FAILURE(status)) | 2480 | if (ACPI_FAILURE(status)) |
| 2488 | return true; | 2481 | goto not_found; |
| 2482 | |||
| 2483 | if (acpi_has_method(handle, "PCCH")) | ||
| 2484 | return false; | ||
| 2489 | 2485 | ||
| 2490 | return !acpi_has_method(handle, "PCCH"); | 2486 | not_found: |
| 2487 | pr_debug("ACPI PCCH not found\n"); | ||
| 2488 | return true; | ||
| 2491 | } | 2489 | } |
| 2492 | 2490 | ||
| 2493 | static bool __init intel_pstate_has_acpi_ppc(void) | 2491 | static bool __init intel_pstate_has_acpi_ppc(void) |
| @@ -2502,6 +2500,7 @@ static bool __init intel_pstate_has_acpi_ppc(void) | |||
| 2502 | if (acpi_has_method(pr->handle, "_PPC")) | 2500 | if (acpi_has_method(pr->handle, "_PPC")) |
| 2503 | return true; | 2501 | return true; |
| 2504 | } | 2502 | } |
| 2503 | pr_debug("ACPI _PPC not found\n"); | ||
| 2505 | return false; | 2504 | return false; |
| 2506 | } | 2505 | } |
| 2507 | 2506 | ||
| @@ -2539,8 +2538,10 @@ static bool __init intel_pstate_platform_pwr_mgmt_exists(void) | |||
| 2539 | id = x86_match_cpu(intel_pstate_cpu_oob_ids); | 2538 | id = x86_match_cpu(intel_pstate_cpu_oob_ids); |
| 2540 | if (id) { | 2539 | if (id) { |
| 2541 | rdmsrl(MSR_MISC_PWR_MGMT, misc_pwr); | 2540 | rdmsrl(MSR_MISC_PWR_MGMT, misc_pwr); |
| 2542 | if ( misc_pwr & (1 << 8)) | 2541 | if (misc_pwr & (1 << 8)) { |
| 2542 | pr_debug("Bit 8 in the MISC_PWR_MGMT MSR set\n"); | ||
| 2543 | return true; | 2543 | return true; |
| 2544 | } | ||
| 2544 | } | 2545 | } |
| 2545 | 2546 | ||
| 2546 | idx = acpi_match_platform_list(plat_info); | 2547 | idx = acpi_match_platform_list(plat_info); |
| @@ -2606,22 +2607,28 @@ static int __init intel_pstate_init(void) | |||
| 2606 | } | 2607 | } |
| 2607 | } else { | 2608 | } else { |
| 2608 | id = x86_match_cpu(intel_pstate_cpu_ids); | 2609 | id = x86_match_cpu(intel_pstate_cpu_ids); |
| 2609 | if (!id) | 2610 | if (!id) { |
| 2611 | pr_info("CPU ID not supported\n"); | ||
| 2610 | return -ENODEV; | 2612 | return -ENODEV; |
| 2613 | } | ||
| 2611 | 2614 | ||
| 2612 | copy_cpu_funcs((struct pstate_funcs *)id->driver_data); | 2615 | copy_cpu_funcs((struct pstate_funcs *)id->driver_data); |
| 2613 | } | 2616 | } |
| 2614 | 2617 | ||
| 2615 | if (intel_pstate_msrs_not_valid()) | 2618 | if (intel_pstate_msrs_not_valid()) { |
| 2619 | pr_info("Invalid MSRs\n"); | ||
| 2616 | return -ENODEV; | 2620 | return -ENODEV; |
| 2621 | } | ||
| 2617 | 2622 | ||
| 2618 | hwp_cpu_matched: | 2623 | hwp_cpu_matched: |
| 2619 | /* | 2624 | /* |
| 2620 | * The Intel pstate driver will be ignored if the platform | 2625 | * The Intel pstate driver will be ignored if the platform |
| 2621 | * firmware has its own power management modes. | 2626 | * firmware has its own power management modes. |
| 2622 | */ | 2627 | */ |
| 2623 | if (intel_pstate_platform_pwr_mgmt_exists()) | 2628 | if (intel_pstate_platform_pwr_mgmt_exists()) { |
| 2629 | pr_info("P-states controlled by the platform\n"); | ||
| 2624 | return -ENODEV; | 2630 | return -ENODEV; |
| 2631 | } | ||
| 2625 | 2632 | ||
| 2626 | if (!hwp_active && hwp_only) | 2633 | if (!hwp_active && hwp_only) |
| 2627 | return -ENOTSUPP; | 2634 | return -ENOTSUPP; |
diff --git a/drivers/cpufreq/longhaul.c b/drivers/cpufreq/longhaul.c index 279bd9e9fa95..fb546e0d0356 100644 --- a/drivers/cpufreq/longhaul.c +++ b/drivers/cpufreq/longhaul.c | |||
| @@ -851,7 +851,7 @@ static int longhaul_cpu_init(struct cpufreq_policy *policy) | |||
| 851 | case TYPE_POWERSAVER: | 851 | case TYPE_POWERSAVER: |
| 852 | pr_cont("Powersaver supported\n"); | 852 | pr_cont("Powersaver supported\n"); |
| 853 | break; | 853 | break; |
| 854 | }; | 854 | } |
| 855 | 855 | ||
| 856 | /* Doesn't hurt */ | 856 | /* Doesn't hurt */ |
| 857 | longhaul_setup_southbridge(); | 857 | longhaul_setup_southbridge(); |
diff --git a/drivers/cpufreq/mediatek-cpufreq.c b/drivers/cpufreq/mediatek-cpufreq.c index eb8920d39818..4229fcc31310 100644 --- a/drivers/cpufreq/mediatek-cpufreq.c +++ b/drivers/cpufreq/mediatek-cpufreq.c | |||
| @@ -14,7 +14,6 @@ | |||
| 14 | 14 | ||
| 15 | #include <linux/clk.h> | 15 | #include <linux/clk.h> |
| 16 | #include <linux/cpu.h> | 16 | #include <linux/cpu.h> |
| 17 | #include <linux/cpu_cooling.h> | ||
| 18 | #include <linux/cpufreq.h> | 17 | #include <linux/cpufreq.h> |
| 19 | #include <linux/cpumask.h> | 18 | #include <linux/cpumask.h> |
| 20 | #include <linux/module.h> | 19 | #include <linux/module.h> |
| @@ -48,7 +47,6 @@ struct mtk_cpu_dvfs_info { | |||
| 48 | struct regulator *sram_reg; | 47 | struct regulator *sram_reg; |
| 49 | struct clk *cpu_clk; | 48 | struct clk *cpu_clk; |
| 50 | struct clk *inter_clk; | 49 | struct clk *inter_clk; |
| 51 | struct thermal_cooling_device *cdev; | ||
| 52 | struct list_head list_head; | 50 | struct list_head list_head; |
| 53 | int intermediate_voltage; | 51 | int intermediate_voltage; |
| 54 | bool need_voltage_tracking; | 52 | bool need_voltage_tracking; |
| @@ -307,13 +305,6 @@ static int mtk_cpufreq_set_target(struct cpufreq_policy *policy, | |||
| 307 | 305 | ||
| 308 | #define DYNAMIC_POWER "dynamic-power-coefficient" | 306 | #define DYNAMIC_POWER "dynamic-power-coefficient" |
| 309 | 307 | ||
| 310 | static void mtk_cpufreq_ready(struct cpufreq_policy *policy) | ||
| 311 | { | ||
| 312 | struct mtk_cpu_dvfs_info *info = policy->driver_data; | ||
| 313 | |||
| 314 | info->cdev = of_cpufreq_cooling_register(policy); | ||
| 315 | } | ||
| 316 | |||
| 317 | static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu) | 308 | static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu) |
| 318 | { | 309 | { |
| 319 | struct device *cpu_dev; | 310 | struct device *cpu_dev; |
| @@ -472,7 +463,6 @@ static int mtk_cpufreq_exit(struct cpufreq_policy *policy) | |||
| 472 | { | 463 | { |
| 473 | struct mtk_cpu_dvfs_info *info = policy->driver_data; | 464 | struct mtk_cpu_dvfs_info *info = policy->driver_data; |
| 474 | 465 | ||
| 475 | cpufreq_cooling_unregister(info->cdev); | ||
| 476 | dev_pm_opp_free_cpufreq_table(info->cpu_dev, &policy->freq_table); | 466 | dev_pm_opp_free_cpufreq_table(info->cpu_dev, &policy->freq_table); |
| 477 | 467 | ||
| 478 | return 0; | 468 | return 0; |
| @@ -480,13 +470,13 @@ static int mtk_cpufreq_exit(struct cpufreq_policy *policy) | |||
| 480 | 470 | ||
| 481 | static struct cpufreq_driver mtk_cpufreq_driver = { | 471 | static struct cpufreq_driver mtk_cpufreq_driver = { |
| 482 | .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK | | 472 | .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK | |
| 483 | CPUFREQ_HAVE_GOVERNOR_PER_POLICY, | 473 | CPUFREQ_HAVE_GOVERNOR_PER_POLICY | |
| 474 | CPUFREQ_IS_COOLING_DEV, | ||
| 484 | .verify = cpufreq_generic_frequency_table_verify, | 475 | .verify = cpufreq_generic_frequency_table_verify, |
| 485 | .target_index = mtk_cpufreq_set_target, | 476 | .target_index = mtk_cpufreq_set_target, |
| 486 | .get = cpufreq_generic_get, | 477 | .get = cpufreq_generic_get, |
| 487 | .init = mtk_cpufreq_init, | 478 | .init = mtk_cpufreq_init, |
| 488 | .exit = mtk_cpufreq_exit, | 479 | .exit = mtk_cpufreq_exit, |
| 489 | .ready = mtk_cpufreq_ready, | ||
| 490 | .name = "mtk-cpufreq", | 480 | .name = "mtk-cpufreq", |
| 491 | .attr = cpufreq_generic_attr, | 481 | .attr = cpufreq_generic_attr, |
| 492 | }; | 482 | }; |
diff --git a/drivers/cpufreq/pcc-cpufreq.c b/drivers/cpufreq/pcc-cpufreq.c index 099a849396f6..1e5e64643c3a 100644 --- a/drivers/cpufreq/pcc-cpufreq.c +++ b/drivers/cpufreq/pcc-cpufreq.c | |||
| @@ -268,7 +268,7 @@ static int pcc_get_offset(int cpu) | |||
| 268 | if (!pccp || pccp->type != ACPI_TYPE_PACKAGE) { | 268 | if (!pccp || pccp->type != ACPI_TYPE_PACKAGE) { |
| 269 | ret = -ENODEV; | 269 | ret = -ENODEV; |
| 270 | goto out_free; | 270 | goto out_free; |
| 271 | }; | 271 | } |
| 272 | 272 | ||
| 273 | offset = &(pccp->package.elements[0]); | 273 | offset = &(pccp->package.elements[0]); |
| 274 | if (!offset || offset->type != ACPI_TYPE_INTEGER) { | 274 | if (!offset || offset->type != ACPI_TYPE_INTEGER) { |
diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c index 7e7ad3879c4e..d2230812fa4b 100644 --- a/drivers/cpufreq/powernv-cpufreq.c +++ b/drivers/cpufreq/powernv-cpufreq.c | |||
| @@ -244,6 +244,7 @@ static int init_powernv_pstates(void) | |||
| 244 | u32 len_ids, len_freqs; | 244 | u32 len_ids, len_freqs; |
| 245 | u32 pstate_min, pstate_max, pstate_nominal; | 245 | u32 pstate_min, pstate_max, pstate_nominal; |
| 246 | u32 pstate_turbo, pstate_ultra_turbo; | 246 | u32 pstate_turbo, pstate_ultra_turbo; |
| 247 | int rc = -ENODEV; | ||
| 247 | 248 | ||
| 248 | power_mgt = of_find_node_by_path("/ibm,opal/power-mgt"); | 249 | power_mgt = of_find_node_by_path("/ibm,opal/power-mgt"); |
| 249 | if (!power_mgt) { | 250 | if (!power_mgt) { |
| @@ -327,8 +328,11 @@ next: | |||
| 327 | powernv_freqs[i].frequency = freq * 1000; /* kHz */ | 328 | powernv_freqs[i].frequency = freq * 1000; /* kHz */ |
| 328 | powernv_freqs[i].driver_data = id & 0xFF; | 329 | powernv_freqs[i].driver_data = id & 0xFF; |
| 329 | 330 | ||
| 330 | revmap_data = (struct pstate_idx_revmap_data *) | 331 | revmap_data = kmalloc(sizeof(*revmap_data), GFP_KERNEL); |
| 331 | kmalloc(sizeof(*revmap_data), GFP_KERNEL); | 332 | if (!revmap_data) { |
| 333 | rc = -ENOMEM; | ||
| 334 | goto out; | ||
| 335 | } | ||
| 332 | 336 | ||
| 333 | revmap_data->pstate_id = id & 0xFF; | 337 | revmap_data->pstate_id = id & 0xFF; |
| 334 | revmap_data->cpufreq_table_idx = i; | 338 | revmap_data->cpufreq_table_idx = i; |
| @@ -357,7 +361,7 @@ next: | |||
| 357 | return 0; | 361 | return 0; |
| 358 | out: | 362 | out: |
| 359 | of_node_put(power_mgt); | 363 | of_node_put(power_mgt); |
| 360 | return -ENODEV; | 364 | return rc; |
| 361 | } | 365 | } |
| 362 | 366 | ||
| 363 | /* Returns the CPU frequency corresponding to the pstate_id. */ | 367 | /* Returns the CPU frequency corresponding to the pstate_id. */ |
diff --git a/drivers/cpufreq/qcom-cpufreq-hw.c b/drivers/cpufreq/qcom-cpufreq-hw.c index d83939a1b3d4..4b0b50403901 100644 --- a/drivers/cpufreq/qcom-cpufreq-hw.c +++ b/drivers/cpufreq/qcom-cpufreq-hw.c | |||
| @@ -10,18 +10,21 @@ | |||
| 10 | #include <linux/module.h> | 10 | #include <linux/module.h> |
| 11 | #include <linux/of_address.h> | 11 | #include <linux/of_address.h> |
| 12 | #include <linux/of_platform.h> | 12 | #include <linux/of_platform.h> |
| 13 | #include <linux/pm_opp.h> | ||
| 13 | #include <linux/slab.h> | 14 | #include <linux/slab.h> |
| 14 | 15 | ||
| 15 | #define LUT_MAX_ENTRIES 40U | 16 | #define LUT_MAX_ENTRIES 40U |
| 16 | #define LUT_SRC GENMASK(31, 30) | 17 | #define LUT_SRC GENMASK(31, 30) |
| 17 | #define LUT_L_VAL GENMASK(7, 0) | 18 | #define LUT_L_VAL GENMASK(7, 0) |
| 18 | #define LUT_CORE_COUNT GENMASK(18, 16) | 19 | #define LUT_CORE_COUNT GENMASK(18, 16) |
| 20 | #define LUT_VOLT GENMASK(11, 0) | ||
| 19 | #define LUT_ROW_SIZE 32 | 21 | #define LUT_ROW_SIZE 32 |
| 20 | #define CLK_HW_DIV 2 | 22 | #define CLK_HW_DIV 2 |
| 21 | 23 | ||
| 22 | /* Register offsets */ | 24 | /* Register offsets */ |
| 23 | #define REG_ENABLE 0x0 | 25 | #define REG_ENABLE 0x0 |
| 24 | #define REG_LUT_TABLE 0x110 | 26 | #define REG_FREQ_LUT 0x110 |
| 27 | #define REG_VOLT_LUT 0x114 | ||
| 25 | #define REG_PERF_STATE 0x920 | 28 | #define REG_PERF_STATE 0x920 |
| 26 | 29 | ||
| 27 | static unsigned long cpu_hw_rate, xo_rate; | 30 | static unsigned long cpu_hw_rate, xo_rate; |
| @@ -70,11 +73,12 @@ static unsigned int qcom_cpufreq_hw_fast_switch(struct cpufreq_policy *policy, | |||
| 70 | return policy->freq_table[index].frequency; | 73 | return policy->freq_table[index].frequency; |
| 71 | } | 74 | } |
| 72 | 75 | ||
| 73 | static int qcom_cpufreq_hw_read_lut(struct device *dev, | 76 | static int qcom_cpufreq_hw_read_lut(struct device *cpu_dev, |
| 74 | struct cpufreq_policy *policy, | 77 | struct cpufreq_policy *policy, |
| 75 | void __iomem *base) | 78 | void __iomem *base) |
| 76 | { | 79 | { |
| 77 | u32 data, src, lval, i, core_count, prev_cc = 0, prev_freq = 0, freq; | 80 | u32 data, src, lval, i, core_count, prev_cc = 0, prev_freq = 0, freq; |
| 81 | u32 volt; | ||
| 78 | unsigned int max_cores = cpumask_weight(policy->cpus); | 82 | unsigned int max_cores = cpumask_weight(policy->cpus); |
| 79 | struct cpufreq_frequency_table *table; | 83 | struct cpufreq_frequency_table *table; |
| 80 | 84 | ||
| @@ -83,23 +87,28 @@ static int qcom_cpufreq_hw_read_lut(struct device *dev, | |||
| 83 | return -ENOMEM; | 87 | return -ENOMEM; |
| 84 | 88 | ||
| 85 | for (i = 0; i < LUT_MAX_ENTRIES; i++) { | 89 | for (i = 0; i < LUT_MAX_ENTRIES; i++) { |
| 86 | data = readl_relaxed(base + REG_LUT_TABLE + i * LUT_ROW_SIZE); | 90 | data = readl_relaxed(base + REG_FREQ_LUT + |
| 91 | i * LUT_ROW_SIZE); | ||
| 87 | src = FIELD_GET(LUT_SRC, data); | 92 | src = FIELD_GET(LUT_SRC, data); |
| 88 | lval = FIELD_GET(LUT_L_VAL, data); | 93 | lval = FIELD_GET(LUT_L_VAL, data); |
| 89 | core_count = FIELD_GET(LUT_CORE_COUNT, data); | 94 | core_count = FIELD_GET(LUT_CORE_COUNT, data); |
| 90 | 95 | ||
| 96 | data = readl_relaxed(base + REG_VOLT_LUT + | ||
| 97 | i * LUT_ROW_SIZE); | ||
| 98 | volt = FIELD_GET(LUT_VOLT, data) * 1000; | ||
| 99 | |||
| 91 | if (src) | 100 | if (src) |
| 92 | freq = xo_rate * lval / 1000; | 101 | freq = xo_rate * lval / 1000; |
| 93 | else | 102 | else |
| 94 | freq = cpu_hw_rate / 1000; | 103 | freq = cpu_hw_rate / 1000; |
| 95 | 104 | ||
| 96 | /* Ignore boosts in the middle of the table */ | 105 | if (freq != prev_freq && core_count == max_cores) { |
| 97 | if (core_count != max_cores) { | ||
| 98 | table[i].frequency = CPUFREQ_ENTRY_INVALID; | ||
| 99 | } else { | ||
| 100 | table[i].frequency = freq; | 106 | table[i].frequency = freq; |
| 101 | dev_dbg(dev, "index=%d freq=%d, core_count %d\n", i, | 107 | dev_pm_opp_add(cpu_dev, freq * 1000, volt); |
| 108 | dev_dbg(cpu_dev, "index=%d freq=%d, core_count %d\n", i, | ||
| 102 | freq, core_count); | 109 | freq, core_count); |
| 110 | } else { | ||
| 111 | table[i].frequency = CPUFREQ_ENTRY_INVALID; | ||
| 103 | } | 112 | } |
| 104 | 113 | ||
| 105 | /* | 114 | /* |
| @@ -116,6 +125,7 @@ static int qcom_cpufreq_hw_read_lut(struct device *dev, | |||
| 116 | if (prev_cc != max_cores) { | 125 | if (prev_cc != max_cores) { |
| 117 | prev->frequency = prev_freq; | 126 | prev->frequency = prev_freq; |
| 118 | prev->flags = CPUFREQ_BOOST_FREQ; | 127 | prev->flags = CPUFREQ_BOOST_FREQ; |
| 128 | dev_pm_opp_add(cpu_dev, prev_freq * 1000, volt); | ||
| 119 | } | 129 | } |
| 120 | 130 | ||
| 121 | break; | 131 | break; |
| @@ -127,6 +137,7 @@ static int qcom_cpufreq_hw_read_lut(struct device *dev, | |||
| 127 | 137 | ||
| 128 | table[i].frequency = CPUFREQ_TABLE_END; | 138 | table[i].frequency = CPUFREQ_TABLE_END; |
| 129 | policy->freq_table = table; | 139 | policy->freq_table = table; |
| 140 | dev_pm_opp_set_sharing_cpus(cpu_dev, policy->cpus); | ||
| 130 | 141 | ||
| 131 | return 0; | 142 | return 0; |
| 132 | } | 143 | } |
| @@ -159,10 +170,18 @@ static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy) | |||
| 159 | struct device *dev = &global_pdev->dev; | 170 | struct device *dev = &global_pdev->dev; |
| 160 | struct of_phandle_args args; | 171 | struct of_phandle_args args; |
| 161 | struct device_node *cpu_np; | 172 | struct device_node *cpu_np; |
| 173 | struct device *cpu_dev; | ||
| 162 | struct resource *res; | 174 | struct resource *res; |
| 163 | void __iomem *base; | 175 | void __iomem *base; |
| 164 | int ret, index; | 176 | int ret, index; |
| 165 | 177 | ||
| 178 | cpu_dev = get_cpu_device(policy->cpu); | ||
| 179 | if (!cpu_dev) { | ||
| 180 | pr_err("%s: failed to get cpu%d device\n", __func__, | ||
| 181 | policy->cpu); | ||
| 182 | return -ENODEV; | ||
| 183 | } | ||
| 184 | |||
| 166 | cpu_np = of_cpu_device_node_get(policy->cpu); | 185 | cpu_np = of_cpu_device_node_get(policy->cpu); |
| 167 | if (!cpu_np) | 186 | if (!cpu_np) |
| 168 | return -EINVAL; | 187 | return -EINVAL; |
| @@ -199,12 +218,21 @@ static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy) | |||
| 199 | 218 | ||
| 200 | policy->driver_data = base + REG_PERF_STATE; | 219 | policy->driver_data = base + REG_PERF_STATE; |
| 201 | 220 | ||
| 202 | ret = qcom_cpufreq_hw_read_lut(dev, policy, base); | 221 | ret = qcom_cpufreq_hw_read_lut(cpu_dev, policy, base); |
| 203 | if (ret) { | 222 | if (ret) { |
| 204 | dev_err(dev, "Domain-%d failed to read LUT\n", index); | 223 | dev_err(dev, "Domain-%d failed to read LUT\n", index); |
| 205 | goto error; | 224 | goto error; |
| 206 | } | 225 | } |
| 207 | 226 | ||
| 227 | ret = dev_pm_opp_get_opp_count(cpu_dev); | ||
| 228 | if (ret <= 0) { | ||
| 229 | dev_err(cpu_dev, "Failed to add OPPs\n"); | ||
| 230 | ret = -ENODEV; | ||
| 231 | goto error; | ||
| 232 | } | ||
| 233 | |||
| 234 | dev_pm_opp_of_register_em(policy->cpus); | ||
| 235 | |||
| 208 | policy->fast_switch_possible = true; | 236 | policy->fast_switch_possible = true; |
| 209 | 237 | ||
| 210 | return 0; | 238 | return 0; |
| @@ -215,8 +243,10 @@ error: | |||
| 215 | 243 | ||
| 216 | static int qcom_cpufreq_hw_cpu_exit(struct cpufreq_policy *policy) | 244 | static int qcom_cpufreq_hw_cpu_exit(struct cpufreq_policy *policy) |
| 217 | { | 245 | { |
| 246 | struct device *cpu_dev = get_cpu_device(policy->cpu); | ||
| 218 | void __iomem *base = policy->driver_data - REG_PERF_STATE; | 247 | void __iomem *base = policy->driver_data - REG_PERF_STATE; |
| 219 | 248 | ||
| 249 | dev_pm_opp_remove_all_dynamic(cpu_dev); | ||
| 220 | kfree(policy->freq_table); | 250 | kfree(policy->freq_table); |
| 221 | devm_iounmap(&global_pdev->dev, base); | 251 | devm_iounmap(&global_pdev->dev, base); |
| 222 | 252 | ||
| @@ -231,7 +261,8 @@ static struct freq_attr *qcom_cpufreq_hw_attr[] = { | |||
| 231 | 261 | ||
| 232 | static struct cpufreq_driver cpufreq_qcom_hw_driver = { | 262 | static struct cpufreq_driver cpufreq_qcom_hw_driver = { |
| 233 | .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK | | 263 | .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK | |
| 234 | CPUFREQ_HAVE_GOVERNOR_PER_POLICY, | 264 | CPUFREQ_HAVE_GOVERNOR_PER_POLICY | |
| 265 | CPUFREQ_IS_COOLING_DEV, | ||
| 235 | .verify = cpufreq_generic_frequency_table_verify, | 266 | .verify = cpufreq_generic_frequency_table_verify, |
| 236 | .target_index = qcom_cpufreq_hw_target_index, | 267 | .target_index = qcom_cpufreq_hw_target_index, |
| 237 | .get = qcom_cpufreq_hw_get, | 268 | .get = qcom_cpufreq_hw_get, |
| @@ -296,7 +327,7 @@ static int __init qcom_cpufreq_hw_init(void) | |||
| 296 | { | 327 | { |
| 297 | return platform_driver_register(&qcom_cpufreq_hw_driver); | 328 | return platform_driver_register(&qcom_cpufreq_hw_driver); |
| 298 | } | 329 | } |
| 299 | subsys_initcall(qcom_cpufreq_hw_init); | 330 | device_initcall(qcom_cpufreq_hw_init); |
| 300 | 331 | ||
| 301 | static void __exit qcom_cpufreq_hw_exit(void) | 332 | static void __exit qcom_cpufreq_hw_exit(void) |
| 302 | { | 333 | { |
diff --git a/drivers/cpufreq/qcom-cpufreq-kryo.c b/drivers/cpufreq/qcom-cpufreq-kryo.c index 2a3675c24032..dd64dcf89c74 100644 --- a/drivers/cpufreq/qcom-cpufreq-kryo.c +++ b/drivers/cpufreq/qcom-cpufreq-kryo.c | |||
| @@ -42,7 +42,7 @@ enum _msm8996_version { | |||
| 42 | NUM_OF_MSM8996_VERSIONS, | 42 | NUM_OF_MSM8996_VERSIONS, |
| 43 | }; | 43 | }; |
| 44 | 44 | ||
| 45 | struct platform_device *cpufreq_dt_pdev, *kryo_cpufreq_pdev; | 45 | static struct platform_device *cpufreq_dt_pdev, *kryo_cpufreq_pdev; |
| 46 | 46 | ||
| 47 | static enum _msm8996_version qcom_cpufreq_kryo_get_msm_id(void) | 47 | static enum _msm8996_version qcom_cpufreq_kryo_get_msm_id(void) |
| 48 | { | 48 | { |
| @@ -75,7 +75,7 @@ static enum _msm8996_version qcom_cpufreq_kryo_get_msm_id(void) | |||
| 75 | 75 | ||
| 76 | static int qcom_cpufreq_kryo_probe(struct platform_device *pdev) | 76 | static int qcom_cpufreq_kryo_probe(struct platform_device *pdev) |
| 77 | { | 77 | { |
| 78 | struct opp_table *opp_tables[NR_CPUS] = {0}; | 78 | struct opp_table **opp_tables; |
| 79 | enum _msm8996_version msm8996_version; | 79 | enum _msm8996_version msm8996_version; |
| 80 | struct nvmem_cell *speedbin_nvmem; | 80 | struct nvmem_cell *speedbin_nvmem; |
| 81 | struct device_node *np; | 81 | struct device_node *np; |
| @@ -133,6 +133,10 @@ static int qcom_cpufreq_kryo_probe(struct platform_device *pdev) | |||
| 133 | } | 133 | } |
| 134 | kfree(speedbin); | 134 | kfree(speedbin); |
| 135 | 135 | ||
| 136 | opp_tables = kcalloc(num_possible_cpus(), sizeof(*opp_tables), GFP_KERNEL); | ||
| 137 | if (!opp_tables) | ||
| 138 | return -ENOMEM; | ||
| 139 | |||
| 136 | for_each_possible_cpu(cpu) { | 140 | for_each_possible_cpu(cpu) { |
| 137 | cpu_dev = get_cpu_device(cpu); | 141 | cpu_dev = get_cpu_device(cpu); |
| 138 | if (NULL == cpu_dev) { | 142 | if (NULL == cpu_dev) { |
| @@ -151,8 +155,10 @@ static int qcom_cpufreq_kryo_probe(struct platform_device *pdev) | |||
| 151 | 155 | ||
| 152 | cpufreq_dt_pdev = platform_device_register_simple("cpufreq-dt", -1, | 156 | cpufreq_dt_pdev = platform_device_register_simple("cpufreq-dt", -1, |
| 153 | NULL, 0); | 157 | NULL, 0); |
| 154 | if (!IS_ERR(cpufreq_dt_pdev)) | 158 | if (!IS_ERR(cpufreq_dt_pdev)) { |
| 159 | platform_set_drvdata(pdev, opp_tables); | ||
| 155 | return 0; | 160 | return 0; |
| 161 | } | ||
| 156 | 162 | ||
| 157 | ret = PTR_ERR(cpufreq_dt_pdev); | 163 | ret = PTR_ERR(cpufreq_dt_pdev); |
| 158 | dev_err(cpu_dev, "Failed to register platform device\n"); | 164 | dev_err(cpu_dev, "Failed to register platform device\n"); |
| @@ -163,13 +169,23 @@ free_opp: | |||
| 163 | break; | 169 | break; |
| 164 | dev_pm_opp_put_supported_hw(opp_tables[cpu]); | 170 | dev_pm_opp_put_supported_hw(opp_tables[cpu]); |
| 165 | } | 171 | } |
| 172 | kfree(opp_tables); | ||
| 166 | 173 | ||
| 167 | return ret; | 174 | return ret; |
| 168 | } | 175 | } |
| 169 | 176 | ||
| 170 | static int qcom_cpufreq_kryo_remove(struct platform_device *pdev) | 177 | static int qcom_cpufreq_kryo_remove(struct platform_device *pdev) |
| 171 | { | 178 | { |
| 179 | struct opp_table **opp_tables = platform_get_drvdata(pdev); | ||
| 180 | unsigned int cpu; | ||
| 181 | |||
| 172 | platform_device_unregister(cpufreq_dt_pdev); | 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 | |||
| 173 | return 0; | 189 | return 0; |
| 174 | } | 190 | } |
| 175 | 191 | ||
diff --git a/drivers/cpufreq/qoriq-cpufreq.c b/drivers/cpufreq/qoriq-cpufreq.c index 3d773f64b4df..4295e5476264 100644 --- a/drivers/cpufreq/qoriq-cpufreq.c +++ b/drivers/cpufreq/qoriq-cpufreq.c | |||
| @@ -13,7 +13,6 @@ | |||
| 13 | #include <linux/clk.h> | 13 | #include <linux/clk.h> |
| 14 | #include <linux/clk-provider.h> | 14 | #include <linux/clk-provider.h> |
| 15 | #include <linux/cpufreq.h> | 15 | #include <linux/cpufreq.h> |
| 16 | #include <linux/cpu_cooling.h> | ||
| 17 | #include <linux/errno.h> | 16 | #include <linux/errno.h> |
| 18 | #include <linux/init.h> | 17 | #include <linux/init.h> |
| 19 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
| @@ -31,7 +30,6 @@ | |||
| 31 | struct cpu_data { | 30 | struct cpu_data { |
| 32 | struct clk **pclk; | 31 | struct clk **pclk; |
| 33 | struct cpufreq_frequency_table *table; | 32 | struct cpufreq_frequency_table *table; |
| 34 | struct thermal_cooling_device *cdev; | ||
| 35 | }; | 33 | }; |
| 36 | 34 | ||
| 37 | /* | 35 | /* |
| @@ -239,7 +237,6 @@ static int qoriq_cpufreq_cpu_exit(struct cpufreq_policy *policy) | |||
| 239 | { | 237 | { |
| 240 | struct cpu_data *data = policy->driver_data; | 238 | struct cpu_data *data = policy->driver_data; |
| 241 | 239 | ||
| 242 | cpufreq_cooling_unregister(data->cdev); | ||
| 243 | kfree(data->pclk); | 240 | kfree(data->pclk); |
| 244 | kfree(data->table); | 241 | kfree(data->table); |
| 245 | kfree(data); | 242 | kfree(data); |
| @@ -258,23 +255,15 @@ static int qoriq_cpufreq_target(struct cpufreq_policy *policy, | |||
| 258 | return clk_set_parent(policy->clk, parent); | 255 | return clk_set_parent(policy->clk, parent); |
| 259 | } | 256 | } |
| 260 | 257 | ||
| 261 | |||
| 262 | static void qoriq_cpufreq_ready(struct cpufreq_policy *policy) | ||
| 263 | { | ||
| 264 | struct cpu_data *cpud = policy->driver_data; | ||
| 265 | |||
| 266 | cpud->cdev = of_cpufreq_cooling_register(policy); | ||
| 267 | } | ||
| 268 | |||
| 269 | static struct cpufreq_driver qoriq_cpufreq_driver = { | 258 | static struct cpufreq_driver qoriq_cpufreq_driver = { |
| 270 | .name = "qoriq_cpufreq", | 259 | .name = "qoriq_cpufreq", |
| 271 | .flags = CPUFREQ_CONST_LOOPS, | 260 | .flags = CPUFREQ_CONST_LOOPS | |
| 261 | CPUFREQ_IS_COOLING_DEV, | ||
| 272 | .init = qoriq_cpufreq_cpu_init, | 262 | .init = qoriq_cpufreq_cpu_init, |
| 273 | .exit = qoriq_cpufreq_cpu_exit, | 263 | .exit = qoriq_cpufreq_cpu_exit, |
| 274 | .verify = cpufreq_generic_frequency_table_verify, | 264 | .verify = cpufreq_generic_frequency_table_verify, |
| 275 | .target_index = qoriq_cpufreq_target, | 265 | .target_index = qoriq_cpufreq_target, |
| 276 | .get = cpufreq_generic_get, | 266 | .get = cpufreq_generic_get, |
| 277 | .ready = qoriq_cpufreq_ready, | ||
| 278 | .attr = cpufreq_generic_attr, | 267 | .attr = cpufreq_generic_attr, |
| 279 | }; | 268 | }; |
| 280 | 269 | ||
diff --git a/drivers/cpufreq/s5pv210-cpufreq.c b/drivers/cpufreq/s5pv210-cpufreq.c index dbecd7667db2..5b4289460bc9 100644 --- a/drivers/cpufreq/s5pv210-cpufreq.c +++ b/drivers/cpufreq/s5pv210-cpufreq.c | |||
| @@ -584,7 +584,7 @@ static struct notifier_block s5pv210_cpufreq_reboot_notifier = { | |||
| 584 | static int s5pv210_cpufreq_probe(struct platform_device *pdev) | 584 | static int s5pv210_cpufreq_probe(struct platform_device *pdev) |
| 585 | { | 585 | { |
| 586 | struct device_node *np; | 586 | struct device_node *np; |
| 587 | int id; | 587 | int id, result = 0; |
| 588 | 588 | ||
| 589 | /* | 589 | /* |
| 590 | * HACK: This is a temporary workaround to get access to clock | 590 | * HACK: This is a temporary workaround to get access to clock |
| @@ -594,18 +594,39 @@ static int s5pv210_cpufreq_probe(struct platform_device *pdev) | |||
| 594 | * this whole driver as soon as S5PV210 gets migrated to use | 594 | * this whole driver as soon as S5PV210 gets migrated to use |
| 595 | * cpufreq-dt driver. | 595 | * cpufreq-dt driver. |
| 596 | */ | 596 | */ |
| 597 | arm_regulator = regulator_get(NULL, "vddarm"); | ||
| 598 | if (IS_ERR(arm_regulator)) { | ||
| 599 | if (PTR_ERR(arm_regulator) == -EPROBE_DEFER) | ||
| 600 | pr_debug("vddarm regulator not ready, defer\n"); | ||
| 601 | else | ||
| 602 | pr_err("failed to get regulator vddarm\n"); | ||
| 603 | return PTR_ERR(arm_regulator); | ||
| 604 | } | ||
| 605 | |||
| 606 | int_regulator = regulator_get(NULL, "vddint"); | ||
| 607 | if (IS_ERR(int_regulator)) { | ||
| 608 | if (PTR_ERR(int_regulator) == -EPROBE_DEFER) | ||
| 609 | pr_debug("vddint regulator not ready, defer\n"); | ||
| 610 | else | ||
| 611 | pr_err("failed to get regulator vddint\n"); | ||
| 612 | result = PTR_ERR(int_regulator); | ||
| 613 | goto err_int_regulator; | ||
| 614 | } | ||
| 615 | |||
| 597 | np = of_find_compatible_node(NULL, NULL, "samsung,s5pv210-clock"); | 616 | np = of_find_compatible_node(NULL, NULL, "samsung,s5pv210-clock"); |
| 598 | if (!np) { | 617 | if (!np) { |
| 599 | pr_err("%s: failed to find clock controller DT node\n", | 618 | pr_err("%s: failed to find clock controller DT node\n", |
| 600 | __func__); | 619 | __func__); |
| 601 | return -ENODEV; | 620 | result = -ENODEV; |
| 621 | goto err_clock; | ||
| 602 | } | 622 | } |
| 603 | 623 | ||
| 604 | clk_base = of_iomap(np, 0); | 624 | clk_base = of_iomap(np, 0); |
| 605 | of_node_put(np); | 625 | of_node_put(np); |
| 606 | if (!clk_base) { | 626 | if (!clk_base) { |
| 607 | pr_err("%s: failed to map clock registers\n", __func__); | 627 | pr_err("%s: failed to map clock registers\n", __func__); |
| 608 | return -EFAULT; | 628 | result = -EFAULT; |
| 629 | goto err_clock; | ||
| 609 | } | 630 | } |
| 610 | 631 | ||
| 611 | for_each_compatible_node(np, NULL, "samsung,s5pv210-dmc") { | 632 | for_each_compatible_node(np, NULL, "samsung,s5pv210-dmc") { |
| @@ -614,7 +635,8 @@ static int s5pv210_cpufreq_probe(struct platform_device *pdev) | |||
| 614 | pr_err("%s: failed to get alias of dmc node '%pOFn'\n", | 635 | pr_err("%s: failed to get alias of dmc node '%pOFn'\n", |
| 615 | __func__, np); | 636 | __func__, np); |
| 616 | of_node_put(np); | 637 | of_node_put(np); |
| 617 | return id; | 638 | result = id; |
| 639 | goto err_clk_base; | ||
| 618 | } | 640 | } |
| 619 | 641 | ||
| 620 | dmc_base[id] = of_iomap(np, 0); | 642 | dmc_base[id] = of_iomap(np, 0); |
| @@ -622,33 +644,40 @@ static int s5pv210_cpufreq_probe(struct platform_device *pdev) | |||
| 622 | pr_err("%s: failed to map dmc%d registers\n", | 644 | pr_err("%s: failed to map dmc%d registers\n", |
| 623 | __func__, id); | 645 | __func__, id); |
| 624 | of_node_put(np); | 646 | of_node_put(np); |
| 625 | return -EFAULT; | 647 | result = -EFAULT; |
| 648 | goto err_dmc; | ||
| 626 | } | 649 | } |
| 627 | } | 650 | } |
| 628 | 651 | ||
| 629 | for (id = 0; id < ARRAY_SIZE(dmc_base); ++id) { | 652 | for (id = 0; id < ARRAY_SIZE(dmc_base); ++id) { |
| 630 | if (!dmc_base[id]) { | 653 | if (!dmc_base[id]) { |
| 631 | pr_err("%s: failed to find dmc%d node\n", __func__, id); | 654 | pr_err("%s: failed to find dmc%d node\n", __func__, id); |
| 632 | return -ENODEV; | 655 | result = -ENODEV; |
| 656 | goto err_dmc; | ||
| 633 | } | 657 | } |
| 634 | } | 658 | } |
| 635 | 659 | ||
| 636 | arm_regulator = regulator_get(NULL, "vddarm"); | ||
| 637 | if (IS_ERR(arm_regulator)) { | ||
| 638 | pr_err("failed to get regulator vddarm\n"); | ||
| 639 | return PTR_ERR(arm_regulator); | ||
| 640 | } | ||
| 641 | |||
| 642 | int_regulator = regulator_get(NULL, "vddint"); | ||
| 643 | if (IS_ERR(int_regulator)) { | ||
| 644 | pr_err("failed to get regulator vddint\n"); | ||
| 645 | regulator_put(arm_regulator); | ||
| 646 | return PTR_ERR(int_regulator); | ||
| 647 | } | ||
| 648 | |||
| 649 | register_reboot_notifier(&s5pv210_cpufreq_reboot_notifier); | 660 | register_reboot_notifier(&s5pv210_cpufreq_reboot_notifier); |
| 650 | 661 | ||
| 651 | return cpufreq_register_driver(&s5pv210_driver); | 662 | return cpufreq_register_driver(&s5pv210_driver); |
| 663 | |||
| 664 | err_dmc: | ||
| 665 | for (id = 0; id < ARRAY_SIZE(dmc_base); ++id) | ||
| 666 | if (dmc_base[id]) { | ||
| 667 | iounmap(dmc_base[id]); | ||
| 668 | dmc_base[id] = NULL; | ||
| 669 | } | ||
| 670 | |||
| 671 | err_clk_base: | ||
| 672 | iounmap(clk_base); | ||
| 673 | |||
| 674 | err_clock: | ||
| 675 | regulator_put(int_regulator); | ||
| 676 | |||
| 677 | err_int_regulator: | ||
| 678 | regulator_put(arm_regulator); | ||
| 679 | |||
| 680 | return result; | ||
| 652 | } | 681 | } |
| 653 | 682 | ||
| 654 | static struct platform_driver s5pv210_cpufreq_platdrv = { | 683 | static struct platform_driver s5pv210_cpufreq_platdrv = { |
diff --git a/drivers/cpufreq/scmi-cpufreq.c b/drivers/cpufreq/scmi-cpufreq.c index 9ed46d188cb5..c47182fc64ea 100644 --- a/drivers/cpufreq/scmi-cpufreq.c +++ b/drivers/cpufreq/scmi-cpufreq.c | |||
| @@ -11,7 +11,6 @@ | |||
| 11 | #include <linux/cpu.h> | 11 | #include <linux/cpu.h> |
| 12 | #include <linux/cpufreq.h> | 12 | #include <linux/cpufreq.h> |
| 13 | #include <linux/cpumask.h> | 13 | #include <linux/cpumask.h> |
| 14 | #include <linux/cpu_cooling.h> | ||
| 15 | #include <linux/export.h> | 14 | #include <linux/export.h> |
| 16 | #include <linux/module.h> | 15 | #include <linux/module.h> |
| 17 | #include <linux/pm_opp.h> | 16 | #include <linux/pm_opp.h> |
| @@ -22,7 +21,6 @@ | |||
| 22 | struct scmi_data { | 21 | struct scmi_data { |
| 23 | int domain_id; | 22 | int domain_id; |
| 24 | struct device *cpu_dev; | 23 | struct device *cpu_dev; |
| 25 | struct thermal_cooling_device *cdev; | ||
| 26 | }; | 24 | }; |
| 27 | 25 | ||
| 28 | static const struct scmi_handle *handle; | 26 | static const struct scmi_handle *handle; |
| @@ -185,7 +183,6 @@ static int scmi_cpufreq_exit(struct cpufreq_policy *policy) | |||
| 185 | { | 183 | { |
| 186 | struct scmi_data *priv = policy->driver_data; | 184 | struct scmi_data *priv = policy->driver_data; |
| 187 | 185 | ||
| 188 | cpufreq_cooling_unregister(priv->cdev); | ||
| 189 | dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table); | 186 | dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table); |
| 190 | dev_pm_opp_remove_all_dynamic(priv->cpu_dev); | 187 | dev_pm_opp_remove_all_dynamic(priv->cpu_dev); |
| 191 | kfree(priv); | 188 | kfree(priv); |
| @@ -193,17 +190,11 @@ static int scmi_cpufreq_exit(struct cpufreq_policy *policy) | |||
| 193 | return 0; | 190 | return 0; |
| 194 | } | 191 | } |
| 195 | 192 | ||
| 196 | static void scmi_cpufreq_ready(struct cpufreq_policy *policy) | ||
| 197 | { | ||
| 198 | struct scmi_data *priv = policy->driver_data; | ||
| 199 | |||
| 200 | priv->cdev = of_cpufreq_cooling_register(policy); | ||
| 201 | } | ||
| 202 | |||
| 203 | static struct cpufreq_driver scmi_cpufreq_driver = { | 193 | static struct cpufreq_driver scmi_cpufreq_driver = { |
| 204 | .name = "scmi", | 194 | .name = "scmi", |
| 205 | .flags = CPUFREQ_STICKY | CPUFREQ_HAVE_GOVERNOR_PER_POLICY | | 195 | .flags = CPUFREQ_STICKY | CPUFREQ_HAVE_GOVERNOR_PER_POLICY | |
| 206 | CPUFREQ_NEED_INITIAL_FREQ_CHECK, | 196 | CPUFREQ_NEED_INITIAL_FREQ_CHECK | |
| 197 | CPUFREQ_IS_COOLING_DEV, | ||
| 207 | .verify = cpufreq_generic_frequency_table_verify, | 198 | .verify = cpufreq_generic_frequency_table_verify, |
| 208 | .attr = cpufreq_generic_attr, | 199 | .attr = cpufreq_generic_attr, |
| 209 | .target_index = scmi_cpufreq_set_target, | 200 | .target_index = scmi_cpufreq_set_target, |
| @@ -211,7 +202,6 @@ static struct cpufreq_driver scmi_cpufreq_driver = { | |||
| 211 | .get = scmi_cpufreq_get_rate, | 202 | .get = scmi_cpufreq_get_rate, |
| 212 | .init = scmi_cpufreq_init, | 203 | .init = scmi_cpufreq_init, |
| 213 | .exit = scmi_cpufreq_exit, | 204 | .exit = scmi_cpufreq_exit, |
| 214 | .ready = scmi_cpufreq_ready, | ||
| 215 | }; | 205 | }; |
| 216 | 206 | ||
| 217 | static int scmi_cpufreq_probe(struct scmi_device *sdev) | 207 | static int scmi_cpufreq_probe(struct scmi_device *sdev) |
diff --git a/drivers/cpufreq/scpi-cpufreq.c b/drivers/cpufreq/scpi-cpufreq.c index 99449738faa4..1db2f6927e13 100644 --- a/drivers/cpufreq/scpi-cpufreq.c +++ b/drivers/cpufreq/scpi-cpufreq.c | |||
| @@ -22,7 +22,6 @@ | |||
| 22 | #include <linux/cpu.h> | 22 | #include <linux/cpu.h> |
| 23 | #include <linux/cpufreq.h> | 23 | #include <linux/cpufreq.h> |
| 24 | #include <linux/cpumask.h> | 24 | #include <linux/cpumask.h> |
| 25 | #include <linux/cpu_cooling.h> | ||
| 26 | #include <linux/export.h> | 25 | #include <linux/export.h> |
| 27 | #include <linux/module.h> | 26 | #include <linux/module.h> |
| 28 | #include <linux/of_platform.h> | 27 | #include <linux/of_platform.h> |
| @@ -34,7 +33,6 @@ | |||
| 34 | struct scpi_data { | 33 | struct scpi_data { |
| 35 | struct clk *clk; | 34 | struct clk *clk; |
| 36 | struct device *cpu_dev; | 35 | struct device *cpu_dev; |
| 37 | struct thermal_cooling_device *cdev; | ||
| 38 | }; | 36 | }; |
| 39 | 37 | ||
| 40 | static struct scpi_ops *scpi_ops; | 38 | static struct scpi_ops *scpi_ops; |
| @@ -186,7 +184,6 @@ static int scpi_cpufreq_exit(struct cpufreq_policy *policy) | |||
| 186 | { | 184 | { |
| 187 | struct scpi_data *priv = policy->driver_data; | 185 | struct scpi_data *priv = policy->driver_data; |
| 188 | 186 | ||
| 189 | cpufreq_cooling_unregister(priv->cdev); | ||
| 190 | clk_put(priv->clk); | 187 | clk_put(priv->clk); |
| 191 | dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table); | 188 | dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table); |
| 192 | kfree(priv); | 189 | kfree(priv); |
| @@ -195,23 +192,16 @@ static int scpi_cpufreq_exit(struct cpufreq_policy *policy) | |||
| 195 | return 0; | 192 | return 0; |
| 196 | } | 193 | } |
| 197 | 194 | ||
| 198 | static void scpi_cpufreq_ready(struct cpufreq_policy *policy) | ||
| 199 | { | ||
| 200 | struct scpi_data *priv = policy->driver_data; | ||
| 201 | |||
| 202 | priv->cdev = of_cpufreq_cooling_register(policy); | ||
| 203 | } | ||
| 204 | |||
| 205 | static struct cpufreq_driver scpi_cpufreq_driver = { | 195 | static struct cpufreq_driver scpi_cpufreq_driver = { |
| 206 | .name = "scpi-cpufreq", | 196 | .name = "scpi-cpufreq", |
| 207 | .flags = CPUFREQ_STICKY | CPUFREQ_HAVE_GOVERNOR_PER_POLICY | | 197 | .flags = CPUFREQ_STICKY | CPUFREQ_HAVE_GOVERNOR_PER_POLICY | |
| 208 | CPUFREQ_NEED_INITIAL_FREQ_CHECK, | 198 | CPUFREQ_NEED_INITIAL_FREQ_CHECK | |
| 199 | CPUFREQ_IS_COOLING_DEV, | ||
| 209 | .verify = cpufreq_generic_frequency_table_verify, | 200 | .verify = cpufreq_generic_frequency_table_verify, |
| 210 | .attr = cpufreq_generic_attr, | 201 | .attr = cpufreq_generic_attr, |
| 211 | .get = scpi_cpufreq_get_rate, | 202 | .get = scpi_cpufreq_get_rate, |
| 212 | .init = scpi_cpufreq_init, | 203 | .init = scpi_cpufreq_init, |
| 213 | .exit = scpi_cpufreq_exit, | 204 | .exit = scpi_cpufreq_exit, |
| 214 | .ready = scpi_cpufreq_ready, | ||
| 215 | .target_index = scpi_cpufreq_set_target, | 205 | .target_index = scpi_cpufreq_set_target, |
| 216 | }; | 206 | }; |
| 217 | 207 | ||
diff --git a/drivers/cpufreq/speedstep-ich.c b/drivers/cpufreq/speedstep-ich.c index fbbcb88db061..5d8a09b82efb 100644 --- a/drivers/cpufreq/speedstep-ich.c +++ b/drivers/cpufreq/speedstep-ich.c | |||
| @@ -243,8 +243,7 @@ static unsigned int speedstep_get(unsigned int cpu) | |||
| 243 | unsigned int speed; | 243 | unsigned int speed; |
| 244 | 244 | ||
| 245 | /* You're supposed to ensure CPU is online. */ | 245 | /* You're supposed to ensure CPU is online. */ |
| 246 | if (smp_call_function_single(cpu, get_freq_data, &speed, 1) != 0) | 246 | BUG_ON(smp_call_function_single(cpu, get_freq_data, &speed, 1)); |
| 247 | BUG(); | ||
| 248 | 247 | ||
| 249 | pr_debug("detected %u kHz as current frequency\n", speed); | 248 | pr_debug("detected %u kHz as current frequency\n", speed); |
| 250 | return speed; | 249 | return speed; |
diff --git a/drivers/cpufreq/tegra124-cpufreq.c b/drivers/cpufreq/tegra124-cpufreq.c index 43530254201a..4bb154f6c54c 100644 --- a/drivers/cpufreq/tegra124-cpufreq.c +++ b/drivers/cpufreq/tegra124-cpufreq.c | |||
| @@ -134,6 +134,8 @@ static int tegra124_cpufreq_probe(struct platform_device *pdev) | |||
| 134 | 134 | ||
| 135 | platform_set_drvdata(pdev, priv); | 135 | platform_set_drvdata(pdev, priv); |
| 136 | 136 | ||
| 137 | of_node_put(np); | ||
| 138 | |||
| 137 | return 0; | 139 | return 0; |
| 138 | 140 | ||
| 139 | out_switch_to_pllx: | 141 | out_switch_to_pllx: |
diff --git a/drivers/opp/core.c b/drivers/opp/core.c index 18f1639dbc4a..4e00301060cf 100644 --- a/drivers/opp/core.c +++ b/drivers/opp/core.c | |||
| @@ -533,9 +533,8 @@ static int _set_opp_voltage(struct device *dev, struct regulator *reg, | |||
| 533 | return ret; | 533 | return ret; |
| 534 | } | 534 | } |
| 535 | 535 | ||
| 536 | static inline int | 536 | static inline int _generic_set_opp_clk_only(struct device *dev, struct clk *clk, |
| 537 | _generic_set_opp_clk_only(struct device *dev, struct clk *clk, | 537 | unsigned long freq) |
| 538 | unsigned long old_freq, unsigned long freq) | ||
| 539 | { | 538 | { |
| 540 | int ret; | 539 | int ret; |
| 541 | 540 | ||
| @@ -572,7 +571,7 @@ static int _generic_set_opp_regulator(const struct opp_table *opp_table, | |||
| 572 | } | 571 | } |
| 573 | 572 | ||
| 574 | /* Change frequency */ | 573 | /* Change frequency */ |
| 575 | ret = _generic_set_opp_clk_only(dev, opp_table->clk, old_freq, freq); | 574 | ret = _generic_set_opp_clk_only(dev, opp_table->clk, freq); |
| 576 | if (ret) | 575 | if (ret) |
| 577 | goto restore_voltage; | 576 | goto restore_voltage; |
| 578 | 577 | ||
| @@ -586,7 +585,7 @@ static int _generic_set_opp_regulator(const struct opp_table *opp_table, | |||
| 586 | return 0; | 585 | return 0; |
| 587 | 586 | ||
| 588 | restore_freq: | 587 | restore_freq: |
| 589 | if (_generic_set_opp_clk_only(dev, opp_table->clk, freq, old_freq)) | 588 | if (_generic_set_opp_clk_only(dev, opp_table->clk, old_freq)) |
| 590 | dev_err(dev, "%s: failed to restore old-freq (%lu Hz)\n", | 589 | dev_err(dev, "%s: failed to restore old-freq (%lu Hz)\n", |
| 591 | __func__, old_freq); | 590 | __func__, old_freq); |
| 592 | restore_voltage: | 591 | restore_voltage: |
| @@ -759,7 +758,7 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq) | |||
| 759 | opp->supplies); | 758 | opp->supplies); |
| 760 | } else { | 759 | } else { |
| 761 | /* Only frequency scaling */ | 760 | /* Only frequency scaling */ |
| 762 | ret = _generic_set_opp_clk_only(dev, clk, old_freq, freq); | 761 | ret = _generic_set_opp_clk_only(dev, clk, freq); |
| 763 | } | 762 | } |
| 764 | 763 | ||
| 765 | /* Scaling down? Configure required OPPs after frequency */ | 764 | /* Scaling down? Configure required OPPs after frequency */ |
diff --git a/drivers/opp/of.c b/drivers/opp/of.c index 06f0f632ec47..cd58959e5158 100644 --- a/drivers/opp/of.c +++ b/drivers/opp/of.c | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | #include <linux/pm_domain.h> | 20 | #include <linux/pm_domain.h> |
| 21 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
| 22 | #include <linux/export.h> | 22 | #include <linux/export.h> |
| 23 | #include <linux/energy_model.h> | ||
| 23 | 24 | ||
| 24 | #include "opp.h" | 25 | #include "opp.h" |
| 25 | 26 | ||
| @@ -1047,3 +1048,101 @@ struct device_node *dev_pm_opp_get_of_node(struct dev_pm_opp *opp) | |||
| 1047 | return of_node_get(opp->np); | 1048 | return of_node_get(opp->np); |
| 1048 | } | 1049 | } |
| 1049 | EXPORT_SYMBOL_GPL(dev_pm_opp_get_of_node); | 1050 | EXPORT_SYMBOL_GPL(dev_pm_opp_get_of_node); |
| 1051 | |||
| 1052 | /* | ||
| 1053 | * Callback function provided to the Energy Model framework upon registration. | ||
| 1054 | * This computes the power estimated by @CPU at @kHz if it is the frequency | ||
| 1055 | * of an existing OPP, or at the frequency of the first OPP above @kHz otherwise | ||
| 1056 | * (see dev_pm_opp_find_freq_ceil()). This function updates @kHz to the ceiled | ||
| 1057 | * frequency and @mW to the associated power. The power is estimated as | ||
| 1058 | * P = C * V^2 * f with C being the CPU's capacitance and V and f respectively | ||
| 1059 | * the voltage and frequency of the OPP. | ||
| 1060 | * | ||
| 1061 | * Returns -ENODEV if the CPU device cannot be found, -EINVAL if the power | ||
| 1062 | * calculation failed because of missing parameters, 0 otherwise. | ||
| 1063 | */ | ||
| 1064 | static int __maybe_unused _get_cpu_power(unsigned long *mW, unsigned long *kHz, | ||
| 1065 | int cpu) | ||
| 1066 | { | ||
| 1067 | struct device *cpu_dev; | ||
| 1068 | struct dev_pm_opp *opp; | ||
| 1069 | struct device_node *np; | ||
| 1070 | unsigned long mV, Hz; | ||
| 1071 | u32 cap; | ||
| 1072 | u64 tmp; | ||
| 1073 | int ret; | ||
| 1074 | |||
| 1075 | cpu_dev = get_cpu_device(cpu); | ||
| 1076 | if (!cpu_dev) | ||
| 1077 | return -ENODEV; | ||
| 1078 | |||
| 1079 | np = of_node_get(cpu_dev->of_node); | ||
| 1080 | if (!np) | ||
| 1081 | return -EINVAL; | ||
| 1082 | |||
| 1083 | ret = of_property_read_u32(np, "dynamic-power-coefficient", &cap); | ||
| 1084 | of_node_put(np); | ||
| 1085 | if (ret) | ||
| 1086 | return -EINVAL; | ||
| 1087 | |||
| 1088 | Hz = *kHz * 1000; | ||
| 1089 | opp = dev_pm_opp_find_freq_ceil(cpu_dev, &Hz); | ||
| 1090 | if (IS_ERR(opp)) | ||
| 1091 | return -EINVAL; | ||
| 1092 | |||
| 1093 | mV = dev_pm_opp_get_voltage(opp) / 1000; | ||
| 1094 | dev_pm_opp_put(opp); | ||
| 1095 | if (!mV) | ||
| 1096 | return -EINVAL; | ||
| 1097 | |||
| 1098 | tmp = (u64)cap * mV * mV * (Hz / 1000000); | ||
| 1099 | do_div(tmp, 1000000000); | ||
| 1100 | |||
| 1101 | *mW = (unsigned long)tmp; | ||
| 1102 | *kHz = Hz / 1000; | ||
| 1103 | |||
| 1104 | return 0; | ||
| 1105 | } | ||
| 1106 | |||
| 1107 | /** | ||
| 1108 | * dev_pm_opp_of_register_em() - Attempt to register an Energy Model | ||
| 1109 | * @cpus : CPUs for which an Energy Model has to be registered | ||
| 1110 | * | ||
| 1111 | * This checks whether the "dynamic-power-coefficient" devicetree property has | ||
| 1112 | * been specified, and tries to register an Energy Model with it if it has. | ||
| 1113 | */ | ||
| 1114 | void dev_pm_opp_of_register_em(struct cpumask *cpus) | ||
| 1115 | { | ||
| 1116 | struct em_data_callback em_cb = EM_DATA_CB(_get_cpu_power); | ||
| 1117 | int ret, nr_opp, cpu = cpumask_first(cpus); | ||
| 1118 | struct device *cpu_dev; | ||
| 1119 | struct device_node *np; | ||
| 1120 | u32 cap; | ||
| 1121 | |||
| 1122 | cpu_dev = get_cpu_device(cpu); | ||
| 1123 | if (!cpu_dev) | ||
| 1124 | return; | ||
| 1125 | |||
| 1126 | nr_opp = dev_pm_opp_get_opp_count(cpu_dev); | ||
| 1127 | if (nr_opp <= 0) | ||
| 1128 | return; | ||
| 1129 | |||
| 1130 | np = of_node_get(cpu_dev->of_node); | ||
| 1131 | if (!np) | ||
| 1132 | return; | ||
| 1133 | |||
| 1134 | /* | ||
| 1135 | * Register an EM only if the 'dynamic-power-coefficient' property is | ||
| 1136 | * set in devicetree. It is assumed the voltage values are known if that | ||
| 1137 | * property is set since it is useless otherwise. If voltages are not | ||
| 1138 | * known, just let the EM registration fail with an error to alert the | ||
| 1139 | * user about the inconsistent configuration. | ||
| 1140 | */ | ||
| 1141 | ret = of_property_read_u32(np, "dynamic-power-coefficient", &cap); | ||
| 1142 | of_node_put(np); | ||
| 1143 | if (ret || !cap) | ||
| 1144 | return; | ||
| 1145 | |||
| 1146 | em_register_perf_domain(cpus, nr_opp, &em_cb); | ||
| 1147 | } | ||
| 1148 | EXPORT_SYMBOL_GPL(dev_pm_opp_of_register_em); | ||
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 30323426902e..58bb7d72dc2b 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig | |||
| @@ -152,6 +152,7 @@ config CPU_THERMAL | |||
| 152 | bool "generic cpu cooling support" | 152 | bool "generic cpu cooling support" |
| 153 | depends on CPU_FREQ | 153 | depends on CPU_FREQ |
| 154 | depends on THERMAL_OF | 154 | depends on THERMAL_OF |
| 155 | depends on THERMAL=y | ||
| 155 | help | 156 | help |
| 156 | This implements the generic cpu cooling mechanism through frequency | 157 | This implements the generic cpu cooling mechanism through frequency |
| 157 | reduction. An ACPI version of this already exists | 158 | reduction. An ACPI version of this already exists |
diff --git a/include/acpi/cppc_acpi.h b/include/acpi/cppc_acpi.h index 4f34734e7f36..ba6fd7202775 100644 --- a/include/acpi/cppc_acpi.h +++ b/include/acpi/cppc_acpi.h | |||
| @@ -137,6 +137,7 @@ struct cppc_cpudata { | |||
| 137 | cpumask_var_t shared_cpu_map; | 137 | cpumask_var_t shared_cpu_map; |
| 138 | }; | 138 | }; |
| 139 | 139 | ||
| 140 | extern int cppc_get_desired_perf(int cpunum, u64 *desired_perf); | ||
| 140 | extern int cppc_get_perf_ctrs(int cpu, struct cppc_perf_fb_ctrs *perf_fb_ctrs); | 141 | extern int cppc_get_perf_ctrs(int cpu, struct cppc_perf_fb_ctrs *perf_fb_ctrs); |
| 141 | extern int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls); | 142 | extern int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls); |
| 142 | extern int cppc_get_perf_caps(int cpu, struct cppc_perf_caps *caps); | 143 | extern int cppc_get_perf_caps(int cpu, struct cppc_perf_caps *caps); |
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index c86d6d8bdfed..b160e98076e3 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h | |||
| @@ -151,6 +151,9 @@ struct cpufreq_policy { | |||
| 151 | 151 | ||
| 152 | /* For cpufreq driver's internal use */ | 152 | /* For cpufreq driver's internal use */ |
| 153 | void *driver_data; | 153 | void *driver_data; |
| 154 | |||
| 155 | /* Pointer to the cooling device if used for thermal mitigation */ | ||
| 156 | struct thermal_cooling_device *cdev; | ||
| 154 | }; | 157 | }; |
| 155 | 158 | ||
| 156 | /* Only for ACPI */ | 159 | /* Only for ACPI */ |
| @@ -254,20 +257,12 @@ __ATTR(_name, 0644, show_##_name, store_##_name) | |||
| 254 | static struct freq_attr _name = \ | 257 | static struct freq_attr _name = \ |
| 255 | __ATTR(_name, 0200, NULL, store_##_name) | 258 | __ATTR(_name, 0200, NULL, store_##_name) |
| 256 | 259 | ||
| 257 | struct global_attr { | ||
| 258 | struct attribute attr; | ||
| 259 | ssize_t (*show)(struct kobject *kobj, | ||
| 260 | struct attribute *attr, char *buf); | ||
| 261 | ssize_t (*store)(struct kobject *a, struct attribute *b, | ||
| 262 | const char *c, size_t count); | ||
| 263 | }; | ||
| 264 | |||
| 265 | #define define_one_global_ro(_name) \ | 260 | #define define_one_global_ro(_name) \ |
| 266 | static struct global_attr _name = \ | 261 | static struct kobj_attribute _name = \ |
| 267 | __ATTR(_name, 0444, show_##_name, NULL) | 262 | __ATTR(_name, 0444, show_##_name, NULL) |
| 268 | 263 | ||
| 269 | #define define_one_global_rw(_name) \ | 264 | #define define_one_global_rw(_name) \ |
| 270 | static struct global_attr _name = \ | 265 | static struct kobj_attribute _name = \ |
| 271 | __ATTR(_name, 0644, show_##_name, store_##_name) | 266 | __ATTR(_name, 0644, show_##_name, store_##_name) |
| 272 | 267 | ||
| 273 | 268 | ||
| @@ -330,6 +325,8 @@ struct cpufreq_driver { | |||
| 330 | /* optional */ | 325 | /* optional */ |
| 331 | int (*bios_limit)(int cpu, unsigned int *limit); | 326 | int (*bios_limit)(int cpu, unsigned int *limit); |
| 332 | 327 | ||
| 328 | int (*online)(struct cpufreq_policy *policy); | ||
| 329 | int (*offline)(struct cpufreq_policy *policy); | ||
| 333 | int (*exit)(struct cpufreq_policy *policy); | 330 | int (*exit)(struct cpufreq_policy *policy); |
| 334 | void (*stop_cpu)(struct cpufreq_policy *policy); | 331 | void (*stop_cpu)(struct cpufreq_policy *policy); |
| 335 | int (*suspend)(struct cpufreq_policy *policy); | 332 | int (*suspend)(struct cpufreq_policy *policy); |
| @@ -346,14 +343,15 @@ struct cpufreq_driver { | |||
| 346 | }; | 343 | }; |
| 347 | 344 | ||
| 348 | /* flags */ | 345 | /* flags */ |
| 349 | #define CPUFREQ_STICKY (1 << 0) /* driver isn't removed even if | 346 | |
| 350 | all ->init() calls failed */ | 347 | /* driver isn't removed even if all ->init() calls failed */ |
| 351 | #define CPUFREQ_CONST_LOOPS (1 << 1) /* loops_per_jiffy or other | 348 | #define CPUFREQ_STICKY BIT(0) |
| 352 | kernel "constants" aren't | 349 | |
| 353 | affected by frequency | 350 | /* loops_per_jiffy or other kernel "constants" aren't affected by frequency transitions */ |
| 354 | transitions */ | 351 | #define CPUFREQ_CONST_LOOPS BIT(1) |
| 355 | #define CPUFREQ_PM_NO_WARN (1 << 2) /* don't warn on suspend/resume | 352 | |
| 356 | speed mismatches */ | 353 | /* don't warn on suspend/resume speed mismatches */ |
| 354 | #define CPUFREQ_PM_NO_WARN BIT(2) | ||
| 357 | 355 | ||
| 358 | /* | 356 | /* |
| 359 | * This should be set by platforms having multiple clock-domains, i.e. | 357 | * This should be set by platforms having multiple clock-domains, i.e. |
| @@ -361,14 +359,14 @@ struct cpufreq_driver { | |||
| 361 | * be created in cpu/cpu<num>/cpufreq/ directory and so they can use the same | 359 | * be created in cpu/cpu<num>/cpufreq/ directory and so they can use the same |
| 362 | * governor with different tunables for different clusters. | 360 | * governor with different tunables for different clusters. |
| 363 | */ | 361 | */ |
| 364 | #define CPUFREQ_HAVE_GOVERNOR_PER_POLICY (1 << 3) | 362 | #define CPUFREQ_HAVE_GOVERNOR_PER_POLICY BIT(3) |
| 365 | 363 | ||
| 366 | /* | 364 | /* |
| 367 | * Driver will do POSTCHANGE notifications from outside of their ->target() | 365 | * Driver will do POSTCHANGE notifications from outside of their ->target() |
| 368 | * routine and so must set cpufreq_driver->flags with this flag, so that core | 366 | * routine and so must set cpufreq_driver->flags with this flag, so that core |
| 369 | * can handle them specially. | 367 | * can handle them specially. |
| 370 | */ | 368 | */ |
| 371 | #define CPUFREQ_ASYNC_NOTIFICATION (1 << 4) | 369 | #define CPUFREQ_ASYNC_NOTIFICATION BIT(4) |
| 372 | 370 | ||
| 373 | /* | 371 | /* |
| 374 | * Set by drivers which want cpufreq core to check if CPU is running at a | 372 | * Set by drivers which want cpufreq core to check if CPU is running at a |
| @@ -377,13 +375,19 @@ struct cpufreq_driver { | |||
| 377 | * from the table. And if that fails, we will stop further boot process by | 375 | * from the table. And if that fails, we will stop further boot process by |
| 378 | * issuing a BUG_ON(). | 376 | * issuing a BUG_ON(). |
| 379 | */ | 377 | */ |
| 380 | #define CPUFREQ_NEED_INITIAL_FREQ_CHECK (1 << 5) | 378 | #define CPUFREQ_NEED_INITIAL_FREQ_CHECK BIT(5) |
| 381 | 379 | ||
| 382 | /* | 380 | /* |
| 383 | * Set by drivers to disallow use of governors with "dynamic_switching" flag | 381 | * Set by drivers to disallow use of governors with "dynamic_switching" flag |
| 384 | * set. | 382 | * set. |
| 385 | */ | 383 | */ |
| 386 | #define CPUFREQ_NO_AUTO_DYNAMIC_SWITCHING (1 << 6) | 384 | #define CPUFREQ_NO_AUTO_DYNAMIC_SWITCHING BIT(6) |
| 385 | |||
| 386 | /* | ||
| 387 | * Set by drivers that want the core to automatically register the cpufreq | ||
| 388 | * driver as a thermal cooling device. | ||
| 389 | */ | ||
| 390 | #define CPUFREQ_IS_COOLING_DEV BIT(7) | ||
| 387 | 391 | ||
| 388 | int cpufreq_register_driver(struct cpufreq_driver *driver_data); | 392 | int cpufreq_register_driver(struct cpufreq_driver *driver_data); |
| 389 | int cpufreq_unregister_driver(struct cpufreq_driver *driver_data); | 393 | int cpufreq_unregister_driver(struct cpufreq_driver *driver_data); |
diff --git a/include/linux/platform_data/davinci-cpufreq.h b/include/linux/platform_data/davinci-cpufreq.h new file mode 100644 index 000000000000..3fbf9f2793b5 --- /dev/null +++ b/include/linux/platform_data/davinci-cpufreq.h | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 2 | /* | ||
| 3 | * TI DaVinci CPUFreq platform support. | ||
| 4 | * | ||
| 5 | * Copyright (C) 2009 Texas Instruments, Inc. http://www.ti.com/ | ||
| 6 | */ | ||
| 7 | |||
| 8 | #ifndef _MACH_DAVINCI_CPUFREQ_H | ||
| 9 | #define _MACH_DAVINCI_CPUFREQ_H | ||
| 10 | |||
| 11 | #include <linux/cpufreq.h> | ||
| 12 | |||
| 13 | struct davinci_cpufreq_config { | ||
| 14 | struct cpufreq_frequency_table *freq_table; | ||
| 15 | int (*set_voltage)(unsigned int index); | ||
| 16 | int (*init)(void); | ||
| 17 | }; | ||
| 18 | |||
| 19 | #endif /* _MACH_DAVINCI_CPUFREQ_H */ | ||
diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h index b895f4e79868..c9c76310865a 100644 --- a/include/linux/pm_opp.h +++ b/include/linux/pm_opp.h | |||
| @@ -327,6 +327,7 @@ int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpuma | |||
| 327 | struct device_node *dev_pm_opp_of_get_opp_desc_node(struct device *dev); | 327 | struct device_node *dev_pm_opp_of_get_opp_desc_node(struct device *dev); |
| 328 | struct device_node *dev_pm_opp_get_of_node(struct dev_pm_opp *opp); | 328 | struct device_node *dev_pm_opp_get_of_node(struct dev_pm_opp *opp); |
| 329 | int of_get_required_opp_performance_state(struct device_node *np, int index); | 329 | int of_get_required_opp_performance_state(struct device_node *np, int index); |
| 330 | void dev_pm_opp_of_register_em(struct cpumask *cpus); | ||
| 330 | #else | 331 | #else |
| 331 | static inline int dev_pm_opp_of_add_table(struct device *dev) | 332 | static inline int dev_pm_opp_of_add_table(struct device *dev) |
| 332 | { | 333 | { |
| @@ -365,6 +366,11 @@ static inline struct device_node *dev_pm_opp_get_of_node(struct dev_pm_opp *opp) | |||
| 365 | { | 366 | { |
| 366 | return NULL; | 367 | return NULL; |
| 367 | } | 368 | } |
| 369 | |||
| 370 | static inline void dev_pm_opp_of_register_em(struct cpumask *cpus) | ||
| 371 | { | ||
| 372 | } | ||
| 373 | |||
| 368 | static inline int of_get_required_opp_performance_state(struct device_node *np, int index) | 374 | static inline int of_get_required_opp_performance_state(struct device_node *np, int index) |
| 369 | { | 375 | { |
| 370 | return -ENOTSUPP; | 376 | return -ENOTSUPP; |
