Skip to content

Commit

Permalink
drm/edid: Split deep color modes between RGB and YUV444
Browse files Browse the repository at this point in the history
The current code assumes that the RGB444 and YUV444 formats are the
same, but the HDMI 2.0 specification states that:

   The three DC_XXbit bits above only indicate support for RGB 4:4:4 at
   that pixel size. Support for YCBCR 4:4:4 in Deep Color modes is
   indicated with the DC_Y444 bit. If DC_Y444 is set, then YCBCR 4:4:4
   is supported for all modes indicated by the DC_XXbit flags.

So if we have YUV444 support and any DC_XXbit flag set but the DC_Y444
flag isn't, we'll assume that we support that deep colour mode for
YUV444 which breaks the specification.

In order to fix this, let's split the edid_hdmi_dc_modes field in struct
drm_display_info into two fields, one for RGB444 and one for YUV444.

Suggested-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Fixes: d0c9469 ("drm/edid: Parse and handle HDMI deep color modes.")
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20220120151625.594595-4-maxime@cerno.tech
  • Loading branch information
Maxime Ripard committed Jan 25, 2022
1 parent 75478b3 commit 4adc33f
Show file tree
Hide file tree
Showing 5 changed files with 17 additions and 10 deletions.
2 changes: 1 addition & 1 deletion drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ int amdgpu_connector_get_monitor_bpc(struct drm_connector *connector)

/* Check if bpc is within clock limit. Try to degrade gracefully otherwise */
if ((bpc == 12) && (mode_clock * 3/2 > max_tmds_clock)) {
if ((connector->display_info.edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_30) &&
if ((connector->display_info.edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_30) &&
(mode_clock * 5/4 <= max_tmds_clock))
bpc = 10;
else
Expand Down
7 changes: 4 additions & 3 deletions drivers/gpu/drm/drm_edid.c
Original file line number Diff line number Diff line change
Expand Up @@ -5086,21 +5086,21 @@ static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector,

if (hdmi[6] & DRM_EDID_HDMI_DC_30) {
dc_bpc = 10;
info->edid_hdmi_dc_modes |= DRM_EDID_HDMI_DC_30;
info->edid_hdmi_rgb444_dc_modes |= DRM_EDID_HDMI_DC_30;
DRM_DEBUG("%s: HDMI sink does deep color 30.\n",
connector->name);
}

if (hdmi[6] & DRM_EDID_HDMI_DC_36) {
dc_bpc = 12;
info->edid_hdmi_dc_modes |= DRM_EDID_HDMI_DC_36;
info->edid_hdmi_rgb444_dc_modes |= DRM_EDID_HDMI_DC_36;
DRM_DEBUG("%s: HDMI sink does deep color 36.\n",
connector->name);
}

if (hdmi[6] & DRM_EDID_HDMI_DC_48) {
dc_bpc = 16;
info->edid_hdmi_dc_modes |= DRM_EDID_HDMI_DC_48;
info->edid_hdmi_rgb444_dc_modes |= DRM_EDID_HDMI_DC_48;
DRM_DEBUG("%s: HDMI sink does deep color 48.\n",
connector->name);
}
Expand All @@ -5117,6 +5117,7 @@ static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector,

/* YCRCB444 is optional according to spec. */
if (hdmi[6] & DRM_EDID_HDMI_DC_Y444) {
info->edid_hdmi_ycbcr444_dc_modes = info->edid_hdmi_rgb444_dc_modes;
DRM_DEBUG("%s: HDMI sink does YCRCB444 in deep color.\n",
connector->name);
}
Expand Down
4 changes: 2 additions & 2 deletions drivers/gpu/drm/i915/display/intel_hdmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -1912,15 +1912,15 @@ static bool intel_hdmi_sink_bpc_possible(struct drm_connector *connector,
if (ycbcr420_output)
return hdmi->y420_dc_modes & DRM_EDID_YCBCR420_DC_36;
else
return info->edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_36;
return info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_36;
case 10:
if (!has_hdmi_sink)
return false;

if (ycbcr420_output)
return hdmi->y420_dc_modes & DRM_EDID_YCBCR420_DC_30;
else
return info->edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_30;
return info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_30;
case 8:
return true;
default:
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/radeon/radeon_connectors.c
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ int radeon_get_monitor_bpc(struct drm_connector *connector)

/* Check if bpc is within clock limit. Try to degrade gracefully otherwise */
if ((bpc == 12) && (mode_clock * 3/2 > max_tmds_clock)) {
if ((connector->display_info.edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_30) &&
if ((connector->display_info.edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_30) &&
(mode_clock * 5/4 <= max_tmds_clock))
bpc = 10;
else
Expand Down
12 changes: 9 additions & 3 deletions include/drm/drm_connector.h
Original file line number Diff line number Diff line change
Expand Up @@ -592,10 +592,16 @@ struct drm_display_info {
bool rgb_quant_range_selectable;

/**
* @edid_hdmi_dc_modes: Mask of supported hdmi deep color modes. Even
* more stuff redundant with @bus_formats.
* @edid_hdmi_dc_rgb444_modes: Mask of supported hdmi deep color modes
* in RGB 4:4:4. Even more stuff redundant with @bus_formats.
*/
u8 edid_hdmi_dc_modes;
u8 edid_hdmi_rgb444_dc_modes;

/**
* @edid_hdmi_dc_ycbcr444_modes: Mask of supported hdmi deep color
* modes in YCbCr 4:4:4. Even more stuff redundant with @bus_formats.
*/
u8 edid_hdmi_ycbcr444_dc_modes;

/**
* @cea_rev: CEA revision of the HDMI sink.
Expand Down

0 comments on commit 4adc33f

Please sign in to comment.