diff options
Diffstat (limited to 'drivers/gpu/drm/radeon/r600_hdmi.c')
-rw-r--r-- | drivers/gpu/drm/radeon/r600_hdmi.c | 65 |
1 files changed, 52 insertions, 13 deletions
diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c index f5ac7e788d8..0b592067145 100644 --- a/drivers/gpu/drm/radeon/r600_hdmi.c +++ b/drivers/gpu/drm/radeon/r600_hdmi.c | |||
@@ -196,6 +196,13 @@ static void r600_hdmi_videoinfoframe( | |||
196 | frame[0xD] = (right_bar >> 8); | 196 | frame[0xD] = (right_bar >> 8); |
197 | 197 | ||
198 | r600_hdmi_infoframe_checksum(0x82, 0x02, 0x0D, frame); | 198 | r600_hdmi_infoframe_checksum(0x82, 0x02, 0x0D, frame); |
199 | /* Our header values (type, version, length) should be alright, Intel | ||
200 | * is using the same. Checksum function also seems to be OK, it works | ||
201 | * fine for audio infoframe. However calculated value is always lower | ||
202 | * by 2 in comparison to fglrx. It breaks displaying anything in case | ||
203 | * of TVs that strictly check the checksum. Hack it manually here to | ||
204 | * workaround this issue. */ | ||
205 | frame[0x0] += 2; | ||
199 | 206 | ||
200 | WREG32(offset+R600_HDMI_VIDEOINFOFRAME_0, | 207 | WREG32(offset+R600_HDMI_VIDEOINFOFRAME_0, |
201 | frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24)); | 208 | frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24)); |
@@ -313,7 +320,7 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod | |||
313 | struct radeon_device *rdev = dev->dev_private; | 320 | struct radeon_device *rdev = dev->dev_private; |
314 | uint32_t offset = to_radeon_encoder(encoder)->hdmi_offset; | 321 | uint32_t offset = to_radeon_encoder(encoder)->hdmi_offset; |
315 | 322 | ||
316 | if (ASIC_IS_DCE4(rdev)) | 323 | if (ASIC_IS_DCE5(rdev)) |
317 | return; | 324 | return; |
318 | 325 | ||
319 | if (!offset) | 326 | if (!offset) |
@@ -455,13 +462,31 @@ static void r600_hdmi_assign_block(struct drm_encoder *encoder) | |||
455 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); | 462 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
456 | struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; | 463 | struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; |
457 | 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 | |||
458 | if (!dig) { | 474 | if (!dig) { |
459 | dev_err(rdev->dev, "Enabling HDMI on non-dig encoder\n"); | 475 | dev_err(rdev->dev, "Enabling HDMI on non-dig encoder\n"); |
460 | return; | 476 | return; |
461 | } | 477 | } |
462 | 478 | ||
463 | if (ASIC_IS_DCE4(rdev)) { | 479 | if (ASIC_IS_DCE5(rdev)) { |
464 | /* TODO */ | 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; | ||
465 | } else if (ASIC_IS_DCE3(rdev)) { | 490 | } else if (ASIC_IS_DCE3(rdev)) { |
466 | radeon_encoder->hdmi_offset = dig->dig_encoder ? | 491 | radeon_encoder->hdmi_offset = dig->dig_encoder ? |
467 | R600_HDMI_BLOCK3 : R600_HDMI_BLOCK1; | 492 | R600_HDMI_BLOCK3 : R600_HDMI_BLOCK1; |
@@ -484,7 +509,7 @@ void r600_hdmi_enable(struct drm_encoder *encoder) | |||
484 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); | 509 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
485 | uint32_t offset; | 510 | uint32_t offset; |
486 | 511 | ||
487 | if (ASIC_IS_DCE4(rdev)) | 512 | if (ASIC_IS_DCE5(rdev)) |
488 | return; | 513 | return; |
489 | 514 | ||
490 | if (!radeon_encoder->hdmi_offset) { | 515 | if (!radeon_encoder->hdmi_offset) { |
@@ -497,16 +522,24 @@ void r600_hdmi_enable(struct drm_encoder *encoder) | |||
497 | } | 522 | } |
498 | 523 | ||
499 | offset = radeon_encoder->hdmi_offset; | 524 | offset = radeon_encoder->hdmi_offset; |
500 | if (ASIC_IS_DCE32(rdev) && !ASIC_IS_DCE4(rdev)) { | 525 | if (ASIC_IS_DCE5(rdev)) { |
526 | /* TODO */ | ||
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)) { | ||
501 | WREG32_P(radeon_encoder->hdmi_config_offset + 0x4, 0x1, ~0x1); | 530 | WREG32_P(radeon_encoder->hdmi_config_offset + 0x4, 0x1, ~0x1); |
502 | } else if (rdev->family >= CHIP_R600 && !ASIC_IS_DCE3(rdev)) { | 531 | } else if (ASIC_IS_DCE3(rdev)) { |
532 | /* TODO */ | ||
533 | } else if (rdev->family >= CHIP_R600) { | ||
503 | switch (radeon_encoder->encoder_id) { | 534 | switch (radeon_encoder->encoder_id) { |
504 | case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: | 535 | case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: |
505 | WREG32_P(AVIVO_TMDSA_CNTL, 0x4, ~0x4); | 536 | WREG32_P(AVIVO_TMDSA_CNTL, AVIVO_TMDSA_CNTL_HDMI_EN, |
537 | ~AVIVO_TMDSA_CNTL_HDMI_EN); | ||
506 | WREG32(offset + R600_HDMI_ENABLE, 0x101); | 538 | WREG32(offset + R600_HDMI_ENABLE, 0x101); |
507 | break; | 539 | break; |
508 | case ENCODER_OBJECT_ID_INTERNAL_LVTM1: | 540 | case ENCODER_OBJECT_ID_INTERNAL_LVTM1: |
509 | WREG32_P(AVIVO_LVTMA_CNTL, 0x4, ~0x4); | 541 | WREG32_P(AVIVO_LVTMA_CNTL, AVIVO_LVTMA_CNTL_HDMI_EN, |
542 | ~AVIVO_LVTMA_CNTL_HDMI_EN); | ||
510 | WREG32(offset + R600_HDMI_ENABLE, 0x105); | 543 | WREG32(offset + R600_HDMI_ENABLE, 0x105); |
511 | break; | 544 | break; |
512 | default: | 545 | default: |
@@ -518,8 +551,8 @@ void r600_hdmi_enable(struct drm_encoder *encoder) | |||
518 | if (rdev->irq.installed | 551 | if (rdev->irq.installed |
519 | && rdev->family != CHIP_RS600 | 552 | && rdev->family != CHIP_RS600 |
520 | && rdev->family != CHIP_RS690 | 553 | && rdev->family != CHIP_RS690 |
521 | && rdev->family != CHIP_RS740) { | 554 | && rdev->family != CHIP_RS740 |
522 | 555 | && !ASIC_IS_DCE4(rdev)) { | |
523 | /* if irq is available use it */ | 556 | /* if irq is available use it */ |
524 | rdev->irq.hdmi[offset == R600_HDMI_BLOCK1 ? 0 : 1] = true; | 557 | rdev->irq.hdmi[offset == R600_HDMI_BLOCK1 ? 0 : 1] = true; |
525 | radeon_irq_set(rdev); | 558 | radeon_irq_set(rdev); |
@@ -544,7 +577,7 @@ void r600_hdmi_disable(struct drm_encoder *encoder) | |||
544 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); | 577 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
545 | uint32_t offset; | 578 | uint32_t offset; |
546 | 579 | ||
547 | if (ASIC_IS_DCE4(rdev)) | 580 | if (ASIC_IS_DCE5(rdev)) |
548 | return; | 581 | return; |
549 | 582 | ||
550 | offset = radeon_encoder->hdmi_offset; | 583 | offset = radeon_encoder->hdmi_offset; |
@@ -563,16 +596,22 @@ void r600_hdmi_disable(struct drm_encoder *encoder) | |||
563 | /* disable polling */ | 596 | /* disable polling */ |
564 | r600_audio_disable_polling(encoder); | 597 | r600_audio_disable_polling(encoder); |
565 | 598 | ||
566 | if (ASIC_IS_DCE32(rdev) && !ASIC_IS_DCE4(rdev)) { | 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)) { | ||
567 | WREG32_P(radeon_encoder->hdmi_config_offset + 0x4, 0, ~0x1); | 604 | WREG32_P(radeon_encoder->hdmi_config_offset + 0x4, 0, ~0x1); |
568 | } else if (rdev->family >= CHIP_R600 && !ASIC_IS_DCE3(rdev)) { | 605 | } else if (rdev->family >= CHIP_R600 && !ASIC_IS_DCE3(rdev)) { |
569 | switch (radeon_encoder->encoder_id) { | 606 | switch (radeon_encoder->encoder_id) { |
570 | case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: | 607 | case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: |
571 | WREG32_P(AVIVO_TMDSA_CNTL, 0, ~0x4); | 608 | WREG32_P(AVIVO_TMDSA_CNTL, 0, |
609 | ~AVIVO_TMDSA_CNTL_HDMI_EN); | ||
572 | WREG32(offset + R600_HDMI_ENABLE, 0); | 610 | WREG32(offset + R600_HDMI_ENABLE, 0); |
573 | break; | 611 | break; |
574 | case ENCODER_OBJECT_ID_INTERNAL_LVTM1: | 612 | case ENCODER_OBJECT_ID_INTERNAL_LVTM1: |
575 | WREG32_P(AVIVO_LVTMA_CNTL, 0, ~0x4); | 613 | WREG32_P(AVIVO_LVTMA_CNTL, 0, |
614 | ~AVIVO_LVTMA_CNTL_HDMI_EN); | ||
576 | WREG32(offset + R600_HDMI_ENABLE, 0); | 615 | WREG32(offset + R600_HDMI_ENABLE, 0); |
577 | break; | 616 | break; |
578 | default: | 617 | default: |