RK3568 DRM显示框架

一.简介

显示子系统是 Rockchip 平台显示输出相关软硬件系统的统称,它包括 VOP(比较老的平台叫 LCDC,比如 RK3188、RK3066)和 RGB、BT1120、BT656、I8080(MCU 显示接口),LVDS、MIPI DSI、EDP、DP、HDMI 等显示信号输 出模块以及与之对应的软件驱动。

RK3568 DRM显示框架_第1张图片

从上面的 DSS 框图可以看到,在整个显示通路的最后端,是由 RGA,GPU、VPU 组成的显示图形加速模块,他们是专 门针对图像处理优化设计的硬件 IP,能够高效的进行图像的生成和进一步处理(比如 GPU 通过 opengl 功能提供图像 渲染功能,RGA 可以对图像数据进行缩放,旋转,合成等 2D 处理,VPU 可以高效的进行视频解码),从而减轻 CPU

负担。 经过这些图像加速模块处理后的数据会存放在 DDR 中,然后由 VOP 读取,根据应用需求进行 Alpha 叠加,颜色空间 转换,gamma 矫正,HDR 转换 等处理后,再发送到对应的显示接口模块(HDMI/DP/DSI/RGB/LVDS), 这些接口模 块会把接收到的数据转换成符合各自协议的数据流,发送到显示器或者屏幕上,呈现在最终用户眼前。

二.DRM 驱动和 libdrm 的交互过程

RK3568 DRM显示框架_第2张图片

三.DRM显示框架的DTS配置

在一颗 SOC 上,可能有多个 VOP,HDMI,eDP,DP,MIPI,Panel 模块,根据具体产品定义,一款产品可能只需要 使用到其中一部分模块来组成显示通路。具体使用哪些模块,以及这些模块之间如何衔接则通过 dts 配置。

display_subsystem: display-subsystem {
		compatible = "rockchip,display-subsystem";
		ports = <&vop_out>;

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

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

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

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

			route_edp1: route-edp1 {
				status = "disabled";
				logo,uboot = "logo.bmp";
				logo,kernel = "logo_kernel.bmp";
				logo,mode = "center";
				charge_logo,mode = "center";
			};

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

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

VOP: 

vop: vop@fdd90000 {
		compatible = "rockchip,rk3588-vop";
		reg = <0x0 0xfdd90000 0x0 0x4200>, <0x0 0xfdd95000 0x0 0x1000>;
		reg-names = "regs", "gamma_lut";
		interrupts = ;
		clocks = <&cru ACLK_VOP>,
			 <&cru HCLK_VOP>,
			 <&cru DCLK_VOP0>,
			 <&cru DCLK_VOP1>,
			 <&cru DCLK_VOP2>,
			 <&cru DCLK_VOP3>,
			 <&cru PCLK_VOP_ROOT>,
			 <&cru DCLK_VOP0_SRC>,
			 <&cru DCLK_VOP1_SRC>,
			 <&cru DCLK_VOP2_SRC>;
		clock-names = "aclk_vop",
			      "hclk_vop",
			      "dclk_vp0",
			      "dclk_vp1",
			      "dclk_vp2",
			      "dclk_vp3",
			      "pclk_vop",
			      "dclk_src_vp0",
			      "dclk_src_vp1",
			      "dclk_src_vp2";
		assigned-clocks = <&cru ACLK_VOP>;
		assigned-clock-rates = <500000000>;
		resets = <&cru SRST_A_VOP>,
			 <&cru SRST_H_VOP>,
			 <&cru SRST_D_VOP0>,
			 <&cru SRST_D_VOP1>,
			 <&cru SRST_D_VOP2>,
			 <&cru SRST_D_VOP3>;
		reset-names = "axi",
			      "ahb",
			      "dclk_vp0",
			      "dclk_vp1",
			      "dclk_vp2",
			      "dclk_vp3";
		iommus = <&vop_mmu>;
		power-domains = <&power RK3588_PD_VOP>;
		rockchip,grf = <&sys_grf>;
		rockchip,vop-grf = <&vop_grf>;
		rockchip,vo1-grf = <&vo1_grf>;
		rockchip,pmu = <&pmu>;

		status = "disabled";

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

			vp0: port@0 {
				#address-cells = <1>;
				#size-cells = <0>;
				reg = <0>;

				vp0_out_dp0: endpoint@0 {
					reg = <0>;
					remote-endpoint = <&dp0_in_vp0>;
				};

				vp0_out_edp0: endpoint@1 {
					reg = <1>;
					remote-endpoint = <&edp0_in_vp0>;
				};

				vp0_out_hdmi0: endpoint@2 {
					reg = <2>;
					remote-endpoint = <&hdmi0_in_vp0>;
				};
			};

			vp1: port@1 {
				#address-cells = <1>;
				#size-cells = <0>;
				reg = <1>;

				vp1_out_dp0: endpoint@0 {
					reg = <0>;
					remote-endpoint = <&dp0_in_vp1>;
				};

				vp1_out_edp0: endpoint@1 {
					reg = <1>;
					remote-endpoint = <&edp0_in_vp1>;
				};

				vp1_out_hdmi0: endpoint@2 {
					reg = <2>;
					remote-endpoint = <&hdmi0_in_vp1>;
				};
			};

			vp2: port@2 {
				#address-cells = <1>;
				#size-cells = <0>;
				reg = <2>;

				assigned-clocks = <&cru DCLK_VOP2_SRC>;
				assigned-clock-parents = <&cru PLL_V0PLL>;

				vp2_out_dp0: endpoint@0 {
					reg = <0>;
					remote-endpoint = <&dp0_in_vp2>;
				};

				vp2_out_edp0: endpoint@1 {
					reg = <1>;
					remote-endpoint = <&edp0_in_vp2>;
				};

				vp2_out_hdmi0: endpoint@2 {
					reg = <2>;
					remote-endpoint = <&hdmi0_in_vp2>;
				};

				vp2_out_dsi0: endpoint@3 {
					reg = <3>;
					remote-endpoint = <&dsi0_in_vp2>;
				};

				vp2_out_dsi1: endpoint@4 {
					reg = <4>;
					remote-endpoint = <&dsi1_in_vp2>;
				};
			};

			vp3: port@3 {
				#address-cells = <1>;
				#size-cells = <0>;
				reg = <3>;

				vp3_out_dsi0: endpoint@0 {
					reg = <0>;
					remote-endpoint = <&dsi0_in_vp3>;
				};

				vp3_out_dsi1: endpoint@1 {
					reg = <1>;
					remote-endpoint = <&dsi1_in_vp3>;
				};

				vp3_out_rgb: endpoint@2 {
					reg = <2>;
					remote-endpoint = <&rgb_in_vp3>;
				};
			};
		};
	};

该节点描述 VOP 硬件资源,控制着 vop 驱动的加载 rockchip_drm_vop.c/rockchip_drm_vop2.c , 它描述了如下 的显示通路连接关系:

RK3568 DRM显示框架_第3张图片 

vop_out: ports 节点描述 VOP 的输出通道,vp0/1/2 对应 VOP 上 Video Port0/1/2 三个独立的输出通路。

vp0/1/2 : port 下的 endpoint 节点描述 VP 和显示接口的连接关系,以上面的 dts 描述为例:vp0 节点下有

vp0_out_dsi0 , vp0_out_dsi1 , vp0_out_edp , vp0_out_hdmi 四个节点,说明 vp0 可以和 dsi0、dsi1、

edp、hdmi、四个显示接口连接。 每个 endpoint 通过 remote-endpoint 属性和对应的显示接口组成一个连接通路 ,比如和 hdmi 显示接口的连接:

hdmi0: hdmi@fde80000 {
		compatible = "rockchip,rk3588-dw-hdmi";
		reg = <0x0 0xfde80000 0x0 0x20000>;
		interrupts = ,
			     ,
			     ,
			     ,
			     ;
		clocks = <&cru PCLK_HDMITX0>,
			 <&cru CLK_HDMIHDP0>,
			 <&cru CLK_HDMITX0_EARC>,
			 <&cru CLK_HDMITX0_REF>,
			 <&cru MCLK_I2S5_8CH_TX>,
			 <&cru DCLK_VOP0>,
			 <&cru DCLK_VOP1>,
			 <&cru DCLK_VOP2>,
			 <&cru DCLK_VOP3>,
			 <&hclk_vo1>,
			 <&hdptxphy_hdmi_clk0>;
		clock-names = "pclk",
			      "hpd",
			      "earc",
			      "hdmitx_ref",
			      "aud",
			      "dclk_vp0",
			      "dclk_vp1",
			      "dclk_vp2",
			      "dclk_vp3",
			      "hclk_vo1",
			      "link_clk";
		resets = <&cru SRST_HDMITX0_REF>, <&cru SRST_HDMIHDP0>;
		reset-names = "ref", "hdp";
		power-domains = <&power RK3588_PD_VO1>;
		pinctrl-names = "default";
		pinctrl-0 = <&hdmim0_tx0_cec &hdmim0_tx0_hpd &hdmim0_tx0_scl &hdmim0_tx0_sda>;
		reg-io-width = <4>;
		rockchip,grf = <&sys_grf>;
		rockchip,vo1_grf = <&vo1_grf>;
		phys = <&hdptxphy_hdmi0>;
		phy-names = "hdmi";
		#sound-dai-cells = <0>;
		status = "disabled";

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

			hdmi0_in: port@0 {
				reg = <0>;
				#address-cells = <1>;
				#size-cells = <0>;

				hdmi0_in_vp0: endpoint@0 {
					reg = <0>;
					remote-endpoint = <&vp0_out_hdmi0>;
					status = "disabled";
				};

				hdmi0_in_vp1: endpoint@1 {
					reg = <1>;
					remote-endpoint = <&vp1_out_hdmi0>;
					status = "disabled";
				};

				hdmi0_in_vp2: endpoint@2 {
					reg = <2>;
					remote-endpoint = <&vp2_out_hdmi0>;
					status = "disabled";
				};
			};
		};
	};

结合上面的 dts 描述我们可以知道,在 rk3568 上,hdmi 可以和 vop 的 vp0,vp1 连接。 需要注意的是,一个显示接口在同一个时刻只能和一个 vp 连接,所以在具体的板级配置中,需要在 dts 中把要使用的 通路打开,把不使用的通路设置为 disabled 状态。

&hdmi {
        status = "okay";
};

&hdmi_in_vp0 {
        status = "okay";
};

&hdmi_in_vp1 {
        status = "disabled";
};

&route_hdmi {
        status = "okay";
        connect = <&vp0_out_hdmi>;
};

四.调试手段

调试命令:

cat /sys/kernel/debug/dri/0/summary

RK3568 DRM显示框架_第4张图片

 参数说明:

1. 两个红色方框表示两个显示设备使用的 vop 分别是 ff900000.vop 和 ff8f0000.vop;

2. 绿色部分表示 connector 信息,两个显示设备分别为 eDP 屏和 MIPI 屏;

3. 粉色部分为显示模式,可以知道具体的时序、DCLK 以及帧率,上图中两个设备分别为分辨率为 1536x2048p60的 eDP 屏和分辨率 1280x720p29 的 MIPI 屏;

4. 蓝色部分是 VOP 图层信息,第一个显示设备打开 win0 图层,大小为 1536x2048 格式为 XRGB 第二个显示设备 打开 win0 图层,大小 1280x720 格式为 XRGB, src 和 dst 表示源数据和显示的大小和位置,如果 src 和 dst 的 大小不一致,VOP 会进行缩放处理。

查看vop时钟命令:

cat /sys/kernel/debug/clk/clk_summary | grep vop

你可能感兴趣的:(驱动开发,c++)