转自:http://blog.csdn.net/lizhiguo0532/article/details/6453552

suspend第三、四、五阶段:platform、processor、core

static int suspend_enter(suspend_state_t state)

{

int error;

if (suspend_ops->prepare) {

// 平台特定的函数,mtkpm.c, 有定义,对pmic和cpu 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))       // suspend第3阶段到此为止

goto Platform_wake;

error = disable_nonboot_cpus();  // disable nonboot cpus

if (error || suspend_test(TEST_CPUS))  // suspend第4阶段到此为止

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))               // suspend第5阶段到此为止

error = suspend_ops->enter(state);

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

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

sysdev_resume();         // resuem system devices

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

}

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)

stmfd sp!, {r4-r12, lr}

// r0 = MT6516_CPUSuspend physical address,

// r1 = TCM address

mov r4, r0

mov r9, r1

// Set SVC mode

mrs r0, cpsr

bic r0, r0, #MODE_MASK1

orr r1, r0, #Mode_SVC

// Set I/F bit, disable IRQ and FIQ

orr r1, r1, #I_Bit|F_Bit

// Update CPSR

msr cpsr_cxsf, r1

// calculate the physical address of instruction after disable MMU

ldr r0, =PhysicalPart

ldr r1, =MT6516_CPUSuspend

sub r0, r0, r1

mov r1, r4

// Now r0 is the physical address of PhysicalPart

add r0, r0, r1

...

...

// Power down Cache and MMU, MCU_MEM_PDN

ldr r0, =0xF0001308

ldr r1, [r0]

// ldr r1, =0xFFFFFFFF

orr r1, r1, #0x0F

str r1, [r0]

// STEP1: Set AP SLEEP (IRQ CODE: 0x36) to level sensitive on CIRQ.

// already done when system start.

// STEP2: Unmask AP SLEEP CTRL interrupt.

// already done at mt6516_pm_Maskinterrupt.

// STEP3: EOI AP SLEEP interrupt.

// already done at mt6516_pm_Maskinterrupt.

// STEP4: Read clear AP_SM_STA (OxF003C21C).

// already done at mt6516_pm_Maskinterrupt.

// STEP5: Set AP_SM_PAUSE_M(0x8003C200) and AP_SM_PAUSE_L(0x8003C204) for sleep duration. 16 seconds as default

...

// STEP6: Set AP_SM_CLK_SETTLE(0xF003C208) to 0x64. Must over 5ms

...

// STEP7: Set AP_SM_CNF(DxF003C22C) to wanted wake-up source. (TP, GPT, MSDC, RTC, EINT, KP or SM)

// already done at mt6516_pm_SuspendEnter

// STEP8: Set AP_SM_CON[1]:PAUSE_START to 1 to enable AP sleep controller.

...

// STEP9: Execute the CP15 command(MCR p15, 0, r0, c7, c0, 4),

// then ARM9 MCU enters low power state

// and STANDBYWFI signal becomes HIGH. CLOCK_OFF signal is issued to Clock Management Unit,

// and then AP MCU Sub-system clock is gated and VCXO OFF signal is issued to AP Sleep Controller.

mov r0, #0

mcr p15, 0, r0,c7,c0,4

// wait till interrupt occurs

// polling AP_SM_STA

mov r2, #0

mov r3, #0x10

15:

//mov r10, r1

// Power up I-Cache

...

//delay

...

// Power up I-Cache upper 16KB

...

//delay

...

// Power up D-Cache

...

//delay

...

// Power up D-Cache upper 16KB

...

//delay

...

// Clean and invalid DCache

// Invalidate instruction cache

// TCM_START_UA saved in r9

mov r2, r9

add r1, r1, r2

// make sure no stall on ¨mov pc,r0〃 below

cmp r1, #0

// restore MMU

mov r4, #0

// access domain 0

// TTB

// flush TLBs

// Turn on MMU

//test

mcr p15, 0, r6, c1, c0, 0

//mov pc, r1

nop

nop

VirtualPart:

nop

nop

mov r0, r10

ldmia sp!, {r4-r12, lr}

mov pc, lr

Nop

六、系统正常suspend和resume时函数调用和配对

enter_state(state)

--> sys_sync()

--> suspend_prepare()

--> pm_prepare_console()

--> pm_notifier_call_chain(PM_SUSPEND_PREPARE)

--> usermodehelper_disable()

--> suspend_freeze_processes()

--> suspend_devices_and_enter(state)

--> suspend_ops->begin(state)

--> _Chip_pm_begin()

--> suspend_console()  // 此后串口无信息出来,缓存起来等后面resume打出

--> dpm_suspend_start(PMSG_SUSPEND)

--> dpm_prepare(state)

--> device_prepare(dev, state)

--> dpm_suspend(state)

--> device_suspend(dev, state)

--> suspend_enter(state)

--> suspend_ops->prepare()

--> _Chip_pm_prepare()

--> SetARM9Freq(DIV_4_104)

--> dpm_suspend_noirq(PMSG_SUSPEND)

--> suspend_ops->prepare_late() // 无定义

--> disable_nonboot_cpus()

--> arch_suspend_disable_irqs()

--> sysdev_suspend(PMSG_SUSPEND)

--> suspend_ops->enter(state)

--> _Chip_pm_enter(state)

--> mt6516_pm_SuspendEnter()

--> MT6516_CPUSuspend() // 汇编函数,suspend cpu

<-- MT6516_CPUSuspend() // 汇编函数,resume cpu

<-- mt6516_pm_CheckStatus()

<-- return 0

<-- return 0

<-- sysdev_resume()

<-- arch_suspend_enable_irqs()

<-- enable_nonboot_cpus()

<-- suspend_ops->wake() // 无定义

<-- dpm_resume_noirq(PMSG_RESUME)

<-- suspend_ops->finish()

<-- _Chip_pm_finish()

<-- SetARM9Freq(DIV_1_416)

<-- return 0

<-- return 0

<-- dpm_resume_end(PMSG_RESUME)

<-- dpm_resume(state)

<-- device_resume(dev, state)

<-- dpm_complete(state)

<-- device_complete(dev, state)

<-- resume_console()   // 打印出缓存中的信息

<-- suspend_ops->end()

<-- return 0

<-- suspend_finish()

<-- suspend_thaw_processes()

<-- usermodehelper_enable()

<-- pm_notifier_call_chain(PM_POST_SUSPEND)

<-- pm_restore_console()

<-- return 0

标准linu休眠和唤醒机制分析(四)【转】的更多相关文章

  1. linux驱动程序之电源管理之标准linux休眠和唤醒机制分析(二)

    三.pm_test属性文件读写 int pm_test_level = TEST_NONE; static const char * const  pm_tests[__TEST_AFTER_LAST ...

  2. linux驱动程序之电源管理之标准linux休眠与唤醒机制分析(一)

    1. Based on linux2.6.32,  only for mem(SDR) 2. 有兴趣请先参考阅读: 电源管理方案APM和ACPI比较.doc Linux系统的休眠与唤醒简介.doc 3 ...

  3. android 休眠唤醒机制分析(二) — early_suspend

    本文转自:http://blog.csdn.net/g_salamander/article/details/7982170 early_suspend是Android休眠流程的第一阶段即浅度休眠,不 ...

  4. android 休眠唤醒机制分析(三) — suspend

    本文转自:http://blog.csdn.net/g_salamander/article/details/7988340 前面我们分析了休眠的第一个阶段即浅度休眠,现在我们继续看休眠的第二个阶段 ...

  5. android 休眠唤醒机制分析(一) — wake_lock

    本文转自:http://blog.csdn.net/g_salamander/article/details/7978772 Android的休眠唤醒主要基于wake_lock机制,只要系统中存在任一 ...

  6. android 休眠唤醒机制分析(一) — wake_lock【转】

    Android的休眠唤醒主要基于wake_lock机制,只要系统中存在任一有效的wake_lock,系统就不能进入深度休眠,但可以进行设备的浅度休眠操作.wake_lock一般在关闭lcd.tp但系统 ...

  7. Android休眠唤醒机制简介(一)【转】

    本文转载自:http://blog.csdn.net/zhaoxiaoqiang10_/article/details/24408129 Android休眠唤醒机制简介(一) ************ ...

  8. Android休眠唤醒机制

    有四种方式可以引起休眠 ①在wake_unlock()中, 如果发现解锁以后没有任何其他的wake lock了, 就开始休眠 ②在定时器到时间以后, 定时器的回调函数会查看是否有其他的wake loc ...

  9. Android休眠唤醒机制简介(二)

    本文转载自:http://blog.csdn.net/zhaoxiaoqiang10_/article/details/24408911 Android休眠唤醒机制简介(二)************* ...

随机推荐

  1. “数学口袋精灵”App的第一个Sprint计划(总结)

    “数学口袋精灵”App的第一个Sprint计划 ——11.20  星期五(第十天)第一次Sprint计划结束   第一阶段Sprint的目标以及完成情况: 时间:11月11号~11月20号(10天) ...

  2. Daily Scrum - 12/01

    Meeting Minutes 今天重阳去和UI设计团队的人去讨论UI方面的事宜了,剩下的人主要还是在讨论文件输入输出的事.目前总算是能实现文件存取了,尽量在明天前把文件的格式内容都弄好. Burnd ...

  3. Visual Studio(VS)C++单元测试

    版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:Visual Studio(VS)C++单元测试     本文地址:http://techie ...

  4. Oracle Profile 的简单说明

    1. 查看已经有的oracle 的profile 首先profile的解释 我理解为 是一个 简略的配置文件, 跟linux的 bash文件的配置信息类似 bash_profile . select ...

  5. 【转】mysql优化步骤

    作者:zhuqz链接:https://www.zhihu.com/question/19719997/answer/81930332来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请 ...

  6. 移动端web开发整理

    /* 移动端定义字体的代码 */body { font-family: "Helvetica Neue", Helvetica; } ios端触摸时,会出现一个半透明灰色遮罩 如果 ...

  7. [USACO4.4]追查坏牛奶Pollutant Control

    题目链接:ヾ(≧∇≦*)ゝ Solution: 第一问很好解决,根据网络流:最大流=最小割定理,我们可以轻松求出. 至于第二问,我们不妨把每一条边乘上一个大于1000的数再加上1. 这样的话,对于最小 ...

  8. 【刷题】BZOJ 2125 最短路

    Description 给一个N个点M条边的连通无向图,满足每条边最多属于一个环,有Q组询问,每次询问两点之间的最短路径. Input 输入的第一行包含三个整数,分别表示N和M和Q 下接M行,每行三个 ...

  9. 【刷题】LOJ 6013 「网络流 24 题」负载平衡

    题目描述 G 公司有 \(n\) 个沿铁路运输线环形排列的仓库,每个仓库存储的货物数量不等.如何用最少搬运量可以使 \(n\) 个仓库的库存数量相同.搬运货物时,只能在相邻的仓库之间搬运. 输入格式 ...

  10. 【题解】 [SCOI2010]连续攻击游戏 (二分图匹配)

    原题目戳我 Solution: 方法很巧妙,我们把每个装备的属性 与 装备编号连起来 从1-10000跑二分图,如果出现断层,就退出,输出答案就好. memset清理bool快一点,int洛谷上超时了 ...