aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/radeon/r600_hdmi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/radeon/r600_hdmi.c')
-rw-r--r--drivers/gpu/drm/radeon/r600_hdmi.c200
1 files changed, 130 insertions, 70 deletions
diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c
index fcc949df0e5d..2616b822ba68 100644
--- a/drivers/gpu/drm/radeon/r600_hdmi.c
+++ b/drivers/gpu/drm/radeon/r600_hdmi.c
@@ -42,13 +42,13 @@ enum r600_hdmi_color_format {
42 */ 42 */
43enum r600_hdmi_iec_status_bits { 43enum r600_hdmi_iec_status_bits {
44 AUDIO_STATUS_DIG_ENABLE = 0x01, 44 AUDIO_STATUS_DIG_ENABLE = 0x01,
45 AUDIO_STATUS_V = 0x02, 45 AUDIO_STATUS_V = 0x02,
46 AUDIO_STATUS_VCFG = 0x04, 46 AUDIO_STATUS_VCFG = 0x04,
47 AUDIO_STATUS_EMPHASIS = 0x08, 47 AUDIO_STATUS_EMPHASIS = 0x08,
48 AUDIO_STATUS_COPYRIGHT = 0x10, 48 AUDIO_STATUS_COPYRIGHT = 0x10,
49 AUDIO_STATUS_NONAUDIO = 0x20, 49 AUDIO_STATUS_NONAUDIO = 0x20,
50 AUDIO_STATUS_PROFESSIONAL = 0x40, 50 AUDIO_STATUS_PROFESSIONAL = 0x40,
51 AUDIO_STATUS_LEVEL = 0x80 51 AUDIO_STATUS_LEVEL = 0x80
52}; 52};
53 53
54struct { 54struct {
@@ -85,7 +85,7 @@ struct {
85static void r600_hdmi_calc_CTS(uint32_t clock, int *CTS, int N, int freq) 85static void r600_hdmi_calc_CTS(uint32_t clock, int *CTS, int N, int freq)
86{ 86{
87 if (*CTS == 0) 87 if (*CTS == 0)
88 *CTS = clock*N/(128*freq)*1000; 88 *CTS = clock * N / (128 * freq) * 1000;
89 DRM_DEBUG("Using ACR timing N=%d CTS=%d for frequency %d\n", 89 DRM_DEBUG("Using ACR timing N=%d CTS=%d for frequency %d\n",
90 N, *CTS, freq); 90 N, *CTS, freq);
91} 91}
@@ -131,11 +131,11 @@ static void r600_hdmi_infoframe_checksum(uint8_t packetType,
131 uint8_t length, 131 uint8_t length,
132 uint8_t *frame) 132 uint8_t *frame)
133{ 133{
134 int i; 134 int i;
135 frame[0] = packetType + versionNumber + length; 135 frame[0] = packetType + versionNumber + length;
136 for (i = 1; i <= length; i++) 136 for (i = 1; i <= length; i++)
137 frame[0] += frame[i]; 137 frame[0] += frame[i];
138 frame[0] = 0x100 - frame[0]; 138 frame[0] = 0x100 - frame[0];
139} 139}
140 140
141/* 141/*
@@ -314,6 +314,9 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod
314 struct radeon_device *rdev = dev->dev_private; 314 struct radeon_device *rdev = dev->dev_private;
315 uint32_t offset = to_radeon_encoder(encoder)->hdmi_offset; 315 uint32_t offset = to_radeon_encoder(encoder)->hdmi_offset;
316 316
317 if (ASIC_IS_DCE4(rdev))
318 return;
319
317 if (!offset) 320 if (!offset)
318 return; 321 return;
319 322
@@ -417,90 +420,147 @@ void r600_hdmi_update_audio_settings(struct drm_encoder *encoder,
417 WREG32_P(offset+R600_HDMI_CNTL, 0x04000000, ~0x04000000); 420 WREG32_P(offset+R600_HDMI_CNTL, 0x04000000, ~0x04000000);
418} 421}
419 422
420/* 423static int r600_hdmi_find_free_block(struct drm_device *dev)
421 * enable/disable the HDMI engine 424{
422 */ 425 struct radeon_device *rdev = dev->dev_private;
423void r600_hdmi_enable(struct drm_encoder *encoder, int enable) 426 struct drm_encoder *encoder;
427 struct radeon_encoder *radeon_encoder;
428 bool free_blocks[3] = { true, true, true };
429
430 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
431 radeon_encoder = to_radeon_encoder(encoder);
432 switch (radeon_encoder->hdmi_offset) {
433 case R600_HDMI_BLOCK1:
434 free_blocks[0] = false;
435 break;
436 case R600_HDMI_BLOCK2:
437 free_blocks[1] = false;
438 break;
439 case R600_HDMI_BLOCK3:
440 free_blocks[2] = false;
441 break;
442 }
443 }
444
445 if (rdev->family == CHIP_RS600 || rdev->family == CHIP_RS690) {
446 return free_blocks[0] ? R600_HDMI_BLOCK1 : 0;
447 } else if (rdev->family >= CHIP_R600) {
448 if (free_blocks[0])
449 return R600_HDMI_BLOCK1;
450 else if (free_blocks[1])
451 return R600_HDMI_BLOCK2;
452 }
453 return 0;
454}
455
456static void r600_hdmi_assign_block(struct drm_encoder *encoder)
424{ 457{
425 struct drm_device *dev = encoder->dev; 458 struct drm_device *dev = encoder->dev;
426 struct radeon_device *rdev = dev->dev_private; 459 struct radeon_device *rdev = dev->dev_private;
427 struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 460 struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
428 uint32_t offset = to_radeon_encoder(encoder)->hdmi_offset; 461 struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
429 462
430 if (!offset) 463 if (!dig) {
464 dev_err(rdev->dev, "Enabling HDMI on non-dig encoder\n");
431 return; 465 return;
466 }
432 467
433 DRM_DEBUG("%s HDMI interface @ 0x%04X\n", enable ? "Enabling" : "Disabling", offset); 468 if (ASIC_IS_DCE4(rdev)) {
434 469 /* TODO */
435 /* some version of atombios ignore the enable HDMI flag 470 } else if (ASIC_IS_DCE3(rdev)) {
436 * so enabling/disabling HDMI was moved here for TMDS1+2 */ 471 radeon_encoder->hdmi_offset = dig->dig_encoder ?
437 switch (radeon_encoder->encoder_id) { 472 R600_HDMI_BLOCK3 : R600_HDMI_BLOCK1;
438 case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: 473 if (ASIC_IS_DCE32(rdev))
439 WREG32_P(AVIVO_TMDSA_CNTL, enable ? 0x4 : 0x0, ~0x4); 474 radeon_encoder->hdmi_config_offset = dig->dig_encoder ?
440 WREG32(offset+R600_HDMI_ENABLE, enable ? 0x101 : 0x0); 475 R600_HDMI_CONFIG2 : R600_HDMI_CONFIG1;
441 break; 476 } else if (rdev->family >= CHIP_R600) {
442 477 radeon_encoder->hdmi_offset = r600_hdmi_find_free_block(dev);
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:
449 case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
450 case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
451 case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
452 /* This part is doubtfull in my opinion */
453 WREG32(offset+R600_HDMI_ENABLE, enable ? 0x110 : 0x0);
454 break;
455
456 default:
457 DRM_ERROR("unknown HDMI output type\n");
458 break;
459 } 478 }
460} 479}
461 480
462/* 481/*
463 * determin at which register offset the HDMI encoder is 482 * enable the HDMI engine
464 */ 483 */
465void r600_hdmi_init(struct drm_encoder *encoder) 484void r600_hdmi_enable(struct drm_encoder *encoder)
466{ 485{
486 struct drm_device *dev = encoder->dev;
487 struct radeon_device *rdev = dev->dev_private;
467 struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 488 struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
468 489
469 switch (radeon_encoder->encoder_id) { 490 if (ASIC_IS_DCE4(rdev))
470 case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: 491 return;
471 case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 492
472 case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 493 if (!radeon_encoder->hdmi_offset) {
473 radeon_encoder->hdmi_offset = R600_HDMI_TMDS1; 494 r600_hdmi_assign_block(encoder);
474 break; 495 if (!radeon_encoder->hdmi_offset) {
475 496 dev_warn(rdev->dev, "Could not find HDMI block for "
476 case ENCODER_OBJECT_ID_INTERNAL_LVTM1: 497 "0x%x encoder\n", radeon_encoder->encoder_id);
477 switch (r600_audio_tmds_index(encoder)) { 498 return;
478 case 0: 499 }
479 radeon_encoder->hdmi_offset = R600_HDMI_TMDS1; 500 }
501
502 if (ASIC_IS_DCE32(rdev) && !ASIC_IS_DCE4(rdev)) {
503 WREG32_P(radeon_encoder->hdmi_config_offset + 0x4, 0x1, ~0x1);
504 } else if (rdev->family >= CHIP_R600 && !ASIC_IS_DCE3(rdev)) {
505 int offset = radeon_encoder->hdmi_offset;
506 switch (radeon_encoder->encoder_id) {
507 case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
508 WREG32_P(AVIVO_TMDSA_CNTL, 0x4, ~0x4);
509 WREG32(offset + R600_HDMI_ENABLE, 0x101);
480 break; 510 break;
481 case 1: 511 case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
482 radeon_encoder->hdmi_offset = R600_HDMI_TMDS2; 512 WREG32_P(AVIVO_LVTMA_CNTL, 0x4, ~0x4);
513 WREG32(offset + R600_HDMI_ENABLE, 0x105);
483 break; 514 break;
484 default: 515 default:
485 radeon_encoder->hdmi_offset = 0; 516 dev_err(rdev->dev, "Unknown HDMI output type\n");
486 break; 517 break;
487 } 518 }
488 case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 519 }
489 radeon_encoder->hdmi_offset = R600_HDMI_TMDS2; 520
490 break; 521 DRM_DEBUG("Enabling HDMI interface @ 0x%04X for encoder 0x%x\n",
522 radeon_encoder->hdmi_offset, radeon_encoder->encoder_id);
523}
524
525/*
526 * disable the HDMI engine
527 */
528void r600_hdmi_disable(struct drm_encoder *encoder)
529{
530 struct drm_device *dev = encoder->dev;
531 struct radeon_device *rdev = dev->dev_private;
532 struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
491 533
492 case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: 534 if (ASIC_IS_DCE4(rdev))
493 radeon_encoder->hdmi_offset = R600_HDMI_DIG; 535 return;
494 break;
495 536
496 default: 537 if (!radeon_encoder->hdmi_offset) {
497 radeon_encoder->hdmi_offset = 0; 538 dev_err(rdev->dev, "Disabling not enabled HDMI\n");
498 break; 539 return;
499 } 540 }
500 541
501 DRM_DEBUG("using HDMI engine at offset 0x%04X for encoder 0x%x\n", 542 DRM_DEBUG("Disabling HDMI interface @ 0x%04X for encoder 0x%x\n",
502 radeon_encoder->hdmi_offset, radeon_encoder->encoder_id); 543 radeon_encoder->hdmi_offset, radeon_encoder->encoder_id);
544
545 if (ASIC_IS_DCE32(rdev) && !ASIC_IS_DCE4(rdev)) {
546 WREG32_P(radeon_encoder->hdmi_config_offset + 0x4, 0, ~0x1);
547 } else if (rdev->family >= CHIP_R600 && !ASIC_IS_DCE3(rdev)) {
548 int offset = radeon_encoder->hdmi_offset;
549 switch (radeon_encoder->encoder_id) {
550 case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
551 WREG32_P(AVIVO_TMDSA_CNTL, 0, ~0x4);
552 WREG32(offset + R600_HDMI_ENABLE, 0);
553 break;
554 case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
555 WREG32_P(AVIVO_LVTMA_CNTL, 0, ~0x4);
556 WREG32(offset + R600_HDMI_ENABLE, 0);
557 break;
558 default:
559 dev_err(rdev->dev, "Unknown HDMI output type\n");
560 break;
561 }
562 }
503 563
504 /* TODO: make this configureable */ 564 radeon_encoder->hdmi_offset = 0;
505 radeon_encoder->hdmi_audio_workaround = 0; 565 radeon_encoder->hdmi_config_offset = 0;
506} 566}