summaryrefslogtreecommitdiff
path: root/driver/xf86-video-trident/src/trident_dac.c
diff options
context:
space:
mode:
Diffstat (limited to 'driver/xf86-video-trident/src/trident_dac.c')
-rw-r--r--driver/xf86-video-trident/src/trident_dac.c1277
1 files changed, 1277 insertions, 0 deletions
diff --git a/driver/xf86-video-trident/src/trident_dac.c b/driver/xf86-video-trident/src/trident_dac.c
new file mode 100644
index 000000000..1324ddfc1
--- /dev/null
+++ b/driver/xf86-video-trident/src/trident_dac.c
@@ -0,0 +1,1277 @@
+/*
+ * Copyright 1992-2003 by Alan Hourihane, North Wales, UK.
+ *
+ * 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.
+ *
+ * ALAN HOURIHANE 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.
+ *
+ * Author: Alan Hourihane, alanh@fairlite.demon.co.uk
+ */
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/trident/trident_dac.c,v 1.79 2003/11/03 05:11:42 tsi Exp $ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "xf86.h"
+#include "xf86_OSproc.h"
+#include "xf86Version.h"
+#include "xf86PciInfo.h"
+#include "xf86Pci.h"
+
+#include "vgaHW.h"
+
+#include "trident.h"
+#include "trident_regs.h"
+
+
+static biosMode bios1[] = {
+ { 640, 480, 0x11 }
+};
+
+static biosMode bios4[] = {
+ { 320, 200, 0xd },
+ { 640, 200, 0xe },
+ { 640, 350, 0x11 },
+ { 640, 480, 0x12 },
+ { 800, 600, 0x5b },
+ { 1024, 768 , 0x5f },
+ { 1280, 1024, 0x63 },
+ { 1600, 1200, 0x65 }
+};
+
+static biosMode bios8[] = {
+ { 320, 200, 0x13 },
+ { 640, 400, 0x5c },
+ { 640, 480, 0x5d },
+ { 720, 480, 0x60 },
+ { 800, 600, 0x5e },
+ { 1024, 768, 0x62 },
+ { 1280, 1024, 0x64 },
+ { 1600, 1200, 0x66 }
+};
+
+static biosMode bios15[] = {
+ { 640, 400, 0x72 },
+ { 640, 480, 0x74 },
+ { 720, 480, 0x70 },
+ { 800, 600, 0x76 },
+ { 1024, 768, 0x78 },
+ { 1280, 1024, 0x7a },
+ { 1600, 1200, 0x7c }
+};
+
+static biosMode bios16[] = {
+ { 640, 400, 0x73 },
+ { 640, 480, 0x75 },
+ { 720, 480, 0x71 },
+ { 800, 600, 0x77 },
+ { 1024, 768, 0x79 },
+ { 1280, 1024, 0x7b },
+ { 1600, 1200, 0x7d }
+};
+
+static biosMode bios24[] = {
+ { 640, 400, 0x6b },
+ { 640, 480, 0x6c },
+ { 720, 480, 0x61 },
+ { 800, 600, 0x6d },
+ { 1024, 768, 0x6e }
+};
+
+static newModes newModeRegs [] = {
+ { 320, 200, 0x13, 0x30 },
+ { 640, 480, 0x13, 0x61 },
+ { 800, 600, 0x13, 0x62 },
+ { 1024, 768, 0x31, 0x63 },
+ { 1280, 1024, 0x7b, 0x64 },
+ { 1400, 1050, 0x11, 0x7b }
+};
+
+int
+TridentFindMode(int xres, int yres, int depth)
+{
+ int xres_s;
+ int i, size;
+ biosMode *mode;
+
+ switch (depth) {
+ case 8:
+ size = sizeof(bios8) / sizeof(biosMode);
+ mode = bios8;
+ break;
+ case 15:
+ size = sizeof(bios15) / sizeof(biosMode);
+ mode = bios15;
+ break;
+ case 16:
+ size = sizeof(bios16) / sizeof(biosMode);
+ mode = bios16;
+ break;
+ case 24:
+ size = sizeof(bios24) / sizeof(biosMode);
+ mode = bios24;
+ break;
+ default:
+ return 0;
+ }
+
+ for (i = 0; i < size; i++) {
+ if (xres <= mode[i].x_res) {
+ xres_s = mode[i].x_res;
+ for (; i < size; i++) {
+ if (mode[i].x_res != xres_s)
+ return mode[i-1].mode;
+ if (yres <= mode[i].y_res)
+ return mode[i].mode;
+ }
+ }
+ }
+ return mode[size - 1].mode;
+}
+
+static void
+TridentFindNewMode(int xres, int yres, CARD8 *gr5a, CARD8 *gr5c)
+{
+ int xres_s;
+ int i, size;
+
+ size = sizeof(newModeRegs) / sizeof(newModes);
+
+ for (i = 0; i < size; i++) {
+ if (xres <= newModeRegs[i].x_res) {
+ xres_s = newModeRegs[i].x_res;
+ for (; i < size; i++) {
+ if (newModeRegs[i].x_res != xres_s
+ || yres <= newModeRegs[i].y_res) {
+ *gr5a = newModeRegs[i].GR5a;
+ *gr5c = newModeRegs[i].GR5c;
+ return;
+ }
+ }
+ }
+ }
+ *gr5a = newModeRegs[size - 1].GR5a;
+ *gr5c = newModeRegs[size - 1].GR5c;
+ return;
+}
+
+static void
+tridentSetBrightnessAndGamma(TRIDENTRegPtr tridentReg,
+ Bool on, double exp,int brightness)
+{
+ int pivots[] = {0,3,15,63,255};
+
+ double slope;
+ double y_0;
+ double x, x_prev = 0, y, y_prev = 0;
+ int i;
+ CARD8 i_slopes[4];
+ CARD8 intercepts[4];
+
+ if (!on) {
+ tridentReg->tridentRegs3C4[0xB4] &= ~0x80;
+ return;
+ }
+
+ for (i = 0; i < 4; i++) {
+ x = pivots[i + 1] / 255.0;
+ y = pow(x,exp);
+ slope = (y - y_prev) / (x - x_prev);
+ y_0 = y - x * slope;
+ {
+#define RND(x) ((((x) - (int) (x)) < 0.5) ? (int)(x) : (int)(x) + 1)
+ int val = slope;
+ if (val > 7)
+ i_slopes[i] = (3 << 4) | (RND(slope) & 0xf);
+ else if (val > 3)
+ i_slopes[i] = (2 << 4) | (RND(slope * 2) & 0xf);
+ else if (val > 1)
+ i_slopes[i] = (1 << 4) | (RND(slope * 4) & 0xf);
+ else
+ i_slopes[i] = (RND(slope * 8) & 0xf);
+#undef RND
+ }
+ intercepts[i] = (char)(y_0 * 256 / 4);
+ x_prev = x;
+ y_prev = y;
+ }
+
+ tridentReg->tridentRegs3C4[0xB4] = 0x80 | i_slopes[0];
+ tridentReg->tridentRegs3C4[0xB5] = i_slopes[1];
+ tridentReg->tridentRegs3C4[0xB6] = i_slopes[2];
+ tridentReg->tridentRegs3C4[0xB7] = i_slopes[3];
+ tridentReg->tridentRegs3C4[0xB8] = (intercepts[0] + brightness);
+ tridentReg->tridentRegs3C4[0xB9] = (intercepts[1] + brightness);
+ tridentReg->tridentRegs3C4[0xBA] = (intercepts[2] + brightness);
+ tridentReg->tridentRegs3C4[0xBB] = (intercepts[3] + brightness);
+}
+
+Bool
+TridentInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
+{
+ TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
+ TRIDENTRegPtr pReg = &pTrident->ModeReg;
+
+ int vgaIOBase;
+ int offset = 0;
+ int clock = pTrident->currentClock;
+ CARD8 protect = 0;
+ Bool fullSize = FALSE;
+
+ vgaHWPtr hwp = VGAHWPTR(pScrn);
+ vgaRegPtr regp = &hwp->ModeReg;
+ vgaRegPtr vgaReg = &hwp->ModeReg;
+ vgaIOBase = VGAHWPTR(pScrn)->IOBase;
+
+ /* Unprotect */
+ if (pTrident->Chipset > PROVIDIA9685) {
+ OUTB(0x3C4, Protection);
+ protect = INB(0x3C5);
+ OUTB(0x3C5, 0x92);
+ }
+
+ OUTB(0x3C4, 0x0B); INB(0x3C5); /* Ensure we are in New Mode */
+
+ pReg->tridentRegs3x4[PixelBusReg] = 0x00;
+ pReg->tridentRegsDAC[0x00] = 0x00;
+ pReg->tridentRegs3C4[NewMode2] = 0x20;
+ OUTB(0x3CE, MiscExtFunc);
+ pReg->tridentRegs3CE[MiscExtFunc] = INB(0x3CF) & 0xF0;
+ pReg->tridentRegs3x4[GraphEngReg] = 0x00;
+ pReg->tridentRegs3x4[PreEndControl] = 0;
+ pReg->tridentRegs3x4[PreEndFetch] = 0;
+
+ pReg->tridentRegs3x4[CRTHiOrd] = (((mode->CrtcVBlankEnd-1) & 0x400)>>4) |
+ (((mode->CrtcVTotal - 2) & 0x400) >> 3) |
+ ((mode->CrtcVSyncStart & 0x400) >> 5) |
+ (((mode->CrtcVDisplay - 1) & 0x400) >> 6)|
+ 0x08;
+
+ pReg->tridentRegs3x4[HorizOverflow] = ((mode->CrtcHTotal & 0x800) >> 11) |
+ ((mode->CrtcHBlankStart & 0x800)>>7);
+
+ if (pTrident->IsCyber) {
+ Bool LCDActive;
+#ifdef READOUT
+ Bool ShadowModeActive;
+#endif
+ int i = pTrident->lcdMode;
+#ifdef READOUT
+ OUTB(0x3CE, CyberControl);
+ ShadowModeActive = ((INB(0x3CF) & 0x81) == 0x81);
+#endif
+ OUTB(0x3CE, FPConfig);
+ pReg->tridentRegs3CE[FPConfig] = INB(0x3CF);
+ if (pTrident->dspOverride) {
+ if (pTrident->dspOverride & LCD_ACTIVE) {
+ pReg->tridentRegs3CE[FPConfig] |= 0x10;
+ LCDActive = TRUE;
+ } else {
+ pReg->tridentRegs3CE[FPConfig] &= ~0x10;
+ LCDActive = FALSE;
+ }
+ if (pTrident->dspOverride & CRT_ACTIVE)
+ pReg->tridentRegs3CE[FPConfig] |= 0x20;
+ else
+ pReg->tridentRegs3CE[FPConfig] &= ~0x20;
+ } else {
+ LCDActive = (pReg->tridentRegs3CE[FPConfig] & 0x10);
+ }
+
+ OUTB(0x3CE, CyberEnhance);
+#if 0
+ pReg->tridentRegs3CE[CyberEnhance] = INB(0x3CF);
+#else
+ pReg->tridentRegs3CE[CyberEnhance] = INB(0x3CF) & 0x8F;
+ if (mode->CrtcVDisplay > 1024)
+ pReg->tridentRegs3CE[CyberEnhance] |= 0x50;
+ else
+ if (mode->CrtcVDisplay > 768)
+ pReg->tridentRegs3CE[CyberEnhance] |= 0x30;
+ else
+ if (mode->CrtcVDisplay > 600)
+ pReg->tridentRegs3CE[CyberEnhance] |= 0x20;
+ else
+ if (mode->CrtcVDisplay > 480)
+ pReg->tridentRegs3CE[CyberEnhance] |= 0x10;
+#endif
+ OUTB(0x3CE, CyberControl);
+ pReg->tridentRegs3CE[CyberControl] = INB(0x3CF);
+
+ OUTB(0x3CE,HorStretch);
+ pReg->tridentRegs3CE[HorStretch] = INB(0x3CF);
+ OUTB(0x3CE,VertStretch);
+ pReg->tridentRegs3CE[VertStretch] = INB(0x3CF);
+
+#ifdef READOUT
+ if ((!((pReg->tridentRegs3CE[VertStretch] & 1) ||
+ (pReg->tridentRegs3CE[HorStretch] & 1)))
+ && (!LCDActive || ShadowModeActive))
+ {
+ unsigned char tmp;
+
+ SHADOW_ENABLE(tmp);
+ OUTB(vgaIOBase + 4,0);
+ pReg->tridentRegs3x4[0x0] = INB(vgaIOBase + 5);
+ OUTB(vgaIOBase + 4,3);
+ pReg->tridentRegs3x4[0x3] = INB(vgaIOBase + 5);
+ OUTB(vgaIOBase + 4,4);
+ pReg->tridentRegs3x4[0x4] = INB(vgaIOBase + 5);
+ OUTB(vgaIOBase + 4,5);
+ pReg->tridentRegs3x4[0x5] = INB(vgaIOBase + 5);
+ OUTB(vgaIOBase + 4,0x6);
+ pReg->tridentRegs3x4[0x6] = INB(vgaIOBase + 5);
+ SHADOW_RESTORE(tmp);
+ } else
+#endif
+ {
+ if (i != 0xff) {
+ pReg->tridentRegs3x4[0x0] = LCD[i].shadow_0;
+ pReg->tridentRegs3x4[0x1] = regp->CRTC[1];
+ pReg->tridentRegs3x4[0x2] = regp->CRTC[2];
+ pReg->tridentRegs3x4[0x3] = LCD[i].shadow_3;
+ pReg->tridentRegs3x4[0x4] = LCD[i].shadow_4;
+ pReg->tridentRegs3x4[0x5] = LCD[i].shadow_5;
+ pReg->tridentRegs3x4[0x6] = LCD[i].shadow_6;
+ xf86DrvMsgVerb(pScrn->scrnIndex,X_INFO,1,
+ "Overriding Horizontal timings.\n");
+ }
+ }
+
+ if (i != 0xff) {
+ pReg->tridentRegs3x4[0x7] = LCD[i].shadow_7;
+ pReg->tridentRegs3x4[0x10] = LCD[i].shadow_10;
+ pReg->tridentRegs3x4[0x11] = LCD[i].shadow_11;
+ pReg->tridentRegs3x4[0x12] = regp->CRTC[0x12];
+ pReg->tridentRegs3x4[0x15] = regp->CRTC[0x15];
+ pReg->tridentRegs3x4[0x16] = LCD[i].shadow_16;
+ if (LCDActive) {
+ /* use current screen size not panel size for display area */
+ pReg->tridentRegs3x4[CRTHiOrd] =
+ (pReg->tridentRegs3x4[CRTHiOrd] & 0x10)
+ | (LCD[i].shadow_HiOrd & ~0x10);
+ }
+
+ fullSize = (mode->HDisplay == LCD[i].display_x)
+ && (mode->VDisplay == LCD[i].display_y);
+ }
+
+ /* copy over common bits from normal VGA */
+
+ pReg->tridentRegs3x4[0x7] &= ~0x4A;
+ pReg->tridentRegs3x4[0x7] |= (vgaReg->CRTC[0x7] & 0x4A);
+ if (LCDActive && fullSize) {
+ regp->CRTC[0] = pReg->tridentRegs3x4[0];
+ regp->CRTC[3] = pReg->tridentRegs3x4[3];
+ regp->CRTC[4] = pReg->tridentRegs3x4[4];
+ regp->CRTC[5] = pReg->tridentRegs3x4[5];
+ regp->CRTC[6] = pReg->tridentRegs3x4[6];
+ regp->CRTC[7] = pReg->tridentRegs3x4[7];
+ regp->CRTC[0x10] = pReg->tridentRegs3x4[0x10];
+ regp->CRTC[0x11] = pReg->tridentRegs3x4[0x11];
+ regp->CRTC[0x16] = pReg->tridentRegs3x4[0x16];
+ }
+ if (LCDActive && !fullSize) {
+ /*
+ * Set negative h/vsync polarity to center display nicely
+ * Seems to work on several systems.
+ */
+ regp->MiscOutReg |= 0xC0;
+ /*
+ * If the LCD is active and we don't fill the entire screen
+ * and the previous mode was stretched we may need help from
+ * the BIOS to set all registers for the unstreched mode.
+ */
+ pTrident->doInit = ((pReg->tridentRegs3CE[HorStretch] & 1)
+ || (pReg->tridentRegs3CE[VertStretch] & 1));
+ pReg->tridentRegs3CE[CyberControl] |= 0x81;
+ xf86DrvMsgVerb(pScrn->scrnIndex,X_INFO,1,"Shadow on\n");
+ } else {
+ pReg->tridentRegs3CE[CyberControl] &= 0x7E;
+ xf86DrvMsgVerb(pScrn->scrnIndex,X_INFO,1,"Shadow off\n");
+ }
+ if (pTrident->FPDelay < 6) {
+ pReg->tridentRegs3CE[CyberControl] &= 0xC7;
+ pReg->tridentRegs3CE[CyberControl] |= (pTrident->FPDelay + 2) << 3;
+ }
+
+ if (pTrident->CyberShadow) {
+ pReg->tridentRegs3CE[CyberControl] &= 0x7E;
+ xf86DrvMsgVerb(pScrn->scrnIndex,X_INFO,1,"Forcing Shadow off\n");
+ }
+
+ xf86DrvMsgVerb(pScrn->scrnIndex,X_INFO,1,"H-timing shadow registers:"
+ " 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x\n",
+ pReg->tridentRegs3x4[0], pReg->tridentRegs3x4[3],
+ pReg->tridentRegs3x4[4], pReg->tridentRegs3x4[5]);
+ xf86DrvMsgVerb(pScrn->scrnIndex,X_INFO,1,"H-timing registers: "
+ " 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x\n",
+ regp->CRTC[0], regp->CRTC[1], regp->CRTC[2],
+ regp->CRTC[3], regp->CRTC[4], regp->CRTC[5]);
+ xf86DrvMsgVerb(pScrn->scrnIndex,X_INFO,1,"V-timing shadow registers: "
+ "0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x"
+ " 0x%2.2x (0x%2.2x)\n",
+ pReg->tridentRegs3x4[6], pReg->tridentRegs3x4[7],
+ pReg->tridentRegs3x4[0x10],pReg->tridentRegs3x4[0x11],
+ pReg->tridentRegs3x4[0x16],
+ pReg->tridentRegs3x4[CRTHiOrd]);
+ xf86DrvMsgVerb(pScrn->scrnIndex,X_INFO,1,"V-timing registers: "
+ "0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x "
+ "0x%2.2x 0x%2.2x 0x%2.2x\n",
+ regp->CRTC[6], regp->CRTC[7], regp->CRTC[0x10],
+ regp->CRTC[0x11],regp->CRTC[0x12],
+ regp->CRTC[0x14],regp->CRTC[0x16]);
+
+
+ /* disable stretching, enable centering for default sizes */
+ pReg->tridentRegs3CE[VertStretch] &= 0x7C;
+ switch (mode->VDisplay) {
+ case 768:
+ case 600:
+ case 480:
+ case 240:
+ pReg->tridentRegs3CE[VertStretch] |= 0x80;
+ }
+ pReg->tridentRegs3CE[HorStretch] &= 0x7C;
+ switch (mode->HDisplay) {
+ case 1024:
+ case 800:
+ case 640:
+ case 320:
+ pReg->tridentRegs3CE[HorStretch] |= 0x80;
+ }
+#if 1
+ {
+ int mul = pScrn->bitsPerPixel >> 3;
+ int val;
+
+ if (!mul) mul = 1;
+
+ /* this is what my BIOS does */
+ val = (mode->HDisplay * mul / 8) + 16;
+
+ pReg->tridentRegs3x4[PreEndControl] = ((val >> 8) < 2 ? 2 :0)
+ | ((val >> 8) & 0x01);
+ pReg->tridentRegs3x4[PreEndFetch] = val & 0xff;
+ }
+#else
+ OUTB(vgaIOBase + 4,PreEndControl);
+ pReg->tridentRegs3x4[PreEndControl] = INB(vgaIOBase + 5);
+ OUTB(vgaIOBase + 4,PreEndFetch);
+ pReg->tridentRegs3x4[PreEndFetch] = INB(vgaIOBase + 5);
+#endif
+ /* set mode */
+ if (pTrident->Chipset < BLADEXP) {
+ pReg->tridentRegs3CE[BiosMode] = TridentFindMode(
+ mode->HDisplay,
+ mode->VDisplay,
+ pScrn->depth);
+ xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 1,
+ "Setting BIOS Mode: %x for: %ix%i\n",
+ pReg->tridentRegs3CE[BiosMode],
+ mode->HDisplay,
+ mode->VDisplay);
+ } else {
+ TridentFindNewMode(mode->HDisplay,
+ mode->VDisplay,
+ &pReg->tridentRegs3CE[BiosNewMode1],
+ &pReg->tridentRegs3CE[BiosNewMode2]);
+ xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 1,
+ "Setting BIOS Mode Regs: %x %x for: %ix%i\n",
+ pReg->tridentRegs3CE[BiosNewMode1],
+ pReg->tridentRegs3CE[BiosNewMode2],
+ mode->HDisplay,
+ mode->VDisplay);
+ };
+
+ /* no stretch */
+ if (pTrident->Chipset == CYBERBLADEXPAI1
+ || pTrident->Chipset == BLADEXP)
+ pReg->tridentRegs3CE[BiosReg] = 8;
+ else
+ pReg->tridentRegs3CE[BiosReg] = 0;
+
+ if (pTrident->CyberStretch) {
+ pReg->tridentRegs3CE[VertStretch] |= 0x01;
+ pReg->tridentRegs3CE[HorStretch] |= 0x01;
+ xf86DrvMsgVerb(pScrn->scrnIndex,X_INFO,1,"Enabling StretchMode\n");
+ }
+ }
+
+ /* Enable Chipset specific options */
+ switch (pTrident->Chipset) {
+ case XP5:
+ case CYBERBLADEXP4:
+ case CYBERBLADEXPAI1:
+ case BLADEXP:
+ case CYBERBLADEI7:
+ case CYBERBLADEI7D:
+ case CYBERBLADEI1:
+ case CYBERBLADEI1D:
+ case CYBERBLADEAI1:
+ case CYBERBLADEAI1D:
+ case CYBERBLADEE4:
+ case BLADE3D:
+ OUTB(vgaIOBase + 4, RAMDACTiming);
+ pReg->tridentRegs3x4[RAMDACTiming] = INB(vgaIOBase + 5) | 0x0F;
+ /* Fall Through */
+ case CYBER9520:
+ case CYBER9525DVD:
+ case CYBER9397DVD:
+ case CYBER9397:
+ case IMAGE975:
+ case IMAGE985:
+ case CYBER9388:
+ pReg->tridentRegs3CE[MiscExtFunc] |= 0x10;
+ if (!pReg->tridentRegs3x4[PreEndControl])
+ pReg->tridentRegs3x4[PreEndControl] = 0x01;
+ if (!pReg->tridentRegs3x4[PreEndFetch])
+ pReg->tridentRegs3x4[PreEndFetch] = 0xFF;
+ /* Fall Through */
+ case PROVIDIA9685:
+ case CYBER9385:
+ pReg->tridentRegs3x4[Enhancement0] = 0x40;
+ /* Fall Through */
+ case PROVIDIA9682:
+ case CYBER9382:
+ if (pTrident->UsePCIRetry)
+ pReg->tridentRegs3x4[PCIRetry] = 0xDF;
+ else
+ pReg->tridentRegs3x4[PCIRetry] = 0x1F;
+ /* Fall Through */
+ case TGUI9660:
+ case TGUI9680:
+ if (pTrident->MUX && pScrn->bitsPerPixel == 8) {
+ pReg->tridentRegs3x4[PixelBusReg] |= 0x01; /* 16bit bus */
+ pReg->tridentRegs3C4[NewMode2] |= 0x02; /* half clock */
+ pReg->tridentRegsDAC[0x00] |= 0x20; /* mux mode */
+ }
+ }
+
+ /* Defaults for all trident chipsets follows */
+ switch (pScrn->bitsPerPixel) {
+ case 8:
+ pReg->tridentRegs3CE[MiscExtFunc] |= 0x02;
+ offset = pScrn->displayWidth >> 3;
+ break;
+ case 16:
+ pReg->tridentRegs3CE[MiscExtFunc] |= 0x02;
+ offset = pScrn->displayWidth >> 2;
+ if (pScrn->depth == 15)
+ pReg->tridentRegsDAC[0x00] = 0x10;
+ else
+ pReg->tridentRegsDAC[0x00] = 0x30;
+ pReg->tridentRegs3x4[PixelBusReg] = 0x04;
+ /* Reload with any chipset specific stuff here */
+ if (pTrident->Chipset >= TGUI9660)
+ pReg->tridentRegs3x4[PixelBusReg] |= 0x01;
+ if (pTrident->Chipset == TGUI9440AGi) {
+ pReg->tridentRegs3CE[MiscExtFunc] |= 0x08;/*Clock Division / 2*/
+ clock *= 2; /* Double the clock */
+ }
+ break;
+ case 24:
+ pReg->tridentRegs3CE[MiscExtFunc] |= 0x02;
+ offset = (pScrn->displayWidth * 3) >> 3;
+ pReg->tridentRegs3x4[PixelBusReg] = 0x29;
+ pReg->tridentRegsDAC[0x00] = 0xD0;
+ if (pTrident->Chipset == CYBERBLADEXP4 ||
+ pTrident->Chipset == XP5 ||
+ pTrident->Chipset == CYBERBLADEE4) {
+ OUTB(vgaIOBase+ 4, New32);
+ pReg->tridentRegs3x4[New32] = INB(vgaIOBase + 5) & 0x7F;
+ }
+ break;
+ case 32:
+ pReg->tridentRegs3CE[MiscExtFunc] |= 0x02;
+ if (pTrident->Chipset != CYBERBLADEXP4
+ && pTrident->Chipset != BLADEXP
+ && pTrident->Chipset != XP5
+ && pTrident->Chipset != CYBERBLADEE4
+ && pTrident->Chipset != CYBERBLADEXPAI1) {
+ /* Clock Division by 2*/
+ pReg->tridentRegs3CE[MiscExtFunc] |= 0x08;
+ clock *= 2; /* Double the clock */
+ }
+ offset = pScrn->displayWidth >> 1;
+ pReg->tridentRegs3x4[PixelBusReg] = 0x09;
+ pReg->tridentRegsDAC[0x00] = 0xD0;
+ if (pTrident->Chipset == CYBERBLADEXP4
+ || pTrident->Chipset == BLADEXP
+ || pTrident->Chipset == XP5
+ || pTrident->Chipset == CYBERBLADEE4
+ || pTrident->Chipset == CYBERBLADEXPAI1) {
+ OUTB(vgaIOBase+ 4, New32);
+ pReg->tridentRegs3x4[New32] = INB(vgaIOBase + 5) | 0x80;
+ /* With new mode 32bpp we set the packed flag */
+ pReg->tridentRegs3x4[PixelBusReg] |= 0x20;
+ }
+ break;
+ }
+ pReg->tridentRegs3x4[Offset] = offset & 0xFF;
+
+ {
+ CARD8 a, b;
+ TGUISetClock(pScrn, clock, &a, &b);
+ pReg->tridentRegsClock[0x00] = (regp->MiscOutReg & 0xF3) | 0x08;
+ pReg->tridentRegsClock[0x01] = a;
+ pReg->tridentRegsClock[0x02] = b;
+ if (pTrident->MCLK > 0) {
+ TGUISetMCLK(pScrn, pTrident->MCLK, &a, &b);
+ pReg->tridentRegsClock[0x03] = a;
+ pReg->tridentRegsClock[0x04] = b;
+ }
+ }
+
+ pReg->tridentRegs3C4[NewMode1] = 0xC0;
+ pReg->tridentRegs3C4[Protection] = 0x92;
+
+ pReg->tridentRegs3x4[LinearAddReg] = 0;
+ if (pTrident->Linear) {
+ /* This is used for VLB, when we support it again in 4.0 */
+ if (pTrident->Chipset < CYBER9385)
+ pReg->tridentRegs3x4[LinearAddReg] |=
+ ((pTrident->FbAddress >> 24) << 6)|
+ ((pTrident->FbAddress >> 20) & 0x0F);
+ /* Turn on linear mapping */
+ pReg->tridentRegs3x4[LinearAddReg] |= 0x20;
+ } else {
+ pReg->tridentRegs3CE[MiscExtFunc] |= 0x04;
+ }
+
+ pReg->tridentRegs3x4[CRTCModuleTest] =
+ (mode->Flags & V_INTERLACE ? 0x84 : 0x80);
+
+ OUTB(vgaIOBase+ 4, InterfaceSel);
+ pReg->tridentRegs3x4[InterfaceSel] = INB(vgaIOBase + 5) | 0x40;
+
+ OUTB(vgaIOBase+ 4, Performance);
+ pReg->tridentRegs3x4[Performance] = INB(vgaIOBase + 5);
+ if (pTrident->Chipset < BLADEXP)
+ pReg->tridentRegs3x4[Performance] |= 0x10;
+
+ OUTB(vgaIOBase+ 4, DRAMControl);
+ if (pTrident->Chipset >= CYBER9388)
+ pReg->tridentRegs3x4[DRAMControl] = INB(vgaIOBase + 5) | 0x10;
+
+ if (pTrident->IsCyber && !pTrident->MMIOonly)
+ pReg->tridentRegs3x4[DRAMControl] |= 0x20;
+
+ if (pTrident->NewClockCode && pTrident->Chipset <= CYBER9397DVD) {
+ OUTB(vgaIOBase + 4, ClockControl);
+ pReg->tridentRegs3x4[ClockControl] = INB(vgaIOBase + 5) | 0x01;
+ }
+
+ OUTB(vgaIOBase+ 4, AddColReg);
+ pReg->tridentRegs3x4[AddColReg] = INB(vgaIOBase + 5) & 0xEF;
+ pReg->tridentRegs3x4[AddColReg] |= (offset & 0x100) >> 4;
+
+ if (pTrident->Chipset >= TGUI9660) {
+ pReg->tridentRegs3x4[AddColReg] &= 0xDF;
+ pReg->tridentRegs3x4[AddColReg] |= (offset & 0x200) >> 4;
+ }
+
+ if (IsPciCard && UseMMIO) {
+ if (!pTrident->NoAccel)
+ pReg->tridentRegs3x4[GraphEngReg] |= 0x80;
+ } else {
+ if (!pTrident->NoAccel)
+ pReg->tridentRegs3x4[GraphEngReg] |= 0x82;
+ }
+
+ OUTB(0x3CE, MiscIntContReg);
+ pReg->tridentRegs3CE[MiscIntContReg] = INB(0x3CF) | 0x04;
+
+ /* Fix hashing problem in > 8bpp on 9320 chipset */
+ if (pTrident->Chipset == CYBER9320 && pScrn->bitsPerPixel > 8)
+ pReg->tridentRegs3CE[MiscIntContReg] &= ~0x80;
+
+ OUTB(vgaIOBase+ 4, PCIReg);
+ if (IsPciCard && UseMMIO)
+ pReg->tridentRegs3x4[PCIReg] = INB(vgaIOBase + 5) & 0xF9;
+ else
+ pReg->tridentRegs3x4[PCIReg] = INB(vgaIOBase + 5) & 0xF8;
+
+ /* Enable PCI Bursting on capable chips */
+ if (pTrident->Chipset >= TGUI9660) {
+ if(pTrident->UsePCIBurst) {
+ pReg->tridentRegs3x4[PCIReg] |= 0x06;
+ } else {
+ pReg->tridentRegs3x4[PCIReg] &= 0xF9;
+ }
+ }
+
+ if (pTrident->Chipset >= CYBER9388) {
+ if (pTrident->GammaBrightnessOn)
+ xf86DrvMsgVerb(pScrn->scrnIndex,X_INFO,1,
+ "Setting Gamma: %f Brightness: %i\n",
+ pTrident->gamma, pTrident->brightness);
+ tridentSetBrightnessAndGamma(pReg,
+ pTrident->GammaBrightnessOn,
+ pTrident->gamma, pTrident->brightness);
+ }
+
+ /* Video */
+ OUTB(0x3C4,0x20);
+ pReg->tridentRegs3C4[SSetup] = INB(0x3C5) | 0x4;
+ pReg->tridentRegs3C4[SKey] = 0x00;
+ pReg->tridentRegs3C4[SPKey] = 0xC0;
+ OUTB(0x3C4,0x12);
+ pReg->tridentRegs3C4[Threshold] = INB(0x3C5);
+ if (pScrn->bitsPerPixel > 16)
+ pReg->tridentRegs3C4[Threshold] =
+ (pReg->tridentRegs3C4[Threshold] & 0xf0) | 0x2;
+
+ /* restore */
+ if (pTrident->Chipset > PROVIDIA9685) {
+ OUTB(0x3C4, Protection);
+ OUTB(0x3C5, protect);
+ }
+
+ if (pTrident->Chipset == CYBERBLADEXP4 ||
+ pTrident->Chipset == XP5)
+ pReg->tridentRegs3CE[DisplayEngCont] = 0x08;
+
+ /* Avoid lockup on Blade3D, PCI Retry is permanently on */
+ if (pTrident->Chipset == BLADE3D)
+ pReg->tridentRegs3x4[PCIRetry] = 0x9F;
+
+ return(TRUE);
+}
+
+void
+TridentRestore(ScrnInfoPtr pScrn, TRIDENTRegPtr tridentReg)
+{
+ TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
+ int vgaIOBase;
+ vgaIOBase = VGAHWPTR(pScrn)->IOBase;
+
+ if (pTrident->Chipset > PROVIDIA9685) {
+ OUTB(0x3C4, Protection);
+ OUTB(0x3C5, 0x92);
+ }
+#if 0
+ if (pTrident->doInit && pTrident->Int10) {
+ OUTW_3CE(BiosReg);
+ }
+#endif
+ /* Goto New Mode */
+ OUTB(0x3C4, 0x0B);
+ (void) INB(0x3C5);
+
+ /* Unprotect registers */
+ OUTW(0x3C4, ((0xC0 ^ 0x02) << 8) | NewMode1);
+
+ (void) INB(0x3C8);
+ (void) INB(0x3C6);
+ (void) INB(0x3C6);
+ (void) INB(0x3C6);
+ (void) INB(0x3C6);
+ OUTB(0x3C6, tridentReg->tridentRegsDAC[0x00]);
+ (void) INB(0x3C8);
+
+ OUTW_3x4(CRTCModuleTest);
+ OUTW_3x4(LinearAddReg);
+ OUTW_3C4(NewMode2);
+ OUTW_3x4(CursorControl);
+ OUTW_3x4(CRTHiOrd);
+ OUTW_3x4(HorizOverflow);
+ OUTW_3x4(AddColReg);
+ OUTW_3x4(GraphEngReg);
+ OUTW_3x4(Performance);
+ OUTW_3x4(InterfaceSel);
+ OUTW_3x4(DRAMControl);
+ OUTW_3x4(PixelBusReg);
+ OUTW_3x4(PCIReg);
+ OUTW_3x4(PCIRetry);
+ OUTW_3CE(MiscIntContReg);
+ OUTW_3CE(MiscExtFunc);
+ OUTW_3x4(Offset);
+ if (pTrident->NewClockCode && pTrident->Chipset <= CYBER9397DVD)
+ OUTW_3x4(ClockControl);
+ if (pTrident->Chipset >= CYBER9388) {
+ OUTW_3C4(Threshold);
+ OUTW_3C4(SSetup);
+ OUTW_3C4(SKey);
+ OUTW_3C4(SPKey);
+ OUTW_3x4(PreEndControl);
+ OUTW_3x4(PreEndFetch);
+ OUTW_3C4(GBslope1);
+ OUTW_3C4(GBslope2);
+ OUTW_3C4(GBslope3);
+ OUTW_3C4(GBslope4);
+ OUTW_3C4(GBintercept1);
+ OUTW_3C4(GBintercept2);
+ OUTW_3C4(GBintercept3);
+ OUTW_3C4(GBintercept4);
+ }
+ if (pTrident->Chipset >= CYBER9385) OUTW_3x4(Enhancement0);
+ if (pTrident->Chipset >= BLADE3D) OUTW_3x4(RAMDACTiming);
+ if (pTrident->Chipset == CYBERBLADEXP4 ||
+ pTrident->Chipset == XP5 ||
+ pTrident->Chipset == CYBERBLADEE4) OUTW_3x4(New32);
+ if (pTrident->Chipset == CYBERBLADEXP4 ||
+ pTrident->Chipset == XP5) OUTW_3CE(DisplayEngCont);
+ if (pTrident->IsCyber) {
+ CARD8 tmp;
+
+ OUTW_3CE(VertStretch);
+ OUTW_3CE(HorStretch);
+ if (pTrident->Chipset < BLADEXP) {
+ OUTW_3CE(BiosMode);
+ } else {
+ OUTW_3CE(BiosNewMode1);
+ OUTW_3CE(BiosNewMode2);
+ };
+ OUTW_3CE(BiosReg);
+ OUTW_3CE(FPConfig);
+ OUTW_3CE(CyberControl);
+ OUTW_3CE(CyberEnhance);
+ SHADOW_ENABLE(tmp);
+ OUTW_3x4(0x0);
+ if (pTrident->shadowNew) {
+ OUTW_3x4(0x1);
+ OUTW_3x4(0x2);
+ }
+ OUTW_3x4(0x3);
+ OUTW_3x4(0x4);
+ OUTW_3x4(0x5);
+ OUTW_3x4(0x6);
+ OUTW_3x4(0x7);
+ OUTW_3x4(0x10);
+ OUTW_3x4(0x11);
+ if (pTrident->shadowNew) {
+ OUTW_3x4(0x12);
+ OUTW_3x4(0x15);
+ }
+ OUTW_3x4(0x16);
+ SHADOW_RESTORE(tmp);
+ }
+
+ if (Is3Dchip) {
+#ifdef READOUT
+ if (!pTrident->DontSetClock)
+#endif
+ {
+ OUTW(0x3C4, (tridentReg->tridentRegsClock[0x01])<<8 | ClockLow);
+ OUTW(0x3C4, (tridentReg->tridentRegsClock[0x02])<<8 | ClockHigh);
+ }
+ if (pTrident->MCLK > 0) {
+ OUTW(0x3C4,(tridentReg->tridentRegsClock[0x03])<<8 | MCLKLow);
+ OUTW(0x3C4,(tridentReg->tridentRegsClock[0x04])<<8 | MCLKHigh);
+ }
+ } else {
+#ifdef READOUT
+ if (!pTrident->DontSetClock)
+#endif
+ {
+ OUTB(0x43C8, tridentReg->tridentRegsClock[0x01]);
+ OUTB(0x43C9, tridentReg->tridentRegsClock[0x02]);
+ }
+ if (pTrident->MCLK > 0) {
+ OUTB(0x43C6, tridentReg->tridentRegsClock[0x03]);
+ OUTB(0x43C7, tridentReg->tridentRegsClock[0x04]);
+ }
+ }
+#ifdef READOUT
+ if (!pTrident->DontSetClock)
+#endif
+ {
+ OUTB(0x3C2, tridentReg->tridentRegsClock[0x00]);
+ }
+
+ if (pTrident->Chipset > PROVIDIA9685) {
+ OUTB(0x3C4, Protection);
+ OUTB(0x3C5, tridentReg->tridentRegs3C4[Protection]);
+ }
+
+ OUTW(0x3C4, ((tridentReg->tridentRegs3C4[NewMode1] ^ 0x02) << 8)| NewMode1);
+}
+
+void
+TridentSave(ScrnInfoPtr pScrn, TRIDENTRegPtr tridentReg)
+{
+ TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
+ int vgaIOBase;
+ vgaIOBase = VGAHWPTR(pScrn)->IOBase;
+
+ /* Goto New Mode */
+ OUTB(0x3C4, 0x0B);
+ (void) INB(0x3C5);
+
+ INB_3C4(NewMode1);
+ if (pTrident->Chipset > PROVIDIA9685)
+ INB_3C4(Protection);
+
+ /* Unprotect registers */
+ OUTW(0x3C4, ((0xC0 ^ 0x02) << 8) | NewMode1);
+ if (pTrident->Chipset > PROVIDIA9685)
+ OUTW(0x3C4, (0x92 << 8) | Protection);
+
+ INB_3x4(Offset);
+ INB_3x4(LinearAddReg);
+ INB_3x4(CRTCModuleTest);
+ INB_3x4(CRTHiOrd);
+ INB_3x4(HorizOverflow);
+ INB_3x4(Performance);
+ INB_3x4(InterfaceSel);
+ INB_3x4(DRAMControl);
+ INB_3x4(AddColReg);
+ INB_3x4(PixelBusReg);
+ INB_3x4(GraphEngReg);
+ INB_3x4(PCIReg);
+ INB_3x4(PCIRetry);
+ if (pTrident->NewClockCode && pTrident->Chipset <= CYBER9397DVD)
+ INB_3x4(ClockControl);
+ if (pTrident->Chipset >= CYBER9388) {
+ INB_3C4(Threshold);
+ INB_3C4(SSetup);
+ INB_3C4(SKey);
+ INB_3C4(SPKey);
+ INB_3x4(PreEndControl);
+ INB_3x4(PreEndFetch);
+ INB_3C4(GBslope1);
+ INB_3C4(GBslope2);
+ INB_3C4(GBslope3);
+ INB_3C4(GBslope4);
+ INB_3C4(GBintercept1);
+ INB_3C4(GBintercept2);
+ INB_3C4(GBintercept3);
+ INB_3C4(GBintercept4);
+ }
+ if (pTrident->Chipset >= CYBER9385) INB_3x4(Enhancement0);
+ if (pTrident->Chipset >= BLADE3D) INB_3x4(RAMDACTiming);
+ if (pTrident->Chipset == CYBERBLADEXP4 ||
+ pTrident->Chipset == XP5 ||
+ pTrident->Chipset == CYBERBLADEE4) INB_3x4(New32);
+ if (pTrident->Chipset == CYBERBLADEXP4 ||
+ pTrident->Chipset == XP5) INB_3CE(DisplayEngCont);
+ if (pTrident->IsCyber) {
+ CARD8 tmp;
+ INB_3CE(VertStretch);
+ INB_3CE(HorStretch);
+ if (pTrident->Chipset < BLADEXP) {
+ INB_3CE(BiosMode);
+ } else {
+ INB_3CE(BiosNewMode1);
+ INB_3CE(BiosNewMode2);
+ }
+ INB_3CE(BiosReg);
+ INB_3CE(FPConfig);
+ INB_3CE(CyberControl);
+ INB_3CE(CyberEnhance);
+ SHADOW_ENABLE(tmp);
+ INB_3x4(0x0);
+ if (pTrident->shadowNew) {
+ INB_3x4(0x1);
+ INB_3x4(0x2);
+ }
+ INB_3x4(0x3);
+ INB_3x4(0x4);
+ INB_3x4(0x5);
+ INB_3x4(0x6);
+ INB_3x4(0x7);
+ INB_3x4(0x10);
+ INB_3x4(0x11);
+ if (pTrident->shadowNew) {
+ INB_3x4(0x12);
+ INB_3x4(0x15);
+ }
+ INB_3x4(0x16);
+ SHADOW_RESTORE(tmp);
+ }
+
+ /* save cursor registers */
+ INB_3x4(CursorControl);
+
+ INB_3CE(MiscExtFunc);
+ INB_3CE(MiscIntContReg);
+
+ (void) INB(0x3C8);
+ (void) INB(0x3C6);
+ (void) INB(0x3C6);
+ (void) INB(0x3C6);
+ (void) INB(0x3C6);
+ tridentReg->tridentRegsDAC[0x00] = INB(0x3C6);
+ (void) INB(0x3C8);
+
+ tridentReg->tridentRegsClock[0x00] = INB(0x3CC);
+ if (Is3Dchip) {
+ OUTB(0x3C4, ClockLow);
+ tridentReg->tridentRegsClock[0x01] = INB(0x3C5);
+ OUTB(0x3C4, ClockHigh);
+ tridentReg->tridentRegsClock[0x02] = INB(0x3C5);
+ if (pTrident->MCLK > 0) {
+ OUTB(0x3C4, MCLKLow);
+ tridentReg->tridentRegsClock[0x03] = INB(0x3C5);
+ OUTB(0x3C4, MCLKHigh);
+ tridentReg->tridentRegsClock[0x04] = INB(0x3C5);
+ }
+ } else {
+ tridentReg->tridentRegsClock[0x01] = INB(0x43C8);
+ tridentReg->tridentRegsClock[0x02] = INB(0x43C9);
+ if (pTrident->MCLK > 0) {
+ tridentReg->tridentRegsClock[0x03] = INB(0x43C6);
+ tridentReg->tridentRegsClock[0x04] = INB(0x43C7);
+ }
+ }
+
+ INB_3C4(NewMode2);
+
+ /* Protect registers */
+ OUTW_3C4(NewMode1);
+}
+
+static void
+TridentShowCursor(ScrnInfoPtr pScrn)
+{
+ TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
+ int vgaIOBase;
+ vgaIOBase = VGAHWPTR(pScrn)->IOBase;
+
+ /* 64x64 */
+ OUTW(vgaIOBase + 4, 0xC150);
+}
+
+static void
+TridentHideCursor(ScrnInfoPtr pScrn) {
+ int vgaIOBase;
+ TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
+ vgaIOBase = VGAHWPTR(pScrn)->IOBase;
+
+ OUTW(vgaIOBase + 4, 0x4150);
+}
+
+static void
+TridentSetCursorPosition(ScrnInfoPtr pScrn, int x, int y)
+{
+ int vgaIOBase;
+ TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
+ vgaIOBase = VGAHWPTR(pScrn)->IOBase;
+
+ if (x < 0) {
+ OUTW(vgaIOBase + 4, (-x)<<8 | 0x46);
+ x = 0;
+ } else
+ OUTW(vgaIOBase + 4, 0x0046);
+
+ if (y < 0) {
+ OUTW(vgaIOBase + 4, (-y)<<8 | 0x47);
+ y = 0;
+ } else
+ OUTW(vgaIOBase + 4, 0x0047);
+
+ OUTW(vgaIOBase + 4, (x&0xFF)<<8 | 0x40);
+ OUTW(vgaIOBase + 4, (x&0x0F00) | 0x41);
+ OUTW(vgaIOBase + 4, (y&0xFF)<<8 | 0x42);
+ OUTW(vgaIOBase + 4, (y&0x0F00) | 0x43);
+}
+
+static void
+TridentSetCursorColors(ScrnInfoPtr pScrn, int bg, int fg)
+{
+ int vgaIOBase;
+ TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
+ vgaIOBase = VGAHWPTR(pScrn)->IOBase;
+ OUTW(vgaIOBase + 4, (fg & 0x000000FF)<<8 | 0x48);
+ OUTW(vgaIOBase + 4, (fg & 0x0000FF00) | 0x49);
+ OUTW(vgaIOBase + 4, (fg & 0x00FF0000)>>8 | 0x4A);
+ OUTW(vgaIOBase + 4, (fg & 0xFF000000)>>16 | 0x4B);
+ OUTW(vgaIOBase + 4, (bg & 0x000000FF)<<8 | 0x4C);
+ OUTW(vgaIOBase + 4, (bg & 0x0000FF00) | 0x4D);
+ OUTW(vgaIOBase + 4, (bg & 0x00FF0000)>>8 | 0x4E);
+ OUTW(vgaIOBase + 4, (bg & 0xFF000000)>>16 | 0x4F);
+}
+
+static void
+TridentLoadCursorImage(
+ ScrnInfoPtr pScrn,
+ CARD8 *src
+)
+{
+ TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
+ int vgaIOBase;
+ int programmed_offset = pTrident->CursorOffset / 1024;
+ vgaIOBase = VGAHWPTR(pScrn)->IOBase;
+
+ memcpy((CARD8 *)pTrident->FbBase + pTrident->CursorOffset,
+ src, pTrident->CursorInfoRec->MaxWidth *
+ pTrident->CursorInfoRec->MaxHeight / 4);
+
+ OUTW(vgaIOBase + 4, ((programmed_offset & 0xFF) << 8) | 0x44);
+ OUTW(vgaIOBase + 4, (programmed_offset & 0xFF00) | 0x45);
+}
+
+static Bool
+TridentUseHWCursor(ScreenPtr pScreen, CursorPtr pCurs)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
+
+ if (pTrident->MUX && pScrn->bitsPerPixel == 8) return FALSE;
+
+ if (!pTrident->HWCursor) return FALSE;
+
+ return TRUE;
+}
+
+#define CURSOR_WIDTH 64
+#define CURSOR_HEIGHT 64
+#define CURSOR_ALIGN(x,bytes) (((x) + ((bytes) - 1)) & ~((bytes) - 1))
+
+Bool
+TridentHWCursorInit(ScreenPtr pScreen)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
+ xf86CursorInfoPtr infoPtr;
+ FBAreaPtr fbarea;
+ int width;
+ int width_bytes;
+ int height;
+ int size_bytes;
+
+ size_bytes = CURSOR_WIDTH * 4 * CURSOR_HEIGHT;
+ width = pScrn->displayWidth;
+ width_bytes = width * (pScrn->bitsPerPixel / 8);
+ height = (size_bytes + width_bytes - 1) / width_bytes;
+ fbarea = xf86AllocateOffscreenArea(pScreen,
+ width,
+ height,
+ 1024,
+ NULL,
+ NULL,
+ NULL);
+
+ if (!fbarea) {
+ pTrident->CursorOffset = 0;
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ "Hardware cursor disabled"
+ " due to insufficient offscreen memory\n");
+ return FALSE;
+ } else {
+ pTrident->CursorOffset = CURSOR_ALIGN((fbarea->box.x1 +
+ fbarea->box.y1 * width) *
+ pScrn->bitsPerPixel / 8,
+ 1024);
+ }
+
+ if ((pTrident->Chipset != CYBER9397DVD) &&
+ (pTrident->Chipset < CYBERBLADEE4)) {
+ /* Can't deal with an offset more than 4MB - 4096 bytes */
+ if (pTrident->CursorOffset >= ((4096*1024) - 4096)) {
+ pTrident->CursorOffset = 0;
+ xf86FreeOffscreenArea(fbarea);
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ "Hardware cursor disabled"
+ " due to cursor offset constraints.\n");
+ return FALSE;
+ }
+ }
+
+ infoPtr = xf86CreateCursorInfoRec();
+ if(!infoPtr) return FALSE;
+
+ pTrident->CursorInfoRec = infoPtr;
+
+ infoPtr->MaxWidth = 64;
+ infoPtr->MaxHeight = 64;
+ infoPtr->Flags = HARDWARE_CURSOR_BIT_ORDER_MSBFIRST |
+ HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK |
+ HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_32 |
+ ((pTrident->Chipset == CYBERBLADEXP4 ||
+ pTrident->Chipset == BLADEXP ||
+ pTrident->Chipset == XP5 ||
+ pTrident->Chipset == CYBERBLADEE4) ?
+ HARDWARE_CURSOR_TRUECOLOR_AT_8BPP : 0);
+ infoPtr->SetCursorColors = TridentSetCursorColors;
+ infoPtr->SetCursorPosition = TridentSetCursorPosition;
+ infoPtr->LoadCursorImage = TridentLoadCursorImage;
+ infoPtr->HideCursor = TridentHideCursor;
+ infoPtr->ShowCursor = TridentShowCursor;
+ infoPtr->UseHWCursor = TridentUseHWCursor;
+
+ return(xf86InitCursor(pScreen, infoPtr));
+}
+
+unsigned int
+Tridentddc1Read(ScrnInfoPtr pScrn)
+{
+ TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
+ int vgaIOBase = VGAHWPTR(pScrn)->IOBase;
+ CARD8 temp;
+
+ /* New mode */
+ OUTB(0x3C4, 0x0B); temp = INB(0x3C5);
+
+ OUTB(0x3C4, NewMode1);
+ temp = INB(0x3C5);
+ OUTB(0x3C5, temp | 0x80);
+
+ /* Define SDA as input */
+ OUTW(vgaIOBase + 4, (0x04 << 8) | I2C);
+
+ OUTW(0x3C4, (temp << 8) | NewMode1);
+
+ /* Wait until vertical retrace is in progress. */
+ while (INB(vgaIOBase + 0xA) & 0x08);
+ while (!(INB(vgaIOBase + 0xA) & 0x08));
+
+ /* Get the result */
+ OUTB(vgaIOBase + 4, I2C);
+ return ( INB(vgaIOBase + 5) & 0x01 );
+}
+
+void TridentSetOverscan(
+ ScrnInfoPtr pScrn,
+ int overscan
+){
+ vgaHWPtr hwp = VGAHWPTR(pScrn);
+
+ if (overscan < 0 || overscan > 255)
+ return;
+
+ hwp->enablePalette(hwp);
+ hwp->writeAttr(hwp, OVERSCAN, overscan);
+ hwp->disablePalette(hwp);
+}
+
+void TridentLoadPalette(
+ ScrnInfoPtr pScrn,
+ int numColors,
+ int *indicies,
+ LOCO *colors,
+ VisualPtr pVisual
+){
+ vgaHWPtr hwp = VGAHWPTR(pScrn);
+ TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
+ int i, index;
+ for(i = 0; i < numColors; i++) {
+ index = indicies[i];
+ OUTB(0x3C6, 0xFF);
+ DACDelay(hwp);
+ OUTB(0x3c8, index);
+ DACDelay(hwp);
+ OUTB(0x3c9, colors[index].red);
+ DACDelay(hwp);
+ OUTB(0x3c9, colors[index].green);
+ DACDelay(hwp);
+ OUTB(0x3c9, colors[index].blue);
+ DACDelay(hwp);
+ }
+}