Hi everybody,
around 4 weeks ago I've got a new HD 2600 Pro cause the graphics card in
my media/vdr system just stopped working. The main reason for getting
the HD 2600 was that it is able to send the HD Audio via an DVI->HDMI
Adapter directly to my LCD TV.
After some try&error i found out that the sound device of the card is
supported by alsa, but works only with the help of the binary only fglrx
driver. The only problem remaining was that the fglrx driver is SO
FUCKING UNSTABLE that it deadlocks the system aprox every 10 minutes.
So i started to reverse engine what the fglrx driver does to make HDMI
Audio working, with the goal to add this to the radeonhd driver.
At that point i simply assumed that it wasn't more than turning some
bits in an reg on or off. This assumption turns out to be wrong, but
after 3 weeks of debugging i finally got it working.
The following patch is far away from being complete. The Video und Audio
InfoFrames are not calculated correctly and i don't have any clue what
most of the registers are used for and i never worked with git before so
hopefully the patch is in the correct form.
I would really like to complete my work so does anybody have an register
documentation off the Azalia/HDMI engine?
If somebody find this use full please leave me a note and sorry for my
poor English.
cu, Christian.
---
src/Makefile.am | 4 +
src/rhd.h | 1 +
src/rhd_azalia.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++
src/rhd_azalia.h | 54 ++++++++++++++++
src/rhd_driver.c | 9 +++
src/rhd_hdmi.c | 187
++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/rhd_hdmi.h | 50 ++++++++++++++
src/rhd_lvtma.c | 15 ++++-
src/rhd_randr.c | 3 +
src/rhd_regs.h | 42 ++++++++++++
src/rhd_tmds.c | 17 ++++-
11 files changed, 538 insertions(+), 5 deletions(-)
create mode 100644 src/rhd_azalia.c
create mode 100644 src/rhd_azalia.h
create mode 100644 src/rhd_hdmi.c
create mode 100644 src/rhd_hdmi.h
diff --git a/src/Makefile.am b/src/Makefile.am
index 8cd61c7..23e7888 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -34,6 +34,8 @@ radeonhd_drv_la_SOURCES = \
rhd_randr.c \
rhd_dig.c \
rhd_ddia.c \
+ rhd_azalia.c \
+ rhd_hdmi.c \
rhd_atombios.h \
rhd.h \
rhd_i2c.h \
@@ -51,6 +53,8 @@ radeonhd_drv_la_SOURCES = \
rhd_vga.h \
rhd_shadow.h \
rhd_mc.h \
+ rhd_azalia.h \
+ rhd_hdmi.h \
r5xx_accel.c \
r5xx_accel.h \
r5xx_xaa.c \
diff --git a/src/rhd.h b/src/rhd.h
index cbba493..164f7ae 100644
--- a/src/rhd.h
+++ b/src/rhd.h
@@ -252,6 +252,7 @@ typedef struct RHDRec {
struct rhdVGA *VGA; /* VGA compatibility HW */
struct rhdCrtc *Crtc[2];
struct rhdPLL *PLLs[2]; /* Pixelclock PLLs */
+ struct rhdAzalia *Azalia;
struct rhdLUTStore *LUTStore;
struct rhdLUT *LUT[2];
diff --git a/src/rhd_azalia.c b/src/rhd_azalia.c
new file mode 100644
index 0000000..76faf88
--- /dev/null
+++ b/src/rhd_azalia.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2008 Christian König
+ * Copyright 2007 Luc Verhaegen
+ * Copyright 2007 Matthias Hopf
+ * Copyright 2007 Egbert Eich
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "xf86.h"
+
+/* for usleep */
+#if HAVE_XF86_ANSIC_H
+# include "xf86_ansic.h"
+#else
+# include
+#endif
+
+#include "rhd.h"
+#include "rhd_azalia.h"
+#include "rhd_regs.h"
+
+/*
+ *
+ */
+void
+RHDAzaliaInit(RHDPtr rhdPtr)
+{
+ struct rhdAzalia *Azalia;
+
+ RHDFUNC(rhdPtr);
+
+ Azalia = (struct rhdAzalia *) xnfcalloc(sizeof(struct rhdAzalia),
1);
+
+ Azalia->scrnIndex = rhdPtr->scrnIndex;
+ Azalia->StorePll1Mul = 0;
+ Azalia->StorePll1Div = 0;
+ Azalia->StorePll2Mul = 0;
+ Azalia->StorePll2Div = 0;
+ Azalia->StoreClockSrcSel = 0;
+
+ Azalia->Stored = FALSE;
+
+ rhdPtr->Azalia = Azalia;
+}
+
+/*
+ *
+ */
+void
+RHDAzaliaSetClock(RHDPtr rhdPtr, CARD32 Clock)
+{
+ struct rhdAzalia *Azalia = rhdPtr->Azalia;
+ CARD32 AudioRate = 48000;
+
+ RHDRegWrite(Azalia, AZALIA_PLL1_MUL, AudioRate*50);
+ RHDRegWrite(Azalia, AZALIA_PLL1_DIV, Clock*100);
+
+ RHDRegWrite(Azalia, AZALIA_PLL2_MUL, AudioRate*50);
+ RHDRegWrite(Azalia, AZALIA_PLL2_DIV, Clock*100);
+
+ RHDRegWrite(Azalia, AZALIA_CLK_SRCSEL, 0);
+}
+
+/*
+ *
+ */
+void
+RHDAzaliaEnable(RHDPtr rhdPtr, Bool Enable)
+{
+ struct rhdAzalia *Azalia = rhdPtr->Azalia;
+ RHDFUNC(Azalia);
+
+ RHDRegMask(Azalia, AZALIA_ENABLE, Enable ? 0x80000000 : 0x0,
0x80000000);
+ /*
+ RHDRegWrite(Output, AZALIA_UNKNOWN_0, 0x70);
+ RHDRegWrite(Output, AZALIA_UNKNOWN_1, 0x1);
+ */
+}
+
+/*
+ *
+ */
+void
+RHDAzaliaSave(RHDPtr rhdPtr)
+{
+ struct rhdAzalia *Azalia = rhdPtr->Azalia;
+ RHDFUNC(Azalia);
+
+ Azalia->StoreEnabled = RHDRegRead(Azalia, AZALIA_ENABLE) &
0x80000000 ? TRUE : FALSE;
+
+ Azalia->StoreUnknown0 = RHDRegRead(Azalia, AZALIA_UNKNOWN_0);
+ Azalia->StoreUnknown1 = RHDRegRead(Azalia, AZALIA_UNKNOWN_1);
+
+ Azalia->StorePll1Mul = RHDRegRead(Azalia, AZALIA_PLL1_MUL);
+ Azalia->StorePll1Div = RHDRegRead(Azalia, AZALIA_PLL1_DIV);
+ Azalia->StorePll2Mul = RHDRegRead(Azalia, AZALIA_PLL2_MUL);
+ Azalia->StorePll2Div = RHDRegRead(Azalia, AZALIA_PLL2_DIV);
+ Azalia->StoreClockSrcSel = RHDRegRead(Azalia, AZALIA_CLK_SRCSEL);
+
+ Azalia->Stored = TRUE;
+}
+
+/*
+ *
+ */
+void
+RHDAzaliaRestore(RHDPtr rhdPtr)
+{
+ struct rhdAzalia *Azalia = rhdPtr->Azalia;
+ RHDFUNC(Azalia);
+
+ if (!Azalia->Stored) {
+ xf86DrvMsg(Azalia->scrnIndex, X_ERROR, "%s: trying to restore "
+ "uninitialized values.\n", __func__);
+ return;
+ }
+
+ RHDAzaliaEnable(rhdPtr, Azalia->StoreEnabled);
+
+ RHDRegWrite(Azalia, AZALIA_UNKNOWN_0, Azalia->StoreUnknown0);
+ RHDRegWrite(Azalia, AZALIA_UNKNOWN_1, Azalia->StoreUnknown1);
+
+ RHDRegWrite(Azalia, AZALIA_PLL1_MUL, Azalia->StorePll1Mul);
+ RHDRegWrite(Azalia, AZALIA_PLL1_DIV, Azalia->StorePll1Div);
+ RHDRegWrite(Azalia, AZALIA_PLL2_MUL, Azalia->StorePll2Mul);
+ RHDRegWrite(Azalia, AZALIA_PLL2_DIV, Azalia->StorePll2Div);
+ RHDRegWrite(Azalia, AZALIA_CLK_SRCSEL, Azalia->StoreClockSrcSel);
+}
+
+/*
+ *
+ */
+void
+RHDAzaliaDestroy(RHDPtr rhdPtr)
+{
+ RHDFUNC(rhdPtr);
+
+ xfree(rhdPtr->Azalia);
+}
diff --git a/src/rhd_azalia.h b/src/rhd_azalia.h
new file mode 100644
index 0000000..085df3a
--- /dev/null
+++ b/src/rhd_azalia.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2008 Christian König
+ * Copyright 2007 Luc Verhaegen
+ * Copyright 2007 Matthias Hopf
+ * Copyright 2007 Egbert Eich
+ * 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.
+ */
+
+#ifndef _RHD_AZALIA_H
+#define _RHD_AZALIA_H
+
+struct rhdAzalia {
+
+ int scrnIndex;
+
+ Bool Stored;
+ Bool StoreEnabled;
+
+ CARD32 StoreUnknown0;
+ CARD32 StoreUnknown1;
+
+ CARD32 StorePll1Mul;
+ CARD32 StorePll1Div;
+ CARD32 StorePll2Mul;
+ CARD32 StorePll2Div;
+ CARD32 StoreClockSrcSel;
+};
+
+void RHDAzaliaInit(RHDPtr rhdPtr);
+void RHDAzaliaSetClock(RHDPtr rhdPtr, CARD32 Clock);
+void RHDAzaliaEnable(RHDPtr rhdPtr, Bool Enable );
+void RHDAzaliaSave(RHDPtr rhdPtr);
+void RHDAzaliaRestore(RHDPtr rhdPtr);
+void RHDAzaliaDestroy(RHDPtr rhdPtr);
+
+#endif /* _RHD_AZALIA_H */
diff --git a/src/rhd_driver.c b/src/rhd_driver.c
index 3174b9e..186d0f3 100644
--- a/src/rhd_driver.c
+++ b/src/rhd_driver.c
@@ -111,6 +111,7 @@
#include "rhd_shadow.h"
#include "rhd_card.h"
#include "rhd_randr.h"
+#include "rhd_azalia.h"
#include "r5xx_accel.h"
/* ??? */
@@ -318,6 +319,7 @@ RHDFreeRec(ScrnInfoPtr pScrn)
RHDMCDestroy(rhdPtr);
RHDVGADestroy(rhdPtr);
RHDPLLsDestroy(rhdPtr);
+ RHDAzaliaDestroy(rhdPtr);
RHDLUTsDestroy(rhdPtr);
RHDOutputsDestroy(rhdPtr);
RHDConnectorsDestroy(rhdPtr);
@@ -737,6 +739,7 @@ RHDPreInit(ScrnInfoPtr pScrn, int flags)
RHDMCInit(rhdPtr);
RHDCrtcsInit(rhdPtr);
RHDPLLsInit(rhdPtr);
+ RHDAzaliaInit(rhdPtr);
RHDLUTsInit(rhdPtr);
RHDCursorsInit(rhdPtr); /* do this irrespective of hw/sw cursor
setting */
@@ -1982,6 +1985,7 @@ rhdSetMode(ScrnInfoPtr pScrn, DisplayModePtr mode)
if (Crtc->ScaleSet)
Crtc->ScaleSet(Crtc, RHD_CRTC_SCALE_TYPE_NONE, mode, NULL);
RHDPLLSet(Crtc->PLL, mode->Clock);
+ RHDAzaliaSetClock(rhdPtr, mode->Clock);
Crtc->LUTSelect(Crtc, Crtc->LUT);
RHDOutputsMode(rhdPtr, Crtc, mode);
}
@@ -1995,10 +1999,13 @@ rhdSetMode(ScrnInfoPtr pScrn, DisplayModePtr
mode)
if (Crtc->ScaleSet)
Crtc->ScaleSet(Crtc, RHD_CRTC_SCALE_TYPE_NONE, mode, NULL);
RHDPLLSet(Crtc->PLL, mode->Clock);
+ RHDAzaliaSetClock(rhdPtr, mode->Clock);
Crtc->LUTSelect(Crtc, Crtc->LUT);
RHDOutputsMode(rhdPtr, Crtc, mode);
}
+ RHDAzaliaEnable(rhdPtr, TRUE);
+
/* shut down that what we don't use */
RHDPLLsShutdownInactive(rhdPtr);
RHDOutputsShutdownInactive(rhdPtr);
@@ -2033,6 +2040,7 @@ rhdSave(RHDPtr rhdPtr)
RHDOutputsSave(rhdPtr);
RHDPLLsSave(rhdPtr);
+ RHDAzaliaSave(rhdPtr);
RHDLUTsSave(rhdPtr);
rhdPtr->Crtc[0]->Save(rhdPtr->Crtc[0]);
@@ -2056,6 +2064,7 @@ rhdRestore(RHDPtr rhdPtr)
rhdRestoreCursor(pScrn);
RHDPLLsRestore(rhdPtr);
+ RHDAzaliaRestore(rhdPtr);
RHDLUTsRestore(rhdPtr);
RHDVGARestore(rhdPtr);
diff --git a/src/rhd_hdmi.c b/src/rhd_hdmi.c
new file mode 100644
index 0000000..0c7ea59
--- /dev/null
+++ b/src/rhd_hdmi.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2008 Christian König
+ * Copyright 2007 Luc Verhaegen
+ * Copyright 2007 Matthias Hopf
+ * Copyright 2007 Egbert Eich
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "xf86.h"
+
+/* for usleep */
+#if HAVE_XF86_ANSIC_H
+# include "xf86_ansic.h"
+#else
+# include
+#endif
+
+#include "rhd.h"
+#include "rhd_hdmi.h"
+#include "rhd_regs.h"
+
+/*
+ *
+ */
+struct rhdHdmi*
+RHDHdmiInit(RHDPtr rhdPtr, CARD16 Offset)
+{
+ struct rhdHdmi *hdmi;
+ RHDFUNC(rhdPtr);
+
+ hdmi = (struct rhdHdmi *) xnfcalloc(sizeof(struct rhdHdmi), 1);
+ hdmi->scrnIndex = rhdPtr->scrnIndex;
+ hdmi->Offset = Offset;
+ hdmi->Stored = FALSE;
+ return hdmi;
+}
+
+/*
+ *
+ */
+void
+RHDHdmiEnable(struct rhdHdmi *hdmi, Bool Enable)
+{
+ RHDFUNC(hdmi);
+
+ if(!Enable)
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_ENABLE, 0x0);
+ else if(hdmi->Offset == HDMI_TMDSA)
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_ENABLE, 0x101);
+ else if(hdmi->Offset == HDMI_LVTMA)
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_ENABLE, 0x105);
+
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_CNTL, 0x14020011);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_0, 0x31);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_1, 0x93);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_2, 0x202);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_3, 0x0);
+ /*
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_VIDEOINFOFRAME_0, 0xa85ec6);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_VIDEOINFOFRAME_1, 0x1c0004);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_VIDEOINFOFRAME_2, 0x32001d);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_VIDEOINFOFRAME_3, 0x2000034);
+ */
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_VIDEOINFOFRAME_0, 0x0);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_VIDEOINFOFRAME_1, 0x0);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_VIDEOINFOFRAME_2, 0x0);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_VIDEOINFOFRAME_3, 0x0);
+
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_4, 0x1220a000);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_5, 0x1000);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_6, 0x14244000);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_7, 0x1880);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_8, 0x1220a000);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_9, 0x1800);
+ /*
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_AUDIOINFOFRAME_0, 0x170);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_AUDIOINFOFRAME_1, 0x0);
+ */
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_AUDIOINFOFRAME_0, 0x0);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_AUDIOINFOFRAME_1, 0x0);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_A, 0x100000);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_B, 0x200000);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_C, 0x1000);
+}
+
+/*
+ *
+ */
+void
+RHDHdmiSave(struct rhdHdmi *hdmi)
+{
+ RHDFUNC(hdmi);
+
+ hdmi->StoreEnable = RHDRegRead(hdmi, hdmi->Offset+HDMI_ENABLE);
+ hdmi->StoreControl = RHDRegRead(hdmi, hdmi->Offset+HDMI_CNTL);
+ hdmi->StoreUnknown[0x0] = RHDRegRead(hdmi, hdmi->Offset
+HDMI_UNKNOWN_0);
+ hdmi->StoreUnknown[0x1] = RHDRegRead(hdmi, hdmi->Offset
+HDMI_UNKNOWN_1);
+ hdmi->StoreUnknown[0x2] = RHDRegRead(hdmi, hdmi->Offset
+HDMI_UNKNOWN_2);
+ hdmi->StoreUnknown[0x3] = RHDRegRead(hdmi, hdmi->Offset
+HDMI_UNKNOWN_3);
+ hdmi->StoreVideoInfoFrame[0x0] = RHDRegRead(hdmi, hdmi->Offset
+HDMI_VIDEOINFOFRAME_0);
+ hdmi->StoreVideoInfoFrame[0x1] = RHDRegRead(hdmi, hdmi->Offset
+HDMI_VIDEOINFOFRAME_1);
+ hdmi->StoreVideoInfoFrame[0x2] = RHDRegRead(hdmi, hdmi->Offset
+HDMI_VIDEOINFOFRAME_2);
+ hdmi->StoreVideoInfoFrame[0x3] = RHDRegRead(hdmi, hdmi->Offset
+HDMI_VIDEOINFOFRAME_3);
+ hdmi->StoreUnknown[0x4] = RHDRegRead(hdmi, hdmi->Offset
+HDMI_UNKNOWN_4);
+ hdmi->StoreUnknown[0x5] = RHDRegRead(hdmi, hdmi->Offset
+HDMI_UNKNOWN_5);
+ hdmi->StoreUnknown[0x6] = RHDRegRead(hdmi, hdmi->Offset
+HDMI_UNKNOWN_6);
+ hdmi->StoreUnknown[0x7] = RHDRegRead(hdmi, hdmi->Offset
+HDMI_UNKNOWN_7);
+ hdmi->StoreUnknown[0x8] = RHDRegRead(hdmi, hdmi->Offset
+HDMI_UNKNOWN_8);
+ hdmi->StoreUnknown[0x9] = RHDRegRead(hdmi, hdmi->Offset
+HDMI_UNKNOWN_9);
+ hdmi->StoreAudioInfoFrame[0x0] = RHDRegRead(hdmi, hdmi->Offset
+HDMI_AUDIOINFOFRAME_0);
+ hdmi->StoreAudioInfoFrame[0x1] = RHDRegRead(hdmi, hdmi->Offset
+HDMI_AUDIOINFOFRAME_1);
+ hdmi->StoreUnknown[0xa] = RHDRegRead(hdmi, hdmi->Offset
+HDMI_UNKNOWN_A);
+ hdmi->StoreUnknown[0xb] = RHDRegRead(hdmi, hdmi->Offset
+HDMI_UNKNOWN_B);
+ hdmi->StoreUnknown[0xc] = RHDRegRead(hdmi, hdmi->Offset
+HDMI_UNKNOWN_C);
+
+ hdmi->Stored = TRUE;
+}
+
+/*
+ *
+ */
+void
+RHDHdmiRestore(struct rhdHdmi *hdmi)
+{
+ RHDFUNC(hdmi);
+
+ if (!hdmi->Stored) {
+ xf86DrvMsg(hdmi->scrnIndex, X_ERROR, "%s: trying to restore "
+ "uninitialized values.\n", __func__);
+ return;
+ }
+
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_ENABLE, hdmi->StoreEnable);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_CNTL, hdmi->StoreControl);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_0,
hdmi->StoreUnknown[0x0]);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_1,
hdmi->StoreUnknown[0x1]);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_2,
hdmi->StoreUnknown[0x2]);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_3,
hdmi->StoreUnknown[0x3]);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_VIDEOINFOFRAME_0,
hdmi->StoreVideoInfoFrame[0x0]);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_VIDEOINFOFRAME_1,
hdmi->StoreVideoInfoFrame[0x1]);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_VIDEOINFOFRAME_2,
hdmi->StoreVideoInfoFrame[0x2]);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_VIDEOINFOFRAME_3,
hdmi->StoreVideoInfoFrame[0x3]);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_4,
hdmi->StoreUnknown[0x4]);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_5,
hdmi->StoreUnknown[0x5]);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_6,
hdmi->StoreUnknown[0x6]);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_7,
hdmi->StoreUnknown[0x7]);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_8,
hdmi->StoreUnknown[0x8]);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_9,
hdmi->StoreUnknown[0x9]);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_AUDIOINFOFRAME_0,
hdmi->StoreAudioInfoFrame[0x0]);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_AUDIOINFOFRAME_1,
hdmi->StoreAudioInfoFrame[0x1]);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_A,
hdmi->StoreUnknown[0xa]);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_B,
hdmi->StoreUnknown[0xb]);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_C,
hdmi->StoreUnknown[0xc]);
+}
+
+/*
+ *
+ */
+void
+RHDHdmiDestroy(struct rhdHdmi *hdmi)
+{
+ RHDFUNC(hdmi);
+
+ xfree(hdmi);
+}
diff --git a/src/rhd_hdmi.h b/src/rhd_hdmi.h
new file mode 100644
index 0000000..3f0f5a9
--- /dev/null
+++ b/src/rhd_hdmi.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2008 Christian König
+ * Copyright 2007 Luc Verhaegen
+ * Copyright 2007 Matthias Hopf
+ * Copyright 2007 Egbert Eich
+ * 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.
+ */
+
+#ifndef _RHD_HDMI_H
+#define _RHD_HDMI_H
+
+struct rhdHdmi {
+
+ int scrnIndex;
+
+ CARD16 Offset;
+
+ Bool Stored;
+ CARD32 StoreEnable;
+ CARD32 StoreControl;
+ CARD32 StoreUnknown[0xd];
+ CARD32 StoreVideoInfoFrame[0x4];
+ CARD32 StoreAudioInfoFrame[0x2];
+};
+
+struct rhdHdmi* RHDHdmiInit(RHDPtr rhdPtr, CARD16 Offset);
+void RHDHdmiEnable(struct rhdHdmi *rhdHdmi, Bool Enable);
+void RHDHdmiSave(struct rhdHdmi* rhdHdmi);
+void RHDHdmiRestore(struct rhdHdmi* rhdHdmi);
+void RHDHdmiDestroy(struct rhdHdmi* rhdHdmi);
+
+#endif /* _RHD_HDMI_H */
diff --git a/src/rhd_lvtma.c b/src/rhd_lvtma.c
index 53e7627..1ebc132 100644
--- a/src/rhd_lvtma.c
+++ b/src/rhd_lvtma.c
@@ -46,6 +46,7 @@
#include "rhd_crtc.h"
#include "rhd_connector.h"
#include "rhd_output.h"
+#include "rhd_hdmi.h"
#include "rhd_regs.h"
#include "rhd_card.h"
#ifdef ATOM_BIOS
@@ -278,7 +279,7 @@ LVDSSet(struct rhdOutput *Output, DisplayModePtr
Mode)
RHDFUNC(Output);
- RHDRegMask(Output, LVTMA_CNTL, 0x00000001, 0x00000001); /* enable
*/
+ RHDRegMask(Output, LVTMA_CNTL, 0x00000001, 0x00000005); /* enable
*/
usleep(20);
RHDRegWrite(Output, LVTMA_MODE, 0); /* set to LVDS */
@@ -696,6 +697,7 @@ struct rhdTMDSBPrivate {
Bool RunsDualLink;
Bool Coherent;
DisplayModePtr Mode;
+ struct rhdHdmi* Hdmi;
Bool Stored;
@@ -1130,7 +1132,7 @@ TMDSBPower(struct rhdOutput *Output, int Power)
switch (Power) {
case RHD_POWER_ON:
- RHDRegMask(Output, LVTMA_CNTL, 0x00000001, 0x00000001);
+ RHDRegMask(Output, LVTMA_CNTL, 0x00000005, 0x00000005);
if (Private->RunsDualLink)
RHDRegMask(Output, LVTMA_TRANSMITTER_ENABLE,
0x00003E3E,0x00003E3E);
@@ -1140,6 +1142,7 @@ TMDSBPower(struct rhdOutput *Output, int Power)
RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0x00000001, 0x00000001);
usleep(2);
RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0, 0x00000002);
+ RHDHdmiEnable(Private->Hdmi, TRUE);
return;
case RHD_POWER_RESET:
RHDRegMask(Output, LVTMA_TRANSMITTER_ENABLE, 0, 0x00003E3E);
@@ -1150,7 +1153,8 @@ TMDSBPower(struct rhdOutput *Output, int Power)
usleep(2);
RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0, 0x00000001);
RHDRegMask(Output, LVTMA_TRANSMITTER_ENABLE, 0, 0x00003E3E);
- RHDRegMask(Output, LVTMA_CNTL, 0, 0x00000001);
+ RHDRegMask(Output, LVTMA_CNTL, 0, 0x00000005);
+ RHDHdmiEnable(Private->Hdmi, FALSE);
return;
}
}
@@ -1166,6 +1170,8 @@ TMDSBSave(struct rhdOutput *Output)
RHDFUNC(Output);
+ RHDHdmiSave(Private->Hdmi);
+
Private->StoreControl = RHDRegRead(Output, LVTMA_CNTL);
Private->StoreSource = RHDRegRead(Output, LVTMA_SOURCE_SELECT);
Private->StoreFormat = RHDRegRead(Output, LVTMA_COLOR_FORMAT);
@@ -1199,6 +1205,8 @@ TMDSBRestore(struct rhdOutput *Output)
RHDFUNC(Output);
+ RHDHdmiRestore(Private->Hdmi);
+
if (!Private->Stored) {
xf86DrvMsg(Output->scrnIndex, X_ERROR,
"%s: No registers stored.\n", __func__);
@@ -1296,6 +1304,7 @@ RHDLVTMAInit(RHDPtr rhdPtr, CARD8 Type)
Private->RunsDualLink = FALSE;
Private->Coherent = FALSE;
+ Private->Hdmi = RHDHdmiInit(rhdPtr, HDMI_LVTMA);
}
return Output;
diff --git a/src/rhd_randr.c b/src/rhd_randr.c
index fffc78a..44a4818 100644
--- a/src/rhd_randr.c
+++ b/src/rhd_randr.c
@@ -70,6 +70,7 @@
# include "rhd_lut.h"
# include "rhd_mc.h"
# include "rhd_card.h"
+# include "rhd_azalia.h"
/*
* Driver internal
@@ -364,6 +365,8 @@ rhdRRCrtcModeSet(xf86CrtcPtr crtc,
Crtc->FrameSet(Crtc, x, y);
rhdUpdateCrtcPos(Crtc, Crtc->Cursor->X, Crtc->Cursor->Y);
RHDPLLSet(Crtc->PLL, Mode->Clock); /* This also powers up PLL */
+ RHDAzaliaSetClock(rhdPtr, Mode->Clock);
+ RHDAzaliaEnable(rhdPtr, TRUE);
Crtc->LUTSelect(Crtc, Crtc->LUT);
}
static void
diff --git a/src/rhd_regs.h b/src/rhd_regs.h
index ca6b90f..4917793 100644
--- a/src/rhd_regs.h
+++ b/src/rhd_regs.h
@@ -93,6 +93,15 @@ enum {
PCLK_CRTC1_CNTL = 0x0480,
PCLK_CRTC2_CNTL = 0x0484,
+ /* these regs were reverse enginered,
+ * so the chance is high that the naming is wrong
+ * R6xx+ ??? */
+ AZALIA_PLL1_MUL = 0x0514,
+ AZALIA_PLL1_DIV = 0x0518,
+ AZALIA_PLL2_MUL = 0x0524,
+ AZALIA_PLL2_DIV = 0x0528,
+ AZALIA_CLK_SRCSEL = 0x0534,
+
DCCG_DISP_CLK_SRCSEL = 0x0538, /* rv620+ */
R6XX_MC_VM_FB_LOCATION = 0x2180,
@@ -249,6 +258,15 @@ enum {
D2SCL_DITHER = 0x6DD4, /* guess */
D2SCL_FLIP_CONTROL = 0x6DD8, /* guess */
+ /* AZALIA, reverse enginered */
+ AZALIA_ENABLE = 0x7300,
+ AZALIA_UNKNOWN_0 = 0x7344,
+ AZALIA_UNKNOWN_1 = 0x7398,
+
+ /* HDMI */
+ HDMI_TMDSA = 0x7400,
+ HDMI_LVTMA = 0x7700,
+
/* R500 DAC A */
DACA_ENABLE = 0x7800,
DACA_SOURCE_SELECT = 0x7804,
@@ -901,5 +919,29 @@ enum {
#define MC_IND_DATA_BIT 0xffffffff
};
+enum {
+ /* HDMI registers */
+ HDMI_ENABLE = 0x00,
+ HDMI_CNTL = 0x08,
+ HDMI_UNKNOWN_0 = 0x10,
+ HDMI_UNKNOWN_1 = 0x14,
+ HDMI_UNKNOWN_2 = 0x18,
+ HDMI_UNKNOWN_3 = 0x28,
+ HDMI_VIDEOINFOFRAME_0 = 0x54,
+ HDMI_VIDEOINFOFRAME_1 = 0x58,
+ HDMI_VIDEOINFOFRAME_2 = 0x5c,
+ HDMI_VIDEOINFOFRAME_3 = 0x60,
+ HDMI_UNKNOWN_4 = 0xac,
+ HDMI_UNKNOWN_5 = 0xb0,
+ HDMI_UNKNOWN_6 = 0xb4,
+ HDMI_UNKNOWN_7 = 0xb8,
+ HDMI_UNKNOWN_8 = 0xbc,
+ HDMI_UNKNOWN_9 = 0xc0,
+ HDMI_AUDIOINFOFRAME_0 = 0xcc,
+ HDMI_AUDIOINFOFRAME_1 = 0xd0,
+ HDMI_UNKNOWN_A = 0xd4,
+ HDMI_UNKNOWN_B = 0xd8,
+ HDMI_UNKNOWN_C = 0xdc
+};
#endif /* _RHD_REGS_H */
diff --git a/src/rhd_tmds.c b/src/rhd_tmds.c
index 2921a53..8230293 100644
--- a/src/rhd_tmds.c
+++ b/src/rhd_tmds.c
@@ -45,6 +45,7 @@
#include "rhd_crtc.h"
#include "rhd_connector.h"
#include "rhd_output.h"
+#include "rhd_hdmi.h"
#include "rhd_regs.h"
struct rhdTMDSPrivate {
@@ -53,6 +54,8 @@ struct rhdTMDSPrivate {
Bool Coherent;
int PowerState;
+ struct rhdHdmi* Hdmi;
+
Bool Stored;
CARD32 StoreControl;
@@ -347,7 +350,7 @@ TMDSAPower(struct rhdOutput *Output, int Power)
case RHD_POWER_ON:
if (Private->PowerState == RHD_POWER_SHUTDOWN
|| Private->PowerState == RHD_POWER_UNKNOWN) {
- RHDRegMask(Output, TMDSA_CNTL, 0x00000001, 0x00000001);
+ RHDRegMask(Output, TMDSA_CNTL, 0x00000005, 0x00000005);
RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0x00000001,
0x00000001);
usleep(20);
@@ -379,6 +382,9 @@ TMDSAPower(struct rhdOutput *Output, int Power)
RHDRegMask(Output, TMDSA_TRANSMITTER_ENABLE, 0x00001F1F,
0x00001F1F);
} else
RHDRegMask(Output, TMDSA_TRANSMITTER_ENABLE, 0x0000001F,
0x00001F1F);
+
+ RHDHdmiEnable(Private->Hdmi, TRUE);
+
Private->PowerState = RHD_POWER_ON;
return;
@@ -396,7 +402,8 @@ TMDSAPower(struct rhdOutput *Output, int Power)
usleep(2);
RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0, 0x00000001);
RHDRegMask(Output, TMDSA_TRANSMITTER_ENABLE, 0, 0x00001F1F);
- RHDRegMask(Output, TMDSA_CNTL, 0, 0x00000001);
+ RHDRegMask(Output, TMDSA_CNTL, 0, 0x00000005);
+ RHDHdmiEnable(Private->Hdmi, FALSE);
Private->PowerState = RHD_POWER_SHUTDOWN;
return;
}
@@ -432,6 +439,8 @@ TMDSASave(struct rhdOutput *Output)
if (ChipSet >= RHD_RV610)
Private->StoreTXAdjust = RHDRegRead(Output, TMDSA_TRANSMITTER_ADJUST);
+ RHDHdmiSave(Private->Hdmi);
+
Private->Stored = TRUE;
}
@@ -470,6 +479,8 @@ TMDSARestore(struct rhdOutput *Output)
if (ChipSet >= RHD_RV610)
RHDRegWrite(Output, TMDSA_TRANSMITTER_ADJUST, Private->StoreTXAdjust);
+
+ RHDHdmiRestore(Private->Hdmi);
}
/*
@@ -483,6 +494,7 @@ TMDSADestroy(struct rhdOutput *Output)
if (!Output->Private)
return;
+ RHDHdmiDestroy(((struct rhdTMDSPrivate *)Output->Private)->Hdmi);
xfree(Output->Private);
Output->Private = NULL;
}
@@ -517,6 +529,7 @@ RHDTMDSAInit(RHDPtr rhdPtr)
Private->RunsDualLink = FALSE;
Private->Coherent = FALSE;
Private->PowerState = RHD_POWER_UNKNOWN;
+ Private->Hdmi = RHDHdmiInit(rhdPtr, HDMI_TMDSA);
Output->Private = Private;
--
1.5.4.3
--
To unsubscribe, e-mail: radeonhd+unsubscribe@opensuse.org
For additional commands, e-mail: radeonhd+help@opensuse.org