lg_driver.c revision 1e66b2a2
176888252Smrg/*
276888252Smrg * Driver for CL-GD546x -- The Laguna family
376888252Smrg *
476888252Smrg * lg_driver.c
576888252Smrg *
676888252Smrg * (c) 1998 Corin Anderson.
776888252Smrg *          corina@the4cs.com
876888252Smrg *          Tukwila, WA
976888252Smrg *
1076888252Smrg * This driver is derived from the cir_driver.c module.
1176888252Smrg * Original authors and contributors list include:
1276888252Smrg *	Radoslaw Kapitan, Andrew Vanderstock, Dirk Hohndel,
1376888252Smrg *	David Dawes, Andrew E. Mileski, Leonard N. Zubkoff,
1476888252Smrg *	Guy DESBIEF, Itai Nahshon.
1576888252Smrg */
1676888252Smrg/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/cirrus/lg_driver.c,v 1.49 2003/11/03 05:11:09 tsi Exp $ */
1776888252Smrg
1876888252Smrg#ifdef HAVE_CONFIG_H
1976888252Smrg#include "config.h"
2076888252Smrg#endif
2176888252Smrg
2276888252Smrg#define EXPERIMENTAL
2376888252Smrg
2476888252Smrg/* All drivers should typically include these */
2576888252Smrg#include "xf86.h"
2676888252Smrg#include "xf86_OSproc.h"
2776888252Smrg
2876888252Smrg/* All drivers need this */
2976888252Smrg
3076888252Smrg#include "compiler.h"
3176888252Smrg
3276888252Smrg/* Drivers for PCI hardware need this */
3376888252Smrg#include "xf86PciInfo.h"
3476888252Smrg
3576888252Smrg/* Drivers that need to access the PCI config space directly need this */
3676888252Smrg#include "xf86Pci.h"
3776888252Smrg
3876888252Smrg/* All drivers using the vgahw module need this */
3976888252Smrg/* This driver needs to be modified to not use vgaHW for multihead operation */
4076888252Smrg#include "vgaHW.h"
4176888252Smrg
421e66b2a2Smrg#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 6
4376888252Smrg#include "xf86RAC.h"
4476888252Smrg#include "xf86Resources.h"
451e66b2a2Smrg#endif
4676888252Smrg
4776888252Smrg/* All drivers initialising the SW cursor need this */
4876888252Smrg#include "mipointer.h"
4976888252Smrg
50afee0becSmrg/* need this for inputInfo */
51afee0becSmrg#include "inputstr.h"
52afee0becSmrg
5376888252Smrg/* All drivers implementing backing store need this */
5476888252Smrg#include "mibstore.h"
5576888252Smrg
5676888252Smrg#include "micmap.h"
5776888252Smrg
5876888252Smrg/* Needed by the Shadow Framebuffer */
5976888252Smrg#include "shadowfb.h"
6076888252Smrg
6176888252Smrg#include "xf86int10.h"
6276888252Smrg
6376888252Smrg#include "fb.h"
6476888252Smrg
6510219488Smrg#include "inputstr.h"
6610219488Smrg
6776888252Smrg#include "xf86DDC.h"
6876888252Smrg
6976888252Smrg#undef LG_DEBUG
7076888252Smrg
7176888252Smrg#include "cir.h"
7276888252Smrg#define _LG_PRIVATE_
7376888252Smrg#include "lg.h"
7476888252Smrg
7576888252Smrg#include "xf86xv.h"
7676888252Smrg#include <X11/extensions/Xv.h>
7776888252Smrg
7876888252Smrg/*
7976888252Smrg * Forward definitions for the functions that make up the driver.
8076888252Smrg */
8176888252Smrg
8276888252Smrg/* Mandatory functions */
8376888252SmrgBool LgPreInit(ScrnInfoPtr pScrn, int flags);
8476888252SmrgBool LgScreenInit(int Index, ScreenPtr pScreen, int argc, char **argv);
8576888252SmrgBool LgEnterVT(int scrnIndex, int flags);
8676888252Smrgvoid LgLeaveVT(int scrnIndex, int flags);
8776888252Smrgstatic Bool	LgCloseScreen(int scrnIndex, ScreenPtr pScreen);
8876888252Smrgstatic Bool	LgSaveScreen(ScreenPtr pScreen, Bool mode);
8976888252Smrg
9076888252Smrg/* Required if the driver supports mode switching */
9176888252SmrgBool LgSwitchMode(int scrnIndex, DisplayModePtr mode, int flags);
9276888252Smrg/* Required if the driver supports moving the viewport */
9376888252Smrgvoid LgAdjustFrame(int scrnIndex, int x, int y, int flags);
9476888252Smrg
9576888252Smrg/* Optional functions */
9676888252Smrgvoid LgFreeScreen(int scrnIndex, int flags);
9776888252SmrgModeStatus LgValidMode(int scrnIndex, DisplayModePtr mode,
9876888252Smrg		       Bool verbose, int flags);
9976888252Smrg
10076888252Smrg/* Internally used functions */
10176888252Smrgstatic void LgRestoreLgRegs(ScrnInfoPtr pScrn, LgRegPtr lgReg);
10276888252Smrgstatic int LgFindLineData(int displayWidth, int bpp);
10376888252Smrgstatic CARD16 LgSetClock(CirPtr pCir, vgaHWPtr hwp, int freq);
10476888252Smrgstatic void lg_vgaHWSetMmioFunc(vgaHWPtr hwp, CARD8 *base);
10576888252Smrg
10676888252Smrgstatic void LgDisplayPowerManagementSet(ScrnInfoPtr pScrn,
10776888252Smrg				        int PowerManagementMode, int flags);
10876888252Smrg
10976888252Smrg/*
11076888252Smrg * This is intentionally screen-independent.  It indicates the binding
11176888252Smrg * choice made in the first PreInit.
11276888252Smrg */
11376888252Smrgstatic int pix24bpp = 0;
11476888252Smrg
11576888252Smrg/*
11676888252Smrg * This contains the functions needed by the server after loading the
11776888252Smrg * driver module.  It must be supplied, and gets added the driver list by
11876888252Smrg * the Module Setup funtion in the dynamic case.  In the static case a
11976888252Smrg * reference to this is compiled in, and this requires that the name of
12076888252Smrg * this DriverRec be an upper-case version of the driver name.
12176888252Smrg */
12276888252Smrg
12376888252Smrgtypedef enum {
12476888252Smrg	OPTION_HW_CURSOR,
12576888252Smrg	OPTION_PCI_RETRY,
12676888252Smrg	OPTION_ROTATE,
12776888252Smrg	OPTION_SHADOW_FB,
12876888252Smrg	OPTION_NOACCEL
12976888252Smrg} LgOpts;
13076888252Smrg
13176888252Smrgstatic const OptionInfoRec LgOptions[] = {
13276888252Smrg    { OPTION_HW_CURSOR,		"HWcursor",	OPTV_BOOLEAN,	{0}, FALSE },
13376888252Smrg    { OPTION_NOACCEL,		"NoAccel",	OPTV_BOOLEAN,	{0}, FALSE },
13476888252Smrg    { OPTION_SHADOW_FB,         "ShadowFB",	OPTV_BOOLEAN,	{0}, FALSE },
13576888252Smrg    { OPTION_ROTATE, 	        "Rotate",	OPTV_ANYSTR,	{0}, FALSE },
13676888252Smrg    /* fifo_conservative/aggressive; fast/med/slow_dram; ... */
13776888252Smrg    { -1,					NULL,		OPTV_NONE,		{0}, FALSE }
13876888252Smrg};
13976888252Smrg
14076888252Smrg
14176888252Smrg/*                                1/4bpp   8bpp   15/16bpp  24bpp  32bpp */
14276888252Smrgstatic int gd5462_MaxClocks[] = { 170000, 170000, 135100, 135100,  85500 };
14376888252Smrgstatic int gd5464_MaxClocks[] = { 170000, 250000, 170000, 170000, 135100 };
14476888252Smrgstatic int gd5465_MaxClocks[] = { 170000, 250000, 170000, 170000, 135100 };
14576888252Smrg
14676888252SmrgLgLineDataRec LgLineData[] = {
14776888252Smrg	{ 5,  640, 0},		/* We're rather use skinny tiles, so put all of */
14876888252Smrg	{ 8, 1024, 0},		/* them at the head of the table */
14976888252Smrg	{10, 1280, 0},
15076888252Smrg	{13, 1664, 0},
15176888252Smrg	{16, 2048, 0},
15276888252Smrg	{20, 2560, 0},
15376888252Smrg	{10, 2560, 1},
15476888252Smrg	{26, 3328, 0},
15576888252Smrg	{ 5, 1280, 1},
15676888252Smrg	{ 8, 2048, 1},
15776888252Smrg	{13, 3328, 1},
15876888252Smrg	{16, 4096, 1},
15976888252Smrg	{20, 5120, 1},
16076888252Smrg	{26, 6656, 1},
16176888252Smrg	{-1, -1, -1}		/* Sentinal to indicate end of table */
16276888252Smrg};
16376888252Smrg
16476888252Smrgstatic int LgLinePitches[4][11] = {
16576888252Smrg	/*  8 */ { 640, 1024, 1280, 1664, 2048, 2560, 3328, 4096, 5120, 6656, 0 },
16676888252Smrg	/* 16 */ { 320,  512,  640,  832, 1024, 1280, 1664, 2048, 2560, 3328, 0 },
16776888252Smrg	/* 24 */ { 213,  341,  426,  554,  682,  853, 1109, 1365, 1706, 2218, 0 },
16876888252Smrg	/* 32 */ { 160,  256,  320,  416,  512,  640,  832, 1024, 1280, 1664, 0 }
16976888252Smrg};
17076888252Smrg
17176888252Smrg#ifdef XFree86LOADER
17276888252Smrg
17376888252Smrg#define LG_MAJOR_VERSION 1
17476888252Smrg#define LG_MINOR_VERSION 0
17576888252Smrg#define LG_PATCHLEVEL 0
17676888252Smrg
17776888252Smrgstatic MODULESETUPPROTO(lgSetup);
17876888252Smrg
17976888252Smrgstatic XF86ModuleVersionInfo lgVersRec =
18076888252Smrg{
18176888252Smrg	"cirrus_laguna",
18276888252Smrg	MODULEVENDORSTRING,
18376888252Smrg	MODINFOSTRING1,
18476888252Smrg	MODINFOSTRING2,
18576888252Smrg	XORG_VERSION_CURRENT,
18676888252Smrg	LG_MAJOR_VERSION, LG_MINOR_VERSION, LG_PATCHLEVEL,
18776888252Smrg	ABI_CLASS_VIDEODRV,			/* This is a video driver */
18876888252Smrg	ABI_VIDEODRV_VERSION,
18976888252Smrg	MOD_CLASS_NONE,
19076888252Smrg	{0,0,0,0}
19176888252Smrg};
19276888252Smrg
19376888252Smrg/*
19476888252Smrg * This is the module init data.
19576888252Smrg * Its name has to be the driver name followed by ModuleData.
19676888252Smrg */
19776888252Smrg_X_EXPORT XF86ModuleData cirrus_lagunaModuleData = {
19876888252Smrg    &lgVersRec,
19976888252Smrg    lgSetup,
20076888252Smrg    NULL
20176888252Smrg};
20276888252Smrg
20376888252Smrgstatic pointer
20476888252SmrglgSetup(pointer module, pointer opts, int *errmaj, int *errmin)
20576888252Smrg{
20676888252Smrg    static Bool setupDone = FALSE;
20776888252Smrg
20876888252Smrg    if (!setupDone) {
20976888252Smrg	setupDone = TRUE;
21076888252Smrg    }
21176888252Smrg    return (pointer)1;
21276888252Smrg}
21376888252Smrg
21476888252Smrg#endif /* XFree86LOADER */
21576888252Smrg
21676888252Smrg_X_EXPORT const OptionInfoRec *
21776888252SmrgLgAvailableOptions(int chipid)
21876888252Smrg{
21976888252Smrg    return LgOptions;
22076888252Smrg}
22176888252Smrg
22276888252Smrg_X_EXPORT ScrnInfoPtr
22376888252SmrgLgProbe(int entity)
22476888252Smrg{
22576888252Smrg    ScrnInfoPtr pScrn = NULL;
22676888252Smrg    if ((pScrn = xf86ConfigPciEntity(pScrn, 0, entity, CIRPciChipsets,
22776888252Smrg					   NULL, NULL, NULL, NULL, NULL))) {
22876888252Smrg	pScrn->PreInit		= LgPreInit;
22976888252Smrg	pScrn->ScreenInit	= LgScreenInit;
23076888252Smrg	pScrn->SwitchMode	= LgSwitchMode;
23176888252Smrg	pScrn->AdjustFrame	= LgAdjustFrame;
23276888252Smrg	pScrn->EnterVT		= LgEnterVT;
23376888252Smrg	pScrn->LeaveVT		= LgLeaveVT;
23476888252Smrg	pScrn->FreeScreen	= LgFreeScreen;
23576888252Smrg	pScrn->ValidMode	= LgValidMode;
23676888252Smrg    }
23776888252Smrg    return pScrn;
23876888252Smrg}
23976888252Smrg
24076888252Smrg
24176888252Smrgstatic Bool
24276888252SmrgLgGetRec(ScrnInfoPtr pScrn)
24376888252Smrg{
24476888252Smrg	CirPtr pCir;
24576888252Smrg
24676888252Smrg	if (pScrn->driverPrivate != NULL)
24776888252Smrg		return TRUE;
24876888252Smrg
24976888252Smrg	pScrn->driverPrivate = xnfcalloc(sizeof(CirRec), 1);
25076888252Smrg	((CirPtr)pScrn->driverPrivate)->chip.lg = xnfcalloc(sizeof(LgRec),1);
25176888252Smrg
25276888252Smrg	/* Initialize it */
25376888252Smrg	pCir = CIRPTR(pScrn);
25476888252Smrg	pCir->chip.lg->oldBitmask = 0x00000000;
25576888252Smrg
25676888252Smrg	return TRUE;
25776888252Smrg}
25876888252Smrg
25976888252Smrgstatic void
26076888252SmrgLgFreeRec(ScrnInfoPtr pScrn)
26176888252Smrg{
26276888252Smrg	if (pScrn->driverPrivate == NULL)
26376888252Smrg		return;
26476888252Smrg	xfree(pScrn->driverPrivate);
26576888252Smrg	pScrn->driverPrivate = NULL;
26676888252Smrg}
26776888252Smrg
26876888252Smrg
26976888252Smrg
27076888252Smrg/*
27176888252Smrg * LgCountRAM --
27276888252Smrg *
27376888252Smrg * Counts amount of installed RAM
27476888252Smrg */
27576888252Smrg
27676888252Smrg/* XXX We need to get rid of this PIO (MArk) */
27776888252Smrgstatic int
27876888252SmrgLgCountRam(ScrnInfoPtr pScrn)
27976888252Smrg{
28076888252Smrg	vgaHWPtr hwp = VGAHWPTR(pScrn);
28176888252Smrg	CARD8 SR14;
28276888252Smrg
28376888252Smrg	vgaHWProtect(pScrn, TRUE);
28476888252Smrg
28576888252Smrg	/* The ROM BIOS scratchpad registers contain,
28676888252Smrg	   among other things, the amount of installed
28776888252Smrg	   RDRAM on the laguna chip. */
28876888252Smrg	SR14 = hwp->readSeq(hwp, 0x14);
28976888252Smrg
29076888252Smrg	ErrorF("Scratch Pads: 0:%02x 1:%02x 2:%02x 3:%02x\n",
29176888252Smrg		hwp->readSeq(hwp, 9), hwp->readSeq(hwp, 10),
29276888252Smrg		SR14, hwp->readSeq(hwp, 0x15));
29376888252Smrg
29476888252Smrg	vgaHWProtect(pScrn, FALSE);
29576888252Smrg
29676888252Smrg	return 1024 * ((SR14&0x7) + 1);
29776888252Smrg
29876888252Smrg	/* !!! This function seems to be incorrect... */
29976888252Smrg}
30076888252Smrg
30176888252Smrgstatic xf86MonPtr
30276888252SmrgLgDoDDC(ScrnInfoPtr pScrn)
30376888252Smrg{
30476888252Smrg	CirPtr pCir = CIRPTR(pScrn);
30576888252Smrg	xf86MonPtr MonInfo = NULL;
30676888252Smrg
30776888252Smrg	/* Map the CIR memory and MMIO areas */
30876888252Smrg	if (!CirMapMem(pCir, pScrn->scrnIndex))
30976888252Smrg		return FALSE;
31076888252Smrg
31176888252Smrg#if LGuseI2C
31276888252Smrg	if (!LgI2CInit(pScrn)) {
31376888252Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "I2C initialization failed\n");
31476888252Smrg
31576888252Smrg		goto unmap_out;
31676888252Smrg	}
31776888252Smrg
31876888252Smrg	/* Read and output monitor info using DDC2 over I2C bus */
31976888252Smrg	MonInfo = xf86DoEDID_DDC2(pScrn->scrnIndex, pCir->I2CPtr1);
32076888252Smrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "I2C Monitor info: %p\n",
32176888252Smrg		   (void *)MonInfo);
32276888252Smrg	xf86PrintEDID(MonInfo);
32376888252Smrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "end of I2C Monitor info\n\n");
32476888252Smrg#endif /* LGuseI2C */
32576888252Smrg
32676888252Smrg	xf86SetDDCproperties(pScrn, MonInfo);
32776888252Smrg
32876888252Smrgunmap_out:
32976888252Smrg	CirUnmapMem(pCir, pScrn->scrnIndex);
33076888252Smrg
33176888252Smrg	return MonInfo;
33276888252Smrg}
33376888252Smrg
33476888252Smrg/* Mandatory */
33576888252SmrgBool
33676888252SmrgLgPreInit(ScrnInfoPtr pScrn, int flags)
33776888252Smrg{
33876888252Smrg	CirPtr pCir;
33976888252Smrg	vgaHWPtr hwp;
34076888252Smrg	MessageType from;
34176888252Smrg	int i;
34276888252Smrg	ClockRangePtr clockRanges;
34376888252Smrg	int fbPCIReg, ioPCIReg;
34476888252Smrg	char *s;
34576888252Smrg
34676888252Smrg	if (flags & PROBE_DETECT)  {
34776888252Smrg	  cirProbeDDC( pScrn, xf86GetEntityInfo(pScrn->entityList[0])->index );
34876888252Smrg	  return TRUE;
34976888252Smrg	}
35076888252Smrg
35176888252Smrg#ifdef LG_DEBUG
35276888252Smrg	ErrorF("LgPreInit\n");
35376888252Smrg#endif
35476888252Smrg
35576888252Smrg	/* Check the number of entities, and fail if it isn't one. */
35676888252Smrg	if (pScrn->numEntities != 1)
35776888252Smrg		return FALSE;
35876888252Smrg
35976888252Smrg	/* The vgahw module should be loaded here when needed */
36076888252Smrg	if (!xf86LoadSubModule(pScrn, "vgahw"))
36176888252Smrg		return FALSE;
36276888252Smrg
36376888252Smrg	/*
36476888252Smrg	 * Allocate a vgaHWRec
36576888252Smrg	 */
36676888252Smrg	if (!vgaHWGetHWRec(pScrn))
36776888252Smrg		return FALSE;
36876888252Smrg
36976888252Smrg	hwp = VGAHWPTR(pScrn);
37076888252Smrg	vgaHWGetIOBase(hwp);
37176888252Smrg
37276888252Smrg	/* Allocate the LgRec driverPrivate */
37376888252Smrg	if (!LgGetRec(pScrn))
37476888252Smrg		return FALSE;
37576888252Smrg
37676888252Smrg	pCir = CIRPTR(pScrn);
37776888252Smrg	pCir->pScrn = pScrn;
37876888252Smrg	pCir->PIOReg = hwp->PIOOffset + 0x3CE;
37976888252Smrg
38076888252Smrg	/* Get the entity, and make sure it is PCI. */
38176888252Smrg	pCir->pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
38276888252Smrg	if (pCir->pEnt->location.type != BUS_PCI)
38376888252Smrg		return FALSE;
38476888252Smrg	pCir->Chipset = pCir->pEnt->chipset;
38576888252Smrg
38676888252Smrg	/* Find the PCI info for this screen */
38776888252Smrg	pCir->PciInfo = xf86GetPciInfoForEntity(pCir->pEnt->index);
3881ae1b5e8Smrg	pCir->PciTag = pciTag(PCI_DEV_BUS(pCir->PciInfo),
3891ae1b5e8Smrg			      PCI_DEV_DEV(pCir->PciInfo),
3901ae1b5e8Smrg			      PCI_DEV_FUNC(pCir->PciInfo));
39176888252Smrg
39276888252Smrg	if (xf86LoadSubModule(pScrn, "int10")) {
39376888252Smrg	    xf86Int10InfoPtr int10InfoPtr;
39476888252Smrg
39576888252Smrg	    int10InfoPtr = xf86InitInt10(pCir->pEnt->index);
39676888252Smrg
39776888252Smrg	    if (int10InfoPtr)
39876888252Smrg		xf86FreeInt10(int10InfoPtr);
39976888252Smrg	}
40076888252Smrg
40176888252Smrg	/* Set pScrn->monitor */
40276888252Smrg	pScrn->monitor = pScrn->confScreen->monitor;
40376888252Smrg
40476888252Smrg	/*
40576888252Smrg	 * The first thing we should figure out is the depth, bpp, etc.
40676888252Smrg	 * We support both 24bpp and 32bpp layouts, so indicate that.
40776888252Smrg	 */
40876888252Smrg	if (!xf86SetDepthBpp(pScrn, 0, 0, 0, Support24bppFb | Support32bppFb |
40976888252Smrg							SupportConvert32to24 | PreferConvert32to24)) {
41076888252Smrg		return FALSE;
41176888252Smrg    }
41276888252Smrg	/* Check that the returned depth is one we support */
41376888252Smrg	switch (pScrn->depth) {
41476888252Smrg	case 8:
41576888252Smrg	case 15:
41676888252Smrg	case 16:
41776888252Smrg	case 24:
41876888252Smrg	case 32:
41976888252Smrg		/* OK */
42076888252Smrg		break;
42176888252Smrg	default:
42276888252Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
42376888252Smrg			"Given depth (%d) is not supported by this driver\n", pScrn->depth);
42476888252Smrg		return FALSE;
42576888252Smrg	}
42676888252Smrg	xf86PrintDepthBpp(pScrn);
42776888252Smrg
42876888252Smrg	/* Get the depth24 pixmap format */
42976888252Smrg	if (pScrn->depth == 24 && pix24bpp == 0)
43076888252Smrg		pix24bpp = xf86GetBppFromDepth(pScrn, 24);
43176888252Smrg
43276888252Smrg	/*
43376888252Smrg	 * This must happen after pScrn->display has been set because
43476888252Smrg	 * xf86SetWeight references it.
43576888252Smrg	 */
43676888252Smrg	if (pScrn->depth > 8) {
43776888252Smrg		/* The defaults are OK for us */
43876888252Smrg		rgb zeros = {0, 0, 0};
43976888252Smrg
44076888252Smrg		/* !!! I think we can force 5-6-5 weight for 16bpp here for
44176888252Smrg		   the 5462. */
44276888252Smrg
44376888252Smrg		if (!xf86SetWeight(pScrn, zeros, zeros)) {
44476888252Smrg			return FALSE;
44576888252Smrg		} else {
44676888252Smrg			/* XXX check that weight returned is supported */
44776888252Smrg			;
44876888252Smrg		}
44976888252Smrg	}
45076888252Smrg
45176888252Smrg	if (!xf86SetDefaultVisual(pScrn, -1))
45276888252Smrg		return FALSE;
45376888252Smrg
45476888252Smrg
45576888252Smrg	/* Collect all of the relevant option flags (fill in pScrn->options) */
45676888252Smrg	xf86CollectOptions(pScrn, NULL);
45776888252Smrg
45876888252Smrg	/* Process the options */
45976888252Smrg	if (!(pCir->Options = xalloc(sizeof(LgOptions))))
46076888252Smrg		return FALSE;
46176888252Smrg	memcpy(pCir->Options, LgOptions, sizeof(LgOptions));
46276888252Smrg	xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pCir->Options);
46376888252Smrg
46476888252Smrg	pScrn->rgbBits = 6;
46576888252Smrg	from = X_DEFAULT;
46676888252Smrg	pCir->HWCursor = FALSE;
46776888252Smrg	if (xf86GetOptValBool(pCir->Options, OPTION_HW_CURSOR, &pCir->HWCursor))
46876888252Smrg		from = X_CONFIG;
46976888252Smrg
47076888252Smrg	xf86DrvMsg(pScrn->scrnIndex, from, "Using %s cursor\n",
47176888252Smrg		pCir->HWCursor ? "HW" : "SW");
47276888252Smrg	if (xf86ReturnOptValBool(pCir->Options, OPTION_NOACCEL, FALSE)) {
47376888252Smrg		pCir->NoAccel = TRUE;
47476888252Smrg		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Acceleration disabled\n");
47576888252Smrg	}
47676888252Smrg	if (pScrn->bitsPerPixel < 8) {
47776888252Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
47876888252Smrg			"Cannot use in less than 8 bpp\n");
47976888252Smrg		return FALSE;
48076888252Smrg	}
48176888252Smrg	/*
48276888252Smrg	 * Set the ChipRev, allowing config file entries to
48376888252Smrg	 * override.
48476888252Smrg	 */
48576888252Smrg	if (pCir->pEnt->device->chipRev >= 0) {
48676888252Smrg		pCir->ChipRev = pCir->pEnt->device->chipRev;
48776888252Smrg		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n",
48876888252Smrg			pCir->ChipRev);
48976888252Smrg	} else {
4901ae1b5e8Smrg	        pCir->ChipRev = PCI_DEV_REVISION(pCir->PciInfo);
49176888252Smrg	}
49276888252Smrg
49376888252Smrg	/* Cirrus swapped the FB and IO registers in the 5465 (by design). */
49476888252Smrg	if (PCI_CHIP_GD5465 == pCir->Chipset) {
49576888252Smrg		fbPCIReg = 0;
49676888252Smrg		ioPCIReg = 1;
49776888252Smrg	} else {
49876888252Smrg		fbPCIReg = 1;
49976888252Smrg		ioPCIReg = 0;
50076888252Smrg	}
50176888252Smrg
50276888252Smrg	/* Find the frame buffer base address */
50376888252Smrg	if (pCir->pEnt->device->MemBase != 0) {
50476888252Smrg		/* Require that the config file value matches one of the PCI values. */
50576888252Smrg		if (!xf86CheckPciMemBase(pCir->PciInfo, pCir->pEnt->device->MemBase)) {
50676888252Smrg			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
50776888252Smrg				"MemBase 0x%08lX doesn't match any PCI base register.\n",
50876888252Smrg				pCir->pEnt->device->MemBase);
50976888252Smrg			return FALSE;
51076888252Smrg		}
51176888252Smrg		pCir->FbAddress = pCir->pEnt->device->MemBase;
51276888252Smrg		from = X_CONFIG;
51376888252Smrg	} else {
5141ae1b5e8Smrg		if (PCI_REGION_BASE(pCir->PciInfo, fbPCIReg, REGION_MEM) != 0) {
5151ae1b5e8Smrg			pCir->FbAddress = PCI_REGION_BASE(pCir->PciInfo, fbPCIReg, REGION_MEM) & 0xff000000;
51676888252Smrg			from = X_PROBED;
51776888252Smrg		} else {
51876888252Smrg			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
51976888252Smrg				"No valid FB address in PCI config space\n");
52076888252Smrg			LgFreeRec(pScrn);
52176888252Smrg			return FALSE;
52276888252Smrg		}
52376888252Smrg	}
52476888252Smrg	xf86DrvMsg(pScrn->scrnIndex, from, "Linear framebuffer at 0x%lX\n",
52576888252Smrg		(unsigned long)pCir->FbAddress);
52676888252Smrg
52776888252Smrg	/* Find the MMIO base address */
52876888252Smrg	if (pCir->pEnt->device->IOBase != 0) {
52976888252Smrg		/* Require that the config file value matches one of the PCI values. */
53076888252Smrg		if (!xf86CheckPciMemBase(pCir->PciInfo, pCir->pEnt->device->IOBase)) {
53176888252Smrg			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
53276888252Smrg				"IOBase 0x%08lX doesn't match any PCI base register.\n",
53376888252Smrg				pCir->pEnt->device->IOBase);
53476888252Smrg			return FALSE;
53576888252Smrg		}
53676888252Smrg		pCir->IOAddress = pCir->pEnt->device->IOBase;
53776888252Smrg		from = X_CONFIG;
53876888252Smrg	} else {
5391ae1b5e8Smrg		if (PCI_REGION_BASE(pCir->PciInfo, ioPCIReg, REGION_MEM) != 0) {
5401ae1b5e8Smrg			pCir->IOAddress = PCI_REGION_BASE(pCir->PciInfo, ioPCIReg, REGION_MEM) & 0xfffff000;
54176888252Smrg			from = X_PROBED;
54276888252Smrg		} else {
54376888252Smrg			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
54476888252Smrg			"No valid MMIO address in PCI config space\n");
54576888252Smrg		}
54676888252Smrg	}
54776888252Smrg	xf86DrvMsg(pScrn->scrnIndex, from, "MMIO registers at 0x%lX\n",
54876888252Smrg		(unsigned long)pCir->IOAddress);
54976888252Smrg
55076888252Smrg	/*
55176888252Smrg	 * If the user has specified the amount of memory in the XF86Config
55276888252Smrg	 * file, we respect that setting.
55376888252Smrg	 */
55476888252Smrg	if (pCir->pEnt->device->videoRam != 0) {
55576888252Smrg		pScrn->videoRam = pCir->pEnt->device->videoRam;
55676888252Smrg		from = X_CONFIG;
55776888252Smrg	} else {
55876888252Smrg		pScrn->videoRam = LgCountRam(pScrn);
55976888252Smrg		from = X_PROBED;
56076888252Smrg	}
56176888252Smrg	if (2048 == pScrn->videoRam) {
56276888252Smrg		/* Two-way interleaving */
56376888252Smrg		pCir->chip.lg->memInterleave = 0x40;
56476888252Smrg	} else if (4096 == pScrn->videoRam || 8192 == pScrn->videoRam) {
56576888252Smrg		/* Four-way interleaving */
56676888252Smrg		pCir->chip.lg->memInterleave = 0x80;
56776888252Smrg	} else {
56876888252Smrg		/* One-way interleaving */
56976888252Smrg		pCir->chip.lg->memInterleave = 0x00;
57076888252Smrg	}
57176888252Smrg
57276888252Smrg	xf86DrvMsg(pScrn->scrnIndex, from, "VideoRAM: %d kByte\n",
57376888252Smrg				pScrn->videoRam);
57476888252Smrg
57576888252Smrg	pCir->FbMapSize = pScrn->videoRam * 1024;
57676888252Smrg	pCir->IoMapSize = 0x4000;	/* 16K for moment,  will increase */
57776888252Smrg
5781e66b2a2Smrg#ifndef XSERVER_LIBPCIACCESS
57976888252Smrg	pScrn->racIoFlags =   RAC_COLORMAP
58076888252Smrg#ifndef EXPERIMENTAL
58176888252Smrg	  | RAC_VIEWPORT
58276888252Smrg#endif
58376888252Smrg;
58476888252Smrg 	xf86SetOperatingState(resVgaMem, pCir->pEnt->index, ResUnusedOpr);
58576888252Smrg
58676888252Smrg	/* Register the PCI-assigned resources. */
58776888252Smrg	if (xf86RegisterResources(pCir->pEnt->index, NULL, ResExclusive)) {
58876888252Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
58976888252Smrg			"xf86RegisterResources() found resource conflicts\n");
59076888252Smrg		return FALSE;
59176888252Smrg	}
5921e66b2a2Smrg#endif
59376888252Smrg	if (!xf86LoadSubModule(pScrn, "ddc")) {
59476888252Smrg		LgFreeRec(pScrn);
59576888252Smrg		return FALSE;
59676888252Smrg	}
59776888252Smrg
59876888252Smrg#if LGuseI2C
59976888252Smrg	if (!xf86LoadSubModule(pScrn, "i2c")) {
60076888252Smrg		LgFreeRec(pScrn);
60176888252Smrg		return FALSE;
60276888252Smrg	}
60376888252Smrg#endif
60476888252Smrg
60576888252Smrg	/* Read and print the monitor DDC information */
60676888252Smrg	pScrn->monitor->DDC = LgDoDDC(pScrn);
60776888252Smrg
60876888252Smrg	/* The gamma fields must be initialised when using the new cmap code */
60976888252Smrg	if (pScrn->depth > 1) {
61076888252Smrg		Gamma zeros = {0.0, 0.0, 0.0};
61176888252Smrg
61276888252Smrg		if (!xf86SetGamma(pScrn, zeros))
61376888252Smrg			return FALSE;
61476888252Smrg	}
61576888252Smrg	if (xf86GetOptValBool(pCir->Options,
61676888252Smrg			      OPTION_SHADOW_FB,&pCir->shadowFB))
61776888252Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ShadowFB %s.\n",
61876888252Smrg		       pCir->shadowFB ? "enabled" : "disabled");
61976888252Smrg
62076888252Smrg	if ((s = xf86GetOptValString(pCir->Options, OPTION_ROTATE))) {
62176888252Smrg	    if(!xf86NameCmp(s, "CW")) {
62276888252Smrg		/* accel is disabled below for shadowFB */
62376888252Smrg		pCir->shadowFB = TRUE;
62476888252Smrg		pCir->rotate = 1;
62576888252Smrg		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
62676888252Smrg			   "Rotating screen clockwise - acceleration disabled\n");
62776888252Smrg	    } else if(!xf86NameCmp(s, "CCW")) {
62876888252Smrg		pCir->shadowFB = TRUE;
62976888252Smrg		pCir->rotate = -1;
63076888252Smrg		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,  "Rotating screen"
63176888252Smrg			   "counter clockwise - acceleration disabled\n");
63276888252Smrg	    } else {
63376888252Smrg		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "\"%s\" is not a valid"
63476888252Smrg			   "value for Option \"Rotate\"\n", s);
63576888252Smrg		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
63676888252Smrg			   "Valid options are \"CW\" or \"CCW\"\n");
63776888252Smrg	    }
63876888252Smrg	}
63976888252Smrg
64076888252Smrg	if (pCir->shadowFB && !pCir->NoAccel) {
64176888252Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
64276888252Smrg		       "HW acceleration not supported with \"shadowFB\".\n");
64376888252Smrg	    pCir->NoAccel = TRUE;
64476888252Smrg	}
64576888252Smrg
64676888252Smrg	if (pCir->rotate && pCir->HWCursor) {
64776888252Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
64876888252Smrg		       "HW cursor not supported with \"rotate\".\n");
64976888252Smrg	    pCir->HWCursor = FALSE;
65076888252Smrg	}
65176888252Smrg
65276888252Smrg	/* We use a programmable clock */
65376888252Smrg	pScrn->progClock = TRUE;
65476888252Smrg
65576888252Smrg	/* XXX Set HW cursor use */
65676888252Smrg
65776888252Smrg	/* Set the min pixel clock */
65876888252Smrg	pCir->MinClock = 12000;	/* XXX Guess, need to check this */
65976888252Smrg	xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "Min pixel clock is %d MHz\n",
66076888252Smrg				pCir->MinClock / 1000);
66176888252Smrg	/*
66276888252Smrg	 * If the user has specified ramdac speed in the XF86Config
66376888252Smrg	 * file, we respect that setting.
66476888252Smrg	 */
66576888252Smrg	if (pCir->pEnt->device->dacSpeeds[0]) {
66676888252Smrg		ErrorF("Do not specify a Clocks line for Cirrus chips\n");
66776888252Smrg		return FALSE;
66876888252Smrg	} else {
66976888252Smrg		int speed;
67076888252Smrg		int *p;
67176888252Smrg		switch (pCir->Chipset) {
67276888252Smrg		case PCI_CHIP_GD5462:
67376888252Smrg			p = gd5462_MaxClocks;
67476888252Smrg			break;
67576888252Smrg		case PCI_CHIP_GD5464:
67676888252Smrg		case PCI_CHIP_GD5464BD:
67776888252Smrg			p = gd5464_MaxClocks;
67876888252Smrg			break;
67976888252Smrg		case PCI_CHIP_GD5465:
68076888252Smrg			p = gd5465_MaxClocks;
68176888252Smrg			break;
68276888252Smrg		default:
68376888252Smrg			ErrorF("???\n");
68476888252Smrg			return FALSE;
68576888252Smrg		}
68676888252Smrg		switch (pScrn->bitsPerPixel) {
68776888252Smrg		case 8:
68876888252Smrg			speed = p[1];
68976888252Smrg			break;
69076888252Smrg		case 15:
69176888252Smrg		case 16:
69276888252Smrg			speed = p[2];
69376888252Smrg			break;
69476888252Smrg		case 24:
69576888252Smrg			speed = p[3];
69676888252Smrg			break;
69776888252Smrg		case 32:
69876888252Smrg			speed = p[4];
69976888252Smrg			break;
70076888252Smrg		default:
70176888252Smrg			/* Should not get here */
70276888252Smrg			speed = 0;
70376888252Smrg			break;
70476888252Smrg		}
70576888252Smrg		pCir->MaxClock = speed;
70676888252Smrg		from = X_PROBED;
70776888252Smrg	}
70876888252Smrg	xf86DrvMsg(pScrn->scrnIndex, from, "Max pixel clock is %d MHz\n",
70976888252Smrg				pCir->MaxClock / 1000);
71076888252Smrg
71176888252Smrg	/*
71276888252Smrg	 * Setup the ClockRanges, which describe what clock ranges are available,
71376888252Smrg	 * and what sort of modes they can be used for.
71476888252Smrg	 */
71576888252Smrg	clockRanges = xnfcalloc(sizeof(ClockRange), 1);
71676888252Smrg	clockRanges->next = NULL;
71776888252Smrg	clockRanges->minClock = pCir->MinClock;
71876888252Smrg	clockRanges->maxClock = pCir->MaxClock;
71976888252Smrg	clockRanges->clockIndex = -1;		/* programmable */
72076888252Smrg	clockRanges->interlaceAllowed = FALSE;	/* XXX check this */
72176888252Smrg	clockRanges->doubleScanAllowed = FALSE;	/* XXX check this */
72276888252Smrg	clockRanges->doubleScanAllowed = FALSE;	/* XXX check this */
72376888252Smrg	clockRanges->doubleScanAllowed = FALSE;	/* XXX check this */
72476888252Smrg	clockRanges->ClockMulFactor = 1;
72576888252Smrg	clockRanges->ClockDivFactor = 1;
72676888252Smrg	clockRanges->PrivFlags = 0;
72776888252Smrg
72876888252Smrg	/* Depending upon what sized tiles used, either 128 or 256. */
72976888252Smrg	/* Aw, heck.  Just say 128. */
73076888252Smrg	pCir->Rounding = 128 >> pCir->BppShift;
73176888252Smrg
73276888252Smrg	/*
73376888252Smrg	 * xf86ValidateModes will check that the mode HTotal and VTotal values
73476888252Smrg	 * don't exceed the chipset's limit if pScrn->maxHValue and
73576888252Smrg	 * pScrn->maxVValue are set.  Since our CIRValidMode() already takes
73676888252Smrg	 * care of this, we don't worry about setting them here.
73776888252Smrg	 */
73876888252Smrg
73976888252Smrg	i = xf86ValidateModes(pScrn, pScrn->monitor->Modes, pScrn->display->modes,
74076888252Smrg							clockRanges,
74176888252Smrg							LgLinePitches[pScrn->bitsPerPixel / 8 - 1],
74276888252Smrg							0, 0, 128 * 8,
74376888252Smrg							0, 0, /* Any virtual height is allowed. */
74476888252Smrg							pScrn->display->virtualX,
74576888252Smrg							pScrn->display->virtualY,
74676888252Smrg							pCir->FbMapSize,
74776888252Smrg							LOOKUP_BEST_REFRESH);
74876888252Smrg
74976888252Smrg	pCir->chip.lg->lineDataIndex = LgFindLineData(pScrn->displayWidth,
75076888252Smrg										pScrn->bitsPerPixel);
75176888252Smrg
75276888252Smrg	if (i == -1) {
75376888252Smrg		LgFreeRec(pScrn);
75476888252Smrg		return FALSE;
75576888252Smrg	}
75676888252Smrg
75776888252Smrg	/* Prune the modes marked as invalid */
75876888252Smrg	xf86PruneDriverModes(pScrn);
75976888252Smrg
76076888252Smrg	if (i == 0 || pScrn->modes == NULL) {
76176888252Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n");
76276888252Smrg		LgFreeRec(pScrn);
76376888252Smrg		return FALSE;
76476888252Smrg	}
76576888252Smrg
76676888252Smrg	/*
76776888252Smrg	 * Set the CRTC parameters for all of the modes based on the type
76876888252Smrg	 * of mode, and the chipset's interlace requirements.
76976888252Smrg	 *
77076888252Smrg	 * Calling this is required if the mode->Crtc* values are used by the
77176888252Smrg	 * driver and if the driver doesn't provide code to set them.  They
77276888252Smrg	 * are not pre-initialised at all.
77376888252Smrg	 */
77476888252Smrg	xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V);
77576888252Smrg
77676888252Smrg	/* Set the current mode to the first in the list */
77776888252Smrg	pScrn->currentMode = pScrn->modes;
77876888252Smrg
77976888252Smrg	/* Print the list of modes being used */
78076888252Smrg	xf86PrintModes(pScrn);
78176888252Smrg
78276888252Smrg	/* Set display resolution */
78376888252Smrg	xf86SetDpi(pScrn, 0, 0);
78476888252Smrg
78576888252Smrg	/* Load bpp-specific modules */
78676888252Smrg	switch (pScrn->bitsPerPixel) {
78776888252Smrg	case 8:
78876888252Smrg	case 16:
78976888252Smrg	case 24:
79076888252Smrg	case 32:
79176888252Smrg	    if (xf86LoadSubModule(pScrn, "fb") == NULL) {
79276888252Smrg	         LgFreeRec(pScrn);
79376888252Smrg		 return FALSE;
79476888252Smrg	    }
79576888252Smrg	    break;
79676888252Smrg	}
79776888252Smrg
79876888252Smrg	/* Load XAA if needed */
79976888252Smrg	if (!pCir->NoAccel) {
80076888252Smrg		if (!xf86LoadSubModule(pScrn, "xaa")) {
80176888252Smrg			LgFreeRec(pScrn);
80276888252Smrg			return FALSE;
80376888252Smrg		}
80476888252Smrg	}
80576888252Smrg
80676888252Smrg	/* Load ramdac if needed */
80776888252Smrg	if (pCir->HWCursor) {
80876888252Smrg		if (!xf86LoadSubModule(pScrn, "ramdac")) {
80976888252Smrg			LgFreeRec(pScrn);
81076888252Smrg			return FALSE;
81176888252Smrg		}
81276888252Smrg	}
81376888252Smrg
81476888252Smrg	if (pCir->shadowFB) {
81576888252Smrg	    if (!xf86LoadSubModule(pScrn, "shadowfb")) {
81676888252Smrg		LgFreeRec(pScrn);
81776888252Smrg		return FALSE;
81876888252Smrg	    }
81976888252Smrg	}
82076888252Smrg
82176888252Smrg	return TRUE;
82276888252Smrg}
82376888252Smrg
82476888252Smrg/*
82576888252Smrg * This function saves the video state.
82676888252Smrg */
82776888252Smrgstatic void
82876888252SmrgLgSave(ScrnInfoPtr pScrn)
82976888252Smrg{
83076888252Smrg	CirPtr pCir = CIRPTR(pScrn);
83176888252Smrg	vgaHWPtr hwp = VGAHWPTR(pScrn);
83276888252Smrg
83376888252Smrg#ifdef LG_DEBUG
83476888252Smrg	ErrorF("LgSave\n");
83576888252Smrg#endif
83676888252Smrg
83776888252Smrg	vgaHWSave(pScrn, &VGAHWPTR(pScrn)->SavedReg, VGA_SR_ALL);
83876888252Smrg
83976888252Smrg	pCir->chip.lg->ModeReg.ExtVga[CR1A] = pCir->chip.lg->SavedReg.ExtVga[CR1A] = hwp->readCrtc(hwp, 0x1A);
84076888252Smrg	pCir->chip.lg->ModeReg.ExtVga[CR1B] = pCir->chip.lg->SavedReg.ExtVga[CR1B] = hwp->readCrtc(hwp, 0x1B);
84176888252Smrg	pCir->chip.lg->ModeReg.ExtVga[CR1D] = pCir->chip.lg->SavedReg.ExtVga[CR1D] = hwp->readCrtc(hwp, 0x1D);
84276888252Smrg	pCir->chip.lg->ModeReg.ExtVga[CR1E] = pCir->chip.lg->SavedReg.ExtVga[CR1E] = hwp->readCrtc(hwp, 0x1E);
84376888252Smrg	pCir->chip.lg->ModeReg.ExtVga[SR07] = pCir->chip.lg->SavedReg.ExtVga[SR07] = hwp->readSeq(hwp, 0x07);
84476888252Smrg	pCir->chip.lg->ModeReg.ExtVga[SR0E] = pCir->chip.lg->SavedReg.ExtVga[SR0E] = hwp->readSeq(hwp, 0x0E);
84576888252Smrg	pCir->chip.lg->ModeReg.ExtVga[SR12] = pCir->chip.lg->SavedReg.ExtVga[SR12] = hwp->readSeq(hwp, 0x12);
84676888252Smrg	pCir->chip.lg->ModeReg.ExtVga[SR13] = pCir->chip.lg->SavedReg.ExtVga[SR13] = hwp->readSeq(hwp, 0x13);
84776888252Smrg	pCir->chip.lg->ModeReg.ExtVga[SR1E] = pCir->chip.lg->SavedReg.ExtVga[SR1E] = hwp->readSeq(hwp, 0x1E);
84876888252Smrg
84976888252Smrg	pCir->chip.lg->ModeReg.FORMAT = pCir->chip.lg->SavedReg.FORMAT = memrw(0xC0);
85076888252Smrg
85176888252Smrg	pCir->chip.lg->ModeReg.VSC = pCir->chip.lg->SavedReg.VSC = memrl(0x3FC);
85276888252Smrg
85376888252Smrg	pCir->chip.lg->ModeReg.DTTC = pCir->chip.lg->SavedReg.DTTC = memrw(0xEA);
85476888252Smrg
85576888252Smrg	if (pCir->Chipset == PCI_CHIP_GD5465) {
85676888252Smrg	    pCir->chip.lg->ModeReg.TileCtrl = pCir->chip.lg->SavedReg.TileCtrl = memrw(0x2C4);
85776888252Smrg	}
85876888252Smrg
85976888252Smrg	pCir->chip.lg->ModeReg.TILE = pCir->chip.lg->SavedReg.TILE = memrb(0x407);
86076888252Smrg
86176888252Smrg	if (pCir->Chipset == PCI_CHIP_GD5465)
86276888252Smrg	    pCir->chip.lg->ModeReg.BCLK = pCir->chip.lg->SavedReg.BCLK = memrb(0x2C0);
86376888252Smrg	else
86476888252Smrg	    pCir->chip.lg->ModeReg.BCLK = pCir->chip.lg->SavedReg.BCLK = memrb(0x8C);
86576888252Smrg
86676888252Smrg	pCir->chip.lg->ModeReg.CONTROL = pCir->chip.lg->SavedReg.CONTROL = memrw(0x402);
86776888252Smrg}
86876888252Smrg
86976888252Smrg/*
87076888252Smrg * Initialise a new mode.  This is currently still using the old
87176888252Smrg * "initialise struct, restore/write struct to HW" model.  That could
87276888252Smrg * be changed.
87376888252Smrg */
87476888252Smrg
87576888252Smrgstatic Bool
87676888252SmrgLgModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
87776888252Smrg{
87876888252Smrg	vgaHWPtr hwp;
87976888252Smrg	CirPtr pCir;
88076888252Smrg	int width;
88176888252Smrg	Bool VDiv2 = FALSE;
88276888252Smrg	CARD16 clockData;
88376888252Smrg	LgLineDataPtr lineData;
88476888252Smrg
88576888252Smrg#ifdef LG_DEBUG
88676888252Smrg	ErrorF("LgModeInit %d bpp,   %d   %d %d %d %d   %d %d %d %d\n",
88776888252Smrg				pScrn->bitsPerPixel,
88876888252Smrg				mode->Clock,
88976888252Smrg				mode->HDisplay,
89076888252Smrg				mode->HSyncStart,
89176888252Smrg				mode->HSyncEnd,
89276888252Smrg				mode->HTotal,
89376888252Smrg				mode->VDisplay,
89476888252Smrg				mode->VSyncStart,
89576888252Smrg				mode->VSyncEnd,
89676888252Smrg				mode->VTotal);
89776888252Smrg
89876888252Smrg	ErrorF("LgModeInit: depth %d bits\n", pScrn->depth);
89976888252Smrg#endif
90076888252Smrg
90176888252Smrg	pCir = CIRPTR(pScrn);
90276888252Smrg	hwp = VGAHWPTR(pScrn);
90376888252Smrg	vgaHWUnlock(hwp);
90476888252Smrg
90576888252Smrg	if (mode->VTotal >= 1024 && !(mode->Flags & V_INTERLACE)) {
90676888252Smrg		/* For non-interlaced vertical timing >= 1024, the vertical timings */
90776888252Smrg		/* are divided by 2 and VGA CRTC 0x17 bit 2 is set. */
90876888252Smrg		if (!mode->CrtcVAdjusted) {
90976888252Smrg			mode->CrtcVDisplay >>= 1;
91076888252Smrg			mode->CrtcVSyncStart >>= 1;
91176888252Smrg			mode->CrtcVSyncEnd >>= 1;
91276888252Smrg			mode->CrtcVTotal >>= 1;
91376888252Smrg			mode->CrtcVAdjusted = TRUE;
91476888252Smrg		}
91576888252Smrg		VDiv2 = TRUE;
91676888252Smrg	}
91776888252Smrg
91876888252Smrg	/* Initialise the ModeReg values */
91976888252Smrg	if (!vgaHWInit(pScrn, mode))
92076888252Smrg		return FALSE;
92176888252Smrg	pScrn->vtSema = TRUE;
92276888252Smrg
92376888252Smrg	if (VDiv2)
92476888252Smrg		hwp->ModeReg.CRTC[0x17] |= 0x04;
92576888252Smrg
92676888252Smrg#ifdef LG_DEBUG
92776888252Smrg	ErrorF("SynthClock = %d\n", mode->SynthClock);
92876888252Smrg#endif
92976888252Smrg	hwp->IOBase = 0x3D0;
93076888252Smrg	hwp->ModeReg.MiscOutReg |= 0x01;
93176888252Smrg#if 0 /* Mono address */
93276888252Smrg	hwp->IOBase = 0x3B0;
93376888252Smrg	hwp->ModeReg.MiscOutReg &= ~0x01;
93476888252Smrg#endif
93576888252Smrg
93676888252Smrg
93776888252Smrg	/* ??? Should these be both ...End or ...Start, not one of each? */
93876888252Smrg	pCir->chip.lg->ModeReg.ExtVga[CR1A] = (((mode->CrtcVSyncStart + 1) & 0x300 ) >> 2)
93976888252Smrg								| (((mode->CrtcHSyncEnd >> 3) & 0xC0) >> 2);
94076888252Smrg
94176888252Smrg	width = pScrn->displayWidth * pScrn->bitsPerPixel / 8;
94276888252Smrg	if (pScrn->bitsPerPixel == 1)
94376888252Smrg		width <<= 2;
94476888252Smrg	hwp->ModeReg.CRTC[0x13] = (width + 7) >> 3;
94576888252Smrg	/* Offset extension (see CR13) */
94676888252Smrg	pCir->chip.lg->ModeReg.ExtVga[CR1B] &= 0xEF;
94776888252Smrg	pCir->chip.lg->ModeReg.ExtVga[CR1B] |= (((width + 7) >> 3) & 0x100)?0x10:0x00;
94876888252Smrg	pCir->chip.lg->ModeReg.ExtVga[CR1B] |= 0x22;
94976888252Smrg	pCir->chip.lg->ModeReg.ExtVga[CR1D] = (((width + 7) >> 3) & 0x200)?0x01:0x00;
95076888252Smrg
95176888252Smrg	/* Set the 28th bit to enable extended modes. */
95276888252Smrg	pCir->chip.lg->ModeReg.VSC = 0x10000000;
95376888252Smrg
95476888252Smrg	/* Overflow register (sure are a lot of overflow bits around...) */
95576888252Smrg	pCir->chip.lg->ModeReg.ExtVga[CR1E] = 0x00;
95676888252Smrg	pCir->chip.lg->ModeReg.ExtVga[CR1E] |= ((mode->CrtcHTotal>>3 & 0x0100)?1:0)<<7;
95776888252Smrg	pCir->chip.lg->ModeReg.ExtVga[CR1E] |= ((mode->CrtcHDisplay>>3 & 0x0100)?1:0)<<6;
95876888252Smrg	pCir->chip.lg->ModeReg.ExtVga[CR1E] |= ((mode->CrtcHSyncStart>>3 & 0x0100)?1:0)<<5;
95976888252Smrg	pCir->chip.lg->ModeReg.ExtVga[CR1E] |= ((mode->CrtcHSyncStart>>3 & 0x0100)?1:0)<<4;
96076888252Smrg	pCir->chip.lg->ModeReg.ExtVga[CR1E] |= ((mode->CrtcVTotal & 0x0400)?1:0)<<3;
96176888252Smrg	pCir->chip.lg->ModeReg.ExtVga[CR1E] |= ((mode->CrtcVDisplay & 0x0400)?1:0)<<2;
96276888252Smrg	pCir->chip.lg->ModeReg.ExtVga[CR1E] |= ((mode->CrtcVSyncStart & 0x0400)?1:0)<<1;
96376888252Smrg	pCir->chip.lg->ModeReg.ExtVga[CR1E] |= ((mode->CrtcVSyncStart & 0x0400)?1:0)<<0;
96476888252Smrg
96576888252Smrg	lineData = &LgLineData[pCir->chip.lg->lineDataIndex];
96676888252Smrg
96776888252Smrg	pCir->chip.lg->ModeReg.TILE = lineData->tilesPerLine & 0x3F;
96876888252Smrg
96976888252Smrg	if (8 == pScrn->bitsPerPixel) {
97076888252Smrg		pCir->chip.lg->ModeReg.FORMAT = 0x0000;
97176888252Smrg
97276888252Smrg		pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.TILE << 8) | 0x0080
97376888252Smrg							| (lineData->width << 6);
97476888252Smrg		pCir->chip.lg->ModeReg.CONTROL = 0x0000 | (lineData->width << 11);
97576888252Smrg
97676888252Smrg
97776888252Smrg		/* There is an optimal FIFO threshold value (lower 5 bits of DTTC)
97876888252Smrg		   for every resolution and color depth combination.  We'll hit
97976888252Smrg		   the highlights here, and get close for anything that's not
98076888252Smrg		   covered. */
98176888252Smrg		if (mode->CrtcHDisplay <= 640) {
98276888252Smrg			/* BAD numbers:  0x1E */
98376888252Smrg			/* GOOD numbers:  0x14 */
98476888252Smrg			pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) | (0x0014);
98576888252Smrg		} else if (mode->CrtcHDisplay <= 800) {
98676888252Smrg			/* BAD numbers:  0x16 */
98776888252Smrg			/* GOOD numbers:  0x13 0x14 */
98876888252Smrg			pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) | (0x0014);
98976888252Smrg		} else if (mode->CrtcHDisplay <= 1024) {
99076888252Smrg			/* BAD numbers:  */
99176888252Smrg			/* GOOD numbers: 0x15 */
99276888252Smrg			pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) | (0x0015);
99376888252Smrg		} else if (mode->CrtcHDisplay <= 1280) {
99476888252Smrg			/* BAD numbers:  */
99576888252Smrg			/* GOOD numbers:  0x16 */
99676888252Smrg			pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) | (0x0016);
99776888252Smrg		} else {
99876888252Smrg			/* BAD numbers:  */
99976888252Smrg			/* GOOD numbers:  */
100076888252Smrg			pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) | (0x0017);
100176888252Smrg		}
100276888252Smrg	} else if (16 == pScrn->bitsPerPixel) {
100376888252Smrg		/* !!! Assume 5-6-5 RGB mode (for now...) */
100476888252Smrg		pCir->chip.lg->ModeReg.FORMAT = 0x1400;
100576888252Smrg
100676888252Smrg		if (pScrn->depth == 15)
100776888252Smrg			pCir->chip.lg->ModeReg.FORMAT = 0x1600;
100876888252Smrg
100976888252Smrg		pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.TILE << 8) | 0x0080
101076888252Smrg							| (lineData->width << 6);
101176888252Smrg		pCir->chip.lg->ModeReg.CONTROL = 0x2000 | (lineData->width << 11);
101276888252Smrg
101376888252Smrg		if (mode->CrtcHDisplay <= 640) {
101476888252Smrg			/* BAD numbers:  0x12 */
101576888252Smrg			/* GOOD numbers: 0x10 */
101676888252Smrg			pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) | (0x0010);
101776888252Smrg		} else if (mode->CrtcHDisplay <= 800) {
101876888252Smrg			/* BAD numbers:  0x13 */
101976888252Smrg			/* GOOD numbers:  0x11 */
102076888252Smrg			pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) | (0x0011);
102176888252Smrg		} else if (mode->CrtcHDisplay <= 1024) {
102276888252Smrg			/* BAD numbers:  0x14 */
102376888252Smrg			/* GOOD numbers: 0x12  */
102476888252Smrg			pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) | (0x0012);
102576888252Smrg		} else if (mode->CrtcHDisplay <= 1280) {
102676888252Smrg			/* BAD numbers:   0x08 0x10 */
102776888252Smrg			/* Borderline numbers: 0x12 */
102876888252Smrg			/* GOOD numbers:  0x15 */
102976888252Smrg			pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) | (0x0015);
103076888252Smrg		} else {
103176888252Smrg			pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) | (0x0017);
103276888252Smrg		}
103376888252Smrg	} else if (24 == pScrn->bitsPerPixel) {
103476888252Smrg		pCir->chip.lg->ModeReg.FORMAT = 0x2400;
103576888252Smrg
103676888252Smrg		pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.TILE << 8) | 0x0080
103776888252Smrg							| (lineData->width << 6);
103876888252Smrg		pCir->chip.lg->ModeReg.CONTROL = 0x4000 | (lineData->width << 11);
103976888252Smrg
104076888252Smrg		if (mode->CrtcHDisplay <= 640) {
104176888252Smrg			/* BAD numbers:   */
104276888252Smrg			/* GOOD numbers:  0x10 */
104376888252Smrg			pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) | (0x0010);
104476888252Smrg		} else if (mode->CrtcHDisplay <= 800) {
104576888252Smrg			/* BAD numbers:   */
104676888252Smrg			/* GOOD numbers:   0x11 */
104776888252Smrg			pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) | (0x0011);
104876888252Smrg		} else if (mode->CrtcHDisplay <= 1024) {
104976888252Smrg			/* BAD numbers:  0x12 0x13 */
105076888252Smrg			/* Borderline numbers:  0x15 */
105176888252Smrg			/* GOOD numbers:  0x17 */
105276888252Smrg			pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) | (0x0017);
105376888252Smrg		} else if (mode->CrtcHDisplay <= 1280) {
105476888252Smrg			/* BAD numbers:   */
105576888252Smrg			/* GOOD numbers:  0x1E */
105676888252Smrg			pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) | (0x001E);
105776888252Smrg		} else {
105876888252Smrg			/* BAD numbers:   */
105976888252Smrg			/* GOOD numbers:  */
106076888252Smrg			pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) | (0x0020);
106176888252Smrg		}
106276888252Smrg	} else if (32 == pScrn->bitsPerPixel) {
106376888252Smrg		pCir->chip.lg->ModeReg.FORMAT = 0x3400;
106476888252Smrg
106576888252Smrg		pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.TILE << 8) | 0x0080
106676888252Smrg							| (lineData->width << 6);
106776888252Smrg		pCir->chip.lg->ModeReg.CONTROL = 0x6000 | (lineData->width << 11);
106876888252Smrg
106976888252Smrg		if (mode->CrtcHDisplay <= 640) {
107076888252Smrg			/* GOOD numbers:  0x0E */
107176888252Smrg			/* BAD numbers:  */
107276888252Smrg			pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) | (0x000E);
107376888252Smrg		} else if (mode->CrtcHDisplay <= 800) {
107476888252Smrg			/* GOOD numbers:  0x17 */
107576888252Smrg			/* BAD numbers:  */
107676888252Smrg			pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) | (0x0017);
107776888252Smrg		} else if (mode->CrtcHDisplay <= 1024) {
107876888252Smrg			/* GOOD numbers: 0x1D */
107976888252Smrg			/* OKAY numbers:  0x15 0x14 0x16 0x18 0x19 */
108076888252Smrg			/* BAD numbers:  0x0E 0x12 0x13 0x0D */
108176888252Smrg			pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) | (0x001D);
108276888252Smrg		} else if (mode->CrtcHDisplay <= 1280) {
108376888252Smrg			/* GOOD numbers:  */
108476888252Smrg			/* BAD numbers:  */
108576888252Smrg			pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) | (0x0022); /* 10 */
108676888252Smrg		} else {
108776888252Smrg			pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) | (0x0024);
108876888252Smrg		}
108976888252Smrg	} else {
109076888252Smrg		/* ??? What could it be?  Use some sane numbers. */
109176888252Smrg	}
109276888252Smrg
109376888252Smrg	/* Setup the appropriate memory interleaving */
109476888252Smrg	pCir->chip.lg->ModeReg.DTTC |= (pCir->chip.lg->memInterleave << 8);
109576888252Smrg	pCir->chip.lg->ModeReg.TILE |= pCir->chip.lg->memInterleave & 0xC0;
109676888252Smrg
109776888252Smrg	if (PCI_CHIP_GD5465 == pCir->Chipset) {
109876888252Smrg		/* The tile control information in the DTTC is also mirrored
109976888252Smrg		   elsewhere. */
110076888252Smrg		pCir->chip.lg->ModeReg.TileCtrl = pCir->chip.lg->ModeReg.DTTC & 0xFFC0;
110176888252Smrg
110276888252Smrg		/* The 5465's DTTC records _fetches_ per line, not
110376888252Smrg		   tiles per line.  Fetchs are 128-byte fetches. */
110476888252Smrg		if (pCir->chip.lg->ModeReg.DTTC & 0x0040) {
110576888252Smrg			/* Using 256-byte wide tiles.  Double the fetches
110676888252Smrg			   per line field. */
110776888252Smrg			pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.DTTC & 0xC0FF)
110876888252Smrg								| ((pCir->chip.lg->ModeReg.DTTC & 0x3F00) << 1);
110976888252Smrg		}
111076888252Smrg	}
111176888252Smrg
111276888252Smrg	/* Program the registers */
111376888252Smrg	vgaHWProtect(pScrn, TRUE);
111476888252Smrg	hwp->writeMiscOut(hwp, hwp->ModeReg.MiscOutReg);
111576888252Smrg
111676888252Smrg	clockData = LgSetClock(pCir, hwp, mode->SynthClock);
111776888252Smrg	pCir->chip.lg->ModeReg.ExtVga[SR0E] = (clockData >> 8) & 0xFF;
111876888252Smrg	pCir->chip.lg->ModeReg.ExtVga[SR1E] = clockData & 0xFF;
111976888252Smrg
112076888252Smrg	/* Write those registers out to the card. */
112176888252Smrg	LgRestoreLgRegs(pScrn, &pCir->chip.lg->ModeReg);
112276888252Smrg
112376888252Smrg	/* Programme the registers */
112476888252Smrg	vgaHWRestore(pScrn, &hwp->ModeReg, VGA_SR_MODE | VGA_SR_CMAP);
112576888252Smrg
112676888252Smrg	vgaHWProtect(pScrn, FALSE);
112776888252Smrg
112876888252Smrg	return TRUE;
112976888252Smrg}
113076888252Smrg
113176888252Smrgstatic int LgFindLineData(int displayWidth, int bpp)
113276888252Smrg{
113376888252Smrg	/* Find the smallest tile-line-pitch such that the total byte pitch
113476888252Smrg	 is greater than or equal to displayWidth*Bpp. */
113576888252Smrg	int i;
113676888252Smrg
113776888252Smrg	/* Some pitch sizes are duplicates in the table.  BUT, the invariant is
113876888252Smrg	 that the _first_ time a pitch occurs in the table is always _before_
113976888252Smrg	 all other pitches greater than it.  Said in another way... if all
114076888252Smrg	 duplicate entries from the table were removed, then the resulting pitch
114176888252Smrg	 values are strictly increasing. */
114276888252Smrg
114376888252Smrg	for (i = 0; LgLineData[i].pitch > 0; i++)
114476888252Smrg		if (LgLineData[i].pitch >= displayWidth*bpp>>3)
114576888252Smrg			return i;
114676888252Smrg
114776888252Smrg	/* Um, uh oh! */
114876888252Smrg	return -1;
114976888252Smrg}
115076888252Smrg
115176888252Smrg
115276888252Smrg
115376888252Smrg
115476888252Smrgstatic void
115576888252SmrgLgRestoreLgRegs(ScrnInfoPtr pScrn, LgRegPtr lgReg)
115676888252Smrg{
115776888252Smrg	CirPtr pCir;
115876888252Smrg	vgaHWPtr hwp;
115976888252Smrg	CARD8 cr1D;
116076888252Smrg
116176888252Smrg	pCir = CIRPTR(pScrn);
116276888252Smrg
116376888252Smrg	/* First, VGAish registers. */
116476888252Smrg	hwp = VGAHWPTR(pScrn);
116576888252Smrg	hwp->writeCrtc(hwp, 0x1A, lgReg->ExtVga[CR1A]);
116676888252Smrg	hwp->writeCrtc(hwp, 0x1B, lgReg->ExtVga[CR1B]);
116776888252Smrg	cr1D = (hwp->readCrtc(hwp, 0x1D) & ~1) | (lgReg->ExtVga[CR1D] & 0x01);
116876888252Smrg	hwp->writeCrtc(hwp, 0x1D, cr1D);
116976888252Smrg	hwp->writeCrtc(hwp, 0x1E, lgReg->ExtVga[CR1E]);
117076888252Smrg
117176888252Smrg	hwp->writeSeq(hwp, 0x07, lgReg->ExtVga[SR07]);
117276888252Smrg	hwp->writeSeq(hwp, 0x0E, lgReg->ExtVga[SR0E]);
117376888252Smrg	hwp->writeSeq(hwp, 0x12, lgReg->ExtVga[SR12]);
117476888252Smrg	hwp->writeSeq(hwp, 0x13, lgReg->ExtVga[SR13]);
117576888252Smrg	hwp->writeSeq(hwp, 0x1E, lgReg->ExtVga[SR1E]);
117676888252Smrg	memww(0xC0, lgReg->FORMAT);
117776888252Smrg
117876888252Smrg    /* Vendor Specific Control is touchy.  Only bit 28 is of concern. */
117976888252Smrg	memwl(0x3FC, ((memrl(0x3FC) & ~(1<<28)) | (lgReg->VSC & (1<<28))));
118076888252Smrg
118176888252Smrg	memww(0xEA, lgReg->DTTC);
118276888252Smrg
118376888252Smrg	if (pCir->Chipset == PCI_CHIP_GD5465) {
118476888252Smrg	    memww(0x2C4, lgReg->TileCtrl);
118576888252Smrg	}
118676888252Smrg
118776888252Smrg	memwb(0x407, lgReg->TILE);
118876888252Smrg
118976888252Smrg	if (pCir->Chipset == PCI_CHIP_GD5465)
119076888252Smrg	    memwb(0x2C0, lgReg->BCLK);
119176888252Smrg	else
119276888252Smrg	    memwb(0x8C, lgReg->BCLK);
119376888252Smrg
119476888252Smrg	memww(0x402, lgReg->CONTROL);
119576888252Smrg}
119676888252Smrg
119776888252Smrg/*
119876888252Smrg * Restore the initial (text) mode.
119976888252Smrg */
120076888252Smrgstatic void
120176888252SmrgLgRestore(ScrnInfoPtr pScrn)
120276888252Smrg{
120376888252Smrg	vgaHWPtr hwp;
120476888252Smrg	vgaRegPtr vgaReg;
120576888252Smrg	CirPtr pCir;
120676888252Smrg	LgRegPtr lgReg;
120776888252Smrg
120876888252Smrg#ifdef LG_DEBUG
120976888252Smrg	ErrorF("LgRestore  pScrn = %p\n", (void *)pScrn);
121076888252Smrg#endif
121176888252Smrg
121276888252Smrg	pCir = CIRPTR(pScrn);
121376888252Smrg	hwp = VGAHWPTR(pScrn);
121476888252Smrg	vgaReg = &hwp->SavedReg;
121576888252Smrg	lgReg = &pCir->chip.lg->SavedReg;
121676888252Smrg
121776888252Smrg	vgaHWProtect(pScrn, TRUE);
121876888252Smrg
121976888252Smrg	LgRestoreLgRegs(pScrn, lgReg);
122076888252Smrg
122176888252Smrg	vgaHWRestore(pScrn, vgaReg, VGA_SR_ALL);
122276888252Smrg	vgaHWProtect(pScrn, FALSE);
122376888252Smrg}
122476888252Smrg
122576888252Smrg/* Mandatory */
122676888252Smrg
122776888252Smrg/* This gets called at the start of each server generation */
122876888252Smrg
122976888252SmrgBool
123076888252SmrgLgScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
123176888252Smrg{
123276888252Smrg	/* The vgaHW references will disappear one day */
123376888252Smrg	ScrnInfoPtr pScrn;
123476888252Smrg	vgaHWPtr hwp;
123576888252Smrg	CirPtr pCir;
123676888252Smrg	int i, ret;
123776888252Smrg	VisualPtr visual;
123876888252Smrg	int displayWidth,width,height;
123976888252Smrg	unsigned char * FbBase = NULL;
124076888252Smrg
124176888252Smrg#ifdef LG_DEBUG
124276888252Smrg	ErrorF("LgScreenInit\n");
124376888252Smrg#endif
124476888252Smrg
124576888252Smrg	/*
124676888252Smrg	 * First get the ScrnInfoRec
124776888252Smrg	 */
124876888252Smrg	pScrn = xf86Screens[pScreen->myNum];
124976888252Smrg
125076888252Smrg	hwp = VGAHWPTR(pScrn);
125176888252Smrg
125276888252Smrg	hwp->MapSize = 0x10000;		/* Standard 64k VGA window */
125376888252Smrg
125476888252Smrg	pCir = CIRPTR(pScrn);
125576888252Smrg
125676888252Smrg	/* Map the VGA memory and get the VGA IO base */
125776888252Smrg	if (!vgaHWMapMem(pScrn))
125876888252Smrg		return FALSE;
125976888252Smrg
126076888252Smrg	/* Map the CIR memory and MMIO areas */
126176888252Smrg	if (!CirMapMem(pCir, pScrn->scrnIndex))
126276888252Smrg		return FALSE;
126376888252Smrg#ifdef EXPERIMENTAL
126476888252Smrg	lg_vgaHWSetMmioFunc(hwp, pCir->IOBase);
126576888252Smrg#endif
126676888252Smrg	vgaHWGetIOBase(hwp);
126776888252Smrg
126876888252Smrg	/* Save the current state */
126976888252Smrg	LgSave(pScrn);
127076888252Smrg
127176888252Smrg	/* Initialise the first mode */
127276888252Smrg	if (!LgModeInit(pScrn, pScrn->currentMode))
127376888252Smrg		return FALSE;
127476888252Smrg
127576888252Smrg	/* Make things beautiful */
127676888252Smrg	LgSaveScreen(pScreen, SCREEN_SAVER_ON);
127776888252Smrg
127876888252Smrg	/* Set the viewport */
127976888252Smrg	LgAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
128076888252Smrg
128176888252Smrg	/*
128276888252Smrg	 * The next step is to setup the screen's visuals, and initialise the
128376888252Smrg	 * framebuffer code.  In cases where the framebuffer's default
128476888252Smrg	 * choices for things like visual layouts and bits per RGB are OK,
128576888252Smrg	 * this may be as simple as calling the framebuffer's ScreenInit()
128676888252Smrg	 * function.  If not, the visuals will need to be setup before calling
128776888252Smrg	 * a fb ScreenInit() function and fixed up after.
128876888252Smrg	 *
128976888252Smrg	 */
129076888252Smrg
129176888252Smrg	/*
129276888252Smrg	 * Reset the visual list.
129376888252Smrg	 */
129476888252Smrg	miClearVisualTypes();
129576888252Smrg
129676888252Smrg	/* Setup the visuals we support. */
129776888252Smrg
129876888252Smrg	if (!miSetVisualTypes(pScrn->depth,
129976888252Smrg			      miGetDefaultVisualMask(pScrn->depth),
130076888252Smrg			      pScrn->rgbBits, pScrn->defaultVisual))
130176888252Smrg	  return FALSE;
130276888252Smrg
130376888252Smrg	miSetPixmapDepths ();
130476888252Smrg
130576888252Smrg#ifdef LG_DEBUG
130676888252Smrg	ErrorF("LgScreenInit after miSetVisualTypes\n");
130776888252Smrg#endif
130876888252Smrg	displayWidth = pScrn->displayWidth;
130976888252Smrg	if (pCir->rotate) {
131076888252Smrg	    height = pScrn->virtualX;
131176888252Smrg	    width = pScrn->virtualY;
131276888252Smrg	} else {
131376888252Smrg	    width = pScrn->virtualX;
131476888252Smrg	    height = pScrn->virtualY;
131576888252Smrg	}
131676888252Smrg
131776888252Smrg	if(pCir->shadowFB) {
131876888252Smrg	    pCir->ShadowPitch = BitmapBytePad(pScrn->bitsPerPixel * width);
131976888252Smrg	    pCir->ShadowPtr = xalloc(pCir->ShadowPitch * height);
132076888252Smrg	    displayWidth = pCir->ShadowPitch / (pScrn->bitsPerPixel >> 3);
132176888252Smrg	    FbBase = pCir->ShadowPtr;
132276888252Smrg	} else {
132376888252Smrg	    pCir->ShadowPtr = NULL;
132476888252Smrg	    FbBase = pCir->FbBase;
132576888252Smrg	}
132676888252Smrg
132776888252Smrg	/*
132876888252Smrg	 * Call the framebuffer layer's ScreenInit function, and fill in other
132976888252Smrg	 * pScreen fields.
133076888252Smrg	 */
133176888252Smrg	switch (pScrn->bitsPerPixel) {
133276888252Smrg	case 8:
133376888252Smrg	case 16:
133476888252Smrg	case 24:
133576888252Smrg	case 32:
133676888252Smrg	    ret = fbScreenInit(pScreen, FbBase,
133776888252Smrg				width,height,
133876888252Smrg				pScrn->xDpi, pScrn->yDpi,
133976888252Smrg				displayWidth,pScrn->bitsPerPixel);
134076888252Smrg	    break;
134176888252Smrg	default:
134276888252Smrg		xf86DrvMsg(scrnIndex, X_ERROR,
134376888252Smrg			   "X11: Internal error: invalid bpp (%d) in LgScreenInit\n",
134476888252Smrg			   pScrn->bitsPerPixel);
134576888252Smrg		ret = FALSE;
134676888252Smrg		break;
134776888252Smrg	}
134876888252Smrg	if (!ret)
134976888252Smrg		return FALSE;
135076888252Smrg
135176888252Smrg#ifdef LG_DEBUG
135276888252Smrg	ErrorF("LgScreenInit after depth dependent init\n");
135376888252Smrg#endif
135476888252Smrg
135576888252Smrg	/* Override the default mask/offset settings */
135676888252Smrg	if (pScrn->bitsPerPixel > 8) {
135776888252Smrg		for (i = 0; i < pScreen->numVisuals; i++) {
135876888252Smrg			visual = &pScreen->visuals[i];
135976888252Smrg			if ((visual->class | DynamicClass) == DirectColor) {
136076888252Smrg				visual->offsetRed = pScrn->offset.red;
136176888252Smrg				visual->offsetGreen = pScrn->offset.green;
136276888252Smrg				visual->offsetBlue = pScrn->offset.blue;
136376888252Smrg				visual->redMask = pScrn->mask.red;
136476888252Smrg				visual->greenMask = pScrn->mask.green;
136576888252Smrg				visual->blueMask = pScrn->mask.blue;
136676888252Smrg			}
136776888252Smrg		}
136876888252Smrg	}
136976888252Smrg
137076888252Smrg	/* must be after RGB ordering fixed */
137176888252Smrg
137276888252Smrg	fbPictureInit(pScreen, 0, 0);
137376888252Smrg
137476888252Smrg	miInitializeBackingStore(pScreen);
137576888252Smrg
137676888252Smrg	/*
137776888252Smrg	 * Set initial black & white colourmap indices.
137876888252Smrg	 */
137976888252Smrg	xf86SetBlackWhitePixels(pScreen);
138076888252Smrg
138176888252Smrg	if (!pCir->NoAccel) { /* Initialize XAA functions */
138276888252Smrg		if (!LgXAAInit(pScreen))
138376888252Smrg			xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Could not initialize XAA\n");
138476888252Smrg	}
138576888252Smrg#if 1
138676888252Smrg	pCir->DGAModeInit = LgModeInit;
138776888252Smrg	if (!CirDGAInit(pScreen))
138876888252Smrg	  xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
138976888252Smrg		     "DGA initialization failed\n");
139076888252Smrg#endif
139176888252Smrg        xf86SetSilkenMouse(pScreen);
139276888252Smrg
139376888252Smrg	/* Initialise cursor functions */
139476888252Smrg	miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
139576888252Smrg
139676888252Smrg	if (pCir->HWCursor) { /* Initialize HW cursor layer */
139776888252Smrg		if (!LgHWCursorInit(pScreen))
139876888252Smrg			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
139976888252Smrg				"Hardware cursor initialization failed\n");
140076888252Smrg	}
140176888252Smrg
140276888252Smrg	/* Initialise default colourmap */
140376888252Smrg	if (!miCreateDefColormap(pScreen))
140476888252Smrg		return FALSE;
140576888252Smrg
140676888252Smrg	if (pScrn->bitsPerPixel > 1 && pScrn->bitsPerPixel <= 8)
140776888252Smrg		vgaHWHandleColormaps(pScreen);
140876888252Smrg
140976888252Smrg	xf86DPMSInit(pScreen, LgDisplayPowerManagementSet, 0);
141076888252Smrg
141176888252Smrg	pScrn->memPhysBase = pCir->FbAddress;
141276888252Smrg	pScrn->fbOffset = 0;
141376888252Smrg
141476888252Smrg	{
141576888252Smrg		XF86VideoAdaptorPtr *ptr;
141676888252Smrg		int n;
141776888252Smrg
141876888252Smrg		n = xf86XVListGenericAdaptors(pScrn,&ptr);
141976888252Smrg		if (n)
142076888252Smrg			xf86XVScreenInit(pScreen, ptr, n);
142176888252Smrg	}
142276888252Smrg
142376888252Smrg	/*
142476888252Smrg	 * Wrap the CloseScreen vector and set SaveScreen.
142576888252Smrg	 */
142676888252Smrg	pScreen->SaveScreen = LgSaveScreen;
142776888252Smrg	pCir->CloseScreen = pScreen->CloseScreen;
142876888252Smrg	pScreen->CloseScreen = LgCloseScreen;
142976888252Smrg
143076888252Smrg	/* Report any unused options (only for the first generation) */
143176888252Smrg	if (serverGeneration == 1)
143276888252Smrg		xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
143376888252Smrg
143476888252Smrg	/* Done */
143576888252Smrg	return TRUE;
143676888252Smrg}
143776888252Smrg
143876888252Smrg
143976888252Smrg/* Usually mandatory */
144076888252SmrgBool
144176888252SmrgLgSwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
144276888252Smrg{
144376888252Smrg	return LgModeInit(xf86Screens[scrnIndex], mode);
144476888252Smrg}
144576888252Smrg
144676888252Smrg#define ROUND_DOWN(x, mod)	(((x) / (mod)) * (mod))
144776888252Smrg#define ROUND_UP(x, mod)	((((x) + (mod) - 1) / (mod)) * (mod))
144876888252Smrg
144976888252Smrg/*
145076888252Smrg * This function is used to initialize the Start Address - the first
145176888252Smrg * displayed location in the video memory.
145276888252Smrg */
145376888252Smrg/* Usually mandatory */
145476888252Smrgvoid
145576888252SmrgLgAdjustFrame(int scrnIndex, int x, int y, int flags)
145676888252Smrg{
145776888252Smrg	ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
145876888252Smrg	int Base, tmp;
145976888252Smrg	CirPtr pCir = CIRPTR(pScrn);
146076888252Smrg	vgaHWPtr hwp = VGAHWPTR(pScrn);
146176888252Smrg	int cursorX, cursorY;
146276888252Smrg	int middleX, middleY;
146376888252Smrg	const LgLineDataPtr lineData = &LgLineData[pCir->chip.lg->lineDataIndex];
146476888252Smrg	const int viewportXRes =
146576888252Smrg		(PCI_CHIP_GD5465 == pCir->Chipset) ? (24==pScrn->bitsPerPixel?24:1) :
146676888252Smrg			(lineData->width?256:128) /
146776888252Smrg			(24==pScrn->bitsPerPixel?1:(pScrn->bitsPerPixel>>3));
146876888252Smrg	const int viewportYRes =
146976888252Smrg		(PCI_CHIP_GD5465 == pCir->Chipset) ? 1 : (24==pScrn->bitsPerPixel?3:1);
147076888252Smrg
147176888252Smrg	/* Where's the pointer? */
14721ae1b5e8Smrg	miPointerGetPosition(inputInfo.pointer, &cursorX, &cursorY);
147376888252Smrg
147476888252Smrg	/* Where's the middle of the screen?  We want to eventually know
147576888252Smrg	   which side of the screen the pointer is on. */
147676888252Smrg	middleX = (pScrn->frameX1 + pScrn->frameX0) / 2;
147776888252Smrg	middleY = (pScrn->frameY1 + pScrn->frameY0) / 2;
147876888252Smrg
147976888252Smrg	if (cursorX < middleX) {
148076888252Smrg		/* Pointer is on left side of screen.  Round the frame value down. */
148176888252Smrg		pScrn->frameX0 = ROUND_DOWN(pScrn->frameX0, viewportXRes);
148276888252Smrg	} else {
148376888252Smrg		/* Pointer is on right side of screen.  Round the frame value
148476888252Smrg		   up.  A side effect of this rounding up is that we might expose
148576888252Smrg		   a part of the screen that's actually on the far /left/ of the
148676888252Smrg		   frame buffer.  That's because, although the virtual desktop might
148776888252Smrg		   be an integral number of tiles, the display might not.  We'll
148876888252Smrg		   just live with this artifact. */
148976888252Smrg		pScrn->frameX0 = ROUND_UP(pScrn->frameX0, viewportXRes);
149076888252Smrg	}
149176888252Smrg	pScrn->frameX1 = pScrn->frameX0 + pScrn->currentMode->HDisplay - 1;
149276888252Smrg
149376888252Smrg	if (cursorY < middleY) {
149476888252Smrg		pScrn->frameY0 = ROUND_DOWN(pScrn->frameY0, viewportYRes);
149576888252Smrg	} else {
149676888252Smrg		pScrn->frameY0 = ROUND_UP(pScrn->frameY0, viewportYRes);
149776888252Smrg	}
149876888252Smrg	pScrn->frameY1 = pScrn->frameY0 + pScrn->currentMode->VDisplay - 1;
149976888252Smrg
150076888252Smrg
150176888252Smrg	if (x != pScrn->frameX0 || y != pScrn->frameY0) {
150276888252Smrg		/* !!! */
150376888252Smrg		/* We moved the frame from where xf86SetViewport() placed it.
150476888252Smrg		   If we're using a SW cursor, that's okay -- the pointer exists in
150576888252Smrg		   the framebuffer, and those bits are still all aligned.  But
150676888252Smrg		   if we're using a HW cursor, then we need to re-align the pointer.
150776888252Smrg		   Call SetCursorPosition() with the appropriate new pointer
150876888252Smrg		   values, adjusted to be wrt the new frame. */
150976888252Smrg
151076888252Smrg		x = pScrn->frameX0;
151176888252Smrg		y = pScrn->frameY0;
151276888252Smrg	}
151376888252Smrg
151476888252Smrg	/* ??? Will this work for 1bpp?  */
151576888252Smrg	Base = (y * lineData->pitch + (x*pScrn->bitsPerPixel/8)) / 4;
151676888252Smrg
151776888252Smrg	if ((Base & ~0x000FFFFF) != 0) {
151876888252Smrg		/* ??? */
151976888252Smrg		ErrorF("X11: Internal error: LgAdjustFrame: cannot handle overflow\n");
152076888252Smrg		return;
152176888252Smrg	}
152276888252Smrg
152376888252Smrg	hwp->writeCrtc(hwp, 0x0C, (Base >> 8) & 0xFF);
152476888252Smrg	hwp->writeCrtc(hwp, 0x0D, Base & 0xFF);
152576888252Smrg	tmp = hwp->readCrtc(hwp, 0x1B) & 0xF2;
152676888252Smrg	tmp |= (Base >> 16) & 0x01;
152776888252Smrg	tmp |= (Base >> 15) & 0x0C;
152876888252Smrg	hwp->writeCrtc(hwp, 0x1B, tmp);
152976888252Smrg	tmp = hwp->readCrtc(hwp, 0x1D) & 0xE7;
153076888252Smrg	tmp |= (Base >> 16) & 0x18;
153176888252Smrg	hwp->writeCrtc(hwp, 0x1D, tmp);
153276888252Smrg}
153376888252Smrg
153476888252Smrg/*
153576888252Smrg * This is called when VT switching back to the X server.  Its job is
153676888252Smrg * to reinitialise the video mode.
153776888252Smrg *
153876888252Smrg * We may wish to unmap video/MMIO memory too.
153976888252Smrg */
154076888252Smrg
154176888252Smrg/* Mandatory */
154276888252SmrgBool
154376888252SmrgLgEnterVT(int scrnIndex, int flags)
154476888252Smrg{
154576888252Smrg	ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
154676888252Smrg	CirPtr pCir = CIRPTR(pScrn);
154776888252Smrg#ifdef LG_DEBUG
154876888252Smrg	ErrorF("LgEnterVT\n");
154976888252Smrg#endif
155076888252Smrg
155176888252Smrg	/* XXX Shouldn't this be in LeaveVT? */
155276888252Smrg	/* Disable HW cursor */
155376888252Smrg	if (pCir->HWCursor)
155476888252Smrg		LgHideCursor(pScrn);
155576888252Smrg
155676888252Smrg	/* Should we re-save the text mode on each VT enter? */
155776888252Smrg	return LgModeInit(pScrn, pScrn->currentMode);
155876888252Smrg}
155976888252Smrg
156076888252Smrg
156176888252Smrg/*
156276888252Smrg * This is called when VT switching away from the X server.  Its job is
156376888252Smrg * to restore the previous (text) mode.
156476888252Smrg *
156576888252Smrg * We may wish to remap video/MMIO memory too.
156676888252Smrg */
156776888252Smrg
156876888252Smrg/* Mandatory */
156976888252Smrgvoid
157076888252SmrgLgLeaveVT(int scrnIndex, int flags)
157176888252Smrg{
157276888252Smrg	ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
157376888252Smrg	vgaHWPtr hwp = VGAHWPTR(pScrn);
157476888252Smrg	CirPtr pCir = CIRPTR(pScrn);
157576888252Smrg#ifdef LG_DEBUG
157676888252Smrg	ErrorF("LgLeaveVT\n");
157776888252Smrg#endif
157876888252Smrg
157976888252Smrg	/* XXX Shouldn't this be in EnterVT? */
158076888252Smrg	/* Enable HW cursor */
158176888252Smrg	if (pCir->HWCursor)
158276888252Smrg		LgShowCursor(pScrn);
158376888252Smrg
158476888252Smrg	LgRestore(pScrn);
158576888252Smrg	vgaHWLock(hwp);
158676888252Smrg}
158776888252Smrg
158876888252Smrg
158976888252Smrg/*
159076888252Smrg * This is called at the end of each server generation.  It restores the
159176888252Smrg * original (text) mode.  It should also unmap the video memory, and free
159276888252Smrg * any per-generation data allocated by the driver.  It should finish
159376888252Smrg * by unwrapping and calling the saved CloseScreen function.
159476888252Smrg */
159576888252Smrg
159676888252Smrg/* Mandatory */
159776888252Smrgstatic Bool
159876888252SmrgLgCloseScreen(int scrnIndex, ScreenPtr pScreen)
159976888252Smrg{
160076888252Smrg	ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
160176888252Smrg	vgaHWPtr hwp = VGAHWPTR(pScrn);
160276888252Smrg	CirPtr pCir = CIRPTR(pScrn);
160376888252Smrg
160476888252Smrg	if(pScrn->vtSema) {
160576888252Smrg	LgRestore(pScrn);
160676888252Smrg	if (pCir->HWCursor)
160776888252Smrg	    LgHideCursor(pScrn);
160876888252Smrg
160976888252Smrg	vgaHWLock(hwp);
161076888252Smrg
161176888252Smrg	CirUnmapMem(pCir, pScrn->scrnIndex);
161276888252Smrg	}
161376888252Smrg
161476888252Smrg	if (pCir->AccelInfoRec)
161576888252Smrg		XAADestroyInfoRec(pCir->AccelInfoRec);
161676888252Smrg	pCir->AccelInfoRec = NULL;
161776888252Smrg
161876888252Smrg	if (pCir->CursorInfoRec)
161976888252Smrg		xf86DestroyCursorInfoRec(pCir->CursorInfoRec);
162076888252Smrg	pCir->CursorInfoRec = NULL;
162176888252Smrg	if (pCir->DGAModes)
162276888252Smrg		xfree(pCir->DGAModes);
162376888252Smrg	pCir->DGAnumModes = 0;
162476888252Smrg	pCir->DGAModes = NULL;
162576888252Smrg
162676888252Smrg	pScrn->vtSema = FALSE;
162776888252Smrg
162876888252Smrg	pScreen->CloseScreen = pCir->CloseScreen;
162976888252Smrg	return (*pScreen->CloseScreen)(scrnIndex, pScreen);
163076888252Smrg}
163176888252Smrg
163276888252Smrg
163376888252Smrg/* Free up any persistent data structures */
163476888252Smrg
163576888252Smrg/* Optional */
163676888252Smrgvoid
163776888252SmrgLgFreeScreen(int scrnIndex, int flags)
163876888252Smrg{
163976888252Smrg#ifdef LG_DEBUG
164076888252Smrg	ErrorF("LgFreeScreen\n");
164176888252Smrg#endif
164276888252Smrg	/*
164376888252Smrg	 * This only gets called when a screen is being deleted.  It does not
164476888252Smrg	 * get called routinely at the end of a server generation.
164576888252Smrg	 */
164676888252Smrg	if (xf86LoaderCheckSymbol("vgaHWFreeHWRec"))
164776888252Smrg		vgaHWFreeHWRec(xf86Screens[scrnIndex]);
164876888252Smrg	LgFreeRec(xf86Screens[scrnIndex]);
164976888252Smrg}
165076888252Smrg
165176888252Smrg
165276888252Smrg/* Checks if a mode is suitable for the selected chipset. */
165376888252Smrg
165476888252Smrg/* Optional */
165576888252SmrgModeStatus
165676888252SmrgLgValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags)
165776888252Smrg{
165876888252Smrg	int lace;
165976888252Smrg
166076888252Smrg	lace = 1 + ((mode->Flags & V_INTERLACE) != 0);
166176888252Smrg
166276888252Smrg	if ((mode->CrtcHDisplay <= 2048) &&
166376888252Smrg		(mode->CrtcHSyncStart <= 4096) &&
166476888252Smrg		(mode->CrtcHSyncEnd <= 4096) &&
166576888252Smrg		(mode->CrtcHTotal <= 4096) &&
166676888252Smrg		(mode->CrtcVDisplay <= 2048 * lace) &&
166776888252Smrg		(mode->CrtcVSyncStart <= 4096 * lace) &&
166876888252Smrg		(mode->CrtcVSyncEnd <= 4096 * lace) &&
166976888252Smrg		(mode->CrtcVTotal <= 4096 * lace)) {
167076888252Smrg		return(MODE_OK);
167176888252Smrg	}
167276888252Smrg	return(MODE_BAD);
167376888252Smrg}
167476888252Smrg
167576888252Smrg
167676888252Smrg/* Do screen blanking */
167776888252Smrg
167876888252Smrg/* Mandatory */
167976888252Smrgstatic Bool
168076888252SmrgLgSaveScreen(ScreenPtr pScreen, int mode)
168176888252Smrg{
168276888252Smrg	CirPtr pCir = CIRPTR(xf86Screens[pScreen->myNum]);
168376888252Smrg	ScrnInfoPtr pScrn = NULL;
168476888252Smrg	Bool unblank;
168576888252Smrg
168676888252Smrg	unblank = xf86IsUnblank(mode);
168776888252Smrg
168876888252Smrg	if (pScreen != NULL)
168976888252Smrg	    pScrn = xf86Screens[pScreen->myNum];
169076888252Smrg
169176888252Smrg	if (pScrn != NULL && pScrn->vtSema) {
169276888252Smrg	    if (unblank)
169376888252Smrg		/* Power up the palette DAC */
169476888252Smrg		memwb(0xB0,memrb(0xB0) & 0x7F);
169576888252Smrg	    else
169676888252Smrg		/* Power down the palette DAC */
169776888252Smrg		memwb(0xB0,memrb(0xB0) | 0x80);
169876888252Smrg	}
169976888252Smrg
170076888252Smrg	return vgaHWSaveScreen(pScreen, mode);
170176888252Smrg}
170276888252Smrg
170376888252Smrgstatic CARD16
170476888252SmrgLgSetClock(CirPtr pCir, vgaHWPtr hwp, int freq)
170576888252Smrg{
170676888252Smrg	int ffreq, num, den;
170776888252Smrg	CARD8 tmp;
170876888252Smrg
170976888252Smrg	ErrorF("LgSetClock freq=%d.%03dMHz\n", freq / 1000, freq % 1000);
171076888252Smrg
171176888252Smrg	ffreq = freq;
171276888252Smrg	if (!CirrusFindClock(&ffreq, pCir->MaxClock, &num, &den))
171376888252Smrg		return 0;
171476888252Smrg
171576888252Smrg	ErrorF("LgSetClock: nom=%x den=%x ffreq=%d.%03dMHz\n",
171676888252Smrg		num, den, ffreq / 1000, ffreq % 1000);
171776888252Smrg
171876888252Smrg	/* Set VCLK3. */
171976888252Smrg	/* The numerator and denominator registers are switched
172076888252Smrg	   around in the Laguna chips. */
172176888252Smrg	tmp = hwp->readSeq(hwp, 0x0E);
172276888252Smrg	hwp->writeSeq(hwp, 0x0E, (tmp & 0x80) | den);
172376888252Smrg	hwp->writeSeq(hwp, 0x1E, num);
172476888252Smrg
172576888252Smrg	return (den << 8) | num;
172676888252Smrg}
172776888252Smrg
172876888252Smrg/*
172976888252Smrg * CIRDisplayPowerManagementSet --
173076888252Smrg *
173176888252Smrg * Sets VESA Display Power Management Signaling (DPMS) Mode.
173276888252Smrg */
173376888252Smrgstatic void
173476888252SmrgLgDisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode,
173576888252Smrg							int flags)
173676888252Smrg{
173776888252Smrg	unsigned char sr01, cr1a;
173876888252Smrg	vgaHWPtr hwp;
173976888252Smrg
174076888252Smrg#ifdef LG_DEBUG
174176888252Smrg	ErrorF("LgDisplayPowerManagementSet: %d\n", PowerManagementMode);
174276888252Smrg#endif
174376888252Smrg
174476888252Smrg	hwp = VGAHWPTR(pScrn);
174576888252Smrg
174676888252Smrg	switch (PowerManagementMode) {
174776888252Smrg	case DPMSModeOn:
174876888252Smrg		/* Screen: On; HSync: On, VSync: On */
174976888252Smrg		sr01 = 0x00;
175076888252Smrg		cr1a = 0x00;
175176888252Smrg		break;
175276888252Smrg	case DPMSModeStandby:
175376888252Smrg		/* Screen: Off; HSync: Off, VSync: On */
175476888252Smrg		sr01 = 0x20;
175576888252Smrg		cr1a = 0x08;
175676888252Smrg		break;
175776888252Smrg	case DPMSModeSuspend:
175876888252Smrg		/* Screen: Off; HSync: On, VSync: Off */
175976888252Smrg		sr01 = 0x20;
176076888252Smrg		cr1a = 0x04;
176176888252Smrg		break;
176276888252Smrg	case DPMSModeOff:
176376888252Smrg		/* Screen: Off; HSync: Off, VSync: Off */
176476888252Smrg		sr01 = 0x20;
176576888252Smrg		cr1a = 0x0c;
176676888252Smrg		break;
176776888252Smrg	default:
176876888252Smrg		return;
176976888252Smrg	}
177076888252Smrg
177176888252Smrg	sr01 |= hwp->readSeq(hwp, 0x01) & ~0x20;
177276888252Smrg	hwp->writeSeq(hwp, 0x01, sr01);
177376888252Smrg	cr1a |= hwp->readCrtc(hwp, 0x1A) & ~0x0C;
177476888252Smrg	hwp->writeCrtc(hwp, 0x1A, cr1a);
177576888252Smrg}
177676888252Smrg
177776888252Smrg#define minb(p) MMIO_IN8(hwp->MMIOBase, (p))
177876888252Smrg#define moutb(p,v) MMIO_OUT8(hwp->MMIOBase, (p),(v))
177976888252Smrg
178076888252Smrgstatic void
178176888252SmrgmmioWriteCrtc(vgaHWPtr hwp, CARD8 index, CARD8 value)
178276888252Smrg{
178376888252Smrg  moutb(index << 2, value);
178476888252Smrg}
178576888252Smrg
178676888252Smrgstatic CARD8
178776888252SmrgmmioReadCrtc(vgaHWPtr hwp, CARD8 index)
178876888252Smrg{
178976888252Smrg  return minb(index << 2);
179076888252Smrg}
179176888252Smrg
179276888252Smrgstatic void
179376888252Smrglg_vgaHWSetMmioFunc(vgaHWPtr hwp, CARD8 *base)
179476888252Smrg{
179576888252Smrg    hwp->writeCrtc		= mmioWriteCrtc;
179676888252Smrg    hwp->readCrtc		= mmioReadCrtc;
179776888252Smrg    hwp->MMIOBase		= base;
179876888252Smrg    hwp->MMIOOffset		= 0;
179976888252Smrg}
1800