使用的瑞芯微的rv1109的平台,显示接口为MIPI,需要外接LVDS的显示屏,同时外接HDMI显示屏显示。
硬件调试注意事项如下:
强烈建议使用4层板设计,并且注意差分对的阻抗匹配100Ω±10%,差分对间,差分对组间需要做等长。
首先确认硬件电平是否正确, 查看REST脚是否按时序要求进行操作,手册上要求是拉低10ms再拉高,实际调试中,就用上电复位也是可以工作的。
参考官方代码进行配置,配置很多,就不贴出来了,后面会讲注意事项和如何调试。
代码写好后,在确保IIC通信正常的情况下,先把hdmi的 test pattern 模式设置了,如果能显示如下图,则说明lt8912芯片与硬件焊接基本没问题。
// Test pattern 1080P 60Hz,其它分辨率的Timing设置请参考Sheet4
//I2CADR = 0x92;
lt8912b_write_byte(lt8912b_I2C_S_ADDR, 0x72, 0x12 );
lt8912b_write_byte(lt8912b_I2C_S_ADDR, 0x73, 0xc0 ); //RGD_PTN_DE_DLY[7:0]
lt8912b_write_byte(lt8912b_I2C_S_ADDR, 0x74, 0x00 ); //RGD_PTN_DE_DLY[11:8] 192
lt8912b_write_byte(lt8912b_I2C_S_ADDR, 0x75, 0x29 ); //RGD_PTN_DE_TOP[6:0] 41
lt8912b_write_byte(lt8912b_I2C_S_ADDR, 0x76, 0x80 ); //RGD_PTN_DE_CNT[7:0]
lt8912b_write_byte(lt8912b_I2C_S_ADDR, 0x77, 0x38 ); //RGD_PTN_DE_LIN[7:0]
lt8912b_write_byte(lt8912b_I2C_S_ADDR, 0x78, 0x47 ); //RGD_PTN_DE_LIN[10:8],RGD_PTN_DE_CNT[11:8]
lt8912b_write_byte(lt8912b_I2C_S_ADDR, 0x79, 0x98 ); //RGD_PTN_H_TOTAL[7:0]
lt8912b_write_byte(lt8912b_I2C_S_ADDR, 0x7a, 0x65 ); //RGD_PTN_V_TOTAL[7:0]
lt8912b_write_byte(lt8912b_I2C_S_ADDR, 0x7b, 0x48 ); //RGD_PTN_V_TOTAL[10:8],RGD_PTN_H_TOTAL[11:8]
lt8912b_write_byte(lt8912b_I2C_S_ADDR, 0x7c, 0x2c ); //RGD_PTN_HWIDTH[7:0]
lt8912b_write_byte(lt8912b_I2C_S_ADDR, 0x7d, 0x05 ); //RGD_PTN_HWIDTH[9:8],RGD_PTN_VWIDTH[5:0]
lt8912b_write_byte(lt8912b_I2C_S_ADDR, 0x70, 0x80 );
lt8912b_write_byte(lt8912b_I2C_S_ADDR, 0x71, 0x76 );
// DDS,148.5M CLK,见Sheet4
lt8912b_write_byte(lt8912b_I2C_S_ADDR, 0x4e, 0x33 );
lt8912b_write_byte(lt8912b_I2C_S_ADDR, 0x4f, 0x33 );
lt8912b_write_byte(lt8912b_I2C_S_ADDR, 0x50, 0xd3 );
lt8912b_write_byte(lt8912b_I2C_S_ADDR, 0x51, 0x80 );
这里请注意使用的屏是否支持HDMI。显示效果如下图所示
因为电路和屏的参数不一样,有些参数按照官方的配置并不能正确工作,需要做一些调整
#define _PN_Swap_En 0x20
#define _PN_Swap_Dis 0x00
u8 MIPI_Lane_PN_Swap = _PN_Swap_Dis;
lt8912b_write_byte( lt8912b_I2C_F_ADDR,0x3e, 0x96 + MIPI_Lane_PN_Swap ); // bit5=1: P/N swap ; 0 : Normal
lt8912b_write_byte( lt8912b_I2C_S_ADDR,0x13, MIPI_Lane % 4 ); // 4 lane // 01 lane // 02 2 lane //03 3lane
lt8912b_write_byte( lt8912b_I2C_S_ADDR,0x15, MIPI_Lane_CH_Swap ); // 00: 0123 normal ; a8 : 3210 swap
#define _6_Bit_Color_ 0x17
#define _8_Bit_Color_ 0x13
lt8912b_write_byte( lt8912b_I2C_F_ADDR,0xa8, LVDS_Map + LVDS_mode + Color_Depth );
关于我使用的屏手册描述Color_Depth 供大家参考
16.2M 是6 bit color ,如果是16.7 M 则是8 bit_color . 关于位数问题,后面有补充。
const u16 MIPI_Timing[6][8] =
{
//H_act V_act H_total V_total H_BP H_sync V_sync V_BP
{ 720, 480, 858, 525, 60, 62, 6, 30 }, // 480P Vesa Timing
{ 1024, 768, 1344, 806, 160, 136, 6, 29 }, // 1024x768
{ 1280, 720, 1650, 750, 220, 40, 5, 20 }, // 720P Vesa Timing
{ 1280, 800, 1440, 823, 80, 32, 6, 14 }, // 1280x800 timing
{ 1024, 600, 1344, 635, 140, 20, 3, 20 }, // 1024x600
// { 1024, 600, 1274, 645, 80, 10, 10, 23 }, // 1024x600
{ 1920, 1080, 2200, 1125, 148, 44, 5, 36 }, // 1080P Vesa Timing
// { 1920, 1200, 2080, 1235, 80, 32, 6, 26 }, // 1920x1200 154MHz Vesa Timing
// { 1280, 480, 1460, 530, 80, 20, 10, 20 }, // 1280x480
};
&dsi {
status = "okay";
// rockchip,lane-rate = <480>;//900
panel@0 {
compatible ="simple-panel-dsi";
reg = <0>;
backlight = <&backlight>;
/delete-property/ power-supply;
prepare-delay-ms = <100>;
reset-delay-ms = <10>;
init-delay-ms = <100>;
disable-delay-ms = <50>;
unprepare-delay-ms = <20>;
width-mm = <68>;
height-mm = <121>;
pinctrl-names = "default";
pinctrl-0 = <&vdd_5v_3v3_h>;
enable-gpios = <&gpio2 RK_PD1 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpio3 RK_PA4 GPIO_ACTIVE_LOW>;
dsi,flags = <(MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
MIPI_DSI_MODE_VIDEO_HBP | MIPI_DSI_MODE_LPM |
MIPI_DSI_MODE_EOT_PACKET)>;
dsi,format = <MIPI_DSI_FMT_RGB888>;
dsi,lanes = <4>;
panel-init-sequence = [
05 78 01 29
05 78 01 11
];
display-timings {
native-mode = <&timing0>;
timing0: timing0 {
clock-frequency = <71000000>;
hactive = <1280>;
vactive = <800>;
hback-porch = <80>;
hfront-porch = <48>;
vback-porch = <14>;
vfront-porch = <3>;
hsync-len = <32>;
vsync-len = <6>;
hsync-active = <0>;
vsync-active = <0>;
de-active = <0>;
pixelclk-active = <0>;
};
};
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
panel_in_dsi: endpoint {
remote-endpoint = <&dsi_out_panel>;
};
};
};
};
ports {
#address-cells = <1>;
#size-cells = <0>;
port@1 {
reg = <1>;
dsi_out_panel: endpoint {
remote-endpoint = <&panel_in_dsi>;
};
};
};
};
这里要注意的地方:
驱动就使用方自带的驱动,“simple-panel-dsi”
rockchip,lane-rate 如果不知道设置多少,可以把这一行屏蔽,因为驱动中会自动计算速率,代码在dw-mipi-dsi.c中
像我这里设置为480(mipi clk 为240MHZ)就可以了,设置高了如900,mipi的clk为450Mhz,则图像会左右晃动。低了不能工作。
dsi,flags 中的 MIPI_DSI_MODE_VIDEO_HBP 这个设置一定要加上,否则不能显示,后面会说原因。
dsi,flags 中的 MIPI_DSI_MODE_EOT_PACKET 也要加,后面会有波形说明。
static unsigned long dw_mipi_dsi_get_lane_rate(struct dw_mipi_dsi *dsi)
{
struct device *dev = dsi->dev;
const struct drm_display_mode *mode = &dsi->mode;
unsigned long max_lane_rate = dsi->pdata->max_bit_rate_per_lane;
unsigned long lane_rate;
unsigned int value;
int bpp, lanes;
u64 tmp;
/* optional override of the desired bandwidth */
if (!of_property_read_u32(dev->of_node, "rockchip,lane-rate", &value))
return value * USEC_PER_SEC;
bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
if (bpp < 0)
bpp = 24;
lanes = dsi->slave ? dsi->lanes * 2 : dsi->lanes;
tmp = (u64)mode->clock * 1000 * bpp;
do_div(tmp, lanes);
/* take 1 / 0.9, since mbps must big than bandwidth of RGB */
tmp *= 10;
do_div(tmp, 9);
if (tmp > max_lane_rate)
lane_rate = max_lane_rate;
else
lane_rate = tmp;
return lane_rate;
}
mipi 的clk信号幅度问题
这个幅值是正确的,注意,因为mipi是差分信号,还要看p,n信号的幅值差,要符合mipi标准。
红色方框波形个数
从下图中可以看出共23个波形 ,23 是等于 vback-porch + vfront-porch + vsync-len = 14+3+6 =23
timing0: timing0 {
clock-frequency = <71000000>;
hactive = <1280>;
vactive = <800>;
hback-porch = <80>;
hfront-porch = <48>;
vback-porch = <14>;
vfront-porch = <3>;
hsync-len = <32>;
vsync-len = <6>;
hsync-active = <0>;
vsync-active = <0>;
de-active = <0>;
pixelclk-active = <0>;
};
};
确保MIPI信号已经给到LT8912B之后,再读video check的寄存器。
连续多次读video check寄存器,正常情况下,每次读到的值都是相同的,如果MIPI信号接收不稳定,则读到的值会变化。
读(IIC addr:0x92) 0x0c ~ 0x0f 4个寄存器(0x0f寄存器是最高位,一般都是0x00),如果MIPI源发生的信号的pixel clk是148.5M,那么理论上读到的值应该是0x32/0x33/0xD3,允许低位跳动,既是0x0c寄存器值跳动,其它三个寄存器保持稳定,那么就说明成功恢复了pixel clk。
如果pixel clk的值一直不稳定,
1、请确认MIPI源的屏参 和 LT8912B的MIPI timing配置完全相同。
2、关闭MIPI CLK的展频,关闭EOTP。
dsi,flags = <(MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
MIPI_DSI_MODE_VIDEO_HBP | MIPI_DSI_MODE_LPM |
MIPI_DSI_MODE_EOT_PACKET)>;
加上MIPI_DSI_MODE_EOT_PACKET 就是关闭EOT
查看EOT是否配置生效,可以使用如下命令
io -4 0xffb3002c
0xffb3002c 寄存器的值为 0x1c
说明已经关闭了。
eopt的信号见下图
这里会出现交互变化的过程,如果一直是高,或者一直是低,则表示eopt 没有关闭,注意高低变化不是按顺序出现,可能相邻的都是高,后面才变低。
2023-3-30 补充 关于6 bit 与 8bit 解释
那16.2M表示屏是6bit还是8bit,
抖动的实现原理是,如果要显示的颜色,不在真实能显示的颜色中,就用最近的两个颜色,用散点进行混合
用灰度来举例,有0,1,2,,,255一共256级灰度,8bit面板对每种灰度都可以完整表现。而6bit只能显示0,4,8,12,,,,252。这64级,如果要显示比如灰度为2的色块,就只能用0灰度和4灰度各50%的颜色点来混合形成。
于是,大块的色块就都一样,但是小的色块6bit就不行。
6Bit 则是253的3次方=16194277
8Bit 则是256的3次方=16777216
用6Bit 显示256灰阶,会造成色彩空间 3.5%的loss。
后面在处理屏亮度问题时
&backlight {
compatible = "pwm-backlight";
pwms = <&pwm0 0 5000000 0>;
......
}
把屏的背光pwm调到屏规格推荐的200HZ, 占空比调到最大,屏的亮度还是不够(单纯调试pwm无效)。
后面检查屏的驱动发现 关于6bit 与8bit的配置有问题,要改成8bit