--- /dev/null
+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;
+ }
--- /dev/null
+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)
--- /dev/null
+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);
+ }
--- /dev/null
+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;
+ }
+
--- /dev/null
+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;
+ }
--- /dev/null
+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;
--- /dev/null
+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 {
--- /dev/null
+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;
+ }
+
--- /dev/null
+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);
--- /dev/null
+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:
--- /dev/null
+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)
--- /dev/null
+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);
--- /dev/null
+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 },
+ { }
--- /dev/null
+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 },
+ { }
--- /dev/null
+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);
--- /dev/null
+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;
--- /dev/null
+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;
--- /dev/null
+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);
+ }
--- /dev/null
+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);
--- /dev/null
+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 },
--- /dev/null
+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 },
--- /dev/null
+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,
+ };
+