Linux standby 開發指南
1 前言
1.1 文檔簡介
介紹 Standby 模塊配置和調試方法。
1.2 目標讀者
Standby 模塊開發、維護人員。
1.3 適用范圍
表 1-1: 適用產品列表
產品名稱 | 內核版本 | 驅動文件 |
---|---|---|
T509 | Linux-4.9 | kernel/power/* |
MR813 | Linux-4.9 | kernel/power/* |
R818 | Linux-4.9 | kernel/power/* |
A133 | Linux-4.9 | kernel/power/* |
H616 | Linux-4.9 | kernel/power/* |
T507 | Linux-4.9 | kernel/power/* |
R328 | Linux-4.9 | kernel/power/* |
T3 | Linux-4.9 | kernel/power/* |
V853 | Linux-4.9 | kernel/power/* |
2 模塊介紹
2.1 模塊功能介紹
? 休眠喚醒指系統進入低功耗和退出低功耗模式,一般稱之為 Standby。standby 分為 super standby 和 normal standby,區別是 cpu 是否掉電。
? 假關機是類似 standby 的一種低功耗模式。進入假關機,系統會先復位,再進入低功耗模式,等待喚醒源;檢測到喚醒源,系統退出假關機,直接從低功耗模式復位重啟。適用于 OTT 類產品代替常規的關機,實現紅外/藍牙開機功能。
2.2 相關術語介紹
表 2-1: 術語介紹
術語 | 說明 |
---|---|
Super standby | Vdd_cpu 掉電或 Core 掉電,dram 進入 self refresh 狀態 |
Normal standby | CPUX WFI,dram 進入 self refresh 狀態 |
Fake Poweroff | 假關機,類似 standby,主要區別是系統退出假關機會重啟,而不是喚醒 |
SCP/CPUS | 全志平臺輔助進行電源管理的協處理器 |
2.3 模塊配置介紹
2.3.1 Device Tree 配置說明
設備樹中存在的是該類芯片所有平臺的模塊配置,設備樹文件的路徑為:kernel/linux-4.9/arch/arm64(32 位平臺為 arm)/boot/dts/sunxi/CHIP.dtsi(CHIP 為研發代號,如sun50iw10p1 等)。Standby 模塊在 dtsi 中無用戶可用配置。
2.3.2 board.dts 配置說明
board.dts 用于保存每一個板級平臺的設備信息(如 demo 板,perf1 板等),里面的配置信息會覆蓋上面的 Device Tree 默認配置信息。
? standby 參數配置
描述系統資源的相關信息。例如,“vdd-cpu = <0x00000006>;”,其中各個 bit 代表 PMU 的各路供電,則 vdd-cpu 使用 PMU的第二、三路供電。
“osc24m-on = <0x1>;”,表示系統休眠后 osc24m 是否關閉,0x0 表示關閉,0x1 表示不關閉。
standby_param: standby_param {
vdd-cpu = <0x00000006>;
vdd-sys = <0x00000008>;
vcc-pll = <0x00000100>;
osc24m-on = <0x1>;
...
};
注:由于 r528/v853 部分方案, 沒有外掛 PMU,即硬件上不支持 vdd-sys/vdd-cpu 掉電,故R528/v853 board.dts 不需要該信息(standby_param)。
? 喚醒源配置
以 RTC 模塊為例,RTC 驅動支持通過 “wakeup-source” 配置是否作為喚醒源;在 RTC 模塊節點下添加 “wakeup-source” 屬性,則可以設置為喚醒源。
rtc: rtc@07000000 {
compatible = "allwinner,sunxi-rtc";
device_type = "rtc";
wakeup-source;
...
};
? GPIO 為喚醒源配置
下面以 gpio-key 驅動為例, 演示一下 gpio 作為 wakeup-source 的代碼編寫:
keys {
compatible = "gpio-keys";
status = "okay";
wakeup {
wakeup-source; (1)
gpios = <&pio PH 9 6 2 2 1>; (2)
label = "wakeup";
linux,code = ;
};
};
1.wakeup-source:device的wakeup source屬性.需要設備驅動自己去解析該屬性,如果有,則表示設備具有wakeup source功能.
2.gpios:配置gpio的mux,pull,drive,data等屬性,如上的配置代表把PH9設置為6號功能(中斷功能),下拉,驅動能力為2,data值為1.
? 假關機參數配置
描述系統關機的方式及假關機時需要用到的系統資源。如:
box_start_os0 {
compatible = "allwinner,box_start_os";
start_type = <0x1>;
irkey_used = <0x0>;
pmukey_used = <0x0>;
pmukey_num = <0x0>;
led_power = <0x0>;
led_state = <0x0>;
pinctrl-0 = <&standby_blue>;
pinctrl-1 = <&standby_red>;
pinctrl-2 = <&standby_bt>;
/*pinctrl-3 = <&standby_bt>;*/
}
...
s_cir0 {
s_cir0_used = <1>;
ir_power_key_code0 = <0x40>;
ir_addr_code0 = <0xfe01>;
ir_power_key_code1 = <0x1a>;
ir_addr_code1 = <0xfb04>;
ir_power_key_code2 = <0xf2>;
ir_addr_code2 = <0x2992>;
ir_power_key_code3 = <0x57>;
ir_addr_code3 = <0x9f00>;
ir_power_key_code4 = <0xdc>;
ir_addr_code4 = <0x4cb3>;
ir_power_key_code5 = <0x18>;
ir_addr_code5 = <0xff00>;
ir_power_key_code6 = <0xdc>;
ir_addr_code6 = <0xdd22>;
ir_power_key_code7 = <0x0d>;
ir_addr_code7 = <0xbc00>;
ir_power_key_code8 = <0x4d>;
ir_addr_code8 = <0x4040>;
wakeup-source;
}
“start_type = <0x1>;”,0x0 代表當系統啟動時檢測到是適配器上電啟動則進入假關機(H700 TV);0x1 不做適配器上電檢測判斷,按普通的假關機判斷流程;
“irkey_used = <0x0>;”,當前代碼并未解析該節點,為無用節點,不影響假關機流程;
“pmukey_used = <0x0>;”,當前代碼并未解析該節點,為無用節點,不影響假關機流程;
“pmukey_num = <0x0>;”,當前代碼并未解析該節點,為無用節點,不影響假關機流程;
“led_power = <0x0>;”,當前代碼并未解析該節點,為無用節點,不影響假關機流程;
“led_state = <0x0>;”,當前代碼并未解析該節點,為無用節點,不影響假關機流程;
“pinctrl-0 = <&standby_blue>;”,LED 顯示需要用到的 pinctrl 配置(其中一種顏色);
“pinctrl-1 = <&standby_red>;”,LED 顯示需要用到的 pinctrl 配置(其中一種顏色);
“pinctrl-2 = <&standby_bt>;”,外部喚醒源(如藍牙/wifi/rtc 模塊)喚醒系統時拉對應 gpio,高脈沖有效,高脈沖持續時間需要大于 200 ms;
“pinctrl-3 = <&standby_bt>;”,外部喚醒源(如藍牙/wifi/rtc 模塊)喚醒系統時拉對應 gpio,低脈沖有效,低脈沖持續時間需要大于 200 ms;
“ir_power_key_code = <0x40>;”,ir 模塊特定數據的碼值,根據方案需求進行配置;
“ir_addr_code = <0xfe01>;”,ir 模塊特定地址的碼值,根據方案需求進行配置。
表 2-2: 平臺支持喚醒源列表
平臺/喚醒源 | 非CPUS域GPIO | CPUS域GPIO | POWER-KEY | RTC | USB | 紅外 | 藍牙/WiFi | MAD |
---|---|---|---|---|---|---|---|---|
T509 | 不支持 | super standby | super standby | super standby | super standby | 不支持 | super standby | 不支持 |
H616 | normal standby | 不支持 | normal standby | normal standby | normal standby | normal standby | normal standby | 不支持 |
V853 | normal standby | 不支持 | super standby | super standby | super standby | 不支持 | normal standby | 不支持 |
T113 | normal standby | 不支持 | 不支持 | normal standby | 不支持 | 不支持 | normal standby | 不支持 |
2.3.3 kernel menuconfig 配置說明
linux-4.9 內核版本:在命令行中進入 linux 目錄,執行 make ARCH=arm64 menuconfig(32 位系統為 make ARCH=arm menuconfig) 進入配置主界面 (Linux-5.4 內核版本執行:./build.sh menuconfig),并按以下步驟作。
? 內核 PSCI 選項
Kernel Features --->
[*] Support for the ARM Power State Coordination Interface (PSCI)
? 內核 CPUIDLE 相關選項(可選)
CPU Power Management --->
CPU Idle --->
[*] CPU idle PM support
ARM CPU Idle Drivers --->
[*] Generic ARM/ARM64 CPU idle Driver
? 內核 POWER 相關選項
Power management options --->
[*] Suspend to RAM and standby
[ ] Opportunistic sleep
[*] User space wakeup sources interface
(100) Maximum number of user space wakeup sources (0 = no limit)
-*- Device power management core functionality
[*] Power Management Debug Support
[*] Extra PM attributes in sysfs for low-level debugging/testing
? 內核 FAKE_POWEROFF 相關選項
Device Drivers --->
[*] Real Time Clock --->
[*] support ir fake poweroff
2.3.4 uboot-2018 配置
? uboot-2018 FAKE_POWEROFF 相關配置
在平臺的 defconfig 中,將 CONFIG_ATF_BOX_STANDBY 配置為 Y
CONFIG_ATF_BOX_STANDBY = Y;
2.4 源碼結構介紹
Standby 的源代碼位于內核 kernel/power/目錄下:
kernel/power/ ├── autosleep.c ├── console.c ├── hibernate.c ├── Kconfig ├── main.c ├── Makefile ├── modules.builtin ├── modules.order ├── power.h ├── poweroff.c ├── process.c ├── qos.c ├── snapshot.c ├── suspend.c ├── suspend_test.c ├── swap.c ├── user.c ├── wakelock.c └── wakeup_reason.c
2.5 驅動框架介紹
休眠喚醒指系統進入低功耗和退出低功耗模式,一般稱之為 Standby。休眠過程由應用發起,經由內核的電源管理框架來進行休眠喚醒管理工作,如果存在 CPUS(一顆集成在 IC 內部的對電源進行管理的 openrisc 核,是 SoC 內置的超低功耗硬件管理模塊),最終會傳遞到到 CPUS。因此休眠喚醒類出現問題的可能為應用層、內核層、CPUS 層,如果不存在 CPUS,則 CPU 進入WFI。休眠喚醒流程圖如下,虛線部分為部分內核實現。
圖 2-1: standby 驅動總體結構
圖 2-2: linux standby 流程
3 FAQ
3.1 調試方法
3.1.1 調試節點
? pm_test 節點
該節點可用于測試 linux 部分休眠喚醒功能。Eg:echo x > /sys/power/pm_test。
Freezer:表明,任務凍結后,等待 5s,即返回,執行喚醒動作。
Devices: 表明,設備凍結后,等待 5s, 即返回,執行喚醒動作。
Platform:在 a1x, a2x, a3x 上,與 devices 相同;
Processors: 凍結 non-boot cpu 后,等待 5s, 即返回,執行喚醒動作。
Core: 凍結 timer 等系統資源后,等待 5s, 即返回,執行喚醒動作。
None: 表明,整個休眠流程全部走完,等待喚醒源喚醒。
? wake_lock 節點
該節點可查看安卓系統 wake lock 狀態,安卓系統在持鎖時不會進入深度睡眠流程 (Suspend-to-mem)。Eg: cat /sys/power/wake_lock。
? wakeup_sources 節點
該節點可查看系統喚醒源的情況。Eg:cat /sys/kernel/debug/wakeup_sources。
3.2 常見問題
3.2.1 系統被錯誤喚醒
3.2.1.1 系統被定時器喚醒
問題現象
休眠后,自動被喚醒,過會自動進入休眠,屏幕黑屏,串口有輸出。
問題分析
系統休眠后自動被喚醒,原因可能是,某些應用或者后臺進程,通過設置鬧鐘的方式,定時喚醒系統。
當出現如下打印,表示 Linux 已經休眠完成,準備進入 CPUS 休眠階段:
[ 3465.885063] PM: noirq suspend of devices complete after 16.487 msecs [ 3465.892225] Disabling non-boot CPUs ... ......
當出現以上打印后自動喚醒,則查看如下打印:
[ 3466.063570] wake up source:0x80000 //H3 linux4.4平臺 [21676.174594] [pm]platform wakeup, standby wakesource is:0x100000 //H5/H6 linux-3.10平臺 后面的數字代表喚醒源,根據數字定位喚醒源,定位喚醒源后再判斷為何被喚醒。 WAKEUP_SRC is as follow: CPUS_WAKEUP_LOWBATT bit 0x1000 CPUS_WAKEUP_USB bit 0x2000 CPUS_WAKEUP_AC bit 0x4000 CPUS_WAKEUP_ASCEND bit 0x8000 CPUS_WAKEUP_DESCEND bit 0x10000 CPUS_WAKEUP_IR bit 0x80000 CPUS_WAKEUP_ALM0 bit 0x100000 CPUS_WAKEUP_HDMI_CEC bit 0x100000
使用范圍適用于非 psci1.0 版本,詳見 dts 文件 psci 節點配置。
常見場景:android 某些應用或者后臺進程,會通過設置鬧鐘的方式,定時喚醒系統,當判斷喚醒源為 0x100000 時,大多數為該原因導致。
問題解決
確認是某些應用或者后臺進程設置鬧鐘定時喚醒系統,方案開發人員可以自行解決。
3.2.1.2 系統被其他喚醒源喚醒
問題現象
休眠后,被異常喚醒。
問題分析
系統休眠后被異常喚醒,原因可能是,被其他非預期的喚醒源喚醒。
查看喚醒源。對應的代碼路徑在:lichee/linux4.9/include/linux/power/aw_pm.h
/* the wakeup source of assistant cpu: cpus */ #define CPUS_WAKEUP_HDMI_CEC (1<<11) #define CPUS_WAKEUP_LOWBATT (1<<12) #define CPUS_WAKEUP_USB (1<<13) #define CPUS_WAKEUP_AC (1<<14) #define CPUS_WAKEUP_ASCEND (1<<15) #define CPUS_WAKEUP_DESCEND (1<<16) #define CPUS_WAKEUP_SHORT_KEY (1<<17) #define CPUS_WAKEUP_LONG_KEY (1<<18) #define CPUS_WAKEUP_IR (1<<19) #define CPUS_WAKEUP_ALM0 (1<<20) #define CPUS_WAKEUP_ALM1 (1<<21) #define CPUS_WAKEUP_TIMEOUT (1<<22) #define CPUS_WAKEUP_GPIO (1<<23) #define CPUS_WAKEUP_USBMOUSE (1<<24) #define CPUS_WAKEUP_LRADC (1<<25) #define CPUS_WAKEUP_WLAN (1<<26) #define CPUS_WAKEUP_CODEC (1<<27) #define CPUS_WAKEUP_BAT_TEMP (1<<28) #define CPUS_WAKEUP_FULLBATT (1<<29) #define CPUS_WAKEUP_HMIC (1<<30) #define CPUS_WAKEUP_POWER_EXP (1<<31) #define CPUS_WAKEUP_KEY (CPUS_WAKEUP_SHORT_KEY | CPUS_WAKEUP_LONG_KEY)
查看關鍵打印:
platform wakeup, standby wakesource is:0x800000
此時對應的是 gpio 喚醒。
問題解決
確認是其他非預期的喚醒源喚醒系統,方案開發人員可以自行解決。
3.2.2 系統不能被喚醒
3.2.2.1 休眠后無法喚醒
問題現象
系統休眠后無法喚醒。
問題分析
系統休眠后無法喚醒,原因可能有:
? 模塊休眠失敗。
查看是否模塊休眠失敗,輸入以下命令,確認是否在內核休眠喚醒模塊出異常。
echo N > /sys/module/printk/parameters/console_suspend echo 1 > /sys/power/pm_print_times
? 若上述無異常打印,則認為是 Linux 后的階段出現異常。
不斷電重啟系統,將啟動時候的 RTC 寄存器的信息發給休眠模塊負責人,根據 RTC 寄存器信息判斷。
[2341]HELLO! pmu_init stub called! [2645]set pll start [2648]set pll end [2649]try to probe rtc region [2652]rtc[0] value = 0x00000000 [2655]rtc[1] value = 0x000000e0 [2658]rtc[2] value = 0xf1f18000 [2661]rtc[3] value = 0x0000000f [2663]rtc[4] value = 0x00000000 [2666]rtc[5] value = 0x00000000
問題解決
? 模塊休眠失敗。確認是模塊休眠失敗,方案開發人員可以自行解決。
? Linux 后的階段出現異常。將復位重啟時的 RTC 寄存器信息發給相關負責人。
3.2.2.2 喚醒源不支持喚醒
問題現象
休眠后,喚醒源無法喚醒系統,串口沒有輸出。
問題分析
休眠后,喚醒源無法喚醒,可能是喚醒源不支持。
? cpus 休眠后異常。
當出現如下打印時表示 Linux 休眠已經完畢,此時喚醒不了,則可能是 cpus 退出休眠失敗,或者喚醒源不對。
[ 3465.885063] PM: noirq suspend of devices complete after 16.487 msecs [ 3465.892225] Disabling non-boot CPUs ... ......
通過以下手段可以判斷 cpus 休眠后是否正常運行,以下命令表示休眠后 cpus 過一定時間軟件自動喚醒。
如果串口能正常打印,wake up source 為 0x400000,則表示 cpus 是正常運行的,這時應該排查一下系統是否支持相應的喚醒源。
? 喚醒源不支持。
確認喚醒源不支持的情況。
問題解決
? cpus 休眠后異常。
將復位重啟時的 RTC 寄存器信息發給相關負責人。
? 喚醒源不支持。
將喚醒源的情況發給相關負責人。
3.2.2.3 紅外遙控器不能喚醒系統
問題現象
紅外遙控不能喚醒系統。
問題分析
紅外遙控喚醒需要配置喚醒源。
問題解決
紅外遙控器默認支持 NEC 紅外協議遙控器喚醒,也支持 RC5 紅外協議遙控器喚醒,但是需要在sys_config.fex 進行配置,配置如下:
;-------------------------------------------------------------------------------- ;ir --- infra remote configuration ;ir_protocol_used : 0 = NEC / 1 = RC5 ;-------------------------------------------------------------------------------- [s_cir0] s_cir0_used = 1 ir_used = 1 ir_protocol_used = 0 //置為0 支持NEC 紅外協議遙控喚醒,配置為0 支持RC5 紅外協議遙控喚醒
對于同一協議的紅外遙控器,能支持喚醒的個數也是有限的,具體在 sys_config.fex 配置 s_cir0 節點。
ir_power_key_code0 = 0x57 //遙控POWER 值 ir_addr_code0 = 0x9f00 //遙控設備碼 ir_power_key_code1 = 0x1a ir_addr_code1 = 0xfb04
3.2.2.4 USB設備不能喚醒系統
問題現象
USB 不能喚醒系統。
問題分析
USB 需要設置為喚醒源。
問題解決
USB 設備喚醒需要系統支持 USB_STANDBY,需要在 sys_config.fex 配置 usbc* 節點。需要
注意 [usbc0] usb_wakeup_suspend = 1 //1 表示支持 USB0 喚醒,0 表示屏蔽該喚醒源。
3.2.2.5 hdmi_cec 不能喚醒系統
問題現象
HDMI 不能喚醒系統。
問題分析
HDMI 需要設置為喚醒源。
問題解決
需要在 sys_config.fex 配置 hdmi 節點。
[hdmi] hdmi_cec_support = 1 hdmi_cec_super_standby = 1
3.2.2.6 cpus 退出休眠失敗
問題現象
休眠后,無法喚醒,串口沒有輸出。
問題分析
可能是 cpus 退出休眠失敗。
如果通過寫 time_to_wakeup 命令,系統沒法正常喚醒,則考慮是 cpus 退出休眠失敗的了,這時需要短接 reset 腳重啟系統(注意不是完全斷電,完全斷電將無法保留 RTC 值),然后將 boot 階段打印的 RTC 碼值發送給休眠喚醒負責人,定位問題。
[2341]HELLO! pmu_init stub called! [2645]set pll start [2648]set pll end [2649]try to probe rtc region [2652]rtc[0] value = 0x00000000 [2655]rtc[1] value = 0x000000e0 [2658]rtc[2] value = 0xf1f18000 [2661]rtc[3] value = 0x0000000f [2663]rtc[4] value = 0x00000000 [2666]rtc[5] value = 0x00000000
問題解決
? 確認是否 dram 錯誤。
? 確認是否上下電時序錯誤。
? 將復位重啟時的 RTC 寄存器信息發給相關負責人。
3.2.3 系統無法休眠
3.2.3.1 系統持鎖無法休眠
問題現象
系統持鎖,suspend 失敗。
問題分析
suspend 失敗,可能是系統持鎖阻止休眠。
問題解決
? 安卓查看是否有持鎖相關信息:
dumpsys power | grep PART
? 內核中是否有相關持鎖信息:
cat /sys/kernel/debug/wakeup_sources
查看 active_since 項,若對應模塊不為 0,則該模塊一直阻止系統進入休眠,查看該模塊是否異常;
cat /sys/power/wake_lock
查看是否有安卓申請的鎖。
? Linux devices driver suspend 失敗:
3.2.3.2 Android 系統持鎖無法休眠
問題現象
定時休眠到時后,屏幕亮屏,串口可以輸入,系統無法休眠。
問題分析
系統無法休眠,確認 Android 是否支持,是否禁止定時休眠。
串口輸入 dumpsys power,查看如下打印。如果發現 mStayOn=true,則系統是不支持定時休眠功能,可以將該屬性設置成 false;另外 screen off timeout 表示休眠時間,可通過該值判斷你設置的定時時間是否正確;如果是 androidN ,screen off timeout 還取決于 Sleep timeout,Sleep timeout 的值比 Screen off timeout 小時,系統取 Sleep timeout 當做定時休眠的時間,當 Sleep timeout 為-1 時,也表示系統無法定時休眠。如果是以上情況可咨詢 android 系統的同事,修改相應的屬性。
Power Manager State: ...... mStayOn=true //true 保持常亮,false 可以支持定時休眠 Sleep timeout: -1 ms //只有androidN 平臺無該該值,定時休眠時間 Screen off timeout: 1800000 ms //定時滅屏時間 Screen dim duration: 7000 ms //屏保時間
常見場景:eng 固件開發階段為了測試長時間老化的測試項,會禁止系統定時進入休眠。
問題解決
確認是 Android 系統持鎖阻止休眠,方案開發人員可以自行解決。
3.2.4 休眠喚醒過程中掛掉
3.2.4.1 分階段過程掛掉
問題現象
在 Linux 某個階段出現的休眠或者喚醒失敗。
問題分析
打開內核選項
CONFIG_PM_DEBUG=y
查看具體失敗在哪個階段:
echo freezer > /sys/power/pm_test 查看 freezer 階段是否正常;
echo devices > /sys/power/pm_test 查看 freezer/devices 階段是否正常;
echo platform > /sys/power/pm_test 查看 freezer/devices/platform 階段是否正常;
echo processors > /sys/power/pm_test 查看 freezer/devices/platform/processors 階段是否正常;
echo core > /sys/power/pm_test 查看 freezer/devices/platform/processors/core 階段是否正常;
echo mem > /sys/power/state 測試分階段休眠喚醒。
問題解決
確認是哪個階段出現的休眠或者喚醒失敗,方案開發人員可以自行解決。
-
模塊
+關注
關注
7文章
2716瀏覽量
47543 -
Linux
+關注
關注
87文章
11313瀏覽量
209748 -
開發指南
+關注
關注
0文章
34瀏覽量
7549 -
Standby
+關注
關注
0文章
4瀏覽量
7064
發布評論請先 登錄
相關推薦
評論