How-to: Forcing HDMI Configuration on RK3568

A guide on how to force the HDMI connection status (HPD) and set a fixed resolution via DTS on Rockchip RK3568, bypassing EDID.

How-to: Keep HDMI Connected No Matter What

Schematic:

Analysis: Not controlled by GPIO

  • Setting either hpd-state or force_hpd has no effect.
  • Using display-timings also doesn’t work.
  • The next step would be to consider changing the cmdline… this seems to be the only available method.

Solution (Successful)

Open kernel/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c Modify the function dw_hdmi_phy_read_hpd Change it to the following:

enum drm_connector_status dw_hdmi_phy_read_hpd(struct dw_hdmi *hdmi,void *data)
{
	// return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ?
	// connector_status_connected : connector_status_disconnected;
	return connector_status_connected;
}

How-to: Force HDMI Resolution

Method (Solution)

Open kernel/arch/arm64/boot/dts/rockchip/submodule-display.dtsi Modify the hdmi node (RK3568 only has one HDMI). Modify it as follows (you can add other properties, but the following statements and blocks are mandatory):

&hdmi {
	status = "okay";

	/*
	 * Use 'force-output' to trigger the driver's logic to ignore EDID
	 * and use the 'force-timing' node below.
	 * The properties 'force_hpd' and 'hpd-state' are not standard
	 * for this driver and should be removed.
	 */
	force-output;

	/*
	 * This node provides the specific timing information that the driver
	 * will use when 'force-output' is present.
	 * The name must be "force_timing".
	 */
	force_timing {
		clock-frequency = <148500000>;
		hactive = <1920>;
		vactive = <1080>;
		hfront-porch = <88>;
		hsync-len = <44>;
		hback-porch = <148>;
		vfront-porch = <4>;
		vsync-len = <5>;
		vback-porch = <36>;
		hsync-active = <1>; /* <1> for positive sync, as per standard 1080p60 */
		vsync-active = <1>; /* <1> for positive sync, as per standard 1080p60 */
	};

	/* 'display-timings' is typically used by simple-panel drivers,
	 * not by the dw-hdmi bridge driver for forcing modes.
	 * This section should be removed to avoid confusion.
	 */
	// display-timings { ... };
};

Analysis of the Method

Key Steps

  1. display-timings is not suitable for the Rockchip HDMI driver.
  2. It must be the node force_timing, and the name must be spelled correctly.
  3. You must include force-output; otherwise, the force_timing node will be ignored.

Basis - Source Code - (dw_hdmi-rockchip.c)

  • kernel/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
  • static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi)
  • This function contains the following code snippet:
if (of_property_read_bool(np, "force-output")) {
	hdmi->timing_force_output = true;

	ret = of_get_display_timing(np, "force_timing", &timing);
	if (ret < 0) {
		dev_err(hdmi->dev, "can't get force timing\n");
		hdmi->timing_force_output = false;
		return ret;
	}

	videomode_from_timing(&timing, &vm);
	drm_display_mode_from_videomode(&vm, &hdmi->force_mode);
	hdmi->force_mode.type |= DRM_MODE_TYPE_PREFERRED;

	if (of_property_read_u32(np, "force-bus-format", &hdmi->force_bus_format))
		hdmi->force_bus_format = MEDIA_BUS_FMT_RGB888_1X24;
}

This code shows that if the force-output property is found, the driver then attempts to read the force_timing node. If successful, the kernel will use these forced timings for the display mode setup.

Boot Log

[    3.075190] rockchip-vop2 fe040000.vop: Adding to iommu group 8
[    3.081939] rockchip-vop2 fe040000.vop: [drm:vop2_bind] vp0 assign plane mask: 0x3f, primary plane phy id: 4
[    3.081965] rockchip-vop2 fe040000.vop: [drm:vop2_bind] vp1 assign plane mask: 0x0, primary plane phy id: -1
[    3.081975] rockchip-vop2 fe040000.vop: [drm:vop2_bind] vp2 assign plane mask: 0x0, primary plane phy id: -1
[    3.082097] rockchip-vop2 fe040000.vop: [drm:vop2_bind] Cluster0-win0 as cursor plane for vp0
[    3.082151] rockchip-vop2 fe040000.vop: [drm:vop2_bind] VP1 plane_mask is zero, so ignore register crtc
[    3.082174] rockchip-vop2 fe040000.vop: [drm:vop2_bind] VP2 plane_mask is zero, so ignore register crtc
[    3.082249] [drm] failed to init overlay plane Cluster0-win1
[    3.082288] [drm] failed to init overlay plane Cluster1-win1
[    3.082369] rockchip-drm display-subsystem: bound fe040000.vop (ops 0xffffffc009381478)
[    3.082647] dwhdmi-rockchip fe0a0000.hdmi: Detected HDMI TX controller v2.11a with HDCP (DWC HDMI 2.0 TX PHY)
[    3.083208] dwhdmi-rockchip fe0a0000.hdmi: registered DesignWare HDMI I2C bus driver
[    3.083434] dwhdmi-rockchip fe0a0000.hdmi: IRQ index 1 not found
[    3.083783] rockchip-drm display-subsystem: bound fe0a0000.hdmi (ops 0xffffffc009390598)
[    3.084132] rockchip-drm display-subsystem: route-edp: failed to get logo,offset
[    3.084146] rockchip-drm display-subsystem: route-hdmi: failed to get logo,offset
[    3.084156] rockchip-drm display-subsystem: can't not find any logo display
[    3.084166] rockchip-drm display-subsystem: failed to show kernel logo
[    3.091830] rockchip-vop2 fe040000.vop: [drm:vop2_crtc_atomic_enable] Update mode to 1920x1080p60, type: 11(if:800, flag:0x0) for vp0 dclk: 148500000
[    3.093308] rockchip-drm display-subsystem: [drm] fb0: rockchipdrmfb frame buffer device
[    3.101205] [drm] Initialized rockchip 3.0.0 20140818 for display-subsystem on minor 0
[    3.101392] rockchip-drm display-subsystem: [drm] run display error_event monitor
[    3.106409] input: hdmi_cec_key as /devices/platform/fe0a0000.hdmi/dw-hdmi-cec.1.auto/input/input0

Log - (modetest)

        crtc    type    possible crtcs  possible clones
153     0       Virtual 0x00000001      0x00000001
155     85      TMDS    0x00000001      0x00000002

Connectors:
id      encoder status          name            size (mm)       modes   encoders
156     155     connected       HDMI-A-1        0x0             1       155
  modes:
        index name refresh (Hz) hdisp hss hse htot vdisp vss vse vtot
  #0 1920x1080 60.00 1920 2008 2052 2200 1080 1084 1089 1125 148500 flags: phsync, pvsync; type: preferrd
  props:
        1 EDID:
                flags: immutable blob
                blobs:

                value:
        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:
        157 max bpc:
                flags: range
                values: 8 16
                value: 0
        7 HDR_OUTPUT_METADATA:
                flags: blob
                blobs:

                value:
        158 color_depth:
                flags: enum
                enums: Automatic=0 24bit=8 30bit=10
                value: 8
        159 color_format:
                flags: enum
                enums: rgb=0 ycbcr444=1 ycbcr422=2 ycbcr420=3 ycbcr_high_subsampling=4 ycbcr_low_subsamp6
                value: 0
        160 color_depth_caps:
                flags: range
                values: 0 255
                value: 1
        161 color_format_caps:
                flags: range
                values: 0 15
                value: 1
        162 HDR_PANEL_METADATA:
                flags: immutable blob
                blobs:

                value:
        163 NEXT_HDR_SINK_DATA:
                flags: immutable blob
                blobs:

                value:
        164 output_hdmi_dvi:
                flags: enum
                enums: auto=0 force_hdmi=1 force_dvi=2
                value: 0
        165 output_type_capacity:
                flags: enum
                enums: DVI=0 HDMI=1
                value: 1
        166 hdmi_quant_range:
                flags: enum
                enums: default=0 limit=1 full=2
                value: 0
        167 Colorspace:
                flags: enum
                enums: Default=0 SMPTE_170M_YCC=1 BT709_YCC=2 XVYCC_601=3 XVYCC_709=4 SYCC_601=5 opYCC_62
                value: 0
        168 Content Protection:
                flags: enum
                enums: Undesired=0 Desired=1 Enabled=2
                value: 0
        169 HDCP Content Type:
                flags: enum
                enums: HDCP Type0=0 HDCP Type1=1
                value: 0
        170 hdcp_encrypted:
                flags: range
                values: 0 2
                value: 0
        51 brightness:
                flags: range
                values: 0 100
                value: 50
        52 contrast:
                flags: range
                values: 0 100
                value: 50
        55 saturation:
                flags: range
                values: 0 100
                value: 50
        56 hue:
                flags: range
                values: 0 100
                value: 50
Where can I get the timings to write in the DTS?
  1. Search Google for “Video Timings Calculator” For example: https://tomverbeure.github.io/video_timings_calculator?horiz_pixels=1920&vert_pixels=1080&refresh_rate=60&margins=false&interlaced=false&bpc=8&color_fmt=rgb444&video_opt=false&custom_hblank=80&custom_vblank=6

  2. In the kernel source code For example: drivers/gpu/drm/drm_modes.c