1/*
2 * Copyright 1999, 2000 ATI Technologies Inc., Markham, Ontario,
3 *                      Precision Insight, Inc., Cedar Park, Texas, and
4 *                      VA Linux Systems Inc., Fremont, California.
5 *
6 * All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining
9 * a copy of this software and associated documentation files (the
10 * "Software"), to deal in the Software without restriction, including
11 * without limitation on the rights to use, copy, modify, merge,
12 * publish, distribute, sublicense, and/or sell copies of the Software,
13 * and to permit persons to whom the Software is furnished to do so,
14 * subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice (including the
17 * next paragraph) shall be included in all copies or substantial
18 * portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 * NON-INFRINGEMENT.  IN NO EVENT SHALL ATI, PRECISION INSIGHT, VA LINUX
24 * SYSTEMS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
25 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
26 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 * OTHER DEALINGS IN THE SOFTWARE.
28 */
29
30#ifdef HAVE_CONFIG_H
31#include "config.h"
32#endif
33
34#include <string.h>
35#include <stdio.h>
36
37/*
38 * Authors:
39 *   Kevin E. Martin <martin@valinux.com>
40 *   Rickard E. Faith <faith@valinux.com>
41 *   Daryll Strauss <daryll@valinux.com>
42 *   Gareth Hughes <gareth@valinux.com>
43 *
44 */
45
46				/* Driver data structures */
47#include "r128.h"
48#include "r128_dri.h"
49#include "r128_common.h"
50#include "r128_reg.h"
51#include "r128_sarea.h"
52#include "r128_version.h"
53
54				/* X and server generic header files */
55#include "xf86.h"
56#include "windowstr.h"
57
58#include "shadowfb.h"
59				/* DRI/DRM definitions */
60#define _XF86DRI_SERVER_
61#include "sarea.h"
62
63static size_t r128_drm_page_size;
64
65static void R128DRITransitionTo2d(ScreenPtr pScreen);
66static void R128DRITransitionTo3d(ScreenPtr pScreen);
67static void R128DRITransitionMultiToSingle3d(ScreenPtr pScreen);
68static void R128DRITransitionSingleToMulti3d(ScreenPtr pScreen);
69
70static void R128DRIRefreshArea(ScrnInfoPtr pScrn, int num, BoxPtr pbox);
71
72/* Create the Rage 128-specific context information */
73static Bool R128CreateContext(ScreenPtr pScreen, VisualPtr visual,
74			      drm_context_t hwContext, void *pVisualConfigPriv,
75			      DRIContextType contextStore)
76{
77    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
78    R128InfoPtr info = R128PTR(pScrn);
79
80    info->drmCtx = hwContext;
81    return TRUE;
82}
83
84/* Destroy the Rage 128-specific context information */
85static void R128DestroyContext(ScreenPtr pScreen, drm_context_t hwContext,
86			       DRIContextType contextStore)
87{
88    /* Nothing yet */
89}
90
91/* Called when the X server is woken up to allow the last client's
92   context to be saved and the X server's context to be loaded.  This is
93   not necessary for the Rage 128 since the client detects when it's
94   context is not currently loaded and then load's it itself.  Since the
95   registers to start and stop the CCE are privileged, only the X server
96   can start/stop the engine. */
97static void R128EnterServer(ScreenPtr pScreen)
98{
99    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
100    R128InfoPtr info = R128PTR(pScrn);
101
102#ifdef HAVE_XAA_H
103    if (info->accel) info->accel->NeedToSync = TRUE;
104#endif
105#ifdef USE_EXA
106    if (info->ExaDriver) exaMarkSync(pScreen);
107    /* EXA and DRI are fighting over control of the texture hardware.
108     * That means we need to setup compositing when the server wakes
109     * up if a 3D app is running.
110     */
111    if (info->have3DWindows) info->state_2d.composite_setup = FALSE;
112#endif
113}
114
115/* Called when the X server goes to sleep to allow the X server's
116   context to be saved and the last client's context to be loaded.  This
117   is not necessary for the Rage 128 since the client detects when it's
118   context is not currently loaded and then load's it itself.  Since the
119   registers to start and stop the CCE are privileged, only the X server
120   can start/stop the engine. */
121static void R128LeaveServer(ScreenPtr pScreen)
122{
123    ScrnInfoPtr   pScrn     = xf86ScreenToScrn(pScreen);
124    R128InfoPtr   info      = R128PTR(pScrn);
125    unsigned char *R128MMIO = info->MMIO;
126
127    if (!info->directRenderingEnabled) {
128	/* Save all hardware scissors */
129	info->sc_left     = INREG(R128_SC_LEFT);
130	info->sc_right    = INREG(R128_SC_RIGHT);
131	info->sc_top      = INREG(R128_SC_TOP);
132	info->sc_bottom   = INREG(R128_SC_BOTTOM);
133	info->aux_sc_cntl = INREG(R128_SC_BOTTOM);
134    } else if (info->CCEInUse) {
135	R128CCEReleaseIndirect(pScrn);
136
137	info->CCEInUse = FALSE;
138    }
139}
140
141/* Contexts can be swapped by the X server if necessary.  This callback
142   is currently only used to perform any functions necessary when
143   entering or leaving the X server, and in the future might not be
144   necessary. */
145static void R128DRISwapContext(ScreenPtr pScreen, DRISyncType syncType,
146			       DRIContextType oldContextType, void *oldContext,
147			       DRIContextType newContextType, void *newContext)
148{
149    if ((syncType==DRI_3D_SYNC) && (oldContextType==DRI_2D_CONTEXT) &&
150	(newContextType==DRI_2D_CONTEXT)) { /* Entering from Wakeup */
151	R128EnterServer(pScreen);
152    }
153    if ((syncType==DRI_2D_SYNC) && (oldContextType==DRI_NO_CONTEXT) &&
154	(newContextType==DRI_2D_CONTEXT)) { /* Exiting from Block Handler */
155	R128LeaveServer(pScreen);
156    }
157}
158
159/* Initialize the state of the back and depth buffers. */
160static void R128DRIInitBuffers(WindowPtr pWin, RegionPtr prgn, CARD32 indx)
161{
162    /* FIXME: This routine needs to have acceleration turned on */
163    ScreenPtr   pScreen = pWin->drawable.pScreen;
164    ScrnInfoPtr pScrn   = xf86ScreenToScrn(pScreen);
165    R128InfoPtr info    = R128PTR(pScrn);
166#ifdef HAVE_XAA_H
167    BoxPtr      pbox, pboxSave;
168    int         nbox, nboxSave;
169    int         depth;
170#endif
171
172    /* FIXME: Use accel when CCE 2D code is written
173     * EA: What is this code kept for? Radeon doesn't have it and
174     * has a comment: "There's no need for the 2d driver to be clearing
175     * buffers for the 3d client.  It knows how to do that on its own."
176     */
177    if (info->directRenderingEnabled)
178	return;
179#ifdef HAVE_XAA_H
180    /* FIXME: This should be based on the __GLXvisualConfig info */
181    switch (pScrn->bitsPerPixel) {
182    case  8: depth = 0x000000ff; break;
183    case 16: depth = 0x0000ffff; break;
184    case 24: depth = 0x00ffffff; break;
185    case 32: depth = 0xffffffff; break;
186    default: depth = 0x00000000; break;
187    }
188
189    /* FIXME: Copy XAAPaintWindow() and use REGION_TRANSLATE() */
190    /* FIXME: Only initialize the back and depth buffers for contexts
191       that request them */
192
193    pboxSave = pbox = REGION_RECTS(prgn);
194    nboxSave = nbox = REGION_NUM_RECTS(prgn);
195
196    (*info->accel->SetupForSolidFill)(pScrn, 0, GXcopy, (uint32_t)(-1));
197    for (; nbox; nbox--, pbox++) {
198	(*info->accel->SubsequentSolidFillRect)(pScrn,
199						pbox->x1 + info->fbX,
200						pbox->y1 + info->fbY,
201						pbox->x2 - pbox->x1,
202						pbox->y2 - pbox->y1);
203	(*info->accel->SubsequentSolidFillRect)(pScrn,
204						pbox->x1 + info->backX,
205						pbox->y1 + info->backY,
206						pbox->x2 - pbox->x1,
207						pbox->y2 - pbox->y1);
208    }
209
210    pbox = pboxSave;
211    nbox = nboxSave;
212
213    /* FIXME: this needs to consider depth tiling. */
214    (*info->accel->SetupForSolidFill)(pScrn, depth, GXcopy, (uint32_t)(-1));
215    for (; nbox; nbox--, pbox++)
216	(*info->accel->SubsequentSolidFillRect)(pScrn,
217						pbox->x1 + info->depthX,
218						pbox->y1 + info->depthY,
219						pbox->x2 - pbox->x1,
220						pbox->y2 - pbox->y1);
221
222    info->accel->NeedToSync = TRUE;
223#endif
224}
225
226/* Copy the back and depth buffers when the X server moves a window. */
227static void R128DRIMoveBuffers(WindowPtr pWin, DDXPointRec ptOldOrg,
228			       RegionPtr prgnSrc, CARD32 indx)
229{
230    ScreenPtr   pScreen = pWin->drawable.pScreen;
231    ScrnInfoPtr pScrn   = xf86ScreenToScrn(pScreen);
232    R128InfoPtr info   = R128PTR(pScrn);
233
234    /* FIXME: This routine needs to have acceleration turned on */
235    /* FIXME: Copy XAACopyWindow() and use REGION_TRANSLATE() */
236    /* FIXME: Only initialize the back and depth buffers for contexts
237       that request them */
238
239    /* FIXME: Use accel when CCE 2D code is written */
240    if (info->directRenderingEnabled)
241	return;
242}
243
244/* Initialize the AGP state.  Request memory for use in AGP space, and
245   initialize the Rage 128 registers to point to that memory. */
246static Bool R128DRIAgpInit(R128InfoPtr info, ScreenPtr pScreen)
247{
248    unsigned char *R128MMIO = info->MMIO;
249    unsigned long mode;
250    unsigned int  vendor, device;
251    int           ret;
252    unsigned long cntl, chunk;
253    int           s, l;
254    int           flags;
255    unsigned long agpBase;
256
257    if (drmAgpAcquire(info->drmFD) < 0) {
258	xf86DrvMsg(pScreen->myNum, X_WARNING, "[agp] AGP not available\n");
259	return FALSE;
260    }
261
262				/* Modify the mode if the default mode is
263				   not appropriate for this particular
264				   combination of graphics card and AGP
265				   chipset. */
266
267    mode   = drmAgpGetMode(info->drmFD);        /* Default mode */
268    vendor = drmAgpVendorId(info->drmFD);
269    device = drmAgpDeviceId(info->drmFD);
270
271    mode &= ~R128_AGP_MODE_MASK;
272    switch (info->agpMode) {
273    case 4:          mode |= R128_AGP_4X_MODE;
274    case 2:          mode |= R128_AGP_2X_MODE;
275    case 1: default: mode |= R128_AGP_1X_MODE;
276    }
277
278    xf86DrvMsg(pScreen->myNum, X_INFO,
279	       "[agp] Mode 0x%08lx [AGP 0x%04x/0x%04x; Card 0x%04x/0x%04x]\n",
280	       mode, vendor, device,
281	       PCI_DEV_VENDOR_ID(info->PciInfo),
282	       PCI_DEV_DEVICE_ID(info->PciInfo));
283
284    if (drmAgpEnable(info->drmFD, mode) < 0) {
285	xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] AGP not enabled\n");
286	drmAgpRelease(info->drmFD);
287	return FALSE;
288    }
289
290    info->agpOffset = 0;
291
292    if ((ret = drmAgpAlloc(info->drmFD, info->agpSize*1024*1024, 0, NULL,
293			   &info->agpMemHandle)) < 0) {
294	xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] Out of memory (%d)\n", ret);
295	drmAgpRelease(info->drmFD);
296	return FALSE;
297    }
298    xf86DrvMsg(pScreen->myNum, X_INFO,
299	       "[agp] %d kB allocated with handle 0x%08x\n",
300	       info->agpSize*1024, info->agpMemHandle);
301
302    if (drmAgpBind(info->drmFD, info->agpMemHandle, info->agpOffset) < 0) {
303	xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] Could not bind\n");
304	drmAgpFree(info->drmFD, info->agpMemHandle);
305	drmAgpRelease(info->drmFD);
306	return FALSE;
307    }
308
309				/* Initialize the CCE ring buffer data */
310    info->ringStart       = info->agpOffset;
311    info->ringMapSize     = info->ringSize*1024*1024 + r128_drm_page_size;
312    info->ringSizeLog2QW  = R128MinBits(info->ringSize*1024*1024/8) - 1;
313
314    info->ringReadOffset  = info->ringStart + info->ringMapSize;
315    info->ringReadMapSize = r128_drm_page_size;
316
317				/* Reserve space for vertex/indirect buffers */
318    info->bufStart        = info->ringReadOffset + info->ringReadMapSize;
319    info->bufMapSize      = info->bufSize*1024*1024;
320
321				/* Reserve the rest for AGP textures */
322    info->agpTexStart     = info->bufStart + info->bufMapSize;
323    s = (info->agpSize*1024*1024 - info->agpTexStart);
324    l = R128MinBits((s-1) / R128_NR_TEX_REGIONS);
325    if (l < R128_LOG_TEX_GRANULARITY) l = R128_LOG_TEX_GRANULARITY;
326    info->agpTexMapSize   = (s >> l) << l;
327    info->log2AGPTexGran  = l;
328
329    if (info->CCESecure) flags = DRM_READ_ONLY;
330    else                  flags = 0;
331
332    if (drmAddMap(info->drmFD, info->ringStart, info->ringMapSize,
333		  DRM_AGP, flags, &info->ringHandle) < 0) {
334	xf86DrvMsg(pScreen->myNum, X_ERROR,
335		   "[agp] Could not add ring mapping\n");
336	return FALSE;
337    }
338    xf86DrvMsg(pScreen->myNum, X_INFO,
339	       "[agp] ring handle = 0x%08x\n", info->ringHandle);
340
341    if (drmMap(info->drmFD, info->ringHandle, info->ringMapSize,
342	       &info->ring) < 0) {
343	xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] Could not map ring\n");
344	return FALSE;
345    }
346    xf86DrvMsg(pScreen->myNum, X_INFO,
347	       "[agp] Ring mapped at 0x%08lx\n",
348	       (unsigned long)info->ring);
349
350    if (drmAddMap(info->drmFD, info->ringReadOffset, info->ringReadMapSize,
351		  DRM_AGP, flags, &info->ringReadPtrHandle) < 0) {
352	xf86DrvMsg(pScreen->myNum, X_ERROR,
353		   "[agp] Could not add ring read ptr mapping\n");
354	return FALSE;
355    }
356    xf86DrvMsg(pScreen->myNum, X_INFO,
357 	       "[agp] ring read ptr handle = 0x%08x\n",
358	       info->ringReadPtrHandle);
359
360    if (drmMap(info->drmFD, info->ringReadPtrHandle, info->ringReadMapSize,
361	       &info->ringReadPtr) < 0) {
362	xf86DrvMsg(pScreen->myNum, X_ERROR,
363		   "[agp] Could not map ring read ptr\n");
364	return FALSE;
365    }
366    xf86DrvMsg(pScreen->myNum, X_INFO,
367	       "[agp] Ring read ptr mapped at 0x%08lx\n",
368	       (unsigned long)info->ringReadPtr);
369
370    if (drmAddMap(info->drmFD, info->bufStart, info->bufMapSize,
371		  DRM_AGP, 0, &info->bufHandle) < 0) {
372	xf86DrvMsg(pScreen->myNum, X_ERROR,
373		   "[agp] Could not add vertex/indirect buffers mapping\n");
374	return FALSE;
375    }
376    xf86DrvMsg(pScreen->myNum, X_INFO,
377	       "[agp] vertex/indirect buffers handle = 0x%08x\n",
378	       info->bufHandle);
379
380    if (drmMap(info->drmFD, info->bufHandle, info->bufMapSize,
381	       &info->buf) < 0) {
382	xf86DrvMsg(pScreen->myNum, X_ERROR,
383		   "[agp] Could not map vertex/indirect buffers\n");
384	return FALSE;
385    }
386    xf86DrvMsg(pScreen->myNum, X_INFO,
387	       "[agp] Vertex/indirect buffers mapped at 0x%08lx\n",
388	       (unsigned long)info->buf);
389
390    if (drmAddMap(info->drmFD, info->agpTexStart, info->agpTexMapSize,
391		  DRM_AGP, 0, &info->agpTexHandle) < 0) {
392	xf86DrvMsg(pScreen->myNum, X_ERROR,
393		   "[agp] Could not add AGP texture map mapping\n");
394	return FALSE;
395    }
396    xf86DrvMsg(pScreen->myNum, X_INFO,
397	       "[agp] AGP texture map handle = 0x%08x\n",
398	       info->agpTexHandle);
399
400    if (drmMap(info->drmFD, info->agpTexHandle, info->agpTexMapSize,
401	       &info->agpTex) < 0) {
402	xf86DrvMsg(pScreen->myNum, X_ERROR,
403		   "[agp] Could not map AGP texture map\n");
404	return FALSE;
405    }
406    xf86DrvMsg(pScreen->myNum, X_INFO,
407	       "[agp] AGP Texture map mapped at 0x%08lx\n",
408	       (unsigned long)info->agpTex);
409
410				/* Initialize Rage 128's AGP registers */
411    cntl  = INREG(R128_AGP_CNTL);
412    cntl &= ~R128_AGP_APER_SIZE_MASK;
413    switch (info->agpSize) {
414    case 256: cntl |= R128_AGP_APER_SIZE_256MB; break;
415    case 128: cntl |= R128_AGP_APER_SIZE_128MB; break;
416    case  64: cntl |= R128_AGP_APER_SIZE_64MB;  break;
417    case  32: cntl |= R128_AGP_APER_SIZE_32MB;  break;
418    case  16: cntl |= R128_AGP_APER_SIZE_16MB;  break;
419    case   8: cntl |= R128_AGP_APER_SIZE_8MB;   break;
420    case   4: cntl |= R128_AGP_APER_SIZE_4MB;   break;
421    default:
422	xf86DrvMsg(pScreen->myNum, X_ERROR,
423		   "[agp] Illegal aperture size %d kB\n",
424		   info->agpSize*1024);
425	return FALSE;
426    }
427    agpBase = drmAgpBase(info->drmFD);
428    OUTREG(R128_AGP_BASE, agpBase);
429    OUTREG(R128_AGP_CNTL, cntl);
430
431				/* Disable Rage 128's PCIGART registers */
432    chunk = INREG(R128_BM_CHUNK_0_VAL);
433    chunk &= ~(R128_BM_PTR_FORCE_TO_PCI |
434	       R128_BM_PM4_RD_FORCE_TO_PCI |
435	       R128_BM_GLOBAL_FORCE_TO_PCI);
436    OUTREG(R128_BM_CHUNK_0_VAL, chunk);
437
438    OUTREG(R128_PCI_GART_PAGE, 1); /* Ensure AGP GART is used (for now) */
439
440    return TRUE;
441}
442
443static Bool R128DRIPciInit(R128InfoPtr info, ScreenPtr pScreen)
444{
445    unsigned char *R128MMIO = info->MMIO;
446    uint32_t chunk;
447    int ret;
448    int flags;
449
450    info->agpOffset = 0;
451
452    ret = drmScatterGatherAlloc(info->drmFD, info->agpSize*1024*1024,
453				&info->pciMemHandle);
454    if (ret < 0) {
455	xf86DrvMsg(pScreen->myNum, X_ERROR, "[pci] Out of memory (%d)\n", ret);
456	return FALSE;
457    }
458    xf86DrvMsg(pScreen->myNum, X_INFO,
459	       "[pci] %d kB allocated with handle 0x%08x\n",
460	       info->agpSize*1024, info->pciMemHandle);
461
462				/* Initialize the CCE ring buffer data */
463    info->ringStart       = info->agpOffset;
464    info->ringMapSize     = info->ringSize*1024*1024 + r128_drm_page_size;
465    info->ringSizeLog2QW  = R128MinBits(info->ringSize*1024*1024/8) - 1;
466
467    info->ringReadOffset  = info->ringStart + info->ringMapSize;
468    info->ringReadMapSize = r128_drm_page_size;
469
470				/* Reserve space for vertex/indirect buffers */
471    info->bufStart        = info->ringReadOffset + info->ringReadMapSize;
472    info->bufMapSize      = info->bufSize*1024*1024;
473
474    flags = DRM_READ_ONLY | DRM_LOCKED | DRM_KERNEL;
475
476    if (drmAddMap(info->drmFD, info->ringStart, info->ringMapSize,
477		  DRM_SCATTER_GATHER, flags, &info->ringHandle) < 0) {
478	xf86DrvMsg(pScreen->myNum, X_ERROR,
479		   "[pci] Could not add ring mapping\n");
480	return FALSE;
481    }
482    xf86DrvMsg(pScreen->myNum, X_INFO,
483	       "[pci] ring handle = 0x%08x\n", info->ringHandle);
484
485    if (drmMap(info->drmFD, info->ringHandle, info->ringMapSize,
486	       &info->ring) < 0) {
487	xf86DrvMsg(pScreen->myNum, X_ERROR, "[pci] Could not map ring\n");
488	return FALSE;
489    }
490    xf86DrvMsg(pScreen->myNum, X_INFO,
491	       "[pci] Ring mapped at 0x%08lx\n",
492	       (unsigned long)info->ring);
493    xf86DrvMsg(pScreen->myNum, X_INFO,
494	       "[pci] Ring contents 0x%08lx\n",
495	       *(unsigned long *)(pointer)info->ring);
496
497    if (drmAddMap(info->drmFD, info->ringReadOffset, info->ringReadMapSize,
498		  DRM_SCATTER_GATHER, flags, &info->ringReadPtrHandle) < 0) {
499	xf86DrvMsg(pScreen->myNum, X_ERROR,
500		   "[pci] Could not add ring read ptr mapping\n");
501	return FALSE;
502    }
503    xf86DrvMsg(pScreen->myNum, X_INFO,
504	       "[pci] ring read ptr handle = 0x%08x\n",
505	       info->ringReadPtrHandle);
506
507    if (drmMap(info->drmFD, info->ringReadPtrHandle, info->ringReadMapSize,
508	       &info->ringReadPtr) < 0) {
509	xf86DrvMsg(pScreen->myNum, X_ERROR,
510		   "[pci] Could not map ring read ptr\n");
511	return FALSE;
512    }
513    xf86DrvMsg(pScreen->myNum, X_INFO,
514	       "[pci] Ring read ptr mapped at 0x%08lx\n",
515	       (unsigned long)info->ringReadPtr);
516    xf86DrvMsg(pScreen->myNum, X_INFO,
517	       "[pci] Ring read ptr contents 0x%08lx\n",
518	       *(unsigned long *)(pointer)info->ringReadPtr);
519
520    if (drmAddMap(info->drmFD, info->bufStart, info->bufMapSize,
521		  DRM_SCATTER_GATHER, 0, &info->bufHandle) < 0) {
522	xf86DrvMsg(pScreen->myNum, X_ERROR,
523		   "[pci] Could not add vertex/indirect buffers mapping\n");
524	return FALSE;
525    }
526    xf86DrvMsg(pScreen->myNum, X_INFO,
527	       "[pci] vertex/indirect buffers handle = 0x%08x\n",
528	       info->bufHandle);
529
530    if (drmMap(info->drmFD, info->bufHandle, info->bufMapSize,
531	       &info->buf) < 0) {
532	xf86DrvMsg(pScreen->myNum, X_ERROR,
533		   "[pci] Could not map vertex/indirect buffers\n");
534	return FALSE;
535    }
536    xf86DrvMsg(pScreen->myNum, X_INFO,
537	       "[pci] Vertex/indirect buffers mapped at 0x%08lx\n",
538	       (unsigned long)info->buf);
539    xf86DrvMsg(pScreen->myNum, X_INFO,
540	       "[pci] Vertex/indirect buffers contents 0x%08lx\n",
541	       *(unsigned long *)(pointer)info->buf);
542
543    switch (info->Chipset) {
544    case PCI_CHIP_RAGE128LE:
545    case PCI_CHIP_RAGE128RE:
546    case PCI_CHIP_RAGE128RK:
547    case PCI_CHIP_RAGE128PD:
548    case PCI_CHIP_RAGE128PP:
549    case PCI_CHIP_RAGE128PR:
550	/* This is a PCI card, do nothing */
551	break;
552
553    case PCI_CHIP_RAGE128LF:
554    case PCI_CHIP_RAGE128MF:
555    case PCI_CHIP_RAGE128ML:
556    case PCI_CHIP_RAGE128RF:
557    case PCI_CHIP_RAGE128RG:
558    case PCI_CHIP_RAGE128RL:
559    case PCI_CHIP_RAGE128SM:
560    case PCI_CHIP_RAGE128PF:
561    case PCI_CHIP_RAGE128TF:
562    case PCI_CHIP_RAGE128TL:
563    case PCI_CHIP_RAGE128TR:
564    /* FIXME: ATI documentation does not specify if the following chips are
565     * AGP or PCI, it just mentions their PCI IDs.  I'm assuming they're AGP
566     * until I get more correct information. <mharris@redhat.com>
567     */
568    case PCI_CHIP_RAGE128PA:
569    case PCI_CHIP_RAGE128PB:
570    case PCI_CHIP_RAGE128PC:
571    case PCI_CHIP_RAGE128PE:
572    case PCI_CHIP_RAGE128PG:
573    case PCI_CHIP_RAGE128PH:
574    case PCI_CHIP_RAGE128PI:
575    case PCI_CHIP_RAGE128PJ:
576    case PCI_CHIP_RAGE128PK:
577    case PCI_CHIP_RAGE128PL:
578    case PCI_CHIP_RAGE128PM:
579    case PCI_CHIP_RAGE128PN:
580    case PCI_CHIP_RAGE128PO:
581    case PCI_CHIP_RAGE128PQ:
582    case PCI_CHIP_RAGE128PS:
583    case PCI_CHIP_RAGE128PT:
584    case PCI_CHIP_RAGE128PU:
585    case PCI_CHIP_RAGE128PV:
586    case PCI_CHIP_RAGE128PW:
587    case PCI_CHIP_RAGE128PX:
588    case PCI_CHIP_RAGE128SE:
589    case PCI_CHIP_RAGE128SF:
590    case PCI_CHIP_RAGE128SG:
591    case PCI_CHIP_RAGE128SH:
592    case PCI_CHIP_RAGE128SK:
593    case PCI_CHIP_RAGE128SL:
594    case PCI_CHIP_RAGE128SN:
595    case PCI_CHIP_RAGE128TS:
596    case PCI_CHIP_RAGE128TT:
597    case PCI_CHIP_RAGE128TU:
598    default:
599	/* This is really an AGP card, force PCI GART mode */
600        chunk = INREG(R128_BM_CHUNK_0_VAL);
601        chunk |= (R128_BM_PTR_FORCE_TO_PCI |
602		  R128_BM_PM4_RD_FORCE_TO_PCI |
603		  R128_BM_GLOBAL_FORCE_TO_PCI);
604        OUTREG(R128_BM_CHUNK_0_VAL, chunk);
605        OUTREG(R128_PCI_GART_PAGE, 0); /* Ensure PCI GART is used */
606        break;
607    }
608
609    return TRUE;
610}
611
612/* Add a map for the MMIO registers that will be accessed by any
613   DRI-based clients. */
614static Bool R128DRIMapInit(R128InfoPtr info, ScreenPtr pScreen)
615{
616    int flags;
617
618    if (info->CCESecure) flags = DRM_READ_ONLY;
619    else                 flags = 0;
620
621				/* Map registers */
622    info->registerSize = R128_MMIOSIZE;
623    if (drmAddMap(info->drmFD, info->MMIOAddr, info->registerSize,
624		  DRM_REGISTERS, flags, &info->registerHandle) < 0) {
625	return FALSE;
626    }
627    xf86DrvMsg(pScreen->myNum, X_INFO,
628	       "[drm] register handle = 0x%08x\n", info->registerHandle);
629
630    return TRUE;
631}
632
633/* Initialize the kernel data structures. */
634static int R128DRIKernelInit(R128InfoPtr info, ScreenPtr pScreen)
635{
636    drmR128Init drmInfo;
637
638    memset( &drmInfo, 0, sizeof(drmR128Init) );
639
640    drmInfo.func                = DRM_R128_INIT_CCE;
641    drmInfo.sarea_priv_offset   = sizeof(XF86DRISAREARec);
642    drmInfo.is_pci              = info->IsPCI;
643    drmInfo.cce_mode            = info->CCEMode;
644    drmInfo.cce_secure          = info->CCESecure;
645    drmInfo.ring_size           = info->ringSize*1024*1024;
646    drmInfo.usec_timeout        = info->CCEusecTimeout;
647
648    drmInfo.fb_bpp              = info->CurrentLayout.pixel_code;
649    drmInfo.depth_bpp           = info->CurrentLayout.pixel_code;
650
651    drmInfo.front_offset        = info->frontOffset;
652    drmInfo.front_pitch         = info->frontPitch;
653
654    drmInfo.back_offset         = info->backOffset;
655    drmInfo.back_pitch          = info->backPitch;
656
657    drmInfo.depth_offset        = info->depthOffset;
658    drmInfo.depth_pitch         = info->depthPitch;
659    drmInfo.span_offset         = info->spanOffset;
660
661    drmInfo.fb_offset           = info->fbHandle;
662    drmInfo.mmio_offset         = info->registerHandle;
663    drmInfo.ring_offset         = info->ringHandle;
664    drmInfo.ring_rptr_offset    = info->ringReadPtrHandle;
665    drmInfo.buffers_offset      = info->bufHandle;
666    drmInfo.agp_textures_offset = info->agpTexHandle;
667
668    if (drmCommandWrite(info->drmFD, DRM_R128_INIT,
669                        &drmInfo, sizeof(drmR128Init)) < 0)
670        return FALSE;
671
672    return TRUE;
673}
674
675/* Add a map for the vertex buffers that will be accessed by any
676   DRI-based clients. */
677static Bool R128DRIBufInit(R128InfoPtr info, ScreenPtr pScreen)
678{
679				/* Initialize vertex buffers */
680    if (info->IsPCI) {
681	info->bufNumBufs = drmAddBufs(info->drmFD,
682				      info->bufMapSize / R128_BUFFER_SIZE,
683				      R128_BUFFER_SIZE,
684				      DRM_SG_BUFFER,
685				      info->bufStart);
686    } else {
687	info->bufNumBufs = drmAddBufs(info->drmFD,
688				      info->bufMapSize / R128_BUFFER_SIZE,
689				      R128_BUFFER_SIZE,
690				      DRM_AGP_BUFFER,
691				      info->bufStart);
692    }
693    if (info->bufNumBufs <= 0) {
694	xf86DrvMsg(pScreen->myNum, X_ERROR,
695		   "[drm] Could not create vertex/indirect buffers list\n");
696	return FALSE;
697    }
698    xf86DrvMsg(pScreen->myNum, X_INFO,
699	       "[drm] Added %d %d byte vertex/indirect buffers\n",
700	       info->bufNumBufs, R128_BUFFER_SIZE);
701
702    if (!(info->buffers = drmMapBufs(info->drmFD))) {
703	xf86DrvMsg(pScreen->myNum, X_ERROR,
704		   "[drm] Failed to map vertex/indirect buffers list\n");
705	return FALSE;
706    }
707    xf86DrvMsg(pScreen->myNum, X_INFO,
708	       "[drm] Mapped %d vertex/indirect buffers\n",
709	       info->buffers->count);
710
711    return TRUE;
712}
713
714static void R128DRIIrqInit(R128InfoPtr info, ScreenPtr pScreen)
715{
716   ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
717
718   if (!info->irq) {
719      info->irq = drmGetInterruptFromBusID(
720	 info->drmFD,
721	 PCI_CFG_BUS(info->PciInfo),
722	 PCI_CFG_DEV(info->PciInfo),
723	 PCI_CFG_FUNC(info->PciInfo));
724
725      if((drmCtlInstHandler(info->drmFD, info->irq)) != 0) {
726	 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
727		    "[drm] failure adding irq handler, "
728		    "there is a device already using that irq\n"
729		    "[drm] falling back to irq-free operation\n");
730	 info->irq = 0;
731      } else {
732          unsigned char *R128MMIO = info->MMIO;
733          info->gen_int_cntl = INREG( R128_GEN_INT_CNTL );
734      }
735   }
736
737   if (info->irq)
738      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
739		 "[drm] dma control initialized, using IRQ %d\n",
740		 info->irq);
741}
742
743/* Initialize the CCE state, and start the CCE (if used by the X server) */
744static void R128DRICCEInit(ScrnInfoPtr pScrn)
745{
746    R128InfoPtr   info      = R128PTR(pScrn);
747
748				/* Turn on bus mastering */
749    info->BusCntl &= ~R128_BUS_MASTER_DIS;
750
751				/* CCEMode is initialized in r128_driver.c */
752    switch (info->CCEMode) {
753    case R128_PM4_NONPM4:                 info->CCEFifoSize = 0;   break;
754    case R128_PM4_192PIO:                 info->CCEFifoSize = 192; break;
755    case R128_PM4_192BM:                  info->CCEFifoSize = 192; break;
756    case R128_PM4_128PIO_64INDBM:         info->CCEFifoSize = 128; break;
757    case R128_PM4_128BM_64INDBM:          info->CCEFifoSize = 128; break;
758    case R128_PM4_64PIO_128INDBM:         info->CCEFifoSize = 64;  break;
759    case R128_PM4_64BM_128INDBM:          info->CCEFifoSize = 64;  break;
760    case R128_PM4_64PIO_64VCBM_64INDBM:   info->CCEFifoSize = 64;  break;
761    case R128_PM4_64BM_64VCBM_64INDBM:    info->CCEFifoSize = 64;  break;
762    case R128_PM4_64PIO_64VCPIO_64INDPIO: info->CCEFifoSize = 64;  break;
763    }
764
765    if (info->directRenderingEnabled) {
766				/* Make sure the CCE is on for the X server */
767	R128CCE_START(pScrn, info);
768    } else {
769				/* Make sure the CCE is off for the X server */
770	R128CCE_STOP(pScrn, info);
771    }
772}
773
774/* Initialize the screen-specific data structures for the DRI and the
775   Rage 128.  This is the main entry point to the device-specific
776   initialization code.  It calls device-independent DRI functions to
777   create the DRI data structures and initialize the DRI state. */
778Bool R128DRIScreenInit(ScreenPtr pScreen)
779{
780    ScrnInfoPtr   pScrn = xf86ScreenToScrn(pScreen);
781    R128InfoPtr   info = R128PTR(pScrn);
782    DRIInfoPtr    pDRIInfo;
783    R128DRIPtr    pR128DRI;
784    int           major, minor, patch;
785    drmVersionPtr version;
786
787    /* Check that the DRI, and DRM modules have been loaded by testing
788     * for known symbols in each module. */
789    if (!xf86LoaderCheckSymbol("drmAvailable"))        return FALSE;
790    if (!xf86LoaderCheckSymbol("DRIQueryVersion")) {
791      xf86DrvMsg(pScreen->myNum, X_ERROR,
792		 "[dri] R128DRIScreenInit failed (libdri.a too old)\n");
793      return FALSE;
794    }
795
796    /* Check the DRI version */
797    DRIQueryVersion(&major, &minor, &patch);
798    if (major != DRIINFO_MAJOR_VERSION || minor < 0) {
799	xf86DrvMsg(pScreen->myNum, X_ERROR,
800		"[dri] R128DRIScreenInit failed because of a version mismatch.\n"
801		"[dri] libdri version is %d.%d.%d but version %d.%d.x is needed.\n"
802		"[dri] Disabling the DRI.\n",
803		major, minor, patch,
804                DRIINFO_MAJOR_VERSION, 0);
805	return FALSE;
806    }
807
808    switch (info->CurrentLayout.pixel_code) {
809    case 8:
810	/* These modes are not supported (yet). */
811    case 15:
812    case 24:
813	xf86DrvMsg(pScreen->myNum, X_ERROR,
814		   "[dri] R128DRIScreenInit failed (depth %d not supported).  "
815		   "[dri] Disabling DRI.\n", info->CurrentLayout.pixel_code);
816	return FALSE;
817
818	/* Only 16 and 32 color depths are supports currently. */
819    case 16:
820    case 32:
821	break;
822    }
823
824    r128_drm_page_size = getpagesize();
825
826    /* Create the DRI data structure, and fill it in before calling the
827       DRIScreenInit(). */
828    if (!(pDRIInfo = DRICreateInfoRec())) return FALSE;
829
830    info->pDRIInfo                       = pDRIInfo;
831    pDRIInfo->drmDriverName              = R128_DRIVER_NAME;
832    pDRIInfo->clientDriverName           = R128_DRIVER_NAME;
833    if (xf86LoaderCheckSymbol("DRICreatePCIBusID")) {
834	pDRIInfo->busIdString = DRICreatePCIBusID(info->PciInfo);
835    } else {
836	pDRIInfo->busIdString            = malloc(64);
837	sprintf(pDRIInfo->busIdString,
838		"PCI:%d:%d:%d",
839		PCI_DEV_BUS(info->PciInfo),
840		PCI_DEV_DEV(info->PciInfo),
841		PCI_DEV_FUNC(info->PciInfo));
842    }
843    pDRIInfo->ddxDriverMajorVersion      = R128_VERSION_MAJOR;
844    pDRIInfo->ddxDriverMinorVersion      = R128_VERSION_MINOR;
845    pDRIInfo->ddxDriverPatchVersion      = R128_VERSION_PATCH;
846    pDRIInfo->frameBufferPhysicalAddress = (void *)info->LinearAddr;
847    pDRIInfo->frameBufferSize            = info->FbMapSize;
848    pDRIInfo->frameBufferStride          = (pScrn->displayWidth *
849					    info->CurrentLayout.pixel_bytes);
850    pDRIInfo->ddxDrawableTableEntry      = R128_MAX_DRAWABLES;
851    pDRIInfo->maxDrawableTableEntry      = (SAREA_MAX_DRAWABLES
852					    < R128_MAX_DRAWABLES
853					    ? SAREA_MAX_DRAWABLES
854					    : R128_MAX_DRAWABLES);
855
856#ifdef NOT_DONE
857    /* FIXME: Need to extend DRI protocol to pass this size back to
858     * client for SAREA mapping that includes a device private record
859     */
860    pDRIInfo->SAREASize =
861	((sizeof(XF86DRISAREARec) + 0xfff) & 0x1000); /* round to page */
862    /* + shared memory device private rec */
863#else
864    /* For now the mapping works by using a fixed size defined
865     * in the SAREA header
866     */
867    if (sizeof(XF86DRISAREARec)+sizeof(R128SAREAPriv)>SAREA_MAX) {
868        xf86DrvMsg(pScreen->myNum, X_ERROR,
869                   "[dri] Data does not fit in SAREA.  Disabling DRI.\n");
870	return FALSE;
871    }
872    pDRIInfo->SAREASize = SAREA_MAX;
873#endif
874
875    if (!(pR128DRI = (R128DRIPtr)calloc(sizeof(R128DRIRec),1))) {
876	DRIDestroyInfoRec(info->pDRIInfo);
877	info->pDRIInfo = NULL;
878	return FALSE;
879    }
880    pDRIInfo->devPrivate     = pR128DRI;
881    pDRIInfo->devPrivateSize = sizeof(R128DRIRec);
882    pDRIInfo->contextSize    = sizeof(R128DRIContextRec);
883
884    pDRIInfo->CreateContext  = R128CreateContext;
885    pDRIInfo->DestroyContext = R128DestroyContext;
886    pDRIInfo->SwapContext    = R128DRISwapContext;
887    pDRIInfo->InitBuffers    = R128DRIInitBuffers;
888    pDRIInfo->MoveBuffers    = R128DRIMoveBuffers;
889    pDRIInfo->bufferRequests = DRI_ALL_WINDOWS;
890    pDRIInfo->TransitionTo2d = R128DRITransitionTo2d;
891    pDRIInfo->TransitionTo3d = R128DRITransitionTo3d;
892    pDRIInfo->TransitionSingleToMulti3D = R128DRITransitionSingleToMulti3d;
893    pDRIInfo->TransitionMultiToSingle3D = R128DRITransitionMultiToSingle3d;
894
895    pDRIInfo->createDummyCtx     = TRUE;
896    pDRIInfo->createDummyCtxPriv = FALSE;
897
898    if (!DRIScreenInit(pScreen, pDRIInfo, &info->drmFD)) {
899	xf86DrvMsg(pScreen->myNum, X_ERROR,
900                   "[dri] DRIScreenInit failed.  Disabling DRI.\n");
901	free(pDRIInfo->devPrivate);
902	pDRIInfo->devPrivate = NULL;
903	DRIDestroyInfoRec(pDRIInfo);
904	pDRIInfo = NULL;
905	return FALSE;
906    }
907
908    /* Check the DRM lib version.
909       drmGetLibVersion was not supported in version 1.0, so check for
910       symbol first to avoid possible crash or hang.
911     */
912    if (xf86LoaderCheckSymbol("drmGetLibVersion")) {
913        version = drmGetLibVersion(info->drmFD);
914    }
915    else {
916        /* drmlib version 1.0.0 didn't have the drmGetLibVersion
917           entry point.  Fake it by allocating a version record
918           via drmGetVersion and changing it to version 1.0.0
919         */
920        version = drmGetVersion(info->drmFD);
921        version->version_major      = 1;
922        version->version_minor      = 0;
923        version->version_patchlevel = 0;
924    }
925
926    if (version) {
927	if (version->version_major != 1 ||
928	    version->version_minor < 1) {
929            /* incompatible drm library version */
930            xf86DrvMsg(pScreen->myNum, X_ERROR,
931		"[dri] R128DRIScreenInit failed because of a version mismatch.\n"
932		"[dri] libdrm.a module version is %d.%d.%d but version 1.1.x is needed.\n"
933		"[dri] Disabling DRI.\n",
934                version->version_major,
935                version->version_minor,
936                version->version_patchlevel);
937            drmFreeVersion(version);
938	    R128DRICloseScreen(pScreen);
939            return FALSE;
940	}
941	drmFreeVersion(version);
942    }
943
944    /* Check the r128 DRM version */
945    version = drmGetVersion(info->drmFD);
946    if (version) {
947	if (version->version_major != 2 ||
948	    version->version_minor < 2) {
949	    /* incompatible drm version */
950	    xf86DrvMsg(pScreen->myNum, X_ERROR,
951		"[dri] R128DRIScreenInit failed because of a version mismatch.\n"
952		"[dri] r128.o kernel module version is %d.%d.%d but version 2.2 or greater is needed.\n"
953		"[dri] Disabling the DRI.\n",
954		version->version_major,
955		version->version_minor,
956		version->version_patchlevel);
957	    drmFreeVersion(version);
958	    R128DRICloseScreen(pScreen);
959	    return FALSE;
960	}
961	info->drmMinor = version->version_minor;
962	drmFreeVersion(version);
963    }
964
965				/* Initialize AGP */
966    if (!info->IsPCI && !R128DRIAgpInit(info, pScreen)) {
967	info->IsPCI = TRUE;
968	xf86DrvMsg(pScreen->myNum, X_WARNING,
969		   "[agp] AGP failed to initialize -- falling back to PCI mode.\n");
970	xf86DrvMsg(pScreen->myNum, X_WARNING,
971		   "[agp] Make sure you have the agpgart kernel module loaded.\n");
972    }
973
974				/* Initialize PCIGART */
975    if (info->IsPCI && !R128DRIPciInit(info, pScreen)) {
976	R128DRICloseScreen(pScreen);
977	return FALSE;
978    }
979
980				/* DRIScreenInit doesn't add all the
981				   common mappings.  Add additional
982				   mappings here. */
983    if (!R128DRIMapInit(info, pScreen)) {
984	R128DRICloseScreen(pScreen);
985	return FALSE;
986    }
987
988				/* DRIScreenInit adds the frame buffer
989				   map, but we need it as well */
990    {
991	void *scratch_ptr;
992        int scratch_int;
993
994	DRIGetDeviceInfo(pScreen, &info->fbHandle,
995                         &scratch_int, &scratch_int,
996                         &scratch_int, &scratch_int,
997                         &scratch_ptr);
998    }
999
1000				/* FIXME: When are these mappings unmapped? */
1001
1002    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[dri] Visual configs initialized\n");
1003
1004    return TRUE;
1005}
1006
1007/* Finish initializing the device-dependent DRI state, and call
1008   DRIFinishScreenInit() to complete the device-independent DRI
1009   initialization. */
1010Bool R128DRIFinishScreenInit(ScreenPtr pScreen)
1011{
1012    ScrnInfoPtr      pScrn = xf86ScreenToScrn(pScreen);
1013    R128InfoPtr      info  = R128PTR(pScrn);
1014    R128SAREAPrivPtr pSAREAPriv;
1015    R128DRIPtr       pR128DRI;
1016
1017    info->pDRIInfo->driverSwapMethod = DRI_HIDE_X_CONTEXT;
1018    /* info->pDRIInfo->driverSwapMethod = DRI_SERVER_SWAP; */
1019
1020    /* NOTE: DRIFinishScreenInit must be called before *DRIKernelInit
1021       because *DRIKernelInit requires that the hardware lock is held by
1022       the X server, and the first time the hardware lock is grabbed is
1023       in DRIFinishScreenInit. */
1024    if (!DRIFinishScreenInit(pScreen)) {
1025	R128DRICloseScreen(pScreen);
1026	return FALSE;
1027    }
1028
1029    /* Initialize the kernel data structures */
1030    if (!R128DRIKernelInit(info, pScreen)) {
1031	R128DRICloseScreen(pScreen);
1032	return FALSE;
1033    }
1034
1035    /* Initialize the vertex buffers list */
1036    if (!R128DRIBufInit(info, pScreen)) {
1037	R128DRICloseScreen(pScreen);
1038	return FALSE;
1039    }
1040
1041    /* Initialize IRQ */
1042    R128DRIIrqInit(info, pScreen);
1043
1044    /* Initialize and start the CCE if required */
1045    R128DRICCEInit(pScrn);
1046
1047    pSAREAPriv = (R128SAREAPrivPtr)DRIGetSAREAPrivate(pScreen);
1048    memset(pSAREAPriv, 0, sizeof(*pSAREAPriv));
1049
1050    pR128DRI                    = (R128DRIPtr)info->pDRIInfo->devPrivate;
1051
1052    pR128DRI->deviceID          = info->Chipset;
1053    pR128DRI->width             = pScrn->virtualX;
1054    pR128DRI->height            = pScrn->virtualY;
1055    pR128DRI->depth             = pScrn->depth;
1056    pR128DRI->bpp               = pScrn->bitsPerPixel;
1057
1058    pR128DRI->IsPCI             = info->IsPCI;
1059    pR128DRI->AGPMode           = info->agpMode;
1060
1061    pR128DRI->frontOffset       = info->frontOffset;
1062    pR128DRI->frontPitch        = info->frontPitch;
1063    pR128DRI->backOffset        = info->backOffset;
1064    pR128DRI->backPitch         = info->backPitch;
1065    pR128DRI->depthOffset       = info->depthOffset;
1066    pR128DRI->depthPitch        = info->depthPitch;
1067    pR128DRI->spanOffset        = info->spanOffset;
1068    pR128DRI->textureOffset     = info->textureOffset;
1069    pR128DRI->textureSize       = info->textureSize;
1070    pR128DRI->log2TexGran       = info->log2TexGran;
1071
1072    pR128DRI->registerHandle    = info->registerHandle;
1073    pR128DRI->registerSize      = info->registerSize;
1074
1075    pR128DRI->agpTexHandle      = info->agpTexHandle;
1076    pR128DRI->agpTexMapSize     = info->agpTexMapSize;
1077    pR128DRI->log2AGPTexGran    = info->log2AGPTexGran;
1078    pR128DRI->agpTexOffset      = info->agpTexStart;
1079    pR128DRI->sarea_priv_offset = sizeof(XF86DRISAREARec);
1080
1081    /* Have shadowfb run only while there is 3d active. */
1082    if (info->allowPageFlip && info->drmMinor >= 5 ) {
1083	ShadowFBInit( pScreen, R128DRIRefreshArea );
1084    } else if (info->allowPageFlip) {
1085	xf86DrvMsg(pScreen->myNum, X_WARNING,
1086		   "[dri] Kernel module version 2.5.0 or newer is required for pageflipping.\n");
1087       info->allowPageFlip = 0;
1088    }
1089
1090    return TRUE;
1091}
1092
1093/* The screen is being closed, so clean up any state and free any
1094   resources used by the DRI. */
1095void R128DRICloseScreen(ScreenPtr pScreen)
1096{
1097    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1098    R128InfoPtr info = R128PTR(pScrn);
1099    drmR128Init drmInfo;
1100
1101				/* Stop the CCE if it is still in use */
1102    if (info->directRenderingEnabled) {
1103	R128CCE_STOP(pScrn, info);
1104    }
1105
1106    if (info->irq) {
1107	drmCtlUninstHandler(info->drmFD);
1108	info->irq = 0;
1109	info->gen_int_cntl = 0;
1110    }
1111
1112				/* De-allocate vertex buffers */
1113    if (info->buffers) {
1114	drmUnmapBufs(info->buffers);
1115	info->buffers = NULL;
1116    }
1117
1118				/* De-allocate all kernel resources */
1119    memset(&drmInfo, 0, sizeof(drmR128Init));
1120    drmInfo.func = DRM_R128_CLEANUP_CCE;
1121    drmCommandWrite(info->drmFD, DRM_R128_INIT,
1122                    &drmInfo, sizeof(drmR128Init));
1123
1124				/* De-allocate all AGP resources */
1125    if (info->agpTex) {
1126	drmUnmap(info->agpTex, info->agpTexMapSize);
1127	info->agpTex = NULL;
1128    }
1129    if (info->buf) {
1130	drmUnmap(info->buf, info->bufMapSize);
1131	info->buf = NULL;
1132    }
1133    if (info->ringReadPtr) {
1134	drmUnmap(info->ringReadPtr, info->ringReadMapSize);
1135	info->ringReadPtr = NULL;
1136    }
1137    if (info->ring) {
1138	drmUnmap(info->ring, info->ringMapSize);
1139	info->ring = NULL;
1140    }
1141    if (info->agpMemHandle != DRM_AGP_NO_HANDLE) {
1142	drmAgpUnbind(info->drmFD, info->agpMemHandle);
1143	drmAgpFree(info->drmFD, info->agpMemHandle);
1144	info->agpMemHandle = DRM_AGP_NO_HANDLE;
1145	drmAgpRelease(info->drmFD);
1146    }
1147    if (info->pciMemHandle) {
1148	drmScatterGatherFree(info->drmFD, info->pciMemHandle);
1149	info->pciMemHandle = 0;
1150    }
1151
1152				/* De-allocate all DRI resources */
1153    DRICloseScreen(pScreen);
1154
1155				/* De-allocate all DRI data structures */
1156    if (info->pDRIInfo) {
1157	if (info->pDRIInfo->devPrivate) {
1158	    free(info->pDRIInfo->devPrivate);
1159	    info->pDRIInfo->devPrivate = NULL;
1160	}
1161	DRIDestroyInfoRec(info->pDRIInfo);
1162	info->pDRIInfo = NULL;
1163    }
1164}
1165
1166/* Use callbacks from dri.c to support pageflipping mode for a single
1167 * 3d context without need for any specific full-screen extension.
1168 */
1169
1170/* Use the shadowfb module to maintain a list of dirty rectangles.
1171 * These are blitted to the back buffer to keep both buffers clean
1172 * during page-flipping when the 3d application isn't fullscreen.
1173 *
1174 * Unlike most use of the shadowfb code, both buffers are in video memory.
1175 *
1176 * An alternative to this would be to organize for all on-screen drawing
1177 * operations to be duplicated for the two buffers.  That might be
1178 * faster, but seems like a lot more work...
1179 */
1180
1181
1182static void R128DRIRefreshArea(ScrnInfoPtr pScrn, int num, BoxPtr pbox)
1183{
1184    R128InfoPtr         info       = R128PTR(pScrn);
1185    int                 i;
1186    R128SAREAPrivPtr    pSAREAPriv = DRIGetSAREAPrivate(pScrn->pScreen);
1187    PixmapPtr		pPix	   = pScrn->pScreen->GetScreenPixmap(pScrn->pScreen);
1188
1189    /* Don't want to do this when no 3d is active and pages are
1190     * right-way-round
1191     */
1192    if (!pSAREAPriv->pfAllowPageFlip && pSAREAPriv->pfCurrentPage == 0)
1193	return;
1194
1195#ifdef HAVE_XAA_H
1196    if (!info->useEXA) {
1197	(*info->accel->SetupForScreenToScreenCopy)(pScrn,
1198					       1, 1, GXcopy,
1199					       (uint32_t)(-1), -1);
1200    }
1201#endif
1202#ifdef USE_EXA
1203    if (info->useEXA) {
1204        uint32_t src_pitch_offset, dst_pitch_offset, datatype;
1205
1206	R128GetPixmapOffsetPitch(pPix, &src_pitch_offset);
1207	dst_pitch_offset = src_pitch_offset + (info->backOffset >> 5);
1208	R128GetDatatypeBpp(pScrn->bitsPerPixel, &datatype);
1209	info->xdir = info->ydir = 1;
1210
1211	R128DoPrepareCopy(pScrn, src_pitch_offset, dst_pitch_offset, datatype, GXcopy, ~0);
1212    }
1213#endif
1214
1215    for (i = 0 ; i < num ; i++, pbox++) {
1216	int xa = max(pbox->x1, 0), xb = min(pbox->x2, pScrn->virtualX-1);
1217	int ya = max(pbox->y1, 0), yb = min(pbox->y2, pScrn->virtualY-1);
1218
1219	if (xa <= xb && ya <= yb) {
1220#ifdef HAVE_XAA_H
1221	    if (!info->useEXA) {
1222	        (*info->accel->SubsequentScreenToScreenCopy)(pScrn, xa, ya,
1223							 xa + info->backX,
1224							 ya + info->backY,
1225							 xb - xa + 1,
1226							 yb - ya + 1);
1227	    }
1228#endif
1229#ifdef USE_EXA
1230	    if (info->useEXA) {
1231		(*info->ExaDriver->Copy)(pPix, xa, ya, xa, ya, xb - xa + 1, yb - ya + 1);
1232	    }
1233#endif
1234	}
1235    }
1236}
1237
1238static void R128EnablePageFlip(ScreenPtr pScreen)
1239{
1240    ScrnInfoPtr         pScrn      = xf86ScreenToScrn(pScreen);
1241    R128InfoPtr         info       = R128PTR(pScrn);
1242    R128SAREAPrivPtr    pSAREAPriv = DRIGetSAREAPrivate(pScreen);
1243    PixmapPtr		pPix	   = pScreen->GetScreenPixmap(pScreen);
1244
1245    if (info->allowPageFlip) {
1246	/* Duplicate the frontbuffer to the backbuffer */
1247#ifdef HAVE_XAA_H
1248	if (!info->useEXA) {
1249	    (*info->accel->SetupForScreenToScreenCopy)(pScrn,
1250						   1, 1, GXcopy,
1251						   (uint32_t)(-1), -1);
1252
1253	    (*info->accel->SubsequentScreenToScreenCopy)(pScrn,
1254						     0,
1255						     0,
1256						     info->backX,
1257						     info->backY,
1258						     pScrn->virtualX,
1259						     pScrn->virtualY);
1260	}
1261#endif
1262#ifdef USE_EXA
1263	if (info->useEXA) {
1264	    uint32_t src_pitch_offset, dst_pitch_offset, datatype;
1265
1266	    R128GetPixmapOffsetPitch(pPix, &src_pitch_offset);
1267	    dst_pitch_offset = src_pitch_offset + (info->backOffset >> 5);
1268	    R128GetDatatypeBpp(pScrn->bitsPerPixel, &datatype);
1269	    info->xdir = info->ydir = 1;
1270
1271            R128DoPrepareCopy(pScrn, src_pitch_offset, dst_pitch_offset, datatype, GXcopy, ~0);
1272
1273	    (*info->ExaDriver->Copy)(pPix, 0, 0, 0, 0, pScrn->virtualX, pScrn->virtualY);
1274	}
1275#endif
1276
1277	pSAREAPriv->pfAllowPageFlip = 1;
1278    }
1279}
1280
1281static void R128DisablePageFlip(ScreenPtr pScreen)
1282{
1283    /* Tell the clients not to pageflip.  How?
1284     *   -- Field in sarea, plus bumping the window counters.
1285     *   -- DRM needs to cope with Front-to-Back swapbuffers.
1286     */
1287    R128SAREAPrivPtr  pSAREAPriv = DRIGetSAREAPrivate(pScreen);
1288
1289    pSAREAPriv->pfAllowPageFlip = 0;
1290}
1291
1292static void R128DRITransitionSingleToMulti3d(ScreenPtr pScreen)
1293{
1294    R128DisablePageFlip(pScreen);
1295}
1296
1297static void R128DRITransitionMultiToSingle3d(ScreenPtr pScreen)
1298{
1299    /* Let the remaining 3d app start page flipping again */
1300    R128EnablePageFlip(pScreen);
1301}
1302
1303static void R128DRITransitionTo3d(ScreenPtr pScreen)
1304{
1305    ScrnInfoPtr    pScrn = xf86ScreenToScrn(pScreen);
1306    R128InfoPtr    info  = R128PTR(pScrn);
1307
1308    R128EnablePageFlip(pScreen);
1309
1310    info->have3DWindows = 1;
1311}
1312
1313static void R128DRITransitionTo2d(ScreenPtr pScreen)
1314{
1315    ScrnInfoPtr         pScrn      = xf86ScreenToScrn(pScreen);
1316    R128InfoPtr         info       = R128PTR(pScrn);
1317    R128SAREAPrivPtr    pSAREAPriv = DRIGetSAREAPrivate(pScreen);
1318
1319    /* Try flipping back to the front page if necessary */
1320    if (pSAREAPriv->pfCurrentPage == 1)
1321	drmCommandNone(info->drmFD, DRM_R128_FLIP);
1322
1323    /* Shut down shadowing if we've made it back to the front page */
1324    if (pSAREAPriv->pfCurrentPage == 0) {
1325	R128DisablePageFlip(pScreen);
1326    } else {
1327	xf86DrvMsg(pScreen->myNum, X_WARNING,
1328		   "[dri] R128DRITransitionTo2d: "
1329		   "kernel failed to unflip buffers.\n");
1330    }
1331
1332    info->have3DWindows = 0;
1333}
1334