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