lcm 驱动分析

struct LCM_setting_table {
unsigned char cmd; // 命令地址
unsigned char count; // 寄存器值的个数
unsigned char para_list[128]; //寄存器的值
};

static struct LCM_setting_table lcm_initialization_setting[] = {
{0xFF, 4, {0xAA,0x55,0xA5,0x80}}, //就是LCM_setting_table结构体的三个成员。

mipi屏的话,MTK平台的是不同的屏只要换这个初始化设置的代码就可以跑起来的,当然有些屏ic已经有程序,不需要再从初始化里下载这段代码。只要上电时序和配置对了就可以跑起来。

效果调试最多的是调试水波纹,可以调试vcom对应的寄存器。竖的波纹好像和pll_clk有关,可以调试试一下。

初始化里的这部分延时不能少。0x11和0x29是用来下载这段代码到lcd ic的,还有其它下载模式。比如:0x10和0x28.

{0x11,  1,  {0x00}},
{REGFLAG_DELAY, 120, {}},

{0x29,  1,  {0x00}},
{REGFLAG_DELAY, 20, {}},

{REGFLAG_END_OF_TABLE, 0x00, {}},

static struct LCM_setting_table lcm_deep_sleep_mode_in_setting[] = { }
这个是睡眠设置的寄存器

static struct LCM_setting_table lcm_deep_sleep_mode_in_setting[] = {}

这个是深度睡眠设置的寄存器

static void push_table(struct LCM_setting_table *table, unsigned int count, unsigned char force_update){}

这个是讲上面这些设置寄存器的数组push到ic里面去的函数。参数:结构体数组,个数,强制更新吧1次(我理解的)

重点内容

驱动实现部分

static void lcm_set_util_funcs(const LCM_UTIL_FUNCS *util)
{
memcpy(&lcm_util, util, sizeof(LCM_UTIL_FUNCS));
}

lcm 驱动框架提供给驱动开发者的接口函数,将util复制到lcm_util。

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; //高

if (LCM_DSI_CMD_MODE)

    params->dsi.mode   = CMD_MODE;

else

    params->dsi.mode   = SYNC_PULSE_VDO_MODE;

endif

// DSI
/* Command mode setting */
params->dsi.LANE_NUM                = LCM_FOUR_LANE;
params->dsi.data_format.format              = LCM_DSI_FORMAT_RGB888;

//video mode timing
    params->dsi.PS=LCM_PACKED_PS_24BIT_RGB888;

params->dsi.vertical_sync_active                = 4;
params->dsi.vertical_backporch              = 40;
params->dsi.vertical_frontporch             = 40;
params->dsi.vertical_active_line                = FRAME_HEIGHT;

params->dsi.horizontal_sync_active          = 4;
params->dsi.horizontal_backporch                = 82;
params->dsi.horizontal_frontporch               = 82;
params->dsi.horizontal_active_pixel         = FRAME_WIDTH;

//improve clk quality
params->dsi.PLL_CLOCK = 240; //this value must be in MTK suggested table
params->dsi.compatibility_for_nvk = 1;
params->dsi.ssc_disable = 1;

}

这个是lcm的配置部分,调试驱动必然要改的地方。
MIPI接口:一共有三种接口:DBI(也做CPU或MCU接口)、DPI(也叫RGB接口)、DSI.
在使用DSI接口时,目前6735支持到4条data lane,加上一条clock lane.我们采用的是DSI的

params->dsi.vertical_sync_active                = 4;
params->dsi.vertical_backporch              = 40;
params->dsi.vertical_frontporch             = 40;

params->dsi.horizontal_sync_active          = 4;
params->dsi.horizontal_backporch                = 82;
params->dsi.horizontal_frontporch               = 82;

这几个数据要看datasheet,才可以,调试的关键地方。

params->dsi.PLL_CLOCK = 240; lcm的频率,更据实际情况改动,这个一般mtk的都会影响gps的信号强弱。

static void lcm_id_pin_handle(void)
{
mt_set_gpio_pull_select(GPIO_DISP_ID0_PIN,GPIO_PULL_UP);
mt_set_gpio_pull_select(GPIO_DISP_ID1_PIN,GPIO_PULL_DOWN);
}
这个防止漏电的

static void lcm_init(void)
{
//enable VSP & VSN
lcm_util.set_gpio_out(GPIO_LCD_BIAS_ENP_PIN, GPIO_OUT_ONE);
lcm_util.set_gpio_out(GPIO_LCD_BIAS_ENN_PIN, GPIO_OUT_ONE);
msleep(50);
//reset high to low to high
lcm_util.set_gpio_out(GPIO_DISP_LRSTB_PIN, GPIO_OUT_ONE);
mdelay(5);
lcm_util.set_gpio_out(GPIO_DISP_LRSTB_PIN, GPIO_OUT_ZERO);
mdelay(5);
lcm_util.set_gpio_out(GPIO_DISP_LRSTB_PIN, GPIO_OUT_ONE);
msleep(10);

lcm_id_pin_handle();

push_table(lcm_initialization_setting, sizeof(lcm_initialization_setting) / sizeof(struct LCM_setting_table), 1);  

// when phone initial , config output high, enable backlight drv chip 
lcm_util.set_gpio_out(GPIO_LCD_DRV_EN_PIN, GPIO_OUT_ONE);

LCD_DEBUG("uboot:boe_nt35521_lcm_init\n");

}
//只要是初始化的上电时序,reset脚1 0 1(高低高),vsp和vsn,背光使能。mipi的屏都是一样的。

static void lcm_suspend(void)
{
//Back to MP.P7 baseline , solve LCD display abnormal On the right
// when phone sleep , config output low, disable backlight drv chip
lcm_util.set_gpio_out(GPIO_LCD_DRV_EN_PIN, GPIO_OUT_ZERO);
push_table(lcm_deep_sleep_mode_in_setting, sizeof(lcm_deep_sleep_mode_in_setting) / sizeof(struct LCM_setting_table), 1);
//reset low
lcm_util.set_gpio_out(GPIO_DISP_LRSTB_PIN, GPIO_OUT_ZERO);
mdelay(5);
//disable VSP & VSN
lcm_util.set_gpio_out(GPIO_LCD_BIAS_ENP_PIN, GPIO_OUT_ZERO);
lcm_util.set_gpio_out(GPIO_LCD_BIAS_ENN_PIN, GPIO_OUT_ZERO);
mdelay(5);

LCD_DEBUG("kernel:boe_nt35521_lcm_suspend\n");

}

static void lcm_resume(void)
{

//enable VSP & VSN
lcm_util.set_gpio_out(GPIO_LCD_BIAS_ENP_PIN, GPIO_OUT_ONE);
lcm_util.set_gpio_out(GPIO_LCD_BIAS_ENN_PIN, GPIO_OUT_ONE);
msleep(50);

//reset low to high
lcm_util.set_gpio_out(GPIO_DISP_LRSTB_PIN, GPIO_OUT_ONE);
mdelay(5);   
lcm_util.set_gpio_out(GPIO_DISP_LRSTB_PIN, GPIO_OUT_ZERO);
mdelay(5); 
lcm_util.set_gpio_out(GPIO_DISP_LRSTB_PIN, GPIO_OUT_ONE);
msleep(10); 

push_table(lcm_initialization_setting, sizeof(lcm_initialization_setting) / sizeof(struct LCM_setting_table), 1);
//Back to MP.P7 baseline , solve LCD display abnormal On the right
//when sleep out, config output high ,enable backlight drv chip  
lcm_util.set_gpio_out(GPIO_LCD_DRV_EN_PIN, GPIO_OUT_ONE);

LCD_DEBUG("kernel:boe_nt35521_lcm_resume\n");

}

唤醒和休眠刚好,时序相反,唤醒和初始化的程序是一样的。

static unsigned int lcm_compare_id(void)
{
unsigned int id = 0;
unsigned char buffer[3];
unsigned int array[16];

SET_RESET_PIN(1);  //NOTE:should reset LCM firstly
SET_RESET_PIN(0);
MDELAY(10);
SET_RESET_PIN(1);
MDELAY(120);

array[0] = 0x00033700;// read id return two byte,version and id
dsi_set_cmdq(array, 1, 1);
read_reg_v2(0x04, buffer, 3);
id = buffer[1]; //we only need ID

if defined(BUILD_UBOOT)

/*The Default Value should be 0x00,0x80,0x00*/
printf("\n\n\n\n[soso]%s, id0 = 0x%08x,id1 = 0x%08x,id2 = 0x%08x\n", __func__, buffer[0],buffer[1],buffer[2]);

endif

return (id == 0x80)?1:0;

}

看数据手册,获取lcm id。

LCM_DRIVER nt35521_hd720_dsi_vdo_boe_lcm_drv =
{
.name = “nt35521_hd720_dsi_vdo_boe”,
.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,
};

给lcm驱动上层提供的接口。

你可能感兴趣的:(lcd框架)