高通LCD之显示帧数据简析

1、显示帧数据

MDP和SurfaceFlinger之间通过hal层来链接

       hwcomposer便是两者之间的桥梁。

       hwcomposer显示前,要打开framebuffer设备

       hardware/qcom/display/libhwcomposer/hwc_utils.cpp文件:

       static int openFramebufferDevice(hwc_context_t *ctx)

       {

             ...................

                  int fb_fd = openFb(HWC_DISPLAY_PRIMARY);

             .....................

                 ioctl(fb_fd, MSMFB_METADATA_GET, &metadata)

      }

      打开设备之后,发送 MSMFB_METADATA_GET获取到memory data;

      之后通过hwc_vsync_control函数,发送MSMFB_OVERLAY_VSYNC_CTRL,来获得VSYNC 的控制。

      发送MSMFB_MDP_PP,来设置mdp 的pipe类型。

      最后发送MSMFB_DISPLAY_COMMIT,调用到MDP的mdss_fb_display_commit

      flush 第一帧画面,则此时第一帧画面显示出现。

      发送MSMFB_OVERLAY_PREPARE,来准备overlay machine。调用MDP 的__handle_ioctl_overlay_prepare 函数。实现例如z_order, pipesetup相关的设置。

      发送MSMFB_BUFFER_SYNC,调用MDP的mdss_fb_handle_buf_sync_ioctl来实现Buffer 的同步控制。

      发送MSMFB_OVERLAY_PLAY,调用mdss_mdp_overlay_play,mdss_mdp_overlay_start,来打开overlay machine。

      发送MSMFB_DISPLAY_COMMIT,调用mdss_fb_display_commit,继续显示下一帧画面。

2、实现显示mode切换

    首先,需要MDP 的DSI 接口支持Video Mode 和 CommandMode,显示屏也可以支持Video Mode 和 Command Mode。

    在kernel/arch/arm/boot/dts/msm89***.dts中

           &dsi_sharp_1080_vid {

            qcom,mdss-dsi-panel-type= "dsi_video_mode";

            qcom,mdss-dsi-on-command= [15 01 00 00 00 00 02 ff 10

                1501 00 00 00 00 02 bb 10

                1501 00 00 00 00 02 b0 03

                1501 00 00 00 00 02 ff 10

                0501 00 00 00 00 02 35 00

                0501 00 00 64 00 01 11

                1501 00 00 00 00 02 51 ff

                1501 00 00 00 00 02 53 24

                1501 00 00 00 00 02 55 83

                1501 00 00 00 00 02 ff f0

                15 01 00 00 00 00 02 92 01

                15 01 00 00 00 00 02 13 01

                1501 00 00 00 00 02 ff 10

                0501 00 00 28 00 01 29];

            qcom,mdss-dsi-traffic-mode= "burst_mode";

            qcom,cont-splash-enabled;

            qcom,dynamic-mode-switch-enabled;

            qcom,video-to-cmd-mode-switch-commands= [15 01 00 00 00 00 02 ff 10

                1501 00 00 00 00 02 bb 10

                1501 00 00 00 00 02 b0 03

                1501 00 00 00 00 02 ff 10

                0501 00 00 00 00 02 35 00

                0501 00 00 64 00 01 11

                1501 00 00 00 00 02 51 ff

                1501 00 00 00 00 02 53 24

                1501 00 00 00 00 02 55 83

                1501 00 00 00 00 02 ff f0

                1501 00 00 00 00 02 92 01

                1501 00 00 00 00 02 13 01

                1501 00 00 00 00 02 ff 10

                0501 00 00 28 00 01 29];

            qcom,mdss-dsi-cmd-reset-sequence= <1 20>, <0 200>, <1 20>;

            qcom,mdss-dsi-te-pin-select= <1>;

            qcom,mdss-dsi-te-v-sync-rd-ptr-irq-line= <0x2c>;

            qcom,mdss-dsi-te-v-sync-continues-lines= <0x3c>;

            qcom,mdss-dsi-te-dcs-command= <1>;

            qcom,mdss-dsi-te-check-enable;

        qcom,mdss-dsi-te-using-te-pin;

        qcom,cmd-to-video-mode-switch-commands= [15 01 00 00 00 00 02 ff 10

                1501 00 00 00 00 02 bb 13

                1501 00 00 00 00 02 b0 03

                1501 00 00 00 00 02 ff 10

                0501 00 00 00 00 02 35 00

                0501 00 00 64 00 01 11

                1501 00 00 00 00 02 ff 10

                0501 00 00 28 00 01 29];

        qcom,mdss-dsi-video-reset-sequence= <1 2>, <0 2>, <1 10>;

        }

        需要添加dynamic-mode-switch-enabled,使能动态切换的开关。

        添加cmd-to-video-mode-switch-commands, video-to-cmd-mode-switch-commands 的命令也就是是panel on 的command序列。

        添加 mdss-dsi-cmd-reset-sequence, mdss-dsi-video-reset-sequence。

        添加mdss-dsi-te-pin-select,mdss-dsi-te-v-sync-rd-ptr-irq-line,mdss-dsi-te-v-sync-continues-lines,mdss-dsi-te-dcs-command, mdss-dsi-te-check-enable,

         mdss-dsi-te-using-te-pin,在probe初始化的时候,这些资源就应该提前申请。

         则此时在dtsi文件中所需求的内容就已经准备好了。

        接下来,在kernel/drivers/video/msm/mdss/mdss_fb.c中,mdss_fb_blank函数中,做如下修改:

         if((mfd->switch_en == 1) && (blank_mode == FB_BLANK_UNBLANK)) {

            if (mfd->switch_mod != last_sw_mod) {

                pr_debug("panelswitch mode : %d\n", mfd->switch_mod);

                mfd->mdp.configure_panel(mfd,mfd->switch_mod);

                mdss_fb_set_mdp_sync_pt_threshold(mfd);

                pdata->panel_info.is_lpm_mode= false;

                last_sw_mod= mfd->switch_mod;

            }

       }

         当切换被使能,且在亮屏的时候,如果显示模式有变化,则进行切换。

         切换时主要的执行函数是 configure_panel 也就是mdss_mdp_update_panel_info函数。

         staticint mdss_mdp_update_panel_info(struct msm_fb_data_type *mfd, int mode)  

         {

              ------------

             ret = mdss_mdp_ctl_intf_event(ctl,MDSS_EVENT_DSI_DYNAMIC_SWITCH,

              (void*)(unsigned long)mode);

               if (ret)

                     pr_err("Dynamicswitch to %s mode failed!\n",

                                mode? "command" : "video");

            /*

            *Destroy current ctrl sturcture as this is

            *going to be re-initialized with the requested mode.

            */

            mdss_mdp_ctl_destroy(mdp5_data->ctl);

            mdp5_data->ctl= NULL;

            -------------------------

       }

       首先发送MDSS_EVENT_DSI_DYNAMIC_SWITCH ,当dsi_event_handler接收到这个命令后,会执行mdss_dsi_update_panel_config这个函数。在这个函数中,

       staticint mdss_dsi_update_panel_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata,

       int mode)

       {

           ------------------------

    if (mode ==DSI_CMD_MODE) {

            pinfo->mipi.mode= DSI_CMD_MODE;

            pinfo->type= MIPI_CMD_PANEL;

            pinfo->mipi.vsync_enable= 1;

            pinfo->mipi.hw_vsync_mode= 1;

            pinfo->mipi.force_clk_lane_hs= 0;

            pinfo->mipi.traffic_mode= DSI_NON_BURST_SYNCH_EVENT;

     } else {>-------/*video mode*/

                  pinfo->mipi.mode = DSI_VIDEO_MODE;

                    pinfo->type = MIPI_VIDEO_PANEL;

                    pinfo->mipi.vsync_enable = 0;

                    pinfo->mipi.hw_vsync_mode = 0;

                  pinfo->mipi.force_clk_lane_hs = 1;

                   pinfo->mipi.traffic_mode = DSI_BURST_MODE;

              }

               ctrl_pdata->panel_mode = pinfo->mipi.mode;

               mdss_panel_get_dst_fmt(pinfo->bpp, pinfo->mipi.mode,

              pinfo->mipi.pixel_packing, &(pinfo->mipi.dst_format));

            pinfo->cont_splash_enabled = 0;

            pr_info("%s: switching to %s mode\n", __func__,

                                               (pinfo->mipi.mode ? "command" : "video"));

              if (pinfo->type == MIPI_CMD_PANEL) {

                  ctrl_pdata->switch_mode(&ctrl_pdata->panel_data,DSI_CMD_MODE);

            }else if (pinfo->type == MIPI_VIDEO_PANEL) {

                  ctrl_pdata->switch_mode(&ctrl_pdata->panel_data,DSI_VIDEO_MODE);

            }

             ------------

         }

      在这个函数中我们要把所有和显示模式有关的参数都做修改。例如:pinfo->mipi。

      switch_mode = mdss_dsi_panel_switch_mode;

      在mdss_dsi_panel_switch_mode函数中,需要根据显示模式去-mdss_dsi_parse_reset_seq 更新显示的序列。

      回到 mdss_mdp_update_panel_info ,mdss_mdp_ctl_destroy(mdp5_data->ctl);mdp5_data->ctl= NULL; 会把 mdp5_data->ctl之前注册的函数销毁掉,当执行mdss_mdp_overlay_on         的时候 mdp5_data->ctl 会被重新注册。之后执行过程都会按着目标Panel type 来执行。

你可能感兴趣的:(Android之LCD开发)