Merge branch 'cpufreq/arm/linux-next' of git://git.kernel.org/pub/scm/linux/kernel...
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Wed, 26 Jun 2019 08:51:27 +0000 (10:51 +0200)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Wed, 26 Jun 2019 08:51:27 +0000 (10:51 +0200)
Pull ARM cpufreq changes for v5.3 from Viresh Kumar:

"This pull request contains:

 - Minor fixes for brcmstb driver (Florian).
 - New imx-cpufreq driver, its bindings and code around it (Leonard).
 - New Raspberry Pi driver (Nicolas).
 - Minor fix for s5pv210 driver (Pawel).
 - Minor cleanup for armada driver (YueHaibing)."

* 'cpufreq/arm/linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm:
  cpufreq: s5pv210: Don't flood kernel log after cpufreq change
  cpufreq: add driver for Raspberry Pi
  cpufreq: Switch imx7d to imx-cpufreq-dt for speed grading
  cpufreq: imx-cpufreq-dt: Remove global platform match list
  cpufreq: brcmstb-avs-cpufreq: Fix types for voltage/frequency
  cpufreq: brcmstb-avs-cpufreq: Fix initial command check
  cpufreq: armada-37xx: Remove set but not used variable 'freq'
  cpufreq: imx-cpufreq-dt: Fix no OPPs available on unfused parts
  dt-bindings: imx-cpufreq-dt: Document opp-supported-hw usage
  cpufreq: Add imx-cpufreq-dt driver

Documentation/devicetree/bindings/cpufreq/imx-cpufreq-dt.txt [new file with mode: 0644]
drivers/cpufreq/Kconfig.arm
drivers/cpufreq/Makefile
drivers/cpufreq/armada-37xx-cpufreq.c
drivers/cpufreq/brcmstb-avs-cpufreq.c
drivers/cpufreq/cpufreq-dt-platdev.c
drivers/cpufreq/imx-cpufreq-dt.c [new file with mode: 0644]
drivers/cpufreq/raspberrypi-cpufreq.c [new file with mode: 0644]
drivers/cpufreq/s5pv210-cpufreq.c
drivers/soc/imx/soc-imx8.c

diff --git a/Documentation/devicetree/bindings/cpufreq/imx-cpufreq-dt.txt b/Documentation/devicetree/bindings/cpufreq/imx-cpufreq-dt.txt
new file mode 100644 (file)
index 0000000..87bff5a
--- /dev/null
@@ -0,0 +1,37 @@
+i.MX CPUFreq-DT OPP bindings
+================================
+
+Certain i.MX SoCs support different OPPs depending on the "market segment" and
+"speed grading" value which are written in fuses. These bits are combined with
+the opp-supported-hw values for each OPP to check if the OPP is allowed.
+
+Required properties:
+--------------------
+
+For each opp entry in 'operating-points-v2' table:
+- opp-supported-hw: Two bitmaps indicating:
+  - Supported speed grade mask
+  - Supported market segment mask
+    0: Consumer
+    1: Extended Consumer
+    2: Industrial
+    3: Automotive
+
+Example:
+--------
+
+opp_table {
+       compatible = "operating-points-v2";
+       opp-1000000000 {
+               opp-hz = /bits/ 64 <1000000000>;
+               /* grade >= 0, consumer only */
+               opp-supported-hw = <0xf>, <0x3>;
+       };
+
+       opp-1300000000 {
+               opp-hz = /bits/ 64 <1300000000>;
+               opp-microvolt = <1000000>;
+               /* grade >= 1, all segments */
+               opp-supported-hw = <0xe>, <0x7>;
+       };
+}
index f8129ed..56c31a7 100644 (file)
@@ -93,6 +93,15 @@ config ARM_IMX6Q_CPUFREQ
 
          If in doubt, say N.
 
+config ARM_IMX_CPUFREQ_DT
+       tristate "Freescale i.MX8M cpufreq support"
+       depends on ARCH_MXC && CPUFREQ_DT
+       help
+         This adds cpufreq driver support for Freescale i.MX8M series SoCs,
+         based on cpufreq-dt.
+
+         If in doubt, say N.
+
 config ARM_KIRKWOOD_CPUFREQ
        def_bool MACH_KIRKWOOD
        help
@@ -133,6 +142,14 @@ config ARM_QCOM_CPUFREQ_HW
          The driver implements the cpufreq interface for this HW engine.
          Say Y if you want to support CPUFreq HW.
 
+config ARM_RASPBERRYPI_CPUFREQ
+       tristate "Raspberry Pi cpufreq support"
+       depends on CLK_RASPBERRYPI || COMPILE_TEST
+       help
+         This adds the CPUFreq driver for Raspberry Pi
+
+         If in doubt, say N.
+
 config ARM_S3C_CPUFREQ
        bool
        help
index 689b26c..5a6c70d 100644 (file)
@@ -56,6 +56,7 @@ obj-$(CONFIG_ACPI_CPPC_CPUFREQ)               += cppc_cpufreq.o
 obj-$(CONFIG_ARCH_DAVINCI)             += davinci-cpufreq.o
 obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ)     += highbank-cpufreq.o
 obj-$(CONFIG_ARM_IMX6Q_CPUFREQ)                += imx6q-cpufreq.o
+obj-$(CONFIG_ARM_IMX_CPUFREQ_DT)       += imx-cpufreq-dt.o
 obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ)     += kirkwood-cpufreq.o
 obj-$(CONFIG_ARM_MEDIATEK_CPUFREQ)     += mediatek-cpufreq.o
 obj-$(CONFIG_MACH_MVEBU_V7)            += mvebu-cpufreq.o
@@ -64,6 +65,7 @@ obj-$(CONFIG_ARM_PXA2xx_CPUFREQ)      += pxa2xx-cpufreq.o
 obj-$(CONFIG_PXA3xx)                   += pxa3xx-cpufreq.o
 obj-$(CONFIG_ARM_QCOM_CPUFREQ_HW)      += qcom-cpufreq-hw.o
 obj-$(CONFIG_ARM_QCOM_CPUFREQ_KRYO)    += qcom-cpufreq-kryo.o
+obj-$(CONFIG_ARM_RASPBERRYPI_CPUFREQ)  += raspberrypi-cpufreq.o
 obj-$(CONFIG_ARM_S3C2410_CPUFREQ)      += s3c2410-cpufreq.o
 obj-$(CONFIG_ARM_S3C2412_CPUFREQ)      += s3c2412-cpufreq.o
 obj-$(CONFIG_ARM_S3C2416_CPUFREQ)      += s3c2416-cpufreq.o
index 0df16eb..aa0f06d 100644 (file)
@@ -257,7 +257,7 @@ static void __init armada37xx_cpufreq_avs_configure(struct regmap *base,
 static void __init armada37xx_cpufreq_avs_setup(struct regmap *base,
                                                struct armada_37xx_dvfs *dvfs)
 {
-       unsigned int avs_val = 0, freq;
+       unsigned int avs_val = 0;
        int load_level = 0;
 
        if (base == NULL)
@@ -275,8 +275,6 @@ static void __init armada37xx_cpufreq_avs_setup(struct regmap *base,
 
 
        for (load_level = 1; load_level < LOAD_LEVEL_NR; load_level++) {
-               freq = dvfs->cpu_freq_max / dvfs->divider[load_level];
-
                avs_val = dvfs->avs[load_level];
                regmap_update_bits(base, ARMADA_37XX_AVS_VSET(load_level-1),
                    ARMADA_37XX_AVS_VDD_MASK << ARMADA_37XX_AVS_HIGH_VDD_LIMIT |
index e6f9cbe..77b0e5d 100644 (file)
@@ -384,12 +384,12 @@ static int brcm_avs_set_pstate(struct private_data *priv, unsigned int pstate)
        return __issue_avs_command(priv, AVS_CMD_SET_PSTATE, true, args);
 }
 
-static unsigned long brcm_avs_get_voltage(void __iomem *base)
+static u32 brcm_avs_get_voltage(void __iomem *base)
 {
        return readl(base + AVS_MBOX_VOLTAGE1);
 }
 
-static unsigned long brcm_avs_get_frequency(void __iomem *base)
+static u32 brcm_avs_get_frequency(void __iomem *base)
 {
        return readl(base + AVS_MBOX_FREQUENCY) * 1000; /* in kHz */
 }
@@ -446,8 +446,8 @@ static bool brcm_avs_is_firmware_loaded(struct private_data *priv)
        rc = brcm_avs_get_pmap(priv, NULL);
        magic = readl(priv->base + AVS_MBOX_MAGIC);
 
-       return (magic == AVS_FIRMWARE_MAGIC) && (rc != -ENOTSUPP) &&
-               (rc != -EINVAL);
+       return (magic == AVS_FIRMWARE_MAGIC) && ((rc != -ENOTSUPP) ||
+               (rc != -EINVAL));
 }
 
 static unsigned int brcm_avs_cpufreq_get(unsigned int cpu)
@@ -653,14 +653,14 @@ static ssize_t show_brcm_avs_voltage(struct cpufreq_policy *policy, char *buf)
 {
        struct private_data *priv = policy->driver_data;
 
-       return sprintf(buf, "0x%08lx\n", brcm_avs_get_voltage(priv->base));
+       return sprintf(buf, "0x%08x\n", brcm_avs_get_voltage(priv->base));
 }
 
 static ssize_t show_brcm_avs_frequency(struct cpufreq_policy *policy, char *buf)
 {
        struct private_data *priv = policy->driver_data;
 
-       return sprintf(buf, "0x%08lx\n", brcm_avs_get_frequency(priv->base));
+       return sprintf(buf, "0x%08x\n", brcm_avs_get_frequency(priv->base));
 }
 
 cpufreq_freq_attr_ro(brcm_avs_pstate);
index 47729a2..eb282df 100644 (file)
@@ -40,7 +40,6 @@ static const struct of_device_id whitelist[] __initconst = {
        { .compatible = "fsl,imx27", },
        { .compatible = "fsl,imx51", },
        { .compatible = "fsl,imx53", },
-       { .compatible = "fsl,imx7d", },
 
        { .compatible = "marvell,berlin", },
        { .compatible = "marvell,pxa250", },
@@ -108,6 +107,10 @@ static const struct of_device_id blacklist[] __initconst = {
        { .compatible = "calxeda,highbank", },
        { .compatible = "calxeda,ecx-2000", },
 
+       { .compatible = "fsl,imx7d", },
+       { .compatible = "fsl,imx8mq", },
+       { .compatible = "fsl,imx8mm", },
+
        { .compatible = "marvell,armadaxp", },
 
        { .compatible = "mediatek,mt2701", },
diff --git a/drivers/cpufreq/imx-cpufreq-dt.c b/drivers/cpufreq/imx-cpufreq-dt.c
new file mode 100644 (file)
index 0000000..b54fd26
--- /dev/null
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP
+ */
+
+#include <linux/cpu.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_opp.h>
+#include <linux/slab.h>
+
+#define OCOTP_CFG3_SPEED_GRADE_SHIFT   8
+#define OCOTP_CFG3_SPEED_GRADE_MASK    (0x3 << 8)
+#define OCOTP_CFG3_MKT_SEGMENT_SHIFT    6
+#define OCOTP_CFG3_MKT_SEGMENT_MASK     (0x3 << 6)
+
+/* cpufreq-dt device registered by imx-cpufreq-dt */
+static struct platform_device *cpufreq_dt_pdev;
+static struct opp_table *cpufreq_opp_table;
+
+static int imx_cpufreq_dt_probe(struct platform_device *pdev)
+{
+       struct device *cpu_dev = get_cpu_device(0);
+       u32 cell_value, supported_hw[2];
+       int speed_grade, mkt_segment;
+       int ret;
+
+       ret = nvmem_cell_read_u32(cpu_dev, "speed_grade", &cell_value);
+       if (ret)
+               return ret;
+
+       speed_grade = (cell_value & OCOTP_CFG3_SPEED_GRADE_MASK) >> OCOTP_CFG3_SPEED_GRADE_SHIFT;
+       mkt_segment = (cell_value & OCOTP_CFG3_MKT_SEGMENT_MASK) >> OCOTP_CFG3_MKT_SEGMENT_SHIFT;
+
+       /*
+        * Early samples without fuses written report "0 0" which means
+        * consumer segment and minimum speed grading.
+        *
+        * According to datasheet minimum speed grading is not supported for
+        * consumer parts so clamp to 1 to avoid warning for "no OPPs"
+        *
+        * Applies to 8mq and 8mm.
+        */
+       if (mkt_segment == 0 && speed_grade == 0 && (
+                       of_machine_is_compatible("fsl,imx8mm") ||
+                       of_machine_is_compatible("fsl,imx8mq")))
+               speed_grade = 1;
+
+       supported_hw[0] = BIT(speed_grade);
+       supported_hw[1] = BIT(mkt_segment);
+       dev_info(&pdev->dev, "cpu speed grade %d mkt segment %d supported-hw %#x %#x\n",
+                       speed_grade, mkt_segment, supported_hw[0], supported_hw[1]);
+
+       cpufreq_opp_table = dev_pm_opp_set_supported_hw(cpu_dev, supported_hw, 2);
+       if (IS_ERR(cpufreq_opp_table)) {
+               ret = PTR_ERR(cpufreq_opp_table);
+               dev_err(&pdev->dev, "Failed to set supported opp: %d\n", ret);
+               return ret;
+       }
+
+       cpufreq_dt_pdev = platform_device_register_data(
+                       &pdev->dev, "cpufreq-dt", -1, NULL, 0);
+       if (IS_ERR(cpufreq_dt_pdev)) {
+               dev_pm_opp_put_supported_hw(cpufreq_opp_table);
+               ret = PTR_ERR(cpufreq_dt_pdev);
+               dev_err(&pdev->dev, "Failed to register cpufreq-dt: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int imx_cpufreq_dt_remove(struct platform_device *pdev)
+{
+       platform_device_unregister(cpufreq_dt_pdev);
+       dev_pm_opp_put_supported_hw(cpufreq_opp_table);
+
+       return 0;
+}
+
+static struct platform_driver imx_cpufreq_dt_driver = {
+       .probe = imx_cpufreq_dt_probe,
+       .remove = imx_cpufreq_dt_remove,
+       .driver = {
+               .name = "imx-cpufreq-dt",
+       },
+};
+module_platform_driver(imx_cpufreq_dt_driver);
+
+MODULE_ALIAS("platform:imx-cpufreq-dt");
+MODULE_DESCRIPTION("Freescale i.MX cpufreq speed grading driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/cpufreq/raspberrypi-cpufreq.c b/drivers/cpufreq/raspberrypi-cpufreq.c
new file mode 100644 (file)
index 0000000..2bc7d97
--- /dev/null
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Raspberry Pi cpufreq driver
+ *
+ * Copyright (C) 2019, Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+ */
+
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/cpufreq.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_opp.h>
+
+#define RASPBERRYPI_FREQ_INTERVAL      100000000
+
+static struct platform_device *cpufreq_dt;
+
+static int raspberrypi_cpufreq_probe(struct platform_device *pdev)
+{
+       struct device *cpu_dev;
+       unsigned long min, max;
+       unsigned long rate;
+       struct clk *clk;
+       int ret;
+
+       cpu_dev = get_cpu_device(0);
+       if (!cpu_dev) {
+               pr_err("Cannot get CPU for cpufreq driver\n");
+               return -ENODEV;
+       }
+
+       clk = clk_get(cpu_dev, NULL);
+       if (IS_ERR(clk)) {
+               dev_err(cpu_dev, "Cannot get clock for CPU0\n");
+               return PTR_ERR(clk);
+       }
+
+       /*
+        * The max and min frequencies are configurable in the Raspberry Pi
+        * firmware, so we query them at runtime.
+        */
+       min = roundup(clk_round_rate(clk, 0), RASPBERRYPI_FREQ_INTERVAL);
+       max = roundup(clk_round_rate(clk, ULONG_MAX), RASPBERRYPI_FREQ_INTERVAL);
+       clk_put(clk);
+
+       for (rate = min; rate <= max; rate += RASPBERRYPI_FREQ_INTERVAL) {
+               ret = dev_pm_opp_add(cpu_dev, rate, 0);
+               if (ret)
+                       goto remove_opp;
+       }
+
+       cpufreq_dt = platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
+       ret = PTR_ERR_OR_ZERO(cpufreq_dt);
+       if (ret) {
+               dev_err(cpu_dev, "Failed to create platform device, %d\n", ret);
+               goto remove_opp;
+       }
+
+       return 0;
+
+remove_opp:
+       dev_pm_opp_remove_all_dynamic(cpu_dev);
+
+       return ret;
+}
+
+static int raspberrypi_cpufreq_remove(struct platform_device *pdev)
+{
+       struct device *cpu_dev;
+
+       cpu_dev = get_cpu_device(0);
+       if (cpu_dev)
+               dev_pm_opp_remove_all_dynamic(cpu_dev);
+
+       platform_device_unregister(cpufreq_dt);
+
+       return 0;
+}
+
+/*
+ * Since the driver depends on clk-raspberrypi, which may return EPROBE_DEFER,
+ * all the activity is performed in the probe, which may be defered as well.
+ */
+static struct platform_driver raspberrypi_cpufreq_driver = {
+       .driver = {
+               .name = "raspberrypi-cpufreq",
+       },
+       .probe          = raspberrypi_cpufreq_probe,
+       .remove         = raspberrypi_cpufreq_remove,
+};
+module_platform_driver(raspberrypi_cpufreq_driver);
+
+MODULE_AUTHOR("Nicolas Saenz Julienne <nsaenzjulienne@suse.de");
+MODULE_DESCRIPTION("Raspberry Pi cpufreq driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:raspberrypi-cpufreq");
index 5b42894..c7b7d1e 100644 (file)
@@ -481,7 +481,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index)
                                arm_volt, arm_volt_max);
        }
 
-       printk(KERN_DEBUG "Perf changed[L%d]\n", index);
+       pr_debug("Perf changed[L%d]\n", index);
 
 exit:
        mutex_unlock(&set_freq_lock);
index fc6429f..b1bd8e2 100644 (file)
@@ -103,6 +103,9 @@ static int __init imx8_soc_init(void)
        if (IS_ERR(soc_dev))
                goto free_rev;
 
+       if (IS_ENABLED(CONFIG_ARM_IMX_CPUFREQ_DT))
+               platform_device_register_simple("imx-cpufreq-dt", -1, NULL, 0);
+
        return 0;
 
 free_rev: