對於LCM驅動移植,通常分爲三部曲:數組
一、硬件IO口配置;框架
二、確保LCM背光可以正常點亮;ide
三、LCM驅動移植;函數
硬件電路:spa
![](http://static.javashuo.com/static/loading.gif)
一、GPIO配置.net
打開 mediatek\dct\DrvGen.exe 設計
選擇 mediatek\custom\xiaoxi\kernel\dct\dct\codegen.dws 配置文件3d
配置LCM PWM引腳、RST復位引腳、DISP_PWM引腳和LCM電源控制引腳調試
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
二、背光燈
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各項參數;
- LCM_DRIVER ili9806e_drv =
- {
- .name = "ili9806e_txd_dsi_cmd_sp13_lcm_drv",
- .set_util_funcs = lcm_set_util_funcs,
- .get_params = lcm_get_params,
- .init = lcm_init,
- .suspend = lcm_suspend,
- .resume = lcm_resume,
- .compare_id = lcm_compare_id,
- };
以上函數接口是爲MTK框架中的幾個重要接口;
/* 獲取設備的LCM_DRIVER結構 */
- static void lcm_set_util_funcs(const LCM_UTIL_FUNCS *util)
- {
- memcpy(&lcm_util, util, sizeof(LCM_UTIL_FUNCS));
- }
-
- static void lcm_get_params(LCM_PARAMS *params)
- {
- memset(params, 0, sizeof(LCM_PARAMS));
-
- params->type = LCM_TYPE_DSI;
- params->width = FRAME_WIDTH;
- params->height = FRAME_HEIGHT;
-
-
- params->dbi.te_mode = LCM_DBI_TE_MODE_DISABLED;
- params->dbi.te_edge_polarity = LCM_POLARITY_RISING;
-
- #if (LCM_DSI_CMD_MODE)
- params->dsi.mode = CMD_MODE;
- #else
- params->dsi.mode = SYNC_PULSE_VDO_MODE;
- #endif
-
-
-
- params->dsi.LANE_NUM = LCM_TWO_LANE;
-
- params->dsi.data_format.color_order = LCM_COLOR_ORDER_RGB;
- params->dsi.data_format.trans_seq = LCM_DSI_TRANS_SEQ_MSB_FIRST;
- params->dsi.data_format.padding = LCM_DSI_PADDING_ON_LSB;
- params->dsi.data_format.format = LCM_DSI_FORMAT_RGB888;
-
-
-
- params->dsi.packet_size = 256;
-
-
- params->dsi.intermediat_buffer_num = 0;
-
- params->dsi.PS = LCM_PACKED_PS_24BIT_RGB888;
- params->dsi.word_count = 480 * 3;
-
- params->dsi.vertical_sync_active = 4;
- params->dsi.vertical_backporch = 16;
- params->dsi.vertical_frontporch = 20;
- params->dsi.vertical_active_line = FRAME_HEIGHT;
-
- params->dsi.horizontal_sync_active = 10;
- params->dsi.horizontal_backporch = 50;
- params->dsi.horizontal_frontporch = 60;
- params->dsi.horizontal_active_pixel = FRAME_WIDTH;
-
- params->dsi.PLL_CLOCK= 200;
- }
//復位引腳
#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)
/* 初始化參數及函數接口 */
- static struct LCM_setting_table lcm_initialization_setting[] = {
-
- {0xFF, 5,{0xFF,0x98,0x06,0x04,0x01}},
- {0x08, 1, {0x10}},
- {0x21, 1, {0x01}},
- {0x30, 1, {0x02}},
- {0x31, 1, {0x02}},
- {0x40, 1, {0x16}},
- {0x41, 1, {0x22}},
- ......
- {0x53, 1, {0x1A}},
- {0xFF, 5,{0xFF,0x98,0x06,0x04,0x07}},
- {0x17, 1, {0x12}},
- {0x02, 1, {0x77}},
- {0xFF, 5,{0xFF,0x98,0x06,0x04,0x00}},
- {0x35,1, {0x00}},
- {0x36,1, {0x03}},
- {0x11, 1, {0x00}},
- {REGFLAG_DELAY, 120, {}},
- {0x29, 1, {0x00}},
- {REGFLAG_DELAY, 50, {}},
- {REGFLAG_END_OF_TABLE, 0x00, {}}
- };
-
- static void lcm_init(void)
- {
-
- SET_RESET_PIN(1);
- MDELAY(10);
- SET_RESET_PIN(0);
-
- MDELAY(10);
- SET_RESET_PIN(1);
- MDELAY(120);
-
- push_table(lcm_initialization_setting, sizeof(lcm_initialization_setting) / sizeof(struct LCM_setting_table), 1);
- }
/* 設備掛起 */
- static void lcm_suspend(void)
- {
- #ifdef BUILD_LK
- printf("%s, ALS/PS bbbbbbbbbbbbbbb \n", __func__);
- #else
- printk("%s, ALS/PS bbbbbbbbbbbbbb \n", __func__);
- #endif
-
- push_table(lcm_deep_sleep_mode_in_setting, sizeof(lcm_deep_sleep_mode_in_setting) / sizeof(struct LCM_setting_table), 1);
- SET_RESET_PIN(0);
- MDELAY(20);
- SET_RESET_PIN(1);
- MDELAY(50);
- }
由於lcm驅動被映射到lk層,在lk層只能使用printf進行調試,但在kernel層中只能printk進行打印調試,因此可使用宏進行BUILD_LK區分;
掛起的機制通常有兩種:簡單睡眠或深度睡眠;
簡單睡眠:設備還處於工做狀態,能夠被喚醒,可是此時也會存在待機功耗等問題;
深度睡眠:設備處於休眠狀態,基本處於不工做狀態,所以沒法被喚醒;
通常程序設計都是使用深度睡眠,在喚醒時進行從新初始化;
/* 設備恢復 */
- static void lcm_resume(void)
- {
- lcm_init();
-
- }
從新初始化設備
/* 設備id匹配 */
- static unsigned int lcm_compare_id()
- {
- unsigned int array[4];
- unsigned char buffer[4] = {0,0,0,0};
- unsigned char id_high=0;
- unsigned char id_low=0;
- unsigned char id_low0=0;
- unsigned int id=0;
-
-
- SET_RESET_PIN(1);
- MDELAY(10);
- SET_RESET_PIN(0);
- MDELAY(10);
- SET_RESET_PIN(1);
- MDELAY(200);
-
- array[0]=0x00063902;
- array[1]=0x0698ffff;
- array[2]=0x00000104;
- dsi_set_cmdq(array, 3, 1);
-
- array[0] = 0x00043700;
- dsi_set_cmdq(array, 1, 1);
- MDELAY(10);
- read_reg_v2(0x00, buffer, 4);
- id_high = buffer[0];
-
- array[0] = 0x00043700;
- dsi_set_cmdq(array, 1, 1);
- MDELAY(10);
- read_reg_v2(0x01, buffer, 4);
- id_low = buffer[0];
-
- array[0] = 0x00043700;
- dsi_set_cmdq(array, 1, 1);
- MDELAY(10);
- read_reg_v2(0x02, buffer, 4);
- id_low0 = buffer[0];
-
- id = (id_high<<16) | (id_low<<8)|id_low0;
-
- #ifdef BUILD_LK
- printf("ILI9806e:id2=%x.\n",id);
- printf("ILI9806e:id4=%x.\n",id_high);
- printf("ILI9806e:id5=%x.\n",id_low);
- printf("ILI9806e:id5=%x.\n",id_low0);
- #else
- printk("ILI9806e:id=%x.\n",id);
- printk("ILI9806e:id_high=%x.\n",id_high);
- printk("ILI9806e:id_low=%x.\n",id_low);
- printk("ILI9806e:id_low=%x.\n",id_low0);
- #endif
-
- return (0x980604 == id) ? 1 : 0;
- }
數據編寫格式是遵循MIPI協議進行編寫的
注:若是系統只配置一個lcm設備,lcm_compare_id接口不會調用,只有系統存在多個設備的是纔會調用該接口進行匹配;