现在的位置: 首页 > 综合 > 正文

标准linu休眠和唤醒机制分析(四)

2013年12月09日 ⁄ 综合 ⁄ 共 5791字 ⁄ 字号 评论关闭

suspend第三、四、五阶段:platformprocessorcore

static int suspend_enter(suspend_state_t state)

{

       int error;

 

       if (suspend_ops->prepare) {

 // 平台特定的函数,mtkpm.c, 有定义,对pmiccpu dll的一些设置

              error = suspend_ops->prepare();

              if (error)

                     return error;

       }

 

       error = dpm_suspend_noirq(PMSG_SUSPEND);

// 对于一些non-sysdev devices,需要调用禁止中断的dpm_suspend函数来suspend那些设备

       if (error) {

              printk(KERN_ERR "PM: Some devices failed to power down/n");

              goto Platfrom_finish;

       }

 

       if (suspend_ops->prepare_late) { // 这里没定义

              error = suspend_ops->prepare_late();

              if (error)

                     goto Power_up_devices;

       }

 

       if (suspend_test(TEST_PLATFORM))       // suspend3阶段到此为止

              goto Platform_wake;

 

       error = disable_nonboot_cpus();  // disable nonboot cpus

       if (error || suspend_test(TEST_CPUS))  // suspend4阶段到此为止

              goto Enable_cpus;

 

       arch_suspend_disable_irqs();             // 中断禁止

       BUG_ON(!irqs_disabled());

 

       error = sysdev_suspend(PMSG_SUSPEND);    // kernel/driver/base/sys.c

  // suspend system devices

       if (!error) {

              if (!suspend_test(TEST_CORE))               // suspend5阶段到此为止

                     error = suspend_ops->enter(state);           

// 真正才进入suspend,调用的函数时平台特定的suspend enter函数, //  mtkpm.c, 在下面列出mtk平台的该函数实现,供分析:

                     //  如果有唤醒源被操作,那么处理将会被wakeup,先做一些平台相                         //  关的动作,最后从函数suspend_ops->enter()中返回,这之后的唤                          // 醒操作实际上是按照suspend流程的相反顺序的来走的。

sysdev_resume();         // resuem system devices

// 跳到本文档最后面,将会有一个总结,这里会展示出正常的suspendresume的时候函数调用

       }

 

       arch_suspend_enable_irqs();

       BUG_ON(irqs_disabled());

 

 Enable_cpus:

       enable_nonboot_cpus();

 

 Platform_wake:

       if (suspend_ops->wake)       // 平台无定义

              suspend_ops->wake();

 

 Power_up_devices:

       dpm_resume_noirq(PMSG_RESUME);

 

 Platfrom_finish:

       if (suspend_ops->finish) // 做和函数suspend_ops->prepare()相反的工作

              suspend_ops->finish();

 

       return error;

}

 

static int mtk_pm_enter(suspend_state_t state)

{

       _Chip_pm_enter(state);

       return 0;

}

 

int _Chip_pm_enter(suspend_state_t state)

{

       MSG_FUNC_ENTRY();

       printk("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@/n");

       printk("_Chip_pm_enter @@@@@@@@@@@@@@@@@@@@@@/n");

       printk(" @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@/n");

 

       /* ensure the debug is initialised (if enabled) */

       switch (state)

       {

           case PM_SUSPEND_ON:

                  MSG(SUSP,"mt6516_pm_enter PM_SUSPEND_ON/n/r");

                  break;

           case PM_SUSPEND_STANDBY:

                  MSG(SUSP,"mt6516_pm_enter PM_SUSPEND_STANDBY/n/r");       

                  break;

           case PM_SUSPEND_MEM:  // 只支持mem的系统省电模式

                  MSG(SUSP,"mt6516_pm_enter PM_SUSPEND_MEM/n/r");

            if (g_ChipVer == CHIP_VER_ECO_2)

                   mt6516_pm_SuspendEnter(); 

// cpu进入省电模式的函数,真正休眠之后,执行的代码会停在这个函数中,直到外部有EINT将其cpu唤醒,停下来的代码才继续执行,也就是正常按下了唤醒键的时候。

                  break;

           case PM_SUSPEND_MAX:

                  MSG(SUSP,"mt6516_pm_enter PM_SUSPEND_MAX/n/r");       

                  MSG(SUSP,"Not support for MT6516/n/r");                      

                  break;

                 

           default:

               MSG(SUSP,"mt6516_pm_enter Error state/n/r");

                  break;

       }

       return 0;

}

 

void mt6516_pm_SuspendEnter(void)

{

    UINT32 u32TCM = 0xF0400000;

    UINT32 u4SuspendAddr = 0;

    UINT32 u4Status, u4BATVol;

       UINT32 counter = 0;

 

    /* Check Chip Version*/

    if (g_ChipVer == CHIP_VER_ECO_1)

        u4SuspendAddr = u32TCM;

    else if(g_ChipVer == CHIP_VER_ECO_2)

        u4SuspendAddr = __virt_to_phys((unsigned long)MT6516_CPUSuspend);

 

       /*wifi low power optimization : shutdown MCPLL & VSDIO */

    wifi_lowpower_opt(TRUE);

 

    /* Check PM related register*/

    mt6516_pm_RegDump();

    //mt6326_check_power();

 

       DRV_WriteReg32(APMCUSYS_PDN_SET0,0x04200000);  

 

/* STEP7: Set AP_SM_CNF(DxF003C22C) to wanted wake-up source. 设置唤醒源*/

#if defined(PLATFORM_EVB)

              mt6516_pm_SetWakeSrc((1<< WS_KP)|(1<<WS_EINT)|(1<<WS_RTC));

#elif defined(PMIC_BL_SETTING)

              mt6516_pm_SetWakeSrc((1<<                      

WS_KP)|(1<<WS_EINT)|(1<<WS_CCIF)|(1<<WS_SM)|(1<<WS_RTC));

#else

       mt6516_pm_SetWakeSrc((1<<WS_EINT)|(1<<WS_CCIF)|(1<<WS_SM)|(1<<WS_RTC));

              //mt6516_pm_SetWakeSrc((1<<WS_SM));     

#endif

 

       /* Save interrupt masks*/

    irqMask_L = *MT6516_IRQ_MASKL;

    irqMask_H = *MT6516_IRQ_MASKH;

    mt6516_pm_Maskinterrupt(); // 20100316 James

       while(1)

       {

#ifdef AP_MD_EINT_SHARE_DATA

    /* Update Sleep flag*/

       mt6516_EINT_SetMDShareInfo();

       mt6516_pm_SleepWorkAround();

#endif

    /* Enter suspend mode, mt6516_slpctrl.s */

       if ( g_Sleep_lock <= 0 )

           u4Status = MT6516_CPUSuspend (u4SuspendAddr, u32TCM);

       else

        MSG(SUSP,"Someone lock sleep/n/r");

             

#ifdef AP_MD_EINT_SHARE_DATA

       mt6516_pm_SleepWorkAroundUp();

#endif

 

    /* Check Sleep status*/

    u4Status = mt6516_pm_CheckStatus();

       if (u4Status == RET_WAKE_TIMEOUT)

       {

#ifndef PLATFORM_EVB

              DRV_WriteReg32(APMCUSYS_PDN_CLR0,0x04200000);         

              u4BATVol = (mt6516_pm_GetOneChannelValue(VBAT_CHANNEL,VBAT_COUNT)/VBAT_COUNT);          

              DRV_WriteReg32(APMCUSYS_PDN_SET0,0x04200000);         

              MSG(SUSP,"counter = %d, vbat = %d/n/r",counter++, u4BATVol);

              if(u4BATVol <= LOW_BAT_ALARM)

        {     

            MSG(SUSP,"Battery Low!!Power off/n/r");     

                     bBAT_UVLO = TRUE;

            goto SLP_EXIT;

        }

#endif

       }

       else

       {

              MSG(SUSP,"leave sleep, wakeup!!/n/r");         

              goto SLP_EXIT;

              //break;

       }

       }

      

SLP_EXIT:   

       wifi_lowpower_opt(FALSE);

       /* Restore interrupt mask ;  */  

       *MT6516_IRQ_MASKL = irqMask_L;

       *MT6516_IRQ_MASKH = irqMask_H;

}

 

函数MT6516_CPUSuspend (u4SuspendAddr, u32TCM)是一段汇编代码,在文件:

Kernel/arch/arm/amch-mt6516/mt6516_slpctrl.S中。下面是这段汇编代码片段,看一看也蛮有意思,因为处理进入low power模式之后,是停留在该函数之中的。

 

ENTRY(MT6516_CPUSuspend)

抱歉!评论已关闭.