xref: /linux/drivers/gpu/drm/radeon/evergreen_hdmi.c (revision b1f6f47e3e33c4a74534f1301aca241ffabbb3a0)
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"
32e55d3e6cSRafał Miłecki #include "evergreend.h"
33e55d3e6cSRafał Miłecki #include "atom.h"
34e55d3e6cSRafał Miłecki 
35e55d3e6cSRafał Miłecki /*
36e55d3e6cSRafał Miłecki  * update the N and CTS parameters for a given pixel clock rate
37e55d3e6cSRafał Miłecki  */
38e55d3e6cSRafał Miłecki static void evergreen_hdmi_update_ACR(struct drm_encoder *encoder, uint32_t clock)
39e55d3e6cSRafał Miłecki {
40e55d3e6cSRafał Miłecki 	struct drm_device *dev = encoder->dev;
41e55d3e6cSRafał Miłecki 	struct radeon_device *rdev = dev->dev_private;
42e55d3e6cSRafał Miłecki 	struct radeon_hdmi_acr acr = r600_hdmi_acr(clock);
43cfcbd6d3SRafał Miłecki 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
44cfcbd6d3SRafał Miłecki 	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
45cfcbd6d3SRafał Miłecki 	uint32_t offset = dig->afmt->offset;
46e55d3e6cSRafał Miłecki 
47e55d3e6cSRafał Miłecki 	WREG32(HDMI_ACR_32_0 + offset, HDMI_ACR_CTS_32(acr.cts_32khz));
48e55d3e6cSRafał Miłecki 	WREG32(HDMI_ACR_32_1 + offset, acr.n_32khz);
49e55d3e6cSRafał Miłecki 
50e55d3e6cSRafał Miłecki 	WREG32(HDMI_ACR_44_0 + offset, HDMI_ACR_CTS_44(acr.cts_44_1khz));
51e55d3e6cSRafał Miłecki 	WREG32(HDMI_ACR_44_1 + offset, acr.n_44_1khz);
52e55d3e6cSRafał Miłecki 
53e55d3e6cSRafał Miłecki 	WREG32(HDMI_ACR_48_0 + offset, HDMI_ACR_CTS_48(acr.cts_48khz));
54e55d3e6cSRafał Miłecki 	WREG32(HDMI_ACR_48_1 + offset, acr.n_48khz);
55e55d3e6cSRafał Miłecki }
56e55d3e6cSRafał Miłecki 
57e55d3e6cSRafał Miłecki /*
58e55d3e6cSRafał Miłecki  * build a HDMI Video Info Frame
59e55d3e6cSRafał Miłecki  */
60e3b2e034SThierry Reding static void evergreen_hdmi_update_avi_infoframe(struct drm_encoder *encoder,
61e3b2e034SThierry Reding 						void *buffer, size_t size)
62e55d3e6cSRafał Miłecki {
63e55d3e6cSRafał Miłecki 	struct drm_device *dev = encoder->dev;
64e55d3e6cSRafał Miłecki 	struct radeon_device *rdev = dev->dev_private;
65cfcbd6d3SRafał Miłecki 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
66cfcbd6d3SRafał Miłecki 	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
67cfcbd6d3SRafał Miłecki 	uint32_t offset = dig->afmt->offset;
68e3b2e034SThierry Reding 	uint8_t *frame = buffer + 3;
69e55d3e6cSRafał Miłecki 
70e55d3e6cSRafał Miłecki 	/* Our header values (type, version, length) should be alright, Intel
71e55d3e6cSRafał Miłecki 	 * is using the same. Checksum function also seems to be OK, it works
72e55d3e6cSRafał Miłecki 	 * fine for audio infoframe. However calculated value is always lower
73e55d3e6cSRafał Miłecki 	 * by 2 in comparison to fglrx. It breaks displaying anything in case
74e55d3e6cSRafał Miłecki 	 * of TVs that strictly check the checksum. Hack it manually here to
75e55d3e6cSRafał Miłecki 	 * workaround this issue. */
76e55d3e6cSRafał Miłecki 	frame[0x0] += 2;
77e55d3e6cSRafał Miłecki 
78e55d3e6cSRafał Miłecki 	WREG32(AFMT_AVI_INFO0 + offset,
79e55d3e6cSRafał Miłecki 		frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24));
80e55d3e6cSRafał Miłecki 	WREG32(AFMT_AVI_INFO1 + offset,
81e55d3e6cSRafał Miłecki 		frame[0x4] | (frame[0x5] << 8) | (frame[0x6] << 16) | (frame[0x7] << 24));
82e55d3e6cSRafał Miłecki 	WREG32(AFMT_AVI_INFO2 + offset,
83e55d3e6cSRafał Miłecki 		frame[0x8] | (frame[0x9] << 8) | (frame[0xA] << 16) | (frame[0xB] << 24));
84e55d3e6cSRafał Miłecki 	WREG32(AFMT_AVI_INFO3 + offset,
85e55d3e6cSRafał Miłecki 		frame[0xC] | (frame[0xD] << 8));
86e55d3e6cSRafał Miłecki }
87e55d3e6cSRafał Miłecki 
88*b1f6f47eSAlex Deucher static void evergreen_audio_set_dto(struct drm_encoder *encoder, u32 clock)
89*b1f6f47eSAlex Deucher {
90*b1f6f47eSAlex Deucher 	struct drm_device *dev = encoder->dev;
91*b1f6f47eSAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
92*b1f6f47eSAlex Deucher 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
93*b1f6f47eSAlex Deucher 	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
94*b1f6f47eSAlex Deucher 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
95*b1f6f47eSAlex Deucher 	u32 base_rate = 48000;
96*b1f6f47eSAlex Deucher 
97*b1f6f47eSAlex Deucher 	if (!dig || !dig->afmt)
98*b1f6f47eSAlex Deucher 		return;
99*b1f6f47eSAlex Deucher 
100*b1f6f47eSAlex Deucher 	/* XXX: properly calculate this */
101*b1f6f47eSAlex Deucher 	/* XXX two dtos; generally use dto0 for hdmi */
102*b1f6f47eSAlex Deucher 	/* Express [24MHz / target pixel clock] as an exact rational
103*b1f6f47eSAlex Deucher 	 * number (coefficient of two integer numbers.  DCCG_AUDIO_DTOx_PHASE
104*b1f6f47eSAlex Deucher 	 * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
105*b1f6f47eSAlex Deucher 	 */
106*b1f6f47eSAlex Deucher 	WREG32(DCCG_AUDIO_DTO0_PHASE, (base_rate*50) & 0xffffff);
107*b1f6f47eSAlex Deucher 	WREG32(DCCG_AUDIO_DTO0_MODULE, (clock*100) & 0xffffff);
108*b1f6f47eSAlex Deucher 	WREG32(DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO0_SOURCE_SEL(radeon_crtc->crtc_id));
109*b1f6f47eSAlex Deucher }
110*b1f6f47eSAlex Deucher 
111*b1f6f47eSAlex Deucher 
112e55d3e6cSRafał Miłecki /*
113e55d3e6cSRafał Miłecki  * update the info frames with the data from the current display mode
114e55d3e6cSRafał Miłecki  */
115e55d3e6cSRafał Miłecki void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode)
116e55d3e6cSRafał Miłecki {
117e55d3e6cSRafał Miłecki 	struct drm_device *dev = encoder->dev;
118e55d3e6cSRafał Miłecki 	struct radeon_device *rdev = dev->dev_private;
119cfcbd6d3SRafał Miłecki 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
120cfcbd6d3SRafał Miłecki 	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
121e3b2e034SThierry Reding 	u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE];
122e3b2e034SThierry Reding 	struct hdmi_avi_infoframe frame;
123cfcbd6d3SRafał Miłecki 	uint32_t offset;
124e3b2e034SThierry Reding 	ssize_t err;
125e55d3e6cSRafał Miłecki 
126cfcbd6d3SRafał Miłecki 	/* Silent, r600_hdmi_enable will raise WARN for us */
127cfcbd6d3SRafał Miłecki 	if (!dig->afmt->enabled)
128e55d3e6cSRafał Miłecki 		return;
129cfcbd6d3SRafał Miłecki 	offset = dig->afmt->offset;
130e55d3e6cSRafał Miłecki 
131*b1f6f47eSAlex Deucher 	evergreen_audio_set_dto(encoder, mode->clock);
132e55d3e6cSRafał Miłecki 
1331c3439f2SRafał Miłecki 	WREG32(HDMI_VBI_PACKET_CONTROL + offset,
1341c3439f2SRafał Miłecki 	       HDMI_NULL_SEND); /* send null packets when required */
1351c3439f2SRafał Miłecki 
136e55d3e6cSRafał Miłecki 	WREG32(AFMT_AUDIO_CRC_CONTROL + offset, 0x1000);
137e55d3e6cSRafał Miłecki 
1381c3439f2SRafał Miłecki 	WREG32(HDMI_VBI_PACKET_CONTROL + offset,
1391c3439f2SRafał Miłecki 	       HDMI_NULL_SEND | /* send null packets when required */
1401c3439f2SRafał Miłecki 	       HDMI_GC_SEND | /* send general control packets */
1411c3439f2SRafał Miłecki 	       HDMI_GC_CONT); /* send general control packets every frame */
142e55d3e6cSRafał Miłecki 
1431c3439f2SRafał Miłecki 	WREG32(HDMI_INFOFRAME_CONTROL0 + offset,
1441c3439f2SRafał Miłecki 	       HDMI_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */
1451c3439f2SRafał Miłecki 	       HDMI_AUDIO_INFO_CONT); /* required for audio info values to be updated */
1461c3439f2SRafał Miłecki 
1471c3439f2SRafał Miłecki 	WREG32(AFMT_INFOFRAME_CONTROL0 + offset,
1481c3439f2SRafał Miłecki 	       AFMT_AUDIO_INFO_UPDATE); /* required for audio info values to be updated */
1491c3439f2SRafał Miłecki 
1501c3439f2SRafał Miłecki 	WREG32(HDMI_INFOFRAME_CONTROL1 + offset,
1511c3439f2SRafał Miłecki 	       HDMI_AUDIO_INFO_LINE(2)); /* anything other than 0 */
1521c3439f2SRafał Miłecki 
1531c3439f2SRafał Miłecki 	WREG32(HDMI_GC + offset, 0); /* unset HDMI_GC_AVMUTE */
154e55d3e6cSRafał Miłecki 
15591a44019SRafał Miłecki 	WREG32(HDMI_AUDIO_PACKET_CONTROL + offset,
15691a44019SRafał Miłecki 	       HDMI_AUDIO_DELAY_EN(1) | /* set the default audio delay */
15791a44019SRafał Miłecki 	       HDMI_AUDIO_PACKETS_PER_LINE(3)); /* should be suffient for all audio modes and small enough for all hblanks */
15891a44019SRafał Miłecki 
15991a44019SRafał Miłecki 	WREG32(AFMT_AUDIO_PACKET_CONTROL + offset,
16091a44019SRafał Miłecki 	       AFMT_60958_CS_UPDATE); /* allow 60958 channel status fields to be updated */
16191a44019SRafał Miłecki 
16291a44019SRafał Miłecki 	/* fglrx clears sth in AFMT_AUDIO_PACKET_CONTROL2 here */
16391a44019SRafał Miłecki 
16491a44019SRafał Miłecki 	WREG32(HDMI_ACR_PACKET_CONTROL + offset,
16591a44019SRafał Miłecki 	       HDMI_ACR_AUTO_SEND | /* allow hw to sent ACR packets when required */
16691a44019SRafał Miłecki 	       HDMI_ACR_SOURCE); /* select SW CTS value */
16791a44019SRafał Miłecki 
16891a44019SRafał Miłecki 	evergreen_hdmi_update_ACR(encoder, mode->clock);
16991a44019SRafał Miłecki 
170f93e3fc3SRafał Miłecki 	WREG32(AFMT_60958_0 + offset,
171f93e3fc3SRafał Miłecki 	       AFMT_60958_CS_CHANNEL_NUMBER_L(1));
172f93e3fc3SRafał Miłecki 
173f93e3fc3SRafał Miłecki 	WREG32(AFMT_60958_1 + offset,
174f93e3fc3SRafał Miłecki 	       AFMT_60958_CS_CHANNEL_NUMBER_R(2));
175f93e3fc3SRafał Miłecki 
176f93e3fc3SRafał Miłecki 	WREG32(AFMT_60958_2 + offset,
177f93e3fc3SRafał Miłecki 	       AFMT_60958_CS_CHANNEL_NUMBER_2(3) |
178f93e3fc3SRafał Miłecki 	       AFMT_60958_CS_CHANNEL_NUMBER_3(4) |
179f93e3fc3SRafał Miłecki 	       AFMT_60958_CS_CHANNEL_NUMBER_4(5) |
180f93e3fc3SRafał Miłecki 	       AFMT_60958_CS_CHANNEL_NUMBER_5(6) |
181f93e3fc3SRafał Miłecki 	       AFMT_60958_CS_CHANNEL_NUMBER_6(7) |
182f93e3fc3SRafał Miłecki 	       AFMT_60958_CS_CHANNEL_NUMBER_7(8));
183f93e3fc3SRafał Miłecki 
184f93e3fc3SRafał Miłecki 	/* fglrx sets 0x0001005f | (x & 0x00fc0000) in 0x5f78 here */
185f93e3fc3SRafał Miłecki 
186f93e3fc3SRafał Miłecki 	WREG32(AFMT_AUDIO_PACKET_CONTROL2 + offset,
187f93e3fc3SRafał Miłecki 	       AFMT_AUDIO_CHANNEL_ENABLE(0xff));
188f93e3fc3SRafał Miłecki 
189f93e3fc3SRafał Miłecki 	/* fglrx sets 0x40 in 0x5f80 here */
190f93e3fc3SRafał Miłecki 
191e3b2e034SThierry Reding 	err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
192e3b2e034SThierry Reding 	if (err < 0) {
193e3b2e034SThierry Reding 		DRM_ERROR("failed to setup AVI infoframe: %zd\n", err);
194e3b2e034SThierry Reding 		return;
195e3b2e034SThierry Reding 	}
196e55d3e6cSRafał Miłecki 
197e3b2e034SThierry Reding 	err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer));
198e3b2e034SThierry Reding 	if (err < 0) {
199e3b2e034SThierry Reding 		DRM_ERROR("failed to pack AVI infoframe: %zd\n", err);
200e3b2e034SThierry Reding 		return;
201e3b2e034SThierry Reding 	}
202e3b2e034SThierry Reding 
203e3b2e034SThierry Reding 	evergreen_hdmi_update_avi_infoframe(encoder, buffer, sizeof(buffer));
2041c3439f2SRafał Miłecki 
205d3418eacSRafał Miłecki 	WREG32_OR(HDMI_INFOFRAME_CONTROL0 + offset,
206d3418eacSRafał Miłecki 		  HDMI_AVI_INFO_SEND | /* enable AVI info frames */
207d3418eacSRafał Miłecki 		  HDMI_AVI_INFO_CONT); /* required for audio info values to be updated */
208d3418eacSRafał Miłecki 
209d3418eacSRafał Miłecki 	WREG32_P(HDMI_INFOFRAME_CONTROL1 + offset,
210d3418eacSRafał Miłecki 		 HDMI_AVI_INFO_LINE(2), /* anything other than 0 */
211d3418eacSRafał Miłecki 		 ~HDMI_AVI_INFO_LINE_MASK);
212d3418eacSRafał Miłecki 
213d3418eacSRafał Miłecki 	WREG32_OR(AFMT_AUDIO_PACKET_CONTROL + offset,
214d3418eacSRafał Miłecki 		  AFMT_AUDIO_SAMPLE_SEND); /* send audio packets */
215d3418eacSRafał Miłecki 
216e55d3e6cSRafał Miłecki 	/* it's unknown what these bits do excatly, but it's indeed quite useful for debugging */
217e55d3e6cSRafał Miłecki 	WREG32(AFMT_RAMP_CONTROL0 + offset, 0x00FFFFFF);
218e55d3e6cSRafał Miłecki 	WREG32(AFMT_RAMP_CONTROL1 + offset, 0x007FFFFF);
219e55d3e6cSRafał Miłecki 	WREG32(AFMT_RAMP_CONTROL2 + offset, 0x00000001);
220e55d3e6cSRafał Miłecki 	WREG32(AFMT_RAMP_CONTROL3 + offset, 0x00000001);
221e55d3e6cSRafał Miłecki }
222