132b578d3Smrg/*
232b578d3Smrg * Copyright 1999 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org
332b578d3Smrg *
432b578d3Smrg * Permission to use, copy, modify, distribute, and sell this software and its
532b578d3Smrg * documentation for any purpose is hereby granted without fee, provided that
632b578d3Smrg * the above copyright notice appear in all copies and that both that copyright
732b578d3Smrg * notice and this permission notice appear in supporting documentation, and
832b578d3Smrg * that the name of Marc Aurele La France not be used in advertising or
932b578d3Smrg * publicity pertaining to distribution of the software without specific,
1032b578d3Smrg * written prior permission.  Marc Aurele La France makes no representations
1132b578d3Smrg * about the suitability of this software for any purpose.  It is provided
1232b578d3Smrg * "as-is" without express or implied warranty.
1332b578d3Smrg *
1432b578d3Smrg * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1532b578d3Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO
1632b578d3Smrg * EVENT SHALL MARC AURELE LA FRANCE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
1732b578d3Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
1832b578d3Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
1932b578d3Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
2032b578d3Smrg * PERFORMANCE OF THIS SOFTWARE.
2132b578d3Smrg */
2232b578d3Smrg
2332b578d3Smrg#ifdef HAVE_CONFIG_H
2432b578d3Smrg#include "config.h"
2532b578d3Smrg#endif
2632b578d3Smrg
2732b578d3Smrg#include <string.h>
2832b578d3Smrg#include <stdio.h>
2932b578d3Smrg
3007f4e327Smacallan#ifdef __NetBSD__
3107f4e327Smacallan#include <sys/time.h>
3207f4e327Smacallan#include <sys/ioctl.h>
3307f4e327Smacallan#include <errno.h>
3407f4e327Smacallan#include <dev/wscons/wsconsio.h>
3507f4e327Smacallan#endif
3607f4e327Smacallan
3732b578d3Smrg#include "ati.h"
3832b578d3Smrg#include "atiaudio.h"
3932b578d3Smrg#include "atibus.h"
4032b578d3Smrg#include "atichip.h"
4132b578d3Smrg#include "aticursor.h"
4232b578d3Smrg#include "atidac.h"
4332b578d3Smrg#include "atidsp.h"
4432b578d3Smrg#include "atii2c.h"
4532b578d3Smrg#include "atiload.h"
4632b578d3Smrg#include "atilock.h"
4732b578d3Smrg#include "atimach64.h"
4832b578d3Smrg#include "atimach64accel.h"
4932b578d3Smrg#include "atimach64io.h"
5032b578d3Smrg#include "atimach64probe.h"
5132b578d3Smrg#include "atimode.h"
5232b578d3Smrg#include "atioption.h"
5332b578d3Smrg#include "atipreinit.h"
5432b578d3Smrg#include "atiprint.h"
5532b578d3Smrg#include "atiprobe.h"
5632b578d3Smrg#include "atividmem.h"
5732b578d3Smrg#include "atiwonderio.h"
5832b578d3Smrg#include "atixv.h"
5984354367Smrg#include "atiadjust.h"
6032b578d3Smrg
6132b578d3Smrg#include "vbe.h"
622a51b5beSmrg#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 6
6332b578d3Smrg#include "xf86RAC.h"
642a51b5beSmrg#endif
6532b578d3Smrg
6607f4e327Smacallan#include "xf86Priv.h"
67a6bf028eSmrg#include "xf86Privstr.h"
6807f4e327Smacallan
6932b578d3Smrg/*
7032b578d3Smrg * FreeScreen handles the clean-up.
7132b578d3Smrg */
7232b578d3Smrgstatic Bool
7332b578d3SmrgMach64GetRec(ScrnInfoPtr pScrn)
7432b578d3Smrg{
7532b578d3Smrg    if (!pScrn->driverPrivate) {
7632b578d3Smrg        pScrn->driverPrivate = xnfcalloc(sizeof(ATIRec), 1);
7732b578d3Smrg        memset(pScrn->driverPrivate, 0, sizeof(ATIRec));
7832b578d3Smrg    }
7932b578d3Smrg
8032b578d3Smrg    return TRUE;
8132b578d3Smrg}
8232b578d3Smrg
8332b578d3Smrg/*
8432b578d3Smrg * ATIReportMemory --
8532b578d3Smrg *
8632b578d3Smrg * This function reports on the amount and type of video memory found.
8732b578d3Smrg */
8832b578d3Smrgstatic void
8932b578d3SmrgATIReportMemory
9032b578d3Smrg(
9132b578d3Smrg    ScrnInfoPtr pScreenInfo,
9232b578d3Smrg    ATIPtr      pATI,
9332b578d3Smrg    const char *MemoryTypeName
9432b578d3Smrg)
9532b578d3Smrg{
9632b578d3Smrg    char Buffer[128], *Message;
9732b578d3Smrg
9832b578d3Smrg    Message = Buffer +
9932b578d3Smrg        snprintf(Buffer, SizeOf(Buffer), "%d kB of %s detected",
10032b578d3Smrg            pATI->VideoRAM, MemoryTypeName);
10132b578d3Smrg
10232b578d3Smrg    if (pATI->VideoRAM > pScreenInfo->videoRam)
10332b578d3Smrg    {
10432b578d3Smrg        Message += snprintf(Message, Buffer + SizeOf(Buffer) - Message,
10532b578d3Smrg            " (using %d kB)", pScreenInfo->videoRam);
10632b578d3Smrg    }
10732b578d3Smrg    xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED, "%s.\n", Buffer);
10832b578d3Smrg}
10932b578d3Smrg
11032b578d3Smrgstatic const int videoRamSizes[] =
11132b578d3Smrg    {512, 1024, 2*1024, 4*1024, 6*1024, 8*1024, 12*1024, 16*1024};
11232b578d3Smrgstatic const rgb   defaultWeight = {0, 0, 0};
11332b578d3Smrgstatic const Gamma defaultGamma  = {0.0, 0.0, 0.0};
11432b578d3Smrg
11532b578d3Smrg/*
11632b578d3Smrg * ATIPrintNoiseIfRequested --
11732b578d3Smrg *
11832b578d3Smrg * This function formats debugging information on the server's stderr when
11932b578d3Smrg * requested by the user through the server's verbosity setting.
12032b578d3Smrg */
12132b578d3Smrgstatic void
12232b578d3SmrgATIPrintNoiseIfRequested
12332b578d3Smrg(
12432b578d3Smrg    ATIPtr       pATI,
12532b578d3Smrg    CARD8       *BIOS,
12632b578d3Smrg    unsigned int BIOSSize
12732b578d3Smrg)
12832b578d3Smrg{
12932b578d3Smrg    if (xf86GetVerbosity() <= 3)
13032b578d3Smrg        return;
13132b578d3Smrg
13232b578d3Smrg    if (BIOSSize > 0)
13332b578d3Smrg        ATIPrintBIOS(BIOS, BIOSSize);
13432b578d3Smrg    xf86ErrorFVerb(4, "\n On server entry:\n");
13532b578d3Smrg    ATIPrintRegisters(pATI);
13632b578d3Smrg}
13732b578d3Smrg
13832b578d3Smrg#define BIOS_SIZE    0x00010000U     /* 64kB */
13932b578d3Smrg#define BIOSByte(_n) ((CARD8)(BIOS[_n]))
14032b578d3Smrg#define BIOSWord(_n) ((CARD16)(BIOS[_n] |                \
14132b578d3Smrg                               (BIOS[(_n) + 1] << 8)))
14232b578d3Smrg
14332b578d3Smrg/*
14432b578d3Smrg * For Mach64 adapters, pick up, from the BIOS, the type of programmable
14532b578d3Smrg * clock generator (if any), and various information about it.
14632b578d3Smrg */
14732b578d3Smrgstatic void
14832b578d3Smrgati_bios_clock
14932b578d3Smrg(
15032b578d3Smrg    ScrnInfoPtr  pScreenInfo,
15132b578d3Smrg    ATIPtr       pATI,
15232b578d3Smrg    CARD8       *BIOS,
15332b578d3Smrg    unsigned int ClockTable,
15432b578d3Smrg    GDevPtr      pGDev
15532b578d3Smrg)
15632b578d3Smrg{
15732b578d3Smrg    CARD16 ClockDac;
15832b578d3Smrg
15932b578d3Smrg    if (ClockTable > 0)
16032b578d3Smrg    {
16132b578d3Smrg        pATI->ProgrammableClock = BIOSByte(ClockTable);
16232b578d3Smrg        pATI->ClockNumberToProgramme = BIOSByte(ClockTable + 0x06U);
16332b578d3Smrg        pATI->refclk = BIOSWord(ClockTable + 0x08U);
16432b578d3Smrg        pATI->refclk *= 10000;
16532b578d3Smrg    }
16632b578d3Smrg    else
16732b578d3Smrg    {
16832b578d3Smrg        /*
16932b578d3Smrg         * Compensate for BIOS absence.  Note that the reference
17032b578d3Smrg         * frequency has already been set by option processing.
17132b578d3Smrg         */
17232b578d3Smrg        if ((pATI->DAC & ~0x0FU) == ATI_DAC_INTERNAL)
17332b578d3Smrg        {
17432b578d3Smrg            pATI->ProgrammableClock = ATI_CLOCK_INTERNAL;
17532b578d3Smrg        }
17632b578d3Smrg        else switch (pATI->DAC)
17732b578d3Smrg        {
17832b578d3Smrg            case ATI_DAC_STG1703:
17932b578d3Smrg                pATI->ProgrammableClock = ATI_CLOCK_STG1703;
18032b578d3Smrg                break;
18132b578d3Smrg
18232b578d3Smrg            case ATI_DAC_CH8398:
18332b578d3Smrg                pATI->ProgrammableClock = ATI_CLOCK_CH8398;
18432b578d3Smrg                break;
18532b578d3Smrg
18632b578d3Smrg            case ATI_DAC_ATT20C408:
18732b578d3Smrg                pATI->ProgrammableClock = ATI_CLOCK_ATT20C408;
18832b578d3Smrg                break;
18932b578d3Smrg
19032b578d3Smrg            case ATI_DAC_IBMRGB514:
19132b578d3Smrg                pATI->ProgrammableClock = ATI_CLOCK_IBMRGB514;
19232b578d3Smrg                break;
19332b578d3Smrg
19432b578d3Smrg            default:        /* Provisional */
19532b578d3Smrg                pATI->ProgrammableClock = ATI_CLOCK_ICS2595;
19632b578d3Smrg                break;
19732b578d3Smrg        }
19832b578d3Smrg
19932b578d3Smrg        /* This should be safe for all generators except IBM's RGB514 */
20032b578d3Smrg        pATI->ClockNumberToProgramme = 3;
20132b578d3Smrg    }
20232b578d3Smrg
20332b578d3Smrg    pATI->ClockDescriptor = ATIClockDescriptors[ATI_CLOCK_FIXED];
20432b578d3Smrg
20532b578d3Smrg    if ((pATI->ProgrammableClock > ATI_CLOCK_FIXED) &&
20632b578d3Smrg        (pATI->ProgrammableClock < ATI_CLOCK_MAX))
20732b578d3Smrg    {
20832b578d3Smrg        /*
20932b578d3Smrg         * Graphics PRO TURBO 1600's are unusual in that an ICS2595 is used
21032b578d3Smrg         * to generate clocks for VGA modes, and an IBM RGB514 is used for
21132b578d3Smrg         * accelerator modes.
21232b578d3Smrg         */
21332b578d3Smrg        if ((pATI->ProgrammableClock == ATI_CLOCK_ICS2595) &&
21432b578d3Smrg            (pATI->DAC == ATI_DAC_IBMRGB514))
21532b578d3Smrg            pATI->ProgrammableClock = ATI_CLOCK_IBMRGB514;
21632b578d3Smrg
21732b578d3Smrg        pATI->ClockDescriptor = ATIClockDescriptors[pATI->ProgrammableClock];
21832b578d3Smrg    }
21932b578d3Smrg
22032b578d3Smrg    ClockDac = pATI->DAC;
22132b578d3Smrg    switch (pATI->ProgrammableClock)
22232b578d3Smrg    {
22332b578d3Smrg        case ATI_CLOCK_ICS2595:
22432b578d3Smrg            /*
22532b578d3Smrg             * Pick up reference divider (43 or 46) appropriate to the chip
22632b578d3Smrg             * revision level.
22732b578d3Smrg             */
22832b578d3Smrg            if (ClockTable > 0)
22932b578d3Smrg                pATI->ClockDescriptor.MinM =
23032b578d3Smrg                pATI->ClockDescriptor.MaxM = BIOSWord(ClockTable + 0x0AU);
23132b578d3Smrg            else if (!xf86NameCmp(pGDev->clockchip, "ATI 18818-0"))
23232b578d3Smrg                pATI->ClockDescriptor.MinM =
23332b578d3Smrg                pATI->ClockDescriptor.MaxM = 43;
23432b578d3Smrg            else if (!xf86NameCmp(pGDev->clockchip, "ATI 18818-1"))
23532b578d3Smrg                pATI->ClockDescriptor.MinM =
23632b578d3Smrg                pATI->ClockDescriptor.MaxM = 46;
23732b578d3Smrg            else
23832b578d3Smrg                pATI->ProgrammableClock = ATI_CLOCK_UNKNOWN;
23932b578d3Smrg            break;
24032b578d3Smrg
24132b578d3Smrg        case ATI_CLOCK_STG1703:
24232b578d3Smrg            /* This one's also a RAMDAC */
24332b578d3Smrg            ClockDac = ATI_DAC_STG1703;
24432b578d3Smrg            break;
24532b578d3Smrg
24632b578d3Smrg        case ATI_CLOCK_CH8398:
24732b578d3Smrg            /* This one's also a RAMDAC */
24832b578d3Smrg            ClockDac = ATI_DAC_CH8398;
24932b578d3Smrg            break;
25032b578d3Smrg
25132b578d3Smrg        case ATI_CLOCK_INTERNAL:
25232b578d3Smrg            /*
25332b578d3Smrg             * The reference divider has already been programmed by BIOS
25432b578d3Smrg             * initialisation.  Because, there is only one reference
25532b578d3Smrg             * divider for all generated frequencies (including MCLK), it
25632b578d3Smrg             * cannot be changed without reprogramming all clocks every
25732b578d3Smrg             * time one of them needs a different reference divider.
25832b578d3Smrg             *
25932b578d3Smrg             * Besides, it's not a good idea to change the reference
26032b578d3Smrg             * divider.  BIOS initialisation sets it to a value that
26132b578d3Smrg             * effectively prevents generating frequencies beyond the
26232b578d3Smrg             * graphics controller's tolerance.
26332b578d3Smrg             */
26432b578d3Smrg            pATI->ClockDescriptor.MinM =
26532b578d3Smrg            pATI->ClockDescriptor.MaxM = ATIMach64GetPLLReg(PLL_REF_DIV);
26632b578d3Smrg
26732b578d3Smrg            /* The DAC is also integrated */
26832b578d3Smrg            if ((pATI->DAC & ~0x0FU) != ATI_DAC_INTERNAL)
26932b578d3Smrg                ClockDac = ATI_DAC_INTERNAL;
27032b578d3Smrg
27132b578d3Smrg            break;
27232b578d3Smrg
27332b578d3Smrg        case ATI_CLOCK_ATT20C408:
27432b578d3Smrg            /* This one's also a RAMDAC */
27532b578d3Smrg            ClockDac = ATI_DAC_ATT20C408;
27632b578d3Smrg            break;
27732b578d3Smrg
27832b578d3Smrg        case ATI_CLOCK_IBMRGB514:
27932b578d3Smrg            /* This one's also a RAMDAC */
28032b578d3Smrg            ClockDac = ATI_DAC_IBMRGB514;
28132b578d3Smrg            pATI->ClockNumberToProgramme = 7;
28232b578d3Smrg            break;
28332b578d3Smrg
28432b578d3Smrg        default:
28532b578d3Smrg            break;
28632b578d3Smrg    }
28732b578d3Smrg
28832b578d3Smrg    /*
28932b578d3Smrg     * We now have up to two indications of what RAMDAC the adapter uses.
29032b578d3Smrg     * They should be the same.  The following test and corresponding
29132b578d3Smrg     * action are under construction.
29232b578d3Smrg     */
29332b578d3Smrg    if (pATI->DAC != ClockDac)
29432b578d3Smrg    {
29532b578d3Smrg        xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING,
29632b578d3Smrg                   "Mach64 RAMDAC probe discrepancy detected:\n"
29732b578d3Smrg                   "  DAC=0x%02X;  ClockDac=0x%02X.\n",
29832b578d3Smrg                   pATI->DAC, ClockDac);
29932b578d3Smrg
30032b578d3Smrg        if (pATI->DAC == ATI_DAC_IBMRGB514)
30132b578d3Smrg        {
30232b578d3Smrg            pATI->ProgrammableClock = ATI_CLOCK_IBMRGB514;
30332b578d3Smrg            pATI->ClockDescriptor = ATIClockDescriptors[ATI_CLOCK_IBMRGB514];
30432b578d3Smrg            pATI->ClockNumberToProgramme = 7;
30532b578d3Smrg        }
30632b578d3Smrg        else
30732b578d3Smrg        {
30832b578d3Smrg            pATI->DAC = ClockDac;   /* For now */
30932b578d3Smrg        }
31032b578d3Smrg    }
31132b578d3Smrg
31232b578d3Smrg    switch (pATI->refclk / 100000)
31332b578d3Smrg    {
31432b578d3Smrg        case 143:
31532b578d3Smrg            pATI->ReferenceNumerator = 157500;
31632b578d3Smrg            pATI->ReferenceDenominator = 11;
31732b578d3Smrg            break;
31832b578d3Smrg
31932b578d3Smrg        case 286:
32032b578d3Smrg            pATI->ReferenceNumerator = 315000;
32132b578d3Smrg            pATI->ReferenceDenominator = 11;
32232b578d3Smrg            break;
32332b578d3Smrg
32432b578d3Smrg        default:
32532b578d3Smrg            pATI->ReferenceNumerator = pATI->refclk / 1000;
32632b578d3Smrg            pATI->ReferenceDenominator = 1;
32732b578d3Smrg            break;
32832b578d3Smrg    }
32932b578d3Smrg}
33032b578d3Smrg
33132b578d3Smrg/*
33232b578d3Smrg * Pick up multimedia information, which will be at different
33332b578d3Smrg * displacements depending on table revision.
33432b578d3Smrg */
33532b578d3Smrgstatic void
33632b578d3Smrgati_bios_mmedia
33732b578d3Smrg(
33832b578d3Smrg    ScrnInfoPtr  pScreenInfo,
33932b578d3Smrg    ATIPtr       pATI,
34032b578d3Smrg    CARD8       *BIOS,
34132b578d3Smrg    unsigned int VideoTable,
34232b578d3Smrg    unsigned int HardwareTable
34332b578d3Smrg)
34432b578d3Smrg{
34532b578d3Smrg    pATI->Audio = ATI_AUDIO_NONE;
34632b578d3Smrg
34732b578d3Smrg    if (VideoTable > 0)
34832b578d3Smrg    {
34932b578d3Smrg        switch (BIOSByte(VideoTable - 0x02U))
35032b578d3Smrg        {
35132b578d3Smrg            case 0x00U:
35232b578d3Smrg                pATI->Tuner = BIOSByte(VideoTable) & 0x1FU;
35332b578d3Smrg
35432b578d3Smrg                /*
35532b578d3Smrg                 * XXX  The VideoTable[1] byte is known to have been
35632b578d3Smrg                 *      omitted in LTPro and Mobility BIOS'es.  Any others?
35732b578d3Smrg                 */
35832b578d3Smrg                switch (pATI->Chip)
35932b578d3Smrg                {
36032b578d3Smrg                    case ATI_CHIP_264LTPRO:
36132b578d3Smrg                    case ATI_CHIP_MOBILITY:
36232b578d3Smrg                        pATI->Decoder = BIOSByte(VideoTable + 0x01U) & 0x07U;
36332b578d3Smrg                        pATI->Audio = BIOSByte(VideoTable + 0x02U) & 0x0FU;
36432b578d3Smrg                        break;
36532b578d3Smrg
36632b578d3Smrg                    default:
36732b578d3Smrg                        pATI->Decoder = BIOSByte(VideoTable + 0x02U) & 0x07U;
36832b578d3Smrg                        pATI->Audio = BIOSByte(VideoTable + 0x03U) & 0x0FU;
36932b578d3Smrg                        break;
37032b578d3Smrg                }
37132b578d3Smrg
37232b578d3Smrg                break;
37332b578d3Smrg
37432b578d3Smrg            case 0x01U:
37532b578d3Smrg                pATI->Tuner = BIOSByte(VideoTable) & 0x1FU;
37632b578d3Smrg                pATI->Audio = BIOSByte(VideoTable + 0x01U) & 0x0FU;
37732b578d3Smrg                pATI->Decoder = BIOSByte(VideoTable + 0x05U) & 0x0FU;
37832b578d3Smrg                break;
37932b578d3Smrg
38032b578d3Smrg            default:
38132b578d3Smrg                break;
38232b578d3Smrg        }
38332b578d3Smrg    }
38432b578d3Smrg
38532b578d3Smrg    if (HardwareTable > 0)
38632b578d3Smrg    {
38732b578d3Smrg        pATI->I2CType = BIOSByte(HardwareTable + 0x06U) & 0x0FU;
38832b578d3Smrg    }
38932b578d3Smrg}
39032b578d3Smrg
39132b578d3Smrg/*
39232b578d3Smrg * Determine panel dimensions and model.
39332b578d3Smrg */
39432b578d3Smrgstatic void
39532b578d3Smrgati_bios_panel_info
39632b578d3Smrg(
39732b578d3Smrg    ScrnInfoPtr  pScreenInfo,
39832b578d3Smrg    ATIPtr       pATI,
39932b578d3Smrg    CARD8       *BIOS,
40032b578d3Smrg    unsigned int BIOSSize,
40132b578d3Smrg    unsigned int LCDTable
40232b578d3Smrg)
40332b578d3Smrg{
40432b578d3Smrg    unsigned int LCDPanelInfo = 0;
40532b578d3Smrg    char         Buffer[128];
40632b578d3Smrg    int          i, j;
40732b578d3Smrg
40832b578d3Smrg    if (LCDTable > 0)
40932b578d3Smrg    {
41032b578d3Smrg        LCDPanelInfo = BIOSWord(LCDTable + 0x0AU);
41132b578d3Smrg        if (((LCDPanelInfo + 0x1DU) > BIOSSize) ||
41232b578d3Smrg            ((BIOSByte(LCDPanelInfo) != pATI->LCDPanelID) &&
41332b578d3Smrg             (pATI->LCDPanelID || (BIOSByte(LCDPanelInfo) > 0x1FU) ||
41432b578d3Smrg              (pATI->Chip <= ATI_CHIP_264LTPRO))))
41532b578d3Smrg            LCDPanelInfo = 0;
41632b578d3Smrg    }
41732b578d3Smrg
41832b578d3Smrg    if (!LCDPanelInfo)
41932b578d3Smrg    {
42032b578d3Smrg        /*
42132b578d3Smrg         * Scan BIOS for panel info table.
42232b578d3Smrg         */
42332b578d3Smrg        for (i = 0;  i <= (int)(BIOSSize - 0x1DU);  i++)
42432b578d3Smrg        {
42532b578d3Smrg            /* Look for panel ID ... */
42632b578d3Smrg            if ((BIOSByte(i) != pATI->LCDPanelID) &&
42732b578d3Smrg                (pATI->LCDPanelID || (BIOSByte(i) > 0x1FU) ||
42832b578d3Smrg                 (pATI->Chip <= ATI_CHIP_264LTPRO)))
42932b578d3Smrg                continue;
43032b578d3Smrg
43132b578d3Smrg            /* ... followed by 24-byte panel model name ... */
43232b578d3Smrg            for (j = 0;  j < 24;  j++)
43332b578d3Smrg            {
43432b578d3Smrg                if ((CARD8)(BIOSByte(i + j + 1) - 0x20U) > 0x5FU)
43532b578d3Smrg                {
43632b578d3Smrg                    i += j;
43732b578d3Smrg                    goto NextBIOSByte;
43832b578d3Smrg                }
43932b578d3Smrg            }
44032b578d3Smrg
44132b578d3Smrg            /* ... verify panel width ... */
44232b578d3Smrg            if (pATI->LCDHorizontal &&
44332b578d3Smrg                (pATI->LCDHorizontal != BIOSWord(i + 0x19U)))
44432b578d3Smrg                continue;
44532b578d3Smrg
44632b578d3Smrg            /* ... and verify panel height */
44732b578d3Smrg            if (pATI->LCDVertical &&
44832b578d3Smrg                (pATI->LCDVertical != BIOSWord(i + 0x1BU)))
44932b578d3Smrg                continue;
45032b578d3Smrg
45132b578d3Smrg            if (LCDPanelInfo)
45232b578d3Smrg            {
45332b578d3Smrg                /*
45432b578d3Smrg                 * More than one possibility, but don't care if all
45532b578d3Smrg                 * tables describe panels of the same size.
45632b578d3Smrg                 */
45732b578d3Smrg                if ((BIOSByte(LCDPanelInfo + 0x19U) ==
45832b578d3Smrg                     BIOSByte(i + 0x19U)) &&
45932b578d3Smrg                    (BIOSByte(LCDPanelInfo + 0x1AU) ==
46032b578d3Smrg                     BIOSByte(i + 0x1AU)) &&
46132b578d3Smrg                    (BIOSByte(LCDPanelInfo + 0x1BU) ==
46232b578d3Smrg                     BIOSByte(i + 0x1BU)) &&
46332b578d3Smrg                    (BIOSByte(LCDPanelInfo + 0x1CU) ==
46432b578d3Smrg                     BIOSByte(i + 0x1CU)))
46532b578d3Smrg                    continue;
46632b578d3Smrg
46732b578d3Smrg                LCDPanelInfo = 0;
46832b578d3Smrg                break;
46932b578d3Smrg            }
47032b578d3Smrg
47132b578d3Smrg            LCDPanelInfo = i;
47232b578d3Smrg
47332b578d3Smrg    NextBIOSByte:  ;
47432b578d3Smrg        }
47532b578d3Smrg    }
47632b578d3Smrg
47732b578d3Smrg    if (LCDPanelInfo > 0)
47832b578d3Smrg    {
47932b578d3Smrg        pATI->LCDPanelID = BIOSByte(LCDPanelInfo);
48032b578d3Smrg        pATI->LCDHorizontal = BIOSWord(LCDPanelInfo + 0x19U);
48132b578d3Smrg        pATI->LCDVertical = BIOSWord(LCDPanelInfo + 0x1BU);
48232b578d3Smrg    }
48332b578d3Smrg
48432b578d3Smrg    if (LCDPanelInfo)
48532b578d3Smrg    {
48632b578d3Smrg        for (i = 0;  i < 24;  i++)
48732b578d3Smrg            Buffer[i] = BIOSByte(LCDPanelInfo + 1 + i);
48832b578d3Smrg        for (;  --i >= 0;  )
48932b578d3Smrg            if (Buffer[i] && Buffer[i] != ' ')
49032b578d3Smrg            {
49132b578d3Smrg                Buffer[i + 1] = '\0';
49232b578d3Smrg                xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED,
49332b578d3Smrg                    "Panel model %s.\n", Buffer);
49432b578d3Smrg                break;
49532b578d3Smrg            }
49632b578d3Smrg    }
49732b578d3Smrg}
49832b578d3Smrg
49932b578d3Smrg/*
50032b578d3Smrg * ATIPreInit --
50132b578d3Smrg *
50232b578d3Smrg * This function is only called once per screen at the start of the first
50332b578d3Smrg * server generation.
50432b578d3Smrg */
50532b578d3SmrgBool
50632b578d3SmrgATIPreInit
50732b578d3Smrg(
50832b578d3Smrg    ScrnInfoPtr pScreenInfo,
50932b578d3Smrg    int flags
51032b578d3Smrg)
51132b578d3Smrg{
51232b578d3Smrg    CARD8            BIOS[BIOS_SIZE];
51332b578d3Smrg    unsigned int     BIOSSize = 0;
51432b578d3Smrg    unsigned int     ROMTable = 0, ClockTable = 0, FrequencyTable = 0;
51532b578d3Smrg    unsigned int     LCDTable = 0, VideoTable = 0;
51632b578d3Smrg    unsigned int     HardwareTable = 0;
51732b578d3Smrg
51832b578d3Smrg    char             Buffer[128], *Message;
51932b578d3Smrg    ATIPtr           pATI;
52032b578d3Smrg    GDevPtr          pGDev;
52132b578d3Smrg    EntityInfoPtr    pEntity;
5222a51b5beSmrg#ifndef XSERVER_LIBPCIACCESS
52332b578d3Smrg    resPtr           pResources;
5242a51b5beSmrg#endif
52532b578d3Smrg    pciVideoPtr      pVideo;
52632b578d3Smrg    DisplayModePtr   pMode;
52732b578d3Smrg    CARD32           IOValue;
52832b578d3Smrg    int              i, j;
52932b578d3Smrg    int              Numerator, Denominator;
53032b578d3Smrg    int              MinX, MinY;
53132b578d3Smrg    ClockRange       ATIClockRange = {NULL, 0, 80000, -1, TRUE, TRUE, 1, 1, 0};
53232b578d3Smrg    int              DefaultmaxClock = 0;
53332b578d3Smrg    int              minPitch, maxPitch = 0xFFU, pitchInc, maxHeight = 0;
53432b578d3Smrg    int              ApertureSize = 0x00010000U;
53532b578d3Smrg    int              ModeType = M_T_BUILTIN;
53632b578d3Smrg    LookupModeFlags  Strategy = LOOKUP_CLOSEST_CLOCK;
53732b578d3Smrg    int              DefaultDepth;
53832b578d3Smrg    Bool             PreInitSuccess = FALSE;
53932b578d3Smrg
54032b578d3Smrg#   define           pATIHW     (&pATI->OldHW)
54132b578d3Smrg
54207f4e327Smacallan#ifndef AVOID_CPIO_
54332b578d3Smrg
54432b578d3Smrg    vbeInfoPtr       pVBE = NULL;
545621ff18cSmrg    pointer          pVBEModule = NULL;
54632b578d3Smrg
54732b578d3Smrg#endif /* AVOID_CPIO */
54832b578d3Smrg
54932b578d3Smrg    if (pScreenInfo->numEntities != 1)
55032b578d3Smrg    {
55132b578d3Smrg        xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR,
55232b578d3Smrg            "Logic error:  Number of attached entities not 1.\n");
55332b578d3Smrg        return FALSE;
55432b578d3Smrg    }
55532b578d3Smrg
55632b578d3Smrg    if (!Mach64GetRec(pScreenInfo))
55732b578d3Smrg        return FALSE;
55832b578d3Smrg
55932b578d3Smrg    pATI = ATIPTR(pScreenInfo);
56032b578d3Smrg
56132b578d3Smrg    /* Register resources */
56232b578d3Smrg    pEntity = xf86GetEntityInfo(pScreenInfo->entityList[0]);
56332b578d3Smrg    pGDev = pEntity->device;
5642a51b5beSmrg#ifndef XSERVER_LIBPCIACCESS
56532b578d3Smrg    pResources = pEntity->resources;
5662a51b5beSmrg#endif
56732b578d3Smrg
56832b578d3Smrg    pATI->iEntity = pEntity->index;
56932b578d3Smrg    pATI->Chip = pEntity->chipset;
57032b578d3Smrg    pVideo = xf86GetPciInfoForEntity(pATI->iEntity);
57132b578d3Smrg
5721b12faf6Smrg    free(pEntity);
57332b578d3Smrg
5742a51b5beSmrg#ifndef XSERVER_LIBPCIACCESS
57532b578d3Smrg    if (!pResources)
57632b578d3Smrg        pResources = xf86RegisterResources(pATI->iEntity, NULL, ResShared);
57732b578d3Smrg    if (pResources)
57832b578d3Smrg    {
57932b578d3Smrg        xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR,
580d31dbc53Smrg            "Unable to register bus resources\n");
58132b578d3Smrg        xf86FreeResList(pResources);
58232b578d3Smrg        return FALSE;
58332b578d3Smrg    }
5842a51b5beSmrg#endif
58532b578d3Smrg    ConfiguredMonitor = NULL;
58632b578d3Smrg    (void)memset(BIOS, 0, SizeOf(BIOS));
58732b578d3Smrg
58832b578d3Smrg    if (!(flags & PROBE_DETECT))
58932b578d3Smrg    {
59032b578d3Smrg        /* Set monitor */
59132b578d3Smrg        pScreenInfo->monitor = pScreenInfo->confScreen->monitor;
59232b578d3Smrg
59332b578d3Smrg        /* Set depth, bpp, etc. */
59432b578d3Smrg        if ((pATI->Chip < ATI_CHIP_264CT))
59532b578d3Smrg        {
59632b578d3Smrg            i = NoDepth24Support;       /* No support for >8bpp either */
59732b578d3Smrg            DefaultDepth = 8;
59832b578d3Smrg        }
59932b578d3Smrg        else
60032b578d3Smrg        {
60132b578d3Smrg            i = Support24bppFb | Support32bppFb;
60232b578d3Smrg            DefaultDepth = 0;
60332b578d3Smrg        }
60432b578d3Smrg
60532b578d3Smrg        if (!xf86SetDepthBpp(pScreenInfo, DefaultDepth, 0, 0, i))
60632b578d3Smrg            return FALSE;
60732b578d3Smrg
60832b578d3Smrg        for (j = 0;  ;  j++)
60932b578d3Smrg        {
61032b578d3Smrg            static const CARD8 AllowedDepthBpp[][2] =
61132b578d3Smrg            {
61232b578d3Smrg                { 8,  8},
61332b578d3Smrg                {15, 16},
61432b578d3Smrg                {16, 16},
61532b578d3Smrg                {24, 24},
61632b578d3Smrg                {24, 32}
61732b578d3Smrg            };
61832b578d3Smrg
61932b578d3Smrg            if (j < NumberOf(AllowedDepthBpp))
62032b578d3Smrg            {
62132b578d3Smrg                if (pScreenInfo->depth > AllowedDepthBpp[j][0])
62232b578d3Smrg                    continue;
62332b578d3Smrg
62432b578d3Smrg                if (pScreenInfo->depth == AllowedDepthBpp[j][0])
62532b578d3Smrg                {
62632b578d3Smrg                    if (pScreenInfo->bitsPerPixel > AllowedDepthBpp[j][1])
62732b578d3Smrg                        continue;
62832b578d3Smrg
62932b578d3Smrg                    if (pScreenInfo->bitsPerPixel == AllowedDepthBpp[j][1])
63032b578d3Smrg                        break;
63132b578d3Smrg                }
63232b578d3Smrg            }
63332b578d3Smrg
63432b578d3Smrg            xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR,
63532b578d3Smrg                "Driver does not support depth %d at fbbpp %d.\n",
63632b578d3Smrg                pScreenInfo->depth, pScreenInfo->bitsPerPixel);
63732b578d3Smrg            return FALSE;
63832b578d3Smrg        }
63932b578d3Smrg
64032b578d3Smrg        xf86PrintDepthBpp(pScreenInfo);
64132b578d3Smrg
64232b578d3Smrg        if ((i == NoDepth24Support) && (pScreenInfo->depth > 8))
64332b578d3Smrg        {
64432b578d3Smrg            xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR,
64532b578d3Smrg                "Depth %d is not supported through this adapter.\n",
64632b578d3Smrg                pScreenInfo->depth);
64732b578d3Smrg            return FALSE;
64832b578d3Smrg        }
64932b578d3Smrg
65032b578d3Smrg        /* Pick up XF86Config options */
65132b578d3Smrg        ATIProcessOptions(pScreenInfo, pATI);
65232b578d3Smrg    }
65332b578d3Smrg
65432b578d3Smrg    if (!ATIMach64ProbeIO(pVideo, pATI))
65532b578d3Smrg        return FALSE;
65632b578d3Smrg
65732b578d3Smrg    ATIClaimBusSlot(pGDev->active, pATI);
65832b578d3Smrg
65932b578d3Smrg#ifndef AVOID_CPIO
66032b578d3Smrg#ifdef TV_OUT
66132b578d3Smrg
66232b578d3Smrg    pATI->pVBE = NULL;
66332b578d3Smrg    pATI->pInt10 = NULL;
66432b578d3Smrg
66532b578d3Smrg#endif /* TV_OUT */
66632b578d3Smrg
66732b578d3Smrg    /*
668621ff18cSmrg     * If VBE setup works, grab DDC from it
66932b578d3Smrg     */
670621ff18cSmrg    if (!(pVBEModule = xf86LoadSubModule(pScreenInfo, "vbe"))) {
671621ff18cSmrg	xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING,
672621ff18cSmrg		   "Unable to load vbe module.\n");
67332b578d3Smrg    }
67432b578d3Smrg    else
67532b578d3Smrg    {
676621ff18cSmrg	if ((pVBE = VBEInit(NULL, pATI->iEntity)))
677621ff18cSmrg	    ConfiguredMonitor = vbeDoEDID(pVBE, NULL);
67832b578d3Smrg
679621ff18cSmrg        if (pVBE && !(flags & PROBE_DETECT))
68032b578d3Smrg        {
681621ff18cSmrg	    xf86Int10InfoPtr pInt10Info = pVBE->pInt10;
682621ff18cSmrg
68332b578d3Smrg            /* Validate, then make a private copy of, the initialised BIOS */
68432b578d3Smrg            CARD8 *pBIOS = xf86int10Addr(pInt10Info, pInt10Info->BIOSseg << 4);
68532b578d3Smrg
68632b578d3Smrg            if ((pBIOS[0] != 0x55U) || (pBIOS[1] != 0xAAU) || !pBIOS[2])
68732b578d3Smrg            {
68832b578d3Smrg                xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING,
68932b578d3Smrg                    "Unable to correctly retrieve adapter BIOS.\n");
69032b578d3Smrg            }
69132b578d3Smrg            else
69232b578d3Smrg            {
69332b578d3Smrg                BIOSSize = pBIOS[2] << 9;
69432b578d3Smrg                if (BIOSSize > BIOS_SIZE)
69532b578d3Smrg                    BIOSSize = BIOS_SIZE;
69632b578d3Smrg                (void)memcpy(BIOS, pBIOS, BIOSSize);
69732b578d3Smrg            }
69832b578d3Smrg        }
69932b578d3Smrg    }
70032b578d3Smrg
70132b578d3Smrg#ifndef TV_OUT
70232b578d3Smrg    /* De-activate VBE */
70332b578d3Smrg    vbeFree(pVBE);
70432b578d3Smrg    xf86UnloadSubModule(pVBEModule);
70532b578d3Smrg#else
70632b578d3Smrg    pATI->pVBE = pVBE;
70732b578d3Smrg    pVBE = NULL;
70832b578d3Smrg#endif /* TV_OUT */
70907f4e327Smacallan#endif /* AVOID_CPIO */
71007f4e327Smacallan#ifdef __NetBSD__
71107f4e327Smacallan    if (ConfiguredMonitor == NULL) {
71207f4e327Smacallan    	struct wsdisplayio_edid_info ei;
71307f4e327Smacallan    	char buffer[1024];
71407f4e327Smacallan    	int i, j;
71507f4e327Smacallan
71607f4e327Smacallan	ei.edid_data = buffer;
71707f4e327Smacallan	ei.buffer_size = 1024;
718a6bf028eSmrg	if (ioctl(xf86Info.consoleFd, WSDISPLAYIO_GET_EDID, &ei) != -1) {
71907f4e327Smacallan	    xf86Msg(X_INFO, "got %d bytes worth of EDID from wsdisplay\n", ei.data_size);
72007f4e327Smacallan	    ConfiguredMonitor = xf86InterpretEDID(pScreenInfo->scrnIndex, buffer);
72107f4e327Smacallan	} else
72207f4e327Smacallan	    xf86Msg(X_INFO, "ioctl failed %d\n", errno);
72307f4e327Smacallan    }
72407f4e327Smacallan#endif
72507f4e327Smacallan
72632b578d3Smrg
72732b578d3Smrg    if (ConfiguredMonitor && !(flags & PROBE_DETECT))
72832b578d3Smrg    {
72932b578d3Smrg        xf86PrintEDID(ConfiguredMonitor);
73032b578d3Smrg        xf86SetDDCproperties(pScreenInfo, ConfiguredMonitor);
73132b578d3Smrg    }
73232b578d3Smrg
73332b578d3Smrg    if (flags & PROBE_DETECT)
73432b578d3Smrg    {
73532b578d3Smrg        return TRUE;
73632b578d3Smrg    }
73732b578d3Smrg
73832b578d3Smrg#ifndef AVOID_CPIO
73932b578d3Smrg
74032b578d3Smrg    /* I/O bases might no longer be valid after BIOS initialisation */
74132b578d3Smrg    {
74232b578d3Smrg        if (pATI->CPIODecoding == BLOCK_IO)
74332b578d3Smrg            pATI->CPIOBase = PCI_REGION_BASE(pVideo, 1, REGION_IO);
74432b578d3Smrg
74532b578d3Smrg        pATI->MMIOInLinear = FALSE;
74632b578d3Smrg
74732b578d3Smrg        /* Set MMIO address from PCI configuration space, if available */
74832b578d3Smrg        if ((pATI->Block0Base = PCI_REGION_BASE(pVideo, 2, REGION_MEM)))
74932b578d3Smrg        {
75032b578d3Smrg            pATI->Block0Base += 0x0400U;
75132b578d3Smrg        }
75232b578d3Smrg    }
75332b578d3Smrg
75432b578d3Smrg#endif /* AVOID_CPIO */
75532b578d3Smrg
7562a51b5beSmrg#ifndef XSERVER_LIBPCIACCESS
75732b578d3Smrg#ifdef AVOID_CPIO
75832b578d3Smrg
75932b578d3Smrg    pScreenInfo->racMemFlags =
76032b578d3Smrg        RAC_FB | RAC_COLORMAP | RAC_VIEWPORT | RAC_CURSOR;
76132b578d3Smrg
76232b578d3Smrg#else /* AVOID_CPIO */
76332b578d3Smrg
76432b578d3Smrg    pScreenInfo->racIoFlags =
76532b578d3Smrg        RAC_FB | RAC_COLORMAP | RAC_VIEWPORT | RAC_CURSOR;
76632b578d3Smrg    pScreenInfo->racMemFlags = RAC_FB | RAC_CURSOR;
76732b578d3Smrg
76832b578d3Smrg#endif /* AVOID_CPIO */
7692a51b5beSmrg#endif
77032b578d3Smrg    /* Finish private area initialisation */
77132b578d3Smrg    pATI->nFIFOEntries = 16;                    /* For now */
77232b578d3Smrg
77332b578d3Smrg    /* Finish probing the adapter */
77432b578d3Smrg    {
77532b578d3Smrg        /*
77632b578d3Smrg         * For MMIO register access, the MMIO address is computed when probing
77732b578d3Smrg         * and there are no BIOS calls. This mapping should always succeed.
77832b578d3Smrg         *
77932b578d3Smrg         * For CPIO register access, the MMIO address is computed above in the
78032b578d3Smrg         * presence of an auxiliary aperture. Otherwise, it is set to zero and
78132b578d3Smrg         * gets computed when we read the linear aperture configuration. This
78232b578d3Smrg         * mapping is either irrelevant or a no-op.
78332b578d3Smrg         */
78432b578d3Smrg        if (!ATIMapApertures(pScreenInfo->scrnIndex, pATI))
78532b578d3Smrg            return FALSE;
78632b578d3Smrg
78732b578d3Smrg#ifdef AVOID_CPIO
78832b578d3Smrg
78932b578d3Smrg            if (!pATI->pBlock[0])
79032b578d3Smrg            {
79132b578d3Smrg                xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR,
79232b578d3Smrg                    "Unable to mmap() adapter registers.\n");
79332b578d3Smrg                return FALSE;
79432b578d3Smrg            }
79532b578d3Smrg
79632b578d3Smrg#endif /* AVOID_CPIO */
79732b578d3Smrg
79832b578d3Smrg            /*
79932b578d3Smrg             * Verify register access by comparing against the CONFIG_CHIP_ID
80032b578d3Smrg             * value saved by adapter detection.
80132b578d3Smrg             */
80232b578d3Smrg            if (pATI->config_chip_id != inr(CONFIG_CHIP_ID))
80332b578d3Smrg            {
80432b578d3Smrg                xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR,
80532b578d3Smrg                    "Adapter registers not mapped correctly.\n");
80632b578d3Smrg                ATIUnmapApertures(pScreenInfo->scrnIndex, pATI);
80732b578d3Smrg                return FALSE;
80832b578d3Smrg            }
80932b578d3Smrg
81032b578d3Smrg            pATIHW->crtc_gen_cntl = inr(CRTC_GEN_CNTL);
81132b578d3Smrg            if (!(pATIHW->crtc_gen_cntl & CRTC_EN) &&
81232b578d3Smrg                (pATI->Chip >= ATI_CHIP_264CT))
81332b578d3Smrg            {
81432b578d3Smrg                xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR,
81532b578d3Smrg                    "Adapter has not been initialised.\n");
81632b578d3Smrg                goto bail_locked;
81732b578d3Smrg            }
81832b578d3Smrg
81932b578d3Smrg#ifdef AVOID_CPIO
82032b578d3Smrg
82132b578d3Smrg            if (!(pATIHW->crtc_gen_cntl & CRTC_EXT_DISP_EN))
82232b578d3Smrg            {
82332b578d3Smrg                xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR,
82432b578d3Smrg                    "Adapters found to be in VGA mode on server entry are not"
82532b578d3Smrg                    " supported by the MMIO-only version of this driver.\n");
82632b578d3Smrg                goto bail_locked;
82732b578d3Smrg            }
82832b578d3Smrg
82932b578d3Smrg#endif /* AVOID_CPIO */
83032b578d3Smrg
83132b578d3Smrg            pATIHW->mem_cntl = inr(MEM_CNTL);
83232b578d3Smrg            if (pATI->Chip < ATI_CHIP_264VTB)
83332b578d3Smrg            {
83432b578d3Smrg                IOValue = GetBits(pATIHW->mem_cntl, CTL_MEM_SIZE);
83532b578d3Smrg                pATI->VideoRAM = videoRamSizes[IOValue];
83632b578d3Smrg            }
83732b578d3Smrg            else
83832b578d3Smrg            {
83932b578d3Smrg                pATI->nFIFOEntries =            /* Don't care */
84032b578d3Smrg                    (unsigned int)(-1) >> 1;
84132b578d3Smrg
84232b578d3Smrg                IOValue = GetBits(pATIHW->mem_cntl, CTL_MEM_SIZEB);
84332b578d3Smrg                if (IOValue < 8)
84432b578d3Smrg                    pATI->VideoRAM = (IOValue + 1) * 512;
84532b578d3Smrg                else if (IOValue < 12)
84632b578d3Smrg                    pATI->VideoRAM = (IOValue - 3) * 1024;
84732b578d3Smrg                else
84832b578d3Smrg                    pATI->VideoRAM = (IOValue - 7) * 2048;
84932b578d3Smrg            }
85032b578d3Smrg
85132b578d3Smrg            IOValue = inr(CONFIG_STATUS64_0);
85232b578d3Smrg            if (pATI->Chip >= ATI_CHIP_264CT)
85332b578d3Smrg            {
85432b578d3Smrg                pATI->MemoryType = GetBits(IOValue, CFG_MEM_TYPE_T);
85532b578d3Smrg            }
85632b578d3Smrg            else
85732b578d3Smrg            {
85832b578d3Smrg                pATI->MemoryType = GetBits(IOValue, CFG_MEM_TYPE);
85932b578d3Smrg            }
86032b578d3Smrg
86132b578d3Smrg            pATI->LCDPanelID = -1;
86232b578d3Smrg
86332b578d3Smrg            if (pATI->Chip >= ATI_CHIP_264CT)
86432b578d3Smrg            {
86532b578d3Smrg                /* Get LCD panel id */
86632b578d3Smrg                if (pATI->Chip == ATI_CHIP_264LT)
86732b578d3Smrg                {
86832b578d3Smrg                    pATI->LCDPanelID = GetBits(IOValue, CFG_PANEL_ID);
86932b578d3Smrg
87032b578d3Smrg                    pATIHW->horz_stretching = inr(HORZ_STRETCHING);
87132b578d3Smrg                    pATIHW->vert_stretching = inr(VERT_STRETCHING);
87232b578d3Smrg                    pATIHW->lcd_gen_ctrl = inr(LCD_GEN_CTRL);
87332b578d3Smrg                }
87432b578d3Smrg                else if ((pATI->Chip == ATI_CHIP_264LTPRO) ||
87532b578d3Smrg                         (pATI->Chip == ATI_CHIP_264XL) ||
87632b578d3Smrg                         (pATI->Chip == ATI_CHIP_MOBILITY))
87732b578d3Smrg                {
87832b578d3Smrg                    pATI->LCDPanelID = GetBits(IOValue, CFG_PANEL_ID);
87932b578d3Smrg
88032b578d3Smrg                    pATIHW->lcd_index = inr(LCD_INDEX);
88132b578d3Smrg                    pATIHW->horz_stretching =
88232b578d3Smrg                        ATIMach64GetLCDReg(LCD_HORZ_STRETCHING);
88332b578d3Smrg                    pATI->LCDHorizontal =
88432b578d3Smrg                        GetBits(pATIHW->horz_stretching, HORZ_PANEL_SIZE);
88532b578d3Smrg                    if (pATI->LCDHorizontal)
88632b578d3Smrg                    {
88732b578d3Smrg                        if (pATI->LCDHorizontal == MaxBits(HORZ_PANEL_SIZE))
88832b578d3Smrg                            pATI->LCDHorizontal = 0;
88932b578d3Smrg                        else
89032b578d3Smrg                            pATI->LCDHorizontal =
89132b578d3Smrg                                (pATI->LCDHorizontal + 1) << 3;
89232b578d3Smrg                    }
89332b578d3Smrg                    pATIHW->ext_vert_stretch =
89432b578d3Smrg                        ATIMach64GetLCDReg(LCD_EXT_VERT_STRETCH);
89532b578d3Smrg                    pATI->LCDVertical =
89632b578d3Smrg                        GetBits(pATIHW->ext_vert_stretch, VERT_PANEL_SIZE);
89732b578d3Smrg                    if (pATI->LCDVertical)
89832b578d3Smrg                    {
89932b578d3Smrg                        if (pATI->LCDVertical == MaxBits(VERT_PANEL_SIZE))
90032b578d3Smrg                            pATI->LCDVertical = 0;
90132b578d3Smrg                        else
90232b578d3Smrg                            pATI->LCDVertical++;
90332b578d3Smrg                    }
90432b578d3Smrg                    pATIHW->vert_stretching =
90532b578d3Smrg                        ATIMach64GetLCDReg(LCD_VERT_STRETCHING);
90632b578d3Smrg                    pATIHW->lcd_gen_ctrl = ATIMach64GetLCDReg(LCD_GEN_CNTL);
90732b578d3Smrg                    outr(LCD_INDEX, pATIHW->lcd_index);
90832b578d3Smrg                }
90932b578d3Smrg
91032b578d3Smrg                /*
91132b578d3Smrg                 * Don't bother with panel support if it hasn't been previously
91232b578d3Smrg                 * enabled.
91332b578d3Smrg                 */
91432b578d3Smrg                if ((pATI->LCDPanelID >= 0) &&
91532b578d3Smrg                    !(pATIHW->horz_stretching & HORZ_STRETCH_EN) &&
91632b578d3Smrg                    !(pATIHW->vert_stretching & VERT_STRETCH_EN) &&
91732b578d3Smrg                    !(pATIHW->lcd_gen_ctrl & LCD_ON))
91832b578d3Smrg                {
91932b578d3Smrg                    /*
92032b578d3Smrg                     * At this point, if an XL or Mobility BIOS hasn't set
92132b578d3Smrg                     * panel dimensions, then there is no panel.  Otherwise,
92232b578d3Smrg                     * keep any panel disabled to allow for modes greater than
92332b578d3Smrg                     * the panel's dimensions.
92432b578d3Smrg                     */
92532b578d3Smrg                    if ((pATI->Chip >= ATI_CHIP_264XL) &&
92632b578d3Smrg                        (!pATI->LCDHorizontal || !pATI->LCDVertical))
92732b578d3Smrg                        pATI->LCDPanelID = -1;
92832b578d3Smrg                    else
92932b578d3Smrg                        pATI->OptionPanelDisplay = FALSE;
93032b578d3Smrg                }
93132b578d3Smrg            }
93232b578d3Smrg
93332b578d3Smrg            /* Get DAC type */
93432b578d3Smrg            pATI->DAC = GetBits(inr(DAC_CNTL), DAC_TYPE);
93532b578d3Smrg
93632b578d3Smrg            if (pATI->Chip < ATI_CHIP_264CT)
93732b578d3Smrg            {
93832b578d3Smrg                /* Factor in what the BIOS says the DAC is */
93932b578d3Smrg                pATI->DAC = ATI_DAC(pATI->DAC,
94032b578d3Smrg                    GetBits(inr(SCRATCH_REG1), BIOS_INIT_DAC_SUBTYPE));
94132b578d3Smrg            }
94232b578d3Smrg
94332b578d3Smrg            /*
94432b578d3Smrg             * RAMDAC types 0 & 1 for Mach64's are different than those for
94532b578d3Smrg             * Mach32's.
94632b578d3Smrg             */
94732b578d3Smrg            if (pATI->DAC < ATI_DAC_ATI68875)
94832b578d3Smrg                pATI->DAC += ATI_DAC_INTERNAL;
94932b578d3Smrg    }
95032b578d3Smrg
95132b578d3Smrg    {
95232b578d3Smrg        ROMTable = BIOSWord(0x48U);
95332b578d3Smrg        if ((ROMTable < 0x0002U) ||
95432b578d3Smrg            (BIOSWord(ROMTable - 0x02U) < 0x0012U) ||
95532b578d3Smrg            ((ROMTable + BIOSWord(ROMTable - 0x02U)) > BIOSSize))
95632b578d3Smrg            ROMTable = 0;
95732b578d3Smrg
95832b578d3Smrg        if (ROMTable > 0)
95932b578d3Smrg        {
96032b578d3Smrg            ClockTable = BIOSWord(ROMTable + 0x10U);
96132b578d3Smrg            if ((ClockTable + 0x20U) > BIOSSize)
96232b578d3Smrg                ClockTable = 0;
96332b578d3Smrg
96432b578d3Smrg            if (BIOSWord(ROMTable - 0x02U) >= 0x0048U)
96532b578d3Smrg            {
96632b578d3Smrg                VideoTable = BIOSWord(ROMTable + 0x46U);
96732b578d3Smrg                if ((VideoTable < 0x08U) ||
96832b578d3Smrg                    (BIOSByte(VideoTable - 0x01U) < 0x08U) ||
96932b578d3Smrg                    (BIOSByte(VideoTable - 0x02U) > 0x01U) ||
97032b578d3Smrg                    ((VideoTable + BIOSByte(VideoTable - 0x01U)) > BIOSSize))
97132b578d3Smrg                    VideoTable = 0;
97232b578d3Smrg            }
97332b578d3Smrg
97432b578d3Smrg            if (BIOSWord(ROMTable - 0x02U) >= 0x004AU)
97532b578d3Smrg            {
97632b578d3Smrg                HardwareTable = BIOSWord(ROMTable + 0x48U);
97732b578d3Smrg                if (((HardwareTable + 0x08U) > BIOSSize) ||
97832b578d3Smrg                    (memcmp(BIOS + HardwareTable, "$ATI", 4) != 0))
97932b578d3Smrg                    HardwareTable = 0;
98032b578d3Smrg            }
98132b578d3Smrg        }
98232b578d3Smrg
983b7306217Smacallan#if defined(__sparc__)
984b7306217Smacallan	/* make PGX64 work by default */
985b7306217Smacallan	if (pATI->Chip == ATI_CHIP_264XL)
986b7306217Smacallan		pATI->refclk = 29498000;
987b7306217Smacallan#endif
98832b578d3Smrg
989b7306217Smacallan        ati_bios_clock(pScreenInfo, pATI, BIOS, ClockTable, pGDev);
99032b578d3Smrg        ati_bios_mmedia(pScreenInfo, pATI, BIOS, VideoTable, HardwareTable);
99132b578d3Smrg
99232b578d3Smrg        if (pATI->LCDPanelID >= 0)
99332b578d3Smrg        {
99432b578d3Smrg            LCDTable = BIOSWord(0x78U);
99532b578d3Smrg            if ((LCDTable + BIOSByte(LCDTable + 5)) > BIOSSize)
99632b578d3Smrg                LCDTable = 0;
99732b578d3Smrg
99832b578d3Smrg            ati_bios_panel_info(pScreenInfo, pATI, BIOS, BIOSSize, LCDTable);
99932b578d3Smrg        }
100032b578d3Smrg
100132b578d3Smrg        xf86DrvMsgVerb(pScreenInfo->scrnIndex, X_INFO, 3,
100232b578d3Smrg            "BIOS Data:  BIOSSize=0x%04X, ROMTable=0x%04X.\n",
100332b578d3Smrg            BIOSSize, ROMTable);
100432b578d3Smrg        xf86DrvMsgVerb(pScreenInfo->scrnIndex, X_INFO, 3,
100532b578d3Smrg            "BIOS Data:  ClockTable=0x%04X, FrequencyTable=0x%04X.\n",
100632b578d3Smrg            ClockTable, FrequencyTable);
100732b578d3Smrg        xf86DrvMsgVerb(pScreenInfo->scrnIndex, X_INFO, 3,
100832b578d3Smrg            "BIOS Data:  LCDTable=0x%04X.\n",
100932b578d3Smrg            LCDTable);
101032b578d3Smrg        xf86DrvMsgVerb(pScreenInfo->scrnIndex, X_INFO, 3,
101132b578d3Smrg            "BIOS Data:  VideoTable=0x%04X, HardwareTable=0x%04X.\n",
101232b578d3Smrg            VideoTable, HardwareTable);
101332b578d3Smrg        xf86DrvMsgVerb(pScreenInfo->scrnIndex, X_INFO, 3,
101432b578d3Smrg            "BIOS Data:  I2CType=0x%02X, Tuner=0x%02X, Decoder=0x%02X,"
101532b578d3Smrg            " Audio=0x%02X.\n",
101632b578d3Smrg            pATI->I2CType, pATI->Tuner, pATI->Decoder, pATI->Audio);
101732b578d3Smrg    }
101832b578d3Smrg
101932b578d3Smrg    ATIUnlock(pATI);            /* Unlock registers */
102032b578d3Smrg
102132b578d3Smrg    /* Report what was found */
102232b578d3Smrg    xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED,
102332b578d3Smrg        "%s graphics controller detected.\n",
102432b578d3Smrg        xf86TokenToString(Mach64Chipsets, pATI->Chip));
102532b578d3Smrg
102632b578d3Smrg    {
102732b578d3Smrg        Message = Buffer + snprintf(Buffer, SizeOf(Buffer), "Chip type %04X",
102832b578d3Smrg            pATI->ChipType);
102932b578d3Smrg        if (!(pATI->ChipType & ~(CHIP_CODE_0 | CHIP_CODE_1)))
103032b578d3Smrg            Message += snprintf(Message, Buffer + SizeOf(Buffer) - Message,
103132b578d3Smrg                " (%c%c)",
103232b578d3Smrg                GetBits(pATI->ChipType, CHIP_CODE_1) + 0x41U,
103332b578d3Smrg                GetBits(pATI->ChipType, CHIP_CODE_0) + 0x41U);
103432b578d3Smrg        else if ((pATI->ChipType & 0x4040U) == 0x4040U)
103532b578d3Smrg            Message += snprintf(Message, Buffer + SizeOf(Buffer) - Message,
103632b578d3Smrg                " \"%c%c\"",
103732b578d3Smrg                GetByte(pATI->ChipType, 1), GetByte(pATI->ChipType, 0));
103832b578d3Smrg        if ((pATI->Chip >= ATI_CHIP_264CT) && (pATI->Chip != ATI_CHIP_Mach64))
103932b578d3Smrg            Message += snprintf(Message, Buffer + SizeOf(Buffer) - Message,
104032b578d3Smrg                ", version %d, foundry %s",
104132b578d3Smrg                pATI->ChipVersion, ATIFoundryNames[pATI->ChipFoundry]);
104232b578d3Smrg        xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED,
104332b578d3Smrg            "%s, class %d, revision 0x%02X.\n",
104432b578d3Smrg            Buffer, pATI->ChipClass, pATI->ChipRevision);
104532b578d3Smrg    }
104632b578d3Smrg
104732b578d3Smrg    {
104832b578d3Smrg        Message = Buffer + snprintf(Buffer, SizeOf(Buffer),
104932b578d3Smrg            "%s bus interface detected", ATIBusNames[pATI->BusType]);
105032b578d3Smrg
105132b578d3Smrg#ifndef AVOID_CPIO
105232b578d3Smrg
105332b578d3Smrg        {
105432b578d3Smrg            Message += snprintf(Message, Buffer + SizeOf(Buffer) - Message,
105532b578d3Smrg                ";  %s I/O base is 0x%04lX",
105632b578d3Smrg                (pATI->CPIODecoding == SPARSE_IO) ? "sparse" : "block",
105732b578d3Smrg                pATI->CPIOBase);
105832b578d3Smrg        }
105932b578d3Smrg
106032b578d3Smrg#endif /* AVOID_CPIO */
106132b578d3Smrg
106232b578d3Smrg        xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED, "%s.\n", Buffer);
106332b578d3Smrg    }
106432b578d3Smrg
10652a51b5beSmrg#ifndef XSERVER_LIBPCIACCESS
106632b578d3Smrg#ifndef AVOID_CPIO
106732b578d3Smrg
106832b578d3Smrg    if (pATI->CPIO_VGAWonder)
106932b578d3Smrg        xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED,
107032b578d3Smrg            "VGA Wonder registers at I/O port 0x%04lX.\n",
107132b578d3Smrg            pATI->CPIO_VGAWonder);
107232b578d3Smrg
107332b578d3Smrg#endif /* AVOID_CPIO */
10742a51b5beSmrg#endif
107532b578d3Smrg
107632b578d3Smrg    xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED,
107732b578d3Smrg        "ATI Mach64 adapter detected.\n");
107832b578d3Smrg
107932b578d3Smrg    if (pATI->Chip >= ATI_CHIP_264GT)
108032b578d3Smrg        xf86DrvMsg(pScreenInfo->scrnIndex, X_NOTICE,
108132b578d3Smrg            "For information on using the multimedia capabilities\n\tof this"
108232b578d3Smrg            " adapter, please see http://gatos.sf.net.\n");
108332b578d3Smrg
108432b578d3Smrg    if ((pATI->DAC & ~0x0FU) == ATI_DAC_INTERNAL)
108532b578d3Smrg    {
108632b578d3Smrg        xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED,
108732b578d3Smrg            "Internal RAMDAC (subtype %d) detected.\n", pATI->DAC & 0x0FU);
108832b578d3Smrg    }
108932b578d3Smrg    else
109032b578d3Smrg    {
109132b578d3Smrg        const SymTabRec *DAC;
109232b578d3Smrg
109332b578d3Smrg        for (DAC = ATIDACDescriptors;  ;  DAC++)
109432b578d3Smrg        {
109532b578d3Smrg            if (pATI->DAC == DAC->token)
109632b578d3Smrg            {
109732b578d3Smrg                xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED,
109832b578d3Smrg                    "%s RAMDAC detected.\n", DAC->name);
109932b578d3Smrg                break;
110032b578d3Smrg            }
110132b578d3Smrg
110232b578d3Smrg            if (pATI->DAC < DAC->token)
110332b578d3Smrg            {
110432b578d3Smrg                xf86DrvMsgVerb(pScreenInfo->scrnIndex, X_WARNING, 0,
110532b578d3Smrg                    "Unknown RAMDAC type 0x%02X detected.\n", pATI->DAC);
110632b578d3Smrg                break;
110732b578d3Smrg            }
110832b578d3Smrg        }
110932b578d3Smrg    }
111032b578d3Smrg
1111621ff18cSmrg#ifndef XSERVER_LIBPCIACCESS
111232b578d3Smrg    if (!xf86LinearVidMem())
111332b578d3Smrg    {
111432b578d3Smrg        xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR,
111532b578d3Smrg            "A linear aperture is not available.\n");
111632b578d3Smrg        goto bail;
111732b578d3Smrg    }
1118621ff18cSmrg#endif
111932b578d3Smrg
112032b578d3Smrg    /*
112132b578d3Smrg     * Set colour weights.
112232b578d3Smrg     */
112332b578d3Smrg
112432b578d3Smrg    if (pATI->Chip < ATI_CHIP_264CT)
112532b578d3Smrg        pScreenInfo->rgbBits = 6;
112632b578d3Smrg    else
112732b578d3Smrg        pScreenInfo->rgbBits = 8;
112832b578d3Smrg    pATI->rgbBits = pScreenInfo->rgbBits;
112932b578d3Smrg    if (!xf86SetWeight(pScreenInfo, defaultWeight, defaultWeight))
113032b578d3Smrg        goto bail;
113132b578d3Smrg
113232b578d3Smrg    if ((pScreenInfo->depth > 8) &&
113332b578d3Smrg        ((pScreenInfo->weight.red != pScreenInfo->weight.blue) ||
113432b578d3Smrg         (pScreenInfo->weight.red != (CARD32)(pScreenInfo->depth / 3)) ||
113532b578d3Smrg         ((CARD32)pScreenInfo->depth != (pScreenInfo->weight.red +
113632b578d3Smrg                                         pScreenInfo->weight.green +
113732b578d3Smrg                                         pScreenInfo->weight.blue))))
113832b578d3Smrg    {
113932b578d3Smrg        xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR,
114032b578d3Smrg            "Driver does not support weight %d%d%d for depth %d.\n",
114132b578d3Smrg            (int)pScreenInfo->weight.red, (int)pScreenInfo->weight.green,
114232b578d3Smrg            (int)pScreenInfo->weight.blue, pScreenInfo->depth);
114332b578d3Smrg        goto bail;
114432b578d3Smrg    }
114532b578d3Smrg
114632b578d3Smrg    /*
114732b578d3Smrg     * Set default visual.
114832b578d3Smrg     */
114932b578d3Smrg
115032b578d3Smrg    if (!xf86SetDefaultVisual(pScreenInfo, -1))
115132b578d3Smrg        goto bail;
115232b578d3Smrg
115332b578d3Smrg    if ((pScreenInfo->depth > 8) &&
115432b578d3Smrg        (((pScreenInfo->defaultVisual | DynamicClass) != DirectColor) ||
115532b578d3Smrg         ((pScreenInfo->defaultVisual == DirectColor) &&
115632b578d3Smrg          (pATI->DAC == ATI_DAC_INTERNAL))))
115732b578d3Smrg    {
115832b578d3Smrg        xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR,
115932b578d3Smrg            "Driver does not support default visual %s for depth %d.\n",
116032b578d3Smrg            xf86GetVisualName(pScreenInfo->defaultVisual),
116132b578d3Smrg            pScreenInfo->depth);
116232b578d3Smrg        goto bail;
116332b578d3Smrg    }
116432b578d3Smrg
116532b578d3Smrg    /*
116632b578d3Smrg     * Set colour gamma.
116732b578d3Smrg     */
116832b578d3Smrg
116932b578d3Smrg    if (!xf86SetGamma(pScreenInfo, defaultGamma))
117032b578d3Smrg        goto bail;
117132b578d3Smrg
117232b578d3Smrg    pATI->depth = pScreenInfo->depth;
117332b578d3Smrg    pATI->bitsPerPixel = pScreenInfo->bitsPerPixel;
117432b578d3Smrg    pATI->weight = pScreenInfo->weight;
117532b578d3Smrg    pATI->XModifier = pATI->bitsPerPixel / UnitOf(pATI->bitsPerPixel);
117632b578d3Smrg
117732b578d3Smrg    /*
117832b578d3Smrg     * Determine which CRT controller to use for video modes.
117932b578d3Smrg     */
118032b578d3Smrg
118132b578d3Smrg    {
118232b578d3Smrg        pATI->NewHW.crtc = ATI_CRTC_MACH64;
118332b578d3Smrg
118432b578d3Smrg        xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO,
118532b578d3Smrg            "Using Mach64 accelerator CRTC.\n");
118632b578d3Smrg
11872a51b5beSmrg#ifndef XSERVER_LIBPCIACCESS
118832b578d3Smrg#ifndef AVOID_CPIO
118932b578d3Smrg
119032b578d3Smrg        if (pATI->VGAAdapter)
119132b578d3Smrg        {
119232b578d3Smrg            /*
119332b578d3Smrg             * No need for VGA I/O resources during operating state (but they
119432b578d3Smrg             * are still decoded).
119532b578d3Smrg             */
119632b578d3Smrg            pResources =
119732b578d3Smrg                xf86SetOperatingState(resVgaIo, pATI->iEntity, ResUnusedOpr);
119832b578d3Smrg            if (pResources)
119932b578d3Smrg            {
120032b578d3Smrg                xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING,
120132b578d3Smrg                    "Logic error setting operating state for VGA I/O.\n");
120232b578d3Smrg                xf86FreeResList(pResources);
120332b578d3Smrg            }
120432b578d3Smrg
120532b578d3Smrg            if (pATI->CPIO_VGAWonder)
120632b578d3Smrg            {
120732b578d3Smrg                pResources = xf86SetOperatingState(pATI->VGAWonderResources,
120832b578d3Smrg                    pATI->iEntity, ResUnusedOpr);
120932b578d3Smrg                if (pResources)
121032b578d3Smrg                {
121132b578d3Smrg                    xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING,
121232b578d3Smrg                        "Logic error setting operating state for"
121332b578d3Smrg                        " VGAWonder I/O.\n");
121432b578d3Smrg                    xf86FreeResList(pResources);
121532b578d3Smrg                }
121632b578d3Smrg            }
121732b578d3Smrg        }
121832b578d3Smrg
121932b578d3Smrg#endif /* AVOID_CPIO */
12202a51b5beSmrg#endif
122132b578d3Smrg
122232b578d3Smrg    }
122332b578d3Smrg
122432b578d3Smrg    /*
122532b578d3Smrg     * Decide between the CRT and the panel.
122632b578d3Smrg     */
122732b578d3Smrg    if (pATI->LCDPanelID >= 0)
122832b578d3Smrg    {
122932b578d3Smrg        if (!pATI->OptionPanelDisplay)
123032b578d3Smrg        {
123132b578d3Smrg            xf86DrvMsg(pScreenInfo->scrnIndex, X_CONFIG,
123232b578d3Smrg                "Using CRT interface and disabling digital flat panel.\n");
123332b578d3Smrg        }
123432b578d3Smrg        else
123532b578d3Smrg        {
123632b578d3Smrg            unsigned HDisplay, VDisplay;
123732b578d3Smrg            CARD8 ClockMask, PostMask;
123832b578d3Smrg
123932b578d3Smrg            /*
124032b578d3Smrg             * Determine porch data.  This groks the mode on entry to extract
124132b578d3Smrg             * the width and position of its sync and blanking pulses, and
124232b578d3Smrg             * considers any overscan as part of the displayed area, given that
124332b578d3Smrg             * the overscan is also stretched.
124432b578d3Smrg             *
124532b578d3Smrg             * This also attempts to determine panel dimensions but cannot do
124632b578d3Smrg             * so for one that is "auto-stretched".
124732b578d3Smrg             */
124832b578d3Smrg
124932b578d3Smrg            if (pATI->Chip == ATI_CHIP_264LT)
125032b578d3Smrg            {
125132b578d3Smrg                pATIHW->lcd_gen_ctrl = inr(LCD_GEN_CTRL);
125232b578d3Smrg
125332b578d3Smrg                /* Set up to read non-shadow registers */
125432b578d3Smrg                if (pATIHW->lcd_gen_ctrl & SHADOW_RW_EN)
125532b578d3Smrg                    outr(LCD_GEN_CTRL, pATIHW->lcd_gen_ctrl & ~SHADOW_RW_EN);
125632b578d3Smrg            }
125732b578d3Smrg            else /* if ((pATI->Chip == ATI_CHIP_264LTPRO) ||
125832b578d3Smrg                        (pATI->Chip == ATI_CHIP_264XL) ||
125932b578d3Smrg                        (pATI->Chip == ATI_CHIP_MOBILITY)) */
126032b578d3Smrg            {
126132b578d3Smrg                pATIHW->lcd_index = inr(LCD_INDEX);
126232b578d3Smrg                pATIHW->config_panel = ATIMach64GetLCDReg(LCD_CONFIG_PANEL);
126332b578d3Smrg                pATIHW->lcd_gen_ctrl = ATIMach64GetLCDReg(LCD_GEN_CNTL);
126432b578d3Smrg
126532b578d3Smrg                /* Set up to read non-shadow registers */
126632b578d3Smrg                if (pATIHW->lcd_gen_ctrl & SHADOW_RW_EN)
126732b578d3Smrg                    ATIMach64PutLCDReg(LCD_GEN_CNTL,
126832b578d3Smrg                        pATIHW->lcd_gen_ctrl & ~SHADOW_RW_EN);
126932b578d3Smrg            }
127032b578d3Smrg
127132b578d3Smrg#ifndef AVOID_CPIO
127232b578d3Smrg
127332b578d3Smrg            if (!(pATIHW->crtc_gen_cntl & CRTC_EXT_DISP_EN))
127432b578d3Smrg            {
127532b578d3Smrg                unsigned HBlankStart, HSyncStart, HSyncEnd, HBlankEnd, HTotal;
127632b578d3Smrg                unsigned VBlankStart, VSyncStart, VSyncEnd, VBlankEnd, VTotal;
127732b578d3Smrg
127832b578d3Smrg                pATIHW->clock = (inb(R_GENMO) & 0x0CU) >> 2;
127932b578d3Smrg
128032b578d3Smrg                pATIHW->crt[2] = GetReg(CRTX(pATI->CPIO_VGABase), 0x02U);
128132b578d3Smrg                pATIHW->crt[3] = GetReg(CRTX(pATI->CPIO_VGABase), 0x03U);
128232b578d3Smrg                pATIHW->crt[5] = GetReg(CRTX(pATI->CPIO_VGABase), 0x05U);
128332b578d3Smrg                pATIHW->crt[7] = GetReg(CRTX(pATI->CPIO_VGABase), 0x07U);
128432b578d3Smrg                pATIHW->crt[9] = GetReg(CRTX(pATI->CPIO_VGABase), 0x09U);
128532b578d3Smrg                pATIHW->crt[21] = GetReg(CRTX(pATI->CPIO_VGABase), 0x15U);
128632b578d3Smrg                pATIHW->crt[22] = GetReg(CRTX(pATI->CPIO_VGABase), 0x16U);
128732b578d3Smrg
128832b578d3Smrg                pATIHW->crtc_h_total_disp = inr(CRTC_H_TOTAL_DISP);
128932b578d3Smrg                pATIHW->crtc_h_sync_strt_wid = inr(CRTC_H_SYNC_STRT_WID);
129032b578d3Smrg                pATIHW->crtc_v_total_disp = inr(CRTC_V_TOTAL_DISP);
129132b578d3Smrg                pATIHW->crtc_v_sync_strt_wid = inr(CRTC_V_SYNC_STRT_WID);
129232b578d3Smrg
129332b578d3Smrg                /* Switch to shadow registers */
129432b578d3Smrg                if (pATI->Chip == ATI_CHIP_264LT)
129532b578d3Smrg                    outr(LCD_GEN_CTRL, pATIHW->lcd_gen_ctrl | SHADOW_RW_EN);
129632b578d3Smrg                else /* if ((pATI->Chip == ATI_CHIP_264LTPRO) ||
129732b578d3Smrg                            (pATI->Chip == ATI_CHIP_264XL) ||
129832b578d3Smrg                            (pATI->Chip == ATI_CHIP_MOBILITY)) */
129932b578d3Smrg                    ATIMach64PutLCDReg(LCD_GEN_CNTL,
130032b578d3Smrg                        pATIHW->lcd_gen_ctrl | SHADOW_RW_EN);
130132b578d3Smrg
130232b578d3Smrg                pATIHW->shadow_vga[2] =
130332b578d3Smrg                    GetReg(CRTX(pATI->CPIO_VGABase), 0x02U);
130432b578d3Smrg                pATIHW->shadow_vga[3] =
130532b578d3Smrg                    GetReg(CRTX(pATI->CPIO_VGABase), 0x03U);
130632b578d3Smrg                pATIHW->shadow_vga[5] =
130732b578d3Smrg                    GetReg(CRTX(pATI->CPIO_VGABase), 0x05U);
130832b578d3Smrg                pATIHW->shadow_vga[7] =
130932b578d3Smrg                    GetReg(CRTX(pATI->CPIO_VGABase), 0x07U);
131032b578d3Smrg                pATIHW->shadow_vga[9] =
131132b578d3Smrg                    GetReg(CRTX(pATI->CPIO_VGABase), 0x09U);
131232b578d3Smrg                pATIHW->shadow_vga[21] =
131332b578d3Smrg                    GetReg(CRTX(pATI->CPIO_VGABase), 0x15U);
131432b578d3Smrg                pATIHW->shadow_vga[22] =
131532b578d3Smrg                    GetReg(CRTX(pATI->CPIO_VGABase), 0x16U);
131632b578d3Smrg
131732b578d3Smrg                pATIHW->shadow_h_total_disp = inr(CRTC_H_TOTAL_DISP);
131832b578d3Smrg                pATIHW->shadow_h_sync_strt_wid = inr(CRTC_H_SYNC_STRT_WID);
131932b578d3Smrg                pATIHW->shadow_v_total_disp = inr(CRTC_V_TOTAL_DISP);
132032b578d3Smrg                pATIHW->shadow_v_sync_strt_wid = inr(CRTC_V_SYNC_STRT_WID);
132132b578d3Smrg
132232b578d3Smrg                /*
132332b578d3Smrg                 * HSyncStart and HSyncEnd should equal their shadow
132432b578d3Smrg                 * counterparts.  Otherwise, due to a chip bug, the panel might
132532b578d3Smrg                 * not sync, regardless of which register set is used to drive
132632b578d3Smrg                 * the panel.  There are certain combinations of register
132732b578d3Smrg                 * values where the panel does in fact sync, but it remains
132832b578d3Smrg                 * impossible to accurately determine the horizontal sync pulse
132932b578d3Smrg                 * timing actually seen by the panel.
133032b578d3Smrg                 *
133132b578d3Smrg                 * Note that this hardware bug does not affect the CRT output.
133232b578d3Smrg                 */
133332b578d3Smrg                if (((pATIHW->crtc_h_sync_strt_wid ^
133432b578d3Smrg                      pATIHW->shadow_h_sync_strt_wid) &
133532b578d3Smrg                     (CRTC_H_SYNC_STRT | CRTC_H_SYNC_STRT_HI |
133632b578d3Smrg                      CRTC_H_SYNC_WID)))
133732b578d3Smrg                {
133832b578d3Smrg                    xf86DrvMsgVerb(pScreenInfo->scrnIndex, X_NOTICE, 0,
133932b578d3Smrg                        "Invalid horizontal sync pulse timing detected in mode"
134032b578d3Smrg                        " on server entry.\n");
134132b578d3Smrg
134232b578d3Smrg                    /* Don't trust input timing */
134332b578d3Smrg                    pATI->OptionLCDSync = TRUE;
134432b578d3Smrg                    ModeType = 0;
134532b578d3Smrg                }
134632b578d3Smrg
134732b578d3Smrg                /* Merge in shadow registers as appropriate */
134832b578d3Smrg                if (pATIHW->lcd_gen_ctrl & SHADOW_EN)
134932b578d3Smrg                {
135032b578d3Smrg                    pATIHW->crt[2] = pATIHW->shadow_vga[2];
135132b578d3Smrg                    pATIHW->crt[3] = pATIHW->shadow_vga[3];
135232b578d3Smrg                    pATIHW->crt[5] = pATIHW->shadow_vga[5];
135332b578d3Smrg
135432b578d3Smrg                    /* XXX Does this apply to VGA?  If so, what about the LT? */
135532b578d3Smrg                    if ((pATI->Chip < ATI_CHIP_264LTPRO) ||
135632b578d3Smrg                        !(pATIHW->config_panel & DONT_SHADOW_HEND))
135732b578d3Smrg                    {
135832b578d3Smrg                        pATIHW->crtc_h_total_disp &= ~CRTC_H_DISP;
135932b578d3Smrg                        pATIHW->crtc_h_total_disp |=
136032b578d3Smrg                            pATIHW->shadow_h_total_disp & CRTC_H_DISP;
136132b578d3Smrg                    }
136232b578d3Smrg
136332b578d3Smrg                    pATIHW->crtc_h_total_disp &= ~CRTC_H_TOTAL;
136432b578d3Smrg                    pATIHW->crtc_h_total_disp |=
136532b578d3Smrg                        pATIHW->shadow_h_total_disp & CRTC_H_TOTAL;
136632b578d3Smrg                    pATIHW->crtc_h_sync_strt_wid =
136732b578d3Smrg                        pATIHW->shadow_h_sync_strt_wid;
136832b578d3Smrg
136932b578d3Smrg                    /* XXX Does this apply to VGA? */
137032b578d3Smrg                    if (pATIHW->lcd_gen_ctrl & USE_SHADOWED_VEND)
137132b578d3Smrg                    {
137232b578d3Smrg                        pATIHW->crtc_v_total_disp &= ~CRTC_V_DISP;
137332b578d3Smrg                        pATIHW->crtc_v_total_disp |=
137432b578d3Smrg                            pATIHW->shadow_v_total_disp & CRTC_V_DISP;
137532b578d3Smrg                    }
137632b578d3Smrg
137732b578d3Smrg                    if (!(pATIHW->lcd_gen_ctrl & DONT_SHADOW_VPAR))
137832b578d3Smrg                    {
137932b578d3Smrg                        pATIHW->crt[7] = pATIHW->shadow_vga[7];
138032b578d3Smrg                        pATIHW->crt[9] = pATIHW->shadow_vga[9];
138132b578d3Smrg                        pATIHW->crt[21] = pATIHW->shadow_vga[21];
138232b578d3Smrg                        pATIHW->crt[22] = pATIHW->shadow_vga[22];
138332b578d3Smrg
138432b578d3Smrg                        pATIHW->crtc_v_total_disp &= ~CRTC_V_TOTAL;
138532b578d3Smrg                        pATIHW->crtc_v_total_disp |=
138632b578d3Smrg                            pATIHW->shadow_v_total_disp & CRTC_V_TOTAL;
138732b578d3Smrg                    }
138832b578d3Smrg                }
138932b578d3Smrg
139032b578d3Smrg                if (!(pATIHW->lcd_gen_ctrl & DONT_SHADOW_VPAR))
139132b578d3Smrg                    pATIHW->crtc_v_sync_strt_wid =
139232b578d3Smrg                        pATIHW->shadow_v_sync_strt_wid;
139332b578d3Smrg
139432b578d3Smrg                /*
139532b578d3Smrg                 * Decipher input timing.  This is complicated by the fact that
139632b578d3Smrg                 * the full width of all timing parameters, except for the
139732b578d3Smrg                 * blanking pulses, is only available through the accelerator
139832b578d3Smrg                 * registers, not the VGA ones.  Blanking pulse boundaries must
139932b578d3Smrg                 * then be interpolated.
140032b578d3Smrg                 *
140132b578d3Smrg                 * Note that, in VGA mode, the accelerator's sync width fields
140232b578d3Smrg                 * are actually end positions, not widths.
140332b578d3Smrg                 */
140432b578d3Smrg                HDisplay = GetBits(pATIHW->crtc_h_total_disp, CRTC_H_DISP);
140532b578d3Smrg                HSyncStart =
140632b578d3Smrg                    (GetBits(pATIHW->crtc_h_sync_strt_wid,
140732b578d3Smrg                        CRTC_H_SYNC_STRT_HI) *
140832b578d3Smrg                     (MaxBits(CRTC_H_SYNC_STRT) + 1)) |
140932b578d3Smrg                    GetBits(pATIHW->crtc_h_sync_strt_wid, CRTC_H_SYNC_STRT);
141032b578d3Smrg                HSyncEnd = (HSyncStart & ~MaxBits(CRTC_H_SYNC_WID)) |
141132b578d3Smrg                    GetBits(pATIHW->crtc_h_sync_strt_wid, CRTC_H_SYNC_WID);
141232b578d3Smrg                if (HSyncStart >= HSyncEnd)
141332b578d3Smrg                    HSyncEnd += MaxBits(CRTC_H_SYNC_WID) + 1;
141432b578d3Smrg                HTotal = GetBits(pATIHW->crtc_h_total_disp, CRTC_H_TOTAL);
141532b578d3Smrg
141632b578d3Smrg                HBlankStart = (HDisplay & ~0xFFU) | pATIHW->crt[2];
141732b578d3Smrg                if (HDisplay > HBlankStart)
141832b578d3Smrg                    HBlankStart += 0x0100U;
141932b578d3Smrg                HBlankEnd = (HSyncEnd & ~0x3FU) |
142032b578d3Smrg                    ((pATIHW->crt[5] >> 2) & 0x20U) |
142132b578d3Smrg                    (pATIHW->crt[3] & 0x1FU);
142232b578d3Smrg                if (HSyncEnd > (HBlankEnd + 1))
142332b578d3Smrg                    HBlankEnd += 0x40U;
142432b578d3Smrg
142532b578d3Smrg                VDisplay = GetBits(pATIHW->crtc_v_total_disp, CRTC_V_DISP);
142632b578d3Smrg                VSyncStart =
142732b578d3Smrg                    GetBits(pATIHW->crtc_v_sync_strt_wid, CRTC_V_SYNC_STRT);
142832b578d3Smrg                VSyncEnd = (VSyncStart & ~MaxBits(CRTC_V_SYNC_END_VGA)) |
142932b578d3Smrg                    GetBits(pATIHW->crtc_v_sync_strt_wid, CRTC_V_SYNC_END_VGA);
143032b578d3Smrg                if (VSyncStart > VSyncEnd)
143132b578d3Smrg                    VSyncEnd += MaxBits(CRTC_V_SYNC_END_VGA) + 1;
143232b578d3Smrg                VTotal = GetBits(pATIHW->crtc_v_total_disp, CRTC_V_TOTAL);
143332b578d3Smrg
143432b578d3Smrg                VBlankStart = (VDisplay & ~0x03FFU) |
143532b578d3Smrg                   ((pATIHW->crt[9] << 4) & 0x0200U) |
143632b578d3Smrg                   ((pATIHW->crt[7] << 5) & 0x0100U) | pATIHW->crt[21];
143732b578d3Smrg                if (VDisplay > VBlankStart)
143832b578d3Smrg                   VBlankStart += 0x0400U;
143932b578d3Smrg                VBlankEnd = (VSyncEnd & ~0x00FFU) | pATIHW->crt[22];
144032b578d3Smrg                if (VSyncEnd > (VBlankEnd + 1))
144132b578d3Smrg                   VBlankEnd += 0x0100U;
144232b578d3Smrg
144332b578d3Smrg                pATI->LCDHBlankWidth = HBlankEnd - HBlankStart;
144432b578d3Smrg                pATI->LCDHSyncStart = HSyncStart - HBlankStart;
144532b578d3Smrg                pATI->LCDHSyncWidth = HSyncEnd - HSyncStart;
144632b578d3Smrg
144732b578d3Smrg                pATI->LCDVBlankWidth = VBlankEnd - VBlankStart;
144832b578d3Smrg                pATI->LCDVSyncStart = VSyncStart - VBlankStart;
144932b578d3Smrg                pATI->LCDVSyncWidth = VSyncEnd - VSyncStart;
145032b578d3Smrg
145132b578d3Smrg                HDisplay = HTotal + 5 - pATI->LCDHBlankWidth;
145232b578d3Smrg                VDisplay = VTotal + 2 - pATI->LCDVBlankWidth;
145332b578d3Smrg            }
145432b578d3Smrg            else
145532b578d3Smrg
145632b578d3Smrg#endif /* AVOID_CPIO */
145732b578d3Smrg
145832b578d3Smrg            {
145932b578d3Smrg                pATIHW->clock = inr(CLOCK_CNTL) & 0x03U;
146032b578d3Smrg
146132b578d3Smrg                pATIHW->crtc_h_total_disp = inr(CRTC_H_TOTAL_DISP);
146232b578d3Smrg                pATIHW->crtc_h_sync_strt_wid = inr(CRTC_H_SYNC_STRT_WID);
146332b578d3Smrg                pATIHW->crtc_v_total_disp = inr(CRTC_V_TOTAL_DISP);
146432b578d3Smrg                pATIHW->crtc_v_sync_strt_wid = inr(CRTC_V_SYNC_STRT_WID);
146532b578d3Smrg                pATIHW->ovr_wid_left_right = inr(OVR_WID_LEFT_RIGHT);
146632b578d3Smrg                pATIHW->ovr_wid_top_bottom = inr(OVR_WID_TOP_BOTTOM);
146732b578d3Smrg
146832b578d3Smrg                /* Switch to shadow registers */
146932b578d3Smrg                if (pATI->Chip == ATI_CHIP_264LT)
147032b578d3Smrg                    outr(LCD_GEN_CTRL, pATIHW->lcd_gen_ctrl | SHADOW_RW_EN);
147132b578d3Smrg                else /* if ((pATI->Chip == ATI_CHIP_264LTPRO) ||
147232b578d3Smrg                            (pATI->Chip == ATI_CHIP_264XL) ||
147332b578d3Smrg                            (pATI->Chip == ATI_CHIP_MOBILITY)) */
147432b578d3Smrg                    ATIMach64PutLCDReg(LCD_GEN_CNTL,
147532b578d3Smrg                        pATIHW->lcd_gen_ctrl | SHADOW_RW_EN);
147632b578d3Smrg
147732b578d3Smrg                /* Oddly enough, there are no shadow overscan registers */
147832b578d3Smrg                pATIHW->shadow_h_total_disp = inr(CRTC_H_TOTAL_DISP);
147932b578d3Smrg                pATIHW->shadow_h_sync_strt_wid = inr(CRTC_H_SYNC_STRT_WID);
148032b578d3Smrg                pATIHW->shadow_v_total_disp = inr(CRTC_V_TOTAL_DISP);
148132b578d3Smrg                pATIHW->shadow_v_sync_strt_wid = inr(CRTC_V_SYNC_STRT_WID);
148232b578d3Smrg
148332b578d3Smrg                /*
148432b578d3Smrg                 * HSyncStart and HSyncEnd should equal their shadow
148532b578d3Smrg                 * counterparts.  Otherwise, due to a chip bug, the panel might
148632b578d3Smrg                 * not sync, regardless of which register set is used to drive
148732b578d3Smrg                 * the panel.  There are certain combinations of register
148832b578d3Smrg                 * values where the panel does in fact sync, but it remains
148932b578d3Smrg                 * impossible to accurately determine the horizontal sync pulse
149032b578d3Smrg                 * timing actually seen by the panel.
149132b578d3Smrg                 *
149232b578d3Smrg                 * Note that this hardware bug does not affect the CRT output.
149332b578d3Smrg                 */
149432b578d3Smrg                if (((pATIHW->crtc_h_sync_strt_wid ^
149532b578d3Smrg                      pATIHW->shadow_h_sync_strt_wid) &
149632b578d3Smrg                     (CRTC_H_SYNC_STRT | CRTC_H_SYNC_STRT_HI |
149732b578d3Smrg                      CRTC_H_SYNC_WID)))
149832b578d3Smrg                {
149932b578d3Smrg                    xf86DrvMsgVerb(pScreenInfo->scrnIndex, X_NOTICE, 0,
150032b578d3Smrg                        "Invalid horizontal sync pulse timing detected in mode"
150132b578d3Smrg                        " on server entry.\n");
150232b578d3Smrg
150332b578d3Smrg                    /* Don't trust input timing */
150432b578d3Smrg                    pATI->OptionLCDSync = TRUE;
150532b578d3Smrg                    ModeType = 0;
150632b578d3Smrg                }
150732b578d3Smrg
150832b578d3Smrg                /* Merge in shadow registers as appropriate */
150932b578d3Smrg                if (pATIHW->lcd_gen_ctrl & SHADOW_EN)
151032b578d3Smrg                {
151132b578d3Smrg                    /* XXX What about the LT? */
151232b578d3Smrg                    if ((pATI->Chip < ATI_CHIP_264LTPRO) ||
151332b578d3Smrg                        !(pATIHW->config_panel & DONT_SHADOW_HEND))
151432b578d3Smrg                    {
151532b578d3Smrg                        pATIHW->crtc_h_total_disp &= ~CRTC_H_DISP;
151632b578d3Smrg                        pATIHW->crtc_h_total_disp |=
151732b578d3Smrg                            pATIHW->shadow_h_total_disp & CRTC_H_DISP;
151832b578d3Smrg                    }
151932b578d3Smrg
152032b578d3Smrg                    pATIHW->crtc_h_total_disp &= ~CRTC_H_TOTAL;
152132b578d3Smrg                    pATIHW->crtc_h_total_disp |=
152232b578d3Smrg                        pATIHW->shadow_h_total_disp & CRTC_H_TOTAL;
152332b578d3Smrg                    pATIHW->crtc_h_sync_strt_wid =
152432b578d3Smrg                        pATIHW->shadow_h_sync_strt_wid;
152532b578d3Smrg
152632b578d3Smrg                    if (pATIHW->lcd_gen_ctrl & USE_SHADOWED_VEND)
152732b578d3Smrg                    {
152832b578d3Smrg                        pATIHW->crtc_v_total_disp &= ~CRTC_V_DISP;
152932b578d3Smrg                        pATIHW->crtc_v_total_disp |=
153032b578d3Smrg                            pATIHW->shadow_v_total_disp & CRTC_V_DISP;
153132b578d3Smrg                    }
153232b578d3Smrg
153332b578d3Smrg                    if (!(pATIHW->lcd_gen_ctrl & DONT_SHADOW_VPAR))
153432b578d3Smrg                    {
153532b578d3Smrg                        pATIHW->crtc_v_total_disp &= ~CRTC_V_TOTAL;
153632b578d3Smrg                        pATIHW->crtc_v_total_disp |=
153732b578d3Smrg                            pATIHW->shadow_v_total_disp & CRTC_V_TOTAL;
153832b578d3Smrg                    }
153932b578d3Smrg                }
154032b578d3Smrg
154132b578d3Smrg                if (!(pATIHW->lcd_gen_ctrl & DONT_SHADOW_VPAR))
154232b578d3Smrg                    pATIHW->crtc_v_sync_strt_wid =
154332b578d3Smrg                        pATIHW->shadow_v_sync_strt_wid;
154432b578d3Smrg
154532b578d3Smrg                /* Decipher input timing */
154632b578d3Smrg                HDisplay = GetBits(pATIHW->crtc_h_total_disp, CRTC_H_DISP) +
154732b578d3Smrg                    GetBits(pATIHW->ovr_wid_left_right, OVR_WID_LEFT) +
154832b578d3Smrg                    GetBits(pATIHW->ovr_wid_left_right, OVR_WID_RIGHT);
154932b578d3Smrg                VDisplay = GetBits(pATIHW->crtc_v_total_disp, CRTC_V_DISP) +
155032b578d3Smrg                    GetBits(pATIHW->ovr_wid_top_bottom, OVR_WID_TOP) +
155132b578d3Smrg                    GetBits(pATIHW->ovr_wid_top_bottom, OVR_WID_BOTTOM);
155232b578d3Smrg
155332b578d3Smrg                pATI->LCDHSyncStart =
155432b578d3Smrg                    (GetBits(pATIHW->crtc_h_sync_strt_wid,
155532b578d3Smrg                        CRTC_H_SYNC_STRT_HI) *
155632b578d3Smrg                     (MaxBits(CRTC_H_SYNC_STRT) + 1)) +
155732b578d3Smrg                    GetBits(pATIHW->crtc_h_sync_strt_wid, CRTC_H_SYNC_STRT) -
155832b578d3Smrg                    HDisplay;
155932b578d3Smrg                pATI->LCDHSyncWidth =
156032b578d3Smrg                    GetBits(pATIHW->crtc_h_sync_strt_wid, CRTC_H_SYNC_WID);
156132b578d3Smrg                pATI->LCDHBlankWidth =
156232b578d3Smrg                    GetBits(pATIHW->crtc_h_total_disp, CRTC_H_TOTAL) -
156332b578d3Smrg                    HDisplay;
156432b578d3Smrg                pATI->LCDVSyncStart =
156532b578d3Smrg                    GetBits(pATIHW->crtc_v_sync_strt_wid, CRTC_V_SYNC_STRT) -
156632b578d3Smrg                    VDisplay;
156732b578d3Smrg                pATI->LCDVSyncWidth =
156832b578d3Smrg                    GetBits(pATIHW->crtc_v_sync_strt_wid, CRTC_V_SYNC_WID);
156932b578d3Smrg                pATI->LCDVBlankWidth =
157032b578d3Smrg                    GetBits(pATIHW->crtc_v_total_disp, CRTC_V_TOTAL) -
157132b578d3Smrg                    VDisplay;
157232b578d3Smrg
157332b578d3Smrg                HDisplay++;
157432b578d3Smrg                VDisplay++;
157532b578d3Smrg            }
157632b578d3Smrg
157732b578d3Smrg            /* Restore LCD registers */
157832b578d3Smrg            if (pATI->Chip == ATI_CHIP_264LT)
157932b578d3Smrg            {
158032b578d3Smrg                outr(LCD_GEN_CTRL, pATIHW->lcd_gen_ctrl);
158132b578d3Smrg            }
158232b578d3Smrg            else /* if ((pATI->Chip == ATI_CHIP_264LTPRO) ||
158332b578d3Smrg                        (pATI->Chip == ATI_CHIP_264XL) ||
158432b578d3Smrg                        (pATI->Chip == ATI_CHIP_MOBILITY)) */
158532b578d3Smrg            {
158632b578d3Smrg                ATIMach64PutLCDReg(LCD_GEN_CNTL, pATIHW->lcd_gen_ctrl);
158732b578d3Smrg                outr(LCD_INDEX, pATIHW->lcd_index);
158832b578d3Smrg            }
158932b578d3Smrg
159032b578d3Smrg            HDisplay <<= 3;
159132b578d3Smrg            pATI->LCDHSyncStart <<= 3;
159232b578d3Smrg            pATI->LCDHSyncWidth <<= 3;
159332b578d3Smrg            pATI->LCDHBlankWidth <<= 3;
159432b578d3Smrg
159532b578d3Smrg            /* Calculate panel dimensions implied by the input timing */
159632b578d3Smrg            if ((pATIHW->horz_stretching &
159732b578d3Smrg                 (HORZ_STRETCH_EN | AUTO_HORZ_RATIO)) ==
159832b578d3Smrg                HORZ_STRETCH_EN)
159932b578d3Smrg            {
160032b578d3Smrg                if (pATIHW->horz_stretching & HORZ_STRETCH_MODE)
160132b578d3Smrg                {
160232b578d3Smrg                    if (pATIHW->horz_stretching & HORZ_STRETCH_BLEND)
160332b578d3Smrg                    {
160432b578d3Smrg                        HDisplay =
160532b578d3Smrg                            (HDisplay * (MaxBits(HORZ_STRETCH_BLEND) + 1)) /
160632b578d3Smrg                            GetBits(pATIHW->horz_stretching,
160732b578d3Smrg                                HORZ_STRETCH_BLEND);
160832b578d3Smrg                    }
160932b578d3Smrg                }
161032b578d3Smrg                else if (((pATIHW->horz_stretching & HORZ_STRETCH_LOOP) >
161132b578d3Smrg                          HORZ_STRETCH_LOOP15) ||
161232b578d3Smrg                         (pATIHW->horz_stretching &
161332b578d3Smrg                          SetBits(1, HORZ_STRETCH_RATIO)))
161432b578d3Smrg                {
161532b578d3Smrg                    xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING,
161632b578d3Smrg                        "Ignoring invalid horizontal stretch ratio in mode on"
161732b578d3Smrg                        " server entry.\n");
161832b578d3Smrg                }
161932b578d3Smrg                else
162032b578d3Smrg                {
162132b578d3Smrg                    IOValue =
162232b578d3Smrg                        GetBits(pATIHW->horz_stretching, HORZ_STRETCH_RATIO);
162332b578d3Smrg
162432b578d3Smrg                    switch (GetBits(pATIHW->horz_stretching,
162532b578d3Smrg                                    HORZ_STRETCH_LOOP))
162632b578d3Smrg                    {
162732b578d3Smrg                        case GetBits(HORZ_STRETCH_LOOP09, HORZ_STRETCH_LOOP):
162832b578d3Smrg                            i = 9;
162932b578d3Smrg                            IOValue &= (1 << 9) - 1;
163032b578d3Smrg                            break;
163132b578d3Smrg
163232b578d3Smrg                        case GetBits(HORZ_STRETCH_LOOP11, HORZ_STRETCH_LOOP):
163332b578d3Smrg                            i = 11;
163432b578d3Smrg                            IOValue &= (1 << 11) - 1;
163532b578d3Smrg                            break;
163632b578d3Smrg
163732b578d3Smrg                        case GetBits(HORZ_STRETCH_LOOP12, HORZ_STRETCH_LOOP):
163832b578d3Smrg                            i = 12;
163932b578d3Smrg                            IOValue &= (1 << 12) - 1;
164032b578d3Smrg                            break;
164132b578d3Smrg
164232b578d3Smrg                        case GetBits(HORZ_STRETCH_LOOP14, HORZ_STRETCH_LOOP):
164332b578d3Smrg                            i = 14;
164432b578d3Smrg                            IOValue &= (1 << 14) - 1;
164532b578d3Smrg                            break;
164632b578d3Smrg
164732b578d3Smrg                        case GetBits(HORZ_STRETCH_LOOP15, HORZ_STRETCH_LOOP):
164832b578d3Smrg                        default:    /* Muffle compiler */
164932b578d3Smrg                            i = 15;
165032b578d3Smrg                            IOValue &= (1 << 15) - 1;
165132b578d3Smrg                            break;
165232b578d3Smrg                    }
165332b578d3Smrg
165432b578d3Smrg                    if (IOValue)
165532b578d3Smrg                    {
165632b578d3Smrg                        /* Count the number of bits in IOValue */
165732b578d3Smrg                        j = (IOValue >> 1) & 0x36DBU;
165832b578d3Smrg                        j = IOValue - j - ((j >> 1) & 0x36DBU);
165932b578d3Smrg                        j = ((j + (j >> 3)) & 0x71C7U) % 0x3FU;
166032b578d3Smrg
166132b578d3Smrg                        HDisplay = (HDisplay * i) / j;
166232b578d3Smrg                    }
166332b578d3Smrg                }
166432b578d3Smrg            }
166532b578d3Smrg
166632b578d3Smrg            if ((pATIHW->vert_stretching & VERT_STRETCH_EN) &&
166732b578d3Smrg                !(pATIHW->ext_vert_stretch & AUTO_VERT_RATIO))
166832b578d3Smrg            {
166932b578d3Smrg                if ((pATIHW->vert_stretching & VERT_STRETCH_USE0) ||
167032b578d3Smrg                    (VDisplay <= 350))
167132b578d3Smrg                    IOValue =
167232b578d3Smrg                        GetBits(pATIHW->vert_stretching, VERT_STRETCH_RATIO0);
167332b578d3Smrg                else if (VDisplay <= 400)
167432b578d3Smrg                    IOValue =
167532b578d3Smrg                        GetBits(pATIHW->vert_stretching, VERT_STRETCH_RATIO1);
167632b578d3Smrg                else if ((VDisplay <= 480) ||
167732b578d3Smrg                         !(pATIHW->ext_vert_stretch & VERT_STRETCH_RATIO3))
167832b578d3Smrg                    IOValue =
167932b578d3Smrg                        GetBits(pATIHW->vert_stretching, VERT_STRETCH_RATIO2);
168032b578d3Smrg                else
168132b578d3Smrg                    IOValue =
168232b578d3Smrg                        GetBits(pATIHW->ext_vert_stretch, VERT_STRETCH_RATIO3);
168332b578d3Smrg
168432b578d3Smrg                if (IOValue)
168532b578d3Smrg                    VDisplay =
168632b578d3Smrg                        (VDisplay * (MaxBits(VERT_STRETCH_RATIO0) + 1)) /
168732b578d3Smrg                        IOValue;
168832b578d3Smrg            }
168932b578d3Smrg
169032b578d3Smrg            /* Match calculated dimensions to probed dimensions */
169132b578d3Smrg            if (!pATI->LCDHorizontal)
169232b578d3Smrg            {
169332b578d3Smrg                if ((pATIHW->horz_stretching &
169432b578d3Smrg                     (HORZ_STRETCH_EN | AUTO_HORZ_RATIO)) !=
169532b578d3Smrg                     (HORZ_STRETCH_EN | AUTO_HORZ_RATIO))
169632b578d3Smrg                    pATI->LCDHorizontal = HDisplay;
169732b578d3Smrg            }
169832b578d3Smrg            else if (pATI->LCDHorizontal != (int)HDisplay)
169932b578d3Smrg            {
170032b578d3Smrg                if ((pATIHW->horz_stretching &
170132b578d3Smrg                    (HORZ_STRETCH_EN | AUTO_HORZ_RATIO)) !=
170232b578d3Smrg                    (HORZ_STRETCH_EN | AUTO_HORZ_RATIO))
170332b578d3Smrg                    xf86DrvMsgVerb(pScreenInfo->scrnIndex, X_WARNING, 4,
170432b578d3Smrg                        "Inconsistent panel horizontal dimension:"
170532b578d3Smrg                        "  %d and %d.\n", pATI->LCDHorizontal, HDisplay);
170632b578d3Smrg                HDisplay = pATI->LCDHorizontal;
170732b578d3Smrg            }
170832b578d3Smrg
170932b578d3Smrg            if (!pATI->LCDVertical)
171032b578d3Smrg            {
171132b578d3Smrg                if (!(pATIHW->vert_stretching & VERT_STRETCH_EN) ||
171232b578d3Smrg                    !(pATIHW->ext_vert_stretch & AUTO_VERT_RATIO))
171332b578d3Smrg                    pATI->LCDVertical = VDisplay;
171432b578d3Smrg            }
171532b578d3Smrg            else if (pATI->LCDVertical != (int)VDisplay)
171632b578d3Smrg            {
171732b578d3Smrg                if (!(pATIHW->vert_stretching & VERT_STRETCH_EN) ||
171832b578d3Smrg                    !(pATIHW->ext_vert_stretch & AUTO_VERT_RATIO))
171932b578d3Smrg                    xf86DrvMsgVerb(pScreenInfo->scrnIndex, X_WARNING, 4,
172032b578d3Smrg                        "Inconsistent panel vertical dimension:  %d and %d.\n",
172132b578d3Smrg                        pATI->LCDVertical, VDisplay);
172232b578d3Smrg                VDisplay = pATI->LCDVertical;
172332b578d3Smrg            }
172432b578d3Smrg
172532b578d3Smrg            if (!pATI->LCDHorizontal || !pATI->LCDVertical)
172632b578d3Smrg            {
172732b578d3Smrg                if (pATI->LCDPanelID || (pATI->Chip <= ATI_CHIP_264LTPRO))
172832b578d3Smrg                    xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR,
172932b578d3Smrg                        "Unable to determine dimensions of panel (ID %d).\n",
173032b578d3Smrg                        pATI->LCDPanelID);
173132b578d3Smrg                else
173232b578d3Smrg                    xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR,
173332b578d3Smrg                        "Unable to determine dimensions of panel.\n");
173432b578d3Smrg
173532b578d3Smrg                goto bail;
173632b578d3Smrg            }
173732b578d3Smrg
173832b578d3Smrg            /* If the mode on entry wasn't stretched, adjust timings */
173932b578d3Smrg            if (!(pATIHW->horz_stretching & HORZ_STRETCH_EN) &&
174032b578d3Smrg                (pATI->LCDHorizontal > (int)HDisplay))
174132b578d3Smrg            {
174232b578d3Smrg                HDisplay = pATI->LCDHorizontal - HDisplay;
174332b578d3Smrg                if (pATI->LCDHSyncStart >= HDisplay)
174432b578d3Smrg                    pATI->LCDHSyncStart -= HDisplay;
174532b578d3Smrg                else
174632b578d3Smrg                    pATI->LCDHSyncStart = 0;
174732b578d3Smrg                pATI->LCDHBlankWidth -= HDisplay;
174832b578d3Smrg                HDisplay = pATI->LCDHSyncStart + pATI->LCDHSyncWidth;
174932b578d3Smrg                if (pATI->LCDHBlankWidth < HDisplay)
175032b578d3Smrg                    pATI->LCDHBlankWidth = HDisplay;
175132b578d3Smrg            }
175232b578d3Smrg
175332b578d3Smrg            if (!(pATIHW->vert_stretching & VERT_STRETCH_EN) &&
175432b578d3Smrg                (pATI->LCDVertical > (int)VDisplay))
175532b578d3Smrg            {
175632b578d3Smrg                VDisplay = pATI->LCDVertical - VDisplay;
175732b578d3Smrg                if (pATI->LCDVSyncStart >= VDisplay)
175832b578d3Smrg                    pATI->LCDVSyncStart -= VDisplay;
175932b578d3Smrg                else
176032b578d3Smrg                    pATI->LCDVSyncStart = 0;
176132b578d3Smrg                pATI->LCDVBlankWidth -= VDisplay;
176232b578d3Smrg                VDisplay = pATI->LCDVSyncStart + pATI->LCDVSyncWidth;
176332b578d3Smrg                if (pATI->LCDVBlankWidth < VDisplay)
176432b578d3Smrg                    pATI->LCDVBlankWidth = VDisplay;
176532b578d3Smrg            }
176632b578d3Smrg
176732b578d3Smrg            if (pATI->LCDPanelID || (pATI->Chip <= ATI_CHIP_264LTPRO))
176832b578d3Smrg                xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED,
176932b578d3Smrg                    "%dx%d panel (ID %d) detected.\n",
177032b578d3Smrg                    pATI->LCDHorizontal, pATI->LCDVertical, pATI->LCDPanelID);
177132b578d3Smrg            else
177232b578d3Smrg                xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED,
177332b578d3Smrg                    "%dx%d panel detected.\n",
177432b578d3Smrg                    pATI->LCDHorizontal, pATI->LCDVertical);
177532b578d3Smrg
177632b578d3Smrg            /*
177732b578d3Smrg             * Determine panel clock.  This must be done after option
177832b578d3Smrg             * processing so that the adapter's reference frequency is always
177932b578d3Smrg             * available.
178032b578d3Smrg             *
178132b578d3Smrg             * Get post divider.  A GCC bug has caused the following expression
178232b578d3Smrg             * to be broken down into its individual components.
178332b578d3Smrg             */
178432b578d3Smrg            ClockMask = PLL_VCLK0_XDIV << pATIHW->clock;
178532b578d3Smrg            PostMask = PLL_VCLK0_POST_DIV << (pATIHW->clock * 2);
178632b578d3Smrg            i = GetBits(ATIMach64GetPLLReg(PLL_XCLK_CNTL), ClockMask);
178732b578d3Smrg            i *= MaxBits(PLL_VCLK0_POST_DIV) + 1;
178832b578d3Smrg            i |= GetBits(ATIMach64GetPLLReg(PLL_VCLK_POST_DIV), PostMask);
178932b578d3Smrg
179032b578d3Smrg            /* Calculate clock of mode on entry */
179132b578d3Smrg            Numerator = ATIMach64GetPLLReg(PLL_VCLK0_FB_DIV + pATIHW->clock) *
179232b578d3Smrg                pATI->ReferenceNumerator;
179332b578d3Smrg            Denominator = pATI->ClockDescriptor.MinM *
179432b578d3Smrg                pATI->ReferenceDenominator *
179532b578d3Smrg                pATI->ClockDescriptor.PostDividers[i];
179632b578d3Smrg            pATI->LCDClock = ATIDivide(Numerator, Denominator, 1, 0);
179732b578d3Smrg
179832b578d3Smrg            xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED,
179932b578d3Smrg                "Panel clock is %.3f MHz.\n",
180032b578d3Smrg                (double)(pATI->LCDClock) / 1000.0);
180132b578d3Smrg
180232b578d3Smrg            xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO,
180332b578d3Smrg                "Using digital flat panel interface%s.\n",
180432b578d3Smrg                pATI->OptionCRTDisplay ?
180532b578d3Smrg                    " to display on both CRT and panel" : "");
180632b578d3Smrg        }
180732b578d3Smrg    }
180832b578d3Smrg
180932b578d3Smrg    /*
181032b578d3Smrg     * Finish detecting video RAM size.
181132b578d3Smrg     */
181232b578d3Smrg    pScreenInfo->videoRam = pATI->VideoRAM;
181332b578d3Smrg
181432b578d3Smrg    {
181532b578d3Smrg        {
181632b578d3Smrg            /* Get adapter's linear aperture configuration */
181732b578d3Smrg            pATIHW->config_cntl = inr(CONFIG_CNTL);
181832b578d3Smrg            pATI->LinearBase =
181932b578d3Smrg                GetBits(pATIHW->config_cntl, CFG_MEM_AP_LOC) << 22;
182032b578d3Smrg            if ((pATIHW->config_cntl & CFG_MEM_AP_SIZE) != CFG_MEM_AP_SIZE)
182132b578d3Smrg            {
182232b578d3Smrg                pATI->LinearSize =
182332b578d3Smrg                    GetBits(pATIHW->config_cntl, CFG_MEM_AP_SIZE) << 22;
182432b578d3Smrg
182532b578d3Smrg                /*
182632b578d3Smrg                 * Linear aperture could have been disabled (but still
182732b578d3Smrg                 * assigned) by BIOS initialisation.
182832b578d3Smrg                 */
182932b578d3Smrg                if (pATI->LinearBase && !pATI->LinearSize)
183032b578d3Smrg                {
183132b578d3Smrg                    if ((pATI->Chip <= ATI_CHIP_88800GXD) &&
183232b578d3Smrg                        (pATI->VideoRAM < 4096))
183332b578d3Smrg                        pATI->LinearSize = 4 * 1024 * 1024;
183432b578d3Smrg                    else
183532b578d3Smrg                        pATI->LinearSize = 8 * 1024 * 1024;
183632b578d3Smrg                }
183732b578d3Smrg            }
183832b578d3Smrg
183932b578d3Smrg            if (pATI->LinearBase && pATI->LinearSize)
184032b578d3Smrg            {
184132b578d3Smrg                int AcceleratorVideoRAM = 0, ServerVideoRAM;
184232b578d3Smrg
184332b578d3Smrg#ifndef AVOID_CPIO
184432b578d3Smrg
184532b578d3Smrg                /*
184632b578d3Smrg                 * Unless specified in PCI configuration space, set MMIO
184732b578d3Smrg                 * address to tail end of linear aperture.
184832b578d3Smrg                 */
184932b578d3Smrg                if (!pATI->Block0Base)
185032b578d3Smrg                {
185132b578d3Smrg                    pATI->Block0Base =
185232b578d3Smrg                        pATI->LinearBase + pATI->LinearSize - 0x00000400U;
185332b578d3Smrg                    pATI->MMIOInLinear = TRUE;
185432b578d3Smrg                }
185532b578d3Smrg
185632b578d3Smrg#endif /* AVOID_CPIO */
185732b578d3Smrg
185832b578d3Smrg                AcceleratorVideoRAM = pATI->LinearSize >> 10;
185932b578d3Smrg
186032b578d3Smrg                /*
186132b578d3Smrg                 * Account for MMIO area at the tail end of the linear
186232b578d3Smrg                 * aperture, if it is needed or if it cannot be disabled.
186332b578d3Smrg                 */
186432b578d3Smrg                if (pATI->MMIOInLinear || (pATI->Chip < ATI_CHIP_264VTB))
186532b578d3Smrg                    AcceleratorVideoRAM -= 2;
186632b578d3Smrg
186732b578d3Smrg                ServerVideoRAM = pATI->VideoRAM;
186832b578d3Smrg
186932b578d3Smrg                if (pATI->Cursor > ATI_CURSOR_SOFTWARE)
187032b578d3Smrg                {
187132b578d3Smrg                    /*
187232b578d3Smrg                     * Allocate a 1 kB cursor image area at the top of the
187332b578d3Smrg                     * little-endian aperture, just before any MMIO area that
187432b578d3Smrg                     * might also be there.
187532b578d3Smrg                     */
187632b578d3Smrg                    if (ServerVideoRAM > AcceleratorVideoRAM)
187732b578d3Smrg                        ServerVideoRAM = AcceleratorVideoRAM;
187832b578d3Smrg
187932b578d3Smrg                    ServerVideoRAM--;
188032b578d3Smrg                    pATI->CursorOffset = ServerVideoRAM << 10;
188132b578d3Smrg                    pATI->CursorBase = pATI->LinearBase + pATI->CursorOffset;
188232b578d3Smrg
188332b578d3Smrg                    xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO,
188432b578d3Smrg                        "Storing hardware cursor image at 0x%08lX.\n",
188532b578d3Smrg                        pATI->CursorBase);
188632b578d3Smrg                }
188732b578d3Smrg
188832b578d3Smrg                {
188932b578d3Smrg                    CARD32 PageSize = getpagesize() >> 10;
189032b578d3Smrg
189132b578d3Smrg#if X_BYTE_ORDER == X_LITTLE_ENDIAN
189232b578d3Smrg
189332b578d3Smrg                    /*
189432b578d3Smrg                     * MMIO areas must be mmap()'ed separately to avoid write
189532b578d3Smrg                     * combining them.  Thus, they might not end up still
189632b578d3Smrg                     * adjacent with the little-endian linear aperture after
189732b578d3Smrg                     * mmap()'ing.  So, round down the linear aperture size to
189832b578d3Smrg                     * avoid an overlap.  Any hardware cursor image area might
189932b578d3Smrg                     * not end up being write combined, but this seems
190032b578d3Smrg                     * preferable to further reducing the video memory size
190132b578d3Smrg                     * advertised to the server.
190232b578d3Smrg                     *
190332b578d3Smrg                     * XXX Ideally this should be dealt with in the os-support
190432b578d3Smrg                     *     layer, i.e., it should be possible to reset a
190532b578d3Smrg                     *     subarea's write combining after it has been
190632b578d3Smrg                     *     mmap()'ed, but doing so currently causes the removal
190732b578d3Smrg                     *     of write combining for the entire aperture.
190832b578d3Smrg                     */
190932b578d3Smrg                    if (pATI->MMIOInLinear)
191032b578d3Smrg                        AcceleratorVideoRAM -= AcceleratorVideoRAM % PageSize;
191132b578d3Smrg
191232b578d3Smrg#else /* if X_BYTE_ORDER != X_LITTLE_ENDIAN */
191332b578d3Smrg
191432b578d3Smrg                    /*
191532b578d3Smrg                     * Big-endian apertures are 8 MB higher and don't contain
191632b578d3Smrg                     * an MMIO area.
191732b578d3Smrg                     */
191832b578d3Smrg                    pATI->LinearBase += 0x00800000U;
191932b578d3Smrg                    AcceleratorVideoRAM = pATI->LinearSize >> 10;
192032b578d3Smrg
192132b578d3Smrg#endif /* X_BYTE_ORDER */
192232b578d3Smrg
192332b578d3Smrg                    if (ServerVideoRAM > AcceleratorVideoRAM)
192432b578d3Smrg                        ServerVideoRAM = AcceleratorVideoRAM;
192532b578d3Smrg                    else if (AcceleratorVideoRAM > pATI->VideoRAM)
192632b578d3Smrg                        AcceleratorVideoRAM = pATI->VideoRAM;
192732b578d3Smrg
192832b578d3Smrg                    PageSize--;
192932b578d3Smrg                    AcceleratorVideoRAM =
193032b578d3Smrg                        (AcceleratorVideoRAM + PageSize) & ~PageSize;
193132b578d3Smrg
193232b578d3Smrg                    xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO,
193332b578d3Smrg                        "Using %d MB linear aperture at 0x%08lX.\n",
193432b578d3Smrg                        pATI->LinearSize >> 20, pATI->LinearBase);
193532b578d3Smrg
193632b578d3Smrg                    /* Only mmap what is needed */
193732b578d3Smrg                    ApertureSize = pATI->LinearSize =
193832b578d3Smrg                        AcceleratorVideoRAM << 10;
193932b578d3Smrg                }
194032b578d3Smrg
194132b578d3Smrg                if (ServerVideoRAM < pATI->VideoRAM)
194232b578d3Smrg                {
194332b578d3Smrg                    pScreenInfo->videoRam = ServerVideoRAM;
194432b578d3Smrg                    xf86DrvMsg(pScreenInfo->scrnIndex, X_NOTICE,
194532b578d3Smrg                        "Virtual resolutions will be limited to %d kB\n due to"
194632b578d3Smrg                        " linear aperture size and/or placement of hardware"
194732b578d3Smrg                        " cursor image area.\n",
194832b578d3Smrg                        ServerVideoRAM);
194932b578d3Smrg                }
195032b578d3Smrg            }
195132b578d3Smrg        }
195232b578d3Smrg
195332b578d3Smrg        if (!pATI->LinearBase || !pATI->LinearSize)
195432b578d3Smrg        {
195532b578d3Smrg                xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR,
195632b578d3Smrg                    "Linear aperture not available.\n");
195732b578d3Smrg                goto bail;
195832b578d3Smrg        }
195932b578d3Smrg
196032b578d3Smrg        if (pATI->Block0Base)
196132b578d3Smrg        {
196232b578d3Smrg            xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO,
196332b578d3Smrg                "Using Block 0 MMIO aperture at 0x%08lX.\n", pATI->Block0Base);
196432b578d3Smrg
196532b578d3Smrg            /* Set Block1 MMIO address if supported */
196632b578d3Smrg            if (pATI->Chip >= ATI_CHIP_264VT)
196732b578d3Smrg            {
196832b578d3Smrg                pATI->Block1Base = pATI->Block0Base - 0x00000400U;
196932b578d3Smrg                xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO,
197032b578d3Smrg                    "Using Block 1 MMIO aperture at 0x%08lX.\n",
197132b578d3Smrg                    pATI->Block1Base);
197232b578d3Smrg            }
197332b578d3Smrg        }
197432b578d3Smrg    }
197532b578d3Smrg
19762a51b5beSmrg#ifndef XSERVER_LIBPCIACCESS
197732b578d3Smrg#ifndef AVOID_CPIO
197832b578d3Smrg
197932b578d3Smrg        if (pATI->VGAAdapter)
198032b578d3Smrg        {
198132b578d3Smrg            /*
198232b578d3Smrg             * Free VGA memory aperture during operating state (but it is still
198332b578d3Smrg             * decoded).
198432b578d3Smrg             */
198532b578d3Smrg            pResources = xf86SetOperatingState(resVgaMem, pATI->iEntity,
198632b578d3Smrg                ResUnusedOpr);
198732b578d3Smrg            if (pResources)
198832b578d3Smrg            {
198932b578d3Smrg                xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING,
199032b578d3Smrg                    "Logic error setting operating state for VGA memory"
199132b578d3Smrg                    " aperture.\n");
199232b578d3Smrg                xf86FreeResList(pResources);
199332b578d3Smrg            }
199432b578d3Smrg        }
199532b578d3Smrg
199632b578d3Smrg#endif /* AVOID_CPIO */
19972a51b5beSmrg#endif
199832b578d3Smrg
199932b578d3Smrg    /*
200032b578d3Smrg     * Remap apertures.  Must lock and re-unlock around this in case the
200132b578d3Smrg     * remapping fails.
200232b578d3Smrg     */
200332b578d3Smrg    ATILock(pATI);
200432b578d3Smrg    ATIUnmapApertures(pScreenInfo->scrnIndex, pATI);
200532b578d3Smrg    if (!ATIMapApertures(pScreenInfo->scrnIndex, pATI))
200632b578d3Smrg        return FALSE;
200732b578d3Smrg
200832b578d3Smrg    ATIUnlock(pATI);
200932b578d3Smrg
201032b578d3Smrg    if (pATI->OptionAccel)
201132b578d3Smrg    {
201232b578d3Smrg            xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO,
201332b578d3Smrg                "MMIO write caching %sabled.\n",
201432b578d3Smrg                pATI->OptionMMIOCache ? "en" : "dis");
201532b578d3Smrg    }
201632b578d3Smrg
201732b578d3Smrg    {
201832b578d3Smrg        if (pATI->Chip >= ATI_CHIP_264CT)
201932b578d3Smrg            ATIReportMemory(pScreenInfo, pATI,
202032b578d3Smrg                ATIMemoryTypeNames_264xT[pATI->MemoryType]);
202132b578d3Smrg        else if (pATI->Chip == ATI_CHIP_88800CX)
202232b578d3Smrg            ATIReportMemory(pScreenInfo, pATI,
202332b578d3Smrg                ATIMemoryTypeNames_88800CX[pATI->MemoryType]);
202432b578d3Smrg        else
202532b578d3Smrg            ATIReportMemory(pScreenInfo, pATI,
202632b578d3Smrg                ATIMemoryTypeNames_Mach[pATI->MemoryType]);
202732b578d3Smrg    }
202832b578d3Smrg
202932b578d3Smrg    /*
203032b578d3Smrg     * Finish banking setup.  This needs to be fixed to not assume the mode on
203132b578d3Smrg     * entry is a VGA mode.  XXX
203232b578d3Smrg     */
203332b578d3Smrg
203432b578d3Smrg#ifndef AVOID_CPIO
203532b578d3Smrg
203632b578d3Smrg    if (!pATI->VGAAdapter)
203732b578d3Smrg    {
203832b578d3Smrg        pATI->NewHW.SetBank = ATIx8800SetBank;
203932b578d3Smrg        pATI->NewHW.nPlane = 0;
204032b578d3Smrg
204132b578d3Smrg        pATIHW->crtc = pATI->NewHW.crtc;
204232b578d3Smrg
204332b578d3Smrg        pATIHW->SetBank = (ATIBankProcPtr)NoopDDA;
204432b578d3Smrg    }
204532b578d3Smrg    else
204632b578d3Smrg    {
204732b578d3Smrg        Bool ext_disp_en = (pATI->LockData.crtc_gen_cntl & CRTC_EXT_DISP_EN);
204832b578d3Smrg        Bool vga_ap_en = (pATI->LockData.config_cntl & CFG_MEM_VGA_AP_EN);
204932b578d3Smrg        Bool vga_color_256 = (GetReg(SEQX, 0x04U) & 0x08U);
205032b578d3Smrg
205132b578d3Smrg        pATI->NewHW.SetBank = ATIMach64SetBankPacked;
205232b578d3Smrg        pATI->NewHW.nPlane = 1;
205332b578d3Smrg
205432b578d3Smrg        pATIHW->crtc = ATI_CRTC_VGA;
205532b578d3Smrg
205632b578d3Smrg        if (ext_disp_en)
205732b578d3Smrg            pATIHW->crtc = ATI_CRTC_MACH64;
205832b578d3Smrg
205932b578d3Smrg        if ((pATIHW->crtc != ATI_CRTC_VGA) || vga_color_256)
206032b578d3Smrg            pATIHW->nPlane = 1;
206132b578d3Smrg        else
206232b578d3Smrg            pATIHW->nPlane = 4;
206332b578d3Smrg
206432b578d3Smrg        /* VideoRAM is a multiple of 512kB and BankSize is 64kB */
206532b578d3Smrg        pATIHW->nBank = pATI->VideoRAM / (pATIHW->nPlane * 0x40U);
206632b578d3Smrg
206732b578d3Smrg        if ((pATIHW->crtc == ATI_CRTC_VGA) && !vga_ap_en)
206832b578d3Smrg        {
206932b578d3Smrg            pATIHW->SetBank = (ATIBankProcPtr)NoopDDA;
207032b578d3Smrg            pATIHW->nBank = 1;
207132b578d3Smrg        }
207232b578d3Smrg        else if (pATIHW->nPlane == 1)
207332b578d3Smrg        {
207432b578d3Smrg            pATIHW->SetBank = ATIMach64SetBankPacked;
207532b578d3Smrg        }
207632b578d3Smrg        else
207732b578d3Smrg        {
207832b578d3Smrg            pATIHW->SetBank = ATIMach64SetBankPlanar;
207932b578d3Smrg        }
208032b578d3Smrg    }
208132b578d3Smrg
208232b578d3Smrg#else /* AVOID_CPIO */
208332b578d3Smrg
208432b578d3Smrg    {
208532b578d3Smrg        pATIHW->crtc = pATI->NewHW.crtc;
208632b578d3Smrg    }
208732b578d3Smrg
208832b578d3Smrg#endif /* AVOID_CPIO */
208932b578d3Smrg
209032b578d3Smrg    if (pATI->OptionShadowFB)
209132b578d3Smrg    {
209232b578d3Smrg        /* Until ShadowFB becomes a true screen wrapper, if it ever does... */
209332b578d3Smrg
209432b578d3Smrg        if (pATI->OptionAccel)
209532b578d3Smrg        {
209632b578d3Smrg            xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING,
209732b578d3Smrg                "Cannot shadow an accelerated frame buffer.\n");
209832b578d3Smrg            pATI->OptionShadowFB = FALSE;
209932b578d3Smrg        }
210032b578d3Smrg        else
210132b578d3Smrg        {
210232b578d3Smrg            xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO,
210332b578d3Smrg                "Using shadow frame buffer.\n");
210432b578d3Smrg        }
210532b578d3Smrg    }
210632b578d3Smrg
210732b578d3Smrg    /* 264VT-B's and later have DSP registers */
210832b578d3Smrg    if ((pATI->Chip >= ATI_CHIP_264VTB) &&
210932b578d3Smrg        !ATIDSPPreInit(pScreenInfo->scrnIndex, pATI))
211032b578d3Smrg        goto bail;
211132b578d3Smrg
211232b578d3Smrg    /*
211332b578d3Smrg     * Determine minClock and maxClock.  For adapters with supported
211432b578d3Smrg     * programmable clock generators, start with an absolute maximum.
211532b578d3Smrg     */
211632b578d3Smrg    if (pATI->ClockDescriptor.MaxN > 0)
211732b578d3Smrg    {
211832b578d3Smrg        Numerator = pATI->ClockDescriptor.MaxN * pATI->ReferenceNumerator;
211932b578d3Smrg        Denominator = pATI->ClockDescriptor.MinM * pATI->ReferenceDenominator *
212032b578d3Smrg            pATI->ClockDescriptor.PostDividers[0];
212132b578d3Smrg
212232b578d3Smrg        /*
212332b578d3Smrg         * An integrated PLL behaves as though the reference frequency were
212432b578d3Smrg         * doubled.  It also does not appear to care about the colour depth.
212532b578d3Smrg         */
212632b578d3Smrg        if (pATI->ProgrammableClock == ATI_CLOCK_INTERNAL)
212732b578d3Smrg            Numerator <<= 1;
212832b578d3Smrg
212932b578d3Smrg        ATIClockRange.maxClock = (Numerator / (Denominator * 1000)) * 1000;
213032b578d3Smrg
213132b578d3Smrg        Numerator = pATI->ClockDescriptor.MinN * pATI->ReferenceNumerator;
213232b578d3Smrg        Denominator = pATI->ClockDescriptor.MaxM * pATI->ReferenceDenominator *
213332b578d3Smrg            pATI->ClockDescriptor.PostDividers[pATI->ClockDescriptor.NumD - 1];
213432b578d3Smrg
213532b578d3Smrg        if (pATI->ProgrammableClock == ATI_CLOCK_INTERNAL)
213632b578d3Smrg            Numerator <<= 1;
213732b578d3Smrg
213832b578d3Smrg        ATIClockRange.minClock = (Numerator / (Denominator * 1000)) * 1000;
213932b578d3Smrg
214032b578d3Smrg        if (pATI->XCLKFeedbackDivider)
214132b578d3Smrg        {
214232b578d3Smrg            /* Possibly reduce maxClock due to memory bandwidth */
214332b578d3Smrg            Numerator = pATI->XCLKFeedbackDivider * 2 *
214432b578d3Smrg                pATI->ReferenceNumerator;
214532b578d3Smrg            Denominator = pATI->ClockDescriptor.MinM *
214632b578d3Smrg                pATI->XCLKReferenceDivider * pATI->ReferenceDenominator;
214732b578d3Smrg
214832b578d3Smrg            {
214932b578d3Smrg                Denominator *= pATI->bitsPerPixel / 4;
215032b578d3Smrg            }
215132b578d3Smrg
215232b578d3Smrg            i = (6 - 2) - pATI->XCLKPostDivider;
215332b578d3Smrg
215432b578d3Smrg            i = (ATIDivide(Numerator, Denominator, i, -1) / 1000) * 1000;
215532b578d3Smrg            if (i < ATIClockRange.maxClock)
215632b578d3Smrg                ATIClockRange.maxClock = i;
215732b578d3Smrg        }
215832b578d3Smrg    }
215932b578d3Smrg
216032b578d3Smrg    /*
216132b578d3Smrg     * Assume an internal DAC can handle whatever frequency the internal PLL
216232b578d3Smrg     * can produce (with the reference divider set by BIOS initialisation), but
216332b578d3Smrg     * default maxClock to a lower chip-specific default.
216432b578d3Smrg     */
216532b578d3Smrg    if ((pATI->DAC & ~0x0FU) == ATI_DAC_INTERNAL)
216632b578d3Smrg    {
216732b578d3Smrg        int DacSpeed;
216832b578d3Smrg        switch (pATI->bitsPerPixel)
216932b578d3Smrg        {
217032b578d3Smrg            case 15:
217132b578d3Smrg            case 16:
217232b578d3Smrg                DacSpeed = pGDev->dacSpeeds[DAC_BPP16];
217332b578d3Smrg                break;
217432b578d3Smrg
217532b578d3Smrg            case 24:
217632b578d3Smrg                DacSpeed = pGDev->dacSpeeds[DAC_BPP24];
217732b578d3Smrg                break;
217832b578d3Smrg
217932b578d3Smrg            case 32:
218032b578d3Smrg                DacSpeed = pGDev->dacSpeeds[DAC_BPP32];
218132b578d3Smrg                break;
218232b578d3Smrg
218332b578d3Smrg            default:
218432b578d3Smrg                DacSpeed = 0;
218532b578d3Smrg                break;
218632b578d3Smrg        }
218732b578d3Smrg        if (!DacSpeed)
218832b578d3Smrg            DacSpeed = pGDev->dacSpeeds[DAC_BPP8];
218932b578d3Smrg        if (DacSpeed < ATIClockRange.maxClock)
219032b578d3Smrg        {
219132b578d3Smrg            DefaultmaxClock = 135000;
219232b578d3Smrg
219332b578d3Smrg            if (pATI->depth > 8)
219432b578d3Smrg                DefaultmaxClock = 80000;
219532b578d3Smrg
219632b578d3Smrg            if ((pATI->Chip >= ATI_CHIP_264VTB) &&
219732b578d3Smrg                (pATI->Chip != ATI_CHIP_Mach64))
219832b578d3Smrg            {
219932b578d3Smrg                if ((pATI->Chip >= ATI_CHIP_264VT4) &&
220032b578d3Smrg                    (pATI->Chip != ATI_CHIP_264LTPRO))
220132b578d3Smrg                    DefaultmaxClock = 230000;
220232b578d3Smrg                else if (pATI->Chip >= ATI_CHIP_264VT3)
220332b578d3Smrg                    DefaultmaxClock = 200000;
220432b578d3Smrg                else
220532b578d3Smrg                    DefaultmaxClock = 170000;
220632b578d3Smrg            }
220732b578d3Smrg            if (DacSpeed > DefaultmaxClock)
220832b578d3Smrg                ATIClockRange.maxClock = DacSpeed;
220932b578d3Smrg            else if (DefaultmaxClock < ATIClockRange.maxClock)
221032b578d3Smrg                ATIClockRange.maxClock = DefaultmaxClock;
221132b578d3Smrg        }
221232b578d3Smrg    }
221332b578d3Smrg    else
221432b578d3Smrg    {
221532b578d3Smrg        switch(pATI->DAC)
221632b578d3Smrg        {
221732b578d3Smrg            case ATI_DAC_STG1700:
221832b578d3Smrg            case ATI_DAC_STG1702:
221932b578d3Smrg            case ATI_DAC_STG1703:
222032b578d3Smrg                DefaultmaxClock = 110000;
222132b578d3Smrg                break;
222232b578d3Smrg
222332b578d3Smrg            case ATI_DAC_IBMRGB514:
222432b578d3Smrg                pATI->maxClock = 220000;
222532b578d3Smrg                {
222632b578d3Smrg                    DefaultmaxClock = 220000;
222732b578d3Smrg                }
222832b578d3Smrg                break;
222932b578d3Smrg
223032b578d3Smrg            default:
223132b578d3Smrg
223232b578d3Smrg#ifndef AVOID_CPIO
223332b578d3Smrg
223432b578d3Smrg                if (pATI->CPIO_VGAWonder && (pATI->VideoRAM < 1024))
223532b578d3Smrg                {
223632b578d3Smrg                    DefaultmaxClock =
223732b578d3Smrg                        (GetBits(BIOSByte(0x44U), 0x04U) * 5000) + 40000;
223832b578d3Smrg                }
223932b578d3Smrg                else
224032b578d3Smrg
224132b578d3Smrg#endif /* AVOID_CPIO */
224232b578d3Smrg
224332b578d3Smrg                {
224432b578d3Smrg                    DefaultmaxClock = 80000;
224532b578d3Smrg                }
224632b578d3Smrg
224732b578d3Smrg                break;
224832b578d3Smrg        }
224932b578d3Smrg
225032b578d3Smrg        if (DefaultmaxClock < ATIClockRange.maxClock)
225132b578d3Smrg            ATIClockRange.maxClock = DefaultmaxClock;
225232b578d3Smrg    }
225332b578d3Smrg
225432b578d3Smrg    /*
225532b578d3Smrg     * Determine available pixel clock frequencies.
225632b578d3Smrg     */
225732b578d3Smrg
225832b578d3Smrg    if ((pATI->ProgrammableClock <= ATI_CLOCK_FIXED) ||
225932b578d3Smrg        (pATI->ProgrammableClock >= ATI_CLOCK_MAX))
226032b578d3Smrg    {
226132b578d3Smrg        xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR,
226232b578d3Smrg            "Unsupported or non-programmable clock generator.\n");
226332b578d3Smrg        goto bail;
226432b578d3Smrg    }
226532b578d3Smrg
226632b578d3Smrg    ATIClockPreInit(pScreenInfo, pATI);
226732b578d3Smrg    Strategy = LOOKUP_BEST_REFRESH;
226832b578d3Smrg
226932b578d3Smrg    /*
227032b578d3Smrg     * Mode validation.
227132b578d3Smrg     */
227232b578d3Smrg
227332b578d3Smrg    if (pATI->Chip >= ATI_CHIP_264CT)
227432b578d3Smrg    {
227532b578d3Smrg        minPitch = 8;
227632b578d3Smrg    }
227732b578d3Smrg    else
227832b578d3Smrg    {
227932b578d3Smrg        minPitch = 16;
228032b578d3Smrg    }
228132b578d3Smrg
228232b578d3Smrg    pitchInc = minPitch * pATI->bitsPerPixel;
228332b578d3Smrg
228432b578d3Smrg    if (pATI->Chip < ATI_CHIP_264VT)
228532b578d3Smrg    {
228632b578d3Smrg        /*
228732b578d3Smrg         * ATI finally fixed accelerated doublescanning in the 264VT
228832b578d3Smrg         * and later.  On 88800's, the bit is documented to exist, but
228932b578d3Smrg         * only doubles the vertical timings.  On the 264CT and 264ET,
229032b578d3Smrg         * the bit is ignored.
229132b578d3Smrg         */
229232b578d3Smrg        ATIClockRange.doubleScanAllowed = FALSE;
2293d2b10af6Smrg
229432b578d3Smrg    }
229532b578d3Smrg
229632b578d3Smrg    maxPitch = minPitch * MaxBits(CRTC_PITCH);
229732b578d3Smrg
229832b578d3Smrg    if (pATI->OptionAccel)
229932b578d3Smrg    {
230032b578d3Smrg        /*
230132b578d3Smrg         * Set engine restrictions on coordinate space.  Use maxPitch for the
230232b578d3Smrg         * horizontal and maxHeight for the vertical.
230332b578d3Smrg         */
230432b578d3Smrg        if (maxPitch > (ATIMach64MaxX / pATI->XModifier))
230532b578d3Smrg            maxPitch = ATIMach64MaxX / pATI->XModifier;
230632b578d3Smrg
230732b578d3Smrg        maxHeight = ATIMach64MaxY;
230832b578d3Smrg
230932b578d3Smrg        /*
231032b578d3Smrg         * For SGRAM & WRAM adapters, the display engine limits the pitch to
231132b578d3Smrg         * multiples of 64 bytes.
231232b578d3Smrg         */
231332b578d3Smrg        if ((pATI->Chip >= ATI_CHIP_264CT) &&
231432b578d3Smrg            ((pATI->Chip >= ATI_CHIP_264VTB) ||
231532b578d3Smrg             (pATI->MemoryType >= MEM_264_SGRAM)))
231632b578d3Smrg            pitchInc = pATI->XModifier * (64 * 8);
231732b578d3Smrg    }
231832b578d3Smrg
231932b578d3Smrg    if (pATI->OptionPanelDisplay && (pATI->LCDPanelID >= 0))
232032b578d3Smrg    {
232132b578d3Smrg        /*
232232b578d3Smrg         * Given LCD modes are more tightly controlled than CRT modes, allow
232332b578d3Smrg         * the user the option of not specifying a panel's horizontal sync
232432b578d3Smrg         * and/or vertical refresh tolerances.
232532b578d3Smrg         */
232632b578d3Smrg        Strategy |= LOOKUP_OPTIONAL_TOLERANCES;
232732b578d3Smrg
232832b578d3Smrg        if (ModeType == M_T_BUILTIN)
232932b578d3Smrg        {
233032b578d3Smrg            /*
233132b578d3Smrg             * Add a mode to the end of the monitor's list for the panel's
233232b578d3Smrg             * native resolution.
233332b578d3Smrg             */
233432b578d3Smrg            pMode = (DisplayModePtr)xnfcalloc(1, SizeOf(DisplayModeRec));
233532b578d3Smrg            pMode->name = "Native panel mode";
233632b578d3Smrg            pMode->type = M_T_BUILTIN;
233732b578d3Smrg            pMode->Clock = pATI->LCDClock;
233832b578d3Smrg            pMode->HDisplay = pATI->LCDHorizontal;
233932b578d3Smrg            pMode->VDisplay = pATI->LCDVertical;
234032b578d3Smrg
234132b578d3Smrg            /*
234232b578d3Smrg             * These timings are bogus, but enough to survive sync tolerance
234332b578d3Smrg             * checks.
234432b578d3Smrg             */
234532b578d3Smrg            pMode->HSyncStart = pMode->HDisplay;
234632b578d3Smrg            pMode->HSyncEnd = pMode->HSyncStart + minPitch;
234732b578d3Smrg            pMode->HTotal = pMode->HSyncEnd + minPitch;
234832b578d3Smrg            pMode->VSyncStart = pMode->VDisplay;
234932b578d3Smrg            pMode->VSyncEnd = pMode->VSyncStart + 1;
235032b578d3Smrg            pMode->VTotal = pMode->VSyncEnd + 1;
235132b578d3Smrg
235232b578d3Smrg            pMode->CrtcHDisplay = pMode->HDisplay;
235332b578d3Smrg            pMode->CrtcHBlankStart = pMode->HDisplay;
235432b578d3Smrg            pMode->CrtcHSyncStart = pMode->HSyncStart;
235532b578d3Smrg            pMode->CrtcHSyncEnd = pMode->HSyncEnd;
235632b578d3Smrg            pMode->CrtcHBlankEnd = pMode->HTotal;
235732b578d3Smrg            pMode->CrtcHTotal = pMode->HTotal;
235832b578d3Smrg
235932b578d3Smrg            pMode->CrtcVDisplay = pMode->VDisplay;
236032b578d3Smrg            pMode->CrtcVBlankStart = pMode->VDisplay;
236132b578d3Smrg            pMode->CrtcVSyncStart = pMode->VSyncStart;
236232b578d3Smrg            pMode->CrtcVSyncEnd = pMode->VSyncEnd;
236332b578d3Smrg            pMode->CrtcVBlankEnd = pMode->VTotal;
236432b578d3Smrg            pMode->CrtcVTotal = pMode->VTotal;
236532b578d3Smrg
236632b578d3Smrg            if (!pScreenInfo->monitor->Modes)
236732b578d3Smrg            {
236832b578d3Smrg                pScreenInfo->monitor->Modes = pMode;
236932b578d3Smrg            }
237032b578d3Smrg            else
237132b578d3Smrg            {
237232b578d3Smrg                pScreenInfo->monitor->Last->next = pMode;
237332b578d3Smrg                pMode->prev = pScreenInfo->monitor->Last;
237432b578d3Smrg            }
237532b578d3Smrg
237632b578d3Smrg            pScreenInfo->monitor->Last = pMode;
237732b578d3Smrg        }
237832b578d3Smrg
237932b578d3Smrg        /*
238032b578d3Smrg         * Defeat Xconfigurator brain damage.  Ignore all HorizSync and
238132b578d3Smrg         * VertRefresh specifications.  For now, this does not take
238232b578d3Smrg         * SYNC_TOLERANCE into account.
238332b578d3Smrg         */
238432b578d3Smrg        if (pScreenInfo->monitor->nHsync > 0)
238532b578d3Smrg        {
238632b578d3Smrg            double hsync = (double)pATI->LCDClock /
238732b578d3Smrg                           (pATI->LCDHorizontal + pATI->LCDHBlankWidth);
238832b578d3Smrg
238932b578d3Smrg            for (i = 0;  ;  i++)
239032b578d3Smrg            {
239132b578d3Smrg                if (i >= pScreenInfo->monitor->nHsync)
239232b578d3Smrg                {
239332b578d3Smrg                    xf86DrvMsg(pScreenInfo->scrnIndex, X_NOTICE,
239432b578d3Smrg                        "Conflicting XF86Config HorizSync specification(s)"
239532b578d3Smrg                        " ignored.\n");
239632b578d3Smrg                    break;
239732b578d3Smrg                }
239832b578d3Smrg
239932b578d3Smrg                if ((hsync >= pScreenInfo->monitor->hsync[i].lo) &&
240032b578d3Smrg                    (hsync <= pScreenInfo->monitor->hsync[i].hi))
240132b578d3Smrg                {
240232b578d3Smrg                    xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING,
240332b578d3Smrg                        "Extraneous XF86Config HorizSync specification(s)"
240432b578d3Smrg                        " ignored.\n");
240532b578d3Smrg                    break;
240632b578d3Smrg                }
240732b578d3Smrg            }
240832b578d3Smrg
240932b578d3Smrg            pScreenInfo->monitor->nHsync = 0;
241032b578d3Smrg        }
241132b578d3Smrg
241232b578d3Smrg        if (pScreenInfo->monitor->nVrefresh > 0)
241332b578d3Smrg        {
241432b578d3Smrg            double vrefresh = ((double)pATI->LCDClock * 1000.0) /
241532b578d3Smrg                              ((pATI->LCDHorizontal + pATI->LCDHBlankWidth) *
241632b578d3Smrg                               (pATI->LCDVertical + pATI->LCDVBlankWidth));
241732b578d3Smrg
241832b578d3Smrg            for (i = 0;  ;  i++)
241932b578d3Smrg            {
242032b578d3Smrg                if (i >= pScreenInfo->monitor->nVrefresh)
242132b578d3Smrg                {
242232b578d3Smrg                    xf86DrvMsg(pScreenInfo->scrnIndex, X_NOTICE,
242332b578d3Smrg                        "Conflicting XF86Config VertRefresh specification(s)"
242432b578d3Smrg                        " ignored.\n");
242532b578d3Smrg                    break;
242632b578d3Smrg                }
242732b578d3Smrg
242832b578d3Smrg                if ((vrefresh >= pScreenInfo->monitor->vrefresh[i].lo) &&
242932b578d3Smrg                    (vrefresh <= pScreenInfo->monitor->vrefresh[i].hi))
243032b578d3Smrg                {
243132b578d3Smrg                    xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING,
243232b578d3Smrg                        "Extraneous XF86Config VertRefresh specification(s)"
243332b578d3Smrg                        " ignored.\n");
243432b578d3Smrg                    break;
243532b578d3Smrg                }
243632b578d3Smrg            }
243732b578d3Smrg
243832b578d3Smrg            pScreenInfo->monitor->nVrefresh = 0;
243932b578d3Smrg        }
244032b578d3Smrg    }
244132b578d3Smrg
244232b578d3Smrg    i = xf86ValidateModes(pScreenInfo,
244332b578d3Smrg            pScreenInfo->monitor->Modes, pScreenInfo->display->modes,
244432b578d3Smrg            &ATIClockRange, NULL, minPitch, maxPitch,
244532b578d3Smrg            pitchInc, 0, maxHeight,
244632b578d3Smrg            pScreenInfo->display->virtualX, pScreenInfo->display->virtualY,
244732b578d3Smrg            ApertureSize, Strategy);
244832b578d3Smrg    if (i <= 0)
244932b578d3Smrg        goto bail;
245032b578d3Smrg
245132b578d3Smrg    /* Remove invalid modes */
245232b578d3Smrg    xf86PruneDriverModes(pScreenInfo);
245332b578d3Smrg
245432b578d3Smrg    /* Set current mode to the first in the list */
245532b578d3Smrg    pScreenInfo->currentMode = pScreenInfo->modes;
245632b578d3Smrg
245732b578d3Smrg    /* Print mode list */
245832b578d3Smrg    xf86PrintModes(pScreenInfo);
245932b578d3Smrg
246032b578d3Smrg    /* Set display resolution */
246132b578d3Smrg    xf86SetDpi(pScreenInfo, 0, 0);
246232b578d3Smrg
246332b578d3Smrg    /* Load required modules */
246432b578d3Smrg    if (!ATILoadModules(pScreenInfo, pATI))
246532b578d3Smrg        goto bail;
246632b578d3Smrg
246732b578d3Smrg    pATI->displayWidth = pScreenInfo->displayWidth;
246832b578d3Smrg
246932b578d3Smrg    /* Initialise for panning */
247032b578d3Smrg    ATIAdjustPreInit(pATI);
247132b578d3Smrg
247232b578d3Smrg    /*
247332b578d3Smrg     * Warn about modes that are too small, or not aligned, to scroll to the
247432b578d3Smrg     * bottom right corner of the virtual screen.
247532b578d3Smrg     */
247632b578d3Smrg    MinX = pScreenInfo->virtualX - pATI->AdjustMaxX;
247732b578d3Smrg    MinY = pScreenInfo->virtualY - pATI->AdjustMaxY;
247832b578d3Smrg
247932b578d3Smrg    pMode = pScreenInfo->modes;
248032b578d3Smrg    do
248132b578d3Smrg    {
248232b578d3Smrg        if ((pMode->VDisplay <= MinY) &&
248332b578d3Smrg            ((pMode->VDisplay < MinY) || (pMode->HDisplay < MinX)))
248432b578d3Smrg            xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING,
248532b578d3Smrg                "Mode \"%s\" too small to scroll to bottom right corner of"
248632b578d3Smrg                " virtual resolution.\n", pMode->name);
248732b578d3Smrg        else if ((pMode->HDisplay & ~pATI->AdjustMask) / pScreenInfo->xInc)
248832b578d3Smrg            xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING,
248932b578d3Smrg                "Mode \"%s\" cannot scroll to bottom right corner of virtual"
249032b578d3Smrg                " resolution.\n Horizontal dimension not a multiple of %ld.\n",
249132b578d3Smrg                pMode->name, ~pATI->AdjustMask + 1);
249232b578d3Smrg    } while ((pMode = pMode->next) != pScreenInfo->modes);
249332b578d3Smrg
249432b578d3Smrg    /* Initialise XVideo extension support */
249532b578d3Smrg    ATIXVPreInit(pATI);
249632b578d3Smrg
249732b578d3Smrg    /* Initialise CRTC code */
249832b578d3Smrg    ATIModePreInit(pScreenInfo, pATI, &pATI->NewHW);
249932b578d3Smrg
250032b578d3Smrg    /* Set up for I2C */
250132b578d3Smrg    ATII2CPreInit(pScreenInfo, pATI);
250232b578d3Smrg
250332b578d3Smrg    if (!pScreenInfo->chipset || !*pScreenInfo->chipset)
250432b578d3Smrg        pScreenInfo->chipset = "mach64";
250532b578d3Smrg
250632b578d3Smrg    PreInitSuccess = TRUE;
250732b578d3Smrg
250832b578d3Smrgbail:
250932b578d3Smrg    ATILock(pATI);
251032b578d3Smrg
251132b578d3Smrgbail_locked:
251232b578d3Smrg    ATIPrintNoiseIfRequested(pATI, BIOS, BIOSSize);
251332b578d3Smrg    ATIUnmapApertures(pScreenInfo->scrnIndex, pATI);
251432b578d3Smrg
251532b578d3Smrg    return PreInitSuccess;
251632b578d3Smrg}
2517