diff options
Diffstat (limited to 'src/ct_driver.c')
-rw-r--r-- | src/ct_driver.c | 7487 |
1 files changed, 7487 insertions, 0 deletions
diff --git a/src/ct_driver.c b/src/ct_driver.c new file mode 100644 index 0000000..2aa6cc2 --- /dev/null +++ b/src/ct_driver.c @@ -0,0 +1,7487 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/chips/ct_driver.c,v 1.122 2002/11/25 14:04:58 eich 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 int 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, "NoStretch", 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, "NoStretch", 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 xf86LoaderReqSymbols() or + * xf86LoaderReqSymLists(). 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 +}; + +static const char *miscfbSymbols[] = { + "xf1bppScreenInit", + "xf4bppScreenInit", + "cfb8_16ScreenInit", + NULL +}; + +static const char *fbSymbols[] = { + "fbScreenInit", + "fbPictureInit", + NULL +}; + +static const char *xaaSymbols[] = { + "XAACreateInfoRec", + "XAADestroyInfoRec", + "XAAFillSolidRects" , + "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(pointer 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. + */ + LoaderRefSymLists(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) +{ + if (pScrn->driverPrivate == NULL) + return; + xfree(pScrn->driverPrivate); + 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; + + if (flags & PROBE_DETECT) return FALSE; + + /* The vgahw module should be loaded here when needed */ + if (!xf86LoadSubModule(pScrn, "vgahw")) + return FALSE; + xf86LoaderReqSymLists(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 (xf86LoadSubModule(pScrn, "int10")) { + xf86Int10InfoPtr pInt; + xf86LoaderReqSymLists(int10Symbols, NULL); +#if 1 + xf86DrvMsg(pScrn->scrnIndex,X_INFO,"initializing int10\n"); + pInt = xf86InitInt10(cPtr->pEnt->index); + xf86FreeInt10(pInt); +#endif + } +#endif + + if (xf86LoadSubModule(pScrn, "vbe")) { + xf86LoaderReqSymLists(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) { + vbeFree(cPtr->pVbe); + cPtr->pVbe = NULL; + 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) { + vbeFree(cPtr->pVbe); + cPtr->pVbe = NULL; + 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"); + vbeFree(cPtr->pVbe); + cPtr->pVbe = NULL; + 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 (xf86LoadSubModule(pScrn, "xf1bpp") == NULL) { + vbeFree(cPtr->pVbe); + cPtr->pVbe = NULL; + CHIPSFreeRec(pScrn); + return FALSE; + } + xf86LoaderReqSymbols("xf1bppScreenInit", NULL); + break; + case 4: + if (xf86LoadSubModule(pScrn, "xf4bpp") == NULL) { + vbeFree(cPtr->pVbe); + cPtr->pVbe = NULL; + CHIPSFreeRec(pScrn); + return FALSE; + } + xf86LoaderReqSymbols("xf4bppScreenInit", NULL); + break; + case 16: + if (cPtr->Flags & ChipsOverlay8plus16) { + if (xf86LoadSubModule(pScrn, "xf8_16bpp") == NULL) { + vbeFree(cPtr->pVbe); + cPtr->pVbe = NULL; + CHIPSFreeRec(pScrn); + return FALSE; + } + xf86LoaderReqSymbols("cfb8_16bppScreenInit", NULL); + break; + } + default: + if (xf86LoadSubModule(pScrn, "fb") == NULL) { + vbeFree(cPtr->pVbe); + cPtr->pVbe = NULL; + CHIPSFreeRec(pScrn); + return FALSE; + } + xf86LoaderReqSymLists(fbSymbols, NULL); + break; + } + + if (cPtr->Flags & ChipsAccelSupport) { + if (!xf86LoadSubModule(pScrn, "xaa")) { + vbeFree(cPtr->pVbe); + cPtr->pVbe = NULL; + CHIPSFreeRec(pScrn); + return FALSE; + } + xf86LoaderReqSymLists(xaaSymbols, NULL); + } + + if (cPtr->Flags & ChipsShadowFB) { + if (!xf86LoadSubModule(pScrn, "shadowfb")) { + vbeFree(cPtr->pVbe); + cPtr->pVbe = NULL; + CHIPSFreeRec(pScrn); + return FALSE; + } + xf86LoaderReqSymLists(shadowSymbols, NULL); + } + + if (cPtr->Accel.UseHWCursor) { + if (!xf86LoadSubModule(pScrn, "ramdac")) { + vbeFree(cPtr->pVbe); + cPtr->pVbe = NULL; + CHIPSFreeRec(pScrn); + return FALSE; + } + xf86LoaderReqSymLists(ramdacSymbols, NULL); + } + + if (cPtr->Flags & ChipsLinearSupport) + xf86SetOperatingState(resVgaMem, cPtr->pEnt->index, ResDisableOpr); + + if (cPtr->MMIOBaseVGA) + xf86SetOperatingState(resVgaIo, cPtr->pEnt->index, ResDisableOpr); + vbeFree(cPtr->pVbe); + cPtr->pVbe = NULL; + 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; + pointer pVbeModule = NULL; + + 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, 8, 8, 8, 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%X.\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_STRETCH)) + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + " - Forcing option \"NoStretch\".\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; + break; + case CHIPS_CT69000: + /* The ct69000 has 2Mb of SGRAM integrated */ + pScrn->videoRam = 2048; + 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; + } + 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 ((pVbeModule = xf86LoadSubModule(pScrn, "ddc"))) { + Bool ddc_done = FALSE; + xf86MonPtr pMon; + + xf86LoaderReqSymLists(ddcSymbols, NULL); + + if (cPtr->pVbe) { + if ((pMon + = xf86PrintEDID(vbeDoEDID(cPtr->pVbe, pVbeModule))) != NULL) { + ddc_done = TRUE; + xf86SetDDCproperties(pScrn,pMon); + } + } + + if (!ddc_done) + if (xf86LoadSubModule(pScrn, "i2c")) { + xf86LoaderReqSymLists(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 */ + /* We have a 64bit wide memory bus on the 69030 and 69000, and 32bits */ + /* on the others. Thus multiply by a suitable factor */ + if ((cPtr->Chipset == CHIPS_CT69030) || (cPtr->Chipset == CHIPS_CT69000)) { + 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 }; + + /* Set pScrn->monitor */ + pScrn->monitor = pScrn->confScreen->monitor; + + if (cPtr->Flags & ChipsHDepthSupport) + i = xf86SetDepthBpp(pScrn, 8, 8, 8, Support24bppFb | + SupportConvert32to24 | PreferConvert32to24); + else + i = xf86SetDepthBpp(pScrn, 8, 8, 8, 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%X.\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 = 0x83FC; + 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 (xf86LoadSubModule(pScrn, "ddc")) { + xf86LoaderReqSymLists(ddcSymbols, NULL); + if (cPtr->pVbe) + xf86SetDDCproperties(pScrn,xf86PrintEDID(vbeDoEDID(cPtr->pVbe, NULL))); + } + 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 }; + + /* Set pScrn->monitor */ + pScrn->monitor = pScrn->confScreen->monitor; + + if (cPtr->Flags & ChipsHDepthSupport) + i = xf86SetDepthBpp(pScrn, 8, 8, 8, Support24bppFb | + SupportConvert32to24 | PreferConvert32to24); + else + i = xf86SetDepthBpp(pScrn, 8, 8, 8, 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%X.\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 < 0) ? (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 = 0x83FC; + 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 (xf86LoadSubModule(pScrn, "ddc")) { + xf86LoaderReqSymLists(ddcSymbols, NULL); + if (cPtr->pVbe) + xf86SetDDCproperties(pScrn,xf86PrintEDID(vbeDoEDID(cPtr->pVbe, NULL))); + } + 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 cfb 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 int +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) + && ((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 bestError, abest = 42, bestFout = 0; + 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; + bestError = error; + bestM = M; + bestN = N; + bestP = P; + bestPSN = PSN; + bestFout = Fout; + } + } + } + } + } + /* @@@ >= 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 */ + if (!vgaHWInit(pScrn, mode)) { + ErrorF("bomb 1\n"); + return (FALSE); + } + pScrn->vtSema = TRUE; + + /* 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); + lcdHRetraceEnd = (mode->CrtcHSyncEnd >> 3); + lcdHSyncStart = lcdHRetraceStart - 2; + + lcdVTotal = mode->CrtcVTotal - 2; + lcdVDisplay = cPtr->PanelSize.VDisplay - 1; + lcdVRetraceStart = mode->CrtcVSyncStart; + lcdVRetraceEnd = mode->CrtcVSyncEnd; + + ChipsNew->FR[0x20] = lcdHDisplay & 0xFF; + ChipsNew->FR[0x21] = lcdHRetraceStart & 0xFF; + ChipsNew->FR[0x25] = ((lcdHRetraceStart & 0xF00) >> 4) | + ((lcdHDisplay & 0xF00) >> 8); + ChipsNew->FR[0x22] = lcdHRetraceEnd & 0x1F; + ChipsNew->FR[0x23] = lcdHTotal & 0xFF; + ChipsNew->FR[0x24] = (lcdHSyncStart >> 3) & 0xFF; + ChipsNew->FR[0x26] = (ChipsNew->FR[0x26] & ~0x1F) + | ((lcdHTotal & 0xF00) >> 8) + | (((lcdHSyncStart >> 3) & 0x100) >> 4); + ChipsNew->FR[0x27] &= 0x7F; + + ChipsNew->FR[0x30] = lcdVDisplay & 0xFF; + ChipsNew->FR[0x31] = lcdVRetraceStart & 0xFF; + ChipsNew->FR[0x35] = ((lcdVRetraceStart & 0xF00) >> 4) + | ((lcdVDisplay & 0xF00) >> 8); + ChipsNew->FR[0x32] = lcdVRetraceEnd & 0x0F; + ChipsNew->FR[0x33] = lcdVTotal & 0xFF; + ChipsNew->FR[0x34] = (lcdVTotal - lcdVRetraceStart) & 0xFF; + ChipsNew->FR[0x36] = ((lcdVTotal & 0xF00) >> 8) | + (((lcdVTotal - lcdVRetraceStart) & 0x700) >> 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 & 0xF00) >> 8; + ChipsNew->CR[0x33] = (mode->CrtcVBlankStart & 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; +#if 0 + /* We need to redo the overscan voodoo from vgaHW.c */ + ChipsStd->CRTC[3] = (ChipsStd->CRTC[3] & ~0x1F) + | (((mode->CrtcHBlankEnd >> 3) - 1) & 0x1F); + ChipsStd->CRTC[5] = (ChipsStd->CRTC[5] & ~0x80) + | ((((mode->CrtcHBlankEnd >> 3) - 1) & 0x20) << 2); + ChipsNew->CR[0x3C] = ((mode->CrtcHBlankEnd >> 3) - 1) & 0xC0; + if ((mode->CrtcHBlankEnd >> 3) == (mode->CrtcHTotal >> 3)) { + int i = (ChipsStd->CRTC[3] & 0x1F) + | ((ChipsStd->CRTC[5] & 0x80) >> 2) + | (ChipsNew->CR[0x3C] & 0xC0); + if ((i-- > (ChipsStd->CRTC[2])) && + (mode->CrtcHBlankEnd == mode->CrtcHTotal)) + i = 0; + ChipsStd->CRTC[3] = (ChipsStd->CRTC[3] & ~0x1F) | (i & 0x1F); + ChipsStd->CRTC[5] = (ChipsStd->CRTC[5] & ~0x80) | ((i << 2) &0x80); + ChipsNew->CR[0x3C] = (i & 0xC0); + } +#else + ChipsNew->CR[0x3C] = vgaHWHBlankKGA(mode, ChipsStd, 8, 0) << 6; +#endif + } else + vgaHWHBlankKGA(mode, ChipsStd, 6, 0); + vgaHWVBlankKGA(mode, ChipsStd, 8, 0); + + 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, FALSE)) + || (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 (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 (mode->CrtcHDisplay == 1024) + cPtr->OverlaySkewY += 5; + if (mode->CrtcHDisplay == 1280) + 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 */ + 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); + } + + /* 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)) & 0x20) >> 2) + | ((((mode->CrtcHBlankStart >> 3) - 1) & 0x100) >> 4) + | ((((mode->CrtcHBlankEnd >> 3) - 1) & 0x40) >> 1); + + + ChipsNew->XR[0x16] = (((mode->CrtcVTotal -2) & 0x400) >> 10 ) + | (((mode->CrtcVDisplay -1) & 0x400) >> 9 ) + | ((mode->CrtcVSyncStart & 0x400) >> 8 ) + | (((mode->CrtcVBlankStart) & 0x400) >> 6 ); + + /* 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 */ + if (!vgaHWInit(pScrn, mode)) { + ErrorF("bomb 5\n"); + return (FALSE); + } + pScrn->vtSema = TRUE; + + /* 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)) & 0x20) >> 2) + | ((((mode->CrtcHBlankStart >> 3) - 1) & 0x100) >> 4) + | ((((mode->CrtcHBlankEnd >> 3) - 1) & 0x40) >> 1); + + ChipsNew->XR[0x16] = (((mode->CrtcVTotal -2) & 0x400) >> 10 ) + | (((mode->CrtcVDisplay -1) & 0x400) >> 9 ) + | ((mode->CrtcVSyncStart & 0x400) >> 8 ) + | (((mode->CrtcVBlankStart) & 0x400) >> 6 ); + } 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); + } + lcdHRetraceStart -=8; /* HBlank = HRetrace - 1: for */ + lcdHRetraceEnd -=8; /* compatibility with vgaHW.c */ + } 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); + lcdHRetraceEnd = (lcdHRetraceEnd >> 3); + /* 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 */ + 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; + lcdVRetraceEnd = mode->CrtcVSyncEnd; + + ChipsNew->XR[0x64] = lcdVTotal & 0xFF; + ChipsNew->XR[0x66] = lcdVRetraceStart & 0xFF; + ChipsNew->XR[0x67] = lcdVRetraceEnd & 0x0F; + ChipsNew->XR[0x68] = lcdVDisplay & 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); + + /* + * 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 h-centering */ + else 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] |= 0x02; + else + ChipsNew->XR[0x51] &= ~0x02; + + /* 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; + } + 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); + } +} |