void NvRmPrivAp20DttPolicyUpdate( NvRmDeviceHandle hRmDevice, NvRmDtt* pDtt) { NvBool Throttle = NvOdmTmonThrottle(pDtt->hOdmTcore); // 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)) { 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 = NV_MIN( NvRmPrivGetSocClockLimits(NvRmModuleID_Cpu)->MaxKHz, p[steps-1]); s_CpuThrottleMinKHz = NvRmPrivGetSocClockLimits(NvRmModuleID_Cpu)->MaxKHz / NVRM_DTT_RATIO_MAX; NV_ASSERT(s_CpuThrottleMaxKHz > s_CpuThrottleMinKHz); NV_ASSERT(s_CpuThrottleMinKHz > NVRM_DTT_CPU_DELTA_KHZ); s_CpuThrottleKHz = s_CpuThrottleMaxKHz; } pDtt->TcorePolicy.PolicyRange = Throttle ? NvRmDttAp20PolicyRange_ThrottleDown : NvRmDttAp20PolicyRange_FreeRunning; pDtt->TcorePolicy.UpdateIntervalUs = Throttle ? NVRM_DTT_POLL_MS_CRITICAL * 1000 : NV_WAIT_INFINITE; }
void NvRmPrivAp20DttPolicyUpdate( NvRmDeviceHandle hRmDevice, NvS32 TemperatureC, NvRmDtt* pDtt) { NvRmDttAp20PolicyRange Range; // 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)) { 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 = NV_MIN( NvRmPrivGetSocClockLimits(NvRmModuleID_Cpu)->MaxKHz, p[steps-1]); s_CpuThrottleMinKHz = NvRmPrivGetSocClockLimits(NvRmModuleID_Cpu)->MaxKHz / NVRM_DTT_RATIO_MAX; 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); } // Advanced policy range state machine (one step at a time) Range = (NvRmDttAp20PolicyRange)pDtt->TcorePolicy.PolicyRange; switch (Range) { 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; } /* * 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. */ pDtt->CoreTemperatureC = TemperatureC; switch (Range) { 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; 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; 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; }
void NvRmPrivCoreVoltageInit(NvRmDeviceHandle hRmDevice) { NvU32 CoreRailAddress, RtcRailAddress, CpuRailAddress; const NvOdmPeripheralConnectivity* pPmuRail; NvRmMilliVolts CurrentCoreMv = 0; NvRmMilliVolts CurrentRtcMv = 0; NvRmMilliVolts NominalCoreMv = NvRmPrivGetNominalMV(hRmDevice); NV_ASSERT(hRmDevice); if (NvRmPrivGetExecPlatform(hRmDevice) != ExecPlatform_Soc) { return; } pPmuRail = NvOdmPeripheralGetGuid(NV_VDD_CORE_ODM_ID); NV_ASSERT(pPmuRail); NV_ASSERT(pPmuRail->NumAddress); CoreRailAddress = pPmuRail->AddressList[0].Address; pPmuRail = NvOdmPeripheralGetGuid(NV_VDD_RTC_ODM_ID); NV_ASSERT(pPmuRail); NV_ASSERT(pPmuRail->NumAddress); RtcRailAddress = pPmuRail->AddressList[0].Address; // This function is called during PMU initialization when current (= boot) // core voltage is expected to be within one safe step from nominal, and // RTC voltage must be within one safe step from the core. Set nominal // voltage (bump PMU ref count), if the above conditions are true. NvRmPmuGetVoltage(hRmDevice, CoreRailAddress, &CurrentCoreMv); NvRmPmuGetVoltage(hRmDevice, RtcRailAddress, &CurrentRtcMv); if((CurrentCoreMv > (NominalCoreMv + NVRM_SAFE_VOLTAGE_STEP_MV)) || ((CurrentCoreMv + NVRM_SAFE_VOLTAGE_STEP_MV) < NominalCoreMv)) { NV_ASSERT(!"Unexpected initial core voltage"); return; } if((CurrentRtcMv > (CurrentCoreMv + NVRM_SAFE_VOLTAGE_STEP_MV)) || ((CurrentRtcMv + NVRM_SAFE_VOLTAGE_STEP_MV) < CurrentCoreMv)) { NV_ASSERT(!"Unexpected initial RTC voltage"); return; } // If core voltage is going up, update it before CPU if (CurrentCoreMv <= NominalCoreMv) { NvRmPmuSetVoltage(hRmDevice, RtcRailAddress, NominalCoreMv, NULL); NvRmPmuSetVoltage(hRmDevice, CoreRailAddress, NominalCoreMv, NULL); } // If the platform has dedicated CPU voltage rail, make sure it is set to // nominal level as well (bump PMU ref count along the way). if (NvRmPrivIsCpuRailDedicated(hRmDevice)) { NvRmPmuVddRailCapabilities cap; NvRmMilliVolts NominalCpuMv = NvRmPrivModuleVscaleGetMV( hRmDevice, NvRmModuleID_Cpu, NvRmPrivGetSocClockLimits(NvRmModuleID_Cpu)->MaxKHz); pPmuRail = NvOdmPeripheralGetGuid(NV_VDD_CPU_ODM_ID); NV_ASSERT(pPmuRail); NV_ASSERT(pPmuRail->NumAddress); CpuRailAddress = pPmuRail->AddressList[0].Address; // Clip nominal CPU voltage to minimal PMU capabilities, and set it. // (note: PMU with CPU voltage range above nominal is temporary // accepted exception; for other limit violations: PMU maximum level // for CPU is not high enough, or PMU core range does not include // nominal core voltage, assert is fired inside NvRmPmuSetVoltage()) NvRmPmuGetCapabilities(hRmDevice, CpuRailAddress, &cap); NominalCpuMv = NV_MAX(NominalCpuMv, cap.MinMilliVolts); NvRmPmuSetVoltage(hRmDevice, CpuRailAddress, NominalCpuMv, NULL); if (CurrentCoreMv > NominalCoreMv) NvOsWaitUS(NVRM_CPU_TO_CORE_DOWN_US); // delay if core to go down } // If core voltage is going down, update it after CPU voltage if (CurrentCoreMv > NominalCoreMv) { NvRmPmuSetVoltage(hRmDevice, RtcRailAddress, NominalCoreMv, NULL); NvRmPmuSetVoltage(hRmDevice, CoreRailAddress, NominalCoreMv, NULL); } // Always On System I/O, DDR IO and RX DDR (if exist) - set nominal, // bump ref count NvRmPrivPmuRailControl(hRmDevice, NV_VDD_SYS_ODM_ID, NV_TRUE); NvRmPrivPmuRailControl(hRmDevice, NV_VDD_DDR_ODM_ID, NV_TRUE); if (NvOdmPeripheralGetGuid(NV_VDD_DDR_RX_ODM_ID)) NvRmPrivPmuRailControl(hRmDevice, NV_VDD_DDR_RX_ODM_ID, NV_TRUE); }