diff options
author | Gary King <gking@nvidia.com> | 2009-12-16 13:38:41 -0800 |
---|---|---|
committer | Gary King <gking@nvidia.com> | 2009-12-16 19:27:26 -0800 |
commit | 1accf09674a3a36463bc7f15212b14de92e5ae86 (patch) | |
tree | edea1b4bfb72aba386b819b95b84cc83a069630e /arch/arm/mach-tegra/nvrm/core | |
parent | e2d05b4f4cb28a6e66236bc814f01e74d2466121 (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.c | 256 | ||||
-rw-r--r-- | arch/arm/mach-tegra/nvrm/core/ap20/ap20rm_power_dfs.h | 33 | ||||
-rw-r--r-- | arch/arm/mach-tegra/nvrm/core/common/nvrm_power_dfs.c | 145 | ||||
-rw-r--r-- | arch/arm/mach-tegra/nvrm/core/common/nvrm_power_dfs.h | 32 |
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; |