高通mipi LCM初始化和兼容移植笔记

前言

参考> 高通平台移植mipi LCD屏幕lk过程,还要些其他的网络资料,结合自己的理解输出笔记

一、MIPI DSI

MIPI (Mobile Industry Processor Interface) 是2003年由ARM, Nokia, ST ,TI等公司成立的一个联盟,目的是把手机内部的接口如摄像头、显示屏接口、射频/基带接口等标准化,从而减少手机设计的复杂程度和增加设计灵活性。

MIPI信号是成对传输的,主要是为了减少干扰,MIPI信号成对走线,两根线从波形看是成反相,所以有外部干扰过来,就会被抵消很大部分。

MIPI接口

a.     1对差分时钟(CLKP,CLKN)
b.     4对数据差分线(D0P,D0N;D1P,D1N;D2P,D2N;D3P,D3N),
    每一对之间有GND线,4对数据差分线并不一定要全部使用,很多屏只需要2对就可以了
c.    RESET(复位脚),STBYB(高电平有效)
d.     VGL,VGH(像素点上开关管的开启关闭电压,加在开关管的栅极上,
        VGH 高电平打开给像素点电容充电, VGL 负电压 关闭开关管),
    VCOM( 液晶像素点的存储电容共用电极),
e.    VLED-(背光负极),VLED+(背光正极),电源有1.8V和3.3V。

DSI协议是一个基于数据包传送的通信协议,主机端和显示模块之间传送的命令和数据基本上都以数据包格式进行。

DSI所定义的数据包有两种:短数据包(short packet) 和 长数据包(long packet)。
短数据包主要用于传输命令、读写寄存器。长数据包主要用用于传输大量图象数据或部分控制命令。

长数据包长度为665541字节,包括4byte数据包头、065535byte有效数据、2byte数据包尾。短数据包长度为4byte,只有数据包头。发送数据的时候,主机的协议层将根据协议进行打包,并生成ECC和CRC添加到数据包里面。相反的,从机的协议层负责把接收到的数据包根据ECC和CRC对数据包进行纠错,并且把有用数据提取出来送到应用层。

mipi 接口下有两种模式:vedio mode 和 command mode

DSI(Video Mode)视频模式.

这种工作模式与传统RGB接口相似,主机需要持续刷新显示器。由于不使用专用的数据信号传输同步信息,控制信号和RGB数据是以报文的形式通过MIPI总线传输的。因为主机需要定期刷新显示器,显示器就不需要帧缓冲器。

DCS(Command mode)命令模式

MIPI总线控制器使用显示命令报文来向显示器发送像素数据流。显示器应该有一个全帧长的帧缓冲器来存储所有的像素数据。一旦数据被放在显示器的帧缓冲器中,定时控制器就从帧缓冲器中取出数据,并自动把它们显示在屏幕上。MIPI总线控制器不需要定期刷新显示器。

video mode 主要针对没有驱动芯片内没有帧buffer(ram)的lcd进行操作的,主控要按照lcd的刷新率持续发送pixel数据。

command mode主要针对驱动内含有帧buffer(ram)的cpu屏进行操作的,主控只在需要更改显示图像的时候发送pixel数据,其他时候驱动芯片自己从内部buffer里取数据显示,这种屏一般分辨率比较小。command mode 还用来配置驱动芯片的内部寄存器。

二、LK软件实现

lk 是高通平台通用的bootloader,类似以前使用的UBOOT。系统在启动前,前调用lk加载和初始化硬件设备,具体流程如下。

aboot_init()    //lk
    //do while循环遍历所有的LCM初始化,兼容多少LCD就循环多少次
    --->target_display_init()
        --->gcdb_display_init() //结构体panel赋值
            /*根据名字匹配supp_panels,获取对应屏幕的ID号,可在此处做兼容,
            函数在msm8952中*/
            --->oem_panel_select() 
                /*将对应头文件中的值赋值到结构体,同时pan_type = PANEL_TYPE_DSI*/
                --->init_panel_data(panelstruct, pinfo, phy_db)
             /*------DSI信息配置------*/   
            --->update_dsi_display_config() //初始化 DSI 配置
            /*拷贝 display.h// 中的 DSI 配置信息到实际寄存器中*/
            --->target_dsi_phy_config(&dsi_video_mode_phy_db);
            /*检测DSI 通道是否配置错误, 如果错了, 则将 dsi1 和 dsi0 进行交换*/
            --->mdss_dsi_check_swap_status()
            --->mdss_dsi_set_pll_src();/*DSI PLL锁相环配置*/
            /*屏pinfo节构体初始化:主要初始化屏幕DSI相关的配置及屏的调用函数初始化*/
            --->dsi_panel_init(&(panel.panel_info), &panelstruct)
            /*----------end-----------*/

            /*---------初始化LCM-------*/
            --->msm_display_init() /*开始正式init 初始化LCM*/
                /*mdss_dsi_panel_power()上电*/
                --->pdata->power_func(1, &(panel->panel_info));
                /*mdss_dsi_mipi_dfps_config()读取 splash 分区的内容(图片数据
                信息), 以及初始化framebuffer的地址*/
                --->pdata->dfps_func(&(panel->panel_info));
                /*mdss_dsi_panel_clock()使能CLK*/
                --->pdata->clk_func(1, &(panel->panel_info));
                //为framebuffer分配内存
                --->msm_fb_alloc();fbcon_setup() 
                /*正式显示图片,将图片写入framebuffer显示logo*/
                --->display_image_on_screen() 
                /*mipi 初始化,初始化物理层 相关配置 (包括地址等)2.2.3.9 mipi 初
                始化, 初始化物理层 相关配置 (包括地址等)*/ 
                --->msm_display_config() 
                    --->mdss_dsi_config() //配置控制器
                    //mdss_dsi_panel_pre_init()复位panel
                    --->panel->pre_init_func()
                --->msm_display_on()//初始化panel,开始显示
                    --->mdp_dsi_video_on() // 使能DSI VIDEO
                    //使用初始化命令来初始化panel包括识别屏幕(兼容有关)
                    --->mdss_dsi_post_on(); 
                            --->mdss_dsi_panel_initialize()
                                /*读取屏幕signature,判断是否匹配,匹配成功执
                                行完剩下的代码,然后跳出do-while循环,若不成功,
                                则继续循环*/
                                --->mdss_dsi_read_panel_signature()
                --->pdata->bl_func()
                    mdss_spi_bl_enable()//调整背光
                        --->target_backlight_ctrl()//控制背光

mdss_dsi_read_panel_signature兼容

在lk/platform/msm_shared/include/mipi_dsi.h定义了read_ddb_start_cmd。

//这里意思是读A1寄存器的包
static char read_id_a1h_cmd[4] = { 0xA1, 0x00, 0x06, 0xA0 };
static struct mipi_dsi_cmd read_ddb_start_cmd =
     {sizeof(read_id_a1h_cmd), read_id_a1h_cmd};

 /*panel_signature在头文件中定义,在init_panel_data中赋值*/
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;

 #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()指的是ntohl函数,是将一个无符号长整形数从网络字节顺序转换为主机字节顺序, 
//ntohl()返/回一个以主机字节顺序表达的数
     data = ntohl(*lp);
     data = data >> 8;
     response_value = data;
     if (response_value != panel_signature)
       ret = response_value;


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

三、增加一个panel

  1. 在oem.panel中添加一个panel枚举
enum {
    ILI9881D_720P_VIDEO_PANEL,
    HX8394D_480P_VIDEO_PANEL,
    HX8394D_720P_VIDEO_PANEL,
    SHARP_QHD_VIDEO_PANEL,
    TRULY_WVGA_CMD_PANEL,
    HX8379A_FWVGA_SKUA_VIDEO_PANEL,
    ILI9806E_FWVGA_VIDEO_PANEL,
    HX8394D_QHD_VIDEO_PANEL,
    HX8379C_FWVGA_VIDEO_PANEL,
    FL10802_FWVGA_VIDEO_PANEL,
    AUO_QVGA_CMD_PANEL,
    AUO_CX_QVGA_CMD_PANEL,
    HX8394F_720P_VIDEO_PANEL,
    ILI9881C_720P_VIDEO_PANEL,
    GC9306_QVGA_SPI_CMD_PANEL,
    XXX_VIDEO_PANEL, // 举个例子
    UNKNOWN_PANEL
};
  1. 增加相应的的头文件在#include "include/xxx_video.h"

找供应商要

  1. supp_panels中添加绑定,在init_panel_data中添加属性,属性为头文件中定义
// 如果要增加一个panel就需要在这里增加一个supp_panels
static struct panel_list supp_panels[] = {
    {"truly_1080p_video", TRULY_1080P_VIDEO_PANEL},
    {"truly_1080p_cmd", TRULY_1080P_CMD_PANEL},
    {"r69006_1080p_video", R69006_1080P_VIDEO_PANEL},
    {"r69006_1080p_cmd", R69006_1080P_CMD_PANEL},
    {"truly_wuxga_video", TRULY_WUXGA_VIDEO_PANEL},
    {"nt35523_720p_video", NT35523_720P_VIDEO_PANEL},
    {"xxx_video", XXX_VIDEO_PANEL}, //新增绑定
};


static int init_panel_data(struct panel_struct *panelstruct,
            struct msm_panel_info *pinfo,
            struct mdss_dsi_phy_ctrl *phy_db)
{
    int pan_type = PANEL_TYPE_DSI;

    switch (panel_id) {
    case GC9306_QVGA_SPI_CMD_PANEL:
        panelstruct->paneldata    = &gc9306_qvga_cmd_panel_data;
        panelstruct->panelres     = &gc9306_qvga_cmd_panel_res;
        panelstruct->color        = &gc9306_qvga_cmd_color;
        panelstruct->panelresetseq
                    = &gc9306_qvga_cmd_reset_seq;
        panelstruct->backlightinfo = &gc9306_qvga_cmd_backlight;
        pinfo->spi.panel_cmds
                    = gc9306_qvga_cmd_on_command;
        pinfo->spi.num_of_panel_cmds
                    = GC9306_QVGA_CMD_ON_COMMAND;
        pan_type = PANEL_TYPE_SPI;
        break;
    // 添加 属性
    case XXX_VIDEO_PANEL:
        // 照猫画虎添加对应的属性。
    case UNKNOWN_PANEL:
    default:
    /*.......*/
        break;
    }
    return pan_type;
}
  1. panel_id
    在网上一些参考教程中,在oem_panel_select()函数中有两种实现方式,一种是根据panel_name去调用panel_override_id 函数匹配supp_panels, 然后获取到id,一种是通过平台不同,去赋值id,代码如下
int oem_panel_select(const char *panel_name, struct panel_struct *panelstruct,
            struct msm_panel_info *pinfo,
            struct mdss_dsi_phy_ctrl *phy_db)
{
		if (panel_name) {
		panel_override_id = panel_name_to_id(supp_panels,
				ARRAY_SIZE(supp_panels), panel_name);

		if (panel_override_id < 0) {
			dprintf(CRITICAL, "oem_panel_select hw_id = %d\n",hw_id);
			dprintf(CRITICAL, "Not able to search the panel:%s\n",
					 panel_name);
		} else if (panel_override_id < UNKNOWN_PANEL) {
			/* panel override using fastboot oem command */
			panel_id = panel_override_id;

			dprintf(INFO, "OEM panel override:%s\n",
					panel_name);
			goto panel_init;
		}
	}
    //...
    switch (hw_id) {
    case xx:
        panel_id = XXX_VIDEO_PANEL;
        break;
            
    default:
        dprintf(CRITICAL, "Display not enabled for %d HW type\n",
            hw_id);
        return PANEL_TYPE_UNKNOWN;
    }
    //...
}
  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值