summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/tegra11_soctherm.c
diff options
context:
space:
mode:
authorPaul Walmsley <pwalmsley@nvidia.com>2014-04-17 18:03:23 -0700
committerSeema Khowala <seemaj@nvidia.com>2014-04-23 14:07:18 -0700
commitd570a7f70c526e1bf6cd753750d49f8575e1c4a9 (patch)
tree067420d5d4e46c50fc1137b1278d979db908a76e /arch/arm/mach-tegra/tegra11_soctherm.c
parent2f686f38ae8fbea547ef430356f75097b00f81d8 (diff)
arm: tegra: thermal: clean up the GPU thermal pulse skipper status read path
Clean up the GPU thermal throttling pulse skipper status read path. Add some temporary functions to indicate what features are present on what chips -- these need to be removed and replaced with some DT mechanism during the platform_driver conversion. I suspect this implementation still isn't ideal. Seems to me that we should register two separate cooling devices, one for the CPU and the other for the GPU. If SOC_THERM doesn't control CPU or GPU throttling on a given chip, then it shouldn't register the software cooling device. Instead, the driver for the IP block that handles the cooling device should do it. That should clean this code up somewhat. Bug 1201644 Bug 1380438 Bug 1482040 Change-Id: I48240ea0624842a389af74bd7f7fdc71c5f2eae8 Cc: Aleksandr Frid <afrid@nvidia.com> Cc: Diwakar Tundlam <dtundlam@nvidia.com> Signed-off-by: Paul Walmsley <pwalmsley@nvidia.com> Reviewed-on: http://git-master/r/397740 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.c159
1 files changed, 142 insertions, 17 deletions
diff --git a/arch/arm/mach-tegra/tegra11_soctherm.c b/arch/arm/mach-tegra/tegra11_soctherm.c
index bc028c7cda1f..f84e188f7f1f 100644
--- a/arch/arm/mach-tegra/tegra11_soctherm.c
+++ b/arch/arm/mach-tegra/tegra11_soctherm.c
@@ -837,6 +837,68 @@ int soctherm_get_mn_cpu_pskip_status(u8 *enabled, u8 *sw_override, u16 *m,
}
/**
+ * soctherm_has_gpu_pskip_status() - is GPU pskip state readable via SOC_THERM?
+ *
+ * If the currently-running SoC reports the GPU thermal throttling
+ * pulse skipper status via SOC_THERM registers, then return true;
+ * otherwise, return false. XXX Temporary - should be replaced by
+ * autodetection or DT properties/compatible flags.
+ *
+ * Return: true if GPU thermal pulse-skipper status is readable via
+ * SOC_THERM, or false if not.
+ */
+static int soctherm_has_gpu_pskip_status(void)
+{
+ return IS_T11X || IS_T14X;
+}
+
+/**
+ * soctherm_get_gpu_pskip_status() - read state of the GPU thermal pulse skipper
+ * @enabled: pointer to a u8: return 0 if the skipper is disabled, 1 if enabled
+ * @sw_override: ptr to a u8: return 0 if sw override is disabled, 1 if enabled
+ * @m: pointer to a u8 to return the current pulse skipper ratio numerator into
+ * @n: pointer to a u8 to return the current pulse skipper ratio denominator to
+ *
+ * Read the current status of the thermal throttling pulse skipper
+ * attached to the GPU clock, and return the status into the variables
+ * pointed to by @enabled, @sw_override, @m, and @n. Note that the M
+ * and N values are not what is stored in the register bitfields, but
+ * instead are the actual values used by the pulse skipper -- i.e., they
+ * are the bitfield values _plus one_; they have valid ranges of 1-256.
+ *
+ * Return: 0 upon success, -ENOTSUPP on chips with GPU-local
+ * throttling status (e.g., T124, T132) or -EINVAL if any of the
+ * arguments are NULL.
+ */
+int soctherm_get_gpu_pskip_status(u8 *enabled, u8 *sw_override, u16 *m, u16 *n)
+{
+ u32 v;
+
+ if (!enabled || !m || !n || !sw_override)
+ return -EINVAL;
+
+ /*
+ * XXX should be replaced with an earlier DT property read to
+ * determine the GPU type (or GPU->SOC_THERM integration) in
+ * use
+ */
+ if (!soctherm_has_gpu_pskip_status())
+ return -ENOTSUPP;
+
+ v = soctherm_readl(GPU_PSKIP_STATUS);
+ if (REG_GET(v, XPU_PSKIP_STATUS_ENABLED)) {
+ *enabled = 1;
+ *sw_override = REG_GET(v, XPU_PSKIP_STATUS_SW_OVERRIDE);
+ *m = REG_GET(v, XPU_PSKIP_STATUS_M) + 1;
+ *n = REG_GET(v, XPU_PSKIP_STATUS_N) + 1;
+ } else {
+ *enabled = 0;
+ }
+
+ return 0;
+}
+
+/**
* enforce_temp_range() - check and enforce temperature range [min, max]
* @trip_temp: The trip temperature to check
*
@@ -1173,6 +1235,62 @@ static int soctherm_get_cpu_throt_state(u16 dividend, u16 divisor,
}
/**
+ * soctherm_get_gpu_throt_state - read the current state of the GPU pulse skipper
+ * @dividend: pulse skipper numerator value to test against (1-256)
+ * @divisor: pulse skipper denominator value to test against (1-256)
+ * @cur_state: ptr to the variable that the current throttle state is stored in
+ *
+ * Determine the current state of the GPU thermal throttling pulse
+ * skipper, and if it's enabled and at its configured ending state,
+ * set the appropriate 'enabled' bit in the variable pointed to by
+ * @cur_state. This works on T114 and T148 by comparing @dividend and
+ * @divisor with the current state of the hardware - though note that
+ * @dividend and @divisor must be the actual dividend and divisor
+ * values. That is, they must be in 1-256 range, not the 0-255 range used
+ * by the hardware bitfields.
+ *
+ * Unfortunately, on T12x and T13x, the GPU manages its own thermal
+ * throttling, and does not report its state to the SOC_THERM IP
+ * block. So on those chips, this function will return an error.
+ *
+ * Return: 0 upon success, -ENOTSUPP on T12x and T13x, or -EINVAL if
+ * the arguments are invalid or out of range.
+ */
+static int soctherm_get_gpu_throt_state(u16 dividend, u16 divisor,
+ unsigned long *cur_state)
+{
+ u16 m, n;
+ u8 enabled, sw_override;
+ int r;
+
+ if (!cur_state || dividend == 0 || divisor == 0 ||
+ dividend > 256 || divisor > 256)
+ return -EINVAL;
+
+ /*
+ * XXX should be replaced with an earlier DT property read to
+ * determine the GPU type (or GPU->SOC_THERM integration) in
+ * use
+ */
+ if (!soctherm_has_gpu_pskip_status())
+ return -ENOTSUPP;
+
+ r = soctherm_get_gpu_pskip_status(&enabled, &sw_override, &m, &n);
+ if (r) {
+ WARN_ON(1);
+ return r;
+ }
+
+ if (!enabled)
+ return 0;
+
+ *cur_state |= (m == dividend && n == divisor) ?
+ (1 << THROTTLE_DEV_GPU) : 0;
+
+ return r;
+}
+
+/**
* soctherm_hw_action_get_cur_state() - get the current CPU/GPU throttling state
* @cdev: ptr to the struct thermal_cooling_device associated with SOC_THERM
* @cur_state: ptr to a variable to return the throttling state into
@@ -1189,8 +1307,7 @@ static int soctherm_hw_action_get_cur_state(struct thermal_cooling_device *cdev,
{
struct thermal_trip_info *trip_state = cdev->devdata;
struct soctherm_throttle_dev *devs;
- u32 r, m, n;
- int i;
+ int i, r;
if (!trip_state)
return 0;
@@ -1210,24 +1327,32 @@ static int soctherm_hw_action_get_cur_state(struct thermal_cooling_device *cdev,
devs->divisor + 1,
cur_state);
- r = soctherm_readl(GPU_PSKIP_STATUS);
devs = &plat_data.throttle[i].devs[THROTTLE_DEV_GPU];
- if (REG_GET(r, XPU_PSKIP_STATUS_ENABLED) && devs->enable) {
- m = REG_GET(r, XPU_PSKIP_STATUS_M);
- n = REG_GET(r, XPU_PSKIP_STATUS_N);
+ if (devs->enable) {
+ r = soctherm_get_gpu_throt_state(devs->dividend + 1,
+ devs->divisor + 1,
+ cur_state);
/*
- * On Tegra12x OC5 is a reserved alarm. Hence
- * GPU 'PSKIP' state always shows ON. The real
- * status register 'NV_THERM_CLK_STATUS' can't
- * be read safely. So we mirror the CPU status.
+ * On some chips, the GPU thermal throttling
+ * status isn't reported back to the SOC_THERM
+ * hardware. The ideal situation is for the
+ * GPU driver to register its own cooling
+ * device in that case; however, that code
+ * isn't implemented AFAIK. On those chips,
+ * Diwakar's preferred approach is for the GPU
+ * throttling status bit to follow the CPU
+ * throttling status bit, since that's the
+ * vendor- recommended thermal configuration.
+ * Diwakar notes: On Tegra12x OC5 is a
+ * reserved alarm. Hence GPU 'PSKIP' state
+ * always shows ON. The real status register
+ * 'NV_THERM_CLK_STATUS' can't be read safely
+ * [from this code - pjw]. So we mirror the
+ * CPU status.
*/
- *cur_state |=
- (IS_T12X || IS_T13X) ?
- ((*cur_state & (1 << THROTTLE_DEV_CPU)) ?
- (1 << THROTTLE_DEV_GPU) : 0) :
- ((m == devs->dividend && n == devs->divisor) ?
- (1 << THROTTLE_DEV_GPU) : 0);
- /* FIXME: For T132 switch to Denver:CCROC NV_THERM style status */
+ if (r == -ENOTSUPP)
+ if (*cur_state & (1 << THROTTLE_DEV_CPU))
+ *cur_state |= (1 << THROTTLE_DEV_GPU);
}
}