From: Stephen <[email protected]> DP-to-HDMI PCON connectors are exposed to DRM as DP connectors, but the downstream sink capability for RGB deep color is carried in the HDMI CTA deep-color flags. If AMDGPU only uses the base EDID bpc field for RGB output, HDMI sinks behind PCONs can be capped at 8 bpc even when the CTA block advertises RGB 10/12 bpc support.
For RGB output through a recognized DP-HDMI converter, derive the candidate bpc from edid_hdmi_rgb444_dc_modes before applying the requested max bpc cap. Keep YCbCr420 on the existing y420 deep-color path and leave native DP behavior unchanged. Signed-off-by: Stephen <[email protected]> --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 41 ++++++++++++++++++----- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 8f80420e9f0b..3b814b839ddf 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -6769,22 +6769,44 @@ static void update_stream_scaling_settings(struct drm_device *dev, static enum dc_color_depth convert_color_depth_from_display_info(const struct drm_connector *connector, - bool is_y420, int requested_bpc) + enum dc_pixel_encoding pixel_encoding, + int requested_bpc) { + const struct drm_display_info *info = &connector->display_info; + bool is_hdmi_pcon = false; u8 bpc; - if (is_y420) { + if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK) { + const struct amdgpu_dm_connector *aconnector = + to_amdgpu_dm_connector(connector); + + is_hdmi_pcon = aconnector->dc_link && + aconnector->dc_link->dpcd_caps.dongle_type == + DISPLAY_DONGLE_DP_HDMI_CONVERTER; + } + + if (pixel_encoding == PIXEL_ENCODING_YCBCR420) { 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) + if (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_48) + bpc = 16; + else if (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_36) + bpc = 12; + else if (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_30) + bpc = 10; + } else if (pixel_encoding == PIXEL_ENCODING_RGB && is_hdmi_pcon) { + bpc = 8; + + /* The downstream sink is HDMI even though DRM exposes DP. */ + if (info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_48) bpc = 16; - else if (connector->display_info.hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_36) + else if (info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_36) bpc = 12; - else if (connector->display_info.hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_30) + else if (info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_30) bpc = 10; } else { - bpc = (uint8_t)connector->display_info.bpc; + bpc = (uint8_t)info->bpc; /* Assume 8 bpc by default if no bpc is specified. */ bpc = bpc ? bpc : 8; } @@ -7004,7 +7026,7 @@ 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, - (timing_out->pixel_encoding == PIXEL_ENCODING_YCBCR420), + timing_out->pixel_encoding, requested_bpc); timing_out->scan_type = SCANNING_TYPE_NODATA; timing_out->hdmi_vic = 0; @@ -8761,6 +8783,7 @@ static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder, struct drm_dp_mst_port *mst_port; struct drm_dp_mst_topology_state *mst_state; enum dc_color_depth color_depth; + enum dc_pixel_encoding pixel_encoding = PIXEL_ENCODING_RGB; int clock, bpp = 0; bool is_y420 = false; @@ -8801,8 +8824,10 @@ static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder, is_y420 = drm_mode_is_420_also(&connector->display_info, adjusted_mode) && aconnector->force_yuv420_output; + if (is_y420) + pixel_encoding = PIXEL_ENCODING_YCBCR420; color_depth = convert_color_depth_from_display_info(connector, - is_y420, + pixel_encoding, max_bpc); bpp = convert_dc_color_depth_into_bpc(color_depth) * 3; clock = adjusted_mode->clock; -- 2.54.0
