From 46db138dc83ae16e188038358c925c560110f804 Mon Sep 17 00:00:00 2001 From: Stylon Wang Date: Sat, 29 May 2021 14:19:20 +0800 Subject: [PATCH] drm/amd/display: Add Freesync HDMI support to DM with DMUB [Why] Changes in DM needed to support Freesync HDMI on DMUB. [How] Change implementation to parse CEA blocks in case of DMUB-enabled ASICs. Signed-off-by: Stylon Wang Reviewed-by: Nicholas Kazlauskas Acked-by: Rodrigo Siqueira Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 95 +++++++++++++++++-- 1 file changed, 89 insertions(+), 6 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 01e1062dc235..f69be1286348 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -10549,13 +10549,68 @@ static bool is_dp_capable_without_timing_msa(struct dc *dc, return capable; } -static bool parse_edid_cea(struct amdgpu_dm_connector *aconnector, +static bool dm_edid_parser_send_cea(struct amdgpu_display_manager *dm, + unsigned int offset, + unsigned int total_length, + uint8_t *data, + unsigned int length, + struct amdgpu_hdmi_vsdb_info *vsdb) +{ + bool res; + union dmub_rb_cmd cmd; + struct dmub_cmd_send_edid_cea *input; + struct dmub_cmd_edid_cea_output *output; + + if (length > DMUB_EDID_CEA_DATA_CHUNK_BYTES) + return false; + + memset(&cmd, 0, sizeof(cmd)); + + input = &cmd.edid_cea.data.input; + + cmd.edid_cea.header.type = DMUB_CMD__EDID_CEA; + cmd.edid_cea.header.sub_type = 0; + cmd.edid_cea.header.payload_bytes = + sizeof(cmd.edid_cea) - sizeof(cmd.edid_cea.header); + input->offset = offset; + input->length = length; + input->total_length = total_length; + memcpy(input->payload, data, length); + + res = dc_dmub_srv_cmd_with_reply_data(dm->dc->ctx->dmub_srv, &cmd); + if (!res) { + DRM_ERROR("EDID CEA parser failed\n"); + return false; + } + + output = &cmd.edid_cea.data.output; + + if (output->type == DMUB_CMD__EDID_CEA_ACK) { + if (!output->ack.success) { + DRM_ERROR("EDID CEA ack failed at offset %d\n", + output->ack.offset); + } + } else if (output->type == DMUB_CMD__EDID_CEA_AMD_VSDB) { + if (!output->amd_vsdb.vsdb_found) + return false; + + vsdb->freesync_supported = output->amd_vsdb.freesync_supported; + vsdb->amd_vsdb_version = output->amd_vsdb.amd_vsdb_version; + vsdb->min_refresh_rate_hz = output->amd_vsdb.min_frame_rate; + vsdb->max_refresh_rate_hz = output->amd_vsdb.max_frame_rate; + } else { + DRM_ERROR("Unknown EDID CEA parser results\n"); + return false; + } + + return true; +} + +static bool parse_edid_cea_dmcu(struct amdgpu_display_manager *dm, uint8_t *edid_ext, int len, struct amdgpu_hdmi_vsdb_info *vsdb_info) { int i; - struct amdgpu_device *adev = drm_to_adev(aconnector->base.dev); - struct dc *dc = adev->dm.dc; /* send extension block to DMCU for parsing */ for (i = 0; i < len; i += 8) { @@ -10563,14 +10618,14 @@ static bool parse_edid_cea(struct amdgpu_dm_connector *aconnector, int offset; /* send 8 bytes a time */ - if (!dc_edid_parser_send_cea(dc, i, len, &edid_ext[i], 8)) + if (!dc_edid_parser_send_cea(dm->dc, i, len, &edid_ext[i], 8)) return false; if (i+8 == len) { /* EDID block sent completed, expect result */ int version, min_rate, max_rate; - res = dc_edid_parser_recv_amd_vsdb(dc, &version, &min_rate, &max_rate); + res = dc_edid_parser_recv_amd_vsdb(dm->dc, &version, &min_rate, &max_rate); if (res) { /* amd vsdb found */ vsdb_info->freesync_supported = 1; @@ -10584,7 +10639,7 @@ static bool parse_edid_cea(struct amdgpu_dm_connector *aconnector, } /* check for ack*/ - res = dc_edid_parser_recv_cea_ack(dc, &offset); + res = dc_edid_parser_recv_cea_ack(dm->dc, &offset); if (!res) return false; } @@ -10592,6 +10647,34 @@ static bool parse_edid_cea(struct amdgpu_dm_connector *aconnector, return false; } +static bool parse_edid_cea_dmub(struct amdgpu_display_manager *dm, + uint8_t *edid_ext, int len, + struct amdgpu_hdmi_vsdb_info *vsdb_info) +{ + int i; + + /* send extension block to DMCU for parsing */ + for (i = 0; i < len; i += 8) { + /* send 8 bytes a time */ + if (!dm_edid_parser_send_cea(dm, i, len, &edid_ext[i], 8, vsdb_info)) + return false; + } + + return vsdb_info->freesync_supported; +} + +static bool parse_edid_cea(struct amdgpu_dm_connector *aconnector, + uint8_t *edid_ext, int len, + struct amdgpu_hdmi_vsdb_info *vsdb_info) +{ + struct amdgpu_device *adev = drm_to_adev(aconnector->base.dev); + + if (adev->dm.dmub_srv) + return parse_edid_cea_dmub(&adev->dm, edid_ext, len, vsdb_info); + else + return parse_edid_cea_dmcu(&adev->dm, edid_ext, len, vsdb_info); +} + static int parse_hdmi_amd_vsdb(struct amdgpu_dm_connector *aconnector, struct edid *edid, struct amdgpu_hdmi_vsdb_info *vsdb_info) { -- 2.25.1