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;
}
示例#2
0
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;
}
示例#3
0
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);
}