Merge branch 'cpufreq/scmi' into cpufreq/arm/linux-next
authorViresh Kumar <viresh.kumar@linaro.org>
Tue, 8 Dec 2020 05:52:17 +0000 (11:22 +0530)
committerViresh Kumar <viresh.kumar@linaro.org>
Tue, 8 Dec 2020 05:52:17 +0000 (11:22 +0530)
14 files changed:
drivers/cpufreq/Kconfig.arm
drivers/cpufreq/armada-8k-cpufreq.c
drivers/cpufreq/cpufreq-dt-platdev.c
drivers/cpufreq/highbank-cpufreq.c
drivers/cpufreq/loongson1-cpufreq.c
drivers/cpufreq/mediatek-cpufreq.c
drivers/cpufreq/qcom-cpufreq-nvmem.c
drivers/cpufreq/scmi-cpufreq.c
drivers/cpufreq/scpi-cpufreq.c
drivers/cpufreq/sti-cpufreq.c
drivers/cpufreq/sun50i-cpufreq-nvmem.c
drivers/cpufreq/tegra186-cpufreq.c
drivers/cpufreq/tegra194-cpufreq.c
drivers/cpufreq/vexpress-spc-cpufreq.c

index 015ec0c..1f73fa7 100644 (file)
@@ -94,7 +94,7 @@ config ARM_IMX6Q_CPUFREQ
        tristate "Freescale i.MX6 cpufreq support"
        depends on ARCH_MXC
        depends on REGULATOR_ANATOP
-       select NVMEM_IMX_OCOTP
+       depends on NVMEM_IMX_OCOTP || COMPILE_TEST
        select PM_OPP
        help
          This adds cpufreq driver support for Freescale i.MX6 series SoCs.
index 39e34f5..b0fc5e8 100644 (file)
@@ -204,6 +204,12 @@ static void __exit armada_8k_cpufreq_exit(void)
 }
 module_exit(armada_8k_cpufreq_exit);
 
+static const struct of_device_id __maybe_unused armada_8k_cpufreq_of_match[] = {
+       { .compatible = "marvell,ap806-cpu-clock" },
+       { },
+};
+MODULE_DEVICE_TABLE(of, armada_8k_cpufreq_of_match);
+
 MODULE_AUTHOR("Gregory Clement <gregory.clement@bootlin.com>");
 MODULE_DESCRIPTION("Armada 8K cpufreq driver");
 MODULE_LICENSE("GPL");
index 3776d96..bd2db01 100644 (file)
@@ -119,10 +119,12 @@ static const struct of_device_id blacklist[] __initconst = {
        { .compatible = "mediatek,mt2712", },
        { .compatible = "mediatek,mt7622", },
        { .compatible = "mediatek,mt7623", },
+       { .compatible = "mediatek,mt8167", },
        { .compatible = "mediatek,mt817x", },
        { .compatible = "mediatek,mt8173", },
        { .compatible = "mediatek,mt8176", },
        { .compatible = "mediatek,mt8183", },
+       { .compatible = "mediatek,mt8516", },
 
        { .compatible = "nvidia,tegra20", },
        { .compatible = "nvidia,tegra30", },
index 5a7f6da..ac57cdd 100644 (file)
@@ -101,6 +101,13 @@ out_put_node:
 }
 module_init(hb_cpufreq_driver_init);
 
+static const struct of_device_id __maybe_unused hb_cpufreq_of_match[] = {
+       { .compatible = "calxeda,highbank" },
+       { .compatible = "calxeda,ecx-2000" },
+       { },
+};
+MODULE_DEVICE_TABLE(of, hb_cpufreq_of_match);
+
 MODULE_AUTHOR("Mark Langsdorf <mark.langsdorf@calxeda.com>");
 MODULE_DESCRIPTION("Calxeda Highbank cpufreq driver");
 MODULE_LICENSE("GPL");
index 0ea8877..86f6125 100644 (file)
@@ -216,6 +216,7 @@ static struct platform_driver ls1x_cpufreq_platdrv = {
 
 module_platform_driver(ls1x_cpufreq_platdrv);
 
+MODULE_ALIAS("platform:ls1x-cpufreq");
 MODULE_AUTHOR("Kelvin Cheung <keguang.zhang@gmail.com>");
 MODULE_DESCRIPTION("Loongson1 CPUFreq driver");
 MODULE_LICENSE("GPL");
index 7d1212c..022e3e9 100644 (file)
@@ -532,6 +532,7 @@ static const struct of_device_id mtk_cpufreq_machines[] __initconst = {
        { .compatible = "mediatek,mt2712", },
        { .compatible = "mediatek,mt7622", },
        { .compatible = "mediatek,mt7623", },
+       { .compatible = "mediatek,mt8167", },
        { .compatible = "mediatek,mt817x", },
        { .compatible = "mediatek,mt8173", },
        { .compatible = "mediatek,mt8176", },
@@ -540,6 +541,7 @@ static const struct of_device_id mtk_cpufreq_machines[] __initconst = {
 
        { }
 };
+MODULE_DEVICE_TABLE(of, mtk_cpufreq_machines);
 
 static int __init mtk_cpufreq_driver_init(void)
 {
@@ -572,6 +574,7 @@ static int __init mtk_cpufreq_driver_init(void)
        pdev = platform_device_register_simple("mtk-cpufreq", -1, NULL, 0);
        if (IS_ERR(pdev)) {
                pr_err("failed to register mtk-cpufreq platform device\n");
+               platform_driver_unregister(&mtk_cpufreq_platdrv);
                return PTR_ERR(pdev);
        }
 
index d06b378..fba9937 100644 (file)
@@ -464,6 +464,7 @@ static const struct of_device_id qcom_cpufreq_match_list[] __initconst = {
        { .compatible = "qcom,msm8960", .data = &match_data_krait },
        {},
 };
+MODULE_DEVICE_TABLE(of, qcom_cpufreq_match_list);
 
 /*
  * Since the driver depends on smem and nvmem drivers, which may
index 144afd1..491a0a2 100644 (file)
@@ -8,6 +8,7 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
+#include <linux/clk-provider.h>
 #include <linux/cpu.h>
 #include <linux/cpufreq.h>
 #include <linux/cpumask.h>
@@ -231,15 +232,22 @@ static struct cpufreq_driver scmi_cpufreq_driver = {
 static int scmi_cpufreq_probe(struct scmi_device *sdev)
 {
        int ret;
+       struct device *dev = &sdev->dev;
 
        handle = sdev->handle;
 
        if (!handle || !handle->perf_ops)
                return -ENODEV;
 
+#ifdef CONFIG_COMMON_CLK
+       /* dummy clock provider as needed by OPP if clocks property is used */
+       if (of_find_property(dev->of_node, "#clock-cells", NULL))
+               devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, NULL);
+#endif
+
        ret = cpufreq_register_driver(&scmi_cpufreq_driver);
        if (ret) {
-               dev_err(&sdev->dev, "%s: registering cpufreq failed, err: %d\n",
+               dev_err(dev, "%s: registering cpufreq failed, err: %d\n",
                        __func__, ret);
        }
 
index 43db05b..e5140ad 100644 (file)
@@ -233,6 +233,7 @@ static struct platform_driver scpi_cpufreq_platdrv = {
 };
 module_platform_driver(scpi_cpufreq_platdrv);
 
+MODULE_ALIAS("platform:scpi-cpufreq");
 MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
 MODULE_DESCRIPTION("ARM SCPI CPUFreq interface driver");
 MODULE_LICENSE("GPL v2");
index 4ac6fb2..fdb0a72 100644 (file)
@@ -223,7 +223,8 @@ use_defaults:
        opp_table = dev_pm_opp_set_supported_hw(dev, version, VERSION_ELEMENTS);
        if (IS_ERR(opp_table)) {
                dev_err(dev, "Failed to set supported hardware\n");
-               return PTR_ERR(opp_table);
+               ret = PTR_ERR(opp_table);
+               goto err_put_prop_name;
        }
 
        dev_dbg(dev, "pcode: %d major: %d minor: %d substrate: %d\n",
@@ -232,6 +233,10 @@ use_defaults:
                version[0], version[1], version[2]);
 
        return 0;
+
+err_put_prop_name:
+       dev_pm_opp_put_prop_name(opp_table);
+       return ret;
 }
 
 static int sti_cpufreq_fetch_syscon_registers(void)
@@ -292,6 +297,13 @@ register_cpufreq_dt:
 }
 module_init(sti_cpufreq_init);
 
+static const struct of_device_id __maybe_unused sti_cpufreq_of_match[] = {
+       { .compatible = "st,stih407" },
+       { .compatible = "st,stih410" },
+       { },
+};
+MODULE_DEVICE_TABLE(of, sti_cpufreq_of_match);
+
 MODULE_DESCRIPTION("STMicroelectronics CPUFreq/OPP driver");
 MODULE_AUTHOR("Ajitpal Singh <ajitpal.singh@st.com>");
 MODULE_AUTHOR("Lee Jones <lee.jones@linaro.org>");
index 9907a16..2deed8d 100644 (file)
@@ -167,6 +167,7 @@ static const struct of_device_id sun50i_cpufreq_match_list[] = {
        { .compatible = "allwinner,sun50i-h6" },
        {}
 };
+MODULE_DEVICE_TABLE(of, sun50i_cpufreq_match_list);
 
 static const struct of_device_id *sun50i_cpufreq_match_node(void)
 {
index 4b4079f..e566ea2 100644 (file)
 #include <soc/tegra/bpmp.h>
 #include <soc/tegra/bpmp-abi.h>
 
-#define EDVD_CORE_VOLT_FREQ(core)              (0x20 + (core) * 0x4)
-#define EDVD_CORE_VOLT_FREQ_F_SHIFT            0
-#define EDVD_CORE_VOLT_FREQ_F_MASK             0xffff
-#define EDVD_CORE_VOLT_FREQ_V_SHIFT            16
-
-struct tegra186_cpufreq_cluster_info {
-       unsigned long offset;
-       int cpus[4];
+#define TEGRA186_NUM_CLUSTERS          2
+#define EDVD_OFFSET_A57(core)          ((SZ_64K * 6) + (0x20 + (core) * 0x4))
+#define EDVD_OFFSET_DENVER(core)       ((SZ_64K * 7) + (0x20 + (core) * 0x4))
+#define EDVD_CORE_VOLT_FREQ_F_SHIFT    0
+#define EDVD_CORE_VOLT_FREQ_F_MASK     0xffff
+#define EDVD_CORE_VOLT_FREQ_V_SHIFT    16
+
+struct tegra186_cpufreq_cpu {
        unsigned int bpmp_cluster_id;
+       unsigned int edvd_offset;
 };
 
-#define NO_CPU -1
-static const struct tegra186_cpufreq_cluster_info tegra186_clusters[] = {
-       /* Denver cluster */
+static const struct tegra186_cpufreq_cpu tegra186_cpus[] = {
+       /* CPU0 - A57 Cluster */
+       {
+               .bpmp_cluster_id = 1,
+               .edvd_offset = EDVD_OFFSET_A57(0)
+       },
+       /* CPU1 - Denver Cluster */
        {
-               .offset = SZ_64K * 7,
-               .cpus = { 1, 2, NO_CPU, NO_CPU },
                .bpmp_cluster_id = 0,
+               .edvd_offset = EDVD_OFFSET_DENVER(0)
+       },
+       /* CPU2 - Denver Cluster */
+       {
+               .bpmp_cluster_id = 0,
+               .edvd_offset = EDVD_OFFSET_DENVER(1)
+       },
+       /* CPU3 - A57 Cluster */
+       {
+               .bpmp_cluster_id = 1,
+               .edvd_offset = EDVD_OFFSET_A57(1)
        },
-       /* A57 cluster */
+       /* CPU4 - A57 Cluster */
        {
-               .offset = SZ_64K * 6,
-               .cpus = { 0, 3, 4, 5 },
                .bpmp_cluster_id = 1,
+               .edvd_offset = EDVD_OFFSET_A57(2)
+       },
+       /* CPU5 - A57 Cluster */
+       {
+               .bpmp_cluster_id = 1,
+               .edvd_offset = EDVD_OFFSET_A57(3)
        },
 };
 
 struct tegra186_cpufreq_cluster {
-       const struct tegra186_cpufreq_cluster_info *info;
        struct cpufreq_frequency_table *table;
+       u32 ref_clk_khz;
+       u32 div;
 };
 
 struct tegra186_cpufreq_data {
        void __iomem *regs;
-
-       size_t num_clusters;
        struct tegra186_cpufreq_cluster *clusters;
+       const struct tegra186_cpufreq_cpu *cpus;
 };
 
 static int tegra186_cpufreq_init(struct cpufreq_policy *policy)
 {
        struct tegra186_cpufreq_data *data = cpufreq_get_driver_data();
-       unsigned int i;
-
-       for (i = 0; i < data->num_clusters; i++) {
-               struct tegra186_cpufreq_cluster *cluster = &data->clusters[i];
-               const struct tegra186_cpufreq_cluster_info *info =
-                       cluster->info;
-               int core;
-
-               for (core = 0; core < ARRAY_SIZE(info->cpus); core++) {
-                       if (info->cpus[core] == policy->cpu)
-                               break;
-               }
-               if (core == ARRAY_SIZE(info->cpus))
-                       continue;
-
-               policy->driver_data =
-                       data->regs + info->offset + EDVD_CORE_VOLT_FREQ(core);
-               policy->freq_table = cluster->table;
-               break;
-       }
+       unsigned int cluster = data->cpus[policy->cpu].bpmp_cluster_id;
 
+       policy->freq_table = data->clusters[cluster].table;
        policy->cpuinfo.transition_latency = 300 * 1000;
+       policy->driver_data = NULL;
 
        return 0;
 }
@@ -83,41 +84,35 @@ static int tegra186_cpufreq_init(struct cpufreq_policy *policy)
 static int tegra186_cpufreq_set_target(struct cpufreq_policy *policy,
                                       unsigned int index)
 {
+       struct tegra186_cpufreq_data *data = cpufreq_get_driver_data();
        struct cpufreq_frequency_table *tbl = policy->freq_table + index;
-       void __iomem *edvd_reg = policy->driver_data;
+       unsigned int edvd_offset = data->cpus[policy->cpu].edvd_offset;
        u32 edvd_val = tbl->driver_data;
 
-       writel(edvd_val, edvd_reg);
+       writel(edvd_val, data->regs + edvd_offset);
 
        return 0;
 }
 
 static unsigned int tegra186_cpufreq_get(unsigned int cpu)
 {
-       struct cpufreq_frequency_table *tbl;
+       struct tegra186_cpufreq_data *data = cpufreq_get_driver_data();
+       struct tegra186_cpufreq_cluster *cluster;
        struct cpufreq_policy *policy;
-       void __iomem *edvd_reg;
-       unsigned int i, freq = 0;
+       unsigned int edvd_offset, cluster_id;
        u32 ndiv;
 
        policy = cpufreq_cpu_get(cpu);
        if (!policy)
                return 0;
 
-       tbl = policy->freq_table;
-       edvd_reg = policy->driver_data;
-       ndiv = readl(edvd_reg) & EDVD_CORE_VOLT_FREQ_F_MASK;
-
-       for (i = 0; tbl[i].frequency != CPUFREQ_TABLE_END; i++) {
-               if ((tbl[i].driver_data & EDVD_CORE_VOLT_FREQ_F_MASK) == ndiv) {
-                       freq = tbl[i].frequency;
-                       break;
-               }
-       }
-
+       edvd_offset = data->cpus[policy->cpu].edvd_offset;
+       ndiv = readl(data->regs + edvd_offset) & EDVD_CORE_VOLT_FREQ_F_MASK;
+       cluster_id = data->cpus[policy->cpu].bpmp_cluster_id;
+       cluster = &data->clusters[cluster_id];
        cpufreq_cpu_put(policy);
 
-       return freq;
+       return (cluster->ref_clk_khz * ndiv) / cluster->div;
 }
 
 static struct cpufreq_driver tegra186_cpufreq_driver = {
@@ -133,7 +128,7 @@ static struct cpufreq_driver tegra186_cpufreq_driver = {
 
 static struct cpufreq_frequency_table *init_vhint_table(
        struct platform_device *pdev, struct tegra_bpmp *bpmp,
-       unsigned int cluster_id)
+       struct tegra186_cpufreq_cluster *cluster, unsigned int cluster_id)
 {
        struct cpufreq_frequency_table *table;
        struct mrq_cpu_vhint_request req;
@@ -185,6 +180,9 @@ static struct cpufreq_frequency_table *init_vhint_table(
                goto free;
        }
 
+       cluster->ref_clk_khz = data->ref_clk_hz / 1000;
+       cluster->div = data->pdiv * data->mdiv;
+
        for (i = data->vfloor, j = 0; i <= data->vceil; i++) {
                struct cpufreq_frequency_table *point;
                u16 ndiv = data->ndiv[i];
@@ -202,8 +200,7 @@ static struct cpufreq_frequency_table *init_vhint_table(
 
                point = &table[j++];
                point->driver_data = edvd_val;
-               point->frequency = data->ref_clk_hz * ndiv / data->pdiv /
-                       data->mdiv / 1000;
+               point->frequency = (cluster->ref_clk_khz * ndiv) / cluster->div;
        }
 
        table[j].frequency = CPUFREQ_TABLE_END;
@@ -224,12 +221,12 @@ static int tegra186_cpufreq_probe(struct platform_device *pdev)
        if (!data)
                return -ENOMEM;
 
-       data->clusters = devm_kcalloc(&pdev->dev, ARRAY_SIZE(tegra186_clusters),
+       data->clusters = devm_kcalloc(&pdev->dev, TEGRA186_NUM_CLUSTERS,
                                      sizeof(*data->clusters), GFP_KERNEL);
        if (!data->clusters)
                return -ENOMEM;
 
-       data->num_clusters = ARRAY_SIZE(tegra186_clusters);
+       data->cpus = tegra186_cpus;
 
        bpmp = tegra_bpmp_get(&pdev->dev);
        if (IS_ERR(bpmp))
@@ -241,12 +238,10 @@ static int tegra186_cpufreq_probe(struct platform_device *pdev)
                goto put_bpmp;
        }
 
-       for (i = 0; i < data->num_clusters; i++) {
+       for (i = 0; i < TEGRA186_NUM_CLUSTERS; i++) {
                struct tegra186_cpufreq_cluster *cluster = &data->clusters[i];
 
-               cluster->info = &tegra186_clusters[i];
-               cluster->table = init_vhint_table(
-                       pdev, bpmp, cluster->info->bpmp_cluster_id);
+               cluster->table = init_vhint_table(pdev, bpmp, cluster, i);
                if (IS_ERR(cluster->table)) {
                        err = PTR_ERR(cluster->table);
                        goto put_bpmp;
index e1d931c..6a67f36 100644 (file)
@@ -21,7 +21,6 @@
 #define KHZ                     1000
 #define REF_CLK_MHZ             408 /* 408 MHz */
 #define US_DELAY                500
-#define US_DELAY_MIN            2
 #define CPUFREQ_TBL_STEP_HZ     (50 * KHZ * KHZ)
 #define MAX_CNT                 ~0U
 
@@ -44,7 +43,6 @@ struct tegra194_cpufreq_data {
 
 struct tegra_cpu_ctr {
        u32 cpu;
-       u32 delay;
        u32 coreclk_cnt, last_coreclk_cnt;
        u32 refclk_cnt, last_refclk_cnt;
 };
@@ -112,7 +110,7 @@ static void tegra_read_counters(struct work_struct *work)
        val = read_freq_feedback();
        c->last_refclk_cnt = lower_32_bits(val);
        c->last_coreclk_cnt = upper_32_bits(val);
-       udelay(c->delay);
+       udelay(US_DELAY);
        val = read_freq_feedback();
        c->refclk_cnt = lower_32_bits(val);
        c->coreclk_cnt = upper_32_bits(val);
@@ -139,7 +137,7 @@ static void tegra_read_counters(struct work_struct *work)
  * @cpu - logical cpu whose freq to be updated
  * Returns freq in KHz on success, 0 if cpu is offline
  */
-static unsigned int tegra194_get_speed_common(u32 cpu, u32 delay)
+static unsigned int tegra194_calculate_speed(u32 cpu)
 {
        struct read_counters_work read_counters_work;
        struct tegra_cpu_ctr c;
@@ -153,7 +151,6 @@ static unsigned int tegra194_get_speed_common(u32 cpu, u32 delay)
         * interrupts enabled.
         */
        read_counters_work.c.cpu = cpu;
-       read_counters_work.c.delay = delay;
        INIT_WORK_ONSTACK(&read_counters_work.work, tegra_read_counters);
        queue_work_on(cpu, read_counters_wq, &read_counters_work.work);
        flush_work(&read_counters_work.work);
@@ -180,9 +177,61 @@ static unsigned int tegra194_get_speed_common(u32 cpu, u32 delay)
        return (rate_mhz * KHZ); /* in KHz */
 }
 
+static void get_cpu_ndiv(void *ndiv)
+{
+       u64 ndiv_val;
+
+       asm volatile("mrs %0, s3_0_c15_c0_4" : "=r" (ndiv_val) : );
+
+       *(u64 *)ndiv = ndiv_val;
+}
+
+static void set_cpu_ndiv(void *data)
+{
+       struct cpufreq_frequency_table *tbl = data;
+       u64 ndiv_val = (u64)tbl->driver_data;
+
+       asm volatile("msr s3_0_c15_c0_4, %0" : : "r" (ndiv_val));
+}
+
 static unsigned int tegra194_get_speed(u32 cpu)
 {
-       return tegra194_get_speed_common(cpu, US_DELAY);
+       struct tegra194_cpufreq_data *data = cpufreq_get_driver_data();
+       struct cpufreq_frequency_table *pos;
+       unsigned int rate;
+       u64 ndiv;
+       int ret;
+       u32 cl;
+
+       smp_call_function_single(cpu, get_cpu_cluster, &cl, true);
+
+       /* reconstruct actual cpu freq using counters */
+       rate = tegra194_calculate_speed(cpu);
+
+       /* get last written ndiv value */
+       ret = smp_call_function_single(cpu, get_cpu_ndiv, &ndiv, true);
+       if (WARN_ON_ONCE(ret))
+               return rate;
+
+       /*
+        * If the reconstructed frequency has acceptable delta from
+        * the last written value, then return freq corresponding
+        * to the last written ndiv value from freq_table. This is
+        * done to return consistent value.
+        */
+       cpufreq_for_each_valid_entry(pos, data->tables[cl]) {
+               if (pos->driver_data != ndiv)
+                       continue;
+
+               if (abs(pos->frequency - rate) > 115200) {
+                       pr_warn("cpufreq: cpu%d,cur:%u,set:%u,set ndiv:%llu\n",
+                               cpu, rate, pos->frequency, ndiv);
+               } else {
+                       rate = pos->frequency;
+               }
+               break;
+       }
+       return rate;
 }
 
 static int tegra194_cpufreq_init(struct cpufreq_policy *policy)
@@ -196,9 +245,6 @@ static int tegra194_cpufreq_init(struct cpufreq_policy *policy)
        if (cl >= data->num_clusters)
                return -EINVAL;
 
-       /* boot freq */
-       policy->cur = tegra194_get_speed_common(policy->cpu, US_DELAY_MIN);
-
        /* set same policy for all cpus in a cluster */
        for (cpu = (cl * 2); cpu < ((cl + 1) * 2); cpu++)
                cpumask_set_cpu(cpu, policy->cpus);
@@ -209,14 +255,6 @@ static int tegra194_cpufreq_init(struct cpufreq_policy *policy)
        return 0;
 }
 
-static void set_cpu_ndiv(void *data)
-{
-       struct cpufreq_frequency_table *tbl = data;
-       u64 ndiv_val = (u64)tbl->driver_data;
-
-       asm volatile("msr s3_0_c15_c0_4, %0" : : "r" (ndiv_val));
-}
-
 static int tegra194_cpufreq_set_target(struct cpufreq_policy *policy,
                                       unsigned int index)
 {
index e89b905..f711d8e 100644 (file)
@@ -591,6 +591,7 @@ static struct platform_driver ve_spc_cpufreq_platdrv = {
 };
 module_platform_driver(ve_spc_cpufreq_platdrv);
 
+MODULE_ALIAS("platform:vexpress-spc-cpufreq");
 MODULE_AUTHOR("Viresh Kumar <viresh.kumar@linaro.org>");
 MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
 MODULE_DESCRIPTION("Vexpress SPC ARM big LITTLE cpufreq driver");