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