From 2fe6021c015dd6573e554bde43bd44ce71f8bdf4 Mon Sep 17 00:00:00 2001 From: Christian König Date: Mon, 14 Jul 2008 16:05:50 +0200 Subject: Audio/HDMI: Add basic support for Audio frames over HDMI. --- src/Makefile.am | 4 + src/rhd.h | 4 + src/rhd_audio.c | 162 +++++++++++++++++++++++++++++ src/rhd_audio.h | 54 ++++++++++ src/rhd_dig.c | 13 ++- src/rhd_driver.c | 38 ++++++- src/rhd_hdmi.c | 304 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/rhd_hdmi.h | 50 +++++++++ src/rhd_lvtma.c | 43 ++++++-- src/rhd_randr.c | 2 + src/rhd_regs.h | 44 ++++++++ src/rhd_tmds.c | 22 +++- 12 files changed, 727 insertions(+), 13 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 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 + * 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_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 + * 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_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 + * 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_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 + * 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[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 */ @@ -687,6 +688,21 @@ LVDSInfoRetrieve(RHDPtr rhdPtr) return Private; } +/* + * + */ +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; -- cgit v1.2.3