RK3288 android7.1 HDMI的使用与调试方法 -- (一)

RK平台主要采用 FB 和 DRM 两种显示框架。与此相对应, HDMI 也有两套驱动。
FB:
LINUX 3.10 内核主要采用传统的 FB 框架, HDMI 驱动的路径为:

kernel/drivers/video/rockchip/hdmi/

DRM:
DRM全称是 Direct Rendering Manager 是 DRI ( Direct Rendering Infrastructure ) 框架的一个
组件。LINUX 4.4/4.19 内核采用 DRM框架, HDMI 驱动的路径为:

kernel/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
kernel/drivers/gpu/drm/bridge/synopsys/

RK3288_Android7.1内核为4.4,采用的DRM框架,本文只分析DRM框架下hdmi相关功能调试。


1.HDMI 软件功能配置

1.1 使能HDMI
&hdmi {
    
    
	status = "okay";
};
1.2 绑定VOP

RK3288平台存在两个 VOP:VOPB(支持 4K)、VOPL(只支持 2K),两个 VOP
可以分别与两个显示接口绑定(一个显示接口只能和一个 VOP 绑定),且可以相互交换:
在这里插入图片描述
当 dts 中显示设备节点打开时,显示接口对应 VOPB和 VOPL 的 ports 都会打开,所以需要关闭用不到的那个 VOP。 比如 HDMI 绑定到 VOPB 需要添加:

&hdmi_in_vopl {
    
    
	status = "disabled";
};

反之若绑定到 VOPL 则添加:

&hdmi_in_vopb {
    
    
	status = "disabled";
};
1.3 打开开机logo

如果 U-Boot logo 未开启,那 kernel 阶段也无法显示开机 logo,只能等到系统启动后才能看到显示。
在 dts 里面将 route_hdmi 使能即可打开 U-Boot logo 支持:

&route_hdmi {
    
    
	status = "okay"
};
1.4 新增特殊分辨率

DRM 框架目前代码已经支持了绝大部分分辨率时序,但是部分 HDMI 屏幕旋转的场景下,可能还有一些特殊分辨率不支持。需要在 kernel\drivers\gpu\drm\drm_edid.c 中的 drm_dmt_modes 当末尾新增:

/* 0x58 - [email protected] RB */
{
    
     DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 556188, 4096, 4104,
	4136, 4176, 0, 2160, 2208, 2216, 2222, 0,
	DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
参数 说明
4096x2160 mode name,为分辨率的 hdisplay*vdisplay
DRM_MODE_TYPE_DRIVER mode type,配置为DRM_MODE_TYPE_DRIVER
556188 像素时钟
4096 行有效像素
4104 行同步起始像素
4136 行同步结束像素
4176 一行总像素
0 hskew,通常为 0
2160 帧有效行
2208 帧同步开始行
2216 帧同步结束行
2222 一帧总行数
0 vscan, 通常为 0
vrefresh 显示设备帧率
DRM_MODE_FLAG_PHSYNC I DRM_MODE_FLAG_NVSYNC hsync 和 vsync 极性,flags 的定义如下:DRM_MODE_FLAG_PHSYNC (1<<0) DRM_MODE_FLAG_NHSYNC (1<<1) DRM_MODE_FLAG_PVSYNC (1<<2) DRM_MODE_FLAG_NVSYNC (1<<3) DRM_MODE_FLAG_INTERLACE (1<<4)
1.5 强制输出指定分辨率

当需要无视 EDID 的限制,需要强制输出某个分辨率:

diff --git a/kernel/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/kernel/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index 8165851656..12137d0c68 100644
--- a/kernel/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/kernel/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -2497,7 +2497,7 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector)
 					     connector);
 	struct edid *edid;
 	struct drm_display_mode *mode;
-	const u8 def_modes[6] = {
    
    4, 16, 31, 19, 17, 2};
+	const u8 def_modes[6] = {
    
    30, 16, 31, 19, 17, 2}; //把def_mode数组的第一个值对应的是默认显示hdmi的分辨率对应的 vic(dw-hdmi.c文件中)
 	struct drm_display_info *info = &connector->display_info;
 	struct hdr_static_metadata *metedata =
 			&connector->display_info.hdmi.hdr_panel_metadata;
@@ -2507,6 +2507,7 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector)
 		return 0;
 
 	edid = drm_get_edid(connector, hdmi->ddc);
+   edid = NULL; //edid = NULL; 强制进入 EDID 读取失败的流程,不管有没有读到 EDID 都强制按def_modes 的分辨率来显示。
 	if (edid) {
    
    
 		dev_dbg(hdmi->dev, "got edid: width[%d] x height[%d]\n",
 			edid->width_cm, edid->height_cm);
diff --git a/kernel/drivers/gpu/drm/drm_edid.c b/kernel/drivers/gpu/drm/drm_edid.c
index 3fd2dd5c4a..4cac0b7584 100644
--- a/kernel/drivers/gpu/drm/drm_edid.c
+++ b/kernel/drivers/gpu/drm/drm_edid.c
@@ -820,11 +820,11 @@ static const struct drm_display_mode edid_cea_modes[] = {
    
    
 		   1592, 1728, 0, 576, 581, 586, 625, 0,
 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
 	  .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
-	/* 30 - 1440x576@50Hz */
-	{
    
     DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464,
-		   1592, 1728, 0, 576, 581, 586, 625, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
-	  .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
+    /* 30 - 3840x1448@60Hz */
+    {
    
     DRM_MODE("3840x1448", DRM_MODE_TYPE_DRIVER, 297000, 3840, 3888,
+           3920, 4400, 0, 1448, 1451, 1456, 1538, 0,
+          DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC),
+     .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, 
 	/* 31 - 1920x1080@50Hz */
 	{
    
     DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448,
 		   2492, 2640, 0, 1080, 1084, 1089, 1125, 0,

如果需要强制显示 4K 的分辨率,还需要注释掉以下代码,解除对 4K 分辨率的限制

diff --git a/kernel/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/kernel/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index cabddaa6f2..8cf1b19b7c 100644
--- a/kernel/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/kernel/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -490,10 +490,12 @@ dw_hdmi_rockchip_mode_valid(struct drm_connector *connector,
 	 * If sink max TMDS clock < 340MHz, we should check the mode pixel
 	 * clock > 340MHz is YCbCr420 or not.
 	 */
+#if 0
 	if (mode->clock > 340000 &&
 	    connector->display_info.max_tmds_clock < 340000 &&
 	    (!drm_mode_is_420(&connector->display_info, mode)|| !connector->ycbcr_420_allowed))
 		return MODE_BAD;
+#endif
 
 	if (!encoder) {
    
    
 		const struct drm_connector_helper_funcs *funcs;
1.6 打开音频

RK3288 默认 HDMI 声卡和 Codec 公用,要确保以下配置打开:

&hdmi_analog_sound {
    
    
	status = "okay";
}

2. 常用调试方法

2.1 查看 VOP 状态
cat d/dri/0/summary

在这里插入图片描述

2.2 查看 Connector 状态

/sys/class/drm 目录下可以看到驱动注册的各个显卡,
在这里插入图片描述
可以看到注册了 card0-HDMI-A-1 和 card0-DSI-1 两种显示设备,分别表示 HDMI 和 DSI。

以 card0-HDMI-A-1 为例,其目录下有以下文件:
1.Enabled:使能状态
2.Status:连接状态
3.Mode:当前输出分辨率
4.Modes:连接设备支持的分辨率列表
5.Audioformat:连接设备支持的音频格式
6.Edid:连接设备的 EDID,可以通过命令 cat edid > /data/edid.bin 保存下来。

2.3 查看 HDMI 工作状态

使用以下命令查看当前 HDMI 输出状态:

cat /sys/kernel/debug/dw-hdmi/status

在这里插入图片描述

2.4 强制使能/禁用 HDMI

强制使能 HDMI:

echo on > /sys/class/drm/card0-HDMI-A-1/status 1

强制禁用 HDMI:

echo off > /sys/class/drm/card0-HDMI-A-1/status 1

恢复检测热插拔:

echo detect > /sys/class/drm/card0-HDMI-A-1/status

相关链接文章:[RK3288][Android5.1] HDMI的使用与调试方法 – (二)

猜你喜欢

转载自blog.csdn.net/weixin_45639314/article/details/132026699