这份代码是我从37平台上复制过来的,一般MTK平台的屏驱动代码都大同小异,屏部分的代码在平台架构的2个地方,一个是lk层,一个是kernel层,在整机启动 的时候屏的代码init、lcm_compare_id等在lk层就会都跑一遍,虽然在2个地方都有一样的屏代码,但是kernel层的那份屏代码最主要的功能还是起到lcm_suspend与lcm_resume作用,什么lcm_compare_id就算删掉也没事,下面这份代码是otm1287a的一份屏代码,关键的地方我会加上自己的理解注释,如有错误,望指出! (不定期更新)
#ifdef BUILD_LK
#else
#include <linux/string.h>
#if defined(BUILD_UBOOT)
#include <asm/arch/mt_gpio.h>
#else
//#include <mach/mt_gpio.h>
#endif
#endif
#include "lcm_drv.h"
// ---------------------------------------------------------------------------
// Local Constants (局部常量)
// ---------------------------------------------------------------------------
//此部分是屏幕分辨率的定义
//如果同一个屏需要用在多个项目上,那么可以通过宏控制,但是需使用时要在内核的kconfig文件中注册一下
#define FRAME_WIDTH (720)
#define FRAME_HEIGHT (1280)
//这个是不同型号屏幕的ID,在机器刚起来即LK层的时候会有lcm_compare_id这个函数使用到,抓log就可以看到
#define LCD_ID_OTM1287A (0x1287)
// ---------------------------------------------------------------------------
// Local Variables (局部变量)
// ---------------------------------------------------------------------------
//这部分的代码可以在lcm_drv.h中找到,是一个封装好的结构体(LCM_UTIL_FUNCS)
static LCM_UTIL_FUNCS lcm_util = {0};
#define SET_RESET_PIN(v) (lcm_util.set_reset_pin((v)))
#define UDELAY(n) (lcm_util.udelay(n))
#define MDELAY(n) (lcm_util.mdelay(n))
#define REGFLAG_DELAY 0XFE //调整延迟的寄存器地址
#define dsi_set_cmdq_V2(cmd, count, ppara, force_update) lcm_util.dsi_set_cmdq_V2(cmd,count,ppara, force_update)
#define dsi_set_cmdq(pdata, queue_size, force_update) lcm_util.dsi_set_cmdq(pdata,queue_size,force_update)
#define wrtie_cmd(cmd) lcm_util.dsi_write_cmd(cmd)
#define write_regs(addr, pdata, byte_nums) lcm_util.dsi_write_regs(addr,pdata,byte_nums)
//#define read_reg lcm_util.dsi_read_reg()
#define read_reg_v2(cmd, buffer, buffer_size) lcm_util.dsi_dcs_read_lcm_reg_v2(cmd,buffer,buffer_size)
//这个结构体主要是屏幕初始化对寄存器的操作,具体的格式为:{寄存器的地址,写入寄存器数据的个数,写入的数据}
//这个会在下面的LCM_setting_table 数组中使用到,来初始化屏幕
struct LCM_setting_table {
unsigned cmd;
unsigned char count;
unsigned char para_list[64];
};
//下面这部分就是屏幕的初始化
static struct LCM_setting_table lcm_initialization_setting[] = {
{0x00, 1, {0x00}},
{0xff, 3, {0x12,0x87,0x01}},
{0x00, 1, {0x80}},
{0xff, 2, {0x12,0x87}},
{0x00, 1, {0x92}},
{0xff, 2, {0x20,0x02}},// 20 3LANE 30 4LANE
{0x2a, 4, {0x00,0x00,0x03,0x1F}},
{0xc0, 9, {0x00,0x6f,0x00,0x10,0x10,0x00,0x64,0x10,0x10}},
{0x00, 1, {0x90}},
{0xc0, 6, {0x00,0x5c,0x00,0x01,0x00,0x04}},
.
.
. //这边省略一些值,因为这个具体值的含义只有屏厂的FAE知道,我接触到的只是一些关键点值的含义
.
.
{0x00, 1, {0x00}},
{0xff, 3, {0xff,0xff,0xff}},
{0x00, 1 ,{0x00}},
{0x11,1,{0x00}}, // Sleep-Out
{REGFLAG_DELAY,150,{}},
{0x00, 1 ,{0x00}},
{0x29,1,{0x00}}, // Display On
{REGFLAG_DELAY,50,{}},
#endif
初始化代码部分,后面最主要的就是lk部分读屏的函数,以及mipi部分一些参数的值设定,因为我的工作发生变化,后面接触是高通平台,屏这部分还是有点差别的,高通是uefi架构,,所以MTK的平台的暂时不更新了,如果后面再做MTK的会继续更新。
};
```#if 0
static struct LCM_setting_table lcm_sleep_out_setting[] = {
// Sleep Out
{0x11, 0, {0x00}},
{REGFLAG_DELAY, 120, {}},
// Display ON
{0x29, 0, {0x00}},
{REGFLAG_DELAY, 100, {}},
};
static struct LCM_setting_table lcm_sleep_mode_in_setting[] = {
// Display off sequence
{0x28, 0, {0x00}},
{REGFLAG_DELAY, 100, {}},
// Sleep Mode On
{0x10, 0, {0x00}},
{REGFLAG_DELAY, 200, {}},
};
static struct LCM_setting_table lcm_compare_id_setting[] = {
// Display off sequence
{0xF0, 5, {0x55, 0xaa, 0x52,0x08,0x00}},
{REGFLAG_DELAY, 10, {}},
};
#endif
//static int vcom=0x20;
static void push_table(struct LCM_setting_table *table, unsigned int count, unsigned char force_update)
{
unsigned int i;
for(i = 0; i < count; i++) {
unsigned cmd;
cmd = table[i].cmd;
switch (cmd) {
/*
case 0xd9:
table[i].para_list[0]=vcom;
dsi_set_cmdq_V2(cmd, table[i].count, table[i].para_list, force_update);
vcom+=2;
break;
*/
case REGFLAG_DELAY :
MDELAY(table[i].count);
break;
default:
dsi_set_cmdq_V2(cmd, table[i].count, table[i].para_list, force_update);
}
}
}
// ---------------------------------------------------------------------------
// LCM Driver Implementations
// ---------------------------------------------------------------------------
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;
// enable tearing-free
params->dbi.te_mode = LCM_DBI_TE_MODE_DISABLED; //LCM_DBI_TE_MODE_VSYNC_ONLY;
params->dbi.te_edge_polarity = LCM_POLARITY_RISING;
params->dsi.mode = SYNC_PULSE_VDO_MODE;
// DSI
/* Command mode setting */
params->dsi.LANE_NUM = LCM_THREE_LANE;
//The following defined the fomat for data coming from LCD engine.
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;
// Video mode setting
params->dsi.intermediat_buffer_num = 2;
params->dsi.PS=LCM_PACKED_PS_24BIT_RGB888;
params->dsi.word_count=FRAME_WIDTH*3; //DSI CMD mode need set these two bellow params, different to 6577
params->dsi.vertical_active_line=FRAME_HEIGHT;
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 = 80;
params->dsi.horizontal_frontporch = 80;
params->dsi.horizontal_blanking_pixel = 60;
params->dsi.horizontal_active_pixel = FRAME_WIDTH;
params->dsi.compatibility_for_nvk = 0; // this parameter would be set to 1 if DriverIC is NTK's and when force match DSI clock for NTK's
params->dsi.PLL_CLOCK = 260; //dsi clock customization: should config clock value directly
//params->dsi.PLL_CLOCK = 230; //dsi clock customization: should config clock value directly
}
static unsigned int lcm_compare_id(void)
{
unsigned char id[5];
unsigned int lcd_id;
unsigned int data_array[5];
SET_RESET_PIN(1);
MDELAY(10);
SET_RESET_PIN(0);
MDELAY(50);
SET_RESET_PIN(1);
MDELAY(10);
data_array[0]=0x00053700;
dsi_set_cmdq(data_array, 1, 1);
read_reg_v2(0xA1, id,5);
lcd_id =(id[2]<<8)|id[3];
#ifdef BUILD_LK
printf("[lcm_init]: lk OTM1287A id0=%x, id1=%x, id2=%x, id3=%x , id4=%x , lcd_id=%x \n",id[0], id[1], id[2], id[3], id[4], lcd_id);
#else
printk("[lcm_init]: kerne OTM1287A id0=%x, id1=%x, id2=%x, id3=%x, id4=%x \n",id[0], id[1], id[2], id[3], id[4]);
#endif
return (LCD_ID_OTM1287A == lcd_id)?1:0;
}
static void lcm_init(void)
{
SET_RESET_PIN(1);
MDELAY(10);
SET_RESET_PIN(0);
MDELAY(50);
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)
{
SET_RESET_PIN(0);
MDELAY(50);
SET_RESET_PIN(1);
MDELAY(120);
//push_table(lcm_sleep_mode_in_setting, sizeof(lcm_sleep_mode_in_setting) / sizeof(struct LCM_setting_table), 1);
}
static void lcm_resume(void)
{
lcm_init();
//push_table(lcm_sleep_out_setting, sizeof(lcm_sleep_out_setting) / sizeof(struct LCM_setting_table), 1);
}
#if defined(LCM_DSI_CMD_MODE)
static void lcm_update(unsigned int x, unsigned int y,
unsigned int width, unsigned int height)
{
}
#endif
LCM_DRIVER otm1287a_hd_dsi_vdo_lcm_drv =
{
.name = "otm1287a_hd_dsi_vdo",
.set_util_funcs = lcm_set_util_funcs,
.compare_id = lcm_compare_id,
.get_params = lcm_get_params,
.init = lcm_init,
.suspend = lcm_suspend,
.resume = lcm_resume,
#if defined(LCM_DSI_CMD_MODE)
.update = lcm_update,
#endif
};