日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > linux >内容正文

linux

Linux睡眠唤醒机制分析--以IMX6UL为例

發(fā)布時(shí)間:2024/10/12 linux 50 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux睡眠唤醒机制分析--以IMX6UL为例 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

鑒于當(dāng)前做的項(xiàng)目中有低功耗的需求,因此查探了一番Linux的睡眠及喚醒的機(jī)制。

當(dāng)前網(wǎng)絡(luò)上已經(jīng)有很多關(guān)于睡眠喚醒的分析文章,有的分析也非常透徹,因此本文只從寄存器以及匯編處理和CPU架構(gòu)方面來(lái)補(bǔ)充一下。

睡眠總體上可以分為淺睡及深睡眠,從PM管理上來(lái)說(shuō),主要是電源域和時(shí)鐘控制的不同,如下IMX6介紹:

Linux進(jìn)入睡眠的方式,在應(yīng)用層可以直接操作/sys/power/state文件,cat此文件可以查看支持睡眠的種類,我的imx6開(kāi)發(fā)板只有3種模式:

root@mys6ull14x14:~# cat /sys/power/state freeze standby mem
  • freeze: 凍結(jié)I/O設(shè)備,將它們置于低功耗狀態(tài),使處理器進(jìn)入空閑狀態(tài),喚醒最快,耗電比其它standby, mem, disk方式高
  • standby:除了凍結(jié)I/O設(shè)備外,還會(huì)暫停系統(tǒng),喚醒較快,耗電比其它 mem, disk方式高
  • mem:將運(yùn)行狀態(tài)數(shù)據(jù)存到內(nèi)存,并關(guān)閉外設(shè),進(jìn)入等待模式,喚醒較慢,耗電比disk方式高
  • disk: 將運(yùn)行狀態(tài)數(shù)據(jù)存到硬盤(pán),然后關(guān)機(jī),喚醒最慢

在我的IMX6UL板子上,外設(shè)只有一個(gè)wifi而且是禁用狀態(tài),5V正常工作時(shí),電流170ma左右,進(jìn)入mem狀態(tài),大概20ma

看一下睡眠和喚醒的過(guò)程日志:

root@mys6ull14x14:~# echo mem > /sys/power/state PM: Syncing filesystems ... done. Freezing user space processes ... (elapsed 0.002 seconds) done. Freezing remaining freezable tasks ... (elapsed 0.001 seconds) done. Suspending console(s) (use no_console_suspend to debug) ----此時(shí)已進(jìn)入睡眠,調(diào)試串口無(wú)打印 --以下為喚醒過(guò)程的輸出: RTW: suspend start PM: suspend of devices complete after 12.485 msecs PM: suspend devices took 0.010 seconds PM: late suspend of devices complete after 2.056 msecs PM: noirq suspend of devices complete after 2.235 msecs Disabling non-boot CPUs ... PM: noirq resume of devices complete after 1.326 msecs PM: early resume of devices complete after 1.394 msecs gpmi-nand 1806000.gpmi-nand: enable the asynchronous EDO mode 5 RTW: resume start ==> rtl8188e_iol_efuse_patch RTW: wlan0- hw port(0) mac_addr =a0:2c:36:e7:23:5e RTW: rtw_resume_common:0 in 590 ms PM: resume of devices complete after 659.844 msecs PM: resume devices took 0.660 seconds Restarting tasks ... done. root@mys6ull14x14:~#

Linux將各種外設(shè)進(jìn)入低功耗模式之后,關(guān)閉各域的Power,對(duì)于ARM core,直接使用WFI指令讓其進(jìn)入低功耗模式,此后等待外部喚醒。

對(duì)于喚醒機(jī)制,首先得確認(rèn)CPU支持哪些喚醒源,針對(duì)IMX6,喚醒源如下:

對(duì)于Other wakeup source,主要是一些外設(shè),比如UART,SD卡,網(wǎng)絡(luò)等等,可以直接在外設(shè)寄存器中查看。

對(duì)于喚醒源的設(shè)定,主要是進(jìn)入低功耗模式之前,屏蔽其中斷,睡眠后當(dāng)此中斷發(fā)生時(shí),arm core會(huì)自動(dòng)喚醒。

關(guān)于設(shè)定方式,主要在DTS中配置,如gpio:

user {label = "User Button";gpios = <&gpio5 0 GPIO_ACTIVE_HIGH>;gpio-key,wakeup;linux,code = <KEY_1>; };

其中g(shù)pio-key,wakeup即設(shè)定為支持喚醒功能。在驅(qū)動(dòng)中,關(guān)于此配置最主要的操作為enable_irq_wake,最后會(huì)調(diào)用到cpu層接口

static struct irq_chip imx_gpc_chip = {.name = "GPC",.irq_eoi = irq_chip_eoi_parent,.irq_mask = imx_gpc_irq_mask,.irq_unmask = imx_gpc_irq_unmask,.irq_retrigger = irq_chip_retrigger_hierarchy,.irq_set_wake = imx_gpc_irq_set_wake,.irq_set_type = irq_chip_set_type_parent, #ifdef CONFIG_SMP.irq_set_affinity = irq_chip_set_affinity_parent, #endif };

在imx_gpc_irq_set_wake把喚醒中斷ID記錄到gpc_wake_irqs,

static int imx_gpc_irq_set_wake(struct irq_data *d, unsigned int on) {unsigned int idx = d->hwirq / 32;unsigned long flags;u32 mask;mask = 1 << d->hwirq % 32;spin_lock_irqsave(&gpc_lock, flags);gpc_wake_irqs[idx] = on ? gpc_wake_irqs[idx] | mask :gpc_wake_irqs[idx] & ~mask;spin_unlock_irqrestore(&gpc_lock, flags);/** Do *not* call into the parent, as the GIC doesn't have any* wake-up facility...*/return 0; }

登記之后在進(jìn)入睡眠之前應(yīng)用imx_gpc_pre_suspend:

void imx_gpc_pre_suspend(bool arm_power_off) {void __iomem *reg_imr1 = gpc_base + GPC_IMR1;int i;if (cpu_is_imx6q() && imx_get_soc_revision() == IMX_CHIP_REVISION_2_0)_imx6q_pm_pu_power_off(&imx6q_pu_domain.base);/* power down the mega-fast power domain */if ((cpu_is_imx6sx() || cpu_is_imx6ul() || cpu_is_imx6ull()) && arm_power_off)imx_gpc_mf_mix_off();/* Tell GPC to power off ARM core when suspend */if (arm_power_off)imx_gpc_set_arm_power_in_lpm(arm_power_off);for (i = 0; i < IMR_NUM; i++) {gpc_saved_imrs[i] = readl_relaxed(reg_imr1 + i * 4);writel_relaxed(~gpc_wake_irqs[i], reg_imr1 + i * 4);} }

?

writel_relaxed(~gpc_wake_irqs[i], reg_imr1 + i * 4); 寫(xiě)入中斷屏蔽寄存器即可.

睡眠后,cpu大部分功能不可用,包括中斷控制器,當(dāng)中斷發(fā)生時(shí),不能進(jìn)入正常的中斷響應(yīng)程序,而且被另一套獨(dú)立的“中斷控制器”所接管,跳入指定的地址執(zhí)行,在imx6上此地址可以在如下寄存器中配置:

SRC_GPR1為睡眠后中斷發(fā)生時(shí)跳入的地址,SRC_GPR2為相關(guān)參數(shù)

在Linux中使用如下,文件arch/arm/mach-imx/suspend-imx6.S 中函數(shù)ENTRY(imx6_suspend)會(huì)保存相關(guān)寄存器

ENTRY(imx6_suspend)ldr r1, [r0, #PM_INFO_PBASE_OFFSET]ldr r2, [r0, #PM_INFO_RESUME_ADDR_OFFSET]ldr r3, [r0, #PM_INFO_DDR_TYPE_OFFSET]ldr r4, [r0, #PM_INFO_PM_INFO_SIZE_OFFSET]/** counting the resume address in iram* to set it in SRC register.*/ldr r6, =imx6_suspendldr r7, =resumesub r7, r7, r6add r8, r1, r4add r9, r8, r7/** make sure TLB contain the addr we want,* as we will access them after MMDC IO floated.*/ldr r11, [r0, #PM_INFO_MX6Q_CCM_V_OFFSET]ldr r6, [r11, #0x0]ldr r11, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET]ldr r6, [r11, #0x0]ldr r11, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET]ldr r6, [r11, #0x0]/* use r11 to store the IO address */ldr r11, [r0, #PM_INFO_MX6Q_SRC_V_OFFSET]/* store physical resume addr and pm_info address. */str r9, [r11, #MX6Q_SRC_GPR1]str r1, [r11, #MX6Q_SRC_GPR2]

關(guān)于保存的位置和內(nèi)容,文件中有相關(guān)注釋:

/** ==================== low level suspend ====================** Better to follow below rules to use ARM registers:* r0: pm_info structure address;* r1 ~ r4: for saving pm_info members;* r5 ~ r10: free registers;* r11: io base address.** suspend ocram space layout:* ======================== high address ======================* .* .* .* ^* ^* ^* imx6_suspend code* PM_INFO structure(imx6_cpu_pm_info)* ======================== low address =======================*/

關(guān)于恢復(fù),resume地址此前已經(jīng)存入R9 即SRC_GPR1:

resume:/* invalidate L1 I-cache first */mov r6, #0x0mcr p15, 0, r6, c7, c5, 0mcr p15, 0, r6, c7, c5, 6/* enable the Icache and branch prediction */mov r6, #0x1800mcr p15, 0, r6, c1, c0, 0isb/* restore it with 0x1f if use ldo bypass mode.*/ldr r11, [r0, #PM_INFO_MX6Q_ANATOP_P_OFFSET]ldr r7, [r11, #MX6Q_ANATOP_CORE]and r7, r7, #0x1fcmp r7, #0x1ebne ldo_check_done3ldr r7, [r11, #MX6Q_ANATOP_CORE]orr r7, r7, #0x1fstr r7, [r11, #MX6Q_ANATOP_CORE] ldo_check_done3:/* get physical resume address from pm_info. */ldr lr, [r0, #PM_INFO_RESUME_ADDR_OFFSET]/* clear core0's entry and parameter */ldr r11, [r0, #PM_INFO_MX6Q_SRC_P_OFFSET]mov r7, #0x0str r7, [r11, #MX6Q_SRC_GPR1]str r7, [r11, #MX6Q_SRC_GPR2]ldr r3, [r0, #PM_INFO_DDR_TYPE_OFFSET]mov r5, #0x1/* check whether it supports Mega/Fast off */ldr r6, [r0, #PM_INFO_MMDC_NUM_OFFSET]cmp r6, #0x0beq dsm_only_resume_ioresume_mmdc_iob dsm_resume_mmdc_done dsm_only_resume_io:ldr r3, [r0, #PM_INFO_DDR_TYPE_OFFSET]resume_io dsm_resume_mmdc_done:ret lr

關(guān)于結(jié)構(gòu)體imx6_cpu_pm_info與匯編中保存位置的定義,需要一一對(duì)應(yīng):

/** This structure is for passing necessary data for low level ocram* suspend code(arch/arm/mach-imx/suspend-imx6.S), if this struct* definition is changed, the offset definition in* arch/arm/mach-imx/suspend-imx6.S must be also changed accordingly,* otherwise, the suspend to ocram function will be broken!*/ struct imx6_cpu_pm_info {phys_addr_t pbase; /* The physical address of pm_info. */phys_addr_t resume_addr; /* The physical resume address for asm code */u32 ddr_type;u32 pm_info_size; /* Size of pm_info. */struct imx6_pm_base mmdc0_base;struct imx6_pm_base mmdc1_base;struct imx6_pm_base src_base;struct imx6_pm_base iomuxc_base;struct imx6_pm_base ccm_base;struct imx6_pm_base gpc_base;struct imx6_pm_base l2_base;struct imx6_pm_base anatop_base;u32 ttbr1; /* Store TTBR1 */u32 mmdc_io_num; /* Number of MMDC IOs which need saved/restored. */u32 mmdc_io_val[MX6_MAX_MMDC_IO_NUM][2]; /* To save offset and value */u32 mmdc_num; /* Number of MMDC registers which need saved/restored. */u32 mmdc_val[MX6_MAX_MMDC_NUM][2]; } __aligned(8);

?

與50位技術(shù)專家面對(duì)面20年技術(shù)見(jiàn)證,附贈(zèng)技術(shù)全景圖

總結(jié)

以上是生活随笔為你收集整理的Linux睡眠唤醒机制分析--以IMX6UL为例的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。