Merge tag 'pm-5.10-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 19 Nov 2020 19:11:50 +0000 (11:11 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 19 Nov 2020 19:11:50 +0000 (11:11 -0800)
Pull power management fixes from Rafael Wysocki:
 "These fix two issues in ARM cpufreq drivers and one cpuidle driver
  issue.

  Specifics:

   - Add missing RCU_NONIDLE() annotations to the Tegra cpuidle driver
     (Dmitry Osipenko)

   - Fix boot frequency computation in the tegra186 cpufreq driver (Jon
     Hunter)

   - Make the SCMI cpufreq driver register a dummy clock provider to
     avoid OPP addition failures (Sudeep Holla)"

* tag 'pm-5.10-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
  cpufreq: scmi: Fix OPP addition failure with a dummy clock provider
  cpufreq: tegra186: Fix get frequency callback
  cpuidle: tegra: Annotate tegra_pm_set_cpu_in_lp2() with RCU_NONIDLE

drivers/cpufreq/scmi-cpufreq.c
drivers/cpufreq/tegra186-cpufreq.c
drivers/cpuidle/cpuidle-tegra.c

index e855e86..7831850 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>
@@ -228,12 +229,17 @@ 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;
 
+       /* 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);
+
        ret = cpufreq_register_driver(&scmi_cpufreq_driver);
        if (ret) {
                dev_err(&sdev->dev, "%s: registering cpufreq failed, err: %d\n",
index 4b4079f..7eb2c56 100644 (file)
@@ -42,6 +42,8 @@ static const struct tegra186_cpufreq_cluster_info tegra186_clusters[] = {
 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 {
@@ -94,7 +96,7 @@ static int tegra186_cpufreq_set_target(struct cpufreq_policy *policy,
 
 static unsigned int tegra186_cpufreq_get(unsigned int cpu)
 {
-       struct cpufreq_frequency_table *tbl;
+       struct tegra186_cpufreq_data *data = cpufreq_get_driver_data();
        struct cpufreq_policy *policy;
        void __iomem *edvd_reg;
        unsigned int i, freq = 0;
@@ -104,17 +106,23 @@ static unsigned int tegra186_cpufreq_get(unsigned int 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;
+       for (i = 0; i < data->num_clusters; i++) {
+               struct tegra186_cpufreq_cluster *cluster = &data->clusters[i];
+               int core;
+
+               for (core = 0; core < ARRAY_SIZE(cluster->info->cpus); core++) {
+                       if (cluster->info->cpus[core] != policy->cpu)
+                               continue;
+
+                       freq = (cluster->ref_clk_khz * ndiv) / cluster->div;
+                       goto out;
                }
        }
 
+out:
        cpufreq_cpu_put(policy);
 
        return freq;
@@ -133,7 +141,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)
 {
        struct cpufreq_frequency_table *table;
        struct mrq_cpu_vhint_request req;
@@ -152,7 +160,7 @@ static struct cpufreq_frequency_table *init_vhint_table(
 
        memset(&req, 0, sizeof(req));
        req.addr = phys;
-       req.cluster_id = cluster_id;
+       req.cluster_id = cluster->info->bpmp_cluster_id;
 
        memset(&msg, 0, sizeof(msg));
        msg.mrq = MRQ_CPU_VHINT;
@@ -185,6 +193,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 +213,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;
@@ -245,8 +255,7 @@ static int tegra186_cpufreq_probe(struct platform_device *pdev)
                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);
                if (IS_ERR(cluster->table)) {
                        err = PTR_ERR(cluster->table);
                        goto put_bpmp;
index e895670..191966d 100644 (file)
@@ -189,7 +189,7 @@ static int tegra_cpuidle_state_enter(struct cpuidle_device *dev,
        }
 
        local_fiq_disable();
-       tegra_pm_set_cpu_in_lp2();
+       RCU_NONIDLE(tegra_pm_set_cpu_in_lp2());
        cpu_pm_enter();
 
        switch (index) {
@@ -207,7 +207,7 @@ static int tegra_cpuidle_state_enter(struct cpuidle_device *dev,
        }
 
        cpu_pm_exit();
-       tegra_pm_clear_cpu_in_lp2();
+       RCU_NONIDLE(tegra_pm_clear_cpu_in_lp2());
        local_fiq_enable();
 
        return err ?: index;