平台:RK3399
KERNEL版本:kernel4.4
Android版本:android8.1
一、硬件原理图
调试前先过一遍原理图这个是必须滴,硬件上对比旧的MIPI显示方案,LCM的RST脚没有变化,LT9211的RST和ENABLE脚释放出来,ZA7783仅需要一个供电脚,再就是多路供电,包含LCM及整体
电路,这些对于硬件同事应该不难,结合芯片参考电路,这个需要找供应商咨询。
二、屏幕参数和DTS配置
1.屏参
开头有提到是旧屏(的确挺旧的,久违的1024x768)由于项目对亮度及分辨率没有太高要求,这些都不深究了…手册里参数如下:
直接采用里面的Typ值,这里要说到一个工具:ZA7783_APPTOOL_V1.2.xls。表格内可以填充对应的CLK,脉冲,HSYNC,DATAEN值,完毕后会自动给出芯片初始化配置,这部分也算是关键了,最高找中星微支持拿到工具。
2.DTS贴图
没有太多需要注意的,放在所在I2C下,I2C地址根据手册看是0X37,芯片唯一的供电脚,pinctrl可加可不加,最好是加上便于查看。
三、参考代码
初始化部分代码我这是参考MTK项目上的,之前有调试过,提供一个思路,可以根据具体寄存器的值查手册来分析为什么要这么配,在结合具体项目分析,7783的寄存器数量也不算很多,代码如下:
//I2C读写
u32 lcm_va7783_i2c_read(u16 addr)
{
u32 u4Reg = 0;
u32 ret_code = 0;
ret_code = va7783_i2c_read(addr, &u4Reg);
if (ret_code != 0)
{
return ret_code;
}
return u4Reg;
}
sta
tic void lcm_va7783_dump_register(void)
{
u32 u4Reg = 0;
u32 i;
for(i = 0; i < 13; i++)
{
u4Reg = VA7783_REG_READ(reg
);
#ifdef BUILD_LK
printf("[LK/LCM] read Reg[0x%X] = 0x%X n", reg, u4Reg);
#else
printk("[LCM] read Reg[0x%X] = 0x%X n", reg, u4Reg);
#endif
}
}
//芯片初始化CODE
static void init_va7783_registers(void)
{
printk("[LK/LCM] init_va7783_registers() n");
#if 0
VA7783_REG_WRITE(0x00, 0x00);
VA7783_REG_WRITE(0x08, 0x01);
VA7783_REG_WRITE(0x10, 0x3F);
VA7783_REG_WRITE(0x11, 0x00);
VA7783_REG_WRITE(0x12, 0x00);
VA7783_REG_WRITE(0x13, 0xE4);
VA7783_REG_WRITE(0x14, 0x02);
VA7783_REG_WRITE(0x15, 0x02);
VA7783_REG_WRITE(0x16, 0x24);
VA7783_REG_WRITE(0x17, 0x00);
VA7783_REG_WRITE(0x18, 0x21);
VA7783_REG_WRITE(0x20, 0x3F);
VA7783_REG_WRITE(0x21, 0xFF);
VA7783_REG_WRITE(0x22, 0x00);
VA7783_REG_WRITE(0x23, 0x00);
VA7783_REG_WRITE(0x24, 0x00);
VA7783_REG_WRITE(0x25, 0x00);
VA7783_REG_WRITE(0x26, 0xE4);
VA7783_REG_WRITE(0x27, 0x00);
VA7783_REG_WRITE(0x28, 0x28);
VA7783_REG_WRITE(0x29, 0x01);
VA7783_REG_WRITE(0x2A, 0x00);
VA7783_REG_WRITE(0x2B, 0x01);
VA7783_REG_WRITE(0x2C, 0x0E);
VA7783_REG_WRITE(0x2D, 0x00);
VA7783_REG_WRITE(0x2E, 0x18);
VA7783_REG_WRITE(0x2F, 0x02);
VA7783_REG_WRITE(0x30, 0x02);
VA7783_REG_WRITE(0x31, 0x00);
VA7783_REG_WRITE(0x32, 0x63);
VA7783_REG_WRITE(0x40, 0x00);
VA7783_REG_WRITE(0x41, 0x00);
VA7783_REG_WRITE(0x42, 0x00);
VA7783_REG_WRITE(0x12, 0x00);
VA7783_REG_WRITE(0x13, 0xE4);
VA7783_REG_WRITE(0x14, 0x02);
VA7783_REG_WRITE(0x15, 0x00);
VA7783_REG_WRITE(0x16, 0x12);
VA7783_REG_WRITE(0x17, 0x00);
VA7783_REG_WRITE(0x18, 0x21);
VA7783_REG_WRITE(0x24, 0x0C);
VA7783_REG_WRITE(0x25, 0x00);
VA7783_REG_WRITE(0x26, 0xE4);
VA7783_REG_WRITE(0x27, 0x00);
VA7783_REG_WRITE(0x29, 0x01);
VA7783_REG_WRITE(0x2B, 0x03);
VA7783_REG_WRITE(0x42, 0x02);
VA7783_REG_WRITE(0x00, 0x01);
VA7783_REG_WRITE(0x10, 0x00);
VA7783_REG_WRITE(0x11, 0x0F);
VA7783_REG_WRITE(0x20, 0x00);
VA7783_REG_WRITE(0x21, 0x00);
VA7783_REG_WRITE(0x22, 0x03);
VA7783_REG_WRITE(0x23, 0x01);
#else
VA7783_REG_WRITE(0x00, 0x00);
VA7783_REG_WRITE(0x08, 0x01);
VA7783_REG_WRITE(0x10, 0x3F);
VA7783_REG_WRITE(0x11, 0x00);
VA7783_REG_WRITE(0x12, 0x00);
VA7783_REG_WRITE(0x13, 0xE4);
VA7783_REG_WRITE(0x14, 0x02);
VA7783_REG_WRITE(0x15, 0x02);
VA7783_REG_WRITE(0x16, 0x24);
VA7783_REG_WRITE(0x17, 0x00);
VA7783_REG_WRITE(0x18, 0x21); //考虑修改验证 0x00
VA7783_REG_WRITE(0x20, 0x3F);
VA7783_REG_WRITE(0x21, 0xFF);
VA7783_REG_WRITE(0x22, 0x00);
VA7783_REG_WRITE(0x23, 0x00);
VA7783_REG_WRITE(0x24, 0x00);
VA7783_REG_WRITE(0x25, 0x00);
VA7783_REG_WRITE(0x26, 0xE4);
VA7783_REG_WRITE(0x27, 0x00);
VA7783_REG_WRITE(0x28, 0x28);
VA7783_REG_WRITE(0x29, 0x01);
VA7783_REG_WRITE(0x2A, 0x00);
VA7783_REG_WRITE(0x2B, 0x01);
VA7783_REG_WRITE(0x2C, 0x0E);
VA7783_REG_WRITE(0x2D, 0x00);
VA7783_REG_WRITE(0x2E, 0x18);
VA7783_REG_WRITE(0x2F, 0x02);
VA7783_REG_WRITE(0x30, 0x02);
VA7783_REG_WRITE(0x31, 0x00);
VA7783_REG_WRITE(0x32, 0x63);
VA7783_REG_WRITE(0x40, 0x00);
VA7783_REG_WRITE(0x41, 0x00);
VA7783_REG_WRITE(0x42, 0x00);
VA7783_REG_WRITE(0x12, 0x00);
VA7783_REG_WRITE(0x13, 0xE4);
VA7783_REG_WRITE(0x14, 0x02);
VA7783_REG_WRITE(0x15, 0x00);
VA7783_REG_WRITE(0x16, 0x16);
VA7783_REG_WRITE(0x17, 0x00);
VA7783_REG_WRITE(0x18, 0x21);//0x00
VA7783_REG_WRITE(0x24, 0x0C);
VA7783_REG_WRITE(0x25, 0x00);
VA7783_REG_WRITE(0x26, 0xE4);
VA7783_REG_WRITE(0x27, 0x00);
VA7783_REG_WRITE(0x29, 0x01);
VA7783_REG_WRITE(0x2B, 0x03);
VA7783_REG_WRITE(0x42, 0x02);//考虑修改验证 0x00
VA7783_REG_WRITE(0x00, 0x01);
VA7783_REG_WRITE(0x10, 0x00);
VA7783_REG_WRITE(0x11, 0x0F);
VA7783_REG_WRITE(0x20, 0x00);
VA7783_REG_WRITE(0x21, 0x00);
VA7783_REG_WRITE(0x22, 0x03);
VA7783_REG_WRITE(0x23, 0x01);
#endif
}
//供电脚输出
static void config_gpio(void)
{
mt_set_gpio_mode(GPIO_POWER_LCM, GPIO_MODE_00);
mt_set_gpio_dir(GPIO_POWER_LCM, GPIO_DIR_OUT); // GPIO out
mt_set_gpio_mode(GPIO_POWER_LCM_EXT, GPIO_MODE_00);
mt_set_gpio_dir(GPIO_POWER_LCM_EXT, GPIO_DIR_OUT); // GPIO out
// mt_set_gpio_mode(test_pin, GPIO_MODE_00);
// mt_set_gpio_dir(test_pin, GPIO_DIR_OUT);
}
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;
params->physical_width = FRAME_WIDTH;
params->physical_height = FRAME_HEIGHT;
params->dsi.mode = SYNC_PULSE_VDO_MODE;
params->dsi.LANE_NUM = LCM_FOUR_LANE;
// 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;
params->dsi.PS = LCM_PACKED_PS_24BIT_RGB888;
#if 0
params->dsi.vertical_sync_active = 1;
params->dsi.vertical_backporch = 2;
params->dsi.vertical_frontporch = 7;
params->dsi.vertical_active_line = FRAME_HEIGHT;
params->dsi.horizontal_sync_active = 4;
params->dsi.horizontal_backporch = 60;
params->dsi.horizontal_frontporch = 28;
params->dsi.horizontal_active_pixel = FRAME_WIDTH ;
params->dsi.cont_clock = 1;
params->dsi.PLL_CLOCK = 165;
#else
params->dsi.vertical_sync_active = 4;//4
params->dsi.vertical_backporch = 4;//4
params->dsi.vertical_frontporch = 30;//20
params->dsi.vertical_active_line = FRAME_HEIGHT;
params->dsi.horizontal_sync_active = 4;
params->dsi.horizontal_backporch = 216;
params->dsi.horizontal_frontporch = 100;
params->dsi.horizontal_active_pixel = FRAME_WIDTH ;
params->dsi.cont_clock = 1;
params->dsi.PLL_CLOCK = 195;//200;
#endif
#ifdef ESD_CHECK_EN
params->dsi.esd_check_enable = 1;
params->dsi.customization_esd_check_enable = 1;
params->dsi.lcm_esd_check_table[0].cmd = 0x0a;
params->dsi.lcm_esd_check_table[0].count = 1;
params->dsi.lcm_esd_check_table[0].para_list[0] = 0x9c;
#endif
}
static void lcm_init_power(void)
{
}
static void lcm_suspend_power(void)
{
SET_RESET_PIN(1);
MDELAY(5);
SET_RESET_PIN(0);
MDELAY(10);
}
static void lcm_resume_power(void)
{
}
static void init_lcm_registers(void)
{
}
//芯片使用上只在LK初次上电,后面不再下电,休眠唤醒也不下电。
//稍微关注时序
static void lcm_init(void)
{
SET_RESET_PIN(1);
MDELAY(5);
SET_RESET_PIN(0);
MDELAY(5);
SET_RESET_PIN(1);
MDELAY(20);
LCM_PRINT("########################lcm_init##########################");
// init_lcm_registers();
MDELAY(500);
init_va7783_registers();
MDELAY(500);
// mt_set_gpio_out(test_pin, GPIO_OUT_ONE);
MDELAY(10);
mt_set_gpio_out(GPIO_POWER_LCM_EXT, 1);
MDELAY(5);
mt_set_gpio_out(GPIO_POWER_LCM, 1);
}
static void lcm_suspend(void)
{
SET_RESET_PIN(0);
VA7783_REG_WRITE(0x23, 0x00);
VA7783_REG_WRITE(0x22, 0x00);
VA7783_REG_WRITE(0x21, 0xFF);
VA7783_REG_WRITE(0x20, 0x3F);
VA7783_REG_WRITE(0x11, 0x00);
VA7783_REG_WRITE(0x10, 0x3F);
VA7783_REG_WRITE(0x00, 0x00);
mt_set_gpio_out(GPIO_POWER_LCM, 0);
//mt_set_gpio_out(GPIO_POWER_LCM_EXT, 0);
// mt_set_gpio_out(test_pin, GPIO_OUT_ZERO);
// lcm_va7783_dump_register();
}
static void lcm_resume(void)
{
//lcm_init();
#if 0
init_va7783_registers();
#else
VA7783_REG_WRITE(0x00, 0x01);
VA7783_REG_WRITE(0x10, 0x00);
VA7783_REG_WRITE(0x11, 0x0F);
VA7783_REG_WRITE(0x20, 0x00);
VA7783_REG_WRITE(0x21, 0x00);
VA7783_REG_WRITE(0x22, 0x03);
VA7783_REG_WRITE(0x23, 0x01);
#endif
MDELAY(500);
config_gpio();
// mt_set_gpio_out(test_pin, GPIO_OUT_ONE);
MDELAY(5);
mt_set_gpio_out(GPIO_POWER_LCM_EXT, 1);
MDELAY(10);
mt_set_gpio_out(GPIO_POWER_LCM, 1);
MDELAY(10);
SET_RESET_PIN(1);
MDELAY(5);
SET_RESET_PIN(0);
MDELAY(5);
SET_RESET_PIN(1);
MDELAY(20);
//MDELAY(500);
init_lcm_registers();
MDELAY(300);
}
四、调试中遇到的坑
首先说一下,MIPI转LVDS可以参照前面的文章了解一下时序,如果对RK平台有了解,看前面贴出的DTS就能知道个大概了。问题点以下进行罗列:
1.7783上电位置考究,一开始尝试在MIPI信号输出后上电,发现画面显示闪烁明显,观感效果很差,结合芯片手册的时序,这部分操作应该在屏初始化之前进行,修改后改善。
2.屏只刷了2S LOGO后就花屏甚至不显示了…这个问题排查了一天,开始以为是时序不对,反复对照手册调整延迟等,发现没有实质性改善,于是跟硬件探讨将整个供电和时序量下,发现遇到两个问题,一个是IO控制不正常,这里牵扯到两点:1.UBOOT部分没有提供LDO7的供电,导致在进入KERNEL才供电,过长的延迟导致无法显示,在u-boot/drivers/power/pmic/pmic_rk818.c的rk818_pre_init内添加
i2c_reg_write(addr, RK818_LDO_EN_REG,
i2c_reg_read(addr, RK818_LDO_EN_REG) |0x40);/*enable ldo7 for display*/
即可解决,但是进到kernel后发现控制还是不正常,排查后发现IO复用存在,这部分可以参照RK的手册进行检查,可以通过adb的cat /sys/kernel/debug/gpio 以及cat /sys/kernel/debug/pinctrl/pinctrl/pinmux-pins来确认有没有实际复用。RK平台复用算是比较常见的了…苦笑。2.虽然1解决IO问题,但是刷LOGO问题还是存在,第二天测量时钟发现从UBOOT切换至KERNEL明显时钟源不一样,这点根据RK手册里的描述,修改位置如下:u-boot/drivers/video/rockchip_vop.c
#ifdef CONFIG_RKCHIP_RK3399
/* Set Dclk pll parent */ //lk-modify
// if (conn_state->type == DRM_MODE_CONNECTOR_HDMIA)
if(!crtc_state->crtc_id)
rkclk_lcdc_dclk_pll_sel(crtc_state->crtc_id, 0);
else
rkclk_lcdc_dclk_pll_sel(crtc_state->crtc_id, 1);
#endif
至此2问题总算解决…
3.先来张图:
图中为7783MIPI转LVDS的注意事项,很明显看到芯片为Video Mode且应该为Non-Burst,而RK一直使用的为BURST Mode,切换dsi,flag为MIPI_DSI_MODE_VIDEO_SYNC_PULSE后发现有屏偏,这点找RK的人员咨询过,他们回复说是这个模式使用场景少,没有很好的适配,可以看看BURST能否支持。实际上BURST的确也能输出,最后采用BURST,经几天测试发现没有出现显示异常问题。
4.由于之前调过其它的显示方案,这里没有出现不显示,休眠唤醒不亮或者花屏的问题,如果有出现的,需要仔细排查时序,看看是否合理,7783时序对比9211要简单,在LK上电后不需要下电,休眠唤醒也只是对屏本身时序进行考量,即考虑RST,ENABLE时序。
总结
ZA7783芯片初始化内容相较简单,可以有效节省IO,转换效果也不错,但是由于Non-Burst的限制导致适用范围不再广泛,仅为可选项。文首有提RK支持问题,因为现在大多为Burst模式,那边尝试用Non-Burst配置并没有成功,后面被搁置(Non-Burst使用场合低)。屏本身基本都支持两种方式,这里其实受限于芯片,这也是为什么考虑要不要写的主要原因。(MTK项目上用这个应该能多点)
原作者:彡渲染丨灬繁华