2440 休眠唤醒的实现过程(作者:wogoyixikexie@gliet)

2440 休眠唤醒的实现过程(作者:wogoyixikexie@gliet)

 //-----------------------------------------------------------------------------------------------------------

// 作者: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 GwesPowerOffSystem to 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

  1. 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.

  2. 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.
  3. Turn off window message queues, stopping the processing of messages.
  4. Determine if the Startup UI screen needs to appear on resume.
  5. Save video RAM to system RAM is necessary to preserve state on resume.
  6. 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.
  7. 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.
  8. 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函数。

 

      现在来看看OALCPUPowerOff这个函数吧。

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

//------------------------------------------------------------------------------
//
// 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
    OALCPUPowerOff();
  

     // 奇怪,在OALCPUPowerOff里面有个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();
}

//------------------------------------------------------------------------------

 
原文地址:https://www.cnblogs.com/gooogleman/p/1869694.html