imx8qm LVDS屏 DS90UB9478调试

1.947驱动是根据parade-ps8622.c改编的,电源由于pmic的ldo无法输出1.8v电源,改飞线。

2.改编后发现报错

定位代码位置

vendor\nxp-opensource\kernel_imx\drivers\gpu\drm\imx\nwl_dsi-imx.c

imx_nwl_dsi_bind函数

最终死在

kernel去掉CONFIG_DRM_IMX_NWL_DSI=y能正常启动,但是没有bind bridge,没有以下动作:

DTS如下:

&ldb1 {
	status = "okay";

	lvds-channel@0 {
		fsl,data-mapping = "jeida";
		fsl,data-width = <24>;
		status = "okay";

		port@1 {
			reg = <1>;

			lvds0_out: endpoint {
				remote-endpoint = <&ds90ub947_0_in>;
			};
		};
	};
};

&i2c1_lvds0 {
	#address-cells = <1>;
	#size-cells = <0>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_lvds0_lpi2c1>;
	clock-frequency = <400000>;
	status = "okay";



		lvds-pannel@1a {
		compatible = "ti,ds90ub947";
		reg = <0x1a>;
		#address-cells = <0x1>;
		#size-cells = <0x0>;
		#reset-cells = <0x1>;
		dual-pixel-mode;

		port {
			ds90ub947_0_in: endpoint {
				clock-lanes = <3>;
				data-lanes = <0 1 2 4>;
				remote-endpoint = <&lvds0_out>;
			};
		};
		
		display-timings {

			1920X1080P@60 {
				clock-frequency = <72800000>;
				hactive = <1920>;
				vactive = <1080>;
				hfront-porch = <0>;
				hback-porch = <120>;
				hsync-len = <0>;
				vback-porch = <44>;
				vfront-porch = <0>;
				vsync-len = <0>;
				hsync-active = <1>;
				vsync-active = <0>;
			};
		};
	};

可生成ldb绑定:

imx-drm display-subsystem: bound ldb@562410e0 (ops imx_ldb_ops)

但是通过对比发现frame buffer device生成。

kernel_imx/drivers/gpu/drm/drm_fb_helper.c 下手动添加显示参数信息:

drm_fb_helper_single_fb_probe ->

+       crtc_count =1;

+       sizes.surface_width=1900;

+       sizes.surface_height=1060;

+       sizes.fb_width=1920;

+       sizes.fb_height=1080;

生成frame buffer device,如下:

[    2.250241] Console: switching to colour frame buffer device 240x67

[    2.279556] imx-drm display-subsystem: fb0:  frame buffer device

还是没有输出,发现是0x4F寄存器配置的是双路的lvds屏驱动,顺便把12.3寸屏给调了。

修改DTS如下:

	lvds0_panel {
		compatible = "lvds0_1080p";
	#	dual-pixel-mode;    //LVDS信号pixel-clock为双倍,但是该属性在kernel中找不到了,而且在947中也已经配置好了,实验证明可以去掉。
		
		port@0 {
			ds90ub947_0_in: endpoint {
				remote-endpoint = <&lvds0_out>;
			};
		};
	};
	
	lvds1_panel {
		compatible = "lvds1_720p";
	#	dual-pixel-mode;
		
		port@0 {
			ds90ub947_1_in: endpoint {
				remote-endpoint = <&lvds1_out>;
			};
		};

	};

&ldb1_phy {
	status = "okay";
};

&ldb1 {
	status = "okay";
	fsl,dual-channel;
	
	lvds-channel@0 {
		fsl,data-mapping = "spwg";  //和947配置相对应格式,不然会出现花屏现象
		fsl,data-width = <24>;   
		status = "okay";

		port@1 {
			reg = <1>;

			lvds0_out: endpoint {
				remote-endpoint = <&ds90ub947_0_in>;
			};
		};
	};
};

&ldb2_phy {
	status = "okay";
};

&ldb2 {
	status = "okay"
	fsl,dual-channel;
	lvds-channel@0 {
		fsl,data-mapping = "spwg";//这描述了如何在序列化的LVDS信号中布局颜色位。
		fsl,data-width = <24>;
		status = "okay";

		port@1 {
			reg = <1>;
			lvds1_out: endpoint {
				remote-endpoint = <&ds90ub947_1_in>;
			};
		};
	};
};

there are two LVDS channels(LVDS0 and LVDS1) which can transfer video *    datas, there two channels can be used as split/dual/single/separate mode. * *    split mode means display data from DI0 or DI1 will send to both channels *    LVDS0+LVDS1. *    dual mode means display data from DI0 or DI1 will be duplicated on LVDS0 *    and LVDS1, it said, LVDS0 and LVDS1 has the same content. *    single mode means only work for DI0/DI1->LVDS0 or DI0/DI1->LVDS1. *    separate mode means you can make DI0/DI1->LVDS0 and DI0/DI1->LVDS1 work *    at the same time.

根据如上说明,uboot参数中可以配置ldb的这四种模式,并且在设备树中,对于单通道和双通道也有以下配置: 

split-mode: Provide this bool property if your board uses LDB split 

mode to drive a high resolution display, say 1080P@60. In this 

mode, two LVDS channels will drive one display

(如果您的电路板使用LDB split模式来驱动高分辨率显示器,例如1080P@60,则提供此bool属性

。在这种模式下,两个LVDS通道将驱动一个显示).  -->fsl,dual-channel;

dual-mode: Provide this bool property if your board uses LDB dual 

mode to drive two displays. In this mode, one display engine will 

drive two displays which have the same timings and display content.

如果板使用LDB dual-mode驱动两个显示器,则提供此bool属性。在这种模式下,一个显示引擎将驱动两个具有相同clock和显示内容的显示。

对于大分辨率双通道lvds来说,需要配置设备树中: 

lvds属性split-mode, 

并且clock-frequency为datasheet中DCLK×2 

根据上图,我们lvds采用CH0和CH1双通道,需要配置947的0x4f寄存器为Dual-pixel-mode,则 the

pixel frequency is 2x the OLDI frequency,也就是说pixel clock需要配置成双倍来配合lvds的split mode。

fsl,dual-channel;对应imx-ldb.c如下:

fsl,data-mapping = "spwg"对应VESA格式如下:

HSD156JUW1-A00 Preliminary Specification 2.0 for Customer.pdf

Display-Timming计算:

先了解一下LCD的两种扫描方式:

 对于pannel来说,需要一些时序型号与RGB信号配合显示,时序告知pannel,这些颜色显示在pannel的什么物理位子。这些时序叫做TCON. 根据pannel自带的drive ic。所需要的TCON信号不同。

  DE 模式一般需要:DE和clock信号来确定点。比如一个800x480分辨率的pannel。理论上,在DE有效信号的时候(高或底),就有一个800个clock,来确认行中800个点。每个clock有效的时候,读取一次RGB信号。因为存在(回扫信号)所以DE是个方波,当视频在会扫的时候,DE就拉底。DE一个周期,pannel就扫描一行。扫描480行后,又从第一行扫描开始。(这个规律由pannel的驱动IC所决定的)。

HV模式,需要行同步,和场同步。来表示扫描的行于列。提供多种接口,有利于视频信号的兼容。

DE= data enable

HV = horizontal vertical

两种不同的同步方式,现在的大尺寸一般都是DE同步模式

小尺寸的HV同步模式多.

HV模式扫描介绍:

名称

在数据手册中的简称

中文名

意义

备注

name

No

名字

液晶屏名字(可选)

No

refresh

No

刷新频率

刷新频率(内核中很多例子都赋值为60)

No

xres

No

行宽

每行的像素个数

No

yres

No

屏幕高度

屏幕的行数

No

pixclock

No

像素时钟

每个像素时钟周期的长度,单位是皮秒(10的负12次方分之1秒)

No

left_margin

HBP (Horizontal Back Porch)

水平后沿

在每行或每列的象素数据开始输出时要插入的象

素时钟周期数

No

right_margin

HFP (Horizontal Front Porch )

水平前沿

在每行或每列的象素结束到LCD 行时钟输出脉冲

之间的象素时钟数

No

upper_margin

VBP (Vertical Back Porch)

垂直后沿

在垂直同步周期之后帧开头时的无效行数

No

lower_margin

VFP (Vertical Front Porch)

垂直前沿

本帧数据输出结束到下一帧垂直同步周期开始之

前的无效行数

No

hsync_len

HPW (HSYNC plus width)

行同步脉宽

单位:像素时钟周期

也有手册简称为HWH(HSYNC width)

vsync_len

VPW (VSYNC width)

垂直同步脉宽

单位:显示一行的时间th

也有手册简称为VWH(VSYNC width)

sync

No

同步极性设置

可以根据需要设置FB_SYNC_HOR_HIGH_ACT(水平同步高电平有效)和FB_SYNC_VERT_HIGH_ACT(垂直同步高电平有效)

No

vmode

No

No

在内核中的大多数示例都直接置为FB_VMODE_NONINTERLACED。interlaced的意思是交错[隔行]扫描,电视中使用2:1的交错率, 即每帧分两场,垂直扫描两次,一场扫描奇数行,另一场扫描偶数行。很显然LCD目前不是这种模式。

No

flag

No

No

目前没有看到用法

No

我们先来理解下面引脚有寄存器中相关参数的意义吧

 

外部引脚信号:

VSYNC: 帧同步信号,表示扫描1帧的开始,一帧也就是LCD显示的一个画面。

HSYNC: 行同步信号,表示扫描1行的开始。

VDEN:数据使能信号。

VD[23:0] : LCD像素数据输出端口。

VCLK:像素时钟信号。

 

寄存器参数:

VSPW:帧同步信号的脉宽,单位为1行(Line)的时间。

VFPD: 帧同步信号的前肩,单位为1行(Line)的时间。

VBPD: 帧同步信号的后肩,单位为1行(Line)的时间。

LINEVAL :帧显示尺寸-1,即屏行宽-1,对于800*480分配率的LCD屏,那么LINEVAL=480-1=479,请记住,是屏行宽,也就是LCD屏显示一帧数据所需要的行的数目。

 

HBPD:行同步信号的后肩,单位为1VCLK的时间。

HFPD:行同步信号的前肩,单位为1VCLK的时间。

HSPW:行同步信号的脉宽,单位为1VCLK的时间。

HOZVAL:行显示尺寸-1,即屏列宽-1,对于800*480分配率的LCD屏,那么HOZVAL=800-1=799,请记住,是屏列宽,也就是LCD屏显示一行数据所需要的像素(pixel)的数目。

上图是一帧图像的显示时序图。的上图显示,up_margin = 13-1=12,, yres= 240,

整个场周期为263,所以lower_margin= 263-13-240 = 10

同时看到,列同步信号高电平有效,行同步信号也是高电平有效。

上图是一行的时序图。

可以看到,left_margin = 69, xres = 320, right_margin = 408 -320 - 70 = 18

具体参考:https://blog.csdn.net/a617996505/article/details/82386952#

DE模式扫描:

根据屏的datesheet得出,时序图如下:

可知:

  1. 水平总周期t4 = t5 + t6
  2. 垂直总周期 t1 = t2 + t3
  3. t7为时钟周期,因为是大屏需要双通道驱动,配置947的0x4f寄存器为Dual-pixel-mode,所以pixelclock * 2
  4. DE为高电平有效。(DISPLAY_FLAGS_DE_HIGH)
  5. 该DE,模式没有行同步和场同步,所以都设置为1。
  6. 一行扫描两个像素点,所以hactive=t5 * 2

由上图得出的参数表如下:

匹配到panel-simple.c中去:

static const struct display_timing lvds0_adan_timing = {
        .pixelclock = { 132000000, 145600000, 161000000 },
        .hactive = { 1920, 1920, 1920 },
        .hfront_porch = { 90, 120, 150 },
        .hback_porch = { 1, 1, 1 },
        .hsync_len = { 1, 1, 1 },
        .vactive = { 1080, 1080, 1080 },
        .vfront_porch = { 5, 44, 88 },
        .vback_porch = { 1, 1, 1 },
        .vsync_len = { 1, 1, 1 },
        .flags = DISPLAY_FLAGS_DE_HIGH,
};

static const struct panel_desc lvds0_adan = {
       .timings = &lvds0_adan_timing,
       .num_timings = 1,
       .bpc = 8,
       .size = {
               .width = 158,
               .height = 211,
       },
       .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
};  
     {
       .compatible = "lvds0_1080p",
	   .data = &lvds0_adan ,
     },{

以上bus_format解释一下:

目前LVDS采用的是8bit lvds VESA格式输出。

所以一个cycle是4行,每行有7个数据,一共28个bit,其中RGB888占用24个,DE VS HS --占用4个,所以bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG。

此时lvds基本调完,总结一下:

1.大屏一般都是lvds双通道驱动,扫描模式为DE模式,947需要设置为dual-pixel-mode,时钟频率为双倍驱动。

2.背光

      调试屏幕首先要把背光点亮,没有点亮背光屏幕什么都显示不了,根据规格书将背光点亮,可以寻求硬件工程师帮忙

3.屏幕上星星点点

在调试的时候,我们会发现屏幕上有莫名其妙的星星点点,一般这种情况下,我们首先要看看VGH和VGL电压是否处于datasheet所描述的范围之 内。如果属于标准范围之内,但星星点点依旧,很有可能就是时序问题。这时候不妨在代码中变更采样的时序(比如上升沿采样改为下降沿采样)。如果无法在代码 中更改,也可以在clk信号线加个100R电阻,也可能解决该问题。

3.显示抖动

在确认VPW,VBP,VFP,HPW,HBP,HFP的设置已经符合LCD规格要求后,如果屏幕的显示还在抖动的话,不妨将输出的时钟信号频率降低,有可能解决该问题。                  

还存在一种现象,LVDS的信号线电压高出规格书一点也会出现。曾经有过LVDS信号电压为3.3V的接到5V导致屏幕显示出现细小电波抖动。

4.显示花屏

 出现花屏现象,理论上是RGB没有调好导致的。如颜色位数(24),格式标准(VESA和JEIDA)。

检查一下规格书的颜色格式部分, 是否将RGB888格式设置成了666,或者顺序是RBG,BGR之类的都有可能。

DS90UB9478调试

9478的调试主要有以下几点功能:

1.GPIO的透传功能。

2.普通GPIO功能引脚。

3.中断引脚配置(0xc6固定配置为0x21     0xc7清除中断)

4.i2c和lvds的配置

  1. GPIO的透传功能

GPIO[3:0]都是可以作为透传功能的GPIO,且可以配置方向,如947 GPIO0输入,948 GPIO0输出,则配置为0x0D[947]=0x03,0x1D[948]=0x05。

  1. 普通GPIO功能引脚

以上GPIO_REG[8:5]是仅用于寄存器配置的GPIOs,可以输出进行编程,也可以仅通过本地寄存器位作为输入进行读取。在适用的情况下,如果启用

GPIO_REG模式,这些位与I2S引脚共享,并将覆盖I2S输入。GPIO的启用和配置见表。

注意:本地GPIO值可以通过本地寄存器访问进行配置和读取,也可以通过双向控制通道进行远程寄存器访问。这些引脚的配置和状态不会像GPIO[3:0]那样从串行器传输到解串器

  1. 中断引脚配置

0xc6固定配置成0x21,如果选用947端INTB脚作为中断输出,则需要低电平有效时对0xc7寄存器读一次进行清除中断动作,否则将被一直拉低。

上图可知,选用REM_INTB引脚作为中断,则不需要进行清除中断标志动作。

  1. i2c和lvds的配置

主要由947端配置寄存器0x03 [DA]、0x17 [DE]、0x4f [00],如下:

0X03主要是i2c的透传读写功能打开[bit3],0x17主要配置i2c远端地址读取功能[bit7],0x4f主要配置格式为OpenLDI Mapping。

注意:

Open LVDS Display Interface(OpenLDI) 

LVDS接口电路中,将像素的并行数据转换为串行数据的格式主要有两种标准:VESA和JEIDA,此模式的意思是lvds格式根据arm输出的格式不做改变,直通到948端进行输出,

而SPWG mapping则表示会经过一次转换,如arm端输入VESA格式,则948端是JEIDA格式,会倒转一下。

当然也可以通过硬件改变电阻配置模式:

 如上,可以通过配置R3 R4 R5 R6的阻值来更改模式。

基本也就这几个需要配置的,目前9478的驱动是不需要bind drm_bridge的,就是普通的I2C驱动放在bridge下面就好了。

具体代码如下配置:

947代码:

	err = ds90ub947_write_checkout(ds90ub947, 0x03, 0xDA);

	err = ds90ub947_write_checkout(ds90ub947, 0x17, 0xDE);

	err = ds90ub947_write_checkout(ds90ub947, 0x4F, 0x00); // OpenLDI mapping  Dual-pixel mode.

	err = ds90ub947_write_checkout(ds90ub947, 0xC6, 0x21);  //INI

	err = ds90ub947_write_checkout(ds90ub947, 0x11, 0x03);//GPIO7(TP_RST) 011: GPIO mode, input.

	err = ds90ub947_write_checkout(ds90ub947, 0x10, 0x30); //GPIO6(BL_ENABLE) 011: GPIO mode, input.

	err = ds90ub947_write_checkout(ds90ub947, 0x0E, 0x03); //GPIO1(PWM) 011: GPIO mode, input.

	err = ds90ub947_write_checkout(ds90ub947, 0x0D, 0x03); //GPIO0 (TP_RST) 011: GPIO mode, input.

948代码:

	err = ds90ub948_write_checkout(ds90ub948, 0x20, 0x90);	//BL_ENABLE GPIO6
	
	err = ds90ub948_write_checkout(ds90ub948, 0x1E, 0x95);

	err = ds90ub948_write_checkout(ds90ub948, 0x60, 0x40);   //GPIO output=3.3v
	
	err = ds90ub948_write_checkout(ds90ub948, 0x1D, 0x05);  //TP_RST(GPIO0) 101: Remote GPIO Control,  GPIO mode; output.
	
	err = ds90ub948_write_checkout(ds90ub948, 0x1D, 0x05);  //TP_RST(GPIO0) 101: Remote GPIO Control,  GPIO mode; output.

	err = ds90ub948_write_checkout(ds90ub948, 0x1D, 0x05);  //TP_RST(GPIO0) 101: Remote GPIO Control,  GPIO mode; output.

	err = ds90ub948_write_checkout(ds90ub948, 0x1F, 0x09);  //LCD0_STBY(GPIO3) default:high
	
	msleep(380);
	
	err = ds90ub948_write_checkout(ds90ub948, 0x1E, 0x95);  //PWM(GPIO1) TP_EN(GPIO2)
	
	err = ds90ub948_write_checkout(ds90ub948, 0x1E, 0x95);  //PWM(GPIO1) TP_EN(GPIO2)
	
	err = ds90ub948_write_checkout(ds90ub948, 0x1E, 0x95);  //PWM(GPIO1) TP_EN(GPIO2)

程序流程:

* panel_simple_init(void)

  * err = platform_driver_register(&panel_simple_platform_driver);

    * __platform_driver_register(drv, THIS_MODULE)

     * drv->driver.bus = &platform_bus_type;

       * struct bus_type platform_bus_type

        * .match = platform_match

          * if (of_driver_match_device(dev, drv))

           * return of_match_device(drv->of_match_table, dev) != NULL;

             * return of_match_node(matches, dev->of_node);

              * match = __of_match_node(matches, node);

                * score = __of_device_is_compatible(node, matches->compatible, matches->type, matches->name);

                 * if (of_compat_cmp(cp, compat, strlen(compat)) == 0)



* /drivers/gpu/drm/imx/imx-drm-core.c

  * module_platform_driver(imx_drm_pdrv);

    * .probe = imx_drm_platform_probe,

     * static int imx_drm_platform_probe(struct platform_device *pdev)

       * ret = drm_of_component_probe_with_match(&pdev->dev, match, compare_of, &imx_drm_ops);

        * .bind = imx_drm_bind,

          * ret = component_bind_all(dev, drm);

           * ret = component_bind(c, master, data);

             * imx_ldb_bind

              * drm_of_find_panel_or_bridge

          * imxdrm->fbhelper = drm_fbdev_cma_init(drm, legacyfb_depth, MAX_CRTC);

           * return drm_fbdev_cma_init_with_funcs(dev, preferred_bpp, max_conn_count, &drm_fb_cma_funcs);

             * ret = drm_fb_helper_initial_config(helper, preferred_bpp);

              * ret = __drm_fb_helper_initial_config_and_unlock(fb_helper, bpp_sel);

                * ret = register_framebuffer(info);

947pclk频率要求:

 

  • 10
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值