xref: /linux/drivers/gpu/drm/radeon/evergreen_hdmi.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
1e55d3e6cSRafał Miłecki /*
2e55d3e6cSRafał Miłecki  * Copyright 2008 Advanced Micro Devices, Inc.
3e55d3e6cSRafał Miłecki  * Copyright 2008 Red Hat Inc.
4e55d3e6cSRafał Miłecki  * Copyright 2009 Christian König.
5e55d3e6cSRafał Miłecki  *
6e55d3e6cSRafał Miłecki  * Permission is hereby granted, free of charge, to any person obtaining a
7e55d3e6cSRafał Miłecki  * copy of this software and associated documentation files (the "Software"),
8e55d3e6cSRafał Miłecki  * to deal in the Software without restriction, including without limitation
9e55d3e6cSRafał Miłecki  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10e55d3e6cSRafał Miłecki  * and/or sell copies of the Software, and to permit persons to whom the
11e55d3e6cSRafał Miłecki  * Software is furnished to do so, subject to the following conditions:
12e55d3e6cSRafał Miłecki  *
13e55d3e6cSRafał Miłecki  * The above copyright notice and this permission notice shall be included in
14e55d3e6cSRafał Miłecki  * all copies or substantial portions of the Software.
15e55d3e6cSRafał Miłecki  *
16e55d3e6cSRafał Miłecki  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17e55d3e6cSRafał Miłecki  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18e55d3e6cSRafał Miłecki  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19e55d3e6cSRafał Miłecki  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20e55d3e6cSRafał Miłecki  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21e55d3e6cSRafał Miłecki  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22e55d3e6cSRafał Miłecki  * OTHER DEALINGS IN THE SOFTWARE.
23e55d3e6cSRafał Miłecki  *
24e55d3e6cSRafał Miłecki  * Authors: Christian König
25e55d3e6cSRafał Miłecki  *          Rafał Miłecki
26e55d3e6cSRafał Miłecki  */
27e3b2e034SThierry Reding #include <linux/hdmi.h>
28c182615fSSam Ravnborg 
29e747235eSJani Nikula #include <drm/drm_edid.h>
30760285e7SDavid Howells #include <drm/radeon_drm.h>
31dc872ff5SLee Jones #include "evergreen_hdmi.h"
32e55d3e6cSRafał Miłecki #include "radeon.h"
33e55d3e6cSRafał Miłecki #include "radeon_asic.h"
34070a2e63SAlex Deucher #include "radeon_audio.h"
35e55d3e6cSRafał Miłecki #include "evergreend.h"
36e55d3e6cSRafał Miłecki #include "atom.h"
37e55d3e6cSRafał Miłecki 
38d3d8c141SAlex Deucher /* enable the audio stream */
dce4_audio_enable(struct radeon_device * rdev,struct r600_audio_pin * pin,u8 enable_mask)398bf59820SSlava Grigorev void dce4_audio_enable(struct radeon_device *rdev,
40d3d8c141SAlex Deucher 			      struct r600_audio_pin *pin,
41d3d8c141SAlex Deucher 			      u8 enable_mask)
42d3d8c141SAlex Deucher {
43d3d8c141SAlex Deucher 	u32 tmp = RREG32(AZ_HOT_PLUG_CONTROL);
44d3d8c141SAlex Deucher 
45d3d8c141SAlex Deucher 	if (!pin)
46d3d8c141SAlex Deucher 		return;
47d3d8c141SAlex Deucher 
48d3d8c141SAlex Deucher 	if (enable_mask) {
49d3d8c141SAlex Deucher 		tmp |= AUDIO_ENABLED;
50d3d8c141SAlex Deucher 		if (enable_mask & 1)
51d3d8c141SAlex Deucher 			tmp |= PIN0_AUDIO_ENABLED;
52d3d8c141SAlex Deucher 		if (enable_mask & 2)
53d3d8c141SAlex Deucher 			tmp |= PIN1_AUDIO_ENABLED;
54d3d8c141SAlex Deucher 		if (enable_mask & 4)
55d3d8c141SAlex Deucher 			tmp |= PIN2_AUDIO_ENABLED;
56d3d8c141SAlex Deucher 		if (enable_mask & 8)
57d3d8c141SAlex Deucher 			tmp |= PIN3_AUDIO_ENABLED;
58d3d8c141SAlex Deucher 	} else {
59d3d8c141SAlex Deucher 		tmp &= ~(AUDIO_ENABLED |
60d3d8c141SAlex Deucher 			 PIN0_AUDIO_ENABLED |
61d3d8c141SAlex Deucher 			 PIN1_AUDIO_ENABLED |
62d3d8c141SAlex Deucher 			 PIN2_AUDIO_ENABLED |
63d3d8c141SAlex Deucher 			 PIN3_AUDIO_ENABLED);
64d3d8c141SAlex Deucher 	}
65d3d8c141SAlex Deucher 
66d3d8c141SAlex Deucher 	WREG32(AZ_HOT_PLUG_CONTROL, tmp);
67d3d8c141SAlex Deucher }
68d3d8c141SAlex Deucher 
evergreen_hdmi_update_acr(struct drm_encoder * encoder,long offset,const struct radeon_hdmi_acr * acr)6964424d6eSSlava Grigorev void evergreen_hdmi_update_acr(struct drm_encoder *encoder, long offset,
7064424d6eSSlava Grigorev 	const struct radeon_hdmi_acr *acr)
71e55d3e6cSRafał Miłecki {
72e55d3e6cSRafał Miłecki 	struct drm_device *dev = encoder->dev;
73e55d3e6cSRafał Miłecki 	struct radeon_device *rdev = dev->dev_private;
7464424d6eSSlava Grigorev 	int bpc = 8;
75e55d3e6cSRafał Miłecki 
7664424d6eSSlava Grigorev 	if (encoder->crtc) {
7764424d6eSSlava Grigorev 		struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
7864424d6eSSlava Grigorev 		bpc = radeon_crtc->bpc;
7964424d6eSSlava Grigorev 	}
80e55d3e6cSRafał Miłecki 
8164424d6eSSlava Grigorev 	if (bpc > 8)
8264424d6eSSlava Grigorev 		WREG32(HDMI_ACR_PACKET_CONTROL + offset,
8364424d6eSSlava Grigorev 			HDMI_ACR_AUTO_SEND);	/* allow hw to sent ACR packets when required */
8464424d6eSSlava Grigorev 	else
8564424d6eSSlava Grigorev 		WREG32(HDMI_ACR_PACKET_CONTROL + offset,
8664424d6eSSlava Grigorev 			HDMI_ACR_SOURCE |		/* select SW CTS value */
8764424d6eSSlava Grigorev 			HDMI_ACR_AUTO_SEND);	/* allow hw to sent ACR packets when required */
88e55d3e6cSRafał Miłecki 
8964424d6eSSlava Grigorev 	WREG32(HDMI_ACR_32_0 + offset, HDMI_ACR_CTS_32(acr->cts_32khz));
9064424d6eSSlava Grigorev 	WREG32(HDMI_ACR_32_1 + offset, acr->n_32khz);
9164424d6eSSlava Grigorev 
9264424d6eSSlava Grigorev 	WREG32(HDMI_ACR_44_0 + offset, HDMI_ACR_CTS_44(acr->cts_44_1khz));
9364424d6eSSlava Grigorev 	WREG32(HDMI_ACR_44_1 + offset, acr->n_44_1khz);
9464424d6eSSlava Grigorev 
9564424d6eSSlava Grigorev 	WREG32(HDMI_ACR_48_0 + offset, HDMI_ACR_CTS_48(acr->cts_48khz));
9664424d6eSSlava Grigorev 	WREG32(HDMI_ACR_48_1 + offset, acr->n_48khz);
97e55d3e6cSRafał Miłecki }
98e55d3e6cSRafał Miłecki 
dce4_afmt_write_latency_fields(struct drm_encoder * encoder,struct drm_connector * connector,struct drm_display_mode * mode)9987654f87SSlava Grigorev void dce4_afmt_write_latency_fields(struct drm_encoder *encoder,
10087654f87SSlava Grigorev 		struct drm_connector *connector, struct drm_display_mode *mode)
101712fd8a2SAlex Deucher {
102712fd8a2SAlex Deucher 	struct radeon_device *rdev = encoder->dev->dev_private;
103712fd8a2SAlex Deucher 	u32 tmp = 0;
104712fd8a2SAlex Deucher 
105712fd8a2SAlex Deucher 	if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
106712fd8a2SAlex Deucher 		if (connector->latency_present[1])
107712fd8a2SAlex Deucher 			tmp = VIDEO_LIPSYNC(connector->video_latency[1]) |
108712fd8a2SAlex Deucher 				AUDIO_LIPSYNC(connector->audio_latency[1]);
109712fd8a2SAlex Deucher 		else
110712fd8a2SAlex Deucher 			tmp = VIDEO_LIPSYNC(255) | AUDIO_LIPSYNC(255);
111712fd8a2SAlex Deucher 	} else {
112712fd8a2SAlex Deucher 		if (connector->latency_present[0])
113712fd8a2SAlex Deucher 			tmp = VIDEO_LIPSYNC(connector->video_latency[0]) |
114712fd8a2SAlex Deucher 				AUDIO_LIPSYNC(connector->audio_latency[0]);
115712fd8a2SAlex Deucher 		else
116712fd8a2SAlex Deucher 			tmp = VIDEO_LIPSYNC(255) | AUDIO_LIPSYNC(255);
117712fd8a2SAlex Deucher 	}
11887654f87SSlava Grigorev 	WREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_RESPONSE_LIPSYNC, tmp);
119712fd8a2SAlex Deucher }
120712fd8a2SAlex Deucher 
dce4_afmt_hdmi_write_speaker_allocation(struct drm_encoder * encoder,u8 * sadb,int sad_count)12100a9d4bcSSlava Grigorev void dce4_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder,
12200a9d4bcSSlava Grigorev 	u8 *sadb, int sad_count)
123ba7def4fSAlex Deucher {
124ba7def4fSAlex Deucher 	struct radeon_device *rdev = encoder->dev->dev_private;
125ba7def4fSAlex Deucher 	u32 tmp;
126ba7def4fSAlex Deucher 
127ba7def4fSAlex Deucher 	/* program the speaker allocation */
12800a9d4bcSSlava Grigorev 	tmp = RREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER);
129ba7def4fSAlex Deucher 	tmp &= ~(DP_CONNECTION | SPEAKER_ALLOCATION_MASK);
130ba7def4fSAlex Deucher 	/* set HDMI mode */
131ba7def4fSAlex Deucher 	tmp |= HDMI_CONNECTION;
132ba7def4fSAlex Deucher 	if (sad_count)
133ba7def4fSAlex Deucher 		tmp |= SPEAKER_ALLOCATION(sadb[0]);
134ba7def4fSAlex Deucher 	else
135ba7def4fSAlex Deucher 		tmp |= SPEAKER_ALLOCATION(5); /* stereo */
13600a9d4bcSSlava Grigorev 	WREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER, tmp);
13700a9d4bcSSlava Grigorev }
138ba7def4fSAlex Deucher 
dce4_afmt_dp_write_speaker_allocation(struct drm_encoder * encoder,u8 * sadb,int sad_count)13900a9d4bcSSlava Grigorev void dce4_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder,
14000a9d4bcSSlava Grigorev 	u8 *sadb, int sad_count)
14100a9d4bcSSlava Grigorev {
14200a9d4bcSSlava Grigorev 	struct radeon_device *rdev = encoder->dev->dev_private;
14300a9d4bcSSlava Grigorev 	u32 tmp;
14400a9d4bcSSlava Grigorev 
14500a9d4bcSSlava Grigorev 	/* program the speaker allocation */
14600a9d4bcSSlava Grigorev 	tmp = RREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER);
14700a9d4bcSSlava Grigorev 	tmp &= ~(HDMI_CONNECTION | SPEAKER_ALLOCATION_MASK);
14800a9d4bcSSlava Grigorev 	/* set DP mode */
14900a9d4bcSSlava Grigorev 	tmp |= DP_CONNECTION;
15000a9d4bcSSlava Grigorev 	if (sad_count)
15100a9d4bcSSlava Grigorev 		tmp |= SPEAKER_ALLOCATION(sadb[0]);
15200a9d4bcSSlava Grigorev 	else
15300a9d4bcSSlava Grigorev 		tmp |= SPEAKER_ALLOCATION(5); /* stereo */
15400a9d4bcSSlava Grigorev 	WREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER, tmp);
155ba7def4fSAlex Deucher }
156ba7def4fSAlex Deucher 
evergreen_hdmi_write_sad_regs(struct drm_encoder * encoder,struct cea_sad * sads,int sad_count)157070a2e63SAlex Deucher void evergreen_hdmi_write_sad_regs(struct drm_encoder *encoder,
158070a2e63SAlex Deucher 	struct cea_sad *sads, int sad_count)
15946892caaSRafał Miłecki {
160070a2e63SAlex Deucher 	int i;
16146892caaSRafał Miłecki 	struct radeon_device *rdev = encoder->dev->dev_private;
16246892caaSRafał Miłecki 	static const u16 eld_reg_to_type[][2] = {
16346892caaSRafał Miłecki 		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR0, HDMI_AUDIO_CODING_TYPE_PCM },
16446892caaSRafał Miłecki 		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR1, HDMI_AUDIO_CODING_TYPE_AC3 },
16546892caaSRafał Miłecki 		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR2, HDMI_AUDIO_CODING_TYPE_MPEG1 },
16646892caaSRafał Miłecki 		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR3, HDMI_AUDIO_CODING_TYPE_MP3 },
16746892caaSRafał Miłecki 		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR4, HDMI_AUDIO_CODING_TYPE_MPEG2 },
16846892caaSRafał Miłecki 		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR5, HDMI_AUDIO_CODING_TYPE_AAC_LC },
16946892caaSRafał Miłecki 		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR6, HDMI_AUDIO_CODING_TYPE_DTS },
17046892caaSRafał Miłecki 		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR7, HDMI_AUDIO_CODING_TYPE_ATRAC },
17146892caaSRafał Miłecki 		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR9, HDMI_AUDIO_CODING_TYPE_EAC3 },
17246892caaSRafał Miłecki 		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR10, HDMI_AUDIO_CODING_TYPE_DTS_HD },
17346892caaSRafał Miłecki 		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR11, HDMI_AUDIO_CODING_TYPE_MLP },
17446892caaSRafał Miłecki 		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR13, HDMI_AUDIO_CODING_TYPE_WMA_PRO },
17546892caaSRafał Miłecki 	};
17646892caaSRafał Miłecki 
17746892caaSRafał Miłecki 	for (i = 0; i < ARRAY_SIZE(eld_reg_to_type); i++) {
17846892caaSRafał Miłecki 		u32 value = 0;
1790f57bca9SAnssi Hannula 		u8 stereo_freqs = 0;
1800f57bca9SAnssi Hannula 		int max_channels = -1;
18146892caaSRafał Miłecki 		int j;
18246892caaSRafał Miłecki 
18346892caaSRafał Miłecki 		for (j = 0; j < sad_count; j++) {
18446892caaSRafał Miłecki 			struct cea_sad *sad = &sads[j];
18546892caaSRafał Miłecki 
18646892caaSRafał Miłecki 			if (sad->format == eld_reg_to_type[i][1]) {
1870f57bca9SAnssi Hannula 				if (sad->channels > max_channels) {
18846892caaSRafał Miłecki 					value = MAX_CHANNELS(sad->channels) |
18946892caaSRafał Miłecki 						DESCRIPTOR_BYTE_2(sad->byte2) |
19046892caaSRafał Miłecki 						SUPPORTED_FREQUENCIES(sad->freq);
1910f57bca9SAnssi Hannula 					max_channels = sad->channels;
1920f57bca9SAnssi Hannula 				}
1930f57bca9SAnssi Hannula 
19446892caaSRafał Miłecki 				if (sad->format == HDMI_AUDIO_CODING_TYPE_PCM)
1950f57bca9SAnssi Hannula 					stereo_freqs |= sad->freq;
1960f57bca9SAnssi Hannula 				else
19746892caaSRafał Miłecki 					break;
19846892caaSRafał Miłecki 			}
19946892caaSRafał Miłecki 		}
2000f57bca9SAnssi Hannula 
2010f57bca9SAnssi Hannula 		value |= SUPPORTED_FREQUENCIES_STEREO(stereo_freqs);
2020f57bca9SAnssi Hannula 
203070a2e63SAlex Deucher 		WREG32_ENDPOINT(0, eld_reg_to_type[i][0], value);
20446892caaSRafał Miłecki 	}
20546892caaSRafał Miłecki }
20646892caaSRafał Miłecki 
207e55d3e6cSRafał Miłecki /*
20896ea7afbSSlava Grigorev  * build a AVI Info Frame
209e55d3e6cSRafał Miłecki  */
evergreen_set_avi_packet(struct radeon_device * rdev,u32 offset,unsigned char * buffer,size_t size)210baa7d8e4SSlava Grigorev void evergreen_set_avi_packet(struct radeon_device *rdev, u32 offset,
21196ea7afbSSlava Grigorev 			      unsigned char *buffer, size_t size)
212e55d3e6cSRafał Miłecki {
213e3b2e034SThierry Reding 	uint8_t *frame = buffer + 3;
214e55d3e6cSRafał Miłecki 
215e55d3e6cSRafał Miłecki 	WREG32(AFMT_AVI_INFO0 + offset,
216e55d3e6cSRafał Miłecki 		frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24));
217e55d3e6cSRafał Miłecki 	WREG32(AFMT_AVI_INFO1 + offset,
218e55d3e6cSRafał Miłecki 		frame[0x4] | (frame[0x5] << 8) | (frame[0x6] << 16) | (frame[0x7] << 24));
219e55d3e6cSRafał Miłecki 	WREG32(AFMT_AVI_INFO2 + offset,
220e55d3e6cSRafał Miłecki 		frame[0x8] | (frame[0x9] << 8) | (frame[0xA] << 16) | (frame[0xB] << 24));
221e55d3e6cSRafał Miłecki 	WREG32(AFMT_AVI_INFO3 + offset,
22296ea7afbSSlava Grigorev 		frame[0xC] | (frame[0xD] << 8) | (buffer[1] << 24));
223baa7d8e4SSlava Grigorev 
224baa7d8e4SSlava Grigorev 	WREG32_P(HDMI_INFOFRAME_CONTROL1 + offset,
225baa7d8e4SSlava Grigorev 		 HDMI_AVI_INFO_LINE(2),	/* anything other than 0 */
226baa7d8e4SSlava Grigorev 		 ~HDMI_AVI_INFO_LINE_MASK);
227e55d3e6cSRafał Miłecki }
228e55d3e6cSRafał Miłecki 
dce4_hdmi_audio_set_dto(struct radeon_device * rdev,struct radeon_crtc * crtc,unsigned int clock)229a85d682aSSlava Grigorev void dce4_hdmi_audio_set_dto(struct radeon_device *rdev,
230a85d682aSSlava Grigorev 	struct radeon_crtc *crtc, unsigned int clock)
231b1f6f47eSAlex Deucher {
232a85d682aSSlava Grigorev 	unsigned int max_ratio = clock / 24000;
2331518dd8eSAlex Deucher 	u32 dto_phase;
2341518dd8eSAlex Deucher 	u32 wallclock_ratio;
235a85d682aSSlava Grigorev 	u32 value;
236b1f6f47eSAlex Deucher 
2371518dd8eSAlex Deucher 	if (max_ratio >= 8) {
2381518dd8eSAlex Deucher 		dto_phase = 192 * 1000;
2391518dd8eSAlex Deucher 		wallclock_ratio = 3;
2401518dd8eSAlex Deucher 	} else if (max_ratio >= 4) {
2411518dd8eSAlex Deucher 		dto_phase = 96 * 1000;
2421518dd8eSAlex Deucher 		wallclock_ratio = 2;
2431518dd8eSAlex Deucher 	} else if (max_ratio >= 2) {
2441518dd8eSAlex Deucher 		dto_phase = 48 * 1000;
2451518dd8eSAlex Deucher 		wallclock_ratio = 1;
2461518dd8eSAlex Deucher 	} else {
2471518dd8eSAlex Deucher 		dto_phase = 24 * 1000;
2481518dd8eSAlex Deucher 		wallclock_ratio = 0;
2491518dd8eSAlex Deucher 	}
2501518dd8eSAlex Deucher 
251a85d682aSSlava Grigorev 	value = RREG32(DCCG_AUDIO_DTO0_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK;
252a85d682aSSlava Grigorev 	value |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio);
253a85d682aSSlava Grigorev 	value &= ~DCCG_AUDIO_DTO1_USE_512FBR_DTO;
254a85d682aSSlava Grigorev 	WREG32(DCCG_AUDIO_DTO0_CNTL, value);
255a85d682aSSlava Grigorev 
256a85d682aSSlava Grigorev 	/* Two dtos; generally use dto0 for HDMI */
257a85d682aSSlava Grigorev 	value = 0;
258a85d682aSSlava Grigorev 
259a85d682aSSlava Grigorev 	if (crtc)
260a85d682aSSlava Grigorev 		value |= DCCG_AUDIO_DTO0_SOURCE_SEL(crtc->crtc_id);
261a85d682aSSlava Grigorev 
262a85d682aSSlava Grigorev 	WREG32(DCCG_AUDIO_DTO_SOURCE, value);
263a85d682aSSlava Grigorev 
264b1f6f47eSAlex Deucher 	/* Express [24MHz / target pixel clock] as an exact rational
265b1f6f47eSAlex Deucher 	 * number (coefficient of two integer numbers.  DCCG_AUDIO_DTOx_PHASE
266b1f6f47eSAlex Deucher 	 * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
267b1f6f47eSAlex Deucher 	 */
2681518dd8eSAlex Deucher 	WREG32(DCCG_AUDIO_DTO0_PHASE, dto_phase);
269a85d682aSSlava Grigorev 	WREG32(DCCG_AUDIO_DTO0_MODULE, clock);
270b1f6f47eSAlex Deucher }
271b1f6f47eSAlex Deucher 
dce4_dp_audio_set_dto(struct radeon_device * rdev,struct radeon_crtc * crtc,unsigned int clock)272a85d682aSSlava Grigorev void dce4_dp_audio_set_dto(struct radeon_device *rdev,
273a85d682aSSlava Grigorev 			   struct radeon_crtc *crtc, unsigned int clock)
274a85d682aSSlava Grigorev {
275a85d682aSSlava Grigorev 	u32 value;
276a85d682aSSlava Grigorev 
277a85d682aSSlava Grigorev 	value = RREG32(DCCG_AUDIO_DTO1_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK;
278a85d682aSSlava Grigorev 	value |= DCCG_AUDIO_DTO1_USE_512FBR_DTO;
279a85d682aSSlava Grigorev 	WREG32(DCCG_AUDIO_DTO1_CNTL, value);
280a85d682aSSlava Grigorev 
281a85d682aSSlava Grigorev 	/* Two dtos; generally use dto1 for DP */
282a85d682aSSlava Grigorev 	value = 0;
283a85d682aSSlava Grigorev 	value |= DCCG_AUDIO_DTO_SEL;
284a85d682aSSlava Grigorev 
285a85d682aSSlava Grigorev 	if (crtc)
286a85d682aSSlava Grigorev 		value |= DCCG_AUDIO_DTO0_SOURCE_SEL(crtc->crtc_id);
287a85d682aSSlava Grigorev 
288a85d682aSSlava Grigorev 	WREG32(DCCG_AUDIO_DTO_SOURCE, value);
289a85d682aSSlava Grigorev 
290a85d682aSSlava Grigorev 	/* Express [24MHz / target pixel clock] as an exact rational
291a85d682aSSlava Grigorev 	 * number (coefficient of two integer numbers.  DCCG_AUDIO_DTOx_PHASE
292a85d682aSSlava Grigorev 	 * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
293a85d682aSSlava Grigorev 	 */
294fe6fc1f1SSlava Grigorev 	if (ASIC_IS_DCE41(rdev)) {
295fe6fc1f1SSlava Grigorev 		unsigned int div = (RREG32(DCE41_DENTIST_DISPCLK_CNTL) &
296fe6fc1f1SSlava Grigorev 			DENTIST_DPREFCLK_WDIVIDER_MASK) >>
297fe6fc1f1SSlava Grigorev 			DENTIST_DPREFCLK_WDIVIDER_SHIFT;
298fe6fc1f1SSlava Grigorev 		div = radeon_audio_decode_dfs_div(div);
299fe6fc1f1SSlava Grigorev 
300fe6fc1f1SSlava Grigorev 		if (div)
301fe6fc1f1SSlava Grigorev 			clock = 100 * clock / div;
302fe6fc1f1SSlava Grigorev 	}
303fe6fc1f1SSlava Grigorev 
304a85d682aSSlava Grigorev 	WREG32(DCCG_AUDIO_DTO1_PHASE, 24000);
305aeefd07eSAlex Deucher 	WREG32(DCCG_AUDIO_DTO1_MODULE, clock);
306a85d682aSSlava Grigorev }
307b1f6f47eSAlex Deucher 
dce4_set_vbi_packet(struct drm_encoder * encoder,u32 offset)308930a9785SAlex Deucher void dce4_set_vbi_packet(struct drm_encoder *encoder, u32 offset)
309930a9785SAlex Deucher {
310930a9785SAlex Deucher 	struct drm_device *dev = encoder->dev;
311930a9785SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
312930a9785SAlex Deucher 
313930a9785SAlex Deucher 	WREG32(HDMI_VBI_PACKET_CONTROL + offset,
314930a9785SAlex Deucher 		HDMI_NULL_SEND |	/* send null packets when required */
315930a9785SAlex Deucher 		HDMI_GC_SEND |		/* send general control packets */
316930a9785SAlex Deucher 		HDMI_GC_CONT);		/* send general control packets every frame */
317930a9785SAlex Deucher }
318930a9785SAlex Deucher 
dce4_hdmi_set_color_depth(struct drm_encoder * encoder,u32 offset,int bpc)319be273e58SSlava Grigorev void dce4_hdmi_set_color_depth(struct drm_encoder *encoder, u32 offset, int bpc)
320e55d3e6cSRafał Miłecki {
321e55d3e6cSRafał Miłecki 	struct drm_device *dev = encoder->dev;
322e55d3e6cSRafał Miłecki 	struct radeon_device *rdev = dev->dev_private;
32379766915SAlex Deucher 	struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
3247b555e06SAlex Deucher 	uint32_t val;
325e55d3e6cSRafał Miłecki 
3267b555e06SAlex Deucher 	val = RREG32(HDMI_CONTROL + offset);
3277b555e06SAlex Deucher 	val &= ~HDMI_DEEP_COLOR_ENABLE;
3287b555e06SAlex Deucher 	val &= ~HDMI_DEEP_COLOR_DEPTH_MASK;
3297b555e06SAlex Deucher 
3307b555e06SAlex Deucher 	switch (bpc) {
3317b555e06SAlex Deucher 		case 0:
3327b555e06SAlex Deucher 		case 6:
3337b555e06SAlex Deucher 		case 8:
3347b555e06SAlex Deucher 		case 16:
3357b555e06SAlex Deucher 		default:
3367b555e06SAlex Deucher 			DRM_DEBUG("%s: Disabling hdmi deep color for %d bpc.\n",
33772082093SJani Nikula 					 connector->name, bpc);
3387b555e06SAlex Deucher 			break;
3397b555e06SAlex Deucher 		case 10:
3407b555e06SAlex Deucher 			val |= HDMI_DEEP_COLOR_ENABLE;
3417b555e06SAlex Deucher 			val |= HDMI_DEEP_COLOR_DEPTH(HDMI_30BIT_DEEP_COLOR);
3427b555e06SAlex Deucher 			DRM_DEBUG("%s: Enabling hdmi deep color 30 for 10 bpc.\n",
34372082093SJani Nikula 					 connector->name);
3447b555e06SAlex Deucher 			break;
3457b555e06SAlex Deucher 		case 12:
3467b555e06SAlex Deucher 			val |= HDMI_DEEP_COLOR_ENABLE;
3477b555e06SAlex Deucher 			val |= HDMI_DEEP_COLOR_DEPTH(HDMI_36BIT_DEEP_COLOR);
3487b555e06SAlex Deucher 			DRM_DEBUG("%s: Enabling hdmi deep color 36 for 12 bpc.\n",
34972082093SJani Nikula 					 connector->name);
3507b555e06SAlex Deucher 			break;
3517b555e06SAlex Deucher 	}
3527b555e06SAlex Deucher 
3537b555e06SAlex Deucher 	WREG32(HDMI_CONTROL + offset, val);
354be273e58SSlava Grigorev }
355be273e58SSlava Grigorev 
dce4_set_audio_packet(struct drm_encoder * encoder,u32 offset)3561852c9a0SSlava Grigorev void dce4_set_audio_packet(struct drm_encoder *encoder, u32 offset)
3571852c9a0SSlava Grigorev {
3581852c9a0SSlava Grigorev 	struct drm_device *dev = encoder->dev;
3591852c9a0SSlava Grigorev 	struct radeon_device *rdev = dev->dev_private;
3601852c9a0SSlava Grigorev 
3611852c9a0SSlava Grigorev 	WREG32(AFMT_INFOFRAME_CONTROL0 + offset,
3621852c9a0SSlava Grigorev 		AFMT_AUDIO_INFO_UPDATE); /* required for audio info values to be updated */
3631852c9a0SSlava Grigorev 
3641852c9a0SSlava Grigorev 	WREG32(AFMT_60958_0 + offset,
3651852c9a0SSlava Grigorev 		AFMT_60958_CS_CHANNEL_NUMBER_L(1));
3661852c9a0SSlava Grigorev 
3671852c9a0SSlava Grigorev 	WREG32(AFMT_60958_1 + offset,
3681852c9a0SSlava Grigorev 		AFMT_60958_CS_CHANNEL_NUMBER_R(2));
3691852c9a0SSlava Grigorev 
3701852c9a0SSlava Grigorev 	WREG32(AFMT_60958_2 + offset,
3711852c9a0SSlava Grigorev 		AFMT_60958_CS_CHANNEL_NUMBER_2(3) |
3721852c9a0SSlava Grigorev 		AFMT_60958_CS_CHANNEL_NUMBER_3(4) |
3731852c9a0SSlava Grigorev 		AFMT_60958_CS_CHANNEL_NUMBER_4(5) |
3741852c9a0SSlava Grigorev 		AFMT_60958_CS_CHANNEL_NUMBER_5(6) |
3751852c9a0SSlava Grigorev 		AFMT_60958_CS_CHANNEL_NUMBER_6(7) |
3761852c9a0SSlava Grigorev 		AFMT_60958_CS_CHANNEL_NUMBER_7(8));
3771852c9a0SSlava Grigorev 
3781852c9a0SSlava Grigorev 	WREG32(AFMT_AUDIO_PACKET_CONTROL2 + offset,
3791852c9a0SSlava Grigorev 		AFMT_AUDIO_CHANNEL_ENABLE(0xff));
3801852c9a0SSlava Grigorev 
381362ff251SAlex Deucher 	WREG32(HDMI_AUDIO_PACKET_CONTROL + offset,
382362ff251SAlex Deucher 	       HDMI_AUDIO_DELAY_EN(1) | /* set the default audio delay */
383362ff251SAlex Deucher 	       HDMI_AUDIO_PACKETS_PER_LINE(3)); /* should be suffient for all audio modes and small enough for all hblanks */
384362ff251SAlex Deucher 
3851852c9a0SSlava Grigorev 	/* allow 60958 channel status and send audio packets fields to be updated */
386362ff251SAlex Deucher 	WREG32_OR(AFMT_AUDIO_PACKET_CONTROL + offset,
387362ff251SAlex Deucher 		  AFMT_RESET_FIFO_WHEN_AUDIO_DIS | AFMT_60958_CS_UPDATE);
3881852c9a0SSlava Grigorev }
3891852c9a0SSlava Grigorev 
3903be2e7d0SSlava Grigorev 
dce4_set_mute(struct drm_encoder * encoder,u32 offset,bool mute)3913be2e7d0SSlava Grigorev void dce4_set_mute(struct drm_encoder *encoder, u32 offset, bool mute)
3923be2e7d0SSlava Grigorev {
3933be2e7d0SSlava Grigorev 	struct drm_device *dev = encoder->dev;
3943be2e7d0SSlava Grigorev 	struct radeon_device *rdev = dev->dev_private;
3953be2e7d0SSlava Grigorev 
3963be2e7d0SSlava Grigorev 	if (mute)
3973be2e7d0SSlava Grigorev 		WREG32_OR(HDMI_GC + offset, HDMI_GC_AVMUTE);
3983be2e7d0SSlava Grigorev 	else
3993be2e7d0SSlava Grigorev 		WREG32_AND(HDMI_GC + offset, ~HDMI_GC_AVMUTE);
4003be2e7d0SSlava Grigorev }
4013be2e7d0SSlava Grigorev 
evergreen_hdmi_enable(struct drm_encoder * encoder,bool enable)402a973bea1SAlex Deucher void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable)
403a973bea1SAlex Deucher {
4044adb34efSAlex Deucher 	struct drm_device *dev = encoder->dev;
4054adb34efSAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
406a973bea1SAlex Deucher 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
407a973bea1SAlex Deucher 	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
408a973bea1SAlex Deucher 
409c2b4cacfSAlex Deucher 	if (!dig || !dig->afmt)
410c2b4cacfSAlex Deucher 		return;
411c2b4cacfSAlex Deucher 
412add7d759SAlex Deucher 	if (enable) {
41338aef154SAlex Deucher 		struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
41438aef154SAlex Deucher 
415*242136edSJani Nikula 		if (connector && connector->display_info.has_audio) {
416add7d759SAlex Deucher 			WREG32(HDMI_INFOFRAME_CONTROL0 + dig->afmt->offset,
417362ff251SAlex Deucher 			       HDMI_AVI_INFO_SEND | /* enable AVI info frames */
418362ff251SAlex Deucher 			       HDMI_AVI_INFO_CONT | /* required for audio info values to be updated */
419add7d759SAlex Deucher 			       HDMI_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */
420add7d759SAlex Deucher 			       HDMI_AUDIO_INFO_CONT); /* required for audio info values to be updated */
421362ff251SAlex Deucher 			WREG32_OR(AFMT_AUDIO_PACKET_CONTROL + dig->afmt->offset,
422362ff251SAlex Deucher 				  AFMT_AUDIO_SAMPLE_SEND);
423add7d759SAlex Deucher 		} else {
42438aef154SAlex Deucher 			WREG32(HDMI_INFOFRAME_CONTROL0 + dig->afmt->offset,
42538aef154SAlex Deucher 			       HDMI_AVI_INFO_SEND | /* enable AVI info frames */
42638aef154SAlex Deucher 			       HDMI_AVI_INFO_CONT); /* required for audio info values to be updated */
42738aef154SAlex Deucher 			WREG32_AND(AFMT_AUDIO_PACKET_CONTROL + dig->afmt->offset,
42838aef154SAlex Deucher 				   ~AFMT_AUDIO_SAMPLE_SEND);
42938aef154SAlex Deucher 		}
43038aef154SAlex Deucher 	} else {
431362ff251SAlex Deucher 		WREG32_AND(AFMT_AUDIO_PACKET_CONTROL + dig->afmt->offset,
432362ff251SAlex Deucher 			   ~AFMT_AUDIO_SAMPLE_SEND);
433add7d759SAlex Deucher 		WREG32(HDMI_INFOFRAME_CONTROL0 + dig->afmt->offset, 0);
4344adb34efSAlex Deucher 	}
4354adb34efSAlex Deucher 
436a973bea1SAlex Deucher 	dig->afmt->enabled = enable;
437a973bea1SAlex Deucher 
438a973bea1SAlex Deucher 	DRM_DEBUG("%sabling HDMI interface @ 0x%04X for encoder 0x%x\n",
439a973bea1SAlex Deucher 		  enable ? "En" : "Dis", dig->afmt->offset, radeon_encoder->encoder_id);
440a973bea1SAlex Deucher }
441e55bca26SSlava Grigorev 
evergreen_dp_enable(struct drm_encoder * encoder,bool enable)442add7d759SAlex Deucher void evergreen_dp_enable(struct drm_encoder *encoder, bool enable)
443e55bca26SSlava Grigorev {
444e55bca26SSlava Grigorev 	struct drm_device *dev = encoder->dev;
445e55bca26SSlava Grigorev 	struct radeon_device *rdev = dev->dev_private;
446e55bca26SSlava Grigorev 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
447e55bca26SSlava Grigorev 	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
44838aef154SAlex Deucher 	struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
449e55bca26SSlava Grigorev 
450e55bca26SSlava Grigorev 	if (!dig || !dig->afmt)
451e55bca26SSlava Grigorev 		return;
452e55bca26SSlava Grigorev 
453*242136edSJani Nikula 	if (enable && connector && connector->display_info.has_audio) {
454e55bca26SSlava Grigorev 		struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
455e55bca26SSlava Grigorev 		struct radeon_connector *radeon_connector = to_radeon_connector(connector);
456e55bca26SSlava Grigorev 		struct radeon_connector_atom_dig *dig_connector;
457e55bca26SSlava Grigorev 		uint32_t val;
458e55bca26SSlava Grigorev 
459362ff251SAlex Deucher 		WREG32_OR(AFMT_AUDIO_PACKET_CONTROL + dig->afmt->offset,
460362ff251SAlex Deucher 			  AFMT_AUDIO_SAMPLE_SEND);
461362ff251SAlex Deucher 
462add7d759SAlex Deucher 		WREG32(EVERGREEN_DP_SEC_TIMESTAMP + dig->afmt->offset,
463add7d759SAlex Deucher 		       EVERGREEN_DP_SEC_TIMESTAMP_MODE(1));
464e55bca26SSlava Grigorev 
46512428327SAlex Deucher 		if (!ASIC_IS_DCE6(rdev) && radeon_connector->con_priv) {
466e55bca26SSlava Grigorev 			dig_connector = radeon_connector->con_priv;
467add7d759SAlex Deucher 			val = RREG32(EVERGREEN_DP_SEC_AUD_N + dig->afmt->offset);
468e55bca26SSlava Grigorev 			val &= ~EVERGREEN_DP_SEC_N_BASE_MULTIPLE(0xf);
469e55bca26SSlava Grigorev 
470e55bca26SSlava Grigorev 			if (dig_connector->dp_clock == 162000)
471e55bca26SSlava Grigorev 				val |= EVERGREEN_DP_SEC_N_BASE_MULTIPLE(3);
472e55bca26SSlava Grigorev 			else
473e55bca26SSlava Grigorev 				val |= EVERGREEN_DP_SEC_N_BASE_MULTIPLE(5);
474e55bca26SSlava Grigorev 
475add7d759SAlex Deucher 			WREG32(EVERGREEN_DP_SEC_AUD_N + dig->afmt->offset, val);
476e55bca26SSlava Grigorev 		}
477e55bca26SSlava Grigorev 
478add7d759SAlex Deucher 		WREG32(EVERGREEN_DP_SEC_CNTL + dig->afmt->offset,
479e55bca26SSlava Grigorev 			EVERGREEN_DP_SEC_ASP_ENABLE |		/* Audio packet transmission */
480e55bca26SSlava Grigorev 			EVERGREEN_DP_SEC_ATP_ENABLE |		/* Audio timestamp packet transmission */
481e55bca26SSlava Grigorev 			EVERGREEN_DP_SEC_AIP_ENABLE |		/* Audio infoframe packet transmission */
482e55bca26SSlava Grigorev 			EVERGREEN_DP_SEC_STREAM_ENABLE);	/* Master enable for secondary stream engine */
483e55bca26SSlava Grigorev 	} else {
484add7d759SAlex Deucher 		WREG32(EVERGREEN_DP_SEC_CNTL + dig->afmt->offset, 0);
485362ff251SAlex Deucher 		WREG32_AND(AFMT_AUDIO_PACKET_CONTROL + dig->afmt->offset,
486362ff251SAlex Deucher 			   ~AFMT_AUDIO_SAMPLE_SEND);
487e55bca26SSlava Grigorev 	}
488e55bca26SSlava Grigorev 
489e55bca26SSlava Grigorev 	dig->afmt->enabled = enable;
490e55bca26SSlava Grigorev }
491