All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3] drm/amdgpu: add DP audio support for si dce6 (v3)
@ 2017-02-22  3:37 Xiaojie Yuan
       [not found] ` <1487734626-27738-1-git-send-email-Xiaojie.Yuan-5C7GfCeVMHo@public.gmane.org>
  0 siblings, 1 reply; 4+ messages in thread
From: Xiaojie Yuan @ 2017-02-22  3:37 UTC (permalink / raw)
  To: amd-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW; +Cc: Xiaojie Yuan

v2: refine dce_v6_0_audio_endpt_wreg() and unify inconsistent method names
v3: fix num_pins for tahiti, pitcairn, verde and oland

Signed-off-by: Xiaojie Yuan <Xiaojie.Yuan@amd.com>
---
 drivers/gpu/drm/amd/amdgpu/dce_v6_0.c              | 467 +++++++++++++++++++--
 .../drm/amd/include/asic_reg/dce/dce_6_0_sh_mask.h |   2 +
 2 files changed, 433 insertions(+), 36 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
index 94877cb..7c11ed8 100644
--- a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
@@ -118,14 +118,27 @@ static const struct {
 static u32 dce_v6_0_audio_endpt_rreg(struct amdgpu_device *adev,
 				     u32 block_offset, u32 reg)
 {
-	DRM_INFO("xxxx: dce_v6_0_audio_endpt_rreg ----no impl!!!!\n");
-	return 0;
+	unsigned long flags;
+	u32 r;
+
+	spin_lock_irqsave(&adev->audio_endpt_idx_lock, flags);
+	WREG32(mmAZALIA_F0_CODEC_ENDPOINT_INDEX + block_offset, reg);
+	r = RREG32(mmAZALIA_F0_CODEC_ENDPOINT_DATA + block_offset);
+	spin_unlock_irqrestore(&adev->audio_endpt_idx_lock, flags);
+
+	return r;
 }
 
 static void dce_v6_0_audio_endpt_wreg(struct amdgpu_device *adev,
 				      u32 block_offset, u32 reg, u32 v)
 {
-	DRM_INFO("xxxx: dce_v6_0_audio_endpt_wreg ----no impl!!!!\n");
+	unsigned long flags;
+
+	spin_lock_irqsave(&adev->audio_endpt_idx_lock, flags);
+	WREG32(mmAZALIA_F0_CODEC_ENDPOINT_INDEX + block_offset,
+		reg | AZALIA_F0_CODEC_ENDPOINT_INDEX__AZALIA_ENDPOINT_REG_WRITE_EN_MASK);
+	WREG32(mmAZALIA_F0_CODEC_ENDPOINT_DATA + block_offset, v);
+	spin_unlock_irqrestore(&adev->audio_endpt_idx_lock, flags);
 }
 
 static bool dce_v6_0_is_in_vblank(struct amdgpu_device *adev, int crtc)
@@ -1231,17 +1244,17 @@ static void dce_v6_0_bandwidth_update(struct amdgpu_device *adev)
 		dce_v6_0_program_watermarks(adev, adev->mode_info.crtcs[i+1], lb_size, num_heads);
 	}
 }
-/*
+
 static void dce_v6_0_audio_get_connected_pins(struct amdgpu_device *adev)
 {
 	int i;
-	u32 offset, tmp;
+	u32 tmp;
 
 	for (i = 0; i < adev->mode_info.audio.num_pins; i++) {
-		offset = adev->mode_info.audio.pin[i].offset;
-		tmp = RREG32_AUDIO_ENDPT(offset,
-				      AZ_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT);
-		if (((tmp & PORT_CONNECTIVITY_MASK) >> PORT_CONNECTIVITY_SHIFT) == 1)
+		tmp = RREG32_AUDIO_ENDPT(adev->mode_info.audio.pin[i].offset,
+				ixAZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT);
+		if (REG_GET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT,
+					PORT_CONNECTIVITY))
 			adev->mode_info.audio.pin[i].connected = false;
 		else
 			adev->mode_info.audio.pin[i].connected = true;
@@ -1263,45 +1276,206 @@ static struct amdgpu_audio_pin *dce_v6_0_audio_get_pin(struct amdgpu_device *ade
 	return NULL;
 }
 
-static void dce_v6_0_afmt_audio_select_pin(struct drm_encoder *encoder)
+static void dce_v6_0_audio_select_pin(struct drm_encoder *encoder)
 {
 	struct amdgpu_device *adev = encoder->dev->dev_private;
 	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
 	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
-	u32 offset;
 
 	if (!dig || !dig->afmt || !dig->afmt->pin)
 		return;
 
-	offset = dig->afmt->offset;
-
-	WREG32(AFMT_AUDIO_SRC_CONTROL + offset,
-	       AFMT_AUDIO_SRC_SELECT(dig->afmt->pin->id));
-
+	WREG32(mmAFMT_AUDIO_SRC_CONTROL + dig->afmt->offset,
+	       REG_SET_FIELD(0, AFMT_AUDIO_SRC_CONTROL, AFMT_AUDIO_SRC_SELECT,
+		             dig->afmt->pin->id));
 }
 
 static void dce_v6_0_audio_write_latency_fields(struct drm_encoder *encoder,
 						struct drm_display_mode *mode)
 {
-	DRM_INFO("xxxx: dce_v6_0_audio_write_latency_fields---no imp!!!!!\n");
+	struct amdgpu_device *adev = encoder->dev->dev_private;
+	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
+	struct drm_connector *connector;
+	struct amdgpu_connector *amdgpu_connector = NULL;
+	int interlace = 0;
+	u32 tmp;
+
+	list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
+		if (connector->encoder == encoder) {
+			amdgpu_connector = to_amdgpu_connector(connector);
+			break;
+		}
+	}
+
+	if (!amdgpu_connector) {
+		DRM_ERROR("Couldn't find encoder's connector\n");
+		return;
+	}
+
+	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+		interlace = 1;
+
+	if (connector->latency_present[interlace]) {
+		tmp = REG_SET_FIELD(0, AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
+				VIDEO_LIPSYNC, connector->video_latency[interlace]);
+		tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
+				AUDIO_LIPSYNC, connector->audio_latency[interlace]);
+	} else {
+		tmp = REG_SET_FIELD(0, AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
+				VIDEO_LIPSYNC, 0);
+		tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
+				AUDIO_LIPSYNC, 0);
+	}
+	WREG32_AUDIO_ENDPT(dig->afmt->pin->offset,
+			   ixAZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC, tmp);
 }
 
 static void dce_v6_0_audio_write_speaker_allocation(struct drm_encoder *encoder)
 {
-	DRM_INFO("xxxx: dce_v6_0_audio_write_speaker_allocation---no imp!!!!!\n");
+	struct amdgpu_device *adev = encoder->dev->dev_private;
+	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
+	struct drm_connector *connector;
+	struct amdgpu_connector *amdgpu_connector = NULL;
+	u8 *sadb = NULL;
+	int sad_count;
+	u32 tmp;
+
+	list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
+		if (connector->encoder == encoder) {
+			amdgpu_connector = to_amdgpu_connector(connector);
+			break;
+		}
+	}
+
+	if (!amdgpu_connector) {
+		DRM_ERROR("Couldn't find encoder's connector\n");
+		return;
+	}
+
+	sad_count = drm_edid_to_speaker_allocation(amdgpu_connector_edid(connector), &sadb);
+	if (sad_count < 0) {
+		DRM_ERROR("Couldn't read Speaker Allocation Data Block: %d\n", sad_count);
+		sad_count = 0;
+	}
+
+	/* program the speaker allocation */
+	tmp = RREG32_AUDIO_ENDPT(dig->afmt->pin->offset,
+			ixAZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER);
+	tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
+			HDMI_CONNECTION, 0);
+	tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
+			DP_CONNECTION, 0);
+
+	if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort)
+		tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
+				DP_CONNECTION, 1);
+	else
+		tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
+				HDMI_CONNECTION, 1);
+
+	if (sad_count)
+		tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
+				SPEAKER_ALLOCATION, sadb[0]);
+	else
+		tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
+				SPEAKER_ALLOCATION, 5); /* stereo */
+
+	WREG32_AUDIO_ENDPT(dig->afmt->pin->offset,
+			ixAZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, tmp);
+
+	kfree(sadb);
 }
 
 static void dce_v6_0_audio_write_sad_regs(struct drm_encoder *encoder)
 {
-	DRM_INFO("xxxx: dce_v6_0_audio_write_sad_regs---no imp!!!!!\n");
+	struct amdgpu_device *adev = encoder->dev->dev_private;
+	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
+	struct drm_connector *connector;
+	struct amdgpu_connector *amdgpu_connector = NULL;
+	struct cea_sad *sads;
+	int i, sad_count;
+
+	static const u16 eld_reg_to_type[][2] = {
+		{ ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0, HDMI_AUDIO_CODING_TYPE_PCM },
+		{ ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR1, HDMI_AUDIO_CODING_TYPE_AC3 },
+		{ ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR2, HDMI_AUDIO_CODING_TYPE_MPEG1 },
+		{ ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR3, HDMI_AUDIO_CODING_TYPE_MP3 },
+		{ ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR4, HDMI_AUDIO_CODING_TYPE_MPEG2 },
+		{ ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR5, HDMI_AUDIO_CODING_TYPE_AAC_LC },
+		{ ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR6, HDMI_AUDIO_CODING_TYPE_DTS },
+		{ ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR7, HDMI_AUDIO_CODING_TYPE_ATRAC },
+		{ ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR9, HDMI_AUDIO_CODING_TYPE_EAC3 },
+		{ ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR10, HDMI_AUDIO_CODING_TYPE_DTS_HD },
+		{ ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR11, HDMI_AUDIO_CODING_TYPE_MLP },
+		{ ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR13, HDMI_AUDIO_CODING_TYPE_WMA_PRO },
+	};
+
+	list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
+		if (connector->encoder == encoder) {
+			amdgpu_connector = to_amdgpu_connector(connector);
+			break;
+		}
+	}
+
+	if (!amdgpu_connector) {
+		DRM_ERROR("Couldn't find encoder's connector\n");
+		return;
+	}
+
+	sad_count = drm_edid_to_sad(amdgpu_connector_edid(connector), &sads);
+	if (sad_count <= 0) {
+		DRM_ERROR("Couldn't read SADs: %d\n", sad_count);
+		return;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(eld_reg_to_type); i++) {
+		u32 tmp = 0;
+		u8 stereo_freqs = 0;
+		int max_channels = -1;
+		int j;
+
+		for (j = 0; j < sad_count; j++) {
+			struct cea_sad *sad = &sads[j];
+
+			if (sad->format == eld_reg_to_type[i][1]) {
+				if (sad->channels > max_channels) {
+					tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
+							MAX_CHANNELS, sad->channels);
+					tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
+							DESCRIPTOR_BYTE_2, sad->byte2);
+					tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
+							SUPPORTED_FREQUENCIES, sad->freq);
+					max_channels = sad->channels;
+				}
+
+				if (sad->format == HDMI_AUDIO_CODING_TYPE_PCM)
+					stereo_freqs |= sad->freq;
+				else
+					break;
+			}
+		}
+
+		tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
+				SUPPORTED_FREQUENCIES_STEREO, stereo_freqs);
+		WREG32_AUDIO_ENDPT(dig->afmt->pin->offset, eld_reg_to_type[i][0], tmp);
+	}
+
+	kfree(sads);
 
 }
-*/
+
 static void dce_v6_0_audio_enable(struct amdgpu_device *adev,
 				  struct amdgpu_audio_pin *pin,
 				  bool enable)
 {
-	DRM_INFO("xxxx: dce_v6_0_audio_enable---no imp!!!!!\n");
+	if (!pin)
+		return;
+
+	WREG32_AUDIO_ENDPT(pin->offset, ixAZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
+			enable ? AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL__AUDIO_ENABLED_MASK : 0);
 }
 
 static const u32 pin_offsets[7] =
@@ -1317,12 +1491,54 @@ static const u32 pin_offsets[7] =
 
 static int dce_v6_0_audio_init(struct amdgpu_device *adev)
 {
+	int i;
+
+	if (!amdgpu_audio)
+		return 0;
+
+	adev->mode_info.audio.enabled = true;
+
+	switch (adev->asic_type) {
+	case CHIP_TAHITI:
+	case CHIP_PITCAIRN:
+	case CHIP_VERDE:
+	default:
+		adev->mode_info.audio.num_pins = 6;
+		break;
+	case CHIP_OLAND:
+		adev->mode_info.audio.num_pins = 2;
+		break;
+	}
+
+	for (i = 0; i < adev->mode_info.audio.num_pins; i++) {
+		adev->mode_info.audio.pin[i].channels = -1;
+		adev->mode_info.audio.pin[i].rate = -1;
+		adev->mode_info.audio.pin[i].bits_per_sample = -1;
+		adev->mode_info.audio.pin[i].status_bits = 0;
+		adev->mode_info.audio.pin[i].category_code = 0;
+		adev->mode_info.audio.pin[i].connected = false;
+		adev->mode_info.audio.pin[i].offset = pin_offsets[i];
+		adev->mode_info.audio.pin[i].id = i;
+		dce_v6_0_audio_enable(adev, &adev->mode_info.audio.pin[i], false);
+	}
+
 	return 0;
 }
 
 static void dce_v6_0_audio_fini(struct amdgpu_device *adev)
 {
+	int i;
 
+	if (!amdgpu_audio)
+		return;
+
+	if (!adev->mode_info.audio.enabled)
+		return;
+
+	for (i = 0; i < adev->mode_info.audio.num_pins; i++)
+		dce_v6_0_audio_enable(adev, &adev->mode_info.audio.pin[i], false);
+
+	adev->mode_info.audio.enabled = false;
 }
 
 /*
@@ -1331,28 +1547,204 @@ static void dce_v6_0_afmt_update_ACR(struct drm_encoder *encoder, uint32_t clock
 	DRM_INFO("xxxx: dce_v6_0_afmt_update_ACR---no imp!!!!!\n");
 }
 */
-/*
- * build a HDMI Video Info Frame
- */
-/*
-static void dce_v6_0_afmt_update_avi_infoframe(struct drm_encoder *encoder,
-					       void *buffer, size_t size)
+
+static void dce_v6_0_audio_set_avi_infoframe(struct drm_encoder *encoder,
+					       struct drm_display_mode *mode)
 {
-	DRM_INFO("xxxx: dce_v6_0_afmt_update_avi_infoframe---no imp!!!!!\n");
+	struct drm_device *dev = encoder->dev;
+	struct amdgpu_device *adev = dev->dev_private;
+	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
+	struct hdmi_avi_infoframe frame;
+	u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE];
+	uint8_t *payload = buffer + 3;
+	uint8_t *header = buffer;
+	ssize_t err;
+	u32 tmp;
+
+	err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
+	if (err < 0) {
+		DRM_ERROR("failed to setup AVI infoframe: %zd\n", err);
+		return;
+	}
+
+	err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer));
+	if (err < 0) {
+		DRM_ERROR("failed to pack AVI infoframe: %zd\n", err);
+		return;
+	}
+
+	WREG32(mmAFMT_AVI_INFO0 + dig->afmt->offset,
+	       payload[0x0] | (payload[0x1] << 8) | (payload[0x2] << 16) | (payload[0x3] << 24));
+	WREG32(mmAFMT_AVI_INFO1 + dig->afmt->offset,
+	       payload[0x4] | (payload[0x5] << 8) | (payload[0x6] << 16) | (payload[0x7] << 24));
+	WREG32(mmAFMT_AVI_INFO2 + dig->afmt->offset,
+	       payload[0x8] | (payload[0x9] << 8) | (payload[0xA] << 16) | (payload[0xB] << 24));
+	WREG32(mmAFMT_AVI_INFO3 + dig->afmt->offset,
+	       payload[0xC] | (payload[0xD] << 8) | (header[1] << 24));
+
+	tmp = RREG32(mmHDMI_INFOFRAME_CONTROL1 + dig->afmt->offset);
+	/* anything other than 0 */
+	tmp = REG_SET_FIELD(tmp, HDMI_INFOFRAME_CONTROL1,
+			HDMI_AUDIO_INFO_LINE, 2);
+	WREG32(mmHDMI_INFOFRAME_CONTROL1 + dig->afmt->offset, tmp);
 }
 
 static void dce_v6_0_audio_set_dto(struct drm_encoder *encoder, u32 clock)
 {
-	DRM_INFO("xxxx: dce_v6_0_audio_set_dto---no imp!!!!!\n");
+	struct drm_device *dev = encoder->dev;
+	struct amdgpu_device *adev = dev->dev_private;
+	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(encoder->crtc);
+	u32 tmp;
+
+	/*
+	 * Two dtos: generally use dto0 for hdmi, dto1 for dp.
+	 * Express [24MHz / target pixel clock] as an exact rational
+	 * number (coefficient of two integer numbers.  DCCG_AUDIO_DTOx_PHASE
+	 * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
+	 */
+	tmp = RREG32(mmDCCG_AUDIO_DTO_SOURCE);
+	tmp = REG_SET_FIELD(tmp, DCCG_AUDIO_DTO_SOURCE,
+			DCCG_AUDIO_DTO0_SOURCE_SEL, amdgpu_crtc->crtc_id);
+	tmp = REG_SET_FIELD(tmp, DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO_SEL, 1);
+	WREG32(mmDCCG_AUDIO_DTO_SOURCE, tmp);
+	WREG32(mmDCCG_AUDIO_DTO1_PHASE, 24000);
+	WREG32(mmDCCG_AUDIO_DTO1_MODULE, clock);
 }
-*/
-/*
- * update the info frames with the data from the current display mode
- */
+
+static void dce_v6_0_audio_set_packet(struct drm_encoder *encoder)
+{
+	struct drm_device *dev = encoder->dev;
+	struct amdgpu_device *adev = dev->dev_private;
+	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
+	u32 tmp;
+
+	tmp = RREG32(mmAFMT_INFOFRAME_CONTROL0 + dig->afmt->offset);
+	tmp = REG_SET_FIELD(tmp, AFMT_INFOFRAME_CONTROL0, AFMT_AUDIO_INFO_UPDATE, 1);
+	WREG32(mmAFMT_INFOFRAME_CONTROL0 + dig->afmt->offset, tmp);
+
+	tmp = RREG32(mmAFMT_60958_0 + dig->afmt->offset);
+	tmp = REG_SET_FIELD(tmp, AFMT_60958_0, AFMT_60958_CS_CHANNEL_NUMBER_L, 1);
+	WREG32(mmAFMT_60958_0 + dig->afmt->offset, tmp);
+
+	tmp = RREG32(mmAFMT_60958_1 + dig->afmt->offset);
+	tmp = REG_SET_FIELD(tmp, AFMT_60958_1, AFMT_60958_CS_CHANNEL_NUMBER_R, 2);
+	WREG32(mmAFMT_60958_1 + dig->afmt->offset, tmp);
+
+	tmp = RREG32(mmAFMT_60958_2 + dig->afmt->offset);
+	tmp = REG_SET_FIELD(tmp, AFMT_60958_2, AFMT_60958_CS_CHANNEL_NUMBER_2, 3);
+	tmp = REG_SET_FIELD(tmp, AFMT_60958_2, AFMT_60958_CS_CHANNEL_NUMBER_3, 4);
+	tmp = REG_SET_FIELD(tmp, AFMT_60958_2, AFMT_60958_CS_CHANNEL_NUMBER_4, 5);
+	tmp = REG_SET_FIELD(tmp, AFMT_60958_2, AFMT_60958_CS_CHANNEL_NUMBER_5, 6);
+	tmp = REG_SET_FIELD(tmp, AFMT_60958_2, AFMT_60958_CS_CHANNEL_NUMBER_6, 7);
+	tmp = REG_SET_FIELD(tmp, AFMT_60958_2, AFMT_60958_CS_CHANNEL_NUMBER_7, 8);
+	WREG32(mmAFMT_60958_2 + dig->afmt->offset, tmp);
+
+	tmp = RREG32(mmAFMT_AUDIO_PACKET_CONTROL2 + dig->afmt->offset);
+	tmp = REG_SET_FIELD(tmp, AFMT_AUDIO_PACKET_CONTROL2, AFMT_AUDIO_CHANNEL_ENABLE, 0xff);
+	WREG32(mmAFMT_AUDIO_PACKET_CONTROL2 + dig->afmt->offset, tmp);
+
+	tmp = RREG32(mmHDMI_AUDIO_PACKET_CONTROL + dig->afmt->offset);
+	tmp = REG_SET_FIELD(tmp, HDMI_AUDIO_PACKET_CONTROL, HDMI_AUDIO_DELAY_EN, 1);
+	tmp = REG_SET_FIELD(tmp, HDMI_AUDIO_PACKET_CONTROL, HDMI_AUDIO_PACKETS_PER_LINE, 3);
+	WREG32(mmHDMI_AUDIO_PACKET_CONTROL + dig->afmt->offset, tmp);
+
+	tmp = RREG32(mmAFMT_AUDIO_PACKET_CONTROL + dig->afmt->offset);
+	tmp = REG_SET_FIELD(tmp, AFMT_AUDIO_PACKET_CONTROL, AFMT_RESET_FIFO_WHEN_AUDIO_DIS, 1);
+	tmp = REG_SET_FIELD(tmp, AFMT_AUDIO_PACKET_CONTROL, AFMT_60958_CS_UPDATE, 1);
+	WREG32(mmAFMT_AUDIO_PACKET_CONTROL + dig->afmt->offset, tmp);
+}
+
+static void dce_v6_0_audio_set_mute(struct drm_encoder *encoder, bool mute)
+{
+	struct drm_device *dev = encoder->dev;
+	struct amdgpu_device *adev = dev->dev_private;
+	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
+	u32 tmp;
+
+	tmp = RREG32(mmHDMI_GC + dig->afmt->offset);
+	tmp = REG_SET_FIELD(tmp, HDMI_GC, HDMI_GC_AVMUTE, mute ? 1 : 0);
+	WREG32(mmHDMI_GC + dig->afmt->offset, tmp);
+}
+
+static void dce_v6_0_audio_dp_enable(struct drm_encoder *encoder, bool enable)
+{
+	struct drm_device *dev = encoder->dev;
+	struct amdgpu_device *adev = dev->dev_private;
+	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
+	u32 tmp;
+
+	if (enable) {
+		tmp = RREG32(mmAFMT_AUDIO_PACKET_CONTROL + dig->afmt->offset);
+		tmp = REG_SET_FIELD(tmp, AFMT_AUDIO_PACKET_CONTROL, AFMT_AUDIO_SAMPLE_SEND, 1);
+		WREG32(mmAFMT_AUDIO_PACKET_CONTROL + dig->afmt->offset, tmp);
+
+		tmp = RREG32(mmDP_SEC_TIMESTAMP + dig->afmt->offset);
+		tmp = REG_SET_FIELD(tmp, DP_SEC_TIMESTAMP, DP_SEC_TIMESTAMP_MODE, 1);
+		WREG32(mmDP_SEC_TIMESTAMP + dig->afmt->offset, tmp);
+
+		tmp = RREG32(mmDP_SEC_CNTL + dig->afmt->offset);
+		tmp = REG_SET_FIELD(tmp, DP_SEC_CNTL, DP_SEC_ASP_ENABLE, 1);
+		tmp = REG_SET_FIELD(tmp, DP_SEC_CNTL, DP_SEC_ATP_ENABLE, 1);
+		tmp = REG_SET_FIELD(tmp, DP_SEC_CNTL, DP_SEC_AIP_ENABLE, 1);
+		tmp = REG_SET_FIELD(tmp, DP_SEC_CNTL, DP_SEC_STREAM_ENABLE, 1);
+		WREG32(mmDP_SEC_CNTL + dig->afmt->offset, tmp);
+	} else {
+		WREG32(mmDP_SEC_CNTL + dig->afmt->offset, 0);
+	}
+}
+
 static void dce_v6_0_afmt_setmode(struct drm_encoder *encoder,
 				  struct drm_display_mode *mode)
 {
-	DRM_INFO("xxxx: dce_v6_0_afmt_setmode ----no impl !!!!!!!!\n");
+	struct drm_device *dev = encoder->dev;
+	struct amdgpu_device *adev = dev->dev_private;
+	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
+	struct drm_connector *connector;
+	struct amdgpu_connector *amdgpu_connector = NULL;
+
+	if (!dig || !dig->afmt)
+		return;
+
+	list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
+		if (connector->encoder == encoder) {
+			amdgpu_connector = to_amdgpu_connector(connector);
+			break;
+		}
+	}
+
+	if (!amdgpu_connector) {
+		DRM_ERROR("Couldn't find encoder's connector\n");
+		return;
+	}
+
+	if (!dig->afmt->enabled)
+		return;
+
+	dig->afmt->pin = dce_v6_0_audio_get_pin(adev);
+	if (!dig->afmt->pin)
+		return;
+
+	/* disable audio before setting up hw */
+	dce_v6_0_audio_enable(adev, dig->afmt->pin, false);
+
+	dce_v6_0_audio_set_mute(encoder, true);
+	dce_v6_0_audio_write_speaker_allocation(encoder);
+	dce_v6_0_audio_write_sad_regs(encoder);
+	dce_v6_0_audio_write_latency_fields(encoder, mode);
+	dce_v6_0_audio_set_dto(encoder, adev->clock.default_dispclk * 10);
+	dce_v6_0_audio_set_packet(encoder);
+	dce_v6_0_audio_select_pin(encoder);
+	dce_v6_0_audio_set_avi_infoframe(encoder, mode);
+	dce_v6_0_audio_set_mute(encoder, false);
+	dce_v6_0_audio_dp_enable(encoder, 1);
+
+	/* enable audio after setting up hw */
+	dce_v6_0_audio_enable(adev, dig->afmt->pin, true);
 }
 
 static void dce_v6_0_afmt_enable(struct drm_encoder *encoder, bool enable)
@@ -1368,6 +1760,7 @@ static void dce_v6_0_afmt_enable(struct drm_encoder *encoder, bool enable)
 	/* Silent, r600_hdmi_enable will raise WARN for us */
 	if (enable && dig->afmt->enabled)
 		return;
+
 	if (!enable && !dig->afmt->enabled)
 		return;
 
@@ -2781,6 +3174,7 @@ dce_v6_0_encoder_mode_set(struct drm_encoder *encoder,
 {
 
 	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+	int em = amdgpu_atombios_encoder_get_encoder_mode(encoder);
 
 	amdgpu_encoder->pixel_clock = adjusted_mode->clock;
 
@@ -2790,7 +3184,7 @@ dce_v6_0_encoder_mode_set(struct drm_encoder *encoder,
 	/* set scaler clears this on some chips */
 	dce_v6_0_set_interleave(encoder->crtc, mode);
 
-	if (amdgpu_atombios_encoder_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) {
+	if (em == ATOM_ENCODER_MODE_HDMI || ENCODER_MODE_IS_DP(em)) {
 		dce_v6_0_afmt_enable(encoder, true);
 		dce_v6_0_afmt_setmode(encoder, adjusted_mode);
 	}
@@ -2852,11 +3246,12 @@ static void dce_v6_0_encoder_disable(struct drm_encoder *encoder)
 
 	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
 	struct amdgpu_encoder_atom_dig *dig;
+	int em = amdgpu_atombios_encoder_get_encoder_mode(encoder);
 
 	amdgpu_atombios_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
 
 	if (amdgpu_atombios_encoder_is_digital(encoder)) {
-		if (amdgpu_atombios_encoder_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI)
+		if (em == ATOM_ENCODER_MODE_HDMI || ENCODER_MODE_IS_DP(em))
 			dce_v6_0_afmt_enable(encoder, false);
 		dig = amdgpu_encoder->enc_priv;
 		dig->dig_encoder = -1;
diff --git a/drivers/gpu/drm/amd/include/asic_reg/dce/dce_6_0_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/dce/dce_6_0_sh_mask.h
index 9a4d4c2..abe05bc 100644
--- a/drivers/gpu/drm/amd/include/asic_reg/dce/dce_6_0_sh_mask.h
+++ b/drivers/gpu/drm/amd/include/asic_reg/dce/dce_6_0_sh_mask.h
@@ -906,6 +906,8 @@
 #define AZALIA_F0_CODEC_ENDPOINT_DATA__AZALIA_ENDPOINT_REG_DATA__SHIFT 0x00000000
 #define AZALIA_F0_CODEC_ENDPOINT_INDEX__AZALIA_ENDPOINT_REG_INDEX_MASK 0x000000ffL
 #define AZALIA_F0_CODEC_ENDPOINT_INDEX__AZALIA_ENDPOINT_REG_INDEX__SHIFT 0x00000000
+#define AZALIA_F0_CODEC_ENDPOINT_INDEX__AZALIA_ENDPOINT_REG_WRITE_EN_MASK 0x00000100L
+#define AZALIA_F0_CODEC_ENDPOINT_INDEX__AZALIA_ENDPOINT_REG_WRITE_EN__SHIFT 0x00000008
 #define AZALIA_F0_CODEC_FUNCTION_CONTROL_CONVERTER_SYNCHRONIZATION__CONVERTER_SYNCHRONIZATION_MASK 0x0000003fL
 #define AZALIA_F0_CODEC_FUNCTION_CONTROL_CONVERTER_SYNCHRONIZATION__CONVERTER_SYNCHRONIZATION__SHIFT 0x00000000
 #define AZALIA_F0_CODEC_FUNCTION_CONTROL_POWER_STATE__CLKSTOPOK_MASK 0x00000200L
-- 
2.7.4

_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH v3] drm/amdgpu: add DP audio support for si dce6 (v3)
       [not found] ` <1487734626-27738-1-git-send-email-Xiaojie.Yuan-5C7GfCeVMHo@public.gmane.org>
@ 2017-02-22  4:40   ` Edward O'Callaghan
       [not found]     ` <86e62166-a3fa-92af-17d1-4bf1f90f1583-dczkZgxz+BNUPWh3PAxdjQ@public.gmane.org>
  2017-02-22 17:08   ` Deucher, Alexander
  1 sibling, 1 reply; 4+ messages in thread
From: Edward O'Callaghan @ 2017-02-22  4:40 UTC (permalink / raw)
  To: Xiaojie Yuan, amd-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW


[-- Attachment #1.1.1: Type: text/plain, Size: 25053 bytes --]

Reviewed-by: Edward O'Callaghan <funfunctor-dczkZgxz+BNUPWh3PAxdjQ@public.gmane.org>

On 02/22/2017 02:37 PM, Xiaojie Yuan wrote:
> v2: refine dce_v6_0_audio_endpt_wreg() and unify inconsistent method names
> v3: fix num_pins for tahiti, pitcairn, verde and oland
> 
> Signed-off-by: Xiaojie Yuan <Xiaojie.Yuan-5C7GfCeVMHo@public.gmane.org>
> ---
>  drivers/gpu/drm/amd/amdgpu/dce_v6_0.c              | 467 +++++++++++++++++++--
>  .../drm/amd/include/asic_reg/dce/dce_6_0_sh_mask.h |   2 +
>  2 files changed, 433 insertions(+), 36 deletions(-)
> 
> diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
> index 94877cb..7c11ed8 100644
> --- a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
> +++ b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
> @@ -118,14 +118,27 @@ static const struct {
>  static u32 dce_v6_0_audio_endpt_rreg(struct amdgpu_device *adev,
>  				     u32 block_offset, u32 reg)
>  {
> -	DRM_INFO("xxxx: dce_v6_0_audio_endpt_rreg ----no impl!!!!\n");
> -	return 0;
> +	unsigned long flags;
> +	u32 r;
> +
> +	spin_lock_irqsave(&adev->audio_endpt_idx_lock, flags);
> +	WREG32(mmAZALIA_F0_CODEC_ENDPOINT_INDEX + block_offset, reg);
> +	r = RREG32(mmAZALIA_F0_CODEC_ENDPOINT_DATA + block_offset);
> +	spin_unlock_irqrestore(&adev->audio_endpt_idx_lock, flags);
> +
> +	return r;
>  }
>  
>  static void dce_v6_0_audio_endpt_wreg(struct amdgpu_device *adev,
>  				      u32 block_offset, u32 reg, u32 v)
>  {
> -	DRM_INFO("xxxx: dce_v6_0_audio_endpt_wreg ----no impl!!!!\n");
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&adev->audio_endpt_idx_lock, flags);
> +	WREG32(mmAZALIA_F0_CODEC_ENDPOINT_INDEX + block_offset,
> +		reg | AZALIA_F0_CODEC_ENDPOINT_INDEX__AZALIA_ENDPOINT_REG_WRITE_EN_MASK);
> +	WREG32(mmAZALIA_F0_CODEC_ENDPOINT_DATA + block_offset, v);
> +	spin_unlock_irqrestore(&adev->audio_endpt_idx_lock, flags);
>  }
>  
>  static bool dce_v6_0_is_in_vblank(struct amdgpu_device *adev, int crtc)
> @@ -1231,17 +1244,17 @@ static void dce_v6_0_bandwidth_update(struct amdgpu_device *adev)
>  		dce_v6_0_program_watermarks(adev, adev->mode_info.crtcs[i+1], lb_size, num_heads);
>  	}
>  }
> -/*
> +
>  static void dce_v6_0_audio_get_connected_pins(struct amdgpu_device *adev)
>  {
>  	int i;
> -	u32 offset, tmp;
> +	u32 tmp;
>  
>  	for (i = 0; i < adev->mode_info.audio.num_pins; i++) {
> -		offset = adev->mode_info.audio.pin[i].offset;
> -		tmp = RREG32_AUDIO_ENDPT(offset,
> -				      AZ_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT);
> -		if (((tmp & PORT_CONNECTIVITY_MASK) >> PORT_CONNECTIVITY_SHIFT) == 1)
> +		tmp = RREG32_AUDIO_ENDPT(adev->mode_info.audio.pin[i].offset,
> +				ixAZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT);
> +		if (REG_GET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT,
> +					PORT_CONNECTIVITY))
>  			adev->mode_info.audio.pin[i].connected = false;
>  		else
>  			adev->mode_info.audio.pin[i].connected = true;
> @@ -1263,45 +1276,206 @@ static struct amdgpu_audio_pin *dce_v6_0_audio_get_pin(struct amdgpu_device *ade
>  	return NULL;
>  }
>  
> -static void dce_v6_0_afmt_audio_select_pin(struct drm_encoder *encoder)
> +static void dce_v6_0_audio_select_pin(struct drm_encoder *encoder)
>  {
>  	struct amdgpu_device *adev = encoder->dev->dev_private;
>  	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
>  	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
> -	u32 offset;
>  
>  	if (!dig || !dig->afmt || !dig->afmt->pin)
>  		return;
>  
> -	offset = dig->afmt->offset;
> -
> -	WREG32(AFMT_AUDIO_SRC_CONTROL + offset,
> -	       AFMT_AUDIO_SRC_SELECT(dig->afmt->pin->id));
> -
> +	WREG32(mmAFMT_AUDIO_SRC_CONTROL + dig->afmt->offset,
> +	       REG_SET_FIELD(0, AFMT_AUDIO_SRC_CONTROL, AFMT_AUDIO_SRC_SELECT,
> +		             dig->afmt->pin->id));
>  }
>  
>  static void dce_v6_0_audio_write_latency_fields(struct drm_encoder *encoder,
>  						struct drm_display_mode *mode)
>  {
> -	DRM_INFO("xxxx: dce_v6_0_audio_write_latency_fields---no imp!!!!!\n");
> +	struct amdgpu_device *adev = encoder->dev->dev_private;
> +	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
> +	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
> +	struct drm_connector *connector;
> +	struct amdgpu_connector *amdgpu_connector = NULL;
> +	int interlace = 0;
> +	u32 tmp;
> +
> +	list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
> +		if (connector->encoder == encoder) {
> +			amdgpu_connector = to_amdgpu_connector(connector);
> +			break;
> +		}
> +	}
> +
> +	if (!amdgpu_connector) {
> +		DRM_ERROR("Couldn't find encoder's connector\n");
> +		return;
> +	}
> +
> +	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
> +		interlace = 1;
> +
> +	if (connector->latency_present[interlace]) {
> +		tmp = REG_SET_FIELD(0, AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
> +				VIDEO_LIPSYNC, connector->video_latency[interlace]);
> +		tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
> +				AUDIO_LIPSYNC, connector->audio_latency[interlace]);
> +	} else {
> +		tmp = REG_SET_FIELD(0, AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
> +				VIDEO_LIPSYNC, 0);
> +		tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
> +				AUDIO_LIPSYNC, 0);
> +	}
> +	WREG32_AUDIO_ENDPT(dig->afmt->pin->offset,
> +			   ixAZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC, tmp);
>  }
>  
>  static void dce_v6_0_audio_write_speaker_allocation(struct drm_encoder *encoder)
>  {
> -	DRM_INFO("xxxx: dce_v6_0_audio_write_speaker_allocation---no imp!!!!!\n");
> +	struct amdgpu_device *adev = encoder->dev->dev_private;
> +	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
> +	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
> +	struct drm_connector *connector;
> +	struct amdgpu_connector *amdgpu_connector = NULL;
> +	u8 *sadb = NULL;
> +	int sad_count;
> +	u32 tmp;
> +
> +	list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
> +		if (connector->encoder == encoder) {
> +			amdgpu_connector = to_amdgpu_connector(connector);
> +			break;
> +		}
> +	}
> +
> +	if (!amdgpu_connector) {
> +		DRM_ERROR("Couldn't find encoder's connector\n");
> +		return;
> +	}
> +
> +	sad_count = drm_edid_to_speaker_allocation(amdgpu_connector_edid(connector), &sadb);
> +	if (sad_count < 0) {
> +		DRM_ERROR("Couldn't read Speaker Allocation Data Block: %d\n", sad_count);
> +		sad_count = 0;
> +	}
> +
> +	/* program the speaker allocation */
> +	tmp = RREG32_AUDIO_ENDPT(dig->afmt->pin->offset,
> +			ixAZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER);
> +	tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
> +			HDMI_CONNECTION, 0);
> +	tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
> +			DP_CONNECTION, 0);
> +
> +	if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort)
> +		tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
> +				DP_CONNECTION, 1);
> +	else
> +		tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
> +				HDMI_CONNECTION, 1);
> +
> +	if (sad_count)
> +		tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
> +				SPEAKER_ALLOCATION, sadb[0]);
> +	else
> +		tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
> +				SPEAKER_ALLOCATION, 5); /* stereo */
> +
> +	WREG32_AUDIO_ENDPT(dig->afmt->pin->offset,
> +			ixAZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, tmp);
> +
> +	kfree(sadb);
>  }
>  
>  static void dce_v6_0_audio_write_sad_regs(struct drm_encoder *encoder)
>  {
> -	DRM_INFO("xxxx: dce_v6_0_audio_write_sad_regs---no imp!!!!!\n");
> +	struct amdgpu_device *adev = encoder->dev->dev_private;
> +	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
> +	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
> +	struct drm_connector *connector;
> +	struct amdgpu_connector *amdgpu_connector = NULL;
> +	struct cea_sad *sads;
> +	int i, sad_count;
> +
> +	static const u16 eld_reg_to_type[][2] = {
> +		{ ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0, HDMI_AUDIO_CODING_TYPE_PCM },
> +		{ ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR1, HDMI_AUDIO_CODING_TYPE_AC3 },
> +		{ ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR2, HDMI_AUDIO_CODING_TYPE_MPEG1 },
> +		{ ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR3, HDMI_AUDIO_CODING_TYPE_MP3 },
> +		{ ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR4, HDMI_AUDIO_CODING_TYPE_MPEG2 },
> +		{ ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR5, HDMI_AUDIO_CODING_TYPE_AAC_LC },
> +		{ ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR6, HDMI_AUDIO_CODING_TYPE_DTS },
> +		{ ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR7, HDMI_AUDIO_CODING_TYPE_ATRAC },
> +		{ ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR9, HDMI_AUDIO_CODING_TYPE_EAC3 },
> +		{ ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR10, HDMI_AUDIO_CODING_TYPE_DTS_HD },
> +		{ ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR11, HDMI_AUDIO_CODING_TYPE_MLP },
> +		{ ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR13, HDMI_AUDIO_CODING_TYPE_WMA_PRO },
> +	};
> +
> +	list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
> +		if (connector->encoder == encoder) {
> +			amdgpu_connector = to_amdgpu_connector(connector);
> +			break;
> +		}
> +	}
> +
> +	if (!amdgpu_connector) {
> +		DRM_ERROR("Couldn't find encoder's connector\n");
> +		return;
> +	}
> +
> +	sad_count = drm_edid_to_sad(amdgpu_connector_edid(connector), &sads);
> +	if (sad_count <= 0) {
> +		DRM_ERROR("Couldn't read SADs: %d\n", sad_count);
> +		return;
> +	}
> +
> +	for (i = 0; i < ARRAY_SIZE(eld_reg_to_type); i++) {
> +		u32 tmp = 0;
> +		u8 stereo_freqs = 0;
> +		int max_channels = -1;
> +		int j;
> +
> +		for (j = 0; j < sad_count; j++) {
> +			struct cea_sad *sad = &sads[j];
> +
> +			if (sad->format == eld_reg_to_type[i][1]) {
> +				if (sad->channels > max_channels) {
> +					tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
> +							MAX_CHANNELS, sad->channels);
> +					tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
> +							DESCRIPTOR_BYTE_2, sad->byte2);
> +					tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
> +							SUPPORTED_FREQUENCIES, sad->freq);
> +					max_channels = sad->channels;
> +				}
> +
> +				if (sad->format == HDMI_AUDIO_CODING_TYPE_PCM)
> +					stereo_freqs |= sad->freq;
> +				else
> +					break;
> +			}
> +		}
> +
> +		tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
> +				SUPPORTED_FREQUENCIES_STEREO, stereo_freqs);
> +		WREG32_AUDIO_ENDPT(dig->afmt->pin->offset, eld_reg_to_type[i][0], tmp);
> +	}
> +
> +	kfree(sads);
>  
>  }
> -*/
> +
>  static void dce_v6_0_audio_enable(struct amdgpu_device *adev,
>  				  struct amdgpu_audio_pin *pin,
>  				  bool enable)
>  {
> -	DRM_INFO("xxxx: dce_v6_0_audio_enable---no imp!!!!!\n");
> +	if (!pin)
> +		return;
> +
> +	WREG32_AUDIO_ENDPT(pin->offset, ixAZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
> +			enable ? AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL__AUDIO_ENABLED_MASK : 0);
>  }
>  
>  static const u32 pin_offsets[7] =
> @@ -1317,12 +1491,54 @@ static const u32 pin_offsets[7] =
>  
>  static int dce_v6_0_audio_init(struct amdgpu_device *adev)
>  {
> +	int i;
> +
> +	if (!amdgpu_audio)
> +		return 0;
> +
> +	adev->mode_info.audio.enabled = true;
> +
> +	switch (adev->asic_type) {
> +	case CHIP_TAHITI:
> +	case CHIP_PITCAIRN:
> +	case CHIP_VERDE:
> +	default:
> +		adev->mode_info.audio.num_pins = 6;
> +		break;
> +	case CHIP_OLAND:
> +		adev->mode_info.audio.num_pins = 2;
> +		break;
> +	}
> +
> +	for (i = 0; i < adev->mode_info.audio.num_pins; i++) {
> +		adev->mode_info.audio.pin[i].channels = -1;
> +		adev->mode_info.audio.pin[i].rate = -1;
> +		adev->mode_info.audio.pin[i].bits_per_sample = -1;
> +		adev->mode_info.audio.pin[i].status_bits = 0;
> +		adev->mode_info.audio.pin[i].category_code = 0;
> +		adev->mode_info.audio.pin[i].connected = false;
> +		adev->mode_info.audio.pin[i].offset = pin_offsets[i];
> +		adev->mode_info.audio.pin[i].id = i;
> +		dce_v6_0_audio_enable(adev, &adev->mode_info.audio.pin[i], false);
> +	}
> +
>  	return 0;
>  }
>  
>  static void dce_v6_0_audio_fini(struct amdgpu_device *adev)
>  {
> +	int i;
>  
> +	if (!amdgpu_audio)
> +		return;
> +
> +	if (!adev->mode_info.audio.enabled)
> +		return;
> +
> +	for (i = 0; i < adev->mode_info.audio.num_pins; i++)
> +		dce_v6_0_audio_enable(adev, &adev->mode_info.audio.pin[i], false);
> +
> +	adev->mode_info.audio.enabled = false;
>  }
>  
>  /*
> @@ -1331,28 +1547,204 @@ static void dce_v6_0_afmt_update_ACR(struct drm_encoder *encoder, uint32_t clock
>  	DRM_INFO("xxxx: dce_v6_0_afmt_update_ACR---no imp!!!!!\n");
>  }
>  */
> -/*
> - * build a HDMI Video Info Frame
> - */
> -/*
> -static void dce_v6_0_afmt_update_avi_infoframe(struct drm_encoder *encoder,
> -					       void *buffer, size_t size)
> +
> +static void dce_v6_0_audio_set_avi_infoframe(struct drm_encoder *encoder,
> +					       struct drm_display_mode *mode)
>  {
> -	DRM_INFO("xxxx: dce_v6_0_afmt_update_avi_infoframe---no imp!!!!!\n");
> +	struct drm_device *dev = encoder->dev;
> +	struct amdgpu_device *adev = dev->dev_private;
> +	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
> +	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
> +	struct hdmi_avi_infoframe frame;
> +	u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE];
> +	uint8_t *payload = buffer + 3;
> +	uint8_t *header = buffer;
> +	ssize_t err;
> +	u32 tmp;
> +
> +	err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
> +	if (err < 0) {
> +		DRM_ERROR("failed to setup AVI infoframe: %zd\n", err);
> +		return;
> +	}
> +
> +	err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer));
> +	if (err < 0) {
> +		DRM_ERROR("failed to pack AVI infoframe: %zd\n", err);
> +		return;
> +	}
> +
> +	WREG32(mmAFMT_AVI_INFO0 + dig->afmt->offset,
> +	       payload[0x0] | (payload[0x1] << 8) | (payload[0x2] << 16) | (payload[0x3] << 24));
> +	WREG32(mmAFMT_AVI_INFO1 + dig->afmt->offset,
> +	       payload[0x4] | (payload[0x5] << 8) | (payload[0x6] << 16) | (payload[0x7] << 24));
> +	WREG32(mmAFMT_AVI_INFO2 + dig->afmt->offset,
> +	       payload[0x8] | (payload[0x9] << 8) | (payload[0xA] << 16) | (payload[0xB] << 24));
> +	WREG32(mmAFMT_AVI_INFO3 + dig->afmt->offset,
> +	       payload[0xC] | (payload[0xD] << 8) | (header[1] << 24));
> +
> +	tmp = RREG32(mmHDMI_INFOFRAME_CONTROL1 + dig->afmt->offset);
> +	/* anything other than 0 */
> +	tmp = REG_SET_FIELD(tmp, HDMI_INFOFRAME_CONTROL1,
> +			HDMI_AUDIO_INFO_LINE, 2);
> +	WREG32(mmHDMI_INFOFRAME_CONTROL1 + dig->afmt->offset, tmp);
>  }
>  
>  static void dce_v6_0_audio_set_dto(struct drm_encoder *encoder, u32 clock)
>  {
> -	DRM_INFO("xxxx: dce_v6_0_audio_set_dto---no imp!!!!!\n");
> +	struct drm_device *dev = encoder->dev;
> +	struct amdgpu_device *adev = dev->dev_private;
> +	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(encoder->crtc);
> +	u32 tmp;
> +
> +	/*
> +	 * Two dtos: generally use dto0 for hdmi, dto1 for dp.
> +	 * Express [24MHz / target pixel clock] as an exact rational
> +	 * number (coefficient of two integer numbers.  DCCG_AUDIO_DTOx_PHASE
> +	 * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
> +	 */
> +	tmp = RREG32(mmDCCG_AUDIO_DTO_SOURCE);
> +	tmp = REG_SET_FIELD(tmp, DCCG_AUDIO_DTO_SOURCE,
> +			DCCG_AUDIO_DTO0_SOURCE_SEL, amdgpu_crtc->crtc_id);
> +	tmp = REG_SET_FIELD(tmp, DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO_SEL, 1);
> +	WREG32(mmDCCG_AUDIO_DTO_SOURCE, tmp);
> +	WREG32(mmDCCG_AUDIO_DTO1_PHASE, 24000);
> +	WREG32(mmDCCG_AUDIO_DTO1_MODULE, clock);
>  }
> -*/
> -/*
> - * update the info frames with the data from the current display mode
> - */
> +
> +static void dce_v6_0_audio_set_packet(struct drm_encoder *encoder)
> +{
> +	struct drm_device *dev = encoder->dev;
> +	struct amdgpu_device *adev = dev->dev_private;
> +	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
> +	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
> +	u32 tmp;
> +
> +	tmp = RREG32(mmAFMT_INFOFRAME_CONTROL0 + dig->afmt->offset);
> +	tmp = REG_SET_FIELD(tmp, AFMT_INFOFRAME_CONTROL0, AFMT_AUDIO_INFO_UPDATE, 1);
> +	WREG32(mmAFMT_INFOFRAME_CONTROL0 + dig->afmt->offset, tmp);
> +
> +	tmp = RREG32(mmAFMT_60958_0 + dig->afmt->offset);
> +	tmp = REG_SET_FIELD(tmp, AFMT_60958_0, AFMT_60958_CS_CHANNEL_NUMBER_L, 1);
> +	WREG32(mmAFMT_60958_0 + dig->afmt->offset, tmp);
> +
> +	tmp = RREG32(mmAFMT_60958_1 + dig->afmt->offset);
> +	tmp = REG_SET_FIELD(tmp, AFMT_60958_1, AFMT_60958_CS_CHANNEL_NUMBER_R, 2);
> +	WREG32(mmAFMT_60958_1 + dig->afmt->offset, tmp);
> +
> +	tmp = RREG32(mmAFMT_60958_2 + dig->afmt->offset);
> +	tmp = REG_SET_FIELD(tmp, AFMT_60958_2, AFMT_60958_CS_CHANNEL_NUMBER_2, 3);
> +	tmp = REG_SET_FIELD(tmp, AFMT_60958_2, AFMT_60958_CS_CHANNEL_NUMBER_3, 4);
> +	tmp = REG_SET_FIELD(tmp, AFMT_60958_2, AFMT_60958_CS_CHANNEL_NUMBER_4, 5);
> +	tmp = REG_SET_FIELD(tmp, AFMT_60958_2, AFMT_60958_CS_CHANNEL_NUMBER_5, 6);
> +	tmp = REG_SET_FIELD(tmp, AFMT_60958_2, AFMT_60958_CS_CHANNEL_NUMBER_6, 7);
> +	tmp = REG_SET_FIELD(tmp, AFMT_60958_2, AFMT_60958_CS_CHANNEL_NUMBER_7, 8);
> +	WREG32(mmAFMT_60958_2 + dig->afmt->offset, tmp);
> +
> +	tmp = RREG32(mmAFMT_AUDIO_PACKET_CONTROL2 + dig->afmt->offset);
> +	tmp = REG_SET_FIELD(tmp, AFMT_AUDIO_PACKET_CONTROL2, AFMT_AUDIO_CHANNEL_ENABLE, 0xff);
> +	WREG32(mmAFMT_AUDIO_PACKET_CONTROL2 + dig->afmt->offset, tmp);
> +
> +	tmp = RREG32(mmHDMI_AUDIO_PACKET_CONTROL + dig->afmt->offset);
> +	tmp = REG_SET_FIELD(tmp, HDMI_AUDIO_PACKET_CONTROL, HDMI_AUDIO_DELAY_EN, 1);
> +	tmp = REG_SET_FIELD(tmp, HDMI_AUDIO_PACKET_CONTROL, HDMI_AUDIO_PACKETS_PER_LINE, 3);
> +	WREG32(mmHDMI_AUDIO_PACKET_CONTROL + dig->afmt->offset, tmp);
> +
> +	tmp = RREG32(mmAFMT_AUDIO_PACKET_CONTROL + dig->afmt->offset);
> +	tmp = REG_SET_FIELD(tmp, AFMT_AUDIO_PACKET_CONTROL, AFMT_RESET_FIFO_WHEN_AUDIO_DIS, 1);
> +	tmp = REG_SET_FIELD(tmp, AFMT_AUDIO_PACKET_CONTROL, AFMT_60958_CS_UPDATE, 1);
> +	WREG32(mmAFMT_AUDIO_PACKET_CONTROL + dig->afmt->offset, tmp);
> +}
> +
> +static void dce_v6_0_audio_set_mute(struct drm_encoder *encoder, bool mute)
> +{
> +	struct drm_device *dev = encoder->dev;
> +	struct amdgpu_device *adev = dev->dev_private;
> +	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
> +	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
> +	u32 tmp;
> +
> +	tmp = RREG32(mmHDMI_GC + dig->afmt->offset);
> +	tmp = REG_SET_FIELD(tmp, HDMI_GC, HDMI_GC_AVMUTE, mute ? 1 : 0);
> +	WREG32(mmHDMI_GC + dig->afmt->offset, tmp);
> +}
> +
> +static void dce_v6_0_audio_dp_enable(struct drm_encoder *encoder, bool enable)
> +{
> +	struct drm_device *dev = encoder->dev;
> +	struct amdgpu_device *adev = dev->dev_private;
> +	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
> +	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
> +	u32 tmp;
> +
> +	if (enable) {
> +		tmp = RREG32(mmAFMT_AUDIO_PACKET_CONTROL + dig->afmt->offset);
> +		tmp = REG_SET_FIELD(tmp, AFMT_AUDIO_PACKET_CONTROL, AFMT_AUDIO_SAMPLE_SEND, 1);
> +		WREG32(mmAFMT_AUDIO_PACKET_CONTROL + dig->afmt->offset, tmp);
> +
> +		tmp = RREG32(mmDP_SEC_TIMESTAMP + dig->afmt->offset);
> +		tmp = REG_SET_FIELD(tmp, DP_SEC_TIMESTAMP, DP_SEC_TIMESTAMP_MODE, 1);
> +		WREG32(mmDP_SEC_TIMESTAMP + dig->afmt->offset, tmp);
> +
> +		tmp = RREG32(mmDP_SEC_CNTL + dig->afmt->offset);
> +		tmp = REG_SET_FIELD(tmp, DP_SEC_CNTL, DP_SEC_ASP_ENABLE, 1);
> +		tmp = REG_SET_FIELD(tmp, DP_SEC_CNTL, DP_SEC_ATP_ENABLE, 1);
> +		tmp = REG_SET_FIELD(tmp, DP_SEC_CNTL, DP_SEC_AIP_ENABLE, 1);
> +		tmp = REG_SET_FIELD(tmp, DP_SEC_CNTL, DP_SEC_STREAM_ENABLE, 1);
> +		WREG32(mmDP_SEC_CNTL + dig->afmt->offset, tmp);
> +	} else {
> +		WREG32(mmDP_SEC_CNTL + dig->afmt->offset, 0);
> +	}
> +}
> +
>  static void dce_v6_0_afmt_setmode(struct drm_encoder *encoder,
>  				  struct drm_display_mode *mode)
>  {
> -	DRM_INFO("xxxx: dce_v6_0_afmt_setmode ----no impl !!!!!!!!\n");
> +	struct drm_device *dev = encoder->dev;
> +	struct amdgpu_device *adev = dev->dev_private;
> +	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
> +	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
> +	struct drm_connector *connector;
> +	struct amdgpu_connector *amdgpu_connector = NULL;
> +
> +	if (!dig || !dig->afmt)
> +		return;
> +
> +	list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
> +		if (connector->encoder == encoder) {
> +			amdgpu_connector = to_amdgpu_connector(connector);
> +			break;
> +		}
> +	}
> +
> +	if (!amdgpu_connector) {
> +		DRM_ERROR("Couldn't find encoder's connector\n");
> +		return;
> +	}
> +
> +	if (!dig->afmt->enabled)
> +		return;
> +
> +	dig->afmt->pin = dce_v6_0_audio_get_pin(adev);
> +	if (!dig->afmt->pin)
> +		return;
> +
> +	/* disable audio before setting up hw */
> +	dce_v6_0_audio_enable(adev, dig->afmt->pin, false);
> +
> +	dce_v6_0_audio_set_mute(encoder, true);
> +	dce_v6_0_audio_write_speaker_allocation(encoder);
> +	dce_v6_0_audio_write_sad_regs(encoder);
> +	dce_v6_0_audio_write_latency_fields(encoder, mode);
> +	dce_v6_0_audio_set_dto(encoder, adev->clock.default_dispclk * 10);
> +	dce_v6_0_audio_set_packet(encoder);
> +	dce_v6_0_audio_select_pin(encoder);
> +	dce_v6_0_audio_set_avi_infoframe(encoder, mode);
> +	dce_v6_0_audio_set_mute(encoder, false);
> +	dce_v6_0_audio_dp_enable(encoder, 1);
> +
> +	/* enable audio after setting up hw */
> +	dce_v6_0_audio_enable(adev, dig->afmt->pin, true);
>  }
>  
>  static void dce_v6_0_afmt_enable(struct drm_encoder *encoder, bool enable)
> @@ -1368,6 +1760,7 @@ static void dce_v6_0_afmt_enable(struct drm_encoder *encoder, bool enable)
>  	/* Silent, r600_hdmi_enable will raise WARN for us */
>  	if (enable && dig->afmt->enabled)
>  		return;
> +
>  	if (!enable && !dig->afmt->enabled)
>  		return;
>  
> @@ -2781,6 +3174,7 @@ dce_v6_0_encoder_mode_set(struct drm_encoder *encoder,
>  {
>  
>  	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
> +	int em = amdgpu_atombios_encoder_get_encoder_mode(encoder);
>  
>  	amdgpu_encoder->pixel_clock = adjusted_mode->clock;
>  
> @@ -2790,7 +3184,7 @@ dce_v6_0_encoder_mode_set(struct drm_encoder *encoder,
>  	/* set scaler clears this on some chips */
>  	dce_v6_0_set_interleave(encoder->crtc, mode);
>  
> -	if (amdgpu_atombios_encoder_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) {
> +	if (em == ATOM_ENCODER_MODE_HDMI || ENCODER_MODE_IS_DP(em)) {
>  		dce_v6_0_afmt_enable(encoder, true);
>  		dce_v6_0_afmt_setmode(encoder, adjusted_mode);
>  	}
> @@ -2852,11 +3246,12 @@ static void dce_v6_0_encoder_disable(struct drm_encoder *encoder)
>  
>  	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
>  	struct amdgpu_encoder_atom_dig *dig;
> +	int em = amdgpu_atombios_encoder_get_encoder_mode(encoder);
>  
>  	amdgpu_atombios_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
>  
>  	if (amdgpu_atombios_encoder_is_digital(encoder)) {
> -		if (amdgpu_atombios_encoder_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI)
> +		if (em == ATOM_ENCODER_MODE_HDMI || ENCODER_MODE_IS_DP(em))
>  			dce_v6_0_afmt_enable(encoder, false);
>  		dig = amdgpu_encoder->enc_priv;
>  		dig->dig_encoder = -1;
> diff --git a/drivers/gpu/drm/amd/include/asic_reg/dce/dce_6_0_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/dce/dce_6_0_sh_mask.h
> index 9a4d4c2..abe05bc 100644
> --- a/drivers/gpu/drm/amd/include/asic_reg/dce/dce_6_0_sh_mask.h
> +++ b/drivers/gpu/drm/amd/include/asic_reg/dce/dce_6_0_sh_mask.h
> @@ -906,6 +906,8 @@
>  #define AZALIA_F0_CODEC_ENDPOINT_DATA__AZALIA_ENDPOINT_REG_DATA__SHIFT 0x00000000
>  #define AZALIA_F0_CODEC_ENDPOINT_INDEX__AZALIA_ENDPOINT_REG_INDEX_MASK 0x000000ffL
>  #define AZALIA_F0_CODEC_ENDPOINT_INDEX__AZALIA_ENDPOINT_REG_INDEX__SHIFT 0x00000000
> +#define AZALIA_F0_CODEC_ENDPOINT_INDEX__AZALIA_ENDPOINT_REG_WRITE_EN_MASK 0x00000100L
> +#define AZALIA_F0_CODEC_ENDPOINT_INDEX__AZALIA_ENDPOINT_REG_WRITE_EN__SHIFT 0x00000008
>  #define AZALIA_F0_CODEC_FUNCTION_CONTROL_CONVERTER_SYNCHRONIZATION__CONVERTER_SYNCHRONIZATION_MASK 0x0000003fL
>  #define AZALIA_F0_CODEC_FUNCTION_CONTROL_CONVERTER_SYNCHRONIZATION__CONVERTER_SYNCHRONIZATION__SHIFT 0x00000000
>  #define AZALIA_F0_CODEC_FUNCTION_CONTROL_POWER_STATE__CLKSTOPOK_MASK 0x00000200L
> 


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

[-- Attachment #2: Type: text/plain, Size: 154 bytes --]

_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH v3] drm/amdgpu: add DP audio support for si dce6 (v3)
       [not found]     ` <86e62166-a3fa-92af-17d1-4bf1f90f1583-dczkZgxz+BNUPWh3PAxdjQ@public.gmane.org>
@ 2017-02-22  9:13       ` Christian König
  0 siblings, 0 replies; 4+ messages in thread
From: Christian König @ 2017-02-22  9:13 UTC (permalink / raw)
  To: Edward O'Callaghan, Xiaojie Yuan,
	amd-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW


[-- Attachment #1.1: Type: text/plain, Size: 25492 bytes --]

Acked-by: Christian König <christian.koenig-5C7GfCeVMHo@public.gmane.org>

Am 22.02.2017 um 05:40 schrieb Edward O'Callaghan:
> Reviewed-by: Edward O'Callaghan <funfunctor-dczkZgxz+BNUPWh3PAxdjQ@public.gmane.org>
>
> On 02/22/2017 02:37 PM, Xiaojie Yuan wrote:
>> v2: refine dce_v6_0_audio_endpt_wreg() and unify inconsistent method names
>> v3: fix num_pins for tahiti, pitcairn, verde and oland
>>
>> Signed-off-by: Xiaojie Yuan <Xiaojie.Yuan-5C7GfCeVMHo@public.gmane.org>
>> ---
>>   drivers/gpu/drm/amd/amdgpu/dce_v6_0.c              | 467 +++++++++++++++++++--
>>   .../drm/amd/include/asic_reg/dce/dce_6_0_sh_mask.h |   2 +
>>   2 files changed, 433 insertions(+), 36 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
>> index 94877cb..7c11ed8 100644
>> --- a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
>> +++ b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
>> @@ -118,14 +118,27 @@ static const struct {
>>   static u32 dce_v6_0_audio_endpt_rreg(struct amdgpu_device *adev,
>>   				     u32 block_offset, u32 reg)
>>   {
>> -	DRM_INFO("xxxx: dce_v6_0_audio_endpt_rreg ----no impl!!!!\n");
>> -	return 0;
>> +	unsigned long flags;
>> +	u32 r;
>> +
>> +	spin_lock_irqsave(&adev->audio_endpt_idx_lock, flags);
>> +	WREG32(mmAZALIA_F0_CODEC_ENDPOINT_INDEX + block_offset, reg);
>> +	r = RREG32(mmAZALIA_F0_CODEC_ENDPOINT_DATA + block_offset);
>> +	spin_unlock_irqrestore(&adev->audio_endpt_idx_lock, flags);
>> +
>> +	return r;
>>   }
>>   
>>   static void dce_v6_0_audio_endpt_wreg(struct amdgpu_device *adev,
>>   				      u32 block_offset, u32 reg, u32 v)
>>   {
>> -	DRM_INFO("xxxx: dce_v6_0_audio_endpt_wreg ----no impl!!!!\n");
>> +	unsigned long flags;
>> +
>> +	spin_lock_irqsave(&adev->audio_endpt_idx_lock, flags);
>> +	WREG32(mmAZALIA_F0_CODEC_ENDPOINT_INDEX + block_offset,
>> +		reg | AZALIA_F0_CODEC_ENDPOINT_INDEX__AZALIA_ENDPOINT_REG_WRITE_EN_MASK);
>> +	WREG32(mmAZALIA_F0_CODEC_ENDPOINT_DATA + block_offset, v);
>> +	spin_unlock_irqrestore(&adev->audio_endpt_idx_lock, flags);
>>   }
>>   
>>   static bool dce_v6_0_is_in_vblank(struct amdgpu_device *adev, int crtc)
>> @@ -1231,17 +1244,17 @@ static void dce_v6_0_bandwidth_update(struct amdgpu_device *adev)
>>   		dce_v6_0_program_watermarks(adev, adev->mode_info.crtcs[i+1], lb_size, num_heads);
>>   	}
>>   }
>> -/*
>> +
>>   static void dce_v6_0_audio_get_connected_pins(struct amdgpu_device *adev)
>>   {
>>   	int i;
>> -	u32 offset, tmp;
>> +	u32 tmp;
>>   
>>   	for (i = 0; i < adev->mode_info.audio.num_pins; i++) {
>> -		offset = adev->mode_info.audio.pin[i].offset;
>> -		tmp = RREG32_AUDIO_ENDPT(offset,
>> -				      AZ_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT);
>> -		if (((tmp & PORT_CONNECTIVITY_MASK) >> PORT_CONNECTIVITY_SHIFT) == 1)
>> +		tmp = RREG32_AUDIO_ENDPT(adev->mode_info.audio.pin[i].offset,
>> +				ixAZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT);
>> +		if (REG_GET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT,
>> +					PORT_CONNECTIVITY))
>>   			adev->mode_info.audio.pin[i].connected = false;
>>   		else
>>   			adev->mode_info.audio.pin[i].connected = true;
>> @@ -1263,45 +1276,206 @@ static struct amdgpu_audio_pin *dce_v6_0_audio_get_pin(struct amdgpu_device *ade
>>   	return NULL;
>>   }
>>   
>> -static void dce_v6_0_afmt_audio_select_pin(struct drm_encoder *encoder)
>> +static void dce_v6_0_audio_select_pin(struct drm_encoder *encoder)
>>   {
>>   	struct amdgpu_device *adev = encoder->dev->dev_private;
>>   	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
>>   	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
>> -	u32 offset;
>>   
>>   	if (!dig || !dig->afmt || !dig->afmt->pin)
>>   		return;
>>   
>> -	offset = dig->afmt->offset;
>> -
>> -	WREG32(AFMT_AUDIO_SRC_CONTROL + offset,
>> -	       AFMT_AUDIO_SRC_SELECT(dig->afmt->pin->id));
>> -
>> +	WREG32(mmAFMT_AUDIO_SRC_CONTROL + dig->afmt->offset,
>> +	       REG_SET_FIELD(0, AFMT_AUDIO_SRC_CONTROL, AFMT_AUDIO_SRC_SELECT,
>> +		             dig->afmt->pin->id));
>>   }
>>   
>>   static void dce_v6_0_audio_write_latency_fields(struct drm_encoder *encoder,
>>   						struct drm_display_mode *mode)
>>   {
>> -	DRM_INFO("xxxx: dce_v6_0_audio_write_latency_fields---no imp!!!!!\n");
>> +	struct amdgpu_device *adev = encoder->dev->dev_private;
>> +	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
>> +	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
>> +	struct drm_connector *connector;
>> +	struct amdgpu_connector *amdgpu_connector = NULL;
>> +	int interlace = 0;
>> +	u32 tmp;
>> +
>> +	list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
>> +		if (connector->encoder == encoder) {
>> +			amdgpu_connector = to_amdgpu_connector(connector);
>> +			break;
>> +		}
>> +	}
>> +
>> +	if (!amdgpu_connector) {
>> +		DRM_ERROR("Couldn't find encoder's connector\n");
>> +		return;
>> +	}
>> +
>> +	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
>> +		interlace = 1;
>> +
>> +	if (connector->latency_present[interlace]) {
>> +		tmp = REG_SET_FIELD(0, AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
>> +				VIDEO_LIPSYNC, connector->video_latency[interlace]);
>> +		tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
>> +				AUDIO_LIPSYNC, connector->audio_latency[interlace]);
>> +	} else {
>> +		tmp = REG_SET_FIELD(0, AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
>> +				VIDEO_LIPSYNC, 0);
>> +		tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
>> +				AUDIO_LIPSYNC, 0);
>> +	}
>> +	WREG32_AUDIO_ENDPT(dig->afmt->pin->offset,
>> +			   ixAZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC, tmp);
>>   }
>>   
>>   static void dce_v6_0_audio_write_speaker_allocation(struct drm_encoder *encoder)
>>   {
>> -	DRM_INFO("xxxx: dce_v6_0_audio_write_speaker_allocation---no imp!!!!!\n");
>> +	struct amdgpu_device *adev = encoder->dev->dev_private;
>> +	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
>> +	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
>> +	struct drm_connector *connector;
>> +	struct amdgpu_connector *amdgpu_connector = NULL;
>> +	u8 *sadb = NULL;
>> +	int sad_count;
>> +	u32 tmp;
>> +
>> +	list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
>> +		if (connector->encoder == encoder) {
>> +			amdgpu_connector = to_amdgpu_connector(connector);
>> +			break;
>> +		}
>> +	}
>> +
>> +	if (!amdgpu_connector) {
>> +		DRM_ERROR("Couldn't find encoder's connector\n");
>> +		return;
>> +	}
>> +
>> +	sad_count = drm_edid_to_speaker_allocation(amdgpu_connector_edid(connector), &sadb);
>> +	if (sad_count < 0) {
>> +		DRM_ERROR("Couldn't read Speaker Allocation Data Block: %d\n", sad_count);
>> +		sad_count = 0;
>> +	}
>> +
>> +	/* program the speaker allocation */
>> +	tmp = RREG32_AUDIO_ENDPT(dig->afmt->pin->offset,
>> +			ixAZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER);
>> +	tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
>> +			HDMI_CONNECTION, 0);
>> +	tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
>> +			DP_CONNECTION, 0);
>> +
>> +	if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort)
>> +		tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
>> +				DP_CONNECTION, 1);
>> +	else
>> +		tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
>> +				HDMI_CONNECTION, 1);
>> +
>> +	if (sad_count)
>> +		tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
>> +				SPEAKER_ALLOCATION, sadb[0]);
>> +	else
>> +		tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
>> +				SPEAKER_ALLOCATION, 5); /* stereo */
>> +
>> +	WREG32_AUDIO_ENDPT(dig->afmt->pin->offset,
>> +			ixAZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, tmp);
>> +
>> +	kfree(sadb);
>>   }
>>   
>>   static void dce_v6_0_audio_write_sad_regs(struct drm_encoder *encoder)
>>   {
>> -	DRM_INFO("xxxx: dce_v6_0_audio_write_sad_regs---no imp!!!!!\n");
>> +	struct amdgpu_device *adev = encoder->dev->dev_private;
>> +	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
>> +	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
>> +	struct drm_connector *connector;
>> +	struct amdgpu_connector *amdgpu_connector = NULL;
>> +	struct cea_sad *sads;
>> +	int i, sad_count;
>> +
>> +	static const u16 eld_reg_to_type[][2] = {
>> +		{ ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0, HDMI_AUDIO_CODING_TYPE_PCM },
>> +		{ ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR1, HDMI_AUDIO_CODING_TYPE_AC3 },
>> +		{ ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR2, HDMI_AUDIO_CODING_TYPE_MPEG1 },
>> +		{ ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR3, HDMI_AUDIO_CODING_TYPE_MP3 },
>> +		{ ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR4, HDMI_AUDIO_CODING_TYPE_MPEG2 },
>> +		{ ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR5, HDMI_AUDIO_CODING_TYPE_AAC_LC },
>> +		{ ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR6, HDMI_AUDIO_CODING_TYPE_DTS },
>> +		{ ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR7, HDMI_AUDIO_CODING_TYPE_ATRAC },
>> +		{ ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR9, HDMI_AUDIO_CODING_TYPE_EAC3 },
>> +		{ ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR10, HDMI_AUDIO_CODING_TYPE_DTS_HD },
>> +		{ ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR11, HDMI_AUDIO_CODING_TYPE_MLP },
>> +		{ ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR13, HDMI_AUDIO_CODING_TYPE_WMA_PRO },
>> +	};
>> +
>> +	list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
>> +		if (connector->encoder == encoder) {
>> +			amdgpu_connector = to_amdgpu_connector(connector);
>> +			break;
>> +		}
>> +	}
>> +
>> +	if (!amdgpu_connector) {
>> +		DRM_ERROR("Couldn't find encoder's connector\n");
>> +		return;
>> +	}
>> +
>> +	sad_count = drm_edid_to_sad(amdgpu_connector_edid(connector), &sads);
>> +	if (sad_count <= 0) {
>> +		DRM_ERROR("Couldn't read SADs: %d\n", sad_count);
>> +		return;
>> +	}
>> +
>> +	for (i = 0; i < ARRAY_SIZE(eld_reg_to_type); i++) {
>> +		u32 tmp = 0;
>> +		u8 stereo_freqs = 0;
>> +		int max_channels = -1;
>> +		int j;
>> +
>> +		for (j = 0; j < sad_count; j++) {
>> +			struct cea_sad *sad = &sads[j];
>> +
>> +			if (sad->format == eld_reg_to_type[i][1]) {
>> +				if (sad->channels > max_channels) {
>> +					tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
>> +							MAX_CHANNELS, sad->channels);
>> +					tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
>> +							DESCRIPTOR_BYTE_2, sad->byte2);
>> +					tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
>> +							SUPPORTED_FREQUENCIES, sad->freq);
>> +					max_channels = sad->channels;
>> +				}
>> +
>> +				if (sad->format == HDMI_AUDIO_CODING_TYPE_PCM)
>> +					stereo_freqs |= sad->freq;
>> +				else
>> +					break;
>> +			}
>> +		}
>> +
>> +		tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
>> +				SUPPORTED_FREQUENCIES_STEREO, stereo_freqs);
>> +		WREG32_AUDIO_ENDPT(dig->afmt->pin->offset, eld_reg_to_type[i][0], tmp);
>> +	}
>> +
>> +	kfree(sads);
>>   
>>   }
>> -*/
>> +
>>   static void dce_v6_0_audio_enable(struct amdgpu_device *adev,
>>   				  struct amdgpu_audio_pin *pin,
>>   				  bool enable)
>>   {
>> -	DRM_INFO("xxxx: dce_v6_0_audio_enable---no imp!!!!!\n");
>> +	if (!pin)
>> +		return;
>> +
>> +	WREG32_AUDIO_ENDPT(pin->offset, ixAZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
>> +			enable ? AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL__AUDIO_ENABLED_MASK : 0);
>>   }
>>   
>>   static const u32 pin_offsets[7] =
>> @@ -1317,12 +1491,54 @@ static const u32 pin_offsets[7] =
>>   
>>   static int dce_v6_0_audio_init(struct amdgpu_device *adev)
>>   {
>> +	int i;
>> +
>> +	if (!amdgpu_audio)
>> +		return 0;
>> +
>> +	adev->mode_info.audio.enabled = true;
>> +
>> +	switch (adev->asic_type) {
>> +	case CHIP_TAHITI:
>> +	case CHIP_PITCAIRN:
>> +	case CHIP_VERDE:
>> +	default:
>> +		adev->mode_info.audio.num_pins = 6;
>> +		break;
>> +	case CHIP_OLAND:
>> +		adev->mode_info.audio.num_pins = 2;
>> +		break;
>> +	}
>> +
>> +	for (i = 0; i < adev->mode_info.audio.num_pins; i++) {
>> +		adev->mode_info.audio.pin[i].channels = -1;
>> +		adev->mode_info.audio.pin[i].rate = -1;
>> +		adev->mode_info.audio.pin[i].bits_per_sample = -1;
>> +		adev->mode_info.audio.pin[i].status_bits = 0;
>> +		adev->mode_info.audio.pin[i].category_code = 0;
>> +		adev->mode_info.audio.pin[i].connected = false;
>> +		adev->mode_info.audio.pin[i].offset = pin_offsets[i];
>> +		adev->mode_info.audio.pin[i].id = i;
>> +		dce_v6_0_audio_enable(adev, &adev->mode_info.audio.pin[i], false);
>> +	}
>> +
>>   	return 0;
>>   }
>>   
>>   static void dce_v6_0_audio_fini(struct amdgpu_device *adev)
>>   {
>> +	int i;
>>   
>> +	if (!amdgpu_audio)
>> +		return;
>> +
>> +	if (!adev->mode_info.audio.enabled)
>> +		return;
>> +
>> +	for (i = 0; i < adev->mode_info.audio.num_pins; i++)
>> +		dce_v6_0_audio_enable(adev, &adev->mode_info.audio.pin[i], false);
>> +
>> +	adev->mode_info.audio.enabled = false;
>>   }
>>   
>>   /*
>> @@ -1331,28 +1547,204 @@ static void dce_v6_0_afmt_update_ACR(struct drm_encoder *encoder, uint32_t clock
>>   	DRM_INFO("xxxx: dce_v6_0_afmt_update_ACR---no imp!!!!!\n");
>>   }
>>   */
>> -/*
>> - * build a HDMI Video Info Frame
>> - */
>> -/*
>> -static void dce_v6_0_afmt_update_avi_infoframe(struct drm_encoder *encoder,
>> -					       void *buffer, size_t size)
>> +
>> +static void dce_v6_0_audio_set_avi_infoframe(struct drm_encoder *encoder,
>> +					       struct drm_display_mode *mode)
>>   {
>> -	DRM_INFO("xxxx: dce_v6_0_afmt_update_avi_infoframe---no imp!!!!!\n");
>> +	struct drm_device *dev = encoder->dev;
>> +	struct amdgpu_device *adev = dev->dev_private;
>> +	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
>> +	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
>> +	struct hdmi_avi_infoframe frame;
>> +	u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE];
>> +	uint8_t *payload = buffer + 3;
>> +	uint8_t *header = buffer;
>> +	ssize_t err;
>> +	u32 tmp;
>> +
>> +	err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
>> +	if (err < 0) {
>> +		DRM_ERROR("failed to setup AVI infoframe: %zd\n", err);
>> +		return;
>> +	}
>> +
>> +	err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer));
>> +	if (err < 0) {
>> +		DRM_ERROR("failed to pack AVI infoframe: %zd\n", err);
>> +		return;
>> +	}
>> +
>> +	WREG32(mmAFMT_AVI_INFO0 + dig->afmt->offset,
>> +	       payload[0x0] | (payload[0x1] << 8) | (payload[0x2] << 16) | (payload[0x3] << 24));
>> +	WREG32(mmAFMT_AVI_INFO1 + dig->afmt->offset,
>> +	       payload[0x4] | (payload[0x5] << 8) | (payload[0x6] << 16) | (payload[0x7] << 24));
>> +	WREG32(mmAFMT_AVI_INFO2 + dig->afmt->offset,
>> +	       payload[0x8] | (payload[0x9] << 8) | (payload[0xA] << 16) | (payload[0xB] << 24));
>> +	WREG32(mmAFMT_AVI_INFO3 + dig->afmt->offset,
>> +	       payload[0xC] | (payload[0xD] << 8) | (header[1] << 24));
>> +
>> +	tmp = RREG32(mmHDMI_INFOFRAME_CONTROL1 + dig->afmt->offset);
>> +	/* anything other than 0 */
>> +	tmp = REG_SET_FIELD(tmp, HDMI_INFOFRAME_CONTROL1,
>> +			HDMI_AUDIO_INFO_LINE, 2);
>> +	WREG32(mmHDMI_INFOFRAME_CONTROL1 + dig->afmt->offset, tmp);
>>   }
>>   
>>   static void dce_v6_0_audio_set_dto(struct drm_encoder *encoder, u32 clock)
>>   {
>> -	DRM_INFO("xxxx: dce_v6_0_audio_set_dto---no imp!!!!!\n");
>> +	struct drm_device *dev = encoder->dev;
>> +	struct amdgpu_device *adev = dev->dev_private;
>> +	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(encoder->crtc);
>> +	u32 tmp;
>> +
>> +	/*
>> +	 * Two dtos: generally use dto0 for hdmi, dto1 for dp.
>> +	 * Express [24MHz / target pixel clock] as an exact rational
>> +	 * number (coefficient of two integer numbers.  DCCG_AUDIO_DTOx_PHASE
>> +	 * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
>> +	 */
>> +	tmp = RREG32(mmDCCG_AUDIO_DTO_SOURCE);
>> +	tmp = REG_SET_FIELD(tmp, DCCG_AUDIO_DTO_SOURCE,
>> +			DCCG_AUDIO_DTO0_SOURCE_SEL, amdgpu_crtc->crtc_id);
>> +	tmp = REG_SET_FIELD(tmp, DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO_SEL, 1);
>> +	WREG32(mmDCCG_AUDIO_DTO_SOURCE, tmp);
>> +	WREG32(mmDCCG_AUDIO_DTO1_PHASE, 24000);
>> +	WREG32(mmDCCG_AUDIO_DTO1_MODULE, clock);
>>   }
>> -*/
>> -/*
>> - * update the info frames with the data from the current display mode
>> - */
>> +
>> +static void dce_v6_0_audio_set_packet(struct drm_encoder *encoder)
>> +{
>> +	struct drm_device *dev = encoder->dev;
>> +	struct amdgpu_device *adev = dev->dev_private;
>> +	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
>> +	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
>> +	u32 tmp;
>> +
>> +	tmp = RREG32(mmAFMT_INFOFRAME_CONTROL0 + dig->afmt->offset);
>> +	tmp = REG_SET_FIELD(tmp, AFMT_INFOFRAME_CONTROL0, AFMT_AUDIO_INFO_UPDATE, 1);
>> +	WREG32(mmAFMT_INFOFRAME_CONTROL0 + dig->afmt->offset, tmp);
>> +
>> +	tmp = RREG32(mmAFMT_60958_0 + dig->afmt->offset);
>> +	tmp = REG_SET_FIELD(tmp, AFMT_60958_0, AFMT_60958_CS_CHANNEL_NUMBER_L, 1);
>> +	WREG32(mmAFMT_60958_0 + dig->afmt->offset, tmp);
>> +
>> +	tmp = RREG32(mmAFMT_60958_1 + dig->afmt->offset);
>> +	tmp = REG_SET_FIELD(tmp, AFMT_60958_1, AFMT_60958_CS_CHANNEL_NUMBER_R, 2);
>> +	WREG32(mmAFMT_60958_1 + dig->afmt->offset, tmp);
>> +
>> +	tmp = RREG32(mmAFMT_60958_2 + dig->afmt->offset);
>> +	tmp = REG_SET_FIELD(tmp, AFMT_60958_2, AFMT_60958_CS_CHANNEL_NUMBER_2, 3);
>> +	tmp = REG_SET_FIELD(tmp, AFMT_60958_2, AFMT_60958_CS_CHANNEL_NUMBER_3, 4);
>> +	tmp = REG_SET_FIELD(tmp, AFMT_60958_2, AFMT_60958_CS_CHANNEL_NUMBER_4, 5);
>> +	tmp = REG_SET_FIELD(tmp, AFMT_60958_2, AFMT_60958_CS_CHANNEL_NUMBER_5, 6);
>> +	tmp = REG_SET_FIELD(tmp, AFMT_60958_2, AFMT_60958_CS_CHANNEL_NUMBER_6, 7);
>> +	tmp = REG_SET_FIELD(tmp, AFMT_60958_2, AFMT_60958_CS_CHANNEL_NUMBER_7, 8);
>> +	WREG32(mmAFMT_60958_2 + dig->afmt->offset, tmp);
>> +
>> +	tmp = RREG32(mmAFMT_AUDIO_PACKET_CONTROL2 + dig->afmt->offset);
>> +	tmp = REG_SET_FIELD(tmp, AFMT_AUDIO_PACKET_CONTROL2, AFMT_AUDIO_CHANNEL_ENABLE, 0xff);
>> +	WREG32(mmAFMT_AUDIO_PACKET_CONTROL2 + dig->afmt->offset, tmp);
>> +
>> +	tmp = RREG32(mmHDMI_AUDIO_PACKET_CONTROL + dig->afmt->offset);
>> +	tmp = REG_SET_FIELD(tmp, HDMI_AUDIO_PACKET_CONTROL, HDMI_AUDIO_DELAY_EN, 1);
>> +	tmp = REG_SET_FIELD(tmp, HDMI_AUDIO_PACKET_CONTROL, HDMI_AUDIO_PACKETS_PER_LINE, 3);
>> +	WREG32(mmHDMI_AUDIO_PACKET_CONTROL + dig->afmt->offset, tmp);
>> +
>> +	tmp = RREG32(mmAFMT_AUDIO_PACKET_CONTROL + dig->afmt->offset);
>> +	tmp = REG_SET_FIELD(tmp, AFMT_AUDIO_PACKET_CONTROL, AFMT_RESET_FIFO_WHEN_AUDIO_DIS, 1);
>> +	tmp = REG_SET_FIELD(tmp, AFMT_AUDIO_PACKET_CONTROL, AFMT_60958_CS_UPDATE, 1);
>> +	WREG32(mmAFMT_AUDIO_PACKET_CONTROL + dig->afmt->offset, tmp);
>> +}
>> +
>> +static void dce_v6_0_audio_set_mute(struct drm_encoder *encoder, bool mute)
>> +{
>> +	struct drm_device *dev = encoder->dev;
>> +	struct amdgpu_device *adev = dev->dev_private;
>> +	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
>> +	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
>> +	u32 tmp;
>> +
>> +	tmp = RREG32(mmHDMI_GC + dig->afmt->offset);
>> +	tmp = REG_SET_FIELD(tmp, HDMI_GC, HDMI_GC_AVMUTE, mute ? 1 : 0);
>> +	WREG32(mmHDMI_GC + dig->afmt->offset, tmp);
>> +}
>> +
>> +static void dce_v6_0_audio_dp_enable(struct drm_encoder *encoder, bool enable)
>> +{
>> +	struct drm_device *dev = encoder->dev;
>> +	struct amdgpu_device *adev = dev->dev_private;
>> +	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
>> +	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
>> +	u32 tmp;
>> +
>> +	if (enable) {
>> +		tmp = RREG32(mmAFMT_AUDIO_PACKET_CONTROL + dig->afmt->offset);
>> +		tmp = REG_SET_FIELD(tmp, AFMT_AUDIO_PACKET_CONTROL, AFMT_AUDIO_SAMPLE_SEND, 1);
>> +		WREG32(mmAFMT_AUDIO_PACKET_CONTROL + dig->afmt->offset, tmp);
>> +
>> +		tmp = RREG32(mmDP_SEC_TIMESTAMP + dig->afmt->offset);
>> +		tmp = REG_SET_FIELD(tmp, DP_SEC_TIMESTAMP, DP_SEC_TIMESTAMP_MODE, 1);
>> +		WREG32(mmDP_SEC_TIMESTAMP + dig->afmt->offset, tmp);
>> +
>> +		tmp = RREG32(mmDP_SEC_CNTL + dig->afmt->offset);
>> +		tmp = REG_SET_FIELD(tmp, DP_SEC_CNTL, DP_SEC_ASP_ENABLE, 1);
>> +		tmp = REG_SET_FIELD(tmp, DP_SEC_CNTL, DP_SEC_ATP_ENABLE, 1);
>> +		tmp = REG_SET_FIELD(tmp, DP_SEC_CNTL, DP_SEC_AIP_ENABLE, 1);
>> +		tmp = REG_SET_FIELD(tmp, DP_SEC_CNTL, DP_SEC_STREAM_ENABLE, 1);
>> +		WREG32(mmDP_SEC_CNTL + dig->afmt->offset, tmp);
>> +	} else {
>> +		WREG32(mmDP_SEC_CNTL + dig->afmt->offset, 0);
>> +	}
>> +}
>> +
>>   static void dce_v6_0_afmt_setmode(struct drm_encoder *encoder,
>>   				  struct drm_display_mode *mode)
>>   {
>> -	DRM_INFO("xxxx: dce_v6_0_afmt_setmode ----no impl !!!!!!!!\n");
>> +	struct drm_device *dev = encoder->dev;
>> +	struct amdgpu_device *adev = dev->dev_private;
>> +	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
>> +	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
>> +	struct drm_connector *connector;
>> +	struct amdgpu_connector *amdgpu_connector = NULL;
>> +
>> +	if (!dig || !dig->afmt)
>> +		return;
>> +
>> +	list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
>> +		if (connector->encoder == encoder) {
>> +			amdgpu_connector = to_amdgpu_connector(connector);
>> +			break;
>> +		}
>> +	}
>> +
>> +	if (!amdgpu_connector) {
>> +		DRM_ERROR("Couldn't find encoder's connector\n");
>> +		return;
>> +	}
>> +
>> +	if (!dig->afmt->enabled)
>> +		return;
>> +
>> +	dig->afmt->pin = dce_v6_0_audio_get_pin(adev);
>> +	if (!dig->afmt->pin)
>> +		return;
>> +
>> +	/* disable audio before setting up hw */
>> +	dce_v6_0_audio_enable(adev, dig->afmt->pin, false);
>> +
>> +	dce_v6_0_audio_set_mute(encoder, true);
>> +	dce_v6_0_audio_write_speaker_allocation(encoder);
>> +	dce_v6_0_audio_write_sad_regs(encoder);
>> +	dce_v6_0_audio_write_latency_fields(encoder, mode);
>> +	dce_v6_0_audio_set_dto(encoder, adev->clock.default_dispclk * 10);
>> +	dce_v6_0_audio_set_packet(encoder);
>> +	dce_v6_0_audio_select_pin(encoder);
>> +	dce_v6_0_audio_set_avi_infoframe(encoder, mode);
>> +	dce_v6_0_audio_set_mute(encoder, false);
>> +	dce_v6_0_audio_dp_enable(encoder, 1);
>> +
>> +	/* enable audio after setting up hw */
>> +	dce_v6_0_audio_enable(adev, dig->afmt->pin, true);
>>   }
>>   
>>   static void dce_v6_0_afmt_enable(struct drm_encoder *encoder, bool enable)
>> @@ -1368,6 +1760,7 @@ static void dce_v6_0_afmt_enable(struct drm_encoder *encoder, bool enable)
>>   	/* Silent, r600_hdmi_enable will raise WARN for us */
>>   	if (enable && dig->afmt->enabled)
>>   		return;
>> +
>>   	if (!enable && !dig->afmt->enabled)
>>   		return;
>>   
>> @@ -2781,6 +3174,7 @@ dce_v6_0_encoder_mode_set(struct drm_encoder *encoder,
>>   {
>>   
>>   	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
>> +	int em = amdgpu_atombios_encoder_get_encoder_mode(encoder);
>>   
>>   	amdgpu_encoder->pixel_clock = adjusted_mode->clock;
>>   
>> @@ -2790,7 +3184,7 @@ dce_v6_0_encoder_mode_set(struct drm_encoder *encoder,
>>   	/* set scaler clears this on some chips */
>>   	dce_v6_0_set_interleave(encoder->crtc, mode);
>>   
>> -	if (amdgpu_atombios_encoder_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) {
>> +	if (em == ATOM_ENCODER_MODE_HDMI || ENCODER_MODE_IS_DP(em)) {
>>   		dce_v6_0_afmt_enable(encoder, true);
>>   		dce_v6_0_afmt_setmode(encoder, adjusted_mode);
>>   	}
>> @@ -2852,11 +3246,12 @@ static void dce_v6_0_encoder_disable(struct drm_encoder *encoder)
>>   
>>   	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
>>   	struct amdgpu_encoder_atom_dig *dig;
>> +	int em = amdgpu_atombios_encoder_get_encoder_mode(encoder);
>>   
>>   	amdgpu_atombios_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
>>   
>>   	if (amdgpu_atombios_encoder_is_digital(encoder)) {
>> -		if (amdgpu_atombios_encoder_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI)
>> +		if (em == ATOM_ENCODER_MODE_HDMI || ENCODER_MODE_IS_DP(em))
>>   			dce_v6_0_afmt_enable(encoder, false);
>>   		dig = amdgpu_encoder->enc_priv;
>>   		dig->dig_encoder = -1;
>> diff --git a/drivers/gpu/drm/amd/include/asic_reg/dce/dce_6_0_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/dce/dce_6_0_sh_mask.h
>> index 9a4d4c2..abe05bc 100644
>> --- a/drivers/gpu/drm/amd/include/asic_reg/dce/dce_6_0_sh_mask.h
>> +++ b/drivers/gpu/drm/amd/include/asic_reg/dce/dce_6_0_sh_mask.h
>> @@ -906,6 +906,8 @@
>>   #define AZALIA_F0_CODEC_ENDPOINT_DATA__AZALIA_ENDPOINT_REG_DATA__SHIFT 0x00000000
>>   #define AZALIA_F0_CODEC_ENDPOINT_INDEX__AZALIA_ENDPOINT_REG_INDEX_MASK 0x000000ffL
>>   #define AZALIA_F0_CODEC_ENDPOINT_INDEX__AZALIA_ENDPOINT_REG_INDEX__SHIFT 0x00000000
>> +#define AZALIA_F0_CODEC_ENDPOINT_INDEX__AZALIA_ENDPOINT_REG_WRITE_EN_MASK 0x00000100L
>> +#define AZALIA_F0_CODEC_ENDPOINT_INDEX__AZALIA_ENDPOINT_REG_WRITE_EN__SHIFT 0x00000008
>>   #define AZALIA_F0_CODEC_FUNCTION_CONTROL_CONVERTER_SYNCHRONIZATION__CONVERTER_SYNCHRONIZATION_MASK 0x0000003fL
>>   #define AZALIA_F0_CODEC_FUNCTION_CONTROL_CONVERTER_SYNCHRONIZATION__CONVERTER_SYNCHRONIZATION__SHIFT 0x00000000
>>   #define AZALIA_F0_CODEC_FUNCTION_CONTROL_POWER_STATE__CLKSTOPOK_MASK 0x00000200L
>>
>
>
> _______________________________________________
> amd-gfx mailing list
> amd-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW@public.gmane.org
> https://lists.freedesktop.org/mailman/listinfo/amd-gfx



[-- Attachment #1.2: Type: text/html, Size: 25429 bytes --]

[-- Attachment #2: Type: text/plain, Size: 154 bytes --]

_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

^ permalink raw reply	[flat|nested] 4+ messages in thread

* RE: [PATCH v3] drm/amdgpu: add DP audio support for si dce6 (v3)
       [not found] ` <1487734626-27738-1-git-send-email-Xiaojie.Yuan-5C7GfCeVMHo@public.gmane.org>
  2017-02-22  4:40   ` Edward O'Callaghan
@ 2017-02-22 17:08   ` Deucher, Alexander
  1 sibling, 0 replies; 4+ messages in thread
From: Deucher, Alexander @ 2017-02-22 17:08 UTC (permalink / raw)
  To: amd-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW; +Cc: Yuan, Xiaojie

> -----Original Message-----
> From: amd-gfx [mailto:amd-gfx-bounces@lists.freedesktop.org] On Behalf
> Of Xiaojie Yuan
> Sent: Tuesday, February 21, 2017 10:37 PM
> To: amd-gfx@lists.freedesktop.org
> Cc: Yuan, Xiaojie
> Subject: [PATCH v3] drm/amdgpu: add DP audio support for si dce6 (v3)
> 
> v2: refine dce_v6_0_audio_endpt_wreg() and unify inconsistent method
> names
> v3: fix num_pins for tahiti, pitcairn, verde and oland
> 
> Signed-off-by: Xiaojie Yuan <Xiaojie.Yuan@amd.com>

Reviewed-by: Alex Deucher <alexander.deucher@amd.com>


> ---
>  drivers/gpu/drm/amd/amdgpu/dce_v6_0.c              | 467
> +++++++++++++++++++--
>  .../drm/amd/include/asic_reg/dce/dce_6_0_sh_mask.h |   2 +
>  2 files changed, 433 insertions(+), 36 deletions(-)
> 
> diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
> b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
> index 94877cb..7c11ed8 100644
> --- a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
> +++ b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
> @@ -118,14 +118,27 @@ static const struct {
>  static u32 dce_v6_0_audio_endpt_rreg(struct amdgpu_device *adev,
>  				     u32 block_offset, u32 reg)
>  {
> -	DRM_INFO("xxxx: dce_v6_0_audio_endpt_rreg ----no impl!!!!\n");
> -	return 0;
> +	unsigned long flags;
> +	u32 r;
> +
> +	spin_lock_irqsave(&adev->audio_endpt_idx_lock, flags);
> +	WREG32(mmAZALIA_F0_CODEC_ENDPOINT_INDEX + block_offset,
> reg);
> +	r = RREG32(mmAZALIA_F0_CODEC_ENDPOINT_DATA +
> block_offset);
> +	spin_unlock_irqrestore(&adev->audio_endpt_idx_lock, flags);
> +
> +	return r;
>  }
> 
>  static void dce_v6_0_audio_endpt_wreg(struct amdgpu_device *adev,
>  				      u32 block_offset, u32 reg, u32 v)
>  {
> -	DRM_INFO("xxxx: dce_v6_0_audio_endpt_wreg ----no impl!!!!\n");
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&adev->audio_endpt_idx_lock, flags);
> +	WREG32(mmAZALIA_F0_CODEC_ENDPOINT_INDEX + block_offset,
> +		reg |
> AZALIA_F0_CODEC_ENDPOINT_INDEX__AZALIA_ENDPOINT_REG_WRITE_E
> N_MASK);
> +	WREG32(mmAZALIA_F0_CODEC_ENDPOINT_DATA + block_offset,
> v);
> +	spin_unlock_irqrestore(&adev->audio_endpt_idx_lock, flags);
>  }
> 
>  static bool dce_v6_0_is_in_vblank(struct amdgpu_device *adev, int crtc)
> @@ -1231,17 +1244,17 @@ static void dce_v6_0_bandwidth_update(struct
> amdgpu_device *adev)
>  		dce_v6_0_program_watermarks(adev, adev-
> >mode_info.crtcs[i+1], lb_size, num_heads);
>  	}
>  }
> -/*
> +
>  static void dce_v6_0_audio_get_connected_pins(struct amdgpu_device
> *adev)
>  {
>  	int i;
> -	u32 offset, tmp;
> +	u32 tmp;
> 
>  	for (i = 0; i < adev->mode_info.audio.num_pins; i++) {
> -		offset = adev->mode_info.audio.pin[i].offset;
> -		tmp = RREG32_AUDIO_ENDPT(offset,
> -
> AZ_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT);
> -		if (((tmp & PORT_CONNECTIVITY_MASK) >>
> PORT_CONNECTIVITY_SHIFT) == 1)
> +		tmp = RREG32_AUDIO_ENDPT(adev-
> >mode_info.audio.pin[i].offset,
> +
> 	ixAZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_
> DEFAULT);
> +		if (REG_GET_FIELD(tmp,
> AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT,
> +					PORT_CONNECTIVITY))
>  			adev->mode_info.audio.pin[i].connected = false;
>  		else
>  			adev->mode_info.audio.pin[i].connected = true;
> @@ -1263,45 +1276,206 @@ static struct amdgpu_audio_pin
> *dce_v6_0_audio_get_pin(struct amdgpu_device *ade
>  	return NULL;
>  }
> 
> -static void dce_v6_0_afmt_audio_select_pin(struct drm_encoder
> *encoder)
> +static void dce_v6_0_audio_select_pin(struct drm_encoder *encoder)
>  {
>  	struct amdgpu_device *adev = encoder->dev->dev_private;
>  	struct amdgpu_encoder *amdgpu_encoder =
> to_amdgpu_encoder(encoder);
>  	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder-
> >enc_priv;
> -	u32 offset;
> 
>  	if (!dig || !dig->afmt || !dig->afmt->pin)
>  		return;
> 
> -	offset = dig->afmt->offset;
> -
> -	WREG32(AFMT_AUDIO_SRC_CONTROL + offset,
> -	       AFMT_AUDIO_SRC_SELECT(dig->afmt->pin->id));
> -
> +	WREG32(mmAFMT_AUDIO_SRC_CONTROL + dig->afmt->offset,
> +	       REG_SET_FIELD(0, AFMT_AUDIO_SRC_CONTROL,
> AFMT_AUDIO_SRC_SELECT,
> +		             dig->afmt->pin->id));
>  }
> 
>  static void dce_v6_0_audio_write_latency_fields(struct drm_encoder
> *encoder,
>  						struct drm_display_mode
> *mode)
>  {
> -	DRM_INFO("xxxx: dce_v6_0_audio_write_latency_fields---no
> imp!!!!!\n");
> +	struct amdgpu_device *adev = encoder->dev->dev_private;
> +	struct amdgpu_encoder *amdgpu_encoder =
> to_amdgpu_encoder(encoder);
> +	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder-
> >enc_priv;
> +	struct drm_connector *connector;
> +	struct amdgpu_connector *amdgpu_connector = NULL;
> +	int interlace = 0;
> +	u32 tmp;
> +
> +	list_for_each_entry(connector, &encoder->dev-
> >mode_config.connector_list, head) {
> +		if (connector->encoder == encoder) {
> +			amdgpu_connector =
> to_amdgpu_connector(connector);
> +			break;
> +		}
> +	}
> +
> +	if (!amdgpu_connector) {
> +		DRM_ERROR("Couldn't find encoder's connector\n");
> +		return;
> +	}
> +
> +	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
> +		interlace = 1;
> +
> +	if (connector->latency_present[interlace]) {
> +		tmp = REG_SET_FIELD(0,
> AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
> +				VIDEO_LIPSYNC, connector-
> >video_latency[interlace]);
> +		tmp = REG_SET_FIELD(tmp,
> AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
> +				AUDIO_LIPSYNC, connector-
> >audio_latency[interlace]);
> +	} else {
> +		tmp = REG_SET_FIELD(0,
> AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
> +				VIDEO_LIPSYNC, 0);
> +		tmp = REG_SET_FIELD(tmp,
> AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
> +				AUDIO_LIPSYNC, 0);
> +	}
> +	WREG32_AUDIO_ENDPT(dig->afmt->pin->offset,
> +
> ixAZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC, tmp);
>  }
> 
>  static void dce_v6_0_audio_write_speaker_allocation(struct drm_encoder
> *encoder)
>  {
> -	DRM_INFO("xxxx: dce_v6_0_audio_write_speaker_allocation---no
> imp!!!!!\n");
> +	struct amdgpu_device *adev = encoder->dev->dev_private;
> +	struct amdgpu_encoder *amdgpu_encoder =
> to_amdgpu_encoder(encoder);
> +	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder-
> >enc_priv;
> +	struct drm_connector *connector;
> +	struct amdgpu_connector *amdgpu_connector = NULL;
> +	u8 *sadb = NULL;
> +	int sad_count;
> +	u32 tmp;
> +
> +	list_for_each_entry(connector, &encoder->dev-
> >mode_config.connector_list, head) {
> +		if (connector->encoder == encoder) {
> +			amdgpu_connector =
> to_amdgpu_connector(connector);
> +			break;
> +		}
> +	}
> +
> +	if (!amdgpu_connector) {
> +		DRM_ERROR("Couldn't find encoder's connector\n");
> +		return;
> +	}
> +
> +	sad_count =
> drm_edid_to_speaker_allocation(amdgpu_connector_edid(connector),
> &sadb);
> +	if (sad_count < 0) {
> +		DRM_ERROR("Couldn't read Speaker Allocation Data Block:
> %d\n", sad_count);
> +		sad_count = 0;
> +	}
> +
> +	/* program the speaker allocation */
> +	tmp = RREG32_AUDIO_ENDPT(dig->afmt->pin->offset,
> +
> 	ixAZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER);
> +	tmp = REG_SET_FIELD(tmp,
> AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
> +			HDMI_CONNECTION, 0);
> +	tmp = REG_SET_FIELD(tmp,
> AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
> +			DP_CONNECTION, 0);
> +
> +	if (connector->connector_type ==
> DRM_MODE_CONNECTOR_DisplayPort)
> +		tmp = REG_SET_FIELD(tmp,
> AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
> +				DP_CONNECTION, 1);
> +	else
> +		tmp = REG_SET_FIELD(tmp,
> AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
> +				HDMI_CONNECTION, 1);
> +
> +	if (sad_count)
> +		tmp = REG_SET_FIELD(tmp,
> AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
> +				SPEAKER_ALLOCATION, sadb[0]);
> +	else
> +		tmp = REG_SET_FIELD(tmp,
> AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
> +				SPEAKER_ALLOCATION, 5); /* stereo */
> +
> +	WREG32_AUDIO_ENDPT(dig->afmt->pin->offset,
> +
> 	ixAZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, tmp);
> +
> +	kfree(sadb);
>  }
> 
>  static void dce_v6_0_audio_write_sad_regs(struct drm_encoder *encoder)
>  {
> -	DRM_INFO("xxxx: dce_v6_0_audio_write_sad_regs---no
> imp!!!!!\n");
> +	struct amdgpu_device *adev = encoder->dev->dev_private;
> +	struct amdgpu_encoder *amdgpu_encoder =
> to_amdgpu_encoder(encoder);
> +	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder-
> >enc_priv;
> +	struct drm_connector *connector;
> +	struct amdgpu_connector *amdgpu_connector = NULL;
> +	struct cea_sad *sads;
> +	int i, sad_count;
> +
> +	static const u16 eld_reg_to_type[][2] = {
> +		{
> ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
> HDMI_AUDIO_CODING_TYPE_PCM },
> +		{
> ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR1,
> HDMI_AUDIO_CODING_TYPE_AC3 },
> +		{
> ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR2,
> HDMI_AUDIO_CODING_TYPE_MPEG1 },
> +		{
> ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR3,
> HDMI_AUDIO_CODING_TYPE_MP3 },
> +		{
> ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR4,
> HDMI_AUDIO_CODING_TYPE_MPEG2 },
> +		{
> ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR5,
> HDMI_AUDIO_CODING_TYPE_AAC_LC },
> +		{
> ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR6,
> HDMI_AUDIO_CODING_TYPE_DTS },
> +		{
> ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR7,
> HDMI_AUDIO_CODING_TYPE_ATRAC },
> +		{
> ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR9,
> HDMI_AUDIO_CODING_TYPE_EAC3 },
> +		{
> ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR10,
> HDMI_AUDIO_CODING_TYPE_DTS_HD },
> +		{
> ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR11,
> HDMI_AUDIO_CODING_TYPE_MLP },
> +		{
> ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR13,
> HDMI_AUDIO_CODING_TYPE_WMA_PRO },
> +	};
> +
> +	list_for_each_entry(connector, &encoder->dev-
> >mode_config.connector_list, head) {
> +		if (connector->encoder == encoder) {
> +			amdgpu_connector =
> to_amdgpu_connector(connector);
> +			break;
> +		}
> +	}
> +
> +	if (!amdgpu_connector) {
> +		DRM_ERROR("Couldn't find encoder's connector\n");
> +		return;
> +	}
> +
> +	sad_count =
> drm_edid_to_sad(amdgpu_connector_edid(connector), &sads);
> +	if (sad_count <= 0) {
> +		DRM_ERROR("Couldn't read SADs: %d\n", sad_count);
> +		return;
> +	}
> +
> +	for (i = 0; i < ARRAY_SIZE(eld_reg_to_type); i++) {
> +		u32 tmp = 0;
> +		u8 stereo_freqs = 0;
> +		int max_channels = -1;
> +		int j;
> +
> +		for (j = 0; j < sad_count; j++) {
> +			struct cea_sad *sad = &sads[j];
> +
> +			if (sad->format == eld_reg_to_type[i][1]) {
> +				if (sad->channels > max_channels) {
> +					tmp = REG_SET_FIELD(tmp,
> AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
> +							MAX_CHANNELS,
> sad->channels);
> +					tmp = REG_SET_FIELD(tmp,
> AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
> +							DESCRIPTOR_BYTE_2,
> sad->byte2);
> +					tmp = REG_SET_FIELD(tmp,
> AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
> +
> 	SUPPORTED_FREQUENCIES, sad->freq);
> +					max_channels = sad->channels;
> +				}
> +
> +				if (sad->format ==
> HDMI_AUDIO_CODING_TYPE_PCM)
> +					stereo_freqs |= sad->freq;
> +				else
> +					break;
> +			}
> +		}
> +
> +		tmp = REG_SET_FIELD(tmp,
> AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
> +				SUPPORTED_FREQUENCIES_STEREO,
> stereo_freqs);
> +		WREG32_AUDIO_ENDPT(dig->afmt->pin->offset,
> eld_reg_to_type[i][0], tmp);
> +	}
> +
> +	kfree(sads);
> 
>  }
> -*/
> +
>  static void dce_v6_0_audio_enable(struct amdgpu_device *adev,
>  				  struct amdgpu_audio_pin *pin,
>  				  bool enable)
>  {
> -	DRM_INFO("xxxx: dce_v6_0_audio_enable---no imp!!!!!\n");
> +	if (!pin)
> +		return;
> +
> +	WREG32_AUDIO_ENDPT(pin->offset,
> ixAZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
> +			enable ?
> AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL__AUDIO_ENABLE
> D_MASK : 0);
>  }
> 
>  static const u32 pin_offsets[7] =
> @@ -1317,12 +1491,54 @@ static const u32 pin_offsets[7] =
> 
>  static int dce_v6_0_audio_init(struct amdgpu_device *adev)
>  {
> +	int i;
> +
> +	if (!amdgpu_audio)
> +		return 0;
> +
> +	adev->mode_info.audio.enabled = true;
> +
> +	switch (adev->asic_type) {
> +	case CHIP_TAHITI:
> +	case CHIP_PITCAIRN:
> +	case CHIP_VERDE:
> +	default:
> +		adev->mode_info.audio.num_pins = 6;
> +		break;
> +	case CHIP_OLAND:
> +		adev->mode_info.audio.num_pins = 2;
> +		break;
> +	}
> +
> +	for (i = 0; i < adev->mode_info.audio.num_pins; i++) {
> +		adev->mode_info.audio.pin[i].channels = -1;
> +		adev->mode_info.audio.pin[i].rate = -1;
> +		adev->mode_info.audio.pin[i].bits_per_sample = -1;
> +		adev->mode_info.audio.pin[i].status_bits = 0;
> +		adev->mode_info.audio.pin[i].category_code = 0;
> +		adev->mode_info.audio.pin[i].connected = false;
> +		adev->mode_info.audio.pin[i].offset = pin_offsets[i];
> +		adev->mode_info.audio.pin[i].id = i;
> +		dce_v6_0_audio_enable(adev, &adev-
> >mode_info.audio.pin[i], false);
> +	}
> +
>  	return 0;
>  }
> 
>  static void dce_v6_0_audio_fini(struct amdgpu_device *adev)
>  {
> +	int i;
> 
> +	if (!amdgpu_audio)
> +		return;
> +
> +	if (!adev->mode_info.audio.enabled)
> +		return;
> +
> +	for (i = 0; i < adev->mode_info.audio.num_pins; i++)
> +		dce_v6_0_audio_enable(adev, &adev-
> >mode_info.audio.pin[i], false);
> +
> +	adev->mode_info.audio.enabled = false;
>  }
> 
>  /*
> @@ -1331,28 +1547,204 @@ static void dce_v6_0_afmt_update_ACR(struct
> drm_encoder *encoder, uint32_t clock
>  	DRM_INFO("xxxx: dce_v6_0_afmt_update_ACR---no imp!!!!!\n");
>  }
>  */
> -/*
> - * build a HDMI Video Info Frame
> - */
> -/*
> -static void dce_v6_0_afmt_update_avi_infoframe(struct drm_encoder
> *encoder,
> -					       void *buffer, size_t size)
> +
> +static void dce_v6_0_audio_set_avi_infoframe(struct drm_encoder
> *encoder,
> +					       struct drm_display_mode *mode)
>  {
> -	DRM_INFO("xxxx: dce_v6_0_afmt_update_avi_infoframe---no
> imp!!!!!\n");
> +	struct drm_device *dev = encoder->dev;
> +	struct amdgpu_device *adev = dev->dev_private;
> +	struct amdgpu_encoder *amdgpu_encoder =
> to_amdgpu_encoder(encoder);
> +	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder-
> >enc_priv;
> +	struct hdmi_avi_infoframe frame;
> +	u8 buffer[HDMI_INFOFRAME_HEADER_SIZE +
> HDMI_AVI_INFOFRAME_SIZE];
> +	uint8_t *payload = buffer + 3;
> +	uint8_t *header = buffer;
> +	ssize_t err;
> +	u32 tmp;
> +
> +	err = drm_hdmi_avi_infoframe_from_display_mode(&frame,
> mode);
> +	if (err < 0) {
> +		DRM_ERROR("failed to setup AVI infoframe: %zd\n", err);
> +		return;
> +	}
> +
> +	err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer));
> +	if (err < 0) {
> +		DRM_ERROR("failed to pack AVI infoframe: %zd\n", err);
> +		return;
> +	}
> +
> +	WREG32(mmAFMT_AVI_INFO0 + dig->afmt->offset,
> +	       payload[0x0] | (payload[0x1] << 8) | (payload[0x2] << 16) |
> (payload[0x3] << 24));
> +	WREG32(mmAFMT_AVI_INFO1 + dig->afmt->offset,
> +	       payload[0x4] | (payload[0x5] << 8) | (payload[0x6] << 16) |
> (payload[0x7] << 24));
> +	WREG32(mmAFMT_AVI_INFO2 + dig->afmt->offset,
> +	       payload[0x8] | (payload[0x9] << 8) | (payload[0xA] << 16) |
> (payload[0xB] << 24));
> +	WREG32(mmAFMT_AVI_INFO3 + dig->afmt->offset,
> +	       payload[0xC] | (payload[0xD] << 8) | (header[1] << 24));
> +
> +	tmp = RREG32(mmHDMI_INFOFRAME_CONTROL1 + dig->afmt-
> >offset);
> +	/* anything other than 0 */
> +	tmp = REG_SET_FIELD(tmp, HDMI_INFOFRAME_CONTROL1,
> +			HDMI_AUDIO_INFO_LINE, 2);
> +	WREG32(mmHDMI_INFOFRAME_CONTROL1 + dig->afmt->offset,
> tmp);
>  }
> 
>  static void dce_v6_0_audio_set_dto(struct drm_encoder *encoder, u32
> clock)
>  {
> -	DRM_INFO("xxxx: dce_v6_0_audio_set_dto---no imp!!!!!\n");
> +	struct drm_device *dev = encoder->dev;
> +	struct amdgpu_device *adev = dev->dev_private;
> +	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(encoder-
> >crtc);
> +	u32 tmp;
> +
> +	/*
> +	 * Two dtos: generally use dto0 for hdmi, dto1 for dp.
> +	 * Express [24MHz / target pixel clock] as an exact rational
> +	 * number (coefficient of two integer numbers.
> DCCG_AUDIO_DTOx_PHASE
> +	 * is the numerator, DCCG_AUDIO_DTOx_MODULE is the
> denominator
> +	 */
> +	tmp = RREG32(mmDCCG_AUDIO_DTO_SOURCE);
> +	tmp = REG_SET_FIELD(tmp, DCCG_AUDIO_DTO_SOURCE,
> +			DCCG_AUDIO_DTO0_SOURCE_SEL, amdgpu_crtc-
> >crtc_id);
> +	tmp = REG_SET_FIELD(tmp, DCCG_AUDIO_DTO_SOURCE,
> DCCG_AUDIO_DTO_SEL, 1);
> +	WREG32(mmDCCG_AUDIO_DTO_SOURCE, tmp);
> +	WREG32(mmDCCG_AUDIO_DTO1_PHASE, 24000);
> +	WREG32(mmDCCG_AUDIO_DTO1_MODULE, clock);
>  }
> -*/
> -/*
> - * update the info frames with the data from the current display mode
> - */
> +
> +static void dce_v6_0_audio_set_packet(struct drm_encoder *encoder)
> +{
> +	struct drm_device *dev = encoder->dev;
> +	struct amdgpu_device *adev = dev->dev_private;
> +	struct amdgpu_encoder *amdgpu_encoder =
> to_amdgpu_encoder(encoder);
> +	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder-
> >enc_priv;
> +	u32 tmp;
> +
> +	tmp = RREG32(mmAFMT_INFOFRAME_CONTROL0 + dig->afmt-
> >offset);
> +	tmp = REG_SET_FIELD(tmp, AFMT_INFOFRAME_CONTROL0,
> AFMT_AUDIO_INFO_UPDATE, 1);
> +	WREG32(mmAFMT_INFOFRAME_CONTROL0 + dig->afmt->offset,
> tmp);
> +
> +	tmp = RREG32(mmAFMT_60958_0 + dig->afmt->offset);
> +	tmp = REG_SET_FIELD(tmp, AFMT_60958_0,
> AFMT_60958_CS_CHANNEL_NUMBER_L, 1);
> +	WREG32(mmAFMT_60958_0 + dig->afmt->offset, tmp);
> +
> +	tmp = RREG32(mmAFMT_60958_1 + dig->afmt->offset);
> +	tmp = REG_SET_FIELD(tmp, AFMT_60958_1,
> AFMT_60958_CS_CHANNEL_NUMBER_R, 2);
> +	WREG32(mmAFMT_60958_1 + dig->afmt->offset, tmp);
> +
> +	tmp = RREG32(mmAFMT_60958_2 + dig->afmt->offset);
> +	tmp = REG_SET_FIELD(tmp, AFMT_60958_2,
> AFMT_60958_CS_CHANNEL_NUMBER_2, 3);
> +	tmp = REG_SET_FIELD(tmp, AFMT_60958_2,
> AFMT_60958_CS_CHANNEL_NUMBER_3, 4);
> +	tmp = REG_SET_FIELD(tmp, AFMT_60958_2,
> AFMT_60958_CS_CHANNEL_NUMBER_4, 5);
> +	tmp = REG_SET_FIELD(tmp, AFMT_60958_2,
> AFMT_60958_CS_CHANNEL_NUMBER_5, 6);
> +	tmp = REG_SET_FIELD(tmp, AFMT_60958_2,
> AFMT_60958_CS_CHANNEL_NUMBER_6, 7);
> +	tmp = REG_SET_FIELD(tmp, AFMT_60958_2,
> AFMT_60958_CS_CHANNEL_NUMBER_7, 8);
> +	WREG32(mmAFMT_60958_2 + dig->afmt->offset, tmp);
> +
> +	tmp = RREG32(mmAFMT_AUDIO_PACKET_CONTROL2 + dig->afmt-
> >offset);
> +	tmp = REG_SET_FIELD(tmp, AFMT_AUDIO_PACKET_CONTROL2,
> AFMT_AUDIO_CHANNEL_ENABLE, 0xff);
> +	WREG32(mmAFMT_AUDIO_PACKET_CONTROL2 + dig->afmt-
> >offset, tmp);
> +
> +	tmp = RREG32(mmHDMI_AUDIO_PACKET_CONTROL + dig->afmt-
> >offset);
> +	tmp = REG_SET_FIELD(tmp, HDMI_AUDIO_PACKET_CONTROL,
> HDMI_AUDIO_DELAY_EN, 1);
> +	tmp = REG_SET_FIELD(tmp, HDMI_AUDIO_PACKET_CONTROL,
> HDMI_AUDIO_PACKETS_PER_LINE, 3);
> +	WREG32(mmHDMI_AUDIO_PACKET_CONTROL + dig->afmt->offset,
> tmp);
> +
> +	tmp = RREG32(mmAFMT_AUDIO_PACKET_CONTROL + dig->afmt-
> >offset);
> +	tmp = REG_SET_FIELD(tmp, AFMT_AUDIO_PACKET_CONTROL,
> AFMT_RESET_FIFO_WHEN_AUDIO_DIS, 1);
> +	tmp = REG_SET_FIELD(tmp, AFMT_AUDIO_PACKET_CONTROL,
> AFMT_60958_CS_UPDATE, 1);
> +	WREG32(mmAFMT_AUDIO_PACKET_CONTROL + dig->afmt->offset,
> tmp);
> +}
> +
> +static void dce_v6_0_audio_set_mute(struct drm_encoder *encoder, bool
> mute)
> +{
> +	struct drm_device *dev = encoder->dev;
> +	struct amdgpu_device *adev = dev->dev_private;
> +	struct amdgpu_encoder *amdgpu_encoder =
> to_amdgpu_encoder(encoder);
> +	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder-
> >enc_priv;
> +	u32 tmp;
> +
> +	tmp = RREG32(mmHDMI_GC + dig->afmt->offset);
> +	tmp = REG_SET_FIELD(tmp, HDMI_GC, HDMI_GC_AVMUTE, mute ?
> 1 : 0);
> +	WREG32(mmHDMI_GC + dig->afmt->offset, tmp);
> +}
> +
> +static void dce_v6_0_audio_dp_enable(struct drm_encoder *encoder, bool
> enable)
> +{
> +	struct drm_device *dev = encoder->dev;
> +	struct amdgpu_device *adev = dev->dev_private;
> +	struct amdgpu_encoder *amdgpu_encoder =
> to_amdgpu_encoder(encoder);
> +	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder-
> >enc_priv;
> +	u32 tmp;
> +
> +	if (enable) {
> +		tmp = RREG32(mmAFMT_AUDIO_PACKET_CONTROL + dig-
> >afmt->offset);
> +		tmp = REG_SET_FIELD(tmp,
> AFMT_AUDIO_PACKET_CONTROL, AFMT_AUDIO_SAMPLE_SEND, 1);
> +		WREG32(mmAFMT_AUDIO_PACKET_CONTROL + dig->afmt-
> >offset, tmp);
> +
> +		tmp = RREG32(mmDP_SEC_TIMESTAMP + dig->afmt-
> >offset);
> +		tmp = REG_SET_FIELD(tmp, DP_SEC_TIMESTAMP,
> DP_SEC_TIMESTAMP_MODE, 1);
> +		WREG32(mmDP_SEC_TIMESTAMP + dig->afmt->offset,
> tmp);
> +
> +		tmp = RREG32(mmDP_SEC_CNTL + dig->afmt->offset);
> +		tmp = REG_SET_FIELD(tmp, DP_SEC_CNTL,
> DP_SEC_ASP_ENABLE, 1);
> +		tmp = REG_SET_FIELD(tmp, DP_SEC_CNTL,
> DP_SEC_ATP_ENABLE, 1);
> +		tmp = REG_SET_FIELD(tmp, DP_SEC_CNTL,
> DP_SEC_AIP_ENABLE, 1);
> +		tmp = REG_SET_FIELD(tmp, DP_SEC_CNTL,
> DP_SEC_STREAM_ENABLE, 1);
> +		WREG32(mmDP_SEC_CNTL + dig->afmt->offset, tmp);
> +	} else {
> +		WREG32(mmDP_SEC_CNTL + dig->afmt->offset, 0);
> +	}
> +}
> +
>  static void dce_v6_0_afmt_setmode(struct drm_encoder *encoder,
>  				  struct drm_display_mode *mode)
>  {
> -	DRM_INFO("xxxx: dce_v6_0_afmt_setmode ----no impl !!!!!!!!\n");
> +	struct drm_device *dev = encoder->dev;
> +	struct amdgpu_device *adev = dev->dev_private;
> +	struct amdgpu_encoder *amdgpu_encoder =
> to_amdgpu_encoder(encoder);
> +	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder-
> >enc_priv;
> +	struct drm_connector *connector;
> +	struct amdgpu_connector *amdgpu_connector = NULL;
> +
> +	if (!dig || !dig->afmt)
> +		return;
> +
> +	list_for_each_entry(connector, &encoder->dev-
> >mode_config.connector_list, head) {
> +		if (connector->encoder == encoder) {
> +			amdgpu_connector =
> to_amdgpu_connector(connector);
> +			break;
> +		}
> +	}
> +
> +	if (!amdgpu_connector) {
> +		DRM_ERROR("Couldn't find encoder's connector\n");
> +		return;
> +	}
> +
> +	if (!dig->afmt->enabled)
> +		return;
> +
> +	dig->afmt->pin = dce_v6_0_audio_get_pin(adev);
> +	if (!dig->afmt->pin)
> +		return;
> +
> +	/* disable audio before setting up hw */
> +	dce_v6_0_audio_enable(adev, dig->afmt->pin, false);
> +
> +	dce_v6_0_audio_set_mute(encoder, true);
> +	dce_v6_0_audio_write_speaker_allocation(encoder);
> +	dce_v6_0_audio_write_sad_regs(encoder);
> +	dce_v6_0_audio_write_latency_fields(encoder, mode);
> +	dce_v6_0_audio_set_dto(encoder, adev->clock.default_dispclk *
> 10);
> +	dce_v6_0_audio_set_packet(encoder);
> +	dce_v6_0_audio_select_pin(encoder);
> +	dce_v6_0_audio_set_avi_infoframe(encoder, mode);
> +	dce_v6_0_audio_set_mute(encoder, false);
> +	dce_v6_0_audio_dp_enable(encoder, 1);
> +
> +	/* enable audio after setting up hw */
> +	dce_v6_0_audio_enable(adev, dig->afmt->pin, true);
>  }
> 
>  static void dce_v6_0_afmt_enable(struct drm_encoder *encoder, bool
> enable)
> @@ -1368,6 +1760,7 @@ static void dce_v6_0_afmt_enable(struct
> drm_encoder *encoder, bool enable)
>  	/* Silent, r600_hdmi_enable will raise WARN for us */
>  	if (enable && dig->afmt->enabled)
>  		return;
> +
>  	if (!enable && !dig->afmt->enabled)
>  		return;
> 
> @@ -2781,6 +3174,7 @@ dce_v6_0_encoder_mode_set(struct
> drm_encoder *encoder,
>  {
> 
>  	struct amdgpu_encoder *amdgpu_encoder =
> to_amdgpu_encoder(encoder);
> +	int em =
> amdgpu_atombios_encoder_get_encoder_mode(encoder);
> 
>  	amdgpu_encoder->pixel_clock = adjusted_mode->clock;
> 
> @@ -2790,7 +3184,7 @@ dce_v6_0_encoder_mode_set(struct
> drm_encoder *encoder,
>  	/* set scaler clears this on some chips */
>  	dce_v6_0_set_interleave(encoder->crtc, mode);
> 
> -	if (amdgpu_atombios_encoder_get_encoder_mode(encoder) ==
> ATOM_ENCODER_MODE_HDMI) {
> +	if (em == ATOM_ENCODER_MODE_HDMI ||
> ENCODER_MODE_IS_DP(em)) {
>  		dce_v6_0_afmt_enable(encoder, true);
>  		dce_v6_0_afmt_setmode(encoder, adjusted_mode);
>  	}
> @@ -2852,11 +3246,12 @@ static void dce_v6_0_encoder_disable(struct
> drm_encoder *encoder)
> 
>  	struct amdgpu_encoder *amdgpu_encoder =
> to_amdgpu_encoder(encoder);
>  	struct amdgpu_encoder_atom_dig *dig;
> +	int em =
> amdgpu_atombios_encoder_get_encoder_mode(encoder);
> 
>  	amdgpu_atombios_encoder_dpms(encoder,
> DRM_MODE_DPMS_OFF);
> 
>  	if (amdgpu_atombios_encoder_is_digital(encoder)) {
> -		if
> (amdgpu_atombios_encoder_get_encoder_mode(encoder) ==
> ATOM_ENCODER_MODE_HDMI)
> +		if (em == ATOM_ENCODER_MODE_HDMI ||
> ENCODER_MODE_IS_DP(em))
>  			dce_v6_0_afmt_enable(encoder, false);
>  		dig = amdgpu_encoder->enc_priv;
>  		dig->dig_encoder = -1;
> diff --git a/drivers/gpu/drm/amd/include/asic_reg/dce/dce_6_0_sh_mask.h
> b/drivers/gpu/drm/amd/include/asic_reg/dce/dce_6_0_sh_mask.h
> index 9a4d4c2..abe05bc 100644
> --- a/drivers/gpu/drm/amd/include/asic_reg/dce/dce_6_0_sh_mask.h
> +++ b/drivers/gpu/drm/amd/include/asic_reg/dce/dce_6_0_sh_mask.h
> @@ -906,6 +906,8 @@
>  #define
> AZALIA_F0_CODEC_ENDPOINT_DATA__AZALIA_ENDPOINT_REG_DATA__S
> HIFT 0x00000000
>  #define
> AZALIA_F0_CODEC_ENDPOINT_INDEX__AZALIA_ENDPOINT_REG_INDEX_M
> ASK 0x000000ffL
>  #define
> AZALIA_F0_CODEC_ENDPOINT_INDEX__AZALIA_ENDPOINT_REG_INDEX__S
> HIFT 0x00000000
> +#define
> AZALIA_F0_CODEC_ENDPOINT_INDEX__AZALIA_ENDPOINT_REG_WRITE_E
> N_MASK 0x00000100L
> +#define
> AZALIA_F0_CODEC_ENDPOINT_INDEX__AZALIA_ENDPOINT_REG_WRITE_E
> N__SHIFT 0x00000008
>  #define
> AZALIA_F0_CODEC_FUNCTION_CONTROL_CONVERTER_SYNCHRONIZATION
> __CONVERTER_SYNCHRONIZATION_MASK 0x0000003fL
>  #define
> AZALIA_F0_CODEC_FUNCTION_CONTROL_CONVERTER_SYNCHRONIZATION
> __CONVERTER_SYNCHRONIZATION__SHIFT 0x00000000
>  #define
> AZALIA_F0_CODEC_FUNCTION_CONTROL_POWER_STATE__CLKSTOPOK_M
> ASK 0x00000200L
> --
> 2.7.4
> 
> _______________________________________________
> amd-gfx mailing list
> amd-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/amd-gfx
_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2017-02-22 17:08 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-02-22  3:37 [PATCH v3] drm/amdgpu: add DP audio support for si dce6 (v3) Xiaojie Yuan
     [not found] ` <1487734626-27738-1-git-send-email-Xiaojie.Yuan-5C7GfCeVMHo@public.gmane.org>
2017-02-22  4:40   ` Edward O'Callaghan
     [not found]     ` <86e62166-a3fa-92af-17d1-4bf1f90f1583-dczkZgxz+BNUPWh3PAxdjQ@public.gmane.org>
2017-02-22  9:13       ` Christian König
2017-02-22 17:08   ` Deucher, Alexander

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.