From 1c055e55a242a33e574e48be530e06770a210dcd Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Mon, 19 Feb 2024 03:26:26 +0000
Subject: [PATCH] add r8169 read mac form eeprom

---
 kernel/drivers/devfreq/rockchip_dmc.c | 1387 ++++++++++++++++++++++++++++++++------------------------
 1 files changed, 788 insertions(+), 599 deletions(-)

diff --git a/kernel/drivers/devfreq/rockchip_dmc.c b/kernel/drivers/devfreq/rockchip_dmc.c
index d75c21e..e3d39bd 100644
--- a/kernel/drivers/devfreq/rockchip_dmc.c
+++ b/kernel/drivers/devfreq/rockchip_dmc.c
@@ -1,20 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd.
- * Author: Lin Huang <hl@rock-chips.com>
+ * Rockchip Generic dmc support.
  *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
+ * Copyright (c) 2021 Rockchip Electronics Co. Ltd.
+ * Author: Finley Xiao <finley.xiao@rock-chips.com>
  */
 
 #include <dt-bindings/clock/rockchip-ddr.h>
-#include <dt-bindings/soc/rockchip-system-status.h>
-#include <drm/drmP.h>
 #include <drm/drm_modeset_lock.h>
 #include <linux/arm-smccc.h>
 #include <linux/clk.h>
@@ -50,11 +42,13 @@
 #include <soc/rockchip/rockchip_system_monitor.h>
 #include <soc/rockchip/rockchip-system-status.h>
 #include <soc/rockchip/rockchip_opp_select.h>
-#include <soc/rockchip/scpi.h>
 #include <uapi/drm/drm_mode.h>
 
 #include "governor.h"
 #include "rockchip_dmc_timing.h"
+#include "../clk/rockchip/clk.h"
+#include "../gpu/drm/rockchip/rockchip_drm_drv.h"
+#include "../opp/opp.h"
 
 #define system_status_to_dmcfreq(nb) container_of(nb, struct rockchip_dmcfreq, \
 						  status_nb)
@@ -62,35 +56,17 @@
 					   reboot_nb)
 #define boost_to_dmcfreq(work) container_of(work, struct rockchip_dmcfreq, \
 					    boost_work)
-#define msch_rl_to_dmcfreq(work) container_of(to_delayed_work(work), \
-					      struct rockchip_dmcfreq, \
-					      msch_rl_work)
 #define input_hd_to_dmcfreq(hd) container_of(hd, struct rockchip_dmcfreq, \
 					     input_handler)
 
 #define VIDEO_1080P_SIZE	(1920 * 1080)
-#define FIQ_INIT_HANDLER	(0x1)
-#define FIQ_CPU_TGT_BOOT	(0x0) /* to booting cpu */
-#define FIQ_NUM_FOR_DCF		(143) /* NA irq map to fiq for dcf */
 #define DTS_PAR_OFFSET		(4096)
-#define MSCH_RL_DELAY_TIME	50 /* ms */
 
 #define FALLBACK_STATIC_TEMPERATURE 55000
 
-struct freq_map_table {
-	unsigned int min;
-	unsigned int max;
-	unsigned long freq;
-};
-
-struct rl_map_table {
-	unsigned int pn; /* panel number */
-	unsigned int rl; /* readlatency */
-};
-
 struct dmc_freq_table {
 	unsigned long freq;
-	unsigned long volt;
+	struct dev_pm_opp_supply supplies[2];
 };
 
 struct share_params {
@@ -116,7 +92,9 @@
 
 	u32 freq_count;
 	u32 freq_info_mhz[6];
-	 /* if need, add parameter after */
+	u32 wait_mode;
+	u32 vop_scan_line_time_ns;
+	/* if need, add parameter after */
 };
 
 static struct share_params *ddr_psci_param;
@@ -128,43 +106,45 @@
 
 struct rockchip_dmcfreq {
 	struct device *dev;
-	struct devfreq *devfreq;
+	struct dmcfreq_common_info info;
 	struct rockchip_dmcfreq_ondemand_data ondemand_data;
 	struct clk *dmc_clk;
 	struct devfreq_event_dev **edev;
 	struct mutex lock; /* serializes access to video_info_list */
 	struct dram_timing *timing;
 	struct regulator *vdd_center;
+	struct regulator *mem_reg;
 	struct notifier_block status_nb;
+	struct notifier_block panic_nb;
 	struct list_head video_info_list;
-	struct freq_map_table *vop_bw_tbl;
-	struct freq_map_table *vop_frame_bw_tbl;
 	struct freq_map_table *cpu_bw_tbl;
 	struct work_struct boost_work;
 	struct input_handler input_handler;
 	struct monitor_dev_info *mdev_info;
-	struct rl_map_table *vop_pn_rl_tbl;
-	struct delayed_work msch_rl_work;
+	struct share_params *set_rate_params;
 
 	unsigned long *nocp_bw;
-	unsigned long rate, target_rate;
-	unsigned long volt, target_volt;
-
+	unsigned long rate;
+	unsigned long volt, mem_volt;
+	unsigned long sleep_volt, sleep_mem_volt;
 	unsigned long auto_min_rate;
 	unsigned long status_rate;
 	unsigned long normal_rate;
 	unsigned long video_1080p_rate;
 	unsigned long video_4k_rate;
 	unsigned long video_4k_10b_rate;
+	unsigned long video_4k_60p_rate;
+	unsigned long video_svep_rate;
 	unsigned long performance_rate;
 	unsigned long hdmi_rate;
+	unsigned long hdmirx_rate;
 	unsigned long idle_rate;
 	unsigned long suspend_rate;
+	unsigned long deep_suspend_rate;
 	unsigned long reboot_rate;
 	unsigned long boost_rate;
 	unsigned long fixed_rate;
 	unsigned long low_power_rate;
-	unsigned long vop_req_rate;
 
 	unsigned long freq_count;
 	unsigned long freq_info_rate[6];
@@ -174,17 +154,14 @@
 	unsigned long rate_high;
 
 	unsigned int min_cpu_freq;
-	unsigned int auto_freq_en;
 	unsigned int system_status_en;
 	unsigned int refresh;
-	unsigned int last_refresh;
-	unsigned int read_latency;
 	int edev_count;
 	int dfi_id;
 	int nocp_cpu_id;
+	int regulator_count;
 
 	bool is_fixed;
-	bool is_msch_rl_work_started;
 	bool is_set_rate_direct;
 
 	struct thermal_cooling_device *devfreq_cooling;
@@ -196,12 +173,19 @@
 	u64 touchboostpulse_endtime;
 
 	int (*set_auto_self_refresh)(u32 en);
-	int (*set_msch_readlatency)(unsigned int rl);
 };
 
 static struct pm_qos_request pm_qos;
 
-static DECLARE_RWSEM(rockchip_dmcfreq_sem);
+static int rockchip_dmcfreq_opp_helper(struct dev_pm_set_opp_data *data);
+
+static struct monitor_dev_profile dmc_mdevp = {
+	.type = MONITOR_TYPE_DEV,
+	.low_temp_adjust = rockchip_monitor_dev_low_temp_adjust,
+	.high_temp_adjust = rockchip_monitor_dev_high_temp_adjust,
+	.update_volt = rockchip_monitor_check_rate_volt,
+	.set_opp = rockchip_dmcfreq_opp_helper,
+};
 
 static inline unsigned long is_dualview(unsigned long status)
 {
@@ -214,24 +198,6 @@
 	       (status & SYS_STATUS_CIF0) ||
 	       (status & SYS_STATUS_CIF1);
 }
-
-void rockchip_dmcfreq_lock(void)
-{
-	down_read(&rockchip_dmcfreq_sem);
-}
-EXPORT_SYMBOL(rockchip_dmcfreq_lock);
-
-void rockchip_dmcfreq_lock_nested(void)
-{
-	down_read_nested(&rockchip_dmcfreq_sem, SINGLE_DEPTH_NESTING);
-}
-EXPORT_SYMBOL(rockchip_dmcfreq_lock_nested);
-
-void rockchip_dmcfreq_unlock(void)
-{
-	up_read(&rockchip_dmcfreq_sem);
-}
-EXPORT_SYMBOL(rockchip_dmcfreq_unlock);
 
 /*
  * function: packaging de-skew setting to px30_ddr_dts_config_timing,
@@ -346,21 +312,8 @@
 
 static int rk_drm_get_lcdc_type(void)
 {
-	struct drm_device *drm;
-	u32 lcdc_type = 0;
+	u32 lcdc_type = rockchip_drm_get_sub_dev_type();
 
-	drm = drm_device_get_by_name("rockchip");
-	if (drm) {
-		struct drm_connector *conn;
-
-		list_for_each_entry(conn, &drm->mode_config.connector_list,
-				    head) {
-			if (conn->encoder) {
-				lcdc_type = conn->connector_type;
-				break;
-			}
-		}
-	}
 	switch (lcdc_type) {
 	case DRM_MODE_CONNECTOR_DPI:
 	case DRM_MODE_CONNECTOR_LVDS:
@@ -396,6 +349,7 @@
 
 	ddr_psci_param->hz = target_rate;
 	ddr_psci_param->lcdc_type = rk_drm_get_lcdc_type();
+	ddr_psci_param->vop_scan_line_time_ns = rockchip_drm_get_scan_line_time_ns();
 	ddr_psci_param->wait_flag1 = 1;
 	ddr_psci_param->wait_flag0 = 1;
 
@@ -408,48 +362,47 @@
 	return res.a0;
 }
 
-static int rockchip_dmcfreq_target(struct device *dev, unsigned long *freq,
-				   u32 flags)
+static int rockchip_dmcfreq_set_volt(struct device *dev, struct regulator *reg,
+				     struct dev_pm_opp_supply *supply,
+				     char *reg_name)
 {
+	int ret;
+
+	dev_dbg(dev, "%s: %s voltages (mV): %lu %lu %lu\n", __func__, reg_name,
+		supply->u_volt_min, supply->u_volt, supply->u_volt_max);
+	ret = regulator_set_voltage_triplet(reg, supply->u_volt_min,
+					    supply->u_volt, INT_MAX);
+	if (ret)
+		dev_err(dev, "%s: failed to set voltage (%lu %lu %lu mV): %d\n",
+			__func__, supply->u_volt_min, supply->u_volt,
+			supply->u_volt_max, ret);
+
+	return ret;
+}
+
+static int rockchip_dmcfreq_opp_helper(struct dev_pm_set_opp_data *data)
+{
+	struct dev_pm_opp_supply *old_supply_vdd = &data->old_opp.supplies[0];
+	struct dev_pm_opp_supply *new_supply_vdd = &data->new_opp.supplies[0];
+	struct regulator *vdd_reg = data->regulators[0];
+	struct dev_pm_opp_supply *old_supply_mem;
+	struct dev_pm_opp_supply *new_supply_mem;
+	struct regulator *mem_reg;
+	struct device *dev = data->dev;
+	struct clk *clk = data->clk;
 	struct rockchip_dmcfreq *dmcfreq = dev_get_drvdata(dev);
-	struct dev_pm_opp *opp;
 	struct cpufreq_policy *policy;
-	unsigned long old_clk_rate = dmcfreq->rate;
-	unsigned long target_volt, target_rate;
-	unsigned int cpu_cur, cpufreq_cur;
+	unsigned long old_freq = data->old_opp.rate;
+	unsigned long freq = data->new_opp.rate;
+	unsigned int reg_count = data->regulator_count;
 	bool is_cpufreq_changed = false;
-	int err = 0;
+	unsigned int cpu_cur, cpufreq_cur;
+	int ret = 0;
 
-	opp = devfreq_recommended_opp(dev, freq, flags);
-	if (IS_ERR(opp)) {
-		dev_err(dev, "Failed to find opp for %lu Hz\n", *freq);
-		return PTR_ERR(opp);
-	}
-	target_volt = dev_pm_opp_get_voltage(opp);
-	dev_pm_opp_put(opp);
-
-	if (dmcfreq->is_set_rate_direct) {
-		target_rate = *freq;
-	} else {
-		target_rate = clk_round_rate(dmcfreq->dmc_clk, *freq);
-		if ((long)target_rate <= 0)
-			target_rate = *freq;
-	}
-
-	if (dmcfreq->rate == target_rate) {
-		if (dmcfreq->volt == target_volt)
-			return 0;
-		err = regulator_set_voltage(dmcfreq->vdd_center, target_volt,
-					    INT_MAX);
-		if (err) {
-			dev_err(dev, "Cannot set voltage %lu uV\n",
-				target_volt);
-			return err;
-		}
-		dmcfreq->volt = target_volt;
-		return 0;
-	} else if (!dmcfreq->volt) {
-		dmcfreq->volt = regulator_get_voltage(dmcfreq->vdd_center);
+	if (reg_count > 1) {
+		old_supply_mem = &data->old_opp.supplies[1];
+		new_supply_mem = &data->new_opp.supplies[1];
+		mem_reg = data->regulators[1];
 	}
 
 	/*
@@ -459,47 +412,54 @@
 	 * Do this before taking the policy rwsem to avoid deadlocks between the
 	 * mutex that is locked/unlocked in cpu_hotplug_disable/enable. And it
 	 * can also avoid deadlocks between the mutex that is locked/unlocked
-	 * in get/put_online_cpus (such as store_scaling_max_freq()).
+	 * in cpus_read_lock/unlock (such as store_scaling_max_freq()).
 	 */
-	get_online_cpus();
+	cpus_read_lock();
 
-	/*
-	 * Go to specified cpufreq and block other cpufreq changes since
-	 * set_rate needs to complete during vblank.
-	 */
-	cpu_cur = raw_smp_processor_id();
-	policy = cpufreq_cpu_get(cpu_cur);
-	if (!policy) {
-		dev_err(dev, "cpu%d policy NULL\n", cpu_cur);
-		goto cpufreq;
-	}
-	down_write(&policy->rwsem);
-	cpufreq_cur = cpufreq_quick_get(cpu_cur);
+	if (dmcfreq->min_cpu_freq) {
+		/*
+		 * Go to specified cpufreq and block other cpufreq changes since
+		 * set_rate needs to complete during vblank.
+		 */
+		cpu_cur = raw_smp_processor_id();
+		policy = cpufreq_cpu_get(cpu_cur);
+		if (!policy) {
+			dev_err(dev, "cpu%d policy NULL\n", cpu_cur);
+			ret = -EINVAL;
+			goto cpufreq;
+		}
+		down_write(&policy->rwsem);
+		cpufreq_cur = cpufreq_quick_get(cpu_cur);
 
-	/* If we're thermally throttled; don't change; */
-	if (dmcfreq->min_cpu_freq && cpufreq_cur < dmcfreq->min_cpu_freq) {
-		if (policy->max >= dmcfreq->min_cpu_freq) {
-			__cpufreq_driver_target(policy, dmcfreq->min_cpu_freq,
-						CPUFREQ_RELATION_L);
-			is_cpufreq_changed = true;
-		} else {
-			dev_dbg(dev, "CPU may too slow for DMC (%d MHz)\n",
-				policy->max);
+		/* If we're thermally throttled; don't change; */
+		if (cpufreq_cur < dmcfreq->min_cpu_freq) {
+			if (policy->max >= dmcfreq->min_cpu_freq) {
+				__cpufreq_driver_target(policy,
+							dmcfreq->min_cpu_freq,
+							CPUFREQ_RELATION_L);
+				is_cpufreq_changed = true;
+			} else {
+				dev_dbg(dev,
+					"CPU may too slow for DMC (%d MHz)\n",
+					policy->max);
+			}
 		}
 	}
 
-	/*
-	 * If frequency scaling from low to high, adjust voltage first.
-	 * If frequency scaling from high to low, adjust frequency first.
-	 */
-	if (old_clk_rate < target_rate) {
-		err = regulator_set_voltage(dmcfreq->vdd_center, target_volt,
-					    INT_MAX);
-		if (err) {
-			dev_err(dev, "Cannot set voltage %lu uV\n",
-				target_volt);
+	/* Scaling up? Scale voltage before frequency */
+	if (freq >= old_freq) {
+		if (reg_count > 1) {
+			ret = rockchip_dmcfreq_set_volt(dev, mem_reg,
+							new_supply_mem, "mem");
+			if (ret)
+				goto restore_voltage;
+		}
+		ret = rockchip_dmcfreq_set_volt(dev, vdd_reg, new_supply_vdd,
+						"vdd");
+		if (ret)
+			goto restore_voltage;
+		if (freq == old_freq)
 			goto out;
-		}
 	}
 
 	/*
@@ -509,61 +469,119 @@
 	 * As a (suboptimal) workaround, let writer to spin until it gets the
 	 * lock.
 	 */
-	while (!down_write_trylock(&rockchip_dmcfreq_sem))
+	while (!rockchip_dmcfreq_write_trylock())
 		cond_resched();
-	dev_dbg(dev, "%lu-->%lu\n", old_clk_rate, target_rate);
+	dev_dbg(dev, "%lu Hz --> %lu Hz\n", old_freq, freq);
+
+	if (dmcfreq->set_rate_params) {
+		dmcfreq->set_rate_params->lcdc_type = rk_drm_get_lcdc_type();
+		dmcfreq->set_rate_params->wait_flag1 = 1;
+		dmcfreq->set_rate_params->wait_flag0 = 1;
+	}
 
 	if (dmcfreq->is_set_rate_direct)
-		err = rockchip_ddr_set_rate(target_rate);
+		ret = rockchip_ddr_set_rate(freq);
 	else
-		err = clk_set_rate(dmcfreq->dmc_clk, target_rate);
+		ret = clk_set_rate(clk, freq);
 
-	up_write(&rockchip_dmcfreq_sem);
-	if (err) {
-		dev_err(dev, "Cannot set frequency %lu (%d)\n",
-			target_rate, err);
-		regulator_set_voltage(dmcfreq->vdd_center, dmcfreq->volt,
-				      INT_MAX);
-		goto out;
+	rockchip_dmcfreq_write_unlock();
+	if (ret) {
+		dev_err(dev, "%s: failed to set clock rate: %d\n", __func__,
+			ret);
+		goto restore_voltage;
 	}
 
 	/*
 	 * Check the dpll rate,
 	 * There only two result we will get,
 	 * 1. Ddr frequency scaling fail, we still get the old rate.
-	 * 2. Ddr frequency scaling sucessful, we get the rate we set.
+	 * 2. Ddr frequency scaling successful, we get the rate we set.
 	 */
-	dmcfreq->rate = clk_get_rate(dmcfreq->dmc_clk);
+	dmcfreq->rate = clk_get_rate(clk);
 
 	/* If get the incorrect rate, set voltage to old value. */
-	if (dmcfreq->rate != target_rate) {
+	if (dmcfreq->rate != freq) {
 		dev_err(dev, "Get wrong frequency, Request %lu, Current %lu\n",
-			target_rate, dmcfreq->rate);
-		regulator_set_voltage(dmcfreq->vdd_center, dmcfreq->volt,
-				      INT_MAX);
-		goto out;
-	} else if (old_clk_rate > target_rate) {
-		err = regulator_set_voltage(dmcfreq->vdd_center, target_volt,
-					    INT_MAX);
-		if (err) {
-			dev_err(dev, "Cannot set vol %lu uV\n", target_volt);
-			goto out;
-		}
+			freq, dmcfreq->rate);
+		ret = -EINVAL;
+		goto restore_voltage;
 	}
 
-	if (dmcfreq->devfreq)
-		dmcfreq->devfreq->last_status.current_frequency = *freq;
+	/* Scaling down? Scale voltage after frequency */
+	if (freq < old_freq) {
+		ret = rockchip_dmcfreq_set_volt(dev, vdd_reg, new_supply_vdd,
+						"vdd");
+		if (ret)
+			goto restore_freq;
+		if (reg_count > 1) {
+			ret = rockchip_dmcfreq_set_volt(dev, mem_reg,
+							new_supply_mem, "mem");
+			if (ret)
+				goto restore_freq;
+		}
+	}
+	dmcfreq->volt = new_supply_vdd->u_volt;
+	if (reg_count > 1)
+		dmcfreq->mem_volt = new_supply_mem->u_volt;
 
-	dmcfreq->volt = target_volt;
+	goto out;
+
+restore_freq:
+	if (dmcfreq->is_set_rate_direct)
+		ret = rockchip_ddr_set_rate(freq);
+	else
+		ret = clk_set_rate(clk, freq);
+	if (ret)
+		dev_err(dev, "%s: failed to restore old-freq (%lu Hz)\n",
+			__func__, old_freq);
+restore_voltage:
+	if (reg_count > 1 && old_supply_mem->u_volt)
+		rockchip_dmcfreq_set_volt(dev, mem_reg, old_supply_mem, "mem");
+	if (old_supply_vdd->u_volt)
+		rockchip_dmcfreq_set_volt(dev, vdd_reg, old_supply_vdd, "vdd");
 out:
-	if (is_cpufreq_changed)
-		__cpufreq_driver_target(policy, cpufreq_cur,
-					CPUFREQ_RELATION_L);
-	up_write(&policy->rwsem);
-	cpufreq_cpu_put(policy);
+	if (dmcfreq->min_cpu_freq) {
+		if (is_cpufreq_changed)
+			__cpufreq_driver_target(policy, cpufreq_cur,
+						CPUFREQ_RELATION_L);
+		up_write(&policy->rwsem);
+		cpufreq_cpu_put(policy);
+	}
 cpufreq:
-	put_online_cpus();
-	return err;
+	cpus_read_unlock();
+
+	return ret;
+}
+
+static int rockchip_dmcfreq_target(struct device *dev, unsigned long *freq,
+				   u32 flags)
+{
+	struct rockchip_dmcfreq *dmcfreq = dev_get_drvdata(dev);
+	struct devfreq *devfreq;
+	struct dev_pm_opp *opp;
+	int ret = 0;
+
+	if (!dmc_mdevp.is_checked)
+		return -EINVAL;
+
+	opp = devfreq_recommended_opp(dev, freq, flags);
+	if (IS_ERR(opp)) {
+		dev_err(dev, "Failed to find opp for %lu Hz\n", *freq);
+		return PTR_ERR(opp);
+	}
+	dev_pm_opp_put(opp);
+
+	rockchip_monitor_volt_adjust_lock(dmcfreq->mdev_info);
+	ret = dev_pm_opp_set_rate(dev, *freq);
+	if (!ret) {
+		if (dmcfreq->info.devfreq) {
+			devfreq = dmcfreq->info.devfreq;
+			devfreq->last_status.current_frequency = *freq;
+		}
+	}
+	rockchip_monitor_volt_adjust_unlock(dmcfreq->mdev_info);
+
+	return ret;
 }
 
 static int rockchip_dmcfreq_get_dev_status(struct device *dev,
@@ -573,15 +591,20 @@
 	struct devfreq_event_data edata;
 	int i, ret = 0;
 
-	if (!dmcfreq->auto_freq_en)
+	if (!dmcfreq->info.auto_freq_en)
 		return -EINVAL;
 
+	/*
+	 * RK3588 platform may crash if the CPU and MCU access the DFI/DMC
+	 * registers at same time.
+	 */
+	rockchip_monitor_volt_adjust_lock(dmcfreq->mdev_info);
 	for (i = 0; i < dmcfreq->edev_count; i++) {
 		ret = devfreq_event_get_event(dmcfreq->edev[i], &edata);
 		if (ret < 0) {
 			dev_err(dev, "failed to get event %s\n",
 				dmcfreq->edev[i]->desc->name);
-			return ret;
+			goto out;
 		}
 		if (i == dmcfreq->dfi_id) {
 			stat->busy_time = edata.load_count;
@@ -591,7 +614,10 @@
 		}
 	}
 
-	return 0;
+out:
+	rockchip_monitor_volt_adjust_unlock(dmcfreq->mdev_info);
+
+	return ret;
 }
 
 static int rockchip_dmcfreq_get_cur_freq(struct device *dev,
@@ -962,70 +988,6 @@
 	of_node_put(np_tim);
 }
 
-static struct rk3368_dram_timing *of_get_rk3368_timings(struct device *dev,
-							struct device_node *np)
-{
-	struct rk3368_dram_timing *timing = NULL;
-	struct device_node *np_tim;
-	int ret = 0;
-
-	np_tim = of_parse_phandle(np, "ddr_timing", 0);
-	if (np_tim) {
-		timing = devm_kzalloc(dev, sizeof(*timing), GFP_KERNEL);
-		if (!timing)
-			goto err;
-
-		ret |= of_property_read_u32(np_tim, "dram_spd_bin",
-					    &timing->dram_spd_bin);
-		ret |= of_property_read_u32(np_tim, "sr_idle",
-					    &timing->sr_idle);
-		ret |= of_property_read_u32(np_tim, "pd_idle",
-					    &timing->pd_idle);
-		ret |= of_property_read_u32(np_tim, "dram_dll_disb_freq",
-					    &timing->dram_dll_dis_freq);
-		ret |= of_property_read_u32(np_tim, "phy_dll_disb_freq",
-					    &timing->phy_dll_dis_freq);
-		ret |= of_property_read_u32(np_tim, "dram_odt_disb_freq",
-					    &timing->dram_odt_dis_freq);
-		ret |= of_property_read_u32(np_tim, "phy_odt_disb_freq",
-					    &timing->phy_odt_dis_freq);
-		ret |= of_property_read_u32(np_tim, "ddr3_drv",
-					    &timing->ddr3_drv);
-		ret |= of_property_read_u32(np_tim, "ddr3_odt",
-					    &timing->ddr3_odt);
-		ret |= of_property_read_u32(np_tim, "lpddr3_drv",
-					    &timing->lpddr3_drv);
-		ret |= of_property_read_u32(np_tim, "lpddr3_odt",
-					    &timing->lpddr3_odt);
-		ret |= of_property_read_u32(np_tim, "lpddr2_drv",
-					    &timing->lpddr2_drv);
-		ret |= of_property_read_u32(np_tim, "phy_clk_drv",
-					    &timing->phy_clk_drv);
-		ret |= of_property_read_u32(np_tim, "phy_cmd_drv",
-					    &timing->phy_cmd_drv);
-		ret |= of_property_read_u32(np_tim, "phy_dqs_drv",
-					    &timing->phy_dqs_drv);
-		ret |= of_property_read_u32(np_tim, "phy_odt",
-					    &timing->phy_odt);
-		ret |= of_property_read_u32(np_tim, "ddr_2t",
-					    &timing->ddr_2t);
-		if (ret) {
-			devm_kfree(dev, timing);
-			goto err;
-		}
-		of_node_put(np_tim);
-		return timing;
-	}
-
-err:
-	if (timing) {
-		devm_kfree(dev, timing);
-		timing = NULL;
-	}
-	of_node_put(np_tim);
-	return timing;
-}
-
 static struct rk3399_dram_timing *of_get_rk3399_timings(struct device *dev,
 							struct device_node *np)
 {
@@ -1176,7 +1138,7 @@
 	 * CPUs only enter WFI when idle to make sure that
 	 * FIQn can quick response.
 	 */
-	pm_qos_update_request(&pm_qos, 0);
+	cpu_latency_qos_update_request(&pm_qos, 0);
 
 	if (wait_ctrl.dcf_en == 1) {
 		/* start dcf */
@@ -1192,7 +1154,17 @@
 	wait_event_timeout(wait_ctrl.wait_wq, (wait_ctrl.wait_flag == 0),
 			   msecs_to_jiffies(wait_ctrl.wait_time_out_ms));
 
-	pm_qos_update_request(&pm_qos, PM_QOS_DEFAULT_VALUE);
+	/*
+	 * If waiting for wait_ctrl.complt_irq times out, clear the IRQ and stop the MCU by
+	 * sip_smc_dram(DRAM_POST_SET_RATE).
+	 */
+	if (wait_ctrl.dcf_en == 2 && wait_ctrl.wait_flag != 0) {
+		res = sip_smc_dram(SHARE_PAGE_TYPE_DDR, 0, ROCKCHIP_SIP_CONFIG_DRAM_POST_SET_RATE);
+		if (res.a0)
+			pr_err("%s: dram post set rate error:%lx\n", __func__, res.a0);
+	}
+
+	cpu_latency_qos_update_request(&pm_qos, PM_QOS_DEFAULT_VALUE);
 	disable_irq(wait_ctrl.complt_irq);
 
 	return 0;
@@ -1230,7 +1202,7 @@
 		return ret;
 	}
 
-	freq_table = kmalloc(sizeof(struct dmc_freq_table) * count, GFP_KERNEL);
+	freq_table = kzalloc(sizeof(*freq_table) * count, GFP_KERNEL);
 	for (i = 0, rate = 0; i < count; i++, rate++) {
 		/* find next rate */
 		opp = dev_pm_opp_find_freq_ceil(dmcfreq->dev, &rate);
@@ -1240,7 +1212,7 @@
 			goto out;
 		}
 		freq_table[i].freq = rate;
-		freq_table[i].volt = dev_pm_opp_get_voltage(opp);
+		freq_table[i].supplies[0].u_volt = dev_pm_opp_get_voltage(opp);
 		dev_pm_opp_put(opp);
 
 		for (j = 0; j < dmcfreq->freq_count; j++) {
@@ -1248,7 +1220,7 @@
 				break;
 		}
 		if (j == dmcfreq->freq_count)
-			dev_pm_opp_remove(dmcfreq->dev, rate);
+			dev_pm_opp_disable(dmcfreq->dev, rate);
 	}
 
 	for (i = 0; i < dmcfreq->freq_count; i++) {
@@ -1257,7 +1229,7 @@
 				break;
 			} else if (dmcfreq->freq_info_rate[i] < freq_table[j].freq) {
 				dev_pm_opp_add(dmcfreq->dev, dmcfreq->freq_info_rate[i],
-					       freq_table[j].volt);
+					       freq_table[j].supplies[0].u_volt);
 				break;
 			}
 		}
@@ -1271,6 +1243,103 @@
 			goto out;
 		}
 	}
+
+out:
+	kfree(freq_table);
+	return ret;
+}
+
+static __maybe_unused int
+rockchip_dmcfreq_adjust_opp_table(struct rockchip_dmcfreq *dmcfreq)
+{
+	struct device *dev = dmcfreq->dev;
+	struct arm_smccc_res res;
+	struct dev_pm_opp *opp;
+	struct opp_table *opp_table;
+	struct dmc_freq_table *freq_table;
+	int i, j, count = 0, ret = 0;
+
+	res = sip_smc_dram(SHARE_PAGE_TYPE_DDR, 0,
+			   ROCKCHIP_SIP_CONFIG_DRAM_GET_FREQ_INFO);
+	if (res.a0) {
+		dev_err(dev, "rockchip_sip_config_dram_get_freq_info error:%lx\n",
+			res.a0);
+		return -ENOMEM;
+	}
+
+	if (ddr_psci_param->freq_count == 0 || ddr_psci_param->freq_count > 6) {
+		dev_err(dev, "there is no available frequencies!\n");
+		return -EPERM;
+	}
+
+	for (i = 0; i < ddr_psci_param->freq_count; i++)
+		dmcfreq->freq_info_rate[i] = ddr_psci_param->freq_info_mhz[i] * 1000000;
+	dmcfreq->freq_count = ddr_psci_param->freq_count;
+
+	count = dev_pm_opp_get_opp_count(dev);
+	if (count <= 0) {
+		dev_err(dev, "there is no available opp\n");
+		ret = count ? count : -ENODATA;
+		return ret;
+	}
+
+	freq_table = kzalloc(sizeof(*freq_table) * count, GFP_KERNEL);
+	opp_table = dev_pm_opp_get_opp_table(dev);
+	if (!opp_table) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	mutex_lock(&opp_table->lock);
+	i = 0;
+	list_for_each_entry(opp, &opp_table->opp_list, node) {
+		if (!opp->available)
+			continue;
+
+		freq_table[i].freq = opp->rate;
+		freq_table[i].supplies[0] = opp->supplies[0];
+		if (dmcfreq->regulator_count > 1)
+			freq_table[i].supplies[1] = opp->supplies[1];
+
+		i++;
+	}
+
+	i = 0;
+	list_for_each_entry(opp, &opp_table->opp_list, node) {
+		if (!opp->available)
+			continue;
+
+		if (i >= dmcfreq->freq_count) {
+			opp->available = false;
+			continue;
+		}
+
+		for (j = 0; j < count; j++) {
+			if (dmcfreq->freq_info_rate[i] <= freq_table[j].freq) {
+				opp->rate = dmcfreq->freq_info_rate[i];
+				opp->supplies[0] = freq_table[j].supplies[0];
+				if (dmcfreq->regulator_count > 1)
+					opp->supplies[1] = freq_table[j].supplies[1];
+
+				break;
+			}
+		}
+		if (j == count) {
+			dev_err(dmcfreq->dev, "failed to match dmc_opp_table for %ld\n",
+				dmcfreq->freq_info_rate[i]);
+			if (i == 0) {
+				ret = -EPERM;
+				goto out;
+			} else {
+				opp->available = false;
+				dmcfreq->freq_count = i;
+			}
+		}
+		i++;
+	}
+
+	mutex_unlock(&opp_table->lock);
+	dev_pm_opp_put_opp_table(opp_table);
 
 out:
 	kfree(freq_table);
@@ -1336,6 +1405,10 @@
 	complt_irq_data = irq_get_irq_data(complt_irq);
 	complt_hwirq = irqd_to_hwirq(complt_irq_data);
 	ddr_psci_param->complt_hwirq = complt_hwirq;
+
+	dmcfreq->set_rate_params = ddr_psci_param;
+	rockchip_set_ddrclk_params(dmcfreq->set_rate_params);
+	rockchip_set_ddrclk_dmcfreq_wait_complete(rockchip_dmcfreq_wait_complete);
 
 	res = sip_smc_dram(SHARE_PAGE_TYPE_DDR, 0,
 			   ROCKCHIP_SIP_CONFIG_DRAM_INIT);
@@ -1410,6 +1483,10 @@
 	}
 	disable_irq(complt_irq);
 
+	dmcfreq->set_rate_params = ddr_psci_param;
+	rockchip_set_ddrclk_params(dmcfreq->set_rate_params);
+	rockchip_set_ddrclk_dmcfreq_wait_complete(rockchip_dmcfreq_wait_complete);
+
 	res = sip_smc_dram(SHARE_PAGE_TYPE_DDR, 0,
 			   ROCKCHIP_SIP_CONFIG_DRAM_INIT);
 	if (res.a0) {
@@ -1427,12 +1504,6 @@
 					  struct rockchip_dmcfreq *dmcfreq)
 {
 	struct arm_smccc_res res;
-	struct drm_device *drm = drm_device_get_by_name("rockchip");
-
-	if (!drm) {
-		dev_err(&pdev->dev, "Get drm_device fail\n");
-		return -EPROBE_DEFER;
-	}
 
 	res = sip_smc_request_share_mem(DIV_ROUND_UP(sizeof(
 					struct rk3128_ddr_dts_config_timing),
@@ -1447,6 +1518,10 @@
 
 	ddr_psci_param->hz = 0;
 	ddr_psci_param->lcdc_type = rk_drm_get_lcdc_type();
+
+	dmcfreq->set_rate_params = ddr_psci_param;
+	rockchip_set_ddrclk_params(dmcfreq->set_rate_params);
+
 	res = sip_smc_dram(SHARE_PAGE_TYPE_DDR, 0,
 			   ROCKCHIP_SIP_CONFIG_DRAM_INIT);
 
@@ -1480,6 +1555,10 @@
 		return -ENOMEM;
 
 	ddr_psci_param->hz = 0;
+
+	dmcfreq->set_rate_params = ddr_psci_param;
+	rockchip_set_ddrclk_params(dmcfreq->set_rate_params);
+
 	res = sip_smc_dram(SHARE_PAGE_TYPE_DDR, 0,
 			   ROCKCHIP_SIP_CONFIG_DRAM_INIT);
 
@@ -1500,13 +1579,7 @@
 	struct device *dev = &pdev->dev;
 	struct clk *pclk_phy, *pclk_upctl, *dmc_clk;
 	struct arm_smccc_res res;
-	struct drm_device *drm = drm_device_get_by_name("rockchip");
 	int ret;
-
-	if (!drm) {
-		dev_err(dev, "Get drm_device fail\n");
-		return -EPROBE_DEFER;
-	}
 
 	dmc_clk = devm_clk_get(dev, "dmc_clk");
 	if (IS_ERR(dmc_clk)) {
@@ -1575,6 +1648,10 @@
 
 	ddr_psci_param->hz = 0;
 	ddr_psci_param->lcdc_type = rk_drm_get_lcdc_type();
+
+	dmcfreq->set_rate_params = ddr_psci_param;
+	rockchip_set_ddrclk_params(dmcfreq->set_rate_params);
+
 	res = sip_smc_dram(SHARE_PAGE_TYPE_DDR, 0,
 			   ROCKCHIP_SIP_CONFIG_DRAM_INIT);
 
@@ -1621,6 +1698,9 @@
 	of_get_rk3328_timings(&pdev->dev, pdev->dev.of_node,
 			      (uint32_t *)ddr_psci_param);
 
+	dmcfreq->set_rate_params = ddr_psci_param;
+	rockchip_set_ddrclk_params(dmcfreq->set_rate_params);
+
 	res = sip_smc_dram(SHARE_PAGE_TYPE_DDR, 0,
 			   ROCKCHIP_SIP_CONFIG_DRAM_INIT);
 	if (res.a0) {
@@ -1630,86 +1710,6 @@
 	}
 
 	dmcfreq->set_auto_self_refresh = rockchip_ddr_set_auto_self_refresh;
-
-	return 0;
-}
-
-static __maybe_unused int rk3368_dmc_init(struct platform_device *pdev,
-					  struct rockchip_dmcfreq *dmcfreq)
-{
-	struct device *dev = &pdev->dev;
-	struct device_node *np = pdev->dev.of_node;
-	struct arm_smccc_res res;
-	struct rk3368_dram_timing *dram_timing;
-	struct clk *pclk_phy, *pclk_upctl;
-	struct drm_device *drm = drm_device_get_by_name("rockchip");
-	int ret;
-	u32 dram_spd_bin;
-	u32 addr_mcu_el3;
-	u32 dclk_mode;
-	u32 lcdc_type;
-
-	if (!drm) {
-		dev_err(dev, "Get drm_device fail\n");
-		return -EPROBE_DEFER;
-	}
-
-	pclk_phy = devm_clk_get(dev, "pclk_phy");
-	if (IS_ERR(pclk_phy)) {
-		dev_err(dev, "Cannot get the clk pclk_phy\n");
-		return PTR_ERR(pclk_phy);
-	}
-	ret = clk_prepare_enable(pclk_phy);
-	if (ret < 0) {
-		dev_err(dev, "failed to prepare/enable pclk_phy\n");
-		return ret;
-	}
-	pclk_upctl = devm_clk_get(dev, "pclk_upctl");
-	if (IS_ERR(pclk_upctl)) {
-		dev_err(dev, "Cannot get the clk pclk_upctl\n");
-		return PTR_ERR(pclk_upctl);
-	}
-	ret = clk_prepare_enable(pclk_upctl);
-	if (ret < 0) {
-		dev_err(dev, "failed to prepare/enable pclk_upctl\n");
-		return ret;
-	}
-
-	/*
-	 * Get dram timing and pass it to arm trust firmware,
-	 * the dram drvier in arm trust firmware will get these
-	 * timing and to do dram initial.
-	 */
-	dram_timing = of_get_rk3368_timings(dev, np);
-	if (dram_timing) {
-		dram_spd_bin = dram_timing->dram_spd_bin;
-		if (scpi_ddr_send_timing((u32 *)dram_timing,
-					 sizeof(struct rk3368_dram_timing)))
-			dev_err(dev, "send ddr timing timeout\n");
-	} else {
-		dev_err(dev, "get ddr timing from dts error\n");
-		dram_spd_bin = DDR3_DEFAULT;
-	}
-
-	res = sip_smc_mcu_el3fiq(FIQ_INIT_HANDLER,
-				 FIQ_NUM_FOR_DCF,
-				 FIQ_CPU_TGT_BOOT);
-	if ((res.a0) || (res.a1 == 0) || (res.a1 > 0x80000))
-		dev_err(dev, "Trust version error, pls check trust version\n");
-	addr_mcu_el3 = res.a1;
-
-	if (of_property_read_u32(np, "vop-dclk-mode", &dclk_mode) == 0)
-		scpi_ddr_dclk_mode(dclk_mode);
-
-	lcdc_type = rk_drm_get_lcdc_type();
-
-	if (scpi_ddr_init(dram_spd_bin, 0, lcdc_type,
-			  addr_mcu_el3))
-		dev_err(dev, "ddr init error\n");
-	else
-		dev_dbg(dev, ("%s out\n"), __func__);
-
-	dmcfreq->set_auto_self_refresh = scpi_ddr_set_auto_self_refresh;
 
 	return 0;
 }
@@ -1756,11 +1756,90 @@
 		}
 	}
 
+	dmcfreq->set_rate_params =
+		devm_kzalloc(dev, sizeof(struct share_params), GFP_KERNEL);
+	if (!dmcfreq->set_rate_params)
+		return -ENOMEM;
+	rockchip_set_ddrclk_params(dmcfreq->set_rate_params);
+
 	arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, 0, 0,
 		      ROCKCHIP_SIP_CONFIG_DRAM_INIT,
 		      0, 0, 0, 0, &res);
 
-	dmcfreq->set_msch_readlatency = rk3399_set_msch_readlatency;
+	dmcfreq->info.set_msch_readlatency = rk3399_set_msch_readlatency;
+
+	return 0;
+}
+
+static __maybe_unused int rk3528_dmc_init(struct platform_device *pdev,
+					  struct rockchip_dmcfreq *dmcfreq)
+{
+	struct arm_smccc_res res;
+	int ret;
+	int complt_irq;
+	u32 complt_hwirq;
+	struct irq_data *complt_irq_data;
+
+	res = sip_smc_dram(0, 0, ROCKCHIP_SIP_CONFIG_DRAM_GET_VERSION);
+	dev_notice(&pdev->dev, "current ATF version 0x%lx\n", res.a1);
+	if (res.a0 || res.a1 < 0x100) {
+		dev_err(&pdev->dev, "trusted firmware need update to V1.00 and above.\n");
+		return -ENXIO;
+	}
+
+	/*
+	 * first 4KB is used for interface parameters
+	 * after 4KB is dts parameters
+	 * request share memory size 4KB * 2
+	 */
+	res = sip_smc_request_share_mem(2, SHARE_PAGE_TYPE_DDR);
+	if (res.a0 != 0) {
+		dev_err(&pdev->dev, "no ATF memory for init\n");
+		return -ENOMEM;
+	}
+	ddr_psci_param = (struct share_params *)res.a1;
+	/* Clear ddr_psci_param, size is 4KB * 2 */
+	memset_io(ddr_psci_param, 0x0, 4096 * 2);
+
+	wait_ctrl.dcf_en = 0;
+
+	init_waitqueue_head(&wait_ctrl.wait_wq);
+	wait_ctrl.wait_en = 1;
+	wait_ctrl.wait_time_out_ms = 17 * 5;
+
+	complt_irq = platform_get_irq_byname(pdev, "complete");
+	if (complt_irq < 0) {
+		dev_err(&pdev->dev, "no IRQ for complt_irq: %d\n", complt_irq);
+		return complt_irq;
+	}
+	wait_ctrl.complt_irq = complt_irq;
+
+	ret = devm_request_irq(&pdev->dev, complt_irq, wait_dcf_complete_irq,
+			       0, dev_name(&pdev->dev), &wait_ctrl);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "cannot request complt_irq\n");
+		return ret;
+	}
+	disable_irq(complt_irq);
+
+	complt_irq_data = irq_get_irq_data(complt_irq);
+	complt_hwirq = irqd_to_hwirq(complt_irq_data);
+	ddr_psci_param->complt_hwirq = complt_hwirq;
+
+	res = sip_smc_dram(SHARE_PAGE_TYPE_DDR, 0, ROCKCHIP_SIP_CONFIG_DRAM_INIT);
+	if (res.a0) {
+		dev_err(&pdev->dev, "rockchip_sip_config_dram_init error:%lx\n", res.a0);
+		return -ENOMEM;
+	}
+
+	ret = rockchip_get_freq_info(dmcfreq);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "cannot get frequency info\n");
+		return ret;
+	}
+	dmcfreq->is_set_rate_direct = true;
+
+	dmcfreq->set_auto_self_refresh = rockchip_ddr_set_auto_self_refresh;
 
 	return 0;
 }
@@ -1837,6 +1916,97 @@
 	return 0;
 }
 
+static __maybe_unused int rk3588_dmc_init(struct platform_device *pdev,
+					  struct rockchip_dmcfreq *dmcfreq)
+{
+	struct arm_smccc_res res;
+	struct dev_pm_opp *opp;
+	unsigned long opp_rate;
+	int ret;
+	int complt_irq;
+
+	res = sip_smc_dram(0, 0, ROCKCHIP_SIP_CONFIG_DRAM_GET_VERSION);
+	dev_notice(&pdev->dev, "current ATF version 0x%lx\n", res.a1);
+	if (res.a0) {
+		dev_err(&pdev->dev, "trusted firmware unsupported, please update.\n");
+		return -ENXIO;
+	}
+
+	/*
+	 * first 4KB is used for interface parameters
+	 * after 4KB is dts parameters
+	 * request share memory size 4KB * 2
+	 */
+	res = sip_smc_request_share_mem(2, SHARE_PAGE_TYPE_DDR);
+	if (res.a0 != 0) {
+		dev_err(&pdev->dev, "no ATF memory for init\n");
+		return -ENOMEM;
+	}
+	ddr_psci_param = (struct share_params *)res.a1;
+	/* Clear ddr_psci_param, size is 4KB * 2 */
+	memset_io(ddr_psci_param, 0x0, 4096 * 2);
+
+	/* start mcu with sip_smc_dram */
+	wait_ctrl.dcf_en = 2;
+
+	init_waitqueue_head(&wait_ctrl.wait_wq);
+	wait_ctrl.wait_en = 1;
+	wait_ctrl.wait_time_out_ms = 17 * 5;
+
+	complt_irq = platform_get_irq_byname(pdev, "complete");
+	if (complt_irq < 0) {
+		dev_err(&pdev->dev, "no IRQ for complt_irq: %d\n", complt_irq);
+		return complt_irq;
+	}
+	wait_ctrl.complt_irq = complt_irq;
+
+	ret = devm_request_irq(&pdev->dev, complt_irq, wait_dcf_complete_irq,
+			       0, dev_name(&pdev->dev), &wait_ctrl);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "cannot request complt_irq\n");
+		return ret;
+	}
+	disable_irq(complt_irq);
+
+	res = sip_smc_dram(SHARE_PAGE_TYPE_DDR, 0, ROCKCHIP_SIP_CONFIG_DRAM_INIT);
+	if (res.a0) {
+		dev_err(&pdev->dev, "rockchip_sip_config_dram_init error:%lx\n", res.a0);
+		return -ENOMEM;
+	}
+
+	ret = rockchip_dmcfreq_adjust_opp_table(dmcfreq);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "cannot get frequency info\n");
+		return ret;
+	}
+	dmcfreq->is_set_rate_direct = true;
+
+	/* Config the dmcfreq->sleep_volt for deepsleep */
+	opp_rate = dmcfreq->freq_info_rate[dmcfreq->freq_count - 1];
+	opp = devfreq_recommended_opp(&pdev->dev, &opp_rate, 0);
+	if (IS_ERR(opp)) {
+		dev_err(&pdev->dev, "Failed to find opp for %lu Hz\n", opp_rate);
+		return PTR_ERR(opp);
+	}
+	dmcfreq->sleep_volt = opp->supplies[0].u_volt;
+	if (dmcfreq->regulator_count > 1)
+		dmcfreq->sleep_mem_volt = opp->supplies[1].u_volt;
+	dev_pm_opp_put(opp);
+
+	if (of_property_read_u32(pdev->dev.of_node, "wait-mode", &ddr_psci_param->wait_mode))
+		ddr_psci_param->wait_mode = 0;
+
+	res = sip_smc_dram(SHARE_PAGE_TYPE_DDR, 0, ROCKCHIP_SIP_CONFIG_DRAM_GET_STALL_TIME);
+	if (res.a0)
+		dev_err(dmcfreq->dev, "Current ATF unsupported get_stall_time\n");
+	else
+		dmcfreq->info.stall_time_ns = (unsigned int)res.a1;
+
+	dmcfreq->set_auto_self_refresh = rockchip_ddr_set_auto_self_refresh;
+
+	return 0;
+}
+
 static __maybe_unused int rv1126_dmc_init(struct platform_device *pdev,
 					  struct rockchip_dmcfreq *dmcfreq)
 {
@@ -1905,6 +2075,10 @@
 				 &ddr_psci_param->update_deskew_cfg))
 		ddr_psci_param->update_deskew_cfg = 0;
 
+	dmcfreq->set_rate_params = ddr_psci_param;
+	rockchip_set_ddrclk_params(dmcfreq->set_rate_params);
+	rockchip_set_ddrclk_dmcfreq_wait_complete(rockchip_dmcfreq_wait_complete);
+
 	res = sip_smc_dram(SHARE_PAGE_TYPE_DDR, 0,
 			   ROCKCHIP_SIP_CONFIG_DRAM_INIT);
 	if (res.a0) {
@@ -1919,37 +2093,43 @@
 }
 
 static const struct of_device_id rockchip_dmcfreq_of_match[] = {
-#ifdef CONFIG_CPU_PX30
+#if IS_ENABLED(CONFIG_CPU_PX30)
 	{ .compatible = "rockchip,px30-dmc", .data = px30_dmc_init },
 #endif
-#ifdef CONFIG_CPU_RK1808
+#if IS_ENABLED(CONFIG_CPU_RK1808)
 	{ .compatible = "rockchip,rk1808-dmc", .data = rk1808_dmc_init },
 #endif
-#ifdef CONFIG_CPU_RK312X
+#if IS_ENABLED(CONFIG_CPU_RK312X)
 	{ .compatible = "rockchip,rk3128-dmc", .data = rk3128_dmc_init },
 #endif
-#ifdef CONFIG_CPU_RK322X
+#if IS_ENABLED(CONFIG_CPU_RK322X)
 	{ .compatible = "rockchip,rk3228-dmc", .data = rk3228_dmc_init },
 #endif
-#ifdef CONFIG_CPU_RK3288
+#if IS_ENABLED(CONFIG_CPU_RK3288)
 	{ .compatible = "rockchip,rk3288-dmc", .data = rk3288_dmc_init },
 #endif
-#ifdef CONFIG_CPU_RK3308
+#if IS_ENABLED(CONFIG_CPU_RK3308)
 	{ .compatible = "rockchip,rk3308-dmc", .data = NULL },
 #endif
-#ifdef CONFIG_CPU_RK3328
+#if IS_ENABLED(CONFIG_CPU_RK3328)
 	{ .compatible = "rockchip,rk3328-dmc", .data = rk3328_dmc_init },
 #endif
-#ifdef CONFIG_CPU_RK3368
-	{ .compatible = "rockchip,rk3368-dmc", .data = rk3368_dmc_init },
-#endif
-#ifdef CONFIG_CPU_RK3399
+#if IS_ENABLED(CONFIG_CPU_RK3399)
 	{ .compatible = "rockchip,rk3399-dmc", .data = rk3399_dmc_init },
 #endif
-#ifdef CONFIG_CPU_RK3568
+#if IS_ENABLED(CONFIG_CPU_RK3528)
+	{ .compatible = "rockchip,rk3528-dmc", .data = rk3528_dmc_init },
+#endif
+#if IS_ENABLED(CONFIG_CPU_RK3562)
+	{ .compatible = "rockchip,rk3562-dmc", .data = rk3568_dmc_init },
+#endif
+#if IS_ENABLED(CONFIG_CPU_RK3568)
 	{ .compatible = "rockchip,rk3568-dmc", .data = rk3568_dmc_init },
 #endif
-#ifdef CONFIG_CPU_RV1126
+#if IS_ENABLED(CONFIG_CPU_RK3588)
+	{ .compatible = "rockchip,rk3588-dmc", .data = rk3588_dmc_init },
+#endif
+#if IS_ENABLED(CONFIG_CPU_RV1126)
 	{ .compatible = "rockchip,rv1126-dmc", .data = rv1126_dmc_init },
 #endif
 	{ },
@@ -1993,7 +2173,7 @@
 
 	tbl[i].min = 0;
 	tbl[i].max = 0;
-	tbl[i].freq = CPUFREQ_TABLE_END;
+	tbl[i].freq = DMCFREQ_TABLE_END;
 
 	*table = tbl;
 
@@ -2032,7 +2212,7 @@
 	}
 
 	tbl[i].pn = 0;
-	tbl[i].rl = CPUFREQ_TABLE_END;
+	tbl[i].rl = DMCFREQ_TABLE_END;
 
 	*table = tbl;
 
@@ -2074,6 +2254,9 @@
 		case SYS_STATUS_SUSPEND:
 			dmcfreq->suspend_rate = freq * 1000;
 			break;
+		case SYS_STATUS_DEEP_SUSPEND:
+			dmcfreq->deep_suspend_rate = freq * 1000;
+			break;
 		case SYS_STATUS_VIDEO_1080P:
 			dmcfreq->video_1080p_rate = freq * 1000;
 			break;
@@ -2083,11 +2266,17 @@
 		case SYS_STATUS_VIDEO_4K_10B:
 			dmcfreq->video_4k_10b_rate = freq * 1000;
 			break;
+		case SYS_STATUS_VIDEO_SVEP:
+			dmcfreq->video_svep_rate = freq * 1000;
+			break;
 		case SYS_STATUS_PERFORMANCE:
 			dmcfreq->performance_rate = freq * 1000;
 			break;
 		case SYS_STATUS_HDMI:
 			dmcfreq->hdmi_rate = freq * 1000;
+			break;
+		case SYS_STATUS_HDMIRX:
+			dmcfreq->hdmirx_rate = freq * 1000;
 			break;
 		case SYS_STATUS_IDLE:
 			dmcfreq->idle_rate = freq * 1000;
@@ -2194,6 +2383,8 @@
 		return -EINVAL;
 	}
 
+	dmcfreq->auto_min_rate = dmcfreq->rate_low;
+
 	for (i = 0; i < count / 2; i++) {
 		of_property_read_u32_index(np, porp_name, 2 * i,
 					   &status);
@@ -2207,6 +2398,11 @@
 		case SYS_STATUS_SUSPEND:
 			dmcfreq->suspend_rate = rockchip_freq_level_2_rate(dmcfreq, level);
 			dev_info(dmcfreq->dev, "suspend_rate = %ld\n", dmcfreq->suspend_rate);
+			break;
+		case SYS_STATUS_DEEP_SUSPEND:
+			dmcfreq->deep_suspend_rate = rockchip_freq_level_2_rate(dmcfreq, level);
+			dev_info(dmcfreq->dev, "deep_suspend_rate = %ld\n",
+				 dmcfreq->deep_suspend_rate);
 			break;
 		case SYS_STATUS_VIDEO_1080P:
 			dmcfreq->video_1080p_rate = rockchip_freq_level_2_rate(dmcfreq, level);
@@ -2222,6 +2418,16 @@
 			dev_info(dmcfreq->dev, "video_4k_10b_rate = %ld\n",
 				 dmcfreq->video_4k_10b_rate);
 			break;
+		case SYS_STATUS_VIDEO_4K_60P:
+			dmcfreq->video_4k_60p_rate = rockchip_freq_level_2_rate(dmcfreq, level);
+			dev_info(dmcfreq->dev, "video_4k_60p_rate = %ld\n",
+				 dmcfreq->video_4k_60p_rate);
+			break;
+		case SYS_STATUS_VIDEO_SVEP:
+			dmcfreq->video_svep_rate = rockchip_freq_level_2_rate(dmcfreq, level);
+			dev_info(dmcfreq->dev, "video_svep_rate = %ld\n",
+				 dmcfreq->video_svep_rate);
+			break;
 		case SYS_STATUS_PERFORMANCE:
 			dmcfreq->performance_rate = rockchip_freq_level_2_rate(dmcfreq, level);
 			dev_info(dmcfreq->dev, "performance_rate = %ld\n",
@@ -2230,6 +2436,10 @@
 		case SYS_STATUS_HDMI:
 			dmcfreq->hdmi_rate = rockchip_freq_level_2_rate(dmcfreq, level);
 			dev_info(dmcfreq->dev, "hdmi_rate = %ld\n", dmcfreq->hdmi_rate);
+			break;
+		case SYS_STATUS_HDMIRX:
+			dmcfreq->hdmirx_rate = rockchip_freq_level_2_rate(dmcfreq, level);
+			dev_info(dmcfreq->dev, "hdmirx_rate = %ld\n", dmcfreq->hdmirx_rate);
 			break;
 		case SYS_STATUS_IDLE:
 			dmcfreq->idle_rate = rockchip_freq_level_2_rate(dmcfreq, level);
@@ -2269,19 +2479,11 @@
 
 static void rockchip_dmcfreq_update_target(struct rockchip_dmcfreq *dmcfreq)
 {
-	struct devfreq *df = dmcfreq->devfreq;
+	struct devfreq *devfreq = dmcfreq->info.devfreq;
 
-	mutex_lock(&df->lock);
-
-	if (dmcfreq->last_refresh != dmcfreq->refresh) {
-		if (dmcfreq->set_auto_self_refresh)
-			dmcfreq->set_auto_self_refresh(dmcfreq->refresh);
-		dmcfreq->last_refresh = dmcfreq->refresh;
-	}
-
-	update_devfreq(df);
-
-	mutex_unlock(&df->lock);
+	mutex_lock(&devfreq->lock);
+	update_devfreq(devfreq);
+	mutex_unlock(&devfreq->lock);
 }
 
 static int rockchip_dmcfreq_system_status_notifier(struct notifier_block *nb,
@@ -2302,8 +2504,8 @@
 	}
 
 	if (dmcfreq->reboot_rate && (status & SYS_STATUS_REBOOT)) {
-		if (dmcfreq->auto_freq_en)
-			devfreq_monitor_stop(dmcfreq->devfreq);
+		if (dmcfreq->info.auto_freq_en)
+			devfreq_monitor_stop(dmcfreq->info.devfreq);
 		target_rate = dmcfreq->reboot_rate;
 		goto next;
 	}
@@ -2329,6 +2531,11 @@
 			target_rate = dmcfreq->hdmi_rate;
 	}
 
+	if (dmcfreq->hdmirx_rate && (status & SYS_STATUS_HDMIRX)) {
+		if (dmcfreq->hdmirx_rate > target_rate)
+			target_rate = dmcfreq->hdmirx_rate;
+	}
+
 	if (dmcfreq->video_4k_rate && (status & SYS_STATUS_VIDEO_4K)) {
 		if (dmcfreq->video_4k_rate > target_rate)
 			target_rate = dmcfreq->video_4k_rate;
@@ -2339,20 +2546,51 @@
 			target_rate = dmcfreq->video_4k_10b_rate;
 	}
 
+	if (dmcfreq->video_4k_60p_rate && (status & SYS_STATUS_VIDEO_4K_60P)) {
+		if (dmcfreq->video_4k_60p_rate > target_rate)
+			target_rate = dmcfreq->video_4k_60p_rate;
+	}
+
 	if (dmcfreq->video_1080p_rate && (status & SYS_STATUS_VIDEO_1080P)) {
 		if (dmcfreq->video_1080p_rate > target_rate)
 			target_rate = dmcfreq->video_1080p_rate;
 	}
 
+	if (dmcfreq->video_svep_rate && (status & SYS_STATUS_VIDEO_SVEP)) {
+		if (dmcfreq->video_svep_rate > target_rate)
+			target_rate = dmcfreq->video_svep_rate;
+	}
+
 next:
 
-	dev_dbg(&dmcfreq->devfreq->dev, "status=0x%x\n", (unsigned int)status);
-	dmcfreq->refresh = refresh;
+	dev_dbg(dmcfreq->dev, "status=0x%x\n", (unsigned int)status);
 	dmcfreq->is_fixed = is_fixed;
 	dmcfreq->status_rate = target_rate;
+	if (dmcfreq->refresh != refresh) {
+		if (dmcfreq->set_auto_self_refresh)
+			dmcfreq->set_auto_self_refresh(refresh);
+		dmcfreq->refresh = refresh;
+	}
 	rockchip_dmcfreq_update_target(dmcfreq);
 
 	return NOTIFY_OK;
+}
+
+static int rockchip_dmcfreq_panic_notifier(struct notifier_block *nb,
+					   unsigned long v, void *p)
+{
+	struct rockchip_dmcfreq *dmcfreq =
+		container_of(nb, struct rockchip_dmcfreq, panic_nb);
+	struct device *dev = dmcfreq->dev;
+
+	if (dmcfreq->regulator_count == 1)
+		dev_info(dev, "cur_freq: %lu Hz, volt: %lu uV\n",
+			 dmcfreq->rate, dmcfreq->volt);
+	else
+		dev_info(dev, "cur_freq: %lu Hz, volt_vdd: %lu uV, volt_mem: %lu uV\n",
+			 dmcfreq->rate, dmcfreq->volt, dmcfreq->mem_volt);
+
+	return 0;
 }
 
 static ssize_t rockchip_dmcfreq_status_show(struct device *dev,
@@ -2438,133 +2676,6 @@
 
 static DEVICE_ATTR_RW(downdifferential);
 
-static void rockchip_dmcfreq_set_msch_rl(struct rockchip_dmcfreq *dmcfreq,
-					 unsigned int readlatency)
-
-{
-	down_read(&rockchip_dmcfreq_sem);
-	dev_dbg(dmcfreq->dev, "rl 0x%x -> 0x%x\n",
-		dmcfreq->read_latency, readlatency);
-	if (!dmcfreq->set_msch_readlatency(readlatency))
-		dmcfreq->read_latency = readlatency;
-	else
-		dev_err(dmcfreq->dev, "failed to set msch rl\n");
-	up_read(&rockchip_dmcfreq_sem);
-}
-
-static void rockchip_dmcfreq_set_msch_rl_work(struct work_struct *work)
-{
-	struct rockchip_dmcfreq *dmcfreq = msch_rl_to_dmcfreq(work);
-
-	rockchip_dmcfreq_set_msch_rl(dmcfreq, 0);
-	dmcfreq->is_msch_rl_work_started = false;
-}
-
-static void rockchip_dmcfreq_msch_rl_init(struct rockchip_dmcfreq *dmcfreq)
-{
-	if (!dmcfreq->set_msch_readlatency)
-		return;
-	INIT_DELAYED_WORK(&dmcfreq->msch_rl_work,
-			  rockchip_dmcfreq_set_msch_rl_work);
-}
-
-void rockchip_dmcfreq_vop_bandwidth_update(struct devfreq *devfreq,
-					   unsigned int line_bw_mbyte,
-					   unsigned int frame_bw_mbyte,
-					   unsigned int plane_num)
-{
-	struct device *dev;
-	struct rockchip_dmcfreq *dmcfreq;
-	unsigned long vop_last_rate, target = 0;
-	unsigned int readlatency = 0;
-	int i;
-
-	if (!devfreq)
-		return;
-
-	dev = devfreq->dev.parent;
-	dmcfreq = dev_get_drvdata(dev);
-	if (!dmcfreq)
-		return;
-
-	dev_dbg(dmcfreq->dev, "line bw=%u, frame bw=%u, pn=%u\n",
-		line_bw_mbyte, frame_bw_mbyte, plane_num);
-
-	if (!dmcfreq->vop_pn_rl_tbl || !dmcfreq->set_msch_readlatency)
-		goto vop_bw_tbl;
-	for (i = 0; dmcfreq->vop_pn_rl_tbl[i].rl != CPUFREQ_TABLE_END; i++) {
-		if (plane_num >= dmcfreq->vop_pn_rl_tbl[i].pn)
-			readlatency = dmcfreq->vop_pn_rl_tbl[i].rl;
-	}
-	if (readlatency) {
-		cancel_delayed_work_sync(&dmcfreq->msch_rl_work);
-		dmcfreq->is_msch_rl_work_started = false;
-		if (dmcfreq->read_latency != readlatency)
-			rockchip_dmcfreq_set_msch_rl(dmcfreq, readlatency);
-	} else if (dmcfreq->read_latency &&
-		   !dmcfreq->is_msch_rl_work_started) {
-		dmcfreq->is_msch_rl_work_started = true;
-		schedule_delayed_work(&dmcfreq->msch_rl_work,
-				      msecs_to_jiffies(MSCH_RL_DELAY_TIME));
-	}
-
-vop_bw_tbl:
-	if (!dmcfreq->auto_freq_en || !dmcfreq->vop_bw_tbl)
-		goto vop_frame_bw_tbl;
-	for (i = 0; dmcfreq->vop_bw_tbl[i].freq != CPUFREQ_TABLE_END; i++) {
-		if (line_bw_mbyte >= dmcfreq->vop_bw_tbl[i].min)
-			target = dmcfreq->vop_bw_tbl[i].freq;
-	}
-
-vop_frame_bw_tbl:
-	if (!dmcfreq->auto_freq_en || !dmcfreq->vop_frame_bw_tbl)
-		goto next;
-	for (i = 0; dmcfreq->vop_frame_bw_tbl[i].freq != CPUFREQ_TABLE_END;
-	     i++) {
-		if (frame_bw_mbyte >= dmcfreq->vop_frame_bw_tbl[i].min) {
-			if (target < dmcfreq->vop_frame_bw_tbl[i].freq)
-				target = dmcfreq->vop_frame_bw_tbl[i].freq;
-		}
-	}
-
-next:
-	vop_last_rate = dmcfreq->vop_req_rate;
-	dmcfreq->vop_req_rate = target;
-	if (target > vop_last_rate)
-		rockchip_dmcfreq_update_target(dmcfreq);
-}
-EXPORT_SYMBOL(rockchip_dmcfreq_vop_bandwidth_update);
-
-int rockchip_dmcfreq_vop_bandwidth_request(struct devfreq *devfreq,
-					   unsigned int bw_mbyte)
-{
-	struct device *dev;
-	struct rockchip_dmcfreq *dmcfreq;
-	unsigned long target = 0;
-	int i;
-
-	if (!devfreq)
-		return 0;
-
-	dev = devfreq->dev.parent;
-	dmcfreq = dev_get_drvdata(dev);
-
-	if (!dmcfreq || !dmcfreq->auto_freq_en || !dmcfreq->vop_bw_tbl)
-		return 0;
-
-	for (i = 0; dmcfreq->vop_bw_tbl[i].freq != CPUFREQ_TABLE_END; i++) {
-		if (bw_mbyte <= dmcfreq->vop_bw_tbl[i].max) {
-			target = dmcfreq->vop_bw_tbl[i].freq;
-			break;
-		}
-	}
-	if (target)
-		return 0;
-	else
-		return -EINVAL;
-}
-EXPORT_SYMBOL(rockchip_dmcfreq_vop_bandwidth_request);
-
 static unsigned long get_nocp_req_rate(struct rockchip_dmcfreq *dmcfreq)
 {
 	unsigned long target = 0, cpu_bw = 0;
@@ -2597,14 +2708,14 @@
 	unsigned long target_freq = 0, nocp_req_rate = 0;
 	u64 now;
 
-	if (dmcfreq->auto_freq_en && !dmcfreq->is_fixed) {
+	if (dmcfreq->info.auto_freq_en && !dmcfreq->is_fixed) {
 		if (dmcfreq->status_rate)
 			target_freq = dmcfreq->status_rate;
 		else if (dmcfreq->auto_min_rate)
 			target_freq = dmcfreq->auto_min_rate;
 		nocp_req_rate = get_nocp_req_rate(dmcfreq);
 		target_freq = max3(target_freq, nocp_req_rate,
-				   dmcfreq->vop_req_rate);
+				   dmcfreq->info.vop_req_rate);
 		now = ktime_to_us(ktime_get());
 		if (now < dmcfreq->touchboostpulse_endtime)
 			target_freq = max(target_freq, dmcfreq->boost_rate);
@@ -2615,7 +2726,7 @@
 			target_freq = dmcfreq->normal_rate;
 		if (target_freq)
 			*freq = target_freq;
-		if (dmcfreq->auto_freq_en && !devfreq_update_stats(df))
+		if (dmcfreq->info.auto_freq_en && !devfreq_update_stats(df))
 			return 0;
 		goto reset_last_status;
 	}
@@ -2686,7 +2797,7 @@
 {
 	struct rockchip_dmcfreq *dmcfreq = dev_get_drvdata(devfreq->dev.parent);
 
-	if (!dmcfreq->auto_freq_en)
+	if (!dmcfreq->info.auto_freq_en)
 		return 0;
 
 	switch (event) {
@@ -2698,8 +2809,8 @@
 		devfreq_monitor_stop(devfreq);
 		break;
 
-	case DEVFREQ_GOV_INTERVAL:
-		devfreq_interval_update(devfreq, (unsigned int *)data);
+	case DEVFREQ_GOV_UPDATE_INTERVAL:
+		devfreq_update_interval(devfreq, (unsigned int *)data);
 		break;
 
 	case DEVFREQ_GOV_SUSPEND:
@@ -2727,7 +2838,7 @@
 {
 	int i, ret;
 
-	if (!dmcfreq->auto_freq_en)
+	if (!dmcfreq->info.auto_freq_en)
 		return 0;
 
 	for (i = 0; i < dmcfreq->edev_count; i++) {
@@ -2746,7 +2857,7 @@
 {
 	int i, ret;
 
-	if (!dmcfreq->auto_freq_en)
+	if (!dmcfreq->info.auto_freq_en)
 		return 0;
 
 	for (i = 0; i < dmcfreq->edev_count; i++) {
@@ -2782,7 +2893,7 @@
 	struct device_node *events_np, *np = dev->of_node;
 	int i, j, count, available_count = 0;
 
-	count = devfreq_event_get_edev_count(dev);
+	count = devfreq_event_get_edev_count(dev, "devfreq-events");
 	if (count < 0) {
 		dev_dbg(dev, "failed to get count of devfreq-event dev\n");
 		return 0;
@@ -2817,7 +2928,7 @@
 				return -EINVAL;
 			}
 			dmcfreq->edev[j] =
-				devfreq_event_get_edev_by_phandle(dev, i);
+				devfreq_event_get_edev_by_phandle(dev, "devfreq-events", i);
 			if (IS_ERR(dmcfreq->edev[j]))
 				return -EPROBE_DEFER;
 			j++;
@@ -2825,7 +2936,7 @@
 			of_node_put(events_np);
 		}
 	}
-	dmcfreq->auto_freq_en = true;
+	dmcfreq->info.auto_freq_en = true;
 	dmcfreq->dfi_id = rockchip_get_edev_id(dmcfreq, "dfi");
 	dmcfreq->nocp_cpu_id = rockchip_get_edev_id(dmcfreq, "nocp-cpu");
 	dmcfreq->nocp_bw =
@@ -2840,21 +2951,61 @@
 static int rockchip_dmcfreq_power_control(struct rockchip_dmcfreq *dmcfreq)
 {
 	struct device *dev = dmcfreq->dev;
+	struct device_node *np = dev->of_node;
+	struct opp_table *opp_table = NULL, *reg_opp_table = NULL;
+	const char * const reg_names[] = {"center", "mem"};
+	int ret = 0;
+
+	if (of_find_property(np, "mem-supply", NULL))
+		dmcfreq->regulator_count = 2;
+	else
+		dmcfreq->regulator_count = 1;
+	reg_opp_table = dev_pm_opp_set_regulators(dev, reg_names,
+						  dmcfreq->regulator_count);
+	if (IS_ERR(reg_opp_table)) {
+		dev_err(dev, "failed to set regulators\n");
+		return PTR_ERR(reg_opp_table);
+	}
+	opp_table = dev_pm_opp_register_set_opp_helper(dev, rockchip_dmcfreq_opp_helper);
+	if (IS_ERR(opp_table)) {
+		dev_err(dev, "failed to set opp helper\n");
+		ret = PTR_ERR(opp_table);
+		goto reg_opp_table;
+	}
 
 	dmcfreq->vdd_center = devm_regulator_get_optional(dev, "center");
 	if (IS_ERR(dmcfreq->vdd_center)) {
 		dev_err(dev, "Cannot get the regulator \"center\"\n");
-		return PTR_ERR(dmcfreq->vdd_center);
+		ret = PTR_ERR(dmcfreq->vdd_center);
+		goto opp_table;
+	}
+	if (dmcfreq->regulator_count > 1) {
+		dmcfreq->mem_reg = devm_regulator_get_optional(dev, "mem");
+		if (IS_ERR(dmcfreq->mem_reg)) {
+			dev_err(dev, "Cannot get the regulator \"mem\"\n");
+			ret = PTR_ERR(dmcfreq->mem_reg);
+			goto opp_table;
+		}
 	}
 
 	dmcfreq->dmc_clk = devm_clk_get(dev, "dmc_clk");
 	if (IS_ERR(dmcfreq->dmc_clk)) {
 		dev_err(dev, "Cannot get the clk dmc_clk. If using SCMI, trusted firmware need update to V1.01 and above.\n");
-		return PTR_ERR(dmcfreq->dmc_clk);
+		ret = PTR_ERR(dmcfreq->dmc_clk);
+		goto opp_table;
 	}
 	dmcfreq->rate = clk_get_rate(dmcfreq->dmc_clk);
 
 	return 0;
+
+opp_table:
+	if (opp_table)
+		dev_pm_opp_unregister_set_opp_helper(opp_table);
+reg_opp_table:
+	if (reg_opp_table)
+		dev_pm_opp_put_regulators(reg_opp_table);
+
+	return ret;
 }
 
 static int rockchip_dmcfreq_dmc_init(struct platform_device *pdev,
@@ -2894,25 +3045,31 @@
 			     &dmcfreq->ondemand_data.upthreshold);
 	of_property_read_u32(np, "downdifferential",
 			     &dmcfreq->ondemand_data.downdifferential);
-	if (dmcfreq->auto_freq_en)
+	if (dmcfreq->info.auto_freq_en)
 		of_property_read_u32(np, "auto-freq-en",
-				     &dmcfreq->auto_freq_en);
-	of_property_read_u32(np, "auto-min-freq",
-			     (u32 *)&dmcfreq->auto_min_rate);
-	dmcfreq->auto_min_rate *= 1000;
+				     &dmcfreq->info.auto_freq_en);
+	if (!dmcfreq->auto_min_rate) {
+		of_property_read_u32(np, "auto-min-freq",
+				     (u32 *)&dmcfreq->auto_min_rate);
+		dmcfreq->auto_min_rate *= 1000;
+	}
 
 	if (rockchip_get_freq_map_talbe(np, "cpu-bw-dmc-freq",
 					&dmcfreq->cpu_bw_tbl))
 		dev_dbg(dev, "failed to get cpu bandwidth to dmc rate\n");
 	if (rockchip_get_freq_map_talbe(np, "vop-frame-bw-dmc-freq",
-					&dmcfreq->vop_frame_bw_tbl))
+					&dmcfreq->info.vop_frame_bw_tbl))
 		dev_dbg(dev, "failed to get vop frame bandwidth to dmc rate\n");
 	if (rockchip_get_freq_map_talbe(np, "vop-bw-dmc-freq",
-					&dmcfreq->vop_bw_tbl))
+					&dmcfreq->info.vop_bw_tbl))
 		dev_err(dev, "failed to get vop bandwidth to dmc rate\n");
 	if (rockchip_get_rl_map_talbe(np, "vop-pn-msch-readlatency",
-				      &dmcfreq->vop_pn_rl_tbl))
+				      &dmcfreq->info.vop_pn_rl_tbl))
 		dev_err(dev, "failed to get vop pn to msch rl\n");
+	if (dmcfreq->video_4k_rate)
+		dmcfreq->info.vop_4k_rate = dmcfreq->video_4k_rate;
+	else if (dmcfreq->video_4k_10b_rate)
+		dmcfreq->info.vop_4k_rate = dmcfreq->video_4k_10b_rate;
 
 	of_property_read_u32(np, "touchboost_duration",
 			     (u32 *)&dmcfreq->touchboostpulse_duration_val);
@@ -2922,35 +3079,12 @@
 		dmcfreq->touchboostpulse_duration_val = 500 * USEC_PER_MSEC;
 }
 
-static int rockchip_dmcfreq_set_volt_only(struct rockchip_dmcfreq *dmcfreq)
-{
-	struct device *dev = dmcfreq->dev;
-	struct dev_pm_opp *opp;
-	unsigned long opp_volt, opp_rate = dmcfreq->rate;
-	int ret;
-
-	opp = devfreq_recommended_opp(dev, &opp_rate, 0);
-	if (IS_ERR(opp)) {
-		dev_err(dev, "Failed to find opp for %lu Hz\n", opp_rate);
-		return PTR_ERR(opp);
-	}
-	opp_volt = dev_pm_opp_get_voltage(opp);
-	dev_pm_opp_put(opp);
-
-	ret = regulator_set_voltage(dmcfreq->vdd_center, opp_volt, INT_MAX);
-	if (ret) {
-		dev_err(dev, "Cannot set voltage %lu uV\n", opp_volt);
-		return ret;
-	}
-
-	return 0;
-}
-
 static int rockchip_dmcfreq_add_devfreq(struct rockchip_dmcfreq *dmcfreq)
 {
 	struct devfreq_dev_profile *devp = &rockchip_devfreq_dmc_profile;
 	struct device *dev = dmcfreq->dev;
 	struct dev_pm_opp *opp;
+	struct devfreq *devfreq;
 	unsigned long opp_rate = dmcfreq->rate;
 
 	opp = devfreq_recommended_opp(dev, &opp_rate, 0);
@@ -2961,43 +3095,47 @@
 	dev_pm_opp_put(opp);
 
 	devp->initial_freq = dmcfreq->rate;
-	dmcfreq->devfreq = devm_devfreq_add_device(dev, devp,
-						   "dmc_ondemand",
-						   &dmcfreq->ondemand_data);
-	if (IS_ERR(dmcfreq->devfreq)) {
+	devfreq = devm_devfreq_add_device(dev, devp, "dmc_ondemand",
+					  &dmcfreq->ondemand_data);
+	if (IS_ERR(devfreq)) {
 		dev_err(dev, "failed to add devfreq\n");
-		return PTR_ERR(dmcfreq->devfreq);
+		return PTR_ERR(devfreq);
 	}
 
-	devm_devfreq_register_opp_notifier(dev, dmcfreq->devfreq);
+	devm_devfreq_register_opp_notifier(dev, devfreq);
 
-	dmcfreq->devfreq->last_status.current_frequency = opp_rate;
+	devfreq->last_status.current_frequency = opp_rate;
+	devfreq->suspend_freq = dmcfreq->deep_suspend_rate;
 
-	reset_last_status(dmcfreq->devfreq);
+	reset_last_status(devfreq);
+
+	dmcfreq->info.devfreq = devfreq;
 
 	return 0;
 }
-
-static struct monitor_dev_profile dmc_mdevp = {
-	.type = MONITOR_TPYE_DEV,
-	.low_temp_adjust = rockchip_monitor_dev_low_temp_adjust,
-	.high_temp_adjust = rockchip_monitor_dev_high_temp_adjust,
-};
 
 static void rockchip_dmcfreq_register_notifier(struct rockchip_dmcfreq *dmcfreq)
 {
 	int ret;
 
-	if (vop_register_dmc())
-		dev_err(dmcfreq->dev, "fail to register notify to vop.\n");
+	if (dmcfreq->system_status_en || dmcfreq->info.auto_freq_en) {
+		if (vop_register_dmc())
+			dev_err(dmcfreq->dev, "fail to register notify to vop.\n");
 
-	dmcfreq->status_nb.notifier_call =
-		rockchip_dmcfreq_system_status_notifier;
-	ret = rockchip_register_system_status_notifier(&dmcfreq->status_nb);
+		dmcfreq->status_nb.notifier_call =
+			rockchip_dmcfreq_system_status_notifier;
+		ret = rockchip_register_system_status_notifier(&dmcfreq->status_nb);
+		if (ret)
+			dev_err(dmcfreq->dev, "failed to register system_status nb\n");
+	}
+
+	dmcfreq->panic_nb.notifier_call = rockchip_dmcfreq_panic_notifier;
+	ret = atomic_notifier_chain_register(&panic_notifier_list,
+					     &dmcfreq->panic_nb);
 	if (ret)
-		dev_err(dmcfreq->dev, "failed to register system_status nb\n");
+		dev_err(dmcfreq->dev, "failed to register panic nb\n");
 
-	dmc_mdevp.data = dmcfreq->devfreq;
+	dmc_mdevp.data = dmcfreq->info.devfreq;
 	dmcfreq->mdev_info = rockchip_system_monitor_register(dmcfreq->dev,
 							      &dmc_mdevp);
 	if (IS_ERR(dmcfreq->mdev_info)) {
@@ -3008,18 +3146,19 @@
 
 static void rockchip_dmcfreq_add_interface(struct rockchip_dmcfreq *dmcfreq)
 {
-	if (sysfs_create_file(&dmcfreq->devfreq->dev.kobj,
-			      &dev_attr_upthreshold.attr))
+	struct devfreq *devfreq = dmcfreq->info.devfreq;
+
+	if (sysfs_create_file(&devfreq->dev.kobj, &dev_attr_upthreshold.attr))
 		dev_err(dmcfreq->dev,
 			"failed to register upthreshold sysfs file\n");
-	if (sysfs_create_file(&dmcfreq->devfreq->dev.kobj,
+	if (sysfs_create_file(&devfreq->dev.kobj,
 			      &dev_attr_downdifferential.attr))
 		dev_err(dmcfreq->dev,
 			"failed to register downdifferential sysfs file\n");
 
-	if (!rockchip_add_system_status_interface(&dmcfreq->devfreq->dev))
+	if (!rockchip_add_system_status_interface(&devfreq->dev))
 		return;
-	if (sysfs_create_file(&dmcfreq->devfreq->dev.kobj,
+	if (sysfs_create_file(&devfreq->dev.kobj,
 			      &dev_attr_system_status.attr))
 		dev_err(dmcfreq->dev,
 			"failed to register system_status sysfs file\n");
@@ -3049,7 +3188,7 @@
 		return;
 	dmcfreq->touchboostpulse_endtime = endtime;
 
-	schedule_work(&dmcfreq->boost_work);
+	queue_work(system_freezable_wq, &dmcfreq->boost_work);
 }
 
 static int rockchip_dmcfreq_input_connect(struct input_handler *handler,
@@ -3238,7 +3377,7 @@
 		return;
 	dmcfreq->devfreq_cooling =
 		of_devfreq_cooling_register_power(dmcfreq->dev->of_node,
-						  dmcfreq->devfreq,
+						  dmcfreq->info.devfreq,
 						  &ddr_cooling_power_data);
 	if (IS_ERR(dmcfreq->devfreq_cooling)) {
 		ret = PTR_ERR(dmcfreq->devfreq_cooling);
@@ -3259,6 +3398,7 @@
 		return -ENOMEM;
 
 	data->dev = dev;
+	data->info.dev = dev;
 	mutex_init(&data->lock);
 	INIT_LIST_HEAD(&data->video_info_list);
 
@@ -3279,14 +3419,16 @@
 		return ret;
 
 	rockchip_dmcfreq_parse_dt(data);
-	if (!data->system_status_en && !data->auto_freq_en) {
+
+	platform_set_drvdata(pdev, data);
+
+	if (!data->system_status_en && !data->info.auto_freq_en) {
 		dev_info(dev, "don't add devfreq feature\n");
-		return rockchip_dmcfreq_set_volt_only(data);
+		rockchip_dmcfreq_register_notifier(data);
+		return 0;
 	}
 
-	pm_qos_add_request(&pm_qos, PM_QOS_CPU_DMA_LATENCY,
-			   PM_QOS_DEFAULT_VALUE);
-	platform_set_drvdata(pdev, data);
+	cpu_latency_qos_add_request(&pm_qos, PM_QOS_DEFAULT_VALUE);
 
 	ret = devfreq_add_governor(&devfreq_dmc_ondemand);
 	if (ret)
@@ -3303,7 +3445,7 @@
 	rockchip_dmcfreq_register_notifier(data);
 	rockchip_dmcfreq_add_interface(data);
 	rockchip_dmcfreq_boost_init(data);
-	rockchip_dmcfreq_msch_rl_init(data);
+	rockchip_dmcfreq_vop_bandwidth_init(&data->info);
 	rockchip_dmcfreq_register_cooling_device(data);
 
 	rockchip_set_system_status(SYS_STATUS_NORMAL);
@@ -3323,10 +3465,33 @@
 	if (ret)
 		return ret;
 
-	ret = devfreq_suspend_device(dmcfreq->devfreq);
-	if (ret < 0) {
-		dev_err(dev, "failed to suspend the devfreq devices\n");
-		return ret;
+	if (dmcfreq->info.devfreq) {
+		ret = devfreq_suspend_device(dmcfreq->info.devfreq);
+		if (ret < 0) {
+			dev_err(dev, "failed to suspend the devfreq devices\n");
+			return ret;
+		}
+	}
+
+	/* set voltage to sleep_volt if need */
+	if (dmcfreq->sleep_volt && dmcfreq->sleep_volt != dmcfreq->volt) {
+		ret = regulator_set_voltage(dmcfreq->vdd_center,
+					    dmcfreq->sleep_volt, INT_MAX);
+		if (ret) {
+			dev_err(dev, "Cannot set vdd voltage %lu uV\n",
+				dmcfreq->sleep_volt);
+			return ret;
+		}
+	}
+	if (dmcfreq->sleep_mem_volt &&
+	    dmcfreq->sleep_mem_volt != dmcfreq->mem_volt) {
+		ret = regulator_set_voltage(dmcfreq->mem_reg,
+					    dmcfreq->sleep_mem_volt, INT_MAX);
+		if (ret) {
+			dev_err(dev, "Cannot set mem voltage %lu uV\n",
+				dmcfreq->sleep_mem_volt);
+			return ret;
+		}
 	}
 
 	return 0;
@@ -3340,15 +3505,39 @@
 	if (!dmcfreq)
 		return 0;
 
+	/* restore voltage if it is sleep_volt */
+	if (dmcfreq->sleep_volt && dmcfreq->sleep_volt != dmcfreq->volt) {
+		ret = regulator_set_voltage(dmcfreq->vdd_center, dmcfreq->volt,
+					    INT_MAX);
+		if (ret) {
+			dev_err(dev, "Cannot set vdd voltage %lu uV\n",
+				dmcfreq->volt);
+			return ret;
+		}
+	}
+	if (dmcfreq->sleep_mem_volt &&
+	    dmcfreq->sleep_mem_volt != dmcfreq->mem_volt) {
+		ret = regulator_set_voltage(dmcfreq->mem_reg, dmcfreq->mem_volt,
+					    INT_MAX);
+		if (ret) {
+			dev_err(dev, "Cannot set mem voltage %lu uV\n",
+				dmcfreq->mem_volt);
+			return ret;
+		}
+	}
+
 	ret = rockchip_dmcfreq_enable_event(dmcfreq);
 	if (ret)
 		return ret;
 
-	ret = devfreq_resume_device(dmcfreq->devfreq);
-	if (ret < 0) {
-		dev_err(dev, "failed to resume the devfreq devices\n");
-		return ret;
+	if (dmcfreq->info.devfreq) {
+		ret = devfreq_resume_device(dmcfreq->info.devfreq);
+		if (ret < 0) {
+			dev_err(dev, "failed to resume the devfreq devices\n");
+			return ret;
+		}
 	}
+
 	return ret;
 }
 
@@ -3364,6 +3553,6 @@
 };
 module_platform_driver(rockchip_dmcfreq_driver);
 
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Lin Huang <hl@rock-chips.com>");
+MODULE_AUTHOR("Finley Xiao <finley.xiao@rock-chips.com>");
 MODULE_DESCRIPTION("rockchip dmcfreq driver with devfreq framework");
+MODULE_LICENSE("GPL v2");

--
Gitblit v1.6.2