Rev 1403 | Rev 2997 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1403 | Rev 1963 | ||
---|---|---|---|
Line 24... | Line 24... | ||
24 | * Authors: Christian König |
24 | * Authors: Christian König |
25 | */ |
25 | */ |
26 | #include "drmP.h" |
26 | #include "drmP.h" |
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 "atom.h" |
30 | #include "atom.h" |
Line 30... | Line 31... | ||
30 | 31 | ||
31 | /* |
32 | /* |
32 | * HDMI color format |
33 | * HDMI color format |
Line 288... | Line 289... | ||
288 | uint32_t offset = radeon_encoder->hdmi_offset; |
289 | uint32_t offset = radeon_encoder->hdmi_offset; |
Line 289... | Line 290... | ||
289 | 290 | ||
290 | if (!offset) |
291 | if (!offset) |
Line -... | Line 292... | ||
- | 292 | return; |
|
291 | return; |
293 | |
292 | - | ||
293 | if (r600_hdmi_is_audio_buffer_filled(encoder)) { |
- | |
Line 294... | Line 294... | ||
294 | /* disable audio workaround and start delivering of audio frames */ |
294 | if (!radeon_encoder->hdmi_audio_workaround || |
295 | WREG32_P(offset+R600_HDMI_CNTL, 0x00000001, ~0x00001001); |
- | |
296 | 295 | r600_hdmi_is_audio_buffer_filled(encoder)) { |
|
Line 297... | Line 296... | ||
297 | } else if (radeon_encoder->hdmi_audio_workaround) { |
296 | |
298 | /* enable audio workaround and start delivering of audio frames */ |
297 | /* disable audio workaround */ |
299 | WREG32_P(offset+R600_HDMI_CNTL, 0x00001001, ~0x00001001); |
298 | WREG32_P(offset+R600_HDMI_CNTL, 0x00000001, ~0x00001001); |
300 | 299 | ||
301 | } else { |
300 | } else { |
Line 302... | Line 301... | ||
302 | /* disable audio workaround and stop delivering of audio frames */ |
301 | /* enable audio workaround */ |
Line 312... | Line 311... | ||
312 | { |
311 | { |
313 | struct drm_device *dev = encoder->dev; |
312 | struct drm_device *dev = encoder->dev; |
314 | struct radeon_device *rdev = dev->dev_private; |
313 | struct radeon_device *rdev = dev->dev_private; |
315 | uint32_t offset = to_radeon_encoder(encoder)->hdmi_offset; |
314 | uint32_t offset = to_radeon_encoder(encoder)->hdmi_offset; |
Line -... | Line 315... | ||
- | 315 | ||
- | 316 | if (ASIC_IS_DCE4(rdev)) |
|
- | 317 | return; |
|
316 | 318 | ||
317 | if (!offset) |
319 | if (!offset) |
Line 318... | Line 320... | ||
318 | return; |
320 | return; |
Line 330... | Line 332... | ||
330 | WREG32(offset+R600_HDMI_VERSION, 0x202); |
332 | WREG32(offset+R600_HDMI_VERSION, 0x202); |
Line 331... | Line 333... | ||
331 | 333 | ||
332 | r600_hdmi_videoinfoframe(encoder, RGB, 0, 0, 0, 0, |
334 | r600_hdmi_videoinfoframe(encoder, RGB, 0, 0, 0, 0, |
Line 333... | Line 335... | ||
333 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); |
335 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); |
334 | 336 | ||
335 | /* it's unknown what these bits do excatly, but it's indeed quite usefull for debugging */ |
337 | /* it's unknown what these bits do excatly, but it's indeed quite useful for debugging */ |
336 | WREG32(offset+R600_HDMI_AUDIO_DEBUG_0, 0x00FFFFFF); |
338 | WREG32(offset+R600_HDMI_AUDIO_DEBUG_0, 0x00FFFFFF); |
337 | WREG32(offset+R600_HDMI_AUDIO_DEBUG_1, 0x007FFFFF); |
339 | WREG32(offset+R600_HDMI_AUDIO_DEBUG_1, 0x007FFFFF); |
Line 338... | Line 340... | ||
338 | WREG32(offset+R600_HDMI_AUDIO_DEBUG_2, 0x00000001); |
340 | WREG32(offset+R600_HDMI_AUDIO_DEBUG_2, 0x00000001); |
Line 339... | Line 341... | ||
339 | WREG32(offset+R600_HDMI_AUDIO_DEBUG_3, 0x00000001); |
341 | WREG32(offset+R600_HDMI_AUDIO_DEBUG_3, 0x00000001); |
340 | 342 | ||
341 | r600_hdmi_audio_workaround(encoder); |
- | |
342 | - | ||
343 | /* audio packets per line, does anyone know how to calc this ? */ |
- | |
344 | WREG32_P(offset+R600_HDMI_CNTL, 0x00040000, ~0x001F0000); |
343 | r600_hdmi_audio_workaround(encoder); |
Line 345... | Line 344... | ||
345 | 344 | ||
346 | /* update? reset? don't realy know */ |
345 | /* audio packets per line, does anyone know how to calc this ? */ |
347 | WREG32_P(offset+R600_HDMI_CNTL, 0x14000000, ~0x14000000); |
346 | WREG32_P(offset+R600_HDMI_CNTL, 0x00040000, ~0x001F0000); |
348 | } |
347 | } |
349 | - | ||
350 | /* |
- | |
351 | * update settings with current parameters from audio engine |
- | |
352 | */ |
- | |
353 | void r600_hdmi_update_audio_settings(struct drm_encoder *encoder, |
- | |
354 | int channels, |
348 | |
355 | int rate, |
349 | /* |
356 | int bps, |
350 | * update settings with current parameters from audio engine |
357 | uint8_t status_bits, |
351 | */ |
Line -... | Line 352... | ||
- | 352 | void r600_hdmi_update_audio_settings(struct drm_encoder *encoder) |
|
- | 353 | { |
|
- | 354 | struct drm_device *dev = encoder->dev; |
|
- | 355 | struct radeon_device *rdev = dev->dev_private; |
|
- | 356 | uint32_t offset = to_radeon_encoder(encoder)->hdmi_offset; |
|
- | 357 | ||
358 | uint8_t category_code) |
358 | int channels = r600_audio_channels(rdev); |
Line 359... | Line 359... | ||
359 | { |
359 | int rate = r600_audio_rate(rdev); |
360 | struct drm_device *dev = encoder->dev; |
360 | int bps = r600_audio_bits_per_sample(rdev); |
Line 410... | Line 410... | ||
410 | /* 0x021 or 0x031 sets the audio frame length */ |
410 | /* 0x021 or 0x031 sets the audio frame length */ |
411 | WREG32(offset+R600_HDMI_AUDIOCNTL, 0x31); |
411 | WREG32(offset+R600_HDMI_AUDIOCNTL, 0x31); |
412 | r600_hdmi_audioinfoframe(encoder, channels-1, 0, 0, 0, 0, 0, 0, 0); |
412 | r600_hdmi_audioinfoframe(encoder, channels-1, 0, 0, 0, 0, 0, 0, 0); |
Line 413... | Line 413... | ||
413 | 413 | ||
- | 414 | r600_hdmi_audio_workaround(encoder); |
|
- | 415 | } |
|
- | 416 | ||
- | 417 | static int r600_hdmi_find_free_block(struct drm_device *dev) |
|
- | 418 | { |
|
- | 419 | struct radeon_device *rdev = dev->dev_private; |
|
- | 420 | struct drm_encoder *encoder; |
|
- | 421 | struct radeon_encoder *radeon_encoder; |
|
- | 422 | bool free_blocks[3] = { true, true, true }; |
|
- | 423 | ||
- | 424 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
|
- | 425 | radeon_encoder = to_radeon_encoder(encoder); |
|
- | 426 | switch (radeon_encoder->hdmi_offset) { |
|
- | 427 | case R600_HDMI_BLOCK1: |
|
- | 428 | free_blocks[0] = false; |
|
- | 429 | break; |
|
- | 430 | case R600_HDMI_BLOCK2: |
|
- | 431 | free_blocks[1] = false; |
|
- | 432 | break; |
|
- | 433 | case R600_HDMI_BLOCK3: |
|
- | 434 | free_blocks[2] = false; |
|
- | 435 | break; |
|
- | 436 | } |
|
Line -... | Line 437... | ||
- | 437 | } |
|
- | 438 | ||
- | 439 | if (rdev->family == CHIP_RS600 || rdev->family == CHIP_RS690 || |
|
- | 440 | rdev->family == CHIP_RS740) { |
|
- | 441 | return free_blocks[0] ? R600_HDMI_BLOCK1 : 0; |
|
- | 442 | } else if (rdev->family >= CHIP_R600) { |
|
- | 443 | if (free_blocks[0]) |
|
- | 444 | return R600_HDMI_BLOCK1; |
|
- | 445 | else if (free_blocks[1]) |
|
- | 446 | return R600_HDMI_BLOCK2; |
|
- | 447 | } |
|
- | 448 | return 0; |
|
- | 449 | } |
|
- | 450 | ||
414 | r600_hdmi_audio_workaround(encoder); |
451 | static void r600_hdmi_assign_block(struct drm_encoder *encoder) |
- | 452 | { |
|
- | 453 | struct drm_device *dev = encoder->dev; |
|
- | 454 | struct radeon_device *rdev = dev->dev_private; |
|
- | 455 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
|
- | 456 | struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; |
|
- | 457 | ||
- | 458 | if (!dig) { |
|
- | 459 | dev_err(rdev->dev, "Enabling HDMI on non-dig encoder\n"); |
|
- | 460 | return; |
|
- | 461 | } |
|
- | 462 | ||
- | 463 | if (ASIC_IS_DCE4(rdev)) { |
|
- | 464 | /* TODO */ |
|
- | 465 | } else if (ASIC_IS_DCE3(rdev)) { |
|
- | 466 | radeon_encoder->hdmi_offset = dig->dig_encoder ? |
|
- | 467 | R600_HDMI_BLOCK3 : R600_HDMI_BLOCK1; |
|
415 | 468 | if (ASIC_IS_DCE32(rdev)) |
|
- | 469 | radeon_encoder->hdmi_config_offset = dig->dig_encoder ? |
|
- | 470 | R600_HDMI_CONFIG2 : R600_HDMI_CONFIG1; |
|
- | 471 | } else if (rdev->family >= CHIP_R600 || rdev->family == CHIP_RS600 || |
|
- | 472 | rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) { |
|
416 | /* update? reset? don't realy know */ |
473 | radeon_encoder->hdmi_offset = r600_hdmi_find_free_block(dev); |
Line 417... | Line 474... | ||
417 | WREG32_P(offset+R600_HDMI_CNTL, 0x04000000, ~0x04000000); |
474 | } |
418 | } |
475 | } |
419 | 476 | ||
420 | /* |
477 | /* |
421 | * enable/disable the HDMI engine |
478 | * enable the HDMI engine |
422 | */ |
479 | */ |
423 | void r600_hdmi_enable(struct drm_encoder *encoder, int enable) |
480 | void r600_hdmi_enable(struct drm_encoder *encoder) |
424 | { |
481 | { |
425 | struct drm_device *dev = encoder->dev; |
482 | struct drm_device *dev = encoder->dev; |
Line 426... | Line 483... | ||
426 | struct radeon_device *rdev = dev->dev_private; |
483 | struct radeon_device *rdev = dev->dev_private; |
427 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
484 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
Line -... | Line 485... | ||
- | 485 | uint32_t offset; |
|
- | 486 | ||
- | 487 | if (ASIC_IS_DCE4(rdev)) |
|
428 | uint32_t offset = to_radeon_encoder(encoder)->hdmi_offset; |
488 | return; |
- | 489 | ||
- | 490 | if (!radeon_encoder->hdmi_offset) { |
|
- | 491 | r600_hdmi_assign_block(encoder); |
|
- | 492 | if (!radeon_encoder->hdmi_offset) { |
|
Line -... | Line 493... | ||
- | 493 | dev_warn(rdev->dev, "Could not find HDMI block for " |
|
- | 494 | "0x%x encoder\n", radeon_encoder->encoder_id); |
|
429 | 495 | return; |
|
430 | if (!offset) |
496 | } |
431 | return; |
497 | } |
432 | 498 | ||
433 | DRM_DEBUG("%s HDMI interface @ 0x%04X\n", enable ? "Enabling" : "Disabling", offset); |
499 | offset = radeon_encoder->hdmi_offset; |
434 | 500 | if (ASIC_IS_DCE32(rdev) && !ASIC_IS_DCE4(rdev)) { |
|
435 | /* some version of atombios ignore the enable HDMI flag |
501 | WREG32_P(radeon_encoder->hdmi_config_offset + 0x4, 0x1, ~0x1); |
436 | * so enabling/disabling HDMI was moved here for TMDS1+2 */ |
- | |
437 | switch (radeon_encoder->encoder_id) { |
502 | } else if (rdev->family >= CHIP_R600 && !ASIC_IS_DCE3(rdev)) { |
438 | case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: |
503 | switch (radeon_encoder->encoder_id) { |
439 | WREG32_P(AVIVO_TMDSA_CNTL, enable ? 0x4 : 0x0, ~0x4); |
504 | case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: |
440 | WREG32(offset+R600_HDMI_ENABLE, enable ? 0x101 : 0x0); |
- | |
441 | break; |
- | |
442 | - | ||
443 | case ENCODER_OBJECT_ID_INTERNAL_LVTM1: |
- | |
444 | WREG32_P(AVIVO_LVTMA_CNTL, enable ? 0x4 : 0x0, ~0x4); |
- | |
445 | WREG32(offset+R600_HDMI_ENABLE, enable ? 0x105 : 0x0); |
- | |
446 | break; |
- | |
447 | - | ||
448 | case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: |
505 | WREG32_P(AVIVO_TMDSA_CNTL, 0x4, ~0x4); |
449 | case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: |
- | |
450 | case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: |
506 | WREG32(offset + R600_HDMI_ENABLE, 0x101); |
451 | case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: |
507 | break; |
452 | /* This part is doubtfull in my opinion */ |
508 | case ENCODER_OBJECT_ID_INTERNAL_LVTM1: |
453 | WREG32(offset+R600_HDMI_ENABLE, enable ? 0x110 : 0x0); |
509 | WREG32_P(AVIVO_LVTMA_CNTL, 0x4, ~0x4); |
454 | break; |
510 | WREG32(offset + R600_HDMI_ENABLE, 0x105); |
- | 511 | break; |
|
- | 512 | default: |
|
- | 513 | dev_err(rdev->dev, "Unknown HDMI output type\n"); |
|
- | 514 | break; |
|
- | 515 | } |
|
- | 516 | } |
|
- | 517 | #if 0 |
|
- | 518 | if (rdev->irq.installed |
|
- | 519 | && rdev->family != CHIP_RS600 |
|
- | 520 | && rdev->family != CHIP_RS690 |
|
- | 521 | && rdev->family != CHIP_RS740) { |
|
- | 522 | ||
- | 523 | /* if irq is available use it */ |
|
- | 524 | rdev->irq.hdmi[offset == R600_HDMI_BLOCK1 ? 0 : 1] = true; |
|
- | 525 | radeon_irq_set(rdev); |
|
- | 526 | ||
- | 527 | r600_audio_disable_polling(encoder); |
|
- | 528 | } else { |
|
- | 529 | /* if not fallback to polling */ |
|
Line 455... | Line 530... | ||
455 | 530 | r600_audio_enable_polling(encoder); |
|
456 | default: |
531 | } |
457 | DRM_ERROR("unknown HDMI output type\n"); |
532 | #endif |
458 | break; |
533 | DRM_DEBUG("Enabling HDMI interface @ 0x%04X for encoder 0x%x\n", |
459 | } |
534 | radeon_encoder->hdmi_offset, radeon_encoder->encoder_id); |
- | 535 | } |
|
- | 536 | ||
460 | } |
537 | /* |
- | 538 | * disable the HDMI engine |
|
- | 539 | */ |
|
- | 540 | void r600_hdmi_disable(struct drm_encoder *encoder) |
|
- | 541 | { |
|
Line -... | Line 542... | ||
- | 542 | struct drm_device *dev = encoder->dev; |
|
- | 543 | struct radeon_device *rdev = dev->dev_private; |
|
- | 544 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
|
- | 545 | uint32_t offset; |
|
- | 546 | ||
- | 547 | if (ASIC_IS_DCE4(rdev)) |
|
- | 548 | return; |
|
- | 549 | ||
- | 550 | offset = radeon_encoder->hdmi_offset; |
|
- | 551 | if (!offset) { |
|
- | 552 | dev_err(rdev->dev, "Disabling not enabled HDMI\n"); |
|
- | 553 | return; |
|
461 | 554 | } |
|
462 | /* |
555 | |
463 | * determin at which register offset the HDMI encoder is |
556 | DRM_DEBUG("Disabling HDMI interface @ 0x%04X for encoder 0x%x\n", |
464 | */ |
- | |
465 | void r600_hdmi_init(struct drm_encoder *encoder) |
557 | offset, radeon_encoder->encoder_id); |
466 | { |
558 | |
467 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
- | |
468 | 559 | if (ASIC_IS_DCE32(rdev) && !ASIC_IS_DCE4(rdev)) { |
|
469 | switch (radeon_encoder->encoder_id) { |
- | |
470 | case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: |
- | |
471 | case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: |
560 | WREG32_P(radeon_encoder->hdmi_config_offset + 0x4, 0, ~0x1); |
472 | case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: |
- | |
473 | radeon_encoder->hdmi_offset = R600_HDMI_TMDS1; |
- | |
474 | break; |
561 | } else if (rdev->family >= CHIP_R600 && !ASIC_IS_DCE3(rdev)) { |
475 | 562 | switch (radeon_encoder->encoder_id) { |
|
476 | case ENCODER_OBJECT_ID_INTERNAL_LVTM1: |
563 | case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: |
477 | switch (r600_audio_tmds_index(encoder)) { |
564 | WREG32_P(AVIVO_TMDSA_CNTL, 0, ~0x4); |
478 | case 0: |
565 | WREG32(offset + R600_HDMI_ENABLE, 0); |
479 | radeon_encoder->hdmi_offset = R600_HDMI_TMDS1; |
566 | break; |
480 | break; |
- | |
481 | case 1: |
- | |
482 | radeon_encoder->hdmi_offset = R600_HDMI_TMDS2; |
- | |
483 | break; |
- | |
484 | default: |
- | |
485 | radeon_encoder->hdmi_offset = 0; |
- | |
486 | break; |
- | |
487 | } |
- | |
488 | case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: |
- | |
489 | radeon_encoder->hdmi_offset = R600_HDMI_TMDS2; |
- | |
490 | break; |
- | |
491 | 567 | case ENCODER_OBJECT_ID_INTERNAL_LVTM1: |
|
Line 492... | Line -... | ||
492 | case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: |
- | |
493 | radeon_encoder->hdmi_offset = R600_HDMI_DIG; |
568 | WREG32_P(AVIVO_LVTMA_CNTL, 0, ~0x4); |
494 | break; |
- | |
495 | - | ||
496 | default: |
569 | WREG32(offset + R600_HDMI_ENABLE, 0); |
497 | radeon_encoder->hdmi_offset = 0; |
570 | break; |