summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/tegra11_soctherm.c
diff options
context:
space:
mode:
authorDiwakar Tundlam <dtundlam@nvidia.com>2014-03-17 17:33:09 -0700
committerDiwakar Tundlam <dtundlam@nvidia.com>2014-03-21 11:07:38 -0700
commit91a5bd4c79926ef89d1d8584bd29a64c00387d8c (patch)
treefe86078a38b13a713638c69398f7130e45278bc8 /arch/arm/mach-tegra/tegra11_soctherm.c
parent63af1b1c746abb140cf68bda66a295f6a1d31ec2 (diff)
arm: tegra: soctherm: check HW max and min temp
Soctherm trip points are set in HW registers that take temperature in the range -127C to +127C. This causes the bug# noted below. Fix by checking temp before changing HW register. If threshold temp is over the range HW can support, we set it to the max. Also added a change to show the TSOSC STOP bit in debug output. Bug 1480200 Change-Id: I3c69ca1978ad17ec19af3e896d7e537fb5986ea5 Signed-off-by: Diwakar Tundlam <dtundlam@nvidia.com> Reviewed-on: http://git-master/r/382727 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Paul Walmsley <pwalmsley@nvidia.com>
Diffstat (limited to 'arch/arm/mach-tegra/tegra11_soctherm.c')
-rw-r--r--arch/arm/mach-tegra/tegra11_soctherm.c73
1 files changed, 52 insertions, 21 deletions
diff --git a/arch/arm/mach-tegra/tegra11_soctherm.c b/arch/arm/mach-tegra/tegra11_soctherm.c
index 0abfdc096939..6bd0dc1ec2ef 100644
--- a/arch/arm/mach-tegra/tegra11_soctherm.c
+++ b/arch/arm/mach-tegra/tegra11_soctherm.c
@@ -47,7 +47,8 @@
#include "common.h"
#include "dvfs.h"
-static const int MAX_HIGH_TEMP = 128000;
+static const int MAX_HIGH_TEMP = 127000;
+static const int MIN_LOW_TEMP = -127000;
/* Min temp granularity specified as X in 2^X.
* -1: Hi precision option: 2^-1 = 0.5C (T12x onwards)
@@ -747,7 +748,6 @@ static inline s64 div64_s64_precise(s64 a, s32 b)
*
* Return: the translated temperature in millicelsius
*/
-
static inline long temp_translate(int readback)
{
int abs = readback >> 8;
@@ -759,6 +759,34 @@ static inline long temp_translate(int readback)
}
#ifdef CONFIG_THERMAL
+
+/**
+ * enforce_temp_range() - check and enforce temperature range [min, max]
+ * @trip_temp: The trip temperature to check
+ *
+ * Checks and enforces the permitted temperature range that SOC_THERM
+ * HW can support with 8-bit registers to specify temperature. This is
+ * done while taking care of precision.
+ *
+ * Return: The precsion adjusted capped temperature in millicelsius.
+ */
+static int enforce_temp_range(long trip_temp)
+{
+ long temp = LOWER_PRECISION_FOR_TEMP(trip_temp);
+
+ if (temp < MIN_LOW_TEMP) {
+ pr_info("soctherm: trip_point temp %ld forced to %d\n",
+ trip_temp, LOWER_PRECISION_FOR_CONV(MIN_LOW_TEMP));
+ temp = MIN_LOW_TEMP;
+ } else if (temp > MAX_HIGH_TEMP) {
+ pr_info("soctherm: trip_point temp %ld forced to %d\n",
+ trip_temp, LOWER_PRECISION_FOR_CONV(MAX_HIGH_TEMP));
+ temp = MAX_HIGH_TEMP;
+ }
+
+ return temp;
+}
+
/**
* prog_hw_shutdown() - Configures the hardware to shut down the
* system if a given sensor group reaches a given temperature
@@ -778,24 +806,26 @@ static inline long temp_translate(int readback)
static inline void prog_hw_shutdown(struct thermal_trip_info *trip_state,
int therm)
{
- int trip_temp;
u32 r;
+ int temp;
+
+
- trip_temp = LOWER_PRECISION_FOR_TEMP(trip_state->trip_temp / 1000);
+ temp = enforce_temp_range(trip_state->trip_temp) / 1000;
r = soctherm_readl(THERMTRIP);
if (therm == THERM_CPU) {
r = REG_SET(r, THERMTRIP_CPU_EN, 1);
- r = REG_SET(r, THERMTRIP_CPU_THRESH, trip_temp);
+ r = REG_SET(r, THERMTRIP_CPU_THRESH, temp);
} else if (therm == THERM_GPU) {
r = REG_SET(r, THERMTRIP_GPU_EN, 1);
- r = REG_SET(r, THERMTRIP_GPUMEM_THRESH, trip_temp);
+ r = REG_SET(r, THERMTRIP_GPUMEM_THRESH, temp);
} else if (therm == THERM_PLL) {
r = REG_SET(r, THERMTRIP_TSENSE_EN, 1);
- r = REG_SET(r, THERMTRIP_TSENSE_THRESH, trip_temp);
+ r = REG_SET(r, THERMTRIP_TSENSE_THRESH, temp);
} else if (therm == THERM_MEM) {
r = REG_SET(r, THERMTRIP_MEM_EN, 1);
- r = REG_SET(r, THERMTRIP_GPUMEM_THRESH, trip_temp);
+ r = REG_SET(r, THERMTRIP_GPUMEM_THRESH, temp);
}
r = REG_SET(r, THERMTRIP_ANY_EN, 0);
soctherm_writel(r, THERMTRIP);
@@ -815,17 +845,17 @@ static inline void prog_hw_shutdown(struct thermal_trip_info *trip_state,
static inline void prog_hw_threshold(struct thermal_trip_info *trip_state,
int therm, int throt)
{
- int trip_temp;
u32 r, reg_off;
+ int temp;
- trip_temp = LOWER_PRECISION_FOR_TEMP(trip_state->trip_temp / 1000);
+ temp = enforce_temp_range(trip_state->trip_temp) / 1000;
/* Hardcode LITE on level-1 and HEAVY on level-2 */
reg_off = TS_THERM_REG_OFFSET(CTL_LVL0_CPU0, throt + 1, therm);
r = soctherm_readl(reg_off);
- r = REG_SET(r, CTL_LVL0_CPU0_UP_THRESH, trip_temp);
- r = REG_SET(r, CTL_LVL0_CPU0_DN_THRESH, trip_temp);
+ r = REG_SET(r, CTL_LVL0_CPU0_UP_THRESH, temp);
+ r = REG_SET(r, CTL_LVL0_CPU0_DN_THRESH, temp);
r = REG_SET(r, CTL_LVL0_CPU0_EN, 1);
r = REG_SET(r, CTL_LVL0_CPU0_CPU_THROT,
@@ -836,7 +866,6 @@ static inline void prog_hw_threshold(struct thermal_trip_info *trip_state,
throt == THROTTLE_HEAVY ?
CTL_LVL0_CPU0_GPU_THROT_HEAVY :
CTL_LVL0_CPU0_GPU_THROT_LIGHT);
-
soctherm_writel(r, reg_off);
}
@@ -854,15 +883,15 @@ static void soctherm_set_limits(enum soctherm_therm_id therm,
long lo_limit, long hi_limit)
{
u32 r, reg_off;
+ int lo_temp, hi_temp;
+
+ lo_temp = enforce_temp_range(lo_limit) / 1000;
+ hi_temp = enforce_temp_range(hi_limit) / 1000;
reg_off = TS_THERM_REG_OFFSET(CTL_LVL0_CPU0, 0, therm);
r = soctherm_readl(reg_off);
-
- lo_limit = LOWER_PRECISION_FOR_TEMP(lo_limit);
- hi_limit = LOWER_PRECISION_FOR_TEMP(hi_limit);
-
- r = REG_SET(r, CTL_LVL0_CPU0_DN_THRESH, lo_limit);
- r = REG_SET(r, CTL_LVL0_CPU0_UP_THRESH, hi_limit);
+ r = REG_SET(r, CTL_LVL0_CPU0_DN_THRESH, lo_temp);
+ r = REG_SET(r, CTL_LVL0_CPU0_UP_THRESH, hi_temp);
r = REG_SET(r, CTL_LVL0_CPU0_EN, 1);
soctherm_writel(r, reg_off);
@@ -944,7 +973,7 @@ static void soctherm_update_zone(int zn)
if (passive_low_temp != MAX_HIGH_TEMP)
low_temp = max(low_temp, passive_low_temp);
- soctherm_set_limits(zn, low_temp/1000, high_temp/1000);
+ soctherm_set_limits(zn, low_temp, high_temp);
}
/**
@@ -1366,7 +1395,7 @@ static int soctherm_set_trip_temp(struct thermal_zone_device *thz,
trip_state = &plat_data.therm[index].trips[trip];
- trip_state->trip_temp = temp;
+ trip_state->trip_temp = enforce_temp_range(temp);
rem = trip_state->trip_temp % LOWER_PRECISION_FOR_CONV(1000);
if (rem) {
@@ -3276,6 +3305,8 @@ static int regs_show(struct seq_file *s, void *data)
sensor2therm_b[i]));
r = soctherm_readl(TS_TSENSE_REG_OFFSET(TS_CPU0_CONFIG0, i));
+ state = REG_GET(r, TS_CPU0_CONFIG0_STOP);
+ seq_printf(s, "Stop(%d) ", state);
state = REG_GET(r, TS_CPU0_CONFIG0_TALL);
seq_printf(s, "Tall(%d) ", state);
state = REG_GET(r, TS_CPU0_CONFIG0_TCALC_OVER);