基于RK3288的Linux驱动开发 -- LVDS驱动调试

文章目录

  • 概述
  • 核心概念
      • 视觉输出处理器vop(Visual Output Processor)
      • 视频信号传输接口LVDS(Low-Voltage Differential Signaling)
      • 显示面板Panel
      • 显示时序
  • 内核DTS修改

概述

平台:RK3288
板型:Firefly-RK3288
Host:Ubuntu 16.04
LCD:BP101WX1-206
Firefly Linux SDK:具体参考Firefly-RK3288维基教程
由于Firefly-RK3288这块板默认没有开启LVDS输出,所以编写了这份文档,记录LVDS屏幕如何驱动。

核心概念

视觉输出处理器vop(Visual Output Processor)

基于RK3288的Linux驱动开发 -- LVDS驱动调试_第1张图片
vop是一个把frame buffer数据传输到指定显示设备(RGB LCD Panel,LVDS,MIPI,eDPHDMI等)的接口,它还包含了显示处理和图层处理等功能,传统意义上就是一个显示控制器(Display Controller)。rk3288内部有两个vop单元,分别是vopbvopl。具体可参考《rk3288-chapter-27-visual-output-processor-(vop)

视频信号传输接口LVDS(Low-Voltage Differential Signaling)

基于RK3288的Linux驱动开发 -- LVDS驱动调试_第2张图片
LVDS接口把vop输出的CMOS信号为低压差分信号,以此减少噪声对视频信号的干扰,同时减少了线路数量,RGB接口的线路比LVDS要多很多。具体参考《rk3288-chapter-33-lvds》。

显示面板Panel

主要用来把RGB信号转为视觉画面展示出来。

显示时序

有几个重要参数必须要了解的,这些参数都可以在显示屏的datasheet里面找到。

名称 解释 缩写 单位
Clock Frequency 像素时钟 cf hz
Horizontal Back Porch 水平后肩,水平同步信号之后的时延 hbp clk
Horizontal Front Porch 水平前肩,水平同步信号之前的时延 hfp clk
Horizontal Pulse Width 水平同步信号的长度 hsync clk
Vertical Back Porch 垂直后肩,垂直同步信号之后的时延 vbp line
Vertical Front Porch 垂直前肩,垂直同步信号之前的时延 vfp line
Vertical Pulse Width 垂直同步信号长度 vsync line

基于RK3288的Linux驱动开发 -- LVDS驱动调试_第3张图片
这里clk = 1 / cf,line =(hbp + hfp + hsync)* clk,假如显示屏的像素时钟规定为65000000hz,则clk = 1 / 65000000s(具体我就不算了)。

内核DTS修改

1、屏幕datasheet第32页显示的关键参数
基于RK3288的Linux驱动开发 -- LVDS驱动调试_第4张图片
从屏幕datasheet可知道
Main clock = clock-frequency = 65000000hz
Hor Blanking = hbp + hfb + hsync = 50
H Sync Pulse Width = hsync = 32
H Sync Offset = hbp = 10
所以 hfp = 50 - 32 - 10 = 8
Ver Blanking = vbp + vfp + vsync = 12
V Sync Pulse Width = vsync = 6
V Sync Offset = vbp = 3
所以vfp = 12 - 6 - 3 = 3
2、屏幕datasheet第20页显示的时序图
基于RK3288的Linux驱动开发 -- LVDS驱动调试_第5张图片
基于RK3288的Linux驱动开发 -- LVDS驱动调试_第6张图片
可知道在DCLK(这里就是我指的cf)下降沿采集数据,DE为高电平时数据有效。而hsync和vsync都是低电平触发。

3、进入arch/arm/boot/dts,修改rk3288-firefly.dts

cd arch/arm/boot/dts/
vi rk3288-firefly.dts

4、增加使用LVDS相关节点

#include  // 需要增加这个头文件
......
&route_hdmi {
	status = "okay";
};

&route_lvds { // 使能lvds路由,使显示子系统的数据能够经过vopl传输到lvds
	status = "okay";
};

......

&lvds_in_vopb { // 我们屏幕是1280x800使用vopl输入即可,所以关闭vopb的输入
	status = "disabled";
};

&lvds { // 使能lvds接口
	status = "okay";
};

&lvds_panel {
	status = "okay";
	compatible ="simple-panel"; // 使用4.x内核的simple panel框架
	// power-supply = <&vcc_lcd>; // 因为屏幕不使用gpio供电,所以注释掉
	// backlight = <&backlight>; // 因为屏幕不使用背光调节,所以注释掉
	bus-format = <MEDIA_BUS_FMT_RBG888_1X24>; // RGB888
	enable-delay-ms = <10>;
	rockchip,data-mapping = "vesa"; // lvds数据格式
	rockchip,data-width = <24>; // 24位
	rockchip,output = "lvds"; // lvds接口输出

	display-timings {
		native-mode = <&timing0>;
		timing0: timing0 {
			clock-frequency = <65000000>; // 参考第1点
			hactive = <1280>; // 这里填分辨率即可
			vactive = <800>;
			hback-porch = <10>; // 参考第1点
			hfront-porch = <8>; // 参考第1点
			vback-porch = <3>; // 参考第1点
			vfront-porch = <3>; // 参考第1点
			hsync-len = <32>; // 参考第1点
			vsync-len = <6>; // 参考第1点
			hsync-active = <0>; // 参考第2点
			vsync-active = <0>; // 参考第2点
			de-active = <1>; // 参考第2点
			pixelclk-active = <0>; // 参考第2点
		};
	};
};

5、相关dts节点查看
文件rk3288-linux.dtsi

	display-subsystem {
		status = "okay";

		ports = <&vopb_out>, <&vopl_out>;
		logo-memory-region = <&drm_logo>;

		route {
			route_hdmi: route-hdmi {
				status = "disabled";
				logo,uboot = "logo.bmp";
				logo,kernel = "logo_kernel.bmp";
				logo,mode = "center";
				charge_logo,mode = "center";
				connect = <&vopb_out_hdmi>;
			};

			route_edp: route-edp {
				status = "disabled";
				logo,uboot = "logo.bmp";
				logo,kernel = "logo_kernel.bmp";
				logo,mode = "center";
				charge_logo,mode = "center";
				connect = <&vopl_out_edp>;
			};

			route_dsi0: route-dsi0 {
				status = "disabled";
				logo,uboot = "logo.bmp";
				logo,kernel = "logo_kernel.bmp";
				logo,mode = "center";
				charge_logo,mode = "center";
				connect = <&vopl_out_dsi0>;
			};

			route_lvds: route-lvds {
				status = "disabled";
				logo,uboot = "logo.bmp";
				logo,kernel = "logo_kernel.bmp";
				logo,mode = "center";
				charge_logo,mode = "center";
				connect = <&vopl_out_lvds>; // 这里连接到vopl输出lvds的链路
			};
		};

文件rk3288.dtsi

	vopl: vop@ff940000 {
		compatible = "rockchip,rk3288-vop-lit";
		rockchip,grf = <&grf>;
		reg = <0x0 0xff940000 0x0 0x19c>, <0x0 0xff941000 0x0 0x1000>;
		reg-names = "regs", "gamma_lut";
		interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
		clocks = <&cru ACLK_VOP1>, <&cru DCLK_VOP1>, <&cru HCLK_VOP1>;
		clock-names = "aclk_vop", "dclk_vop", "hclk_vop";
		power-domains = <&power RK3288_PD_VIO>;
		resets = <&cru SRST_LCDC1_AXI>, <&cru SRST_LCDC1_AHB>, <&cru SRST_LCDC1_DCLK>;
		reset-names = "axi", "ahb", "dclk";
		iommus = <&vopl_mmu>;
		status = "disabled";

		vopl_out: port {
			#address-cells = <1>;
			#size-cells = <0>;

			vopl_out_hdmi: endpoint@0 {
				reg = <0>;
				remote-endpoint = <&hdmi_in_vopl>;
			};

			vopl_out_edp: endpoint@1 {
				reg = <1>;
				remote-endpoint = <&edp_in_vopl>;
			};

			vopl_out_dsi0: endpoint@2 {
				reg = <2>;
				remote-endpoint = <&dsi0_in_vopl>;
			};

			vopl_out_lvds: endpoint@3 { // 端点3
				reg = <3>;
				remote-endpoint = <&lvds_in_vopl>; // 连接到lvds的输入端 
			};

			vopl_out_dsi1: endpoint@4 {
				reg = <4>;
				remote-endpoint = <&dsi1_in_vopl>;
			};
		};
	};

	lvds: lvds@ff96c000 {
		compatible = "rockchip,rk3288-lvds";
		reg = <0x0 0xff96c000 0x0 0x4000>;
		clocks = <&cru PCLK_LVDS_PHY>;
		clock-names = "pclk_lvds";
		power-domains = <&power RK3288_PD_VIO>;
		rockchip,grf = <&grf>;
		status = "disabled";

		ports {
			#address-cells = <1>;
			#size-cells = <0>;

			lvds_in: port@0 { // 两个端点
				reg = <0>;

				#address-cells = <1>;
				#size-cells = <0>;

				lvds_in_vopb: endpoint@0 { // 连接到vopb的输出端
					reg = <0>;
					remote-endpoint = <&vopb_out_lvds>;
				};
				lvds_in_vopl: endpoint@1 { // 连接到vopl的输出端
					reg = <1>;
					remote-endpoint = <&vopl_out_lvds>;
				};
			};
		};

你可能感兴趣的:(Linux驱动开发)