From c1a63c40f08f1db5fa6a0dfefbd3fe89fff4c025 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E9=99=88=E4=BA=AE?= Date: Tue, 16 Sep 2014 18:34:33 -0700 Subject: [PATCH] dvfs: add virtual temperature control MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: 陈亮 --- arch/arm/boot/dts/rk312x.dtsi | 5 +- arch/arm/boot/dts/rk3288.dtsi | 4 +- arch/arm/mach-rockchip/ddr_freq.c | 2 +- arch/arm/mach-rockchip/dvfs.c | 97 ++++++++++++++++++++++++++----- include/linux/rockchip/dvfs.h | 1 + 5 files changed, 90 insertions(+), 19 deletions(-) diff --git a/arch/arm/boot/dts/rk312x.dtsi b/arch/arm/boot/dts/rk312x.dtsi index d0229748a9aa..05ac265b1e5d 100755 --- a/arch/arm/boot/dts/rk312x.dtsi +++ b/arch/arm/boot/dts/rk312x.dtsi @@ -829,9 +829,6 @@ }; dvfs { - temp-limit-enable = <0>; - target-temp = <80>; - vd_arm: vd_arm { regulator_name = "vdd_arm"; pd_core { @@ -843,6 +840,8 @@ 816000 1100000 1008000 1100000 >; + temp-limit-enable = <0>; + target-temp = <80>; temp-channel = <1>; normal-temp-limit = < /*delta-temp delta-freq*/ diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi index 51b7f061a571..c26b49c13b49 100755 --- a/arch/arm/boot/dts/rk3288.dtsi +++ b/arch/arm/boot/dts/rk3288.dtsi @@ -898,8 +898,6 @@ }; dvfs { - temp-limit-enable = <1>; - target-temp = <80>; vd_arm: vd_arm { regulator_name = "vdd_arm"; @@ -913,6 +911,8 @@ 816000 1100000 1008000 1100000 >; + temp-limit-enable = <1>; + target-temp = <80>; temp-channel = <1>; normal-temp-limit = < /*delta-temp delta-freq*/ diff --git a/arch/arm/mach-rockchip/ddr_freq.c b/arch/arm/mach-rockchip/ddr_freq.c index 5c41cf7b0520..dd09a5b30735 100644 --- a/arch/arm/mach-rockchip/ddr_freq.c +++ b/arch/arm/mach-rockchip/ddr_freq.c @@ -291,7 +291,6 @@ static noinline long ddrfreq_work(unsigned long sys_status) if (ddr.reboot_rate && (s & SYS_STATUS_REBOOT)) { ddrfreq_mode(false, ddr.reboot_rate, "shutdown/reboot"); - rockchip_cpufreq_reboot_limit_freq(); return timeout; } @@ -769,6 +768,7 @@ CLK_NOTIFIER(pd_vop1, LCDC1) static int ddrfreq_reboot_notifier_event(struct notifier_block *this, unsigned long event, void *ptr) { rockchip_set_system_status(SYS_STATUS_REBOOT); + rockchip_cpufreq_reboot_limit_freq(); return NOTIFY_OK; } diff --git a/arch/arm/mach-rockchip/dvfs.c b/arch/arm/mach-rockchip/dvfs.c index 9647969a9543..ba676f686464 100644 --- a/arch/arm/mach-rockchip/dvfs.c +++ b/arch/arm/mach-rockchip/dvfs.c @@ -23,6 +23,9 @@ #include #include #include +#include +#include +#include #include "../../../drivers/clk/rockchip/clk-pd.h" extern int rockchip_tsadc_get_temp(int chn); @@ -33,7 +36,7 @@ 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 = 1; +static int temp_limit_enable; static int pd_gpu_off, early_suspend; static DEFINE_MUTEX(switch_vdd_gpu_mutex); @@ -855,6 +858,67 @@ static void dvfs_temp_limit_work_func(struct work_struct *work) } #endif +static void dvfs_virt_temp_limit_work_func(void) +{ + const struct cpufreq_frequency_table *limits_table = NULL; + unsigned int new_temp_limit_rate = -1; + unsigned int nr_cpus = num_online_cpus(); + static bool in_perf; + int i; + + if (!soc_is_rk3126() && !soc_is_rk3128()) + return; + + if (rockchip_get_system_status() & SYS_STATUS_PERFORMANCE) { + in_perf = true; + } else if (in_perf) { + in_perf = false; + } else { + static u64 last_time_in_idle; + static u64 last_time_in_idle_timestamp; + u64 time_in_idle = 0, now; + u32 delta_idle; + u32 delta_time; + unsigned cpu, busy_cpus; + + for_each_online_cpu(cpu) { + time_in_idle += get_cpu_idle_time_us(cpu, &now); + } + delta_time = now - last_time_in_idle_timestamp; + delta_idle = time_in_idle - last_time_in_idle; + last_time_in_idle = time_in_idle; + last_time_in_idle_timestamp = now; + delta_idle += delta_time >> 4; /* +6.25% */ + if (delta_idle > (nr_cpus - 1) + * delta_time && delta_idle < (nr_cpus + 1) * delta_time) + busy_cpus = 1; + else if (delta_idle > (nr_cpus - 2) * delta_time) + busy_cpus = 2; + else if (delta_idle > (nr_cpus - 3) * delta_time) + busy_cpus = 3; + else + busy_cpus = 4; + + limits_table = clk_cpu_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); + } + + 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) + 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); + } +} + static void dvfs_temp_limit_work_func(struct work_struct *work) { int temp=0, delta_temp=0; @@ -867,6 +931,9 @@ static void dvfs_temp_limit_work_func(struct work_struct *work) temp = rockchip_tsadc_get_temp(1); + if (temp == INVALID_TEMP) + return dvfs_virt_temp_limit_work_func(); + //debounce delta_temp = (old_temp>temp) ? (old_temp-temp) : (temp-old_temp); if (delta_temp <= 1) @@ -1592,16 +1659,6 @@ int of_dvfs_init(void) return PTR_ERR(dvfs_dev_node); } - val = of_get_property(dvfs_dev_node, "target-temp", NULL); - if (val) { - target_temp = be32_to_cpup(val); - } - - val = of_get_property(dvfs_dev_node, "temp-limit-enable", NULL); - if (val) { - temp_limit_enable = be32_to_cpup(val); - } - for_each_available_child_of_node(dvfs_dev_node, vd_dev_node) { vd = kzalloc(sizeof(struct vd_node), GFP_KERNEL); if (!vd) @@ -1667,13 +1724,27 @@ int of_dvfs_init(void) else dvfs_node->regu_mode_table = NULL; + val = of_get_property(clk_dev_node, "temp-limit-enable", NULL); + if (val) + temp_limit_enable = be32_to_cpup(val); if (temp_limit_enable) { + val = of_get_property(clk_dev_node, "target-temp", NULL); + if (val) + target_temp = be32_to_cpup(val); val = of_get_property(clk_dev_node, "temp-channel", NULL); - if (val) { + if (val) dvfs_node->temp_channel = be32_to_cpup(val); - } + dvfs_node->nor_temp_limit_table = of_get_temp_limit_table(clk_dev_node, "normal-temp-limit"); dvfs_node->per_temp_limit_table = of_get_temp_limit_table(clk_dev_node, "performance-temp-limit"); + dvfs_node->virt_temp_limit_table[0] = + of_get_temp_limit_table(clk_dev_node, "virt-temp-limit-1-cpu-busy"); + dvfs_node->virt_temp_limit_table[1] = + of_get_temp_limit_table(clk_dev_node, "virt-temp-limit-2-cpu-busy"); + dvfs_node->virt_temp_limit_table[2] = + of_get_temp_limit_table(clk_dev_node, "virt-temp-limit-3-cpu-busy"); + dvfs_node->virt_temp_limit_table[3] = + of_get_temp_limit_table(clk_dev_node, "virt-temp-limit-4-cpu-busy"); } dvfs_node->temp_limit_rate = -1; dvfs_node->dev.of_node = clk_dev_node; diff --git a/include/linux/rockchip/dvfs.h b/include/linux/rockchip/dvfs.h index 163b95575928..209374a21182 100644 --- a/include/linux/rockchip/dvfs.h +++ b/include/linux/rockchip/dvfs.h @@ -109,6 +109,7 @@ struct dvfs_node { struct cpufreq_frequency_table *dvfs_table; struct cpufreq_frequency_table *per_temp_limit_table; struct cpufreq_frequency_table *nor_temp_limit_table; + struct cpufreq_frequency_table *virt_temp_limit_table[4]; clk_set_rate_callback clk_dvfs_target; struct cpufreq_frequency_table *regu_mode_table; int regu_mode_en; -- 2.34.1