zoukankan      html  css  js  c++  java
  • 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();
    }

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

     
  • 相关阅读:
    【BZOJ 2120】 数颜色
    【BZOJ 1878】 HH的项链
    【BZOJ 2038】小Z的袜子
    【BZOJ 2724】 蒲公英
    【POJ 2482】 Stars in Your Windows
    【POJ 2182】Lost Cows
    __align(num) 分析
    C# 获取图片某像素点RGB565值
    基于OpenCV的火焰检测(三)——HSI颜色判据
    基于OpenCV的火焰检测(一)——图像预处理
  • 原文地址:https://www.cnblogs.com/gooogleman/p/1869694.html
Copyright © 2011-2022 走看看