MSM8909与android5.1.1的LCM屏的兼容———自我感悟

刚刚接触高通平台,需要实现两个LCM屏组的兼容。于是就各种百度,什么读LCD_ID,通过AD转换实现,什么读IC_ID软件实现兼容,晕。于是看着前辈的log,简单实现了屏的兼容。

兼容的前提是实现屏的替换,高通的屏在Android5.1.1中分为两部分。lk与kernel。屏的显示是通过mipi接口实现的,而触摸实现方法需要另外在kernel中实现(IIC实现)。当系统开始运行时候,先初始化屏,接着判断屏是否初始化完毕,根据这一点。我们可以实现屏的兼容。

首先添加屏的相关信息,添加panel_ssd2075m1_720p_video.h文件,添加到lk/dev/gcdb/display/include目录下。接着在lk/target/msm8909/oem_panel.c文件中添加屏的选项,照着参考一下。有的版本的枚举类型在lk/target/msm8909/include/target/display.h文件中照着添加即可。除此之外在oem_panel.c中的oem_panel_select()添加兼容选项。

static uint32_t auto_scpan_loop = 0; //初始化一个全局变量,代表第几块兼容屏

int oem_panel_select(const char *panel_name, struct panel_struct *panelstruct,
            struct msm_panel_info *pinfo,
            struct mdss_dsi_phy_ctrl *phy_db)
{
    uint32_t hw_id = board_hardware_id();
    uint32_t platform_subtype = board_hardware_subtype();
    int32_t panel_override_id;

    .........
    switch (hw_id) {            //选择一个case,不知从哪里来
    case HW_PLATFORM_SURF:
    case HW_PLATFORM_MTP:
    case HW_PLATFORM_RCM:
        panel_id = HX8394D_720P_VIDEO_PANEL;
        break;
    case HW_PLATFORM_QRD:   //值为11,不出意外从这里进来
        switch (platform_subtype) {
                
            case QRD_SKUA:            //值为 0,不出意外从这里进来  
                //panel_id = NT35521_720P_VIDEO_PANEL;
                panel_id = HSX097LVDS_720P_VIDEO_PANEL;
                break;
            case QRD_SKUC:
                panel_id = ILI9881C_720P_VIDEO_PANEL;
                break;
            case QRD_SKUE:
                panel_id = ILI9881C_720P_VIDEO_PANEL;
                break;
//            default:
//                dprintf(CRITICAL, "QRD Display not enabled for %d type\n",
//                        platform_subtype);
//                return PANEL_TYPE_UNKNOWN;
        }
        break;
//    default:
//        dprintf(CRITICAL, "Display not enabled for %d HW type\n",
//            hw_id);
//        return PANEL_TYPE_UNKNOWN;
    }

    dprintf(CRITICAL, "auto_scpan_loop:%d \n",auto_scpan_loop);
    panel_id = NT35521z_720P_VIDEO_PANEL;
    switch (auto_scpan_loop) {
        case 0:
            panel_id = NT35521z_720P_VIDEO_PANEL;
            break;
        case 1:
            panel_id = SSD2075ML_720P_VIDEO_PANEL;
            break;
        default:
            panel_id = UNKNOWN_PANEL;
            dprintf(CRITICAL, "Unknown panel\n");
            return PANEL_TYPE_UNKNOWN;
    }
    auto_scpan_loop ++;

panel_init:
    phy_db->regulator_mode = DSI_PHY_REGULATOR_LDO_MODE;
    return init_panel_data(panelstruct, pinfo, phy_db);
}

其实就是将panel_id的值,赋予什么,就调用相关寄存器的值初始化LCD屏。

初始化的最初调用函数是lk/target/msm8909/target_display.c中的gcdb_display_init()函数,通过while实现反复初始化,达到最终目的。函数中的oem_panel_max_auto_detect_panels()函数最终返回的是一个宏,定义在lk/target/msm8909/oem_panel.c中,为:#define    DISPLAY_MAX_PANEL_DETECTION    2      可以控制while循环的次数。

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());//条件是一个宏
}
 

初始化过程大致如下图所示: 

                    target_display_init()
                            ||
                            \/
                    gcdb_display_init()
                            ||
                            \/
———————————————————————————
msm_display_init()                              oem_panel_select()
        ||                                              ||
        \/                                              \/
msm_display_config()                           init_panel_data()
        ||
        \/ 
mdss_dsi_config()
        ||
        \/
msm_dis_panel_initiliaze()
 

应该是搭建框架的人帮我们想好了一切,在msm_dis_panel_initiliaze()调用了mdss_dsi_read_panel_signature(),该函数可以帮我们实现兼容。

int mdss_dsi_panel_initialize(struct mipi_dsi_panel_config *pinfo, uint32_t
        broadcast)
{
    int status = 0;
    uint32_t ctrl_mode = 0;

#if (DISPLAY_TYPE_MDSS == 1)
    if (pinfo->panel_cmds) {

        ctrl_mode = readl(MIPI_DSI0_BASE + CTRL);
        if (broadcast) {
            /* Enable command mode before sending the commands. */
            writel(ctrl_mode | 0x04, MIPI_DSI0_BASE + CTRL);
            writel(ctrl_mode | 0x04, MIPI_DSI1_BASE + CTRL);
            status = mdss_dual_dsi_cmds_tx(pinfo->panel_cmds,
                    pinfo->num_of_panel_cmds);
            writel(ctrl_mode, MIPI_DSI0_BASE + CTRL);
            writel(ctrl_mode, MIPI_DSI1_BASE + CTRL);

        } else {
            /* Enable command mode before sending the commands. */
            writel(ctrl_mode | 0x04, MIPI_DSI0_BASE + CTRL);
            status = mipi_dsi_cmds_tx(pinfo->panel_cmds,
                    pinfo->num_of_panel_cmds);
            writel(ctrl_mode, MIPI_DSI0_BASE + CTRL);
            if (!status && target_panel_auto_detect_enabled())       //前面的不知道干嘛的,反正会走到这一步
                status =
                    mdss_dsi_read_panel_signature(pinfo->signature);
            dprintf(SPEW, "Read panel signature status = 0x%x \n", status);
        }
    }
#endif
    return status;
}
 

要想运行mdss_dsi_read_panel_signature();那么if中的条件需要成立。status为0,成立,而target_panel_auto_detect_enabled()永远返回0,不成立。所以我们需要修改该函数中的内容,如下。

uint8_t target_panel_auto_detect_enabled()
{
    uint8_t ret = 0;

    switch(board_hardware_id()) {

    case HW_PLATFORM_QRD://简单做个判断意思一下,反正成立

        ret = 1;

        break;
    default:
        ret = 0;
        break;
    }
    return ret;
}

接下来程序会进入mdss_dsi_read_panel_signature();函数会读取屏的信息,不知是什么。自我猜测是屏的IC_ID,有了这个就好办了,IC_ID不变,而屏的配置信息改变。在panel_ssd2075m1_720p_video.h中有一个宏:#define SSD2075ML_720P_VIDEO_SIGNATURE 0xFFF7。这个值就是panel_signature,我们可以事先读取response_value的值,通过串口打印出来,接着赋值给panel_signature。这样相等就代表匹配成功,否则则代表初始化失败。返回至函数target_display_init(),开始下一轮的初始化。

uint32_t mdss_dsi_read_panel_signature(uint32_t panel_signature)
{
    uint32_t rec_buf[1];
    uint32_t *lp = rec_buf, data;
    int ret = response_value;

    /*将其初始化为0,不然只可以兼容两块屏。原因是ret第一次被赋值,第一次容错判断条件直接成立*/

     ret = 0;

#if (DISPLAY_TYPE_MDSS == 1)
    if (ret && ret != panel_signature)
        goto exit_read_signature;

    ret = mipi_dsi_cmds_tx(&read_ddb_start_cmd, 1);
    if (ret)
        goto exit_read_signature;
    if (!mdss_dsi_cmds_rx(&lp, 1, 1))
        goto exit_read_signature;

    data = ntohl(*lp);
    data = data >> 8;
    response_value = data;       //response_value为响应值,不知道代表什么
    if (response_value == panel_signature)
    {

    return 0;//屏的初始化配置正确,继续往下执行

    }

    else{

    return 1;//屏的初始化配置不正确,继续while转圈

    }

exit_read_signature:
    /* Keep the non detectable panel at the end and set panel signature 0xFFFF */
    if ((panel_signature == 0) || (panel_signature == 0xFFFF) || (panel_signature == 0xFFF7) )
        ret = 0;
#endif
    return ret;
}
 

至此lk部分初始化完成,据说lk部分初始化完成后会传参给kernel,这样kernel只需照常配置即可,这样屏就能亮起了。

tp部分的兼容并不知道怎么实现,不过相同类型的屏,tp都不会发生改变,只是固件不同,即cfg信息不同。当cfg信息初始化进TP芯片后,就会固定不变了,除非你再次初始化。在tp驱动中,有一个宏:#define GTP_DRIVER_SEND_CFG   1    // send config to TP while initializing (for no config built in TP's flash)   将其打开就刷新固件,否者不刷。 其它的,随缘吧。

 注意:后来发现response_value 值有的屏不一样,而有的一样。有些醉,不过可以自己按初始化的顺序添加不通用的屏兼容。晕啊,求大神告知response_value 的值是干嘛的。继续调屏去了。。。。。。

你可能感兴趣的:(一时兴起)