diff options
Diffstat (limited to 'drivers/gpu/drm/radeon/r600_hdmi.c')
-rw-r--r-- | drivers/gpu/drm/radeon/r600_hdmi.c | 464 |
1 files changed, 215 insertions, 249 deletions
diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c index 0b5920671450..226379e00ac1 100644 --- a/drivers/gpu/drm/radeon/r600_hdmi.c +++ b/drivers/gpu/drm/radeon/r600_hdmi.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include "radeon_drm.h" | 27 | #include "radeon_drm.h" |
28 | #include "radeon.h" | 28 | #include "radeon.h" |
29 | #include "radeon_asic.h" | 29 | #include "radeon_asic.h" |
30 | #include "r600d.h" | ||
30 | #include "atom.h" | 31 | #include "atom.h" |
31 | 32 | ||
32 | /* | 33 | /* |
@@ -52,19 +53,7 @@ enum r600_hdmi_iec_status_bits { | |||
52 | AUDIO_STATUS_LEVEL = 0x80 | 53 | AUDIO_STATUS_LEVEL = 0x80 |
53 | }; | 54 | }; |
54 | 55 | ||
55 | struct { | 56 | struct radeon_hdmi_acr r600_hdmi_predefined_acr[] = { |
56 | uint32_t Clock; | ||
57 | |||
58 | int N_32kHz; | ||
59 | int CTS_32kHz; | ||
60 | |||
61 | int N_44_1kHz; | ||
62 | int CTS_44_1kHz; | ||
63 | |||
64 | int N_48kHz; | ||
65 | int CTS_48kHz; | ||
66 | |||
67 | } r600_hdmi_ACR[] = { | ||
68 | /* 32kHz 44.1kHz 48kHz */ | 57 | /* 32kHz 44.1kHz 48kHz */ |
69 | /* Clock N CTS N CTS N CTS */ | 58 | /* Clock N CTS N CTS N CTS */ |
70 | { 25174, 4576, 28125, 7007, 31250, 6864, 28125 }, /* 25,20/1.001 MHz */ | 59 | { 25174, 4576, 28125, 7007, 31250, 6864, 28125 }, /* 25,20/1.001 MHz */ |
@@ -83,7 +72,7 @@ struct { | |||
83 | /* | 72 | /* |
84 | * calculate CTS value if it's not found in the table | 73 | * calculate CTS value if it's not found in the table |
85 | */ | 74 | */ |
86 | static void r600_hdmi_calc_CTS(uint32_t clock, int *CTS, int N, int freq) | 75 | static void r600_hdmi_calc_cts(uint32_t clock, int *CTS, int N, int freq) |
87 | { | 76 | { |
88 | if (*CTS == 0) | 77 | if (*CTS == 0) |
89 | *CTS = clock * N / (128 * freq) * 1000; | 78 | *CTS = clock * N / (128 * freq) * 1000; |
@@ -91,6 +80,24 @@ static void r600_hdmi_calc_CTS(uint32_t clock, int *CTS, int N, int freq) | |||
91 | N, *CTS, freq); | 80 | N, *CTS, freq); |
92 | } | 81 | } |
93 | 82 | ||
83 | struct radeon_hdmi_acr r600_hdmi_acr(uint32_t clock) | ||
84 | { | ||
85 | struct radeon_hdmi_acr res; | ||
86 | u8 i; | ||
87 | |||
88 | for (i = 0; r600_hdmi_predefined_acr[i].clock != clock && | ||
89 | r600_hdmi_predefined_acr[i].clock != 0; i++) | ||
90 | ; | ||
91 | res = r600_hdmi_predefined_acr[i]; | ||
92 | |||
93 | /* In case some CTS are missing */ | ||
94 | r600_hdmi_calc_cts(clock, &res.cts_32khz, res.n_32khz, 32000); | ||
95 | r600_hdmi_calc_cts(clock, &res.cts_44_1khz, res.n_44_1khz, 44100); | ||
96 | r600_hdmi_calc_cts(clock, &res.cts_48khz, res.n_48khz, 48000); | ||
97 | |||
98 | return res; | ||
99 | } | ||
100 | |||
94 | /* | 101 | /* |
95 | * update the N and CTS parameters for a given pixel clock rate | 102 | * update the N and CTS parameters for a given pixel clock rate |
96 | */ | 103 | */ |
@@ -98,30 +105,19 @@ static void r600_hdmi_update_ACR(struct drm_encoder *encoder, uint32_t clock) | |||
98 | { | 105 | { |
99 | struct drm_device *dev = encoder->dev; | 106 | struct drm_device *dev = encoder->dev; |
100 | struct radeon_device *rdev = dev->dev_private; | 107 | struct radeon_device *rdev = dev->dev_private; |
101 | uint32_t offset = to_radeon_encoder(encoder)->hdmi_offset; | 108 | struct radeon_hdmi_acr acr = r600_hdmi_acr(clock); |
102 | int CTS; | 109 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
103 | int N; | 110 | struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; |
104 | int i; | 111 | uint32_t offset = dig->afmt->offset; |
112 | |||
113 | WREG32(HDMI0_ACR_32_0 + offset, HDMI0_ACR_CTS_32(acr.cts_32khz)); | ||
114 | WREG32(HDMI0_ACR_32_1 + offset, acr.n_32khz); | ||
105 | 115 | ||
106 | for (i = 0; r600_hdmi_ACR[i].Clock != clock && r600_hdmi_ACR[i].Clock != 0; i++); | 116 | WREG32(HDMI0_ACR_44_0 + offset, HDMI0_ACR_CTS_44(acr.cts_44_1khz)); |
107 | 117 | WREG32(HDMI0_ACR_44_1 + offset, acr.n_44_1khz); | |
108 | CTS = r600_hdmi_ACR[i].CTS_32kHz; | 118 | |
109 | N = r600_hdmi_ACR[i].N_32kHz; | 119 | WREG32(HDMI0_ACR_48_0 + offset, HDMI0_ACR_CTS_48(acr.cts_48khz)); |
110 | r600_hdmi_calc_CTS(clock, &CTS, N, 32000); | 120 | WREG32(HDMI0_ACR_48_1 + offset, acr.n_48khz); |
111 | WREG32(offset+R600_HDMI_32kHz_CTS, CTS << 12); | ||
112 | WREG32(offset+R600_HDMI_32kHz_N, N); | ||
113 | |||
114 | CTS = r600_hdmi_ACR[i].CTS_44_1kHz; | ||
115 | N = r600_hdmi_ACR[i].N_44_1kHz; | ||
116 | r600_hdmi_calc_CTS(clock, &CTS, N, 44100); | ||
117 | WREG32(offset+R600_HDMI_44_1kHz_CTS, CTS << 12); | ||
118 | WREG32(offset+R600_HDMI_44_1kHz_N, N); | ||
119 | |||
120 | CTS = r600_hdmi_ACR[i].CTS_48kHz; | ||
121 | N = r600_hdmi_ACR[i].N_48kHz; | ||
122 | r600_hdmi_calc_CTS(clock, &CTS, N, 48000); | ||
123 | WREG32(offset+R600_HDMI_48kHz_CTS, CTS << 12); | ||
124 | WREG32(offset+R600_HDMI_48kHz_N, N); | ||
125 | } | 121 | } |
126 | 122 | ||
127 | /* | 123 | /* |
@@ -165,7 +161,9 @@ static void r600_hdmi_videoinfoframe( | |||
165 | { | 161 | { |
166 | struct drm_device *dev = encoder->dev; | 162 | struct drm_device *dev = encoder->dev; |
167 | struct radeon_device *rdev = dev->dev_private; | 163 | struct radeon_device *rdev = dev->dev_private; |
168 | uint32_t offset = to_radeon_encoder(encoder)->hdmi_offset; | 164 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
165 | struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; | ||
166 | uint32_t offset = dig->afmt->offset; | ||
169 | 167 | ||
170 | uint8_t frame[14]; | 168 | uint8_t frame[14]; |
171 | 169 | ||
@@ -204,13 +202,13 @@ static void r600_hdmi_videoinfoframe( | |||
204 | * workaround this issue. */ | 202 | * workaround this issue. */ |
205 | frame[0x0] += 2; | 203 | frame[0x0] += 2; |
206 | 204 | ||
207 | WREG32(offset+R600_HDMI_VIDEOINFOFRAME_0, | 205 | WREG32(HDMI0_AVI_INFO0 + offset, |
208 | frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24)); | 206 | frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24)); |
209 | WREG32(offset+R600_HDMI_VIDEOINFOFRAME_1, | 207 | WREG32(HDMI0_AVI_INFO1 + offset, |
210 | frame[0x4] | (frame[0x5] << 8) | (frame[0x6] << 16) | (frame[0x7] << 24)); | 208 | frame[0x4] | (frame[0x5] << 8) | (frame[0x6] << 16) | (frame[0x7] << 24)); |
211 | WREG32(offset+R600_HDMI_VIDEOINFOFRAME_2, | 209 | WREG32(HDMI0_AVI_INFO2 + offset, |
212 | frame[0x8] | (frame[0x9] << 8) | (frame[0xA] << 16) | (frame[0xB] << 24)); | 210 | frame[0x8] | (frame[0x9] << 8) | (frame[0xA] << 16) | (frame[0xB] << 24)); |
213 | WREG32(offset+R600_HDMI_VIDEOINFOFRAME_3, | 211 | WREG32(HDMI0_AVI_INFO3 + offset, |
214 | frame[0xC] | (frame[0xD] << 8)); | 212 | frame[0xC] | (frame[0xD] << 8)); |
215 | } | 213 | } |
216 | 214 | ||
@@ -231,7 +229,9 @@ static void r600_hdmi_audioinfoframe( | |||
231 | { | 229 | { |
232 | struct drm_device *dev = encoder->dev; | 230 | struct drm_device *dev = encoder->dev; |
233 | struct radeon_device *rdev = dev->dev_private; | 231 | struct radeon_device *rdev = dev->dev_private; |
234 | uint32_t offset = to_radeon_encoder(encoder)->hdmi_offset; | 232 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
233 | struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; | ||
234 | uint32_t offset = dig->afmt->offset; | ||
235 | 235 | ||
236 | uint8_t frame[11]; | 236 | uint8_t frame[11]; |
237 | 237 | ||
@@ -249,22 +249,24 @@ static void r600_hdmi_audioinfoframe( | |||
249 | 249 | ||
250 | r600_hdmi_infoframe_checksum(0x84, 0x01, 0x0A, frame); | 250 | r600_hdmi_infoframe_checksum(0x84, 0x01, 0x0A, frame); |
251 | 251 | ||
252 | WREG32(offset+R600_HDMI_AUDIOINFOFRAME_0, | 252 | WREG32(HDMI0_AUDIO_INFO0 + offset, |
253 | frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24)); | 253 | frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24)); |
254 | WREG32(offset+R600_HDMI_AUDIOINFOFRAME_1, | 254 | WREG32(HDMI0_AUDIO_INFO1 + offset, |
255 | frame[0x4] | (frame[0x5] << 8) | (frame[0x6] << 16) | (frame[0x8] << 24)); | 255 | frame[0x4] | (frame[0x5] << 8) | (frame[0x6] << 16) | (frame[0x8] << 24)); |
256 | } | 256 | } |
257 | 257 | ||
258 | /* | 258 | /* |
259 | * test if audio buffer is filled enough to start playing | 259 | * test if audio buffer is filled enough to start playing |
260 | */ | 260 | */ |
261 | static int r600_hdmi_is_audio_buffer_filled(struct drm_encoder *encoder) | 261 | static bool r600_hdmi_is_audio_buffer_filled(struct drm_encoder *encoder) |
262 | { | 262 | { |
263 | struct drm_device *dev = encoder->dev; | 263 | struct drm_device *dev = encoder->dev; |
264 | struct radeon_device *rdev = dev->dev_private; | 264 | struct radeon_device *rdev = dev->dev_private; |
265 | uint32_t offset = to_radeon_encoder(encoder)->hdmi_offset; | 265 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
266 | struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; | ||
267 | uint32_t offset = dig->afmt->offset; | ||
266 | 268 | ||
267 | return (RREG32(offset+R600_HDMI_STATUS) & 0x10) != 0; | 269 | return (RREG32(HDMI0_STATUS + offset) & 0x10) != 0; |
268 | } | 270 | } |
269 | 271 | ||
270 | /* | 272 | /* |
@@ -273,14 +275,15 @@ static int r600_hdmi_is_audio_buffer_filled(struct drm_encoder *encoder) | |||
273 | int r600_hdmi_buffer_status_changed(struct drm_encoder *encoder) | 275 | int r600_hdmi_buffer_status_changed(struct drm_encoder *encoder) |
274 | { | 276 | { |
275 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); | 277 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
278 | struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; | ||
276 | int status, result; | 279 | int status, result; |
277 | 280 | ||
278 | if (!radeon_encoder->hdmi_offset) | 281 | if (!dig->afmt || !dig->afmt->enabled) |
279 | return 0; | 282 | return 0; |
280 | 283 | ||
281 | status = r600_hdmi_is_audio_buffer_filled(encoder); | 284 | status = r600_hdmi_is_audio_buffer_filled(encoder); |
282 | result = radeon_encoder->hdmi_buffer_status != status; | 285 | result = dig->afmt->last_buffer_filled_status != status; |
283 | radeon_encoder->hdmi_buffer_status = status; | 286 | dig->afmt->last_buffer_filled_status = status; |
284 | 287 | ||
285 | return result; | 288 | return result; |
286 | } | 289 | } |
@@ -288,26 +291,23 @@ int r600_hdmi_buffer_status_changed(struct drm_encoder *encoder) | |||
288 | /* | 291 | /* |
289 | * write the audio workaround status to the hardware | 292 | * write the audio workaround status to the hardware |
290 | */ | 293 | */ |
291 | void r600_hdmi_audio_workaround(struct drm_encoder *encoder) | 294 | static void r600_hdmi_audio_workaround(struct drm_encoder *encoder) |
292 | { | 295 | { |
293 | struct drm_device *dev = encoder->dev; | 296 | struct drm_device *dev = encoder->dev; |
294 | struct radeon_device *rdev = dev->dev_private; | 297 | struct radeon_device *rdev = dev->dev_private; |
295 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); | 298 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
296 | uint32_t offset = radeon_encoder->hdmi_offset; | 299 | struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; |
297 | 300 | uint32_t offset = dig->afmt->offset; | |
298 | if (!offset) | 301 | bool hdmi_audio_workaround = false; /* FIXME */ |
299 | return; | 302 | u32 value; |
300 | 303 | ||
301 | if (!radeon_encoder->hdmi_audio_workaround || | 304 | if (!hdmi_audio_workaround || |
302 | r600_hdmi_is_audio_buffer_filled(encoder)) { | 305 | r600_hdmi_is_audio_buffer_filled(encoder)) |
303 | 306 | value = 0; /* disable workaround */ | |
304 | /* disable audio workaround */ | 307 | else |
305 | WREG32_P(offset+R600_HDMI_CNTL, 0x00000001, ~0x00001001); | 308 | value = HDMI0_AUDIO_TEST_EN; /* enable workaround */ |
306 | 309 | WREG32_P(HDMI0_AUDIO_PACKET_CONTROL + offset, | |
307 | } else { | 310 | value, ~HDMI0_AUDIO_TEST_EN); |
308 | /* enable audio workaround */ | ||
309 | WREG32_P(offset+R600_HDMI_CNTL, 0x00001001, ~0x00001001); | ||
310 | } | ||
311 | } | 311 | } |
312 | 312 | ||
313 | 313 | ||
@@ -318,39 +318,75 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod | |||
318 | { | 318 | { |
319 | struct drm_device *dev = encoder->dev; | 319 | struct drm_device *dev = encoder->dev; |
320 | struct radeon_device *rdev = dev->dev_private; | 320 | struct radeon_device *rdev = dev->dev_private; |
321 | uint32_t offset = to_radeon_encoder(encoder)->hdmi_offset; | 321 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
322 | struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; | ||
323 | uint32_t offset; | ||
322 | 324 | ||
323 | if (ASIC_IS_DCE5(rdev)) | 325 | if (ASIC_IS_DCE5(rdev)) |
324 | return; | 326 | return; |
325 | 327 | ||
326 | if (!offset) | 328 | /* Silent, r600_hdmi_enable will raise WARN for us */ |
329 | if (!dig->afmt->enabled) | ||
327 | return; | 330 | return; |
331 | offset = dig->afmt->offset; | ||
328 | 332 | ||
329 | r600_audio_set_clock(encoder, mode->clock); | 333 | r600_audio_set_clock(encoder, mode->clock); |
330 | 334 | ||
331 | WREG32(offset+R600_HDMI_UNKNOWN_0, 0x1000); | 335 | WREG32(HDMI0_VBI_PACKET_CONTROL + offset, |
332 | WREG32(offset+R600_HDMI_UNKNOWN_1, 0x0); | 336 | HDMI0_NULL_SEND); /* send null packets when required */ |
333 | WREG32(offset+R600_HDMI_UNKNOWN_2, 0x1000); | ||
334 | 337 | ||
335 | r600_hdmi_update_ACR(encoder, mode->clock); | 338 | WREG32(HDMI0_AUDIO_CRC_CONTROL + offset, 0x1000); |
339 | |||
340 | if (ASIC_IS_DCE32(rdev)) { | ||
341 | WREG32(HDMI0_AUDIO_PACKET_CONTROL + offset, | ||
342 | HDMI0_AUDIO_DELAY_EN(1) | /* default audio delay */ | ||
343 | HDMI0_AUDIO_PACKETS_PER_LINE(3)); /* should be suffient for all audio modes and small enough for all hblanks */ | ||
344 | WREG32(AFMT_AUDIO_PACKET_CONTROL + offset, | ||
345 | AFMT_AUDIO_SAMPLE_SEND | /* send audio packets */ | ||
346 | AFMT_60958_CS_UPDATE); /* allow 60958 channel status fields to be updated */ | ||
347 | } else { | ||
348 | WREG32(HDMI0_AUDIO_PACKET_CONTROL + offset, | ||
349 | HDMI0_AUDIO_SAMPLE_SEND | /* send audio packets */ | ||
350 | HDMI0_AUDIO_DELAY_EN(1) | /* default audio delay */ | ||
351 | HDMI0_AUDIO_SEND_MAX_PACKETS | /* send NULL packets if no audio is available */ | ||
352 | HDMI0_AUDIO_PACKETS_PER_LINE(3) | /* should be suffient for all audio modes and small enough for all hblanks */ | ||
353 | HDMI0_60958_CS_UPDATE); /* allow 60958 channel status fields to be updated */ | ||
354 | } | ||
355 | |||
356 | WREG32(HDMI0_ACR_PACKET_CONTROL + offset, | ||
357 | HDMI0_ACR_AUTO_SEND | /* allow hw to sent ACR packets when required */ | ||
358 | HDMI0_ACR_SOURCE); /* select SW CTS value */ | ||
359 | |||
360 | WREG32(HDMI0_VBI_PACKET_CONTROL + offset, | ||
361 | HDMI0_NULL_SEND | /* send null packets when required */ | ||
362 | HDMI0_GC_SEND | /* send general control packets */ | ||
363 | HDMI0_GC_CONT); /* send general control packets every frame */ | ||
336 | 364 | ||
337 | WREG32(offset+R600_HDMI_VIDEOCNTL, 0x13); | 365 | /* TODO: HDMI0_AUDIO_INFO_UPDATE */ |
366 | WREG32(HDMI0_INFOFRAME_CONTROL0 + offset, | ||
367 | HDMI0_AVI_INFO_SEND | /* enable AVI info frames */ | ||
368 | HDMI0_AVI_INFO_CONT | /* send AVI info frames every frame/field */ | ||
369 | HDMI0_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */ | ||
370 | HDMI0_AUDIO_INFO_CONT); /* send audio info frames every frame/field */ | ||
338 | 371 | ||
339 | WREG32(offset+R600_HDMI_VERSION, 0x202); | 372 | WREG32(HDMI0_INFOFRAME_CONTROL1 + offset, |
373 | HDMI0_AVI_INFO_LINE(2) | /* anything other than 0 */ | ||
374 | HDMI0_AUDIO_INFO_LINE(2)); /* anything other than 0 */ | ||
375 | |||
376 | WREG32(HDMI0_GC + offset, 0); /* unset HDMI0_GC_AVMUTE */ | ||
340 | 377 | ||
341 | r600_hdmi_videoinfoframe(encoder, RGB, 0, 0, 0, 0, | 378 | r600_hdmi_videoinfoframe(encoder, RGB, 0, 0, 0, 0, |
342 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); | 379 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); |
343 | 380 | ||
381 | r600_hdmi_update_ACR(encoder, mode->clock); | ||
382 | |||
344 | /* it's unknown what these bits do excatly, but it's indeed quite useful for debugging */ | 383 | /* it's unknown what these bits do excatly, but it's indeed quite useful for debugging */ |
345 | WREG32(offset+R600_HDMI_AUDIO_DEBUG_0, 0x00FFFFFF); | 384 | WREG32(HDMI0_RAMP_CONTROL0 + offset, 0x00FFFFFF); |
346 | WREG32(offset+R600_HDMI_AUDIO_DEBUG_1, 0x007FFFFF); | 385 | WREG32(HDMI0_RAMP_CONTROL1 + offset, 0x007FFFFF); |
347 | WREG32(offset+R600_HDMI_AUDIO_DEBUG_2, 0x00000001); | 386 | WREG32(HDMI0_RAMP_CONTROL2 + offset, 0x00000001); |
348 | WREG32(offset+R600_HDMI_AUDIO_DEBUG_3, 0x00000001); | 387 | WREG32(HDMI0_RAMP_CONTROL3 + offset, 0x00000001); |
349 | 388 | ||
350 | r600_hdmi_audio_workaround(encoder); | 389 | r600_hdmi_audio_workaround(encoder); |
351 | |||
352 | /* audio packets per line, does anyone know how to calc this ? */ | ||
353 | WREG32_P(offset+R600_HDMI_CNTL, 0x00040000, ~0x001F0000); | ||
354 | } | 390 | } |
355 | 391 | ||
356 | /* | 392 | /* |
@@ -360,145 +396,82 @@ void r600_hdmi_update_audio_settings(struct drm_encoder *encoder) | |||
360 | { | 396 | { |
361 | struct drm_device *dev = encoder->dev; | 397 | struct drm_device *dev = encoder->dev; |
362 | struct radeon_device *rdev = dev->dev_private; | 398 | struct radeon_device *rdev = dev->dev_private; |
363 | uint32_t offset = to_radeon_encoder(encoder)->hdmi_offset; | 399 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
364 | 400 | struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; | |
365 | int channels = r600_audio_channels(rdev); | 401 | struct r600_audio audio = r600_audio_status(rdev); |
366 | int rate = r600_audio_rate(rdev); | 402 | uint32_t offset; |
367 | int bps = r600_audio_bits_per_sample(rdev); | ||
368 | uint8_t status_bits = r600_audio_status_bits(rdev); | ||
369 | uint8_t category_code = r600_audio_category_code(rdev); | ||
370 | |||
371 | uint32_t iec; | 403 | uint32_t iec; |
372 | 404 | ||
373 | if (!offset) | 405 | if (!dig->afmt || !dig->afmt->enabled) |
374 | return; | 406 | return; |
407 | offset = dig->afmt->offset; | ||
375 | 408 | ||
376 | DRM_DEBUG("%s with %d channels, %d Hz sampling rate, %d bits per sample,\n", | 409 | DRM_DEBUG("%s with %d channels, %d Hz sampling rate, %d bits per sample,\n", |
377 | r600_hdmi_is_audio_buffer_filled(encoder) ? "playing" : "stopped", | 410 | r600_hdmi_is_audio_buffer_filled(encoder) ? "playing" : "stopped", |
378 | channels, rate, bps); | 411 | audio.channels, audio.rate, audio.bits_per_sample); |
379 | DRM_DEBUG("0x%02X IEC60958 status bits and 0x%02X category code\n", | 412 | DRM_DEBUG("0x%02X IEC60958 status bits and 0x%02X category code\n", |
380 | (int)status_bits, (int)category_code); | 413 | (int)audio.status_bits, (int)audio.category_code); |
381 | 414 | ||
382 | iec = 0; | 415 | iec = 0; |
383 | if (status_bits & AUDIO_STATUS_PROFESSIONAL) | 416 | if (audio.status_bits & AUDIO_STATUS_PROFESSIONAL) |
384 | iec |= 1 << 0; | 417 | iec |= 1 << 0; |
385 | if (status_bits & AUDIO_STATUS_NONAUDIO) | 418 | if (audio.status_bits & AUDIO_STATUS_NONAUDIO) |
386 | iec |= 1 << 1; | 419 | iec |= 1 << 1; |
387 | if (status_bits & AUDIO_STATUS_COPYRIGHT) | 420 | if (audio.status_bits & AUDIO_STATUS_COPYRIGHT) |
388 | iec |= 1 << 2; | 421 | iec |= 1 << 2; |
389 | if (status_bits & AUDIO_STATUS_EMPHASIS) | 422 | if (audio.status_bits & AUDIO_STATUS_EMPHASIS) |
390 | iec |= 1 << 3; | 423 | iec |= 1 << 3; |
391 | 424 | ||
392 | iec |= category_code << 8; | 425 | iec |= HDMI0_60958_CS_CATEGORY_CODE(audio.category_code); |
393 | 426 | ||
394 | switch (rate) { | 427 | switch (audio.rate) { |
395 | case 32000: iec |= 0x3 << 24; break; | 428 | case 32000: |
396 | case 44100: iec |= 0x0 << 24; break; | 429 | iec |= HDMI0_60958_CS_SAMPLING_FREQUENCY(0x3); |
397 | case 88200: iec |= 0x8 << 24; break; | 430 | break; |
398 | case 176400: iec |= 0xc << 24; break; | 431 | case 44100: |
399 | case 48000: iec |= 0x2 << 24; break; | 432 | iec |= HDMI0_60958_CS_SAMPLING_FREQUENCY(0x0); |
400 | case 96000: iec |= 0xa << 24; break; | 433 | break; |
401 | case 192000: iec |= 0xe << 24; break; | 434 | case 48000: |
435 | iec |= HDMI0_60958_CS_SAMPLING_FREQUENCY(0x2); | ||
436 | break; | ||
437 | case 88200: | ||
438 | iec |= HDMI0_60958_CS_SAMPLING_FREQUENCY(0x8); | ||
439 | break; | ||
440 | case 96000: | ||
441 | iec |= HDMI0_60958_CS_SAMPLING_FREQUENCY(0xa); | ||
442 | break; | ||
443 | case 176400: | ||
444 | iec |= HDMI0_60958_CS_SAMPLING_FREQUENCY(0xc); | ||
445 | break; | ||
446 | case 192000: | ||
447 | iec |= HDMI0_60958_CS_SAMPLING_FREQUENCY(0xe); | ||
448 | break; | ||
402 | } | 449 | } |
403 | 450 | ||
404 | WREG32(offset+R600_HDMI_IEC60958_1, iec); | 451 | WREG32(HDMI0_60958_0 + offset, iec); |
405 | 452 | ||
406 | iec = 0; | 453 | iec = 0; |
407 | switch (bps) { | 454 | switch (audio.bits_per_sample) { |
408 | case 16: iec |= 0x2; break; | 455 | case 16: |
409 | case 20: iec |= 0x3; break; | 456 | iec |= HDMI0_60958_CS_WORD_LENGTH(0x2); |
410 | case 24: iec |= 0xb; break; | 457 | break; |
458 | case 20: | ||
459 | iec |= HDMI0_60958_CS_WORD_LENGTH(0x3); | ||
460 | break; | ||
461 | case 24: | ||
462 | iec |= HDMI0_60958_CS_WORD_LENGTH(0xb); | ||
463 | break; | ||
411 | } | 464 | } |
412 | if (status_bits & AUDIO_STATUS_V) | 465 | if (audio.status_bits & AUDIO_STATUS_V) |
413 | iec |= 0x5 << 16; | 466 | iec |= 0x5 << 16; |
467 | WREG32_P(HDMI0_60958_1 + offset, iec, ~0x5000f); | ||
414 | 468 | ||
415 | WREG32_P(offset+R600_HDMI_IEC60958_2, iec, ~0x5000f); | 469 | r600_hdmi_audioinfoframe(encoder, audio.channels - 1, 0, 0, 0, 0, 0, 0, |
416 | 470 | 0); | |
417 | /* 0x021 or 0x031 sets the audio frame length */ | ||
418 | WREG32(offset+R600_HDMI_AUDIOCNTL, 0x31); | ||
419 | r600_hdmi_audioinfoframe(encoder, channels-1, 0, 0, 0, 0, 0, 0, 0); | ||
420 | 471 | ||
421 | r600_hdmi_audio_workaround(encoder); | 472 | r600_hdmi_audio_workaround(encoder); |
422 | } | 473 | } |
423 | 474 | ||
424 | static int r600_hdmi_find_free_block(struct drm_device *dev) | ||
425 | { | ||
426 | struct radeon_device *rdev = dev->dev_private; | ||
427 | struct drm_encoder *encoder; | ||
428 | struct radeon_encoder *radeon_encoder; | ||
429 | bool free_blocks[3] = { true, true, true }; | ||
430 | |||
431 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { | ||
432 | radeon_encoder = to_radeon_encoder(encoder); | ||
433 | switch (radeon_encoder->hdmi_offset) { | ||
434 | case R600_HDMI_BLOCK1: | ||
435 | free_blocks[0] = false; | ||
436 | break; | ||
437 | case R600_HDMI_BLOCK2: | ||
438 | free_blocks[1] = false; | ||
439 | break; | ||
440 | case R600_HDMI_BLOCK3: | ||
441 | free_blocks[2] = false; | ||
442 | break; | ||
443 | } | ||
444 | } | ||
445 | |||
446 | if (rdev->family == CHIP_RS600 || rdev->family == CHIP_RS690 || | ||
447 | rdev->family == CHIP_RS740) { | ||
448 | return free_blocks[0] ? R600_HDMI_BLOCK1 : 0; | ||
449 | } else if (rdev->family >= CHIP_R600) { | ||
450 | if (free_blocks[0]) | ||
451 | return R600_HDMI_BLOCK1; | ||
452 | else if (free_blocks[1]) | ||
453 | return R600_HDMI_BLOCK2; | ||
454 | } | ||
455 | return 0; | ||
456 | } | ||
457 | |||
458 | static void r600_hdmi_assign_block(struct drm_encoder *encoder) | ||
459 | { | ||
460 | struct drm_device *dev = encoder->dev; | ||
461 | struct radeon_device *rdev = dev->dev_private; | ||
462 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); | ||
463 | struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; | ||
464 | |||
465 | u16 eg_offsets[] = { | ||
466 | EVERGREEN_CRTC0_REGISTER_OFFSET, | ||
467 | EVERGREEN_CRTC1_REGISTER_OFFSET, | ||
468 | EVERGREEN_CRTC2_REGISTER_OFFSET, | ||
469 | EVERGREEN_CRTC3_REGISTER_OFFSET, | ||
470 | EVERGREEN_CRTC4_REGISTER_OFFSET, | ||
471 | EVERGREEN_CRTC5_REGISTER_OFFSET, | ||
472 | }; | ||
473 | |||
474 | if (!dig) { | ||
475 | dev_err(rdev->dev, "Enabling HDMI on non-dig encoder\n"); | ||
476 | return; | ||
477 | } | ||
478 | |||
479 | if (ASIC_IS_DCE5(rdev)) { | ||
480 | /* TODO */ | ||
481 | } else if (ASIC_IS_DCE4(rdev)) { | ||
482 | if (dig->dig_encoder >= ARRAY_SIZE(eg_offsets)) { | ||
483 | dev_err(rdev->dev, "Enabling HDMI on unknown dig\n"); | ||
484 | return; | ||
485 | } | ||
486 | radeon_encoder->hdmi_offset = EVERGREEN_HDMI_BASE + | ||
487 | eg_offsets[dig->dig_encoder]; | ||
488 | radeon_encoder->hdmi_config_offset = radeon_encoder->hdmi_offset | ||
489 | + EVERGREEN_HDMI_CONFIG_OFFSET; | ||
490 | } else if (ASIC_IS_DCE3(rdev)) { | ||
491 | radeon_encoder->hdmi_offset = dig->dig_encoder ? | ||
492 | R600_HDMI_BLOCK3 : R600_HDMI_BLOCK1; | ||
493 | if (ASIC_IS_DCE32(rdev)) | ||
494 | radeon_encoder->hdmi_config_offset = dig->dig_encoder ? | ||
495 | R600_HDMI_CONFIG2 : R600_HDMI_CONFIG1; | ||
496 | } else if (rdev->family >= CHIP_R600 || rdev->family == CHIP_RS600 || | ||
497 | rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) { | ||
498 | radeon_encoder->hdmi_offset = r600_hdmi_find_free_block(dev); | ||
499 | } | ||
500 | } | ||
501 | |||
502 | /* | 475 | /* |
503 | * enable the HDMI engine | 476 | * enable the HDMI engine |
504 | */ | 477 | */ |
@@ -507,64 +480,57 @@ void r600_hdmi_enable(struct drm_encoder *encoder) | |||
507 | struct drm_device *dev = encoder->dev; | 480 | struct drm_device *dev = encoder->dev; |
508 | struct radeon_device *rdev = dev->dev_private; | 481 | struct radeon_device *rdev = dev->dev_private; |
509 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); | 482 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
483 | struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; | ||
510 | uint32_t offset; | 484 | uint32_t offset; |
485 | u32 hdmi; | ||
511 | 486 | ||
512 | if (ASIC_IS_DCE5(rdev)) | 487 | if (ASIC_IS_DCE5(rdev)) |
513 | return; | 488 | return; |
514 | 489 | ||
515 | if (!radeon_encoder->hdmi_offset) { | 490 | /* Silent, r600_hdmi_enable will raise WARN for us */ |
516 | r600_hdmi_assign_block(encoder); | 491 | if (dig->afmt->enabled) |
517 | if (!radeon_encoder->hdmi_offset) { | 492 | return; |
518 | dev_warn(rdev->dev, "Could not find HDMI block for " | 493 | offset = dig->afmt->offset; |
519 | "0x%x encoder\n", radeon_encoder->encoder_id); | ||
520 | return; | ||
521 | } | ||
522 | } | ||
523 | 494 | ||
524 | offset = radeon_encoder->hdmi_offset; | 495 | /* Older chipsets require setting HDMI and routing manually */ |
525 | if (ASIC_IS_DCE5(rdev)) { | 496 | if (rdev->family >= CHIP_R600 && !ASIC_IS_DCE3(rdev)) { |
526 | /* TODO */ | 497 | hdmi = HDMI0_ERROR_ACK | HDMI0_ENABLE; |
527 | } else if (ASIC_IS_DCE4(rdev)) { | ||
528 | WREG32_P(radeon_encoder->hdmi_config_offset + 0xc, 0x1, ~0x1); | ||
529 | } else if (ASIC_IS_DCE32(rdev)) { | ||
530 | WREG32_P(radeon_encoder->hdmi_config_offset + 0x4, 0x1, ~0x1); | ||
531 | } else if (ASIC_IS_DCE3(rdev)) { | ||
532 | /* TODO */ | ||
533 | } else if (rdev->family >= CHIP_R600) { | ||
534 | switch (radeon_encoder->encoder_id) { | 498 | switch (radeon_encoder->encoder_id) { |
535 | case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: | 499 | case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: |
536 | WREG32_P(AVIVO_TMDSA_CNTL, AVIVO_TMDSA_CNTL_HDMI_EN, | 500 | WREG32_P(AVIVO_TMDSA_CNTL, AVIVO_TMDSA_CNTL_HDMI_EN, |
537 | ~AVIVO_TMDSA_CNTL_HDMI_EN); | 501 | ~AVIVO_TMDSA_CNTL_HDMI_EN); |
538 | WREG32(offset + R600_HDMI_ENABLE, 0x101); | 502 | hdmi |= HDMI0_STREAM(HDMI0_STREAM_TMDSA); |
539 | break; | 503 | break; |
540 | case ENCODER_OBJECT_ID_INTERNAL_LVTM1: | 504 | case ENCODER_OBJECT_ID_INTERNAL_LVTM1: |
541 | WREG32_P(AVIVO_LVTMA_CNTL, AVIVO_LVTMA_CNTL_HDMI_EN, | 505 | WREG32_P(AVIVO_LVTMA_CNTL, AVIVO_LVTMA_CNTL_HDMI_EN, |
542 | ~AVIVO_LVTMA_CNTL_HDMI_EN); | 506 | ~AVIVO_LVTMA_CNTL_HDMI_EN); |
543 | WREG32(offset + R600_HDMI_ENABLE, 0x105); | 507 | hdmi |= HDMI0_STREAM(HDMI0_STREAM_LVTMA); |
508 | break; | ||
509 | case ENCODER_OBJECT_ID_INTERNAL_DDI: | ||
510 | WREG32_P(DDIA_CNTL, DDIA_HDMI_EN, ~DDIA_HDMI_EN); | ||
511 | hdmi |= HDMI0_STREAM(HDMI0_STREAM_DDIA); | ||
512 | break; | ||
513 | case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: | ||
514 | hdmi |= HDMI0_STREAM(HDMI0_STREAM_DVOA); | ||
544 | break; | 515 | break; |
545 | default: | 516 | default: |
546 | dev_err(rdev->dev, "Unknown HDMI output type\n"); | 517 | dev_err(rdev->dev, "Invalid encoder for HDMI: 0x%X\n", |
518 | radeon_encoder->encoder_id); | ||
547 | break; | 519 | break; |
548 | } | 520 | } |
521 | WREG32(HDMI0_CONTROL + offset, hdmi); | ||
549 | } | 522 | } |
550 | 523 | ||
551 | if (rdev->irq.installed | 524 | if (rdev->irq.installed) { |
552 | && rdev->family != CHIP_RS600 | ||
553 | && rdev->family != CHIP_RS690 | ||
554 | && rdev->family != CHIP_RS740 | ||
555 | && !ASIC_IS_DCE4(rdev)) { | ||
556 | /* if irq is available use it */ | 525 | /* if irq is available use it */ |
557 | rdev->irq.hdmi[offset == R600_HDMI_BLOCK1 ? 0 : 1] = true; | 526 | rdev->irq.afmt[dig->afmt->id] = true; |
558 | radeon_irq_set(rdev); | 527 | radeon_irq_set(rdev); |
559 | |||
560 | r600_audio_disable_polling(encoder); | ||
561 | } else { | ||
562 | /* if not fallback to polling */ | ||
563 | r600_audio_enable_polling(encoder); | ||
564 | } | 528 | } |
565 | 529 | ||
530 | dig->afmt->enabled = true; | ||
531 | |||
566 | DRM_DEBUG("Enabling HDMI interface @ 0x%04X for encoder 0x%x\n", | 532 | DRM_DEBUG("Enabling HDMI interface @ 0x%04X for encoder 0x%x\n", |
567 | radeon_encoder->hdmi_offset, radeon_encoder->encoder_id); | 533 | offset, radeon_encoder->encoder_id); |
568 | } | 534 | } |
569 | 535 | ||
570 | /* | 536 | /* |
@@ -575,51 +541,51 @@ void r600_hdmi_disable(struct drm_encoder *encoder) | |||
575 | struct drm_device *dev = encoder->dev; | 541 | struct drm_device *dev = encoder->dev; |
576 | struct radeon_device *rdev = dev->dev_private; | 542 | struct radeon_device *rdev = dev->dev_private; |
577 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); | 543 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
544 | struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; | ||
578 | uint32_t offset; | 545 | uint32_t offset; |
579 | 546 | ||
580 | if (ASIC_IS_DCE5(rdev)) | 547 | if (ASIC_IS_DCE5(rdev)) |
581 | return; | 548 | return; |
582 | 549 | ||
583 | offset = radeon_encoder->hdmi_offset; | 550 | /* Called for ATOM_ENCODER_MODE_HDMI only */ |
584 | if (!offset) { | 551 | if (!dig || !dig->afmt) { |
585 | dev_err(rdev->dev, "Disabling not enabled HDMI\n"); | 552 | WARN_ON(1); |
586 | return; | 553 | return; |
587 | } | 554 | } |
555 | if (!dig->afmt->enabled) | ||
556 | return; | ||
557 | offset = dig->afmt->offset; | ||
588 | 558 | ||
589 | DRM_DEBUG("Disabling HDMI interface @ 0x%04X for encoder 0x%x\n", | 559 | DRM_DEBUG("Disabling HDMI interface @ 0x%04X for encoder 0x%x\n", |
590 | offset, radeon_encoder->encoder_id); | 560 | offset, radeon_encoder->encoder_id); |
591 | 561 | ||
592 | /* disable irq */ | 562 | /* disable irq */ |
593 | rdev->irq.hdmi[offset == R600_HDMI_BLOCK1 ? 0 : 1] = false; | 563 | rdev->irq.afmt[dig->afmt->id] = false; |
594 | radeon_irq_set(rdev); | 564 | radeon_irq_set(rdev); |
595 | 565 | ||
596 | /* disable polling */ | 566 | /* Older chipsets not handled by AtomBIOS */ |
597 | r600_audio_disable_polling(encoder); | 567 | if (rdev->family >= CHIP_R600 && !ASIC_IS_DCE3(rdev)) { |
598 | |||
599 | if (ASIC_IS_DCE5(rdev)) { | ||
600 | /* TODO */ | ||
601 | } else if (ASIC_IS_DCE4(rdev)) { | ||
602 | WREG32_P(radeon_encoder->hdmi_config_offset + 0xc, 0, ~0x1); | ||
603 | } else if (ASIC_IS_DCE32(rdev)) { | ||
604 | WREG32_P(radeon_encoder->hdmi_config_offset + 0x4, 0, ~0x1); | ||
605 | } else if (rdev->family >= CHIP_R600 && !ASIC_IS_DCE3(rdev)) { | ||
606 | switch (radeon_encoder->encoder_id) { | 568 | switch (radeon_encoder->encoder_id) { |
607 | case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: | 569 | case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: |
608 | WREG32_P(AVIVO_TMDSA_CNTL, 0, | 570 | WREG32_P(AVIVO_TMDSA_CNTL, 0, |
609 | ~AVIVO_TMDSA_CNTL_HDMI_EN); | 571 | ~AVIVO_TMDSA_CNTL_HDMI_EN); |
610 | WREG32(offset + R600_HDMI_ENABLE, 0); | ||
611 | break; | 572 | break; |
612 | case ENCODER_OBJECT_ID_INTERNAL_LVTM1: | 573 | case ENCODER_OBJECT_ID_INTERNAL_LVTM1: |
613 | WREG32_P(AVIVO_LVTMA_CNTL, 0, | 574 | WREG32_P(AVIVO_LVTMA_CNTL, 0, |
614 | ~AVIVO_LVTMA_CNTL_HDMI_EN); | 575 | ~AVIVO_LVTMA_CNTL_HDMI_EN); |
615 | WREG32(offset + R600_HDMI_ENABLE, 0); | 576 | break; |
577 | case ENCODER_OBJECT_ID_INTERNAL_DDI: | ||
578 | WREG32_P(DDIA_CNTL, 0, ~DDIA_HDMI_EN); | ||
579 | break; | ||
580 | case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: | ||
616 | break; | 581 | break; |
617 | default: | 582 | default: |
618 | dev_err(rdev->dev, "Unknown HDMI output type\n"); | 583 | dev_err(rdev->dev, "Invalid encoder for HDMI: 0x%X\n", |
584 | radeon_encoder->encoder_id); | ||
619 | break; | 585 | break; |
620 | } | 586 | } |
587 | WREG32(HDMI0_CONTROL + offset, HDMI0_ERROR_ACK); | ||
621 | } | 588 | } |
622 | 589 | ||
623 | radeon_encoder->hdmi_offset = 0; | 590 | dig->afmt->enabled = false; |
624 | radeon_encoder->hdmi_config_offset = 0; | ||
625 | } | 591 | } |