summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian König <deathsimple@vodafone.de>2008-07-14 14:05:50 (GMT)
committerEgbert Eich <eich@freedesktop.org>2008-07-20 14:55:57 (GMT)
commit2fe6021c015dd6573e554bde43bd44ce71f8bdf4 (patch)
treeaab184773f8645d9e3ab2d74fbcfcc3a091b7e14
parent435320ded4596c2924404fac679184932d40e885 (diff)
Audio/HDMI: Add basic support for Audio frames over HDMI.HDMI-Audio
-rw-r--r--src/Makefile.am4
-rw-r--r--src/rhd.h4
-rw-r--r--src/rhd_audio.c162
-rw-r--r--src/rhd_audio.h54
-rw-r--r--src/rhd_dig.c13
-rw-r--r--src/rhd_driver.c38
-rw-r--r--src/rhd_hdmi.c304
-rw-r--r--src/rhd_hdmi.h50
-rw-r--r--src/rhd_lvtma.c43
-rw-r--r--src/rhd_randr.c2
-rw-r--r--src/rhd_regs.h44
-rw-r--r--src/rhd_tmds.c22
12 files changed, 727 insertions, 13 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 1212486..11ac06c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -36,6 +36,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 \
@@ -53,6 +55,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 976d6d6..18cd832 100644
--- a/src/rhd.h
+++ b/src/rhd.h
@@ -222,6 +222,9 @@ typedef struct RHDRec {
RHDOpt tvModeName;
RHDOpt scaleTypeOpt;
RHDOpt unverifiedFeatures;
+ Bool enableAudio;
+ Bool enableHDMI_TMDSA;
+ Bool enableHDMI_TMDSB;
enum RHD_HPD_USAGE hpdUsage;
unsigned int FbMapSize;
pointer FbBase; /* map base of fb */
@@ -269,6 +272,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..69803b4
--- /dev/null
+++ b/src/rhd_audio.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2008 Christian König <deathsimple@vodafone.de>
+ * Copyright 2007 Luc Verhaegen <lverhaegen@novell.com>
+ * Copyright 2007 Matthias Hopf <mhopf@novell.com>
+ * Copyright 2007 Egbert Eich <eich@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.
+ */
+
+#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_R600) {
+ 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(Audio, AUDIO_UNKNOWN_0, 0x170);
+ RHDRegWrite(Audio, 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 <deathsimple@vodafone.de>
+ * Copyright 2007 Luc Verhaegen <lverhaegen@novell.com>
+ * Copyright 2007 Matthias Hopf <mhopf@novell.com>
+ * Copyright 2007 Egbert Eich <eich@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.
+ */
+
+#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_dig.c b/src/rhd_dig.c
index ee355dc..800c6b5 100644
--- a/src/rhd_dig.c
+++ b/src/rhd_dig.c
@@ -42,6 +42,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
@@ -106,6 +107,7 @@ struct DIGPrivate
Bool Coherent;
Bool RunDualLink;
DisplayModePtr Mode;
+ struct rhdHdmi *Hdmi;
/* LVDS */
Bool FPDI;
@@ -1238,6 +1240,7 @@ DigPower(struct rhdOutput *Output, int Power)
case RHD_POWER_ON:
Encoder->Power(Output, Power);
Transmitter->Power(Output, Power);
+ RHDHdmiEnable(Private->Hdmi, Private->EncoderMode == TMDS_HDMI);
return;
case RHD_POWER_RESET:
Transmitter->Power(Output, Power);
@@ -1247,6 +1250,7 @@ DigPower(struct rhdOutput *Output, int Power)
default:
Transmitter->Power(Output, Power);
Encoder->Power(Output, Power);
+ RHDHdmiEnable(Private->Hdmi, FALSE);
return;
}
}
@@ -1315,6 +1319,7 @@ DigSave(struct rhdOutput *Output)
Encoder->Save(Output);
Transmitter->Save(Output);
+ RHDHdmiSave(Private->Hdmi);
}
/*
@@ -1331,6 +1336,7 @@ DigRestore(struct rhdOutput *Output)
Encoder->Restore(Output);
Transmitter->Restore(Output);
+ RHDHdmiRestore(Private->Hdmi);
}
/*
@@ -1347,6 +1353,7 @@ DigDestroy(struct rhdOutput *Output)
Encoder->Destroy(Output);
Transmitter->Destroy(Output);
+ RHDHdmiDestroy(Private->Hdmi);
xfree(Private);
Output->Private = NULL;
@@ -1510,6 +1517,7 @@ RHDDIGInit(RHDPtr rhdPtr, enum rhdOutputType outputType, CARD8 ConnectorType)
Private->Encoder.Save = EncoderSave;
Private->Encoder.Restore = EncoderRestore;
Private->Encoder.Destroy = EncoderDestroy;
+ Private->Hdmi = RHDHdmiInit(rhdPtr, HDMI_DIG);
switch (ConnectorType) {
case RHD_CONNECTOR_PANEL:
@@ -1522,7 +1530,10 @@ RHDDIGInit(RHDPtr rhdPtr, enum rhdOutputType outputType, CARD8 ConnectorType)
break;
case RHD_CONNECTOR_DVI_SINGLE:
Private->RunDualLink = FALSE;
- Private->EncoderMode = TMDS_DVI; /* currently also HDMI */
+ if(rhdPtr->enableHDMI_TMDSA)
+ Private->EncoderMode = TMDS_HDMI;
+ else
+ Private->EncoderMode = TMDS_DVI;
break;
}
diff --git a/src/rhd_driver.c b/src/rhd_driver.c
index db90679..8478a1f 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"
#ifdef USE_DRI
@@ -238,7 +239,9 @@ typedef enum {
OPTION_DRI,
OPTION_TV_MODE,
OPTION_SCALE_TYPE,
- OPTION_UNVERIFIED_FEAT
+ OPTION_UNVERIFIED_FEAT,
+ OPTION_AUDIO,
+ OPTION_HDMI
} RHDOpts;
static const OptionInfoRec RHDOptions[] = {
@@ -258,6 +261,8 @@ static const OptionInfoRec RHDOptions[] = {
{ OPTION_TV_MODE, "TVMode", OPTV_ANYSTR, {0}, FALSE },
{ OPTION_SCALE_TYPE, "ScaleType", OPTV_ANYSTR, {0}, FALSE },
{ OPTION_UNVERIFIED_FEAT, "UnverifiedFeatures", OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_AUDIO, "Audio", OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_HDMI, "HDMI", OPTV_ANYSTR, {0}, FALSE },
{ -1, NULL, OPTV_NONE, {0}, FALSE }
};
@@ -329,6 +334,7 @@ RHDFreeRec(ScrnInfoPtr pScrn)
RHDMCDestroy(rhdPtr);
RHDVGADestroy(rhdPtr);
RHDPLLsDestroy(rhdPtr);
+ RHDAudioDestroy(rhdPtr);
RHDLUTsDestroy(rhdPtr);
RHDOutputsDestroy(rhdPtr);
RHDConnectorsDestroy(rhdPtr);
@@ -753,6 +759,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 */
@@ -1059,6 +1066,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());
@@ -2108,6 +2118,7 @@ rhdSetMode(ScrnInfoPtr pScrn, DisplayModePtr mode)
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);
}
@@ -2147,6 +2158,7 @@ rhdSave(RHDPtr rhdPtr)
RHDOutputsSave(rhdPtr);
RHDPLLsSave(rhdPtr);
+ RHDAudioSave(rhdPtr);
RHDLUTsSave(rhdPtr);
rhdPtr->Crtc[0]->Save(rhdPtr->Crtc[0]);
@@ -2170,6 +2182,7 @@ rhdRestore(RHDPtr rhdPtr)
rhdRestoreCursor(pScrn);
RHDPLLsRestore(rhdPtr);
+ RHDAudioRestore(rhdPtr);
RHDLUTsRestore(rhdPtr);
RHDVGARestore(rhdPtr);
@@ -2425,6 +2438,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);
@@ -2455,6 +2470,10 @@ rhdProcessOptions(ScrnInfoPtr pScrn)
&rhdPtr->scaleTypeOpt, "default");
RhdGetOptValBool (rhdPtr->Options, OPTION_UNVERIFIED_FEAT,
&rhdPtr->unverifiedFeatures, FALSE);
+ RhdGetOptValBool (rhdPtr->Options, OPTION_AUDIO,
+ &audio, FALSE);
+ RhdGetOptValString (rhdPtr->Options, OPTION_HDMI,
+ &hdmi, "none");
rhdAccelOptionsHandle(pScrn);
@@ -2474,6 +2493,23 @@ 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..1730354
--- /dev/null
+++ b/src/rhd_hdmi.c
@@ -0,0 +1,304 @@
+/*
+ * Copyright 2008 Christian König <deathsimple@vodafone.de>
+ * Copyright 2007 Luc Verhaegen <lverhaegen@novell.com>
+ * Copyright 2007 Matthias Hopf <mhopf@novell.com>
+ * Copyright 2007 Egbert Eich <eich@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.
+ */
+
+#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_R600) {
+ 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 switch(hdmi->Offset) {
+ case HDMI_TMDS: RHDRegWrite(hdmi, hdmi->Offset+HDMI_ENABLE, 0x101); break;
+ case HDMI_LVTMA: RHDRegWrite(hdmi, hdmi->Offset+HDMI_ENABLE, 0x105); break;
+ case HDMI_DIG: RHDRegWrite(hdmi, hdmi->Offset+HDMI_ENABLE, 0x110); break;
+ }
+
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_CNTL, 0x4020011);
+
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_0, 0x1000);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_1, 0x31);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_2, 0x93);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_3, 0x202);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_4, 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_5, 0x1220a000);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_6, 0x1000);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_7, 0x14244000);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_8, 0x1880);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_9, 0x1220a000);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_A, 0x1800);
+
+ HdmiAudioInfoFrame(hdmi, 1, 0, 0, 0, 0, 0, 0, FALSE);
+
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_B, 0x100000);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_C, 0x200000);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_D, 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->StoreUnknown[0x4] = RHDRegRead(hdmi, hdmi->Offset+HDMI_UNKNOWN_4);
+ 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[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->StoreUnknown[0xa] = RHDRegRead(hdmi, hdmi->Offset+HDMI_UNKNOWN_A);
+ hdmi->StoreAudioInfoFrame[0x0] = RHDRegRead(hdmi, hdmi->Offset+HDMI_AUDIOINFOFRAME_0);
+ hdmi->StoreAudioInfoFrame[0x1] = RHDRegRead(hdmi, hdmi->Offset+HDMI_AUDIOINFOFRAME_1);
+ hdmi->StoreUnknown[0xb] = RHDRegRead(hdmi, hdmi->Offset+HDMI_UNKNOWN_B);
+ hdmi->StoreUnknown[0xc] = RHDRegRead(hdmi, hdmi->Offset+HDMI_UNKNOWN_C);
+ hdmi->StoreUnknown[0xd] = RHDRegRead(hdmi, hdmi->Offset+HDMI_UNKNOWN_D);
+
+ 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_UNKNOWN_4, hdmi->StoreUnknown[0x4]);
+ 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_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_UNKNOWN_A, hdmi->StoreUnknown[0xa]);
+ 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_B, hdmi->StoreUnknown[0xb]);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_C, hdmi->StoreUnknown[0xc]);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_D, hdmi->StoreUnknown[0xd]);
+}
+
+/*
+ *
+ */
+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..2b5710e
--- /dev/null
+++ b/src/rhd_hdmi.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2008 Christian König <deathsimple@vodafone.de>
+ * Copyright 2007 Luc Verhaegen <lverhaegen@novell.com>
+ * Copyright 2007 Matthias Hopf <mhopf@novell.com>
+ * Copyright 2007 Egbert Eich <eich@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.
+ */
+
+#ifndef _RHD_HDMI_H
+#define _RHD_HDMI_H
+
+struct rhdHdmi {
+
+ int scrnIndex;
+
+ CARD16 Offset;
+
+ Bool Stored;
+ CARD32 StoreEnable;
+ CARD32 StoreControl;
+ CARD32 StoreUnknown[0xe];
+ 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..7a6d63d 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,17 @@ 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);
+ RHDHdmiDestroy(Private->Hdmi);
+
+ xfree(Private);
Output->Private = NULL;
}
@@ -1266,7 +1293,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 +1303,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 +1318,9 @@ RHDLVTMAInit(RHDPtr rhdPtr, CARD8 Type)
Output->Save = TMDSBSave;
Output->Restore = TMDSBRestore;
Output->Property = TMDSBPropertyControl;
+ Output->Destroy = TMDSBDestroy;
+ Private->Hdmi = RHDHdmiInit(rhdPtr, HDMI_LVTMA);
Output->Private = Private;
Private->RunsDualLink = FALSE;
diff --git a/src/rhd_randr.c b/src/rhd_randr.c
index 229344d..2bbdc19 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
@@ -379,6 +380,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 bbf2e15..2b91e38 100644
--- a/src/rhd_regs.h
+++ b/src/rhd_regs.h
@@ -96,6 +96,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+ */
SRBM_STATUS = 0x0E50,
@@ -261,6 +270,16 @@ 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_TMDS = 0x7400,
+ HDMI_LVTMA = 0x7700,
+ HDMI_DIG = 0x7800,
+
/* R500 DAC A */
DACA_ENABLE = 0x7800,
DACA_SOURCE_SELECT = 0x7804,
@@ -1030,5 +1049,30 @@ enum AGP_STATUS_BITS {
AGPv3_8X_MODE = 0x02
};
+enum {
+ /* HDMI registers */
+ HDMI_ENABLE = 0x00,
+ HDMI_CNTL = 0x08,
+ HDMI_UNKNOWN_0 = 0x0C,
+ HDMI_UNKNOWN_1 = 0x10,
+ HDMI_UNKNOWN_2 = 0x14,
+ HDMI_UNKNOWN_3 = 0x18,
+ HDMI_UNKNOWN_4 = 0x28,
+ HDMI_VIDEOINFOFRAME_0 = 0x54,
+ HDMI_VIDEOINFOFRAME_1 = 0x58,
+ HDMI_VIDEOINFOFRAME_2 = 0x5c,
+ HDMI_VIDEOINFOFRAME_3 = 0x60,
+ HDMI_UNKNOWN_5 = 0xac,
+ HDMI_UNKNOWN_6 = 0xb0,
+ HDMI_UNKNOWN_7 = 0xb4,
+ HDMI_UNKNOWN_8 = 0xb8,
+ HDMI_UNKNOWN_9 = 0xbc,
+ HDMI_UNKNOWN_A = 0xc0,
+ HDMI_AUDIOINFOFRAME_0 = 0xcc,
+ HDMI_AUDIOINFOFRAME_1 = 0xd0,
+ HDMI_UNKNOWN_B = 0xd4,
+ HDMI_UNKNOWN_C = 0xd8,
+ HDMI_UNKNOWN_D = 0xdc
+};
#endif /* _RHD_REGS_H */
diff --git a/src/rhd_tmds.c b/src/rhd_tmds.c
index 31dfea1..1e5b4b3 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,15 @@ 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);
+ RHDHdmiDestroy(Private->Hdmi);
+
+ xfree(Private);
Output->Private = NULL;
}
@@ -518,6 +531,7 @@ RHDTMDSAInit(RHDPtr rhdPtr)
Private->RunsDualLink = FALSE;
Private->Coherent = FALSE;
Private->PowerState = RHD_POWER_UNKNOWN;
+ Private->Hdmi = RHDHdmiInit(rhdPtr, HDMI_TMDS);
Output->Private = Private;