summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/tegra11_soctherm.c
diff options
context:
space:
mode:
authorJoshua Primero <jprimero@nvidia.com>2012-10-02 15:09:55 -0700
committerSimone Willett <swillett@nvidia.com>2012-10-25 16:38:51 -0700
commit0168925545135165293ca27aaffb7098827e9b39 (patch)
tree23339f55611ef670cecda1e99c8cb32c2c81d154 /arch/arm/mach-tegra/tegra11_soctherm.c
parentd790e3fa579c55ac0f1ea650865edefcf3eb1756 (diff)
ARM: tegra: soctherm: Enable pulse skipper
Enable pulse skipper hardware throttling. Change-Id: I00855d491e603270b8e81b7f7feb8e94e294b1fd Signed-off-by: Joshua Primero <jprimero@nvidia.com> Reviewed-on: http://git-master/r/141035 (cherry picked from commit a42307516078f48c2b784158e84adcf3eaf4cd30) Signed-off-by: Gaurav Batra <gbatra@nvidia.com> Reviewed-on: http://git-master/r/147057 Reviewed-by: Simone Willett <swillett@nvidia.com> Tested-by: Simone Willett <swillett@nvidia.com>
Diffstat (limited to 'arch/arm/mach-tegra/tegra11_soctherm.c')
-rw-r--r--arch/arm/mach-tegra/tegra11_soctherm.c273
1 files changed, 189 insertions, 84 deletions
diff --git a/arch/arm/mach-tegra/tegra11_soctherm.c b/arch/arm/mach-tegra/tegra11_soctherm.c
index 1022a60a5487..8a09dc39c1c5 100644
--- a/arch/arm/mach-tegra/tegra11_soctherm.c
+++ b/arch/arm/mach-tegra/tegra11_soctherm.c
@@ -52,6 +52,9 @@
#define CTL_LVL0_CPU0_STATUS_SHIFT 0
#define CTL_LVL0_CPU0_STATUS_MASK 0x3
+#define CTL_LVL_OFFSET 0x20
+#define CTL_LVL_CPU0(lvl) (CTL_LVL0_CPU0 + (lvl * CTL_LVL_OFFSET))
+
#define THERMTRIP 0x80
#define THERMTRIP_ANY_EN_SHIFT 28
#define THERMTRIP_ANY_EN_MASK 0x1
@@ -188,23 +191,54 @@
#define LOCK_CTL 0x90
#define STATS_CTL 0x94
-#define PSKIP_STATUS 0x418
-
-#define PSKIP_CTRL_LITE_CPU 0x430
-
-#define PSKIP_CTRL_HEAVY_CPU 0x460
-#define PSKIP_CTRL_HEAVY_CPU_ENABLE_SHIFT 31
-#define PSKIP_CTRL_HEAVY_CPU_ENABLE_MASK 0x1
-#define PSKIP_CTRL_HEAVY_CPU_DIVIDEND_SHIFT 8
-#define PSKIP_CTRL_HEAVY_CPU_DIVIDEND_MASK 0xff
-#define PSKIP_CTRL_HEAVY_CPU_DIVISOR_SHIFT 0
-#define PSKIP_CTRL_HEAVY_CPU_DIVISOR_MASK 0xff
-
-#define PSKIP_RAMP_HEAVY_CPU 0x464
-#define PSKIP_RAMP_HEAVY_CPU_DURATION_SHIFT 8
-#define PSKIP_RAMP_HEAVY_CPU_DURATION_MASK 0xffff
-#define PSKIP_RAMP_HEAVY_CPU_STEP_SHIFT 0
-#define PSKIP_RAMP_HEAVY_CPU_STEP_MASK 0xff
+#define THROT_GLOBAL_CFG 0x400
+
+#define CPU_PSKIP_STATUS 0x418
+#define CPU_PSKIP_STATUS_M_SHIFT 12
+#define CPU_PSKIP_STATUS_M_MASK 0xff
+#define CPU_PSKIP_STATUS_N_SHIFT 4
+#define CPU_PSKIP_STATUS_N_MASK 0xff
+#define CPU_PSKIP_STATUS_ENABLED_SHIFT 0
+#define CPU_PSKIP_STATUS_ENABLED_MASK 0x1
+
+#define THROT_PRIORITY_LOCK 0x424
+#define THROT_PRIORITY_LOCK_PRIORITY_SHIFT 0
+#define THROT_PRIORITY_LOCK_PRIORITY_MASK 0xff
+
+#define THROT_STATUS 0x428
+#define THROT_STATUS_BREACH_SHIFT 12
+#define THROT_STATUS_BREACH_MASK 0x1
+#define THROT_STATUS_STATE_SHIFT 4
+#define THROT_STATUS_STATE_MASK 0xff
+#define THROT_STATUS_ENABLED_SHIFT 0
+#define THROT_STATUS_ENABLED_MASK 0x1
+
+#define THROT_PSKIP_CTRL_LITE_CPU 0x430
+#define THROT_PSKIP_CTRL_ENABLE_SHIFT 31
+#define THROT_PSKIP_CTRL_ENABLE_MASK 0x1
+#define THROT_PSKIP_CTRL_DIVIDEND_SHIFT 8
+#define THROT_PSKIP_CTRL_DIVIDEND_MASK 0xff
+#define THROT_PSKIP_CTRL_DIVISOR_SHIFT 0
+#define THROT_PSKIP_CTRL_DIVISOR_MASK 0xff
+
+#define THROT_PSKIP_RAMP_LITE_CPU 0x434
+#define THROT_PSKIP_RAMP_DURATION_SHIFT 8
+#define THROT_PSKIP_RAMP_DURATION_MASK 0xffff
+#define THROT_PSKIP_RAMP_STEP_SHIFT 0
+#define THROT_PSKIP_RAMP_STEP_MASK 0xff
+
+#define THROT_LITE_PRIORITY 0x444
+#define THROT_LITE_PRIORITY_PRIORITY_SHIFT 0
+#define THROT_LITE_PRIORITY_PRIORITY_MASK 0xff
+
+#define THROT_OFFSET 0x30
+
+#define THROT_PSKIP_CTRL(throt, dev) (THROT_PSKIP_CTRL_LITE_CPU + \
+ (THROT_OFFSET * throt) + \
+ (8 * dev))
+#define THROT_PSKIP_RAMP(throt, dev) (THROT_PSKIP_RAMP_LITE_CPU + \
+ (THROT_OFFSET * throt) + \
+ (8 * dev))
#define PSKIP_CTRL_OC1_CPU 0x490
@@ -216,6 +250,11 @@
static void __iomem *reg_soctherm_base = IO_ADDRESS(TEGRA_SOCTHERM_BASE);
static void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+static void __iomem *clk_reset_base = IO_ADDRESS(TEGRA_CLK_RESET_BASE);
+
+#define clk_reset_writel(value, reg) \
+ __raw_writel(value, (u32)clk_reset_base + (reg))
+#define clk_reset_readl(reg) __raw_readl((u32)clk_reset_base + (reg))
#define pmc_writel(value, reg) __raw_writel(value, (u32)pmc_base + (reg))
#define pmc_readl(reg) __raw_readl((u32)pmc_base + (reg))
@@ -257,7 +296,7 @@ static inline long temp_translate(int readback)
return (abs * 1000 + lsb * 500) * (sign * -2 + 1);
}
-static int soctherm_set_limits(enum soctherm_therm therm,
+static int soctherm_set_limits(enum soctherm_therm_id therm,
long lo_limit, long hi_limit)
{
u32 r = soctherm_readl(CTL_LVL0_CPU0);
@@ -307,7 +346,7 @@ static int soctherm_bind(struct thermal_zone_device *thz,
if (index < 0)
return 0;
- if (plat_data.passive[index].cdev == cdevice)
+ if (plat_data.therm[index].cdev == cdevice)
return thermal_zone_bind_cooling_device(thz, 0, cdevice);
return 0;
@@ -321,7 +360,7 @@ static int soctherm_unbind(struct thermal_zone_device *thz,
if (index < 0)
return 0;
- if (plat_data.passive[index].cdev == cdevice)
+ if (plat_data.therm[index].cdev == cdevice)
return thermal_zone_unbind_cooling_device(thz, 0, cdevice);
return 0;
@@ -359,7 +398,7 @@ static int soctherm_get_trip_type(struct thermal_zone_device *thz,
enum thermal_trip_type *type) {
int index = ((int)thz->devdata) - TSENSE_SIZE;
- if (index < 0 || !plat_data.passive[index].cdev)
+ if (index < 0 || !plat_data.therm[index].cdev)
return -EINVAL;
*type = THERMAL_TRIP_PASSIVE;
@@ -371,10 +410,10 @@ static int soctherm_get_trip_temp(struct thermal_zone_device *thz,
unsigned long *temp) {
int index = ((int)thz->devdata) - TSENSE_SIZE;
- if (index < 0 || !plat_data.passive[index].cdev)
+ if (index < 0 || !plat_data.therm[index].cdev)
return -EINVAL;
- *temp = plat_data.passive[index].trip_temp;
+ *temp = plat_data.therm[index].trip_temp;
return 0;
}
@@ -383,10 +422,10 @@ static int soctherm_set_trip_temp(struct thermal_zone_device *thz,
unsigned long temp)
{
int index = ((int)thz->devdata) - TSENSE_SIZE;
- if (index < 0 || !plat_data.passive[index].cdev)
+ if (index < 0 || !plat_data.therm[index].cdev)
return -EINVAL;
- plat_data.passive[index].trip_temp = temp;
+ plat_data.therm[index].trip_temp = temp;
soctherm_update();
@@ -424,19 +463,36 @@ static irqreturn_t soctherm_isr(int irq, void *arg_data)
return IRQ_HANDLED;
}
-void tegra11_soctherm_skipper_program(struct soctherm_skipper_data *data)
+void tegra11_soctherm_throttle_program(enum soctherm_throttle_id throttle,
+ struct soctherm_throttle *data)
{
u32 r;
- r = soctherm_readl(PSKIP_CTRL_HEAVY_CPU);
- r = REG_SET(r, PSKIP_CTRL_HEAVY_CPU_ENABLE, data->enable);
- r = REG_SET(r, PSKIP_CTRL_HEAVY_CPU_DIVIDEND, data->dividend);
- r = REG_SET(r, PSKIP_CTRL_HEAVY_CPU_DIVISOR, data->divisor);
- soctherm_writel(r, PSKIP_CTRL_HEAVY_CPU);
-
- r = soctherm_readl(PSKIP_RAMP_HEAVY_CPU);
- r = REG_SET(r, PSKIP_RAMP_HEAVY_CPU_DURATION, data->duration);
- r = REG_SET(r, PSKIP_RAMP_HEAVY_CPU_STEP, data->step);
- soctherm_writel(r, PSKIP_RAMP_HEAVY_CPU);
+ int i;
+ struct soctherm_throttle_dev *dev;
+
+ for (i = 0; i < THROTTLE_DEV_SIZE; i++) {
+ dev = &data->devs[i];
+
+ r = soctherm_readl(THROT_PSKIP_CTRL(throttle, i));
+ r = REG_SET(r, THROT_PSKIP_CTRL_ENABLE, dev->enable);
+ r = REG_SET(r, THROT_PSKIP_CTRL_DIVIDEND, dev->dividend);
+ r = REG_SET(r, THROT_PSKIP_CTRL_DIVISOR, dev->divisor);
+ soctherm_writel(r, THROT_PSKIP_CTRL(throttle, i));
+
+ r = soctherm_readl(THROT_PSKIP_RAMP(throttle, i));
+ r = REG_SET(r, THROT_PSKIP_RAMP_DURATION, dev->duration);
+ r = REG_SET(r, THROT_PSKIP_RAMP_STEP, dev->step);
+ soctherm_writel(r, THROT_PSKIP_RAMP(throttle, i));
+ }
+
+ r = soctherm_readl(THROT_PRIORITY_LOCK);
+ if (r < data->priority) {
+ r = REG_SET(0, THROT_PRIORITY_LOCK_PRIORITY, data->priority);
+ soctherm_writel(r, THROT_PRIORITY_LOCK);
+ }
+
+ r = REG_SET(0, THROT_LITE_PRIORITY_PRIORITY, data->priority);
+ soctherm_writel(r, THROT_LITE_PRIORITY + THROT_OFFSET * throttle);
}
static void __init soctherm_tsense_program(enum soctherm_sense sensor,
@@ -463,15 +519,19 @@ int __init tegra11_soctherm_init(struct soctherm_platform_data *data)
{
int err, i;
u32 r;
+ u32 reg_off;
char name[64];
+ struct soctherm_therm *therm;
+
+ memcpy(&plat_data, data, sizeof(struct soctherm_platform_data));
+
+ therm = plat_data.therm;
/* Can only thermtrip with either GPU or MEM but not both */
- if (data->thermtrip[THERM_GPU] && data->thermtrip[THERM_MEM])
+ if (therm[THERM_GPU].thermtrip && therm[THERM_MEM].thermtrip)
return -EINVAL;
- memcpy(&plat_data, data, sizeof(struct soctherm_platform_data));
-
/* Thermal Sensing programming */
for (i = 0; i < TSENSE_SIZE; i++) {
if (plat_data.sensor_data[i].enable) {
@@ -501,46 +561,48 @@ int __init tegra11_soctherm_init(struct soctherm_platform_data *data)
r = REG_SET(r, TS_PDIV_CPU, data->sensor_data[TSENSE_PLLX].pdiv);
soctherm_writel(r, TS_PDIV);
-#ifdef CONFIG_THERMAL
for (i = 0; i < THERM_SIZE; i++) {
+#ifdef CONFIG_THERMAL
sprintf(name, "%s-therm", therm_names[i]);
thz[i] = thermal_zone_device_register(
name,
- 0x1,
- data->passive[i].cdev ? 1 : 0,
+ data->therm[i].cdev ? 1 : 0,
+ data->therm[i].cdev ? 0x1 : 0,
(void *)TSENSE_SIZE + i,
&soctherm_ops,
- data->passive[i].tc1,
- data->passive[i].tc2,
- data->passive[i].passive_delay,
+ data->therm[i].tc1,
+ data->therm[i].tc2,
+ data->therm[i].passive_delay,
0);
- }
#endif
+ if (data->therm[i].hw_backstop) {
+ reg_off = CTL_LVL_CPU0(1) + i * 4;
+ r = soctherm_readl(reg_off);
+ r = REG_SET(r, CTL_LVL0_CPU0_UP_THRESH,
+ data->therm[i].hw_backstop);
+ r = REG_SET(r, CTL_LVL0_CPU0_DN_THRESH,
+ data->therm[i].hw_backstop - 2);
+ r = REG_SET(r, CTL_LVL0_CPU0_EN, 1);
+ /* Heavy throttling */
+ r = REG_SET(r, CTL_LVL0_CPU0_CPU_THROT, 2);
+ soctherm_writel(r, reg_off);
+ }
+ }
/* Enable Level 0 */
r = soctherm_readl(CTL_LVL0_CPU0);
r = REG_SET(r, CTL_LVL0_CPU0_EN, 1);
soctherm_writel(r, CTL_LVL0_CPU0);
-#if 0
- /* Enable Level 1 Hw throttling */
- r = soctherm_readl(CTL_LVL1_MEM0);
- r = REG_SET(r, CTL_LVL0_MEM0_UP_THRESH, 60);
- r = REG_SET(r, CTL_LVL0_MEM0_EN, 1);
- r = REG_SET(r, CTL_LVL0_MEM0_CPU_THROT, 2); /* Heavy throttling */
-
- soctherm_writel(r, CTL_LVL1_MEM0);
-#endif
-
/* Thermtrip */
- r = REG_SET(0, THERMTRIP_CPU_EN, !!data->thermtrip[THERM_CPU]);
- r = REG_SET(r, THERMTRIP_GPU_EN, !!data->thermtrip[THERM_GPU]);
- r = REG_SET(r, THERMTRIP_MEM_EN, !!data->thermtrip[THERM_MEM]);
- r = REG_SET(r, THERMTRIP_TSENSE_EN, !!data->thermtrip[THERM_PLL]);
- r = REG_SET(r, THERMTRIP_CPU_THRESH, data->thermtrip[THERM_CPU]);
- r = REG_SET(r, THERMTRIP_GPUMEM_THRESH, data->thermtrip[THERM_GPU] |
- data->thermtrip[THERM_MEM]);
- r = REG_SET(r, THERMTRIP_TSENSE_THRESH, data->thermtrip[THERM_PLL]);
+ r = REG_SET(0, THERMTRIP_CPU_EN, !!therm[THERM_CPU].thermtrip);
+ r = REG_SET(r, THERMTRIP_GPU_EN, !!therm[THERM_GPU].thermtrip);
+ r = REG_SET(r, THERMTRIP_MEM_EN, !!therm[THERM_MEM].thermtrip);
+ r = REG_SET(r, THERMTRIP_TSENSE_EN, !!therm[THERM_PLL].thermtrip);
+ r = REG_SET(r, THERMTRIP_CPU_THRESH, therm[THERM_CPU].thermtrip);
+ r = REG_SET(r, THERMTRIP_GPUMEM_THRESH, therm[THERM_GPU].thermtrip |
+ therm[THERM_MEM].thermtrip);
+ r = REG_SET(r, THERMTRIP_TSENSE_THRESH, therm[THERM_PLL].thermtrip);
soctherm_writel(r, THERMTRIP);
/* Enable PMC to shutdown */
@@ -548,6 +610,15 @@ int __init tegra11_soctherm_init(struct soctherm_platform_data *data)
r |= 0x2;
pmc_writel(r, 0x1b0);
+ /* Throttling */
+ for (i = 0; i < THROTTLE_SIZE; i++)
+ tegra11_soctherm_throttle_program(i, &data->throttle[i]);
+
+ r = clk_reset_readl(0x24);
+ r |= (1 << 30);
+ clk_reset_writel(r, 0x24);
+
+ /* enable interrupts */
workqueue = create_singlethread_workqueue("soctherm");
INIT_WORK(&work, soctherm_work_func);
@@ -579,7 +650,7 @@ static int regs_show(struct seq_file *s, void *data)
{
u32 r;
u32 state;
- int i;
+ int i, level;
seq_printf(s, "-----TSENSE-----\n");
for (i = 0; i < TSENSE_SIZE; i++) {
@@ -646,23 +717,25 @@ static int regs_show(struct seq_file *s, void *data)
state = REG_GET(r, TS_TEMP2_MEM_TEMP);
seq_printf(s, " MEM(%ld) ", temp_translate(state));
state = REG_GET(r, TS_TEMP2_PLLX_TEMP);
- seq_printf(s, " PLLX(%ld)\n", temp_translate(state));
+ seq_printf(s, " PLLX(%ld)\n\n", temp_translate(state));
for (i = 0; i < THERM_SIZE; i++) {
- seq_printf(s, "%s: ", therm_names[i]);
-
- r = soctherm_readl(CTL_LVL0_CPU0 + i * 4);
- state = REG_GET(r, CTL_LVL0_CPU0_UP_THRESH);
- seq_printf(s, "Up/Dn(%d/", state);
- state = REG_GET(r, CTL_LVL0_CPU0_DN_THRESH);
- seq_printf(s, "%d) ", state);
- state = REG_GET(r, CTL_LVL0_CPU0_EN);
- seq_printf(s, "En(%d) ", state);
- state = REG_GET(r, CTL_LVL0_CPU0_STATUS);
- seq_printf(s, "Status(%s)\n", state == 0 ? "below" :
- state == 1 ? "in" :
- state == 2 ? "res" :
- "above");
+ seq_printf(s, "%s:\n", therm_names[i]);
+
+ for (level = 0; level < 4; level++) {
+ r = soctherm_readl(CTL_LVL_CPU0(level) + i * 4);
+ state = REG_GET(r, CTL_LVL0_CPU0_UP_THRESH);
+ seq_printf(s, " Up/Dn(%d/", state);
+ state = REG_GET(r, CTL_LVL0_CPU0_DN_THRESH);
+ seq_printf(s, "%d) ", state);
+ state = REG_GET(r, CTL_LVL0_CPU0_EN);
+ seq_printf(s, "En(%d) ", state);
+ state = REG_GET(r, CTL_LVL0_CPU0_STATUS);
+ seq_printf(s, "Status(%s)\n", state == 0 ? "below" :
+ state == 1 ? "in" :
+ state == 2 ? "res" :
+ "above");
+ }
}
r = soctherm_readl(INTR_STATUS);
@@ -671,16 +744,48 @@ static int regs_show(struct seq_file *s, void *data)
state = REG_GET(r, INTR_STATUS_MU0);
seq_printf(s, "MU0: %d\n", state);
- r = soctherm_readl(PSKIP_STATUS);
- seq_printf(s, "PSKIP: 0x%x\n", r);
-
r = soctherm_readl(THERMTRIP);
- seq_printf(s, "THERMTRIP: 0x%x\n", r);
state = REG_GET(r, THERMTRIP_CPU_THRESH);
seq_printf(s, "THERMTRIP_CPU_THRESH: %d ", state);
state = REG_GET(r, THERMTRIP_CPU_EN);
seq_printf(s, "%d\n", state);
+
+ seq_printf(s, "\n-----THROTTLE-----\n");
+
+ r = soctherm_readl(THROT_GLOBAL_CFG);
+ seq_printf(s, "GLOBAL CONFIG: 0x%x\n", r);
+
+ r = soctherm_readl(THROT_STATUS);
+ state = REG_GET(r, THROT_STATUS_BREACH);
+ seq_printf(s, "THROT STATUS: breach(%d) ", state);
+ state = REG_GET(r, THROT_STATUS_STATE);
+ seq_printf(s, "state(%d) ", state);
+ state = REG_GET(r, THROT_STATUS_ENABLED);
+ seq_printf(s, "enabled(%d)\n", state);
+
+ r = soctherm_readl(CPU_PSKIP_STATUS);
+ state = REG_GET(r, CPU_PSKIP_STATUS_M);
+ seq_printf(s, "CPU PSKIP: M(%d) ", state);
+ state = REG_GET(r, CPU_PSKIP_STATUS_N);
+ seq_printf(s, "N(%d) ", state);
+ state = REG_GET(r, CPU_PSKIP_STATUS_ENABLED);
+ seq_printf(s, "enabled(%d)\n", state);
+
+ r = soctherm_readl(THROT_PSKIP_CTRL(THROTTLE_HEAVY, THROTTLE_DEV_CPU));
+ state = REG_GET(r, THROT_PSKIP_CTRL_ENABLE);
+ seq_printf(s, "CPU PSKIP HEAVY: enabled(%d) ", state);
+ state = REG_GET(r, THROT_PSKIP_CTRL_DIVIDEND);
+ seq_printf(s, "dividend(%d) ", state);
+ state = REG_GET(r, THROT_PSKIP_CTRL_DIVISOR);
+ seq_printf(s, "divisor(%d) ", state);
+
+ r = soctherm_readl(THROT_PSKIP_RAMP(THROTTLE_HEAVY, THROTTLE_DEV_CPU));
+ state = REG_GET(r, THROT_PSKIP_RAMP_DURATION);
+ seq_printf(s, "duration(%d) ", state);
+ state = REG_GET(r, THROT_PSKIP_RAMP_STEP);
+ seq_printf(s, "step(%d)\n", state);
+
return 0;
}