From 86704c77d2bcaf512fff27bd433dcbd86c72cd04 Mon Sep 17 00:00:00 2001 From: ktoonsez Date: Sun, 19 May 2013 20:36:04 -0700 Subject: [PATCH] CPU OC and kthermal (Thanks to ktoonsez) --- arch/arm/configs/jf_defconfig | 2 +- arch/arm/mach-msm/Makefile | 1 + arch/arm/mach-msm/acpuclock-8064.c | 37 ++- arch/arm/mach-msm/acpuclock-krait.c | 3 - arch/arm/mach-msm/board-8064-regulator.c | 9 +- arch/arm/mach-msm/cpufreq.c | 14 +- arch/arm/mach-msm/kthermal.c | 294 +++++++++++++++++++++++ arch/arm/mach-msm/kthermal.h | 37 +++ drivers/cpufreq/cpufreq.c | 89 ++++++- include/linux/cpufreq.h | 5 +- 10 files changed, 472 insertions(+), 19 deletions(-) create mode 100644 arch/arm/mach-msm/kthermal.c create mode 100644 arch/arm/mach-msm/kthermal.h diff --git a/arch/arm/configs/jf_defconfig b/arch/arm/configs/jf_defconfig index c6683fdc..c93e6bc7 100755 --- a/arch/arm/configs/jf_defconfig +++ b/arch/arm/configs/jf_defconfig @@ -373,7 +373,7 @@ CONFIG_SENSORS_EPM_ADC=y CONFIG_THERMAL=y CONFIG_THERMAL_TSENS8960=y CONFIG_THERMAL_PM8XXX=y -CONFIG_THERMAL_MONITOR=y +# CONFIG_THERMAL_MONITOR is not set CONFIG_SEC_THERMISTOR=y CONFIG_MFD_PM8921_CORE=y CONFIG_MFD_PM8821_CORE=y diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 348f1c8b..e5255cf1 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -272,6 +272,7 @@ obj-$(CONFIG_ARCH_MSM8960) += devices-8960.o obj-$(CONFIG_ARCH_APQ8064) += devices-8960.o devices-8064.o obj-$(CONFIG_INPUT_TOUCHSCREEN) += board-mxt540s-tsp.o board-s5000-tsp.o obj-$(CONFIG_ARCH_APQ8064) += acpuclock-8064.o +obj-$(CONFIG_ARCH_APQ8064) += kthermal.o board-8960-all-objs += board-8960.o board-8960-camera.o board-8960-display.o board-8960-pmic.o board-8960-storage.o board-8960-gpiomux.o board-8930-all-objs += board-8930.o board-8930-camera.o board-8930-display.o board-8930-pmic.o board-8930-storage.o board-8930-gpiomux.o devices-8930.o board-8930-gpu.o board-8064-all-objs += board-8064.o board-8064-pmic.o board-8064-storage.o board-8064-gpiomux.o board-8064-camera.o board-8064-display.o board-8064-gpu.o diff --git a/arch/arm/mach-msm/acpuclock-8064.c b/arch/arm/mach-msm/acpuclock-8064.c index edf912ff..9b4e9094 100644 --- a/arch/arm/mach-msm/acpuclock-8064.c +++ b/arch/arm/mach-msm/acpuclock-8064.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "mach/socinfo.h" #include "acpuclock.h" @@ -47,7 +48,7 @@ static struct scalable scalable[] __initdata = { .aux_clk_sel = 3, .sec_clk_sel = 2, .l2cpmr_iaddr = 0x4501, - .vreg[VREG_CORE] = { "krait0", 1300000 }, + .vreg[VREG_CORE] = { "krait0", MAX_VDD_SC }, .vreg[VREG_MEM] = { "krait0_mem", 1150000 }, .vreg[VREG_DIG] = { "krait0_dig", 1150000 }, .vreg[VREG_HFPLL_A] = { "krait0_hfpll", 1800000 }, @@ -58,7 +59,7 @@ static struct scalable scalable[] __initdata = { .aux_clk_sel = 3, .sec_clk_sel = 2, .l2cpmr_iaddr = 0x5501, - .vreg[VREG_CORE] = { "krait1", 1300000 }, + .vreg[VREG_CORE] = { "krait1", MAX_VDD_SC }, .vreg[VREG_MEM] = { "krait1_mem", 1150000 }, .vreg[VREG_DIG] = { "krait1_dig", 1150000 }, .vreg[VREG_HFPLL_A] = { "krait1_hfpll", 1800000 }, @@ -69,7 +70,7 @@ static struct scalable scalable[] __initdata = { .aux_clk_sel = 3, .sec_clk_sel = 2, .l2cpmr_iaddr = 0x6501, - .vreg[VREG_CORE] = { "krait2", 1300000 }, + .vreg[VREG_CORE] = { "krait2", MAX_VDD_SC }, .vreg[VREG_MEM] = { "krait2_mem", 1150000 }, .vreg[VREG_DIG] = { "krait2_dig", 1150000 }, .vreg[VREG_HFPLL_A] = { "krait2_hfpll", 1800000 }, @@ -80,7 +81,7 @@ static struct scalable scalable[] __initdata = { .aux_clk_sel = 3, .sec_clk_sel = 2, .l2cpmr_iaddr = 0x7501, - .vreg[VREG_CORE] = { "krait3", 1300000 }, + .vreg[VREG_CORE] = { "krait3", MAX_VDD_SC }, .vreg[VREG_MEM] = { "krait3_mem", 1150000 }, .vreg[VREG_DIG] = { "krait3_dig", 1150000 }, .vreg[VREG_HFPLL_A] = { "krait3_hfpll", 1800000 }, @@ -496,6 +497,10 @@ static struct acpu_level tbl_PVS0_2000MHz[] __initdata = { { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1175000 }, { 1, { 1782000, HFPLL, 1, 0x42 }, L2(15), 1225000 }, { 1, { 1890000, HFPLL, 1, 0x46 }, L2(15), 1287500 }, + { 1, { 1998000, HFPLL, 1, 0x4A }, L2(15), 1300000 }, + { 1, { 2106000, HFPLL, 1, 0x4E }, L2(15), 1350000 }, + { 1, { 2214000, HFPLL, 1, 0x52 }, L2(15), 1400000 }, + { 1, { 2322000, HFPLL, 1, 0x56 }, L2(15), 1425000 }, { 0, { 0 } } }; @@ -518,6 +523,10 @@ static struct acpu_level tbl_PVS1_2000MHz[] __initdata = { { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1137500 }, { 1, { 1782000, HFPLL, 1, 0x42 }, L2(15), 1187500 }, { 1, { 1890000, HFPLL, 1, 0x46 }, L2(15), 1250000 }, + { 1, { 1998000, HFPLL, 1, 0x4A }, L2(15), 1275000 }, + { 1, { 2106000, HFPLL, 1, 0x4E }, L2(15), 1325000 }, + { 1, { 2214000, HFPLL, 1, 0x52 }, L2(15), 1375000 }, + { 1, { 2322000, HFPLL, 1, 0x56 }, L2(15), 1400000 }, { 0, { 0 } } }; @@ -540,6 +549,10 @@ static struct acpu_level tbl_PVS2_2000MHz[] __initdata = { { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1112500 }, { 1, { 1782000, HFPLL, 1, 0x42 }, L2(15), 1162500 }, { 1, { 1890000, HFPLL, 1, 0x46 }, L2(15), 1212500 }, + { 1, { 1998000, HFPLL, 1, 0x4A }, L2(15), 1250000 }, + { 1, { 2106000, HFPLL, 1, 0x4E }, L2(15), 1300000 }, + { 1, { 2214000, HFPLL, 1, 0x52 }, L2(15), 1350000 }, + { 1, { 2322000, HFPLL, 1, 0x56 }, L2(15), 1375000 }, { 0, { 0 } } }; @@ -562,6 +575,10 @@ static struct acpu_level tbl_PVS3_2000MHz[] __initdata = { { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1087500 }, { 1, { 1782000, HFPLL, 1, 0x42 }, L2(15), 1137500 }, { 1, { 1890000, HFPLL, 1, 0x46 }, L2(15), 1175000 }, + { 1, { 1998000, HFPLL, 1, 0x4A }, L2(15), 1225000 }, + { 1, { 2106000, HFPLL, 1, 0x4E }, L2(15), 1275000 }, + { 1, { 2214000, HFPLL, 1, 0x52 }, L2(15), 1325000 }, + { 1, { 2322000, HFPLL, 1, 0x56 }, L2(15), 1350000 }, { 0, { 0 } } }; @@ -584,6 +601,10 @@ static struct acpu_level tbl_PVS4_2000MHz[] __initdata = { { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1075000 }, { 1, { 1782000, HFPLL, 1, 0x42 }, L2(15), 1112500 }, { 1, { 1890000, HFPLL, 1, 0x46 }, L2(15), 1150000 }, + { 1, { 1998000, HFPLL, 1, 0x4A }, L2(15), 1200000 }, + { 1, { 2106000, HFPLL, 1, 0x4E }, L2(15), 1250000 }, + { 1, { 2214000, HFPLL, 1, 0x52 }, L2(15), 1300000 }, + { 1, { 2322000, HFPLL, 1, 0x56 }, L2(15), 1325000 }, { 0, { 0 } } }; @@ -606,6 +627,10 @@ static struct acpu_level tbl_PVS5_2000MHz[] __initdata = { { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1050000 }, { 1, { 1782000, HFPLL, 1, 0x42 }, L2(15), 1087500 }, { 1, { 1890000, HFPLL, 1, 0x46 }, L2(15), 1125000 }, + { 1, { 1998000, HFPLL, 1, 0x4A }, L2(15), 1175000 }, + { 1, { 2106000, HFPLL, 1, 0x4E }, L2(15), 1225000 }, + { 1, { 2214000, HFPLL, 1, 0x52 }, L2(15), 1275000 }, + { 1, { 2322000, HFPLL, 1, 0x56 }, L2(15), 1325000 }, { 0, { 0 } } }; @@ -628,6 +653,10 @@ static struct acpu_level tbl_PVS6_2000MHz[] __initdata = { { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1025000 }, { 1, { 1782000, HFPLL, 1, 0x42 }, L2(15), 1062500 }, { 1, { 1890000, HFPLL, 1, 0x46 }, L2(15), 1100000 }, + { 1, { 1998000, HFPLL, 1, 0x4A }, L2(15), 1150000 }, + { 1, { 2106000, HFPLL, 1, 0x4E }, L2(15), 1200000 }, + { 1, { 2214000, HFPLL, 1, 0x52 }, L2(15), 1250000 }, + { 1, { 2322000, HFPLL, 1, 0x56 }, L2(15), 1300000 }, { 0, { 0 } } }; diff --git a/arch/arm/mach-msm/acpuclock-krait.c b/arch/arm/mach-msm/acpuclock-krait.c index ffee8094..f0418f40 100644 --- a/arch/arm/mach-msm/acpuclock-krait.c +++ b/arch/arm/mach-msm/acpuclock-krait.c @@ -56,9 +56,6 @@ int pvs_bin; extern void reset_num_cpu_freqs(void); -#define MAX_VDD_SC 1400000 /* uV */ -#define MIN_VDD_SC 700000 /* uV */ - static DEFINE_MUTEX(driver_lock); static DEFINE_SPINLOCK(l2_lock); diff --git a/arch/arm/mach-msm/board-8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c index d764cc23..501aca5c 100644 --- a/arch/arm/mach-msm/board-8064-regulator.c +++ b/arch/arm/mach-msm/board-8064-regulator.c @@ -14,6 +14,7 @@ #include #include "board-8064.h" +#include #ifdef CONFIG_REGULATOR_MAX77693 #include @@ -721,15 +722,15 @@ mpq8064_gpio_regulator_pdata[] __devinitdata = { /* SAW regulator constraints */ struct regulator_init_data msm8064_saw_regulator_pdata_8921_s5 = /* ID vreg_name min_uV max_uV */ - SAW_VREG_INIT(S5, "8921_s5", 850000, 1300000); + SAW_VREG_INIT(S5, "8921_s5", MIN_VDD_SC, MAX_VDD_SC); struct regulator_init_data msm8064_saw_regulator_pdata_8921_s6 = - SAW_VREG_INIT(S6, "8921_s6", 850000, 1300000); + SAW_VREG_INIT(S6, "8921_s6", MIN_VDD_SC, MAX_VDD_SC); struct regulator_init_data msm8064_saw_regulator_pdata_8821_s0 = /* ID vreg_name min_uV max_uV */ - SAW_VREG_INIT(8821_S0, "8821_s0", 850000, 1300000); + SAW_VREG_INIT(8821_S0, "8821_s0", MIN_VDD_SC, MAX_VDD_SC); struct regulator_init_data msm8064_saw_regulator_pdata_8821_s1 = - SAW_VREG_INIT(8821_S1, "8821_s1", 850000, 1300000); + SAW_VREG_INIT(8821_S1, "8821_s1", MIN_VDD_SC, MAX_VDD_SC); /* PM8921 regulator constraints */ struct pm8xxx_regulator_platform_data diff --git a/arch/arm/mach-msm/cpufreq.c b/arch/arm/mach-msm/cpufreq.c index 96cc5b3f..16e67f22 100644 --- a/arch/arm/mach-msm/cpufreq.c +++ b/arch/arm/mach-msm/cpufreq.c @@ -136,6 +136,9 @@ static int set_cpu_freq(struct cpufreq_policy *policy, unsigned int new_freq) return 0; } #endif + if (new_freq > 0 && new_freq > kthermal_limit) + new_freq = kthermal_limit; + //pr_alert("KT SET CPU FREQ %u-%u-%u\n", new_freq, policy->cur, policy->cpu); freqs.old = policy->cur; freqs.new = new_freq; @@ -169,6 +172,8 @@ static int msm_cpufreq_target(struct cpufreq_policy *policy, ret = -EFAULT; goto done; } + if (kthermal_limit > 0 && target_freq > kthermal_limit) + target_freq = kthermal_limit; table = cpufreq_frequency_get_table(policy->cpu); if (cpufreq_frequency_table_target(policy, table, target_freq, relation, @@ -178,7 +183,7 @@ static int msm_cpufreq_target(struct cpufreq_policy *policy, goto done; } - pr_debug("CPU[%d] target %d relation %d (%d-%d) selected %d\n", + pr_debug("KT CPU[%d] target %d relation %d (%d-%d) selected %d\n", policy->cpu, target_freq, relation, policy->min, policy->max, table[index].frequency); @@ -291,10 +296,11 @@ static int __cpuinit msm_cpufreq_init(struct cpufreq_policy *policy) #endif #ifdef CONFIG_SEC_DVFS - cpuinfo_max_freq = policy->cpuinfo.max_freq; - cpuinfo_min_freq = policy->cpuinfo.min_freq; + cpuinfo_max_freq = GLOBALKT_MAX_FREQ_LIMIT; //policy->cpuinfo.max_freq; + cpuinfo_min_freq = GLOBALKT_MIN_FREQ_LIMIT; //policy->cpuinfo.min_freq; #endif - + pr_alert("MSM_CPUFREQ_INIT: %d-%d-%d\n", cpuinfo_max_freq, policy->max, policy->cpuinfo.max_freq); + cur_freq = acpuclk_get_rate(policy->cpu); if (cpufreq_frequency_table_target(policy, table, cur_freq, CPUFREQ_RELATION_H, &index) && diff --git a/arch/arm/mach-msm/kthermal.c b/arch/arm/mach-msm/kthermal.c new file mode 100644 index 00000000..71b6e0ad --- /dev/null +++ b/arch/arm/mach-msm/kthermal.c @@ -0,0 +1,294 @@ +#include "kthermal.h" + +static struct delayed_work check_temp_workk; +static struct cpufreq_frequency_table *table; + +static int limit_idx = 18; +static int limit_idx_low = 3; +static int limit_idx_high = 18; + +extern void do_kthermal(unsigned int cpu, unsigned int freq); + +static int thermal_get_freq_table(void) +{ + int ret = 0; + int i = 0; + struct cpufreq_policy *policy = cpufreq_cpu_get(0); + + table = cpufreq_frequency_get_table(0); + if (table == NULL) { + pr_debug("%s: error reading cpufreq table\n", KBUILD_MODNAME); + ret = -EINVAL; + goto fail; + } + + while (table[i].frequency != CPUFREQ_TABLE_END) + { + //pr_alert("LOAD TABLE %d-%d-%d-%d\n", table[i].frequency, kmsm_thermal_info.minimum_throttle_mhz, limit_idx_low, limit_idx_high); + if (kmsm_thermal_info.minimum_throttle_mhz == table[i].frequency) + limit_idx_low = i; + if (policy->user_policy.max == table[i].frequency) + limit_idx_high = i; + i++; + } + limit_idx = limit_idx_high; + pr_alert("LOADED THERMAL TABLE: low=%d high=%d current limit = %d\n", limit_idx_low, limit_idx_high, limit_idx); +fail: + return ret; +} + +static void __cpuinit check_tempk(struct work_struct *work) +{ + unsigned int new_freq; + struct tsens_device tsens_dev; + long temp = 0; + int ret = 0; + + tsens_dev.sensor_num = kmsm_thermal_info.sensor_id; + ret = tsens_get_temp(&tsens_dev, &temp); + if (ret) { + pr_debug("%s: Unable to read TSENS sensor %d\n", + KBUILD_MODNAME, tsens_dev.sensor_num); + goto reschedule; + } + //pr_alert("CHECK TEMP %lu-%d-%d\n", temp, kmsm_thermal_info.temp_limit_degC_start, kmsm_thermal_info.temp_limit_degC_stop); + kmsm_thermal_info.current_temp = temp; + + if (temp >= kmsm_thermal_info.temp_limit_degC_start) + { + unsigned int i; + if (!kmsm_thermal_info.isthrottling) + { + //prev_freq = cpufreq_get(0); + thermal_get_freq_table(); + pr_alert("START KTHROTTLING - current temp = %lu - set point = %d\n", temp, kmsm_thermal_info.temp_limit_degC_start); + } + kmsm_thermal_info.isthrottling = 1; + //policy = cpufreq_cpu_get(0); + //__cpufreq_driver_target(policy, 1296000, CPUFREQ_RELATION_H); + limit_idx -= kmsm_thermal_info.freq_steps_while_throttling; + if (limit_idx < limit_idx_low) + limit_idx = limit_idx_low; + for (i = 0; i < num_online_cpus(); i++) + { + //pr_alert("KTHROTTLING LOOP - current temp = %lu - set point = %d\n", temp, kmsm_thermal_info.temp_limit_degC_start); + if (cpu_online(i) && cpufreq_get(i) != table[limit_idx].frequency) + { + //pr_alert("KTHROTTLING LOOP IN IF - current temp = %lu - set point = %d\n", temp, kmsm_thermal_info.temp_limit_degC_start); + //policy = NULL; + //policy = cpufreq_cpu_get(i); + //if (policy != NULL) + // __cpufreq_driver_target(policy, 1296000, CPUFREQ_RELATION_H); + new_freq = table[limit_idx].frequency; + do_kthermal(i, new_freq); + } + } + } + else if (kmsm_thermal_info.isthrottling && temp > kmsm_thermal_info.temp_limit_degC_stop && temp < kmsm_thermal_info.temp_limit_degC_start) + { + unsigned int i; + for (i = 0; i < num_online_cpus(); i++) + { + if (cpu_online(i) && cpufreq_get(i) != table[limit_idx].frequency) + { + new_freq = table[limit_idx].frequency; + do_kthermal(i, new_freq); + } + } + } + else if (kmsm_thermal_info.isthrottling && temp <= kmsm_thermal_info.temp_limit_degC_stop) + { + unsigned int i; + //policy = cpufreq_cpu_get(0); + //if (prev_freq > 0) + // __cpufreq_driver_target(policy, prev_freq, CPUFREQ_RELATION_H); + limit_idx += kmsm_thermal_info.freq_steps_while_throttling; + if (limit_idx >= limit_idx_high) + { + limit_idx = limit_idx_high; + kmsm_thermal_info.isthrottling = 0; + do_kthermal(0, 0); + pr_alert("STOP KTHROTTLING - current temp = %lu\n", temp); + } + for (i = 0; i < num_online_cpus(); i++) + { + if (cpu_online(i)) + { + //policy = NULL; + //policy = cpufreq_cpu_get(i); + //if (prev_freq > 0 && policy != NULL) + // __cpufreq_driver_target(policy, prev_freq, CPUFREQ_RELATION_H); + //do_thermal(i, prev_freq); + new_freq = table[limit_idx].frequency; + do_kthermal(i, new_freq); + } + } + } + +reschedule: + schedule_delayed_work_on(0, &check_temp_workk, + msecs_to_jiffies(kmsm_thermal_info.poll_speed)); +} + +static ssize_t show_isthrottling(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", kmsm_thermal_info.isthrottling); +} + +static ssize_t show_poll_speed(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", kmsm_thermal_info.poll_speed); +} + +static ssize_t store_poll_speed(struct kobject *kobj, + struct attribute *attr, const char *buf, size_t count) +{ + unsigned int ret = -EINVAL; + unsigned int value = 0; + + ret = sscanf(buf, "%u", &value); + if (ret != 1) + return -EINVAL; + + if (value < 100) + value = 100; + kmsm_thermal_info.poll_speed = value; + return count; +} + +static ssize_t show_current_temp(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + return sprintf(buf, "%lu\n", kmsm_thermal_info.current_temp); +} + +static ssize_t show_temp_limit_degC_start(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", kmsm_thermal_info.temp_limit_degC_start); +} + +static ssize_t store_temp_limit_degC_start(struct kobject *kobj, + struct attribute *attr, const char *buf, size_t count) +{ + unsigned int ret = -EINVAL; + unsigned int value = 0; + + ret = sscanf(buf, "%u", &value); + if (ret != 1) + return -EINVAL; + + if (value < kmsm_thermal_info.temp_limit_degC_stop) + value = kmsm_thermal_info.temp_limit_degC_stop + 1; + + kmsm_thermal_info.temp_limit_degC_start = value; + return count; +} + +static ssize_t show_temp_limit_degC_stop(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", kmsm_thermal_info.temp_limit_degC_stop); +} + +static ssize_t store_temp_limit_degC_stop(struct kobject *kobj, + struct attribute *attr, const char *buf, size_t count) +{ + unsigned int ret = -EINVAL; + unsigned int value = 0; + + ret = sscanf(buf, "%u", &value); + if (ret != 1) + return -EINVAL; + + if (value > kmsm_thermal_info.temp_limit_degC_start) + value = kmsm_thermal_info.temp_limit_degC_start - 1; + + kmsm_thermal_info.temp_limit_degC_stop = value; + return count; +} + +static ssize_t show_freq_steps_while_throttling(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", kmsm_thermal_info.freq_steps_while_throttling); +} + +static ssize_t store_freq_steps_while_throttling(struct kobject *kobj, + struct attribute *attr, const char *buf, size_t count) +{ + unsigned int ret = -EINVAL; + unsigned int value = 0; + + ret = sscanf(buf, "%u", &value); + if (ret != 1) + return -EINVAL; + + if (value < 0 || value > 5) + value = 1; + kmsm_thermal_info.freq_steps_while_throttling = value; + return count; +} + +static ssize_t show_minimum_throttle_mhz(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", kmsm_thermal_info.minimum_throttle_mhz); +} + +static ssize_t store_minimum_throttle_mhz(struct kobject *kobj, + struct attribute *attr, const char *buf, size_t count) +{ + unsigned int ret = -EINVAL; + unsigned int value = 0; + + ret = sscanf(buf, "%u", &value); + if (ret != 1) + return -EINVAL; + + if (value <= 0) + value = 378000; + + kmsm_thermal_info.minimum_throttle_mhz = value; + return count; +} + +static struct global_attr isthrottling_attr = __ATTR(isthrottling, 0444, show_isthrottling, NULL); +static struct global_attr poll_speed_attr = __ATTR(poll_speed, 0666, show_poll_speed, store_poll_speed); +static struct global_attr current_temp_attr = __ATTR(current_temp, 0444, show_current_temp, NULL); +static struct global_attr temp_limit_degC_start_attr = __ATTR(temp_limit_degC_start, 0666, show_temp_limit_degC_start, store_temp_limit_degC_start); +static struct global_attr temp_limit_degC_stop_attr = __ATTR(temp_limit_degC_stop, 0666, show_temp_limit_degC_stop, store_temp_limit_degC_stop); +static struct global_attr freq_steps_while_throttling_attr = __ATTR(freq_steps_while_throttling, 0666, show_freq_steps_while_throttling, store_freq_steps_while_throttling); +static struct global_attr minimum_throttle_mhz_attr = __ATTR(minimum_throttle_mhz, 0666, show_minimum_throttle_mhz, store_minimum_throttle_mhz); + +static struct attribute *kthermal_attributes[] = { + &isthrottling_attr.attr, + &poll_speed_attr.attr, + ¤t_temp_attr.attr, + &temp_limit_degC_start_attr.attr, + &temp_limit_degC_stop_attr.attr, + &freq_steps_while_throttling_attr.attr, + &minimum_throttle_mhz_attr.attr, + NULL, +}; + +static struct attribute_group kthermal_attr_group = { + .attrs = kthermal_attributes, + .name = "kthermal", +}; + +static int __init start_kthermal(void) +{ + int rc; + rc = sysfs_create_group(cpufreq_global_kobject, + &kthermal_attr_group); + + pr_alert("START KTHERMAL\n"); + INIT_DELAYED_WORK(&check_temp_workk, check_tempk); + schedule_delayed_work_on(0, &check_temp_workk, msecs_to_jiffies(60000)); + + return 0; +} +late_initcall(start_kthermal); diff --git a/arch/arm/mach-msm/kthermal.h b/arch/arm/mach-msm/kthermal.h new file mode 100644 index 00000000..4f5f88ad --- /dev/null +++ b/arch/arm/mach-msm/kthermal.h @@ -0,0 +1,37 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct kmsm_thermal_data { + uint32_t sensor_id; + int isthrottling; + uint32_t poll_speed; + uint32_t temp_limit_degC_start; + uint32_t temp_limit_degC_stop; + uint32_t freq_steps_while_throttling; + uint32_t minimum_throttle_mhz; + uint32_t core_limit_temp_degC; + uint32_t core_temp_hysteresis_degC; + uint32_t core_control_mask; + long current_temp; +}; + +static struct kmsm_thermal_data kmsm_thermal_info = { + .sensor_id = 0, + .isthrottling = false, + .poll_speed = 1000, + .temp_limit_degC_start = 70, + .temp_limit_degC_stop = 67, + .freq_steps_while_throttling = 1, + .minimum_throttle_mhz = 918000, + .current_temp = 0, +}; diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 5288fda6..a4e59762 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -40,6 +40,11 @@ static unsigned int vfreq_lock = 0; static bool vfreq_lock_tempOFF = false; static unsigned int isBooted = 0; +//Global placeholder for CPU policies +static struct cpufreq_policy trmlpolicy[10]; +//Kthermal limit holder to stop govs from setting CPU speed higher than the thermal limit +unsigned int kthermal_limit; + /** * The "cpufreq driver" - the arch- or hardware-dependent low * level driver of CPUFreq support, and its spinlock. This lock @@ -519,7 +524,7 @@ static ssize_t store_scaling_booted(struct cpufreq_policy *policy, const char *b } isBooted = 1; GLOBALKT_MIN_FREQ_LIMIT = 81000; - GLOBALKT_MAX_FREQ_LIMIT = 1890000; + GLOBALKT_MAX_FREQ_LIMIT = 2322000; cpufreq_get_policy(&new_policy, policy->cpu); new_policy.min = 378000; new_policy.max = 1890000; @@ -715,6 +720,26 @@ static ssize_t show_bios_limit(struct cpufreq_policy *policy, char *buf) return sprintf(buf, "%u\n", policy->cpuinfo.max_freq); } +static ssize_t show_freq_lock(struct cpufreq_policy *policy, char *buf) +{ + return sprintf(buf, "%u\n", vfreq_lock); +} +static ssize_t store_freq_lock(struct cpufreq_policy *policy, + const char *buf, size_t count) +{ + unsigned int value = 0; + unsigned int ret; + ret = sscanf(buf, "%u", &value); + if (value > 1) + value = 1; + if (value == 0) + vfreq_lock_tempOFF = false; + + vfreq_lock = value; + + return count; +} + cpufreq_freq_attr_ro_perm(cpuinfo_cur_freq, 0400); cpufreq_freq_attr_ro(cpuinfo_min_freq); cpufreq_freq_attr_ro(cpuinfo_max_freq); @@ -731,6 +756,7 @@ cpufreq_freq_attr_rw(scaling_max_freq); cpufreq_freq_attr_rw(scaling_governor); cpufreq_freq_attr_rw(scaling_setspeed); cpufreq_freq_attr_rw(scaling_booted); +cpufreq_freq_attr_rw(freq_lock); static struct attribute *default_attrs[] = { &cpuinfo_min_freq.attr, @@ -746,6 +772,7 @@ static struct attribute *default_attrs[] = { &scaling_available_governors.attr, &scaling_setspeed.attr, &scaling_booted.attr, + &freq_lock.attr, NULL }; @@ -1614,11 +1641,21 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy, if (cpufreq_disabled()) return -ENODEV; + //pr_alert("DO KTHERMAL 2 %u-%u-%u\n", target_freq, relation, policy->cpu); + + if (kthermal_limit > 0 && target_freq > kthermal_limit) + target_freq = kthermal_limit; + + //pr_alert("DO KTHERMAL 3 %u-%u-%u\n", target_freq, relation, policy->cpu); + pr_debug("target for CPU %u: %u kHz, relation %u\n", policy->cpu, target_freq, relation); if (cpu_online(policy->cpu) && cpufreq_driver->target) + { + //pr_alert("DO KTHERMAL 4 %u-%u-%u\n", target_freq, relation, policy->cpu); retval = cpufreq_driver->target(policy, target_freq, relation); - + } + return retval; } EXPORT_SYMBOL_GPL(__cpufreq_driver_target); @@ -1800,6 +1837,15 @@ int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu) } EXPORT_SYMBOL(cpufreq_get_policy); +void do_kthermal(unsigned int cpu, unsigned int freq) +{ + kthermal_limit = freq; + if (freq > 0) + { + //pr_alert("DO KTHERMAL %u-%u\n", cpu, freq); + __cpufreq_driver_target(&trmlpolicy[cpu], freq, CPUFREQ_RELATION_H); + } +} /* * data : current policy. @@ -1815,6 +1861,11 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data, memcpy(&policy->cpuinfo, &data->cpuinfo, sizeof(struct cpufreq_cpuinfo)); + + memcpy(&trmlpolicy[policy->cpu], policy, sizeof(struct cpufreq_policy)); + + if (vfreq_lock_tempOFF) + vfreq_lock = 1; if (policy->min > data->max || policy->max < data->min) { ret = -EINVAL; @@ -1826,6 +1877,23 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data, if (ret) goto error_out; + //Do KT checker + if (policy->cpuinfo.min_freq != GLOBALKT_MIN_FREQ_LIMIT || policy->cpuinfo.max_freq != GLOBALKT_MAX_FREQ_LIMIT) + { + policy->cpuinfo.min_freq = GLOBALKT_MIN_FREQ_LIMIT; + policy->cpuinfo.max_freq = GLOBALKT_MAX_FREQ_LIMIT; + } + if (policy->min < GLOBALKT_MIN_FREQ_LIMIT || policy->max > GLOBALKT_MAX_FREQ_LIMIT) + { + policy->min = GLOBALKT_MIN_FREQ_LIMIT; + policy->max = GLOBALKT_MAX_FREQ_LIMIT; + } + if (policy->user_policy.min < GLOBALKT_MIN_FREQ_LIMIT || policy->user_policy.max > GLOBALKT_MAX_FREQ_LIMIT) + { + policy->user_policy.min = GLOBALKT_MIN_FREQ_LIMIT; + policy->user_policy.max = GLOBALKT_MAX_FREQ_LIMIT; + } + /* adjust if necessary - all reasons */ blocking_notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_ADJUST, policy); @@ -1840,6 +1908,23 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data, if (ret) goto error_out; + //Do KT checker + if (policy->cpuinfo.min_freq != GLOBALKT_MIN_FREQ_LIMIT || policy->cpuinfo.max_freq != GLOBALKT_MAX_FREQ_LIMIT) + { + policy->cpuinfo.min_freq = GLOBALKT_MIN_FREQ_LIMIT; + policy->cpuinfo.max_freq = GLOBALKT_MAX_FREQ_LIMIT; + } + if (policy->min < GLOBALKT_MIN_FREQ_LIMIT || policy->max > GLOBALKT_MAX_FREQ_LIMIT) + { + policy->min = GLOBALKT_MIN_FREQ_LIMIT; + policy->max = GLOBALKT_MAX_FREQ_LIMIT; + } + if (policy->user_policy.min < GLOBALKT_MIN_FREQ_LIMIT || policy->user_policy.max > GLOBALKT_MAX_FREQ_LIMIT) + { + policy->user_policy.min = GLOBALKT_MIN_FREQ_LIMIT; + policy->user_policy.max = GLOBALKT_MAX_FREQ_LIMIT; + } + /* notification of the new policy */ blocking_notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_NOTIFY, policy); diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 1484b378..5ec8f4be 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -25,7 +25,10 @@ extern int GLOBALKT_MIN_FREQ_LIMIT; extern int GLOBALKT_MAX_FREQ_LIMIT; -#define FREQ_TABLE_SIZE 38 +#define FREQ_TABLE_SIZE 42 +#define MAX_VDD_SC 1450000 /* uV */ +#define MIN_VDD_SC 700000 /* uV */ +extern unsigned int kthermal_limit; /********************************************************************* * CPUFREQ NOTIFIER INTERFACE *