summaryrefslogtreecommitdiff
path: root/src/ativga.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ativga.c')
-rw-r--r--src/ativga.c532
1 files changed, 532 insertions, 0 deletions
diff --git a/src/ativga.c b/src/ativga.c
new file mode 100644
index 00000000..9a732a37
--- /dev/null
+++ b/src/ativga.c
@@ -0,0 +1,532 @@
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/ativga.c,v 1.19 2003/01/01 19:16:34 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 "atiadapter.h"
+#include "atichip.h"
+#include "atimono.h"
+#include "atistruct.h"
+#include "ativga.h"
+#include "ativgaio.h"
+
+#ifndef DPMS_SERVER
+# define DPMS_SERVER
+#endif
+#include "extensions/dpms.h"
+
+#ifndef AVOID_CPIO
+
+/*
+ * ATIVGAPreInit --
+ *
+ * This function is called to set up VGA-related data that is common to all
+ * video modes generated by the driver.
+ */
+void
+ATIVGAPreInit
+(
+ ATIPtr pATI,
+ ATIHWPtr pATIHW
+)
+{
+ int Index;
+
+ /* Initialise sequencer register values */
+ pATIHW->seq[0] = 0x03U;
+ if (pATI->depth == 1)
+ pATIHW->seq[2] = 0x01U << BIT_PLANE;
+ else
+ pATIHW->seq[2] = 0x0FU;
+ if (pATI->depth <= 4)
+ pATIHW->seq[4] = 0x06U;
+ else if (pATI->Adapter == ATI_ADAPTER_VGA)
+ pATIHW->seq[4] = 0x0EU;
+ else
+ pATIHW->seq[4] = 0x0AU;
+
+ /* Initialise CRTC register values */
+ if ((pATI->depth >= 8) &&
+ ((pATI->Chip >= ATI_CHIP_264CT) ||
+ (pATI->CPIO_VGAWonder &&
+ (pATI->Chip <= ATI_CHIP_18800_1) &&
+ (pATI->VideoRAM == 256))))
+ pATIHW->crt[19] = pATI->displayWidth >> 3;
+ else
+ pATIHW->crt[19] = pATI->displayWidth >> 4;
+ if ((pATI->depth >= 8) && (pATI->Adapter == ATI_ADAPTER_VGA))
+ pATIHW->crt[23] = 0xC3U;
+ else
+ pATIHW->crt[23] = 0xE3U;
+ pATIHW->crt[24] = 0xFFU;
+
+ /* Initialise attribute controller register values */
+ if (pATI->depth == 1)
+ {
+ Bool FlipPixels = xf86GetFlipPixels();
+
+ for (Index = 0; Index < 16; Index++)
+ if (((Index & (0x01U << BIT_PLANE)) != 0) != FlipPixels)
+ pATIHW->attr[Index] = MONO_WHITE;
+ else
+ pATIHW->attr[Index] = MONO_BLACK;
+ pATIHW->attr[16] = 0x01U;
+ pATIHW->attr[17] = MONO_OVERSCAN;
+ }
+ else
+ {
+ for (Index = 0; Index < 16; Index++)
+ pATIHW->attr[Index] = Index;
+ if (pATI->depth <= 4)
+ pATIHW->attr[16] = 0x81U;
+ else if (pATI->Adapter == ATI_ADAPTER_VGA)
+ pATIHW->attr[16] = 0x41U;
+ else
+ pATIHW->attr[16] = 0x01U;
+ pATIHW->attr[17] = 0xFFU;
+ }
+ pATIHW->attr[18] = 0x0FU;
+
+ /* Initialise graphics controller register values */
+ if (pATI->depth == 1)
+ pATIHW->gra[4] = BIT_PLANE;
+ else if (pATI->depth <= 4)
+ pATIHW->gra[5] = 0x02U;
+ else if (pATI->Chip >= ATI_CHIP_264CT)
+ pATIHW->gra[5] = 0x40U;
+ if (pATI->UseSmallApertures && (pATI->Chip >= ATI_CHIP_264CT) &&
+ ((pATI->Chip >= ATI_CHIP_264VT) || !pATI->LinearBase))
+ pATIHW->gra[6] = 0x01U; /* 128kB aperture */
+ else
+ pATIHW->gra[6] = 0x05U; /* 64kB aperture */
+ pATIHW->gra[7] = 0x0FU;
+ pATIHW->gra[8] = 0xFFU;
+}
+
+/*
+ * ATIVGASave --
+ *
+ * This function is called to save the VGA portion of the current video state.
+ */
+void
+ATIVGASave
+(
+ ATIPtr pATI,
+ ATIHWPtr pATIHW
+)
+{
+ int Index;
+
+ /* Save miscellaneous output register */
+ pATIHW->genmo = inb(R_GENMO);
+ ATISetVGAIOBase(pATI, pATIHW->genmo);
+
+ /* Save sequencer registers */
+ for (Index = 0; Index < NumberOf(pATIHW->seq); Index++)
+ pATIHW->seq[Index] = GetReg(SEQX, Index);
+
+ /* Save CRTC registers */
+ for (Index = 0; Index < NumberOf(pATIHW->crt); Index++)
+ pATIHW->crt[Index] = GetReg(CRTX(pATI->CPIO_VGABase), Index);
+
+ /* Save attribute controller registers */
+ for (Index = 0; Index < NumberOf(pATIHW->attr); Index++)
+ {
+ (void)inb(GENS1(pATI->CPIO_VGABase)); /* Reset flip-flop */
+ pATIHW->attr[Index] = GetReg(ATTRX, Index);
+ }
+
+ /* Save graphics controller registers */
+ for (Index = 0; Index < NumberOf(pATIHW->gra); Index++)
+ pATIHW->gra[Index] = GetReg(GRAX, Index);
+}
+
+/*
+ * ATIVGACalculate --
+ *
+ * This function fills in the VGA portion of an ATIHWRec.
+ */
+void
+ATIVGACalculate
+(
+ ATIPtr pATI,
+ ATIHWPtr pATIHW,
+ DisplayModePtr pMode
+)
+{
+ int Index, VDisplay;
+
+ /* If not already done, adjust horizontal timings */
+ if (!pMode->CrtcHAdjusted)
+ {
+ pMode->CrtcHAdjusted = TRUE;
+ pMode->CrtcHDisplay = (pMode->HDisplay >> 3) - 1;
+ pMode->CrtcHBlankStart = (pMode->HDisplay >> 3);
+ if ((pATI->Chip == ATI_CHIP_18800_1) ||
+ (pATI->Chip >= ATI_CHIP_264CT))
+ pMode->CrtcHBlankStart--;
+ pMode->CrtcHSyncStart = pMode->HSyncStart >> 3;
+ pMode->CrtcHSyncEnd = pMode->HSyncEnd >> 3;
+ pMode->CrtcHBlankEnd = (pMode->HTotal >> 3) - 1;
+ pMode->CrtcHTotal = (pMode->HTotal >> 3) - 5;
+ pMode->CrtcHSkew = pMode->HSkew;
+
+ /* Check sync pulse width */
+ Index = pMode->CrtcHSyncEnd - pMode->CrtcHSyncStart - 0x1F;
+ if (Index > 0)
+ {
+ pMode->CrtcHSyncStart += Index / 2;
+ pMode->CrtcHSyncEnd = pMode->CrtcHSyncStart + 0x1F;
+ }
+
+ /* Check blank pulse width */
+ Index = pMode->CrtcHBlankEnd - pMode->CrtcHBlankStart - 0x3F;
+ if (Index > 0)
+ {
+ if ((pMode->CrtcHBlankEnd - Index) > pMode->CrtcHSyncEnd)
+ {
+ pMode->CrtcHBlankStart += Index / 2;
+ if (pMode->CrtcHBlankStart >= pMode->CrtcHSyncStart)
+ pMode->CrtcHBlankStart = pMode->CrtcHSyncStart - 1;
+ pMode->CrtcHBlankEnd = pMode->CrtcHBlankStart + 0x3F;
+ }
+ else
+ {
+ Index -= 0x40;
+ if (Index > 0)
+ {
+ pMode->CrtcHBlankStart += Index / 2;
+ if (pMode->CrtcHBlankStart >= pMode->CrtcHSyncStart)
+ pMode->CrtcHBlankStart = pMode->CrtcHSyncStart - 1;
+ pMode->CrtcHBlankEnd = pMode->CrtcHBlankStart + 0x7F;
+ }
+ }
+ }
+ }
+
+ /*
+ * Because of the use of CRTC[23] bit 0x04's for vertical doubling, it is
+ * necessary to always re-adjust vertical timings here.
+ */
+ pMode->CrtcVDisplay = pMode->VDisplay;
+ pMode->CrtcVBlankStart = pMode->VDisplay;
+ pMode->CrtcVSyncStart = pMode->VSyncStart;
+ pMode->CrtcVSyncEnd = pMode->VSyncEnd;
+ pMode->CrtcVBlankEnd = pMode->VTotal;
+ pMode->CrtcVTotal = pMode->VTotal;
+
+ /* Adjust for doublescanned modes */
+ if (pMode->Flags & V_DBLSCAN)
+ {
+ pMode->CrtcVDisplay <<= 1;
+ pMode->CrtcVBlankStart <<= 1;
+ pMode->CrtcVSyncStart <<= 1;
+ pMode->CrtcVSyncEnd <<= 1;
+ pMode->CrtcVBlankEnd <<= 1;
+ pMode->CrtcVTotal <<= 1;
+ }
+
+ /* Adjust for multiscanned modes */
+ if (pMode->VScan > 1)
+ {
+ pMode->CrtcVDisplay *= pMode->VScan;
+ pMode->CrtcVBlankStart *= pMode->VScan;
+ pMode->CrtcVSyncStart *= pMode->VScan;
+ pMode->CrtcVSyncEnd *= pMode->VScan;
+ pMode->CrtcVBlankEnd *= pMode->VScan;
+ pMode->CrtcVTotal *= pMode->VScan;
+ }
+
+ /* Set up miscellaneous output register value */
+ pATIHW->genmo = 0x23U;
+ if ((pMode->Flags & (V_PHSYNC | V_NHSYNC)) &&
+ (pMode->Flags & (V_PVSYNC | V_NVSYNC)))
+ {
+ if (pMode->Flags & V_NHSYNC)
+ pATIHW->genmo |= 0x40U;
+ if (pMode->Flags & V_NVSYNC)
+ pATIHW->genmo |= 0x80U;
+ }
+ else
+ {
+ pMode->Flags &= ~(V_PHSYNC | V_NHSYNC | V_PVSYNC | V_NVSYNC);
+
+ if (pATI->OptionPanelDisplay && (pATI->LCDPanelID >= 0))
+ VDisplay = pATI->LCDVertical;
+ else
+ VDisplay = pMode->CrtcVDisplay;
+
+ if (VDisplay < 400)
+ {
+ pMode->Flags |= V_PHSYNC | V_NVSYNC;
+ pATIHW->genmo |= 0x80U;
+ }
+ else if (VDisplay < 480)
+ {
+ pMode->Flags |= V_NHSYNC | V_PVSYNC;
+ pATIHW->genmo |= 0x40U;
+ }
+ else if (VDisplay < 768)
+ {
+ pMode->Flags |= V_NHSYNC | V_NVSYNC;
+ pATIHW->genmo |= 0xC0U;
+ }
+ else
+ {
+ pMode->Flags |= V_PHSYNC | V_PVSYNC;
+ }
+ }
+
+ /* Adjust for interlaced modes */
+ if ((pMode->Flags & V_INTERLACE) && (pATI->Chip < ATI_CHIP_264CT))
+ {
+ pMode->CrtcVDisplay >>= 1;
+ pMode->CrtcVBlankStart >>= 1;
+ pMode->CrtcVSyncStart >>= 1;
+ pMode->CrtcVSyncEnd >>= 1;
+ pMode->CrtcVBlankEnd >>= 1;
+ pMode->CrtcVTotal >>= 1;
+ }
+
+ if (pMode->CrtcVTotal > 1024)
+ {
+ pATIHW->crt[23] |= 0x04U;
+ pMode->CrtcVDisplay >>= 1;
+ pMode->CrtcVBlankStart >>= 1;
+ pMode->CrtcVSyncStart >>= 1;
+ pMode->CrtcVSyncEnd >>= 1;
+ pMode->CrtcVBlankEnd >>= 1;
+ pMode->CrtcVTotal >>= 1;
+ }
+ else
+ pATIHW->crt[23] &= ~0x04U;
+
+ pMode->CrtcVDisplay--;
+ if (pATI->Chip == ATI_CHIP_18800)
+ pMode->CrtcVBlankStart++;
+ else
+ pMode->CrtcVBlankStart--;
+ pMode->CrtcVBlankEnd--;
+ if (pATI->Chip < ATI_CHIP_264CT)
+ pMode->CrtcVBlankEnd--;
+ pMode->CrtcVTotal -= 2;
+ pMode->CrtcVAdjusted = TRUE; /* Redundant */
+
+ /* Check sync pulse width */
+ Index = pMode->CrtcVSyncEnd - pMode->CrtcVSyncStart - 0x0F;
+ if (Index > 0)
+ {
+ pMode->CrtcVSyncStart += Index / 2;
+ pMode->CrtcVSyncEnd = pMode->CrtcVSyncStart + 0x0F;
+ }
+
+ /* Check blank pulse width */
+ Index = pMode->CrtcVBlankEnd - pMode->CrtcVBlankStart - 0x00FF;
+ if (Index > 0)
+ {
+ if ((pMode->CrtcVBlankEnd - Index) > pMode->CrtcVSyncEnd)
+ {
+ pMode->CrtcVBlankStart += Index / 2;
+ if (pMode->CrtcVBlankStart >= pMode->CrtcVSyncStart)
+ pMode->CrtcVBlankStart = pMode->CrtcVSyncStart - 1;
+ pMode->CrtcVBlankEnd = pMode->CrtcVBlankStart + 0x00FF;
+ }
+ else
+ {
+ Index -= 0x0100;
+ if (Index > 0)
+ {
+ pMode->CrtcVBlankStart += Index / 2;
+ if (pMode->CrtcVBlankStart >= pMode->CrtcVSyncStart)
+ pMode->CrtcVBlankStart = pMode->CrtcVSyncStart - 1;
+ pMode->CrtcVBlankEnd = pMode->CrtcVBlankStart + 0x01FF;
+ }
+ }
+ }
+
+ /* Set up sequencer register values */
+ if (pMode->Flags & V_CLKDIV2)
+ pATIHW->seq[1] = 0x09U;
+ else
+ pATIHW->seq[1] = 0x01U;
+
+ /* Set up CRTC register values */
+ pATIHW->crt[0] = pMode->CrtcHTotal;
+ pATIHW->crt[1] = pMode->CrtcHDisplay;
+ pATIHW->crt[2] = pMode->CrtcHBlankStart;
+ pATIHW->crt[3] = (pMode->CrtcHBlankEnd & 0x1FU) | 0x80U;
+ Index = ((pMode->CrtcHSkew << 2) + 0x10U) & ~0x1FU;
+ if (Index < 0x0080)
+ pATIHW->crt[3] |= Index;
+ pATIHW->crt[4] = pMode->CrtcHSyncStart;
+ pATIHW->crt[5] = ((pMode->CrtcHBlankEnd & 0x20U) << 2) |
+ ((pMode->CrtcHSyncEnd & 0x1FU) );
+ pATIHW->crt[6] = pMode->CrtcVTotal & 0xFFU;
+ pATIHW->crt[7] = ((pMode->CrtcVTotal & 0x0100U) >> 8) |
+ ((pMode->CrtcVDisplay & 0x0100U) >> 7) |
+ ((pMode->CrtcVSyncStart & 0x0100U) >> 6) |
+ ((pMode->CrtcVBlankStart & 0x0100U) >> 5) |
+ 0x10U |
+ ((pMode->CrtcVTotal & 0x0200U) >> 4) |
+ ((pMode->CrtcVDisplay & 0x0200U) >> 3) |
+ ((pMode->CrtcVSyncStart & 0x0200U) >> 2);
+ pATIHW->crt[9] = ((pMode->CrtcVBlankStart & 0x0200U) >> 4) | 0x40U;
+ /*
+ * Doublescanned modes are missing the top scanline. Convert
+ * doublescanning to multiscanning, using the doublescan bit only as a last
+ * resort.
+ */
+ if ((Index = pMode->VScan) <= 0)
+ Index = 1;
+ if (pMode->Flags & V_DBLSCAN)
+ Index <<= 1;
+ Index--;
+ pATIHW->crt[9] |= (Index & 0x1FU) | ((Index & 0x20U) << 2);
+ pATIHW->crt[16] = pMode->CrtcVSyncStart & 0xFFU;
+ pATIHW->crt[17] = (pMode->CrtcVSyncEnd & 0x0FU) | 0x20U;
+ pATIHW->crt[18] = pMode->CrtcVDisplay & 0xFFU;
+ pATIHW->crt[21] = pMode->CrtcVBlankStart & 0xFFU;
+ pATIHW->crt[22] = pMode->CrtcVBlankEnd & 0xFFU;
+}
+
+/*
+ * ATIVGASet --
+ *
+ * This function is called to load the VGA portion of a video state.
+ */
+void
+ATIVGASet
+(
+ ATIPtr pATI,
+ ATIHWPtr pATIHW
+)
+{
+ int Index;
+
+ /* Set VGA I/O base */
+ ATISetVGAIOBase(pATI, pATIHW->genmo);
+
+ /* Load miscellaneous output register */
+ outb(GENMO, pATIHW->genmo);
+
+ /* Load sequencer in reverse index order; this also ends its reset */
+ for (Index = NumberOf(pATIHW->seq); --Index >= 0; )
+ PutReg(SEQX, Index, pATIHW->seq[Index]);
+
+ /* Load CRTC registers */
+ for (Index = 0; Index < NumberOf(pATIHW->crt); Index++)
+ PutReg(CRTX(pATI->CPIO_VGABase), Index, pATIHW->crt[Index]);
+
+ /* Load attribute controller registers */
+ for (Index = 0; Index < NumberOf(pATIHW->attr); Index++)
+ {
+ (void)inb(GENS1(pATI->CPIO_VGABase)); /* Reset flip-flop & delay */
+ outb(ATTRX, Index);
+ outb(ATTRX, pATIHW->attr[Index]);
+ }
+
+ /* Load graphics controller registers */
+ for (Index = 0; Index < NumberOf(pATIHW->gra); Index++)
+ PutReg(GRAX, Index, pATIHW->gra[Index]);
+}
+
+/*
+ * ATIVGASaveScreen --
+ *
+ * This function blanks or unblanks a VGA screen.
+ */
+void
+ATIVGASaveScreen
+(
+ ATIPtr pATI,
+ int Mode
+)
+{
+ (void)inb(GENS1(pATI->CPIO_VGABase)); /* Reset flip-flop */
+
+ switch (Mode)
+ {
+ case SCREEN_SAVER_OFF:
+ case SCREEN_SAVER_FORCER:
+ outb(ATTRX, 0x20U); /* Turn PAS on */
+ break;
+
+ case SCREEN_SAVER_ON:
+ case SCREEN_SAVER_CYCLE:
+ outb(ATTRX, 0x00U); /* Turn PAS off */
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*
+ * ATIVGASetDPMSMode --
+ *
+ * This function sets a VGA's VESA Display Power Management Signaling mode.
+ */
+void
+ATIVGASetDPMSMode
+(
+ ATIPtr pATI,
+ int DPMSMode
+)
+{
+ CARD8 seq1, crt17;
+
+ switch (DPMSMode)
+ {
+ case DPMSModeOn: /* HSync on, VSync on */
+ seq1 = 0x00U;
+ crt17 = 0x80U;
+ break;
+
+ case DPMSModeStandby: /* HSync off, VSync on -- unsupported */
+ seq1 = 0x20U;
+ crt17 = 0x80U;
+ break;
+
+ case DPMSModeSuspend: /* HSync on, VSync off -- unsupported */
+ seq1 = 0x20U;
+ crt17 = 0x80U;
+ break;
+
+ case DPMSModeOff: /* HSync off, VSync off */
+ seq1 = 0x20U;
+ crt17 = 0x00U;
+ break;
+
+ default: /* Muffle compiler */
+ return;
+ }
+
+ PutReg(SEQX, 0x00U, 0x01U); /* Start synchonous reset */
+ seq1 |= GetReg(SEQX, 0x01U) & ~0x20U;
+ PutReg(SEQX, 0x01U, seq1);
+ crt17 |= GetReg(CRTX(pATI->CPIO_VGABase), 0x17U) & ~0x80U;
+ usleep(10000);
+ PutReg(CRTX(pATI->CPIO_VGABase), 0x17U, crt17);
+ PutReg(SEQX, 0x01U, 0x03U); /* End synchonous reset */
+}
+
+#endif /* AVOID_CPIO */