您的位置:首页 > 编程语言 > Go语言

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: