[RFH] Add HDMI audio support
Luis R. Rodriguez
lrodriguez at atheros.com
Fri Jul 24 10:24:41 PDT 2009
This is based on radeonhd driver, this is a port to radeon.
Cc: Egbert Eich <eich at novell.com>
Cc: Matthias Hopf <mhopf at novell.com>
Cc: Luc Verhaegen <libv at exsuse.de>
Cc: Christian König <deathsimple at vodafone.de>
Signed-off-by: Luis R. Rodriguez <mcgrof at gmail.com>
---
RFT - Request For Help/patch takeover
I've taken a stab at porting HDMI support from the radeonhd driver
onto the radeon driver. Mind you this is my first video patch, so
not sure if it was done properly. I kept telling myself I was going
to finish this during my night hours but my night hours are now reserved.
So if it is at least done some-what right was hoping someone could take this
on themselves and complete it... The missing piece should be the
generic HDMI stuff which I thought was not required but in fact is.
Forgot if I compile tested.. definitely didn't try loading yet.
I just rebased this onto today's git HEAD.
I do have an HD4800 which I can test.
Anyway, hope someone with more time can take this over.
src/atombios_output.c | 2 +
src/radeon.h | 96 ++++++++++
src/radeon_atombios.c | 17 ++
src/radeon_hdmi_audio.c | 442 +++++++++++++++++++++++++++++++++++++++++++++++
src/radeon_macros.h | 3 +
src/radeon_probe.h | 1 +
src/radeon_reg.h | 6 +
7 files changed, 567 insertions(+), 0 deletions(-)
create mode 100644 src/radeon_hdmi_audio.c
diff --git a/src/atombios_output.c b/src/atombios_output.c
index 00d17cb..73196c0 100644
--- a/src/atombios_output.c
+++ b/src/atombios_output.c
@@ -1509,6 +1509,8 @@ atombios_output_mode_set(xf86OutputPtr output,
atombios_output_dig_encoder_setup(output, ATOM_ENABLE);
atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_SETUP);
atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_ENABLE);
+ if (atombios_get_encoder_mode(output) == ATOM_ENCODER_MODE_HDMI)
+ radeon_hdmi_audio_register();
break;
case ENCODER_OBJECT_ID_INTERNAL_DDI:
atombios_output_ddia_setup(output, ATOM_ENABLE);
diff --git a/src/radeon.h b/src/radeon.h
index 3c62fd9..7d280e5 100644
--- a/src/radeon.h
+++ b/src/radeon.h
@@ -1,6 +1,11 @@
/*
* Copyright 2000 ATI Technologies Inc., Markham, Ontario, and
* VA Linux Systems Inc., Fremont, California.
+ * Copyright 2008 Christian König <deathsimple at vodafone.de>
+ * Copyright 2007 Luc Verhaegen <libv at exsuse.de>
+ * Copyright 2007 Matthias Hopf <mhopf at novell.com>
+ * Copyright 2007 Egbert Eich <eich at novell.com>
+ * Copyright 2007 Advanced Micro Devices, Inc.
*
* All Rights Reserved.
*
@@ -775,6 +780,34 @@ struct radeon_accel_state {
};
+struct radeon_hdmi_audio {
+
+ int scrnIndex;
+
+ //struct rhdHdmi* Registered;
+ OsTimerPtr Timer;
+
+ Bool SavedPlaying;
+ int SavedChannels;
+ int SavedRate;
+ int SavedBitsPerSample;
+ CARD8 SavedStatusBits;
+ CARD8 SavedCategoryCode;
+
+ Bool Stored;
+
+ CARD32 StoreEnabled;
+ CARD32 StoreTiming;
+ CARD32 StoreSupportedSizeRate;
+ CARD32 StoreSupportedCodec;
+
+ CARD32 StorePll1Mul;
+ CARD32 StorePll1Div;
+ CARD32 StorePll2Mul;
+ CARD32 StorePll2Div;
+ CARD32 StoreClockSrcSel;
+};
+
typedef struct {
EntityInfoPtr pEnt;
pciVideoPtr PciInfo;
@@ -979,6 +1012,7 @@ typedef struct {
float igp_system_mclk;
float igp_ht_link_clk;
float igp_ht_link_width;
+ struct radeon_hdmi_audio *hdmi_audio;
int can_resize;
void (*reemit_current2d)(ScrnInfoPtr pScrn, int op); // emit the current 2D state into the IB
@@ -1005,6 +1039,53 @@ typedef struct {
int bicubic_offset;
} RADEONInfoRec, *RADEONInfoPtr;
+/*
+ * used for config value of radeon_hmdi_audio_set_supported
+ */
+enum {
+ AUDIO_RATE_8000_HZ = 0x00000001,
+ AUDIO_RATE_11025_HZ = 0x00000002,
+ AUDIO_RATE_16000_HZ = 0x00000004,
+ AUDIO_RATE_22050_HZ = 0x00000008,
+ AUDIO_RATE_32000_HZ = 0x00000010,
+ AUDIO_RATE_44100_HZ = 0x00000020,
+ AUDIO_RATE_48000_HZ = 0x00000040,
+ AUDIO_RATE_88200_HZ = 0x00000080,
+ AUDIO_RATE_96000_HZ = 0x00000100,
+ AUDIO_RATE_176400_HZ = 0x00000200,
+ AUDIO_RATE_192000_HZ = 0x00000400,
+ AUDIO_RATE_384000_HZ = 0x00000800,
+
+ AUDIO_BPS_8 = 0x00010000,
+ AUDIO_BPS_16 = 0x00020000,
+ AUDIO_BPS_20 = 0x00040000,
+ AUDIO_BPS_24 = 0x00080000,
+ AUDIO_BPS_32 = 0x00100000
+};
+
+/*
+ * used for codec value of radeon_hmdi_audio_set_supported
+ */
+enum {
+ AUDIO_CODEC_PCM = 0x00000001,
+ AUDIO_CODEC_FLOAT32 = 0x00000002,
+ AUDIO_CODEC_AC3 = 0x00000004
+};
+
+/*
+ * used for status bist value in radeon_update_hdmi_audio
+ */
+enum {
+ AUDIO_STATUS_DIG_ENABLE = 0x01,
+ AUDIO_STATUS_V = 0x02,
+ AUDIO_STATUS_VCFG = 0x04,
+ AUDIO_STATUS_EMPHASIS = 0x08,
+ AUDIO_STATUS_COPYRIGHT = 0x10,
+ AUDIO_STATUS_NONAUDIO = 0x20,
+ AUDIO_STATUS_PROFESSIONAL = 0x40,
+ AUDIO_STATUS_LEVEL = 0x80
+};
+
#define RADEONWaitForFifo(pScrn, entries) \
do { \
if (info->accel_state->fifo_slots < entries) \
@@ -1284,6 +1365,21 @@ extern void radeon_ddx_cs_start(ScrnInfoPtr pScrn,
struct radeon_bo *radeon_get_pixmap_bo(PixmapPtr pPix);
void radeon_set_pixmap_bo(PixmapPtr pPix, struct radeon_bo *bo);
+/* radeon_hdmi_audio.c */
+extern void radeon_hdmi_audio_init(RHDPtr rhdPtr);
+
+extern void radeon_hdmi_audio_set_supported(RHDPtr rhdPtr, Bool clear, CARD32 config, CARD32 codec);
+extern void radeon_hdmi_audio_set_enable(RHDPtr rhdPtr, Bool Enable);
+extern void radeon_hdmi_audio_set_clock(RHDPtr rhdPtr, struct rhdOutput* Output, CARD32 Clock);
+
+extern void radeon_hdmi_audio_register(RHDPtr rhdPtr, struct rhdHdmi* rhdHdmi);
+extern void radeon_hdmi_audio_unregister(RHDPtr rhdPtr, struct rhdHdmi* rhdHdmi);
+
+extern void radeon_hdmi_audio_save(RHDPtr rhdPtr);
+extern void radeon_hdmi_audio_restore(RHDPtr rhdPtr);
+
+extern void radeon_hdmi_audio_destroy(RHDPtr rhdPtr);
+
#ifdef XF86DRI
# ifdef USE_XAA
/* radeon_accelfuncs.c */
diff --git a/src/radeon_atombios.c b/src/radeon_atombios.c
index f590d5b..ff8c11d 100644
--- a/src/radeon_atombios.c
+++ b/src/radeon_atombios.c
@@ -1771,6 +1771,23 @@ radeon_add_encoder(ScrnInfoPtr pScrn, uint32_t encoder_id, uint32_t device_suppo
}
break;
}
+
+ /* This time around we'll just set the HDMI offset */
+ switch (encoder_id) {
+ case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+ info->encoders[device_index]->hdmi_offset = RADEON_HDMI_TMDS;
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
+ info->encoders[device_index]->hdmi_offset = RADEON_HDMI_LVTMA;
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
+ info->encoders[device_index]->hdmi_offset = RADEON_HDMI_DIG;
+ break;
+ default:
+ info->encoders[device_index]->hdmi_offset = 0;
+ break;
+ }
return TRUE;
} else {
ErrorF("xalloc failed\n");
diff --git a/src/radeon_hdmi_audio.c b/src/radeon_hdmi_audio.c
new file mode 100644
index 0000000..931cb6d
--- /dev/null
+++ b/src/radeon_hdmi_audio.c
@@ -0,0 +1,442 @@
+/*
+ * Copyright 2009 Luis R. Rodriguez <mcgrof at gmail.com>
+ * Copyright 2008 Christian König <deathsimple at vodafone.de>
+ * Copyright 2007 Luc Verhaegen <libv at exsuse.de>
+ * Copyright 2007 Matthias Hopf <mhopf at novell.com>
+ * Copyright 2007 Egbert Eich <eich at novell.com>
+ * Copyright 2007 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "radeon.h"
+
+#define RADEON_HDMI_AUDIO_TIMER_INTERVALL 100 /* 1/10 sekund should be enough */
+
+/*
+ * current number of channels
+ */
+static int radeon_hdmi_audio_channels(xf86OutputPtr output)
+{
+ RADEONInfoPtr info = RADEONPTR(output->scrn);
+ unsigned char *RADEONMMIO = info->MMIO;
+ return (INREG(AUDIO_RATE_BPS_CHANNEL) & 0x7) + 1;
+}
+
+/*
+ * current bits per sample
+ */
+static int radeon_hdmi_audio_bits_per_sample(xf86OutputPtr output)
+{
+ RADEONOutputPrivatePtr radeon_output = output->driver_private;
+ struct radeon_hdmi_audio *Audio = radeon_output->hdmi_audio;
+ RADEONInfoPtr info = RADEONPTR(output->scrn);
+ unsigned char *RADEONMMIO = info->MMIO;
+
+ CARD32 value = (INREG(AUDIO_RATE_BPS_CHANNEL) & 0xF0) >> 4;
+ switch(value)
+ {
+ case 0x0: return 8;
+ case 0x1: return 16;
+ case 0x2: return 20;
+ case 0x3: return 24;
+ case 0x4: return 32;
+ }
+
+ xf86DrvMsg(Audio->scrnIndex, X_WARNING, "%s: unknown bits per sample 0x%x "
+ "using 16 instead.\n", __func__, (int) value);
+
+ return 16;
+}
+
+/*
+ * current sampling rate in HZ
+ */
+static int radeon_hdmi_audio_rate(xf86OutputPtr output)
+{
+ RADEONInfoPtr info = RADEONPTR(output->scrn);
+ unsigned char *RADEONMMIO = info->MMIO;
+
+ CARD32 value = INREG(AUDIO_RATE_BPS_CHANNEL);
+ CARD32 result;
+
+ if(value & 0x4000)
+ result = 44100;
+ else
+ result = 48000;
+
+ result *= ((value >> 11) & 0x7) + 1;
+ result /= ((value >> 8) & 0x7) + 1;
+
+ return result;
+}
+
+/*
+ * something playing ?
+ */
+static Bool radeon_hdmi_audio_playing(xf86OutputPtr output)
+{
+ RADEONInfoPtr info = RADEONPTR(output->scrn);
+ unsigned char *RADEONMMIO = info->MMIO;
+ return (INREG(AUDIO_PLAYING) >> 4) & 1;
+}
+
+/*
+ * iec 60958 status bits
+ */
+static CARD8 radeon_hdmi_audio_status_bits(xf86OutputPtr output)
+{
+ RADEONInfoPtr info = RADEONPTR(output->scrn);
+ unsigned char *RADEONMMIO = info->MMIO;
+ return INREG(AUDIO_STATUS_BITS) & 0xff;
+}
+
+/*
+ * iec 60958 category code
+ */
+static CARD8 radeon_hdmi_audio_category_code(xf86OutputPtr output)
+{
+ RADEONInfoPtr info = RADEONPTR(output->scrn);
+ unsigned char *RADEONMMIO = info->MMIO;
+ return (INREG(AUDIO_STATUS_BITS) >> 8) & 0xff;
+}
+
+/*
+ * update all registered hdmi interfaces with current audio parameters
+ */
+static CARD32 radeon_timer_hdmi_audio(OsTimerPtr timer, CARD32 time, pointer ptr)
+{
+ struct radeon_hdmi_audio *Audio = (struct radeon_hdmi_audio*)ptr;
+ Bool playing = radeon_hdmi_audio_playing(Audio);
+ int channels = radeon_hdmi_audio_hannels(Audio);
+ int rate = radeon_hdmi_audio_rate(Audio);
+ int bps = radeon_hdmi_audio_bits_per_sample(Audio);
+ CARD8 status_bits = radeon_audio_status_bits(Audio);
+ CARD8 category_code = radeon_audio_category_code(Audio);
+
+ struct rhdHdmi* hdmi;
+
+ if (playing != Audio->SavedPlaying ||
+ channels != Audio->SavedChannels ||
+ rate != Audio->SavedRate ||
+ bps != Audio->SavedBitsPerSample ||
+ status_bits != Audio->SavedStatusBits ||
+ category_code != Audio->SavedCategoryCode) {
+
+ Audio->SavedPlaying = playing;
+ Audio->SavedChannels = channels;
+ Audio->SavedRate = rate;
+ Audio->SavedBitsPerSample = bps;
+ Audio->SavedStatusBits = status_bits;
+ Audio->SavedCategoryCode = category_code;
+
+ /* XXX: port hdmi struct usage */
+ for (hdmi=Audio->Registered; hdmi != NULL; hdmi=hdmi->Next)
+ radeon_hdmi_update_audio_settings(
+ hdmi, playing, channels,
+ rate, bps, status_bits,
+ category_code);
+ }
+
+ return RADEON_HDMI_AUDIO_TIMER_INTERVALL;
+}
+
+/*
+ * allocate and init the audio structure
+ */
+void
+radeon_hdmi_audio_init(xf86OutputPtr output)
+{
+ RADEONInfoPtr info = RADEONPTR(output->scrn);
+ RADEONOutputPrivatePtr radeon_output = output->driver_private;
+ struct radeon_hdmi_audio *Audio;
+
+ if (info->ChipFamily < CHIP_FAMILY_RS600) {
+ radeon_output->Audio = NULL;
+ return;
+ }
+
+ Audio = (struct radeon_hdmi_audio *) xnfcalloc(sizeof(struct radeon_hdmi_audio), 1);
+ Audio->scrnIndex = info->atomBIOS->scrnIndex;
+ Audio->Registered = NULL;
+ Audio->Stored = FALSE;
+
+ radeon_output->Audio = Audio;
+}
+
+/*
+ * enable or disable the complete audio engine
+ */
+void
+radeon_hdmi_audio_set_enable(xf86OutputPtr output, Bool Enable)
+{
+ RADEONOutputPrivatePtr radeon_output = output->driver_private;
+ struct radeon_hdmi_audio *Audio = radeon_output->hdmi_audio;
+
+ if (!Audio)
+ return;
+
+ REG_RMW(AUDIO_ENABLE, Enable ? 0x80000000 : 0x0, 0x80000000);
+ if (!Enable) {
+ TimerFree(Audio->Timer);
+ Audio->Timer = NULL;
+ return;
+ }
+
+ /*
+ * the hardware generates an interrupt if audio starts/stops playing,
+ * but since drm doesn't support this interrupt, we check
+ * every RADEON_HDMI_AUDIO_TIMER_INTERVALL ms if something has changed
+ */
+
+ Audio->SavedChannels = -1;
+ Audio->SavedRate = -1;
+ Audio->SavedBitsPerSample = -1;
+ Audio->SavedStatusBits = 0;
+ Audio->SavedCategoryCode = 0;
+ Audio->Timer = TimerSet(NULL, 0, RADEON_HDMI_AUDIO_TIMER_INTERVALL,
+ radeon_hdmi_audio_update, Audio);
+
+ /* 48kHz and 16/20 bits per sample are always supported */
+ radeon_hdmi_audio_set_supported(output, TRUE,
+ AUDIO_RATE_48000_HZ |
+ AUDIO_BPS_16 |
+ AUDIO_BPS_20,
+ AUDIO_CODEC_PCM);
+}
+
+/*
+ * programm the audio clock and timing registers
+ */
+void
+radeon_hdmi_audio_set_clock(xf86OutputPtr output, CARD32 Clock)
+{
+ RADEONOutputPrivatePtr radeon_output = output->driver_private;
+ struct radeon_hdmi_audio *Audio = radeon_output->hdmi_audio;
+ radeon_encoder_ptr radeon_encoder;
+ RADEONInfoPtr info = RADEONPTR(output->scrn);
+ unsigned char *RADEONMMIO = info->MMIO;
+
+ int Rate = 48000;
+
+ if (!Audio)
+ return;
+
+ radeon_encoder = radeon_get_encoder(output);
+
+ xf86DrvMsg(Audio->scrnIndex, X_INFO, "%s: using %s as clock source with %d khz\n",
+ __func__,
+ device_name[radeon_get_device_index(radeon_output->active_device)],
+ (int) Clock);
+
+ switch(radeon_encoder->encoder_id) {
+ case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
+ case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
+ REG_RMW(AUDIO_TIMING, 0, 0x301);
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
+ REG_RMW(AUDIO_TIMING, 0x100, 0x301);
+ break;
+
+ default:
+ break;
+ }
+
+ switch(radeon_encoder->encoder_id) {
+ case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+ OUTREG(AUDIO_PLL1_MUL, Rate*50);
+ OUTREG(AUDIO_PLL1_DIV, Clock*100);
+ OUTREG(AUDIO_CLK_SRCSEL, 0);
+ break;
+
+ case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
+ OUTREG(AUDIO_PLL2_MUL, Rate*50);
+ OUTREG(AUDIO_PLL2_DIV, Clock*100);
+ OUTREG(AUDIO_CLK_SRCSEL, 1);
+ break;
+
+ default:
+ xf86DrvMsg(Audio->scrnIndex, X_ERROR, "%s: unsupported output type\n", __func__);
+ break;
+ }
+}
+
+/*
+ * set the supported audio rates, bits per sample and codecs
+ */
+void
+radeon_hdmi_audio_set_supported(xf86OutputPtr output, Bool clear, CARD32 config, CARD32 codec)
+{
+ RADEONOutputPrivatePtr radeon_output = output->driver_private;
+ struct radeon_hdmi_audio *Audio = radeon_output->hdmi_audio;
+ RADEONInfoPtr info = RADEONPTR(output->scrn);
+ unsigned char *RADEONMMIO = info->MMIO;
+
+ if (!Audio)
+ return;
+
+ xf86DrvMsg(Audio->scrnIndex, X_INFO, "%s: config 0x%x codec 0x%x\n",
+ __func__, (int) config, (int) codec);
+
+ if(config & 0xFFE0F000)
+ xf86DrvMsg(Audio->scrnIndex, X_WARNING, "%s: reserved config bits set 0x%x\n",
+ __func__, (int) config);
+
+ if(codec & 0xFFFFFFF8)
+ xf86DrvMsg(Audio->scrnIndex, X_WARNING, "%s: reserved codec bits set 0x%x\n",
+ __func__, (int) codec);
+
+ if (clear) {
+ OUTREG(AUDIO_SUPPORTED_SIZE_RATE, config);
+ OUTREG(AUDIO_SUPPORTED_CODEC, codec);
+ } else {
+ OUTREG(AUDIO_SUPPORTED_SIZE_RATE, config, config);
+ OUTREG(AUDIO_SUPPORTED_CODEC, codec, codec);
+ }
+}
+
+/*
+ * register and hdmi interface for getting updates when audio parameters change.
+ * The right approach here is to use DRM interrupts for Audio updates but until
+ * DRM does not suppor that we use a timer to update it regularly.
+ */
+void radeon_hdmi_audio_register(xf86OutputPtr output, struct rhdHdmi* rhdHdmi)
+{
+ RADEONOutputPrivatePtr radeon_output = output->driver_private;
+ struct radeon_hdmi_audio *Audio = radeon_output->hdmi_audio;
+
+ if (!Audio)
+ return;
+
+ /* XXX: How to port rhdHmdi to ati driver from radeonhd */
+ if(!rhdHdmi)
+ return;
+
+ rhdHdmi->Next = Audio->Registered;
+ Audio->Registered = rhdHdmi;
+}
+
+
+/*
+ * unregister the hdmi interface
+ */
+void radeon_hdmi_audio_unregister(xf86OutputPtr output, struct rhdHdmi* rhdHdmi)
+{
+ RADEONOutputPrivatePtr radeon_output = output->driver_private;
+ struct radeon_hdmi_audio *Audio = radeon_output->hdmi_audio;
+ struct rhdHdmi** hdmiPtr;
+
+ if (!Audio)
+ return;
+
+ for (hdmiPtr=&Audio->Registered; hdmiPtr!=NULL; hdmiPtr=&(*hdmiPtr)->Next) {
+ if(*hdmiPtr != rhdHdmi)
+ continue;
+ *hdmiPtr = rhdHdmi->Next;
+ rhdHdmi->Next = NULL;
+ return;
+ }
+
+}
+
+/*
+ * save the current config of audio engine
+ */
+void
+radeon_hdmi_audio_save(xf86OutputPtr output)
+{
+ RADEONOutputPrivatePtr radeon_output = output->driver_private;
+ struct radeon_hdmi_audio *Audio = radeon_output->hdmi_audio;
+ unsigned char *RADEONMMIO = info->MMIO;
+
+ if (!Audio)
+ return;
+
+ Audio->StoreEnabled = INREG(AUDIO_ENABLE);
+ Audio->StoreTiming = INREG(AUDIO_TIMING);
+
+ Audio->StoreSupportedSizeRate = INREG(AUDIO_SUPPORTED_SIZE_RATE);
+ Audio->StoreSupportedCodec = INREG(AUDIO_SUPPORTED_CODEC);
+
+ Audio->StorePll1Mul = INREG(AUDIO_PLL1_MUL);
+ Audio->StorePll1Div = INREG(AUDIO_PLL1_DIV);
+ Audio->StorePll2Mul = INREG(AUDIO_PLL2_MUL);
+ Audio->StorePll2Div = INREG(AUDIO_PLL2_DIV);
+ Audio->StoreClockSrcSel = INREG(AUDIO_CLK_SRCSEL);
+
+ Audio->Stored = TRUE;
+}
+
+/*
+ * restore the saved config of audio engine
+ */
+void
+radeon_hdmi_audio_restore(xf86OutputPtr output)
+{
+ RADEONOutputPrivatePtr radeon_output = output->driver_private;
+ struct radeon_hdmi_audio *Audio = radeon_output->hdmi_audio;
+ RADEONInfoPtr info = RADEONPTR(output->scrn);
+ unsigned char *RADEONMMIO = info->MMIO;
+
+ if (!Audio)
+ return;
+
+ if (!Audio->Stored) {
+ xf86DrvMsg(Audio->scrnIndex, X_ERROR, "%s: trying to restore "
+ "uninitialized values.\n", __func__);
+ return;
+ }
+
+ /* shoutdown the audio engine before doing anything else */
+ radeon_hdmi_audio_set_enable(output, FALSE);
+
+ OUTREG(AUDIO_TIMING, Audio->StoreTiming);
+ OUTREG(AUDIO_SUPPORTED_SIZE_RATE, Audio->StoreSupportedSizeRate);
+ OUTREG(AUDIO_SUPPORTED_CODEC, Audio->StoreSupportedCodec);
+
+ OUTREG(AUDIO_PLL1_MUL, Audio->StorePll1Mul);
+ OUTREG(AUDIO_PLL1_DIV, Audio->StorePll1Div);
+ OUTREG(AUDIO_PLL2_MUL, Audio->StorePll2Mul);
+ OUTREG(AUDIO_PLL2_DIV, Audio->StorePll2Div);
+ OUTREG(AUDIO_CLK_SRCSEL, Audio->StoreClockSrcSel);
+ OUTREG(AUDIO_ENABLE, Audio->StoreEnabled);
+}
+
+/*
+ * release the allocated memory
+ */
+void
+radeon_hdmi_audio_destroy(xf86OutputPtr output)
+{
+ RADEONOutputPrivatePtr radeon_output = output->driver_private;
+
+ if (!radeon_output->hdmi_audio)
+ return;
+
+ if(radeon_output->hdmi_audio->Timer)
+ TimerFree(radeon_output->hdmi_audio->Timer);
+
+ xfree(radeon_output->hdmi_audio);
+ radeon_output->hdmi_audio = NULL;
+}
diff --git a/src/radeon_macros.h b/src/radeon_macros.h
index 26d9825..a51f2f4 100644
--- a/src/radeon_macros.h
+++ b/src/radeon_macros.h
@@ -69,6 +69,9 @@
#define ADDRREG(addr) ((volatile uint32_t *)(pointer)(RADEONMMIO + (addr)))
+#define REG_RMW(_r, _m, _v) \
+ OUTREG((_r), \
+ (INREG(_r) & ~_m) | ((_v) & _m))
#define OUTREGP(addr, val, mask) \
do { \
diff --git a/src/radeon_probe.h b/src/radeon_probe.h
index 9cac15c..b62f019 100644
--- a/src/radeon_probe.h
+++ b/src/radeon_probe.h
@@ -167,6 +167,7 @@ typedef struct _RADEONCrtcPrivateRec {
typedef struct _radeon_encoder {
uint16_t encoder_id;
int devices;
+ uint32_t hdmi_offset;
void *dev_priv;
} radeon_encoder_rec, *radeon_encoder_ptr;
diff --git a/src/radeon_reg.h b/src/radeon_reg.h
index 9df7fff..0e1e9a4 100644
--- a/src/radeon_reg.h
+++ b/src/radeon_reg.h
@@ -3833,6 +3833,12 @@
#define AVIVO_D2SCL_SCALER_TAP_CONTROL 0x6d94
#define AVIVO_D2SCL_UPDATE 0x6dcc
+/* HDMI offsets */
+#define RADEON_HDMI_TMDS 0x7400
+#define RADEON_HDMI_LVTMA 0x7700
+#define RADEON_HDMI_DIG 0x7800
+
+
#define AVIVO_DDIA_BIT_DEPTH_CONTROL 0x7214
#define AVIVO_DACA_ENABLE 0x7800
--
1.6.3.3
More information about the xorg-driver-ati
mailing list