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