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