Merge branch 'pm-cpufreq'
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Sun, 3 Sep 2017 22:05:13 +0000 (00:05 +0200)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Sun, 3 Sep 2017 22:05:13 +0000 (00:05 +0200)
* pm-cpufreq: (33 commits)
  cpufreq: imx6q: Fix imx6sx low frequency support
  cpufreq: speedstep-lib: make several arrays static, makes code smaller
  cpufreq: ti: Fix 'of_node_put' being called twice in error handling path
  cpufreq: dt-platdev: Drop few entries from whitelist
  cpufreq: dt-platdev: Automatically create cpufreq device with OPP v2
  ARM: ux500: don't select CPUFREQ_DT
  cpufreq: Convert to using %pOF instead of full_name
  cpufreq: Cap the default transition delay value to 10 ms
  cpufreq: dbx500: Delete obsolete driver
  mfd: db8500-prcmu: Get rid of cpufreq dependency
  cpufreq: enable the DT cpufreq driver on the Ux500
  cpufreq: Loongson2: constify platform_device_id
  cpufreq: dt: Add r8a7796 support to to use generic cpufreq driver
  cpufreq: remove setting of policy->cpu in policy->cpus during init
  cpufreq: mediatek: add support of cpufreq to MT7622 SoC
  cpufreq: mediatek: add cleanups with the more generic naming
  cpufreq: rcar: Add support for R8A7795 SoC
  cpufreq: dt: Add rk3328 compatible to use generic cpufreq driver
  cpufreq: s5pv210: add missing of_node_put()
  cpufreq: Allow dynamic switching with CPUFREQ_ETERNAL latency
  ...

40 files changed:
Documentation/admin-guide/pm/cpufreq.rst
Documentation/devicetree/bindings/clock/mt8173-cpu-dvfs.txt [deleted file]
Documentation/devicetree/bindings/cpufreq/cpufreq-mediatek.txt [new file with mode: 0644]
arch/arm/boot/dts/tango4-smp8758.dtsi
drivers/cpufreq/Kconfig.arm
drivers/cpufreq/Makefile
drivers/cpufreq/arm_big_little.c
drivers/cpufreq/cppc_cpufreq.c
drivers/cpufreq/cpufreq-dt-platdev.c
drivers/cpufreq/cpufreq-nforce2.c
drivers/cpufreq/cpufreq.c
drivers/cpufreq/cpufreq_conservative.c
drivers/cpufreq/cpufreq_governor.c
drivers/cpufreq/cpufreq_governor.h
drivers/cpufreq/cpufreq_ondemand.c
drivers/cpufreq/dbx500-cpufreq.c [deleted file]
drivers/cpufreq/elanfreq.c
drivers/cpufreq/gx-suspmod.c
drivers/cpufreq/imx6q-cpufreq.c
drivers/cpufreq/intel_pstate.c
drivers/cpufreq/longrun.c
drivers/cpufreq/loongson2_cpufreq.c
drivers/cpufreq/mediatek-cpufreq.c [new file with mode: 0644]
drivers/cpufreq/mt8173-cpufreq.c [deleted file]
drivers/cpufreq/pmac32-cpufreq.c
drivers/cpufreq/pmac64-cpufreq.c
drivers/cpufreq/s5pv210-cpufreq.c
drivers/cpufreq/sa1100-cpufreq.c
drivers/cpufreq/sa1110-cpufreq.c
drivers/cpufreq/sh-cpufreq.c
drivers/cpufreq/speedstep-ich.c
drivers/cpufreq/speedstep-lib.c
drivers/cpufreq/speedstep-smi.c
drivers/cpufreq/sti-cpufreq.c
drivers/cpufreq/tango-cpufreq.c [new file with mode: 0644]
drivers/cpufreq/ti-cpufreq.c
drivers/cpufreq/unicore2-cpufreq.c
drivers/mfd/db8500-prcmu.c
include/linux/cpufreq.h
kernel/sched/cpufreq_schedutil.c

index 7af83a92d2d6103ea3fb0a3a0425e994b29f7f53..47153e64dfb530465ca01d28272e058293eb08b5 100644 (file)
@@ -479,14 +479,6 @@ This governor exposes the following tunables:
 
        # echo `$(($(cat cpuinfo_transition_latency) * 750 / 1000)) > ondemand/sampling_rate
 
-
-``min_sampling_rate``
-       The minimum value of ``sampling_rate``.
-
-       Equal to 10000 (10 ms) if :c:macro:`CONFIG_NO_HZ_COMMON` and
-       :c:data:`tick_nohz_active` are both set or to 20 times the value of
-       :c:data:`jiffies` in microseconds otherwise.
-
 ``up_threshold``
        If the estimated CPU load is above this value (in percent), the governor
        will set the frequency to the maximum value allowed for the policy.
diff --git a/Documentation/devicetree/bindings/clock/mt8173-cpu-dvfs.txt b/Documentation/devicetree/bindings/clock/mt8173-cpu-dvfs.txt
deleted file mode 100644 (file)
index 52b457c..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-Device Tree Clock bindins for CPU DVFS of Mediatek MT8173 SoC
-
-Required properties:
-- clocks: A list of phandle + clock-specifier pairs for the clocks listed in clock names.
-- clock-names: Should contain the following:
-       "cpu"           - The multiplexer for clock input of CPU cluster.
-       "intermediate"  - A parent of "cpu" clock which is used as "intermediate" clock
-                         source (usually MAINPLL) when the original CPU PLL is under
-                         transition and not stable yet.
-       Please refer to Documentation/devicetree/bindings/clk/clock-bindings.txt for
-       generic clock consumer properties.
-- proc-supply: Regulator for Vproc of CPU cluster.
-
-Optional properties:
-- sram-supply: Regulator for Vsram of CPU cluster. When present, the cpufreq driver
-              needs to do "voltage tracking" to step by step scale up/down Vproc and
-              Vsram to fit SoC specific needs. When absent, the voltage scaling
-              flow is handled by hardware, hence no software "voltage tracking" is
-              needed.
-
-Example:
---------
-       cpu0: cpu@0 {
-               device_type = "cpu";
-               compatible = "arm,cortex-a53";
-               reg = <0x000>;
-               enable-method = "psci";
-               cpu-idle-states = <&CPU_SLEEP_0>;
-               clocks = <&infracfg CLK_INFRA_CA53SEL>,
-                        <&apmixedsys CLK_APMIXED_MAINPLL>;
-               clock-names = "cpu", "intermediate";
-       };
-
-       cpu1: cpu@1 {
-               device_type = "cpu";
-               compatible = "arm,cortex-a53";
-               reg = <0x001>;
-               enable-method = "psci";
-               cpu-idle-states = <&CPU_SLEEP_0>;
-               clocks = <&infracfg CLK_INFRA_CA53SEL>,
-                        <&apmixedsys CLK_APMIXED_MAINPLL>;
-               clock-names = "cpu", "intermediate";
-       };
-
-       cpu2: cpu@100 {
-               device_type = "cpu";
-               compatible = "arm,cortex-a57";
-               reg = <0x100>;
-               enable-method = "psci";
-               cpu-idle-states = <&CPU_SLEEP_0>;
-               clocks = <&infracfg CLK_INFRA_CA57SEL>,
-                        <&apmixedsys CLK_APMIXED_MAINPLL>;
-               clock-names = "cpu", "intermediate";
-       };
-
-       cpu3: cpu@101 {
-               device_type = "cpu";
-               compatible = "arm,cortex-a57";
-               reg = <0x101>;
-               enable-method = "psci";
-               cpu-idle-states = <&CPU_SLEEP_0>;
-               clocks = <&infracfg CLK_INFRA_CA57SEL>,
-                        <&apmixedsys CLK_APMIXED_MAINPLL>;
-               clock-names = "cpu", "intermediate";
-       };
-
-       &cpu0 {
-               proc-supply = <&mt6397_vpca15_reg>;
-       };
-
-       &cpu1 {
-               proc-supply = <&mt6397_vpca15_reg>;
-       };
-
-       &cpu2 {
-               proc-supply = <&da9211_vcpu_reg>;
-               sram-supply = <&mt6397_vsramca7_reg>;
-       };
-
-       &cpu3 {
-               proc-supply = <&da9211_vcpu_reg>;
-               sram-supply = <&mt6397_vsramca7_reg>;
-       };
diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-mediatek.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-mediatek.txt
new file mode 100644 (file)
index 0000000..f640308
--- /dev/null
@@ -0,0 +1,247 @@
+Binding for MediaTek's CPUFreq driver
+=====================================
+
+Required properties:
+- clocks: A list of phandle + clock-specifier pairs for the clocks listed in clock names.
+- clock-names: Should contain the following:
+       "cpu"           - The multiplexer for clock input of CPU cluster.
+       "intermediate"  - A parent of "cpu" clock which is used as "intermediate" clock
+                         source (usually MAINPLL) when the original CPU PLL is under
+                         transition and not stable yet.
+       Please refer to Documentation/devicetree/bindings/clk/clock-bindings.txt for
+       generic clock consumer properties.
+- operating-points-v2: Please refer to Documentation/devicetree/bindings/opp/opp.txt
+       for detail.
+- proc-supply: Regulator for Vproc of CPU cluster.
+
+Optional properties:
+- sram-supply: Regulator for Vsram of CPU cluster. When present, the cpufreq driver
+              needs to do "voltage tracking" to step by step scale up/down Vproc and
+              Vsram to fit SoC specific needs. When absent, the voltage scaling
+              flow is handled by hardware, hence no software "voltage tracking" is
+              needed.
+- #cooling-cells:
+- cooling-min-level:
+- cooling-max-level:
+       Please refer to Documentation/devicetree/bindings/thermal/thermal.txt
+       for detail.
+
+Example 1 (MT7623 SoC):
+
+       cpu_opp_table: opp_table {
+               compatible = "operating-points-v2";
+               opp-shared;
+
+               opp-598000000 {
+                       opp-hz = /bits/ 64 <598000000>;
+                       opp-microvolt = <1050000>;
+               };
+
+               opp-747500000 {
+                       opp-hz = /bits/ 64 <747500000>;
+                       opp-microvolt = <1050000>;
+               };
+
+               opp-1040000000 {
+                       opp-hz = /bits/ 64 <1040000000>;
+                       opp-microvolt = <1150000>;
+               };
+
+               opp-1196000000 {
+                       opp-hz = /bits/ 64 <1196000000>;
+                       opp-microvolt = <1200000>;
+               };
+
+               opp-1300000000 {
+                       opp-hz = /bits/ 64 <1300000000>;
+                       opp-microvolt = <1300000>;
+               };
+       };
+
+       cpu0: cpu@0 {
+               device_type = "cpu";
+               compatible = "arm,cortex-a7";
+               reg = <0x0>;
+               clocks = <&infracfg CLK_INFRA_CPUSEL>,
+                        <&apmixedsys CLK_APMIXED_MAINPLL>;
+               clock-names = "cpu", "intermediate";
+               operating-points-v2 = <&cpu_opp_table>;
+               #cooling-cells = <2>;
+               cooling-min-level = <0>;
+               cooling-max-level = <7>;
+       };
+       cpu@1 {
+               device_type = "cpu";
+               compatible = "arm,cortex-a7";
+               reg = <0x1>;
+               operating-points-v2 = <&cpu_opp_table>;
+       };
+       cpu@2 {
+               device_type = "cpu";
+               compatible = "arm,cortex-a7";
+               reg = <0x2>;
+               operating-points-v2 = <&cpu_opp_table>;
+       };
+       cpu@3 {
+               device_type = "cpu";
+               compatible = "arm,cortex-a7";
+               reg = <0x3>;
+               operating-points-v2 = <&cpu_opp_table>;
+       };
+
+Example 2 (MT8173 SoC):
+       cpu_opp_table_a: opp_table_a {
+               compatible = "operating-points-v2";
+               opp-shared;
+
+               opp-507000000 {
+                       opp-hz = /bits/ 64 <507000000>;
+                       opp-microvolt = <859000>;
+               };
+
+               opp-702000000 {
+                       opp-hz = /bits/ 64 <702000000>;
+                       opp-microvolt = <908000>;
+               };
+
+               opp-1001000000 {
+                       opp-hz = /bits/ 64 <1001000000>;
+                       opp-microvolt = <983000>;
+               };
+
+               opp-1105000000 {
+                       opp-hz = /bits/ 64 <1105000000>;
+                       opp-microvolt = <1009000>;
+               };
+
+               opp-1183000000 {
+                       opp-hz = /bits/ 64 <1183000000>;
+                       opp-microvolt = <1028000>;
+               };
+
+               opp-1404000000 {
+                       opp-hz = /bits/ 64 <1404000000>;
+                       opp-microvolt = <1083000>;
+               };
+
+               opp-1508000000 {
+                       opp-hz = /bits/ 64 <1508000000>;
+                       opp-microvolt = <1109000>;
+               };
+
+               opp-1573000000 {
+                       opp-hz = /bits/ 64 <1573000000>;
+                       opp-microvolt = <1125000>;
+               };
+       };
+
+       cpu_opp_table_b: opp_table_b {
+               compatible = "operating-points-v2";
+               opp-shared;
+
+               opp-507000000 {
+                       opp-hz = /bits/ 64 <507000000>;
+                       opp-microvolt = <828000>;
+               };
+
+               opp-702000000 {
+                       opp-hz = /bits/ 64 <702000000>;
+                       opp-microvolt = <867000>;
+               };
+
+               opp-1001000000 {
+                       opp-hz = /bits/ 64 <1001000000>;
+                       opp-microvolt = <927000>;
+               };
+
+               opp-1209000000 {
+                       opp-hz = /bits/ 64 <1209000000>;
+                       opp-microvolt = <968000>;
+               };
+
+               opp-1404000000 {
+                       opp-hz = /bits/ 64 <1007000000>;
+                       opp-microvolt = <1028000>;
+               };
+
+               opp-1612000000 {
+                       opp-hz = /bits/ 64 <1612000000>;
+                       opp-microvolt = <1049000>;
+               };
+
+               opp-1807000000 {
+                       opp-hz = /bits/ 64 <1807000000>;
+                       opp-microvolt = <1089000>;
+               };
+
+               opp-1989000000 {
+                       opp-hz = /bits/ 64 <1989000000>;
+                       opp-microvolt = <1125000>;
+               };
+       };
+
+       cpu0: cpu@0 {
+               device_type = "cpu";
+               compatible = "arm,cortex-a53";
+               reg = <0x000>;
+               enable-method = "psci";
+               cpu-idle-states = <&CPU_SLEEP_0>;
+               clocks = <&infracfg CLK_INFRA_CA53SEL>,
+                        <&apmixedsys CLK_APMIXED_MAINPLL>;
+               clock-names = "cpu", "intermediate";
+               operating-points-v2 = <&cpu_opp_table_a>;
+       };
+
+       cpu1: cpu@1 {
+               device_type = "cpu";
+               compatible = "arm,cortex-a53";
+               reg = <0x001>;
+               enable-method = "psci";
+               cpu-idle-states = <&CPU_SLEEP_0>;
+               clocks = <&infracfg CLK_INFRA_CA53SEL>,
+                        <&apmixedsys CLK_APMIXED_MAINPLL>;
+               clock-names = "cpu", "intermediate";
+               operating-points-v2 = <&cpu_opp_table_a>;
+       };
+
+       cpu2: cpu@100 {
+               device_type = "cpu";
+               compatible = "arm,cortex-a57";
+               reg = <0x100>;
+               enable-method = "psci";
+               cpu-idle-states = <&CPU_SLEEP_0>;
+               clocks = <&infracfg CLK_INFRA_CA57SEL>,
+                        <&apmixedsys CLK_APMIXED_MAINPLL>;
+               clock-names = "cpu", "intermediate";
+               operating-points-v2 = <&cpu_opp_table_b>;
+       };
+
+       cpu3: cpu@101 {
+               device_type = "cpu";
+               compatible = "arm,cortex-a57";
+               reg = <0x101>;
+               enable-method = "psci";
+               cpu-idle-states = <&CPU_SLEEP_0>;
+               clocks = <&infracfg CLK_INFRA_CA57SEL>,
+                        <&apmixedsys CLK_APMIXED_MAINPLL>;
+               clock-names = "cpu", "intermediate";
+               operating-points-v2 = <&cpu_opp_table_b>;
+       };
+
+       &cpu0 {
+               proc-supply = <&mt6397_vpca15_reg>;
+       };
+
+       &cpu1 {
+               proc-supply = <&mt6397_vpca15_reg>;
+       };
+
+       &cpu2 {
+               proc-supply = <&da9211_vcpu_reg>;
+               sram-supply = <&mt6397_vsramca7_reg>;
+       };
+
+       &cpu3 {
+               proc-supply = <&da9211_vcpu_reg>;
+               sram-supply = <&mt6397_vsramca7_reg>;
+       };
index d2e65c46bcc7a56048e8892fc9cfc5d5f100f0ce..eca33d56869011b69878d33c115150f52e59bf92 100644 (file)
@@ -13,7 +13,6 @@
                        reg = <0>;
                        clocks = <&clkgen CPU_CLK>;
                        clock-latency = <1>;
-                       operating-points = <1215000 0 607500 0 405000 0 243000 0 135000 0>;
                };
 
                cpu1: cpu@1 {
index 2011fec2d6ad9d5b4ad1b089c38a1be23baeb509..bdce4488ded1709b40282e8b14c614ee14e35ac8 100644 (file)
@@ -71,15 +71,6 @@ config ARM_HIGHBANK_CPUFREQ
 
          If in doubt, say N.
 
-config ARM_DB8500_CPUFREQ
-       tristate "ST-Ericsson DB8500 cpufreq" if COMPILE_TEST && !ARCH_U8500
-       default ARCH_U8500
-       depends on HAS_IOMEM
-       depends on !CPU_THERMAL || THERMAL
-       help
-         This adds the CPUFreq driver for ST-Ericsson Ux500 (DB8500) SoC
-         series.
-
 config ARM_IMX6Q_CPUFREQ
        tristate "Freescale i.MX6 cpufreq support"
        depends on ARCH_MXC
@@ -96,14 +87,13 @@ config ARM_KIRKWOOD_CPUFREQ
          This adds the CPUFreq driver for Marvell Kirkwood
          SoCs.
 
-config ARM_MT8173_CPUFREQ
-       tristate "Mediatek MT8173 CPUFreq support"
+config ARM_MEDIATEK_CPUFREQ
+       tristate "CPU Frequency scaling support for MediaTek SoCs"
        depends on ARCH_MEDIATEK && REGULATOR
-       depends on ARM64 || (ARM_CPU_TOPOLOGY && COMPILE_TEST)
        depends on !CPU_THERMAL || THERMAL
        select PM_OPP
        help
-         This adds the CPUFreq driver support for Mediatek MT8173 SoC.
+         This adds the CPUFreq driver support for MediaTek SoCs.
 
 config ARM_OMAP2PLUS_CPUFREQ
        bool "TI OMAP2+"
@@ -242,6 +232,11 @@ config ARM_STI_CPUFREQ
          this config option if you wish to add CPUFreq support for STi based
          SoCs.
 
+config ARM_TANGO_CPUFREQ
+       bool
+       depends on CPUFREQ_DT && ARCH_TANGO
+       default y
+
 config ARM_TEGRA20_CPUFREQ
        bool "Tegra20 CPUFreq support"
        depends on ARCH_TEGRA
index ab3a42cd29ef210bcf0cad2ee48c74cb954b14f2..c7af9b2a255e1914fafd89d5bcfe2032c8db5b07 100644 (file)
@@ -53,12 +53,11 @@ obj-$(CONFIG_ARM_DT_BL_CPUFREQ)             += arm_big_little_dt.o
 
 obj-$(CONFIG_ARM_BRCMSTB_AVS_CPUFREQ)  += brcmstb-avs-cpufreq.o
 obj-$(CONFIG_ARCH_DAVINCI)             += davinci-cpufreq.o
-obj-$(CONFIG_ARM_DB8500_CPUFREQ)       += dbx500-cpufreq.o
 obj-$(CONFIG_ARM_EXYNOS5440_CPUFREQ)   += exynos5440-cpufreq.o
 obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ)     += highbank-cpufreq.o
 obj-$(CONFIG_ARM_IMX6Q_CPUFREQ)                += imx6q-cpufreq.o
 obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ)     += kirkwood-cpufreq.o
-obj-$(CONFIG_ARM_MT8173_CPUFREQ)       += mt8173-cpufreq.o
+obj-$(CONFIG_ARM_MEDIATEK_CPUFREQ)     += mediatek-cpufreq.o
 obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ)    += omap-cpufreq.o
 obj-$(CONFIG_ARM_PXA2xx_CPUFREQ)       += pxa2xx-cpufreq.o
 obj-$(CONFIG_PXA3xx)                   += pxa3xx-cpufreq.o
@@ -75,6 +74,7 @@ obj-$(CONFIG_ARM_SA1110_CPUFREQ)      += sa1110-cpufreq.o
 obj-$(CONFIG_ARM_SCPI_CPUFREQ)         += scpi-cpufreq.o
 obj-$(CONFIG_ARM_SPEAR_CPUFREQ)                += spear-cpufreq.o
 obj-$(CONFIG_ARM_STI_CPUFREQ)          += sti-cpufreq.o
+obj-$(CONFIG_ARM_TANGO_CPUFREQ)                += tango-cpufreq.o
 obj-$(CONFIG_ARM_TEGRA20_CPUFREQ)      += tegra20-cpufreq.o
 obj-$(CONFIG_ARM_TEGRA124_CPUFREQ)     += tegra124-cpufreq.o
 obj-$(CONFIG_ARM_TEGRA186_CPUFREQ)     += tegra186-cpufreq.o
index ea6d62547b10dea2afe9957448c3fb06b8742e66..17504129fd778164aadcdbbee89dbbbdb40d22b4 100644 (file)
@@ -483,11 +483,8 @@ static int bL_cpufreq_init(struct cpufreq_policy *policy)
                return ret;
        }
 
-       if (arm_bL_ops->get_transition_latency)
-               policy->cpuinfo.transition_latency =
-                       arm_bL_ops->get_transition_latency(cpu_dev);
-       else
-               policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
+       policy->cpuinfo.transition_latency =
+                               arm_bL_ops->get_transition_latency(cpu_dev);
 
        if (is_bL_switching_enabled())
                per_cpu(cpu_last_req_freq, policy->cpu) = clk_get_cpu_rate(policy->cpu);
@@ -622,7 +619,8 @@ int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops)
                return -EBUSY;
        }
 
-       if (!ops || !strlen(ops->name) || !ops->init_opp_table) {
+       if (!ops || !strlen(ops->name) || !ops->init_opp_table ||
+           !ops->get_transition_latency) {
                pr_err("%s: Invalid arm_bL_ops, exiting\n", __func__);
                return -ENODEV;
        }
index 10be285c9055791d7e54927da62666c394dc6dc0..a1c3025f9df77b91bfe278ca89ab16ebe3c295eb 100644 (file)
@@ -172,7 +172,6 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
                return -EFAULT;
        }
 
-       cpumask_set_cpu(policy->cpu, policy->cpus);
        cpu->cur_policy = policy;
 
        /* Set policy->cur to max now. The governors will adjust later. */
index 1c262923fe588256e4ee1c48212f2742340ebf4a..a020da7940d6395a326d5c2ddb6dd01c8f5835e3 100644 (file)
@@ -9,11 +9,16 @@
 
 #include <linux/err.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 
 #include "cpufreq-dt.h"
 
-static const struct of_device_id machines[] __initconst = {
+/*
+ * Machines for which the cpufreq device is *always* created, mostly used for
+ * platforms using "operating-points" (V1) property.
+ */
+static const struct of_device_id whitelist[] __initconst = {
        { .compatible = "allwinner,sun4i-a10", },
        { .compatible = "allwinner,sun5i-a10s", },
        { .compatible = "allwinner,sun5i-a13", },
@@ -22,7 +27,6 @@ static const struct of_device_id machines[] __initconst = {
        { .compatible = "allwinner,sun6i-a31s", },
        { .compatible = "allwinner,sun7i-a20", },
        { .compatible = "allwinner,sun8i-a23", },
-       { .compatible = "allwinner,sun8i-a33", },
        { .compatible = "allwinner,sun8i-a83t", },
        { .compatible = "allwinner,sun8i-h3", },
 
@@ -32,7 +36,6 @@ static const struct of_device_id machines[] __initconst = {
        { .compatible = "arm,integrator-cp", },
 
        { .compatible = "hisilicon,hi3660", },
-       { .compatible = "hisilicon,hi6220", },
 
        { .compatible = "fsl,imx27", },
        { .compatible = "fsl,imx51", },
@@ -46,11 +49,8 @@ static const struct of_device_id machines[] __initconst = {
        { .compatible = "samsung,exynos3250", },
        { .compatible = "samsung,exynos4210", },
        { .compatible = "samsung,exynos4212", },
-       { .compatible = "samsung,exynos4412", },
        { .compatible = "samsung,exynos5250", },
 #ifndef CONFIG_BL_SWITCHER
-       { .compatible = "samsung,exynos5420", },
-       { .compatible = "samsung,exynos5433", },
        { .compatible = "samsung,exynos5800", },
 #endif
 
@@ -67,6 +67,8 @@ static const struct of_device_id machines[] __initconst = {
        { .compatible = "renesas,r8a7792", },
        { .compatible = "renesas,r8a7793", },
        { .compatible = "renesas,r8a7794", },
+       { .compatible = "renesas,r8a7795", },
+       { .compatible = "renesas,r8a7796", },
        { .compatible = "renesas,sh73a0", },
 
        { .compatible = "rockchip,rk2928", },
@@ -76,17 +78,17 @@ static const struct of_device_id machines[] __initconst = {
        { .compatible = "rockchip,rk3188", },
        { .compatible = "rockchip,rk3228", },
        { .compatible = "rockchip,rk3288", },
+       { .compatible = "rockchip,rk3328", },
        { .compatible = "rockchip,rk3366", },
        { .compatible = "rockchip,rk3368", },
        { .compatible = "rockchip,rk3399", },
 
-       { .compatible = "sigma,tango4" },
-
-       { .compatible = "socionext,uniphier-pro5", },
-       { .compatible = "socionext,uniphier-pxs2", },
        { .compatible = "socionext,uniphier-ld6b", },
-       { .compatible = "socionext,uniphier-ld11", },
-       { .compatible = "socionext,uniphier-ld20", },
+
+       { .compatible = "st-ericsson,u8500", },
+       { .compatible = "st-ericsson,u8540", },
+       { .compatible = "st-ericsson,u9500", },
+       { .compatible = "st-ericsson,u9540", },
 
        { .compatible = "ti,omap2", },
        { .compatible = "ti,omap3", },
@@ -94,27 +96,56 @@ static const struct of_device_id machines[] __initconst = {
        { .compatible = "ti,omap5", },
 
        { .compatible = "xlnx,zynq-7000", },
+       { .compatible = "xlnx,zynqmp", },
 
-       { .compatible = "zte,zx296718", },
+       { }
+};
 
+/*
+ * Machines for which the cpufreq device is *not* created, mostly used for
+ * platforms using "operating-points-v2" property.
+ */
+static const struct of_device_id blacklist[] __initconst = {
        { }
 };
 
+static bool __init cpu0_node_has_opp_v2_prop(void)
+{
+       struct device_node *np = of_cpu_device_node_get(0);
+       bool ret = false;
+
+       if (of_get_property(np, "operating-points-v2", NULL))
+               ret = true;
+
+       of_node_put(np);
+       return ret;
+}
+
 static int __init cpufreq_dt_platdev_init(void)
 {
        struct device_node *np = of_find_node_by_path("/");
        const struct of_device_id *match;
+       const void *data = NULL;
 
        if (!np)
                return -ENODEV;
 
-       match = of_match_node(machines, np);
+       match = of_match_node(whitelist, np);
+       if (match) {
+               data = match->data;
+               goto create_pdev;
+       }
+
+       if (cpu0_node_has_opp_v2_prop() && !of_match_node(blacklist, np))
+               goto create_pdev;
+
        of_node_put(np);
-       if (!match)
-               return -ENODEV;
+       return -ENODEV;
 
+create_pdev:
+       of_node_put(np);
        return PTR_ERR_OR_ZERO(platform_device_register_data(NULL, "cpufreq-dt",
-                              -1, match->data,
+                              -1, data,
                               sizeof(struct cpufreq_dt_platform_data)));
 }
 device_initcall(cpufreq_dt_platdev_init);
index 5503d491b0160f39be799469aef3fd0d5bc60e72..dbf82f36d270dfd8fd5bd51b4db5f261c37930c4 100644 (file)
@@ -357,7 +357,6 @@ static int nforce2_cpu_init(struct cpufreq_policy *policy)
        /* cpuinfo and default policy values */
        policy->min = policy->cpuinfo.min_freq = min_fsb * fid * 100;
        policy->max = policy->cpuinfo.max_freq = max_fsb * fid * 100;
-       policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
 
        return 0;
 }
@@ -369,6 +368,7 @@ static int nforce2_cpu_exit(struct cpufreq_policy *policy)
 
 static struct cpufreq_driver nforce2_driver = {
        .name = "nforce2",
+       .flags = CPUFREQ_NO_AUTO_DYNAMIC_SWITCHING,
        .verify = nforce2_verify,
        .target = nforce2_target,
        .get = nforce2_get,
index 9bf97a366029f22b959a50d819d362b0f51bf5a4..c7ae67d6886d1730bdccfc445b475991904b8e82 100644 (file)
@@ -524,6 +524,32 @@ unsigned int cpufreq_driver_resolve_freq(struct cpufreq_policy *policy,
 }
 EXPORT_SYMBOL_GPL(cpufreq_driver_resolve_freq);
 
+unsigned int cpufreq_policy_transition_delay_us(struct cpufreq_policy *policy)
+{
+       unsigned int latency;
+
+       if (policy->transition_delay_us)
+               return policy->transition_delay_us;
+
+       latency = policy->cpuinfo.transition_latency / NSEC_PER_USEC;
+       if (latency) {
+               /*
+                * For platforms that can change the frequency very fast (< 10
+                * us), the above formula gives a decent transition delay. But
+                * for platforms where transition_latency is in milliseconds, it
+                * ends up giving unrealistic values.
+                *
+                * Cap the default transition delay to 10 ms, which seems to be
+                * a reasonable amount of time after which we should reevaluate
+                * the frequency.
+                */
+               return min(latency * LATENCY_MULTIPLIER, (unsigned int)10000);
+       }
+
+       return LATENCY_MULTIPLIER;
+}
+EXPORT_SYMBOL_GPL(cpufreq_policy_transition_delay_us);
+
 /*********************************************************************
  *                          SYSFS INTERFACE                          *
  *********************************************************************/
@@ -1988,13 +2014,13 @@ static int cpufreq_init_governor(struct cpufreq_policy *policy)
        if (!policy->governor)
                return -EINVAL;
 
-       if (policy->governor->max_transition_latency &&
-           policy->cpuinfo.transition_latency >
-           policy->governor->max_transition_latency) {
+       /* Platform doesn't want dynamic frequency switching ? */
+       if (policy->governor->dynamic_switching &&
+           cpufreq_driver->flags & CPUFREQ_NO_AUTO_DYNAMIC_SWITCHING) {
                struct cpufreq_governor *gov = cpufreq_fallback_governor();
 
                if (gov) {
-                       pr_warn("%s governor failed, too long transition latency of HW, fallback to %s governor\n",
+                       pr_warn("Can't use %s governor as dynamic switching is disallowed. Fallback to %s governor\n",
                                policy->governor->name, gov->name);
                        policy->governor = gov;
                } else {
index 88220ff3e1c226277e7ef8895317a5a1314ddee6..f20f20a77d4d37cad47eea9673552478dd1ccf32 100644 (file)
@@ -246,7 +246,6 @@ gov_show_one_common(sampling_rate);
 gov_show_one_common(sampling_down_factor);
 gov_show_one_common(up_threshold);
 gov_show_one_common(ignore_nice_load);
-gov_show_one_common(min_sampling_rate);
 gov_show_one(cs, down_threshold);
 gov_show_one(cs, freq_step);
 
@@ -254,12 +253,10 @@ gov_attr_rw(sampling_rate);
 gov_attr_rw(sampling_down_factor);
 gov_attr_rw(up_threshold);
 gov_attr_rw(ignore_nice_load);
-gov_attr_ro(min_sampling_rate);
 gov_attr_rw(down_threshold);
 gov_attr_rw(freq_step);
 
 static struct attribute *cs_attributes[] = {
-       &min_sampling_rate.attr,
        &sampling_rate.attr,
        &sampling_down_factor.attr,
        &up_threshold.attr,
@@ -297,10 +294,7 @@ static int cs_init(struct dbs_data *dbs_data)
        dbs_data->up_threshold = DEF_FREQUENCY_UP_THRESHOLD;
        dbs_data->sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR;
        dbs_data->ignore_nice_load = 0;
-
        dbs_data->tuners = tuners;
-       dbs_data->min_sampling_rate = MIN_SAMPLING_RATE_RATIO *
-               jiffies_to_usecs(10);
 
        return 0;
 }
index 47e24b5384b37978cde5ce1f0e2eeb440e6ea04b..eed069ecfd5ebf49a72a45e347f788c6cd13fe84 100644 (file)
@@ -47,14 +47,11 @@ ssize_t store_sampling_rate(struct gov_attr_set *attr_set, const char *buf,
 {
        struct dbs_data *dbs_data = to_dbs_data(attr_set);
        struct policy_dbs_info *policy_dbs;
-       unsigned int rate;
        int ret;
-       ret = sscanf(buf, "%u", &rate);
+       ret = sscanf(buf, "%u", &dbs_data->sampling_rate);
        if (ret != 1)
                return -EINVAL;
 
-       dbs_data->sampling_rate = max(rate, dbs_data->min_sampling_rate);
-
        /*
         * We are operating under dbs_data->mutex and so the list and its
         * entries can't be freed concurrently.
@@ -392,7 +389,6 @@ int cpufreq_dbs_governor_init(struct cpufreq_policy *policy)
        struct dbs_governor *gov = dbs_governor_of(policy);
        struct dbs_data *dbs_data;
        struct policy_dbs_info *policy_dbs;
-       unsigned int latency;
        int ret = 0;
 
        /* State should be equivalent to EXIT */
@@ -431,16 +427,7 @@ int cpufreq_dbs_governor_init(struct cpufreq_policy *policy)
        if (ret)
                goto free_policy_dbs_info;
 
-       /* policy latency is in ns. Convert it to us first */
-       latency = policy->cpuinfo.transition_latency / 1000;
-       if (latency == 0)
-               latency = 1;
-
-       /* Bring kernel and HW constraints together */
-       dbs_data->min_sampling_rate = max(dbs_data->min_sampling_rate,
-                                         MIN_LATENCY_MULTIPLIER * latency);
-       dbs_data->sampling_rate = max(dbs_data->min_sampling_rate,
-                                     LATENCY_MULTIPLIER * latency);
+       dbs_data->sampling_rate = cpufreq_policy_transition_delay_us(policy);
 
        if (!have_governor_per_policy())
                gov->gdbs_data = dbs_data;
index 0236ec2cd654b34bb9fb1e42d416138f63619b10..8463f5def0f596fb3424f6e2a25bb775460e05c7 100644 (file)
@@ -41,7 +41,6 @@ enum {OD_NORMAL_SAMPLE, OD_SUB_SAMPLE};
 struct dbs_data {
        struct gov_attr_set attr_set;
        void *tuners;
-       unsigned int min_sampling_rate;
        unsigned int ignore_nice_load;
        unsigned int sampling_rate;
        unsigned int sampling_down_factor;
@@ -160,7 +159,7 @@ void cpufreq_dbs_governor_limits(struct cpufreq_policy *policy);
 #define CPUFREQ_DBS_GOVERNOR_INITIALIZER(_name_)                       \
        {                                                               \
                .name = _name_,                                         \
-               .max_transition_latency = TRANSITION_LATENCY_LIMIT,     \
+               .dynamic_switching = true,                              \
                .owner = THIS_MODULE,                                   \
                .init = cpufreq_dbs_governor_init,                      \
                .exit = cpufreq_dbs_governor_exit,                      \
index 3937acf7e026cdf80296f1eef4116e1774b76dab..6b423eebfd5dbefccc2f20e52825271d0b2a7114 100644 (file)
@@ -319,7 +319,6 @@ gov_show_one_common(sampling_rate);
 gov_show_one_common(up_threshold);
 gov_show_one_common(sampling_down_factor);
 gov_show_one_common(ignore_nice_load);
-gov_show_one_common(min_sampling_rate);
 gov_show_one_common(io_is_busy);
 gov_show_one(od, powersave_bias);
 
@@ -329,10 +328,8 @@ gov_attr_rw(up_threshold);
 gov_attr_rw(sampling_down_factor);
 gov_attr_rw(ignore_nice_load);
 gov_attr_rw(powersave_bias);
-gov_attr_ro(min_sampling_rate);
 
 static struct attribute *od_attributes[] = {
-       &min_sampling_rate.attr,
        &sampling_rate.attr,
        &up_threshold.attr,
        &sampling_down_factor.attr,
@@ -373,17 +370,8 @@ static int od_init(struct dbs_data *dbs_data)
        if (idle_time != -1ULL) {
                /* Idle micro accounting is supported. Use finer thresholds */
                dbs_data->up_threshold = MICRO_FREQUENCY_UP_THRESHOLD;
-               /*
-                * In nohz/micro accounting case we set the minimum frequency
-                * not depending on HZ, but fixed (very low).
-               */
-               dbs_data->min_sampling_rate = MICRO_FREQUENCY_MIN_SAMPLE_RATE;
        } else {
                dbs_data->up_threshold = DEF_FREQUENCY_UP_THRESHOLD;
-
-               /* For correct statistics, we need 10 ticks for each measure */
-               dbs_data->min_sampling_rate = MIN_SAMPLING_RATE_RATIO *
-                       jiffies_to_usecs(10);
        }
 
        dbs_data->sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR;
diff --git a/drivers/cpufreq/dbx500-cpufreq.c b/drivers/cpufreq/dbx500-cpufreq.c
deleted file mode 100644 (file)
index 4ee0431..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) STMicroelectronics 2009
- * Copyright (C) ST-Ericsson SA 2010-2012
- *
- * License Terms: GNU General Public License v2
- * Author: Sundar Iyer <sundar.iyer@stericsson.com>
- * Author: Martin Persson <martin.persson@stericsson.com>
- * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/cpufreq.h>
-#include <linux/cpu_cooling.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-
-static struct cpufreq_frequency_table *freq_table;
-static struct clk *armss_clk;
-static struct thermal_cooling_device *cdev;
-
-static int dbx500_cpufreq_target(struct cpufreq_policy *policy,
-                               unsigned int index)
-{
-       /* update armss clk frequency */
-       return clk_set_rate(armss_clk, freq_table[index].frequency * 1000);
-}
-
-static int dbx500_cpufreq_init(struct cpufreq_policy *policy)
-{
-       policy->clk = armss_clk;
-       return cpufreq_generic_init(policy, freq_table, 20 * 1000);
-}
-
-static int dbx500_cpufreq_exit(struct cpufreq_policy *policy)
-{
-       if (!IS_ERR(cdev))
-               cpufreq_cooling_unregister(cdev);
-       return 0;
-}
-
-static void dbx500_cpufreq_ready(struct cpufreq_policy *policy)
-{
-       cdev = cpufreq_cooling_register(policy);
-       if (IS_ERR(cdev))
-               pr_err("Failed to register cooling device %ld\n", PTR_ERR(cdev));
-       else
-               pr_info("Cooling device registered: %s\n", cdev->type);
-}
-
-static struct cpufreq_driver dbx500_cpufreq_driver = {
-       .flags  = CPUFREQ_STICKY | CPUFREQ_CONST_LOOPS |
-                       CPUFREQ_NEED_INITIAL_FREQ_CHECK,
-       .verify = cpufreq_generic_frequency_table_verify,
-       .target_index = dbx500_cpufreq_target,
-       .get    = cpufreq_generic_get,
-       .init   = dbx500_cpufreq_init,
-       .exit  = dbx500_cpufreq_exit,
-       .ready  = dbx500_cpufreq_ready,
-       .name   = "DBX500",
-       .attr   = cpufreq_generic_attr,
-};
-
-static int dbx500_cpufreq_probe(struct platform_device *pdev)
-{
-       struct cpufreq_frequency_table *pos;
-
-       freq_table = dev_get_platdata(&pdev->dev);
-       if (!freq_table) {
-               pr_err("dbx500-cpufreq: Failed to fetch cpufreq table\n");
-               return -ENODEV;
-       }
-
-       armss_clk = clk_get(&pdev->dev, "armss");
-       if (IS_ERR(armss_clk)) {
-               pr_err("dbx500-cpufreq: Failed to get armss clk\n");
-               return PTR_ERR(armss_clk);
-       }
-
-       pr_info("dbx500-cpufreq: Available frequencies:\n");
-       cpufreq_for_each_entry(pos, freq_table)
-               pr_info("  %d Mhz\n", pos->frequency / 1000);
-
-       return cpufreq_register_driver(&dbx500_cpufreq_driver);
-}
-
-static struct platform_driver dbx500_cpufreq_plat_driver = {
-       .driver = {
-               .name = "cpufreq-ux500",
-       },
-       .probe = dbx500_cpufreq_probe,
-};
-
-static int __init dbx500_cpufreq_register(void)
-{
-       return platform_driver_register(&dbx500_cpufreq_plat_driver);
-}
-device_initcall(dbx500_cpufreq_register);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("cpufreq driver for DBX500");
index bfce11cba1df8d92068b4095e1772ce38b7db12e..45e2ca62515e5647bdd60034575b35e964185005 100644 (file)
@@ -165,9 +165,6 @@ static int elanfreq_cpu_init(struct cpufreq_policy *policy)
                if (pos->frequency > max_freq)
                        pos->frequency = CPUFREQ_ENTRY_INVALID;
 
-       /* cpuinfo and default policy values */
-       policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
-
        return cpufreq_table_validate_and_show(policy, elanfreq_table);
 }
 
@@ -196,6 +193,7 @@ __setup("elanfreq=", elanfreq_setup);
 
 static struct cpufreq_driver elanfreq_driver = {
        .get            = elanfreq_get_cpu_frequency,
+       .flags          = CPUFREQ_NO_AUTO_DYNAMIC_SWITCHING,
        .verify         = cpufreq_generic_frequency_table_verify,
        .target_index   = elanfreq_target,
        .init           = elanfreq_cpu_init,
index 3488c9c175eb2ed90164d1b2d20fcf2c089262b7..8f52a06664e32d058c3192406f233cdafa7d1a98 100644 (file)
@@ -428,7 +428,6 @@ static int cpufreq_gx_cpu_init(struct cpufreq_policy *policy)
        policy->max = maxfreq;
        policy->cpuinfo.min_freq = maxfreq / max_duration;
        policy->cpuinfo.max_freq = maxfreq;
-       policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
 
        return 0;
 }
@@ -438,6 +437,7 @@ static int cpufreq_gx_cpu_init(struct cpufreq_policy *policy)
  *   MediaGX/Geode GX initialize cpufreq driver
  */
 static struct cpufreq_driver gx_suspmod_driver = {
+       .flags          = CPUFREQ_NO_AUTO_DYNAMIC_SWITCHING,
        .get            = gx_get_cpuspeed,
        .verify         = cpufreq_gx_verify,
        .target         = cpufreq_gx_target,
index b6edd3ccaa55b3e59c272b580796193f266f9ed4..14466a9b01c0b42b4eaa10fc946e1c5ad70f0d82 100644 (file)
@@ -47,6 +47,7 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
        struct dev_pm_opp *opp;
        unsigned long freq_hz, volt, volt_old;
        unsigned int old_freq, new_freq;
+       bool pll1_sys_temp_enabled = false;
        int ret;
 
        new_freq = freq_table[index].frequency;
@@ -124,6 +125,10 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
                if (freq_hz > clk_get_rate(pll2_pfd2_396m_clk)) {
                        clk_set_rate(pll1_sys_clk, new_freq * 1000);
                        clk_set_parent(pll1_sw_clk, pll1_sys_clk);
+               } else {
+                       /* pll1_sys needs to be enabled for divider rate change to work. */
+                       pll1_sys_temp_enabled = true;
+                       clk_prepare_enable(pll1_sys_clk);
                }
        }
 
@@ -135,6 +140,10 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
                return ret;
        }
 
+       /* PLL1 is only needed until after ARM-PODF is set. */
+       if (pll1_sys_temp_enabled)
+               clk_disable_unprepare(pll1_sys_clk);
+
        /* scaling down?  scale voltage after frequency */
        if (new_freq < old_freq) {
                ret = regulator_set_voltage_tol(arm_reg, volt, 0);
index 65ee4fcace1f260632cf53c150c3260cc27240ad..04dd5f46803dd268b3189857edbd89db24b7cbf1 100644 (file)
@@ -2132,7 +2132,6 @@ static int __intel_pstate_cpu_init(struct cpufreq_policy *policy)
        policy->cpuinfo.max_freq *= cpu->pstate.scaling;
 
        intel_pstate_init_acpi_perf_limits(policy);
-       cpumask_set_cpu(policy->cpu, policy->cpus);
 
        policy->fast_switch_possible = true;
 
@@ -2146,7 +2145,6 @@ static int intel_pstate_cpu_init(struct cpufreq_policy *policy)
        if (ret)
                return ret;
 
-       policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
        if (IS_ENABLED(CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE))
                policy->policy = CPUFREQ_POLICY_PERFORMANCE;
        else
index 074971b12635af04b7214f510c70e7e8c37ebcbf..542aa9adba1a407c26bc025c4272af700e5251df 100644 (file)
@@ -270,7 +270,6 @@ static int longrun_cpu_init(struct cpufreq_policy *policy)
        /* cpuinfo and default policy values */
        policy->cpuinfo.min_freq = longrun_low_freq;
        policy->cpuinfo.max_freq = longrun_high_freq;
-       policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
        longrun_get_policy(policy);
 
        return 0;
index 9ac27b22476cd10437c13a870cc383b7441b9ff0..da344696beed7ff611a40c58582ffcf39bc79d2d 100644 (file)
@@ -114,7 +114,7 @@ static struct cpufreq_driver loongson2_cpufreq_driver = {
        .attr = cpufreq_generic_attr,
 };
 
-static struct platform_device_id platform_device_ids[] = {
+static const struct platform_device_id platform_device_ids[] = {
        {
                .name = "loongson2_cpufreq",
        },
diff --git a/drivers/cpufreq/mediatek-cpufreq.c b/drivers/cpufreq/mediatek-cpufreq.c
new file mode 100644 (file)
index 0000000..18c4bd9
--- /dev/null
@@ -0,0 +1,622 @@
+/*
+ * Copyright (c) 2015 Linaro Ltd.
+ * Author: Pi-Cheng Chen <pi-cheng.chen@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#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>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_opp.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/thermal.h>
+
+#define MIN_VOLT_SHIFT         (100000)
+#define MAX_VOLT_SHIFT         (200000)
+#define MAX_VOLT_LIMIT         (1150000)
+#define VOLT_TOL               (10000)
+
+/*
+ * The struct mtk_cpu_dvfs_info holds necessary information for doing CPU DVFS
+ * on each CPU power/clock domain of Mediatek SoCs. Each CPU cluster in
+ * Mediatek SoCs has two voltage inputs, Vproc and Vsram. In some cases the two
+ * voltage inputs need to be controlled under a hardware limitation:
+ * 100mV < Vsram - Vproc < 200mV
+ *
+ * When scaling the clock frequency of a CPU clock domain, the clock source
+ * needs to be switched to another stable PLL clock temporarily until
+ * the original PLL becomes stable at target frequency.
+ */
+struct mtk_cpu_dvfs_info {
+       struct cpumask cpus;
+       struct device *cpu_dev;
+       struct regulator *proc_reg;
+       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;
+};
+
+static LIST_HEAD(dvfs_info_list);
+
+static struct mtk_cpu_dvfs_info *mtk_cpu_dvfs_info_lookup(int cpu)
+{
+       struct mtk_cpu_dvfs_info *info;
+
+       list_for_each_entry(info, &dvfs_info_list, list_head) {
+               if (cpumask_test_cpu(cpu, &info->cpus))
+                       return info;
+       }
+
+       return NULL;
+}
+
+static int mtk_cpufreq_voltage_tracking(struct mtk_cpu_dvfs_info *info,
+                                       int new_vproc)
+{
+       struct regulator *proc_reg = info->proc_reg;
+       struct regulator *sram_reg = info->sram_reg;
+       int old_vproc, old_vsram, new_vsram, vsram, vproc, ret;
+
+       old_vproc = regulator_get_voltage(proc_reg);
+       if (old_vproc < 0) {
+               pr_err("%s: invalid Vproc value: %d\n", __func__, old_vproc);
+               return old_vproc;
+       }
+       /* Vsram should not exceed the maximum allowed voltage of SoC. */
+       new_vsram = min(new_vproc + MIN_VOLT_SHIFT, MAX_VOLT_LIMIT);
+
+       if (old_vproc < new_vproc) {
+               /*
+                * When scaling up voltages, Vsram and Vproc scale up step
+                * by step. At each step, set Vsram to (Vproc + 200mV) first,
+                * then set Vproc to (Vsram - 100mV).
+                * Keep doing it until Vsram and Vproc hit target voltages.
+                */
+               do {
+                       old_vsram = regulator_get_voltage(sram_reg);
+                       if (old_vsram < 0) {
+                               pr_err("%s: invalid Vsram value: %d\n",
+                                      __func__, old_vsram);
+                               return old_vsram;
+                       }
+                       old_vproc = regulator_get_voltage(proc_reg);
+                       if (old_vproc < 0) {
+                               pr_err("%s: invalid Vproc value: %d\n",
+                                      __func__, old_vproc);
+                               return old_vproc;
+                       }
+
+                       vsram = min(new_vsram, old_vproc + MAX_VOLT_SHIFT);
+
+                       if (vsram + VOLT_TOL >= MAX_VOLT_LIMIT) {
+                               vsram = MAX_VOLT_LIMIT;
+
+                               /*
+                                * If the target Vsram hits the maximum voltage,
+                                * try to set the exact voltage value first.
+                                */
+                               ret = regulator_set_voltage(sram_reg, vsram,
+                                                           vsram);
+                               if (ret)
+                                       ret = regulator_set_voltage(sram_reg,
+                                                       vsram - VOLT_TOL,
+                                                       vsram);
+
+                               vproc = new_vproc;
+                       } else {
+                               ret = regulator_set_voltage(sram_reg, vsram,
+                                                           vsram + VOLT_TOL);
+
+                               vproc = vsram - MIN_VOLT_SHIFT;
+                       }
+                       if (ret)
+                               return ret;
+
+                       ret = regulator_set_voltage(proc_reg, vproc,
+                                                   vproc + VOLT_TOL);
+                       if (ret) {
+                               regulator_set_voltage(sram_reg, old_vsram,
+                                                     old_vsram);
+                               return ret;
+                       }
+               } while (vproc < new_vproc || vsram < new_vsram);
+       } else if (old_vproc > new_vproc) {
+               /*
+                * When scaling down voltages, Vsram and Vproc scale down step
+                * by step. At each step, set Vproc to (Vsram - 200mV) first,
+                * then set Vproc to (Vproc + 100mV).
+                * Keep doing it until Vsram and Vproc hit target voltages.
+                */
+               do {
+                       old_vproc = regulator_get_voltage(proc_reg);
+                       if (old_vproc < 0) {
+                               pr_err("%s: invalid Vproc value: %d\n",
+                                      __func__, old_vproc);
+                               return old_vproc;
+                       }
+                       old_vsram = regulator_get_voltage(sram_reg);
+                       if (old_vsram < 0) {
+                               pr_err("%s: invalid Vsram value: %d\n",
+                                      __func__, old_vsram);
+                               return old_vsram;
+                       }
+
+                       vproc = max(new_vproc, old_vsram - MAX_VOLT_SHIFT);
+                       ret = regulator_set_voltage(proc_reg, vproc,
+                                                   vproc + VOLT_TOL);
+                       if (ret)
+                               return ret;
+
+                       if (vproc == new_vproc)
+                               vsram = new_vsram;
+                       else
+                               vsram = max(new_vsram, vproc + MIN_VOLT_SHIFT);
+
+                       if (vsram + VOLT_TOL >= MAX_VOLT_LIMIT) {
+                               vsram = MAX_VOLT_LIMIT;
+
+                               /*
+                                * If the target Vsram hits the maximum voltage,
+                                * try to set the exact voltage value first.
+                                */
+                               ret = regulator_set_voltage(sram_reg, vsram,
+                                                           vsram);
+                               if (ret)
+                                       ret = regulator_set_voltage(sram_reg,
+                                                       vsram - VOLT_TOL,
+                                                       vsram);
+                       } else {
+                               ret = regulator_set_voltage(sram_reg, vsram,
+                                                           vsram + VOLT_TOL);
+                       }
+
+                       if (ret) {
+                               regulator_set_voltage(proc_reg, old_vproc,
+                                                     old_vproc);
+                               return ret;
+                       }
+               } while (vproc > new_vproc + VOLT_TOL ||
+                        vsram > new_vsram + VOLT_TOL);
+       }
+
+       return 0;
+}
+
+static int mtk_cpufreq_set_voltage(struct mtk_cpu_dvfs_info *info, int vproc)
+{
+       if (info->need_voltage_tracking)
+               return mtk_cpufreq_voltage_tracking(info, vproc);
+       else
+               return regulator_set_voltage(info->proc_reg, vproc,
+                                            vproc + VOLT_TOL);
+}
+
+static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
+                                 unsigned int index)
+{
+       struct cpufreq_frequency_table *freq_table = policy->freq_table;
+       struct clk *cpu_clk = policy->clk;
+       struct clk *armpll = clk_get_parent(cpu_clk);
+       struct mtk_cpu_dvfs_info *info = policy->driver_data;
+       struct device *cpu_dev = info->cpu_dev;
+       struct dev_pm_opp *opp;
+       long freq_hz, old_freq_hz;
+       int vproc, old_vproc, inter_vproc, target_vproc, ret;
+
+       inter_vproc = info->intermediate_voltage;
+
+       old_freq_hz = clk_get_rate(cpu_clk);
+       old_vproc = regulator_get_voltage(info->proc_reg);
+       if (old_vproc < 0) {
+               pr_err("%s: invalid Vproc value: %d\n", __func__, old_vproc);
+               return old_vproc;
+       }
+
+       freq_hz = freq_table[index].frequency * 1000;
+
+       opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz);
+       if (IS_ERR(opp)) {
+               pr_err("cpu%d: failed to find OPP for %ld\n",
+                      policy->cpu, freq_hz);
+               return PTR_ERR(opp);
+       }
+       vproc = dev_pm_opp_get_voltage(opp);
+       dev_pm_opp_put(opp);
+
+       /*
+        * If the new voltage or the intermediate voltage is higher than the
+        * current voltage, scale up voltage first.
+        */
+       target_vproc = (inter_vproc > vproc) ? inter_vproc : vproc;
+       if (old_vproc < target_vproc) {
+               ret = mtk_cpufreq_set_voltage(info, target_vproc);
+               if (ret) {
+                       pr_err("cpu%d: failed to scale up voltage!\n",
+                              policy->cpu);
+                       mtk_cpufreq_set_voltage(info, old_vproc);
+                       return ret;
+               }
+       }
+
+       /* Reparent the CPU clock to intermediate clock. */
+       ret = clk_set_parent(cpu_clk, info->inter_clk);
+       if (ret) {
+               pr_err("cpu%d: failed to re-parent cpu clock!\n",
+                      policy->cpu);
+               mtk_cpufreq_set_voltage(info, old_vproc);
+               WARN_ON(1);
+               return ret;
+       }
+
+       /* Set the original PLL to target rate. */
+       ret = clk_set_rate(armpll, freq_hz);
+       if (ret) {
+               pr_err("cpu%d: failed to scale cpu clock rate!\n",
+                      policy->cpu);
+               clk_set_parent(cpu_clk, armpll);
+               mtk_cpufreq_set_voltage(info, old_vproc);
+               return ret;
+       }
+
+       /* Set parent of CPU clock back to the original PLL. */
+       ret = clk_set_parent(cpu_clk, armpll);
+       if (ret) {
+               pr_err("cpu%d: failed to re-parent cpu clock!\n",
+                      policy->cpu);
+               mtk_cpufreq_set_voltage(info, inter_vproc);
+               WARN_ON(1);
+               return ret;
+       }
+
+       /*
+        * If the new voltage is lower than the intermediate voltage or the
+        * original voltage, scale down to the new voltage.
+        */
+       if (vproc < inter_vproc || vproc < old_vproc) {
+               ret = mtk_cpufreq_set_voltage(info, vproc);
+               if (ret) {
+                       pr_err("cpu%d: failed to scale down voltage!\n",
+                              policy->cpu);
+                       clk_set_parent(cpu_clk, info->inter_clk);
+                       clk_set_rate(armpll, old_freq_hz);
+                       clk_set_parent(cpu_clk, armpll);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+#define DYNAMIC_POWER "dynamic-power-coefficient"
+
+static void mtk_cpufreq_ready(struct cpufreq_policy *policy)
+{
+       struct mtk_cpu_dvfs_info *info = policy->driver_data;
+       struct device_node *np = of_node_get(info->cpu_dev->of_node);
+       u32 capacitance = 0;
+
+       if (WARN_ON(!np))
+               return;
+
+       if (of_find_property(np, "#cooling-cells", NULL)) {
+               of_property_read_u32(np, DYNAMIC_POWER, &capacitance);
+
+               info->cdev = of_cpufreq_power_cooling_register(np,
+                                               policy, capacitance, NULL);
+
+               if (IS_ERR(info->cdev)) {
+                       dev_err(info->cpu_dev,
+                               "running cpufreq without cooling device: %ld\n",
+                               PTR_ERR(info->cdev));
+
+                       info->cdev = NULL;
+               }
+       }
+
+       of_node_put(np);
+}
+
+static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
+{
+       struct device *cpu_dev;
+       struct regulator *proc_reg = ERR_PTR(-ENODEV);
+       struct regulator *sram_reg = ERR_PTR(-ENODEV);
+       struct clk *cpu_clk = ERR_PTR(-ENODEV);
+       struct clk *inter_clk = ERR_PTR(-ENODEV);
+       struct dev_pm_opp *opp;
+       unsigned long rate;
+       int ret;
+
+       cpu_dev = get_cpu_device(cpu);
+       if (!cpu_dev) {
+               pr_err("failed to get cpu%d device\n", cpu);
+               return -ENODEV;
+       }
+
+       cpu_clk = clk_get(cpu_dev, "cpu");
+       if (IS_ERR(cpu_clk)) {
+               if (PTR_ERR(cpu_clk) == -EPROBE_DEFER)
+                       pr_warn("cpu clk for cpu%d not ready, retry.\n", cpu);
+               else
+                       pr_err("failed to get cpu clk for cpu%d\n", cpu);
+
+               ret = PTR_ERR(cpu_clk);
+               return ret;
+       }
+
+       inter_clk = clk_get(cpu_dev, "intermediate");
+       if (IS_ERR(inter_clk)) {
+               if (PTR_ERR(inter_clk) == -EPROBE_DEFER)
+                       pr_warn("intermediate clk for cpu%d not ready, retry.\n",
+                               cpu);
+               else
+                       pr_err("failed to get intermediate clk for cpu%d\n",
+                              cpu);
+
+               ret = PTR_ERR(inter_clk);
+               goto out_free_resources;
+       }
+
+       proc_reg = regulator_get_exclusive(cpu_dev, "proc");
+       if (IS_ERR(proc_reg)) {
+               if (PTR_ERR(proc_reg) == -EPROBE_DEFER)
+                       pr_warn("proc regulator for cpu%d not ready, retry.\n",
+                               cpu);
+               else
+                       pr_err("failed to get proc regulator for cpu%d\n",
+                              cpu);
+
+               ret = PTR_ERR(proc_reg);
+               goto out_free_resources;
+       }
+
+       /* Both presence and absence of sram regulator are valid cases. */
+       sram_reg = regulator_get_exclusive(cpu_dev, "sram");
+
+       /* Get OPP-sharing information from "operating-points-v2" bindings */
+       ret = dev_pm_opp_of_get_sharing_cpus(cpu_dev, &info->cpus);
+       if (ret) {
+               pr_err("failed to get OPP-sharing information for cpu%d\n",
+                      cpu);
+               goto out_free_resources;
+       }
+
+       ret = dev_pm_opp_of_cpumask_add_table(&info->cpus);
+       if (ret) {
+               pr_warn("no OPP table for cpu%d\n", cpu);
+               goto out_free_resources;
+       }
+
+       /* Search a safe voltage for intermediate frequency. */
+       rate = clk_get_rate(inter_clk);
+       opp = dev_pm_opp_find_freq_ceil(cpu_dev, &rate);
+       if (IS_ERR(opp)) {
+               pr_err("failed to get intermediate opp for cpu%d\n", cpu);
+               ret = PTR_ERR(opp);
+               goto out_free_opp_table;
+       }
+       info->intermediate_voltage = dev_pm_opp_get_voltage(opp);
+       dev_pm_opp_put(opp);
+
+       info->cpu_dev = cpu_dev;
+       info->proc_reg = proc_reg;
+       info->sram_reg = IS_ERR(sram_reg) ? NULL : sram_reg;
+       info->cpu_clk = cpu_clk;
+       info->inter_clk = inter_clk;
+
+       /*
+        * If SRAM regulator is present, software "voltage tracking" is needed
+        * for this CPU power domain.
+        */
+       info->need_voltage_tracking = !IS_ERR(sram_reg);
+
+       return 0;
+
+out_free_opp_table:
+       dev_pm_opp_of_cpumask_remove_table(&info->cpus);
+
+out_free_resources:
+       if (!IS_ERR(proc_reg))
+               regulator_put(proc_reg);
+       if (!IS_ERR(sram_reg))
+               regulator_put(sram_reg);
+       if (!IS_ERR(cpu_clk))
+               clk_put(cpu_clk);
+       if (!IS_ERR(inter_clk))
+               clk_put(inter_clk);
+
+       return ret;
+}
+
+static void mtk_cpu_dvfs_info_release(struct mtk_cpu_dvfs_info *info)
+{
+       if (!IS_ERR(info->proc_reg))
+               regulator_put(info->proc_reg);
+       if (!IS_ERR(info->sram_reg))
+               regulator_put(info->sram_reg);
+       if (!IS_ERR(info->cpu_clk))
+               clk_put(info->cpu_clk);
+       if (!IS_ERR(info->inter_clk))
+               clk_put(info->inter_clk);
+
+       dev_pm_opp_of_cpumask_remove_table(&info->cpus);
+}
+
+static int mtk_cpufreq_init(struct cpufreq_policy *policy)
+{
+       struct mtk_cpu_dvfs_info *info;
+       struct cpufreq_frequency_table *freq_table;
+       int ret;
+
+       info = mtk_cpu_dvfs_info_lookup(policy->cpu);
+       if (!info) {
+               pr_err("dvfs info for cpu%d is not initialized.\n",
+                      policy->cpu);
+               return -EINVAL;
+       }
+
+       ret = dev_pm_opp_init_cpufreq_table(info->cpu_dev, &freq_table);
+       if (ret) {
+               pr_err("failed to init cpufreq table for cpu%d: %d\n",
+                      policy->cpu, ret);
+               return ret;
+       }
+
+       ret = cpufreq_table_validate_and_show(policy, freq_table);
+       if (ret) {
+               pr_err("%s: invalid frequency table: %d\n", __func__, ret);
+               goto out_free_cpufreq_table;
+       }
+
+       cpumask_copy(policy->cpus, &info->cpus);
+       policy->driver_data = info;
+       policy->clk = info->cpu_clk;
+
+       return 0;
+
+out_free_cpufreq_table:
+       dev_pm_opp_free_cpufreq_table(info->cpu_dev, &freq_table);
+       return ret;
+}
+
+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;
+}
+
+static struct cpufreq_driver mtk_cpufreq_driver = {
+       .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK |
+                CPUFREQ_HAVE_GOVERNOR_PER_POLICY,
+       .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,
+};
+
+static int mtk_cpufreq_probe(struct platform_device *pdev)
+{
+       struct mtk_cpu_dvfs_info *info, *tmp;
+       int cpu, ret;
+
+       for_each_possible_cpu(cpu) {
+               info = mtk_cpu_dvfs_info_lookup(cpu);
+               if (info)
+                       continue;
+
+               info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+               if (!info) {
+                       ret = -ENOMEM;
+                       goto release_dvfs_info_list;
+               }
+
+               ret = mtk_cpu_dvfs_info_init(info, cpu);
+               if (ret) {
+                       dev_err(&pdev->dev,
+                               "failed to initialize dvfs info for cpu%d\n",
+                               cpu);
+                       goto release_dvfs_info_list;
+               }
+
+               list_add(&info->list_head, &dvfs_info_list);
+       }
+
+       ret = cpufreq_register_driver(&mtk_cpufreq_driver);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to register mtk cpufreq driver\n");
+               goto release_dvfs_info_list;
+       }
+
+       return 0;
+
+release_dvfs_info_list:
+       list_for_each_entry_safe(info, tmp, &dvfs_info_list, list_head) {
+               mtk_cpu_dvfs_info_release(info);
+               list_del(&info->list_head);
+       }
+
+       return ret;
+}
+
+static struct platform_driver mtk_cpufreq_platdrv = {
+       .driver = {
+               .name   = "mtk-cpufreq",
+       },
+       .probe          = mtk_cpufreq_probe,
+};
+
+/* List of machines supported by this driver */
+static const struct of_device_id mtk_cpufreq_machines[] __initconst = {
+       { .compatible = "mediatek,mt2701", },
+       { .compatible = "mediatek,mt7622", },
+       { .compatible = "mediatek,mt7623", },
+       { .compatible = "mediatek,mt817x", },
+       { .compatible = "mediatek,mt8173", },
+       { .compatible = "mediatek,mt8176", },
+
+       { }
+};
+
+static int __init mtk_cpufreq_driver_init(void)
+{
+       struct device_node *np;
+       const struct of_device_id *match;
+       struct platform_device *pdev;
+       int err;
+
+       np = of_find_node_by_path("/");
+       if (!np)
+               return -ENODEV;
+
+       match = of_match_node(mtk_cpufreq_machines, np);
+       of_node_put(np);
+       if (!match) {
+               pr_warn("Machine is not compatible with mtk-cpufreq\n");
+               return -ENODEV;
+       }
+
+       err = platform_driver_register(&mtk_cpufreq_platdrv);
+       if (err)
+               return err;
+
+       /*
+        * Since there's no place to hold device registration code and no
+        * device tree based way to match cpufreq driver yet, both the driver
+        * and the device registration codes are put here to handle defer
+        * probing.
+        */
+       pdev = platform_device_register_simple("mtk-cpufreq", -1, NULL, 0);
+       if (IS_ERR(pdev)) {
+               pr_err("failed to register mtk-cpufreq platform device\n");
+               return PTR_ERR(pdev);
+       }
+
+       return 0;
+}
+device_initcall(mtk_cpufreq_driver_init);
diff --git a/drivers/cpufreq/mt8173-cpufreq.c b/drivers/cpufreq/mt8173-cpufreq.c
deleted file mode 100644 (file)
index f9f00fb..0000000
+++ /dev/null
@@ -1,619 +0,0 @@
-/*
- * Copyright (c) 2015 Linaro Ltd.
- * Author: Pi-Cheng Chen <pi-cheng.chen@linaro.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#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>
-#include <linux/of.h>
-#include <linux/platform_device.h>
-#include <linux/pm_opp.h>
-#include <linux/regulator/consumer.h>
-#include <linux/slab.h>
-#include <linux/thermal.h>
-
-#define MIN_VOLT_SHIFT         (100000)
-#define MAX_VOLT_SHIFT         (200000)
-#define MAX_VOLT_LIMIT         (1150000)
-#define VOLT_TOL               (10000)
-
-/*
- * The struct mtk_cpu_dvfs_info holds necessary information for doing CPU DVFS
- * on each CPU power/clock domain of Mediatek SoCs. Each CPU cluster in
- * Mediatek SoCs has two voltage inputs, Vproc and Vsram. In some cases the two
- * voltage inputs need to be controlled under a hardware limitation:
- * 100mV < Vsram - Vproc < 200mV
- *
- * When scaling the clock frequency of a CPU clock domain, the clock source
- * needs to be switched to another stable PLL clock temporarily until
- * the original PLL becomes stable at target frequency.
- */
-struct mtk_cpu_dvfs_info {
-       struct cpumask cpus;
-       struct device *cpu_dev;
-       struct regulator *proc_reg;
-       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;
-};
-
-static LIST_HEAD(dvfs_info_list);
-
-static struct mtk_cpu_dvfs_info *mtk_cpu_dvfs_info_lookup(int cpu)
-{
-       struct mtk_cpu_dvfs_info *info;
-
-       list_for_each_entry(info, &dvfs_info_list, list_head) {
-               if (cpumask_test_cpu(cpu, &info->cpus))
-                       return info;
-       }
-
-       return NULL;
-}
-
-static int mtk_cpufreq_voltage_tracking(struct mtk_cpu_dvfs_info *info,
-                                       int new_vproc)
-{
-       struct regulator *proc_reg = info->proc_reg;
-       struct regulator *sram_reg = info->sram_reg;
-       int old_vproc, old_vsram, new_vsram, vsram, vproc, ret;
-
-       old_vproc = regulator_get_voltage(proc_reg);
-       if (old_vproc < 0) {
-               pr_err("%s: invalid Vproc value: %d\n", __func__, old_vproc);
-               return old_vproc;
-       }
-       /* Vsram should not exceed the maximum allowed voltage of SoC. */
-       new_vsram = min(new_vproc + MIN_VOLT_SHIFT, MAX_VOLT_LIMIT);
-
-       if (old_vproc < new_vproc) {
-               /*
-                * When scaling up voltages, Vsram and Vproc scale up step
-                * by step. At each step, set Vsram to (Vproc + 200mV) first,
-                * then set Vproc to (Vsram - 100mV).
-                * Keep doing it until Vsram and Vproc hit target voltages.
-                */
-               do {
-                       old_vsram = regulator_get_voltage(sram_reg);
-                       if (old_vsram < 0) {
-                               pr_err("%s: invalid Vsram value: %d\n",
-                                      __func__, old_vsram);
-                               return old_vsram;
-                       }
-                       old_vproc = regulator_get_voltage(proc_reg);
-                       if (old_vproc < 0) {
-                               pr_err("%s: invalid Vproc value: %d\n",
-                                      __func__, old_vproc);
-                               return old_vproc;
-                       }
-
-                       vsram = min(new_vsram, old_vproc + MAX_VOLT_SHIFT);
-
-                       if (vsram + VOLT_TOL >= MAX_VOLT_LIMIT) {
-                               vsram = MAX_VOLT_LIMIT;
-
-                               /*
-                                * If the target Vsram hits the maximum voltage,
-                                * try to set the exact voltage value first.
-                                */
-                               ret = regulator_set_voltage(sram_reg, vsram,
-                                                           vsram);
-                               if (ret)
-                                       ret = regulator_set_voltage(sram_reg,
-                                                       vsram - VOLT_TOL,
-                                                       vsram);
-
-                               vproc = new_vproc;
-                       } else {
-                               ret = regulator_set_voltage(sram_reg, vsram,
-                                                           vsram + VOLT_TOL);
-
-                               vproc = vsram - MIN_VOLT_SHIFT;
-                       }
-                       if (ret)
-                               return ret;
-
-                       ret = regulator_set_voltage(proc_reg, vproc,
-                                                   vproc + VOLT_TOL);
-                       if (ret) {
-                               regulator_set_voltage(sram_reg, old_vsram,
-                                                     old_vsram);
-                               return ret;
-                       }
-               } while (vproc < new_vproc || vsram < new_vsram);
-       } else if (old_vproc > new_vproc) {
-               /*
-                * When scaling down voltages, Vsram and Vproc scale down step
-                * by step. At each step, set Vproc to (Vsram - 200mV) first,
-                * then set Vproc to (Vproc + 100mV).
-                * Keep doing it until Vsram and Vproc hit target voltages.
-                */
-               do {
-                       old_vproc = regulator_get_voltage(proc_reg);
-                       if (old_vproc < 0) {
-                               pr_err("%s: invalid Vproc value: %d\n",
-                                      __func__, old_vproc);
-                               return old_vproc;
-                       }
-                       old_vsram = regulator_get_voltage(sram_reg);
-                       if (old_vsram < 0) {
-                               pr_err("%s: invalid Vsram value: %d\n",
-                                      __func__, old_vsram);
-                               return old_vsram;
-                       }
-
-                       vproc = max(new_vproc, old_vsram - MAX_VOLT_SHIFT);
-                       ret = regulator_set_voltage(proc_reg, vproc,
-                                                   vproc + VOLT_TOL);
-                       if (ret)
-                               return ret;
-
-                       if (vproc == new_vproc)
-                               vsram = new_vsram;
-                       else
-                               vsram = max(new_vsram, vproc + MIN_VOLT_SHIFT);
-
-                       if (vsram + VOLT_TOL >= MAX_VOLT_LIMIT) {
-                               vsram = MAX_VOLT_LIMIT;
-
-                               /*
-                                * If the target Vsram hits the maximum voltage,
-                                * try to set the exact voltage value first.
-                                */
-                               ret = regulator_set_voltage(sram_reg, vsram,
-                                                           vsram);
-                               if (ret)
-                                       ret = regulator_set_voltage(sram_reg,
-                                                       vsram - VOLT_TOL,
-                                                       vsram);
-                       } else {
-                               ret = regulator_set_voltage(sram_reg, vsram,
-                                                           vsram + VOLT_TOL);
-                       }
-
-                       if (ret) {
-                               regulator_set_voltage(proc_reg, old_vproc,
-                                                     old_vproc);
-                               return ret;
-                       }
-               } while (vproc > new_vproc + VOLT_TOL ||
-                        vsram > new_vsram + VOLT_TOL);
-       }
-
-       return 0;
-}
-
-static int mtk_cpufreq_set_voltage(struct mtk_cpu_dvfs_info *info, int vproc)
-{
-       if (info->need_voltage_tracking)
-               return mtk_cpufreq_voltage_tracking(info, vproc);
-       else
-               return regulator_set_voltage(info->proc_reg, vproc,
-                                            vproc + VOLT_TOL);
-}
-
-static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
-                                 unsigned int index)
-{
-       struct cpufreq_frequency_table *freq_table = policy->freq_table;
-       struct clk *cpu_clk = policy->clk;
-       struct clk *armpll = clk_get_parent(cpu_clk);
-       struct mtk_cpu_dvfs_info *info = policy->driver_data;
-       struct device *cpu_dev = info->cpu_dev;
-       struct dev_pm_opp *opp;
-       long freq_hz, old_freq_hz;
-       int vproc, old_vproc, inter_vproc, target_vproc, ret;
-
-       inter_vproc = info->intermediate_voltage;
-
-       old_freq_hz = clk_get_rate(cpu_clk);
-       old_vproc = regulator_get_voltage(info->proc_reg);
-       if (old_vproc < 0) {
-               pr_err("%s: invalid Vproc value: %d\n", __func__, old_vproc);
-               return old_vproc;
-       }
-
-       freq_hz = freq_table[index].frequency * 1000;
-
-       opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz);
-       if (IS_ERR(opp)) {
-               pr_err("cpu%d: failed to find OPP for %ld\n",
-                      policy->cpu, freq_hz);
-               return PTR_ERR(opp);
-       }
-       vproc = dev_pm_opp_get_voltage(opp);
-       dev_pm_opp_put(opp);
-
-       /*
-        * If the new voltage or the intermediate voltage is higher than the
-        * current voltage, scale up voltage first.
-        */
-       target_vproc = (inter_vproc > vproc) ? inter_vproc : vproc;
-       if (old_vproc < target_vproc) {
-               ret = mtk_cpufreq_set_voltage(info, target_vproc);
-               if (ret) {
-                       pr_err("cpu%d: failed to scale up voltage!\n",
-                              policy->cpu);
-                       mtk_cpufreq_set_voltage(info, old_vproc);
-                       return ret;
-               }
-       }
-
-       /* Reparent the CPU clock to intermediate clock. */
-       ret = clk_set_parent(cpu_clk, info->inter_clk);
-       if (ret) {
-               pr_err("cpu%d: failed to re-parent cpu clock!\n",
-                      policy->cpu);
-               mtk_cpufreq_set_voltage(info, old_vproc);
-               WARN_ON(1);
-               return ret;
-       }
-
-       /* Set the original PLL to target rate. */
-       ret = clk_set_rate(armpll, freq_hz);
-       if (ret) {
-               pr_err("cpu%d: failed to scale cpu clock rate!\n",
-                      policy->cpu);
-               clk_set_parent(cpu_clk, armpll);
-               mtk_cpufreq_set_voltage(info, old_vproc);
-               return ret;
-       }
-
-       /* Set parent of CPU clock back to the original PLL. */
-       ret = clk_set_parent(cpu_clk, armpll);
-       if (ret) {
-               pr_err("cpu%d: failed to re-parent cpu clock!\n",
-                      policy->cpu);
-               mtk_cpufreq_set_voltage(info, inter_vproc);
-               WARN_ON(1);
-               return ret;
-       }
-
-       /*
-        * If the new voltage is lower than the intermediate voltage or the
-        * original voltage, scale down to the new voltage.
-        */
-       if (vproc < inter_vproc || vproc < old_vproc) {
-               ret = mtk_cpufreq_set_voltage(info, vproc);
-               if (ret) {
-                       pr_err("cpu%d: failed to scale down voltage!\n",
-                              policy->cpu);
-                       clk_set_parent(cpu_clk, info->inter_clk);
-                       clk_set_rate(armpll, old_freq_hz);
-                       clk_set_parent(cpu_clk, armpll);
-                       return ret;
-               }
-       }
-
-       return 0;
-}
-
-#define DYNAMIC_POWER "dynamic-power-coefficient"
-
-static void mtk_cpufreq_ready(struct cpufreq_policy *policy)
-{
-       struct mtk_cpu_dvfs_info *info = policy->driver_data;
-       struct device_node *np = of_node_get(info->cpu_dev->of_node);
-       u32 capacitance = 0;
-
-       if (WARN_ON(!np))
-               return;
-
-       if (of_find_property(np, "#cooling-cells", NULL)) {
-               of_property_read_u32(np, DYNAMIC_POWER, &capacitance);
-
-               info->cdev = of_cpufreq_power_cooling_register(np,
-                                               policy, capacitance, NULL);
-
-               if (IS_ERR(info->cdev)) {
-                       dev_err(info->cpu_dev,
-                               "running cpufreq without cooling device: %ld\n",
-                               PTR_ERR(info->cdev));
-
-                       info->cdev = NULL;
-               }
-       }
-
-       of_node_put(np);
-}
-
-static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
-{
-       struct device *cpu_dev;
-       struct regulator *proc_reg = ERR_PTR(-ENODEV);
-       struct regulator *sram_reg = ERR_PTR(-ENODEV);
-       struct clk *cpu_clk = ERR_PTR(-ENODEV);
-       struct clk *inter_clk = ERR_PTR(-ENODEV);
-       struct dev_pm_opp *opp;
-       unsigned long rate;
-       int ret;
-
-       cpu_dev = get_cpu_device(cpu);
-       if (!cpu_dev) {
-               pr_err("failed to get cpu%d device\n", cpu);
-               return -ENODEV;
-       }
-
-       cpu_clk = clk_get(cpu_dev, "cpu");
-       if (IS_ERR(cpu_clk)) {
-               if (PTR_ERR(cpu_clk) == -EPROBE_DEFER)
-                       pr_warn("cpu clk for cpu%d not ready, retry.\n", cpu);
-               else
-                       pr_err("failed to get cpu clk for cpu%d\n", cpu);
-
-               ret = PTR_ERR(cpu_clk);
-               return ret;
-       }
-
-       inter_clk = clk_get(cpu_dev, "intermediate");
-       if (IS_ERR(inter_clk)) {
-               if (PTR_ERR(inter_clk) == -EPROBE_DEFER)
-                       pr_warn("intermediate clk for cpu%d not ready, retry.\n",
-                               cpu);
-               else
-                       pr_err("failed to get intermediate clk for cpu%d\n",
-                              cpu);
-
-               ret = PTR_ERR(inter_clk);
-               goto out_free_resources;
-       }
-
-       proc_reg = regulator_get_exclusive(cpu_dev, "proc");
-       if (IS_ERR(proc_reg)) {
-               if (PTR_ERR(proc_reg) == -EPROBE_DEFER)
-                       pr_warn("proc regulator for cpu%d not ready, retry.\n",
-                               cpu);
-               else
-                       pr_err("failed to get proc regulator for cpu%d\n",
-                              cpu);
-
-               ret = PTR_ERR(proc_reg);
-               goto out_free_resources;
-       }
-
-       /* Both presence and absence of sram regulator are valid cases. */
-       sram_reg = regulator_get_exclusive(cpu_dev, "sram");
-
-       /* Get OPP-sharing information from "operating-points-v2" bindings */
-       ret = dev_pm_opp_of_get_sharing_cpus(cpu_dev, &info->cpus);
-       if (ret) {
-               pr_err("failed to get OPP-sharing information for cpu%d\n",
-                      cpu);
-               goto out_free_resources;
-       }
-
-       ret = dev_pm_opp_of_cpumask_add_table(&info->cpus);
-       if (ret) {
-               pr_warn("no OPP table for cpu%d\n", cpu);
-               goto out_free_resources;
-       }
-
-       /* Search a safe voltage for intermediate frequency. */
-       rate = clk_get_rate(inter_clk);
-       opp = dev_pm_opp_find_freq_ceil(cpu_dev, &rate);
-       if (IS_ERR(opp)) {
-               pr_err("failed to get intermediate opp for cpu%d\n", cpu);
-               ret = PTR_ERR(opp);
-               goto out_free_opp_table;
-       }
-       info->intermediate_voltage = dev_pm_opp_get_voltage(opp);
-       dev_pm_opp_put(opp);
-
-       info->cpu_dev = cpu_dev;
-       info->proc_reg = proc_reg;
-       info->sram_reg = IS_ERR(sram_reg) ? NULL : sram_reg;
-       info->cpu_clk = cpu_clk;
-       info->inter_clk = inter_clk;
-
-       /*
-        * If SRAM regulator is present, software "voltage tracking" is needed
-        * for this CPU power domain.
-        */
-       info->need_voltage_tracking = !IS_ERR(sram_reg);
-
-       return 0;
-
-out_free_opp_table:
-       dev_pm_opp_of_cpumask_remove_table(&info->cpus);
-
-out_free_resources:
-       if (!IS_ERR(proc_reg))
-               regulator_put(proc_reg);
-       if (!IS_ERR(sram_reg))
-               regulator_put(sram_reg);
-       if (!IS_ERR(cpu_clk))
-               clk_put(cpu_clk);
-       if (!IS_ERR(inter_clk))
-               clk_put(inter_clk);
-
-       return ret;
-}
-
-static void mtk_cpu_dvfs_info_release(struct mtk_cpu_dvfs_info *info)
-{
-       if (!IS_ERR(info->proc_reg))
-               regulator_put(info->proc_reg);
-       if (!IS_ERR(info->sram_reg))
-               regulator_put(info->sram_reg);
-       if (!IS_ERR(info->cpu_clk))
-               clk_put(info->cpu_clk);
-       if (!IS_ERR(info->inter_clk))
-               clk_put(info->inter_clk);
-
-       dev_pm_opp_of_cpumask_remove_table(&info->cpus);
-}
-
-static int mtk_cpufreq_init(struct cpufreq_policy *policy)
-{
-       struct mtk_cpu_dvfs_info *info;
-       struct cpufreq_frequency_table *freq_table;
-       int ret;
-
-       info = mtk_cpu_dvfs_info_lookup(policy->cpu);
-       if (!info) {
-               pr_err("dvfs info for cpu%d is not initialized.\n",
-                      policy->cpu);
-               return -EINVAL;
-       }
-
-       ret = dev_pm_opp_init_cpufreq_table(info->cpu_dev, &freq_table);
-       if (ret) {
-               pr_err("failed to init cpufreq table for cpu%d: %d\n",
-                      policy->cpu, ret);
-               return ret;
-       }
-
-       ret = cpufreq_table_validate_and_show(policy, freq_table);
-       if (ret) {
-               pr_err("%s: invalid frequency table: %d\n", __func__, ret);
-               goto out_free_cpufreq_table;
-       }
-
-       cpumask_copy(policy->cpus, &info->cpus);
-       policy->driver_data = info;
-       policy->clk = info->cpu_clk;
-
-       return 0;
-
-out_free_cpufreq_table:
-       dev_pm_opp_free_cpufreq_table(info->cpu_dev, &freq_table);
-       return ret;
-}
-
-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;
-}
-
-static struct cpufreq_driver mt8173_cpufreq_driver = {
-       .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK |
-                CPUFREQ_HAVE_GOVERNOR_PER_POLICY,
-       .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,
-};
-
-static int mt8173_cpufreq_probe(struct platform_device *pdev)
-{
-       struct mtk_cpu_dvfs_info *info, *tmp;
-       int cpu, ret;
-
-       for_each_possible_cpu(cpu) {
-               info = mtk_cpu_dvfs_info_lookup(cpu);
-               if (info)
-                       continue;
-
-               info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
-               if (!info) {
-                       ret = -ENOMEM;
-                       goto release_dvfs_info_list;
-               }
-
-               ret = mtk_cpu_dvfs_info_init(info, cpu);
-               if (ret) {
-                       dev_err(&pdev->dev,
-                               "failed to initialize dvfs info for cpu%d\n",
-                               cpu);
-                       goto release_dvfs_info_list;
-               }
-
-               list_add(&info->list_head, &dvfs_info_list);
-       }
-
-       ret = cpufreq_register_driver(&mt8173_cpufreq_driver);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to register mtk cpufreq driver\n");
-               goto release_dvfs_info_list;
-       }
-
-       return 0;
-
-release_dvfs_info_list:
-       list_for_each_entry_safe(info, tmp, &dvfs_info_list, list_head) {
-               mtk_cpu_dvfs_info_release(info);
-               list_del(&info->list_head);
-       }
-
-       return ret;
-}
-
-static struct platform_driver mt8173_cpufreq_platdrv = {
-       .driver = {
-               .name   = "mt8173-cpufreq",
-       },
-       .probe          = mt8173_cpufreq_probe,
-};
-
-/* List of machines supported by this driver */
-static const struct of_device_id mt8173_cpufreq_machines[] __initconst = {
-       { .compatible = "mediatek,mt817x", },
-       { .compatible = "mediatek,mt8173", },
-       { .compatible = "mediatek,mt8176", },
-
-       { }
-};
-
-static int __init mt8173_cpufreq_driver_init(void)
-{
-       struct device_node *np;
-       const struct of_device_id *match;
-       struct platform_device *pdev;
-       int err;
-
-       np = of_find_node_by_path("/");
-       if (!np)
-               return -ENODEV;
-
-       match = of_match_node(mt8173_cpufreq_machines, np);
-       of_node_put(np);
-       if (!match) {
-               pr_warn("Machine is not compatible with mt8173-cpufreq\n");
-               return -ENODEV;
-       }
-
-       err = platform_driver_register(&mt8173_cpufreq_platdrv);
-       if (err)
-               return err;
-
-       /*
-        * Since there's no place to hold device registration code and no
-        * device tree based way to match cpufreq driver yet, both the driver
-        * and the device registration codes are put here to handle defer
-        * probing.
-        */
-       pdev = platform_device_register_simple("mt8173-cpufreq", -1, NULL, 0);
-       if (IS_ERR(pdev)) {
-               pr_err("failed to register mtk-cpufreq platform device\n");
-               return PTR_ERR(pdev);
-       }
-
-       return 0;
-}
-device_initcall(mt8173_cpufreq_driver_init);
index ff44016ea0312e4b6c50ff1d9f0126f2d63dcddc..61ae06ca008e746ac7d166f502ac212ab86148fc 100644 (file)
@@ -442,7 +442,8 @@ static struct cpufreq_driver pmac_cpufreq_driver = {
        .init           = pmac_cpufreq_cpu_init,
        .suspend        = pmac_cpufreq_suspend,
        .resume         = pmac_cpufreq_resume,
-       .flags          = CPUFREQ_PM_NO_WARN,
+       .flags          = CPUFREQ_PM_NO_WARN |
+                         CPUFREQ_NO_AUTO_DYNAMIC_SWITCHING,
        .attr           = cpufreq_generic_attr,
        .name           = "powermac",
 };
@@ -626,14 +627,16 @@ static int __init pmac_cpufreq_setup(void)
        if (!value)
                goto out;
        cur_freq = (*value) / 1000;
-       transition_latency = CPUFREQ_ETERNAL;
 
        /*  Check for 7447A based MacRISC3 */
        if (of_machine_is_compatible("MacRISC3") &&
            of_get_property(cpunode, "dynamic-power-step", NULL) &&
            PVR_VER(mfspr(SPRN_PVR)) == 0x8003) {
                pmac_cpufreq_init_7447A(cpunode);
+
+               /* Allow dynamic switching */
                transition_latency = 8000000;
+               pmac_cpufreq_driver.flags &= ~CPUFREQ_NO_AUTO_DYNAMIC_SWITCHING;
        /* Check for other MacRISC3 machines */
        } else if (of_machine_is_compatible("PowerBook3,4") ||
                   of_machine_is_compatible("PowerBook3,5") ||
index 267e0894c62d08643d1cf34bef94fd54c95daeb8..be623dd7b9f2a38bdd814391439a393f7137e836 100644 (file)
@@ -516,7 +516,7 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpunode)
                goto bail;
        }
 
-       DBG("cpufreq: i2c clock chip found: %s\n", hwclock->full_name);
+       DBG("cpufreq: i2c clock chip found: %pOF\n", hwclock);
 
        /* Now get all the platform functions */
        pfunc_cpu_getfreq =
index f82074eea779ca40684cf98e8ab29a33b05f13b9..5d31c2db12a3f31b25d43be5eb73056a59d7415b 100644 (file)
@@ -602,6 +602,7 @@ static int s5pv210_cpufreq_probe(struct platform_device *pdev)
        }
 
        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;
@@ -612,6 +613,7 @@ static int s5pv210_cpufreq_probe(struct platform_device *pdev)
                if (id < 0 || id >= ARRAY_SIZE(dmc_base)) {
                        pr_err("%s: failed to get alias of dmc node '%s'\n",
                                __func__, np->name);
+                       of_node_put(np);
                        return id;
                }
 
@@ -619,6 +621,7 @@ static int s5pv210_cpufreq_probe(struct platform_device *pdev)
                if (!dmc_base[id]) {
                        pr_err("%s: failed to map dmc%d registers\n",
                                __func__, id);
+                       of_node_put(np);
                        return -EFAULT;
                }
        }
index 728eab77e8e080457bca09f1ad8d7e69d936e6d1..e2d8a77c36d5824dda438e2800c46e2afc58b0c7 100644 (file)
@@ -197,11 +197,12 @@ static int sa1100_target(struct cpufreq_policy *policy, unsigned int ppcr)
 
 static int __init sa1100_cpu_init(struct cpufreq_policy *policy)
 {
-       return cpufreq_generic_init(policy, sa11x0_freq_table, CPUFREQ_ETERNAL);
+       return cpufreq_generic_init(policy, sa11x0_freq_table, 0);
 }
 
 static struct cpufreq_driver sa1100_driver __refdata = {
-       .flags          = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK,
+       .flags          = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK |
+                         CPUFREQ_NO_AUTO_DYNAMIC_SWITCHING,
        .verify         = cpufreq_generic_frequency_table_verify,
        .target_index   = sa1100_target,
        .get            = sa11x0_getspeed,
index 2bac9b6cfeea3b905ca99e171f5f60012f9a9363..66e5fb088ecca76c6d62065ea11a15ce01d488db 100644 (file)
@@ -306,13 +306,14 @@ static int sa1110_target(struct cpufreq_policy *policy, unsigned int ppcr)
 
 static int __init sa1110_cpu_init(struct cpufreq_policy *policy)
 {
-       return cpufreq_generic_init(policy, sa11x0_freq_table, CPUFREQ_ETERNAL);
+       return cpufreq_generic_init(policy, sa11x0_freq_table, 0);
 }
 
 /* sa1110_driver needs __refdata because it must remain after init registers
  * it with cpufreq_register_driver() */
 static struct cpufreq_driver sa1110_driver __refdata = {
-       .flags          = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK,
+       .flags          = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK |
+                         CPUFREQ_NO_AUTO_DYNAMIC_SWITCHING,
        .verify         = cpufreq_generic_frequency_table_verify,
        .target_index   = sa1110_target,
        .get            = sa11x0_getspeed,
index 719c3d9f07fb1adbb0e4e528d00c3f49bb39be33..28893d435cf56b940143bb169193b3bb3f1506a4 100644 (file)
@@ -137,8 +137,6 @@ static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy)
                        (clk_round_rate(cpuclk, ~0UL) + 500) / 1000;
        }
 
-       policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
-
        dev_info(dev, "CPU Frequencies - Minimum %u.%03u MHz, "
               "Maximum %u.%03u MHz.\n",
               policy->min / 1000, policy->min % 1000,
@@ -159,6 +157,7 @@ static int sh_cpufreq_cpu_exit(struct cpufreq_policy *policy)
 
 static struct cpufreq_driver sh_cpufreq_driver = {
        .name           = "sh",
+       .flags          = CPUFREQ_NO_AUTO_DYNAMIC_SWITCHING,
        .get            = sh_cpufreq_get,
        .target         = sh_cpufreq_target,
        .verify         = sh_cpufreq_verify,
index b86953a3ddc4aea6e9bedecdd23766c975f87364..0412a246a785bc8b6d14e3e5408994afe87cf552 100644 (file)
@@ -207,7 +207,7 @@ static unsigned int speedstep_detect_chipset(void)
                 * 8100 which use a pretty old revision of the 82815
                 * host bridge. Abort on these systems.
                 */
-               static struct pci_dev *hostbridge;
+               struct pci_dev *hostbridge;
 
                hostbridge  = pci_get_subsys(PCI_VENDOR_ID_INTEL,
                              PCI_DEVICE_ID_INTEL_82815_MC,
index 1b8062182c813b359200070306a228d0c0cef18b..ccab452a4ef5b739cd8294cfa3197211afa9afb8 100644 (file)
@@ -35,7 +35,7 @@ static int relaxed_check;
 static unsigned int pentium3_get_frequency(enum speedstep_processor processor)
 {
        /* See table 14 of p3_ds.pdf and table 22 of 29834003.pdf */
-       struct {
+       static const struct {
                unsigned int ratio;     /* Frequency Multiplier (x10) */
                u8 bitmap;              /* power on configuration bits
                                        [27, 25:22] (in MSR 0x2a) */
@@ -58,7 +58,7 @@ static unsigned int pentium3_get_frequency(enum speedstep_processor processor)
        };
 
        /* PIII(-M) FSB settings: see table b1-b of 24547206.pdf */
-       struct {
+       static const struct {
                unsigned int value;     /* Front Side Bus speed in MHz */
                u8 bitmap;              /* power on configuration bits [18: 19]
                                        (in MSR 0x2a) */
index 37b30071c220e456c72985bf50147c12f2edcc67..d23f24ccff38ef59dbb23880bf2492be4acb300c 100644 (file)
@@ -266,7 +266,6 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
                        pr_debug("workaround worked.\n");
        }
 
-       policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
        return cpufreq_table_validate_and_show(policy, speedstep_freqs);
 }
 
@@ -290,6 +289,7 @@ static int speedstep_resume(struct cpufreq_policy *policy)
 
 static struct cpufreq_driver speedstep_driver = {
        .name           = "speedstep-smi",
+       .flags          = CPUFREQ_NO_AUTO_DYNAMIC_SWITCHING,
        .verify         = cpufreq_generic_frequency_table_verify,
        .target_index   = speedstep_target,
        .init           = speedstep_cpu_init,
index d2d0430d09d4ddcaa3626319741cdb3ef66ef3aa..47105735df12651dcad502aff80f069ca9f447be 100644 (file)
@@ -65,8 +65,8 @@ static int sti_cpufreq_fetch_major(void) {
        ret = of_property_read_u32_index(np, "st,syscfg",
                                         MAJOR_ID_INDEX, &major_offset);
        if (ret) {
-               dev_err(dev, "No major number offset provided in %s [%d]\n",
-                       np->full_name, ret);
+               dev_err(dev, "No major number offset provided in %pOF [%d]\n",
+                       np, ret);
                return ret;
        }
 
@@ -92,8 +92,8 @@ static int sti_cpufreq_fetch_minor(void)
                                         MINOR_ID_INDEX, &minor_offset);
        if (ret) {
                dev_err(dev,
-                       "No minor number offset provided %s [%d]\n",
-                       np->full_name, ret);
+                       "No minor number offset provided %pOF [%d]\n",
+                       np, ret);
                return ret;
        }
 
diff --git a/drivers/cpufreq/tango-cpufreq.c b/drivers/cpufreq/tango-cpufreq.c
new file mode 100644 (file)
index 0000000..89a7f86
--- /dev/null
@@ -0,0 +1,38 @@
+#include <linux/of.h>
+#include <linux/cpu.h>
+#include <linux/clk.h>
+#include <linux/pm_opp.h>
+#include <linux/platform_device.h>
+
+static const struct of_device_id machines[] __initconst = {
+       { .compatible = "sigma,tango4" },
+       { /* sentinel */ }
+};
+
+static int __init tango_cpufreq_init(void)
+{
+       struct device *cpu_dev = get_cpu_device(0);
+       unsigned long max_freq;
+       struct clk *cpu_clk;
+       void *res;
+
+       if (!of_match_node(machines, of_root))
+               return -ENODEV;
+
+       cpu_clk = clk_get(cpu_dev, NULL);
+       if (IS_ERR(cpu_clk))
+               return -ENODEV;
+
+       max_freq = clk_get_rate(cpu_clk);
+
+       dev_pm_opp_add(cpu_dev, max_freq / 1, 0);
+       dev_pm_opp_add(cpu_dev, max_freq / 2, 0);
+       dev_pm_opp_add(cpu_dev, max_freq / 3, 0);
+       dev_pm_opp_add(cpu_dev, max_freq / 5, 0);
+       dev_pm_opp_add(cpu_dev, max_freq / 9, 0);
+
+       res = platform_device_register_data(NULL, "cpufreq-dt", -1, NULL, 0);
+
+       return PTR_ERR_OR_ZERO(res);
+}
+device_initcall(tango_cpufreq_init);
index a7b5658c04609dc57d66a4049af55a25e157ee02..b29cd339846302402dcee8333765ad670555a2b3 100644 (file)
@@ -245,8 +245,6 @@ static int ti_cpufreq_init(void)
        if (ret)
                goto fail_put_node;
 
-       of_node_put(opp_data->opp_node);
-
        ret = PTR_ERR_OR_ZERO(dev_pm_opp_set_supported_hw(opp_data->cpu_dev,
                                                          version, VERSION_COUNT));
        if (ret) {
@@ -255,6 +253,8 @@ static int ti_cpufreq_init(void)
                goto fail_put_node;
        }
 
+       of_node_put(opp_data->opp_node);
+
 register_cpufreq_dt:
        platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
 
index 6f9dfa80563a344249ef153aa4f92b17b35ce158..db62d984475132f0f9abb24a0dfd1db2e405e7e6 100644 (file)
@@ -58,13 +58,12 @@ static int __init ucv2_cpu_init(struct cpufreq_policy *policy)
 
        policy->min = policy->cpuinfo.min_freq = 250000;
        policy->max = policy->cpuinfo.max_freq = 1000000;
-       policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
        policy->clk = clk_get(NULL, "MAIN_CLK");
        return PTR_ERR_OR_ZERO(policy->clk);
 }
 
 static struct cpufreq_driver ucv2_driver = {
-       .flags          = CPUFREQ_STICKY,
+       .flags          = CPUFREQ_STICKY | CPUFREQ_NO_AUTO_DYNAMIC_SWITCHING,
        .verify         = ucv2_verify_speed,
        .target         = ucv2_target,
        .get            = cpufreq_generic_get,
index 5c739ac752e820fc2b652649bcfe7384a202e749..5970b8def5487ea3b7f40296d7da61824905df0e 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/mfd/abx500/ab8500.h>
 #include <linux/regulator/db8500-prcmu.h>
 #include <linux/regulator/machine.h>
-#include <linux/cpufreq.h>
 #include <linux/platform_data/ux500_wdt.h>
 #include <linux/platform_data/db8500_thermal.h>
 #include "dbx500-prcmu-regs.h"
@@ -1692,32 +1691,27 @@ static long round_clock_rate(u8 clock, unsigned long rate)
        return rounded_rate;
 }
 
-/* CPU FREQ table, may be changed due to if MAX_OPP is supported. */
-static struct cpufreq_frequency_table db8500_cpufreq_table[] = {
-       { .frequency = 200000, .driver_data = ARM_EXTCLK,},
-       { .frequency = 400000, .driver_data = ARM_50_OPP,},
-       { .frequency = 800000, .driver_data = ARM_100_OPP,},
-       { .frequency = CPUFREQ_TABLE_END,}, /* To be used for MAX_OPP. */
-       { .frequency = CPUFREQ_TABLE_END,},
+static const unsigned long armss_freqs[] = {
+       200000000,
+       400000000,
+       800000000,
+       998400000
 };
 
 static long round_armss_rate(unsigned long rate)
 {
-       struct cpufreq_frequency_table *pos;
-       long freq = 0;
-
-       /* cpufreq table frequencies is in KHz. */
-       rate = rate / 1000;
+       unsigned long freq = 0;
+       int i;
 
        /* Find the corresponding arm opp from the cpufreq table. */
-       cpufreq_for_each_entry(pos, db8500_cpufreq_table) {
-               freq = pos->frequency;
-               if (freq == rate)
+       for (i = 0; i < ARRAY_SIZE(armss_freqs); i++) {
+               freq = armss_freqs[i];
+               if (rate <= freq)
                        break;
        }
 
        /* Return the last valid value, even if a match was not found. */
-       return freq * 1000;
+       return freq;
 }
 
 #define MIN_PLL_VCO_RATE 600000000ULL
@@ -1854,21 +1848,23 @@ static void set_clock_rate(u8 clock, unsigned long rate)
 
 static int set_armss_rate(unsigned long rate)
 {
-       struct cpufreq_frequency_table *pos;
-
-       /* cpufreq table frequencies is in KHz. */
-       rate = rate / 1000;
+       unsigned long freq;
+       u8 opps[] = { ARM_EXTCLK, ARM_50_OPP, ARM_100_OPP, ARM_MAX_OPP };
+       int i;
 
        /* Find the corresponding arm opp from the cpufreq table. */
-       cpufreq_for_each_entry(pos, db8500_cpufreq_table)
-               if (pos->frequency == rate)
+       for (i = 0; i < ARRAY_SIZE(armss_freqs); i++) {
+               freq = armss_freqs[i];
+               if (rate == freq)
                        break;
+       }
 
-       if (pos->frequency != rate)
+       if (rate != freq)
                return -EINVAL;
 
        /* Set the new arm opp. */
-       return db8500_prcmu_set_arm_opp(pos->driver_data);
+       pr_debug("SET ARM OPP 0x%02x\n", opps[i]);
+       return db8500_prcmu_set_arm_opp(opps[i]);
 }
 
 static int set_plldsi_rate(unsigned long rate)
@@ -3048,12 +3044,6 @@ static const struct mfd_cell db8500_prcmu_devs[] = {
                .platform_data = &db8500_regulators,
                .pdata_size = sizeof(db8500_regulators),
        },
-       {
-               .name = "cpufreq-ux500",
-               .of_compatible = "stericsson,cpufreq-ux500",
-               .platform_data = &db8500_cpufreq_table,
-               .pdata_size = sizeof(db8500_cpufreq_table),
-       },
        {
                .name = "cpuidle-dbx500",
                .of_compatible = "stericsson,cpuidle-dbx500",
@@ -3067,14 +3057,6 @@ static const struct mfd_cell db8500_prcmu_devs[] = {
        },
 };
 
-static void db8500_prcmu_update_cpufreq(void)
-{
-       if (prcmu_has_arm_maxopp()) {
-               db8500_cpufreq_table[3].frequency = 1000000;
-               db8500_cpufreq_table[3].driver_data = ARM_MAX_OPP;
-       }
-}
-
 static int db8500_prcmu_register_ab8500(struct device *parent)
 {
        struct device_node *np;
@@ -3160,8 +3142,6 @@ static int db8500_prcmu_probe(struct platform_device *pdev)
 
        prcmu_config_esram0_deep_sleep(ESRAM0_DEEP_SLEEP_STATE_RET);
 
-       db8500_prcmu_update_cpufreq();
-
        err = mfd_add_devices(&pdev->dev, 0, common_prcmu_devs,
                              ARRAY_SIZE(common_prcmu_devs), NULL, 0, db8500_irq_domain);
        if (err) {
index f10a9b3761cdbef777c38a131cc1cb1e4aec0c1e..5f40522ec98cbe12a2eca27d08812e6487342df2 100644 (file)
@@ -370,6 +370,12 @@ struct cpufreq_driver {
  */
 #define CPUFREQ_NEED_INITIAL_FREQ_CHECK        (1 << 5)
 
+/*
+ * Set by drivers to disallow use of governors with "dynamic_switching" flag
+ * set.
+ */
+#define CPUFREQ_NO_AUTO_DYNAMIC_SWITCHING (1 << 6)
+
 int cpufreq_register_driver(struct cpufreq_driver *driver_data);
 int cpufreq_unregister_driver(struct cpufreq_driver *driver_data);
 
@@ -487,14 +493,8 @@ static inline unsigned long cpufreq_scale(unsigned long old, u_int div,
  * polling frequency is 1000 times the transition latency of the processor. The
  * ondemand governor will work on any processor with transition latency <= 10ms,
  * using appropriate sampling rate.
- *
- * For CPUs with transition latency > 10ms (mostly drivers with CPUFREQ_ETERNAL)
- * the ondemand governor will not work. All times here are in us (microseconds).
  */
-#define MIN_SAMPLING_RATE_RATIO                (2)
 #define LATENCY_MULTIPLIER             (1000)
-#define MIN_LATENCY_MULTIPLIER         (20)
-#define TRANSITION_LATENCY_LIMIT       (10 * 1000 * 1000)
 
 struct cpufreq_governor {
        char    name[CPUFREQ_NAME_LEN];
@@ -507,9 +507,8 @@ struct cpufreq_governor {
                                         char *buf);
        int     (*store_setspeed)       (struct cpufreq_policy *policy,
                                         unsigned int freq);
-       unsigned int max_transition_latency; /* HW must be able to switch to
-                       next freq faster than this value in nano secs or we
-                       will fallback to performance governor */
+       /* For governors which change frequency dynamically by themselves */
+       bool                    dynamic_switching;
        struct list_head        governor_list;
        struct module           *owner;
 };
@@ -525,6 +524,7 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
                                   unsigned int relation);
 unsigned int cpufreq_driver_resolve_freq(struct cpufreq_policy *policy,
                                         unsigned int target_freq);
+unsigned int cpufreq_policy_transition_delay_us(struct cpufreq_policy *policy);
 int cpufreq_register_governor(struct cpufreq_governor *governor);
 void cpufreq_unregister_governor(struct cpufreq_governor *governor);
 
index 29a397067ffa0f7c818990f3defe1a4bdd437708..45fcf21ad685df8a665abf71c3516f6fc124ea1a 100644 (file)
@@ -528,16 +528,7 @@ static int sugov_init(struct cpufreq_policy *policy)
                goto stop_kthread;
        }
 
-       if (policy->transition_delay_us) {
-               tunables->rate_limit_us = policy->transition_delay_us;
-       } else {
-               unsigned int lat;
-
-               tunables->rate_limit_us = LATENCY_MULTIPLIER;
-               lat = policy->cpuinfo.transition_latency / NSEC_PER_USEC;
-               if (lat)
-                       tunables->rate_limit_us *= lat;
-       }
+       tunables->rate_limit_us = cpufreq_policy_transition_delay_us(policy);
 
        policy->governor_data = sg_policy;
        sg_policy->tunables = tunables;
@@ -655,6 +646,7 @@ static void sugov_limits(struct cpufreq_policy *policy)
 static struct cpufreq_governor schedutil_gov = {
        .name = "schedutil",
        .owner = THIS_MODULE,
+       .dynamic_switching = true,
        .init = sugov_init,
        .exit = sugov_exit,
        .start = sugov_start,