函數加載流程: dsi_panel_init(struct msm_panel_info *pinfo,struct panel_struct *pstruct)---->panel初始化,獲取屏的基本信息,從屏對應的頭文件中; msm_display_init();---->亮屏的開始 pdata->power_func(1, &(panel->panel_info));---->給屏上電,panel.power_func = mdss_dsi_panel_power; pdata->dfps_func(&(panel->panel_info));---->panel.dfps_func = mdss_dsi_mipi_dfps_config; pdata->pll_clk_func(1, &(panel->panel_info));---->使能時鐘;panel.pll_clk_func = mdss_dsi_panel_clock; msm_fb_alloc(&(panel->fb));----->申請FB緩衝區 msm_display_config();------->LCD的基本配置;如;mipi的配置,DSI控制器的初始化等; msm_display_on();------>向LCD屏的寄存器中寫入ON_command命令參數,並檢測mipi的數據通道是不是通路; ret = pdata->bl_func(1);---->背光使能;初始化背光;
上層調用ioctrl()函數向底層FB節點發送亮滅屏事件命令,底層調用fb_ioctrl()函數去調用fb_blank()以通知鏈的方式去通知TP和加載一系列事件函數,根據事件命令去處理對應的操做,而這個
事件處理函數是在DSI驅動中的probe()函數中註冊的;ide
先執行LCD上電事件命令,再執行亮屏事件命令,通過函數調用,最終會調用到在DSI驅動中解析屏的on_command命令參數寫入到LCD屏對應的寄存器中,亮屏後,在打開背光;函數
執行滅屏操做和亮屏操做其實差很少,也是把滅屏的OFF_command指令寫到LCD寄存器中,但在執行命令以前,會把背光設置爲0,關閉背光;在執行完滅屏事件後,再去執行給LCD下電的操做;spa
亮屏操做流程;線程
fb_ioctl()------->framebuff節點對應的函數操做,位置:fbdev/core/fbmem.c ,建立一個FB節點給上層去操做; info = file_fb_info(file);---->獲取mdss_fb_probe()裏面註冊的一些函數; do_fb_ioctl(); fb_blank(struct fb_info *info, int blank);---->參數blank就是下面函數中的blank_mode;這個是亮屏的起始函數; fb_notifier_call_chain(FB_EARLY_EVENT_BLANK, &event);---->TP通知鏈,通知TP作一些相應的動做; mdss_fb_blank(int blank_mode, struct fb_info *info);------>啓動事件子系統;---->fb_blank = mdss_fb_blank();在fb_probe中註冊的; mdss_fb_blank_sub(int blank_mode, struct fb_info *info,int op_enable);----->switch函數中判斷的根據blank_mode; mdss_fb_blank_unblank(mfd);----->亮屏操做; mfd->mdp.on_fnc();--->mdp5_interface->on_fnc = mdss_mdp_overlay_on; mdss_mdp_overlay_on();------>mdp5_interface->on_fnc = mdss_mdp_overlay_on; mdss_mdp_overlay_kickoff(); mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg,struct mdss_mdp_commit_cb *commit_cb); ctl->ops.display_fnc;----->ctl->ops.display_fnc = mdss_mdp_video_display; mdss_mdp_video_display()回調函數註冊在mdss_mdp_video_start()中;/////////// mdss_mdp_video_display();------->亮屏的主要函數; mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_LINK_READY, NULL,CTL_INTF_EVENT_FLAG_DEFAULT);---->上電操做; mdss_dsi_on(struct mdss_panel_data *pdata); mdss_dsi_panel_power_ctrl(pdata, MDSS_PANEL_POWER_ON);---->上電操做 mdss_mdp_ctl_intf_event(ctl,MDSS_EVENT_UNBLANK, NULL,CTL_INTF_EVENT_FLAG_DEFAULT);----->發送亮屏(MDSS_EVENT_UNBLANK)和滅屏(MDSS_EVENT_BLANK)事件來點亮和熄滅屏; rc = pdata->event_handler(pdata, event, arg);------->接受事件去處理;ctrl_pdata->panel_data.event_handler = mdss_dsi_event_handler; mdss_dsi_event_handler(struct mdss_panel_data *pdata,int event, void *arg);-----》事件處理函數; mdss_dsi_unblank(struct mdss_panel_data *pdata);----->點亮屏和使能TE引腳中斷等功能; ctrl_pdata->on(pdata);--->ctrl_pdata->on = mdss_dsi_panel_on; mdss_dsi_panel_on(struct mdss_panel_data *pdata);---->發送on命令和屏幕相關參數命令; mdss_dsi_panel_cmds_send(ctrl, on_cmds, CMD_REQ_COMMIT);---->發送on_cmds,CE_cmds,CABC_cmds等命令; mdss_mdp_ctl_intf_event(ctl,MDSS_EVENT_PANEL_ON, NULL);---->也是點亮屏,只是這個另外一模式HS模式,這個模式主要在dtsi文件中去配; mdss_fb_set_backlight(mfd, mfd->unset_bl_level);----->打開背光;
滅屏函數流程:設計
在這裏插入fb_ioctl()------->framebuff節點對應的函數操做,位置:fbdev/core/fbmem.c ,建立一個FB節點給上層去操做; info = file_fb_info(file);---->獲取mdss_fb_probe()裏面註冊的一些函數; do_fb_ioctl(); fb_blank(struct fb_info *info, int blank);---->參數blank就是下面函數中的blank_mode;這個是亮屏的起始函數; fb_notifier_call_chain(FB_EARLY_EVENT_BLANK, &event);---->TP通知鏈,通知TP; mdss_fb_blank(int blank_mode, struct fb_info *info);------>啓動事件子系統;---->fb_blank = mdss_fb_blank();在fb_probe中註冊的; mdss_fb_blank_sub(int blank_mode, struct fb_info *info,int op_enable);----->switch函數中判斷的根據blank_mode; mdss_fb_blank_blank(); mdss_panel_is_power_off(req_power_state);----->有一個電源狀態檢測; mdss_fb_stop_disp_thread(mfd);--->關閉那個dispaly處理線程; mdss_fb_set_backlight(mfd, 0);---->設置背光亮度爲0;關閉背光; mdss_mdp_overlay_off(mfd);---->mdp5_interface->off_fnc = mdss_mdp_overlay_off; mdss_mdp_ctl_stop(mdp5_data->ctl, mfd->panel_power_state);--->滅屏 mdss_mdp_video_stop(struct mdss_mdp_ctl *ctl, int panel_power_state);-------->ctl->ops.stop_fnc = mdss_mdp_video_stop; mdss_mdp_video_intfs_stop(); mdss_mdp_video_ctx_stop(); mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_BLANK, NULL,CTL_INTF_EVENT_FLAG_DEFAULT); mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_OFF, NULL,CTL_INTF_EVENT_FLAG_DEFAULT); mdss_dsi_blank();----->滅屏事件處理函數 ctrl_pdata->off(pdata);---->滅屏指令的發送; mdss_dsi_panel_off(struct mdss_panel_data *pdata); mdss_dsi_panel_cmds_send(ctrl, &ctrl->off_cmds, CMD_REQ_COMMIT); mdss_dsi_off(pdata, power_state);---->下電操做; mdss_dsi_panel_power_ctrl(pdata, power_state);----下電;代碼片
背光概念:背光是控制屏幕亮度, 背光控制有3種方式: 1.LED燈控制背光,經過控制LED的電流大小,來控制最大亮度,經過控制級數來控制背光的變化;(pmic提供引腳) 2.PWM的方式控制背光,從電路中引出某一引腳來控制三極管電路,從而控制電路的電流大小;(單獨的電路芯片) 3.命令集的方式控制背光,經過以命令的方式向寄存器中寫入控制的值來控制電路;(它的供電的腳是從LCD芯片引出來的) wled方式背光驅動路徑:kernel/msm-3.18/drivers/leds 背光級別的映射關係:(這個很重要,跟上層設置滑動亮度進度條,亮度值大小有關係,) #define MDSS_BRIGHT_TO_BL(out, v, bl_max, max_bright) do {\ out = (2 * (v) * (bl_max) + max_bright);\ do_div(out, 2 * max_bright);\ } while (0) mdss_fb_probe(): backlight_led.brightness = mfd->panel_info->brightness_max; backlight_led.max_brightness = mfd->panel_info->brightness_max; led_classdev_register(&pdev->dev, &backlight_led);---->註冊背光目錄和節點供上層使用;(重要點,上層會操做該目錄的節點去控制背光亮度) device_create_with_groups();----->建立背光組控制;一系列的節點文件; 上層對節點寫亮度值,底層亮度設置的操做流程: mdss_fb_set_bl_brightness();---->mdss_fb.c mdss_fb_set_backlight();----->mdss_fb.c mdss_fb_scale_bl(mfd, &temp);----->CABL開啓後,會從新計算出一個背光值,目的是下降功耗; pdata->set_backlight(pdata, temp);----->mdss_dsi_panel.c mdss_dsi_panel_bl_ctrl(struct mdss_panel_data *pdata, int level);----->這邊已經能夠達到4095級別; led_trigger_event(struct led_trigger *trig, int brightness); led_set_brightness(struct led_classdev *led_cdev, int brightness); __led_set_brightness(struct led_classdev *led_cdev, int brightness); led_cdev->brightness_set(led_cdev, brightness);----->函數指針的方式跳轉到設置函數; qpnp_wled_set(led_cdev, brightness);------->kernel/msm-3.18/drivers/leds/leds-qpnp-wled.c schedule_work(&wled->work);----->調用工做隊列,使用工做線程去執行這設置函數; qpnp_wled_set_level(struct qpnp_wled *wled, int level); qpnp_wled_write_reg();------>分別向寄存器中寫入高8位和低8位數據; qpnp_wled_sync_reg_toggle();---->同步寄存器 qpnp_wled_module_en();----->背光是否使能;
DSI時鐘計算以下: H-total = HorizontalActive + HorizontalFrontPorch + HorizontalBackPorch + HorizontalSyncPulse + HorizontalSyncSkew(data + 前肩 +後肩 + 行同步(換行時鐘 + 電子前移時鐘)) V-total = VerticalActive + VerticalFrontPorch + VerticalBackPorch + VerticalSyncPulse + VerticalSyncSkew Total pixel = H-total * V-total * 60(Hz一般都是這個,固然能夠變). Bitclk = Total pixel * bpp(byte) *8/lane number(有幾路mipi data lane). Byteclk = bitclk/8 Dsipclk(Dsi pixel clock) = (Byteclk * lane number)/bpp(byte) = Total pixel * 8 Byteclk = pclk * pixel depth / lane number 另外一種寫法:(一秒傳輸數據的所須要的時鐘,這跟幀率有關係) PLL_CLOCK:Mipiclock = [ (width+hsync+hfp+hbp) x (height+vsync+vfp+vbp) ] x(bus_width) x fps/ (lane_num)/2; MIPI時鐘是每一條數據通道的時鐘,由於在傳輸數據的時候,是多數據通道同時在傳輸數據,而且只用一個時鐘腳;
高通的esd功能也是經過dtsi來配置的。如: qcom,esd-check-enabled; qcom,mdss-dsi-panel-status-command = [06 01 00 01 05 00 01 0A];//read reg qcom,mdss-dsi-panel-status-command-mode = "dsi_lp_mpde"; qcom,mdss-dsi-panel-status-check-mode = "reg_read"; qcom,mdss-dsi-panel-status-read-length = <1>; qcom,mdss-dsi-panel-status-valid-params = <1>; qcom,mdss-dsi-panel-status-value = <0x9C>;//right value qcom,mdss-dsi-panel-max-error-count = <3>; 須要注意的是,這些屬性對應的參數除qcom,mdss-dsi-panel-max-error-count都沒有默認值,若是配置不完整,可能會致使整個esd功能失效。配置完成後,確保屏幕無異常。 能夠修改qcom,mdss-dsi-panel-status-value爲其餘值,觀察是否有esd resume狀況發生。判斷esd機制是否生效。 總結:上層會在定時去檢查屏幕是否有問題,而ESD這個功能的檢測就去檢測是否有問題,ESD功能的檢測有兩種方式,一種是TE引腳的方式(硬件),一種是讀取寄存器值的方式(軟件); 到時候系統去定時檢測屏狀態時,會根據dtsi裏配置的ESD方式去調用相應的函數來檢測;根據 "qcom,mdss-dsi-panel-status-check-mode"去判斷哪種模式; 1.讀寄存器方式check dsi 狀態的流程: __init mdss_dsi_status_init(void);--->驅動加載函數; check_dsi_ctrl_status();---->INIT_DELAYED_WORK(&pstatus_data->check_status, check_dsi_ctrl_status);工做隊列的方式; mdss_check_dsi_ctrl_status();----->pdsi_status->mfd->mdp.check_dsi_status(work, ESD_interval);工做隊列的方式; mdss_dsi_reg_status_check();---->會把這個函數放在延遲工做隊列中去執行; mdss_dsi_gen_read_status();------->check_read_status(ctrl_pdata);---->ctrl->check_read_status = mdss_dsi_gen_read_status; mdss_dsi_cmp_panel_reg_v2();----->讀取對應的寄存器值,並與在以前的dtsi文件設置的值,進行比較; 2.TE引腳中斷方式去check dsi 狀態的流程; __init mdss_dsi_status_init(void);--->q驅動加載函數; check_dsi_ctrl_status();---->INIT_DELAYED_WORK(&pstatus_data->check_status, check_dsi_ctrl_status);工做隊列的方式; mdss_check_dsi_ctrl_status();----->pdsi_status->mfd->mdp.check_dsi_status(work, ESD_interval);工做隊列的方式; mdss_dsi_TE_NT35596_check();------->硬件中斷的方式去檢測DSI狀態;
花屏問題:
1.LCD初始化時序信號不對;
2.花屏還有一種多是Baseband給LCD送的數據跟LCD工做模式不對。好比你對LCD的工做模式設爲RGB565,但你給它送的數據是RGB444或RGB666;
3.host對LCD讀寫過快;指針
開機LCD亮的瞬間有花屏問題:
解釋:通常都是因爲LCD在初始化完成後刷新第一副圖像未徹底準備好的時候背光已經亮了。解決的辦法就是在UBOOT時候背光亮以前的延時相應的加長一點。code
屏幕閃爍問題:1.背光閃爍;2.屏幕閃爍;隊列
在休眠狀況下,從新喚醒屏,使用一段時間出現燒屏問題:
緣由:在滅屏狀況下,不斷喚醒上電操做和睡眠操做致使IC芯片;PM頻繁調用TP suspend/resume,當LCD 處於sleep in狀態,頻繁進出LPWG會致使IC狀態異常,擊穿VCOM。
解決方案:1.只在FFBM模式下PM才能調用TP resume/suspend(喚醒/休眠); 2.IC廠商修改TP固件,保證出現這種現象也不會形成IC芯片燒壞;事件
打開CABC開關,偶現花屏現象:圖片
緣由:屏幕的相關參數問題,在config的時候沒有配置上;
解決方案:修改相關屏的初始化參數,