OSDN Git Service

drm/amd/display: Fix incorrect deep color setting in YCBCR420 modes
authorStylon Wang <stylon.wang@amd.com>
Fri, 20 Sep 2019 07:40:55 +0000 (15:40 +0800)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 19 Nov 2019 15:12:52 +0000 (10:12 -0500)
[Why]
HDMI 2.0 HF-VSDB in EDID defines supported color depths in YCBCR420 modes.
But we did not honor these bit masks when choosing pixel encoding.
HDMI 2.0 compliance tests with deep color and YCBCR420 failed as a result.

[How]
Cap color depth based on y420_dc_modes from EDID.

Signed-off-by: Stylon Wang <stylon.wang@amd.com>
Reviewed-by: Nicholas Kazlauskas <Nicholas.Kazlauskas@amd.com>
Acked-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c

index 700cbd5..11b9c65 100644 (file)
@@ -3539,12 +3539,26 @@ static void update_stream_scaling_settings(const struct drm_display_mode *mode,
 
 static enum dc_color_depth
 convert_color_depth_from_display_info(const struct drm_connector *connector,
-                                     const struct drm_connector_state *state)
+                                     const struct drm_connector_state *state,
+                                     bool is_y420)
 {
-       uint8_t bpc = (uint8_t)connector->display_info.bpc;
+       uint8_t bpc;
 
-       /* Assume 8 bpc by default if no bpc is specified. */
-       bpc = bpc ? bpc : 8;
+       if (is_y420) {
+               bpc = 8;
+
+               /* Cap display bpc based on HDMI 2.0 HF-VSDB */
+               if (connector->display_info.hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_48)
+                       bpc = 16;
+               else if (connector->display_info.hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_36)
+                       bpc = 12;
+               else if (connector->display_info.hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_30)
+                       bpc = 10;
+       } else {
+               bpc = (uint8_t)connector->display_info.bpc;
+               /* Assume 8 bpc by default if no bpc is specified. */
+               bpc = bpc ? bpc : 8;
+       }
 
        if (!state)
                state = connector->state;
@@ -3715,7 +3729,8 @@ static void fill_stream_properties_from_drm_display_mode(
 
        timing_out->timing_3d_format = TIMING_3D_FORMAT_NONE;
        timing_out->display_color_depth = convert_color_depth_from_display_info(
-               connector, connector_state);
+               connector, connector_state,
+               (timing_out->pixel_encoding == PIXEL_ENCODING_YCBCR420));
        timing_out->scan_type = SCANNING_TYPE_NODATA;
        timing_out->hdmi_vic = 0;
 
@@ -4847,6 +4862,7 @@ static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder,
        struct drm_dp_mst_port *mst_port;
        enum dc_color_depth color_depth;
        int clock, bpp = 0;
+       bool is_y420 = false;
 
        if (!aconnector->port || !aconnector->dc_sink)
                return 0;
@@ -4858,7 +4874,10 @@ static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder,
                return 0;
 
        if (!state->duplicated) {
-               color_depth = convert_color_depth_from_display_info(connector, conn_state);
+               is_y420 = drm_mode_is_420_also(&connector->display_info, adjusted_mode) &&
+                               aconnector->force_yuv420_output;
+               color_depth = convert_color_depth_from_display_info(connector, conn_state,
+                                                                   is_y420);
                bpp = convert_dc_color_depth_into_bpc(color_depth) * 3;
                clock = adjusted_mode->clock;
                dm_new_connector_state->pbn = drm_dp_calc_pbn_mode(clock, bpp);