📄 xllp_suspendresume.c
字号:
crsa_sp = pSVC_regs;
pSYS_regs = Xllp_SaveMSARMRegs(crsa_sp, XLLP_CPSR_Mode_SYS);
SYS_words = (crsa_sp - pSYS_regs);
//DBGMSG(("Xllp_SuspendResume: SYS(x%x) saved: x%08x-x%08x, (%d)\r\n",
// XLLP_CPSR_Mode_SYS, crsa_sp, pSYS_regs, SYS_words));
crsa_sp = pSYS_regs;
DBGMSG(("Xllp_SuspendResume: mode specific core registers saved\r\n"));
#if 0 // ENABLE_DEBUG_MESSAGES // debug code
{
int i;
unsigned long *p;
unsigned long words;
p = (unsigned long *)pFIQ_regs;
words = FIQ_words;
DBGMSG(("Xllp_SuspendResume: FIQ@x%08x (%d)\r\n", p, words));
for (i = words-1; i>=0; i--)
DBGMSG((" x%08x:x%08x\r\n", &p[i], p[i]));
p = (unsigned long *)pIRQ_regs;
words = IRQ_words;
DBGMSG(("Xllp_SuspendResume: IRQ@x%08x (%d)\r\n", p, words));
for (i = words-1; i>=0; i--)
DBGMSG((" x%08x:x%08x\r\n", &p[i], p[i]));
p = (unsigned long *)pUND_regs;
words = UND_words;
DBGMSG(("Xllp_SuspendResume: UND@x%08x (%d)\r\n", p, words));
for (i = words-1; i>=0; i--)
DBGMSG((" x%08x:x%08x\r\n", &p[i], p[i]));
p = (unsigned long *)pABT_regs;
words = ABT_words;
DBGMSG(("Xllp_SuspendResume: ABT@x%08x (%d)\r\n", p, words));
for (i = words-1; i>=0; i--)
DBGMSG((" x%08x:x%08x\r\n", &p[i], p[i]));
p = (unsigned long *)pSVC_regs;
words = SVC_words;
DBGMSG(("Xllp_SuspendResume: SVC@x%08x (%d)\r\n", p, words));
for (i = words-1; i>=0; i--)
DBGMSG((" x%08x:x%08x\r\n", &p[i], p[i]));
p = (unsigned long *)pSYS_regs;
words = SYS_words;
DBGMSG(("Xllp_SuspendResume: SYS@x%08x (%d)\r\n", p, words));
for (i = words-1; i>=0; i--)
DBGMSG((" x%08x:x%08x\r\n", &p[i], p[i]));
}
DBGMSG(("Xllp_SuspendResume: After Core Save: ResumePhase2Data=x%08x->x%08x\r\n",
pResumePhase2Data, ResumePhase2DataPA));
#endif // debug code
pMEMCRegs->MDREFR &= ~(0x00080000u );/*xlli_MDREFR_K2DB2*/
pPWRRegs->PSPR = ResumePhase2DataPA;
//----------------------------------------------------------------------------------------------
#ifdef BSP_MAINSTONE
// PGSRn values will most likely be platform dependent.
#if 0
// The following PGSR defined values are what was used in WinCE Ozone (which seemed to work well).
#define PMGR_PGSR0_vals_DFLT ((0x00008800u)| 0xC0000000u) // xlli_GPSR0_value
#define PMGR_PGSR1_vals_DFLT (0x00000002u) // xlli_GPSR1_value
#define PMGR_PGSR2_vals_DFLT (0x0001FC00u) // xlli_GPSR2_value
// Must set AC97 reset line high (deasserted) in PGSR for ACUNIT to work after sleep
// Force all reserved GPIO control bits low
#define PMGR_PGSR3_vals_DFLT (0x00000000u|XLLP_GPIO_BIT_AC97_RESET_n) // xlli_GPSR3_value
#endif
#if 1
// I haven't figured out what all these bits do exactly but they work.
// The alternative used in WinCE Ozone don't work (platform won't wake up)
pPWRRegs->PGSR0 = 0xd02c861b;
pPWRRegs->PGSR1 = 0x03cf5746;
pPWRRegs->PGSR2 = 0x173d4000;
pPWRRegs->PGSR3 = 0x0073ff81;
#else
pPWRRegs->PGSR0 = (0x00008800 | 0xC0000000); // 0xd02c861b;
pPWRRegs->PGSR1 = (0x00000002); //0x03cf5746;
pPWRRegs->PGSR2 = (0x0001FC00); //0x173d4000;
pPWRRegs->PGSR3 = (0x00000000 | XLLP_GPIO_BIT_AC97_RESET_n); //0x0073ff81;
#endif
#endif // BSP_MAINSTONE
pPWRRegs->PWER = 0x80000000; // wake on RTC
// Wakeup sources will eventually be set based on values passed in via the RESTART_DATA structure
// For now they are hardcoded to keypad, touch, RTC alarm, and GPIO0 (card or cable insert/remove)
#ifdef BSP_MAINSTONE
pPWRRegs->PWER |= 0x00000001; // wake on GPIO 0
pPWRRegs->PRER = 0x1; // GPIO0 rising edge enable
pPWRRegs->PFER = 0x1; // GPIO0 falling edge enable
pPWRRegs->PKWR = 0x000FD000; // Enable wake on keypad activity
DBGMSG(("Xllp_SuspendResume: PWER=x%08x->x%08x, PRER=x%08x->x%08x, PFER=x%08x->x%08x, PKWR=x%08x->x%08x\r\n",
PWRSave.PWER, pPWRRegs->PWER
,PWRSave.PRER, pPWRRegs->PRER
,PWRSave.PFER, pPWRRegs->PFER
,PWRSave.PKWR, pPWRRegs->PKWR
));
//pPWRRegs->PCFR = 0x71;
//pPWRRegs->PCFR = 0x61;
pPWRRegs->PSLR |= 0x00100000; // nResetOut prevents FPGA triggered wakeup so set SL_ROD
//pPWRRegs->PSLR = 0xff100008;
DBGMSG(("Xllp_SuspendResume: PCFR=x%08x->x%08x, PSLR=x%08x->x%08x\r\n",
PWRSave.PCFR, pPWRRegs->PCFR, PWRSave.PSLR, pPWRRegs->PSLR));
// For FPGA interrupts to cause wakeup, pending interrupts must be cleared before sleeping.
pBCRegs->PSCR1 = 0; // clear all pending FPGA interrupts
pBCRegs->PIMER1 = (0x25); // enable FPGA interrupt for pen, USB cable, MMC card detect
DBGMSG(("Xllp_SuspendResume: PSCR1=x%08x->x%08x, PIMER1=x%08x->x%08x\r\n",
BCRSave.PSCR1, pBCRegs->PSCR1, BCRSave.PIMER1, pBCRegs->PIMER1));
#else
#endif // BSP_MAINSTONE
//----------------------------------------------------------------------------------------------
SetHexLeds(0xce055555); // won't be visible unless disable fails
DisableHexLeds();
// Allow log messages to be sent before power off
#if (ENABLE_DEBUG_MESSAGES || ENABLE_LOG_MESSAGES)
{
unsigned long t1 = pOSTRegs->oscr0;
while (DIFF_UL(pOSTRegs->oscr0, t1) < (500 * XLLP_OST_TICKS_MS))
;
}
#endif
//========================================================================
Xllp_SuspendAndResumeA(pResumePhase2Data); // goodnight!
//========================================================================
// At this point we've woken up again.
// NOTE!!!
// No log messages should be output until platform restore is complete.
// Attempting to do so will probably crash the system.
// SETHEXLEDS seems to be safe (probably because the boot code inits them).
SetHexLeds(0xce05aaaa);
// Restore CPU Core registers.
// Note that although the regs for all modes were saved prior to power off above,
// we don't restore the core regs for the mode we're currently in (probably SVC).
// Restoring the mode we're in would screw up our current context (particularly SP, LR, and SPSR)
// However SPSR does need to be restored to it's value on entry prior to returning from this function.
{
XLLP_UINT32_T mode = Xllp_Get_ARM_CPSR() & XLLP_CPSR_Mode_Mask;
// We'de better be in the same mode as when we saved state or things will get rather confusing.
if (mode != (entry_CPSR & XLLP_CPSR_Mode_Mask))
{
while(1)
;
}
// Note that although we saved mode specific registers for all modes above,
// we only restore them for modes other than the current mode.
// Current mode registers are restored from the stack just before we return.
if (mode != XLLP_CPSR_Mode_FIQ)
Xllp_RestoreMSARMRegs(pFIQ_regs, XLLP_CPSR_Mode_FIQ);
if (mode != XLLP_CPSR_Mode_IRQ)
Xllp_RestoreMSARMRegs(pIRQ_regs, XLLP_CPSR_Mode_IRQ);
if (mode != XLLP_CPSR_Mode_UND)
Xllp_RestoreMSARMRegs(pUND_regs, XLLP_CPSR_Mode_UND);
if (mode != XLLP_CPSR_Mode_ABT)
Xllp_RestoreMSARMRegs(pABT_regs, XLLP_CPSR_Mode_ABT);
if (mode != XLLP_CPSR_Mode_SVC)
Xllp_RestoreMSARMRegs(pSVC_regs, XLLP_CPSR_Mode_SVC);
if (mode != XLLP_CPSR_Mode_SYS)
Xllp_RestoreMSARMRegs(pSYS_regs, XLLP_CPSR_Mode_SYS);
}
SetHexLeds(0xce05fffe);
// save information so we can (eventually) determine wakeup source.
resume_PWR_PEDR = pPWRRegs->PEDR;
resume_PWR_PKSR = pPWRRegs->PKSR;
#ifdef BSP_MAINSTONE
resume_FPGA_ISCR = pBCRegs->PSCR1;
resume_FPGA_IER = pBCRegs->PIMER1;
#endif // BSP_MAINSTONE
XllpPWRRestore(pPWRRegs, &PWRSave);
XllpCLKRestore(pCLKRegs, &CLKSave);
XllpGPIORestore(pGPIORegs, &GPIOSave);
XllpINTCRestore(pINTCRegs, &INTCSave);
#ifdef BSP_MAINSTONE
{
XLLP_UINT32_T ISCReg;
// FPGA interrupts need to be handled specially because FPGA is powered during suspend.
// If one or more FPGA interrupts is asserted while in suspend mode,
// the interrupt handler will not be called after resume
// unless the interrupts are cleared and re-asserted.
// Save current active interrupts (this will indicate any interrupts that happened while suspended)
ISCReg = pBCRegs->PSCR1;
// clear any active interrupts so they don't fire when IMER1 is restored
pBCRegs->PSCR1 = 0;
// Restore all saved regs except interrupt set/clear reg
XllpBCRRestore(pBCRegs, &BCRSave);
// Re-assert any interrupts active prior to or that occurred while suspended
pBCRegs->PSCR1 = BCRSave.PSCR1 | ISCReg;
}
#endif // BSP_MAINSTONE
SetHexLeds(0xce05fffd);
// XllpIMRestore(IMAddr, IMSave, IMSize);
OSD_ExecuteAfterAllResets();
OSD_DebugCommsResume();
// Log messages should be OK from here on.
SetHexLeds(0xce05fffc);
LOGMSG(("Xllp_SuspendResume: State Restored: ResumePhase2Data=x%08x->x%08x\r\n",
pResumePhase2Data, ResumePhase2DataPA));
// XllpI2cInit((XLLP_I2C_T*)pI2CRegs, (XLLP_GPIO_T*)pGPIORegs, (XLLP_CLKMGR_T*)pCLKRegs, 0);
// XllpOSTRestore(pOSTRegs, &OSTSave);
// WinCE seems to need a timer interrupt to make it's timers work after resume.
if ((entry_OIER & 1) && (entry_OSMR0 != 0))
{
pOSTRegs->osmr0 = entry_OSMR0;
pOSTRegs->oscr0 = entry_OSMR0 - 5;
pOSTRegs->oier |= 1;
while (DIFF_UL(pOSTRegs->osmr0, pOSTRegs->oscr0) >= 0) // wait for match to occur
;
}
SetHexLeds(0xce05fffb);
DBGMSG(("Xllp_SuspendResume: Wake Reason: PEDR=x%08x, PKSR=x%08x, ISCR=x%08x, IER=x%08x\r\n",
resume_PWR_PEDR, resume_PWR_PKSR, resume_FPGA_ISCR, resume_FPGA_IER));
DBGMSG(("Xllp_SuspendResume: Exit: (entry_CPSR=x%08x)\r\n", entry_CPSR));
DBGMSG(("Xllp_SuspendResume: Exit: RCNR=x%08x, RTAR=x%08x, RTSR=x%08x, PICR=x%08x\r\n",
pRTCRegs->rcnr, pRTCRegs->rtar, pRTCRegs->rtsr, pRTCRegs->picr));
DBGMSG(("Xllp_SuspendResume: Exit: RYAR1=x%08x, RDAR1=x%08x\r\n",
pRTCRegs->ryar1, pRTCRegs->rdar1));
DBGMSG(("Xllp_SuspendResume: Exit: OSCR0=x%08x, OSMR0=x%08x, OIER=x%08x\r\n",
pOSTRegs->oscr0, pOSTRegs->osmr0, pOSTRegs->oier));
DBGMSG(("Xllp_SuspendResume: Exit: OMCR4=x%08x, OMCR5=x%08x, OMCR6=x%08x, OMCR7=x%08x\r\n",
pOSTRegs->omcr4, pOSTRegs->omcr5, pOSTRegs->omcr6, pOSTRegs->omcr7));
SetHexLeds(entry_hexleds);
Xllp_Set_ARM_SPSR(entry_SPSR);
Xllp_Set_ARM_CPSR(entry_CPSR);
return(0); // eventually we'll return the wakeup reason
} // Xllp_SuspendAndResume
#if 0
void RtcWakeupSet(UINT32 sec)
{
XLLP_INTC_T *pINTCRegs = (XLLP_INTC_T*)OSD_MapPAtoVA(BULVERDE_BASE_REG_PA_INTC);
XLLP_RTC_T *pRTCRegs = (XLLP_RTC_T*)OSD_MapPAtoVA(BULVERDE_BASE_REG_PA_RTC);
pINTCRegs->icmr &= ~XLLP_INTC_RTCALARM;
// Setup the RTC controller to have the alarm interrupt enabled.
// Testing with current (C0 Bulverde) silicon suggests this isn't essential (RCNR == RTAR seems to cause wakeup anyway).
// ie. wakeup occurs even if the line commented out below is used.
// However, doing this seems intuitive and it does work with current hardware as well.
pRTCRegs->rtsr = (pRTCRegs->rtsr & ~(XLLP_RTSR_MASK | XLLP_RTSR_RESERVED_BITS)) | XLLP_RTSR_ALE;
// v_pRTCReg->rtsr = (v_pRTCReg->rtsr & ~(XLLP_RTSR_ALE));
// Set RTC match register to wake up almost immediately.
pRTCRegs->rtar = pRTCRegs->rcnr + sec ;
}
#endif
//------------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -