一,lcm 相关概念
1.1) MIPI接口
一共有三种接口:DBI(也做CPU或MCU接口)、DPI(也叫RGB接口)、DSI.在使用DSI接口时,目前75/77都只支持到2条data lane,加上一条clock lane.使用DPI接口时,根据LCM IC支持的情况,可以选择16bus、18bus传输RGB格式文件。
1.2) DSI接口有两种sync 模式
兼容MIPI DSI协议的外设都支持Command Mode和Video Mode两种操作模式,具体使用哪一种操作模式由具体的外设架构决定,那么这两种操作模式它们有什么区别呢。
Video Mode:
这种操作模式同传统的RGB接口类似,主控制器需要实时的往显示屏上刷新像素数据,因为数据流一般比较大,这种模式只能工作在高速率模式下。这种模式是不需要带有显存的。
Video Mode同样也包含一些简单的命令操作,例如屏的初始化、屏的打开、关闭等等,这个时候是工作在低速模式下的。
Video Mode主要又有三种模式:
- Non-burst Mode Sync pulses
- Non-burst Mode Sync event
- Burst mode
Command Mode:
MIPI主控制器通过命令集往显示器发送像素数据流,所以这种模式必须要有一个显存(frame buffer)用来存储像素数据。
1.3)HS/LP
HS:high speed , clock切为HS模式,高速模式。
LP:low power,低电平
LCM在开机的时候,使用LP下发init code,
continuous clock/no-continuous clock模式
二,LCM时钟配置
2.1.MIPI接口的PLL计算
MT6582 LCM Driver中配置:params->dsi.PLL_CLOCK = 234;
DSI vdo mode下的数据速率data_rate的计算公式为:
Data rate= (width+VSA+VBP+VFP)*(height+HSA+HBP+HFP)* total_bit_per_pixel*frame_per_second/total_lane_num
2.2.DSI cmd mode下的数据速率data_rate的计算公式为:
Data rate= width*height*1.2* total_bit_per_pixel*frame_per_second/total_lane_num
2.3.参数注释:
data_rate : 表示的是数据速率
width,height :屏幕分辨率
VSA VBP VFP :DSI vdo mode的vertical porch配置参数
HSA HBP HFP :DSI vdo mode的horizontal porch配置参数
total_bit_per_pixel :表示的是一个pixel需要用几个bit来表示,比如RGB565的话就是16个bit
frame_per_second :就是我们通常看到的fps,叫做帧率,表示每秒发送多少个帧,一般是60帧每秒
total_lane_num :表示的是data lane的对数。
2.4.DSI采用的是双边采样,则clk等于数据速率的一半,因此: clk=data_rate/2
2.5.在lcm porting过程中,这些参数都定义在lcm_drv.h文件中的LCM_DSI_PARAMS结构体中,随着平台的发展,或许有所不同,但是基本原理都是一致的,如何配置clk的大小,请先根据自己的帧率、像素格式、porch值、屏的分辨率、data lane对数等计算出data_rate,然后计算出clk。
三,LCM驱动移植步骤
3.1 配置LCM的相关尺寸, ProjectConfig.mk中配置
alps/device/mediateksample/k62v1_64_bsp/ProjectConfig.mk
BOOT_LOGO = hd720
LCM_HEIGHT = 1440
LCM_WIDTH = 720
3.2 cfg文件配置LCM的尺寸与编译LCD模块名称
alps/kernel-4.9/arch/arm64/configs/k62v1_64_bsp_defconfig
CONFIG_CUSTOM_KERNEL_LCM="ili9881c_hdp_dsi_vdo_ilitek_rt5081"
CONFIG_LCM_HEIGHT="1440"
CONFIG_LCM_WIDTH="720"
3.3 配置 bootloader的logo大小与编译LCD模块名称
alps/vendor/mediatek/proprietary/bootable/bootloader/lk/project/k62v1_64_bsp.mk
那么相应的开机logo也要做相应的修改:
CUSTOM_LK_LCM="ili9881c_hdp_dsi_vdo_ilitek_rt5081"
BOOT_LOGO := hd720
修改分辨率 lcm_width lcm_height 还要修改对应的logo
logo 所在文件夹 /vendor/mediatek/proprietary/bootable/bootloader/lk/dev/logo
查看文件夹内图片的分辨率即可知道要改什么logo
3.4 修改mt65xx_lcm_list.c
那么先在mediatek/custom/common/kernel/lcm目录中创建一个目录ili9881c_hdp_dsi_vdo_ilitek_rt5081(注意,目录的名字要和ProjectConfig.mk中的lcm配置相对应),然后在该目录下创建一个文件ili9881c_hdp_dsi_vdo_ilitek_rt5081.c,至于这个文件里面应该填些什么内容,我们稍后来看。
然后修改mt65xx_lcm_list.c,依照已有的格式在lcm_driver_list这个数组里面添加下面的内容:
#if defined(HX8389B_QHD_DSI_VDO)
&ili9881c_hdp_dsi_vdo_ilitek_rt5081_drv,
#endif
3.5 编写ili9881c_hdp_dsi_vdo_ilitek_rt5081.c
kernel驱动文件ili9881c_hdp_dsi_vdo_ilitek_rt5081添加,将文件夹丢进kernel的alps/kernel-4.9/drivers/misc/mediatek/lcm/目录下;
alps/kernel-4.9/drivers/misc/mediatek/lcm/ili9881c_hdp_dsi_vdo_ilitek_rt5081/ili9881c_hdp_dsi_vdo_ilitek_rt5081.c
根据前面步骤可以看到,肯定需要一个hx8389b_qhd_dsi_vdo_drv这个结构,它的类型是LCM_DRIVER,来看一下应该怎么定义:
LCM_DRIVER ili9881c_hdp_dsi_vdo_ilitek_rt5081_drv = {
.name = "ili9881c_hdp_dsi_vdo_ilitek_rt5081",
.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_get_params。
lcm_get_params函数中主要是一些参数定义,例如屏的分辨率,屏的接口类型等等:
#define FRAME_WIDTH 540
#define FRAME_HEIGHT 960
static void lcm_get_params(LCM_PARAMS *params)
{
memset(params, 0, sizeof(LCM_PARAMS));
params->type = LCM_TYPE_DSI; /* lcm的接口类型 */
params->width = FRAME_WIDTH; /* lcm分辨率 */
params->height = FRAME_HEIGHT;
params->dsi.mode = SYNC_PULSE_VDO_MODE; /* video mode */
params->dsi.LANE_NUM = LCM_THREE_LANE; /* lanes */
params->dsi.data_format.format = LCM_DSI_FORMAT_RGB888; /* 数据格式 */
params->dsi.PS = LCM_PACKED_PS_24BIT_RGB888;
params->dsi.vertical_sync_active = 0x02; /* video mode需要配置的一些参数 */
params->dsi.vertical_backporch = 0x0e;
params->dsi.vertical_frontporch = 0x09;
params->dsi.vertical_active_line = FRAME_HEIGHT;
params->dsi.horizontal_sync_active = 0x21;
params->dsi.horizontal_backporch = 0x21;
params->dsi.horizontal_frontporch = 0x15;
params->dsi.horizontal_active_pixel = FRAME_WIDTH;
params->dsi.PLL_CLOCK = 180; /* clock(MHz) */
}
这个是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,才可以,调试的关键地方。
上面时序图上各时钟延时参数的含义如下:(这些参数的值,LCD产生厂商会提供相应的数据手册)
VBPD(vertical back porch): 表示在一帧图像开始时,垂直同步信号以后的无效的行数,对应驱动中的upper_margin;
VFBD(vertical front porch):表示在一帧图像结束后,垂直同步信号以前的无效的行数,对应驱动中的lower_margin;
VSPW(vertical sync pulse width):表示垂直同步脉冲的宽度,用行数计算,对应驱动中的vsync_len;
HBPD(horizontal back porch):表示从水平同步信号开始到一行的有效数据开始之间VCLK的个数,对应驱动中的left_margin;
HFPD(horizontal front porth):表示一行的有效数据结束到下一个水平同步信号开始之间的VCLK的个数,对应驱动中的right_margin;
HSPW(horizontal sync pulse width):表示水平同步信号的宽度,用VCLK计算,对应驱动中的hsync_len;
params->dsi.PLL_CLOCK = 240; lcm的频率,更据实际情况改动,这个一般mtk的都会影响gps的信号强弱。
再来看lcm_init:
#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 dsi_set_cmdq_V3(para_tbl, size, force_update) lcm_util.dsi_set_cmdq_V3(para_tbl, size, force_update)
#define dsi_set_cmdq_V2(cmd, count ppara, force_update) lcm_util.dsi_set_cmdq_V2(cmd, count, ppare, force_update)
#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 LCM_setting_table_V3 lcm_initialization_setting[] = {
{
0x39, 0xF0, 5, {
0x55, 0xAA, 0x52, 0x08, 0x03}},