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