Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/edid: Allow HDMI infoframe without VIC or S3D

Appedix F of HDMI 2.0 says that some HDMI sink may fail to switch from
3D to 2D mode in a timely fashion if the source simply stops sending the
HDMI infoframe. The suggested workaround is to keep sending the
infoframe even when strictly not necessary (ie. no VIC and no S3D).
HDMI 1.4 does allow for this behaviour, stating that sending the
infoframe is optional in this case.

The infoframe was first specified in HDMI 1.4, so in theory sinks
predating that may not appreciate us sending an uknown infoframe
their way. To avoid regressions let's try to determine if the sink
supports the infoframe or not. Unfortunately there's no direct way
to do that, so instead we'll just check if we managed to parse any
HDMI 1.4 4k or stereo modes from the EDID, and if so we assume the
sink will accept the infoframe. Also if the EDID contains the HDMI
2.0 HDMI Forum VSDB we can assume the sink is prepared to receive
the infoframe.

v2: Fix getting has_hdmi_infoframe from display_info
Always fail constructing the infoframe if the display
possibly can't handle it

Cc: Shashank Sharma <shashank.sharma@intel.com>
Cc: Andrzej Hajda <a.hajda@samsung.com>
Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Shashank Sharma <shashank.sharma@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20171113170427.4150-3-ville.syrjala@linux.intel.com

+58 -18
+2 -1
drivers/gpu/drm/bridge/sil-sii8620.c
··· 2233 2233 union hdmi_infoframe frm; 2234 2234 u8 mhl_vic[] = { 0, 95, 94, 93, 98 }; 2235 2235 2236 + /* FIXME: We need the connector here */ 2236 2237 drm_hdmi_vendor_infoframe_from_display_mode( 2237 - &frm.vendor.hdmi, adjusted_mode); 2238 + &frm.vendor.hdmi, NULL, adjusted_mode); 2238 2239 vic = frm.vendor.hdmi.vic; 2239 2240 if (vic >= ARRAY_SIZE(mhl_vic)) 2240 2241 vic = 0;
+3 -1
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
··· 1437 1437 u8 buffer[10]; 1438 1438 ssize_t err; 1439 1439 1440 - err = drm_hdmi_vendor_infoframe_from_display_mode(&frame, mode); 1440 + err = drm_hdmi_vendor_infoframe_from_display_mode(&frame, 1441 + &hdmi->connector, 1442 + mode); 1441 1443 if (err < 0) 1442 1444 /* 1443 1445 * Going into that statement does not means vendor infoframe
+28 -6
drivers/gpu/drm/drm_edid.c
··· 3393 3393 do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len, 3394 3394 const u8 *video_db, u8 video_len) 3395 3395 { 3396 + struct drm_display_info *info = &connector->display_info; 3396 3397 int modes = 0, offset = 0, i, multi_present = 0, multi_len; 3397 3398 u8 vic_len, hdmi_3d_len = 0; 3398 3399 u16 mask; ··· 3521 3520 } 3522 3521 3523 3522 out: 3523 + if (modes > 0) 3524 + info->has_hdmi_infoframe = true; 3524 3525 return modes; 3525 3526 } 3526 3527 ··· 4246 4243 struct drm_display_info *display = &connector->display_info; 4247 4244 struct drm_hdmi_info *hdmi = &display->hdmi; 4248 4245 4246 + display->has_hdmi_infoframe = true; 4247 + 4249 4248 if (hf_vsdb[6] & 0x80) { 4250 4249 hdmi->scdc.supported = true; 4251 4250 if (hf_vsdb[6] & 0x40) ··· 4421 4416 info->cea_rev = 0; 4422 4417 info->max_tmds_clock = 0; 4423 4418 info->dvi_dual = false; 4419 + info->has_hdmi_infoframe = false; 4424 4420 4425 4421 if (edid->revision < 3) 4426 4422 return; ··· 4909 4903 * drm_hdmi_vendor_infoframe_from_display_mode() - fill an HDMI infoframe with 4910 4904 * data from a DRM display mode 4911 4905 * @frame: HDMI vendor infoframe 4906 + * @connector: the connector 4912 4907 * @mode: DRM display mode 4913 4908 * 4914 4909 * Note that there's is a need to send HDMI vendor infoframes only when using a ··· 4920 4913 */ 4921 4914 int 4922 4915 drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame, 4916 + struct drm_connector *connector, 4923 4917 const struct drm_display_mode *mode) 4924 4918 { 4919 + /* 4920 + * FIXME: sil-sii8620 doesn't have a connector around when 4921 + * we need one, so we have to be prepared for a NULL connector. 4922 + */ 4923 + bool has_hdmi_infoframe = connector ? 4924 + connector->display_info.has_hdmi_infoframe : false; 4925 4925 int err; 4926 4926 u32 s3d_flags; 4927 4927 u8 vic; ··· 4936 4922 if (!frame || !mode) 4937 4923 return -EINVAL; 4938 4924 4925 + if (!has_hdmi_infoframe) 4926 + return -EINVAL; 4927 + 4939 4928 vic = drm_match_hdmi_mode(mode); 4940 4929 s3d_flags = mode->flags & DRM_MODE_FLAG_3D_MASK; 4941 4930 4942 - if (!vic && !s3d_flags) 4943 - return -EINVAL; 4931 + /* 4932 + * Even if it's not absolutely necessary to send the infoframe 4933 + * (ie.vic==0 and s3d_struct==0) we will still send it if we 4934 + * know that the sink can handle it. This is based on a 4935 + * suggestion in HDMI 2.0 Appendix F. Apparently some sinks 4936 + * have trouble realizing that they shuld switch from 3D to 2D 4937 + * mode if the source simply stops sending the infoframe when 4938 + * it wants to switch from 3D to 2D. 4939 + */ 4944 4940 4945 4941 if (vic && s3d_flags) 4946 4942 return -EINVAL; ··· 4959 4935 if (err < 0) 4960 4936 return err; 4961 4937 4962 - if (vic) 4963 - frame->vic = vic; 4964 - else 4965 - frame->s3d_struct = s3d_structure_from_display_mode(mode); 4938 + frame->vic = vic; 4939 + frame->s3d_struct = s3d_structure_from_display_mode(mode); 4966 4940 4967 4941 return 0; 4968 4942 }
+2 -1
drivers/gpu/drm/exynos/exynos_hdmi.c
··· 829 829 DRM_INFO("%s: invalid AVI infoframe (%d)\n", __func__, ret); 830 830 } 831 831 832 - ret = drm_hdmi_vendor_infoframe_from_display_mode(&frm.vendor.hdmi, m); 832 + ret = drm_hdmi_vendor_infoframe_from_display_mode(&frm.vendor.hdmi, 833 + &hdata->connector, m); 833 834 if (!ret) 834 835 ret = hdmi_vendor_infoframe_pack(&frm.vendor.hdmi, buf, 835 836 sizeof(buf));
+8 -6
drivers/gpu/drm/i915/intel_hdmi.c
··· 512 512 513 513 static void 514 514 intel_hdmi_set_hdmi_infoframe(struct drm_encoder *encoder, 515 - const struct intel_crtc_state *crtc_state) 515 + const struct intel_crtc_state *crtc_state, 516 + const struct drm_connector_state *conn_state) 516 517 { 517 518 union hdmi_infoframe frame; 518 519 int ret; 519 520 520 521 ret = drm_hdmi_vendor_infoframe_from_display_mode(&frame.vendor.hdmi, 522 + conn_state->connector, 521 523 &crtc_state->base.adjusted_mode); 522 524 if (ret < 0) 523 525 return; ··· 586 584 587 585 intel_hdmi_set_avi_infoframe(encoder, crtc_state); 588 586 intel_hdmi_set_spd_infoframe(encoder, crtc_state); 589 - intel_hdmi_set_hdmi_infoframe(encoder, crtc_state); 587 + intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state); 590 588 } 591 589 592 590 static bool hdmi_sink_is_deep_color(const struct drm_connector_state *conn_state) ··· 727 725 728 726 intel_hdmi_set_avi_infoframe(encoder, crtc_state); 729 727 intel_hdmi_set_spd_infoframe(encoder, crtc_state); 730 - intel_hdmi_set_hdmi_infoframe(encoder, crtc_state); 728 + intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state); 731 729 } 732 730 733 731 static void cpt_set_infoframes(struct drm_encoder *encoder, ··· 770 768 771 769 intel_hdmi_set_avi_infoframe(encoder, crtc_state); 772 770 intel_hdmi_set_spd_infoframe(encoder, crtc_state); 773 - intel_hdmi_set_hdmi_infoframe(encoder, crtc_state); 771 + intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state); 774 772 } 775 773 776 774 static void vlv_set_infoframes(struct drm_encoder *encoder, ··· 823 821 824 822 intel_hdmi_set_avi_infoframe(encoder, crtc_state); 825 823 intel_hdmi_set_spd_infoframe(encoder, crtc_state); 826 - intel_hdmi_set_hdmi_infoframe(encoder, crtc_state); 824 + intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state); 827 825 } 828 826 829 827 static void hsw_set_infoframes(struct drm_encoder *encoder, ··· 856 854 857 855 intel_hdmi_set_avi_infoframe(encoder, crtc_state); 858 856 intel_hdmi_set_spd_infoframe(encoder, crtc_state); 859 - intel_hdmi_set_hdmi_infoframe(encoder, crtc_state); 857 + intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state); 860 858 } 861 859 862 860 void intel_dp_dual_mode_set_tmds_output(struct intel_hdmi *hdmi, bool enable)
+2 -1
drivers/gpu/drm/mediatek/mtk_hdmi.c
··· 1054 1054 u8 buffer[10]; 1055 1055 ssize_t err; 1056 1056 1057 - err = drm_hdmi_vendor_infoframe_from_display_mode(&frame, mode); 1057 + err = drm_hdmi_vendor_infoframe_from_display_mode(&frame, 1058 + &hdmi->conn, mode); 1058 1059 if (err) { 1059 1060 dev_err(hdmi->dev, 1060 1061 "Failed to get vendor infoframe from mode: %zd\n", err);
+2 -1
drivers/gpu/drm/nouveau/nv50_display.c
··· 2756 2756 = hdmi_infoframe_pack(&avi_frame, args.infoframes, 17); 2757 2757 } 2758 2758 2759 - ret = drm_hdmi_vendor_infoframe_from_display_mode(&vendor_frame.vendor.hdmi, mode); 2759 + ret = drm_hdmi_vendor_infoframe_from_display_mode(&vendor_frame.vendor.hdmi, 2760 + &nv_connector->base, mode); 2760 2761 if (!ret) { 2761 2762 /* We have a Vendor InfoFrame, populate it to the display */ 2762 2763 args.pwr.vendor_infoframe_length
+1
drivers/gpu/drm/rockchip/inno_hdmi.c
··· 282 282 int rc; 283 283 284 284 rc = drm_hdmi_vendor_infoframe_from_display_mode(&frame.vendor.hdmi, 285 + &hdmi->connector, 285 286 mode); 286 287 287 288 return inno_hdmi_upload_frame(hdmi, rc, &frame, INFOFRAME_VSI,
+3 -1
drivers/gpu/drm/sti/sti_hdmi.c
··· 515 515 516 516 DRM_DEBUG_DRIVER("\n"); 517 517 518 - ret = drm_hdmi_vendor_infoframe_from_display_mode(&infoframe, mode); 518 + ret = drm_hdmi_vendor_infoframe_from_display_mode(&infoframe, 519 + hdmi->drm_connector, 520 + mode); 519 521 if (ret < 0) { 520 522 /* 521 523 * Going into that statement does not means vendor infoframe
+1
drivers/gpu/drm/zte/zx_hdmi.c
··· 108 108 int ret; 109 109 110 110 ret = drm_hdmi_vendor_infoframe_from_display_mode(&frame.vendor.hdmi, 111 + &hdmi->connector, 111 112 mode); 112 113 if (ret) { 113 114 DRM_DEV_ERROR(hdmi->dev, "failed to get vendor infoframe: %d\n",
+5
include/drm/drm_connector.h
··· 270 270 bool dvi_dual; 271 271 272 272 /** 273 + * @has_hdmi_infoframe: Does the sink support the HDMI infoframe? 274 + */ 275 + bool has_hdmi_infoframe; 276 + 277 + /** 273 278 * @edid_hdmi_dc_modes: Mask of supported hdmi deep color modes. Even 274 279 * more stuff redundant with @bus_formats. 275 280 */
+1
include/drm/drm_edid.h
··· 356 356 bool is_hdmi2_sink); 357 357 int 358 358 drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame, 359 + struct drm_connector *connector, 359 360 const struct drm_display_mode *mode); 360 361 void 361 362 drm_hdmi_avi_infoframe_quant_range(struct hdmi_avi_infoframe *frame,