gx_driver.c revision c744f008
141687f09Smrg/* Copyright (c) 2003-2006 Advanced Micro Devices, Inc.
241687f09Smrg *
341687f09Smrg * Portioned modeled from xf86-video-intel/src/i830_driver.c
441687f09Smrg * Copyright 2001 VA Linux Systems Inc., Fremont, California.
541687f09Smrg * Copyright \ufffd 2002 by David Dawes
641687f09Smrg
741687f09Smrg * Permission is hereby granted, free of charge, to any person obtaining a copy
841687f09Smrg * of this software and associated documentation files (the "Software"), to
941687f09Smrg * deal in the Software without restriction, including without limitation the
1041687f09Smrg * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
1141687f09Smrg * sell copies of the Software, and to permit persons to whom the Software is
1241687f09Smrg * furnished to do so, subject to the following conditions:
1341687f09Smrg *
1441687f09Smrg * The above copyright notice and this permission notice shall be included in
1541687f09Smrg * all copies or substantial portions of the Software.
1641687f09Smrg *
1741687f09Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1841687f09Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1941687f09Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2041687f09Smrg * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2141687f09Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2241687f09Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
2341687f09Smrg * IN THE SOFTWARE.
2441687f09Smrg *
2541687f09Smrg * Neither the name of the Advanced Micro Devices, Inc. nor the names of its
2641687f09Smrg * contributors may be used to endorse or promote products derived from this
2741687f09Smrg * software without specific prior written permission.
2841687f09Smrg */
2941687f09Smrg
3041687f09Smrg#ifdef HAVE_CONFIG_H
3141687f09Smrg#include "config.h"
3241687f09Smrg#endif
3341687f09Smrg
3441687f09Smrg#include <stdio.h>
3541687f09Smrg#include <fcntl.h>
3641687f09Smrg#include <unistd.h>
3741687f09Smrg#include <sys/mman.h>
3841687f09Smrg
3941687f09Smrg#include "xorg-server.h"
4041687f09Smrg
4141687f09Smrg#include "xf86.h"
4241687f09Smrg#include "xf86_OSproc.h"
4341687f09Smrg#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 6
4441687f09Smrg#include "xf86Resources.h"
4541687f09Smrg#endif
4641687f09Smrg#include "xf86cmap.h"
4741687f09Smrg#include "compiler.h"
4841687f09Smrg#include "mipointer.h"
4941687f09Smrg#include "shadow.h"
5041687f09Smrg#include <X11/extensions/randr.h>
5141687f09Smrg#include "fb.h"
5241687f09Smrg#include "miscstruct.h"
5341687f09Smrg#include "micmap.h"
5441687f09Smrg#include "vbe.h"
5541687f09Smrg#include "fb.h"
5641687f09Smrg#include "randrstr.h"
5741687f09Smrg
5841687f09Smrg#include "geode.h"
5941687f09Smrg#include "gfx_defs.h"
6041687f09Smrg#include "gfx_regs.h"
6141687f09Smrg#include "panel.h"
6241687f09Smrg
6341687f09Smrg/* Bring in VGA functions */
6441687f09Smrg#include "gx_vga.c"
6541687f09Smrg
6641687f09Smrg#define GX_MIN_PITCH 1024
6741687f09Smrg#define GX_MAX_PITCH 8192
6841687f09Smrg#define GX_MAX_WIDTH  1600
6941687f09Smrg#define GX_MIN_HEIGHT  400
7041687f09Smrg#define GX_MAX_HEIGHT 1200
7141687f09Smrg#define GX_CB_PITCH   544
7241687f09Smrg#define GX_CB_SIZE    544
7341687f09Smrg
7441687f09Smrg#define GX_CPU_REG_SIZE 0x4000
7541687f09Smrg#define GX_GP_REG_SIZE  0x4000
7641687f09Smrg#define GX_VID_REG_SIZE 0x4000
7741687f09Smrg
7841687f09Smrg#define DEFAULT_IMG_LINE_BUFS 20
7941687f09Smrg#define DEFAULT_CLR_LINE_BUFS 20
8041687f09Smrg
8141687f09Smrgextern OptionInfoRec GX_GeodeOptions[];
8241687f09Smrg
8341687f09Smrgextern unsigned char *XpressROMPtr;
8441687f09Smrg
8541687f09Smrgstatic inline void
8641687f09Smrggx_enable_dac_power(void)
8741687f09Smrg{
8841687f09Smrg    gfx_write_vid32(RCDF_VID_MISC,
8941687f09Smrg                    gfx_read_vid32(RCDF_VID_MISC) & RCDF_GAMMA_BYPASS_BOTH);
9041687f09Smrg}
9141687f09Smrg
9241687f09Smrgstatic inline void
9341687f09Smrggx_disable_dac_power(void)
9441687f09Smrg{
9541687f09Smrg    gfx_write_vid32(RCDF_VID_MISC,
9641687f09Smrg                    RCDF_DAC_POWER_DOWN | RCDF_ANALOG_POWER_DOWN |
9741687f09Smrg                    (gfx_read_vid32(RCDF_VID_MISC) & RCDF_GAMMA_BYPASS_BOTH));
9841687f09Smrg}
9941687f09Smrg
10041687f09Smrgstatic void
10141687f09SmrgGXInitEXAMemory(ScrnInfoPtr pScrni, unsigned int *offset, unsigned int *avail)
10241687f09Smrg{
10341687f09Smrg    GeodePtr pGeode = GEODEPTR(pScrni);
10441687f09Smrg
10541687f09Smrg    if (pGeode->exaBfrSz > 0 && pGeode->exaBfrSz <= *avail) {
10641687f09Smrg        pGeode->exaBfrOffset = *offset;
10741687f09Smrg        *offset += pGeode->exaBfrOffset;
10841687f09Smrg        *avail -= pGeode->exaBfrOffset;
10941687f09Smrg    }
11041687f09Smrg}
11141687f09Smrg
11241687f09Smrgstatic void
11341687f09SmrgGXInitXAAMemory(ScrnInfoPtr pScrni, unsigned int *offset, unsigned int *avail)
11441687f09Smrg{
11541687f09Smrg    GeodePtr pGeode = GEODEPTR(pScrni);
11641687f09Smrg    unsigned int size, i, pitch;
11741687f09Smrg
11841687f09Smrg    /* XXX - FIXME - What if we are out of room?  Then what? */
11941687f09Smrg    /* For now, we NULL them all out.                        */
12041687f09Smrg
12141687f09Smrg    if (pGeode->NoOfImgBuffers > 0) {
12241687f09Smrg        size = pGeode->displayPitch * pGeode->NoOfImgBuffers;
12341687f09Smrg        if (size <= *avail) {
12441687f09Smrg            for (i = 0; i < pGeode->NoOfImgBuffers; i++) {
12541687f09Smrg                pGeode->AccelImageWriteBuffers[i] = pGeode->FBBase + *offset;
12641687f09Smrg                *offset += pGeode->displayPitch;
12741687f09Smrg                *avail -= pGeode->displayPitch;
12841687f09Smrg            }
12941687f09Smrg        }
13041687f09Smrg        else {
13141687f09Smrg            xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
13241687f09Smrg                       "Not enough memory for image write buffers.\n");
13341687f09Smrg
13441687f09Smrg            for (i = 0; i < pGeode->NoOfImgBuffers; i++)
13541687f09Smrg                pGeode->AccelImageWriteBuffers[i] = NULL;
13641687f09Smrg        }
13741687f09Smrg    }
13841687f09Smrg
13941687f09Smrg    if (pGeode->NoOfColorExpandLines > 0) {
14041687f09Smrg        pitch = ((pGeode->displayPitch + 31) >> 5) << 2;
14141687f09Smrg        size = pitch * pGeode->NoOfColorExpandLines;
14241687f09Smrg
14341687f09Smrg        if (size <= *avail) {
14441687f09Smrg            for (i = 0; i < pGeode->NoOfColorExpandLines; i++) {
14541687f09Smrg                pGeode->AccelColorExpandBuffers[i] = pGeode->FBBase + *offset;
14641687f09Smrg                *offset += pitch;
14741687f09Smrg                *avail -= pitch;
14841687f09Smrg            }
14941687f09Smrg        }
15041687f09Smrg        else {
15141687f09Smrg            xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
15241687f09Smrg                       "Not enough memory for color expansion buffers.\n");
15341687f09Smrg
15441687f09Smrg            for (i = 0; i < pGeode->NoOfImgBuffers; i++)
15541687f09Smrg                pGeode->AccelColorExpandBuffers[i] = NULL;
15641687f09Smrg        }
15741687f09Smrg    }
15841687f09Smrg}
15941687f09Smrg
16041687f09Smrgstatic Bool
16141687f09SmrgGXAllocateMemory(ScreenPtr pScrn, ScrnInfoPtr pScrni, int rotate)
16241687f09Smrg{
16341687f09Smrg    GeodePtr pGeode = GEODEPTR(pScrni);
16441687f09Smrg
16541687f09Smrg    unsigned int fboffset, fbavail;
16641687f09Smrg    unsigned int size;
16741687f09Smrg    unsigned int bytpp = (pScrni->bitsPerPixel + 7) / 8;
16841687f09Smrg    BOOL ret = TRUE;
16941687f09Smrg
17041687f09Smrg    if (pGeode->tryCompression)
17141687f09Smrg        pGeode->displayPitch =
17241687f09Smrg            GeodeCalculatePitchBytes(pScrni->virtualX, pScrni->bitsPerPixel);
17341687f09Smrg    else
17441687f09Smrg        pGeode->displayPitch =
17541687f09Smrg            ((pScrni->virtualX + 3) & ~3) * (pScrni->bitsPerPixel >> 3);
17641687f09Smrg
17741687f09Smrg    pGeode->Pitch = pGeode->displayPitch;
17841687f09Smrg    pGeode->displayWidth = pGeode->displayPitch / bytpp;
17941687f09Smrg    pScrni->displayWidth = pGeode->displayWidth;
18041687f09Smrg
18141687f09Smrg    fbavail = pGeode->FBAvail - 0x4000;
18241687f09Smrg
18341687f09Smrg    pGeode->displayOffset = fboffset = 0;
18441687f09Smrg    pGeode->displaySize = pScrni->virtualY * pGeode->displayPitch;
18541687f09Smrg
18641687f09Smrg    fbavail -= pGeode->displaySize;
18741687f09Smrg    fboffset += pGeode->displaySize;
18841687f09Smrg
18941687f09Smrg    if (pGeode->tryCompression) {
19041687f09Smrg        size = pScrni->virtualY * GX_CB_PITCH;
19141687f09Smrg
19241687f09Smrg        if (size <= fbavail) {
19341687f09Smrg            pGeode->CBData.compression_offset = fboffset;
19441687f09Smrg
19541687f09Smrg            fboffset += size;
19641687f09Smrg            fbavail -= size;
19741687f09Smrg
19841687f09Smrg            pGeode->Compression = TRUE;
19941687f09Smrg        }
20041687f09Smrg        else {
20141687f09Smrg            xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
20241687f09Smrg                       "Not enough memory for compression\n");
20341687f09Smrg            pGeode->Compression = FALSE;
20441687f09Smrg        }
20541687f09Smrg    }
20641687f09Smrg
20741687f09Smrg    if (pGeode->tryHWCursor) {
20841687f09Smrg
20941687f09Smrg        if (fbavail >= 1024) {
21041687f09Smrg            pGeode->CursorStartOffset = fboffset;
21141687f09Smrg            fboffset += 1024;
21241687f09Smrg            fbavail -= 1024;
21341687f09Smrg            pGeode->HWCursor = TRUE;
21441687f09Smrg        }
21541687f09Smrg        else {
21641687f09Smrg            xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
21741687f09Smrg                       "Not enough memory for the hardware cursor\n");
21841687f09Smrg            pGeode->HWCursor = FALSE;
21941687f09Smrg        }
22041687f09Smrg    }
22141687f09Smrg
22241687f09Smrg    if (!pGeode->NoAccel) {
22341687f09Smrg        if (pGeode->useEXA)
22441687f09Smrg            GXInitEXAMemory(pScrni, &fboffset, &fbavail);
22541687f09Smrg        else
22641687f09Smrg            GXInitXAAMemory(pScrni, &fboffset, &fbavail);
22741687f09Smrg    }
22841687f09Smrg
22941687f09Smrg    pGeode->shadowSize = 0;
23041687f09Smrg
23141687f09Smrg    if (rotate != RR_Rotate_0) {
23241687f09Smrg        if (rotate & (RR_Rotate_90 | RR_Rotate_270))
23341687f09Smrg            size = pGeode->displayPitch * pScrni->virtualX;
23441687f09Smrg        else
23541687f09Smrg            size = pGeode->displayPitch * pScrni->virtualY;
23641687f09Smrg
23741687f09Smrg        if (size <= fbavail) {
23841687f09Smrg            pGeode->shadowOffset = fboffset;
23941687f09Smrg            pGeode->shadowSize = size;
24041687f09Smrg
24141687f09Smrg            fboffset += size;
24241687f09Smrg            fbavail -= size;
24341687f09Smrg        }
24441687f09Smrg        else {
24541687f09Smrg            xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
24641687f09Smrg                       "Not enough memory for the shadow framebuffer\n");
24741687f09Smrg            ret = FALSE;
24841687f09Smrg        }
24941687f09Smrg    }
25041687f09Smrg
25141687f09Smrg    /* XAA always exists - we can't remove it on demand like we can with EXA.
25241687f09Smrg     * So we assume the worse, and only give XAA enough offspace room to
25341687f09Smrg     * account for any eventuality that RandR might throw at us. */
25441687f09Smrg
25541687f09Smrg    if (!pGeode->NoAccel) {
25641687f09Smrg
25741687f09Smrg        if (pGeode->useEXA && pGeode->pExa) {
25841687f09Smrg            ExaDriverPtr pExa = pGeode->pExa;
25941687f09Smrg
26041687f09Smrg            pExa->offScreenBase = fboffset;
26141687f09Smrg            pExa->memorySize = fboffset + fbavail;
26241687f09Smrg        }
26341687f09Smrg
26441687f09Smrg        if (!pGeode->useEXA) {
26541687f09Smrg
26641687f09Smrg#if XF86XAA
26741687f09Smrg            if (!xf86FBManagerRunning(pScrn)) {
26841687f09Smrg
26941687f09Smrg                unsigned int offset = fboffset;
27041687f09Smrg                unsigned int avail = fbavail;
27141687f09Smrg                RegionRec OffscreenRegion;
27241687f09Smrg                BoxRec AvailBox;
27341687f09Smrg
27441687f09Smrg                /* Assume the shadow FB exists even if it doesn't */
27541687f09Smrg
27641687f09Smrg                if (pGeode->shadowSize == 0) {
27741687f09Smrg                    size = (pScrn->width * bytpp) * pScrni->virtualX;
27841687f09Smrg                    offset += size;
27941687f09Smrg                    avail -= size;
28041687f09Smrg                }
28141687f09Smrg
28241687f09Smrg                AvailBox.x1 = 0;
28341687f09Smrg                AvailBox.y1 =
28441687f09Smrg                    (offset + pGeode->displayPitch - 1) / pGeode->displayPitch;
28541687f09Smrg
28641687f09Smrg                AvailBox.x2 = pGeode->displayWidth;
28741687f09Smrg                AvailBox.y2 = (offset + avail) / pGeode->displayPitch;
28841687f09Smrg
28941687f09Smrg                if (AvailBox.y1 < AvailBox.y2) {
29041687f09Smrg                    REGION_INIT(pScrn, &OffscreenRegion, &AvailBox, 2);
29141687f09Smrg
29241687f09Smrg                    if (!xf86InitFBManagerRegion(pScrn, &OffscreenRegion))
29341687f09Smrg                        xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
29441687f09Smrg                                   "Memory manager initialization failed.\n");
29541687f09Smrg
29641687f09Smrg                    REGION_UNINIT(pScrn, &OffscreenRegion);
29741687f09Smrg                }
29841687f09Smrg                else
29941687f09Smrg                    xf86DrvMsg(pScrni->scrnIndex, X_INFO,
30041687f09Smrg                               "Cache disabled - no offscreen memory available.\n");
30141687f09Smrg            }
30241687f09Smrg            else
30341687f09Smrg                xf86DrvMsg(pScrni->scrnIndex, X_INFO,
30441687f09Smrg                           "XAA offscreen memory has already been allocated.\n");
30541687f09Smrg#endif
30641687f09Smrg        }
30741687f09Smrg    }
3080ed5401bSmrg    return ret;
30941687f09Smrg}
31041687f09Smrg
31141687f09Smrgstatic Bool
31241687f09SmrgGXSaveScreen(ScreenPtr pScrn, int mode)
31341687f09Smrg{
31441687f09Smrg    ScrnInfoPtr pScrni = xf86ScreenToScrn(pScrn);
31541687f09Smrg    GeodePtr pGeode = GEODEPTR(pScrni);
31641687f09Smrg
31741687f09Smrg    if (pGeode->useVGA && !pScrni->vtSema)
31849ef06a4Smrg        return vgaHWSaveScreen(pScrn, mode);
31941687f09Smrg
32041687f09Smrg    return TRUE;
32141687f09Smrg}
32241687f09Smrg
32341687f09Smrg/* Common function - used by the LX too */
32441687f09Smrg#ifdef XSERVER_LIBPCIACCESS
32541687f09Smrgstatic inline void *
32649ef06a4Smrgmap_pci_mem(ScrnInfoPtr pScrni, int vram,
32741687f09Smrg            struct pci_device *dev, int bar, int size)
32849ef06a4Smrg{
32941687f09Smrg    void *ptr;
33041687f09Smrg    int map_size = size ? size : dev->regions[bar].size;
33141687f09Smrg
33241687f09Smrg    int err = pci_device_map_range(dev,
33341687f09Smrg                                   dev->regions[bar].base_addr,
33441687f09Smrg                                   map_size,
33541687f09Smrg                                   PCI_DEV_MAP_FLAG_WRITABLE |
33641687f09Smrg                                   (vram ? PCI_DEV_MAP_FLAG_WRITE_COMBINE : 0),
33741687f09Smrg                                   &ptr);
33841687f09Smrg
33949ef06a4Smrg    if (err)
34041687f09Smrg        return NULL;
34149ef06a4Smrg    return ptr;
34241687f09Smrg}
34341687f09Smrg
34441687f09Smrgstatic inline int
34541687f09Smrgunmap_pci_mem(ScrnInfoPtr pScrni, struct pci_device *dev, void *ptr, int size)
3460ed5401bSmrg{
34741687f09Smrg    return pci_device_unmap_range(dev, ptr, size);
34841687f09Smrg}
34941687f09Smrg#endif
35041687f09Smrg
35141687f09Smrgextern unsigned long gfx_gx2_scratch_base;
35241687f09Smrg
35341687f09Smrgstatic Bool
35441687f09SmrgGXMapMem(ScrnInfoPtr pScrni)
35541687f09Smrg{
35641687f09Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
35741687f09Smrg    int index = pScrni->scrnIndex;
35841687f09Smrg
35941687f09Smrg    pciVideoPtr pci = xf86GetPciInfoForEntity(pGeode->pEnt->index);
36041687f09Smrg
36141687f09Smrg#ifndef XSERVER_LIBPCIACCESS
36241687f09Smrg    gfx_virt_regptr = (unsigned char *) xf86MapVidMem(index, VIDMEM_MMIO,
36341687f09Smrg                                                      pci->memBase[2],
36441687f09Smrg                                                      pci->size[2]);
36541687f09Smrg
36641687f09Smrg    gfx_virt_gpptr = (unsigned char *) xf86MapVidMem(index, VIDMEM_MMIO,
36741687f09Smrg                                                     pci->memBase[1],
36841687f09Smrg                                                     pci->size[1]);
36941687f09Smrg
37041687f09Smrg    gfx_virt_vidptr = (unsigned char *) xf86MapVidMem(index, VIDMEM_MMIO,
37141687f09Smrg                                                      pci->memBase[3],
37241687f09Smrg                                                      pci->size[3]);
37341687f09Smrg
37441687f09Smrg    gfx_virt_fbptr = (unsigned char *) xf86MapVidMem(index, VIDMEM_FRAMEBUFFER,
37541687f09Smrg                                                     pci->memBase[0],
37641687f09Smrg                                                     pGeode->FBAvail);
37741687f09Smrg#else
37841687f09Smrg    gfx_virt_regptr = map_pci_mem(pScrni, 0, pci, 2, 0);
37941687f09Smrg    gfx_virt_gpptr = map_pci_mem(pScrni, 0, pci, 1, 0);
38041687f09Smrg    gfx_virt_vidptr = map_pci_mem(pScrni, 0, pci, 3, 0);
38141687f09Smrg    gfx_virt_fbptr = map_pci_mem(pScrni, 1, pci, 0, pGeode->FBAvail);
38241687f09Smrg#endif
38341687f09Smrg
38441687f09Smrg    gfx_gx2_scratch_base = pGeode->FBAvail - 0x4000;
38541687f09Smrg
38641687f09Smrg#ifndef XSERVER_LIBPCIACCESS
38741687f09Smrg    XpressROMPtr = xf86MapVidMem(index, VIDMEM_FRAMEBUFFER, 0xF0000, 0x10000);
38841687f09Smrg#else
38941687f09Smrg    {
39041687f09Smrg        int fd = open("/dev/mem", O_RDWR);
39141687f09Smrg        if (fd < 0) {
39241687f09Smrg            xf86DrvMsg(index, X_ERROR, "Failed to open /dev/mem: %m\n");
39341687f09Smrg            return FALSE;
39441687f09Smrg        }
39541687f09Smrg        XpressROMPtr = mmap(NULL, 0x10000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0xF0000);
39641687f09Smrg        close(fd);
39741687f09Smrg    }
39841687f09Smrg#endif
39941687f09Smrg    pGeode->FBBase = gfx_virt_fbptr;
40041687f09Smrg
40141687f09Smrg    if ((!gfx_virt_regptr) || (!gfx_virt_gpptr) ||
40241687f09Smrg        (!gfx_virt_vidptr) || (!gfx_virt_fbptr))
40341687f09Smrg        return FALSE;
40441687f09Smrg
40541687f09Smrg    if (!pGeode->NoAccel && pGeode->useEXA)
40641687f09Smrg        pGeode->pExa->memoryBase = pGeode->FBBase;
40741687f09Smrg
40841687f09Smrg    xf86DrvMsg(index, X_INFO, "Found Geode %x %p\n",
40941687f09Smrg               pGeode->FBAvail, pGeode->FBBase);
41041687f09Smrg
41141687f09Smrg    return TRUE;
41241687f09Smrg}
41341687f09Smrg
41441687f09Smrg/* Check to see if VGA exists - we map the space and look for a
41541687f09Smrg   signature - if it doesn't match exactly, then we assume no VGA.
41641687f09Smrg*/
41741687f09Smrg
41841687f09Smrgstatic Bool
41941687f09SmrgGXCheckVGA(ScrnInfoPtr pScrni, EntityInfoPtr pEnt)
42041687f09Smrg{
42141687f09Smrg#ifndef XSERVER_LIBPCIACCESS
42241687f09Smrg    unsigned char *ptr;
42341687f09Smrg    const char *vgasig = "IBM VGA Compatible";
42441687f09Smrg    int ret;
42541687f09Smrg
42641687f09Smrg    ptr =
42741687f09Smrg        xf86MapVidMem(pScrni->scrnIndex, VIDMEM_FRAMEBUFFER, 0xC001E,
42841687f09Smrg                      strlen(vgasig));
42941687f09Smrg
43041687f09Smrg    if (ptr == NULL)
43141687f09Smrg        return FALSE;
43241687f09Smrg
43341687f09Smrg    ret = memcmp(ptr, vgasig, strlen(vgasig));
43441687f09Smrg    xf86UnMapVidMem(pScrni->scrnIndex, (pointer) ptr, strlen(vgasig));
4354babd585Smrg
4364babd585Smrg    return ret ? FALSE : TRUE;
43741687f09Smrg#else
43841687f09Smrg    pciVideoPtr pci = xf86GetPciInfoForEntity(pEnt->index);
43941687f09Smrg
44041687f09Smrg    return pci_device_is_boot_vga(pci);
44141687f09Smrg#endif
44241687f09Smrg}
44341687f09Smrg
44441687f09Smrgstatic Bool
44541687f09SmrgGXPreInit(ScrnInfoPtr pScrni, int flags)
44641687f09Smrg{
44741687f09Smrg    GeodePtr pGeode;
44841687f09Smrg    ClockRangePtr GeodeClockRange;
44941687f09Smrg    OptionInfoRec *GeodeOptions = &GX_GeodeOptions[0];
45041687f09Smrg    int ret;
45141687f09Smrg    QQ_WORD msrValue;
45241687f09Smrg    EntityInfoPtr pEnt;
45341687f09Smrg    rgb defaultWeight = { 0, 0, 0 };
45441687f09Smrg    int modecnt;
45541687f09Smrg    const char *s, *panelgeo;
45641687f09Smrg    Bool useVGA;
45741687f09Smrg
45841687f09Smrg    if (pScrni->numEntities != 1)
45941687f09Smrg        return FALSE;
46041687f09Smrg
46141687f09Smrg    pEnt = xf86GetEntityInfo(pScrni->entityList[0]);
46241687f09Smrg#ifndef XSERVER_LIBPCIACCESS
46341687f09Smrg    if (pEnt->resources)
46441687f09Smrg        return FALSE;
46541687f09Smrg#endif
46641687f09Smrg
46741687f09Smrg    pGeode = pScrni->driverPrivate = xnfcalloc(1, sizeof(GeodeRec));
46841687f09Smrg
46941687f09Smrg    if (pGeode == NULL)
47041687f09Smrg        return FALSE;
47141687f09Smrg
47241687f09Smrg    useVGA = GXCheckVGA(pScrni, pEnt);
47341687f09Smrg
47441687f09Smrg    if (flags & PROBE_DETECT) {
47541687f09Smrg        GeodeProbeDDC(pScrni, pEnt->index);
47641687f09Smrg        return TRUE;
47741687f09Smrg    }
47841687f09Smrg
47941687f09Smrg    /* Probe for VGA */
48041687f09Smrg    pGeode->useVGA = useVGA;
48141687f09Smrg    pGeode->pEnt = pEnt;
48241687f09Smrg
48341687f09Smrg    if (pGeode->useVGA) {
48441687f09Smrg        if (!xf86LoadSubModule(pScrni, "vgahw") || !vgaHWGetHWRec(pScrni))
48541687f09Smrg            pGeode->useVGA = FALSE;
48641687f09Smrg        else
487            vgaHWSetStdFuncs(VGAHWPTR(pScrni));
488
489#if INT10_SUPPORT
490        pGeode->vesa = calloc(1, sizeof(VESARec));
491#endif
492    }
493
494    gfx_msr_init();
495
496    ret = gfx_msr_read(RC_ID_DF, MBD_MSR_CONFIG, &msrValue);
497
498    if (!ret) {
499        pGeode->Output =
500            ((msrValue.low & RCDF_CONFIG_FMT_MASK) ==
501             RCDF_CONFIG_FMT_FP) ? OUTPUT_PANEL : OUTPUT_CRT;
502    }
503
504    /* Fill in the monitor information */
505    pScrni->monitor = pScrni->confScreen->monitor;
506
507    if (!xf86SetDepthBpp(pScrni, 16, 16, 16, Support24bppFb | Support32bppFb))
508        return FALSE;
509
510    switch (pScrni->depth) {
511    case 8:
512        pScrni->rgbBits = 8;
513    case 16:
514    case 24:
515    case 32:
516        break;
517    default:
518        xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
519                   "The driver does not support %d as a depth.\n",
520                   pScrni->depth);
521        return FALSE;
522    }
523
524    xf86PrintDepthBpp(pScrni);
525
526    if (!xf86SetWeight(pScrni, defaultWeight, defaultWeight))
527        return FALSE;
528
529    if (!xf86SetDefaultVisual(pScrni, -1))
530        return FALSE;
531
532    /*
533     * If the driver can do gamma correction, it should call xf86SetGamma()
534     * here.
535     */
536    {
537        Gamma zeros = { 0.0, 0.0, 0.0 };
538
539        if (!xf86SetGamma(pScrni, zeros)) {
540            return FALSE;
541        }
542    }
543
544    pScrni->progClock = TRUE;
545    xf86CollectOptions(pScrni, NULL);
546    xf86ProcessOptions(pScrni->scrnIndex, pScrni->options, GeodeOptions);
547
548    /* Set up our various options that may get reversed as we go on */
549
550    pGeode->FBVGAActive = FALSE;
551    pGeode->tryHWCursor = TRUE;
552    pGeode->tryCompression = TRUE;
553
554    pGeode->NoAccel = FALSE;
555    pGeode->useEXA = FALSE;
556
557    pGeode->Panel = (pGeode->Output & OUTPUT_PANEL) ? TRUE : FALSE;
558
559    pGeode->NoOfImgBuffers = DEFAULT_IMG_LINE_BUFS;
560    pGeode->NoOfColorExpandLines = DEFAULT_CLR_LINE_BUFS;
561    pGeode->exaBfrSz = DEFAULT_EXA_SCRATCH_BFRSZ;
562
563    xf86GetOptValBool(GeodeOptions, GX_OPTION_HW_CURSOR, &pGeode->tryHWCursor);
564
565    if (!xf86GetOptValInteger(GeodeOptions, GX_OPTION_FBSIZE,
566                              (int *) &(pGeode->FBAvail)))
567        pGeode->FBAvail = 0;
568
569    /* For compatibility - allow SWCursor too */
570
571    if (xf86ReturnOptValBool(GeodeOptions, GX_OPTION_SW_CURSOR, FALSE))
572        pGeode->tryHWCursor = FALSE;
573
574    if (xf86ReturnOptValBool(GeodeOptions, GX_OPTION_NOCOMPRESSION, FALSE))
575        pGeode->tryCompression = FALSE;
576
577    if (xf86ReturnOptValBool(GeodeOptions, GX_OPTION_NOACCEL, FALSE))
578        pGeode->NoAccel = TRUE;
579
580    pGeode->rotation = RR_Rotate_0;
581
582    if ((s = xf86GetOptValString(GeodeOptions, GX_OPTION_ROTATE))) {
583
584        if (!xf86NameCmp(s, "LEFT"))
585            pGeode->rotation = RR_Rotate_90;
586        else if (!xf86NameCmp(s, "INVERT"))
587            pGeode->rotation = RR_Rotate_180;
588        else if (!xf86NameCmp(s, "CCW"))
589            pGeode->rotation = RR_Rotate_270;
590        else
591            xf86DrvMsg(pScrni->scrnIndex, X_ERROR, "Invalid rotation %s.\n", s);
592    }
593
594    xf86GetOptValInteger(GeodeOptions, GX_OPTION_OSM_IMG_BUFS,
595                         &(pGeode->NoOfImgBuffers));
596
597    if (pGeode->NoOfImgBuffers <= 0)
598        pGeode->NoOfImgBuffers = 0;
599
600    xf86GetOptValInteger(GeodeOptions, GX_OPTION_OSM_CLR_BUFS,
601                         &(pGeode->NoOfColorExpandLines));
602
603    if (pGeode->NoOfColorExpandLines <= 0)
604        pGeode->NoOfColorExpandLines = 0;
605
606    xf86GetOptValInteger(GeodeOptions, GX_OPTION_OSM_CLR_BUFS,
607                         (int *) &(pGeode->exaBfrSz));
608
609    if (pGeode->exaBfrSz <= 0)
610        pGeode->exaBfrSz = 0;
611
612    if (pGeode->Panel == TRUE) {
613        if (xf86ReturnOptValBool(GeodeOptions, GX_OPTION_NOPANEL, FALSE))
614            pGeode->Panel = FALSE;
615    }
616
617    panelgeo = xf86GetOptValString(GeodeOptions, GX_OPTION_PANEL_GEOMETRY);
618
619    if ((s = xf86GetOptValString(GeodeOptions, GX_OPTION_ACCEL_METHOD))) {
620#if defined(XF86XAA) && defined(XF86EXA)
621        if (!xf86NameCmp(s, "XAA"))
622            pGeode->useEXA = FALSE;
623        else if (xf86NameCmp(s, "EXA"))
624            xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
625                       "Unknown acceleration method %s.  Defaulting to XAA.\n",
626                       s);
627#elif defined(XF86EXA)
628        pGeode->useEXA = TRUE;
629#else
630        pGeode->useEXA = FALSE;
631#endif
632    }
633
634    xf86DrvMsg(pScrni->scrnIndex, X_INFO,
635               "Using %s acceleration architecture\n",
636               pGeode->useEXA ? "EXA" : "XAA");
637
638    /* Set up the panel */
639
640    if (pGeode->Panel) {
641        if (panelgeo != NULL) {
642            if (GeodeGetFPGeometry(panelgeo, &pGeode->PanelX, &pGeode->PanelY))
643                pGeode->Panel = FALSE;
644        }
645#ifdef PNL_SUP
646        else {
647            int b, f;
648
649            /* The bitdepth and refresh isn't used anywhere else in the driver */
650
651            if ((pGeode->Panel = Pnl_IsPanelEnabledInBIOS()))
652                Pnl_GetPanelInfoFromBIOS(&pGeode->PanelX, &pGeode->PanelY, &b,
653                                         &f);
654        }
655#endif
656    }
657
658    /* Set up the VGA */
659
660    if (pGeode->useVGA) {
661#if INT10_SUPPORT
662        VESARec *pVesa;
663
664        if (!xf86LoadSubModule(pScrni, "int10"))
665            return FALSE;
666
667        pVesa = pGeode->vesa;
668
669        if ((pVesa->pInt = xf86InitInt10(pGeode->pEnt->index)) == NULL) {
670            xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
671                       "Unable to initialize 1NT10 support\n");
672            pGeode->useVGA = FALSE;
673        }
674#endif
675    }
676
677    /* First try to get the framebuffer size from the framebuffer,
678     * and if that fails, revert all  the way back to the legacy
679     * method
680     */
681
682    if (pGeode->FBAvail == 0) {
683        if (GeodeGetSizeFromFB(&pGeode->FBAvail))
684            pGeode->FBAvail = gfx_get_frame_buffer_size();
685    }
686
687    if (pScrni->memPhysBase == 0)
688        pScrni->memPhysBase = gfx_get_frame_buffer_base();
689
690    pScrni->fbOffset = 0;
691
692    if (pGeode->pEnt->device->videoRam == 0)
693        pScrni->videoRam = pGeode->FBAvail / 1024;
694    else
695        pScrni->videoRam = pGeode->pEnt->device->videoRam;
696
697    GeodeClockRange = (ClockRangePtr) xnfcalloc(1, sizeof(ClockRange));
698    GeodeClockRange->next = NULL;
699    GeodeClockRange->minClock = 25175;
700    GeodeClockRange->maxClock = 229500;
701    GeodeClockRange->clockIndex = -1;
702    GeodeClockRange->interlaceAllowed = TRUE;
703    GeodeClockRange->doubleScanAllowed = FALSE;
704
705    pScrni->monitor->DDC = GeodeDoDDC(pScrni, pGeode->pEnt->index);
706
707    /* I'm still not 100% sure this uses the right values */
708
709    modecnt = xf86ValidateModes(pScrni,
710                                pScrni->monitor->Modes,
711                                pScrni->display->modes,
712                                GeodeClockRange,
713                                NULL, GX_MIN_PITCH, GX_MAX_PITCH,
714                                32, GX_MIN_HEIGHT, GX_MAX_HEIGHT,
715                                pScrni->display->virtualX,
716                                pScrni->display->virtualY, pGeode->FBAvail,
717                                LOOKUP_BEST_REFRESH);
718
719    if (modecnt <= 0) {
720        xf86DrvMsg(pScrni->scrnIndex, X_ERROR, "No valid modes were found\n");
721        return FALSE;
722    }
723
724    xf86PruneDriverModes(pScrni);
725
726    if (pScrni->modes == NULL) {
727        xf86DrvMsg(pScrni->scrnIndex, X_ERROR, "No valid modes were found\n");
728        return FALSE;
729    }
730
731    xf86SetCrtcForModes(pScrni, 0);
732    pScrni->currentMode = pScrni->modes;
733
734    xf86PrintModes(pScrni);
735    xf86SetDpi(pScrni, 0, 0);
736
737    /* Load the modules we'll need */
738
739    if (xf86LoadSubModule(pScrni, "fb") == NULL) {
740        return FALSE;
741    }
742
743    if (pGeode->NoAccel == FALSE) {
744        const char *module = (pGeode->useEXA) ? "exa" : "xaa";
745
746        if (!xf86LoadSubModule(pScrni, module)) {
747            return FALSE;
748        }
749    }
750
751    if (pGeode->tryHWCursor == TRUE) {
752        if (!xf86LoadSubModule(pScrni, "ramdac")) {
753            return FALSE;
754        }
755    }
756
757#ifndef XSERVER_LIBPCIACCESS
758    if (xf86RegisterResources(pGeode->pEnt->index, NULL, ResExclusive)) {
759        xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
760                   "Couldn't register the resources.\n");
761        return FALSE;
762    }
763#endif
764    return TRUE;
765}
766
767static void
768GXRestore(ScrnInfoPtr pScrni)
769{
770    GeodeRec *pGeode = GEODEPTR(pScrni);
771
772    if (pGeode->useVGA && pGeode->FBVGAActive) {
773        vgaHWPtr pvgaHW = VGAHWPTR(pScrni);
774
775        vgaHWProtect(pScrni, TRUE);
776        vgaHWRestore(pScrni, &pvgaHW->SavedReg, VGA_SR_ALL);
777        vgaHWProtect(pScrni, FALSE);
778    }
779}
780
781static Bool
782GXUnmapMem(ScrnInfoPtr pScrni)
783{
784    GeodeRec *pGeode = GEODEPTR(pScrni);
785
786    /* unmap all the memory map's */
787#ifndef XSERVER_LIBPCIACCESS
788    xf86UnMapVidMem(pScrni->scrnIndex, gfx_virt_regptr, GX_CPU_REG_SIZE);
789    xf86UnMapVidMem(pScrni->scrnIndex, gfx_virt_gpptr, GX_GP_REG_SIZE);
790    xf86UnMapVidMem(pScrni->scrnIndex, gfx_virt_vidptr, GX_VID_REG_SIZE);
791    xf86UnMapVidMem(pScrni->scrnIndex, gfx_virt_fbptr, pGeode->FBAvail);
792#else
793    pciVideoPtr pci = xf86GetPciInfoForEntity(pGeode->pEnt->index);
794
795    unmap_pci_mem(pScrni, pci, gfx_virt_regptr, GX_CPU_REG_SIZE);
796    unmap_pci_mem(pScrni, pci, gfx_virt_gpptr, GX_GP_REG_SIZE);
797    unmap_pci_mem(pScrni, pci, gfx_virt_vidptr, GX_VID_REG_SIZE);
798    unmap_pci_mem(pScrni, pci, gfx_virt_fbptr, pGeode->FBAvail);
799
800    munmap(XpressROMPtr, 0x10000);
801#endif
802    return TRUE;
803}
804
805static void
806GXSetDvLineSize(unsigned int pitch)
807{
808    unsigned long temp, dv_size = MDC_DV_LINE_SIZE_1024;
809
810    if (pitch > 1024) {
811        dv_size = MDC_DV_LINE_SIZE_2048;
812    }
813    if (pitch > 2048) {
814        dv_size = MDC_DV_LINE_SIZE_4096;
815    }
816    if (pitch > 4096) {
817        dv_size = MDC_DV_LINE_SIZE_8192;
818    }
819
820    /* WRITE DIRTY/VALID CONTROL WITH LINE LENGTH */
821
822    temp = READ_REG32(MDC_DV_CTL);
823    WRITE_REG32(MDC_DV_CTL, (temp & ~MDC_DV_LINE_SIZE_MASK) | dv_size);
824}
825
826/* XXX - this is nothing like the original function - not sure exactly what the purpose is for this quite yet */
827
828static void
829GXAdjustFrame(ADJUST_FRAME_ARGS_DECL)
830{
831    SCRN_INFO_PTR(arg);
832    GeodeRec *pGeode = GEODEPTR(pScrni);
833    unsigned long offset;
834
835    offset = y * pGeode->Pitch + x * (pScrni->bitsPerPixel >> 3);
836
837    gfx_set_display_offset(offset);
838}
839
840static Bool
841GXSetVideoMode(ScrnInfoPtr pScrni, DisplayModePtr pMode)
842{
843    GeodeRec *pGeode = GEODEPTR(pScrni);
844    int flags = 0;
845    int custom = 0;
846
847    pScrni->vtSema = TRUE;
848
849    gx_disable_dac_power();
850
851    if (pMode->Flags & V_NHSYNC)
852        flags |= 1;
853    if (pMode->Flags & V_NVSYNC)
854        flags |= 2;
855
856    /* Check to see if we should use custom or built-in timings */
857
858    if (pGeode->Panel)
859        custom = (pMode->type & M_T_USERDEF);
860    else
861        custom = !(pMode->type & (M_T_BUILTIN | M_T_DEFAULT));
862
863    /* If we're not doing a custom mode, then just set the fixed timings,
864     * otherwise, do the whole shooting match */
865
866    if (!custom) {
867        GFX(set_fixed_timings(pGeode->PanelX, pGeode->PanelY,
868                              pMode->CrtcHDisplay, pMode->CrtcVDisplay,
869                              pScrni->bitsPerPixel));
870    }
871    else {
872        if (pGeode->Panel)
873            GFX(set_panel_present(pGeode->PanelX, pGeode->PanelY,
874                                  pMode->CrtcHDisplay, pMode->CrtcVDisplay,
875                                  pScrni->bitsPerPixel));
876
877        GFX(set_display_timings(pScrni->bitsPerPixel, flags,
878                                pMode->CrtcHDisplay, pMode->CrtcHBlankStart,
879                                pMode->CrtcHSyncStart, pMode->CrtcHSyncEnd,
880                                pMode->CrtcHBlankEnd, pMode->CrtcHTotal,
881                                pMode->CrtcVDisplay, pMode->CrtcVBlankStart,
882                                pMode->CrtcVSyncStart, pMode->CrtcVSyncEnd,
883                                pMode->CrtcVBlankEnd, pMode->CrtcVTotal,
884                                (int) ((pMode->SynthClock / 1000.0) *
885                                       0x10000)));
886    }
887
888    GFX(set_crt_enable(CRT_ENABLE));
889    GFX(set_display_pitch(pGeode->displayPitch));
890    GFX(set_display_offset(0L));
891    GFX(wait_vertical_blank());
892
893    if (pGeode->Compression) {
894        GXSetDvLineSize(pGeode->Pitch);
895
896        gfx_set_compression_offset(pGeode->CBData.compression_offset);
897        gfx_set_compression_pitch(GX_CB_PITCH);
898        gfx_set_compression_size(GX_CB_SIZE);
899
900        gfx_set_compression_enable(1);
901    }
902
903    if (pGeode->HWCursor && !(pMode->Flags & V_DBLSCAN)) {
904        GXLoadCursorImage(pScrni, NULL);
905        GFX(set_cursor_position(pGeode->CursorStartOffset, 0, 0, 0, 0));
906        GXShowCursor(pScrni);
907    }
908    else {
909        GFX(set_cursor_enable(0));
910        pGeode->HWCursor = FALSE;
911    }
912
913    GXAdjustFrame(ADJUST_FRAME_ARGS(pScrni->frameX0, pScrni->frameY0));
914    gx_enable_dac_power();
915
916    return TRUE;
917}
918
919static Bool
920GXSwitchMode(SWITCH_MODE_ARGS_DECL)
921{
922    SCRN_INFO_PTR(arg);
923    GeodeRec *pGeode = GEODEPTR(pScrni);
924    int ret = TRUE;
925    int rotate;
926
927    /* Syn the engine and shutdown the DAC momentarily */
928
929    gfx_wait_until_idle();
930
931    /* Set up the memory for the new mode */
932    rotate = GXGetRotation(pScrni->pScreen);
933    ret = GXAllocateMemory(pScrni->pScreen, pScrni, rotate);
934
935    if (ret) {
936        if (pGeode->curMode != pMode)
937            ret = GXSetVideoMode(pScrni, pMode);
938    }
939
940    if (ret)
941        ret = GXRotate(pScrni, pMode);
942
943    /* Go back the way it was */
944
945    if (ret == FALSE) {
946        if (!GXSetVideoMode(pScrni, pGeode->curMode))
947            xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
948                       "Could not restore the previous mode\n");
949    }
950    else
951        pGeode->curMode = pMode;
952
953    return ret;
954}
955
956static void
957GXLeaveGraphics(ScrnInfoPtr pScrni)
958{
959    GeodeRec *pGeode = GEODEPTR(pScrni);
960
961    gfx_wait_until_idle();
962
963    /* Restore VG registers */
964    gfx_set_display_timings(pGeode->FBgfxdisplaytiming.wBpp,
965                            pGeode->FBgfxdisplaytiming.wPolarity,
966                            pGeode->FBgfxdisplaytiming.wHActive,
967                            pGeode->FBgfxdisplaytiming.wHBlankStart,
968                            pGeode->FBgfxdisplaytiming.wHSyncStart,
969                            pGeode->FBgfxdisplaytiming.wHSyncEnd,
970                            pGeode->FBgfxdisplaytiming.wHBlankEnd,
971                            pGeode->FBgfxdisplaytiming.wHTotal,
972                            pGeode->FBgfxdisplaytiming.wVActive,
973                            pGeode->FBgfxdisplaytiming.wVBlankStart,
974                            pGeode->FBgfxdisplaytiming.wVSyncStart,
975                            pGeode->FBgfxdisplaytiming.wVSyncEnd,
976                            pGeode->FBgfxdisplaytiming.wVBlankEnd,
977                            pGeode->FBgfxdisplaytiming.wVTotal,
978                            pGeode->FBgfxdisplaytiming.dwDotClock);
979
980    gfx_set_compression_enable(0);
981
982    /* Restore the previous Compression state */
983    if (pGeode->FBCompressionEnable) {
984        gfx_set_compression_offset(pGeode->FBCompressionOffset);
985        gfx_set_compression_pitch(pGeode->FBCompressionPitch);
986        gfx_set_compression_size(pGeode->FBCompressionSize);
987        gfx_set_compression_enable(1);
988    }
989
990    gfx_set_display_pitch(pGeode->FBgfxdisplaytiming.wPitch);
991
992    gfx_set_display_offset(pGeode->FBDisplayOffset);
993
994    /* Restore Cursor */
995    gfx_set_cursor_position(pGeode->FBCursorOffset, 0, 0, 0, 0);
996
997    if (pGeode->useVGA) {
998        pGeode->vesa->pInt->num = 0x10;
999        pGeode->vesa->pInt->ax = 0x0 | pGeode->FBBIOSMode;
1000        pGeode->vesa->pInt->bx = 0;
1001        xf86ExecX86int10(pGeode->vesa->pInt);
1002        gfx_delay_milliseconds(3);
1003    }
1004
1005    GXRestore(pScrni);
1006
1007    gx_enable_dac_power();
1008}
1009
1010static Bool
1011GXCloseScreen(CLOSE_SCREEN_ARGS_DECL)
1012{
1013    ScrnInfoPtr pScrni = xf86ScreenToScrn(pScrn);
1014    GeodeRec *pGeode = GEODEPTR(pScrni);
1015
1016    if (pScrni->vtSema)
1017        GXLeaveGraphics(pScrni);
1018
1019#ifdef XF86XAA
1020    if (pGeode->AccelInfoRec)
1021        XAADestroyInfoRec(pGeode->AccelInfoRec);
1022#endif
1023
1024    if (pGeode->AccelImageWriteBuffers) {
1025        free(pGeode->AccelImageWriteBuffers[0]);
1026        free(pGeode->AccelImageWriteBuffers);
1027        pGeode->AccelImageWriteBuffers = NULL;
1028    }
1029
1030    if (pGeode->AccelColorExpandBuffers) {
1031        free(pGeode->AccelColorExpandBuffers);
1032        pGeode->AccelColorExpandBuffers = NULL;
1033    }
1034
1035    if (pGeode->pExa) {
1036        exaDriverFini(pScrn);
1037        free(pGeode->pExa);
1038        pGeode->pExa = NULL;
1039    }
1040
1041    pScrni->vtSema = FALSE;
1042
1043    GXUnmapMem(pScrni);
1044
1045    pScrni->PointerMoved = pGeode->PointerMoved;
1046    pScrn->CloseScreen = pGeode->CloseScreen;
1047
1048    if (pScrn->CloseScreen)
1049        return (*pScrn->CloseScreen) (CLOSE_SCREEN_ARGS);
1050
1051    return TRUE;
1052}
1053
1054static Bool
1055GXEnterGraphics(ScreenPtr pScrn, ScrnInfoPtr pScrni)
1056{
1057    GeodeRec *pGeode = GEODEPTR(pScrni);
1058
1059    if (!GXMapMem(pScrni))
1060        return FALSE;
1061
1062    if (pGeode->useVGA)
1063        pGeode->FBVGAActive = gu2_get_vga_active();
1064
1065    gfx_wait_until_idle();
1066
1067    /* Save off the current state (should this be somewhere else)? */
1068
1069    pGeode->FBgfxdisplaytiming.dwDotClock = gfx_get_clock_frequency();
1070    pGeode->FBgfxdisplaytiming.wPitch = gfx_get_display_pitch();
1071    pGeode->FBgfxdisplaytiming.wBpp = gfx_get_display_bpp();
1072    pGeode->FBgfxdisplaytiming.wHTotal = gfx_get_htotal();
1073    pGeode->FBgfxdisplaytiming.wHActive = gfx_get_hactive();
1074    pGeode->FBgfxdisplaytiming.wHSyncStart = gfx_get_hsync_start();
1075    pGeode->FBgfxdisplaytiming.wHSyncEnd = gfx_get_hsync_end();
1076    pGeode->FBgfxdisplaytiming.wHBlankStart = gfx_get_hblank_start();
1077    pGeode->FBgfxdisplaytiming.wHBlankEnd = gfx_get_hblank_end();
1078    pGeode->FBgfxdisplaytiming.wVTotal = gfx_get_vtotal();
1079    pGeode->FBgfxdisplaytiming.wVActive = gfx_get_vactive();
1080    pGeode->FBgfxdisplaytiming.wVSyncStart = gfx_get_vsync_start();
1081    pGeode->FBgfxdisplaytiming.wVSyncEnd = gfx_get_vsync_end();
1082    pGeode->FBgfxdisplaytiming.wVBlankStart = gfx_get_vblank_start();
1083    pGeode->FBgfxdisplaytiming.wVBlankEnd = gfx_get_vblank_end();
1084    pGeode->FBgfxdisplaytiming.wPolarity = gfx_get_sync_polarities();
1085
1086    pGeode->FBDisplayOffset = gfx_get_display_offset();
1087
1088    if (pGeode->useVGA) {
1089        vgaHWPtr pvgaHW = VGAHWPTR(pScrni);
1090
1091        pGeode->FBBIOSMode = pvgaHW->readCrtc(pvgaHW, 0x040);
1092    }
1093
1094    pGeode->FBCompressionEnable = gfx_get_compression_enable();
1095    pGeode->FBCompressionOffset = gfx_get_compression_offset();
1096    pGeode->FBCompressionPitch = gfx_get_compression_pitch();
1097    pGeode->FBCompressionSize = gfx_get_compression_size();
1098
1099#ifdef PNL_SUP
1100    Pnl_SavePanelState();
1101#endif
1102
1103    /* Turn off the VGA */
1104
1105    if (pGeode->useVGA && pGeode->FBVGAActive) {
1106        unsigned short sequencer;
1107        vgaHWPtr pvgaHW = VGAHWPTR(pScrni);
1108
1109        /* Map VGA aperture */
1110        if (!vgaHWMapMem(pScrni))
1111            return FALSE;
1112
1113        /* Unlock VGA registers */
1114        vgaHWUnlock(pvgaHW);
1115
1116        /* Save the current state and setup the current mode */
1117        vgaHWSave(pScrni, &VGAHWPTR(pScrni)->SavedReg, VGA_SR_ALL);
1118
1119        /* DISABLE VGA SEQUENCER */
1120        /* This allows the VGA state machine to terminate. We must delay */
1121        /* such that there are no pending MBUS requests.  */
1122
1123        gfx_outb(MDC_SEQUENCER_INDEX, MDC_SEQUENCER_CLK_MODE);
1124        sequencer = gfx_inb(MDC_SEQUENCER_DATA);
1125        sequencer |= MDC_CLK_MODE_SCREEN_OFF;
1126        gfx_outb(MDC_SEQUENCER_DATA, sequencer);
1127
1128        gfx_delay_milliseconds(1);
1129
1130        /* BLANK THE VGA DISPLAY */
1131        gfx_outw(MDC_SEQUENCER_INDEX, MDC_SEQUENCER_RESET);
1132        sequencer = gfx_inb(MDC_SEQUENCER_DATA);
1133        sequencer &= ~MDC_RESET_VGA_DISP_ENABLE;
1134        gfx_outb(MDC_SEQUENCER_DATA, sequencer);
1135
1136        gfx_delay_milliseconds(1);
1137    }
1138
1139    /* Set up the memory */
1140    /* XXX - FIXME - when we allow initial rotation, it should be here */
1141    GXAllocateMemory(pScrn, pScrni, pGeode->rotation);
1142
1143    /* Clear the framebuffer */
1144    memset(pGeode->FBBase + pGeode->displayOffset, 0, pGeode->displaySize);
1145
1146    /* Set up the video mode */
1147    GXSetVideoMode(pScrni, pScrni->currentMode);
1148    pGeode->curMode = pScrni->currentMode;
1149
1150    return TRUE;
1151}
1152
1153static void
1154GXLoadPalette(ScrnInfoPtr pScrni,
1155              int numColors, int *indizes, LOCO * colors, VisualPtr pVisual)
1156{
1157    int i, index, color;
1158
1159    for (i = 0; i < numColors; i++) {
1160        index = indizes[i] & 0xFF;
1161        color = (((unsigned long) (colors[index].red & 0xFF)) << 16) |
1162            (((unsigned long) (colors[index].green & 0xFF)) << 8) |
1163            ((unsigned long) (colors[index].blue & 0xFF));
1164
1165        GFX(set_display_palette_entry(index, color));
1166    }
1167}
1168
1169#ifdef DPMSExtension
1170static void
1171GXPanelPower(int enable)
1172{
1173    unsigned long power = READ_VID32(RCDF_POWER_MANAGEMENT);
1174
1175    if (enable != 0)
1176        power |= RCDF_PM_PANEL_POWER_ON;
1177    else
1178        power &= ~RCDF_PM_PANEL_POWER_ON;
1179
1180    WRITE_VID32(RCDF_POWER_MANAGEMENT, power);
1181}
1182
1183static void
1184GXDPMSSet(ScrnInfoPtr pScrni, int mode, int flags)
1185{
1186    GeodeRec *pGeode;
1187
1188    pGeode = GEODEPTR(pScrni);
1189
1190    if (!pScrni->vtSema)
1191        return;
1192
1193    switch (mode) {
1194    case DPMSModeOn:
1195        /* Screen: On; HSync: On; VSync: On */
1196        GFX(set_crt_enable(CRT_ENABLE));
1197#if defined(PNL_SUP)
1198        if (pGeode->Panel) {
1199            Pnl_PowerUp();
1200            GXPanelPower(1);
1201        }
1202#endif
1203        break;
1204
1205    case DPMSModeStandby:
1206        /* Screen: Off; HSync: Off; VSync: On */
1207        GFX(set_crt_enable(CRT_STANDBY));
1208#if defined(PNL_SUP)
1209        if (pGeode->Panel) {
1210            Pnl_PowerDown();
1211            GXPanelPower(0);
1212        }
1213#endif
1214        break;
1215
1216    case DPMSModeSuspend:
1217        /* Screen: Off; HSync: On; VSync: Off */
1218        GFX(set_crt_enable(CRT_SUSPEND));
1219#if defined(PNL_SUP)
1220        if (pGeode->Panel) {
1221            Pnl_PowerDown();
1222            GXPanelPower(0);
1223        }
1224#endif
1225        break;
1226
1227    case DPMSModeOff:
1228        /* Screen: Off; HSync: Off; VSync: Off */
1229        GFX(set_crt_enable(CRT_DISABLE));
1230#if defined(PNL_SUP)
1231        if (pGeode->Panel) {
1232            Pnl_PowerDown();
1233            GXPanelPower(0);
1234        }
1235#endif
1236        break;
1237    }
1238}
1239#endif
1240
1241static Bool
1242GXCreateScreenResources(ScreenPtr pScreen)
1243{
1244    ScrnInfoPtr pScrni = xf86ScreenToScrn(pScreen);
1245    GeodeRec *pGeode = GEODEPTR(pScrni);
1246
1247    pScreen->CreateScreenResources = pGeode->CreateScreenResources;
1248    if (!(*pScreen->CreateScreenResources) (pScreen))
1249        return FALSE;
1250
1251    if (xf86LoaderCheckSymbol("GXRandRSetConfig")
1252        && pGeode->rotation != RR_Rotate_0) {
1253        Rotation(*GXRandRSetConfig) (ScreenPtr pScreen, Rotation rr, int rate,
1254                                     RRScreenSizePtr pSize) = NULL;
1255
1256        RRScreenSize p;
1257        Rotation requestedRotation = pGeode->rotation;
1258
1259        pGeode->rotation = RR_Rotate_0;
1260
1261        /* Just setup enough for an initial rotate */
1262
1263        p.width = pScreen->width;
1264        p.height = pScreen->height;
1265        p.mmWidth = pScreen->mmWidth;
1266        p.mmHeight = pScreen->mmHeight;
1267
1268        GXRandRSetConfig = LoaderSymbol("GXRandRSetConfig");
1269        if (GXRandRSetConfig) {
1270            pGeode->starting = TRUE;
1271            (*GXRandRSetConfig) (pScreen, requestedRotation, 0, &p);
1272            pGeode->starting = FALSE;
1273        }
1274    }
1275
1276    return TRUE;
1277}
1278
1279static Bool
1280GXScreenInit(SCREEN_INIT_ARGS_DECL)
1281{
1282    ScrnInfoPtr pScrni = xf86ScreenToScrn(pScrn);
1283    GeodeRec *pGeode = GEODEPTR(pScrni);
1284    XF86ModReqInfo shadowReq;
1285    int maj, min, ret, rotate;
1286
1287    pGeode->starting = TRUE;
1288
1289    /* If we are using VGA then go ahead and map the memory */
1290
1291    if (pGeode->useVGA) {
1292
1293        if (!vgaHWMapMem(pScrni))
1294            return FALSE;
1295
1296        vgaHWGetIOBase(VGAHWPTR(pScrni));
1297    }
1298
1299    if (!pGeode->NoAccel) {
1300
1301        if (pGeode->useEXA) {
1302
1303            if (!(pGeode->pExa = exaDriverAlloc())) {
1304                xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
1305                           "Couldn't allocate the EXA structure.\n");
1306                pGeode->NoAccel = TRUE;
1307            }
1308            else {
1309                ExaDriverPtr pExa = pGeode->pExa;
1310
1311                /* THis is set in GXAllocMem */
1312                pExa->memoryBase = 0;
1313
1314                /* This is set in GXAllocateMemory */
1315                pExa->memorySize = 0;
1316
1317                pExa->pixmapOffsetAlign = 32;
1318                pExa->pixmapPitchAlign = 32;
1319                pExa->flags = EXA_OFFSCREEN_PIXMAPS;
1320                pExa->maxX = GX_MAX_WIDTH - 1;
1321                pExa->maxY = GX_MAX_HEIGHT - 1;
1322            }
1323        }
1324        else {
1325            pGeode->AccelImageWriteBuffers =
1326                calloc(pGeode->NoOfImgBuffers,
1327                       sizeof(pGeode->AccelImageWriteBuffers[0]));
1328            pGeode->AccelColorExpandBuffers =
1329                calloc(pGeode->NoOfColorExpandLines,
1330                       sizeof(pGeode->AccelColorExpandBuffers[0]));
1331        }
1332    }
1333
1334    /* XXX FIXME - Take down any of the structures on failure? */
1335
1336    if (!GXEnterGraphics(pScrn, pScrni))
1337        return FALSE;
1338
1339    miClearVisualTypes();
1340
1341    /* XXX Again - take down anything? */
1342
1343    if (pScrni->bitsPerPixel > 8) {
1344        if (!miSetVisualTypes(pScrni->depth,
1345                              TrueColorMask, pScrni->rgbBits,
1346                              pScrni->defaultVisual)) {
1347            return FALSE;
1348        }
1349    }
1350    else {
1351        if (!miSetVisualTypes(pScrni->depth,
1352                              miGetDefaultVisualMask(pScrni->depth),
1353                              pScrni->rgbBits, pScrni->defaultVisual)) {
1354            return FALSE;
1355        }
1356    }
1357
1358    miSetPixmapDepths();
1359
1360    /* Point at the visible area to start */
1361
1362    ret = fbScreenInit(pScrn, pGeode->FBBase + pGeode->displayOffset,
1363                       pScrni->virtualX, pScrni->virtualY,
1364                       pScrni->xDpi, pScrni->yDpi, pGeode->displayWidth,
1365                       pScrni->bitsPerPixel);
1366
1367    if (!ret)
1368        return FALSE;
1369
1370    xf86SetBlackWhitePixels(pScrn);
1371
1372    /* Set up the color ordering */
1373
1374    if (pScrni->bitsPerPixel > 8) {
1375        VisualPtr visual = pScrn->visuals + pScrn->numVisuals;
1376
1377        while (--visual >= pScrn->visuals) {
1378            if ((visual->class | DynamicClass) == DirectColor) {
1379                visual->offsetRed = pScrni->offset.red;
1380                visual->offsetGreen = pScrni->offset.green;
1381                visual->offsetBlue = pScrni->offset.blue;
1382                visual->redMask = pScrni->mask.red;
1383                visual->greenMask = pScrni->mask.green;
1384                visual->blueMask = pScrni->mask.blue;
1385            }
1386        }
1387    }
1388
1389    /* Must follow the color ordering */
1390    fbPictureInit(pScrn, 0, 0);
1391
1392    if (!pGeode->NoAccel)
1393        GXAccelInit(pScrn);
1394
1395    xf86SetBackingStore(pScrn);
1396
1397    /* Set up the soft cursor */
1398    miDCInitialize(pScrn, xf86GetPointerScreenFuncs());
1399
1400    /* Set up the HW cursor - must follow the soft cursor init */
1401
1402    if (pGeode->tryHWCursor) {
1403        if (!GXHWCursorInit(pScrn))
1404            xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
1405                       "Hardware cursor initialization failed.\n");
1406    }
1407
1408    /* Set up the color map */
1409
1410    if (!miCreateDefColormap(pScrn))
1411        return FALSE;
1412
1413    if (pScrni->bitsPerPixel == 8) {
1414        /* Must follow initialization of the default colormap */
1415
1416        if (!xf86HandleColormaps(pScrn, 256, 8,
1417                                 GXLoadPalette, NULL,
1418                                 CMAP_PALETTED_TRUECOLOR |
1419                                 CMAP_RELOAD_ON_MODE_SWITCH)) {
1420            return FALSE;
1421        }
1422    }
1423#ifdef DPMSExtension
1424    xf86DPMSInit(pScrn, GXDPMSSet, 0);
1425#endif
1426
1427    GXInitVideo(pScrn);
1428
1429    /* Set up RandR */
1430
1431#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 24
1432    xf86DisableRandR();         /* We provide our own RandR goodness */
1433#endif
1434
1435    /* Try to set up the shadow FB for rotation */
1436
1437    memset(&shadowReq, 0, sizeof(shadowReq));
1438    shadowReq.majorversion = 1;
1439    shadowReq.minorversion = 1;
1440
1441    if (LoadSubModule(pScrni->module, "shadow",
1442                      NULL, NULL, NULL, &shadowReq, &maj, &min)) {
1443
1444        rotate = RR_Rotate_0 | RR_Rotate_90 | RR_Rotate_180 | RR_Rotate_270;
1445        shadowSetup(pScrn);
1446    }
1447    else {
1448        LoaderErrorMsg(NULL, "shadow", maj, min);
1449        xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
1450                   "Error loading shadow - rotation not available.\n");
1451
1452        if (pGeode->rotation != RR_Rotate_0)
1453            xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
1454                       "Reverting back to normal rotation.\n");
1455
1456        rotate = pGeode->rotation = RR_Rotate_0;
1457    }
1458
1459    GXRandRInit(pScrn, rotate);
1460
1461    pGeode->PointerMoved = pScrni->PointerMoved;
1462    pScrni->PointerMoved = GeodePointerMoved;
1463
1464    pGeode->CreateScreenResources = pScrn->CreateScreenResources;
1465    pScrn->CreateScreenResources = GXCreateScreenResources;
1466
1467    pGeode->CloseScreen = pScrn->CloseScreen;
1468    pScrn->CloseScreen = GXCloseScreen;
1469    pScrn->SaveScreen = GXSaveScreen;
1470
1471    if (serverGeneration == 1)
1472        xf86ShowUnusedOptions(pScrni->scrnIndex, pScrni->options);
1473
1474    pGeode->starting = FALSE;
1475
1476    return TRUE;
1477}
1478
1479static int
1480GXValidMode(VALID_MODE_ARGS_DECL)
1481{
1482    SCRN_INFO_PTR(arg);
1483    GeodeRec *pGeode = GEODEPTR(pScrni);
1484    int p;
1485    int custom = 0;
1486
1487    if (pGeode->Panel)
1488        custom = (pMode->type & M_T_USERDEF);
1489    else
1490        custom = (pMode->type & (M_T_BUILTIN | M_T_DEFAULT));
1491
1492    /* Use the durango lookup for !custom modes */
1493
1494    if (!custom && pGeode->Panel) {
1495        if (pMode->CrtcHDisplay > pGeode->PanelX ||
1496            pMode->CrtcVDisplay > pGeode->PanelY ||
1497            gfx_is_panel_mode_supported(pGeode->PanelX,
1498                                        pGeode->PanelY,
1499                                        pMode->CrtcHDisplay,
1500                                        pMode->CrtcVDisplay,
1501                                        pScrni->bitsPerPixel) < 0) {
1502
1503            return MODE_BAD;
1504        }
1505    }
1506
1507    if (gfx_is_display_mode_supported(pMode->CrtcHDisplay,
1508                                      pMode->CrtcVDisplay,
1509                                      pScrni->bitsPerPixel,
1510                                      GeodeGetRefreshRate(pMode)) < 0) {
1511        return MODE_BAD;
1512    }
1513
1514    if (pMode->Flags & V_INTERLACE)
1515        return MODE_NO_INTERLACE;
1516
1517    if (pGeode->tryCompression)
1518        p = GeodeCalculatePitchBytes(pMode->CrtcHDisplay, pScrni->bitsPerPixel);
1519    else
1520        p = ((pMode->CrtcHDisplay + 3) & ~3) * (pScrni->bitsPerPixel >> 3);
1521
1522    if (p * pMode->CrtcVDisplay > pGeode->FBAvail)
1523        return MODE_MEM;
1524
1525    return MODE_OK;
1526}
1527
1528/* XXX - Way more to do here */
1529
1530static Bool
1531GXEnterVT(VT_FUNC_ARGS_DECL)
1532{
1533    SCRN_INFO_PTR(arg);
1534    return GXEnterGraphics(NULL, pScrni);
1535}
1536
1537static void
1538GXLeaveVT(VT_FUNC_ARGS_DECL)
1539{
1540    SCRN_INFO_PTR(arg);
1541    GeodeRec *pGeode = GEODEPTR(pScrni);
1542
1543    pGeode->PrevDisplayOffset = gfx_get_display_offset();
1544    GXLeaveGraphics(pScrni);
1545}
1546
1547void
1548GXSetupChipsetFPtr(ScrnInfoPtr pScrn)
1549{
1550    pScrn->PreInit = GXPreInit;
1551    pScrn->ScreenInit = GXScreenInit;
1552    pScrn->SwitchMode = GXSwitchMode;
1553    pScrn->AdjustFrame = GXAdjustFrame;
1554    pScrn->EnterVT = GXEnterVT;
1555    pScrn->LeaveVT = GXLeaveVT;
1556    pScrn->FreeScreen = GeodeFreeScreen;
1557    pScrn->ValidMode = GXValidMode;
1558}
1559
1560/* ====== Common functions ======
1561 * These are all the common functions that we use for both GX and LX - They live here
1562 * because most of them came along for the GX first, and then were adapted to the LX.
1563 *  We could move these to a common function, but there is no hurry
1564 * ============================== */
1565
1566void
1567GeodePointerMoved(POINTER_MOVED_ARGS_DECL)
1568{
1569    SCRN_INFO_PTR(arg);
1570    GeodeRec *pGeode = GEODEPTR(pScrni);
1571
1572    int newX = x, newY = y;
1573
1574    switch (pGeode->rotation) {
1575    case RR_Rotate_0:
1576        break;
1577    case RR_Rotate_90:
1578        newX = y;
1579        newY = pScrni->pScreen->width - x - 1;
1580        break;
1581    case RR_Rotate_180:
1582        newX = pScrni->pScreen->width - x - 1;
1583        newY = pScrni->pScreen->height - y - 1;
1584        break;
1585    case RR_Rotate_270:
1586        newX = pScrni->pScreen->height - y - 1;
1587        newY = x;
1588        break;
1589    }
1590
1591    (*pGeode->PointerMoved) (POINTER_MOVED_ARGS(newX, newY));
1592}
1593
1594int
1595GeodeGetFPGeometry(const char *str, int *width, int *height)
1596{
1597
1598    int ret = sscanf(str, "%dx%d", width, height);
1599
1600    return (ret == 2) ? 0 : 1;
1601}
1602
1603static void
1604GeodeFreeRec(ScrnInfoPtr pScrni)
1605{
1606    if (pScrni->driverPrivate != NULL) {
1607        free(pScrni->driverPrivate);
1608        pScrni->driverPrivate = NULL;
1609    }
1610}
1611
1612void
1613GeodeFreeScreen(FREE_SCREEN_ARGS_DECL)
1614{
1615    SCRN_INFO_PTR(arg);
1616    GeodeRec *pGeode = GEODEPTR(pScrni);
1617
1618    if (pGeode == NULL)
1619        return;
1620
1621    if (pGeode->useVGA) {
1622        if (xf86LoaderCheckSymbol("vgaHWFreeHWRec"))
1623            vgaHWFreeHWRec(pScrni);
1624    }
1625
1626    GeodeFreeRec(pScrni);
1627}
1628
1629int
1630GeodeCalculatePitchBytes(unsigned int width, unsigned int bpp)
1631{
1632
1633    int delta = width * (bpp >> 3);
1634
1635    /* Less then 640 has doubling enabled */
1636
1637    if (width < 640)
1638        delta <<= 1;
1639
1640    /* Calculate the pitch (compression requires a power of 2) */
1641
1642    if (delta > 4096)
1643        delta = 8192;
1644    else if (delta > 2048)
1645        delta = 4096;
1646    else if (delta > 1024)
1647        delta = 2048;
1648    else
1649        delta = 1024;
1650
1651    return delta;
1652}
1653