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屏幕常用于安卓平台,有些还直接用单片机驱动,故厂家给出的序列极少会是直接满足要求的,都需要进行一定的改写。

    现举例说明改写方式。一般厂家给出的文档可能是这样的:

RK3399 Linux-SDK mipi屏幕驱动及调试_第1张图片

    不同厂家提供的文档写法可能有些不同,不过基本还是相通的.

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 改写举例

    以上图作为依据,分别将三种类型的写法做个举例:

    一、多个数据情况

RK3399 Linux-SDK mipi屏幕驱动及调试_第2张图片

    上图中红框,按数个数方式可确定有四个数据,需要用39指令。本次发送无延时,故延时数量为0.数据长度为4.数据内容为FF 98 81 00.改写后结果为:

39 00 04 FF 98 81 00

    二、两个数据情况(带延时)

RK3399 Linux-SDK mipi屏幕驱动及调试_第3张图片

    上图中红框,按数个数方式可确定有两个数据,需要用15指令。本次发送延时为1.数据长度为2.改写后结果为:

15 01 02 3A 77

    三、单个数据情况

RK3399 Linux-SDK mipi屏幕驱动及调试_第4张图片

    上图中红框,按数个数方式可确定有一个数据,需要用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 = ;

		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的延时。之后就再没出现过灰屏问题了。

 

你可能感兴趣的:(RK3399)