diff options
author | Alex Frid <afrid@nvidia.com> | 2010-04-02 14:15:19 -0700 |
---|---|---|
committer | Gary King <gking@nvidia.com> | 2010-04-06 20:21:39 -0700 |
commit | b01be20bf4a6dd5273747cdda308bd24187de813 (patch) | |
tree | 2f37bdca7b455a03cd2701a3cd10550f63797367 /arch | |
parent | 6dbb4916287e842f3e8541a980e30ee0cc9479b4 (diff) |
tegra RM: Power gated core partitions on suspend entry.
Power gated all core partitions (except L2C) when entering suspend. During
resume ungate those partitions that were powered before suspend.
Change-Id: I6559f7d314df5904acc8f639efe953d8382925ac
Reviewed-on: http://git-master/r/1046
Tested-by: Aleksandr Frid <afrid@nvidia.com>
Reviewed-by: Narendra Damahe <ndamahe@nvidia.com>
Tested-by: Narendra Damahe <ndamahe@nvidia.com>
Reviewed-by: Gary King <gking@nvidia.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/mach-tegra/include/nvrm_power_private.h | 9 | ||||
-rw-r--r-- | arch/arm/mach-tegra/nvrm/core/ap15/ap15rm_power.c | 102 | ||||
-rw-r--r-- | arch/arm/mach-tegra/nvrm/core/common/nvrm_power.c | 9 |
3 files changed, 107 insertions, 13 deletions
diff --git a/arch/arm/mach-tegra/include/nvrm_power_private.h b/arch/arm/mach-tegra/include/nvrm_power_private.h index 87a6ca6ef69b..f4adaa0c64ca 100644 --- a/arch/arm/mach-tegra/include/nvrm_power_private.h +++ b/arch/arm/mach-tegra/include/nvrm_power_private.h @@ -407,6 +407,15 @@ NvRmPrivPowerGroupGetVoltage( NvRmDeviceHandle hRmDeviceHandle, NvU32 PowerGroup); + +/** + * Gate/ungate power groups on entry/exit to/from low power state. + * + * @param hRmDeviceHandle The RM device handle. + */ +void NvRmPrivPowerGroupSuspend(NvRmDeviceHandle hRmDeviceHandle); +void NvRmPrivPowerGroupResume(NvRmDeviceHandle hRmDeviceHandle); + /** * Controls power state and clamping for PCIEXCLK/PLLE (chip-specific). * diff --git a/arch/arm/mach-tegra/nvrm/core/ap15/ap15rm_power.c b/arch/arm/mach-tegra/nvrm/core/ap15/ap15rm_power.c index 116e4148a474..d9fd9f3d1251 100644 --- a/arch/arm/mach-tegra/nvrm/core/ap15/ap15rm_power.c +++ b/arch/arm/mach-tegra/nvrm/core/ap15/ap15rm_power.c @@ -75,10 +75,11 @@ // Power Group -to- Power Gating Ids mapping static const NvU32* s_PowerGroupIds = NULL; +static NvBool s_UngateOnResume[NV_POWERGROUP_MAX] = {0}; /*****************************************************************************/ -static NvBool IsPowerGateSupported(NvU32 PowerGroup) +static NvBool IsRunTimePowerGateSupported(NvU32 PowerGroup) { // 1st check h/w support capabilities NV_ASSERT(s_PowerGroupIds); @@ -101,6 +102,27 @@ static NvBool IsPowerGateSupported(NvU32 PowerGroup) } } +static NvBool IsSuspendPowerGateForced(NvU32 PowerGroup) +{ + // 1st check h/w support capabilities + NV_ASSERT(s_PowerGroupIds); + if (s_PowerGroupIds[PowerGroup] == NV_POWERGROUP_INVALID) + return NV_FALSE; + + // now check s/w support + switch (PowerGroup) + { + case NV_POWERGROUP_TD: + case NV_POWERGROUP_PCIE: + case NV_POWERGROUP_VDE: + case NV_POWERGROUP_VE: + case NV_POWERGROUP_MPE: + return NV_TRUE; + default: + return NV_FALSE; + } +} + static void PowerGroupResetControl( NvRmDeviceHandle hRmDeviceHandle, NvU32 PowerGroup, @@ -126,6 +148,12 @@ static void PowerGroupResetControl( case NV_POWERGROUP_VDE: NvRmModuleResetWithHold(hRmDeviceHandle, NvRmModuleID_Vde, Assert); break; + case NV_POWERGROUP_VE: + NvRmModuleResetWithHold(hRmDeviceHandle, NvRmModuleID_Vi, Assert); + NvRmModuleResetWithHold(hRmDeviceHandle, NvRmModuleID_Csi, Assert); + NvRmModuleResetWithHold(hRmDeviceHandle, NvRmModuleID_Isp, Assert); + NvRmModuleResetWithHold(hRmDeviceHandle, NvRmModuleID_Epp, Assert); + break; case NV_POWERGROUP_MPE: NvRmModuleResetWithHold(hRmDeviceHandle, NvRmModuleID_Mpe, Assert); break; @@ -156,6 +184,16 @@ static void PowerGroupClockControl( NvRmPrivEnableModuleClock( hRmDeviceHandle, NvRmModuleID_Vde, ClockState); break; + case NV_POWERGROUP_VE: + NvRmPrivEnableModuleClock( + hRmDeviceHandle, NvRmModuleID_Vi, ClockState); + NvRmPrivEnableModuleClock( + hRmDeviceHandle, NvRmModuleID_Csi, ClockState); + NvRmPrivEnableModuleClock( + hRmDeviceHandle, NvRmModuleID_Isp, ClockState); + NvRmPrivEnableModuleClock( + hRmDeviceHandle, NvRmModuleID_Epp, ClockState); + break; case NV_POWERGROUP_MPE: NvRmPrivEnableModuleClock( hRmDeviceHandle, NvRmModuleID_Mpe, ClockState); @@ -165,27 +203,19 @@ static void PowerGroupClockControl( } } -void -NvRmPrivPowerGroupControl( +static void +PowerGroupPowerControl( NvRmDeviceHandle hRmDeviceHandle, NvU32 PowerGroup, NvBool Enable) { NvU32 reg, Id, Mask, Status; - NVRM_POWER_PRINTF(("%s Power Group %d\n", - (Enable ? "Enable" : "Disable"), PowerGroup)); // Do nothing if not SoC platform NV_ASSERT(hRmDeviceHandle); if (NvRmPrivGetExecPlatform(hRmDeviceHandle) != ExecPlatform_Soc) return; - // Do nothing if power gating is not supported for this group - if (PowerGroup >= NV_POWERGROUP_MAX) - return; // "virtual" groups are always On - if (!IsPowerGateSupported(PowerGroup)) - return; - // Do nothing if power group is already in requested state NV_ASSERT(s_PowerGroupIds[PowerGroup] != NV_POWERGROUP_INVALID); Id = s_PowerGroupIds[PowerGroup]; @@ -250,6 +280,25 @@ NvRmPrivPowerGroupControl( } } +void +NvRmPrivPowerGroupControl( + NvRmDeviceHandle hRmDeviceHandle, + NvU32 PowerGroup, + NvBool Enable) +{ + NVRM_POWER_PRINTF(("%s Power Group %d\n", + (Enable ? "Enable" : "Disable"), PowerGroup)); + + // Do nothing if dynamic power gating is not supported for this group + if (PowerGroup >= NV_POWERGROUP_MAX) + return; // "virtual" groups are always On + if (!IsRunTimePowerGateSupported(PowerGroup)) + return; + + // Gate/ungate the group + PowerGroupPowerControl(hRmDeviceHandle, PowerGroup, Enable); +} + NvRmMilliVolts NvRmPrivPowerGroupGetVoltage( NvRmDeviceHandle hRmDeviceHandle, @@ -273,6 +322,37 @@ NvRmPrivPowerGroupGetVoltage( return Voltage; } +void NvRmPrivPowerGroupSuspend(NvRmDeviceHandle hRmDeviceHandle) +{ + NvU32 i; + + // On suspend entry power gate core group that is still On, but must be Off + for (i = 0; i < NV_POWERGROUP_MAX; i++) + { + if (!IsSuspendPowerGateForced(i) || + (NvRmPrivPowerGroupGetVoltage(hRmDeviceHandle, i) == NvRmVoltsOff)) + { + s_UngateOnResume[i] = NV_FALSE; + continue; + } + + s_UngateOnResume[i] = NV_TRUE; + PowerGroupPowerControl(hRmDeviceHandle, i, NV_FALSE); + } +} + +void NvRmPrivPowerGroupResume(NvRmDeviceHandle hRmDeviceHandle) +{ + NvU32 i; + + // On resume ungate core group that was forcefully gated on suspend entry + for (i = 0; i < NV_POWERGROUP_MAX; i++) + { + if (s_UngateOnResume[i] == NV_TRUE) + PowerGroupPowerControl(hRmDeviceHandle, i, NV_TRUE); + } +} + void NvRmPrivPowerGroupControlInit(NvRmDeviceHandle hRmDeviceHandle) { NvU32 i, Size; diff --git a/arch/arm/mach-tegra/nvrm/core/common/nvrm_power.c b/arch/arm/mach-tegra/nvrm/core/common/nvrm_power.c index 9bb8ae412807..e748aa2e563d 100644 --- a/arch/arm/mach-tegra/nvrm/core/common/nvrm_power.c +++ b/arch/arm/mach-tegra/nvrm/core/common/nvrm_power.c @@ -688,8 +688,11 @@ PowerEventNotify( } else if (Event == NvRmPowerEvent_WakeLP1) { - // LP1: core power is preserved; modules in powered down - // groups are tracked via RecordPowerCycle() + // LP1: core power is preserved; but all power groups + // except AO and NPG group are power gated + if ((pVoltageReq->PowerGroup != NV_POWERGROUP_AO) && + (pVoltageReq->PowerGroup != NV_POWERGROUP_NPG)) + pVoltageReq->PowerCycled = NV_TRUE; } pVoltageReq = pVoltageReq->pNext; } @@ -1476,6 +1479,7 @@ NvRmKernelPowerSuspend( NvRmDeviceHandle hRmDeviceHandle ) NvRmPrivPmuInterruptMask(hRmDeviceHandle, NV_TRUE); NvRmPrivDfsSuspend(NvOdmQueryLowestSocPowerState()->LowestPowerState); + NvRmPrivPowerGroupSuspend(hRmDeviceHandle); #if NVRM_POWER_DEBUG_SUSPEND_ENTRY NvOsMutexLock(s_hPowerClientMutex); @@ -1522,6 +1526,7 @@ NvError NvRmKernelPowerResume( NvRmDeviceHandle hRmDeviceHandle ) { NvRmPrivPmuInterruptMask(hRmDeviceHandle, NV_FALSE); + NvRmPrivPowerGroupResume(hRmDeviceHandle); return NvSuccess; } |