xref: /linux/drivers/gpu/drm/radeon/evergreen_hdmi.c (revision 3be2e7d0e705621c1bb41eeabb63b122d50ecff3)
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>
28760285e7SDavid Howells #include <drm/drmP.h>
29760285e7SDavid Howells #include <drm/radeon_drm.h>
30e55d3e6cSRafał Miłecki #include "radeon.h"
31e55d3e6cSRafał Miłecki #include "radeon_asic.h"
32070a2e63SAlex Deucher #include "radeon_audio.h"
33e55d3e6cSRafał Miłecki #include "evergreend.h"
34e55d3e6cSRafał Miłecki #include "atom.h"
35e55d3e6cSRafał Miłecki 
36d3d8c141SAlex Deucher /* enable the audio stream */
378bf59820SSlava Grigorev void dce4_audio_enable(struct radeon_device *rdev,
38d3d8c141SAlex Deucher 			      struct r600_audio_pin *pin,
39d3d8c141SAlex Deucher 			      u8 enable_mask)
40d3d8c141SAlex Deucher {
41d3d8c141SAlex Deucher 	u32 tmp = RREG32(AZ_HOT_PLUG_CONTROL);
42d3d8c141SAlex Deucher 
43d3d8c141SAlex Deucher 	if (!pin)
44d3d8c141SAlex Deucher 		return;
45d3d8c141SAlex Deucher 
46d3d8c141SAlex Deucher 	if (enable_mask) {
47d3d8c141SAlex Deucher 		tmp |= AUDIO_ENABLED;
48d3d8c141SAlex Deucher 		if (enable_mask & 1)
49d3d8c141SAlex Deucher 			tmp |= PIN0_AUDIO_ENABLED;
50d3d8c141SAlex Deucher 		if (enable_mask & 2)
51d3d8c141SAlex Deucher 			tmp |= PIN1_AUDIO_ENABLED;
52d3d8c141SAlex Deucher 		if (enable_mask & 4)
53d3d8c141SAlex Deucher 			tmp |= PIN2_AUDIO_ENABLED;
54d3d8c141SAlex Deucher 		if (enable_mask & 8)
55d3d8c141SAlex Deucher 			tmp |= PIN3_AUDIO_ENABLED;
56d3d8c141SAlex Deucher 	} else {
57d3d8c141SAlex Deucher 		tmp &= ~(AUDIO_ENABLED |
58d3d8c141SAlex Deucher 			 PIN0_AUDIO_ENABLED |
59d3d8c141SAlex Deucher 			 PIN1_AUDIO_ENABLED |
60d3d8c141SAlex Deucher 			 PIN2_AUDIO_ENABLED |
61d3d8c141SAlex Deucher 			 PIN3_AUDIO_ENABLED);
62d3d8c141SAlex Deucher 	}
63d3d8c141SAlex Deucher 
64d3d8c141SAlex Deucher 	WREG32(AZ_HOT_PLUG_CONTROL, tmp);
65d3d8c141SAlex Deucher }
66d3d8c141SAlex Deucher 
6764424d6eSSlava Grigorev void evergreen_hdmi_update_acr(struct drm_encoder *encoder, long offset,
6864424d6eSSlava Grigorev 	const struct radeon_hdmi_acr *acr)
69e55d3e6cSRafał Miłecki {
70e55d3e6cSRafał Miłecki 	struct drm_device *dev = encoder->dev;
71e55d3e6cSRafał Miłecki 	struct radeon_device *rdev = dev->dev_private;
7264424d6eSSlava Grigorev 	int bpc = 8;
73e55d3e6cSRafał Miłecki 
7464424d6eSSlava Grigorev 	if (encoder->crtc) {
7564424d6eSSlava Grigorev 		struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
7664424d6eSSlava Grigorev 		bpc = radeon_crtc->bpc;
7764424d6eSSlava Grigorev 	}
78e55d3e6cSRafał Miłecki 
7964424d6eSSlava Grigorev 	if (bpc > 8)
8064424d6eSSlava Grigorev 		WREG32(HDMI_ACR_PACKET_CONTROL + offset,
8164424d6eSSlava Grigorev 			HDMI_ACR_AUTO_SEND);	/* allow hw to sent ACR packets when required */
8264424d6eSSlava Grigorev 	else
8364424d6eSSlava Grigorev 		WREG32(HDMI_ACR_PACKET_CONTROL + offset,
8464424d6eSSlava Grigorev 			HDMI_ACR_SOURCE |		/* select SW CTS value */
8564424d6eSSlava Grigorev 			HDMI_ACR_AUTO_SEND);	/* allow hw to sent ACR packets when required */
86e55d3e6cSRafał Miłecki 
8764424d6eSSlava Grigorev 	WREG32(HDMI_ACR_32_0 + offset, HDMI_ACR_CTS_32(acr->cts_32khz));
8864424d6eSSlava Grigorev 	WREG32(HDMI_ACR_32_1 + offset, acr->n_32khz);
8964424d6eSSlava Grigorev 
9064424d6eSSlava Grigorev 	WREG32(HDMI_ACR_44_0 + offset, HDMI_ACR_CTS_44(acr->cts_44_1khz));
9164424d6eSSlava Grigorev 	WREG32(HDMI_ACR_44_1 + offset, acr->n_44_1khz);
9264424d6eSSlava Grigorev 
9364424d6eSSlava Grigorev 	WREG32(HDMI_ACR_48_0 + offset, HDMI_ACR_CTS_48(acr->cts_48khz));
9464424d6eSSlava Grigorev 	WREG32(HDMI_ACR_48_1 + offset, acr->n_48khz);
95e55d3e6cSRafał Miłecki }
96e55d3e6cSRafał Miłecki 
9787654f87SSlava Grigorev void dce4_afmt_write_latency_fields(struct drm_encoder *encoder,
9887654f87SSlava Grigorev 		struct drm_connector *connector, struct drm_display_mode *mode)
99712fd8a2SAlex Deucher {
100712fd8a2SAlex Deucher 	struct radeon_device *rdev = encoder->dev->dev_private;
101712fd8a2SAlex Deucher 	u32 tmp = 0;
102712fd8a2SAlex Deucher 
103712fd8a2SAlex Deucher 	if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
104712fd8a2SAlex Deucher 		if (connector->latency_present[1])
105712fd8a2SAlex Deucher 			tmp = VIDEO_LIPSYNC(connector->video_latency[1]) |
106712fd8a2SAlex Deucher 				AUDIO_LIPSYNC(connector->audio_latency[1]);
107712fd8a2SAlex Deucher 		else
108712fd8a2SAlex Deucher 			tmp = VIDEO_LIPSYNC(255) | AUDIO_LIPSYNC(255);
109712fd8a2SAlex Deucher 	} else {
110712fd8a2SAlex Deucher 		if (connector->latency_present[0])
111712fd8a2SAlex Deucher 			tmp = VIDEO_LIPSYNC(connector->video_latency[0]) |
112712fd8a2SAlex Deucher 				AUDIO_LIPSYNC(connector->audio_latency[0]);
113712fd8a2SAlex Deucher 		else
114712fd8a2SAlex Deucher 			tmp = VIDEO_LIPSYNC(255) | AUDIO_LIPSYNC(255);
115712fd8a2SAlex Deucher 	}
11687654f87SSlava Grigorev 	WREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_RESPONSE_LIPSYNC, tmp);
117712fd8a2SAlex Deucher }
118712fd8a2SAlex Deucher 
11900a9d4bcSSlava Grigorev void dce4_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder,
12000a9d4bcSSlava Grigorev 	u8 *sadb, int sad_count)
121ba7def4fSAlex Deucher {
122ba7def4fSAlex Deucher 	struct radeon_device *rdev = encoder->dev->dev_private;
123ba7def4fSAlex Deucher 	u32 tmp;
124ba7def4fSAlex Deucher 
125ba7def4fSAlex Deucher 	/* program the speaker allocation */
12600a9d4bcSSlava Grigorev 	tmp = RREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER);
127ba7def4fSAlex Deucher 	tmp &= ~(DP_CONNECTION | SPEAKER_ALLOCATION_MASK);
128ba7def4fSAlex Deucher 	/* set HDMI mode */
129ba7def4fSAlex Deucher 	tmp |= HDMI_CONNECTION;
130ba7def4fSAlex Deucher 	if (sad_count)
131ba7def4fSAlex Deucher 		tmp |= SPEAKER_ALLOCATION(sadb[0]);
132ba7def4fSAlex Deucher 	else
133ba7def4fSAlex Deucher 		tmp |= SPEAKER_ALLOCATION(5); /* stereo */
13400a9d4bcSSlava Grigorev 	WREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER, tmp);
13500a9d4bcSSlava Grigorev }
136ba7def4fSAlex Deucher 
13700a9d4bcSSlava Grigorev void dce4_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder,
13800a9d4bcSSlava Grigorev 	u8 *sadb, int sad_count)
13900a9d4bcSSlava Grigorev {
14000a9d4bcSSlava Grigorev 	struct radeon_device *rdev = encoder->dev->dev_private;
14100a9d4bcSSlava Grigorev 	u32 tmp;
14200a9d4bcSSlava Grigorev 
14300a9d4bcSSlava Grigorev 	/* program the speaker allocation */
14400a9d4bcSSlava Grigorev 	tmp = RREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER);
14500a9d4bcSSlava Grigorev 	tmp &= ~(HDMI_CONNECTION | SPEAKER_ALLOCATION_MASK);
14600a9d4bcSSlava Grigorev 	/* set DP mode */
14700a9d4bcSSlava Grigorev 	tmp |= DP_CONNECTION;
14800a9d4bcSSlava Grigorev 	if (sad_count)
14900a9d4bcSSlava Grigorev 		tmp |= SPEAKER_ALLOCATION(sadb[0]);
15000a9d4bcSSlava Grigorev 	else
15100a9d4bcSSlava Grigorev 		tmp |= SPEAKER_ALLOCATION(5); /* stereo */
15200a9d4bcSSlava Grigorev 	WREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER, tmp);
153ba7def4fSAlex Deucher }
154ba7def4fSAlex Deucher 
155070a2e63SAlex Deucher void evergreen_hdmi_write_sad_regs(struct drm_encoder *encoder,
156070a2e63SAlex Deucher 	struct cea_sad *sads, int sad_count)
15746892caaSRafał Miłecki {
158070a2e63SAlex Deucher 	int i;
15946892caaSRafał Miłecki 	struct radeon_device *rdev = encoder->dev->dev_private;
16046892caaSRafał Miłecki 	static const u16 eld_reg_to_type[][2] = {
16146892caaSRafał Miłecki 		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR0, HDMI_AUDIO_CODING_TYPE_PCM },
16246892caaSRafał Miłecki 		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR1, HDMI_AUDIO_CODING_TYPE_AC3 },
16346892caaSRafał Miłecki 		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR2, HDMI_AUDIO_CODING_TYPE_MPEG1 },
16446892caaSRafał Miłecki 		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR3, HDMI_AUDIO_CODING_TYPE_MP3 },
16546892caaSRafał Miłecki 		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR4, HDMI_AUDIO_CODING_TYPE_MPEG2 },
16646892caaSRafał Miłecki 		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR5, HDMI_AUDIO_CODING_TYPE_AAC_LC },
16746892caaSRafał Miłecki 		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR6, HDMI_AUDIO_CODING_TYPE_DTS },
16846892caaSRafał Miłecki 		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR7, HDMI_AUDIO_CODING_TYPE_ATRAC },
16946892caaSRafał Miłecki 		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR9, HDMI_AUDIO_CODING_TYPE_EAC3 },
17046892caaSRafał Miłecki 		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR10, HDMI_AUDIO_CODING_TYPE_DTS_HD },
17146892caaSRafał Miłecki 		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR11, HDMI_AUDIO_CODING_TYPE_MLP },
17246892caaSRafał Miłecki 		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR13, HDMI_AUDIO_CODING_TYPE_WMA_PRO },
17346892caaSRafał Miłecki 	};
17446892caaSRafał Miłecki 
17546892caaSRafał Miłecki 	for (i = 0; i < ARRAY_SIZE(eld_reg_to_type); i++) {
17646892caaSRafał Miłecki 		u32 value = 0;
1770f57bca9SAnssi Hannula 		u8 stereo_freqs = 0;
1780f57bca9SAnssi Hannula 		int max_channels = -1;
17946892caaSRafał Miłecki 		int j;
18046892caaSRafał Miłecki 
18146892caaSRafał Miłecki 		for (j = 0; j < sad_count; j++) {
18246892caaSRafał Miłecki 			struct cea_sad *sad = &sads[j];
18346892caaSRafał Miłecki 
18446892caaSRafał Miłecki 			if (sad->format == eld_reg_to_type[i][1]) {
1850f57bca9SAnssi Hannula 				if (sad->channels > max_channels) {
18646892caaSRafał Miłecki 					value = MAX_CHANNELS(sad->channels) |
18746892caaSRafał Miłecki 						DESCRIPTOR_BYTE_2(sad->byte2) |
18846892caaSRafał Miłecki 						SUPPORTED_FREQUENCIES(sad->freq);
1890f57bca9SAnssi Hannula 					max_channels = sad->channels;
1900f57bca9SAnssi Hannula 				}
1910f57bca9SAnssi Hannula 
19246892caaSRafał Miłecki 				if (sad->format == HDMI_AUDIO_CODING_TYPE_PCM)
1930f57bca9SAnssi Hannula 					stereo_freqs |= sad->freq;
1940f57bca9SAnssi Hannula 				else
19546892caaSRafał Miłecki 					break;
19646892caaSRafał Miłecki 			}
19746892caaSRafał Miłecki 		}
1980f57bca9SAnssi Hannula 
1990f57bca9SAnssi Hannula 		value |= SUPPORTED_FREQUENCIES_STEREO(stereo_freqs);
2000f57bca9SAnssi Hannula 
201070a2e63SAlex Deucher 		WREG32_ENDPOINT(0, eld_reg_to_type[i][0], value);
20246892caaSRafał Miłecki 	}
20346892caaSRafał Miłecki }
20446892caaSRafał Miłecki 
205e55d3e6cSRafał Miłecki /*
20696ea7afbSSlava Grigorev  * build a AVI Info Frame
207e55d3e6cSRafał Miłecki  */
208baa7d8e4SSlava Grigorev void evergreen_set_avi_packet(struct radeon_device *rdev, u32 offset,
20996ea7afbSSlava Grigorev     unsigned char *buffer, size_t size)
210e55d3e6cSRafał Miłecki {
211e3b2e034SThierry Reding 	uint8_t *frame = buffer + 3;
212e55d3e6cSRafał Miłecki 
213e55d3e6cSRafał Miłecki 	WREG32(AFMT_AVI_INFO0 + offset,
214e55d3e6cSRafał Miłecki 		frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24));
215e55d3e6cSRafał Miłecki 	WREG32(AFMT_AVI_INFO1 + offset,
216e55d3e6cSRafał Miłecki 		frame[0x4] | (frame[0x5] << 8) | (frame[0x6] << 16) | (frame[0x7] << 24));
217e55d3e6cSRafał Miłecki 	WREG32(AFMT_AVI_INFO2 + offset,
218e55d3e6cSRafał Miłecki 		frame[0x8] | (frame[0x9] << 8) | (frame[0xA] << 16) | (frame[0xB] << 24));
219e55d3e6cSRafał Miłecki 	WREG32(AFMT_AVI_INFO3 + offset,
22096ea7afbSSlava Grigorev 		frame[0xC] | (frame[0xD] << 8) | (buffer[1] << 24));
221baa7d8e4SSlava Grigorev 
222baa7d8e4SSlava Grigorev 	WREG32_OR(HDMI_INFOFRAME_CONTROL0 + offset,
223baa7d8e4SSlava Grigorev 		HDMI_AVI_INFO_SEND |	/* enable AVI info frames */
224baa7d8e4SSlava Grigorev 		HDMI_AVI_INFO_CONT);	/* required for audio info values to be updated */
225baa7d8e4SSlava Grigorev 
226baa7d8e4SSlava Grigorev 	WREG32_P(HDMI_INFOFRAME_CONTROL1 + offset,
227baa7d8e4SSlava Grigorev 		HDMI_AVI_INFO_LINE(2),	/* anything other than 0 */
228baa7d8e4SSlava Grigorev 		~HDMI_AVI_INFO_LINE_MASK);
229e55d3e6cSRafał Miłecki }
230e55d3e6cSRafał Miłecki 
231a85d682aSSlava Grigorev void dce4_hdmi_audio_set_dto(struct radeon_device *rdev,
232a85d682aSSlava Grigorev 	struct radeon_crtc *crtc, unsigned int clock)
233b1f6f47eSAlex Deucher {
234a85d682aSSlava Grigorev 	unsigned int max_ratio = clock / 24000;
2351518dd8eSAlex Deucher 	u32 dto_phase;
2361518dd8eSAlex Deucher 	u32 wallclock_ratio;
237a85d682aSSlava Grigorev 	u32 value;
238b1f6f47eSAlex Deucher 
2391518dd8eSAlex Deucher 	if (max_ratio >= 8) {
2401518dd8eSAlex Deucher 		dto_phase = 192 * 1000;
2411518dd8eSAlex Deucher 		wallclock_ratio = 3;
2421518dd8eSAlex Deucher 	} else if (max_ratio >= 4) {
2431518dd8eSAlex Deucher 		dto_phase = 96 * 1000;
2441518dd8eSAlex Deucher 		wallclock_ratio = 2;
2451518dd8eSAlex Deucher 	} else if (max_ratio >= 2) {
2461518dd8eSAlex Deucher 		dto_phase = 48 * 1000;
2471518dd8eSAlex Deucher 		wallclock_ratio = 1;
2481518dd8eSAlex Deucher 	} else {
2491518dd8eSAlex Deucher 		dto_phase = 24 * 1000;
2501518dd8eSAlex Deucher 		wallclock_ratio = 0;
2511518dd8eSAlex Deucher 	}
2521518dd8eSAlex Deucher 
253a85d682aSSlava Grigorev 	value = RREG32(DCCG_AUDIO_DTO0_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK;
254a85d682aSSlava Grigorev 	value |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio);
255a85d682aSSlava Grigorev 	value &= ~DCCG_AUDIO_DTO1_USE_512FBR_DTO;
256a85d682aSSlava Grigorev 	WREG32(DCCG_AUDIO_DTO0_CNTL, value);
257a85d682aSSlava Grigorev 
258a85d682aSSlava Grigorev 	/* Two dtos; generally use dto0 for HDMI */
259a85d682aSSlava Grigorev 	value = 0;
260a85d682aSSlava Grigorev 
261a85d682aSSlava Grigorev 	if (crtc)
262a85d682aSSlava Grigorev 		value |= DCCG_AUDIO_DTO0_SOURCE_SEL(crtc->crtc_id);
263a85d682aSSlava Grigorev 
264a85d682aSSlava Grigorev 	WREG32(DCCG_AUDIO_DTO_SOURCE, value);
265a85d682aSSlava Grigorev 
266b1f6f47eSAlex Deucher 	/* Express [24MHz / target pixel clock] as an exact rational
267b1f6f47eSAlex Deucher 	 * number (coefficient of two integer numbers.  DCCG_AUDIO_DTOx_PHASE
268b1f6f47eSAlex Deucher 	 * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
269b1f6f47eSAlex Deucher 	 */
2701518dd8eSAlex Deucher 	WREG32(DCCG_AUDIO_DTO0_PHASE, dto_phase);
271a85d682aSSlava Grigorev 	WREG32(DCCG_AUDIO_DTO0_MODULE, clock);
272b1f6f47eSAlex Deucher }
273b1f6f47eSAlex Deucher 
274a85d682aSSlava Grigorev void dce4_dp_audio_set_dto(struct radeon_device *rdev,
275a85d682aSSlava Grigorev 	struct radeon_crtc *crtc, unsigned int clock)
276a85d682aSSlava Grigorev {
277a85d682aSSlava Grigorev 	u32 value;
278a85d682aSSlava Grigorev 
279a85d682aSSlava Grigorev 	value = RREG32(DCCG_AUDIO_DTO1_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK;
280a85d682aSSlava Grigorev 	value |= DCCG_AUDIO_DTO1_USE_512FBR_DTO;
281a85d682aSSlava Grigorev 	WREG32(DCCG_AUDIO_DTO1_CNTL, value);
282a85d682aSSlava Grigorev 
283a85d682aSSlava Grigorev 	/* Two dtos; generally use dto1 for DP */
284a85d682aSSlava Grigorev 	value = 0;
285a85d682aSSlava Grigorev 	value |= DCCG_AUDIO_DTO_SEL;
286a85d682aSSlava Grigorev 
287a85d682aSSlava Grigorev 	if (crtc)
288a85d682aSSlava Grigorev 		value |= DCCG_AUDIO_DTO0_SOURCE_SEL(crtc->crtc_id);
289a85d682aSSlava Grigorev 
290a85d682aSSlava Grigorev 	WREG32(DCCG_AUDIO_DTO_SOURCE, value);
291a85d682aSSlava Grigorev 
292a85d682aSSlava Grigorev 	/* Express [24MHz / target pixel clock] as an exact rational
293a85d682aSSlava Grigorev 	 * number (coefficient of two integer numbers.  DCCG_AUDIO_DTOx_PHASE
294a85d682aSSlava Grigorev 	 * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
295a85d682aSSlava Grigorev 	 */
296a85d682aSSlava Grigorev 	WREG32(DCCG_AUDIO_DTO1_PHASE, 24000);
297a85d682aSSlava Grigorev 	WREG32(DCCG_AUDIO_DTO1_MODULE, rdev->clock.max_pixel_clock * 10);
298a85d682aSSlava Grigorev }
299b1f6f47eSAlex Deucher 
300930a9785SAlex Deucher void dce4_set_vbi_packet(struct drm_encoder *encoder, u32 offset)
301930a9785SAlex Deucher {
302930a9785SAlex Deucher 	struct drm_device *dev = encoder->dev;
303930a9785SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
304930a9785SAlex Deucher 
305930a9785SAlex Deucher 	WREG32(HDMI_VBI_PACKET_CONTROL + offset,
306930a9785SAlex Deucher 		HDMI_NULL_SEND |	/* send null packets when required */
307930a9785SAlex Deucher 		HDMI_GC_SEND |		/* send general control packets */
308930a9785SAlex Deucher 		HDMI_GC_CONT);		/* send general control packets every frame */
309930a9785SAlex Deucher }
310930a9785SAlex Deucher 
311be273e58SSlava Grigorev void dce4_hdmi_set_color_depth(struct drm_encoder *encoder, u32 offset, int bpc)
312e55d3e6cSRafał Miłecki {
313e55d3e6cSRafał Miłecki 	struct drm_device *dev = encoder->dev;
314e55d3e6cSRafał Miłecki 	struct radeon_device *rdev = dev->dev_private;
31579766915SAlex Deucher 	struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
3167b555e06SAlex Deucher 	uint32_t val;
317e55d3e6cSRafał Miłecki 
3187b555e06SAlex Deucher 	val = RREG32(HDMI_CONTROL + offset);
3197b555e06SAlex Deucher 	val &= ~HDMI_DEEP_COLOR_ENABLE;
3207b555e06SAlex Deucher 	val &= ~HDMI_DEEP_COLOR_DEPTH_MASK;
3217b555e06SAlex Deucher 
3227b555e06SAlex Deucher 	switch (bpc) {
3237b555e06SAlex Deucher 		case 0:
3247b555e06SAlex Deucher 		case 6:
3257b555e06SAlex Deucher 		case 8:
3267b555e06SAlex Deucher 		case 16:
3277b555e06SAlex Deucher 		default:
3287b555e06SAlex Deucher 			DRM_DEBUG("%s: Disabling hdmi deep color for %d bpc.\n",
32972082093SJani Nikula 					 connector->name, bpc);
3307b555e06SAlex Deucher 			break;
3317b555e06SAlex Deucher 		case 10:
3327b555e06SAlex Deucher 			val |= HDMI_DEEP_COLOR_ENABLE;
3337b555e06SAlex Deucher 			val |= HDMI_DEEP_COLOR_DEPTH(HDMI_30BIT_DEEP_COLOR);
3347b555e06SAlex Deucher 			DRM_DEBUG("%s: Enabling hdmi deep color 30 for 10 bpc.\n",
33572082093SJani Nikula 					 connector->name);
3367b555e06SAlex Deucher 			break;
3377b555e06SAlex Deucher 		case 12:
3387b555e06SAlex Deucher 			val |= HDMI_DEEP_COLOR_ENABLE;
3397b555e06SAlex Deucher 			val |= HDMI_DEEP_COLOR_DEPTH(HDMI_36BIT_DEEP_COLOR);
3407b555e06SAlex Deucher 			DRM_DEBUG("%s: Enabling hdmi deep color 36 for 12 bpc.\n",
34172082093SJani Nikula 					 connector->name);
3427b555e06SAlex Deucher 			break;
3437b555e06SAlex Deucher 	}
3447b555e06SAlex Deucher 
3457b555e06SAlex Deucher 	WREG32(HDMI_CONTROL + offset, val);
346be273e58SSlava Grigorev }
347be273e58SSlava Grigorev 
3481852c9a0SSlava Grigorev void dce4_set_audio_packet(struct drm_encoder *encoder, u32 offset)
3491852c9a0SSlava Grigorev {
3501852c9a0SSlava Grigorev 	struct drm_device *dev = encoder->dev;
3511852c9a0SSlava Grigorev 	struct radeon_device *rdev = dev->dev_private;
3521852c9a0SSlava Grigorev 
3531852c9a0SSlava Grigorev 	WREG32(HDMI_INFOFRAME_CONTROL0 + offset,
3541852c9a0SSlava Grigorev 		HDMI_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */
3551852c9a0SSlava Grigorev 		HDMI_AUDIO_INFO_CONT); /* required for audio info values to be updated */
3561852c9a0SSlava Grigorev 
3571852c9a0SSlava Grigorev 	WREG32(AFMT_INFOFRAME_CONTROL0 + offset,
3581852c9a0SSlava Grigorev 		AFMT_AUDIO_INFO_UPDATE); /* required for audio info values to be updated */
3591852c9a0SSlava Grigorev 
3601852c9a0SSlava Grigorev 	WREG32(HDMI_INFOFRAME_CONTROL1 + offset,
3611852c9a0SSlava Grigorev 		HDMI_AUDIO_INFO_LINE(2)); /* anything other than 0 */
3621852c9a0SSlava Grigorev 
3631852c9a0SSlava Grigorev 	WREG32(HDMI_AUDIO_PACKET_CONTROL + offset,
3641852c9a0SSlava Grigorev 		HDMI_AUDIO_DELAY_EN(1) | /* set the default audio delay */
3651852c9a0SSlava Grigorev 		HDMI_AUDIO_PACKETS_PER_LINE(3)); /* should be suffient for all audio modes and small enough for all hblanks */
3661852c9a0SSlava Grigorev 
3671852c9a0SSlava Grigorev 	WREG32(AFMT_60958_0 + offset,
3681852c9a0SSlava Grigorev 		AFMT_60958_CS_CHANNEL_NUMBER_L(1));
3691852c9a0SSlava Grigorev 
3701852c9a0SSlava Grigorev 	WREG32(AFMT_60958_1 + offset,
3711852c9a0SSlava Grigorev 		AFMT_60958_CS_CHANNEL_NUMBER_R(2));
3721852c9a0SSlava Grigorev 
3731852c9a0SSlava Grigorev 	WREG32(AFMT_60958_2 + offset,
3741852c9a0SSlava Grigorev 		AFMT_60958_CS_CHANNEL_NUMBER_2(3) |
3751852c9a0SSlava Grigorev 		AFMT_60958_CS_CHANNEL_NUMBER_3(4) |
3761852c9a0SSlava Grigorev 		AFMT_60958_CS_CHANNEL_NUMBER_4(5) |
3771852c9a0SSlava Grigorev 		AFMT_60958_CS_CHANNEL_NUMBER_5(6) |
3781852c9a0SSlava Grigorev 		AFMT_60958_CS_CHANNEL_NUMBER_6(7) |
3791852c9a0SSlava Grigorev 		AFMT_60958_CS_CHANNEL_NUMBER_7(8));
3801852c9a0SSlava Grigorev 
3811852c9a0SSlava Grigorev 	WREG32(AFMT_AUDIO_PACKET_CONTROL2 + offset,
3821852c9a0SSlava Grigorev 		AFMT_AUDIO_CHANNEL_ENABLE(0xff));
3831852c9a0SSlava Grigorev 
3841852c9a0SSlava Grigorev 	/* allow 60958 channel status and send audio packets fields to be updated */
3851852c9a0SSlava Grigorev 	WREG32(AFMT_AUDIO_PACKET_CONTROL + offset,
3861852c9a0SSlava Grigorev 		AFMT_AUDIO_SAMPLE_SEND | AFMT_RESET_FIFO_WHEN_AUDIO_DIS | AFMT_60958_CS_UPDATE);
3871852c9a0SSlava Grigorev }
3881852c9a0SSlava Grigorev 
389*3be2e7d0SSlava Grigorev 
390*3be2e7d0SSlava Grigorev void dce4_set_mute(struct drm_encoder *encoder, u32 offset, bool mute)
391*3be2e7d0SSlava Grigorev {
392*3be2e7d0SSlava Grigorev 	struct drm_device *dev = encoder->dev;
393*3be2e7d0SSlava Grigorev 	struct radeon_device *rdev = dev->dev_private;
394*3be2e7d0SSlava Grigorev 
395*3be2e7d0SSlava Grigorev 	if (mute)
396*3be2e7d0SSlava Grigorev 		WREG32_OR(HDMI_GC + offset, HDMI_GC_AVMUTE);
397*3be2e7d0SSlava Grigorev 	else
398*3be2e7d0SSlava Grigorev 		WREG32_AND(HDMI_GC + offset, ~HDMI_GC_AVMUTE);
399*3be2e7d0SSlava Grigorev }
400*3be2e7d0SSlava Grigorev 
401be273e58SSlava Grigorev /*
402be273e58SSlava Grigorev  * update the info frames with the data from the current display mode
403be273e58SSlava Grigorev  */
404be273e58SSlava Grigorev void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode)
405be273e58SSlava Grigorev {
406be273e58SSlava Grigorev 	struct drm_device *dev = encoder->dev;
407be273e58SSlava Grigorev 	struct radeon_device *rdev = dev->dev_private;
408be273e58SSlava Grigorev 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
409be273e58SSlava Grigorev 	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
410be273e58SSlava Grigorev 	uint32_t offset;
411be273e58SSlava Grigorev 
412be273e58SSlava Grigorev 	if (!dig || !dig->afmt)
413be273e58SSlava Grigorev 		return;
414be273e58SSlava Grigorev 
415be273e58SSlava Grigorev 	/* Silent, r600_hdmi_enable will raise WARN for us */
416be273e58SSlava Grigorev 	if (!dig->afmt->enabled)
417be273e58SSlava Grigorev 		return;
418be273e58SSlava Grigorev 	offset = dig->afmt->offset;
419be273e58SSlava Grigorev 
420be273e58SSlava Grigorev 	/* disable audio prior to setting up hw */
421be273e58SSlava Grigorev 	dig->afmt->pin = radeon_audio_get_pin(encoder);
422be273e58SSlava Grigorev 	radeon_audio_enable(rdev, dig->afmt->pin, 0);
423be273e58SSlava Grigorev 
424be273e58SSlava Grigorev 	radeon_audio_set_dto(encoder, mode->clock);
425be273e58SSlava Grigorev 	radeon_audio_set_vbi_packet(encoder);
426be273e58SSlava Grigorev 	radeon_hdmi_set_color_depth(encoder);
427*3be2e7d0SSlava Grigorev 	radeon_audio_set_mute(encoder, false);
42864424d6eSSlava Grigorev 	radeon_audio_update_acr(encoder, mode->clock);
42900a9d4bcSSlava Grigorev 	radeon_audio_write_speaker_allocation(encoder);
4301852c9a0SSlava Grigorev 	radeon_audio_set_audio_packet(encoder);
43188252d77SSlava Grigorev 	radeon_audio_select_pin(encoder);
432070a2e63SAlex Deucher 	radeon_audio_write_sad_regs(encoder);
43387654f87SSlava Grigorev 	radeon_audio_write_latency_fields(encoder, mode);
434070a2e63SAlex Deucher 
435baa7d8e4SSlava Grigorev 	if (radeon_audio_set_avi_packet(encoder, mode) < 0)
436e3b2e034SThierry Reding 		return;
437d3418eacSRafał Miłecki 
438e55d3e6cSRafał Miłecki 	/* it's unknown what these bits do excatly, but it's indeed quite useful for debugging */
439e55d3e6cSRafał Miłecki 	WREG32(AFMT_RAMP_CONTROL0 + offset, 0x00FFFFFF);
440e55d3e6cSRafał Miłecki 	WREG32(AFMT_RAMP_CONTROL1 + offset, 0x007FFFFF);
441e55d3e6cSRafał Miłecki 	WREG32(AFMT_RAMP_CONTROL2 + offset, 0x00000001);
442e55d3e6cSRafał Miłecki 	WREG32(AFMT_RAMP_CONTROL3 + offset, 0x00000001);
443832eafafSAlex Deucher 
444832eafafSAlex Deucher 	/* enable audio after to setting up hw */
4458bf59820SSlava Grigorev 	radeon_audio_enable(rdev, dig->afmt->pin, 0xf);
446e55d3e6cSRafał Miłecki }
447a973bea1SAlex Deucher 
448a973bea1SAlex Deucher void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable)
449a973bea1SAlex Deucher {
4504adb34efSAlex Deucher 	struct drm_device *dev = encoder->dev;
4514adb34efSAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
452a973bea1SAlex Deucher 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
453a973bea1SAlex Deucher 	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
454a973bea1SAlex Deucher 
455c2b4cacfSAlex Deucher 	if (!dig || !dig->afmt)
456c2b4cacfSAlex Deucher 		return;
457c2b4cacfSAlex Deucher 
458a973bea1SAlex Deucher 	/* Silent, r600_hdmi_enable will raise WARN for us */
459a973bea1SAlex Deucher 	if (enable && dig->afmt->enabled)
460a973bea1SAlex Deucher 		return;
461a973bea1SAlex Deucher 	if (!enable && !dig->afmt->enabled)
462a973bea1SAlex Deucher 		return;
463a973bea1SAlex Deucher 
4644adb34efSAlex Deucher 	if (!enable && dig->afmt->pin) {
4658bf59820SSlava Grigorev 		radeon_audio_enable(rdev, dig->afmt->pin, 0);
4664adb34efSAlex Deucher 		dig->afmt->pin = NULL;
4674adb34efSAlex Deucher 	}
4684adb34efSAlex Deucher 
469a973bea1SAlex Deucher 	dig->afmt->enabled = enable;
470a973bea1SAlex Deucher 
471a973bea1SAlex Deucher 	DRM_DEBUG("%sabling HDMI interface @ 0x%04X for encoder 0x%x\n",
472a973bea1SAlex Deucher 		  enable ? "En" : "Dis", dig->afmt->offset, radeon_encoder->encoder_id);
473a973bea1SAlex Deucher }
474