高通LCD之亮灭屏过程简析

1、如何看亮灭屏时间

adb shell

        kmsgcat |grep fb_blank

2、code简介

        在kernel/drivers/video/msm/mdss/mdss_fb.c中,

        static intmdss_fb_blank_sub(int blank_mode, struct fb_info *info, int op_enable)  

        blank_mode这个参数的值主要有两个,FB_BLANK_UNBLANK和 FB_BLANK_POWERDOWN ,

           FB_BLANK_UNBLANK是亮屏操作;

           FB_BLANK_POWERDOWN 是灭屏操作;

        当要亮屏的时候,传入参数FB_BLANK_UNBLANK时,会执行下面这些函数,

        if (!mfd->panel_power_on &&mfd->mdp.on_fnc) {

            ret = mfd->mdp.on_fnc(mfd);

            if (ret == 0) {

                mfd->panel_power_on = true;

                mfd->panel_info->panel_dead= false;

            }

                mutex_lock(&mfd->update.lock);

                mfd->update.type =NOTIFY_TYPE_UPDATE;

                mfd->update.is_suspend = 0;

                mutex_unlock(&mfd->update.lock);

                /* Start the work thread tosignal idle time */

                if (mfd->idle_time)

                schedule_delayed_work(&mfd->idle_notify_work,

                                msecs_to_jiffies(mfd->idle_time));

            }

            mutex_lock(&mfd->bl_lock);

            if (!mfd->bl_updated) {

                mfd->bl_updated = 1;

                mdss_fb_set_backlight(mfd,mfd->bl_level_prev_scaled);

            }

        mutex_unlock(&mfd->bl_lock);

           }

       当执行ret =mfd->mdp.on_fnc(mfd);会调用(上一篇文章http://blog.csdn.net/liwei16611/article/details/52830483)注册的函数mdss_mdp_overlay_on;

       在mdss_mdp_overlay_on函数中,

       staticint mdss_mdp_overlay_on(struct msm_fb_data_type *mfd)

       {

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

        if (!mdp5_data->ctl) {

                ctl =__mdss_mdp_overlay_ctl_init(mfd);

                if (IS_ERR_OR_NULL(ctl))

                    return PTR_ERR(ctl);

                    mdp5_data->ctl = ctl;

        }

        if (!mfd->panel_info->cont_splash_enabled&&

                (mfd->panel_info->type !=DTV_PANEL)) {

                    rc =mdss_mdp_overlay_start(mfd);

                    if (!IS_ERR_VALUE(rc)&&

                        (mfd->panel_info->type!= WRITEBACK_PANEL)) {

                            atomic_inc(&mfd->mdp_sync_pt_data.commit_cnt);

                            rc= mdss_mdp_overlay_kickoff(mfd, NULL);

                    }

            } else {

                    rc =mdss_mdp_ctl_setup(mdp5_data->ctl);

                if (rc)

                    return rc;

            }

            ......

      }

       在这里我们看到如果mdp5_data->ctl 还没有被初始化,则对他进行初始化,实际上在fb_probe 已经被初始化了, 那在这判断的作用,是为了如果有动态切换的话,                    mdp5_data->ctl 会被置成NULL,当要亮屏的时候回去重新初始化。

       如果连续显示打开的话则mfd->panel_info->cont_splash_enabled会被置1,那么就不去执行mdss_mdp_overlay_start,因为它在fb_probe中已经被执行了。

       执行mdss_mdp_ctl_setup会对pipe 及Mixer 进行一些配置,为传入的帧数据做准备。

       当要显示数据的帧的时候,会从hal 层传入commit的命令,调用 mdss_mdp_display_commit 函数,然后调用display_fnc,

       这个回调函数是在mdss_mdp_video_start中注册的;

       ctl->display_fnc= mdss_mdp_video_display;

       在mdss_mdp_video_display函数中,

       staticint mdss_mdp_video_display(struct mdss_mdp_ctl *ctl, void *arg)

       {

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

        if(!ctx->timegen_en) {

                rc =mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_UNBLANK, NULL);

                if (rc) {

                        pr_warn("intf #%dunblank error (%d)\n",

                                ctl->intf_num,rc);

                        video_vsync_irq_disable(ctl);

                        ctx->wait_pending =0;

                        return rc;

            }

                pr_debug("enabling timinggen for intf=%d\n", ctl->intf_num);

                    if((pdata->panel_info.cont_splash_enabled &&

                        !ctl->mfd->splash_info.splash_logo_enabled)

                            ||(ctl->mfd->splash_info.splash_logo_enabled

                            &&!is_mdss_iommu_attached())) {

                        rc =wait_for_completion_timeout(&ctx->vsync_comp,

                                        usecs_to_jiffies(VSYNC_TIMEOUT_US));

                    }

                    rc = mdss_iommu_ctrl(1);

                    if (IS_ERR_VALUE(rc)) {

                        pr_err("IOMMUattach failed\n");

                        return rc;

                    }

                    mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON,false);

                 mdss_mdp_irq_enable(MDSS_MDP_IRQ_INTF_UNDER_RUN, ctl->intf_num);

            mdss_bus_bandwidth_ctrl(true);

            mdp_video_write(ctx,MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 1);

            wmb();

            rc = wait_for_completion_timeout(&ctx->vsync_comp,

                    usecs_to_jiffies(VSYNC_TIMEOUT_US));

                    WARN(rc == 0, "timeout(%d) enabling timegen on ctl=%d\n",

                        rc, ctl->num);

                    ctx->timegen_en = true;

                    rc =mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_ON, NULL);

                    WARN(rc,"intf %d panel on error (%d)\n", ctl->intf_num, rc);

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

        }

         通过mdss_mdp_ctl_intf_event(ctl,MDSS_EVENT_UNBLANK, NULL); 发送一个event事件,

         dsi_event_handler 会接收到这个事件,去执行dsi_on,mdss_dsi_op_mode_config;

         之后通过mdss_mdp_ctl_intf_event(ctl,MDSS_EVENT_PANEL_ON, NULL);

         dsi_event_handler会接收到这个事件,去执行mdss_dsi_unblank;

         当要灭屏的时候,从hal层会发送stop命令,当驱动接收到这个命令会执行mdss_mdp_video_stop函数;

         staticint mdss_mdp_video_stop(struct mdss_mdp_ctl *ctl)

         {

            rc = mdss_mdp_ctl_intf_event(ctl,MDSS_EVENT_BLANK, NULL);

                    if (rc == -EBUSY) {

                        pr_debug("intf #%dbusy don't turn off\n",

                                ctl->intf_num);

                        return rc;

                }

                WARN(rc, "intf %d blankerror (%d)\n", ctl->intf_num, rc);

                mdp_video_write(ctx,MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 0);

                /* wait for at least one VSYNCon HDMI intf for proper TG OFF */

                if (MDSS_INTF_HDMI ==ctx->intf_type) {

                        frame_rate =mdss_panel_get_framerate

                                        (&(ctl->panel_data->panel_info));

                    if (!(frame_rate >= 24&& frame_rate <= 240))

                            frame_rate = 24;

                            msleep((1000/frame_rate)+ 1);

                    }

                    mdss_iommu_ctrl(0);

                    mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF,false);

                    ctx->timegen_en = false;

                    rc =mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_OFF, NULL);

                    WARN(rc, "intf %dtimegen off error (%d)\n", ctl->intf_num, rc);

                    mdss_mdp_irq_disable(MDSS_MDP_IRQ_INTF_UNDER_RUN,

                                    ctl->intf_num);

                    sctl =mdss_mdp_get_split_ctl(ctl);

                    if (sctl)

                        mdss_mdp_irq_disable(MDSS_MDP_IRQ_INTF_UNDER_RUN,   sctl->intf_num);

                mdss_bus_bandwidth_ctrl(false);

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

      }

      通过mdss_mdp_ctl_intf_event(ctl,MDSS_EVENT_BLANK, NULL);发送灭屏的事件,

      dsi_event_handler会接收到这个事件,会去执行mdss_dsi_blank。

      通过mdss_mdp_ctl_intf_event(ctl,MDSS_EVENT_PANEL_OFF, NULL);发送事件,同样dsi_event_handler 会接收到这个事件,会去执行mdss_dsi_off。

      最后在mdss_fb_suspend_sub中发送FB_BLANK_POWERDOWN,最后屏熄灭。

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