From 35d98a8d1254dcf4f0059610f6ab17ac47d646ac Mon Sep 17 00:00:00 2001 From: Xiao Feng Date: Thu, 12 Mar 2015 19:56:11 +0800 Subject: [PATCH] dvfs: add gpu temperate control Signed-off-by: Xiao Feng --- arch/arm/boot/dts/rk3288.dtsi | 10 ++ arch/arm/mach-rockchip/dvfs.c | 205 +++++++++++++++++++++------------- include/linux/rockchip/dvfs.h | 4 + 3 files changed, 139 insertions(+), 80 deletions(-) diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi index dfd65ef7959d..55bd723853aa 100644 --- a/arch/arm/boot/dts/rk3288.dtsi +++ b/arch/arm/boot/dts/rk3288.dtsi @@ -907,6 +907,7 @@ channel = <0>; temp-limit-enable = <1>; target-temp = <80>; + min_temp_limit = <48>; normal-temp-limit = < /*delta-temp delta-freq*/ 3 96000 @@ -969,6 +970,15 @@ 400000 1200000 >; channel = <1>; + temp-limit-enable = <0>; + target-temp = <90>; + min_temp_limit = <200>; + normal-temp-limit = < + /*delta-temp delta-freq*/ + 3 50000 + 6 150000 + 15 250000 + >; status = "okay"; regu-mode-table = < /*freq mode*/ diff --git a/arch/arm/mach-rockchip/dvfs.c b/arch/arm/mach-rockchip/dvfs.c index f5679cd0723b..20cb311198b1 100644 --- a/arch/arm/mach-rockchip/dvfs.c +++ b/arch/arm/mach-rockchip/dvfs.c @@ -29,16 +29,12 @@ #include "../../../drivers/clk/rockchip/clk-pd.h" #include "efuse.h" -extern int rockchip_tsadc_get_temp(int chn); - #define MHz (1000 * 1000) static LIST_HEAD(rk_dvfs_tree); static DEFINE_MUTEX(rk_dvfs_mutex); static struct workqueue_struct *dvfs_wq; static struct dvfs_node *clk_cpu_dvfs_node; -static unsigned int target_temp = 80; -static int temp_limit_enable; - +static struct dvfs_node *clk_gpu_dvfs_node; static int pd_gpu_off, early_suspend; static DEFINE_MUTEX(switch_vdd_gpu_mutex); struct regulator *vdd_gpu_regulator; @@ -1041,7 +1037,7 @@ static void pvtm_set_dvfs_table(struct dvfs_node *dvfs_node) } } -static void dvfs_virt_temp_limit_work_func(void) +static void dvfs_virt_temp_limit_work_func(struct dvfs_node *dvfs_node) { const struct cpufreq_frequency_table *limits_table = NULL; unsigned int new_temp_limit_rate = -1; @@ -1082,7 +1078,7 @@ static void dvfs_virt_temp_limit_work_func(void) else busy_cpus = 4; - limits_table = clk_cpu_dvfs_node->virt_temp_limit_table[busy_cpus-1]; + limits_table = dvfs_node->virt_temp_limit_table[busy_cpus-1]; DVFS_DBG("delta time %6u us idle %6u us %u cpus select table %d\n", delta_time, delta_idle, nr_cpus, busy_cpus); } @@ -1090,91 +1086,129 @@ static void dvfs_virt_temp_limit_work_func(void) if (limits_table) { new_temp_limit_rate = limits_table[0].frequency; for (i = 0; limits_table[i].frequency != CPUFREQ_TABLE_END; i++) { - if (target_temp >= limits_table[i].index) + if (dvfs_node->target_temp >= + limits_table[i].index) new_temp_limit_rate = limits_table[i].frequency; } } - if (clk_cpu_dvfs_node->temp_limit_rate != new_temp_limit_rate) { - clk_cpu_dvfs_node->temp_limit_rate = new_temp_limit_rate; - dvfs_clk_set_rate(clk_cpu_dvfs_node, clk_cpu_dvfs_node->last_set_rate); - DVFS_DBG("temp_limit_rate:%d\n", (int)clk_cpu_dvfs_node->temp_limit_rate); + if (dvfs_node->temp_limit_rate != new_temp_limit_rate) { + dvfs_node->temp_limit_rate = new_temp_limit_rate; + dvfs_clk_set_rate(dvfs_node, dvfs_node->last_set_rate); + DVFS_DBG("temp_limit_rate:%d\n", + (int)dvfs_node->temp_limit_rate); } } -static void dvfs_temp_limit_work_func(struct work_struct *work) +static void dvfs_temp_limit_performance(struct dvfs_node *dvfs_node, int temp) { - int temp=0, delta_temp=0; - unsigned long delay = HZ/10; - unsigned long arm_rate_step=0; - static int old_temp=0; int i; - queue_delayed_work_on(0, dvfs_wq, to_delayed_work(work), delay); + dvfs_node->temp_limit_rate = dvfs_node->max_rate; + for (i = 0; dvfs_node->per_temp_limit_table[i].frequency != + CPUFREQ_TABLE_END; i++) { + if (temp > dvfs_node->per_temp_limit_table[i].index) + dvfs_node->temp_limit_rate = + dvfs_node->per_temp_limit_table[i].frequency; + } + dvfs_clk_set_rate(dvfs_node, dvfs_node->last_set_rate); +} - temp = rockchip_tsadc_get_temp(1); +static void dvfs_temp_limit_normal(struct dvfs_node *dvfs_node, int temp) +{ + int delta_temp = 0; + unsigned long arm_rate_step = 0; + int i; - if (temp == INVALID_TEMP) - return dvfs_virt_temp_limit_work_func(); + if (temp > dvfs_node->target_temp) { + if (temp > dvfs_node->old_temp) { + delta_temp = temp - dvfs_node->target_temp; + for (i = 0; + dvfs_node->nor_temp_limit_table[i].frequency != + CPUFREQ_TABLE_END; i++) { + if (delta_temp > + dvfs_node->nor_temp_limit_table[i].index) + arm_rate_step = + dvfs_node->nor_temp_limit_table[i].frequency; + } + if (arm_rate_step && + (dvfs_node->temp_limit_rate > arm_rate_step)) { + dvfs_node->temp_limit_rate -= arm_rate_step; + if (dvfs_node->temp_limit_rate < + dvfs_node->min_temp_limit) + dvfs_node->temp_limit_rate = + dvfs_node->min_temp_limit; + dvfs_clk_set_rate(dvfs_node, + dvfs_node->last_set_rate); + } + } + } else { + if (dvfs_node->temp_limit_rate < dvfs_node->max_rate) { + delta_temp = dvfs_node->target_temp - temp; + for (i = 0; + dvfs_node->nor_temp_limit_table[i].frequency != + CPUFREQ_TABLE_END; i++) { + if (delta_temp > + dvfs_node->nor_temp_limit_table[i].index) + arm_rate_step = + dvfs_node->nor_temp_limit_table[i].frequency; + } + + if (arm_rate_step) { + dvfs_node->temp_limit_rate += arm_rate_step; + if (dvfs_node->temp_limit_rate > + dvfs_node->max_rate) + dvfs_node->temp_limit_rate = + dvfs_node->max_rate; + dvfs_clk_set_rate(dvfs_node, + dvfs_node->last_set_rate); + } + } + } +} + +static void dvfs_temp_limit(struct dvfs_node *dvfs_node, int temp) +{ + int delta_temp = 0; //debounce - delta_temp = (old_temp>temp) ? (old_temp-temp) : (temp-old_temp); + delta_temp = (dvfs_node->old_temp > temp) ? (dvfs_node->old_temp-temp) : + (temp-dvfs_node->old_temp); if (delta_temp <= 1) return; if (ROCKCHIP_PM_POLICY_PERFORMANCE == rockchip_pm_get_policy()) { - if (!clk_cpu_dvfs_node->per_temp_limit_table) { + if (!dvfs_node->per_temp_limit_table) return; - } - - clk_cpu_dvfs_node->temp_limit_rate = clk_cpu_dvfs_node->max_rate; - for (i=0; clk_cpu_dvfs_node->per_temp_limit_table[i].frequency != CPUFREQ_TABLE_END; i++) { - if (temp > clk_cpu_dvfs_node->per_temp_limit_table[i].index) { - clk_cpu_dvfs_node->temp_limit_rate = clk_cpu_dvfs_node->per_temp_limit_table[i].frequency; - } - } - dvfs_clk_set_rate(clk_cpu_dvfs_node, clk_cpu_dvfs_node->last_set_rate); + dvfs_temp_limit_performance(dvfs_node, temp); } else if (ROCKCHIP_PM_POLICY_NORMAL == rockchip_pm_get_policy()){ - if (!clk_cpu_dvfs_node->nor_temp_limit_table) { + if (!dvfs_node->nor_temp_limit_table) return; - } - - if (temp > target_temp) { - if (temp > old_temp) { - delta_temp = temp - target_temp; - for (i=0; clk_cpu_dvfs_node->nor_temp_limit_table[i].frequency != CPUFREQ_TABLE_END; i++) { - if (delta_temp > clk_cpu_dvfs_node->nor_temp_limit_table[i].index) { - arm_rate_step = clk_cpu_dvfs_node->nor_temp_limit_table[i].frequency; - } - } - if (arm_rate_step && (clk_cpu_dvfs_node->temp_limit_rate > arm_rate_step)) { - clk_cpu_dvfs_node->temp_limit_rate -= arm_rate_step; - dvfs_clk_set_rate(clk_cpu_dvfs_node, clk_cpu_dvfs_node->last_set_rate); - } - } - } else { - if (clk_cpu_dvfs_node->temp_limit_rate < clk_cpu_dvfs_node->max_rate) { - delta_temp = target_temp - temp; - for (i=0; clk_cpu_dvfs_node->nor_temp_limit_table[i].frequency != CPUFREQ_TABLE_END; i++) { - if (delta_temp > clk_cpu_dvfs_node->nor_temp_limit_table[i].index) { - arm_rate_step = clk_cpu_dvfs_node->nor_temp_limit_table[i].frequency; - } - } - - if (arm_rate_step) { - clk_cpu_dvfs_node->temp_limit_rate += arm_rate_step; - if (clk_cpu_dvfs_node->temp_limit_rate > clk_cpu_dvfs_node->max_rate) { - clk_cpu_dvfs_node->temp_limit_rate = clk_cpu_dvfs_node->max_rate; - } - dvfs_clk_set_rate(clk_cpu_dvfs_node, clk_cpu_dvfs_node->last_set_rate); - } - } - } + dvfs_temp_limit_normal(dvfs_node, temp); } + dvfs_node->old_temp = temp; + DVFS_DBG("cur temp: %d, temp_limit_core_rate: %lu\n", + temp, dvfs_node->temp_limit_rate); +} +static void dvfs_temp_limit_work_func(struct work_struct *work) +{ + unsigned long delay = HZ/10; + int temp = 0; - DVFS_DBG("cur temp: %d, temp_limit_core_rate: %lu\n", temp, clk_cpu_dvfs_node->temp_limit_rate); + queue_delayed_work_on(0, dvfs_wq, to_delayed_work(work), delay); - old_temp = temp; + if (clk_cpu_dvfs_node->temp_limit_enable == 1) { + temp = rockchip_tsadc_get_temp(1); + if (temp == INVALID_TEMP) + dvfs_virt_temp_limit_work_func(clk_cpu_dvfs_node); + else + dvfs_temp_limit(clk_cpu_dvfs_node, temp); + } + if (clk_gpu_dvfs_node->temp_limit_enable == 1) { + temp = rockchip_tsadc_get_temp(2); + if (temp != INVALID_TEMP) + dvfs_temp_limit(clk_gpu_dvfs_node, temp); + } } static DECLARE_DELAYED_WORK(dvfs_temp_limit_work, dvfs_temp_limit_work_func); @@ -1247,7 +1281,10 @@ int dvfs_clk_disable_limit(struct dvfs_node *clk_dvfs_node) EXPORT_SYMBOL(dvfs_clk_disable_limit); void dvfs_disable_temp_limit(void) { - temp_limit_enable = 0; + if (clk_cpu_dvfs_node) + clk_cpu_dvfs_node->temp_limit_enable = 0; + if (clk_gpu_dvfs_node) + clk_gpu_dvfs_node->temp_limit_enable = 0; cancel_delayed_work_sync(&dvfs_temp_limit_work); } @@ -1558,7 +1595,7 @@ static unsigned long dvfs_get_limit_rate(struct dvfs_node *clk_dvfs_node, unsign } else if (rate > clk_dvfs_node->max_rate) { limit_rate = clk_dvfs_node->max_rate; } - if (temp_limit_enable) { + if (clk_dvfs_node->temp_limit_enable) { if (limit_rate > clk_dvfs_node->temp_limit_rate) { limit_rate = clk_dvfs_node->temp_limit_rate; } @@ -2016,10 +2053,13 @@ static int dvfs_node_parse_dt(struct device_node *np, dvfs_node->regu_mode_table = NULL; of_property_read_u32_index(np, "temp-limit-enable", 0, - &temp_limit_enable); - if (temp_limit_enable) { - of_property_read_u32_index(np, "target-temp", 0, &target_temp); - pr_info("target-temp:%d\n", target_temp); + &dvfs_node->temp_limit_enable); + if (dvfs_node->temp_limit_enable) { + of_property_read_u32_index(np, "min_temp_limit", + 0, &dvfs_node->min_temp_limit); + of_property_read_u32_index(np, "target-temp", + 0, &dvfs_node->target_temp); + pr_info("target-temp:%d\n", dvfs_node->target_temp); dvfs_node->nor_temp_limit_table = of_get_temp_limit_table(np, "normal-temp-limit"); @@ -2301,13 +2341,18 @@ static int __init dvfs_init(void) } } - if (temp_limit_enable) { - clk_cpu_dvfs_node = clk_get_dvfs_node("clk_core"); - if (!clk_cpu_dvfs_node){ - return -EINVAL; - } + clk_cpu_dvfs_node = clk_get_dvfs_node("clk_core"); + if (!clk_cpu_dvfs_node) + return -EINVAL; + clk_cpu_dvfs_node->temp_limit_rate = clk_cpu_dvfs_node->max_rate; + + clk_gpu_dvfs_node = clk_get_dvfs_node("clk_gpu"); + if (!clk_gpu_dvfs_node) + return -EINVAL; + clk_gpu_dvfs_node->temp_limit_rate = clk_gpu_dvfs_node->max_rate; - clk_cpu_dvfs_node->temp_limit_rate = clk_cpu_dvfs_node->max_rate; + if (clk_cpu_dvfs_node->temp_limit_enable || + clk_gpu_dvfs_node->temp_limit_enable) { dvfs_wq = alloc_workqueue("dvfs", WQ_NON_REENTRANT | WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_FREEZABLE, 1); queue_delayed_work_on(0, dvfs_wq, &dvfs_temp_limit_work, 0*HZ); } diff --git a/include/linux/rockchip/dvfs.h b/include/linux/rockchip/dvfs.h index 594f9986cbd3..e489edb6f249 100644 --- a/include/linux/rockchip/dvfs.h +++ b/include/linux/rockchip/dvfs.h @@ -133,6 +133,10 @@ struct dvfs_node { unsigned int channel; unsigned int temp_channel; unsigned long temp_limit_rate; + unsigned int target_temp; + unsigned int temp_limit_enable; + unsigned int min_temp_limit; + int old_temp; struct clk *clk; struct pd_node *pd; struct vd_node *vd; -- 2.34.1