forked from KolibriOS/kolibrios
fb8dc89b4d
git-svn-id: svn://kolibrios.org@1029 a494cfbc-eb01-0410-851d-a64ba20cac60
1501 lines
40 KiB
C
1501 lines
40 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.
|
|
*/
|
|
|
|
#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_pll.h"
|
|
#include "rhd_lut.h"
|
|
#include "rhd_regs.h"
|
|
#include "rhd_modes.h"
|
|
#include "rhd_mc.h"
|
|
#ifdef ATOM_BIOS
|
|
# include "rhd_atombios.h"
|
|
#endif
|
|
|
|
#define D1_REG_OFFSET 0x0000
|
|
#define D2_REG_OFFSET 0x0800
|
|
#define FMT1_REG_OFFSET 0x0000
|
|
#define FMT2_REG_OFFSET 0x800
|
|
|
|
struct rhdCrtcFMTPrivate {
|
|
CARD32 StoreControl;
|
|
CARD32 StoreBitDepthControl;
|
|
CARD32 StoreClampCntl;
|
|
};
|
|
|
|
struct rhdCrtcFBPrivate {
|
|
CARD32 StoreGrphEnable;
|
|
CARD32 StoreGrphControl;
|
|
CARD32 StoreGrphXStart;
|
|
CARD32 StoreGrphYStart;
|
|
CARD32 StoreGrphXEnd;
|
|
CARD32 StoreGrphYEnd;
|
|
CARD32 StoreGrphSwap;
|
|
CARD32 StoreGrphPrimarySurfaceAddress;
|
|
CARD32 StoreGrphSurfaceOffsetX;
|
|
CARD32 StoreGrphSurfaceOffsetY;
|
|
CARD32 StoreGrphPitch;
|
|
CARD32 StoreModeDesktopHeight;
|
|
};
|
|
|
|
struct rhdCrtcLUTPrivate {
|
|
CARD32 StoreGrphLutSel;
|
|
};
|
|
|
|
struct rhdCrtcScalePrivate {
|
|
CARD32 StoreModeViewPortSize;
|
|
|
|
CARD32 StoreModeOverScanH;
|
|
CARD32 StoreModeOverScanV;
|
|
|
|
CARD32 StoreModeViewPortStart;
|
|
CARD32 StoreScaleEnable;
|
|
CARD32 StoreScaleTapControl;
|
|
CARD32 StoreModeCenter;
|
|
CARD32 StoreScaleHV;
|
|
CARD32 StoreScaleHFilter;
|
|
CARD32 StoreScaleVFilter;
|
|
CARD32 StoreScaleDither;
|
|
};
|
|
|
|
struct rhdCrtcModePrivate {
|
|
CARD32 StoreCrtcControl;
|
|
|
|
CARD32 StoreCrtcHTotal;
|
|
CARD32 StoreCrtcHBlankStartEnd;
|
|
CARD32 StoreCrtcHSyncA;
|
|
CARD32 StoreCrtcHSyncACntl;
|
|
CARD32 StoreCrtcHSyncB;
|
|
CARD32 StoreCrtcHSyncBCntl;
|
|
|
|
CARD32 StoreCrtcVTotal;
|
|
CARD32 StoreCrtcVBlankStartEnd;
|
|
CARD32 StoreCrtcVSyncA;
|
|
CARD32 StoreCrtcVSyncACntl;
|
|
CARD32 StoreCrtcVSyncB;
|
|
CARD32 StoreCrtcVSyncBCntl;
|
|
CARD32 StoreCrtcCountControl;
|
|
|
|
CARD32 StoreModeDataFormat;
|
|
CARD32 StoreCrtcInterlaceControl;
|
|
|
|
CARD32 StoreCrtcBlackColor;
|
|
CARD32 StoreCrtcBlankControl;
|
|
};
|
|
|
|
/*
|
|
* Checks whether Width, Height are within boundaries.
|
|
* If MODE_OK is returned and pPitch is not NULL, it is set.
|
|
*/
|
|
static ModeStatus
|
|
DxFBValid(struct rhdCrtc *Crtc, CARD16 Width, CARD16 Height, int bpp,
|
|
CARD32 Offset, CARD32 Size, CARD32 *pPitch)
|
|
{
|
|
RHDPtr rhdPtr = RHDPTRI(Crtc);
|
|
ScrnInfoPtr pScrn = rhdPtr->pScrn;
|
|
|
|
CARD16 Pitch;
|
|
unsigned int BytesPerPixel;
|
|
CARD8 PitchMask = 0xFF;
|
|
|
|
RHDDebug(Crtc->scrnIndex, "FUNCTION: %s: %s\n", __func__, Crtc->Name);
|
|
|
|
/* If we hit this, then the memory claimed so far is not properly aligned */
|
|
if (Offset & 0xFFF) {
|
|
xf86DrvMsg(Crtc->scrnIndex, X_ERROR, "%s: Offset (0x%08X) is invalid!\n",
|
|
__func__, (int) Offset);
|
|
return MODE_ERROR;
|
|
}
|
|
|
|
switch (pScrn->bitsPerPixel) {
|
|
case 8:
|
|
BytesPerPixel = 1;
|
|
break;
|
|
case 15:
|
|
case 16:
|
|
BytesPerPixel = 2;
|
|
PitchMask /= BytesPerPixel;
|
|
break;
|
|
case 24:
|
|
case 32:
|
|
BytesPerPixel = 4;
|
|
PitchMask /= BytesPerPixel;
|
|
break;
|
|
default:
|
|
xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "%s: %dbpp is not implemented!\n",
|
|
__func__, pScrn->bitsPerPixel);
|
|
return MODE_BAD;
|
|
}
|
|
|
|
if((Width==720)&&(Height==400)) //skip textmode
|
|
return MODE_BAD;
|
|
|
|
/* Be reasonable */
|
|
if (Width < 640)
|
|
return MODE_H_ILLEGAL;
|
|
if (Height < 480)
|
|
return MODE_V_ILLEGAL;
|
|
|
|
/* D1GRPH_X_START is 14bits while D1_MODE_VIEWPORT_X_START is only 13 bits.
|
|
* Since it is reasonable to assume that modes will be at least 1x1
|
|
* limit at 13bits + 1 */
|
|
if (Width > 0x2000)
|
|
return MODE_VIRTUAL_X;
|
|
|
|
/* D1GRPH_Y_START is 14bits while D1_MODE_VIEWPORT_Y_START is only 13 bits.
|
|
* Since it is reasonable to assume that modes will be at least 1x1
|
|
* limit at 13bits + 1 */
|
|
if (Height > 0x2000)
|
|
return MODE_VIRTUAL_Y;
|
|
|
|
Pitch = (Width + PitchMask) & ~PitchMask;
|
|
/* D1_PITCH limit: should never happen after clamping Width to 0x2000 */
|
|
if (Pitch >= 0x4000)
|
|
return MODE_VIRTUAL_X;
|
|
|
|
if ((Pitch * BytesPerPixel * Height) > Size)
|
|
return MODE_MEM_VIRT;
|
|
|
|
if (pPitch)
|
|
*pPitch = Pitch;
|
|
return MODE_OK;
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static void
|
|
DxFBSet(struct rhdCrtc *Crtc, CARD16 Pitch, CARD16 Width, CARD16 Height,
|
|
int bpp, CARD32 Offset)
|
|
{
|
|
RHDPtr rhdPtr = RHDPTRI(Crtc);
|
|
CARD16 RegOff;
|
|
|
|
RHDDebug(Crtc->scrnIndex, "FUNCTION: %s: %s (%i[%i]x%i@%ibpp) +0x%x )\n",
|
|
__func__, Crtc->Name, Width, Pitch, Height, bpp, Offset);
|
|
|
|
if (Crtc->Id == RHD_CRTC_1)
|
|
RegOff = D1_REG_OFFSET;
|
|
else
|
|
RegOff = D2_REG_OFFSET;
|
|
|
|
RHDRegMask(Crtc, RegOff + D1GRPH_ENABLE, 1, 0x00000001);
|
|
|
|
/* disable R/B swap, disable tiling, disable 16bit alpha, etc. */
|
|
RHDRegWrite(Crtc, RegOff + D1GRPH_CONTROL, 0);
|
|
|
|
switch (bpp) {
|
|
case 8:
|
|
RHDRegMask(Crtc, RegOff + D1GRPH_CONTROL, 0, 0x00000703);
|
|
break;
|
|
case 15:
|
|
RHDRegMask(Crtc, RegOff + D1GRPH_CONTROL, 0x000001, 0x00000703);
|
|
break;
|
|
case 16:
|
|
RHDRegMask(Crtc, RegOff + D1GRPH_CONTROL, 0x000101, 0x00000703);
|
|
break;
|
|
case 24:
|
|
case 32:
|
|
default:
|
|
RHDRegMask(Crtc, RegOff + D1GRPH_CONTROL, 0x000002, 0x00000703);
|
|
break;
|
|
/* TODO: 64bpp ;p */
|
|
}
|
|
|
|
/* Make sure that we are not swapping colours around */
|
|
if (rhdPtr->ChipSet > RHD_R600)
|
|
RHDRegWrite(Crtc, RegOff + D1GRPH_SWAP_CNTL, 0);
|
|
/* R5xx - RS690 case is GRPH_CONTROL bit 16 */
|
|
|
|
RHDRegWrite(Crtc, RegOff + D1GRPH_PRIMARY_SURFACE_ADDRESS,
|
|
rhdPtr->FbIntAddress + Offset);
|
|
RHDRegWrite(Crtc, RegOff + D1GRPH_PITCH, Pitch);
|
|
RHDRegWrite(Crtc, RegOff + D1GRPH_SURFACE_OFFSET_X, 0);
|
|
RHDRegWrite(Crtc, RegOff + D1GRPH_SURFACE_OFFSET_Y, 0);
|
|
RHDRegWrite(Crtc, RegOff + D1GRPH_X_START, 0);
|
|
RHDRegWrite(Crtc, RegOff + D1GRPH_Y_START, 0);
|
|
RHDRegWrite(Crtc, RegOff + D1GRPH_X_END, Width);
|
|
RHDRegWrite(Crtc, RegOff + D1GRPH_Y_END, Height);
|
|
|
|
/* D1Mode registers */
|
|
RHDRegWrite(Crtc, RegOff + D1MODE_DESKTOP_HEIGHT, Height);
|
|
|
|
Crtc->Pitch = Pitch;
|
|
Crtc->Width = Width;
|
|
Crtc->Height = Height;
|
|
Crtc->bpp = bpp;
|
|
Crtc->Offset = Offset;
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static void
|
|
DxFBSave(struct rhdCrtc *Crtc)
|
|
{
|
|
struct rhdCrtcFBPrivate *FBPriv;
|
|
CARD32 RegOff;
|
|
|
|
if (!Crtc->FBPriv)
|
|
FBPriv = xnfcalloc(1, sizeof(struct rhdCrtcFBPrivate));
|
|
else
|
|
FBPriv = Crtc->FBPriv;
|
|
|
|
if (Crtc->Id == RHD_CRTC_1)
|
|
RegOff = D1_REG_OFFSET;
|
|
else
|
|
RegOff = D2_REG_OFFSET;
|
|
|
|
FBPriv->StoreGrphEnable = RHDRegRead(Crtc, RegOff + D1GRPH_ENABLE);
|
|
FBPriv->StoreGrphControl = RHDRegRead(Crtc, RegOff + D1GRPH_CONTROL);
|
|
FBPriv->StoreGrphXStart = RHDRegRead(Crtc, RegOff + D1GRPH_X_START);
|
|
FBPriv->StoreGrphYStart = RHDRegRead(Crtc, RegOff + D1GRPH_Y_START);
|
|
FBPriv->StoreGrphXEnd = RHDRegRead(Crtc, RegOff + D1GRPH_X_END);
|
|
FBPriv->StoreGrphYEnd = RHDRegRead(Crtc, RegOff + D1GRPH_Y_END);
|
|
if (RHDPTRI(Crtc)->ChipSet >= RHD_R600)
|
|
FBPriv->StoreGrphSwap = RHDRegRead(Crtc, RegOff + D1GRPH_SWAP_CNTL);
|
|
FBPriv->StoreGrphPrimarySurfaceAddress =
|
|
RHDRegRead(Crtc, RegOff + D1GRPH_PRIMARY_SURFACE_ADDRESS);
|
|
FBPriv->StoreGrphSurfaceOffsetX =
|
|
RHDRegRead(Crtc, RegOff + D1GRPH_SURFACE_OFFSET_X);
|
|
FBPriv->StoreGrphSurfaceOffsetY =
|
|
RHDRegRead(Crtc, RegOff + D1GRPH_SURFACE_OFFSET_Y);
|
|
FBPriv->StoreGrphPitch = RHDRegRead(Crtc, RegOff + D1GRPH_PITCH);
|
|
FBPriv->StoreModeDesktopHeight = RHDRegRead(Crtc, RegOff + D1MODE_DESKTOP_HEIGHT);
|
|
|
|
Crtc->FBPriv = FBPriv;
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static void
|
|
DxFBRestore(struct rhdCrtc *Crtc)
|
|
{
|
|
struct rhdCrtcFBPrivate *FBPriv = Crtc->FBPriv;
|
|
CARD32 RegOff;
|
|
|
|
if (!FBPriv) {
|
|
xf86DrvMsg(Crtc->scrnIndex, X_ERROR, "%s: no registers stored!\n",
|
|
__func__);
|
|
return;
|
|
}
|
|
|
|
if (Crtc->Id == RHD_CRTC_1)
|
|
RegOff = D1_REG_OFFSET;
|
|
else
|
|
RegOff = D2_REG_OFFSET;
|
|
|
|
/* FBSet */
|
|
RHDRegWrite(Crtc, RegOff + D1GRPH_CONTROL, FBPriv->StoreGrphControl);
|
|
RHDRegWrite(Crtc, RegOff + D1GRPH_X_START, FBPriv->StoreGrphXStart);
|
|
RHDRegWrite(Crtc, RegOff + D1GRPH_Y_START, FBPriv->StoreGrphYStart);
|
|
RHDRegWrite(Crtc, RegOff + D1GRPH_X_END, FBPriv->StoreGrphXEnd);
|
|
RHDRegWrite(Crtc, RegOff + D1GRPH_Y_END, FBPriv->StoreGrphYEnd);
|
|
if (RHDPTRI(Crtc)->ChipSet >= RHD_R600)
|
|
RHDRegWrite(Crtc, RegOff + D1GRPH_SWAP_CNTL, FBPriv->StoreGrphSwap);
|
|
|
|
/* disable read requests */
|
|
RHDRegMask(Crtc, RegOff + D1CRTC_CONTROL, 0x01000000, 0x01000000);
|
|
RHDRegMask(Crtc, RegOff + D1GRPH_ENABLE, 0, 0x00000001);
|
|
usleep (10);
|
|
|
|
RHDRegWrite(Crtc, RegOff + D1GRPH_PRIMARY_SURFACE_ADDRESS,
|
|
FBPriv->StoreGrphPrimarySurfaceAddress);
|
|
usleep(10);
|
|
|
|
RHDRegWrite(Crtc, RegOff + D1GRPH_ENABLE, FBPriv->StoreGrphEnable);
|
|
|
|
RHDRegWrite(Crtc, RegOff + D1GRPH_SURFACE_OFFSET_X,
|
|
FBPriv->StoreGrphSurfaceOffsetX);
|
|
RHDRegWrite(Crtc, RegOff + D1GRPH_SURFACE_OFFSET_Y,
|
|
FBPriv->StoreGrphSurfaceOffsetY);
|
|
|
|
RHDRegWrite(Crtc, RegOff + D1GRPH_PITCH, FBPriv->StoreGrphPitch);
|
|
RHDRegWrite(Crtc, RegOff + D1MODE_DESKTOP_HEIGHT, FBPriv->StoreModeDesktopHeight);
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static void
|
|
DxFBDestroy(struct rhdCrtc *Crtc)
|
|
{
|
|
if (Crtc->FBPriv)
|
|
xfree(Crtc->FBPriv);
|
|
Crtc->FBPriv = NULL;
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static ModeStatus
|
|
DxModeValid(struct rhdCrtc *Crtc, DisplayModePtr Mode)
|
|
{
|
|
CARD32 tmp;
|
|
|
|
RHDDebug(Crtc->scrnIndex, "%s: %s\n", __func__, Crtc->Name);
|
|
|
|
/* Work around HW bug: need at least 2 lines of front porch
|
|
for interlaced mode */
|
|
if ((Mode->Flags & V_INTERLACE)
|
|
&& (Mode->CrtcVSyncStart < (Mode->CrtcVDisplay + 2))) {
|
|
Mode->CrtcVSyncStart = Mode->CrtcVDisplay + 2;
|
|
Mode->CrtcVAdjusted = TRUE;
|
|
}
|
|
|
|
/* D1CRTC_H_TOTAL - 1 : 13bits */
|
|
if (Mode->CrtcHTotal > 0x2000)
|
|
return MODE_BAD_HVALUE;
|
|
|
|
tmp = Mode->CrtcHTotal + Mode->CrtcHBlankStart - Mode->CrtcHSyncStart;
|
|
/* D1CRTC_H_BLANK_START: 13bits */
|
|
if (tmp >= 0x2000)
|
|
return MODE_BAD_HVALUE;
|
|
|
|
tmp = Mode->CrtcHBlankEnd - Mode->CrtcHSyncStart;
|
|
/* D1CRTC_H_BLANK_END: 13bits */
|
|
if (tmp >= 0x2000)
|
|
return MODE_BAD_HVALUE;
|
|
|
|
tmp = Mode->CrtcHSyncEnd - Mode->CrtcHSyncStart;
|
|
/* D1CRTC_H_SYNC_A_END: 13bits */
|
|
if (tmp >= 0x2000)
|
|
return MODE_HSYNC_WIDE;
|
|
|
|
/* D1CRTC_V_TOTAL - 1 : 13bits */
|
|
if (Mode->CrtcVTotal > 0x2000)
|
|
return MODE_BAD_VVALUE;
|
|
|
|
tmp = Mode->CrtcVTotal + Mode->CrtcVBlankStart - Mode->CrtcVSyncStart;
|
|
/* D1CRTC_V_BLANK_START: 13bits */
|
|
if (tmp >= 0x2000)
|
|
return MODE_BAD_VVALUE;
|
|
|
|
tmp = Mode->CrtcVBlankEnd - Mode->CrtcVSyncStart;
|
|
/* D1CRTC_V_BLANK_END: 13bits */
|
|
if (tmp >= 0x2000)
|
|
return MODE_BAD_VVALUE;
|
|
|
|
tmp = Mode->CrtcVSyncEnd - Mode->CrtcVSyncStart;
|
|
/* D1CRTC_V_SYNC_A_END: 13bits */
|
|
if (tmp >= 0x2000)
|
|
return MODE_VSYNC_WIDE;
|
|
|
|
return MODE_OK;
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static void
|
|
DxModeSet(struct rhdCrtc *Crtc, DisplayModePtr Mode)
|
|
{
|
|
RHDPtr rhdPtr = RHDPTRI(Crtc);
|
|
CARD16 BlankStart, BlankEnd;
|
|
CARD16 RegOff;
|
|
|
|
RHDDebug(Crtc->scrnIndex, "FUNCTION: %s: %s\n", __func__, Crtc->Name);
|
|
|
|
if (rhdPtr->verbosity > 6) {
|
|
xf86DrvMsg(Crtc->scrnIndex, X_INFO, "%s: Setting ",__func__);
|
|
RHDPrintModeline(Mode);
|
|
}
|
|
|
|
if (Crtc->Id == RHD_CRTC_1)
|
|
RegOff = D1_REG_OFFSET;
|
|
else
|
|
RegOff = D2_REG_OFFSET;
|
|
|
|
/* enable read requests */
|
|
RHDRegMask(Crtc, RegOff + D1CRTC_CONTROL, 0, 0x01000000);
|
|
|
|
/* Horizontal */
|
|
RHDRegWrite(Crtc, RegOff + D1CRTC_H_TOTAL, Mode->CrtcHTotal - 1);
|
|
|
|
BlankStart = Mode->CrtcHTotal + Mode->CrtcHBlankStart - Mode->CrtcHSyncStart;
|
|
BlankEnd = Mode->CrtcHBlankEnd - Mode->CrtcHSyncStart;
|
|
RHDRegWrite(Crtc, RegOff + D1CRTC_H_BLANK_START_END,
|
|
BlankStart | (BlankEnd << 16));
|
|
|
|
RHDRegWrite(Crtc, RegOff + D1CRTC_H_SYNC_A,
|
|
(Mode->CrtcHSyncEnd - Mode->CrtcHSyncStart) << 16);
|
|
RHDRegWrite(Crtc, RegOff + D1CRTC_H_SYNC_A_CNTL, Mode->Flags & V_NHSYNC);
|
|
|
|
/* Vertical */
|
|
RHDRegWrite(Crtc, RegOff + D1CRTC_V_TOTAL, Mode->CrtcVTotal - 1);
|
|
|
|
BlankStart = Mode->CrtcVTotal + Mode->CrtcVBlankStart - Mode->CrtcVSyncStart;
|
|
BlankEnd = Mode->CrtcVBlankEnd - Mode->CrtcVSyncStart;
|
|
RHDRegWrite(Crtc, RegOff + D1CRTC_V_BLANK_START_END,
|
|
BlankStart | (BlankEnd << 16));
|
|
|
|
/* set interlaced */
|
|
if (Mode->Flags & V_INTERLACE) {
|
|
RHDRegWrite(Crtc, RegOff + D1CRTC_INTERLACE_CONTROL, 0x1);
|
|
RHDRegWrite(Crtc, RegOff + D1MODE_DATA_FORMAT, 0x1);
|
|
} else {
|
|
RHDRegWrite(Crtc, RegOff + D1CRTC_INTERLACE_CONTROL, 0x0);
|
|
RHDRegWrite(Crtc, RegOff + D1MODE_DATA_FORMAT, 0x0);
|
|
}
|
|
|
|
RHDRegWrite(Crtc, RegOff + D1CRTC_V_SYNC_A,
|
|
(Mode->CrtcVSyncEnd - Mode->CrtcVSyncStart) << 16);
|
|
RHDRegWrite(Crtc, RegOff + D1CRTC_V_SYNC_A_CNTL, Mode->Flags & V_NVSYNC);
|
|
|
|
/* set D1CRTC_HORZ_COUNT_BY2_EN to 0; should only be set to 1 on 30bpp DVI modes */
|
|
RHDRegMask(Crtc, RegOff + D1CRTC_COUNT_CONTROL, 0x0, 0x1);
|
|
|
|
Crtc->CurrentMode = Mode;
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static void
|
|
DxModeSave(struct rhdCrtc *Crtc)
|
|
{
|
|
struct rhdCrtcModePrivate *ModePriv;
|
|
CARD32 RegOff;
|
|
|
|
if (!Crtc->ModePriv)
|
|
ModePriv = xnfcalloc(1, sizeof(struct rhdCrtcModePrivate));
|
|
else
|
|
ModePriv = Crtc->ModePriv;
|
|
|
|
if (Crtc->Id == RHD_CRTC_1)
|
|
RegOff = D1_REG_OFFSET;
|
|
else
|
|
RegOff = D2_REG_OFFSET;
|
|
|
|
ModePriv->StoreCrtcControl = RHDRegRead(Crtc, RegOff + D1CRTC_CONTROL);
|
|
|
|
ModePriv->StoreCrtcHTotal = RHDRegRead(Crtc, RegOff + D1CRTC_H_TOTAL);
|
|
ModePriv->StoreCrtcHBlankStartEnd =
|
|
RHDRegRead(Crtc, RegOff + D1CRTC_H_BLANK_START_END);
|
|
ModePriv->StoreCrtcHSyncA = RHDRegRead(Crtc, RegOff + D1CRTC_H_SYNC_A);
|
|
ModePriv->StoreCrtcHSyncACntl = RHDRegRead(Crtc, RegOff + D1CRTC_H_SYNC_A_CNTL);
|
|
ModePriv->StoreCrtcHSyncB = RHDRegRead(Crtc, RegOff + D1CRTC_H_SYNC_B);
|
|
ModePriv->StoreCrtcHSyncBCntl = RHDRegRead(Crtc, RegOff + D1CRTC_H_SYNC_B_CNTL);
|
|
|
|
ModePriv->StoreModeDataFormat = RHDRegRead(Crtc, RegOff + D1MODE_DATA_FORMAT);
|
|
ModePriv->StoreCrtcInterlaceControl = RHDRegRead(Crtc, RegOff + D1CRTC_INTERLACE_CONTROL);
|
|
|
|
ModePriv->StoreCrtcVTotal = RHDRegRead(Crtc, RegOff + D1CRTC_V_TOTAL);
|
|
ModePriv->StoreCrtcVBlankStartEnd =
|
|
RHDRegRead(Crtc, RegOff + D1CRTC_V_BLANK_START_END);
|
|
ModePriv->StoreCrtcVSyncA = RHDRegRead(Crtc, RegOff + D1CRTC_V_SYNC_A);
|
|
ModePriv->StoreCrtcVSyncACntl = RHDRegRead(Crtc, RegOff + D1CRTC_V_SYNC_A_CNTL);
|
|
ModePriv->StoreCrtcVSyncB = RHDRegRead(Crtc, RegOff + D1CRTC_V_SYNC_B);
|
|
ModePriv->StoreCrtcVSyncBCntl = RHDRegRead(Crtc, RegOff + D1CRTC_V_SYNC_B_CNTL);
|
|
|
|
ModePriv->StoreCrtcBlackColor = RHDRegRead(Crtc, RegOff + D1CRTC_BLACK_COLOR);
|
|
ModePriv->StoreCrtcBlankControl = RHDRegRead(Crtc, RegOff + D1CRTC_BLANK_CONTROL);
|
|
|
|
ModePriv->StoreCrtcCountControl = RHDRegRead(Crtc, RegOff + D1CRTC_COUNT_CONTROL);
|
|
RHDDebug(Crtc->scrnIndex, "Saved CrtcCountControl[%i] = 0x%8.8x\n",
|
|
Crtc->Id,ModePriv->StoreCrtcCountControl);
|
|
|
|
Crtc->ModePriv = ModePriv;
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static void
|
|
DxModeRestore(struct rhdCrtc *Crtc)
|
|
{
|
|
struct rhdCrtcModePrivate *ModePriv = Crtc->ModePriv;
|
|
CARD32 RegOff;
|
|
|
|
if (!ModePriv) {
|
|
xf86DrvMsg(Crtc->scrnIndex, X_ERROR, "%s: no registers stored!\n",
|
|
__func__);
|
|
return;
|
|
}
|
|
|
|
if (Crtc->Id == RHD_CRTC_1)
|
|
RegOff = D1_REG_OFFSET;
|
|
else
|
|
RegOff = D2_REG_OFFSET;
|
|
|
|
/* ModeSet */
|
|
RHDRegWrite(Crtc, RegOff + D1CRTC_CONTROL, ModePriv->StoreCrtcControl);
|
|
|
|
RHDRegWrite(Crtc, RegOff + D1CRTC_H_TOTAL, ModePriv->StoreCrtcHTotal);
|
|
RHDRegWrite(Crtc, RegOff + D1CRTC_H_BLANK_START_END,
|
|
ModePriv->StoreCrtcHBlankStartEnd);
|
|
RHDRegWrite(Crtc, RegOff + D1CRTC_H_SYNC_A, ModePriv->StoreCrtcHSyncA);
|
|
RHDRegWrite(Crtc, RegOff + D1CRTC_H_SYNC_A_CNTL, ModePriv->StoreCrtcHSyncACntl);
|
|
RHDRegWrite(Crtc, RegOff + D1CRTC_H_SYNC_B, ModePriv->StoreCrtcHSyncB);
|
|
RHDRegWrite(Crtc, RegOff + D1CRTC_H_SYNC_B_CNTL, ModePriv->StoreCrtcHSyncBCntl);
|
|
|
|
RHDRegWrite(Crtc, RegOff + D1MODE_DATA_FORMAT, ModePriv->StoreModeDataFormat);
|
|
RHDRegWrite(Crtc, RegOff + D1CRTC_INTERLACE_CONTROL, ModePriv->StoreCrtcInterlaceControl);
|
|
|
|
RHDRegWrite(Crtc, RegOff + D1CRTC_V_TOTAL, ModePriv->StoreCrtcVTotal);
|
|
RHDRegWrite(Crtc, RegOff + D1CRTC_V_BLANK_START_END,
|
|
ModePriv->StoreCrtcVBlankStartEnd);
|
|
RHDRegWrite(Crtc, RegOff + D1CRTC_V_SYNC_A, ModePriv->StoreCrtcVSyncA);
|
|
RHDRegWrite(Crtc, RegOff + D1CRTC_V_SYNC_A_CNTL, ModePriv->StoreCrtcVSyncACntl);
|
|
RHDRegWrite(Crtc, RegOff + D1CRTC_V_SYNC_B, ModePriv->StoreCrtcVSyncB);
|
|
RHDRegWrite(Crtc, RegOff + D1CRTC_V_SYNC_B_CNTL, ModePriv->StoreCrtcVSyncBCntl);
|
|
|
|
RHDRegWrite(Crtc, RegOff + D1CRTC_COUNT_CONTROL, ModePriv->StoreCrtcCountControl);
|
|
|
|
/* Blank */
|
|
RHDRegWrite(Crtc, RegOff + D1CRTC_BLACK_COLOR, ModePriv->StoreCrtcBlackColor);
|
|
RHDRegWrite(Crtc, RegOff + D1CRTC_BLANK_CONTROL, ModePriv->StoreCrtcBlankControl);
|
|
|
|
/* When VGA is enabled, it imposes its timing on us, so our CRTC SYNC
|
|
* timing can be set to 0. This doesn't always restore properly...
|
|
* Workaround is to set a valid sync length for a bit so VGA can
|
|
* latch in. */
|
|
if (!ModePriv->StoreCrtcVSyncA && (ModePriv->StoreCrtcControl & 0x00000001)) {
|
|
RHDRegWrite(Crtc, RegOff + D1CRTC_V_SYNC_A, 0x00040000);
|
|
usleep(300000); /* seems a reliable timeout here */
|
|
RHDRegWrite(Crtc, RegOff + D1CRTC_V_SYNC_A, ModePriv->StoreCrtcVSyncA);
|
|
}
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static void
|
|
DxModeDestroy(struct rhdCrtc *Crtc)
|
|
{
|
|
RHDFUNC(Crtc);
|
|
|
|
if (Crtc->ModePriv)
|
|
xfree(Crtc->ModePriv);
|
|
Crtc->ModePriv = NULL;
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
struct rhdScalerOverscan
|
|
rhdCalculateOverscan(DisplayModePtr Mode, DisplayModePtr ScaledToMode, enum rhdCrtcScaleType Type)
|
|
{
|
|
struct rhdScalerOverscan Overscan;
|
|
int tmp;
|
|
|
|
Overscan.OverscanTop = Overscan.OverscanBottom = Overscan.OverscanLeft = Overscan.OverscanRight = 0;
|
|
Overscan.Type = Type;
|
|
|
|
if (ScaledToMode) {
|
|
Overscan.OverscanTop = ScaledToMode->CrtcVDisplay - Mode->CrtcVDisplay;
|
|
Overscan.OverscanLeft = ScaledToMode->CrtcHDisplay - Mode->CrtcHDisplay;
|
|
|
|
if (!Overscan.OverscanTop && !Overscan.OverscanLeft)
|
|
Overscan.Type = RHD_CRTC_SCALE_TYPE_NONE;
|
|
|
|
/* handle down scaling */
|
|
if (Overscan.OverscanTop < 0) {
|
|
Overscan.Type = RHD_CRTC_SCALE_TYPE_SCALE;
|
|
Overscan.OverscanTop = 0;
|
|
}
|
|
if (Overscan.OverscanLeft < 0) {
|
|
Overscan.Type = RHD_CRTC_SCALE_TYPE_SCALE;
|
|
Overscan.OverscanLeft = 0;
|
|
}
|
|
}
|
|
|
|
switch (Type) {
|
|
case RHD_CRTC_SCALE_TYPE_NONE:
|
|
break;
|
|
|
|
case RHD_CRTC_SCALE_TYPE_CENTER:
|
|
tmp = Overscan.OverscanTop;
|
|
Overscan.OverscanTop >>= 1;
|
|
Overscan.OverscanBottom = tmp - Overscan.OverscanTop;
|
|
tmp = Overscan.OverscanLeft;
|
|
Overscan.OverscanLeft >>= 1;
|
|
Overscan.OverscanRight = tmp - Overscan.OverscanLeft;
|
|
break;
|
|
|
|
case RHD_CRTC_SCALE_TYPE_SCALE:
|
|
Overscan.OverscanLeft = Overscan.OverscanRight = Overscan.OverscanTop = Overscan.OverscanBottom = 0;
|
|
break;
|
|
case RHD_CRTC_SCALE_TYPE_SCALE_KEEP_ASPECT_RATIO:
|
|
{
|
|
int p1, p2, tmp;
|
|
Overscan.OverscanLeft = Overscan.OverscanRight = Overscan.OverscanTop = Overscan.OverscanBottom = 0;
|
|
p1 = Mode->CrtcVDisplay * ScaledToMode->CrtcHDisplay;
|
|
p2 = ScaledToMode->CrtcVDisplay * Mode->CrtcHDisplay;
|
|
if (p1 == p2) {
|
|
Overscan.Type = RHD_CRTC_SCALE_TYPE_SCALE;
|
|
} else if (p1 > p2) {
|
|
tmp = (p2 / Mode->CrtcVDisplay);
|
|
tmp = ScaledToMode->CrtcHDisplay - tmp;
|
|
Overscan.OverscanLeft = tmp >> 1;
|
|
Overscan.OverscanRight = tmp - Overscan.OverscanLeft;
|
|
ErrorF("HScale %i %i\n", Overscan.OverscanLeft, Overscan.OverscanRight);
|
|
} else {
|
|
tmp = (p1 / Mode->CrtcHDisplay);
|
|
tmp = ScaledToMode->CrtcVDisplay - tmp;
|
|
Overscan.OverscanTop = tmp >> 1;
|
|
Overscan.OverscanBottom = tmp - Overscan.OverscanTop;
|
|
ErrorF("VScale %i %i\n", Overscan.OverscanTop, Overscan.OverscanBottom);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return Overscan;
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static ModeStatus
|
|
DxScaleValid(struct rhdCrtc *Crtc, enum rhdCrtcScaleType Type,
|
|
DisplayModePtr Mode, DisplayModePtr ScaledToMode)
|
|
{
|
|
struct rhdScalerOverscan Overscan;
|
|
|
|
/* D1_MODE_VIEWPORT_WIDTH: 14bits */
|
|
if (Mode->CrtcHDisplay >= 0x4000)
|
|
return MODE_BAD_HVALUE;
|
|
|
|
/* D1_MODE_VIEWPORT_HEIGHT: 14bits */
|
|
if (Mode->CrtcVDisplay >= 0x4000)
|
|
return MODE_BAD_VVALUE;
|
|
|
|
Overscan = rhdCalculateOverscan(Mode, ScaledToMode, Type);
|
|
|
|
if (Overscan.OverscanLeft >= 4096 || Overscan.OverscanRight >= 4096)
|
|
return MODE_HBLANK_WIDE;
|
|
|
|
if (Overscan.OverscanTop >= 4096 || Overscan.OverscanBottom >= 4096)
|
|
return MODE_VBLANK_WIDE;
|
|
|
|
if ((Type == RHD_CRTC_SCALE_TYPE_SCALE
|
|
|| Type == RHD_CRTC_SCALE_TYPE_SCALE_KEEP_ASPECT_RATIO)
|
|
&& (Mode->Flags & V_INTERLACE))
|
|
return MODE_NO_INTERLACE;
|
|
|
|
/* should we also fail of Type != Overscan.Type? */
|
|
|
|
return MODE_OK;
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static void
|
|
DxScaleSet(struct rhdCrtc *Crtc, enum rhdCrtcScaleType Type,
|
|
DisplayModePtr Mode, DisplayModePtr ScaledToMode)
|
|
{
|
|
RHDPtr rhdPtr = RHDPTRI(Crtc);
|
|
CARD16 RegOff;
|
|
struct rhdScalerOverscan Overscan;
|
|
|
|
RHDDebug(Crtc->scrnIndex, "FUNCTION: %s: %s viewport: %ix%i\n", __func__, Crtc->Name,
|
|
Mode->CrtcHDisplay, Mode->CrtcVDisplay);
|
|
|
|
if (Crtc->Id == RHD_CRTC_1)
|
|
RegOff = D1_REG_OFFSET;
|
|
else
|
|
RegOff = D2_REG_OFFSET;
|
|
|
|
Overscan = rhdCalculateOverscan(Mode, ScaledToMode, Type);
|
|
Type = Overscan.Type;
|
|
|
|
RHDDebug(Crtc->scrnIndex, "FUNCTION: %s: %s viewport: %ix%i - OverScan: T: %i B: %i R: %i L: %i\n",
|
|
__func__, Crtc->Name, Mode->CrtcHDisplay, Mode->CrtcVDisplay,
|
|
Overscan.OverscanTop, Overscan.OverscanBottom,
|
|
Overscan.OverscanLeft, Overscan.OverscanRight);
|
|
|
|
/* D1Mode registers */
|
|
RHDRegWrite(Crtc, RegOff + D1MODE_VIEWPORT_SIZE,
|
|
Mode->CrtcVDisplay | (Mode->CrtcHDisplay << 16));
|
|
RHDRegWrite(Crtc, RegOff + D1MODE_VIEWPORT_START, 0);
|
|
|
|
RHDRegWrite(Crtc, RegOff + D1MODE_EXT_OVERSCAN_LEFT_RIGHT,
|
|
(Overscan.OverscanLeft << 16) | Overscan.OverscanRight);
|
|
RHDRegWrite(Crtc, RegOff + D1MODE_EXT_OVERSCAN_TOP_BOTTOM,
|
|
(Overscan.OverscanTop << 16) | Overscan.OverscanBottom);
|
|
|
|
switch (Type) {
|
|
case RHD_CRTC_SCALE_TYPE_NONE: /* No scaling whatsoever */
|
|
ErrorF("None\n");
|
|
RHDRegWrite(Crtc, RegOff + D1SCL_ENABLE, 0);
|
|
RHDRegWrite(Crtc, RegOff + D1SCL_TAP_CONTROL, 0);
|
|
RHDRegWrite(Crtc, RegOff + D1MODE_CENTER, 0);
|
|
break;
|
|
case RHD_CRTC_SCALE_TYPE_CENTER: /* center of the actual mode */
|
|
ErrorF("Center\n");
|
|
RHDRegWrite(Crtc, RegOff + D1SCL_ENABLE, 0);
|
|
RHDRegWrite(Crtc, RegOff + D1SCL_TAP_CONTROL, 0);
|
|
RHDRegWrite(Crtc, RegOff + D1MODE_CENTER, 1);
|
|
break;
|
|
case RHD_CRTC_SCALE_TYPE_SCALE_KEEP_ASPECT_RATIO: /* scaled to fullscreen */
|
|
case RHD_CRTC_SCALE_TYPE_SCALE: /* scaled to fullscreen */
|
|
ErrorF("Full\n");
|
|
if (Type == RHD_CRTC_SCALE_TYPE_SCALE_KEEP_ASPECT_RATIO)
|
|
RHDRegWrite(Crtc, RegOff + D1MODE_CENTER, 1);
|
|
else
|
|
RHDRegWrite(Crtc, RegOff + D1MODE_CENTER, 0);
|
|
|
|
RHDRegWrite(Crtc, RegOff + D1SCL_UPDATE, 0);
|
|
RHDRegWrite(Crtc, RegOff + D1SCL_DITHER, 0);
|
|
|
|
RHDRegWrite(Crtc, RegOff + D1SCL_ENABLE, 1);
|
|
RHDRegWrite(Crtc, RegOff + D1SCL_HVSCALE, 0x00010001); /* both h/v */
|
|
|
|
RHDRegWrite(Crtc, RegOff + D1SCL_TAP_CONTROL, 0x00000101);
|
|
|
|
RHDRegWrite(Crtc, RegOff + D1SCL_HFILTER, 0x00030100);
|
|
RHDRegWrite(Crtc, RegOff + D1SCL_VFILTER, 0x00030100);
|
|
|
|
RHDRegWrite(Crtc, RegOff + D1SCL_DITHER, 0x00001010);
|
|
break;
|
|
}
|
|
RHDMCTuneAccessForDisplay(rhdPtr, Crtc->Id, Mode,
|
|
ScaledToMode ? ScaledToMode : Mode);
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static void
|
|
DxScaleSave(struct rhdCrtc *Crtc)
|
|
{
|
|
struct rhdCrtcScalePrivate *ScalePriv;
|
|
CARD32 RegOff;
|
|
|
|
if (!Crtc->ScalePriv)
|
|
ScalePriv = xnfcalloc(1, sizeof(struct rhdCrtcScalePrivate));
|
|
else
|
|
ScalePriv = Crtc->ScalePriv;
|
|
|
|
if (Crtc->Id == RHD_CRTC_1)
|
|
RegOff = D1_REG_OFFSET;
|
|
else
|
|
RegOff = D2_REG_OFFSET;
|
|
|
|
ScalePriv->StoreModeViewPortSize = RHDRegRead(Crtc, RegOff + D1MODE_VIEWPORT_SIZE);
|
|
ScalePriv->StoreModeViewPortStart = RHDRegRead(Crtc, RegOff + D1MODE_VIEWPORT_START);
|
|
ScalePriv->StoreModeOverScanH =
|
|
RHDRegRead(Crtc, RegOff + D1MODE_EXT_OVERSCAN_LEFT_RIGHT);
|
|
ScalePriv->StoreModeOverScanV =
|
|
RHDRegRead(Crtc, RegOff + D1MODE_EXT_OVERSCAN_TOP_BOTTOM);
|
|
|
|
ScalePriv->StoreScaleEnable = RHDRegRead(Crtc, RegOff + D1SCL_ENABLE);
|
|
ScalePriv->StoreScaleTapControl = RHDRegRead(Crtc, RegOff + D1SCL_TAP_CONTROL);
|
|
ScalePriv->StoreModeCenter = RHDRegRead(Crtc, RegOff + D1MODE_CENTER);
|
|
ScalePriv->StoreScaleHV = RHDRegRead(Crtc, RegOff + D1SCL_HVSCALE);
|
|
ScalePriv->StoreScaleHFilter = RHDRegRead(Crtc, RegOff + D1SCL_HFILTER);
|
|
ScalePriv->StoreScaleVFilter = RHDRegRead(Crtc, RegOff + D1SCL_VFILTER);
|
|
ScalePriv->StoreScaleDither = RHDRegRead(Crtc, RegOff + D1SCL_DITHER);
|
|
|
|
Crtc->ScalePriv = ScalePriv;
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static void
|
|
DxScaleRestore(struct rhdCrtc *Crtc)
|
|
{
|
|
struct rhdCrtcScalePrivate *ScalePriv = Crtc->ScalePriv;
|
|
CARD32 RegOff;
|
|
|
|
if (!ScalePriv) {
|
|
xf86DrvMsg(Crtc->scrnIndex, X_ERROR, "%s: no registers stored!\n",
|
|
__func__);
|
|
return;
|
|
}
|
|
|
|
if (Crtc->Id == RHD_CRTC_1)
|
|
RegOff = D1_REG_OFFSET;
|
|
else
|
|
RegOff = D2_REG_OFFSET;
|
|
|
|
/* ScaleSet */
|
|
RHDRegWrite(Crtc, RegOff + D1MODE_VIEWPORT_SIZE, ScalePriv->StoreModeViewPortSize);
|
|
|
|
/* ScaleSet/ViewPortStart */
|
|
RHDRegWrite(Crtc, RegOff + D1MODE_VIEWPORT_START, ScalePriv->StoreModeViewPortStart);
|
|
|
|
/* ScaleSet */
|
|
RHDRegWrite(Crtc, RegOff + D1MODE_EXT_OVERSCAN_LEFT_RIGHT,
|
|
ScalePriv->StoreModeOverScanH);
|
|
RHDRegWrite(Crtc, RegOff + D1MODE_EXT_OVERSCAN_TOP_BOTTOM,
|
|
ScalePriv->StoreModeOverScanV);
|
|
|
|
RHDRegWrite(Crtc, RegOff + D1SCL_ENABLE, ScalePriv->StoreScaleEnable);
|
|
RHDRegWrite(Crtc, RegOff + D1SCL_TAP_CONTROL, ScalePriv->StoreScaleTapControl);
|
|
RHDRegWrite(Crtc, RegOff + D1MODE_CENTER, ScalePriv->StoreModeCenter);
|
|
RHDRegWrite(Crtc, RegOff + D1SCL_HVSCALE, ScalePriv->StoreScaleHV);
|
|
RHDRegWrite(Crtc, RegOff + D1SCL_HFILTER, ScalePriv->StoreScaleHFilter);
|
|
RHDRegWrite(Crtc, RegOff + D1SCL_VFILTER, ScalePriv->StoreScaleVFilter);
|
|
RHDRegWrite(Crtc, RegOff + D1SCL_DITHER, ScalePriv->StoreScaleDither);
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static void
|
|
DxScaleDestroy(struct rhdCrtc *Crtc)
|
|
{
|
|
RHDFUNC(Crtc);
|
|
|
|
if (Crtc->ScalePriv)
|
|
xfree(Crtc->ScalePriv);
|
|
Crtc->ScalePriv = NULL;
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static void
|
|
D1LUTSelect(struct rhdCrtc *Crtc, struct rhdLUT *LUT)
|
|
{
|
|
RHDFUNC(Crtc);
|
|
|
|
RHDRegWrite(Crtc, D1GRPH_LUT_SEL, LUT->Id & 1);
|
|
Crtc->LUT = LUT;
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static void
|
|
D2LUTSelect(struct rhdCrtc *Crtc, struct rhdLUT *LUT)
|
|
{
|
|
RHDFUNC(Crtc);
|
|
|
|
RHDRegWrite(Crtc, D2GRPH_LUT_SEL, LUT->Id & 1);
|
|
Crtc->LUT = LUT;
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static void
|
|
DxLUTSave(struct rhdCrtc *Crtc)
|
|
{
|
|
struct rhdCrtcLUTPrivate *LUTPriv;
|
|
CARD32 RegOff;
|
|
|
|
if (!Crtc->LUTPriv)
|
|
LUTPriv = xnfcalloc(1, sizeof(struct rhdCrtcLUTPrivate));
|
|
else
|
|
LUTPriv = Crtc->LUTPriv;
|
|
|
|
if (Crtc->Id == RHD_CRTC_1)
|
|
RegOff = D1_REG_OFFSET;
|
|
else
|
|
RegOff = D2_REG_OFFSET;
|
|
|
|
LUTPriv->StoreGrphLutSel = RHDRegRead(Crtc, RegOff + D1GRPH_LUT_SEL);
|
|
|
|
Crtc->LUTPriv = LUTPriv;
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static void
|
|
DxLUTRestore(struct rhdCrtc *Crtc)
|
|
{
|
|
struct rhdCrtcLUTPrivate *LUTPriv = Crtc->LUTPriv;
|
|
CARD32 RegOff;
|
|
|
|
if (!LUTPriv) {
|
|
xf86DrvMsg(Crtc->scrnIndex, X_ERROR, "%s: no registers stored!\n",
|
|
__func__);
|
|
return;
|
|
}
|
|
|
|
if (Crtc->Id == RHD_CRTC_1)
|
|
RegOff = D1_REG_OFFSET;
|
|
else
|
|
RegOff = D2_REG_OFFSET;
|
|
|
|
/* LUTSelect */
|
|
RHDRegWrite(Crtc, RegOff + D1GRPH_LUT_SEL, LUTPriv->StoreGrphLutSel);
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static void
|
|
DxLUTDestroy(struct rhdCrtc *Crtc)
|
|
{
|
|
RHDFUNC(Crtc);
|
|
|
|
if (Crtc->LUTPriv)
|
|
xfree(Crtc->LUTPriv);
|
|
Crtc->LUTPriv = NULL;
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static void
|
|
D1ViewPortStart(struct rhdCrtc *Crtc, CARD16 X, CARD16 Y)
|
|
{
|
|
RHDFUNC(Crtc);
|
|
|
|
/* not as granular as docs make it seem to be.
|
|
* if the lower two bits are set the line buffer might screw up, requiring
|
|
* a power cycle. */
|
|
X = (X + 0x02) & ~0x03;
|
|
Y &= ~0x01;
|
|
|
|
RHDRegMask(Crtc, D1SCL_UPDATE, 0x00010000, 0x0001000);
|
|
RHDRegWrite(Crtc, D1MODE_VIEWPORT_START, (X << 16) | Y);
|
|
RHDRegMask(Crtc, D1SCL_UPDATE, 0, 0x0001000);
|
|
|
|
Crtc->X = X;
|
|
Crtc->Y = Y;
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static void
|
|
D2ViewPortStart(struct rhdCrtc *Crtc, CARD16 X, CARD16 Y)
|
|
{
|
|
RHDFUNC(Crtc);
|
|
|
|
/* not as granular as docs make it seem to be. */
|
|
X = (X + 0x02) & ~0x03;
|
|
Y &= ~0x01;
|
|
|
|
RHDRegMask(Crtc, D2SCL_UPDATE, 0x00010000, 0x0001000);
|
|
RHDRegWrite(Crtc, D2MODE_VIEWPORT_START, (X << 16) | Y);
|
|
RHDRegMask(Crtc, D2SCL_UPDATE, 0, 0x0001000);
|
|
|
|
Crtc->X = X;
|
|
Crtc->Y = Y;
|
|
}
|
|
|
|
#define CRTC_SYNC_WAIT 0x100000
|
|
/*
|
|
*
|
|
*/
|
|
static Bool
|
|
D1CRTCDisable(struct rhdCrtc *Crtc)
|
|
{
|
|
if (RHDRegRead(Crtc, D1CRTC_CONTROL) & 0x00000001) {
|
|
CARD32 Control = RHDRegRead(Crtc, D1CRTC_CONTROL);
|
|
int i;
|
|
|
|
RHDRegMask(Crtc, D1CRTC_CONTROL, 0, 0x00000301);
|
|
(void)RHDRegRead(Crtc, D1CRTC_CONTROL);
|
|
|
|
for (i = 0; i < CRTC_SYNC_WAIT; i++)
|
|
if (!(RHDRegRead(Crtc, D1CRTC_CONTROL) & 0x00010000)) {
|
|
RHDDebug(Crtc->scrnIndex, "%s: %d loops\n", __func__, i);
|
|
RHDRegMask(Crtc, D1CRTC_CONTROL, Control, 0x00000300);
|
|
return TRUE;
|
|
}
|
|
xf86DrvMsg(Crtc->scrnIndex, X_ERROR,
|
|
"%s: Failed to Unsync %s\n", __func__, Crtc->Name);
|
|
RHDRegMask(Crtc, D1CRTC_CONTROL, Control, 0x00000300);
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static Bool
|
|
D2CRTCDisable(struct rhdCrtc *Crtc)
|
|
{
|
|
if (RHDRegRead(Crtc, D2CRTC_CONTROL) & 0x00000001) {
|
|
CARD32 Control = RHDRegRead(Crtc, D2CRTC_CONTROL);
|
|
int i;
|
|
|
|
RHDRegMask(Crtc, D2CRTC_CONTROL, 0, 0x00000301);
|
|
(void)RHDRegRead(Crtc, D2CRTC_CONTROL);
|
|
|
|
for (i = 0; i < CRTC_SYNC_WAIT; i++)
|
|
if (!(RHDRegRead(Crtc, D2CRTC_CONTROL) & 0x00010000)) {
|
|
RHDDebug(Crtc->scrnIndex, "%s: %d loops\n", __func__, i);
|
|
RHDRegMask(Crtc, D2CRTC_CONTROL, Control, 0x00000300);
|
|
return TRUE;
|
|
}
|
|
xf86DrvMsg(Crtc->scrnIndex, X_ERROR,
|
|
"%s: Failed to Unsync %s\n", __func__, Crtc->Name);
|
|
RHDRegMask(Crtc, D2CRTC_CONTROL, Control, 0x00000300);
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static Bool
|
|
D1Power(struct rhdCrtc *Crtc, int Power)
|
|
{
|
|
Bool ret;
|
|
RHDFUNC(Crtc);
|
|
|
|
switch (Power) {
|
|
case RHD_POWER_ON:
|
|
RHDRegMask(Crtc, D1GRPH_ENABLE, 0x00000001, 0x00000001);
|
|
usleep(2);
|
|
RHDRegMask(Crtc, D1CRTC_CONTROL, 0, 0x01000000); /* enable read requests */
|
|
RHDRegMask(Crtc, D1CRTC_CONTROL, 1, 1);
|
|
return TRUE;
|
|
case RHD_POWER_RESET:
|
|
RHDRegMask(Crtc, D1CRTC_CONTROL, 0x01000000, 0x01000000); /* disable read requests */
|
|
return D1CRTCDisable(Crtc);
|
|
case RHD_POWER_SHUTDOWN:
|
|
default:
|
|
RHDRegMask(Crtc, D1CRTC_CONTROL, 0x01000000, 0x01000000); /* disable read requests */
|
|
ret = D1CRTCDisable(Crtc);
|
|
RHDRegMask(Crtc, D1GRPH_ENABLE, 0, 0x00000001);
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static Bool
|
|
D2Power(struct rhdCrtc *Crtc, int Power)
|
|
{
|
|
Bool ret;
|
|
RHDFUNC(Crtc);
|
|
|
|
switch (Power) {
|
|
case RHD_POWER_ON:
|
|
RHDRegMask(Crtc, D2GRPH_ENABLE, 0x00000001, 0x00000001);
|
|
usleep(2);
|
|
RHDRegMask(Crtc, D2CRTC_CONTROL, 0, 0x01000000); /* enable read requests */
|
|
RHDRegMask(Crtc, D2CRTC_CONTROL, 1, 1);
|
|
return TRUE;
|
|
case RHD_POWER_RESET:
|
|
RHDRegMask(Crtc, D2CRTC_CONTROL, 0x01000000, 0x01000000); /* disable read requests */
|
|
return D2CRTCDisable(Crtc);
|
|
case RHD_POWER_SHUTDOWN:
|
|
default:
|
|
RHDRegMask(Crtc, D2CRTC_CONTROL, 0x01000000, 0x01000000); /* disable read requests */
|
|
ret = D2CRTCDisable(Crtc);
|
|
RHDRegMask(Crtc, D2GRPH_ENABLE, 0, 0x00000001);
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* This is quite different from Power. Power disables and enables things,
|
|
* this here makes the hw send out black, and can switch back and forth
|
|
* immediately. Useful for covering up a framebuffer that is not filled
|
|
* in yet.
|
|
*/
|
|
static void
|
|
D1Blank(struct rhdCrtc *Crtc, Bool Blank)
|
|
{
|
|
RHDFUNC(Crtc);
|
|
|
|
RHDRegWrite(Crtc, D1CRTC_BLACK_COLOR, 0);
|
|
if (Blank)
|
|
RHDRegMask(Crtc, D1CRTC_BLANK_CONTROL, 0x00000100, 0x00000100);
|
|
else
|
|
RHDRegMask(Crtc, D1CRTC_BLANK_CONTROL, 0, 0x00000100);
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static void
|
|
D2Blank(struct rhdCrtc *Crtc, Bool Blank)
|
|
{
|
|
RHDFUNC(Crtc);
|
|
|
|
RHDRegWrite(Crtc, D2CRTC_BLACK_COLOR, 0);
|
|
if (Blank)
|
|
RHDRegMask(Crtc, D2CRTC_BLANK_CONTROL, 0x00000100, 0x00000100);
|
|
else
|
|
RHDRegMask(Crtc, D2CRTC_BLANK_CONTROL, 0, 0x00000100);
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static void
|
|
DxFMTSet(struct rhdCrtc *Crtc, struct rhdFMTDither *FMTDither)
|
|
{
|
|
CARD32 RegOff;
|
|
CARD32 fmt_cntl = 0;
|
|
|
|
RHDFUNC(Crtc);
|
|
|
|
if (Crtc->Id == RHD_CRTC_1)
|
|
RegOff = FMT1_REG_OFFSET;
|
|
else
|
|
RegOff = FMT2_REG_OFFSET;
|
|
|
|
if (FMTDither) {
|
|
|
|
/* set dither depth to 18/24 */
|
|
fmt_cntl = FMTDither->LVDS24Bit
|
|
? (RV62_FMT_SPATIAL_DITHER_DEPTH | RV62_FMT_TEMPORAL_DITHER_DEPTH)
|
|
: 0;
|
|
RHDRegMask(Crtc, RegOff + RV620_FMT1_BIT_DEPTH_CONTROL, fmt_cntl,
|
|
RV62_FMT_SPATIAL_DITHER_DEPTH | RV62_FMT_TEMPORAL_DITHER_DEPTH);
|
|
|
|
/* set temporal dither */
|
|
if (FMTDither->LVDSTemporalDither) {
|
|
fmt_cntl = FMTDither->LVDSGreyLevel ? RV62_FMT_TEMPORAL_LEVEL : 0x0;
|
|
/* grey level */
|
|
RHDRegMask(Crtc, RegOff + RV620_FMT1_BIT_DEPTH_CONTROL,
|
|
fmt_cntl, RV62_FMT_TEMPORAL_LEVEL);
|
|
/* turn on temporal dither and reset */
|
|
RHDRegMask(Crtc, RegOff + RV620_FMT1_BIT_DEPTH_CONTROL,
|
|
RV62_FMT_TEMPORAL_DITHER_EN | RV62_FMT_TEMPORAL_DITHER_RESET,
|
|
RV62_FMT_TEMPORAL_DITHER_EN | RV62_FMT_TEMPORAL_DITHER_RESET);
|
|
usleep(20);
|
|
/* turn off reset */
|
|
RHDRegMask(Crtc, RegOff + RV620_FMT1_BIT_DEPTH_CONTROL, 0x0,
|
|
RV62_FMT_TEMPORAL_DITHER_RESET);
|
|
}
|
|
/* spatial dither */
|
|
RHDRegMask(Crtc, RegOff + RV620_FMT1_BIT_DEPTH_CONTROL,
|
|
FMTDither->LVDSSpatialDither ? RV62_FMT_SPATIAL_DITHER_EN : 0,
|
|
RV62_FMT_SPATIAL_DITHER_EN);
|
|
} else
|
|
RHDRegWrite(Crtc, RegOff + RV620_FMT1_BIT_DEPTH_CONTROL, 0);
|
|
|
|
/* 4:4:4 encoding */
|
|
RHDRegMask(Crtc, RegOff + RV620_FMT1_CONTROL, 0, RV62_FMT_PIXEL_ENCODING);
|
|
/* disable color clamping */
|
|
RHDRegWrite(Crtc, RegOff + RV620_FMT1_CLAMP_CNTL, 0);
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static void
|
|
DxFMTSave(struct rhdCrtc *Crtc)
|
|
{
|
|
struct rhdCrtcFMTPrivate *FMTPrivate;
|
|
CARD32 RegOff;
|
|
|
|
RHDFUNC(Crtc);
|
|
|
|
if (!Crtc->FMTPriv)
|
|
FMTPrivate = xnfcalloc(sizeof (struct rhdCrtcFMTPrivate),1);
|
|
else
|
|
FMTPrivate = Crtc->FMTPriv;
|
|
|
|
if (Crtc->Id == RHD_CRTC_1)
|
|
RegOff = FMT1_REG_OFFSET;
|
|
else
|
|
RegOff = FMT2_REG_OFFSET;
|
|
|
|
FMTPrivate->StoreControl = RHDRegRead(Crtc, RegOff + RV620_FMT1_CONTROL);
|
|
FMTPrivate->StoreBitDepthControl = RHDRegRead(Crtc, RegOff + RV620_FMT1_BIT_DEPTH_CONTROL);
|
|
FMTPrivate->StoreClampCntl = RHDRegRead(Crtc, RegOff + RV620_FMT1_CLAMP_CNTL);
|
|
|
|
Crtc->FMTPriv = FMTPrivate;
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static void
|
|
DxFMTRestore(struct rhdCrtc *Crtc)
|
|
{
|
|
struct rhdCrtcFMTPrivate *FMTPrivate = Crtc->FMTPriv;
|
|
CARD32 RegOff;
|
|
|
|
RHDFUNC(Crtc);
|
|
|
|
if (!FMTPrivate)
|
|
return;
|
|
|
|
if (Crtc->Id == RHD_CRTC_1)
|
|
RegOff = FMT1_REG_OFFSET;
|
|
else
|
|
RegOff = FMT2_REG_OFFSET;
|
|
|
|
RHDRegWrite(Crtc, RegOff + RV620_FMT1_CONTROL, FMTPrivate->StoreControl);
|
|
RHDRegWrite(Crtc, RegOff + RV620_FMT1_BIT_DEPTH_CONTROL, FMTPrivate->StoreBitDepthControl);
|
|
RHDRegWrite(Crtc, RegOff + RV620_FMT1_CLAMP_CNTL, FMTPrivate->StoreClampCntl);
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static void
|
|
DxFMTDestroy(struct rhdCrtc *Crtc)
|
|
{
|
|
RHDFUNC(Crtc);
|
|
|
|
if (Crtc->FMTPriv)
|
|
xfree(Crtc->FMTPriv);
|
|
Crtc->FMTPriv = NULL;
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static enum rhdCrtcScaleType
|
|
rhdInitScaleType(RHDPtr rhdPtr)
|
|
{
|
|
RHDFUNC(rhdPtr);
|
|
/*
|
|
if (rhdPtr->scaleTypeOpt.set) {
|
|
if (!strcasecmp(rhdPtr->scaleTypeOpt.val.string, "none"))
|
|
return RHD_CRTC_SCALE_TYPE_NONE;
|
|
else if (!strcasecmp(rhdPtr->scaleTypeOpt.val.string, "center"))
|
|
return RHD_CRTC_SCALE_TYPE_CENTER;
|
|
else if (!strcasecmp(rhdPtr->scaleTypeOpt.val.string, "scale"))
|
|
return RHD_CRTC_SCALE_TYPE_SCALE;
|
|
else if (!strcasecmp(rhdPtr->scaleTypeOpt.val.string, "scale_keep_aspect_ratio"))
|
|
return RHD_CRTC_SCALE_TYPE_SCALE_KEEP_ASPECT_RATIO;
|
|
else if (!strcasecmp(rhdPtr->scaleTypeOpt.val.string, "default"))
|
|
return RHD_CRTC_SCALE_TYPE_DEFAULT;
|
|
else {
|
|
xf86DrvMsgVerb(rhdPtr->scrnIndex, X_ERROR, 0,
|
|
"Unknown scale type: %s\n", rhdPtr->scaleTypeOpt.val.string);
|
|
return RHD_CRTC_SCALE_TYPE_DEFAULT;
|
|
}
|
|
} else */
|
|
return RHD_CRTC_SCALE_TYPE_SCALE;
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
Bool
|
|
RHDCrtcsInit(RHDPtr rhdPtr)
|
|
{
|
|
struct rhdCrtc *Crtc;
|
|
enum rhdCrtcScaleType ScaleType;
|
|
Bool useAtom;
|
|
|
|
RHDFUNC(rhdPtr);
|
|
|
|
useAtom = RHDUseAtom(rhdPtr, NULL, atomUsageCrtc);
|
|
|
|
ScaleType = rhdInitScaleType(rhdPtr);
|
|
|
|
Crtc = xnfcalloc(sizeof(struct rhdCrtc), 1);
|
|
Crtc->scrnIndex = rhdPtr->scrnIndex;
|
|
Crtc->Name = "CRTC 1";
|
|
Crtc->Id = RHD_CRTC_1;
|
|
|
|
Crtc->ScaleType = ScaleType;
|
|
|
|
if (rhdPtr->ChipSet >= RHD_RV620) {
|
|
Crtc->FMTDestroy = DxFMTDestroy;
|
|
Crtc->FMTSave = DxFMTSave;
|
|
Crtc->FMTRestore = DxFMTRestore;
|
|
Crtc->FMTModeSet = DxFMTSet;
|
|
}
|
|
Crtc->FMTPriv = NULL;
|
|
|
|
Crtc->FBValid = DxFBValid;
|
|
Crtc->FBSet = DxFBSet;
|
|
Crtc->FBSave = DxFBSave;
|
|
Crtc->FBRestore = DxFBRestore;
|
|
Crtc->FBDestroy = DxFBDestroy;
|
|
|
|
Crtc->ModeValid = DxModeValid;
|
|
Crtc->ModeSet = DxModeSet;
|
|
Crtc->ModeSave = DxModeSave;
|
|
Crtc->ModeRestore = DxModeRestore;
|
|
Crtc->ModeDestroy = DxModeDestroy;
|
|
Crtc->ModePriv = NULL;
|
|
|
|
Crtc->ScaleValid = DxScaleValid;
|
|
Crtc->ScaleSet = DxScaleSet;
|
|
Crtc->ScaleSave = DxScaleSave;
|
|
Crtc->ScaleRestore = DxScaleRestore;
|
|
Crtc->ScaleDestroy = DxScaleDestroy;
|
|
Crtc->ScalePriv = NULL;
|
|
|
|
Crtc->LUTSelect = D1LUTSelect;
|
|
Crtc->LUTSave = DxLUTSave;
|
|
Crtc->LUTRestore = DxLUTRestore;
|
|
Crtc->LUTDestroy = DxLUTDestroy;
|
|
Crtc->LUTPriv = NULL;
|
|
|
|
Crtc->FrameSet = D1ViewPortStart;
|
|
|
|
Crtc->Power = D1Power;
|
|
Crtc->Blank = D1Blank;
|
|
|
|
rhdPtr->Crtc[0] = Crtc;
|
|
|
|
Crtc = xnfcalloc(sizeof(struct rhdCrtc), 1);
|
|
Crtc->scrnIndex = rhdPtr->scrnIndex;
|
|
Crtc->Name = "CRTC 2";
|
|
Crtc->Id = RHD_CRTC_2;
|
|
|
|
Crtc->ScaleType = ScaleType;
|
|
|
|
if (rhdPtr->ChipSet >= RHD_RV620) {
|
|
Crtc->FMTDestroy = DxFMTDestroy;
|
|
Crtc->FMTSave = DxFMTSave;
|
|
Crtc->FMTRestore = DxFMTRestore;
|
|
Crtc->FMTModeSet = DxFMTSet;
|
|
}
|
|
Crtc->FMTPriv = NULL;
|
|
|
|
Crtc->FBValid = DxFBValid;
|
|
Crtc->FBSet = DxFBSet;
|
|
Crtc->FBSave = DxFBSave;
|
|
Crtc->FBRestore = DxFBRestore;
|
|
Crtc->FBDestroy = DxFBDestroy;
|
|
|
|
Crtc->ModeValid = DxModeValid;
|
|
Crtc->ModeSet = DxModeSet;
|
|
Crtc->ModeSave = DxModeSave;
|
|
Crtc->ModeRestore = DxModeRestore;
|
|
Crtc->ModeDestroy = DxModeDestroy;
|
|
Crtc->ModePriv = NULL;
|
|
|
|
Crtc->ScaleValid = DxScaleValid;
|
|
Crtc->ScaleSet = DxScaleSet;
|
|
Crtc->ScaleSave = DxScaleSave;
|
|
Crtc->ScaleRestore = DxScaleRestore;
|
|
Crtc->ScaleDestroy = DxScaleDestroy;
|
|
Crtc->ScalePriv = NULL;
|
|
|
|
Crtc->LUTSelect = D2LUTSelect;
|
|
Crtc->LUTSave = DxLUTSave;
|
|
Crtc->LUTRestore = DxLUTRestore;
|
|
Crtc->LUTDestroy = DxLUTDestroy;
|
|
Crtc->LUTPriv = NULL;
|
|
|
|
Crtc->FrameSet = D2ViewPortStart;
|
|
|
|
Crtc->Power = D2Power;
|
|
Crtc->Blank = D2Blank;
|
|
|
|
rhdPtr->Crtc[1] = Crtc;
|
|
|
|
return !useAtom;
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
void
|
|
RHDCrtcsDestroy(RHDPtr rhdPtr)
|
|
{
|
|
struct rhdCrtc *Crtc;
|
|
int i;
|
|
|
|
RHDFUNC(rhdPtr);
|
|
|
|
for (i = 0; i < 2; i++) {
|
|
Crtc = rhdPtr->Crtc[i];
|
|
if (Crtc) {
|
|
if (Crtc->FMTDestroy)
|
|
Crtc->FMTDestroy(Crtc);
|
|
|
|
if (Crtc->LUTDestroy)
|
|
Crtc->LUTDestroy(Crtc);
|
|
|
|
if (Crtc->FBDestroy)
|
|
Crtc->FBDestroy(Crtc);
|
|
|
|
if (Crtc->ScaleDestroy)
|
|
Crtc->ScaleDestroy(Crtc);
|
|
|
|
if (Crtc->ModeDestroy)
|
|
Crtc->ModeDestroy(Crtc);
|
|
|
|
xfree(Crtc);
|
|
rhdPtr->Crtc[i] = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
*/
|
|
void
|
|
RHDCrtcSave(struct rhdCrtc *Crtc)
|
|
{
|
|
RHDDebug(Crtc->scrnIndex, "%s: %s\n", __func__, Crtc->Name);
|
|
|
|
if (Crtc->FMTSave)
|
|
Crtc->FMTSave(Crtc);
|
|
|
|
if (Crtc->FBSave)
|
|
Crtc->FBSave(Crtc);
|
|
|
|
if (Crtc->LUTSave)
|
|
Crtc->LUTSave(Crtc);
|
|
|
|
if (Crtc->ScaleSave)
|
|
Crtc->ScaleSave(Crtc);
|
|
|
|
if (Crtc->ModeSave)
|
|
Crtc->ModeSave(Crtc);
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
void
|
|
RHDCrtcRestore(struct rhdCrtc *Crtc)
|
|
{
|
|
|
|
RHDDebug(Crtc->scrnIndex, "%s: %s\n", __func__, Crtc->Name);
|
|
|
|
if (Crtc->FMTRestore)
|
|
Crtc->FMTRestore(Crtc);
|
|
|
|
if (Crtc->FBRestore)
|
|
Crtc->FBRestore(Crtc);
|
|
|
|
if (Crtc->LUTRestore)
|
|
Crtc->LUTRestore(Crtc);
|
|
|
|
if (Crtc->ScaleRestore)
|
|
Crtc->ScaleRestore(Crtc);
|
|
|
|
if (Crtc->ModeRestore)
|
|
Crtc->ModeRestore(Crtc);
|
|
}
|