/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/chips/ct_driver.c,v 1.138 2006/03/16 16:50:00 dawes Exp $ */

/*
 * Copyright 1993 by Jon Block <block@frc.com>
 * Modified by Mike Hollick <hollick@graphics.cis.upenn.edu>
 * Modified 1994 by Régis Cridlig <cridlig@dmi.ens.fr>
 *
 * Major Contributors to XFree86 3.2
 *   Modified 1995/6 by Nozomi Ytow
 *   Modified 1996 by Egbert Eich <eich@xfree86.org>
 *   Modified 1996 by David Bateman <dbateman@club-internet.fr>
 *   Modified 1996 by Xavier Ducoin <xavier@rd.lectra.fr>
 *
 * Contributors to XFree86 3.2
 *   Modified 1995/6 by Ken Raeburn <raeburn@raeburn.org>
 *   Modified 1996 by Shigehiro Nomura <nomura@sm.sony.co.jp>
 *   Modified 1996 by Marc de Courville <marc@courville.org>
 *   Modified 1996 by Adam Sulmicki <adam@cfar.umd.edu>
 *   Modified 1996 by Jens Maurer <jmaurer@cck.uni-kl.de>
 *
 * Large parts rewritten for XFree86 4.0
 *   Modified 1998 by David Bateman <dbateman@club-internet.fr>
 *   Modified 1998 by Egbert Eich <eich@xfree86.org>
 *   Modified 1998 by Nozomi Ytow
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of the authors not be used in
 * advertising or publicity pertaining to distribution of the software without
 * specific, written prior permission.  The authors makes no representations
 * about the suitability of this software for any purpose.  It is provided
 * "as is" without express or implied warranty.
 *
 * THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 * EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 */
/*
 * Copyright 1997
 * Digital Equipment Corporation. All rights reserved.
 * This software is furnished under license and may be used and copied only in 
 * accordance with the following terms and conditions.  Subject to these 
 * conditions, you may download, copy, install, use, modify and distribute 
 * this software in source and/or binary form. No title or ownership is 
 * transferred hereby.
 * 1) Any source code used, modified or distributed must reproduce and retain 
 *    this copyright notice and list of conditions as they appear in the 
 *    source file.
 *
 * 2) No right is granted to use any trade name, trademark, or logo of Digital 
 *    Equipment Corporation. Neither the "Digital Equipment Corporation" name 
 *    nor any trademark or logo of Digital Equipment Corporation may be used 
 *    to endorse or promote products derived from this software without the 
 *    prior written permission of Digital Equipment Corporation.
 *
 * 3) This software is provided "AS-IS" and any express or implied warranties,
 *    including but not limited to, any implied warranties of merchantability,
 *    fitness for a particular purpose, or non-infringement are disclaimed. In
 *    no event shall DIGITAL be liable for any damages whatsoever, and in 
 *    particular, DIGITAL shall not be liable for special, indirect, 
 *    consequential, or incidental damages or damages for lost profits, loss 
 *    of revenue or loss of use, whether such damages arise in contract, 
 *    negligence, tort, under statute, in equity, at law or otherwise, even if
 *    advised of the possibility of such damage. 
 */

/* All drivers should typically include these */
#include "xf86.h"
#include "xf86_OSproc.h"
#include "xf86_ansic.h"

/* Everything using inb/outb, etc needs "compiler.h" */
#include "compiler.h"

/* Drivers for PCI hardware need this */
#include "xf86PciInfo.h"

/* Drivers that need to access the PCI config space directly need this */
#include "xf86Pci.h"

/* This is used for module versioning */
#include "xf86Version.h"

/* Standard resources are defined here */
#include "xf86Resources.h"

/* All drivers using the vgahw module need this */
#include "vgaHW.h"

/* All drivers initialising the SW cursor need this */
#include "mipointer.h"

/* All drivers implementing backing store need this */
#include "mibstore.h"

/* All drivers using the mi banking wrapper need this */
#include "mibank.h"

/* All drivers using the mi colormap manipulation need this */
#include "micmap.h"

#include "fb.h"
#include "cfb8_16.h"

/* Needed for the 1 and 4 bpp framebuffers */
#include "xf1bpp.h"
#include "xf4bpp.h"

/* Needed by Resources Access Control (RAC) */
#include "xf86RAC.h"

/* int10 */
#include "xf86int10.h"
#include "vbe.h"

/* Needed by the Shadow Framebuffer */
#include "shadowfb.h"

/* Needed for replacement LoadPalette function for Gamma Correction */
#include "xf86cmap.h"

#include "dixstruct.h"

/* Driver specific headers */
#include "ct_driver.h"

/* Mandatory functions */
static const OptionInfoRec *	CHIPSAvailableOptions(int chipid, int busid);
static void     CHIPSIdentify(int flags);
static Bool     CHIPSProbe(DriverPtr drv, int flags);
static Bool     CHIPSPreInit(ScrnInfoPtr pScrn, int flags);
static Bool     CHIPSScreenInit(int Index, ScreenPtr pScreen, int argc,
                                  char **argv);
static Bool     CHIPSEnterVT(int scrnIndex, int flags);
static void     CHIPSLeaveVT(int scrnIndex, int flags);
static Bool     CHIPSCloseScreen(int scrnIndex, ScreenPtr pScreen);
static void     CHIPSFreeScreen(int scrnIndex, int flags);
static ModeStatus CHIPSValidMode(int scrnIndex, DisplayModePtr mode,
                                 Bool verbose, int flags);
static Bool	CHIPSSaveScreen(ScreenPtr pScreen, int mode);

/* Internally used functions */
static int      chipsFindIsaDevice(GDevPtr dev);
static Bool     chipsClockSelect(ScrnInfoPtr pScrn, int no);
Bool     chipsModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode);
static void     chipsSave(ScrnInfoPtr pScrn, vgaRegPtr VgaSave,
			  CHIPSRegPtr ChipsSave);
static void     chipsRestore(ScrnInfoPtr pScrn, vgaRegPtr VgaReg,
				 CHIPSRegPtr ChipsReg, Bool restoreFonts);
static void     chipsLock(ScrnInfoPtr pScrn);
static void     chipsUnlock(ScrnInfoPtr pScrn);
static void     chipsClockSave(ScrnInfoPtr pScrn, CHIPSClockPtr Clock);
static void     chipsClockLoad(ScrnInfoPtr pScrn, CHIPSClockPtr Clock);
static Bool     chipsClockFind(ScrnInfoPtr pScrn, int no, CHIPSClockPtr Clock);
static void     chipsCalcClock(ScrnInfoPtr pScrn, int Clock,
				 unsigned char *vclk);
static int      chipsGetHWClock(ScrnInfoPtr pScrn);
static Bool     chipsPreInit655xx(ScrnInfoPtr pScrn, int flags);
static Bool     chipsPreInitHiQV(ScrnInfoPtr pScrn, int flags);
static Bool     chipsPreInitWingine(ScrnInfoPtr pScrn, int flags);
static int      chipsSetMonitor(ScrnInfoPtr pScrn);
static Bool	chipsMapMem(ScrnInfoPtr pScrn);
static Bool	chipsUnmapMem(ScrnInfoPtr pScrn);
static void     chipsProtect(ScrnInfoPtr pScrn, Bool on);
static void	chipsBlankScreen(ScrnInfoPtr pScrn, Bool unblank);
static void     chipsRestoreExtendedRegs(ScrnInfoPtr pScrn, CHIPSRegPtr Regs);
static void     chipsRestoreStretching(ScrnInfoPtr pScrn,
				unsigned char ctHorizontalStretch,
				unsigned char ctVerticalStretch);
static Bool     chipsModeInitHiQV(ScrnInfoPtr pScrn, DisplayModePtr mode);
static Bool     chipsModeInitWingine(ScrnInfoPtr pScrn, DisplayModePtr mode);
static Bool     chipsModeInit655xx(ScrnInfoPtr pScrn, DisplayModePtr mode);
static int      chipsVideoMode(int vgaBitsPerPixel,int displayHSize,
			       int displayVSize);
static void     chipsDisplayPowerManagementSet(ScrnInfoPtr pScrn,
				int PowerManagementMode, int flags);
static void     chipsHWCursorOn(CHIPSPtr cPtr, ScrnInfoPtr pScrn);
static void     chipsHWCursorOff(CHIPSPtr cPtr, ScrnInfoPtr pScrn);
static void     chipsFixResume(ScrnInfoPtr pScrn);
static void     chipsLoadPalette(ScrnInfoPtr pScrn, int numColors,
				int *indices, LOCO *colors, VisualPtr pVisual);
static void     chipsLoadPalette16(ScrnInfoPtr pScrn, int numColors,
				int *indices, LOCO *colors, VisualPtr pVisual);
static void chipsSetPanelType(CHIPSPtr cPtr);
static void chipsBlockHandler(int, pointer, pointer, pointer);

/*
 * This is intentionally screen-independent.  It indicates the binding
 * choice made in the first PreInit.
 */
static int pix24bpp = 0;

/*
 * Index of Entity
 */ 
static int CHIPSEntityIndex = -1;


/* Set the non-documented SAR04 register for overlay/video */
#define SAR04 

/*
 * Initialise some arrays that are used in multiple instances of the
 * acceleration code. Set them up here as its a convenient place to do it.
 */
/* alu to C&T conversion for use with source data */
int ChipsAluConv[] =
{
    0x00,			/* dest =  0; GXclear, 0 */
    0x88,			/* dest &= src; GXand, 0x1 */
    0x44,			/* dest =  src & ~dest; GXandReverse, 0x2 */
    0xCC,			/* dest =  src; GXcopy, 0x3 */
    0x22,			/* dest &= ~src; GXandInverted, 0x4 */
    0xAA,			/* dest =  dest; GXnoop, 0x5 */
    0x66,			/* dest =  ^src; GXxor, 0x6 */
    0xEE,			/* dest |= src; GXor, 0x7 */
    0x11,			/* dest =  ~src & ~dest;GXnor, 0x8 */
    0x99,			/* dest ^= ~src ;GXequiv, 0x9 */
    0x55,			/* dest =  ~dest; GXInvert, 0xA */
    0xDD,			/* dest =  src|~dest ;GXorReverse, 0xB */
    0x33,			/* dest =  ~src; GXcopyInverted, 0xC */
    0xBB,			/* dest |= ~src; GXorInverted, 0xD */
    0x77,			/* dest =  ~src|~dest ;GXnand, 0xE */
    0xFF,			/* dest =  0xFF; GXset, 0xF */
};

/* alu to C&T conversion for use with pattern data */
int ChipsAluConv2[] =
{
    0x00,			/* dest =  0; GXclear, 0 */
    0xA0,			/* dest &= src; GXand, 0x1 */
    0x50,			/* dest =  src & ~dest; GXandReverse, 0x2 */
    0xF0,			/* dest =  src; GXcopy, 0x3 */
    0x0A,			/* dest &= ~src; GXandInverted, 0x4 */
    0xAA,			/* dest =  dest; GXnoop, 0x5 */
    0x5A,			/* dest =  ^src; GXxor, 0x6 */
    0xFA,			/* dest |= src; GXor, 0x7 */
    0x05,			/* dest =  ~src & ~dest;GXnor, 0x8 */
    0xA5,			/* dest ^= ~src ;GXequiv, 0x9 */
    0x55,			/* dest =  ~dest; GXInvert, 0xA */
    0xF5,			/* dest =  src|~dest ;GXorReverse, 0xB */
    0x0F,			/* dest =  ~src; GXcopyInverted, 0xC */
    0xAF,			/* dest |= ~src; GXorInverted, 0xD */
    0x5F,			/* dest =  ~src|~dest ;GXnand, 0xE */
    0xFF,			/* dest =  0xFF; GXset, 0xF */
};

/* alu to C&T conversion for use with pattern data as a planemask */
int ChipsAluConv3[] =
{
    0x0A,			/* dest =  0; GXclear, 0 */
    0x8A,			/* dest &= src; GXand, 0x1 */
    0x4A,			/* dest =  src & ~dest; GXandReverse, 0x2 */
    0xCA,			/* dest =  src; GXcopy, 0x3 */
    0x2A,			/* dest &= ~src; GXandInverted, 0x4 */
    0xAA,			/* dest =  dest; GXnoop, 0x5 */
    0x6A,			/* dest =  ^src; GXxor, 0x6 */
    0xEA,			/* dest |= src; GXor, 0x7 */
    0x1A,			/* dest =  ~src & ~dest;GXnor, 0x8 */
    0x9A,			/* dest ^= ~src ;GXequiv, 0x9 */
    0x5A,			/* dest =  ~dest; GXInvert, 0xA */
    0xDA,			/* dest =  src|~dest ;GXorReverse, 0xB */
    0x3A,			/* dest =  ~src; GXcopyInverted, 0xC */
    0xBA,			/* dest |= ~src; GXorInverted, 0xD */
    0x7A,			/* dest =  ~src|~dest ;GXnand, 0xE */
    0xFA,			/* dest =  0xFF; GXset, 0xF */
};

/* The addresses of the acceleration registers */
unsigned int ChipsReg32HiQV[] =
{
    0x00,		/* BR00 Source and Destination offset register */
    0x04,		/* BR01 Color expansion background color       */
    0x08,		/* BR02 Color expansion foreground color       */
    0x0C,		/* BR03 Monochrome source control register     */
    0x10,		/* BR04 BitBLT control register                */
    0x14,		/* BR05 Pattern address register               */
    0x18,		/* BR06 Source address register                */
    0x1C,		/* BR07 Destination  address register          */
    0x20		/* BR08 Destination width and height register  */
};

unsigned int ChipsReg32[] =
{
  /*BitBLT */
    0x83D0,			       /*DR0 src/dest offset                 */
    0x87D0,			       /*DR1 BitBlt. address of freeVram?    */
    0x8BD0,			       /*DR2 BitBlt. paintBrush, or tile pat.*/
    0x8FD0,                            /*DR3                                 */
    0x93D0,			       /*DR4 BitBlt.                         */
    0x97D0,			       /*DR5 BitBlt. srcAddr, or 0 in VRAM   */
    0x9BD0,			       /*DR6 BitBlt. dest?                   */
    0x9FD0,			       /*DR7 BitBlt. width << 16 | height    */
  /*H/W cursor */
    0xA3D0,			       /*DR8 write/erase cursor              */
		                       /*bit 0-1 if 0  cursor is not shown
		                        * if 1  32x32 cursor
					* if 2  64x64 cursor
					* if 3  128x128 cursor
					*/
                                        /* bit 7 if 1  cursor is not shown   */
		                        /* bit 9 cursor expansion in X       */
		                        /* bit 10 cursor expansion in Y      */
    0xA7D0,			        /* DR9 foreGroundCursorColor         */
    0xABD0,			        /* DR0xA backGroundCursorColor       */
    0xAFD0,			        /* DR0xB cursorPosition              */
		                        /* bit 0-7       x coordinate        */
		                        /* bit 8-14      0                   */
		                        /* bit 15        x signum            */
		                        /* bit 16-23     y coordinate        */
		                        /* bit 24-30     0                   */
		                        /* bit 31        y signum            */
    0xB3D0,			        /* DR0xC address of cursor pattern   */
};

#if defined(__arm32__) && defined(__NetBSD__)
/*
 * Built in TV output modes: These modes have been tested on NetBSD with
 * CT65550 and StrongARM. They give what seems to be the best output for
 * a roughly 640x480 display. To enable one of the built in modes, add 
 * the identifier "NTSC" or "PAL" to the list of modes in the appropriate
 * "Display" subsection of the "Screen" section in the XF86Config file.
 * Note that the call to xf86SetTVOut(), which tells the kernel to enable
 * TV output results in hardware specific actions. There must be code to
 * support this in the kernel or TV output won't work.
 */
static DisplayModeRec ChipsPALMode = {
	NULL, NULL,     /* prev, next */
	"PAL",          /* identifier of this mode */
	MODE_OK,        /* mode status */
	M_T_BUILTIN,    /* mode type */
	15000,		/* Clock frequency */
	776,		/* HDisplay */
	800,		/* HSyncStart */
	872,		/* HSyncEnd */
	960,		/* HTotal */
	0,		/* HSkew */
	585,		/* VDisplay */
	590,		/* VSyncStart */
	595,		/* VSyncEnd */
	625,		/* VTotal */
	0,		/* VScan */
	V_INTERLACE,	/* Flags */
	-1,		/* ClockIndex */
	15000,		/* SynthClock */
	776,		/* CRTC HDisplay */
	800,            /* CRTC HBlankStart */
	800,            /* CRTC HSyncStart */
	872,            /* CRTC HSyncEnd */
	872,            /* CRTC HBlankEnd */
	960,            /* CRTC HTotal */
	0,              /* CRTC HSkew */
	585,		/* CRTC VDisplay */
	590,		/* CRTC VBlankStart */
	590,		/* CRTC VSyncStart */
	595,		/* CRTC VSyncEnd */
	595,		/* CRTC VBlankEnd */
	625,		/* CRTC VTotal */
	FALSE,		/* CrtcHAdjusted */
	FALSE,		/* CrtcVAdjusted */
	0,		/* PrivSize */
	NULL,		/* Private */
	0.0,		/* HSync */
	0.0		/* VRefresh */
};

/*
** So far, it looks like SECAM uses the same values as PAL
*/
static DisplayModeRec ChipsSECAMMode = {
	NULL,           /* prev */
	&ChipsPALMode,  /* next */   
	"SECAM",        /* identifier of this mode */
	MODE_OK,        /* mode status */
	M_T_BUILTIN,    /* mode type */
	15000,		/* Clock frequency */
	776,		/* HDisplay */
	800,		/* HSyncStart */
	872,		/* HSyncEnd */
	960,		/* HTotal */
	0,		/* HSkew */
	585,		/* VDisplay */
	590,		/* VSyncStart */
	595,		/* VSyncEnd */
	625,		/* VTotal */
	0,		/* VScan */
	V_INTERLACE,	/* Flags */
	-1,		/* ClockIndex */
	15000,		/* SynthClock */
	776,		/* CRTC HDisplay */
	800,            /* CRTC HBlankStart */
	800,            /* CRTC HSyncStart */
	872,            /* CRTC HSyncEnd */
	872,            /* CRTC HBlankEnd */
	960,            /* CRTC HTotal */
	0,              /* CRTC HSkew */
	585,		/* CRTC VDisplay */
	590,		/* CRTC VBlankStart */
	590,		/* CRTC VSyncStart */
	595,		/* CRTC VSyncEnd */
	595,		/* CRTC VBlankEnd */
	625,		/* CRTC VTotal */
	FALSE,		/* CrtcHAdjusted */
	FALSE,		/* CrtcVAdjusted */
	0,		/* PrivSize */
	NULL,		/* Private */
	0.0,		/* HSync */
	0.0		/* VRefresh */
};


static DisplayModeRec ChipsNTSCMode = {
	NULL,           /* prev */
	&ChipsSECAMMode,/* next */
	"NTSC",         /* identifier of this mode */
	MODE_OK,        /* mode status */
	M_T_BUILTIN,    /* mode type */
	11970,		/* Clock frequency */
	584,		/* HDisplay */
	640,		/* HSyncStart */
	696,		/* HSyncEnd */
	760,		/* HTotal */
	0,		/* HSkew */
	450,		/* VDisplay */
	479,		/* VSyncStart */
	485,		/* VSyncEnd */
	525,		/* VTotal */
	0,		/* VScan */
	V_INTERLACE | V_NVSYNC | V_NHSYNC ,	/* Flags */
	-1,		/* ClockIndex */
	11970,		/* SynthClock */
	584,		/* CRTC HDisplay */
	640,            /* CRTC HBlankStart */
	640,            /* CRTC HSyncStart */
	696,            /* CRTC HSyncEnd */
	696,            /* CRTC HBlankEnd */
	760,            /* CRTC HTotal */
	0,              /* CRTC HSkew */
	450,		/* CRTC VDisplay */
	479,		/* CRTC VBlankStart */
	479,		/* CRTC VSyncStart */
	485,		/* CRTC VSyncEnd */
	485,		/* CRTC VBlankEnd */
	525,		/* CRTC VTotal */
	FALSE,		/* CrtcHAdjusted */
	FALSE,		/* CrtcVAdjusted */
	0,		/* PrivSize */
	NULL,		/* Private */
	0.0,		/* HSync */
	0.0		/* VRefresh */
};
#endif

#define VERSION 4000
#define CHIPS_NAME "CHIPS"
#define CHIPS_DRIVER_NAME "chips"
#define CHIPS_MAJOR_VERSION 1
#define CHIPS_MINOR_VERSION 0
#define CHIPS_PATCHLEVEL 0

/*
 * This contains the functions needed by the server after loading the driver
 * module.  It must be supplied, and gets passed back by the SetupProc
 * function in the dynamic case.  In the static case, a reference to this
 * is compiled in, and this requires that the name of this DriverRec be
 * an upper-case version of the driver name.
 */

DriverRec CHIPS = {
	VERSION,
	CHIPS_DRIVER_NAME,
	CHIPSIdentify,
	CHIPSProbe,
	CHIPSAvailableOptions,
	NULL,
	0
};

static SymTabRec CHIPSChipsets[] = {
    { CHIPS_CT65520,		"ct65520" },
    { CHIPS_CT65525,		"ct65525" },
    { CHIPS_CT65530,		"ct65530" },
    { CHIPS_CT65535,		"ct65535" },
    { CHIPS_CT65540,		"ct65540" },
    { CHIPS_CT65545,		"ct65545" },
    { CHIPS_CT65546,		"ct65546" },
    { CHIPS_CT65548,		"ct65548" },
    { CHIPS_CT65550,		"ct65550" },
    { CHIPS_CT65554,		"ct65554" },
    { CHIPS_CT65555,		"ct65555" },
    { CHIPS_CT68554,		"ct68554" },
    { CHIPS_CT69000,		"ct69000" },
    { CHIPS_CT69030,		"ct69030" },
    { CHIPS_CT64200,		"ct64200" },
    { CHIPS_CT64300,		"ct64300" },
    { -1,			NULL }
};

/* Conversion PCI ID to chipset name */
static PciChipsets CHIPSPCIchipsets[] = {
    { CHIPS_CT65545, PCI_CHIP_65545, RES_SHARED_VGA },
    { CHIPS_CT65548, PCI_CHIP_65548, RES_SHARED_VGA },
    { CHIPS_CT65550, PCI_CHIP_65550, RES_SHARED_VGA },
    { CHIPS_CT65554, PCI_CHIP_65554, RES_SHARED_VGA },
    { CHIPS_CT65555, PCI_CHIP_65555, RES_SHARED_VGA },
    { CHIPS_CT68554, PCI_CHIP_68554, RES_SHARED_VGA },
    { CHIPS_CT69000, PCI_CHIP_69000, RES_SHARED_VGA },
    { CHIPS_CT69030, PCI_CHIP_69030, RES_SHARED_VGA },
    { -1,	     -1,	     RES_UNDEFINED}
};

static IsaChipsets CHIPSISAchipsets[] = {
    { CHIPS_CT65520,		RES_EXCLUSIVE_VGA },
    { CHIPS_CT65525,		RES_EXCLUSIVE_VGA },
    { CHIPS_CT65530,		RES_EXCLUSIVE_VGA },
    { CHIPS_CT65535,		RES_EXCLUSIVE_VGA },
    { CHIPS_CT65540,		RES_EXCLUSIVE_VGA },
    { CHIPS_CT65545,		RES_EXCLUSIVE_VGA },
    { CHIPS_CT65546,		RES_EXCLUSIVE_VGA },
    { CHIPS_CT65548,		RES_EXCLUSIVE_VGA },
    { CHIPS_CT65550,		RES_EXCLUSIVE_VGA },
    { CHIPS_CT65554,		RES_EXCLUSIVE_VGA },
    { CHIPS_CT65555,		RES_EXCLUSIVE_VGA },
    { CHIPS_CT68554,		RES_EXCLUSIVE_VGA },
    { CHIPS_CT69000,		RES_EXCLUSIVE_VGA },
    { CHIPS_CT69030,		RES_EXCLUSIVE_VGA },
    { CHIPS_CT64200,		RES_EXCLUSIVE_VGA },
    { CHIPS_CT64300,		RES_EXCLUSIVE_VGA },
    { -1,			RES_UNDEFINED }
};

/* The options supported by the Chips and Technologies Driver */
typedef enum {
    OPTION_LINEAR,
    OPTION_NOACCEL,
    OPTION_HW_CLKS,
    OPTION_SW_CURSOR,
    OPTION_HW_CURSOR,
    OPTION_STN,
    OPTION_USE_MODELINE,
    OPTION_LCD_STRETCH,
    OPTION_LCD_CENTER,
    OPTION_MMIO,
    OPTION_FULL_MMIO,
    OPTION_SUSPEND_HACK,
    OPTION_RGB_BITS,
    OPTION_SYNC_ON_GREEN,
    OPTION_PANEL_SIZE,
    OPTION_18_BIT_BUS,
    OPTION_SHOWCACHE,
    OPTION_SHADOW_FB,
    OPTION_OVERLAY,
    OPTION_COLOR_KEY,
    OPTION_VIDEO_KEY,
    OPTION_FP_CLOCK_8,
    OPTION_FP_CLOCK_16,
    OPTION_FP_CLOCK_24,
    OPTION_FP_CLOCK_32,
    OPTION_SET_MCLK,
    OPTION_ROTATE,
    OPTION_NO_TMED,
    OPTION_CRT2_MEM,
    OPTION_DUAL_REFRESH,
    OPTION_CRT_CLK_INDX,
    OPTION_FP_CLK_INDX,
    OPTION_FP_MODE
} CHIPSOpts;

static const OptionInfoRec Chips655xxOptions[] = {
    { OPTION_LINEAR,		"Linear",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_NOACCEL,		"NoAccel",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_HW_CLKS,		"HWclocks",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_SW_CURSOR,		"SWcursor",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_HW_CURSOR,		"HWcursor",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_STN,		"STN",		OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_USE_MODELINE,	"UseModeline",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_LCD_STRETCH,	"Stretch",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_LCD_CENTER,	"LcdCenter",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_MMIO,		"MMIO",		OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_SUSPEND_HACK,	"SuspendHack",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_PANEL_SIZE,	"FixPanelSize",	OPTV_BOOLEAN,	{0}, FALSE },
#if 0
    { OPTION_RGB_BITS,		"RGBbits",	OPTV_INTEGER,	{0}, FALSE },
#endif
    { OPTION_18_BIT_BUS,	"18BitBus",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_SHOWCACHE,		"ShowCache",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_SHADOW_FB,		"ShadowFB",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_ROTATE, 	        "Rotate",	OPTV_ANYSTR,	{0}, FALSE },
    { OPTION_SET_MCLK,		"SetMclk",	OPTV_FREQ,      {0}, FALSE },
    { OPTION_FP_CLOCK_8,        "FPClock8",	OPTV_FREQ,      {0}, FALSE },
    { OPTION_FP_CLOCK_16,	"FPClock16",	OPTV_FREQ,      {0}, FALSE },
    { OPTION_FP_CLOCK_24,	"FPClock24",	OPTV_FREQ,      {0}, FALSE },
    { OPTION_FP_MODE,		"FPMode",	OPTV_BOOLEAN,   {0}, FALSE },
    { -1,			NULL,		OPTV_NONE,	{0}, FALSE }
};

static const OptionInfoRec ChipsWingineOptions[] = {
    { OPTION_LINEAR,		"Linear",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_NOACCEL,		"NoAccel",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_HW_CLKS,		"HWclocks",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_SW_CURSOR,		"SWcursor",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_HW_CURSOR,		"HWcursor",	OPTV_BOOLEAN,	{0}, FALSE },
#if 0
    { OPTION_RGB_BITS,		"RGBbits",	OPTV_INTEGER,	{0}, FALSE },
#endif
    { OPTION_SHOWCACHE,		"ShowCache",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_SHADOW_FB,		"ShadowFB",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_ROTATE,  	        "Rotate",	OPTV_ANYSTR,	{0}, FALSE },
    { -1,			NULL,		OPTV_NONE,	{0}, FALSE }
};

static const OptionInfoRec ChipsHiQVOptions[] = {
    { OPTION_LINEAR,		"Linear",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_NOACCEL,		"NoAccel",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_SW_CURSOR,		"SWcursor",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_HW_CURSOR,		"HWcursor",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_STN,		"STN",		OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_USE_MODELINE,	"UseModeline",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_LCD_STRETCH,	"Stretch",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_LCD_CENTER,	"LcdCenter",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_MMIO,		"MMIO",		OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_FULL_MMIO,		"FullMMIO",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_SUSPEND_HACK,	"SuspendHack",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_PANEL_SIZE,	"FixPanelSize",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_RGB_BITS,		"RGBbits",	OPTV_INTEGER,	{0}, FALSE },
    { OPTION_SYNC_ON_GREEN,	"SyncOnGreen",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_SHOWCACHE,		"ShowCache",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_SHADOW_FB,		"ShadowFB",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_ROTATE, 	        "Rotate",	OPTV_ANYSTR,	{0}, FALSE },
    { OPTION_OVERLAY,		"Overlay",	OPTV_ANYSTR,	{0}, FALSE },
    { OPTION_COLOR_KEY,		"ColorKey",	OPTV_INTEGER,	{0}, FALSE },
    { OPTION_VIDEO_KEY,		"VideoKey",	OPTV_INTEGER,	{0}, FALSE },
    { OPTION_FP_CLOCK_8,	"FPClock8",	OPTV_FREQ,      {0}, FALSE },
    { OPTION_FP_CLOCK_16,	"FPClock16",	OPTV_FREQ,      {0}, FALSE },
    { OPTION_FP_CLOCK_24,	"FPClock24",	OPTV_FREQ,      {0}, FALSE },
    { OPTION_FP_CLOCK_32,	"FPClock32",	OPTV_FREQ,      {0}, FALSE },
    { OPTION_SET_MCLK,		"SetMclk",	OPTV_FREQ,      {0}, FALSE },
    { OPTION_NO_TMED,		"NoTMED",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_CRT2_MEM,		"Crt2Memory",	OPTV_INTEGER,	{0}, FALSE },
    { OPTION_DUAL_REFRESH,	"DualRefresh",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_CRT_CLK_INDX,	"CrtClkIndx",	OPTV_INTEGER,	{0}, FALSE },
    { OPTION_FP_CLK_INDX,	"FPClkIndx",	OPTV_INTEGER,	{0}, FALSE },
    { OPTION_FP_MODE,		"FPMode",	OPTV_BOOLEAN,   {0}, FALSE },
    { -1,			NULL,		OPTV_NONE,	{0}, FALSE }
};

/*
 * List of symbols from other modules that this module references.  This
 * list is used to tell the loader that it is OK for symbols here to be
 * unresolved providing that it hasn't been told that they haven't been
 * told that they are essential via a call to xf86LoaderModReqSymbols() or
 * xf86LoaderModReqSymLists().  The purpose is this is to avoid warnings about
 * unresolved symbols that are not required.
 */

static const char *vgahwSymbols[] = {
    "vgaHWAllocDefaultRegs",
    "vgaHWFreeHWRec",
    "vgaHWGetHWRec",
    "vgaHWGetIOBase",
    "vgaHWGetIndex",
    "vgaHWHBlankKGA",
    "vgaHWInit",
    "vgaHWLock",
    "vgaHWMapMem",
    "vgaHWProtect",
    "vgaHWRestore",
    "vgaHWSave",
    "vgaHWUnlock",
    "vgaHWVBlankKGA",
    "vgaHWddc1SetSpeed",
    NULL
};

#ifdef XFree86LOADER
static const char *miscfbSymbols[] = {
    "xf1bppScreenInit",
    "xf4bppScreenInit",
    "cfb8_16ScreenInit",
    NULL
};
#endif

static const char *fbSymbols[] = {
    "fbScreenInit",
    "fbPictureInit",
    NULL
};

static const char *xaaSymbols[] = {
    "XAACreateInfoRec",
    "XAADestroyInfoRec",
    "XAAInit",
    "XAAInitDualFramebufferOverlay",
    "XAAStippleScanlineFuncMSBFirst",
    NULL
};

static const char *ramdacSymbols[] = {
    "xf86CreateCursorInfoRec",
    "xf86DestroyCursorInfoRec",
    "xf86InitCursor",
    NULL
};

static const char *ddcSymbols[] = {
    "xf86DoEDID_DDC1",
    "xf86DoEDID_DDC2",
    "xf86PrintEDID",
    "xf86SetDDCproperties",
    NULL
};

static const char *i2cSymbols[] = {
    "xf86CreateI2CBusRec",
    "xf86I2CBusInit",
    "xf86I2CFindBus",
    "xf86I2CProbeAddress",
    NULL
};

static const char *shadowSymbols[] = {
    "ShadowFBInit",
    NULL
};

static const char *vbeSymbols[] = {
    "VBEInit",
    "vbeDoEDID",
    "vbeFree",
    NULL
};

#ifdef XFree86LOADER

static MODULESETUPPROTO(chipsSetup);

static XF86ModuleVersionInfo chipsVersRec =
{
	"chips",
	MODULEVENDORSTRING,
	MODINFOSTRING1,
	MODINFOSTRING2,
	XF86_VERSION_CURRENT,
	CHIPS_MAJOR_VERSION, CHIPS_MINOR_VERSION, CHIPS_PATCHLEVEL,
	ABI_CLASS_VIDEODRV,
	ABI_VIDEODRV_VERSION,
	MOD_CLASS_VIDEODRV,
	{0,0,0,0}
};

/*
 * This is the module init data.
 * Its name has to be the driver name followed by ModuleData
 */
XF86ModuleData chipsModuleData = { &chipsVersRec, chipsSetup, NULL };

static pointer
chipsSetup(ModuleDescPtr module, pointer opts, int *errmaj, int *errmin)
{
    static Bool setupDone = FALSE;

    if (!setupDone) {
	setupDone = TRUE;
        xf86AddDriver(&CHIPS, module, 0);

	/*
	 * Modules that this driver always requires can be loaded here
	 * by calling LoadSubModule().
	 */

	/*
	 * Tell the loader about symbols from other modules that this module
	 * might refer to.
	 */
	LoaderModRefSymLists(module, vgahwSymbols, miscfbSymbols, fbSymbols,
			     xaaSymbols, ramdacSymbols, ddcSymbols,
			     i2cSymbols, shadowSymbols, vbeSymbols, NULL);

	/*
	 * The return value must be non-NULL on success even though there
	 * is no TearDownProc.
	 */
	return (pointer)1;
    } else {
	if (errmaj) *errmaj = LDR_ONCEONLY;
	return NULL;
    }
}

#endif /* XFree86LOADER */

static Bool
CHIPSGetRec(ScrnInfoPtr pScrn)
{
    /*
     * Allocate a CHIPSRec, and hook it into pScrn->driverPrivate.
     * pScrn->driverPrivate is initialised to NULL, so we can check if
     * the allocation has already been done.
     */
    if (pScrn->driverPrivate != NULL)
	return TRUE;

    pScrn->driverPrivate = xnfcalloc(sizeof(CHIPSRec), 1);

    if (pScrn->driverPrivate == NULL)
	return FALSE;
    
    return TRUE;
}

static void
CHIPSFreeRec(ScrnInfoPtr pScrn)
{
    CHIPSPtr    cPtr = CHIPSPTR(pScrn);

    if (!cPtr)
	return;

    cPtr = CHIPSPTR(pScrn);
    if (cPtr->pVbe) {
	vbeFree(cPtr->pVbe);
	cPtr->pVbe = NULL;
    }
    xfree(cPtr);
    pScrn->driverPrivate = NULL;
}

/* Mandatory */
static void
CHIPSIdentify(int flags)
{
    xf86PrintChipsets(CHIPS_NAME, "Driver for Chips and Technologies chipsets",
			CHIPSChipsets);
}

static const OptionInfoRec *
CHIPSAvailableOptions(int chipid, int busid)
{
    int chip = chipid & 0x0000ffff;

    if (busid == BUS_ISA) {
    	if ((chip == CHIPS_CT64200) || (chip == CHIPS_CT64300)) 
	    return ChipsWingineOptions;
    }
    if (busid == BUS_PCI) {
    	if ((chip >= CHIPS_CT65550) && (chip <= CHIPS_CT69030))
	    return ChipsHiQVOptions;
    }
    return Chips655xxOptions;
}

/* Mandatory */
static Bool
CHIPSProbe(DriverPtr drv, int flags)
{
    Bool foundScreen = FALSE;
    int numDevSections, numUsed;
    GDevPtr *devSections;
    int *usedChips;
    int i;
    
    /*
     * Find the config file Device sections that match this
     * driver, and return if there are none.
     */
    if ((numDevSections = xf86MatchDevice(CHIPS_DRIVER_NAME,
					  &devSections)) <= 0) {
	return FALSE;
    }
    /* PCI BUS */
    if (xf86GetPciVideoInfo() ) {
	numUsed = xf86MatchPciInstances(CHIPS_NAME, PCI_VENDOR_CHIPSTECH,
					CHIPSChipsets, CHIPSPCIchipsets, 
					devSections,numDevSections, drv,
					&usedChips);
	if (numUsed > 0) {
	    if (flags & PROBE_DETECT)
		foundScreen = TRUE;
	    else for (i = 0; i < numUsed; i++) {
		EntityInfoPtr pEnt;
		/* Allocate a ScrnInfoRec  */
		ScrnInfoPtr pScrn = NULL;
		if ((pScrn = xf86ConfigPciEntity(pScrn,0,usedChips[i],
						       CHIPSPCIchipsets,NULL,
						       NULL,NULL,NULL,NULL))){
		    pScrn->driverVersion = VERSION;
		    pScrn->driverName    = CHIPS_DRIVER_NAME;
		    pScrn->name          = CHIPS_NAME;
		    pScrn->Probe         = CHIPSProbe;
		    pScrn->PreInit       = CHIPSPreInit;
		    pScrn->ScreenInit    = CHIPSScreenInit;
		    pScrn->SwitchMode    = CHIPSSwitchMode;
		    pScrn->AdjustFrame   = CHIPSAdjustFrame;
		    pScrn->EnterVT       = CHIPSEnterVT;
		    pScrn->LeaveVT       = CHIPSLeaveVT;
		    pScrn->FreeScreen    = CHIPSFreeScreen;
		    pScrn->ValidMode     = CHIPSValidMode;
		    foundScreen = TRUE;
		}

		/*
		 * For cards that can do dual head per entity, mark the entity
		 * as sharable.
		 */
		pEnt = xf86GetEntityInfo(usedChips[i]);
		if (pEnt->chipset == CHIPS_CT69030) {
		    CHIPSEntPtr cPtrEnt = NULL;
		    DevUnion *pPriv;

		    xf86SetEntitySharable(usedChips[i]);
		    /* Allocate an entity private if necessary */
		    if (CHIPSEntityIndex < 0)
			CHIPSEntityIndex = xf86AllocateEntityPrivateIndex();
		    pPriv = xf86GetEntityPrivate(pScrn->entityList[0], 
				CHIPSEntityIndex);
		    if (!pPriv->ptr) {
			pPriv->ptr = xnfcalloc(sizeof(CHIPSEntRec), 1);
			cPtrEnt = pPriv->ptr;
			cPtrEnt->lastInstance = -1;
		    } else {
			cPtrEnt = pPriv->ptr;
		    }
		    /*
		     * Set the entity instance for this instance of the 
		     * driver.  For dual head per card, instance 0 is the 
		     * "master" instance, driving the primary head, and 
                     * instance 1 is the "slave".
		     */
		    cPtrEnt->lastInstance++;
		    xf86SetEntityInstanceForScreen(pScrn, pScrn->entityList[0],
						   cPtrEnt->lastInstance);
		}

	    }
	    xfree(usedChips);
	}
    }
    
    /* Isa Bus */
    numUsed = xf86MatchIsaInstances(CHIPS_NAME,CHIPSChipsets,CHIPSISAchipsets,
				    drv,chipsFindIsaDevice,devSections,
				    numDevSections,&usedChips);
    if (numUsed > 0) {
	if (flags & PROBE_DETECT)
	    foundScreen = TRUE;
	else for (i = 0; i < numUsed; i++) {
	    ScrnInfoPtr pScrn = NULL;
	    if ((pScrn = xf86ConfigIsaEntity(pScrn,0,
						   usedChips[i],
						   CHIPSISAchipsets,NULL,
						   NULL,NULL,NULL,NULL))) {
		pScrn->driverVersion = VERSION;
		pScrn->driverName    = CHIPS_DRIVER_NAME;
		pScrn->name          = CHIPS_NAME;
		pScrn->Probe         = CHIPSProbe;
		pScrn->PreInit       = CHIPSPreInit;
		pScrn->ScreenInit    = CHIPSScreenInit;
		pScrn->SwitchMode    = CHIPSSwitchMode;
		pScrn->AdjustFrame   = CHIPSAdjustFrame;
		pScrn->EnterVT       = CHIPSEnterVT;
		pScrn->LeaveVT       = CHIPSLeaveVT;
		pScrn->FreeScreen    = CHIPSFreeScreen;
		pScrn->ValidMode     = CHIPSValidMode;
		foundScreen = TRUE;
	    }
	    xfree(usedChips);
	}
    }
    
    xfree(devSections);
    return foundScreen;
}

static int
chipsFindIsaDevice(GDevPtr dev)
{
    int found = -1;
    unsigned char tmp;

    /* 
     * This function has the only direct register access in the C&T driver. 
     * All other register access through functions to allow for full MMIO.
     */
    outb(0x3D6, 0x00);
    tmp = inb(0x3D7);

    switch (tmp & 0xF0) {
    case 0x70: 		/* CT65520 */
	found = CHIPS_CT65520; break;
    case 0x80:		/* CT65525 or CT65530 */
	found = CHIPS_CT65530; break;
    case 0xA0:		/* CT64200 */
	found = CHIPS_CT64200; break;
    case 0xB0:		/* CT64300 */
	found = CHIPS_CT64300; break;
    case 0xC0:		/* CT65535 */
	found = CHIPS_CT65535; break;
    default:
	switch (tmp & 0xF8) {
	    case 0xD0:		/* CT65540 */
		found = CHIPS_CT65540; break;
	    case 0xD8:		/* CT65545 or CT65546 or CT65548 */
		switch (tmp & 7) {
		case 3:
		    found = CHIPS_CT65546; break;
		case 4:
		    found = CHIPS_CT65548; break;
		default:
		    found = CHIPS_CT65545; break;

		}
		break;
	    default:
		if (tmp == 0x2C) {
		    outb(0x3D6, 0x01);
		    tmp = inb(0x3D7);
		    if (tmp != 0x10) break;
		    outb(0x3D6, 0x02);
		    tmp = inb(0x3D7);
		    switch (tmp) {
		    case 0xE0:		/* CT65550 */
			found = CHIPS_CT65550; break;
		    case 0xE4:		/* CT65554 */
			found = CHIPS_CT65554; break;
		    case 0xE5:		/* CT65555 */
			found = CHIPS_CT65555; break;
		    case 0xF4:		/* CT68554 */
			found = CHIPS_CT68554; break;
		    case 0xC0:		/* CT69000 */
			found = CHIPS_CT69000; break;
		    case 0x30:		/* CT69030 */
			outb(0x3D6, 0x03);
			tmp = inb(0x3D7);
			if (tmp == 0xC)
			    found = CHIPS_CT69030;
			break;
		    default:
			break;
		    }
		}
		break;
	}
	break;
    }
    /* We only want ISA/VL Bus - so check for PCI Bus */
    if(found > CHIPS_CT65548) {
	outb(0x3D6, 0x08);
	tmp = inb(0x3D7);
	if(tmp & 0x01) found = -1; 
    } else if(found > CHIPS_CT65535) {
	outb(0x3D6, 0x01);
	tmp = inb(0x3D7);
	if ((tmp & 0x07) == 0x06) found = -1;
    }
    return found;
}

/* Mandatory */
Bool
CHIPSPreInit(ScrnInfoPtr pScrn, int flags)
{
    pciVideoPtr pciPtr;
    ClockRangePtr clockRanges;
    int i;
    CHIPSPtr cPtr;
    Bool res = FALSE;
    CHIPSEntPtr cPtrEnt = NULL;
    ModuleDescPtr pMod;

    if (flags & PROBE_DETECT) return FALSE;

    /* The vgahw module should be loaded here when needed */
    if (!(pMod = xf86LoadSubModule(pScrn, "vgahw")))
	return FALSE;
    xf86LoaderModReqSymLists(pMod, vgahwSymbols, NULL);

    /* Allocate the ChipsRec driverPrivate */
    if (!CHIPSGetRec(pScrn)) {
	return FALSE;
    }
    cPtr = CHIPSPTR(pScrn);

    /* XXX Check the number of entities, and fail if it isn't one. */
    if (pScrn->numEntities != 1)
	return FALSE;

    /* Since the capabilities are determined by the chipset the very
     * first thing to do is, figure out the chipset and its capabilities
     */

    /* This is the general case */
    for (i = 0; i<pScrn->numEntities; i++) {
	cPtr->pEnt = xf86GetEntityInfo(pScrn->entityList[i]);
	if (cPtr->pEnt->resources) return FALSE;
	cPtr->Chipset = cPtr->pEnt->chipset;
	pScrn->chipset = (char *)xf86TokenToString(CHIPSChipsets,
						   cPtr->pEnt->chipset);
	if ((cPtr->Chipset == CHIPS_CT64200) ||
	    (cPtr->Chipset == CHIPS_CT64300)) cPtr->Flags |= ChipsWingine;
	if ((cPtr->Chipset >= CHIPS_CT65550) &&
	    (cPtr->Chipset <= CHIPS_CT69030)) cPtr->Flags |= ChipsHiQV;

	/* This driver can handle ISA and PCI buses */
	if (cPtr->pEnt->location.type == BUS_PCI) {
	    pciPtr = xf86GetPciInfoForEntity(cPtr->pEnt->index);
	    cPtr->PciInfo = pciPtr;
	    cPtr->PciTag = pciTag(cPtr->PciInfo->bus, 
				  cPtr->PciInfo->device,
				  cPtr->PciInfo->func);
	}
    }
    /* INT10 */
#if 0
    if ((pMod = xf86LoadSubModule(pScrn, "int10"))) {
 	xf86Int10InfoPtr pInt;
	xf86LoaderModReqSymLists(pMod, int10Symbols, NULL);
#if 1
	xf86DrvMsg(pScrn->scrnIndex,X_INFO,"initializing int10\n");
	pInt = xf86InitInt10(cPtr->pEnt->index);
	xf86FreeInt10(pInt);
#endif
    }
#endif

    if ((pMod = xf86LoadVBEModule(pScrn))) {
	xf86LoaderModReqSymLists(pMod, vbeSymbols, NULL);
	cPtr->pVbe =  VBEInit(NULL,cPtr->pEnt->index);
    }
    
    /* Now that we've identified the chipset, setup the capabilities flags */
    switch (cPtr->Chipset) {
    case CHIPS_CT69030:
	cPtr->Flags |= ChipsDualChannelSupport;
    case CHIPS_CT69000:
	cPtr->Flags |= ChipsFullMMIOSupport;
	/* Fall through */
    case CHIPS_CT65555:
	cPtr->Flags |= ChipsImageReadSupport; /* Does the 69000 support it? */
	/* Fall through */
    case CHIPS_CT68554:
	cPtr->Flags |= ChipsTMEDSupport;
	/* Fall through */
    case CHIPS_CT65554:
    case CHIPS_CT65550:
	cPtr->Flags |= ChipsGammaSupport;
	cPtr->Flags |= ChipsVideoSupport;
	/* Fall through */
    case CHIPS_CT65548:
    case CHIPS_CT65546:
    case CHIPS_CT65545:
	cPtr->Flags |= ChipsMMIOSupport;
	/* Fall through */
    case CHIPS_CT64300:
	cPtr->Flags |= ChipsAccelSupport;
	/* Fall through */
    case CHIPS_CT65540:
	cPtr->Flags |= ChipsHDepthSupport;
	cPtr->Flags |= ChipsDPMSSupport;
	/* Fall through */
    case CHIPS_CT65535:
    case CHIPS_CT65530:
    case CHIPS_CT65525:
	cPtr->Flags |= ChipsLinearSupport;
	/* Fall through */
    case CHIPS_CT64200:
    case CHIPS_CT65520:
	break;
    }

    /* Check for shared entities */
    if (xf86IsEntityShared(pScrn->entityList[0])) {
        if (!(cPtr->Flags & ChipsDualChannelSupport)) 
	    return FALSE;

	/* Make sure entity is PCI for now, though this might not be needed. */
	if (cPtr->pEnt->location.type != BUS_PCI)
	    return FALSE;

	/* Allocate an entity private if necessary */
	if (xf86IsEntityShared(pScrn->entityList[0])) {
	    cPtrEnt = xf86GetEntityPrivate(pScrn->entityList[0],
					CHIPSEntityIndex)->ptr;
	    cPtr->entityPrivate = cPtrEnt;
	}
#if 0
	/* Set cPtr->device to the relevant Device section */
	cPtr->device = xf86GetDevFromEntity(pScrn->entityList[0],
					    pScrn->entityInstanceList[0]);
#endif
    }

    /* Set the driver to use the PIO register functions by default */
    CHIPSSetStdExtFuncs(cPtr);

    /* Call the device specific PreInit */
    if (IS_HiQV(cPtr)) 
	res = chipsPreInitHiQV(pScrn, flags);
    else if (IS_Wingine(cPtr)) 
	res = chipsPreInitWingine(pScrn, flags);
    else 
	res = chipsPreInit655xx(pScrn, flags);

    if (cPtr->UseFullMMIO)
	chipsUnmapMem(pScrn);

    if (!res) {
	CHIPSFreeRec(pScrn);
	return FALSE;
    }
    
/*********/
    /*
     * Setup the ClockRanges, which describe what clock ranges are available,
     * and what sort of modes they can be used for.
     */
    clockRanges = xnfcalloc(sizeof(ClockRange), 1);
    clockRanges->next = NULL;
    clockRanges->ClockMulFactor = cPtr->ClockMulFactor;
    clockRanges->minClock = cPtr->MinClock;
    clockRanges->maxClock = cPtr->MaxClock;
    clockRanges->clockIndex = -1;		/* programmable */
    if (cPtr->PanelType & ChipsLCD) {
	clockRanges->interlaceAllowed = FALSE;
	clockRanges->doubleScanAllowed = FALSE;
    } else {
	clockRanges->interlaceAllowed = TRUE;
        clockRanges->doubleScanAllowed = TRUE;
    }
    /* 
     * Reduce the amount of video ram for the modes, so that they
     * don't overlap with the DSTN framebuffer
     */
    pScrn->videoRam -= (cPtr->FrameBufferSize + 1023) / 1024;
    
    cPtr->Rounding = 8 * (pScrn->bitsPerPixel <= 8 ? 8 
			  : pScrn->bitsPerPixel);

    i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,
			  pScrn->display->modes, clockRanges,
			  NULL, 256, 2048, cPtr->Rounding,
			  128, 2048, pScrn->display->virtualX,
			  pScrn->display->virtualY, cPtr->FbMapSize,
			  LOOKUP_BEST_REFRESH);

    if (i == -1) {
	CHIPSFreeRec(pScrn);
	return FALSE;
    }

    /*
     * Put the DSTN framebuffer back into the video ram
     */
    pScrn->videoRam += (cPtr->FrameBufferSize + 1023) / 1024;

    /* Prune the modes marked as invalid */
    xf86PruneDriverModes(pScrn);

    if (i == 0 || pScrn->modes == NULL) {
	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n");
	CHIPSFreeRec(pScrn);
	return FALSE;
    }

    /*
     * Set the CRTC parameters for all of the modes based on the type
     * of mode, and the chipset's interlace requirements.
     *
     * Calling this is required if the mode->Crtc* values are used by the
     * driver and if the driver doesn't provide code to set them.  They
     * are not pre-initialised at all.
     */
    xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V);

    /* Set the current mode to the first in the list */
    pScrn->currentMode = pScrn->modes;

    /* Print the list of modes being used */
    xf86PrintModes(pScrn);

    /* If monitor resolution is set on the command line, use it */
    xf86SetDpi(pScrn, 0, 0);

    /* Load bpp-specific modules */
    switch (pScrn->bitsPerPixel) {
    case 1:
	if (!(pMod = xf86LoadSubModule(pScrn, "xf1bpp"))) {
	    CHIPSFreeRec(pScrn);
	    return FALSE;
	}	
	xf86LoaderModReqSymbols(pMod, "xf1bppScreenInit", NULL);
	break;
    case 4:
	if (!(pMod = xf86LoadSubModule(pScrn, "xf4bpp"))) {
	    CHIPSFreeRec(pScrn);
	    return FALSE;
	}
	xf86LoaderModReqSymbols(pMod, "xf4bppScreenInit", NULL);
	break;
    case 16:
	if (cPtr->Flags & ChipsOverlay8plus16) {
	    if (!(pMod = xf86LoadSubModule(pScrn, "xf8_16bpp"))) {
	        CHIPSFreeRec(pScrn);
		return FALSE;
	    }	
	    xf86LoaderModReqSymbols(pMod, "cfb8_16bppScreenInit", NULL);
	    break;
	}
    default:
	if (!(pMod = xf86LoadSubModule(pScrn, "fb"))) {
	    CHIPSFreeRec(pScrn);
	    return FALSE;
	}	
	xf86LoaderModReqSymLists(pMod, fbSymbols, NULL);
	break;
    }
    
    if (cPtr->Flags & ChipsAccelSupport) {
	if (!(pMod = xf86LoadSubModule(pScrn, "xaa"))) {
	    CHIPSFreeRec(pScrn);
	    return FALSE;
	}
	xf86LoaderModReqSymLists(pMod, xaaSymbols, NULL);
    }

    if (cPtr->Flags & ChipsShadowFB) {
	if (!(pMod = xf86LoadSubModule(pScrn, "shadowfb"))) {
	    CHIPSFreeRec(pScrn);
	    return FALSE;
	}
	xf86LoaderModReqSymLists(pMod, shadowSymbols, NULL);
    }
    
    if (cPtr->Accel.UseHWCursor) {
	if (!(pMod = xf86LoadSubModule(pScrn, "ramdac"))) {
	    CHIPSFreeRec(pScrn);
	    return FALSE;
	}
	xf86LoaderModReqSymLists(pMod, ramdacSymbols, NULL);
    }

    if (cPtr->Flags & ChipsLinearSupport) 
 	xf86SetOperatingState(resVgaMem, cPtr->pEnt->index, ResDisableOpr);

    if (cPtr->MMIOBaseVGA)
 	xf86SetOperatingState(resVgaIo, cPtr->pEnt->index, ResDisableOpr);
    return TRUE;
}

static Bool
chipsPreInitHiQV(ScrnInfoPtr pScrn, int flags)
{
    int bytesPerPixel;
    unsigned char tmp;
    MessageType from;
    int i;
    unsigned int Probed[3], FPclkI, CRTclkI;
    double real;
    int val, indx;
    const char *s;
    ModuleDescPtr pDDCModule = NULL, pMod;

    vgaHWPtr hwp;
    CHIPSPtr cPtr = CHIPSPTR(pScrn);
    CHIPSEntPtr cPtrEnt = NULL;
    CHIPSPanelSizePtr Size = &cPtr->PanelSize;
    CHIPSMemClockPtr MemClk = &cPtr->MemClock;
    CHIPSClockPtr SaveClk = &(cPtr->SavedReg.Clock);
    resRange linearRes[] = { {ResExcMemBlock|ResBios|ResBus,0,0},_END };

    /* Set pScrn->monitor */
    pScrn->monitor = pScrn->confScreen->monitor;
    
    /* All HiQV chips support 16/24/32 bpp */
    if (!xf86SetDepthBpp(pScrn, 0, 0, 0, Support24bppFb | Support32bppFb |
				SupportConvert32to24 | PreferConvert32to24))
	return FALSE;
    else {
	/* Check that the returned depth is one we support */
	switch (pScrn->depth) {
	case 1:
	case 4:
	case 8:
	case 15:
	case 16:
	case 24:
	case 32:
	    /* OK */
	    break;
	default:
	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
		       "Given depth (%d) is not supported by this driver\n",
		       pScrn->depth);
	    return FALSE;
	}
    }
    xf86PrintDepthBpp(pScrn);

    /* Get the depth24 pixmap format */
    if (pScrn->depth == 24 && pix24bpp == 0)
	pix24bpp = xf86GetBppFromDepth(pScrn, 24);

    /*
     * Allocate a vgaHWRec, this must happen after xf86SetDepthBpp for 1bpp
     */
    if (!vgaHWGetHWRec(pScrn))
        return FALSE;

    hwp = VGAHWPTR(pScrn);
    vgaHWGetIOBase(hwp);
    cPtr->PIOBase = hwp->PIOOffset;

    /*
     * Must allow ensure that storage for the 2nd set of vga registers is
     * allocated for dual channel cards
     */
    if ((cPtr->Flags & ChipsDualChannelSupport) && 
		(! xf86IsEntityShared(pScrn->entityList[0])))
	vgaHWAllocDefaultRegs(&(cPtr->VgaSavedReg2));

    /*
     * This must happen after pScrn->display has been set because
     * xf86SetWeight references it.
     */
    if (pScrn->depth > 8) {
	/* The defaults are OK for us */
	rgb zeros = {0, 0, 0};
	
	if (!xf86SetWeight(pScrn, zeros, zeros)) {
	    return FALSE;
	} else {
	    /* XXX check that weight returned is supported */
            ;
        }
    }

    if (!xf86SetDefaultVisual(pScrn, -1)) 
	return FALSE;

    /* The gamma fields must be initialised when using the new cmap code */
    if (pScrn->depth > 1) {
	Gamma zeros = {0.0, 0.0, 0.0};

	if (!xf86SetGamma(pScrn, zeros))
	    return FALSE;
    }

    bytesPerPixel = max(1, pScrn->bitsPerPixel >> 3);

    /* Collect all of the relevant option flags (fill in pScrn->options) */
    xf86CollectOptions(pScrn, NULL);
    /* Process the options */
    if (!(cPtr->Options = xalloc(sizeof(ChipsHiQVOptions))))
	return FALSE;
    memcpy(cPtr->Options, ChipsHiQVOptions, sizeof(ChipsHiQVOptions));
    xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, cPtr->Options);

    /* Set the bits per RGB */
    if (pScrn->depth > 1) {
	/* Default to 6, is this right for HiQV?? */
	pScrn->rgbBits = 8;
	if (xf86GetOptValInteger(cPtr->Options, OPTION_RGB_BITS, &val)) {
	    if (val == 6 || val == 8) {
		pScrn->rgbBits = val;
		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Bits per RGB set to "
			   "%d\n", pScrn->rgbBits);
	    } else 
		xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Invalid number of "
			   "rgb bits %d\n", val);
	}
    }
    if ((cPtr->Flags & ChipsAccelSupport) &&
	(xf86ReturnOptValBool(cPtr->Options, OPTION_NOACCEL, FALSE))) {
	cPtr->Flags &= ~ChipsAccelSupport;
	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Acceleration disabled\n");
    }
    
    from = X_DEFAULT;
    if (pScrn->bitsPerPixel < 8) {
	/* Default to SW cursor for 1/4 bpp */
	cPtr->Accel.UseHWCursor = FALSE;
    } else {
	cPtr->Accel.UseHWCursor = TRUE;
    }
    if (xf86GetOptValBool(cPtr->Options, OPTION_HW_CURSOR,
			  &cPtr->Accel.UseHWCursor))
	from = X_CONFIG;
    if (xf86GetOptValBool(cPtr->Options, OPTION_SW_CURSOR,
			  &cPtr->Accel.UseHWCursor)) {
	from = X_CONFIG;
	cPtr->Accel.UseHWCursor = !cPtr->Accel.UseHWCursor;
    }
    xf86DrvMsg(pScrn->scrnIndex, from, "Using %s cursor\n",
	       (cPtr->Accel.UseHWCursor) ? "HW" : "SW");

    /* Default to nonlinear for < 8bpp and linear for >= 8bpp. */
    if (pScrn->bitsPerPixel < 8) {
	if (!xf86ReturnOptValBool(cPtr->Options, OPTION_LINEAR, FALSE)) {
	cPtr->Flags &= ~ChipsLinearSupport;
	from = X_CONFIG;
	}
    } else if (!xf86ReturnOptValBool(cPtr->Options, OPTION_LINEAR, TRUE)) {
	cPtr->Flags &= ~ChipsLinearSupport;
	from = X_CONFIG;
    }

    /* linear base */
    if (cPtr->Flags & ChipsLinearSupport) {
	if (cPtr->pEnt->location.type == BUS_PCI) {
	    /* Tack on 0x800000 to access the big-endian aperture? */
#if X_BYTE_ORDER == X_BIG_ENDIAN
	    cPtr->FbAddress =  (cPtr->PciInfo->memBase[0] & 0xff800000) + 0x800000L;
#else
	    cPtr->FbAddress =  cPtr->PciInfo->memBase[0] & 0xff800000;
#endif
	    from = X_PROBED;
	    if (xf86RegisterResources(cPtr->pEnt->index,NULL,ResNone))
		cPtr->Flags &= ~ChipsLinearSupport;
	} else 	{
	    if (cPtr->pEnt->device->MemBase) {
		cPtr->FbAddress = cPtr->pEnt->device->MemBase;
		from = X_CONFIG;
	    } else {
		cPtr->FbAddress = ((unsigned int)
				   (cPtr->readXR(cPtr, 0x06))) << 24;
		cPtr->FbAddress |= ((unsigned int)
				    (0x80 & (cPtr->readXR(cPtr, 0x05)))) << 16;
		from = X_PROBED;
	    }
	    linearRes[0].rBegin = cPtr->FbAddress;
	    linearRes[0].rEnd = cPtr->FbAddress + 0x800000;
	    if (xf86RegisterResources(cPtr->pEnt->index,linearRes,ResNone)) {
		cPtr->Flags &= ~ChipsLinearSupport;
		from = X_PROBED;
	    }
	}
    }
    if (cPtr->Flags & ChipsLinearSupport) {
	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
		   "Enabling linear addressing\n");
	xf86DrvMsg(pScrn->scrnIndex, from,
		   "base address is set at 0x%lX.\n", cPtr->FbAddress);
	cPtr->IOAddress = cPtr->FbAddress + 0x400000L;
    } else
	xf86DrvMsg(pScrn->scrnIndex, from,
		   "Disabling linear addressing\n");

    if ((s = xf86GetOptValString(cPtr->Options, OPTION_ROTATE))
	|| xf86ReturnOptValBool(cPtr->Options, OPTION_SHADOW_FB, FALSE)) {
	if (!(cPtr->Flags & ChipsLinearSupport)) {
	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
		    "Option \"ShadowFB\" ignored. Not supported without linear addressing\n");
	} else if (pScrn->depth < 8) {
	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
		    "Option \"ShadowFB\" ignored. Not supported at this depth.\n");
	} else {
	    cPtr->Rotate = 0;
	    if (s) {
		if(!xf86NameCmp(s, "CW")) {
		    /* accel is disabled below for shadowFB */
		    cPtr->Flags |= ChipsShadowFB;
		    cPtr->Rotate = 1;
		    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, 
			       "Rotating screen clockwise\n");
		} else if(!xf86NameCmp(s, "CCW")) {
		    cPtr->Flags |= ChipsShadowFB;
		    cPtr->Rotate = -1;
		    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,  "Rotating screen"
			       "counter clockwise\n");
		} else {
		    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "\"%s\" is not a valid"
			       "value for Option \"Rotate\"\n", s);
		    xf86DrvMsg(pScrn->scrnIndex, X_INFO, 
			       "Valid options are \"CW\" or \"CCW\"\n");
		}
	    } else {
		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, 
			   "Using \"Shadow Framebuffer\"\n");
		cPtr->Flags |= ChipsShadowFB;
	    }
	}
    }
    
    if ((s = xf86GetOptValString(cPtr->Options, OPTION_OVERLAY))) {
	if (!*s || !xf86NameCmp(s, "8,16") || !xf86NameCmp(s, "16,8")) {
	  if (pScrn->bitsPerPixel == 16) {
	    if (cPtr->Flags & ChipsLinearSupport) {
		cPtr->Flags |= ChipsOverlay8plus16;
		if(!xf86GetOptValInteger(
			cPtr->Options, OPTION_COLOR_KEY, &(pScrn->colorKey)))
		    pScrn->colorKey = TRANSPARENCY_KEY;
		pScrn->overlayFlags = OVERLAY_8_16_DUALFB;
		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, 
			   "PseudoColor overlay enabled.\n");
		if (!xf86IsOptionSet(cPtr->Options, OPTION_LCD_CENTER))
		    xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 
			   "                             - Forcing option \"LcdCenter\".\n");
		if (cPtr->Flags & ChipsShadowFB) {
		    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
		           "                             - Disabling \"Shadow Framebuffer\".\n");
		    xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 
			   "                               Not support with option \"8Plus16\".\n");
		    cPtr->Flags &= ~ChipsShadowFB;
		    cPtr->Rotate = 0;
		}
	    } else {
		xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Option \"Overlay\" ignored. Not supported without linear addressing\n");
	    }
	  } else {
	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 
		"Option \"Overlay\" is not supported in this configuration\n");
	  }
	} else {
	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 
		"\"%s\" is not a valid value for Option \"Overlay\"\n", s); 
	}
    }

    if (!(cPtr->Flags & ChipsOverlay8plus16)) {
	if(xf86GetOptValInteger(cPtr->Options, OPTION_VIDEO_KEY,
		&(cPtr->videoKey))) {
	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "video key set to 0x%x\n",
		cPtr->videoKey);
	} else {
	    cPtr->videoKey =  (1 << pScrn->offset.red) | 
			(1 << pScrn->offset.green) |
			(((pScrn->mask.blue >> pScrn->offset.blue) - 1)
			<< pScrn->offset.blue); 
	}
    }

    if (cPtr->Flags & ChipsShadowFB) {
	if (cPtr->Flags & ChipsAccelSupport) {
	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 
		"HW acceleration is not supported with shadow fb\n");
	    cPtr->Flags &= ~ChipsAccelSupport;
	}
	if (cPtr->Rotate && cPtr->Accel.UseHWCursor) {
	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 
		"HW cursor is not supported with rotate\n");
	    cPtr->Accel.UseHWCursor = FALSE;
	}
    }

    if (xf86ReturnOptValBool(cPtr->Options, OPTION_MMIO, TRUE)) {
        cPtr->UseMMIO = TRUE;
	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
		   "Using MMIO\n");
    
	/* Are we using MMIO mapping of VGA registers */
	if (xf86ReturnOptValBool(cPtr->Options, OPTION_FULL_MMIO, FALSE)) {
	    if ((cPtr->Flags & ChipsLinearSupport) 
		&& (cPtr->Flags & ChipsFullMMIOSupport) 
		&& (cPtr->pEnt->location.type == BUS_PCI)) {

		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
			   "Enabling Full MMIO\n");
		cPtr->UseFullMMIO = TRUE;
		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
			   "Using Full MMIO\n");

		/* 
		 * We need to map the framebuffer to read/write regs.
		 * but can't do that without the FbMapSize. So need to
		 * fake value for PreInit. This isn't a problem as
		 * framebuffer isn't actually used in PreInit
		 */
		cPtr->FbMapSize = 1024 * 1024;

		/* Map the linear framebuffer */
		if (!chipsMapMem(pScrn))
		  return FALSE;
	  
		/* Setup the MMIO register functions */
		if (cPtr->MMIOBaseVGA) {
		  CHIPSSetMmioExtFuncs(cPtr);
		  CHIPSHWSetMmioFuncs(pScrn, cPtr->MMIOBaseVGA, 0x0);
		}
	    } else {
		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, 
			   "FULL_MMIO option ignored\n");
	    }
	}
    } else {
	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,"Disabling MMIO: "
		   "no acceleration, no hw_cursor\n");
	cPtr->UseMMIO = FALSE;
	cPtr->Accel.UseHWCursor = FALSE;
	cPtr->Flags &= ~ChipsAccelSupport;
    }


    if (cPtr->Flags & ChipsDualChannelSupport) {

	if (xf86IsEntityShared(pScrn->entityList[0])) {
	    cPtrEnt = xf86GetEntityPrivate(pScrn->entityList[0],
					CHIPSEntityIndex)->ptr;
#if 1
	    /*
	     * XXX This assumes that the lower number screen is always the 
	     * "master" head, and that the "master" is the first CRTC.  This
	     * can result in unexpected behaviour when the config file marks
	     * the primary CRTC as the second screen.
	     */
	    if (xf86IsPrimInitDone(pScrn->entityList[0])) 
#else
	    /*
	     * This is an alternative version that determines which is the 
	     * secondary CRTC from the screen field in cPtr->pEnt->device.
	     * It doesn't currently work because there are things that assume
	     * the primary CRTC is initialised first.
	     */
	    if (cPtr->pEnt->device->screen == 1) 
		
#endif
	    {
		/* This is the second crtc */
		cPtr->SecondCrtc = TRUE;
		cPtr->UseDualChannel = TRUE;
	    } else
		cPtr->SecondCrtc = FALSE;

	} else {
	    if (xf86ReturnOptValBool(cPtr->Options, 
				   OPTION_DUAL_REFRESH, FALSE)) {
		cPtr->Flags |= ChipsDualRefresh;
		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, 
			   "Dual Refresh mode enabled\n");
		cPtr->UseDualChannel = TRUE;
	    }
	}

	/* Store IOSS/MSS so that we can restore them */
	cPtr->storeIOSS = cPtr->readIOSS(cPtr);
	cPtr->storeMSS = cPtr->readMSS(cPtr);
        DUALOPEN;
    }

	    /* memory size */
    if (cPtr->pEnt->device->videoRam != 0) {
	pScrn->videoRam = cPtr->pEnt->device->videoRam;
	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "VideoRAM: %d kByte\n",
		   pScrn->videoRam);
    } else {
        /* not given, probe it    */
	switch (cPtr->Chipset) {
	case CHIPS_CT69030:
	    /* The ct69030 has 4Mb of SGRAM integrated */
	    pScrn->videoRam = 4096;
	    cPtr->Flags |= Chips64BitMemory;
	    break;
	case CHIPS_CT69000:
	    /* The ct69000 has 2Mb of SGRAM integrated */
	    pScrn->videoRam = 2048;
	    cPtr->Flags |= Chips64BitMemory;
	    break;
	case CHIPS_CT65550:
	    /* XR43: DRAM interface   */
	    /* bit 2-1: memory size   */
	    /*          0: 1024 kB    */
	    /*          1: 2048 kB    */
	    /*          2:  reserved  */
	    /*          3: reserved   */
	    switch (((cPtr->readXR(cPtr, 0x43)) & 0x06) >> 1) {
	    case 0:
		pScrn->videoRam = 1024;
		break;
	    case 1:
	    case 2:
	    case 3:
		pScrn->videoRam = 2048;
		break;
	    }
	    break;
	default:
	    /* XRE0: Software reg     */
	    /* bit 3-0: memory size   */
	    /*          0: 512k       */
	    /*          1: 1024k      */
	    /*          2: 1536k(1.5M)*/
	    /*          3: 2048k      */
	    /*          7: 4096k      */
	    tmp = (cPtr->readXR(cPtr, 0xE0)) & 0xF;
	    switch (tmp) {
	    case 0:
		pScrn->videoRam = 512;
		break;
	    case 1:
		pScrn->videoRam = 1024;
		break;
	    case 2:
		pScrn->videoRam = 1536;
		break;
	    case 3:
		pScrn->videoRam = 2048;
		break;
	    case 7:
		pScrn->videoRam = 4096;
		break;
	    default:
		pScrn->videoRam = 1024;
		break;
	    }
	    /* XR43: DRAM interface        */
	    /* bit 4-5 mem interface width */
	    /* 00: 32Bit		   */
	    /* 01: 64Bit		   */
	    tmp = cPtr->readXR(cPtr, 0x43);
	    if ((tmp & 0x10) == 0x10)
		cPtr->Flags |= Chips64BitMemory;
	    break;
	}
    }

    if ((cPtr->Flags & ChipsDualChannelSupport) &&
		(xf86IsEntityShared(pScrn->entityList[0]))) {
       /* 
	* This takes gives either half or the amount of memory specified
        * with the Crt2Memory option 
        */
        if(cPtr->SecondCrtc == FALSE) {
	    int crt2mem = -1, adjust;
	  
	    xf86GetOptValInteger(cPtr->Options, OPTION_CRT2_MEM, &crt2mem);
	    if (crt2mem > 0) {
		adjust = crt2mem;
		from = X_CONFIG;
	    } else {
		adjust = pScrn->videoRam / 2;
		from = X_DEFAULT;
	    }
	    xf86DrvMsg(pScrn->scrnIndex, from,
			   "CRT2 will use %dK of VideoRam\n",
			   adjust);

	    cPtrEnt->mastervideoRam = pScrn->videoRam - adjust;
	    pScrn->videoRam = cPtrEnt->mastervideoRam;
	    cPtrEnt->slavevideoRam = adjust;
	    cPtrEnt->masterFbAddress = cPtr->FbAddress;
	    cPtr->FbMapSize = 
	       cPtrEnt->masterFbMapSize = pScrn->videoRam * 1024;
	    cPtrEnt->slaveFbMapSize = cPtrEnt->slavevideoRam * 1024;
	} else {
	    cPtrEnt->slaveFbAddress = cPtr->FbAddress + 
				cPtrEnt->masterFbAddress;
	    cPtr->FbMapSize = cPtrEnt->slaveFbMapSize;
	    pScrn->videoRam = cPtrEnt->slavevideoRam;
	}
        cPtrEnt->refCount++;
    } else {
        /* Normal Handling of video ram etc */
        cPtr->FbMapSize = pScrn->videoRam * 1024;
    }

    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "VideoRAM: %d kByte\n",
		   pScrn->videoRam);

    /* Store register values that might be messed up by a suspend resume */
    /* Do this early as some of the other code in PreInit relies on it   */
    cPtr->SuspendHack.vgaIOBaseFlag = ((hwp->readMiscOut(hwp)) & 0x01);
    cPtr->IOBase = (unsigned int)(cPtr->SuspendHack.vgaIOBaseFlag ?
				  0x3D0 : 0x3B0);

    /* 
     * Do DDC here: if VESA BIOS detects an external monitor it
     * might switch. SetPanelType() will detect this.
     */
    if ((pDDCModule = xf86LoadSubModule(pScrn, "ddc"))) {
	Bool ddc_done = FALSE;
	xf86MonPtr pMon;
	
	xf86LoaderModReqSymLists(pDDCModule, ddcSymbols, NULL);

	if (cPtr->pVbe) {
	    if ((pMon 
		 = xf86PrintEDID(vbeDoEDID(cPtr->pVbe, pDDCModule))) != NULL) {
		ddc_done = TRUE;
		xf86SetDDCproperties(pScrn,pMon);
	    }
	}

	if (!ddc_done)
	    if ((pMod = xf86LoadSubModule(pScrn, "i2c"))) {
		xf86LoaderModReqSymLists(pMod, i2cSymbols,NULL);
	    
		if (chips_i2cInit(pScrn)) {
		    if ((pMon = xf86PrintEDID(xf86DoEDID_DDC2(pScrn->scrnIndex,
						      cPtr->I2C))) != NULL)
		       ddc_done = TRUE;
		       xf86SetDDCproperties(pScrn,pMon);
		}
	    }
	if (!ddc_done)
	    chips_ddc1(pScrn);
    }

    /*test STN / TFT */
    tmp = cPtr->readFR(cPtr, 0x10);

    /* XR51 or FR10: DISPLAY TYPE REGISTER                      */
    /* XR51[1-0] or FR10[1:0] for ct65550 : PanelType,          */
    /* 0 = Single Panel Single Drive, 3 = Dual Panel Dual Drive */
    switch (tmp & 0x3) {
    case 0:
	if (xf86ReturnOptValBool(cPtr->Options, OPTION_STN, FALSE)) {
	    cPtr->PanelType |= ChipsSS;
	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "SS-STN probed\n");
	} else {
	    cPtr->PanelType |= ChipsTFT;
	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "TFT probed\n");
	}
	break;
    case 2:
	cPtr->PanelType |= ChipsDS;
	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "DS-STN probed\n");
    case 3:
	cPtr->PanelType |= ChipsDD;
	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "DD-STN probed\n");
	break;
    default:
	break;
    }
    
    chipsSetPanelType(cPtr);
    from = X_PROBED;
    {
      Bool fp_mode;
      if (xf86GetOptValBool(cPtr->Options, OPTION_FP_MODE, &fp_mode)) {
	if (fp_mode) {
	  xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Forcing FP Mode on\n");
	  cPtr->PanelType |= ChipsLCD;
	} else {
	  xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Forcing FP Mode off\n");
	  cPtr->PanelType = ~ChipsLCD;
	} 
	from = X_CONFIG;
      }
    }
    if ((cPtr->PanelType & ChipsLCD) && (cPtr->PanelType & ChipsCRT))
	xf86DrvMsg(pScrn->scrnIndex, from, "LCD/CRT\n");
    else if (cPtr->PanelType & ChipsLCD)
        xf86DrvMsg(pScrn->scrnIndex, from, "LCD\n");
    else if (cPtr->PanelType & ChipsCRT) {
        xf86DrvMsg(pScrn->scrnIndex, from, "CRT\n");
	/* monitor info */
#if 1
	cPtr->Monitor = chipsSetMonitor(pScrn);
#endif
    }
    /* screen size */
    /* 
     * In LCD mode / dual mode we want to derive the timing values from
     * the ones preset by bios
     */
    if (cPtr->PanelType & ChipsLCD) {

	/* for 65550 we only need H/VDisplay values for screen size */
	unsigned char fr25, tmp1;
#ifdef DEBUG
	unsigned char fr26;
	char tmp2;
#endif
 	fr25 = cPtr->readFR(cPtr, 0x25);
 	tmp = cPtr->readFR(cPtr, 0x20);
	Size->HDisplay = ((tmp + ((fr25 & 0x0F) << 8)) + 1) << 3;
 	tmp = cPtr->readFR(cPtr, 0x30);
 	tmp1 = cPtr->readFR(cPtr, 0x35);
	Size->VDisplay = ((tmp1 & 0x0F) << 8) + tmp + 1;
#ifdef DEBUG
 	tmp = cPtr->readFR(cPtr, 0x21);
	Size->HRetraceStart = ((tmp + ((fr25 & 0xF0) << 4)) + 1) << 3;
 	tmp1 = cPtr->readFR(cPtr, 0x22);
	tmp2 = (tmp1 & 0x1F) - (tmp & 0x3F);
	Size->HRetraceEnd = ((((tmp2 < 0) ? (tmp2 + 0x40) : tmp2) << 3)
			     + Size->HRetraceStart);
 	tmp = cPtr->readFR(cPtr, 0x23);
 	fr26 = cPtr->readFR(cPtr, 0x26);
	Size->HTotal = ((tmp + ((fr26 & 0x0F) << 8)) + 5) << 3;
	xf86ErrorF("x=%i, y=%i; xSync=%i, xSyncEnd=%i, xTotal=%i\n",
	       Size->HDisplay, Size->VDisplay,
	       Size->HRetraceStart,Size->HRetraceEnd,
	       Size->HTotal);
#endif
	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Display Size: x=%i; y=%i\n",
		   Size->HDisplay, Size->VDisplay);
	/* Warn the user if the panel size has been overridden by
	 * the modeline values
	 */
	if (xf86ReturnOptValBool(cPtr->Options, OPTION_PANEL_SIZE, FALSE)) {
	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
		       "Display size overridden by modelines.\n");
	}
    }

    /* Frame Buffer */                 /* for LCDs          */ 
    if (IS_STN(cPtr->PanelType)) {
	tmp = cPtr->readFR(cPtr, 0x1A); /*Frame Buffer Ctrl. */
	if (tmp & 1) {
	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Frame Buffer used\n");
	    if (!(tmp & 0x80)) {
		/* Formula for calculating the size of the framebuffer. 3
		 * bits per pixel 10 pixels per 32 bit dword. If frame
		 * acceleration is enabled the size can be halved.
		 */
		cPtr->FrameBufferSize = ( Size->HDisplay * 
				  Size->VDisplay / 5 ) * ((tmp & 2) ? 1 : 2);
		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
			   "Using embedded Frame Buffer, size %d bytes\n",
			   cPtr->FrameBufferSize);
	    } else
		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
			   "Using external Frame Buffer used\n");
	}
	if (tmp & 2)
	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
		       "Frame accelerator enabled\n");
    }

    /* bus type */
    tmp = (cPtr->readXR(cPtr, 0x08)) & 1;
    if (tmp == 1) {	       /*PCI */
	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "PCI Bus\n");
	cPtr->Bus = ChipsPCI;
    } else {   /* XR08: Linear addressing base, not for PCI */
	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "VL Bus\n");
	cPtr->Bus = ChipsVLB;
    }

    /* disable acceleration for 1 and 4 bpp */
    if (pScrn->bitsPerPixel < 8) {
	xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
		   "Disabling acceleration for %d bpp\n", pScrn->bitsPerPixel);
	cPtr->Flags &= ~ChipsAccelSupport;
    }
    
    /* Set the flags for Colour transparency. This is dependent
     * on the revision on the chip. Until exactly which chips
     * have this bug are found, only allow 8bpp Colour transparency */
    if ((pScrn->bitsPerPixel == 8) || ((cPtr->Chipset >= CHIPS_CT65555) &&
	    (pScrn->bitsPerPixel >= 8) && (pScrn->bitsPerPixel <= 24)))
        cPtr->Flags |= ChipsColorTransparency;
    else
        cPtr->Flags &= ~ChipsColorTransparency;

    /* DAC info */
    if (!((cPtr->readXR(cPtr, 0xD0)) & 0x01))
	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Internal DAC disabled\n");

    /* MMIO address offset */
    cPtr->Regs32 = ChipsReg32HiQV;
  
    /* sync reset ignored on this chipset */
    cPtr->SyncResetIgn = TRUE;   /* !! */

    /* We use a programmable clock */
    pScrn->numClocks = 26;		/* Some number */
    pScrn->progClock = TRUE;
    cPtr->ClockType = HiQV_STYLE | TYPE_PROGRAMMABLE;

    if (cPtr->pEnt->device->textClockFreq > 0) {
	SaveClk->Clock = cPtr->pEnt->device->textClockFreq;
	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
		   "Using textclock freq: %7.3f.\n",
		   SaveClk->Clock/1000.0);
    } else
	SaveClk->Clock = 0;

    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Using programmable clocks\n");

    /* Set the maximum memory clock. */
    switch (cPtr->Chipset) {
    case CHIPS_CT65550:
	if (((cPtr->readXR(cPtr, 0x04)) & 0xF) < 6)
	    MemClk->Max = 38000; /* Revision A chips */
	else
	    MemClk->Max = 50000; /* Revision B chips */
	break;
    case CHIPS_CT65554:
    case CHIPS_CT65555:
    case CHIPS_CT68554:
	MemClk->Max = 55000;
	break;
    case CHIPS_CT69000:
	MemClk->Max = 83000;
	break;
    case CHIPS_CT69030:
	MemClk->Max = 100000;
	break;
    }

    /* Probe the dot clocks */
    for (i = 0; i < 3; i++) {
      unsigned int N,M,PSN,P,VCO_D;
      int offset = i * 4;
      
      tmp = cPtr->readXR(cPtr,0xC2 + offset);
      M = (cPtr->readXR(cPtr, 0xC0 + offset) 
	   | (tmp & 0x03)) + 2;
      N = (cPtr->readXR(cPtr, 0xC1 + offset) 
	| (( tmp >> 4) & 0x03)) + 2;
      tmp = cPtr->readXR(cPtr, 0xC3 + offset);
      PSN = (cPtr->Chipset == CHIPS_CT69000 || cPtr->Chipset == CHIPS_CT69030)
		? 1 : (((tmp & 0x1) ? 1 : 4) * ((tmp & 0x02) ? 5 : 1));
      VCO_D = ((tmp & 0x04) ? ((cPtr->Chipset == CHIPS_CT69000 || 
				cPtr->Chipset == CHIPS_CT69030) ? 1 : 16) : 4);
      P = ((tmp & 0x70) >> 4);
      Probed[i] = VCO_D * Fref / N;
      Probed[i] = Probed[i] * M / (PSN * (1 << P));
      Probed[i] = Probed[i] / 1000;
    }
    CRTclkI = (hwp->readMiscOut(hwp) >> 2) & 0x03; 
    if (CRTclkI == 3) CRTclkI = 2;
    if (cPtr->Chipset == CHIPS_CT69030) 
	FPclkI = (cPtr->readFR(cPtr, 0x01) >> 2) & 0x3; 
    else
	FPclkI = (cPtr->readFR(cPtr, 0x03) >> 2) & 0x3; 
    if (FPclkI == 3) FPclkI = 2;
    for (i = 0; i < 3; i++) {
      xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
		 "Dot clock %i: %7.3f MHz",i,
		 (float)(Probed[i])/1000.);
      if (FPclkI == i) xf86ErrorF(" FPclk");
      if (CRTclkI == i) xf86ErrorF(" CRTclk");
      xf86ErrorF("\n");
    }
    cPtr->FPclock = Probed[FPclkI];
    cPtr->FPclkInx = FPclkI;
    if (CRTclkI == FPclkI) {
      if (FPclkI == 2)
	CRTclkI = 1;
      else
	CRTclkI = 2;
    }
    cPtr->CRTclkInx = CRTclkI;


    /* 
     * Some chips seem to dislike some clocks in one of the PLL's. Give
     * the user the oppurtunity to change it
     */
    if (xf86GetOptValInteger(cPtr->Options, OPTION_CRT_CLK_INDX, &indx)) {
	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Force CRT Clock index to %d\n",
		 indx);
	cPtr->CRTclkInx = indx;

	if (xf86GetOptValInteger(cPtr->Options, OPTION_FP_CLK_INDX, &indx)) {
	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, 
		       "Force FP Clock index to %d\n", indx);
	    cPtr->FPclkInx = indx;
	} else {
	    if (indx == cPtr->FPclkInx) {
		if (indx == 2)
		    cPtr->FPclkInx = 1;
		else
		    cPtr->FPclkInx = indx + 1;
		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
			   "FP Clock index forced to %d\n", cPtr->FPclkInx);
	    }
	}
    } else if (xf86GetOptValInteger(cPtr->Options, OPTION_FP_CLK_INDX, 
				    &indx)) {
	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, 
		   "Force FP Clock index to %d\n", indx);
	cPtr->FPclkInx = indx;
	if (indx == cPtr->CRTclkInx) {
	    if (indx == 2)
		cPtr->CRTclkInx = 1;
	    else
		cPtr->CRTclkInx = indx + 1;
	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
		       "CRT Clock index forced to %d\n", cPtr->CRTclkInx);
	}
    }
    

    /* Probe the memory clock currently in use */
    MemClk->xrCC = cPtr->readXR(cPtr, 0xCC);
    MemClk->M = (MemClk->xrCC  & 0x7F) + 2;
    MemClk->xrCD = cPtr->readXR(cPtr, 0xCD);
    MemClk->N = (MemClk->xrCD & 0x7F) + 2;
    MemClk->xrCE = cPtr->readXR(cPtr, 0xCE);
    MemClk->PSN = (MemClk->xrCE & 0x1) ? 1 : 4;
    MemClk->P = ((MemClk->xrCE & 0x70) >> 4);
    /* Be careful with the calculation of ProbeClk as it can overflow */ 
    MemClk->ProbedClk = 4 * Fref / MemClk->N;
    MemClk->ProbedClk = MemClk->ProbedClk * MemClk->M / (MemClk->PSN * 
							 (1 << MemClk->P));
    MemClk->ProbedClk = MemClk->ProbedClk / 1000;
    MemClk->Clk = MemClk->ProbedClk;

    if (xf86GetOptValFreq(cPtr->Options, OPTION_SET_MCLK, OPTUNITS_MHZ, &real)) {
	int mclk = (int)(real * 1000.0);
	if (mclk <= MemClk->Max) {
	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
		       "Using memory clock of %7.3f MHz\n",
		       (float)(mclk/1000.));

	    /* Only alter the memory clock if the desired memory clock differs
	     * by 50kHz from the one currently being used.
	     */
	    if (abs(mclk - MemClk->ProbedClk) > 50) {
		unsigned char vclk[3];

		MemClk->Clk = mclk;
		chipsCalcClock(pScrn, MemClk->Clk, vclk);
		MemClk->M = vclk[1] + 2;
		MemClk->N = vclk[2] + 2;
		MemClk->P = (vclk[0] & 0x70) >> 4;
		MemClk->PSN = (vclk[0] & 0x1) ? 1 : 4;
		MemClk->xrCC = vclk[1];
		MemClk->xrCD = vclk[2];
		MemClk->xrCE = 0x80 || vclk[0];
	    }
	} else
	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
		       "Memory clock of %7.3f MHz exceeds limit of %7.3f MHz\n",
		       (float)(mclk/1000.), 
		       (float)(MemClk->Max/1000.));
    } else 
        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
		   "Probed memory clock of %7.3f MHz\n",
		   (float)(MemClk->ProbedClk/1000.));
    
    cPtr->ClockMulFactor = 1;

    /* Set the min pixel clock */
    cPtr->MinClock = 11000;	/* XXX Guess, need to check this */
    xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "Min pixel clock is %7.3f MHz\n",
	       (float)(cPtr->MinClock / 1000.));
    /* Set the max pixel clock */
    switch (cPtr->Chipset) {
    case CHIPS_CT69030:
	cPtr->MaxClock = 170000;
	break;
    case CHIPS_CT69000:
	cPtr->MaxClock = 135000;
	break;
    case CHIPS_CT68554:
    case CHIPS_CT65555:
	cPtr->MaxClock = 110000;
	break;
    case CHIPS_CT65554:
	cPtr->MaxClock = 95000;
	break;
    case CHIPS_CT65550:
	if (((cPtr->readXR(cPtr, 0x04)) & 0xF) < 6) {
   if ((cPtr->readFR(cPtr, 0x0A)) & 2) {
		/*5V Vcc */
		cPtr->MaxClock = 100000;
	    } else {
		/*3.3V Vcc */
		cPtr->MaxClock = 80000;
	    }
	} else
	    cPtr->MaxClock = 95000; /* Revision B */
	break;
    }
    
    /* Check if maxClock is limited by the MemClk. Only 70% to allow for */
    /* RAS/CAS. Extra byte per memory clock needed if framebuffer used   */
    /* Extra byte if the overlay plane is activated                      */
    /* If flag Chips64BitMemory is set assume a 64bitmemory interface,   */
    /* and 32bits on the others. Thus multiply by a suitable factor      */  
    if (cPtr->Flags & Chips64BitMemory) {
	if (cPtr->FrameBufferSize && (cPtr->PanelType & ChipsLCD))
	    if (cPtr->Flags & ChipsOverlay8plus16 )
		cPtr->MaxClock = min(cPtr->MaxClock, MemClk->Clk * 8 * 0.7 / 4);
	    else
		cPtr->MaxClock = min(cPtr->MaxClock,
			     MemClk->Clk * 8 * 0.7 / (bytesPerPixel + 1));
	else
	    if (cPtr->Flags & ChipsOverlay8plus16)
		cPtr->MaxClock = min(cPtr->MaxClock, MemClk->Clk * 8 * 0.7 / 3);
	    else
		cPtr->MaxClock = min(cPtr->MaxClock, 
			     MemClk->Clk * 8 * 0.7 / bytesPerPixel);
    } else {
	if (cPtr->FrameBufferSize && (cPtr->PanelType & ChipsLCD))
	    if (cPtr->Flags & ChipsOverlay8plus16 )
		cPtr->MaxClock = min(cPtr->MaxClock, MemClk->Clk * 4 * 0.7 / 4);
	    else
		cPtr->MaxClock = min(cPtr->MaxClock,
			     MemClk->Clk * 4 * 0.7 / (bytesPerPixel + 1));
	else
	    if (cPtr->Flags & ChipsOverlay8plus16)
		cPtr->MaxClock = min(cPtr->MaxClock, MemClk->Clk * 4 * 0.7 / 3);
	    else
		cPtr->MaxClock = min(cPtr->MaxClock, 
			     MemClk->Clk * 4 * 0.7 / bytesPerPixel);
    }
    

    
    if (cPtr->pEnt->device->dacSpeeds[0]) {
	int speed = 0;
	switch (pScrn->bitsPerPixel) {
	case 1:
	case 4:
	case 8:
	    speed = cPtr->pEnt->device->dacSpeeds[DAC_BPP8];
	    break;
	case 16:
	    speed = cPtr->pEnt->device->dacSpeeds[DAC_BPP16];
	    break;
	case 24:
	    speed = cPtr->pEnt->device->dacSpeeds[DAC_BPP24];
	    break;
	case 32:
	    speed = cPtr->pEnt->device->dacSpeeds[DAC_BPP32];
	    break;
	}

	if (speed == 0)
	    speed = cPtr->pEnt->device->dacSpeeds[0];
	from = X_CONFIG;
	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
		   "User max pixel clock of %7.3f MHz overrides %7.3f MHz limit\n",
		   (float)(speed / 1000.), (float)(cPtr->MaxClock / 1000.));
	cPtr->MaxClock = speed;
    } else {
	xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
		   "Max pixel clock is %7.3f MHz\n",
		   (float)(cPtr->MaxClock / 1000.));
    }
    /* 
     * Prepare the FPclock: 
     *    if FPclock <= MaxClock : don't modify the FP clock.
     *    else set FPclock to 90% of MaxClock.
     */
    real = 0.;
    switch(bytesPerPixel) {
    case 1:
        if (xf86GetOptValFreq(cPtr->Options, OPTION_FP_CLOCK_8, OPTUNITS_MHZ, &real))
	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
		       "FP clock %7.3f MHz requested\n",real);
	break;
    case 2:
        if (xf86GetOptValFreq(cPtr->Options, OPTION_FP_CLOCK_16, OPTUNITS_MHZ, &real))
	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
		       "FP clock %7.3f MHz requested\n",real);
	break;
    case 3:
        if (xf86GetOptValFreq(cPtr->Options, OPTION_FP_CLOCK_24, OPTUNITS_MHZ, &real))
	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
		       "FP clock %7.3f MHz requested\n",real);
	break;
    case 4:
        if (xf86GetOptValFreq(cPtr->Options, OPTION_FP_CLOCK_32, OPTUNITS_MHZ, &real))
	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
		       "FP clock %7.3f MHz requested\n",real);
	break;
    }
    val = (int) (real * 1000.);
    if (val && val >= cPtr->MinClock && val <= cPtr->MaxClock)
      cPtr->FPclock = val;
    else if (cPtr->FPclock > cPtr->MaxClock)
        cPtr->FPclock = (int)((float)cPtr->MaxClock * 0.9);
    else
        cPtr->FPclock = 0; /* special value */
    cPtr->FPClkModified = FALSE;
    if (cPtr->FPclock)
        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
		   "FP clock set to %7.3f MHz\n",
		   (float)(cPtr->FPclock / 1000.));

#if defined(__arm32__) && defined(__NetBSD__)
    ChipsPALMode.next = pScrn->monitor->Modes;
    pScrn->monitor->Modes = &ChipsNTSCMode;
#endif

    
    if (cPtr->Flags & ChipsDualChannelSupport) {
	if (xf86IsEntityShared(pScrn->entityList[0])) {
	    if (cPtr->SecondCrtc == TRUE) {
		cPtrEnt->slaveActive = FALSE;
	    } else {
		cPtrEnt->masterActive = FALSE;
	    }
	}
	/* Put IOSS/MSS back to normal */
	cPtr->writeIOSS(cPtr, cPtr->storeIOSS);
	cPtr->writeMSS(cPtr, hwp, cPtr->storeMSS);

	xf86SetPrimInitDone(pScrn->entityList[0]);
    }

    return TRUE;
}

static Bool
chipsPreInitWingine(ScrnInfoPtr pScrn, int flags)
{
    int i, bytesPerPixel, NoClocks = 0;
    unsigned char tmp;
    MessageType from;
    vgaHWPtr hwp;
    CHIPSPtr cPtr = CHIPSPTR(pScrn);
    CHIPSClockPtr SaveClk = &(cPtr->SavedReg.Clock);
    Bool useLinear = FALSE;
    char *s;
    resRange linearRes[] = { {ResExcMemBlock|ResBios|ResBus,0,0},_END };
    ModuleDescPtr pMod;

    /* Set pScrn->monitor */
    pScrn->monitor = pScrn->confScreen->monitor;

    if (cPtr->Flags & ChipsHDepthSupport)
	i = xf86SetDepthBpp(pScrn, 0, 0, 0, Support24bppFb |
				SupportConvert32to24 | PreferConvert32to24);
    else
	i = xf86SetDepthBpp(pScrn, 8, 0, 0, NoDepth24Support);

    if (!i)
	return FALSE;
    else {
	/* Check that the returned depth is one we support */
	switch (pScrn->depth) {
	case 1:
	case 4:
	case 8:
	    /* OK */
	    break;
	case 15:
	case 16:
	case 24:
	    if (cPtr->Flags & ChipsHDepthSupport) 
		break; /* OK */
	    /* fall through */
	default:
	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
		       "Given depth (%d) is not supported by this driver\n",
		       pScrn->depth);
	    return FALSE;
	}
    }

    xf86PrintDepthBpp(pScrn);

    /* Get the depth24 pixmap format */
    if (pScrn->depth == 24 && pix24bpp == 0)
	pix24bpp = xf86GetBppFromDepth(pScrn, 24);

    /*
     * Allocate a vgaHWRec, this must happen after xf86SetDepthBpp for 1bpp
     */
    if (!vgaHWGetHWRec(pScrn))
        return FALSE;

    hwp = VGAHWPTR(pScrn);
    vgaHWGetIOBase(hwp);

    /*
     * This must happen after pScrn->display has been set because
     * xf86SetWeight references it.
     */
    if (pScrn->depth > 8) {
	/* The defaults are OK for us */
	rgb zeros = {0, 0, 0};

	if (!xf86SetWeight(pScrn, zeros, zeros)) {
	    return FALSE;
	} else {
	    /* XXX check that weight returned is supported */
            ;
        }
    }

    if (!xf86SetDefaultVisual(pScrn, -1)) 
	return FALSE;

    /* The gamma fields must be initialised when using the new cmap code */
    if (pScrn->depth > 1) {
	Gamma zeros = {0.0, 0.0, 0.0};

	if (!xf86SetGamma(pScrn, zeros))
	    return FALSE;
    }

    /* Store register values that might be messed up by a suspend resume */
    /* Do this early as some of the other code in PreInit relies on it   */
    cPtr->SuspendHack.xr02 = (cPtr->readXR(cPtr, 0x02)) & 0x18;
    cPtr->SuspendHack.xr03 = (cPtr->readXR(cPtr, 0x03)) & 0x0A;
    cPtr->SuspendHack.xr14 = (cPtr->readXR(cPtr, 0x14)) & 0x20;
    cPtr->SuspendHack.xr15 = cPtr->readXR(cPtr, 0x15);

    cPtr->SuspendHack.vgaIOBaseFlag = ((hwp->readMiscOut(hwp)) & 0x01);
    cPtr->IOBase = (unsigned int)(cPtr->SuspendHack.vgaIOBaseFlag ?
				  0x3D0 : 0x3B0);

    bytesPerPixel = max(1, pScrn->bitsPerPixel >> 3);

    /* Collect all of the relevant option flags (fill in pScrn->options) */
    xf86CollectOptions(pScrn, NULL);

    /* Process the options */
    if (!(cPtr->Options = xalloc(sizeof(ChipsWingineOptions))))
	return FALSE;
    memcpy(cPtr->Options, ChipsWingineOptions, sizeof(ChipsWingineOptions));
    xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, cPtr->Options);

    /* Set the bits per RGB */
    if (pScrn->depth > 1) {
	/* Default to 6, is this right?? */
	pScrn->rgbBits = 6;
#if 0
	if (xf86GetOptValInteger(cPtr->Options, OPTION_RGB_BITS,
				 &pScrn->rgbBits)) {
	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Bits per RGB set to %d\n",
		       pScrn->rgbBits);
	}
#endif
    }
    if ((cPtr->Flags & ChipsAccelSupport) &&
	    (xf86ReturnOptValBool(cPtr->Options, OPTION_NOACCEL, FALSE))) {
	cPtr->Flags &= ~ChipsAccelSupport;
	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Acceleration disabled\n");
    }
    
    from = X_DEFAULT;
    if (pScrn->bitsPerPixel < 8) {
	/* Default to SW cursor for 1/4 bpp */
	cPtr->Accel.UseHWCursor = FALSE;
    } else {
	cPtr->Accel.UseHWCursor = TRUE;
    }
    if (xf86GetOptValBool(cPtr->Options, OPTION_HW_CURSOR,
			  &cPtr->Accel.UseHWCursor))
	from = X_CONFIG;
    if (xf86GetOptValBool(cPtr->Options, OPTION_SW_CURSOR,
			  &cPtr->Accel.UseHWCursor)) {
	from = X_CONFIG;
	cPtr->Accel.UseHWCursor = !cPtr->Accel.UseHWCursor;
    }
    xf86DrvMsg(pScrn->scrnIndex, from, "Using %s cursor\n",
	       (cPtr->Accel.UseHWCursor) ? "HW" : "SW");

    /* memory size */
    if (cPtr->pEnt->device->videoRam != 0) {
	pScrn->videoRam = cPtr->pEnt->device->videoRam;
	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "VideoRAM: %d kByte\n",
               pScrn->videoRam);
    } else {
	/* not given, probe it    */
	/* XR0F: Software flags 0 */
	/* bit 1-0: memory size   */
	/*          0: 256 kB     */
	/*          1: 512 kB     */
	/*          2: 1024 kB    */
	/*          3: 1024 kB    */

	switch ((cPtr->readXR(cPtr, 0x0F)) & 3) {
	case 0:
	    pScrn->videoRam = 256;
	    break;
	case 1:
	    pScrn->videoRam = 512;
	    break;
	case 2:
	    pScrn->videoRam = 1024;
	    break;
	case 3:
	    pScrn->videoRam = 2048;
	    break;
	}
	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "VideoRAM: %d kByte\n",
               pScrn->videoRam);
    }
    cPtr->FbMapSize = pScrn->videoRam * 1024;

    /* Default to nonlinear for < 8bpp and linear for >= 8bpp. */
    if (cPtr->Flags & ChipsLinearSupport) useLinear = TRUE;
    if (pScrn->bitsPerPixel < 8) {
	if (!xf86ReturnOptValBool(cPtr->Options, OPTION_LINEAR, FALSE)) {
	    useLinear = FALSE;
	    from = X_CONFIG;
	}
    } else if (!xf86ReturnOptValBool(cPtr->Options, OPTION_LINEAR, TRUE)) {
	useLinear = FALSE;
	from = X_CONFIG;
    }

    /* linear base */
    if (useLinear) {
	unsigned char mask = 0xF8;
	if (pScrn->videoRam == 1024)
	    mask = 0xF0;
	else if (pScrn->videoRam == 2048)
	    mask = 0xE0;
	if (cPtr->pEnt->device->MemBase) {
	    cPtr->FbAddress = cPtr->pEnt->device->MemBase
		& ((0xFF << 24) | (mask << 16));
	    from = X_CONFIG;	    
	} else {
	    cPtr->FbAddress = ((0xFF & (cPtr->readXR(cPtr, 0x09))) << 24);
	    cPtr->FbAddress |= ((mask  & (cPtr->readXR(cPtr, 0x08))) << 16);
	    from = X_PROBED;
	}
	linearRes[0].rBegin = cPtr->FbAddress;
	linearRes[0].rEnd = cPtr->FbAddress + 0x800000;
	if (xf86RegisterResources(cPtr->pEnt->index,linearRes,ResNone)) {
	    useLinear = FALSE;
	    from = X_PROBED;
	}
    }

    if (useLinear) {
	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
		   "Enabling linear addressing\n");
	xf86DrvMsg(pScrn->scrnIndex, from,
		   "base address is set at 0x%lX.\n", cPtr->FbAddress);
	if (xf86ReturnOptValBool(cPtr->Options, OPTION_MMIO, FALSE) &&
	    (cPtr->Flags & ChipsMMIOSupport)) {
	    cPtr->UseMMIO = TRUE;
	    cPtr->IOAddress = cPtr->FbAddress + 0x200000L;
	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Enabling MMIO\n");
	}
    } else {
	if (cPtr->Flags & ChipsLinearSupport)	
	    xf86DrvMsg(pScrn->scrnIndex, from,
		       "Disabling linear addressing\n");
	cPtr->Flags &= ~ChipsLinearSupport;
    }

    if ((s = xf86GetOptValString(cPtr->Options, OPTION_ROTATE))
	|| xf86ReturnOptValBool(cPtr->Options, OPTION_SHADOW_FB, FALSE)) {
	if (!(cPtr->Flags & ChipsLinearSupport)) {
	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
		    "Option \"ShadowFB\" ignored. Not supported without linear addressing\n");
	} else if (pScrn->depth < 8) {
	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
		    "Option \"ShadowFB\" ignored. Not supported at this depth.\n");
	} else {
	    cPtr->Rotate = 0;
	    if (s) {
		if(!xf86NameCmp(s, "CW")) {
		    /* accel is disabled below for shadowFB */
		    cPtr->Flags |= ChipsShadowFB;
		    cPtr->Rotate = 1;
		    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, 
			       "Rotating screen clockwise\n");
		} else if(!xf86NameCmp(s, "CCW")) {
		    cPtr->Flags |= ChipsShadowFB;
		    cPtr->Rotate = -1;
		    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,  "Rotating screen"
			       "counter clockwise\n");
		} else {
		    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "\"%s\" is not a valid"
			       "value for Option \"Rotate\"\n", s);
		    xf86DrvMsg(pScrn->scrnIndex, X_INFO, 
			       "Valid options are \"CW\" or \"CCW\"\n");
		}
	    } else {
		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, 
			   "Using \"Shadow Framebuffer\"\n");
		cPtr->Flags |= ChipsShadowFB;
	    }
	}
    }
    if (cPtr->Flags & ChipsShadowFB) {
	if (cPtr->Flags & ChipsAccelSupport) {
	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 
		"HW acceleration is not supported with shadow fb\n");
	    cPtr->Flags &= ~ChipsAccelSupport;
	}
	if (cPtr->Rotate && cPtr->Accel.UseHWCursor) {
	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 
		"HW cursor is not supported with rotate\n");
	    cPtr->Accel.UseHWCursor = FALSE;
	}
    }

    cPtr->PanelType |= ChipsCRT;
    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "CRT\n");

    /* monitor info */
    cPtr->Monitor = chipsSetMonitor(pScrn);

    /* bus type */
    tmp = cPtr->readXR(cPtr, 0x01) & 3;
    switch (tmp) {
    case 0:
	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "ISA Bus\n");
	cPtr->Bus = ChipsISA;
	break;
    case 3:
	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "VL Bus\n");
	cPtr->Bus = ChipsVLB;
	break;
    default:
	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Unknown Bus\n");
	cPtr->Bus = ChipsUnknown;
	break;
    }

    /* disable acceleration for 1 and 4 bpp */
    if (pScrn->bitsPerPixel < 8) {
	xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
		 "Disabling acceleration for %d bpp\n", pScrn->bitsPerPixel);
	cPtr->Flags &= ~ChipsAccelSupport;
    }

    /* 32bit register address offsets */
    if ((cPtr->Flags & ChipsAccelSupport) ||
	    (cPtr->Accel.UseHWCursor)) {
	cPtr->Regs32 = xnfalloc(sizeof(ChipsReg32));
	tmp = cPtr->readXR(cPtr, 0x07);
	for( i = 0; i < (sizeof(ChipsReg32) / sizeof(ChipsReg32[0])); i++) {
	    cPtr->Regs32[i] =  ((ChipsReg32[i] & 0x7E03)) | ((tmp & 0x80)
		<< 8)| ((tmp & 0x7F) << 2);
#ifdef DEBUG
	    ErrorF("DR[%X] = %X\n",i,cPtr->Regs32[i]);
#endif
	}
	linearRes[0].type = ResExcIoSparse | ResBios | ResBus;
	linearRes[0].rBase = cPtr->Regs32[0];
	linearRes[0].rMask = (int)0xFFFF83FC;
	if (xf86RegisterResources(cPtr->pEnt->index,linearRes,ResNone)) {
	    if (cPtr->Flags & ChipsAccelSupport) {
		cPtr->Flags &= ~ChipsAccelSupport;
		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
			   "Cannot allocate IO registers: "
			   "Disabling acceleration\n");
	    }
	    if (cPtr->Accel.UseHWCursor) {
		cPtr->Accel.UseHWCursor = FALSE;
		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
			   "Cannot allocate IO registers: "
			   "Disabling HWCursor\n");
	    }
	}
    }

    cPtr->ClockMulFactor = ((pScrn->bitsPerPixel >= 8) ? bytesPerPixel : 1);
    if (cPtr->ClockMulFactor != 1)
	xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
	       "Clocks scaled by %d\n", cPtr->ClockMulFactor);

    /* Clock type */
    switch (cPtr->Chipset) {
    case CHIPS_CT64200:
	NoClocks = 4;
	cPtr->ClockType = WINGINE_1_STYLE | TYPE_HW;
	break;
    default:
	if (!((cPtr->readXR(cPtr, 0x01)) & 0x10)) {
	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
		       "Using external clock generator\n");
	    NoClocks = 4;
	    cPtr->ClockType = WINGINE_1_STYLE | TYPE_HW;
	} else {
	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
		       "Using internal clock generator\n");
	    if (xf86ReturnOptValBool(cPtr->Options, OPTION_HW_CLKS, FALSE)) {
		NoClocks = 3;
		cPtr->ClockType = WINGINE_2_STYLE | TYPE_HW;
	    } else {
		NoClocks = 26; /* some number */
		cPtr->ClockType = WINGINE_2_STYLE | TYPE_PROGRAMMABLE;
		pScrn->progClock = TRUE;
	    }
	}
    }

    if (cPtr->ClockType & TYPE_PROGRAMMABLE) {
	pScrn->numClocks = NoClocks;
	if(cPtr->pEnt->device->textClockFreq > 0) {
	    SaveClk->Clock = cPtr->pEnt->device->textClockFreq;
	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
		       "Using textclock freq: %7.3f.\n",
		       SaveClk->Clock/1000.0);
	} else
	   SaveClk->Clock = CRT_TEXT_CLK_FREQ;
	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Using programmable clocks\n");
    } else {  /* TYPE_PROGRAMMABLE */
	SaveClk->Clock = chipsGetHWClock(pScrn);
	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Using textclock clock %i.\n",
	       SaveClk->Clock);
	if (!cPtr->pEnt->device->numclocks) {
	    pScrn->numClocks = NoClocks;
	    xf86GetClocks(pScrn, NoClocks, chipsClockSelect,
			  chipsProtect, chipsBlankScreen,
			  cPtr->IOBase + 0x0A, 0x08, 1, 28322);
	    from = X_PROBED;
	} else {
	    pScrn->numClocks = cPtr->pEnt->device->numclocks;
	    if (pScrn->numClocks > NoClocks) {
		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
			   "Too many Clocks specified in configuration file.\n");
		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
			   "\t\tAt most %d clocks may be specified\n", NoClocks);
		pScrn->numClocks= NoClocks;
	    }
	    for (i = 0; i < pScrn->numClocks; i++)
		pScrn->clock[i] = cPtr->pEnt->device->clock[i];
	    from = X_CONFIG;
	}
	xf86ShowClocks(pScrn, from);
    }
      
    /* Set the min pixel clock */
    /* XXX Guess, need to check this */
    cPtr->MinClock = 11000 / cPtr->ClockMulFactor;
    xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "Min pixel clock is %7.3f MHz\n",
	       (float)(cPtr->MinClock / 1000.));
    /* maximal clock */
    switch (cPtr->Chipset) {
    case CHIPS_CT64200:
	cPtr->MaxClock = 80000 / cPtr->ClockMulFactor;
	break;
    case CHIPS_CT64300:
	cPtr->MaxClock = 85000 / cPtr->ClockMulFactor;
	break;
    }

    if (cPtr->pEnt->device->dacSpeeds[0]) {
	int speed = 0;
	switch (pScrn->bitsPerPixel) {
	case 1:
	case 4:
	case 8:
	   speed = cPtr->pEnt->device->dacSpeeds[DAC_BPP8];
	   break;
	case 16:
	   speed = cPtr->pEnt->device->dacSpeeds[DAC_BPP16];
	   break;
	case 24:
	   speed = cPtr->pEnt->device->dacSpeeds[DAC_BPP24];
	   break;
	}
	if (speed == 0)
	    cPtr->MaxClock = cPtr->pEnt->device->dacSpeeds[0];
	from = X_CONFIG;
	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
	    "User max pixel clock of %7.3f MHz overrides %7.3f MHz limit\n",
	    (float)(cPtr->MaxClock / 1000.), (float)(speed / 1000.));
	cPtr->MaxClock = speed;
    } else {
	xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
		"Max pixel clock is %7.3f MHz\n",
		(float)(cPtr->MaxClock / 1000.));
    }
    
    if ((pMod = xf86LoadSubModule(pScrn, "ddc"))) {
	xf86LoaderModReqSymLists(pMod, ddcSymbols, NULL);
	if (cPtr->pVbe)
	    xf86SetDDCproperties(pScrn,xf86PrintEDID(vbeDoEDID(cPtr->pVbe, pMod)));
    }
    return TRUE;
}

static Bool
chipsPreInit655xx(ScrnInfoPtr pScrn, int flags)
{
    int i, bytesPerPixel, NoClocks = 0;
    unsigned char tmp;
    MessageType from;
    vgaHWPtr hwp;
    CHIPSPtr cPtr = CHIPSPTR(pScrn);
    CHIPSPanelSizePtr Size = &cPtr->PanelSize;
    CHIPSClockPtr SaveClk = &(cPtr->SavedReg.Clock);
    Bool useLinear = FALSE;
    char *s;
    resRange linearRes[] = { {ResExcMemBlock|ResBios|ResBus,0,0},_END };
    ModuleDescPtr pMod;
    
    /* Set pScrn->monitor */
    pScrn->monitor = pScrn->confScreen->monitor;

    if (cPtr->Flags & ChipsHDepthSupport)
	i = xf86SetDepthBpp(pScrn, 0, 0, 0, Support24bppFb |
				SupportConvert32to24 | PreferConvert32to24);
    else
	i = xf86SetDepthBpp(pScrn, 8, 0, 0, NoDepth24Support);

    if (!i)
	return FALSE;
    else {
	/* Check that the returned depth is one we support */
	switch (pScrn->depth) {
	case 1:
	case 4:
	case 8:
	    /* OK */
	    break;
	case 15:
	case 16:
	case 24:
	    if (cPtr->Flags & ChipsHDepthSupport) 
		break; /* OK */
	    /* fall through */
	default:
	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
		       "Given depth (%d) is not supported by this driver\n",
		       pScrn->depth);
	    return FALSE;
	}
    }
    xf86PrintDepthBpp(pScrn);

    /* Get the depth24 pixmap format */
    if (pScrn->depth == 24 && pix24bpp == 0)
	pix24bpp = xf86GetBppFromDepth(pScrn, 24);

    /*
     * Allocate a vgaHWRec, this must happen after xf86SetDepthBpp for 1bpp
     */
    if (!vgaHWGetHWRec(pScrn))
        return FALSE;

    hwp = VGAHWPTR(pScrn);
    vgaHWGetIOBase(hwp);

    /*
     * This must happen after pScrn->display has been set because
     * xf86SetWeight references it.
     */
    if (pScrn->depth > 8) {
	/* The defaults are OK for us */
	rgb zeros = {0, 0, 0};

	if (!xf86SetWeight(pScrn, zeros, zeros)) {
	    return FALSE;
	} else {
	    /* XXX check that weight returned is supported */
            ;
        }
    }

    if (!xf86SetDefaultVisual(pScrn, -1))
	return FALSE;

    /* The gamma fields must be initialised when using the new cmap code */
    if (pScrn->depth > 1) {
	Gamma zeros = {0.0, 0.0, 0.0};

	if (!xf86SetGamma(pScrn, zeros))
	    return FALSE;
    }

    /* Store register values that might be messed up by a suspend resume */
    /* Do this early as some of the other code in PreInit relies on it   */
    cPtr->SuspendHack.xr02 = (cPtr->readXR(cPtr, 0x02)) & 0x18;
    cPtr->SuspendHack.xr03 = (cPtr->readXR(cPtr, 0x03)) & 0x0A;
    cPtr->SuspendHack.xr14 = (cPtr->readXR(cPtr, 0x14)) & 0x20;
    cPtr->SuspendHack.xr15 = cPtr->readXR(cPtr, 0x15);

    cPtr->SuspendHack.vgaIOBaseFlag = ((hwp->readMiscOut(hwp)) & 0x01);
    cPtr->IOBase = cPtr->SuspendHack.vgaIOBaseFlag ? 0x3D0 : 0x3B0;

    bytesPerPixel = max(1, pScrn->bitsPerPixel >> 3);

    /* Collect all of the relevant option flags (fill in pScrn->options) */
    xf86CollectOptions(pScrn, NULL);

    /* Process the options */
    if (!(cPtr->Options = xalloc(sizeof(Chips655xxOptions))))
	return FALSE;
    memcpy(cPtr->Options, Chips655xxOptions, sizeof(Chips655xxOptions));
    xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, cPtr->Options);

    /* Set the bits per RGB */
    if (pScrn->depth > 1) {
	/* Default to 6, is this right */
	pScrn->rgbBits = 6;
#if 0
	if (xf86GetOptValInteger(cPtr->Options, OPTION_RGB_BITS,
				 &pScrn->rgbBits)) {
	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Bits per RGB set to %d\n",
		       pScrn->rgbBits);
	}
#endif
    }
    if ((cPtr->Flags & ChipsAccelSupport) &&
	    (xf86ReturnOptValBool(cPtr->Options, OPTION_NOACCEL, FALSE))) {
	cPtr->Flags &= ~ChipsAccelSupport;
	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Acceleration disabled\n");
    }
    
    from = X_DEFAULT;
    if (pScrn->bitsPerPixel < 8) {
	/* Default to SW cursor for 1/4 bpp */
	cPtr->Accel.UseHWCursor = FALSE;
    } else {
	cPtr->Accel.UseHWCursor = TRUE;
    }
    if (xf86GetOptValBool(cPtr->Options, OPTION_HW_CURSOR,
			  &cPtr->Accel.UseHWCursor))
	from = X_CONFIG;
    if (xf86GetOptValBool(cPtr->Options, OPTION_SW_CURSOR,
			  &cPtr->Accel.UseHWCursor)) {
	from = X_CONFIG;
	cPtr->Accel.UseHWCursor = !cPtr->Accel.UseHWCursor;
    }
    xf86DrvMsg(pScrn->scrnIndex, from, "Using %s cursor\n",
	       (cPtr->Accel.UseHWCursor) ? "HW" : "SW");

    /* memory size */
    if (cPtr->pEnt->device->videoRam != 0) {
	pScrn->videoRam = cPtr->pEnt->device->videoRam;
	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "VideoRAM: %d kByte\n",
               pScrn->videoRam);
    } else {
        /* not given, probe it    */
	/* XR0F: Software flags 0 */
	/* bit 1-0: memory size   */
	/*          0: 256 kB     */
	/*          1: 512 kB     */
	/*          2: 1024 kB    */
	/*          3: 1024 kB    */

	switch ((cPtr->readXR(cPtr, 0x0F)) & 3) {
	case 0:
	    pScrn->videoRam = 256;
	    break;
	case 1:
	    pScrn->videoRam = 512;
	    break;
	case 2:
	case 3:
	    pScrn->videoRam = 1024;
	    break;
	}

	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "VideoRAM: %d kByte\n",
               pScrn->videoRam);
    }
    cPtr->FbMapSize = pScrn->videoRam * 1024;

    /* Default to nonlinear for < 8bpp and linear for >= 8bpp. */
    if (cPtr->Flags & ChipsLinearSupport) useLinear = TRUE;
    if (pScrn->bitsPerPixel < 8) {
	if (!xf86ReturnOptValBool(cPtr->Options, OPTION_LINEAR, FALSE)) {
	    useLinear = FALSE;
	    from = X_CONFIG;
	}
    } else if (!xf86ReturnOptValBool(cPtr->Options, OPTION_LINEAR, TRUE)) {
	useLinear = FALSE;
	from = X_CONFIG;
    }
    
    /* linear base */
    if (useLinear) {
	unsigned char mask;
	if (cPtr->Chipset == CHIPS_CT65535) {
	    mask = (pScrn->videoRam > 512) ? 0xF8 :0xFC;
	    if (cPtr->Bus == ChipsISA)
	    mask &= 0x7F;
	} else if (cPtr->Bus == ChipsISA) {
	    mask = 0x0F;
	} else {
	    mask = 0xFF;
	    tmp = cPtr->readXR(cPtr, 0x01);
	    if(tmp & 0x40)
		mask &= 0x3F;
	    if(!(tmp & 0x80))
		mask &= 0xCF;
	}
	if (cPtr->pEnt->location.type == BUS_PCI) {
	    cPtr->FbAddress =  cPtr->PciInfo->memBase[0] & 0xff800000;
	    if (xf86RegisterResources(cPtr->pEnt->index,NULL,ResNone))
		useLinear = FALSE;
		from = X_PROBED;
	} else {
	    if (cPtr->pEnt->device->MemBase) {
		cPtr->FbAddress = cPtr->pEnt->device->MemBase;
		if (cPtr->Chipset == CHIPS_CT65535)
		    cPtr->FbAddress &= (mask << 17);
		else if (cPtr->Chipset > CHIPS_CT65535)
		    cPtr->FbAddress &= (mask << 20);
		from = X_CONFIG;
	    } else { 
		if (cPtr->Chipset <= CHIPS_CT65530) {
		    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
			       "base address assumed at  0xC00000!\n");
		    cPtr->FbAddress = 0xC00000;
		    from = X_CONFIG;
		} else if (cPtr->Chipset == CHIPS_CT65535) {
		    cPtr->FbAddress =
			((mask & (cPtr->readXR(cPtr, 0x08))) << 17);
		} else {
		    cPtr->FbAddress =
			((mask & (cPtr->readXR(cPtr, 0x08))) << 20);
		}
		from = X_PROBED;
	    }
	    linearRes[0].rBegin = cPtr->FbAddress;
	    linearRes[0].rEnd = cPtr->FbAddress + 0x800000;
	    if (xf86RegisterResources(cPtr->pEnt->index,linearRes,ResNone)) {
		useLinear = FALSE;
		from = X_PROBED;
	    }
	}
    }
    
    if (useLinear) {
	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
		   "Enabling linear addressing\n");
	xf86DrvMsg(pScrn->scrnIndex, from,
		   "base address is set at 0x%lX.\n", cPtr->FbAddress);
	if (xf86ReturnOptValBool(cPtr->Options, OPTION_MMIO, FALSE) &&
	    (cPtr->Flags & ChipsMMIOSupport)) {
	    cPtr->UseMMIO = TRUE;
	    cPtr->IOAddress = cPtr->FbAddress + 0x200000L;
	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Enabling MMIO\n");
	}
    } else {
	if (cPtr->Flags & ChipsLinearSupport)	
	    xf86DrvMsg(pScrn->scrnIndex, from,
		       "Disabling linear addressing\n");
	cPtr->Flags &= ~ChipsLinearSupport;
    }
    
    if ((s = xf86GetOptValString(cPtr->Options, OPTION_ROTATE))
	|| xf86ReturnOptValBool(cPtr->Options, OPTION_SHADOW_FB, FALSE)) {
	if (!(cPtr->Flags & ChipsLinearSupport)) {
	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
		    "Option \"ShadowFB\" ignored. Not supported without linear addressing\n");
	} else if (pScrn->depth < 8) {
	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
		    "Option \"ShadowFB\" ignored. Not supported at this depth.\n");
	} else {
	    cPtr->Rotate = 0;
	    if (s) {
		if(!xf86NameCmp(s, "CW")) {
		    /* accel is disabled below for shadowFB */
		    cPtr->Flags |= ChipsShadowFB;
		    cPtr->Rotate = 1;
		    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, 
			       "Rotating screen clockwise\n");
		} else if(!xf86NameCmp(s, "CCW")) {
		    cPtr->Flags |= ChipsShadowFB;
		    cPtr->Rotate = -1;
		    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,  "Rotating screen"
			       "counter clockwise\n");
		} else {
		    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "\"%s\" is not a valid"
			       "value for Option \"Rotate\"\n", s);
		    xf86DrvMsg(pScrn->scrnIndex, X_INFO, 
			       "Valid options are \"CW\" or \"CCW\"\n");
		}
	    } else {
		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, 
			   "Using \"Shadow Framebuffer\"\n");
		cPtr->Flags |= ChipsShadowFB;
	    }
	}
    }
    if (cPtr->Flags & ChipsShadowFB) {
	if (cPtr->Flags & ChipsAccelSupport) {
	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 
		"HW acceleration is not supported with shadow fb\n");
	    cPtr->Flags &= ~ChipsAccelSupport;
	}
	if (cPtr->Rotate && cPtr->Accel.UseHWCursor) {
	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 
		"HW cursor is not supported with rotate\n");
	    cPtr->Accel.UseHWCursor = FALSE;
	}
    }

    /*test STN / TFT */
    tmp = cPtr->readXR(cPtr, 0x51);

    /* XR51 or FR10: DISPLAY TYPE REGISTER                      */
    /* XR51[1-0] or FR10[1:0] for ct65550 : PanelType,          */
    /* 0 = Single Panel Single Drive, 3 = Dual Panel Dual Drive */
    switch (tmp & 0x3) {
    case 0:
	if (xf86ReturnOptValBool(cPtr->Options, OPTION_STN, FALSE)) {
	    cPtr->PanelType |= ChipsSS;
	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "SS-STN probed\n");
	} else {
	    cPtr->PanelType |= ChipsTFT;
	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "TFT probed\n");
	}
	break;
    case 2:
	cPtr->PanelType |= ChipsDS;
	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "DS-STN probed\n");
    case 3:
	cPtr->PanelType |= ChipsDD;
	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "DD-STN probed\n");
	break;
    default:
	break;
    }

    chipsSetPanelType(cPtr);
    from = X_PROBED;
    {
        Bool fp_mode;
	if (xf86GetOptValBool(cPtr->Options, OPTION_FP_MODE, &fp_mode)) {
	    if (fp_mode) {
	        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Forcing FP Mode on\n");
		cPtr->PanelType |= ChipsLCD;
	    } else {
	       xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Forcing FP Mode off\n");
	       cPtr->PanelType = ~ChipsLCD;
	    } 
	    from = X_CONFIG;
	}
    }
    if ((cPtr->PanelType & ChipsLCD) && (cPtr->PanelType & ChipsCRT))
	xf86DrvMsg(pScrn->scrnIndex, from, "LCD/CRT\n");
    else if (cPtr->PanelType & ChipsLCD)
        xf86DrvMsg(pScrn->scrnIndex, from, "LCD\n");
    else if (cPtr->PanelType & ChipsCRT) {
        xf86DrvMsg(pScrn->scrnIndex, from, "CRT\n");
	/* monitor info */
	cPtr->Monitor = chipsSetMonitor(pScrn);
    }
      
    /* screen size */
    /* 
     * In LCD mode / dual mode we want to derive the timing values from
     * the ones preset by bios
     */
    if (cPtr->PanelType & ChipsLCD) {
	unsigned char xr17, tmp1;
	char tmp2;

	xr17 = cPtr->readXR(cPtr, 0x17);
	tmp = cPtr->readXR(cPtr, 0x1B);
	Size->HTotal =((tmp + ((xr17 & 0x01) << 8)) + 5) << 3;
	tmp = cPtr->readXR(cPtr, 0x1C);
	Size->HDisplay = ((tmp + ((xr17 & 0x02) << 7)) + 1) << 3;
	tmp = cPtr->readXR(cPtr, 0x19);
	Size->HRetraceStart = ((tmp + ((xr17 & 0x04) << 9)) + 1) << 3;
	tmp1 = cPtr->readXR(cPtr, 0x1A);
	tmp2 = (tmp1 & 0x1F) + ((xr17 & 0x08) << 2) - (tmp & 0x3F);
	Size->HRetraceEnd = ((((tmp2 & 0x080u) ? (tmp2 + 0x40) : tmp2) << 3)
		+ Size->HRetraceStart);
	tmp1 = cPtr->readXR(cPtr, 0x65);
	tmp = cPtr->readXR(cPtr, 0x68);
	Size->VDisplay = ((tmp1 & 0x02) << 7) 
	      + ((tmp1 & 0x40) << 3) + tmp + 1;
	tmp = cPtr->readXR(cPtr, 0x66);
	Size->VRetraceStart = ((tmp1 & 0x04) << 6) 
	      + ((tmp1 & 0x80) << 2) + tmp + 1;
	tmp = cPtr->readXR(cPtr, 0x64);
	Size->VTotal = ((tmp1 & 0x01) << 8)
	      + ((tmp1 & 0x20) << 4) + tmp + 2;
#ifdef DEBUG
	ErrorF("x=%i, y=%i; xSync=%i, xSyncEnd=%i, xTotal=%i\n",
	       Size->HDisplay, Size->VDisplay,
	       Size->HRetraceStart, Size->HRetraceEnd,
	       Size->HTotal);
#endif
	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Display Size: x=%i; y=%i\n",
		Size->HDisplay, Size->VDisplay);
	/* Warn the user if the panel size has been overridden by
	 * the modeline values
	 */
	if (xf86ReturnOptValBool(cPtr->Options, OPTION_PANEL_SIZE, FALSE)) {
	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
		       "Display size overridden by modelines.\n");
	}
    }

    /* Frame Buffer */                 /* for LCDs          */ 
    if (IS_STN(cPtr->PanelType)) {
	tmp = cPtr->readXR(cPtr, 0x6F); /*Frame Buffer Ctrl. */
	if (tmp & 1) {
	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Frame Buffer used\n");
	    if ((cPtr->Chipset > CHIPS_CT65530) && !(tmp & 0x80)) {
		/* Formula for calculating the size of the framebuffer. 3
		 * bits per pixel 10 pixels per 32 bit dword. If frame
		 * acceleration is enabled the size can be halved.
		 */
		cPtr->FrameBufferSize = ( Size->HDisplay *
			Size->VDisplay / 5 ) * ((tmp & 2) ? 1 : 2);
		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
			   "Using embedded Frame Buffer, size %d bytes\n",
			   cPtr->FrameBufferSize);
	    } else
		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
			   "Using external Frame Buffer used\n");
	}
	if (tmp & 2)
	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
		       "Frame accelerator enabled\n");
    }

    /* bus type */
    if (cPtr->Chipset > CHIPS_CT65535) {
	tmp = (cPtr->readXR(cPtr, 0x01)) & 7;
	if (tmp == 6) {	       /*PCI */
	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "PCI Bus\n");
	    cPtr->Bus = ChipsPCI;
	    if ((cPtr->Chipset == CHIPS_CT65545) ||
		    (cPtr->Chipset == CHIPS_CT65546)) {
		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
			   "32Bit IO not supported on 65545 PCI\n");
		xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "\tenabling MMIO\n");
		cPtr->UseMMIO = TRUE;
		cPtr->IOAddress = cPtr->FbAddress + 0x200000L;
	    }
	    
	} else {   /* XR08: Linear addressing base, not for PCI */
	    switch (tmp) {
	    case 3:
		xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "CPU Direct\n");
		cPtr->Bus = ChipsCPUDirect;
		break;
	    case 5:
		xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "ISA Bus\n");
		cPtr->Bus = ChipsISA;
		break;
	    case 7:
		xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "VL Bus\n");
		cPtr->Bus = ChipsVLB;
		break;
	    default:
		xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Unknown Bus\n");
	    }
	}
    } else {
	tmp = (cPtr->readXR(cPtr, 0x01)) & 3;
	switch (tmp) {
	case 0:
	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "PI Bus\n");
	    cPtr->Bus = ChipsPIB;
	    break;
	case 1:
	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "MC Bus\n");
	    cPtr->Bus = ChipsMCB;
	    break;
	case 2:
	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "VL Bus\n");
	    cPtr->Bus = ChipsVLB;
	    break;
	case 3:
	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "ISA Bus\n");
	    cPtr->Bus = ChipsISA;
	    break;
	}
    }

    if (!(cPtr->Bus == ChipsPCI) && (cPtr->UseMMIO)) {
	cPtr->UseMMIO = FALSE;
	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
		   "MMIO only supported on PCI Bus. Disabling MMIO\n");
    }

    /* disable acceleration for 1 and 4 bpp */
    if (pScrn->bitsPerPixel < 8) {
	xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
		 "Disabling acceleration for %d bpp\n", pScrn->bitsPerPixel);
	cPtr->Flags &= ~ChipsAccelSupport;
    }

    if ((cPtr->Chipset == CHIPS_CT65530) &&
	    (cPtr->Flags & ChipsLinearSupport)) {
	/* linear mode is no longer default on ct65530 since it */
	/* requires additional hardware which some manufacturers*/
	/* might not provide.                                   */
	if (!xf86ReturnOptValBool(cPtr->Options, OPTION_LINEAR, FALSE))
	    cPtr->Flags &= ~ChipsLinearSupport;
	
	/* Test wether linear addressing is possible on 65530 */
	/* on the 65530 only the A19 select scheme can be used*/
	/* for linear addressing since MEMW is used on ISA bus*/
	/* systems.                                           */
	/* A19 however is used if video memory is > 512 Mb    */   
	if ((cPtr->Bus == ChipsISA) && (pScrn->videoRam > 512)) {
	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
		       "User selected linear fb not supported by HW!\n");
	    cPtr->Flags &= ~ChipsLinearSupport;
	}
    }

    /* DAC info */
    if ((cPtr->readXR(cPtr, 0x06)) & 0x02)
	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Internal DAC disabled\n");

    /* MMIO address offset */
    if (cPtr->UseMMIO)
	cPtr->Regs32 = ChipsReg32;
    else if ((cPtr->Flags & ChipsAccelSupport) ||
	     (cPtr->Accel.UseHWCursor)) {
	cPtr->Regs32 = xnfalloc(sizeof(ChipsReg32));
	tmp =  cPtr->readXR(cPtr, 0x07);
	for (i = 0; i < (sizeof(ChipsReg32)/sizeof(ChipsReg32[0])); i++) {
	    cPtr->Regs32[i] =
		((ChipsReg32[i] & 0x7E03)) | ((tmp & 0x80)<< 8)
		| ((tmp & 0x7F) << 2);
#ifdef DEBUG
	    ErrorF("DR[%X] = %X\n",i,cPtr->Regs32[i]);
#endif
	}
	linearRes[0].type = ResExcIoSparse | ResBios | ResBus;
	linearRes[0].rBase = cPtr->Regs32[0];
	linearRes[0].rMask = (int)0xFFFF83FC;
	if (xf86RegisterResources(cPtr->pEnt->index,linearRes,ResNone)) {
	    if (cPtr->Flags & ChipsAccelSupport) {
		cPtr->Flags &= ~ChipsAccelSupport;
		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
			   "Cannot allocate IO registers: "
			   "Disabling acceleration\n");
	    }
	    if (cPtr->Accel.UseHWCursor) {
		cPtr->Accel.UseHWCursor = FALSE;
		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
			   "Cannot allocate IO registers: "
			   "Disabling HWCursor\n");
	    }
	}
    }

    /* sync reset ignored on this chipset */
    if (cPtr->Chipset > CHIPS_CT65530) {
	tmp = cPtr->readXR(cPtr, 0x0E);
	if (tmp & 0x80)
	    cPtr->SyncResetIgn = TRUE;
	xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
		   "Synchronous reset %signored.\n",
		   (cPtr->SyncResetIgn ? "" : "not ")); 
    }

    cPtr->ClockMulFactor = ((pScrn->bitsPerPixel >= 8) ? bytesPerPixel : 1);
    if (cPtr->ClockMulFactor != 1)
	xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
	       "Clocks scaled by %d\n", cPtr->ClockMulFactor);
    /* We use a programmable clock */
    switch (cPtr->Chipset) {
    case CHIPS_CT65520:
    case CHIPS_CT65525:
    case CHIPS_CT65530:
	NoClocks = 4;		/* Some number */
	cPtr->ClockType = OLD_STYLE | TYPE_HW;
	break;
    default:
	if (xf86ReturnOptValBool(cPtr->Options, OPTION_HW_CLKS, FALSE)) {
	    NoClocks = 5;		/* Some number */
	    cPtr->ClockType = NEW_STYLE | TYPE_HW;
	} else {
	    NoClocks = 26;		/* Some number */
	    cPtr->ClockType = NEW_STYLE | TYPE_PROGRAMMABLE;
	    pScrn->progClock = TRUE;
	}
    }

    if (cPtr->ClockType & TYPE_PROGRAMMABLE) {
	pScrn->numClocks = NoClocks;
	if (cPtr->pEnt->device->textClockFreq > 0) {
	    SaveClk->Clock = cPtr->pEnt->device->textClockFreq;
	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
		       "Using textclock freq: %7.3f.\n",
		       SaveClk->Clock/1000.0);
	} else
	   SaveClk->Clock = ((cPtr->PanelType & ChipsLCDProbed) ? 
				 LCD_TEXT_CLK_FREQ : CRT_TEXT_CLK_FREQ);
	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Using programmable clocks\n");
    } else {  /* TYPE_PROGRAMMABLE */
	SaveClk->Clock = chipsGetHWClock(pScrn);
	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Using textclock clock %i.\n",
	       SaveClk->Clock);
	if (!cPtr->pEnt->device->numclocks) {
	    pScrn->numClocks = NoClocks;
	    xf86GetClocks(pScrn, NoClocks, chipsClockSelect,
			  chipsProtect, chipsBlankScreen,
			  cPtr->IOBase + 0x0A, 0x08, 1, 28322);
	    from = X_PROBED;
	} else { 
	    pScrn->numClocks = cPtr->pEnt->device->numclocks;
	    if (pScrn->numClocks > NoClocks) {
		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
			   "Too many Clocks specified in configuration file.\n");
		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
			   "\t\tAt most %d clocks may be specified\n", NoClocks);
		pScrn->numClocks = NoClocks;
	    }
	    for (i = 0; i < pScrn->numClocks; i++)
		pScrn->clock[i] = cPtr->pEnt->device->clock[i];
	    from = X_CONFIG;
	}
	xf86ShowClocks(pScrn, from);
    }
    /* Set the min pixel clock */
    /* XXX Guess, need to check this */
    cPtr->MinClock = 11000 / cPtr->ClockMulFactor;
    xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "Min pixel clock is %7.3f MHz\n",
	       (float)(cPtr->MinClock / 1000.));
    /* Set the max pixel clock */
    switch (cPtr->Chipset) {
    case CHIPS_CT65546:
    case CHIPS_CT65548:
	/* max VCLK is 80 MHz, max MCLK is 75 MHz for CT65548 */
	/* It is not sure for CT65546, but it works with 60 nsec EDODRAM */
	cPtr->MaxClock = 80000 / cPtr->ClockMulFactor;
	break;
    default:
	if ((cPtr->readXR(cPtr, 0x6C)) & 2) {
	    /*5V Vcc */
	    cPtr->MaxClock = 68000 / cPtr->ClockMulFactor;
	} else {
	    /*3.3V Vcc */
	    cPtr->MaxClock = 56000 / cPtr->ClockMulFactor;
	}
    }
    
    if (cPtr->pEnt->device->dacSpeeds[0]) {
	int speed = 0;
	switch (pScrn->bitsPerPixel) {
	case 1:
	case 4:
	case 8:
	    speed = cPtr->pEnt->device->dacSpeeds[DAC_BPP8];
	    break;
	case 16:
	    speed = cPtr->pEnt->device->dacSpeeds[DAC_BPP16];
	    break;
	case 24:
	    speed = cPtr->pEnt->device->dacSpeeds[DAC_BPP24];
	    break;
	}
	if (speed == 0)
	    cPtr->MaxClock = cPtr->pEnt->device->dacSpeeds[0];
	from = X_CONFIG;
	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
	    "User max pixel clock of %7.3f MHz overrides %7.3f MHz limit\n",
	    (float)(cPtr->MaxClock / 1000.), (float)(speed / 1000.));
	cPtr->MaxClock = speed;
    } else {
	xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
		   "Max pixel clock is %7.3f MHz\n",
		   (float)(cPtr->MaxClock / 1000.));
    }

    /* FP clock */
    if (cPtr->ClockType & TYPE_PROGRAMMABLE) {
	double real = 0;
	    
	switch(bytesPerPixel) {
	case 1:
	    xf86GetOptValFreq(cPtr->Options, OPTION_FP_CLOCK_8,
			      OPTUNITS_MHZ, &real);
	    break;
	case 2:
	    xf86GetOptValFreq(cPtr->Options, OPTION_FP_CLOCK_16,
			      OPTUNITS_MHZ, &real);
	    break;
	case 3:
	    xf86GetOptValFreq(cPtr->Options, OPTION_FP_CLOCK_24,
			      OPTUNITS_MHZ, &real);
	    break;
	}
	
	if (real > 0) {
	    int val;
	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
		       "FP clock %7.3f MHz requested\n",real);
	    val = (int) (real * 1000.);
	    if (val && (val >= cPtr->MinClock)
		&& (val <= cPtr->MaxClock))
		cPtr->FPclock = val * cPtr->ClockMulFactor;
	    else if (val > cPtr->MaxClock)
		cPtr->FPclock = (int)((float)cPtr->MaxClock
				      * cPtr->ClockMulFactor * 0.9);
	    else
		cPtr->FPclock = 0; /* special value */
	}  else 
	    cPtr->FPclock = 0; /* special value */
	
	if (cPtr->FPclock)
	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
		       "FP clock set to %7.3f MHz\n",
		       (float)(cPtr->FPclock / 1000.));
    } else {
	if (xf86IsOptionSet(cPtr->Options, OPTION_SET_MCLK))
	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
		       "FP clock option not supported for this chipset\n");
    }
    
    /* Memory Clock */
    if (cPtr->ClockType & TYPE_PROGRAMMABLE) {
	double real;
	
	switch (cPtr->Chipset) {
	case CHIPS_CT65546:
	case CHIPS_CT65548:
	    /* max MCLK is 75 MHz for CT65548 */
	    cPtr->MemClock.Max = 75000;
	    break;
	default:
	    if ((cPtr->readXR(cPtr, 0x6C)) & 2) {
		/*5V Vcc */
		cPtr->MemClock.Max = 68000;
	    } else {
		/*3.3V Vcc */
		cPtr->MemClock.Max = 56000;
	    }
	}
	
	if (xf86GetOptValFreq(cPtr->Options, OPTION_SET_MCLK,
			      OPTUNITS_MHZ, &real)) {
	    int mclk = (int)(real * 1000.0);
	    if (mclk <= cPtr->MemClock.Max) {
		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
			   "Using memory clock of %7.3f MHz\n",
			   (float)(mclk/1000.));
		cPtr->MemClock.Clk = mclk;
	    } else {
		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
			   "Memory clock of %7.3f MHz exceeds limit of "
			   "%7.3f MHz\n",(float)(mclk/1000.),
			   (float)(cPtr->MemClock.Max/1000.));
		cPtr->MemClock.Clk = cPtr->MemClock.Max * 0.9;
	    }
	} else
	    cPtr->MemClock.Clk = 0;
    } else
	if (xf86IsOptionSet(cPtr->Options, OPTION_SET_MCLK))
	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
		       "Memory clock option not supported for this chipset\n");
    
    if ((pMod = xf86LoadSubModule(pScrn, "ddc"))) {
	xf86LoaderModReqSymLists(pMod, ddcSymbols, NULL);
	if (cPtr->pVbe)
	    xf86SetDDCproperties(pScrn,xf86PrintEDID(vbeDoEDID(cPtr->pVbe, pMod)));
    }
    return TRUE;
}
    

/* Mandatory */
static Bool
CHIPSEnterVT(int scrnIndex, int flags)
{
    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
    CHIPSPtr cPtr = CHIPSPTR(pScrn);
    CHIPSEntPtr cPtrEnt;

    if (cPtr->Flags & ChipsDualChannelSupport) {
        cPtrEnt = xf86GetEntityPrivate(pScrn->entityList[0],
					       CHIPSEntityIndex)->ptr;
	DUALOPEN;
    }
    /* Should we re-save the text mode on each VT enter? */
    if(!chipsModeInit(pScrn, pScrn->currentMode))
      return FALSE;
    if ((!(cPtr->Flags & ChipsOverlay8plus16)) 
	&& (cPtr->Flags & ChipsVideoSupport)
	&& (cPtr->Flags & ChipsLinearSupport)) 
        CHIPSResetVideo(pScrn); 

    /*xf86UDelay(50000);*/
    chipsHWCursorOn(cPtr, pScrn);
    /* cursor settle delay */
    xf86UDelay(50000);
    CHIPSAdjustFrame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);    
    xf86UDelay(50000);
    return TRUE;
}

/* Mandatory */
static void
CHIPSLeaveVT(int scrnIndex, int flags)
{
    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
    CHIPSPtr cPtr = CHIPSPTR(pScrn);
    CHIPSACLPtr cAcl = CHIPSACLPTR(pScrn);
    CHIPSEntPtr cPtrEnt;

    /* Invalidate the cached acceleration registers */
    cAcl->planemask = -1;
    cAcl->fgColor = -1;
    cAcl->bgColor = -1;

    if (cPtr->Flags & ChipsDualChannelSupport) {
        cPtrEnt = xf86GetEntityPrivate(pScrn->entityList[0],
				       CHIPSEntityIndex)->ptr;
	if (cPtr->UseDualChannel)
	    DUALREOPEN;
       	DUALCLOSE;
    } else {
	chipsHWCursorOff(cPtr, pScrn);
	chipsRestore(pScrn, &(VGAHWPTR(pScrn))->SavedReg, &cPtr->SavedReg,
					TRUE);
	chipsLock(pScrn);
    }
}


static void
chipsLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO *colors,
		 VisualPtr pVisual)
{
    vgaHWPtr hwp = VGAHWPTR(pScrn);
    CHIPSPtr cPtr = CHIPSPTR(pScrn);
    int i, index, shift ;
    CHIPSEntPtr cPtrEnt;    

    shift = ((pScrn->depth == 15) && 
	     (!(cPtr->Flags & ChipsOverlay8plus16))) ? 3 : 0;

    if (cPtr->UseDualChannel) {
        cPtrEnt = xf86GetEntityPrivate(pScrn->entityList[0],
					       CHIPSEntityIndex)->ptr;
	DUALREOPEN;
    }

    for (i = 0; i < numColors; i++) {
	index = indices[i];
	hwp->writeDacWriteAddr(hwp,index << shift);
	DACDelay(hwp);
	hwp->writeDacData(hwp, colors[index].red);
	DACDelay(hwp);
	hwp->writeDacData(hwp, colors[index].green);
	DACDelay(hwp);
	hwp->writeDacData(hwp, colors[index].blue);
	DACDelay(hwp);
    }

    if (cPtr->UseDualChannel && 
		(! xf86IsEntityShared(pScrn->entityList[0]))) {
	unsigned int IOSS, MSS;
	IOSS = cPtr->readIOSS(cPtr);
	MSS = cPtr->readMSS(cPtr);
	cPtr->writeIOSS(cPtr, ((cPtr->storeIOSS & IOSS_MASK) |
			       IOSS_PIPE_B));
	cPtr->writeMSS(cPtr, hwp, ((cPtr->storeMSS & MSS_MASK) | MSS_PIPE_B));

	for (i = 0; i < numColors; i++) {
	    index = indices[i];
	    hwp->writeDacWriteAddr(hwp,index << shift);
	    DACDelay(hwp);
	    hwp->writeDacData(hwp, colors[index].red);
	    DACDelay(hwp);
	    hwp->writeDacData(hwp, colors[index].green);
	    DACDelay(hwp);
	    hwp->writeDacData(hwp, colors[index].blue);
	    DACDelay(hwp);
	}
	cPtr->writeIOSS(cPtr, IOSS);
	cPtr->writeMSS(cPtr, hwp, MSS);
    }
    
    /* This shouldn't be necessary, but we'll play safe. */
    hwp->disablePalette(hwp);
}

static void
chipsLoadPalette16(ScrnInfoPtr pScrn, int numColors, int *indices,
		 LOCO *colors, VisualPtr pVisual)
{
    vgaHWPtr hwp = VGAHWPTR(pScrn);
    CHIPSPtr cPtr = CHIPSPTR(pScrn);
    CHIPSEntPtr cPtrEnt;

    int i, index;

    if (cPtr->UseDualChannel) {
        cPtrEnt = xf86GetEntityPrivate(pScrn->entityList[0],
					       CHIPSEntityIndex)->ptr;
	DUALREOPEN;
    }
    
    for (i = 0; i < numColors; i++) {
	index = indices[i];
	hwp->writeDacWriteAddr(hwp, index << 2);
	DACDelay(hwp);
	hwp->writeDacData(hwp, colors[index >> 1].red);
	DACDelay(hwp);
	hwp->writeDacData(hwp, colors[index].green);
	DACDelay(hwp);
	hwp->writeDacData(hwp, colors[index >> 1].blue);
	DACDelay(hwp);
    }


    if (cPtr->UseDualChannel &&
		(! xf86IsEntityShared(pScrn->entityList[0]))) {
	unsigned int IOSS, MSS;
	IOSS = cPtr->readIOSS(cPtr);
	MSS = cPtr->readMSS(cPtr);
	cPtr->writeIOSS(cPtr, ((cPtr->storeIOSS & IOSS_MASK) |
			       IOSS_PIPE_B));
	cPtr->writeMSS(cPtr, hwp, ((cPtr->storeMSS & MSS_MASK) | MSS_PIPE_B));

	for (i = 0; i < numColors; i++) {
	    index = indices[i];
	    hwp->writeDacWriteAddr(hwp, index << 2);
	    DACDelay(hwp);
	    hwp->writeDacData(hwp, colors[index >> 1].red);
	    DACDelay(hwp);
	    hwp->writeDacData(hwp, colors[index].green);
	    DACDelay(hwp);
	    hwp->writeDacData(hwp, colors[index >> 1].blue);
	    DACDelay(hwp);
	}

	cPtr->writeIOSS(cPtr, IOSS);
	cPtr->writeMSS(cPtr, hwp, MSS);
    }

    /* This shouldn't be necessary, but we'll play safe. */
    hwp->disablePalette(hwp);
}

/* Mandatory */
static Bool
CHIPSScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
{
    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
    vgaHWPtr hwp;
    CHIPSPtr cPtr;
    CHIPSACLPtr cAcl;
    int ret;
    int init_picture = 0;
    VisualPtr visual;
    int allocatebase, freespace, currentaddr;
    unsigned int racflag = 0;
    unsigned char *FBStart;
    int height, width, displayWidth;
    CHIPSEntPtr cPtrEnt = NULL;
#ifdef DEBUG
    ErrorF("CHIPSScreenInit\n");
#endif    

    /*
     * we need to get the ScrnInfoRec for this screen, so let's allocate
     * one first thing
     */
    cPtr = CHIPSPTR(pScrn);
    cAcl = CHIPSACLPTR(pScrn);

    hwp = VGAHWPTR(pScrn);
    hwp->MapSize = 0x10000;		/* Standard 64k VGA window */

    /* Map the VGA memory */
    if (!vgaHWMapMem(pScrn))
	return FALSE;

    /* Map the Chips memory and possible MMIO areas */
    if (!chipsMapMem(pScrn))
	return FALSE;

    /* Setup a pointer to the overlay if needed */
    if (cPtr->Flags & ChipsOverlay8plus16) {
	cPtr->FbOffset16 = pScrn->displayWidth * pScrn->virtualY;
	cPtr->FbSize16 =  (pScrn->displayWidth << 1) * pScrn->virtualY;
	if (cPtr->FbSize16 > (cPtr->FbMapSize - cPtr->FrameBufferSize)) {
	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
		   "Too little memory for overlay. Disabling.\n");
	    cPtr->Flags &= ~ChipsOverlay8plus16;
	}
	if ((pScrn->displayWidth > 1024) || (pScrn->virtualY > 1024)) {
	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
		   "Max overlay Width/Height 1024 pixels. Disabling.\n");
	    cPtr->Flags &= ~ChipsOverlay8plus16;
	}
    }

    /* Setup the MMIO register access functions if need */
    if (cPtr->UseFullMMIO && cPtr->MMIOBaseVGA) {
	CHIPSSetMmioExtFuncs(cPtr);
	CHIPSHWSetMmioFuncs(pScrn, cPtr->MMIOBaseVGA, 0x0);
    }

    if (cPtr->Flags & ChipsDualChannelSupport) {
        cPtrEnt = xf86GetEntityPrivate(pScrn->entityList[0],
					       CHIPSEntityIndex)->ptr;
	DUALOPEN;
    }

#if defined(__arm32__) && defined(__NetBSD__)
    if (strcmp(pScrn->currentMode->name,"PAL") == 0) {
	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Using built-in PAL TV mode\n");
	cPtr->TVMode = XMODE_PAL;
    } else if (strcmp(pScrn->currentMode->name,"SECAM") == 0){
	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
		   "Using built-in SECAM TV mode\n");
	cPtr->TVMode = XMODE_SECAM;
    } else if (strcmp(pScrn->currentMode->name,"NTSC") == 0) {
	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
		   "Using built-in NTSC TV mode\n");
	cPtr->TVMode = XMODE_NTSC;
    } else 
	cPtr->TVMode = XMODE_RGB;
#endif

    /*
     * next we save the current state and setup the first mode
     */
    if ((cPtr->Flags & ChipsDualChannelSupport) && 
		(! xf86IsEntityShared(pScrn->entityList[0]))) {
	unsigned int IOSS, MSS;
	IOSS = cPtr->readIOSS(cPtr);
	MSS = cPtr->readMSS(cPtr);
	cPtr->writeIOSS(cPtr, ((cPtr->storeIOSS & IOSS_MASK) |
					IOSS_PIPE_A));
	cPtr->writeMSS(cPtr, hwp, ((cPtr->storeMSS & MSS_MASK) | MSS_PIPE_A));
	chipsSave(pScrn, &hwp->SavedReg, &cPtr->SavedReg);
	cPtr->writeIOSS(cPtr, ((cPtr->storeIOSS & IOSS_MASK) |
			       IOSS_PIPE_B));
	cPtr->writeMSS(cPtr, hwp, ((cPtr->storeMSS & MSS_MASK) | MSS_PIPE_B));
	chipsSave(pScrn, &cPtr->VgaSavedReg2, &cPtr->SavedReg2);
	cPtr->writeIOSS(cPtr, IOSS);
	cPtr->writeMSS(cPtr, hwp, MSS);
    } else
	chipsSave(pScrn, &hwp->SavedReg, &cPtr->SavedReg);

    if (!chipsModeInit(pScrn,pScrn->currentMode))
	return FALSE;
    CHIPSSaveScreen(pScreen,SCREEN_SAVER_ON);
    CHIPSAdjustFrame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
    
    /*
     * The next step is to setup the screen's visuals, and initialise the
     * framebuffer code.  In cases where the framebuffer's default
     * choices for things like visual layouts and bits per RGB are OK,
     * this may be as simple as calling the framebuffer's ScreenInit()
     * function.  If not, the visuals will need to be setup before calling
     * a fb ScreenInit() function and fixed up after.
     *
     * For most PC hardware at depths >= 8, the defaults that fb uses
     * are not appropriate.  In this driver, we fixup the visuals after.
     */

    /*
     * Reset visual list.
     */
    miClearVisualTypes();

    /* Setup the visuals we support. */
    if ((pScrn->bitsPerPixel == 16) && (cPtr->Flags & ChipsOverlay8plus16)){
	if (!miSetVisualTypes(8, PseudoColorMask | GrayScaleMask,
			      pScrn->rgbBits, PseudoColor))
		return FALSE;
	if (!miSetVisualTypes(16, TrueColorMask, pScrn->rgbBits, TrueColor))
		return FALSE;
    } else {
      if (!miSetVisualTypes(pScrn->depth,
			    miGetDefaultVisualMask(pScrn->depth),
			    pScrn->rgbBits, pScrn->defaultVisual))
	return FALSE;
    }
    miSetPixmapDepths ();

    /*
     * Call the framebuffer layer's ScreenInit function, and fill in other
     * pScreen fields.
     */
    if ((cPtr->Flags & ChipsShadowFB) && cPtr->Rotate) {
	height = pScrn->virtualX;
	width = pScrn->virtualY;
    } else {
	width = pScrn->virtualX;
	height = pScrn->virtualY;
    }

    if(cPtr->Flags & ChipsShadowFB) {
	cPtr->ShadowPitch = BitmapBytePad(pScrn->bitsPerPixel * width);
	cPtr->ShadowPtr = xalloc(cPtr->ShadowPitch * height);
	displayWidth = cPtr->ShadowPitch / (pScrn->bitsPerPixel >> 3);
	FBStart = cPtr->ShadowPtr;
    } else {
	cPtr->ShadowPtr = NULL;
	displayWidth = pScrn->displayWidth;
	FBStart = cPtr->FbBase;
    }

    switch (pScrn->bitsPerPixel) {
    case 1:
	ret = xf1bppScreenInit(pScreen, FBStart,
 		        width,height,
			pScrn->xDpi, pScrn->yDpi,
			displayWidth);
	break;
    case 4:
	ret = xf4bppScreenInit(pScreen, FBStart,
 		        width,height,
			pScrn->xDpi, pScrn->yDpi,
			displayWidth);
	break;
    case 16:
      if (cPtr->Flags & ChipsOverlay8plus16) {
	  ret = cfb8_16ScreenInit(pScreen, (unsigned char *)FBStart + 
				  cPtr->FbOffset16, FBStart, width, 
				  height, pScrn->xDpi, pScrn->yDpi,
				  displayWidth, displayWidth);
	  break;
      }
    default:
	ret = fbScreenInit(pScreen, FBStart,
 		        width,height,
			pScrn->xDpi, pScrn->yDpi,
			displayWidth,pScrn->bitsPerPixel);
	init_picture = 1;
	break;
    }

    if (!ret)
	return FALSE;

    if (pScrn->depth > 8) {
        /* Fixup RGB ordering */
        visual = pScreen->visuals + pScreen->numVisuals;
        while (--visual >= pScreen->visuals) {
	    if ((visual->class | DynamicClass) == DirectColor) {
		visual->offsetRed = pScrn->offset.red;
		visual->offsetGreen = pScrn->offset.green;
		visual->offsetBlue = pScrn->offset.blue;
		visual->redMask = pScrn->mask.red;
		visual->greenMask = pScrn->mask.green;
		visual->blueMask = pScrn->mask.blue;
	    }
	}
    }

    /* must be after RGB ordering fixed */
    if (init_picture)
	fbPictureInit (pScreen, 0, 0);
    
    xf86SetBlackWhitePixels(pScreen);

    cPtr->BlockHandler = pScreen->BlockHandler;
    pScreen->BlockHandler = chipsBlockHandler;

    if ( (pScrn->depth >= 8))
	CHIPSDGAInit(pScreen);

    cPtr->HWCursorShown = FALSE;

    if (!(cPtr->Flags & ChipsLinearSupport)) {
	miBankInfoPtr pBankInfo;

	/* Setup the vga banking variables */
	pBankInfo = (miBankInfoPtr)xnfcalloc(sizeof(miBankInfoRec),1);
	if (pBankInfo == NULL)
	    return FALSE;
	
#if defined(__arm32__)
	cPtr->Bank = -1;
#endif
	pBankInfo->pBankA = hwp->Base;
	pBankInfo->pBankB = (unsigned char *)hwp->Base + 0x08000;
	pBankInfo->BankSize = 0x08000;
	pBankInfo->nBankDepth = (pScrn->depth == 4) ? 1 : pScrn->depth;

	if (IS_HiQV(cPtr)) {
	    pBankInfo->pBankB = hwp->Base;
	    pBankInfo->BankSize = 0x10000;
	    if (pScrn->bitsPerPixel < 8) {
		pBankInfo->SetSourceBank =
			(miBankProcPtr)CHIPSHiQVSetReadWritePlanar;
		pBankInfo->SetDestinationBank =
			(miBankProcPtr)CHIPSHiQVSetReadWritePlanar;
		pBankInfo->SetSourceAndDestinationBanks =
			(miBankProcPtr)CHIPSHiQVSetReadWritePlanar;
	    } else {
		pBankInfo->SetSourceBank =
			(miBankProcPtr)CHIPSHiQVSetReadWrite;
		pBankInfo->SetDestinationBank =
			(miBankProcPtr)CHIPSHiQVSetReadWrite;
		pBankInfo->SetSourceAndDestinationBanks =
			(miBankProcPtr)CHIPSHiQVSetReadWrite;
	    }
	} else {
	    if (IS_Wingine(cPtr)) {
		if (pScrn->bitsPerPixel < 8) {
		    pBankInfo->SetSourceBank =
			    (miBankProcPtr)CHIPSWINSetReadPlanar;
		    pBankInfo->SetDestinationBank =
			    (miBankProcPtr)CHIPSWINSetWritePlanar;
		    pBankInfo->SetSourceAndDestinationBanks =
			    (miBankProcPtr)CHIPSWINSetReadWritePlanar;
		} else {
		    pBankInfo->SetSourceBank = (miBankProcPtr)CHIPSWINSetRead;
		    pBankInfo->SetDestinationBank =
			    (miBankProcPtr)CHIPSWINSetWrite;
		    pBankInfo->SetSourceAndDestinationBanks =
			    (miBankProcPtr)CHIPSWINSetReadWrite;
		}
	    } else {
		if (pScrn->bitsPerPixel < 8) {
		    pBankInfo->SetSourceBank =
			    (miBankProcPtr)CHIPSSetReadPlanar;
		    pBankInfo->SetDestinationBank =
			    (miBankProcPtr)CHIPSSetWritePlanar;
		    pBankInfo->SetSourceAndDestinationBanks =
			    (miBankProcPtr)CHIPSSetReadWritePlanar;
		} else {
		    pBankInfo->SetSourceBank = (miBankProcPtr)CHIPSSetRead;
		    pBankInfo->SetDestinationBank =
			    (miBankProcPtr)CHIPSSetWrite;
		    pBankInfo->SetSourceAndDestinationBanks =
			    (miBankProcPtr)CHIPSSetReadWrite;
		}
	    }
	}
	if (!miInitializeBanking(pScreen, pScrn->virtualX, pScrn->virtualY,
				 pScrn->displayWidth, pBankInfo)) {
	    xfree(pBankInfo);
	    pBankInfo = NULL;
	    return FALSE;
	}
	miInitializeBackingStore(pScreen);
	xf86SetBackingStore(pScreen);

	/* Initialise cursor functions */
	miDCInitialize (pScreen, xf86GetPointerScreenFuncs());

    } else {
    /* !!! Only support linear addressing for now. This might change */
	/* Setup pointers to free space in video ram */
#define CHIPSALIGN(size, align) (currentaddr - ((currentaddr - size) & ~align))
	allocatebase = (pScrn->videoRam<<10) - cPtr->FrameBufferSize;
	
	if (pScrn->bitsPerPixel < 8)
	    freespace = allocatebase - pScrn->displayWidth * 
		    pScrn->virtualY / 2;
	else if ((pScrn->bitsPerPixel == 16) && (cPtr->Flags & ChipsOverlay8plus16))
	    freespace = allocatebase - pScrn->displayWidth * 
		    pScrn->virtualY - cPtr->FbSize16;
	else	
	    freespace = allocatebase - pScrn->displayWidth * 
		    pScrn->virtualY * (pScrn->bitsPerPixel >> 3);

	if ((cPtr->Flags & ChipsDualChannelSupport) && 
	    (cPtr->SecondCrtc == TRUE)) {
	    currentaddr = allocatebase + cPtrEnt->masterFbMapSize;
	} else
	    currentaddr = allocatebase;
	if (serverGeneration == 1)
	    xf86DrvMsg(scrnIndex, X_PROBED,
		   "%d bytes off-screen memory available\n", freespace);

	/* 
	 * Allocate video memory to store the hardware cursor. Allocate 1kB
	 * vram to the cursor, with 1kB alignment for 6554x's and 4kb alignment
	 * for 65550's. Wingine cursor is stored in registers and so no memory
	 * is needed.
	 */
	if (cAcl->UseHWCursor) {
	    cAcl->CursorAddress = -1;
	    if (IS_HiQV(cPtr)) {
		if (CHIPSALIGN(1024, 0xFFF) <= freespace) {
		    currentaddr -= CHIPSALIGN(1024, 0xFFF);
		    freespace -= CHIPSALIGN(1024, 0xFFF);
		    cAcl->CursorAddress = currentaddr;
		}
	    } else if (IS_Wingine(cPtr)) {
		cAcl->CursorAddress = 0;
	    } else if (CHIPSALIGN(1024, 0x3FF) <= freespace) {
		currentaddr -= CHIPSALIGN(1024, 0x3FF);
		freespace -= CHIPSALIGN(1024, 0x3FF);
		cAcl->CursorAddress = currentaddr;
	    }
	    if (cAcl->CursorAddress == -1)
		xf86DrvMsg(scrnIndex, X_ERROR,
		       "Too little space for H/W cursor.\n");
	}
    
	cAcl->CacheEnd = currentaddr;

	/* Setup the acceleration primitives */
	/* Calculate space needed of offscreen pixmaps etc. */
	if (cPtr->Flags & ChipsAccelSupport) {
	    /* 
	     * A scratch area is now allocated in the video ram. This is used
	     * at 8 and 16 bpp to simulate a planemask with a complex ROP, and 
	     * at 24 and 32 bpp to aid in accelerating solid fills
	     */
	    cAcl->ScratchAddress = -1;
	    switch  (pScrn->bitsPerPixel) {
	    case 8:
		if (CHIPSALIGN(64, 0x3F) <= freespace) {
		    currentaddr -= CHIPSALIGN(64, 0x3F);
		    freespace -= CHIPSALIGN(64, 0x3F);
		    cAcl->ScratchAddress = currentaddr;
		}
		break;
	    case 16:
		if (CHIPSALIGN(128, 0x7F) <= freespace) {
		    currentaddr -= CHIPSALIGN(128, 0x7F);
		    freespace -= CHIPSALIGN(128, 0x7F);
		    cAcl->ScratchAddress = currentaddr;
		}
		break;
	    case 24:
		/* One scanline of data used for solid fill */
		if (!IS_HiQV(cPtr)) {
		    if (CHIPSALIGN(3 * (pScrn->displayWidth + 4), 0x3)
			<= freespace) {
			currentaddr -= CHIPSALIGN(3 * (pScrn->displayWidth
					       + 4), 0x3);
			freespace -= CHIPSALIGN(3 * (pScrn->displayWidth + 4),
						0x3);
			cAcl->ScratchAddress = currentaddr;
		    }
		}
		break;
	    case 32:
		/* 16bpp 8x8 mono pattern fill for solid fill. QWORD aligned */
		if (IS_HiQV(cPtr)) {
		    if (CHIPSALIGN(8, 0x7) <= freespace) {
			currentaddr -= CHIPSALIGN(8, 0x7);
			freespace -= CHIPSALIGN(8, 0x7);
			cAcl->ScratchAddress = currentaddr;
		    }
		}
		break;
	    }

	    /* Setup the boundaries of the pixmap cache */
	    cAcl->CacheStart = currentaddr - freespace;
	    cAcl->CacheEnd = currentaddr;

	    if (cAcl->CacheStart >= cAcl->CacheEnd) {
		xf86DrvMsg(scrnIndex, X_ERROR,
		       "Too little space for pixmap cache.\n");
		cAcl->CacheStart = 0;
		cAcl->CacheEnd = 0;
	    }

	    if (IS_HiQV(cPtr)) 
		cAcl->BltDataWindow = (unsigned char *)cPtr->MMIOBase
		    + 0x10000L;
	    else
		cAcl->BltDataWindow = cPtr->FbBase;
	    
	}
	/*
	 * Initialize FBManager: 
	 * we do even with no acceleration enabled
	 * so that video support can allocate space.
	 */
	   
	{
	    BoxRec AvailFBArea;
	    AvailFBArea.x1 = 0;
	    AvailFBArea.y1 = 0;
	    AvailFBArea.x2 = pScrn->displayWidth;
	    AvailFBArea.y2 = cAcl->CacheEnd /
		(pScrn->displayWidth * (pScrn->bitsPerPixel >> 3));

	    if (!(cPtr->Flags & ChipsOverlay8plus16)) {     
		xf86InitFBManager(pScreen, &AvailFBArea); 
	    }
	}
	if (cPtr->Flags & ChipsAccelSupport) {
	    if (IS_HiQV(cPtr)) {
		CHIPSHiQVAccelInit(pScreen);
	    } else if (cPtr->UseMMIO) {
		CHIPSMMIOAccelInit(pScreen);
	    } else {
		CHIPSAccelInit(pScreen);
	    }
	}
	
	miInitializeBackingStore(pScreen);
	xf86SetBackingStore(pScreen);
#ifdef ENABLE_SILKEN_MOUSE
	xf86SetSilkenMouse(pScreen);
#endif

	/* Initialise cursor functions */
	miDCInitialize (pScreen, xf86GetPointerScreenFuncs());

	if ((cAcl->UseHWCursor) && (cAcl->CursorAddress != -1)) {
	    /* HW cursor functions */
	    if (!CHIPSCursorInit(pScreen)) {
		xf86DrvMsg(scrnIndex, X_ERROR,
		       "Hardware cursor initialization failed\n");
		return FALSE;
	    }
	}
    }

    if (cPtr->Flags & ChipsShadowFB) {
	RefreshAreaFuncPtr refreshArea = chipsRefreshArea;

	if(cPtr->Rotate) {
	    if (!cPtr->PointerMoved) {
		cPtr->PointerMoved = pScrn->PointerMoved;
		pScrn->PointerMoved = chipsPointerMoved;
	    }
	    
	   switch(pScrn->bitsPerPixel) {
	   case 8:	refreshArea = chipsRefreshArea8;	break;
	   case 16:	refreshArea = chipsRefreshArea16;	break;
	   case 24:	refreshArea = chipsRefreshArea24;	break;
	   case 32:	refreshArea = chipsRefreshArea32;	break;
	   }
	}
	ShadowFBInit(pScreen, refreshArea);
    }
	
    /* Initialise default colourmap */
    if (!miCreateDefColormap(pScreen))
	return FALSE;
    
    if ((cPtr->Flags & ChipsOverlay8plus16) && (pScrn->bitsPerPixel == 16)) {
	if(!xf86HandleColormaps(pScreen, 256, pScrn->rgbBits, chipsLoadPalette,
		NULL, CMAP_RELOAD_ON_MODE_SWITCH))
	    return FALSE;
    } else {
	if(!xf86HandleColormaps(pScreen, 256, pScrn->rgbBits,
		(pScrn->depth == 16 ? chipsLoadPalette16 : chipsLoadPalette),
		NULL, CMAP_RELOAD_ON_MODE_SWITCH | CMAP_PALETTED_TRUECOLOR))
	    return FALSE;
    }
    
    racflag = RAC_COLORMAP;
    if (cAcl->UseHWCursor)
        racflag |= RAC_CURSOR;
    racflag |= (RAC_FB | RAC_VIEWPORT);
    /* XXX Check if I/O and Mem flags need to be the same. */
    pScrn->racIoFlags = pScrn->racMemFlags = racflag;
#ifdef ENABLE_SILKEN_MOUSE
	xf86SetSilkenMouse(pScreen);
#endif

	if ((!(cPtr->Flags & ChipsOverlay8plus16)) 
	    && (cPtr->Flags & ChipsVideoSupport)
	    && (cPtr->Flags & ChipsLinearSupport)) {
	    CHIPSInitVideo(pScreen);
    }

    pScreen->SaveScreen = CHIPSSaveScreen;

    /* Setup DPMS mode */
    if (cPtr->Flags & ChipsDPMSSupport)
	xf86DPMSInit(pScreen, (DPMSSetProcPtr)chipsDisplayPowerManagementSet,
		     0);

#if 0 /* #### Shouldn't be needed */
    /* Dual head, needs to fix framebuffer memory address */
    if ((cPtr->Flags & ChipsDualChannelSupport) &&
        (cPtr->SecondCrtc == TRUE))
	pScrn->memPhysBase = cPtr->FbAddress + cPtrEnt->masterFbMapSize;
#endif

    /* Wrap the current CloseScreen function */
    cPtr->CloseScreen = pScreen->CloseScreen;
    pScreen->CloseScreen = CHIPSCloseScreen;

    /* Report any unused options (only for the first generation) */
    if (serverGeneration == 1) {
	xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
    }

    return TRUE;
}

/* Mandatory */
Bool
CHIPSSwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
{
    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
    CHIPSPtr cPtr = CHIPSPTR(pScrn);
    CHIPSEntPtr cPtrEnt;

#ifdef DEBUG
    ErrorF("CHIPSSwitchMode\n");
#endif
    if (cPtr->UseDualChannel) {
        cPtrEnt = xf86GetEntityPrivate(pScrn->entityList[0],
					       CHIPSEntityIndex)->ptr;
	DUALREOPEN;
    }

    return chipsModeInit(xf86Screens[scrnIndex], mode);
}

/* Mandatory */
void
CHIPSAdjustFrame(int scrnIndex, int x, int y, int flags)
{
    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
    CHIPSPtr cPtr = CHIPSPTR(pScrn);
    CHIPSEntPtr cPtrEnt;

    int Base;
    vgaHWPtr hwp = VGAHWPTR(pScrn);
    unsigned char tmp;

    if (xf86ReturnOptValBool(cPtr->Options, OPTION_SHOWCACHE, FALSE) && y) {
	int lastline = cPtr->FbMapSize / 
		((pScrn->displayWidth * pScrn->bitsPerPixel) / 8);
	lastline -= pScrn->currentMode->VDisplay;
	y += pScrn->virtualY - 1;
        if (y > lastline) y = lastline;
    }
    
    Base = y * pScrn->displayWidth + x;
    
    /* calculate base bpp dep. */
    switch (pScrn->bitsPerPixel) {
    case 1:
    case 4:
	Base >>= 3;
	break;
    case 16:
	if (!(cPtr->Flags & ChipsOverlay8plus16))
	   Base >>= 1;
	else
	   Base >>= 2;
	break;
    case 24:
	if (!IS_HiQV(cPtr))
	    Base = (Base >> 2) * 3;
	else
	    Base = (Base >> 3) * 6;  /* 65550 seems to need 64bit alignment */
	break;
    case 32:
	break;
    default:			     /* 8bpp */
	Base >>= 2;
	break;
    }

    if (cPtr->UseDualChannel) {
        cPtrEnt = xf86GetEntityPrivate(pScrn->entityList[0],
					       CHIPSEntityIndex)->ptr;
	DUALREOPEN;
    }

    /* write base to chip */
    /*
     * These are the generic starting address registers.
     */
    chipsFixResume(pScrn);
    hwp->writeCrtc(hwp, 0x0C, (Base & 0xFF00) >> 8);
    hwp->writeCrtc(hwp, 0x0D, Base & 0xFF);
    if (IS_HiQV(cPtr)) {
	if (((cPtr->readXR(cPtr, 0x09)) & 0x1) == 0x1)
	    hwp->writeCrtc(hwp, 0x40, ((Base & 0x0F0000) >> 16) | 0x80);
    } else {
	tmp = cPtr->readXR(cPtr, 0x0C);
	cPtr->writeXR(cPtr, 0x0C, ((Base & (IS_Wingine(cPtr) ? 0x0F0000 : 
	     0x030000)) >> 16) | (tmp & 0xF8));
    }

    if (cPtr->UseDualChannel &&
		(! xf86IsEntityShared(pScrn->entityList[0]))) {
	unsigned int IOSS, MSS;
	IOSS = cPtr->readIOSS(cPtr);
	MSS = cPtr->readMSS(cPtr);
	cPtr->writeIOSS(cPtr, ((cPtr->storeIOSS & IOSS_MASK) |
			       IOSS_PIPE_B));
	cPtr->writeMSS(cPtr, hwp, ((cPtr->storeMSS & MSS_MASK) | MSS_PIPE_B));

	chipsFixResume(pScrn);
	hwp->writeCrtc(hwp, 0x0C, (Base & 0xFF00) >> 8);
	hwp->writeCrtc(hwp, 0x0D, Base & 0xFF);
	if (((cPtr->readXR(cPtr, 0x09)) & 0x1) == 0x1)
	    hwp->writeCrtc(hwp, 0x40, ((Base & 0x0F0000) >> 16) | 0x80);

	cPtr->writeIOSS(cPtr, IOSS);
	cPtr->writeMSS(cPtr, hwp, MSS);
    }

    if (cPtr->Flags & ChipsOverlay8plus16) {
	Base = (Base << 3) & ~(unsigned long)0xF;

	cPtr->writeMR(cPtr, 0x22, (cPtr->FbOffset16 + Base) & 0xF8);
	cPtr->writeMR(cPtr, 0x23, ((cPtr->FbOffset16 + Base) >> 8) & 0xFF);
	cPtr->writeMR(cPtr, 0x24, ((cPtr->FbOffset16 + Base) >> 16) & 0xFF);
    }

}

/* Mandatory */
static Bool
CHIPSCloseScreen(int scrnIndex, ScreenPtr pScreen)
{
    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
    CHIPSPtr cPtr = CHIPSPTR(pScrn);
    CHIPSEntPtr cPtrEnt;    

    if(pScrn->vtSema){   /*§§§*/
	if (cPtr->Flags & ChipsDualChannelSupport) {
  	    cPtrEnt = xf86GetEntityPrivate(pScrn->entityList[0],
					   CHIPSEntityIndex)->ptr;
	    if (cPtr->UseDualChannel)
		DUALREOPEN;
	    DUALCLOSE;
	} else {
	    chipsHWCursorOff(cPtr, pScrn);
	    chipsRestore(pScrn, &(VGAHWPTR(pScrn))->SavedReg, &cPtr->SavedReg,
					TRUE);
	    chipsLock(pScrn);
	}
	chipsUnmapMem(pScrn);
    }

    if (xf86IsEntityShared(pScrn->entityList[0])) {
	DevUnion *pPriv;
	pPriv = xf86GetEntityPrivate(pScrn->entityList[0], CHIPSEntityIndex);
	cPtrEnt = pPriv->ptr;
	cPtrEnt->refCount--;
    }
    if (cPtr->AccelInfoRec)
	XAADestroyInfoRec(cPtr->AccelInfoRec);
    if (cPtr->CursorInfoRec)
	xf86DestroyCursorInfoRec(cPtr->CursorInfoRec);
    if (cPtr->ShadowPtr)
	xfree(cPtr->ShadowPtr);
    if (cPtr->DGAModes)
	xfree(cPtr->DGAModes);
    pScrn->vtSema = FALSE;
    if(cPtr->BlockHandler)
	pScreen->BlockHandler = cPtr->BlockHandler;

    pScreen->CloseScreen = cPtr->CloseScreen; /*§§§*/
    xf86ClearPrimInitDone(pScrn->entityList[0]);
    return (*pScreen->CloseScreen)(scrnIndex, pScreen);/*§§§*/
}

/* Optional */
static void
CHIPSFreeScreen(int scrnIndex, int flags)
{
    if (xf86LoaderCheckSymbol("vgaHWFreeHWRec"))
	vgaHWFreeHWRec(xf86Screens[scrnIndex]);
    CHIPSFreeRec(xf86Screens[scrnIndex]);
}

/* Optional */
static ModeStatus
CHIPSValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags)
{
    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
    CHIPSPtr cPtr = CHIPSPTR(pScrn);

    if (flags & MODECHECK_FINAL) {
    /* Don't subtract FrambufferSize here as it should be subtracted already */
    if ((cPtr->Flags & ChipsOverlay8plus16) 
      && ((pScrn->videoRam<<10) - pScrn->displayWidth * 3 * pScrn->virtualY 
	  < 0))
	return MODE_MEM;
    }
    /* The tests here need to be expanded */
    if ((mode->Flags & V_INTERLACE) && (cPtr->PanelType & ChipsLCD))
	return MODE_NO_INTERLACE;
    if ((cPtr->PanelType & ChipsLCD)
	&& !xf86ReturnOptValBool(cPtr->Options, OPTION_PANEL_SIZE, FALSE)
	&& ((cPtr->PanelSize.HDisplay < mode->HDisplay)
	    || (cPtr->PanelSize.VDisplay < mode->VDisplay)))
      return MODE_PANEL;

    return MODE_OK;
}

/*
 * DPMS Control registers
 *
 * XR73 6554x and 64300 (what about 65535?)
 * XR61 6555x
 *    0   HSync Powerdown data
 *    1   HSync Select 1=Powerdown
 *    2   VSync Powerdown data
 *    3   VSync Select 1=Powerdown
 */

static void
chipsDisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode,
			       int flags)
{
    vgaHWPtr hwp = VGAHWPTR(pScrn);
    CHIPSPtr cPtr = CHIPSPTR(pScrn);
    CHIPSEntPtr cPtrEnt;

    unsigned char dpmsreg, seqreg, lcdoff, tmp;
    
    if (!pScrn->vtSema)
	return;

    xf86EnableAccess(pScrn);
    switch (PowerManagementMode) {
    case DPMSModeOn:
	/* Screen: On; HSync: On, VSync: On */
	dpmsreg = 0x00;
	seqreg = 0x00;
	lcdoff = 0x0;
	break;
    case DPMSModeStandby:
	/* Screen: Off; HSync: Off, VSync: On */
	dpmsreg = 0x02;
	seqreg = 0x20;
	lcdoff = 0x0;
	break;
    case DPMSModeSuspend:
	/* Screen: Off; HSync: On, VSync: Off */
	dpmsreg = 0x08;
	seqreg = 0x20;
	lcdoff = 0x1;
	break;
    case DPMSModeOff:
	/* Screen: Off; HSync: Off, VSync: Off */
	dpmsreg = 0x0A;
	seqreg = 0x20;
	lcdoff = 0x1;
	break;
    default:
	return;
    }

    if (cPtr->UseDualChannel) {
        cPtrEnt = xf86GetEntityPrivate(pScrn->entityList[0],
					       CHIPSEntityIndex)->ptr;
	DUALREOPEN;
    }

    seqreg |= hwp->readSeq(hwp, 0x01) & ~0x20;
    hwp->writeSeq(hwp, 0x01, seqreg);
    if (IS_HiQV(cPtr)) {
	tmp = cPtr->readXR(cPtr, 0x61);
	cPtr->writeXR(cPtr, 0x61, (tmp & 0xF0) | dpmsreg);
    } else {
	tmp = cPtr->readXR(cPtr, 0x73);
	cPtr->writeXR(cPtr, 0x73, (tmp & 0xF0) | dpmsreg);
    }
    
    /* Turn off the flat panel */
    if (cPtr->PanelType & ChipsLCDProbed) {
	if (IS_HiQV(cPtr)) {
	    if (cPtr->Chipset == CHIPS_CT69030) {
#if 0
	        /* Where is this for the 69030?? */
		tmp = cPtr->readFR(cPtr, 0x05);
		if (lcdoff)
		    cPtr->writeFR(cPtr, 0x05, tmp | 0x08);
		else
		    cPtr->writeFR(cPtr, 0x05, tmp & 0xF7);
#endif
	    } else {
		tmp = cPtr->readFR(cPtr, 0x05);
		if (lcdoff)
		    cPtr->writeFR(cPtr, 0x05, tmp | 0x08);
		else
		    cPtr->writeFR(cPtr, 0x05, tmp & 0xF7);
	    }
	} else {
	    tmp = cPtr->readXR(cPtr, 0x52);
	    if (lcdoff)
		cPtr->writeXR(cPtr, 0x52, tmp | 0x08);
	    else
		cPtr->writeXR(cPtr, 0x52, tmp & 0xF7);
	}
    }
}

static Bool
CHIPSSaveScreen(ScreenPtr pScreen, int mode)
{
    ScrnInfoPtr pScrn = NULL;            /* §§§ */
    Bool unblank;

    unblank = xf86IsUnblank(mode);

    if (pScreen != NULL)
	pScrn = xf86Screens[pScreen->myNum];

    if (unblank)
	SetTimeSinceLastInputEvent();

    if ((pScrn != NULL) && pScrn->vtSema) { /* §§§ */
	chipsBlankScreen(pScrn, unblank);
    }
    return (TRUE);
}

static Bool
chipsClockSelect(ScrnInfoPtr pScrn, int no)
{
    CHIPSClockReg TmpClock;
    CHIPSPtr cPtr = CHIPSPTR(pScrn);

    switch (no) {
    case CLK_REG_SAVE:
	chipsClockSave(pScrn, &cPtr->SaveClock);
	break;

    case CLK_REG_RESTORE:
	chipsClockLoad(pScrn, &cPtr->SaveClock);
	break;

    default:
	if (!chipsClockFind(pScrn, no, &TmpClock))
	    return (FALSE);
	chipsClockLoad(pScrn, &TmpClock);
    }
    return (TRUE);
}

/*
 * 
 * Fout = (Fref * 4 * M) / (PSN * N * (1 << P) )
 * Fvco = (Fref * 4 * M) / (PSN * N)
 * where
 * M = XR31+2
 * N = XR32+2
 * P = XR30[3:1]
 * PSN = XR30[0]? 1:4
 * 
 * constraints:
 * 4 MHz <= Fref <= 20 MHz (typ. 14.31818 MHz)
 * 150 kHz <= Fref/(PSN * N) <= 2 MHz
 * 48 MHz <= Fvco <= 220 MHz
 * 2 < M < 128
 * 2 < N < 128
 */

static void
chipsClockSave(ScrnInfoPtr pScrn, CHIPSClockPtr Clock)
{
    unsigned char tmp;
    vgaHWPtr hwp = VGAHWPTR(pScrn);
    CHIPSPtr cPtr = CHIPSPTR(pScrn);
    unsigned char Type = cPtr->ClockType;
    CHIPSEntPtr cPtrEnt;

    Clock->msr = hwp->readMiscOut(hwp)&0xFE; /* save standard VGA clock reg */
    switch (Type & GET_STYLE) {
    case HiQV_STYLE:
	/* save alternate clock select reg.*/
	/* The 69030 FP clock select is at FR01 instead */
      if (cPtr->UseDualChannel) {
        cPtrEnt = xf86GetEntityPrivate(pScrn->entityList[0],
					       CHIPSEntityIndex)->ptr;
	DUALREOPEN;
      }

	if (cPtr->Flags & ChipsDualChannelSupport)
	    Clock->fr03 = cPtr->readFR(cPtr, 0x01);
	else
	    Clock->fr03 = cPtr->readFR(cPtr, 0x03);
	if (!Clock->Clock) {   /* save HiQV console clock           */
	    tmp = cPtr->CRTclkInx << 2;
	    cPtr->CRTClk[0] = cPtr->readXR(cPtr, 0xC0 + tmp);
	    cPtr->CRTClk[1] = cPtr->readXR(cPtr, 0xC1 + tmp);
	    cPtr->CRTClk[2] = cPtr->readXR(cPtr, 0xC2 + tmp);
	    cPtr->CRTClk[3] = cPtr->readXR(cPtr, 0xC3 + tmp);
	    tmp = cPtr->FPclkInx << 2;
	    cPtr->FPClk[0] = cPtr->readXR(cPtr, 0xC0 + tmp);
	    cPtr->FPClk[1] = cPtr->readXR(cPtr, 0xC1 + tmp);
	    cPtr->FPClk[2] = cPtr->readXR(cPtr, 0xC2 + tmp);
	    cPtr->FPClk[3] = cPtr->readXR(cPtr, 0xC3 + tmp);
	}
	break;
    case OLD_STYLE: 
	Clock->fcr = hwp->readFCR(hwp);
	Clock->xr02 = cPtr->readXR(cPtr, 0x02);
	Clock->xr54 = cPtr->readXR(cPtr, 0x54); /* save alternate clock select reg.*/
	break;
    case WINGINE_1_STYLE:
    case WINGINE_2_STYLE:
	break;
    case NEW_STYLE:
	Clock->xr54 = cPtr->readXR(cPtr, 0x54); /* save alternate clock select reg.*/
	Clock->xr33 = cPtr->readXR(cPtr, 0x33); /* get status of MCLK/VCLK sel reg.*/
	break;
    }
#ifdef DEBUG
    ErrorF("saved \n");
#endif
}

static Bool
chipsClockFind(ScrnInfoPtr pScrn, int no, CHIPSClockPtr Clock)
{
    vgaHWPtr hwp = VGAHWPTR(pScrn);
    CHIPSPtr cPtr = CHIPSPTR(pScrn);
    unsigned char Type = cPtr->ClockType;
    CHIPSEntPtr cPtrEnt;

    if (no > (pScrn->numClocks - 1))
	return (FALSE);

    if (cPtr->UseDualChannel) {
        cPtrEnt = xf86GetEntityPrivate(pScrn->entityList[0],
					       CHIPSEntityIndex)->ptr;
	DUALREOPEN;
    }

    switch (Type & GET_STYLE) {
    case HiQV_STYLE:
	Clock->msr = cPtr->CRTclkInx << 2;
	Clock->fr03 = cPtr->FPclkInx << 2;
	Clock->Clock = pScrn->currentMode->Clock;
	if (xf86ReturnOptValBool(cPtr->Options, OPTION_USE_MODELINE, FALSE)) {
	    Clock->FPClock = pScrn->currentMode->Clock;
	} else
	    Clock->FPClock = cPtr->FPclock;
	break;
    case NEW_STYLE:
	if (Type & TYPE_HW) {
	    Clock->msr = (no == 4 ? 3 << 2: (no & 0x01) << 2);
	    Clock->xr54 = Clock->msr;               
	    Clock->xr33 = no > 1 ? 0x80 : 0;	
	} else {
	    Clock->msr = 3 << 2;
	    Clock->xr33 = 0;
	    Clock->xr54 = Clock->msr;
	    /* update panel type in case somebody switched.
	     * This should be handled more generally:
	     * On mode switch DDC should be reread, all
	     * display dependent data should be reevaluated.
	     * This will be built in when we start Display
	     * HotPlug support.
	     * Until then we have to do it here as somebody
	     * might have switched displays on us and we only
	     * have one programmable clock which needs to
	     * be shared for CRT and LCD.
	     */
	    chipsSetPanelType(cPtr);
	    {
	      Bool fp_m;
	      if (cPtr->Options 
		  && xf86GetOptValBool(cPtr->Options, OPTION_FP_MODE, &fp_m)) {
		   if (fp_m) 
		       cPtr->PanelType |= ChipsLCD;
		   else 
		       cPtr->PanelType = ~ChipsLCD;
	      }
	    }

	    if ((cPtr->PanelType & ChipsLCD) && cPtr->FPclock) 
		Clock->Clock = cPtr->FPclock;
	    else
		Clock->Clock = pScrn->currentMode->SynthClock;
	}
	break;
    case OLD_STYLE:
	if (no > 3) {
	    Clock->msr = 3 << 2;
	    Clock->fcr = no & 0x03;
	    Clock->xr02 = 0;
	    Clock->xr54 = Clock->msr & (Clock->fcr << 4);
	} else {
	    Clock->msr = (no << 2) & 0x4;
	    Clock->fcr = 0;
	    Clock->xr02 = no & 0x02;
	    Clock->xr54 = Clock->msr;
	}
	break;
    case WINGINE_1_STYLE:
	Clock->msr = no << 2;
    case WINGINE_2_STYLE:
	if (Type & TYPE_HW) {
	    Clock->msr = (no == 2 ? 3 << 2: (no & 0x01) << 2);
	    Clock->xr33 = 0;	
	} else {
	    Clock->msr = 3 << 2;
	    Clock->xr33 = 0;
	    Clock->Clock = pScrn->currentMode->SynthClock;
	}
	break;
    }
    Clock->msr |= (hwp->readMiscOut(hwp) & 0xF2);

#ifdef DEBUG
    ErrorF("found\n");
#endif
    return (TRUE);
}
    

static int
chipsGetHWClock(ScrnInfoPtr pScrn)
{
    vgaHWPtr hwp = VGAHWPTR(pScrn);
    CHIPSPtr cPtr = CHIPSPTR(pScrn);
    unsigned char Type = cPtr->ClockType;
    unsigned char tmp, tmp1;

    if (!(Type & TYPE_HW))
        return 0;		/* shouldn't happen                   */

    switch (Type & GET_STYLE) {
    case WINGINE_1_STYLE:
	return ((hwp->readMiscOut(hwp) & 0x0C) >> 2);
    case WINGINE_2_STYLE:
	tmp = ((hwp->readMiscOut(hwp) & 0x04) >> 2);
	return (tmp > 2) ? 2 : tmp;
    case OLD_STYLE:
	if (!(cPtr->PanelType & ChipsLCDProbed))
	    tmp = hwp->readMiscOut(hwp);
	else
	    tmp = cPtr->readXR(cPtr, 0x54);
	if (tmp & 0x08) {
	    if (!(cPtr->PanelType & ChipsLCDProbed))
		tmp = hwp->readFCR(hwp) & 0x03;
	    else 
		tmp = (tmp >> 4) & 0x03;
	    return (tmp + 4);
	} else {
	    tmp = (tmp >> 2) & 0x01;
	    tmp1 = cPtr->readXR(cPtr, 0x02);
	    return (tmp + (tmp1 & 0x02));
	}
    case NEW_STYLE:
	if (cPtr->PanelType & ChipsLCDProbed) {
	    tmp = cPtr->readXR(cPtr, 0x54);
	} else
	    tmp = hwp->readMiscOut(hwp);
	tmp = (tmp & 0x0C) >> 2;
	if (tmp > 1) return 4;
	tmp1 = cPtr->readXR(cPtr, 0x33);
	tmp1 = (tmp1 & 0x80) >> 6; /* iso mode 25.175/28.322 or 32/36 MHz  */
	return (tmp + tmp1);       /*            ^=0    ^=1     ^=4 ^=5    */
    default:		       /* we should never get here              */
	return (0);
    }
}

static void
chipsClockLoad(ScrnInfoPtr pScrn, CHIPSClockPtr Clock)
{
    vgaHWPtr hwp = VGAHWPTR(pScrn);
    CHIPSPtr cPtr = CHIPSPTR(pScrn);
    unsigned char Type = cPtr->ClockType;
    volatile unsigned char tmp, tmpmsr, tmpfcr, tmp02;
    volatile unsigned char tmp33, tmp54, tmpf03;
    unsigned char vclk[3];       

    tmpmsr = hwp->readMiscOut(hwp);  /* read msr, needed for all styles */

    switch (Type & GET_STYLE) {
    case HiQV_STYLE:
	/* save alternate clock select reg.  */
	/* The 69030 FP clock select is at FR01 instead */
	if (cPtr->Flags & ChipsDualChannelSupport) {
	    tmpf03 = cPtr->readFR(cPtr, 0x01);
	} else
	    tmpf03 = cPtr->readFR(cPtr, 0x03);
	/* select fixed clock 0  before tampering with VCLK select */
	hwp->writeMiscOut(hwp, (tmpmsr & ~0x0D) |
			   cPtr->SuspendHack.vgaIOBaseFlag);
	/* The 69030 FP clock select is at FR01 instead */
	if (cPtr->Flags & ChipsDualChannelSupport) {
	    cPtr->writeFR(cPtr, 0x01, (tmpf03 & ~0x0C) | 0x04);
	} else
	    cPtr->writeFR(cPtr, 0x03, (tmpf03 & ~0x0C) | 0x04);
	if (!Clock->Clock) {      /* Hack to load saved console clock  */
	    tmp = cPtr->CRTclkInx << 2;
	    cPtr->writeXR(cPtr, 0xC0 + tmp, (cPtr->CRTClk[0] & 0xFF));
	    cPtr->writeXR(cPtr, 0xC1 + tmp, (cPtr->CRTClk[1] & 0xFF));
	    cPtr->writeXR(cPtr, 0xC2 + tmp, (cPtr->CRTClk[2] & 0xFF));
	    cPtr->writeXR(cPtr, 0xC3 + tmp, (cPtr->CRTClk[3] & 0xFF));

	    if (cPtr->FPClkModified) {
	        usleep(10000); /* let VCO stabilize */
	        tmp = cPtr->FPclkInx << 2;
		cPtr->writeXR(cPtr, 0xC0 + tmp, (cPtr->FPClk[0] & 0xFF));
		cPtr->writeXR(cPtr, 0xC1 + tmp, (cPtr->FPClk[1] & 0xFF));
		cPtr->writeXR(cPtr, 0xC2 + tmp, (cPtr->FPClk[2] & 0xFF));
		cPtr->writeXR(cPtr, 0xC3 + tmp, (cPtr->FPClk[3] & 0xFF));
	    }
	} else {
	    /* 
	     * Don't use the extra 2 bits in the M, N registers available
	     * on the HiQV, so write zero to 0xCA 
	     */
	    chipsCalcClock(pScrn, Clock->Clock, vclk);
	    tmp = cPtr->CRTclkInx << 2;
	    cPtr->writeXR(cPtr, 0xC0 + tmp, (vclk[1] & 0xFF));
	    cPtr->writeXR(cPtr, 0xC1 + tmp, (vclk[2] & 0xFF));
	    cPtr->writeXR(cPtr, 0xC2 + tmp, 0x0);
	    cPtr->writeXR(cPtr, 0xC3 + tmp, (vclk[0] & 0xFF));
	    if (Clock->FPClock) { 
	        usleep(10000); /* let VCO stabilize */
    	        chipsCalcClock(pScrn, Clock->FPClock, vclk);
	        tmp = cPtr->FPclkInx << 2;
		cPtr->writeXR(cPtr, 0xC0 + tmp, (vclk[1] & 0xFF));
		cPtr->writeXR(cPtr, 0xC1 + tmp, (vclk[2] & 0xFF));
		cPtr->writeXR(cPtr, 0xC2 + tmp, 0x0);
		cPtr->writeXR(cPtr, 0xC3 + tmp, (vclk[0] & 0xFF));
		cPtr->FPClkModified = TRUE;
	    }
	}
	usleep(10000);		         /* Let VCO stabilise    */
	/* The 69030 FP clock select is at FR01 instead */
	if (cPtr->Flags & ChipsDualChannelSupport) {
	    cPtr->writeFR(cPtr, 0x01, ((tmpf03 & ~0x0C) |
			(Clock->fr03 & 0x0C)));
	} else
	    cPtr->writeFR(cPtr, 0x03, ((tmpf03 & ~0x0C) |
			(Clock->fr03 & 0x0C)));
	break;
    case WINGINE_1_STYLE:
	break;
    case WINGINE_2_STYLE:
	/* Only write to soft clock registers if we really need to */
	if ((Type & GET_TYPE) == TYPE_PROGRAMMABLE) {
	    /* select fixed clock 0  before tampering with VCLK select */
	    hwp->writeMiscOut(hwp, (tmpmsr & ~0x0D) | 
			       cPtr->SuspendHack.vgaIOBaseFlag);
	    chipsCalcClock(pScrn, Clock->Clock, vclk);
	    tmp33 = cPtr->readXR(cPtr, 0x33); /* get status of MCLK/VCLK select reg */
	    cPtr->writeXR(cPtr, 0x33, tmp33 & ~0x20);
	    cPtr->writeXR(cPtr, 0x30, vclk[0]);
	    cPtr->writeXR(cPtr, 0x31, vclk[1]);     /* restore VCLK regs.   */
	    cPtr->writeXR(cPtr, 0x32, vclk[2]);
	    /*  cPtr->writeXR(cPtr, 0x33, tmp33 & ~0x20);*/
	    usleep(10000);		     /* Let VCO stabilise    */
	}
	break;
    case OLD_STYLE:
	tmp02 = cPtr->readXR(cPtr, 0x02);
	tmp54 = cPtr->readXR(cPtr, 0x54);
	tmpfcr = hwp->readFCR(hwp);
	cPtr->writeXR(cPtr, 0x02, ((tmp02 & ~0x02) | (Clock->xr02 & 0x02)));
	cPtr->writeXR(cPtr, 0x54, ((tmp54 & 0xF0) | (Clock->xr54 & ~0xF0)));
	hwp->writeFCR(hwp, (tmpfcr & ~0x03) & Clock->fcr);
	break;
    case NEW_STYLE:
	tmp33 = cPtr->readXR(cPtr, 0x33); /* get status of MCLK/VCLK select reg */
	tmp54 = cPtr->readXR(cPtr, 0x54);
	/* Only write to soft clock registers if we really need to */
	if ((Type & GET_TYPE) == TYPE_PROGRAMMABLE) {
	    /* select fixed clock 0  before tampering with VCLK select */
	    hwp->writeMiscOut(hwp, (tmpmsr & ~0x0D) |
			   cPtr->SuspendHack.vgaIOBaseFlag);
	    cPtr->writeXR(cPtr, 0x54, (tmp54 & 0xF3));
	    /* if user wants to set the memory clock, do it first */
	    if (cPtr->MemClock.Clk) {
		chipsCalcClock(pScrn, cPtr->MemClock.Clk, vclk);
		/* close eyes, hold breath ....*/
		cPtr->writeXR(cPtr, 0x33, tmp33 | 0x20);
		cPtr->writeXR(cPtr, 0x30, vclk[0]);
		cPtr->writeXR(cPtr, 0x31, vclk[1]);
		cPtr->writeXR(cPtr, 0x32, vclk[2]);
		usleep(10000);
	    }
	    chipsCalcClock(pScrn, Clock->Clock, vclk);
	    cPtr->writeXR(cPtr, 0x33, tmp33 & ~0x20);
	    cPtr->writeXR(cPtr, 0x30, vclk[0]);
	    cPtr->writeXR(cPtr, 0x31, vclk[1]);     /* restore VCLK regs.   */
	    cPtr->writeXR(cPtr, 0x32, vclk[2]);
	    /*  cPtr->writeXR(cPtr, 0x33, tmp33 & ~0x20);*/
	    usleep(10000);		         /* Let VCO stabilise    */
	}
	cPtr->writeXR(cPtr, 0x33, ((tmp33 & ~0x80) | (Clock->xr33 & 0x80))); 
	cPtr->writeXR(cPtr, 0x54, ((tmp54 & 0xF3) | (Clock->xr54 & ~0xF3)));
	break;
    }
    hwp->writeMiscOut(hwp, (Clock->msr & 0xFE) |
			   cPtr->SuspendHack.vgaIOBaseFlag);
#ifdef DEBUG
    ErrorF("restored\n");
#endif
}
   
/* 
 * This is Ken Raeburn's <raeburn@raeburn.org> clock
 * calculation code just modified a little bit to fit in here.
 */

static void
chipsCalcClock(ScrnInfoPtr pScrn, int Clock, unsigned char *vclk)
{
    CHIPSPtr cPtr = CHIPSPTR(pScrn);
    int M, N, P = 0, PSN = 0, PSNx = 0;

    int bestM = 0, bestN = 0, bestP = 0, bestPSN = 0;
    double abest = 42;
#ifdef DEBUG
    double bestFout = 0;
#endif
    double target;

    double Fvco, Fout;
    double error, aerror;

    int M_min = 3;

    /* Hack to deal with problem of Toshiba 720CDT clock */
    int M_max = (IS_HiQV(cPtr) && cPtr->Chipset != CHIPS_CT69000 &&
				   cPtr->Chipset != CHIPS_CT69030) ? 63 : 127;

    /* @@@ < CHIPS_CT690x0 ?? */

    /* Other parameters available on the 65548 but not the 65545, and
     * not documented in the Clock Synthesizer doc in rev 1.0 of the
     * 65548 datasheet:
     * 
     * + XR30[4] = 0, VCO divider loop uses divide by 4 (same as 65545)
     * 1, VCO divider loop uses divide by 16
     * 
     * + XR30[5] = 1, reference clock is divided by 5
     * 
     * Other parameters available on the 65550 and not on the 65545
     * 
     * + XRCB[2] = 0, VCO divider loop uses divide by 4 (same as 65545)
     * 1, VCO divider loop uses divide by 16
     * 
     * + XRCB[1] = 1, reference clock is divided by 5
     * 
     * + XRCB[7] = Vclk = Mclk
     * 
     * + XRCA[0:1] = 2 MSB of a 10 bit M-Divisor
     * 
     * + XRCA[4:5] = 2 MSB of a 10 bit N-Divisor
     * 
     * I haven't put in any support for those here.  For simplicity,
     * they should be set to 0 on the 65548, and left untouched on
     * earlier chips.
     *
     * Other parameters available on the 690x0
     *
     * + The 690x0 has no reference clock divider, so PSN must
     *   always be 1.
     *   XRCB[0:1] are reserved according to the data book
     */


    target = Clock * 1000;

    /* @@@ >= CHIPS_CT690x0 ?? */
    for (PSNx = ((cPtr->Chipset == CHIPS_CT69000) || 
		 (cPtr->Chipset == CHIPS_CT69030)) ? 1 : 0; PSNx <= 1; PSNx++) {
	int low_N, high_N;
	double Fref4PSN;

	PSN = PSNx ? 1 : 4;

	low_N = 3;
	high_N = 127;

	while (Fref / (PSN * low_N) > (((cPtr->Chipset == CHIPS_CT69000) || 
					(cPtr->Chipset == CHIPS_CT69030)) ? 5.0e6 : 2.0e6))
	    low_N++;
	while (Fref / (PSN * high_N) < 150.0e3)
	    high_N--;

	Fref4PSN = Fref * 4 / PSN;
	for (N = low_N; N <= high_N; N++) {
	    double tmp = Fref4PSN / N;

	    /* @@@ < CHIPS_CT690x0 ?? */
	    for (P = (IS_HiQV(cPtr) && (cPtr->Chipset != CHIPS_CT69000) &&
				(cPtr->Chipset != CHIPS_CT69030)) ? 1 : 0;
		 P <= 5; P++) {	
	        /* to force post divisor on Toshiba 720CDT */
		double Fvco_desired = target * (1 << P);
		double M_desired = Fvco_desired / tmp;

		/* Which way will M_desired be rounded?  Do all three just to
		 * be safe.  */
		int M_low = M_desired - 1;
		int M_hi = M_desired + 1;

		if (M_hi < M_min || M_low > M_max)
		    continue;

		if (M_low < M_min)
		    M_low = M_min;
		if (M_hi > M_max)
		    M_hi = M_max;

		for (M = M_low; M <= M_hi; M++) {
		    Fvco = tmp * M;
		    /* @@@ >= CHIPS_CT690x0 ?? */
		    if (Fvco <= ((cPtr->Chipset == CHIPS_CT69000 ||
			cPtr->Chipset == CHIPS_CT69030) ? 100.0e6 : 48.0e6))
			continue;
		    if (Fvco > 220.0e6)
			break;

		    Fout = Fvco / (1 << P);

		    error = (target - Fout) / target;

		    aerror = (error < 0) ? -error : error;
		    if (aerror < abest) {
			abest = aerror;
			bestM = M;
			bestN = N;
			bestP = P;
			bestPSN = PSN;
#ifdef DEBUG
			bestFout = Fout;
#endif
		    }
		}
	    }
	}
    }
    /* @@@ >= CHIPS_CT690x0 ?? */
    vclk[0] = (bestP << (IS_HiQV(cPtr) ? 4 : 1)) +
	(((cPtr->Chipset == CHIPS_CT69000) || (cPtr->Chipset == CHIPS_CT69030)) 
	? 0 : (bestPSN == 1));
    vclk[1] = bestM - 2;
    vclk[2] = bestN - 2;
#ifdef DEBUG
    ErrorF("Freq. selected: %.2f MHz, vclk[0]=%X, vclk[1]=%X, vclk[2]=%X\n",
	(float)(Clock / 1000.), vclk[0], vclk[1], vclk[2]);
    ErrorF("Freq. set: %.2f MHz\n", bestFout / 1.0e6);
#endif
}

static void
chipsSave(ScrnInfoPtr pScrn, vgaRegPtr VgaSave, CHIPSRegPtr ChipsSave)
{
    vgaHWPtr hwp = VGAHWPTR(pScrn);
    CHIPSPtr cPtr = CHIPSPTR(pScrn);
    int i;
    unsigned char tmp;
#ifdef DEBUG
    ErrorF("chipsSave\n");
#endif
    
    /* set registers that we can program the controller */
    /* bank 0 */
    if (IS_HiQV(cPtr)) {
	cPtr->writeXR(cPtr, 0x0E, 0x00);
    } else {
	cPtr->writeXR(cPtr, 0x10, 0x00);
	cPtr->writeXR(cPtr, 0x11, 0x00);
	tmp = cPtr->readXR(cPtr, 0x0C) & ~0x50; /* WINgine stores MSB here */
	cPtr->writeXR(cPtr, 0x0C, tmp);
    }
    chipsFixResume(pScrn);
    tmp = cPtr->readXR(cPtr, 0x02);
    cPtr->writeXR(cPtr, 0x02, tmp & ~0x18);
    /* get generic registers */
    vgaHWSave(pScrn, VgaSave, VGA_SR_ALL);

    /* save clock */
    chipsClockSave(pScrn, &ChipsSave->Clock);

    /* save extended registers */
    if (IS_HiQV(cPtr)) {
	for (i = 0; i < 0xFF; i++) {
#ifdef SAR04
	    /* Save SAR04 multimedia register correctly */
	    if (i == 0x4F)
	        cPtr->writeXR(cPtr, 0x4E, 0x04);
#endif
	    ChipsSave->XR[i] = cPtr->readXR(cPtr,i);
#ifdef DEBUG
	    ErrorF("XS%X - %X\n", i, ChipsSave->XR[i]);
#endif
	}
	for (i = 0; i < 0x80; i++) {
	    ChipsSave->FR[i] = cPtr->readFR(cPtr, i);
#ifdef DEBUG
	    ErrorF("FS%X - %X\n", i, ChipsSave->FR[i]);
#endif
	}
	for (i = 0; i < 0x80; i++) {
		ChipsSave->MR[i] = cPtr->readMR(cPtr, i);
#ifdef DEBUG
	    ErrorF("MS%X - %X\n", i, ChipsSave->FR[i]);
#endif
	}
	/* Save CR0-CR40 even though we don't use them, so they can be 
	 *  printed */
	for (i = 0x0; i < 0x80; i++) {
	    ChipsSave->CR[i] = hwp->readCrtc(hwp, i);
#ifdef DEBUG
	    ErrorF("CS%X - %X\n", i, ChipsSave->CR[i]);
#endif
	}
    } else {
	for (i = 0; i < 0x7D; i++) { /* don't touch XR7D and XR7F on WINGINE */
	    ChipsSave->XR[i] = cPtr->readXR(cPtr, i);
#ifdef DEBUG
	    ErrorF("XS%X - %X\n", i, ChipsSave->XR[i]);
#endif
	}
    }
}

Bool
chipsModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
{
    CHIPSPtr cPtr = CHIPSPTR(pScrn);
#ifdef DEBUG
    ErrorF("chipsModeInit\n");
#endif
#if 0
    *(int*)0xFFFFFF0 = 0;
    ErrorF("done\n");
#endif

    chipsUnlock(pScrn);
    chipsFixResume(pScrn);

    if (cPtr->Accel.UseHWCursor)
	cPtr->Flags |= ChipsHWCursor;
    else
	cPtr->Flags &= ~ChipsHWCursor;
    /*
     * We need to delay cursor loading after resetting the video mode
     * to give the engine a chance to recover.
     */
    cPtr->cursorDelay = TRUE;
    
    if (IS_HiQV(cPtr))
	return chipsModeInitHiQV(pScrn, mode);
    else if (IS_Wingine(cPtr))
        return chipsModeInitWingine(pScrn, mode);
    else
      return chipsModeInit655xx(pScrn, mode);
}

/*
 * The timing register of the C&T FP chipsets are organized
 * as follows:
 * The chipsets have two sets of timing registers:
 * the standard horizontal and vertical timing registers for
 * display size, blank start, sync start, sync end, blank end 
 * and total size at their default VGA locations and extensions
 * and the alternate horizontal and vertical timing registers for
 * display size, sync start, sync end and total size.
 * In LCD and mixed (LCD+CRT) mode the alternate timing registers
 * control the timing. The alternate horizontal and vertical display 
 * size registers are set to the physical pixel size of the display. 
 * Normally the alternalte registers are set by the BIOS to optimized 
 * values. 
 * While the horizontal an vertical refresh rates are fixed independent
 * of the visible display size to ensure optimal performace of both 
 * displays they can be adapted to the screen resolution and CRT
 * requirements in CRT mode by programming the standard timing registers
 * in the VGA fashion.
 * In LCD and mixed mode the _standard_ horizontal and vertical display
 * size registers control the size of the _visible_ part of the display
 * in contast to the _physical_ size of the display which is specified
 * by the _alternate_ horizontal and vertical display size registers.
 * The size of the visible should always be equal or less than the
 * physical size.
 * For the 69030 chipsets, the CRT and LCD display channels are seperate
 * and so can be driven independently.
 */
static Bool
chipsModeInitHiQV(ScrnInfoPtr pScrn, DisplayModePtr mode)
{
    int i;
    int lcdHTotal, lcdHDisplay;
    int lcdVTotal, lcdVDisplay;
    int lcdHRetraceStart, lcdHRetraceEnd;
    int lcdVRetraceStart, lcdVRetraceEnd;
    int lcdHSyncStart;
    vgaHWPtr hwp = VGAHWPTR(pScrn);
    CHIPSPtr cPtr = CHIPSPTR(pScrn);
    CHIPSRegPtr ChipsNew;
    vgaRegPtr ChipsStd;
    unsigned int tmp;
    
    ChipsNew = &cPtr->ModeReg;
    ChipsStd = &hwp->ModeReg;


    /*
     * Possibly fix up the panel size, if the manufacture is stupid
     * enough to set it incorrectly in text modes
     */
    if (xf86ReturnOptValBool(cPtr->Options, OPTION_PANEL_SIZE, FALSE)) {
	cPtr->PanelSize.HDisplay = mode->CrtcHDisplay;
	cPtr->PanelSize.VDisplay = mode->CrtcVDisplay;
    }

    /* generic init */
    hwp->Flags |= VGA_FIX_SYNC_PULSES;
    if (!vgaHWInit(pScrn, mode)) {
	ErrorF("bomb 1\n");
	return (FALSE);
    }
    pScrn->vtSema = TRUE;

    /* We need to redo the overscan voodoo from vgaHW.c */
    vgaHWHBlankKGA(mode, ChipsStd, 0, 0);
    vgaHWVBlankKGA(mode, ChipsStd, 0, 0);

    /* init clock */
    if (!chipsClockFind(pScrn, mode->ClockIndex, &ChipsNew->Clock)) {
	ErrorF("bomb 2\n");
	return (FALSE);
    }

    /* Give Warning if the dual display mode will cause problems */
    /* Note 64bit wide memory bus assumed (as in 69000 and 69030 */
    if (cPtr->UseDualChannel && ((cPtr->SecondCrtc == TRUE) ||
				 (cPtr->Flags & ChipsDualRefresh))) {
	if (((ChipsNew->Clock.FPClock + ChipsNew->Clock.Clock) * 
		(max(1, pScrn->bitsPerPixel >> 3) +
		((cPtr->FrameBufferSize && (cPtr->PanelType & ChipsLCD)) ?
		1 : 0)) / (8 * 0.7)) > cPtr->MemClock.Max) {
	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
		"Memory bandwidth requirements exceeded by dual-channel\n");
	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
		       "   mode. Display might be corrupted!!!\n");
	}
    }

    /* get C&T Specific Registers */
    for (i = 0; i < 0xFF; i++) {
#ifdef SAR04
	/* Save SAR04 multimedia register correctly */
	if (i == 0x4F)
	    cPtr->writeXR(cPtr, 0x4E, 0x04);
#endif
	ChipsNew->XR[i] = cPtr->readXR(cPtr, i);
    }
    for (i = 0; i < 0x80; i++) {
	ChipsNew->FR[i] = cPtr->readFR(cPtr, i);
    }
    for (i = 0; i < 0x80; i++) {
	ChipsNew->MR[i] = cPtr->readMR(cPtr, i);
    }
    for (i = 0x30; i < 0x80; i++) {    /* These are the CT extended CRT regs */
	ChipsNew->CR[i] = hwp->readCrtc(hwp, i);
    }

    /*
     * Here all of the other fields of 'ChipsNew' get filled in, to
     * handle the SVGA extended registers.  It is also allowable
     * to override generic registers whenever necessary.
     */

    /* some generic settings */
    if (pScrn->depth == 1) {
	ChipsStd->Attribute[0x10] = 0x03;   /* mode */
    } else {
	ChipsStd->Attribute[0x10] = 0x01;   /* mode */
    }
    if ((pScrn->bitsPerPixel == 16) && (cPtr->Flags & ChipsOverlay8plus16)) {
	/* Make sure that the overlay isn't visible in the overscan region */
	if (ChipsStd->Attribute[0x11] == pScrn->colorKey)
	    ChipsStd->Attribute[0x11] = pScrn->colorKey - 1;
    } else
	ChipsStd->Attribute[0x11] = 0x00;   /* overscan (border) color */
    ChipsStd->Attribute[0x12] = 0x0F;   /* enable all color planes */
    ChipsStd->Attribute[0x13] = 0x00;   /* horiz pixel panning 0 */

    ChipsStd->Graphics[0x05] = 0x00;    /* normal read/write mode */

    /* set virtual screen width */
    tmp = pScrn->displayWidth >> 3;
    if (pScrn->bitsPerPixel == 16) {
	if (!(cPtr->Flags & ChipsOverlay8plus16))
	    tmp <<= 1;		       /* double the width of the buffer */
    } else if (pScrn->bitsPerPixel == 24) {
	tmp += tmp << 1;
    } else if (pScrn->bitsPerPixel == 32) {
	tmp <<= 2;
    } else if (pScrn->bitsPerPixel < 8) {
	tmp >>= 1;
    }
    ChipsStd->CRTC[0x13] = tmp & 0xFF;
    ChipsNew->CR[0x41] = (tmp >> 8) & 0x0F;

    /* Set paging mode on the HiQV32 architecture, if required */
    if (!(cPtr->Flags & ChipsLinearSupport) || (pScrn->bitsPerPixel < 8))
	ChipsNew->XR[0x0A] |= 0x1;

    ChipsNew->XR[0x09] |= 0x1;	       /* Enable extended CRT registers */
    ChipsNew->XR[0x0E] = 0;           /* Single map */
    ChipsNew->XR[0x40] |= 0x2;	       /* Don't wrap at 256kb */
    ChipsNew->XR[0x81] &= 0xF8;
    if (pScrn->bitsPerPixel >= 8) {
        ChipsNew->XR[0x40] |= 0x1;    /* High Resolution. XR40[1] reserved? */
	ChipsNew->XR[0x81] |= 0x2;    /* 256 Color Video */
    }
    ChipsNew->XR[0x80] |= 0x10;       /* Enable cursor output on P0 and P1 */
    if (pScrn->depth > 1) {
	if (pScrn->rgbBits == 8)
	    ChipsNew->XR[0x80] |= 0x80;
	else
	    ChipsNew->XR[0x80] &= ~0x80;
    }

    if (abs(cPtr->MemClock.Clk - cPtr->MemClock.ProbedClk) > 50) {
	/* set mem clk */
	ChipsNew->XR[0xCC] = cPtr->MemClock.xrCC;
	ChipsNew->XR[0xCD] = cPtr->MemClock.xrCD;
	ChipsNew->XR[0xCE] = cPtr->MemClock.xrCE;
    }

    /* Set the 69030 dual channel settings */
    if (cPtr->Flags & ChipsDualChannelSupport) {
	ChipsNew->FR[0x01] &= 0xFC;
        if ((cPtr->SecondCrtc == FALSE) && (cPtr->PanelType & ChipsLCD))
	    ChipsNew->FR[0x01] |= 0x02;
	else
	    ChipsNew->FR[0x01] |= 0x01;
	ChipsNew->FR[0x02] &= 0xCC;
	if ((cPtr->SecondCrtc == TRUE) || (cPtr->Flags & ChipsDualRefresh))
	    ChipsNew->FR[0x02] |= 0x01;	/* Set DAC to pipe B */
	else
	    ChipsNew->FR[0x02] &= 0xFE;	/* Set DAC to pipe A */

        if (cPtr->PanelType & ChipsLCD)
	    ChipsNew->FR[0x02] |= 0x20;	/* Enable the LCD output */
        if (cPtr->PanelType & ChipsCRT)
	    ChipsNew->FR[0x02] |= 0x10;	/* Enable the CRT output */
    }
    
    /* linear specific */
    if (cPtr->Flags & ChipsLinearSupport) {
	ChipsNew->XR[0x0A] |= 0x02;   /* Linear Addressing Mode */
	ChipsNew->XR[0x20] = 0x0;     /*BitBLT Draw Mode for 8 */
	ChipsNew->XR[0x05] =
	    (unsigned char)((cPtr->FbAddress >> 16) & 0xFF);
	ChipsNew->XR[0x06] = 
	    (unsigned char)((cPtr->FbAddress >> 24) & 0xFF);
    }

    /* panel timing */
    /* By default don't set panel timings, but allow it as an option */
    if (xf86ReturnOptValBool(cPtr->Options, OPTION_USE_MODELINE, FALSE)) {
	lcdHTotal = (mode->CrtcHTotal >> 3) - 5;
	lcdHDisplay = (cPtr->PanelSize.HDisplay >> 3) - 1;
	lcdHRetraceStart = (mode->CrtcHSyncStart >> 3) - 1;
	lcdHRetraceEnd = (mode->CrtcHSyncEnd >> 3) - 1;
	lcdHSyncStart = lcdHRetraceStart - 2;				/* ?? */

	lcdVTotal = mode->CrtcVTotal - 2;
	lcdVDisplay = cPtr->PanelSize.VDisplay - 1;
	lcdVRetraceStart = mode->CrtcVSyncStart - 1;
	lcdVRetraceEnd = mode->CrtcVSyncEnd - 1;

	ChipsNew->FR[0x20] = lcdHDisplay & 0xFF;
	ChipsNew->FR[0x21] = lcdHRetraceStart & 0xFF;
	ChipsNew->FR[0x22] = lcdHRetraceEnd & 0x1F;
	ChipsNew->FR[0x23] = lcdHTotal & 0xFF;
	ChipsNew->FR[0x24] = (lcdHSyncStart >> 3) & 0xFF;		/* ?? */
	ChipsNew->FR[0x25] = ((lcdHRetraceStart & 0xF00) >> 4) |
	    ((lcdHDisplay & 0xF00) >> 8);
	ChipsNew->FR[0x26] = ((lcdHTotal & 0xF00) >> 8)
	    | ((lcdHSyncStart & 0xF00) >> 4);				/* ?? */
	ChipsNew->FR[0x27] &= 0x7F;

	ChipsNew->FR[0x30] = lcdVDisplay & 0xFF;
	ChipsNew->FR[0x31] = lcdVRetraceStart & 0xFF;
	ChipsNew->FR[0x32] = lcdVRetraceEnd & 0x0F;
	ChipsNew->FR[0x33] = lcdVTotal & 0xFF;
	ChipsNew->FR[0x34] = (lcdVTotal - lcdVRetraceStart) & 0xFF;	/* ?? */
	ChipsNew->FR[0x35] = ((lcdVRetraceStart & 0xF00) >> 4)
	    | ((lcdVDisplay & 0xF00) >> 8);
	ChipsNew->FR[0x36] = ((lcdVTotal & 0xF00) >> 8) |
	    (((lcdVTotal - lcdVRetraceStart) & 0xF00) >> 4);		/* ?? */
	ChipsNew->FR[0x37] |= 0x80;
    }

    /* Set up the extended CRT registers of the HiQV32 chips */
    ChipsNew->CR[0x30] = ((mode->CrtcVTotal - 2) & 0xF00) >> 8;
    ChipsNew->CR[0x31] = ((mode->CrtcVDisplay - 1) & 0xF00) >> 8;
    ChipsNew->CR[0x32] = ((mode->CrtcVSyncStart - 1) & 0xF00) >> 8;
    ChipsNew->CR[0x33] = ((mode->CrtcVBlankStart - 1) & 0xF00) >> 8;
    if ((cPtr->Chipset == CHIPS_CT69000) || (cPtr->Chipset == CHIPS_CT69030)) {
	/* The 690xx has overflow bits for the horizontal values as well */
	ChipsNew->CR[0x38] = (((mode->CrtcHTotal >> 3) - 5) & 0x100) >> 8;
	ChipsNew->CR[0x3C] = ((mode->CrtcHBlankEnd >> 3) - 1) & 0xC0;
    }

    ChipsNew->CR[0x40] |= 0x80;

    /* centering/stretching */
    if (!xf86ReturnOptValBool(cPtr->Options, OPTION_SUSPEND_HACK, FALSE)) {
	if (!xf86ReturnOptValBool(cPtr->Options, OPTION_LCD_STRETCH, FALSE) ||
	(cPtr->Flags & ChipsOverlay8plus16)) {
	    ChipsNew->FR[0x40] &= 0xDF;    /* Disable Horizontal stretching */
	    ChipsNew->FR[0x48] &= 0xFB;    /* Disable vertical stretching */
	    ChipsNew->XR[0xA0] = 0x10;     /* Disable cursor stretching */
	} else {
	    ChipsNew->FR[0x40] |= 0x21;    /* Enable Horizontal stretching */
	    ChipsNew->FR[0x48] |= 0x05;    /* Enable vertical stretching */
	    ChipsNew->XR[0xA0] = 0x70;     /* Enable cursor stretching */
	    if (cPtr->Accel.UseHWCursor 
		&& cPtr->PanelSize.HDisplay && cPtr->PanelSize.VDisplay
		&& (cPtr->PanelSize.HDisplay != mode->CrtcHDisplay)
		&& (cPtr->PanelSize.VDisplay != mode->CrtcVDisplay)) {
		if(cPtr->Accel.UseHWCursor)
		    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
			       "Disabling HW Cursor on stretched LCD\n");
		cPtr->Flags &= ~ChipsHWCursor;
	    }
	}
    }

    if ((xf86ReturnOptValBool(cPtr->Options, OPTION_LCD_CENTER, TRUE))
		|| (cPtr->Flags & ChipsOverlay8plus16)) {
	ChipsNew->FR[0x40] |= 0x3;    /* Enable Horizontal centering */
	ChipsNew->FR[0x48] |= 0x3;    /* Enable Vertical centering */
    } else {
	ChipsNew->FR[0x40] &= 0xFD;    /* Disable Horizontal centering */
	ChipsNew->FR[0x48] &= 0xFD;    /* Disable Vertical centering */
    }

    /* sync on green */
    if (xf86ReturnOptValBool(cPtr->Options, OPTION_SYNC_ON_GREEN, FALSE))
	ChipsNew->XR[0x82] |=0x02;

    /* software mode flag */
    ChipsNew->XR[0xE2] = chipsVideoMode(((cPtr->Flags & ChipsOverlay8plus16) ?
	8 : pScrn->depth), (cPtr->PanelType & ChipsLCD) ?
	min(mode->CrtcHDisplay, cPtr->PanelSize.HDisplay) :
	mode->CrtcHDisplay, mode->CrtcVDisplay);
#ifdef DEBUG
    ErrorF("VESA Mode: %Xh\n", ChipsNew->XR[0xE2]);
#endif

    /* sync. polarities */
    if ((mode->Flags & (V_PHSYNC | V_NHSYNC))
	&& (mode->Flags & (V_PVSYNC | V_NVSYNC))) {
	if (mode->Flags & (V_PHSYNC | V_NHSYNC)) {
	    if (mode->Flags & V_PHSYNC)
		ChipsNew->FR[0x08] &= 0xBF;	/* Alt. CRT Hsync positive */
	    else
		ChipsNew->FR[0x08] |= 0x40;	/* Alt. CRT Hsync negative */
	}
	if (mode->Flags & (V_PVSYNC | V_NVSYNC)) {
	    if (mode->Flags & V_PVSYNC)
		ChipsNew->FR[0x08] &= 0x7F;	/* Alt. CRT Vsync positive */
	    else
		ChipsNew->FR[0x08] |= 0x80;	/* Alt. CRT Vsync negative */
	}
    }
    if (mode->Flags & (V_PCSYNC | V_NCSYNC)) {
	ChipsNew->FR[0x0B] |= 0x20;
	if (mode->Flags & V_PCSYNC) {
	    ChipsNew->FR[0x08] &= 0x7F;	/* Alt. CRT Vsync positive */
	    ChipsNew->FR[0x08] &= 0xBF;	/* Alt. CRT Hsync positive */
	    ChipsStd->MiscOutReg &= 0x7F;
	    ChipsStd->MiscOutReg &= 0xBF;
	} else {
	    ChipsNew->FR[0x08] |= 0x80;	/* Alt. CRT Vsync negative */
	    ChipsNew->FR[0x08] |= 0x40;	/* Alt. CRT Hsync negative */
	    ChipsStd->MiscOutReg |= 0x40;
	    ChipsStd->MiscOutReg |= 0x80;
    	}
    }	    
    /* bpp depend */
    if ((pScrn->bitsPerPixel == 16) && (!(cPtr->Flags & ChipsOverlay8plus16))) {
	ChipsNew->XR[0x81] = (ChipsNew->XR[0x81] & 0xF0) | 0x4;
	if (cPtr->Flags & ChipsGammaSupport)
	    ChipsNew->XR[0x82] |= 0x0C;
	/* 16bpp = 5-5-5             */
	ChipsNew->FR[0x10] |= 0x0C;   /*Colour Panel               */
	ChipsNew->XR[0x20] = 0x10;    /*BitBLT Draw Mode for 16 bpp */
	if (pScrn->weight.green != 5)
	    ChipsNew->XR[0x81] |= 0x01;	/*16bpp */
    } else if (pScrn->bitsPerPixel == 24) {
	ChipsNew->XR[0x81] = (ChipsNew->XR[0x81] & 0xF0) | 0x6;
	if (cPtr->Flags & ChipsGammaSupport)
	    ChipsNew->XR[0x82] |= 0x0C;
	/* 24bpp colour              */
	ChipsNew->XR[0x20] = 0x20;    /*BitBLT Draw Mode for 24 bpp */
    } else if (pScrn->bitsPerPixel == 32) {
	ChipsNew->XR[0x81] = (ChipsNew->XR[0x81] & 0xF0) | 0x7;
	if (cPtr->Flags & ChipsGammaSupport)
	    ChipsNew->XR[0x82] |= 0x0C;
	/* 32bpp colour              */
	ChipsNew->XR[0x20] = 0x10;    /*BitBLT Mode for 16bpp used at 32bpp */
    }
    
    /*CRT only */
    if (!(cPtr->PanelType & ChipsLCD)) {
	if (mode->Flags & V_INTERLACE) {
	    ChipsNew->CR[0x70] = 0x80          /*   set interlace */
	      | (((((mode->CrtcHDisplay >> 3) - 1) >> 1) - 6) & 0x7F);
	    /* 
	     ** Double VDisplay to get back the full screen value, otherwise
	     ** you only see half the picture.
	     */
	    mode->CrtcVDisplay = mode->VDisplay;
	    tmp = ChipsStd->CRTC[7] & ~0x42;
	    ChipsStd->CRTC[7] = (tmp | 
				((((mode->CrtcVDisplay -1) & 0x100) >> 7 ) |
				 (((mode->CrtcVDisplay -1) & 0x200) >> 3 )));
	    ChipsStd->CRTC[0x12] = (mode->CrtcVDisplay -1) & 0xFF;
	    ChipsNew->CR[0x31] = ((mode->CrtcVDisplay - 1) & 0xF00) >> 8;
	} else {
	    ChipsNew->CR[0x70] &= ~0x80;	/* unset interlace */
	}
    }
    
#if defined(__arm32__) && defined(__NetBSD__)
    if (cPtr->TVMode != XMODE_RGB) {
	/*
	 * Put the console into TV Out mode.
	 */
	xf86SetTVOut(cPtr->TVMode);
	
	ChipsNew->CR[0x72] = (mode->CrtcHTotal >> 1) >> 3;/* First horizontal
							   * serration pulse */
	ChipsNew->CR[0x73] = mode->CrtcHTotal >> 3; /* Second pulse */
	ChipsNew->CR[0x74] = (((mode->HSyncEnd - mode->HSyncStart) >> 3) - 1)
					& 0x1F; /* equalization pulse */
	
	if (cPtr->TVMode == XMODE_PAL || cPtr->TVMode == XMODE_SECAM) {
	    ChipsNew->CR[0x71] = 0xA0; /* PAL support with blanking delay */
	} else {
	    ChipsNew->CR[0x71] = 0x20; /* NTSC support with blanking delay */
	}
    } else {	/* XMODE_RGB */
	/*
	 * Put the console into RGB Out mode.
	 */
	xf86SetRGBOut();
    }
#endif

    /* STN specific */
    if (IS_STN(cPtr->PanelType)) {
	ChipsNew->FR[0x11] &= ~0x03;	/* FRC clear                    */
	ChipsNew->FR[0x11] &= ~0x8C;	/* Dither clear                 */
	ChipsNew->FR[0x11] |= 0x01;	/* 16 frame FRC                 */
	ChipsNew->FR[0x11] |= 0x84;	/* Dither                       */
	if ((cPtr->Flags & ChipsTMEDSupport) &&
		!xf86ReturnOptValBool(cPtr->Options, OPTION_NO_TMED, FALSE)) {
	    ChipsNew->FR[0x73] &= 0x4F; /* Clear TMED                   */
	    ChipsNew->FR[0x73] |= 0x80; /* Enable TMED                  */
	    ChipsNew->FR[0x73] |= 0x30; /* TMED 256 Shades of RGB       */
	}
	if (cPtr->PanelType & ChipsDD)	/* Shift Clock Mask. Use to get */
	    ChipsNew->FR[0x12] |= 0x4;	/* rid of line in DSTN screens  */
    }

    /*
     * The zero position of the overlay does not align with the zero
     * position of the display. The skew is dependent on the depth,
     * display type and refresh rate. Calculate the skew before setting
     * the X and Y dimensions of the overlay. These values are needed
     * both by the overlay and XvImages. So calculate and store them
     */
    if (cPtr->PanelType & ChipsLCD) {
	cPtr->OverlaySkewX = (((ChipsNew->FR[0x23] & 0xFF) 
			    - (ChipsNew->FR[0x20] & 0xFF) + 3) << 3) 
	    - 1;
	cPtr->OverlaySkewY = (ChipsNew->FR[0x33]
			    + ((ChipsNew->FR[0x36] & 0xF) << 8)
			    - (ChipsNew->FR[0x31] & 0xF0)
			    - (ChipsNew->FR[0x32] & 0x0F)
			    - ((ChipsNew->FR[0x35] & 0xF0) << 4));
	if (!xf86ReturnOptValBool(cPtr->Options, OPTION_LCD_STRETCH, FALSE)
	      && xf86ReturnOptValBool(cPtr->Options, OPTION_LCD_CENTER, TRUE))
	{
	    if (cPtr->PanelSize.HDisplay > mode->CrtcHDisplay) 
		cPtr->OverlaySkewX += (cPtr->PanelSize.HDisplay - 
				       mode->CrtcHDisplay) / 2;
	    if (cPtr->PanelSize.VDisplay > mode->CrtcVDisplay)
		cPtr->OverlaySkewY += (cPtr->PanelSize.VDisplay -
				       mode->CrtcVDisplay) / 2;
	}
    } else {
	cPtr->OverlaySkewX = mode->CrtcHTotal - mode->CrtcHBlankStart - 9;
	cPtr->OverlaySkewY = mode->CrtcVTotal - mode->CrtcVSyncEnd - 1;
	    
	if (mode->Flags & V_INTERLACE) {
	    /*
	     * This handles 1024 and 1280 interlaced modes only. Its 
	     * pretty arbitrary, but its what C&T recommends
	     */
#if 0
	    if (mode->CrtcHDisplay == 1024)
		cPtr->OverlaySkewY += 5;
	    else  if (mode->CrtcHDisplay == 1280)
#endif
		cPtr->OverlaySkewY *= 2;
	    
	}
    }

    /* mask for viewport granularity */

    switch (pScrn->bitsPerPixel) {
    case 8:
	cPtr->viewportMask = ~7U;
	break;
    case 16:
	cPtr->viewportMask = ~3U;
	break;
    case 24:
	cPtr->viewportMask = ~7U;
	break;
    case 32:
	cPtr->viewportMask = ~0U;
	break;
    default:
	cPtr->viewportMask = ~7U;
    }
    
    /* Turn off multimedia by default as it degrades performance */
    ChipsNew->XR[0xD0] &= 0x0f;	 
    
    /* Setup the video/overlay */
    if (cPtr->Flags & ChipsOverlay8plus16) {
	ChipsNew->XR[0xD0] |= 0x10;	/* Force the Multimedia engine on */
#ifdef SAR04
	ChipsNew->XR[0x4F] = 0x2A;	/* SAR04 >352 pixel overlay width */
#endif
	ChipsNew->MR[0x1E] &= 0xE0;	/* Set Zoom and Direction */
	if ((!(cPtr->PanelType & ChipsLCD)) && (mode->Flags & V_INTERLACE))
	    ChipsNew->MR[0x1E] |= 0x10;	/* Interlace */
	ChipsNew->MR[0x1F] &= 0x14;	/* Mask reserved bits */
	ChipsNew->MR[0x1F] |= 0x08;	/* RGB 16bpp */
	if (pScrn->weight.green == 5)
	    ChipsNew->MR[0x1F] |= 0x01;	/* RGB 15bpp */

	ChipsNew->MR[0x20] &= 0x03;	/* Mask reserved bits */
	ChipsNew->MR[0x20] |= 0x80;	/* Auto Centre, Use mem ptr1 */
	ChipsNew->MR[0x22] = cPtr->FbOffset16 & 0xF8;	/* Setup Pointer 1 */
	ChipsNew->MR[0x23] = (cPtr->FbOffset16 >> 8) & 0xFF;
	ChipsNew->MR[0x24] = (cPtr->FbOffset16 >> 16) & 0xFF;
	ChipsNew->MR[0x25] = cPtr->FbOffset16 & 0xF8;	/* Setup Pointer 2 */
	ChipsNew->MR[0x26] = (cPtr->FbOffset16 >> 8) & 0xFF;
	ChipsNew->MR[0x27] = (cPtr->FbOffset16 >> 16) & 0xFF;
	ChipsNew->MR[0x28] = (pScrn->displayWidth >> 2) - 1; /* Width */ 
	ChipsNew->MR[0x34] = (pScrn->displayWidth >> 2) - 1;

	/* Left Edge of Overlay */
	ChipsNew->MR[0x2A] = cPtr->OverlaySkewX;
	ChipsNew->MR[0x2B] &= 0xF8;	/* Mask reserved bits */
	ChipsNew->MR[0x2B] |= ((cPtr->OverlaySkewX >> 8) & 0x7);
	/* Right Edge of Overlay */
	ChipsNew->MR[0x2C] = (cPtr->OverlaySkewX + pScrn->displayWidth - 
							1) & 0xFF;
	ChipsNew->MR[0x2D] &= 0xF8;	/* Mask reserved bits */
	ChipsNew->MR[0x2D] |= ((cPtr->OverlaySkewX + pScrn->displayWidth -
							1) >> 8) & 0x07;
	/* Top Edge of Overlay */
	ChipsNew->MR[0x2E] = cPtr->OverlaySkewY;
	ChipsNew->MR[0x2F] &= 0xF8;
	ChipsNew->MR[0x2F] |= ((cPtr->OverlaySkewY >> 8) & 0x7);
	/* Bottom Edge of Overlay*/
	ChipsNew->MR[0x30] = (cPtr->OverlaySkewY + pScrn->virtualY - 1 )& 0xFF;
	ChipsNew->MR[0x31] &= 0xF8;	/* Mask reserved bits */
	ChipsNew->MR[0x31] |= ((cPtr->OverlaySkewY + pScrn->virtualY - 
							1 ) >> 8) & 0x07;

	ChipsNew->MR[0x3C] &= 0x18;	/* Mask reserved bits */
	ChipsNew->MR[0x3C] |= 0x07;	/* Enable keyed overlay window */
	ChipsNew->MR[0x3D] = 0x00;
	ChipsNew->MR[0x3E] = 0x00;
	ChipsNew->MR[0x3F] = pScrn->colorKey; /* 8bpp transparency key */
	ChipsNew->MR[0x40] = 0xFF;
	ChipsNew->MR[0x41] = 0xFF;
	ChipsNew->MR[0x42] = 0x00;
    } else if (cPtr->Flags & ChipsVideoSupport) {
#if 0   /* if we do this even though video isn't playing we kill performance */
	ChipsNew->XR[0xD0] |= 0x10;	/* Force the Multimedia engine on */
#endif
#ifdef SAR04
	ChipsNew->XR[0x4F] = 0x2A;	/* SAR04 >352 pixel overlay width */
#endif
	ChipsNew->MR[0x3C] &= 0x18;	/* Ensure that the overlay is off */
	cPtr->VideoZoomMax = 0x100;

	if (cPtr->Chipset == CHIPS_CT65550) {
	    tmp = cPtr->readXR(cPtr, 0x04);
	    if (tmp < 0x02)				/* 65550 ES0 has */ 
		cPtr->VideoZoomMax = 0x40;		/* 0x40 max zoom */
	}
    }

    /* Program the registers */
    /*vgaHWProtect(pScrn, TRUE);*/

    if (cPtr->Chipset <= CHIPS_CT69000) {
        ChipsNew->FR[0x01] &= ~0x03;
	if (cPtr->PanelType & ChipsLCD) 
	    ChipsNew->FR[0x01] |= 0x02;
	else
	    ChipsNew->FR[0x01] |= 0x01;
    }
    if ((cPtr->Flags & ChipsDualChannelSupport) &&
	(!xf86IsEntityShared(pScrn->entityList[0]))) {
	unsigned char IOSS, MSS, tmpfr01;


	IOSS = cPtr->readIOSS(cPtr);
	MSS = cPtr->readMSS(cPtr);
	cPtr->writeIOSS(cPtr, ((cPtr->storeIOSS & IOSS_MASK) |
			       IOSS_PIPE_A));
	cPtr->writeMSS(cPtr, hwp, ((cPtr->storeMSS & MSS_MASK) |
			      MSS_PIPE_A));
	chipsRestore(pScrn, ChipsStd, ChipsNew, FALSE);
	cPtr->writeIOSS(cPtr, ((cPtr->storeIOSS & IOSS_MASK) |
			       IOSS_PIPE_B));
	cPtr->writeMSS(cPtr, hwp, ((cPtr->storeMSS & MSS_MASK) |
			      MSS_PIPE_B));
	/* 
	 * Hack:: Force Pipe-B on for dual refresh, and off elsewise
	 */
	tmpfr01 = ChipsNew->FR[0x01];
	ChipsNew->FR[0x01] &= 0xFC;
	if (cPtr->UseDualChannel)
	    ChipsNew->FR[0x01] |= 0x01;
	chipsRestore(pScrn, ChipsStd, ChipsNew, FALSE);
	ChipsNew->FR[0x01] = tmpfr01;
	cPtr->writeIOSS(cPtr, IOSS);
	cPtr->writeMSS(cPtr, hwp, MSS);
    } else {
	chipsRestore(pScrn, ChipsStd, ChipsNew, FALSE);
    }

    /*vgaHWProtect(pScrn, FALSE);*/
    usleep(100000);  /* prevents cursor corruption seen on a TECRA 510 */
    
    return(TRUE);
}

static Bool
chipsModeInitWingine(ScrnInfoPtr pScrn, DisplayModePtr mode)
{
    int i, bytesPerPixel;
    vgaHWPtr hwp = VGAHWPTR(pScrn);
    CHIPSPtr cPtr = CHIPSPTR(pScrn);
    CHIPSRegPtr ChipsNew;
    vgaRegPtr ChipsStd;
    unsigned int tmp;

    ChipsNew = &cPtr->ModeReg;
    ChipsStd = &hwp->ModeReg;

    bytesPerPixel = pScrn->bitsPerPixel >> 3;

    /* 
     * This chipset seems to have problems if 
     * HBlankEnd is choosen equals HTotal
     */
    if (!mode->CrtcHAdjusted)
      mode->CrtcHBlankEnd = min(mode->CrtcHSyncEnd, mode->CrtcHTotal - 2);

    /* correct the timings for 16/24 bpp */
    if (pScrn->bitsPerPixel == 16) {
	if (!mode->CrtcHAdjusted) {
	    mode->CrtcHDisplay++;
	    mode->CrtcHDisplay <<= 1;
	    mode->CrtcHDisplay--;
	    mode->CrtcHSyncStart <<= 1;
	    mode->CrtcHSyncEnd <<= 1;
	    mode->CrtcHBlankStart <<= 1;
	    mode->CrtcHBlankEnd <<= 1;
	    mode->CrtcHTotal <<= 1;
	    mode->CrtcHAdjusted = TRUE;
	}
    } else if (pScrn->bitsPerPixel == 24) {
	if (!mode->CrtcHAdjusted) {
	    mode->CrtcHDisplay++;
	    mode->CrtcHDisplay += ((mode->CrtcHDisplay) << 1);
	    mode->CrtcHDisplay--;
	    mode->CrtcHSyncStart += ((mode->CrtcHSyncStart) << 1);
	    mode->CrtcHSyncEnd += ((mode->CrtcHSyncEnd) << 1);
	    mode->CrtcHBlankStart += ((mode->CrtcHBlankStart) << 1);
	    mode->CrtcHBlankEnd += ((mode->CrtcHBlankEnd) << 1);
	    mode->CrtcHTotal += ((mode->CrtcHTotal) << 1);
	    mode->CrtcHAdjusted = TRUE;
	}
    }

    /* generic init */
    hwp->Flags |= VGA_FIX_SYNC_PULSES;
    if (!vgaHWInit(pScrn, mode)) {
	ErrorF("bomb 3\n");
	return (FALSE);
    }
    pScrn->vtSema = TRUE;
    
    /* init clock */
    if (!chipsClockFind(pScrn, mode->ClockIndex, &ChipsNew->Clock)) {
	ErrorF("bomb 4\n");
	return (FALSE);
    }

    /* We have horizontal blank end extension bits, so undo KGA workaround */
    vgaHWHBlankKGA(mode, ChipsStd, 0, 0);

    /* get  C&T Specific Registers */
    for (i = 0; i < 0x7D; i++) {   /* don't touch XR7D and XR7F on WINGINE */
	ChipsNew->XR[i] = cPtr->readXR(cPtr, i);
    }

    /* some generic settings */
    if (pScrn->bitsPerPixel == 1) {
	ChipsStd->Attribute[0x10] = 0x03;   /* mode */
    } else {
	ChipsStd->Attribute[0x10] = 0x01;   /* mode */
    }
    ChipsStd->Attribute[0x11] = 0x00;   /* overscan (border) color */
    ChipsStd->Attribute[0x12] = 0x0F;   /* enable all color planes */
    ChipsStd->Attribute[0x13] = 0x00;   /* horiz pixel panning 0 */

    ChipsStd->Graphics[0x05] = 0x00;    /* normal read/write mode */


    /* set virtual screen width */
    if (pScrn->bitsPerPixel >= 8)
	ChipsStd->CRTC[0x13] = (pScrn->displayWidth * bytesPerPixel) >> 3;
    else
	ChipsStd->CRTC[0x13] = pScrn->displayWidth >> 4;

    
    /* set C&T Specific Registers */
    /* set virtual screen width */
    if (pScrn->bitsPerPixel >= 8)
	tmp = (pScrn->displayWidth >> 4) * bytesPerPixel;
    else
	tmp = (pScrn->displayWidth >> 5);
    ChipsNew->XR[0x0D] = (tmp & 0x80) >> 5; 

    ChipsNew->XR[0x04] |= 4;	       /* enable addr counter bits 16-17 */
    /* XR04: Memory control 1 */
    /* bit 2: Memory Wraparound */
    /*        Enable CRTC addr counter bits 16-17 if set */

    ChipsNew->XR[0x0B] |= 0x07;       /* extended mode, dual pages enabled */
    ChipsNew->XR[0x0B] &= ~0x10;      /* linear mode off */
    /* XR0B: CPU paging */
    /* bit 0: Memory mapping mode */
    /*        VGA compatible if 0 (default) */
    /*        Extended mode (mapping for > 256 kB mem) if 1 */
    /* bit 1: CPU single/dual mapping */
    /*        0, CPU uses only a single map to access (default) */
    /*        1, CPU uses two maps to access */
    /* bit 2: CPU address divide by 4 */

    ChipsNew->XR[0x10] = 0;	       /* XR10: Single/low map */
    ChipsNew->XR[0x11] = 0;	       /* XR11: High map      */
    ChipsNew->XR[0x0C] &= ~0x50;       /* MSB for XR10 & XR11  */ 
    if (pScrn->bitsPerPixel >= 8) {
	ChipsNew->XR[0x28] |= 0x10;       /* 256-color video     */
    } else {
	ChipsNew->XR[0x28] &= 0xEF;       /* 16-color video      */
    }
    /* set up extended display timings */
    /* in CRTonly mode this is simple: only set overflow for CR00-CR06 */
    ChipsNew->XR[0x17] = ((((mode->CrtcHTotal >> 3) - 5) & 0x100) >> 8)
	| ((((mode->CrtcHDisplay >> 3) - 1) & 0x100) >> 7)
	| ((((mode->CrtcHSyncStart >> 3) - 1) & 0x100) >> 6)
	| ((((mode->CrtcHSyncEnd >> 3) - 1) & 0x20) >> 2)
	| ((((mode->CrtcHBlankStart >> 3) - 1) & 0x100) >> 4)
	| ((((mode->CrtcHBlankEnd >> 3) - 1) & 0x40) >> 1)
	| 0x40;


    ChipsNew->XR[0x16] = (((mode->CrtcVTotal - 2) & 0x400) >> 10)
	| (((mode->CrtcVDisplay - 1) & 0x400) >> 9)
	| (((mode->CrtcVSyncStart - 1) & 0x400) >> 8)
	| (((mode->CrtcVBlankStart - 1) & 0x400) >> 6)
	| 0x40;

    /* set video mode */
    ChipsNew->XR[0x2B] = chipsVideoMode(pScrn->depth, mode->CrtcHDisplay, mode->CrtcVDisplay);
#ifdef DEBUG
    ErrorF("VESA Mode: %Xh\n", ChipsNew->XR[0x2B]);
#endif

    /* set some linear specific registers */
    if (cPtr->Flags & ChipsLinearSupport) {
	/* enable linear addressing  */
	ChipsNew->XR[0x0B] &= 0xFD;   /* dual page clear                */
	ChipsNew->XR[0x0B] |= 0x10;   /* linear mode on                 */

	ChipsNew->XR[0x08] = 
	  (unsigned char)((cPtr->FbAddress >> 16) & 0xFF);    
	ChipsNew->XR[0x09] = 
	  (unsigned char)((cPtr->FbAddress >> 24) & 0xFF);    

	/* general setup */
	ChipsNew->XR[0x40] = 0x01;    /*BitBLT Draw Mode for 8 and 24 bpp */
    }

    /* common general setup */
    ChipsNew->XR[0x52] |= 0x01;       /* Refresh count                   */
    ChipsNew->XR[0x0F] &= 0xEF;       /* not Hi-/True-Colour             */
    ChipsNew->XR[0x02] &= 0xE7;       /* Attr. Cont. default access      */
                                       /* use ext. regs. for hor. in dual */
    ChipsNew->XR[0x06] &= 0xF3;       /* bpp clear                       */

    /* bpp depend */
    /*XR06: Palette control */
    /* bit 0: Pixel Data Pin Diag, 0 for flat panel pix. data (def)  */
    /* bit 1: Internal DAC disable                                   */
    /* bit 3-2: Colour depth, 0 for 4 or 8 bpp, 1 for 16(5-5-5) bpp, */
    /*          2 for 24 bpp, 3 for 16(5-6-5)bpp                     */
    /* bit 4:   Enable PC Video Overlay on colour key                */
    /* bit 5:   Bypass Internal VGA palette                          */
    /* bit 7-6: Colour reduction select, 0 for NTSC (default),       */
    /*          1 for Equivalent weighting, 2 for green only,        */
    /*          3 for Colour w/o reduction                           */
    /* XR50 Panel Format Register 1                                  */
    /* bit 1-0: Frame Rate Control; 00, No FRC;                      */
    /*          01, 16-frame FRC for colour STN and monochrome       */
    /*          10, 2-frame FRC for colour TFT or monochrome;        */
    /*          11, reserved                                         */
    /* bit 3-2: Dither Enable                                        */
    /*          00, disable dithering; 01, enable dithering          */
    /*          for 256 mode                                         */
    /*          10, enable dithering for all modes; 11, reserved     */
    /* bit6-4: Clock Divide (CD)                                     */
    /*          000, Shift Clock Freq = Dot Clock Freq;              */
    /*          001, SClk = DClk/2; 010 SClk = DClk/4;               */
    /*          011, SClk = DClk/8; 100 SClk = DClk/16;              */
    /* bit 7: TFT data width                                         */
    /*          0, 16 bit(565RGB); 1, 24bit (888RGB)                 */
    if (pScrn->bitsPerPixel == 16) {
	ChipsNew->XR[0x06] |= 0xC4;   /*15 or 16 bpp colour         */
	ChipsNew->XR[0x0F] |= 0x10;   /*Hi-/True-Colour             */
	ChipsNew->XR[0x40] = 0x02;    /*BitBLT Draw Mode for 16 bpp */
	if (pScrn->weight.green != 5)
	    ChipsNew->XR[0x06] |= 0x08;	/*16bpp              */
    } else if (pScrn->bitsPerPixel == 24) {
	ChipsNew->XR[0x06] |= 0xC8;   /*24 bpp colour               */
	ChipsNew->XR[0x0F] |= 0x10;   /*Hi-/True-Colour             */
    }

    /*CRT only: interlaced mode */
    if (mode->Flags & V_INTERLACE) {
	ChipsNew->XR[0x28] |= 0x20;    /* set interlace         */
	/* empirical value       */
	tmp = ((((mode->CrtcHDisplay >> 3) - 1) >> 1) 
	       - 6 * (pScrn->bitsPerPixel >= 8 ? bytesPerPixel : 1 ));
	ChipsNew->XR[0x19] = tmp & 0xFF;
	ChipsNew->XR[0x17] |= ((tmp & 0x100) >> 1); /* overflow */
	ChipsNew->XR[0x0F] &= ~0x40;   /* set SW-Flag           */
    } else {
	ChipsNew->XR[0x28] &= ~0x20;   /* unset interlace       */
	ChipsNew->XR[0x0F] |=  0x40;   /* set SW-Flag           */
    }

    /* Program the registers */
    /*vgaHWProtect(pScrn, TRUE);*/
    chipsRestore(pScrn, ChipsStd, ChipsNew, FALSE);
    /*vgaHWProtect(pScrn, FALSE);*/

    return (TRUE);
}

static Bool
chipsModeInit655xx(ScrnInfoPtr pScrn, DisplayModePtr mode)
{
    int i, bytesPerPixel;
    int lcdHTotal, lcdHDisplay;
    int lcdVTotal, lcdVDisplay;
    int lcdHRetraceStart, lcdHRetraceEnd;
    int lcdVRetraceStart, lcdVRetraceEnd;
    int HSyncStart, HDisplay;
    int CrtcHDisplay;
    vgaHWPtr hwp = VGAHWPTR(pScrn);
    CHIPSPtr cPtr = CHIPSPTR(pScrn);
    CHIPSRegPtr ChipsNew;
    vgaRegPtr ChipsStd;
    unsigned int tmp;

    ChipsNew = &cPtr->ModeReg;
    ChipsStd = &hwp->ModeReg;

    bytesPerPixel = pScrn->bitsPerPixel >> 3;

    /*
     * Possibly fix up the panel size, if the manufacture is stupid
     * enough to set it incorrectly in text modes
     */
    if (xf86ReturnOptValBool(cPtr->Options, OPTION_PANEL_SIZE, FALSE)) {
	cPtr->PanelSize.HDisplay = mode->CrtcHDisplay;
	cPtr->PanelSize.VDisplay = mode->CrtcVDisplay;
    }
    
    /* 
     * This chipset seems to have problems if 
     * HBlankEnd is choosen equals HTotal
     */
    if (!mode->CrtcHAdjusted)
      mode->CrtcHBlankEnd = min(mode->CrtcHSyncEnd, mode->CrtcHTotal - 2);

    /* correct the timings for 16/24 bpp */
    if (pScrn->bitsPerPixel == 16) {
	if (!mode->CrtcHAdjusted) {
	    mode->CrtcHDisplay++;
	    mode->CrtcHDisplay <<= 1;
	    mode->CrtcHDisplay--;
	    mode->CrtcHSyncStart <<= 1;
	    mode->CrtcHSyncEnd <<= 1;
	    mode->CrtcHBlankStart <<= 1;
	    mode->CrtcHBlankEnd <<= 1;
	    mode->CrtcHTotal <<= 1;
	    mode->CrtcHAdjusted = TRUE;
	}
    } else if (pScrn->bitsPerPixel == 24) {
	if (!mode->CrtcHAdjusted) {
	    mode->CrtcHDisplay++;
	    mode->CrtcHDisplay += ((mode->CrtcHDisplay) << 1);
	    mode->CrtcHDisplay--;
	    mode->CrtcHSyncStart += ((mode->CrtcHSyncStart) << 1);
	    mode->CrtcHSyncEnd += ((mode->CrtcHSyncEnd) << 1);
	    mode->CrtcHBlankStart += ((mode->CrtcHBlankStart) << 1);
	    mode->CrtcHBlankEnd += ((mode->CrtcHBlankEnd) << 1);
	    mode->CrtcHTotal += ((mode->CrtcHTotal) << 1);
	    mode->CrtcHAdjusted = TRUE;
	}
    }
	   
    /* store orig. HSyncStart needed for flat panel mode */
    HSyncStart = mode->CrtcHSyncStart / (pScrn->bitsPerPixel >= 8 ? 
					 bytesPerPixel : 1 ) - 16;
    HDisplay = (mode->CrtcHDisplay + 1) /  (pScrn->bitsPerPixel >= 8 ? 
					 bytesPerPixel : 1 );
    
    /* generic init */
    hwp->Flags |= VGA_FIX_SYNC_PULSES;
    if (!vgaHWInit(pScrn, mode)) {
	ErrorF("bomb 5\n");
	return (FALSE);
    }
    pScrn->vtSema = TRUE;

    /* We have horizontal blank end extension bits, so undo KGA workaround */
    vgaHWHBlankKGA(mode, ChipsStd, 0, 0);

    /* init clock */
    if (!chipsClockFind(pScrn, mode->ClockIndex, &ChipsNew->Clock)) {
	ErrorF("bomb 6\n");
	return (FALSE);
    }

    /* get  C&T Specific Registers */
    for (i = 0; i < 0x80; i++) {
	ChipsNew->XR[i] = cPtr->readXR(cPtr, i);
    }

    /* some generic settings */
    if (pScrn->bitsPerPixel == 1) {
	ChipsStd->Attribute[0x10] = 0x03;   /* mode */
    } else {
	ChipsStd->Attribute[0x10] = 0x01;   /* mode */
    }
    ChipsStd->Attribute[0x11] = 0x00;   /* overscan (border) color */
    ChipsStd->Attribute[0x12] = 0x0F;   /* enable all color planes */
    ChipsStd->Attribute[0x13] = 0x00;   /* horiz pixel panning 0 */

    ChipsStd->Graphics[0x05] = 0x00;    /* normal read/write mode */

    /* set virtual screen width */
    if (pScrn->bitsPerPixel >= 8)
	ChipsStd->CRTC[0x13] = (pScrn->displayWidth * bytesPerPixel) >> 3;
    else
	ChipsStd->CRTC[0x13] = pScrn->displayWidth >> 4;

    
    /* set C&T Specific Registers */
    /* set virtual screen width */
    ChipsNew->XR[0x1E] = ChipsStd->CRTC[0x13];	/* alternate offset */
    /*databook is not clear about 0x1E might be needed for 65520/30 */
    if (pScrn->bitsPerPixel >= 8)
	tmp = (pScrn->displayWidth * bytesPerPixel) >> 2;
    else
	tmp = pScrn->displayWidth >> 3;
    ChipsNew->XR[0x0D] = (tmp & 0x01) | ((tmp << 1) & 0x02)  ; 

    ChipsNew->XR[0x04] |= 4;	       /* enable addr counter bits 16-17 */
    /* XR04: Memory control 1 */
    /* bit 2: Memory Wraparound */
    /*        Enable CRTC addr counter bits 16-17 if set */

    ChipsNew->XR[0x0B] |= 0x07;       /* extended mode, dual pages enabled */
    ChipsNew->XR[0x0B] &= ~0x10;      /* linear mode off */
    /* XR0B: CPU paging */
    /* bit 0: Memory mapping mode */
    /*        VGA compatible if 0 (default) */
    /*        Extended mode (mapping for > 256 kB mem) if 1 */
    /* bit 1: CPU single/dual mapping */
    /*        0, CPU uses only a single map to access (default) */
    /*        1, CPU uses two maps to access */
    /* bit 2: CPU address divide by 4 */

    ChipsNew->XR[0x10] = 0;	       /* XR10: Single/low map */
    ChipsNew->XR[0x11] = 0;	       /* XR11: High map      */
    if (pScrn->bitsPerPixel >= 8) {
	ChipsNew->XR[0x28] |= 0x10;       /* 256-color video     */
    } else {
	ChipsNew->XR[0x28] &= 0xEF;       /* 16-color video      */
    }
    /* set up extended display timings */
    if (!(cPtr->PanelType & ChipsLCD)) {
	/* in CRTonly mode this is simple: only set overflow for CR00-CR06 */
	ChipsNew->XR[0x17] = ((((mode->CrtcHTotal >> 3) - 5) & 0x100) >> 8)
	    | ((((mode->CrtcHDisplay >> 3) - 1) & 0x100) >> 7)
	    | ((((mode->CrtcHSyncStart >> 3) - 1) & 0x100) >> 6)
	    | ((((mode->CrtcHSyncEnd >> 3) - 1) & 0x20) >> 2)
	    | ((((mode->CrtcHBlankStart >> 3) - 1) & 0x100) >> 4)
	    | ((((mode->CrtcHBlankEnd >> 3) - 1) & 0x40) >> 1)
	    | 0x40;

	ChipsNew->XR[0x16] = (((mode->CrtcVTotal - 2) & 0x400) >> 10)
	    | (((mode->CrtcVDisplay - 1) & 0x400) >> 9)
	    | (((mode->CrtcVSyncStart - 1) & 0x400) >> 8)
	    | (((mode->CrtcVBlankStart - 1) & 0x400) >> 6)
	    | 0x40;
    } else {
	/* horizontal timing registers */
	/* in LCD/dual mode use saved bios values to derive timing values if
	 * not told otherwise */
	if (!xf86ReturnOptValBool(cPtr->Options, OPTION_USE_MODELINE, FALSE)) {
	    lcdHTotal = cPtr->PanelSize.HTotal;
	    lcdHRetraceStart = cPtr->PanelSize.HRetraceStart;
	    lcdHRetraceEnd = cPtr->PanelSize.HRetraceEnd;
	    if (pScrn->bitsPerPixel == 16) {
		lcdHRetraceStart <<= 1;
		lcdHRetraceEnd <<= 1;
		lcdHTotal <<= 1;
	    } else if (pScrn->bitsPerPixel == 24) {
		lcdHRetraceStart += (lcdHRetraceStart << 1);
		lcdHRetraceEnd += (lcdHRetraceEnd << 1);
		lcdHTotal += (lcdHTotal << 1);
	    }
#if 0	/* This should no longer be needed */
 	    lcdHRetraceStart -=8;       /* HBlank =  HRetrace - 1: for */
 	    lcdHRetraceEnd   -=8;       /* compatibility with vgaHW.c  */
#endif
	} else {
	    /* use modeline values if bios values don't work */
	    lcdHTotal = mode->CrtcHTotal;
	    lcdHRetraceStart = mode->CrtcHSyncStart;
	    lcdHRetraceEnd = mode->CrtcHSyncEnd;
	}
	/* The chip takes the size of the visible display area from the
	 * CRTC values. We use bios screensize for LCD in LCD/dual mode
	 * wether or not we use modeline for LCD. This way we can specify
	 * always specify a smaller than default display size on LCD
	 * by writing it to the CRTC registers. */
	lcdHDisplay = cPtr->PanelSize.HDisplay;
	if (pScrn->bitsPerPixel == 16) {
	    lcdHDisplay++;
	    lcdHDisplay <<= 1;
	    lcdHDisplay--;
	} else if (pScrn->bitsPerPixel == 24) {
	    lcdHDisplay++;
	    lcdHDisplay += (lcdHDisplay << 1);
	    lcdHDisplay--;
	}
	lcdHTotal = (lcdHTotal >> 3) - 5;
	lcdHDisplay = (lcdHDisplay >> 3) - 1;
	lcdHRetraceStart = (lcdHRetraceStart >> 3) - 1;
	lcdHRetraceEnd = (lcdHRetraceEnd >> 3) - 1;
	/* This ugly hack is needed because CR01 and XR1C share the 8th bit!*/
	CrtcHDisplay = ((mode->CrtcHDisplay >> 3) - 1);
	if ((lcdHDisplay & 0x100) != (CrtcHDisplay & 0x100)) {
	    xf86ErrorF("This display configuration might cause problems !\n");
	    lcdHDisplay = 255;
	}

	/* now init register values */
	/* XXX  What about Line Compare and/or HBlank pulse and/or XR16? */
	ChipsNew->XR[0x17] = ((lcdHTotal & 0x100) >> 8)
	    | ((lcdHDisplay & 0x100) >> 7)
	    | ((lcdHRetraceStart & 0x100) >> 6)
	    | ((lcdHRetraceEnd & 0x20) >> 2);

	ChipsNew->XR[0x19] = lcdHRetraceStart & 0xFF;
	ChipsNew->XR[0x1A] = lcdHRetraceEnd & 0x1F;

	/* XR1B: Alternate horizontal total */
	/* used in all flat panel mode with horiz. compression disabled, */
	/* CRT CGA text and graphic modes and Hercules graphics mode */
	/* similar to CR00, actual value - 5 */
	ChipsNew->XR[0x1B] = lcdHTotal & 0xFF;

	/*XR1C: Alternate horizontal blank start (CRT mode) */
	/*      /horizontal panel size (FP mode) */
	/* FP horizontal panel size (FP mode), */
	/* actual value - 1 (in characters unit) */
	/* CRT horizontal blank start (CRT mode) */
	/* similar to CR02, actual value - 1 */
	ChipsNew->XR[0x1C] = lcdHDisplay & 0xFF;

	if (xf86ReturnOptValBool(cPtr->Options, OPTION_USE_MODELINE, FALSE)) {
	    /* for ext. packed pixel mode on 64520/64530 */
	    /* no need to rescale: used only in 65530    */
	    ChipsNew->XR[0x21] = lcdHRetraceStart & 0xFF;
	    ChipsNew->XR[0x22] = lcdHRetraceEnd & 0x1F;
	    ChipsNew->XR[0x23] = lcdHTotal & 0xFF;

	    /* vertical timing registers */
	    lcdVTotal = mode->CrtcVTotal - 2;
	    lcdVDisplay = cPtr->PanelSize.VDisplay - 1;
	    lcdVRetraceStart = mode->CrtcVSyncStart - 1;
	    lcdVRetraceEnd = mode->CrtcVSyncEnd - 1;

	    ChipsNew->XR[0x64] = lcdVTotal & 0xFF;
	    ChipsNew->XR[0x65] = ((lcdVTotal & 0x100) >> 8)
		| ((lcdVDisplay & 0x100) >> 7)
		| ((lcdVRetraceStart & 0x100) >> 6)
		| ((lcdVRetraceStart & 0x400) >> 7)
		| ((lcdVTotal & 0x400) >> 6)
		| ((lcdVTotal & 0x200) >> 4)
		| ((lcdVDisplay & 0x200) >> 3)
		| ((lcdVRetraceStart & 0x200) >> 2);
	    ChipsNew->XR[0x66] = lcdVRetraceStart & 0xFF;
	    ChipsNew->XR[0x67] = lcdVRetraceEnd & 0x0F;
	    ChipsNew->XR[0x68] = lcdVDisplay & 0xFF;

	    /* 
	     * These are important: 0x2C specifies the numbers of lines 
	     * (hsync pulses) between vertical blank start and vertical 
	     * line total, 0x2D specifies the number of clock ticks? to
	     * horiz. blank start ( caution ! 16bpp/24bpp modes: that's
	     * why we need HSyncStart - can't use mode->CrtcHSyncStart) 
	     */
	    tmp = ((cPtr->PanelType & ChipsDD) && !(ChipsNew->XR[0x6F] & 0x02))
	      ? 1 : 0; /* double LP delay, FLM: 2 lines iff DD+no acc*/
	    /* Currently we support 2 FLM schemes: #1: FLM coincides with
	     * VTotal ie. the delay is programmed to the difference bet-
	     * ween lctVTotal and lcdVRetraceStart.    #2: FLM coincides
	     * lcdVRetraceStart - in this case FLM delay will be turned
	     * off. To decide which scheme to use we compare the value of
	     * XR2C set by the bios to the two schemes. The one that fits
	     * better will be used.
	     */

	    if (ChipsNew->XR[0x2C]  < abs((cPtr->PanelSize.VTotal -
		    cPtr->PanelSize.VRetraceStart - tmp - 1) -
		    ChipsNew->XR[0x2C]))
	        ChipsNew->XR[0x2F] |= 0x80;   /* turn FLM delay off */
	    ChipsNew->XR[0x2C] = lcdVTotal - lcdVRetraceStart - tmp;
	    /*ChipsNew->XR[0x2D] = (HSyncStart >> (3 - tmp)) & 0xFF;*/
	    ChipsNew->XR[0x2D] = (HDisplay >> (3 - tmp)) & 0xFF;
	    ChipsNew->XR[0x2F] = (ChipsNew->XR[0x2F] & 0xDF)
		| (((HSyncStart >> (3 - tmp)) & 0x100) >> 3);
	}

	/* set stretching/centering */	
	if (!xf86ReturnOptValBool(cPtr->Options, OPTION_SUSPEND_HACK, FALSE)) {
	    ChipsNew->XR[0x51] |= 0x40;   /* enable FP compensation          */
	    ChipsNew->XR[0x55] |= 0x01;   /* enable horiz. compensation      */
	    ChipsNew->XR[0x57] |= 0x01;   /* enable horiz. compensation      */
	    if (!xf86ReturnOptValBool(cPtr->Options, OPTION_LCD_STRETCH,
				     FALSE)) {
		if (mode->CrtcHDisplay < 1489)      /* HWBug                 */
		    ChipsNew->XR[0x55] |= 0x02;	/* enable auto h-centering   */
		else {
		    ChipsNew->XR[0x55] &= 0xFD;	/* disable auto h-centering  */
		    if (pScrn->bitsPerPixel == 24) /* ? */
			ChipsNew->XR[0x56] = (lcdHDisplay - CrtcHDisplay) >> 1;
		}
	    } else {
	      ChipsNew->XR[0x55] &= 0xFD;	/* disable h-centering    */
	      ChipsNew->XR[0x56] = 0;
	    }
	    ChipsNew->XR[0x57] = 0x03;    /* enable v-comp disable v-stretch */
	    if (!xf86ReturnOptValBool(cPtr->Options, OPTION_LCD_STRETCH,
				      FALSE)) {
		ChipsNew->XR[0x55] |= 0x20; /* enable h-comp disable h-double*/
		ChipsNew->XR[0x57] |= 0x60; /* Enable vertical stretching    */
		tmp = (mode->CrtcVDisplay / (cPtr->PanelSize.VDisplay -
		    mode->CrtcVDisplay + 1));
		if (tmp) {
			if (cPtr->PanelSize.HDisplay
			    && cPtr->PanelSize.VDisplay
			    && (cPtr->PanelSize.HDisplay != mode->CrtcHDisplay)
			 && (cPtr->PanelSize.VDisplay != mode->CrtcVDisplay)) {
			    /* Possible H/W bug? */
			    if(cPtr->Accel.UseHWCursor)
				xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
				    "Disabling HW Cursor on stretched LCD\n");
			    cPtr->Flags &= ~ChipsHWCursor;
			}
		    }
		if (cPtr->Flags & ChipsHWCursor)
		    tmp = (tmp == 0 ? 1 : tmp);  /* Bug when doubling */
		ChipsNew->XR[0x5A] = tmp > 0x0F ? 0 : (unsigned char)tmp;
	    } else {
		ChipsNew->XR[0x55] &= 0xDF; /* disable h-comp, h-double */
		ChipsNew->XR[0x57] &= 0x9F; /* disable vertical stretching  */
	    }
	}
    }

    /* set video mode */
    ChipsNew->XR[0x2B] = chipsVideoMode(pScrn->depth, (cPtr->PanelType & ChipsLCD) ?
	min(HDisplay, cPtr->PanelSize.HDisplay) : HDisplay,cPtr->PanelSize.VDisplay);
#ifdef DEBUG
    ErrorF("VESA Mode: %Xh\n", ChipsNew->XR[0x2B]);
#endif

    /* set some linear specific registers */
    if (cPtr->Flags & ChipsLinearSupport) {
	/* enable linear addressing  */
	ChipsNew->XR[0x0B] &= 0xFD;   /* dual page clear                */
	ChipsNew->XR[0x0B] |= 0x10;   /* linear mode on                 */
 	if (cPtr->Chipset == CHIPS_CT65535)
 	    ChipsNew->XR[0x08] = (unsigned char)(cPtr->FbAddress >> 17);
 	else if (cPtr->Chipset > CHIPS_CT65535)
 	    ChipsNew->XR[0x08] = (unsigned char)(cPtr->FbAddress >> 20);
	else {
            /* Its probably set correctly by BIOS anyway. Leave it alone    */
	    /* 65525 - 65530 require XR04[6] set for greater than 512k of   */
            /* ram. We only correct obvious bugs; VL probably uses MEMR/MEMW*/
	    if (cPtr->Bus == ChipsISA)
		ChipsNew->XR[0x04] &= ~0x40;  /* A19 sceme       */
	    if (pScrn->videoRam > 512)
		ChipsNew->XR[0x04] |= 0x40;   /* MEMR/MEMW sceme */
	}

	/* general setup */
	ChipsNew->XR[0x03] |= 0x08;   /* High bandwidth on 65548         */
	ChipsNew->XR[0x40] = 0x01;    /*BitBLT Draw Mode for 8 and 24 bpp */
    }

    /* common general setup */
    ChipsNew->XR[0x52] |= 0x01;       /* Refresh count                   */
    ChipsNew->XR[0x0F] &= 0xEF;       /* not Hi-/True-Colour             */
    ChipsNew->XR[0x02] |= 0x01;       /* 16bit CPU Memory Access         */
    ChipsNew->XR[0x02] &= 0xE3;       /* Attr. Cont. default access      */
                                      /* use ext. regs. for hor. in dual */
    ChipsNew->XR[0x06] &= 0xF3;       /* bpp clear                       */

    /* PCI */
    if (cPtr->Bus == ChipsPCI)
	ChipsNew->XR[0x03] |= 0x40;   /*PCI burst */
    
    /* sync. polarities */
    if ((mode->Flags & (V_PHSYNC | V_NHSYNC))
	&& (mode->Flags & (V_PVSYNC | V_NVSYNC))) {
	if (mode->Flags & (V_PHSYNC | V_NHSYNC)) {
	    if (mode->Flags & V_PHSYNC) {
		ChipsNew->XR[0x55] &= 0xBF;	/* CRT Hsync positive */
	    } else {
		ChipsNew->XR[0x55] |= 0x40;	/* CRT Hsync negative */
	    }
	}
	if (mode->Flags & (V_PVSYNC | V_NVSYNC)) {
	    if (mode->Flags & V_PVSYNC) {
		ChipsNew->XR[0x55] &= 0x7F;	/* CRT Vsync positive */
	    } else {
		ChipsNew->XR[0x55] |= 0x80;	/* CRT Vsync negative */
	    }
	}
    }

    /* bpp depend */
    /*XR06: Palette control */
    /* bit 0: Pixel Data Pin Diag, 0 for flat panel pix. data (def)  */
    /* bit 1: Internal DAC disable                                   */
    /* bit 3-2: Colour depth, 0 for 4 or 8 bpp, 1 for 16(5-5-5) bpp, */
    /*          2 for 24 bpp, 3 for 16(5-6-5)bpp                     */
    /* bit 4:   Enable PC Video Overlay on colour key                */
    /* bit 5:   Bypass Internal VGA palette                          */
    /* bit 7-6: Colour reduction select, 0 for NTSC (default),       */
    /*          1 for Equivalent weighting, 2 for green only,        */
    /*          3 for Colour w/o reduction                           */
    /* XR50 Panel Format Register 1                                  */
    /* bit 1-0: Frame Rate Control; 00, No FRC;                      */
    /*          01, 16-frame FRC for colour STN and monochrome       */
    /*          10, 2-frame FRC for colour TFT or monochrome;        */
    /*          11, reserved                                         */
    /* bit 3-2: Dither Enable                                        */
    /*          00, disable dithering; 01, enable dithering          */
    /*          for 256 mode                                         */
    /*          10, enable dithering for all modes; 11, reserved     */
    /* bit6-4: Clock Divide (CD)                                     */
    /*          000, Shift Clock Freq = Dot Clock Freq;              */
    /*          001, SClk = DClk/2; 010 SClk = DClk/4;               */
    /*          011, SClk = DClk/8; 100 SClk = DClk/16;              */
    /* bit 7: TFT data width                                         */
    /*          0, 16 bit(565RGB); 1, 24bit (888RGB)                 */
    if (pScrn->bitsPerPixel == 16) {
	ChipsNew->XR[0x06] |= 0xC4;   /*15 or 16 bpp colour         */
	ChipsNew->XR[0x0F] |= 0x10;   /*Hi-/True-Colour             */
	ChipsNew->XR[0x40] = 0x02;    /*BitBLT Draw Mode for 16 bpp */
	if (pScrn->weight.green != 5)
	    ChipsNew->XR[0x06] |= 0x08;	/*16bpp              */
    } else if (pScrn->bitsPerPixel == 24) {
	ChipsNew->XR[0x06] |= 0xC8;   /*24 bpp colour               */
	ChipsNew->XR[0x0F] |= 0x10;   /*Hi-/True-Colour             */
	if (xf86ReturnOptValBool(cPtr->Options, OPTION_18_BIT_BUS, FALSE)) {
	    ChipsNew->XR[0x50] &= 0x7F;   /*18 bit TFT data width   */
	} else {
	    ChipsNew->XR[0x50] |= 0x80;   /*24 bit TFT data width   */
	}
    }

    /*CRT only: interlaced mode */
    if (!(cPtr->PanelType & ChipsLCD)) {
	if (mode->Flags & V_INTERLACE){
	    ChipsNew->XR[0x28] |= 0x20;    /* set interlace         */
	    /* empirical value       */
	    tmp = ((((mode->CrtcHDisplay >> 3) - 1) >> 1) 
		- 6 * (pScrn->bitsPerPixel >= 8 ? bytesPerPixel : 1 ));
	    if(cPtr->Chipset < CHIPS_CT65535)
		ChipsNew->XR[0x19] = tmp & 0xFF;
	    else
		ChipsNew->XR[0x29] = tmp & 0xFF;
 	    ChipsNew->XR[0x0F] &= ~0x40;   /* set SW-Flag           */
	} else {
	    ChipsNew->XR[0x28] &= ~0x20;   /* unset interlace       */
 	    ChipsNew->XR[0x0F] |=  0x40;   /* set SW-Flag           */
	}
    }

    /* STN specific */
    if (IS_STN(cPtr->PanelType)) {
	ChipsNew->XR[0x50] &= ~0x03;  /* FRC clear                  */
	ChipsNew->XR[0x50] |= 0x01;   /* 16 frame FRC               */
	ChipsNew->XR[0x50] &= ~0x0C;  /* Dither clear               */
	ChipsNew->XR[0x50] |= 0x08;   /* Dither all modes           */
 	if (cPtr->Chipset == CHIPS_CT65548) {
	    ChipsNew->XR[0x03] |= 0x20; /* CRT I/F priority           */
	    ChipsNew->XR[0x04] |= 0x10; /* RAS precharge 65548        */
	}
    }

    /* This stuff was emprically derived several years ago. Not sure its 
     * still needed, and I'd love to get rid of it as its ugly
     */
    switch (cPtr->Chipset) {
    case CHIPS_CT65545:		  /*jet mini *//*DEC HighNote Ultra DSTN */
	ChipsNew->XR[0x03] |= 0x10;   /* do not hold off CPU for palette acc*/
	break;
    case CHIPS_CT65546:			       /*CT 65546, only for Toshiba */
	ChipsNew->XR[0x05] |= 0x80;   /* EDO RAM enable */
	break;
    }
    
    if (cPtr->PanelType & ChipsLCD) 
        ChipsNew->XR[0x51] |= 0x04;
    else 
        ChipsNew->XR[0x51] &= ~0x04;

    /* Program the registers */
    /*vgaHWProtect(pScrn, TRUE);*/
    chipsRestore(pScrn, ChipsStd, ChipsNew, FALSE);
    /*vgaHWProtect(pScrn, FALSE);*/

    return (TRUE);
}

static void 
chipsRestore(ScrnInfoPtr pScrn, vgaRegPtr VgaReg, CHIPSRegPtr ChipsReg,
	     Bool restoreFonts)
{
    vgaHWPtr hwp = VGAHWPTR(pScrn);
    CHIPSPtr cPtr = CHIPSPTR(pScrn);
    unsigned char tmp = 0;

    /*vgaHWProtect(pScrn, TRUE);*/

    /* set registers so that we can program the controller */
    if (IS_HiQV(cPtr)) {
	cPtr->writeXR(cPtr, 0x0E, 0x00);
	if (cPtr->Flags & ChipsDualChannelSupport) {
	    tmp = cPtr->readFR(cPtr, 0x01);		/* Disable pipeline */
	    cPtr->writeFR(cPtr, 0x01, (tmp & 0xFC));
	    cPtr->writeFR(cPtr, 0x02, 0x00);		/* CRT/FP off */
	}
    } else {
	cPtr->writeXR(cPtr, 0x10, 0x00);
	cPtr->writeXR(cPtr, 0x11, 0x00);
	tmp = cPtr->readXR(cPtr, 0x0C) & ~0x50; /* WINgine stores MSB here */
	cPtr->writeXR(cPtr, 0x0C, tmp);
	cPtr->writeXR(cPtr, 0x15, 0x00); /* unprotect all registers */
	tmp = cPtr->readXR(cPtr, 0x14); 
	cPtr->writeXR(cPtr, 0x14, tmp & ~0x20);  /* enable vsync on ST01 */
    }

    chipsFixResume(pScrn);

    /* 
     * Wait for vsync if sequencer is running - stop sequencer.
     * Only do if sync reset is ignored. Dual pipeline capable 
     * chips have pipeline forced off here, so we don't care. 
     */
    if ((cPtr->SyncResetIgn)  && (!(cPtr->Flags & ChipsDualChannelSupport))) {
	while (((hwp->readST01(hwp)) & 0x08) == 0x08); /* VSync off */
	while (((hwp->readST01(hwp)) & 0x08) == 0x00); /* VSync on  */
	hwp->writeSeq(hwp, 0x07, 0x00); /* reset hsync - just in case...  */
    }

    /* set the clock */
    chipsClockLoad(pScrn, &ChipsReg->Clock);
    /* chipsClockLoad() sets this so we don't want vgaHWRestore() change it */
    VgaReg->MiscOutReg = inb(cPtr->PIOBase + 0x3CC);
	
    /* set extended regs */
    chipsRestoreExtendedRegs(pScrn, ChipsReg);
#if 0
    /* if people complain about lock ups or blank screens -- reenable */
    /* set CRTC registers - do it before sequencer restarts */
    for (i=0; i<25; i++) 
	hwp->writeCrtc(hwp, i, VgaReg->CRTC[i]);
#endif
    /* set generic registers */
    /* 
     * Enabling writing to the colourmap causes 69030's to lock. 
     * Anyone care to explain to me why ????
     */
    if (cPtr->Flags & ChipsDualChannelSupport) {
        /* Enable pipeline if needed */
        cPtr->writeFR(cPtr, 0x01, ChipsReg->FR[0x01]);
	cPtr->writeFR(cPtr, 0x02, ChipsReg->FR[0x02]);
	vgaHWRestore(pScrn, VgaReg, VGA_SR_MODE |
		(restoreFonts ? VGA_SR_FONTS : 0));
    } else {
	vgaHWRestore(pScrn, VgaReg, VGA_SR_MODE | VGA_SR_CMAP | 
		     (restoreFonts ? VGA_SR_FONTS : 0));
    }

    /* set stretching registers */
    if (IS_HiQV(cPtr)) {
	chipsRestoreStretching(pScrn, (unsigned char)ChipsReg->FR[0x40],
			       (unsigned char)ChipsReg->FR[0x48]);
#if 0 
	/* if people report about stretching not working -- reenable */
	/* why twice ? :
	 * sometimes the console is not well restored even if these registers 
	 * are good, re-write the registers works around it
	 */
	chipsRestoreStretching(pScrn, (unsigned char)ChipsReg->FR[0x40],
			       (unsigned char)ChipsReg->FR[0x48]);
#endif
    } else if (!IS_Wingine(cPtr))
	chipsRestoreStretching(pScrn, (unsigned char)ChipsReg->XR[0x55],
			       (unsigned char)ChipsReg->XR[0x57]);

    /* perform a synchronous reset */
    if (!cPtr->SyncResetIgn) {
	if (!IS_HiQV(cPtr)) {
	    /* enable syncronous reset on 655xx */
	    tmp = cPtr->readXR(cPtr, 0x0E);
	    cPtr->writeXR(cPtr, 0x0E, tmp & 0x7F);
	}
	hwp->writeSeq(hwp, 0x00, 0x01);
	usleep(10000);
	hwp->writeSeq(hwp, 0x00, 0x03);
	if (!IS_HiQV(cPtr))
	    cPtr->writeXR(cPtr, 0x0E, tmp);
    }
    /* Flag valid start address, if using CRT extensions */
    if (IS_HiQV(cPtr) && (ChipsReg->XR[0x09] & 0x1) == 0x1) {
	tmp = hwp->readCrtc(hwp, 0x40);
	hwp->writeCrtc(hwp, 0x40, tmp | 0x80);
    }

    /* Fix resume again here, as Nozomi seems to need it          */
     chipsFixResume(pScrn);
    /*vgaHWProtect(pScrn, FALSE);*/

#if 0
     /* Enable pipeline if needed */
     if (cPtr->Flags & ChipsDualChannelSupport) {
	cPtr->writeFR(cPtr, 0x01, ChipsReg->FR[0x01]);
	cPtr->writeFR(cPtr, 0x02, ChipsReg->FR[0x02]);
     }
#endif
}

static void
chipsRestoreExtendedRegs(ScrnInfoPtr pScrn, CHIPSRegPtr Regs)
{
    vgaHWPtr hwp = VGAHWPTR(pScrn);
    CHIPSPtr cPtr = CHIPSPTR(pScrn);
    int i;
    unsigned char tmp;

    if (IS_HiQV(cPtr)) {
	/* set extended regs */
	for (i = 0; i < 0x43; i++) {
	    if ((cPtr->readXR(cPtr, i)) != Regs->XR[i])
		cPtr->writeXR(cPtr, i, Regs->XR[i]);
	}

	/* Set SAR04 multimedia register correctly */
	if ((cPtr->Flags & ChipsOverlay8plus16)
	    || (cPtr->Flags & ChipsVideoSupport)) {
#ifdef SAR04
	    cPtr->writeXR(cPtr, 0x4E, 0x04);
	    if (cPtr->readXR(cPtr, 0x4F) != Regs->XR[0x4F])
		cPtr->writeXR(cPtr, 0x4F, Regs->XR[0x4F]);
#endif
	}

	/* Don't touch reserved memory control registers */
	for (i = 0x50; i < 0xBF; i++) {
	    if ((cPtr->readXR(cPtr, i)) != Regs->XR[i])
		cPtr->writeXR(cPtr, i, Regs->XR[i]);
	}
	/* Don't touch VCLK regs, but fix up MClk */
	
	/* set mem clock */
	tmp = cPtr->readXR(cPtr, 0xCE); /* Select Fixed MClk before */
	cPtr->writeXR(cPtr, 0xCE, tmp & 0x7F);
	if ((cPtr->readXR(cPtr, 0xCC)) != Regs->XR[0xCC])
	    cPtr->writeXR(cPtr, 0xCC, Regs->XR[0xCC]);
	if ((cPtr->readXR(cPtr, 0xCD)) != Regs->XR[0xCD])
	    cPtr->writeXR(cPtr, 0xCD, Regs->XR[0xCD]);
	if ((cPtr->readXR(cPtr, 0xCE)) != Regs->XR[0xCE])
	    cPtr->writeXR(cPtr, 0xCE, Regs->XR[0xCE]);

	/* set flat panel regs. */
	for (i = 0xD0; i < 0xFF; i++) {
	    if ((cPtr->readXR(cPtr, i)) != Regs->XR[i])
		cPtr->writeXR(cPtr, i, Regs->XR[i]);
	}

	for (i = 0; i < 0x80; i++) {
	    /* Don't touch alternate clock select reg. */
	    if ((i == 0x01) && (cPtr->Chipset == CHIPS_CT69030)) {
	    	/* restore the non clock bits */
		tmp = cPtr->readFR(cPtr, 0x01);
		cPtr->writeFR(cPtr, 0x01, ((Regs->FR[0x01] & 0xF0) |
				(tmp & ~0xF0)));
		continue;
	    }

	    if ((i == 0x02) && (cPtr->Chipset == CHIPS_CT69030))
	    	/* keep pipeline disabled till we are ready */
		continue;
	  
	    if ((i == 0x03) && (cPtr->Chipset != CHIPS_CT69030)) {
	    	/* restore the non clock bits */
		tmp = cPtr->readFR(cPtr, 0x03);
		cPtr->writeFR(cPtr, 0x03, ((Regs->FR[0x03] & 0xC3) |
				(tmp & ~0xC3)));
		continue;
	    }

	    if ((i > 0x03) && (cPtr->Chipset != CHIPS_CT69030) &&
				(cPtr->SecondCrtc == TRUE))
		continue;

	    if ( (i == 0x40) || (i==0x48)) {
	      /* !! set stretching but disable compensation   */
	      cPtr->writeFR(cPtr, i, Regs->FR[i] & 0xFE);
	      continue ;     /* some registers must be set before FR40/FR48 */
	    }
	    if ((cPtr->readFR(cPtr, i)) != Regs->FR[i]) {
		cPtr->writeFR(cPtr, i, Regs->FR[i]);
	    }
	}

	/* set the multimedia regs */
	for (i = 0x02; i < 0x80; i++) {
	    if ( (i == 0x43) || (i == 0x44))
		continue;
	    if ((cPtr->readMR(cPtr, i)) != Regs->MR[i])
		cPtr->writeMR(cPtr, i, Regs->MR[i]);
	}
	
	/* set extended crtc regs. */
	for (i = 0x30; i < 0x80; i++) {
	    if ((hwp->readCrtc(hwp, i)) != Regs->CR[i]) 
		hwp->writeCrtc(hwp, i, Regs->CR[i]);
	}
    } else {
	/* set extended regs. */
	for (i = 0; i < 0x30; i++) {
	    if ((cPtr->readXR(cPtr, i)) != Regs->XR[i])
		cPtr->writeXR(cPtr, i, Regs->XR[i]);
	}
	cPtr->writeXR(cPtr, 0x15, 0x00); /* unprotect just in case ... */
	/* Don't touch MCLK/VCLK regs. */
	for (i = 0x34; i < 0x54; i++) {
	    if ((cPtr->readXR(cPtr, i)) != Regs->XR[i])
		cPtr->writeXR(cPtr, i, Regs->XR[i]);
	}
	tmp = cPtr->readXR(cPtr, 0x54);	/*  restore the non clock bits     */
	cPtr->writeXR(cPtr, 0x54, ((Regs->XR[0x54] & 0xF3) | (tmp & ~0xF3)));
	cPtr->writeXR(cPtr, 0x55, Regs->XR[0x55] & 0xFE); /* h-comp off     */
	cPtr->writeXR(cPtr, 0x56, Regs->XR[0x56]);
	cPtr->writeXR(cPtr, 0x57, Regs->XR[0x57] & 0xFE); /* v-comp off     */
	for (i=0x58; i < 0x7D; i++) {/* don't touch XR7D and XR7F on WINGINE */
	    if ((cPtr->readXR(cPtr, i)) != Regs->XR[i])
		cPtr->writeXR(cPtr, i, Regs->XR[i]);
	}
    }
#ifdef DEBUG
    /* debug - dump out all the extended registers... */
    if (IS_HiQV(cPtr)) {
	for (i = 0; i < 0xFF; i++) {
	    ErrorF("XR%X - %X : %X\n", i, Regs->XR[i],
		   cPtr->readXR(cPtr, i));
	}
	for (i = 0; i < 0x80; i++) {
	    ErrorF("FR%X - %X : %X\n", i, Regs->FR[i],
		   cPtr->readFR(cPtr, i));
	}
    } else {
	for (i = 0; i < 0x80; i++) {
	    ErrorF("XR%X - %X : %X\n", i, Regs->XR[i],
		   cPtr->readXR(cPtr, i));
	}
    }
#endif
}

static void
chipsRestoreStretching(ScrnInfoPtr pScrn, unsigned char ctHorizontalStretch,
		       unsigned char ctVerticalStretch)
{
    unsigned char tmp;
    CHIPSPtr cPtr = CHIPSPTR(pScrn);
    
    /* write to regs. */
    if (IS_HiQV(cPtr)) {
	tmp = cPtr->readFR(cPtr, 0x48);
	cPtr->writeFR(cPtr, 0x48, (tmp & 0xFE) | (ctVerticalStretch & 0x01));
	tmp = cPtr->readFR(cPtr, 0x40);
	cPtr->writeFR(cPtr, 0x40, (tmp & 0xFE) | (ctHorizontalStretch & 0x01));
    } else {
	tmp = cPtr->readXR(cPtr, 0x55);
	cPtr->writeXR(cPtr, 0x55, (tmp & 0xFE) | (ctHorizontalStretch & 0x01));
	tmp = cPtr->readXR(cPtr, 0x57);
	cPtr->writeXR(cPtr, 0x57, (tmp & 0xFE) | (ctVerticalStretch & 0x01));
    }

    usleep(20000);			/* to be active */
}

static int
chipsVideoMode(int depth, int displayHSize,
	       int displayVSize)
{
    /*     4 bpp  8 bpp  16 bpp  18 bpp  24 bpp  32 bpp */
    /* 640  0x20   0x30    0x40    -      0x50     -    */
    /* 800  0x22   0x32    0x42    -      0x52     -    */
    /*1024  0x24   0x34    0x44    -      0x54     -    for 1024x768 */
    /*1024   -     0x36    0x47    -      0x56     -    for 1024x600 */
    /*1152  0x27   0x37    0x47    -      0x57     -    */
    /*1280  0x28   0x38    0x49    -        -      -    */
    /*1600  0x2C   0x3C    0x4C   0x5D      -      -    */
    /*This value is only for BIOS.... */

    int videoMode = 0;

    switch (depth) {
    case 1:
    case 4:
	videoMode = 0x20;
	break;
    case 8:
	videoMode = 0x30;
	break;
    case 15:
	videoMode = 0x40;
	break;
    case 16:
	videoMode = 0x41;
	break;
    default:
	videoMode = 0x50;
	break;
    }

    switch (displayHSize) {
    case 800:
	videoMode |= 0x02;
	break;
    case 1024:
	videoMode |= 0x04;
	if(displayVSize < 768)
	    videoMode |= 0x02;
	break;
    case 1152:
	videoMode |= 0x07;
	break;
    case 1280:
	videoMode |= 0x08;
	break;
    case 1600:
	videoMode |= 0x0C; /*0x0A??*/
	break;
    }

    return videoMode;
}


/*
 * Map the framebuffer and MMIO memory.
 */

static Bool
chipsMapMem(ScrnInfoPtr pScrn)
{
    CHIPSPtr cPtr = CHIPSPTR(pScrn);
    vgaHWPtr hwp = VGAHWPTR(pScrn);
    CHIPSEntPtr cPtrEnt;

    if (cPtr->Flags & ChipsLinearSupport) {
	if (cPtr->UseMMIO) {
	    if (IS_HiQV(cPtr)) {
		if (cPtr->Bus == ChipsPCI)
		    cPtr->MMIOBase = xf86MapPciMem(pScrn->scrnIndex,
			   VIDMEM_MMIO_32BIT,cPtr->PciTag, cPtr->IOAddress,
			   0x20000L);
		 else 
		    cPtr->MMIOBase = xf86MapVidMem(pScrn->scrnIndex,
			   VIDMEM_MMIO_32BIT, cPtr->IOAddress, 0x20000L);
	    } else {
		if (cPtr->Bus == ChipsPCI)
		    cPtr->MMIOBase = xf86MapPciMem(pScrn->scrnIndex,
			  VIDMEM_MMIO_32BIT, cPtr->PciTag, cPtr->IOAddress,
			  0x10000L);
		else
		    cPtr->MMIOBase = xf86MapVidMem(pScrn->scrnIndex,
			  VIDMEM_MMIO_32BIT, cPtr->IOAddress, 0x10000L);
	    }

	    if (cPtr->MMIOBase == NULL)
		return FALSE;
	}
	if (cPtr->FbMapSize) {
	  unsigned long Addr = (unsigned long)cPtr->FbAddress;
	  unsigned int Map =  cPtr->FbMapSize;
	  
	  if ((cPtr->Flags & ChipsDualChannelSupport) &&
	      (xf86IsEntityShared(pScrn->entityList[0]))) {
	      cPtrEnt = xf86GetEntityPrivate(pScrn->entityList[0],
					     CHIPSEntityIndex)->ptr;
	    if(cPtr->SecondCrtc == FALSE) {
	      Addr = cPtrEnt->masterFbAddress;
	      Map = cPtrEnt->masterFbMapSize;
	    } else {
	      Addr = cPtrEnt->slaveFbAddress;
	      Map = cPtrEnt->slaveFbMapSize;
	    }
	  }

	  if (cPtr->Bus == ChipsPCI)
	      cPtr->FbBase = xf86MapPciMem(pScrn->scrnIndex,VIDMEM_FRAMEBUFFER,
 			          cPtr->PciTag, Addr, Map);

	  else
	      cPtr->FbBase = xf86MapVidMem(pScrn->scrnIndex,VIDMEM_FRAMEBUFFER,
					   Addr, Map);

	  if (cPtr->FbBase == NULL)
	      return FALSE;
	}
	if (cPtr->Flags & ChipsFullMMIOSupport) {
		cPtr->MMIOBaseVGA = xf86MapPciMem(pScrn->scrnIndex,
						  VIDMEM_MMIO,cPtr->PciTag,
						  cPtr->IOAddress, 0x2000L);
	    /* 69030 MMIO Fix.
	     *
	     * The hardware lets us map the PipeB data registers
	     * into the MMIO address space normally occupied by PipeA,
	     * but it doesn't allow remapping of the index registers.
	     * So we're forced to map a separate MMIO space for each
	     * pipe and to toggle between them as necessary. -GHB
	     */
	    if (cPtr->Flags & ChipsDualChannelSupport)
	       	cPtr->MMIOBasePipeB = xf86MapPciMem(pScrn->scrnIndex,
				      VIDMEM_MMIO,cPtr->PciTag,
				      cPtr->IOAddress + 0x800000, 0x2000L);

	    cPtr->MMIOBasePipeA = cPtr->MMIOBaseVGA;
	}
    } else {
	/* In paged mode Base is the VGA window at 0xA0000 */
	cPtr->FbBase = hwp->Base;
    }
    
    return TRUE;
}


/*
 * Unmap the framebuffer and MMIO memory.
 */

static Bool
chipsUnmapMem(ScrnInfoPtr pScrn)
{
    CHIPSPtr cPtr = CHIPSPTR(pScrn);

    if (cPtr->Flags & ChipsLinearSupport) {
	if (IS_HiQV(cPtr)) {
	    if (cPtr->MMIOBase)
		xf86UnMapVidMem(pScrn->scrnIndex, (pointer)cPtr->MMIOBase,
				0x20000);
	    if (cPtr->MMIOBasePipeB)
		xf86UnMapVidMem(pScrn->scrnIndex, (pointer)cPtr->MMIOBasePipeB,
				0x20000);
	    cPtr->MMIOBasePipeB = NULL;
	} else {
	  if (cPtr->MMIOBase)
	      xf86UnMapVidMem(pScrn->scrnIndex, (pointer)cPtr->MMIOBase,
			      0x10000);
	}
	cPtr->MMIOBase = NULL;
	xf86UnMapVidMem(pScrn->scrnIndex, (pointer)cPtr->FbBase, 
			cPtr->FbMapSize);
    }
    cPtr->FbBase = NULL;
    
    return TRUE;
}

static void
chipsProtect(ScrnInfoPtr pScrn, Bool on)
{
    vgaHWProtect(pScrn, on);
}

static void
chipsBlankScreen(ScrnInfoPtr pScrn, Bool unblank)
{
    CHIPSPtr cPtr = CHIPSPTR(pScrn);
    vgaHWPtr hwp = VGAHWPTR(pScrn);
    unsigned char scrn;
    CHIPSEntPtr cPtrEnt;    

    if (cPtr->UseDualChannel) {
        cPtrEnt = xf86GetEntityPrivate(pScrn->entityList[0],
					       CHIPSEntityIndex)->ptr;
	DUALREOPEN;
    }

    /* fix things that could be messed up by suspend/resume */
    if (!IS_HiQV(cPtr))
	cPtr->writeXR(cPtr, 0x15, 0x00);

    scrn = hwp->readSeq(hwp, 0x01);

    if (unblank) {
	scrn &= 0xDF;                       /* enable screen */
    } else {
	scrn |= 0x20;                       /* blank screen */
    }

    /* synchronous reset - stop counters */
    if (!cPtr->SyncResetIgn) {
	hwp->writeSeq(hwp, 0x00, 0x01);
    }

    hwp->writeSeq(hwp, 0x01, scrn); /* change mode */

    /* end reset - start counters */
    if (!cPtr->SyncResetIgn) {
	hwp->writeSeq(hwp, 0x00, 0x03);
    }

    if ((cPtr->UseDualChannel) &&
		(! xf86IsEntityShared(pScrn->entityList[0]))) {
	unsigned int IOSS, MSS;
	IOSS = cPtr->readIOSS(cPtr);
	MSS = cPtr->readMSS(cPtr);
	cPtr->writeIOSS(cPtr, ((cPtr->storeIOSS & IOSS_MASK) |
			       IOSS_PIPE_B));
	cPtr->writeMSS(cPtr, hwp, ((cPtr->storeMSS & MSS_MASK) | MSS_PIPE_B));

	/* fix things that could be messed up by suspend/resume */
	if (!IS_HiQV(cPtr))
	    cPtr->writeXR(cPtr, 0x15, 0x00);

	scrn = hwp->readSeq(hwp, 0x01);
	
	if (unblank) {
	    scrn &= 0xDF;                       /* enable screen */
	} else {
	    scrn |= 0x20;                       /* blank screen */
	}

	/* synchronous reset - stop counters */
	if (!cPtr->SyncResetIgn) {
	    hwp->writeSeq(hwp, 0x00, 0x01);
	}

	hwp->writeSeq(hwp, 0x01, scrn); /* change mode */

	/* end reset - start counters */
	if (!cPtr->SyncResetIgn) {
	    hwp->writeSeq(hwp, 0x00, 0x03);
	}

	cPtr->writeIOSS(cPtr, IOSS);
	cPtr->writeMSS(cPtr, hwp, MSS);
    }

}

static void
chipsLock(ScrnInfoPtr pScrn)
{
    vgaHWPtr hwp = VGAHWPTR(pScrn);
    CHIPSPtr cPtr = CHIPSPTR(pScrn);
    unsigned char tmp;
    
    vgaHWLock(hwp);

    if (!IS_HiQV(cPtr)) {
	/* group protection attribute controller access */
	cPtr->writeXR(cPtr, 0x15, cPtr->SuspendHack.xr15);
	tmp = cPtr->readXR(cPtr, 0x02);
	cPtr->writeXR(cPtr, 0x02, (tmp & ~0x18) | cPtr->SuspendHack.xr02);
	tmp = cPtr->readXR(cPtr, 0x14);
	cPtr->writeXR(cPtr, 0x14, (tmp & ~0x20) | cPtr->SuspendHack.xr14);

	/* reset 32 bit register access */
	if (cPtr->Chipset > CHIPS_CT65540) {
	    tmp = cPtr->readXR(cPtr, 0x03);
	    cPtr->writeXR(cPtr, 0x03, (tmp & ~0x0A) | cPtr->SuspendHack.xr03);
	}
    }
}

static void
chipsUnlock(ScrnInfoPtr pScrn)
{
    vgaHWPtr hwp = VGAHWPTR(pScrn);
    CHIPSPtr cPtr = CHIPSPTR(pScrn);
    unsigned char tmp;
    
    if (!IS_HiQV(cPtr)) {
	/* group protection attribute controller access */
	cPtr->writeXR(cPtr, 0x15, 0x00);
	tmp = cPtr->readXR(cPtr, 0x02);
	cPtr->writeXR(cPtr, 0x02, (tmp & ~0x18));
	tmp = cPtr->readXR(cPtr, 0x14);
	cPtr->writeXR(cPtr, 0x14, (tmp & ~0x20));
	/* enable 32 bit register access */
	if (cPtr->Chipset > CHIPS_CT65540) {
	    cPtr->writeXR(cPtr, 0x03, cPtr->SuspendHack.xr03 | 0x0A);
	}
    }
    vgaHWUnlock(hwp);
}

static void
chipsHWCursorOn(CHIPSPtr cPtr, ScrnInfoPtr pScrn)
{
    /* enable HW cursor */
    if (cPtr->HWCursorShown) {
	if (IS_HiQV(cPtr)) {
	    cPtr->writeXR(cPtr, 0xA0, cPtr->HWCursorContents & 0xFF);
	    if (cPtr->UseDualChannel && 
		(! xf86IsEntityShared(pScrn->entityList[0]))) {
		unsigned int IOSS, MSS;
		IOSS = cPtr->readIOSS(cPtr);
		MSS = cPtr->readMSS(cPtr);
		cPtr->writeIOSS(cPtr, ((cPtr->storeIOSS & IOSS_MASK) |
				       IOSS_PIPE_B));
		cPtr->writeMSS(cPtr, VGAHWPTR(pScrn), ((cPtr->storeMSS &
					  MSS_MASK) | MSS_PIPE_B));
		cPtr->writeXR(cPtr, 0xA0, cPtr->HWCursorContents & 0xFF);
		cPtr->writeIOSS(cPtr, IOSS);
		cPtr->writeMSS(cPtr, VGAHWPTR(pScrn), MSS);
	    }
	} else {
	    HW_DEBUG(0x8);	
	    if (cPtr->UseMMIO) {
		MMIOmeml(DR(0x8)) = cPtr->HWCursorContents;
	    } else {
		outl(cPtr->PIOBase + DR(0x8), cPtr->HWCursorContents);
	    }
	}
    }
}

static void
chipsHWCursorOff(CHIPSPtr cPtr, ScrnInfoPtr pScrn)
{
    /* disable HW cursor */
    if (cPtr->HWCursorShown) {
	if (IS_HiQV(cPtr)) {
	    cPtr->HWCursorContents = cPtr->readXR(cPtr, 0xA0);
	    cPtr->writeXR(cPtr, 0xA0, cPtr->HWCursorContents & 0xF8);
	} else {
	    HW_DEBUG(0x8);
	    if (cPtr->UseMMIO) {
		cPtr->HWCursorContents = MMIOmeml(DR(0x8));
		/* Below used to be MMIOmemw() change back if problem!!! */
		/* Also see ct_cursor.c */
		MMIOmeml(DR(0x8)) = cPtr->HWCursorContents & 0xFFFE;
	    } else {
		cPtr->HWCursorContents = inl(cPtr->PIOBase + DR(0x8));
		outw(cPtr->PIOBase + DR(0x8), cPtr->HWCursorContents & 0xFFFE);
	    }
	}
    }
}

void
chipsFixResume(ScrnInfoPtr pScrn)
{
    CHIPSPtr cPtr = CHIPSPTR(pScrn);
    vgaHWPtr hwp = VGAHWPTR(pScrn);
    unsigned char tmp;
    
    /* fix things that could be messed up by suspend/resume */
    if (!IS_HiQV(cPtr))
	cPtr->writeXR(cPtr, 0x15, 0x00);
    tmp = hwp->readMiscOut(hwp);
    hwp->writeMiscOut(hwp, (tmp & 0xFE) | cPtr->SuspendHack.vgaIOBaseFlag);
    tmp = hwp->readCrtc(hwp, 0x11);
    hwp->writeCrtc(hwp, 0x11, (tmp & 0x7F));
}

static char
chipsTestDACComp(ScrnInfoPtr pScrn, unsigned char a, unsigned char b,
		 unsigned char c)
{
    vgaHWPtr hwp = VGAHWPTR(pScrn);
    unsigned char type;

    hwp->writeDacWriteAddr(hwp, 0x00);
    while ((hwp->readST01(hwp)) & 0x08){};    /* wait for vsync to end */
    while (!(hwp->readST01(hwp)) & 0x08){};   /* wait for new vsync  */
    hwp->writeDacData(hwp, a);                /* set pattern */
    hwp->writeDacData(hwp, b);
    hwp->writeDacData(hwp, c);
    while (!(hwp->readST01(hwp)) & 0x01){};   /* wait for hsync to end  */
    while ((hwp->readST01(hwp)) & 0x01){};    /* wait for hsync to end  */
    type = hwp->readST00(hwp);                /* read comparator        */
    return (type & 0x10);
}

static int
chipsProbeMonitor(ScrnInfoPtr pScrn)
{
    CHIPSPtr cPtr = CHIPSPTR(pScrn);
    vgaHWPtr hwp = VGAHWPTR(pScrn);
    unsigned char dacmask;
    unsigned char dacdata[3];
    unsigned char xr1, xr2;
    int type = 2;  /* no monitor */
    unsigned char IOSS=0, MSS=0, tmpfr02=0, tmpfr01a=0, tmpfr01b=0;

    /* Dual channel display, enable both pipelines */
    if (cPtr->Flags & ChipsDualChannelSupport) {
	IOSS = cPtr->readIOSS(cPtr);
	MSS = cPtr->readMSS(cPtr);
	tmpfr02 = cPtr->readFR(cPtr,0x02);
	cPtr->writeFR(cPtr, 0x02, (tmpfr02 & 0xCF)); /* CRT/FP off */
	usleep(1000);
	cPtr->writeIOSS(cPtr, ((IOSS & IOSS_MASK) | IOSS_PIPE_A));
	cPtr->writeMSS(cPtr, hwp, ((MSS & MSS_MASK) | MSS_PIPE_A));
	tmpfr01a = cPtr->readFR(cPtr,0x01);
	if ((tmpfr01a & 0x3) != 0x01)
	  cPtr->writeFR(cPtr, 0x01, ((tmpfr01a & 0xFC) | 0x1)); 
	cPtr->writeIOSS(cPtr, ((IOSS & IOSS_MASK) | IOSS_PIPE_B));
	cPtr->writeMSS(cPtr, hwp, ((MSS & MSS_MASK) | MSS_PIPE_B));
	tmpfr01b = cPtr->readFR(cPtr,0x01);
	if ((tmpfr01b & 0x3) != 0x01)
	  cPtr->writeFR(cPtr, 0x01, ((tmpfr01b & 0xFC) | 0x1)); 
	cPtr->writeIOSS(cPtr, IOSS);
	cPtr->writeMSS(cPtr, hwp, MSS);
	cPtr->writeFR(cPtr, 0x02, (tmpfr02 & 0xCF) | 0x10); /* CRT on/FP off*/ 
    }

    dacmask = hwp->readDacMask(hwp);    /* save registers */ 
    hwp->writeDacMask(hwp, 0x00);
    hwp->writeDacReadAddr(hwp, 0x00);

    dacdata[0]=hwp->readDacData(hwp);
    dacdata[1]=hwp->readDacData(hwp);
    dacdata[2]=hwp->readDacData(hwp);

    if (!IS_HiQV(cPtr)) {
	xr1 = cPtr->readXR(cPtr, 0x06);
	xr2 = cPtr->readXR(cPtr, 0x1F);
	cPtr->writeXR(cPtr, 0x06, xr1 & 0xF1);  /* turn on dac */
	cPtr->writeXR(cPtr, 0x1F, xr2 & 0x7F);  /* enable comp */
    } else {
	xr1 = cPtr->readXR(cPtr, 0x81);
	xr2 = cPtr->readXR(cPtr, 0xD0);
	cPtr->writeXR(cPtr, 0x81,(xr1 & 0xF0));
	cPtr->writeXR(cPtr, 0xD0,(xr2 | 0x03));
    }
    if (chipsTestDACComp(pScrn, 0x12,0x12,0x12)) {         /* test patterns */
	if (chipsTestDACComp(pScrn,0x14,0x14,0x14))        /* taken  from   */
	    if (!chipsTestDACComp(pScrn,0x2D,0x14,0x14))   /* BIOS          */
		if (!chipsTestDACComp(pScrn,0x14,0x2D,0x14))
		    if (!chipsTestDACComp(pScrn,0x14,0x14,0x2D))
			if (!chipsTestDACComp(pScrn,0x2D,0x2D,0x2D))
			    type = 0;    /* color monitor */
    } else {
	if (chipsTestDACComp(pScrn,0x04,0x12,0x04))
	    if (!chipsTestDACComp(pScrn,0x1E,0x12,0x04))
		if (!chipsTestDACComp(pScrn,0x04,0x2D,0x04))
		    if (!chipsTestDACComp(pScrn,0x1E,0x16,0x15))
			if (chipsTestDACComp(pScrn,0x00,0x00,0x00))
			    type = 1;    /* monochrome */
    }

    hwp->writeDacWriteAddr(hwp, 0x00);         /* restore registers */
    hwp->writeDacData(hwp, dacdata[0]);
    hwp->writeDacData(hwp, dacdata[1]);
    hwp->writeDacData(hwp, dacdata[2]);
    hwp->writeDacMask(hwp, dacmask);
    if (!IS_HiQV(cPtr)) {
	cPtr->writeXR(cPtr,0x06,xr1);
	cPtr->writeXR(cPtr,0x1F,xr2);
    } else {
	cPtr->writeXR(cPtr,0x81,xr1);
	cPtr->writeXR(cPtr,0xD0,xr2);
    }

    if (cPtr->Flags & ChipsDualChannelSupport) {
	cPtr->writeIOSS(cPtr, ((IOSS & IOSS_MASK) | IOSS_PIPE_A));
	cPtr->writeMSS(cPtr, hwp, ((MSS & MSS_MASK) | MSS_PIPE_A));
	cPtr->writeFR(cPtr, 0x01, tmpfr01a);
	cPtr->writeIOSS(cPtr, ((IOSS & IOSS_MASK) | IOSS_PIPE_B));
	cPtr->writeMSS(cPtr, hwp, ((MSS & MSS_MASK) | MSS_PIPE_B));
	cPtr->writeFR(cPtr, 0x01, tmpfr01b);
	usleep(1000);
	cPtr->writeIOSS(cPtr, IOSS);
	cPtr->writeMSS(cPtr, hwp, MSS);
	cPtr->writeFR(cPtr, 0x02, tmpfr02);
    }

    return type;
}

static int
chipsSetMonitor(ScrnInfoPtr pScrn)
{
    int tmp= chipsProbeMonitor(pScrn);

    switch (tmp) {
    case 0:
	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Color monitor detected\n");
	break;
    case 1:
	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Monochrome monitor detected\n");
	break;
    default:
	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "No monitor detected\n");
    }
    return (tmp);
}

static void
chipsSetPanelType(CHIPSPtr cPtr)
{
    CARD8 tmp;
    
    if (IS_HiQV(cPtr)) {
	if (cPtr->Chipset == CHIPS_CT69030) {
	    tmp = cPtr->readFR(cPtr, 0x00);
	    if (tmp & 0x20) {
		/* FR02: DISPLAY TYPE REGISTER                         */
		/* FR02[4] = CRT, FR02[5] = FlatPanel                  */
		tmp = cPtr->readFR(cPtr, 0x02);
		if (tmp & 0x10)
		    cPtr->PanelType |= ChipsCRT;
		if (tmp & 0x20)
		    cPtr->PanelType |= ChipsLCD | ChipsLCDProbed;
	    } else {
		cPtr->PanelType |= ChipsCRT;
	    }
	} else {
	    /* test LCD */
	    /* FR01: DISPLAY TYPE REGISTER                         */
	    /* FR01[1:0]:   Display Type, 01 = CRT, 10 = FlatPanel */
	    /* LCD                                                 */
	    tmp = cPtr->readFR(cPtr, 0x01);
	    if ((tmp & 0x03) == 0x02) {
	        cPtr->PanelType |= ChipsLCD | ChipsLCDProbed;
	    }
	    tmp = cPtr->readXR(cPtr,0xD0);	
	    if (tmp & 0x01) {
	        cPtr->PanelType |= ChipsCRT;
	    }
	}
    } else {
	tmp = cPtr->readXR(cPtr, 0x51);
	/* test LCD */
	/* XR51: DISPLAY TYPE REGISTER                     */
	/* XR51[2]:   Display Type, 0 = CRT, 1 = FlatPanel */
	if (tmp & 0x04) {
	    cPtr->PanelType |= ChipsLCD | ChipsLCDProbed;
	} 
	if ((cPtr->readXR(cPtr, 0x06)) & 0x02) {
	    cPtr->PanelType |= ChipsCRT;
	}
    }
}

static void
chipsBlockHandler (
    int i,
    pointer     blockData,
    pointer     pTimeout,
    pointer     pReadmask
){
    ScreenPtr   pScreen = screenInfo.screens[i];
    ScrnInfoPtr pScrn = xf86Screens[i];
    CHIPSPtr    cPtr = CHIPSPTR(pScrn);
    
    pScreen->BlockHandler = cPtr->BlockHandler;
    (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask);
    pScreen->BlockHandler = chipsBlockHandler;

    if(cPtr->VideoTimerCallback) {
	UpdateCurrentTime();
	(*cPtr->VideoTimerCallback)(pScrn, currentTime.milliseconds);
    }
}
