基於msm8916移植lcd流程--LK
本篇先不講解lcd程式碼在kernel和lk中的流程,講解基於msm8916,移植ILI9881C型號的lcd
首先要準備一下東西:屏IC 規格書,初始化程式碼,硬體原理圖
屏IC 規格書—>獲得時序等資料
初始化程式碼 —>獲得初始化螢幕ic的命令,用於編寫屏的.h檔案(lk)和.dtsi檔案(kernel)
硬體原理圖 —>獲得開啟背光、reset等有關電源的引腳,在程式碼中拉高拉低
首先從規格書中可以獲得以下一些資訊:
得到的資訊如下:
水平脈衝寬度(qcom,mdss-dsi-h-pulse-width,Hsync)為30
水平後沿值(qcom,mdss-dsi-h-back-porch,HBP)為30
水平前沿值(qcom,mdss-dsi-h-front-porch,HFP)為38
面板寬度(qcom,mdss-dsi-panel-width,HAdr)為720
垂直脈衝寬度(qcom,mdss-dsi-v-pulse-width,Vsync)為6
垂直後沿值(qcom,mdss-dsi-v-back-porch,VBP)為8
垂直前沿值(qcom,mdss-dsi-v-front-porch,VFP)為10
面板高度(qcom,mdss-dsi-panel-height,VAdr)為1280
一、在LK中移植LCD
1.首先要準備好LCD的.h檔案
因為ILI9881C型號的lcd在高通的推薦供應商列表中,所以可以在高通官網中找到類似的patch,裡面有相關的.h程式碼,仿照來合成需要的.h檔案。
在這個.h檔案中,需要修改的地方有如下:
static struct panel_resolution cpt_claa053wd41_3xb_ili9881_720p_video_panel_res = {
720, 1280, 38, 30, 30, 0, 10, 8, 6, 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;
};
根據屏的資訊,把資料填入相應的位置。(上面結構體是改好的)
static const uint32_t cpt_claa053wd41_3xb_ili9881_720p_video_timings[] = {
0x80, 0x20, 0x11, 0x00, 0x3C, 0x38, 0x1A, 0x20, 0x13, 0x03, 0x04, 0x00
};
指定面板 PHY 定時設定的長度為 12 的陣列。這組資料一般是根據計算得到,在這裡我使用的是以前專案使用的資料。
static struct panel_timing cpt_claa053wd41_3xb_ili9881_720p_video_timing_info = {
0, 4, 0x04, 0x1b
};
0x04是指qcom,mdss-dsi-t-clk-post,指定模式切換後的位元組時鐘週期。
0x1b是指 qcom,mdss-dsi-t-clk-pre,指定模式切換前的位元組時鐘週期。
這兩個資料都是沿用上一個專案的資料。
static struct panel_reset_sequence cpt_claa053wd41_3xb_ili9881_720p_video_reset_seq = {
{1, 0, 1, }, {50, 20, 50, }, 2
};
對應的結構體如下:
typedef struct panel_reset_sequence {
//引腳的狀態,資料對應的含義分別為,拉低,拉高,拉低
uint8_t pin_state[TOTAL_RESET_GPIO_CTRL];
//拉高、拉低的狀態持續的時間,分別為50、20和50毫秒
uint32_t sleep[TOTAL_RESET_GPIO_CTRL];
//pin腳的兩個方向
uint8_t pin_direction;
};
看產品規格書可以獲得此資料:
只要符合圖片的值就可以了
static struct backlight cpt_claa053wd41_3xb_ili9881_720p_video_backlight = {
1, 1, 255, 100, 2, “BL_PWM”
};
對應的結構體如下:
typedef struct backlight {
uint16_t bl_interface_type;
uint16_t bl_min_level;
uint16_t bl_max_level; //背光的最大值為255
uint16_t bl_step;
uint16_t bl_pmic_controltype;
char *bl_pmic_model; //背光的模式為PWM模式
};
最麻煩的是,利用廠家的初始化程式碼合成.h檔案的以下結構體(一般廠商會直接給合成後的,這次沒有):
首先看一下廠家給的初始化程式碼:
Generic_Long_Write_3P(0xFF,0x98,0x81,0x03);
Generic_Short_Write_1P(0x01,0x00);
Generic_Short_Write_1P(0x02,0x00);
...
Generic_Short_Write_1P(0x35,0x00);
Generic_Short_Write_NP(0x11);
Delay(120);
Generic_Short_Write_NP(0x29); // Display On
Delay(20);
根據下載的patch中的例子,可以模仿有:
static char cpt_claa053wd41_3xb_ili9881_720p_video_on_cmd0[] = {
0x04, 0x00, 0x39, 0xC0, //0x04, 0x00--有效位元組為四個,0x39--表示寫,0xC0--ECC校驗
0xFF, 0x98, 0x81, 0x03, //0xFF, 0x98,0x81, 0x03--有效資料
};
static char cpt_claa053wd41_3xb_ili9881_720p_video_on_cmd1[] = {
0x02, 0x00, 0x39, 0xC0,//0x02, 0x00--兩個有效位元組
0x01, 0x00, 0xFF, 0xFF,//0x01, 0x00--有效資料 0xFF, 0xFF--crc校驗
};
...
static char cpt_claa053wd41_3xb_ili9881_720p_video_on_cmd192[] = {
0x11, 0x00, 0x05, 0x80 //最後兩個命令有點不一樣,0x11--有效資料
};
static char cpt_claa053wd41_3xb_ili9881_720p_video_on_cmd193[] = {
0x29, 0x00, 0x05, 0x80 //0x29
};
static struct mipi_dsi_cmd cpt_claa053wd41_3xb_ili9881_720p_video_on_command[] = {
{0x8, cpt_claa053wd41_3xb_ili9881_720p_video_on_cmd0, 0x00},
{0x8, cpt_claa053wd41_3xb_ili9881_720p_video_on_cmd1, 0x00},
...
{0x4, cpt_claa053wd41_3xb_ili9881_720p_video_on_cmd192, 0x78},//0x78為延遲時間,十進位制為120
{0x4, cpt_claa053wd41_3xb_ili9881_720p_video_on_cmd193, 0x00}
};
#define CPT_CLAA053WD41_3XB_ILI9881_720P_VIDEO_ON_COMMAND 194
mipi_dsi_cmd對應的結構體如下:
struct mipi_dsi_cmd {
int size; //大小
char *payload; //命令
int wait; //等待時間
uint8_t cmds_post_tg;
};
從中可以看出,每一條命令寫入一個cpt_claa053wd41_3xb_ili9881_720p_video_on_cmdx[]中,最後在彙總到static struct mipi_dsi_cmd結構體中。
至此,.h檔案完成了。
2.接下來的步驟是使得lk程式碼可以呼叫這個.h檔案
在display.h中的列舉型別中,新增這個屏
enum {
JDI_1080P_VIDEO_PANEL,
...
XXX_PANEL,
UNKNOWN_PANEL
};
在bootable/bootloader/lk/target/msm8916/oem_panel.c中
首先,新增標頭檔案#include “include/xxx.h” —>上一步的標頭檔案
接著在屏列表資訊中新增新屏:
static struct panel_list supp_panels[] = {
{"jdi_1080p_video", JDI_1080P_VIDEO_PANEL},
...
{"xxx_video", XXX_PANEL},
};
//屏列表結構體
struct panel_list {
char name[MAX_PANEL_ID_LEN];
uint32_t id;
};
在進入oem_panel_select函式中,事先要知道hw_id是什麼,switch後進入相應的分支,進行如下賦值:
panel_id = XXX_PANEL;
在init_panel_data函式中,利用switch (panel_id),找到相應的地方,給panelstruct結構體賦值
//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;
};
//賦值的程式碼,
case XXX_PANEL:
panelstruct->paneldata = &XXX_video_panel_data;
panelstruct->panelres = &XXX_video_panel_res;
panelstruct->color = &XXX_video_color;
panelstruct->videopanel = &XXX_video_video_panel;
panelstruct->commandpanel = &XXX_video_command_panel;
panelstruct->state = &XXX_video_state;
panelstruct->laneconfig = &XXX_video_lane_config;
panelstruct->paneltiminginfo
= &XXX_video_timing_info;
panelstruct->panelresetseq
= &XXX_video_reset_seq;
panelstruct->backlightinfo = &XXX_video_backlight;
pinfo->mipi.panel_cmds
= XXX_video_on_command;
pinfo->mipi.num_of_panel_cmds
= XXX_VIDEO_ON_COMMAND;
memcpy(phy_db->timing,
XXX_video_timings, TIMING_SIZE);
break;
至此.h檔案的資訊就可以被程式碼使用了
3.根據原理圖,在程式碼某處拉高引腳
從中可以看出,要拉高的引腳為GPIO_24和GPIO_25,分別為點亮背光和reset引腳
在bootable\bootloader\lk\target\msm8916\target_display.c中,
int target_panel_reset(uint8_t enable, struct panel_reset_sequence *resetseq,
struct msm_panel_info *pinfo)
{
...
//在Display.h中定義為24號引腳
gpio_tlmm_config(vdd_enable_gpio.pin_id, 0,
vdd_enable_gpio.pin_direction, vdd_enable_gpio.pin_pull,
vdd_enable_gpio.pin_strength,
vdd_enable_gpio.pin_state);
gpio_set_dir(vdd_enable_gpio.pin_id, 2); //拉高
//在Display.h中定義為25號引腳
gpio_tlmm_config(reset_gpio.pin_id, 0,
reset_gpio.pin_direction, reset_gpio.pin_pull,
reset_gpio.pin_strength, reset_gpio.pin_state);
gpio_set_dir(reset_gpio.pin_id, 2); //拉高
...
}
display.h中定義了顯示屏相關的引腳,和一些相關的巨集以及配置資訊
panel.h中定義了顯示屏程式碼中相關的結構體
4.注意
有些屏的穩壓器tps系列的,需要手動拉高引腳,例如97號引腳
在新的程式碼中新增顯示屏,一般要在bootable/bootloader/lk/platform/msm8916/中新增和初始化相關i2c的介面,需要改變的檔案為(一般可以仿照前後程式碼寫):gpio.c、iomap.h、msm8916-clock.c
5.完成,下篇講解在kernel中新增顯示屏