zoukankan      html  css  js  c++  java
  • MSM8909中LK阶段LCM屏适配与显示流程分析(二)

    1、前言

    在前面的文章《MSM8909中LK阶段LCM屏适配与显示流程分析(一)》,链接如下:

    https://www.cnblogs.com/Cqlismy/p/12019317.html

    介绍了如何使用GCDB工具生成要适配的屏幕的相关配置文件,同时,也介绍了如何在LK启动阶段中,在基于Qualcomm的LCD屏幕软件驱动框架中,修改相应的文件去适配一款屏幕,此外,该文章是"MSM8909中LK阶段LCM屏适配与显示流程分析"的第二部分,主要是分析LK启动阶段中屏幕的初始化和显示流程是怎么样的。

    2、LK中屏初始化和显示流程分析

    LK启动阶段中,LCM屏幕的初始化和log的显示是在aboot_init()函数中完成,调用的函数为target_display_init(),具体代码如下:

        /* Display splash screen if enabled */
    #if DISPLAY_SPLASH_SCREEN
        dprintf(INFO, "Display Init: Start
    ");
        target_display_init(device.display_panel);
        dprintf(INFO, "Display Init: Done
    ");
    #endif

    开启debug信息后,LK启动阶段中会输出如下的调试信息:

    从启动的输出的调试信息,可以知道大概的初始化流程了,调用target_display_init()函数后,会通过panel_id变量的值,选择相应要初始化和显示的LCD屏幕,根据LCD屏幕的相关配置参数,去完成MSM8909芯片的mipi dsi接口的初始化,然后打开panel,进行启动log的显示。

    接下来,开始对代码进行分析,对于target_display_init()函数的定义在文件:

    msm8909_7.1/bootable/bootloader/lk/target/msm8909/target_display.c

    该函数的定义如下:

    void target_display_init(const char *panel_name)
    {
        uint32_t panel_loop = 0;
        uint32_t ret = 0;
    ...
    do { target_force_cont_splash_disable(false); ret = gcdb_display_init(panel_name, MDP_REV_305, MIPI_FB_ADDR); if (!ret || ret == ERR_NOT_SUPPORTED) { break; } else { target_force_cont_splash_disable(true); msm_display_off(); } } while (++panel_loop <= oem_panel_max_auto_detect_panels()); }

    在这里,panel_name字符串为空串,panel的选择是通过panel_id进行选择的,在上面的代码中,可以看到,target_display_init()函数调用了gcdb_display_init()函数,该函数在文件:

    msm8909_7.1/bootable/bootloader/lk/dev/gcdb/display/gcdb_display.c

    函数的定义如下所示:

    int gcdb_display_init(const char *panel_name, uint32_t rev, void *base)
    {
        int ret = NO_ERROR;
        int pan_type;
    
        /* 通过panel_id选择屏幕,并填充panelstruct和panel.panel_info */
        pan_type = oem_panel_select(panel_name, &panelstruct, &(panel.panel_info),
                     &dsi_video_mode_phy_db); 
    
        if (pan_type == PANEL_TYPE_DSI) { /* 判断panel是否是dsi显示接口 */
            init_platform_data();    /* 初始化dsi显示模式的数据 */
            if (dsi_panel_init(&(panel.panel_info), &panelstruct)) {
                dprintf(CRITICAL, "DSI panel init failed!
    ");
                ret = ERROR;
                goto error_gcdb_display_init;
            }
    
            panel.panel_info.mipi.mdss_dsi_phy_db = &dsi_video_mode_phy_db;
            panel.pll_clk_func = mdss_dsi_panel_clock;
            panel.power_func = mdss_dsi_panel_power;
            panel.pre_init_func = mdss_dsi_panel_pre_init;
            panel.bl_func = mdss_dsi_bl_enable;
            panel.fb.base = base;
            panel.fb.width =  panel.panel_info.xres;
            panel.fb.height =  panel.panel_info.yres;
            panel.fb.stride =  panel.panel_info.xres;
            panel.fb.bpp =  panel.panel_info.bpp;
            panel.fb.format = panel.panel_info.mipi.dst_format;
        }
    
        panel.fb.base = base;
        panel.mdp_rev = rev;
    
        ret = msm_display_init(&panel);
    
    error_gcdb_display_init:
        display_enable = ret ? 0 : 1;
        return ret;
    }

    上面的函数调用后,调用oem_panel_select()函数来选择要初始化和显示的屏幕,在这里是通过panel_id进行选择的,而不是panel_name,oem_panel_select()函数返回panel的接口,如果为mipi dsi接口,初始化一些关于dsi平台的数据,base的显存的地址,对函数和某些成员变量赋值操作后,最后则是调用msm_display_init()函数完成最后的屏幕初始化和启动log的显示。

    panel是一个静态的全局变量,为struct msm_fb_panel_data类型,该结构体的定义如下所示:

    struct msm_fb_panel_data {
        struct msm_panel_info panel_info; /* 描述panel的数据结构 */
        struct fbcon_config fb;
        int mdp_rev;
        int rotate;
    
        /* function entry chain */    /* 与msm底层寄存器操作相关函数API */
        int (*power_func) (int enable, struct msm_panel_info *);
        int (*clk_func) (int enable);
        int (*bl_func) (int enable);
        int (*pll_clk_func) (int enable, struct msm_panel_info *);
        int (*post_power_func)(int enable);
        int (*pre_init_func)(void);
    };

    该结构体中,比较重要的成员为panel_info,它描述了我们LCD屏幕相关的配置信息,还要一系列函数指针,在oem_panel_select()函数中完成了对该结构的函数指针初始化,是与SoC底层寄存器操作相关的API函数:

    panel.pll_clk_func = mdss_dsi_panel_clock;   /* panel时钟控制相关*/
    panel.power_func = mdss_dsi_panel_power;    /* 电源相关 */
    panel.pre_init_func = mdss_dsi_panel_pre_init;   /* 预初始化 */
    panel.bl_func = mdss_dsi_bl_enable;   /* panel背光灯使能函数 */

    对于上面列出的函数的实现,就不贴了,本文只描述LK阶段中LCM屏幕初始化和显示流程,有兴趣可以自己琢磨源码实现。

    最后,则是调用msm_display_init()函数完成LCM屏幕的初始化和log显示,该函数的定义在文件:

    msm8909_7.1/bootable/bootloader/lk/platform/msm_shared/display.c

    简化后的函数的定义如下所示:

    int msm_display_init(struct msm_fb_panel_data *pdata)
    {
        int ret = NO_ERROR;
    
        panel = pdata;
        if (!panel) {
            ret = ERR_INVALID_ARGS;
            goto msm_display_init_out;
        }
    
        /* Turn on panel */
        if (pdata->power_func)    /* 开启panel的电源 */
            ret = pdata->power_func(1, &(panel->panel_info));
        if (ret)
            goto msm_display_init_out;
    
        /* Enable clock */
        if (pdata->clk_func)    /* 将dsi时钟使能 */
            ret = pdata->clk_func(1);
    
        ret = msm_fb_alloc(&(panel->fb));    /* 分配显存 */
        if (ret)
            goto msm_display_init_out;
    
        ret = msm_display_config();    /* 显示配置 */
        if (ret)
            goto msm_display_init_out;
    
        fbcon_setup(&(panel->fb));
        display_image_on_screen();    /* 启动log载入并显示 */
        ret = msm_display_on();
        if (ret)
            goto msm_display_init_out;
    
        /* Turn on backlight */
        if (pdata->bl_func)    /* 开启背光灯 */
            ret = pdata->bl_func(1);
        if (ret)
            goto msm_display_init_out;
    
    msm_display_init_out:
        return ret;
    }

    从注释中,可以很清楚地知道了流程,msm_display_init()函数,其实就是调用了全局变量panel填充的底层函数API接口,dsi接口初始化完成后,会将启动log图片复制到显示缓存,最后,背光灯打开后,我们就能看到了启动log图片了,这就是LK启动阶段中LCM屏幕的初始化和显示流程了。

    3、小结

    接下来,总结一下函数的调用过程,如下:

    target_display_init()
        |
        gcdb_display_init()
            |
            oem_panel_select()  /* 根据panel_id选择屏幕 */
            |
            init_platform_data()  /* 初始化dsi接口 */
            |
            dsi_panel_init()
            |
            msm_display_init()
                |
                power_func()  /* panel电源开启 */
                |
                clk_func()    /* dis时钟开启 */
                |
                display_image_on_screen()  /* 载入log并显示 */
                |
                msm_display_on()
                |
                bl_func()        /* 开启panel的背光灯 */

    本文,主要简单介绍了MSM8909中Android系统的LK启动阶段中LCM屏幕的初始化和显示流程。

  • 相关阅读:
    Hadoop Mapreduce分区、分组、二次排序过程详解
    hadoop的NullWritable
    CentOS7.0修改主机名(hostname)
    Linux下不重启永久修改hostname
    稀缺——我们是如何陷入贫穷与忙碌的
    slf4j log4j logback关系详解和相关用法
    使用logstash+elasticsearch+kibana快速搭建日志平台
    安装XAMPP时出现 unable to realloc 83886080 bytes
    ElasticSearch查询max_result_window问题处理
    后台CMS日志处理记录
  • 原文地址:https://www.cnblogs.com/Cqlismy/p/12026052.html
Copyright © 2011-2022 走看看