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