MTK LCM驱动分析
参考:
http://blog.csdn.net/sunweizhong1024/article/details/8447915
platform_driver_register(&mtkfb_driver)
probe
strstr(saved_command_line, "fps="); //得到UBOOT传过来的参数
mtkfb_find_lcm_driver :hj101na02a_lcm_drv
disp_drv_get_lcm_driver
lcm->set_util_funcs(&lcm_utils); //设置LCD操作函数
lcm->get_params(lcm_params); //得到LCD的一些硬件参数
disp_drv_init_ctrl_if //如果是DBI(mcu 屏)
//LCM_CTRL_SERIAL_DBI
LCD_Init()
LCD_ConfigSerialIF
//LCM_CTRL_PARALLEL_DBI
LCD_Init()
LCD_ConfigParallelIF
LCD_SelectWriteIF //选择是串口还是并口
LCD_ConfigIfFormat //配置接口的数据类型
to_lcd_if_width //数据宽度,DBI
disp_drv_set_driving_current //设置接口的电流
LCD_Init_IO_pad //初始化GPIO
disp_drv_init_context
DISP_GetDriverDBI :DBI_DISP_DRV 操作函数
DISP_GetDriverDPI :DPI_DISP_DRV
DISP_GetDriverDSI :DSI_DISP_DRV
//得到LCD的一些参数
DISP_GetScreenWidth
。。。。。。
kthread_create(esd_recovery_kthread, NULL, "esd_recovery_kthread"); //esd检测
得到指点屏幕的信息:
DISPCHECK("[POWER]lcm suspend[begin]\n");while (1) {msleep(2000);/* esd check every 2s */ 两秒就会检测一次ret = wait_event_interruptible(esd_check_task_wq, atomic_read(&esd_check_task_wakeup));两种检测模式1./* / Esd Check : EXT TE */ 配置dsi.customization_esd_check_enable == 02./* / Esd Check : Read from lcm */ 配置dsi.customization_esd_check_enable == 1/* 0.create esd check cmdq */cmdqRecCreate(CMDQ_SCENARIO_DISP_ESD_CHECK, &(pgc->cmdq_handle_config_esd));dpmgr_path_build_cmdq(pgc->dpmgr_handle, pgc->cmdq_handle_config_esd, CMDQ_ESD_ALLC_SLOT);MMProfileLogEx(ddp_mmp_get_events()->esd_rdlcm, MMProfileFlagPulse, 0, 2);/* 1.use cmdq to read from lcm */if (primary_display_is_video_mode())ret = _esd_check_config_handle_vdo();/* 2.check data(*cpu check now) */ret = dpmgr_path_build_cmdq(pgc->dpmgr_handle, pgc->cmdq_handle_config_esd, CMDQ_ESD_CHECK_CMP);MMProfileLogEx(ddp_mmp_get_events()->esd_rdlcm, MMProfileFlagPulse, 0, 4);/* 3.destroy esd config thread */cmdqRecDestroy(pgc->cmdq_handle_config_esd);}if (ret == 1) { //如果发现LCM被打死,需要重启primary_display_esd_recovery();
DISPCHECK("[POWER]lcm suspend[end]\n");
三、Display
1.lcm 相关概念
1.1) MIPI接口:
一共有三种接口:DBI(也做CPU或MCU接口)、DPI(也叫RGB接口)、DSI.
在使用DSI接口时,目前75/77都只支持到2条data lane,加上一条clock lane.
使用DPI接口时,根据LCM IC支持的情况,可以选择16bus、18bus传输RGB格式文件,在GPIO部分分为R、G、B分别对应 8个GPIO(GPIO20~46期间),客户采用DPI接口需要根据选择的bus方式进行配置,推荐RGB端口全部配置为对应的复选模 式,并设置为OUT输出。
采用DBI接口,有两种模式选择,一种是选择共用DPI的bus脚 +DPI控制线,另一种是共用nand data pin+CPU 控制线。
1.2) DSI接口有两种sync 模式:
video mode和command mode,其中video mode是BB端一直刷数据到LCM,cmd mode是在有数 据更新时刷数据到LCM GRAM中) 和DSI command mode相比,video mode 是需要实时传输image data到lcm端,DSI 的refresh rate决定了lcm的refresh rate。
1.3)EDS机制:
92平台LCM driver中定义了esd_check和esd_recovery的接口,但ESD线程不工作。
目前在MT6589之前平台,video mode的ESD实现有三种模式,分别是:ext TE(外部TE信号检测)、int TE(内部TE信号检 测)、non cout clk不同ESD方式需要注意的方面
a) int TE和ext TE的检测,都不需要实现lcm_esd_check函数,而需要实现lcm_esd_recover函数。
non cont clk则不需要实现lcm_esd_check函数和lcm_esd_recover函数,而只需要在上面 params中配置为TRUE即可
b) ext TE的实现,需要LCM外接TE pin到BB端,同时在inital code中配置寄存器打开TE信号的输出 (一般是写0x35寄存器,具体需要和LCM IC FAE确认)
1.4)HDMI/MHL:
目前我司HDMI/MHL的相关code和driver都是有集成在codebase中的,要使用的话,只需要只需要在对应的 ProjectConfig.mk文件中开启,并且在dct中配置好对应的引脚定义即可。
以下以MHL为例:
ProjectConfig中配置:
MTK_HDMI_SUPPORT=yes #表明开启HDMI/MHL功能
CUSTOM_KERNEL_HDMI=Sii8338 #表明配置为MHL的IC型号
1.5)TE 信号:
大部分TE问题是由于没有正常开启TE所导致,首先检查TE是否开启。
89平台使用内部TE,lcm driver中只需要在init过程中打开LCM TE即可,一般是写0x35寄存器,部分IC需要额外写其他 寄存器,可与FAE确认。
检查TE是否正常开启,如果是工版,则可使用如下方式打开fps的log,查看TE信息:
adb shell
cd sys/kernel/debug
echo fps:on>mtkfb
然后查看mtklog, 搜索“FPS”,若看到等待TE时间为0, 表示TE未正常开启,需要与LCM IC的FAE进一步确认开启流程 。
若TE已经成功开启,依然有Teering现象,可从如下方面思考分析。
1)是否使用了竖屏横用,导致对GRAM的读写方向不一致,一般会出现斜线切屏现象。
2)是否clock速度过低,FPS低于LCM自刷新率的1/2?
3)是否clock速率过快,超过LCM的自刷新率,导致写GRAM时可能从后面赶上读,导致Teering发生。
4)fmark周期与CS周期
出现TE现象的根本原因是两边速度不一致,具体是LCM的刷新速度要快于主控送数据的速度,两者的速度要符合一定的范围才行。只要保证CS的周期在两个TE周期之间即可,也就是CS的写频率不能低于TE读频率的二分之一,Tearing出现的根本条件是读写有交叉。通常都是写Gram速度(WR)慢于lcd刷屏速度(TE)[x2] ,只要刷屏的位置不超过写Gram位置就不会有切屏现象。[x3]
举个实例:比如CS差不多就比两个TE周期小一点,要刷两桢数据,首先第一桢刷屏开始刷屏了,表示读GRAM开始,它的速度比较快,它读的是老旧数据;紧接着主控开始写GRAM,大概写到GRAM的快一半时,这时候已经刷完一桢,然后开始刷第二桢,即又从GRAM的最上方开始读并刷屏,此时读出来的才是刚写入的新数据,在写完GRAM之前,读的步骤永远跟不上写的步骤,就不会出现tearing。
如果CS比两个TE周期大,假设相当于三个TE周期,那么只有在第三个TE读周期时,显示的数据才是写好的GRAM的数据;第一个TE读的是老旧的数据,第二个TE周期由于GRAM还没有写完,但读步骤赶上写GRAM步骤了,导致显式一部分是旧的一部分是新的,所以出现TE。此即本质。
5) TE类型
TE显示使能时,必须保证CPU的LCD TE使能和LCM驱动的TE功能都打开。LCM的TM使能有两
1.6)HS/LP:
HS:high speed , clock切为HS模式,高速模式。
LP:low power,低电平
有些LCM在开机的时候,如果使用LP下发init code,可能会不准确或者导致花屏等问题,这时候需要使用HS mode发送init code,比如三星的某款OLED(D53D6EA8061V-Amoled)。
continuous clock/no-continuous clock模式
1.6)dithering:
抖动显示技术:
MT6572 如所用lcm不支持RGB888 color format, 显示效果差需要开启dithering的。
1.7)其他概念:
AAL:BB端CABC(即AAL),为1种方式控制背光
continuous clock/Non-continuous clock : Switch clock lane from HS to LP
2.LCM时钟配置
MT6582 LCM Driver中配置:params->dsi.PLL_CLOCK = 234;
计算方法:
展频开关:
如果MIPI Clock对RF/WCN产生干扰,并且在尝试寻找相应的频点依然无法解除 EMI,可以尝试做Frequency Hopping;
82平台默认打开展频开关,不同于72/89平台,将展频的开关以及展频幅度的选择 ,都开放到LCM Driver中,以如下为例:
params->dsi.ssc_range =4;
params->dsi.ssc_disable = 0;
代表:展频打开,ssc_range = 4%
3.AAL与CABC背光选择(两种方式控制背光):
参考[FAQ05966]
【BB端CABC(即AAL)】
- 打开功能,向MTK申请patch,并在ProjectConfig.mk中打开MTK_AAL_SUPPORT = yes
4. 调整Display 消耗的BW(bandwidth带宽)方法:
•LCM driver建议如下:
–MIPI的clock 尽量低,建议60fps
–For DSI Video mode,建议不要使用burst mode(比较能吃BW)
params->dsi.mode = BURST_VDO_MODE;
–Video mode的时序,blank 区间(如VBP/VFP/HBP/HFP)尽量少(当然也需要满足LCM module的spec)
5.DSI video mode相关参数配置方法:
对应配置文件:\alps\mediatek\custom\common\kernel\lcm\xxxx.c中lcm_get_params()函数
1,data lane每帧回LP11(Low Power state,dp,dn都为高电平),clk一直HS( High Speed),对应配置:
params->dsi.cont_clock=1;
params->dsi.clk_lp_per_line_enable=0;
2,data lane每一行回一次LP11,clk lane每一帧回一次LP,对应配置:
params->dsi.cont_clock=0;
params->dsi.clk_lp_per_line_enable=0;
3,data lane和clk lane都是每行回一次LP11,对应配置:
params->dsi.cont_clock=0;
params->dsi.clk_lp_per_line_enable=1;
6.LCM CABC 配置
参考[FAQ12413]
7.MHL 卡顿问题
8.ESD机制各个平台的差异:
对于89/72/82等新平台,Display架构做了调整,ESD的实现方式与之前的75/77等平台稍有差异。对于之前75/77平台,可以参考FAQ03210及FAQ05163.
新旧架构下,主要是DSI Video Mode下ESD方式不一样。
之前的架构下Video Mode的屏采用检测外部TE或者内部TE来做ESD Check,因此需要在lcm driver中配置相应的参数。
新架构下不支持外部TE或内部TE来做ESD check, lcm_get_params中关于esd的参数不用再配置。
如lcm_int_te_monitor、lcm_int_te_period、lcm_ext_te_monitor等无需配置。
[SOLUTION]
新的Display架构下,DSI Video Mode及DSI Command Mode都采用读寄存器的方式来进行esd check. 因此都只需要在lcm driver中实现esd_check和esd_recover函数即可。
对于具体读取哪些寄存器来进行esd check,需要与屏厂确认。
ESD实现后如果出现每两秒闪屏的问题,可以按如下流程处理:
1. 首先检查esd check中是否添了过多的log信息或者有delay操作,建议先去掉所有log测试。
2. 如果依然出现每两秒闪屏,可参考FAQ05680和FAQ05681进行处理。
9.DBI/DPI接口的GPIO的配置情况
DBI:DBI接口分为串行和并行两种。由lcm_params->ctrl这个参数控制。
LCM_CTRL_SERIAL_DBI/LCM_CTRL_PARALLEL_DBI
1.)如果是serial类型的,是通过MT6572 datasheet里面的0x14012028 DBI_SCNF (DBI Serial Interface Configuration Register)这个寄存器来config串行接口。比如使用LSDI还是LSDA,LSCK上升沿还是下降沿发送数据 ,LSCK在没有数据的时候是LOW/HIGH.
配置几个GPIO pin:LSCE0B(相当于数据使能信号,低电平有效), LSCK, LSDA/LSDI(传送command时用),DBI[XX:0](传 送data时用)
CSS,CSH:chip select setup time/chip select hold time
(这两个时间之内是不会传数据的,Invalid data)
2.)如果是Parallel类型的,
配置几个GPIO pin:LPCE0B(相当于CS信号,低电平有效), LPA0(RS信号,MTK平台上面和CS信号是同步的), LCD CLK,LPWRB/LPRDB(类似数据使能信号)和DBI[XX:0](复用DPI的data pin,传送data和command时用)
写的时候用LPWRB,读的时候用LPRDB
有C2WS和C2WH两个变量:chip selection to write setup time和chip selection to write hold time
同理C2RS和C2RH.
硬件连接:
DBI Parallel类型:BB端需要打开LRDB、LWRB、LPA0 pin脚复用功能,并连接到LCM的RD、WR、RS
DBI serial类型: BB端需要打开LSCE0B、LSCK、LSDA/LSDI pin脚复用功能, 并连接到LCM的CSX, SCL, SDA/DOUT/DIN
lcm Driver里面变量write wait state time,是处于wait状态的时间。比如大于等于C2WS,参考MT6572 datasheet PAGE1659原理图
note:89和72的DBI的clock都是不可调整的,都是130Mhz.
但是如果需要调整DBI的FPS的话,可以调整C2WS/C2WH/WST,分别对应write_setup/write_hold/write_wait
DPI:
使用DPI接口时,根据LCM IC支持的情况,可以选择16bus、18bus传输RGB格式文件,在GPIO部分分为R、G、B分别对应 8个GPIO(GPIO20~46期间),客户采用DPI接口需要根据选择的bus方式进行配置,推荐RGB端口全部配置为对应的复选模式,并设置为 OUT输出。
同时DPI的接口需要BB端打开DPIHSYNC、DPIVSYNC、DPIDE、DPICK复用功能,并分别连接到对应的LCM控制端
另注:
其实DPI和DBI一样,都是可以通过lcm_params->ctrl这个变量来控制是使用Parallel还是serial还是GPIO的类型来下 command。
但是一般DPI都会选择使用LCM_CTRL_SERIAL_DBI这个类型,因为DPI的屏,DB[17..0]只是会用来做数据传输,控制线是 会通过LSDA/LSDI传输。
10.LCM Porting时如何配置Clock
clock配置方法:
lcm driver中配置clock有不同的方式,曾经使用过的配置方法有如下几种:
Type1: 配置倍频与分频参数:dsi.pll_div1(倍频), dsi.pll_div2(分频)--- (适用于75/77等之前的平台)
Type2: 配置倍频与分频参数:dsi.pll_fbk_div(倍频), dsi.pll_div1 & dsi.pll_div2 (分频)---(适用于89/72等前 期版本)
Type3: 直接配置clock lane频率:dsi.PLL_CLOCK(前期配置成枚举值,后期将直接配置成对应的频率常数值)----(适 用于89/72/82...)
11.如何使用PMIC的LDO方式供给LCM端 1.8/2.8v的电压
参考[FAQ10038]
1. 如何在开机阶段使用PMIC的LDO方式供给LCM端1.8/2.8v的电压?
2. 如何在suspend/resume的时候,断掉/供给LCM端1.8/2.8v的电压?
1. )在开机的时候,建议在preloader或者LK阶段就通过PMIC的LDO方式来给LCM端上电,
比如可以在alps\mediatek\platform\mt6589\preloader\src\drivers\mtk_pmic_6320.c文件里面的 pmic6320_init函数中做上电1.8/2.8v的操作。
AOSP版本mtk_pmic_6320.c的路径 :alps/bootable/bootloader/preloader/platform/mt6572/src/drivers/mtk_pmic_6320.c
下面是在LK阶段的上电/掉电方法:
使用upmu_common.c文件里面API来分别控制每一个LDO_VGPX.
比如:
upmu_set_rg_vgp6_vosel用来控制上电的电压值;
upmu_set_rg_vgp6_en用来控制enable VGP6这个pin
2. )因为在suspend/resume的时候,kernel都是跑起来的,所以上电/掉电 1.8/2.8v的操作都应该放在kernel里面。
下面是在kernel里面的上电/掉电方法,在kernel里面有统一的上电/掉电的接口函数: 上电接口函数:hwPowerOn 掉电接口函数hwPowerDown
以下以PMIC6320的VGP6为例。
请在您要上电的文件#include <mach/mt_pm_ldo.h> 上电请调用 hwPowerOn,掉电请调用hwPowerDown
hwPowerOn(MT65XX_POWER_LDO_VGP6, VOL_2800, "ldo_test");
bool hwPowerDown(MT65XX_POWER_LDO_VGP6, "ldo_test");
12.如何拉低并保持LCM RESET PIN脚为低 电平
平台默认RESET PIN脚输出为高平的,如果一定需要拉低,可以配置RESET PIN脚为GPIO模式,再通过GPIO方式拉低。
使用mediatek/dct目录下的DCT工具,使用其打开custom/XXX/kernel/dct/dct目录下的DWS文件,将GPIO131配置成 0:GPIO131.
对GPIO PIN脚的控制有如下一些方法:
lcm_util.set_gpio_mode(GPIO131, GPIO_MODE_00);
lcm_util.set_gpio_dir(GPIO131,GPIO_DIR_OUT);
lcm_util.set_gpio_out(GPIO131,0);
13.如何调节MIPI接口驱动能力
在使用DBI、DPI的MIPI接口时,可以在lcm_get_params函数中设置参数 io_driving_current的值来配置IO的驱动电流(6589上面不支持)
DSI的MIPI接口,不支持IO驱动电路的调节 ,其可选值的大小可以在lcm_drv.h看到定义。
其可选值的大小可以在lcm_drv.h看到定义:
typedef enum{
}LCM_DRIVING_CURRENT;
该值的会在lcd_drv.c文件中写到寄存器中:
LCD_STATUS LCD_Set_DrivingCurrent();
14.如何通过检测外部TE实现esd check的 功能
在72/82/92的JB/KK版本,我们都是通过读取esd寄存器的方式实现esd check,但是由于esd check的时候会切换到cmd mode去读,所以屏的玻璃存在最大1帧时间的等待,如果这个vdo
mode屏的玻璃延时等待时间较小(小于切换的时间),就会出现闪屏,所以不能使用读esd寄存器 的方式做esd check。
如果这个屏有 external TE管脚的话,可以通过检测ext.TE的方式来做esd check,具体原理 为:把原来的esd流程全部关闭,启动一个新的线程,循环检测外部TE中断,如果检测失败,就
recovery。
新的esd流程里面需要做三件事:
1) 物理连接一根外部TE pin,然后在dws文件里面配置一个GPIO口为DSI_TE模式。
2) 在DSI初始化的时候,注册该ext.TE的irq处理函数,收到中断则设置irq_flag为TRUE。
3) 启动线程定时去wait flag==1,如果超时,则做esd recovery。
15.如何配置DSI时钟频率
1、)DSI vdo mode下的数据速率data_rate的大致计算公式为: Data rate= (Height+VSA+VBP+VFP)*(Width+HSA+HBP+HFP)* total_bit_per_pixel*frame_per_second/total_lane_num
2、)DSI cmd mode下的数据速率data_rate的大致计算公式为: Data rate= width*height*1.2* total_bit_per_pixel*frame_per_second/total_lane_num
参数注释:
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的对数。
3、)DSI采用的是双边采样,则clk等于数据速率的一半,因此: clk=data_rate/2
有两种配置clk的方式,第一种方式配置四个参数得到,第二种配置方式直接配置频 率,建议采用第二种。
第一种方式,通过div分频倍频实现,各个平台略有差异,但是原理基本一致,请参 考porting guide,如下举例89平台:
params->dsi.pll_div1 = ; //配置范围为0,1,2,3的时候,对应的 div1_real等于1,2,4,4
params->dsi.pll_div2 = ; //配置范围为0,1,2,3的时候,对应的 div2_real等于1,2,4,4
params->dsi.fbk_div = ; //范围 0..63
params->dsi.fbk_sel = ; //配置范围为0,1,2,3的时候,对应的 fbk_sel_real等于1,2,4,4
输出频率 =26MHz*(fbk_div+1)*(2*fbk_sel_real)/(div1_real*div2_real)
第二种方式,直接配置clk大小:
params->dsi.PLL_CLOCK = LCM_DSI_6589_PLL_CLOCK_234;//这里举例89平台,使用 一个宏,表示配置的clk等于234MHz。但是在89之后的平台,使用直接配置一个频率
数字的方式,比如params->dsi.PLL_CLOCK = 234,表示234MHZ)
4、在lcm porting过程中,这些参数都定义在lcm_drv.h文件中的LCM_DSI_PARAMS结 构体中,随着平台的发展,或许有所不同,但是基本原理都是一致的,如何配置clk的大小,请先根据自己的帧率、像素格式、porch值、屏的分辨率、 data lane对数等计算出data_rate,然后计算出clk。
16.背光模式设置成 T65XX_LED_MODE_CUST_BLS_PWM,如何修改PWM的工作频率
前提:cust_leds.c文件里面使用的背光模式是MT65XX_LED_MODE_CUST_BLS_PWM
MT6582版本工作频率计算公式如下:
PWM工作频率计算公式:26MHz (clock freq.) / (PWM_CLKDIV+1) / 1024 (period) 26 KHz
所以需要修改PWM的工作频率,可以通过修改PWM_CLKDIV,clock freq,或者period的值来达到修 改PWM的工作频率的效果。
以下的三种方法可以任选1~2种来达到想要的PWM工作频率:
1. 修改分频参数方法,修改config_data里面的第二个参数:
{"lcd-backlight", MT65XX_LED_MODE_CUST_BLS_PWM, (int)disp_bls_set_backlight,{0, 1, 0, 0, 0}} //设置div=1
2. 修改clock freq:
在alps\mediatek\platform\mt6582\kernel\drivers\dispsys\ddp_bls.c文件的 disp_bls_init和disp_bls_config函数中设置CLK_CFG_1这个寄存器的值,来选择合适的时钟源,加入如下代码:
mt65xx_reg_sync_writel(DRV_Reg32(CLK_CFG_1) | (0x00000003), CLK_CFG_1); //设置156 MHz的时钟源