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