• 高通平台MSM8916LCM模块移植(一)-bootloader部分【转】


    本文转载自:http://www.mobile-open.com/2016/970947.html

            高通平台中的bootloader叫做LK(Little Kernel,对于LCM来说LK部分相当重要,它不仅要负责开机部分的LCD显示任务,还要负责传参给kernel的LCM驱动,指导kernel选择合适的LCM参数。

    1、LK中LCM启动流程

    注:read_panel_id()和read_panel_id_ddr3()为私有添加,非高通库上代码。
     
    在这个流程图中,需要着重了解的有oem_panel_select() mdss_dsi_initialize() 和read_panel_id()函数,这三个函数主要是做lcd兼容,下面来具体看函数内容。
     

    2、oem_panel_select()

    这个函数在 android/bootloader/lk/target/msm8916/oem_panel.c文件中
    主要是识别不同IC,赋值给参数panel_id,panel_id的使用在同一文件中的 init_panel_data()函数中。
    [objc] view plain copy
     
    1. /********************************************************  
    2. *Name:        oem_panel_select  
    3. *Function:    selection different lcm panel  
    4. *Description: 1)This func will be roaded twice,first time use default value  
    [objc] view plain copy
     
    1.                 second time depend on lk_lcd_id value match correct branch.  
    2. *Author:      Jerry.peng  
    3. *********************************************************/  
    4. bool oem_panel_select(const charchar *panel_name, struct panel_struct *panelstruct,  
    5.             struct msm_panel_info *pinfo,  
    6.             struct mdss_dsi_phy_ctrl *phy_db)  
    7. {  
    8.     uint32_t soc_version = board_soc_version();  
    9.     uint32_t gpio_state = 0;  
    10.   
    11.     gpio_tlmm_config(LCM_GPIO_DETECT, 0, GPIO_INPUT, GPIO_NO_PULL, GPIO_8MA, GPIO_ENABLE);<span style="color:#33ff33;"> </span><span style="color:#009900;">//这个主要是硬件检测lcd_id引脚,用来区分同一IC不同模组厂屏</span>  
    12.     mdelay(10);  
    13.     gpio_state = gpio_status(LCM_GPIO_DETECT);  
    14.     dprintf(CRITICAL, "[PHC]:oem_panel.c soc_version = 0X%x value,gpio_state=%d ",soc_version,gpio_state);  
    15.             if(0x6089 == lk_lcd_id || 0xFFFF == lk_lcd_id){                     <span style="color:#009900;">  //lk_lcd_id 是自己设定的一个全局变量,赋值在mipi_dsi.c文件中</span>  
    16.                 if(gpio_state){                                            <span style="color:#009900;">//这个是同一个IC,不同模组厂的情况,由之前说的lcd_id引脚来判定</span>  
    17.                     panel_id = ILI9806E_WVGA_VIDEO_HONGTAO_PANEL;  
    18.                     dprintf(CRITICAL,"[PHC]: ILI9806E hongtao panel choosed ");  
    19.                 } else {  
    20.                     panel_id = ILI9806E_WVGA_VIDEO_HAIFEI_PANEL;  
    21.                     dprintf(CRITICAL,"[PHC]: ILI9806E haifei panel choosed ");  
    22.                 }  
    23.             }  
    [objc] view plain copy
     
    1. else if(0x8018 == lk_lcd_id){                                     <span style="background-color: rgb(255, 255, 255);"><span style="color:#009900;">//此处为IC(OTM8019)的情况</span></span>  
    2.     if(gpio_state){  
    3.         panel_id = OTM8019_WVGA_VIDEO_SUXIAN_PANEL;  
    4.         dprintf(CRITICAL,"[PHC]: otm8019 panel choosed ");  
    5.     } else {  
    6.         panel_id = OTM8019_WVGA_VIDEO_HAOSHITONG_PANEL;  
    7.         dprintf(CRITICAL,"[PHC]: otm8018b panel choosed ");  
    8.     }  
    9. }  
    [objc] view plain copy
     
    1.             else if (0x3551 == lk_lcd_id){                               <span style="font-family: Arial, Helvetica, sans-serif;"><span style="color:#009900;">//此处为IC(NT35512S)的情况</span></span>  
    2.   
    3.                     panel_id = NT35512S_WVGA_VIDEO_HAIFEI_PANEL;  
    4.                     dprintf(CRITICAL,"[PHC]: NT35512S haifei panel choosed ");  
    5.             }  
    6. panel_init:  
    7.     pinfo->pipe_type = MDSS_MDP_PIPE_TYPE_RGB;  
    8.     return init_panel_data(panelstruct, pinfo, phy_db);  
    9. }  

    3、mdss_dsi_initialize()

    mdss_dsi_initialize() 在文件Android/bootable/bootloader/lk/platform/msm_shared/mipi_dsi.c 中

    在 mipi_dsi.c 文件开始先申明全局变量 lk_lcd_id

    [cpp] view plain copy
     
    1. uint32_t lk_lcd_id = 0xFFFF;  
    [cpp] view plain copy
     
    1. /***************************************************************** 
    2. *Name:        mdss_dsi_panel_initialize 
    3. *Function:    Read LCM id & send lcm config 
    4. *Descritpion: 1/ soc_version use for identify T3F project 
    5.               2/ lcm_id_retry usr for identify 2 lane or 4lane mipi 
    6. *******************************************************************/  
    7. int mdss_dsi_panel_initialize(struct mipi_dsi_panel_config *pinfo, uint32_t  
    8.         broadcast)  
    9. {  
    10.     int status = 0;  
    11.       
    12. #if (DISPLAY_TYPE_MDSS == 1)  
    13. <span style="background-color: rgb(255, 255, 255);"><span style="color:#cc33cc;">   if (0xffff == lk_lcd_id ){                                      </span><span style="color:#009900;">//洋红色这部分代码是自己添加的和上面函数所说的oem_panel_select()配合使用</span><span style="color:#cc33cc;">  
    14.             lk_lcd_id = read_panel_id();                   </span><span style="color:#009900;"> //此为读ID的函数调用处</span><span style="color:#cc33cc;">  
    15.         target_force_cont_splash_disable(true);  
    16.         msm_display_off();  
    17.         target_force_cont_splash_disable(false);  
    18.         target_display_init(NULL);                             </span><span style="color:#009900;">//从上面流程图看以看出,这个是屏初始化的开始函数,相当于第二次初始化屏幕</span><span style="color:#cc33cc;">  
    19.         return 1;  
    20.     }</span></span>  
    21.     if (pinfo->panel_cmds) {  
    22.         if (broadcast) {  
    23.             status = mdss_dual_dsi_cmds_tx(pinfo->panel_cmds,  
    24.                     pinfo->num_of_panel_cmds);  
    25.   
    26.         } else {  
    27.             status = mipi_dsi_cmds_tx(pinfo->panel_cmds,  
    28.                     pinfo->num_of_panel_cmds);  
    29.             if (!status && target_panel_auto_detect_enabled())  
    30.                 status =  
    31.                     mdss_dsi_read_panel_signature(pinfo->signature);  
    32.         }  
    33.         dprintf(CRITICAL,"[PHC]: status=%d ",status);  
    34.     }  
    35. #endif  
    36.     return status;  
    37. }  

    4、read_panel_id()

    read_panel_id()为读取LCM ID的函数,里面包括读取各中IC函数,详细看下面代码。

    [cpp] view plain copy
     
    1. <pre name="code" class="cpp">/***************************************************************** 
    2. *Name:        read_panel_id 
    3. *Function:    Read LCM id 
    4. *Descritpion: 1/ lcm_id_retry usr for identify 2 lane or 4lane mipi 
    5.               2/ lcm_id_retry == 0 means 2 lane 
    6. *Author:      Jerry.peng 
    7. *******************************************************************/  
    8. uint32_t read_panel_id(void)  
    9. {  
    10.     uint32_t lcd_id = 0xffff;  
    [cpp] view plain copy
     
    1. <span style="white-space:pre">    </span>if( mdss_dsi_read_ili9806e_id() )  
    2. <span style="white-space:pre">        </span>lcd_id = 0x6089;       /* panel ic is ili9806e */  
    3. <span style="white-space:pre">    </span>else if( mdss_dsi_read_otm8018b_id())  
    4. <span style="white-space:pre">        </span>lcd_id = 0x8018;       /* panel ic is otm8018b */  
    5. <span style="white-space:pre">    </span>else if( mdss_dsi_read_nt35512s_id() )  
    6. <span style="white-space:pre">        </span>lcd_id = 0x3551;       /* panel ic is nt35512s */  
    7.     if(lcd_id == 0xffff){  
    8.         lcd_id = 0x1283;  
    9.         dprintf(CRITICAL,"[PHC]: no panel id readed use default  ");  
    10.     return lcd_id;  
    11. }  

    不同IC的读取ID的函数都大同小异,我这里就用ili9806e这颗IC来举例:

    [cpp] view plain copy
     
    1. <pre name="code" class="cpp">static struct mipi_dsi_cmd apex_ili9806e_panel_set_cmd[] = {  
    2.        {sizeof(apex_ili9806e_cmd0), apex_ili9806e_cmd0},  
    3. };  
    4.   
    5. static char apex_ili9806e_panel_set_pkt_size[4] = {0x08, 0x00, 0x37, 0x80};  
    6. static struct mipi_dsi_cmd apex_ili9806e_panel_set_pkt_size_cmd[] = {  
    7.     {sizeof(apex_ili9806e_panel_set_pkt_size), apex_ili9806e_panel_set_pkt_size},};  
    8. static char apex_ili9806e_panel_manufacture_id[4] = {0x00, 0x00, 0x06, 0xA0};  
    9. static struct mipi_dsi_cmd apex_ili9806e_panel_manufacture_id_cmd[] = {  
    10.     {sizeof(apex_ili9806e_panel_manufacture_id), apex_ili9806e_panel_manufacture_id},};  
    [cpp] view plain copy
     
    1. <pre name="code" class="cpp">static bool mdss_dsi_read_ili9806e_id(void)  
    2. {  
    3.     char rec_buf[24];  
    4.     char *rp = rec_buf;  
    5.     uint32_t *lp,temp,ret, data = 0;  
    6.   
    7.   
    8.         ret = mipi_dsi_cmds_tx(apex_ili9806e_panel_set_cmd, ARRAY_SIZE(apex_ili9806e_panel_set_cmd));  
    9.         mdelay(10);  
    10.         ret = mipi_dsi_cmds_tx(apex_ili9806e_panel_set_pkt_size_cmd, ARRAY_SIZE(apex_ili9806e_panel_set_pkt_size_cmd));  
    11.         mdelay(10);  
    12.         ret = mipi_dsi_cmds_tx(apex_ili9806e_panel_manufacture_id_cmd, ARRAY_SIZE(apex_ili9806e_panel_manufacture_id_cmd));  
    13.         mdelay(10);  
    14.         if(ret == 1)  
    15.             lcm_id_retry += 1;  
    16.         mipi_dsi_cmds_rx(&rp, 3);  
    17.   
    18.   
    19.         lp = (uint32_t *)rp;  
    20.         data = (uint32_t)*lp;  
    21.         data = ntohl(data);  
    22.   
    23.   
    24.         data = data & 0xFF;  
    25.         dprintf(CRITICAL,"[PHC]: ili9806e id: 0x%x ", data);  
    26.         if(data == 0x98) {  
    27.             lcm_id_retry = 0;  
    28.             return true;  
    29.         }  
    30.         else  
    31.             return false;  
    32. }  

           到此,整个lk中LCM兼容和移植的主体部分就已经完成了,剩下就是填LCM参数进.h文件,这里再对整个流程进行一个补充整理。
           首先解释下为什么不用高通默认的兼容方法,因为高通默认的兼容需要用到各种硬件id,平台id,这些都是在SBL中设定的,修改起来麻烦,而且可以兼容的屏幕个数有限,我上面所说的这种方法加上我拓展的一些代码,已经可以兼容十多块屏幕。
    整个兼容方法的思路是,在LCM进行第一遍初始化的时候,什么都不变,但进行到mipi_dsi.c文件中的mdss_dsi_initialize()函数的时候,回去读当前使用的LCM IC 的id
    ,如果和默认的屏幕id一样,则不进行第二次初始化,若不一样,则重新初始化,这个时候全局变量lk_lcd_id已经被赋值,当第二遍初始化到了oem_panel.c文件的oem_panel_select()函数中,函数根据lk_lcd_id的值来匹配正确的屏幕变量。匹配完成之后继续未完成的屏幕初始化,至此整个流程走完,屏幕点亮!

          文章介绍完毕,如有错误欢迎大家指正~

  • 相关阅读:
    docker部署nginx文件服务器
    local variable 'a' referenced before assignment
    函数嵌套的顺序
    动态参数
    函数——函数接收不定个数的数字实参,将数字之和返回给调用者
    函数——函数接收四个参数分别是:姓名,性别,年龄,学历。用户通过输入这四个内容,然后将这四个内容传入到函数中, 此函数接收到这四个内容,将内容追加到一个student msg文件中
    函数——此函数只接收一个参数且此参数必须是列表数据类型,此函数完成的功能是返回给调用者一个字典, 此字典的键值对为此列表的索引及对应元素。例如传入的列表为:[11,22,33]返回的字典为{0:11,1:22,2:33}
    函数——检查传入列表的长度,如果大于2,那么仅保留前两个长度的内容,并将新内容返回给调用者
    函数—判断用户传入的对象(字符串、列表、元组)长度是否大于5
    Python中深拷贝与浅拷贝的区别
  • 原文地址:https://www.cnblogs.com/zzb-Dream-90Time/p/6411518.html
Copyright © 2020-2023  润新知