From ce28fbc8a6fbc5bf2a6d8157d9eb7f24bbe0e75a Mon Sep 17 00:00:00 2001 From: Finley Xiao Date: Tue, 26 Mar 2019 09:24:11 +0800 Subject: [PATCH] soc: rockchip: system_monitor: Add support limit rate when 4k video Change-Id: I15b443df1e7b24df03e986e401e6032f307aa376 Signed-off-by: Finley Xiao --- .../soc/rockchip/rockchip_system_monitor.c | 84 +++++++++++++++---- .../soc/rockchip/rockchip_system_monitor.h | 4 + 2 files changed, 73 insertions(+), 15 deletions(-) diff --git a/drivers/soc/rockchip/rockchip_system_monitor.c b/drivers/soc/rockchip/rockchip_system_monitor.c index 90f7af9f6ee3..dfe5b0df86b1 100644 --- a/drivers/soc/rockchip/rockchip_system_monitor.c +++ b/drivers/soc/rockchip/rockchip_system_monitor.c @@ -516,10 +516,10 @@ static int rockchip_init_temp_opp_table(struct monitor_dev_info *info) return ret; } -static int monitor_device_parse_dt(struct device *dev, - struct monitor_dev_info *info) +static int monitor_device_parse_wide_temp_config(struct device_node *np, + struct monitor_dev_info *info) { - struct device_node *np; + struct device *dev = info->dev; unsigned long high_temp_max_freq; int ret = 0; u32 value; @@ -565,22 +565,49 @@ static int monitor_device_parse_dt(struct device *dev, info->low_temp, info->high_temp, info->temp_hysteresis); ret = -EINVAL; - goto out; + goto err; } if (!info->low_temp_adjust_table && !info->low_temp_min_volt && !info->low_limit && !info->high_limit) { ret = -EINVAL; - goto out; + goto err; } if (info->low_temp_adjust_table || info->low_temp_min_volt) info->is_low_temp_enabled = true; -out: + return 0; +err: + kfree(info->low_temp_adjust_table); + info->low_temp_adjust_table = NULL; + kfree(info->opp_table); + info->opp_table = NULL; + + return ret; +} + +static int monitor_device_parse_dt(struct device *dev, + struct monitor_dev_info *info) +{ + struct device_node *np; + int ret = 0; + bool is_wide_temp_en = false; + bool is_4k_limit_en = false; + + np = of_parse_phandle(dev->of_node, "operating-points-v2", 0); + if (!np) + return -EINVAL; + + if (!monitor_device_parse_wide_temp_config(np, info)) + is_wide_temp_en = true; + if (!of_property_read_u32(np, "rockchip,video-4k-freq", + &info->video_4k_freq)) + is_4k_limit_en = true; + if (is_wide_temp_en || is_4k_limit_en) + ret = 0; + else + ret = -EINVAL; + of_node_put(np); - if (ret) { - kfree(info->low_temp_adjust_table); - kfree(info->opp_table); - } return ret; } @@ -1018,6 +1045,28 @@ static void rockchip_system_monitor_thermal_check(struct work_struct *work) rockchip_system_monitor_thermal_update(); } +static void rockchip_system_status_limit_freq(unsigned long status) +{ + struct monitor_dev_info *info; + unsigned int target_freq, cpu; + + down_read(&mdev_list_sem); + list_for_each_entry(info, &monitor_dev_list, node) { + if (info->devp->type != MONITOR_TPYE_CPU) + continue; + if (status & SYS_STATUS_VIDEO_4K) + target_freq = info->video_4k_freq; + else + target_freq = 0; + if (target_freq != info->status_limit) { + info->status_limit = target_freq; + cpu = cpumask_any(&info->devp->allowed_cpus); + cpufreq_update_policy(cpu); + } + } + up_read(&mdev_list_sem); +} + static void rockchip_system_status_cpu_on_off(unsigned long status) { struct cpumask offline_cpus; @@ -1039,6 +1088,8 @@ static int rockchip_system_status_notifier(struct notifier_block *nb, unsigned long status, void *ptr) { + rockchip_system_status_limit_freq(status); + rockchip_system_status_cpu_on_off(status); return NOTIFY_OK; @@ -1077,7 +1128,7 @@ static int rockchip_monitor_cpufreq_policy_notifier(struct notifier_block *nb, struct monitor_dev_info *info; struct cpufreq_policy *policy = data; int cpu = policy->cpu; - unsigned int target_freq; + unsigned int limit_freq = UINT_MAX; if (event != CPUFREQ_ADJUST) return NOTIFY_OK; @@ -1088,12 +1139,15 @@ static int rockchip_monitor_cpufreq_policy_notifier(struct notifier_block *nb, continue; if (!cpumask_test_cpu(cpu, &info->devp->allowed_cpus)) continue; + if (info->wide_temp_limit) { - target_freq = info->wide_temp_limit / 1000; - if (target_freq < policy->max) - cpufreq_verify_within_limits(policy, 0, - target_freq); + if (limit_freq > info->wide_temp_limit / 1000) + limit_freq = info->wide_temp_limit / 1000; } + if (info->status_limit && limit_freq > info->status_limit) + limit_freq = info->status_limit; + if (limit_freq < policy->max) + cpufreq_verify_within_limits(policy, 0, limit_freq); } up_read(&mdev_list_sem); diff --git a/include/soc/rockchip/rockchip_system_monitor.h b/include/soc/rockchip/rockchip_system_monitor.h index 4a5f1dbe9e53..70a351ff8de2 100644 --- a/include/soc/rockchip/rockchip_system_monitor.h +++ b/include/soc/rockchip/rockchip_system_monitor.h @@ -49,6 +49,8 @@ struct temp_opp_table { * @high_temp_max_volt: Maximum voltage when high temperature, in microvolt * @wide_temp_limit: Target maximum frequency when low or high temperature, * in Hz + * @video_4k_freq: Maximum frequency when paly 4k video, in KHz + * @status_limit: Minimum frequency of all status frequency, in KHz * @low_temp: Low temperature trip point, in millicelsius * @high_temp: High temperature trip point, in millicelsius * @temp_hysteresis: A low hysteresis value on low_temp, in millicelsius @@ -70,6 +72,8 @@ struct monitor_dev_info { unsigned long low_temp_min_volt; unsigned long high_temp_max_volt; unsigned long wide_temp_limit; + unsigned int video_4k_freq; + unsigned int status_limit; int low_temp; int high_temp; int temp_hysteresis;