RK3399 Linux-SDK mipi屏幕驅動及調試

一,流程及通路

    我接觸到的三款mipi屏幕,基本的點亮流程都是很一致的,就是背光使能-背光點亮-屏幕使能-reset引腳按指定時序/波形拉高或拉低-初始化序列命令發送。

    3399的linuxSDK中,包含一種類似通用的屏幕驅動。本文檔以使用此驅動爲前提,不包含原理內容(硬件基礎實在太差,原理自己也沒有搞很通),只描述如何儘快的完成屏幕配置並最終將屏幕點亮。給自己留一個記錄,也希望其中的內容能對剛上手的朋友們有一點幫助。

    流程上分爲以下幾步:

(1)需要預先向屏幕廠商討要一些屏幕關鍵參數及資料。

(2)進行關鍵引腳對應

(3)進行DTS配置

(4)固件編譯,燒寫調試

    文檔會按順序說明以上幾步的關鍵位置及步驟。

二,參數及配置

2.1 關鍵引腳對應

    按上述流程說明,我們需要對應以下幾個引腳:

    1.屏幕使能;2.屏幕reset;3.背光使能;4.背光pwm

    需要根據核心板原理圖,底板原理圖(如果存在轉接板還要看轉接板部分的原理圖),屏幕接線端接線的原理圖三個確定內核中引腳的對應。

    按3399來講,一般是有4個GPIO分組。常見的原理圖寫法,應該是類似GPIO4_D5這種寫法。各個引腳完成對應後記錄好名稱,需要配置到DTS中,下面文檔會提到DTS中引腳的改寫方式。

2.2 向屏幕廠商討要一些屏幕關鍵參數及資料

    主要包括初始化序列,display off序列,reset波形,timing參數

    其實除去序列外,波形及timing參數都可以通過屏幕的spec或datasheet文件中讀取,如需要磨練此部分的個人技能,可以嘗試進行自己的對應。不過由於我硬件基礎差,文檔多數是英文且含有較多專業次會,時序和參數對應學習成本也比較高,這部分屏幕廠商應該會有的。討要一下會減少很多的時間花費,也會更準確一點。

 

 

2.3 屏幕初始化序列/display off序列及Linux平臺改寫

    屏幕在點亮後會涉及到初始化序列發送,這部分序列廠家會提供。不過一般由於mipi屏幕常用於安卓平臺,有些還直接用單片機驅動,故廠家給出的序列極少會是直接滿足要求的,都需要進行一定的改寫。

    現舉例說明改寫方式。一般廠家給出的文檔可能是這樣的:

    不同廠家提供的文檔寫法可能有些不同,不過基本還是相通的.

2.3.1 改寫方法/公式

    以圖中內容來講,有三種指令:GP_COMMAND_PA,SPI_WriteData,Delay。Delay很好理解,延時嘛,一般輸入的參數就是延時數量,延時單位一般是毫秒(ms).另兩種其實不用區別,只需要掌握以下方式:

    1.數個數;以GP_COMMAND_PA爲開始,下一個GP_COMMAND_PA(不包含這次的GP_COMMAND_PA和Delay)爲結束作爲一次數據發送,數一共有幾個數據。

    2.看延時。看是否存在延時。

    改寫格式上是這樣的:

    命令類型+延時數量+數據長度+數據

    命令類型根據上文提到的數個數來確定,只講三種:一個數據,兩個數據,多於兩個數據

    如果只有一個數據,對應的命令類型是0x05;如果有兩個數據,對應的命令類型是0x15;如果多於兩個數據,對應的命令類型是0x39.

    延時數量就是根據代碼中的延時,轉換爲16進制就好。

    數據長度,就是數個數的結果,不改寫前一次數據發送有幾個數據,轉換爲16進制填入此位置。

    數據就是把函數中除延時外的內容按從上到下順序接在後面就好。注意全部數據爲16進制,0x要求省略。

2.3.2 改寫舉例

    以上圖作爲依據,分別將三種類型的寫法做個舉例:

    一、多個數據情況

    上圖中紅框,按數個數方式可確定有四個數據,需要用39指令。本次發送無延時,故延時數量爲0.數據長度爲4.數據內容爲FF 98 81 00.改寫後結果爲:

39 00 04 FF 98 81 00

    二、兩個數據情況(帶延時)

    上圖中紅框,按數個數方式可確定有兩個數據,需要用15指令。本次發送延時爲1.數據長度爲2.改寫後結果爲:

15 01 02 3A 77

    三、單個數據情況

    上圖中紅框,按數個數方式可確定有一個數據,需要用05指令。本次發送延時爲200.數據長度爲1.改寫後結果爲:

05 C8 01 11

    全部數據按順序改寫完成後,先保存在一個文件中,後續配置DTS時會使用到。

2.4 DTS配置

    這一部分是重點,全部之前的工作全爲此處進行準備。

    首先,進行DTS文件對應。dts文件存於 sdk目錄/kernel/arch/arm64/boot/dts/rockchip/ 中。由於瑞芯微平臺提供兩種編譯內核的方式,故請在對應前確認到底使用的是哪一個DTS文件。

    DTS寫法這裏不贅述(主要我還沒有對寫法全通),主要描述需要添加的內容和具體放置位置。

    共需要以下幾個重點內容:dsi,route_dsi,backlight,vcc_lcd,dsi_in_vopb,dsi_in_vopl,vopb。

    另注意,由於DTS文件設計到層層包含(DTS文件可以包含後綴爲.dtsi的文件,作用就像C語言中的.h文件),故建議重要配置及板卡特性配置寫到最後一級的DTS文件中,防止由於在較高層級的dtsi配置後手誤在後面又進行了配置,導致配置被錯誤覆蓋。

2.4.1 dsi

    dsi部分的內容較多,只說明重點內容:

backlight = <&backlight>;
power-supply = <&vcc_lcd>;
enable-gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>; 
reset-gpios = <&gpio4 29 GPIO_ACTIVE_HIGH>;

    enable-gpios表示屏幕使能引腳,要求拉高,GPIO_ACTIVE_HIGH意爲拉高。reset-gpios表示屏幕reset引腳,具體拉高拉低,要根據內核配置和時序要求來進行對應修改。

    說明以下引腳對應,以reset引腳來舉例。對應芯片引腳爲GPIO4_D5。寫法上如上述寫法,引腳分組寫爲&gpio4,對應引腳的GPIO4。D5的數字是這麼對應的。一般每個引腳分組再細分爲ABCD四組,按順序對應數字0,1,2,3.D5對應的數字方式,是字母對應數字乘以8再加上字母后數字,D5的話就是3*8+5=29.

reset-delay-ms = <1>;
disable-delay-ms = <10>;
init-delay-ms = <10>;
enable-delay-ms = <20>;	
prepare-delay-ms = <10>;
unprepare-delay-ms = <10>;
dsi,lanes = <4>; 
status = "okay";

    上述配置中有一些延時,我暫時瞭解到的相對重要的是reset-delay-ms和init-delay-ms。reset-delay-ms是在屏幕初始化過程中,第一次操作reset引腳之前的延時。init-delay-ms,是在屏幕初始化過程中,第一次操作reset引腳之後的延時。如有特殊的reset時序要求,可分別在uboot和kernel中進行修改,具體代碼分別爲:

uboot:
u-boot\drivers\video\drm\rockchip_panel.c 
修改時序:panel_simple_prepare

kernel:
kernel\drivers\gpu\drm\panel\panel-simple.c
修改時序:panel_simple_prepare

    需注意,reset引腳時序配置,如DTS中route_dsi開啓,則無特殊情況開機過程kernel部分的reset引腳控制不調用,kernel部分的reset引腳配置,只在屏幕出現休眠喚醒時使用。

dsi,lanes = <4>;

    dsi,lanes = <4>;是配置當前mipi是幾通道的,需根據屏幕實際情況配置。

panel-init-sequence = [];

    panel-init-sequence填寫剛剛改寫好的初始化序列。

panel-exit-sequence

    panel-exit-sequence填寫display off序列,一般爲兩條,也需要廠家提供。

disp_timings: display-timings {
	native-mode = <&timing0>;

	timing0: timing0 {
		clock-frequency = <59000000>;
		hactive = <720>;
		vactive = <1280>;
		hback-porch = <40>;
		hfront-porch = <60>;
		vback-porch = <32>;
		vfront-porch = <28>;
		hsync-len = <8>;
		vsync-len = <6>;
		hsync-active = <0>;
		vsync-active = <0>;
		de-active = <0>;
		pixelclk-active = <1>;
	};
};

    這一部分也很重要,是屏幕的一些參數。hactive和vactive就是水平數值的像素,也就是屏幕分辨率了。

    hback-porch,hfront-porch,vback-porch,vfront-porch按順序簡寫爲HBP,HFP,VBP,VFP,這個跟廠家討要後,根據簡寫字母對應即 可。

    hsync-len,vsync-len也請與廠家溝通確定

    clock-frequency 像素時鐘頻率,廠家如不給出,可以通過公式計算出。公式爲:

像素時鐘頻率 = (hactive+hbp+hfp+hsync-len)x (vactive+vbp+vfp+vsync-len)xfps

    然後保留兩位有效數字(不要四捨五入),後面數據直接填0即可。

    最後附上整體的dsi配置,供參考。

&dsi {
	status = "okay";
	dsi_panel: panel {
		compatible ="simple-panel-dsi";
		reg = <0>;
		backlight = <&backlight>;
		//power-supply = <&vcc_lcd>;

		enable-gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>; 
		reset-gpios = <&gpio4 29 GPIO_ACTIVE_HIGH>;//此處我自己改了內核驅動代碼
                                                   //做了特殊時序
                                                   //不建議參考,通常配置爲GPIO_ACTIVE_LOW
		
		dsi,flags = <(MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
				MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_EOT_PACKET)>;
		dsi,format = <MIPI_DSI_FMT_RGB888>;

		reset-delay-ms = <1>;
		disable-delay-ms = <10>;
		init-delay-ms = <10>;
		enable-delay-ms = <20>;	
		prepare-delay-ms = <10>;
		unprepare-delay-ms = <10>;
		dsi,lanes = <4>; 
		status = "okay";

		panel-init-sequence = [
			39 00 04 FF 98 81 03
			15 00 02 01 00
			15 00 02 02 00
			15 00 02 03 72
			15 00 02 04 00
			15 00 02 05 00
			... ... ... ... //這部分內容太多了,每個屏幕都有不同,全部省略方便查看
			05 C8 01 11
			05 C8 01 29
		];

		panel-exit-sequence = [
			05 14 01 28
			05 78 01 10
		];

		disp_timings: display-timings {
			native-mode = <&timing0>;

			timing0: timing0 {
				clock-frequency = <59000000>;
				hactive = <720>;
				vactive = <1280>;
				hback-porch = <40>;
				hfront-porch = <60>;
				vback-porch = <32>;
				vfront-porch = <28>;
				hsync-len = <8>;
				vsync-len = <6>;
				hsync-active = <0>;
				vsync-active = <0>;
				de-active = <0>;
				pixelclk-active = <0>;
			};
		};
	};
};

2.4.2 backlight

    根據翻譯,此處爲背光配置。

&backlight {
	status = "okay";
	pwms = <&pwm1 0 25000 0>;
 	enable-gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>;
};

    注意,pwms要與芯片引腳對應,確認具體是哪一組;enable-gpios表示使能引腳,使能引腳如硬件級別保證了拉高,就可以不進行配置了。另注意,使能與PWM是兩個引腳,使能引腳千萬不要配置錯誤,如錯誤會導致異常的系統內核循環,無法正常啓動系統。

    另,需注意對應的pwm在DTS中是否已啓用。

    啓用寫法如下:

&pwm1 {
	status = "okay";
};

2.4.3 route_dsi

    這個配置,作用是是否經由mipi接口在uboot和kernel階段顯示過度圖片(圖片可更換)。開啓此配置的方式爲:

&route_dsi{
	status = "okay";
};

    這個配置的生效,還仰仗uboot階段使用kernel的dtb。uboot開啓使用kernel的dtb功能的配置相對簡單,只需在使用的config文件中添加CONFIG_USING_KERNEL_DTB=y即可。(注意此配置有一項項配置依賴,OF_LIVE).

    其實此項配置還與mipi的驅動鏈路相關。理論上就我現有了解,HOST鏈接爲VOP->MIPI-DSI->Panel,VOP在kernel中分爲vopb和vopl,route_dsi這個配置在rk3399.dtsi中配置了一個connect,也就是鏈接到哪一個vop,之後也會講到將DSI具體配置到哪個鏈路中。要求此項配置中connect選擇的vop與實際配置的vop要一致,才能打通這個通路。

    如配置爲vopb,配置方式爲在此配置中添加connect = <&vopb_out_dsi>;

2.4.4 dsi通路

    通路問題在上一節有講到,假定我們將dsi配置到vopb中,則共需要進行dsi_in_vopl,vopb,dsi_in_vopb這三項的配置。

    首先,vopb要打開:

&vopb {
	status = "okay";
};

    其次,dsi_in_vopl要關閉

&dsi_in_vopl{
	status = "disabled";
};

    最後,dsi_in_vopb要打開

&dsi_in_vopb{
	status = "okay";
};

    以上全部完成修改,通路就已經配置完畢了。剩餘其他基本在dts文件中都有默認配置

三、調試

    說明一些調試內容。

    內容上如完成以上配置,屏幕應是成功點亮的。背光不亮,有可能是該組pwm沒有使能;如使能無背光,檢查以下enable引腳及pwm引腳配置。如以上全都正確,多數是硬件問題了(pwm是獨立於屏幕配置之外的,故只要將該組pwm使能,背光上電就會亮,無論是否有uboot部分的配置及啓用)。

    之後如屏幕無法點亮,可以跟進內核查看uboot部分及kernel部分打印,查看錯誤原因。

    建議開啓uboot階段的顯示,能屏蔽系統問題直接去定位驅動及配置問題。

    如參數配置後屏幕背光亮但無顯示,可能是驅動鏈路問題,需要進行dsi的鏈路檢查,重點查看route_dsi的初始配置鏈路,和2.4.4 dsi通路對應內容。

    如鏈路正確,驅動正確且內核顯示已綁定,仍有背光無顯示,可以查看一下reset引腳配置是否正確,如正確,抓取以下啓動時的波形,看是否reset波形時間上有問題。

    類似花屏等的問題,可以參考相對有經驗的大神博客:https://me.csdn.net/Shushan1,個人受益匪淺。

    另調試過程中出現過一種奇怪現象,如啓動uboot顯示logo,保持系統級別默認屏幕顯示方向,屏幕初始化只在uboot階段進行,內核階段不進行。如進行默認屏幕顯示方向翻轉後,內核運行的最後,會重新初始化一遍屏幕(官方請教後好像是一種休眠喚醒)。這種情況下屏幕會短暫的滅-亮,之後顯示系統界面。

    奇怪在哪兒呢,奇怪在內核進行屏幕初始化後,屏幕有機率灰屏。現象上灰屏時內核無其他錯誤打印,但滅-亮的時間會短很多。個人由於不通原理,考慮到有可能是系統界面顯示較快與屏幕初始化有衝突,在發送完初始化序列後,內核代碼中再添加固定50ms的延時。之後就再沒出現過灰屏問題了。

 

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