mtk lcm驱动流程

lcm驱动流程:
lcm模组驱动,ili9881c_dsi_hd_vdo_dj_sp603_drv

LCM_DRIVER ili9881c_dsi_hd_vdo_dj_sp603_drv =
{
.name = “ili9881c_dsi_hd_vdo_dj_sp603”,
.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,
#if defined(LCM_DSI_CMD_MODE)
.update = lcm_update,
#endif
};

Mt65xx_lcm_list.c 函数中通过lcm_driver_list调用到lcm模组驱动函数。

Disp_lcm.c文件中通过disp_lcm_probe函数来调用lcm_driver_list数组,

Primary_display.c文件中通过primary_display_init函数调用
disp_lcm_probe(lcm_name, LCM_INTERFACE_NOTDEFINED)

在mtkfb.c文件中通过mtkfb_probe函数调用
primary_display_init(mtkfb_find_lcm_driver(), lcd_fps);

通过数据结构platform_driver挂接的到platform总线上

static struct platform_driver mtkfb_driver = {
.driver = {
.name = MTKFB_DRIVER,
#ifdef CONFIG_PM
.pm = &mtkfb_pm_ops,
#endif
.bus = &platform_bus_type,
.probe = mtkfb_probe,
.remove = mtkfb_remove,
.suspend = mtkfb_suspend,
.resume = mtkfb_resume,
.shutdown = mtkfb_shutdown,
.of_match_table = mtkfb_of_ids,
},
};

framebuffer设备驱动程序的核心数据结构是fb_ops;用户空间就是
通过此结构体,调用其中的函数来对LCD实现控制。

Mtkfb.c中定义并实现了fb_ops类型的mtkfb_ops。

static struct fb_ops mtkfb_ops = {
.owner = THIS_MODULE,
.fb_open = mtkfb_open,
.fb_release = mtkfb_release,
.fb_setcolreg = mtkfb_setcolreg, //批量配置颜色参数
.fb_pan_display = mtkfb_pan_display_proxy, //虚拟屏幕内容显示
.fb_fillrect = cfb_fillrect, //填充区域显示
.fb_copyarea = cfb_copyarea, //复制区域显示
.fb_imageblit = cfb_imageblit, //显示图象
.fb_cursor = mtkfb_soft_cursor, //光标显示
.fb_check_var = mtkfb_check_var, //检查并配置fb_var_screeninfo参数
.fb_set_par = mtkfb_set_par, //change display mode and set parameter
.fb_ioctl = mtkfb_ioctl, //特定ioctl配置LCD屏幕特性
#ifdef CONFIG_COMPAT
.fb_compat_ioctl = mtkfb_compat_ioctl,
#endif
#if defined(CONFIG_PM_AUTOSLEEP)
.fb_blank = mtkfb_blank,
#endif
};

对结构体的调用关系 在函数中mtkfb_fbinfo_init,info->fbops = &mtkfb_ops;
在mtkfb_probe函数中注册到系统/* Register to system */r = mtkfb_fbinfo_init(fbi);

probe函数会调用register_framebuffer来向内核注册一个fb_info结构体。而这个fb_info结构体便是lcd驱动的核心了。它就是应用程序调用open,open函数根据次设备号寻找的fb_info结构体。下面可以总结下probe函数的核心工作了,也是我们写整个驱动的核心工作:

1、分配fb_info结构体;

2、设置fb_info结构体;

3、register_framebuffer()向内核注册fb_info结构体;

这样应用程序在调用open函数时,它会找到我们提交的fb_info结构体。并应用里边的设置来完成相应的操作。当然除了open函数,read、write等函数都会调用到我们的fb_info.

驱动具体实现代码解析

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驱动上层提供的接口。

http://blog.csdn.net/good123_2014/article/details/52416358
http://blog.csdn.net/loongembedded/article/details/46929173
http://blog.csdn.net/ojiuyue1234567890/article/details/52964072

  • 0
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值