欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

LCD移植

程序员文章站 2022-03-05 11:35:53
...

基于msm8909移植lcd流程

模块功能描述

LCD模块功能主要是LCD液晶显示

LCD移植

以helitech ili9881d为例,首先需要准备东西如下:
1、屏IC Data Sheet
2、初始化代码 —>获得初始化屏幕ic的命令,用于编写屏的.h文件(lk)和.dtsi文件(kernel)
首先从Data Sheet或者初始化代码中可以获得以下一些信息:
1、水平脉冲宽度(qcom,mdss-dsi-h-pulse-width,Hsync)为68
2、水平后沿值(qcom,mdss-dsi-h-back-porch,HBP)为120
3、水平前沿值(qcom,mdss-dsi-h-front-porch,HFP)为88
4、垂直脉冲宽度(qcom,mdss-dsi-v-pulse-width,Vsync)为8
5、垂直后沿值(qcom,mdss-dsi-v-back-porch,VBP)为24
6、垂直前沿值(qcom,mdss-dsi-v-front-porch,VFP)为16
7、面板高度(qcom,mdss-dsi-panel-height,VAdr)为1280
8、面板宽度(qcom,mdss-dsi-panel-width,HAdr)为720

lk部分

首先准备好LCD的.h(命名规则panel_ic_vendor_platform_res_mod)
因为ILI9881D型号的LCD在高通的推荐供应商列表中,所以可以在高通官网中找到类似的patch,里面有相关的.h代码,仿照来合成需要的.h文件。
在这个.h文件中,需要修改的地方有如下:

static struct panel_resolution ili9881d_hlt_a8_720p_video_panel_res = {
  720, 1280, 88, 120, 68, 0, 16, 24, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0
};

这个结构体包含了显示屏的许多参数,在panel.h中可以找到其结构体如下:

typedef struct panel_resolution{
    uint16_t panel_width;
    uint16_t panel_height;
    uint16_t hfront_porch;
    uint16_t hback_porch;
    uint16_t hpulse_width;
    uint16_t hsync_skew;
    uint16_t vfront_porch;
    uint16_t vback_porch;
    uint16_t vpulse_width;
    uint16_t hleft_border;
    uint16_t hright_border;
    uint16_t vtop_border;
    uint16_t vbottom_border;
    uint16_t hactive_res;
    uint16_t vactive_res;
    uint16_t invert_data_polarity;
    uint16_t invert_vsync_polarity;
    uint16_t invert_hsync_polarity;
};

根据屏的信息,把数据填入相应的位置。

const uint32_t ili9881d_hlt_a8_720p_video_timings[] = {
0x86, 0x1E, 0x14, 0x00, 0x42, 0x46, 0x18, 0x20, 0x16, 0x03, 0x04, 0x00
};

指定面板 PHY 定时设置的长度为 12 的数组。这组数据一般是根据计算得到.

static struct panel_timing ili9881d_hlt_a8_720p_video_timing_info = {
  0, 4, 0x04, 0x1B
};

0x04是指qcom,mdss-dsi-t-clk-post,指定模式切换后的字节时钟周期。
0x1B是指 qcom,mdss-dsi-t-clk-pre,指定模式切换前的字节时钟周期。
上面两组数据通过DSI_Timing_Parameters.xlsm计算得来,方法如下:
LCD移植将从规格书中获得信息依次填入上表,然后ctrl+j;ctrl+k;得到
DSI PHY registers和DSI Registers,如下图
`LCD移植

Static struct panel_reset_sequence ili9881d_hlt_a8_720p_video_panel_reset_seq  =  {
{ 1, 0, 1, }, { 20, 20, 20, }, 2
};

对应的结构体如下:

typedef struct panel_reset_sequence {
    //引脚的状态,数据对应的含义分别为,拉低,拉高,拉低
    uint8_t pin_state[TOTAL_RESET_GPIO_CTRL]; 
    //拉高、拉低的状态持续的时间,分别为20、20和20毫秒
    uint32_t sleep[TOTAL_RESET_GPIO_CTRL];
    //pin脚的两个方向
    uint8_t pin_direction;
};
static struct backlight ili9881d_hlt_a8_720p_video_backlight = {
  2, 1, 4095, 100, 1, "PMIC_8909"
};
对应的结构体如下:
typedef struct backlight {
    uint16_t bl_interface_type;
    uint16_t bl_min_level;
    uint16_t bl_max_level;  //背光的最大值为4096
    uint16_t bl_step;
    uint16_t bl_pmic_controltype;
char     *bl_pmic_model; //背光的模式
};

看一下厂家给的初始化代码:

REGISTER,FF,03,98,81,03
REGISTER,02,01,00
REGISTER,03,01,56
REGISTER,04,01,13
REGISTER,05,01,00
………
REGISTER,FF,03,98,91,00
REGISTER,35
REGISTER,11
Delayms(120);
REGISTER,29
Delayms(10);

参考已有的LCD屏幕,可以模仿有:
LCD移植
厂家提供的初始化代码中没有点亮背光的代码,自己Data Sheet中找到ILI9881d的背光控制为0x51和0x53;
LCD移植
LCD移植
mipi_dsi_cmd对应的结构体如下:

struct mipi_dsi_cmd {
    int size;    //大小
    char *payload; //命令
    int wait;  //等待时间
    uint8_t cmds_post_tg;
};

从中可以看出,每一条命令写入一个ili9881d_hlt_a8_720p_video_on_command[]中,最后在汇总到
static struct mipi_dsi_cmd结构体中。
至此,.h文件完成了。

接下来的步骤是使得lk代码可以调用这个.h文件
1、在msm_panel.h中,添加这个屏的LCM_ID

2、在bootloader/lk/platform/msm_shared/mipi_dsi.c 中的mdss_dsi_panel_initialize函数中可以通get_panel_rdid来获取屏幕的LCMID,给panel_ic_id赋值;

3、在bootable/bootloader/lk/target/msm8909/oem_panel.c中
首先,添加lcd头文件#include “include/xxx.h” —>上一步的头文件
接着在init_panel_data函数中,利用switch (panel_ic_id),找到相应的地方,给panelstruct结构体赋值
LCD移植
//panelstruct结构体

typedef struct panel_struct{
    struct panel_config         *paneldata;
    struct panel_resolution     *panelres;
    struct color_info           *color;
    struct videopanel_info      *videopanel;
    struct commandpanel_info    *commandpanel;
    struct command_state        *state;
    struct lane_configuration   *laneconfig;
    struct panel_timing         *paneltiminginfo;
    struct panel_reset_sequence *panelresetseq;
    struct backlight            *backlightinfo;
    struct fb_compression       fbcinfo;
};

至此lk中的移植就完成了.

kernel部分

在Kernel中移植lcd ,流程大致和在lk中移植lcd差不多
首先要写好.dts文件
创建arch/arm/boot/dts/qcom/dsi-panel-xxx-video.dtsi文件
文件就一个节点,&mdss_mdp,这其中有显示屏的节点dsi_xxx,其中很多节点的数值都在LK中有提及

&mdss_mdp {
dsi_ili9881d_hlt_a8_hd_vid: qcom,mdss_dsi_ili9881d_hlt_a8_hd_video 
(LK添加的显示屏的节点名称(panel_config->panel_node_id)一样)
{
		//qcom,mdss-dsi-panel-name = " ic vendor platform res mod dsi panel ";
		qcom,mdss-dsi-panel-name = "ili9881d hlt a8 hd video mode dsi panel";
		qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
		qcom,mdss-dsi-panel-type = "dsi_video_mode";
		qcom,mdss-dsi-panel-destination = "display_1";
		qcom,mdss-dsi-panel-framerate = <60>;
		qcom,mdss-dsi-virtual-channel-id = <0>;
		qcom,mdss-dsi-stream = <0>;
		qcom,mdss-dsi-panel-width = <720>;//面板宽度
		qcom,mdss-dsi-panel-height = <1280>;//面板高度
		qcom,mdss-dsi-h-front-porch = <88>;//水平前沿值
		qcom,mdss-dsi-h-back-porch = <120>;//水平后沿值
		qcom,mdss-dsi-h-pulse-width = <68>;//水平脉冲宽度
		qcom,mdss-dsi-h-sync-skew = <0>;
		qcom,mdss-dsi-v-back-porch = <24>;//垂直后沿值
		qcom,mdss-dsi-v-front-porch = <16>;//垂直前沿值
		qcom,mdss-dsi-v-pulse-width = <8>;//垂直脉冲宽度
		qcom,mdss-dsi-h-left-border = <0>;
		qcom,mdss-dsi-h-right-border = <0>;
		qcom,mdss-dsi-v-top-border = <0>;
		qcom,mdss-dsi-v-bottom-border = <0>;
		qcom,mdss-dsi-bpp = <24>;
		qcom,mdss-dsi-color-order = <0>;
		qcom,mdss-dsi-underflow-color = <0xff>;
		qcom,mdss-dsi-border-color = <0>;
		qcom,ulps-enabled;
  		//厂商初始化改为以下属性,每一行一条命令
		//39--写,格式,04--写的字节,命令
		qcom,mdss-dsi-on-command = 
			[
			39 01 00 00 00 00 04 FF 98 81 03
			39 01 00 00 00 00 02 02 00
			39 01 00 00 00 00 02 03 56
			39 01 00 00 00 00 02 04 13
			.....	
			39 01 00 00 00 00 03 51 0F FF 
			39 01 00 00 00 00 02 53 24 
			39 01 00 00 00 00 02 35 00
			05 01 00 00 80 00 02 11 00      
			05 01 00 00 20 00 02 29 00
		];
		qcom,mdss-dsi-off-command = [			
					05 01 00 00 32 00 02 28 00
					05 01 00 00 78 00 02 10 00
					];
		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
		qcom,mdss-dsi-h-sync-pulse = <0>;
		qcom,mdss-dsi-traffic-mode = "burst_mode";
		qcom,mdss-dsi-lane-map ="lane_map_0123";
		qcom,mdss-dsi-bllp-eof-power-mode;
		qcom,mdss-dsi-bllp-power-mode;
		qcom,mdss-dsi-lane-0-state;
		qcom,mdss-dsi-lane-1-state;
		qcom,mdss-dsi-lane-2-state;
		qcom,mdss-dsi-lane-3-state;
 		//指定面板 PHY 定时设置的长度为 12 的数组,跟lk一样
		qcom,mdss-dsi-panel-timings =[86 1E 14 00 42 46 18 20 16 03 04 00]; 
		//指定模式切换后的字节时钟周期,跟lk一样
		qcom,mdss-dsi-t-clk-post = <0x04>;//1f>;
		//指定模式切换前的字节时钟周期,跟lk一样
		qcom,mdss-dsi-t-clk-pre = <0x1b>;//x2d>;		
		qcom,mdss-dsi-bl-min-level = <20>;
		//背光最大电流,4095
		qcom,mdss-dsi-bl-max-level = <4095>;
		qcom,mdss-dsi-dma-trigger = "trigger_sw";
		qcom,mdss-dsi-mdp-trigger = "none";
		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs";
		//屏幕的上电时序,1代表拉高,0代表拉低,20代表20ms时间
		qcom,mdss-dsi-reset-sequence = <1 20>,<0 2>, <1 20>;
		qcom,mdss-dsi-lp11-init;		
		qcom,cont-splash-enabled;
		qcom,mdss-dsi-hbp-power-mode;
		qcom,mdss-dsi-panel-status-check-mode = "bta_check";
	};
};

在对应的msm89-qrd-skue.dtsi加上dsi-panel-xxx-video.dtsi,以在A8添加ILI9881d为例,则在msm8909-qrd-skue.dtsi中添加
dsi-panel-ili9881d-holitech-a8-hd-video.dtsi;