mirror of
https://github.com/KolibriOS/kolibrios.git
synced 2024-12-12 01:53:58 +03:00
549 lines
16 KiB
C
549 lines
16 KiB
C
|
/*
|
||
|
* Copyright 2007-2008 Luc Verhaegen <lverhaegen@novell.com>
|
||
|
* Copyright 2007-2008 Matthias Hopf <mhopf@novell.com>
|
||
|
* Copyright 2007-2008 Egbert Eich <eich@novell.com>
|
||
|
* Copyright 2007-2008 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.
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* Deals with the Primary TMDS device (TMDSA) of R500s, R600s.
|
||
|
* Gets replaced by DDIA on RS690 and DIG/UNIPHY on RV620.
|
||
|
*/
|
||
|
|
||
|
#ifdef HAVE_CONFIG_H
|
||
|
#include "config.h"
|
||
|
#endif
|
||
|
|
||
|
#include "xf86.h"
|
||
|
|
||
|
/* for usleep */
|
||
|
#if HAVE_XF86_ANSIC_H
|
||
|
# include "xf86_ansic.h"
|
||
|
#else
|
||
|
# include <unistd.h>
|
||
|
#endif
|
||
|
#include "rhd.h"
|
||
|
#include "rhd_crtc.h"
|
||
|
#include "rhd_connector.h"
|
||
|
#include "rhd_output.h"
|
||
|
#include "rhd_regs.h"
|
||
|
#include "rhd_hdmi.h"
|
||
|
|
||
|
#ifdef ATOM_BIOS
|
||
|
#include "rhd_atombios.h"
|
||
|
#endif
|
||
|
|
||
|
struct rhdTMDSPrivate {
|
||
|
Bool RunsDualLink;
|
||
|
DisplayModePtr Mode;
|
||
|
Bool Coherent;
|
||
|
int PowerState;
|
||
|
|
||
|
struct rhdHdmi *Hdmi;
|
||
|
|
||
|
Bool Stored;
|
||
|
|
||
|
CARD32 StoreControl;
|
||
|
CARD32 StoreSource;
|
||
|
CARD32 StoreFormat;
|
||
|
CARD32 StoreForce;
|
||
|
CARD32 StoreReduction;
|
||
|
CARD32 StoreDCBalancer;
|
||
|
CARD32 StoreDataSynchro;
|
||
|
CARD32 StoreTXEnable;
|
||
|
CARD32 StoreMacro;
|
||
|
CARD32 StoreTXControl;
|
||
|
CARD32 StoreTXAdjust;
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
* We cannot sense for dual link here at all, plus, we need a bit more work
|
||
|
* for enabling the transmitter for sensing to happen on most R5xx cards.
|
||
|
* RV570 (0x7280) and R600 and above seem ok.
|
||
|
*/
|
||
|
static enum rhdSensedOutput
|
||
|
TMDSASense(struct rhdOutput *Output, struct rhdConnector *Connector)
|
||
|
{
|
||
|
RHDPtr rhdPtr = RHDPTRI(Output);
|
||
|
CARD32 Enable, Control, Detect;
|
||
|
enum rhdConnectorType Type = Connector->Type;
|
||
|
Bool ret;
|
||
|
|
||
|
RHDFUNC(Output);
|
||
|
|
||
|
if ((Type != RHD_CONNECTOR_DVI) && (Type != RHD_CONNECTOR_DVI_SINGLE)) {
|
||
|
xf86DrvMsg(Output->scrnIndex, X_WARNING,
|
||
|
"%s: connector type %d is not supported.\n",
|
||
|
__func__, Type);
|
||
|
return RHD_SENSED_NONE;
|
||
|
}
|
||
|
|
||
|
Enable = RHDRegRead(Output, TMDSA_TRANSMITTER_ENABLE);
|
||
|
Control = RHDRegRead(Output, TMDSA_TRANSMITTER_CONTROL);
|
||
|
Detect = RHDRegRead(Output, TMDSA_LOAD_DETECT);
|
||
|
|
||
|
if (rhdPtr->ChipSet < RHD_R600) {
|
||
|
RHDRegMask(Output, TMDSA_TRANSMITTER_ENABLE, 0x00000003, 0x00000003);
|
||
|
RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0x00000001, 0x00000003);
|
||
|
}
|
||
|
|
||
|
RHDRegMask(Output, TMDSA_LOAD_DETECT, 0x00000001, 0x00000001);
|
||
|
usleep(1);
|
||
|
ret = RHDRegRead(Output, TMDSA_LOAD_DETECT) & 0x00000010;
|
||
|
|
||
|
RHDRegMask(Output, TMDSA_LOAD_DETECT, Detect, 0x00000001);
|
||
|
|
||
|
if (rhdPtr->ChipSet < RHD_R600) {
|
||
|
RHDRegWrite(Output, TMDSA_TRANSMITTER_ENABLE, Enable);
|
||
|
RHDRegWrite(Output, TMDSA_TRANSMITTER_CONTROL, Control);
|
||
|
}
|
||
|
|
||
|
RHDDebug(Output->scrnIndex, "%s: %s\n", __func__,
|
||
|
ret ? "Attached" : "Disconnected");
|
||
|
|
||
|
if (ret)
|
||
|
return RHD_SENSED_DVI;
|
||
|
else
|
||
|
return RHD_SENSED_NONE;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
*
|
||
|
*/
|
||
|
static ModeStatus
|
||
|
TMDSAModeValid(struct rhdOutput *Output, DisplayModePtr Mode)
|
||
|
{
|
||
|
RHDFUNC(Output);
|
||
|
|
||
|
if (Mode->Flags & V_INTERLACE)
|
||
|
return MODE_NO_INTERLACE;
|
||
|
|
||
|
if (Mode->Clock < 25000)
|
||
|
return MODE_CLOCK_LOW;
|
||
|
|
||
|
if (Output->Connector->Type == RHD_CONNECTOR_DVI_SINGLE) {
|
||
|
if (Mode->Clock > 165000)
|
||
|
return MODE_CLOCK_HIGH;
|
||
|
} else if (Output->Connector->Type == RHD_CONNECTOR_DVI) {
|
||
|
if (Mode->Clock > 330000) /* could go higher still */
|
||
|
return MODE_CLOCK_HIGH;
|
||
|
}
|
||
|
|
||
|
return MODE_OK;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* This information is not provided in an atombios data table.
|
||
|
*/
|
||
|
static struct R5xxTMDSAMacro {
|
||
|
CARD16 Device;
|
||
|
CARD32 Macro;
|
||
|
} R5xxTMDSAMacro[] = {
|
||
|
{ 0x7104, 0x00C00414 }, /* R520 */
|
||
|
{ 0x7142, 0x00A00415 }, /* RV515 */
|
||
|
{ 0x7145, 0x00A00416 }, /* M54 */
|
||
|
{ 0x7146, 0x00C0041F }, /* RV515 */
|
||
|
{ 0x7147, 0x00C00418 }, /* RV505 */
|
||
|
{ 0x7149, 0x00800416 }, /* M56 */
|
||
|
{ 0x7152, 0x00A00415 }, /* RV515 */
|
||
|
{ 0x7183, 0x00600412 }, /* RV530 */
|
||
|
{ 0x71C1, 0x00C0041F }, /* RV535 */
|
||
|
{ 0x71C2, 0x00A00416 }, /* RV530 */
|
||
|
{ 0x71C4, 0x00A00416 }, /* M56 */
|
||
|
{ 0x71C5, 0x00A00416 }, /* M56 */
|
||
|
{ 0x71C6, 0x00A00513 }, /* RV530 */
|
||
|
{ 0x71D2, 0x00A00513 }, /* RV530 */
|
||
|
{ 0x71D5, 0x00A00513 }, /* M66 */
|
||
|
{ 0x7249, 0x00A00513 }, /* R580 */
|
||
|
{ 0x724B, 0x00A00513 }, /* R580 */
|
||
|
{ 0x7280, 0x00C0041F }, /* RV570 */
|
||
|
{ 0x7288, 0x00C0041F }, /* RV570 */
|
||
|
{ 0x9400, 0x00910419 }, /* R600: */
|
||
|
{ 0, 0} /* End marker */
|
||
|
};
|
||
|
|
||
|
static struct Rv6xxTMDSAMacro {
|
||
|
CARD16 Device;
|
||
|
CARD32 PLL;
|
||
|
CARD32 TX;
|
||
|
} Rv6xxTMDSAMacro[] = {
|
||
|
{ 0x94C1, 0x00010416, 0x00010308 }, /* RV610 */
|
||
|
{ 0x94C3, 0x00010416, 0x00010308 }, /* RV610 */
|
||
|
{ 0x9501, 0x00010416, 0x00010308 }, /* RV670: != atombios */
|
||
|
{ 0x9505, 0x00010416, 0x00010308 }, /* RV670: != atombios */
|
||
|
{ 0x950F, 0x00010416, 0x00010308 }, /* R680 : != atombios */
|
||
|
{ 0x9581, 0x00030410, 0x00301044 }, /* M76 */
|
||
|
{ 0x9587, 0x00010416, 0x00010308 }, /* RV630 */
|
||
|
{ 0x9588, 0x00010416, 0x00010388 }, /* RV630 */
|
||
|
{ 0x9589, 0x00010416, 0x00010388 }, /* RV630 */
|
||
|
{ 0, 0, 0} /* End marker */
|
||
|
};
|
||
|
|
||
|
static void
|
||
|
TMDSAVoltageControl(struct rhdOutput *Output)
|
||
|
{
|
||
|
RHDPtr rhdPtr = RHDPTRI(Output);
|
||
|
int i;
|
||
|
|
||
|
if (rhdPtr->ChipSet < RHD_RV610) {
|
||
|
for (i = 0; R5xxTMDSAMacro[i].Device; i++)
|
||
|
if (R5xxTMDSAMacro[i].Device == rhdPtr->PciDeviceID) {
|
||
|
RHDRegWrite(Output, TMDSA_MACRO_CONTROL, R5xxTMDSAMacro[i].Macro);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
xf86DrvMsg(Output->scrnIndex, X_ERROR, "%s: unhandled chipset: 0x%04X.\n",
|
||
|
__func__, rhdPtr->PciDeviceID);
|
||
|
xf86DrvMsg(Output->scrnIndex, X_INFO, "TMDSA_MACRO_CONTROL: 0x%08X\n",
|
||
|
(unsigned int) RHDRegRead(Output, TMDSA_MACRO_CONTROL));
|
||
|
} else {
|
||
|
for (i = 0; Rv6xxTMDSAMacro[i].Device; i++)
|
||
|
if (Rv6xxTMDSAMacro[i].Device == rhdPtr->PciDeviceID) {
|
||
|
RHDRegWrite(Output, TMDSA_PLL_ADJUST, Rv6xxTMDSAMacro[i].PLL);
|
||
|
RHDRegWrite(Output, TMDSA_TRANSMITTER_ADJUST, Rv6xxTMDSAMacro[i].TX);
|
||
|
return;
|
||
|
}
|
||
|
xf86DrvMsg(Output->scrnIndex, X_ERROR, "%s: unhandled chipset: 0x%04X.\n",
|
||
|
__func__, rhdPtr->PciDeviceID);
|
||
|
xf86DrvMsg(Output->scrnIndex, X_INFO, "TMDSA_PLL_ADJUST: 0x%08X\n",
|
||
|
(unsigned int) RHDRegRead(Output, TMDSA_PLL_ADJUST));
|
||
|
xf86DrvMsg(Output->scrnIndex, X_INFO, "TMDSA_TRANSMITTER_ADJUST: 0x%08X\n",
|
||
|
(unsigned int) RHDRegRead(Output, TMDSA_TRANSMITTER_ADJUST));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
*
|
||
|
*/
|
||
|
static Bool
|
||
|
TMDSAPropertyControl(struct rhdOutput *Output,
|
||
|
enum rhdPropertyAction Action, enum rhdOutputProperty Property, union rhdPropertyData *val)
|
||
|
{
|
||
|
struct rhdTMDSPrivate *Private = (struct rhdTMDSPrivate *) Output->Private;
|
||
|
|
||
|
RHDFUNC(Output);
|
||
|
switch (Action) {
|
||
|
case rhdPropertyCheck:
|
||
|
switch (Property) {
|
||
|
case RHD_OUTPUT_COHERENT:
|
||
|
return TRUE;
|
||
|
default:
|
||
|
return FALSE;
|
||
|
}
|
||
|
case rhdPropertyGet:
|
||
|
switch (Property) {
|
||
|
case RHD_OUTPUT_COHERENT:
|
||
|
val->Bool = Private->Coherent;
|
||
|
return TRUE;
|
||
|
break;
|
||
|
default:
|
||
|
return FALSE;
|
||
|
}
|
||
|
break;
|
||
|
case rhdPropertySet:
|
||
|
switch (Property) {
|
||
|
case RHD_OUTPUT_COHERENT:
|
||
|
Private->Coherent = val->Bool;
|
||
|
Output->Mode(Output, Private->Mode);
|
||
|
Output->Power(Output, RHD_POWER_ON);
|
||
|
break;
|
||
|
default:
|
||
|
return FALSE;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
*
|
||
|
*/
|
||
|
static void
|
||
|
TMDSASet(struct rhdOutput *Output, DisplayModePtr Mode)
|
||
|
{
|
||
|
RHDPtr rhdPtr = RHDPTRI(Output);
|
||
|
struct rhdTMDSPrivate *Private = (struct rhdTMDSPrivate *) Output->Private;
|
||
|
|
||
|
RHDFUNC(Output);
|
||
|
|
||
|
/* Clear out some HPD events first: this should be under driver control. */
|
||
|
RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0, 0x0000000C);
|
||
|
RHDRegMask(Output, TMDSA_TRANSMITTER_ENABLE, 0, 0x00070000);
|
||
|
RHDRegMask(Output, TMDSA_CNTL, 0, 0x00000010);
|
||
|
|
||
|
/* Disable the transmitter */
|
||
|
RHDRegMask(Output, TMDSA_TRANSMITTER_ENABLE, 0, 0x00001D1F);
|
||
|
|
||
|
/* Disable bit reduction and reset temporal dither */
|
||
|
RHDRegMask(Output, TMDSA_BIT_DEPTH_CONTROL, 0, 0x00010101);
|
||
|
if (rhdPtr->ChipSet < RHD_R600) {
|
||
|
RHDRegMask(Output, TMDSA_BIT_DEPTH_CONTROL, 0x04000000, 0x04000000);
|
||
|
usleep(2);
|
||
|
RHDRegMask(Output, TMDSA_BIT_DEPTH_CONTROL, 0, 0x04000000);
|
||
|
} else {
|
||
|
RHDRegMask(Output, TMDSA_BIT_DEPTH_CONTROL, 0x02000000, 0x02000000);
|
||
|
usleep(2);
|
||
|
RHDRegMask(Output, TMDSA_BIT_DEPTH_CONTROL, 0, 0x02000000);
|
||
|
}
|
||
|
|
||
|
/* reset phase on vsync and use RGB */
|
||
|
RHDRegMask(Output, TMDSA_CNTL, 0x00001000, 0x00011000);
|
||
|
|
||
|
/* Select CRTC, select syncA, no stereosync */
|
||
|
RHDRegMask(Output, TMDSA_SOURCE_SELECT, Output->Crtc->Id, 0x00010101);
|
||
|
|
||
|
/* Single link, for now */
|
||
|
RHDRegWrite(Output, TMDSA_COLOR_FORMAT, 0);
|
||
|
|
||
|
/* store this for TRANSMITTER_ENABLE in TMDSAPower */
|
||
|
Private->Mode = Mode;
|
||
|
if (Mode->SynthClock > 165000) {
|
||
|
RHDRegMask(Output, TMDSA_CNTL, 0x01000000, 0x01000000);
|
||
|
Private->RunsDualLink = TRUE; /* for TRANSMITTER_ENABLE in TMDSAPower */
|
||
|
} else {
|
||
|
RHDRegMask(Output, TMDSA_CNTL, 0, 0x01000000);
|
||
|
Private->RunsDualLink = FALSE;
|
||
|
}
|
||
|
|
||
|
/* Disable force data */
|
||
|
RHDRegMask(Output, TMDSA_FORCE_OUTPUT_CNTL, 0, 0x00000001);
|
||
|
|
||
|
/* DC balancer enable */
|
||
|
RHDRegMask(Output, TMDSA_DCBALANCER_CONTROL, 0x00000001, 0x00000001);
|
||
|
|
||
|
TMDSAVoltageControl(Output);
|
||
|
|
||
|
/* use IDCLK */
|
||
|
RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0x00000010, 0x00000010);
|
||
|
|
||
|
if (Private->Coherent)
|
||
|
RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0x00000000, 0x10000000);
|
||
|
else
|
||
|
RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0x10000000, 0x10000000);
|
||
|
|
||
|
RHDHdmiSetMode(Private->Hdmi, Mode);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
*
|
||
|
*/
|
||
|
static void
|
||
|
TMDSAPower(struct rhdOutput *Output, int Power)
|
||
|
{
|
||
|
RHDPtr rhdPtr = RHDPTRI(Output);
|
||
|
struct rhdTMDSPrivate *Private = (struct rhdTMDSPrivate *) Output->Private;
|
||
|
|
||
|
RHDDebug(Output->scrnIndex, "%s(%s,%s)\n",__func__,Output->Name,
|
||
|
rhdPowerString[Power]);
|
||
|
|
||
|
switch (Power) {
|
||
|
case RHD_POWER_ON:
|
||
|
if (Private->PowerState == RHD_POWER_SHUTDOWN
|
||
|
|| Private->PowerState == RHD_POWER_UNKNOWN) {
|
||
|
RHDRegMask(Output, TMDSA_CNTL, 0x1, 0x00000001);
|
||
|
|
||
|
RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0x00000001, 0x00000001);
|
||
|
usleep(20);
|
||
|
|
||
|
/* reset transmitter PLL */
|
||
|
RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0x00000002, 0x00000002);
|
||
|
usleep(2);
|
||
|
RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0, 0x00000002);
|
||
|
|
||
|
usleep(30);
|
||
|
|
||
|
/* restart data synchronisation */
|
||
|
if (rhdPtr->ChipSet < RHD_R600) {
|
||
|
RHDRegMask(Output, TMDSA_DATA_SYNCHRONIZATION_R500, 0x00000001, 0x00000001);
|
||
|
usleep(2);
|
||
|
RHDRegMask(Output, TMDSA_DATA_SYNCHRONIZATION_R500, 0x00000100, 0x00000100);
|
||
|
RHDRegMask(Output, TMDSA_DATA_SYNCHRONIZATION_R500, 0, 0x00000001);
|
||
|
} else {
|
||
|
RHDRegMask(Output, TMDSA_DATA_SYNCHRONIZATION_R600, 0x00000001, 0x00000001);
|
||
|
usleep(2);
|
||
|
RHDRegMask(Output, TMDSA_DATA_SYNCHRONIZATION_R600, 0x00000100, 0x00000100);
|
||
|
RHDRegMask(Output, TMDSA_DATA_SYNCHRONIZATION_R600, 0, 0x00000001);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (Private->RunsDualLink) {
|
||
|
/* bit 9 is not known by anything below RV610, but is ignored by
|
||
|
the hardware anyway */
|
||
|
RHDRegMask(Output, TMDSA_TRANSMITTER_ENABLE, 0x00001F1F, 0x00001F1F);
|
||
|
} else
|
||
|
RHDRegMask(Output, TMDSA_TRANSMITTER_ENABLE, 0x0000001F, 0x00001F1F);
|
||
|
|
||
|
if(Output->Connector != NULL && RHDConnectorEnableHDMI(Output->Connector))
|
||
|
RHDHdmiEnable(Private->Hdmi, TRUE);
|
||
|
else
|
||
|
RHDHdmiEnable(Private->Hdmi, FALSE);
|
||
|
Private->PowerState = RHD_POWER_ON;
|
||
|
return;
|
||
|
|
||
|
case RHD_POWER_RESET:
|
||
|
RHDRegMask(Output, TMDSA_TRANSMITTER_ENABLE, 0, 0x00001F1F);
|
||
|
/* if we do a RESET after a SHUTDOWN don't raise the power level,
|
||
|
* and similarly, don't raise from UNKNOWN state. */
|
||
|
if (Private->PowerState == RHD_POWER_ON)
|
||
|
Private->PowerState = RHD_POWER_RESET;
|
||
|
return;
|
||
|
|
||
|
case RHD_POWER_SHUTDOWN:
|
||
|
default:
|
||
|
RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0x00000002, 0x00000002);
|
||
|
usleep(2);
|
||
|
RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0, 0x00000001);
|
||
|
RHDRegMask(Output, TMDSA_TRANSMITTER_ENABLE, 0, 0x00001F1F);
|
||
|
RHDRegMask(Output, TMDSA_CNTL, 0, 0x00000001);
|
||
|
RHDHdmiEnable(Private->Hdmi, FALSE);
|
||
|
Private->PowerState = RHD_POWER_SHUTDOWN;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
*
|
||
|
*/
|
||
|
static void
|
||
|
TMDSASave(struct rhdOutput *Output)
|
||
|
{
|
||
|
int ChipSet = RHDPTRI(Output)->ChipSet;
|
||
|
struct rhdTMDSPrivate *Private = (struct rhdTMDSPrivate *) Output->Private;
|
||
|
|
||
|
RHDFUNC(Output);
|
||
|
|
||
|
Private->StoreControl = RHDRegRead(Output, TMDSA_CNTL);
|
||
|
Private->StoreSource = RHDRegRead(Output, TMDSA_SOURCE_SELECT);
|
||
|
Private->StoreFormat = RHDRegRead(Output, TMDSA_COLOR_FORMAT);
|
||
|
Private->StoreForce = RHDRegRead(Output, TMDSA_FORCE_OUTPUT_CNTL);
|
||
|
Private->StoreReduction = RHDRegRead(Output, TMDSA_BIT_DEPTH_CONTROL);
|
||
|
Private->StoreDCBalancer = RHDRegRead(Output, TMDSA_DCBALANCER_CONTROL);
|
||
|
|
||
|
if (ChipSet < RHD_R600)
|
||
|
Private->StoreDataSynchro = RHDRegRead(Output, TMDSA_DATA_SYNCHRONIZATION_R500);
|
||
|
else
|
||
|
Private->StoreDataSynchro = RHDRegRead(Output, TMDSA_DATA_SYNCHRONIZATION_R600);
|
||
|
|
||
|
Private->StoreTXEnable = RHDRegRead(Output, TMDSA_TRANSMITTER_ENABLE);
|
||
|
Private->StoreMacro = RHDRegRead(Output, TMDSA_MACRO_CONTROL);
|
||
|
Private->StoreTXControl = RHDRegRead(Output, TMDSA_TRANSMITTER_CONTROL);
|
||
|
|
||
|
if (ChipSet >= RHD_RV610)
|
||
|
Private->StoreTXAdjust = RHDRegRead(Output, TMDSA_TRANSMITTER_ADJUST);
|
||
|
|
||
|
RHDHdmiSave(Private->Hdmi);
|
||
|
|
||
|
Private->Stored = TRUE;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
*
|
||
|
*/
|
||
|
static void
|
||
|
TMDSARestore(struct rhdOutput *Output)
|
||
|
{
|
||
|
int ChipSet = RHDPTRI(Output)->ChipSet;
|
||
|
struct rhdTMDSPrivate *Private = (struct rhdTMDSPrivate *) Output->Private;
|
||
|
|
||
|
RHDFUNC(Output);
|
||
|
|
||
|
if (!Private->Stored) {
|
||
|
xf86DrvMsg(Output->scrnIndex, X_ERROR,
|
||
|
"%s: No registers stored.\n", __func__);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
RHDRegWrite(Output, TMDSA_CNTL, Private->StoreControl);
|
||
|
RHDRegWrite(Output, TMDSA_SOURCE_SELECT, Private->StoreSource);
|
||
|
RHDRegWrite(Output, TMDSA_COLOR_FORMAT, Private->StoreFormat);
|
||
|
RHDRegWrite(Output, TMDSA_FORCE_OUTPUT_CNTL, Private->StoreForce);
|
||
|
RHDRegWrite(Output, TMDSA_BIT_DEPTH_CONTROL, Private->StoreReduction);
|
||
|
RHDRegWrite(Output, TMDSA_DCBALANCER_CONTROL, Private->StoreDCBalancer);
|
||
|
|
||
|
if (ChipSet < RHD_R600)
|
||
|
RHDRegWrite(Output, TMDSA_DATA_SYNCHRONIZATION_R500, Private->StoreDataSynchro);
|
||
|
else
|
||
|
RHDRegWrite(Output, TMDSA_DATA_SYNCHRONIZATION_R600, Private->StoreDataSynchro);
|
||
|
|
||
|
RHDRegWrite(Output, TMDSA_TRANSMITTER_ENABLE, Private->StoreTXEnable);
|
||
|
RHDRegWrite(Output, TMDSA_MACRO_CONTROL, Private->StoreMacro);
|
||
|
RHDRegWrite(Output, TMDSA_TRANSMITTER_CONTROL, Private->StoreTXControl);
|
||
|
|
||
|
if (ChipSet >= RHD_RV610)
|
||
|
RHDRegWrite(Output, TMDSA_TRANSMITTER_ADJUST, Private->StoreTXAdjust);
|
||
|
|
||
|
RHDHdmiRestore(Private->Hdmi);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
*
|
||
|
*/
|
||
|
static void
|
||
|
TMDSADestroy(struct rhdOutput *Output)
|
||
|
{
|
||
|
struct rhdTMDSPrivate *Private = (struct rhdTMDSPrivate *) Output->Private;
|
||
|
RHDFUNC(Output);
|
||
|
|
||
|
if (!Private)
|
||
|
return;
|
||
|
|
||
|
RHDHdmiDestroy(Private->Hdmi);
|
||
|
|
||
|
xfree(Private);
|
||
|
Output->Private = NULL;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
*
|
||
|
*/
|
||
|
struct rhdOutput *
|
||
|
RHDTMDSAInit(RHDPtr rhdPtr)
|
||
|
{
|
||
|
struct rhdOutput *Output;
|
||
|
struct rhdTMDSPrivate *Private;
|
||
|
|
||
|
RHDFUNC(rhdPtr);
|
||
|
|
||
|
Output = xnfcalloc(sizeof(struct rhdOutput), 1);
|
||
|
|
||
|
Output->scrnIndex = rhdPtr->scrnIndex;
|
||
|
Output->Name = "TMDS A";
|
||
|
Output->Id = RHD_OUTPUT_TMDSA;
|
||
|
|
||
|
Output->Sense = TMDSASense;
|
||
|
Output->ModeValid = TMDSAModeValid;
|
||
|
Output->Mode = TMDSASet;
|
||
|
Output->Power = TMDSAPower;
|
||
|
Output->Save = TMDSASave;
|
||
|
Output->Restore = TMDSARestore;
|
||
|
Output->Destroy = TMDSADestroy;
|
||
|
Output->Property = TMDSAPropertyControl;
|
||
|
|
||
|
Private = xnfcalloc(sizeof(struct rhdTMDSPrivate), 1);
|
||
|
Private->RunsDualLink = FALSE;
|
||
|
Private->Coherent = FALSE;
|
||
|
Private->PowerState = RHD_POWER_UNKNOWN;
|
||
|
|
||
|
Output->Private = Private;
|
||
|
|
||
|
return Output;
|
||
|
}
|