1
0
mirror of https://git.openwrt.org/openwrt/openwrt.git synced 2024-06-16 04:03:56 +02:00

mediatek: backport cpufreq changes to support MT7988

Backport cpufreq changes from upstream so that the MediaTek MT7988 SoC
can be supported.

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
(cherry picked from commit e4555d69a1)
This commit is contained in:
Daniel Golle 2023-04-30 18:03:00 +01:00
parent fd17917951
commit 670dedbbd7
22 changed files with 2178 additions and 0 deletions

View File

@ -0,0 +1,166 @@
From 7a768326fdba542144833b9198a6d0edab52fad2 Mon Sep 17 00:00:00 2001
From: Jia-Wei Chang <jia-wei.chang@mediatek.com>
Date: Fri, 8 Apr 2022 12:58:56 +0800
Subject: [PATCH 01/21] cpufreq: mediatek: Cleanup variables and error handling
in mtk_cpu_dvfs_info_init()
- Remove several unnecessary varaibles in mtk_cpu_dvfs_info_init().
- Unify error message format and use dev_err_probe() if possible.
Signed-off-by: Jia-Wei Chang <jia-wei.chang@mediatek.com>
Signed-off-by: Rex-BC Chen <rex-bc.chen@mediatek.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
drivers/cpufreq/mediatek-cpufreq.c | 89 ++++++++++++------------------
1 file changed, 34 insertions(+), 55 deletions(-)
--- a/drivers/cpufreq/mediatek-cpufreq.c
+++ b/drivers/cpufreq/mediatek-cpufreq.c
@@ -302,96 +302,75 @@ static int mtk_cpufreq_set_target(struct
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);
+ dev_err(cpu_dev, "failed to get cpu%d device\n", cpu);
return -ENODEV;
}
+ info->cpu_dev = cpu_dev;
- 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);
+ info->cpu_clk = clk_get(cpu_dev, "cpu");
+ if (IS_ERR(info->cpu_clk)) {
+ ret = PTR_ERR(info->cpu_clk);
+ return dev_err_probe(cpu_dev, ret,
+ "cpu%d: failed to get cpu clk\n", cpu);
+ }
- ret = PTR_ERR(inter_clk);
+ info->inter_clk = clk_get(cpu_dev, "intermediate");
+ if (IS_ERR(info->inter_clk)) {
+ ret = PTR_ERR(info->inter_clk);
+ dev_err_probe(cpu_dev, ret,
+ "cpu%d: failed to get intermediate clk\n", cpu);
goto out_free_resources;
}
- proc_reg = regulator_get_optional(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);
+ info->proc_reg = regulator_get_optional(cpu_dev, "proc");
+ if (IS_ERR(info->proc_reg)) {
+ ret = PTR_ERR(info->proc_reg);
+ dev_err_probe(cpu_dev, ret,
+ "cpu%d: failed to get proc regulator\n", cpu);
goto out_free_resources;
}
/* Both presence and absence of sram regulator are valid cases. */
- sram_reg = regulator_get_exclusive(cpu_dev, "sram");
+ info->sram_reg = regulator_get_exclusive(cpu_dev, "sram");
+ if (IS_ERR(info->sram_reg))
+ info->sram_reg = NULL;
/* 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);
+ dev_err(cpu_dev,
+ "cpu%d: failed to get OPP-sharing information\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);
+ dev_warn(cpu_dev, "cpu%d: no OPP table\n", cpu);
goto out_free_resources;
}
/* Search a safe voltage for intermediate frequency. */
- rate = clk_get_rate(inter_clk);
+ rate = clk_get_rate(info->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);
+ dev_err(cpu_dev, "cpu%d: failed to get intermediate opp\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);
+ info->need_voltage_tracking = (info->sram_reg != NULL);
return 0;
@@ -399,14 +378,14 @@ 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);
+ 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);
return ret;
}

View File

@ -0,0 +1,25 @@
From 756104b856d4bc3121420af3ced342f5fc2b2123 Mon Sep 17 00:00:00 2001
From: Jia-Wei Chang <jia-wei.chang@mediatek.com>
Date: Fri, 8 Apr 2022 12:58:57 +0800
Subject: [PATCH 02/21] cpufreq: mediatek: Remove unused headers
Remove unused headers.
Signed-off-by: Jia-Wei Chang <jia-wei.chang@mediatek.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
drivers/cpufreq/mediatek-cpufreq.c | 2 --
1 file changed, 2 deletions(-)
--- a/drivers/cpufreq/mediatek-cpufreq.c
+++ b/drivers/cpufreq/mediatek-cpufreq.c
@@ -13,8 +13,6 @@
#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)

View File

@ -0,0 +1,117 @@
From 342d5545e9f40496db9ae0d31c2427dd5f369a43 Mon Sep 17 00:00:00 2001
From: Jia-Wei Chang <jia-wei.chang@mediatek.com>
Date: Fri, 8 Apr 2022 12:58:58 +0800
Subject: [PATCH 03/21] cpufreq: mediatek: Enable clocks and regulators
We need to enable regulators so that the max and min requested values will
be recorded.
The intermediate clock is not always enabled by CCF in different projects,
so we should enable it in the cpufreq driver.
Signed-off-by: Andrew-sh.Cheng <andrew-sh.cheng@mediatek.com>
Signed-off-by: Jia-Wei Chang <jia-wei.chang@mediatek.com>
Signed-off-by: Rex-BC Chen <rex-bc.chen@mediatek.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
drivers/cpufreq/mediatek-cpufreq.c | 50 +++++++++++++++++++++++++++---
1 file changed, 45 insertions(+), 5 deletions(-)
--- a/drivers/cpufreq/mediatek-cpufreq.c
+++ b/drivers/cpufreq/mediatek-cpufreq.c
@@ -334,10 +334,23 @@ static int mtk_cpu_dvfs_info_init(struct
goto out_free_resources;
}
+ ret = regulator_enable(info->proc_reg);
+ if (ret) {
+ dev_warn(cpu_dev, "cpu%d: failed to enable vproc\n", cpu);
+ goto out_free_resources;
+ }
+
/* Both presence and absence of sram regulator are valid cases. */
info->sram_reg = regulator_get_exclusive(cpu_dev, "sram");
if (IS_ERR(info->sram_reg))
info->sram_reg = NULL;
+ else {
+ ret = regulator_enable(info->sram_reg);
+ if (ret) {
+ dev_warn(cpu_dev, "cpu%d: failed to enable vsram\n", cpu);
+ goto out_free_resources;
+ }
+ }
/* Get OPP-sharing information from "operating-points-v2" bindings */
ret = dev_pm_opp_of_get_sharing_cpus(cpu_dev, &info->cpus);
@@ -353,13 +366,21 @@ static int mtk_cpu_dvfs_info_init(struct
goto out_free_resources;
}
+ ret = clk_prepare_enable(info->cpu_clk);
+ if (ret)
+ goto out_free_opp_table;
+
+ ret = clk_prepare_enable(info->inter_clk);
+ if (ret)
+ goto out_disable_mux_clock;
+
/* Search a safe voltage for intermediate frequency. */
rate = clk_get_rate(info->inter_clk);
opp = dev_pm_opp_find_freq_ceil(cpu_dev, &rate);
if (IS_ERR(opp)) {
dev_err(cpu_dev, "cpu%d: failed to get intermediate opp\n", cpu);
ret = PTR_ERR(opp);
- goto out_free_opp_table;
+ goto out_disable_inter_clock;
}
info->intermediate_voltage = dev_pm_opp_get_voltage(opp);
dev_pm_opp_put(opp);
@@ -372,10 +393,21 @@ static int mtk_cpu_dvfs_info_init(struct
return 0;
+out_disable_inter_clock:
+ clk_disable_unprepare(info->inter_clk);
+
+out_disable_mux_clock:
+ clk_disable_unprepare(info->cpu_clk);
+
out_free_opp_table:
dev_pm_opp_of_cpumask_remove_table(&info->cpus);
out_free_resources:
+ if (regulator_is_enabled(info->proc_reg))
+ regulator_disable(info->proc_reg);
+ if (info->sram_reg && regulator_is_enabled(info->sram_reg))
+ regulator_disable(info->sram_reg);
+
if (!IS_ERR(info->proc_reg))
regulator_put(info->proc_reg);
if (!IS_ERR(info->sram_reg))
@@ -390,14 +422,22 @@ out_free_resources:
static void mtk_cpu_dvfs_info_release(struct mtk_cpu_dvfs_info *info)
{
- if (!IS_ERR(info->proc_reg))
+ if (!IS_ERR(info->proc_reg)) {
+ regulator_disable(info->proc_reg);
regulator_put(info->proc_reg);
- if (!IS_ERR(info->sram_reg))
+ }
+ if (!IS_ERR(info->sram_reg)) {
+ regulator_disable(info->sram_reg);
regulator_put(info->sram_reg);
- if (!IS_ERR(info->cpu_clk))
+ }
+ if (!IS_ERR(info->cpu_clk)) {
+ clk_disable_unprepare(info->cpu_clk);
clk_put(info->cpu_clk);
- if (!IS_ERR(info->inter_clk))
+ }
+ if (!IS_ERR(info->inter_clk)) {
+ clk_disable_unprepare(info->inter_clk);
clk_put(info->inter_clk);
+ }
dev_pm_opp_of_cpumask_remove_table(&info->cpus);
}

View File

@ -0,0 +1,161 @@
From a02e2b359141035d2d6999940bc1b9f83ec88587 Mon Sep 17 00:00:00 2001
From: Rex-BC Chen <rex-bc.chen@mediatek.com>
Date: Fri, 22 Apr 2022 15:52:27 +0800
Subject: [PATCH 04/21] cpufreq: mediatek: Use device print to show logs
- Replace pr_* with dev_* to show logs.
- Remove usage of __func__.
Signed-off-by: Rex-BC Chen <rex-bc.chen@mediatek.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
drivers/cpufreq/mediatek-cpufreq.c | 54 ++++++++++++++++--------------
1 file changed, 28 insertions(+), 26 deletions(-)
--- a/drivers/cpufreq/mediatek-cpufreq.c
+++ b/drivers/cpufreq/mediatek-cpufreq.c
@@ -67,7 +67,8 @@ static int mtk_cpufreq_voltage_tracking(
old_vproc = regulator_get_voltage(proc_reg);
if (old_vproc < 0) {
- pr_err("%s: invalid Vproc value: %d\n", __func__, old_vproc);
+ dev_err(info->cpu_dev,
+ "invalid Vproc value: %d\n", old_vproc);
return old_vproc;
}
/* Vsram should not exceed the maximum allowed voltage of SoC. */
@@ -83,14 +84,14 @@ static int mtk_cpufreq_voltage_tracking(
do {
old_vsram = regulator_get_voltage(sram_reg);
if (old_vsram < 0) {
- pr_err("%s: invalid Vsram value: %d\n",
- __func__, old_vsram);
+ dev_err(info->cpu_dev,
+ "invalid Vsram value: %d\n", 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);
+ dev_err(info->cpu_dev,
+ "invalid Vproc value: %d\n", old_vproc);
return old_vproc;
}
@@ -138,14 +139,14 @@ static int mtk_cpufreq_voltage_tracking(
do {
old_vproc = regulator_get_voltage(proc_reg);
if (old_vproc < 0) {
- pr_err("%s: invalid Vproc value: %d\n",
- __func__, old_vproc);
+ dev_err(info->cpu_dev,
+ "invalid Vproc value: %d\n", 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);
+ dev_err(info->cpu_dev,
+ "invalid Vsram value: %d\n", old_vsram);
return old_vsram;
}
@@ -216,7 +217,7 @@ static int mtk_cpufreq_set_target(struct
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);
+ dev_err(cpu_dev, "invalid Vproc value: %d\n", old_vproc);
return old_vproc;
}
@@ -224,8 +225,8 @@ static int mtk_cpufreq_set_target(struct
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);
+ dev_err(cpu_dev, "cpu%d: failed to find OPP for %ld\n",
+ policy->cpu, freq_hz);
return PTR_ERR(opp);
}
vproc = dev_pm_opp_get_voltage(opp);
@@ -239,8 +240,8 @@ static int mtk_cpufreq_set_target(struct
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);
+ dev_err(cpu_dev,
+ "cpu%d: failed to scale up voltage!\n", policy->cpu);
mtk_cpufreq_set_voltage(info, old_vproc);
return ret;
}
@@ -249,8 +250,8 @@ static int mtk_cpufreq_set_target(struct
/* 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);
+ dev_err(cpu_dev,
+ "cpu%d: failed to re-parent cpu clock!\n", policy->cpu);
mtk_cpufreq_set_voltage(info, old_vproc);
WARN_ON(1);
return ret;
@@ -259,8 +260,8 @@ static int mtk_cpufreq_set_target(struct
/* 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);
+ dev_err(cpu_dev,
+ "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;
@@ -269,8 +270,8 @@ static int mtk_cpufreq_set_target(struct
/* 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);
+ dev_err(cpu_dev,
+ "cpu%d: failed to re-parent cpu clock!\n", policy->cpu);
mtk_cpufreq_set_voltage(info, inter_vproc);
WARN_ON(1);
return ret;
@@ -283,8 +284,8 @@ static int mtk_cpufreq_set_target(struct
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);
+ dev_err(cpu_dev,
+ "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);
@@ -450,15 +451,16 @@ static int mtk_cpufreq_init(struct cpufr
info = mtk_cpu_dvfs_info_lookup(policy->cpu);
if (!info) {
- pr_err("dvfs info for cpu%d is not initialized.\n",
- policy->cpu);
+ dev_err(info->cpu_dev,
+ "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);
+ dev_err(info->cpu_dev,
+ "failed to init cpufreq table for cpu%d: %d\n",
+ policy->cpu, ret);
return ret;
}

View File

@ -0,0 +1,201 @@
From 35832d9f9c5c1da01420d962dc56e7e61d104829 Mon Sep 17 00:00:00 2001
From: Rex-BC Chen <rex-bc.chen@mediatek.com>
Date: Fri, 22 Apr 2022 15:52:28 +0800
Subject: [PATCH 05/21] cpufreq: mediatek: Replace old_* with pre_*
To make driver more readable, replace old_* with pre_*.
Signed-off-by: Rex-BC Chen <rex-bc.chen@mediatek.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
drivers/cpufreq/mediatek-cpufreq.c | 84 +++++++++++++++---------------
1 file changed, 42 insertions(+), 42 deletions(-)
--- a/drivers/cpufreq/mediatek-cpufreq.c
+++ b/drivers/cpufreq/mediatek-cpufreq.c
@@ -63,18 +63,18 @@ static int mtk_cpufreq_voltage_tracking(
{
struct regulator *proc_reg = info->proc_reg;
struct regulator *sram_reg = info->sram_reg;
- int old_vproc, old_vsram, new_vsram, vsram, vproc, ret;
+ int pre_vproc, pre_vsram, new_vsram, vsram, vproc, ret;
- old_vproc = regulator_get_voltage(proc_reg);
- if (old_vproc < 0) {
+ pre_vproc = regulator_get_voltage(proc_reg);
+ if (pre_vproc < 0) {
dev_err(info->cpu_dev,
- "invalid Vproc value: %d\n", old_vproc);
- return old_vproc;
+ "invalid Vproc value: %d\n", pre_vproc);
+ return pre_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) {
+ if (pre_vproc < new_vproc) {
/*
* When scaling up voltages, Vsram and Vproc scale up step
* by step. At each step, set Vsram to (Vproc + 200mV) first,
@@ -82,20 +82,20 @@ static int mtk_cpufreq_voltage_tracking(
* Keep doing it until Vsram and Vproc hit target voltages.
*/
do {
- old_vsram = regulator_get_voltage(sram_reg);
- if (old_vsram < 0) {
+ pre_vsram = regulator_get_voltage(sram_reg);
+ if (pre_vsram < 0) {
dev_err(info->cpu_dev,
- "invalid Vsram value: %d\n", old_vsram);
- return old_vsram;
+ "invalid Vsram value: %d\n", pre_vsram);
+ return pre_vsram;
}
- old_vproc = regulator_get_voltage(proc_reg);
- if (old_vproc < 0) {
+ pre_vproc = regulator_get_voltage(proc_reg);
+ if (pre_vproc < 0) {
dev_err(info->cpu_dev,
- "invalid Vproc value: %d\n", old_vproc);
- return old_vproc;
+ "invalid Vproc value: %d\n", pre_vproc);
+ return pre_vproc;
}
- vsram = min(new_vsram, old_vproc + MAX_VOLT_SHIFT);
+ vsram = min(new_vsram, pre_vproc + MAX_VOLT_SHIFT);
if (vsram + VOLT_TOL >= MAX_VOLT_LIMIT) {
vsram = MAX_VOLT_LIMIT;
@@ -124,12 +124,12 @@ static int mtk_cpufreq_voltage_tracking(
ret = regulator_set_voltage(proc_reg, vproc,
vproc + VOLT_TOL);
if (ret) {
- regulator_set_voltage(sram_reg, old_vsram,
- old_vsram);
+ regulator_set_voltage(sram_reg, pre_vsram,
+ pre_vsram);
return ret;
}
} while (vproc < new_vproc || vsram < new_vsram);
- } else if (old_vproc > new_vproc) {
+ } else if (pre_vproc > new_vproc) {
/*
* When scaling down voltages, Vsram and Vproc scale down step
* by step. At each step, set Vproc to (Vsram - 200mV) first,
@@ -137,20 +137,20 @@ static int mtk_cpufreq_voltage_tracking(
* Keep doing it until Vsram and Vproc hit target voltages.
*/
do {
- old_vproc = regulator_get_voltage(proc_reg);
- if (old_vproc < 0) {
+ pre_vproc = regulator_get_voltage(proc_reg);
+ if (pre_vproc < 0) {
dev_err(info->cpu_dev,
- "invalid Vproc value: %d\n", old_vproc);
- return old_vproc;
+ "invalid Vproc value: %d\n", pre_vproc);
+ return pre_vproc;
}
- old_vsram = regulator_get_voltage(sram_reg);
- if (old_vsram < 0) {
+ pre_vsram = regulator_get_voltage(sram_reg);
+ if (pre_vsram < 0) {
dev_err(info->cpu_dev,
- "invalid Vsram value: %d\n", old_vsram);
- return old_vsram;
+ "invalid Vsram value: %d\n", pre_vsram);
+ return pre_vsram;
}
- vproc = max(new_vproc, old_vsram - MAX_VOLT_SHIFT);
+ vproc = max(new_vproc, pre_vsram - MAX_VOLT_SHIFT);
ret = regulator_set_voltage(proc_reg, vproc,
vproc + VOLT_TOL);
if (ret)
@@ -180,8 +180,8 @@ static int mtk_cpufreq_voltage_tracking(
}
if (ret) {
- regulator_set_voltage(proc_reg, old_vproc,
- old_vproc);
+ regulator_set_voltage(proc_reg, pre_vproc,
+ pre_vproc);
return ret;
}
} while (vproc > new_vproc + VOLT_TOL ||
@@ -209,16 +209,16 @@ static int mtk_cpufreq_set_target(struct
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;
+ long freq_hz, pre_freq_hz;
+ int vproc, pre_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) {
- dev_err(cpu_dev, "invalid Vproc value: %d\n", old_vproc);
- return old_vproc;
+ pre_freq_hz = clk_get_rate(cpu_clk);
+ pre_vproc = regulator_get_voltage(info->proc_reg);
+ if (pre_vproc < 0) {
+ dev_err(cpu_dev, "invalid Vproc value: %d\n", pre_vproc);
+ return pre_vproc;
}
freq_hz = freq_table[index].frequency * 1000;
@@ -237,12 +237,12 @@ static int mtk_cpufreq_set_target(struct
* current voltage, scale up voltage first.
*/
target_vproc = (inter_vproc > vproc) ? inter_vproc : vproc;
- if (old_vproc < target_vproc) {
+ if (pre_vproc < target_vproc) {
ret = mtk_cpufreq_set_voltage(info, target_vproc);
if (ret) {
dev_err(cpu_dev,
"cpu%d: failed to scale up voltage!\n", policy->cpu);
- mtk_cpufreq_set_voltage(info, old_vproc);
+ mtk_cpufreq_set_voltage(info, pre_vproc);
return ret;
}
}
@@ -252,7 +252,7 @@ static int mtk_cpufreq_set_target(struct
if (ret) {
dev_err(cpu_dev,
"cpu%d: failed to re-parent cpu clock!\n", policy->cpu);
- mtk_cpufreq_set_voltage(info, old_vproc);
+ mtk_cpufreq_set_voltage(info, pre_vproc);
WARN_ON(1);
return ret;
}
@@ -263,7 +263,7 @@ static int mtk_cpufreq_set_target(struct
dev_err(cpu_dev,
"cpu%d: failed to scale cpu clock rate!\n", policy->cpu);
clk_set_parent(cpu_clk, armpll);
- mtk_cpufreq_set_voltage(info, old_vproc);
+ mtk_cpufreq_set_voltage(info, pre_vproc);
return ret;
}
@@ -281,13 +281,13 @@ static int mtk_cpufreq_set_target(struct
* 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) {
+ if (vproc < inter_vproc || vproc < pre_vproc) {
ret = mtk_cpufreq_set_voltage(info, vproc);
if (ret) {
dev_err(cpu_dev,
"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_rate(armpll, pre_freq_hz);
clk_set_parent(cpu_clk, armpll);
return ret;
}

View File

@ -0,0 +1,64 @@
From 34737eb8d0daa0d4183f10286a2f55d8788066bc Mon Sep 17 00:00:00 2001
From: Jia-Wei Chang <jia-wei.chang@mediatek.com>
Date: Fri, 22 Apr 2022 15:52:29 +0800
Subject: [PATCH 06/21] cpufreq: mediatek: Record previous target vproc value
We found the buck voltage may not be exactly the same with what we set
because CPU may share the same buck with other module.
Therefore, we need to record the previous desired value instead of reading
it from regulators.
Signed-off-by: Andrew-sh.Cheng <andrew-sh.cheng@mediatek.com>
Signed-off-by: Jia-Wei Chang <jia-wei.chang@mediatek.com>
Signed-off-by: Rex-BC Chen <rex-bc.chen@mediatek.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
drivers/cpufreq/mediatek-cpufreq.c | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
--- a/drivers/cpufreq/mediatek-cpufreq.c
+++ b/drivers/cpufreq/mediatek-cpufreq.c
@@ -40,6 +40,7 @@ struct mtk_cpu_dvfs_info {
struct list_head list_head;
int intermediate_voltage;
bool need_voltage_tracking;
+ int pre_vproc;
};
static struct platform_device *cpufreq_pdev;
@@ -193,11 +194,17 @@ static int mtk_cpufreq_voltage_tracking(
static int mtk_cpufreq_set_voltage(struct mtk_cpu_dvfs_info *info, int vproc)
{
+ int ret;
+
if (info->need_voltage_tracking)
- return mtk_cpufreq_voltage_tracking(info, vproc);
+ ret = mtk_cpufreq_voltage_tracking(info, vproc);
else
- return regulator_set_voltage(info->proc_reg, vproc,
- vproc + VOLT_TOL);
+ ret = regulator_set_voltage(info->proc_reg, vproc,
+ MAX_VOLT_LIMIT);
+ if (!ret)
+ info->pre_vproc = vproc;
+
+ return ret;
}
static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
@@ -215,7 +222,12 @@ static int mtk_cpufreq_set_target(struct
inter_vproc = info->intermediate_voltage;
pre_freq_hz = clk_get_rate(cpu_clk);
- pre_vproc = regulator_get_voltage(info->proc_reg);
+
+ if (unlikely(info->pre_vproc <= 0))
+ pre_vproc = regulator_get_voltage(info->proc_reg);
+ else
+ pre_vproc = info->pre_vproc;
+
if (pre_vproc < 0) {
dev_err(cpu_dev, "invalid Vproc value: %d\n", pre_vproc);
return pre_vproc;

View File

@ -0,0 +1,30 @@
From f6114c2bc563a8050e9dc874ad87e1448865f031 Mon Sep 17 00:00:00 2001
From: Jia-Wei Chang <jia-wei.chang@mediatek.com>
Date: Fri, 22 Apr 2022 15:52:33 +0800
Subject: [PATCH 07/21] cpufreq: mediatek: Make sram regulator optional
For some MediaTek SoCs, like MT8186, it's possible that the sram regulator
is shared between CPU and CCI.
We hope regulator framework can return error for error handling rather
than a dummy handler from regulator_get api.
Therefore, we choose to use regulator_get_optional.
Signed-off-by: Jia-Wei Chang <jia-wei.chang@mediatek.com>
Signed-off-by: Rex-BC Chen <rex-bc.chen@mediatek.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
drivers/cpufreq/mediatek-cpufreq.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/cpufreq/mediatek-cpufreq.c
+++ b/drivers/cpufreq/mediatek-cpufreq.c
@@ -354,7 +354,7 @@ static int mtk_cpu_dvfs_info_init(struct
}
/* Both presence and absence of sram regulator are valid cases. */
- info->sram_reg = regulator_get_exclusive(cpu_dev, "sram");
+ info->sram_reg = regulator_get_optional(cpu_dev, "sram");
if (IS_ERR(info->sram_reg))
info->sram_reg = NULL;
else {

View File

@ -0,0 +1,32 @@
From fa7030d8ad4638acfd9e0fac84a20716d031dc95 Mon Sep 17 00:00:00 2001
From: Wan Jiabing <wanjiabing@vivo.com>
Date: Tue, 26 Apr 2022 19:17:14 +0800
Subject: [PATCH 08/21] cpufreq: mediatek: Fix NULL pointer dereference in
mediatek-cpufreq
Fix following coccicheck error:
drivers/cpufreq/mediatek-cpufreq.c:464:16-23: ERROR: info is NULL but dereferenced.
Use pr_err instead of dev_err to avoid dereferring a NULL pointer.
Fixes: f52b16ba9fe4 ("cpufreq: mediatek: Use device print to show logs")
Signed-off-by: Wan Jiabing <wanjiabing@vivo.com>
Reviewed-by: Matthias Brugger <matthias.bgg@gmail.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
drivers/cpufreq/mediatek-cpufreq.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
--- a/drivers/cpufreq/mediatek-cpufreq.c
+++ b/drivers/cpufreq/mediatek-cpufreq.c
@@ -463,8 +463,8 @@ static int mtk_cpufreq_init(struct cpufr
info = mtk_cpu_dvfs_info_lookup(policy->cpu);
if (!info) {
- dev_err(info->cpu_dev,
- "dvfs info for cpu%d is not initialized.\n", policy->cpu);
+ pr_err("dvfs info for cpu%d is not initialized.\n",
+ policy->cpu);
return -EINVAL;
}

View File

@ -0,0 +1,227 @@
From be2354b064e6bafbbad599ae2e10569ba4f7d5a6 Mon Sep 17 00:00:00 2001
From: Rex-BC Chen <rex-bc.chen@mediatek.com>
Date: Thu, 5 May 2022 19:52:19 +0800
Subject: [PATCH 09/21] cpufreq: mediatek: Move voltage limits to platform data
Voltages and shifts are defined as macros originally.
There are different requirements of these values for each MediaTek SoCs.
Therefore, we add the platform data and move these values into it.
Signed-off-by: Jia-Wei Chang <jia-wei.chang@mediatek.com>
Signed-off-by: Rex-BC Chen <rex-bc.chen@mediatek.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
drivers/cpufreq/mediatek-cpufreq.c | 84 +++++++++++++++++++++---------
1 file changed, 58 insertions(+), 26 deletions(-)
--- a/drivers/cpufreq/mediatek-cpufreq.c
+++ b/drivers/cpufreq/mediatek-cpufreq.c
@@ -10,15 +10,21 @@
#include <linux/cpumask.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pm_opp.h>
#include <linux/regulator/consumer.h>
-#define MIN_VOLT_SHIFT (100000)
-#define MAX_VOLT_SHIFT (200000)
-#define MAX_VOLT_LIMIT (1150000)
#define VOLT_TOL (10000)
+struct mtk_cpufreq_platform_data {
+ int min_volt_shift;
+ int max_volt_shift;
+ int proc_max_volt;
+ int sram_min_volt;
+ int sram_max_volt;
+};
+
/*
* 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
@@ -41,6 +47,7 @@ struct mtk_cpu_dvfs_info {
int intermediate_voltage;
bool need_voltage_tracking;
int pre_vproc;
+ const struct mtk_cpufreq_platform_data *soc_data;
};
static struct platform_device *cpufreq_pdev;
@@ -62,6 +69,7 @@ static struct mtk_cpu_dvfs_info *mtk_cpu
static int mtk_cpufreq_voltage_tracking(struct mtk_cpu_dvfs_info *info,
int new_vproc)
{
+ const struct mtk_cpufreq_platform_data *soc_data = info->soc_data;
struct regulator *proc_reg = info->proc_reg;
struct regulator *sram_reg = info->sram_reg;
int pre_vproc, pre_vsram, new_vsram, vsram, vproc, ret;
@@ -73,7 +81,8 @@ static int mtk_cpufreq_voltage_tracking(
return pre_vproc;
}
/* Vsram should not exceed the maximum allowed voltage of SoC. */
- new_vsram = min(new_vproc + MIN_VOLT_SHIFT, MAX_VOLT_LIMIT);
+ new_vsram = min(new_vproc + soc_data->min_volt_shift,
+ soc_data->sram_max_volt);
if (pre_vproc < new_vproc) {
/*
@@ -96,10 +105,11 @@ static int mtk_cpufreq_voltage_tracking(
return pre_vproc;
}
- vsram = min(new_vsram, pre_vproc + MAX_VOLT_SHIFT);
+ vsram = min(new_vsram,
+ pre_vproc + soc_data->min_volt_shift);
- if (vsram + VOLT_TOL >= MAX_VOLT_LIMIT) {
- vsram = MAX_VOLT_LIMIT;
+ if (vsram + VOLT_TOL >= soc_data->sram_max_volt) {
+ vsram = soc_data->sram_max_volt;
/*
* If the target Vsram hits the maximum voltage,
@@ -117,7 +127,7 @@ static int mtk_cpufreq_voltage_tracking(
ret = regulator_set_voltage(sram_reg, vsram,
vsram + VOLT_TOL);
- vproc = vsram - MIN_VOLT_SHIFT;
+ vproc = vsram - soc_data->min_volt_shift;
}
if (ret)
return ret;
@@ -151,7 +161,8 @@ static int mtk_cpufreq_voltage_tracking(
return pre_vsram;
}
- vproc = max(new_vproc, pre_vsram - MAX_VOLT_SHIFT);
+ vproc = max(new_vproc,
+ pre_vsram - soc_data->max_volt_shift);
ret = regulator_set_voltage(proc_reg, vproc,
vproc + VOLT_TOL);
if (ret)
@@ -160,10 +171,11 @@ static int mtk_cpufreq_voltage_tracking(
if (vproc == new_vproc)
vsram = new_vsram;
else
- vsram = max(new_vsram, vproc + MIN_VOLT_SHIFT);
+ vsram = max(new_vsram,
+ vproc + soc_data->min_volt_shift);
- if (vsram + VOLT_TOL >= MAX_VOLT_LIMIT) {
- vsram = MAX_VOLT_LIMIT;
+ if (vsram + VOLT_TOL >= soc_data->sram_max_volt) {
+ vsram = soc_data->sram_max_volt;
/*
* If the target Vsram hits the maximum voltage,
@@ -194,13 +206,14 @@ static int mtk_cpufreq_voltage_tracking(
static int mtk_cpufreq_set_voltage(struct mtk_cpu_dvfs_info *info, int vproc)
{
+ const struct mtk_cpufreq_platform_data *soc_data = info->soc_data;
int ret;
if (info->need_voltage_tracking)
ret = mtk_cpufreq_voltage_tracking(info, vproc);
else
ret = regulator_set_voltage(info->proc_reg, vproc,
- MAX_VOLT_LIMIT);
+ soc_data->proc_max_volt);
if (!ret)
info->pre_vproc = vproc;
@@ -509,9 +522,17 @@ static struct cpufreq_driver mtk_cpufreq
static int mtk_cpufreq_probe(struct platform_device *pdev)
{
+ const struct mtk_cpufreq_platform_data *data;
struct mtk_cpu_dvfs_info *info, *tmp;
int cpu, ret;
+ data = dev_get_platdata(&pdev->dev);
+ if (!data) {
+ dev_err(&pdev->dev,
+ "failed to get mtk cpufreq platform data\n");
+ return -ENODEV;
+ }
+
for_each_possible_cpu(cpu) {
info = mtk_cpu_dvfs_info_lookup(cpu);
if (info)
@@ -523,6 +544,7 @@ static int mtk_cpufreq_probe(struct plat
goto release_dvfs_info_list;
}
+ info->soc_data = data;
ret = mtk_cpu_dvfs_info_init(info, cpu);
if (ret) {
dev_err(&pdev->dev,
@@ -558,20 +580,27 @@ static struct platform_driver mtk_cpufre
.probe = mtk_cpufreq_probe,
};
+static const struct mtk_cpufreq_platform_data mt2701_platform_data = {
+ .min_volt_shift = 100000,
+ .max_volt_shift = 200000,
+ .proc_max_volt = 1150000,
+ .sram_min_volt = 0,
+ .sram_max_volt = 1150000,
+};
+
/* List of machines supported by this driver */
static const struct of_device_id mtk_cpufreq_machines[] __initconst = {
- { .compatible = "mediatek,mt2701", },
- { .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,mt8365", },
- { .compatible = "mediatek,mt8516", },
-
+ { .compatible = "mediatek,mt2701", .data = &mt2701_platform_data },
+ { .compatible = "mediatek,mt2712", .data = &mt2701_platform_data },
+ { .compatible = "mediatek,mt7622", .data = &mt2701_platform_data },
+ { .compatible = "mediatek,mt7623", .data = &mt2701_platform_data },
+ { .compatible = "mediatek,mt8167", .data = &mt2701_platform_data },
+ { .compatible = "mediatek,mt817x", .data = &mt2701_platform_data },
+ { .compatible = "mediatek,mt8173", .data = &mt2701_platform_data },
+ { .compatible = "mediatek,mt8176", .data = &mt2701_platform_data },
+ { .compatible = "mediatek,mt8183", .data = &mt2701_platform_data },
+ { .compatible = "mediatek,mt8365", .data = &mt2701_platform_data },
+ { .compatible = "mediatek,mt8516", .data = &mt2701_platform_data },
{ }
};
MODULE_DEVICE_TABLE(of, mtk_cpufreq_machines);
@@ -580,6 +609,7 @@ static int __init mtk_cpufreq_driver_ini
{
struct device_node *np;
const struct of_device_id *match;
+ const struct mtk_cpufreq_platform_data *data;
int err;
np = of_find_node_by_path("/");
@@ -592,6 +622,7 @@ static int __init mtk_cpufreq_driver_ini
pr_debug("Machine is not compatible with mtk-cpufreq\n");
return -ENODEV;
}
+ data = match->data;
err = platform_driver_register(&mtk_cpufreq_platdrv);
if (err)
@@ -603,7 +634,8 @@ static int __init mtk_cpufreq_driver_ini
* and the device registration codes are put here to handle defer
* probing.
*/
- cpufreq_pdev = platform_device_register_simple("mtk-cpufreq", -1, NULL, 0);
+ cpufreq_pdev = platform_device_register_data(NULL, "mtk-cpufreq", -1,
+ data, sizeof(*data));
if (IS_ERR(cpufreq_pdev)) {
pr_err("failed to register mtk-cpufreq platform device\n");
platform_driver_unregister(&mtk_cpufreq_platdrv);

View File

@ -0,0 +1,255 @@
From 944b041c91f1e1cd762c39c1222f078550149486 Mon Sep 17 00:00:00 2001
From: Jia-Wei Chang <jia-wei.chang@mediatek.com>
Date: Thu, 5 May 2022 19:52:20 +0800
Subject: [PATCH 10/21] cpufreq: mediatek: Refine
mtk_cpufreq_voltage_tracking()
Because the difference of sram and proc should in a range of min_volt_shift
and max_volt_shift. We need to adjust the sram and proc step by step.
We replace VOLT_TOL (voltage tolerance) with the platform data and update the
logic to determine the voltage boundary and invoking regulator_set_voltage.
- Use 'sram_min_volt' and 'sram_max_volt' to determine the voltage boundary
of sram regulator.
- Use (sram_min_volt - min_volt_shift) and 'proc_max_volt' to determine the
voltage boundary of vproc regulator.
Moreover, to prevent infinite loop when tracking voltage, we calculate the
maximum value for each platform data.
We assume min voltage is 0 and tracking target voltage using
min_volt_shift for each iteration.
The retry_max is 3 times of expeted iteration count.
Signed-off-by: Jia-Wei Chang <jia-wei.chang@mediatek.com>
Signed-off-by: Rex-BC Chen <rex-bc.chen@mediatek.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
drivers/cpufreq/mediatek-cpufreq.c | 147 ++++++++++-------------------
1 file changed, 51 insertions(+), 96 deletions(-)
--- a/drivers/cpufreq/mediatek-cpufreq.c
+++ b/drivers/cpufreq/mediatek-cpufreq.c
@@ -8,6 +8,7 @@
#include <linux/cpu.h>
#include <linux/cpufreq.h>
#include <linux/cpumask.h>
+#include <linux/minmax.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
@@ -15,8 +16,6 @@
#include <linux/pm_opp.h>
#include <linux/regulator/consumer.h>
-#define VOLT_TOL (10000)
-
struct mtk_cpufreq_platform_data {
int min_volt_shift;
int max_volt_shift;
@@ -48,6 +47,7 @@ struct mtk_cpu_dvfs_info {
bool need_voltage_tracking;
int pre_vproc;
const struct mtk_cpufreq_platform_data *soc_data;
+ int vtrack_max;
};
static struct platform_device *cpufreq_pdev;
@@ -73,6 +73,7 @@ static int mtk_cpufreq_voltage_tracking(
struct regulator *proc_reg = info->proc_reg;
struct regulator *sram_reg = info->sram_reg;
int pre_vproc, pre_vsram, new_vsram, vsram, vproc, ret;
+ int retry = info->vtrack_max;
pre_vproc = regulator_get_voltage(proc_reg);
if (pre_vproc < 0) {
@@ -80,91 +81,44 @@ static int mtk_cpufreq_voltage_tracking(
"invalid Vproc value: %d\n", pre_vproc);
return pre_vproc;
}
- /* Vsram should not exceed the maximum allowed voltage of SoC. */
- new_vsram = min(new_vproc + soc_data->min_volt_shift,
- soc_data->sram_max_volt);
-
- if (pre_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 {
- pre_vsram = regulator_get_voltage(sram_reg);
- if (pre_vsram < 0) {
- dev_err(info->cpu_dev,
- "invalid Vsram value: %d\n", pre_vsram);
- return pre_vsram;
- }
- pre_vproc = regulator_get_voltage(proc_reg);
- if (pre_vproc < 0) {
- dev_err(info->cpu_dev,
- "invalid Vproc value: %d\n", pre_vproc);
- return pre_vproc;
- }
- vsram = min(new_vsram,
- pre_vproc + soc_data->min_volt_shift);
+ pre_vsram = regulator_get_voltage(sram_reg);
+ if (pre_vsram < 0) {
+ dev_err(info->cpu_dev, "invalid Vsram value: %d\n", pre_vsram);
+ return pre_vsram;
+ }
- if (vsram + VOLT_TOL >= soc_data->sram_max_volt) {
- vsram = soc_data->sram_max_volt;
+ new_vsram = clamp(new_vproc + soc_data->min_volt_shift,
+ soc_data->sram_min_volt, soc_data->sram_max_volt);
+
+ do {
+ if (pre_vproc <= new_vproc) {
+ vsram = clamp(pre_vproc + soc_data->max_volt_shift,
+ soc_data->sram_min_volt, new_vsram);
+ ret = regulator_set_voltage(sram_reg, vsram,
+ soc_data->sram_max_volt);
- /*
- * 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);
+ if (ret)
+ return ret;
+ if (vsram == soc_data->sram_max_volt ||
+ new_vsram == soc_data->sram_min_volt)
vproc = new_vproc;
- } else {
- ret = regulator_set_voltage(sram_reg, vsram,
- vsram + VOLT_TOL);
-
+ else
vproc = vsram - soc_data->min_volt_shift;
- }
- if (ret)
- return ret;
ret = regulator_set_voltage(proc_reg, vproc,
- vproc + VOLT_TOL);
+ soc_data->proc_max_volt);
if (ret) {
regulator_set_voltage(sram_reg, pre_vsram,
- pre_vsram);
+ soc_data->sram_max_volt);
return ret;
}
- } while (vproc < new_vproc || vsram < new_vsram);
- } else if (pre_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 {
- pre_vproc = regulator_get_voltage(proc_reg);
- if (pre_vproc < 0) {
- dev_err(info->cpu_dev,
- "invalid Vproc value: %d\n", pre_vproc);
- return pre_vproc;
- }
- pre_vsram = regulator_get_voltage(sram_reg);
- if (pre_vsram < 0) {
- dev_err(info->cpu_dev,
- "invalid Vsram value: %d\n", pre_vsram);
- return pre_vsram;
- }
-
+ } else if (pre_vproc > new_vproc) {
vproc = max(new_vproc,
pre_vsram - soc_data->max_volt_shift);
ret = regulator_set_voltage(proc_reg, vproc,
- vproc + VOLT_TOL);
+ soc_data->proc_max_volt);
if (ret)
return ret;
@@ -174,32 +128,24 @@ static int mtk_cpufreq_voltage_tracking(
vsram = max(new_vsram,
vproc + soc_data->min_volt_shift);
- if (vsram + VOLT_TOL >= soc_data->sram_max_volt) {
- vsram = soc_data->sram_max_volt;
-
- /*
- * 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);
- }
-
+ ret = regulator_set_voltage(sram_reg, vsram,
+ soc_data->sram_max_volt);
if (ret) {
regulator_set_voltage(proc_reg, pre_vproc,
- pre_vproc);
+ soc_data->proc_max_volt);
return ret;
}
- } while (vproc > new_vproc + VOLT_TOL ||
- vsram > new_vsram + VOLT_TOL);
- }
+ }
+
+ pre_vproc = vproc;
+ pre_vsram = vsram;
+
+ if (--retry < 0) {
+ dev_err(info->cpu_dev,
+ "over loop count, failed to set voltage\n");
+ return -EINVAL;
+ }
+ } while (vproc != new_vproc || vsram != new_vsram);
return 0;
}
@@ -261,8 +207,8 @@ static int mtk_cpufreq_set_target(struct
* 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 (pre_vproc < target_vproc) {
+ target_vproc = max(inter_vproc, vproc);
+ if (pre_vproc <= target_vproc) {
ret = mtk_cpufreq_set_voltage(info, target_vproc);
if (ret) {
dev_err(cpu_dev,
@@ -417,6 +363,15 @@ static int mtk_cpu_dvfs_info_init(struct
*/
info->need_voltage_tracking = (info->sram_reg != NULL);
+ /*
+ * We assume min voltage is 0 and tracking target voltage using
+ * min_volt_shift for each iteration.
+ * The vtrack_max is 3 times of expeted iteration count.
+ */
+ info->vtrack_max = 3 * DIV_ROUND_UP(max(info->soc_data->sram_max_volt,
+ info->soc_data->proc_max_volt),
+ info->soc_data->min_volt_shift);
+
return 0;
out_disable_inter_clock:

View File

@ -0,0 +1,184 @@
From 01be227eff7e5fc01f7c8de8f6daddd5fb17ddd1 Mon Sep 17 00:00:00 2001
From: Rex-BC Chen <rex-bc.chen@mediatek.com>
Date: Thu, 5 May 2022 19:52:21 +0800
Subject: [PATCH 11/21] cpufreq: mediatek: Add opp notification support
From this opp notifier, cpufreq should listen to opp notification and do
proper actions when receiving events of disable and voltage adjustment.
One of the user for this opp notifier is MediaTek SVS.
The MediaTek Smart Voltage Scaling (SVS) is a hardware which calculates
suitable SVS bank voltages to OPP voltage table.
Signed-off-by: Andrew-sh.Cheng <andrew-sh.cheng@mediatek.com>
Signed-off-by: Jia-Wei Chang <jia-wei.chang@mediatek.com>
Signed-off-by: Rex-BC Chen <rex-bc.chen@mediatek.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
[ Viresh: Renamed opp_freq as current_freq and moved its initialization ]
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
drivers/cpufreq/mediatek-cpufreq.c | 90 +++++++++++++++++++++++++++---
1 file changed, 82 insertions(+), 8 deletions(-)
--- a/drivers/cpufreq/mediatek-cpufreq.c
+++ b/drivers/cpufreq/mediatek-cpufreq.c
@@ -46,6 +46,11 @@ struct mtk_cpu_dvfs_info {
int intermediate_voltage;
bool need_voltage_tracking;
int pre_vproc;
+ /* Avoid race condition for regulators between notify and policy */
+ struct mutex reg_lock;
+ struct notifier_block opp_nb;
+ unsigned int opp_cpu;
+ unsigned long current_freq;
const struct mtk_cpufreq_platform_data *soc_data;
int vtrack_max;
};
@@ -182,6 +187,8 @@ static int mtk_cpufreq_set_target(struct
pre_freq_hz = clk_get_rate(cpu_clk);
+ mutex_lock(&info->reg_lock);
+
if (unlikely(info->pre_vproc <= 0))
pre_vproc = regulator_get_voltage(info->proc_reg);
else
@@ -214,7 +221,7 @@ static int mtk_cpufreq_set_target(struct
dev_err(cpu_dev,
"cpu%d: failed to scale up voltage!\n", policy->cpu);
mtk_cpufreq_set_voltage(info, pre_vproc);
- return ret;
+ goto out;
}
}
@@ -224,8 +231,7 @@ static int mtk_cpufreq_set_target(struct
dev_err(cpu_dev,
"cpu%d: failed to re-parent cpu clock!\n", policy->cpu);
mtk_cpufreq_set_voltage(info, pre_vproc);
- WARN_ON(1);
- return ret;
+ goto out;
}
/* Set the original PLL to target rate. */
@@ -235,7 +241,7 @@ static int mtk_cpufreq_set_target(struct
"cpu%d: failed to scale cpu clock rate!\n", policy->cpu);
clk_set_parent(cpu_clk, armpll);
mtk_cpufreq_set_voltage(info, pre_vproc);
- return ret;
+ goto out;
}
/* Set parent of CPU clock back to the original PLL. */
@@ -244,8 +250,7 @@ static int mtk_cpufreq_set_target(struct
dev_err(cpu_dev,
"cpu%d: failed to re-parent cpu clock!\n", policy->cpu);
mtk_cpufreq_set_voltage(info, inter_vproc);
- WARN_ON(1);
- return ret;
+ goto out;
}
/*
@@ -260,15 +265,72 @@ static int mtk_cpufreq_set_target(struct
clk_set_parent(cpu_clk, info->inter_clk);
clk_set_rate(armpll, pre_freq_hz);
clk_set_parent(cpu_clk, armpll);
- return ret;
+ goto out;
}
}
- return 0;
+ info->current_freq = freq_hz;
+
+out:
+ mutex_unlock(&info->reg_lock);
+
+ return ret;
}
#define DYNAMIC_POWER "dynamic-power-coefficient"
+static int mtk_cpufreq_opp_notifier(struct notifier_block *nb,
+ unsigned long event, void *data)
+{
+ struct dev_pm_opp *opp = data;
+ struct dev_pm_opp *new_opp;
+ struct mtk_cpu_dvfs_info *info;
+ unsigned long freq, volt;
+ struct cpufreq_policy *policy;
+ int ret = 0;
+
+ info = container_of(nb, struct mtk_cpu_dvfs_info, opp_nb);
+
+ if (event == OPP_EVENT_ADJUST_VOLTAGE) {
+ freq = dev_pm_opp_get_freq(opp);
+
+ mutex_lock(&info->reg_lock);
+ if (info->current_freq == freq) {
+ volt = dev_pm_opp_get_voltage(opp);
+ ret = mtk_cpufreq_set_voltage(info, volt);
+ if (ret)
+ dev_err(info->cpu_dev,
+ "failed to scale voltage: %d\n", ret);
+ }
+ mutex_unlock(&info->reg_lock);
+ } else if (event == OPP_EVENT_DISABLE) {
+ freq = dev_pm_opp_get_freq(opp);
+
+ /* case of current opp item is disabled */
+ if (info->current_freq == freq) {
+ freq = 1;
+ new_opp = dev_pm_opp_find_freq_ceil(info->cpu_dev,
+ &freq);
+ if (IS_ERR(new_opp)) {
+ dev_err(info->cpu_dev,
+ "all opp items are disabled\n");
+ ret = PTR_ERR(new_opp);
+ return notifier_from_errno(ret);
+ }
+
+ dev_pm_opp_put(new_opp);
+ policy = cpufreq_cpu_get(info->opp_cpu);
+ if (policy) {
+ cpufreq_driver_target(policy, freq / 1000,
+ CPUFREQ_RELATION_L);
+ cpufreq_cpu_put(policy);
+ }
+ }
+ }
+
+ return notifier_from_errno(ret);
+}
+
static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
{
struct device *cpu_dev;
@@ -357,6 +419,17 @@ static int mtk_cpu_dvfs_info_init(struct
info->intermediate_voltage = dev_pm_opp_get_voltage(opp);
dev_pm_opp_put(opp);
+ mutex_init(&info->reg_lock);
+ info->current_freq = clk_get_rate(info->cpu_clk);
+
+ info->opp_cpu = cpu;
+ info->opp_nb.notifier_call = mtk_cpufreq_opp_notifier;
+ ret = dev_pm_opp_register_notifier(cpu_dev, &info->opp_nb);
+ if (ret) {
+ dev_err(cpu_dev, "cpu%d: failed to register opp notifier\n", cpu);
+ goto out_disable_inter_clock;
+ }
+
/*
* If SRAM regulator is present, software "voltage tracking" is needed
* for this CPU power domain.
@@ -421,6 +494,7 @@ static void mtk_cpu_dvfs_info_release(st
}
dev_pm_opp_of_cpumask_remove_table(&info->cpus);
+ dev_pm_opp_unregister_notifier(info->cpu_dev, &info->opp_nb);
}
static int mtk_cpufreq_init(struct cpufreq_policy *policy)

View File

@ -0,0 +1,43 @@
From 6a1bd7cf4ed7a1948f564aaf16d34b7352c0029b Mon Sep 17 00:00:00 2001
From: Wan Jiabing <wanjiabing@vivo.com>
Date: Tue, 10 May 2022 17:05:31 +0800
Subject: [PATCH 12/21] cpufreq: mediatek: Fix potential deadlock problem in
mtk_cpufreq_set_target
Fix following coccichek error:
./drivers/cpufreq/mediatek-cpufreq.c:199:2-8: preceding lock on line
./drivers/cpufreq/mediatek-cpufreq.c:208:2-8: preceding lock on line
mutex_lock is acquired but not released before return.
Use 'goto out' to help releasing the mutex_lock.
Fixes: c210063b40ac ("cpufreq: mediatek: Add opp notification support")
Signed-off-by: Wan Jiabing <wanjiabing@vivo.com>
Reviewed-by: Rex-BC Chen <rex-bc.chen@mediatek.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
drivers/cpufreq/mediatek-cpufreq.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
--- a/drivers/cpufreq/mediatek-cpufreq.c
+++ b/drivers/cpufreq/mediatek-cpufreq.c
@@ -196,7 +196,8 @@ static int mtk_cpufreq_set_target(struct
if (pre_vproc < 0) {
dev_err(cpu_dev, "invalid Vproc value: %d\n", pre_vproc);
- return pre_vproc;
+ ret = pre_vproc;
+ goto out;
}
freq_hz = freq_table[index].frequency * 1000;
@@ -205,7 +206,8 @@ static int mtk_cpufreq_set_target(struct
if (IS_ERR(opp)) {
dev_err(cpu_dev, "cpu%d: failed to find OPP for %ld\n",
policy->cpu, freq_hz);
- return PTR_ERR(opp);
+ ret = PTR_ERR(opp);
+ goto out;
}
vproc = dev_pm_opp_get_voltage(opp);
dev_pm_opp_put(opp);

View File

@ -0,0 +1,188 @@
From 15aaf74fb734a3e69b10d00b97b322711b81e222 Mon Sep 17 00:00:00 2001
From: Rex-BC Chen <rex-bc.chen@mediatek.com>
Date: Thu, 5 May 2022 19:52:22 +0800
Subject: [PATCH 13/21] cpufreq: mediatek: Link CCI device to CPU
In some MediaTek SoCs, like MT8183, CPU and CCI share the same power
supplies. Cpufreq needs to check if CCI devfreq exists and wait until
CCI devfreq ready before scaling frequency.
Before CCI devfreq is ready, we record the voltage when booting to
kernel and use the max(cpu target voltage, booting voltage) to
prevent cpufreq adjust to the lower voltage which will cause the CCI
crash because of high frequency and low voltage.
- Add is_ccifreq_ready() to link CCI device to CPI, and CPU will start
DVFS when CCI is ready.
- Add platform data for MT8183.
Signed-off-by: Jia-Wei Chang <jia-wei.chang@mediatek.com>
Signed-off-by: Rex-BC Chen <rex-bc.chen@mediatek.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Reviewed-by: Kevin Hilman <khilman@baylibre.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
drivers/cpufreq/mediatek-cpufreq.c | 82 +++++++++++++++++++++++++++++-
1 file changed, 81 insertions(+), 1 deletion(-)
--- a/drivers/cpufreq/mediatek-cpufreq.c
+++ b/drivers/cpufreq/mediatek-cpufreq.c
@@ -22,6 +22,7 @@ struct mtk_cpufreq_platform_data {
int proc_max_volt;
int sram_min_volt;
int sram_max_volt;
+ bool ccifreq_supported;
};
/*
@@ -38,6 +39,7 @@ struct mtk_cpufreq_platform_data {
struct mtk_cpu_dvfs_info {
struct cpumask cpus;
struct device *cpu_dev;
+ struct device *cci_dev;
struct regulator *proc_reg;
struct regulator *sram_reg;
struct clk *cpu_clk;
@@ -45,6 +47,7 @@ struct mtk_cpu_dvfs_info {
struct list_head list_head;
int intermediate_voltage;
bool need_voltage_tracking;
+ int vproc_on_boot;
int pre_vproc;
/* Avoid race condition for regulators between notify and policy */
struct mutex reg_lock;
@@ -53,6 +56,7 @@ struct mtk_cpu_dvfs_info {
unsigned long current_freq;
const struct mtk_cpufreq_platform_data *soc_data;
int vtrack_max;
+ bool ccifreq_bound;
};
static struct platform_device *cpufreq_pdev;
@@ -171,6 +175,28 @@ static int mtk_cpufreq_set_voltage(struc
return ret;
}
+static bool is_ccifreq_ready(struct mtk_cpu_dvfs_info *info)
+{
+ struct device_link *sup_link;
+
+ if (info->ccifreq_bound)
+ return true;
+
+ sup_link = device_link_add(info->cpu_dev, info->cci_dev,
+ DL_FLAG_AUTOREMOVE_CONSUMER);
+ if (!sup_link) {
+ dev_err(info->cpu_dev, "cpu%d: sup_link is NULL\n", info->opp_cpu);
+ return false;
+ }
+
+ if (sup_link->supplier->links.status != DL_DEV_DRIVER_BOUND)
+ return false;
+
+ info->ccifreq_bound = true;
+
+ return true;
+}
+
static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
unsigned int index)
{
@@ -213,6 +239,14 @@ static int mtk_cpufreq_set_target(struct
dev_pm_opp_put(opp);
/*
+ * If MediaTek cci is supported but is not ready, we will use the value
+ * of max(target cpu voltage, booting voltage) to prevent high freqeuncy
+ * low voltage crash.
+ */
+ if (info->soc_data->ccifreq_supported && !is_ccifreq_ready(info))
+ vproc = max(vproc, info->vproc_on_boot);
+
+ /*
* If the new voltage or the intermediate voltage is higher than the
* current voltage, scale up voltage first.
*/
@@ -333,6 +367,23 @@ static int mtk_cpufreq_opp_notifier(stru
return notifier_from_errno(ret);
}
+static struct device *of_get_cci(struct device *cpu_dev)
+{
+ struct device_node *np;
+ struct platform_device *pdev;
+
+ np = of_parse_phandle(cpu_dev->of_node, "mediatek,cci", 0);
+ if (IS_ERR_OR_NULL(np))
+ return NULL;
+
+ pdev = of_find_device_by_node(np);
+ of_node_put(np);
+ if (IS_ERR_OR_NULL(pdev))
+ return NULL;
+
+ return &pdev->dev;
+}
+
static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
{
struct device *cpu_dev;
@@ -347,6 +398,16 @@ static int mtk_cpu_dvfs_info_init(struct
}
info->cpu_dev = cpu_dev;
+ info->ccifreq_bound = false;
+ if (info->soc_data->ccifreq_supported) {
+ info->cci_dev = of_get_cci(info->cpu_dev);
+ if (IS_ERR_OR_NULL(info->cci_dev)) {
+ ret = PTR_ERR(info->cci_dev);
+ dev_err(cpu_dev, "cpu%d: failed to get cci device\n", cpu);
+ return -ENODEV;
+ }
+ }
+
info->cpu_clk = clk_get(cpu_dev, "cpu");
if (IS_ERR(info->cpu_clk)) {
ret = PTR_ERR(info->cpu_clk);
@@ -410,6 +471,15 @@ static int mtk_cpu_dvfs_info_init(struct
if (ret)
goto out_disable_mux_clock;
+ if (info->soc_data->ccifreq_supported) {
+ info->vproc_on_boot = regulator_get_voltage(info->proc_reg);
+ if (info->vproc_on_boot < 0) {
+ dev_err(info->cpu_dev,
+ "invalid Vproc value: %d\n", info->vproc_on_boot);
+ goto out_disable_inter_clock;
+ }
+ }
+
/* Search a safe voltage for intermediate frequency. */
rate = clk_get_rate(info->inter_clk);
opp = dev_pm_opp_find_freq_ceil(cpu_dev, &rate);
@@ -617,6 +687,16 @@ static const struct mtk_cpufreq_platform
.proc_max_volt = 1150000,
.sram_min_volt = 0,
.sram_max_volt = 1150000,
+ .ccifreq_supported = false,
+};
+
+static const struct mtk_cpufreq_platform_data mt8183_platform_data = {
+ .min_volt_shift = 100000,
+ .max_volt_shift = 200000,
+ .proc_max_volt = 1150000,
+ .sram_min_volt = 0,
+ .sram_max_volt = 1150000,
+ .ccifreq_supported = true,
};
/* List of machines supported by this driver */
@@ -629,7 +709,7 @@ static const struct of_device_id mtk_cpu
{ .compatible = "mediatek,mt817x", .data = &mt2701_platform_data },
{ .compatible = "mediatek,mt8173", .data = &mt2701_platform_data },
{ .compatible = "mediatek,mt8176", .data = &mt2701_platform_data },
- { .compatible = "mediatek,mt8183", .data = &mt2701_platform_data },
+ { .compatible = "mediatek,mt8183", .data = &mt8183_platform_data },
{ .compatible = "mediatek,mt8365", .data = &mt2701_platform_data },
{ .compatible = "mediatek,mt8516", .data = &mt2701_platform_data },
{ }

View File

@ -0,0 +1,42 @@
From b6be0baa6615afc65c3963adab674e36af1d4d5f Mon Sep 17 00:00:00 2001
From: Jia-Wei Chang <jia-wei.chang@mediatek.com>
Date: Thu, 5 May 2022 19:52:23 +0800
Subject: [PATCH 14/21] cpufreq: mediatek: Add support for MT8186
The platform data of MT8186 is different from previous MediaTek SoCs,
so we add a new compatible and platform data for it.
Signed-off-by: Jia-Wei Chang <jia-wei.chang@mediatek.com>
Signed-off-by: Rex-BC Chen <rex-bc.chen@mediatek.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
drivers/cpufreq/mediatek-cpufreq.c | 10 ++++++++++
1 file changed, 10 insertions(+)
--- a/drivers/cpufreq/mediatek-cpufreq.c
+++ b/drivers/cpufreq/mediatek-cpufreq.c
@@ -699,6 +699,15 @@ static const struct mtk_cpufreq_platform
.ccifreq_supported = true,
};
+static const struct mtk_cpufreq_platform_data mt8186_platform_data = {
+ .min_volt_shift = 100000,
+ .max_volt_shift = 250000,
+ .proc_max_volt = 1118750,
+ .sram_min_volt = 850000,
+ .sram_max_volt = 1118750,
+ .ccifreq_supported = true,
+};
+
/* List of machines supported by this driver */
static const struct of_device_id mtk_cpufreq_machines[] __initconst = {
{ .compatible = "mediatek,mt2701", .data = &mt2701_platform_data },
@@ -710,6 +719,7 @@ static const struct of_device_id mtk_cpu
{ .compatible = "mediatek,mt8173", .data = &mt2701_platform_data },
{ .compatible = "mediatek,mt8176", .data = &mt2701_platform_data },
{ .compatible = "mediatek,mt8183", .data = &mt8183_platform_data },
+ { .compatible = "mediatek,mt8186", .data = &mt8186_platform_data },
{ .compatible = "mediatek,mt8365", .data = &mt2701_platform_data },
{ .compatible = "mediatek,mt8516", .data = &mt2701_platform_data },
{ }

View File

@ -0,0 +1,35 @@
From 75d19b24aa3203d6c78e4c431c2cc07157ce12fe Mon Sep 17 00:00:00 2001
From: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Date: Wed, 13 Jul 2022 13:15:36 +0200
Subject: [PATCH 15/21] cpufreq: mediatek: Handle sram regulator probe deferral
If the regulator_get_optional() call for the SRAM regulator returns
a probe deferral, we must bail out and retry probing later: failing
to do this will produce unstabilities on platforms requiring the
handling for this regulator.
Fixes: ffa7bdf7f344 ("cpufreq: mediatek: Make sram regulator optional")
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
drivers/cpufreq/mediatek-cpufreq.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
--- a/drivers/cpufreq/mediatek-cpufreq.c
+++ b/drivers/cpufreq/mediatek-cpufreq.c
@@ -439,9 +439,13 @@ static int mtk_cpu_dvfs_info_init(struct
/* Both presence and absence of sram regulator are valid cases. */
info->sram_reg = regulator_get_optional(cpu_dev, "sram");
- if (IS_ERR(info->sram_reg))
+ if (IS_ERR(info->sram_reg)) {
+ ret = PTR_ERR(info->sram_reg);
+ if (ret == -EPROBE_DEFER)
+ goto out_free_resources;
+
info->sram_reg = NULL;
- else {
+ } else {
ret = regulator_enable(info->sram_reg);
if (ret) {
dev_warn(cpu_dev, "cpu%d: failed to enable vsram\n", cpu);

View File

@ -0,0 +1,29 @@
From dd1174c21dacacd6c0129c1dabc5decad35c02c2 Mon Sep 17 00:00:00 2001
From: Yang Yingliang <yangyingliang@huawei.com>
Date: Tue, 17 May 2022 21:34:50 +0800
Subject: [PATCH 16/21] cpufreq: mediatek: fix error return code in
mtk_cpu_dvfs_info_init()
If regulator_get_voltage() fails, it should return the error code in
mtk_cpu_dvfs_info_init().
Fixes: 0daa47325bae ("cpufreq: mediatek: Link CCI device to CPU")
Reported-by: Hulk Robot <hulkci@huawei.com>
Signed-off-by: Yang Yingliang <yangyingliang@huawei.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Reviewed-by: Rex-BC Chen <rex-bc.chen@mediatek.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
drivers/cpufreq/mediatek-cpufreq.c | 1 +
1 file changed, 1 insertion(+)
--- a/drivers/cpufreq/mediatek-cpufreq.c
+++ b/drivers/cpufreq/mediatek-cpufreq.c
@@ -478,6 +478,7 @@ static int mtk_cpu_dvfs_info_init(struct
if (info->soc_data->ccifreq_supported) {
info->vproc_on_boot = regulator_get_voltage(info->proc_reg);
if (info->vproc_on_boot < 0) {
+ ret = info->vproc_on_boot;
dev_err(info->cpu_dev,
"invalid Vproc value: %d\n", info->vproc_on_boot);
goto out_disable_inter_clock;

View File

@ -0,0 +1,47 @@
From 230a74d459244411db91bfd678f17fcf7aedfcd0 Mon Sep 17 00:00:00 2001
From: Jia-Wei Chang <jia-wei.chang@mediatek.com>
Date: Fri, 24 Mar 2023 18:11:27 +0800
Subject: [PATCH 17/21] cpufreq: mediatek: fix passing zero to 'PTR_ERR'
In order to prevent passing zero to 'PTR_ERR' in
mtk_cpu_dvfs_info_init(), we fix the return value of of_get_cci() using
error pointer by explicitly casting error number.
Signed-off-by: Jia-Wei Chang <jia-wei.chang@mediatek.com>
Fixes: 0daa47325bae ("cpufreq: mediatek: Link CCI device to CPU")
Reported-by: Dan Carpenter <error27@gmail.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
drivers/cpufreq/mediatek-cpufreq.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
--- a/drivers/cpufreq/mediatek-cpufreq.c
+++ b/drivers/cpufreq/mediatek-cpufreq.c
@@ -373,13 +373,13 @@ static struct device *of_get_cci(struct
struct platform_device *pdev;
np = of_parse_phandle(cpu_dev->of_node, "mediatek,cci", 0);
- if (IS_ERR_OR_NULL(np))
- return NULL;
+ if (!np)
+ return ERR_PTR(-ENODEV);
pdev = of_find_device_by_node(np);
of_node_put(np);
- if (IS_ERR_OR_NULL(pdev))
- return NULL;
+ if (!pdev)
+ return ERR_PTR(-ENODEV);
return &pdev->dev;
}
@@ -401,7 +401,7 @@ static int mtk_cpu_dvfs_info_init(struct
info->ccifreq_bound = false;
if (info->soc_data->ccifreq_supported) {
info->cci_dev = of_get_cci(info->cpu_dev);
- if (IS_ERR_OR_NULL(info->cci_dev)) {
+ if (IS_ERR(info->cci_dev)) {
ret = PTR_ERR(info->cci_dev);
dev_err(cpu_dev, "cpu%d: failed to get cci device\n", cpu);
return -ENODEV;

View File

@ -0,0 +1,149 @@
From fced531b7c7e18192e7982637c8e8f20c29aad64 Mon Sep 17 00:00:00 2001
From: Jia-Wei Chang <jia-wei.chang@mediatek.com>
Date: Fri, 24 Mar 2023 18:11:28 +0800
Subject: [PATCH 18/21] cpufreq: mediatek: fix KP caused by handler usage after
regulator_put/clk_put
Any kind of failure in mtk_cpu_dvfs_info_init() will lead to calling
regulator_put() or clk_put() and the KP will occur since the regulator/clk
handlers are used after released in mtk_cpu_dvfs_info_release().
To prevent the usage after regulator_put()/clk_put(), the regulator/clk
handlers are addressed in a way of "Free the Last Thing Style".
Signed-off-by: Jia-Wei Chang <jia-wei.chang@mediatek.com>
Fixes: 4b9ceb757bbb ("cpufreq: mediatek: Enable clocks and regulators")
Suggested-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Suggested-by: Dan Carpenter <error27@gmail.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
drivers/cpufreq/mediatek-cpufreq.c | 62 +++++++++++++++---------------
1 file changed, 30 insertions(+), 32 deletions(-)
--- a/drivers/cpufreq/mediatek-cpufreq.c
+++ b/drivers/cpufreq/mediatek-cpufreq.c
@@ -420,7 +420,7 @@ static int mtk_cpu_dvfs_info_init(struct
ret = PTR_ERR(info->inter_clk);
dev_err_probe(cpu_dev, ret,
"cpu%d: failed to get intermediate clk\n", cpu);
- goto out_free_resources;
+ goto out_free_mux_clock;
}
info->proc_reg = regulator_get_optional(cpu_dev, "proc");
@@ -428,13 +428,13 @@ static int mtk_cpu_dvfs_info_init(struct
ret = PTR_ERR(info->proc_reg);
dev_err_probe(cpu_dev, ret,
"cpu%d: failed to get proc regulator\n", cpu);
- goto out_free_resources;
+ goto out_free_inter_clock;
}
ret = regulator_enable(info->proc_reg);
if (ret) {
dev_warn(cpu_dev, "cpu%d: failed to enable vproc\n", cpu);
- goto out_free_resources;
+ goto out_free_proc_reg;
}
/* Both presence and absence of sram regulator are valid cases. */
@@ -442,14 +442,14 @@ static int mtk_cpu_dvfs_info_init(struct
if (IS_ERR(info->sram_reg)) {
ret = PTR_ERR(info->sram_reg);
if (ret == -EPROBE_DEFER)
- goto out_free_resources;
+ goto out_disable_proc_reg;
info->sram_reg = NULL;
} else {
ret = regulator_enable(info->sram_reg);
if (ret) {
dev_warn(cpu_dev, "cpu%d: failed to enable vsram\n", cpu);
- goto out_free_resources;
+ goto out_free_sram_reg;
}
}
@@ -458,13 +458,13 @@ static int mtk_cpu_dvfs_info_init(struct
if (ret) {
dev_err(cpu_dev,
"cpu%d: failed to get OPP-sharing information\n", cpu);
- goto out_free_resources;
+ goto out_disable_sram_reg;
}
ret = dev_pm_opp_of_cpumask_add_table(&info->cpus);
if (ret) {
dev_warn(cpu_dev, "cpu%d: no OPP table\n", cpu);
- goto out_free_resources;
+ goto out_disable_sram_reg;
}
ret = clk_prepare_enable(info->cpu_clk);
@@ -533,43 +533,41 @@ out_disable_mux_clock:
out_free_opp_table:
dev_pm_opp_of_cpumask_remove_table(&info->cpus);
-out_free_resources:
- if (regulator_is_enabled(info->proc_reg))
- regulator_disable(info->proc_reg);
- if (info->sram_reg && regulator_is_enabled(info->sram_reg))
+out_disable_sram_reg:
+ if (info->sram_reg)
regulator_disable(info->sram_reg);
- if (!IS_ERR(info->proc_reg))
- regulator_put(info->proc_reg);
- if (!IS_ERR(info->sram_reg))
+out_free_sram_reg:
+ if (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);
+
+out_disable_proc_reg:
+ regulator_disable(info->proc_reg);
+
+out_free_proc_reg:
+ regulator_put(info->proc_reg);
+
+out_free_inter_clock:
+ clk_put(info->inter_clk);
+
+out_free_mux_clock:
+ clk_put(info->cpu_clk);
return ret;
}
static void mtk_cpu_dvfs_info_release(struct mtk_cpu_dvfs_info *info)
{
- if (!IS_ERR(info->proc_reg)) {
- regulator_disable(info->proc_reg);
- regulator_put(info->proc_reg);
- }
- if (!IS_ERR(info->sram_reg)) {
+ regulator_disable(info->proc_reg);
+ regulator_put(info->proc_reg);
+ if (info->sram_reg) {
regulator_disable(info->sram_reg);
regulator_put(info->sram_reg);
}
- if (!IS_ERR(info->cpu_clk)) {
- clk_disable_unprepare(info->cpu_clk);
- clk_put(info->cpu_clk);
- }
- if (!IS_ERR(info->inter_clk)) {
- clk_disable_unprepare(info->inter_clk);
- clk_put(info->inter_clk);
- }
-
+ clk_disable_unprepare(info->cpu_clk);
+ clk_put(info->cpu_clk);
+ clk_disable_unprepare(info->inter_clk);
+ clk_put(info->inter_clk);
dev_pm_opp_of_cpumask_remove_table(&info->cpus);
dev_pm_opp_unregister_notifier(info->cpu_dev, &info->opp_nb);
}

View File

@ -0,0 +1,55 @@
From 24bc42a2d44cb821818717a5c607270921ec5d20 Mon Sep 17 00:00:00 2001
From: Jia-Wei Chang <jia-wei.chang@mediatek.com>
Date: Fri, 24 Mar 2023 18:11:29 +0800
Subject: [PATCH 19/21] cpufreq: mediatek: raise proc/sram max voltage for
MT8516
Since the upper boundary of proc/sram voltage of MT8516 is 1300 mV,
which is greater than the value of MT2701 1150 mV, we fix it by adding
the corresponding platform data and specify proc/sram_max_volt to
support MT8516.
Signed-off-by: Jia-Wei Chang <jia-wei.chang@mediatek.com>
Fixes: ead858bd128d ("cpufreq: mediatek: Move voltage limits to platform data")
Fixes: 6a17b3876bc8 ("cpufreq: mediatek: Refine mtk_cpufreq_voltage_tracking()")
Reported-by: Nick Hainke <vincent@systemli.org>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
drivers/cpufreq/mediatek-cpufreq.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
--- a/drivers/cpufreq/mediatek-cpufreq.c
+++ b/drivers/cpufreq/mediatek-cpufreq.c
@@ -711,20 +711,29 @@ static const struct mtk_cpufreq_platform
.ccifreq_supported = true,
};
+static const struct mtk_cpufreq_platform_data mt8516_platform_data = {
+ .min_volt_shift = 100000,
+ .max_volt_shift = 200000,
+ .proc_max_volt = 1310000,
+ .sram_min_volt = 0,
+ .sram_max_volt = 1310000,
+ .ccifreq_supported = false,
+};
+
/* List of machines supported by this driver */
static const struct of_device_id mtk_cpufreq_machines[] __initconst = {
{ .compatible = "mediatek,mt2701", .data = &mt2701_platform_data },
{ .compatible = "mediatek,mt2712", .data = &mt2701_platform_data },
{ .compatible = "mediatek,mt7622", .data = &mt2701_platform_data },
{ .compatible = "mediatek,mt7623", .data = &mt2701_platform_data },
- { .compatible = "mediatek,mt8167", .data = &mt2701_platform_data },
+ { .compatible = "mediatek,mt8167", .data = &mt8516_platform_data },
{ .compatible = "mediatek,mt817x", .data = &mt2701_platform_data },
{ .compatible = "mediatek,mt8173", .data = &mt2701_platform_data },
{ .compatible = "mediatek,mt8176", .data = &mt2701_platform_data },
{ .compatible = "mediatek,mt8183", .data = &mt8183_platform_data },
{ .compatible = "mediatek,mt8186", .data = &mt8186_platform_data },
{ .compatible = "mediatek,mt8365", .data = &mt2701_platform_data },
- { .compatible = "mediatek,mt8516", .data = &mt2701_platform_data },
+ { .compatible = "mediatek,mt8516", .data = &mt8516_platform_data },
{ }
};
MODULE_DEVICE_TABLE(of, mtk_cpufreq_machines);

View File

@ -0,0 +1,58 @@
From fe6ef09358dc0cfead9d383a8676fbe7a40fcef7 Mon Sep 17 00:00:00 2001
From: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Date: Fri, 24 Mar 2023 18:11:30 +0800
Subject: [PATCH 20/21] cpufreq: mediatek: Raise proc and sram max voltage for
MT7622/7623
During the addition of SRAM voltage tracking for CCI scaling, this
driver got some voltage limits set for the vtrack algorithm: these
were moved to platform data first, then enforced in a later commit
6a17b3876bc8 ("cpufreq: mediatek: Refine mtk_cpufreq_voltage_tracking()")
using these as max values for the regulator_set_voltage() calls.
In this case, the vsram/vproc constraints for MT7622 and MT7623
were supposed to be the same as MT2701 (and a number of other SoCs),
but that turned out to be a mistake because the aforementioned two
SoCs' maximum voltage for both VPROC and VPROC_SRAM is 1.36V.
Fix that by adding new platform data for MT7622/7623 declaring the
right {proc,sram}_max_volt parameter.
Fixes: ead858bd128d ("cpufreq: mediatek: Move voltage limits to platform data")
Fixes: 6a17b3876bc8 ("cpufreq: mediatek: Refine mtk_cpufreq_voltage_tracking()")
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Signed-off-by: Jia-Wei Chang <jia-wei.chang@mediatek.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
drivers/cpufreq/mediatek-cpufreq.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
--- a/drivers/cpufreq/mediatek-cpufreq.c
+++ b/drivers/cpufreq/mediatek-cpufreq.c
@@ -693,6 +693,15 @@ static const struct mtk_cpufreq_platform
.ccifreq_supported = false,
};
+static const struct mtk_cpufreq_platform_data mt7622_platform_data = {
+ .min_volt_shift = 100000,
+ .max_volt_shift = 200000,
+ .proc_max_volt = 1360000,
+ .sram_min_volt = 0,
+ .sram_max_volt = 1360000,
+ .ccifreq_supported = false,
+};
+
static const struct mtk_cpufreq_platform_data mt8183_platform_data = {
.min_volt_shift = 100000,
.max_volt_shift = 200000,
@@ -724,8 +733,8 @@ static const struct mtk_cpufreq_platform
static const struct of_device_id mtk_cpufreq_machines[] __initconst = {
{ .compatible = "mediatek,mt2701", .data = &mt2701_platform_data },
{ .compatible = "mediatek,mt2712", .data = &mt2701_platform_data },
- { .compatible = "mediatek,mt7622", .data = &mt2701_platform_data },
- { .compatible = "mediatek,mt7623", .data = &mt2701_platform_data },
+ { .compatible = "mediatek,mt7622", .data = &mt7622_platform_data },
+ { .compatible = "mediatek,mt7623", .data = &mt7622_platform_data },
{ .compatible = "mediatek,mt8167", .data = &mt8516_platform_data },
{ .compatible = "mediatek,mt817x", .data = &mt2701_platform_data },
{ .compatible = "mediatek,mt8173", .data = &mt2701_platform_data },

View File

@ -0,0 +1,41 @@
From 4983a1517e7ddbc6f53fc07607e4ebeb51412843 Mon Sep 17 00:00:00 2001
From: Sam Shih <sam.shih@mediatek.com>
Date: Tue, 28 Feb 2023 19:59:22 +0800
Subject: [PATCH 21/21] cpufreq: mediatek: Add support for MT7988
This add cpufreq support for mediatek MT7988 SoC.
The platform data of MT7988 is different from previous MediaTek SoCs,
so we add a new compatible and platform data for it.
Signed-off-by: Sam Shih <sam.shih@mediatek.com>
---
drivers/cpufreq/mediatek-cpufreq.c | 10 ++++++++++
1 file changed, 10 insertions(+)
--- a/drivers/cpufreq/mediatek-cpufreq.c
+++ b/drivers/cpufreq/mediatek-cpufreq.c
@@ -702,6 +702,15 @@ static const struct mtk_cpufreq_platform
.ccifreq_supported = false,
};
+static const struct mtk_cpufreq_platform_data mt7988_platform_data = {
+ .min_volt_shift = 100000,
+ .max_volt_shift = 200000,
+ .proc_max_volt = 900000,
+ .sram_min_volt = 0,
+ .sram_max_volt = 1150000,
+ .ccifreq_supported = true,
+};
+
static const struct mtk_cpufreq_platform_data mt8183_platform_data = {
.min_volt_shift = 100000,
.max_volt_shift = 200000,
@@ -735,6 +744,7 @@ static const struct of_device_id mtk_cpu
{ .compatible = "mediatek,mt2712", .data = &mt2701_platform_data },
{ .compatible = "mediatek,mt7622", .data = &mt7622_platform_data },
{ .compatible = "mediatek,mt7623", .data = &mt7622_platform_data },
+ { .compatible = "mediatek,mt7988", .data = &mt7988_platform_data },
{ .compatible = "mediatek,mt8167", .data = &mt8516_platform_data },
{ .compatible = "mediatek,mt817x", .data = &mt2701_platform_data },
{ .compatible = "mediatek,mt8173", .data = &mt2701_platform_data },

View File

@ -0,0 +1,29 @@
From 20aad28ba5d62f1618408c264384d0b2ad7417db Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Mon, 22 May 2023 23:25:48 +0100
Subject: [PATCH] cpufreq: mediatek: don't request unsupported voltage
PMICs on MT7622 and MT7623 boards only support up to 1350000uV despite
the SoC's processor and SRAM voltage can be up to 1360000uV. As a
work-around specify max. processor and SRAM voltage as 1350000uV to
avoid requesting an unsupported voltage from the regulator.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/cpufreq/mediatek-cpufreq.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
--- a/drivers/cpufreq/mediatek-cpufreq.c
+++ b/drivers/cpufreq/mediatek-cpufreq.c
@@ -696,9 +696,9 @@ static const struct mtk_cpufreq_platform
static const struct mtk_cpufreq_platform_data mt7622_platform_data = {
.min_volt_shift = 100000,
.max_volt_shift = 200000,
- .proc_max_volt = 1360000,
+ .proc_max_volt = 1350000,
.sram_min_volt = 0,
- .sram_max_volt = 1360000,
+ .sram_max_volt = 1350000,
.ccifreq_supported = false,
};