2440 休眠唤醒的实现过程(作者:wogoyixikexie@gliet)
2009-03-27 10:03
531 查看
//-----------------------------------------------------------------------------------------------------------
// 作者:wogoyixikexie@gliet
// 版权:桂林电子科技大学一系科协wogoyixikexie@gliet
// 平台:wince5.0 2440 5.0 BSP
// 发布日期:2009年3月27日 9:29:16
// 最后修改:
// 注意事项:未经作者同意,不得在转载的时候擅自修改、删除文章的任何部分
//-----------------------------------------------------------------------------------------------------------
这周开始看电源管理的知识,发现相当复杂,现在先在电源管理的外围走一圈,看看2440的休眠挂起是如何实现的,然后就会好好研究微软提供的PM代码。
一般情况下,PDA、手机都是通过一个按键来实现休眠唤醒的,现在来看看PB帮助文档。
Suspend State
When a device is asked to suspend, it is being asked to remain powered to the point that RAM is in a self-refresh state where an interrupt can wake the device. The suspend process can occur in three ways:
The keyboard driver issues a VK_OFF to GWES. This eventually causes GwesPowerOffSystemto be called.
The OEM can call GwesPowerOffSystem directly.
The OEM can call SetSystemPowerState.
The GwesPowerOff function performs key operations before a device can suspend.
To suspend a device
Notify the Taskbar that the device is being suspended.
Post the WM_POWERBROADCAST message with the flag PBT_APMSUSPEND. Only the registered Taskbar will get this message.
Abort calibration if the calibration screen is up and in one of the following states:
Waiting at cross hairs.
If calibration was waiting at confirmation.
Turn off window message queues, stopping the processing of messages.
Determine if the Startup UI screen needs to appear on resume.
Save video RAM to system RAM is necessary to preserve state on resume.
Call SetSystemPowerState with the arguments (NULL, POWER_STATE_SUSPEND, POWER_FORCE). This calls into the power manager that coordinates the rest of the suspend operation. At this point, GwesPowerOff is not completed until the system resumes.
Power manager performs the following actions:
Calls FileSystemPowerFunction(FSNOTIFY_POWER_OFF) to power off file system drivers.
Calls PowerOffSystem.
Calls Sleep(0) to allow the kernel scheduler to run and perform the final suspend process.
The kernel performs the following final steps to suspend:
Power off GWES process.
Power off Filesys.exe.
If this is an SHx microprocessor, call OEMFlushCache.
Call OEMPowerOff.
我们的键盘是使用IO中断而已,所以我们Call SetSystemPowerState with the arguments (NULL, POWER_STATE_SUSPEND, POWER_FORCE). SetSystemPowerState 函数会调用BSP的OEMPowerOff函数。
//------------------------------------------------------------------------------
//
// Function: OEMPowerOff
//
// Description: Called when the system is to transition to it's lowest
// power mode (off)
//
void OEMPowerOff()
{
static UINT32 saveArea[51];
S3C2440A_INTR_REG *pIntr = (S3C2440A_INTR_REG*)OALPAtoVA(S3C2440A_BASE_REG_PA_INTR, FALSE);
S3C2440A_IOPORT_REG *pIOPort = (S3C2440A_IOPORT_REG*)OALPAtoVA(S3C2440A_BASE_REG_PA_IOPORT, FALSE);
S3C2440A_LCD_REG *pLCD = (S3C2440A_LCD_REG*)OALPAtoVA(S3C2440A_BASE_REG_PA_LCD, FALSE);
// First do platform specific actions
BSPPowerOff();
// Then save system registers
saveArea[0] = INPORT32(&pIOPort->GPACON);
saveArea[1] = INPORT32(&pIOPort->GPADAT);
saveArea[2] = INPORT32(&pIOPort->GPBCON);
saveArea[3] = INPORT32(&pIOPort->GPBDAT);
saveArea[4] = INPORT32(&pIOPort->GPBUP);
saveArea[5] = INPORT32(&pIOPort->GPCCON);
saveArea[6] = INPORT32(&pIOPort->GPCDAT);
saveArea[7] = INPORT32(&pIOPort->GPCUP);
saveArea[8] = INPORT32(&pIOPort->GPDCON);
saveArea[9] = INPORT32(&pIOPort->GPDDAT);
saveArea[10] = INPORT32(&pIOPort->GPDUP);
saveArea[11] = INPORT32(&pIOPort->GPECON);
saveArea[12] = INPORT32(&pIOPort->GPEDAT);
saveArea[13] = INPORT32(&pIOPort->GPEUP);
saveArea[14] = INPORT32(&pIOPort->GPFCON);
saveArea[15] = INPORT32(&pIOPort->GPFDAT);
saveArea[16] = INPORT32(&pIOPort->GPFUP);
saveArea[17] = INPORT32(&pIOPort->GPGCON);
saveArea[18] = INPORT32(&pIOPort->GPGDAT);
saveArea[19] = INPORT32(&pIOPort->GPGUP);
saveArea[20] = INPORT32(&pIOPort->GPHCON);
saveArea[21] = INPORT32(&pIOPort->GPHDAT);
saveArea[22] = INPORT32(&pIOPort->GPHUP);
saveArea[23] = INPORT32(&pIOPort->MISCCR);
saveArea[24] = INPORT32(&pIOPort->DCLKCON);
saveArea[25] = INPORT32(&pIOPort->EXTINT0);
saveArea[26] = INPORT32(&pIOPort->EXTINT1);
saveArea[27] = INPORT32(&pIOPort->EXTINT2);
saveArea[28] = INPORT32(&pIOPort->EINTFLT0);
saveArea[29] = INPORT32(&pIOPort->EINTFLT1);
saveArea[30] = INPORT32(&pIOPort->EINTFLT2);
saveArea[31] = INPORT32(&pIOPort->EINTFLT3);
saveArea[32] = INPORT32(&pIOPort->EINTMASK);
saveArea[33] = INPORT32(&pIntr->INTMOD);
saveArea[34] = INPORT32(&pIntr->INTMSK);
saveArea[35] = INPORT32(&pIntr->INTSUBMSK);
saveArea[36] = INPORT32(&pLCD->TCONSEL);
saveArea[37] = INPORT32(&pLCD->LCDINTMSK);
saveArea[38] = INPORT32(&pLCD->TPAL);
saveArea[39] = INPORT32(&pLCD->DITHMODE);
saveArea[40] = INPORT32(&pLCD->BLUELUT);
saveArea[41] = INPORT32(&pLCD->GREENLUT);
saveArea[42] = INPORT32(&pLCD->REDLUT);
saveArea[43] = INPORT32(&pLCD->LCDSADDR3);
saveArea[44] = INPORT32(&pLCD->LCDSADDR2);
saveArea[45] = INPORT32(&pLCD->LCDSADDR1);
saveArea[46] = INPORT32(&pLCD->LCDCON5);
saveArea[47] = INPORT32(&pLCD->LCDCON4);
saveArea[48] = INPORT32(&pLCD->LCDCON3);
saveArea[49] = INPORT32(&pLCD->LCDCON2);
saveArea[50] = INPORT32(&pLCD->LCDCON1);
pLCD->LCDCON1 = 0;
pLCD->LCDCON2 = 0;
pLCD->LCDCON3 = 0;
pLCD->LCDCON4 = 0;
pLCD->LCDCON5 = 0;
pLCD->LCDSADDR1 = 0;
pLCD->LCDSADDR2 = 0;
pLCD->LCDSADDR3 = 0;
pLCD->TCONSEL = 0;
pLCD->TPAL = 0;
ConfigStopGPIO();//里面根据电路板的连接情况设置IO,把GPF0配置成中断EINT0
// Switch off power for KITL device
OALKitlPowerOff();
// Go to power off mode
//该函数在startup.s使2440真正进入sleep模式,在里面设置好唤醒中断源,并且最后用B.等待中断,一旦产生中断就进入bootloader
[b]OALCPUPowerOff();[/b]
// 奇怪,在[b]OALCPUPowerOff[/b]里面有个B.,一旦产生中断还会回来这里执行下面的吗?如果不会执行那很多寄存器都恢复不了?
// Switch on power for KITL device
OALKitlPowerOn();
/* Recover Process, Load CPU Regs */
OUTPORT32(&pIOPort->GPACON, saveArea[0]);
OUTPORT32(&pIOPort->GPADAT, saveArea[1]);
OUTPORT32(&pIOPort->GPBCON, saveArea[2]);
OUTPORT32(&pIOPort->GPBDAT, saveArea[3]);
OUTPORT32(&pIOPort->GPBUP, saveArea[4]);
OUTPORT32(&pIOPort->GPCCON, saveArea[5]);
OUTPORT32(&pIOPort->GPCDAT, saveArea[6]);
OUTPORT32(&pIOPort->GPCUP, saveArea[7]);
OUTPORT32(&pIOPort->GPDCON, saveArea[8]);
OUTPORT32(&pIOPort->GPDDAT, saveArea[9]);
OUTPORT32(&pIOPort->GPDUP, saveArea[10]);
OUTPORT32(&pIOPort->GPECON, saveArea[11]);
OUTPORT32(&pIOPort->GPEDAT, saveArea[12]);
OUTPORT32(&pIOPort->GPEUP, saveArea[13]);
OUTPORT32(&pIOPort->GPFCON, saveArea[14]);
OUTPORT32(&pIOPort->GPFDAT, saveArea[15]);
OUTPORT32(&pIOPort->GPFUP, saveArea[16]);
OUTPORT32(&pIOPort->GPGCON, saveArea[17]);
OUTPORT32(&pIOPort->GPGDAT, saveArea[18]);
OUTPORT32(&pIOPort->GPGUP, saveArea[19]);
OUTPORT32(&pIOPort->GPHCON, saveArea[20]);
OUTPORT32(&pIOPort->GPHDAT, saveArea[21]);
OUTPORT32(&pIOPort->GPHUP, saveArea[22]);
OUTPORT32(&pIOPort->MISCCR, saveArea[23]);
OUTPORT32(&pIOPort->DCLKCON, saveArea[24]);
OUTPORT32(&pIOPort->EXTINT0, saveArea[25]);
OUTPORT32(&pIOPort->EXTINT1, saveArea[26]);
OUTPORT32(&pIOPort->EXTINT2, saveArea[27]);
OUTPORT32(&pIOPort->EINTFLT0, saveArea[28]);
OUTPORT32(&pIOPort->EINTFLT1, saveArea[29]);
OUTPORT32(&pIOPort->EINTFLT2, saveArea[30]);
OUTPORT32(&pIOPort->EINTFLT3, saveArea[31]);
OUTPORT32(&pIOPort->EINTMASK, saveArea[32]);
OUTPORT32(&pIntr->INTMOD, saveArea[33]);
OUTPORT32(&pIntr->INTMSK, saveArea[34]);
OUTPORT32(&pIntr->INTSUBMSK, saveArea[35]);
pLCD->TCONSEL = saveArea[36];
pLCD->LCDINTMSK = saveArea[37];
pLCD->TPAL = saveArea[38];
pLCD->DITHMODE = saveArea[39];
pLCD->BLUELUT = saveArea[40];
pLCD->GREENLUT = saveArea[41];
pLCD->REDLUT = saveArea[42];
pLCD->LCDSADDR3 = saveArea[43];
pLCD->LCDSADDR2 = saveArea[44];
pLCD->LCDSADDR1 = saveArea[45];
pLCD->LCDCON5 = saveArea[46];
pLCD->LCDCON4 = saveArea[47];
pLCD->LCDCON3 = saveArea[48];
pLCD->LCDCON2 = saveArea[49];
pLCD->LCDCON1 = saveArea[50];
/* Interrupt Clear */
OUTPORT32(&pIOPort->EINTPEND, INPORT32(&pIOPort->EINTPEND));
OUTPORT32(&pIntr->SUBSRCPND, INPORT32(&pIntr->SUBSRCPND));
OUTPORT32(&pIntr->SRCPND, INPORT32(&pIntr->SRCPND));
OUTPORT32(&pIntr->INTPND, INPORT32(&pIntr->INTPND));
pLCD->LCDSRCPND = pLCD->LCDSRCPND;
pLCD->LCDINTPND = pLCD->LCDINTPND;
// Do platform dependent power on actions
BSPPowerOn();
}
//------------------------------------------------------------------------------
现在来看看[b]OALCPUPowerOff[/b]这个函数吧。
C:\WINCE500\PLATFORM\SMDK2440A\Src\Kernel\Oal\startup.s(172): LEAF_ENTRY OALCPUPowerOff
LEAF_ENTRY OALCPUPowerOff
; 1. Push SVC state onto our stack
stmdb sp!, {r4-r12}
stmdb sp!, {lr}
; 2. Save MMU & CPU Register to RAM
ldr r3, =SLEEPDATA_BASE_VIRTUAL ; base of Sleep mode storage
ldr r2, =Awake_address ; store Virtual return address
str r2, [r3], #4
mrc p15, 0, r2, c1, c0, 0 ; load r2 with MMU Control
ldr r0, =MMU_CTL_MASK ; mask off the undefined bits
bic r2, r2, r0
str r2, [r3], #4 ; store MMU Control data
mrc p15, 0, r2, c2, c0, 0 ; load r2 with TTB address.
ldr r0, =MMU_TTB_MASK ; mask off the undefined bits
bic r2, r2, r0
str r2, [r3], #4 ; store TTB address
mrc p15, 0, r2, c3, c0, 0 ; load r2 with domain access control.
str r2, [r3], #4 ; store domain access control
str sp, [r3], #4 ; store SVC stack pointer
mrs r2, spsr
str r2, [r3], #4 ; store SVC status register
mov r1, #Mode_FIQ:OR:I_Bit:OR:F_Bit ; Enter FIQ mode, no interrupts
msr cpsr, r1
mrs r2, spsr
stmia r3!, {r2, r8-r12, sp, lr} ; store the FIQ mode registers
mov r1, #Mode_ABT:OR:I_Bit:OR:F_Bit ; Enter ABT mode, no interrupts
msr cpsr, r1
mrs r0, spsr
stmia r3!, {r0, sp, lr} ; store the ABT mode Registers
mov r1, #Mode_IRQ:OR:I_Bit:OR:F_Bit ; Enter IRQ mode, no interrupts
msr cpsr, r1
mrs r0, spsr
stmia r3!, {r0, sp, lr} ; store the IRQ Mode Registers
mov r1, #Mode_UND:OR:I_Bit:OR:F_Bit ; Enter UND mode, no interrupts
msr cpsr, r1
mrs r0, spsr
stmia r3!, {r0, sp, lr} ; store the UND mode Registers
mov r1, #Mode_SYS:OR:I_Bit:OR:F_Bit ; Enter SYS mode, no interrupts
msr cpsr, r1
stmia r3!, {sp, lr} ; store the SYS mode Registers
mov r1, #Mode_SVC:OR:I_Bit:OR:F_Bit ; Back to SVC mode, no interrupts
msr cpsr, r1
; 3. do Checksum on the Sleepdata
ldr r3, =SLEEPDATA_BASE_VIRTUAL ; get pointer to SLEEPDATA
ldr r2, =0x0
ldr r0, =(SLEEPDATA_SIZE-1) ; get size of data structure (in words)
30
ldr r1, [r3], #4
and r1, r1, #0x1
mov r1, r1, ROR #31
add r2, r2, r1
subs r0, r0, #1
bne %b30
ldr r0, =vGPIOBASE
;;;add r2, r2, #1 ; test checksum of the Sleep data error
str r2, [r0, #oGSTATUS3] ; Store in Power Manager Scratch pad register
ldr r0, =vGPIOBASE
ldr r1, =0x550a
str r1, [r0, #oGPFCON]
ldr r1, =0x30
str r1, [r0, #oGPFDAT]
; 4. Interrupt Disable
ldr r0, =vINTBASE
mvn r2, #0
str r2, [r0, #oINTMSK]
str r2, [r0, #oSRCPND]
str r2, [r0, #oINTPND]
;; 5. Cache Flush
bl OALClearUTLB
bl OALFlushICache
ldr r0, = (DCACHE_LINES_PER_SET - 1)
ldr r1, = (DCACHE_NUM_SETS - 1)
ldr r2, = DCACHE_SET_INDEX_BIT
ldr r3, = DCACHE_LINE_SIZE
bl OALFlushDCache
; 6. Setting Wakeup External Interrupt(EINT0,1,2) Mode
ldr r0, =vGPIOBASE
ldr r1, =0x550a
str r1, [r0, #oGPFCON]
; ldr r1, =0x55550100
; str r1, [r0, #oGPGCON]
; 7. Go to Power-Off Mode
ldr r0, =vMISCCR ; hit the TLB
ldr r0, [r0]
ldr r0, =vCLKCON
ldr r0, [r0]
ldr r0, =vREFRESH
ldr r1, [r0] ; r1=rREFRESH
orr r1, r1, #(1 << 22)
ldr r2, =vMISCCR
ldr r3, [r2]
orr r3, r3, #(3<<17) ; Make sure that SCLK0:SCLK->0, SCLK1:SCLK->0, SCKE=L during boot-up
bic r3, r3, #(7<<20)
orr r3, r3, #(6<<20)
ldr r4, =vCLKCON
ldr r5, =0x1ffff8 ; Power Off Mode
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Sometimes it is not working in cache mode. So I modify to jump to ROM area.
;
;;; ldr r6, =0x92000000 ; make address to 0x9200 0020
;;; add r6, r6, #0x20 ;
;;; mov pc, r6 ; jump to Power off code in ROM
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
b SelfRefreshAndPowerOff
ALIGN 32 ; for I-Cache Line(32Byte, 8 Word)
SelfRefreshAndPowerOff ; run with Instruction Cache's code
str r1, [r0] ; Enable SDRAM self-refresh
str r3, [r2] ; MISCCR Setting
str r5, [r4] ; Power Off !!
b .
;;; LTORG
; This point is called from EBOOT's startup code(MMU is enabled)
; in this routine, left information(REGs, INTMSK, INTSUBMSK ...)
Awake_address
; 1. Recover CPU Registers
ldr r3, =SLEEPDATA_BASE_VIRTUAL ; Sleep mode information data structure
add r2, r3, #SleepState_FIQ_SPSR
mov r1, #Mode_FIQ:OR:I_Bit:OR:F_Bit ; Enter FIQ mode, no interrupts - also FIQ
msr cpsr, r1
ldr r0, [r2], #4
msr spsr, r0
ldr r8, [r2], #4
ldr r9, [r2], #4
ldr r10, [r2], #4
ldr r11, [r2], #4
ldr r12, [r2], #4
ldr sp, [r2], #4
ldr lr, [r2], #4
mov r1, #Mode_ABT:OR:I_Bit ; Enter ABT mode, no interrupts
msr cpsr, r1
ldr r0, [r2], #4
msr spsr, r0
ldr sp, [r2], #4
ldr lr, [r2], #4
mov r1, #Mode_IRQ:OR:I_Bit ; Enter IRQ mode, no interrupts
msr cpsr, r1
ldr r0, [r2], #4
msr spsr, r0
ldr sp, [r2], #4
ldr lr, [r2], #4
mov r1, #Mode_UND:OR:I_Bit ; Enter UND mode, no interrupts
msr cpsr, r1
ldr r0, [r2], #4
msr spsr, r0
ldr sp, [r2], #4
ldr lr, [r2], #4
mov r1, #Mode_SYS:OR:I_Bit ; Enter SYS mode, no interrupts
msr cpsr, r1
ldr sp, [r2], #4
ldr lr, [r2]
mov r1, #Mode_SVC:OR:I_Bit ; Enter SVC mode, no interrupts - FIQ is available
msr cpsr, r1
ldr r0, [r3, #SleepState_SVC_SPSR]
msr spsr, r0
; 2. Recover Last mode's REG's, & go back to caller of OALCPUPowerOff()
ldr sp, [r3, #SleepState_SVC_SP]
ldr lr, [sp], #4
ldmia sp!, {r4-r12}
mov pc, lr ; and now back to our sponsors
ENTRY_END
// 作者:wogoyixikexie@gliet
// 版权:桂林电子科技大学一系科协wogoyixikexie@gliet
// 平台:wince5.0 2440 5.0 BSP
// 发布日期:2009年3月27日 9:29:16
// 最后修改:
// 注意事项:未经作者同意,不得在转载的时候擅自修改、删除文章的任何部分
//-----------------------------------------------------------------------------------------------------------
这周开始看电源管理的知识,发现相当复杂,现在先在电源管理的外围走一圈,看看2440的休眠挂起是如何实现的,然后就会好好研究微软提供的PM代码。
一般情况下,PDA、手机都是通过一个按键来实现休眠唤醒的,现在来看看PB帮助文档。
Suspend State
When a device is asked to suspend, it is being asked to remain powered to the point that RAM is in a self-refresh state where an interrupt can wake the device. The suspend process can occur in three ways:
The keyboard driver issues a VK_OFF to GWES. This eventually causes GwesPowerOffSystemto be called.
The OEM can call GwesPowerOffSystem directly.
The OEM can call SetSystemPowerState.
The GwesPowerOff function performs key operations before a device can suspend.
To suspend a device
Notify the Taskbar that the device is being suspended.
Post the WM_POWERBROADCAST message with the flag PBT_APMSUSPEND. Only the registered Taskbar will get this message.
Abort calibration if the calibration screen is up and in one of the following states:
Waiting at cross hairs.
If calibration was waiting at confirmation.
Turn off window message queues, stopping the processing of messages.
Determine if the Startup UI screen needs to appear on resume.
Save video RAM to system RAM is necessary to preserve state on resume.
Call SetSystemPowerState with the arguments (NULL, POWER_STATE_SUSPEND, POWER_FORCE). This calls into the power manager that coordinates the rest of the suspend operation. At this point, GwesPowerOff is not completed until the system resumes.
Power manager performs the following actions:
Calls FileSystemPowerFunction(FSNOTIFY_POWER_OFF) to power off file system drivers.
Calls PowerOffSystem.
Calls Sleep(0) to allow the kernel scheduler to run and perform the final suspend process.
The kernel performs the following final steps to suspend:
Power off GWES process.
Power off Filesys.exe.
If this is an SHx microprocessor, call OEMFlushCache.
Call OEMPowerOff.
我们的键盘是使用IO中断而已,所以我们Call SetSystemPowerState with the arguments (NULL, POWER_STATE_SUSPEND, POWER_FORCE). SetSystemPowerState 函数会调用BSP的OEMPowerOff函数。
//------------------------------------------------------------------------------
//
// Function: OEMPowerOff
//
// Description: Called when the system is to transition to it's lowest
// power mode (off)
//
void OEMPowerOff()
{
static UINT32 saveArea[51];
S3C2440A_INTR_REG *pIntr = (S3C2440A_INTR_REG*)OALPAtoVA(S3C2440A_BASE_REG_PA_INTR, FALSE);
S3C2440A_IOPORT_REG *pIOPort = (S3C2440A_IOPORT_REG*)OALPAtoVA(S3C2440A_BASE_REG_PA_IOPORT, FALSE);
S3C2440A_LCD_REG *pLCD = (S3C2440A_LCD_REG*)OALPAtoVA(S3C2440A_BASE_REG_PA_LCD, FALSE);
// First do platform specific actions
BSPPowerOff();
// Then save system registers
saveArea[0] = INPORT32(&pIOPort->GPACON);
saveArea[1] = INPORT32(&pIOPort->GPADAT);
saveArea[2] = INPORT32(&pIOPort->GPBCON);
saveArea[3] = INPORT32(&pIOPort->GPBDAT);
saveArea[4] = INPORT32(&pIOPort->GPBUP);
saveArea[5] = INPORT32(&pIOPort->GPCCON);
saveArea[6] = INPORT32(&pIOPort->GPCDAT);
saveArea[7] = INPORT32(&pIOPort->GPCUP);
saveArea[8] = INPORT32(&pIOPort->GPDCON);
saveArea[9] = INPORT32(&pIOPort->GPDDAT);
saveArea[10] = INPORT32(&pIOPort->GPDUP);
saveArea[11] = INPORT32(&pIOPort->GPECON);
saveArea[12] = INPORT32(&pIOPort->GPEDAT);
saveArea[13] = INPORT32(&pIOPort->GPEUP);
saveArea[14] = INPORT32(&pIOPort->GPFCON);
saveArea[15] = INPORT32(&pIOPort->GPFDAT);
saveArea[16] = INPORT32(&pIOPort->GPFUP);
saveArea[17] = INPORT32(&pIOPort->GPGCON);
saveArea[18] = INPORT32(&pIOPort->GPGDAT);
saveArea[19] = INPORT32(&pIOPort->GPGUP);
saveArea[20] = INPORT32(&pIOPort->GPHCON);
saveArea[21] = INPORT32(&pIOPort->GPHDAT);
saveArea[22] = INPORT32(&pIOPort->GPHUP);
saveArea[23] = INPORT32(&pIOPort->MISCCR);
saveArea[24] = INPORT32(&pIOPort->DCLKCON);
saveArea[25] = INPORT32(&pIOPort->EXTINT0);
saveArea[26] = INPORT32(&pIOPort->EXTINT1);
saveArea[27] = INPORT32(&pIOPort->EXTINT2);
saveArea[28] = INPORT32(&pIOPort->EINTFLT0);
saveArea[29] = INPORT32(&pIOPort->EINTFLT1);
saveArea[30] = INPORT32(&pIOPort->EINTFLT2);
saveArea[31] = INPORT32(&pIOPort->EINTFLT3);
saveArea[32] = INPORT32(&pIOPort->EINTMASK);
saveArea[33] = INPORT32(&pIntr->INTMOD);
saveArea[34] = INPORT32(&pIntr->INTMSK);
saveArea[35] = INPORT32(&pIntr->INTSUBMSK);
saveArea[36] = INPORT32(&pLCD->TCONSEL);
saveArea[37] = INPORT32(&pLCD->LCDINTMSK);
saveArea[38] = INPORT32(&pLCD->TPAL);
saveArea[39] = INPORT32(&pLCD->DITHMODE);
saveArea[40] = INPORT32(&pLCD->BLUELUT);
saveArea[41] = INPORT32(&pLCD->GREENLUT);
saveArea[42] = INPORT32(&pLCD->REDLUT);
saveArea[43] = INPORT32(&pLCD->LCDSADDR3);
saveArea[44] = INPORT32(&pLCD->LCDSADDR2);
saveArea[45] = INPORT32(&pLCD->LCDSADDR1);
saveArea[46] = INPORT32(&pLCD->LCDCON5);
saveArea[47] = INPORT32(&pLCD->LCDCON4);
saveArea[48] = INPORT32(&pLCD->LCDCON3);
saveArea[49] = INPORT32(&pLCD->LCDCON2);
saveArea[50] = INPORT32(&pLCD->LCDCON1);
pLCD->LCDCON1 = 0;
pLCD->LCDCON2 = 0;
pLCD->LCDCON3 = 0;
pLCD->LCDCON4 = 0;
pLCD->LCDCON5 = 0;
pLCD->LCDSADDR1 = 0;
pLCD->LCDSADDR2 = 0;
pLCD->LCDSADDR3 = 0;
pLCD->TCONSEL = 0;
pLCD->TPAL = 0;
ConfigStopGPIO();//里面根据电路板的连接情况设置IO,把GPF0配置成中断EINT0
// Switch off power for KITL device
OALKitlPowerOff();
// Go to power off mode
//该函数在startup.s使2440真正进入sleep模式,在里面设置好唤醒中断源,并且最后用B.等待中断,一旦产生中断就进入bootloader
[b]OALCPUPowerOff();[/b]
// 奇怪,在[b]OALCPUPowerOff[/b]里面有个B.,一旦产生中断还会回来这里执行下面的吗?如果不会执行那很多寄存器都恢复不了?
// Switch on power for KITL device
OALKitlPowerOn();
/* Recover Process, Load CPU Regs */
OUTPORT32(&pIOPort->GPACON, saveArea[0]);
OUTPORT32(&pIOPort->GPADAT, saveArea[1]);
OUTPORT32(&pIOPort->GPBCON, saveArea[2]);
OUTPORT32(&pIOPort->GPBDAT, saveArea[3]);
OUTPORT32(&pIOPort->GPBUP, saveArea[4]);
OUTPORT32(&pIOPort->GPCCON, saveArea[5]);
OUTPORT32(&pIOPort->GPCDAT, saveArea[6]);
OUTPORT32(&pIOPort->GPCUP, saveArea[7]);
OUTPORT32(&pIOPort->GPDCON, saveArea[8]);
OUTPORT32(&pIOPort->GPDDAT, saveArea[9]);
OUTPORT32(&pIOPort->GPDUP, saveArea[10]);
OUTPORT32(&pIOPort->GPECON, saveArea[11]);
OUTPORT32(&pIOPort->GPEDAT, saveArea[12]);
OUTPORT32(&pIOPort->GPEUP, saveArea[13]);
OUTPORT32(&pIOPort->GPFCON, saveArea[14]);
OUTPORT32(&pIOPort->GPFDAT, saveArea[15]);
OUTPORT32(&pIOPort->GPFUP, saveArea[16]);
OUTPORT32(&pIOPort->GPGCON, saveArea[17]);
OUTPORT32(&pIOPort->GPGDAT, saveArea[18]);
OUTPORT32(&pIOPort->GPGUP, saveArea[19]);
OUTPORT32(&pIOPort->GPHCON, saveArea[20]);
OUTPORT32(&pIOPort->GPHDAT, saveArea[21]);
OUTPORT32(&pIOPort->GPHUP, saveArea[22]);
OUTPORT32(&pIOPort->MISCCR, saveArea[23]);
OUTPORT32(&pIOPort->DCLKCON, saveArea[24]);
OUTPORT32(&pIOPort->EXTINT0, saveArea[25]);
OUTPORT32(&pIOPort->EXTINT1, saveArea[26]);
OUTPORT32(&pIOPort->EXTINT2, saveArea[27]);
OUTPORT32(&pIOPort->EINTFLT0, saveArea[28]);
OUTPORT32(&pIOPort->EINTFLT1, saveArea[29]);
OUTPORT32(&pIOPort->EINTFLT2, saveArea[30]);
OUTPORT32(&pIOPort->EINTFLT3, saveArea[31]);
OUTPORT32(&pIOPort->EINTMASK, saveArea[32]);
OUTPORT32(&pIntr->INTMOD, saveArea[33]);
OUTPORT32(&pIntr->INTMSK, saveArea[34]);
OUTPORT32(&pIntr->INTSUBMSK, saveArea[35]);
pLCD->TCONSEL = saveArea[36];
pLCD->LCDINTMSK = saveArea[37];
pLCD->TPAL = saveArea[38];
pLCD->DITHMODE = saveArea[39];
pLCD->BLUELUT = saveArea[40];
pLCD->GREENLUT = saveArea[41];
pLCD->REDLUT = saveArea[42];
pLCD->LCDSADDR3 = saveArea[43];
pLCD->LCDSADDR2 = saveArea[44];
pLCD->LCDSADDR1 = saveArea[45];
pLCD->LCDCON5 = saveArea[46];
pLCD->LCDCON4 = saveArea[47];
pLCD->LCDCON3 = saveArea[48];
pLCD->LCDCON2 = saveArea[49];
pLCD->LCDCON1 = saveArea[50];
/* Interrupt Clear */
OUTPORT32(&pIOPort->EINTPEND, INPORT32(&pIOPort->EINTPEND));
OUTPORT32(&pIntr->SUBSRCPND, INPORT32(&pIntr->SUBSRCPND));
OUTPORT32(&pIntr->SRCPND, INPORT32(&pIntr->SRCPND));
OUTPORT32(&pIntr->INTPND, INPORT32(&pIntr->INTPND));
pLCD->LCDSRCPND = pLCD->LCDSRCPND;
pLCD->LCDINTPND = pLCD->LCDINTPND;
// Do platform dependent power on actions
BSPPowerOn();
}
//------------------------------------------------------------------------------
现在来看看[b]OALCPUPowerOff[/b]这个函数吧。
C:\WINCE500\PLATFORM\SMDK2440A\Src\Kernel\Oal\startup.s(172): LEAF_ENTRY OALCPUPowerOff
LEAF_ENTRY OALCPUPowerOff
; 1. Push SVC state onto our stack
stmdb sp!, {r4-r12}
stmdb sp!, {lr}
; 2. Save MMU & CPU Register to RAM
ldr r3, =SLEEPDATA_BASE_VIRTUAL ; base of Sleep mode storage
ldr r2, =Awake_address ; store Virtual return address
str r2, [r3], #4
mrc p15, 0, r2, c1, c0, 0 ; load r2 with MMU Control
ldr r0, =MMU_CTL_MASK ; mask off the undefined bits
bic r2, r2, r0
str r2, [r3], #4 ; store MMU Control data
mrc p15, 0, r2, c2, c0, 0 ; load r2 with TTB address.
ldr r0, =MMU_TTB_MASK ; mask off the undefined bits
bic r2, r2, r0
str r2, [r3], #4 ; store TTB address
mrc p15, 0, r2, c3, c0, 0 ; load r2 with domain access control.
str r2, [r3], #4 ; store domain access control
str sp, [r3], #4 ; store SVC stack pointer
mrs r2, spsr
str r2, [r3], #4 ; store SVC status register
mov r1, #Mode_FIQ:OR:I_Bit:OR:F_Bit ; Enter FIQ mode, no interrupts
msr cpsr, r1
mrs r2, spsr
stmia r3!, {r2, r8-r12, sp, lr} ; store the FIQ mode registers
mov r1, #Mode_ABT:OR:I_Bit:OR:F_Bit ; Enter ABT mode, no interrupts
msr cpsr, r1
mrs r0, spsr
stmia r3!, {r0, sp, lr} ; store the ABT mode Registers
mov r1, #Mode_IRQ:OR:I_Bit:OR:F_Bit ; Enter IRQ mode, no interrupts
msr cpsr, r1
mrs r0, spsr
stmia r3!, {r0, sp, lr} ; store the IRQ Mode Registers
mov r1, #Mode_UND:OR:I_Bit:OR:F_Bit ; Enter UND mode, no interrupts
msr cpsr, r1
mrs r0, spsr
stmia r3!, {r0, sp, lr} ; store the UND mode Registers
mov r1, #Mode_SYS:OR:I_Bit:OR:F_Bit ; Enter SYS mode, no interrupts
msr cpsr, r1
stmia r3!, {sp, lr} ; store the SYS mode Registers
mov r1, #Mode_SVC:OR:I_Bit:OR:F_Bit ; Back to SVC mode, no interrupts
msr cpsr, r1
; 3. do Checksum on the Sleepdata
ldr r3, =SLEEPDATA_BASE_VIRTUAL ; get pointer to SLEEPDATA
ldr r2, =0x0
ldr r0, =(SLEEPDATA_SIZE-1) ; get size of data structure (in words)
30
ldr r1, [r3], #4
and r1, r1, #0x1
mov r1, r1, ROR #31
add r2, r2, r1
subs r0, r0, #1
bne %b30
ldr r0, =vGPIOBASE
;;;add r2, r2, #1 ; test checksum of the Sleep data error
str r2, [r0, #oGSTATUS3] ; Store in Power Manager Scratch pad register
ldr r0, =vGPIOBASE
ldr r1, =0x550a
str r1, [r0, #oGPFCON]
ldr r1, =0x30
str r1, [r0, #oGPFDAT]
; 4. Interrupt Disable
ldr r0, =vINTBASE
mvn r2, #0
str r2, [r0, #oINTMSK]
str r2, [r0, #oSRCPND]
str r2, [r0, #oINTPND]
;; 5. Cache Flush
bl OALClearUTLB
bl OALFlushICache
ldr r0, = (DCACHE_LINES_PER_SET - 1)
ldr r1, = (DCACHE_NUM_SETS - 1)
ldr r2, = DCACHE_SET_INDEX_BIT
ldr r3, = DCACHE_LINE_SIZE
bl OALFlushDCache
; 6. Setting Wakeup External Interrupt(EINT0,1,2) Mode
ldr r0, =vGPIOBASE
ldr r1, =0x550a
str r1, [r0, #oGPFCON]
; ldr r1, =0x55550100
; str r1, [r0, #oGPGCON]
; 7. Go to Power-Off Mode
ldr r0, =vMISCCR ; hit the TLB
ldr r0, [r0]
ldr r0, =vCLKCON
ldr r0, [r0]
ldr r0, =vREFRESH
ldr r1, [r0] ; r1=rREFRESH
orr r1, r1, #(1 << 22)
ldr r2, =vMISCCR
ldr r3, [r2]
orr r3, r3, #(3<<17) ; Make sure that SCLK0:SCLK->0, SCLK1:SCLK->0, SCKE=L during boot-up
bic r3, r3, #(7<<20)
orr r3, r3, #(6<<20)
ldr r4, =vCLKCON
ldr r5, =0x1ffff8 ; Power Off Mode
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Sometimes it is not working in cache mode. So I modify to jump to ROM area.
;
;;; ldr r6, =0x92000000 ; make address to 0x9200 0020
;;; add r6, r6, #0x20 ;
;;; mov pc, r6 ; jump to Power off code in ROM
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
b SelfRefreshAndPowerOff
ALIGN 32 ; for I-Cache Line(32Byte, 8 Word)
SelfRefreshAndPowerOff ; run with Instruction Cache's code
str r1, [r0] ; Enable SDRAM self-refresh
str r3, [r2] ; MISCCR Setting
str r5, [r4] ; Power Off !!
b .
;;; LTORG
; This point is called from EBOOT's startup code(MMU is enabled)
; in this routine, left information(REGs, INTMSK, INTSUBMSK ...)
Awake_address
; 1. Recover CPU Registers
ldr r3, =SLEEPDATA_BASE_VIRTUAL ; Sleep mode information data structure
add r2, r3, #SleepState_FIQ_SPSR
mov r1, #Mode_FIQ:OR:I_Bit:OR:F_Bit ; Enter FIQ mode, no interrupts - also FIQ
msr cpsr, r1
ldr r0, [r2], #4
msr spsr, r0
ldr r8, [r2], #4
ldr r9, [r2], #4
ldr r10, [r2], #4
ldr r11, [r2], #4
ldr r12, [r2], #4
ldr sp, [r2], #4
ldr lr, [r2], #4
mov r1, #Mode_ABT:OR:I_Bit ; Enter ABT mode, no interrupts
msr cpsr, r1
ldr r0, [r2], #4
msr spsr, r0
ldr sp, [r2], #4
ldr lr, [r2], #4
mov r1, #Mode_IRQ:OR:I_Bit ; Enter IRQ mode, no interrupts
msr cpsr, r1
ldr r0, [r2], #4
msr spsr, r0
ldr sp, [r2], #4
ldr lr, [r2], #4
mov r1, #Mode_UND:OR:I_Bit ; Enter UND mode, no interrupts
msr cpsr, r1
ldr r0, [r2], #4
msr spsr, r0
ldr sp, [r2], #4
ldr lr, [r2], #4
mov r1, #Mode_SYS:OR:I_Bit ; Enter SYS mode, no interrupts
msr cpsr, r1
ldr sp, [r2], #4
ldr lr, [r2]
mov r1, #Mode_SVC:OR:I_Bit ; Enter SVC mode, no interrupts - FIQ is available
msr cpsr, r1
ldr r0, [r3, #SleepState_SVC_SPSR]
msr spsr, r0
; 2. Recover Last mode's REG's, & go back to caller of OALCPUPowerOff()
ldr sp, [r3, #SleepState_SVC_SP]
ldr lr, [sp], #4
ldmia sp!, {r4-r12}
mov pc, lr ; and now back to our sponsors
ENTRY_END
相关文章推荐
- 2440 休眠唤醒的实现过程(作者:wogoyixikexie@gliet)
- 如何实现2440软件重启/software reset(作者:wogoyixikexie@gliet)
- wince 5.0 .2440 5.0BSP的中断过程(作者:wogoyixikexie@gliet)
- 如何实现2440软件重启/software reset(作者:wogoyixikexie@gliet)
- 如何实现2440软件重启/software reset(作者:wogoyixikexie@gliet)
- 转:wince 5.0 .2440 5.0BSP的中断过程(作者:wogoyixikexie@gliet)
- wince 5.0 .2440 5.0BSP的中断过程(作者:wogoyixikexie@gliet)
- 2440 5.0BSP触摸屏驱动学习(作者:wogoyixikexie@gliet)
- wince 2440串口驱动PDD分析(作者:wogoyixikexie@gliet)
- 2440 外部串口驱动调试(作者:wogoyixikexie@gliet)
- 2440 OV2640 200W摄像头驱动调试(作者:wogoyixikexie@gliet)
- 2440 5.0BSP增加三串口(作者:wogoyixikexie@gliet)
- 2440 中断优先级问题(作者wogoyixikexie@gliet)
- 从makeimg.out文件看PB打包过程(作者:wogoyixikexie@gliet)
- 从build.log文件了解wince编译过程(作者:wogoyixikexie@gliet)
- 2440 5.0BSP触摸屏驱动学习(作者:wogoyixikexie@gliet)
- 如何实现OV9650摄像头拍照(作者gooogleman/wogoyixikexie@gliet)
- 2440 5.0BSP触摸屏驱动学习(作者:wogoyixikexie@gliet)
- 如何实现OV9650摄像头拍照(作者gooogleman/wogoyixikexie@gliet)
- wince串口打印函数是如何实现的?(作者wogoyixikexie@gliet)