0,0 → 1,1869 |
/* |
* 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. |
*/ |
|
#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" |
#include "rhd_atomout.h" |
#endif |
|
#define FMT2_OFFSET 0x800 |
#define DIG1_OFFSET 0x000 |
#define DIG2_OFFSET 0x400 |
|
/* |
* Transmitter |
*/ |
struct transmitter { |
enum rhdSensedOutput (*Sense) (struct rhdOutput *Output, |
enum rhdConnectorType Type); |
ModeStatus (*ModeValid) (struct rhdOutput *Output, DisplayModePtr Mode); |
void (*Mode) (struct rhdOutput *Output, struct rhdCrtc *Crtc, DisplayModePtr Mode); |
void (*Power) (struct rhdOutput *Output, int Power); |
void (*Save) (struct rhdOutput *Output); |
void (*Restore) (struct rhdOutput *Output); |
void (*Destroy) (struct rhdOutput *Output); |
Bool (*Property) (struct rhdOutput *Output, |
enum rhdPropertyAction Action, enum rhdOutputProperty Property, union rhdPropertyData *val); |
#ifdef NOT_YET |
Bool (*WrappedPropertyCallback) (struct rhdOutput *Output, |
enum rhdPropertyAction Action, enum rhdOutputProperty Property, union rhdPropertyData *val); |
void *PropertyPrivate; |
#endif |
void *Private; |
}; |
|
/* |
* Encoder |
*/ |
struct encoder { |
ModeStatus (*ModeValid) (struct rhdOutput *Output, DisplayModePtr Mode); |
void (*Mode) (struct rhdOutput *Output, struct rhdCrtc *Crtc, DisplayModePtr Mode); |
void (*Power) (struct rhdOutput *Output, int Power); |
void (*Save) (struct rhdOutput *Output); |
void (*Restore) (struct rhdOutput *Output); |
void (*Destroy) (struct rhdOutput *Output); |
void *Private; |
}; |
|
/* |
* |
*/ |
enum encoderMode { |
DISPLAYPORT = 0, |
LVDS = 1, |
TMDS_DVI = 2, |
TMDS_HDMI = 3, |
SDVO = 4 |
}; |
|
enum encoderID { |
ENCODER_NONE, |
ENCODER_DIG1, |
ENCODER_DIG2 |
}; |
|
struct DIGPrivate |
{ |
struct encoder Encoder; |
struct transmitter Transmitter; |
enum encoderID EncoderID; |
enum encoderMode EncoderMode; |
Bool Coherent; |
Bool RunDualLink; |
DisplayModePtr Mode; |
struct rhdHdmi *Hdmi; |
|
/* LVDS */ |
Bool FPDI; |
CARD32 PowerSequenceDe2Bl; |
CARD32 PowerSequenceDig2De; |
CARD32 OffDelay; |
struct rhdFMTDither FMTDither; |
int BlLevel; |
}; |
|
/* |
* LVTMA Transmitter |
*/ |
|
struct LVTMATransmitterPrivate |
{ |
Bool Stored; |
|
CARD32 StoredTransmitterControl; |
CARD32 StoredTransmitterAdjust; |
CARD32 StoredPreemphasisControl; |
CARD32 StoredMacroControl; |
CARD32 StoredLVTMADataSynchronization; |
CARD32 StoredTransmiterEnable; |
CARD32 StoredPwrSeqCntl; |
CARD32 StoredPwrSeqRevDiv; |
CARD32 StoredPwrSeqDelay1; |
CARD32 StoredPwrSeqDelay2; |
}; |
|
/* |
* |
*/ |
static ModeStatus |
LVTMATransmitterModeValid(struct rhdOutput *Output, DisplayModePtr Mode) |
{ |
RHDFUNC(Output); |
|
if (Mode->Flags & V_INTERLACE) |
return MODE_NO_INTERLACE; |
|
if (Output->Connector->Type == RHD_CONNECTOR_DVI_SINGLE |
&& Mode->SynthClock > 165000) |
return MODE_CLOCK_HIGH; |
|
return MODE_OK; |
} |
|
static void |
LVDSSetBacklight(struct rhdOutput *Output, int level) |
{ |
struct DIGPrivate *Private = (struct DIGPrivate *) Output->Private; |
|
RHDFUNC(Output); |
|
Private->BlLevel = level; |
|
RHDRegMask(Output, RV620_LVTMA_PWRSEQ_REF_DIV, |
0x144 << LVTMA_BL_MOD_REF_DI_SHIFT, |
0x7ff << LVTMA_BL_MOD_REF_DI_SHIFT); |
RHDRegWrite(Output, RV620_LVTMA_BL_MOD_CNTL, |
0xff << LVTMA_BL_MOD_RES_SHIFT |
| level << LVTMA_BL_MOD_LEVEL_SHIFT |
| LVTMA_BL_MOD_EN); |
} |
|
/* |
* |
*/ |
static Bool |
LVDSTransmitterPropertyControl(struct rhdOutput *Output, |
enum rhdPropertyAction Action, enum rhdOutputProperty Property, union rhdPropertyData *val) |
{ |
struct DIGPrivate *Private = (struct DIGPrivate *) Output->Private; |
|
RHDFUNC(Output); |
switch (Action) { |
case rhdPropertyCheck: |
if (Private->BlLevel < 0) |
return FALSE; |
switch (Property) { |
case RHD_OUTPUT_BACKLIGHT: |
return TRUE; |
default: |
return FALSE; |
} |
case rhdPropertyGet: |
if (Private->BlLevel < 0) |
return FALSE; |
switch (Property) { |
case RHD_OUTPUT_BACKLIGHT: |
val->integer = Private->BlLevel; |
return TRUE; |
default: |
return FALSE; |
} |
break; |
case rhdPropertySet: |
if (Private->BlLevel < 0) |
return FALSE; |
switch (Property) { |
case RHD_OUTPUT_BACKLIGHT: |
LVDSSetBacklight(Output, val->integer); |
return TRUE; |
default: |
return FALSE; |
} |
break; |
} |
return TRUE; |
} |
|
/* |
* |
*/ |
static Bool |
TMDSTransmitterPropertyControl(struct rhdOutput *Output, |
enum rhdPropertyAction Action, enum rhdOutputProperty Property, union rhdPropertyData *val) |
{ |
struct DIGPrivate *Private = (struct DIGPrivate *) 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; |
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 |
LVTMATransmitterSet(struct rhdOutput *Output, struct rhdCrtc *Crtc, DisplayModePtr Mode) |
{ |
struct DIGPrivate *Private = (struct DIGPrivate *)Output->Private; |
CARD32 value = 0; |
#ifdef ATOM_BIOS |
AtomBiosArgRec data; |
#endif |
RHDPtr rhdPtr = RHDPTRI(Output); |
Bool doCoherent = Private->Coherent; |
RHDFUNC(Output); |
|
/* set coherent / not coherent mode; whatever that is */ |
if (Output->Connector->Type != RHD_CONNECTOR_PANEL) |
RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_CONTROL, |
doCoherent ? 0 : RV62_LVTMA_BYPASS_PLL, RV62_LVTMA_BYPASS_PLL); |
|
Private->Mode = Mode; |
#ifdef ATOM_BIOS |
RHDDebug(Output->scrnIndex, "%s: SynthClock: %i Hex: %x EncoderMode: %x\n",__func__, |
(Mode->SynthClock),(Mode->SynthClock / 10), Private->EncoderMode); |
|
/* Set up magic value that's used for list lookup */ |
value = ((Mode->SynthClock / 10 / ((Private->RunDualLink) ? 2 : 1)) & 0xffff) |
| (Private->EncoderMode << 16) |
| ((doCoherent ? 0x2 : 0) << 24); |
|
RHDDebug(Output->scrnIndex, "%s: GetConditionalGoldenSettings for: %x\n", __func__, value); |
|
/* Get data from DIG2TransmitterControl table */ |
data.val = 0x4d; |
if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, ATOMBIOS_GET_CODE_DATA_TABLE, |
&data) == ATOM_SUCCESS) { |
AtomBiosArgRec data1; |
CARD32 *d_p = NULL; |
|
data1.GoldenSettings.BIOSPtr = data.CommandDataTable.loc; |
data1.GoldenSettings.End = data1.GoldenSettings.BIOSPtr + data.CommandDataTable.size; |
data1.GoldenSettings.value = value; |
|
/* now find pointer */ |
if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, |
ATOM_GET_CONDITIONAL_GOLDEN_SETTINGS, &data1) == ATOM_SUCCESS) { |
d_p = (CARD32*)data1.GoldenSettings.BIOSPtr; |
} else { |
/* nothing found, now try toggling the coherent setting */ |
doCoherent = !doCoherent; |
value = (value & ~(0x2 << 24)) | ((doCoherent ? 0x2 : 0) << 24); |
data1.GoldenSettings.value = value; |
|
if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, |
ATOM_GET_CONDITIONAL_GOLDEN_SETTINGS, &data1) == ATOM_SUCCESS) { |
d_p = (CARD32*)data1.GoldenSettings.BIOSPtr; |
/* set coherent / not coherent mode; whatever that is */ |
xf86DrvMsg(Output->scrnIndex, X_INFO, "%s: %soherent Mode not supported, switching to %soherent.\n", |
__func__, doCoherent ? "Inc" : "C", doCoherent ? "C" : "Inc"); |
if (Output->Connector->Type != RHD_CONNECTOR_PANEL) |
RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_CONTROL, |
doCoherent ? 0 : RV62_LVTMA_BYPASS_PLL, RV62_LVTMA_BYPASS_PLL); |
} else |
doCoherent = Private->Coherent; /* reset old value if nothing found either */ |
} |
if (d_p) { |
RHDDebug(Output->scrnIndex, "TransmitterAdjust: 0x%8.8x\n",d_p[0]); |
RHDRegWrite(Output, RV620_LVTMA_TRANSMITTER_ADJUST, d_p[0]); |
|
RHDDebug(Output->scrnIndex, "PreemphasisControl: 0x%8.8x\n",d_p[1]); |
RHDRegWrite(Output, RV620_LVTMA_PREEMPHASIS_CONTROL, d_p[1]); |
|
RHDDebug(Output->scrnIndex, "MacroControl: 0x%8.8x\n",d_p[2]); |
RHDRegWrite(Output, RV620_LVTMA_MACRO_CONTROL, d_p[2]); |
} else |
xf86DrvMsg(Output->scrnIndex, X_WARNING, "%s: cannot get golden settings\n",__func__); |
} else |
#endif |
{ |
xf86DrvMsg(Output->scrnIndex, X_WARNING, "%s: No AtomBIOS supplied " |
"electrical parameters available\n", __func__); |
} |
} |
|
/* |
* |
*/ |
static void |
LVTMATransmitterSave(struct rhdOutput *Output) |
{ |
struct DIGPrivate *digPrivate = (struct DIGPrivate *)Output->Private; |
struct LVTMATransmitterPrivate *Private = (struct LVTMATransmitterPrivate*)digPrivate->Transmitter.Private; |
|
Private->StoredTransmitterControl = RHDRegRead(Output, RV620_LVTMA_TRANSMITTER_CONTROL); |
Private->StoredTransmitterAdjust = RHDRegRead(Output, RV620_LVTMA_TRANSMITTER_ADJUST); |
Private->StoredPreemphasisControl = RHDRegRead(Output, RV620_LVTMA_PREEMPHASIS_CONTROL); |
Private->StoredMacroControl = RHDRegRead(Output, RV620_LVTMA_MACRO_CONTROL); |
Private->StoredLVTMADataSynchronization = RHDRegRead(Output, RV620_LVTMA_DATA_SYNCHRONIZATION); |
Private->StoredTransmiterEnable = RHDRegRead(Output, RV620_LVTMA_TRANSMITTER_ENABLE); |
} |
|
/* |
* |
*/ |
static void |
LVTMATransmitterRestore(struct rhdOutput *Output) |
{ |
struct DIGPrivate *digPrivate = (struct DIGPrivate *)Output->Private; |
struct LVTMATransmitterPrivate *Private = (struct LVTMATransmitterPrivate*)digPrivate->Transmitter.Private; |
|
RHDFUNC(Output); |
|
/* write control values back */ |
RHDRegWrite(Output, RV620_LVTMA_TRANSMITTER_CONTROL,Private->StoredTransmitterControl); |
usleep (14); |
/* reset PLL */ |
RHDRegWrite(Output, RV620_LVTMA_TRANSMITTER_CONTROL,Private->StoredTransmitterControl |
| RV62_LVTMA_PLL_RESET); |
usleep (10); |
/* unreset PLL */ |
RHDRegWrite(Output, RV620_LVTMA_TRANSMITTER_CONTROL,Private->StoredTransmitterControl); |
usleep(1000); |
RHDRegWrite(Output, RV620_LVTMA_TRANSMITTER_ADJUST, Private->StoredTransmitterAdjust); |
RHDRegWrite(Output, RV620_LVTMA_PREEMPHASIS_CONTROL, Private->StoredPreemphasisControl); |
RHDRegWrite(Output, RV620_LVTMA_MACRO_CONTROL, Private->StoredMacroControl); |
/* start data synchronization */ |
RHDRegWrite(Output, RV620_LVTMA_DATA_SYNCHRONIZATION, (Private->StoredLVTMADataSynchronization |
& ~(CARD32)RV62_LVTMA_DSYNSEL) |
| RV62_LVTMA_PFREQCHG); |
usleep (1); |
RHDRegWrite(Output, RV620_LVTMA_DATA_SYNCHRONIZATION, Private->StoredLVTMADataSynchronization); |
usleep(10); |
RHDRegWrite(Output, RV620_LVTMA_DATA_SYNCHRONIZATION, Private->StoredLVTMADataSynchronization); |
RHDRegWrite(Output, RV620_LVTMA_TRANSMITTER_ENABLE, Private->StoredTransmiterEnable); |
} |
|
/* |
* |
*/ |
static void |
LVTMA_TMDSTransmitterSet(struct rhdOutput *Output, struct rhdCrtc *Crtc, DisplayModePtr Mode) |
{ |
RHDFUNC(Output); |
|
/* TMDS Mode */ |
RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_CONTROL, |
RV62_LVTMA_USE_CLK_DATA, RV62_LVTMA_USE_CLK_DATA); |
|
LVTMATransmitterSet(Output, Crtc, Mode); |
|
/* use differential post divider input */ |
RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_CONTROL, |
RV62_LVTMA_IDSCKSEL, RV62_LVTMA_IDSCKSEL); |
} |
|
/* |
* |
*/ |
static void |
LVTMA_TMDSTransmitterPower(struct rhdOutput *Output, int Power) |
{ |
struct DIGPrivate *Private = (struct DIGPrivate *)Output->Private; |
|
RHDFUNC(Output); |
|
switch (Power) { |
case RHD_POWER_ON: |
/* enable PLL */ |
RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_CONTROL, |
RV62_LVTMA_PLL_ENABLE, RV62_LVTMA_PLL_ENABLE); |
usleep(14); |
/* PLL reset on */ |
RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_CONTROL, |
RV62_LVTMA_PLL_RESET, RV62_LVTMA_PLL_RESET); |
usleep(10); |
/* PLL reset off */ |
RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_CONTROL, |
0, RV62_LVTMA_PLL_RESET); |
usleep(1000); |
/* start data synchronization */ |
RHDRegMask(Output, RV620_LVTMA_DATA_SYNCHRONIZATION, |
RV62_LVTMA_PFREQCHG, RV62_LVTMA_PFREQCHG); |
usleep(1); |
/* restart write address logic */ |
RHDRegMask(Output, RV620_LVTMA_DATA_SYNCHRONIZATION, |
RV62_LVTMA_DSYNSEL, RV62_LVTMA_DSYNSEL); |
#if 1 |
/* TMDS Mode ?? */ |
RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_CONTROL, |
RV62_LVTMA_MODE, RV62_LVTMA_MODE); |
#endif |
/* enable lower link */ |
RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_ENABLE, |
RV62_LVTMA_LNKL, |
RV62_LVTMA_LNK_ALL); |
if (Private->RunDualLink) { |
usleep (28); |
/* enable upper link */ |
RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_ENABLE, |
RV62_LVTMA_LNKU, |
RV62_LVTMA_LNKU); |
} |
return; |
case RHD_POWER_RESET: |
/* disable all links */ |
RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_ENABLE, |
0, RV62_LVTMA_LNK_ALL); |
return; |
case RHD_POWER_SHUTDOWN: |
default: |
/* disable transmitter */ |
RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_ENABLE, |
0, RV62_LVTMA_LNK_ALL); |
/* PLL reset */ |
RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_CONTROL, |
RV62_LVTMA_PLL_RESET, RV62_LVTMA_PLL_RESET); |
usleep(10); |
/* end PLL reset */ |
RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_CONTROL, |
0, RV62_LVTMA_PLL_RESET); |
/* disable data synchronization */ |
RHDRegMask(Output, RV620_LVTMA_DATA_SYNCHRONIZATION, |
0, RV62_LVTMA_DSYNSEL); |
/* reset macro control */ |
RHDRegWrite(Output, RV620_LVTMA_TRANSMITTER_ADJUST, 0); |
|
return; |
} |
} |
|
/* |
* |
*/ |
static void |
LVTMA_TMDSTransmitterSave(struct rhdOutput *Output) |
{ |
struct DIGPrivate *digPrivate = (struct DIGPrivate *)Output->Private; |
struct LVTMATransmitterPrivate *Private = (struct LVTMATransmitterPrivate*)digPrivate->Transmitter.Private; |
|
RHDFUNC(Output); |
|
LVTMATransmitterSave(Output); |
|
Private->Stored = TRUE; |
} |
|
/* |
* |
*/ |
static void |
LVTMA_TMDSTransmitterRestore(struct rhdOutput *Output) |
{ |
struct DIGPrivate *digPrivate = (struct DIGPrivate *)Output->Private; |
struct LVTMATransmitterPrivate *Private = (struct LVTMATransmitterPrivate*)digPrivate->Transmitter.Private; |
|
RHDFUNC(Output); |
|
if (!Private->Stored) { |
xf86DrvMsg(Output->scrnIndex, X_ERROR, |
"%s: No registers stored.\n", __func__); |
return; |
} |
|
LVTMATransmitterRestore(Output); |
} |
|
/* |
* |
*/ |
static void |
LVTMA_LVDSTransmitterSet(struct rhdOutput *Output, struct rhdCrtc *Crtc, DisplayModePtr Mode) |
{ |
RHDFUNC(Output); |
|
/* LVDS Mode */ |
RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_CONTROL, |
0, RV62_LVTMA_USE_CLK_DATA); |
|
LVTMATransmitterSet(Output, Crtc, Mode); |
|
/* use IDCLK */ |
RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_CONTROL, RV62_LVTMA_IDSCKSEL, RV62_LVTMA_IDSCKSEL); |
/* enable pwrseq, pwrseq overwrite PPL enable, reset */ |
RHDRegMask(Output, RV620_LVTMA_PWRSEQ_CNTL, |
RV62_LVTMA_PWRSEQ_EN |
| RV62_LVTMA_PLL_ENABLE_PWRSEQ_MASK |
| RV62_LVTMA_PLL_RESET_PWRSEQ_MASK, |
RV62_LVTMA_PWRSEQ_EN |
| RV62_LVTMA_PLL_ENABLE_PWRSEQ_MASK |
| RV62_LVTMA_PLL_RESET_PWRSEQ_MASK |
); |
|
} |
|
/* |
* |
*/ |
static void |
LVTMA_LVDSTransmitterPower(struct rhdOutput *Output, int Power) |
{ |
struct DIGPrivate *Private = (struct DIGPrivate *)Output->Private; |
CARD32 tmp, tmp1; |
int i; |
|
RHDFUNC(Output); |
|
switch (Power) { |
case RHD_POWER_ON: |
/* enable PLL */ |
RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_CONTROL, |
RV62_LVTMA_PLL_ENABLE, RV62_LVTMA_PLL_ENABLE); |
usleep(14); |
/* PLL reset on */ |
RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_CONTROL, |
RV62_LVTMA_PLL_RESET, RV62_LVTMA_PLL_RESET); |
usleep(10); |
/* PLL reset off */ |
RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_CONTROL, |
0, RV62_LVTMA_PLL_RESET); |
usleep(1000); |
/* start data synchronization */ |
RHDRegMask(Output, RV620_LVTMA_DATA_SYNCHRONIZATION, |
RV62_LVTMA_PFREQCHG, RV62_LVTMA_PFREQCHG); |
usleep(1); |
/* restart write address logic */ |
RHDRegMask(Output, RV620_LVTMA_DATA_SYNCHRONIZATION, |
RV62_LVTMA_DSYNSEL, RV62_LVTMA_DSYNSEL); |
/* SYNCEN disables pwrseq ?? */ |
RHDRegMask(Output, RV620_LVTMA_PWRSEQ_CNTL, |
RV62_LVTMA_PWRSEQ_DISABLE_SYNCEN_CONTROL_OF_TX_EN, |
RV62_LVTMA_PWRSEQ_DISABLE_SYNCEN_CONTROL_OF_TX_EN); |
/* LVDS Mode ?? */ |
RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_CONTROL, |
0, RV62_LVTMA_MODE); |
/* enable links */ |
if (Private->RunDualLink) { |
if (Private->FMTDither.LVDS24Bit) |
RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_ENABLE, 0x3ff, 0x3ff); |
else |
RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_ENABLE, 0x1ef, 0x3ff); |
} else { |
if (Private->FMTDither.LVDS24Bit) |
RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_ENABLE, 0x1f, 0x3ff); |
else |
RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_ENABLE, 0x0f, 0x3ff); |
} |
RHDRegMask(Output, RV620_LVTMA_PWRSEQ_CNTL, 0, |
RV62_LVTMA_DIGON_OVRD | RV62_LVTMA_BLON_OVRD); |
RHDRegMask(Output, RV620_LVTMA_PWRSEQ_REF_DIV, 3999, 0xffff); /* 4000 - 1 */ |
tmp = Private->PowerSequenceDe2Bl * 10 / 4; |
tmp1 = Private->PowerSequenceDig2De * 10 / 4; |
/* power sequencing delay for on / off between DIGON and SYNCEN, and SYNCEN and BLON */ |
RHDRegWrite(Output, RV620_LVTMA_PWRSEQ_DELAY1, (tmp1 << 24) | tmp1 | (tmp << 8) | (tmp << 16)); |
RHDRegWrite(Output, RV620_LVTMA_PWRSEQ_DELAY2, Private->OffDelay / 4); |
RHDRegMask(Output, RV620_LVTMA_PWRSEQ_CNTL, 0, RV62_LVTMA_PWRSEQ_DISABLE_SYNCEN_CONTROL_OF_TX_EN); |
for (i = 0; i < 500; i++) { |
CARD32 tmp; |
|
usleep(1000); |
tmp = RHDRegRead(Output, RV620_LVTMA_PWRSEQ_STATE); |
tmp >>= RV62_LVTMA_PWRSEQ_STATE_SHIFT; |
tmp &= 0xff; |
if (tmp <= RV62_POWERUP_DONE) |
break; |
if (tmp >= RV62_POWERDOWN_DONE) |
break; |
} |
/* LCD on */ |
RHDRegMask(Output, RV620_LVTMA_PWRSEQ_CNTL, RV62_LVTMA_PWRSEQ_TARGET_STATE, |
RV62_LVTMA_PWRSEQ_TARGET_STATE); |
return; |
|
case RHD_POWER_RESET: |
/* Disable LCD and BL */ |
RHDRegMask(Output, RV620_LVTMA_PWRSEQ_CNTL, 0, |
RV62_LVTMA_PWRSEQ_TARGET_STATE |
| RV62_LVTMA_DIGON_OVRD |
| RV62_LVTMA_BLON_OVRD); |
for (i = 0; i < 500; i++) { |
CARD32 tmp; |
|
usleep(1000); |
tmp = RHDRegRead(Output, RV620_LVTMA_PWRSEQ_STATE); |
tmp >>= RV62_LVTMA_PWRSEQ_STATE_SHIFT; |
tmp &= 0xff; |
if (tmp >= RV62_POWERDOWN_DONE) |
break; |
} |
return; |
case RHD_POWER_SHUTDOWN: |
LVTMA_LVDSTransmitterPower(Output, RHD_POWER_RESET); |
/* op-amp down, bias current for output driver down, shunt resistor down */ |
RHDRegWrite(Output, RV620_LVTMA_TRANSMITTER_ADJUST, 0x00e00000); |
/* set macro control */ |
RHDRegWrite(Output, RV620_LVTMA_MACRO_CONTROL, 0x07430408); |
default: |
return; |
} |
} |
|
/* |
* |
*/ |
static void |
LVTMA_LVDSTransmitterSave(struct rhdOutput *Output) |
{ |
struct DIGPrivate *digPrivate = (struct DIGPrivate *)Output->Private; |
struct LVTMATransmitterPrivate *Private = (struct LVTMATransmitterPrivate*)digPrivate->Transmitter.Private; |
|
RHDFUNC(Output); |
|
LVTMATransmitterSave(Output); |
|
Private->StoredPwrSeqCntl = RHDRegRead(Output, RV620_LVTMA_PWRSEQ_CNTL); |
Private->StoredPwrSeqRevDiv = RHDRegRead(Output, RV620_LVTMA_PWRSEQ_REF_DIV); |
Private->StoredPwrSeqDelay1 = RHDRegRead(Output, RV620_LVTMA_PWRSEQ_DELAY1); |
Private->StoredPwrSeqDelay2 = RHDRegRead(Output, RV620_LVTMA_PWRSEQ_DELAY2); |
|
Private->Stored = TRUE; |
} |
|
/* |
* |
*/ |
static void |
LVTMA_LVDSTransmitterRestore(struct rhdOutput *Output) |
{ |
struct DIGPrivate *digPrivate = (struct DIGPrivate *)Output->Private; |
struct LVTMATransmitterPrivate *Private = (struct LVTMATransmitterPrivate*)digPrivate->Transmitter.Private; |
|
RHDFUNC(Output); |
|
if (!Private->Stored) { |
xf86DrvMsg(Output->scrnIndex, X_ERROR, |
"%s: No registers stored.\n", __func__); |
return; |
} |
|
LVTMATransmitterRestore(Output); |
|
RHDRegWrite(Output, RV620_LVTMA_PWRSEQ_REF_DIV, Private->StoredPwrSeqRevDiv); |
RHDRegWrite(Output, RV620_LVTMA_PWRSEQ_DELAY1, Private->StoredPwrSeqDelay1); |
RHDRegWrite(Output, RV620_LVTMA_PWRSEQ_DELAY2, Private->StoredPwrSeqDelay2); |
RHDRegWrite(Output, RV620_LVTMA_PWRSEQ_CNTL, Private->StoredPwrSeqCntl); |
} |
|
/* |
* |
*/ |
static void |
LVTMATransmitterDestroy(struct rhdOutput *Output) |
{ |
struct DIGPrivate *digPrivate = (struct DIGPrivate *)Output->Private; |
|
RHDFUNC(Output); |
|
if (!digPrivate) |
return; |
|
xfree(digPrivate->Transmitter.Private); |
} |
|
#if defined(ATOM_BIOS) && defined(ATOM_BIOS_PARSER) |
|
struct ATOMTransmitterPrivate |
{ |
struct atomTransmitterConfig atomTransmitterConfig; |
enum atomTransmitter atomTransmitterID; |
}; |
|
/* |
* |
*/ |
static ModeStatus |
ATOMTransmitterModeValid(struct rhdOutput *Output, DisplayModePtr Mode) |
{ |
|
RHDFUNC(Output); |
|
if (Output->Connector->Type == RHD_CONNECTOR_DVI_SINGLE |
&& Mode->SynthClock > 165000) |
return MODE_CLOCK_HIGH; |
|
return MODE_OK; |
} |
|
/* |
* |
*/ |
void |
rhdPrintDigDebug(RHDPtr rhdPtr, const char *name) |
{ |
xf86DrvMsgVerb(rhdPtr->scrnIndex, X_INFO, 7, "%s: DIGn_CNTL: n=1: 0x%x n=2: 0x%x\n", |
name, RHDRegRead(rhdPtr, RV620_DIG1_CNTL), |
RHDRegRead(rhdPtr, DIG2_OFFSET + RV620_DIG1_CNTL)); |
} |
|
/* |
* |
*/ |
static void |
ATOMTransmitterSet(struct rhdOutput *Output, struct rhdCrtc *Crtc, DisplayModePtr Mode) |
{ |
RHDPtr rhdPtr = RHDPTRI(Output); |
struct DIGPrivate *Private = (struct DIGPrivate *)Output->Private; |
struct ATOMTransmitterPrivate *transPrivate |
= (struct ATOMTransmitterPrivate*) Private->Transmitter.Private; |
struct atomTransmitterConfig *atc = &transPrivate->atomTransmitterConfig; |
|
RHDFUNC(Output); |
|
atc->Coherent = Private->Coherent; |
atc->PixelClock = Mode->SynthClock; |
|
rhdPrintDigDebug(rhdPtr,__func__); |
|
if (Private->RunDualLink) { |
atc->Mode = atomDualLink; |
|
if (atc->Link == atomTransLinkA) |
atc->Link = atomTransLinkAB; |
else if (atc->Link == atomTransLinkB) |
atc->Link = atomTransLinkBA; |
|
} else { |
atc->Mode = atomSingleLink; |
|
if (atc->Link == atomTransLinkAB) |
atc->Link = atomTransLinkA; |
else if (atc->Link == atomTransLinkBA) |
atc->Link = atomTransLinkB; |
|
} |
|
atc->PixelClock = Mode->SynthClock; |
|
rhdAtomDigTransmitterControl(rhdPtr->atomBIOS, transPrivate->atomTransmitterID, |
atomTransSetup, atc); |
rhdPrintDigDebug(rhdPtr,__func__); |
} |
|
/* |
* |
*/ |
static CARD32 |
digProbeEncoder(struct rhdOutput *Output) |
{ |
if (Output->Id == RHD_OUTPUT_KLDSKP_LVTMA) { |
return ENCODER_DIG2; |
} else { |
Bool swap = (RHDRegRead(Output, RV620_DCIO_LINK_STEER_CNTL) |
& RV62_LINK_STEER_SWAP) == RV62_LINK_STEER_SWAP; |
|
switch (Output->Id) { |
case RHD_OUTPUT_UNIPHYA: |
if (swap) { |
RHDDebug(Output->scrnIndex, "%s: detected ENCODER_DIG2 for UNIPHYA\n",__func__); |
return ENCODER_DIG2; |
} else { |
RHDDebug(Output->scrnIndex, "%s: detected ENCODER_DIG1 for UNIPHYA\n",__func__); |
return ENCODER_DIG1; |
} |
break; |
case RHD_OUTPUT_UNIPHYB: |
if (swap) { |
RHDDebug(Output->scrnIndex, "%s: detected ENCODER_DIG1 for UNIPHYB\n",__func__); |
return ENCODER_DIG1; |
} else { |
RHDDebug(Output->scrnIndex, "%s: detected ENCODER_DIG2 for UNIPHYB\n",__func__); |
return ENCODER_DIG2; |
} |
break; |
default: |
return ENCODER_NONE; /* should not get here */ |
} |
} |
return ENCODER_NONE; |
} |
|
/* |
* |
*/ |
static void |
ATOMTransmitterPower(struct rhdOutput *Output, int Power) |
{ |
RHDPtr rhdPtr = RHDPTRI(Output); |
struct DIGPrivate *Private = (struct DIGPrivate *)Output->Private; |
struct ATOMTransmitterPrivate *transPrivate |
= (struct ATOMTransmitterPrivate*) Private->Transmitter.Private; |
struct atomTransmitterConfig *atc = &transPrivate->atomTransmitterConfig; |
|
RHDFUNC(Output); |
|
rhdPrintDigDebug(rhdPtr,__func__); |
|
if (Private->RunDualLink) |
atc->LinkCnt = atomDualLink; |
else |
atc->LinkCnt = atomSingleLink; |
|
atc->Coherent = Private->Coherent; |
|
if (atc->Encoder == atomEncoderNone) { |
switch (digProbeEncoder(Output)) { |
case ENCODER_DIG1: |
if (rhdPtr->DigEncoderOutput[0]) { |
RHDDebug(Output->scrnIndex,"%s: DIG1 for %s already taken\n",__func__,Output->Name); |
return; |
} |
atc->Encoder = atomEncoderDIG1; |
break; |
case ENCODER_DIG2: |
if (rhdPtr->DigEncoderOutput[1]) { |
RHDDebug(Output->scrnIndex,"%s: DIG2 for %s already taken\n",__func__,Output->Name); |
return; |
} |
atc->Encoder = atomEncoderDIG2; |
break; |
default: |
return; |
} |
} |
|
switch (Power) { |
case RHD_POWER_ON: |
rhdAtomDigTransmitterControl(rhdPtr->atomBIOS, transPrivate->atomTransmitterID, |
atomTransEnable, atc); |
rhdAtomDigTransmitterControl(rhdPtr->atomBIOS, transPrivate->atomTransmitterID, |
atomTransEnableOutput, atc); |
break; |
case RHD_POWER_RESET: |
rhdAtomDigTransmitterControl(rhdPtr->atomBIOS, transPrivate->atomTransmitterID, |
atomTransDisableOutput, atc); |
break; |
case RHD_POWER_SHUTDOWN: |
if (!Output->Connector || Output->Connector->Type == RHD_CONNECTOR_DVI) |
atc->Mode = atomDVI; |
|
rhdAtomDigTransmitterControl(rhdPtr->atomBIOS, transPrivate->atomTransmitterID, |
atomTransDisableOutput, atc); |
rhdAtomDigTransmitterControl(rhdPtr->atomBIOS, transPrivate->atomTransmitterID, |
atomTransDisable, atc); |
break; |
} |
rhdPrintDigDebug(rhdPtr,__func__); |
} |
|
/* |
* |
*/ |
static void |
ATOMTransmitterSave(struct rhdOutput *Output) |
{ |
RHDFUNC(Output); |
} |
|
/* |
* |
*/ |
static void |
ATOMTransmitterRestore(struct rhdOutput *Output) |
{ |
RHDFUNC(Output); |
} |
|
/* |
* |
*/ |
static void |
ATOMTransmitterDestroy(struct rhdOutput *Output) |
{ |
struct DIGPrivate *digPrivate = (struct DIGPrivate *)Output->Private; |
|
RHDFUNC(Output); |
|
if (!digPrivate) |
return; |
|
xfree(digPrivate->Transmitter.Private); |
} |
|
#endif /* ATOM_BIOS && ATOM_BIOS_PASER */ |
|
/* |
* Encoder |
*/ |
|
struct DIGEncoder |
{ |
Bool Stored; |
|
CARD32 StoredOff; |
|
CARD32 StoredRegExt1DiffPostDivCntl; |
CARD32 StoredRegExt2DiffPostDivCntl; |
CARD32 StoredDIGClockPattern; |
CARD32 StoredLVDSDataCntl; |
CARD32 StoredTMDSPixelEncoding; |
CARD32 StoredTMDSCntl; |
CARD32 StoredDIGCntl; |
CARD32 StoredDIGMisc1; |
CARD32 StoredDIGMisc2; |
CARD32 StoredDIGMisc3; |
CARD32 StoredDCCGPclkDigCntl; |
CARD32 StoredDCCGSymclkCntl; |
CARD32 StoredDCIOLinkSteerCntl; |
CARD32 StoredBlModCntl; |
}; |
|
/* |
* |
*/ |
static ModeStatus |
EncoderModeValid(struct rhdOutput *Output, DisplayModePtr Mode) |
{ |
RHDFUNC(Output); |
|
return MODE_OK; |
} |
|
/* |
* |
*/ |
static void |
LVDSEncoder(struct rhdOutput *Output) |
{ |
struct DIGPrivate *Private = (struct DIGPrivate *)Output->Private; |
CARD32 off; |
|
RHDFUNC(Output); |
|
|
off = (Private->EncoderID == ENCODER_DIG2) ? DIG2_OFFSET : DIG1_OFFSET; |
/* Clock pattern ? */ |
RHDRegMask(Output, off + RV620_DIG1_CLOCK_PATTERN, 0x0063, 0xFFFF); |
/* set panel type: 18/24 bit mode */ |
RHDRegMask(Output, off + RV620_LVDS1_DATA_CNTL, |
(Private->FMTDither.LVDS24Bit ? RV62_LVDS_24BIT_ENABLE : 0) |
| (Private->FPDI ? RV62_LVDS_24BIT_FORMAT : 0), |
RV62_LVDS_24BIT_ENABLE | RV62_LVDS_24BIT_FORMAT); |
|
Output->Crtc->FMTModeSet(Output->Crtc, &Private->FMTDither); |
} |
|
/* |
* |
*/ |
static void |
TMDSEncoder(struct rhdOutput *Output) |
{ |
struct DIGPrivate *Private = (struct DIGPrivate *)Output->Private; |
CARD32 off; |
|
RHDFUNC(Output); |
|
off = (Private->EncoderID == ENCODER_DIG2) ? DIG2_OFFSET : DIG1_OFFSET; |
/* clock pattern ? */ |
RHDRegMask(Output, off + RV620_DIG1_CLOCK_PATTERN, 0x001F, 0xFFFF); |
/* color format RGB - normal color format 24bpp, Twin-Single 30bpp or Dual 48bpp*/ |
RHDRegMask(Output, off + RV620_TMDS1_CNTL, 0x0, |
RV62_TMDS_PIXEL_ENCODING | RV62_TMDS_COLOR_FORMAT); |
/* no dithering */ |
Output->Crtc->FMTModeSet(Output->Crtc, NULL); |
} |
|
/* |
* |
*/ |
static void |
EncoderSet(struct rhdOutput *Output, struct rhdCrtc *Crtc, DisplayModePtr Mode) |
{ |
struct DIGPrivate *Private = (struct DIGPrivate *)Output->Private; |
RHDPtr rhdPtr = RHDPTRI(Output); |
CARD32 off; |
|
RHDFUNC(Output); |
|
off = (Private->EncoderID == ENCODER_DIG2) ? DIG2_OFFSET : DIG1_OFFSET; |
|
rhdPrintDigDebug(rhdPtr,__func__); |
|
RHDRegMask(Output, off + RV620_DIG1_CNTL, Output->Crtc->Id, |
RV62_DIG_SOURCE_SELECT); |
|
if (Output->Id == RHD_OUTPUT_UNIPHYA) { |
/* select LinkA ?? */ |
RHDRegMask(Output, RV620_DCIO_LINK_STEER_CNTL, |
((Private->EncoderID == ENCODER_DIG2) |
? RV62_LINK_STEER_SWAP |
: 0), RV62_LINK_STEER_SWAP); /* swap if DIG2 */ |
if (!Private->RunDualLink) { |
RHDRegMask(Output, off + RV620_DIG1_CNTL, |
0, |
RV62_DIG_SWAP |RV62_DIG_DUAL_LINK_ENABLE); |
} else { |
RHDRegMask(Output, off + RV620_DIG1_CNTL, |
RV62_DIG_DUAL_LINK_ENABLE, |
RV62_DIG_SWAP | RV62_DIG_DUAL_LINK_ENABLE); |
} |
} else if (Output->Id == RHD_OUTPUT_UNIPHYB) { |
/* select LinkB ?? */ |
RHDRegMask(Output, RV620_DCIO_LINK_STEER_CNTL, |
((Private->EncoderID == ENCODER_DIG2) |
? 0 |
: RV62_LINK_STEER_SWAP), RV62_LINK_STEER_SWAP); |
if (!Private->RunDualLink) |
RHDRegMask(Output, off + RV620_DIG1_CNTL, |
0, |
RV62_DIG_SWAP | RV62_DIG_DUAL_LINK_ENABLE); |
else |
RHDRegMask(Output, off + RV620_DIG1_CNTL, |
RV62_DIG_SWAP | RV62_DIG_DUAL_LINK_ENABLE, |
RV62_DIG_SWAP | RV62_DIG_DUAL_LINK_ENABLE); |
} else { /* LVTMA */ |
RHDRegMask(Output, RV620_EXT2_DIFF_POST_DIV_CNTL, 0, RV62_EXT2_DIFF_DRIVER_ENABLE); |
} |
|
if (Private->EncoderMode == LVDS) |
LVDSEncoder(Output); |
else if (Private->EncoderMode == DISPLAYPORT) |
dbgprintf("No displayport support yet!",__FILE__, __LINE__, __func__); /* bugger ! */ |
else |
TMDSEncoder(Output); |
|
/* Start DIG, set links, disable stereo sync, select FMT source */ |
RHDRegMask(Output, off + RV620_DIG1_CNTL, |
(Private->EncoderMode & 0x7) << 8 |
| RV62_DIG_START |
| (Private->RunDualLink ? RV62_DIG_DUAL_LINK_ENABLE : 0) |
| Output->Crtc->Id, |
RV62_DIG_MODE |
| RV62_DIG_START |
| RV62_DIG_DUAL_LINK_ENABLE |
| RV62_DIG_STEREOSYNC_SELECT |
| RV62_DIG_SOURCE_SELECT); |
rhdPrintDigDebug(rhdPtr,__func__); |
} |
|
/* |
* |
*/ |
static void |
EncoderPower(struct rhdOutput *Output, int Power) |
{ |
struct DIGPrivate *Private = (struct DIGPrivate *)Output->Private; |
CARD32 off; |
enum encoderID EncoderID = Private->EncoderID; |
RHDPtr rhdPtr = Output->rhdPtr; |
|
RHDFUNC(Output); |
|
if (EncoderID == ENCODER_NONE) { |
EncoderID = digProbeEncoder(Output); |
switch (EncoderID) { |
case ENCODER_DIG1: |
if (rhdPtr->DigEncoderOutput[0]) { |
RHDDebug(Output->scrnIndex,"%s: DIG1 for %s already taken\n",__func__,Output->Name); |
return; |
} |
break; |
case ENCODER_DIG2: |
if (rhdPtr->DigEncoderOutput[1]) { |
RHDDebug(Output->scrnIndex,"%s: DIG2 for %s already taken\n",__func__,Output->Name); |
return; |
} |
break; |
default: |
return; |
} |
} |
|
off = (EncoderID == ENCODER_DIG2) ? DIG2_OFFSET : DIG1_OFFSET; |
|
/* clock src is pixel PLL */ |
RHDRegMask(Output, RV620_DCCG_SYMCLK_CNTL, 0x0, |
0x3 << ((EncoderID == ENCODER_DIG2) |
? RV62_SYMCLKB_SRC_SHIFT |
: RV62_SYMCLKA_SRC_SHIFT)); |
|
rhdPrintDigDebug(rhdPtr,__func__); |
switch (Power) { |
case RHD_POWER_ON: |
RHDDebug(Output->scrnIndex,"%s(RHD_POWER_ON, %i)\n",__func__, |
EncoderID); |
/* enable DIG */ |
RHDRegMask(Output, off + RV620_DIG1_CNTL, 0x10, 0x10); |
RHDRegMask(Output, (EncoderID == ENCODER_DIG2) |
? RV620_DCCG_PCLK_DIGB_CNTL |
: RV620_DCCG_PCLK_DIGA_CNTL, |
RV62_PCLK_DIGA_ON, RV62_PCLK_DIGA_ON); /* @@@ */ |
rhdPrintDigDebug(rhdPtr,__func__); |
return; |
case RHD_POWER_RESET: |
case RHD_POWER_SHUTDOWN: |
default: |
RHDDebug(Output->scrnIndex,"%s(RHD_POWER_SHUTDOWN, %i)\n",__func__, |
EncoderID); |
/* disable differential clock driver */ |
if (EncoderID == ENCODER_DIG1) |
RHDRegMask(Output, RV620_EXT1_DIFF_POST_DIV_CNTL, |
0, |
RV62_EXT1_DIFF_DRIVER_ENABLE); |
else |
RHDRegMask(Output, RV620_EXT2_DIFF_POST_DIV_CNTL, |
0, |
RV62_EXT2_DIFF_DRIVER_ENABLE); |
/* disable DIG */ |
RHDRegMask(Output, off + RV620_DIG1_CNTL, 0x0, 0x10); |
RHDRegMask(Output, (EncoderID == ENCODER_DIG2) |
? RV620_DCCG_PCLK_DIGB_CNTL |
: RV620_DCCG_PCLK_DIGA_CNTL, |
0, RV62_PCLK_DIGA_ON); /* @@@ */ |
rhdPrintDigDebug(rhdPtr,__func__); |
return; |
} |
} |
|
/* |
* |
*/ |
static void |
EncoderSave(struct rhdOutput *Output) |
{ |
struct DIGPrivate *digPrivate = (struct DIGPrivate *)Output->Private; |
struct DIGEncoder *Private = (struct DIGEncoder *)(digPrivate->Encoder.Private); |
CARD32 off; |
enum encoderID EncoderID; |
|
RHDFUNC(Output); |
|
EncoderID = digProbeEncoder(Output); |
off = (EncoderID == ENCODER_DIG2) ? DIG2_OFFSET : DIG1_OFFSET; |
Private->StoredOff = off; |
|
Private->StoredRegExt1DiffPostDivCntl = RHDRegRead(Output, off + RV620_EXT1_DIFF_POST_DIV_CNTL); |
Private->StoredRegExt2DiffPostDivCntl = RHDRegRead(Output, off + RV620_EXT2_DIFF_POST_DIV_CNTL); |
Private->StoredDIGClockPattern = RHDRegRead(Output, off + RV620_DIG1_CLOCK_PATTERN); |
Private->StoredLVDSDataCntl = RHDRegRead(Output, off + RV620_LVDS1_DATA_CNTL); |
Private->StoredDIGCntl = RHDRegRead(Output, off + RV620_DIG1_CNTL); |
Private->StoredTMDSCntl = RHDRegRead(Output, off + RV620_TMDS1_CNTL); |
Private->StoredDCIOLinkSteerCntl = RHDRegRead(Output, RV620_DCIO_LINK_STEER_CNTL); |
Private->StoredDCCGPclkDigCntl = RHDRegRead(Output, |
(off == DIG2_OFFSET) |
? RV620_DCCG_PCLK_DIGB_CNTL |
: RV620_DCCG_PCLK_DIGA_CNTL); |
Private->StoredDCCGSymclkCntl = RHDRegRead(Output, RV620_DCCG_SYMCLK_CNTL); |
Private->StoredBlModCntl = RHDRegRead(Output, RV620_LVTMA_BL_MOD_CNTL); |
|
Private->Stored = TRUE; |
} |
|
/* |
* |
*/ |
static void |
EncoderRestore(struct rhdOutput *Output) |
{ |
struct DIGPrivate *digPrivate = (struct DIGPrivate *)Output->Private; |
struct DIGEncoder *Private = (struct DIGEncoder *)(digPrivate->Encoder.Private); |
CARD32 off; |
|
RHDFUNC(Output); |
|
if (!Private->Stored) { |
xf86DrvMsg(Output->scrnIndex, X_ERROR, |
"%s: No registers stored.\n", __func__); |
return; |
} |
off = Private->StoredOff; |
|
RHDRegWrite(Output, off + RV620_EXT1_DIFF_POST_DIV_CNTL, Private->StoredRegExt1DiffPostDivCntl); |
RHDRegWrite(Output, off + RV620_EXT2_DIFF_POST_DIV_CNTL, Private->StoredRegExt2DiffPostDivCntl); |
/* reprogram all values but don't start the encoder, yet */ |
RHDRegWrite(Output, off + RV620_DIG1_CNTL, Private->StoredDIGCntl & ~(CARD32)RV62_DIG_START); |
RHDRegWrite(Output, RV620_DCIO_LINK_STEER_CNTL, Private->StoredDCIOLinkSteerCntl); |
RHDRegWrite(Output, off + RV620_DIG1_CLOCK_PATTERN, Private->StoredDIGClockPattern); |
RHDRegWrite(Output, off + RV620_LVDS1_DATA_CNTL, Private->StoredLVDSDataCntl); |
RHDRegWrite(Output, off + RV620_TMDS1_CNTL, Private->StoredTMDSCntl); |
RHDRegWrite(Output, (off == DIG2_OFFSET) |
? RV620_DCCG_PCLK_DIGB_CNTL |
: RV620_DCCG_PCLK_DIGA_CNTL, |
Private->StoredDCCGPclkDigCntl); |
/* now enable the encoder */ |
RHDRegWrite(Output, off + RV620_DIG1_CNTL, Private->StoredDIGCntl); |
RHDRegWrite(Output, RV620_DCCG_SYMCLK_CNTL, Private->StoredDCCGSymclkCntl); |
RHDRegWrite(Output, RV620_LVTMA_BL_MOD_CNTL, Private->StoredBlModCntl); |
} |
|
/* |
* |
*/ |
static void |
EncoderDestroy(struct rhdOutput *Output) |
{ |
struct DIGPrivate *digPrivate = (struct DIGPrivate *)Output->Private; |
|
RHDFUNC(Output); |
|
if (!digPrivate || !digPrivate->Encoder.Private) |
return; |
|
xfree(digPrivate->Encoder.Private); |
} |
|
/* |
* Housekeeping |
*/ |
void |
GetLVDSInfo(RHDPtr rhdPtr, struct DIGPrivate *Private) |
{ |
CARD32 off = (Private->EncoderID == ENCODER_DIG2) ? DIG2_OFFSET : DIG1_OFFSET; |
CARD32 tmp; |
|
RHDFUNC(rhdPtr); |
|
Private->FPDI = ((RHDRegRead(rhdPtr, off + RV620_LVDS1_DATA_CNTL) |
& RV62_LVDS_24BIT_FORMAT) != 0); |
Private->RunDualLink = ((RHDRegRead(rhdPtr, off + RV620_DIG1_CNTL) |
& RV62_DIG_DUAL_LINK_ENABLE) != 0); |
Private->FMTDither.LVDS24Bit = ((RHDRegRead(rhdPtr, off + RV620_LVDS1_DATA_CNTL) |
& RV62_LVDS_24BIT_ENABLE) != 0); |
|
tmp = RHDRegRead(rhdPtr, RV620_LVTMA_BL_MOD_CNTL); |
if (tmp & 0x1) |
Private->BlLevel = ( tmp >> LVTMA_BL_MOD_LEVEL_SHIFT ) & 0xff; |
else |
Private->BlLevel = -1; |
|
tmp = RHDRegRead(rhdPtr, RV620_LVTMA_PWRSEQ_REF_DIV); |
tmp &= 0xffff; |
tmp += 1; |
tmp /= 1000; |
Private->PowerSequenceDig2De = Private->PowerSequenceDe2Bl = |
RHDRegRead(rhdPtr, RV620_LVTMA_PWRSEQ_REF_DIV); |
Private->PowerSequenceDig2De = ((Private->PowerSequenceDig2De & 0xff) * tmp) / 10; |
Private->PowerSequenceDe2Bl = (((Private->PowerSequenceDe2Bl >> 8) & 0xff) * tmp) / 10; |
Private->OffDelay = RHDRegRead(rhdPtr, RV620_LVTMA_PWRSEQ_DELAY2); |
Private->OffDelay *= tmp; |
|
/* This is really ugly! */ |
{ |
CARD32 fmt_offset; |
|
tmp = RHDRegRead(rhdPtr, off + RV620_DIG1_CNTL); |
fmt_offset = (tmp & RV62_DIG_SOURCE_SELECT) ? FMT2_OFFSET :0; |
tmp = RHDRegRead(rhdPtr, fmt_offset + RV620_FMT1_BIT_DEPTH_CONTROL); |
Private->FMTDither.LVDSSpatialDither = ((tmp & 0x100) != 0); |
Private->FMTDither.LVDSGreyLevel = ((tmp & 0x10000) != 0); |
Private->FMTDither.LVDSTemporalDither |
= (Private->FMTDither.LVDSGreyLevel > 0) || ((tmp & 0x1000000) != 0); |
} |
|
#ifdef ATOM_BIOS |
{ |
AtomBiosArgRec data; |
|
if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, |
ATOM_LVDS_FPDI, &data) == ATOM_SUCCESS) |
Private->FPDI = data.val; |
|
if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, |
ATOM_LVDS_DUALLINK, &data) == ATOM_SUCCESS) |
Private->RunDualLink = data.val; |
|
if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, |
ATOM_LVDS_GREYLVL, &data) == ATOM_SUCCESS) |
Private->FMTDither.LVDSGreyLevel = data.val; |
|
if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, |
ATOM_LVDS_SEQ_DIG_ONTO_DE, &data) == ATOM_SUCCESS) |
Private->PowerSequenceDig2De = data.val; |
|
if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, |
ATOM_LVDS_SEQ_DE_TO_BL, &data) == ATOM_SUCCESS) |
Private->PowerSequenceDe2Bl = data.val; |
|
if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, |
ATOM_LVDS_OFF_DELAY, &data) == ATOM_SUCCESS) |
Private->OffDelay = data.val; |
|
if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, |
ATOM_LVDS_24BIT, &data) == ATOM_SUCCESS) |
Private->FMTDither.LVDS24Bit = data.val; |
|
if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, |
ATOM_LVDS_SPATIAL_DITHER, &data) == ATOM_SUCCESS) |
Private->FMTDither.LVDSSpatialDither = data.val; |
|
if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, |
ATOM_LVDS_TEMPORAL_DITHER, &data) == ATOM_SUCCESS) |
Private->FMTDither.LVDSTemporalDither = data.val; |
|
Private->PowerSequenceDe2Bl = data.val; |
|
} |
#endif |
|
} |
|
/* |
* Infrastructure |
*/ |
|
static ModeStatus |
DigModeValid(struct rhdOutput *Output, DisplayModePtr Mode) |
{ |
struct DIGPrivate *Private = (struct DIGPrivate *)Output->Private; |
struct transmitter *Transmitter = &Private->Transmitter; |
struct encoder *Encoder = &Private->Encoder; |
ModeStatus Status; |
|
RHDFUNC(Output); |
|
if ((Status = Transmitter->ModeValid(Output, Mode)) == MODE_OK) |
return ((Encoder->ModeValid(Output, Mode))); |
else |
return Status; |
} |
|
/* |
* |
*/ |
static void |
DigPower(struct rhdOutput *Output, int Power) |
{ |
struct DIGPrivate *Private = (struct DIGPrivate *)Output->Private; |
struct transmitter *Transmitter = &Private->Transmitter; |
struct encoder *Encoder = &Private->Encoder; |
Bool enableHDMI; |
|
RHDDebug(Output->scrnIndex, "%s(%s,%s)\n",__func__,Output->Name, |
rhdPowerString[Power]); |
|
if(Output->Connector != NULL) { |
/* check if attached monitor supports HDMI */ |
enableHDMI = RHDConnectorEnableHDMI(Output->Connector); |
if (enableHDMI && Private->EncoderMode == TMDS_DVI) |
Private->EncoderMode = TMDS_HDMI; |
else if (!enableHDMI && Private->EncoderMode == TMDS_HDMI) |
Private->EncoderMode = TMDS_DVI; |
} |
|
switch (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); |
Encoder->Power(Output, Power); |
return; |
case RHD_POWER_SHUTDOWN: |
default: |
Transmitter->Power(Output, Power); |
Encoder->Power(Output, Power); |
RHDHdmiEnable(Private->Hdmi, FALSE); |
return; |
} |
} |
|
/* |
* |
*/ |
static Bool |
DigPropertyControl(struct rhdOutput *Output, |
enum rhdPropertyAction Action, enum rhdOutputProperty Property, union rhdPropertyData *val) |
{ |
struct DIGPrivate *Private = (struct DIGPrivate *)Output->Private; |
|
RHDFUNC(Output); |
|
switch(Property) { |
case RHD_OUTPUT_COHERENT: |
case RHD_OUTPUT_BACKLIGHT: |
{ |
if (!Private->Transmitter.Property) |
return FALSE; |
Private->Transmitter.Property(Output, Action, Property, val); |
break; |
} |
default: |
return FALSE; |
} |
return TRUE; |
} |
|
|
/* |
* |
*/ |
static void |
DigMode(struct rhdOutput *Output, DisplayModePtr Mode) |
{ |
struct DIGPrivate *Private = (struct DIGPrivate *)Output->Private; |
struct transmitter *Transmitter = &Private->Transmitter; |
struct encoder *Encoder = &Private->Encoder; |
struct rhdCrtc *Crtc = Output->Crtc; |
|
RHDFUNC(Output); |
|
/* |
* For dual link capable DVI we need to decide from the pix clock if we are dual link. |
* Do it here as it is convenient. |
*/ |
if (Output->Connector->Type == RHD_CONNECTOR_DVI) |
Private->RunDualLink = (Mode->SynthClock > 165000) ? TRUE : FALSE; |
|
Encoder->Mode(Output, Crtc, Mode); |
Transmitter->Mode(Output, Crtc, Mode); |
RHDHdmiSetMode(Private->Hdmi, Mode); |
} |
|
/* |
* |
*/ |
static void |
DigSave(struct rhdOutput *Output) |
{ |
struct DIGPrivate *Private = (struct DIGPrivate *)Output->Private; |
struct transmitter *Transmitter = &Private->Transmitter; |
struct encoder *Encoder = &Private->Encoder; |
|
RHDFUNC(Output); |
|
Encoder->Save(Output); |
Transmitter->Save(Output); |
RHDHdmiSave(Private->Hdmi); |
} |
|
/* |
* |
*/ |
static void |
DigRestore(struct rhdOutput *Output) |
{ |
struct DIGPrivate *Private = (struct DIGPrivate *)Output->Private; |
struct transmitter *Transmitter = &Private->Transmitter; |
struct encoder *Encoder = &Private->Encoder; |
|
RHDFUNC(Output); |
|
Encoder->Restore(Output); |
Transmitter->Restore(Output); |
RHDHdmiRestore(Private->Hdmi); |
} |
|
/* |
* |
*/ |
static void |
DigDestroy(struct rhdOutput *Output) |
{ |
struct DIGPrivate *Private = (struct DIGPrivate *)Output->Private; |
struct transmitter *Transmitter = &Private->Transmitter; |
struct encoder *Encoder = &Private->Encoder; |
|
RHDFUNC(Output); |
|
Encoder->Destroy(Output); |
Transmitter->Destroy(Output); |
RHDHdmiDestroy(Private->Hdmi); |
#ifdef NOT_YET |
if (Transmitter->PropertyPrivate) |
RhdAtomDestroyBacklightControlProperty(Output, Transmitter->PropertyPrivate); |
#endif |
xfree(Private); |
Output->Private = NULL; |
} |
|
/* |
* |
*/ |
static Bool |
DigAllocFree(struct rhdOutput *Output, enum rhdOutputAllocation Alloc) |
{ |
struct DIGPrivate *Private = (struct DIGPrivate *)Output->Private; |
RHDPtr rhdPtr = RHDPTRI(Output); |
char *TransmitterName; |
|
RHDFUNC(rhdPtr); |
|
switch (Output->Id) { |
case RHD_OUTPUT_KLDSKP_LVTMA: |
TransmitterName = "KLDSKP_LVTMA"; |
break; |
case RHD_OUTPUT_UNIPHYA: |
TransmitterName = "UNIPHYA"; |
break; |
case RHD_OUTPUT_UNIPHYB: |
TransmitterName = "UNIPHYB"; |
break; |
default: |
return FALSE; |
} |
switch (Alloc) { |
case RHD_OUTPUT_ALLOC: |
|
if (Private->EncoderID != ENCODER_NONE) |
return TRUE; |
|
/* |
* LVTMA can only use DIG2. Thus exclude |
* DIG1 for LVTMA and prefer it for the |
* UNIPHYs. |
*/ |
if (Output->Id == RHD_OUTPUT_KLDSKP_LVTMA) { |
if (!rhdPtr->DigEncoderOutput[1]) { |
rhdPtr->DigEncoderOutput[1] = Output; |
Private->EncoderID = ENCODER_DIG2; |
xf86DrvMsg(Output->scrnIndex, X_INFO, |
"Mapping DIG2 encoder to %s\n",TransmitterName); |
return TRUE; |
} else |
return FALSE; |
} else { |
struct ATOMTransmitterPrivate *transPrivate = |
(struct ATOMTransmitterPrivate *)Private->Transmitter.Private; |
struct atomTransmitterConfig *atc = &transPrivate->atomTransmitterConfig; |
if (!rhdPtr->DigEncoderOutput[0]) { |
rhdPtr->DigEncoderOutput[0] = Output; |
Private->EncoderID = ENCODER_DIG1; |
atc->Encoder = atomEncoderDIG1; |
xf86DrvMsg(Output->scrnIndex, X_INFO, |
"Mapping DIG1 encoder to %s\n",TransmitterName); |
return TRUE; |
} else if (!rhdPtr->DigEncoderOutput[1]) { |
rhdPtr->DigEncoderOutput[1] = Output; |
Private->EncoderID = ENCODER_DIG2; |
atc->Encoder = atomEncoderDIG2; |
xf86DrvMsg(Output->scrnIndex, X_INFO, |
"Mapping DIG2 encoder to %s\n",TransmitterName); |
return TRUE; |
} else |
return FALSE; |
} |
|
case RHD_OUTPUT_FREE: |
Private->EncoderID = ENCODER_NONE; |
if (rhdPtr->DigEncoderOutput[0] == Output) { |
rhdPtr->DigEncoderOutput[0] = NULL; |
return TRUE; |
} else if (rhdPtr->DigEncoderOutput[1] == Output) { |
rhdPtr->DigEncoderOutput[1] = NULL; |
return TRUE; |
} else |
return FALSE; |
break; |
default: |
return FALSE; |
} |
} |
|
/* |
* |
*/ |
static Bool |
rhdDIGSetCoherent(RHDPtr rhdPtr,struct rhdOutput *Output) |
{ |
Bool coherent = FALSE; |
// int from = X_CONFIG; |
|
// switch (RhdParseBooleanOption(&rhdPtr->coherent, Output->Name)) { |
// case RHD_OPTION_NOT_SET: |
// case RHD_OPTION_DEFAULT: |
// from = X_DEFAULT; |
// coherent = FALSE; |
// break; |
// case RHD_OPTION_ON: |
// coherent = TRUE; |
// break; |
// case RHD_OPTION_OFF: |
// coherent = FALSE; |
// break; |
// } |
// xf86DrvMsg(rhdPtr->scrnIndex,from,"Setting %s to %scoherent\n", |
// Output->Name,coherent ? "" : "in"); |
|
return coherent; |
} |
|
/* |
* |
*/ |
#ifdef NOT_YET |
static Bool |
digTransmitterPropertyWrapper(struct rhdOutput *Output, |
enum rhdPropertyAction Action, |
enum rhdOutputProperty Property, |
union rhdPropertyData *val) |
{ |
struct DIGPrivate *Private = (struct DIGPrivate *)Output->Private; |
void *storePrivate = Output->Private; |
Bool (*func)(struct rhdOutput *,enum rhdPropertyAction, enum rhdOutputProperty, |
union rhdPropertyData *) = Private->Transmitter.WrappedPropertyCallback; |
Bool ret; |
|
Output->Private = Private->Transmitter.PropertyPrivate; |
ret = func(Output, Action, Property, val); |
Output->Private = storePrivate; |
|
return ret; |
} |
#endif |
|
/* |
* |
*/ |
struct rhdOutput * |
RHDDIGInit(RHDPtr rhdPtr, enum rhdOutputType outputType, CARD8 ConnectorType) |
{ |
struct rhdOutput *Output; |
struct DIGPrivate *Private; |
struct DIGEncoder *Encoder; |
|
RHDFUNC(rhdPtr); |
|
Output = xnfcalloc(sizeof(struct rhdOutput), 1); |
|
Output->scrnIndex = rhdPtr->scrnIndex; |
Output->Id = outputType; |
|
Output->Sense = NULL; |
Output->ModeValid = DigModeValid; |
Output->Mode = DigMode; |
Output->Power = DigPower; |
Output->Save = DigSave; |
Output->Restore = DigRestore; |
Output->Destroy = DigDestroy; |
Output->Property = DigPropertyControl; |
Output->AllocFree = DigAllocFree; |
|
Private = xnfcalloc(sizeof(struct DIGPrivate), 1); |
Output->Private = Private; |
|
Private->EncoderID = ENCODER_NONE; |
|
switch (outputType) { |
case RHD_OUTPUT_UNIPHYA: |
#if defined (ATOM_BIOS) && defined (ATOM_BIOS_PARSER) |
Output->Name = "UNIPHY_A"; |
Private->Transmitter.Private = |
(struct ATOMTransmitterPrivate *)xnfcalloc(sizeof (struct ATOMTransmitterPrivate), 1); |
|
Private->Transmitter.Sense = NULL; |
Private->Transmitter.ModeValid = ATOMTransmitterModeValid; |
Private->Transmitter.Mode = ATOMTransmitterSet; |
Private->Transmitter.Power = ATOMTransmitterPower; |
Private->Transmitter.Save = ATOMTransmitterSave; |
Private->Transmitter.Restore = ATOMTransmitterRestore; |
Private->Transmitter.Destroy = ATOMTransmitterDestroy; |
Private->Transmitter.Property = TMDSTransmitterPropertyControl; |
{ |
struct ATOMTransmitterPrivate *transPrivate = |
(struct ATOMTransmitterPrivate *)Private->Transmitter.Private; |
struct atomTransmitterConfig *atc = &transPrivate->atomTransmitterConfig; |
atc->Coherent = Private->Coherent = rhdDIGSetCoherent(rhdPtr, Output); |
atc->Link = atomTransLinkA; |
atc->Encoder = atomEncoderNone; |
if (RHDIsIGP(rhdPtr->ChipSet)) { |
AtomBiosArgRec data; |
data.val = 1; |
if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, ATOM_GET_PCIE_LANES, |
&data) == ATOM_SUCCESS) |
atc->Lanes = data.pcieLanes.Chassis; /* only do 'chassis' for now */ |
else { |
xfree(Private); |
xfree(Output); |
return NULL; |
} |
} |
if (RHDIsIGP(rhdPtr->ChipSet)) |
transPrivate->atomTransmitterID = atomTransmitterPCIEPHY; |
else |
transPrivate->atomTransmitterID = atomTransmitterUNIPHY; |
} |
break; |
#else |
xfree(Private); |
xfree(Output); |
return NULL; |
#endif /* ATOM_BIOS && ATOM_BIOS_PARSER */ |
|
case RHD_OUTPUT_UNIPHYB: |
#if defined (ATOM_BIOS) && defined (ATOM_BIOS_PARSER) |
Output->Name = "UNIPHY_B"; |
Private->Transmitter.Private = |
(struct atomTransmitterPrivate *)xnfcalloc(sizeof (struct ATOMTransmitterPrivate), 1); |
|
Private->Transmitter.Sense = NULL; |
Private->Transmitter.ModeValid = ATOMTransmitterModeValid; |
Private->Transmitter.Mode = ATOMTransmitterSet; |
Private->Transmitter.Power = ATOMTransmitterPower; |
Private->Transmitter.Save = ATOMTransmitterSave; |
Private->Transmitter.Restore = ATOMTransmitterRestore; |
Private->Transmitter.Destroy = ATOMTransmitterDestroy; |
Private->Transmitter.Property = TMDSTransmitterPropertyControl; |
{ |
struct ATOMTransmitterPrivate *transPrivate = |
(struct ATOMTransmitterPrivate *)Private->Transmitter.Private; |
struct atomTransmitterConfig *atc = &transPrivate->atomTransmitterConfig; |
atc->Coherent = Private->Coherent = rhdDIGSetCoherent(rhdPtr, Output); |
atc->Link = atomTransLinkB; |
atc->Encoder = atomEncoderNone; |
if (RHDIsIGP(rhdPtr->ChipSet)) { |
AtomBiosArgRec data; |
data.val = 2; |
if (RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS, ATOM_GET_PCIE_LANES, |
&data) == ATOM_SUCCESS) |
atc->Lanes = data.pcieLanes.Chassis; /* only do 'chassis' for now */ |
else { |
xfree(Private); |
xfree(Output); |
return NULL; |
} |
} |
if (RHDIsIGP(rhdPtr->ChipSet)) |
transPrivate->atomTransmitterID = atomTransmitterPCIEPHY; |
else |
transPrivate->atomTransmitterID = atomTransmitterUNIPHY; |
} |
break; |
#else |
xfree(Private); |
xfree(Output); |
return NULL; |
#endif /* ATOM_BIOS && ATOM_BIOS_PARSER */ |
|
case RHD_OUTPUT_KLDSKP_LVTMA: |
Output->Name = "UNIPHY_KLDSKP_LVTMA"; |
Private->Coherent = rhdDIGSetCoherent(rhdPtr, Output); |
Private->Transmitter.Private = |
(struct LVTMATransmitterPrivate *)xnfcalloc(sizeof (struct LVTMATransmitterPrivate), 1); |
|
Private->Transmitter.Sense = NULL; |
Private->Transmitter.ModeValid = LVTMATransmitterModeValid; |
if (ConnectorType != RHD_CONNECTOR_PANEL) { |
Private->Transmitter.Mode = LVTMA_TMDSTransmitterSet; |
Private->Transmitter.Power = LVTMA_TMDSTransmitterPower; |
Private->Transmitter.Save = LVTMA_TMDSTransmitterSave; |
Private->Transmitter.Restore = LVTMA_TMDSTransmitterRestore; |
} else { |
Private->Transmitter.Mode = LVTMA_LVDSTransmitterSet; |
Private->Transmitter.Power = LVTMA_LVDSTransmitterPower; |
Private->Transmitter.Save = LVTMA_LVDSTransmitterSave; |
Private->Transmitter.Restore = LVTMA_LVDSTransmitterRestore; |
} |
Private->Transmitter.Destroy = LVTMATransmitterDestroy; |
if (ConnectorType == RHD_CONNECTOR_PANEL) |
Private->Transmitter.Property = LVDSTransmitterPropertyControl; |
else |
Private->Transmitter.Property = TMDSTransmitterPropertyControl; |
break; |
|
default: |
xfree(Private); |
xfree(Output); |
return NULL; |
} |
|
Encoder = (struct DIGEncoder *)(xnfcalloc(sizeof (struct DIGEncoder),1)); |
Private->Encoder.Private = Encoder; |
Private->Encoder.ModeValid = EncoderModeValid; |
Private->Encoder.Mode = EncoderSet; |
Private->Encoder.Power = EncoderPower; |
Private->Encoder.Save = EncoderSave; |
Private->Encoder.Restore = EncoderRestore; |
Private->Encoder.Destroy = EncoderDestroy; |
|
switch (ConnectorType) { |
case RHD_CONNECTOR_PANEL: |
Private->EncoderMode = LVDS; |
GetLVDSInfo(rhdPtr, Private); |
#ifdef ATOM_BIOS |
#ifdef NOT_YET |
if (Private->BlLevel < 0) { |
Private->BlLevel = RhdAtomSetupBacklightControlProperty(Output, |
&Private->Transmitter.WrappedPropertyCallback, |
&Private->Transmitter.PropertyPrivate); |
if (Private->Transmitter.PropertyPrivate) |
Private->Transmitter.Property = digTransmitterPropertyWrapper; |
} |
#endif |
#endif |
Private->Hdmi = NULL; |
break; |
case RHD_CONNECTOR_DVI: |
Private->RunDualLink = FALSE; /* will be set later acc to pxclk */ |
Private->EncoderMode = TMDS_DVI; |
Private->Hdmi = RHDHdmiInit(rhdPtr, Output); |
break; |
case RHD_CONNECTOR_DVI_SINGLE: |
Private->RunDualLink = FALSE; |
Private->EncoderMode = TMDS_DVI; /* changed later to HDMI if aplicateable */ |
Private->Hdmi = RHDHdmiInit(rhdPtr, Output); |
break; |
} |
|
return Output; |
} |