0,0 → 1,459 |
/* |
* 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" |
|
#if HAVE_XF86_ANSIC_H |
# include "xf86_ansic.h" |
#else |
# include <unistd.h> |
#endif |
|
#include "rhd.h" |
#include "rhd_crtc.h" |
#include "rhd_pll.h" |
#include "rhd_lut.h" |
#include "rhd_regs.h" |
#include "rhd_modes.h" |
#include "rhd_mc.h" |
#if defined (ATOM_BIOS) && defined (ATOM_BIOS_PARSER) |
# include "rhd_atombios.h" |
|
# define D1_REG_OFFSET 0x0000 |
# define D2_REG_OFFSET 0x0800 |
|
struct rhdCrtcScalePrivate { |
void *RegList; |
CARD32 StoreViewportSize; |
CARD32 StoreViewportStart; |
}; |
|
/* |
* |
*/ |
static void |
rhdAtomCrtcRestore(struct rhdCrtc *Crtc, void *Store) |
{ |
RHDPtr rhdPtr = RHDPTRI(Crtc); |
union AtomBiosArg data; |
|
RHDFUNC(rhdPtr); |
|
data.Address = Store; |
RHDAtomBiosFunc(Crtc->scrnIndex, rhdPtr->atomBIOS, ATOM_RESTORE_REGISTERS, &data); |
} |
|
/* |
* |
*/ |
static void |
rhdAtomScaleSet(struct rhdCrtc *Crtc, enum rhdCrtcScaleType Type, |
DisplayModePtr Mode, DisplayModePtr ScaledToMode) |
{ |
RHDPtr rhdPtr = RHDPTRI(Crtc); |
struct rhdScalerOverscan Overscan; |
struct atomCrtcOverscan AtomOverscan; |
enum atomCrtc AtomCrtc = RHD_CRTC_1; |
enum atomScaler Scaler = 0; |
enum atomScaleMode ScaleMode = 0; |
union AtomBiosArg data; |
CARD32 RegOff = 0; |
|
RHDDebug(Crtc->scrnIndex, "FUNCTION: %s: %s viewport: %ix%i\n", __func__, Crtc->Name, |
Mode->CrtcHDisplay, Mode->CrtcVDisplay); |
|
/* D1Mode registers */ |
if (Crtc->Id == RHD_CRTC_1) |
RegOff = D1_REG_OFFSET; |
else |
RegOff = D2_REG_OFFSET; |
|
RHDRegWrite(Crtc, RegOff + D1MODE_VIEWPORT_SIZE, |
Mode->CrtcVDisplay | (Mode->CrtcHDisplay << 16)); |
RHDRegWrite(Crtc, RegOff + D1MODE_VIEWPORT_START, 0); |
|
Overscan = rhdCalculateOverscan(Mode, ScaledToMode, Type); |
Type = Overscan.Type; |
|
ASSERT(Crtc->ScalePriv); |
data.Address = &((Crtc->ScalePriv)->RegList); |
RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS, ATOM_SET_REGISTER_LIST_LOCATION, &data); |
|
AtomOverscan.ovscnLeft = Overscan.OverscanLeft; |
AtomOverscan.ovscnRight = Overscan.OverscanRight; |
AtomOverscan.ovscnTop = Overscan.OverscanTop; |
AtomOverscan.ovscnBottom = Overscan.OverscanBottom; |
|
switch (Crtc->Id) { |
case RHD_CRTC_1: |
Scaler = atomScaler1; |
AtomCrtc = atomCrtc1; |
break; |
case RHD_CRTC_2: |
Scaler = atomScaler2; |
AtomCrtc = atomCrtc2; |
break; |
} |
|
rhdAtomSetCRTCOverscan(rhdPtr->atomBIOS, AtomCrtc, &AtomOverscan); |
|
switch (Type) { |
case RHD_CRTC_SCALE_TYPE_NONE: |
ScaleMode = atomScaleDisable; |
break; |
case RHD_CRTC_SCALE_TYPE_CENTER: |
ScaleMode = atomScaleCenter; |
break; |
case RHD_CRTC_SCALE_TYPE_SCALE: |
case RHD_CRTC_SCALE_TYPE_SCALE_KEEP_ASPECT_RATIO: /* scaled to fullscreen */ |
ScaleMode = atomScaleExpand; |
break; |
} |
rhdAtomSetScaler(rhdPtr->atomBIOS, Scaler, ScaleMode); |
|
data.Address = NULL; |
RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS, ATOM_SET_REGISTER_LIST_LOCATION, &data); |
|
RHDMCTuneAccessForDisplay(rhdPtr, Crtc->Id, Mode, |
ScaledToMode ? ScaledToMode : Mode); |
} |
|
/* |
* |
*/ |
static void |
rhdAtomScaleSave(struct rhdCrtc *Crtc) |
{ |
struct rhdCrtcScalePrivate* ScalePriv; |
CARD32 RegOff = 0; |
|
RHDFUNC(Crtc); |
|
if (!Crtc->ScalePriv) { |
if(!(ScalePriv = (struct rhdCrtcScalePrivate*)xnfcalloc(1, sizeof(struct rhdCrtcScalePrivate)))) |
return; |
Crtc->ScalePriv = ScalePriv; |
} else |
ScalePriv = Crtc->ScalePriv; |
|
if (Crtc->Id == RHD_CRTC_1) |
RegOff = D1_REG_OFFSET; |
else |
RegOff = D2_REG_OFFSET; |
|
ScalePriv->StoreViewportSize = RHDRegRead(Crtc, RegOff + D1MODE_VIEWPORT_SIZE); |
ScalePriv->StoreViewportStart = RHDRegRead(Crtc, RegOff + D1MODE_VIEWPORT_START); |
ScalePriv->RegList = NULL; |
} |
|
/* |
* |
*/ |
static void |
rhdAtomCrtcScaleRestore(struct rhdCrtc *Crtc) |
{ |
struct rhdCrtcScalePrivate* ScalePriv; |
CARD32 RegOff = 0; |
|
RHDFUNC(Crtc); |
|
rhdAtomCrtcRestore(Crtc, &(((struct rhdCrtcScalePrivate*)Crtc->ScalePriv)->RegList)); |
|
if (Crtc->Id == RHD_CRTC_1) |
RegOff = D1_REG_OFFSET; |
else |
RegOff = D2_REG_OFFSET; |
|
ScalePriv = (struct rhdCrtcScalePrivate*)Crtc->ScalePriv; |
RHDRegWrite(Crtc, RegOff + D1MODE_VIEWPORT_SIZE, ScalePriv->StoreViewportSize); |
RHDRegWrite(Crtc, RegOff + D1MODE_VIEWPORT_START, ScalePriv->StoreViewportStart); |
} |
|
/* |
* |
*/ |
static void |
rhdAtomCrtcScaleDestroy(struct rhdCrtc *Crtc) |
{ |
RHDFUNC(Crtc); |
|
if (Crtc->ScalePriv) { |
xfree(Crtc->ScalePriv->RegList); |
xfree(Crtc->ScalePriv); |
Crtc->ScalePriv = NULL; |
} |
} |
|
/* |
* |
*/ |
struct rhdCrtcModePrivate { |
void *RegList; |
CARD32 StoreModeDataFormat; |
}; |
|
static void |
rhdAtomModeSet(struct rhdCrtc *Crtc, DisplayModePtr Mode) |
{ |
RHDPtr rhdPtr = RHDPTRI(Crtc); |
union AtomBiosArg data; |
CARD32 RegOff = 0; |
|
RHDFUNC(rhdPtr); |
|
ASSERT(Crtc->ModePriv); |
data.Address = &((Crtc->ModePriv)->RegList); |
RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS, ATOM_SET_REGISTER_LIST_LOCATION, &data); |
|
if (!rhdAtomSetCRTCTimings(rhdPtr->atomBIOS, |
Crtc->Id == RHD_CRTC_1 ? atomCrtc1 : atomCrtc2, |
Mode, 32)) |
xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "%s: failed to set mode.\n",__func__); |
|
/* set interlaced - AtomBIOS never sets the data format - never tested? */ |
if (Crtc->Id == RHD_CRTC_1) |
RegOff = D1_REG_OFFSET; |
else |
RegOff = D2_REG_OFFSET; |
|
if (Mode->Flags & V_INTERLACE) |
RHDRegWrite(Crtc, RegOff + D1MODE_DATA_FORMAT, 0x1); |
else |
RHDRegWrite(Crtc, RegOff + D1MODE_DATA_FORMAT, 0x0); |
|
data.Address = NULL; |
RHDAtomBiosFunc(Crtc->scrnIndex, rhdPtr->atomBIOS, ATOM_SET_REGISTER_LIST_LOCATION, &data); |
} |
|
/* |
* |
*/ |
static Bool |
rhdAtomCrtcPower(struct rhdCrtc *Crtc, int Power) |
{ |
RHDPtr rhdPtr = RHDPTRI(Crtc); |
enum atomCrtc AtomCrtc = atomCrtc1; |
union AtomBiosArg data; |
|
RHDFUNC(Crtc); |
|
switch (Crtc->Id) { |
case RHD_CRTC_1: |
AtomCrtc = atomCrtc1; |
break; |
case RHD_CRTC_2: |
AtomCrtc = atomCrtc2; |
break; |
} |
data.Address = &((Crtc->ModePriv)->RegList); |
RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS, ATOM_SET_REGISTER_LIST_LOCATION, &data); |
|
/* |
* We call rhdAtomEnableCrtcMemReq blindly as this table seemed to have existed in all |
* versions of AtomBIOS on the hardware we support |
*/ |
switch (Power) { |
case RHD_POWER_ON: |
rhdAtomEnableCrtcMemReq(rhdPtr->atomBIOS, AtomCrtc, atomCrtcEnable); |
rhdAtomEnableCrtc(rhdPtr->atomBIOS, AtomCrtc, atomCrtcEnable); |
break; |
case RHD_POWER_RESET: |
case RHD_POWER_SHUTDOWN: |
default: |
rhdAtomEnableCrtc(rhdPtr->atomBIOS, AtomCrtc, atomCrtcDisable); |
rhdAtomEnableCrtcMemReq(rhdPtr->atomBIOS, AtomCrtc, atomCrtcDisable); |
break; |
} |
data.Address = NULL; |
RHDAtomBiosFunc(Crtc->scrnIndex, rhdPtr->atomBIOS, ATOM_SET_REGISTER_LIST_LOCATION, &data); |
|
/* |
* we always claim we succeeded here, after all, we know, AtomBIOS knows |
* how to do things, right? |
* Err, no, when we use AtomBIOS we should not have a clue how to find out. |
*/ |
return TRUE; |
} |
|
/* |
* |
*/ |
static void |
rhdAtomCrtcBlank(struct rhdCrtc *Crtc, Bool Blank) |
{ |
RHDPtr rhdPtr = RHDPTRI(Crtc); |
enum atomCrtc AtomCrtc = atomCrtc1; |
struct atomCrtcBlank Config; |
union AtomBiosArg data; |
|
RHDFUNC(Crtc); |
|
switch (Crtc->Id) { |
case RHD_CRTC_1: |
AtomCrtc = atomCrtc1; |
break; |
case RHD_CRTC_2: |
AtomCrtc = atomCrtc2; |
break; |
} |
if (Blank) |
Config.Action = atomBlankOn; |
else |
Config.Action = atomBlankOff; |
|
Config.r = Config.g = Config.b = 0; |
|
data.Address = &((Crtc->ModePriv)->RegList); |
RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS, ATOM_SET_REGISTER_LIST_LOCATION, &data); |
|
rhdAtomBlankCRTC(rhdPtr->atomBIOS, AtomCrtc , &Config); |
|
data.Address = NULL; |
RHDAtomBiosFunc(Crtc->scrnIndex, rhdPtr->atomBIOS, ATOM_SET_REGISTER_LIST_LOCATION, &data); |
} |
|
/* |
* |
*/ |
static void |
rhdAtomModeSave(struct rhdCrtc *Crtc) |
{ |
struct rhdCrtcModePrivate* ModePriv; |
CARD32 RegOff = 0; |
|
if (!Crtc->ModePriv) { |
if(!(ModePriv = (struct rhdCrtcModePrivate*)xnfcalloc(1, sizeof(struct rhdCrtcModePrivate)))) |
return; |
Crtc->ModePriv = ModePriv; |
} else |
ModePriv = Crtc->ModePriv; |
|
if (Crtc->Id == RHD_CRTC_1) |
RegOff = D1_REG_OFFSET; |
else |
RegOff = D2_REG_OFFSET; |
|
ModePriv->StoreModeDataFormat = RHDRegRead(Crtc, RegOff + D1MODE_DATA_FORMAT); |
ModePriv->RegList = NULL; |
} |
|
/* |
* |
*/ |
static void |
rhdAtomModeRestore(struct rhdCrtc *Crtc) |
{ |
struct rhdCrtcModePrivate* ModePriv; |
CARD32 RegOff = 0; |
|
if (Crtc->Id == RHD_CRTC_1) |
RegOff = D1_REG_OFFSET; |
else |
RegOff = D2_REG_OFFSET; |
|
ModePriv = Crtc->ModePriv; |
|
rhdAtomCrtcRestore(Crtc, &ModePriv->RegList); |
|
RHDRegWrite(Crtc, RegOff + D1MODE_DATA_FORMAT, ModePriv->StoreModeDataFormat); |
} |
|
/* |
* |
*/ |
static void |
rhdAtomModeDestroy(struct rhdCrtc *Crtc) |
{ |
RHDFUNC(Crtc); |
|
if (Crtc->ModePriv) { |
xfree(Crtc->ModePriv->RegList); |
xfree(Crtc->ModePriv); |
Crtc->ModePriv = NULL; |
} |
} |
|
/* |
* |
*/ |
void |
RHDAtomCrtcsInit(RHDPtr rhdPtr) |
{ |
struct rhdCrtc *Crtc; |
int i; |
|
RHDFUNC(rhdPtr); |
|
if (rhdPtr->Crtc[0] == NULL || rhdPtr->Crtc[1] == NULL) { |
xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "%s: CRTCs not initialized\n",__func__); |
return; |
} |
|
for (i = 0; i < 2; i++) { |
|
Crtc = rhdPtr->Crtc[i]; |
|
if (i == 0) { |
Crtc->Name = "ATOM CRTC 1"; |
Crtc->Id = RHD_CRTC_1; |
} else { |
Crtc->Name = "ATOM CRTC 2"; |
Crtc->Id = RHD_CRTC_2; |
} |
|
/* EnableGraphSurfaces is only a BIOS internal table. So use the hardcoded path. |
Crtc->FBValid = atomFBValid; |
Crtc->FBSet = atomFBSet; |
Crtc->FBSave = atomSave; |
Crtc->FBRestore = atomRestore; |
*/ |
|
/* There is no separate function to set up the LUT thru AtomBIOS */ |
|
/* Crtc->ScaleValid: From rhd_crtc.c */ |
Crtc->ScaleSet = rhdAtomScaleSet; |
Crtc->ScaleSave = rhdAtomScaleSave; |
Crtc->ScaleRestore = rhdAtomCrtcScaleRestore; |
Crtc->ScaleDestroy = rhdAtomCrtcScaleDestroy; |
|
/* No such AtomBIOS table */ |
/* Crtc->FrameSet = atomViewPortStart; */ |
|
/* Crtc->ModeValid: From rhd_crtc.c */ |
Crtc->ModeSet = rhdAtomModeSet; |
Crtc->ModeSave = rhdAtomModeSave; |
Crtc->ModeRestore = rhdAtomModeRestore; |
Crtc->ModeDestroy = rhdAtomModeDestroy; |
|
Crtc->Power = rhdAtomCrtcPower; |
Crtc->Blank = rhdAtomCrtcBlank; |
} |
} |
|
#endif /* ATOM_BIOS && ATOM_BIOS_PARSER */ |