Hi,
included is my next version of the HDMI patch, wich also enables audio
support.
Changes:
1. Audio- and VideoInfoFrame are calculated correctly now. Ok most of
the bits are set to 0 (refer to stream header), but setting to RGB or
YCC in the VideoInfoFrame still works fine.
2. The patch now limits its changes to the RV630 chipset (the only one i
know it works correctly with). Feel free to change this limit to
something less restrictive and make some test.
3. The Audio and HDMI engine is now turned on or off with two config
options. Put somthing like
Option "Audio" "true"
Option "HDMI" "both" # or none/tmdsa/tmdsb
in your xorg.conf if you want to turn it on (default if off).
If you ask yourself what's the difference between audio and HDMI part of
the regs -> there is only 1 audio engine, but 2 HDMI engines (one for
each TMDS output).
Thinks that i didn't got working:
1. The info if a connected device is HDMI and/or Audio capable is
encoded in the "Enhanced Extended display identification data" (E-EDID,
i really think one of the worst things mankind ever invented are
marketing names). This E-EDID information is only readable when you use
enhanced DDC wich use a different I2C command to read more than 128
bytes compared to normal DDC. Since E-DDC is not implemented (AFAIK) in
rhd_i2c.c, i don't have any clue how to get this information.
2. I think "General Control Packet", "Audio Clock Regeneration" and
"Gamut Metadata" is somewhere inside the unknown HDMI registers, but i
also don't have any idea where to start searching for this.
I should also note that this is my second attempt to send this mail, so don't bother if you got it twice.
cu, Christian.
---
src/Makefile.am | 4 +
src/rhd.h | 4 +
src/rhd_audio.c | 164 +++++++++++++++++++++++++++++
src/rhd_audio.h | 54 ++++++++++
src/rhd_driver.c | 38 +++++++-
src/rhd_hdmi.c | 300
++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/rhd_hdmi.h | 50 +++++++++
src/rhd_lvtma.c | 44 +++++++--
src/rhd_randr.c | 2 +
src/rhd_regs.h | 42 ++++++++
src/rhd_tmds.c | 23 ++++-
11 files changed, 713 insertions(+), 12 deletions(-)
create mode 100644 src/rhd_audio.c
create mode 100644 src/rhd_audio.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..52a744b 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_audio.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_audio.h \
+ rhd_hdmi.h \
r5xx_accel.c \
r5xx_accel.h \
r5xx_xaa.c \
diff --git a/src/rhd.h b/src/rhd.h
index b0e5835..f9e502c 100644
--- a/src/rhd.h
+++ b/src/rhd.h
@@ -210,6 +210,9 @@ typedef struct RHDRec {
RHDOpt rrUseXF86Edid;
RHDOpt rrOutputOrder;
RHDOpt tvModeName;
+ Bool enableAudio;
+ Bool enableHDMI_TMDSA;
+ Bool enableHDMI_TMDSB;
enum RHD_HPD_USAGE hpdUsage;
unsigned int FbMapSize;
pointer FbBase; /* map base of fb */
@@ -254,6 +257,7 @@ typedef struct RHDRec {
struct rhdVGA *VGA; /* VGA compatibility HW */
struct rhdCrtc *Crtc[2];
struct rhdPLL *PLLs[2]; /* Pixelclock PLLs */
+ struct rhdAudio *Audio;
struct rhdLUTStore *LUTStore;
struct rhdLUT *LUT[2];
diff --git a/src/rhd_audio.c b/src/rhd_audio.c
new file mode 100644
index 0000000..2780e2e
--- /dev/null
+++ b/src/rhd_audio.c
@@ -0,0 +1,164 @@
+/*
+ * 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"
+
+#include "rhd.h"
+#include "rhd_pll.h"
+#include "rhd_audio.h"
+#include "rhd_regs.h"
+
+/*
+ *
+ */
+void
+RHDAudioInit(RHDPtr rhdPtr)
+{
+ RHDFUNC(rhdPtr);
+
+ if (rhdPtr->ChipSet == RHD_RV630) {
+ struct rhdAudio *Audio = (struct rhdAudio *) xnfcalloc(sizeof(struct
rhdAudio), 1);
+
+ Audio->scrnIndex = rhdPtr->scrnIndex;
+ Audio->Stored = FALSE;
+
+ rhdPtr->Audio = Audio;
+ } else
+ rhdPtr->Audio = NULL;
+}
+
+/*
+ *
+ */
+void
+RHDAudioSetClock(RHDPtr rhdPtr, struct rhdPLL *pll)
+{
+ struct rhdAudio *Audio = rhdPtr->Audio;
+ CARD32 AudioRate = 48000;
+ CARD32 Clock = pll->CurrentClock;
+
+ if (!Audio) return;
+
+ if (pll->Id == PLL_ID_PLL1) {
+ RHDRegWrite(Audio, AUDIO_PLL1_MUL, AudioRate*50);
+ RHDRegWrite(Audio, AUDIO_PLL1_DIV, Clock*100);
+ RHDRegWrite(Audio, AUDIO_CLK_SRCSEL, 0);
+
+ } else if (pll->Id == PLL_ID_PLL2) {
+ RHDRegWrite(Audio, AUDIO_PLL2_MUL, AudioRate*50);
+ RHDRegWrite(Audio, AUDIO_PLL2_DIV, Clock*100);
+ RHDRegWrite(Audio, AUDIO_CLK_SRCSEL, 1);
+ }
+}
+
+/*
+ *
+ */
+void
+RHDAudioSetEnable(RHDPtr rhdPtr, Bool Enable)
+{
+ struct rhdAudio *Audio = rhdPtr->Audio;
+ if (!Audio) return;
+
+ RHDFUNC(Audio);
+
+ RHDRegMask(Audio, AUDIO_ENABLE, Enable ? 0x80000000 : 0x0,
0x80000000);
+ /*
+ RHDRegWrite(Output, AUDIO_UNKNOWN_0, 0x70);
+ RHDRegWrite(Output, AUDIO_UNKNOWN_1, 0x1);
+ */
+}
+
+/*
+ *
+ */
+void
+RHDAudioSave(RHDPtr rhdPtr)
+{
+ struct rhdAudio *Audio = rhdPtr->Audio;
+ if (!Audio) return;
+
+ RHDFUNC(Audio);
+
+ Audio->StoreEnabled = RHDRegRead(Audio, AUDIO_ENABLE) &
0x80000000 ? TRUE : FALSE;
+
+ Audio->StoreUnknown0 = RHDRegRead(Audio, AUDIO_UNKNOWN_0);
+ Audio->StoreUnknown1 = RHDRegRead(Audio, AUDIO_UNKNOWN_1);
+
+ Audio->StorePll1Mul = RHDRegRead(Audio, AUDIO_PLL1_MUL);
+ Audio->StorePll1Div = RHDRegRead(Audio, AUDIO_PLL1_DIV);
+ Audio->StorePll2Mul = RHDRegRead(Audio, AUDIO_PLL2_MUL);
+ Audio->StorePll2Div = RHDRegRead(Audio, AUDIO_PLL2_DIV);
+ Audio->StoreClockSrcSel = RHDRegRead(Audio, AUDIO_CLK_SRCSEL);
+
+ Audio->Stored = TRUE;
+}
+
+/*
+ *
+ */
+void
+RHDAudioRestore(RHDPtr rhdPtr)
+{
+ struct rhdAudio *Audio = rhdPtr->Audio;
+ if (!Audio) return;
+
+ RHDFUNC(Audio);
+
+ if (!Audio->Stored) {
+ xf86DrvMsg(Audio->scrnIndex, X_ERROR, "%s: trying to restore "
+ "uninitialized values.\n", __func__);
+ return;
+ }
+
+ RHDAudioSetEnable(rhdPtr, Audio->StoreEnabled);
+
+ RHDRegWrite(Audio, AUDIO_UNKNOWN_0, Audio->StoreUnknown0);
+ RHDRegWrite(Audio, AUDIO_UNKNOWN_1, Audio->StoreUnknown1);
+
+ RHDRegWrite(Audio, AUDIO_PLL1_MUL, Audio->StorePll1Mul);
+ RHDRegWrite(Audio, AUDIO_PLL1_DIV, Audio->StorePll1Div);
+ RHDRegWrite(Audio, AUDIO_PLL2_MUL, Audio->StorePll2Mul);
+ RHDRegWrite(Audio, AUDIO_PLL2_DIV, Audio->StorePll2Div);
+ RHDRegWrite(Audio, AUDIO_CLK_SRCSEL, Audio->StoreClockSrcSel);
+}
+
+/*
+ *
+ */
+void
+RHDAudioDestroy(RHDPtr rhdPtr)
+{
+ RHDFUNC(rhdPtr);
+
+ if (!rhdPtr->Audio) return;
+
+ xfree(rhdPtr->Audio);
+}
diff --git a/src/rhd_audio.h b/src/rhd_audio.h
new file mode 100644
index 0000000..fffb36b
--- /dev/null
+++ b/src/rhd_audio.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_AUDIO_H
+#define _RHD_AUDIO_H
+
+struct rhdAudio {
+
+ int scrnIndex;
+
+ Bool Stored;
+ Bool StoreEnabled;
+
+ CARD32 StoreUnknown0;
+ CARD32 StoreUnknown1;
+
+ CARD32 StorePll1Mul;
+ CARD32 StorePll1Div;
+ CARD32 StorePll2Mul;
+ CARD32 StorePll2Div;
+ CARD32 StoreClockSrcSel;
+};
+
+void RHDAudioInit(RHDPtr rhdPtr);
+void RHDAudioSetClock(RHDPtr rhdPtr, struct rhdPLL *pll);
+void RHDAudioSetEnable(RHDPtr rhdPtr, Bool Enable);
+void RHDAudioSave(RHDPtr rhdPtr);
+void RHDAudioRestore(RHDPtr rhdPtr);
+void RHDAudioDestroy(RHDPtr rhdPtr);
+
+#endif /* _RHD_AUDIO_H */
diff --git a/src/rhd_driver.c b/src/rhd_driver.c
index b8f7dea..e0a5afe 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_audio.h"
#include "r5xx_accel.h"
/* ??? */
@@ -230,7 +231,9 @@ typedef enum {
OPTION_NORANDR,
OPTION_RRUSEXF86EDID,
OPTION_RROUTPUTORDER,
- OPTION_TV_MODE
+ OPTION_TV_MODE,
+ OPTION_AUDIO,
+ OPTION_HDMI
} RHDOpts;
static const OptionInfoRec RHDOptions[] = {
@@ -247,6 +250,8 @@ static const OptionInfoRec RHDOptions[] = {
{ OPTION_RRUSEXF86EDID, "RRUseXF86Edid",
OPTV_BOOLEAN, {0}, FALSE },
{ OPTION_RROUTPUTORDER, "RROutputOrder", OPTV_ANYSTR,
{0}, FALSE },
{ OPTION_TV_MODE, "TVMode", OPTV_ANYSTR, {0},
FALSE },
+ { OPTION_AUDIO, "Audio", OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_HDMI, "HDMI", OPTV_ANYSTR, {0}, FALSE },
{ -1, NULL, OPTV_NONE, {0}, FALSE }
};
@@ -318,6 +323,7 @@ RHDFreeRec(ScrnInfoPtr pScrn)
RHDMCDestroy(rhdPtr);
RHDVGADestroy(rhdPtr);
RHDPLLsDestroy(rhdPtr);
+ RHDAudioDestroy(rhdPtr);
RHDLUTsDestroy(rhdPtr);
RHDOutputsDestroy(rhdPtr);
RHDConnectorsDestroy(rhdPtr);
@@ -737,6 +743,7 @@ RHDPreInit(ScrnInfoPtr pScrn, int flags)
RHDMCInit(rhdPtr);
RHDCrtcsInit(rhdPtr);
RHDPLLsInit(rhdPtr);
+ RHDAudioInit(rhdPtr);
RHDLUTsInit(rhdPtr);
RHDCursorsInit(rhdPtr); /* do this irrespective of hw/sw cursor
setting */
@@ -1024,6 +1031,9 @@ RHDScreenInit(int scrnIndex, ScreenPtr pScreen,
int argc, char **argv)
/* fix viewport */
RHDAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
+ /* enable/disable audio */
+ RHDAudioSetEnable(rhdPtr, rhdPtr->enableAudio);
+
/* Initialise cursor functions */
miDCInitialize (pScreen, xf86GetPointerScreenFuncs());
@@ -1982,6 +1992,7 @@ rhdSetMode(ScrnInfoPtr pScrn, DisplayModePtr mode)
if (Crtc->ScaleSet)
Crtc->ScaleSet(Crtc, RHD_CRTC_SCALE_TYPE_NONE, mode, NULL);
RHDPLLSet(Crtc->PLL, mode->Clock);
+ RHDAudioSetClock(rhdPtr, Crtc->PLL);
Crtc->LUTSelect(Crtc, Crtc->LUT);
RHDOutputsMode(rhdPtr, Crtc, mode);
}
@@ -1995,6 +2006,7 @@ rhdSetMode(ScrnInfoPtr pScrn, DisplayModePtr mode)
if (Crtc->ScaleSet)
Crtc->ScaleSet(Crtc, RHD_CRTC_SCALE_TYPE_NONE, mode, NULL);
RHDPLLSet(Crtc->PLL, mode->Clock);
+ RHDAudioSetClock(rhdPtr, Crtc->PLL);
Crtc->LUTSelect(Crtc, Crtc->LUT);
RHDOutputsMode(rhdPtr, Crtc, mode);
}
@@ -2033,6 +2045,7 @@ rhdSave(RHDPtr rhdPtr)
RHDOutputsSave(rhdPtr);
RHDPLLsSave(rhdPtr);
+ RHDAudioSave(rhdPtr);
RHDLUTsSave(rhdPtr);
rhdPtr->Crtc[0]->Save(rhdPtr->Crtc[0]);
@@ -2056,6 +2069,7 @@ rhdRestore(RHDPtr rhdPtr)
rhdRestoreCursor(pScrn);
RHDPLLsRestore(rhdPtr);
+ RHDAudioRestore(rhdPtr);
RHDLUTsRestore(rhdPtr);
RHDVGARestore(rhdPtr);
@@ -2292,6 +2306,8 @@ rhdProcessOptions(ScrnInfoPtr pScrn)
{
RHDPtr rhdPtr = RHDPTR(pScrn);
RHDOpt hpd;
+ RHDOpt audio;
+ RHDOpt hdmi;
/* Collect all of the relevant option flags (fill in
pScrn->options) */
xf86CollectOptions(pScrn, NULL);
rhdPtr->Options = xnfcalloc(sizeof(RHDOptions), 1);
@@ -2316,6 +2332,10 @@ rhdProcessOptions(ScrnInfoPtr pScrn)
&rhdPtr->rrOutputOrder, NULL);
RhdGetOptValString (rhdPtr->Options, OPTION_TV_MODE,
&rhdPtr->tvModeName, NULL);
+ RhdGetOptValBool (rhdPtr->Options, OPTION_AUDIO,
+ &audio, FALSE);
+ RhdGetOptValString (rhdPtr->Options, OPTION_HDMI,
+ &hdmi, "none");
rhdAccelOptionsHandle(pScrn);
@@ -2335,6 +2355,22 @@ rhdProcessOptions(ScrnInfoPtr pScrn)
"!!! Option HPD is set !!!\n"
" This shall only be used to work around broken connector
tables.\n"
" Please report your findings to radeonhd@opensuse.org\n");
+
+ rhdPtr->enableAudio = audio.val.bool;
+
+ rhdPtr->enableHDMI_TMDSA = FALSE;
+ rhdPtr->enableHDMI_TMDSB = FALSE;
+ if (strcasecmp(hdmi.val.string, "both") == 0) {
+ rhdPtr->enableHDMI_TMDSA = TRUE;
+ rhdPtr->enableHDMI_TMDSB = TRUE;
+ } else if (strcasecmp(hdmi.val.string, "tmdsa") == 0) {
+ rhdPtr->enableHDMI_TMDSA = TRUE;
+ } else if (strcasecmp(hdmi.val.string, "tmdsb") == 0) {
+ rhdPtr->enableHDMI_TMDSB = TRUE;
+ } else if (strcasecmp(hdmi.val.string, "none") != 0) {
+ xf86DrvMsgVerb(rhdPtr->scrnIndex, X_ERROR, 0,
+ "Unknown HDMI Option \"%s\"", hdmi.val.string);
+ }
}
/*
diff --git a/src/rhd_hdmi.c b/src/rhd_hdmi.c
new file mode 100644
index 0000000..5642ff8
--- /dev/null
+++ b/src/rhd_hdmi.c
@@ -0,0 +1,300 @@
+/*
+ * 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"
+
+#include "rhd.h"
+#include "rhd_hdmi.h"
+#include "rhd_regs.h"
+
+enum HdmiColorFormat {
+ RGB = 0,
+ /* YCC 4:2:2 or 4:4:4 ? */
+ YCC = 2
+};
+
+/*
+ *
+ */
+static void
+HdmiInfoFrameChecksum(CARD8 packetType, CARD8 versionNumber, CARD8
length, CARD8* frame)
+{
+ int i;
+ frame[0] = packetType + versionNumber + length;
+ for(i=1;i<=length;i++)
+ frame[0] += frame[i];
+ frame[0] = 0x100 - frame[0];
+}
+
+/*
+ *
+ */
+static void
+HdmiVideoInfoFrame(
+ struct rhdHdmi *hdmi,
+ enum HdmiColorFormat ColorFormat,
+ Bool ActiveInformationPresent,
+ CARD8 ActiveFormatAspectRatio,
+ CARD8 ScanInformation,
+ CARD8 Colorimetry,
+ CARD8 ExColorimetry,
+ CARD8 Quantization,
+ Bool ITC,
+ CARD8 PictureAspectRatio,
+ CARD8 VideoFormatIdentification,
+ CARD8 PixelRepetition,
+ CARD8 NonUniformPictureScaling,
+ CARD8 BarInfoDataValid,
+ CARD16 TopBar,
+ CARD16 BottomBar,
+ CARD16 LeftBar,
+ CARD16 RightBar
+)
+{
+ CARD8 frame[14];
+
+ frame[0x0] = 0;
+ frame[0x1] =
+ (ScanInformation & 0x3) |
+ ((BarInfoDataValid & 0x3) << 2) |
+ ((ActiveInformationPresent & 0x1) << 4) |
+ ((ColorFormat & 0x3) << 5);
+ frame[0x2] =
+ (ActiveFormatAspectRatio & 0xF) |
+ ((PictureAspectRatio & 0x3) << 4) |
+ ((Colorimetry & 0x3) << 6);
+ frame[0x3] =
+ (NonUniformPictureScaling & 0x3) |
+ ((Quantization & 0x3) << 2) |
+ ((ExColorimetry & 0x7) << 4) |
+ ((ITC & 0x1) << 7);
+ frame[0x4] = (VideoFormatIdentification & 0x7F);
+ frame[0x5] = (PixelRepetition & 0xF);
+ frame[0x6] = (TopBar & 0xFF);
+ frame[0x7] = (TopBar >> 8);
+ frame[0x8] = (BottomBar & 0xFF);
+ frame[0x9] = (BottomBar >> 8);
+ frame[0xA] = (LeftBar & 0xFF);
+ frame[0xB] = (LeftBar >> 8);
+ frame[0xC] = (RightBar & 0xFF);
+ frame[0xD] = (RightBar >> 8);
+
+ HdmiInfoFrameChecksum(0x82, 0x02, 0x0D, frame);
+
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_VIDEOINFOFRAME_0,
+ frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] <<
24));
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_VIDEOINFOFRAME_1,
+ frame[0x4] | (frame[0x5] << 8) | (frame[0x6] << 16) | (frame[0x7] <<
24));
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_VIDEOINFOFRAME_2,
+ frame[0x8] | (frame[0x9] << 8) | (frame[0xA] << 16) | (frame[0xB] <<
24));
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_VIDEOINFOFRAME_3,
+ frame[0xC] | (frame[0xD] << 8));
+}
+
+/*
+ *
+ */
+static void
+HdmiAudioInfoFrame(
+ struct rhdHdmi *hdmi,
+ CARD8 ChannelCount,
+ CARD8 CodingType,
+ CARD8 SampleSize,
+ CARD8 SampleFrequency,
+ CARD8 Format,
+ CARD8 ChannelAllocation,
+ CARD8 LevelShift,
+ Bool DownmixInhibit
+)
+{
+ CARD8 frame[11];
+
+ frame[0x0] = 0;
+ frame[0x1] = (ChannelCount & 0x7) | ((CodingType & 0xF) << 4);
+ frame[0x2] = (SampleSize & 0x3) | ((SampleFrequency & 0x7) << 2);
+ frame[0x3] = Format;
+ frame[0x4] = ChannelAllocation;
+ frame[0x5] = ((LevelShift & 0xF) << 3) | ((DownmixInhibit & 0x1) <<
7);
+ frame[0x6] = 0;
+ frame[0x7] = 0;
+ frame[0x8] = 0;
+ frame[0x9] = 0;
+ frame[0xA] = 0;
+
+ HdmiInfoFrameChecksum(0x84, 0x01, 0x0A, frame);
+
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_AUDIOINFOFRAME_0,
+ frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] <<
24));
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_AUDIOINFOFRAME_1,
+ frame[0x4] | (frame[0x5] << 8) | (frame[0x6] << 16) | (frame[0x8] <<
24));
+}
+
+/*
+ *
+ */
+struct rhdHdmi*
+RHDHdmiInit(RHDPtr rhdPtr, CARD16 Offset)
+{
+ struct rhdHdmi *hdmi;
+ RHDFUNC(rhdPtr);
+
+ if(rhdPtr->ChipSet == RHD_RV630) {
+ hdmi = (struct rhdHdmi *) xnfcalloc(sizeof(struct rhdHdmi), 1);
+ hdmi->scrnIndex = rhdPtr->scrnIndex;
+ hdmi->Offset = Offset;
+ hdmi->Stored = FALSE;
+ return hdmi;
+ } else
+ return NULL;
+}
+
+/*
+ *
+ */
+void
+RHDHdmiEnable(struct rhdHdmi *hdmi, Bool Enable)
+{
+ if(!hdmi) return;
+ 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_TMDSB)
+ 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);
+
+ HdmiVideoInfoFrame(hdmi, RGB, FALSE, 0, 0, 0, 0, 0, FALSE, 0, 0, 0,
0, 0, 0, 0, 0, 0);
+
+ 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);
+
+ HdmiAudioInfoFrame(hdmi, 1, 0, 0, 0, 0, 0, 0, FALSE);
+
+ 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)
+{
+ if(!hdmi) return;
+ 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)
+{
+ if(!hdmi) return;
+ 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)
+{
+ if(!hdmi) return;
+ 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 69694c7..5ec3922 100644
--- a/src/rhd_lvtma.c
+++ b/src/rhd_lvtma.c
@@ -48,6 +48,7 @@
#include "rhd_output.h"
#include "rhd_regs.h"
#include "rhd_card.h"
+#include "rhd_hdmi.h"
#ifdef ATOM_BIOS
#include "rhd_atombios.h"
#endif
@@ -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 */
@@ -689,6 +690,21 @@ LVDSInfoRetrieve(RHDPtr rhdPtr)
/*
*
+ */
+static void
+LVDSDestroy(struct rhdOutput *Output)
+{
+ RHDFUNC(Output);
+
+ if (!Output->Private)
+ return;
+
+ xfree(Output->Private);
+ Output->Private = NULL;
+}
+
+/*
+ *
* Handling for LVTMA block as TMDS.
*
*/
@@ -697,6 +713,8 @@ struct rhdTMDSBPrivate {
Bool Coherent;
DisplayModePtr Mode;
+ struct rhdHdmi *Hdmi;
+
Bool Stored;
CARD32 StoreControl;
@@ -1130,7 +1148,7 @@ TMDSBPower(struct rhdOutput *Output, int Power)
switch (Power) {
case RHD_POWER_ON:
- RHDRegMask(Output, LVTMA_CNTL, 0x00000001, 0x00000001);
+ RHDRegMask(Output, LVTMA_CNTL, rhdPtr->enableHDMI_TMDSB ? 0x5 : 0x1,
0x00000005);
if (Private->RunsDualLink)
RHDRegMask(Output, LVTMA_TRANSMITTER_ENABLE,
0x00003E3E,0x00003E3E);
@@ -1140,6 +1158,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, rhdPtr->enableHDMI_TMDSB);
return;
case RHD_POWER_RESET:
RHDRegMask(Output, LVTMA_TRANSMITTER_ENABLE, 0, 0x00003E3E);
@@ -1150,7 +1169,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;
}
}
@@ -1185,6 +1205,8 @@ TMDSBSave(struct rhdOutput *Output)
Private->StoreRv600PreEmphasis = RHDRegRead(Output,
LVTMA_PREEMPHASIS_CONTROL);
}
+ RHDHdmiSave(Private->Hdmi);
+
Private->Stored = TRUE;
}
@@ -1223,6 +1245,8 @@ TMDSBRestore(struct rhdOutput *Output)
RHDRegWrite(Output, LVTMA_TRANSMITTER_ADJUST,
Private->StoreRv600TXAdjust);
RHDRegWrite(Output, LVTMA_PREEMPHASIS_CONTROL,
Private->StoreRv600PreEmphasis);
}
+
+ RHDHdmiRestore(Private->Hdmi);
}
@@ -1230,14 +1254,18 @@ TMDSBRestore(struct rhdOutput *Output)
*
*/
static void
-LVTMADestroy(struct rhdOutput *Output)
+TMDSBDestroy(struct rhdOutput *Output)
{
+ struct rhdTMDSBPrivate *Private = (struct rhdTMDSBPrivate *)
Output->Private;
RHDFUNC(Output);
- if (!Output->Private)
+ if (!Private)
return;
- xfree(Output->Private);
+ if (Private->Hdmi)
+ RHDHdmiDestroy(Private->Hdmi);
+
+ xfree(Private);
Output->Private = NULL;
}
@@ -1266,7 +1294,6 @@ RHDLVTMAInit(RHDPtr rhdPtr, CARD8 Type)
Output->Id = RHD_OUTPUT_LVTMA;
Output->Sense = NULL; /* not implemented in hw */
- Output->Destroy = LVTMADestroy;
if (Type == RHD_CONNECTOR_PANEL) {
Output->Name = "LVDS";
@@ -1277,6 +1304,7 @@ RHDLVTMAInit(RHDPtr rhdPtr, CARD8 Type)
Output->Save = LVDSSave;
Output->Restore = LVDSRestore;
Output->Property = LVDSPropertyControl;
+ Output->Destroy = LVDSDestroy;
Output->Private = LVDSInfoRetrieve(rhdPtr);
LVDSDebugBacklight(Output);
@@ -1291,7 +1319,9 @@ RHDLVTMAInit(RHDPtr rhdPtr, CARD8 Type)
Output->Save = TMDSBSave;
Output->Restore = TMDSBRestore;
Output->Property = TMDSBPropertyControl;
+ Output->Destroy = TMDSBDestroy;
+ Private->Hdmi = RHDHdmiInit(rhdPtr, HDMI_TMDSB);
Output->Private = Private;
Private->RunsDualLink = FALSE;
diff --git a/src/rhd_randr.c b/src/rhd_randr.c
index ea42c83..d8554c5 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_audio.h"
/*
* Driver internal
@@ -369,6 +370,7 @@ 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 */
+ RHDAudioSetClock(rhdPtr, Crtc->PLL);
Crtc->LUTSelect(Crtc, Crtc->LUT);
}
static void
diff --git a/src/rhd_regs.h b/src/rhd_regs.h
index 6b149ed..68bcaf8 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+ ??? */
+ AUDIO_PLL1_MUL = 0x0514,
+ AUDIO_PLL1_DIV = 0x0518,
+ AUDIO_PLL2_MUL = 0x0524,
+ AUDIO_PLL2_DIV = 0x0528,
+ AUDIO_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 */
+ /* Audio, reverse enginered */
+ AUDIO_ENABLE = 0x7300,
+ AUDIO_UNKNOWN_0 = 0x7344,
+ AUDIO_UNKNOWN_1 = 0x7398,
+
+ /* HDMI */
+ HDMI_TMDSA = 0x7400,
+ HDMI_TMDSB = 0x7700,
+
/* R500 DAC A */
DACA_ENABLE = 0x7800,
DACA_SOURCE_SELECT = 0x7804,
@@ -962,5 +980,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 31dfea1..4946d95 100644
--- a/src/rhd_tmds.c
+++ b/src/rhd_tmds.c
@@ -46,6 +46,7 @@
#include "rhd_connector.h"
#include "rhd_output.h"
#include "rhd_regs.h"
+#include "rhd_hdmi.h"
struct rhdTMDSPrivate {
Bool RunsDualLink;
@@ -53,6 +54,8 @@ struct rhdTMDSPrivate {
Bool Coherent;
int PowerState;
+ struct rhdHdmi *Hdmi;
+
Bool Stored;
CARD32 StoreControl;
@@ -348,7 +351,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, rhdPtr->enableHDMI_TMDSA ? 0x5 :
0x1, 0x00000005);
RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0x00000001,
0x00000001);
usleep(20);
@@ -380,6 +383,8 @@ TMDSAPower(struct rhdOutput *Output, int Power)
RHDRegMask(Output, TMDSA_TRANSMITTER_ENABLE, 0x00001F1F,
0x00001F1F);
} else
RHDRegMask(Output, TMDSA_TRANSMITTER_ENABLE, 0x0000001F,
0x00001F1F);
+
+ RHDHdmiEnable(Private->Hdmi, rhdPtr->enableHDMI_TMDSA);
Private->PowerState = RHD_POWER_ON;
return;
@@ -397,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;
}
@@ -433,6 +439,8 @@ TMDSASave(struct rhdOutput *Output)
if (ChipSet >= RHD_RV610)
Private->StoreTXAdjust = RHDRegRead(Output, TMDSA_TRANSMITTER_ADJUST);
+ RHDHdmiSave(Private->Hdmi);
+
Private->Stored = TRUE;
}
@@ -471,6 +479,8 @@ TMDSARestore(struct rhdOutput *Output)
if (ChipSet >= RHD_RV610)
RHDRegWrite(Output, TMDSA_TRANSMITTER_ADJUST, Private->StoreTXAdjust);
+
+ RHDHdmiRestore(Private->Hdmi);
}
/*
@@ -479,12 +489,16 @@ TMDSARestore(struct rhdOutput *Output)
static void
TMDSADestroy(struct rhdOutput *Output)
{
+ struct rhdTMDSPrivate *Private = (struct rhdTMDSPrivate *)
Output->Private;
RHDFUNC(Output);
- if (!Output->Private)
+ if (!Private)
return;
- xfree(Output->Private);
+ if(Private->Hdmi)
+ RHDHdmiDestroy(Private->Hdmi);
+
+ xfree(Private);
Output->Private = NULL;
}
@@ -518,6 +532,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