前面聊的
最近在調試項目的亮屏速度,我們希望在按下power鍵后到亮屏這個時間能達到500MS以內,在Rockchip 3399和3288上面的時間都不能達到要求,因此引發了一系列的調試之路。
計算按下power鍵到亮屏的時間
Android 喚醒時間統計
剛開始的時候,我只在android階段統計時間,也能看到時間的差異,但是不是最準確的,我統計的時間日志如下
01-18 09:13:40.992 683 772 D SurfaceControl: Excessive delay in setPowerMode(): 743ms
01-18 09:13:45.304 683 772 D SurfaceControl: Excessive delay in setPowerMode(): 757ms
01-18 09:13:49.559 683 772 D SurfaceControl: Excessive delay in setPowerMode(): 725ms
01-18 09:18:27.461 683 772 D SurfaceControl: Excessive delay in setPowerMode(): 741ms
01-18 09:18:32.766 683 772 D SurfaceControl: Excessive delay in setPowerMode(): 743ms
01-18 09:18:35.861 683 772 D SurfaceControl: Excessive delay in setPowerMode(): 745ms
01-18 09:18:38.345 683 772 D SurfaceControl: Excessive delay in setPowerMode(): 733ms
Kernel從Power到亮屏的時間統計
后來同事中的精英古總在他的代碼上加入了從按下Power鍵到亮屏的時間,直接通過printk打印,代碼如下
diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.cold mode 100644new mode 100755index 17c3b94..2b39662--- a/drivers/gpu/drm/panel/panel-simple.c+++ b/drivers/gpu/drm/panel/panel-simple.c@@ -504,6 +504,7 @@ static int panel_simple_enable(struct drm_panel *panel) } p->enabled = true;+ printk("%s exit/n", __func__); return 0; }diff --git a/drivers/input/keyboard/rk_keys.c b/drivers/input/keyboard/rk_keys.cold mode 100644new mode 100755index fed5ced..537b599--- a/drivers/input/keyboard/rk_keys.c+++ b/drivers/input/keyboard/rk_keys.c@@ -134,6 +134,10 @@ static void keys_timer(unsigned long _data) key_dbg(pdata, "%skey[%s]: report event[%d] state[%d]/n", button->type == TYPE_ADC ? "adc" : "gpio", button->desc, button->code, button->state);+ if(strcmp(button->desc, "power") == 0)+ printk("%skey[%s]: report event[%d] state[%d]/n",+ button->type == TYPE_ADC ? "adc" : "gpio",+ button->desc, button->code, button->state); input_event(input, EV_KEY, button->code, button->state); input_sync(input); }
統計每個驅動的resume函數調用時間
上面的時間對我們調試非常有用,然后就需要細分到每個驅動的resume函數執行的時間,用的方法是我之前寫過的,大概統計了下TP,LCD,sensor的resume時間,發現TP和LCD占用的時間非常多,然后跟同事一起看了下,同事把TP resume里面的代碼用工作隊列實現后速度明顯有了提升。
然后有很長一段時間不知道干嘛,向打印其他每個驅動的resume時間,一直沒找到方法,后面看到一個代碼,非常有用。
kernel/drivers/base/power/main.c
static void dpm_show_time(ktime_t starttime, pm_message_t state, char *info) { ktime_t calltime; u64 usecs64; int usecs; calltime = ktime_get(); usecs64 = ktime_to_ns(ktime_sub(calltime, starttime)); do_div(usecs64, NSEC_PER_USEC); usecs = usecs64; if (usecs == 0) usecs = 1; pr_info("PM: %s%s%s of devices complete after %ld.%03ld msecs/n", info ?: "", info ? " " : "", pm_verb(state.event), usecs / USEC_PER_MSEC, usecs % USEC_PER_MSEC);}
這個函數用來打印resume的函數消耗的時間,但是如何去觸發打印這個函數呢?
echo N > /sys/module/printk/parameters/console_suspend//使控制臺在suspend最后才關閉,這樣可以打印出休眠過程完整信息echo 1 > /sys/power/pm_print_times//使能調試變量
打印的LOG類似下面的
[ 37.031413] bcmsdh_sdmmc_resume Exit
[ 37.082174] PM: resume of devices complete after 78.589 msecs
[ 37.085277] [BT_RFKILL]: ** disable irq
[ 37.087645] Restarting tasks ...
修改Lcd配置減小resume時間
古總在調試過程中展現了非常厲害的功底,第一步就是修改了LCD的參數,讓亮屏時間加快。修改如下
--- a/arch/arm/boot/dts/rk3288-pad.dts+++ b/arch/arm/boot/dts/rk3288-pad.dts@@ -169,10 +169,10 @@ dsi,lanes = <4>; prepare-delay-ms = <20>;- init-delay-ms = <20>;- enable-delay-ms = <100>;- disable-delay-ms = <20>;- unprepare-delay-ms = <20>;+ //init-delay-ms = <20>;+ enable-delay-ms = <1>;+ disable-delay-ms = <1>;+ unprepare-delay-ms = <1>; panel-init-sequence = [ 15 32 02 8F A5 15 01 02 83 00
修改DRM 超時時間減小喚醒時間
這是最關鍵的,DRM框架非常復雜,RK也是從開源的DRM移植過來使用,在DRM部分有個時間導致問題,最終跟RK拿到最新的patch讓喚醒時間直接加速500MS.
我們在日志下發現問題,并給詢問了RK,最終發現這部分代碼沒有更新到最新的部分。
hi rk:
為什么亮屏的時候有時候會打印這句VOP等待超時?請問下這是什么意思。
[ 1211.293492] rockchip-vop ff930000.vop: wait win close timeout
[ 1211.293514] rockchip-vop ff930000.vop: [drm:vop_crtc_enable] Update mode to 1200*1920, close all win
有時候卻不會打印。
[ 1216.423283] rockchip-vop ff930000.vop: [drm:vop_crtc_enable] Update mode to 12001920, close all win [ 1223.899741] rockchip-vop ff930000.vop: [drm:vop_crtc_enable] Update mode to 12001920, close all win
[ 1234.386252] rockchip-vop ff930000.vop: [drm:vop_crtc_enable] Update mode to 1200*1920, close all win
代碼如下
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@@ -139,6 +139,9 @@ #define to_vop_win(x) container_of(x, struct vop_win, base) #define to_vop_plane_state(x) container_of(x, struct vop_plane_state, base)+/*add by VENDOR_PATCH for seep up the drm vop driver at 2018/1/18 for RK Defect #191554, VENDOR_PATCH PAD100-193*/+#define VENDOR_PATCH+ struct vop_zpos { int win_id; int zpos;@@ -868,9 +871,15 @@ static void vop_disable_all_planes(struct vop *vop) vop_disable_allwin(vop); vop_cfg_done(vop);+#ifdef VENDOR_PATCH ret = readx_poll_timeout_atomic(vop_is_allwin_disabled, vop, active, active,+ 0, 100 * 1000);+#else+ ret = readx_poll_timeout_atomic(vop_is_allwin_disabled,+ vop, active, active, 0, 500 * 1000);+#endif if (ret) dev_err(vop->dev, "wait win close timeout/n"); }@@ -2215,20 +2224,36 @@ static size_t vop_crtc_bandwidth(struct drm_crtc *crtc, u16 htotal = adjusted_mode->crtc_htotal; u16 vdisplay = adjusted_mode->crtc_vdisplay; int clock = adjusted_mode->crtc_clock;+#ifndef VENDOR_PATCH struct vop *vop = to_vop(crtc); const struct vop_data *vop_data = vop->data;+#endif struct vop_plane_state *vop_plane_state; struct drm_plane_state *pstate; struct vop_bandwidth *pbandwidth; struct drm_plane *plane; u64 bandwidth; int i, cnt = 0;+#ifdef VENDOR_PATCH+ int plane_num = 0;+#endif if (!htotal || !vdisplay) return 0;+#ifndef VENDOR_PATCH pbandwidth = kmalloc_array(vop_data->win_size, sizeof(*pbandwidth), GFP_KERNEL);+#else+ for_each_plane_in_state(state, plane, pstate, i) {+ if (pstate->crtc != crtc || !pstate->fb)+ continue;+ plane_num++;+ }+ pbandwidth = kmalloc_array(plane_num, sizeof(*pbandwidth),+ GFP_KERNEL);+#endif+ if (!pbandwidth) return -ENOMEM;@@ -2421,7 +2446,10 @@ static void vop_crtc_enable(struct drm_crtc *crtc) rockchip_set_system_status(sys_status); mutex_lock(&vop->vop_lock); vop_initial(crtc);-+#ifdef VENDOR_PATCH+ vop_disable_allwin(vop);+ VOP_CTRL_SET(vop, standby, 0);+#endif VOP_CTRL_SET(vop, dclk_pol, 1); val = (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) ? 0 : BIT(HSYNC_POSITIVE);@@ -2549,8 +2577,9 @@ static void vop_crtc_enable(struct drm_crtc *crtc) /* * enable vop, all the register would take effect when vop exit standby */+#ifndef VENDOR_PATCH VOP_CTRL_SET(vop, standby, 0);-+#endif enable_irq(vop->irq); drm_crtc_vblank_on(crtc); mutex_unlock(&vop->vop_lock);
休眠喚醒流程圖
從網上拷貝了個休眠喚醒的流程圖,如果以后有問題需要分析的話,可以跟進這個流程去排查。
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對VEVB武林網的支持。
新聞熱點
疑難解答