高通android平臺功耗優化方法
1、底電流除錯(Rock Bottom Current Optimization)
底電流在手機飛航模式下除錯。每個平臺的底電流資料可能不一樣,具體可以參考release出來的Current Consumption Data文件或者release note。一般情況下的底電流參考資料上限是:
512M RAM < 1.5mA; 1G RAM < 2mA; 2G RAM < 2.6mA
1.1校準RF
保證RF的PA、Antenna switch、Tuner、APT、GPIO工作在正常狀態
1.2飛航模式
開啟飛航模式、關閉GPS、關閉自動旋轉螢幕、關閉自動亮度調節、關閉其他特效效果設定
開啟飛航模式,可以基本避免藍芽、wifi、NFC、網路、FM等的一般影響;
關閉GPS,可以基本排除開啟GPS對底電流的影響;
關閉自動旋轉螢幕,可以基本排除sensor的影響;
關閉自動亮度調節,可以基本排除距離感應到的影響;
關閉其他特效效果設定,如指紋識別、黑屏手勢、智慧體感、手勢隔空操作。。。。。。
1.3使用perf_defconfig
修改device/qcom/<TARGET>/AndroidBoard.mk。如果KERNEL_DEFCONFIG := <TARGET>_defconfig,那麼改成KERNEL_DEFCONFIG := <TARGET>-perf_defconfig
同時,kernel程式碼改用/kernel/arch/arm/configs/<TARGET>-perf_defconfig
<TARGET>是平臺名稱或者專案名稱
1.4移除debugging APKs
/system/app/Logkit.apk
/system/app/com.qualcomm.qlogcat.apk
/system/xbin/qlogd
1.5把應用儘量刪除
在設定-->應用,禁用正在執行的應用
1.6去掉CPU佔用高的程序
adb shell
top
檢視CPU佔用,去掉在休眠模式下CPU佔用大於0的程序。kill掉該程序,若kill不掉則
1.7手動移除所有可以移除的外設
手機連上安捷倫電源,手機開機,然後讓手機進入待機狀態。手動移除TP、LCM、前camera、後camera、sensor、SD卡、SIM卡等可以手動移除的外圍器件,同時觀察並記錄底電流變化。
直接移除WLAN晶片可能會導致開不了機,所以在移除WLAN之前,先對軟體做如下處理:
# mount -o rw,remount -t vfat /dev/block/bootdevice/by-name/modem
# cd /firmware/image
# rm wcnss.*
# reboot
或者
#lsmod
#rmmod WLAN
移除其他可以移除的晶片(sensor、NFC。。。)
1.8移除驅動模組
在/kernel/arch/arm/configs/<TARGET>-perf_defconfig中把sensor、TP、LCM、camera等的驅動模組移除;
或者在對應驅動的Makefile裡面,移除驅動程式碼
然後編譯bootimage,燒入手機觀察底電流變化
1.9配置不用的GPIO
將不用的GPIO置為輸入、拉低;配置成SPI、I2C的GPIO,若不用,置為懸空
在boot_images/core/systemdrivers/tlmm/config/platform/TLMMChipset.xml,修改GPIO配置。該處配置GPIO的初始狀態,驅動有可能會修改GPIO。
對比專案原理圖與平臺參考原理圖,專案原理圖中多出的NC GPIO要處理掉。
1.10檢查power相關的NV items
需要跟CE確認。一般如下:
1027 = 0
1895 = 0
1892 = 0
1962 = 0
4679 = 16
4201 = 0
3851 = 0
3852 = 6
7157 = 1
69745 rxd_enable = 0
WCDMA NV:
NV3581 = 0
NV3852 = 6
1.11排查GPIO、LDO、匯流排
對比專案原理圖與平臺參考原理圖,排查硬體不一樣的GPIO、LDO、匯流排配置。
量測各GPIO、LDO、I2C在休眠時候的電壓,需用萬用表準確測量。
休眠時各路I2C GPIO的電壓是多少v,用萬用表準確測量。
如果條件允許,測量所有LDO在休眠前和休眠後的準確電壓。
對於LDO,除錯方法如下:
(1)adb shell關閉LDO
如關閉L3:
cd /sys/kernel/debug/regulator/8916_l3/
echo 0 > enable
(2)LDO太多裝置用到,不適合用adb shell來關。可以這樣除錯:
cat /sys/kernel/debug/regulator/8916_l6/consumers
[email protected]_32:/sys/kernel/debug/regulator/8916_l6 $ cat consumers
Device-Supply EN Min_uV Max_uV load_uA
0-000c-vio Y 1800000 1800000 0
0-0068-vi2c N 1800000 1800000 0
5-0038-vcc_i2c Y 1800000 1800000 0
1a98000.qcom,mdss_dsi-vddio N 1800000 1800000 100
1a98300.qcom,mdss_dsi_pll-vddio N 1800000 1800000 100
8916_l6 N 0 0 0
這樣就可以看到是哪些裝置請求了LDO6。然後 找到對應的程式碼,在休眠時關掉LDO,喚醒時再開啟。
0-000c: 掛在I2C0上地址為0xc
5-0038: 掛在I2C0上地址為0x38
檢視這兩個裝置的驅動程式碼是否有執行regulator_enable。
(3)通過暫存器地址關閉LDO
如LDO6的地址是0x14546,則關閉方法是:
# cd /sys/kernel/debug/spmi/spmi-0
# echo 0x14546 > address
# echo 1 > count
# cat data 可以讀暫存器
# echo 0x00 > data 關LDO6
(4)關閉MPP
在休眠前關閉MPP1、MPP2、MPP3、MPP4
如PM8916的暫存器地址分別是0xA046、0xA146、0xA246、0xA346
在關閉前先cat data以檢視原來的值。
GPIO狀態讀取的方法如下:
(1)GPIO dump
為了得到休眠時的GPIO狀態,增加下面的列印:
rpm_proc/core/power/sleep/src/lpr_definition_uber.c
#include "tlmm_hwio.h"
void deep_sleep_enter(void)
{
uint64 sleep_duration;
...
SWEVENT(SLEEP_DEEP_SLEEP_ENTER_COMPLETE, sleep_mode.deep_sleep_mode, sleep_duration);
// For test
{
int num;
int i=11;/*LCM_I2C_SCL, GPIO_11*/
volatile uint32 cfg ,inout, val;
num = 122; //8916 only. Need modify for 8974/8x10/8x26 etc.
cfg = *(volatile uint32*)HWIO_TLMM_GPIO_CFGn_ADDR(i); //(0x61000000 + i * 0x1000)
inout = *(volatile uint32*)HWIO_TLMM_GPIO_IN_OUTn_ADDR(i);//(0x61000004 + i * 0x1000)
val = ((cfg << 16)&0xffff0000) | (inout&0xffff);
SWEVENT(SLEEP_GPIO_DUMP, i, val);
}
mpm_sw_done(sleep_mode.deep_sleep_mode, sleep_duration);
} while(FALSE);
}
增加for test下面這一段程式碼。
然後再修改:
rpm_proc\core\power\sleep\build\SConscript
if 'USES_QDSS_SWE' in env:
QDSS_IMG = ['QDSS_EN_IMG']
events = [['SLEEP_DEEP_SLEEP_ENTER=320','deep sleep enter. (sleep mode: %d) (count: %d)'],
['SLEEP_DEEP_SLEEP_EXIT','deep sleep exit (sleep mode: %d)'],
['SLEEP_NO_DEEP_SLEEP','bail early from deep sleep. (sleep mode: %d) (reason: %d)'],
['SLEEP_RPM_HALT_ENTER','rpm halt enter'],
['SLEEP_RPM_HALT_EXIT','rpm halt exit'],
['SLEEP_MPM_INTS','pending mpm interrupts at wakeup: (interrupt_status_1 %d), (interrupt_status_2 %d)'],
['SLEEP_DEEP_SLEEP_ENTER_COMPLETE','deep sleep exit complete (sleep mode: %d)'],
['SLEEP_DEEP_SLEEP_EXIT_COMPLETE','deep sleep exit (sleep mode: %d)'],
['SLEEP_MPM_WAKEUP_TIME','mpm wake up time (wakeup time: 0x%0.8x%0.8x)'],
['SLEEP_GPIO_DUMP','gpio [%d] configuration is %d'],
['SLEEP_EVENT_LAST=383','sleep last event placeholder']
增加SLEEP_GPIO_DUMP這一項。
編譯燒寫rpm.mbn。
讓機器休眠,進入download,抓dump,然後將如下日誌發給平臺技術支援分析。
CODERAM.bin
MSGRAM.bin
DATARAM.bin
以及新編譯出來的RPM_AAAAANAZR.elf。
(2)GPIO暫存器讀取
在RPM可能不是很方便,也可以用busybox來讀取暫存器,例如讀GPIO11:
Physical Address for GPIO_CFG11 = 0x100B000
[email protected]Android:/data/busybox # ./busybox devmem 0x100B000 32
./busybox devmem 0x100B000 32
0x00000203
GPIO_PULL = "11" PULL_UP
FUNC_SEL = "0000" FUNCTION GPIO
DRV_STRENGTH = "000" DRV_2_MA
GPIO_OE = "1" Output Enable
1.12 rpm dump
抓rpm dump,然後把log提供給平臺技術支援。
方法如下:
(1)ps_hold接地
在休眠狀態下,接ps_hold到地少於200mS,機器會進入緊急下載狀態,插入USB,QPST會自動得到memory dump,然後上傳以下幾個檔案:
CODERAM.bin
MSGRAM.bin
DATARAM.bin
以及RPM_AAAAANAZR.elf(必須與機器的編譯時間一致匹配的elf)
(2)改reset為download key
發這些命令改reset為download key:
# cd /sys/kernel/debug/spmi/spmi-0
# echo 0x844 > address
# echo 4 > count
# cat data
00840 -- -- -- -- 0F 07 04 00
# echo 0x00 0x00 0x01 0x00 > data
# cat data
00840 -- -- -- -- 00 00 01 00
# echo 0x00 0x00 0x01 0x80 > data
# cat data
00840 -- -- -- -- 00 00 01 80
然後長按下鍵,會進入download。之後抓取log方法同上。
如果進不了download,需要確認:
CONFIG_MSM_DLOAD_MODE=y
另外也有可能與nv 4399和905有關係。
1.13檢查rpm_stats
檢查rpm_stats是否進入vdd min或者xo/no shutdown。使用下面的命令檢查rpm lower power mode count:
cat /sys/kernel/debug/rpm_stats
如果vmin的count是0,則表明裝置從來沒有進入vdd min;non-zero則說明裝置進入過vdd_min。
RPM Mode: xosd
count:0
time in last mode(msec):0
time since last mode(sec):794
actual last sleep(msec):0
RPM Mode:vmin
count:11
time in last mode(msec):0
time since last mode(sec):359
actual last sleep(msec):110000
1.14使用Trace32
可以dump出來完整詳細的gpio/clk/pmic資訊,排除休眠時候的狀態異常。
2、待機電流優化(Standby Current Optimization)
2.1通過adb log排查
adb logcat -v time > YearMounthDayHourMinute_logcat.txt //main log
adb logcat -v time -b events > YearMounthDayHourMinute_logcat_event.txt //event log
adb logcat -v time -b radio > YearMounthDayHourMinute_logcat_radio.txt //radio log
adb shell dmesg > YearMounthDayHourMinute_dmesg.txt //kernel log
可以採用功耗問題時間追蹤表來精確追蹤功耗異常。
可以使用如下命令來開啟指定檔案的kernel log(以qpnp-adc-tm.c和qpnp-adc-common.c為例):
adb shell mount -t debugfs none /sys/kernel/debug
adb shell "echo 8 > /proc/sys/kernel/printk"
adb shell "echo 'file qpnp-adc-tm.c +p' > /sys/kernel/debug/dynamic_debug/control"
adb shell "echo 'file qpnp-adc-common.c +p' > /sys/kernel/debug/dynamic_debug/control"
adb shell "echo 8 > /proc/sys/kernel/printk"
為指定的函式開啟log,以qpnpint_handle_irq為例:
adb shell "echo 'func qpnpint_handle_irq +p' > /sys/kernel/debug/dynamic_debug/control"
*#logkit#*調出logkit apk,可以儲存logcat、dmesg、crash、QXDM、GPU log等日誌資訊到手機裡面。
2.2 top
通過top命令,可以查詢到cpu佔用較高的應用。如果一個應用一直在佔用cpu,而此時並沒有開啟該應用,那麼該應用很可能會導致待機異常。
adb shell
top
“該場景下CPU使用率”是User+System+IOW+IRQ
“模組相關的CPU佔用率”是模組相關程序佔用CPU使用率的總和
2.3正在執行
設定-->應用-->正在執行,可以看到正在執行的應用或者服務。禁止掉應用或者服務,觀察待機電流變化。
2.4 wakeup debug mask
除錯wakeup問題,可以使能debug功能,然後抓取log。Log中會增加一些debug資訊。
mount -t debugfs none /sys/kernel/debug
echo 1 > /sys/kernel/debug/clk/debug_suspend
echo 1 > /sys/module/msm_show_resume_irq/parameters/debug_mask
echo 4 > /sys/module/wakelock/parameters/debug_mask
echo 1 > /sys/module/lpm_levels/parameters/debug_mask
echo 0x16 > /sys/module/smd/parameters/debug_mask
2.5 wakelock
1、wakeup_sources
kernel wakelock和userspace wakelock都有可能阻止系統睡眠。所有的wakeup_sources均儲存在sys節點/sys/kernel/debug/wakeup_sources裡面。
該檔案包含了如下資訊:
(1)the total amount of time a wakeup source has prevented suspend
(2)the amount of time a wakelock has been active since the last activation etc. The unit of time is milliseconds.
2、active_since
active_since值可以用來確認wakelock是否正在阻止休眠。如果該值不是零,那麼這個wakelock正在工作並且阻止休眠。
3、獲取wakeup_sources的命令
adb root 67754400
adb remount
adb shell
cat /sys/kernel/debug/wakeup_sources > /data/wakeup_sources.txt
adb pull /data/wakeup_sources.txt
獲得wakeup_sources.txt以後,通過Excel開啟,active_since不為0的項為wakeup source。以表2為例,msm_dwc3對應的active-since值481756>0,這意味著msm_dwc3驅動在阻止系統睡眠,下一步需要檢查msm_dwc3驅動程式碼及相關log。
表格 2 Wakeup source opened in Excel
4、power:wakeup_source_activate and power:wakeup_source_deactivate events
當一個wakeup source被acquire或者release時候,power:wakeup_source_activate和power:wakeup_source_deactivate event將隨即被寫到trace buffer裡面,這樣可以記錄wakeup source被driver使用的頻率。
開啟該功能的方法:
echo "power:wakeup_source_activate power:wakeup_source_deactivate" > /sys/kernel/debug/tracing/set_event
The power:wakeup_source_activate and power:wakeup_source_deactivate events are written to the trace buffer any time a wakeup source is acquired or released and it can provide information on how often a wakeup source is being used by a driver.
To enable these events, you can enable following:
echo "power:wakeup_source_activate power:wakeup_source_deactivate" > /sys/kernel/debug/tracing/set_event
Once the above done, the traces will be present in /sys/kernel/debug/tracing/trace.
2.6 powertop
powertop用來看CPU的執行統計以協助除錯power問題。powertop的用法如下:
powertop --h
Usage: powertop [OPTION...]
n -d, --dump read wakeups once and print list of top offenders
n -t, --time=DOUBLE default time to gather data in seconds
n -r, --reset Reset PM stats data
n -h, --help Show this help message
n -v, --version Show version information and exit
獲取powertop log的方法:
1. 通過USB連線手機到電腦
2. adb shell,然後執行如下命令:
sleep 10 && /data/powertop [-r] -d -t 30 > /data/powertop.log &
3. 拔掉USB線,等待10秒後開始功耗測試
4. 插上USB
5. adb pull /data/powertop.log
2.7 CPU freq log
開啟CPU freq change log:
mount -t debugfs none /sys/kernel/debug
cd /sys/kernel/debug
echo -n 'file acpuclock-8x60.c +p' > dynamic_debug/control
echo -n 'file acpuclock-krait.c +p' > dynamic_debug/control
檢視cpu freq stats:
cat /sys/devices/system/cpu/cpu0/cpufreq/stats
cat /sys/devices/system/cpu/cpu1/cpufreq/stats
cat /sys/devices/system/cpu/cpu2/cpufreq/stats
cat /sys/devices/system/cpu/cpu3/cpufreq/stats
To lock cpu freg:
echo the same freq to following sys mode will lock cpu freq to the setting freq.
/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq
/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq
To enable/disable specific freq for ACPU
ACPU freq table is defined in acpu_freq_tbl_* structure of specific platform.
arch/arm/mach-msm/acpuclock-<platform name>.c
For 8974, it is defined in arch/arm/mach-msm/acpuclock-8974.c. the first column of following table used to enable/disable freq in the row: 1:enable, 0:disable
static struct acpu_level acpu_freq_tbl_2p3g_pvs0[] __initdata = {
{ 1, { 300000, PLL_0, 0, 0 }, L2(0), 800000, 72 },
{ 0, { 345600, HFPLL, 2, 36 }, L2(1), 800000, 83 },
{ 1, { 422400, HFPLL, 2, 44 }, L2(2), 800000, 101 },
{ 0, { 499200, HFPLL, 2, 52 }, L2(2), 805000, 120 },
{ 0, { 576000, HFPLL, 1, 30 }, L2(3), 815000, 139 },
{ 1, { 652800, HFPLL, 1, 34 }, L2(3), 825000, 159 },
{ 1, { 729600, HFPLL, 1, 38 }, L2(4), 835000, 180 },
{ 0, { 806400, HFPLL, 1, 42 }, L2(4), 845000, 200 },
{ 1, { 883200, HFPLL, 1, 46 }, L2(4), 855000, 221 },
{ 1, { 960000, HFPLL, 1, 50 }, L2(9), 865000, 242 },
{ 1, { 1036800, HFPLL, 1, 54 }, L2(10), 875000, 264 },
{ 0, { 1113600, HFPLL, 1, 58 }, L2(10), 890000, 287 },
{ 1, {