diff mbox

[2/3] drm/radeon: clean up audio dto programming

Message ID 1366299343-28669-3-git-send-email-alexdeucher@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Alex Deucher April 18, 2013, 3:35 p.m. UTC
From: Alex Deucher <alexander.deucher@amd.com>

Split into DCE2/3 and DCE4/5 variants. Still todo is to
calculate the DTO dividers properly.  Add proper formula
to the comments.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/evergreen_hdmi.c |   26 +++++++++++++-
 drivers/gpu/drm/radeon/r600_audio.c     |   59 -------------------------------
 drivers/gpu/drm/radeon/r600_hdmi.c      |   26 +++++++++++++-
 drivers/gpu/drm/radeon/radeon_asic.h    |    1 -
 4 files changed, 50 insertions(+), 62 deletions(-)

Comments

Rafał Miłecki April 19, 2013, 6:10 a.m. UTC | #1
2013/4/18  <alexdeucher@gmail.com>:
> -       switch (radeon_encoder->encoder_id) {
> -       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
> -       case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
> -               WREG32_P(R600_AUDIO_TIMING, 0, ~0x301);
> -               break;
> -       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
> -       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
> -       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
> -       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
> -               WREG32_P(R600_AUDIO_TIMING, 0x100, ~0x301);
> -               break;
> -       default:
> -               dev_err(rdev->dev, "Unsupported encoder type 0x%02X\n",
> -                         radeon_encoder->encoder_id);
> -               return;
> -       }

Are you sure we can just drop that part?

I'd appreciate waiting with this patch until next week, I'll test it
over the weekend on my RV620.
Alex Deucher April 19, 2013, 1:51 p.m. UTC | #2
On Fri, Apr 19, 2013 at 2:10 AM, Rafa? Mi?ecki <zajec5@gmail.com> wrote:
> 2013/4/18  <alexdeucher@gmail.com>:
>> -       switch (radeon_encoder->encoder_id) {
>> -       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
>> -       case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
>> -               WREG32_P(R600_AUDIO_TIMING, 0, ~0x301);
>> -               break;
>> -       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
>> -       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
>> -       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
>> -       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
>> -               WREG32_P(R600_AUDIO_TIMING, 0x100, ~0x301);
>> -               break;
>> -       default:
>> -               dev_err(rdev->dev, "Unsupported encoder type 0x%02X\n",
>> -                         radeon_encoder->encoder_id);
>> -               return;
>> -       }
>
> Are you sure we can just drop that part?

Yes we should be able to drop that part.  The only relevant bits are
9:8 which allows you to force which DTO is used by the audio block.  0
= auto, 1 = force dto0, 2 = force dto1.  Additionally, that register
doesn't exist on evergreen and newer.  On evergreen and newer there is
a DIG PHY register at the same offset which may explain the display
problems some people are experiencing.

>
> I'd appreciate waiting with this patch until next week, I'll test it
> over the weekend on my RV620.

Sounds good.

Alex
Rafał Miłecki April 21, 2013, 7:54 p.m. UTC | #3
2013/4/19 Alex Deucher <alexdeucher@gmail.com>:
> On Fri, Apr 19, 2013 at 2:10 AM, Rafa? Mi?ecki <zajec5@gmail.com> wrote:
>> 2013/4/18  <alexdeucher@gmail.com>:
>>> -       switch (radeon_encoder->encoder_id) {
>>> -       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
>>> -       case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
>>> -               WREG32_P(R600_AUDIO_TIMING, 0, ~0x301);
>>> -               break;
>>> -       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
>>> -       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
>>> -       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
>>> -       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
>>> -               WREG32_P(R600_AUDIO_TIMING, 0x100, ~0x301);
>>> -               break;
>>> -       default:
>>> -               dev_err(rdev->dev, "Unsupported encoder type 0x%02X\n",
>>> -                         radeon_encoder->encoder_id);
>>> -               return;
>>> -       }
>>
>> Are you sure we can just drop that part?
>
> Yes we should be able to drop that part.  The only relevant bits are
> 9:8 which allows you to force which DTO is used by the audio block.  0
> = auto, 1 = force dto0, 2 = force dto1.  Additionally, that register
> doesn't exist on evergreen and newer.  On evergreen and newer there is
> a DIG PHY register at the same offset which may explain the display
> problems some people are experiencing.
>
>>
>> I'd appreciate waiting with this patch until next week, I'll test it
>> over the weekend on my RV620.
>
> Sounds good.

Due to problems with running fglrx I didn't manage to test that patch
over weekend.

As you see some docs and know that registers, I hope this patch is
fine. In case of problems we can always easy revert the problematic
part :)
Rafał Miłecki April 22, 2013, 5:43 a.m. UTC | #4
2013/4/19 Alex Deucher <alexdeucher@gmail.com>:
> On Fri, Apr 19, 2013 at 2:10 AM, Rafa? Mi?ecki <zajec5@gmail.com> wrote:
>> 2013/4/18  <alexdeucher@gmail.com>:
>>> -       switch (radeon_encoder->encoder_id) {
>>> -       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
>>> -       case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
>>> -               WREG32_P(R600_AUDIO_TIMING, 0, ~0x301);
>>> -               break;
>>> -       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
>>> -       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
>>> -       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
>>> -       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
>>> -               WREG32_P(R600_AUDIO_TIMING, 0x100, ~0x301);
>>> -               break;
>>> -       default:
>>> -               dev_err(rdev->dev, "Unsupported encoder type 0x%02X\n",
>>> -                         radeon_encoder->encoder_id);
>>> -               return;
>>> -       }
>>
>> Are you sure we can just drop that part?
>
> Yes we should be able to drop that part.  The only relevant bits are
> 9:8 which allows you to force which DTO is used by the audio block.  0
> = auto, 1 = force dto0, 2 = force dto1.  Additionally, that register
> doesn't exist on evergreen and newer.  On evergreen and newer there is
> a DIG PHY register at the same offset which may explain the display
> problems some people are experiencing.

For now I can only say that fglrx seems to be changing that 0x7344:

RREG32(0x00000534); -> 0x00000001	DCCG_AUDIO_DTO_SELECT
WREG32(0x00000534, 0x00000000);		DCCG_AUDIO_DTO_SELECT

RREG32(0x00007344); -> 0x00000270
WREG32(0x00007344, 0x00000170);

RREG32(0x00000518); -> 0x00000000	DCCG_AUDIO_DTO0_MODULE
WREG32(0x00000518, 0x00e297d0);		DCCG_AUDIO_DTO0_MODULE
RREG32(0x00000514); -> 0x00000000	DCCG_AUDIO_DTO0_PHASE
WREG32(0x00000514, 0x00249f00);		DCCG_AUDIO_DTO0_PHASE

I can't say how well radeon is going to work without that, just
informing you about fglrx.
Alex Deucher April 22, 2013, 12:38 p.m. UTC | #5
On Mon, Apr 22, 2013 at 1:43 AM, Rafa? Mi?ecki <zajec5@gmail.com> wrote:
> 2013/4/19 Alex Deucher <alexdeucher@gmail.com>:
>> On Fri, Apr 19, 2013 at 2:10 AM, Rafa? Mi?ecki <zajec5@gmail.com> wrote:
>>> 2013/4/18  <alexdeucher@gmail.com>:
>>>> -       switch (radeon_encoder->encoder_id) {
>>>> -       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
>>>> -       case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
>>>> -               WREG32_P(R600_AUDIO_TIMING, 0, ~0x301);
>>>> -               break;
>>>> -       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
>>>> -       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
>>>> -       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
>>>> -       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
>>>> -               WREG32_P(R600_AUDIO_TIMING, 0x100, ~0x301);
>>>> -               break;
>>>> -       default:
>>>> -               dev_err(rdev->dev, "Unsupported encoder type 0x%02X\n",
>>>> -                         radeon_encoder->encoder_id);
>>>> -               return;
>>>> -       }
>>>
>>> Are you sure we can just drop that part?
>>
>> Yes we should be able to drop that part.  The only relevant bits are
>> 9:8 which allows you to force which DTO is used by the audio block.  0
>> = auto, 1 = force dto0, 2 = force dto1.  Additionally, that register
>> doesn't exist on evergreen and newer.  On evergreen and newer there is
>> a DIG PHY register at the same offset which may explain the display
>> problems some people are experiencing.
>
> For now I can only say that fglrx seems to be changing that 0x7344:
>
> RREG32(0x00000534); -> 0x00000001       DCCG_AUDIO_DTO_SELECT
> WREG32(0x00000534, 0x00000000);         DCCG_AUDIO_DTO_SELECT

Selects DTO0.

>
> RREG32(0x00007344); -> 0x00000270
> WREG32(0x00007344, 0x00000170);

Force audio to use DTO0.  I think "auto" should work, but I can add
this back for dce2/3 if you'd prefer.

>
> RREG32(0x00000518); -> 0x00000000       DCCG_AUDIO_DTO0_MODULE
> WREG32(0x00000518, 0x00e297d0);         DCCG_AUDIO_DTO0_MODULE
> RREG32(0x00000514); -> 0x00000000       DCCG_AUDIO_DTO0_PHASE
> WREG32(0x00000514, 0x00249f00);         DCCG_AUDIO_DTO0_PHASE
>

Set the DTO0 dividers.

> I can't say how well radeon is going to work without that, just
> informing you about fglrx.

There are two dtos, you can use either one. AUDIO_DTO_SELECT selects
whether you are using DTO0 or DTO1.  The dtos determine how the audio
signal is encoded so that it can be reconstructed in the sink.

24Mhz / pixel clock = AUDIO_DTO0_PHASE / AUDIO_DTO0_MODULE

The current code needs to be updated to calculate this properly at some point.

Alex
diff mbox

Patch

diff --git a/drivers/gpu/drm/radeon/evergreen_hdmi.c b/drivers/gpu/drm/radeon/evergreen_hdmi.c
index 380933b..9fc22ee 100644
--- a/drivers/gpu/drm/radeon/evergreen_hdmi.c
+++ b/drivers/gpu/drm/radeon/evergreen_hdmi.c
@@ -85,6 +85,30 @@  static void evergreen_hdmi_update_avi_infoframe(struct drm_encoder *encoder,
 		frame[0xC] | (frame[0xD] << 8));
 }
 
+static void evergreen_audio_set_dto(struct drm_encoder *encoder, u32 clock)
+{
+	struct drm_device *dev = encoder->dev;
+	struct radeon_device *rdev = dev->dev_private;
+	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+	struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
+	u32 base_rate = 48000;
+
+	if (!dig || !dig->afmt)
+		return;
+
+	/* XXX: properly calculate this */
+	/* XXX two dtos; generally use dto0 for hdmi */
+	/* Express [24MHz / target pixel clock] as an exact rational
+	 * number (coefficient of two integer numbers.  DCCG_AUDIO_DTOx_PHASE
+	 * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
+	 */
+	WREG32(DCCG_AUDIO_DTO0_PHASE, (base_rate*50) & 0xffffff);
+	WREG32(DCCG_AUDIO_DTO0_MODULE, (clock*100) & 0xffffff);
+	WREG32(DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO0_SOURCE_SEL(radeon_crtc->crtc_id));
+}
+
+
 /*
  * update the info frames with the data from the current display mode
  */
@@ -104,7 +128,7 @@  void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode
 		return;
 	offset = dig->afmt->offset;
 
-	r600_audio_set_clock(encoder, mode->clock);
+	evergreen_audio_set_dto(encoder, mode->clock);
 
 	WREG32(HDMI_VBI_PACKET_CONTROL + offset,
 	       HDMI_NULL_SEND); /* send null packets when required */
diff --git a/drivers/gpu/drm/radeon/r600_audio.c b/drivers/gpu/drm/radeon/r600_audio.c
index 72561e4..c92eb86 100644
--- a/drivers/gpu/drm/radeon/r600_audio.c
+++ b/drivers/gpu/drm/radeon/r600_audio.c
@@ -181,65 +181,6 @@  int r600_audio_init(struct radeon_device *rdev)
 }
 
 /*
- * atach the audio codec to the clock source of the encoder
- */
-void r600_audio_set_clock(struct drm_encoder *encoder, int clock)
-{
-	struct drm_device *dev = encoder->dev;
-	struct radeon_device *rdev = dev->dev_private;
-	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
-	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
-	struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
-	int base_rate = 48000;
-
-	switch (radeon_encoder->encoder_id) {
-	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
-	case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
-		WREG32_P(R600_AUDIO_TIMING, 0, ~0x301);
-		break;
-	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
-	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
-	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
-	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
-		WREG32_P(R600_AUDIO_TIMING, 0x100, ~0x301);
-		break;
-	default:
-		dev_err(rdev->dev, "Unsupported encoder type 0x%02X\n",
-			  radeon_encoder->encoder_id);
-		return;
-	}
-
-	if (ASIC_IS_DCE4(rdev)) {
-		/* TODO: other PLLs? */
-		WREG32(EVERGREEN_AUDIO_PLL1_MUL, base_rate * 10);
-		WREG32(EVERGREEN_AUDIO_PLL1_DIV, clock * 10);
-		WREG32(EVERGREEN_AUDIO_PLL1_UNK, 0x00000071);
-
-		/* Select DTO source */
-		WREG32(0x5ac, radeon_crtc->crtc_id);
-	} else {
-		switch (dig->dig_encoder) {
-		case 0:
-			WREG32(R600_AUDIO_PLL1_MUL, base_rate * 50);
-			WREG32(R600_AUDIO_PLL1_DIV, clock * 100);
-			WREG32(R600_AUDIO_CLK_SRCSEL, 0);
-			break;
-
-		case 1:
-			WREG32(R600_AUDIO_PLL2_MUL, base_rate * 50);
-			WREG32(R600_AUDIO_PLL2_DIV, clock * 100);
-			WREG32(R600_AUDIO_CLK_SRCSEL, 1);
-			break;
-		default:
-			dev_err(rdev->dev,
-				"Unsupported DIG on encoder 0x%02X\n",
-				radeon_encoder->encoder_id);
-			return;
-		}
-	}
-}
-
-/*
  * release the audio timer
  * TODO: How to do this correctly on SMP systems?
  */
diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c
index 95397b2..62721bf 100644
--- a/drivers/gpu/drm/radeon/r600_hdmi.c
+++ b/drivers/gpu/drm/radeon/r600_hdmi.c
@@ -226,6 +226,30 @@  static void r600_hdmi_audio_workaround(struct drm_encoder *encoder)
 		 value, ~HDMI0_AUDIO_TEST_EN);
 }
 
+void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock)
+{
+	struct drm_device *dev = encoder->dev;
+	struct radeon_device *rdev = dev->dev_private;
+	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+	u32 base_rate = 48000;
+
+	if (!dig || !dig->afmt)
+		return;
+
+	/* there are two DTOs selected by DCCG_AUDIO_DTO_SELECT.
+	 * doesn't matter which one you use.  Just use the first one.
+	 */
+	/* XXX: properly calculate this */
+	/* XXX two dtos; generally use dto0 for hdmi */
+	/* Express [24MHz / target pixel clock] as an exact rational
+	 * number (coefficient of two integer numbers.  DCCG_AUDIO_DTOx_PHASE
+	 * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
+	 */
+	WREG32(DCCG_AUDIO_DTO0_PHASE, (base_rate*50) & 0xffffff);
+	WREG32(DCCG_AUDIO_DTO0_MODULE, (clock*100) & 0xffffff);
+	WREG32(DCCG_AUDIO_DTO_SELECT, 0); /* select DTO0 */
+}
 
 /*
  * update the info frames with the data from the current display mode
@@ -246,7 +270,7 @@  void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod
 		return;
 	offset = dig->afmt->offset;
 
-	r600_audio_set_clock(encoder, mode->clock);
+	r600_audio_set_dto(encoder, mode->clock);
 
 	WREG32(HDMI0_VBI_PACKET_CONTROL + offset,
 	       HDMI0_NULL_SEND); /* send null packets when required */
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index 2add526..fa8b8bf 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -374,7 +374,6 @@  void r600_disable_interrupts(struct radeon_device *rdev);
 void r600_rlc_stop(struct radeon_device *rdev);
 /* r600 audio */
 int r600_audio_init(struct radeon_device *rdev);
-void r600_audio_set_clock(struct drm_encoder *encoder, int clock);
 struct r600_audio r600_audio_status(struct radeon_device *rdev);
 void r600_audio_fini(struct radeon_device *rdev);
 int r600_hdmi_buffer_status_changed(struct drm_encoder *encoder);