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