summaryrefslogtreecommitdiff
path: root/src/atidac.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/atidac.c')
-rw-r--r--src/atidac.c522
1 files changed, 522 insertions, 0 deletions
diff --git a/src/atidac.c b/src/atidac.c
new file mode 100644
index 00000000..1d3e943b
--- /dev/null
+++ b/src/atidac.c
@@ -0,0 +1,522 @@
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atidac.c,v 1.18 2003/02/25 17:58:13 tsi Exp $ */
+/*
+ * Copyright 1997 through 2003 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org
+ *
+ * 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 Marc Aurele La France not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. Marc Aurele La France makes no representations
+ * about the suitability of this software for any purpose. It is provided
+ * "as-is" without express or implied warranty.
+ *
+ * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
+ * EVENT SHALL MARC AURELE LA FRANCE 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.
+ */
+
+#include "ati.h"
+#include "atidac.h"
+#include "atimach64io.h"
+#include "atimono.h"
+
+/*
+ * RAMDAC-related definitions.
+ */
+const SymTabRec ATIDACDescriptors[] =
+{ /* Keep this table in ascending DACType order */
+ {ATI_DAC_ATI68830, "ATI 68830 or similar"},
+ {ATI_DAC_SC11483, "Sierra 11483 or similar"},
+ {ATI_DAC_ATI68875, "ATI 68875 or similar"},
+ {ATI_DAC_TVP3026_A, "TI ViewPoint3026 or similar"},
+ {ATI_DAC_GENERIC, "Brooktree 476 or similar"},
+ {ATI_DAC_BT481, "Brooktree 481 or similar"},
+ {ATI_DAC_ATT20C491, "AT&T 20C491 or similar"},
+ {ATI_DAC_SC15026, "Sierra 15026 or similar"},
+ {ATI_DAC_MU9C1880, "Music 9C1880 or similar"},
+ {ATI_DAC_IMSG174, "Inmos G174 or similar"},
+ {ATI_DAC_ATI68860_B, "ATI 68860 (Revision B) or similar"},
+ {ATI_DAC_ATI68860_C, "ATI 68860 (Revision C) or similar"},
+ {ATI_DAC_TVP3026_B, "TI ViewPoint3026 or similar"},
+ {ATI_DAC_STG1700, "SGS-Thompson 1700 or similar"},
+ {ATI_DAC_ATT20C498, "AT&T 20C498 or similar"},
+ {ATI_DAC_STG1702, "SGS-Thompson 1702 or similar"},
+ {ATI_DAC_SC15021, "Sierra 15021 or similar"},
+ {ATI_DAC_ATT21C498, "AT&T 21C498 or similar"},
+ {ATI_DAC_STG1703, "SGS-Thompson 1703 or similar"},
+ {ATI_DAC_CH8398, "Chrontel 8398 or similar"},
+ {ATI_DAC_ATT20C408, "AT&T 20C408 or similar"},
+ {ATI_DAC_INTERNAL, "Internal"},
+ {ATI_DAC_IBMRGB514, "IBM RGB 514 or similar"},
+ {ATI_DAC_UNKNOWN, "Unknown"} /* Must be last */
+};
+
+#ifndef AVOID_CPIO
+
+/*
+ * ATISetDACIOPorts --
+ *
+ * This function sets up DAC access I/O port numbers.
+ */
+void
+ATISetDACIOPorts
+(
+ ATIPtr pATI,
+ ATICRTCType crtc
+)
+{
+ switch (crtc)
+ {
+ case ATI_CRTC_VGA:
+ pATI->CPIO_DAC_DATA = VGA_DAC_DATA;
+ pATI->CPIO_DAC_MASK = VGA_DAC_MASK;
+ pATI->CPIO_DAC_READ = VGA_DAC_READ;
+ pATI->CPIO_DAC_WRITE = VGA_DAC_WRITE;
+ pATI->CPIO_DAC_WAIT = GENS1(pATI->CPIO_VGABase);
+ break;
+
+ case ATI_CRTC_8514:
+ pATI->CPIO_DAC_DATA = IBM_DAC_DATA;
+ pATI->CPIO_DAC_MASK = IBM_DAC_MASK;
+ pATI->CPIO_DAC_READ = IBM_DAC_READ;
+ pATI->CPIO_DAC_WRITE = IBM_DAC_WRITE;
+ pATI->CPIO_DAC_WAIT = pATI->CPIO_DAC_MASK;
+ break;
+
+ case ATI_CRTC_MACH64:
+ pATI->CPIO_DAC_DATA = ATIIOPort(DAC_REGS) + 1;
+ pATI->CPIO_DAC_MASK = ATIIOPort(DAC_REGS) + 2;
+ pATI->CPIO_DAC_READ = ATIIOPort(DAC_REGS) + 3;
+ pATI->CPIO_DAC_WRITE = ATIIOPort(DAC_REGS) + 0;
+ pATI->CPIO_DAC_WAIT = pATI->CPIOBase;
+ break;
+
+ default:
+ break;
+ }
+}
+
+#endif /* AVOID_CPIO */
+
+/*
+ * ATIGetDACCmdReg --
+ *
+ * Setup to access a RAMDAC's command register.
+ */
+CARD8
+ATIGetDACCmdReg
+(
+ ATIPtr pATI
+)
+{
+
+#ifdef AVOID_CPIO
+
+ (void)in8(M64_DAC_WRITE); /* Reset to PEL mode */
+ (void)in8(M64_DAC_MASK);
+ (void)in8(M64_DAC_MASK);
+ (void)in8(M64_DAC_MASK);
+ return in8(M64_DAC_MASK);
+
+#else /* AVOID_CPIO */
+
+ (void)inb(pATI->CPIO_DAC_WRITE); /* Reset to PEL mode */
+ (void)inb(pATI->CPIO_DAC_MASK);
+ (void)inb(pATI->CPIO_DAC_MASK);
+ (void)inb(pATI->CPIO_DAC_MASK);
+ return inb(pATI->CPIO_DAC_MASK);
+
+#endif /* AVOID_CPIO */
+
+}
+
+/*
+ * ATIDACPreInit --
+ *
+ * This function initialises the fields in an ATIHWRec that relate to DACs.
+ */
+void
+ATIDACPreInit
+(
+ ScrnInfoPtr pScreenInfo,
+ ATIPtr pATI,
+ ATIHWPtr pATIHW
+)
+{
+ int Index, Index2;
+ CARD8 maxColour = (1 << pATI->rgbBits) - 1;
+
+ pATIHW->dac_read = pATIHW->dac_write = 0x00U;
+ pATIHW->dac_mask = 0xFFU;
+
+ /*
+ * Set colour lookup table. The first entry has already been zeroed out.
+ */
+ if (pATI->depth > 8)
+ for (Index = 1; Index < (NumberOf(pATIHW->lut) / 3); Index++)
+ {
+ Index2 = Index * 3;
+ pATIHW->lut[Index2 + 0] =
+ pATIHW->lut[Index2 + 1] =
+ pATIHW->lut[Index2 + 2] = Index;
+ }
+ else
+ {
+ /*
+ * Initialise hardware colour map so that use of uninitialised
+ * software colour map entries can easily be seen. For 256-colour
+ * modes, this doesn't remain effective for very long...
+ */
+ pATIHW->lut[3] = pATIHW->lut[4] = pATIHW->lut[5] = 0xFFU;
+ for (Index = 2; Index < (NumberOf(pATIHW->lut) / 3); Index++)
+ {
+ Index2 = Index * 3;
+ pATIHW->lut[Index2 + 0] = maxColour;
+ pATIHW->lut[Index2 + 1] = 0x00U;
+ pATIHW->lut[Index2 + 2] = maxColour;
+ }
+
+#ifndef AVOID_CPIO
+
+ if (pATI->depth == 1)
+ {
+ rgb blackColour = pScreenInfo->display->blackColour,
+ whiteColour = pScreenInfo->display->whiteColour;
+
+ if (blackColour.red > maxColour)
+ blackColour.red = maxColour;
+ if (blackColour.green > maxColour)
+ blackColour.green = maxColour;
+ if (blackColour.blue > maxColour)
+ blackColour.blue = maxColour;
+ if (whiteColour.red > maxColour)
+ whiteColour.red = maxColour;
+ if (whiteColour.green > maxColour)
+ whiteColour.green = maxColour;
+ if (whiteColour.blue > maxColour)
+ whiteColour.blue = maxColour;
+
+ if ((blackColour.red == whiteColour.red) &&
+ (blackColour.green == whiteColour.green) &&
+ (blackColour.blue == whiteColour.blue))
+ {
+ blackColour.red ^= maxColour;
+ blackColour.green ^= maxColour;
+ blackColour.blue ^= maxColour;
+ }
+
+ pATIHW->lut[(MONO_BLACK * 3) + 0] = blackColour.red;
+ pATIHW->lut[(MONO_BLACK * 3) + 1] = blackColour.green;
+ pATIHW->lut[(MONO_BLACK * 3) + 2] = blackColour.blue;
+ pATIHW->lut[(MONO_WHITE * 3) + 0] = whiteColour.red;
+ pATIHW->lut[(MONO_WHITE * 3) + 1] = whiteColour.green;
+ pATIHW->lut[(MONO_WHITE * 3) + 2] = whiteColour.blue;
+ }
+
+ if (pATIHW->crtc == ATI_CRTC_VGA)
+ {
+ /* Initialise overscan to black */
+ Index = pATIHW->attr[17] * 3;
+ pATIHW->lut[Index + 0] =
+ pATIHW->lut[Index + 1] =
+ pATIHW->lut[Index + 2] = 0x00U;
+ }
+
+#endif /* AVOID_CPIO */
+
+ }
+}
+
+/*
+ * ATIDACSave --
+ *
+ * This function is called to save the current RAMDAC state into an ATIHWRec
+ * structure occurrence.
+ */
+void
+ATIDACSave
+(
+ ATIPtr pATI,
+ ATIHWPtr pATIHW
+)
+{
+ int Index;
+
+#ifdef AVOID_CPIO
+
+ pATIHW->dac_read = in8(M64_DAC_READ);
+ DACDelay;
+ pATIHW->dac_write = in8(M64_DAC_WRITE);
+ DACDelay;
+ pATIHW->dac_mask = in8(M64_DAC_MASK);
+ DACDelay;
+
+ /* Save DAC's colour lookup table */
+ out8(M64_DAC_MASK, 0xFFU);
+ DACDelay;
+ out8(M64_DAC_READ, 0x00U);
+ DACDelay;
+ for (Index = 0; Index < NumberOf(pATIHW->lut); Index++)
+ {
+ pATIHW->lut[Index] = in8(M64_DAC_DATA);
+ DACDelay;
+ }
+
+ out8(M64_DAC_MASK, pATIHW->dac_mask);
+ DACDelay;
+ out8(M64_DAC_READ, pATIHW->dac_read);
+ DACDelay;
+
+#else /* AVOID_CPIO */
+
+ ATISetDACIOPorts(pATI, pATIHW->crtc);
+
+ pATIHW->dac_read = inb(pATI->CPIO_DAC_READ);
+ DACDelay;
+ pATIHW->dac_write = inb(pATI->CPIO_DAC_WRITE);
+ DACDelay;
+ pATIHW->dac_mask = inb(pATI->CPIO_DAC_MASK);
+ DACDelay;
+
+ /* Save DAC's colour lookup table */
+ outb(pATI->CPIO_DAC_MASK, 0xFFU);
+ DACDelay;
+ outb(pATI->CPIO_DAC_READ, 0x00U);
+ DACDelay;
+ for (Index = 0; Index < NumberOf(pATIHW->lut); Index++)
+ {
+ pATIHW->lut[Index] = inb(pATI->CPIO_DAC_DATA);
+ DACDelay;
+ }
+
+ outb(pATI->CPIO_DAC_MASK, pATIHW->dac_mask);
+ DACDelay;
+ outb(pATI->CPIO_DAC_READ, pATIHW->dac_read);
+ DACDelay;
+
+#endif /* AVOID_CPIO */
+
+}
+
+/*
+ * ATIDACSet --
+ *
+ * This function loads RAMDAC data from an ATIHWRec structure occurrence.
+ */
+void
+ATIDACSet
+(
+ ATIPtr pATI,
+ ATIHWPtr pATIHW
+)
+{
+ int Index;
+
+#ifdef AVOID_CPIO
+
+ /* Load DAC's colour lookup table */
+ out8(M64_DAC_MASK, 0xFFU);
+ DACDelay;
+ out8(M64_DAC_WRITE, 0x00U);
+ DACDelay;
+ for (Index = 0; Index < NumberOf(pATIHW->lut); Index++)
+ {
+ out8(M64_DAC_DATA, pATIHW->lut[Index]);
+ DACDelay;
+ }
+
+ out8(M64_DAC_MASK, pATIHW->dac_mask);
+ DACDelay;
+ out8(M64_DAC_READ, pATIHW->dac_read);
+ DACDelay;
+ out8(M64_DAC_WRITE, pATIHW->dac_write);
+ DACDelay;
+
+#else /* AVOID_CPIO */
+
+ ATISetDACIOPorts(pATI, pATIHW->crtc);
+
+ /* Load DAC's colour lookup table */
+ outb(pATI->CPIO_DAC_MASK, 0xFFU);
+ DACDelay;
+ outb(pATI->CPIO_DAC_WRITE, 0x00U);
+ DACDelay;
+ for (Index = 0; Index < NumberOf(pATIHW->lut); Index++)
+ {
+ outb(pATI->CPIO_DAC_DATA, pATIHW->lut[Index]);
+ DACDelay;
+ }
+
+ outb(pATI->CPIO_DAC_MASK, pATIHW->dac_mask);
+ DACDelay;
+ outb(pATI->CPIO_DAC_READ, pATIHW->dac_read);
+ DACDelay;
+ outb(pATI->CPIO_DAC_WRITE, pATIHW->dac_write);
+ DACDelay;
+
+#endif /* AVOID_CPIO */
+
+}
+
+/*
+ * ATILoadPalette --
+ *
+ * This function updates the RAMDAC's LUT and the in-memory copy of it in
+ * NewHW.
+ */
+void
+ATILoadPalette
+(
+ ScrnInfoPtr pScreenInfo,
+ int nColours,
+ int *Indices,
+ LOCO *Colours,
+ VisualPtr pVisual
+)
+{
+ ATIPtr pATI = ATIPTR(pScreenInfo);
+ CARD8 *LUTEntry;
+ int i, j, Index;
+
+ if (((pVisual->class | DynamicClass) == DirectColor) &&
+ ((1 << pVisual->nplanes) > (SizeOf(pATI->NewHW.lut) / 3)))
+ {
+ int reds = pVisual->redMask >> pVisual->offsetRed;
+ int greens = pVisual->greenMask >> pVisual->offsetGreen;
+ int blues = pVisual->blueMask >> pVisual->offsetBlue;
+
+ int redShift = 8 - pATI->weight.red;
+ int greenShift = 8 - pATI->weight.green;
+ int blueShift = 8 - pATI->weight.blue;
+
+ int redMult = 3 << redShift;
+ int greenMult = 3 << greenShift;
+ int blueMult = 3 << blueShift;
+
+ int minShift;
+
+ CARD8 fChanged[SizeOf(pATI->NewHW.lut) / 3];
+
+ (void)memset(fChanged, SizeOf(fChanged), 0);
+
+ minShift = redShift;
+ if (minShift > greenShift)
+ minShift = greenShift;
+ if (minShift > blueShift)
+ minShift = blueShift;
+
+ for (i = 0; i < nColours; i++)
+ {
+ if((Index = Indices[i]) < 0)
+ continue;
+
+ if (Index <= reds)
+ {
+ j = Index * redMult;
+ pATI->NewHW.lut[j + 0] = Colours[Index].red;
+ fChanged[j / 3] = TRUE;
+ }
+ if (Index <= greens)
+ {
+ j = Index * greenMult;
+ pATI->NewHW.lut[j + 1] = Colours[Index].green;
+ fChanged[j / 3] = TRUE;
+ }
+ if (Index <= blues)
+ {
+ j = Index * blueMult;
+ pATI->NewHW.lut[j + 2] = Colours[Index].blue;
+ fChanged[j / 3] = TRUE;
+ }
+ }
+
+ if (pScreenInfo->vtSema || pATI->currentMode)
+ {
+ /* Rewrite LUT entries that could have been changed */
+ i = 1 << minShift;
+ LUTEntry = pATI->NewHW.lut;
+
+ for (Index = 0;
+ Index < (SizeOf(pATI->NewHW.lut) / 3);
+ Index += i, LUTEntry += i * 3)
+ {
+ if (!fChanged[Index])
+ continue;
+
+#ifdef AVOID_CPIO
+
+ out8(M64_DAC_WRITE, Index);
+ DACDelay;
+ out8(M64_DAC_DATA, LUTEntry[0]);
+ DACDelay;
+ out8(M64_DAC_DATA, LUTEntry[1]);
+ DACDelay;
+ out8(M64_DAC_DATA, LUTEntry[2]);
+ DACDelay;
+
+#else /* AVOID_CPIO */
+
+ outb(pATI->CPIO_DAC_WRITE, Index);
+ DACDelay;
+ outb(pATI->CPIO_DAC_DATA, LUTEntry[0]);
+ DACDelay;
+ outb(pATI->CPIO_DAC_DATA, LUTEntry[1]);
+ DACDelay;
+ outb(pATI->CPIO_DAC_DATA, LUTEntry[2]);
+ DACDelay;
+
+#endif /* AVOID_CPIO */
+
+ }
+ }
+ }
+ else
+ {
+ for (i = 0; i < nColours; i++)
+ {
+ Index = Indices[i];
+ if ((Index < 0) || (Index >= (SizeOf(pATI->NewHW.lut) / 3)))
+ continue;
+
+ LUTEntry = &pATI->NewHW.lut[Index * 3];
+ LUTEntry[0] = Colours[Index].red;
+ LUTEntry[1] = Colours[Index].green;
+ LUTEntry[2] = Colours[Index].blue;
+
+ if (pScreenInfo->vtSema || pATI->currentMode)
+ {
+
+#ifdef AVOID_CPIO
+
+ out8(M64_DAC_WRITE, Index);
+ DACDelay;
+ out8(M64_DAC_DATA, LUTEntry[0]);
+ DACDelay;
+ out8(M64_DAC_DATA, LUTEntry[1]);
+ DACDelay;
+ out8(M64_DAC_DATA, LUTEntry[2]);
+ DACDelay;
+
+#else /* AVOID_CPIO */
+
+ outb(pATI->CPIO_DAC_WRITE, Index);
+ DACDelay;
+ outb(pATI->CPIO_DAC_DATA, LUTEntry[0]);
+ DACDelay;
+ outb(pATI->CPIO_DAC_DATA, LUTEntry[1]);
+ DACDelay;
+ outb(pATI->CPIO_DAC_DATA, LUTEntry[2]);
+ DACDelay;
+
+#endif /* AVOID_CPIO */
+
+ }
+ }
+ }
+}