This is one more patchset bringing minor improvements to the current HDMI implementation. I think after this step I'll start working on moving Evergreen HDMI code to the separated file. Some cleanups and making ACR re-usable were needed before that.
Patches depend on the earlier 5-patches-set I sent yesterday.
Again, tested on RV620 and HD6320. Unfortunately I don't have DCE32 card or sth to test code in r600_hdmi_enable/r600_hdmi_disable (pre DCE3).
P.S. I'm leaving civilization for the rest of this week.
Rafał Miłecki (3): drm/radeon/kms/hdmi: enable audio packets at one place drm/radeon/kms/hdmi: clean&improve handling HDMI mode drm/radeon/kms/hdmi: helper getting ready ACR entry
drivers/gpu/drm/radeon/r600_hdmi.c | 129 +++++++++++++++++++---------------- drivers/gpu/drm/radeon/radeon.h | 14 ++++ 2 files changed, 84 insertions(+), 59 deletions(-)
--- drivers/gpu/drm/radeon/r600_hdmi.c | 26 ++++++++++++++++---------- 1 files changed, 16 insertions(+), 10 deletions(-)
diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c index c6de0022..69839df 100644 --- a/drivers/gpu/drm/radeon/r600_hdmi.c +++ b/drivers/gpu/drm/radeon/r600_hdmi.c @@ -303,11 +303,13 @@ void r600_hdmi_audio_workaround(struct drm_encoder *encoder) r600_hdmi_is_audio_buffer_filled(encoder)) {
/* disable audio workaround */ - WREG32_P(HDMI0_AUDIO_PACKET_CONTROL + offset, 0x0001, ~0x1001); + WREG32_P(HDMI0_AUDIO_PACKET_CONTROL + offset, + 0, ~HDMI0_AUDIO_TEST_EN);
} else { /* enable audio workaround */ - WREG32_P(HDMI0_AUDIO_PACKET_CONTROL + offset, 0x1001, ~0x1001); + WREG32_P(HDMI0_AUDIO_PACKET_CONTROL + offset, + HDMI0_AUDIO_TEST_EN, ~HDMI0_AUDIO_TEST_EN); } }
@@ -331,6 +333,18 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod
WREG32(HDMI0_AUDIO_CRC_CONTROL + offset, 0x1000); WREG32(HDMI0_GC + offset, 0x0); + + /* Send audio packets */ + if (ASIC_IS_DCE4(rdev)) + WREG32_P(0x74fc + offset, + AFMT_AUDIO_SAMPLE_SEND, ~AFMT_AUDIO_SAMPLE_SEND); + else if (ASIC_IS_DCE32(rdev)) + WREG32_P(AFMT_AUDIO_PACKET_CONTROL + offset, + AFMT_AUDIO_SAMPLE_SEND, ~AFMT_AUDIO_SAMPLE_SEND); + else + WREG32_P(HDMI0_AUDIO_PACKET_CONTROL + offset, + HDMI0_AUDIO_SAMPLE_SEND, ~HDMI0_AUDIO_SAMPLE_SEND); + WREG32(HDMI0_ACR_PACKET_CONTROL + offset, 0x1000);
r600_hdmi_update_ACR(encoder, mode->clock); @@ -495,10 +509,6 @@ void r600_hdmi_enable(struct drm_encoder *encoder) offset = radeon_encoder->hdmi_offset; if (ASIC_IS_DCE5(rdev)) { /* TODO */ - } else if (ASIC_IS_DCE4(rdev)) { - WREG32_P(0x74fc + radeon_encoder->hdmi_offset, 0x1, ~0x1); - } else if (ASIC_IS_DCE32(rdev)) { - WREG32_P(AFMT_AUDIO_PACKET_CONTROL + radeon_encoder->hdmi_offset, 0x1, ~0x1); } else if (ASIC_IS_DCE3(rdev)) { /* TODO */ } else if (rdev->family >= CHIP_R600) { @@ -558,10 +568,6 @@ void r600_hdmi_disable(struct drm_encoder *encoder)
if (ASIC_IS_DCE5(rdev)) { /* TODO */ - } else if (ASIC_IS_DCE4(rdev)) { - WREG32_P(0x74fc + radeon_encoder->hdmi_offset, 0, ~0x1); - } else if (ASIC_IS_DCE32(rdev)) { - WREG32_P(AFMT_AUDIO_PACKET_CONTROL + radeon_encoder->hdmi_offset, 0, ~0x1); } else if (rdev->family >= CHIP_R600 && !ASIC_IS_DCE3(rdev)) { switch (radeon_encoder->encoder_id) { case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
--- drivers/gpu/drm/radeon/r600_hdmi.c | 42 +++++++++++++++++++++++------------ 1 files changed, 27 insertions(+), 15 deletions(-)
diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c index 69839df..7d24753 100644 --- a/drivers/gpu/drm/radeon/r600_hdmi.c +++ b/drivers/gpu/drm/radeon/r600_hdmi.c @@ -493,6 +493,7 @@ void r600_hdmi_enable(struct drm_encoder *encoder) struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); uint32_t offset; + u32 hdmi;
if (ASIC_IS_DCE5(rdev)) return; @@ -507,26 +508,34 @@ void r600_hdmi_enable(struct drm_encoder *encoder) }
offset = radeon_encoder->hdmi_offset; - if (ASIC_IS_DCE5(rdev)) { - /* TODO */ - } else if (ASIC_IS_DCE3(rdev)) { - /* TODO */ - } else if (rdev->family >= CHIP_R600) { + + /* Older chipsets require setting HDMI and routing manually */ + if (rdev->family >= CHIP_R600 && !ASIC_IS_DCE3(rdev)) { + hdmi = HDMI0_ERROR_ACK | HDMI0_ENABLE; switch (radeon_encoder->encoder_id) { case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: WREG32_P(AVIVO_TMDSA_CNTL, AVIVO_TMDSA_CNTL_HDMI_EN, ~AVIVO_TMDSA_CNTL_HDMI_EN); - WREG32(HDMI0_CONTROL + offset, 0x101); + hdmi |= HDMI0_STREAM(HDMI0_STREAM_TMDSA); break; case ENCODER_OBJECT_ID_INTERNAL_LVTM1: WREG32_P(AVIVO_LVTMA_CNTL, AVIVO_LVTMA_CNTL_HDMI_EN, ~AVIVO_LVTMA_CNTL_HDMI_EN); - WREG32(HDMI0_CONTROL + offset, 0x105); + hdmi |= HDMI0_STREAM(HDMI0_STREAM_LVTMA); + break; + case ENCODER_OBJECT_ID_INTERNAL_DDI: + WREG32_P(DDIA_CNTL, DDIA_HDMI_EN, ~DDIA_HDMI_EN); + hdmi |= HDMI0_STREAM(HDMI0_STREAM_DDIA); + break; + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + hdmi |= HDMI0_STREAM(HDMI0_STREAM_DVOA); break; default: - dev_err(rdev->dev, "Unknown HDMI output type\n"); + dev_err(rdev->dev, "Invalid encoder for HDMI: 0x%X\n", + radeon_encoder->encoder_id); break; } + WREG32(HDMI0_CONTROL + offset, hdmi); }
if (rdev->irq.installed) { @@ -565,25 +574,28 @@ void r600_hdmi_disable(struct drm_encoder *encoder) rdev->irq.afmt[offset == 0 ? 0 : 1] = false; radeon_irq_set(rdev);
- - if (ASIC_IS_DCE5(rdev)) { - /* TODO */ - } else if (rdev->family >= CHIP_R600 && !ASIC_IS_DCE3(rdev)) { + /* Older chipsets not handled by AtomBIOS */ + if (rdev->family >= CHIP_R600 && !ASIC_IS_DCE3(rdev)) { switch (radeon_encoder->encoder_id) { case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: WREG32_P(AVIVO_TMDSA_CNTL, 0, ~AVIVO_TMDSA_CNTL_HDMI_EN); - WREG32(HDMI0_CONTROL + offset, 0); break; case ENCODER_OBJECT_ID_INTERNAL_LVTM1: WREG32_P(AVIVO_LVTMA_CNTL, 0, ~AVIVO_LVTMA_CNTL_HDMI_EN); - WREG32(HDMI0_CONTROL + offset, 0); + break; + case ENCODER_OBJECT_ID_INTERNAL_DDI: + WREG32_P(DDIA_CNTL, 0, ~DDIA_HDMI_EN); + break; + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: break; default: - dev_err(rdev->dev, "Unknown HDMI output type\n"); + dev_err(rdev->dev, "Invalid encoder for HDMI: 0x%X\n", + radeon_encoder->encoder_id); break; } + WREG32(HDMI0_CONTROL + offset, HDMI0_ERROR_ACK); }
radeon_encoder->hdmi_enabled = false;
--- drivers/gpu/drm/radeon/r600_hdmi.c | 61 ++++++++++++++++-------------------- drivers/gpu/drm/radeon/radeon.h | 14 ++++++++ 2 files changed, 41 insertions(+), 34 deletions(-)
diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c index 7d24753..0319619 100644 --- a/drivers/gpu/drm/radeon/r600_hdmi.c +++ b/drivers/gpu/drm/radeon/r600_hdmi.c @@ -53,19 +53,7 @@ enum r600_hdmi_iec_status_bits { AUDIO_STATUS_LEVEL = 0x80 };
-struct { - uint32_t Clock; - - int N_32kHz; - int CTS_32kHz; - - int N_44_1kHz; - int CTS_44_1kHz; - - int N_48kHz; - int CTS_48kHz; - -} r600_hdmi_ACR[] = { +struct radeon_hdmi_acr r600_hdmi_predefined_acr[] = { /* 32kHz 44.1kHz 48kHz */ /* Clock N CTS N CTS N CTS */ { 25174, 4576, 28125, 7007, 31250, 6864, 28125 }, /* 25,20/1.001 MHz */ @@ -84,7 +72,7 @@ struct { /* * calculate CTS value if it's not found in the table */ -static void r600_hdmi_calc_CTS(uint32_t clock, int *CTS, int N, int freq) +static void r600_hdmi_calc_cts(uint32_t clock, int *CTS, int N, int freq) { if (*CTS == 0) *CTS = clock * N / (128 * freq) * 1000; @@ -92,6 +80,24 @@ static void r600_hdmi_calc_CTS(uint32_t clock, int *CTS, int N, int freq) N, *CTS, freq); }
+struct radeon_hdmi_acr r600_hdmi_acr(uint32_t clock) +{ + struct radeon_hdmi_acr res; + u8 i; + + for (i = 0; r600_hdmi_predefined_acr[i].clock != clock && + r600_hdmi_predefined_acr[i].clock != 0; i++) + ; + res = r600_hdmi_predefined_acr[i]; + + /* In case some CTS are missing */ + r600_hdmi_calc_cts(clock, &res.cts_32khz, res.n_32khz, 32000); + r600_hdmi_calc_cts(clock, &res.cts_44_1khz, res.n_44_1khz, 44100); + r600_hdmi_calc_cts(clock, &res.cts_48khz, res.n_48khz, 48000); + + return res; +} + /* * update the N and CTS parameters for a given pixel clock rate */ @@ -99,30 +105,17 @@ static void r600_hdmi_update_ACR(struct drm_encoder *encoder, uint32_t clock) { struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; + struct radeon_hdmi_acr acr = r600_hdmi_acr(clock); uint32_t offset = to_radeon_encoder(encoder)->hdmi_offset; - int CTS; - int N; - int i; - - for (i = 0; r600_hdmi_ACR[i].Clock != clock && r600_hdmi_ACR[i].Clock != 0; i++);
- CTS = r600_hdmi_ACR[i].CTS_32kHz; - N = r600_hdmi_ACR[i].N_32kHz; - r600_hdmi_calc_CTS(clock, &CTS, N, 32000); - WREG32(HDMI0_ACR_32_0 + offset, HDMI0_ACR_CTS_32(CTS)); - WREG32(HDMI0_ACR_32_1 + offset, N); + WREG32(HDMI0_ACR_32_0 + offset, HDMI0_ACR_CTS_32(acr.cts_32khz)); + WREG32(HDMI0_ACR_32_1 + offset, acr.n_32khz);
- CTS = r600_hdmi_ACR[i].CTS_44_1kHz; - N = r600_hdmi_ACR[i].N_44_1kHz; - r600_hdmi_calc_CTS(clock, &CTS, N, 44100); - WREG32(HDMI0_ACR_44_0 + offset, HDMI0_ACR_CTS_44(CTS)); - WREG32(HDMI0_ACR_44_1 + offset, N); + WREG32(HDMI0_ACR_44_0 + offset, HDMI0_ACR_CTS_44(acr.cts_44_1khz)); + WREG32(HDMI0_ACR_44_1 + offset, acr.n_44_1khz);
- CTS = r600_hdmi_ACR[i].CTS_48kHz; - N = r600_hdmi_ACR[i].N_48kHz; - r600_hdmi_calc_CTS(clock, &CTS, N, 48000); - WREG32(HDMI0_ACR_48_0 + offset, HDMI0_ACR_CTS_48(CTS)); - WREG32(HDMI0_ACR_48_1 + offset, N); + WREG32(HDMI0_ACR_48_0 + offset, HDMI0_ACR_CTS_48(acr.cts_48khz)); + WREG32(HDMI0_ACR_48_1 + offset, acr.n_48khz); }
/* diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 610acee..71779c8 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1860,6 +1860,20 @@ int r600_fmt_get_nblocksy(u32 format, u32 h); /* * r600 functions used by radeon_encoder.c */ +struct radeon_hdmi_acr { + u32 clock; + + int n_32khz; + int cts_32khz; + + int n_44_1khz; + int cts_44_1khz; + + int n_48khz; + int cts_48khz; + +}; + extern void r600_hdmi_enable(struct drm_encoder *encoder); extern void r600_hdmi_disable(struct drm_encoder *encoder); extern void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode);
2012/4/30 Rafał Miłecki zajec5@gmail.com:
This is one more patchset bringing minor improvements to the current HDMI implementation. I think after this step I'll start working on moving Evergreen HDMI code to the separated file. Some cleanups and making ACR re-usable were needed before that.
Patches depend on the earlier 5-patches-set I sent yesterday.
Again, tested on RV620 and HD6320. Unfortunately I don't have DCE32 card or sth to test code in r600_hdmi_enable/r600_hdmi_disable (pre DCE3).
P.S. I'm leaving civilization for the rest of this week.
For both sets:
Reviewed-by: Alex Deucher alexdeucher@gmail.com
Rafał Miłecki (3): drm/radeon/kms/hdmi: enable audio packets at one place drm/radeon/kms/hdmi: clean&improve handling HDMI mode drm/radeon/kms/hdmi: helper getting ready ACR entry
drivers/gpu/drm/radeon/r600_hdmi.c | 129 +++++++++++++++++++---------------- drivers/gpu/drm/radeon/radeon.h | 14 ++++ 2 files changed, 84 insertions(+), 59 deletions(-)
-- 1.7.7
dri-devel@lists.freedesktop.org