DISPLAY(1)——RK3399 HDMI接口了解

文章的主要目的是为了记录,其次希望自己做的东西越来越多以后,可以把这些东西整合、重塑,让自己的知识体系更加的立体、完整

参考文档

https://blog.csdn.net/dahailinan/article/details/111309692
https://blog.csdn.net/qq_30624591/article/details/106840966
https://blog.csdn.net/m0_38022615/article/details/109378391

涉及文件

kernel/drivers/gpu/drm/drm_edid.c
kernel/drivers/gpu/drm/rockchip/inno_hdmi.c
kernel/drivers/gpu/drm/rockchip/inno_hdmi.h
kernel/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
kernel/drivers/video/rockchip/hdmi/rockchip-hdmi.h
kernel/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c

device/rockchip/rk3399/rk3399_all/system.prop
frameworks/base/services/core/jni/com_android_server_rkdisplay_RkDisplayModes.cpp

kernel部分代码

edid相关代码

kernel/drivers/gpu/drm/drm_edid.c
/*
 * Probably taken from CEA-861 spec.
 * This table is converted from xorg's hw/xfree86/modes/xf86EdidModes.c.
 *
 * Index using the VIC.
 */
static const struct drm_display_mode edid_cea_modes[] = {
...
        /* 5 - 1920x1080i@60Hz */
        { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008,
                   2052, 2200, 0, 1080, 1084, 1094, 1125, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
                        DRM_MODE_FLAG_INTERLACE),
          .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
...

------------------
drm_add_edid_modes
	add_detailed_modes
		do_detailed_mode
			drm_mode_detailed
include/drm/drm_edid.h
struct edid {
        u8 header[8];
        /* Vendor & product info */
        u8 mfg_id[2];
        u8 prod_code[2];
        u32 serial; /* FIXME: byte order */
        u8 mfg_week;
        u8 mfg_year;
        /* EDID version */
        u8 version;
        u8 revision;
        /* Display info: */
        u8 input;
        u8 width_cm;
        u8 height_cm;
        u8 gamma;
        u8 features;
        /* Color characteristics */
        u8 red_green_lo;
        u8 black_white_lo;
        u8 red_x;
        u8 red_y;
        u8 green_x;
        u8 green_y;
        u8 blue_x;
        u8 blue_y;
        u8 white_x;
        u8 white_y;
        /* Est. timings and mfg rsvd timings*/
        struct est_timings established_timings;
        /* Standard timings 1-8*/
        struct std_timing standard_timings[8];
        /* Detailing timings 1-4 */
        struct detailed_timing detailed_timings[4];
        /* Number of 128 byte ext. blocks */
        u8 extensions;
        /* Checksum */
        u8 checksum;
} __attribute__((packed));
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
static int dw_hdmi_connector_get_modes(struct drm_connector *connector)
{
        struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
                                             connector);
        struct edid *edid;
        struct drm_display_mode *mode;
        const u8 def_modes[6] = {97, 16, 31, 19, 17, 2};
        struct drm_display_info *info = &connector->display_info;
        struct hdr_static_metadata *metedata =
                        &connector->display_info.hdmi.hdr_panel_metadata;
        int i, ret = 0;

        if (!hdmi->ddc)
                return 0;

        edid = drm_get_edid(connector, hdmi->ddc);
        edid = NULL;
        if (edid) {
                dev_dbg(hdmi->dev, "got edid: width[%d] x height[%d]\n",
                        edid->width_cm, edid->height_cm);

                hdmi->sink_is_hdmi = drm_detect_hdmi_monitor(edid);
                hdmi->sink_has_audio = drm_detect_monitor_audio(edid);
                drm_mode_connector_update_edid_property(connector, edid);
                cec_notifier_set_phys_addr_from_edid(hdmi->cec_notifier, edid);
                ret = drm_add_edid_modes(connector, edid);
                /* Store the ELD */
                drm_edid_to_eld(connector, edid);
                drm_mode_connector_update_hdr_property(connector, metedata);
                kfree(edid);
        } else {
                hdmi->sink_is_hdmi = true;
                hdmi->sink_has_audio = true;
                for (i = 0; i < sizeof(def_modes); i++) {
                        mode = drm_display_mode_from_vic_index(connector,
                                                               def_modes,
                                                               31, i);
                        if (mode) {
                                if (!i)
                                        mode->type = DRM_MODE_TYPE_PREFERRED;
                                drm_mode_probed_add(connector, mode);
                                ret++;
                        }
                }
                info->edid_hdmi_dc_modes = 0;
                info->hdmi.y420_dc_modes = 0;
                info->color_formats = 0;

                dev_info(hdmi->dev, "failed to get edid\n");
        }

        return ret;
}

HDMI 纵横比

查看edid_cea_modes[],我们发现同一个分辨率会对应几个不同的参数结构体,例如:

		/* 97 - 3840x2160p@60Hz 16:9 */
        { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000, 3840, 4016,
                4104, 4400, 0, 2160, 2168, 2178, 2250, 0,
                DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
          .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },

		/* 107 - 3840x2160p@60Hz 64:27 */
        { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000, 3840, 4016,
                4104, 4400, 0, 2160, 2168, 2178, 2250, 0,
                DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
          .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },

显示参数基本相同,唯一的区别在于图像纵横比picture_aspect_ratio,一般有如下几种配置:

HDMI_PICTURE_ASPECT_4_3
HDMI_PICTURE_ASPECT_16_9
HDMI_PICTURE_ASPECT_256_135
HDMI_PICTURE_ASPECT_64_27

该参数需要与屏幕的纵横比相匹配。

热插拔处理逻辑

kernel/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
dw_hdmi_rockchip_bind
	dw_hdmi_bind
kernel/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
int dw_hdmi_bind(struct device *dev, struct device *master,
                 void *data, struct drm_encoder *encoder,
                 struct resource *iores, int irq,
                 const struct dw_hdmi_plat_data *plat_data)
        init_hpd_work(hdmi);
        initialize_hdmi_ih_mutes(hdmi);

        ret = devm_request_threaded_irq(dev, irq, dw_hdmi_hardirq,
                                        dw_hdmi_irq, IRQF_SHARED,
                                        dev_name(dev), hdmi);
init_hpd_work
	INIT_DELAYED_WORK(&hdmi->work, repo_hpd_event);
	repo_hpd_event
devm_request_threaded_irq
	dw_hdmi_hardirq
	dw_hdmi_irq
		check_hdmi_irq

Android部分代码

persist.sys.resolution.main
persist.sys.resolution.aux

static void nativeSaveConfig(JNIEnv* env, jobject obj) {
    char buf[BUFFER_LENGTH];
    bool isMainHdmiConnected=false;
    bool isAuxHdmiConnected = false;
    int foundMainIdx=-1,foundAuxIdx=-1;
    struct file_base_paramer base_paramer;

    if (primary != NULL) {
        std::vector<DrmMode> mModes = primary->modes();
        char resolution[PROPERTY_VALUE_MAX];
        unsigned int w=0,h=0,hsync_start=0,hsync_end=0,htotal=0;
        unsigned int vsync_start=0,vsync_end=0,vtotal=0,flags=0;
        float vfresh=0.0000;

        property_get("persist.sys.resolution.main", resolution, "0x0@0.00-0-0-0-0-0-0-0");
        if (strncmp(resolution, "Auto", 4) != 0 && strncmp(resolution, "0x0p0-0", 7) !=0)
            sscanf(resolution,"%dx%d@%f-%d-%d-%d-%d-%d-%d-%x", &w, &h, &vfresh, &hsync_start,&hsync_end,
                    &htotal,&vsync_start,&vsync_end, &vtotal, &flags);
        for (size_t c = 0; c < mModes.size(); ++c){
            const DrmMode& info = mModes[c];
            char curDrmModeRefresh[16];
            char curRefresh[16];
            float mModeRefresh;
            if (info.flags() & DRM_MODE_FLAG_INTERLACE)
                mModeRefresh = info.clock()*2 / (float)(info.v_total()* info.h_total()) * 1000.0f;
            else
                mModeRefresh = info.clock()/ (float)(info.v_total()* info.h_total()) * 1000.0f;
            sprintf(curDrmModeRefresh, "%.2f", mModeRefresh);
            sprintf(curRefresh, "%.2f", vfresh);
            if (info.h_display() == w &&
                    info.v_display() == h &&
                    info.h_sync_start() == hsync_start &&
                    info.h_sync_end() == hsync_end &&
                    info.h_total() == htotal &&
                    info.v_sync_start() == vsync_start &&
                    info.v_sync_end() == vsync_end &&
                    info.v_total()==vtotal &&
                    atof(curDrmModeRefresh)==atof(curRefresh)) {
                ALOGD("***********************found main idx %d ****************", (int)c);
                foundMainIdx = c;
                sprintf(buf, "display=%d,iface=%d,enable=%d,mode=%s\n",
                        primary->display(), primary->get_type(), primary->state(), resolution);
                break;
            }
        }
    }

    if (extend != NULL) {
        std::vector<DrmMode> mModes = extend->modes();
        char resolution[PROPERTY_VALUE_MAX];
        unsigned int w=0,h=0,hsync_start=0,hsync_end=0,htotal=0;
        unsigned int vsync_start=0,vsync_end=0,vtotal=0,flags;
        float vfresh=0;

        property_get("persist.sys.resolution.aux", resolution, "0x0@0.00-0-0-0-0-0-0-0");
        if (strncmp(resolution, "Auto", 4) != 0 && strncmp(resolution, "0x0p0-0", 7) !=0)
            sscanf(resolution,"%dx%d@%f-%d-%d-%d-%d-%d-%d-%x", &w, &h, &vfresh, &hsync_start,&hsync_end,&htotal,&vsync_start,&vsync_end,
                    &vtotal, &flags);
        for (size_t c = 0; c < mModes.size(); ++c){
            const DrmMode& info = mModes[c];
            char curDrmModeRefresh[16];
            char curRefresh[16];
            float mModeRefresh;
            if (info.flags() & DRM_MODE_FLAG_INTERLACE)
                mModeRefresh = info.clock()*2 / (float)(info.v_total()* info.h_total()) * 1000.0f;
            else
                mModeRefresh = info.clock()/ (float)(info.v_total()* info.h_total()) * 1000.0f;
            sprintf(curDrmModeRefresh, "%.2f", mModeRefresh);
            sprintf(curRefresh, "%.2f", vfresh);
            if (info.h_display() == w &&
                    info.v_display() == h &&
                    info.h_sync_start() == hsync_start &&
                    info.h_sync_end() == hsync_end &&
                    info.h_total() == htotal &&
                    info.v_sync_start() == vsync_start &&
                    info.v_sync_end() == vsync_end &&
                    info.v_total()==vtotal &&
                    atof(curDrmModeRefresh)==atoi(curRefresh)) {
                ALOGD("***********************found aux idx %d ****************", (int)c);
                foundAuxIdx = c;
                break;
            }
        }
    }
    ...
    ...

static void nativeSetMode(JNIEnv* env, jobject obj, jint dpy,jint iface_type, jstring mode)
{
    int display = dpy;
    int type = iface_type;
    const char* mMode = env->GetStringUTFChars(mode, NULL);

    ALOGD("nativeSetMode %s display %d iface_type %d", mMode, display, type);
    if (display == HWC_DISPLAY_PRIMARY){
        property_set("persist.sys.resolution.main", mMode);
    } else if (display == HWC_DISPLAY_EXTERNAL) {
        property_set("persist.sys.resolution.aux", mMode);
    }

}
device/rockchip/rk3399/rk3399_all/system.prop
persist.sys.resolution.aux=3840x2160p30

文件系统相关接口

查看当前HDMI屏分辨率支持列表

# cat /sys/class/drm/card0-HDMI-A-1/modes
3840x2160p60
3840x2160p60
3840x2160p60
...
...
640x480p60
640x480p60
720x400p70

当前的显示分辨率

# cat /sys/class/drm/card0-HDMI-A-1/mode
3840x2160p60

查看EDID信息

# cat sys/class/drm/card0-HDMI-A-1/edid | busybox hexdump
0000000 ff00 ffff ffff 00ff e305 2790 8b64 0000
0000010 1d11 0301 3c80 7822 672a a5a1 4d55 27a2
0000020 500e bf54 00ef c0d1 00b3 0095 8081 4081
...
...
00000e0 5528 5500 2150 0000 4d1e 806c 70a0 3e70
00000f0 3080 3a20 5500 2150 0000 001a 0000 4e00
0000100

强行开关显示设备

关HDMI: echo off > /sys/class/drm/card0-HDMI-A-1/status
开HDMI: echo on > /sys/class/drm/card0-HDMI-A-1/status

VOP的状态

# cat /sys/kernel/debug/dri/0/summary 
VOP [ff900000.vop]: ACTIVE
    Connector: HDMI-A
        overlay_mode[1] bus_format[2025] output_mode[f] color_space[3]
    Display mode: 3840x2160p60
        clk[533250] real_clk[533250] type[48] flag[9]
        H: 3840 3888 3920 4000
        V: 2160 2163 2168 2222
    win0-0: ACTIVE
        format: AR24 little-endian (0x34325241) SDR[0] color_space[0]
        csc: y2r[0] r2r[0] r2y[1] csc mode[1]
        zpos: 0
        src: pos[0x0] rect[3840x2160]
        dst: pos[0x0] rect[3840x2160]
        buf[0]: addr: 0x0000000004000000 pitch: 15360 offset: 0
    win1-0: DISABLED
    win2-0: DISABLED
    win2-1: DISABLED
    win2-2: DISABLED
    win2-3: DISABLED
    win3-0: DISABLED
    win3-1: DISABLED
    win3-2: DISABLED
    win3-3: DISABLED
    post: sdr2hdr[0] hdr2sdr[0]
    pre : sdr2hdr[0]
    post CSC: r2y[0] y2r[0] CSC mode[1]
VOP [ff8f0000.vop]: DISABLED

HDMI当前输出状态

# cat /sys/kernel/debug/dw-hdmi/status 
PHY: enabled                    Mode: HDMI
Pixel Clk: 533250000Hz          TMDS Clk: 133312500Hz
Color Format: YUV444            Color Depth: 8 bit
Colorimetry: ITU.BT709          EOTF: Off

查看HDMI控制寄存器和phy寄存器

[root@rk3399:/]# cat /sys/kernel/debug/dw-hdmi/ctrl 

>>>hdmi_ctl reg   0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
---------------------------------------------------
>>>hdmi_ctl 0000: 21 1a a0 c1 bf 62 f3 00
>>>hdmi_ctl 0100: c2 0b 00 02 00 00 00 74 00 00 00 00 00 00 00 00
>>>hdmi_ctl 0110: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
...
...
>>>hdmi_ctl 7e10: 11 00 24 48 00 00 00 00 00 00 00 00 00 00 00 00
>>>hdmi_ctl 7e20: 00 00 00 00 00 00 00 ba 00 00 00 00 00 00 00 00
>>>hdmi_ctl 7e30: 00 00
---------------------------------------------------
[root@rk3399:/]# cat /sys/kernel/debug/dw-hdmi/phy

>>>hdmi_phy reg
regs 00 val 007f
regs 01 val 003f
...
...
regs 26 val 0004
regs 27 val 0004

可以使用命令来修改寄存器,例如要修改0x1000寄存器为 0xF8,输入命令:

echo 1000 f8 > /sys/kenrel/debug/dw-hdmi/ctrl

修改 PHY 寄存器与控制器类似,例如修改 0x06 寄存器为 0x8002,输入命令:

echo 06 8002 > /sys/kenrel/debug/dw-hdmi/phy

当修改HDMI信号强度等配置是,可以通过查看寄存器来对比前后修改的差异以及验证我们的修改是否生效。

其他功能接口

xrandr指令配置HDMI

$ xrandr
Screen 0: minimum 320 x 200, current 3840 x 2160, maximum 8192 x 8192
HDMI-1 connected primary 3840x2160+0+0 (normal left inverted right x axis y axis) 597mm x 336mm
   3840x2160     60.00*+  60.00    50.00    59.94    30.00    25.00    24.00    29.97    23.98    29.98  
   1920x2160     59.99  
   2560x1440     59.95  
   1920x1080     60.00    50.00    59.94  
   1680x1050     59.88  
   1280x1024     75.02    60.02  
   1440x900      59.90  
   1280x960      60.00  
   1280x720      60.00    50.00    59.94  
   1024x768      75.03    70.07    60.00  
   832x624       74.55  
   800x600       72.19    75.00    60.32    56.25  
   720x576       50.00  
   720x480       60.00    59.94  
   640x480       75.00    72.81    66.67    60.00    59.94  
   720x400       70.08

使用 xrandr 设置不同的分辨率

$ xrandr --output HDMI-1 --mode 3840x2160
$ xrandr --output HDMI-1 --mode 3840x2160 --rate 30
$ xrandr
Screen 0: minimum 320 x 200, current 3840 x 2160, maximum 8192 x 8192
HDMI-1 connected primary 3840x2160+0+0 (normal left inverted right x axis y axis) 597mm x 336mm
   3840x2160     60.00 +  60.00    50.00    59.94    30.00*   25.00    24.00    29.97    23.98    29.98  
   1920x2160     59.99  
   2560x1440     59.95  
   1920x1080     60.00    50.00    59.94  
   1680x1050     59.88  
   1280x1024     75.02    60.02  
   1440x900      59.90  
   1280x960      60.00  
   1280x720      60.00    50.00    59.94  
   1024x768      75.03    70.07    60.00  
   832x624       74.55  
   800x600       72.19    75.00    60.32    56.25  
   720x576       50.00  
   720x480       60.00    59.94  
   640x480       75.00    72.81    66.67    60.00    59.94  
   720x400       70.08

运行gtf或者cvt,查询某分辨率的有效扫描频率

$ gtf 3840 2160 30

  # 3840x2160 @ 30.00 Hz (GTF) hsync: 65.91 kHz; pclk: 339.57 MHz
  Modeline "3840x2160_30.00"  339.57  3840 4080 4496 5152  2160 2161 2164 2197  -HSync +Vsync

$ cvt 3840 2160 30    
# 3840x2160 29.98 Hz (CVT) hsync: 65.96 kHz; pclk: 338.75 MHz
Modeline "3840x2160_30.00"  338.75  3840 4080 4488 5136  2160 2163 2168 2200 -hsync +vsync

通过–newmode参数新建一种xrandr模式

$ xrandr --newmode "3840x2160_30.00" 338.75  3840 4080 4488 5136 2160 2163 2168 2200 -hsync +vsync

新建模式后,我们需要把这模式添加到当前的输出设备HDMI-1

$ xrandr --addmode HDMI-1 3840x2160_30.00

设置该模式输出

$ xrandr --output HDMI-1 --mode 3840x2160_30.00

相关概念

HDCP

参考链接:
https://blog.csdn.net/qq_45763093/article/details/117552991

HDCP 高带宽数字内容保护技术。

  • 3
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值