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;
}
NvRmPmRequest 
NvRmPrivAp20GetPmRequest(
    NvRmDeviceHandle hRmDevice,
    const NvRmDfsSampler* pCpuSampler,
    NvRmFreqKHz* pCpuKHz)
{
    // 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;

    NvU32 t;
    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;

    // Use clocks for load when no busy hint, otherwise use activity metrics
    if (NvRmPrivDfsGetBusyHintActive(NvRmDfsClockId_Cpu)) {
        CpuLoadGaugeKHz = pCpuSampler->AverageKHz;
    } else {
        CpuLoadGaugeKHz = *pCpuKHz;
    }

    // Slave CPU1 power management policy thresholds:
    // - use fixed values if they are defined explicitly, otherwise
    // - set CPU1 OffMax threshold at 3/4 of cpu frequency range,
    //   and 1/2 of max frequency as CPU1 OnMin threshold
    if ((s_Cpu1OffMaxKHz == 0) && (s_Cpu1OnMinKHz == 0))
    {
        NvRmFreqKHz MaxKHz =
            NvRmPrivGetSocClockLimits(NvRmModuleID_Cpu)->MaxKHz;

        s_Cpu1OnMinKHz = NVRM_CPU1_ON_MIN_KHZ ?
                         NVRM_CPU1_ON_MIN_KHZ : (MaxKHz / 2);
        s_Cpu1OffMaxKHz = NVRM_CPU1_OFF_MAX_KHZ ?
                          NVRM_CPU1_OFF_MAX_KHZ : (3 * MaxKHz / 4);
        NV_ASSERT(s_Cpu1OnMinKHz < s_Cpu1OffMaxKHz);
    }

    // Timestamp
    if (s_pTimerUs == NULL)
        s_pTimerUs = NvRmPrivAp15GetTimerUsVirtAddr(hRmDevice);
    t = NV_READ32(s_pTimerUs);

    /*
     * Request OS kernel to turn CPU1 Off if all of the following is true:
     * (a) CPU frequency is below OnMin threshold, 
     * (b) CPU1 is actually On
     *
     * Request OS kernel to turn CPU1 On if all of the following is true:
     * (a) CPU frequency is above OffMax threshold 
     * (b) CPU1 is actually Off
     */
    if (CpuLoadGaugeKHz < s_Cpu1OnMinKHz)
    {
        s_Cpu1OnPendingCnt = 0;
        if ((s_Cpu1OffPendingCnt & 0x1) == 0)
        {
            s_Cpu1OffPendingCnt = t | 0x1;  // Use LSb as a delay start flag
            return PmRequest;
        }
        if ((t - s_Cpu1OffPendingCnt) < (NVRM_CPU1_OFF_PENDING_MS * 1000))
            return PmRequest;

        if (!Cpu1Off)
        {
            s_LastPmRequest = PmRequest = (NvRmPmRequest_CpuOffFlag | 0x1);
            s_Cpu1OffPendingCnt = 0;   // re-start delay after request
        }
#if NVRM_TEST_PMREQUEST_UP_MODE
        NV_REGW(hRmDevice, NvRmPrivModuleID_ClockAndReset, 0,
            CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET_0,
            CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET_0_SET_CPURESET1_FIELD);
#endif
    }
    else if (CpuLoadGaugeKHz > s_Cpu1OffMaxKHz)
    {
        s_Cpu1OffPendingCnt = 0;
        if ((s_Cpu1OnPendingCnt & 0x1) == 0)
        {
            s_Cpu1OnPendingCnt = t | 0x1;  // Use LSb as a delay start flag
            return PmRequest;
        }
        if ((t - s_Cpu1OnPendingCnt) < (NVRM_CPU1_ON_PENDING_MS * 1000))
            return PmRequest;

        if (Cpu1Off)
        {
            s_LastPmRequest = PmRequest = (NvRmPmRequest_CpuOnFlag | 0x1);
            *pCpuKHz = NvRmPrivGetSocClockLimits(NvRmModuleID_Cpu)->MaxKHz;
            s_Cpu1OnPendingCnt = 0;  // re-start delay after request
        }
#if NVRM_TEST_PMREQUEST_UP_MODE
        NV_REGW(hRmDevice, NvRmPrivModuleID_ClockAndReset, 0,
            CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR_0,
            CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR_0_CLR_CPURESET1_FIELD);
#endif
    }
    else
    {   // Re-start both delays inside hysteresis loop
        s_Cpu1OnPendingCnt = 0;
        s_Cpu1OffPendingCnt = 0;
    }
    return PmRequest;
}
Пример #3
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;
}
Пример #4
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);
}