mirror of
https://github.com/X11Libre/xf86-video-cirrus.git
synced 2026-03-24 01:24:45 +00:00
xnfcalloc is just an alias for XNFcallocarray() that doesn't seem to serve any practical purpose, so it can go away once all drivers stopped using it. Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net> Part-of: <https://gitlab.freedesktop.org/xorg/driver/xf86-video-cirrus/-/merge_requests/5>
2262 lines
59 KiB
C
2262 lines
59 KiB
C
/*
|
|
* Driver for CL-GD546x -- The Laguna family
|
|
*
|
|
* lg_driver.c
|
|
*
|
|
* (c) 1998 Corin Anderson.
|
|
* corina@the4cs.com
|
|
* Tukwila, WA
|
|
*
|
|
* This driver is derived from the cir_driver.c module.
|
|
* Original authors and contributors list include:
|
|
* Radoslaw Kapitan, Andrew Vanderstock, Dirk Hohndel,
|
|
* David Dawes, Andrew E. Mileski, Leonard N. Zubkoff,
|
|
* Guy DESBIEF, Itai Nahshon.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#define EXPERIMENTAL
|
|
|
|
/*
|
|
* All drivers should typically include these.
|
|
*/
|
|
#include "xf86.h"
|
|
#include "xf86_OSproc.h"
|
|
|
|
/*
|
|
* All drivers need this.
|
|
*/
|
|
|
|
#include "compiler.h"
|
|
|
|
/*
|
|
* Drivers that need to access the PCI config space directly need
|
|
* this.
|
|
*/
|
|
#include "xf86Pci.h"
|
|
|
|
/*
|
|
* All drivers using the vgahw module need this. This driver needs
|
|
* to be modified to not use vgaHW for multihead operation.
|
|
*/
|
|
#include "vgaHW.h"
|
|
|
|
#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 6
|
|
#include "xf86RAC.h"
|
|
#include "xf86Resources.h"
|
|
#endif
|
|
|
|
/*
|
|
* All drivers initialising the SW cursor need this.
|
|
*/
|
|
#include "mipointer.h"
|
|
|
|
/*
|
|
* Need this for inputInfo.
|
|
*/
|
|
#include "inputstr.h"
|
|
|
|
#include "micmap.h"
|
|
|
|
/*
|
|
* Needed by the shadowfb.
|
|
*/
|
|
#include "shadowfb.h"
|
|
|
|
#include "xf86int10.h"
|
|
|
|
#include "fb.h"
|
|
|
|
#include "xf86DDC.h"
|
|
|
|
#undef LG_DEBUG
|
|
|
|
#include "cir.h"
|
|
#define _LG_PRIVATE_
|
|
#include "lg.h"
|
|
|
|
#include "xf86xv.h"
|
|
#include <X11/extensions/Xv.h>
|
|
|
|
/*
|
|
* Forward definitions for the functions that make up the driver.
|
|
*/
|
|
|
|
/*
|
|
* Mandatory functions
|
|
*/
|
|
Bool LgPreInit(ScrnInfoPtr pScrn, int flags);
|
|
Bool LgScreenInit(SCREEN_INIT_ARGS_DECL);
|
|
Bool LgEnterVT(VT_FUNC_ARGS_DECL);
|
|
void LgLeaveVT(VT_FUNC_ARGS_DECL);
|
|
static Bool LgCloseScreen(CLOSE_SCREEN_ARGS_DECL);
|
|
static Bool LgSaveScreen(ScreenPtr pScreen, Bool mode);
|
|
|
|
/*
|
|
* Required if the driver supports mode switching.
|
|
*/
|
|
Bool LgSwitchMode(SWITCH_MODE_ARGS_DECL);
|
|
/*
|
|
* Required if the driver supports moving the viewport.
|
|
*/
|
|
void LgAdjustFrame(ADJUST_FRAME_ARGS_DECL);
|
|
|
|
/*
|
|
* Optional functions
|
|
*/
|
|
void LgFreeScreen(FREE_SCREEN_ARGS_DECL);
|
|
ModeStatus LgValidMode(SCRN_ARG_TYPE arg, DisplayModePtr mode,
|
|
Bool verbose, int flags);
|
|
|
|
/*
|
|
* Internal functions
|
|
*/
|
|
static void LgRestoreLgRegs(ScrnInfoPtr pScrn, LgRegPtr lgReg);
|
|
static int LgFindLineData(int displayWidth, int bpp);
|
|
static CARD16 LgSetClock(CirPtr pCir, vgaHWPtr hwp, int freq);
|
|
static void lg_vgaHWSetMmioFunc(vgaHWPtr hwp, CARD8 *base);
|
|
|
|
static void LgDisplayPowerManagementSet(ScrnInfoPtr pScrn,
|
|
int PowerManagementMode,
|
|
int flags);
|
|
|
|
/*
|
|
* This is intentionally screen-independent. It indicates the binding
|
|
* choice made in the first PreInit.
|
|
*/
|
|
static int pix24bpp = 0;
|
|
|
|
/*
|
|
* This contains the functions needed by the server after loading the
|
|
* driver module. It must be supplied, and gets added the driver list
|
|
* by the Module Setup function in the dynamic case. In the static
|
|
* case a reference to this is compiled in, and this requires that the
|
|
* name of this DriverRec be an upper-case version of the driver name.
|
|
*/
|
|
|
|
typedef enum {
|
|
OPTION_HW_CURSOR,
|
|
OPTION_PCI_RETRY,
|
|
OPTION_ROTATE,
|
|
OPTION_SHADOW_FB,
|
|
OPTION_NOACCEL
|
|
} LgOpts;
|
|
|
|
static const OptionInfoRec LgOptions[] = {
|
|
{ OPTION_HW_CURSOR, "HWcursor", OPTV_BOOLEAN, {0}, FALSE },
|
|
{ OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN, {0}, FALSE },
|
|
{ OPTION_SHADOW_FB, "ShadowFB", OPTV_BOOLEAN, {0}, FALSE },
|
|
{ OPTION_ROTATE, "Rotate", OPTV_ANYSTR, {0}, FALSE },
|
|
/*
|
|
* fifo_conservative/aggressive; fast/med/slow_dram; ...
|
|
*/
|
|
{ -1, NULL, OPTV_NONE, {0}, FALSE }
|
|
};
|
|
|
|
/*
|
|
* 1/4 bpp 8 bpp 15/16 bpp 24 bpp 32 bpp
|
|
*/
|
|
static int gd5462_MaxClocks[] =
|
|
{ 170000, 170000, 135100, 135100, 85500 };
|
|
static int gd5464_MaxClocks[] =
|
|
{ 170000, 250000, 170000, 170000, 135100 };
|
|
static int gd5465_MaxClocks[] =
|
|
{ 170000, 250000, 170000, 170000, 135100 };
|
|
|
|
/*
|
|
* We're rather use skinny tiles, so put all of them at the head of
|
|
* the table.
|
|
*/
|
|
LgLineDataRec LgLineData[] = {
|
|
{ 5, 640, 0},
|
|
{ 8, 1024, 0},
|
|
{10, 1280, 0},
|
|
{13, 1664, 0},
|
|
{16, 2048, 0},
|
|
{20, 2560, 0},
|
|
{10, 2560, 1},
|
|
{26, 3328, 0},
|
|
{ 5, 1280, 1},
|
|
{ 8, 2048, 1},
|
|
{13, 3328, 1},
|
|
{16, 4096, 1},
|
|
{20, 5120, 1},
|
|
{26, 6656, 1},
|
|
/*
|
|
* Sentinel to indicate end of table.
|
|
*/
|
|
{-1, -1, -1}
|
|
};
|
|
|
|
static int LgLinePitches[4][11] = {
|
|
/*
|
|
* 8 bpp
|
|
*/
|
|
{ 640, 1024, 1280, 1664, 2048, 2560, 3328, 4096, 5120, 6656, 0 },
|
|
/*
|
|
* 16 bpp
|
|
*/
|
|
{ 320, 512, 640, 832, 1024, 1280, 1664, 2048, 2560, 3328, 0 },
|
|
/*
|
|
* 24 bpp
|
|
*/
|
|
{ 213, 341, 426, 554, 682, 853, 1109, 1365, 1706, 2218, 0 },
|
|
/*
|
|
* 32 bpp
|
|
*/
|
|
{ 160, 256, 320, 416, 512, 640, 832, 1024, 1280, 1664, 0 }
|
|
};
|
|
|
|
#ifdef XFree86LOADER
|
|
|
|
#define LG_MAJOR_VERSION 1
|
|
#define LG_MINOR_VERSION 0
|
|
#define LG_PATCHLEVEL 0
|
|
|
|
static XF86ModuleVersionInfo lgVersRec =
|
|
{
|
|
"cirrus_laguna",
|
|
MODULEVENDORSTRING,
|
|
MODINFOSTRING1,
|
|
MODINFOSTRING2,
|
|
XORG_VERSION_CURRENT,
|
|
LG_MAJOR_VERSION, LG_MINOR_VERSION, LG_PATCHLEVEL,
|
|
/*
|
|
* This is a video driver.
|
|
*/
|
|
ABI_CLASS_VIDEODRV,
|
|
ABI_VIDEODRV_VERSION,
|
|
MOD_CLASS_NONE,
|
|
{0,0,0,0}
|
|
};
|
|
|
|
/*
|
|
* This is the module init data.
|
|
* Its name has to be the driver name followed by ModuleData.
|
|
*/
|
|
_X_EXPORT XF86ModuleData cirrus_lagunaModuleData = {
|
|
&lgVersRec,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
#endif /* XFree86LOADER */
|
|
|
|
_X_EXPORT const OptionInfoRec *
|
|
LgAvailableOptions(int chipid) {
|
|
return LgOptions;
|
|
}
|
|
|
|
_X_EXPORT ScrnInfoPtr
|
|
LgProbe(int entity)
|
|
{
|
|
ScrnInfoPtr pScrn = NULL;
|
|
if ((pScrn = xf86ConfigPciEntity(pScrn, 0, entity,
|
|
CIRPciChipsets,
|
|
NULL, NULL, NULL,
|
|
NULL, NULL))) {
|
|
pScrn->PreInit = LgPreInit;
|
|
pScrn->ScreenInit = LgScreenInit;
|
|
pScrn->SwitchMode = LgSwitchMode;
|
|
pScrn->AdjustFrame = LgAdjustFrame;
|
|
pScrn->EnterVT = LgEnterVT;
|
|
pScrn->LeaveVT = LgLeaveVT;
|
|
pScrn->FreeScreen = LgFreeScreen;
|
|
pScrn->ValidMode = LgValidMode;
|
|
}
|
|
return pScrn;
|
|
}
|
|
|
|
static Bool
|
|
LgGetRec(ScrnInfoPtr pScrn)
|
|
{
|
|
CirPtr pCir;
|
|
|
|
if (pScrn->driverPrivate != NULL)
|
|
return TRUE;
|
|
|
|
pScrn->driverPrivate = XNFcallocarray(sizeof(CirRec), 1);
|
|
((CirPtr) pScrn->driverPrivate)->chip.lg =
|
|
XNFcallocarray(sizeof(LgRec), 1);
|
|
|
|
/*
|
|
* Initialize it.
|
|
*/
|
|
pCir = CIRPTR(pScrn);
|
|
pCir->chip.lg->oldBitmask = 0x00000000;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
LgFreeRec(ScrnInfoPtr pScrn)
|
|
{
|
|
if (pScrn->driverPrivate == NULL)
|
|
return;
|
|
free(pScrn->driverPrivate);
|
|
pScrn->driverPrivate = NULL;
|
|
}
|
|
|
|
/*
|
|
* LgCountRAM --
|
|
*
|
|
* Counts amount of installed RAM
|
|
*/
|
|
/*
|
|
* XXX We need to get rid of this PIO (MArk)
|
|
*/
|
|
static int
|
|
LgCountRam(ScrnInfoPtr pScrn)
|
|
{
|
|
vgaHWPtr hwp = VGAHWPTR(pScrn);
|
|
CARD8 SR14;
|
|
|
|
vgaHWProtect(pScrn, TRUE);
|
|
|
|
/*
|
|
* The ROM BIOS scratch pad registers contain, among other things,
|
|
* the amount of installed RDRAM for the Laguna chip.
|
|
*/
|
|
SR14 = hwp->readSeq(hwp, 0x14);
|
|
|
|
ErrorF("Scratch Pads: 0:%02x 1:%02x 2:%02x 3:%02x\n",
|
|
hwp->readSeq(hwp, 9),
|
|
hwp->readSeq(hwp, 10),
|
|
SR14,
|
|
hwp->readSeq(hwp, 0x15));
|
|
|
|
vgaHWProtect(pScrn, FALSE);
|
|
|
|
return 1024 * ((SR14 & 0x7) + 1);
|
|
|
|
/*
|
|
* !!! This function seems to be incorrect...
|
|
*/
|
|
}
|
|
|
|
static xf86MonPtr
|
|
LgDoDDC(ScrnInfoPtr pScrn)
|
|
{
|
|
CirPtr pCir = CIRPTR(pScrn);
|
|
xf86MonPtr MonInfo = NULL;
|
|
|
|
/*
|
|
* Map the CIR memory and MMIO areas.
|
|
*/
|
|
if (!CirMapMem(pCir, pScrn->scrnIndex))
|
|
return FALSE;
|
|
|
|
if (!LgI2CInit(pScrn)) {
|
|
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
|
"I2C initialization failed\n");
|
|
goto unmap_out;
|
|
}
|
|
|
|
/*
|
|
* Read and output monitor info using DDC2 over I2C bus.
|
|
*/
|
|
MonInfo = xf86DoEDID_DDC2(XF86_SCRN_ARG(pScrn), pCir->I2CPtr1);
|
|
if (!MonInfo) {
|
|
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
|
"Failed to obtain EDID.\n");
|
|
goto unmap_out;
|
|
}
|
|
|
|
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
|
|
"I2C Monitor info: %p\n", (void *)MonInfo);
|
|
xf86PrintEDID(MonInfo);
|
|
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
|
|
"end of I2C Monitor info\n\n");
|
|
|
|
xf86SetDDCproperties(pScrn, MonInfo);
|
|
|
|
unmap_out:
|
|
CirUnmapMem(pCir, pScrn->scrnIndex);
|
|
|
|
return MonInfo;
|
|
}
|
|
|
|
/*
|
|
* Mandatory
|
|
*/
|
|
Bool
|
|
LgPreInit(ScrnInfoPtr pScrn, int flags)
|
|
{
|
|
CirPtr pCir;
|
|
vgaHWPtr hwp;
|
|
MessageType from;
|
|
int i;
|
|
ClockRangePtr clockRanges;
|
|
int fbPCIReg, ioPCIReg;
|
|
const char *s;
|
|
|
|
if (flags & PROBE_DETECT) {
|
|
cirProbeDDC(pScrn,
|
|
xf86GetEntityInfo(pScrn->entityList[0])->index);
|
|
return TRUE;
|
|
}
|
|
|
|
#ifdef LG_DEBUG
|
|
ErrorF("LgPreInit\n");
|
|
#endif
|
|
|
|
/*
|
|
* Check the number of entities, and fail if it isn't one.
|
|
*/
|
|
if (pScrn->numEntities != 1)
|
|
return FALSE;
|
|
|
|
/*
|
|
* The vgahw module should be loaded here when needed.
|
|
*/
|
|
if (!xf86LoadSubModule(pScrn, "vgahw"))
|
|
return FALSE;
|
|
|
|
/*
|
|
* Allocate a vgaHWRec.
|
|
*/
|
|
if (!vgaHWGetHWRec(pScrn))
|
|
return FALSE;
|
|
|
|
hwp = VGAHWPTR(pScrn);
|
|
vgaHWSetStdFuncs(hwp);
|
|
vgaHWGetIOBase(hwp);
|
|
|
|
/*
|
|
* Allocate the LgRec driverPrivate.
|
|
*/
|
|
if (!LgGetRec(pScrn))
|
|
return FALSE;
|
|
|
|
pCir = CIRPTR(pScrn);
|
|
pCir->pScrn = pScrn;
|
|
|
|
#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 12
|
|
pCir->PIOReg = hwp->PIOOffset + 0x3CE;
|
|
#else
|
|
pCir->PIOReg = 0x3CE;
|
|
#endif
|
|
|
|
/*
|
|
* Get the entity, and make sure it is PCI.
|
|
*/
|
|
pCir->pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
|
|
if (pCir->pEnt->location.type != BUS_PCI)
|
|
return FALSE;
|
|
pCir->Chipset = pCir->pEnt->chipset;
|
|
|
|
/*
|
|
* Find the PCI info for this screen.
|
|
*/
|
|
pCir->PciInfo = xf86GetPciInfoForEntity(pCir->pEnt->index);
|
|
#ifndef XSERVER_LIBPCIACCESS
|
|
pCir->PciTag = pciTag(PCI_DEV_BUS(pCir->PciInfo),
|
|
PCI_DEV_DEV(pCir->PciInfo), PCI_DEV_FUNC(pCir->PciInfo));
|
|
#endif
|
|
|
|
if (xf86LoadSubModule(pScrn, "int10")) {
|
|
xf86Int10InfoPtr int10InfoPtr;
|
|
|
|
int10InfoPtr = xf86InitInt10(pCir->pEnt->index);
|
|
|
|
if (int10InfoPtr)
|
|
xf86FreeInt10(int10InfoPtr);
|
|
}
|
|
|
|
/*
|
|
* Set pScrn->monitor.
|
|
*/
|
|
pScrn->monitor = pScrn->confScreen->monitor;
|
|
|
|
/*
|
|
* The first thing we should figure out is the depth, bpp, etc.
|
|
* We support both 24 bpp and 32 bpp layouts, so indicate that.
|
|
*/
|
|
if (!xf86SetDepthBpp(pScrn, 0, 0, 0, Support24bppFb |
|
|
Support32bppFb |
|
|
SupportConvert32to24 |
|
|
PreferConvert32to24)) {
|
|
return FALSE;
|
|
}
|
|
/*
|
|
* Check that the returned depth is one we support.
|
|
*/
|
|
switch (pScrn->depth) {
|
|
case 8:
|
|
case 15:
|
|
case 16:
|
|
case 24:
|
|
case 32:
|
|
/*
|
|
* OK
|
|
*/
|
|
break;
|
|
default:
|
|
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
|
"Given depth (%d) is not supported by this "
|
|
"driver\n", pScrn->depth);
|
|
return FALSE;
|
|
}
|
|
xf86PrintDepthBpp(pScrn);
|
|
|
|
/*
|
|
* Get the depth24 pixmap format.
|
|
*/
|
|
if (pScrn->depth == 24 && pix24bpp == 0)
|
|
pix24bpp = xf86GetBppFromDepth(pScrn, 24);
|
|
|
|
/*
|
|
* This must happen after pScrn->display has been set because
|
|
* xf86SetWeight references it.
|
|
*/
|
|
if (pScrn->depth > 8) {
|
|
/*
|
|
* The defaults are OK for us.
|
|
*/
|
|
rgb zeros = { 0, 0, 0 };
|
|
|
|
/*
|
|
* !!! I think we can force 5-6-5 weight for 16bpp here for
|
|
* the 5462.
|
|
*/
|
|
|
|
if (!xf86SetWeight(pScrn, zeros, zeros)) {
|
|
return FALSE;
|
|
} else {
|
|
/*
|
|
* XXX Check that weight returned is supported.
|
|
*/
|
|
;
|
|
}
|
|
}
|
|
|
|
if (!xf86SetDefaultVisual(pScrn, -1))
|
|
return FALSE;
|
|
|
|
/*
|
|
* Collect all of the relevant option flags (fill in
|
|
* pScrn->options).
|
|
*/
|
|
xf86CollectOptions(pScrn, NULL);
|
|
|
|
/*
|
|
* Process the options.
|
|
*/
|
|
if (!(pCir->Options = malloc(sizeof(LgOptions))))
|
|
return FALSE;
|
|
memcpy(pCir->Options, LgOptions, sizeof(LgOptions));
|
|
xf86ProcessOptions(pScrn->scrnIndex,
|
|
pScrn->options,
|
|
pCir->Options);
|
|
|
|
pScrn->rgbBits = 6;
|
|
from = X_DEFAULT;
|
|
pCir->HWCursor = FALSE;
|
|
if (xf86GetOptValBool(pCir->Options, OPTION_HW_CURSOR,
|
|
&pCir->HWCursor))
|
|
from = X_CONFIG;
|
|
|
|
xf86DrvMsg(pScrn->scrnIndex, from, "Using %s cursor\n",
|
|
pCir->HWCursor ? "HW" : "SW");
|
|
if (xf86ReturnOptValBool(pCir->Options, OPTION_NOACCEL, FALSE)) {
|
|
pCir->NoAccel = TRUE;
|
|
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
|
|
"Acceleration disabled\n");
|
|
}
|
|
if (pScrn->bitsPerPixel < 8) {
|
|
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
|
"Cannot use in less than 8 bpp\n");
|
|
return FALSE;
|
|
}
|
|
/*
|
|
* Set the ChipRev, allowing config file entries to override.
|
|
*/
|
|
if (pCir->pEnt->device->chipRev >= 0) {
|
|
pCir->ChipRev = pCir->pEnt->device->chipRev;
|
|
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
|
|
"ChipRev override: %d\n", pCir->ChipRev);
|
|
} else {
|
|
pCir->ChipRev = PCI_DEV_REVISION(pCir->PciInfo);
|
|
}
|
|
|
|
/*
|
|
* Cirrus Logic swapped the FB and IO registers in the 5465
|
|
* (by design).
|
|
*/
|
|
if (PCI_CHIP_GD5465 == pCir->Chipset) {
|
|
fbPCIReg = 0;
|
|
ioPCIReg = 1;
|
|
} else {
|
|
fbPCIReg = 1;
|
|
ioPCIReg = 0;
|
|
}
|
|
|
|
/*
|
|
* Find the frame buffer base address.
|
|
*/
|
|
if (pCir->pEnt->device->MemBase != 0) {
|
|
/*
|
|
* Require that the config file value matches one of the PCI
|
|
* values.
|
|
*/
|
|
if (!xf86CheckPciMemBase(pCir->PciInfo,
|
|
pCir->pEnt->device->MemBase)) {
|
|
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
|
"MemBase 0x%08lX doesn't match any PCI base "
|
|
"register.\n",
|
|
pCir->pEnt->device->MemBase);
|
|
return FALSE;
|
|
}
|
|
pCir->FbAddress = pCir->pEnt->device->MemBase;
|
|
from = X_CONFIG;
|
|
} else {
|
|
if (PCI_REGION_BASE(pCir->PciInfo,
|
|
fbPCIReg,
|
|
REGION_MEM) != 0) {
|
|
pCir->FbAddress = PCI_REGION_BASE(pCir->PciInfo,
|
|
fbPCIReg,
|
|
REGION_MEM) &
|
|
0xff000000;
|
|
from = X_PROBED;
|
|
} else {
|
|
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
|
"No valid FB address in PCI config space\n");
|
|
LgFreeRec(pScrn);
|
|
return FALSE;
|
|
}
|
|
}
|
|
xf86DrvMsg(pScrn->scrnIndex, from,
|
|
"Linear framebuffer at 0x%lX\n",
|
|
(unsigned long) pCir->FbAddress);
|
|
|
|
/*
|
|
* Find the MMIO base address.
|
|
*/
|
|
if (pCir->pEnt->device->IOBase != 0) {
|
|
/*
|
|
* Require that the config file value matches one of the PCI
|
|
* values.
|
|
*/
|
|
if (!xf86CheckPciMemBase(pCir->PciInfo,
|
|
pCir->pEnt->device->IOBase)) {
|
|
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
|
"IOBase 0x%08lX doesn't match any PCI base "
|
|
"register.\n",
|
|
pCir->pEnt->device->IOBase);
|
|
return FALSE;
|
|
}
|
|
pCir->IOAddress = pCir->pEnt->device->IOBase;
|
|
from = X_CONFIG;
|
|
} else {
|
|
if (PCI_REGION_BASE(pCir->PciInfo,
|
|
ioPCIReg,
|
|
REGION_MEM) != 0) {
|
|
pCir->IOAddress = PCI_REGION_BASE(pCir->PciInfo,
|
|
ioPCIReg,
|
|
REGION_MEM) &
|
|
0xfffff000;
|
|
from = X_PROBED;
|
|
} else {
|
|
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
|
"No valid MMIO address in PCI config "
|
|
"space\n");
|
|
}
|
|
}
|
|
xf86DrvMsg(pScrn->scrnIndex, from,
|
|
"MMIO registers at 0x%lX\n",
|
|
(unsigned long) pCir->IOAddress);
|
|
|
|
/*
|
|
* If the user has specified the amount of memory in the
|
|
* XF86Config file, we respect that setting.
|
|
*/
|
|
if (pCir->pEnt->device->videoRam != 0) {
|
|
pScrn->videoRam = pCir->pEnt->device->videoRam;
|
|
from = X_CONFIG;
|
|
} else {
|
|
pScrn->videoRam = LgCountRam(pScrn);
|
|
from = X_PROBED;
|
|
}
|
|
if (2048 == pScrn->videoRam) {
|
|
/*
|
|
* Two-way interleaving
|
|
*/
|
|
pCir->chip.lg->memInterleave = 0x40;
|
|
} else if (4096 == pScrn->videoRam || 8192 == pScrn->videoRam) {
|
|
/*
|
|
* Four-way interleaving
|
|
*/
|
|
pCir->chip.lg->memInterleave = 0x80;
|
|
} else {
|
|
/*
|
|
* One-way interleaving
|
|
*/
|
|
pCir->chip.lg->memInterleave = 0x00;
|
|
}
|
|
|
|
xf86DrvMsg(pScrn->scrnIndex, from,
|
|
"VideoRAM: %d kByte\n", pScrn->videoRam);
|
|
|
|
pCir->FbMapSize = pScrn->videoRam * 1024;
|
|
/*
|
|
* 16K for moment, will increase.
|
|
*/
|
|
pCir->IoMapSize = 0x4000;
|
|
|
|
#ifndef XSERVER_LIBPCIACCESS
|
|
pScrn->racIoFlags = RAC_COLORMAP
|
|
#ifndef EXPERIMENTAL
|
|
| RAC_VIEWPORT
|
|
#endif
|
|
;
|
|
xf86SetOperatingState(resVgaMem, pCir->pEnt->index, ResUnusedOpr);
|
|
|
|
/*
|
|
* Register the PCI-assigned resources.
|
|
*/
|
|
if (xf86RegisterResources(pCir->pEnt->index, NULL, ResExclusive)) {
|
|
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
|
"xf86RegisterResources() found resource "
|
|
"conflicts\n");
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
if (!xf86LoadSubModule(pScrn, "ddc")) {
|
|
LgFreeRec(pScrn);
|
|
return FALSE;
|
|
}
|
|
|
|
#if LGuseI2C
|
|
if (!xf86LoadSubModule(pScrn, "i2c")) {
|
|
LgFreeRec(pScrn);
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Read and print the monitor DDC information.
|
|
*/
|
|
pScrn->monitor->DDC = LgDoDDC(pScrn);
|
|
|
|
/*
|
|
* The gamma fields must be initialised when using the new cmap
|
|
* code.
|
|
*/
|
|
if (pScrn->depth > 1) {
|
|
Gamma zeros = { 0.0, 0.0, 0.0 };
|
|
|
|
if (!xf86SetGamma(pScrn, zeros))
|
|
return FALSE;
|
|
}
|
|
if (xf86GetOptValBool(pCir->Options,
|
|
OPTION_SHADOW_FB,
|
|
&pCir->shadowFB))
|
|
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
|
|
"ShadowFB %s.\n",
|
|
pCir->shadowFB ? "enabled" : "disabled");
|
|
|
|
if ((s = xf86GetOptValString(pCir->Options, OPTION_ROTATE))) {
|
|
if (!xf86NameCmp(s, "CW")) {
|
|
/*
|
|
* Acceleration is disabled below for shadowfb.
|
|
*/
|
|
pCir->shadowFB = TRUE;
|
|
pCir->rotate = 1;
|
|
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
|
|
"Rotating screen clockwise - "
|
|
"acceleration disabled\n");
|
|
} else if (!xf86NameCmp(s, "CCW")) {
|
|
pCir->shadowFB = TRUE;
|
|
pCir->rotate = -1;
|
|
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
|
|
"Rotating screen counter clockwise - "
|
|
"acceleration disabled\n");
|
|
} else {
|
|
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
|
|
"\"%s\" is not a valid value for Option "
|
|
"\"Rotate\"\n", s);
|
|
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
|
|
"Valid options are \"CW\" or \"CCW\"\n");
|
|
}
|
|
}
|
|
|
|
if (pCir->shadowFB && !pCir->NoAccel) {
|
|
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
|
|
"HW acceleration not supported with "
|
|
"\"shadowFB\".\n");
|
|
pCir->NoAccel = TRUE;
|
|
}
|
|
|
|
if (pCir->rotate && pCir->HWCursor) {
|
|
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
|
|
"HW cursor not supported with \"rotate\".\n");
|
|
pCir->HWCursor = FALSE;
|
|
}
|
|
|
|
/*
|
|
* We use a programmable clock.
|
|
*/
|
|
pScrn->progClock = TRUE;
|
|
|
|
/*
|
|
* XXX Set HW cursor use.
|
|
*/
|
|
|
|
/*
|
|
* Set the min pixel clock.
|
|
*/
|
|
/*
|
|
* XXX Guess, need to check this.
|
|
*/
|
|
pCir->MinClock = 12000;
|
|
xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT,
|
|
"Min pixel clock is %d MHz\n",
|
|
pCir->MinClock / 1000);
|
|
/*
|
|
* If the user has specified RAMDAC speed in the XF86Config
|
|
* file, we respect that setting.
|
|
*/
|
|
if (pCir->pEnt->device->dacSpeeds[0]) {
|
|
ErrorF("Do not specify a Clocks line for Cirrus chips\n");
|
|
return FALSE;
|
|
} else {
|
|
int speed;
|
|
int *p;
|
|
switch (pCir->Chipset) {
|
|
case PCI_CHIP_GD5462:
|
|
p = gd5462_MaxClocks;
|
|
break;
|
|
case PCI_CHIP_GD5464:
|
|
case PCI_CHIP_GD5464BD:
|
|
p = gd5464_MaxClocks;
|
|
break;
|
|
case PCI_CHIP_GD5465:
|
|
p = gd5465_MaxClocks;
|
|
break;
|
|
default:
|
|
ErrorF("???\n");
|
|
return FALSE;
|
|
}
|
|
switch (pScrn->bitsPerPixel) {
|
|
case 8:
|
|
speed = p[1];
|
|
break;
|
|
case 15:
|
|
case 16:
|
|
speed = p[2];
|
|
break;
|
|
case 24:
|
|
speed = p[3];
|
|
break;
|
|
case 32:
|
|
speed = p[4];
|
|
break;
|
|
default:
|
|
/*
|
|
* Should not get here.
|
|
*/
|
|
speed = 0;
|
|
break;
|
|
}
|
|
pCir->MaxClock = speed;
|
|
from = X_PROBED;
|
|
}
|
|
xf86DrvMsg(pScrn->scrnIndex, from, "Max pixel clock is %d MHz\n",
|
|
pCir->MaxClock / 1000);
|
|
|
|
/*
|
|
* Setup the ClockRanges, which describe what clock ranges are
|
|
* available, and what sort of modes they can be used for.
|
|
*/
|
|
clockRanges = XNFcallocarray(sizeof(ClockRange), 1);
|
|
clockRanges->next = NULL;
|
|
clockRanges->minClock = pCir->MinClock;
|
|
clockRanges->maxClock = pCir->MaxClock;
|
|
/*
|
|
* programmable
|
|
*/
|
|
clockRanges->clockIndex = -1;
|
|
/*
|
|
* XXX Check this.
|
|
*/
|
|
clockRanges->interlaceAllowed = FALSE;
|
|
/*
|
|
* XXX Check this.
|
|
*/
|
|
clockRanges->doubleScanAllowed = FALSE;
|
|
/*
|
|
* XXX Check this.
|
|
*/
|
|
clockRanges->doubleScanAllowed = FALSE;
|
|
/*
|
|
* XXX Check this.
|
|
*/
|
|
clockRanges->doubleScanAllowed = FALSE;
|
|
clockRanges->ClockMulFactor = 1;
|
|
clockRanges->ClockDivFactor = 1;
|
|
clockRanges->PrivFlags = 0;
|
|
|
|
/*
|
|
* Depending upon what sized tiles used, either 128 or 256.
|
|
*/
|
|
/*
|
|
* Aw, heck. Just say 128.
|
|
*/
|
|
pCir->Rounding = 128 >> pCir->BppShift;
|
|
|
|
/*
|
|
* xf86ValidateModes will check that the mode HTotal and VTotal
|
|
* values don't exceed the chipset's limit if pScrn->maxHValue
|
|
* and pScrn->maxVValue are set. Since our CIRValidMode()
|
|
* already takes care of this, we don't worry about setting them
|
|
* here.
|
|
*/
|
|
|
|
i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,
|
|
pScrn->display->modes, clockRanges,
|
|
LgLinePitches[pScrn->bitsPerPixel / 8 - 1],
|
|
0, 0,
|
|
128 * 8, 0,
|
|
/*
|
|
* Any virtual height is allowed.
|
|
*/
|
|
0,
|
|
pScrn->display->virtualX,
|
|
pScrn->display->virtualY,
|
|
pCir->FbMapSize, LOOKUP_BEST_REFRESH);
|
|
|
|
pCir->chip.lg->lineDataIndex =
|
|
LgFindLineData(pScrn->displayWidth,
|
|
pScrn->bitsPerPixel);
|
|
|
|
if (i == -1) {
|
|
LgFreeRec(pScrn);
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Prune the modes marked as invalid.
|
|
*/
|
|
xf86PruneDriverModes(pScrn);
|
|
|
|
if (i == 0 || pScrn->modes == NULL) {
|
|
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
|
"No valid modes found\n");
|
|
LgFreeRec(pScrn);
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Set the CRTC parameters for all of the modes based on the type
|
|
* of mode, and the chipset's interlace requirements. Calling
|
|
* this is required if the mode->Crtc* values are used by the
|
|
* driver and if the driver doesn't provide code to set
|
|
* them. They are not pre-initialised at all.
|
|
*/
|
|
xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V);
|
|
|
|
/*
|
|
* Set the current mode to the first in the list.
|
|
*/
|
|
pScrn->currentMode = pScrn->modes;
|
|
|
|
/*
|
|
* Print the list of modes being used.
|
|
*/
|
|
xf86PrintModes(pScrn);
|
|
|
|
/*
|
|
* Set display resolution.
|
|
*/
|
|
xf86SetDpi(pScrn, 0, 0);
|
|
|
|
/*
|
|
* Load bpp-specific modules.
|
|
*/
|
|
switch (pScrn->bitsPerPixel) {
|
|
case 8:
|
|
case 16:
|
|
case 24:
|
|
case 32:
|
|
if (xf86LoadSubModule(pScrn, "fb") == NULL) {
|
|
LgFreeRec(pScrn);
|
|
return FALSE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Load XAA if needed.
|
|
*/
|
|
if (!pCir->NoAccel) {
|
|
#ifdef HAVE_XAA_H
|
|
if (!xf86LoadSubModule(pScrn, "xaa"))
|
|
#else
|
|
if (1)
|
|
#endif
|
|
{
|
|
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
|
|
"Falling back to shadowfb\n");
|
|
pCir->NoAccel = TRUE;
|
|
pCir->shadowFB = TRUE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Load RAMDAC if needed.
|
|
*/
|
|
if (pCir->HWCursor) {
|
|
if (!xf86LoadSubModule(pScrn, "ramdac")) {
|
|
LgFreeRec(pScrn);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if (pCir->shadowFB) {
|
|
if (!xf86LoadSubModule(pScrn, "shadowfb")) {
|
|
LgFreeRec(pScrn);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* This function saves the video state.
|
|
*/
|
|
static void
|
|
LgSave(ScrnInfoPtr pScrn)
|
|
{
|
|
CirPtr pCir = CIRPTR(pScrn);
|
|
vgaHWPtr hwp = VGAHWPTR(pScrn);
|
|
|
|
#ifdef LG_DEBUG
|
|
ErrorF("LgSave\n");
|
|
#endif
|
|
|
|
vgaHWSave(pScrn, &VGAHWPTR(pScrn)->SavedReg, VGA_SR_ALL);
|
|
|
|
pCir->chip.lg->ModeReg.ExtVga[CR1A] =
|
|
pCir->chip.lg->SavedReg.ExtVga[CR1A] = hwp->readCrtc(hwp, 0x1A);
|
|
pCir->chip.lg->ModeReg.ExtVga[CR1B] =
|
|
pCir->chip.lg->SavedReg.ExtVga[CR1B] = hwp->readCrtc(hwp, 0x1B);
|
|
pCir->chip.lg->ModeReg.ExtVga[CR1D] =
|
|
pCir->chip.lg->SavedReg.ExtVga[CR1D] = hwp->readCrtc(hwp, 0x1D);
|
|
pCir->chip.lg->ModeReg.ExtVga[CR1E] =
|
|
pCir->chip.lg->SavedReg.ExtVga[CR1E] = hwp->readCrtc(hwp, 0x1E);
|
|
pCir->chip.lg->ModeReg.ExtVga[SR07] =
|
|
pCir->chip.lg->SavedReg.ExtVga[SR07] = hwp->readSeq(hwp, 0x07);
|
|
pCir->chip.lg->ModeReg.ExtVga[SR0E] =
|
|
pCir->chip.lg->SavedReg.ExtVga[SR0E] = hwp->readSeq(hwp, 0x0E);
|
|
pCir->chip.lg->ModeReg.ExtVga[SR1E] =
|
|
pCir->chip.lg->SavedReg.ExtVga[SR1E] = hwp->readSeq(hwp, 0x1E);
|
|
|
|
pCir->chip.lg->ModeReg.FORMAT =
|
|
pCir->chip.lg->SavedReg.FORMAT = memrw(0xC0);
|
|
|
|
pCir->chip.lg->ModeReg.VSC =
|
|
pCir->chip.lg->SavedReg.VSC = memrl(0x3FC);
|
|
|
|
pCir->chip.lg->ModeReg.DTTC =
|
|
pCir->chip.lg->SavedReg.DTTC = memrw(0xEA);
|
|
|
|
if (pCir->Chipset == PCI_CHIP_GD5465) {
|
|
pCir->chip.lg->ModeReg.TileCtrl =
|
|
pCir->chip.lg->SavedReg.TileCtrl = memrw(0x2C4);
|
|
}
|
|
|
|
pCir->chip.lg->ModeReg.TILE =
|
|
pCir->chip.lg->SavedReg.TILE = memrb(0x407);
|
|
|
|
if (pCir->Chipset == PCI_CHIP_GD5465)
|
|
pCir->chip.lg->ModeReg.BCLK =
|
|
pCir->chip.lg->SavedReg.BCLK = memrb(0x2C0);
|
|
else
|
|
pCir->chip.lg->ModeReg.BCLK =
|
|
pCir->chip.lg->SavedReg.BCLK = memrb(0x8C);
|
|
|
|
pCir->chip.lg->ModeReg.CONTROL =
|
|
pCir->chip.lg->SavedReg.CONTROL = memrw(0x402);
|
|
|
|
pCir->chip.lg->ModeReg.RIFCtrl =
|
|
pCir->chip.lg->SavedReg.RIFCtrl = memrw(0x200);
|
|
|
|
pCir->chip.lg->ModeReg.RACCtrl =
|
|
pCir->chip.lg->SavedReg.RACCtrl = memrw(0x202);
|
|
}
|
|
|
|
/*
|
|
* Initialise a new mode. This is currently still using the old
|
|
* "initialise struct, restore/write struct to HW" model. That could
|
|
* be changed.
|
|
*/
|
|
static Bool
|
|
LgModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
|
|
{
|
|
vgaHWPtr hwp;
|
|
CirPtr pCir;
|
|
int width;
|
|
Bool VDiv2 = FALSE;
|
|
CARD16 clockData;
|
|
LgLineDataPtr lineData;
|
|
|
|
#ifdef LG_DEBUG
|
|
ErrorF("LgModeInit %d bpp, %d %d %d %d %d %d %d %d %d\n",
|
|
pScrn->bitsPerPixel, mode->Clock,
|
|
mode->HDisplay, mode->HSyncStart,
|
|
mode->HSyncEnd, mode->HTotal,
|
|
mode->VDisplay, mode->VSyncStart,
|
|
mode->VSyncEnd, mode->VTotal);
|
|
|
|
ErrorF("LgModeInit: depth %d bits\n", pScrn->depth);
|
|
#endif
|
|
|
|
pCir = CIRPTR(pScrn);
|
|
hwp = VGAHWPTR(pScrn);
|
|
vgaHWUnlock(hwp);
|
|
|
|
if (mode->VTotal >= 1024 && !(mode->Flags & V_INTERLACE)) {
|
|
/*
|
|
* For non-interlaced vertical timing >= 1024, the vertical
|
|
* timings are divided by 2 and VGA CRTC 0x17 bit 2 is set.
|
|
*/
|
|
if (!mode->CrtcVAdjusted) {
|
|
mode->CrtcVDisplay >>= 1;
|
|
mode->CrtcVSyncStart >>= 1;
|
|
mode->CrtcVSyncEnd >>= 1;
|
|
mode->CrtcVTotal >>= 1;
|
|
mode->CrtcVAdjusted = TRUE;
|
|
}
|
|
VDiv2 = TRUE;
|
|
}
|
|
|
|
/*
|
|
* Initialise the ModeReg values.
|
|
*/
|
|
if (!vgaHWInit(pScrn, mode))
|
|
return FALSE;
|
|
pScrn->vtSema = TRUE;
|
|
|
|
if (VDiv2)
|
|
hwp->ModeReg.CRTC[0x17] |= 0x04;
|
|
|
|
#ifdef LG_DEBUG
|
|
ErrorF("SynthClock = %d\n", mode->SynthClock);
|
|
#endif
|
|
hwp->IOBase = 0x3D0;
|
|
hwp->ModeReg.MiscOutReg |= 0x01;
|
|
/*
|
|
* Mono address
|
|
*/
|
|
#if 0
|
|
hwp->IOBase = 0x3B0;
|
|
hwp->ModeReg.MiscOutReg &= ~0x01;
|
|
#endif
|
|
|
|
/*
|
|
* ??? Should these be both ...End or ...Start, not one of each?
|
|
*/
|
|
pCir->chip.lg->ModeReg.ExtVga[CR1A] =
|
|
(((mode->CrtcVSyncStart + 1) & 0x300) >> 2) |
|
|
(((mode->CrtcHSyncEnd >> 3) & 0xC0) >> 2);
|
|
|
|
width = pScrn->displayWidth * pScrn->bitsPerPixel / 8;
|
|
if (pScrn->bitsPerPixel == 1)
|
|
width <<= 2;
|
|
hwp->ModeReg.CRTC[0x13] = (width + 7) >> 3;
|
|
/*
|
|
* Offset extension (see CR13)
|
|
*/
|
|
pCir->chip.lg->ModeReg.ExtVga[CR1B] &= 0xEF;
|
|
pCir->chip.lg->ModeReg.ExtVga[CR1B] |=
|
|
(((width + 7) >> 3) & 0x100) ? 0x10 : 0x00;
|
|
pCir->chip.lg->ModeReg.ExtVga[CR1B] |= 0x22;
|
|
pCir->chip.lg->ModeReg.ExtVga[CR1D] =
|
|
(((width + 7) >> 3) & 0x200) ? 0x01 : 0x00;
|
|
|
|
/*
|
|
* Set the 28th bit to enable extended modes.
|
|
*/
|
|
pCir->chip.lg->ModeReg.VSC = 0x10000000;
|
|
|
|
/*
|
|
* Overflow register (sure are a lot of overflow bits around...)
|
|
*/
|
|
pCir->chip.lg->ModeReg.ExtVga[CR1E] = 0x00;
|
|
pCir->chip.lg->ModeReg.ExtVga[CR1E] |= (
|
|
(mode->CrtcHTotal >> 3 & 0x0100) ? 1 : 0) << 7;
|
|
pCir->chip.lg->ModeReg.ExtVga[CR1E] |= (
|
|
(mode->CrtcHDisplay >> 3 & 0x0100) ? 1 : 0) << 6;
|
|
pCir->chip.lg->ModeReg.ExtVga[CR1E] |= (
|
|
(mode->CrtcHSyncStart >> 3 & 0x0100) ? 1 : 0) << 5;
|
|
pCir->chip.lg->ModeReg.ExtVga[CR1E] |= (
|
|
(mode->CrtcHSyncStart >> 3 & 0x0100) ? 1 : 0) << 4;
|
|
pCir->chip.lg->ModeReg.ExtVga[CR1E] |=
|
|
((mode->CrtcVTotal & 0x0400) ? 1 : 0) << 3;
|
|
pCir->chip.lg->ModeReg.ExtVga[CR1E] |= (
|
|
(mode->CrtcVDisplay & 0x0400) ? 1 : 0) << 2;
|
|
pCir->chip.lg->ModeReg.ExtVga[CR1E] |= (
|
|
(mode->CrtcVSyncStart & 0x0400) ? 1 : 0) << 1;
|
|
pCir->chip.lg->ModeReg.ExtVga[CR1E] |= (
|
|
(mode->CrtcVSyncStart & 0x0400) ? 1 : 0) << 0;
|
|
|
|
lineData = &LgLineData[pCir->chip.lg->lineDataIndex];
|
|
|
|
pCir->chip.lg->ModeReg.TILE = lineData->tilesPerLine & 0x3F;
|
|
|
|
if (8 == pScrn->bitsPerPixel) {
|
|
pCir->chip.lg->ModeReg.FORMAT = 0x0000;
|
|
|
|
pCir->chip.lg->ModeReg.DTTC =
|
|
(pCir->chip.lg->ModeReg.TILE << 8) |
|
|
0x0080 |
|
|
(lineData->width << 6);
|
|
pCir->chip.lg->ModeReg.CONTROL = 0x0000 |
|
|
(lineData->width << 11);
|
|
|
|
/*
|
|
* There is an optimal FIFO threshold value (lower
|
|
* 5 bits of DTTC) for every resolution and color depth
|
|
* combination. We'll hit the highlights here, and get
|
|
* close for anything that's not covered.
|
|
*/
|
|
if (mode->CrtcHDisplay <= 640) {
|
|
/*
|
|
* BAD numbers: 0x1E
|
|
* GOOD numbers: 0x14
|
|
*/
|
|
pCir->chip.lg->ModeReg.DTTC =
|
|
(pCir->chip.lg->ModeReg.DTTC & 0xFFE0) |
|
|
(0x0014);
|
|
} else if (mode->CrtcHDisplay <= 800) {
|
|
/*
|
|
* BAD numbers: 0x16
|
|
* GOOD numbers: 0x13 0x14
|
|
*/
|
|
pCir->chip.lg->ModeReg.DTTC =
|
|
(pCir->chip.lg->ModeReg.DTTC & 0xFFE0) |
|
|
(0x0014);
|
|
} else if (mode->CrtcHDisplay <= 1024) {
|
|
/*
|
|
* BAD numbers:
|
|
* GOOD numbers: 0x15
|
|
*/
|
|
pCir->chip.lg->ModeReg.DTTC =
|
|
(pCir->chip.lg->ModeReg.DTTC & 0xFFE0) |
|
|
(0x0015);
|
|
} else if (mode->CrtcHDisplay <= 1280) {
|
|
/*
|
|
* BAD numbers:
|
|
* GOOD numbers: 0x16
|
|
*/
|
|
pCir->chip.lg->ModeReg.DTTC =
|
|
(pCir->chip.lg->ModeReg.DTTC & 0xFFE0) |
|
|
(0x0016);
|
|
} else {
|
|
/*
|
|
* BAD numbers:
|
|
* GOOD numbers:
|
|
*/
|
|
pCir->chip.lg->ModeReg.DTTC =
|
|
(pCir->chip.lg->ModeReg.DTTC & 0xFFE0) |
|
|
(0x0017);
|
|
}
|
|
} else if (16 == pScrn->bitsPerPixel) {
|
|
/*
|
|
* !!! Assume 5-6-5 RGB mode (for now...).
|
|
*/
|
|
pCir->chip.lg->ModeReg.FORMAT = 0x1400;
|
|
|
|
if (pScrn->depth == 15)
|
|
pCir->chip.lg->ModeReg.FORMAT = 0x1600;
|
|
|
|
pCir->chip.lg->ModeReg.DTTC =
|
|
(pCir->chip.lg->ModeReg.TILE << 8) |
|
|
0x0080 |
|
|
(lineData->width << 6);
|
|
pCir->chip.lg->ModeReg.CONTROL = 0x2000 |
|
|
(lineData->width << 11);
|
|
|
|
if (mode->CrtcHDisplay <= 640) {
|
|
/*
|
|
* BAD numbers: 0x12
|
|
* GOOD numbers: 0x10
|
|
*/
|
|
pCir->chip.lg->ModeReg.DTTC =
|
|
(pCir->chip.lg->ModeReg.DTTC & 0xFFE0) |
|
|
(0x0010);
|
|
} else if (mode->CrtcHDisplay <= 800) {
|
|
/*
|
|
* BAD numbers: 0x13
|
|
* GOOD numbers: 0x11
|
|
*/
|
|
pCir->chip.lg->ModeReg.DTTC =
|
|
(pCir->chip.lg->ModeReg.DTTC & 0xFFE0) |
|
|
(0x0011);
|
|
} else if (mode->CrtcHDisplay <= 1024) {
|
|
/*
|
|
* BAD numbers: 0x14
|
|
* GOOD numbers: 0x12
|
|
*/
|
|
pCir->chip.lg->ModeReg.DTTC =
|
|
(pCir->chip.lg->ModeReg.DTTC & 0xFFE0) |
|
|
(0x0012);
|
|
} else if (mode->CrtcHDisplay <= 1280) {
|
|
/*
|
|
* BAD numbers: 0x08 0x10
|
|
* Borderline numbers: 0x12
|
|
* GOOD numbers: 0x15
|
|
*/
|
|
pCir->chip.lg->ModeReg.DTTC =
|
|
(pCir->chip.lg->ModeReg.DTTC & 0xFFE0) |
|
|
(0x0015);
|
|
} else {
|
|
pCir->chip.lg->ModeReg.DTTC =
|
|
(pCir->chip.lg->ModeReg.DTTC & 0xFFE0) |
|
|
(0x0017);
|
|
}
|
|
} else if (24 == pScrn->bitsPerPixel) {
|
|
pCir->chip.lg->ModeReg.FORMAT = 0x2400;
|
|
|
|
pCir->chip.lg->ModeReg.DTTC =
|
|
(pCir->chip.lg->ModeReg.TILE << 8) |
|
|
0x0080 |
|
|
(lineData->width << 6);
|
|
pCir->chip.lg->ModeReg.CONTROL = 0x4000 |
|
|
(lineData->width << 11);
|
|
|
|
if (mode->CrtcHDisplay <= 640) {
|
|
/*
|
|
* BAD numbers:
|
|
* GOOD numbers: 0x10
|
|
*/
|
|
pCir->chip.lg->ModeReg.DTTC =
|
|
(pCir->chip.lg->ModeReg.DTTC & 0xFFE0) |
|
|
(0x0010);
|
|
} else if (mode->CrtcHDisplay <= 800) {
|
|
/*
|
|
* BAD numbers:
|
|
* GOOD numbers: 0x11
|
|
*/
|
|
pCir->chip.lg->ModeReg.DTTC =
|
|
(pCir->chip.lg->ModeReg.DTTC & 0xFFE0) |
|
|
(0x0011);
|
|
} else if (mode->CrtcHDisplay <= 1024) {
|
|
/*
|
|
* BAD numbers: 0x12 0x13
|
|
* Borderline numbers: 0x15
|
|
* GOOD numbers: 0x17
|
|
*/
|
|
pCir->chip.lg->ModeReg.DTTC =
|
|
(pCir->chip.lg->ModeReg.DTTC & 0xFFE0) |
|
|
(0x0017);
|
|
} else if (mode->CrtcHDisplay <= 1280) {
|
|
/*
|
|
* BAD numbers:
|
|
* GOOD numbers: 0x1E
|
|
*/
|
|
pCir->chip.lg->ModeReg.DTTC =
|
|
(pCir->chip.lg->ModeReg.DTTC & 0xFFE0) |
|
|
(0x001E);
|
|
} else {
|
|
/*
|
|
* BAD numbers:
|
|
* GOOD numbers:
|
|
*/
|
|
pCir->chip.lg->ModeReg.DTTC =
|
|
(pCir->chip.lg->ModeReg.DTTC & 0xFFE0) |
|
|
(0x0020);
|
|
}
|
|
} else if (32 == pScrn->bitsPerPixel) {
|
|
pCir->chip.lg->ModeReg.FORMAT = 0x3400;
|
|
|
|
pCir->chip.lg->ModeReg.DTTC =
|
|
(pCir->chip.lg->ModeReg.TILE << 8) |
|
|
0x0080 |
|
|
(lineData->width << 6);
|
|
pCir->chip.lg->ModeReg.CONTROL = 0x6000 |
|
|
(lineData->width << 11);
|
|
|
|
if (mode->CrtcHDisplay <= 640) {
|
|
/*
|
|
* GOOD numbers: 0x0E
|
|
* BAD numbers:
|
|
*/
|
|
pCir->chip.lg->ModeReg.DTTC =
|
|
(pCir->chip.lg->ModeReg.DTTC & 0xFFE0) |
|
|
(0x000E);
|
|
} else if (mode->CrtcHDisplay <= 800) {
|
|
/*
|
|
* GOOD numbers: 0x17
|
|
* BAD numbers:
|
|
*/
|
|
pCir->chip.lg->ModeReg.DTTC =
|
|
(pCir->chip.lg->ModeReg.DTTC & 0xFFE0) |
|
|
(0x0017);
|
|
} else if (mode->CrtcHDisplay <= 1024) {
|
|
/*
|
|
* GOOD numbers: 0x1D
|
|
* OKAY numbers: 0x15 0x14 0x16 0x18 0x19
|
|
* BAD numbers: 0x0E 0x12 0x13 0x0D
|
|
*/
|
|
pCir->chip.lg->ModeReg.DTTC =
|
|
(pCir->chip.lg->ModeReg.DTTC & 0xFFE0) |
|
|
(0x001D);
|
|
} else if (mode->CrtcHDisplay <= 1280) {
|
|
/*
|
|
* GOOD numbers:
|
|
* BAD numbers:
|
|
*/
|
|
/*
|
|
* 10
|
|
*/
|
|
pCir->chip.lg->ModeReg.DTTC =
|
|
(pCir->chip.lg->ModeReg.DTTC & 0xFFE0) |
|
|
(0x0022);
|
|
} else {
|
|
pCir->chip.lg->ModeReg.DTTC =
|
|
(pCir->chip.lg->ModeReg.DTTC & 0xFFE0) |
|
|
(0x0024);
|
|
}
|
|
} else {
|
|
/*
|
|
* ??? What could it be? Use some sane numbers.
|
|
*/
|
|
}
|
|
|
|
/*
|
|
* Setup the appropriate memory interleaving.
|
|
*/
|
|
pCir->chip.lg->ModeReg.DTTC |= (pCir->chip.lg->memInterleave << 8);
|
|
pCir->chip.lg->ModeReg.TILE |= pCir->chip.lg->memInterleave & 0xC0;
|
|
|
|
if (PCI_CHIP_GD5465 == pCir->Chipset) {
|
|
/*
|
|
* The tile control information in the DTTC is also mirrored
|
|
* elsewhere.
|
|
*/
|
|
pCir->chip.lg->ModeReg.TileCtrl =
|
|
pCir->chip.lg->ModeReg.DTTC & 0xFFC0;
|
|
|
|
/*
|
|
* The 5465's DTTC records _fetches_ per line, not tiles per
|
|
* line. Fetches are 128-byte fetches.
|
|
*/
|
|
if (pCir->chip.lg->ModeReg.DTTC & 0x0040) {
|
|
/*
|
|
* Using 256-byte wide tiles. Double the fetches per
|
|
* line field.
|
|
*/
|
|
pCir->chip.lg->ModeReg.DTTC =
|
|
(pCir->chip.lg->ModeReg.DTTC & 0xC0FF) |
|
|
((pCir->chip.lg->ModeReg.DTTC & 0x3F00) << 1);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Programme the registers.
|
|
*/
|
|
vgaHWProtect(pScrn, TRUE);
|
|
hwp->writeMiscOut(hwp, hwp->ModeReg.MiscOutReg);
|
|
|
|
clockData = LgSetClock(pCir, hwp, mode->SynthClock);
|
|
pCir->chip.lg->ModeReg.ExtVga[SR0E] = (clockData >> 8) & 0xFF;
|
|
pCir->chip.lg->ModeReg.ExtVga[SR1E] = clockData & 0xFF;
|
|
|
|
/*
|
|
* Write those registers out to the card.
|
|
*/
|
|
LgRestoreLgRegs(pScrn, &pCir->chip.lg->ModeReg);
|
|
|
|
/*
|
|
* Programme the registers.
|
|
*/
|
|
vgaHWRestore(pScrn, &hwp->ModeReg, VGA_SR_MODE | VGA_SR_CMAP);
|
|
|
|
vgaHWProtect(pScrn, FALSE);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static int
|
|
LgFindLineData(int displayWidth, int bpp)
|
|
{
|
|
/*
|
|
* Find the smallest tile-line-pitch such that the total byte
|
|
* pitch is greater than or equal to displayWidth * Bpp.
|
|
*/
|
|
int i;
|
|
|
|
/*
|
|
* Some pitch sizes are duplicates in the table. BUT, the
|
|
* invariant is that the _first_ time a pitch occurs in the table
|
|
* is always _before_ all other pitches greater than it. Said in
|
|
* another way... if all duplicate entries from the table were
|
|
* removed, then the resulting pitch values are strictly
|
|
* increasing.
|
|
*/
|
|
|
|
for (i = 0; LgLineData[i].pitch > 0; i++)
|
|
if (LgLineData[i].pitch >= displayWidth * bpp >> 3)
|
|
return i;
|
|
|
|
/*
|
|
* Um, uh oh!
|
|
*/
|
|
return -1;
|
|
}
|
|
|
|
static void
|
|
LgRestoreLgRegs(ScrnInfoPtr pScrn, LgRegPtr lgReg)
|
|
{
|
|
CirPtr pCir;
|
|
vgaHWPtr hwp;
|
|
CARD8 cr1D;
|
|
|
|
pCir = CIRPTR(pScrn);
|
|
|
|
/*
|
|
* First, VGAish registers.
|
|
*/
|
|
hwp = VGAHWPTR(pScrn);
|
|
hwp->writeCrtc(hwp, 0x1A, lgReg->ExtVga[CR1A]);
|
|
hwp->writeCrtc(hwp, 0x1B, lgReg->ExtVga[CR1B]);
|
|
cr1D = (hwp->readCrtc(hwp, 0x1D) & ~1) |
|
|
(lgReg->ExtVga[CR1D] & 0x01);
|
|
hwp->writeCrtc(hwp, 0x1D, cr1D);
|
|
hwp->writeCrtc(hwp, 0x1E, lgReg->ExtVga[CR1E]);
|
|
|
|
hwp->writeSeq(hwp, 0x07, lgReg->ExtVga[SR07]);
|
|
hwp->writeSeq(hwp, 0x0E, lgReg->ExtVga[SR0E]);
|
|
hwp->writeSeq(hwp, 0x1E, lgReg->ExtVga[SR1E]);
|
|
memww(0xC0, lgReg->FORMAT);
|
|
|
|
/*
|
|
* Vendor Specific Control is touchy. Only bit 28 is of concern.
|
|
*/
|
|
memwl(0x3FC, ((memrl(0x3FC) & ~(1 << 28)) |
|
|
(lgReg->VSC & (1 << 28))));
|
|
|
|
memww(0xEA, lgReg->DTTC);
|
|
|
|
if (pCir->Chipset == PCI_CHIP_GD5465) {
|
|
memww(0x2C4, lgReg->TileCtrl);
|
|
}
|
|
|
|
memwb(0x407, lgReg->TILE);
|
|
|
|
if (pCir->Chipset == PCI_CHIP_GD5465)
|
|
memwb(0x2C0, lgReg->BCLK);
|
|
else
|
|
memwb(0x8C, lgReg->BCLK);
|
|
|
|
memww(0x402, lgReg->CONTROL);
|
|
|
|
memww(0x200, lgReg->RIFCtrl);
|
|
memww(0x202, lgReg->RACCtrl);
|
|
}
|
|
|
|
/*
|
|
* Restore the initial (text) mode.
|
|
*/
|
|
static void
|
|
LgRestore(ScrnInfoPtr pScrn)
|
|
{
|
|
vgaHWPtr hwp;
|
|
vgaRegPtr vgaReg;
|
|
CirPtr pCir;
|
|
LgRegPtr lgReg;
|
|
|
|
#ifdef LG_DEBUG
|
|
ErrorF("LgRestore pScrn = %p\n", (void *) pScrn);
|
|
#endif
|
|
|
|
pCir = CIRPTR(pScrn);
|
|
hwp = VGAHWPTR(pScrn);
|
|
vgaReg = &hwp->SavedReg;
|
|
lgReg = &pCir->chip.lg->SavedReg;
|
|
|
|
vgaHWProtect(pScrn, TRUE);
|
|
|
|
LgRestoreLgRegs(pScrn, lgReg);
|
|
|
|
vgaHWRestore(pScrn, vgaReg, VGA_SR_ALL);
|
|
vgaHWProtect(pScrn, FALSE);
|
|
}
|
|
|
|
/*
|
|
* This gets called at the start of each server generation
|
|
*/
|
|
/*
|
|
* Mandatory
|
|
*/
|
|
Bool
|
|
LgScreenInit(SCREEN_INIT_ARGS_DECL)
|
|
{
|
|
/*
|
|
* The vgaHW references will disappear one day
|
|
*/
|
|
ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
|
|
vgaHWPtr hwp;
|
|
CirPtr pCir;
|
|
int i, ret;
|
|
VisualPtr visual;
|
|
int displayWidth, width, height;
|
|
unsigned char * FbBase = NULL;
|
|
|
|
#ifdef LG_DEBUG
|
|
ErrorF("LgScreenInit\n");
|
|
#endif
|
|
|
|
hwp = VGAHWPTR(pScrn);
|
|
|
|
/*
|
|
* Standard 64k VGA window
|
|
*/
|
|
hwp->MapSize = 0x10000;
|
|
|
|
pCir = CIRPTR(pScrn);
|
|
|
|
/*
|
|
* Map the VGA memory and get the VGA IO base.
|
|
*/
|
|
if (!vgaHWMapMem(pScrn))
|
|
return FALSE;
|
|
|
|
/*
|
|
* Map the CIR memory and MMIO areas.
|
|
*/
|
|
if (!CirMapMem(pCir, pScrn->scrnIndex))
|
|
return FALSE;
|
|
#ifdef EXPERIMENTAL
|
|
lg_vgaHWSetMmioFunc(hwp, pCir->IOBase);
|
|
#endif
|
|
vgaHWGetIOBase(hwp);
|
|
|
|
/*
|
|
* Save the current state.
|
|
*/
|
|
LgSave(pScrn);
|
|
|
|
/*
|
|
* Initialise the first mode.
|
|
*/
|
|
if (!LgModeInit(pScrn, pScrn->currentMode))
|
|
return FALSE;
|
|
|
|
/*
|
|
* Make things beautiful.
|
|
*/
|
|
LgSaveScreen(pScreen, SCREEN_SAVER_ON);
|
|
|
|
/*
|
|
* Set the viewport.
|
|
*/
|
|
LgAdjustFrame(ADJUST_FRAME_ARGS(pScrn,
|
|
pScrn->frameX0,
|
|
pScrn->frameY0));
|
|
|
|
/*
|
|
* The next step is to setup the screen's visuals, and initialise
|
|
* the framebuffer code. In cases where the framebuffer's default
|
|
* choices for things like visual layouts and bits per RGB are OK,
|
|
* this may be as simple as calling the framebuffer's ScreenInit()
|
|
* function. If not, the visuals will need to be setup before
|
|
* calling a fb ScreenInit() function and fixed up after.
|
|
*/
|
|
|
|
/*
|
|
* Reset the visual list.
|
|
*/
|
|
miClearVisualTypes();
|
|
|
|
/*
|
|
* Setup the visuals we support.
|
|
*/
|
|
if (!miSetVisualTypes(pScrn->depth,
|
|
miGetDefaultVisualMask(pScrn->depth),
|
|
pScrn->rgbBits,
|
|
pScrn->defaultVisual))
|
|
return FALSE;
|
|
|
|
miSetPixmapDepths();
|
|
|
|
#ifdef LG_DEBUG
|
|
ErrorF("LgScreenInit after miSetVisualTypes\n");
|
|
#endif
|
|
displayWidth = pScrn->displayWidth;
|
|
if (pCir->rotate) {
|
|
height = pScrn->virtualX;
|
|
width = pScrn->virtualY;
|
|
} else {
|
|
width = pScrn->virtualX;
|
|
height = pScrn->virtualY;
|
|
}
|
|
|
|
if (pCir->shadowFB) {
|
|
pCir->ShadowPitch = BitmapBytePad(pScrn->bitsPerPixel * width);
|
|
pCir->ShadowPtr = malloc(pCir->ShadowPitch * height);
|
|
displayWidth = pCir->ShadowPitch / (pScrn->bitsPerPixel >> 3);
|
|
FbBase = pCir->ShadowPtr;
|
|
} else {
|
|
pCir->ShadowPtr = NULL;
|
|
FbBase = pCir->FbBase;
|
|
}
|
|
|
|
/*
|
|
* Call the framebuffer layer's ScreenInit function, and fill in
|
|
* other pScreen fields.
|
|
*/
|
|
switch (pScrn->bitsPerPixel) {
|
|
case 8:
|
|
case 16:
|
|
case 24:
|
|
case 32:
|
|
ret = fbScreenInit(pScreen, FbBase, width, height,
|
|
pScrn->xDpi, pScrn->yDpi,
|
|
displayWidth, pScrn->bitsPerPixel);
|
|
break;
|
|
default:
|
|
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
|
"X11: Internal error: invalid bpp (%d) in "
|
|
"LgScreenInit\n",
|
|
pScrn->bitsPerPixel);
|
|
ret = FALSE;
|
|
break;
|
|
}
|
|
if (!ret)
|
|
return FALSE;
|
|
|
|
#ifdef LG_DEBUG
|
|
ErrorF("LgScreenInit after depth dependent init\n");
|
|
#endif
|
|
|
|
/*
|
|
* Override the default mask/offset settings.
|
|
*/
|
|
if (pScrn->bitsPerPixel > 8) {
|
|
for (i = 0; i < pScreen->numVisuals; i++) {
|
|
visual = &pScreen->visuals[i];
|
|
if ((visual->class | DynamicClass) == DirectColor) {
|
|
visual->offsetRed = pScrn->offset.red;
|
|
visual->offsetGreen = pScrn->offset.green;
|
|
visual->offsetBlue = pScrn->offset.blue;
|
|
visual->redMask = pScrn->mask.red;
|
|
visual->greenMask = pScrn->mask.green;
|
|
visual->blueMask = pScrn->mask.blue;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Must be after RGB ordering fixed.
|
|
*/
|
|
|
|
fbPictureInit(pScreen, 0, 0);
|
|
|
|
/*
|
|
* Set initial black & white colourmap indices.
|
|
*/
|
|
xf86SetBlackWhitePixels(pScreen);
|
|
|
|
#ifdef HAVE_XAA_H
|
|
/*
|
|
* Initialize XAA functions.
|
|
*/
|
|
if (!pCir->NoAccel) {
|
|
if (!LgXAAInit(pScreen))
|
|
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
|
"Could not initialize XAA\n");
|
|
}
|
|
#endif
|
|
#if 1
|
|
pCir->DGAModeInit = LgModeInit;
|
|
if (!CirDGAInit(pScreen))
|
|
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
|
"DGA initialization failed\n");
|
|
#endif
|
|
xf86SetSilkenMouse(pScreen);
|
|
|
|
/*
|
|
* Initialise cursor functions.
|
|
*/
|
|
miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
|
|
|
|
/*
|
|
* Initialize HW cursor layer.
|
|
*/
|
|
if (pCir->HWCursor) {
|
|
if (!LgHWCursorInit(pScreen))
|
|
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
|
"Hardware cursor initialization failed\n");
|
|
}
|
|
|
|
/*
|
|
* Initialise default colourmap.
|
|
*/
|
|
if (!miCreateDefColormap(pScreen))
|
|
return FALSE;
|
|
|
|
if (pScrn->bitsPerPixel > 1 && pScrn->bitsPerPixel <= 8)
|
|
vgaHWHandleColormaps(pScreen);
|
|
|
|
xf86DPMSInit(pScreen, LgDisplayPowerManagementSet, 0);
|
|
|
|
pScrn->memPhysBase = pCir->FbAddress;
|
|
pScrn->fbOffset = 0;
|
|
|
|
{
|
|
XF86VideoAdaptorPtr *ptr;
|
|
int n;
|
|
|
|
n = xf86XVListGenericAdaptors(pScrn, &ptr);
|
|
if (n)
|
|
xf86XVScreenInit(pScreen, ptr, n);
|
|
}
|
|
|
|
/*
|
|
* Wrap the CloseScreen vector and set SaveScreen.
|
|
*/
|
|
pScreen->SaveScreen = LgSaveScreen;
|
|
pCir->CloseScreen = pScreen->CloseScreen;
|
|
pScreen->CloseScreen = LgCloseScreen;
|
|
|
|
/*
|
|
* Report any unused options (only for the first generation).
|
|
*/
|
|
if (serverGeneration == 1)
|
|
xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
|
|
|
|
/*
|
|
* Done
|
|
*/
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* Usually mandatory
|
|
*/
|
|
Bool
|
|
LgSwitchMode(SWITCH_MODE_ARGS_DECL)
|
|
{
|
|
SCRN_INFO_PTR(arg);
|
|
return LgModeInit(pScrn, mode);
|
|
}
|
|
|
|
#define ROUND_DOWN(x, mod) (((x) / (mod)) * (mod))
|
|
#define ROUND_UP(x, mod) ((((x) + (mod) - 1) / (mod)) * (mod))
|
|
|
|
/*
|
|
* This function is used to initialize the Start Address - the first
|
|
* displayed location in the video memory.
|
|
*/
|
|
/*
|
|
* Usually mandatory
|
|
*/
|
|
void LgAdjustFrame(ADJUST_FRAME_ARGS_DECL) {
|
|
SCRN_INFO_PTR(arg);
|
|
int Base, tmp;
|
|
CirPtr pCir = CIRPTR(pScrn);
|
|
vgaHWPtr hwp = VGAHWPTR(pScrn);
|
|
int cursorX, cursorY;
|
|
int middleX, middleY;
|
|
const LgLineDataPtr lineData =
|
|
&LgLineData[pCir->chip.lg->lineDataIndex];
|
|
const int viewportXRes =
|
|
(PCI_CHIP_GD5465 == pCir->Chipset) ?
|
|
(24 == pScrn->bitsPerPixel ? 24 : 1) :
|
|
(lineData->width ? 256 : 128)
|
|
/ (24 == pScrn->bitsPerPixel ?
|
|
1 : (pScrn->bitsPerPixel >> 3));
|
|
const int viewportYRes =
|
|
(PCI_CHIP_GD5465 == pCir->Chipset) ?
|
|
1 : (24 == pScrn->bitsPerPixel ? 3 : 1);
|
|
|
|
/*
|
|
* Where's the pointer?
|
|
*/
|
|
miPointerGetPosition(inputInfo.pointer, &cursorX, &cursorY);
|
|
|
|
/*
|
|
* Where's the middle of the screen? We want to eventually know
|
|
* which side of the screen the pointer is on.
|
|
*/
|
|
middleX = (pScrn->frameX1 + pScrn->frameX0) / 2;
|
|
middleY = (pScrn->frameY1 + pScrn->frameY0) / 2;
|
|
|
|
if (cursorX < middleX) {
|
|
/*
|
|
* Pointer is on left side of screen. Round the frame value
|
|
* down.
|
|
*/
|
|
pScrn->frameX0 = ROUND_DOWN(pScrn->frameX0, viewportXRes);
|
|
} else {
|
|
/*
|
|
* Pointer is on right side of screen. Round the frame value
|
|
* up. A side effect of this rounding up is that we might
|
|
* expose a part of the screen that's actually on the far
|
|
* /left/ of the frame buffer. That's because, although the
|
|
* virtual desktop might be an integral number of tiles, the
|
|
* display might not. We'll just live with this artifact.
|
|
*/
|
|
pScrn->frameX0 = ROUND_UP(pScrn->frameX0, viewportXRes);
|
|
}
|
|
pScrn->frameX1 = pScrn->frameX0 +
|
|
pScrn->currentMode->HDisplay - 1;
|
|
|
|
if (cursorY < middleY) {
|
|
pScrn->frameY0 = ROUND_DOWN(pScrn->frameY0, viewportYRes);
|
|
} else {
|
|
pScrn->frameY0 = ROUND_UP(pScrn->frameY0, viewportYRes);
|
|
}
|
|
pScrn->frameY1 = pScrn->frameY0 +
|
|
pScrn->currentMode->VDisplay - 1;
|
|
|
|
if (x != pScrn->frameX0 || y != pScrn->frameY0) {
|
|
/*
|
|
* !!!
|
|
*/
|
|
/*
|
|
* We moved the frame from where xf86SetViewport() placed
|
|
* it. If we're using a SW cursor, that's okay -- the
|
|
* pointer exists in the framebuffer, and those bits are
|
|
* still all aligned. But if we're using a HW cursor, then
|
|
* we need to re-align the pointer. Call SetCursorPosition()
|
|
* with the appropriate new pointer values, adjusted to be
|
|
* wrt the new frame.
|
|
*/
|
|
x = pScrn->frameX0;
|
|
y = pScrn->frameY0;
|
|
}
|
|
|
|
/*
|
|
* ??? Will this work for 1bpp?
|
|
*/
|
|
Base = (y * lineData->pitch + (x * pScrn->bitsPerPixel / 8)) / 4;
|
|
|
|
if ((Base & ~0x000FFFFF) != 0) {
|
|
/*
|
|
* ???
|
|
*/
|
|
ErrorF("X11: Internal error: LgAdjustFrame: cannot handle "
|
|
"overflow\n");
|
|
return;
|
|
}
|
|
|
|
hwp->writeCrtc(hwp, 0x0C, (Base >> 8) & 0xFF);
|
|
hwp->writeCrtc(hwp, 0x0D, Base & 0xFF);
|
|
tmp = hwp->readCrtc(hwp, 0x1B) & 0xF2;
|
|
tmp |= (Base >> 16) & 0x01;
|
|
tmp |= (Base >> 15) & 0x0C;
|
|
hwp->writeCrtc(hwp, 0x1B, tmp);
|
|
tmp = hwp->readCrtc(hwp, 0x1D) & 0xE7;
|
|
tmp |= (Base >> 16) & 0x18;
|
|
hwp->writeCrtc(hwp, 0x1D, tmp);
|
|
}
|
|
|
|
/*
|
|
* This is called when VT switching back to the X server. Its job is
|
|
* to reinitialise the video mode. We may wish to unmap video/MMIO
|
|
* memory too.
|
|
*/
|
|
/*
|
|
* Mandatory
|
|
*/
|
|
Bool
|
|
LgEnterVT(VT_FUNC_ARGS_DECL)
|
|
{
|
|
SCRN_INFO_PTR(arg);
|
|
CirPtr pCir = CIRPTR(pScrn);
|
|
#ifdef LG_DEBUG
|
|
ErrorF("LgEnterVT\n");
|
|
#endif
|
|
|
|
/*
|
|
* XXX Shouldn't this be in LeaveVT?
|
|
*/
|
|
/*
|
|
* Disable HW cursor.
|
|
*/
|
|
if (pCir->HWCursor)
|
|
LgHideCursor(pScrn);
|
|
|
|
/*
|
|
* Should we re-save the text mode on each VT enter?
|
|
*/
|
|
return LgModeInit(pScrn, pScrn->currentMode);
|
|
}
|
|
|
|
/*
|
|
* This is called when VT switching away from the X server. Its job
|
|
* is to restore the previous (text) mode. We may wish to remap
|
|
* video/MMIO memory too.
|
|
*/
|
|
/*
|
|
* Mandatory
|
|
*/
|
|
void LgLeaveVT(VT_FUNC_ARGS_DECL) {
|
|
SCRN_INFO_PTR(arg);
|
|
vgaHWPtr hwp = VGAHWPTR(pScrn);
|
|
CirPtr pCir = CIRPTR(pScrn);
|
|
#ifdef LG_DEBUG
|
|
ErrorF("LgLeaveVT\n");
|
|
#endif
|
|
|
|
/*
|
|
* XXX Shouldn't this be in EnterVT?
|
|
*/
|
|
/*
|
|
* Enable HW cursor.
|
|
*/
|
|
if (pCir->HWCursor)
|
|
LgShowCursor(pScrn);
|
|
|
|
LgRestore(pScrn);
|
|
vgaHWLock(hwp);
|
|
}
|
|
|
|
/*
|
|
* This is called at the end of each server generation. It restores
|
|
* the original (text) mode. It should also unmap the video memory,
|
|
* and free any per-generation data allocated by the driver. It
|
|
* should finish by unwrapping and calling the saved CloseScreen
|
|
* function.
|
|
*/
|
|
/*
|
|
* Mandatory
|
|
*/
|
|
static Bool
|
|
LgCloseScreen(CLOSE_SCREEN_ARGS_DECL)
|
|
{
|
|
ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
|
|
vgaHWPtr hwp = VGAHWPTR(pScrn);
|
|
CirPtr pCir = CIRPTR(pScrn);
|
|
|
|
if (pScrn->vtSema) {
|
|
LgRestore(pScrn);
|
|
if (pCir->HWCursor)
|
|
LgHideCursor(pScrn);
|
|
|
|
vgaHWLock(hwp);
|
|
|
|
CirUnmapMem(pCir, pScrn->scrnIndex);
|
|
}
|
|
|
|
#ifdef HAVE_XAA_H
|
|
if (pCir->AccelInfoRec)
|
|
XAADestroyInfoRec(pCir->AccelInfoRec);
|
|
pCir->AccelInfoRec = NULL;
|
|
#endif
|
|
|
|
if (pCir->CursorInfoRec)
|
|
xf86DestroyCursorInfoRec(pCir->CursorInfoRec);
|
|
pCir->CursorInfoRec = NULL;
|
|
if (pCir->DGAModes)
|
|
free(pCir->DGAModes);
|
|
pCir->DGAnumModes = 0;
|
|
pCir->DGAModes = NULL;
|
|
|
|
pScrn->vtSema = FALSE;
|
|
|
|
pScreen->CloseScreen = pCir->CloseScreen;
|
|
return (*pScreen->CloseScreen)(CLOSE_SCREEN_ARGS);
|
|
}
|
|
|
|
/*
|
|
* Free up any persistent data structures.
|
|
*/
|
|
/*
|
|
* Optional
|
|
*/
|
|
void
|
|
LgFreeScreen(FREE_SCREEN_ARGS_DECL)
|
|
{
|
|
SCRN_INFO_PTR(arg);
|
|
#ifdef LG_DEBUG
|
|
ErrorF("LgFreeScreen\n");
|
|
#endif
|
|
/*
|
|
* This only gets called when a screen is being deleted. It does
|
|
* not get called routinely at the end of a server generation.
|
|
*/
|
|
if (xf86LoaderCheckSymbol("vgaHWFreeHWRec"))
|
|
vgaHWFreeHWRec(pScrn);
|
|
LgFreeRec(pScrn);
|
|
}
|
|
|
|
/*
|
|
* Checks if a mode is suitable for the selected chipset.
|
|
*/
|
|
/*
|
|
* Optional
|
|
*/
|
|
ModeStatus
|
|
LgValidMode(SCRN_ARG_TYPE arg, DisplayModePtr mode,
|
|
Bool verbose, int flags)
|
|
{
|
|
int lace;
|
|
|
|
lace = 1 + ((mode->Flags & V_INTERLACE) != 0);
|
|
|
|
if ((mode->CrtcHDisplay <= 2048) &&
|
|
(mode->CrtcHSyncStart <= 4096) &&
|
|
(mode->CrtcHSyncEnd <= 4096) &&
|
|
(mode->CrtcHTotal <= 4096) &&
|
|
(mode->CrtcVDisplay <= 2048 * lace) &&
|
|
(mode->CrtcVSyncStart <= 4096 * lace) &&
|
|
(mode->CrtcVSyncEnd <= 4096 * lace) &&
|
|
(mode->CrtcVTotal <= 4096 * lace)) {
|
|
return (MODE_OK);
|
|
}
|
|
return (MODE_BAD);
|
|
}
|
|
|
|
/*
|
|
* Do screen blanking.
|
|
*/
|
|
/*
|
|
* Mandatory
|
|
*/
|
|
static Bool
|
|
LgSaveScreen(ScreenPtr pScreen, int mode)
|
|
{
|
|
CirPtr pCir = CIRPTR(xf86ScreenToScrn(pScreen));
|
|
ScrnInfoPtr pScrn = NULL;
|
|
Bool unblank;
|
|
|
|
unblank = xf86IsUnblank(mode);
|
|
|
|
if (pScreen != NULL)
|
|
pScrn = xf86ScreenToScrn(pScreen);
|
|
|
|
if (pScrn != NULL && pScrn->vtSema) {
|
|
if (unblank)
|
|
/*
|
|
* Power up the palette DAC.
|
|
*/
|
|
memwb(0xB0, memrb(0xB0) & 0x7F);
|
|
else
|
|
/*
|
|
* Power down the palette DAC.
|
|
*/
|
|
memwb(0xB0, memrb(0xB0) | 0x80);
|
|
}
|
|
|
|
return vgaHWSaveScreen(pScreen, mode);
|
|
}
|
|
|
|
static CARD16
|
|
LgSetClock(CirPtr pCir, vgaHWPtr hwp, int freq)
|
|
{
|
|
int ffreq, num, den;
|
|
CARD8 tmp;
|
|
|
|
ErrorF("LgSetClock freq=%d.%03dMHz\n", freq / 1000, freq % 1000);
|
|
|
|
ffreq = freq;
|
|
if (!CirrusFindClock(&ffreq, pCir->MaxClock, &num, &den))
|
|
return 0;
|
|
|
|
ErrorF("LgSetClock: nom=%x den=%x ffreq=%d.%03dMHz\n",
|
|
num, den, ffreq / 1000, ffreq % 1000);
|
|
|
|
/*
|
|
* Set VCLK3.
|
|
*/
|
|
/*
|
|
* The numerator and denominator registers are switched around
|
|
* in the Laguna chips.
|
|
*/
|
|
tmp = hwp->readSeq(hwp, 0x0E);
|
|
hwp->writeSeq(hwp, 0x0E, (tmp & 0x80) | den);
|
|
hwp->writeSeq(hwp, 0x1E, num);
|
|
|
|
return (den << 8) | num;
|
|
}
|
|
|
|
/*
|
|
* LgDisplayPowerManagementSet --
|
|
*
|
|
* Sets VESA Display Power Management Signaling (DPMS) Mode.
|
|
*/
|
|
static void
|
|
LgDisplayPowerManagementSet(ScrnInfoPtr pScrn,
|
|
int PowerManagementMode,
|
|
int flags)
|
|
{
|
|
unsigned char sr01, cr1a;
|
|
vgaHWPtr hwp;
|
|
|
|
#ifdef LG_DEBUG
|
|
ErrorF("LgDisplayPowerManagementSet: %d\n", PowerManagementMode);
|
|
#endif
|
|
|
|
hwp = VGAHWPTR(pScrn);
|
|
|
|
switch (PowerManagementMode) {
|
|
case DPMSModeOn:
|
|
/*
|
|
* Screen: On; HSync: On, VSync: On
|
|
*/
|
|
sr01 = 0x00;
|
|
cr1a = 0x00;
|
|
break;
|
|
case DPMSModeStandby:
|
|
/*
|
|
* Screen: Off; HSync: Off, VSync: On
|
|
*/
|
|
sr01 = 0x20;
|
|
cr1a = 0x08;
|
|
break;
|
|
case DPMSModeSuspend:
|
|
/*
|
|
* Screen: Off; HSync: On, VSync: Off
|
|
*/
|
|
sr01 = 0x20;
|
|
cr1a = 0x04;
|
|
break;
|
|
case DPMSModeOff:
|
|
/*
|
|
* Screen: Off; HSync: Off, VSync: Off
|
|
*/
|
|
sr01 = 0x20;
|
|
cr1a = 0x0c;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
sr01 |= hwp->readSeq(hwp, 0x01) & ~0x20;
|
|
hwp->writeSeq(hwp, 0x01, sr01);
|
|
cr1a |= hwp->readCrtc(hwp, 0x1A) & ~0x0C;
|
|
hwp->writeCrtc(hwp, 0x1A, cr1a);
|
|
}
|
|
|
|
#define minb(p) MMIO_IN8(hwp->MMIOBase, (p))
|
|
#define moutb(p,v) MMIO_OUT8(hwp->MMIOBase, (p),(v))
|
|
|
|
static void
|
|
mmioWriteCrtc(vgaHWPtr hwp, CARD8 index, CARD8 value)
|
|
{
|
|
moutb(index << 2, value);
|
|
}
|
|
|
|
static CARD8
|
|
mmioReadCrtc(vgaHWPtr hwp, CARD8 index)
|
|
{
|
|
return minb(index << 2);
|
|
}
|
|
|
|
static void
|
|
lg_vgaHWSetMmioFunc(vgaHWPtr hwp, CARD8 *base)
|
|
{
|
|
hwp->writeCrtc = mmioWriteCrtc;
|
|
hwp->readCrtc = mmioReadCrtc;
|
|
hwp->MMIOBase = base;
|
|
hwp->MMIOOffset = 0;
|
|
}
|