From f8a7c34953f864557f4c563fd5d7a025a5f302f7 Mon Sep 17 00:00:00 2001 From: "Enrico Weigelt, metux IT consult" Date: Mon, 21 Jul 2025 17:53:29 +0200 Subject: [PATCH] xfree86: drivers: cirrus: copy over xf86-video-cirrus tree Since this driver doesn't receive much functional changes, except fixups for server ABI changes, it's a good candidate to move it back into the main Xserver tree. As the first step to move back this driver into the Xserver tree, copy over the source from last release tag. Skipped files we don't need here (eg. gitlab pipeline, automake files, ...) repo: git@github.com:X11Libre/xf86-video-cirrus.git git tag: xlibre-xf86-video-cirrus-1.6.0.1 Signed-off-by: Enrico Weigelt, metux IT consult --- hw/xfree86/drivers/video-cirrus/COPYING | 64 + hw/xfree86/drivers/video-cirrus/README.md | 18 + .../drivers/video-cirrus/README.multihead | 70 + .../drivers/video-cirrus/man/cirrus.man | 34 + .../drivers/video-cirrus/src/CirrusClk.c | 146 ++ hw/xfree86/drivers/video-cirrus/src/alp.h | 83 + .../drivers/video-cirrus/src/alp_driver.c | 2049 +++++++++++++++ .../drivers/video-cirrus/src/alp_hwcurs.c | 258 ++ hw/xfree86/drivers/video-cirrus/src/alp_i2c.c | 131 + hw/xfree86/drivers/video-cirrus/src/cir.h | 99 + hw/xfree86/drivers/video-cirrus/src/cir_dga.c | 198 ++ .../drivers/video-cirrus/src/cir_driver.c | 387 +++ .../drivers/video-cirrus/src/cir_pcirename.h | 148 ++ .../drivers/video-cirrus/src/cir_shadow.c | 288 +++ hw/xfree86/drivers/video-cirrus/src/lg.h | 105 + hw/xfree86/drivers/video-cirrus/src/lg_blit.h | 179 ++ .../drivers/video-cirrus/src/lg_driver.c | 2214 +++++++++++++++++ .../drivers/video-cirrus/src/lg_hwcurs.c | 384 +++ hw/xfree86/drivers/video-cirrus/src/lg_i2c.c | 109 + 19 files changed, 6964 insertions(+) create mode 100644 hw/xfree86/drivers/video-cirrus/COPYING create mode 100644 hw/xfree86/drivers/video-cirrus/README.md create mode 100644 hw/xfree86/drivers/video-cirrus/README.multihead create mode 100644 hw/xfree86/drivers/video-cirrus/man/cirrus.man create mode 100644 hw/xfree86/drivers/video-cirrus/src/CirrusClk.c create mode 100644 hw/xfree86/drivers/video-cirrus/src/alp.h create mode 100644 hw/xfree86/drivers/video-cirrus/src/alp_driver.c create mode 100644 hw/xfree86/drivers/video-cirrus/src/alp_hwcurs.c create mode 100644 hw/xfree86/drivers/video-cirrus/src/alp_i2c.c create mode 100644 hw/xfree86/drivers/video-cirrus/src/cir.h create mode 100644 hw/xfree86/drivers/video-cirrus/src/cir_dga.c create mode 100644 hw/xfree86/drivers/video-cirrus/src/cir_driver.c create mode 100644 hw/xfree86/drivers/video-cirrus/src/cir_pcirename.h create mode 100644 hw/xfree86/drivers/video-cirrus/src/cir_shadow.c create mode 100644 hw/xfree86/drivers/video-cirrus/src/lg.h create mode 100644 hw/xfree86/drivers/video-cirrus/src/lg_blit.h create mode 100644 hw/xfree86/drivers/video-cirrus/src/lg_driver.c create mode 100644 hw/xfree86/drivers/video-cirrus/src/lg_hwcurs.c create mode 100644 hw/xfree86/drivers/video-cirrus/src/lg_i2c.c diff --git a/hw/xfree86/drivers/video-cirrus/COPYING b/hw/xfree86/drivers/video-cirrus/COPYING new file mode 100644 index 000000000..9af424251 --- /dev/null +++ b/hw/xfree86/drivers/video-cirrus/COPYING @@ -0,0 +1,64 @@ +Copyright (C) 1994-2003 The XFree86 Project, Inc. All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is fur- +nished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT- +NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON- +NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of the XFree86 Project shall not +be used in advertising or otherwise to promote the sale, use or other deal- +ings in this Software without prior written authorization from the XFree86 +Project. + +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. + +Copyright 2007 George Sapountzis + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice (including the next +paragraph) shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/hw/xfree86/drivers/video-cirrus/README.md b/hw/xfree86/drivers/video-cirrus/README.md new file mode 100644 index 000000000..94337765b --- /dev/null +++ b/hw/xfree86/drivers/video-cirrus/README.md @@ -0,0 +1,18 @@ +xf86-video-cirrus - Cirrus Logic video driver for the Xorg X server +------------------------------------------------------------------- + +All questions regarding this software should be directed at the +Xorg mailing list: + + https://lists.x.org/mailman/listinfo/xorg + +The primary development code repository can be found at: + + https://gitlab.freedesktop.org/xorg/driver/xf86-video-cirrus + +Please submit bug reports and requests to merge patches there. + +For patch submission instructions, see: + + https://www.x.org/wiki/Development/Documentation/SubmittingPatches + diff --git a/hw/xfree86/drivers/video-cirrus/README.multihead b/hw/xfree86/drivers/video-cirrus/README.multihead new file mode 100644 index 000000000..514696dcf --- /dev/null +++ b/hw/xfree86/drivers/video-cirrus/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 corrupted 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/hw/xfree86/drivers/video-cirrus/man/cirrus.man b/hw/xfree86/drivers/video-cirrus/man/cirrus.man new file mode 100644 index 000000000..79526c0b3 --- /dev/null +++ b/hw/xfree86/drivers/video-cirrus/man/cirrus.man @@ -0,0 +1,34 @@ +.\" shorthand for double quote that works everywhere. +.ds q \N'34' +.TH CIRRUS __drivermansuffix__ 2009-05-07 __vendorversion__ +.SH NAME +cirrus \- Cirrus Logic video driver for Xorg +.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 Xorg 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 +.BR xorg.conf (__filemansuffix__) +for general configuration details. +This section only covers configuration details specific to this driver. +.SH "SEE ALSO" +.BR Xorg (1), +.BR xorg.conf (__filemansuffix__), +.BR Xserver (1), +.BR X (__miscmansuffix__) +.SH AUTHORS +Authors include: Corin Anderson, Egbert Eich, Derek Fawcus, Koen Gadeyne, +Harm Hanemaayer, David Monniaux, Itai Nahshon diff --git a/hw/xfree86/drivers/video-cirrus/src/CirrusClk.c b/hw/xfree86/drivers/video-cirrus/src/CirrusClk.c new file mode 100644 index 000000000..a6b2d63cc --- /dev/null +++ b/hw/xfree86/drivers/video-cirrus/src/CirrusClk.c @@ -0,0 +1,146 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* + * 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 completely chipset independent, and moved chipset dependent parts + * into the specific sub-drivers. Derek Fawcus + */ + +#include "xf86.h" +#include "xf86_OSproc.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. + */ + +_X_EXPORT 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/hw/xfree86/drivers/video-cirrus/src/alp.h b/hw/xfree86/drivers/video-cirrus/src/alp.h new file mode 100644 index 000000000..f2ff19d46 --- /dev/null +++ b/hw/xfree86/drivers/video-cirrus/src/alp.h @@ -0,0 +1,83 @@ +/* (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 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/hw/xfree86/drivers/video-cirrus/src/alp_driver.c b/hw/xfree86/drivers/video-cirrus/src/alp_driver.c new file mode 100644 index 000000000..5c355ffca --- /dev/null +++ b/hw/xfree86/drivers/video-cirrus/src/alp_driver.c @@ -0,0 +1,2049 @@ +/* + * Driver for CL-GD5480. + * Itai Nahshon. + * + * Support for the CL-GD7548: David Monniaux + * + * This is mainly a cut & paste from the MGA driver. + * Original authors and contributors list include: + * Radoslaw Kapitan, Andrew Vanderstock, Dirk Hohndel, + * David Dawes, Andrew E. Mileski, Leonard N. Zubkoff, + * Guy DESBIEF + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* All drivers should typically include these */ +#include "xf86.h" +#include "xf86_OSproc.h" + +/* All drivers need this */ + +/* Everything using inb/outb, etc needs "compiler.h" */ +#include "compiler.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" + +/* All drivers initialising the SW cursor need this */ +#include "mipointer.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 "fb.h" + + +#include "xf86DDC.h" +#include "xf86int10.h" + +#include "cir.h" +#define _ALP_PRIVATE_ +#include "alp.h" + +#include "xf86xv.h" +#include + +#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(ScreenPtr pScreen, int argc, char **argv); +Bool AlpEnterVT(ScrnInfoPtr arg); +void AlpLeaveVT(ScrnInfoPtr arg); +static Bool AlpCloseScreen(ScreenPtr pScreen); +static Bool AlpSaveScreen(ScreenPtr pScreen, int mode); + +/* Required if the driver supports mode switching */ +Bool AlpSwitchMode(ScrnInfoPtr arg, DisplayModePtr mode); +/* Required if the driver supports moving the viewport */ +void AlpAdjustFrame(ScrnInfoPtr arg, int x, int y); + +/* Optional functions */ +void AlpFreeScreen(ScrnInfoPtr arg); +ModeStatus AlpValidMode(ScrnInfoPtr arg, 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 }; +static int gd7555_MaxClocks[] = { 80100, 80100, 80100, 80100, 80100 }; +static int gd7556_MaxClocks[] = { 80100, 80100, 80100, 80100, 80100 }; + +#ifdef XFree86LOADER + +#define ALP_MAJOR_VERSION 1 +#define ALP_MINOR_VERSION 0 +#define ALP_PATCHLEVEL 0 + +static XF86ModuleVersionInfo alpVersRec = +{ + "cirrus_alpine", + MODULEVENDORSTRING, + MODINFOSTRING1, + MODINFOSTRING2, + XORG_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. + */ +_X_EXPORT XF86ModuleData cirrus_alpineModuleData = { + &alpVersRec, + NULL, + NULL +}; + +#endif /* XFree86LOADER */ + +_X_EXPORT const OptionInfoRec * +AlpAvailableOptions(int chipid) +{ + return CirOptions; +} + +_X_EXPORT 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 = XNFcallocarray(sizeof(CirRec), 1); + ((CirPtr)pScrn->driverPrivate)->chip.alp = XNFcallocarray(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; + free(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 */ + if (!pCir->IoMapSize) + 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", + (unsigned int)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", + (unsigned int)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", + (unsigned int)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; + switch (pCir->chip.alp->sr0f & 0x90) { + case 0x10: + /* TODO: 2 256K X 16 DRAMs (1024) or 4 512K X 8 DRAMs (2048)? */ + break; + case 0x90: + videoram <<= 1; + break; + } + break; + + case PCI_CHIP_GD7555: + case PCI_CHIP_GD7556: + videoram = 2048; /* for PC-9821 La13 etc. */ + 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; + int max_pitch; + + 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 + const int accelWidths[] = { 640, 768, 800, 960, 1024, 1152, 1280, + 1600, 1920, 2048, 0 }; +#else + const int accelWidths[] = { 512, 576, 640, 768, 800, 960, 1024, 1152, + 1280, 1536, 1600, 1920, 2048, 0 }; +#endif + + switch (pCir->Chipset) { + case PCI_CHIP_GD5436: + case PCI_CHIP_GD5446: + max_pitch = 0x1ff << 3; + break; + + default: + /* FIXME max_pitch for other chipsets? */ + max_pitch = (pScrn->bitsPerPixel / 8) * 2048; + break; + } + + for (i = 0; accelWidths[i] != 0; i++) { + if ((accelWidths[i] % pCir->Rounding == 0) + && ((accelWidths[i] * pScrn->bitsPerPixel / 8) <= max_pitch)) { + 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; + int depth_flags; + ClockRangePtr clockRanges; + const 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; + + /* + * Allocate a vgaHWRec + */ + if (!vgaHWGetHWRec(pScrn)) + return FALSE; + hwp = VGAHWPTR(pScrn); + vgaHWSetStdFuncs(hwp); + vgaHWGetIOBase(hwp); + + /* Allocate the AlpRec driverPrivate */ + if (!AlpGetRec(pScrn)) + return FALSE; + + pCir = CIRPTR(pScrn); + pCir->pScrn = pScrn; + pCir->PIOReg = 0x3CE; /* was 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) { + free(pCir->pEnt); + return FALSE; + } + + pCir->Chipset = pCir->pEnt->chipset; + /* Find the PCI info for this screen */ + pCir->PciInfo = xf86GetPciInfoForEntity(pCir->pEnt->index); +#ifndef XSERVER_LIBPCIACCESS + pCir->PciTag = pciTag(PCI_DEV_BUS(pCir->PciInfo), + PCI_DEV_DEV(pCir->PciInfo), + PCI_DEV_FUNC(pCir->PciInfo)); +#endif + + if (xf86LoadSubModule(pScrn, "int10")) + { + 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 + */ + + PCI_WRITE_LONG(pCir->PciInfo, PCI_REGION_BASE(pCir->PciInfo, 0, REGION_MEM), 0x10); + PCI_WRITE_LONG(pCir->PciInfo, PCI_REGION_BASE(pCir->PciInfo, 1, REGION_MEM), 0x14); + } + + /* Set pScrn->monitor */ + pScrn->monitor = pScrn->confScreen->monitor; + + /* 32bpp only works on 5480 and 7548 */ + depth_flags = Support24bppFb; + if (pCir->Chipset == PCI_CHIP_GD5480 || pCir->Chipset ==PCI_CHIP_GD7548) + depth_flags |= Support32bppFb | + SupportConvert32to24 | + PreferConvert32to24; + + /* + * The first thing we should figure out is the depth, bpp, etc. + * We support both 24bpp and 32bpp layouts, so indicate that. + */ + if (!xf86SetDepthBpp(pScrn, 0, 0, 16, depth_flags)) { + 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 = malloc(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; + + switch (pCir->Chipset) { + case PCI_CHIP_GD7555: + case PCI_CHIP_GD7556: + pCir->HWCursor = TRUE; + break; + default: + break; + } + + 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 = PCI_DEV_REVISION(pCir->PciInfo); + } + + /* 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 (PCI_REGION_BASE(pCir->PciInfo, 0, REGION_MEM) != 0) { + /* 5446B and 5480 use mask of 0xfe000000. + 5446A uses 0xff000000. */ + pCir->FbAddress = PCI_REGION_BASE(pCir->PciInfo, 0, REGION_MEM) & 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 (PCI_REGION_BASE(pCir->PciInfo, 1, REGION_MEM) != 0) { + pCir->IOAddress = PCI_REGION_BASE(pCir->PciInfo, 1, REGION_MEM) & 0xfffff000; + pCir->IoMapSize = PCI_REGION_SIZE(pCir->PciInfo, 1); + 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"); + +#ifndef XSERVER_LIBPCIACCESS + /* + * 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; + } +#endif + + if (!xf86LoadSubModule(pScrn, "i2c")) { + AlpFreeRec(pScrn); + return FALSE; + } + + if (!xf86LoadSubModule(pScrn, "ddc")) { + AlpFreeRec(pScrn); + return FALSE; + } + + if(!AlpI2CInit(pScrn)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "I2C initialization failed\n"); + } + else + xf86SetDDCproperties(pScrn,xf86PrintEDID( + xf86DoEDID_DDC2(pScrn,pCir->I2CPtr1))); + +#ifdef XSERVER_LIBPCIACCESS + #ifndef PCI_CHIP_QEMU + #define PCI_CHIP_QEMU 0x1af4 + #endif + if (!pScrn->monitor->DDC && + ((pCir->PciInfo->subvendor_id & 0xffff) == PCI_CHIP_QEMU)) { + pCir->NoAccel = TRUE; + } +#endif + + /* 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_GD5440: */ + p = gd5430_MaxClocks; + break; + case PCI_CHIP_GD5436: + case PCI_CHIP_GD5446: + p = gd5446_MaxClocks; + break; + case PCI_CHIP_GD5480: + p = gd5480_MaxClocks; + break; + case PCI_CHIP_GD7548: + p = gd7548_MaxClocks; + break; + case PCI_CHIP_GD7555: + p = gd7555_MaxClocks; + break; + case PCI_CHIP_GD7556: + p = gd7556_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 = XNFcallocarray(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 fb module */ + if (xf86LoadSubModule(pScrn, "fb") == NULL) { + AlpFreeRec(pScrn); + return FALSE; + } + + /* Use shadowfb for acceleration */ + if (!pCir->NoAccel) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Falling back to shadowfb\n"); + pCir->NoAccel = TRUE; + pCir->shadowFB = TRUE; + } + + /* Load ramdac if needed */ + if (pCir->HWCursor) { + if (!xf86LoadSubModule(pScrn, "ramdac")) { + AlpFreeRec(pScrn); + return FALSE; + } + } + + if (pCir->shadowFB) { + if (!xf86LoadSubModule(pScrn, "shadowfb")) { + AlpFreeRec(pScrn); + return FALSE; + } + } + + 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; + 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; + + 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(ScreenPtr pScreen, int argc, char **argv) +{ + ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); + vgaHWPtr hwp; + CirPtr pCir; + 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 + + hwp = VGAHWPTR(pScrn); + pCir = CIRPTR(pScrn); + + /* 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; + + /* Make things beautiful */ + AlpSaveScreen(pScreen, SCREEN_SAVER_ON); + + /* Set the viewport */ + AlpAdjustFrame(pScrn, pScrn->frameX0, pScrn->frameY0); + + /* + * 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 = malloc(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: + case 4: + 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(pScrn->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); + + /* + * 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 acceleration functions */ + AlpOffscreenAccelInit(pScrn); + } + +#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; + + { + XF86VideoAdaptorPtr *ptr; + int n; + + n = xf86XVListGenericAdaptors(pScrn,&ptr); + if (n) + xf86XVScreenInit(pScreen, ptr, n); + } + + /* + * 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(ScrnInfoPtr pScrn, DisplayModePtr mode) +{ + return AlpModeInit(pScrn, mode); +} + + +/* + * This function is used to initialize the Start Address - the first + * displayed location in the video memory. + */ +/* Usually mandatory */ +void +AlpAdjustFrame(ScrnInfoPtr pScrn, int x, int y) +{ + int Base, tmp; + vgaHWPtr hwp; + + 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(ScrnInfoPtr pScrn) +{ + 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(ScrnInfoPtr pScrn) +{ + 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(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); + vgaHWPtr hwp = VGAHWPTR(pScrn); + CirPtr pCir = CIRPTR(pScrn); + + if(pScrn->vtSema) { + AlpRestore(pScrn); + vgaHWLock(hwp); + CirUnmapMem(pCir, pScrn->scrnIndex); + } + + if (pCir->CursorInfoRec) + xf86DestroyCursorInfoRec(pCir->CursorInfoRec); + pCir->CursorInfoRec = NULL; + if (pCir->DGAModes) + free(pCir->DGAModes); + pCir->DGAnumModes = 0; + pCir->DGAModes = NULL; + + pScrn->vtSema = FALSE; + + pScreen->CloseScreen = pCir->CloseScreen; + return (*pScreen->CloseScreen)(pScreen); +} + + +/* Free up any persistent data structures */ + +/* Optional */ +void +AlpFreeScreen(ScrnInfoPtr pScrn) +{ +#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(pScrn); + AlpFreeRec(pScrn); +} + + +/* Checks if a mode is suitable for the selected chipset. */ + +/* Optional */ +ModeStatus +AlpValidMode(ScrnInfoPtr arg, 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; + 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; + +#ifdef ALP_DEBUG + ErrorF("AlpSetClock: nom=%x den=%x ffreq=%d.%03dMHz\n", + num, den, ffreq / 1000, ffreq % 1000); +#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 = { + .x1 = 0, + .y1 = 0, + .x2 = pScrn->virtualX, + .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/hw/xfree86/drivers/video-cirrus/src/alp_hwcurs.c b/hw/xfree86/drivers/video-cirrus/src/alp_hwcurs.c new file mode 100644 index 000000000..c369ffe2f --- /dev/null +++ b/hw/xfree86/drivers/video-cirrus/src/alp_hwcurs.c @@ -0,0 +1,258 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* (c) Itai Nahshon */ + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "compiler.h" + +#include "xf86Pci.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, 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++) { + int m = (-1)<<(x&7); + p1 = p2; + p2 += CURSORWIDTH/8; + for (int 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 = xf86ScreenToScrn(pScreen); +#ifdef ALP_DEBUG + ErrorF("AlpUseHWCursor\n"); +#endif + if (pScrn->bitsPerPixel < 8) + return FALSE; + + return TRUE; +} + +Bool +AlpHWCursorInit(ScreenPtr pScreen, int size) +{ + ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); + 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/hw/xfree86/drivers/video-cirrus/src/alp_i2c.c b/hw/xfree86/drivers/video-cirrus/src/alp_i2c.c new file mode 100644 index 000000000..b52f2c8f9 --- /dev/null +++ b/hw/xfree86/drivers/video-cirrus/src/alp_i2c.c @@ -0,0 +1,131 @@ +/* (c) Itai Nahshon */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "compiler.h" + +#include "xf86Pci.h" + +#include "vgaHW.h" + +#include "cir.h" +#define _ALP_PRIVATE_ +#include "alp.h" + + +static char strI2CBus1[] = "I2C bus 1"; +static char strI2CBus2[] = "I2C bus 2"; + + +/* + * 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 = strI2CBus1; + 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 = strI2CBus2; + I2CPtr->scrnIndex = pScrn->scrnIndex; + I2CPtr->I2CPutBits = AlpI2CPutBits; + I2CPtr->I2CGetBits = AlpI2CGetBits; + I2CPtr->DriverPrivate.ptr = pCir; + + if (!xf86I2CBusInit(I2CPtr)) + return FALSE; + + return TRUE; +} diff --git a/hw/xfree86/drivers/video-cirrus/src/cir.h b/hw/xfree86/drivers/video-cirrus/src/cir.h new file mode 100644 index 000000000..9691db135 --- /dev/null +++ b/hw/xfree86/drivers/video-cirrus/src/cir.h @@ -0,0 +1,99 @@ +/* (c) Itai Nahshon */ + +#ifndef CIR_H +#define CIR_H + +#include "xf86Cursor.h" +#include "xf86i2c.h" +#include +#include + +#include "cir_pcirename.h" + +/* Card-specific driver information */ +#define CIRPTR(p) ((CirPtr)((p)->driverPrivate)) +struct lgRec; +struct alpRec; + +typedef struct { + ScrnInfoPtr pScrn; + CARD32 properties; + pciVideoPtr PciInfo; +#ifndef XSERVER_LIBPCIACCESS + PCITAG PciTag; +#endif + unsigned long 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; + 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)(ScrnInfoPtr arg, 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(ScrnInfoPtr arg, 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/hw/xfree86/drivers/video-cirrus/src/cir_dga.c b/hw/xfree86/drivers/video-cirrus/src/cir_dga.c new file mode 100644 index 000000000..6a50e71fe --- /dev/null +++ b/hw/xfree86/drivers/video-cirrus/src/cir_dga.c @@ -0,0 +1,198 @@ +/* + * 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 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86Pci.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 int Cir_GetViewport(ScrnInfoPtr); +static void Cir_SetViewport(ScrnInfoPtr, int, int, int); + +static +DGAFunctionRec CirDGAFuncs = { + Cir_OpenFramebuffer, + NULL, /* Cir_CloseFramebuffer */ + Cir_SetMode, + Cir_SetViewport, + Cir_GetViewport, + NULL, NULL, NULL, + NULL /* Cir_BlitTransRect */ +}; + + + + +_X_EXPORT Bool +CirDGAInit(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); + 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 = realloc(modes, (num + 1) * sizeof (DGAModeRec)); + if (!newmodes) { + free(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, x, y); + + 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; +} + diff --git a/hw/xfree86/drivers/video-cirrus/src/cir_driver.c b/hw/xfree86/drivers/video-cirrus/src/cir_driver.c new file mode 100644 index 000000000..bc1e4b399 --- /dev/null +++ b/hw/xfree86/drivers/video-cirrus/src/cir_driver.c @@ -0,0 +1,387 @@ +/* + * Driver for CL-GD5480. + * Itai Nahshon. + * + * Support for the CL-GD7548: David Monniaux + * + * This is mainly a cut & paste from the MGA driver. + * Original authors and contributors list include: + * Radoslaw Kapitan, Andrew Vanderstock, Dirk Hohndel, + * David Dawes, Andrew E. Mileski, Leonard N. Zubkoff, + * Guy DESBIEF + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* All drivers should typically include these */ +#include "xf86.h" +#include "xf86_OSproc.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); + +#define CIR_VERSION 4000 +#define CIR_NAME "CIRRUS" +#define CIR_DRIVER_NAME "cirrus" +#define CIR_MAJOR_VERSION PACKAGE_VERSION_MAJOR +#define CIR_MINOR_VERSION PACKAGE_VERSION_MINOR +#define CIR_PATCHLEVEL PACKAGE_VERSION_PATCHLEVEL + +/* + * This contains the functions needed by the server after loading the + * driver module. It must be supplied, and gets added to the driver list by + * the Module Setup function in the dynamic case. In the static case a + * reference to this is compiled in, and this requires that the name of + * this DriverRec be an upper-case version of the driver name. + */ + +_X_EXPORT DriverRec CIRRUS = { + CIR_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" }, + { PCI_CHIP_GD7555, "CL-GD7555" }, + { PCI_CHIP_GD7556, "CL-GD7556" }, + {-1, NULL } +}; + +/* List of PCI chipset names */ +_X_EXPORT 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 }, + { PCI_CHIP_GD7555, PCI_CHIP_GD7555, RES_SHARED_VGA }, + { PCI_CHIP_GD7556, PCI_CHIP_GD7556, RES_SHARED_VGA }, + { -1, -1, RES_UNDEFINED} +}; + +#ifdef XFree86LOADER + +static MODULESETUPPROTO(cirSetup); + +static XF86ModuleVersionInfo cirVersRec = +{ + "cirrus", + MODULEVENDORSTRING, + MODINFOSTRING1, + MODINFOSTRING2, + XORG_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. + */ +_X_EXPORT 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); + + 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: + return LgAvailableOptions(chipid); + + default: + return AlpAvailableOptions(chipid); + } +} + +static Bool +CIRProbe(DriverPtr drv, int flags) +{ + int i; + GDevPtr *devSections; + pciVideoPtr pPci; + int *usedChips; + int numDevSections; + int numUsed; + Bool foundScreen = FALSE; + ScrnInfoPtr pScrn; + +#ifdef CIR_DEBUG + ErrorF("CirProbe\n"); +#endif + + if ((numDevSections = xf86MatchDevice(CIR_DRIVER_NAME, + &devSections)) <= 0) { + return FALSE; + } + +#ifndef XSERVER_LIBPCIACCESS + 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; + } +#endif + + numUsed = xf86MatchPciInstances(CIR_NAME, PCI_VENDOR_CIRRUS, + CIRChipsets, CIRPciChipsets, devSections, + numDevSections, drv, &usedChips); + /* Free it since we don't need that list after this */ + if (numUsed <= 0) { + free(devSections); + 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]); + +#ifdef XSERVER_LIBPCIACCESS + if (pci_device_has_kernel_driver(pPci)) { + xf86DrvMsg(0, X_ERROR, + "cirrus: The PCI device 0x%x at %2.2d@%2.2d:%2.2d:%1.1d has a kernel module claiming it.\n", + pPci->device_id, pPci->bus, pPci->domain, pPci->dev, pPci->func); + xf86DrvMsg(0, X_ERROR, + "cirrus: This driver cannot operate until it has been unloaded.\n"); + xf86UnclaimPciSlot(pPci, devSections[0]); + free(devSections); + return FALSE; + } +#endif + pScrn = NULL; + if (pPci && (PCI_DEV_DEVICE_ID(pPci) == PCI_CHIP_GD5462 || + PCI_DEV_DEVICE_ID(pPci) == PCI_CHIP_GD5464 || + PCI_DEV_DEVICE_ID(pPci) == PCI_CHIP_GD5464BD || + PCI_DEV_DEVICE_ID(pPci) == PCI_CHIP_GD5465)) { + pScrn = LgProbe(usedChips[i]); + } else { + pScrn = AlpProbe(usedChips[i]); + } + + if (pScrn) { + foundScreen = TRUE; + /* Fill in what we can of the ScrnInfoRec */ + pScrn->driverVersion = CIR_VERSION; + pScrn->driverName = CIR_DRIVER_NAME; + pScrn->name = CIR_NAME; + pScrn->Probe = NULL; + } + } + free(devSections); + free(usedChips); + + return foundScreen; +} + +/* + * Map the framebuffer and MMIO memory. + */ + +_X_EXPORT Bool +CirMapMem(CirPtr pCir, int scrnIndex) +{ +#ifdef CIR_DEBUG + ErrorF("CirMapMem\n"); +#endif + + /* + * Map the frame buffer. + */ + if (pCir->FbMapSize) { + +#ifndef XSERVER_LIBPCIACCESS + + pCir->FbBase = xf86MapPciMem(scrnIndex, VIDMEM_FRAMEBUFFER, + pCir->PciTag, pCir->FbAddress, + pCir->FbMapSize); + if (pCir->FbBase == NULL) + return FALSE; + +#else + void** result = (void**)&pCir->FbBase; + int err = pci_device_map_range(pCir->PciInfo, + pCir->FbAddress, + pCir->FbMapSize, + PCI_DEV_MAP_FLAG_WRITABLE | + PCI_DEV_MAP_FLAG_WRITE_COMBINE, + result); + + if (err) + return FALSE; +#endif + } + +#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 { + +#ifndef XSERVER_LIBPCIACCESS + /* + * 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, VIDMEM_MMIO, pCir->PciTag, + pCir->IOAddress, pCir->IoMapSize); + if (pCir->IOBase == NULL) + return FALSE; + +#else + void** result = (void**)&pCir->IOBase; + int err = pci_device_map_range(pCir->PciInfo, + pCir->IOAddress, + pCir->IoMapSize, + PCI_DEV_MAP_FLAG_WRITABLE, + result); + + if (err) + return FALSE; + +#endif + } + +#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. + */ + +_X_EXPORT Bool +CirUnmapMem(CirPtr pCir, int scrnIndex) +{ +#ifdef CIR_DEBUG + ErrorF("CirUnmapMem\n"); +#endif + + if (pCir->IOBase != NULL) { + /* + * Unmap IO registers to virtual address space + */ +#ifndef XSERVER_LIBPCIACCESS + xf86UnMapVidMem(scrnIndex, (pointer)pCir->IOBase, pCir->IoMapSize); +#else + pci_device_unmap_range(pCir->PciInfo, (pointer)pCir->IOBase, pCir->IoMapSize); +#endif + pCir->IOBase = NULL; + } + +#ifndef XSERVER_LIBPCIACCESS + xf86UnMapVidMem(scrnIndex, (pointer)pCir->FbBase, pCir->FbMapSize); +#else + pci_device_unmap_range(pCir->PciInfo, (pointer)pCir->FbBase, pCir->FbMapSize); +#endif + pCir->FbBase = NULL; + return TRUE; +} + +_X_EXPORT void +cirProbeDDC(ScrnInfoPtr pScrn, int index) +{ + vbeInfoPtr pVbe; + + if (xf86LoadSubModule(pScrn, "vbe")) { + pVbe = VBEInit(NULL,index); + ConfiguredMonitor = vbeDoEDID(pVbe, NULL); + vbeFree(pVbe); + } +} diff --git a/hw/xfree86/drivers/video-cirrus/src/cir_pcirename.h b/hw/xfree86/drivers/video-cirrus/src/cir_pcirename.h new file mode 100644 index 000000000..5c47f990b --- /dev/null +++ b/hw/xfree86/drivers/video-cirrus/src/cir_pcirename.h @@ -0,0 +1,148 @@ +/* + * Copyright 2007 George Sapountzis + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * Macros for porting drivers from legacy xfree86 PCI code to the pciaccess + * library. The main purpose being to facilitate source code compatibility. + */ + +#ifndef CIRPCIRENAME_H +#define CIRPCIRENAME_H + +enum region_type { + REGION_MEM, + REGION_IO +}; + +#include "xf86Module.h" + +#ifndef XSERVER_LIBPCIACCESS + +/* pciVideoPtr */ +#define PCI_DEV_VENDOR_ID(_pcidev) ((_pcidev)->vendor) +#define PCI_DEV_DEVICE_ID(_pcidev) ((_pcidev)->chipType) +#define PCI_DEV_REVISION(_pcidev) ((_pcidev)->chipRev) + +#define PCI_SUB_VENDOR_ID(_pcidev) ((_pcidev)->subsysVendor) +#define PCI_SUB_DEVICE_ID(_pcidev) ((_pcidev)->subsysCard) + +#define PCI_DEV_TAG(_pcidev) pciTag((_pcidev)->bus, \ + (_pcidev)->device, \ + (_pcidev)->func) +#define PCI_DEV_BUS(_pcidev) ((_pcidev)->bus) +#define PCI_DEV_DEV(_pcidev) ((_pcidev)->device) +#define PCI_DEV_FUNC(_pcidev) ((_pcidev)->func) + +/* pciConfigPtr */ +#define PCI_CFG_TAG(_pcidev) (((pciConfigPtr)(_pcidev)->thisCard)->tag) +#define PCI_CFG_BUS(_pcidev) (((pciConfigPtr)(_pcidev)->thisCard)->busnum) +#define PCI_CFG_DEV(_pcidev) (((pciConfigPtr)(_pcidev)->thisCard)->devnum) +#define PCI_CFG_FUNC(_pcidev) (((pciConfigPtr)(_pcidev)->thisCard)->funcnum) + +/* region addr: xfree86 uses different fields for memory regions and I/O ports */ +#define PCI_REGION_BASE(_pcidev, _b, _type) \ + (((_type) == REGION_MEM) ? (_pcidev)->memBase[(_b)] \ + : (_pcidev)->ioBase[(_b)]) + +/* region size: xfree86 uses the log2 of the region size, + * but with zero meaning no region, not size of one XXX */ +#define PCI_REGION_SIZE(_pcidev, _b) \ + (((_pcidev)->size[(_b)] > 0) ? (1 << (_pcidev)->size[(_b)]) : 0) + +/* read/write PCI configuration space */ +#define PCI_READ_BYTE(_pcidev, _value_ptr, _offset) \ + *(_value_ptr) = pciReadByte(PCI_CFG_TAG(_pcidev), (_offset)) + +#define PCI_READ_LONG(_pcidev, _value_ptr, _offset) \ + *(_value_ptr) = pciReadLong(PCI_CFG_TAG(_pcidev), (_offset)) + +#define PCI_WRITE_LONG(_pcidev, _value, _offset) \ + pciWriteLong(PCI_CFG_TAG(_pcidev), (_offset), (_value)) + +#else /* XSERVER_LIBPCIACCESS */ + +typedef struct pci_device *pciVideoPtr; + +#define PCI_DEV_VENDOR_ID(_pcidev) ((_pcidev)->vendor_id) +#define PCI_DEV_DEVICE_ID(_pcidev) ((_pcidev)->device_id) +#define PCI_DEV_REVISION(_pcidev) ((_pcidev)->revision) + +#define PCI_SUB_VENDOR_ID(_pcidev) ((_pcidev)->subvendor_id) +#define PCI_SUB_DEVICE_ID(_pcidev) ((_pcidev)->subdevice_id) + +/* pci-rework functions take a 'pci_device' parameter instead of a tag */ +#define PCI_DEV_TAG(_pcidev) (_pcidev) + +/* PCI_DEV macros, typically used in printf's, add domain ? XXX */ +#define PCI_DEV_BUS(_pcidev) ((_pcidev)->bus) +#define PCI_DEV_DEV(_pcidev) ((_pcidev)->dev) +#define PCI_DEV_FUNC(_pcidev) ((_pcidev)->func) + +/* pci-rework functions take a 'pci_device' parameter instead of a tag */ +#define PCI_CFG_TAG(_pcidev) (_pcidev) + +/* PCI_CFG macros, typically used in DRI init, contain the domain */ +#define PCI_CFG_BUS(_pcidev) (((_pcidev)->domain << 8) | \ + (_pcidev)->bus) +#define PCI_CFG_DEV(_pcidev) ((_pcidev)->dev) +#define PCI_CFG_FUNC(_pcidev) ((_pcidev)->func) + +#define PCI_REGION_BASE(_pcidev, _b, _type) ((_pcidev)->regions[(_b)].base_addr) +#define PCI_REGION_SIZE(_pcidev, _b) ((_pcidev)->regions[(_b)].size) + +#define PCI_READ_BYTE(_pcidev, _value_ptr, _offset) \ + pci_device_cfg_read_u8((_pcidev), (_value_ptr), (_offset)) + +#define PCI_READ_LONG(_pcidev, _value_ptr, _offset) \ + pci_device_cfg_read_u32((_pcidev), (_value_ptr), (_offset)) + +#define PCI_WRITE_LONG(_pcidev, _value, _offset) \ + pci_device_cfg_write_u32((_pcidev), (_value), (_offset)) + +#endif /* XSERVER_LIBPCIACCESS */ + +#ifndef _XF86_PCIINFO_H + +#define PCI_VENDOR_CIRRUS 0x1013 +/* Cirrus Logic */ +#define PCI_CHIP_GD7548 0x0038 +#define PCI_CHIP_GD7555 0x0040 +#define PCI_CHIP_GD7556 0x004C +#define PCI_CHIP_GD5430 0x00A0 +#define PCI_CHIP_GD5434_4 0x00A4 +#define PCI_CHIP_GD5434_8 0x00A8 +#define PCI_CHIP_GD5436 0x00AC +#define PCI_CHIP_GD5446 0x00B8 +#define PCI_CHIP_GD5480 0x00BC +#define PCI_CHIP_GD5462 0x00D0 +#define PCI_CHIP_GD5464 0x00D4 +#define PCI_CHIP_GD5464BD 0x00D5 +#define PCI_CHIP_GD5465 0x00D6 +#define PCI_CHIP_6729 0x1100 +#define PCI_CHIP_6832 0x1110 +#define PCI_CHIP_GD7542 0x1200 +#define PCI_CHIP_GD7543 0x1202 +#define PCI_CHIP_GD7541 0x1204 + +#endif +#endif /* CIRPCIRENAME_H */ diff --git a/hw/xfree86/drivers/video-cirrus/src/cir_shadow.c b/hw/xfree86/drivers/video-cirrus/src/cir_shadow.c new file mode 100644 index 000000000..377c9fb5f --- /dev/null +++ b/hw/xfree86/drivers/video-cirrus/src/cir_shadow.c @@ -0,0 +1,288 @@ +/* + Copyright (c) 1999,2000 The XFree86 Project Inc. + based on code written by Mark Vojkovich +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86Pci.h" +#include "shadowfb.h" +#include "servermd.h" +#include "cir.h" +#include "alp.h" + +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) + +_X_EXPORT void +cirRefreshArea(ScrnInfoPtr pScrn, int num, BoxPtr pbox) +{ + CirPtr pCir = CIRPTR(pScrn); + unsigned char *src, *dst; + + int Bpp = pScrn->bitsPerPixel >> 3; + int FBPitch = BitmapBytePad(pScrn->displayWidth * pScrn->bitsPerPixel); + + while(num--) { + int x1 = MAX(pbox->x1, 0); + int y1 = MAX(pbox->y1, 0); + int x2 = MIN(pbox->x2, pScrn->virtualX); + int y2 = MIN(pbox->y2, pScrn->virtualY); + + int width = (x2 - x1) * Bpp; + int height = y2 - y1; + + if (width <= 0 || height <= 0) + continue; + + src = pCir->ShadowPtr + (y1 * pCir->ShadowPitch) + (x1 * Bpp); + dst = pCir->FbBase + (y1 * FBPitch) + (x1 * Bpp); + + while(height--) { + memcpy(dst, src, width); + dst += FBPitch; + src += pCir->ShadowPitch; + } + + pbox++; + } +} + +_X_EXPORT void +cirPointerMoved(ScrnInfoPtr pScrn, int x, int y) +{ + 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)(pScrn, newX, newY); +} + +_X_EXPORT void +cirRefreshArea8(ScrnInfoPtr pScrn, int num, BoxPtr pbox) +{ + CirPtr pCir = CIRPTR(pScrn); + + int dstPitch = pScrn->displayWidth; + int srcPitch = -pCir->rotate * pCir->ShadowPitch; + + while(num--) { + int x1 = MAX(pbox->x1, 0); + int y1 = MAX(pbox->y1, 0); + int x2 = MIN(pbox->x2, pScrn->virtualX); + int y2 = MIN(pbox->y2, pScrn->virtualY); + int width, height; + CARD8 *dstPtr, *srcPtr; + + width = x2 - x1; + y1 = y1 & ~3; + y2 = (y2 + 3) & ~3; + height = (y2 - y1) / 4; /* in dwords */ + + if (width <= 0 || height <= 0) + continue; + + if(pCir->rotate == 1) { + dstPtr = pCir->FbBase + + (x1 * dstPitch) + pScrn->virtualX - y2; + srcPtr = pCir->ShadowPtr + ((1 - y2) * srcPitch) + x1; + } else { + dstPtr = pCir->FbBase + + ((pScrn->virtualY - x2) * dstPitch) + y1; + srcPtr = pCir->ShadowPtr + (y1 * srcPitch) + x2 - 1; + } + + while(width--) { + CARD8 *src = srcPtr; + CARD32 *dst = (CARD32*)dstPtr; + int 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++; + } +} + + +_X_EXPORT void +cirRefreshArea16(ScrnInfoPtr pScrn, int num, BoxPtr pbox) +{ + CirPtr pCir = CIRPTR(pScrn); + + int dstPitch = pScrn->displayWidth; + int srcPitch = -pCir->rotate * pCir->ShadowPitch >> 1; + + while(num--) { + int x1 = MAX(pbox->x1, 0); + int y1 = MAX(pbox->y1, 0); + int x2 = MIN(pbox->x2, pScrn->virtualX); + int y2 = MIN(pbox->y2, pScrn->virtualY); + int width, height; + CARD16 *dstPtr, *srcPtr; + + width = x2 - x1; + y1 = y1 & ~1; + y2 = (y2 + 1) & ~1; + height = (y2 - y1) / 2; /* in dwords */ + + if (width <= 0 || height <= 0) + continue; + + if(pCir->rotate == 1) { + dstPtr = (CARD16*)pCir->FbBase + + (x1 * dstPitch) + pScrn->virtualX - y2; + srcPtr = (CARD16*)pCir->ShadowPtr + + ((1 - y2) * srcPitch) + x1; + } else { + dstPtr = (CARD16*)pCir->FbBase + + ((pScrn->virtualY - x2) * dstPitch) + y1; + srcPtr = (CARD16*)pCir->ShadowPtr + + (y1 * srcPitch) + x2 - 1; + } + + while(width--) { + CARD16 *src = srcPtr; + CARD32 *dst = (CARD32*)dstPtr; + int count = height; + while(count--) { + *(dst++) = src[0] | (src[srcPitch] << 16); + src += srcPitch * 2; + } + srcPtr += pCir->rotate; + dstPtr += dstPitch; + } + + pbox++; + } +} + + +/* this one could be faster */ +_X_EXPORT void +cirRefreshArea24(ScrnInfoPtr pScrn, int num, BoxPtr pbox) +{ + CirPtr pCir = CIRPTR(pScrn); + + int dstPitch = BitmapBytePad(pScrn->displayWidth * 24); + int srcPitch = -pCir->rotate * pCir->ShadowPitch; + + while(num--) { + int x1 = MAX(pbox->x1, 0); + int y1 = MAX(pbox->y1, 0); + int x2 = MIN(pbox->x2, pScrn->virtualX); + int y2 = MIN(pbox->y2, pScrn->virtualY); + int width, height; + CARD8 *dstPtr, *srcPtr; + + width = x2 - x1; + y1 = y1 & ~3; + y2 = (y2 + 3) & ~3; + height = (y2 - y1) / 4; /* blocks of 3 dwords */ + + if (width <= 0 || height <= 0) + continue; + + if(pCir->rotate == 1) { + dstPtr = pCir->FbBase + + (x1 * dstPitch) + ((pScrn->virtualX - y2) * 3); + srcPtr = pCir->ShadowPtr + ((1 - y2) * srcPitch) + (x1 * 3); + } else { + dstPtr = pCir->FbBase + + ((pScrn->virtualY - x2) * dstPitch) + (y1 * 3); + srcPtr = pCir->ShadowPtr + (y1 * srcPitch) + (x2 * 3) - 3; + } + + while(width--) { + CARD8 *src = srcPtr; + CARD32 *dst = (CARD32*)dstPtr; + int 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++; + } +} + +_X_EXPORT void +cirRefreshArea32(ScrnInfoPtr pScrn, int num, BoxPtr pbox) +{ + CirPtr pCir = CIRPTR(pScrn); + + int dstPitch = pScrn->displayWidth; + int srcPitch = -pCir->rotate * pCir->ShadowPitch >> 2; + + while(num--) { + int x1 = MAX(pbox->x1, 0); + int y1 = MAX(pbox->y1, 0); + int x2 = MIN(pbox->x2, pScrn->virtualX); + int y2 = MIN(pbox->y2, pScrn->virtualY); + + int width = x2 - x1; + int height = y2 - y1; + + CARD32 *dstPtr, *srcPtr; + + if (width <= 0 || height <= 0) + continue; + + if(pCir->rotate == 1) { + dstPtr = (CARD32*)pCir->FbBase + + (x1 * dstPitch) + pScrn->virtualX - y2; + srcPtr = (CARD32*)pCir->ShadowPtr + + ((1 - y2) * srcPitch) + x1; + } else { + dstPtr = (CARD32*)pCir->FbBase + + ((pScrn->virtualY - x2) * dstPitch) + y1; + srcPtr = (CARD32*)pCir->ShadowPtr + + (y1 * srcPitch) + x2 - 1; + } + + while(width--) { + CARD32 *src = srcPtr; + CARD32 *dst = dstPtr; + int count = height; + while(count--) { + *(dst++) = *src; + src += srcPitch; + } + srcPtr += pCir->rotate; + dstPtr += dstPitch; + } + + pbox++; + } +} + + + diff --git a/hw/xfree86/drivers/video-cirrus/src/lg.h b/hw/xfree86/drivers/video-cirrus/src/lg.h new file mode 100644 index 000000000..1ced8154b --- /dev/null +++ b/hw/xfree86/drivers/video-cirrus/src/lg.h @@ -0,0 +1,105 @@ +/* + * 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 + */ + +#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, + 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; + CARD16 RIFCtrl, RACCtrl; + 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_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/hw/xfree86/drivers/video-cirrus/src/lg_blit.h b/hw/xfree86/drivers/video-cirrus/src/lg_blit.h new file mode 100644 index 000000000..b5edd90f7 --- /dev/null +++ b/hw/xfree86/drivers/video-cirrus/src/lg_blit.h @@ -0,0 +1,179 @@ +#ifndef __LG_BLIT_H +#define __LG_BLIT_H + +/* + * bitBLT acceleration for CL-GD546x -- The Laguna 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. + */ + +/* This header file defines the necessary structures, constants, 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_BLIT_H */ diff --git a/hw/xfree86/drivers/video-cirrus/src/lg_driver.c b/hw/xfree86/drivers/video-cirrus/src/lg_driver.c new file mode 100644 index 000000000..e840b76ae --- /dev/null +++ b/hw/xfree86/drivers/video-cirrus/src/lg_driver.c @@ -0,0 +1,2214 @@ +/* + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define EXPERIMENTAL + +/* + * All drivers should typically include these. + */ +#include "xf86.h" +#include "xf86_OSproc.h" + +/* + * All drivers need this. + */ + +#include "compiler.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" + +/* + * All drivers initialising the SW cursor need this. + */ +#include "mipointer.h" + +/* + * Need this for inputInfo. + */ +#include "inputstr.h" + +#include "micmap.h" + +/* + * Needed by the shadowfb. + */ +#include "shadowfb.h" + +#include "xf86int10.h" + +#include "fb.h" + +#include "xf86DDC.h" + +#undef LG_DEBUG + +#include "cir.h" +#define _LG_PRIVATE_ +#include "lg.h" + +#include "xf86xv.h" +#include + +/* + * Forward definitions for the functions that make up the driver. + */ + +/* + * Mandatory functions + */ +Bool LgPreInit(ScrnInfoPtr pScrn, int flags); +Bool LgScreenInit(ScreenPtr pScreen, int argc, char **argv); +Bool LgEnterVT(ScrnInfoPtr arg); +void LgLeaveVT(ScrnInfoPtr arg); +static Bool LgCloseScreen(ScreenPtr pScreen); +static Bool LgSaveScreen(ScreenPtr pScreen, Bool mode); + +/* + * Required if the driver supports mode switching. + */ +Bool LgSwitchMode(ScrnInfoPtr arg, DisplayModePtr mode); +/* + * Required if the driver supports moving the viewport. + */ +void LgAdjustFrame(ScrnInfoPtr arg, int x, int y); + +/* + * Optional functions + */ +void LgFreeScreen(ScrnInfoPtr arg); +ModeStatus LgValidMode(ScrnInfoPtr arg, DisplayModePtr mode, + Bool verbose, int flags); + +/* + * Internal 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 function in the dynamic case. In the static + * case a reference to this is compiled in, and this requires that the + * name of this DriverRec be an upper-case version of the driver name. + */ + +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/4 bpp 8 bpp 15/16 bpp 24 bpp 32 bpp + */ +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 }; + +/* + * We're rather use skinny tiles, so put all of them at the head of + * the table. + */ +LgLineDataRec LgLineData[] = { + { 5, 640, 0}, + { 8, 1024, 0}, + {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}, +/* + * Sentinel to indicate end of table. + */ + {-1, -1, -1} +}; + +static int LgLinePitches[4][11] = { +/* + * 8 bpp + */ + { 640, 1024, 1280, 1664, 2048, 2560, 3328, 4096, 5120, 6656, 0 }, +/* + * 16 bpp + */ + { 320, 512, 640, 832, 1024, 1280, 1664, 2048, 2560, 3328, 0 }, +/* + * 24 bpp + */ + { 213, 341, 426, 554, 682, 853, 1109, 1365, 1706, 2218, 0 }, +/* + * 32 bpp + */ + { 160, 256, 320, 416, 512, 640, 832, 1024, 1280, 1664, 0 } +}; + +#ifdef XFree86LOADER + +#define LG_MAJOR_VERSION 1 +#define LG_MINOR_VERSION 0 +#define LG_PATCHLEVEL 0 + +static XF86ModuleVersionInfo lgVersRec = +{ + "cirrus_laguna", + MODULEVENDORSTRING, + MODINFOSTRING1, + MODINFOSTRING2, + XORG_VERSION_CURRENT, + LG_MAJOR_VERSION, LG_MINOR_VERSION, LG_PATCHLEVEL, +/* + * This is a video driver. + */ + ABI_CLASS_VIDEODRV, + 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. + */ +_X_EXPORT XF86ModuleData cirrus_lagunaModuleData = { + &lgVersRec, + NULL, + NULL +}; + +#endif /* XFree86LOADER */ + +_X_EXPORT const OptionInfoRec * +LgAvailableOptions(int chipid) { + return LgOptions; +} + +_X_EXPORT 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 = XNFcallocarray(sizeof(CirRec), 1); + ((CirPtr) pScrn->driverPrivate)->chip.lg = + XNFcallocarray(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; + free(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 scratch pad registers contain, among other things, + * the amount of installed RDRAM for 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; + + 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, pCir->I2CPtr1); + if (!MonInfo) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to obtain EDID.\n"); + goto unmap_out; + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "I2C Monitor info: %p\n", (void *)MonInfo); + xf86PrintEDID(MonInfo); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "end of I2C Monitor info\n\n"); + + 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; + const 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; + + /* + * Allocate a vgaHWRec. + */ + if (!vgaHWGetHWRec(pScrn)) + return FALSE; + + hwp = VGAHWPTR(pScrn); + vgaHWSetStdFuncs(hwp); + vgaHWGetIOBase(hwp); + + /* + * Allocate the LgRec driverPrivate. + */ + if (!LgGetRec(pScrn)) + return FALSE; + + pCir = CIRPTR(pScrn); + pCir->pScrn = pScrn; + pCir->PIOReg = 0x3CE; /* was 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); +#ifndef XSERVER_LIBPCIACCESS + pCir->PciTag = pciTag(PCI_DEV_BUS(pCir->PciInfo), + PCI_DEV_DEV(pCir->PciInfo), PCI_DEV_FUNC(pCir->PciInfo)); +#endif + + if (xf86LoadSubModule(pScrn, "int10")) { + xf86Int10InfoPtr int10InfoPtr; + + 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. + * We support both 24 bpp and 32 bpp layouts, so indicate that. + */ + if (!xf86SetDepthBpp(pScrn, 0, 0, 0, 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 = malloc(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 = PCI_DEV_REVISION(pCir->PciInfo); + } + + /* + * Cirrus Logic 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 (PCI_REGION_BASE(pCir->PciInfo, + fbPCIReg, + REGION_MEM) != 0) { + pCir->FbAddress = PCI_REGION_BASE(pCir->PciInfo, + fbPCIReg, + REGION_MEM) & + 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 (PCI_REGION_BASE(pCir->PciInfo, + ioPCIReg, + REGION_MEM) != 0) { + pCir->IOAddress = PCI_REGION_BASE(pCir->PciInfo, + ioPCIReg, + REGION_MEM) & + 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; + /* + * 16K for moment, will increase. + */ + pCir->IoMapSize = 0x4000; + +#ifndef XSERVER_LIBPCIACCESS + 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; + } +#endif + if (!xf86LoadSubModule(pScrn, "ddc")) { + LgFreeRec(pScrn); + return FALSE; + } + +#if LGuseI2C + if (!xf86LoadSubModule(pScrn, "i2c")) { + LgFreeRec(pScrn); + return FALSE; + } +#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")) { + /* + * Acceleration 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. + */ + /* + * XXX Guess, need to check this. + */ + pCir->MinClock = 12000; + 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 = XNFcallocarray(sizeof(ClockRange), 1); + clockRanges->next = NULL; + clockRanges->minClock = pCir->MinClock; + clockRanges->maxClock = pCir->MaxClock; + /* + * programmable + */ + clockRanges->clockIndex = -1; + /* + * XXX Check this. + */ + clockRanges->interlaceAllowed = FALSE; + /* + * XXX Check this. + */ + clockRanges->doubleScanAllowed = FALSE; + /* + * XXX Check this. + */ + clockRanges->doubleScanAllowed = FALSE; + /* + * XXX Check this. + */ + clockRanges->doubleScanAllowed = FALSE; + 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, + /* + * Any virtual height is allowed. + */ + 0, + 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 fb module. + */ + if (xf86LoadSubModule(pScrn, "fb") == NULL) { + LgFreeRec(pScrn); + return FALSE; + } + + /* + * Use shadowfb for acceleration. + */ + if (!pCir->NoAccel) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Falling back to shadowfb\n"); + pCir->NoAccel = TRUE; + pCir->shadowFB = TRUE; + } + + /* + * Load RAMDAC if needed. + */ + if (pCir->HWCursor) { + if (!xf86LoadSubModule(pScrn, "ramdac")) { + LgFreeRec(pScrn); + return FALSE; + } + } + + if (pCir->shadowFB) { + if (!xf86LoadSubModule(pScrn, "shadowfb")) { + LgFreeRec(pScrn); + return FALSE; + } + } + + 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[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); + + pCir->chip.lg->ModeReg.RIFCtrl = + pCir->chip.lg->SavedReg.RIFCtrl = memrw(0x200); + + pCir->chip.lg->ModeReg.RACCtrl = + pCir->chip.lg->SavedReg.RACCtrl = memrw(0x202); +} + +/* + * 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; + 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 + hwp->IOBase = 0x3D0; + hwp->ModeReg.MiscOutReg |= 0x01; +/* + * Mono address + */ +#if 0 + 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: + */ + /* + * 10 + */ + pCir->chip.lg->ModeReg.DTTC = + (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) | + (0x0022); + } 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. Fetches 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); + } + } + + /* + * Programme 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, 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); + + memww(0x200, lgReg->RIFCtrl); + memww(0x202, lgReg->RACCtrl); +} + +/* + * Restore the initial (text) mode. + */ +static void +LgRestore(ScrnInfoPtr pScrn) +{ + vgaHWPtr hwp; + vgaRegPtr vgaReg; + CirPtr pCir; + LgRegPtr lgReg; + +#ifdef LG_DEBUG + ErrorF("LgRestore pScrn = %p\n", (void *) 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); +} + +/* + * This gets called at the start of each server generation + */ +/* + * Mandatory + */ +Bool +LgScreenInit(ScreenPtr pScreen, int argc, char **argv) +{ + /* + * The vgaHW references will disappear one day + */ + ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); + vgaHWPtr hwp; + CirPtr pCir; + int i, ret; + VisualPtr visual; + int displayWidth, width, height; + unsigned char * FbBase = NULL; + +#ifdef LG_DEBUG + ErrorF("LgScreenInit\n"); +#endif + + hwp = VGAHWPTR(pScrn); + + /* + * Standard 64k VGA window + */ + hwp->MapSize = 0x10000; + + 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; + + /* + * Make things beautiful. + */ + LgSaveScreen(pScreen, SCREEN_SAVER_ON); + + /* + * Set the viewport. + */ + LgAdjustFrame(pScrn, pScrn->frameX0, pScrn->frameY0); + + /* + * 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 = malloc(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(pScrn->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); + + /* + * Set initial black & white colourmap indices. + */ + xf86SetBlackWhitePixels(pScreen); + +#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()); + + /* + * Initialize HW cursor layer. + */ + if (pCir->HWCursor) { + 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; + + { + XF86VideoAdaptorPtr *ptr; + int n; + + n = xf86XVListGenericAdaptors(pScrn, &ptr); + if (n) + xf86XVScreenInit(pScreen, ptr, n); + } + + /* + * 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(ScrnInfoPtr pScrn, DisplayModePtr mode) +{ + return LgModeInit(pScrn, 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(ScrnInfoPtr pScrn, int x, int y) { + 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? + */ + miPointerGetPosition(inputInfo.pointer, &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(ScrnInfoPtr pScrn) +{ + 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(ScrnInfoPtr pScrn) { + 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(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); + 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->CursorInfoRec) + xf86DestroyCursorInfoRec(pCir->CursorInfoRec); + pCir->CursorInfoRec = NULL; + if (pCir->DGAModes) + free(pCir->DGAModes); + pCir->DGAnumModes = 0; + pCir->DGAModes = NULL; + + pScrn->vtSema = FALSE; + + pScreen->CloseScreen = pCir->CloseScreen; + return (*pScreen->CloseScreen)(pScreen); +} + +/* + * Free up any persistent data structures. + */ +/* + * Optional + */ +void +LgFreeScreen(ScrnInfoPtr pScrn) +{ +#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(pScrn); + LgFreeRec(pScrn); +} + +/* + * Checks if a mode is suitable for the selected chipset. + */ +/* + * Optional + */ +ModeStatus +LgValidMode(ScrnInfoPtr arg, 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(xf86ScreenToScrn(pScreen)); + ScrnInfoPtr pScrn = NULL; + Bool unblank; + + unblank = xf86IsUnblank(mode); + + if (pScreen != NULL) + pScrn = xf86ScreenToScrn(pScreen); + + 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; +} + +/* + * LgDisplayPowerManagementSet -- + * + * 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/hw/xfree86/drivers/video-cirrus/src/lg_hwcurs.c b/hw/xfree86/drivers/video-cirrus/src/lg_hwcurs.c new file mode 100644 index 000000000..7d085ec9f --- /dev/null +++ b/hw/xfree86/drivers/video-cirrus/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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "compiler.h" + +#include "xf86Pci.h" + +#include "vgaHW.h" + +#include "cir.h" +#define _LG_PRIVATE_ +#include "lg.h" +#include "lg_blit.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 boundary */ + /* Destination */ + LgSETMDSTXY(pLg->HWCursorImageX+pLg->HWCursorTileWidth, pLg->HWCursorImageY); + + /* Set the source pitch. 0 means that, worst case, the source is + aligned only on a byte boundary */ + 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 + aligned only on a byte boundary */ + 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; + + 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 weird 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 { + int 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 = xf86ScreenToScrn(pScreen); + +#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 = xf86ScreenToScrn(pScreen); + 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/hw/xfree86/drivers/video-cirrus/src/lg_i2c.c b/hw/xfree86/drivers/video-cirrus/src/lg_i2c.c new file mode 100644 index 000000000..44387ffe3 --- /dev/null +++ b/hw/xfree86/drivers/video-cirrus/src/lg_i2c.c @@ -0,0 +1,109 @@ +/* (c) Itai Nahshon */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "compiler.h" + +#include "xf86Pci.h" + +#include "vgaHW.h" + +#include "cir.h" +#define _LG_PRIVATE_ +#include "lg.h" + + +static char strI2CBus1[] = "I2C bus 1"; +static char strI2CBus2[] = "I2C bus 2"; + + +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 = strI2CBus1; + 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 = strI2CBus2; + I2CPtr->scrnIndex = pScrn->scrnIndex; + I2CPtr->I2CPutBits = LgI2CPutBits; + I2CPtr->I2CGetBits = LgI2CGetBits; + I2CPtr->DriverPrivate.ptr = pCir; + + if (!xf86I2CBusInit(I2CPtr)) + return FALSE; + + return TRUE; +} +