From: 黄涛 Date: Wed, 14 Sep 2011 02:52:45 +0000 (+0800) Subject: rk29: cpufreq: throttle more when run 1.2G X-Git-Tag: firefly_0821_release~9767^2~26^2~12 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=9cba9b55eb91b5bf030d556cb71e7bc44aa74917;p=firefly-linux-kernel-4.4.55.git rk29: cpufreq: throttle more when run 1.2G --- diff --git a/arch/arm/mach-rk29/cpufreq.c b/arch/arm/mach-rk29/cpufreq.c index 6da7b65b4f46..bbc7bcc60107 100755 --- a/arch/arm/mach-rk29/cpufreq.c +++ b/arch/arm/mach-rk29/cpufreq.c @@ -1,6 +1,6 @@ -/* arch/arm/mach-rk2818/cpufreq.c +/* arch/arm/mach-rk29/cpufreq.c * - * Copyright (C) 2010 ROCKCHIP, Inc. + * Copyright (C) 2010, 2011 ROCKCHIP, Inc. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -13,11 +13,6 @@ * */ -#ifdef CONFIG_CPU_FREQ_DEBUG -#define DEBUG -#endif -#define pr_fmt(fmt) "%s: " fmt, __func__ - #include #include #include @@ -32,7 +27,6 @@ #include <../../../drivers/video/rk29_fb.h> #define MHZ (1000*1000) -#define KHZ 1000 static int no_cpufreq_access; @@ -64,13 +58,15 @@ static int vcore_uV; static struct workqueue_struct *wq; #ifdef CONFIG_RK29_CPU_FREQ_LIMIT_BY_TEMP -static int limit = 1; -module_param(limit, int, 0644); +static bool limit = true; +module_param(limit, bool, 0644); -#define LIMIT_SECS 30 -static int limit_secs = LIMIT_SECS; +static int limit_secs = 30; module_param(limit_secs, int, 0644); +static int limit_secs_1200 = 6; +module_param(limit_secs_1200, int, 0644); + static int limit_temp; module_param(limit_temp, int, 0444); @@ -86,9 +82,9 @@ enum { }; static uint debug_mask = DEBUG_CHANGE; module_param(debug_mask, uint, 0644); -#define dprintk(mask, fmt, ...) do { if (mask & debug_mask) printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); } while (0) +#define dprintk(mask, fmt, ...) do { if (mask & debug_mask) printk(KERN_DEBUG "cpufreq: " fmt, ##__VA_ARGS__); } while (0) -#define LIMIT_AVG_FREQ (816 * KHZ) /* kHz */ +#define LIMIT_AVG_FREQ (816 * 1000) /* kHz */ static unsigned int limit_avg_freq = LIMIT_AVG_FREQ; module_param(limit_avg_freq, uint, 0444); @@ -107,16 +103,17 @@ module_param_call(limit_avg_voltage, rk29_cpufreq_set_limit_avg_voltage, param_g #define CONFIG_RK29_CPU_FREQ_LIMIT_BY_DISP #ifdef CONFIG_RK29_CPU_FREQ_LIMIT_BY_DISP -static bool limit_fb1_is_on; -static bool limit_hdmi_is_on; -static inline bool aclk_limit(void) { return limit_hdmi_is_on && limit_fb1_is_on; } -module_param(limit_fb1_is_on, bool, 0644); -module_param(limit_hdmi_is_on, bool, 0644); +static bool limit_fb1_enabled; +static bool limit_hdmi_enabled; +static inline bool aclk_limit(void) { return limit_hdmi_enabled && limit_fb1_enabled; } +module_param(limit_fb1_enabled, bool, 0644); +module_param(limit_hdmi_enabled, bool, 0644); #else static inline bool aclk_limit(void) { return false; } #endif #if defined(CONFIG_RK29_CPU_FREQ_LIMIT_BY_DISP) || defined(CONFIG_RK29_CPU_FREQ_LIMIT_BY_TEMP) +static unsigned int limit_max_freq; static int limit_index_816 = -1; static unsigned int limit_freq_816; static int limit_index_1008 = -1; @@ -138,6 +135,7 @@ static void board_do_update_cpufreq_table(struct cpufreq_frequency_table *table) limit_avg_freq = 0; limit_avg_index = -1; #if defined(CONFIG_RK29_CPU_FREQ_LIMIT_BY_DISP) || defined(CONFIG_RK29_CPU_FREQ_LIMIT_BY_TEMP) + limit_max_freq = 0; limit_index_816 = -1; limit_freq_816 = 0; limit_index_1008 = -1; @@ -145,17 +143,19 @@ static void board_do_update_cpufreq_table(struct cpufreq_frequency_table *table) #endif for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { - table[i].frequency = clk_round_rate(arm_clk, table[i].frequency * KHZ) / KHZ; + table[i].frequency = clk_round_rate(arm_clk, table[i].frequency * 1000) / 1000; if (table[i].index <= limit_avg_voltage && limit_avg_freq < table[i].frequency) { limit_avg_freq = table[i].frequency; limit_avg_index = i; } #if defined(CONFIG_RK29_CPU_FREQ_LIMIT_BY_DISP) || defined(CONFIG_RK29_CPU_FREQ_LIMIT_BY_TEMP) - if (table[i].frequency <= 816 * KHZ && + if (limit_max_freq < table[i].frequency) + limit_max_freq = table[i].frequency; + if (table[i].frequency <= 816000 && (limit_index_816 < 0 || (limit_index_816 >= 0 && table[limit_index_816].frequency < table[i].frequency))) limit_index_816 = i; - if (table[i].frequency <= 1008 * KHZ && + if (table[i].frequency <= 1008000 && (limit_index_1008 < 0 || (limit_index_1008 >= 0 && table[limit_index_1008].frequency < table[i].frequency))) { limit_index_1008 = i; @@ -185,13 +185,25 @@ static int rk29_cpufreq_verify(struct cpufreq_policy *policy) } #ifdef CONFIG_RK29_CPU_FREQ_LIMIT_BY_TEMP +static bool limit_vpu_enabled; +static bool limit_gpu_enabled; +static bool limit_gpu_high; +module_param(limit_vpu_enabled, bool, 0644); +module_param(limit_gpu_enabled, bool, 0644); +module_param(limit_gpu_high, bool, 0644); +static struct clk* aclk_vepu; +static struct clk* clk_gpu; +#define GPU_LOW_RATE (300 * MHZ) +static unsigned long limit_gpu_low_rate = GPU_LOW_RATE; +module_param(limit_gpu_low_rate, ulong, 0644); + #define TEMP_COEFF_IDLE -1000 #define TEMP_COEFF_408 -325 #define TEMP_COEFF_624 -202 #define TEMP_COEFF_816 -78 #define TEMP_COEFF_1008 325 -#define TEMP_COEFF_1200 (TEMP_COEFF_1008 * 5 / 2) -#define WORK_DELAY (2*HZ) +#define TEMP_COEFF_1200 1300 +#define WORK_DELAY HZ static void rk29_cpufreq_limit_by_temp(struct cpufreq_policy *policy, unsigned int relation, int *index) { int c, ms; @@ -200,11 +212,13 @@ static void rk29_cpufreq_limit_by_temp(struct cpufreq_policy *policy, unsigned i cputime64_t wall; u64 idle_time_us; static u64 last_idle_time_us; + int idle; unsigned int cur = policy->cur; int overheat_temp_1200, overheat_temp; int temp; int target_index; unsigned int target_freq; + bool overheat; if (!limit || !rk29_cpufreq_is_ondemand_policy(policy) || (limit_index_816 < 0) || (relation & MASK_FURTHER_CPUFREQ)) { @@ -222,14 +236,14 @@ static void rk29_cpufreq_limit_by_temp(struct cpufreq_policy *policy, unsigned i } temp = limit_temp; - if (idle_time_us != last_idle_time_us) { - temp -= idle_time_us - last_idle_time_us; // -1000 - dprintk(DEBUG_TEMP, "idle %lld us\n", idle_time_us - last_idle_time_us); + idle = idle_time_us - last_idle_time_us; + if (idle) { + temp -= idle; // -1000 last_idle_time_us = idle_time_us; } ms = div_u64(ktime_us_delta(now, last), 1000); - dprintk(DEBUG_TEMP, "%d kHz (%d uV) elapsed %d ms\n", cur, vcore_uV, ms); + dprintk(DEBUG_TEMP, "%d kHz (%d uV) elapsed %d ms idle %d us\n", cur, vcore_uV, ms, idle); last = now; if (cur <= 408 * 1000) @@ -249,18 +263,24 @@ static void rk29_cpufreq_limit_by_temp(struct cpufreq_policy *policy, unsigned i target_index = *index; target_freq = freq_table[target_index].frequency; - overheat_temp = TEMP_COEFF_1008 * limit_secs * 1000; - overheat_temp_1200 = overheat_temp - TEMP_COEFF_1200 * (WORK_DELAY/HZ) * 1000; + overheat_temp = TEMP_COEFF_1008 * limit_secs * MSEC_PER_SEC; + overheat_temp_1200 = TEMP_COEFF_1200 * limit_secs_1200 * MSEC_PER_SEC; + overheat = false; - if (temp > overheat_temp && target_freq > limit_freq_816) + if (temp >= overheat_temp && target_freq > limit_freq_816) { target_index = limit_index_816; - else if (target_freq > limit_freq_1008 && limit_freq_1008 > limit_freq_816 && - temp > overheat_temp_1200 && temp <= overheat_temp) + overheat = true; + } else if (target_freq > limit_freq_1008 && limit_freq_1008 > limit_freq_816 && + temp >= overheat_temp_1200 && temp < overheat_temp) { + target_index = limit_index_1008; + overheat = true; + } else if (target_freq > 1008000 && (limit_vpu_enabled || (limit_gpu_enabled && limit_gpu_high))) { target_index = limit_index_1008; + } + dprintk(DEBUG_TEMP, "%d kHz c %d temp %d (%s) selected %d kHz\n", target_freq, c, temp, overheat ? "overheat" : "normal", freq_table[target_index].frequency); limit_temp = temp; *index = target_index; - dprintk(DEBUG_TEMP, "c %d temp %d (%s) index %d\n", c, temp, temp > overheat_temp ? "overheat" : "normal", target_index); } #else #define rk29_cpufreq_limit_by_temp(...) do {} while (0) @@ -276,10 +296,10 @@ static void rk29_cpufreq_limit_by_disp(int *index) return; if (ddr_max_rate < 492 * MHZ) { - if (limit_index_816 >= 0 && frequency > 816 * KHZ) + if (limit_index_816 >= 0 && frequency > 816000) new_index = limit_index_816; } else { - if (limit_index_1008 >= 0 && frequency > 1008 * KHZ) + if (limit_index_1008 >= 0 && frequency > 1008000) new_index = limit_index_1008; } @@ -337,8 +357,8 @@ static int rk29_cpufreq_do_target(struct cpufreq_policy *policy, unsigned int ta freqs.new = freq->frequency; freqs.cpu = 0; new_vcore_uV = freq->index; - new_arm_rate = freqs.new * KHZ; - dprintk(DEBUG_CHANGE, "%d Hz r %d(%c) selected %d Hz (%d uV)\n", + new_arm_rate = freqs.new * 1000; + dprintk(DEBUG_CHANGE, "%d kHz r %d(%c) selected %d kHz (%d uV)\n", target_freq, relation, relation & CPUFREQ_RELATION_H ? 'H' : 'L', freq->frequency, new_vcore_uV); @@ -357,9 +377,9 @@ static int rk29_cpufreq_do_target(struct cpufreq_policy *policy, unsigned int ta cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); dprintk(DEBUG_CHANGE, "pre change\n"); - clk_set_rate(arm_clk, freqs.new * KHZ + aclk_limit()); + clk_set_rate(arm_clk, freqs.new * 1000 + aclk_limit()); dprintk(DEBUG_CHANGE, "post change\n"); - freqs.new = clk_get_rate(arm_clk) / KHZ; + freqs.new = clk_get_rate(arm_clk) / 1000; cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); #ifdef CONFIG_REGULATOR @@ -373,7 +393,7 @@ static int rk29_cpufreq_do_target(struct cpufreq_policy *policy, unsigned int ta } } #endif - dprintk(DEBUG_CHANGE, "ok, got %d kHz\n", freqs.new); + dprintk(DEBUG_CHANGE, "got %d kHz\n", freqs.new); return err; } @@ -424,12 +444,91 @@ static void rk29_cpufreq_limit_by_temp_work_func(struct work_struct *work) struct cpufreq_policy *policy = cpufreq_cpu_get(0); if (policy) { - dprintk(DEBUG_TEMP, "target %d KHz\n", policy->cur); + dprintk(DEBUG_TEMP, "check %d kHz\n", policy->cur); cpufreq_driver_target(policy, policy->cur, CPUFREQ_RELATION_L); cpufreq_cpu_put(policy); } queue_delayed_work(wq, &rk29_cpufreq_limit_by_temp_work, WORK_DELAY); } + +static int rk29_cpufreq_aclk_vepu_notifier_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + switch (event) { + case CLK_PRE_ENABLE: + limit_vpu_enabled = true; + break; + case CLK_ABORT_ENABLE: + case CLK_POST_DISABLE: + limit_vpu_enabled = false; + break; + default: + return NOTIFY_OK; + } + + if (limit_vpu_enabled) { + struct cpufreq_policy *policy = cpufreq_cpu_get(0); + + if (policy) { + dprintk(DEBUG_TEMP, "vpu on\n"); + cpufreq_driver_target(policy, policy->cur, CPUFREQ_RELATION_L); + cpufreq_cpu_put(policy); + } + } + return NOTIFY_OK; +} + +static struct notifier_block rk29_cpufreq_aclk_vepu_notifier = { + .notifier_call = rk29_cpufreq_aclk_vepu_notifier_event, +}; + +static int rk29_cpufreq_clk_gpu_notifier_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + struct clk_notifier_data *cnd = ptr; + bool gpu_high_old = limit_gpu_enabled && limit_gpu_high; + bool gpu_high; + + switch (event) { + case CLK_PRE_RATE_CHANGE: + if (cnd->new_rate > limit_gpu_low_rate) + limit_gpu_high = true; + break; + case CLK_ABORT_RATE_CHANGE: + if (cnd->new_rate > limit_gpu_low_rate && cnd->old_rate <= limit_gpu_low_rate) + limit_gpu_high = false; + break; + case CLK_POST_RATE_CHANGE: + if (cnd->new_rate <= limit_gpu_low_rate) + limit_gpu_high = false; + break; + case CLK_PRE_ENABLE: + limit_gpu_enabled = true; + break; + case CLK_ABORT_ENABLE: + case CLK_POST_DISABLE: + limit_gpu_enabled = false; + break; + default: + return NOTIFY_OK; + } + + gpu_high = limit_gpu_enabled && limit_gpu_high; + if (gpu_high_old != gpu_high && gpu_high) { + struct cpufreq_policy *policy = cpufreq_cpu_get(0); + + if (policy) { + dprintk(DEBUG_TEMP, "gpu high\n"); + cpufreq_driver_target(policy, policy->cur, CPUFREQ_RELATION_L); + cpufreq_cpu_put(policy); + } + } + return NOTIFY_OK; +} + +static struct notifier_block rk29_cpufreq_clk_gpu_notifier = { + .notifier_call = rk29_cpufreq_clk_gpu_notifier_event, +}; #endif #ifdef CONFIG_RK29_CPU_FREQ_LIMIT_BY_DISP @@ -451,16 +550,16 @@ static int rk29_cpufreq_fb_notifier_event(struct notifier_block *this, { switch (event) { case RK29FB_EVENT_HDMI_ON: - limit_hdmi_is_on = true; + limit_hdmi_enabled = true; break; case RK29FB_EVENT_HDMI_OFF: - limit_hdmi_is_on = false; + limit_hdmi_enabled = false; break; case RK29FB_EVENT_FB1_ON: - limit_fb1_is_on = true; + limit_fb1_enabled = true; break; case RK29FB_EVENT_FB1_OFF: - limit_fb1_is_on = false; + limit_fb1_enabled = false; break; } @@ -509,7 +608,7 @@ static int rk29_cpufreq_init(struct cpufreq_policy *policy) board_update_cpufreq_table(freq_table); /* force update frequency */ BUG_ON(cpufreq_frequency_table_cpuinfo(policy, freq_table)); cpufreq_frequency_table_get_attr(freq_table, policy->cpu); - policy->cur = clk_get_rate(arm_clk) / KHZ; + policy->cur = clk_get_rate(arm_clk) / 1000; policy->cpuinfo.transition_latency = 40 * NSEC_PER_USEC; // make default sampling_rate to 40000 @@ -525,6 +624,12 @@ static int rk29_cpufreq_init(struct cpufreq_policy *policy) queue_delayed_work(wq, &rk29_cpufreq_limit_by_temp_work, WORK_DELAY); } cpufreq_register_notifier(¬ifier_policy_block, CPUFREQ_POLICY_NOTIFIER); + if (limit_max_freq > 1008000) { + clk_gpu = clk_get(NULL, "gpu"); + aclk_vepu = clk_get(NULL, "aclk_vepu"); + clk_notifier_register(clk_gpu, &rk29_cpufreq_clk_gpu_notifier); + clk_notifier_register(aclk_vepu, &rk29_cpufreq_aclk_vepu_notifier); + } #endif #ifdef CONFIG_RK29_CPU_FREQ_LIMIT_BY_DISP rk29fb_register_notifier(&rk29_cpufreq_fb_notifier); @@ -538,6 +643,12 @@ static int rk29_cpufreq_exit(struct cpufreq_policy *policy) rk29fb_unregister_notifier(&rk29_cpufreq_fb_notifier); #endif #ifdef CONFIG_RK29_CPU_FREQ_LIMIT_BY_TEMP + if (limit_max_freq > 1008000) { + clk_notifier_unregister(clk_gpu, &rk29_cpufreq_clk_gpu_notifier); + clk_notifier_unregister(aclk_vepu, &rk29_cpufreq_aclk_vepu_notifier); + clk_put(clk_gpu); + clk_put(aclk_vepu); + } cpufreq_unregister_notifier(¬ifier_policy_block, CPUFREQ_POLICY_NOTIFIER); if (wq) cancel_delayed_work(&rk29_cpufreq_limit_by_temp_work);