summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/nvrm/core
diff options
context:
space:
mode:
authorGary King <gking@nvidia.com>2009-12-16 13:38:41 -0800
committerGary King <gking@nvidia.com>2009-12-16 19:27:26 -0800
commit1accf09674a3a36463bc7f15212b14de92e5ae86 (patch)
treeedea1b4bfb72aba386b819b95b84cc83a069630e /arch/arm/mach-tegra/nvrm/core
parente2d05b4f4cb28a6e66236bc814f01e74d2466121 (diff)
tegra: implement thermal throttling algorithm for AP20
limits CPU frequency increases to at most 200MHz when temperature < 50C limits CPU frequency increases to at most 100MHz when temperature < 85C reduces CPU frequency to min of 500MHz or 100MHz less than current freq when temperature > 85C
Diffstat (limited to 'arch/arm/mach-tegra/nvrm/core')
-rw-r--r--arch/arm/mach-tegra/nvrm/core/ap20/ap20rm_power_dfs.c256
-rw-r--r--arch/arm/mach-tegra/nvrm/core/ap20/ap20rm_power_dfs.h33
-rw-r--r--arch/arm/mach-tegra/nvrm/core/common/nvrm_power_dfs.c145
-rw-r--r--arch/arm/mach-tegra/nvrm/core/common/nvrm_power_dfs.h32
4 files changed, 287 insertions, 179 deletions
diff --git a/arch/arm/mach-tegra/nvrm/core/ap20/ap20rm_power_dfs.c b/arch/arm/mach-tegra/nvrm/core/ap20/ap20rm_power_dfs.c
index b1c0b38251c4..8bc72a4c2928 100644
--- a/arch/arm/mach-tegra/nvrm/core/ap20/ap20rm_power_dfs.c
+++ b/arch/arm/mach-tegra/nvrm/core/ap20/ap20rm_power_dfs.c
@@ -167,134 +167,179 @@ NvRmPrivAp20EmcMonitorsRead(
// AP20 Thermal policy definitions
-#define NVRM_THERMAL_DEGREES_HIGH (85L)
-#define NVRM_THERMAL_DEGREES_LOW (50L)
-#define NVRM_THERMAL_DEGREES_HYSTERESIS (5L)
+#define NVRM_DTT_DEGREES_HIGH (85L)
+#define NVRM_DTT_DEGREES_LOW (60L)
+#define NVRM_DTT_DEGREES_HYSTERESIS (5L)
-#define NVRM_THERMAL_POLL_MS_SLOW (200UL)
-#define NVRM_THERMAL_POLL_MS_FAST (100UL)
-#define NVRM_THERMAL_POLL_MS_CRITICAL (50UL)
-#define NVRM_THERMAL_POLL_INTR_FACTOR (10UL)
+#define NVRM_DTT_VOLTAGE_THROTTLE_MV (900UL)
+#define NVRM_DTT_CPU_DELTA_KHZ (100000UL)
-#define NVRM_THERMAL_CPU_KHZ_LOW (500000UL)
+#define NVRM_DTT_POLL_MS_SLOW (2000UL)
+#define NVRM_DTT_POLL_MS_FAST (1000UL)
+#define NVRM_DTT_POLL_MS_CRITICAL (500UL)
-#define NVRM_THERMAL_CPU_DELTA_KHZ_LOW (200000L)
-#define NVRM_THERMAL_CPU_DELTA_KHZ_HIGH (100000L)
-#define NVRM_THERMAL_CPU_DELTA_KHZ_CRITICAL (-100000L)
+typedef enum
+{
+ NvRmDttAp20PolicyRange_Unknown = 0,
+
+ // No throttling
+ NvRmDttAp20PolicyRange_FreeRunning,
+
+ // Keep CPU frequency below low voltage threshold
+ NvRmDttAp20PolicyRange_LimitVoltage,
+
+ // Decrease CPU frequency in steps over time
+ NvRmDttAp20PolicyRange_ThrottleDown,
+
+ NvRmDttAp20PolicyRange_Num,
+ NvRmDttAp20PolicyRange_Force32 = 0x7FFFFFFFUL
+} NvRmDttAp20PolicyRange;
+
+static NvRmFreqKHz s_CpuThrottleMaxKHz = 0;
+static NvRmFreqKHz s_CpuThrottleMinKHz = 0;
+static NvRmFreqKHz s_CpuThrottleKHz = 0;
void
-NvRmPrivAp20DttGetTcorePolicy(
+NvRmPrivAp20DttPolicyUpdate(
+ NvRmDeviceHandle hRmDevice,
NvS32 TemperatureC,
- const NvRmDtt* pDtt,
- NvS32* pLowLimit,
- NvS32* pHighLimit,
- NvU32* pPollMs)
+ NvRmDtt* pDtt)
{
- NvU32 msec;
- NvS32 LowLimit, HighLimit;
-
- NV_ASSERT(pDtt->TcoreCaps.Tmin <
- (NVRM_THERMAL_DEGREES_LOW - NVRM_THERMAL_DEGREES_HYSTERESIS));
- NV_ASSERT(pDtt->TcoreCaps.Tmax > NVRM_THERMAL_DEGREES_HIGH);
+ NvRmDttAp20PolicyRange Range;
- /*
- * Temperature limits policy: limits are laways set "around" current
- * temperature for the next out-of-limit interrupt; range boundaries
- * are used for low and critical temperature.
- */
- if (TemperatureC <= NVRM_THERMAL_DEGREES_LOW)
+ // CPU throttling limits are set at 50% of CPU frequency range (no
+ // throttling below this value), and at CPU frequency boundary that
+ // matches specified voltage throttling limit.
+ if ((!s_CpuThrottleMaxKHz) || (!s_CpuThrottleMinKHz))
{
- LowLimit = pDtt->TcoreLowLimitCaps.MinValue;
- HighLimit = NVRM_THERMAL_DEGREES_LOW;
+ NvU32 steps;
+ const NvRmFreqKHz* p = NvRmPrivModuleVscaleGetMaxKHzList(
+ hRmDevice, NvRmModuleID_Cpu, &steps);
+ NV_ASSERT(p && steps);
+ for (; steps != 0 ; steps--)
+ {
+ if (NVRM_DTT_VOLTAGE_THROTTLE_MV >= NvRmPrivModuleVscaleGetMV(
+ hRmDevice, NvRmModuleID_Cpu, p[steps-1]))
+ break;
+ }
+ NV_ASSERT(steps);
+ s_CpuThrottleMaxKHz = p[steps-1];
+ s_CpuThrottleMinKHz =
+ NvRmPrivGetSocClockLimits(NvRmModuleID_Cpu)->MaxKHz / 2;
+ NV_ASSERT(s_CpuThrottleMaxKHz > s_CpuThrottleMinKHz);
+ NV_ASSERT(s_CpuThrottleMinKHz > NVRM_DTT_CPU_DELTA_KHZ);
+
+ s_CpuThrottleKHz = s_CpuThrottleMaxKHz;
+
+ NV_ASSERT(pDtt->TcoreCaps.Tmin <
+ (NVRM_DTT_DEGREES_LOW - NVRM_DTT_DEGREES_HYSTERESIS));
+ NV_ASSERT(pDtt->TcoreCaps.Tmax > NVRM_DTT_DEGREES_HIGH);
}
- else if (TemperatureC <= NVRM_THERMAL_DEGREES_HIGH)
- {
- LowLimit = NVRM_THERMAL_DEGREES_LOW - NVRM_THERMAL_DEGREES_HYSTERESIS;
- HighLimit = NVRM_THERMAL_DEGREES_HIGH;
- }
- else
+ // Advanced policy range state machine (one step at a time)
+ Range = (NvRmDttAp20PolicyRange)pDtt->TcorePolicy.PolicyRange;
+ switch (Range)
{
- LowLimit = NVRM_THERMAL_DEGREES_HIGH - NVRM_THERMAL_DEGREES_HYSTERESIS;
- HighLimit = pDtt->TcoreHighLimitCaps.MaxValue;
+ case NvRmDttAp20PolicyRange_Unknown:
+ Range = NvRmDttAp20PolicyRange_FreeRunning;
+ // fall through
+ case NvRmDttAp20PolicyRange_FreeRunning:
+ if (TemperatureC >= NVRM_DTT_DEGREES_LOW)
+ Range = NvRmDttAp20PolicyRange_LimitVoltage;
+ break;
+
+ case NvRmDttAp20PolicyRange_LimitVoltage:
+ if (TemperatureC <=
+ (NVRM_DTT_DEGREES_LOW - NVRM_DTT_DEGREES_HYSTERESIS))
+ Range = NvRmDttAp20PolicyRange_FreeRunning;
+ else if (TemperatureC >= NVRM_DTT_DEGREES_HIGH)
+ Range = NvRmDttAp20PolicyRange_ThrottleDown;
+ break;
+
+ case NvRmDttAp20PolicyRange_ThrottleDown:
+ if (TemperatureC <=
+ (NVRM_DTT_DEGREES_HIGH - NVRM_DTT_DEGREES_HYSTERESIS))
+ Range = NvRmDttAp20PolicyRange_LimitVoltage;
+ break;
+
+ default:
+ break;
}
/*
- * Polling time policy:
- * - low/high temperature in polling mode: return policy value
- * - low/high temperature in interrupt mode: policy value increased by intr
- * factor (do not need polling at all in this mode, but just in case ...)
- * - critical temperature and any mode: return policy value (we do need
- * polling even in interrupt mode for active throttling)
- * Keep higher polling rate inside hysteresis range.
+ * Fill in new policy. Temperature limits are set around current
+ * temperature for the next out-of-limit interrupt (possible exception
+ * - temperature "jump" over two ranges would result in two interrupts
+ * in a row before limits cover the temperature). Polling time is set
+ * always in ThrottleDown range, and only for poll mode in other ranges.
*/
- if (TemperatureC <=
- (NVRM_THERMAL_DEGREES_LOW - NVRM_THERMAL_DEGREES_HYSTERESIS))
- {
- if (pDtt->UseIntr)
- msec = NVRM_THERMAL_POLL_MS_SLOW * NVRM_THERMAL_POLL_INTR_FACTOR;
- else
- msec = NVRM_THERMAL_POLL_MS_SLOW;
- }
- else if (TemperatureC <=
- (NVRM_THERMAL_DEGREES_HIGH - NVRM_THERMAL_DEGREES_HYSTERESIS))
+ pDtt->CoreTemperatureC = TemperatureC;
+ switch (Range)
{
- if (pDtt->UseIntr)
- msec = NVRM_THERMAL_POLL_MS_FAST * NVRM_THERMAL_POLL_INTR_FACTOR;
- else
- msec = NVRM_THERMAL_POLL_MS_FAST;
+ case NvRmDttAp20PolicyRange_FreeRunning:
+ pDtt->TcorePolicy.LowLimit = pDtt->TcoreLowLimitCaps.MinValue;
+ pDtt->TcorePolicy.HighLimit = NVRM_DTT_DEGREES_LOW;
+ pDtt->TcorePolicy.UpdateIntervalUs = pDtt->UseIntr ?
+ NV_WAIT_INFINITE : (NVRM_DTT_POLL_MS_SLOW * 1000);
+ break;
- }
- else
- {
- msec = NVRM_THERMAL_POLL_MS_CRITICAL;
- }
+ case NvRmDttAp20PolicyRange_LimitVoltage:
+ pDtt->TcorePolicy.LowLimit =
+ NVRM_DTT_DEGREES_LOW - NVRM_DTT_DEGREES_HYSTERESIS;
+ pDtt->TcorePolicy.HighLimit = NVRM_DTT_DEGREES_HIGH;
+ pDtt->TcorePolicy.UpdateIntervalUs = pDtt->UseIntr ?
+ NV_WAIT_INFINITE : (NVRM_DTT_POLL_MS_FAST * 1000);
+ break;
+
+ case NvRmDttAp20PolicyRange_ThrottleDown:
+ pDtt->TcorePolicy.LowLimit =
+ NVRM_DTT_DEGREES_HIGH - NVRM_DTT_DEGREES_HYSTERESIS;
+ pDtt->TcorePolicy.HighLimit = pDtt->TcoreHighLimitCaps.MaxValue;
+ pDtt->TcorePolicy.UpdateIntervalUs = NVRM_DTT_POLL_MS_CRITICAL * 1000;
+ break;
- // Fill in return values
- *pLowLimit = LowLimit;
- *pHighLimit = HighLimit;
- *pPollMs = msec;
+ default:
+ NV_ASSERT(!"Invalid DTT policy range");
+ NvOsDebugPrintf("DTT: Invalid Range = %d\n", Range);
+ pDtt->TcorePolicy.HighLimit = ODM_TMON_PARAMETER_UNSPECIFIED;
+ pDtt->TcorePolicy.LowLimit = ODM_TMON_PARAMETER_UNSPECIFIED;
+ pDtt->TcorePolicy.PolicyRange = NvRmDttAp20PolicyRange_Unknown;
+ return;
+ }
+ pDtt->TcorePolicy.PolicyRange = (NvU32)Range;
}
+
NvBool
NvRmPrivAp20DttClockUpdate(
NvRmDeviceHandle hRmDevice,
NvS32 TemperatureC,
+ const NvRmTzonePolicy* pDttPolicy,
const NvRmDfsFrequencies* pCurrentKHz,
NvRmDfsFrequencies* pDfsKHz)
{
- // Only CPU throttling for now
- NvRmFreqKHz DeltaKHz;
- NvRmFreqKHz CpuTargetKHz = pDfsKHz->Domains[NvRmDfsClockId_Cpu];
- NvRmFreqKHz CpuThrottledKHz = pCurrentKHz->Domains[NvRmDfsClockId_Cpu];
- NvBool Throttled = NV_FALSE;
-
- // If CPU target is already low, no throttling
- if (CpuTargetKHz <= NVRM_THERMAL_CPU_KHZ_LOW)
- return Throttled;
-
- // Determine max frequency delta based on temperature
- if (TemperatureC <= NVRM_THERMAL_DEGREES_LOW)
- DeltaKHz = NVRM_THERMAL_CPU_DELTA_KHZ_LOW;
- else if (TemperatureC <= NVRM_THERMAL_DEGREES_HIGH)
- DeltaKHz = NVRM_THERMAL_CPU_DELTA_KHZ_HIGH;
- else
- DeltaKHz = NVRM_THERMAL_CPU_DELTA_KHZ_CRITICAL;
-
- // Find throttled limit
- CpuThrottledKHz += DeltaKHz;
- if (((NvS32)CpuThrottledKHz) < 0)
- CpuThrottledKHz = 0;
-
- // Find and set new target
- CpuTargetKHz = NV_MIN(CpuTargetKHz, CpuThrottledKHz);
- CpuTargetKHz = NV_MAX(CpuTargetKHz, NVRM_THERMAL_CPU_KHZ_LOW);
- if (CpuTargetKHz < pDfsKHz->Domains[NvRmDfsClockId_Cpu])
+ switch ((NvRmDttAp20PolicyRange)pDttPolicy->PolicyRange)
{
- Throttled = NV_TRUE;
+ case NvRmDttAp20PolicyRange_LimitVoltage:
+ s_CpuThrottleKHz = s_CpuThrottleMaxKHz;
+ break;
+
+ case NvRmDttAp20PolicyRange_ThrottleDown:
+ if (pDttPolicy->UpdateFlag)
+ s_CpuThrottleKHz -= NVRM_DTT_CPU_DELTA_KHZ;
+ s_CpuThrottleKHz = NV_MAX(s_CpuThrottleKHz, s_CpuThrottleMinKHz);
+ break;
+
+ // No throttling by default (just reset throttling limit to max)
+ default:
+ s_CpuThrottleKHz = s_CpuThrottleMaxKHz;
+ return NV_FALSE;
}
- pDfsKHz->Domains[NvRmDfsClockId_Cpu] = CpuTargetKHz;
- return Throttled;
+ pDfsKHz->Domains[NvRmDfsClockId_Cpu] =
+ NV_MIN(pDfsKHz->Domains[NvRmDfsClockId_Cpu], s_CpuThrottleKHz);
+
+ // Throttling step is completed - no need to force extra DVFS update
+ return NV_FALSE;
}
/*****************************************************************************/
@@ -308,13 +353,14 @@ NvRmPrivAp20GetPmRequest(
// Assume initial slave CPU1 On request
static NvRmPmRequest s_LastPmRequest = (NvRmPmRequest_CpuOnFlag | 0x1);
static NvRmFreqKHz s_Cpu1OnMinKHz = 0, s_Cpu1OffMaxKHz = 0;
+ static NvU32 s_Cpu1OnPendingCnt = 0, s_Cpu1OffPendingCnt = 0;
NvRmPmRequest PmRequest = NvRmPmRequest_None;
NvBool Cpu1Off =
(0 != NV_DRF_VAL(CLK_RST_CONTROLLER, RST_CPU_CMPLX_SET, SET_CPURESET1,
NV_REGR(hRmDevice, NvRmPrivModuleID_ClockAndReset, 0,
CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET_0)));
- NvRmFreqKHz CpuLoadGaugeKHz = pCpuSampler->BumpedAverageKHz;
+ NvRmFreqKHz CpuLoadGaugeKHz = CpuKHz;
// Slave CPU1 power management policy thresholds:
// - use fixed values if they are defined explicitly, otherwise
@@ -347,6 +393,12 @@ NvRmPrivAp20GetPmRequest(
*/
if (CpuLoadGaugeKHz < s_Cpu1OnMinKHz)
{
+ s_Cpu1OnPendingCnt = 0;
+ if (s_Cpu1OffPendingCnt < NVRM_CPU1_OFF_PENDING_CNT)
+ {
+ s_Cpu1OffPendingCnt++;
+ return PmRequest;
+ }
if ((s_LastPmRequest & NvRmPmRequest_CpuOnFlag) && (!Cpu1Off))
s_LastPmRequest = PmRequest = (NvRmPmRequest_CpuOffFlag | 0x1);
#if NVRM_TEST_PMREQUEST_UP_MODE
@@ -357,6 +409,12 @@ NvRmPrivAp20GetPmRequest(
}
else if (CpuLoadGaugeKHz > s_Cpu1OffMaxKHz)
{
+ s_Cpu1OffPendingCnt = 0;
+ if (s_Cpu1OnPendingCnt < NVRM_CPU1_ON_PENDING_CNT)
+ {
+ s_Cpu1OnPendingCnt++;
+ return PmRequest;
+ }
if ((s_LastPmRequest & NvRmPmRequest_CpuOffFlag) && Cpu1Off)
s_LastPmRequest = PmRequest = (NvRmPmRequest_CpuOnFlag | 0x1);
#if NVRM_TEST_PMREQUEST_UP_MODE
diff --git a/arch/arm/mach-tegra/nvrm/core/ap20/ap20rm_power_dfs.h b/arch/arm/mach-tegra/nvrm/core/ap20/ap20rm_power_dfs.h
index 685d04568d27..795b1a8a7d54 100644
--- a/arch/arm/mach-tegra/nvrm/core/ap20/ap20rm_power_dfs.h
+++ b/arch/arm/mach-tegra/nvrm/core/ap20/ap20rm_power_dfs.h
@@ -210,14 +210,19 @@ extern "C"
/**
* Defines CPU frequency threshold for slave CPU1 power management:
- * - CPU1 is turned Off when cpu clock is below ON_MIN
- * - CPU1 is turned On when cpu clock is above OFF_MAX
- * If set to 0, the threshold value is derived at run time from the
+ * - CPU1 is turned Off when cpu clock is below ON_MIN for
+ * ON_PENDING DFS ticks (10ms) in a row
+ * - CPU1 is turned On when cpu clock is above OFF_MAX for
+ * OFF_PENDING DFS ticks (10ms) in a row
+ * If thresholds are set to 0, the values are derived at run time from the
* characterization data
*/
#define NVRM_CPU1_ON_MIN_KHZ (0)
#define NVRM_CPU1_OFF_MAX_KHZ (0)
+#define NVRM_CPU1_ON_PENDING_CNT (250)
+#define NVRM_CPU1_OFF_PENDING_CNT (100)
+
/// Default low corners for core and dedicated CPU voltages
#define NVRM_AP20_LOW_CORE_MV (1200)
#define NVRM_AP20_LOW_CPU_MV (850)
@@ -287,41 +292,37 @@ NvRmPrivAp20DvsChangeCoreVoltage(
NvRmMilliVolts TargetMv);
/**
- * Determines temperature monitoring policy.
+ * Updates thermal policy according to current temperature.
*
+ * @param hRmDevice The RM device handle.
* @param TemperatureC Current core temperature in degrees C.
* @param pDtt A pointer to dynamic thermal throttling structure.
- * @param pLowLimit A pointer to the returned variable with low boundary for
- * temperature out-of-limit interrupt.
- * @param pHighLimit A pointer to the returned variable with high boundary for
- * temperature out-of-limit interrupt.
- * @param pPollMs A pointer to the returned variable with temperature polling
- * interval in milliseconds.
*/
void
-NvRmPrivAp20DttGetTcorePolicy(
+NvRmPrivAp20DttPolicyUpdate(
+ NvRmDeviceHandle hRmDevice,
NvS32 TemperatureC,
- const NvRmDtt* pDtt,
- NvS32* pLowLimit,
- NvS32* pHighLimit,
- NvU32* pPollMs);
+ NvRmDtt* pDt);
/**
* Throttles DFS target clocks.
*
* @param hRmDevice The RM device handle.
* @param TemperatureC Current core temperature in degrees C.
+ * @param pPolicy A pointer to current throttling policy.
* @param pCurrentKHz A pointer to current DFS clock frequencies structure.
* @param pDfsKHz A pointer to DFS clock structure with target frequencies
* on entry, and throttled frequencies on exit.
*
- * @return NV_TRUE if target clocks were throttled, and NV_FALSE otherwise.
+ * @return NV_TRUE if throttling requires additional DVFS scaling steps,
+ * and NV_FALSE otherwise.
*/
NvBool
NvRmPrivAp20DttClockUpdate(
NvRmDeviceHandle hRmDevice,
NvS32 TemperatureC,
+ const NvRmTzonePolicy* pDttPolicy,
const NvRmDfsFrequencies* pCurrentKHz,
NvRmDfsFrequencies* pDfsKHz);
diff --git a/arch/arm/mach-tegra/nvrm/core/common/nvrm_power_dfs.c b/arch/arm/mach-tegra/nvrm/core/common/nvrm_power_dfs.c
index a154209139bd..6bba8ab0f129 100644
--- a/arch/arm/mach-tegra/nvrm/core/common/nvrm_power_dfs.c
+++ b/arch/arm/mach-tegra/nvrm/core/common/nvrm_power_dfs.c
@@ -73,10 +73,10 @@
// An option to stall average accumulation during busy pulse
#define NVRM_DFS_STALL_AVERAGE_IN_BUSY_PULSE (0)
-// TODO: keep disabled until AP20 bring-up
-// Options for temperature monitoring interrupt
-#define NVRM_DTT_DISABLED (1)
-#define NVRM_DTT_USE_INTERRUPT (0)
+// Options for temperature monitoring
+#define NVRM_DTT_DISABLED (0)
+#define NVRM_DTT_USE_INTERRUPT (1)
+#define NVRM_DTT_RANGE_CHANGE_PRINTF (1)
/*****************************************************************************/
@@ -450,16 +450,14 @@ static void NvRmPrivDvsRun(void);
static void NvRmPrivDvsStopAtNominal(void);
/*
- * Gets core temperature monitoring limits and polling time according
- * to chip specific policy.
+ * Updates thermal state and temperature monitoring policies according
+ * to the new sampled temperature.
*/
static void
-DttGetTcorePolicy(
+DttPolicyUpdate(
+ NvRmDeviceHandle hRm,
NvS32 TemperatureC,
- const NvRmDfs* pDfs,
- NvS32* pLowLimit,
- NvS32* pHighLimit,
- NvU32* pPollMs);
+ NvRmDtt* pDtt);
/*
* Updates (throttles) target DFS frequencies based on SoC temperature.
@@ -1007,11 +1005,11 @@ DfsGetTargetFrequencies(
// Update thermal throttling polling control
if (!NVRM_DTT_DISABLED && pDfs->ThermalThrottler.hOdmTcore)
{
- if (pDfs->ThermalThrottler.RdIntervalUs <
- (usec - pDfs->ThermalThrottler.RdTimeUs))
+ if (pDfs->ThermalThrottler.TcorePolicy.UpdateIntervalUs <
+ (usec - pDfs->ThermalThrottler.TcorePolicy.TimeUs))
{
- pDfs->ThermalThrottler.RdTimeUs = usec;
- pDfs->ThermalThrottler.UpdateFlag = NV_TRUE;
+ pDfs->ThermalThrottler.TcorePolicy.TimeUs = usec;
+ pDfs->ThermalThrottler.TcorePolicy.UpdateFlag = NV_TRUE;
}
}
@@ -1321,7 +1319,7 @@ static void DfsIsr(void* args)
ClockChange = DfsGetTargetFrequencies(&IdleData, pDfs, &DfsKHz);
pDfs->TargetKHz = DfsKHz;
ClockChange = ClockChange || pDfs->VoltageScaler.UpdateFlag ||
- pDfs->ThermalThrottler.UpdateFlag;
+ pDfs->ThermalThrottler.TcorePolicy.UpdateFlag;
}
DfsProfileSample(pDfs, NvRmDfsProfileId_Algorithm);
DfsLogEnter(pDfs, IdleData.Lp2TimeMs);
@@ -1515,13 +1513,13 @@ static NvRmPmRequest DfsThread(NvRmDfs* pDfs)
// Configure DFS clocks and update current frequencies if necessary
// (do not touch clocks and voltage if DVS is stopped)
if (NeedClockUpdate || pDfs->VoltageScaler.UpdateFlag ||
- pDfs->ThermalThrottler.UpdateFlag)
+ pDfs->ThermalThrottler.TcorePolicy.UpdateFlag)
{
NvRmPrivLockSharedPll();
if (!pDfs->VoltageScaler.StopFlag)
{
// Check temperature and throttle DFS clocks if necessry. Make
- // sure V/F scaling is running while throotling is in progress.
+ // sure V/F scaling is running while throttling is in progress.
pDfs->VoltageScaler.UpdateFlag =
DttClockUpdate(pDfs, &pDfs->ThermalThrottler, &DfsKHz);
LastKHz = DfsKHz;
@@ -1692,25 +1690,37 @@ DfsClipCpuEmcHighLimits(
/*****************************************************************************/
static void
-DttGetTcorePolicy(
+DttPolicyUpdate(
+ NvRmDeviceHandle hRm,
NvS32 TemperatureC,
- const NvRmDfs* pDfs,
- NvS32* pLowLimit,
- NvS32* pHighLimit,
- NvU32* pPollMs)
+ NvRmDtt* pDtt)
{
- if (pDfs->hRm->ChipId.Id == 0x20)
+ NvU32 Range = pDtt->TcorePolicy.PolicyRange;
+
+ if (hRm->ChipId.Id == 0x20)
{
- NvRmPrivAp20DttGetTcorePolicy(TemperatureC, &pDfs->ThermalThrottler,
- pLowLimit, pHighLimit, pPollMs);
- NV_ASSERT(*pLowLimit != ODM_TMON_PARAMETER_UNSPECIFIED);
- NV_ASSERT(*pHighLimit != ODM_TMON_PARAMETER_UNSPECIFIED);
- return;
+ NvRmPrivAp20DttPolicyUpdate(hRm, TemperatureC, pDtt);
+ NV_ASSERT(pDtt->TcorePolicy.LowLimit !=
+ ODM_TMON_PARAMETER_UNSPECIFIED);
+ NV_ASSERT(pDtt->TcorePolicy.HighLimit !=
+ ODM_TMON_PARAMETER_UNSPECIFIED);
+ }
+ else
+ {
+ // No thermal policy (= do nothing) for this SoC
+ pDtt->TcorePolicy.LowLimit = ODM_TMON_PARAMETER_UNSPECIFIED;
+ pDtt->TcorePolicy.HighLimit = ODM_TMON_PARAMETER_UNSPECIFIED;
+ pDtt->TcorePolicy.UpdateIntervalUs = NV_WAIT_INFINITE;
+ pDtt->TcorePolicy.PolicyRange = 0;
+ }
+ if (pDtt->UseIntr || (pDtt->TcorePolicy.PolicyRange != Range))
+ {
+#if NVRM_DTT_RANGE_CHANGE_PRINTF
+ NvOsDebugPrintf("DTT: T = %d, Range = %d (%d : %d)\n",
+ TemperatureC, pDtt->TcorePolicy.PolicyRange,
+ pDtt->TcorePolicy.LowLimit, pDtt->TcorePolicy.HighLimit);
+#endif
}
- // Default 1-second polling policy
- *pLowLimit = ODM_TMON_PARAMETER_UNSPECIFIED;
- *pHighLimit = ODM_TMON_PARAMETER_UNSPECIFIED;
- *pPollMs = 1000;
}
static NvBool
@@ -1719,24 +1729,27 @@ DttClockUpdate(
NvRmDtt* pDtt,
NvRmDfsFrequencies* pDfsKHz)
{
- NvU32 msec;
NvS32 TemperatureC;
NvS32 LowLimit, HighLimit;
+ NvRmTzonePolicy Policy;
// Check if thermal throttling is supported
if (NVRM_DTT_DISABLED || (!pDtt->hOdmTcore))
return NV_FALSE;
// Update temperature
- if (pDtt->UpdateFlag &&
+ if (pDtt->TcorePolicy.UpdateFlag &&
NvOdmTmonTemperatureGet(pDtt->hOdmTcore, &TemperatureC))
{
// Register TMON interrupt, if it is supported by device, and chip
// policy, but has not been registered yet. Set initial temperature
// limits according to chip specific policy.
- if (pDtt->UseIntr && !pDtt->hOdmTcoreIntr)
+ if (pDtt->UseIntr && !pDtt->hOdmTcoreIntr &&
+ NvOdmTmonTemperatureGet(pDtt->hOdmTcore, &TemperatureC))
{
- DttGetTcorePolicy(TemperatureC, pDfs, &LowLimit, &HighLimit, &msec);
+ DttPolicyUpdate(pDfs->hRm, TemperatureC, pDtt);
+ LowLimit = pDtt->TcorePolicy.LowLimit;
+ HighLimit = pDtt->TcorePolicy.HighLimit;
if ((LowLimit != ODM_TMON_PARAMETER_UNSPECIFIED) &&
(HighLimit != ODM_TMON_PARAMETER_UNSPECIFIED))
{
@@ -1754,28 +1767,43 @@ DttClockUpdate(
}
// Update temperature monitoring policy
- DttGetTcorePolicy(TemperatureC, pDfs, &LowLimit, &HighLimit, &msec);
- NvOsIntrMutexLock(pDfs->hIntrMutex);
- pDtt->CoreTemperatureC = TemperatureC;
- pDtt->RdIntervalUs = msec * 1000;
+ if (!pDtt->UseIntr &&
+ NvOdmTmonTemperatureGet(pDtt->hOdmTcore, &TemperatureC))
+ {
+ NvOsIntrMutexLock(pDfs->hIntrMutex);
+ DttPolicyUpdate(pDfs->hRm, TemperatureC, pDtt);
+ Policy = pDtt->TcorePolicy;
+ }
+ else
+ {
+ NvOsIntrMutexLock(pDfs->hIntrMutex);
+ Policy = pDtt->TcorePolicy;
+ TemperatureC = pDtt->CoreTemperatureC;
+ }
if (pDfs->DfsRunState > NvRmDfsRunState_Stopped)
{
- pDtt->UpdateFlag = NV_FALSE;
+ pDtt->TcorePolicy.UpdateFlag = NV_FALSE;
}
NvOsIntrMutexUnlock(pDfs->hIntrMutex);
}
+ else
+ {
+ NvOsIntrMutexLock(pDfs->hIntrMutex);
+ Policy = pDtt->TcorePolicy;
+ TemperatureC = pDtt->CoreTemperatureC;
+ NvOsIntrMutexUnlock(pDfs->hIntrMutex);
+ }
// Throttle clock frequencies, if necessary
if (pDfs->hRm->ChipId.Id == 0x20)
return NvRmPrivAp20DttClockUpdate(
- pDfs->hRm, pDtt->CoreTemperatureC, &pDfs->CurrentKHz, pDfsKHz);
+ pDfs->hRm, TemperatureC, &Policy, &pDfs->CurrentKHz, pDfsKHz);
else
return NV_FALSE; // No throttling policy for this chip ID
}
static void DttIntrCallback(void* args)
{
- NvU32 msec;
NvS32 TemperatureC = 0;
NvS32 LowLimit = ODM_TMON_PARAMETER_UNSPECIFIED;
NvS32 HighLimit = ODM_TMON_PARAMETER_UNSPECIFIED;
@@ -1784,19 +1812,21 @@ static void DttIntrCallback(void* args)
if (NvOdmTmonTemperatureGet(pDtt->hOdmTcore, &TemperatureC))
{
- DttGetTcorePolicy(TemperatureC, pDfs, &LowLimit, &HighLimit, &msec);
- NV_ASSERT(LowLimit != ODM_TMON_PARAMETER_UNSPECIFIED);
- NV_ASSERT(HighLimit != ODM_TMON_PARAMETER_UNSPECIFIED);
+ NvOsIntrMutexLock(pDfs->hIntrMutex);
+ DttPolicyUpdate(pDfs->hRm, TemperatureC, pDtt);
+ LowLimit = pDtt->TcorePolicy.LowLimit;
+ HighLimit = pDtt->TcorePolicy.HighLimit;
+ pDtt->TcorePolicy.UpdateFlag = NV_TRUE;
+ NvOsIntrMutexUnlock(pDfs->hIntrMutex);
// Clear interrupt condition by setting new limits "around" temperature
+ NV_ASSERT(LowLimit != ODM_TMON_PARAMETER_UNSPECIFIED);
+ NV_ASSERT(HighLimit != ODM_TMON_PARAMETER_UNSPECIFIED);
(void)NvOdmTmonParameterConfig(pDtt->hOdmTcore,
NvOdmTmonConfigParam_IntrLimitLow, &LowLimit);
- (void)NvOdmTmonParameterConfig(pDtt->hOdmTcore,
+ (void)NvOdmTmonParameterConfig(pDtt->hOdmTcore,
NvOdmTmonConfigParam_IntrLimitHigh, &HighLimit);
}
- NvOsIntrMutexLock(pDfs->hIntrMutex);
- pDtt->UpdateFlag = NV_TRUE;
- NvOsIntrMutexUnlock(pDfs->hIntrMutex);
NVRM_DFS_PRINTF(("Dtt Intr: T = %d, LowLimit = %d, HighLimit = %d\n",
TemperatureC, LowLimit, HighLimit));
@@ -2529,10 +2559,10 @@ void NvRmPrivDttInit(NvRmDeviceHandle hRmDeviceHandle)
if (!pDtt->hOdmTcore)
{
- // TODO: uncomment after AP20 bring-up
if (pDfs->hRm->ChipId.Id == 0x20)
{
- // NV_ASSERT(!"TMON is a must on AP20 platform");
+ // TODO: assert?
+ NvOsDebugPrintf("DTT: TMON initialization failed\n");
}
return;
}
@@ -2542,6 +2572,12 @@ void NvRmPrivDttInit(NvRmDeviceHandle hRmDeviceHandle)
NvOdmTmonParameterCapsGet(pDtt->hOdmTcore,
NvOdmTmonConfigParam_IntrLimitHigh, &pDtt->TcoreHighLimitCaps);
+#if !NVRM_DTT_DISABLED
+ // Default policy for room temperature
+ DttPolicyUpdate(hRmDeviceHandle, 25, pDtt);
+ pDtt->TcorePolicy.TimeUs = NvRmPrivGetUs();
+#endif
+
if (pDtt->TcoreCaps.IntrSupported &&
!pDtt->TcoreLowLimitCaps.OdmProtected &&
!pDtt->TcoreHighLimitCaps.OdmProtected)
@@ -2556,9 +2592,6 @@ void NvRmPrivDttInit(NvRmDeviceHandle hRmDeviceHandle)
pDtt->UseIntr = NV_TRUE;
#endif
}
-#if !NVRM_DTT_DISABLED
- pDtt->UpdateFlag = NV_TRUE;
-#endif
}
void NvRmPrivDttDeinit()
diff --git a/arch/arm/mach-tegra/nvrm/core/common/nvrm_power_dfs.h b/arch/arm/mach-tegra/nvrm/core/common/nvrm_power_dfs.h
index 21d7c9e52765..65137c83a8ce 100644
--- a/arch/arm/mach-tegra/nvrm/core/common/nvrm_power_dfs.h
+++ b/arch/arm/mach-tegra/nvrm/core/common/nvrm_power_dfs.h
@@ -408,6 +408,28 @@ typedef struct NvRmDvsRec
} NvRmDvs;
/**
+ * RM thermal zone policy
+ */
+typedef struct NvRmTzonePolicyRec
+{
+ // Request policy update
+ volatile NvBool UpdateFlag;
+
+ // Last policy update request time stamp
+ NvU32 TimeUs;
+
+ // Update period (NV_WAIT_INFINITE is allowed in interrupt mode)
+ NvU32 UpdateIntervalUs;
+
+ // Out of limit interrupt boundaries
+ NvS32 LowLimit;
+ NvS32 HighLimit;
+
+ // Policy range
+ NvU32 PolicyRange;
+} NvRmTzonePolicy;
+
+/**
* Combines status and control information for dynamic thermal throttling
*/
typedef struct NvRmDttRec
@@ -427,18 +449,12 @@ typedef struct NvRmDttRec
// Out-of-limit interrupt cpabilities for high limit
NvOdmTmonParameterCaps TcoreHighLimitCaps;
- // Last TMON reading time stamp
- NvU32 RdTimeUs;
-
- // TMON reading period
- NvU32 RdIntervalUs;
+ // Core zone policy
+ NvRmTzonePolicy TcorePolicy;
// Core temperature
NvS32 CoreTemperatureC;
- // Request core temperature update
- volatile NvBool UpdateFlag;
-
// Specifies if out-of-limit interrupt is used for temperature update
volatile NvBool UseIntr;
} NvRmDtt;