rv1126/1109平台下的lt8912显示驱动的调试

lt8912显示驱动调试的注意事项

前言

使用的瑞芯微的rv1109的平台,显示接口为MIPI,需要外接LVDS的显示屏,同时外接HDMI显示屏显示。

硬件调试

硬件调试注意事项如下:

  • 检查原理图,确保原理图正确。
  • 检查接口的电平匹配问题,LT8912 io最大支持1.8V,注意电平转换问题(IIC,REST脚)。
  • 检查晶振是否振。
  • IIC不要强上拉,否则会导致IIC通信异常,我在调试时就遇到这个问题。
  • 实际调试中发现接了lt8912的芯片rest脚后,rv1109 对应的gpio 输出低电平时,从波形上看无法到0v的位置,波形比较奇特。但只要符合手册的要求,不显示实际功能。判断rest是否生效,看IIC通信是否正常。
  • 注意这是高速信号,PCB布版时有严格的要求(mipi信号的调试不能飞线进行调试),板的信号问题会影响后续的调试。

强烈建议使用4层板设计,并且注意差分对的阻抗匹配100Ω±10%,差分对间,差分对组间需要做等长。

软件调试

LT8912的配置

  • 首先确认硬件电平是否正确, 查看REST脚是否按时序要求进行操作,手册上要求是拉低10ms再拉高,实际调试中,就用上电复位也是可以工作的。
    rv1126/1109平台下的lt8912显示驱动的调试_第1张图片

  • 参考官方代码进行配置,配置很多,就不贴出来了,后面会讲注意事项和如何调试。

  • 代码写好后,在确保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。显示效果如下图所示

rv1126/1109平台下的lt8912显示驱动的调试_第2张图片

lt8912参数可能需要修改的地方

因为电路和屏的参数不一样,有些参数按照官方的配置并不能正确工作,需要做一些调整

  • 检查点1,MIPI 信号的PN看是否需要反接
#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
  • 检查点2,设置lane的数量,rv1109 MIPI_Lane 为4
lt8912b_write_byte( lt8912b_I2C_S_ADDR,0x13, MIPI_Lane % 4 );      // 4 lane  // 01 lane // 02 2 lane //03 3lane
  • 检查点3,mipi 的数据通道是否反接,一般硬件不会所接
lt8912b_write_byte( lt8912b_I2C_S_ADDR,0x15, MIPI_Lane_CH_Swap );  // 00: 0123 normal ; a8 : 3210 swap
  • 检查点4,检查一下屏的多少位的
#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 供大家参考
rv1126/1109平台下的lt8912显示驱动的调试_第3张图片16.2M 是6 bit color ,如果是16.7 M 则是8 bit_color . 关于位数问题,后面有补充。

  • 检查点5 ,查看lt8912的屏的时序配置
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
};

信号源MIPI的设置

  • 接下来设置mipi信号 ,test pattern 模式能正常显示并不能说明mipi信号是正确的,因为测试模式没有使用mipi信号做为输入源。
    rv1109 的mipi驱动不用做修改,仅调整一下设备树就可以了,设备树的改法如下所示
&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;
}

屏的参数如下所示,对应timing0
rv1126/1109平台下的lt8912显示驱动的调试_第4张图片

时序波形分析

  • mipi 的clk信号幅度问题
    rv1126/1109平台下的lt8912显示驱动的调试_第5张图片这个幅值是正确的,注意,因为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>;
			};
		};

rv1126/1109平台下的lt8912显示驱动的调试_第6张图片

遇到的问题

  • 读lt8912寄存器 0x9c ~ 0x9f 读到的值都是ff ff 00 00

确保MIPI信号已经给到LT8912B之后,再读video check的寄存器。
连续多次读video check寄存器,正常情况下,每次读到的值都是相同的,如果MIPI信号接收不稳定,则读到的值会变化。

  • 读lt8912寄存器 0x0c ~ 0x0f

读(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。

  • 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
rv1126/1109平台下的lt8912显示驱动的调试_第7张图片说明已经关闭了。
eopt的信号见下图
rv1126/1109平台下的lt8912显示驱动的调试_第8张图片这里会出现交互变化的过程,如果一直是高,或者一直是低,则表示eopt 没有关闭,注意高低变化不是按顺序出现,可能相邻的都是高,后面才变低。

  • 每个采样周期里面不能出现2个LP
    rv1126/1109平台下的lt8912显示驱动的调试_第9张图片上图这种波形是错误的,需要修改dsi,flags 的配置

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

rv1126/1109平台下的lt8912显示驱动的调试_第10张图片见 6+2bit color depth 这一行信息,修改后屏的显示亮度变亮。

你可能感兴趣的:(linux驱动,嵌入式硬件,linux,arm开发)