drm: handle HDMI 2.0 VICs in AVI info-frames
authorShashank Sharma <shashank.sharma@intel.com>
Thu, 13 Jul 2017 15:33:07 +0000 (21:03 +0530)
committerVille Syrjälä <ville.syrjala@linux.intel.com>
Fri, 14 Jul 2017 18:23:54 +0000 (21:23 +0300)
HDMI 1.4b support the CEA video modes as per range of CEA-861-D (VIC 1-64).
For any other mode, the VIC filed in AVI infoframes should be 0.
HDMI 2.0 sinks, support video modes range as per CEA-861-F spec, which is
extended to (VIC 1-107).

This patch adds a bool input variable, which indicates if the connected
sink is a HDMI 2.0 sink or not. This will make sure that we don't pass a
HDMI 2.0 VIC to a HDMI 1.4 sink.

This patch touches all drm drivers, who are callers of this function
drm_hdmi_avi_infoframe_from_display_mode but to make sure there is
no change in current behavior, is_hdmi2 is kept as false.

In case of I915 driver, this patch:
- checks if the connected display is HDMI 2.0.
- HDMI infoframes carry one of this two type of information:
- VIC for 4K modes for HDMI 1.4 sinks
- S3D information for S3D modes
  As CEA-861-F has already defined VICs for 4K videomodes, this
  patch doesn't allow sending HDMI infoframes for HDMI 2.0 sinks,
  until the mode is 3D.

Cc: Ville Syrjala <ville.syrjala@linux.intel.com>
Cc: Jose Abreu <jose.abreu@synopsys.com>
Cc: Andrzej Hajda <a.hajda@samsung.com>
Cc: Alex Deucher <alexander.deucher@amd.com>
Cc: Daniel Vetter <daniel.vetter@intel.com>
PS: This patch touches a few lines in few files, which were
already above 80 char, so checkpatch gives 80 char warning again.
- gpu/drm/omapdrm/omap_encoder.c
- gpu/drm/i915/intel_sdvo.c

V2: Rebase, Added r-b from Andrzej
V3: Addressed review comment from Ville:
- Do not send VICs in both AVI-IF and HDMI-IF
  send only one of it.
V4: Rebase
V5: Added r-b from Neil.
    Addressed review comments from Ville
    - Do not block HDMI vendor IF, instead check for VIC while
      handling AVI infoframes
V6: Rebase
V7: Rebase

Reviewed-by: Andrzej Hajda <a.hajda@samsung.com>
Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>
Signed-off-by: Shashank Sharma <shashank.sharma@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1499960000-9232-2-git-send-email-shashank.sharma@intel.com
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
25 files changed:
drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
drivers/gpu/drm/amd/amdgpu/dce_v8_0.c
drivers/gpu/drm/bridge/analogix-anx78xx.c
drivers/gpu/drm/bridge/sii902x.c
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/exynos/exynos_hdmi.c
drivers/gpu/drm/i2c/tda998x_drv.c
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/i915/intel_sdvo.c
drivers/gpu/drm/mediatek/mtk_hdmi.c
drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
drivers/gpu/drm/nouveau/nv50_display.c
drivers/gpu/drm/omapdrm/omap_encoder.c
drivers/gpu/drm/radeon/radeon_audio.c
drivers/gpu/drm/rockchip/inno_hdmi.c
drivers/gpu/drm/sti/sti_hdmi.c
drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
drivers/gpu/drm/tegra/hdmi.c
drivers/gpu/drm/tegra/sor.c
drivers/gpu/drm/vc4/vc4_hdmi.c
drivers/gpu/drm/zte/zx_hdmi.c
include/drm/drm_edid.h

index 9f78c03a2e3152eb9244d4b733fbd194c6227299..aff1f48c947eb7e843895f2509fc5c597304ade1 100644 (file)
@@ -1867,7 +1867,7 @@ static void dce_v10_0_afmt_setmode(struct drm_encoder *encoder,
        dce_v10_0_audio_write_sad_regs(encoder);
        dce_v10_0_audio_write_latency_fields(encoder, mode);
 
-       err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
+       err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false);
        if (err < 0) {
                DRM_ERROR("failed to setup AVI infoframe: %zd\n", err);
                return;
index 4bcf01dc567a183b462a4333727f2fa90c6e924d..2df650dfa727ed7b2a3465ceb5c74c38727e6d0a 100644 (file)
@@ -1851,7 +1851,7 @@ static void dce_v11_0_afmt_setmode(struct drm_encoder *encoder,
        dce_v11_0_audio_write_sad_regs(encoder);
        dce_v11_0_audio_write_latency_fields(encoder, mode);
 
-       err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
+       err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false);
        if (err < 0) {
                DRM_ERROR("failed to setup AVI infoframe: %zd\n", err);
                return;
index fd134a4629d7a4ee5f3d8559049f1bfaddd8bb48..0c3891fa62f1786ca21b8e37e766b56be0b319f4 100644 (file)
@@ -1597,7 +1597,7 @@ static void dce_v6_0_audio_set_avi_infoframe(struct drm_encoder *encoder,
        ssize_t err;
        u32 tmp;
 
-       err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
+       err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false);
        if (err < 0) {
                DRM_ERROR("failed to setup AVI infoframe: %zd\n", err);
                return;
index a9e8695546272638e0922ba20853c241b0d7ae3b..c164bef8284688fb52b5f0b8f79d1399367c3969 100644 (file)
@@ -1750,7 +1750,7 @@ static void dce_v8_0_afmt_setmode(struct drm_encoder *encoder,
        dce_v8_0_audio_write_sad_regs(encoder);
        dce_v8_0_audio_write_latency_fields(encoder, mode);
 
-       err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
+       err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false);
        if (err < 0) {
                DRM_ERROR("failed to setup AVI infoframe: %zd\n", err);
                return;
index c2fac39470067dbc26b7967331a1460d569af79c..dc045e0c32fcd4c63eae29fd98fb7a8c2f6ec2dd 100644 (file)
@@ -1097,7 +1097,8 @@ static void anx78xx_bridge_mode_set(struct drm_bridge *bridge,
 
        mutex_lock(&anx78xx->lock);
 
-       err = drm_hdmi_avi_infoframe_from_display_mode(&frame, adjusted_mode);
+       err = drm_hdmi_avi_infoframe_from_display_mode(&frame, adjusted_mode,
+                                                      false);
        if (err) {
                DRM_ERROR("Failed to setup AVI infoframe: %d\n", err);
                goto unlock;
index b8d10e599df08d243eb9da658f5423210fcefb85..9efb7b8fad5751465e353f3241e687fbf79f3dca 100644 (file)
@@ -269,7 +269,7 @@ static void sii902x_bridge_mode_set(struct drm_bridge *bridge,
        if (ret)
                return;
 
-       ret = drm_hdmi_avi_infoframe_from_display_mode(&frame, adj);
+       ret = drm_hdmi_avi_infoframe_from_display_mode(&frame, adj, false);
        if (ret < 0) {
                DRM_ERROR("couldn't fill AVI infoframe\n");
                return;
index de1308b61390ee81d9a472a12fde62ce4b07827b..60faf2d2bc6b42bbcab95c4e60575ea7c2ee646e 100644 (file)
@@ -1317,7 +1317,7 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
        u8 val;
 
        /* Initialise info frame from DRM mode */
-       drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
+       drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false);
 
        if (hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_out_bus_format))
                frame.colorspace = HDMI_COLORSPACE_YUV444;
index 2e55599816aa5dfda1252a4affd0cee81d2c2ef2..0667b0744b17f9f23b4c0a590833fa1501343888 100644 (file)
@@ -4334,12 +4334,14 @@ EXPORT_SYMBOL(drm_set_preferred_mode);
  *                                              data from a DRM display mode
  * @frame: HDMI AVI infoframe
  * @mode: DRM display mode
+ * @is_hdmi2_sink: Sink is HDMI 2.0 compliant
  *
  * Return: 0 on success or a negative error code on failure.
  */
 int
 drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame,
-                                        const struct drm_display_mode *mode)
+                                        const struct drm_display_mode *mode,
+                                        bool is_hdmi2_sink)
 {
        int err;
 
@@ -4355,6 +4357,28 @@ drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame,
 
        frame->video_code = drm_match_cea_mode(mode);
 
+       /*
+        * HDMI 1.4 VIC range: 1 <= VIC <= 64 (CEA-861-D) but
+        * HDMI 2.0 VIC range: 1 <= VIC <= 107 (CEA-861-F). So we
+        * have to make sure we dont break HDMI 1.4 sinks.
+        */
+       if (!is_hdmi2_sink && frame->video_code > 64)
+               frame->video_code = 0;
+
+       /*
+        * HDMI spec says if a mode is found in HDMI 1.4b 4K modes
+        * we should send its VIC in vendor infoframes, else send the
+        * VIC in AVI infoframes. Lets check if this mode is present in
+        * HDMI 1.4b 4K modes
+        */
+       if (frame->video_code) {
+               u8 vendor_if_vic = drm_match_hdmi_mode(mode);
+               bool is_s3d = mode->flags & DRM_MODE_FLAG_3D_MASK;
+
+               if (drm_valid_hdmi_vic(vendor_if_vic) && !is_s3d)
+                       frame->video_code = 0;
+       }
+
        frame->picture_aspect = HDMI_PICTURE_ASPECT_NONE;
 
        /*
index 06bfbe400cf1d2ea23ec361a0fa1364a139ac43d..c953927fb0cbe01b1c24a21b95df2dd6c4985e9e 100644 (file)
@@ -784,7 +784,7 @@ static void hdmi_reg_infoframes(struct hdmi_context *hdata)
        }
 
        ret = drm_hdmi_avi_infoframe_from_display_mode(&frm.avi,
-                       &hdata->current_mode);
+                       &hdata->current_mode, false);
        if (!ret)
                ret = hdmi_avi_infoframe_pack(&frm.avi, buf, sizeof(buf));
        if (ret > 0) {
index 86f47e190309aea31bfdbacfc532f7df3307221c..d1e7ac5401999ebf6cb36a77e817e0896be9b996 100644 (file)
@@ -712,7 +712,7 @@ tda998x_write_avi(struct tda998x_priv *priv, struct drm_display_mode *mode)
 {
        union hdmi_infoframe frame;
 
-       drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode);
+       drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode, false);
        frame.avi.quantization_range = HDMI_QUANTIZATION_RANGE_FULL;
 
        tda998x_write_if(priv, DIP_IF_FLAGS_IF2, REG_IF2_HB0, &frame);
index 916340f038825e9ed9b7601ce34d2da47980abeb..2f831cfdd24330050bdfc4f6645b9a419280b77c 100644 (file)
@@ -459,11 +459,14 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
        struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
        const struct drm_display_mode *adjusted_mode =
                &crtc_state->base.adjusted_mode;
+       struct drm_connector *connector = &intel_hdmi->attached_connector->base;
+       bool is_hdmi2_sink = connector->display_info.hdmi.scdc.supported;
        union hdmi_infoframe frame;
        int ret;
 
        ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
-                                                      adjusted_mode);
+                                                      adjusted_mode,
+                                                      is_hdmi2_sink);
        if (ret < 0) {
                DRM_ERROR("couldn't fill AVI infoframe\n");
                return;
index 3f8f30b412cd883c6919f9c59ca32610a344cf0e..85d9ff361e7435e62253fc0a4e65643c4990c642 100644 (file)
@@ -996,7 +996,8 @@ static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo,
        ssize_t len;
 
        ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
-                                                      &pipe_config->base.adjusted_mode);
+                                                      &pipe_config->base.adjusted_mode,
+                                                      false);
        if (ret < 0) {
                DRM_ERROR("couldn't fill AVI infoframe\n");
                return false;
index 0a4ffd7241468dcbd064fa3a210f17094d10697b..5c0d02444bd354c6108e301dadf44325af5c4432 100644 (file)
@@ -975,7 +975,7 @@ static int mtk_hdmi_setup_avi_infoframe(struct mtk_hdmi *hdmi,
        u8 buffer[17];
        ssize_t err;
 
-       err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
+       err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false);
        if (err < 0) {
                dev_err(hdmi->dev,
                        "Failed to get AVI infoframe from mode: %zd\n", err);
index ae40e7179d4f5f21cbdef9401d68b2e09d954a7f..13ac822dee5d89c7cc47411ea2f7b517223c0b65 100644 (file)
@@ -97,7 +97,7 @@ static void msm_hdmi_config_avi_infoframe(struct hdmi *hdmi)
        u32 val;
        int len;
 
-       drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode);
+       drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode, false);
 
        len = hdmi_infoframe_pack(&frame, buffer, sizeof(buffer));
        if (len < 0) {
index 42a85c14aea0d73b2cc6141c67319c09ebd4fcf9..5f71e304022e08ca12c820ddc88b4207c97669f3 100644 (file)
@@ -2762,7 +2762,8 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct drm_display_mode *mode)
        if (!drm_detect_hdmi_monitor(nv_connector->edid))
                return;
 
-       ret = drm_hdmi_avi_infoframe_from_display_mode(&avi_frame.avi, mode);
+       ret = drm_hdmi_avi_infoframe_from_display_mode(&avi_frame.avi, mode,
+                                                      false);
        if (!ret) {
                /* We have an AVI InfoFrame, populate it to the display */
                args.pwr.avi_infoframe_length
index 86c977b7189a567afc2314c7bb4c140a40181a77..624f5b50b75518dd3f094efbc2c943e9e7dc3658 100644 (file)
@@ -85,7 +85,8 @@ static void omap_encoder_mode_set(struct drm_encoder *encoder,
        if (hdmi_mode && dssdev->driver->set_hdmi_infoframe) {
                struct hdmi_avi_infoframe avi;
 
-               r = drm_hdmi_avi_infoframe_from_display_mode(&avi, adjusted_mode);
+               r = drm_hdmi_avi_infoframe_from_display_mode(&avi, adjusted_mode,
+                                                            false);
                if (r == 0)
                        dssdev->driver->set_hdmi_infoframe(dssdev, &avi);
        }
index aaacac190d2688789928a24b0efbc8c92cb5aba3..770e31f5fd1b0c720762aeb8b9eee949c5c01aa0 100644 (file)
@@ -516,7 +516,7 @@ static int radeon_audio_set_avi_packet(struct drm_encoder *encoder,
        if (!connector)
                return -EINVAL;
 
-       err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
+       err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false);
        if (err < 0) {
                DRM_ERROR("failed to setup AVI infoframe: %d\n", err);
                return err;
index 7d9b75eb6c44ad0a3262e1a85feeb87213ad952d..7149968aa25a1b6ee326105200d545d2ab216364 100644 (file)
@@ -294,7 +294,7 @@ static int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi,
        union hdmi_infoframe frame;
        int rc;
 
-       rc = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode);
+       rc = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode, false);
 
        if (hdmi->hdmi_data.enc_out_format == HDMI_COLORSPACE_YUV444)
                frame.avi.colorspace = HDMI_COLORSPACE_YUV444;
index a59c95a8081b7acce1161b6dca34e027b8975825..dbc6a195d6f912a936b338a1a89648a288d6b98e 100644 (file)
@@ -434,7 +434,7 @@ static int hdmi_avi_infoframe_config(struct sti_hdmi *hdmi)
 
        DRM_DEBUG_DRIVER("\n");
 
-       ret = drm_hdmi_avi_infoframe_from_display_mode(&infoframe, mode);
+       ret = drm_hdmi_avi_infoframe_from_display_mode(&infoframe, mode, false);
        if (ret < 0) {
                DRM_ERROR("failed to setup AVI infoframe: %d\n", ret);
                return ret;
index d3398f6250ef4c95f6fdf21d44667e89eaac90c6..83b7a2a025f27907eba58829333086672abb03d5 100644 (file)
@@ -52,7 +52,7 @@ static int sun4i_hdmi_setup_avi_infoframes(struct sun4i_hdmi *hdmi,
        u8 buffer[17];
        int i, ret;
 
-       ret = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
+       ret = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false);
        if (ret < 0) {
                DRM_ERROR("Failed to get infoframes from mode\n");
                return ret;
index cda0491ed6bf80f2e77fd668adaff5d1233d7e94..718d8db406a6c6a7e4830beb391ea43ebe926d2f 100644 (file)
@@ -734,7 +734,7 @@ static void tegra_hdmi_setup_avi_infoframe(struct tegra_hdmi *hdmi,
        u8 buffer[17];
        ssize_t err;
 
-       err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
+       err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false);
        if (err < 0) {
                dev_err(hdmi->dev, "failed to setup AVI infoframe: %zd\n", err);
                return;
index a8f528925009e67938dc7e7b84b7d33b418733a3..fb2709c0c46102da9eca6490399ed9594f688fe1 100644 (file)
@@ -1904,7 +1904,7 @@ tegra_sor_hdmi_setup_avi_infoframe(struct tegra_sor *sor,
        value &= ~INFOFRAME_CTRL_ENABLE;
        tegra_sor_writel(sor, value, SOR_HDMI_AVI_INFOFRAME_CTRL);
 
-       err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
+       err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false);
        if (err < 0) {
                dev_err(sor->dev, "failed to setup AVI infoframe: %d\n", err);
                return err;
index ed63d4e857624831e9c25d6686554e5e51389002..406d6d83b6c6430200ff480eb55d013ed3b07a2a 100644 (file)
@@ -395,7 +395,7 @@ static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder)
        union hdmi_infoframe frame;
        int ret;
 
-       ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode);
+       ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode, false);
        if (ret < 0) {
                DRM_ERROR("couldn't fill AVI infoframe\n");
                return;
index 0df7366e594b32d8d732987727f0bc2f60f60325..7e834e3eeed9d46c4714dc757421bf58a10797f8 100644 (file)
@@ -124,7 +124,7 @@ static int zx_hdmi_config_video_avi(struct zx_hdmi *hdmi,
        union hdmi_infoframe frame;
        int ret;
 
-       ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode);
+       ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode, false);
        if (ret) {
                DRM_DEV_ERROR(hdmi->dev, "failed to get avi infoframe: %d\n",
                              ret);
index 7b9f48b62e07cda87f74b5d6df617c2dc54734ef..89c00626d6540ef58de5ed99746d4b1dbe4d8545 100644 (file)
@@ -343,7 +343,8 @@ drm_load_edid_firmware(struct drm_connector *connector)
 
 int
 drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame,
-                                        const struct drm_display_mode *mode);
+                                        const struct drm_display_mode *mode,
+                                        bool is_hdmi2_sink);
 int
 drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame,
                                            const struct drm_display_mode *mode);