Загрузка данных
/*--------------------------------------------------------------------------*/
/* Sleep the system */
/*--------------------------------------------------------------------------*/
int32_t DEV_SM_SystemSleep(uint32_t sleepMode)
{
static const uint32_t s_clkRootSleepList[DEV_SM_NUM_SLEEP_ROOTS] =
{
[0] = CLOCK_ROOT_ELE,
[1] = CLOCK_ROOT_BUSAON,
[2] = CLOCK_ROOT_M33
};
static const uint32_t s_pllVcoList[CLOCK_NUM_PLL] =
{
[CLOCK_PLL_SYS1] = CLOCK_SRC_SYSPLL1_VCO,
[CLOCK_PLL_AUDIO1] = CLOCK_SRC_AUDIOPLL1_VCO,
[CLOCK_PLL_AUDIO2] = CLOCK_SRC_AUDIOPLL2_VCO,
[CLOCK_PLL_VIDEO1] = CLOCK_SRC_VIDEOPLL1_VCO,
[CLOCK_PLL_ARM] = CLOCK_SRC_ARMPLL_VCO,
[CLOCK_PLL_DRAM] = CLOCK_SRC_DRAMPLL_VCO,
[CLOCK_PLL_HSIO] = CLOCK_SRC_HSIOPLL_VCO,
[CLOCK_PLL_LDB] = CLOCK_SRC_LDBPLL_VCO
};
static src_mem_slice_t const *const s_srcMemPtrs[] = SRC_MEM_BASE_PTRS;
int32_t status = SM_ERR_SUCCESS;
uint32_t s_clkRootCtrl[DEV_SM_NUM_SLEEP_ROOTS];
uint32_t cpuWakeMask[CPU_NUM_IDX][GPC_CPU_CTRL_CMC_IRQ_WAKEUP_MASK_COUNT];
uint32_t sysWakeMask[GPC_CPU_CTRL_CMC_IRQ_WAKEUP_MASK_COUNT];
uint32_t nvicISER[GPC_CPU_CTRL_CMC_IRQ_WAKEUP_MASK_COUNT];
/* Capture start of sleep entry */
uint64_t sleepEntryStart = DEV_SM_Usec64Get();
uint64_t sleepExitStart = sleepEntryStart;
/* Reset wake source of sleep record */
g_syslog.sysSleepRecord.wakeSource = 0U;
/* Capture system sleep mode/flags */
g_syslog.sysSleepRecord.sysSleepMode = s_sysSleepMode;
g_syslog.sysSleepRecord.sysSleepFlags = s_sysSleepFlags;
/* Capture power status of MIXes */
g_syslog.sysSleepRecord.mixPwrStat = 0U;
for (uint32_t mixIdx = 0U; mixIdx < PWR_NUM_MIX_SLICE; mixIdx++)
{
if (SRC_MixIsPwrSwitchOn(mixIdx))
{
g_syslog.sysSleepRecord.mixPwrStat |= (1UL << mixIdx);
}
}
/* Capture power status of memories */
g_syslog.sysSleepRecord.memPwrStat = 0U;
for (uint32_t memIdx = 0U; memIdx < PWR_NUM_MEM_SLICE; memIdx++)
{
const src_mem_slice_t *srcMem = s_srcMemPtrs[memIdx];
if ((srcMem->MEM_CTRL & SRC_MEM_MEM_CTRL_MEM_LP_MODE_MASK) != 0U)
{
g_syslog.sysSleepRecord.memPwrStat |= (1UL << memIdx);
}
}
/* Capture power status of PLLs */
g_syslog.sysSleepRecord.pllPwrStat = 0U;
for (uint32_t pllIdx = 0U; pllIdx < CLOCK_NUM_PLL; pllIdx++)
{
uint32_t sourceIdx = s_pllVcoList[pllIdx];
if (CLOCK_SourceGetEnable(sourceIdx))
{
g_syslog.sysSleepRecord.pllPwrStat |= (1UL << pllIdx);
}
}
/* Initialize wake masks */
for (uint32_t wakeIdx = 0;
wakeIdx < GPC_CPU_CTRL_CMC_IRQ_WAKEUP_MASK_COUNT;
wakeIdx++)
{
sysWakeMask[wakeIdx] = 0xFFFFFFFFU;
for (uint32_t cpuIdx = 0U; cpuIdx < CPU_NUM_IDX; cpuIdx++)
{
cpuWakeMask[cpuIdx][wakeIdx] = 0xFFFFFFFFU;
}
}
/* Initialize NOC/WAKEUP MIX dependencies */
uint32_t lpmSettingNoc = CPU_PD_LPM_ON_NEVER;
uint32_t lpmSettingWakeup = CPU_PD_LPM_ON_NEVER;
/* Scan CPUs, update GPC wake masks, assess NOC/WAKEUP MIX dependencies */
for (uint32_t cpuIdx = 0U; cpuIdx < CPU_NUM_IDX; cpuIdx++)
{
if (cpuIdx != CPU_IDX_M33P)
{
/* Check if sleep is forced for the CPU */
bool sleepForce;
if (CPU_SleepForceGet(cpuIdx, &sleepForce))
{
/* If sleep is not forced, manage GPC masks */
if (!sleepForce)
{
/* IRQs enabled at NVIC level become GPC wake sources */
for (uint32_t wakeIdx = 0;
wakeIdx < GPC_CPU_CTRL_CMC_IRQ_WAKEUP_MASK_COUNT;
wakeIdx++)
{
uint32_t wakeVal;
if (CPU_IrqWakeGet(cpuIdx, wakeIdx, &wakeVal))
{
cpuWakeMask[cpuIdx][wakeIdx] = wakeVal;
sysWakeMask[wakeIdx] &= wakeVal;
(void) CPU_IrqWakeSet(cpuIdx, wakeIdx,
0xFFFFFFFFU);
}
}
/* Update NOCMIX dependency */
uint32_t lpmSetting;
if (SRC_MixCpuLpmGet(PWR_MIX_SLICE_IDX_NOC, cpuIdx,
&lpmSetting))
{
if (lpmSetting > lpmSettingNoc)
{
lpmSettingNoc = lpmSetting;
}
}
/* Update WAKEUPMIX dependency */
if (SRC_MixCpuLpmGet(PWR_MIX_SLICE_IDX_WAKEUP, cpuIdx,
&lpmSetting))
{
if (lpmSetting > lpmSettingWakeup)
{
lpmSettingWakeup = lpmSetting;
}
}
}
/* Disable GPC wakeups for CPUs forced to sleep */
else
{
/* IRQs enabled at NVIC level become GPC wake sources */
for (uint32_t wakeIdx = 0;
wakeIdx < GPC_CPU_CTRL_CMC_IRQ_WAKEUP_MASK_COUNT;
wakeIdx++)
{
uint32_t wakeVal;
if (CPU_IrqWakeGet(cpuIdx, wakeIdx, &wakeVal))
{
cpuWakeMask[cpuIdx][wakeIdx] = wakeVal;
(void) CPU_IrqWakeSet(cpuIdx, wakeIdx,
0xFFFFFFFFU);
}
}
}
}
}
}
/* Check system sleep status after clearing GPC masks */
uint32_t sysSleepStat;
if (CPU_SystemSleepStatusGet(&sysSleepStat))
{
/* If system can sleep after clearing GPC masks, SUSPEND
* processing has reached point of coherency. Agent CPUs
* cannot wake without SM completion of SUSPEND entry/exit
* sequence below.
*/
if (sysSleepStat == CPU_SLEEP_MODE_SUSPEND)
{
/* Board-level sleep prepare */
BOARD_SystemSleepPrepare(s_sysSleepMode, s_sysSleepFlags);
/* Disable sensor */
(void) DEV_SM_SensorPowerDown(DEV_SM_SENSOR_TEMP_ANA);
/* Check the value doesn't wrap */
if (g_syslog.sysSleepRecord.sleepCnt <= (UINT32_MAX - 1U))
{
/*! Increment system sleep counter */
g_syslog.sysSleepRecord.sleepCnt++;
}
else
{
/* Initialize to zero in case of wrap */
g_syslog.sysSleepRecord.sleepCnt = 0U;
}
bool ddrInRetention = false;
/* Limit DDR access path to SM */
if (DEV_SM_RdcDdrBlock(true) == SM_ERR_SUCCESS)
{
/* Attempt to place DDR into retention */
if (DEV_SM_MemDdrRetentionEnter() == SM_ERR_SUCCESS)
{
/* Set flag to indicate DDR retention is active */
ddrInRetention = true;
/* Power down DDRMIX */
if (DEV_SM_PowerStateSet(DEV_SM_PD_DDR, DEV_SM_POWER_STATE_OFF)
== SM_ERR_SUCCESS)
{
g_syslog.sysSleepRecord.mixPwrStat &=
(~(1UL << PWR_MIX_SLICE_IDX_DDR));
}
}
}
/* If NOCMIX powered down during SUSPEND, force power down */
if (lpmSettingNoc <= sleepMode)
{
if (DEV_SM_PowerStateSet(DEV_SM_PD_NOC, DEV_SM_POWER_STATE_OFF)
== SM_ERR_SUCCESS)
{
g_syslog.sysSleepRecord.mixPwrStat &=
(~(1UL << PWR_MIX_SLICE_IDX_NOC));
}
}
/* Query if any CPU in LP compute mode */
bool lpComputeActive = (CPU_LpComputeListGet() != 0U);
/* Track if WAKEUPMIX powered down */
bool wakeupMixOff = false;
/* Track if WAKEUPMIX performance level forced */
bool restoreWakeupMixPerf = false;
uint32_t savedWakeupMixPerf;
/* If WAKEUPMIX powered down during SUSPEND, force power down */
if ((lpmSettingWakeup <= sleepMode) &&
((CoreDebug->DHCSR & CoreDebug_DHCSR_C_DEBUGEN_Msk) == 0x0U))
{
/* Keep WAKEUPMIX powered at parked level during LP compute */
if (lpComputeActive)
{
if (DEV_SM_PerfLevelGet(DEV_SM_PERF_WAKEUP,
&savedWakeupMixPerf) == SM_ERR_SUCCESS)
{
if (DEV_SM_PerfLevelSet(DEV_SM_PERF_WAKEUP,
DEV_SM_PERF_LVL_PRK) == SM_ERR_SUCCESS)
{
restoreWakeupMixPerf = true;
}
}
}
else
{
if (DEV_SM_PowerStateSet(DEV_SM_PD_WAKEUP,
DEV_SM_POWER_STATE_OFF) == SM_ERR_SUCCESS)
{
g_syslog.sysSleepRecord.mixPwrStat &=
(~(1UL << PWR_MIX_SLICE_IDX_WAKEUP));
wakeupMixOff = true;
}
}
}
/* Inhibit all GPC LP handshakes during SUSPEND */
uint32_t lpHsSm = BLK_CTRL_S_AONMIX->LP_HANDSHAKE_SM;
BLK_CTRL_S_AONMIX->LP_HANDSHAKE_SM = 0U;
uint32_t lpHs2Sm = BLK_CTRL_S_AONMIX->LP_HANDSHAKE2_SM;
BLK_CTRL_S_AONMIX->LP_HANDSHAKE2_SM = 0U;
uint32_t lpHsEle = BLK_CTRL_S_AONMIX->LP_HANDSHAKE_ELE;
BLK_CTRL_S_AONMIX->LP_HANDSHAKE_ELE = 0U;
uint32_t lpHs2Ele = BLK_CTRL_S_AONMIX->LP_HANDSHAKE2_ELE;
BLK_CTRL_S_AONMIX->LP_HANDSHAKE2_ELE = 0U;
/* Configure SM GPC_CTRL and NVIC for system-level wake events */
for (uint32_t wakeIdx = 0;
wakeIdx < GPC_CPU_CTRL_CMC_IRQ_WAKEUP_MASK_COUNT;
wakeIdx++)
{
/* Save context of SM IRQs enabled at NVIC level */
nvicISER[wakeIdx] = NVIC->ISER[wakeIdx];
/* Clear unused system-level IRQs */
uint32_t maskVal = ~nvicISER[wakeIdx];
NVIC->ICPR[wakeIdx] = 0xFFFFFFFFU & maskVal;
/* Add system-level wake events */
maskVal &= sysWakeMask[wakeIdx];
/* Update GPC wake mask */
(void) CPU_IrqWakeSet(CPU_IDX_M33P, wakeIdx, maskVal);
/* Update NVIC wake mask */
NVIC->ICER[wakeIdx] = 0xFFFFFFFFU;
NVIC->ISER[wakeIdx] = ~maskVal;
}
/* Configure M33P to wake from GPC */
(void) CPU_WakeMuxSet(CPU_IDX_M33P, false);
/* Set target M33P sleep mode */
(void) CPU_SleepModeSet(CPU_IDX_M33P, sleepMode);
/* Extract and clamp performance level from system sleep mode */
uint32_t perfLevelSleep = (s_sysSleepMode & 0xF0U) >> 4U;
if (perfLevelSleep > DEV_SM_PERF_LVL_ODV)
{
perfLevelSleep = DEV_SM_PERF_LVL_ODV;
}
/* System remains active during sleep based on performance level
* and OSC24M configuration.
*/
bool activeSleep = (perfLevelSleep != DEV_SM_PERF_LVL_PRK) ||
((s_sysSleepFlags & DEV_SM_SSF_OSC24M_ACTIVE_MASK) != 0U) ||
lpComputeActive;
/* Check if OSC24M must remain active */
if (activeSleep)
{
/* Keep OSC_24M active during system sleep */
GPC_GLOBAL->GPC_ROSC_CTRL = 0U;
}
else
{
/* Shut off OSC_24M during system sleep */
GPC_GLOBAL->GPC_ROSC_CTRL =
GPC_GLOBAL_GPC_ROSC_CTRL_ROSC_OFF_EN_MASK;
}
/* Check PMIC_STBY system sleep mode flag */
if ((s_sysSleepFlags & DEV_SM_SSF_PMIC_STBY_INACTIVE_MASK) == 0U)
{
/* Enable GPC PMIC standby control */
GPC_GLOBAL->GPC_PMIC_CTRL =
GPC_GLOBAL_GPC_PMIC_CTRL_PMIC_STBY_EN_MASK;
}
else
{
/* Disable GPC PMIC standby control */
GPC_GLOBAL->GPC_PMIC_CTRL = 0U;
}
/* Power down eFUSE */
GPC_GLOBAL->GPC_EFUSE_CTRL =
GPC_GLOBAL_GPC_EFUSE_CTRL_EFUSE_PD_EN_MASK;
/* Disable bypass for clock sources */
DEV_SM_ClockSourceBypass(false, true);
if (activeSleep)
{
/* If staying active, move to system sleep performance level */
(void) DEV_SM_PerfSystemSleep(perfLevelSleep);
}
else
{
/* Notify ELE of suspend entry */
ELE_StartDvfsChange(ELE_DVFS_FLAG_SUSPEND, 0U, 0U, 0U);
/* Move ELE and SM clock roots to OSC_24M to allow SysPLL to be
* powered down. OSC_24M may be gated by hardware during final phases
* of system SUSPEND entry.
*/
for (uint32_t sleepRootIdx = 0U;
sleepRootIdx < DEV_SM_NUM_SLEEP_ROOTS;
sleepRootIdx++)
{
uint32_t rootIdx = s_clkRootSleepList[sleepRootIdx];
/* Save clock root context */
s_clkRootCtrl[sleepRootIdx] =
CCM_CTRL->CLOCK_ROOT[rootIdx].CLOCK_ROOT_CONTROL.RW;
/* Set MUX = 0 (OSC_24M) */
CCM_CTRL->CLOCK_ROOT[rootIdx].CLOCK_ROOT_CONTROL.CLR =
CCM_CLOCK_ROOT_MUX_MASK;
/* Set DIV = 0 (/1) */
CCM_CTRL->CLOCK_ROOT[rootIdx].CLOCK_ROOT_CONTROL.CLR =
CCM_CLOCK_ROOT_DIV_MASK;
}
}
/* Check if sleep performance level allows SYSPLL disable */
if (perfLevelSleep == DEV_SM_PERF_LVL_PRK)
{
/* Power down SYSPLL clock nodes */
uint32_t clkSrcIdx = CLOCK_SRC_SYSPLL1_PFD2_DIV2;
while (clkSrcIdx >= CLOCK_SRC_SYSPLL1_VCO)
{
(void) CLOCK_SourceSetEnable(clkSrcIdx, false);
clkSrcIdx--;
}
g_syslog.sysSleepRecord.pllPwrStat &= (~(1UL << CLOCK_PLL_SYS1));
}
/* Board-level sleep entry */
BOARD_SystemSleepEnter(s_sysSleepMode, s_sysSleepFlags);
/* Process SM LPIs for sleep entry */
(void) CPU_PerLpiProcess(CPU_IDX_M33P, sleepMode);
/* Check the expression values doesn't wrap */
if (DEV_SM_Usec64Get() >= sleepEntryStart)
{
/* Capture sleep entry latency */
g_syslog.sysSleepRecord.sleepEntryUsec =
UINT64_L(DEV_SM_Usec64Get() - sleepEntryStart);
}
else
{
/* Initialize to zero in case of wrap */
g_syslog.sysSleepRecord.sleepEntryUsec = 0U;
}
/* Check SYSCTR system sleep mode flag */
if ((s_sysSleepFlags & DEV_SM_SSF_SYSCTR_ACTIVE_MASK) != 0U)
{
/* Switch SYSCTR to low-freq mode (blocking) */
SYSCTR_FreqMode(true, true);
}
/* Manage FRO based on system sleep flags and active sleep state */
if (((s_sysSleepFlags & DEV_SM_SSF_FRO_ACTIVE_MASK) == 0U) &&
!activeSleep)
{
/* Power down FRO */
FRO->CSR.CLR = FRO_CSR_FROEN_MASK;
}
/* Enter WFI to trigger sleep entry */
__DSB();
/* coverity[misra_c_2012_rule_1_2_violation] */
__WFI();
__ISB();
/* Power up FRO */
FRO->CSR.SET = FRO_CSR_FROEN_MASK;
/* Check SYSCTR system sleep mode flag
*
* NOTE: switch completion required before read of exit timestamp
*/
if ((s_sysSleepFlags & DEV_SM_SSF_SYSCTR_ACTIVE_MASK) != 0U)
{
/* Switch SYSCTR to high-freq mode (blocking) */
SYSCTR_FreqMode(false, true);
}
/* Capture start of sleep exit */
sleepExitStart = DEV_SM_Usec64Get();
/* Capture wake source */
g_syslog.sysSleepRecord.wakeSource =
(SCB->ICSR & SCB_ICSR_VECTPENDING_Msk)
>> SCB_ICSR_VECTPENDING_Pos;
/* Process SM LPIs for sleep exit */
(void) CPU_PerLpiProcess(CPU_IDX_M33P, CPU_SLEEP_MODE_RUN);
/* Board-level sleep exit */
BOARD_SystemSleepExit(s_sysSleepMode, s_sysSleepFlags);
/* Check if sleep performance level requires SYSPLL enable */
if (perfLevelSleep == DEV_SM_PERF_LVL_PRK)
{
/* Power up SYSPLL clock nodes */
uint32_t clkSrcIdx = CLOCK_SRC_SYSPLL1_VCO;
while (clkSrcIdx <= CLOCK_SRC_SYSPLL1_PFD2_DIV2)
{
(void) CLOCK_SourceSetEnable(clkSrcIdx, true);
clkSrcIdx++;
}
}
if (activeSleep)
{
/* Move to system wake performance level */
(void) DEV_SM_PerfSystemWake(perfLevelSleep);
}
else
{
/* Restore ELE and SM clock roots */
for (uint32_t sleepRootIdx = 0U;
sleepRootIdx < DEV_SM_NUM_SLEEP_ROOTS;
sleepRootIdx++)
{
uint32_t rootIdx = s_clkRootSleepList[sleepRootIdx];
/* Restore DIV */
CCM_CTRL->CLOCK_ROOT[rootIdx].CLOCK_ROOT_CONTROL.SET =
s_clkRootCtrl[sleepRootIdx] & CCM_CLOCK_ROOT_DIV_MASK;
/* Restore MUX */
CCM_CTRL->CLOCK_ROOT[rootIdx].CLOCK_ROOT_CONTROL.SET =
s_clkRootCtrl[sleepRootIdx] & CCM_CLOCK_ROOT_MUX_MASK;
}
/* Notify ELE of suspend exit */
ELE_StopDvfsChange();
}
/* Enable bypass for clock sources */
DEV_SM_ClockSourceBypass(true, true);
/* Power up eFUSE */
GPC_GLOBAL->GPC_EFUSE_CTRL = 0U;
/* Restore GPC LP handshakes */
BLK_CTRL_S_AONMIX->LP_HANDSHAKE_SM = lpHsSm;
BLK_CTRL_S_AONMIX->LP_HANDSHAKE2_SM = lpHs2Sm;
BLK_CTRL_S_AONMIX->LP_HANDSHAKE_ELE = lpHsEle;
BLK_CTRL_S_AONMIX->LP_HANDSHAKE2_ELE = lpHs2Ele;
/* If WAKEUPMIX powered down during SUSPEND, force power up */
if (wakeupMixOff)
{
status = DEV_SM_PowerStateSet(DEV_SM_PD_WAKEUP,
DEV_SM_POWER_STATE_ON);
}
/* Check if WAKEUPMIX forced to parked level during LP compute */
if ((status == SM_ERR_SUCCESS) && restoreWakeupMixPerf)
{
/* Restore saved WAKEUPMIX performance level */
status = DEV_SM_PerfLevelSet(DEV_SM_PERF_WAKEUP,
savedWakeupMixPerf);
}
if (status == SM_ERR_SUCCESS)
{
/* If NOCMIX powered down during SUSPEND, force power up */
if (lpmSettingNoc <= sleepMode)
{
status = DEV_SM_PowerStateSet(DEV_SM_PD_NOC,
DEV_SM_POWER_STATE_ON);
}
else
{
/* Reopen DDR access if NOCMIX TRDC is not reloaded */
status = DEV_SM_RdcDdrBlock(false);
}
}
/* Check if DDR retention active */
if (ddrInRetention)
{
if (status == SM_ERR_SUCCESS)
{
/* Power up DDRMIX */
status = DEV_SM_PowerStateSet(DEV_SM_PD_DDR,
DEV_SM_POWER_STATE_ON);
}
if (status == SM_ERR_SUCCESS)
{
/* Take DDR out of retention */
status = DEV_SM_MemDdrRetentionExit();
}
}
/* Restore SM NVIC */
for (uint32_t wakeIdx = 0;
wakeIdx < GPC_CPU_CTRL_CMC_IRQ_WAKEUP_MASK_COUNT;
wakeIdx++)
{
NVIC->ICER[wakeIdx] = 0xFFFFFFFFU;
NVIC->ISER[wakeIdx] = nvicISER[wakeIdx];
}
/* Enable sensor */
(void) DEV_SM_SensorPowerUp(DEV_SM_SENSOR_TEMP_ANA);
/* Board-level sleep unprepare */
BOARD_SystemSleepUnprepare(s_sysSleepMode, s_sysSleepFlags);
}
}
/* Check if system did not sleep */
if (g_syslog.sysSleepRecord.wakeSource == 0U)
{
sleepExitStart = DEV_SM_Usec64Get();
/* Check the expression doesn't wrap */
if (sleepExitStart >= sleepEntryStart)
{
g_syslog.sysSleepRecord.sleepEntryUsec =
UINT64_L(sleepExitStart - sleepEntryStart);
}
else
{
/* Initialize to zero in case of wrap */
g_syslog.sysSleepRecord.sleepEntryUsec = 0U;
}
}
/* Restore GPC wake sources modified during sleep flow */
for (uint32_t cpuIdx = 0U; cpuIdx < CPU_NUM_IDX; cpuIdx++)
{
if (cpuIdx != CPU_IDX_M33P)
{
/* Restore saved GPC wake sources */
for (uint32_t wakeIdx = 0U;
wakeIdx < GPC_CPU_CTRL_CMC_IRQ_WAKEUP_MASK_COUNT;
wakeIdx++)
{
(void) CPU_IrqWakeSet(cpuIdx, wakeIdx,
cpuWakeMask[cpuIdx][wakeIdx]);
}
}
}
/* Check the expression value doesn't wrap */
if (DEV_SM_Usec64Get() >= sleepExitStart)
{
g_syslog.sysSleepRecord.sleepExitUsec =
UINT64_L(DEV_SM_Usec64Get() - sleepExitStart);
}
else
{
/* Initialize to zero in case of wrap */
g_syslog.sysSleepRecord.sleepExitUsec = 0U;
}
return status;
}