diff options
Diffstat (limited to 'drivers/gpu/drm/radeon/evergreen_hdmi.c')
| -rw-r--r-- | drivers/gpu/drm/radeon/evergreen_hdmi.c | 146 | 
1 files changed, 123 insertions, 23 deletions
diff --git a/drivers/gpu/drm/radeon/evergreen_hdmi.c b/drivers/gpu/drm/radeon/evergreen_hdmi.c index f71ce390aeb..1ec0e6e83f9 100644 --- a/drivers/gpu/drm/radeon/evergreen_hdmi.c +++ b/drivers/gpu/drm/radeon/evergreen_hdmi.c @@ -35,6 +35,8 @@  extern void dce6_afmt_write_speaker_allocation(struct drm_encoder *encoder);  extern void dce6_afmt_write_sad_regs(struct drm_encoder *encoder);  extern void dce6_afmt_select_pin(struct drm_encoder *encoder); +extern void dce6_afmt_write_latency_fields(struct drm_encoder *encoder, +					   struct drm_display_mode *mode);  /*   * update the N and CTS parameters for a given pixel clock rate @@ -58,6 +60,42 @@ static void evergreen_hdmi_update_ACR(struct drm_encoder *encoder, uint32_t cloc  	WREG32(HDMI_ACR_48_1 + offset, acr.n_48khz);  } +static void dce4_afmt_write_latency_fields(struct drm_encoder *encoder, +					   struct drm_display_mode *mode) +{ +	struct radeon_device *rdev = encoder->dev->dev_private; +	struct drm_connector *connector; +	struct radeon_connector *radeon_connector = NULL; +	u32 tmp = 0; + +	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(AZ_F0_CODEC_PIN0_CONTROL_RESPONSE_LIPSYNC, tmp); +} +  static void dce4_afmt_write_speaker_allocation(struct drm_encoder *encoder)  {  	struct radeon_device *rdev = encoder->dev->dev_private; @@ -68,8 +106,10 @@ static void dce4_afmt_write_speaker_allocation(struct drm_encoder *encoder)  	int sad_count;  	list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) { -		if (connector->encoder == encoder) +		if (connector->encoder == encoder) {  			radeon_connector = to_radeon_connector(connector); +			break; +		}  	}  	if (!radeon_connector) { @@ -78,7 +118,7 @@ static void dce4_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;  	} @@ -121,8 +161,10 @@ static void evergreen_hdmi_write_sad_regs(struct drm_encoder *encoder)  	};  	list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) { -		if (connector->encoder == encoder) +		if (connector->encoder == encoder) {  			radeon_connector = to_radeon_connector(connector); +			break; +		}  	}  	if (!radeon_connector) { @@ -131,7 +173,7 @@ static void evergreen_hdmi_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;  	} @@ -139,20 +181,30 @@ static void evergreen_hdmi_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(eld_reg_to_type[i][0], value);  	} @@ -241,10 +293,13 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode  	struct radeon_device *rdev = 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 = radeon_get_connector_for_encoder(encoder);  	u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE];  	struct hdmi_avi_infoframe frame;  	uint32_t offset;  	ssize_t err; +	uint32_t val; +	int bpc = 8;  	if (!dig || !dig->afmt)  		return; @@ -254,6 +309,21 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode  		return;  	offset = dig->afmt->offset; +	/* hdmi deep color mode general control packets setup, if bpc > 8 */ +	if (encoder->crtc) { +		struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); +		bpc = radeon_crtc->bpc; +	} + +	/* disable audio prior to setting up hw */ +	if (ASIC_IS_DCE6(rdev)) { +		dig->afmt->pin = dce6_audio_get_pin(rdev); +		dce6_audio_enable(rdev, dig->afmt->pin, false); +	} else { +		dig->afmt->pin = r600_audio_get_pin(rdev); +		r600_audio_enable(rdev, dig->afmt->pin, false); +	} +  	evergreen_audio_set_dto(encoder, mode->clock);  	WREG32(HDMI_VBI_PACKET_CONTROL + offset, @@ -261,6 +331,35 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode  	WREG32(AFMT_AUDIO_CRC_CONTROL + offset, 0x1000); +	val = RREG32(HDMI_CONTROL + offset); +	val &= ~HDMI_DEEP_COLOR_ENABLE; +	val &= ~HDMI_DEEP_COLOR_DEPTH_MASK; + +	switch (bpc) { +		case 0: +		case 6: +		case 8: +		case 16: +		default: +			DRM_DEBUG("%s: Disabling hdmi deep color for %d bpc.\n", +					 connector->name, bpc); +			break; +		case 10: +			val |= HDMI_DEEP_COLOR_ENABLE; +			val |= HDMI_DEEP_COLOR_DEPTH(HDMI_30BIT_DEEP_COLOR); +			DRM_DEBUG("%s: Enabling hdmi deep color 30 for 10 bpc.\n", +					 connector->name); +			break; +		case 12: +			val |= HDMI_DEEP_COLOR_ENABLE; +			val |= HDMI_DEEP_COLOR_DEPTH(HDMI_36BIT_DEEP_COLOR); +			DRM_DEBUG("%s: Enabling hdmi deep color 36 for 12 bpc.\n", +					 connector->name); +			break; +	} + +	WREG32(HDMI_CONTROL + offset, val); +  	WREG32(HDMI_VBI_PACKET_CONTROL + offset,  	       HDMI_NULL_SEND | /* send null packets when required */  	       HDMI_GC_SEND | /* send general control packets */ @@ -287,9 +386,13 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode  	/* fglrx clears sth in AFMT_AUDIO_PACKET_CONTROL2 here */ -	WREG32(HDMI_ACR_PACKET_CONTROL + offset, -	       HDMI_ACR_AUTO_SEND | /* allow hw to sent ACR packets when required */ -	       HDMI_ACR_SOURCE); /* select SW CTS value */ +	if (bpc > 8) +		WREG32(HDMI_ACR_PACKET_CONTROL + offset, +		       HDMI_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */ +	else +		WREG32(HDMI_ACR_PACKET_CONTROL + offset, +		       HDMI_ACR_SOURCE | /* select SW CTS value */ +		       HDMI_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */  	evergreen_hdmi_update_ACR(encoder, mode->clock); @@ -321,8 +424,10 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode  	if (ASIC_IS_DCE6(rdev)) {  		dce6_afmt_select_pin(encoder);  		dce6_afmt_write_sad_regs(encoder); +		dce6_afmt_write_latency_fields(encoder, mode);  	} else {  		evergreen_hdmi_write_sad_regs(encoder); +		dce4_afmt_write_latency_fields(encoder, mode);  	}  	err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode); @@ -355,12 +460,16 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode  	WREG32(AFMT_RAMP_CONTROL1 + offset, 0x007FFFFF);  	WREG32(AFMT_RAMP_CONTROL2 + offset, 0x00000001);  	WREG32(AFMT_RAMP_CONTROL3 + offset, 0x00000001); + +	/* enable audio after to setting up hw */ +	if (ASIC_IS_DCE6(rdev)) +		dce6_audio_enable(rdev, dig->afmt->pin, true); +	else +		r600_audio_enable(rdev, dig->afmt->pin, true);  }  void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable)  { -	struct drm_device *dev = encoder->dev; -	struct radeon_device *rdev = dev->dev_private;  	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);  	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; @@ -373,15 +482,6 @@ void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable)  	if (!enable && !dig->afmt->enabled)  		return; -	if (enable) { -		if (ASIC_IS_DCE6(rdev)) -			dig->afmt->pin = dce6_audio_get_pin(rdev); -		else -			dig->afmt->pin = r600_audio_get_pin(rdev); -	} else { -		dig->afmt->pin = NULL; -	} -  	dig->afmt->enabled = enable;  	DRM_DEBUG("%sabling HDMI interface @ 0x%04X for encoder 0x%x\n",  | 
