From 97c9ec2c1201ec09c359f92817033281045c537e Mon Sep 17 00:00:00 2001 From: Kaleb Keithley Date: Fri, 14 Nov 2003 16:48:55 +0000 Subject: Initial revision --- README.multihead | 70 ++ man/cirrus.man | 30 + src/CirrusClk.c | 146 ++++ src/alp.h | 87 +++ src/alp_driver.c | 2151 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/alp_hwcurs.c | 258 +++++++ src/alp_i2c.c | 126 ++++ src/alp_xaa.c | 686 +++++++++++++++++ src/alp_xaam.c | 271 +++++++ src/cir.h | 97 +++ src/cir_dga.c | 256 +++++++ src/cir_driver.c | 409 +++++++++++ src/cir_shadow.c | 251 +++++++ src/lg.h | 110 +++ src/lg_driver.c | 1877 +++++++++++++++++++++++++++++++++++++++++++++++ src/lg_hwcurs.c | 384 ++++++++++ src/lg_i2c.c | 96 +++ src/lg_xaa.c | 298 ++++++++ src/lg_xaa.h | 180 +++++ 19 files changed, 7783 insertions(+) create mode 100644 README.multihead create mode 100644 man/cirrus.man create mode 100644 src/CirrusClk.c create mode 100644 src/alp.h create mode 100644 src/alp_driver.c create mode 100644 src/alp_hwcurs.c create mode 100644 src/alp_i2c.c create mode 100644 src/alp_xaa.c create mode 100644 src/alp_xaam.c create mode 100644 src/cir.h create mode 100644 src/cir_dga.c create mode 100644 src/cir_driver.c create mode 100644 src/cir_shadow.c create mode 100644 src/lg.h create mode 100644 src/lg_driver.c create mode 100644 src/lg_hwcurs.c create mode 100644 src/lg_i2c.c create mode 100644 src/lg_xaa.c create mode 100644 src/lg_xaa.h diff --git a/README.multihead b/README.multihead new file mode 100644 index 0000000..efe62d4 --- /dev/null +++ b/README.multihead @@ -0,0 +1,70 @@ +WARNING: +On exit XFree86 restores the old mode but it +does not disable the secondary card. As a result +the second card (which has some randonm CRTC timing) +may produce synch pulses which are wrong for your +monitor. + +If your monitor does not tolerate bad timing I would +recommend that you don't try Multi-head yet, or at +least, turn it off *before* leaving X. + + +3.9Nl notice: There is a problem with releasing +of LBX colormap privates which may cause a seg. +fault when the server exits. I got a patch from +Mark Vojkovich which fixes it. + +If you have a CL-GD5480 or CL-GD5446 ver. B you +should be able to try Multi-Head with that +card as a secondary. The primary card should not +have any special feature. Some MainBoards may +not do it right too. I tried it with a 5465 (AGP) +as a primary and 5446B (PCI) secondary on an +ABIT LX6 upgraded to the latest bios. + +Version A of the 5446 cannot be pure MMIO (The driver +requires that it is the primary display adapter). +You can distinguish between the rel A and rel B by +running "scanpci -v". Version 1 does not report a +valid BASE1 address. + +The bios upgrade lets me chose if the primary +display adapter is on PCI on AGP (I chose +the AGP card as primary). Warning - this setup +will *NOT* work with XFree86 3.3.2. + +The only problem that I found so far is with +memory configuration initialization. My bios +does not initialize the secondary display adapter. +This results in a currupted display. + +Here are the options: +1. warm booting from Windows 98 may work. I have +not tried that. + +2. Take out the other card and leave the 5446 +(or 5480) as the primary card. Start the server +and watch it's output. Look for lines like: + (--) CIRRUS(0): Memory Config reg 1 is 0x1B + (--) CIRRUS(0): Memory Config reg 2 is 0x21 +Remember these values. Now edit XF86Config +and add to the proper device section the lines: + Option "MemCFG1" "0x1B" + Option "MemCFG2" "0x21" +These values are the contents of registers SR0F +and SR17. (notice: the 5480 driver does not use +and will not print MemCFG2). + +Now you can reinstall the other card (which +must me set as the the primary display adaptor). + +A note about configuring multi-head: +There should be a separate section for each +adapter (device), Monitor and Screen. A "ServerLayout" +section is optional (and recommended). To make it +easier for XFree86 to relate device sections to +actual cards, use a BusId line in each device +section. XFree86 3.9N works properly if the config +file is for Multi-head but it finds only one +display adapter. diff --git a/man/cirrus.man b/man/cirrus.man new file mode 100644 index 0000000..5035b02 --- /dev/null +++ b/man/cirrus.man @@ -0,0 +1,30 @@ +.\" $XFree86: xc/programs/Xserver/hw/xfree86/drivers/cirrus/cirrus.man,v 1.2 2001/01/27 18:20:47 dawes Exp $ +.\" shorthand for double quote that works everywhere. +.ds q \N'34' +.TH CIRRUS __drivermansuffix__ __vendorversion__ +.SH NAME +cirrus \- Cirrus Logic video driver +.SH SYNOPSIS +.nf +.B "Section \*qDevice\*q" +.BI " Identifier \*q" devname \*q +.B " Driver \*qcirrus\*q" +\ \ ... +.B EndSection +.fi +.SH DESCRIPTION +.B cirrus +is an XFree86 driver for Cirrus Logic video chips. +THIS MAN PAGE NEEDS TO BE FILLED IN. +.SH SUPPORTED HARDWARE +The +.B cirrus +driver supports... +.SH CONFIGURATION DETAILS +Please refer to XF86Config(__filemansuffix__) for general configuration +details. This section only covers configuration details specific to this +driver. +.SH "SEE ALSO" +XFree86(1), XF86Config(__filemansuffix__), xf86config(1), Xserver(1), X(__miscmansuffix__) +.SH AUTHORS +Authors include: ... diff --git a/src/CirrusClk.c b/src/CirrusClk.c new file mode 100644 index 0000000..c548f1f --- /dev/null +++ b/src/CirrusClk.c @@ -0,0 +1,146 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/cirrus/CirrusClk.c,v 1.9 1999/12/26 18:24:14 robin Exp $ */ + +/* + * Programming of the built-in Cirrus clock generator. + * Harm Hanemaayer + * + * VCO stability criterion code added by Koen Gadeyne (koen.gadeyne@barco.com) + * Max clock specification added by Harm Hanemaayer (H.Hanemaayer@inter.nl.net) + * + * Minor changes and cleanup Itai Nahshon. + * + * Made this completly chipset independent, and moved chipset dependent parts + * into the specific sub-drivers. Derek Fawcus + */ + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86_ansic.h" +#include "xf86PciInfo.h" +#include "xf86Pci.h" + +#include "cir.h" + +/* CLOCK_FACTOR is double the osc freq in kHz (osc = 14.31818 MHz) */ +#define CLOCK_FACTOR 28636 + +/* Stability constraints for internal VCO -- MAX_VCO also determines + * the maximum Video pixel clock + */ +#define MIN_VCO CLOCK_FACTOR +#define MAX_VCO 111000 + +/* clock in kHz is (numer * CLOCK_FACTOR / (denom & 0x3E)) >> (denom & 1) */ +#define VCOVAL(n, d) \ + ((((n) & 0x7F) * CLOCK_FACTOR / ((d) & 0x3E)) ) + +#define CLOCKVAL(n, d) \ + (VCOVAL(n, d) >> ((d) & 1)) + +typedef struct { + unsigned char numer; + unsigned char denom; +} cirrusClockRec; + +static cirrusClockRec cirrusClockTab[] = { + { 0x2C, 0x33 }, /* 12.599 */ + { 0x4A, 0x2B }, /* 25.227 */ + { 0x5B, 0x2F }, /* 28.325 */ + { 0x45, 0x30 }, /* 41.164 */ + { 0x7E, 0x33 }, /* 36.082 */ + { 0x42, 0x1F }, /* 31.500 */ + { 0x51, 0x3A }, /* 39.992 */ + { 0x55, 0x36 }, /* 45.076 */ + { 0x65, 0x3A }, /* 49.867 */ + { 0x76, 0x34 }, /* 64.983 */ + { 0x7E, 0x32 }, /* 72.163 */ + { 0x6E, 0x2A }, /* 75.000 */ + { 0x5F, 0x22 }, /* 80.013 */ + { 0x7D, 0x2A }, /* 85.226 */ + { 0x58, 0x1C }, /* 89.998 */ + { 0x49, 0x16 }, /* 95.019 */ + { 0x46, 0x14 }, /* 100.226 */ + { 0x53, 0x16 }, /* 108.035 */ + { 0x5C, 0x18 }, /* 110.248 */ + + { 0x6D, 0x1A }, /* 120.050 */ + { 0x58, 0x14 }, /* 125.998 */ + { 0x6D, 0x18 }, /* 130.055 */ + { 0x42, 0x0E }, /* 134.998 */ + + { 0x69, 0x14 }, /* 150.341 */ + { 0x5E, 0x10 }, /* 168.239 */ + { 0x5C, 0x0E }, /* 188.182 */ + { 0x67, 0x0E }, /* 210.682 */ + { 0x60, 0x0C }, /* 229.091 */ +}; + +#define NU_FIXED_CLOCKS (sizeof(cirrusClockTab)/sizeof(cirrusClockTab[0])) + + +/* + * This function returns the 7-bit numerator and 6-bit denominator/post-scalar + * value that corresponds to the closest clock found. + * If a frequency close to one of the tested clock values is found, + * use the tested clock since others can be unstable. + */ + +Bool +CirrusFindClock(int *rfreq, int max_clock, int *num_out, int *den_out) +{ + int n, i; + int num = 0, den = 0; + int freq, ffreq = 0, mindiff = 0; + + freq = *rfreq; + /* Prefer a tested value if it matches within 0.1%. */ + for (i = 0; i < NU_FIXED_CLOCKS; i++) { + int diff; + diff = abs(CLOCKVAL(cirrusClockTab[i].numer, + cirrusClockTab[i].denom) - freq); + if (diff < freq / 1000) { + num = cirrusClockTab[i].numer; + den = cirrusClockTab[i].denom; + ffreq = CLOCKVAL(num, den); + goto foundclock; + } + } + + /* + * If max_clock is greater than the MAX_VCO default, ignore + * MAX_VCO. On the other hand, if MAX_VCO is higher than max_clock, + * make use of the higher MAX_VCO value. + */ + if (MAX_VCO > max_clock) + max_clock = MAX_VCO; + + mindiff = freq; + for (n = 0x10; n < 0x7f; n++) { + int d; + for (d = 0x14; d < 0x3f; d++) { + int c, diff; + + /* Avoid combinations that can be unstable. */ + if ((VCOVAL(n, d) < MIN_VCO) || (VCOVAL(n, d) > max_clock)) + continue; + c = CLOCKVAL(n, d); + diff = abs(c - freq); + if (diff < mindiff) { + mindiff = diff; + num = n; + den = d; + ffreq = c; + } + } + } + + if (0 == num || 0 == den) + return FALSE; + +foundclock: + *num_out = num; + *den_out = den; + *rfreq = ffreq; + + return TRUE; +} diff --git a/src/alp.h b/src/alp.h new file mode 100644 index 0000000..01c5301 --- /dev/null +++ b/src/alp.h @@ -0,0 +1,87 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/cirrus/alp.h,v 1.8 2001/10/01 13:44:05 eich Exp $ */ + +/* (c) Itai Nahshon */ + +#ifndef ALP_H +#define ALP_H + +extern ScrnInfoPtr AlpProbe(int entity); +extern const OptionInfoRec * AlpAvailableOptions(int chipid); + +# ifdef _ALP_PRIVATE_ +/* Saved registers that are not part of the core VGA */ +/* CRTC >= 0x19; Sequencer >= 0x05; Graphics >= 0x09; Attribute >= 0x15 */ + +enum { + /* CR regs */ + CR1A, + CR1B, + CR1D, + /* SR regs */ + SR07, + SR0E, + SR12, + SR13, + SR17, + SR1E, + SR21, + SR2D, + /* GR regs */ + GR17, + GR18, + /* HDR */ + HDR, + /* Must be last! */ + CIR_NSAVED +}; + +typedef enum {LCD_NONE, LCD_DUAL_MONO, LCD_UNKNOWN, LCD_DSTN, LCD_TFT} LCDType; + +typedef struct { + unsigned char ExtVga[CIR_NSAVED]; +} AlpRegRec, *AlpRegPtr; + +extern Bool AlpHWCursorInit(ScreenPtr pScreen, int size); +extern Bool AlpXAAInit(ScreenPtr pScreen); +extern Bool AlpXAAInitMMIO(ScreenPtr pScreen); +extern Bool AlpDGAInit(ScreenPtr pScreen); +extern Bool AlpI2CInit(ScrnInfoPtr pScrn); + +/* Card-specific driver information */ +#define ALPPTR(p) ((AlpPtr)((p)->chip.alp)) + +typedef struct alpRec { + unsigned char * HWCursorBits; + unsigned char * CursorBits; + + AlpRegRec SavedReg; + AlpRegRec ModeReg; + LCDType lcdType; + int lcdWidth, lcdHeight; + int CursorWidth; + int CursorHeight; + int waitMsk; + int scanlineDest; + int scanlineCount; + int scanlineWidth; + + int SubsequentColorExpandScanlineDest; + int SubsequentColorExpandScanlineByteWidth; + int SubsequentColorExpandScanlineDWordWidth; + + /* Offset into framebuffer of a 8-byte scratch area for fills */ + CARD32 monoPattern8x8; + + Bool autoStart; + + /* MMIO Base for BitBLT operation. This is + IOBase for 5446 and 7548, IOBase+0x100 for 5480 */ + unsigned char * BLTBase; + CARD32 transRop; +/* XXX For XF86Config based mem configuration */ + CARD32 sr0f, sr17; +} AlpRec, *AlpPtr; + +# endif /* _ALP_PRIVATE_ */ +#endif /* ALP_H */ + diff --git a/src/alp_driver.c b/src/alp_driver.c new file mode 100644 index 0000000..87f8e9b --- /dev/null +++ b/src/alp_driver.c @@ -0,0 +1,2151 @@ +/* + * Driver for CL-GD5480. + * Itai Nahshon. + * + * Support for the CL-GD7548: David Monniaux + * + * This is mainly a cut & paste from the MGA driver. + * Original autors and contributors list include: + * Radoslaw Kapitan, Andrew Vanderstock, Dirk Hohndel, + * David Dawes, Andrew E. Mileski, Leonard N. Zubkoff, + * Guy DESBIEF + */ + +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/cirrus/alp_driver.c,v 1.28 2002/07/24 01:47:27 tsi Exp $ */ + +/* All drivers should typically include these */ +#include "xf86.h" +#include "xf86_OSproc.h" + +/* All drivers need this */ +#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" + +/* All drivers using the vgahw module need this */ +/* This driver needs to be modified to not use vgaHW for multihead operation */ +#include "vgaHW.h" + +#include "xf86RAC.h" +#include "xf86Resources.h" + +/* All drivers initialising the SW cursor need this */ +#include "mipointer.h" + +/* All drivers implementing backing store need this */ +#include "mibstore.h" + +#include "micmap.h" + +/* Needed by the Shadow Framebuffer */ +#include "shadowfb.h" + +/* Note: can HWCUR64 be set even though the hw cursor is disabled for + want of memory ? */ + +/* Framebuffer memory manager */ +#include "xf86fbman.h" + +#include "xf4bpp.h" +#include "xf1bpp.h" +#include "fb.h" + + +#include "xf86DDC.h" +#include "xf86int10.h" + +#include "cir.h" +#define _ALP_PRIVATE_ +#include "alp.h" + +#ifdef XvExtension +#include "xf86xv.h" +#include "Xv.h" +#endif + +#ifdef ALPPROBEI2C +/* For debugging... should go away. */ +static void AlpProbeI2C(int scrnIndex); +#endif + +/* + * Forward definitions for the functions that make up the driver. + */ + +/* Mandatory functions */ + +Bool AlpPreInit(ScrnInfoPtr pScrn, int flags); +Bool AlpScreenInit(int Index, ScreenPtr pScreen, int argc, char **argv); +Bool AlpEnterVT(int scrnIndex, int flags); +void AlpLeaveVT(int scrnIndex, int flags); +static Bool AlpCloseScreen(int scrnIndex, ScreenPtr pScreen); +static Bool AlpSaveScreen(ScreenPtr pScreen, int mode); + +/* Required if the driver supports mode switching */ +Bool AlpSwitchMode(int scrnIndex, DisplayModePtr mode, int flags); +/* Required if the driver supports moving the viewport */ +void AlpAdjustFrame(int scrnIndex, int x, int y, int flags); + +/* Optional functions */ +void AlpFreeScreen(int scrnIndex, int flags); +int AlpValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags); +/* Internally used functions */ +static void AlpSave(ScrnInfoPtr pScrn); +static void AlpRestore(ScrnInfoPtr pScrn); +static Bool AlpModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode); + +static void AlpProbeLCD(ScrnInfoPtr pScrn); + +static void AlpSetClock(CirPtr pCir, vgaHWPtr hwp, int freq); + +static void AlpOffscreenAccelInit(ScrnInfoPtr pScrn); + +static void AlpDisplayPowerManagementSet(ScrnInfoPtr pScrn, + int PowerManagementMode, int flags); + +/* + * This is intentionally screen-independent. It indicates the binding + * choice made in the first PreInit. + */ +static int pix24bpp = 0; + +typedef enum { + OPTION_HW_CURSOR, + OPTION_PCI_RETRY, + OPTION_NOACCEL, + OPTION_MMIO, + OPTION_ROTATE, + OPTION_SHADOW_FB, + OPTION_MEMCFG1, + OPTION_MEMCFG2 +} CirOpts; + +static const OptionInfoRec CirOptions[] = { + { OPTION_HW_CURSOR, "HWcursor", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_MMIO, "MMIO", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_SHADOW_FB, "ShadowFB", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_ROTATE, "Rotate", OPTV_ANYSTR, {0}, FALSE }, + { OPTION_MEMCFG1, "MemCFG1", OPTV_INTEGER, {0}, -1 }, + { OPTION_MEMCFG2, "MemCFG2", OPTV_INTEGER, {0}, -1 }, + { -1, NULL, OPTV_NONE, {0}, FALSE } +}; + +/* 1/4bpp 8bpp 15/16bpp 24bpp 32bpp +static int unsupp_MaxClocks[] = { 0, 0, 0, 0, 0 }; */ +static int gd5430_MaxClocks[] = { 85500, 85500, 50000, 28500, 0 }; +static int gd5446_MaxClocks[] = { 135100, 135100, 85500, 85500, 0 }; +static int gd5480_MaxClocks[] = { 135100, 200000, 200000, 135100, 135100 }; +static int gd7548_MaxClocks[] = { 80100, 80100, 80100, 80100, 80100 }; + +/* + * 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[] = { + "vgaHWFreeHWRec", + "vgaHWGetHWRec", + "vgaHWGetIOBase", + "vgaHWGetIndex", + "vgaHWHandleColormaps", + "vgaHWInit", + "vgaHWLock", + "vgaHWMapMem", + "vgaHWProtect", + "vgaHWRestore", + "vgaHWSave", + "vgaHWSaveScreen", + "vgaHWSetMmioFuncs", + "vgaHWSetStdFuncs", + "vgaHWUnlock", + NULL +}; + +static const char *miscfbSymbols[] = { + "xf1bppScreenInit", + "xf4bppScreenInit", + NULL +}; + +static const char *fbSymbols[] = { + "fbScreenInit", + "fbPictureInit", + NULL +}; + +static const char *xaaSymbols[] = { + "XAACreateInfoRec", + "XAADestroyInfoRec", + "XAAInit", + NULL +}; + +static const char *ramdacSymbols[] = { + "xf86CreateCursorInfoRec", + "xf86DestroyCursorInfoRec", + "xf86InitCursor", + NULL +}; + +static const char *int10Symbols[] = { + "xf86FreeInt10", + "xf86InitInt10", + NULL +}; + +static const char *shadowSymbols[] = { + "ShadowFBInit", + NULL +}; + +static const char *ddcSymbols[] = { + "xf86PrintEDID", + "xf86DoEDID_DDC2", + "xf86SetDDCproperties", + NULL +}; + +static const char *i2cSymbols[] = { + "xf86CreateI2CBusRec", + "xf86I2CBusInit", + NULL +}; + +#ifdef XFree86LOADER + +#define ALP_MAJOR_VERSION 1 +#define ALP_MINOR_VERSION 0 +#define ALP_PATCHLEVEL 0 + +static MODULESETUPPROTO(alpSetup); + +static XF86ModuleVersionInfo alpVersRec = +{ + "cirrus_alpine", + MODULEVENDORSTRING, + MODINFOSTRING1, + MODINFOSTRING2, + XF86_VERSION_CURRENT, + ALP_MAJOR_VERSION, ALP_MINOR_VERSION, ALP_PATCHLEVEL, + ABI_CLASS_VIDEODRV, /* This is a video driver */ + ABI_VIDEODRV_VERSION, + MOD_CLASS_NONE, + {0,0,0,0} +}; + +/* + * This is the module init data. + * Its name has to be the driver name followed by ModuleData. + */ +XF86ModuleData cirrus_alpineModuleData = { &alpVersRec, alpSetup, NULL }; + +static pointer +alpSetup(pointer module, pointer opts, int *errmaj, int *errmin) +{ + static Bool setupDone = FALSE; + if (!setupDone) { + setupDone = TRUE; + LoaderRefSymLists(vgahwSymbols, fbSymbols, xaaSymbols, + miscfbSymbols, ramdacSymbols,int10Symbols, + ddcSymbols, i2cSymbols, shadowSymbols, NULL); + } + return (pointer)1; +} + +#endif /* XFree86LOADER */ + +const OptionInfoRec * +AlpAvailableOptions(int chipid) +{ + return CirOptions; +} + +ScrnInfoPtr +AlpProbe(int entity) +{ + ScrnInfoPtr pScrn = NULL; + + if ((pScrn = xf86ConfigPciEntity(pScrn, 0, entity, CIRPciChipsets, + NULL,NULL, NULL, NULL, NULL))) { + pScrn->PreInit = AlpPreInit; + pScrn->ScreenInit = AlpScreenInit; + pScrn->SwitchMode = AlpSwitchMode; + pScrn->AdjustFrame = AlpAdjustFrame; + pScrn->EnterVT = AlpEnterVT; + pScrn->LeaveVT = AlpLeaveVT; + pScrn->FreeScreen = AlpFreeScreen; + pScrn->ValidMode = AlpValidMode; + } + + return pScrn; +} + + +static Bool +AlpGetRec(ScrnInfoPtr pScrn) +{ +#ifdef ALP_DEBUG + ErrorF("AlpGetRec\n"); +#endif + if (pScrn->driverPrivate != NULL) + return TRUE; + + pScrn->driverPrivate = xnfcalloc(sizeof(CirRec), 1); + ((CirPtr)pScrn->driverPrivate)->chip.alp = xnfcalloc(sizeof(AlpRec),1); + +#ifdef ALP_DEBUG + ErrorF("AlpGetRec 0x%x\n", CIRPTR(pScrn)); +#endif + return TRUE; +} + +static void +AlpFreeRec(ScrnInfoPtr pScrn) +{ + if (pScrn->driverPrivate == NULL) + return; + xfree(pScrn->driverPrivate); + pScrn->driverPrivate = NULL; +} + + +/* + * AlpCountRAM -- + * + * Counts amount of installed RAM + * + * XXX Can use options to configure memory on non-primary cards. + */ +static int +AlpCountRam(ScrnInfoPtr pScrn) +{ + CirPtr pCir = CIRPTR(pScrn); + vgaHWPtr hwp = VGAHWPTR(pScrn); + MessageType from; + int videoram = 0; + + /* Map the Alp memory and MMIO areas */ + pCir->FbMapSize = 1024*1024; /* XX temp */ + pCir->IoMapSize = 0x4000; /* 16K for moment */ + if (!CirMapMem(pCir, pScrn->scrnIndex)) + return 0; + + /* The 754x supports MMIO for the BitBlt engine but + not for the VGA registers */ + switch (pCir->Chipset) + { + case PCI_CHIP_GD7548: + break; + default: + if (pCir->UseMMIO) + vgaHWSetMmioFuncs(hwp, pCir->IOBase, -0x3C0); + } + + if (pCir->chip.alp->sr0f != (CARD32)-1) { + from = X_CONFIG; + hwp->writeSeq(hwp, 0x0F, pCir->chip.alp->sr0f); + } else { + from = X_PROBED; + pCir->chip.alp->sr0f = hwp->readSeq(hwp, 0x0F); + } + xf86DrvMsg(pScrn->scrnIndex, from, "Memory Config reg 1 is 0x%02X\n", + pCir->chip.alp->sr0f); + + switch (pCir->Chipset) { + case PCI_CHIP_GD5430: +/* case PCI_CHIP_GD5440: */ + switch (pCir->chip.alp->sr0f & 0x18) { + case 0x08: + videoram = 512; + break; + case 0x10: + videoram = 1024; + break; + case 0x18: + videoram = 2048; + break; + } + break; + + case PCI_CHIP_GD5434_4: + case PCI_CHIP_GD5434_8: + case PCI_CHIP_GD5436: + switch (pCir->chip.alp->sr0f & 0x18) { + case 0x10: + videoram = 1024; + break; + case 0x18: + videoram = 2048; + if (pCir->chip.alp->sr0f & 0x80) + videoram = 4096; + break; + } + + case PCI_CHIP_GD5446: + videoram = 1024; + + if (pCir->chip.alp->sr17 != (CARD32)-1) { + from = X_CONFIG; + hwp->writeSeq(hwp, 0x17, pCir->chip.alp->sr17); + } else { + from = X_PROBED; + pCir->chip.alp->sr17 = hwp->readSeq(hwp, 0x17); + } + xf86DrvMsg(pScrn->scrnIndex, from, "Memory Config reg 2 is 0x%02X\n", + pCir->chip.alp->sr17); + + if ((pCir->chip.alp->sr0f & 0x18) == 0x18) { + if (pCir->chip.alp->sr0f & 0x80) { + if (pCir->chip.alp->sr17 & 0x80) + videoram = 2048; + else if (pCir->chip.alp->sr17 & 0x02) + videoram = 3072; + else + videoram = 4096; + } else { + if ((pCir->chip.alp->sr17 & 80) == 0) + videoram = 2048; + } + } + break; + + case PCI_CHIP_GD5480: + if (pCir->chip.alp->sr17 != (CARD32)-1) { + from = X_CONFIG; + hwp->writeSeq(hwp, 0x17, pCir->chip.alp->sr17); + } else { + from = X_PROBED; + pCir->chip.alp->sr17 = hwp->readSeq(hwp, 0x17); + } + xf86DrvMsg(pScrn->scrnIndex, from, "Memory Config reg 2 is 0x%02X\n", + pCir->chip.alp->sr17); + videoram = 1024; + if ((pCir->chip.alp->sr0f & 0x18) == 0x18) { /* 2 or 4 MB */ + videoram = 2048; + if (pCir->chip.alp->sr0f & 0x80) /* Second bank enable */ + videoram = 4096; + } + if (pCir->chip.alp->sr17 & 0x80) + videoram <<= 1; + break; + + case PCI_CHIP_GD7548: + videoram = 1024; /* TODO: actual size */ + break; + } + + /* UNMap the Alp memory and MMIO areas */ + if (!CirUnmapMem(pCir, pScrn->scrnIndex)) + return 0; + vgaHWSetStdFuncs(hwp); + + return videoram; +} + + +/* + * GetAccelPitchValues - + * + * This function returns a list of display width (pitch) values that can + * be used in accelerated mode. + */ +static int * +GetAccelPitchValues(ScrnInfoPtr pScrn) +{ + int *linePitches = NULL; + int i, n = 0; + CirPtr pCir = CIRPTR(pScrn); + + /* XXX ajv - 512, 576, and 1536 may not be supported + line pitches. see sdk pp 4-59 for more + details. Why anyone would want less than 640 is + bizarre. (maybe lots of pixels tall?) */ + + /* The only line pitches the accelerator supports */ +#if 1 + int accelWidths[] = { 640, 768, 800, 960, 1024, 1152, 1280, + 1600, 1920, 2048, 0 }; +#else + int accelWidths[] = { 512, 576, 640, 768, 800, 960, 1024, 1152, + 1280, 1536, 1600, 1920, 2048, 0 }; +#endif + + for (i = 0; accelWidths[i] != 0; i++) { + if (accelWidths[i] % pCir->Rounding == 0) { + n++; + linePitches = xnfrealloc(linePitches, n * sizeof(int)); + linePitches[n - 1] = accelWidths[i]; + } + } + /* Mark the end of the list */ + if (n > 0) { + linePitches = xnfrealloc(linePitches, (n + 1) * sizeof(int)); + linePitches[n] = 0; + } + return linePitches; +} + + +/* Mandatory */ +Bool +AlpPreInit(ScrnInfoPtr pScrn, int flags) +{ + CirPtr pCir; + vgaHWPtr hwp; + MessageType from, from1; + int i; + ClockRangePtr clockRanges; + char *s; + xf86Int10InfoPtr pInt = NULL; + + if (flags & PROBE_DETECT) { + cirProbeDDC( pScrn, xf86GetEntityInfo(pScrn->entityList[0])->index ); + return TRUE; + } + +#ifdef ALP_DEBUG + ErrorF("AlpPreInit\n"); +#endif + + /* Check the number of entities, and fail if it isn't one. */ + if (pScrn->numEntities != 1) + return FALSE; + + if (!xf86LoadSubModule(pScrn, "vgahw")) + return FALSE; + + xf86LoaderReqSymLists(vgahwSymbols, NULL); + + /* + * Allocate a vgaHWRec + */ + if (!vgaHWGetHWRec(pScrn)) + return FALSE; + hwp = VGAHWPTR(pScrn); + vgaHWGetIOBase(hwp); + + /* Allocate the AlpRec driverPrivate */ + if (!AlpGetRec(pScrn)) + return FALSE; + + pCir = CIRPTR(pScrn); + pCir->pScrn = pScrn; + pCir->PIOReg = hwp->PIOOffset + 0x3CE; + + /* Get the entity, and make sure it is PCI. */ + pCir->pEnt = xf86GetEntityInfo(pScrn->entityList[0]); + if (pCir->pEnt->location.type != BUS_PCI) + return FALSE; + + pCir->Chipset = pCir->pEnt->chipset; + /* Find the PCI info for this screen */ + pCir->PciInfo = xf86GetPciInfoForEntity(pCir->pEnt->index); + pCir->PciTag = pciTag(pCir->PciInfo->bus, + pCir->PciInfo->device, + pCir->PciInfo->func); + + if (xf86LoadSubModule(pScrn, "int10")) { + xf86LoaderReqSymLists(int10Symbols,NULL); + xf86DrvMsg(pScrn->scrnIndex,X_INFO,"initializing int10\n"); + pInt = xf86InitInt10(pCir->pEnt->index); + xf86FreeInt10(pInt); + /* + * This is a hack: We restore the PCI base regs as some Colorgraphic + * BIOSes tend to mess them up + */ + pciWriteLong(pCir->PciTag,0x10,pCir->PciInfo->memBase[0]); + pciWriteLong(pCir->PciTag,0x14,pCir->PciInfo->memBase[1]); + + } + + /* Set pScrn->monitor */ + pScrn->monitor = pScrn->confScreen->monitor; + + /* + * The first thing we should figure out is the depth, bpp, etc. + * Our default depth is 8, so pass it to the helper function. + * We support both 24bpp and 32bpp layouts, so indicate that. + */ + 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: + /* 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); + + /* + * 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; + } + /* Collect all of the relevant option flags (fill in pScrn->options) */ + xf86CollectOptions(pScrn, NULL); + + /* Process the options */ + if (!(pCir->Options = xalloc(sizeof(CirOptions)))) + return FALSE; + memcpy(pCir->Options, CirOptions, sizeof(CirOptions)); + xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pCir->Options); + + if (!xf86IsPrimaryPci(pCir->PciInfo) + && !(pInt || (xf86IsOptionSet(pCir->Options,OPTION_MEMCFG1) + && xf86IsOptionSet(pCir->Options,OPTION_MEMCFG2)))) + return FALSE; + + if (pScrn->depth == 8) + pScrn->rgbBits = 6; + + from = X_DEFAULT; + pCir->HWCursor = FALSE; + if (xf86GetOptValBool(pCir->Options, OPTION_HW_CURSOR, &pCir->HWCursor)) + from = X_CONFIG; + + xf86DrvMsg(pScrn->scrnIndex, from, "Using %s cursor\n", + pCir->HWCursor ? "HW" : "SW"); + if (xf86ReturnOptValBool(pCir->Options, OPTION_NOACCEL, FALSE)) { + pCir->NoAccel = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Acceleration disabled\n"); + } + if(pScrn->bitsPerPixel < 8) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Cannot use accelerations in less than 8 bpp\n"); + pCir->NoAccel = TRUE; + } + + /* + * Set the ChipRev, allowing config file entries to + * override. + */ + if (pCir->pEnt->device->chipRev >= 0) { + pCir->ChipRev = pCir->pEnt->device->chipRev; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n", + pCir->ChipRev); + } else { + pCir->ChipRev = pCir->PciInfo->chipRev; + } + + /* Find the frame buffer base address */ + if (pCir->pEnt->device->MemBase != 0) { + if (!xf86CheckPciMemBase(pCir->PciInfo, pCir->pEnt->device->MemBase)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "MemBase 0x%08lX doesn't match any PCI base register.\n", + pCir->pEnt->device->MemBase); + return FALSE; + } + pCir->FbAddress = pCir->pEnt->device->MemBase; + from = X_CONFIG; + } else { + if (pCir->PciInfo->memBase[0] != 0) { + /* 5446B and 5480 use mask of 0xfe000000. + 5446A uses 0xff000000. */ + pCir->FbAddress = pCir->PciInfo->memBase[0] & 0xff000000; + from = X_PROBED; + } else { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "No valid FB address in PCI config space\n"); + AlpFreeRec(pScrn); + return FALSE; + } + } + xf86DrvMsg(pScrn->scrnIndex, from, "Linear framebuffer at 0x%lX\n", + (unsigned long)pCir->FbAddress); + + if (pCir->pEnt->device->IOBase != 0) { + /* Require that the config file value matches one of the PCI values. */ + if (!xf86CheckPciMemBase(pCir->PciInfo, pCir->pEnt->device->IOBase)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "IOBase 0x%08lX doesn't match any PCI base register.\n", + pCir->pEnt->device->IOBase); + return FALSE; + } + pCir->IOAddress = pCir->pEnt->device->IOBase; + from = X_CONFIG; + } else { + if (pCir->PciInfo->memBase[1] != 0) { + pCir->IOAddress = pCir->PciInfo->memBase[1] & 0xfffff000; + from = X_PROBED; + } else { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "No valid MMIO address in PCI config space\n"); + /* 5446 rev A do not use a separate MMIO segment */ + /* We do not really need that YET. */ + } + } + + /* User options can override the MMIO default */ +#if 0 + /* Will we ever support MMIO on 5446A or older? */ + if (xf86ReturnOptValBool(pCir->Options, OPTION_MMIO, FALSE)) { + pCir->UseMMIO = TRUE; + from = X_CONFIG; + } +#endif + if (!xf86ReturnOptValBool(pCir->Options, OPTION_MMIO, TRUE)) { + pCir->UseMMIO = FALSE; + from1 = X_CONFIG; + } else if (pCir->IOAddress) { + /* Default to MMIO if we have a separate IOAddress and + not in monochrome mode (IO 0x3Bx is not relocated!) */ + if (pScrn->bitsPerPixel != 1) { + pCir->UseMMIO = TRUE; + from1 = X_PROBED; + } else { + pCir->UseMMIO = FALSE; + from1 = X_PROBED; + } + } else { + pCir->UseMMIO = FALSE; + from1 = X_PROBED; + } + + if (pCir->UseMMIO) { + xf86DrvMsg(pScrn->scrnIndex, from1, "Using MMIO\n"); + xf86DrvMsg(pScrn->scrnIndex, from, "MMIO registers at 0x%lX\n", + (unsigned long)pCir->IOAddress); + } else + xf86DrvMsg(pScrn->scrnIndex, from1, "Not Using MMIO\n"); + + /* + * XXX Check if this is correct + */ + if (!pCir->UseMMIO) { + pScrn->racIoFlags = RAC_COLORMAP | RAC_CURSOR | RAC_VIEWPORT | RAC_FB; + xf86SetOperatingState(resVgaMem, pCir->pEnt->index, ResUnusedOpr); + } else { + xf86SetOperatingState(resVga, pCir->pEnt->index, ResUnusedOpr); + } + + /* Register the PCI-assigned resources. */ + if (xf86RegisterResources(pCir->pEnt->index, NULL, ResExclusive)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "xf86RegisterResources() found resource conflicts\n"); + return FALSE; + } + + if (!xf86LoadSubModule(pScrn, "i2c")) { + AlpFreeRec(pScrn); + return FALSE; + } + xf86LoaderReqSymLists(i2cSymbols,NULL); + + if (!xf86LoadSubModule(pScrn, "ddc")) { + AlpFreeRec(pScrn); + return FALSE; + } + xf86LoaderReqSymLists(ddcSymbols, NULL); + + if(!AlpI2CInit(pScrn)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "I2C initialization failed\n"); + } + else + xf86SetDDCproperties(pScrn,xf86PrintEDID( + xf86DoEDID_DDC2(pScrn->scrnIndex,pCir->I2CPtr1))); + + /* Probe the possible LCD display */ + AlpProbeLCD(pScrn); + +#ifdef CIRPROBEI2C + CirProbeI2C(pScrn->scrnIndex); +#endif + + /* 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; + } + + /* XXX If UseMMIO == TRUE and for any reason we cannot do MMIO, + abort here */ + + if (xf86GetOptValBool(pCir->Options, + OPTION_SHADOW_FB,&pCir->shadowFB)) + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ShadowFB %s.\n", + pCir->shadowFB ? "enabled" : "disabled"); + + if ((s = xf86GetOptValString(pCir->Options, OPTION_ROTATE))) { + if(!xf86NameCmp(s, "CW")) { + /* accel is disabled below for shadowFB */ + pCir->shadowFB = TRUE; + pCir->rotate = 1; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "Rotating screen clockwise - acceleration disabled\n"); + } else if(!xf86NameCmp(s, "CCW")) { + pCir->shadowFB = TRUE; + pCir->rotate = -1; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Rotating screen" + "counter clockwise - acceleration disabled\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"); + } + } + if (pCir->shadowFB && (pScrn->depth < 8)) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "shadowFB not supported at this depth.\n"); + pCir->shadowFB = FALSE; + pCir->rotate = 0; + } + + if (pCir->shadowFB && !pCir->NoAccel) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "HW acceleration not supported with \"shadowFB\".\n"); + pCir->NoAccel = TRUE; + } + + if (pCir->rotate && pCir->HWCursor) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "HW cursor not supported with \"rotate\".\n"); + pCir->HWCursor = FALSE; + } + + /* XXX We do not know yet how to configure memory on this card. + Use options MemCFG1 and MemCFG2 to set registers SR0F and + SR17 before trying to count ram size. */ + + pCir->chip.alp->sr0f = (CARD32)-1; + pCir->chip.alp->sr17 = (CARD32)-1; + + (void) xf86GetOptValULong(pCir->Options, OPTION_MEMCFG1, (unsigned long *)&pCir->chip.alp->sr0f); + (void) xf86GetOptValULong(pCir->Options, OPTION_MEMCFG2, (unsigned long *)&pCir->chip.alp->sr17); + /* + * If the user has specified the amount of memory in the XF86Config + * file, we respect that setting. + */ + if (pCir->pEnt->device->videoRam != 0) { + pScrn->videoRam = pCir->pEnt->device->videoRam; + pCir->IoMapSize = 0x4000; /* 16K for moment */ + from = X_CONFIG; + } else { + pScrn->videoRam = AlpCountRam(pScrn); + from = X_PROBED; + } + xf86DrvMsg(pScrn->scrnIndex, from, "VideoRAM: %d kByte\n", pScrn->videoRam); + + pCir->FbMapSize = pScrn->videoRam * 1024; + + /* properties */ + pCir->properties = 0; + + if ((pCir->chip.alp->sr0f & 0x18) > 0x8) + pCir->properties |= HWCUR64; + + switch (pCir->Chipset) { + case PCI_CHIP_GD7548: + pCir->properties |= HWCUR64; + pCir->properties |= ACCEL_AUTOSTART; + break; + case PCI_CHIP_GD5436: + case PCI_CHIP_GD5480: + pCir->properties |= ACCEL_AUTOSTART; + break; + default: + break; + } + + /* We use a programmable clock */ + pScrn->progClock = TRUE; + + /* XXX Set HW cursor use */ + + /* Set the min pixel clock */ + pCir->MinClock = 12000; /* XXX Guess, need to check this */ + xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "Min pixel clock is %d MHz\n", + pCir->MinClock / 1000); + /* + * If the user has specified ramdac speed in the XF86Config + * file, we respect that setting. + */ + if (pCir->pEnt->device->dacSpeeds[0]) { + ErrorF("Do not specily a Clocks line for Cirrus chips\n"); + return FALSE; + } else { + int speed; + int *p = NULL; + switch (pCir->Chipset) { + case PCI_CHIP_GD5430: + case PCI_CHIP_GD5434_4: + case PCI_CHIP_GD5434_8: + case PCI_CHIP_GD5436: + /* case PCI_CHIP_GD5440: */ + p = gd5430_MaxClocks; + break; + case PCI_CHIP_GD5446: + p = gd5446_MaxClocks; + break; + case PCI_CHIP_GD5480: + p = gd5480_MaxClocks; + break; + case PCI_CHIP_GD7548: + p = gd7548_MaxClocks; + break; + } + if (!p) + return FALSE; + switch(pScrn->bitsPerPixel) { + case 1: + case 4: + speed = p[0]; + break; + case 8: + speed = p[1]; + break; + case 15: + case 16: + speed = p[2]; + break; + case 24: + speed = p[3]; + break; + case 32: + speed = p[4]; + break; + default: + /* Should not get here */ + speed = 0; + break; + } + pCir->MaxClock = speed; + from = X_PROBED; + } + xf86DrvMsg(pScrn->scrnIndex, from, "Max pixel clock is %d MHz\n", + pCir->MaxClock / 1000); + + /* + * 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->minClock = pCir->MinClock; + clockRanges->maxClock = pCir->MaxClock; + clockRanges->clockIndex = -1; /* programmable */ + clockRanges->interlaceAllowed = FALSE; /* XXX check this */ + clockRanges->doubleScanAllowed = FALSE; /* XXX check this */ + clockRanges->doubleScanAllowed = FALSE; /* XXX check this */ + clockRanges->doubleScanAllowed = FALSE; /* XXX check this */ + clockRanges->ClockMulFactor = 1; + clockRanges->ClockDivFactor = 1; + clockRanges->PrivFlags = 0; + + switch (pCir->Chipset) + { + case PCI_CHIP_GD7548: + pCir->Rounding = 1; + break; + + default: + pCir->Rounding = 128 >> pCir->BppShift; + } + +#if 0 + if (pCir->Chipset != PCI_CHIP_GD5446 && + pCir->Chipset != PCI_CHIP_GD5480) { + /* XXX Kludge */ + pCir->NoAccel = TRUE; + } +#endif + + /* + * xf86ValidateModes will check that the mode HTotal and VTotal values + * don't exceed the chipset's limit if pScrn->maxHValue and + * pScrn->maxVValue are set. Since our AlpValidMode() already takes + * care of this, we don't worry about setting them here. + */ + + /* Select valid modes from those available */ + if (pCir->NoAccel) { + /* + * XXX Assuming min pitch 256, max 2048 + * XXX Assuming min height 128, max 2048 + */ + i = xf86ValidateModes(pScrn, pScrn->monitor->Modes, + pScrn->display->modes, clockRanges, + NULL, 256, 2048, + pCir->Rounding * pScrn->bitsPerPixel, 128, 2048, + pScrn->display->virtualX, + pScrn->display->virtualY, + pCir->FbMapSize, + LOOKUP_BEST_REFRESH); + } else { + /* + * XXX Assuming min height 128, max 2048 + */ + i = xf86ValidateModes(pScrn, pScrn->monitor->Modes, + pScrn->display->modes, clockRanges, + GetAccelPitchValues(pScrn), 0, 0, + pCir->Rounding * pScrn->bitsPerPixel, 128, 2048, + pScrn->display->virtualX, + pScrn->display->virtualY, + pCir->FbMapSize, + LOOKUP_BEST_REFRESH); + } + if (i == -1) { + AlpFreeRec(pScrn); + return FALSE; + } + + /* Prune the modes marked as invalid */ + xf86PruneDriverModes(pScrn); + + if (i == 0 || pScrn->modes == NULL) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n"); + AlpFreeRec(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); + + /* Set display resolution */ + xf86SetDpi(pScrn, 0, 0); + + /* Load bpp-specific modules */ + switch (pScrn->bitsPerPixel) { + case 1: + if (xf86LoadSubModule(pScrn, "xf1bpp") == NULL) { + AlpFreeRec(pScrn); + return FALSE; + } + xf86LoaderReqSymbols("xf1bppScreenInit",NULL); + break; + case 4: + if (xf86LoadSubModule(pScrn, "xf4bpp") == NULL) { + AlpFreeRec(pScrn); + return FALSE; + } + xf86LoaderReqSymbols("xf4bppScreenInit",NULL); + break; + case 8: + case 16: + case 24: + case 32: + if (xf86LoadSubModule(pScrn, "fb") == NULL) { + AlpFreeRec(pScrn); + return FALSE; + } + xf86LoaderReqSymLists(fbSymbols, NULL); + break; + } + + /* Load XAA if needed */ + if (!pCir->NoAccel) { + if (!xf86LoadSubModule(pScrn, "xaa")) { + AlpFreeRec(pScrn); + return FALSE; + } + xf86LoaderReqSymLists(xaaSymbols, NULL); + } + + /* Load ramdac if needed */ + if (pCir->HWCursor) { + if (!xf86LoadSubModule(pScrn, "ramdac")) { + AlpFreeRec(pScrn); + return FALSE; + } + xf86LoaderReqSymLists(ramdacSymbols, NULL); + } + + if (pCir->shadowFB) { + if (!xf86LoadSubModule(pScrn, "shadowfb")) { + AlpFreeRec(pScrn); + return FALSE; + } + xf86LoaderReqSymLists(shadowSymbols, NULL); + } + + return TRUE; +} + +/* + * This function saves the video state. + */ +static void +AlpSave(ScrnInfoPtr pScrn) +{ + CirPtr pCir = CIRPTR(pScrn); + vgaHWPtr hwp = VGAHWPTR(pScrn); + +#ifdef ALP_DEBUG + ErrorF("AlpSave\n"); +#endif + vgaHWSave(pScrn, &VGAHWPTR(pScrn)->SavedReg, VGA_SR_ALL); + + pCir->chip.alp->ModeReg.ExtVga[CR1A] = pCir->chip.alp->SavedReg.ExtVga[CR1A] = hwp->readCrtc(hwp, 0x1A); + pCir->chip.alp->ModeReg.ExtVga[CR1B] = pCir->chip.alp->SavedReg.ExtVga[CR1B] = hwp->readCrtc(hwp, 0x1B); + pCir->chip.alp->ModeReg.ExtVga[CR1D] = pCir->chip.alp->SavedReg.ExtVga[CR1D] = hwp->readCrtc(hwp, 0x1D); + pCir->chip.alp->ModeReg.ExtVga[SR07] = pCir->chip.alp->SavedReg.ExtVga[SR07] = hwp->readSeq(hwp, 0x07); + pCir->chip.alp->ModeReg.ExtVga[SR0E] = pCir->chip.alp->SavedReg.ExtVga[SR0E] = hwp->readSeq(hwp, 0x0E); + pCir->chip.alp->ModeReg.ExtVga[SR12] = pCir->chip.alp->SavedReg.ExtVga[SR12] = hwp->readSeq(hwp, 0x12); + pCir->chip.alp->ModeReg.ExtVga[SR13] = pCir->chip.alp->SavedReg.ExtVga[SR13] = hwp->readSeq(hwp, 0x13); + pCir->chip.alp->ModeReg.ExtVga[SR17] = pCir->chip.alp->SavedReg.ExtVga[SR17] = hwp->readSeq(hwp, 0x17); + pCir->chip.alp->ModeReg.ExtVga[SR1E] = pCir->chip.alp->SavedReg.ExtVga[SR1E] = hwp->readSeq(hwp, 0x1E); + pCir->chip.alp->ModeReg.ExtVga[SR21] = pCir->chip.alp->SavedReg.ExtVga[SR21] = hwp->readSeq(hwp, 0x21); + pCir->chip.alp->ModeReg.ExtVga[SR2D] = pCir->chip.alp->SavedReg.ExtVga[SR2D] = hwp->readSeq(hwp, 0x2D); + pCir->chip.alp->ModeReg.ExtVga[GR17] = pCir->chip.alp->SavedReg.ExtVga[GR17] = hwp->readGr(hwp, 0x17); + pCir->chip.alp->ModeReg.ExtVga[GR18] = pCir->chip.alp->SavedReg.ExtVga[GR18] = hwp->readGr(hwp, 0x18); + /* The first 4 reads are for the pixel mask register. After 4 times that + this register is accessed in succession reading/writing this address + accesses the HDR. */ + hwp->readDacMask(hwp); + hwp->readDacMask(hwp); + hwp->readDacMask(hwp); + hwp->readDacMask(hwp); + pCir->chip.alp->ModeReg.ExtVga[HDR] = pCir->chip.alp->SavedReg.ExtVga[HDR] = hwp->readDacMask(hwp); +} + +/* XXX */ +static void +AlpFix1bppColorMap(ScrnInfoPtr pScrn) +{ + vgaHWPtr hwp = VGAHWPTR(pScrn); +/* In 1 bpp we have color 0 at LUT 0 and color 1 at LUT 0x3f. + This makes white and black look right (otherwise they were both + black. I'm sure there's a better way to do that, just lazy to + search the docs. */ + + hwp->writeDacWriteAddr(hwp, 0x00); + hwp->writeDacData(hwp, 0x00); hwp->writeDacData(hwp, 0x00); hwp->writeDacData(hwp, 0x00); + hwp->writeDacWriteAddr(hwp, 0x3F); + hwp->writeDacData(hwp, 0x3F); hwp->writeDacData(hwp, 0x3F); hwp->writeDacData(hwp, 0x3F); +} + +static void +alpRestore(vgaHWPtr hwp, AlpRegPtr cirReg) +{ + hwp->writeCrtc(hwp, 0x1A, cirReg->ExtVga[CR1A]); + hwp->writeCrtc(hwp, 0x1B, cirReg->ExtVga[CR1B]); + hwp->writeCrtc(hwp, 0x1D, cirReg->ExtVga[CR1D]); + hwp->writeSeq(hwp, 0x07, cirReg->ExtVga[SR07]); + hwp->writeSeq(hwp, 0x0E, cirReg->ExtVga[SR0E]); + hwp->writeSeq(hwp, 0x12, cirReg->ExtVga[SR12]); + hwp->writeSeq(hwp, 0x13, cirReg->ExtVga[SR13]); + hwp->writeSeq(hwp, 0x17, cirReg->ExtVga[SR17]); + hwp->writeSeq(hwp, 0x1E, cirReg->ExtVga[SR1E]); + hwp->writeSeq(hwp, 0x21, cirReg->ExtVga[SR21]); + hwp->writeSeq(hwp, 0x2D, cirReg->ExtVga[SR2D]); + hwp->writeGr(hwp, 0x17, cirReg->ExtVga[GR17]); + hwp->writeGr(hwp, 0x18, cirReg->ExtVga[GR18]); + /* The first 4 reads are for the pixel mask register. After 4 times that + this register is accessed in succession reading/writing this address + accesses the HDR. */ + hwp->readDacMask(hwp); + hwp->readDacMask(hwp); + hwp->readDacMask(hwp); + hwp->readDacMask(hwp); + hwp->writeDacMask(hwp, cirReg->ExtVga[HDR ]); +} + + +/* + * Initialise a new mode. This is currently still using the old + * "initialise struct, restore/write struct to HW" model. That could + * be changed. + * Why?? (EE) + */ + +static Bool +AlpModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode) +{ + vgaHWPtr hwp; + vgaRegPtr vgaReg; + CirPtr pCir; + int depthcode; + int width; + Bool HDiv2 = FALSE, VDiv2 = FALSE; + +#ifdef ALP_DEBUG + ErrorF("AlpModeInit %d bpp, %d %d %d %d %d %d %d %d %d\n", + pScrn->bitsPerPixel, + mode->Clock, + mode->HDisplay, + mode->HSyncStart, + mode->HSyncEnd, + mode->HTotal, + mode->VDisplay, + mode->VSyncStart, + mode->VSyncEnd, + mode->VTotal); + + ErrorF("AlpModeInit: depth %d bits\n", pScrn->depth); +#endif + + pCir = CIRPTR(pScrn); + hwp = VGAHWPTR(pScrn); + vgaHWUnlock(hwp); + + pCir->pitch = pScrn->displayWidth * pScrn->bitsPerPixel >> 3; + + depthcode = pScrn->depth; + if (pScrn->bitsPerPixel == 32) + depthcode = 32; + + if ((pCir->Chipset == PCI_CHIP_GD5480 && mode->Clock > 135100) || + (pCir->Chipset == PCI_CHIP_GD5446 && mode->Clock > 85500)) { + /* The actual DAC register value is set later. */ + /* The CRTC is clocked at VCLK / 2, so we must half the */ + /* horizontal timings. */ + if (!mode->CrtcHAdjusted) { + mode->CrtcHDisplay >>= 1; + mode->CrtcHSyncStart >>= 1; + mode->CrtcHTotal >>= 1; + mode->CrtcHSyncEnd >>= 1; + mode->SynthClock >>= 1; + mode->CrtcHAdjusted = TRUE; + } + depthcode += 64; + HDiv2 = TRUE; + } + + if (mode->VTotal >= 1024 && !(mode->Flags & V_INTERLACE)) { + /* For non-interlaced vertical timing >= 1024, the vertical timings */ + /* are divided by 2 and VGA CRTC 0x17 bit 2 is set. */ + if (!mode->CrtcVAdjusted) { + mode->CrtcVDisplay >>= 1; + mode->CrtcVSyncStart >>= 1; + mode->CrtcVSyncEnd >>= 1; + mode->CrtcVTotal >>= 1; + mode->CrtcVAdjusted = TRUE; + } + VDiv2 = TRUE; + } + + /* Initialise the ModeReg values */ + if (!vgaHWInit(pScrn, mode)) + return FALSE; + pScrn->vtSema = TRUE; + + /* Turn off HW cursor, gamma correction, overscan color protect. */ + pCir->chip.alp->ModeReg.ExtVga[SR12] = 0; + if ((pCir->properties & HWCUR64) == HWCUR64) + { + pCir->chip.alp->ModeReg.ExtVga[SR12] = 0x4; + switch (pCir->Chipset) + { + case PCI_CHIP_GD7548: + pCir->chip.alp->ModeReg.ExtVga[SR21] |= 0x10; + break; + } + + } + else + pCir->chip.alp->ModeReg.ExtVga[SR12] = 0; + + + if(VDiv2) + hwp->ModeReg.CRTC[0x17] |= 0x04; + +#ifdef ALP_DEBUG + ErrorF("SynthClock = %d\n", mode->SynthClock); +#endif + + /* Disable DCLK pin driver, interrupts. */ + pCir->chip.alp->ModeReg.ExtVga[GR17] |= 0x08; + pCir->chip.alp->ModeReg.ExtVga[GR17] &= ~0x04; + + vgaReg = &hwp->ModeReg; + + pCir->chip.alp->ModeReg.ExtVga[HDR] = 0; + /* Enable linear mode and high-res packed pixel mode */ + pCir->chip.alp->ModeReg.ExtVga[SR07] &= 0xe0; +#ifdef ALP_DEBUG + ErrorF("depthcode = %d\n", depthcode); +#endif + + if (pScrn->bitsPerPixel == 1) { + hwp->IOBase = 0x3B0; + hwp->ModeReg.MiscOutReg &= ~0x01; + } else { + hwp->IOBase = 0x3D0; + hwp->ModeReg.MiscOutReg |= 0x01; + } + + switch (depthcode) { + case 1: + case 4: + pCir->chip.alp->ModeReg.ExtVga[SR07] |= 0x10; + break; + case 8: + pCir->chip.alp->ModeReg.ExtVga[SR07] |= 0x11; + break; + case 64+8: + pCir->chip.alp->ModeReg.ExtVga[SR07] |= 0x17; + break; + case 15: + pCir->chip.alp->ModeReg.ExtVga[SR07] |= 0x17; + pCir->chip.alp->ModeReg.ExtVga[HDR ] = 0xC0; + break; + case 64+15: + pCir->chip.alp->ModeReg.ExtVga[SR07] |= 0x19; + pCir->chip.alp->ModeReg.ExtVga[HDR ] = 0xC0; + break; + case 16: + pCir->chip.alp->ModeReg.ExtVga[SR07] |= 0x17; + pCir->chip.alp->ModeReg.ExtVga[HDR ] = 0xC1; + break; + case 64+16: + pCir->chip.alp->ModeReg.ExtVga[SR07] |= 0x19; + pCir->chip.alp->ModeReg.ExtVga[HDR ] = 0xC1; + break; + case 24: + pCir->chip.alp->ModeReg.ExtVga[SR07] |= 0x15; + pCir->chip.alp->ModeReg.ExtVga[HDR ] = 0xC5; + break; + case 32: + pCir->chip.alp->ModeReg.ExtVga[SR07] |= 0x19; + pCir->chip.alp->ModeReg.ExtVga[HDR ] = 0xC5; + break; + default: + ErrorF("X11: Internal error: AlpModeInit: Cannot Initialize display to requested mode\n"); +#ifdef ALP_DEBUG + ErrorF("AlpModeInit returning FALSE on depthcode %d\n", depthcode); +#endif + return FALSE; + } + if (HDiv2) + pCir->chip.alp->ModeReg.ExtVga[GR18] |= 0x20; + else + pCir->chip.alp->ModeReg.ExtVga[GR18] &= ~0x20; + + + /* Some extra init stuff */ + switch (pCir->Chipset) + { + case PCI_CHIP_GD7548: + /* Do we use MMIO ? + If we do and we are on a 7548, we need to tell the board + that we want MMIO. */ + if (pCir->UseMMIO) + { + pCir->chip.alp->ModeReg.ExtVga[SR17] = + (pCir->chip.alp->ModeReg.ExtVga[SR17] & ~0x40) | 4; + ErrorF("UseMMIO: SR17=%2X\n", (int) (pCir->chip.alp->ModeReg.ExtVga[SR17])); + } +#ifdef ALP_SETUP + ErrorF("SR2D=%2X\n", (int) (pCir->chip.alp->ModeReg.ExtVga[SR17])); +#endif + pCir->chip.alp->ModeReg.ExtVga[SR2D] |= 0xC0; + break; + } + + /* No support for interlace (yet) */ + pCir->chip.alp->ModeReg.ExtVga[CR1A] = 0x00; + + width = pScrn->displayWidth * pScrn->bitsPerPixel / 8; + if (pScrn->bitsPerPixel == 1) + width <<= 2; + hwp->ModeReg.CRTC[0x13] = width >> 3; + /* Offset extension (see CR13) */ + pCir->chip.alp->ModeReg.ExtVga[CR1B] &= 0xAF; + pCir->chip.alp->ModeReg.ExtVga[CR1B] |= (width >> (3+4)) & 0x10; + pCir->chip.alp->ModeReg.ExtVga[CR1B] |= (width >> (3+3)) & 0x40; + pCir->chip.alp->ModeReg.ExtVga[CR1B] |= 0x22; + + /* Programme the registers */ + vgaHWProtect(pScrn, TRUE); + hwp->writeMiscOut(hwp, hwp->ModeReg.MiscOutReg); + alpRestore(hwp,&pCir->chip.alp->ModeReg); + AlpSetClock(pCir, hwp, mode->SynthClock); + + vgaHWRestore(pScrn, &hwp->ModeReg, VGA_SR_MODE | VGA_SR_CMAP); + + /* XXX */ + if (pScrn->bitsPerPixel == 1) + AlpFix1bppColorMap(pScrn); + + vgaHWProtect(pScrn, FALSE); + + return TRUE; +} + +/* + * Restore the initial (text) mode. + */ +static void +AlpRestore(ScrnInfoPtr pScrn) +{ + vgaHWPtr hwp; + vgaRegPtr vgaReg; + CirPtr pCir; + AlpRegPtr alpReg; + +#ifdef ALP_DEBUG + ErrorF("AlpRestore\n"); +#endif + + hwp = VGAHWPTR(pScrn); + pCir = CIRPTR(pScrn); + vgaReg = &hwp->SavedReg; + alpReg = &pCir->chip.alp->SavedReg; + + vgaHWProtect(pScrn, TRUE); + + alpRestore(hwp,alpReg); + + vgaHWRestore(pScrn, vgaReg, VGA_SR_ALL); + vgaHWProtect(pScrn, FALSE); +} + +/* Mandatory */ + +/* This gets called at the start of each server generation */ + +Bool +AlpScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) +{ + ScrnInfoPtr pScrn; + vgaHWPtr hwp; + CirPtr pCir; + AlpPtr pAlp; + int i, ret; + int init_picture = 0; + VisualPtr visual; + int displayWidth,width,height; + unsigned char * FbBase = NULL; + int cursor_size = 0; + +#ifdef ALP_DEBUG + ErrorF("AlpScreenInit\n"); +#endif + + /* + * First get the ScrnInfoRec + */ + pScrn = xf86Screens[pScreen->myNum]; + + hwp = VGAHWPTR(pScrn); + pCir = CIRPTR(pScrn); + pAlp = ALPPTR(pCir); + + /* Map the VGA memory when the primary video */ + if (!vgaHWMapMem(pScrn)) + return FALSE; + + /* Map the Alp memory and MMIO areas */ + if (!CirMapMem(pCir, pScrn->scrnIndex)) + return FALSE; + + /* The 754x supports MMIO for the BitBlt engine but + not for the VGA registers */ + switch (pCir->Chipset) + { + case PCI_CHIP_GD7548: + break; + default: + if(pCir->UseMMIO) + vgaHWSetMmioFuncs(hwp, pCir->IOBase, -0x3C0); + } + + vgaHWGetIOBase(hwp); + + /* Save the current state */ + AlpSave(pScrn); + + /* Initialise the first mode */ + if (!AlpModeInit(pScrn, pScrn->currentMode)) + return FALSE; + + /* Set the viewport */ + AlpAdjustFrame(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. + * + */ + + /* + * Reset the visual list. + */ + miClearVisualTypes(); + + /* Setup the visuals we support. */ + + if (!miSetVisualTypes(pScrn->depth, + miGetDefaultVisualMask(pScrn->depth), + pScrn->rgbBits, pScrn->defaultVisual)) + return FALSE; + + miSetPixmapDepths (); + + displayWidth = pScrn->displayWidth; + if (pCir->rotate) { + height = pScrn->virtualX; + width = pScrn->virtualY; + } else { + width = pScrn->virtualX; + height = pScrn->virtualY; + } + + if(pCir->shadowFB) { + pCir->ShadowPitch = BitmapBytePad(pScrn->bitsPerPixel * width); + pCir->ShadowPtr = xalloc(pCir->ShadowPitch * height); + displayWidth = pCir->ShadowPitch / (pScrn->bitsPerPixel >> 3); + FbBase = pCir->ShadowPtr; + } else { + pCir->ShadowPtr = NULL; + FbBase = pCir->FbBase; + } + + /* + * Call the framebuffer layer's ScreenInit function, and fill in other + * pScreen fields. + */ + + switch (pScrn->bitsPerPixel) { + case 1: + ret = xf1bppScreenInit(pScreen, FbBase, + width, height, + pScrn->xDpi, pScrn->yDpi, + displayWidth); + break; + case 4: + ret = xf4bppScreenInit(pScreen, FbBase, + width, height, + pScrn->xDpi, pScrn->yDpi, + displayWidth); + break; + case 8: + case 16: + case 24: + case 32: + ret = fbScreenInit(pScreen, FbBase, + width,height, + pScrn->xDpi, pScrn->yDpi, + displayWidth,pScrn->bitsPerPixel); + init_picture = 1; + break; + default: + xf86DrvMsg(scrnIndex, X_ERROR, + "X11: Internal error: invalid bpp (%d) in AlpScreenInit\n", + pScrn->bitsPerPixel); + ret = FALSE; + break; + } + if (!ret) + return FALSE; + +#ifdef ALP_DEBUG + ErrorF("AlpScreenInit after depth dependent init\n"); +#endif + + /* Override the default mask/offset settings */ + if (pScrn->bitsPerPixel > 8) { + for (i = 0; i < pScreen->numVisuals; i++) { + visual = &pScreen->visuals[i]; + 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); + + miInitializeBackingStore(pScreen); + + /* + * Set initial black & white colourmap indices. + */ + xf86SetBlackWhitePixels(pScreen); + + /* + Allocation of off-screen memory to various stuff + (hardware cursor, 8x8 mono pattern...) + Allocation goes top-down in memory, since the cursor + *must* be in the last videoram locations + */ + pCir->offscreen_offset = pScrn->videoRam*1024; + pCir->offscreen_size = pScrn->videoRam * 1024 - pScrn->virtualY * + (BitmapBytePad(pScrn->displayWidth * pScrn->bitsPerPixel)); + +#ifdef ALP_DEBUG + ErrorF("offscreen_offset=%d, offscreen_size=%d\n", + pCir->offscreen_offset, pCir->offscreen_size); +#endif + + /* Initialise cursor functions */ + if (pCir->HWCursor) { /* Initialize HW cursor layer */ + + if ((pCir->properties & HWCUR64) + && (pCir->offscreen_size >= 64*8*2)) { + cursor_size = 64; + pCir->offscreen_size -= 64*8*2; + pCir->offscreen_offset -= 64*8*2; + } else if (pCir->offscreen_size >= 32*4*2) { + cursor_size = 32; + pCir->offscreen_size -= 32*8*2; + pCir->offscreen_offset -= 32*8*2; + } + } + + if (!pCir->NoAccel) { /* Initialize XAA functions */ + AlpOffscreenAccelInit(pScrn); + if (!(pCir->UseMMIO ? AlpXAAInitMMIO(pScreen) : + AlpXAAInit(pScreen))) + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Could not initialize XAA\n"); + } + +#if 1 + pCir->DGAModeInit = AlpModeInit; + if (!CirDGAInit(pScreen)) + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "DGA initialization failed\n"); +#endif + xf86SetSilkenMouse(pScreen); + + /* Initialise cursor functions */ + miDCInitialize(pScreen, xf86GetPointerScreenFuncs()); + + if (pCir->HWCursor) { + if (!AlpHWCursorInit(pScreen, cursor_size)) + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Hardware cursor initialization failed\n"); +#ifdef ALP_DEBUG + ErrorF("AlpHWCursorInit() complete\n"); +#endif + } + + if (pCir->shadowFB) { + RefreshAreaFuncPtr refreshArea = cirRefreshArea; + + if(pCir->rotate) { + if (!pCir->PointerMoved) { + pCir->PointerMoved = pScrn->PointerMoved; + pScrn->PointerMoved = cirPointerMoved; + } + + switch(pScrn->bitsPerPixel) { + case 8: refreshArea = cirRefreshArea8; break; + case 16: refreshArea = cirRefreshArea16; break; + case 24: refreshArea = cirRefreshArea24; break; + case 32: refreshArea = cirRefreshArea32; break; + } + } + + ShadowFBInit(pScreen, refreshArea); + } + + /* Initialise default colourmap */ + if (!miCreateDefColormap(pScreen)) + return FALSE; + + if (pScrn->bitsPerPixel > 1 && pScrn->bitsPerPixel <= 8) + vgaHWHandleColormaps(pScreen); + + xf86DPMSInit(pScreen, AlpDisplayPowerManagementSet, 0); + + pScrn->memPhysBase = pCir->FbAddress; + pScrn->fbOffset = 0; + +#ifdef XvExtension + { + XF86VideoAdaptorPtr *ptr; + int n; + + n = xf86XVListGenericAdaptors(pScrn,&ptr); + if (n) + xf86XVScreenInit(pScreen, ptr, n); + } +#endif + + /* + * Wrap the CloseScreen vector and set SaveScreen. + */ + pScreen->SaveScreen = AlpSaveScreen; + pCir->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = AlpCloseScreen; + + /* Report any unused options (only for the first generation) */ + if (serverGeneration == 1) + xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options); + + /* Done */ + return TRUE; +} + + +/* Usually mandatory */ +Bool +AlpSwitchMode(int scrnIndex, DisplayModePtr mode, int flags) +{ + return AlpModeInit(xf86Screens[scrnIndex], mode); +} + + +/* + * This function is used to initialize the Start Address - the first + * displayed location in the video memory. + */ +/* Usually mandatory */ +void +AlpAdjustFrame(int scrnIndex, int x, int y, int flags) +{ + ScrnInfoPtr pScrn; + int Base, tmp; + vgaHWPtr hwp; + + pScrn = xf86Screens[scrnIndex]; + hwp = VGAHWPTR(pScrn); + + Base = ((y * pScrn->displayWidth + x) / 8); + if (pScrn->bitsPerPixel != 1) + Base *= (pScrn->bitsPerPixel/4); + +#ifdef ALP_DEBUG + ErrorF("AlpAdjustFrame %d %d 0x%x %d %x\n", x, y, flags, Base, Base); +#endif + + if ((Base & ~0x000FFFFF) != 0) { + ErrorF("X11: Internal error: AlpAdjustFrame: cannot handle overflow\n"); + return; + } + + hwp->writeCrtc(hwp, 0x0C, (Base >> 8) & 0xff); + hwp->writeCrtc(hwp, 0x0D, Base & 0xff); + tmp = hwp->readCrtc(hwp, 0x1B); + tmp &= 0xF2; + tmp |= (Base >> 16) & 0x01; + tmp |= (Base >> 15) & 0x0C; + hwp->writeCrtc(hwp, 0x1B, tmp); + tmp = hwp->readCrtc(hwp, 0x1D); + tmp &= 0x7F; + tmp |= (Base >> 12) & 0x80; + hwp->writeCrtc(hwp, 0x1D, tmp); +} + +/* + * This is called when VT switching back to the X server. Its job is + * to reinitialise the video mode. + * + * We may wish to unmap video/MMIO memory too. + */ + +/* Mandatory */ +Bool +AlpEnterVT(int scrnIndex, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + CirPtr pCir = CIRPTR(pScrn); + Bool ret; + +#ifdef ALP_DEBUG + ErrorF("AlpEnterVT\n"); +#endif + + /* Should we re-save the text mode on each VT enter? */ + if (!(ret = AlpModeInit(pScrn, pScrn->currentMode))) + return FALSE; + + if (!pCir->NoAccel) + pCir->InitAccel(pScrn); + + return ret; +} + + +/* + * This is called when VT switching away from the X server. Its job is + * to restore the previous (text) mode. + * + * We may wish to remap video/MMIO memory too. + */ + +/* Mandatory */ +void +AlpLeaveVT(int scrnIndex, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + vgaHWPtr hwp = VGAHWPTR(pScrn); +#ifdef ALP_DEBUG + ErrorF("AlpLeaveVT\n"); +#endif + + AlpRestore(pScrn); + vgaHWLock(hwp); +} + + +/* + * This is called at the end of each server generation. It restores the + * original (text) mode. It should also unmap the video memory, and free + * any per-generation data allocated by the driver. It should finish + * by unwrapping and calling the saved CloseScreen function. + */ + +/* Mandatory */ +static Bool +AlpCloseScreen(int scrnIndex, ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + vgaHWPtr hwp = VGAHWPTR(pScrn); + CirPtr pCir = CIRPTR(pScrn); + + if(pScrn->vtSema) { + AlpRestore(pScrn); + vgaHWLock(hwp); + CirUnmapMem(pCir, pScrn->scrnIndex); + } + + if (pCir->AccelInfoRec) + XAADestroyInfoRec(pCir->AccelInfoRec); + pCir->AccelInfoRec = NULL; + if (pCir->CursorInfoRec) + xf86DestroyCursorInfoRec(pCir->CursorInfoRec); + pCir->CursorInfoRec = NULL; + if (pCir->DGAModes) + xfree(pCir->DGAModes); + pCir->DGAnumModes = 0; + pCir->DGAModes = NULL; + + pScrn->vtSema = FALSE; + + pScreen->CloseScreen = pCir->CloseScreen; + return (*pScreen->CloseScreen)(scrnIndex, pScreen); +} + + +/* Free up any persistent data structures */ + +/* Optional */ +void +AlpFreeScreen(int scrnIndex, int flags) +{ +#ifdef ALP_DEBUG + ErrorF("AlpFreeScreen\n"); +#endif + /* + * This only gets called when a screen is being deleted. It does not + * get called routinely at the end of a server generation. + */ + if (xf86LoaderCheckSymbol("vgaHWFreeHWRec")) + vgaHWFreeHWRec(xf86Screens[scrnIndex]); + AlpFreeRec(xf86Screens[scrnIndex]); +} + + +/* Checks if a mode is suitable for the selected chipset. */ + +/* Optional */ +int +AlpValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags) +{ + int lace; + + lace = 1 + ((mode->Flags & V_INTERLACE) != 0); + + if ((mode->CrtcHDisplay <= 2048) && + (mode->CrtcHSyncStart <= 4096) && + (mode->CrtcHSyncEnd <= 4096) && + (mode->CrtcHTotal <= 4096) && + (mode->CrtcVDisplay <= 2048 * lace) && + (mode->CrtcVSyncStart <= 4096 * lace) && + (mode->CrtcVSyncEnd <= 4096 * lace) && + (mode->CrtcVTotal <= 4096 * lace)) { + return(MODE_OK); + } else { + return(MODE_BAD); + } +} + +/* Do screen blanking */ + +/* Mandatory */ +static Bool +AlpSaveScreen(ScreenPtr pScreen, int mode) +{ + return vgaHWSaveScreen(pScreen, mode); +} + +/* + * Set the clock to the requested frequency. If the MCLK is very close + * to the requested frequency, it sets a flag so that the MCLK can be used + * as VCLK. However this flag is not yet acted upon. + */ +static void +AlpSetClock(CirPtr pCir, vgaHWPtr hwp, int freq) +{ + int num, den, ffreq, usemclk, diff, mclk; + CARD8 tmp; + +#ifdef ALP_DEBUG + ErrorF("AlpSetClock freq=%d.%03dMHz\n", freq / 1000, freq % 1000); +#endif + + ffreq = freq; + if (!CirrusFindClock(&ffreq, pCir->MaxClock, &num, &den)) + return; + + /* Calculate the MCLK. */ + mclk = 14318 * (hwp->readSeq(hwp, 0x1F) & 0x3F) / 8; /* XXX */ + /* + * Favour MCLK as VLCK if it matches as good as the found clock, + * or if it is within 0.2 MHz of the request clock. A VCLK close + * to MCLK can cause instability. + */ + diff = abs(freq - ffreq); + if (abs(mclk - ffreq) <= diff + 10 || abs(mclk - freq) <= 200) + usemclk = TRUE; + else + usemclk = FALSE; + +#ifdef ALP_DEBUG + ErrorF("AlpSetClock: nom=%x den=%x ffreq=%d.%03dMHz usemclk=%x\n", + num, den, ffreq / 1000, ffreq % 1000, usemclk); +#endif + /* So - how do we use MCLK here for the VCLK ? */ + + /* Set VCLK3. */ + tmp = hwp->readSeq(hwp, 0x0E); + hwp->writeSeq(hwp, 0x0E, (tmp & 0x80) | num); + hwp->writeSeq(hwp, 0x1E, den); +} + +/* + * AlpDisplayPowerManagementSet -- + * + * Sets VESA Display Power Management Signaling (DPMS) Mode. + */ +static void +AlpDisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode, + int flags) +{ + unsigned char sr01, gr0e; + vgaHWPtr hwp; + +#ifdef ALP_DEBUG + ErrorF("AlpDisplayPowerManagementSet\n"); +#endif + + hwp = VGAHWPTR(pScrn); + +#ifdef ALP_DEBUG + ErrorF("AlpDisplayPowerManagementSet: %d\n", PowerManagementMode); +#endif + + switch (PowerManagementMode) { + case DPMSModeOn: + /* Screen: On; HSync: On, VSync: On */ + sr01 = 0x00; + gr0e = 0x00; + break; + case DPMSModeStandby: + /* Screen: Off; HSync: Off, VSync: On */ + sr01 = 0x20; + gr0e = 0x02; + break; + case DPMSModeSuspend: + /* Screen: Off; HSync: On, VSync: Off */ + sr01 = 0x20; + gr0e = 0x04; + break; + case DPMSModeOff: + /* Screen: Off; HSync: Off, VSync: Off */ + sr01 = 0x20; + gr0e = 0x06; + break; + default: + return; + } + + sr01 |= hwp->readSeq(hwp, 0x01) & ~0x20; + hwp->writeSeq(hwp, 0x01, sr01); + gr0e |= hwp->readGr(hwp, 0x0E) & ~0x06; + hwp->writeGr(hwp, 0x0E, gr0e); +} + +#ifdef ALPPROBEI2C +static void AlpProbeI2C(int scrnIndex) +{ + int i; + I2CBusPtr b; + + b = xf86I2CFindBus(scrnIndex, "I2C bus 1"); + if (b == NULL) + ErrorF("Could not find I2C bus \"%s\"\n", "I2C bus 1"); + else { + for (i = 2; i < 256; i += 2) + if (xf86I2CProbeAddress(b, i)) + ErrorF("Found device 0x%02x on bus \"%s\"\n", i, b->BusName); + } + b = xf86I2CFindBus(scrnIndex, "I2C bus 2"); + if (b == NULL) + ErrorF("Could not find I2C bus \"%s\"\n", "I2C bus 2"); + else { + for (i = 2; i < 256; i += 2) + if (xf86I2CProbeAddress(b, i)) + ErrorF("Found device 0x%02x on bus \"%s\"\n", i, b->BusName); + } +} +#endif + +static void +AlpProbeLCD(ScrnInfoPtr pScrn) +{ + CirPtr pCir = CIRPTR(pScrn); + AlpPtr pAlp = ALPPTR(pCir); + + vgaHWPtr hwp = VGAHWPTR(pScrn); + CARD8 lcdCrtl; + + static const char* lcd_type_names[] = + { + "none", + "dual-scan monochrome", + "unknown", + "DSTN (dual scan color)", + "TFT (active matrix)" + }; + + + pAlp->lcdType = LCD_NONE; + + switch (pCir->Chipset) { + case PCI_CHIP_GD7548: + switch (hwp->readCrtc(hwp, 0x2C) >> 6) { + case 0: pAlp->lcdType = LCD_DUAL_MONO; break; + case 1: pAlp->lcdType = LCD_UNKNOWN; break; + case 2: pAlp->lcdType = LCD_DSTN; break; + case 3: pAlp->lcdType = LCD_TFT; break; + } + + /* Enable LCD control registers instead of normal CRTC registers */ + lcdCrtl = hwp->readCrtc(hwp, 0x2D); + hwp->writeCrtc(hwp, 0x2D, lcdCrtl | 0x80); + + switch ((hwp->readCrtc(hwp, 0x9) >> 2) & 3) { + case 0: + pAlp->lcdWidth = 640; + pAlp->lcdHeight = 480; + break; + + case 1: + pAlp->lcdWidth = 800; + pAlp->lcdHeight = 600; + break; + + case 2: + pAlp->lcdWidth = 1024; + pAlp->lcdHeight = 768; + break; + + case 3: + pAlp->lcdWidth = 0; + pAlp->lcdHeight = 0; + break; + } + + /* Disable LCD control registers */ + hwp->writeCrtc(hwp, 0x2D, lcdCrtl); + break; + } + + if (pAlp->lcdType != LCD_NONE) { + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, + "LCD display: %dx%d %s\n", + pAlp->lcdWidth, pAlp->lcdHeight, + lcd_type_names[pAlp->lcdType]); + } +} + +static void +AlpOffscreenAccelInit(ScrnInfoPtr pScrn) +{ + CirPtr pCir = CIRPTR(pScrn); + AlpPtr pAlp = ALPPTR(pCir); + + if (pCir->offscreen_size >= 8 && pCir->Chipset == PCI_CHIP_GD7548) { + pCir->offscreen_offset -= 8; + pCir->offscreen_size -= 8; + pAlp->monoPattern8x8 = pCir->offscreen_offset; +#ifdef ALP_DEBUG + ErrorF("monoPattern8x8=%d\n", pAlp->monoPattern8x8); +#endif + } else pAlp->monoPattern8x8 = 0; + + { + /* TODO: probably not correct if rotated */ + BoxRec box; + box.x1=0; + box.y1=0; + box.x2=pScrn->virtualX; + box.y2= pCir->offscreen_offset / pCir->pitch; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Using %d lines for offscreen memory\n", + box.y2 - pScrn->virtualY); + } +} diff --git a/src/alp_hwcurs.c b/src/alp_hwcurs.c new file mode 100644 index 0000000..a4f0581 --- /dev/null +++ b/src/alp_hwcurs.c @@ -0,0 +1,258 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/cirrus/alp_hwcurs.c,v 1.5 2001/05/07 21:59:06 tsi Exp $ */ + +/* (c) Itai Nahshon */ + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86_ansic.h" +#include "compiler.h" + +#include "xf86Pci.h" +#include "xf86PciInfo.h" + +#include "vgaHW.h" + +#include "cir.h" +#define _ALP_PRIVATE_ +#include "alp.h" + +#define CURSORWIDTH pAlp->CursorWidth +#define CURSORHEIGHT pAlp->CursorHeight +#define CURSORSIZE (CURSORWIDTH*CURSORHEIGHT/8) +#define MAXCURSORSIZE (64*64>>3) + +static void +AlpSetCursorColors(ScrnInfoPtr pScrn, int bg, int fg) +{ + const AlpPtr pAlp = ALPPTR(CIRPTR(pScrn)); + vgaHWPtr hwp = VGAHWPTR(pScrn); +#ifdef ALP_DEBUG + ErrorF("AlpSetCursorColors\n"); +#endif + hwp->writeSeq(hwp, 0x12, pAlp->ModeReg.ExtVga[SR12]|0x02); + hwp->writeDacWriteAddr(hwp, 0x00); + hwp->writeDacData(hwp, 0x3f & (bg >> 18)); + hwp->writeDacData(hwp, 0x3f & (bg >> 10)); + hwp->writeDacData(hwp, 0x3f & (bg >> 2)); + hwp->writeDacWriteAddr(hwp, 0x0F); + hwp->writeDacData(hwp, 0x3F & (fg >> 18)); + hwp->writeDacData(hwp, 0x3F & (fg >> 10)); + hwp->writeDacData(hwp, 0x3F & (fg >> 2)); + hwp->writeSeq(hwp, 0x12, pAlp->ModeReg.ExtVga[SR12]); +} + +static void +AlpLoadSkewedCursor(CirPtr pCir, int x, int y) { + + const AlpPtr pAlp = ALPPTR(pCir); + + unsigned char *memx = pAlp->HWCursorBits; + unsigned char *CursorBits = pAlp->CursorBits; + + unsigned char mem[2*MAXCURSORSIZE]; + unsigned char *p1, *p2; + int i, j, m, a, b; + Bool cur64 = (CURSORWIDTH == 64); + int shift = (cur64? 1 : 0); + + if (x > 0) x = 0; else x = -x; + if (y > 0) y = 0; else y = -y; + + + a = ((y*CURSORWIDTH<>3; + b = x & 7; + + /* Copy the skewed mask bits */ + p1 = mem; + p2 = CursorBits + a; + for (i = 0; i < (CURSORSIZE << shift)-a-1; i++) { + *p1++ = (p2[0] << b) | (p2[1] >> (8-b)); + p2++; + } + /* last mask byte */ + *p1++ = (p2[0] << b); + + /* Clear to end (bottom) of mask. */ + for (i = i+1; i < (CURSORSIZE << shift); i++) + *p1++ = 0; + + if (!cur64) { + /* Now copy the cursor bits */ + /* p1 is already right */ + p2 = CursorBits+CURSORSIZE+a; + for (i = 0; i < CURSORSIZE-a-1; i++) { + *p1++ = (p2[0] << b) | (p2[1] >> (8-b)); + p2++; + } + /* last cursor byte */ + *p1++ = (p2[0] << b); + } + + /* Clear to end (bottom) of cursor. */ + for (i = i+1; i < CURSORSIZE; i++) + *p1++ = 0; + + /* Clear the right unused area of the mask + and cyrsor bits. */ + p2 = mem + CURSORWIDTH/8 - (x>>3) - 1; + for (i = 0; i < 2*CURSORHEIGHT; i++) { + m = (-1)<<(x&7); + p1 = p2; + p2 += CURSORWIDTH/8; + for (j = x>>3; j >= 0; j--) { + *p1 &= m; + m = 0; + p1++; + } + } + memcpy(memx, mem, 2*CURSORSIZE); +} + + +static void +AlpSetCursorPosition(ScrnInfoPtr pScrn, int x, int y) +{ + const CirPtr pCir = CIRPTR(pScrn); + const AlpPtr pAlp = ALPPTR(pCir); + vgaHWPtr hwp = VGAHWPTR(pScrn); + +#if 0 +#ifdef ALP_DEBUG + ErrorF("AlpSetCursorPosition %d %d\n", x, y); +#endif +#endif + + if (x < 0 || y < 0) { + if (x+CURSORWIDTH <= 0 || y+CURSORHEIGHT <= 0) { + hwp->writeSeq(hwp, 0x12, pAlp->ModeReg.ExtVga[SR12] & ~0x01); + return; + } + AlpLoadSkewedCursor(pCir, x, y); + pCir->CursorIsSkewed = TRUE; + if (x < 0) x = 0; + if (y < 0) y = 0; + } else if (pCir->CursorIsSkewed) { + memcpy(pAlp->HWCursorBits, pAlp->CursorBits, 2*CURSORSIZE); + pCir->CursorIsSkewed = FALSE; + } + hwp->writeSeq(hwp, 0x12, pAlp->ModeReg.ExtVga[SR12]); + hwp->writeSeq(hwp, ((x << 5)|0x10)&0xff, x >> 3); + hwp->writeSeq(hwp, ((y << 5)|0x11)&0xff, y >> 3); +} + +static void +AlpLoadCursorImage(ScrnInfoPtr pScrn, unsigned char *bits) +{ + const AlpPtr pAlp = ALPPTR(CIRPTR(pScrn)); + vgaHWPtr hwp = VGAHWPTR(pScrn); + +#ifdef ALP_DEBUG + ErrorF("AlpLoadCursorImage\n"); +#endif + + pAlp->CursorBits = bits; + memcpy(pAlp->HWCursorBits, bits, 2*CURSORSIZE); + /* this should work for both 64 and 32 bit cursors */ + pAlp->ModeReg.ExtVga[SR13] = 0x3f; + hwp->writeSeq(hwp, 0x13, pAlp->ModeReg.ExtVga[SR13]); +} + +static void +AlpHideCursor(ScrnInfoPtr pScrn) +{ + AlpPtr pAlp = ALPPTR(CIRPTR(pScrn)); + vgaHWPtr hwp = VGAHWPTR(pScrn); + +#ifdef ALP_DEBUG + ErrorF("AlpHideCursor\n"); +#endif + pAlp->ModeReg.ExtVga[SR12] &= ~0x01; + hwp->writeSeq(hwp, 0x12, pAlp->ModeReg.ExtVga[SR12]); +} + +static void +AlpShowCursor(ScrnInfoPtr pScrn) +{ + AlpPtr pAlp = ALPPTR(CIRPTR(pScrn)); + vgaHWPtr hwp = VGAHWPTR(pScrn); + +#ifdef ALP_DEBUG + ErrorF("AlpShowCursor\n"); +#endif + pAlp->ModeReg.ExtVga[SR12] |= 0x01; + hwp->writeSeq(hwp, 0x12, pAlp->ModeReg.ExtVga[SR12]); +} + +static Bool +AlpUseHWCursor(ScreenPtr pScreen, CursorPtr pCurs) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; +#ifdef ALP_DEBUG + ErrorF("AlpUseHWCursor\n"); +#endif + if (pScrn->bitsPerPixel < 8) + return FALSE; + + return TRUE; +} + +Bool +AlpHWCursorInit(ScreenPtr pScreen, int size) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + const CirPtr pCir = CIRPTR(pScrn); + const AlpPtr pAlp = ALPPTR(pCir); + + xf86CursorInfoPtr infoPtr; + +#ifdef ALP_DEBUG + ErrorF("AlpHWCursorInit\n"); +#endif + if (!size) return FALSE; + + infoPtr = xf86CreateCursorInfoRec(); + if (!infoPtr) return FALSE; + + pCir->CursorInfoRec = infoPtr; + pCir->CursorIsSkewed = FALSE; + pAlp->CursorBits = NULL; + + if (size == 64) + CURSORWIDTH = CURSORHEIGHT = 64; + else + CURSORWIDTH = CURSORHEIGHT = 32; + + pAlp->HWCursorBits = pCir->FbBase + 1024*pScrn->videoRam - 2*CURSORSIZE; + + infoPtr->MaxWidth = CURSORWIDTH; + infoPtr->MaxHeight = CURSORHEIGHT; + if (CURSORWIDTH == 64) + infoPtr->Flags = +#if X_BYTE_ORDER == X_LITTLE_ENDIAN + HARDWARE_CURSOR_BIT_ORDER_MSBFIRST | +#endif + HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64 | + HARDWARE_CURSOR_TRUECOLOR_AT_8BPP; + else + infoPtr->Flags = +#if X_BYTE_ORDER == X_LITTLE_ENDIAN + HARDWARE_CURSOR_BIT_ORDER_MSBFIRST | +#endif + HARDWARE_CURSOR_TRUECOLOR_AT_8BPP; + + infoPtr->SetCursorColors = AlpSetCursorColors; + infoPtr->SetCursorPosition = AlpSetCursorPosition; + infoPtr->LoadCursorImage = AlpLoadCursorImage; + infoPtr->HideCursor = AlpHideCursor; + infoPtr->ShowCursor = AlpShowCursor; + infoPtr->UseHWCursor = AlpUseHWCursor; + +#ifdef ALP_DEBUG + ErrorF("AlpHWCursorInit before xf86InitCursor\n"); +#endif + xf86DrvMsg(pScrn->scrnIndex,X_INFO,"Hardware cursor: %ix%i\n", + CURSORWIDTH,CURSORHEIGHT); + return(xf86InitCursor(pScreen, infoPtr)); +} + + diff --git a/src/alp_i2c.c b/src/alp_i2c.c new file mode 100644 index 0000000..78d5406 --- /dev/null +++ b/src/alp_i2c.c @@ -0,0 +1,126 @@ +/* (c) Itai Nahshon */ + +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/cirrus/alp_i2c.c,v 1.3 2000/12/06 15:35:15 eich Exp $ */ + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86_ansic.h" +#include "compiler.h" + +#include "xf86Pci.h" +#include "xf86PciInfo.h" + +#include "vgaHW.h" + +#include "cir.h" +#define _ALP_PRIVATE_ +#include "alp.h" + +/* + * Switch between internal I2C bus and external (DDC) bus. + * There is one I2C port controlled bu SR08 and the programmable + * outputs control a multiplexer. + */ +static Bool +AlpI2CSwitchToBus(I2CBusPtr b) +{ + CirPtr pCir = ((CirPtr)b->DriverPrivate.ptr); + vgaHWPtr hwp = VGAHWPTR(pCir->pScrn); + CARD8 reg = hwp->readGr(hwp, 0x17); + if (b == pCir->I2CPtr1) { + if ((reg & 0x60) == 0) + return TRUE; + reg &= ~0x60; + } + else if(b == pCir->I2CPtr2) { + if ((reg & 0x60) != 0) + return TRUE; + reg |= 0x60; + } else return FALSE; + + /* ErrorF("AlpI2CSwitchToBus: \"%s\"\n", b->BusName); */ + hwp->writeGr(hwp, 0x17, reg); + return TRUE; +} + +static void +AlpI2CPutBits(I2CBusPtr b, int clock, int data) +{ + unsigned int reg = 0xfc; + CirPtr pCir = ((CirPtr)b->DriverPrivate.ptr); + vgaHWPtr hwp = VGAHWPTR(pCir->pScrn); + + if (!AlpI2CSwitchToBus(b)) + return; + + if (clock) reg |= 1; + if (data) reg |= 2; + hwp->writeSeq(hwp, 0x08, reg); + /* ErrorF("AlpI2CPutBits: %d %d\n", clock, data); */ +} + +static void +AlpI2CGetBits(I2CBusPtr b, int *clock, int *data) +{ + unsigned int reg; + CirPtr pCir = ((CirPtr)b->DriverPrivate.ptr); + vgaHWPtr hwp = VGAHWPTR(pCir->pScrn); + + if (!AlpI2CSwitchToBus(b)) + return; + + reg = hwp->readSeq(hwp, 0x08); + *clock = (reg & 0x04) != 0; + *data = (reg & 0x80) != 0; + /* ErrorF("AlpI2CGetBits: %d %d\n", *clock, *data); */ +} + +Bool +AlpI2CInit(ScrnInfoPtr pScrn) +{ + CirPtr pCir = CIRPTR(pScrn); + I2CBusPtr I2CPtr; + +#ifdef ALP_DEBUG + ErrorF("AlpI2CInit\n"); +#endif + + switch(pCir->Chipset) { + case PCI_CHIP_GD5446: + case PCI_CHIP_GD5480: + break; + default: + return FALSE; + } + + + I2CPtr = xf86CreateI2CBusRec(); + if (!I2CPtr) return FALSE; + + pCir->I2CPtr1 = I2CPtr; + + I2CPtr->BusName = "I2C bus 1"; + I2CPtr->scrnIndex = pScrn->scrnIndex; + I2CPtr->I2CPutBits = AlpI2CPutBits; + I2CPtr->I2CGetBits = AlpI2CGetBits; + I2CPtr->DriverPrivate.ptr = pCir; + + if (!xf86I2CBusInit(I2CPtr)) + return FALSE; + + I2CPtr = xf86CreateI2CBusRec(); + if (!I2CPtr) return FALSE; + + pCir->I2CPtr2 = I2CPtr; + + I2CPtr->BusName = "I2C bus 2"; + I2CPtr->scrnIndex = pScrn->scrnIndex; + I2CPtr->I2CPutBits = AlpI2CPutBits; + I2CPtr->I2CGetBits = AlpI2CGetBits; + I2CPtr->DriverPrivate.ptr = pCir; + + if (!xf86I2CBusInit(I2CPtr)) + return FALSE; + + return TRUE; +} diff --git a/src/alp_xaa.c b/src/alp_xaa.c new file mode 100644 index 0000000..417f816 --- /dev/null +++ b/src/alp_xaa.c @@ -0,0 +1,686 @@ +/* (c) Itai Nahshon */ + +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/cirrus/alp_xaa.c,v 1.8 2002/01/25 21:56:00 tsi Exp $ */ + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86_ansic.h" +#include "compiler.h" + +#include "xf86Pci.h" +#include "xf86PciInfo.h" + +#include "vgaHW.h" + +#include "cir.h" +#define _ALP_PRIVATE_ +#include "alp.h" + +#define WAIT outb(pCir->PIOReg, 0x31); \ + while(inb(pCir->PIOReg + 1) & pCir->chip.alp->waitMsk){}; +#define WAIT_1 outb(pCir->PIOReg, 0x31); \ + while(inb(pCir->PIOReg + 1) & 0x1){}; + +static const CARD16 translated_rop[] = +{ + /* GXclear */ 0x0032U, + /* GXand */ 0x0532U, + /* GXandreverse */ 0x0932U, + /* GXcopy */ 0x0D32U, + /* GXandinversted */ 0x5032U, + /* GXnoop */ 0x0632U, + /* GXxor */ 0x5932U, + /* GXor */ 0x6D32U, + /* GXnor */ 0x9032U, + /* GXequiv */ 0x9532U, + /* GXinvert */ 0x0B32U, + /* GXorReverse */ 0xAD32U, + /* GXcopyInverted */ 0xD032U, + /* GXorInverted */ 0xD632U, + /* GXnand */ 0xDA32U, + /* GXset */ 0x0E32U +}; + +#if 1 +#define SetupForRop(rop) outw(pCir->PIOReg, translated_rop[rop]) +#else +#define SetupForRop(rop) outw(pCir->PIOReg, 0x0D32) +#endif + +static void AlpSync(ScrnInfoPtr pScrn) +{ + CirPtr pCir = CIRPTR(pScrn); + +#ifdef ALP_DEBUG + ErrorF("AlpSync\n"); +#endif + WAIT_1; + return; +} + +static void +AlpSetupForScreenToScreenCopy(ScrnInfoPtr pScrn, int xdir, int ydir, + int rop, unsigned int planemask, + int trans_color) +{ + CirPtr pCir = CIRPTR(pScrn); + int pitch = pCir->pitch; + +#ifdef ALP_DEBUG + ErrorF("AlpSetupForScreenToScreenCopy xdir=%d ydir=%d rop=%x planemask=%x trans_color=%x\n", + xdir, ydir, rop, planemask, trans_color); +#endif + WAIT; + SetupForRop(rop); + /* Set dest pitch */ + outw(pCir->PIOReg, ((pitch << 8) & 0xff00) | 0x24); + outw(pCir->PIOReg, ((pitch) & 0x1f00) | 0x25); + /* Set source pitch */ + outw(pCir->PIOReg, ((pitch << 8) & 0xff00) | 0x26); + outw(pCir->PIOReg, ((pitch) & 0x1f00) | 0x27); +} + +static void +AlpSubsequentScreenToScreenCopy(ScrnInfoPtr pScrn, int x1, int y1, int x2, + int y2, int w, int h) +{ + CirPtr pCir = CIRPTR(pScrn); + int source, dest; + int hh, ww; + int decrement = 0; + int pitch = pCir->pitch; + + ww = (w * pScrn->bitsPerPixel / 8) - 1; + hh = h - 1; + dest = y2 * pitch + x2 * pScrn->bitsPerPixel / 8; + source = y1 * pitch + x1 * pScrn->bitsPerPixel / 8; + if (dest > source) { + decrement = 1 << 8; + dest += hh * pitch + ww; + source += hh * pitch + ww; + } + + WAIT; + + outw(pCir->PIOReg, decrement | 0x30); + + /* Width */ + outw(pCir->PIOReg, ((ww << 8) & 0xff00) | 0x20); + outw(pCir->PIOReg, ((ww) & 0x1f00) | 0x21); + /* Height */ + outw(pCir->PIOReg, ((hh << 8) & 0xff00) | 0x22); + outw(pCir->PIOReg, ((hh) & 0x0700) | 0x23); + + + /* source */ + outw(pCir->PIOReg, ((source << 8) & 0xff00) | 0x2C); + outw(pCir->PIOReg, ((source) & 0xff00) | 0x2D); + outw(pCir->PIOReg, ((source >> 8) & 0x3f00)| 0x2E); + + /* dest */ + outw(pCir->PIOReg, ((dest << 8) & 0xff00) | 0x28); + outw(pCir->PIOReg, ((dest) & 0xff00) | 0x29); + outw(pCir->PIOReg, ((dest >> 8) & 0x3f00) | 0x2A); + if (!pCir->chip.alp->autoStart) + outw(pCir->PIOReg, 0x0231); + +#ifdef ALP_DEBUG + ErrorF("AlpSubsequentScreenToScreenCopy x1=%d y1=%d x2=%d y2=%d w=%d h=%d\n", + x1, y1, x2, y2, w, h); + ErrorF("AlpSubsequentScreenToScreenCopy s=%d d=%d ww=%d hh=%d\n", + source, dest, ww, hh); +#endif + +} + +static void +AlpSetupForSolidFill(ScrnInfoPtr pScrn, int color, int rop, + unsigned int planemask) +{ + CirPtr pCir = CIRPTR(pScrn); + AlpPtr pAlp = ALPPTR(pCir); + int pitch = pCir->pitch; + +#ifdef ALP_DEBUG + ErrorF("AlpSetupForSolidFill color=%x rop=%x planemask=%x\n", + color, rop, planemask); +#endif + WAIT; + + SetupForRop(rop); + + switch (pCir -> Chipset) + { + case PCI_CHIP_GD7548: + /* The GD7548 does not (apparently) support solid filling + directly, it always need an actual source. + We therefore use it as a pattern fill with a solid + pattern */ + { + int source = pAlp->monoPattern8x8; + /* source = 8x8 solid mono pattern */ + outw(pCir->PIOReg, ((source << 8) & 0xff00) | 0x2C); + outw(pCir->PIOReg, ((source) & 0xff00) | 0x2D); + outw(pCir->PIOReg, ((source >> 8) & 0x3f00) | 0x2E); + /* memset() may not be the fastest */ + memset(pCir->FbBase + pAlp->monoPattern8x8, 0xFF, 8); + write_mem_barrier(); + break; + } + default: + /* GR33 = 0x04 => does not exist on GD7548 */ + outw(pCir->PIOReg, 0x0433); + } + + /* GR30 = color expansion, pattern copy */ + /* Choses 8bpp / 16bpp color expansion */ + outw(pCir->PIOReg, 0xC030 |((pScrn->bitsPerPixel - 8) << 9)); + + outw(pCir->PIOReg, ((color << 8) & 0xff00) | 0x01); + outw(pCir->PIOReg, ((color) & 0xff00) | 0x11); + outw(pCir->PIOReg, ((color >> 8) & 0xff00) | 0x13); + outw(pCir->PIOReg, 0x15); + + /* Set dest pitch */ + outw(pCir->PIOReg, ((pitch << 8) & 0xff00) | 0x24); + outw(pCir->PIOReg, ((pitch) & 0x1f00) | 0x25); +} + +static void +AlpSubsequentSolidFillRect(ScrnInfoPtr pScrn, int x, int y, int w, int h) +{ + CirPtr pCir = CIRPTR(pScrn); + int dest; + int hh, ww; + int pitch = pCir->pitch; + + ww = (w * pScrn->bitsPerPixel / 8) - 1; + hh = h - 1; + dest = y * pitch + x * pScrn->bitsPerPixel / 8; + + WAIT; + + /* Width */ + outw(pCir->PIOReg, ((ww << 8) & 0xff00) | 0x20); + outw(pCir->PIOReg, ((ww) & 0x1f00) | 0x21); + /* Height */ + outw(pCir->PIOReg, ((hh << 8) & 0xff00) | 0x22); + outw(pCir->PIOReg, ((hh) & 0x0700) | 0x23); + + /* dest */ + outw(pCir->PIOReg, ((dest << 8) & 0xff00) | 0x28); + outw(pCir->PIOReg, ((dest) & 0xff00) | 0x29); + outw(pCir->PIOReg, ((dest >> 8) & 0x3f00) | 0x2A); + if (!pCir->chip.alp->autoStart) + outw(pCir->PIOReg, 0x0231); + +#ifdef ALP_DEBUG + ErrorF("AlpSubsequentSolidFillRect x=%d y=%d w=%d h=%d\n", + x, y, w, h); +#endif + +} + +static void +AlpSetupForMono8x8PatternFill(ScrnInfoPtr pScrn, + int patx, int paty, + int fg, int bg, + int rop, unsigned int planemask) +{ + CirPtr pCir = CIRPTR(pScrn); + AlpPtr pAlp = ALPPTR(pCir); + int pitch = pCir->pitch; + +#ifdef ALP_DEBUG + ErrorF("AlpSetupFor8x8PatternFill pattern=%8x%8x" + "fg=%x bg=%x rop=%x planemask=%x\n", + patx, paty, fg, bg, rop, planemask); +#endif + WAIT; + + SetupForRop(rop); + + { + int source = pAlp->monoPattern8x8; + /* source = 8x8 solid mono pattern */ + outw(pCir->PIOReg, ((source << 8) & 0xff00) | 0x2C); + outw(pCir->PIOReg, ((source) & 0xff00) | 0x2D); + outw(pCir->PIOReg, ((source >> 8) & 0x3f00) | 0x2E); + } + + /* GR30 = color expansion, pattern copy */ + /* Choses 8bpp / 16bpp color expansion */ + if (bg == -1) + { /* transparency requested */ + outw(pCir->PIOReg, 0xC830 |((pScrn->bitsPerPixel - 8) << 9)); + + bg = ~fg; + /* transparent color compare */ + outw(pCir->PIOReg, ((bg << 8) & 0xff00) | 0x34); + outw(pCir->PIOReg, ((bg) & 0xff00) | 0x35); + + /* transparent color mask = 0 (all bits matters) */ + outw(pCir->PIOReg, 0x38); + outw(pCir->PIOReg, 0x39); + } + else + { + outw(pCir->PIOReg, 0xC030 |((pScrn->bitsPerPixel - 8) << 9)); + } + + outw(pCir->PIOReg, ((fg << 8) & 0xff00) | 0x01); + outw(pCir->PIOReg, ((fg) & 0xff00) | 0x11); + + outw(pCir->PIOReg, ((bg << 8) & 0xff00) | 0x00); + outw(pCir->PIOReg, ((bg) & 0xff00) | 0x10); + + /* Set dest pitch */ + outw(pCir->PIOReg, ((pitch << 8) & 0xff00) | 0x24); + outw(pCir->PIOReg, ((pitch) & 0x1f00) | 0x25); +} + +static void +AlpSubsequentMono8x8PatternFillRect(ScrnInfoPtr pScrn, int patx, int paty, + int x, int y, int w, int h) +{ + CirPtr pCir = CIRPTR(pScrn); + AlpPtr pAlp = ALPPTR(pCir); + int dest; + int hh, ww; + int pitch = pCir->pitch; + + ww = (w * pScrn->bitsPerPixel / 8) - 1; + hh = h - 1; + dest = y * pitch + x * pScrn->bitsPerPixel / 8; + + WAIT; + /* memcpy() may not be the fastest */ + memcpy(pCir->FbBase + pAlp->monoPattern8x8, &patx, 4); + memcpy(pCir->FbBase + pAlp->monoPattern8x8 + 4, &paty, 4); + write_mem_barrier(); + + /* Width */ + outw(pCir->PIOReg, ((ww << 8) & 0xff00) | 0x20); + outw(pCir->PIOReg, ((ww) & 0x1f00) | 0x21); + /* Height */ + outw(pCir->PIOReg, ((hh << 8) & 0xff00) | 0x22); + outw(pCir->PIOReg, ((hh) & 0x0700) | 0x23); + + /* dest */ + outw(pCir->PIOReg, ((dest << 8) & 0xff00) | 0x28); + outw(pCir->PIOReg, ((dest) & 0xff00) | 0x29); + outw(pCir->PIOReg, ((dest >> 8) & 0x3f00) | 0x2A); + if (!pCir->chip.alp->autoStart) + outw(pCir->PIOReg, 0x0231); + +#ifdef ALP_DEBUG + ErrorF("AlpSubsequent8x8PatternFill x=%d y=%d w=%d h=%d\n", + x, y, w, h); +#endif + +} + +#if 0 +/* XF86 does not support byte-padded scanlines */ + +static void +AlpSetupForCPUToScreenColorExpandFill(ScrnInfoPtr pScrn, + int fg, int bg, + int rop, + unsigned int planemask) +{ + CirPtr pCir = CIRPTR(pScrn); + AlpPtr pAlp = ALPPTR(pCir); + int pitch = pCir->pitch; + +#ifdef ALP_DEBUG + ErrorF("AlpSetupForCPUToScreenColorExpandFill " + "fg=%x bg=%x rop=%x planemask=%x\n", + fg, bg, rop, planemask); +#endif + WAIT; + + SetupForRop(rop); + + /* GR30 = color expansion, CPU->display copy */ + /* Choses 8bpp / 16bpp color expansion */ + if (bg == -1) + { /* transparency requested */ + outw(pCir->PIOReg, 0x8C30 |((pScrn->bitsPerPixel - 8) << 9)); + + bg = ~fg; + /* transparent color compare */ + outw(pCir->PIOReg, ((bg << 8) & 0xff00) | 0x34); + outw(pCir->PIOReg, ((bg) & 0xff00) | 0x35); + + /* transparent color mask = 0 (all bits matters) */ + outw(pCir->PIOReg, 0x38); + outw(pCir->PIOReg, 0x39); + } + else + { + outw(pCir->PIOReg, 0x8430 |((pScrn->bitsPerPixel - 8) << 9)); + } + + outw(pCir->PIOReg, ((bg << 8) & 0xff00) | 0x00); + outw(pCir->PIOReg, ((bg) & 0xff00) | 0x10); + + outw(pCir->PIOReg, ((fg << 8) & 0xff00) | 0x01); + outw(pCir->PIOReg, ((fg) & 0xff00) | 0x11); + + /* Set dest pitch */ + outw(pCir->PIOReg, ((pitch << 8) & 0xff00) | 0x24); + outw(pCir->PIOReg, ((pitch) & 0x1f00) | 0x25); +} + +static void +AlpSubsequentCPUToScreenColorExpandFill( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, + int skipleft) +{ + CirPtr pCir = CIRPTR(pScrn); + int dest; + int hh, ww; + int pitch = pCir->pitch; + + ww = (((w+7) & ~7) * pScrn->bitsPerPixel / 8) - 1; + hh = h - 1; + dest = y * pitch + x * pScrn->bitsPerPixel / 8; + + WAIT; + + /* Width */ + outw(pCir->PIOReg, ((ww << 8) & 0xff00) | 0x20); + outw(pCir->PIOReg, ((ww) & 0x1f00) | 0x21); + /* Height */ + outw(pCir->PIOReg, ((hh << 8) & 0xff00) | 0x22); + outw(pCir->PIOReg, ((hh) & 0x0700) | 0x23); + + /* source = CPU ; description of bit 2 of GR30 in the 7548 manual + says that if we do color expansion we must zero the source + adress registers (GR2C, GR2D, GR2E) */ + outw(pCir->PIOReg, 0x2C); + outw(pCir->PIOReg, 0x2D); + outw(pCir->PIOReg, 0x2E); + + /* dest */ + outw(pCir->PIOReg, ((dest << 8) & 0xff00) | 0x28); + outw(pCir->PIOReg, ((dest) & 0xff00) | 0x29); + outw(pCir->PIOReg, ((dest >> 8) & 0x3f00) | 0x2A); + if (!pCir->chip.alp->autoStart) + outw(pCir->PIOReg, 0x0231); + +#ifdef ALP_DEBUG + ErrorF("AlpSubsequentCPUToScreenColorExpandFill x=%d y=%d w=%d h=%d\n", + x, y, w, h); +#endif +} +#endif + +#if 1 +static void +AlpSetupForScanlineCPUToScreenColorExpandFill(ScrnInfoPtr pScrn, + int fg, int bg, + int rop, + unsigned int planemask) +{ + CirPtr pCir = CIRPTR(pScrn); + int pitch = pCir->pitch; + +#ifdef ALP_DEBUG + ErrorF("AlpSetupForCPUToScreenColorExpandFill " + "fg=%x bg=%x rop=%x planemask=%x, bpp=%d\n", + fg, bg, rop, planemask, pScrn->bitsPerPixel); +#endif + WAIT; + + SetupForRop(rop); + + /* GR30 = color expansion, CPU->display copy */ + /* Choses 8bpp / 16bpp color expansion */ + if (bg == -1) + { /* transparency requested */ + if (pScrn->bitsPerPixel > 8) /* 16 bpp */ + { + outw(pCir->PIOReg, 0x9C30); + + bg = ~fg; + /* transparent color compare */ + outw(pCir->PIOReg, ((bg << 8) & 0xff00) | 0x34); + outw(pCir->PIOReg, ((bg) & 0xff00) | 0x35); + } else /* 8 bpp */ + { + outw(pCir->PIOReg, 0x8C30); + + bg = ~fg; + /* transparent color compare */ + outw(pCir->PIOReg, ((bg << 8) & 0xff00) | 0x34); + outw(pCir->PIOReg, ((bg << 8) & 0xff00) | 0x35); + } + + /* transparent color mask = 0 (all bits matters) */ + outw(pCir->PIOReg, 0x38); + outw(pCir->PIOReg, 0x39); + } + else + { + outw(pCir->PIOReg, 0x8430 |((pScrn->bitsPerPixel - 8) << 9)); + } + + outw(pCir->PIOReg, ((bg << 8) & 0xff00) | 0x00); + outw(pCir->PIOReg, ((bg) & 0xff00) | 0x10); + + outw(pCir->PIOReg, ((fg << 8) & 0xff00) | 0x01); + outw(pCir->PIOReg, ((fg) & 0xff00) | 0x11); + + /* Set dest pitch */ + outw(pCir->PIOReg, ((pitch << 8) & 0xff00) | 0x24); + outw(pCir->PIOReg, ((pitch) & 0x1f00) | 0x25); +} + +static void +AlpSubsequentScanlineCPUToScreenColorExpandFill( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, + int skipleft) +{ + CirPtr pCir = CIRPTR(pScrn); + AlpPtr pAlp = ALPPTR(pCir); + + int pitch = pCir->pitch; + + pAlp->SubsequentColorExpandScanlineByteWidth = + (w * pScrn->bitsPerPixel / 8) - 1; + pAlp->SubsequentColorExpandScanlineDWordWidth = + (w + 31) >> 5; + pAlp->SubsequentColorExpandScanlineDest = + y * pitch + x * pScrn->bitsPerPixel / 8; + +#ifdef ALP_DEBUG + ErrorF("AlpSubsequentScanlineCPUToScreenColorExpandFill x=%d y=%d w=%d h=%d skipleft=%d\n", + x, y, w, h, skipleft); +#endif +} + +static void +AlpSubsequentColorExpandScanline( + ScrnInfoPtr pScrn, + int bufno) +{ + CirPtr pCir = CIRPTR(pScrn); + AlpPtr pAlp = ALPPTR(pCir); + int dest=pAlp->SubsequentColorExpandScanlineDest; + int ww=pAlp->SubsequentColorExpandScanlineByteWidth; + int width=pAlp->SubsequentColorExpandScanlineDWordWidth; + CARD32* from; + volatile CARD32 *to; + +#ifdef ALP_DEBUG + ErrorF("AlpSubsequentColorExpandScanline\n"); +#endif + + pAlp->SubsequentColorExpandScanlineDest += pCir->pitch; + + to = (CARD32*) pCir->FbBase; + from = (CARD32*) (pCir->ScanlineColorExpandBuffers[bufno]); + WAIT_1; + + /* Width */ + outw(pCir->PIOReg, ((ww << 8) & 0xff00) | 0x20); + outw(pCir->PIOReg, ((ww) & 0x1f00) | 0x21); + + /* Height = 1 */ + outw(pCir->PIOReg, 0x22); + outw(pCir->PIOReg, 0x23); + + /* source = CPU ; description of bit 2 of GR30 in the 7548 manual + says that if we do color expansion we must zero the source + adress registers (GR2C, GR2D, GR2E) */ + outw(pCir->PIOReg, 0x2C); + outw(pCir->PIOReg, 0x2D); + outw(pCir->PIOReg, 0x2E); + + /* dest */ + outw(pCir->PIOReg, ((dest << 8) & 0xff00) | 0x28); + outw(pCir->PIOReg, ((dest) & 0xff00) | 0x29); + write_mem_barrier(); + +#ifdef ALP_DEBUG + ErrorF("AlpSubsequentColorExpandScanline (2)\n"); +#endif + + outw(pCir->PIOReg, ((dest >> 8) & 0x3f00) | 0x2A); + if (!pCir->chip.alp->autoStart) + outw(pCir->PIOReg, 0x0231); + + { + int i; + for (i=0; iPIOReg, 0x200E); /* enable writes to gr33 */ + /* Setup things for autostart */ + if (pCir->properties & ACCEL_AUTOSTART) { + outw(pCir->PIOReg, 0x8031); /* enable autostart */ + pCir->chip.alp->waitMsk = 0x10; + pCir->chip.alp->autoStart = TRUE; + } else { + pCir->chip.alp->waitMsk = 0x1; + pCir->chip.alp->autoStart = FALSE; + } +} + +Bool +AlpXAAInit(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + CirPtr pCir = CIRPTR(pScrn); + AlpPtr pAlp = ALPPTR(pCir); + XAAInfoRecPtr XAAPtr; + + pCir->InitAccel = AlpAccelEngineInit; +#ifdef ALP_DEBUG + ErrorF("AlpXAAInit\n"); +#endif + + XAAPtr = XAACreateInfoRec(); + if (!XAAPtr) return FALSE; + + /* Pixmap cache */ + XAAPtr->Flags |= LINEAR_FRAMEBUFFER; + XAAPtr->Sync = AlpSync; + + XAAPtr->SetupForScreenToScreenCopy = AlpSetupForScreenToScreenCopy; + XAAPtr->SubsequentScreenToScreenCopy = AlpSubsequentScreenToScreenCopy; + XAAPtr->ScreenToScreenCopyFlags = + NO_TRANSPARENCY | NO_PLANEMASK; + + XAAPtr->SetupForSolidFill = AlpSetupForSolidFill; + XAAPtr->SubsequentSolidFillRect = AlpSubsequentSolidFillRect; + XAAPtr->SubsequentSolidFillTrap = NULL; + XAAPtr->SolidFillFlags = NO_PLANEMASK; + + if (pCir->Chipset == PCI_CHIP_GD7548) { + if (pAlp->monoPattern8x8) { + XAAPtr->SetupForMono8x8PatternFill + = AlpSetupForMono8x8PatternFill; + XAAPtr->SubsequentMono8x8PatternFillRect + = AlpSubsequentMono8x8PatternFillRect; + XAAPtr->SubsequentMono8x8PatternFillTrap = NULL; + XAAPtr->Mono8x8PatternFillFlags = + NO_PLANEMASK | + HARDWARE_PATTERN_PROGRAMMED_BITS | BIT_ORDER_IN_BYTE_MSBFIRST; + } +#if 1 + /* kludge: since XF86 does not support byte-padded + mono bitmaps (only dword-padded), use the + scanline version */ + XAAPtr->SetupForScanlineCPUToScreenColorExpandFill = + AlpSetupForScanlineCPUToScreenColorExpandFill; + XAAPtr->SubsequentScanlineCPUToScreenColorExpandFill = + AlpSubsequentScanlineCPUToScreenColorExpandFill; + XAAPtr->SubsequentColorExpandScanline = + AlpSubsequentColorExpandScanline; + { + const int NumScanlineColorExpandBuffers = 2; + int i; + int buffer_size = (pCir->pScrn->virtualX + 31) & ~31; +#ifdef ALP_DEBUG + ErrorF("Computing buffers for %d pixel lines\n", + pCir->pScrn->virtualX); +#endif + XAAPtr->NumScanlineColorExpandBuffers = + NumScanlineColorExpandBuffers; + XAAPtr->ScanlineColorExpandBuffers = + pCir->ScanlineColorExpandBuffers = (unsigned char **) + (malloc(sizeof(unsigned char *) * + NumScanlineColorExpandBuffers)); + /* TODO: are those mallocs to be freed ? */ + + for(i=0; iScanlineColorExpandBuffers[i] = (unsigned char *) + malloc(buffer_size); + } + XAAPtr->ScanlineCPUToScreenColorExpandFillFlags = + NO_PLANEMASK | BIT_ORDER_IN_BYTE_MSBFIRST | + SCANLINE_PAD_DWORD | ROP_NEEDS_SOURCE; +#endif +#if 0 + /* Currently disabled: XF86 sends DWORD-padded data, + not byte-padded */ + XAAPtr->SetupForCPUToScreenColorExpandFill = + AlpSetupForCPUToScreenColorExpandFill; + XAAPtr->SubsequentCPUToScreenColorExpandFill = + AlpSubsequentCPUToScreenColorExpandFill; + XAAPtr->ColorExpandBase = pCir->FbBase + 4; + XAAPtr->CPUToScreenColorExpandFillFlags = + NO_PLANEMASK | BIT_ORDER_IN_BYTE_MSBFIRST | + SCANLINE_PAD_DWORD | ROP_NEEDS_SOURCE | + CPU_TRANSFER_PAD_DWORD | CPU_TRANSFER_BASE_FIXED; +#endif + } + + AlpAccelEngineInit(pScrn); + + pCir->AccelInfoRec = XAAPtr; + + if (!XAAInit(pScreen, XAAPtr)) + return FALSE; + + return TRUE; +} + diff --git a/src/alp_xaam.c b/src/alp_xaam.c new file mode 100644 index 0000000..2f25092 --- /dev/null +++ b/src/alp_xaam.c @@ -0,0 +1,271 @@ +/* (c) Itai Nahshon */ +/* #define DEBUG */ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/cirrus/alp_xaam.c,v 1.8 2002/07/10 02:36:50 tsi Exp $ */ + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86_ansic.h" +#include "compiler.h" + +#include "xf86Pci.h" +#include "xf86PciInfo.h" + +#include "vgaHW.h" + +#include "cir.h" +#define _ALP_PRIVATE_ +#include "alp.h" + +#ifdef DEBUG +#define minb(p) \ + (ErrorF("minb(%X)\n", p),\ + MMIO_IN8(pCir->chip.alp->BLTBase, (p))) +#define moutb(p,v) \ + (ErrorF("moutb(%X, %X)\n", p,v),\ + MMIO_OUT8(pCir->chip.alp->BLTBase, (p),(v))) +#define vga_minb(p) \ + (ErrorF("minb(%X)\n", p),\ + MMIO_IN8(hwp->MMIOBase, (hwp->MMIOOffset + (p)))) +#define vga_moutb(p,v) \ + { ErrorF("moutb(%X, %X)\n", p,v);\ + MMIO_OUT8(hwp->MMIOBase, (hwp->MMIOOffset + (p)),(v));} +#define minl(p) \ + (ErrorF("minl(%X)\n", p),\ + MMIO_IN32(pCir->chip.alp->BLTBase, (p))) +#define moutl(p,v) \ + (ErrorF("moutl(%X, %X)\n", p,v),\ + MMIO_OUT32(pCir->chip.alp->BLTBase, (p),(v))) +#else +#define minb(p) MMIO_IN8(pCir->chip.alp->BLTBase, (p)) +#define moutb(p,v) MMIO_OUT8(pCir->chip.alp->BLTBase, (p),(v)) +#define vga_minb(p) MMIO_IN8(hwp->MMIIOBase, (hwp->MMIOOffset + (p))) +#define vga_moutb(p,v) MMIO_OUT8(hwp->MMIOBase, (hwp->MMIOOffset + (p)),(v)) +#define minl(p) MMIO_IN32(pCir->chip.alp->BLTBase, (p)) +#define moutl(p,v) MMIO_OUT32(pCir->chip.alp->BLTBase, (p),(v)) +#endif + +static const CARD8 translated_rop[] = +{ + /* GXclear */ 0x00U, + /* GXand */ 0x05U, + /* GXandreverse */ 0x09U, + /* GXcopy */ 0x0DU, + /* GXandinversted */ 0x50U, + /* GXnoop */ 0x06U, + /* GXxor */ 0x59U, + /* GXor */ 0x6DU, + /* GXnor */ 0x90U, + /* GXequiv */ 0x95U, + /* GXinvert */ 0x0BU, + /* GXorReverse */ 0xADU, + /* GXcopyInverted */ 0xD0U, + /* GXorInverted */ 0xD6U, + /* GXnand */ 0xDAU, + /* GXset */ 0x0EU +}; + +#define WAIT while(minl(0x40) & pCir->chip.alp->waitMsk){}; +#define WAIT_1 while((minl(0x40)) & 0x1){}; + +static void AlpSync(ScrnInfoPtr pScrn) +{ + CirPtr pCir = CIRPTR(pScrn); +#ifdef ALP_DEBUG + ErrorF("AlpSync mm\n"); +#endif + WAIT_1; + return; +} + +static void +AlpSetupForScreenToScreenCopy(ScrnInfoPtr pScrn, int xdir, int ydir, int rop, + unsigned int planemask, int trans_color) +{ + CirPtr pCir = CIRPTR(pScrn); + int pitch = pCir->pitch; + + WAIT; + + pCir->chip.alp->transRop = translated_rop[rop] << 16; + +#ifdef ALP_DEBUG + ErrorF("AlpSetupForScreenToScreenCopy xdir=%d ydir=%d rop=%x planemask=%x trans_color=%x\n", + xdir, ydir, rop, planemask, trans_color); +#endif + moutl(0x0C, (pitch << 16) | pitch); + +} + +static void +AlpSubsequentScreenToScreenCopy(ScrnInfoPtr pScrn, int x1, int y1, int x2, + int y2, int w, int h) +{ + CirPtr pCir = CIRPTR(pScrn); + int source, dest; + int hh, ww; + int decrement = 0; + int pitch = pCir->pitch; + + ww = ((w * pScrn->bitsPerPixel / 8) - 1) & 0x1fff; + hh = (h - 1) & 0x1fff; + dest = y2 * pitch + x2 * pScrn->bitsPerPixel / 8; + source = y1 * pitch + x1 * pScrn->bitsPerPixel / 8; + if (dest > source) { + decrement = 1; + dest += hh * pitch + ww; + source += hh * pitch + ww; + } + + WAIT; + + /* Width / Height */ + moutl(0x08, (hh << 16) | ww); + /* source */ + moutl(0x14, source & 0x3fffff); + moutl(0x18, pCir->chip.alp->transRop | decrement); + + /* dest */ + write_mem_barrier(); + moutl(0x10, dest & 0x3fffff); + +#ifdef ALP_DEBUG + ErrorF("AlpSubsequentScreenToScreenCopy x1=%d y1=%d x2=%d y2=%d w=%d h=%d\n", + x1, y1, x2, y2, w, h); + ErrorF("AlpSubsequentScreenToScreenCopy s=%d d=%d ww=%d hh=%d\n", + source, dest, ww, hh); +#endif + if (!pCir->chip.alp->autoStart) { + CARD32 val = minl(0x40); + moutl(0x40,val | 0x02); + } + write_mem_barrier(); +} + + +static void +AlpSetupForSolidFill(ScrnInfoPtr pScrn, int color, int rop, + unsigned int planemask) +{ + CirPtr pCir = CIRPTR(pScrn); + int pitch = pCir->pitch; + + WAIT; + +#ifdef ALP_DEBUG + ErrorF("AlpSetupForSolidFill color=%x rop=%x planemask=%x\n", + color, rop, planemask); +#endif + + moutl(0x04, color & 0xffffff); + + /* Set dest pitch */ + moutl(0x0C, pitch & 0x1fff); + moutl(0x18, (((pScrn->bitsPerPixel - 8) << 1)) + | translated_rop[rop] << 16 + | 0x040000C0); +} + +static void +AlpSubsequentSolidFillRect(ScrnInfoPtr pScrn, int x, int y, int w, int h) +{ + int dest; + int hh, ww; + CirPtr pCir = CIRPTR(pScrn); + int pitch = pCir->pitch; + + ww = ((w * pScrn->bitsPerPixel / 8) - 1) & 0x1fff; + hh = (h - 1) & 0x7ff; + dest = y * pitch + x * pScrn->bitsPerPixel / 8; + + WAIT; + + /* Width / Height */ + write_mem_barrier(); + moutl(0x08, (hh << 16) | ww); + +#ifdef ALP_DEBUG + ErrorF("AlpSubsequentSolidFillRect x=%d y=%d w=%d h=%d\n", + x, y, w, h); +#endif + /* dest */ + moutl(0x10, (dest & 0x3fffff)); + + if (!pCir->chip.alp->autoStart) { + CARD32 val = minl(0x40); + moutl(0x40, val | 0x02); + } + write_mem_barrier(); +} + +static void +AlpAccelEngineInit(ScrnInfoPtr pScrn) +{ + vgaHWPtr hwp = VGAHWPTR(pScrn); + CirPtr pCir = CIRPTR(pScrn); + + if (pCir->Chipset != PCI_CHIP_GD7548) { + vga_moutb(0x3CE, 0x0E); /* enable writes to gr33 */ + vga_moutb(0x3CF, 0x20); /* enable writes to gr33 */ + } + if (pCir->properties & ACCEL_AUTOSTART) { + moutl(0x40, 0x80); /* enable autostart */ + pCir->chip.alp->waitMsk = 0x10; + pCir->chip.alp->autoStart = TRUE; + } else { + pCir->chip.alp->waitMsk = 0x1; + pCir->chip.alp->autoStart = FALSE; + } +} + +Bool +AlpXAAInitMMIO(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + CirPtr pCir = CIRPTR(pScrn); + XAAInfoRecPtr XAAPtr; + + pCir->InitAccel = AlpAccelEngineInit; +#ifdef ALP_DEBUG + ErrorF("AlpXAAInitMM\n"); +#endif + + XAAPtr = XAACreateInfoRec(); + if (!XAAPtr) return FALSE; + + XAAPtr->Flags |= LINEAR_FRAMEBUFFER; + XAAPtr->Sync = AlpSync; + + XAAPtr->SetupForScreenToScreenCopy = AlpSetupForScreenToScreenCopy; + XAAPtr->SubsequentScreenToScreenCopy = AlpSubsequentScreenToScreenCopy; + XAAPtr->ScreenToScreenCopyFlags = + (NO_TRANSPARENCY | NO_PLANEMASK); + + XAAPtr->SetupForSolidFill = AlpSetupForSolidFill; + XAAPtr->SubsequentSolidFillRect = AlpSubsequentSolidFillRect; + XAAPtr->SubsequentSolidFillTrap = NULL; + XAAPtr->SolidFillFlags = NO_PLANEMASK; + + switch (pCir->Chipset) { + case PCI_CHIP_GD5480: + case PCI_CHIP_GD5446: + pCir->chip.alp->BLTBase = pCir->IOBase + 0x100; + break; + default: + pCir->chip.alp->BLTBase = pCir->IOBase; + break; + } + + AlpAccelEngineInit(pScrn); + + pCir->AccelInfoRec = XAAPtr; + + if (!XAAInit(pScreen, XAAPtr)) + return FALSE; + + return TRUE; +} + + + + + diff --git a/src/cir.h b/src/cir.h new file mode 100644 index 0000000..536f7aa --- /dev/null +++ b/src/cir.h @@ -0,0 +1,97 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/cirrus/cir.h,v 1.21 2002/01/25 21:56:01 tsi Exp $ */ + +/* (c) Itai Nahshon */ + +#ifndef CIR_H +#define CIR_H + +#include "xf86Cursor.h" +#include "xaa.h" +#include "xf86i2c.h" + +/* Card-specific driver information */ +#define CIRPTR(p) ((CirPtr)((p)->driverPrivate)) +struct lgRec; +struct alpRec; + +typedef struct { + ScrnInfoPtr pScrn; + CARD32 properties; + pciVideoPtr PciInfo; + PCITAG PciTag; + IOADDRESS PIOReg; + union { + struct lgRec *lg; + struct alpRec *alp; + } chip; + EntityInfoPtr pEnt; + int Chipset; + int ChipRev; + int Rounding; + int BppShift; + Bool HasFBitBlt; + CARD32 IOAddress; + CARD32 FbAddress; + unsigned char * IOBase; + unsigned char * FbBase; + long FbMapSize; + long IoMapSize; + int MinClock; + int MaxClock; + Bool NoAccel; + Bool HWCursor; + Bool UseMMIO; + XAAInfoRecPtr AccelInfoRec; + xf86CursorInfoPtr CursorInfoRec; + int DGAnumModes; + DGAModePtr DGAModes; + Bool DGAactive; + Bool (*DGAModeInit)(ScrnInfoPtr, DisplayModePtr); + int DGAViewportStatus; + I2CBusPtr I2CPtr1; + I2CBusPtr I2CPtr2; + CloseScreenProcPtr CloseScreen; + + Bool CursorIsSkewed; + Bool shadowFB; + int rotate; + int ShadowPitch; + unsigned char * ShadowPtr; + void (*PointerMoved)(int index, int x, int y); + int pitch; + + unsigned char ** ScanlineColorExpandBuffers; + void (*InitAccel)(ScrnInfoPtr); + int offscreen_size; + int offscreen_offset; + OptionInfoPtr Options; +} CirRec, *CirPtr; + +/* CirrusClk.c */ +extern Bool +CirrusFindClock(int *rfreq, int max_clock, int *num_out, int *den_out); + +/* cir_driver.c */ +extern SymTabRec CIRChipsets[]; +extern PciChipsets CIRPciChipsets[]; + +extern Bool CirMapMem(CirPtr pCir, int scrnIndex); +extern Bool CirUnmapMem(CirPtr pCir, int scrnIndex); +extern void cirProbeDDC(ScrnInfoPtr pScrn, int index); + +/* cir_dga.c */ +extern Bool CirDGAInit(ScreenPtr pScreen); + +/* in cir_shadow.c */ +void cirPointerMoved(int index, int x, int y); +void cirRefreshArea(ScrnInfoPtr pScrn, int num, BoxPtr pbox); +void cirRefreshArea8(ScrnInfoPtr pScrn, int num, BoxPtr pbox); +void cirRefreshArea16(ScrnInfoPtr pScrn, int num, BoxPtr pbox); +void cirRefreshArea24(ScrnInfoPtr pScrn, int num, BoxPtr pbox); +void cirRefreshArea32(ScrnInfoPtr pScrn, int num, BoxPtr pbox); + +/* properties */ +#define HWCUR64 0x1 +#define ACCEL_AUTOSTART 0x2 + +#endif /* CIR_H */ diff --git a/src/cir_dga.c b/src/cir_dga.c new file mode 100644 index 0000000..7677160 --- /dev/null +++ b/src/cir_dga.c @@ -0,0 +1,256 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/cirrus/cir_dga.c,v 1.7 2001/10/01 13:44:05 eich Exp $ */ +/* + * Copyright 2000 by Egbert Eich + * + * 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 Alan Hourihane not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Alan Hourihane makes no representations + * about the suitability of this software for any purpose. It is provided + * "as is" without express or implied warranty. + * + * EGBERT EICH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL ALAN HOURIHANE 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. + * + * Authors: Adapted from: Alan Hourihane, + * by: Egbert Eich + */ + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86_ansic.h" +#include "xf86Pci.h" +#include "xf86PciInfo.h" +#include "xaa.h" +#include "xaalocal.h" +#include "vgaHW.h" +#include "cir.h" +#include "dgaproc.h" + +static Bool Cir_OpenFramebuffer(ScrnInfoPtr, char **, unsigned char **, + int *, int *, int *); +static Bool Cir_SetMode(ScrnInfoPtr, DGAModePtr); +static void Cir_Sync(ScrnInfoPtr); +static int Cir_GetViewport(ScrnInfoPtr); +static void Cir_SetViewport(ScrnInfoPtr, int, int, int); +static void Cir_FillRect(ScrnInfoPtr, int, int, int, int, unsigned long); +static void Cir_BlitRect(ScrnInfoPtr, int, int, int, int, int, int); +/* +static void Cir_BlitTransRect(ScrnInfoPtr, int, int, int, int, int, int, + unsigned long); +*/ + +static +DGAFunctionRec CirDGAFuncs = { + Cir_OpenFramebuffer, + NULL, /* Cir_CloseFramebuffer */ + Cir_SetMode, + Cir_SetViewport, + Cir_GetViewport, + Cir_Sync, + Cir_FillRect, + Cir_BlitRect, + NULL /* Cir_BlitTransRect */ +}; + + + + +Bool +CirDGAInit(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + CirPtr pCir = CIRPTR(pScrn); + DGAModePtr modes = NULL, newmodes = NULL, currentMode; + DisplayModePtr pMode, firstMode; + int Bpp = pScrn->bitsPerPixel >> 3; + int num = 0; + int imlines = (pScrn->videoRam * 1024) / + (pScrn->displayWidth * (pScrn->bitsPerPixel >> 3)); + + + if (!pCir->DGAnumModes) { + pMode = firstMode = pScrn->modes; + while (pMode) { + newmodes = xrealloc(modes, (num + 1) * sizeof (DGAModeRec)); + if (!newmodes) { + xfree(modes); + return FALSE; + } + modes = newmodes; + currentMode = modes + num; + num++; + (void)memset(currentMode, 1, sizeof(DGAModeRec)); + currentMode->mode = pMode; + currentMode->flags = DGA_PIXMAP_AVAILABLE + | ((!pCir->NoAccel) ? (DGA_FILL_RECT | DGA_BLIT_RECT) : 0); + if (pMode->Flags & V_DBLSCAN) + currentMode->flags |= DGA_DOUBLESCAN; + if(pMode->Flags & V_INTERLACE) + currentMode->flags |= DGA_INTERLACED; + currentMode->byteOrder = pScrn->imageByteOrder; + currentMode->depth = pScrn->depth; + currentMode->bitsPerPixel = pScrn->bitsPerPixel; + currentMode->red_mask = pScrn->mask.red; + currentMode->green_mask = pScrn->mask.green; + currentMode->blue_mask = pScrn->mask.blue; + currentMode->visualClass = (Bpp == 1) ? PseudoColor : TrueColor; + currentMode->viewportWidth = pMode->HDisplay; + currentMode->viewportHeight = pMode->VDisplay; + currentMode->xViewportStep = 1; /* The granularity of x and y pos. */ + currentMode->yViewportStep = 1; + currentMode->viewportFlags = 0 /*DGA_FLIP_RETRACE*/; + currentMode->offset = 0; + currentMode->address = pCir->FbBase; + currentMode->bytesPerScanline = ((pScrn->displayWidth * Bpp) + 3) & ~3L; + currentMode->pixmapWidth = currentMode->imageWidth + = pScrn->displayWidth; + currentMode->pixmapHeight = currentMode->imageHeight = imlines; + currentMode->maxViewportX = currentMode->imageWidth - + currentMode->viewportWidth; + /* this might need to get clamped to some maximum */ + currentMode->maxViewportY = currentMode->imageHeight - + currentMode->viewportHeight; + + pMode = pMode->next; + if(pMode == firstMode) + break; + } + pCir->DGAnumModes = num; + pCir->DGAModes = modes; + } + return DGAInit(pScreen, &CirDGAFuncs, pCir->DGAModes, pCir->DGAnumModes); +} + +static Bool +Cir_OpenFramebuffer( + ScrnInfoPtr pScrn, + char **name, + unsigned char **mem, + int *size, + int *offset, + int *flags +){ + CirPtr pCir = CIRPTR(pScrn); + + *name = NULL; /* no special device */ + *mem = (unsigned char*)(long)pCir->FbAddress; + *size = pCir->FbMapSize; + *offset = 0; /* Always */ + *flags = 0; /* Root permissions OS-dependent */ + + return TRUE; +} + + +static Bool +Cir_SetMode( + ScrnInfoPtr pScrn, + DGAModePtr pMode +){ + CirPtr pCir = CIRPTR(pScrn); + static int OldDisplayWidth[MAXSCREENS]; + int index = pScrn->pScreen->myNum; + Bool ret = FALSE; + + if(!pMode) { /* restore the original mode */ + /* put the ScreenParameters back */ + pScrn->displayWidth = OldDisplayWidth[index]; + ret = pCir->DGAModeInit(xf86Screens[index], pScrn->currentMode); + pCir->DGAactive = FALSE; + } else { + if(!pCir->DGAactive) { /* save the old parameters */ + OldDisplayWidth[index] = pScrn->displayWidth; + + pCir->DGAactive = TRUE; + } + pScrn->displayWidth = pMode->bytesPerScanline / + (pMode->bitsPerPixel >> 3); + + ret = pCir->DGAModeInit(xf86Screens[index], pMode->mode); + } + return ret; +} + +static void +Cir_SetViewport( + ScrnInfoPtr pScrn, + int x, int y, + int flags +){ + CirPtr pCir = CIRPTR(pScrn); + vgaHWPtr hwp = VGAHWPTR(pScrn); + + pScrn->AdjustFrame(pScrn->pScreen->myNum, x, y, flags); + + while((hwp->readST01(hwp) & 0x08)); + while(!(hwp->readST01(hwp) & 0x08)); + + pCir->DGAViewportStatus = 0; /* AdjustFrame loops until finished */ +} + +static int +Cir_GetViewport( + ScrnInfoPtr pScrn +){ + CirPtr pCir = CIRPTR(pScrn); + + return pCir->DGAViewportStatus; +} + + + +static void +Cir_Sync( + ScrnInfoPtr pScrn +){ + CirPtr pCir = CIRPTR(pScrn); + + if(pCir->AccelInfoRec) { + (*pCir->AccelInfoRec->Sync)(pScrn); + } +} + +static void +Cir_FillRect ( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, + unsigned long color +){ + CirPtr pCir = CIRPTR(pScrn); + + if(pCir->AccelInfoRec) { + (*pCir->AccelInfoRec->SetupForSolidFill)(pScrn, color, GXcopy, ~0); + (*pCir->AccelInfoRec->SubsequentSolidFillRect)(pScrn, x, y, w, h); + SET_SYNC_FLAG(pCir->AccelInfoRec); + } +} + +static void +Cir_BlitRect( + ScrnInfoPtr pScrn, + int srcx, int srcy, + int w, int h, + int dstx, int dsty +){ + CirPtr pCir = CIRPTR(pScrn); + + if(pCir->AccelInfoRec) { + int xdir = ((srcx < dstx) && (srcy == dsty)) ? -1 : 1; + int ydir = (srcy < dsty) ? -1 : 1; + + (*pCir->AccelInfoRec->SetupForScreenToScreenCopy)( + pScrn, xdir, ydir, GXcopy, ~0, -1); + (*pCir->AccelInfoRec->SubsequentScreenToScreenCopy)( + pScrn, srcx, srcy, dstx, dsty, w, h); + SET_SYNC_FLAG(pCir->AccelInfoRec); + } +} diff --git a/src/cir_driver.c b/src/cir_driver.c new file mode 100644 index 0000000..b8c2c49 --- /dev/null +++ b/src/cir_driver.c @@ -0,0 +1,409 @@ +/* + * Driver for CL-GD5480. + * Itai Nahshon. + * + * Support for the CL-GD7548: David Monniaux + * + * This is mainly a cut & paste from the MGA driver. + * Original autors and contributors list include: + * Radoslaw Kapitan, Andrew Vanderstock, Dirk Hohndel, + * David Dawes, Andrew E. Mileski, Leonard N. Zubkoff, + * Guy DESBIEF + */ + +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/cirrus/cir_driver.c,v 1.68 2001/06/13 23:34:09 dawes Exp $ */ + +/* All drivers should typically include these */ +#include "xf86.h" +#include "xf86_OSproc.h" + +#include "xf86Resources.h" + +/* All drivers need this */ +#include "xf86_ansic.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" + +#include "cir.h" +#include "alp.h" +#include "lg.h" + +#include "vbe.h" + +/* + * Forward definitions for the functions that make up the driver. + */ + +/* Mandatory functions */ + +static const OptionInfoRec * CIRAvailableOptions(int chipid, int busid); +static void CIRIdentify(int flags); +static Bool CIRProbe(DriverPtr drv, int flags); + +static Bool lg_loaded = FALSE; +static Bool alp_loaded = FALSE; + +#define VERSION 4000 +#define CIR_NAME "CIRRUS" +#define CIR_DRIVER_NAME "cirrus" +#define CIR_MAJOR_VERSION 1 +#define CIR_MINOR_VERSION 0 +#define CIR_PATCHLEVEL 0 + +/* + * This contains the functions needed by the server after loading the + * driver module. It must be supplied, and gets added the driver list by + * the Module Setup funtion 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 CIRRUS = { + VERSION, + CIR_DRIVER_NAME, + CIRIdentify, + CIRProbe, + CIRAvailableOptions, + NULL, + 0 +}; + +/* Supported chipsets */ +SymTabRec CIRChipsets[] = { + { PCI_CHIP_GD5430, "CLGD5430" }, + { PCI_CHIP_GD5434_4, "CLGD5434-4" }, + { PCI_CHIP_GD5434_8, "CLGD5434-8" }, + { PCI_CHIP_GD5436, "CLGD5436" }, +/* { PCI_CHIP_GD5440, "CLGD5440" }, */ + { PCI_CHIP_GD5446, "CLGD5446" }, + { PCI_CHIP_GD5480, "CLGD5480" }, + { PCI_CHIP_GD5462, "CL-GD5462" }, + { PCI_CHIP_GD5464, "CL-GD5464" }, + { PCI_CHIP_GD5464BD, "CL-GD5464BD" }, + { PCI_CHIP_GD5465, "CL-GD5465" }, + { PCI_CHIP_GD7548, "CL-GD7548" }, + {-1, NULL } +}; + +/* List of PCI chipset names */ +PciChipsets CIRPciChipsets[] = { + { PCI_CHIP_GD5430, PCI_CHIP_GD5430, RES_SHARED_VGA }, + { PCI_CHIP_GD5434_4,PCI_CHIP_GD5434_4, RES_SHARED_VGA }, + { PCI_CHIP_GD5434_8,PCI_CHIP_GD5434_8, RES_SHARED_VGA }, + { PCI_CHIP_GD5436, PCI_CHIP_GD5436, RES_SHARED_VGA }, +/* { PCI_CHIP_GD5440, PCI_CHIP_GD5440, RES_SHARED_VGA }, */ + { PCI_CHIP_GD5446, PCI_CHIP_GD5446, RES_SHARED_VGA }, + { PCI_CHIP_GD5480, PCI_CHIP_GD5480, RES_SHARED_VGA }, + { PCI_CHIP_GD5462, PCI_CHIP_GD5462, RES_SHARED_VGA }, + { PCI_CHIP_GD5464, PCI_CHIP_GD5464, RES_SHARED_VGA }, + { PCI_CHIP_GD5464BD,PCI_CHIP_GD5464BD, RES_SHARED_VGA }, + { PCI_CHIP_GD5465, PCI_CHIP_GD5465, RES_SHARED_VGA }, + { PCI_CHIP_GD7548, PCI_CHIP_GD7548, RES_SHARED_VGA }, + { -1, -1, RES_UNDEFINED} +}; + +/* + * 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 *alpSymbols[] = { + "AlpAvailableOptions", + "AlpProbe", + NULL +}; +static const char *lgSymbols[] = { + "LgAvailableOptions", + "LgProbe", + NULL +}; + +static const char *vbeSymbols[] = { + "VBEInit", + "vbeDoEDID", + "vbeFree", + NULL +}; + +#ifdef XFree86LOADER + +static MODULESETUPPROTO(cirSetup); + +static XF86ModuleVersionInfo cirVersRec = +{ + "cirrus", + MODULEVENDORSTRING, + MODINFOSTRING1, + MODINFOSTRING2, + XF86_VERSION_CURRENT, + CIR_MAJOR_VERSION, CIR_MINOR_VERSION, CIR_PATCHLEVEL, + ABI_CLASS_VIDEODRV, /* This is a video driver */ + 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 cirrusModuleData = { &cirVersRec, cirSetup, NULL }; + +static pointer +cirSetup(pointer module, pointer opts, int *errmaj, int *errmin) +{ + static Bool setupDone = FALSE; + + /* This module should be loaded only once, but check to be sure. */ + + if (!setupDone) { + setupDone = TRUE; + xf86AddDriver(&CIRRUS, module, 0); + + LoaderRefSymLists(alpSymbols, lgSymbols, vbeSymbols, NULL); + return (pointer)1; + } + if (errmaj) *errmaj = LDR_ONCEONLY; + return NULL; +} + +#endif /* XFree86LOADER */ + +/* Mandatory */ +static void +CIRIdentify(int flags) +{ + xf86PrintChipsets(CIR_NAME, "driver for Cirrus chipsets", CIRChipsets); +} + +static const OptionInfoRec * +CIRAvailableOptions(int chipid, int busid) +{ + int chip = chipid & 0xffff; + + switch (chip) + { + case PCI_CHIP_GD5462: + case PCI_CHIP_GD5464: + case PCI_CHIP_GD5464BD: + case PCI_CHIP_GD5465: + if (lg_loaded) + return LgAvailableOptions(chipid); + else + return NULL; + + default: + if (alp_loaded) + return AlpAvailableOptions(chipid); + else + return NULL; + } +} + +static Bool +CIRProbe(DriverPtr drv, int flags) +{ + int i; + GDevPtr *devSections; + pciVideoPtr pPci; + int *usedChips; + int numDevSections; + int numUsed; + Bool foundScreen = FALSE; + ScrnInfoPtr (*subProbe)(int entity); + ScrnInfoPtr pScrn; + +#ifdef CIR_DEBUG + ErrorF("CirProbe\n"); +#endif + + /* + * For PROBE_DETECT, make sure both sub-modules are loaded before + * calling xf86MatchPciInstances(), because the AvailableOptions() + * functions may be called before xf86MatchPciInstances() returns. + */ + + if (flags & PROBE_DETECT) { + if (!lg_loaded) { + if (xf86LoadDrvSubModule(drv, "cirrus_laguna")) { + xf86LoaderReqSymLists(lgSymbols, NULL); + lg_loaded = TRUE; + } + } + if (!alp_loaded) { + if (xf86LoadDrvSubModule(drv, "cirrus_alpine")) { + xf86LoaderReqSymLists(alpSymbols, NULL); + alp_loaded = TRUE; + } + } + } + + if ((numDevSections = xf86MatchDevice(CIR_DRIVER_NAME, + &devSections)) <= 0) { + return FALSE; + } + + if (xf86GetPciVideoInfo() == NULL) { + /* + * We won't let anything in the config file override finding no + * PCI video cards at all. This seems reasonable now, but we'll see. + */ + return FALSE; + } + + numUsed = xf86MatchPciInstances(CIR_NAME, PCI_VENDOR_CIRRUS, + CIRChipsets, CIRPciChipsets, devSections, + numDevSections, drv, &usedChips); + /* Free it since we don't need that list after this */ + xfree(devSections); + if (numUsed <= 0) + return FALSE; + if (flags & PROBE_DETECT) + foundScreen = TRUE; + else for (i = 0; i < numUsed; i++) { + /* The Laguna family of chips is so different from the Alpine + family that we won't share even the highest-level of + functions. But, the Laguna chips /are/ Cirrus chips, so + they should be handled in this driver (as opposed to their + own driver). */ + pPci = xf86GetPciInfoForEntity(usedChips[i]); + if (pPci->chipType == PCI_CHIP_GD5462 || + pPci->chipType == PCI_CHIP_GD5464 || + pPci->chipType == PCI_CHIP_GD5464BD || + pPci->chipType == PCI_CHIP_GD5465) { + + if (!lg_loaded) { + if (!xf86LoadDrvSubModule(drv, "cirrus_laguna")) + continue; + xf86LoaderReqSymLists(lgSymbols, NULL); + lg_loaded = TRUE; + } + subProbe = LgProbe; + } else { + if (!alp_loaded) { + if (!xf86LoadDrvSubModule(drv, "cirrus_alpine")) + continue; + xf86LoaderReqSymLists(alpSymbols, NULL); + alp_loaded = TRUE; + } + subProbe = AlpProbe; + } + pScrn = NULL; + + if ((pScrn = subProbe(usedChips[i]))) { + foundScreen = TRUE; + /* Fill in what we can of the ScrnInfoRec */ + pScrn->driverVersion = VERSION; + pScrn->driverName = CIR_DRIVER_NAME; + pScrn->name = CIR_NAME; + pScrn->Probe = NULL; + } + } + xfree(usedChips); + + return foundScreen; +} + +/* + * Map the framebuffer and MMIO memory. + */ + +Bool +CirMapMem(CirPtr pCir, int scrnIndex) +{ + int mmioFlags; + +#ifdef CIR_DEBUG + ErrorF("CirMapMem\n"); +#endif + + /* + * Map the frame buffer. + */ + if (pCir->FbMapSize) { + + pCir->FbBase = xf86MapPciMem(scrnIndex, VIDMEM_FRAMEBUFFER, + pCir->PciTag, pCir->FbAddress, + pCir->FbMapSize); + if (pCir->FbBase == NULL) + return FALSE; + } + +#ifdef CIR_DEBUG + ErrorF("CirMapMem pCir->FbBase=0x%08x\n", pCir->FbBase); +#endif + + /* + * Map IO registers to virtual address space + */ + if (pCir->IOAddress == 0) { + pCir->IOBase = NULL; /* Until we are ready to use MMIO */ + } else { + mmioFlags = VIDMEM_MMIO; + /* + * For Alpha, we need to map SPARSE memory, since we need + * byte/short access. Common-level will automatically use + * sparse mapping for MMIO. + */ + pCir->IOBase = + xf86MapPciMem(scrnIndex, mmioFlags, pCir->PciTag, + pCir->IOAddress, pCir->IoMapSize); + if (pCir->IOBase == NULL) + return FALSE; + } + +#ifdef CIR_DEBUG + ErrorF("CirMapMem pCir->IOBase=0x%08x [length=%08x] from PCI=%08x\n", + pCir->IOBase, pCir->IoMapSize, pCir->IOAddress); + ErrorF("MMIO[GR31] = %2X\n", (int) + ((volatile unsigned char*) pCir->IOBase)[0x40]); +#endif + + return TRUE; +} + + +/* + * Unmap the framebuffer and MMIO memory. + */ + +Bool +CirUnmapMem(CirPtr pCir, int scrnIndex) +{ +#ifdef CIR_DEBUG + ErrorF("CirUnmapMem\n"); +#endif + + if (pCir->IOBase != NULL) { + /* + * Unmap IO registers to virtual address space + */ + xf86UnMapVidMem(scrnIndex, (pointer)pCir->IOBase, pCir->IoMapSize); + pCir->IOBase = NULL; + } + + xf86UnMapVidMem(scrnIndex, (pointer)pCir->FbBase, pCir->FbMapSize); + pCir->FbBase = NULL; + return TRUE; +} + +void +cirProbeDDC(ScrnInfoPtr pScrn, int index) +{ + vbeInfoPtr pVbe; + + if (xf86LoadSubModule(pScrn, "vbe")) { + xf86LoaderReqSymLists(vbeSymbols,NULL); + pVbe = VBEInit(NULL,index); + ConfiguredMonitor = vbeDoEDID(pVbe, NULL); + vbeFree(pVbe); + } +} diff --git a/src/cir_shadow.c b/src/cir_shadow.c new file mode 100644 index 0000000..184dee8 --- /dev/null +++ b/src/cir_shadow.c @@ -0,0 +1,251 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/cirrus/cir_shadow.c,v 1.1 2000/02/08 13:13:14 eich Exp $ */ + +/* + Copyright (c) 1999,2000 The XFree86 Project Inc. + based on code written by Mark Vojkovich +*/ + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86Resources.h" +#include "xf86_ansic.h" +#include "xf86PciInfo.h" +#include "xf86Pci.h" +#include "shadowfb.h" +#include "servermd.h" +#include "cir.h" +#include "alp.h" + +void +cirRefreshArea(ScrnInfoPtr pScrn, int num, BoxPtr pbox) +{ + CirPtr pCir = CIRPTR(pScrn); + int width, height, Bpp, FBPitch; + unsigned char *src, *dst; + + Bpp = pScrn->bitsPerPixel >> 3; + FBPitch = BitmapBytePad(pScrn->displayWidth * pScrn->bitsPerPixel); + + while(num--) { + width = (pbox->x2 - pbox->x1) * Bpp; + height = pbox->y2 - pbox->y1; + src = pCir->ShadowPtr + (pbox->y1 * pCir->ShadowPitch) + + (pbox->x1 * Bpp); + dst = pCir->FbBase + (pbox->y1 * FBPitch) + (pbox->x1 * Bpp); + + while(height--) { + memcpy(dst, src, width); + dst += FBPitch; + src += pCir->ShadowPitch; + } + + pbox++; + } +} + +void +cirPointerMoved(int index, int x, int y) +{ + ScrnInfoPtr pScrn = xf86Screens[index]; + CirPtr pCir = CIRPTR(pScrn); + int newX, newY; + + if(pCir->rotate == 1) { + newX = pScrn->pScreen->height - y - 1; + newY = x; + } else { + newX = y; + newY = pScrn->pScreen->width - x - 1; + } + + (*pCir->PointerMoved)(index, newX, newY); +} + +void +cirRefreshArea8(ScrnInfoPtr pScrn, int num, BoxPtr pbox) +{ + CirPtr pCir = CIRPTR(pScrn); + int count, width, height, y1, y2, dstPitch, srcPitch; + CARD8 *dstPtr, *srcPtr, *src; + CARD32 *dst; + + dstPitch = pScrn->displayWidth; + srcPitch = -pCir->rotate * pCir->ShadowPitch; + + while(num--) { + width = pbox->x2 - pbox->x1; + y1 = pbox->y1 & ~3; + y2 = (pbox->y2 + 3) & ~3; + height = (y2 - y1) >> 2; /* in dwords */ + + if(pCir->rotate == 1) { + dstPtr = pCir->FbBase + + (pbox->x1 * dstPitch) + pScrn->virtualX - y2; + srcPtr = pCir->ShadowPtr + ((1 - y2) * srcPitch) + pbox->x1; + } else { + dstPtr = pCir->FbBase + + ((pScrn->virtualY - pbox->x2) * dstPitch) + y1; + srcPtr = pCir->ShadowPtr + (y1 * srcPitch) + pbox->x2 - 1; + } + + while(width--) { + src = srcPtr; + dst = (CARD32*)dstPtr; + count = height; + while(count--) { + *(dst++) = src[0] | (src[srcPitch] << 8) | + (src[srcPitch * 2] << 16) | + (src[srcPitch * 3] << 24); + src += srcPitch * 4; + } + srcPtr += pCir->rotate; + dstPtr += dstPitch; + } + + pbox++; + } +} + + +void +cirRefreshArea16(ScrnInfoPtr pScrn, int num, BoxPtr pbox) +{ + CirPtr pCir = CIRPTR(pScrn); + int count, width, height, y1, y2, dstPitch, srcPitch; + CARD16 *dstPtr, *srcPtr, *src; + CARD32 *dst; + + dstPitch = pScrn->displayWidth; + srcPitch = -pCir->rotate * pCir->ShadowPitch >> 1; + + while(num--) { + width = pbox->x2 - pbox->x1; + y1 = pbox->y1 & ~1; + y2 = (pbox->y2 + 1) & ~1; + height = (y2 - y1) >> 1; /* in dwords */ + + if(pCir->rotate == 1) { + dstPtr = (CARD16*)pCir->FbBase + + (pbox->x1 * dstPitch) + pScrn->virtualX - y2; + srcPtr = (CARD16*)pCir->ShadowPtr + + ((1 - y2) * srcPitch) + pbox->x1; + } else { + dstPtr = (CARD16*)pCir->FbBase + + ((pScrn->virtualY - pbox->x2) * dstPitch) + y1; + srcPtr = (CARD16*)pCir->ShadowPtr + + (y1 * srcPitch) + pbox->x2 - 1; + } + + while(width--) { + src = srcPtr; + dst = (CARD32*)dstPtr; + count = height; + while(count--) { + *(dst++) = src[0] | (src[srcPitch] << 16); + src += srcPitch * 2; + } + srcPtr += pCir->rotate; + dstPtr += dstPitch; + } + + pbox++; + } +} + + +/* this one could be faster */ +void +cirRefreshArea24(ScrnInfoPtr pScrn, int num, BoxPtr pbox) +{ + CirPtr pCir = CIRPTR(pScrn); + int count, width, height, y1, y2, dstPitch, srcPitch; + CARD8 *dstPtr, *srcPtr, *src; + CARD32 *dst; + + dstPitch = BitmapBytePad(pScrn->displayWidth * 24); + srcPitch = -pCir->rotate * pCir->ShadowPitch; + + while(num--) { + width = pbox->x2 - pbox->x1; + y1 = pbox->y1 & ~3; + y2 = (pbox->y2 + 3) & ~3; + height = (y2 - y1) >> 2; /* blocks of 3 dwords */ + + if(pCir->rotate == 1) { + dstPtr = pCir->FbBase + + (pbox->x1 * dstPitch) + ((pScrn->virtualX - y2) * 3); + srcPtr = pCir->ShadowPtr + ((1 - y2) * srcPitch) + (pbox->x1 * 3); + } else { + dstPtr = pCir->FbBase + + ((pScrn->virtualY - pbox->x2) * dstPitch) + (y1 * 3); + srcPtr = pCir->ShadowPtr + (y1 * srcPitch) + (pbox->x2 * 3) - 3; + } + + while(width--) { + src = srcPtr; + dst = (CARD32*)dstPtr; + count = height; + while(count--) { + dst[0] = src[0] | (src[1] << 8) | (src[2] << 16) | + (src[srcPitch] << 24); + dst[1] = src[srcPitch + 1] | (src[srcPitch + 2] << 8) | + (src[srcPitch * 2] << 16) | + (src[(srcPitch * 2) + 1] << 24); + dst[2] = src[(srcPitch * 2) + 2] | (src[srcPitch * 3] << 8) | + (src[(srcPitch * 3) + 1] << 16) | + (src[(srcPitch * 3) + 2] << 24); + dst += 3; + src += srcPitch * 4; + } + srcPtr += pCir->rotate * 3; + dstPtr += dstPitch; + } + + pbox++; + } +} + +void +cirRefreshArea32(ScrnInfoPtr pScrn, int num, BoxPtr pbox) +{ + CirPtr pCir = CIRPTR(pScrn); + int count, width, height, dstPitch, srcPitch; + CARD32 *dstPtr, *srcPtr, *src, *dst; + + dstPitch = pScrn->displayWidth; + srcPitch = -pCir->rotate * pCir->ShadowPitch >> 2; + + while(num--) { + width = pbox->x2 - pbox->x1; + height = pbox->y2 - pbox->y1; + + if(pCir->rotate == 1) { + dstPtr = (CARD32*)pCir->FbBase + + (pbox->x1 * dstPitch) + pScrn->virtualX - pbox->y2; + srcPtr = (CARD32*)pCir->ShadowPtr + + ((1 - pbox->y2) * srcPitch) + pbox->x1; + } else { + dstPtr = (CARD32*)pCir->FbBase + + ((pScrn->virtualY - pbox->x2) * dstPitch) + pbox->y1; + srcPtr = (CARD32*)pCir->ShadowPtr + + (pbox->y1 * srcPitch) + pbox->x2 - 1; + } + + while(width--) { + src = srcPtr; + dst = dstPtr; + count = height; + while(count--) { + *(dst++) = *src; + src += srcPitch; + } + srcPtr += pCir->rotate; + dstPtr += dstPitch; + } + + pbox++; + } +} + + + diff --git a/src/lg.h b/src/lg.h new file mode 100644 index 0000000..9d91053 --- /dev/null +++ b/src/lg.h @@ -0,0 +1,110 @@ +/* + * Common strutures and function for CL-GD546x -- The Laguna family + * + * lg.h + * + * (c) 1998 Corin Anderson. + * corina@the4cs.com + * Tukwila, WA + * + * Inspired by cir.h + */ + +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/cirrus/lg.h,v 1.12 2001/05/04 19:05:36 dawes Exp $ */ + +#ifndef LG_H +#define LG_H +#define LG_DEBUG + +extern ScrnInfoPtr LgProbe(int entity); +extern const OptionInfoRec * LgAvailableOptions(int chipid); + +# ifdef _LG_PRIVATE_ + +/* Saved registers that are not part of the core VGA */ +/* CRTC >= 0x19; Sequencer >= 0x05; Graphics >= 0x09; Attribute >= 0x15 */ + /* CR regs */ +enum { + /* CR regs */ + CR1A, + CR1B, + CR1D, + CR1E, + /* SR regs */ + SR07, + SR0E, + SR12, + SR13, + SR1E, + /* Must be last! */ + LG_LAST_REG +}; + +#undef FORMAT + +typedef struct { + unsigned char ExtVga[LG_LAST_REG]; + + /* Laguna regs */ + CARD8 TILE, BCLK; + CARD16 FORMAT, DTTC, TileCtrl, CONTROL; + CARD32 VSC; +} LgRegRec, *LgRegPtr; + +typedef struct { + int tilesPerLine; /* Number of tiles per line */ + int pitch; /* Display pitch, in bytes */ + int width; /* Tile width. 0 = 128 byte 1 = 256 byte */ +} LgLineDataRec, *LgLineDataPtr; + + +/* lg_driver.c */ +extern LgLineDataRec LgLineData[]; + +/* lg_xaa.c */ +extern Bool LgXAAInit(ScreenPtr pScreen); + +/* lg_hwcurs.c */ +extern Bool LgHWCursorInit(ScreenPtr pScreen); +extern void LgHideCursor(ScrnInfoPtr pScrn); +extern void LgShowCursor(ScrnInfoPtr pScrn); + +/* lg_i2c.c */ +extern Bool LgI2CInit(ScrnInfoPtr pScrn); + +#define memrb(off) MMIO_IN8(pCir->IOBase,off) +#define memrw(off) MMIO_IN16(pCir->IOBase,off) +#define memrl(off) MMIO_IN32(pCir->IOBase,off) +#define memwb(off,val) MMIO_OUT8(pCir->IOBase,off,val) +#define memww(off,val) MMIO_OUT16(pCir->IOBase,off,val) +#define memwl(off,val) MMIO_OUT32(pCir->IOBase,off,val) + +/* Card-specific driver information */ +#define LGPTR(p) ((LgPtr)((p)->chip.lg)) + +typedef struct lgRec { + CARD32 HWCursorAddr; + int HWCursorImageX; + int HWCursorImageY; + int HWCursorTileWidth; + int HWCursorTileHeight; + + int lineDataIndex; + + int memInterleave; + + LgRegRec SavedReg; + LgRegRec ModeReg; + + CARD32 oldBitmask; + Bool blitTransparent; + int blitYDir; +} LgRec, *LgPtr; + +# endif /* _LG_PRIVATE_ */ +#endif /* LG_H */ + + + + + diff --git a/src/lg_driver.c b/src/lg_driver.c new file mode 100644 index 0000000..2f63143 --- /dev/null +++ b/src/lg_driver.c @@ -0,0 +1,1877 @@ +/* + * Driver for CL-GD546x -- The Laguna family + * + * lg_driver.c + * + * (c) 1998 Corin Anderson. + * corina@the4cs.com + * Tukwila, WA + * + * This driver is derived from the cir_driver.c module. + * Original authors and contributors list include: + * Radoslaw Kapitan, Andrew Vanderstock, Dirk Hohndel, + * David Dawes, Andrew E. Mileski, Leonard N. Zubkoff, + * Guy DESBIEF, Itai Nahshon. + */ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/cirrus/lg_driver.c,v 1.43 2002/07/24 01:47:27 tsi Exp $ */ + +#define EXPERIMENTAL + +/* All drivers should typically include these */ +#include "xf86.h" +#include "xf86_OSproc.h" + +/* All drivers need this */ +#include "xf86_ansic.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" + +/* All drivers using the vgahw module need this */ +/* This driver needs to be modified to not use vgaHW for multihead operation */ +#include "vgaHW.h" + +#include "xf86RAC.h" +#include "xf86Resources.h" + +/* All drivers initialising the SW cursor need this */ +#include "mipointer.h" + +/* All drivers implementing backing store need this */ +#include "mibstore.h" + +#include "micmap.h" + +/* Needed by the Shadow Framebuffer */ +#include "shadowfb.h" + +#include "xf86int10.h" + +#include "fb.h" + +#include "xf86DDC.h" + +#undef LG_DEBUG + +#include "cir.h" +#define _LG_PRIVATE_ +#include "lg.h" + +#ifdef XvExtension +#include "xf86xv.h" +#include "Xv.h" +#endif + +/* + * Forward definitions for the functions that make up the driver. + */ + +/* Mandatory functions */ +Bool LgPreInit(ScrnInfoPtr pScrn, int flags); +Bool LgScreenInit(int Index, ScreenPtr pScreen, int argc, char **argv); +Bool LgEnterVT(int scrnIndex, int flags); +void LgLeaveVT(int scrnIndex, int flags); +static Bool LgCloseScreen(int scrnIndex, ScreenPtr pScreen); +static Bool LgSaveScreen(ScreenPtr pScreen, Bool mode); + +/* Required if the driver supports mode switching */ +Bool LgSwitchMode(int scrnIndex, DisplayModePtr mode, int flags); +/* Required if the driver supports moving the viewport */ +void LgAdjustFrame(int scrnIndex, int x, int y, int flags); + +/* Optional functions */ +void LgFreeScreen(int scrnIndex, int flags); +int LgValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags); + +/* Internally used functions */ +static void LgRestoreLgRegs(ScrnInfoPtr pScrn, LgRegPtr lgReg); +static int LgFindLineData(int displayWidth, int bpp); +static CARD16 LgSetClock(CirPtr pCir, vgaHWPtr hwp, int freq); +static void lg_vgaHWSetMmioFunc(vgaHWPtr hwp, CARD8 *base); + +static void LgDisplayPowerManagementSet(ScrnInfoPtr pScrn, + int PowerManagementMode, int flags); + +/* + * This is intentionally screen-independent. It indicates the binding + * choice made in the first PreInit. + */ +static int pix24bpp = 0; + +/* + * This contains the functions needed by the server after loading the + * driver module. It must be supplied, and gets added the driver list by + * the Module Setup funtion 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. + */ + +typedef enum { + OPTION_HW_CURSOR, + OPTION_PCI_RETRY, + OPTION_ROTATE, + OPTION_SHADOW_FB, + OPTION_NOACCEL +} LgOpts; + +static const OptionInfoRec LgOptions[] = { + { OPTION_HW_CURSOR, "HWcursor", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_SHADOW_FB, "ShadowFB", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_ROTATE, "Rotate", OPTV_ANYSTR, {0}, FALSE }, + /* fifo_conservative/aggressive; fast/med/slow_dram; ... */ + { -1, NULL, OPTV_NONE, {0}, FALSE } +}; + + +/* 1/4bpp 8bpp 15/16bpp 24bpp 32bpp */ +static int gd5462_MaxClocks[] = { 170000, 170000, 135100, 135100, 85500 }; +static int gd5464_MaxClocks[] = { 170000, 250000, 170000, 170000, 135100 }; +static int gd5465_MaxClocks[] = { 170000, 250000, 170000, 170000, 135100 }; + +LgLineDataRec LgLineData[] = { + { 5, 640, 0}, /* We're rather use skinny tiles, so put all of */ + { 8, 1024, 0}, /* them at the head of the table */ + {10, 1280, 0}, + {13, 1664, 0}, + {16, 2048, 0}, + {20, 2560, 0}, + {10, 2560, 1}, + {26, 3328, 0}, + { 5, 1280, 1}, + { 8, 2048, 1}, + {13, 3328, 1}, + {16, 4096, 1}, + {20, 5120, 1}, + {26, 6656, 1}, + {-1, -1, -1} /* Sentinal to indicate end of table */ +}; + +static int LgLinePitches[4][11] = { + /* 8 */ { 640, 1024, 1280, 1664, 2048, 2560, 3328, 4096, 5120, 6656, 0 }, + /* 16 */ { 320, 512, 640, 832, 1024, 1280, 1664, 2048, 2560, 3328, 0 }, + /* 24 */ { 213, 341, 426, 554, 682, 853, 1109, 1365, 1706, 2218, 0 }, + /* 32 */ { 160, 256, 320, 416, 512, 640, 832, 1024, 1280, 1664, 0 } +}; + +/* + * 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[] = { + "vgaHWFreeHWRec", + "vgaHWGetHWRec", + "vgaHWGetIOBase", + "vgaHWGetIndex", + "vgaHWHandleColormaps", + "vgaHWInit", + "vgaHWLock", + "vgaHWMapMem", + "vgaHWProtect", + "vgaHWRestore", + "vgaHWSave", + "vgaHWSaveScreen", + "vgaHWUnlock", + NULL +}; + +static const char *fbSymbols[] = { + "fbScreenInit", + "fbPictureInit", + NULL +}; + +static const char *xaaSymbols[] = { + "XAACreateInfoRec", + "XAADestroyInfoRec", + "XAAInit", + NULL +}; + +static const char *ramdacSymbols[] = { + "xf86CreateCursorInfoRec", + "xf86DestroyCursorInfoRec", + "xf86InitCursor", + NULL +}; + +#define LGuseI2C 1 + +static const char *ddcSymbols[] = { + "xf86PrintEDID", +#if LGuseI2C + "xf86DoEDID_DDC2", +#endif + "xf86SetDDCproperties", + NULL +}; + +static const char *i2cSymbols[] = { + "xf86CreateI2CBusRec", + "xf86I2CBusInit", + NULL +}; + +static const char *int10Symbols[] = { + "xf86FreeInt10", + "xf86InitInt10", + NULL +}; + +static const char *shadowSymbols[] = { + "ShadowFBInit", + NULL +}; + +#ifdef XFree86LOADER + +#define LG_MAJOR_VERSION 1 +#define LG_MINOR_VERSION 0 +#define LG_PATCHLEVEL 0 + +static MODULESETUPPROTO(lgSetup); + +static XF86ModuleVersionInfo lgVersRec = +{ + "cirrus_laguna", + MODULEVENDORSTRING, + MODINFOSTRING1, + MODINFOSTRING2, + XF86_VERSION_CURRENT, + LG_MAJOR_VERSION, LG_MINOR_VERSION, LG_PATCHLEVEL, + ABI_CLASS_VIDEODRV, /* This is a video driver */ + ABI_VIDEODRV_VERSION, + MOD_CLASS_NONE, + {0,0,0,0} +}; + +/* + * This is the module init data. + * Its name has to be the driver name followed by ModuleData. + */ +XF86ModuleData cirrus_lagunaModuleData = { &lgVersRec, lgSetup, NULL }; + +static pointer +lgSetup(pointer module, pointer opts, int *errmaj, int *errmin) +{ + static Bool setupDone = FALSE; + + if (!setupDone) { + setupDone = TRUE; + LoaderRefSymLists(vgahwSymbols, fbSymbols, xaaSymbols, + ramdacSymbols, ddcSymbols, i2cSymbols, + int10Symbols, NULL); + } + return (pointer)1; +} + +#endif /* XFree86LOADER */ + +const OptionInfoRec * +LgAvailableOptions(int chipid) +{ + return LgOptions; +} + +ScrnInfoPtr +LgProbe(int entity) +{ + ScrnInfoPtr pScrn = NULL; + if ((pScrn = xf86ConfigPciEntity(pScrn, 0, entity, CIRPciChipsets, + NULL, NULL, NULL, NULL, NULL))) { + pScrn->PreInit = LgPreInit; + pScrn->ScreenInit = LgScreenInit; + pScrn->SwitchMode = LgSwitchMode; + pScrn->AdjustFrame = LgAdjustFrame; + pScrn->EnterVT = LgEnterVT; + pScrn->LeaveVT = LgLeaveVT; + pScrn->FreeScreen = LgFreeScreen; + pScrn->ValidMode = LgValidMode; + } + return pScrn; +} + + +static Bool +LgGetRec(ScrnInfoPtr pScrn) +{ + CirPtr pCir; + + if (pScrn->driverPrivate != NULL) + return TRUE; + + pScrn->driverPrivate = xnfcalloc(sizeof(CirRec), 1); + ((CirPtr)pScrn->driverPrivate)->chip.lg = xnfcalloc(sizeof(LgRec),1); + + /* Initialize it */ + pCir = CIRPTR(pScrn); + pCir->chip.lg->oldBitmask = 0x00000000; + + return TRUE; +} + +static void +LgFreeRec(ScrnInfoPtr pScrn) +{ + if (pScrn->driverPrivate == NULL) + return; + xfree(pScrn->driverPrivate); + pScrn->driverPrivate = NULL; +} + + + +/* + * LgCountRAM -- + * + * Counts amount of installed RAM + */ + +/* XXX We need to get rid of this PIO (MArk) */ +static int +LgCountRam(ScrnInfoPtr pScrn) +{ + vgaHWPtr hwp = VGAHWPTR(pScrn); + CARD8 SR14; + + vgaHWProtect(pScrn, TRUE); + + /* The ROM BIOS scratchpad registers contain, + among other things, the amount of installed + RDRAM on the laguna chip. */ + SR14 = hwp->readSeq(hwp, 0x14); + + ErrorF("Scratch Pads: 0:%02x 1:%02x 2:%02x 3:%02x\n", + hwp->readSeq(hwp, 9), hwp->readSeq(hwp, 10), + SR14, hwp->readSeq(hwp, 0x15)); + + vgaHWProtect(pScrn, FALSE); + + return 1024 * ((SR14&0x7) + 1); + + /* !!! This function seems to be incorrect... */ +} + +static xf86MonPtr +LgDoDDC(ScrnInfoPtr pScrn) +{ + CirPtr pCir = CIRPTR(pScrn); + xf86MonPtr MonInfo = NULL; + + /* Map the CIR memory and MMIO areas */ + if (!CirMapMem(pCir, pScrn->scrnIndex)) + return FALSE; + + { + ErrorF("RIF Control %#04x, RAC Control %#04x\n", + memrw(0x200), memrw(0x201)); + } +#if LGuseI2C + if (!LgI2CInit(pScrn)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "I2C initialization failed\n"); + + goto unmap_out; + } + + /* Read and output monitor info using DDC2 over I2C bus */ + MonInfo = xf86DoEDID_DDC2(pScrn->scrnIndex, pCir->I2CPtr1); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "I2C Monitor info: %p\n", MonInfo); + xf86PrintEDID(MonInfo); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "end of I2C Monitor info\n\n"); +#endif /* LGuseI2C */ + + xf86SetDDCproperties(pScrn, MonInfo); + +unmap_out: + CirUnmapMem(pCir, pScrn->scrnIndex); + + return MonInfo; +} + +/* Mandatory */ +Bool +LgPreInit(ScrnInfoPtr pScrn, int flags) +{ + CirPtr pCir; + vgaHWPtr hwp; + MessageType from; + int i; + ClockRangePtr clockRanges; + int fbPCIReg, ioPCIReg; + char *s; + + if (flags & PROBE_DETECT) { + cirProbeDDC( pScrn, xf86GetEntityInfo(pScrn->entityList[0])->index ); + return TRUE; + } + +#ifdef LG_DEBUG + ErrorF("LgPreInit\n"); +#endif + + /* Check the number of entities, and fail if it isn't one. */ + if (pScrn->numEntities != 1) + return FALSE; + + /* The vgahw module should be loaded here when needed */ + if (!xf86LoadSubModule(pScrn, "vgahw")) + return FALSE; + + xf86LoaderReqSymLists(vgahwSymbols, NULL); + + /* + * Allocate a vgaHWRec + */ + if (!vgaHWGetHWRec(pScrn)) + return FALSE; + + hwp = VGAHWPTR(pScrn); + vgaHWGetIOBase(hwp); + + /* Allocate the LgRec driverPrivate */ + if (!LgGetRec(pScrn)) + return FALSE; + + pCir = CIRPTR(pScrn); + pCir->pScrn = pScrn; + pCir->PIOReg = hwp->PIOOffset + 0x3CE; + + /* Get the entity, and make sure it is PCI. */ + pCir->pEnt = xf86GetEntityInfo(pScrn->entityList[0]); + if (pCir->pEnt->location.type != BUS_PCI) + return FALSE; + pCir->Chipset = pCir->pEnt->chipset; + + /* Find the PCI info for this screen */ + pCir->PciInfo = xf86GetPciInfoForEntity(pCir->pEnt->index); + pCir->PciTag = pciTag(pCir->PciInfo->bus, + pCir->PciInfo->device, + pCir->PciInfo->func); + + if (xf86LoadSubModule(pScrn, "int10")) { + xf86Int10InfoPtr int10InfoPtr; + xf86LoaderReqSymLists(int10Symbols, NULL); + + int10InfoPtr = xf86InitInt10(pCir->pEnt->index); + + if (int10InfoPtr) + xf86FreeInt10(int10InfoPtr); + } + + /* Set pScrn->monitor */ + pScrn->monitor = pScrn->confScreen->monitor; + + /* + * The first thing we should figure out is the depth, bpp, etc. + * Our default depth is 8, so pass it to the helper function. + * We support both 24bpp and 32bpp layouts, so indicate that. + */ + if (!xf86SetDepthBpp(pScrn, 8, 8, 8, Support24bppFb | Support32bppFb | + SupportConvert32to24 | PreferConvert32to24)) { + return FALSE; + } + /* Check that the returned depth is one we support */ + switch (pScrn->depth) { + 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); + + /* + * 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}; + + /* !!! I think we can force 5-6-5 weight for 16bpp here for + the 5462. */ + + if (!xf86SetWeight(pScrn, zeros, zeros)) { + return FALSE; + } else { + /* XXX check that weight returned is supported */ + ; + } + } + + if (!xf86SetDefaultVisual(pScrn, -1)) + return FALSE; + + + /* Collect all of the relevant option flags (fill in pScrn->options) */ + xf86CollectOptions(pScrn, NULL); + + /* Process the options */ + if (!(pCir->Options = xalloc(sizeof(LgOptions)))) + return FALSE; + memcpy(pCir->Options, LgOptions, sizeof(LgOptions)); + xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pCir->Options); + + pScrn->rgbBits = 6; + from = X_DEFAULT; + pCir->HWCursor = FALSE; + if (xf86GetOptValBool(pCir->Options, OPTION_HW_CURSOR, &pCir->HWCursor)) + from = X_CONFIG; + + xf86DrvMsg(pScrn->scrnIndex, from, "Using %s cursor\n", + pCir->HWCursor ? "HW" : "SW"); + if (xf86ReturnOptValBool(pCir->Options, OPTION_NOACCEL, FALSE)) { + pCir->NoAccel = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Acceleration disabled\n"); + } + if (pScrn->bitsPerPixel < 8) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Cannot use in less than 8 bpp\n"); + return FALSE; + } + /* + * Set the ChipRev, allowing config file entries to + * override. + */ + if (pCir->pEnt->device->chipRev >= 0) { + pCir->ChipRev = pCir->pEnt->device->chipRev; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n", + pCir->ChipRev); + } else { + pCir->ChipRev = pCir->PciInfo->chipRev; + } + + /* Cirrus swapped the FB and IO registers in the 5465 (by design). */ + if (PCI_CHIP_GD5465 == pCir->Chipset) { + fbPCIReg = 0; + ioPCIReg = 1; + } else { + fbPCIReg = 1; + ioPCIReg = 0; + } + + /* Find the frame buffer base address */ + if (pCir->pEnt->device->MemBase != 0) { + /* Require that the config file value matches one of the PCI values. */ + if (!xf86CheckPciMemBase(pCir->PciInfo, pCir->pEnt->device->MemBase)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "MemBase 0x%08lX doesn't match any PCI base register.\n", + pCir->pEnt->device->MemBase); + return FALSE; + } + pCir->FbAddress = pCir->pEnt->device->MemBase; + from = X_CONFIG; + } else { + if (pCir->PciInfo->memBase[fbPCIReg] != 0) { + pCir->FbAddress = pCir->PciInfo->memBase[fbPCIReg] & 0xff000000; + from = X_PROBED; + } else { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "No valid FB address in PCI config space\n"); + LgFreeRec(pScrn); + return FALSE; + } + } + xf86DrvMsg(pScrn->scrnIndex, from, "Linear framebuffer at 0x%lX\n", + (unsigned long)pCir->FbAddress); + + /* Find the MMIO base address */ + if (pCir->pEnt->device->IOBase != 0) { + /* Require that the config file value matches one of the PCI values. */ + if (!xf86CheckPciMemBase(pCir->PciInfo, pCir->pEnt->device->IOBase)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "IOBase 0x%08lX doesn't match any PCI base register.\n", + pCir->pEnt->device->IOBase); + return FALSE; + } + pCir->IOAddress = pCir->pEnt->device->IOBase; + from = X_CONFIG; + } else { + if (pCir->PciInfo->memBase[ioPCIReg] != 0) { + pCir->IOAddress = pCir->PciInfo->memBase[ioPCIReg] & 0xfffff000; + from = X_PROBED; + } else { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "No valid MMIO address in PCI config space\n"); + } + } + xf86DrvMsg(pScrn->scrnIndex, from, "MMIO registers at 0x%lX\n", + (unsigned long)pCir->IOAddress); + + /* + * If the user has specified the amount of memory in the XF86Config + * file, we respect that setting. + */ + if (pCir->pEnt->device->videoRam != 0) { + pScrn->videoRam = pCir->pEnt->device->videoRam; + from = X_CONFIG; + } else { + pScrn->videoRam = LgCountRam(pScrn); + from = X_PROBED; + } + if (2048 == pScrn->videoRam) { + /* Two-way interleaving */ + pCir->chip.lg->memInterleave = 0x40; + } else if (4096 == pScrn->videoRam || 8192 == pScrn->videoRam) { + /* Four-way interleaving */ + pCir->chip.lg->memInterleave = 0x80; + } else { + /* One-way interleaving */ + pCir->chip.lg->memInterleave = 0x00; + } + + xf86DrvMsg(pScrn->scrnIndex, from, "VideoRAM: %d kByte\n", + pScrn->videoRam); + + pCir->FbMapSize = pScrn->videoRam * 1024; + pCir->IoMapSize = 0x4000; /* 16K for moment, will increase */ + + pScrn->racIoFlags = RAC_COLORMAP +#ifndef EXPERIMENTAL + | RAC_VIEWPORT +#endif +; + xf86SetOperatingState(resVgaMem, pCir->pEnt->index, ResUnusedOpr); + + /* Register the PCI-assigned resources. */ + if (xf86RegisterResources(pCir->pEnt->index, NULL, ResExclusive)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "xf86RegisterResources() found resource conflicts\n"); + return FALSE; + } + + if (!xf86LoadSubModule(pScrn, "ddc")) { + LgFreeRec(pScrn); + return FALSE; + } + xf86LoaderReqSymLists(ddcSymbols, NULL); + +#if LGuseI2C + if (!xf86LoadSubModule(pScrn, "i2c")) { + LgFreeRec(pScrn); + return FALSE; + } + xf86LoaderReqSymLists(i2cSymbols, NULL); +#endif + + /* Read and print the monitor DDC information */ + pScrn->monitor->DDC = LgDoDDC(pScrn); + + /* 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; + } + if (xf86GetOptValBool(pCir->Options, + OPTION_SHADOW_FB,&pCir->shadowFB)) + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ShadowFB %s.\n", + pCir->shadowFB ? "enabled" : "disabled"); + + if ((s = xf86GetOptValString(pCir->Options, OPTION_ROTATE))) { + if(!xf86NameCmp(s, "CW")) { + /* accel is disabled below for shadowFB */ + pCir->shadowFB = TRUE; + pCir->rotate = 1; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "Rotating screen clockwise - acceleration disabled\n"); + } else if(!xf86NameCmp(s, "CCW")) { + pCir->shadowFB = TRUE; + pCir->rotate = -1; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Rotating screen" + "counter clockwise - acceleration disabled\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"); + } + } + + if (pCir->shadowFB && !pCir->NoAccel) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "HW acceleration not supported with \"shadowFB\".\n"); + pCir->NoAccel = TRUE; + } + + if (pCir->rotate && pCir->HWCursor) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "HW cursor not supported with \"rotate\".\n"); + pCir->HWCursor = FALSE; + } + + /* We use a programmable clock */ + pScrn->progClock = TRUE; + + /* XXX Set HW cursor use */ + + /* Set the min pixel clock */ + pCir->MinClock = 12000; /* XXX Guess, need to check this */ + xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "Min pixel clock is %d MHz\n", + pCir->MinClock / 1000); + /* + * If the user has specified ramdac speed in the XF86Config + * file, we respect that setting. + */ + if (pCir->pEnt->device->dacSpeeds[0]) { + ErrorF("Do not specify a Clocks line for Cirrus chips\n"); + return FALSE; + } else { + int speed; + int *p; + switch (pCir->Chipset) { + case PCI_CHIP_GD5462: + p = gd5462_MaxClocks; + break; + case PCI_CHIP_GD5464: + case PCI_CHIP_GD5464BD: + p = gd5464_MaxClocks; + break; + case PCI_CHIP_GD5465: + p = gd5465_MaxClocks; + break; + default: + ErrorF("???\n"); + return FALSE; + } + switch (pScrn->bitsPerPixel) { + case 8: + speed = p[1]; + break; + case 15: + case 16: + speed = p[2]; + break; + case 24: + speed = p[3]; + break; + case 32: + speed = p[4]; + break; + default: + /* Should not get here */ + speed = 0; + break; + } + pCir->MaxClock = speed; + from = X_PROBED; + } + xf86DrvMsg(pScrn->scrnIndex, from, "Max pixel clock is %d MHz\n", + pCir->MaxClock / 1000); + + /* + * 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->minClock = pCir->MinClock; + clockRanges->maxClock = pCir->MaxClock; + clockRanges->clockIndex = -1; /* programmable */ + clockRanges->interlaceAllowed = FALSE; /* XXX check this */ + clockRanges->doubleScanAllowed = FALSE; /* XXX check this */ + clockRanges->doubleScanAllowed = FALSE; /* XXX check this */ + clockRanges->doubleScanAllowed = FALSE; /* XXX check this */ + clockRanges->ClockMulFactor = 1; + clockRanges->ClockDivFactor = 1; + clockRanges->PrivFlags = 0; + + /* Depending upon what sized tiles used, either 128 or 256. */ + /* Aw, heck. Just say 128. */ + pCir->Rounding = 128 >> pCir->BppShift; + + /* + * xf86ValidateModes will check that the mode HTotal and VTotal values + * don't exceed the chipset's limit if pScrn->maxHValue and + * pScrn->maxVValue are set. Since our CIRValidMode() already takes + * care of this, we don't worry about setting them here. + */ + + i = xf86ValidateModes(pScrn, pScrn->monitor->Modes, pScrn->display->modes, + clockRanges, + LgLinePitches[pScrn->bitsPerPixel / 8 - 1], + 0, 0, 128 * 8, + 0, 0, /* Any virtual height is allowed. */ + pScrn->display->virtualX, + pScrn->display->virtualY, + pCir->FbMapSize, + LOOKUP_BEST_REFRESH); + + pCir->chip.lg->lineDataIndex = LgFindLineData(pScrn->displayWidth, + pScrn->bitsPerPixel); + + if (i == -1) { + LgFreeRec(pScrn); + return FALSE; + } + + /* Prune the modes marked as invalid */ + xf86PruneDriverModes(pScrn); + + if (i == 0 || pScrn->modes == NULL) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n"); + LgFreeRec(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); + + /* Set display resolution */ + xf86SetDpi(pScrn, 0, 0); + + /* Load bpp-specific modules */ + switch (pScrn->bitsPerPixel) { + case 8: + case 16: + case 24: + case 32: + if (xf86LoadSubModule(pScrn, "fb") == NULL) { + LgFreeRec(pScrn); + return FALSE; + } + xf86LoaderReqSymLists(fbSymbols, NULL); + break; + } + + /* Load XAA if needed */ + if (!pCir->NoAccel) { + if (!xf86LoadSubModule(pScrn, "xaa")) { + LgFreeRec(pScrn); + return FALSE; + } + xf86LoaderReqSymLists(xaaSymbols, NULL); + } + + /* Load ramdac if needed */ + if (pCir->HWCursor) { + if (!xf86LoadSubModule(pScrn, "ramdac")) { + LgFreeRec(pScrn); + return FALSE; + } + xf86LoaderReqSymLists(ramdacSymbols, NULL); + } + + if (pCir->shadowFB) { + if (!xf86LoadSubModule(pScrn, "shadowfb")) { + LgFreeRec(pScrn); + return FALSE; + } + xf86LoaderReqSymLists(shadowSymbols, NULL); + } + + return TRUE; +} + +/* + * This function saves the video state. + */ +static void +LgSave(ScrnInfoPtr pScrn) +{ + CirPtr pCir = CIRPTR(pScrn); + vgaHWPtr hwp = VGAHWPTR(pScrn); + +#ifdef LG_DEBUG + ErrorF("LgSave\n"); +#endif + + vgaHWSave(pScrn, &VGAHWPTR(pScrn)->SavedReg, VGA_SR_ALL); + + pCir->chip.lg->ModeReg.ExtVga[CR1A] = pCir->chip.lg->SavedReg.ExtVga[CR1A] = hwp->readCrtc(hwp, 0x1A); + pCir->chip.lg->ModeReg.ExtVga[CR1B] = pCir->chip.lg->SavedReg.ExtVga[CR1B] = hwp->readCrtc(hwp, 0x1B); + pCir->chip.lg->ModeReg.ExtVga[CR1D] = pCir->chip.lg->SavedReg.ExtVga[CR1D] = hwp->readCrtc(hwp, 0x1D); + pCir->chip.lg->ModeReg.ExtVga[CR1E] = pCir->chip.lg->SavedReg.ExtVga[CR1E] = hwp->readCrtc(hwp, 0x1E); + pCir->chip.lg->ModeReg.ExtVga[SR07] = pCir->chip.lg->SavedReg.ExtVga[SR07] = hwp->readSeq(hwp, 0x07); + pCir->chip.lg->ModeReg.ExtVga[SR0E] = pCir->chip.lg->SavedReg.ExtVga[SR0E] = hwp->readSeq(hwp, 0x0E); + pCir->chip.lg->ModeReg.ExtVga[SR12] = pCir->chip.lg->SavedReg.ExtVga[SR12] = hwp->readSeq(hwp, 0x12); + pCir->chip.lg->ModeReg.ExtVga[SR13] = pCir->chip.lg->SavedReg.ExtVga[SR13] = hwp->readSeq(hwp, 0x13); + pCir->chip.lg->ModeReg.ExtVga[SR1E] = pCir->chip.lg->SavedReg.ExtVga[SR1E] = hwp->readSeq(hwp, 0x1E); + + pCir->chip.lg->ModeReg.FORMAT = pCir->chip.lg->SavedReg.FORMAT = memrw(0xC0); + + pCir->chip.lg->ModeReg.VSC = pCir->chip.lg->SavedReg.VSC = memrl(0x3FC); + + pCir->chip.lg->ModeReg.DTTC = pCir->chip.lg->SavedReg.DTTC = memrw(0xEA); + + if (pCir->Chipset == PCI_CHIP_GD5465) { + pCir->chip.lg->ModeReg.TileCtrl = pCir->chip.lg->SavedReg.TileCtrl = memrw(0x2C4); + } + + pCir->chip.lg->ModeReg.TILE = pCir->chip.lg->SavedReg.TILE = memrb(0x407); + + if (pCir->Chipset == PCI_CHIP_GD5465) + pCir->chip.lg->ModeReg.BCLK = pCir->chip.lg->SavedReg.BCLK = memrb(0x2C0); + else + pCir->chip.lg->ModeReg.BCLK = pCir->chip.lg->SavedReg.BCLK = memrb(0x8C); + + pCir->chip.lg->ModeReg.CONTROL = pCir->chip.lg->SavedReg.CONTROL = memrw(0x402); +} + +/* + * Initialise a new mode. This is currently still using the old + * "initialise struct, restore/write struct to HW" model. That could + * be changed. + */ + +static Bool +LgModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode) +{ + vgaHWPtr hwp; + vgaRegPtr vgaReg; + CirPtr pCir; + int width; + Bool VDiv2 = FALSE; + CARD16 clockData; + LgLineDataPtr lineData; + +#ifdef LG_DEBUG + ErrorF("LgModeInit %d bpp, %d %d %d %d %d %d %d %d %d\n", + pScrn->bitsPerPixel, + mode->Clock, + mode->HDisplay, + mode->HSyncStart, + mode->HSyncEnd, + mode->HTotal, + mode->VDisplay, + mode->VSyncStart, + mode->VSyncEnd, + mode->VTotal); + + ErrorF("LgModeInit: depth %d bits\n", pScrn->depth); +#endif + + pCir = CIRPTR(pScrn); + hwp = VGAHWPTR(pScrn); + vgaHWUnlock(hwp); + + if (mode->VTotal >= 1024 && !(mode->Flags & V_INTERLACE)) { + /* For non-interlaced vertical timing >= 1024, the vertical timings */ + /* are divided by 2 and VGA CRTC 0x17 bit 2 is set. */ + if (!mode->CrtcVAdjusted) { + mode->CrtcVDisplay >>= 1; + mode->CrtcVSyncStart >>= 1; + mode->CrtcVSyncEnd >>= 1; + mode->CrtcVTotal >>= 1; + mode->CrtcVAdjusted = TRUE; + } + VDiv2 = TRUE; + } + + /* Initialise the ModeReg values */ + if (!vgaHWInit(pScrn, mode)) + return FALSE; + pScrn->vtSema = TRUE; + + if (VDiv2) + hwp->ModeReg.CRTC[0x17] |= 0x04; + +#ifdef LG_DEBUG + ErrorF("SynthClock = %d\n", mode->SynthClock); +#endif + vgaReg = &hwp->ModeReg; + + hwp->IOBase = 0x3D0; + hwp->ModeReg.MiscOutReg |= 0x01; +#if 0 /* Mono address */ + hwp->IOBase = 0x3B0; + hwp->ModeReg.MiscOutReg &= ~0x01; +#endif + + + /* ??? Should these be both ...End or ...Start, not one of each? */ + pCir->chip.lg->ModeReg.ExtVga[CR1A] = (((mode->CrtcVSyncStart + 1) & 0x300 ) >> 2) + | (((mode->CrtcHSyncEnd >> 3) & 0xC0) >> 2); + + width = pScrn->displayWidth * pScrn->bitsPerPixel / 8; + if (pScrn->bitsPerPixel == 1) + width <<= 2; + hwp->ModeReg.CRTC[0x13] = (width + 7) >> 3; + /* Offset extension (see CR13) */ + pCir->chip.lg->ModeReg.ExtVga[CR1B] &= 0xEF; + pCir->chip.lg->ModeReg.ExtVga[CR1B] |= (((width + 7) >> 3) & 0x100)?0x10:0x00; + pCir->chip.lg->ModeReg.ExtVga[CR1B] |= 0x22; + pCir->chip.lg->ModeReg.ExtVga[CR1D] = (((width + 7) >> 3) & 0x200)?0x01:0x00; + + /* Set the 28th bit to enable extended modes. */ + pCir->chip.lg->ModeReg.VSC = 0x10000000; + + /* Overflow register (sure are a lot of overflow bits around...) */ + pCir->chip.lg->ModeReg.ExtVga[CR1E] = 0x00; + pCir->chip.lg->ModeReg.ExtVga[CR1E] |= ((mode->CrtcHTotal>>3 & 0x0100)?1:0)<<7; + pCir->chip.lg->ModeReg.ExtVga[CR1E] |= ((mode->CrtcHDisplay>>3 & 0x0100)?1:0)<<6; + pCir->chip.lg->ModeReg.ExtVga[CR1E] |= ((mode->CrtcHSyncStart>>3 & 0x0100)?1:0)<<5; + pCir->chip.lg->ModeReg.ExtVga[CR1E] |= ((mode->CrtcHSyncStart>>3 & 0x0100)?1:0)<<4; + pCir->chip.lg->ModeReg.ExtVga[CR1E] |= ((mode->CrtcVTotal & 0x0400)?1:0)<<3; + pCir->chip.lg->ModeReg.ExtVga[CR1E] |= ((mode->CrtcVDisplay & 0x0400)?1:0)<<2; + pCir->chip.lg->ModeReg.ExtVga[CR1E] |= ((mode->CrtcVSyncStart & 0x0400)?1:0)<<1; + pCir->chip.lg->ModeReg.ExtVga[CR1E] |= ((mode->CrtcVSyncStart & 0x0400)?1:0)<<0; + + lineData = &LgLineData[pCir->chip.lg->lineDataIndex]; + + pCir->chip.lg->ModeReg.TILE = lineData->tilesPerLine & 0x3F; + + if (8 == pScrn->bitsPerPixel) { + pCir->chip.lg->ModeReg.FORMAT = 0x0000; + + pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.TILE << 8) | 0x0080 + | (lineData->width << 6); + pCir->chip.lg->ModeReg.CONTROL = 0x0000 | (lineData->width << 11); + + + /* There is an optimal FIFO threshold value (lower 5 bits of DTTC) + for every resolution and color depth combination. We'll hit + the highlights here, and get close for anything that's not + covered. */ + if (mode->CrtcHDisplay <= 640) { + /* BAD numbers: 0x1E */ + /* GOOD numbers: 0x14 */ + pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) | (0x0014); + } else if (mode->CrtcHDisplay <= 800) { + /* BAD numbers: 0x16 */ + /* GOOD numbers: 0x13 0x14 */ + pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) | (0x0014); + } else if (mode->CrtcHDisplay <= 1024) { + /* BAD numbers: */ + /* GOOD numbers: 0x15 */ + pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) | (0x0015); + } else if (mode->CrtcHDisplay <= 1280) { + /* BAD numbers: */ + /* GOOD numbers: 0x16 */ + pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) | (0x0016); + } else { + /* BAD numbers: */ + /* GOOD numbers: */ + pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) | (0x0017); + } + } else if (16 == pScrn->bitsPerPixel) { + /* !!! Assume 5-6-5 RGB mode (for now...) */ + pCir->chip.lg->ModeReg.FORMAT = 0x1400; + + if (pScrn->depth == 15) + pCir->chip.lg->ModeReg.FORMAT = 0x1600; + + pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.TILE << 8) | 0x0080 + | (lineData->width << 6); + pCir->chip.lg->ModeReg.CONTROL = 0x2000 | (lineData->width << 11); + + if (mode->CrtcHDisplay <= 640) { + /* BAD numbers: 0x12 */ + /* GOOD numbers: 0x10 */ + pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) | (0x0010); + } else if (mode->CrtcHDisplay <= 800) { + /* BAD numbers: 0x13 */ + /* GOOD numbers: 0x11 */ + pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) | (0x0011); + } else if (mode->CrtcHDisplay <= 1024) { + /* BAD numbers: 0x14 */ + /* GOOD numbers: 0x12 */ + pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) | (0x0012); + } else if (mode->CrtcHDisplay <= 1280) { + /* BAD numbers: 0x08 0x10 */ + /* Borderline numbers: 0x12 */ + /* GOOD numbers: 0x15 */ + pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) | (0x0015); + } else { + pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) | (0x0017); + } + } else if (24 == pScrn->bitsPerPixel) { + pCir->chip.lg->ModeReg.FORMAT = 0x2400; + + pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.TILE << 8) | 0x0080 + | (lineData->width << 6); + pCir->chip.lg->ModeReg.CONTROL = 0x4000 | (lineData->width << 11); + + if (mode->CrtcHDisplay <= 640) { + /* BAD numbers: */ + /* GOOD numbers: 0x10 */ + pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) | (0x0010); + } else if (mode->CrtcHDisplay <= 800) { + /* BAD numbers: */ + /* GOOD numbers: 0x11 */ + pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) | (0x0011); + } else if (mode->CrtcHDisplay <= 1024) { + /* BAD numbers: 0x12 0x13 */ + /* Borderline numbers: 0x15 */ + /* GOOD numbers: 0x17 */ + pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) | (0x0017); + } else if (mode->CrtcHDisplay <= 1280) { + /* BAD numbers: */ + /* GOOD numbers: 0x1E */ + pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) | (0x001E); + } else { + /* BAD numbers: */ + /* GOOD numbers: */ + pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) | (0x0020); + } + } else if (32 == pScrn->bitsPerPixel) { + pCir->chip.lg->ModeReg.FORMAT = 0x3400; + + pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.TILE << 8) | 0x0080 + | (lineData->width << 6); + pCir->chip.lg->ModeReg.CONTROL = 0x6000 | (lineData->width << 11); + + if (mode->CrtcHDisplay <= 640) { + /* GOOD numbers: 0x0E */ + /* BAD numbers: */ + pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) | (0x000E); + } else if (mode->CrtcHDisplay <= 800) { + /* GOOD numbers: 0x17 */ + /* BAD numbers: */ + pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) | (0x0017); + } else if (mode->CrtcHDisplay <= 1024) { + /* GOOD numbers: 0x1D */ + /* OKAY numbers: 0x15 0x14 0x16 0x18 0x19 */ + /* BAD numbers: 0x0E 0x12 0x13 0x0D */ + pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) | (0x001D); + } else if (mode->CrtcHDisplay <= 1280) { + /* GOOD numbers: */ + /* BAD numbers: */ + pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) | (0x0022); /* 10 */ + } else { + pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) | (0x0024); + } + } else { + /* ??? What could it be? Use some sane numbers. */ + } + + /* Setup the appropriate memory interleaving */ + pCir->chip.lg->ModeReg.DTTC |= (pCir->chip.lg->memInterleave << 8); + pCir->chip.lg->ModeReg.TILE |= pCir->chip.lg->memInterleave & 0xC0; + + if (PCI_CHIP_GD5465 == pCir->Chipset) { + /* The tile control information in the DTTC is also mirrored + elsewhere. */ + pCir->chip.lg->ModeReg.TileCtrl = pCir->chip.lg->ModeReg.DTTC & 0xFFC0; + + /* The 5465's DTTC records _fetches_ per line, not + tiles per line. Fetchs are 128-byte fetches. */ + if (pCir->chip.lg->ModeReg.DTTC & 0x0040) { + /* Using 256-byte wide tiles. Double the fetches + per line field. */ + pCir->chip.lg->ModeReg.DTTC = (pCir->chip.lg->ModeReg.DTTC & 0xC0FF) + | ((pCir->chip.lg->ModeReg.DTTC & 0x3F00) << 1); + } + } + + /* Program the registers */ + vgaHWProtect(pScrn, TRUE); + hwp->writeMiscOut(hwp, hwp->ModeReg.MiscOutReg); + + clockData = LgSetClock(pCir, hwp, mode->SynthClock); + pCir->chip.lg->ModeReg.ExtVga[SR0E] = (clockData >> 8) & 0xFF; + pCir->chip.lg->ModeReg.ExtVga[SR1E] = clockData & 0xFF; + + /* Write those registers out to the card. */ + LgRestoreLgRegs(pScrn, &pCir->chip.lg->ModeReg); + + /* Programme the registers */ + vgaHWRestore(pScrn, &hwp->ModeReg, VGA_SR_MODE | VGA_SR_CMAP); + + vgaHWProtect(pScrn, FALSE); + + return TRUE; +} + +static int LgFindLineData(int displayWidth, int bpp) +{ + /* Find the smallest tile-line-pitch such that the total byte pitch + is greater than or equal to displayWidth*Bpp. */ + int i; + + /* Some pitch sizes are duplicates in the table. BUT, the invariant is + that the _first_ time a pitch occurs in the table is always _before_ + all other pitches greater than it. Said in another way... if all + duplicate entries from the table were removed, then the resulting pitch + values are strictly increasing. */ + + for (i = 0; LgLineData[i].pitch > 0; i++) + if (LgLineData[i].pitch >= displayWidth*bpp>>3) + return i; + + /* Um, uh oh! */ + return -1; +} + + + + +static void +LgRestoreLgRegs(ScrnInfoPtr pScrn, LgRegPtr lgReg) +{ + CirPtr pCir; + vgaHWPtr hwp; + CARD8 cr1D; + + pCir = CIRPTR(pScrn); + + /* First, VGAish registers. */ + hwp = VGAHWPTR(pScrn); + hwp->writeCrtc(hwp, 0x1A, lgReg->ExtVga[CR1A]); + hwp->writeCrtc(hwp, 0x1B, lgReg->ExtVga[CR1B]); + cr1D = (hwp->readCrtc(hwp, 0x1D) & ~1) | (lgReg->ExtVga[CR1D] & 0x01); + hwp->writeCrtc(hwp, 0x1D, cr1D); + hwp->writeCrtc(hwp, 0x1E, lgReg->ExtVga[CR1E]); + + hwp->writeSeq(hwp, 0x07, lgReg->ExtVga[SR07]); + hwp->writeSeq(hwp, 0x0E, lgReg->ExtVga[SR0E]); + hwp->writeSeq(hwp, 0x12, lgReg->ExtVga[SR12]); + hwp->writeSeq(hwp, 0x13, lgReg->ExtVga[SR13]); + hwp->writeSeq(hwp, 0x1E, lgReg->ExtVga[SR1E]); + memww(0xC0, lgReg->FORMAT); + + /* Vendor Specific Control is touchy. Only bit 28 is of concern. */ + memwl(0x3FC, ((memrl(0x3FC) & ~(1<<28)) | (lgReg->VSC & (1<<28)))); + + memww(0xEA, lgReg->DTTC); + + if (pCir->Chipset == PCI_CHIP_GD5465) { + memww(0x2C4, lgReg->TileCtrl); + } + + memwb(0x407, lgReg->TILE); + + if (pCir->Chipset == PCI_CHIP_GD5465) + memwb(0x2C0, lgReg->BCLK); + else + memwb(0x8C, lgReg->BCLK); + + memww(0x402, lgReg->CONTROL); +} + +/* + * Restore the initial (text) mode. + */ +static void +LgRestore(ScrnInfoPtr pScrn) +{ + vgaHWPtr hwp; + vgaRegPtr vgaReg; + CirPtr pCir; + LgRegPtr lgReg; + +#ifdef LG_DEBUG + ErrorF("LgRestore pScrn = 0x%08X\n", pScrn); +#endif + + pCir = CIRPTR(pScrn); + hwp = VGAHWPTR(pScrn); + vgaReg = &hwp->SavedReg; + lgReg = &pCir->chip.lg->SavedReg; + + vgaHWProtect(pScrn, TRUE); + + LgRestoreLgRegs(pScrn, lgReg); + + vgaHWRestore(pScrn, vgaReg, VGA_SR_ALL); + vgaHWProtect(pScrn, FALSE); +} + +/* Mandatory */ + +/* This gets called at the start of each server generation */ + +Bool +LgScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) +{ + /* The vgaHW references will disappear one day */ + ScrnInfoPtr pScrn; + vgaHWPtr hwp; + CirPtr pCir; + int i, ret; + VisualPtr visual; + int displayWidth,width,height; + unsigned char * FbBase = NULL; + +#ifdef LG_DEBUG + ErrorF("LgScreenInit\n"); +#endif + + /* + * First get the ScrnInfoRec + */ + pScrn = xf86Screens[pScreen->myNum]; + + hwp = VGAHWPTR(pScrn); + + hwp->MapSize = 0x10000; /* Standard 64k VGA window */ + + pCir = CIRPTR(pScrn); + + /* Map the VGA memory and get the VGA IO base */ + if (!vgaHWMapMem(pScrn)) + return FALSE; + + /* Map the CIR memory and MMIO areas */ + if (!CirMapMem(pCir, pScrn->scrnIndex)) + return FALSE; +#ifdef EXPERIMENTAL + lg_vgaHWSetMmioFunc(hwp, pCir->IOBase); +#endif + vgaHWGetIOBase(hwp); + + /* Save the current state */ + LgSave(pScrn); + + /* Initialise the first mode */ + if (!LgModeInit(pScrn, pScrn->currentMode)) + return FALSE; + + /* Set the viewport */ + LgAdjustFrame(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. + * + */ + + /* + * Reset the visual list. + */ + miClearVisualTypes(); + + /* Setup the visuals we support. */ + + if (!miSetVisualTypes(pScrn->depth, + miGetDefaultVisualMask(pScrn->depth), + pScrn->rgbBits, pScrn->defaultVisual)) + return FALSE; + + miSetPixmapDepths (); + +#ifdef LG_DEBUG + ErrorF("LgScreenInit after miSetVisualTypes\n"); +#endif + displayWidth = pScrn->displayWidth; + if (pCir->rotate) { + height = pScrn->virtualX; + width = pScrn->virtualY; + } else { + width = pScrn->virtualX; + height = pScrn->virtualY; + } + + if(pCir->shadowFB) { + pCir->ShadowPitch = BitmapBytePad(pScrn->bitsPerPixel * width); + pCir->ShadowPtr = xalloc(pCir->ShadowPitch * height); + displayWidth = pCir->ShadowPitch / (pScrn->bitsPerPixel >> 3); + FbBase = pCir->ShadowPtr; + } else { + pCir->ShadowPtr = NULL; + FbBase = pCir->FbBase; + } + + /* + * Call the framebuffer layer's ScreenInit function, and fill in other + * pScreen fields. + */ + switch (pScrn->bitsPerPixel) { + case 8: + case 16: + case 24: + case 32: + ret = fbScreenInit(pScreen, FbBase, + width,height, + pScrn->xDpi, pScrn->yDpi, + displayWidth,pScrn->bitsPerPixel); + break; + default: + xf86DrvMsg(scrnIndex, X_ERROR, + "X11: Internal error: invalid bpp (%d) in LgScreenInit\n", + pScrn->bitsPerPixel); + ret = FALSE; + break; + } + if (!ret) + return FALSE; + +#ifdef LG_DEBUG + ErrorF("LgScreenInit after depth dependent init\n"); +#endif + + /* Override the default mask/offset settings */ + if (pScrn->bitsPerPixel > 8) { + for (i = 0; i < pScreen->numVisuals; i++) { + visual = &pScreen->visuals[i]; + 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 */ + + fbPictureInit(pScreen, 0, 0); + + miInitializeBackingStore(pScreen); + + /* + * Set initial black & white colourmap indices. + */ + xf86SetBlackWhitePixels(pScreen); + + if (!pCir->NoAccel) { /* Initialize XAA functions */ + if (!LgXAAInit(pScreen)) + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Could not initialize XAA\n"); + } +#if 1 + pCir->DGAModeInit = LgModeInit; + if (!CirDGAInit(pScreen)) + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "DGA initialization failed\n"); +#endif + xf86SetSilkenMouse(pScreen); + + /* Initialise cursor functions */ + miDCInitialize(pScreen, xf86GetPointerScreenFuncs()); + + if (pCir->HWCursor) { /* Initialize HW cursor layer */ + if (!LgHWCursorInit(pScreen)) + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Hardware cursor initialization failed\n"); + } + + /* Initialise default colourmap */ + if (!miCreateDefColormap(pScreen)) + return FALSE; + + if (pScrn->bitsPerPixel > 1 && pScrn->bitsPerPixel <= 8) + vgaHWHandleColormaps(pScreen); + + xf86DPMSInit(pScreen, LgDisplayPowerManagementSet, 0); + + pScrn->memPhysBase = pCir->FbAddress; + pScrn->fbOffset = 0; + +#ifdef XvExtension + { + XF86VideoAdaptorPtr *ptr; + int n; + + n = xf86XVListGenericAdaptors(pScrn,&ptr); + if (n) + xf86XVScreenInit(pScreen, ptr, n); + } +#endif + + /* + * Wrap the CloseScreen vector and set SaveScreen. + */ + pScreen->SaveScreen = LgSaveScreen; + pCir->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = LgCloseScreen; + + /* Report any unused options (only for the first generation) */ + if (serverGeneration == 1) + xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options); + + /* Done */ + return TRUE; +} + + +/* Usually mandatory */ +Bool +LgSwitchMode(int scrnIndex, DisplayModePtr mode, int flags) +{ + return LgModeInit(xf86Screens[scrnIndex], mode); +} + +#define ROUND_DOWN(x, mod) (((x) / (mod)) * (mod)) +#define ROUND_UP(x, mod) ((((x) + (mod) - 1) / (mod)) * (mod)) + +/* + * This function is used to initialize the Start Address - the first + * displayed location in the video memory. + */ +/* Usually mandatory */ +void +LgAdjustFrame(int scrnIndex, int x, int y, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + int Base, tmp; + CirPtr pCir = CIRPTR(pScrn); + vgaHWPtr hwp = VGAHWPTR(pScrn); + int cursorX, cursorY; + int middleX, middleY; + const LgLineDataPtr lineData = &LgLineData[pCir->chip.lg->lineDataIndex]; + const int viewportXRes = + (PCI_CHIP_GD5465 == pCir->Chipset) ? (24==pScrn->bitsPerPixel?24:1) : + (lineData->width?256:128) / + (24==pScrn->bitsPerPixel?1:(pScrn->bitsPerPixel>>3)); + const int viewportYRes = + (PCI_CHIP_GD5465 == pCir->Chipset) ? 1 : (24==pScrn->bitsPerPixel?3:1); + + /* Where's the pointer? */ + miPointerPosition(&cursorX, &cursorY); + + /* Where's the middle of the screen? We want to eventually know + which side of the screen the pointer is on. */ + middleX = (pScrn->frameX1 + pScrn->frameX0) / 2; + middleY = (pScrn->frameY1 + pScrn->frameY0) / 2; + + if (cursorX < middleX) { + /* Pointer is on left side of screen. Round the frame value down. */ + pScrn->frameX0 = ROUND_DOWN(pScrn->frameX0, viewportXRes); + } else { + /* Pointer is on right side of screen. Round the frame value + up. A side effect of this rounding up is that we might expose + a part of the screen that's actually on the far /left/ of the + frame buffer. That's because, although the virtual desktop might + be an integral number of tiles, the display might not. We'll + just live with this artifact. */ + pScrn->frameX0 = ROUND_UP(pScrn->frameX0, viewportXRes); + } + pScrn->frameX1 = pScrn->frameX0 + pScrn->currentMode->HDisplay - 1; + + if (cursorY < middleY) { + pScrn->frameY0 = ROUND_DOWN(pScrn->frameY0, viewportYRes); + } else { + pScrn->frameY0 = ROUND_UP(pScrn->frameY0, viewportYRes); + } + pScrn->frameY1 = pScrn->frameY0 + pScrn->currentMode->VDisplay - 1; + + + if (x != pScrn->frameX0 || y != pScrn->frameY0) { + /* !!! */ + /* We moved the frame from where xf86SetViewport() placed it. + If we're using a SW cursor, that's okay -- the pointer exists in + the framebuffer, and those bits are still all aligned. But + if we're using a HW cursor, then we need to re-align the pointer. + Call SetCursorPosition() with the appropriate new pointer + values, adjusted to be wrt the new frame. */ + + x = pScrn->frameX0; + y = pScrn->frameY0; + } + + /* ??? Will this work for 1bpp? */ + Base = (y * lineData->pitch + (x*pScrn->bitsPerPixel/8)) / 4; + + if ((Base & ~0x000FFFFF) != 0) { + /* ??? */ + ErrorF("X11: Internal error: LgAdjustFrame: cannot handle overflow\n"); + return; + } + + hwp->writeCrtc(hwp, 0x0C, (Base >> 8) & 0xFF); + hwp->writeCrtc(hwp, 0x0D, Base & 0xFF); + tmp = hwp->readCrtc(hwp, 0x1B) & 0xF2; + tmp |= (Base >> 16) & 0x01; + tmp |= (Base >> 15) & 0x0C; + hwp->writeCrtc(hwp, 0x1B, tmp); + tmp = hwp->readCrtc(hwp, 0x1D) & 0xE7; + tmp |= (Base >> 16) & 0x18; + hwp->writeCrtc(hwp, 0x1D, tmp); +} + +/* + * This is called when VT switching back to the X server. Its job is + * to reinitialise the video mode. + * + * We may wish to unmap video/MMIO memory too. + */ + +/* Mandatory */ +Bool +LgEnterVT(int scrnIndex, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + CirPtr pCir = CIRPTR(pScrn); +#ifdef LG_DEBUG + ErrorF("LgEnterVT\n"); +#endif + + /* XXX Shouldn't this be in LeaveVT? */ + /* Disable HW cursor */ + if (pCir->HWCursor) + LgHideCursor(pScrn); + + /* Should we re-save the text mode on each VT enter? */ + return LgModeInit(pScrn, pScrn->currentMode); +} + + +/* + * This is called when VT switching away from the X server. Its job is + * to restore the previous (text) mode. + * + * We may wish to remap video/MMIO memory too. + */ + +/* Mandatory */ +void +LgLeaveVT(int scrnIndex, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + vgaHWPtr hwp = VGAHWPTR(pScrn); + CirPtr pCir = CIRPTR(pScrn); +#ifdef LG_DEBUG + ErrorF("LgLeaveVT\n"); +#endif + + /* XXX Shouldn't this be in EnterVT? */ + /* Enable HW cursor */ + if (pCir->HWCursor) + LgShowCursor(pScrn); + + LgRestore(pScrn); + vgaHWLock(hwp); +} + + +/* + * This is called at the end of each server generation. It restores the + * original (text) mode. It should also unmap the video memory, and free + * any per-generation data allocated by the driver. It should finish + * by unwrapping and calling the saved CloseScreen function. + */ + +/* Mandatory */ +static Bool +LgCloseScreen(int scrnIndex, ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + vgaHWPtr hwp = VGAHWPTR(pScrn); + CirPtr pCir = CIRPTR(pScrn); + + if(pScrn->vtSema) { + LgRestore(pScrn); + if (pCir->HWCursor) + LgHideCursor(pScrn); + + vgaHWLock(hwp); + + CirUnmapMem(pCir, pScrn->scrnIndex); + } + + if (pCir->AccelInfoRec) + XAADestroyInfoRec(pCir->AccelInfoRec); + pCir->AccelInfoRec = NULL; + + if (pCir->CursorInfoRec) + xf86DestroyCursorInfoRec(pCir->CursorInfoRec); + pCir->CursorInfoRec = NULL; + if (pCir->DGAModes) + xfree(pCir->DGAModes); + pCir->DGAnumModes = 0; + pCir->DGAModes = NULL; + + pScrn->vtSema = FALSE; + + pScreen->CloseScreen = pCir->CloseScreen; + return (*pScreen->CloseScreen)(scrnIndex, pScreen); +} + + +/* Free up any persistent data structures */ + +/* Optional */ +void +LgFreeScreen(int scrnIndex, int flags) +{ +#ifdef LG_DEBUG + ErrorF("LgFreeScreen\n"); +#endif + /* + * This only gets called when a screen is being deleted. It does not + * get called routinely at the end of a server generation. + */ + if (xf86LoaderCheckSymbol("vgaHWFreeHWRec")) + vgaHWFreeHWRec(xf86Screens[scrnIndex]); + LgFreeRec(xf86Screens[scrnIndex]); +} + + +/* Checks if a mode is suitable for the selected chipset. */ + +/* Optional */ +int +LgValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags) +{ + int lace; + + lace = 1 + ((mode->Flags & V_INTERLACE) != 0); + + if ((mode->CrtcHDisplay <= 2048) && + (mode->CrtcHSyncStart <= 4096) && + (mode->CrtcHSyncEnd <= 4096) && + (mode->CrtcHTotal <= 4096) && + (mode->CrtcVDisplay <= 2048 * lace) && + (mode->CrtcVSyncStart <= 4096 * lace) && + (mode->CrtcVSyncEnd <= 4096 * lace) && + (mode->CrtcVTotal <= 4096 * lace)) { + return(MODE_OK); + } + return(MODE_BAD); +} + + +/* Do screen blanking */ + +/* Mandatory */ +static Bool +LgSaveScreen(ScreenPtr pScreen, int mode) +{ + CirPtr pCir = CIRPTR(xf86Screens[pScreen->myNum]); + ScrnInfoPtr pScrn = NULL; + Bool unblank; + + unblank = xf86IsUnblank(mode); + + if (pScreen != NULL) + pScrn = xf86Screens[pScreen->myNum]; + + if (pScrn != NULL && pScrn->vtSema) { + if (unblank) + /* Power up the palette DAC */ + memwb(0xB0,memrb(0xB0) & 0x7F); + else + /* Power down the palette DAC */ + memwb(0xB0,memrb(0xB0) | 0x80); + } + + return vgaHWSaveScreen(pScreen, mode); +} + +static CARD16 +LgSetClock(CirPtr pCir, vgaHWPtr hwp, int freq) +{ + int ffreq, num, den; + CARD8 tmp; + + ErrorF("LgSetClock freq=%d.%03dMHz\n", freq / 1000, freq % 1000); + + ffreq = freq; + if (!CirrusFindClock(&ffreq, pCir->MaxClock, &num, &den)) + return 0; + + ErrorF("LgSetClock: nom=%x den=%x ffreq=%d.%03dMHz\n", + num, den, ffreq / 1000, ffreq % 1000); + + /* Set VCLK3. */ + /* The numerator and denominator registers are switched + around in the Laguna chips. */ + tmp = hwp->readSeq(hwp, 0x0E); + hwp->writeSeq(hwp, 0x0E, (tmp & 0x80) | den); + hwp->writeSeq(hwp, 0x1E, num); + + return (den << 8) | num; +} + +/* + * CIRDisplayPowerManagementSet -- + * + * Sets VESA Display Power Management Signaling (DPMS) Mode. + */ +static void +LgDisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode, + int flags) +{ + unsigned char sr01, cr1a; + vgaHWPtr hwp; + +#ifdef LG_DEBUG + ErrorF("LgDisplayPowerManagementSet: %d\n", PowerManagementMode); +#endif + + hwp = VGAHWPTR(pScrn); + + switch (PowerManagementMode) { + case DPMSModeOn: + /* Screen: On; HSync: On, VSync: On */ + sr01 = 0x00; + cr1a = 0x00; + break; + case DPMSModeStandby: + /* Screen: Off; HSync: Off, VSync: On */ + sr01 = 0x20; + cr1a = 0x08; + break; + case DPMSModeSuspend: + /* Screen: Off; HSync: On, VSync: Off */ + sr01 = 0x20; + cr1a = 0x04; + break; + case DPMSModeOff: + /* Screen: Off; HSync: Off, VSync: Off */ + sr01 = 0x20; + cr1a = 0x0c; + break; + default: + return; + } + + sr01 |= hwp->readSeq(hwp, 0x01) & ~0x20; + hwp->writeSeq(hwp, 0x01, sr01); + cr1a |= hwp->readCrtc(hwp, 0x1A) & ~0x0C; + hwp->writeCrtc(hwp, 0x1A, cr1a); +} + +#define minb(p) MMIO_IN8(hwp->MMIOBase, (p)) +#define moutb(p,v) MMIO_OUT8(hwp->MMIOBase, (p),(v)) + +static void +mmioWriteCrtc(vgaHWPtr hwp, CARD8 index, CARD8 value) +{ + moutb(index << 2, value); +} + +static CARD8 +mmioReadCrtc(vgaHWPtr hwp, CARD8 index) +{ + return minb(index << 2); +} + +static void +lg_vgaHWSetMmioFunc(vgaHWPtr hwp, CARD8 *base) +{ + hwp->writeCrtc = mmioWriteCrtc; + hwp->readCrtc = mmioReadCrtc; + hwp->MMIOBase = base; + hwp->MMIOOffset = 0; +} diff --git a/src/lg_hwcurs.c b/src/lg_hwcurs.c new file mode 100644 index 0000000..7e30bdb --- /dev/null +++ b/src/lg_hwcurs.c @@ -0,0 +1,384 @@ +/* + * Hardware cursor support for CL-GD546x -- The Laugna family + * + * lg_hwcurs.c + * + * (c) 1998 Corin Anderson. + * corina@the4cs.com + * Tukwila, WA + * + * Much of this code is inspired by the HW cursor code from XFree86 + * 3.3.3. + */ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/cirrus/lg_hwcurs.c,v 1.5 2001/05/07 21:59:06 tsi Exp $ */ + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86_ansic.h" +#include "compiler.h" + +#include "xf86Pci.h" +#include "xf86PciInfo.h" + +#include "vgaHW.h" + +#include "cir.h" +#define _LG_PRIVATE_ +#include "lg.h" +#include "lg_xaa.h" /* For BitBLT engine macros */ + +/* +#define LG_CURSOR_DEBUG +*/ + +#define CURSORWIDTH 64 +#define CURSORHEIGHT 64 +#define CURSORSIZE (CURSORWIDTH*CURSORHEIGHT/8) + +/* Some registers used for the HW cursor. */ +enum { + PALETTE_READ_ADDR = 0x00A4, + PALETTE_WRITE_ADDR = 0x00A8, + PALETTE_DATA = 0x00AC, + + PALETTE_STATE = 0x00B0, + CURSOR_X_POS = 0x00E0, + CURSOR_Y_POS = 0x00E2, + CURSOR_PRESET = 0x00E4, + CURSOR_CONTROL = 0x00E6, + CURSOR_ADDR = 0x00E8 +}; + + +static void +LgFindCursorTile(ScrnInfoPtr pScrn, int *x, int *y, int *width, int *height, + CARD32 *curAddr); + + +/* + * Set the FG and BG colors of the HW cursor. + */ +static void LgSetCursorColors(ScrnInfoPtr pScrn, int bg, int fg) +{ + const CirPtr pCir = CIRPTR(pScrn); + +#ifdef LG_CURSOR_DEBUG + ErrorF("LgSetCursorColors\n"); +#endif + + /* Enable access to cursor colors in palette */ + memwb(PALETTE_STATE, (memrb(PALETTE_STATE) | (1<<3))); + + /* Slam in the color */ + + memwb(PALETTE_WRITE_ADDR, 0x00); + memwb(PALETTE_DATA, (bg >> 16)); + memwb(PALETTE_DATA, (bg >> 8)); + memwb(PALETTE_DATA, (bg >> 0)); + memwb(PALETTE_WRITE_ADDR, 0x0F); + memwb(PALETTE_DATA, (fg >> 16)); + memwb(PALETTE_DATA, (fg >> 8)); + memwb(PALETTE_DATA, (fg >> 0)); + + /* Disable access to cursor colors */ + memwb(PALETTE_STATE, (memrb(PALETTE_STATE) & ~(1<<3))); +} + + +/* + * Set the (x,y) position of the pointer. + * + * Note: (x,y) are /frame/ relative, not /framebuffer/ relative. + * That is, if the virtual desktop has been panned all the way to + * the right, and the pointer is to be in the upper-right hand corner + * of the viewable screen, the pointer coords are (0,0) (even though + * the pointer is on, say (550,0) wrt the frame buffer). This is, of + * course, a /good/ thing -- we don't want to have to deal with where + * the virtual display is, etc, in the cursor code. + * + */ +static void LgSetCursorPosition(ScrnInfoPtr pScrn, int x, int y) +{ + const CirPtr pCir = CIRPTR(pScrn); + +#if 0 +#ifdef LG_CURSOR_DEBUG + ErrorF("LgSetCursorPosition %d %d\n", x, y); +#endif +#endif + + if (x < 0 || y < 0) { + CARD16 oldPreset = memrw(CURSOR_PRESET); + CARD16 newPreset = 0x8080 & oldPreset; /* Reserved bits */ + + if (x < 0) { + newPreset |= ((-x & 0x7F) << 8); + x = 0; + } + + if (y < 0) { + newPreset |= ((-y & 0x7F) << 0); + y = 0; + } + + memww(CURSOR_PRESET, newPreset); + pCir->CursorIsSkewed = TRUE; + } else if (pCir->CursorIsSkewed) { + /* Reset the hotspot location. */ + memww(CURSOR_PRESET, memrw(CURSOR_PRESET & 0x8080)); + pCir->CursorIsSkewed = FALSE; + } + + /* Commit the new position to the card. */ + memww(CURSOR_X_POS, x); + memww(CURSOR_Y_POS, y); +} + + +/* + * Load the cursor image to the card. The cursor image is given in + * bits. The format is: ??? + */ +static void LgLoadCursorImage(ScrnInfoPtr pScrn, unsigned char *bits) +{ + const CirPtr pCir = CIRPTR(pScrn); + const LgPtr pLg = LGPTR(pCir); + + volatile CARD32 *pXCursorBits = (CARD32 *)bits; + + int l, w; + +#ifdef LG_CURSOR_DEBUG + ErrorF("LgLoadCursorImage\n"); +#endif + + /* All ("all") we have to do is a simple CPU-to-screen copy of the + cursor image to the frame buffer. */ + + while (!LgREADY()) {} + ; + + /* Wait until there's ample room in the chip's queue */ + while (memrb(QFREE) < 10) {} + ; + + LgSETMODE(HOST2SCR); /* Host-to-screen blit */ + LgSETROP(0x00CC); /* Source copy */ + + /* First, copy our transparent cursor image to the next 1/2 tile boundry */ + /* Destination */ + LgSETMDSTXY(pLg->HWCursorImageX+pLg->HWCursorTileWidth, pLg->HWCursorImageY); + + /* Set the source pitch. 0 means that, worst case, the source is + alligned only on a byte boundry */ + LgSETMPHASE1(0); + + LgSETMEXTENTSNOMONOQW(pLg->HWCursorTileWidth, pLg->HWCursorTileHeight); + + for (l = 0; l < CURSORHEIGHT; l++) { + /* Plane 0 */ + for (w = 0; w < CURSORWIDTH >> 5; w++) + memwl(HOSTDATA, 0x00000000); + /* Plane 1 */ + for (w = 0; w < CURSORWIDTH >> 5; w++) + memwl(HOSTDATA, 0x00000000); + } + + /* Now, copy the real cursor image */ + + /* Set the destination */ + LgSETMDSTXY(pLg->HWCursorImageX, pLg->HWCursorImageY); + + /* Set the source pitch. 0 means that, worst case, the source is + alligned only on a byte boundry */ + LgSETMPHASE1(0); + + /* Always copy an entire cursor image to the card. */ + LgSETMEXTENTSNOMONOQW(pLg->HWCursorTileWidth, pLg->HWCursorTileHeight); + + for (l = 0; l < CURSORHEIGHT; l++) { + /* Plane 0 */ + for (w = 0; w < CURSORWIDTH >> 5; w++) + memwl(HOSTDATA, *pXCursorBits++); + /* Plane 1 */ + for (w = 0; w < CURSORWIDTH >> 5; w++) + memwl(HOSTDATA, *pXCursorBits++); + } + + while (!LgREADY()) + ; +} + + + +/* + * LgFindCursorTile() finds the tile of display memory that will be + * used to load the pointer image into. The tile chosen will be the + * last tile in the last line of the frame buffer. + */ +static void +LgFindCursorTile(ScrnInfoPtr pScrn, int *x, int *y, int *width, int *height, + CARD32 *curAddr) +{ + CirPtr pCir = CIRPTR(pScrn); + LgPtr pLg = LGPTR(pCir); + + int videoRam = pScrn->videoRam; /* in K */ + int tileHeight = LgLineData[pLg->lineDataIndex].width?8:16; + int tileWidth = LgLineData[pLg->lineDataIndex].width?256:128; + int tilesPerLine = LgLineData[pLg->lineDataIndex].tilesPerLine; + int filledOutTileLines, leftoverMem; + int yTile, xTile; + int tileNumber; + + filledOutTileLines = videoRam / (tilesPerLine * 2); /* tiles are 2K */ + leftoverMem = videoRam - filledOutTileLines*tilesPerLine*2; + + if (leftoverMem > 0) { + yTile = filledOutTileLines; + } else { + /* There is no incomplete row of tiles. Then just use the last + tile in the last line */ + yTile = filledOutTileLines - 1; + } + xTile = 0; /* Always use the first tile in the determined tile row */ + + /* The (x,y) coords of the pointer image. */ + if (x) + *x = xTile * tileWidth; + if (y) + *y = yTile * tileHeight; + + if (width) + *width = tileWidth; + if (height) + *height = tileHeight / 2; + + /* Now, compute the linear address of the cursor image. This process + is unpleasant because the memory is tiled, and we essetially have + to undo the tiling computation. */ + if (curAddr) { + unsigned int nIL; /* Interleaving */ + nIL = pLg->memInterleave==0x00? 1 : (pLg->memInterleave==0x40 ? 2 : 4); + + if (PCI_CHIP_GD5465 == pCir->Chipset) { + /* The Where's The Cursor formula changed for the 5465. It's really + kinda wierd now. */ + unsigned long page, bank; + unsigned int nX, nY; + + nX = xTile * tileWidth; + nY = yTile * tileHeight; + + page = (nY / (tileHeight * nIL)) * tilesPerLine + nX / tileWidth; + bank = (nX/tileWidth + nY/tileHeight) % nIL + page/(512*nIL); + page = page & 0x1FF; + *curAddr = bank*1024*1024L + page*2048 + (nY%tileHeight)*tileWidth; + } else { + tileNumber = (tilesPerLine*nIL) * (yTile/nIL) + yTile % nIL; + *curAddr = tileNumber * 2048; + } + } +} + + + + +/* + * Hide/disable the HW cursor. + */ +void LgHideCursor(ScrnInfoPtr pScrn) +{ + const CirPtr pCir = CIRPTR(pScrn); + + /* To hide the cursor, we kick it off into the corner, and then set the + cursor image to be a transparent bitmap. That way, if X continues + to move the cursor while it is hidden, there is no way that the user + can move the cursor back on screen! + + We don't just clear the cursor enable bit because doesn't work in some + cases (like when switching back to text mode). + */ + +#ifdef LG_CURSOR_DEBUG + ErrorF("LgHideCursor\n"); +#endif + + memww(CURSOR_CONTROL, (memrw(CURSOR_CONTROL) & 0xFFFE)); +} + +void LgShowCursor(ScrnInfoPtr pScrn) +{ + const CirPtr pCir = CIRPTR(pScrn); + const LgPtr pLg = LGPTR(pCir); + +#ifdef LG_CURSOR_DEBUG + ErrorF("LgShowCursor\n"); +#endif + + memww(CURSOR_CONTROL,(memrw(CURSOR_CONTROL) | (1<<0))); + memww(CURSOR_ADDR,(pLg->HWCursorAddr & 0x7FFC)); +} + + +/* + * Can the HW cursor be used? + */ +static Bool LgUseHWCursor(ScreenPtr pScreen, CursorPtr pCurs) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + +#ifdef LG_CURSOR_DEBUG + ErrorF("LgUseHWCursor\n"); +#endif + + if(pScrn->bitsPerPixel < 8) + return FALSE; + + return TRUE; +} + + +/* + * Initialize all the fun HW cursor code. + */ +Bool LgHWCursorInit(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + CirPtr pCir = CIRPTR(pScrn); + xf86CursorInfoPtr infoPtr; + +#ifdef LG_CURSOR_DEBUG + ErrorF("LgHWCursorInit\n"); +#endif + + infoPtr = xf86CreateCursorInfoRec(); + if(!infoPtr) return FALSE; + + pCir->CursorInfoRec = infoPtr; + LgFindCursorTile(pScrn, &pCir->chip.lg->HWCursorImageX, &pCir->chip.lg->HWCursorImageY, + &pCir->chip.lg->HWCursorTileWidth, &pCir->chip.lg->HWCursorTileHeight, + &pCir->chip.lg->HWCursorAddr); + /* Keep only bits 22:10 of the address. */ + pCir->chip.lg->HWCursorAddr = (pCir->chip.lg->HWCursorAddr >> 8) & 0x7FFC; + + pCir->CursorIsSkewed = FALSE; + + infoPtr->MaxWidth = CURSORWIDTH; + infoPtr->MaxHeight = CURSORHEIGHT; + infoPtr->Flags = HARDWARE_CURSOR_TRUECOLOR_AT_8BPP + | HARDWARE_CURSOR_AND_SOURCE_WITH_MASK + | HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64; + infoPtr->SetCursorColors = LgSetCursorColors; + infoPtr->SetCursorPosition = LgSetCursorPosition; + infoPtr->LoadCursorImage = LgLoadCursorImage; + infoPtr->HideCursor = LgHideCursor; + infoPtr->ShowCursor = LgShowCursor; + infoPtr->UseHWCursor = LgUseHWCursor; + +#ifdef LG_CURSOR_DEBUG + ErrorF("LgHWCursorInit before xf86InitCursor\n"); +#endif + + return(xf86InitCursor(pScreen, infoPtr)); +} diff --git a/src/lg_i2c.c b/src/lg_i2c.c new file mode 100644 index 0000000..6cb3e3d --- /dev/null +++ b/src/lg_i2c.c @@ -0,0 +1,96 @@ +/* (c) Itai Nahshon */ + +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/cirrus/lg_i2c.c,v 1.4 2000/12/06 15:35:17 eich Exp $ */ + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86_ansic.h" +#include "compiler.h" + +#include "xf86Pci.h" +#include "xf86PciInfo.h" + +#include "vgaHW.h" + +#include "cir.h" +#define _LG_PRIVATE_ +#include "lg.h" + +static void +LgI2CPutBits(I2CBusPtr b, int clock, int data) +{ + unsigned int regval, regno; + CirPtr pCir = ((CirPtr)b->DriverPrivate.ptr); + if (b == pCir->I2CPtr1) + regno = 0x280; + else if (b == pCir->I2CPtr2) + regno = 0x282; + else + return; + + regval = 0xff7e; + if (clock) regval |= 0x0080; + if (data) regval |= 0x0001; + memww(regno, regval); + /* ErrorF("LgI2CPutBits: %d %d\n", clock, data); */ +} + +static void +LgI2CGetBits(I2CBusPtr b, int *clock, int *data) +{ + unsigned int regval, regno; + CirPtr pCir = ((CirPtr)b->DriverPrivate.ptr); + if (b == pCir->I2CPtr1) + regno = 0x280; + else if (b == pCir->I2CPtr2) + regno = 0x282; + else + return; + + regval = memrw(regno); + *clock = (regval & 0x8000) != 0; + *data = (regval & 0x0100) != 0; + /* ErrorF("LgI2CGetBits: %d %d\n", *clock, *data); */ +} + +Bool +LgI2CInit(ScrnInfoPtr pScrn) +{ + CirPtr pCir = CIRPTR(pScrn); + I2CBusPtr I2CPtr; + +#ifdef LG_DEBUG + ErrorF("LgI2CInit\n"); +#endif + + I2CPtr = xf86CreateI2CBusRec(); + if (!I2CPtr) return FALSE; + + pCir->I2CPtr1 = I2CPtr; + + I2CPtr->BusName = "I2C bus 1"; + I2CPtr->scrnIndex = pScrn->scrnIndex; + I2CPtr->I2CPutBits = LgI2CPutBits; + I2CPtr->I2CGetBits = LgI2CGetBits; + I2CPtr->DriverPrivate.ptr = pCir; + + if (!xf86I2CBusInit(I2CPtr)) + return FALSE; + + I2CPtr = xf86CreateI2CBusRec(); + if (!I2CPtr) return FALSE; + + pCir->I2CPtr2 = I2CPtr; + + I2CPtr->BusName = "I2C bus 2"; + I2CPtr->scrnIndex = pScrn->scrnIndex; + I2CPtr->I2CPutBits = LgI2CPutBits; + I2CPtr->I2CGetBits = LgI2CGetBits; + I2CPtr->DriverPrivate.ptr = pCir; + + if (!xf86I2CBusInit(I2CPtr)) + return FALSE; + + return TRUE; +} + diff --git a/src/lg_xaa.c b/src/lg_xaa.c new file mode 100644 index 0000000..9488721 --- /dev/null +++ b/src/lg_xaa.c @@ -0,0 +1,298 @@ +/* + * XAA acceleration for CL-GD546x -- The Laugna family + * + * lg_xaa.c + * + * (c) 1998 Corin Anderson. + * corina@the4cs.com + * Tukwila, WA + * + * Much of this code is inspired by the XAA acceleration from XFree86 + * 3.3.3, laguna_acl.c + */ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/cirrus/lg_xaa.c,v 1.5 2001/02/15 17:39:28 eich Exp $ */ + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86_ansic.h" +#include "compiler.h" + +#include "xf86Pci.h" +#include "xf86PciInfo.h" + +#include "vgaHW.h" + +#include "cir.h" +#define _LG_PRIVATE_ +#include "lg.h" +#include "lg_xaa.h" + +/* Laguna raster operations, source is OP1 and destination is OP0. */ +/* The order in this array is important! */ +static int lgRop[16] = { + /* Lg Op X name */ + + 0x00, /* 0 GXclear */ + 0x88, /* S.D GXand */ + 0x44, /* S.~D GXandReverse */ + 0xCC, /* S GXcopy */ + 0x22, /* ~S.D GXandInverted */ + 0xAA, /* D GXnoop */ + 0x66, /* S~=D GXxor */ + 0xEE, /* S+D GXor */ + 0x77, /* ~S.~D GXnor */ + 0x99, /* S=D GXequiv */ + 0x55, /* ~D GXinvert */ + 0xDD, /* S+~D GXorReverse */ + 0x33, /* ~S GXcopyInverted */ + 0xBB, /* ~S+D GXorInverted */ + 0x11, /* ~S+~D GXnand */ + 0xFF /* 1 GXset */ +}; + +#if 0 +/* Laguna raster operations, source is OP2 and destination is OP0. */ +static int lgPatRop[16] = { + /* Lg Op X name */ + + 0x00, /* 0 GXclear */ + 0xA0, /* S.D GXand */ + 0x50, /* S.~D GXandReverse */ + 0xF0, /* S GXcopy */ + 0x0A, /* ~S.D GXandInverted */ + 0xAA, /* D GXnoop */ + 0x5A, /* S~=D GXxor */ + 0xFA, /* S+D GXor */ + 0x05, /* ~S.~D GXnor */ + 0xA5, /* S=D GXequiv */ + 0x55, /* ~D GXinvert */ + 0xF5, /* S+~D GXorReverse */ + 0x0F, /* ~S GXcopyInverted */ + 0xAF, /* ~S+D GXorInverted */ + 0x5F, /* ~S+~D GXnand */ + 0xFF /* 1 GXset */ +}; +#endif + + +static void LgSetBitmask(CirPtr pCir, const CARD32 m); +static void LgWaitQAvail(CirPtr pCir, int n); +static CARD32 LgExpandColor(CARD32 color, int bpp); +static void LgSync(ScrnInfoPtr pScrn); +static void LgSetupForSolidFill(ScrnInfoPtr pScrn, int color, int rop, + unsigned int planemask); + +static void LgSubsequentSolidFillRect(ScrnInfoPtr pScrn, int x, int y, + int w, int h); +static void LgSetupForScreenToScreenCopy(ScrnInfoPtr pScrn, int xdir, int ydir, + int rop, unsigned int planemask, + int transparency_color); +static void LgSubsequentScreenToScreenCopy(ScrnInfoPtr pScrn, int x1, int y1, + int x2, int y2, int w, int h); + + +/**************************************************** LgXAAInit *****/ + +Bool +LgXAAInit(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + CirPtr pCir = CIRPTR(pScrn); + XAAInfoRecPtr XAAPtr; + + XAAPtr = XAACreateInfoRec(); + if (!XAAPtr) + return FALSE; + + /* + * Solid color fills. + */ + XAAPtr->SetupForSolidFill = LgSetupForSolidFill; + XAAPtr->SubsequentSolidFillRect = LgSubsequentSolidFillRect; + XAAPtr->SubsequentSolidFillTrap = NULL; + XAAPtr->SolidFillFlags = 0; + + /* + * Screen-to-screen copies. + */ + XAAPtr->SetupForScreenToScreenCopy = LgSetupForScreenToScreenCopy; + XAAPtr->SubsequentScreenToScreenCopy = LgSubsequentScreenToScreenCopy; + /* Maybe ONLY_LEFT_TO_RIGHT_BITBLT or ONLY_TWO_BITBLT_DIRECTIONS? */ + XAAPtr->ScreenToScreenCopyFlags = ONLY_LEFT_TO_RIGHT_BITBLT; + + /* + * Miscellany. + */ + XAAPtr->Sync = LgSync; + + pCir->AccelInfoRec = XAAPtr; + + if (!XAAInit(pScreen, XAAPtr)) + return FALSE; + + return TRUE; +} + +/******************************************** Lg XAA helper functions ***/ + +/* + * The bitmask is usually all 1's, so it's silly to spend a DWORD write + * to program the register with the same value each time. Bitmask is + * about the only register whose value is worth shadowing, so we special- + * case it. + */ +static void +LgSetBitmask(CirPtr pCir, const CARD32 m) +{ + const LgPtr pLg = LGPTR(pCir); + + if (m != pLg->oldBitmask) { + LgSETBITMASK(m); + pLg->oldBitmask = m; + } +} + +/* + * Return from the function only when there's room somewhere for the + * upcoming register writes. That means that either PCI retry is enabled + * (i.e., we let the PCI bus buffer the register writes), or we wait for + * room in the Laguna's command queue explicitly. + */ +static void +LgWaitQAvail(CirPtr pCir, int n) +{ + if (!0/*lgUsePCIRetry*/) { + CARD8 qfree; + + /* Wait until n entries are open in the command queue */ + do + qfree = *(volatile CARD8 *)(pCir->IOBase + QFREE); + while (qfree < n); + } +} + + +/* We might want to make this a macro at some point. */ +static CARD32 +LgExpandColor(CARD32 color, int bpp) +{ + if (8 == bpp) + color = ((color&0xFF) << 8) | (color&0xFF); + + if (8 == bpp || 16 == bpp) + color = ((color&0xFFFF) << 16) | (color&0xFFFF); + + return color; +} + + +/*************************************************** Lg XAA functions ***/ + + +static void +LgSync(ScrnInfoPtr pScrn) +{ + const CirPtr pCir = CIRPTR(pScrn); +#if 0 + LgPtr pLg = LGPTR(pScrn); +#endif + + while (!LgREADY()) + ; +} + +static void +LgSetupForSolidFill(ScrnInfoPtr pScrn, int color, int rop, + unsigned int planemask) +{ + + const CirPtr pCir = CIRPTR(pScrn); + + color = LgExpandColor(color, pScrn->bitsPerPixel); + + LgWaitQAvail(pCir, 4); + + LgSETBACKGROUND(color); + LgSETROP(lgRop[rop]); + LgSETMODE(SCR2SCR | COLORFILL); + LgSetBitmask(pCir, planemask); +} + +static void +LgSubsequentSolidFillRect(ScrnInfoPtr pScrn, int x, int y, int w, int h) +{ + const CirPtr pCir = CIRPTR(pScrn); + + /* Wait for room in the command queue. */ + LgWaitQAvail(pCir, 2); + + LgSETDSTXY(x, y); + LgSETEXTENTS(w, h); +} + +static void +LgSetupForScreenToScreenCopy(ScrnInfoPtr pScrn, int xdir, int ydir, + int rop, unsigned int planemask, int transparency_color) +{ + int bltmode = 0; + const CirPtr pCir = CIRPTR(pScrn); + const LgPtr pLg = LGPTR(pCir); + + pLg->blitTransparent = (transparency_color != -1); + pLg->blitYDir = ydir; + + LgWaitQAvail(pCir, 4); + + /* We set the rop up here because the LgSETROP macro conveniently + (really -- it is convenient!) clears the transparency bits + in DRAWDEF. We'll set those bits appropriatly later. */ + LgSETROP(lgRop[rop]); + + if (ydir < 0) + bltmode |= BLITUP; + if (pLg->blitTransparent) { + /* Gotta extend the transparency_color to the full 32-bit + size of the register. */ + transparency_color = LgExpandColor(transparency_color, + pScrn->bitsPerPixel); + + bltmode |= COLORTRANS; + LgSETBACKGROUND(transparency_color); + LgSETTRANSPARENCY(TRANSEQ); + } else { + LgSETTRANSPARENCY(TRANSNONE); + } + + LgSETMODE(SCR2SCR | COLORSRC | bltmode); + LgSetBitmask(pCir, planemask); +} + +static void +LgSubsequentScreenToScreenCopy(ScrnInfoPtr pScrn, int x1, int y1, + int x2, int y2, int w, int h) +{ + const CirPtr pCir = CIRPTR(pScrn); + const LgPtr pLg = LGPTR(pCir); + + /* + * We have set the flag indicating that xdir must be one, + * so we can assume that here. + */ + if (pLg->blitYDir == -1) { + y1 += h - 1; + y2 += h - 1; + } + + if (pLg->blitTransparent) { + /* We're doing a transparent blit. We'll need to point + OP2 to the color compare mask. */ + LgWaitQAvail(pCir, 4); + LgSETTRANSMASK(x1, y1); + } else { + LgWaitQAvail(pCir, 3); + } + LgSETSRCXY(x1, y1); + LgSETDSTXY(x2, y2); + LgSETEXTENTS(w, h); +} + diff --git a/src/lg_xaa.h b/src/lg_xaa.h new file mode 100644 index 0000000..7359a49 --- /dev/null +++ b/src/lg_xaa.h @@ -0,0 +1,180 @@ +#ifndef __LG_XAA_H +#define __LG_XAA_H + +/* + * XAA acceleration for CL-GD546x -- The Laugna family + * + * lg_xaa.h + * + * (c) 1996,1998 Corin Anderson. + * corina@the4cs.com + * Tukwila, WA + * + * This header file draws much from the file cir_blitLG.h in version 3.3.3 + * of XFree86. + */ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/cirrus/lg_xaa.h,v 1.3 2000/02/08 13:13:15 eich Exp $ */ + +/* This header file defines the necessary structures, contstants, and + variables for using the bitBLT engine on a Laguna family graphics + accelerator. */ + + +enum { /* Offsets into MMIO space for bitBLT regs */ + STATUS = 0x0400, + OP0_opRDRAM = 0x0520, + OP1_opRDRAM = 0x0540, + OP2_opRDRAM = 0x0560, + OP0_opMRDRAM = 0x0524, + OP1_opMRDRAM = 0x0544, + OP2_opMRDRAM = 0x0564, + OP0_opSRAM = 0x0528, + OP1_opSRAM = 0x0548, + OP2_opSRAM = 0x0568, + OP1_opMSRAM = 0x054A, + OP2_opMSRAM = 0x056A, + DRAWDEF = 0x0584, + BLTDEF = 0x0586, + BLTEXT_EX = 0x0700, + MBLTEXT_EX = 0x0720, + MONOQW = 0x0588, + QFREE = 0x0404, + PATOFF = 0x052A, + HOSTDATA = 0x0800, + OP_opBGCOLOR = 0x05E4, + OP_opFGCOLOR = 0x05E0, + bltCONTROL = 0x0402, + BITMASK = 0x05E8 +}; + +enum { HOSTDATASIZE = 2048 }; /* The HOSTDATA port is 2048 BYTES */ + +enum { /* OR these together to form a bitBLT mode */ + HOST2SCR = 0x1120, /* CPU/Screen transfer modes */ + SCR2HOST = 0x2010, + HOST2PAT = 0x1102, + HOST2SRAM2 = 0x6020, /* CPU to SRAM2 transfer */ + + SCR2SCR = 0x1110, /* Screen/Screen transfers */ + COLORSRC = 0x0000, /* Source is color data */ + MONOSRC = 0x0040, /* Source is mono data (color expansion) */ + COLORTRANS = 0x0001, /* Transparent screen/screen transfer */ + MONOTRANS = 0x0005, /* Transparent screen/screen color expansion */ + COLORFILL = 0x0070, /* Solid color fill mode */ + SRAM1SCR2SCR = 0x1180, /* Pattern fill, source from SRAM1 */ + + PAT2SCR = 0x1109, /* Pattern/Screen transfers */ + COLORPAT = 0x0000, /* Pattern is color data */ + MONOPAT = 0x0004, /* Pattern is mono data (color expansion) */ + SRAM2PAT2SCR = 0x1108, /* SRAM2 is pattern source */ + + PATeqSRC = 0x0800, /* The Pattern and Source operands are the same */ + /* Advice from Corey: don't ever try to use + this option! 8) There's a documented bug + with it on the '62, and, well, I have + empirical evidence that either the bug's + still around, even in the '64 and the '65. + It's a performance option, anyway, so not + using it should be okay. */ + + + BLITUP = 0x8000 /* The blit is proceeding from bottom to top */ +}; + +enum { /* Select transparency compare */ + TRANSBG = 0x0100, + TRANSFG = 0x0300, + TRANSEQ = 0x0100, + TRANSNE = 0x0300, + TRANSNONE = 0x0000 +}; + +#define LgREADY() ((memrb(STATUS) & 0x07) == 0x00) + +#define LgSETROP(rop) memww(DRAWDEF,rop); + +#define LgSETTRANSPARENCY(trans) \ + memww(DRAWDEF,(trans) | (memrw(DRAWDEF) & 0x00FF)); + +#define LgSETMODE(mode) memww(BLTDEF,mode); + +#define LgSETDSTXY(X, Y) memwl(OP0_opRDRAM, (((Y) << 16) | (X))); + +#define LgSETSRCXY(X, Y) memwl(OP1_opRDRAM, (((Y) << 16) | (X))); + +#define LgSETPATXY(X, Y) memwl(OP2_opRDRAM, (((Y) << 16) | (X))); + +#define LgSETTRANSMASK(X, Y) LgSETPATXY(X, Y) + +#define LgSETSRAMDST(offset) memww(OP0_opSRAM, offset); + +/* was this a bug? it read OP2_opSRAM */ +#define LgSETSRAM1OFFSET(offset) memww(OP1_opSRAM, offset); + +#define LgSETSRAM2OFFSET(offset) memww(OP2_opSRAM, offset); + +#define LgSETMSRAM1OFFSET(offset) memww(OP1_opMSRAM, offset); + +#define LgSETMSRAM2OFFSET(offset) memww(OP2_opMSRAM, offset); + +#define LgSETMDSTXY(X, Y) memwl(OP0_opMRDRAM, (((Y) << 16) | (X))); + +#define LgSETMSRCXY(X, Y) memwl(OP1_opMRDRAM, (((Y) << 16) | (X))); + +#define LgSETMPATXY(X, Y) memwl(OP2_opMRDRAM, (((Y) << 16) | (X))); + +#define LgSETMTRANSMASK(X, Y) LgSETMPATXY(X, Y) + +#define LgSETPHASE0(phase) memwl( OP0_opRDRAM, phase); + +#define LgSETPHASE1(phase) memwl(OP1_opRDRAM, phase); + +#define LgSETPHASE2(phase) memwl( OP2_opRDRAM, phase); + +#define LgSETMPHASE0(phase) memwl(OP0_opMRDRAM, phase); + +#define LgSETMPHASE1(phase) memwl(OP1_opMRDRAM, phase); + +#define LgSETEXTENTS(width, height) \ + memwl(BLTEXT_EX, (((height) << 16)|(width))); + +#if 0 +#define LgSETMEXTENTS(width, height) \ + memwl(MBLTEXT_EX, (((height) << 16)|(width))); +#else +/* For monochrome (byte) blits, we need to set how many QWORDs of data + encompass the X extent. Write this piece of data into MONOQW. */ +#define LgSETMEXTENTS(width, height) \ + { \ + memww(MONOQW, ((width + 7) >> 3)); \ + memwl(MBLTEXT_EX, (((height) << 16)|(width))); \ + } + +#define LgSETMEXTENTSNOMONOQW(width, height) \ + memwl(MBLTEXT_EX, (((height) << 16)|(width))); + +/* + memww(MBLTEXT_EX, height); + memww(MBLTEXT_EX + 2, width); + */ +#endif + +#define LgHOSTDATAWRITE(data) memwl(HOSTDATA, data); + +#define LgHOSTDATAREAD() (memrl(HOSTDATA)) + +#define LgSETBACKGROUND(color) memwl(OP_opBGCOLOR, color); + +#define LgSETFOREGROUND(color) memwl(OP_opFGCOLOR, color); + +#define LgSETPATOFF(xoff, yoff) memww(PATOFF, (((yoff) << 8) | (xoff))); + +#define LgSETSWIZZLE() memww(bltCONTROL, memrw(bltCONTROL | 0x0400)); + +#define LgCLEARSWIZZLE() memww(bltCONTROL, memrw(bltCONTROL & ~0x0400)); + +#define LgSETBITMASK(m) memwl(BITMASK, m); + + + +#endif /* __LG_XAA_H */ -- cgit v1.2.1