Rockchip RK3399 - DRM HDMI调试
----------------------------------------------------------------------------------------------------------------------------
开发板 :NanoPC-T4
开发板
eMMC
:16GB
LPDDR3
:4GB
显示屏 :15.6
英寸HDMI
接口显示屏
u-boot
:2023.04
linux
:6.3
----------------------------------------------------------------------------------------------------------------------------
一、烧录内核
1.1 配置内核
在linux
内核根目录下执行make menuconfig
配置以下选项:
Device Drivers --->
Graphics support --->
<*> Direct Rendering Manager (XFree86 4.1.0 and higher DRI support) --->
<*> DRM Support for Rockchip (DRM_ROCKCHIP [=y])
[*] Rockchip VOP driver # CONFIG_ROCKCHIP_VOP2
[ ] Rockchip VOP2 driver # CONFIG_ROCKCHIP_VOP
[*] Rockchip specific extensions for Analogix DP driver # CONFIG_ROCKCHIP_ANALOGIX_DP
[*] Rockchip cdn DP # CONFIG_ROCKCHIP_CDN_DP
[*] Rockchip specific extensions for Synopsys DW HDMI # CONFIG_ROCKCHIP_DW_HDMI
[*] Rockchip specific extensions for Synopsys DW MIPI DSI # CONFIG_ROCKCHIP_DW_MIPI_DSI
[*] Rockchip specific extensions for Innosilicon HDMI # CONFIG_ROCKCHIP_INNO_HDMI 实际上RK3399并没有使用Innosilicon IP,可以不选
[*] Rockchip LVDS support # CONFIG_ROCKCHIP_LVDS
[ ] Rockchip RGB support # CONFIG_ROCKCHIP_RGB
Display Interface Bridges ---> # CONFIG_DRM_DW_HDMI取决于CONFIG_DRM_BRIDGE、DRM_DRM(默认开启)
<M> Synopsys Designware AHB Audio interface # CONFIG_DRM_DW_HDMI_AHB_AUDIO
<*> Synopsys Designware I2S Audio interface # CONFIG_DRM_DW_HDMI_I2S_AUDIO HDMI音频
<M> Synopsys Designware GP Audio interface # CONFIG_DRM_DW_HDMI_I2S_AUDIO
<*> Synopsis Designware CEC interface # CONFIG_DRM_DW_HDMI_CEC
Device Drivers --->
PHY Subsystem --->
<M> Rockchip INNO HDMI PHY Driver
HDMI PHY
使用的是DesignWare HDMI IP
,并没有使用Innosilicon IP
。因此可以不用选择Rockchip INNO HDMI PHY Driver
。
CONFIG_DRM_DW_HDMI
对应的驱动位于drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
。
有关HDMI
音频配置可以参考文章:《Rockchip RK3399 - HDMI
音频》。
1.2 保存配置
配置完内核之后记得保存配置:
存档:
root@zhengyang:/work/sambashare/rk3399/linux-6.3# mv rk3399_defconfig ./arch/arm64/configs/
重新配置内核(如果不想重新编译内核,可以存档一份到.config
):
root@zhengyang:/work/sambashare/rk3399/linux-6.3# make rk3399_defconfig
1.3 编译内核
在linux
内核根目录下执行如下命令进行编译内核:
root@zhengyang:/work/sambashare/rk3399/linux-6.3# make -j8
u-boot-2023.04
路径下的mkimage
工具拷贝过来,然后在命令行使用mkimage
工具编译即可:
root@zhengyang:/work/sambashare/rk3399/linux-6.3# cp ../u-boot-2023.04/tools/mkimage ./
root@zhengyang:/work/sambashare/rk3399/linux-6.3# ./mkimage -f kernel.its kernel.itb
1.4 通过tftp
烧录内核
给开发板上电,同时连接上网线,进入uboot
命令行。我们将内核拷贝到tftp
文件目录:
root@zhengyang:/work/sambashare/rk3399/linux-6.3# cp kernel.itb /work/tftpboot/
接着给开发板上电。通过uboot
命令行将kernel.itb
下到内存地址0x10000000
处:
=> tftp 0x10000000 kernel.itb
通过mmc write
命令将内核镜像烧录到eMMC
第0x8000
个扇区处:
=> mmc erase 0x8000 0xA000
=> mmc write 0x10000000 0x8000 0xA000
=> bootm
1.5 启动内核
将开发板和hdmi
显示器(显示器支持分辨率是12560x1440@144Hz
)通过hdmi
线缆连接起来,然后给开发板上电启动。内核输入有关hdmi
日志:
[ 0.539951] platform ff940000.hdmi: Fixed dependency cycle(s) with /vop@ff8f0000/port/endpoint@2
[ 0.549676] platform ff940000.hdmi: Fixed dependency cycle(s) with /vop@ff900000/port/endpoint@2
[ 1.430309] rockchip-vop ff8f0000.vop: Adding to iommu group 2
[ 1.437640] rockchip-vop ff900000.vop: Adding to iommu group 3
[ 1.450511] rockchip-drm display-subsystem: bound ff8f0000.vop (ops vop_component_ops)
[ 1.459516] [drm] unsupported AFBC format[3231564e]
[ 1.466072] rockchip-drm display-subsystem: bound ff900000.vop (ops vop_component_ops)
[ 1.475048] dwhdmi-rockchip ff940000.hdmi: supply avdd-0v9 not found, using dummy regulator
[ 1.484573] dwhdmi-rockchip ff940000.hdmi: supply avdd-1v8 not found, using dummy regulator
[ 4.136104] rockchip-drm display-subsystem: bound ff8f0000.vop (ops vop_component_ops)
[ 4.146266] rockchip-drm display-subsystem: bound ff900000.vop (ops vop_component_ops)
[ 4.155351] dwhdmi-rockchip ff940000.hdmi: supply avdd-0v9 not found, using dummy regulator
[ 4.164983] dwhdmi-rockchip ff940000.hdmi: supply avdd-1v8 not found, using dummy regulator
[ 4.174627] dwhdmi-rockchip ff940000.hdmi: Detected HDMI TX controller v2.11a with HDCP (DWC HDMI 2.0 TX PHY)
[ 4.188847] rockchip-drm display-subsystem: bound ff940000.hdmi (ops dw_hdmi_rockchip_ops)
[ 4.199257] [drm] Initialized rockchip 1.0.0 20140818 for display-subsystem on minor 0
[ 4.331400] Console: switching to colour frame buffer device 240x67
[ 4.382497] rockchip-drm display-subsystem: [drm] fb0: rockchipdrmfb frame buffer device
[ 5.035286] [drm] Initialized panfrost 1.2.0 20180908 for ff9a0000.gpu on minor 1
二、hdmi
调试
在/dev/dri/
目录下可以看到驱动注册的各个显卡,DRM
设备节点为 /dev/dri/cardX
,X
为0-15
的数值。
root@rk3399:~# ll /dev/dri/
drwxr-xr-x 2 root root 100 Mar 15 23:04 by-path/
crw-rw----+ 1 root video 226, 0 Mar 15 23:07 card0
crw-rw----+ 1 root video 226, 1 Mar 15 23:04 card1
crw-rw----+ 1 root render 226, 128 Mar 15 23:04 renderD128
root@rk3399:~# ll /sys/class/drm
lrwxrwxrwx 1 root root 0 Mar 15 23:04 card0 -> ../../devices/platform/display-subsystem/drm/card0/
lrwxrwxrwx 1 root root 0 Mar 15 23:04 card0-HDMI-A-1 -> ../../devices/platform/display-subsystem/drm/card0/card0-HDMI-A-1/
lrwxrwxrwx 1 root root 0 Mar 15 23:04 card1 -> ../../devices/platform/ff9a0000.gpu/drm/card1/
lrwxrwxrwx 1 root root 0 Mar 15 23:04 renderD128 -> ../../devices/platform/ff9a0000.gpu/drm/renderD128/
-r--r--r-- 1 root root 4096 Mar 15 23:04 version
sysfs
文件系统中的card0-HDMI-A-1
代表的是hdmi
显示设备,是由drm_sysfs_connector_add
函数创建的。查看card0-HDMI-A-1
目录结构;
root@rk3399:~# ll /sys/class/drm/card0-HDMI-A-1/
lrwxrwxrwx 1 root root 0 Mar 15 23:14 ddc -> ../../../../ff160000.i2c/i2c-7/
lrwxrwxrwx 1 root root 0 Mar 15 23:14 device -> ../../card0/
-r--r--r-- 1 root root 4096 Mar 15 23:14 dpms
-r--r--r-- 1 root root 0 Mar 15 23:14 edid
-r--r--r-- 1 root root 4096 Mar 15 23:04 enabled
-r--r--r-- 1 root root 4096 Mar 15 23:14 modes
drwxr-xr-x 2 root root 0 Mar 15 23:14 power/
-rw-r--r-- 1 root root 4096 Mar 15 23:04 status
lrwxrwxrwx 1 root root 0 Mar 15 23:04 subsystem -> ../../../../../../class/drm/
-rw-r--r-- 1 root root 4096 Mar 15 23:04 uevent
其中:
ddc
:hdmi
显示数据通道,指向i2c7
,用来获取edid
、hdcp
密钥等内容;device
:指向card0
;edid
:存储hdmi
显示器的扩展显示标识数据;enabled
:hdmi
接口是否被启用或禁用;modes
:连接的hdmi
显示器以及当前hdmi
控制器同时支持的分辨率列表;status
:hdmi
接口连接状态的信息;
需要注意:下文中提到的分辨率,指的是就是显示模式。
2.1 查看hdmi
使能状态
查看hdmi
输出使能状态:
root@rk3399:~# cat /sys/class/drm/card0-HDMI-A-1/enabled
enabled
如果将hdmi
线拔掉:
root@rk3399:~# cat /sys/class/drm/card0-HDMI-A-1/enabled
disabled
在使用cat
命令读取enabled
文件时调用enabled_show
方法;
static ssize_t enabled_show(struct device *device,
struct device_attribute *attr,
char *buf)
{
struct drm_connector *connector = to_drm_connector(device);
bool enabled;
enabled = READ_ONCE(connector->encoder);
return sysfs_emit(buf, enabled ? "enabled\n" : "disabled\n");
}
2.2 查看hdmi
连接状态
查看hdmi
的插拔连接状态;
root@rk3399:~# cat /sys/class/drm/card0-HDMI-A-1/status
connected
如果将hdmi
线拔掉:
root@rk3399:~# cat /sys/class/drm/card0-HDMI-A-1/status
disconnected
在使用cat
命令读取status
文件时调用status_show
方法;
static ssize_t status_show(struct device *device,
struct device_attribute *attr,
char *buf)
{
struct drm_connector *connector = to_drm_connector(device);
enum drm_connector_status status;
status = READ_ONCE(connector->status);
return sysfs_emit(buf, "%s\n",
drm_get_connector_status_name(status));
}
2.3 查看edid
通过如下命令可以查看edid
信息,一共256个字节;
root@rk3399:/# cat /sys/class/drm/card0-HDMI-A-1/edid > /data/edid.bin
root@rk3399:/# hexdump -C /data/edid.bin
00000000 00 ff ff ff ff ff ff 00 35 34 00 00 01 01 01 01 |........54......|
00000010 00 20 01 03 81 00 00 78 ee 8c 75 a9 54 45 98 22 |. .....x..u.TE."|
00000020 1e 50 54 2f cf 00 71 40 81 c0 81 80 95 00 a9 c0 |.PT/..q@........|
00000030 b3 00 d1 c0 d1 00 d3 bc 00 a0 a0 a0 29 50 30 20 |............)P0 |
00000040 35 00 b9 88 21 00 00 1a 56 5e 00 a0 a0 a0 29 50 |5...!...V^....)P|
00000050 30 20 35 00 b9 88 21 00 00 1a 67 e2 00 a0 a0 a0 |0 5...!...g.....|
00000060 29 50 30 20 35 00 b9 88 21 00 00 1a 00 00 00 fc |)P0 5...!.......|
00000070 00 4d 45 49 54 49 41 4e 48 41 4f 0a 20 20 01 0b |.MEITIANHAO. ..|
00000080 02 03 3a f2 4f 04 05 10 13 14 1f 6c 6c 6c 27 6c |..:.O......lll'l|
00000090 6c 6c 4b 4c e2 00 d5 e3 05 c0 00 23 09 7f 07 83 |llKL.......#....|
000000a0 01 00 00 67 03 0c 00 10 00 38 78 e6 06 05 01 69 |...g.....8x....i|
000000b0 69 4f 67 d8 5d c4 01 76 c0 00 02 3a 80 18 71 38 |iOg.]..v...:..q8|
000000c0 2d 40 58 2c 25 00 58 c3 10 00 00 1e d4 bc 00 a0 |-@X,%.X.........|
000000d0 a0 a0 29 50 30 20 35 00 b9 88 21 00 00 1e 98 e2 |..)P0 5...!.....|
000000e0 00 a0 a0 a0 29 50 30 20 35 00 b9 88 21 00 00 1e |....)P0 5...!...|
000000f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 c4 |................|
这里我们尝试通过EDID Manager
工具去解析,首先需要去下载EDID Manager
工具,然后将edid.bin
下载到windows
系统上,并加载文件解析内容如下:
Time: 21:03:42
Date: 2023年11月9日
EDID Manager Version: 1.0.0.14
___________________________________________________________________
Block 0 (EDID Base Block), Bytes 0 - 127, 128 BYTES OF EDID CODE:
0 1 2 3 4 5 6 7 8 9
000 | 00 FF FF FF FF FF FF 00 35 34
010 | 00 00 01 01 01 01 00 20 01 03
020 | 81 00 00 78 EE 8C 75 A9 54 45
030 | 98 22 1E 50 54 2F CF 00 71 40
040 | 81 C0 81 80 95 00 A9 C0 B3 00
050 | D1 C0 D1 00 D3 BC 00 A0 A0 A0
060 | 29 50 30 20 35 00 B9 88 21 00
070 | 00 1A 56 5E 00 A0 A0 A0 29 50
080 | 30 20 35 00 B9 88 21 00 00 1A
090 | 67 E2 00 A0 A0 A0 29 50 30 20
100 | 35 00 B9 88 21 00 00 1A 00 00
110 | 00 FC 00 4D 45 49 54 49 41 4E
120 | 48 41 4F 0A 20 20 01 0B
(8-9) ID Manufacture Name : MIT
(10-11) ID Product Code : 0000
(12-15) ID Serial Number : N/A
(16) Week of Manufacture : 0
(17) Year of Manufacture : 2022
(18) EDID Version Number : 1
(19) EDID Revision Number: 3
(20) Video Input Definition : Digital
DFP 1.x Compatible
(21) Maximum Horizontal Image Size: 0 cm
(22) Maximum Vertical Image Size : 0 cm
(23) Display Gamma : 2.20
(24) Power Management and Supported Feature(s):
Standby, Suspend, Active Off/Very Low Power, RGB Color, sRGB, Preferred Timing Mode
(25-34) Color Characteristics
Red Chromaticity : Rx = 0.658 Ry = 0.328
Green Chromaticity : Gx = 0.269 Gy = 0.594
Blue Chromaticity : Bx = 0.134 By = 0.120
Default White Point: Wx = 0.313 Wy = 0.329
(35) Established Timings I
640 x 480 @ 60Hz (IBM, VGA)
640 x 480 @ 72Hz (VESA)
640 x 480 @ 75Hz (VESA)
800 x 600 @ 56Hz (VESA)
800 x 600 @ 60Hz (VESA)
(36) Established Timings II
800 x 600 @ 72Hz (VESA)
800 x 600 @ 75Hz (VESA)
1024 x 768 @ 60Hz (VESA)
1024 x 768 @ 70Hz(VESA)
1024 x 768 @ 75Hz (VESA)
1280 x 1024 @ 75Hz (VESA)
(37) Manufacturer's Timings (Not Used)
(38-53) Standard Timings
1152x864 @ 60 Hz (4:3 Aspect Ratio)
1280x720 @ 60 Hz (16:9 Aspect Ratio)
1280x1024 @ 60 Hz (5:4 Aspect Ratio)
1440x900 @ 60 Hz (16:10 Aspect Ratio)
1600x900 @ 60 Hz (16:9 Aspect Ratio)
1680x1050 @ 60 Hz (16:10 Aspect Ratio)
1920x1080 @ 60 Hz (16:9 Aspect Ratio)
1920x1200 @ 60 Hz (16:10 Aspect Ratio)
(54-71) Detailed Descriptor #1: Preferred Detailed Timing (2560x1440 @ 120Hz)
Pixel Clock : 483.39 MHz
Horizontal Image Size : 697 mm
Vertical Image Size : 392 mm
Refresh Mode : Non-interlaced
Normal Display, No Stereo
Horizontal:
Active Time : 2560 Pixels
Blanking Time : 160 Pixels
Sync Offset : 48 Pixels
Sync Pulse Width: 32 Pixels
Border : 0 Pixels
Frequency : 177 kHz
Vertical:
Active Time : 1440 Lines
Blanking Time : 41 Lines
Sync Offset : 3 Lines
Sync Pulse Width: 5 Lines
Border : 0 Lines
Digital Separate, Horizontal Polarity (+), Vertical Polarity (-)
Modeline: "2560x1440" 483.390 2560 2608 2640 2720 1440 1443 1448 1481 +hsync -vsync
(72-89) Detailed Descriptor #2: Detailed Timing (2560x1440 @ 60Hz)
Pixel Clock : 241.5 MHz
Horizontal Image Size : 697 mm
Vertical Image Size : 392 mm
Refresh Mode : Non-interlaced
Normal Display, No Stereo
Horizontal:
Active Time : 2560 Pixels
Blanking Time : 160 Pixels
Sync Offset : 48 Pixels
Sync Pulse Width: 32 Pixels
Border : 0 Pixels
Frequency : 88 kHz
Vertical:
Active Time : 1440 Lines
Blanking Time : 41 Lines
Sync Offset : 3 Lines
Sync Pulse Width: 5 Lines
Border : 0 Lines
Digital Separate, Horizontal Polarity (+), Vertical Polarity (-)
Modeline: "2560x1440" 241.500 2560 2608 2640 2720 1440 1443 1448 1481 +hsync -vsync
(90-107) Detailed Descriptor #3: Detailed Timing (2560x1440 @ 144Hz)
Pixel Clock : 579.59 MHz
Horizontal Image Size : 697 mm
Vertical Image Size : 392 mm
Refresh Mode : Non-interlaced
Normal Display, No Stereo
Horizontal:
Active Time : 2560 Pixels
Blanking Time : 160 Pixels
Sync Offset : 48 Pixels
Sync Pulse Width: 32 Pixels
Border : 0 Pixels
Frequency : 213 kHz
Vertical:
Active Time : 1440 Lines
Blanking Time : 41 Lines
Sync Offset : 3 Lines
Sync Pulse Width: 5 Lines
Border : 0 Lines
Digital Separate, Horizontal Polarity (+), Vertical Polarity (-)
Modeline: "2560x1440" 579.590 2560 2608 2640 2720 1440 1443 1448 1481 +hsync -vsync
(108-125) Detailed Descriptor #4: Monitor Name
Monitor Name: MEITIANHAO
(126-127) Extension Flag and Checksum
Extension Block(s) : 1
Checksum Value : 11
___________________________________________________________________
Block 1 ( CEA-861 Extension Block), Bytes 128 - 255, 128 BYTES OF EDID CODE:
0 1 2 3 4 5 6 7 8 9
128 | 02 03 3A F2 4F 04 05 10 13 14
138 | 1F 6C 6C 6C 27 6C 6C 6C 4B 4C
148 | E2 00 D5 E3 05 C0 00 23 09 7F
158 | 07 83 01 00 00 67 03 0C 00 10
168 | 00 38 78 E6 06 05 01 69 69 4F
178 | 67 D8 5D C4 01 76 C0 00 02 3A
188 | 80 18 71 38 2D 40 58 2C 25 00
198 | 58 C3 10 00 00 1E D4 BC 00 A0
208 | A0 A0 29 50 30 20 35 00 B9 88
218 | 21 00 00 1E 98 E2 00 A0 A0 A0
228 | 29 50 30 20 35 00 B9 88 21 00
238 | 00 1E 00 00 00 00 00 00 00 00
248 | 00 00 00 00 00 00 00 C4
(128-130) Extension Header
Revision Number : 3
DTD Starting Offset: 58
(131) Display Support
DTV Underscan, Basic Audio, YCbCr 4:4:4, YCbCr 4:2:2
Number of Native Formats: 2
(132-147) Video Data Block
1280x720p @ 59.94/60Hz - HDTV (16:9, 1:1)
1920x1080i @ 59.94/60Hz - HDTV (16:9, 1:1)
1920x1080p @ 59.94/60Hz - HDTV (16:9, 1:1)
1280x720p @ 50Hz - HDTV (16:9, 1:1)
1920x1080i @ 50Hz - HDTV (16:9, 1:1)
1920x1080p @ 50Hz - HDTV (16:9, 1:1)
Reserved for the Future
Reserved for the Future
Reserved for the Future
1920x1080i (1250 total) - HDTV 50Hz (16:9, 1:1)
Reserved for the Future
Reserved for the Future
Reserved for the Future
Reserved for the Future
Reserved for the Future
(148-150) Video Capability Data Block (VCDB)
(151-154) Colorimetry Data Block
2.3.1 Established Timings
Established Timings
其定义在drivers/gpu/drm/drm_edid.c
文件的edid_est_modes
数组中:
/*
* These more or less come from the DMT spec. The 720x400 modes are
* inferred from historical 80x25 practice. The 640x480@67 and 832x624@75
* modes are old-school Mac modes. The EDID spec says the 1152x864@75 mode
* should be 1152x870, again for the Mac, but instead we use the x864 DMT
* mode.
*
* The DMT modes have been fact-checked; the rest are mild guesses.
*/
static const struct drm_display_mode edid_est_modes[] = {
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840,
968, 1056, 0, 600, 601, 605, 628, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@60Hz 支持 */
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 36000, 800, 824,
896, 1024, 0, 600, 601, 603, 625, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@56Hz 支持 */
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 656,
720, 840, 0, 480, 481, 484, 500, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@75Hz 支持 */
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 664,
704, 832, 0, 480, 489, 492, 520, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@72Hz 支持 */
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 30240, 640, 704,
768, 864, 0, 480, 483, 486, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@67Hz */
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656,
752, 800, 0, 480, 490, 492, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@60Hz 支持 */
{ DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 35500, 720, 738,
846, 900, 0, 400, 421, 423, 449, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 720x400@88Hz */
{ DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 28320, 720, 738,
846, 900, 0, 400, 412, 414, 449, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 720x400@70Hz */
{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 135000, 1280, 1296,
1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1280x1024@75Hz 支持 */
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 78750, 1024, 1040,
1136, 1312, 0, 768, 769, 772, 800, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1024x768@75Hz 支持 */
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 75000, 1024, 1048,
1184, 1328, 0, 768, 771, 777, 806, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1024x768@70Hz 支持 */
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048,
1184, 1344, 0, 768, 771, 777, 806, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1024x768@60Hz 支持 */
{ DRM_MODE("1024x768i", DRM_MODE_TYPE_DRIVER,44900, 1024, 1032,
1208, 1264, 0, 768, 768, 776, 817, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_INTERLACE) }, /* 1024x768@43Hz */
{ DRM_MODE("832x624", DRM_MODE_TYPE_DRIVER, 57284, 832, 864,
928, 1152, 0, 624, 625, 628, 667, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 832x624@75Hz */
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 49500, 800, 816,
896, 1056, 0, 600, 601, 604, 625, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@75Hz 支持 */
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 50000, 800, 856,
976, 1040, 0, 600, 637, 643, 666, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@72Hz 支持 */
{ DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152, 1216,
1344, 1600, 0, 864, 865, 868, 900, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1152x864@75Hz */
};
其中我使用的这款hdmi
显示器支持的Established Timings
时序有:
-
640x480@60Hz (IBM, VGA)
; -
640x480@72Hz (VESA)
; -
640x480@75Hz (VESA)
; -
800x600@56Hz (VESA)
; -
800x600@60Hz (VESA)
; -
800x600@72Hz (VESA)
; -
800x600@75Hz (VESA)
; -
1024x768@60Hz (VESA)
; -
1024x768@70Hz(VESA)
; -
1024x768@75Hz (VESA)
; -
1280x1024@75Hz (VESA)
;
2.3.2 Standard Timings
Standard Timings
其定义在drivers/gpu/drm/drm_edid.c
文件的drm_dmt_modes
数组中,由于数组元素比较多,这里就不一一列出了,只列出部分:
static const struct drm_display_mode drm_dmt_modes[] = {
/* 0x55 - 1280x720@60Hz */
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1390,
1430, 1650, 0, 720, 725, 730, 750, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 0x23 - 1280x1024@60Hz */
{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 108000, 1280, 1328,
1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 0x2f - 1440x900@60Hz */
{ DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 106500, 1440, 1520,
1672, 1904, 0, 900, 903, 909, 934, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 0x53 - 1600x900@60Hz */
{ DRM_MODE("1600x900", DRM_MODE_TYPE_DRIVER, 108000, 1600, 1624,
1704, 1800, 0, 900, 901, 904, 1000, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 0x3a - 1680x1050@60Hz */
{ DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 146250, 1680, 1784,
1960, 2240, 0, 1050, 1053, 1059, 1089, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 0x52 - 1920x1080@60Hz */
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008,
2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 0x45 - 1920x1200@60Hz */
{ DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 193250, 1920, 2056,
2256, 2592, 0, 1200, 1203, 1209, 1245, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
......
}
其中我使用的这款hdmi
显示器支持的 Standard Timings
时序有:
1152x864@60Hz (4:3 Aspect Ratio)
;1280x720@60Hz (16:9 Aspect Ratio)
;1280x1024@60Hz (5:4 Aspect Ratio);
1440x900@60Hz (16:10 Aspect Ratio);
1600x900@60Hz (16:9 Aspect Ratio)
;1680x1050@60Hz (16:10 Aspect Ratio);
1920x1080@60Hz (16:9 Aspect Ratio);
1920x1200@60Hz (16:10 Aspect Ratio)
;
需要注意的是1152x864@60Hz
并没有在drm_dmt_modes
数组中定义,如果想要支持该显示模式,需要我们自己扩展。
2.3.3 Detailed Timings
此外,我使用的这款hdmi
显示器支持的 Detailed Timings
时序有:
2560x1440@120Hz
最佳时序;2560x1440@60Hz
;2560x1440@144Hz
;
以2560x1440@120Hz
为例,具体描述信息如下:
(54-71) Detailed Descriptor #1: Preferred Detailed Timing (2560x1440 @ 120Hz)
Pixel Clock : 483.39 MHz
Horizontal Image Size : 697 mm
Vertical Image Size : 392 mm
Refresh Mode : Non-interlaced
Normal Display, No Stereo
Horizontal:
Active Time : 2560 Pixels
Blanking Time : 160 Pixels
Sync Offset : 48 Pixels
Sync Pulse Width: 32 Pixels
Border : 0 Pixels
Frequency : 177 kHz
Vertical:
Active Time : 1440 Lines
Blanking Time : 41 Lines
Sync Offset : 3 Lines
Sync Pulse Width: 5 Lines
Border : 0 Lines
Digital Separate, Horizontal Polarity (+), Vertical Polarity (-)
Modeline: "2560x1440" 483.390 2560 2608 2640 2720 1440 1443 1448 1481 +hsync -vsync
2.3.4 Video Data Block
edid
的扩展块Video Data Block
中也定义了支持的显示时序有:
1280x720p @ 59.94/60Hz - HDTV (16:9, 1:1)
;1920x1080i @ 59.94/60Hz - HDTV (16:9, 1:1)
;1920x1080p @ 59.94/60Hz - HDTV (16:9, 1:1)
;1280x720p @ 50Hz - HDTV (16:9, 1:1)
;1920x1080i @ 50Hz - HDTV (16:9, 1:1)
;1920x1080p @ 50Hz - HDTV (16:9, 1:1)
;1920x1080i (1250 total) - HDTV 50Hz (16:9, 1:1)
;
这里我们大概介绍一下p和i的含义:p代表的是逐行扫描(Progressive scan
),而i代表着是隔行扫描(interlaced scan
),具体的区别是:逐行扫描是按照顺序一个一个的扫描;而隔行扫描是对奇数和偶数分别进行扫描。
因此1080i
只需要1080p
一半的带宽,因此在电视信号上十分适合表现非常复杂的场景,比如纪录片的野生动物题材,但是1080p
在画面的表现会更加的平滑,不过一般情况下1080p
的画面效果是优于1080i
,所以在播放的选择上还是1080p
比较好。
默认情况下我们平时所说的1920*1080
指的就是1920x1080p
。
2.4 分辨率
查看连接的hdmi
显示器以及当前hdmi
控制器同时支持的分辨率列表;;
root@rk3399:~# cat /sys/class/drm/card0-HDMI-A-1/modes
1920x1080 # 1920x1080@60Hz
1920x1080
1920x1080
1920x1080i
1920x1080
1920x1080
1920x1080i
1600x900 # 1600x900@60Hz
1280x1024 # 1280x1024@60Hz
1280x720 # 1280x720p@60Hz
1280x720
1280x720
1024x768 # 1024x768@60Hz
800x600 # 800x600@60Hz
800x600 # 800x600@56Hz
需要注意的是:为啥会看到多个重复的分辨率呢?实际上这里输出的是显示模式的名称,同样名称是800x600
,实际上他们的刷新率、屏幕扫描方式可能是不一样的,比如:800x600@56Hz
,800x600@60Hz
;
在使用cat
命令读取modes
文件时调用modes_show
方法;
static ssize_t modes_show(struct device *device,
struct device_attribute *attr,
char *buf)
{
struct drm_connector *connector = to_drm_connector(device);
struct drm_display_mode *mode;
int written = 0;
mutex_lock(&connector->dev->mode_config.mutex);
// 遍历connector支持的modes
list_for_each_entry(mode, &connector->modes, head) {
// 写入到buf 在上一篇博客我们说过显示模式的命名规则为:%dx%d%s 第一个参数为:mode->hdisplay 第二个参数为:mode->vdisplay 第三个参数为:i/''(取决于mode->flags是否设置了DRM_MODE_FLAG_INTERLACE隔行扫描)
written += scnprintf(buf + written, PAGE_SIZE - written, "%s\n",
mode->name);
}
mutex_unlock(&connector->dev->mode_config.mutex);
return written;
}
在上一篇博客中我们介绍了drm_add_edid_modes
函数会探测hdmi
显示器支持的显示模式,并添加到connector
的 probed_modes
链表;
而connector->modes
链表中的显示模式实际上是由drm_helper_probe_single_connector_modes
函数从probed_modes
链表中移动过去的,并通过调用一系列的mode_validae
方法筛选之后的结果,其中有一个至关重要的校验函数drm_bridge_funcs.mode_valid
,其会调用dw_hdmi_bridge_mode_valid
函数进行校验;
static enum drm_mode_status
dw_hdmi_rockchip_mode_valid(struct dw_hdmi *hdmi, void *data,
const struct drm_display_info *info,
const struct drm_display_mode *mode)
{
const struct dw_hdmi_mpll_config *mpll_cfg = rockchip_mpll_cfg;
int pclk = mode->clock * 1000; // 计算得到像素时钟频率
bool valid = false;
int i;
// 遍历mpll_cfg像素时钟,查找匹配的时钟
for (i = 0; mpll_cfg[i].mpixelclock != (~0UL); i++) {
if (pclk == mpll_cfg[i].mpixelclock) {
valid = true;
break;
}
}
return (valid) ? MODE_OK : MODE_BAD;
}
static enum drm_mode_status
dw_hdmi_bridge_mode_valid(struct drm_bridge *bridge,
const struct drm_display_info *info,
const struct drm_display_mode *mode)
{
struct dw_hdmi *hdmi = bridge->driver_private;
const struct dw_hdmi_plat_data *pdata = hdmi->plat_data;
enum drm_mode_status mode_status = MODE_OK;
/* We don't support double-clocked modes */
if (mode->flags & DRM_MODE_FLAG_DBLCLK)
return MODE_BAD;
if (pdata->mode_valid)
// 调用dw_hdmi_rockchip_mode_valid
mode_status = pdata->mode_valid(hdmi, pdata->priv_data, info,
mode);
return mode_status;
}
通过遍历rockchip_mpll_cfg
,查找是否支持当前显示模式的像素时钟频率,如果匹配不到,也会不支持该显示模式。
当然,除了上面的校验外,在解析edid
的Standard Timings
也会去drm_dmt_modes
数组查找匹配的标准显示模式,如果匹配不到,也会不支持该显示模式。
因此命令cat /sys/class/drm/card0-HDMI-A-1/modes
看到的显示模式个数是远远少于edid
中看到的hdmi
显示器支持的显示模式。
2.4.1 查看当前分辨率
在桌面系统打开终端,运行如下命令查看当前分辨率:
root@rk3399:/data# xrandr
Screen 0: minimum 320 x 200, current 1920 x 1080, maximum 4096 x 4096
HDMI-1 connected primary 1920x1080+0+0 (normal left inverted right x axis y axis) 697mm x 392mm
1920x1080 60.00 60.00* 50.00
1920x1080i 60.00 50.00
1600x900 60.00
1280x1024 60.02
1280x720 60.00 50.00
1024x768 60.00
800x600 60.32 56.25
可以看到当前分辨率为1920x1080
,实际上我们从edid
信息中了解到我们使用的hdmi
显示器的最佳时序是2560x1440@120Hz
。
然而这里默认确是1920x1080
,这主要是因为我们的驱动中并没有支持2560x1440
的分辨率。因此我们需要新增2560x1440
分辨率时序。
2.4.2 设置分辨率
如果要设置分辨率为1600X9000@60Hz
,在桌面系统终端运行如下命令:
root@rk3399:/# xrandr --output HDMI-1 --mode 1600x900 --refresh 60
2.4.3 设置HDMI
输出边界
For example, the transformation scaling horizontal coordinates by 0.8, vertical coordinates by 1.04 and moving the screen by 35 pixels right and 19 pixels down
:
root@rk3399:/# xrandr --output HDMI-1 --transform 0.80,0,-35,0,1.04,-19,0,0,1
2.5 modetest
安装modetest
root@rk3399:/# cd /data/
root@rk3399:/data# wget https://gitlab.freedesktop.org/mesa/drm/-/archive/libdrm-2.4.105/drm-libdrm-2.4.105.tar.gz
root@rk3399:/data# tar -zvxf drm-libdrm-2.4.105.tar.gz
root@rk3399:/data# apt-get install meson
root@rk3399:/data# cd drm-libdrm-2.4.105
root@rk3399:/data/drm-libdrm-2.4.105# meson builddir/
root@rk3399:/data/drm-libdrm-2.4.105# ninja -C builddir install
root@rk3399:/data/drm-libdrm-2.4.105# cp builddir/tests/modetest/modetest /usr/bin/
查看帮助信息:
root@rk3399:/data/drm-libdrm-2.4.105# modetest -h
usage: modetest [-acDdefMPpsCvrw]
Query options:
-c list connectors
-e list encoders
-f list framebuffers
-p list CRTCs and planes (pipes)
Test options:
-P <plane_id>@<crtc_id>:<w>x<h>[+<x>+<y>][*<scale>][@<format>] set a plane
-s <connector_id>[,<connector_id>][@<crtc_id>]:[#<mode index>]<mode>[-<vrefresh>][@<format>] set a mode
-C test hw cursor
-v test vsynced page flipping
-r set the preferred mode for all connectors
-w <obj_id>:<prop_name>:<value> set property
-a use atomic API
-F pattern1,pattern2 specify fill patterns
Generic options:
-d drop master after mode set
-M module use the given driver
-D device use the given device
Default is to dump all info.
2.5.1 modetest -c
查看connector
的信息:
root@rk3399:/# modetest -c
trying to open device 'i915'...failed
trying to open device 'amdgpu'...failed
trying to open device 'radeon'...failed
trying to open device 'nouveau'...failed
trying to open device 'vmwgfx'...failed
trying to open device 'omapdrm'...failed
trying to open device 'exynos'...failed
trying to open device 'tilcdc'...failed
trying to open device 'msm'...failed
trying to open device 'sti'...failed
trying to open device 'tegra'...failed
trying to open device 'imx-drm'...failed
trying to open device 'rockchip'...failed
trying to open device 'atmel-hlcdc'...failed
trying to open device 'fsl-dcu-drm'...failed
trying to open device 'vc4'...failed
trying to open device 'virtio_gpu'...failed
trying to open device 'mediatek'...failed
trying to open device 'meson'...failed
trying to open device 'pl111'...failed
trying to open device 'stm'...failed
trying to open device 'sun4i-drm'...failed
trying to open device 'armada-drm'...failed
trying to open device 'komeda'...failed
trying to open device 'imx-dcss'...failed
trying to open device 'mxsfb-drm'...failed
no device found
modetest
测试失败,原因:/dev/dri/card0
被占用。需要关闭系统原有的显示进程,方法:
root@rk3399:/# ps -A | grep Xorg # 显示进程
4828 tty2 00:00:06 Xorg
root@rk3399:/# killall Xorg & modetest -M rockchip -c # 如果一次没有kill Xorg成功,多试几次
[1] 6726
Connectors:
id encoder status name size (mm) modes encoders
52 51 connected HDMI-A-1 0x0 12 51
modes:
index name refresh (Hz) hdisp hss hse htot vdisp vss vse vtot
#0 1920x1080 60.00 1920 2008 2052 2200 1080 1082 1087 1125 148500 flags: phsync, pvsync; type: driver
#1 1920x1080 60.00 1920 2008 2052 2200 1080 1084 1089 1125 148500 flags: phsync, pvsync; type: driver
#2 1920x1080i 30.00 1920 2008 2052 2200 1080 1084 1094 1125 74250 flags: phsync, pvsync, interlace; type: driver
#3 1920x1080 50.00 1920 2448 2492 2640 1080 1084 1089 1125 148500 flags: phsync, pvsync; type: driver
#4 1920x1080i 25.00 1920 2448 2492 2640 1080 1084 1094 1125 74250 flags: phsync, pvsync, interlace; type: driver
#5 1600x900 60.00 1600 1624 1704 1800 900 901 904 1000 108000 flags: phsync, pvsync; type: driver
#6 1280x1024 60.02 1280 1328 1440 1688 1024 1025 1028 1066 108000 flags: phsync, pvsync; type: driver
#7 1280x720 60.00 1280 1390 1430 1650 720 725 730 750 74250 flags: phsync, pvsync; type: driver
#8 1280x720 50.00 1280 1720 1760 1980 720 725 730 750 74250 flags: phsync, pvsync; type: driver
#9 1024x768 60.00 1024 1048 1184 1344 768 771 777 806 65000 flags: nhsync, nvsync; type: driver
#10 800x600 60.32 800 840 968 1056 600 601 605 628 40000 flags: phsync, pvsync; type: driver
#11 800x600 56.25 800 824 896 1024 600 601 603 625 36000 flags: phsync, pvsync; type: driver
props:
1 EDID:
flags: immutable blob
blobs:
value:
00ffffffffffff003534000001010101
0020010381000078ee8c75a954459822
1e50542fcf00714081c081809500a9c0
b300d1c0d100d3bc00a0a0a029503020
3500b9882100001a565e00a0a0a02950
30203500b9882100001a67e200a0a0a0
295030203500b9882100001a000000fc
004d45495449414e48414f0a2020010b
02033af24f04051013141f6c6c6c276c
6c6c4b4ce200d5e305c00023097f0783
01000067030c0010003878e606050169
694f67d85dc40176c000023a80187138
2d40582c250058c31000001ed4bc00a0
a0a0295030203500b9882100001e98e2
00a0a0a0295030203500b9882100001e
000000000000000000000000000000c4
2 DPMS:
flags: enum
enums: On=0 Standby=1 Suspend=2 Off=3
value: 0
5 link-status:
flags: enum
enums: Good=0 Bad=1
value: 0
6 non-desktop:
flags: immutable range
values: 0 1
value: 0
4 TILE:
flags: immutable blob
blobs:
value:
53 max bpc:
flags: range
values: 8 16
value: 0
7 HDR_OUTPUT_METADATA:
flags: blob
blobs:
value:
可以看到connector
只有一个,其中:
modes
是和当前connector
关联的modes
个数,当前为12个;encoders
是和当前connector
关联的encoders
列表,如果有多个会按逗号分隔。当前只有id
为51
的encoder
;
2.5.2 modetest -e
输出当前内核的encoders
,可以看到encoder
只有一个,id
为51
,其连接的crtc
为37
;
root@rk3399:/# killall Xorg & modetest -M rockchip -e
[1] 6184
Encoders:
id crtc type possible crtcs possible clones
51 37 TMDS 0x00000003 0x00000001
possible_crtcs
通常是驱动在是初始化encoder
同时直接设置的,比如dw_hdmi_rockchip_bind
函数中:
static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
void *data)
{
......
encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
......
}
2.5.3 modetest -p
输出当前内核的crtc
和plane
,从输出信息可以看到有两个CRTC
,分别对应vopb
和vopl
;
root@rk3399:/# killall Xorg & modetest -M rockchip -p
[1] 5990
CRTCs:
id fb pos size
37 54 (0,0) (1920x1080)
#0 1920x1080 60.00 1920 2008 2052 2200 1080 1082 1087 1125 148500 flags: phsync, pvsync; type: driver
props:
24 VRR_ENABLED:
flags: range
values: 0 1
value: 0
28 GAMMA_LUT:
flags: blob
blobs:
value:
00000000000000000001000100010000
00020002000200000003000300030000
......
80fa80fa80fa000080fb80fb80fb0000
80fc80fc80fc000080fd80fd80fd0000
80fe80fe80fe0000c0ffc0ffc0ff0000
29 GAMMA_LUT_SIZE:
flags: immutable range
values: 0 4294967295
value: 256
44 0 (0,0) (0x0)
#0 nan 0 0 0 0 0 0 0 0 0 flags: ; type:
props:
24 VRR_ENABLED:
flags: range
values: 0 1
value: 0
28 GAMMA_LUT:
flags: blob
blobs:
value:
29 GAMMA_LUT_SIZE:
flags: immutable range
values: 0 4294967295
value: 1024
Planes:
id crtc fb CRTC x,y x,y gamma size possible crtcs
31 37 54 0,0 0,0 0 0x00000001
formats: XR24 AR24 XB24 AB24 RG24 BG24 RG16 BG16 NV12 NV21 NV16 NV61 NV24 NV42
props:
8 type:
flags: immutable enum
enums: Overlay=0 Primary=1 Cursor=2
value: 1
30 IN_FORMATS:
flags: immutable blob
blobs:
value:
01000000000000000e00000018000000
01000000500000005852323441523234
58423234414232345247323442473234
52473136424731364e5631324e563231
4e5631364e5636314e5632344e563432
ff3f0000000000000000000000000000
0000000000000000
in_formats blob decoded:
XR24: LINEAR
AR24: LINEAR
XB24: LINEAR
AB24: LINEAR
RG24: LINEAR
BG24: LINEAR
RG16: LINEAR
BG16: LINEAR
NV12: LINEAR
NV21: LINEAR
NV16: LINEAR
NV61: LINEAR
NV24: LINEAR
NV42: LINEAR
33 rotation:
flags: bitmask
values: rotate-0=0x1 reflect-x=0x10 reflect-y=0x20
value: 1
34 0 0 0,0 0,0 0 0x00000001
formats: XR24 AR24 XB24 AB24 RG24 BG24 RG16 BG16
props:
8 type:
flags: immutable enum
enums: Overlay=0 Primary=1 Cursor=2
value: 2
30 IN_FORMATS:
flags: immutable blob
blobs:
value:
01000000000000000800000018000000
01000000380000005852323441523234
58423234414232345247323442473234
5247313642473136ff00000000000000
00000000000000000000000000000000
in_formats blob decoded:
XR24: LINEAR
AR24: LINEAR
XB24: LINEAR
AB24: LINEAR
RG24: LINEAR
BG24: LINEAR
RG16: LINEAR
BG16: LINEAR
36 rotation:
flags: bitmask
values: rotate-0=0x1 reflect-y=0x20
value: 1
38 0 0 0,0 0,0 0 0x00000002
formats: XR24 AR24 XB24 AB24 RG24 BG24 RG16 BG16 NV12 NV21 NV16 NV61 NV24 NV42
props:
8 type:
flags: immutable enum
enums: Overlay=0 Primary=1 Cursor=2
value: 1
30 IN_FORMATS:
flags: immutable blob
blobs:
value:
01000000000000000e00000018000000
02000000500000005852323441523234
58423234414232345247323442473234
52473136424731364e5631324e563231
4e5631364e5636314e5632344e563432
ff000000000000000000000000000000
5100000000000008ff3f000000000000
00000000000000000000000000000000
in_formats blob decoded:
XR24: (UNKNOWN MODIFIER) LINEAR
AR24: (UNKNOWN MODIFIER) LINEAR
XB24: (UNKNOWN MODIFIER) LINEAR
AB24: (UNKNOWN MODIFIER) LINEAR
RG24: (UNKNOWN MODIFIER) LINEAR
BG24: (UNKNOWN MODIFIER) LINEAR
RG16: (UNKNOWN MODIFIER) LINEAR
BG16: (UNKNOWN MODIFIER) LINEAR
NV12: LINEAR
NV21: LINEAR
NV16: LINEAR
NV61: LINEAR
NV24: LINEAR
NV42: LINEAR
40 rotation:
flags: bitmask
values: rotate-0=0x1 reflect-x=0x10 reflect-y=0x20
value: 1
41 0 0 0,0 0,0 0 0x00000002
formats: XR24 AR24 XB24 AB24 RG24 BG24 RG16 BG16
props:
8 type:
flags: immutable enum
enums: Overlay=0 Primary=1 Cursor=2
value: 2
30 IN_FORMATS:
flags: immutable blob
blobs:
value:
01000000000000000800000018000000
01000000380000005852323441523234
58423234414232345247323442473234
5247313642473136ff00000000000000
00000000000000000000000000000000
in_formats blob decoded:
XR24: LINEAR
AR24: LINEAR
XB24: LINEAR
AB24: LINEAR
RG24: LINEAR
BG24: LINEAR
RG16: LINEAR
BG16: LINEAR
43 rotation:
flags: bitmask
values: rotate-0=0x1 reflect-y=0x20
value: 1
45 0 0 0,0 0,0 0 0x00000002
formats: XR24 AR24 XB24 AB24 RG24 BG24 RG16 BG16 NV12 NV21 NV16 NV61 NV24 NV42
props:
8 type:
flags: immutable enum
enums: Overlay=0 Primary=1 Cursor=2
value: 0
30 IN_FORMATS:
flags: immutable blob
blobs:
value:
01000000000000000e00000018000000
01000000500000005852323441523234
58423234414232345247323442473234
52473136424731364e5631324e563231
4e5631364e5636314e5632344e563432
ff3f0000000000000000000000000000
0000000000000000
in_formats blob decoded:
XR24: LINEAR
AR24: LINEAR
XB24: LINEAR
AB24: LINEAR
RG24: LINEAR
BG24: LINEAR
RG16: LINEAR
BG16: LINEAR
NV12: LINEAR
NV21: LINEAR
NV16: LINEAR
NV61: LINEAR
NV24: LINEAR
NV42: LINEAR
47 rotation:
flags: bitmask
values: rotate-0=0x1 reflect-x=0x10 reflect-y=0x20
value: 1
48 0 0 0,0 0,0 0 0x00000002
formats: XR24 AR24 XB24 AB24 RG24 BG24 RG16 BG16
props:
8 type:
flags: immutable enum
enums: Overlay=0 Primary=1 Cursor=2
value: 0
30 IN_FORMATS:
flags: immutable blob
blobs:
value:
01000000000000000800000018000000
01000000380000005852323441523234
58423234414232345247323442473234
5247313642473136ff00000000000000
00000000000000000000000000000000
in_formats blob decoded:
XR24: LINEAR
AR24: LINEAR
XB24: LINEAR
AB24: LINEAR
RG24: LINEAR
BG24: LINEAR
RG16: LINEAR
BG16: LINEAR
50 rotation:
flags: bitmask
values: rotate-0=0x1 reflect-y=0x20
value: 1
2.5.4 设置分辨率
在modetest
中通过id
来引用encoder
/ connector
/ CRTC
/ plane
,查看个组件的id
;
root@rk3399:/# modetest -M rockchip | cut -f1 | grep -E ^[0-9A-Z]\|id
Encoders:
id
51
Connectors:
id
52
CRTCs:
id
37
44
Planes:
id
31
34
38
41
45
48
Frame buffers:
id
更改分辨率为1600x900@60Hz
;
root@rk3399:/# killall Xorg & modetest -M rockchip -s 52@37:1600x900-60 # 正常情况下 在对应屏幕会有彩色条纹显示
其中:
52
:HDMI connector id
;37
: 某个vop
的crtc id
;1600x900
:显示 模式;60
:刷新率;
如果出现如下错误:
failed to set mode: Permission denied
大概率是有进程占用了drm
设备;
root@rk3399:~# ps -ef | grep display
gdm 5967 5899 0 13:48 tty1 00:00:00 /usr/bin/Xwayland :1024 -rootless -noreset -accessx -core -auth /run/user/127/.mutter-Xwaylandauth.WK5EE2 -listen 4 -listen 5 -displayfd 6 -listen 7
root@rk3399:~# kill -9 5967
root@rk3399:~# killall Xorg & modetest -M rockchip -s 52@37:1920x1080-60 # 可以正常显示
[1] 6413
Xorg: no process found
setting mode 1920x1080-60.00Hz on connectors 52, crtc 37
root@rk3399:~# killall Xorg & modetest -M rockchip -s 52@37:1600x900 # 可以正常显示
root@rk3399:~# killall Xorg & modetest -M rockchip -s 52@37:1280x1024 # 可以正常显示
root@rk3399:~# killall Xorg & modetest -M rockchip -s 52@37:1280x720 # 可以正常显示
root@rk3399:~# killall Xorg & modetest -M rockchip -s 52@37:1024x768 # 可以正常显示
root@rk3399:~# killall Xorg & modetest -M rockchip -s 52@37:800x600 # 无法显示
正常情况下在对应屏幕会有彩色条纹显示;
![](https://gitee.com/zyly2033/blog-pic/raw/master/202311191353584.png)
2.6 查看调试信息
DRM
子系统内核debug
日志位于/sys/kernel/debug/dri/
:
root@rk3399:~# ll /sys/kernel/debug/dri/
drwxr-xr-x 5 root root 0 Jan 1 1970 0/
drwxr-xr-x 2 root root 0 Jan 1 1970 1/
drwxr-xr-x 2 root root 0 Jan 1 1970 128/
root@rk3399:~# ll /sys/kernel/debug/dri/0/
drwxr-xr-x 2 root root 0 Jan 1 1970 HDMI-A-1/
-r--r--r-- 1 root root 0 Jan 1 1970 clients
drwxr-xr-x 3 root root 0 Jan 1 1970 crtc-0/
drwxr-xr-x 3 root root 0 Jan 1 1970 crtc-1/
-r--r--r-- 1 root root 0 Jan 1 1970 framebuffer
-r--r--r-- 1 root root 0 Jan 1 1970 gem_names
-r--r--r-- 1 root root 0 Jan 1 1970 internal_clients
-r--r--r-- 1 root root 0 Jan 1 1970 name
-r--r--r-- 1 root root 0 Jan 1 1970 state
2.6.1 查看设备名称
root@rk3399:~# cat /sys/kernel/debug/dri/0/name
rockchip dev=display-subsystem unique=display-subsystem
2.6.2 查看framebuffer
查看framebuffer
信息:
root@rk3399:/# cat /sys/kernel/debug/dri/0/framebuffer
framebuffer[56]:
allocated by = Xorg
refcount=2
format=XR24 little-endian (0x34325258)
modifier=0x0
size=1920x1080
layers:
size[0]=1920x1080
pitch[0]=7680
offset[0]=0
obj[0]:
name=0
refcount=5
start=00000000
size=8294400
imported=no
framebuffer[58]:
allocated by = Xorg
refcount=1
format=AR24 little-endian (0x34325241)
modifier=0x0
size=64x64
layers:
size[0]=64x64
pitch[0]=256
offset[0]=0
obj[0]:
name=0
refcount=3
start=00100004
size=16384
imported=no
framebuffer[54]:
allocated by = [fbcon]
refcount=1
format=XR24 little-endian (0x34325258)
modifier=0x0
size=1920x1080
layers:
size[0]=1920x1080
pitch[0]=7680
offset[0]=0
obj[0]:
name=0
refcount=2
start=00000000
size=8294400
imported=no
三、新增特殊分辨率时序
DRM
框架目前代码已经支持了绝大部分分辨率时序,但是还有一些特殊分辨率不支持,如果我们想支持更多的Standard Timings
,那么就需要在 drivers/gpu/drm/drm_edid.c
中的drm_dmt_modes
的末尾新增项目。
以drm_dmt_modes
最后一项为例介绍:
/*
* Autogenerated from the DMT spec.
* This table is copied from xfree86/modes/xf86EdidModes.c.
*/
static const struct drm_display_mode drm_dmt_modes[] = {
......
/* 0x4d - 2560x1600@60Hz */
{ DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 348500, 2560, 2752,
3032, 3504, 0, 1600, 1603, 1609, 1658, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
.....
/* 0x58 - 4096x2160@59.94Hz 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
:display mode name
,为分辨率的名字,命名规则为%dx%d%s
;- 第一个参数为:
mode->hdisplay
; - 第二个参数为:
mode->vdisplay
; - 第三个参数为:
i/''
(如果是隔行扫描,则为i
);
- 第一个参数为:
-
DRM_MODE_TYPE_DRIVER
:display mode type
,配置为DRM_MODE_TYPE_DRIVER
; -
556188
:clock
,像素时钟频率,单位为kHz
; -
4096
:hdisplay
,行有效像素; -
4104
:hsync_start
,行同步起始像素; -
4136
:hsync_end
,行同步结束像素; -
4176
:htotal
,行总大小; -
0
:hskew
,行偏差,通常为0
; -
2160
:vdisplay
,帧有效行; -
2208
:vsync_start
,帧同步起始行; -
2216
:vsync_end
,帧同步结束行; -
2222
:vtotal
,一帧总行数; -
0
:vscan
, 帧扫描信号,通常为0
; -
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC
:flags
,hsync
和vsync
极性;
具体时序说明见下图:
![img](https://gitee.com/zyly2033/blog-pic/raw/master/202311191116781.png)
更多细节参考文章:《Rockchip RK3399 - DRM crtc
基础知识》。
这里我们的目标是使内核支持2560x1440@60Hz
的分辨率,至于刷新率为啥是60Hz
、是因为我们使用的EK3399 hdmi
接口支持的最大输出为:
VOP BIG::4096X2160@60hz
VOP LITE: 2560x1600@60hz
3.1 修改drm_dmt_modes
定位到drivers/gpu/drm/drm_edid.c
,修改drm_dmt_modes
在数组最后新增:
/* 0x59 - 2560x1440@60Hz */
{ DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 241500, 2560, 2608,
2640, 2720, 0, 1440, 1443, 1448, 1481, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
这里的信息来自edid
信息中的Detailed Timings
。
3.2 修改rockchip_mpll_cfg
定位到drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
,修改rockchip_mpll_cfg
数组,由于我们拿不到有关HDMI phy
的datasheet
,所以我去参考了官方提供的linux-4.19
内核源码,将整个rockchip_mpll_cfg
拷贝过来:
static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = {
{
30666000, {
{ 0x00b3, 0x0000 },
{ 0x2153, 0x0000 },
{ 0x40f3, 0x0000 },
},
}, {
36800000, {
{ 0x00b3, 0x0000 },
{ 0x2153, 0x0000 },
{ 0x40a2, 0x0001 },
},
}, {
46000000, {
{ 0x00b3, 0x0000 },
{ 0x2142, 0x0001 },
{ 0x40a2, 0x0001 },
},
}, {
61333000, {
{ 0x0072, 0x0001 },
{ 0x2142, 0x0001 },
{ 0x40a2, 0x0001 },
},
}, {
73600000, {
{ 0x0072, 0x0001 },
{ 0x2142, 0x0001 },
{ 0x4061, 0x0002 },
},
}, {
92000000, {
{ 0x0072, 0x0001 },
{ 0x2145, 0x0002 },
{ 0x4061, 0x0002 },
},
}, {
122666000, {
{ 0x0051, 0x0002 },
{ 0x2145, 0x0002 },
{ 0x4061, 0x0002 },
},
}, {
147200000, {
{ 0x0051, 0x0002 },
{ 0x2145, 0x0002 },
{ 0x4064, 0x0003 },
},
}, {
184000000, {
{ 0x0051, 0x0002 },
{ 0x214c, 0x0003 },
{ 0x4064, 0x0003 },
},
}, {
226666000, {
{ 0x0040, 0x0003 },
{ 0x214c, 0x0003 },
{ 0x4064, 0x0003 },
},
}, {
272000000, {
{ 0x0040, 0x0003 },
{ 0x214c, 0x0003 },
{ 0x5a64, 0x0003 },
},
}, {
340000000, {
{ 0x0040, 0x0003 },
{ 0x3b4c, 0x0003 },
{ 0x5a64, 0x0003 },
},
}, {
600000000, {
{ 0x1a40, 0x0003 },
{ 0x3b4c, 0x0003 },
{ 0x5a64, 0x0003 },
},
}, {
~0UL, {
{ 0x0000, 0x0000 },
{ 0x0000, 0x0000 },
{ 0x0000, 0x0000 },
},
}
};
这里我们将linux-6.3
内核中的rockchip_mpll_cfg
合并进来:
static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = {
{
27000000, {
{ 0x00b3, 0x0000},
{ 0x2153, 0x0000},
{ 0x40f3, 0x0000}
},
}, {
30666000, {
{ 0x00b3, 0x0000 },
{ 0x2153, 0x0000 },
{ 0x40f3, 0x0000 },
},
}, {
36000000, { // 适用于drm_dmt_modes中定义的预定义的标准显示模式:800x600@56Hz 640x480@85Hz;适用于edid_est_modes中定义的显示模式:800x600@56Hz
{ 0x00b3, 0x0000},
{ 0x2153, 0x0000},
{ 0x40f3, 0x0000}
},
}, {
36800000, {
{ 0x00b3, 0x0000 },
{ 0x2153, 0x0000 },
{ 0x40a2, 0x0001 },
},
}, {
40000000, { // 适用于drm_dmt_modes中定义的预定义的标准显示模式:800x600@60Hz;适用于edid_est_modes中定义的显示模式:800x600@60Hz
{ 0x00b3, 0x0000},
{ 0x2153, 0x0000},
{ 0x40f3, 0x0000}
},
}, {
46000000, {
{ 0x00b3, 0x0000 },
{ 0x2142, 0x0001 },
{ 0x40a2, 0x0001 },
},
}, {
54000000, {
{ 0x0072, 0x0001},
{ 0x2142, 0x0001},
{ 0x40a2, 0x0001},
},
}, {
61333000, {
{ 0x0072, 0x0001 },
{ 0x2142, 0x0001 },
{ 0x40a2, 0x0001 },
},
}, {
65000000, { // 适用于edid_est_modes中定义的显示模式:1024x768@70Hz
{ 0x0072, 0x0001},
{ 0x2142, 0x0001},
{ 0x40a2, 0x0001},
},
}, {
66000000, {
{ 0x013e, 0x0003},
{ 0x217e, 0x0002},
{ 0x4061, 0x0002}
},
}, {
73600000, {
{ 0x0072, 0x0001 },
{ 0x2142, 0x0001 },
{ 0x4061, 0x0002 },
},
}, {
74250000, { // 适用于drm_dmt_modes中定义的预定义的标准显示模式:1280x720@60Hz
{ 0x0072, 0x0001},
{ 0x2145, 0x0002},
{ 0x4061, 0x0002}
},
}, {
83500000, { // 适用于drm_dmt_modes中定义的预定义的标准显示模式:1280x800@60Hz
{ 0x0072, 0x0001},
},
}, {
92000000, {
{ 0x0072, 0x0001 },
{ 0x2145, 0x0002 },
{ 0x4061, 0x0002 },
},
}, {
108000000, { // 适用于drm_dmt_modes中定义的预定义的标准显示模式:1600x900@60Hz 1280x1024@60Hz 1152x864@75Hz 1280x960@60Hz;适用于edid_est_modes中定义的显示模式:1152x864@75Hz
{ 0x0051, 0x0002},
{ 0x2145, 0x0002},
{ 0x4061, 0x0002}
},
}, {
106500000, { // 适用于drm_dmt_modes中定义的预定义的标准显示模式:1440x900@60Hz、1280x800@75Hz
{ 0x0051, 0x0002},
{ 0x2145, 0x0002},
{ 0x4061, 0x0002}
},
}, {
122666000, {
{ 0x0051, 0x0002 },
{ 0x2145, 0x0002 },
{ 0x4061, 0x0002 },
},
}, {
146250000, { // 适用于drm_dmt_modes中定义的预定义的标准显示模式:1680x1050@60Hz 1280x800@120Hz RB
{ 0x0051, 0x0002},
{ 0x2145, 0x0002},
{ 0x4061, 0x0002}
},
}, {
147200000, {
{ 0x0051, 0x0002 },
{ 0x2145, 0x0002 },
{ 0x4064, 0x0003 },
},
}, {
148500000, { // 适用于drm_dmt_modes中定义的预定义的标准显示模式:1920x1080@60Hz 1280x960@85Hz
{ 0x0051, 0x0003},
{ 0x214c, 0x0003},
{ 0x4064, 0x0003}
},
}, {
184000000, {
{ 0x0051, 0x0002 },
{ 0x214c, 0x0003 },
{ 0x4064, 0x0003 },
},
}, {
226666000, {
{ 0x0040, 0x0003 },
{ 0x214c, 0x0003 },
{ 0x4064, 0x0003 },
},
}, {
272000000, {
{ 0x0040, 0x0003 },
{ 0x214c, 0x0003 },
{ 0x5a64, 0x0003 },
},
}, {
340000000, {
{ 0x0040, 0x0003 },
{ 0x3b4c, 0x0003 },
{ 0x5a64, 0x0003 },
},
}, {
600000000, {
{ 0x1a40, 0x0003 },
{ 0x3b4c, 0x0003 },
{ 0x5a64, 0x0003 },
},
}, {
~0UL, {
{ 0x0000, 0x0000 },
{ 0x0000, 0x0000 },
{ 0x0000, 0x0000 },
},
}
};
同时需要新增像素时钟频率241500000
,我在272000000
之前新增:
{
241500000, {
{ 0x0040, 0x0003 },
{ 0x214c, 0x0003 },
{ 0x4064, 0x0003 },
},
},
需要注意:该配置是个人猜测的,后面我们会验证是否存在问题。
3.3 修改rockchip_cur_ctr
定位到drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
,如果我们的像素时钟频率小于rockchip_cur_ctr
中最大的像素时钟频率则跳过这一步。
由于rockchip_cur_ctr
中支持的最大像素时钟频率为148500000
,小于241500000
,因此修改rockchip_cur_ctr
数组,在148500000
之后新增新的像素时钟频率配置.
由于我们拿不到有关HDMI phy
的datasheet
,所以我去参考了官方提供的linux-4.19
内核源码,将整个rockchip_cur_ctr
拷贝过来:
static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = {
/* pixelclk bpp8 bpp10 bpp12 */
{
600000000, { 0x0000, 0x0000, 0x0000 },
}, {
~0UL, { 0x0000, 0x0000, 0x0000},
}
};
这里我们将linux-6.3
内核中的rockchip_cur_ctr
合并进来:
static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = {
/* pixelclk bpp8 bpp10 bpp12 */
{
40000000, { 0x0018, 0x0018, 0x0018 },
}, {
65000000, { 0x0028, 0x0028, 0x0028 },
}, {
66000000, { 0x0038, 0x0038, 0x0038 },
}, {
74250000, { 0x0028, 0x0038, 0x0038 },
}, {
83500000, { 0x0028, 0x0038, 0x0038 },
}, {
146250000, { 0x0038, 0x0038, 0x0038 },
}, {
148500000, { 0x0000, 0x0038, 0x0038 },
}, {
600000000, { 0x0000, 0x0000, 0x0000 },
}, {
~0UL, { 0x0000, 0x0000, 0x0000},
}
};
3.4 修改rockchip_phy_config
定位到drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
,如果我们的像素时钟频率小于rockchip_phy_config
中最大的像素时钟频率则跳过这一步。
由于我们的目标像素时钟频率241500000
低于rockchip_phy_config
中的最大像素时钟频率297000000
,因此该项可以不用配置了。
不过这里我去参考了官方提供的linux-4.19
内核源码,将整个rockchip_phy_config
拷贝过来:
static struct dw_hdmi_phy_config rockchip_phy_config[] = {
/*pixelclk symbol term vlev*/
{ 74250000, 0x8009, 0x0004, 0x0272},
{ 165000000, 0x802b, 0x0004, 0x0209},
{ 297000000, 0x8039, 0x0005, 0x028d},
{ 594000000, 0x8039, 0x0000, 0x019d},
{ ~0UL, 0x0000, 0x0000, 0x0000},
};
这里我们将linux-6.3
内核中的rockchip_phy_config
合并进来:
static struct dw_hdmi_phy_config rockchip_phy_config[] = {
/*pixelclk symbol term vlev*/
{ 74250000, 0x8009, 0x0004, 0x0272},
{ 148500000, 0x802b, 0x0004, 0x028d},
{ 165000000, 0x802b, 0x0004, 0x0209},
{ 297000000, 0x8039, 0x0005, 0x028d},
{ 594000000, 0x8039, 0x0000, 0x019d},
{ ~0UL, 0x0000, 0x0000, 0x0000},
};
3.5 测试
重新编译内核并烧录,此时执行cat /sys/class/drm/card0-HDMI-A-1/modes
命令:
root@rk3399:/# cat /sys/class/drm/card0-HDMI-A-1/modes
2560x1440
1920x1080
1920x1080
1920x1080
1920x1080i
1920x1080
1920x1080
1920x1080i
1600x900
1280x1024
1280x720
1280x720
1280x720
1024x768
800x600
800x600
此时固然可以看到分辨率2560x1440
,但是hdmi
显示器确无法正常工作,不难猜测应该是我配置的rockchip_mpll_cfg
、rockchip_cur_ctr
有问题,因此我将之前我追加的这些配置最终移除了,至于如何配置可以联系fae@rock-chips.com
咨询。
参考文章
[1] [Rockchip_Developer_Guide_HDMI_CN
]
[3] LVDS+HDMI
输出特殊分辨率800*1280
竖屏
[5] EDID
的简介和解析