[openwrt/openwrt] mediatek: backport cpufreq changes to support MT7988

LEDE Commits lede-commits at lists.infradead.org
Thu May 25 01:40:29 PDT 2023


dangole pushed a commit to openwrt/openwrt.git, branch openwrt-23.05:
https://git.openwrt.org/670dedbbd71056fa60666a6c5f7bd84ebcf6a2a1

commit 670dedbbd71056fa60666a6c5f7bd84ebcf6a2a1
Author: Daniel Golle <daniel at makrotopia.org>
AuthorDate: Sun Apr 30 18:03:00 2023 +0100

    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 at makrotopia.org>
    (cherry picked from commit e4555d69a1c7c811188d8e257e77ac917d15f492)
---
 ...iatek-Cleanup-variables-and-error-handlin.patch | 166 ++++++++++++++
 ...02-cpufreq-mediatek-Remove-unused-headers.patch |  25 ++
 ...req-mediatek-Enable-clocks-and-regulators.patch | 117 ++++++++++
 ...eq-mediatek-Use-device-print-to-show-logs.patch | 161 +++++++++++++
 ...5-cpufreq-mediatek-Replace-old_-with-pre_.patch | 201 ++++++++++++++++
 ...diatek-Record-previous-target-vproc-value.patch |  64 ++++++
 ...req-mediatek-Make-sram-regulator-optional.patch |  30 +++
 ...iatek-Fix-NULL-pointer-dereference-in-med.patch |  32 +++
 ...iatek-Move-voltage-limits-to-platform-dat.patch | 227 ++++++++++++++++++
 ...iatek-Refine-mtk_cpufreq_voltage_tracking.patch | 255 +++++++++++++++++++++
 ...req-mediatek-Add-opp-notification-support.patch | 184 +++++++++++++++
 ...iatek-Fix-potential-deadlock-problem-in-m.patch |  43 ++++
 ...3-cpufreq-mediatek-Link-CCI-device-to-CPU.patch | 188 +++++++++++++++
 ...4-cpufreq-mediatek-Add-support-for-MT8186.patch |  42 ++++
 ...iatek-Handle-sram-regulator-probe-deferra.patch |  35 +++
 ...iatek-fix-error-return-code-in-mtk_cpu_dv.patch |  29 +++
 ...freq-mediatek-fix-passing-zero-to-PTR_ERR.patch |  47 ++++
 ...iatek-fix-KP-caused-by-handler-usage-afte.patch | 149 ++++++++++++
 ...iatek-raise-proc-sram-max-voltage-for-MT8.patch |  55 +++++
 ...iatek-Raise-proc-and-sram-max-voltage-for.patch |  58 +++++
 ...1-cpufreq-mediatek-Add-support-for-MT7988.patch |  41 ++++
 ...ediatek-don-t-request-unsupported-voltage.patch |  29 +++
 22 files changed, 2178 insertions(+)

diff --git a/target/linux/mediatek/patches-5.15/350-01-cpufreq-mediatek-Cleanup-variables-and-error-handlin.patch b/target/linux/mediatek/patches-5.15/350-01-cpufreq-mediatek-Cleanup-variables-and-error-handlin.patch
new file mode 100644
index 0000000000..8fad64a570
--- /dev/null
+++ b/target/linux/mediatek/patches-5.15/350-01-cpufreq-mediatek-Cleanup-variables-and-error-handlin.patch
@@ -0,0 +1,166 @@
+From 7a768326fdba542144833b9198a6d0edab52fad2 Mon Sep 17 00:00:00 2001
+From: Jia-Wei Chang <jia-wei.chang at 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 at mediatek.com>
+Signed-off-by: Rex-BC Chen <rex-bc.chen at mediatek.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
+Signed-off-by: Viresh Kumar <viresh.kumar at 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;
+ }
diff --git a/target/linux/mediatek/patches-5.15/350-02-cpufreq-mediatek-Remove-unused-headers.patch b/target/linux/mediatek/patches-5.15/350-02-cpufreq-mediatek-Remove-unused-headers.patch
new file mode 100644
index 0000000000..eebeeb0902
--- /dev/null
+++ b/target/linux/mediatek/patches-5.15/350-02-cpufreq-mediatek-Remove-unused-headers.patch
@@ -0,0 +1,25 @@
+From 756104b856d4bc3121420af3ced342f5fc2b2123 Mon Sep 17 00:00:00 2001
+From: Jia-Wei Chang <jia-wei.chang at 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 at mediatek.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
+Signed-off-by: Viresh Kumar <viresh.kumar at 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)
diff --git a/target/linux/mediatek/patches-5.15/350-03-cpufreq-mediatek-Enable-clocks-and-regulators.patch b/target/linux/mediatek/patches-5.15/350-03-cpufreq-mediatek-Enable-clocks-and-regulators.patch
new file mode 100644
index 0000000000..c97d5fc3d9
--- /dev/null
+++ b/target/linux/mediatek/patches-5.15/350-03-cpufreq-mediatek-Enable-clocks-and-regulators.patch
@@ -0,0 +1,117 @@
+From 342d5545e9f40496db9ae0d31c2427dd5f369a43 Mon Sep 17 00:00:00 2001
+From: Jia-Wei Chang <jia-wei.chang at 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 at mediatek.com>
+Signed-off-by: Jia-Wei Chang <jia-wei.chang at mediatek.com>
+Signed-off-by: Rex-BC Chen <rex-bc.chen at mediatek.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
+Signed-off-by: Viresh Kumar <viresh.kumar at 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);
+ }
diff --git a/target/linux/mediatek/patches-5.15/350-04-cpufreq-mediatek-Use-device-print-to-show-logs.patch b/target/linux/mediatek/patches-5.15/350-04-cpufreq-mediatek-Use-device-print-to-show-logs.patch
new file mode 100644
index 0000000000..18e1da728a
--- /dev/null
+++ b/target/linux/mediatek/patches-5.15/350-04-cpufreq-mediatek-Use-device-print-to-show-logs.patch
@@ -0,0 +1,161 @@
+From a02e2b359141035d2d6999940bc1b9f83ec88587 Mon Sep 17 00:00:00 2001
+From: Rex-BC Chen <rex-bc.chen at 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 at mediatek.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
+Signed-off-by: Viresh Kumar <viresh.kumar at 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;
+ 	}
+ 
diff --git a/target/linux/mediatek/patches-5.15/350-05-cpufreq-mediatek-Replace-old_-with-pre_.patch b/target/linux/mediatek/patches-5.15/350-05-cpufreq-mediatek-Replace-old_-with-pre_.patch
new file mode 100644
index 0000000000..8506f4e477
--- /dev/null
+++ b/target/linux/mediatek/patches-5.15/350-05-cpufreq-mediatek-Replace-old_-with-pre_.patch
@@ -0,0 +1,201 @@
+From 35832d9f9c5c1da01420d962dc56e7e61d104829 Mon Sep 17 00:00:00 2001
+From: Rex-BC Chen <rex-bc.chen at 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 at mediatek.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
+Signed-off-by: Viresh Kumar <viresh.kumar at 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;
+ 		}
diff --git a/target/linux/mediatek/patches-5.15/350-06-cpufreq-mediatek-Record-previous-target-vproc-value.patch b/target/linux/mediatek/patches-5.15/350-06-cpufreq-mediatek-Record-previous-target-vproc-value.patch
new file mode 100644
index 0000000000..94e6617d26
--- /dev/null
+++ b/target/linux/mediatek/patches-5.15/350-06-cpufreq-mediatek-Record-previous-target-vproc-value.patch
@@ -0,0 +1,64 @@
+From 34737eb8d0daa0d4183f10286a2f55d8788066bc Mon Sep 17 00:00:00 2001
+From: Jia-Wei Chang <jia-wei.chang at 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 at mediatek.com>
+Signed-off-by: Jia-Wei Chang <jia-wei.chang at mediatek.com>
+Signed-off-by: Rex-BC Chen <rex-bc.chen at mediatek.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
+Signed-off-by: Viresh Kumar <viresh.kumar at 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;
diff --git a/target/linux/mediatek/patches-5.15/350-07-cpufreq-mediatek-Make-sram-regulator-optional.patch b/target/linux/mediatek/patches-5.15/350-07-cpufreq-mediatek-Make-sram-regulator-optional.patch
new file mode 100644
index 0000000000..4b74873b15
--- /dev/null
+++ b/target/linux/mediatek/patches-5.15/350-07-cpufreq-mediatek-Make-sram-regulator-optional.patch
@@ -0,0 +1,30 @@
+From f6114c2bc563a8050e9dc874ad87e1448865f031 Mon Sep 17 00:00:00 2001
+From: Jia-Wei Chang <jia-wei.chang at 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 at mediatek.com>
+Signed-off-by: Rex-BC Chen <rex-bc.chen at mediatek.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
+Signed-off-by: Viresh Kumar <viresh.kumar at 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 {
diff --git a/target/linux/mediatek/patches-5.15/350-08-cpufreq-mediatek-Fix-NULL-pointer-dereference-in-med.patch b/target/linux/mediatek/patches-5.15/350-08-cpufreq-mediatek-Fix-NULL-pointer-dereference-in-med.patch
new file mode 100644
index 0000000000..f2f572a753
--- /dev/null
+++ b/target/linux/mediatek/patches-5.15/350-08-cpufreq-mediatek-Fix-NULL-pointer-dereference-in-med.patch
@@ -0,0 +1,32 @@
+From fa7030d8ad4638acfd9e0fac84a20716d031dc95 Mon Sep 17 00:00:00 2001
+From: Wan Jiabing <wanjiabing at 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 at vivo.com>
+Reviewed-by: Matthias Brugger <matthias.bgg at gmail.com>
+Signed-off-by: Viresh Kumar <viresh.kumar at 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;
+ 	}
+ 
diff --git a/target/linux/mediatek/patches-5.15/350-09-cpufreq-mediatek-Move-voltage-limits-to-platform-dat.patch b/target/linux/mediatek/patches-5.15/350-09-cpufreq-mediatek-Move-voltage-limits-to-platform-dat.patch
new file mode 100644
index 0000000000..23b319648d
--- /dev/null
+++ b/target/linux/mediatek/patches-5.15/350-09-cpufreq-mediatek-Move-voltage-limits-to-platform-dat.patch
@@ -0,0 +1,227 @@
+From be2354b064e6bafbbad599ae2e10569ba4f7d5a6 Mon Sep 17 00:00:00 2001
+From: Rex-BC Chen <rex-bc.chen at 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 at mediatek.com>
+Signed-off-by: Rex-BC Chen <rex-bc.chen at mediatek.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
+Signed-off-by: Viresh Kumar <viresh.kumar at 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);
diff --git a/target/linux/mediatek/patches-5.15/350-10-cpufreq-mediatek-Refine-mtk_cpufreq_voltage_tracking.patch b/target/linux/mediatek/patches-5.15/350-10-cpufreq-mediatek-Refine-mtk_cpufreq_voltage_tracking.patch
new file mode 100644
index 0000000000..0ba9471ffa
--- /dev/null
+++ b/target/linux/mediatek/patches-5.15/350-10-cpufreq-mediatek-Refine-mtk_cpufreq_voltage_tracking.patch
@@ -0,0 +1,255 @@
+From 944b041c91f1e1cd762c39c1222f078550149486 Mon Sep 17 00:00:00 2001
+From: Jia-Wei Chang <jia-wei.chang at 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 at mediatek.com>
+Signed-off-by: Rex-BC Chen <rex-bc.chen at mediatek.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
+Signed-off-by: Viresh Kumar <viresh.kumar at 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:
diff --git a/target/linux/mediatek/patches-5.15/350-11-cpufreq-mediatek-Add-opp-notification-support.patch b/target/linux/mediatek/patches-5.15/350-11-cpufreq-mediatek-Add-opp-notification-support.patch
new file mode 100644
index 0000000000..2cb99b907a
--- /dev/null
+++ b/target/linux/mediatek/patches-5.15/350-11-cpufreq-mediatek-Add-opp-notification-support.patch
@@ -0,0 +1,184 @@
+From 01be227eff7e5fc01f7c8de8f6daddd5fb17ddd1 Mon Sep 17 00:00:00 2001
+From: Rex-BC Chen <rex-bc.chen at 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 at mediatek.com>
+Signed-off-by: Jia-Wei Chang <jia-wei.chang at mediatek.com>
+Signed-off-by: Rex-BC Chen <rex-bc.chen at mediatek.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
+[ Viresh: Renamed opp_freq as current_freq and moved its initialization ]
+Signed-off-by: Viresh Kumar <viresh.kumar at 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)
diff --git a/target/linux/mediatek/patches-5.15/350-12-cpufreq-mediatek-Fix-potential-deadlock-problem-in-m.patch b/target/linux/mediatek/patches-5.15/350-12-cpufreq-mediatek-Fix-potential-deadlock-problem-in-m.patch
new file mode 100644
index 0000000000..76bd795c00
--- /dev/null
+++ b/target/linux/mediatek/patches-5.15/350-12-cpufreq-mediatek-Fix-potential-deadlock-problem-in-m.patch
@@ -0,0 +1,43 @@
+From 6a1bd7cf4ed7a1948f564aaf16d34b7352c0029b Mon Sep 17 00:00:00 2001
+From: Wan Jiabing <wanjiabing at 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 at vivo.com>
+Reviewed-by: Rex-BC Chen <rex-bc.chen at mediatek.com>
+Signed-off-by: Viresh Kumar <viresh.kumar at 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);
diff --git a/target/linux/mediatek/patches-5.15/350-13-cpufreq-mediatek-Link-CCI-device-to-CPU.patch b/target/linux/mediatek/patches-5.15/350-13-cpufreq-mediatek-Link-CCI-device-to-CPU.patch
new file mode 100644
index 0000000000..eeaa466c32
--- /dev/null
+++ b/target/linux/mediatek/patches-5.15/350-13-cpufreq-mediatek-Link-CCI-device-to-CPU.patch
@@ -0,0 +1,188 @@
+From 15aaf74fb734a3e69b10d00b97b322711b81e222 Mon Sep 17 00:00:00 2001
+From: Rex-BC Chen <rex-bc.chen at 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 at mediatek.com>
+Signed-off-by: Rex-BC Chen <rex-bc.chen at mediatek.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
+Reviewed-by: Kevin Hilman <khilman at baylibre.com>
+Signed-off-by: Viresh Kumar <viresh.kumar at 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 },
+ 	{ }
diff --git a/target/linux/mediatek/patches-5.15/350-14-cpufreq-mediatek-Add-support-for-MT8186.patch b/target/linux/mediatek/patches-5.15/350-14-cpufreq-mediatek-Add-support-for-MT8186.patch
new file mode 100644
index 0000000000..31000cfbe0
--- /dev/null
+++ b/target/linux/mediatek/patches-5.15/350-14-cpufreq-mediatek-Add-support-for-MT8186.patch
@@ -0,0 +1,42 @@
+From b6be0baa6615afc65c3963adab674e36af1d4d5f Mon Sep 17 00:00:00 2001
+From: Jia-Wei Chang <jia-wei.chang at 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 at mediatek.com>
+Signed-off-by: Rex-BC Chen <rex-bc.chen at mediatek.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
+Signed-off-by: Viresh Kumar <viresh.kumar at 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 },
+ 	{ }
diff --git a/target/linux/mediatek/patches-5.15/350-15-cpufreq-mediatek-Handle-sram-regulator-probe-deferra.patch b/target/linux/mediatek/patches-5.15/350-15-cpufreq-mediatek-Handle-sram-regulator-probe-deferra.patch
new file mode 100644
index 0000000000..c0137894c9
--- /dev/null
+++ b/target/linux/mediatek/patches-5.15/350-15-cpufreq-mediatek-Handle-sram-regulator-probe-deferra.patch
@@ -0,0 +1,35 @@
+From 75d19b24aa3203d6c78e4c431c2cc07157ce12fe Mon Sep 17 00:00:00 2001
+From: AngeloGioacchino Del Regno <angelogioacchino.delregno at 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 at collabora.com>
+Signed-off-by: Viresh Kumar <viresh.kumar at 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);
diff --git a/target/linux/mediatek/patches-5.15/350-16-cpufreq-mediatek-fix-error-return-code-in-mtk_cpu_dv.patch b/target/linux/mediatek/patches-5.15/350-16-cpufreq-mediatek-fix-error-return-code-in-mtk_cpu_dv.patch
new file mode 100644
index 0000000000..45c4477ff1
--- /dev/null
+++ b/target/linux/mediatek/patches-5.15/350-16-cpufreq-mediatek-fix-error-return-code-in-mtk_cpu_dv.patch
@@ -0,0 +1,29 @@
+From dd1174c21dacacd6c0129c1dabc5decad35c02c2 Mon Sep 17 00:00:00 2001
+From: Yang Yingliang <yangyingliang at 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 at huawei.com>
+Signed-off-by: Yang Yingliang <yangyingliang at huawei.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
+Reviewed-by: Rex-BC Chen <rex-bc.chen at mediatek.com>
+Signed-off-by: Viresh Kumar <viresh.kumar at 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;
diff --git a/target/linux/mediatek/patches-5.15/350-17-cpufreq-mediatek-fix-passing-zero-to-PTR_ERR.patch b/target/linux/mediatek/patches-5.15/350-17-cpufreq-mediatek-fix-passing-zero-to-PTR_ERR.patch
new file mode 100644
index 0000000000..557d02b822
--- /dev/null
+++ b/target/linux/mediatek/patches-5.15/350-17-cpufreq-mediatek-fix-passing-zero-to-PTR_ERR.patch
@@ -0,0 +1,47 @@
+From 230a74d459244411db91bfd678f17fcf7aedfcd0 Mon Sep 17 00:00:00 2001
+From: Jia-Wei Chang <jia-wei.chang at 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 at mediatek.com>
+Fixes: 0daa47325bae ("cpufreq: mediatek: Link CCI device to CPU")
+Reported-by: Dan Carpenter <error27 at gmail.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
+Signed-off-by: Viresh Kumar <viresh.kumar at 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;
diff --git a/target/linux/mediatek/patches-5.15/350-18-cpufreq-mediatek-fix-KP-caused-by-handler-usage-afte.patch b/target/linux/mediatek/patches-5.15/350-18-cpufreq-mediatek-fix-KP-caused-by-handler-usage-afte.patch
new file mode 100644
index 0000000000..61531d38ad
--- /dev/null
+++ b/target/linux/mediatek/patches-5.15/350-18-cpufreq-mediatek-fix-KP-caused-by-handler-usage-afte.patch
@@ -0,0 +1,149 @@
+From fced531b7c7e18192e7982637c8e8f20c29aad64 Mon Sep 17 00:00:00 2001
+From: Jia-Wei Chang <jia-wei.chang at 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 at mediatek.com>
+Fixes: 4b9ceb757bbb ("cpufreq: mediatek: Enable clocks and regulators")
+Suggested-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
+Suggested-by: Dan Carpenter <error27 at gmail.com>
+Signed-off-by: Viresh Kumar <viresh.kumar at 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);
+ }
diff --git a/target/linux/mediatek/patches-5.15/350-19-cpufreq-mediatek-raise-proc-sram-max-voltage-for-MT8.patch b/target/linux/mediatek/patches-5.15/350-19-cpufreq-mediatek-raise-proc-sram-max-voltage-for-MT8.patch
new file mode 100644
index 0000000000..2b7d229f1c
--- /dev/null
+++ b/target/linux/mediatek/patches-5.15/350-19-cpufreq-mediatek-raise-proc-sram-max-voltage-for-MT8.patch
@@ -0,0 +1,55 @@
+From 24bc42a2d44cb821818717a5c607270921ec5d20 Mon Sep 17 00:00:00 2001
+From: Jia-Wei Chang <jia-wei.chang at 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 at 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 at systemli.org>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
+Signed-off-by: Viresh Kumar <viresh.kumar at 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);
diff --git a/target/linux/mediatek/patches-5.15/350-20-cpufreq-mediatek-Raise-proc-and-sram-max-voltage-for.patch b/target/linux/mediatek/patches-5.15/350-20-cpufreq-mediatek-Raise-proc-and-sram-max-voltage-for.patch
new file mode 100644
index 0000000000..2de8eb6394
--- /dev/null
+++ b/target/linux/mediatek/patches-5.15/350-20-cpufreq-mediatek-Raise-proc-and-sram-max-voltage-for.patch
@@ -0,0 +1,58 @@
+From fe6ef09358dc0cfead9d383a8676fbe7a40fcef7 Mon Sep 17 00:00:00 2001
+From: AngeloGioacchino Del Regno <angelogioacchino.delregno at 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 at collabora.com>
+Signed-off-by: Jia-Wei Chang <jia-wei.chang at mediatek.com>
+Signed-off-by: Viresh Kumar <viresh.kumar at 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 },
diff --git a/target/linux/mediatek/patches-5.15/350-21-cpufreq-mediatek-Add-support-for-MT7988.patch b/target/linux/mediatek/patches-5.15/350-21-cpufreq-mediatek-Add-support-for-MT7988.patch
new file mode 100644
index 0000000000..6acd3d607f
--- /dev/null
+++ b/target/linux/mediatek/patches-5.15/350-21-cpufreq-mediatek-Add-support-for-MT7988.patch
@@ -0,0 +1,41 @@
+From 4983a1517e7ddbc6f53fc07607e4ebeb51412843 Mon Sep 17 00:00:00 2001
+From: Sam Shih <sam.shih at 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 at 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 },
diff --git a/target/linux/mediatek/patches-5.15/351-cpufreq-mediatek-don-t-request-unsupported-voltage.patch b/target/linux/mediatek/patches-5.15/351-cpufreq-mediatek-don-t-request-unsupported-voltage.patch
new file mode 100644
index 0000000000..a7a4bd8ea2
--- /dev/null
+++ b/target/linux/mediatek/patches-5.15/351-cpufreq-mediatek-don-t-request-unsupported-voltage.patch
@@ -0,0 +1,29 @@
+From 20aad28ba5d62f1618408c264384d0b2ad7417db Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel at 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 at 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,
+ };
+ 




More information about the lede-commits mailing list