diff options
Diffstat (limited to 'drivers/gpu/drm/radeon/dce6_afmt.c')
| -rw-r--r-- | drivers/gpu/drm/radeon/dce6_afmt.c | 104 | 
1 files changed, 85 insertions, 19 deletions
diff --git a/drivers/gpu/drm/radeon/dce6_afmt.c b/drivers/gpu/drm/radeon/dce6_afmt.c index 85a69d2ea3d..0a65dc7e93e 100644 --- a/drivers/gpu/drm/radeon/dce6_afmt.c +++ b/drivers/gpu/drm/radeon/dce6_afmt.c @@ -93,15 +93,60 @@ void dce6_afmt_select_pin(struct drm_encoder *encoder)  	struct radeon_device *rdev = encoder->dev->dev_private;  	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);  	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; -	u32 offset = dig->afmt->offset; +	u32 offset; -	if (!dig->afmt->pin) +	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));  } +void dce6_afmt_write_latency_fields(struct drm_encoder *encoder, +				    struct drm_display_mode *mode) +{ +	struct radeon_device *rdev = encoder->dev->dev_private; +	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); +	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; +	struct drm_connector *connector; +	struct radeon_connector *radeon_connector = NULL; +	u32 tmp = 0, offset; + +	if (!dig || !dig->afmt || !dig->afmt->pin) +		return; + +	offset = dig->afmt->pin->offset; + +	list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) { +		if (connector->encoder == encoder) { +			radeon_connector = to_radeon_connector(connector); +			break; +		} +	} + +	if (!radeon_connector) { +		DRM_ERROR("Couldn't find encoder's connector\n"); +		return; +	} + +	if (mode->flags & DRM_MODE_FLAG_INTERLACE) { +		if (connector->latency_present[1]) +			tmp = VIDEO_LIPSYNC(connector->video_latency[1]) | +				AUDIO_LIPSYNC(connector->audio_latency[1]); +		else +			tmp = VIDEO_LIPSYNC(255) | AUDIO_LIPSYNC(255); +	} else { +		if (connector->latency_present[0]) +			tmp = VIDEO_LIPSYNC(connector->video_latency[0]) | +				AUDIO_LIPSYNC(connector->audio_latency[0]); +		else +			tmp = VIDEO_LIPSYNC(255) | AUDIO_LIPSYNC(255); +	} +	WREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC, tmp); +} +  void dce6_afmt_write_speaker_allocation(struct drm_encoder *encoder)  {  	struct radeon_device *rdev = encoder->dev->dev_private; @@ -113,7 +158,7 @@ void dce6_afmt_write_speaker_allocation(struct drm_encoder *encoder)  	u8 *sadb;  	int sad_count; -	if (!dig->afmt->pin) +	if (!dig || !dig->afmt || !dig->afmt->pin)  		return;  	offset = dig->afmt->pin->offset; @@ -129,7 +174,7 @@ void dce6_afmt_write_speaker_allocation(struct drm_encoder *encoder)  	}  	sad_count = drm_edid_to_speaker_allocation(radeon_connector->edid, &sadb); -	if (sad_count < 0) { +	if (sad_count <= 0) {  		DRM_ERROR("Couldn't read Speaker Allocation Data Block: %d\n", sad_count);  		return;  	} @@ -174,7 +219,7 @@ void dce6_afmt_write_sad_regs(struct drm_encoder *encoder)  		{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR13, HDMI_AUDIO_CODING_TYPE_WMA_PRO },  	}; -	if (!dig->afmt->pin) +	if (!dig || !dig->afmt || !dig->afmt->pin)  		return;  	offset = dig->afmt->pin->offset; @@ -190,7 +235,7 @@ void dce6_afmt_write_sad_regs(struct drm_encoder *encoder)  	}  	sad_count = drm_edid_to_sad(radeon_connector->edid, &sads); -	if (sad_count < 0) { +	if (sad_count <= 0) {  		DRM_ERROR("Couldn't read SADs: %d\n", sad_count);  		return;  	} @@ -198,20 +243,30 @@ void dce6_afmt_write_sad_regs(struct drm_encoder *encoder)  	for (i = 0; i < ARRAY_SIZE(eld_reg_to_type); i++) {  		u32 value = 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]) { -				value = MAX_CHANNELS(sad->channels) | -					DESCRIPTOR_BYTE_2(sad->byte2) | -					SUPPORTED_FREQUENCIES(sad->freq); +				if (sad->channels > max_channels) { +					value = MAX_CHANNELS(sad->channels) | +						DESCRIPTOR_BYTE_2(sad->byte2) | +						SUPPORTED_FREQUENCIES(sad->freq); +					max_channels = sad->channels; +				} +  				if (sad->format == HDMI_AUDIO_CODING_TYPE_PCM) -					value |= SUPPORTED_FREQUENCIES_STEREO(sad->freq); -				break; +					stereo_freqs |= sad->freq; +				else +					break;  			}  		} + +		value |= SUPPORTED_FREQUENCIES_STEREO(stereo_freqs); +  		WREG32_ENDPOINT(offset, eld_reg_to_type[i][0], value);  	} @@ -223,13 +278,15 @@ static int dce6_audio_chipset_supported(struct radeon_device *rdev)  	return !ASIC_IS_NODCE(rdev);  } -static void dce6_audio_enable(struct radeon_device *rdev, -			      struct r600_audio_pin *pin, -			      bool enable) +void dce6_audio_enable(struct radeon_device *rdev, +		       struct r600_audio_pin *pin, +		       bool enable)  { +	if (!pin) +		return; +  	WREG32_ENDPOINT(pin->offset, AZ_F0_CODEC_PIN_CONTROL_HOTPLUG_CONTROL, -			AUDIO_ENABLED); -	DRM_INFO("%s audio %d support\n", enable ? "Enabling" : "Disabling", pin->id); +			enable ? AUDIO_ENABLED : 0);  }  static const u32 pin_offsets[7] = @@ -252,9 +309,17 @@ int dce6_audio_init(struct radeon_device *rdev)  	rdev->audio.enabled = true; -	if (ASIC_IS_DCE8(rdev)) +	if (ASIC_IS_DCE81(rdev)) /* KV: 4 streams, 7 endpoints */  		rdev->audio.num_pins = 7; -	else +	else if (ASIC_IS_DCE83(rdev)) /* KB: 2 streams, 3 endpoints */ +		rdev->audio.num_pins = 3; +	else if (ASIC_IS_DCE8(rdev)) /* BN/HW: 6 streams, 7 endpoints */ +		rdev->audio.num_pins = 7; +	else if (ASIC_IS_DCE61(rdev)) /* TN: 4 streams, 6 endpoints */ +		rdev->audio.num_pins = 6; +	else if (ASIC_IS_DCE64(rdev)) /* OL: 2 streams, 2 endpoints */ +		rdev->audio.num_pins = 2; +	else /* SI: 6 streams, 6 endpoints */  		rdev->audio.num_pins = 6;  	for (i = 0; i < rdev->audio.num_pins; i++) { @@ -266,7 +331,8 @@ int dce6_audio_init(struct radeon_device *rdev)  		rdev->audio.pin[i].connected = false;  		rdev->audio.pin[i].offset = pin_offsets[i];  		rdev->audio.pin[i].id = i; -		dce6_audio_enable(rdev, &rdev->audio.pin[i], true); +		/* disable audio.  it will be set up later */ +		dce6_audio_enable(rdev, &rdev->audio.pin[i], false);  	}  	return 0;  | 
