diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-02 22:40:34 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-02 22:40:34 -0400 |
commit | 20a2078ce7705a6e0722ef5184336eb8657a58d8 (patch) | |
tree | 5b927c96516380aa0ecd68d8a609f7cd72120ad5 /drivers/gpu/drm/radeon/r600_hdmi.c | |
parent | 0279b3c0ada1d78882f24acf94ac4595bd657a89 (diff) | |
parent | 307b9c022720f9de90d58e51743e01e9a42aec59 (diff) |
Merge branch 'drm-next' of git://people.freedesktop.org/~airlied/linux
Pull drm updates from Dave Airlie:
"This is the main drm pull request for 3.10.
Wierd bits:
- OMAP drm changes required OMAP dss changes, in drivers/video, so I
took them in here.
- one more fbcon fix for font handover
- VT switch avoidance in pm code
- scatterlist helpers for gpu drivers - have acks from akpm
Highlights:
- qxl kms driver - driver for the spice qxl virtual GPU
Nouveau:
- fermi/kepler VRAM compression
- GK110/nvf0 modesetting support.
Tegra:
- host1x core merged with 2D engine support
i915:
- vt switchless resume
- more valleyview support
- vblank fixes
- modesetting pipe config rework
radeon:
- UVD engine support
- SI chip tiling support
- GPU registers initialisation from golden values.
exynos:
- device tree changes
- fimc block support
Otherwise:
- bunches of fixes all over the place."
* 'drm-next' of git://people.freedesktop.org/~airlied/linux: (513 commits)
qxl: update to new idr interfaces.
drm/nouveau: fix build with nv50->nvc0
drm/radeon: fix handling of v6 power tables
drm/radeon: clarify family checks in pm table parsing
drm/radeon: consolidate UVD clock programming
drm/radeon: fix UPLL_REF_DIV_MASK definition
radeon: add bo tracking debugfs
drm/radeon: add new richland pci ids
drm/radeon: add some new SI PCI ids
drm/radeon: fix scratch reg handling for UVD fence
drm/radeon: allocate SA bo in the requested domain
drm/radeon: fix possible segfault when parsing pm tables
drm/radeon: fix endian bugs in atom_allocate_fb_scratch()
OMAPDSS: TFP410: return EPROBE_DEFER if the i2c adapter not found
OMAPDSS: VENC: Add error handling for venc_probe_pdata
OMAPDSS: HDMI: Add error handling for hdmi_probe_pdata
OMAPDSS: RFBI: Add error handling for rfbi_probe_pdata
OMAPDSS: DSI: Add error handling for dsi_probe_pdata
OMAPDSS: SDI: Add error handling for sdi_probe_pdata
OMAPDSS: DPI: Add error handling for dpi_probe_pdata
...
Diffstat (limited to 'drivers/gpu/drm/radeon/r600_hdmi.c')
-rw-r--r-- | drivers/gpu/drm/radeon/r600_hdmi.c | 150 |
1 files changed, 71 insertions, 79 deletions
diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c index 21ecc0e12dc4..47f180a79352 100644 --- a/drivers/gpu/drm/radeon/r600_hdmi.c +++ b/drivers/gpu/drm/radeon/r600_hdmi.c | |||
@@ -226,6 +226,39 @@ static void r600_hdmi_audio_workaround(struct drm_encoder *encoder) | |||
226 | value, ~HDMI0_AUDIO_TEST_EN); | 226 | value, ~HDMI0_AUDIO_TEST_EN); |
227 | } | 227 | } |
228 | 228 | ||
229 | void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock) | ||
230 | { | ||
231 | struct drm_device *dev = encoder->dev; | ||
232 | struct radeon_device *rdev = dev->dev_private; | ||
233 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); | ||
234 | struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; | ||
235 | u32 base_rate = 48000; | ||
236 | |||
237 | if (!dig || !dig->afmt) | ||
238 | return; | ||
239 | |||
240 | /* there are two DTOs selected by DCCG_AUDIO_DTO_SELECT. | ||
241 | * doesn't matter which one you use. Just use the first one. | ||
242 | */ | ||
243 | /* XXX: properly calculate this */ | ||
244 | /* XXX two dtos; generally use dto0 for hdmi */ | ||
245 | /* Express [24MHz / target pixel clock] as an exact rational | ||
246 | * number (coefficient of two integer numbers. DCCG_AUDIO_DTOx_PHASE | ||
247 | * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator | ||
248 | */ | ||
249 | if (ASIC_IS_DCE3(rdev)) { | ||
250 | /* according to the reg specs, this should DCE3.2 only, but in | ||
251 | * practice it seems to cover DCE3.0 as well. | ||
252 | */ | ||
253 | WREG32(DCCG_AUDIO_DTO0_PHASE, base_rate * 50); | ||
254 | WREG32(DCCG_AUDIO_DTO0_MODULE, clock * 100); | ||
255 | WREG32(DCCG_AUDIO_DTO_SELECT, 0); /* select DTO0 */ | ||
256 | } else { | ||
257 | /* according to the reg specs, this should be DCE2.0 and DCE3.0 */ | ||
258 | WREG32(AUDIO_DTO, AUDIO_DTO_PHASE(base_rate * 50) | | ||
259 | AUDIO_DTO_MODULE(clock * 100)); | ||
260 | } | ||
261 | } | ||
229 | 262 | ||
230 | /* | 263 | /* |
231 | * update the info frames with the data from the current display mode | 264 | * update the info frames with the data from the current display mode |
@@ -246,7 +279,7 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod | |||
246 | return; | 279 | return; |
247 | offset = dig->afmt->offset; | 280 | offset = dig->afmt->offset; |
248 | 281 | ||
249 | r600_audio_set_clock(encoder, mode->clock); | 282 | r600_audio_set_dto(encoder, mode->clock); |
250 | 283 | ||
251 | WREG32(HDMI0_VBI_PACKET_CONTROL + offset, | 284 | WREG32(HDMI0_VBI_PACKET_CONTROL + offset, |
252 | HDMI0_NULL_SEND); /* send null packets when required */ | 285 | HDMI0_NULL_SEND); /* send null packets when required */ |
@@ -415,114 +448,73 @@ void r600_hdmi_update_audio_settings(struct drm_encoder *encoder) | |||
415 | /* | 448 | /* |
416 | * enable the HDMI engine | 449 | * enable the HDMI engine |
417 | */ | 450 | */ |
418 | void r600_hdmi_enable(struct drm_encoder *encoder) | 451 | void r600_hdmi_enable(struct drm_encoder *encoder, bool enable) |
419 | { | 452 | { |
420 | struct drm_device *dev = encoder->dev; | 453 | struct drm_device *dev = encoder->dev; |
421 | struct radeon_device *rdev = dev->dev_private; | 454 | struct radeon_device *rdev = dev->dev_private; |
422 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); | 455 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
423 | struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; | 456 | struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; |
424 | uint32_t offset; | 457 | u32 hdmi = HDMI0_ERROR_ACK; |
425 | u32 hdmi; | ||
426 | |||
427 | if (ASIC_IS_DCE6(rdev)) | ||
428 | return; | ||
429 | 458 | ||
430 | /* Silent, r600_hdmi_enable will raise WARN for us */ | 459 | /* Silent, r600_hdmi_enable will raise WARN for us */ |
431 | if (dig->afmt->enabled) | 460 | if (enable && dig->afmt->enabled) |
461 | return; | ||
462 | if (!enable && !dig->afmt->enabled) | ||
432 | return; | 463 | return; |
433 | offset = dig->afmt->offset; | ||
434 | 464 | ||
435 | /* Older chipsets require setting HDMI and routing manually */ | 465 | /* Older chipsets require setting HDMI and routing manually */ |
436 | if (rdev->family >= CHIP_R600 && !ASIC_IS_DCE3(rdev)) { | 466 | if (!ASIC_IS_DCE3(rdev)) { |
437 | hdmi = HDMI0_ERROR_ACK | HDMI0_ENABLE; | 467 | if (enable) |
468 | hdmi |= HDMI0_ENABLE; | ||
438 | switch (radeon_encoder->encoder_id) { | 469 | switch (radeon_encoder->encoder_id) { |
439 | case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: | 470 | case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: |
440 | WREG32_P(AVIVO_TMDSA_CNTL, AVIVO_TMDSA_CNTL_HDMI_EN, | 471 | if (enable) { |
441 | ~AVIVO_TMDSA_CNTL_HDMI_EN); | 472 | WREG32_OR(AVIVO_TMDSA_CNTL, AVIVO_TMDSA_CNTL_HDMI_EN); |
442 | hdmi |= HDMI0_STREAM(HDMI0_STREAM_TMDSA); | 473 | hdmi |= HDMI0_STREAM(HDMI0_STREAM_TMDSA); |
474 | } else { | ||
475 | WREG32_AND(AVIVO_TMDSA_CNTL, ~AVIVO_TMDSA_CNTL_HDMI_EN); | ||
476 | } | ||
443 | break; | 477 | break; |
444 | case ENCODER_OBJECT_ID_INTERNAL_LVTM1: | 478 | case ENCODER_OBJECT_ID_INTERNAL_LVTM1: |
445 | WREG32_P(AVIVO_LVTMA_CNTL, AVIVO_LVTMA_CNTL_HDMI_EN, | 479 | if (enable) { |
446 | ~AVIVO_LVTMA_CNTL_HDMI_EN); | 480 | WREG32_OR(AVIVO_LVTMA_CNTL, AVIVO_LVTMA_CNTL_HDMI_EN); |
447 | hdmi |= HDMI0_STREAM(HDMI0_STREAM_LVTMA); | 481 | hdmi |= HDMI0_STREAM(HDMI0_STREAM_LVTMA); |
482 | } else { | ||
483 | WREG32_AND(AVIVO_LVTMA_CNTL, ~AVIVO_LVTMA_CNTL_HDMI_EN); | ||
484 | } | ||
448 | break; | 485 | break; |
449 | case ENCODER_OBJECT_ID_INTERNAL_DDI: | 486 | case ENCODER_OBJECT_ID_INTERNAL_DDI: |
450 | WREG32_P(DDIA_CNTL, DDIA_HDMI_EN, ~DDIA_HDMI_EN); | 487 | if (enable) { |
451 | hdmi |= HDMI0_STREAM(HDMI0_STREAM_DDIA); | 488 | WREG32_OR(DDIA_CNTL, DDIA_HDMI_EN); |
489 | hdmi |= HDMI0_STREAM(HDMI0_STREAM_DDIA); | ||
490 | } else { | ||
491 | WREG32_AND(DDIA_CNTL, ~DDIA_HDMI_EN); | ||
492 | } | ||
452 | break; | 493 | break; |
453 | case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: | 494 | case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: |
454 | hdmi |= HDMI0_STREAM(HDMI0_STREAM_DVOA); | 495 | if (enable) |
496 | hdmi |= HDMI0_STREAM(HDMI0_STREAM_DVOA); | ||
455 | break; | 497 | break; |
456 | default: | 498 | default: |
457 | dev_err(rdev->dev, "Invalid encoder for HDMI: 0x%X\n", | 499 | dev_err(rdev->dev, "Invalid encoder for HDMI: 0x%X\n", |
458 | radeon_encoder->encoder_id); | 500 | radeon_encoder->encoder_id); |
459 | break; | 501 | break; |
460 | } | 502 | } |
461 | WREG32(HDMI0_CONTROL + offset, hdmi); | 503 | WREG32(HDMI0_CONTROL + dig->afmt->offset, hdmi); |
462 | } | 504 | } |
463 | 505 | ||
464 | if (rdev->irq.installed) { | 506 | if (rdev->irq.installed) { |
465 | /* if irq is available use it */ | 507 | /* if irq is available use it */ |
466 | radeon_irq_kms_enable_afmt(rdev, dig->afmt->id); | 508 | /* XXX: shouldn't need this on any asics. Double check DCE2/3 */ |
509 | if (enable) | ||
510 | radeon_irq_kms_enable_afmt(rdev, dig->afmt->id); | ||
511 | else | ||
512 | radeon_irq_kms_disable_afmt(rdev, dig->afmt->id); | ||
467 | } | 513 | } |
468 | 514 | ||
469 | dig->afmt->enabled = true; | 515 | dig->afmt->enabled = enable; |
470 | 516 | ||
471 | DRM_DEBUG("Enabling HDMI interface @ 0x%04X for encoder 0x%x\n", | 517 | DRM_DEBUG("%sabling HDMI interface @ 0x%04X for encoder 0x%x\n", |
472 | offset, radeon_encoder->encoder_id); | 518 | enable ? "En" : "Dis", dig->afmt->offset, radeon_encoder->encoder_id); |
473 | } | 519 | } |
474 | 520 | ||
475 | /* | ||
476 | * disable the HDMI engine | ||
477 | */ | ||
478 | void r600_hdmi_disable(struct drm_encoder *encoder) | ||
479 | { | ||
480 | struct drm_device *dev = encoder->dev; | ||
481 | struct radeon_device *rdev = dev->dev_private; | ||
482 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); | ||
483 | struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; | ||
484 | uint32_t offset; | ||
485 | |||
486 | if (ASIC_IS_DCE6(rdev)) | ||
487 | return; | ||
488 | |||
489 | /* Called for ATOM_ENCODER_MODE_HDMI only */ | ||
490 | if (!dig || !dig->afmt) { | ||
491 | return; | ||
492 | } | ||
493 | if (!dig->afmt->enabled) | ||
494 | return; | ||
495 | offset = dig->afmt->offset; | ||
496 | |||
497 | DRM_DEBUG("Disabling HDMI interface @ 0x%04X for encoder 0x%x\n", | ||
498 | offset, radeon_encoder->encoder_id); | ||
499 | |||
500 | /* disable irq */ | ||
501 | radeon_irq_kms_disable_afmt(rdev, dig->afmt->id); | ||
502 | |||
503 | /* Older chipsets not handled by AtomBIOS */ | ||
504 | if (rdev->family >= CHIP_R600 && !ASIC_IS_DCE3(rdev)) { | ||
505 | switch (radeon_encoder->encoder_id) { | ||
506 | case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: | ||
507 | WREG32_P(AVIVO_TMDSA_CNTL, 0, | ||
508 | ~AVIVO_TMDSA_CNTL_HDMI_EN); | ||
509 | break; | ||
510 | case ENCODER_OBJECT_ID_INTERNAL_LVTM1: | ||
511 | WREG32_P(AVIVO_LVTMA_CNTL, 0, | ||
512 | ~AVIVO_LVTMA_CNTL_HDMI_EN); | ||
513 | break; | ||
514 | case ENCODER_OBJECT_ID_INTERNAL_DDI: | ||
515 | WREG32_P(DDIA_CNTL, 0, ~DDIA_HDMI_EN); | ||
516 | break; | ||
517 | case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: | ||
518 | break; | ||
519 | default: | ||
520 | dev_err(rdev->dev, "Invalid encoder for HDMI: 0x%X\n", | ||
521 | radeon_encoder->encoder_id); | ||
522 | break; | ||
523 | } | ||
524 | WREG32(HDMI0_CONTROL + offset, HDMI0_ERROR_ACK); | ||
525 | } | ||
526 | |||
527 | dig->afmt->enabled = false; | ||
528 | } | ||