Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4caca706 authored by Xiaojie Yuan's avatar Xiaojie Yuan Committed by Alex Deucher
Browse files

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: default avatarXiaojie Yuan <Xiaojie.Yuan@amd.com>
Reviewed-by: default avatarEdward O'Callaghan <funfunctor@folklore1984.net>
Reviewed-by: default avatarAlex Deucher <alexander.deucher@amd.com>
Acked-by: default avatarJunwei Zhang <Jerry.Zhang@amd.com>
Acked-by: default avatarChristian König <christian.koenig@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 6a124e67
Loading
Loading
Loading
Loading
+431 −36
Original line number Original line Diff line number Diff line
@@ -118,14 +118,27 @@ static const struct {
static u32 dce_v6_0_audio_endpt_rreg(struct amdgpu_device *adev,
static u32 dce_v6_0_audio_endpt_rreg(struct amdgpu_device *adev,
				     u32 block_offset, u32 reg)
				     u32 block_offset, u32 reg)
{
{
	DRM_INFO("xxxx: dce_v6_0_audio_endpt_rreg ----no impl!!!!\n");
	unsigned long flags;
	return 0;
	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,
static void dce_v6_0_audio_endpt_wreg(struct amdgpu_device *adev,
				      u32 block_offset, u32 reg, u32 v)
				      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)
static bool dce_v6_0_is_in_vblank(struct amdgpu_device *adev, int crtc)
@@ -1222,17 +1235,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);
		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)
static void dce_v6_0_audio_get_connected_pins(struct amdgpu_device *adev)
{
{
	int i;
	int i;
	u32 offset, tmp;
	u32 tmp;


	for (i = 0; i < adev->mode_info.audio.num_pins; i++) {
	for (i = 0; i < adev->mode_info.audio.num_pins; i++) {
		offset = adev->mode_info.audio.pin[i].offset;
		tmp = RREG32_AUDIO_ENDPT(adev->mode_info.audio.pin[i].offset,
		tmp = RREG32_AUDIO_ENDPT(offset,
				ixAZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT);
				      AZ_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT);
		if (REG_GET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT,
		if (((tmp & PORT_CONNECTIVITY_MASK) >> PORT_CONNECTIVITY_SHIFT) == 1)
					PORT_CONNECTIVITY))
			adev->mode_info.audio.pin[i].connected = false;
			adev->mode_info.audio.pin[i].connected = false;
		else
		else
			adev->mode_info.audio.pin[i].connected = true;
			adev->mode_info.audio.pin[i].connected = true;
@@ -1254,45 +1267,206 @@ static struct amdgpu_audio_pin *dce_v6_0_audio_get_pin(struct amdgpu_device *ade
	return NULL;
	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_device *adev = encoder->dev->dev_private;
	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
	u32 offset;


	if (!dig || !dig->afmt || !dig->afmt->pin)
	if (!dig || !dig->afmt || !dig->afmt->pin)
		return;
		return;


	offset = dig->afmt->offset;
	WREG32(mmAFMT_AUDIO_SRC_CONTROL + dig->afmt->offset,

	       REG_SET_FIELD(0, AFMT_AUDIO_SRC_CONTROL, AFMT_AUDIO_SRC_SELECT,
	WREG32(AFMT_AUDIO_SRC_CONTROL + offset,
		             dig->afmt->pin->id));
	       AFMT_AUDIO_SRC_SELECT(dig->afmt->pin->id));

}
}


static void dce_v6_0_audio_write_latency_fields(struct drm_encoder *encoder,
static void dce_v6_0_audio_write_latency_fields(struct drm_encoder *encoder,
						struct drm_display_mode *mode)
						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)
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)
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,
static void dce_v6_0_audio_enable(struct amdgpu_device *adev,
				  struct amdgpu_audio_pin *pin,
				  struct amdgpu_audio_pin *pin,
				  bool enable)
				  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] =
static const u32 pin_offsets[7] =
@@ -1308,12 +1482,54 @@ static const u32 pin_offsets[7] =


static int dce_v6_0_audio_init(struct amdgpu_device *adev)
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;
	return 0;
}
}


static void dce_v6_0_audio_fini(struct amdgpu_device *adev)
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;
}
}


/*
/*
@@ -1322,28 +1538,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");
	DRM_INFO("xxxx: dce_v6_0_afmt_update_ACR---no imp!!!!!\n");
}
}
*/
*/
/*

 * build a HDMI Video Info Frame
static void dce_v6_0_audio_set_avi_infoframe(struct drm_encoder *encoder,
 */
					       struct drm_display_mode *mode)
/*
static void dce_v6_0_afmt_update_avi_infoframe(struct drm_encoder *encoder,
					       void *buffer, size_t size)
{
{
	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)
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;

	/*
	/*
 * update the info frames with the data from the current display mode
	 * 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);
}

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,
static void dce_v6_0_afmt_setmode(struct drm_encoder *encoder,
				  struct drm_display_mode *mode)
				  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)
static void dce_v6_0_afmt_enable(struct drm_encoder *encoder, bool enable)
@@ -1359,6 +1751,7 @@ static void dce_v6_0_afmt_enable(struct drm_encoder *encoder, bool enable)
	/* Silent, r600_hdmi_enable will raise WARN for us */
	/* Silent, r600_hdmi_enable will raise WARN for us */
	if (enable && dig->afmt->enabled)
	if (enable && dig->afmt->enabled)
		return;
		return;

	if (!enable && !dig->afmt->enabled)
	if (!enable && !dig->afmt->enabled)
		return;
		return;


@@ -2753,6 +3146,7 @@ dce_v6_0_encoder_mode_set(struct drm_encoder *encoder,
{
{


	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_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;
	amdgpu_encoder->pixel_clock = adjusted_mode->clock;


@@ -2762,7 +3156,7 @@ dce_v6_0_encoder_mode_set(struct drm_encoder *encoder,
	/* set scaler clears this on some chips */
	/* set scaler clears this on some chips */
	dce_v6_0_set_interleave(encoder->crtc, mode);
	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_enable(encoder, true);
		dce_v6_0_afmt_setmode(encoder, adjusted_mode);
		dce_v6_0_afmt_setmode(encoder, adjusted_mode);
	}
	}
@@ -2824,11 +3218,12 @@ static void dce_v6_0_encoder_disable(struct drm_encoder *encoder)


	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
	struct amdgpu_encoder_atom_dig *dig;
	struct amdgpu_encoder_atom_dig *dig;
	int em = amdgpu_atombios_encoder_get_encoder_mode(encoder);


	amdgpu_atombios_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
	amdgpu_atombios_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);


	if (amdgpu_atombios_encoder_is_digital(encoder)) {
	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);
			dce_v6_0_afmt_enable(encoder, false);
		dig = amdgpu_encoder->enc_priv;
		dig = amdgpu_encoder->enc_priv;
		dig->dig_encoder = -1;
		dig->dig_encoder = -1;
+2 −0
Original line number Original line Diff line number Diff line
@@ -906,6 +906,8 @@
#define AZALIA_F0_CODEC_ENDPOINT_DATA__AZALIA_ENDPOINT_REG_DATA__SHIFT 0x00000000
#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_MASK 0x000000ffL
#define AZALIA_F0_CODEC_ENDPOINT_INDEX__AZALIA_ENDPOINT_REG_INDEX__SHIFT 0x00000000
#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_MASK 0x0000003fL
#define AZALIA_F0_CODEC_FUNCTION_CONTROL_CONVERTER_SYNCHRONIZATION__CONVERTER_SYNCHRONIZATION__SHIFT 0x00000000
#define AZALIA_F0_CODEC_FUNCTION_CONTROL_CONVERTER_SYNCHRONIZATION__CONVERTER_SYNCHRONIZATION__SHIFT 0x00000000
#define AZALIA_F0_CODEC_FUNCTION_CONTROL_POWER_STATE__CLKSTOPOK_MASK 0x00000200L
#define AZALIA_F0_CODEC_FUNCTION_CONTROL_POWER_STATE__CLKSTOPOK_MASK 0x00000200L