g80_driver.c revision 6086d97e
1fc5a983dSmrg/*
271ba42d0Smrg * Copyright (c) 2007,2010 NVIDIA Corporation
3fc5a983dSmrg *
4fc5a983dSmrg * Permission is hereby granted, free of charge, to any person obtaining a
5fc5a983dSmrg * copy of this software and associated documentation files (the
6fc5a983dSmrg * "Software"), to deal in the Software without restriction, including
7fc5a983dSmrg * without limitation the rights to use, copy, modify, merge, publish,
8fc5a983dSmrg * distribute, sublicense, and/or sell copies of the Software, and to
9fc5a983dSmrg * permit persons to whom the Software is furnished to do so, subject to
10fc5a983dSmrg * the following conditions:
11fc5a983dSmrg *
12fc5a983dSmrg * The above copyright notice and this permission notice shall be included
13fc5a983dSmrg * in all copies or substantial portions of the Software.
14fc5a983dSmrg *
15fc5a983dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16fc5a983dSmrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17fc5a983dSmrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18fc5a983dSmrg * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19fc5a983dSmrg * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20fc5a983dSmrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21fc5a983dSmrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22fc5a983dSmrg */
23fc5a983dSmrg
24fc5a983dSmrg
25fc5a983dSmrg#ifdef HAVE_CONFIG_H
26fc5a983dSmrg#include "config.h"
27fc5a983dSmrg#endif
28fc5a983dSmrg
29fc5a983dSmrg#include <string.h>
30fc5a983dSmrg
3171ba42d0Smrg#include <xf86.h>
32fc5a983dSmrg#include <xf86_OSproc.h>
3371ba42d0Smrg#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 6
34fc5a983dSmrg#include <xf86Resources.h>
3571ba42d0Smrg#endif
36fc5a983dSmrg#include <mipointer.h>
37fc5a983dSmrg#include <mibstore.h>
38fc5a983dSmrg#include <micmap.h>
39fc5a983dSmrg#include <xf86cmap.h>
40fc5a983dSmrg#include <fb.h>
4171ba42d0Smrg#ifdef HAVE_XEXTPROTO_71
4271ba42d0Smrg#include <X11/extensions/dpmsconst.h>
4371ba42d0Smrg#else
44fc5a983dSmrg#define DPMS_SERVER
45fc5a983dSmrg#include <X11/extensions/dpms.h>
4671ba42d0Smrg#endif
4771ba42d0Smrg
4871ba42d0Smrg#include <xf86RandR12.h>
49fc5a983dSmrg
50fc5a983dSmrg#include "nv_const.h"
51fc5a983dSmrg#include "g80_type.h"
52fc5a983dSmrg#include "g80_cursor.h"
53fc5a983dSmrg#include "g80_display.h"
54fc5a983dSmrg#include "g80_dma.h"
55fc5a983dSmrg#include "g80_output.h"
56fc5a983dSmrg#include "g80_exa.h"
57fc5a983dSmrg#include "g80_xaa.h"
58fc5a983dSmrg
59fc5a983dSmrg#define G80_REG_SIZE (1024 * 1024 * 16)
6071ba42d0Smrg#define G80_RESERVED_VIDMEM 0xe000
61fc5a983dSmrg
62fc5a983dSmrgtypedef enum {
63fc5a983dSmrg    OPTION_HW_CURSOR,
64fc5a983dSmrg    OPTION_NOACCEL,
65fc5a983dSmrg    OPTION_ACCEL_METHOD,
66fc5a983dSmrg    OPTION_FP_DITHER,
67fc5a983dSmrg    OPTION_ALLOW_DUAL_LINK,
68fc5a983dSmrg} G80Opts;
69fc5a983dSmrg
70fc5a983dSmrgstatic const OptionInfoRec G80Options[] = {
71fc5a983dSmrg    { OPTION_HW_CURSOR,         "HWCursor",             OPTV_BOOLEAN,   {0}, FALSE },
72fc5a983dSmrg    { OPTION_NOACCEL,           "NoAccel",              OPTV_BOOLEAN,   {0}, FALSE },
73fc5a983dSmrg    { OPTION_ACCEL_METHOD,      "AccelMethod",          OPTV_STRING,    {0}, FALSE },
74fc5a983dSmrg    { OPTION_FP_DITHER,         "FPDither",             OPTV_BOOLEAN,   {0}, FALSE },
75fc5a983dSmrg    { OPTION_ALLOW_DUAL_LINK,   "AllowDualLinkModes",   OPTV_BOOLEAN,   {0}, FALSE },
76fc5a983dSmrg    { -1,                       NULL,                   OPTV_NONE,      {0}, FALSE }
77fc5a983dSmrg};
78fc5a983dSmrg
79fc5a983dSmrgstatic Bool
80fc5a983dSmrgG80GetRec(ScrnInfoPtr pScrn)
81fc5a983dSmrg{
82fc5a983dSmrg    if(pScrn->driverPrivate == NULL)
836086d97eSmrg        pScrn->driverPrivate = calloc(sizeof(G80Rec), 1);
84fc5a983dSmrg
85fc5a983dSmrg    return (pScrn->driverPrivate != NULL);
86fc5a983dSmrg}
87fc5a983dSmrg
88fc5a983dSmrgstatic void
89fc5a983dSmrgG80FreeRec(ScrnInfoPtr pScrn)
90fc5a983dSmrg{
916086d97eSmrg    free(pScrn->driverPrivate);
92fc5a983dSmrg    pScrn->driverPrivate = NULL;
93fc5a983dSmrg}
94fc5a983dSmrg
95fc5a983dSmrgstatic Bool
96fc5a983dSmrgG80ResizeScreen(ScrnInfoPtr pScrn, int width, int height)
97fc5a983dSmrg{
98fc5a983dSmrg    ScreenPtr pScreen = pScrn->pScreen;
99fc5a983dSmrg    G80Ptr pNv = G80PTR(pScrn);
100fc5a983dSmrg    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
101fc5a983dSmrg    int pitch = width * (pScrn->bitsPerPixel / 8);
102fc5a983dSmrg    int i;
103fc5a983dSmrg
104fc5a983dSmrg    pitch = (pitch + 255) & ~255;
105fc5a983dSmrg
106fc5a983dSmrg    pScrn->virtualX = width;
107fc5a983dSmrg    pScrn->virtualY = height;
108fc5a983dSmrg
109fc5a983dSmrg    /* Can resize if XAA is disabled or EXA is enabled */
110fc5a983dSmrg    if(!pNv->xaa || pNv->exa) {
111fc5a983dSmrg        (*pScrn->pScreen->GetScreenPixmap)(pScrn->pScreen)->devKind = pitch;
112fc5a983dSmrg        pScrn->displayWidth = pitch / (pScrn->bitsPerPixel / 8);
113fc5a983dSmrg
114fc5a983dSmrg        /* Re-set the modes so the new pitch is taken into account */
115fc5a983dSmrg        for(i = 0; i < xf86_config->num_crtc; i++) {
116fc5a983dSmrg            xf86CrtcPtr crtc = xf86_config->crtc[i];
117fc5a983dSmrg            if(crtc->enabled)
118fc5a983dSmrg                xf86CrtcSetMode(crtc, &crtc->mode, crtc->rotation, crtc->x, crtc->y);
119fc5a983dSmrg        }
120fc5a983dSmrg    }
121fc5a983dSmrg
122fc5a983dSmrg    /*
123fc5a983dSmrg     * If EXA is enabled, use exaOffscreenAlloc to carve out a chunk of memory
124fc5a983dSmrg     * for the screen.
125fc5a983dSmrg     */
126fc5a983dSmrg    if(pNv->exa) {
127fc5a983dSmrg        if(pNv->exaScreenArea)
128fc5a983dSmrg            exaOffscreenFree(pScreen, pNv->exaScreenArea);
129fc5a983dSmrg        pNv->exaScreenArea = exaOffscreenAlloc(pScreen, pitch * pScrn->virtualY,
130fc5a983dSmrg                                               256, TRUE, NULL, NULL);
131fc5a983dSmrg        if(!pNv->exaScreenArea || pNv->exaScreenArea->offset != 0) {
132fc5a983dSmrg            xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
133fc5a983dSmrg                       "Failed to reserve EXA memory for the screen or EXA "
134fc5a983dSmrg                       "returned an area with a nonzero offset.  Don't be "
135fc5a983dSmrg                       "surprised if your screen is corrupt.\n");
136fc5a983dSmrg        }
137fc5a983dSmrg    }
138fc5a983dSmrg
139fc5a983dSmrg    return TRUE;
140fc5a983dSmrg}
141fc5a983dSmrg
142fc5a983dSmrgstatic const xf86CrtcConfigFuncsRec randr12_screen_funcs = {
143fc5a983dSmrg    .resize = G80ResizeScreen,
144fc5a983dSmrg};
145fc5a983dSmrg
146fc5a983dSmrgstatic Bool
147fc5a983dSmrgG80PreInit(ScrnInfoPtr pScrn, int flags)
148fc5a983dSmrg{
149fc5a983dSmrg    G80Ptr pNv;
150fc5a983dSmrg    EntityInfoPtr pEnt;
151fc5a983dSmrg#if XSERVER_LIBPCIACCESS
152fc5a983dSmrg    struct pci_device *pPci;
153fc5a983dSmrg    int err;
154fc5a983dSmrg    void *p;
155fc5a983dSmrg#else
156fc5a983dSmrg    pciVideoPtr pPci;
157fc5a983dSmrg    PCITAG pcitag;
158fc5a983dSmrg#endif
159fc5a983dSmrg    MessageType from;
160fc5a983dSmrg    Bool primary;
161fc5a983dSmrg    const rgb zeros = {0, 0, 0};
162fc5a983dSmrg    const Gamma gzeros = {0.0, 0.0, 0.0};
163fc5a983dSmrg    char *s;
164fc5a983dSmrg    CARD32 tmp;
165fc5a983dSmrg    memType BAR1sizeKB;
166fc5a983dSmrg
167f3561b8bSmrg    if(flags & PROBE_DETECT)
168f3561b8bSmrg        return TRUE;
169fc5a983dSmrg
170fc5a983dSmrg    /* Check the number of entities, and fail if it isn't one. */
171fc5a983dSmrg    if(pScrn->numEntities != 1)
172fc5a983dSmrg        return FALSE;
173fc5a983dSmrg
174fc5a983dSmrg    /* Allocate the NVRec driverPrivate */
175fc5a983dSmrg    if(!G80GetRec(pScrn)) {
176fc5a983dSmrg        return FALSE;
177fc5a983dSmrg    }
178fc5a983dSmrg    pNv = G80PTR(pScrn);
179fc5a983dSmrg
180fc5a983dSmrg    /* Get the entity, and make sure it is PCI. */
181fc5a983dSmrg    pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
182fc5a983dSmrg    if(pEnt->location.type != BUS_PCI) goto fail;
183fc5a983dSmrg    pPci = xf86GetPciInfoForEntity(pEnt->index);
184fc5a983dSmrg#if XSERVER_LIBPCIACCESS
185fc5a983dSmrg    /* Need this to unmap */
186fc5a983dSmrg    pNv->pPci = pPci;
187fc5a983dSmrg#endif
188fc5a983dSmrg    primary = xf86IsPrimaryPci(pPci);
189fc5a983dSmrg
190fc5a983dSmrg    /* The ROM size sometimes isn't read correctly, so fix it up here. */
191fc5a983dSmrg#if XSERVER_LIBPCIACCESS
192fc5a983dSmrg    if(pPci->rom_size == 0)
193fc5a983dSmrg        /* The BIOS is 64k */
194fc5a983dSmrg        pPci->rom_size = 64 * 1024;
195fc5a983dSmrg#else
196fc5a983dSmrg    if(pPci->biosSize == 0)
197fc5a983dSmrg        /* The BIOS is 64k */
198fc5a983dSmrg        pPci->biosSize = 16;
199fc5a983dSmrg#endif
200fc5a983dSmrg
201fc5a983dSmrg    pNv->int10 = NULL;
202fc5a983dSmrg    pNv->int10Mode = 0;
203fc5a983dSmrg    if(xf86LoadSubModule(pScrn, "int10")) {
204fc5a983dSmrg        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Initializing int10\n");
205fc5a983dSmrg        pNv->int10 = xf86InitInt10(pEnt->index);
206fc5a983dSmrg    }
207fc5a983dSmrg
208fc5a983dSmrg    if(!pNv->int10) {
209fc5a983dSmrg        if(primary) {
210fc5a983dSmrg            xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
211fc5a983dSmrg                       "Failed to initialize the int10 module; the console "
212fc5a983dSmrg                       "will not be restored.\n");
213fc5a983dSmrg        } else {
214fc5a983dSmrg            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
215fc5a983dSmrg                       "Failed to initialize the int10 module; this screen "
216fc5a983dSmrg                       "will not be initialized.\n");
217fc5a983dSmrg            goto fail;
218fc5a983dSmrg        }
219fc5a983dSmrg    }
220fc5a983dSmrg
221fc5a983dSmrg    if(primary && pNv->int10) {
222fc5a983dSmrg        const xf86Int10InfoPtr int10 = pNv->int10;
223fc5a983dSmrg
224fc5a983dSmrg        /* Get the current video mode */
225fc5a983dSmrg        int10->num = 0x10;
226fc5a983dSmrg        int10->ax = 0x4f03;
227fc5a983dSmrg        int10->bx = int10->cx = int10->dx = 0;
228fc5a983dSmrg        xf86ExecX86int10(int10);
229fc5a983dSmrg        pNv->int10Mode = int10->bx & 0x3fff;
230fc5a983dSmrg        xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Console is VGA mode 0x%x\n",
231fc5a983dSmrg                   pNv->int10Mode);
232fc5a983dSmrg    }
233fc5a983dSmrg
234fc5a983dSmrg    /* Disable VGA access */
23571ba42d0Smrg#ifndef XSERVER_LIBPCIACCESS
236fc5a983dSmrg    xf86SetOperatingState(resVgaIo, pEnt->index, ResUnusedOpr);
237fc5a983dSmrg    xf86SetOperatingState(resVgaMem, pEnt->index, ResDisableOpr);
23871ba42d0Smrg#endif
239fc5a983dSmrg
240fc5a983dSmrg    pScrn->monitor = pScrn->confScreen->monitor;
241fc5a983dSmrg
242fc5a983dSmrg    if(!xf86SetDepthBpp(pScrn, 0, 0, 0, Support32bppFb)) goto fail;
243fc5a983dSmrg    switch (pScrn->depth) {
244fc5a983dSmrg        case 8:
245fc5a983dSmrg        case 15:
246fc5a983dSmrg        case 16:
247fc5a983dSmrg        case 24:
248fc5a983dSmrg            /* OK */
249fc5a983dSmrg            break;
250fc5a983dSmrg        default:
251fc5a983dSmrg            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
252fc5a983dSmrg                    "Given depth (%d) is not supported by this driver\n",
253fc5a983dSmrg                    pScrn->depth);
254fc5a983dSmrg            goto fail;
255fc5a983dSmrg    }
256fc5a983dSmrg    xf86PrintDepthBpp(pScrn);
257fc5a983dSmrg
258fc5a983dSmrg    if(!xf86SetWeight(pScrn, zeros, zeros)) goto fail;
259fc5a983dSmrg    if(!xf86SetDefaultVisual(pScrn, -1)) goto fail;
260fc5a983dSmrg
261fc5a983dSmrg    /* We use a programmable clock */
262fc5a983dSmrg    pScrn->progClock = TRUE;
263fc5a983dSmrg
264fc5a983dSmrg    /* Process options */
265fc5a983dSmrg    xf86CollectOptions(pScrn, NULL);
2666086d97eSmrg    if(!(pNv->Options = malloc(sizeof(G80Options)))) goto fail;
267fc5a983dSmrg    memcpy(pNv->Options, G80Options, sizeof(G80Options));
268fc5a983dSmrg    xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pNv->Options);
269fc5a983dSmrg
270fc5a983dSmrg    from = X_DEFAULT;
271fc5a983dSmrg    pNv->HWCursor = TRUE;
272fc5a983dSmrg    if(xf86GetOptValBool(pNv->Options, OPTION_HW_CURSOR, &pNv->HWCursor))
273fc5a983dSmrg        from = X_CONFIG;
274fc5a983dSmrg    xf86DrvMsg(pScrn->scrnIndex, from, "Using %s cursor\n",
275fc5a983dSmrg               pNv->HWCursor ? "hardware" : "software");
276fc5a983dSmrg    if(xf86ReturnOptValBool(pNv->Options, OPTION_NOACCEL, FALSE)) {
277fc5a983dSmrg        pNv->NoAccel = TRUE;
278fc5a983dSmrg        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Acceleration disabled\n");
279fc5a983dSmrg    }
280fc5a983dSmrg    s = xf86GetOptValString(pNv->Options, OPTION_ACCEL_METHOD);
281fc5a983dSmrg    if(!s || !strcasecmp(s, "xaa"))
282fc5a983dSmrg        pNv->AccelMethod = XAA;
283fc5a983dSmrg    else if(!strcasecmp(s, "exa"))
284fc5a983dSmrg        pNv->AccelMethod = EXA;
285fc5a983dSmrg    else {
286fc5a983dSmrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unrecognized AccelMethod "
287fc5a983dSmrg        "\"%s\".\n", s);
288fc5a983dSmrg        goto fail;
289fc5a983dSmrg    }
290fc5a983dSmrg
291fc5a983dSmrg    pNv->Dither = xf86ReturnOptValBool(pNv->Options, OPTION_FP_DITHER, FALSE);
292fc5a983dSmrg    pNv->AllowDualLink = xf86ReturnOptValBool(pNv->Options, OPTION_ALLOW_DUAL_LINK, FALSE);
293fc5a983dSmrg
294fc5a983dSmrg    /* Set the bits per RGB for 8bpp mode */
295fc5a983dSmrg    if(pScrn->depth == 8)
296fc5a983dSmrg        pScrn->rgbBits = 8;
297fc5a983dSmrg
298fc5a983dSmrg    if(!xf86SetGamma(pScrn, gzeros)) goto fail;
299fc5a983dSmrg
300fc5a983dSmrg    /* Map memory */
301fc5a983dSmrg    pScrn->memPhysBase = MEMBASE(pPci, 1);
302fc5a983dSmrg    pScrn->fbOffset = 0;
303fc5a983dSmrg
304fc5a983dSmrg#if XSERVER_LIBPCIACCESS
305fc5a983dSmrg    err = pci_device_map_range(pPci, pPci->regions[0].base_addr, G80_REG_SIZE,
306fc5a983dSmrg                               PCI_DEV_MAP_FLAG_WRITABLE, &p);
307fc5a983dSmrg    if(err) {
308fc5a983dSmrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
309fc5a983dSmrg                   "Failed to map MMIO registers: %s\n", strerror(err));
310fc5a983dSmrg        goto fail;
311fc5a983dSmrg    }
312fc5a983dSmrg    pNv->reg = p;
313fc5a983dSmrg#else
314fc5a983dSmrg    pcitag = pciTag(pPci->bus, pPci->device, pPci->func);
315fc5a983dSmrg    pNv->reg = xf86MapPciMem(pScrn->scrnIndex,
316fc5a983dSmrg                             VIDMEM_MMIO | VIDMEM_READSIDEEFFECT,
317fc5a983dSmrg                             pcitag, pPci->memBase[0], G80_REG_SIZE);
318fc5a983dSmrg#endif
319fc5a983dSmrg    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "MMIO registers mapped at %p\n",
320fc5a983dSmrg               (void*)pNv->reg);
321fc5a983dSmrg
32271ba42d0Smrg#ifndef XSERVER_LIBPCIACCESS
323fc5a983dSmrg    if(xf86RegisterResources(pEnt->index, NULL, ResExclusive)) {
324fc5a983dSmrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "xf86RegisterResources() found "
325fc5a983dSmrg                   "resource conflicts\n");
326fc5a983dSmrg        goto fail;
327fc5a983dSmrg    }
32871ba42d0Smrg#endif
329fc5a983dSmrg
330fc5a983dSmrg    pNv->architecture = pNv->reg[0] >> 20 & 0x1ff;
331fc5a983dSmrg    tmp = pNv->reg[0x0010020C/4];
332fc5a983dSmrg    pNv->videoRam = pNv->RamAmountKBytes = tmp >> 10 | (tmp & 1) << 22;
333fc5a983dSmrg
334fc5a983dSmrg    /* Determine the size of BAR1 */
335fc5a983dSmrg    /* Some configs have BAR1 < total RAM < 256 MB */
336fc5a983dSmrg#if XSERVER_LIBPCIACCESS
337fc5a983dSmrg    BAR1sizeKB = pPci->regions[1].size / 1024;
338fc5a983dSmrg#else
339fc5a983dSmrg    BAR1sizeKB = 1UL << (pPci->size[1] - 10);
340fc5a983dSmrg#endif
341fc5a983dSmrg    if(BAR1sizeKB > 256 * 1024) {
342fc5a983dSmrg        xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "BAR1 is > 256 MB, which is "
343fc5a983dSmrg                   "probably wrong.  Clamping to 256 MB.\n");
344fc5a983dSmrg        BAR1sizeKB = 256 * 1024;
345fc5a983dSmrg    }
346fc5a983dSmrg
347fc5a983dSmrg    /* Limit videoRam to the size of BAR1 */
348fc5a983dSmrg    if(pNv->videoRam <= 1024 || BAR1sizeKB == 0) {
349fc5a983dSmrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to determine the amount of "
350fc5a983dSmrg                   "available video memory\n");
351fc5a983dSmrg        goto fail;
352fc5a983dSmrg    }
353fc5a983dSmrg    pNv->videoRam -= 1024;
354fc5a983dSmrg    if(pNv->videoRam > BAR1sizeKB)
355fc5a983dSmrg        pNv->videoRam = BAR1sizeKB;
356fc5a983dSmrg
357fc5a983dSmrg    pScrn->videoRam = pNv->videoRam;
358fc5a983dSmrg
359fc5a983dSmrg    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Total video RAM: %.1f MB\n",
360fc5a983dSmrg               pNv->RamAmountKBytes / 1024.0);
361fc5a983dSmrg    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "      BAR1 size: %.1f MB\n",
362fc5a983dSmrg               BAR1sizeKB / 1024.0);
363fc5a983dSmrg    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "  Mapped memory: %.1f MB\n",
364fc5a983dSmrg               pScrn->videoRam / 1024.0);
365fc5a983dSmrg
366fc5a983dSmrg#if XSERVER_LIBPCIACCESS
367fc5a983dSmrg    err = pci_device_map_range(pPci, pPci->regions[1].base_addr,
368fc5a983dSmrg                               pScrn->videoRam * 1024,
369fc5a983dSmrg                               PCI_DEV_MAP_FLAG_WRITABLE |
370fc5a983dSmrg                               PCI_DEV_MAP_FLAG_WRITE_COMBINE,
371fc5a983dSmrg                               &p);
372fc5a983dSmrg    if(err) {
373fc5a983dSmrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
374fc5a983dSmrg                   "Failed to map framebuffer: %s\n", strerror(err));
375fc5a983dSmrg        goto fail;
376fc5a983dSmrg    }
377fc5a983dSmrg    pNv->mem = p;
378fc5a983dSmrg#else
379fc5a983dSmrg    pNv->mem = xf86MapPciMem(pScrn->scrnIndex,
380fc5a983dSmrg                             VIDMEM_MMIO | VIDMEM_READSIDEEFFECT,
381fc5a983dSmrg                             pcitag, pPci->memBase[1], pScrn->videoRam * 1024);
382fc5a983dSmrg#endif
383fc5a983dSmrg    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Linear framebuffer mapped at %p\n",
384fc5a983dSmrg               (void*)pNv->mem);
385fc5a983dSmrg
386fc5a983dSmrg    pNv->table1 = (unsigned const char*)&pNv->reg[0x00800000/4];
387fc5a983dSmrg    tmp = pNv->reg[0x00619F04/4] >> 8;
388fc5a983dSmrg    if(tmp)
389fc5a983dSmrg        pNv->table1 -= ((pNv->RamAmountKBytes << 10) - (tmp << 16));
390fc5a983dSmrg    else
391fc5a983dSmrg        pNv->table1 -= 0x10000;
392fc5a983dSmrg
393fc5a983dSmrg    xf86CrtcConfigInit(pScrn, &randr12_screen_funcs);
394fc5a983dSmrg    xf86CrtcSetSizeRange(pScrn, 320, 200, 8192, 8192);
395fc5a983dSmrg
396fc5a983dSmrg    if(!xf86LoadSubModule(pScrn, "i2c")) goto fail;
397fc5a983dSmrg    if(!xf86LoadSubModule(pScrn, "ddc")) goto fail;
398fc5a983dSmrg
399fc5a983dSmrg    if(!G80DispPreInit(pScrn)) goto fail;
400fc5a983dSmrg    /* Read the DDC routing table and create outputs */
401fc5a983dSmrg    if(!G80CreateOutputs(pScrn)) goto fail;
402fc5a983dSmrg    /* Create the crtcs */
403fc5a983dSmrg    G80DispCreateCrtcs(pScrn);
404fc5a983dSmrg
405fc5a983dSmrg    /* We can grow the desktop if XAA is disabled */
406fc5a983dSmrg    if(!xf86InitialConfiguration(pScrn, pNv->NoAccel || pNv->AccelMethod == EXA)) {
407fc5a983dSmrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
408fc5a983dSmrg            "No valid initial configuration found\n");
409fc5a983dSmrg        goto fail;
410fc5a983dSmrg    }
411fc5a983dSmrg    pScrn->displayWidth = (pScrn->virtualX + 255) & ~255;
412fc5a983dSmrg
413fc5a983dSmrg    if(!xf86RandR12PreInit(pScrn)) {
414fc5a983dSmrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "RandR initialization failure\n");
415fc5a983dSmrg        goto fail;
416fc5a983dSmrg    }
417fc5a983dSmrg    if(!pScrn->modes) {
418fc5a983dSmrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes\n");
419fc5a983dSmrg        goto fail;
420fc5a983dSmrg    }
421fc5a983dSmrg
422fc5a983dSmrg    pScrn->currentMode = pScrn->modes;
423fc5a983dSmrg    xf86PrintModes(pScrn);
424fc5a983dSmrg    xf86SetDpi(pScrn, 0, 0);
425fc5a983dSmrg
426fc5a983dSmrg    /* Load fb */
427fc5a983dSmrg    if(!xf86LoadSubModule(pScrn, "fb")) goto fail;
428fc5a983dSmrg
429fc5a983dSmrg    if(!pNv->NoAccel) {
430fc5a983dSmrg        switch(pNv->AccelMethod) {
431fc5a983dSmrg        case XAA:
432fc5a983dSmrg            if(!xf86LoadSubModule(pScrn, "xaa")) goto fail;
433fc5a983dSmrg            break;
434fc5a983dSmrg        case EXA:
435fc5a983dSmrg            if(!xf86LoadSubModule(pScrn, "exa")) goto fail;
436fc5a983dSmrg            break;
437fc5a983dSmrg        }
438fc5a983dSmrg    }
439fc5a983dSmrg
440fc5a983dSmrg    /* Load ramdac if needed */
441fc5a983dSmrg    if(pNv->HWCursor) {
442fc5a983dSmrg        if(!xf86LoadSubModule(pScrn, "ramdac")) {
443fc5a983dSmrg            xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to load ramdac. "
444fc5a983dSmrg                       "Falling back to software cursor.\n");
445fc5a983dSmrg            pNv->HWCursor = FALSE;
446bd2f6fc9Smrg	}
447fc5a983dSmrg    }
448fc5a983dSmrg
449fc5a983dSmrg    return TRUE;
450fc5a983dSmrg
451fc5a983dSmrgfail:
452fc5a983dSmrg    if(pNv->int10) xf86FreeInt10(pNv->int10);
453fc5a983dSmrg    G80FreeRec(pScrn);
454fc5a983dSmrg    return FALSE;
455fc5a983dSmrg}
456fc5a983dSmrg
457fc5a983dSmrg/*
458fc5a983dSmrg * Initialize the display and set the current mode.
459fc5a983dSmrg */
460fc5a983dSmrgstatic Bool
461fc5a983dSmrgAcquireDisplay(ScrnInfoPtr pScrn)
462fc5a983dSmrg{
463fc5a983dSmrg    if(!G80DispInit(pScrn))
464fc5a983dSmrg        return FALSE;
465fc5a983dSmrg    if(!G80CursorAcquire(pScrn))
466fc5a983dSmrg        return FALSE;
467fc5a983dSmrg    xf86SetDesiredModes(pScrn);
468fc5a983dSmrg
469fc5a983dSmrg    return TRUE;
470fc5a983dSmrg}
471fc5a983dSmrg
472fc5a983dSmrg/*
473fc5a983dSmrg * Tear down the display and restore the console mode.
474fc5a983dSmrg */
475fc5a983dSmrgstatic Bool
476fc5a983dSmrgReleaseDisplay(ScrnInfoPtr pScrn)
477fc5a983dSmrg{
478fc5a983dSmrg    G80Ptr pNv = G80PTR(pScrn);
479fc5a983dSmrg
480fc5a983dSmrg    G80CursorRelease(pScrn);
481fc5a983dSmrg    G80DispShutdown(pScrn);
482fc5a983dSmrg
483fc5a983dSmrg    if(pNv->int10 && pNv->int10Mode) {
484fc5a983dSmrg        xf86Int10InfoPtr int10 = pNv->int10;
485fc5a983dSmrg
486fc5a983dSmrg        /* Use int10 to restore the console mode */
487fc5a983dSmrg        int10->num = 0x10;
488fc5a983dSmrg        int10->ax = 0x4f02;
489fc5a983dSmrg        int10->bx = pNv->int10Mode | 0x8000;
490fc5a983dSmrg        int10->cx = int10->dx = 0;
491fc5a983dSmrg        xf86ExecX86int10(int10);
492fc5a983dSmrg    }
493fc5a983dSmrg
494fc5a983dSmrg    return TRUE;
495fc5a983dSmrg}
496fc5a983dSmrg
497fc5a983dSmrgstatic Bool
498fc5a983dSmrgG80CloseScreen(int scrnIndex, ScreenPtr pScreen)
499fc5a983dSmrg{
500fc5a983dSmrg    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
501fc5a983dSmrg    G80Ptr pNv = G80PTR(pScrn);
502fc5a983dSmrg
503fc5a983dSmrg    if(pScrn->vtSema)
504fc5a983dSmrg        ReleaseDisplay(pScrn);
505fc5a983dSmrg
506fc5a983dSmrg    if(pNv->xaa)
507fc5a983dSmrg        XAADestroyInfoRec(pNv->xaa);
508fc5a983dSmrg    if(pNv->exa) {
509fc5a983dSmrg        if(pNv->exaScreenArea) {
510fc5a983dSmrg            exaOffscreenFree(pScreen, pNv->exaScreenArea);
511fc5a983dSmrg            pNv->exaScreenArea = NULL;
512fc5a983dSmrg        }
513fc5a983dSmrg        exaDriverFini(pScrn->pScreen);
514fc5a983dSmrg    }
515fc5a983dSmrg    xf86_cursors_fini(pScreen);
516fc5a983dSmrg
517fc5a983dSmrg    if(xf86ServerIsExiting()) {
518fc5a983dSmrg        if(pNv->int10) xf86FreeInt10(pNv->int10);
519fc5a983dSmrg#if XSERVER_LIBPCIACCESS
520fc5a983dSmrg        pci_device_unmap_range(pNv->pPci, pNv->mem, pNv->videoRam * 1024);
521fc5a983dSmrg        pci_device_unmap_range(pNv->pPci, (void*)pNv->reg, G80_REG_SIZE);
522fc5a983dSmrg#else
523fc5a983dSmrg        xf86UnMapVidMem(pScrn->scrnIndex, pNv->mem, pNv->videoRam * 1024);
524fc5a983dSmrg        xf86UnMapVidMem(pScrn->scrnIndex, (void*)pNv->reg, G80_REG_SIZE);
525fc5a983dSmrg#endif
526fc5a983dSmrg        pNv->reg = NULL;
527fc5a983dSmrg        pNv->mem = NULL;
528fc5a983dSmrg    }
529fc5a983dSmrg
530fc5a983dSmrg    pScrn->vtSema = FALSE;
531fc5a983dSmrg    pScreen->CloseScreen = pNv->CloseScreen;
532fc5a983dSmrg    pScreen->BlockHandler = pNv->BlockHandler;
533fc5a983dSmrg    return (*pScreen->CloseScreen)(scrnIndex, pScreen);
534fc5a983dSmrg}
535fc5a983dSmrg
536fc5a983dSmrgstatic void
537fc5a983dSmrgG80BlockHandler(int i, pointer blockData, pointer pTimeout, pointer pReadmask)
538fc5a983dSmrg{
539fc5a983dSmrg    ScreenPtr pScreen = screenInfo.screens[i];
540fc5a983dSmrg    ScrnInfoPtr pScrnInfo = xf86Screens[i];
541fc5a983dSmrg    G80Ptr pNv = G80PTR(pScrnInfo);
542fc5a983dSmrg
543fc5a983dSmrg    if(pNv->DMAKickoffCallback)
544fc5a983dSmrg        (*pNv->DMAKickoffCallback)(pScrnInfo);
545fc5a983dSmrg
546fc5a983dSmrg    G80OutputResetCachedStatus(pScrnInfo);
547fc5a983dSmrg
548fc5a983dSmrg    pScreen->BlockHandler = pNv->BlockHandler;
549fc5a983dSmrg    (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask);
550fc5a983dSmrg    pScreen->BlockHandler = G80BlockHandler;
551fc5a983dSmrg}
552fc5a983dSmrg
553fc5a983dSmrgstatic Bool
554fc5a983dSmrgG80SaveScreen(ScreenPtr pScreen, int mode)
555fc5a983dSmrg{
556fc5a983dSmrg    return FALSE;
557fc5a983dSmrg}
558fc5a983dSmrg
559fc5a983dSmrgstatic void
560fc5a983dSmrgG80InitHW(ScrnInfoPtr pScrn)
561fc5a983dSmrg{
562fc5a983dSmrg    G80Ptr pNv = G80PTR(pScrn);
563fc5a983dSmrg    CARD32 bar0_pramin = 0;
564fc5a983dSmrg    const int pitch = pScrn->displayWidth * (pScrn->bitsPerPixel / 8);
565fc5a983dSmrg    volatile CARD32 *p;
566fc5a983dSmrg
567fc5a983dSmrg    /* Clear registers */
568fc5a983dSmrg    for(p = &pNv->reg[0x00700000/4]; p < (const CARD32*)pNv->table1; p++)
569fc5a983dSmrg        *p = 0;
570fc5a983dSmrg
571fc5a983dSmrg    bar0_pramin = pNv->reg[0x00001700/4] << 16;
572fc5a983dSmrg
573fc5a983dSmrg    pNv->reg[0x00000200/4] = 0xffff00ff;
574fc5a983dSmrg    pNv->reg[0x00000200/4] = 0xffffffff;
575fc5a983dSmrg    pNv->reg[0x00002100/4] = 0xffffffff;
576fc5a983dSmrg    pNv->reg[0x0000250c/4] = 0x6f3cfc34;
577fc5a983dSmrg    pNv->reg[0x00400804/4] = 0xc0000000;
578fc5a983dSmrg    pNv->reg[0x00406800/4] = 0xc0000000;
579fc5a983dSmrg    pNv->reg[0x00400c04/4] = 0xc0000000;
580fc5a983dSmrg    pNv->reg[0x00401800/4] = 0xc0000000;
581fc5a983dSmrg    pNv->reg[0x00405018/4] = 0xc0000000;
582fc5a983dSmrg    pNv->reg[0x00402000/4] = 0xc0000000;
583fc5a983dSmrg    pNv->reg[0x00400108/4] = 0xffffffff;
584fc5a983dSmrg    pNv->reg[0x00400100/4] = 0xffffffff;
585fc5a983dSmrg
586fc5a983dSmrg    if(pNv->architecture != 0x50) {
587fc5a983dSmrg        pNv->reg[0x00700000/4] = 0x00000001;
588fc5a983dSmrg        pNv->reg[0x00700004/4] = bar0_pramin + 0x00200;
589fc5a983dSmrg        pNv->reg[0x00700020/4] = 0x00190002;
590fc5a983dSmrg        pNv->reg[0x00700024/4] = bar0_pramin + 0x7ffff;
591fc5a983dSmrg        pNv->reg[0x00700028/4] = bar0_pramin + 0x20000;
592fc5a983dSmrg        pNv->reg[0x00700034/4] = 0x00010000;
593fc5a983dSmrg    } else {
594fc5a983dSmrg        pNv->reg[0x00700200/4] = 0x00190002;
595fc5a983dSmrg        pNv->reg[0x00700204/4] = bar0_pramin + 0x7ffff;
596fc5a983dSmrg        pNv->reg[0x00700208/4] = bar0_pramin + 0x20000;
597fc5a983dSmrg        pNv->reg[0x00700214/4] = 0x00010000;
598fc5a983dSmrg    }
599fc5a983dSmrg
600fc5a983dSmrg    pNv->reg[0x00710004/4] = 0x00100642;
601fc5a983dSmrg    pNv->reg[0x00710008/4] = 0x80000011;
602fc5a983dSmrg    pNv->reg[0x0071000c/4] = 0x00000644;
603fc5a983dSmrg    pNv->reg[0x00710010/4] = 0x80000012;
604fc5a983dSmrg    pNv->reg[0x00710014/4] = 0x00100646;
605fc5a983dSmrg    pNv->reg[0x00710018/4] = 0x80000013;
606fc5a983dSmrg    pNv->reg[0x0071001c/4] = 0x00100648;
607fc5a983dSmrg    pNv->reg[0x00710020/4] = 0x80000014;
608fc5a983dSmrg    pNv->reg[0x00710024/4] = 0x0000064a;
609fc5a983dSmrg    pNv->reg[0x00706420/4] = 0x00190030;
610fc5a983dSmrg    pNv->reg[0x00706434/4] = 0x00010000;
611fc5a983dSmrg    pNv->reg[0x00706440/4] = 0x0019003d;
612fc5a983dSmrg    pNv->reg[0x00706444/4] = (pNv->videoRam << 10) - 0x4001;
613fc5a983dSmrg    pNv->reg[0x00706448/4] = (pNv->videoRam << 10) - G80_RESERVED_VIDMEM;
614fc5a983dSmrg    pNv->reg[0x00706454/4] = 0x00010000;
615fc5a983dSmrg    pNv->reg[0x00706460/4] = 0x0000502d;
616fc5a983dSmrg    pNv->reg[0x00706474/4] = 0x00010000;
61771ba42d0Smrg    if(pNv->architecture == 0xaa || pNv->architecture == 0xac) {
61871ba42d0Smrg        uint64_t base = (uint64_t)pNv->reg[0x00100E10/4] << 12;
61971ba42d0Smrg        size_t size = (uint64_t)pNv->reg[0x00100E14/4] << 12;
62071ba42d0Smrg        uint64_t limit = base + size - G80_RESERVED_VIDMEM;
62171ba42d0Smrg
62271ba42d0Smrg        pNv->reg[0x00706480/4] = 0x1a003d;
62371ba42d0Smrg        pNv->reg[0x00706484/4] = limit;
62471ba42d0Smrg        pNv->reg[0x00706488/4] = base;
62571ba42d0Smrg        pNv->reg[0x0070648c/4] = base >> 32 | ((limit >> 8) & 0xff000000);
62671ba42d0Smrg    } else {
62771ba42d0Smrg        pNv->reg[0x00706480/4] = 0x0019003d;
62871ba42d0Smrg        pNv->reg[0x00706484/4] = (pNv->videoRam << 10) - G80_RESERVED_VIDMEM;
62971ba42d0Smrg        pNv->reg[0x00706494/4] = 0x00010000;
63071ba42d0Smrg    }
631fc5a983dSmrg    pNv->reg[0x007064a0/4] = 0x0019003d;
632fc5a983dSmrg    pNv->reg[0x007064a4/4] = bar0_pramin + 0x1100f;
633fc5a983dSmrg    pNv->reg[0x007064a8/4] = bar0_pramin + 0x11000;
634fc5a983dSmrg    pNv->reg[0x007064b4/4] = 0x00010000;
635fc5a983dSmrg
636fc5a983dSmrg    if(pNv->architecture != 0x50) {
637fc5a983dSmrg        pNv->reg[0x00002604/4] = 0x80000002 | (bar0_pramin >> 8);
638fc5a983dSmrg    } else {
639fc5a983dSmrg        pNv->reg[0x00002604/4] = 0x80000000 | (bar0_pramin >> 12);
640fc5a983dSmrg    }
641fc5a983dSmrg
642fc5a983dSmrg    pNv->reg[0x00003224/4] = 0x000f0078;
643fc5a983dSmrg    pNv->reg[0x0000322c/4] = 0x00000644;
64471ba42d0Smrg    pNv->reg[0x00003234/4] = G80_RESERVED_VIDMEM - 0x6001;
645fc5a983dSmrg    pNv->reg[0x00003254/4] = 0x00000001;
646fc5a983dSmrg    pNv->reg[0x00002210/4] = 0x1c001000;
647fc5a983dSmrg
648fc5a983dSmrg    if(pNv->architecture != 0x50) {
649fc5a983dSmrg        pNv->reg[0x0000340c/4] = (bar0_pramin + 0x1000) >> 10;
650fc5a983dSmrg        pNv->reg[0x00003410/4] = (bar0_pramin >> 12);
651fc5a983dSmrg    }
652fc5a983dSmrg
653fc5a983dSmrg    pNv->reg[0x00400824/4] = 0x00004000;
654fc5a983dSmrg    pNv->reg[0x00400784/4] = 0x80000000 | (bar0_pramin >> 12);
655fc5a983dSmrg    pNv->reg[0x00400320/4] = 0x00000004;
656fc5a983dSmrg    pNv->reg[0x0040032C/4] = 0x80000000 | (bar0_pramin >> 12);
657fc5a983dSmrg    pNv->reg[0x00400500/4] = 0x00010001;
658fc5a983dSmrg    pNv->reg[0x00003250/4] = 0x00000001;
659fc5a983dSmrg    pNv->reg[0x00003200/4] = 0x00000001;
660fc5a983dSmrg    pNv->reg[0x00003220/4] = 0x00001001;
661fc5a983dSmrg    pNv->reg[0x00003204/4] = 0x00010001;
662fc5a983dSmrg
663fc5a983dSmrg    pNv->dmaBase = (CARD32*)(pNv->mem + (pNv->videoRam << 10) -
664fc5a983dSmrg        G80_RESERVED_VIDMEM);
665fc5a983dSmrg    memset(pNv->dmaBase, 0, SKIPS*4);
666fc5a983dSmrg
667fc5a983dSmrg    pNv->dmaPut = 0;
668fc5a983dSmrg    pNv->dmaCurrent = SKIPS;
66971ba42d0Smrg    pNv->dmaMax = (G80_RESERVED_VIDMEM - 0x6000) / 4 - 2;
670fc5a983dSmrg    pNv->dmaFree = pNv->dmaMax - pNv->dmaCurrent;
671fc5a983dSmrg
672fc5a983dSmrg    G80DmaStart(pNv, 0, 1);
673fc5a983dSmrg    G80DmaNext (pNv, 0x80000012);
674fc5a983dSmrg    G80DmaStart(pNv, 0x180, 3);
675fc5a983dSmrg    G80DmaNext (pNv, 0x80000014);
676fc5a983dSmrg    G80DmaNext (pNv, 0x80000013);
677fc5a983dSmrg    G80DmaNext (pNv, 0x80000013);
678fc5a983dSmrg    G80DmaStart(pNv, 0x200, 2);
679fc5a983dSmrg    switch(pScrn->depth) {
680fc5a983dSmrg        case  8: G80DmaNext (pNv, 0x000000f3); break;
681fc5a983dSmrg        case 15: G80DmaNext (pNv, 0x000000f8); break;
682fc5a983dSmrg        case 16: G80DmaNext (pNv, 0x000000e8); break;
683fc5a983dSmrg        case 24: G80DmaNext (pNv, 0x000000e6); break;
684fc5a983dSmrg    }
685fc5a983dSmrg    G80DmaNext (pNv, 0x00000001);
686fc5a983dSmrg    G80DmaStart(pNv, 0x214, 5);
687fc5a983dSmrg    G80DmaNext (pNv, pitch);
688fc5a983dSmrg    G80DmaNext (pNv, pitch);
689fc5a983dSmrg    G80DmaNext (pNv, pNv->offscreenHeight);
690fc5a983dSmrg    G80DmaNext (pNv, 0x00000000);
691fc5a983dSmrg    G80DmaNext (pNv, 0x00000000);
692fc5a983dSmrg    G80DmaStart(pNv, 0x230, 2);
693fc5a983dSmrg    switch(pScrn->depth) {
694fc5a983dSmrg        case  8: G80DmaNext (pNv, 0x000000f3); break;
695fc5a983dSmrg        case 15: G80DmaNext (pNv, 0x000000f8); break;
696fc5a983dSmrg        case 16: G80DmaNext (pNv, 0x000000e8); break;
697fc5a983dSmrg        case 24: G80DmaNext (pNv, 0x000000e6); break;
698fc5a983dSmrg    }
699fc5a983dSmrg    G80DmaNext (pNv, 0x00000001);
700fc5a983dSmrg    G80DmaStart(pNv, 0x244, 5);
701fc5a983dSmrg    G80DmaNext (pNv, pitch);
702fc5a983dSmrg    G80DmaNext (pNv, pitch);
703fc5a983dSmrg    G80DmaNext (pNv, pNv->offscreenHeight);
704fc5a983dSmrg    G80DmaNext (pNv, 0x00000000);
705fc5a983dSmrg    G80DmaNext (pNv, 0x00000000);
706fc5a983dSmrg    G80DmaStart(pNv, 0x260, 1);
707fc5a983dSmrg    G80DmaNext (pNv, 0x00000001);
708fc5a983dSmrg    G80DmaStart(pNv, 0x290, 1);
709fc5a983dSmrg    G80DmaNext (pNv, 1);
710fc5a983dSmrg    G80DmaStart(pNv, 0x29c, 1);
711fc5a983dSmrg    G80DmaNext (pNv, 0);
712fc5a983dSmrg    G80DmaStart(pNv, 0x2e8, 2);
713fc5a983dSmrg    switch(pScrn->depth) {
714fc5a983dSmrg        case  8: G80DmaNext (pNv, 3); break;
715fc5a983dSmrg        case 15: G80DmaNext (pNv, 1); break;
716fc5a983dSmrg        case 16: G80DmaNext (pNv, 0); break;
717fc5a983dSmrg        case 24: G80DmaNext (pNv, 2); break;
718fc5a983dSmrg    }
719fc5a983dSmrg    G80DmaNext (pNv, 1);
720fc5a983dSmrg    G80DmaStart(pNv, 0x584, 1);
721fc5a983dSmrg    switch(pScrn->depth) {
722fc5a983dSmrg        case  8: G80DmaNext (pNv, 0xf3); break;
723fc5a983dSmrg        case 15: G80DmaNext (pNv, 0xf8); break;
724fc5a983dSmrg        case 16: G80DmaNext (pNv, 0xe8); break;
725fc5a983dSmrg        case 24: G80DmaNext (pNv, 0xe6); break;
726fc5a983dSmrg    }
727fc5a983dSmrg    G80DmaStart(pNv, 0x58c, 1);
728fc5a983dSmrg    G80DmaNext (pNv, 0x111);
729fc5a983dSmrg    G80DmaStart(pNv, 0x804, 1);
730fc5a983dSmrg    switch(pScrn->depth) {
731fc5a983dSmrg        case  8: G80DmaNext (pNv, 0xf3); break;
732fc5a983dSmrg        case 15: G80DmaNext (pNv, 0xf8); break;
733fc5a983dSmrg        case 16: G80DmaNext (pNv, 0xe8); break;
734fc5a983dSmrg        case 24: G80DmaNext (pNv, 0xe6); break;
735fc5a983dSmrg    }
736fc5a983dSmrg
737fc5a983dSmrg    pNv->currentRop = ~0; /* Set to something invalid */
738fc5a983dSmrg}
739fc5a983dSmrg
740fc5a983dSmrgstatic Bool
741fc5a983dSmrgG80ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
742fc5a983dSmrg{
743fc5a983dSmrg    ScrnInfoPtr pScrn;
744fc5a983dSmrg    G80Ptr pNv;
745fc5a983dSmrg    CARD32 pitch;
746fc5a983dSmrg    int visualMask, i;
747fc5a983dSmrg    BoxRec AvailFBArea;
748fc5a983dSmrg
749fc5a983dSmrg    /* First get the ScrnInfoRec */
750fc5a983dSmrg    pScrn = xf86Screens[pScreen->myNum];
751fc5a983dSmrg    pNv = G80PTR(pScrn);
752fc5a983dSmrg
753fc5a983dSmrg    pScrn->vtSema = TRUE;
754fc5a983dSmrg
755fc5a983dSmrg    /* DIX visual init */
756fc5a983dSmrg    miClearVisualTypes();
757fc5a983dSmrg    visualMask = miGetDefaultVisualMask(pScrn->depth);
758fc5a983dSmrg    if(!miSetVisualTypes(pScrn->depth, visualMask, 8, pScrn->defaultVisual))
759fc5a983dSmrg        return FALSE;
760fc5a983dSmrg    if(!miSetPixmapDepths())
761fc5a983dSmrg        return FALSE;
762fc5a983dSmrg
763fc5a983dSmrg    /* pad the screen pitch to 256 bytes */
764fc5a983dSmrg    pitch = pScrn->displayWidth * (pScrn->bitsPerPixel / 8);
765fc5a983dSmrg
766fc5a983dSmrg    /* fb init */
767fc5a983dSmrg    if(!fbScreenInit(pScreen, pNv->mem,
768fc5a983dSmrg                     pScrn->virtualX, pScrn->virtualY,
769fc5a983dSmrg                     pScrn->xDpi, pScrn->yDpi,
770fc5a983dSmrg                     pScrn->displayWidth, pScrn->bitsPerPixel))
771fc5a983dSmrg        return FALSE;
772fc5a983dSmrg
773fc5a983dSmrg    if(pScrn->bitsPerPixel > 8) {
774fc5a983dSmrg        VisualPtr visual;
775fc5a983dSmrg
776fc5a983dSmrg        /* Fixup RGB ordering */
777fc5a983dSmrg        visual = pScreen->visuals + pScreen->numVisuals;
778fc5a983dSmrg        while(--visual >= pScreen->visuals) {
779fc5a983dSmrg            if((visual->class | DynamicClass) == DirectColor) {
780fc5a983dSmrg                visual->offsetRed = pScrn->offset.red;
781fc5a983dSmrg                visual->offsetGreen = pScrn->offset.green;
782fc5a983dSmrg                visual->offsetBlue = pScrn->offset.blue;
783fc5a983dSmrg                visual->redMask = pScrn->mask.red;
784fc5a983dSmrg                visual->greenMask = pScrn->mask.green;
785fc5a983dSmrg                visual->blueMask = pScrn->mask.blue;
786fc5a983dSmrg            }
787fc5a983dSmrg        }
788fc5a983dSmrg    }
789fc5a983dSmrg
790fc5a983dSmrg    fbPictureInit(pScreen, 0, 0);
791fc5a983dSmrg
792fc5a983dSmrg    xf86SetBlackWhitePixels(pScreen);
793fc5a983dSmrg
794fc5a983dSmrg    pNv->offscreenHeight = ((pNv->videoRam << 10) - G80_RESERVED_VIDMEM) / pitch;
795fc5a983dSmrg    if(pNv->offscreenHeight > 32767) pNv->offscreenHeight = 32767;
796fc5a983dSmrg    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
797fc5a983dSmrg        "%.2f MB available for offscreen pixmaps\n",
798fc5a983dSmrg        (pNv->offscreenHeight - pScrn->virtualY) * pitch / 1024.0 / 1024.0);
799fc5a983dSmrg
800fc5a983dSmrg    AvailFBArea.x1 = 0;
801fc5a983dSmrg    AvailFBArea.y1 = 0;
802fc5a983dSmrg    AvailFBArea.x2 = pScrn->displayWidth;
803fc5a983dSmrg    AvailFBArea.y2 = pNv->offscreenHeight;
804fc5a983dSmrg    xf86InitFBManager(pScreen, &AvailFBArea);
805fc5a983dSmrg
806fc5a983dSmrg    pNv->reg[0x00001708/4] = 0;
807fc5a983dSmrg    for(i = 0; i < 8; i++)
808fc5a983dSmrg        pNv->reg[0x00001900/4 + i] = 0;
809fc5a983dSmrg
810fc5a983dSmrg    if(!pNv->NoAccel) {
811fc5a983dSmrg        G80InitHW(pScrn);
812fc5a983dSmrg        switch(pNv->AccelMethod) {
813fc5a983dSmrg        case XAA:
814fc5a983dSmrg            if(!G80XAAInit(pScreen)) {
815fc5a983dSmrg                xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
816fc5a983dSmrg                           "XAA hardware acceleration initialization failed\n");
817fc5a983dSmrg                return FALSE;
818fc5a983dSmrg            }
819fc5a983dSmrg            break;
820fc5a983dSmrg        case EXA:
821fc5a983dSmrg            if(!G80ExaInit(pScreen, pScrn)) {
822fc5a983dSmrg                xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
823fc5a983dSmrg                           "EXA hardware acceleration initialization failed\n");
824fc5a983dSmrg                return FALSE;
825fc5a983dSmrg            }
826fc5a983dSmrg            break;
827fc5a983dSmrg        }
828fc5a983dSmrg    }
829fc5a983dSmrg
830fc5a983dSmrg    miInitializeBackingStore(pScreen);
831fc5a983dSmrg    xf86SetBackingStore(pScreen);
832fc5a983dSmrg    xf86SetSilkenMouse(pScreen);
833fc5a983dSmrg
834fc5a983dSmrg    /* Initialize software cursor.
835fc5a983dSmrg       Must precede creation of the default colormap */
836fc5a983dSmrg    miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
837fc5a983dSmrg
83871ba42d0Smrg    if(!xf86CrtcScreenInit(pScreen))
83971ba42d0Smrg        return FALSE;
84071ba42d0Smrg
841fc5a983dSmrg    /* Initialize default colormap */
842fc5a983dSmrg    if(!miCreateDefColormap(pScreen))
843fc5a983dSmrg        return FALSE;
844fc5a983dSmrg
845fc5a983dSmrg    /* Initialize colormap layer.
846fc5a983dSmrg       Must follow initialization of the default colormap */
847fc5a983dSmrg    if(!xf86HandleColormaps(pScreen, 256, 8, G80LoadPalette, NULL,
848fc5a983dSmrg                            CMAP_PALETTED_TRUECOLOR))
849fc5a983dSmrg        return FALSE;
850fc5a983dSmrg
851fc5a983dSmrg    xf86DPMSInit(pScreen, xf86DPMSSet, 0);
852fc5a983dSmrg
853fc5a983dSmrg    /* Clear the screen */
854fc5a983dSmrg    if(pNv->xaa) {
855fc5a983dSmrg        /* Use the acceleration engine */
856fc5a983dSmrg        pNv->xaa->SetupForSolidFill(pScrn, 0, GXcopy, ~0);
857fc5a983dSmrg        pNv->xaa->SubsequentSolidFillRect(pScrn,
858fc5a983dSmrg            0, 0, pScrn->displayWidth, pNv->offscreenHeight);
859fc5a983dSmrg        G80DmaKickoff(pNv);
860fc5a983dSmrg    } else {
861fc5a983dSmrg        /* Use a slow software clear path */
862fc5a983dSmrg        memset(pNv->mem, 0, pitch * pNv->offscreenHeight);
863fc5a983dSmrg    }
864fc5a983dSmrg
865fc5a983dSmrg    /* Initialize the display */
866fc5a983dSmrg    if(!AcquireDisplay(pScrn))
867fc5a983dSmrg        return FALSE;
868fc5a983dSmrg
869f3561b8bSmrg    /* Initialize hardware cursor.  Must follow software cursor initialization. */
870f3561b8bSmrg    if(pNv->HWCursor && !G80CursorInit(pScreen)) {
871f3561b8bSmrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
872f3561b8bSmrg                   "Hardware cursor initialization failed\n");
873f3561b8bSmrg        pNv->HWCursor = FALSE;
874f3561b8bSmrg    }
875f3561b8bSmrg
876fc5a983dSmrg    pScreen->SaveScreen = G80SaveScreen;
877fc5a983dSmrg
878fc5a983dSmrg    pNv->CloseScreen = pScreen->CloseScreen;
879fc5a983dSmrg    pScreen->CloseScreen = G80CloseScreen;
880fc5a983dSmrg
881fc5a983dSmrg    pNv->BlockHandler = pScreen->BlockHandler;
882fc5a983dSmrg    pScreen->BlockHandler = G80BlockHandler;
883fc5a983dSmrg
884fc5a983dSmrg    return TRUE;
885fc5a983dSmrg}
886fc5a983dSmrg
887fc5a983dSmrgstatic void
888fc5a983dSmrgG80FreeScreen(int scrnIndex, int flags)
889fc5a983dSmrg{
890fc5a983dSmrg    G80FreeRec(xf86Screens[scrnIndex]);
891fc5a983dSmrg}
892fc5a983dSmrg
893fc5a983dSmrgstatic Bool
894fc5a983dSmrgG80SwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
895fc5a983dSmrg{
896fc5a983dSmrg    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
897fc5a983dSmrg    return xf86SetSingleMode(pScrn, mode, RR_Rotate_0);
898fc5a983dSmrg}
899fc5a983dSmrg
900fc5a983dSmrgstatic void
901fc5a983dSmrgG80AdjustFrame(int scrnIndex, int x, int y, int flags)
902fc5a983dSmrg{
903fc5a983dSmrg}
904fc5a983dSmrg
905fc5a983dSmrgstatic Bool
906fc5a983dSmrgG80EnterVT(int scrnIndex, int flags)
907fc5a983dSmrg{
908fc5a983dSmrg    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
909fc5a983dSmrg    G80Ptr pNv = G80PTR(pScrn);
910fc5a983dSmrg
911fc5a983dSmrg    /* Reinit the hardware */
912fc5a983dSmrg    if(pNv->xaa)
913fc5a983dSmrg        G80InitHW(pScrn);
914fc5a983dSmrg
915fc5a983dSmrg    if(!AcquireDisplay(pScrn))
916fc5a983dSmrg        return FALSE;
917fc5a983dSmrg
918fc5a983dSmrg    return TRUE;
919fc5a983dSmrg}
920fc5a983dSmrg
921fc5a983dSmrgstatic void
922fc5a983dSmrgG80LeaveVT(int scrnIndex, int flags)
923fc5a983dSmrg{
924fc5a983dSmrg    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
925fc5a983dSmrg
926fc5a983dSmrg    ReleaseDisplay(pScrn);
927fc5a983dSmrg}
928fc5a983dSmrg
929fc5a983dSmrgBool G80GetScrnInfoRec(PciChipsets *chips, int chip)
930fc5a983dSmrg{
931fc5a983dSmrg    ScrnInfoPtr pScrn;
932fc5a983dSmrg
933fc5a983dSmrg    pScrn = xf86ConfigPciEntity(NULL, 0, chip,
934fc5a983dSmrg                                chips, NULL, NULL, NULL,
935fc5a983dSmrg                                NULL, NULL);
936fc5a983dSmrg
937fc5a983dSmrg    if(!pScrn) return FALSE;
938fc5a983dSmrg
939fc5a983dSmrg    pScrn->driverVersion    = NV_VERSION;
940fc5a983dSmrg    pScrn->driverName       = NV_DRIVER_NAME;
941fc5a983dSmrg    pScrn->name             = NV_NAME;
942fc5a983dSmrg
943fc5a983dSmrg    pScrn->PreInit          = G80PreInit;
944fc5a983dSmrg    pScrn->ScreenInit       = G80ScreenInit;
945fc5a983dSmrg    pScrn->SwitchMode       = G80SwitchMode;
946fc5a983dSmrg    pScrn->AdjustFrame      = G80AdjustFrame;
947fc5a983dSmrg    pScrn->EnterVT          = G80EnterVT;
948fc5a983dSmrg    pScrn->LeaveVT          = G80LeaveVT;
949fc5a983dSmrg    pScrn->FreeScreen       = G80FreeScreen;
950fc5a983dSmrg    // pScrn->ValidMode        = G80ValidMode;
951fc5a983dSmrg
952fc5a983dSmrg    return TRUE;
953fc5a983dSmrg}
954