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頻率要求:

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章