]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
Merge back earlier cpufreq material for v5.1.
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Sun, 24 Feb 2019 20:18:05 +0000 (21:18 +0100)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Sun, 24 Feb 2019 20:18:05 +0000 (21:18 +0100)
36 files changed:
MAINTAINERS
arch/arm/mach-davinci/da850.c
arch/arm/mach-davinci/include/mach/cpufreq.h [deleted file]
drivers/acpi/cppc_acpi.c
drivers/cpufreq/Kconfig
drivers/cpufreq/Kconfig.arm
drivers/cpufreq/Makefile
drivers/cpufreq/acpi-cpufreq.c
drivers/cpufreq/armada-8k-cpufreq.c [new file with mode: 0644]
drivers/cpufreq/cppc_cpufreq.c
drivers/cpufreq/cpufreq-dt.c
drivers/cpufreq/cpufreq.c
drivers/cpufreq/cpufreq_stats.c
drivers/cpufreq/davinci-cpufreq.c
drivers/cpufreq/e_powersaver.c
drivers/cpufreq/imx6q-cpufreq.c
drivers/cpufreq/intel_pstate.c
drivers/cpufreq/longhaul.c
drivers/cpufreq/mediatek-cpufreq.c
drivers/cpufreq/pcc-cpufreq.c
drivers/cpufreq/powernv-cpufreq.c
drivers/cpufreq/qcom-cpufreq-hw.c
drivers/cpufreq/qcom-cpufreq-kryo.c
drivers/cpufreq/qoriq-cpufreq.c
drivers/cpufreq/s5pv210-cpufreq.c
drivers/cpufreq/scmi-cpufreq.c
drivers/cpufreq/scpi-cpufreq.c
drivers/cpufreq/speedstep-ich.c
drivers/cpufreq/tegra124-cpufreq.c
drivers/opp/core.c
drivers/opp/of.c
drivers/thermal/Kconfig
include/acpi/cppc_acpi.h
include/linux/cpufreq.h
include/linux/platform_data/davinci-cpufreq.h [new file with mode: 0644]
include/linux/pm_opp.h

index 41ce5f4ad838784909b02f5d377d2987d8ad0e9e..3f2c6d697cab9f305f7b9fb00ae76485f336dafb 100644 (file)
@@ -1737,6 +1737,7 @@ F:        arch/arm/configs/mvebu_*_defconfig
 F:     arch/arm/mach-mvebu/
 F:     arch/arm64/boot/dts/marvell/armada*
 F:     drivers/cpufreq/armada-37xx-cpufreq.c
+F:     drivers/cpufreq/armada-8k-cpufreq.c
 F:     drivers/cpufreq/mvebu-cpufreq.c
 F:     drivers/irqchip/irq-armada-370-xp.c
 F:     drivers/irqchip/irq-mvebu-*
@@ -3961,7 +3962,7 @@ M:        Viresh Kumar <viresh.kumar@linaro.org>
 L:     linux-pm@vger.kernel.org
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
-T:     git git://git.linaro.org/people/vireshk/linux.git (For ARM Updates)
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm.git (For ARM Updates)
 B:     https://bugzilla.kernel.org
 F:     Documentation/admin-guide/pm/cpufreq.rst
 F:     Documentation/admin-guide/pm/intel_pstate.rst
@@ -12604,11 +12605,11 @@ F:    Documentation/media/v4l-drivers/qcom_camss.rst
 F:     drivers/media/platform/qcom/camss/
 
 QUALCOMM CPUFREQ DRIVER MSM8996/APQ8096
-M:  Ilia Lin <ilia.lin@gmail.com>
-L:  linux-pm@vger.kernel.org
-S:  Maintained
-F:  Documentation/devicetree/bindings/opp/kryo-cpufreq.txt
-F:  drivers/cpufreq/qcom-cpufreq-kryo.c
+M:     Ilia Lin <ilia.lin@kernel.org>
+L:     linux-pm@vger.kernel.org
+S:     Maintained
+F:     Documentation/devicetree/bindings/opp/kryo-cpufreq.txt
+F:     drivers/cpufreq/qcom-cpufreq-kryo.c
 
 QUALCOMM EMAC GIGABIT ETHERNET DRIVER
 M:     Timur Tabi <timur@kernel.org>
index e7b78df2bfefbcfd08120d2c6ec08633995472ef..a02ff431ba47913d0b3d09ee78230b83274f1b90 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/mfd/da8xx-cfgchip.h>
 #include <linux/platform_data/clk-da8xx-cfgchip.h>
 #include <linux/platform_data/clk-davinci-pll.h>
+#include <linux/platform_data/davinci-cpufreq.h>
 #include <linux/platform_data/gpio-davinci.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
@@ -29,7 +30,6 @@
 #include <asm/mach/map.h>
 
 #include <mach/common.h>
-#include <mach/cpufreq.h>
 #include <mach/cputype.h>
 #include <mach/da8xx.h>
 #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 (file)
index 3c089cf..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * TI DaVinci CPUFreq platform support.
- *
- * Copyright (C) 2009 Texas Instruments, Inc. http://www.ti.com/
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any
- * kind, whether express or implied; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-#ifndef _MACH_DAVINCI_CPUFREQ_H
-#define _MACH_DAVINCI_CPUFREQ_H
-
-#include <linux/cpufreq.h>
-
-struct davinci_cpufreq_config {
-       struct cpufreq_frequency_table *freq_table;
-       int (*set_voltage) (unsigned int index);
-       int (*init) (void);
-};
-
-#endif
index 217a782c3e552783a2acf3b072dd18648f7c6e89..1b207fca1420bbc5c40469e1b3558cb38a57c450 100644 (file)
@@ -1050,6 +1050,48 @@ static int cpc_write(int cpu, struct cpc_register_resource *reg_res, u64 val)
        return ret_val;
 }
 
+/**
+ * cppc_get_desired_perf - Get the value of desired performance register.
+ * @cpunum: CPU from which to get desired performance.
+ * @desired_perf: address of a variable to store the returned desired performance
+ *
+ * Return: 0 for success, -EIO otherwise.
+ */
+int cppc_get_desired_perf(int cpunum, u64 *desired_perf)
+{
+       struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpunum);
+       int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpunum);
+       struct cpc_register_resource *desired_reg;
+       struct cppc_pcc_data *pcc_ss_data = NULL;
+
+       desired_reg = &cpc_desc->cpc_regs[DESIRED_PERF];
+
+       if (CPC_IN_PCC(desired_reg)) {
+               int ret = 0;
+
+               if (pcc_ss_id < 0)
+                       return -EIO;
+
+               pcc_ss_data = pcc_data[pcc_ss_id];
+
+               down_write(&pcc_ss_data->pcc_lock);
+
+               if (send_pcc_cmd(pcc_ss_id, CMD_READ) >= 0)
+                       cpc_read(cpunum, desired_reg, desired_perf);
+               else
+                       ret = -EIO;
+
+               up_write(&pcc_ss_data->pcc_lock);
+
+               return ret;
+       }
+
+       cpc_read(cpunum, desired_reg, desired_perf);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(cppc_get_desired_perf);
+
 /**
  * cppc_get_perf_caps - Get a CPUs performance capabilities.
  * @cpunum: CPU from which to get capabilities info.
index 608af20a34940d60a716f78ac263b0f3bfaaa47a..b22e6bba71f1510618370bc7ce223cabe38717f1 100644 (file)
@@ -207,8 +207,6 @@ comment "CPU frequency scaling drivers"
 config CPUFREQ_DT
        tristate "Generic DT based cpufreq driver"
        depends on HAVE_CLK && OF
-       # if CPU_THERMAL is on and THERMAL=m, CPUFREQ_DT cannot be =y:
-       depends on !CPU_THERMAL || THERMAL
        select CPUFREQ_DT_PLATDEV
        select PM_OPP
        help
@@ -327,7 +325,6 @@ endif
 config QORIQ_CPUFREQ
        tristate "CPU frequency scaling driver for Freescale QorIQ SoCs"
        depends on OF && COMMON_CLK && (PPC_E500MC || ARM || ARM64)
-       depends on !CPU_THERMAL || THERMAL
        select CLK_QORIQ
        help
          This adds the CPUFreq driver support for Freescale QorIQ SoCs
index 688f10227793d73a687416ad2a3aa69fab53f3a6..f08bb0075316cf1f6bb61e42350e5fb5886aef77 100644 (file)
@@ -25,12 +25,21 @@ config ARM_ARMADA_37XX_CPUFREQ
          This adds the CPUFreq driver support for Marvell Armada 37xx SoCs.
          The Armada 37xx PMU supports 4 frequency and VDD levels.
 
+config ARM_ARMADA_8K_CPUFREQ
+       tristate "Armada 8K CPUFreq driver"
+       depends on ARCH_MVEBU && CPUFREQ_DT
+       help
+         This enables the CPUFreq driver support for Marvell
+         Armada8k SOCs.
+         Armada8K device has the AP806 which supports scaling
+         to any full integer divider.
+
+         If in doubt, say N.
+
 # big LITTLE core layer and glue drivers
 config ARM_BIG_LITTLE_CPUFREQ
        tristate "Generic ARM big LITTLE CPUfreq driver"
        depends on ARM_CPU_TOPOLOGY && HAVE_CLK
-       # if CPU_THERMAL is on and THERMAL=m, ARM_BIT_LITTLE_CPUFREQ cannot be =y
-       depends on !CPU_THERMAL || THERMAL
        select PM_OPP
        help
          This enables the Generic CPUfreq driver for ARM big.LITTLE platforms.
@@ -38,7 +47,6 @@ config ARM_BIG_LITTLE_CPUFREQ
 config ARM_SCPI_CPUFREQ
        tristate "SCPI based CPUfreq driver"
        depends on ARM_SCPI_PROTOCOL && COMMON_CLK_SCPI
-       depends on !CPU_THERMAL || THERMAL
        help
          This adds the CPUfreq driver support for ARM platforms using SCPI
          protocol for CPU power management.
@@ -93,7 +101,6 @@ config ARM_KIRKWOOD_CPUFREQ
 config ARM_MEDIATEK_CPUFREQ
        tristate "CPU Frequency scaling support for MediaTek SoCs"
        depends on ARCH_MEDIATEK && REGULATOR
-       depends on !CPU_THERMAL || THERMAL
        select PM_OPP
        help
          This adds the CPUFreq driver support for MediaTek SoCs.
@@ -233,7 +240,6 @@ config ARM_SA1110_CPUFREQ
 config ARM_SCMI_CPUFREQ
        tristate "SCMI based CPUfreq driver"
        depends on ARM_SCMI_PROTOCOL || COMPILE_TEST
-       depends on !CPU_THERMAL || THERMAL
        select PM_OPP
        help
          This adds the CPUfreq driver support for ARM platforms using SCMI
index 08c071be24912f86514907352aa82d14b625db8d..689b26c6f94957631abb3a90067bf3ecbe7b87e1 100644 (file)
@@ -50,6 +50,7 @@ obj-$(CONFIG_X86_SFI_CPUFREQ)         += sfi-cpufreq.o
 obj-$(CONFIG_ARM_BIG_LITTLE_CPUFREQ)   += arm_big_little.o
 
 obj-$(CONFIG_ARM_ARMADA_37XX_CPUFREQ)  += armada-37xx-cpufreq.o
+obj-$(CONFIG_ARM_ARMADA_8K_CPUFREQ)    += armada-8k-cpufreq.o
 obj-$(CONFIG_ARM_BRCMSTB_AVS_CPUFREQ)  += brcmstb-avs-cpufreq.o
 obj-$(CONFIG_ACPI_CPPC_CPUFREQ)                += cppc_cpufreq.o
 obj-$(CONFIG_ARCH_DAVINCI)             += davinci-cpufreq.o
index d62fd374d5c70f58fdd4fb7c874584a00dc00c16..c72258a44ba4d1e090dedc37b08bb42ec32cac70 100644 (file)
@@ -916,8 +916,10 @@ static void __init acpi_cpufreq_boost_init(void)
 {
        int ret;
 
-       if (!(boot_cpu_has(X86_FEATURE_CPB) || boot_cpu_has(X86_FEATURE_IDA)))
+       if (!(boot_cpu_has(X86_FEATURE_CPB) || boot_cpu_has(X86_FEATURE_IDA))) {
+               pr_debug("Boost capabilities not present in the processor\n");
                return;
+       }
 
        acpi_cpufreq_driver.set_boost = set_boost;
        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 (file)
index 0000000..8a5ddb9
--- /dev/null
@@ -0,0 +1,204 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * CPUFreq support for Armada 8K
+ *
+ * Copyright (C) 2018 Marvell
+ *
+ * Omri Itach <omrii@marvell.com>
+ * Gregory Clement <gregory.clement@bootlin.com>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_opp.h>
+#include <linux/slab.h>
+
+/*
+ * Setup the opps list with the divider for the max frequency, that
+ * will be filled at runtime.
+ */
+static const int opps_div[] __initconst = {1, 2, 3, 4};
+
+static struct platform_device *armada_8k_pdev;
+
+struct freq_table {
+       struct device *cpu_dev;
+       unsigned int freq[ARRAY_SIZE(opps_div)];
+};
+
+/* If the CPUs share the same clock, then they are in the same cluster. */
+static void __init armada_8k_get_sharing_cpus(struct clk *cur_clk,
+                                             struct cpumask *cpumask)
+{
+       int cpu;
+
+       for_each_possible_cpu(cpu) {
+               struct device *cpu_dev;
+               struct clk *clk;
+
+               cpu_dev = get_cpu_device(cpu);
+               if (!cpu_dev) {
+                       pr_warn("Failed to get cpu%d device\n", cpu);
+                       continue;
+               }
+
+               clk = clk_get(cpu_dev, 0);
+               if (IS_ERR(clk)) {
+                       pr_warn("Cannot get clock for CPU %d\n", cpu);
+               } else {
+                       if (clk_is_match(clk, cur_clk))
+                               cpumask_set_cpu(cpu, cpumask);
+
+                       clk_put(clk);
+               }
+       }
+}
+
+static int __init armada_8k_add_opp(struct clk *clk, struct device *cpu_dev,
+                                   struct freq_table *freq_tables,
+                                   int opps_index)
+{
+       unsigned int cur_frequency;
+       unsigned int freq;
+       int i, ret;
+
+       /* Get nominal (current) CPU frequency. */
+       cur_frequency = clk_get_rate(clk);
+       if (!cur_frequency) {
+               dev_err(cpu_dev, "Failed to get clock rate for this CPU\n");
+               return -EINVAL;
+       }
+
+       freq_tables[opps_index].cpu_dev = cpu_dev;
+
+       for (i = 0; i < ARRAY_SIZE(opps_div); i++) {
+               freq = cur_frequency / opps_div[i];
+
+               ret = dev_pm_opp_add(cpu_dev, freq, 0);
+               if (ret)
+                       return ret;
+
+               freq_tables[opps_index].freq[i] = freq;
+       }
+
+       return 0;
+}
+
+static void armada_8k_cpufreq_free_table(struct freq_table *freq_tables)
+{
+       int opps_index, nb_cpus = num_possible_cpus();
+
+       for (opps_index = 0 ; opps_index <= nb_cpus; opps_index++) {
+               int i;
+
+               /* If cpu_dev is NULL then we reached the end of the array */
+               if (!freq_tables[opps_index].cpu_dev)
+                       break;
+
+               for (i = 0; i < ARRAY_SIZE(opps_div); i++) {
+                       /*
+                        * A 0Hz frequency is not valid, this meant
+                        * that it was not yet initialized so there is
+                        * no more opp to free
+                        */
+                       if (freq_tables[opps_index].freq[i] == 0)
+                               break;
+
+                       dev_pm_opp_remove(freq_tables[opps_index].cpu_dev,
+                                         freq_tables[opps_index].freq[i]);
+               }
+       }
+
+       kfree(freq_tables);
+}
+
+static int __init armada_8k_cpufreq_init(void)
+{
+       int ret = 0, opps_index = 0, cpu, nb_cpus;
+       struct freq_table *freq_tables;
+       struct device_node *node;
+       struct cpumask cpus;
+
+       node = of_find_compatible_node(NULL, NULL, "marvell,ap806-cpu-clock");
+       if (!node || !of_device_is_available(node))
+               return -ENODEV;
+
+       nb_cpus = num_possible_cpus();
+       freq_tables = kcalloc(nb_cpus, sizeof(*freq_tables), GFP_KERNEL);
+       cpumask_copy(&cpus, cpu_possible_mask);
+
+       /*
+        * For each CPU, this loop registers the operating points
+        * supported (which are the nominal CPU frequency and full integer
+        * divisions of it).
+        */
+       for_each_cpu(cpu, &cpus) {
+               struct cpumask shared_cpus;
+               struct device *cpu_dev;
+               struct clk *clk;
+
+               cpu_dev = get_cpu_device(cpu);
+
+               if (!cpu_dev) {
+                       pr_err("Cannot get CPU %d\n", cpu);
+                       continue;
+               }
+
+               clk = clk_get(cpu_dev, 0);
+
+               if (IS_ERR(clk)) {
+                       pr_err("Cannot get clock for CPU %d\n", cpu);
+                       ret = PTR_ERR(clk);
+                       goto remove_opp;
+               }
+
+               ret = armada_8k_add_opp(clk, cpu_dev, freq_tables, opps_index);
+               if (ret) {
+                       clk_put(clk);
+                       goto remove_opp;
+               }
+
+               opps_index++;
+               cpumask_clear(&shared_cpus);
+               armada_8k_get_sharing_cpus(clk, &shared_cpus);
+               dev_pm_opp_set_sharing_cpus(cpu_dev, &shared_cpus);
+               cpumask_andnot(&cpus, &cpus, &shared_cpus);
+               clk_put(clk);
+       }
+
+       armada_8k_pdev = platform_device_register_simple("cpufreq-dt", -1,
+                                                        NULL, 0);
+       ret = PTR_ERR_OR_ZERO(armada_8k_pdev);
+       if (ret)
+               goto remove_opp;
+
+       platform_set_drvdata(armada_8k_pdev, freq_tables);
+
+       return 0;
+
+remove_opp:
+       armada_8k_cpufreq_free_table(freq_tables);
+       return ret;
+}
+module_init(armada_8k_cpufreq_init);
+
+static void __exit armada_8k_cpufreq_exit(void)
+{
+       struct freq_table *freq_tables = platform_get_drvdata(armada_8k_pdev);
+
+       platform_device_unregister(armada_8k_pdev);
+       armada_8k_cpufreq_free_table(freq_tables);
+}
+module_exit(armada_8k_cpufreq_exit);
+
+MODULE_AUTHOR("Gregory Clement <gregory.clement@bootlin.com>");
+MODULE_DESCRIPTION("Armada 8K cpufreq driver");
+MODULE_LICENSE("GPL");
index fd25c21cee72f4593be01001b9538568ceea21f2..2ae978d27e613fea57c758968f34ee97f4686f02 100644 (file)
  */
 static struct cppc_cpudata **all_cpu_data;
 
+struct cppc_workaround_oem_info {
+       char oem_id[ACPI_OEM_ID_SIZE +1];
+       char oem_table_id[ACPI_OEM_TABLE_ID_SIZE + 1];
+       u32 oem_revision;
+};
+
+static bool apply_hisi_workaround;
+
+static struct cppc_workaround_oem_info wa_info[] = {
+       {
+               .oem_id         = "HISI  ",
+               .oem_table_id   = "HIP07   ",
+               .oem_revision   = 0,
+       }, {
+               .oem_id         = "HISI  ",
+               .oem_table_id   = "HIP08   ",
+               .oem_revision   = 0,
+       }
+};
+
+static unsigned int cppc_cpufreq_perf_to_khz(struct cppc_cpudata *cpu,
+                                       unsigned int perf);
+
+/*
+ * HISI platform does not support delivered performance counter and
+ * reference performance counter. It can calculate the performance using the
+ * platform specific mechanism. We reuse the desired performance register to
+ * store the real performance calculated by the platform.
+ */
+static unsigned int hisi_cppc_cpufreq_get_rate(unsigned int cpunum)
+{
+       struct cppc_cpudata *cpudata = all_cpu_data[cpunum];
+       u64 desired_perf;
+       int ret;
+
+       ret = cppc_get_desired_perf(cpunum, &desired_perf);
+       if (ret < 0)
+               return -EIO;
+
+       return cppc_cpufreq_perf_to_khz(cpudata, desired_perf);
+}
+
+static void cppc_check_hisi_workaround(void)
+{
+       struct acpi_table_header *tbl;
+       acpi_status status = AE_OK;
+       int i;
+
+       status = acpi_get_table(ACPI_SIG_PCCT, 0, &tbl);
+       if (ACPI_FAILURE(status) || !tbl)
+               return;
+
+       for (i = 0; i < ARRAY_SIZE(wa_info); i++) {
+               if (!memcmp(wa_info[i].oem_id, tbl->oem_id, ACPI_OEM_ID_SIZE) &&
+                   !memcmp(wa_info[i].oem_table_id, tbl->oem_table_id, ACPI_OEM_TABLE_ID_SIZE) &&
+                   wa_info[i].oem_revision == tbl->oem_revision)
+                       apply_hisi_workaround = true;
+       }
+}
+
 /* Callback function used to retrieve the max frequency from DMI */
 static void cppc_find_dmi_mhz(const struct dmi_header *dm, void *private)
 {
@@ -334,6 +394,9 @@ static unsigned int cppc_cpufreq_get_rate(unsigned int cpunum)
        struct cppc_cpudata *cpu = all_cpu_data[cpunum];
        int ret;
 
+       if (apply_hisi_workaround)
+               return hisi_cppc_cpufreq_get_rate(cpunum);
+
        ret = cppc_get_perf_ctrs(cpunum, &fb_ctrs_t0);
        if (ret)
                return ret;
@@ -386,6 +449,8 @@ static int __init cppc_cpufreq_init(void)
                goto out;
        }
 
+       cppc_check_hisi_workaround();
+
        ret = cpufreq_register_driver(&cppc_cpufreq_driver);
        if (ret)
                goto out;
index e58bfcb1169ebb0acc4d5da303b0754192196130..1aefaa1b0ca295ce4cb2aa3f3a4a1ce3e8d946a1 100644 (file)
@@ -13,7 +13,6 @@
 
 #include <linux/clk.h>
 #include <linux/cpu.h>
-#include <linux/cpu_cooling.h>
 #include <linux/cpufreq.h>
 #include <linux/cpumask.h>
 #include <linux/err.h>
@@ -30,7 +29,6 @@
 struct private_data {
        struct opp_table *opp_table;
        struct device *cpu_dev;
-       struct thermal_cooling_device *cdev;
        const char *reg_name;
        bool have_static_opps;
 };
@@ -297,11 +295,25 @@ static int cpufreq_init(struct cpufreq_policy *policy)
        return ret;
 }
 
+static int cpufreq_online(struct cpufreq_policy *policy)
+{
+       /* We did light-weight tear down earlier, nothing to do here */
+       return 0;
+}
+
+static int cpufreq_offline(struct cpufreq_policy *policy)
+{
+       /*
+        * Preserve policy->driver_data and don't free resources on light-weight
+        * tear down.
+        */
+       return 0;
+}
+
 static int cpufreq_exit(struct cpufreq_policy *policy)
 {
        struct private_data *priv = policy->driver_data;
 
-       cpufreq_cooling_unregister(priv->cdev);
        dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table);
        if (priv->have_static_opps)
                dev_pm_opp_of_cpumask_remove_table(policy->related_cpus);
@@ -314,21 +326,16 @@ static int cpufreq_exit(struct cpufreq_policy *policy)
        return 0;
 }
 
-static void cpufreq_ready(struct cpufreq_policy *policy)
-{
-       struct private_data *priv = policy->driver_data;
-
-       priv->cdev = of_cpufreq_cooling_register(policy);
-}
-
 static struct cpufreq_driver dt_cpufreq_driver = {
-       .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK,
+       .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK |
+                CPUFREQ_IS_COOLING_DEV,
        .verify = cpufreq_generic_frequency_table_verify,
        .target_index = set_target,
        .get = cpufreq_generic_get,
        .init = cpufreq_init,
        .exit = cpufreq_exit,
-       .ready = cpufreq_ready,
+       .online = cpufreq_online,
+       .offline = cpufreq_offline,
        .name = "cpufreq-dt",
        .attr = cpufreq_dt_attr,
        .suspend = cpufreq_generic_suspend,
index e35a886e00bcf1d18f9683dd7f1a68a7569d4535..0e626b00053b6672131588034d13d2880e64fe1a 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <linux/cpu.h>
 #include <linux/cpufreq.h>
+#include <linux/cpu_cooling.h>
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/init.h>
@@ -545,13 +546,13 @@ EXPORT_SYMBOL_GPL(cpufreq_policy_transition_delay_us);
  *                          SYSFS INTERFACE                          *
  *********************************************************************/
 static ssize_t show_boost(struct kobject *kobj,
-                                struct attribute *attr, char *buf)
+                         struct kobj_attribute *attr, char *buf)
 {
        return sprintf(buf, "%d\n", cpufreq_driver->boost_enabled);
 }
 
-static ssize_t store_boost(struct kobject *kobj, struct attribute *attr,
-                                 const char *buf, size_t count)
+static ssize_t store_boost(struct kobject *kobj, struct kobj_attribute *attr,
+                          const char *buf, size_t count)
 {
        int ret, enable;
 
@@ -1200,28 +1201,39 @@ static int cpufreq_online(unsigned int cpu)
                        return -ENOMEM;
        }
 
-       cpumask_copy(policy->cpus, cpumask_of(cpu));
+       if (!new_policy && cpufreq_driver->online) {
+               ret = cpufreq_driver->online(policy);
+               if (ret) {
+                       pr_debug("%s: %d: initialization failed\n", __func__,
+                                __LINE__);
+                       goto out_exit_policy;
+               }
 
-       /* call driver. From then on the cpufreq must be able
-        * to accept all calls to ->verify and ->setpolicy for this CPU
-        */
-       ret = cpufreq_driver->init(policy);
-       if (ret) {
-               pr_debug("initialization failed\n");
-               goto out_free_policy;
-       }
+               /* Recover policy->cpus using related_cpus */
+               cpumask_copy(policy->cpus, policy->related_cpus);
+       } else {
+               cpumask_copy(policy->cpus, cpumask_of(cpu));
 
-       ret = cpufreq_table_validate_and_sort(policy);
-       if (ret)
-               goto out_exit_policy;
+               /*
+                * Call driver. From then on the cpufreq must be able
+                * to accept all calls to ->verify and ->setpolicy for this CPU.
+                */
+               ret = cpufreq_driver->init(policy);
+               if (ret) {
+                       pr_debug("%s: %d: initialization failed\n", __func__,
+                                __LINE__);
+                       goto out_free_policy;
+               }
 
-       down_write(&policy->rwsem);
+               ret = cpufreq_table_validate_and_sort(policy);
+               if (ret)
+                       goto out_exit_policy;
 
-       if (new_policy) {
                /* related_cpus should at least include policy->cpus. */
                cpumask_copy(policy->related_cpus, policy->cpus);
        }
 
+       down_write(&policy->rwsem);
        /*
         * affected cpus must always be the one, which are online. We aren't
         * managing offline cpus here.
@@ -1305,8 +1317,6 @@ static int cpufreq_online(unsigned int cpu)
        if (ret) {
                pr_err("%s: Failed to initialize policy for cpu: %d (%d)\n",
                       __func__, cpu, ret);
-               /* cpufreq_policy_free() will notify based on this */
-               new_policy = false;
                goto out_destroy_policy;
        }
 
@@ -1318,6 +1328,10 @@ static int cpufreq_online(unsigned int cpu)
        if (cpufreq_driver->ready)
                cpufreq_driver->ready(policy);
 
+       if (IS_ENABLED(CONFIG_CPU_THERMAL) &&
+           cpufreq_driver->flags & CPUFREQ_IS_COOLING_DEV)
+               policy->cdev = of_cpufreq_cooling_register(policy);
+
        pr_debug("initialization complete\n");
 
        return 0;
@@ -1405,6 +1419,12 @@ static int cpufreq_offline(unsigned int cpu)
                goto unlock;
        }
 
+       if (IS_ENABLED(CONFIG_CPU_THERMAL) &&
+           cpufreq_driver->flags & CPUFREQ_IS_COOLING_DEV) {
+               cpufreq_cooling_unregister(policy->cdev);
+               policy->cdev = NULL;
+       }
+
        if (cpufreq_driver->stop_cpu)
                cpufreq_driver->stop_cpu(policy);
 
@@ -1412,11 +1432,12 @@ static int cpufreq_offline(unsigned int cpu)
                cpufreq_exit_governor(policy);
 
        /*
-        * Perform the ->exit() even during light-weight tear-down,
-        * since this is a core component, and is essential for the
-        * subsequent light-weight ->init() to succeed.
+        * Perform the ->offline() during light-weight tear-down, as
+        * that allows fast recovery when the CPU comes back.
         */
-       if (cpufreq_driver->exit) {
+       if (cpufreq_driver->offline) {
+               cpufreq_driver->offline(policy);
+       } else if (cpufreq_driver->exit) {
                cpufreq_driver->exit(policy);
                policy->freq_table = NULL;
        }
@@ -1445,8 +1466,13 @@ static void cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
        cpumask_clear_cpu(cpu, policy->real_cpus);
        remove_cpu_dev_symlink(policy, dev);
 
-       if (cpumask_empty(policy->real_cpus))
+       if (cpumask_empty(policy->real_cpus)) {
+               /* We did light-weight exit earlier, do full tear down now */
+               if (cpufreq_driver->offline)
+                       cpufreq_driver->exit(policy);
+
                cpufreq_policy_free(policy);
+       }
 }
 
 /**
@@ -2192,12 +2218,25 @@ int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu)
 }
 EXPORT_SYMBOL(cpufreq_get_policy);
 
-/*
- * policy : current policy.
- * new_policy: policy to be set.
+/**
+ * cpufreq_set_policy - Modify cpufreq policy parameters.
+ * @policy: Policy object to modify.
+ * @new_policy: New policy data.
+ *
+ * Pass @new_policy to the cpufreq driver's ->verify() callback, run the
+ * installed policy notifiers for it with the CPUFREQ_ADJUST value, pass it to
+ * the driver's ->verify() callback again and run the notifiers for it again
+ * with the CPUFREQ_NOTIFY value.  Next, copy the min and max parameters
+ * of @new_policy to @policy and either invoke the driver's ->setpolicy()
+ * callback (if present) or carry out a governor update for @policy.  That is,
+ * run the current governor's ->limits() callback (if the governor field in
+ * @new_policy points to the same object as the one in @policy) or replace the
+ * governor for @policy with the new one stored in @new_policy.
+ *
+ * The cpuinfo part of @policy is not updated by this function.
  */
 static int cpufreq_set_policy(struct cpufreq_policy *policy,
-                               struct cpufreq_policy *new_policy)
+                             struct cpufreq_policy *new_policy)
 {
        struct cpufreq_governor *old_gov;
        int ret;
@@ -2247,11 +2286,11 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
        if (cpufreq_driver->setpolicy) {
                policy->policy = new_policy->policy;
                pr_debug("setting range\n");
-               return cpufreq_driver->setpolicy(new_policy);
+               return cpufreq_driver->setpolicy(policy);
        }
 
        if (new_policy->governor == policy->governor) {
-               pr_debug("cpufreq: governor limits update\n");
+               pr_debug("governor limits update\n");
                cpufreq_governor_limits(policy);
                return 0;
        }
@@ -2272,7 +2311,7 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
        if (!ret) {
                ret = cpufreq_start_governor(policy);
                if (!ret) {
-                       pr_debug("cpufreq: governor change\n");
+                       pr_debug("governor change\n");
                        sched_cpufreq_governor_change(policy, old_gov);
                        return 0;
                }
@@ -2293,11 +2332,14 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
 }
 
 /**
- *     cpufreq_update_policy - re-evaluate an existing cpufreq policy
- *     @cpu: CPU which shall be re-evaluated
+ * cpufreq_update_policy - Re-evaluate an existing cpufreq policy.
+ * @cpu: CPU to re-evaluate the policy for.
  *
- *     Useful for policy notifiers which have different necessities
- *     at different times.
+ * Update the current frequency for the cpufreq policy of @cpu and use
+ * cpufreq_set_policy() to re-apply the min and max limits saved in the
+ * user_policy sub-structure of that policy, which triggers the evaluation
+ * of policy notifiers and the cpufreq driver's ->verify() callback for the
+ * policy in question, among other things.
  */
 void cpufreq_update_policy(unsigned int cpu)
 {
@@ -2312,23 +2354,18 @@ void cpufreq_update_policy(unsigned int cpu)
        if (policy_is_inactive(policy))
                goto unlock;
 
-       pr_debug("updating policy for CPU %u\n", cpu);
-       memcpy(&new_policy, policy, sizeof(*policy));
-       new_policy.min = policy->user_policy.min;
-       new_policy.max = policy->user_policy.max;
-
        /*
         * BIOS might change freq behind our back
         * -> ask driver for current freq and notify governors about a change
         */
-       if (cpufreq_driver->get && !cpufreq_driver->setpolicy) {
-               if (cpufreq_suspended)
-                       goto unlock;
+       if (cpufreq_driver->get && !cpufreq_driver->setpolicy &&
+           (cpufreq_suspended || WARN_ON(!cpufreq_update_current_freq(policy))))
+               goto unlock;
 
-               new_policy.cur = cpufreq_update_current_freq(policy);
-               if (WARN_ON(!new_policy.cur))
-                       goto unlock;
-       }
+       pr_debug("updating policy for CPU %u\n", cpu);
+       memcpy(&new_policy, policy, sizeof(*policy));
+       new_policy.min = policy->user_policy.min;
+       new_policy.max = policy->user_policy.max;
 
        cpufreq_set_policy(policy, &new_policy);
 
@@ -2479,7 +2516,8 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
                    driver_data->target) ||
             (driver_data->setpolicy && (driver_data->target_index ||
                    driver_data->target)) ||
-            (!!driver_data->get_intermediate != !!driver_data->target_intermediate))
+            (!driver_data->get_intermediate != !driver_data->target_intermediate) ||
+            (!driver_data->online != !driver_data->offline))
                return -EINVAL;
 
        pr_debug("trying to register driver %s\n", driver_data->name);
index 1572129844a5bf6e223ed92c55733f215feb312e..e2db5581489a03a4db6b91791e4deaec44c7e33a 100644 (file)
@@ -31,26 +31,27 @@ static void cpufreq_stats_update(struct cpufreq_stats *stats)
 {
        unsigned long long cur_time = get_jiffies_64();
 
-       spin_lock(&cpufreq_stats_lock);
        stats->time_in_state[stats->last_index] += cur_time - stats->last_time;
        stats->last_time = cur_time;
-       spin_unlock(&cpufreq_stats_lock);
 }
 
 static void cpufreq_stats_clear_table(struct cpufreq_stats *stats)
 {
        unsigned int count = stats->max_state;
 
+       spin_lock(&cpufreq_stats_lock);
        memset(stats->time_in_state, 0, count * sizeof(u64));
        memset(stats->trans_table, 0, count * count * sizeof(int));
        stats->last_time = get_jiffies_64();
        stats->total_trans = 0;
+       spin_unlock(&cpufreq_stats_lock);
 }
 
 static ssize_t show_total_trans(struct cpufreq_policy *policy, char *buf)
 {
        return sprintf(buf, "%d\n", policy->stats->total_trans);
 }
+cpufreq_freq_attr_ro(total_trans);
 
 static ssize_t show_time_in_state(struct cpufreq_policy *policy, char *buf)
 {
@@ -61,7 +62,10 @@ static ssize_t show_time_in_state(struct cpufreq_policy *policy, char *buf)
        if (policy->fast_switch_enabled)
                return 0;
 
+       spin_lock(&cpufreq_stats_lock);
        cpufreq_stats_update(stats);
+       spin_unlock(&cpufreq_stats_lock);
+
        for (i = 0; i < stats->state_num; i++) {
                len += sprintf(buf + len, "%u %llu\n", stats->freq_table[i],
                        (unsigned long long)
@@ -69,6 +73,7 @@ static ssize_t show_time_in_state(struct cpufreq_policy *policy, char *buf)
        }
        return len;
 }
+cpufreq_freq_attr_ro(time_in_state);
 
 static ssize_t store_reset(struct cpufreq_policy *policy, const char *buf,
                           size_t count)
@@ -77,6 +82,7 @@ static ssize_t store_reset(struct cpufreq_policy *policy, const char *buf,
        cpufreq_stats_clear_table(policy->stats);
        return count;
 }
+cpufreq_freq_attr_wo(reset);
 
 static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf)
 {
@@ -126,10 +132,6 @@ static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf)
 }
 cpufreq_freq_attr_ro(trans_table);
 
-cpufreq_freq_attr_ro(total_trans);
-cpufreq_freq_attr_ro(time_in_state);
-cpufreq_freq_attr_wo(reset);
-
 static struct attribute *default_attrs[] = {
        &total_trans.attr,
        &time_in_state.attr,
@@ -240,9 +242,11 @@ void cpufreq_stats_record_transition(struct cpufreq_policy *policy,
        if (old_index == -1 || new_index == -1 || old_index == new_index)
                return;
 
+       spin_lock(&cpufreq_stats_lock);
        cpufreq_stats_update(stats);
 
        stats->last_index = new_index;
        stats->trans_table[old_index * stats->max_state + new_index]++;
        stats->total_trans++;
+       spin_unlock(&cpufreq_stats_lock);
 }
index d54a27c9912188f472705ade364574e63a90780e..940fe85db97a58df7d3eac9732f51fb865d4f6d8 100644 (file)
 #include <linux/init.h>
 #include <linux/err.h>
 #include <linux/clk.h>
+#include <linux/platform_data/davinci-cpufreq.h>
 #include <linux/platform_device.h>
 #include <linux/export.h>
 
-#include <mach/hardware.h>
-#include <mach/cpufreq.h>
-#include <mach/common.h>
-
 struct davinci_cpufreq {
        struct device *dev;
        struct clk *armclk;
index 60bea302abbee265edf30457ba3df4bfa5a9e440..2d3ef208dd7000db6107893eef368761c2776994 100644 (file)
@@ -323,9 +323,8 @@ static int eps_cpu_init(struct cpufreq_policy *policy)
                states = 2;
 
        /* Allocate private data and frequency table for current cpu */
-       centaur = kzalloc(sizeof(*centaur)
-                   + (states + 1) * sizeof(struct cpufreq_frequency_table),
-                   GFP_KERNEL);
+       centaur = kzalloc(struct_size(centaur, freq_table, states + 1),
+                         GFP_KERNEL);
        if (!centaur)
                return -ENOMEM;
        eps_cpu[0] = centaur;
index 9fedf627e000d5338b3c97b1f0760c8b67dbb28d..ca955713e07052c89e1f6fd9331d1fd7e6ac5ab3 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/clk.h>
 #include <linux/cpu.h>
 #include <linux/cpufreq.h>
-#include <linux/cpu_cooling.h>
 #include <linux/err.h>
 #include <linux/module.h>
 #include <linux/nvmem-consumer.h>
@@ -52,7 +51,6 @@ static struct clk_bulk_data clks[] = {
 };
 
 static struct device *cpu_dev;
-static struct thermal_cooling_device *cdev;
 static bool free_opp;
 static struct cpufreq_frequency_table *freq_table;
 static unsigned int max_freq;
@@ -193,16 +191,6 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
        return 0;
 }
 
-static void imx6q_cpufreq_ready(struct cpufreq_policy *policy)
-{
-       cdev = of_cpufreq_cooling_register(policy);
-
-       if (!cdev)
-               dev_err(cpu_dev,
-                       "running cpufreq without cooling device: %ld\n",
-                       PTR_ERR(cdev));
-}
-
 static int imx6q_cpufreq_init(struct cpufreq_policy *policy)
 {
        int ret;
@@ -214,22 +202,14 @@ static int imx6q_cpufreq_init(struct cpufreq_policy *policy)
        return ret;
 }
 
-static int imx6q_cpufreq_exit(struct cpufreq_policy *policy)
-{
-       cpufreq_cooling_unregister(cdev);
-
-       return 0;
-}
-
 static struct cpufreq_driver imx6q_cpufreq_driver = {
-       .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK,
+       .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK |
+                CPUFREQ_IS_COOLING_DEV,
        .verify = cpufreq_generic_frequency_table_verify,
        .target_index = imx6q_set_target,
        .get = cpufreq_generic_get,
        .init = imx6q_cpufreq_init,
-       .exit = imx6q_cpufreq_exit,
        .name = "imx6q-cpufreq",
-       .ready = imx6q_cpufreq_ready,
        .attr = cpufreq_generic_attr,
        .suspend = cpufreq_generic_suspend,
 };
index dd66decf2087c1cd51bab83533b631885a084952..002f5169d4ebca567e2753b6f3a7bd509b298c2d 100644 (file)
@@ -50,6 +50,8 @@
 #define int_tofp(X) ((int64_t)(X) << FRAC_BITS)
 #define fp_toint(X) ((X) >> FRAC_BITS)
 
+#define ONE_EIGHTH_FP ((int64_t)1 << (FRAC_BITS - 3))
+
 #define EXT_BITS 6
 #define EXT_FRAC_BITS (EXT_BITS + FRAC_BITS)
 #define fp_ext_toint(X) ((X) >> EXT_FRAC_BITS)
@@ -895,7 +897,7 @@ static void intel_pstate_update_policies(void)
 /************************** sysfs begin ************************/
 #define show_one(file_name, object)                                    \
        static ssize_t show_##file_name                                 \
-       (struct kobject *kobj, struct attribute *attr, char *buf)       \
+       (struct kobject *kobj, struct kobj_attribute *attr, char *buf)  \
        {                                                               \
                return sprintf(buf, "%u\n", global.object);             \
        }
@@ -904,7 +906,7 @@ static ssize_t intel_pstate_show_status(char *buf);
 static int intel_pstate_update_status(const char *buf, size_t size);
 
 static ssize_t show_status(struct kobject *kobj,
-                          struct attribute *attr, char *buf)
+                          struct kobj_attribute *attr, char *buf)
 {
        ssize_t ret;
 
@@ -915,7 +917,7 @@ static ssize_t show_status(struct kobject *kobj,
        return ret;
 }
 
-static ssize_t store_status(struct kobject *a, struct attribute *b,
+static ssize_t store_status(struct kobject *a, struct kobj_attribute *b,
                            const char *buf, size_t count)
 {
        char *p = memchr(buf, '\n', count);
@@ -929,7 +931,7 @@ static ssize_t store_status(struct kobject *a, struct attribute *b,
 }
 
 static ssize_t show_turbo_pct(struct kobject *kobj,
-                               struct attribute *attr, char *buf)
+                               struct kobj_attribute *attr, char *buf)
 {
        struct cpudata *cpu;
        int total, no_turbo, turbo_pct;
@@ -955,7 +957,7 @@ static ssize_t show_turbo_pct(struct kobject *kobj,
 }
 
 static ssize_t show_num_pstates(struct kobject *kobj,
-                               struct attribute *attr, char *buf)
+                               struct kobj_attribute *attr, char *buf)
 {
        struct cpudata *cpu;
        int total;
@@ -976,7 +978,7 @@ static ssize_t show_num_pstates(struct kobject *kobj,
 }
 
 static ssize_t show_no_turbo(struct kobject *kobj,
-                            struct attribute *attr, char *buf)
+                            struct kobj_attribute *attr, char *buf)
 {
        ssize_t ret;
 
@@ -998,7 +1000,7 @@ static ssize_t show_no_turbo(struct kobject *kobj,
        return ret;
 }
 
-static ssize_t store_no_turbo(struct kobject *a, struct attribute *b,
+static ssize_t store_no_turbo(struct kobject *a, struct kobj_attribute *b,
                              const char *buf, size_t count)
 {
        unsigned int input;
@@ -1045,7 +1047,7 @@ static ssize_t store_no_turbo(struct kobject *a, struct attribute *b,
        return count;
 }
 
-static ssize_t store_max_perf_pct(struct kobject *a, struct attribute *b,
+static ssize_t store_max_perf_pct(struct kobject *a, struct kobj_attribute *b,
                                  const char *buf, size_t count)
 {
        unsigned int input;
@@ -1075,7 +1077,7 @@ static ssize_t store_max_perf_pct(struct kobject *a, struct attribute *b,
        return count;
 }
 
-static ssize_t store_min_perf_pct(struct kobject *a, struct attribute *b,
+static ssize_t store_min_perf_pct(struct kobject *a, struct kobj_attribute *b,
                                  const char *buf, size_t count)
 {
        unsigned int input;
@@ -1107,12 +1109,13 @@ static ssize_t store_min_perf_pct(struct kobject *a, struct attribute *b,
 }
 
 static ssize_t show_hwp_dynamic_boost(struct kobject *kobj,
-                               struct attribute *attr, char *buf)
+                               struct kobj_attribute *attr, char *buf)
 {
        return sprintf(buf, "%u\n", hwp_boost);
 }
 
-static ssize_t store_hwp_dynamic_boost(struct kobject *a, struct attribute *b,
+static ssize_t store_hwp_dynamic_boost(struct kobject *a,
+                                      struct kobj_attribute *b,
                                       const char *buf, size_t count)
 {
        unsigned int input;
@@ -1444,12 +1447,6 @@ static int knl_get_turbo_pstate(void)
        return ret;
 }
 
-static int intel_pstate_get_base_pstate(struct cpudata *cpu)
-{
-       return global.no_turbo || global.turbo_disabled ?
-                       cpu->pstate.max_pstate : cpu->pstate.turbo_pstate;
-}
-
 static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate)
 {
        trace_cpu_frequency(pstate * cpu->pstate.scaling, cpu->cpu);
@@ -1470,11 +1467,9 @@ static void intel_pstate_set_min_pstate(struct cpudata *cpu)
 
 static void intel_pstate_max_within_limits(struct cpudata *cpu)
 {
-       int pstate;
+       int pstate = max(cpu->pstate.min_pstate, cpu->max_perf_ratio);
 
        update_turbo_state();
-       pstate = intel_pstate_get_base_pstate(cpu);
-       pstate = max(cpu->pstate.min_pstate, cpu->max_perf_ratio);
        intel_pstate_set_pstate(cpu, pstate);
 }
 
@@ -1678,17 +1673,14 @@ static inline int32_t get_avg_pstate(struct cpudata *cpu)
 static inline int32_t get_target_pstate(struct cpudata *cpu)
 {
        struct sample *sample = &cpu->sample;
-       int32_t busy_frac, boost;
+       int32_t busy_frac;
        int target, avg_pstate;
 
        busy_frac = div_fp(sample->mperf << cpu->aperf_mperf_shift,
                           sample->tsc);
 
-       boost = cpu->iowait_boost;
-       cpu->iowait_boost >>= 1;
-
-       if (busy_frac < boost)
-               busy_frac = boost;
+       if (busy_frac < cpu->iowait_boost)
+               busy_frac = cpu->iowait_boost;
 
        sample->busy_scaled = busy_frac * 100;
 
@@ -1715,11 +1707,9 @@ static inline int32_t get_target_pstate(struct cpudata *cpu)
 
 static int intel_pstate_prepare_request(struct cpudata *cpu, int pstate)
 {
-       int max_pstate = intel_pstate_get_base_pstate(cpu);
-       int min_pstate;
+       int min_pstate = max(cpu->pstate.min_pstate, cpu->min_perf_ratio);
+       int max_pstate = max(min_pstate, cpu->max_perf_ratio);
 
-       min_pstate = max(cpu->pstate.min_pstate, cpu->min_perf_ratio);
-       max_pstate = max(min_pstate, cpu->max_perf_ratio);
        return clamp_t(int, pstate, min_pstate, max_pstate);
 }
 
@@ -1767,29 +1757,30 @@ static void intel_pstate_update_util(struct update_util_data *data, u64 time,
        if (smp_processor_id() != cpu->cpu)
                return;
 
+       delta_ns = time - cpu->last_update;
        if (flags & SCHED_CPUFREQ_IOWAIT) {
-               cpu->iowait_boost = int_tofp(1);
-               cpu->last_update = time;
-               /*
-                * The last time the busy was 100% so P-state was max anyway
-                * so avoid overhead of computation.
-                */
-               if (fp_toint(cpu->sample.busy_scaled) == 100)
-                       return;
-
-               goto set_pstate;
+               /* Start over if the CPU may have been idle. */
+               if (delta_ns > TICK_NSEC) {
+                       cpu->iowait_boost = ONE_EIGHTH_FP;
+               } else if (cpu->iowait_boost) {
+                       cpu->iowait_boost <<= 1;
+                       if (cpu->iowait_boost > int_tofp(1))
+                               cpu->iowait_boost = int_tofp(1);
+               } else {
+                       cpu->iowait_boost = ONE_EIGHTH_FP;
+               }
        } else if (cpu->iowait_boost) {
                /* Clear iowait_boost if the CPU may have been idle. */
-               delta_ns = time - cpu->last_update;
                if (delta_ns > TICK_NSEC)
                        cpu->iowait_boost = 0;
+               else
+                       cpu->iowait_boost >>= 1;
        }
        cpu->last_update = time;
        delta_ns = time - cpu->sample.time;
        if ((s64)delta_ns < INTEL_PSTATE_SAMPLING_INTERVAL)
                return;
 
-set_pstate:
        if (intel_pstate_sample(cpu, time))
                intel_pstate_adjust_pstate(cpu);
 }
@@ -1976,7 +1967,8 @@ static void intel_pstate_update_perf_limits(struct cpufreq_policy *policy,
        if (hwp_active) {
                intel_pstate_get_hwp_max(cpu->cpu, &turbo_max, &max_state);
        } else {
-               max_state = intel_pstate_get_base_pstate(cpu);
+               max_state = global.no_turbo || global.turbo_disabled ?
+                       cpu->pstate.max_pstate : cpu->pstate.turbo_pstate;
                turbo_max = cpu->pstate.turbo_pstate;
        }
 
@@ -2475,6 +2467,7 @@ static bool __init intel_pstate_no_acpi_pss(void)
                kfree(pss);
        }
 
+       pr_debug("ACPI _PSS not found\n");
        return true;
 }
 
@@ -2485,9 +2478,14 @@ static bool __init intel_pstate_no_acpi_pcch(void)
 
        status = acpi_get_handle(NULL, "\\_SB", &handle);
        if (ACPI_FAILURE(status))
-               return true;
+               goto not_found;
+
+       if (acpi_has_method(handle, "PCCH"))
+               return false;
 
-       return !acpi_has_method(handle, "PCCH");
+not_found:
+       pr_debug("ACPI PCCH not found\n");
+       return true;
 }
 
 static bool __init intel_pstate_has_acpi_ppc(void)
@@ -2502,6 +2500,7 @@ static bool __init intel_pstate_has_acpi_ppc(void)
                if (acpi_has_method(pr->handle, "_PPC"))
                        return true;
        }
+       pr_debug("ACPI _PPC not found\n");
        return false;
 }
 
@@ -2539,8 +2538,10 @@ static bool __init intel_pstate_platform_pwr_mgmt_exists(void)
        id = x86_match_cpu(intel_pstate_cpu_oob_ids);
        if (id) {
                rdmsrl(MSR_MISC_PWR_MGMT, misc_pwr);
-               if ( misc_pwr & (1 << 8))
+               if (misc_pwr & (1 << 8)) {
+                       pr_debug("Bit 8 in the MISC_PWR_MGMT MSR set\n");
                        return true;
+               }
        }
 
        idx = acpi_match_platform_list(plat_info);
@@ -2606,22 +2607,28 @@ static int __init intel_pstate_init(void)
                }
        } else {
                id = x86_match_cpu(intel_pstate_cpu_ids);
-               if (!id)
+               if (!id) {
+                       pr_info("CPU ID not supported\n");
                        return -ENODEV;
+               }
 
                copy_cpu_funcs((struct pstate_funcs *)id->driver_data);
        }
 
-       if (intel_pstate_msrs_not_valid())
+       if (intel_pstate_msrs_not_valid()) {
+               pr_info("Invalid MSRs\n");
                return -ENODEV;
+       }
 
 hwp_cpu_matched:
        /*
         * The Intel pstate driver will be ignored if the platform
         * firmware has its own power management modes.
         */
-       if (intel_pstate_platform_pwr_mgmt_exists())
+       if (intel_pstate_platform_pwr_mgmt_exists()) {
+               pr_info("P-states controlled by the platform\n");
                return -ENODEV;
+       }
 
        if (!hwp_active && hwp_only)
                return -ENOTSUPP;
index 279bd9e9fa95f6a8fabae628c3829f6f4746f29c..fb546e0d03561576422155ddb0bb39db417a9850 100644 (file)
@@ -851,7 +851,7 @@ static int longhaul_cpu_init(struct cpufreq_policy *policy)
        case TYPE_POWERSAVER:
                pr_cont("Powersaver supported\n");
                break;
-       };
+       }
 
        /* Doesn't hurt */
        longhaul_setup_southbridge();
index eb8920d3981815f930d55465b5318c4356cca37b..4229fcc313105292db9fc28e70daca5546ee43e4 100644 (file)
@@ -14,7 +14,6 @@
 
 #include <linux/clk.h>
 #include <linux/cpu.h>
-#include <linux/cpu_cooling.h>
 #include <linux/cpufreq.h>
 #include <linux/cpumask.h>
 #include <linux/module.h>
@@ -48,7 +47,6 @@ struct mtk_cpu_dvfs_info {
        struct regulator *sram_reg;
        struct clk *cpu_clk;
        struct clk *inter_clk;
-       struct thermal_cooling_device *cdev;
        struct list_head list_head;
        int intermediate_voltage;
        bool need_voltage_tracking;
@@ -307,13 +305,6 @@ static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
 
 #define DYNAMIC_POWER "dynamic-power-coefficient"
 
-static void mtk_cpufreq_ready(struct cpufreq_policy *policy)
-{
-       struct mtk_cpu_dvfs_info *info = policy->driver_data;
-
-       info->cdev = of_cpufreq_cooling_register(policy);
-}
-
 static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
 {
        struct device *cpu_dev;
@@ -472,7 +463,6 @@ static int mtk_cpufreq_exit(struct cpufreq_policy *policy)
 {
        struct mtk_cpu_dvfs_info *info = policy->driver_data;
 
-       cpufreq_cooling_unregister(info->cdev);
        dev_pm_opp_free_cpufreq_table(info->cpu_dev, &policy->freq_table);
 
        return 0;
@@ -480,13 +470,13 @@ static int mtk_cpufreq_exit(struct cpufreq_policy *policy)
 
 static struct cpufreq_driver mtk_cpufreq_driver = {
        .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK |
-                CPUFREQ_HAVE_GOVERNOR_PER_POLICY,
+                CPUFREQ_HAVE_GOVERNOR_PER_POLICY |
+                CPUFREQ_IS_COOLING_DEV,
        .verify = cpufreq_generic_frequency_table_verify,
        .target_index = mtk_cpufreq_set_target,
        .get = cpufreq_generic_get,
        .init = mtk_cpufreq_init,
        .exit = mtk_cpufreq_exit,
-       .ready = mtk_cpufreq_ready,
        .name = "mtk-cpufreq",
        .attr = cpufreq_generic_attr,
 };
index 099a849396f69abc5eb84306eac76f1d96dd3997..1e5e64643c3a595d0f5e3ebb4f116ae8a70bc1b4 100644 (file)
@@ -268,7 +268,7 @@ static int pcc_get_offset(int cpu)
        if (!pccp || pccp->type != ACPI_TYPE_PACKAGE) {
                ret = -ENODEV;
                goto out_free;
-       };
+       }
 
        offset = &(pccp->package.elements[0]);
        if (!offset || offset->type != ACPI_TYPE_INTEGER) {
index 7e7ad3879c4e0510ee1de789815fec26ad807040..d2230812fa4bd7437effd1ce0e5a4e2749850f8f 100644 (file)
@@ -244,6 +244,7 @@ static int init_powernv_pstates(void)
        u32 len_ids, len_freqs;
        u32 pstate_min, pstate_max, pstate_nominal;
        u32 pstate_turbo, pstate_ultra_turbo;
+       int rc = -ENODEV;
 
        power_mgt = of_find_node_by_path("/ibm,opal/power-mgt");
        if (!power_mgt) {
@@ -327,8 +328,11 @@ static int init_powernv_pstates(void)
                powernv_freqs[i].frequency = freq * 1000; /* kHz */
                powernv_freqs[i].driver_data = id & 0xFF;
 
-               revmap_data = (struct pstate_idx_revmap_data *)
-                             kmalloc(sizeof(*revmap_data), GFP_KERNEL);
+               revmap_data = kmalloc(sizeof(*revmap_data), GFP_KERNEL);
+               if (!revmap_data) {
+                       rc = -ENOMEM;
+                       goto out;
+               }
 
                revmap_data->pstate_id = id & 0xFF;
                revmap_data->cpufreq_table_idx = i;
@@ -357,7 +361,7 @@ static int init_powernv_pstates(void)
        return 0;
 out:
        of_node_put(power_mgt);
-       return -ENODEV;
+       return rc;
 }
 
 /* Returns the CPU frequency corresponding to the pstate_id. */
index d83939a1b3d4cd7f4f12a70477eaced3e9bf487f..4b0b50403901b7c67c56d33cff1438b6ca0ba86a 100644 (file)
 #include <linux/module.h>
 #include <linux/of_address.h>
 #include <linux/of_platform.h>
+#include <linux/pm_opp.h>
 #include <linux/slab.h>
 
 #define LUT_MAX_ENTRIES                        40U
 #define LUT_SRC                                GENMASK(31, 30)
 #define LUT_L_VAL                      GENMASK(7, 0)
 #define LUT_CORE_COUNT                 GENMASK(18, 16)
+#define LUT_VOLT                       GENMASK(11, 0)
 #define LUT_ROW_SIZE                   32
 #define CLK_HW_DIV                     2
 
 /* Register offsets */
 #define REG_ENABLE                     0x0
-#define REG_LUT_TABLE                  0x110
+#define REG_FREQ_LUT                   0x110
+#define REG_VOLT_LUT                   0x114
 #define REG_PERF_STATE                 0x920
 
 static unsigned long cpu_hw_rate, xo_rate;
@@ -70,11 +73,12 @@ static unsigned int qcom_cpufreq_hw_fast_switch(struct cpufreq_policy *policy,
        return policy->freq_table[index].frequency;
 }
 
-static int qcom_cpufreq_hw_read_lut(struct device *dev,
+static int qcom_cpufreq_hw_read_lut(struct device *cpu_dev,
                                    struct cpufreq_policy *policy,
                                    void __iomem *base)
 {
        u32 data, src, lval, i, core_count, prev_cc = 0, prev_freq = 0, freq;
+       u32 volt;
        unsigned int max_cores = cpumask_weight(policy->cpus);
        struct cpufreq_frequency_table  *table;
 
@@ -83,23 +87,28 @@ static int qcom_cpufreq_hw_read_lut(struct device *dev,
                return -ENOMEM;
 
        for (i = 0; i < LUT_MAX_ENTRIES; i++) {
-               data = readl_relaxed(base + REG_LUT_TABLE + i * LUT_ROW_SIZE);
+               data = readl_relaxed(base + REG_FREQ_LUT +
+                                     i * LUT_ROW_SIZE);
                src = FIELD_GET(LUT_SRC, data);
                lval = FIELD_GET(LUT_L_VAL, data);
                core_count = FIELD_GET(LUT_CORE_COUNT, data);
 
+               data = readl_relaxed(base + REG_VOLT_LUT +
+                                     i * LUT_ROW_SIZE);
+               volt = FIELD_GET(LUT_VOLT, data) * 1000;
+
                if (src)
                        freq = xo_rate * lval / 1000;
                else
                        freq = cpu_hw_rate / 1000;
 
-               /* Ignore boosts in the middle of the table */
-               if (core_count != max_cores) {
-                       table[i].frequency = CPUFREQ_ENTRY_INVALID;
-               } else {
+               if (freq != prev_freq && core_count == max_cores) {
                        table[i].frequency = freq;
-                       dev_dbg(dev, "index=%d freq=%d, core_count %d\n", i,
+                       dev_pm_opp_add(cpu_dev, freq * 1000, volt);
+                       dev_dbg(cpu_dev, "index=%d freq=%d, core_count %d\n", i,
                                freq, core_count);
+               } else {
+                       table[i].frequency = CPUFREQ_ENTRY_INVALID;
                }
 
                /*
@@ -116,6 +125,7 @@ static int qcom_cpufreq_hw_read_lut(struct device *dev,
                        if (prev_cc != max_cores) {
                                prev->frequency = prev_freq;
                                prev->flags = CPUFREQ_BOOST_FREQ;
+                               dev_pm_opp_add(cpu_dev, prev_freq * 1000, volt);
                        }
 
                        break;
@@ -127,6 +137,7 @@ static int qcom_cpufreq_hw_read_lut(struct device *dev,
 
        table[i].frequency = CPUFREQ_TABLE_END;
        policy->freq_table = table;
+       dev_pm_opp_set_sharing_cpus(cpu_dev, policy->cpus);
 
        return 0;
 }
@@ -159,10 +170,18 @@ static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy)
        struct device *dev = &global_pdev->dev;
        struct of_phandle_args args;
        struct device_node *cpu_np;
+       struct device *cpu_dev;
        struct resource *res;
        void __iomem *base;
        int ret, index;
 
+       cpu_dev = get_cpu_device(policy->cpu);
+       if (!cpu_dev) {
+               pr_err("%s: failed to get cpu%d device\n", __func__,
+                      policy->cpu);
+               return -ENODEV;
+       }
+
        cpu_np = of_cpu_device_node_get(policy->cpu);
        if (!cpu_np)
                return -EINVAL;
@@ -199,12 +218,21 @@ static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy)
 
        policy->driver_data = base + REG_PERF_STATE;
 
-       ret = qcom_cpufreq_hw_read_lut(dev, policy, base);
+       ret = qcom_cpufreq_hw_read_lut(cpu_dev, policy, base);
        if (ret) {
                dev_err(dev, "Domain-%d failed to read LUT\n", index);
                goto error;
        }
 
+       ret = dev_pm_opp_get_opp_count(cpu_dev);
+       if (ret <= 0) {
+               dev_err(cpu_dev, "Failed to add OPPs\n");
+               ret = -ENODEV;
+               goto error;
+       }
+
+       dev_pm_opp_of_register_em(policy->cpus);
+
        policy->fast_switch_possible = true;
 
        return 0;
@@ -215,8 +243,10 @@ static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy)
 
 static int qcom_cpufreq_hw_cpu_exit(struct cpufreq_policy *policy)
 {
+       struct device *cpu_dev = get_cpu_device(policy->cpu);
        void __iomem *base = policy->driver_data - REG_PERF_STATE;
 
+       dev_pm_opp_remove_all_dynamic(cpu_dev);
        kfree(policy->freq_table);
        devm_iounmap(&global_pdev->dev, base);
 
@@ -231,7 +261,8 @@ static struct freq_attr *qcom_cpufreq_hw_attr[] = {
 
 static struct cpufreq_driver cpufreq_qcom_hw_driver = {
        .flags          = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK |
-                         CPUFREQ_HAVE_GOVERNOR_PER_POLICY,
+                         CPUFREQ_HAVE_GOVERNOR_PER_POLICY |
+                         CPUFREQ_IS_COOLING_DEV,
        .verify         = cpufreq_generic_frequency_table_verify,
        .target_index   = qcom_cpufreq_hw_target_index,
        .get            = qcom_cpufreq_hw_get,
@@ -296,7 +327,7 @@ static int __init qcom_cpufreq_hw_init(void)
 {
        return platform_driver_register(&qcom_cpufreq_hw_driver);
 }
-subsys_initcall(qcom_cpufreq_hw_init);
+device_initcall(qcom_cpufreq_hw_init);
 
 static void __exit qcom_cpufreq_hw_exit(void)
 {
index 2a3675c24032bc8059c4c591698d6a7b5218cf1d..1c8583cc06a2aa5f95bfc4c4ce0ca6f56e9a5d62 100644 (file)
@@ -42,7 +42,7 @@ enum _msm8996_version {
        NUM_OF_MSM8996_VERSIONS,
 };
 
-struct platform_device *cpufreq_dt_pdev, *kryo_cpufreq_pdev;
+static struct platform_device *cpufreq_dt_pdev, *kryo_cpufreq_pdev;
 
 static enum _msm8996_version qcom_cpufreq_kryo_get_msm_id(void)
 {
index 3d773f64b4df7e8f0b30e109ef1c865dfdd5ee44..4295e547626426b2f57a5f8381d60e128aa32a3e 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/cpufreq.h>
-#include <linux/cpu_cooling.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -31,7 +30,6 @@
 struct cpu_data {
        struct clk **pclk;
        struct cpufreq_frequency_table *table;
-       struct thermal_cooling_device *cdev;
 };
 
 /*
@@ -239,7 +237,6 @@ static int qoriq_cpufreq_cpu_exit(struct cpufreq_policy *policy)
 {
        struct cpu_data *data = policy->driver_data;
 
-       cpufreq_cooling_unregister(data->cdev);
        kfree(data->pclk);
        kfree(data->table);
        kfree(data);
@@ -258,23 +255,15 @@ static int qoriq_cpufreq_target(struct cpufreq_policy *policy,
        return clk_set_parent(policy->clk, parent);
 }
 
-
-static void qoriq_cpufreq_ready(struct cpufreq_policy *policy)
-{
-       struct cpu_data *cpud = policy->driver_data;
-
-       cpud->cdev = of_cpufreq_cooling_register(policy);
-}
-
 static struct cpufreq_driver qoriq_cpufreq_driver = {
        .name           = "qoriq_cpufreq",
-       .flags          = CPUFREQ_CONST_LOOPS,
+       .flags          = CPUFREQ_CONST_LOOPS |
+                         CPUFREQ_IS_COOLING_DEV,
        .init           = qoriq_cpufreq_cpu_init,
        .exit           = qoriq_cpufreq_cpu_exit,
        .verify         = cpufreq_generic_frequency_table_verify,
        .target_index   = qoriq_cpufreq_target,
        .get            = cpufreq_generic_get,
-       .ready          = qoriq_cpufreq_ready,
        .attr           = cpufreq_generic_attr,
 };
 
index dbecd7667db28a5b325284a519fba0107ff45354..5b4289460bc9ecdb61ef7cbbda15eca84cc2e4ab 100644 (file)
@@ -584,7 +584,7 @@ static struct notifier_block s5pv210_cpufreq_reboot_notifier = {
 static int s5pv210_cpufreq_probe(struct platform_device *pdev)
 {
        struct device_node *np;
-       int id;
+       int id, result = 0;
 
        /*
         * HACK: This is a temporary workaround to get access to clock
@@ -594,18 +594,39 @@ static int s5pv210_cpufreq_probe(struct platform_device *pdev)
         * this whole driver as soon as S5PV210 gets migrated to use
         * cpufreq-dt driver.
         */
+       arm_regulator = regulator_get(NULL, "vddarm");
+       if (IS_ERR(arm_regulator)) {
+               if (PTR_ERR(arm_regulator) == -EPROBE_DEFER)
+                       pr_debug("vddarm regulator not ready, defer\n");
+               else
+                       pr_err("failed to get regulator vddarm\n");
+               return PTR_ERR(arm_regulator);
+       }
+
+       int_regulator = regulator_get(NULL, "vddint");
+       if (IS_ERR(int_regulator)) {
+               if (PTR_ERR(int_regulator) == -EPROBE_DEFER)
+                       pr_debug("vddint regulator not ready, defer\n");
+               else
+                       pr_err("failed to get regulator vddint\n");
+               result = PTR_ERR(int_regulator);
+               goto err_int_regulator;
+       }
+
        np = of_find_compatible_node(NULL, NULL, "samsung,s5pv210-clock");
        if (!np) {
                pr_err("%s: failed to find clock controller DT node\n",
                        __func__);
-               return -ENODEV;
+               result = -ENODEV;
+               goto err_clock;
        }
 
        clk_base = of_iomap(np, 0);
        of_node_put(np);
        if (!clk_base) {
                pr_err("%s: failed to map clock registers\n", __func__);
-               return -EFAULT;
+               result = -EFAULT;
+               goto err_clock;
        }
 
        for_each_compatible_node(np, NULL, "samsung,s5pv210-dmc") {
@@ -614,7 +635,8 @@ static int s5pv210_cpufreq_probe(struct platform_device *pdev)
                        pr_err("%s: failed to get alias of dmc node '%pOFn'\n",
                                __func__, np);
                        of_node_put(np);
-                       return id;
+                       result = id;
+                       goto err_clk_base;
                }
 
                dmc_base[id] = of_iomap(np, 0);
@@ -622,33 +644,40 @@ static int s5pv210_cpufreq_probe(struct platform_device *pdev)
                        pr_err("%s: failed to map dmc%d registers\n",
                                __func__, id);
                        of_node_put(np);
-                       return -EFAULT;
+                       result = -EFAULT;
+                       goto err_dmc;
                }
        }
 
        for (id = 0; id < ARRAY_SIZE(dmc_base); ++id) {
                if (!dmc_base[id]) {
                        pr_err("%s: failed to find dmc%d node\n", __func__, id);
-                       return -ENODEV;
+                       result = -ENODEV;
+                       goto err_dmc;
                }
        }
 
-       arm_regulator = regulator_get(NULL, "vddarm");
-       if (IS_ERR(arm_regulator)) {
-               pr_err("failed to get regulator vddarm\n");
-               return PTR_ERR(arm_regulator);
-       }
-
-       int_regulator = regulator_get(NULL, "vddint");
-       if (IS_ERR(int_regulator)) {
-               pr_err("failed to get regulator vddint\n");
-               regulator_put(arm_regulator);
-               return PTR_ERR(int_regulator);
-       }
-
        register_reboot_notifier(&s5pv210_cpufreq_reboot_notifier);
 
        return cpufreq_register_driver(&s5pv210_driver);
+
+err_dmc:
+       for (id = 0; id < ARRAY_SIZE(dmc_base); ++id)
+               if (dmc_base[id]) {
+                       iounmap(dmc_base[id]);
+                       dmc_base[id] = NULL;
+               }
+
+err_clk_base:
+       iounmap(clk_base);
+
+err_clock:
+       regulator_put(int_regulator);
+
+err_int_regulator:
+       regulator_put(arm_regulator);
+
+       return result;
 }
 
 static struct platform_driver s5pv210_cpufreq_platdrv = {
index 9ed46d188cb5ba3fee03ac61623bf8f531ec6dae..c47182fc64eadb914cc3d631defd6fe2d7697a0d 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/cpu.h>
 #include <linux/cpufreq.h>
 #include <linux/cpumask.h>
-#include <linux/cpu_cooling.h>
 #include <linux/export.h>
 #include <linux/module.h>
 #include <linux/pm_opp.h>
@@ -22,7 +21,6 @@
 struct scmi_data {
        int domain_id;
        struct device *cpu_dev;
-       struct thermal_cooling_device *cdev;
 };
 
 static const struct scmi_handle *handle;
@@ -185,7 +183,6 @@ static int scmi_cpufreq_exit(struct cpufreq_policy *policy)
 {
        struct scmi_data *priv = policy->driver_data;
 
-       cpufreq_cooling_unregister(priv->cdev);
        dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table);
        dev_pm_opp_remove_all_dynamic(priv->cpu_dev);
        kfree(priv);
@@ -193,17 +190,11 @@ static int scmi_cpufreq_exit(struct cpufreq_policy *policy)
        return 0;
 }
 
-static void scmi_cpufreq_ready(struct cpufreq_policy *policy)
-{
-       struct scmi_data *priv = policy->driver_data;
-
-       priv->cdev = of_cpufreq_cooling_register(policy);
-}
-
 static struct cpufreq_driver scmi_cpufreq_driver = {
        .name   = "scmi",
        .flags  = CPUFREQ_STICKY | CPUFREQ_HAVE_GOVERNOR_PER_POLICY |
-                 CPUFREQ_NEED_INITIAL_FREQ_CHECK,
+                 CPUFREQ_NEED_INITIAL_FREQ_CHECK |
+                 CPUFREQ_IS_COOLING_DEV,
        .verify = cpufreq_generic_frequency_table_verify,
        .attr   = cpufreq_generic_attr,
        .target_index   = scmi_cpufreq_set_target,
@@ -211,7 +202,6 @@ static struct cpufreq_driver scmi_cpufreq_driver = {
        .get    = scmi_cpufreq_get_rate,
        .init   = scmi_cpufreq_init,
        .exit   = scmi_cpufreq_exit,
-       .ready  = scmi_cpufreq_ready,
 };
 
 static int scmi_cpufreq_probe(struct scmi_device *sdev)
index 99449738faa4d936f76967fc62ace7a5b61b986d..1db2f6927e1372e1d64862645601ff6e37e36b7b 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/cpu.h>
 #include <linux/cpufreq.h>
 #include <linux/cpumask.h>
-#include <linux/cpu_cooling.h>
 #include <linux/export.h>
 #include <linux/module.h>
 #include <linux/of_platform.h>
@@ -34,7 +33,6 @@
 struct scpi_data {
        struct clk *clk;
        struct device *cpu_dev;
-       struct thermal_cooling_device *cdev;
 };
 
 static struct scpi_ops *scpi_ops;
@@ -186,7 +184,6 @@ static int scpi_cpufreq_exit(struct cpufreq_policy *policy)
 {
        struct scpi_data *priv = policy->driver_data;
 
-       cpufreq_cooling_unregister(priv->cdev);
        clk_put(priv->clk);
        dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table);
        kfree(priv);
@@ -195,23 +192,16 @@ static int scpi_cpufreq_exit(struct cpufreq_policy *policy)
        return 0;
 }
 
-static void scpi_cpufreq_ready(struct cpufreq_policy *policy)
-{
-       struct scpi_data *priv = policy->driver_data;
-
-       priv->cdev = of_cpufreq_cooling_register(policy);
-}
-
 static struct cpufreq_driver scpi_cpufreq_driver = {
        .name   = "scpi-cpufreq",
        .flags  = CPUFREQ_STICKY | CPUFREQ_HAVE_GOVERNOR_PER_POLICY |
-                 CPUFREQ_NEED_INITIAL_FREQ_CHECK,
+                 CPUFREQ_NEED_INITIAL_FREQ_CHECK |
+                 CPUFREQ_IS_COOLING_DEV,
        .verify = cpufreq_generic_frequency_table_verify,
        .attr   = cpufreq_generic_attr,
        .get    = scpi_cpufreq_get_rate,
        .init   = scpi_cpufreq_init,
        .exit   = scpi_cpufreq_exit,
-       .ready  = scpi_cpufreq_ready,
        .target_index   = scpi_cpufreq_set_target,
 };
 
index fbbcb88db061652a35a573538e8cd51fabe6fa6b..5d8a09b82efbd338557d209c7e5a52effce83de7 100644 (file)
@@ -243,8 +243,7 @@ static unsigned int speedstep_get(unsigned int cpu)
        unsigned int speed;
 
        /* You're supposed to ensure CPU is online. */
-       if (smp_call_function_single(cpu, get_freq_data, &speed, 1) != 0)
-               BUG();
+       BUG_ON(smp_call_function_single(cpu, get_freq_data, &speed, 1));
 
        pr_debug("detected %u kHz as current frequency\n", speed);
        return speed;
index 43530254201a8b3a5f98fdcb032ea6c3b635bb96..4bb154f6c54cdcef9ca19ed3a071e1a2f674b474 100644 (file)
@@ -134,6 +134,8 @@ static int tegra124_cpufreq_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, priv);
 
+       of_node_put(np);
+
        return 0;
 
 out_switch_to_pllx:
index 18f1639dbc4a601d951330ea179335cb704ce660..4e00301060cf4d4d5e15ba12c9624fdea430ea7e 100644 (file)
@@ -533,9 +533,8 @@ static int _set_opp_voltage(struct device *dev, struct regulator *reg,
        return ret;
 }
 
-static inline int
-_generic_set_opp_clk_only(struct device *dev, struct clk *clk,
-                         unsigned long old_freq, unsigned long freq)
+static inline int _generic_set_opp_clk_only(struct device *dev, struct clk *clk,
+                                           unsigned long freq)
 {
        int ret;
 
@@ -572,7 +571,7 @@ static int _generic_set_opp_regulator(const struct opp_table *opp_table,
        }
 
        /* Change frequency */
-       ret = _generic_set_opp_clk_only(dev, opp_table->clk, old_freq, freq);
+       ret = _generic_set_opp_clk_only(dev, opp_table->clk, freq);
        if (ret)
                goto restore_voltage;
 
@@ -586,7 +585,7 @@ static int _generic_set_opp_regulator(const struct opp_table *opp_table,
        return 0;
 
 restore_freq:
-       if (_generic_set_opp_clk_only(dev, opp_table->clk, freq, old_freq))
+       if (_generic_set_opp_clk_only(dev, opp_table->clk, old_freq))
                dev_err(dev, "%s: failed to restore old-freq (%lu Hz)\n",
                        __func__, old_freq);
 restore_voltage:
@@ -759,7 +758,7 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
                                                 opp->supplies);
        } else {
                /* Only frequency scaling */
-               ret = _generic_set_opp_clk_only(dev, clk, old_freq, freq);
+               ret = _generic_set_opp_clk_only(dev, clk, freq);
        }
 
        /* Scaling down? Configure required OPPs after frequency */
index 06f0f632ec4771aa84874221900e07c1b8b924ef..cd58959e5158398355876e14b2121db738d377ab 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/pm_domain.h>
 #include <linux/slab.h>
 #include <linux/export.h>
+#include <linux/energy_model.h>
 
 #include "opp.h"
 
@@ -1047,3 +1048,101 @@ struct device_node *dev_pm_opp_get_of_node(struct dev_pm_opp *opp)
        return of_node_get(opp->np);
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_get_of_node);
+
+/*
+ * Callback function provided to the Energy Model framework upon registration.
+ * This computes the power estimated by @CPU at @kHz if it is the frequency
+ * of an existing OPP, or at the frequency of the first OPP above @kHz otherwise
+ * (see dev_pm_opp_find_freq_ceil()). This function updates @kHz to the ceiled
+ * frequency and @mW to the associated power. The power is estimated as
+ * P = C * V^2 * f with C being the CPU's capacitance and V and f respectively
+ * the voltage and frequency of the OPP.
+ *
+ * Returns -ENODEV if the CPU device cannot be found, -EINVAL if the power
+ * calculation failed because of missing parameters, 0 otherwise.
+ */
+static int __maybe_unused _get_cpu_power(unsigned long *mW, unsigned long *kHz,
+                                        int cpu)
+{
+       struct device *cpu_dev;
+       struct dev_pm_opp *opp;
+       struct device_node *np;
+       unsigned long mV, Hz;
+       u32 cap;
+       u64 tmp;
+       int ret;
+
+       cpu_dev = get_cpu_device(cpu);
+       if (!cpu_dev)
+               return -ENODEV;
+
+       np = of_node_get(cpu_dev->of_node);
+       if (!np)
+               return -EINVAL;
+
+       ret = of_property_read_u32(np, "dynamic-power-coefficient", &cap);
+       of_node_put(np);
+       if (ret)
+               return -EINVAL;
+
+       Hz = *kHz * 1000;
+       opp = dev_pm_opp_find_freq_ceil(cpu_dev, &Hz);
+       if (IS_ERR(opp))
+               return -EINVAL;
+
+       mV = dev_pm_opp_get_voltage(opp) / 1000;
+       dev_pm_opp_put(opp);
+       if (!mV)
+               return -EINVAL;
+
+       tmp = (u64)cap * mV * mV * (Hz / 1000000);
+       do_div(tmp, 1000000000);
+
+       *mW = (unsigned long)tmp;
+       *kHz = Hz / 1000;
+
+       return 0;
+}
+
+/**
+ * dev_pm_opp_of_register_em() - Attempt to register an Energy Model
+ * @cpus       : CPUs for which an Energy Model has to be registered
+ *
+ * This checks whether the "dynamic-power-coefficient" devicetree property has
+ * been specified, and tries to register an Energy Model with it if it has.
+ */
+void dev_pm_opp_of_register_em(struct cpumask *cpus)
+{
+       struct em_data_callback em_cb = EM_DATA_CB(_get_cpu_power);
+       int ret, nr_opp, cpu = cpumask_first(cpus);
+       struct device *cpu_dev;
+       struct device_node *np;
+       u32 cap;
+
+       cpu_dev = get_cpu_device(cpu);
+       if (!cpu_dev)
+               return;
+
+       nr_opp = dev_pm_opp_get_opp_count(cpu_dev);
+       if (nr_opp <= 0)
+               return;
+
+       np = of_node_get(cpu_dev->of_node);
+       if (!np)
+               return;
+
+       /*
+        * Register an EM only if the 'dynamic-power-coefficient' property is
+        * set in devicetree. It is assumed the voltage values are known if that
+        * property is set since it is useless otherwise. If voltages are not
+        * known, just let the EM registration fail with an error to alert the
+        * user about the inconsistent configuration.
+        */
+       ret = of_property_read_u32(np, "dynamic-power-coefficient", &cap);
+       of_node_put(np);
+       if (ret || !cap)
+               return;
+
+       em_register_perf_domain(cpus, nr_opp, &em_cb);
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_of_register_em);
index 30323426902e41bbf81a60e7558c8fe391d0729e..58bb7d72dc2bd3afcb1a01d89cc2cbaedf09a361 100644 (file)
@@ -152,6 +152,7 @@ config CPU_THERMAL
        bool "generic cpu cooling support"
        depends on CPU_FREQ
        depends on THERMAL_OF
+       depends on THERMAL=y
        help
          This implements the generic cpu cooling mechanism through frequency
          reduction. An ACPI version of this already exists
index 4f34734e7f3616bb5e07a77a4c8573ff6e155b42..ba6fd7202775e4c3d2b221c9eaf0675e69cc3929 100644 (file)
@@ -137,6 +137,7 @@ struct cppc_cpudata {
        cpumask_var_t shared_cpu_map;
 };
 
+extern int cppc_get_desired_perf(int cpunum, u64 *desired_perf);
 extern int cppc_get_perf_ctrs(int cpu, struct cppc_perf_fb_ctrs *perf_fb_ctrs);
 extern int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls);
 extern int cppc_get_perf_caps(int cpu, struct cppc_perf_caps *caps);
index c86d6d8bdfed2079a161bea6946ce3f6d47d8ac8..b160e98076e3b896fabffd6a78fcfb62501e1fdb 100644 (file)
@@ -151,6 +151,9 @@ struct cpufreq_policy {
 
        /* For cpufreq driver's internal use */
        void                    *driver_data;
+
+       /* Pointer to the cooling device if used for thermal mitigation */
+       struct thermal_cooling_device *cdev;
 };
 
 /* Only for ACPI */
@@ -254,20 +257,12 @@ __ATTR(_name, 0644, show_##_name, store_##_name)
 static struct freq_attr _name =                        \
 __ATTR(_name, 0200, NULL, store_##_name)
 
-struct global_attr {
-       struct attribute attr;
-       ssize_t (*show)(struct kobject *kobj,
-                       struct attribute *attr, char *buf);
-       ssize_t (*store)(struct kobject *a, struct attribute *b,
-                        const char *c, size_t count);
-};
-
 #define define_one_global_ro(_name)            \
-static struct global_attr _name =              \
+static struct kobj_attribute _name =           \
 __ATTR(_name, 0444, show_##_name, NULL)
 
 #define define_one_global_rw(_name)            \
-static struct global_attr _name =              \
+static struct kobj_attribute _name =           \
 __ATTR(_name, 0644, show_##_name, store_##_name)
 
 
@@ -330,6 +325,8 @@ struct cpufreq_driver {
        /* optional */
        int             (*bios_limit)(int cpu, unsigned int *limit);
 
+       int             (*online)(struct cpufreq_policy *policy);
+       int             (*offline)(struct cpufreq_policy *policy);
        int             (*exit)(struct cpufreq_policy *policy);
        void            (*stop_cpu)(struct cpufreq_policy *policy);
        int             (*suspend)(struct cpufreq_policy *policy);
@@ -346,14 +343,15 @@ struct cpufreq_driver {
 };
 
 /* flags */
-#define CPUFREQ_STICKY         (1 << 0)        /* driver isn't removed even if
-                                                  all ->init() calls failed */
-#define CPUFREQ_CONST_LOOPS    (1 << 1)        /* loops_per_jiffy or other
-                                                  kernel "constants" aren't
-                                                  affected by frequency
-                                                  transitions */
-#define CPUFREQ_PM_NO_WARN     (1 << 2)        /* don't warn on suspend/resume
-                                                  speed mismatches */
+
+/* driver isn't removed even if all ->init() calls failed */
+#define CPUFREQ_STICKY                         BIT(0)
+
+/* loops_per_jiffy or other kernel "constants" aren't affected by frequency transitions */
+#define CPUFREQ_CONST_LOOPS                    BIT(1)
+
+/* don't warn on suspend/resume speed mismatches */
+#define CPUFREQ_PM_NO_WARN                     BIT(2)
 
 /*
  * This should be set by platforms having multiple clock-domains, i.e.
@@ -361,14 +359,14 @@ struct cpufreq_driver {
  * be created in cpu/cpu<num>/cpufreq/ directory and so they can use the same
  * governor with different tunables for different clusters.
  */
-#define CPUFREQ_HAVE_GOVERNOR_PER_POLICY (1 << 3)
+#define CPUFREQ_HAVE_GOVERNOR_PER_POLICY       BIT(3)
 
 /*
  * Driver will do POSTCHANGE notifications from outside of their ->target()
  * routine and so must set cpufreq_driver->flags with this flag, so that core
  * can handle them specially.
  */
-#define CPUFREQ_ASYNC_NOTIFICATION  (1 << 4)
+#define CPUFREQ_ASYNC_NOTIFICATION             BIT(4)
 
 /*
  * Set by drivers which want cpufreq core to check if CPU is running at a
@@ -377,13 +375,19 @@ struct cpufreq_driver {
  * from the table. And if that fails, we will stop further boot process by
  * issuing a BUG_ON().
  */
-#define CPUFREQ_NEED_INITIAL_FREQ_CHECK        (1 << 5)
+#define CPUFREQ_NEED_INITIAL_FREQ_CHECK        BIT(5)
 
 /*
  * Set by drivers to disallow use of governors with "dynamic_switching" flag
  * set.
  */
-#define CPUFREQ_NO_AUTO_DYNAMIC_SWITCHING (1 << 6)
+#define CPUFREQ_NO_AUTO_DYNAMIC_SWITCHING      BIT(6)
+
+/*
+ * Set by drivers that want the core to automatically register the cpufreq
+ * driver as a thermal cooling device.
+ */
+#define CPUFREQ_IS_COOLING_DEV                 BIT(7)
 
 int cpufreq_register_driver(struct cpufreq_driver *driver_data);
 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 (file)
index 0000000..3fbf9f2
--- /dev/null
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * TI DaVinci CPUFreq platform support.
+ *
+ * Copyright (C) 2009 Texas Instruments, Inc. http://www.ti.com/
+ */
+
+#ifndef _MACH_DAVINCI_CPUFREQ_H
+#define _MACH_DAVINCI_CPUFREQ_H
+
+#include <linux/cpufreq.h>
+
+struct davinci_cpufreq_config {
+       struct cpufreq_frequency_table *freq_table;
+       int (*set_voltage)(unsigned int index);
+       int (*init)(void);
+};
+
+#endif /* _MACH_DAVINCI_CPUFREQ_H */
index b895f4e798683b4c7d29c171aebe8b8c4026c966..c9c76310865acb807048207f4b3388adf30483a6 100644 (file)
@@ -327,6 +327,7 @@ int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpuma
 struct device_node *dev_pm_opp_of_get_opp_desc_node(struct device *dev);
 struct device_node *dev_pm_opp_get_of_node(struct dev_pm_opp *opp);
 int of_get_required_opp_performance_state(struct device_node *np, int index);
+void dev_pm_opp_of_register_em(struct cpumask *cpus);
 #else
 static inline int dev_pm_opp_of_add_table(struct device *dev)
 {
@@ -365,6 +366,11 @@ static inline struct device_node *dev_pm_opp_get_of_node(struct dev_pm_opp *opp)
 {
        return NULL;
 }
+
+static inline void dev_pm_opp_of_register_em(struct cpumask *cpus)
+{
+}
+
 static inline int of_get_required_opp_performance_state(struct device_node *np, int index)
 {
        return -ENOTSUPP;