summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/tegra11_soctherm.c
diff options
context:
space:
mode:
authorPaul Walmsley <pwalmsley@nvidia.com>2014-04-12 12:37:55 -0700
committerSeema Khowala <seemaj@nvidia.com>2014-04-23 14:04:59 -0700
commit0ee1747f93154ff8ba392d5853928620df3045cb (patch)
treeabde18f7ed039c0132842d9f4c10e8acaa8b52d9 /arch/arm/mach-tegra/tegra11_soctherm.c
parente61c79b70d14ce5401ba3943570037c2a47e2f22 (diff)
arm: tegra: thermal: split CPU throttle control code
For clarity, split the CPU thermal throttling pulse skipper control code, throttlectl_cpu(), into two variants. The first variant is for SoCs with CPU throttling control in the SOC_THERM block, such as T114, T148, and T124. These are programmed by setting pulse skipper M/N ratio values directly in SOC_THERM registers. The abbreviation used in the function names is "mn". The second variant is for SoCs with CPU throttling control in the CPU subsystem, such as T132. For these chips, the M/N ratio values are written to CPU subsystem registers, but the selection of which of these ratio tuples to use for a certain SoC throttling level (low, medium, heavy) is handled via SOC_THERM register writes. The abbreviation used in the function names is "level". While here, fix some minor documentation issues, and remove the pulse-skipper sequencer control code from the "level" variant, since we're not using it there. This version incorporates some comments on the function names from Matt Longnecker <mlongnecker@nvidia.com> Bug 1201644 Bug 1380438 Bug 1482040 Change-Id: Ibcfc370ee3fd83553b778f89bc419910f98b1269 Signed-off-by: Paul Walmsley <pwalmsley@nvidia.com> Cc: Diwakar Tundlam <dtundlam@nvidia.com> Cc: Aleksandr Frid <afrid@nvidia.com> Cc: Matt Longnecker <mlongnecker@nvidia.com> Reviewed-on: http://git-master/r/395530 Reviewed-by: Diwakar Tundlam <dtundlam@nvidia.com> Tested-by: Diwakar Tundlam <dtundlam@nvidia.com>
Diffstat (limited to 'arch/arm/mach-tegra/tegra11_soctherm.c')
-rw-r--r--arch/arm/mach-tegra/tegra11_soctherm.c133
1 files changed, 81 insertions, 52 deletions
diff --git a/arch/arm/mach-tegra/tegra11_soctherm.c b/arch/arm/mach-tegra/tegra11_soctherm.c
index 26142de97936..7c2a8ae4168e 100644
--- a/arch/arm/mach-tegra/tegra11_soctherm.c
+++ b/arch/arm/mach-tegra/tegra11_soctherm.c
@@ -2011,42 +2011,80 @@ static irqreturn_t soctherm_edp_isr(int irq, void *arg)
}
/**
- * throttlectl_cpu() - programs CPU pulse skippers' configuration
- * @throt soctherm_throttle_id describing the level of throttling
- *
- * Pulse skippers are used to throttle clock frequencies.
- * This function programs the pulse skippers based on @throt and platform data.
- *
- * For T132 this function programs soctherm's interface to Denver:CCROC NV_THERM
- * in terms of Low, Medium and Heavy throttling vectors. PSKIP_BYPASS mode is
- * set as required per HW spec.
- *
- * Return: boolean true if HW was programmed
+ * throttlectl_cpu_mn() - program CPU pulse skipper configuration
+ * @throt: soctherm_throttle_id describing the level of throttling
+ *
+ * Pulse skippers are used to throttle clock frequencies. This
+ * function programs the pulse skippers based on @throt and platform
+ * data. This function is used for CPUs that have "remote" pulse
+ * skipper control, e.g., the CPU pulse skipper is controlled by the
+ * SOC_THERM IP block. (SOC_THERM is located outside the CPU
+ * complex.)
+ *
+ * Return: boolean true if HW was programmed, or false if the desired
+ * configuration is not supported.
+ */
+static bool throttlectl_cpu_mn(enum soctherm_throttle_id throt)
+{
+ u32 r;
+ struct soctherm_throttle *data = &plat_data.throttle[throt];
+ struct soctherm_throttle_dev *dev = &data->devs[THROTTLE_DEV_CPU];
+
+ if (!dev->enable)
+ return false;
+
+ r = soctherm_readl(THROT_PSKIP_CTRL(throt, THROTTLE_DEV_CPU));
+ 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(throt, THROTTLE_DEV_CPU));
+
+ r = soctherm_readl(THROT_PSKIP_RAMP(throt, THROTTLE_DEV_CPU));
+ 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(throt, THROTTLE_DEV_CPU));
+
+ return true;
+}
+
+/**
+ * throttlectl_cpu_level() - program CPU pulse skipper configuration
+ * @throt: soctherm_throttle_id describing the level of throttling
+ *
+ * Pulse skippers are used to throttle clock frequencies. This
+ * function programs the pulse skippers based on @throt and platform
+ * data. This function is used on SoCs which have CPU-local pulse
+ * skipper control, such as T13x. It programs soctherm's interface to
+ * Denver:CCROC NV_THERM in terms of Low, Medium and Heavy throttling
+ * vectors. PSKIP_BYPASS mode is set as required per HW spec.
+ *
+ * It's also necessary to set up the CPU-local NV_THERM instance with
+ * the M/N values desired for each level. This function does this
+ * also, although it should be handled by a separate driver.
+ *
+ * Return: boolean true if HW was programmed, or false if the desired
+ * configuration is not supported.
*/
-static bool throttlectl_cpu(enum soctherm_throttle_id throt)
+static bool throttlectl_cpu_level(enum soctherm_throttle_id throt)
{
u32 r, throt_vect = 0;
int throt_level = 0;
-
struct soctherm_throttle *data = &plat_data.throttle[throt];
struct soctherm_throttle_dev *dev = &data->devs[THROTTLE_DEV_CPU];
if (!dev->enable)
return false;
- if (IS_T13X) {
- /* Denver:CCROC NV_THERM interface N:3 Mapping */
- if (!strcmp(dev->throttling_depth, "heavy_throttling")) {
- throt_level = THROT_LEVEL_HVY;
- throt_vect = THROT_VECT_HVY;
- } else if (!strcmp(dev->throttling_depth,
- "medium_throttling")) {
- throt_level = THROT_LEVEL_MED;
- throt_vect = THROT_VECT_MED;
- } else {
- throt_level = THROT_LEVEL_LOW;
- throt_vect = THROT_VECT_LOW;
- }
+ /* Denver:CCROC NV_THERM interface N:3 Mapping */
+ if (!strcmp(dev->throttling_depth, "heavy_throttling")) {
+ throt_level = THROT_LEVEL_HVY;
+ throt_vect = THROT_VECT_HVY;
+ } else if (!strcmp(dev->throttling_depth, "medium_throttling")) {
+ throt_level = THROT_LEVEL_MED;
+ throt_vect = THROT_VECT_MED;
+ } else {
+ throt_level = THROT_LEVEL_LOW;
+ throt_vect = THROT_VECT_LOW;
}
if (dev->depth)
@@ -2054,37 +2092,27 @@ static bool throttlectl_cpu(enum soctherm_throttle_id throt)
r = soctherm_readl(THROT_PSKIP_CTRL(throt, THROTTLE_DEV_CPU));
r = REG_SET(r, THROT_PSKIP_CTRL_ENABLE, dev->enable);
- /* for T32: setup throttle vector in soctherm register */
- if (!IS_T13X) {
- r = REG_SET(r, THROT_PSKIP_CTRL_DIVIDEND, dev->dividend);
- r = REG_SET(r, THROT_PSKIP_CTRL_DIVISOR, dev->divisor);
- } else {
- r = REG_SET(r, THROT_PSKIP_CTRL_VECT_CPU, throt_vect);
- r = REG_SET(r, THROT_PSKIP_CTRL_VECT2_CPU, throt_vect);
- }
+ /* for T132: setup throttle vector in soctherm register */
+ r = REG_SET(r, THROT_PSKIP_CTRL_VECT_CPU, throt_vect);
+ r = REG_SET(r, THROT_PSKIP_CTRL_VECT2_CPU, throt_vect);
soctherm_writel(r, THROT_PSKIP_CTRL(throt, THROTTLE_DEV_CPU));
+ /* No point programming the sequencer, since we're bypassing it */
+
+ /* for T132: setup actual depth in ccroc nv_therm register */
r = soctherm_readl(THROT_PSKIP_RAMP(throt, THROTTLE_DEV_CPU));
- r = REG_SET(r, THROT_PSKIP_RAMP_DURATION, dev->duration);
- r = REG_SET(r, THROT_PSKIP_RAMP_STEP, dev->step);
+ r = REG_SET(r, THROT_PSKIP_RAMP_SEQ_BYPASS_MODE, 1);
soctherm_writel(r, THROT_PSKIP_RAMP(throt, THROTTLE_DEV_CPU));
- if (IS_T13X) {
- /* for T32: setup actual depth in ccroc nv_therm register */
- r = soctherm_readl(THROT_PSKIP_RAMP(throt, THROTTLE_DEV_CPU));
- r = REG_SET(r, THROT_PSKIP_RAMP_SEQ_BYPASS_MODE, 1);
- soctherm_writel(r, THROT_PSKIP_RAMP(throt, THROTTLE_DEV_CPU));
-
- r = throtctl_readl(THROT13_PSKIP_RAMP_CPU(throt_level));
- r = REG_SET(r, THROT_PSKIP_RAMP_SEQ_BYPASS_MODE, 1);
- throtctl_writel(r, THROT13_PSKIP_RAMP_CPU(throt_level));
+ r = throtctl_readl(THROT13_PSKIP_RAMP_CPU(throt_level));
+ r = REG_SET(r, THROT_PSKIP_RAMP_SEQ_BYPASS_MODE, 1);
+ throtctl_writel(r, THROT13_PSKIP_RAMP_CPU(throt_level));
- r = throtctl_readl(THROT13_PSKIP_CTRL_CPU(throt_level));
- 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);
- throtctl_writel(r, THROT13_PSKIP_CTRL_CPU(throt_level));
- }
+ r = throtctl_readl(THROT13_PSKIP_CTRL_CPU(throt_level));
+ 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);
+ throtctl_writel(r, THROT13_PSKIP_CTRL_CPU(throt_level));
return true;
}
@@ -2178,7 +2206,8 @@ static void soctherm_throttle_program(enum soctherm_throttle_id throt)
bool throt_enable;
struct soctherm_throttle *data = &plat_data.throttle[throt];
- throt_enable = throttlectl_cpu(throt);
+ throt_enable = (IS_T13X) ? throttlectl_cpu_level(throt) :
+ throttlectl_cpu_mn(throt);
throt_enable |= throttlectl_gpu(throt);
r = REG_SET(0, THROT_PRIORITY_LITE_PRIO, data->priority);