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