MTK LCM的添加

對於LCM驅動移植,通常分爲三部曲:數組

一、硬件IO口配置;框架

二、確保LCM背光可以正常點亮;ide

三、LCM驅動移植;函數

 

硬件電路:spa

 

  

 

 

 

一、GPIO配置.net

打開 mediatek\dct\DrvGen.exe 設計

選擇 mediatek\custom\xiaoxi\kernel\dct\dct\codegen.dws 配置文件3d

配置LCM PWM引腳、RST復位引腳、DISP_PWM引腳和LCM電源控制引腳調試



二、背光燈
code

編譯燒錄後啓動系統,驗證LCM背光是否能正常點亮,不然沒法繼續調試LCD;

 

三、LCM驅動移植(以ili9806e爲例)

(1)、在mediatek\custom\common\kernel\lcm目錄下建立ili9806目錄,將驅動文件拷貝到驅動文件ili9806.c到新建立的目錄中;代碼自動將lcm軟連接到mediatek\custom\common\lk和mediatek\custom\common\uboot目錄,所以無需拷貝驅動文件到lk和uboot中;

(2)、修改\mediatek\custom\common\kernel\lcm\mt65xx_lcm_list.c, 在lcm_driver_list 數組中增長:
    extern LCM_DRIVER ili9806e_lcm_drv;
    #if defined(ILI9806)   
         &ili9806e_lcm_drv,  //就是ili9488.c中的LCM_DRIVER結構
    #endif

(3)、打開mediatek\config\prj\ProjectConfig.mk修改:
    BUILD_LK=yes 
    CUSTOM_KERNEL_LCM=ili9806   //對應lcm目錄驅動的子目錄名
    CUSTOM_LK_LCM=ili9806           //對應lcm目錄驅動的子目錄名
    CUSTOM_UBOOT_LCM=ili9806   //對應lcm目錄驅動的子目錄名
    LCM_WIDTH=480
    LCM_HEIGHT=800

 

系統編譯的時候,編譯器會根據CUSTOM_KERNEL_LCM、CUSTOM_LK_LCM、CUSTOM_UBOOT_LCM找到mediatek\custom\common\kernel\lcm\ili9806目錄,拷貝mediatek\custom\out\pro\kernel\lcm目錄,參與系統的編譯,因此對於驅動文件名有沒命名要求;lk和uboot同理;

注:系統此時也會產生ILI9806的環境變量,這就是mt65xx_lcm_list.c中的 #if defined(ILI9806) 能夠進行預編譯處理;

 

四、LCM驅動簡要解析

LCM_DRIVER結構表示一個LCM對象,裏邊包含LCM各項參數;

  1. LCM_DRIVER ili9806e_drv =   
  2. {  
  3.     .name          = "ili9806e_txd_dsi_cmd_sp13_lcm_drv",   //設備名  
  4.     .set_util_funcs = lcm_set_util_funcs,    //獲取LCM_DRIVER結構  
  5.     .get_params     = lcm_get_params,  //獲取lcm參數  
  6.     .init           = lcm_init,      //lcm初始化函數  
  7.     .suspend        = lcm_suspend,   //lcm掛起  
  8.     .resume         = lcm_resume,    //lcm恢復  
  9.     .compare_id     = lcm_compare_id,  //設備id匹配  
  10. };  

以上函數接口是爲MTK框架中的幾個重要接口;

 

/* 獲取設備的LCM_DRIVER結構 */

  1. static void lcm_set_util_funcs(const LCM_UTIL_FUNCS *util)  
  2. {  
  3.     memcpy(&lcm_util, util, sizeof(LCM_UTIL_FUNCS));  
  4. }  
  5.   
  6. /* 獲取lcm各個參數 */  
  7. static void lcm_get_params(LCM_PARAMS *params)  
  8. {  
  9.     memset(params, 0, sizeof(LCM_PARAMS));  //先將LCM_PARAMS結構清空  
  10.       
  11.     params->type = LCM_TYPE_DSI;   //lcm接口類型  
  12.     params->width = FRAME_WIDTH;   //lcm顯示寬度  
  13.     params->height = FRAME_HEIGHT; //lcm顯示高度  
  14.         /* 設置通訊模式 */  
  15.     // enable tearing-free  
  16.     params->dbi.te_mode = LCM_DBI_TE_MODE_DISABLED;  
  17.     params->dbi.te_edge_polarity = LCM_POLARITY_RISING;  
  18.         /* dsi分兩種模式,一種是cmd模式,一種是video模式 */  
  19. #if (LCM_DSI_CMD_MODE)  
  20.     params->dsi.mode = CMD_MODE;  
  21. #else  
  22.     params->dsi.mode   = SYNC_PULSE_VDO_MODE;  
  23. #endif  
  24.         /* 設置數據格式 */  
  25.     // DSI  
  26.     /* Command mode setting */  
  27.     params->dsi.LANE_NUM             = LCM_TWO_LANE;   //兩通道MIPI  
  28.     //The following defined the fomat for data coming from LCD engine.  
  29.     params->dsi.data_format.color_order = LCM_COLOR_ORDER_RGB;     
  30.     params->dsi.data_format.trans_seq   = LCM_DSI_TRANS_SEQ_MSB_FIRST;  
  31.     params->dsi.data_format.padding     = LCM_DSI_PADDING_ON_LSB;  
  32.     params->dsi.data_format.format      = LCM_DSI_FORMAT_RGB888;   
  33.   
  34.     // Highly depends on LCD driver capability.  
  35.     // Not support in MT6573  
  36.     params->dsi.packet_size = 256;  
  37.   
  38.     // Video mode setting  
  39.     params->dsi.intermediat_buffer_num = 0;  
  40.   
  41.     params->dsi.PS = LCM_PACKED_PS_24BIT_RGB888;  
  42.     params->dsi.word_count = 480 * 3;  
  43.         /* 垂直參數設置 */  
  44.     params->dsi.vertical_sync_active = 4;      //垂直同步信號的寬度  
  45.     params->dsi.vertical_backporch = 16;//10   //垂直同步信號的後沿  
  46.     params->dsi.vertical_frontporch = 20;//8   //垂直同步信號的前沿  
  47.     params->dsi.vertical_active_line = FRAME_HEIGHT;  
  48.         /* 水平參數設置 */  
  49.     params->dsi.horizontal_sync_active = 10;   //水平同步信號的寬度  
  50.     params->dsi.horizontal_backporch = 50;     //水平同步信號的後沿  
  51.     params->dsi.horizontal_frontporch = 60;    //水平同步信號的前沿  
  52.     params->dsi.horizontal_active_pixel = FRAME_WIDTH;  
  53.         /* 時鐘頻率 */  
  54.     params->dsi.PLL_CLOCK= 200;  
  55. }  

 

//復位引腳
#define SET_RESET_PIN(v) (lcm_util.set_reset_pin((v)))     //這裏就會直接使用GPIO_LCD_RST硬引腳
//延時函數   
#define UDELAY(n) (lcm_util.udelay(n))  
#define MDELAY(n) (lcm_util.mdelay(n))  

 

/* 數據傳輸接口 */
//long packet 操做接口
#define dsi_set_cmdq_V3(para_tbl, size, force_update)       lcm_util.dsi_set_cmdq_V3(para_tbl, size, force_update)     //para_tbl:LCM_setting_table結構, size:大小, force_update:強制更新標誌
#define dsi_set_cmdq_V2(cmd, count, ppara, force_update)     lcm_util.dsi_set_cmdq_V2(cmd, count, ppare, force_update) //cmd:命令, count:大小, ppara:參數,force_update:強制更新標誌
//short packet 操做接口
#define dsi_set_cmdq(pdata, queue_size, force_update)       lcm_util.dsi_set_cmdq(pdata, queue_size, force_update)  


//讀寫寄存器等操做
#define write_cmd(cmd)                      lcm_util.dsi_write_cmd(cmd)  
#define write_regs(addr, pdata, byte_nums)          lcm_util.dsi_write_regs(addr, pdata, bytes_nums)  
#define read_reg(cmd)                       lcm_util.dsi_dcs_read_lcm_reg(cmd)  
#define read_reg_v2(cmd, buffer, buffer_size)           lcm_util.dsi_dcs_read_lcm_reg_v2(cmd, buffer, buffer_size)  

/* 初始化參數及函數接口 */

  1. static struct LCM_setting_table lcm_initialization_setting[] = {  
  2.         /* 數據格式:命令,數據個數,數據 */  //命令通常是對應寄存器地址  
  3.     {0xFF, 5,{0xFF,0x98,0x06,0x04,0x01}},     
  4.     {0x08, 1, {0x10}},  
  5.     {0x21, 1, {0x01}},  
  6.     {0x30, 1, {0x02}},  
  7.     {0x31, 1, {0x02}},  
  8.     {0x40, 1, {0x16}},    
  9.     {0x41, 1, {0x22}},    
  10.      ......  
  11.     {0x53, 1, {0x1A}}, //10     
  12.     {0xFF, 5,{0xFF,0x98,0x06,0x04,0x07}},  
  13.     {0x17, 1, {0x12}}, //22  
  14.     {0x02, 1, {0x77}},  
  15.     {0xFF, 5,{0xFF,0x98,0x06,0x04,0x00}},  
  16.     {0x35,1,    {0x00}},  
  17.     {0x36,1,    {0x03}},  //翻轉180度  
  18.     {0x11,  1,  {0x00}},  
  19.     {REGFLAG_DELAY, 120, {}},  
  20.     {0x29,  1,  {0x00}},  
  21.     {REGFLAG_DELAY, 50, {}},  
  22.     {REGFLAG_END_OF_TABLE, 0x00, {}}  //數據結束必須使用REGFLAG_END_OF_TABLE  
  23. };  
  24.   
  25. static void lcm_init(void)  
  26. {  
  1.         /* 復位 */  
  2.     SET_RESET_PIN(1);     
  3.     MDELAY(10);  
  4.     SET_RESET_PIN(0);  
  5.     /* Third change Lava */  
  6.     MDELAY(10);//10   
  7.     SET_RESET_PIN(1);  
  8.     MDELAY(120);    // 150  
  9.         /* 初始化數據 */  
  10.     push_table(lcm_initialization_setting, sizeof(lcm_initialization_setting) / sizeof(struct LCM_setting_table), 1);  
  11. }  


/* 設備掛起 */

  1. static void lcm_suspend(void)  
  2. {  
  3. #ifdef BUILD_LK     
  4.     printf("%s, ALS/PS bbbbbbbbbbbbbbb \n", __func__);   
  5. #else  
  6.     printk("%s, ALS/PS bbbbbbbbbbbbbb  \n", __func__);     
  7. #endif    
  8.   
  9.     push_table(lcm_deep_sleep_mode_in_setting, sizeof(lcm_deep_sleep_mode_in_setting) / sizeof(struct LCM_setting_table), 1);  
  10.     SET_RESET_PIN(0);  
  11.     MDELAY(20);//10   
  12.     SET_RESET_PIN(1);  
  13.     MDELAY(50);  
  14. }  

 由於lcm驅動被映射到lk層,在lk層只能使用printf進行調試,但在kernel層中只能printk進行打印調試,因此可使用宏進行BUILD_LK區分;

掛起的機制通常有兩種:簡單睡眠或深度睡眠;

簡單睡眠:設備還處於工做狀態,能夠被喚醒,可是此時也會存在待機功耗等問題;

深度睡眠:設備處於休眠狀態,基本處於不工做狀態,所以沒法被喚醒;

通常程序設計都是使用深度睡眠,在喚醒時進行從新初始化;


/* 設備恢復 */

  1. static void lcm_resume(void)  
  2. {  
  3.     lcm_init();  
  4.     //push_table(lcm_sleep_out_setting, sizeof(lcm_sleep_out_setting) / sizeof(struct LCM_setting_table), 1);  
  5. }  

從新初始化設備

/* 設備id匹配 */

  1. static unsigned int lcm_compare_id()  
  2. {  
  3.     unsigned int array[4];  
  4.     unsigned char buffer[4] = {0,0,0,0};  
  5.     unsigned char id_high=0;  
  6.     unsigned char id_low=0;  
  7.     unsigned char id_low0=0;  
  8.     unsigned int id=0;  
  9.   
  10.     /* 先進行復位操做 */  
  11.     SET_RESET_PIN(1);  
  12.     MDELAY(10);  
  13.     SET_RESET_PIN(0);  
  14.     MDELAY(10);  
  15.     SET_RESET_PIN(1);  
  16.     MDELAY(200);  
  17.       
  18. //*************Enable CMD2 Page1  *******************//  
  19.     array[0]=0x00063902;  
  20.     array[1]=0x0698ffff;  
  21.     array[2]=0x00000104;  
  22.     dsi_set_cmdq(array, 3, 1);  
  23.   
  24.     array[0] = 0x00043700;  
  25.     dsi_set_cmdq(array, 1, 1);  
  26.     MDELAY(10);  
  27.     read_reg_v2(0x00, buffer, 4);  
  28.     id_high = buffer[0];     //98  
  29.   
  30.     array[0] = 0x00043700;  
  31.     dsi_set_cmdq(array, 1, 1);  
  32.     MDELAY(10);  
  33.     read_reg_v2(0x01, buffer, 4);  
  34.     id_low = buffer[0];     //06  
  35.   
  36.     array[0] = 0x00043700;  
  37.     dsi_set_cmdq(array, 1, 1);  
  38.     MDELAY(10);  
  39.     read_reg_v2(0x02, buffer, 4);  
  40.     id_low0 = buffer[0];   //04  
  41.   
  42.     id = (id_high<<16) | (id_low<<8)|id_low0;  
  43.   
  44. #ifdef BUILD_LK  
  45.     printf("ILI9806e:id2=%x.\n",id);  
  46.     printf("ILI9806e:id4=%x.\n",id_high);  
  47.     printf("ILI9806e:id5=%x.\n",id_low);  
  48.     printf("ILI9806e:id5=%x.\n",id_low0);  
  49. #else  
  50.     printk("ILI9806e:id=%x.\n",id);  
  51.     printk("ILI9806e:id_high=%x.\n",id_high);  
  52.     printk("ILI9806e:id_low=%x.\n",id_low);  
  53.     printk("ILI9806e:id_low=%x.\n",id_low0);  
  54. #endif  
  55.              
  56.     return (0x980604 == id) ? 1 : 0;  
  57. }  

數據編寫格式是遵循MIPI協議進行編寫的

注:若是系統只配置一個lcm設備,lcm_compare_id接口不會調用,只有系統存在多個設備的是纔會調用該接口進行匹配;

相關文章
相關標籤/搜索