1. 程式人生 > >基於msm8916移植lcd流程--LK

基於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, 0x980x81, 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中新增顯示屏