Commit 46db138d authored by Stylon Wang's avatar Stylon Wang Committed by Alex Deucher
Browse files

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: default avatarStylon Wang <stylon.wang@amd.com>
Reviewed-by: default avatarNicholas Kazlauskas <Nicholas.Kazlauskas@amd.com>
Acked-by: default avatarRodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Tested-by: default avatarDaniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 0713921b
Loading
Loading
Loading
Loading
+89 −6
Original line number Diff line number Diff line
@@ -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)
{