gx_driver.c revision 3406bd8e
1/* Copyright (c) 2003-2006 Advanced Micro Devices, Inc.
2 *
3 * Portioned modeled from xf86-video-intel/src/i830_driver.c
4 * Copyright 2001 VA Linux Systems Inc., Fremont, California.
5 * Copyright \ufffd 2002 by David Dawes
6
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to
9 * deal in the Software without restriction, including without limitation the
10 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
11 * sell copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
23 * IN THE SOFTWARE.
24 *
25 * Neither the name of the Advanced Micro Devices, Inc. nor the names of its
26 * contributors may be used to endorse or promote products derived from this
27 * software without specific prior written permission.
28 */
29
30#ifdef HAVE_CONFIG_H
31#include "config.h"
32#endif
33
34#include <stdio.h>
35#include <fcntl.h>
36#include <unistd.h>
37#include <sys/mman.h>
38
39#include "xorg-server.h"
40#include "xf86.h"
41#include "xf86_OSproc.h"
42#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 6
43#include "xf86Resources.h"
44#endif
45#include "xf86cmap.h"
46#include "compiler.h"
47#include "mipointer.h"
48#include "shadow.h"
49#include <X11/extensions/randr.h>
50#include "fb.h"
51#include "miscstruct.h"
52#include "micmap.h"
53#include "vbe.h"
54#include "fb.h"
55#include "randrstr.h"
56
57#include "geode.h"
58#include "gfx_defs.h"
59#include "gfx_regs.h"
60#include "panel.h"
61
62/* Bring in VGA functions */
63#include "gx_vga.c"
64
65#define GX_MIN_PITCH 1024
66#define GX_MAX_PITCH 8192
67#define GX_MAX_WIDTH  1600
68#define GX_MIN_HEIGHT  400
69#define GX_MAX_HEIGHT 1200
70#define GX_CB_PITCH   544
71#define GX_CB_SIZE    544
72
73#define GX_CPU_REG_SIZE 0x4000
74#define GX_GP_REG_SIZE  0x4000
75#define GX_VID_REG_SIZE 0x4000
76
77#define DEFAULT_IMG_LINE_BUFS 20
78#define DEFAULT_CLR_LINE_BUFS 20
79
80extern OptionInfoRec GX_GeodeOptions[];
81
82unsigned char *XpressROMPtr;
83
84static inline void
85gx_enable_dac_power(void)
86{
87    gfx_write_vid32(RCDF_VID_MISC,
88                    gfx_read_vid32(RCDF_VID_MISC) & RCDF_GAMMA_BYPASS_BOTH);
89}
90
91static inline void
92gx_disable_dac_power(void)
93{
94    gfx_write_vid32(RCDF_VID_MISC,
95                    RCDF_DAC_POWER_DOWN | RCDF_ANALOG_POWER_DOWN |
96                    (gfx_read_vid32(RCDF_VID_MISC) & RCDF_GAMMA_BYPASS_BOTH));
97}
98
99static void
100GXInitEXAMemory(ScrnInfoPtr pScrni, unsigned int *offset, unsigned int *avail)
101{
102    GeodePtr pGeode = GEODEPTR(pScrni);
103
104    if (pGeode->exaBfrSz > 0 && pGeode->exaBfrSz <= *avail) {
105        pGeode->exaBfrOffset = *offset;
106        *offset += pGeode->exaBfrOffset;
107        *avail -= pGeode->exaBfrOffset;
108    }
109}
110
111static void
112GXInitXAAMemory(ScrnInfoPtr pScrni, unsigned int *offset, unsigned int *avail)
113{
114    GeodePtr pGeode = GEODEPTR(pScrni);
115    unsigned int size, i, pitch;
116
117    /* XXX - FIXME - What if we are out of room?  Then what? */
118    /* For now, we NULL them all out.                        */
119
120    if (pGeode->NoOfImgBuffers > 0) {
121        size = pGeode->displayPitch * pGeode->NoOfImgBuffers;
122        if (size <= *avail) {
123            for (i = 0; i < pGeode->NoOfImgBuffers; i++) {
124                pGeode->AccelImageWriteBuffers[i] = pGeode->FBBase + *offset;
125                *offset += pGeode->displayPitch;
126                *avail -= pGeode->displayPitch;
127            }
128        }
129        else {
130            xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
131                       "Not enough memory for image write buffers.\n");
132
133            for (i = 0; i < pGeode->NoOfImgBuffers; i++)
134                pGeode->AccelImageWriteBuffers[i] = NULL;
135        }
136    }
137
138    if (pGeode->NoOfColorExpandLines > 0) {
139        pitch = ((pGeode->displayPitch + 31) >> 5) << 2;
140        size = pitch * pGeode->NoOfColorExpandLines;
141
142        if (size <= *avail) {
143            for (i = 0; i < pGeode->NoOfColorExpandLines; i++) {
144                pGeode->AccelColorExpandBuffers[i] = pGeode->FBBase + *offset;
145                *offset += pitch;
146                *avail -= pitch;
147            }
148        }
149        else {
150            xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
151                       "Not enough memory for color expansion buffers.\n");
152
153            for (i = 0; i < pGeode->NoOfImgBuffers; i++)
154                pGeode->AccelColorExpandBuffers[i] = NULL;
155        }
156    }
157}
158
159static Bool
160GXAllocateMemory(ScreenPtr pScrn, ScrnInfoPtr pScrni, int rotate)
161{
162    GeodePtr pGeode = GEODEPTR(pScrni);
163
164    unsigned int fboffset, fbavail;
165    unsigned int size;
166    unsigned int bytpp = (pScrni->bitsPerPixel + 7) / 8;
167    BOOL ret = TRUE;
168
169    if (pGeode->tryCompression)
170        pGeode->displayPitch =
171            GeodeCalculatePitchBytes(pScrni->virtualX, pScrni->bitsPerPixel);
172    else
173        pGeode->displayPitch =
174            ((pScrni->virtualX + 3) & ~3) * (pScrni->bitsPerPixel >> 3);
175
176    pGeode->Pitch = pGeode->displayPitch;
177    pGeode->displayWidth = pGeode->displayPitch / bytpp;
178    pScrni->displayWidth = pGeode->displayWidth;
179
180    fbavail = pGeode->FBAvail - 0x4000;
181
182    pGeode->displayOffset = fboffset = 0;
183    pGeode->displaySize = pScrni->virtualY * pGeode->displayPitch;
184
185    fbavail -= pGeode->displaySize;
186    fboffset += pGeode->displaySize;
187
188    if (pGeode->tryCompression) {
189        size = pScrni->virtualY * GX_CB_PITCH;
190
191        if (size <= fbavail) {
192            pGeode->CBData.compression_offset = fboffset;
193
194            fboffset += size;
195            fbavail -= size;
196
197            pGeode->Compression = TRUE;
198        }
199        else {
200            xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
201                       "Not enough memory for compression\n");
202            pGeode->Compression = FALSE;
203        }
204    }
205
206    if (pGeode->tryHWCursor) {
207
208        if (fbavail >= 1024) {
209            pGeode->CursorStartOffset = fboffset;
210            fboffset += 1024;
211            fbavail -= 1024;
212            pGeode->HWCursor = TRUE;
213        }
214        else {
215            xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
216                       "Not enough memory for the hardware cursor\n");
217            pGeode->HWCursor = FALSE;
218        }
219    }
220
221    if (!pGeode->NoAccel) {
222        if (pGeode->useEXA)
223            GXInitEXAMemory(pScrni, &fboffset, &fbavail);
224        else
225            GXInitXAAMemory(pScrni, &fboffset, &fbavail);
226    }
227
228    pGeode->shadowSize = 0;
229
230    if (rotate != RR_Rotate_0) {
231        if (rotate & (RR_Rotate_90 | RR_Rotate_270))
232            size = pGeode->displayPitch * pScrni->virtualX;
233        else
234            size = pGeode->displayPitch * pScrni->virtualY;
235
236        if (size <= fbavail) {
237            pGeode->shadowOffset = fboffset;
238            pGeode->shadowSize = size;
239
240            fboffset += size;
241            fbavail -= size;
242        }
243        else {
244            xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
245                       "Not enough memory for the shadow framebuffer\n");
246            ret = FALSE;
247        }
248    }
249
250    /* XAA always exists - we can't remove it on demand like we can with EXA.
251     * So we assume the worse, and only give XAA enough offspace room to
252     * account for any eventuality that RandR might throw at us. */
253
254    if (!pGeode->NoAccel) {
255
256        if (pGeode->useEXA && pGeode->pExa) {
257            ExaDriverPtr pExa = pGeode->pExa;
258
259            pExa->offScreenBase = fboffset;
260            pExa->memorySize = fboffset + fbavail;
261        }
262
263        if (!pGeode->useEXA) {
264
265#if XF86XAA
266            if (!xf86FBManagerRunning(pScrn)) {
267
268                unsigned int offset = fboffset;
269                unsigned int avail = fbavail;
270                RegionRec OffscreenRegion;
271                BoxRec AvailBox;
272
273                /* Assume the shadow FB exists even if it doesnt */
274
275                if (pGeode->shadowSize == 0) {
276                    size = (pScrn->width * bytpp) * pScrni->virtualX;
277                    offset += size;
278                    avail -= size;
279                }
280
281                AvailBox.x1 = 0;
282                AvailBox.y1 =
283                    (offset + pGeode->displayPitch - 1) / pGeode->displayPitch;
284
285                AvailBox.x2 = pGeode->displayWidth;
286                AvailBox.y2 = (offset + avail) / pGeode->displayPitch;
287
288                if (AvailBox.y1 < AvailBox.y2) {
289                    REGION_INIT(pScrn, &OffscreenRegion, &AvailBox, 2);
290
291                    if (!xf86InitFBManagerRegion(pScrn, &OffscreenRegion))
292                        xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
293                                   "Memory manager initialization failed.\n");
294
295                    REGION_UNINIT(pScrn, &OffscreenRegion);
296                }
297                else
298                    xf86DrvMsg(pScrni->scrnIndex, X_INFO,
299                               "Cache disabled - no offscreen memory available.\n");
300            }
301            else
302                xf86DrvMsg(pScrni->scrnIndex, X_INFO,
303                           "XAA offscreen memory has already been allocated.\n");
304#endif
305        }
306    }
307    return ret;
308}
309
310static Bool
311GXSaveScreen(ScreenPtr pScrn, int mode)
312{
313    ScrnInfoPtr pScrni = xf86ScreenToScrn(pScrn);
314    GeodePtr pGeode = GEODEPTR(pScrni);
315
316    if (pGeode->useVGA && !pScrni->vtSema)
317        return vgaHWSaveScreen(pScrn, mode);
318
319    return TRUE;
320}
321
322/* Common function - used by the LX too */
323#ifdef XSERVER_LIBPCIACCESS
324static inline void *
325map_pci_mem(ScrnInfoPtr pScrni, int vram,
326            struct pci_device *dev, int bar, int size)
327{
328    void *ptr;
329    int map_size = size ? size : dev->regions[bar].size;
330
331    int err = pci_device_map_range(dev,
332                                   dev->regions[bar].base_addr,
333                                   map_size,
334                                   PCI_DEV_MAP_FLAG_WRITABLE |
335                                   (vram ? PCI_DEV_MAP_FLAG_WRITE_COMBINE : 0),
336                                   &ptr);
337
338    if (err)
339        return NULL;
340    return ptr;
341}
342
343static inline int
344unmap_pci_mem(ScrnInfoPtr pScrni, struct pci_device *dev, void *ptr, int size)
345{
346    return pci_device_unmap_range(dev, ptr, size);
347}
348#endif
349
350extern unsigned long gfx_gx2_scratch_base;
351
352static Bool
353GXMapMem(ScrnInfoPtr pScrni)
354{
355    GeodeRec *pGeode = GEODEPTR(pScrni);
356    int index = pScrni->scrnIndex;
357
358    pciVideoPtr pci = xf86GetPciInfoForEntity(pGeode->pEnt->index);
359
360#ifndef XSERVER_LIBPCIACCESS
361    gfx_virt_regptr = (unsigned char *) xf86MapVidMem(index, VIDMEM_MMIO,
362                                                      pci->memBase[2],
363                                                      pci->size[2]);
364
365    gfx_virt_gpptr = (unsigned char *) xf86MapVidMem(index, VIDMEM_MMIO,
366                                                     pci->memBase[1],
367                                                     pci->size[1]);
368
369    gfx_virt_vidptr = (unsigned char *) xf86MapVidMem(index, VIDMEM_MMIO,
370                                                      pci->memBase[3],
371                                                      pci->size[3]);
372
373    gfx_virt_fbptr = (unsigned char *) xf86MapVidMem(index, VIDMEM_FRAMEBUFFER,
374                                                     pci->memBase[0],
375                                                     pGeode->FBAvail);
376#else
377    gfx_virt_regptr = map_pci_mem(pScrni, 0, pci, 2, 0);
378    gfx_virt_gpptr = map_pci_mem(pScrni, 0, pci, 1, 0);
379    gfx_virt_vidptr = map_pci_mem(pScrni, 0, pci, 3, 0);
380    gfx_virt_fbptr = map_pci_mem(pScrni, 1, pci, 0, pGeode->FBAvail);
381#endif
382
383    gfx_gx2_scratch_base = pGeode->FBAvail - 0x4000;
384
385#ifndef XSERVER_LIBPCIACCESS
386    XpressROMPtr = xf86MapVidMem(index, VIDMEM_FRAMEBUFFER, 0xF0000, 0x10000);
387#else
388    {
389        int fd = open("/dev/mem", O_RDWR);
390        if (fd < 0) {
391            xf86DrvMsg(index, X_ERROR, "Failed to open /dev/mem: %m\n");
392            return FALSE;
393        }
394        XpressROMPtr = mmap(NULL, 0x10000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0xF0000);
395        close(fd);
396    }
397#endif
398    pGeode->FBBase = gfx_virt_fbptr;
399
400    if ((!gfx_virt_regptr) || (!gfx_virt_gpptr) ||
401        (!gfx_virt_vidptr) || (!gfx_virt_fbptr))
402        return FALSE;
403
404    if (!pGeode->NoAccel && pGeode->useEXA)
405        pGeode->pExa->memoryBase = pGeode->FBBase;
406
407    xf86DrvMsg(index, X_INFO, "Found Geode %x %p\n",
408               pGeode->FBAvail, pGeode->FBBase);
409
410    return TRUE;
411}
412
413/* Check to see if VGA exists - we map the space and look for a
414   signature - if it doesn't match exactly, then we assume no VGA.
415*/
416
417static Bool
418GXCheckVGA(ScrnInfoPtr pScrni, EntityInfoPtr pEnt)
419{
420#ifndef XSERVER_LIBPCIACCESS
421    unsigned char *ptr;
422    const char *vgasig = "IBM VGA Compatible";
423    int ret;
424
425    ptr =
426        xf86MapVidMem(pScrni->scrnIndex, VIDMEM_FRAMEBUFFER, 0xC001E,
427                      strlen(vgasig));
428
429    if (ptr == NULL)
430        return FALSE;
431
432    ret = memcmp(ptr, vgasig, strlen(vgasig));
433    xf86UnMapVidMem(pScrni->scrnIndex, (pointer) ptr, strlen(vgasig));
434
435    return ret ? FALSE : TRUE;
436#else
437    pciVideoPtr pci = xf86GetPciInfoForEntity(pEnt->index);
438
439    return pci_device_is_boot_vga(pci);
440#endif
441}
442
443static Bool
444GXPreInit(ScrnInfoPtr pScrni, int flags)
445{
446    GeodePtr pGeode;
447    ClockRangePtr GeodeClockRange;
448    OptionInfoRec *GeodeOptions = &GX_GeodeOptions[0];
449    int ret;
450    QQ_WORD msrValue;
451    EntityInfoPtr pEnt;
452    rgb defaultWeight = { 0, 0, 0 };
453    int modecnt;
454    const char *s, *panelgeo;
455    Bool useVGA;
456
457    if (pScrni->numEntities != 1)
458        return FALSE;
459
460    pEnt = xf86GetEntityInfo(pScrni->entityList[0]);
461#ifndef XSERVER_LIBPCIACCESS
462    if (pEnt->resources)
463        return FALSE;
464#endif
465
466    pGeode = pScrni->driverPrivate = xnfcalloc(1, sizeof(GeodeRec));
467
468    if (pGeode == NULL)
469        return FALSE;
470
471    useVGA = GXCheckVGA(pScrni, pEnt);
472
473    if (flags & PROBE_DETECT) {
474        GeodeProbeDDC(pScrni, pEnt->index);
475        return TRUE;
476    }
477
478    /* Probe for VGA */
479    pGeode->useVGA = useVGA;
480    pGeode->pEnt = pEnt;
481
482    if (pGeode->useVGA) {
483        if (!xf86LoadSubModule(pScrni, "vgahw") || !vgaHWGetHWRec(pScrni))
484            pGeode->useVGA = FALSE;
485        else
486            vgaHWSetStdFuncs(VGAHWPTR(pScrni));
487
488#if INT10_SUPPORT
489        pGeode->vesa = calloc(1, sizeof(VESARec));
490#endif
491    }
492
493    gfx_msr_init();
494
495    ret = gfx_msr_read(RC_ID_DF, MBD_MSR_CONFIG, &msrValue);
496
497    if (!ret) {
498        pGeode->Output =
499            ((msrValue.low & RCDF_CONFIG_FMT_MASK) ==
500             RCDF_CONFIG_FMT_FP) ? OUTPUT_PANEL : OUTPUT_CRT;
501    }
502
503    /* Fill in the monitor information */
504    pScrni->monitor = pScrni->confScreen->monitor;
505
506    if (!xf86SetDepthBpp(pScrni, 16, 16, 16, Support24bppFb | Support32bppFb))
507        return FALSE;
508
509    switch (pScrni->depth) {
510    case 8:
511        pScrni->rgbBits = 8;
512    case 16:
513    case 24:
514    case 32:
515        break;
516    default:
517        xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
518                   "The driver does not support %d as a depth.\n",
519                   pScrni->depth);
520        return FALSE;
521    }
522
523    xf86PrintDepthBpp(pScrni);
524
525    if (!xf86SetWeight(pScrni, defaultWeight, defaultWeight))
526        return FALSE;
527
528    if (!xf86SetDefaultVisual(pScrni, -1))
529        return FALSE;
530
531    /*
532     * If the driver can do gamma correction, it should call xf86SetGamma()
533     * here.
534     */
535    {
536        Gamma zeros = { 0.0, 0.0, 0.0 };
537
538        if (!xf86SetGamma(pScrni, zeros)) {
539            return FALSE;
540        }
541    }
542
543    pScrni->progClock = TRUE;
544    xf86CollectOptions(pScrni, NULL);
545    xf86ProcessOptions(pScrni->scrnIndex, pScrni->options, GeodeOptions);
546
547    /* Set up our various options that may get reversed as we go on */
548
549    pGeode->FBVGAActive = FALSE;
550    pGeode->tryHWCursor = TRUE;
551    pGeode->tryCompression = TRUE;
552
553    pGeode->NoAccel = FALSE;
554    pGeode->useEXA = FALSE;
555
556    pGeode->Panel = (pGeode->Output & OUTPUT_PANEL) ? TRUE : FALSE;
557
558    pGeode->NoOfImgBuffers = DEFAULT_IMG_LINE_BUFS;
559    pGeode->NoOfColorExpandLines = DEFAULT_CLR_LINE_BUFS;
560    pGeode->exaBfrSz = DEFAULT_EXA_SCRATCH_BFRSZ;
561
562    xf86GetOptValBool(GeodeOptions, GX_OPTION_HW_CURSOR, &pGeode->tryHWCursor);
563
564    if (!xf86GetOptValInteger(GeodeOptions, GX_OPTION_FBSIZE,
565                              (int *) &(pGeode->FBAvail)))
566        pGeode->FBAvail = 0;
567
568    /* For compatability - allow SWCursor too */
569
570    if (xf86ReturnOptValBool(GeodeOptions, GX_OPTION_SW_CURSOR, FALSE))
571        pGeode->tryHWCursor = FALSE;
572
573    if (xf86ReturnOptValBool(GeodeOptions, GX_OPTION_NOCOMPRESSION, FALSE))
574        pGeode->tryCompression = FALSE;
575
576    if (xf86ReturnOptValBool(GeodeOptions, GX_OPTION_NOACCEL, FALSE))
577        pGeode->NoAccel = TRUE;
578
579    pGeode->rotation = RR_Rotate_0;
580
581    if ((s = xf86GetOptValString(GeodeOptions, GX_OPTION_ROTATE))) {
582
583        if (!xf86NameCmp(s, "LEFT"))
584            pGeode->rotation = RR_Rotate_90;
585        else if (!xf86NameCmp(s, "INVERT"))
586            pGeode->rotation = RR_Rotate_180;
587        else if (!xf86NameCmp(s, "CCW"))
588            pGeode->rotation = RR_Rotate_270;
589        else
590            xf86DrvMsg(pScrni->scrnIndex, X_ERROR, "Invalid rotation %s.\n", s);
591    }
592
593    xf86GetOptValInteger(GeodeOptions, GX_OPTION_OSM_IMG_BUFS,
594                         &(pGeode->NoOfImgBuffers));
595
596    if (pGeode->NoOfImgBuffers <= 0)
597        pGeode->NoOfImgBuffers = 0;
598
599    xf86GetOptValInteger(GeodeOptions, GX_OPTION_OSM_CLR_BUFS,
600                         &(pGeode->NoOfColorExpandLines));
601
602    if (pGeode->NoOfColorExpandLines <= 0)
603        pGeode->NoOfColorExpandLines = 0;
604
605    xf86GetOptValInteger(GeodeOptions, GX_OPTION_OSM_CLR_BUFS,
606                         (int *) &(pGeode->exaBfrSz));
607
608    if (pGeode->exaBfrSz <= 0)
609        pGeode->exaBfrSz = 0;
610
611    if (pGeode->Panel == TRUE) {
612        if (xf86ReturnOptValBool(GeodeOptions, GX_OPTION_NOPANEL, FALSE))
613            pGeode->Panel = FALSE;
614    }
615
616    panelgeo = xf86GetOptValString(GeodeOptions, GX_OPTION_PANEL_GEOMETRY);
617
618    if ((s = xf86GetOptValString(GeodeOptions, GX_OPTION_ACCEL_METHOD))) {
619#if defined(XF86XAA) && defined(XF86EXA)
620        if (!xf86NameCmp(s, "XAA"))
621            pGeode->useEXA = FALSE;
622        else if (xf86NameCmp(s, "EXA"))
623            xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
624                       "Unknown accleration method %s.  Defaulting to XAA.\n",
625                       s);
626#elif defined(XF86EXA)
627        pGeode->useEXA = TRUE;
628#else
629        pGeode->useEXA = FALSE;
630#endif
631    }
632
633    xf86DrvMsg(pScrni->scrnIndex, X_INFO,
634               "Using %s acceleration architecture\n",
635               pGeode->useEXA ? "EXA" : "XAA");
636
637    /* Set up the panel */
638
639    if (pGeode->Panel) {
640        if (panelgeo != NULL) {
641            if (GeodeGetFPGeometry(panelgeo, &pGeode->PanelX, &pGeode->PanelY))
642                pGeode->Panel = FALSE;
643        }
644#ifdef PNL_SUP
645        else {
646            int b, f;
647
648            /* The bitdepth and refresh isn't used anywhere else in the driver */
649
650            if ((pGeode->Panel = Pnl_IsPanelEnabledInBIOS()))
651                Pnl_GetPanelInfoFromBIOS(&pGeode->PanelX, &pGeode->PanelY, &b,
652                                         &f);
653        }
654#endif
655    }
656
657    /* Set up the VGA */
658
659    if (pGeode->useVGA) {
660#if INT10_SUPPORT
661        VESARec *pVesa;
662
663        if (!xf86LoadSubModule(pScrni, "int10"))
664            return FALSE;
665
666        pVesa = pGeode->vesa;
667
668        if ((pVesa->pInt = xf86InitInt10(pGeode->pEnt->index)) == NULL) {
669            xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
670                       "Unable to initialize 1NT10 support\n");
671            pGeode->useVGA = FALSE;
672        }
673#endif
674    }
675
676    /* First try to get the framebuffer size from the framebuffer,
677     * and if that fails, revert all  the way back to the legacy
678     * method
679     */
680
681    if (pGeode->FBAvail == 0) {
682        if (GeodeGetSizeFromFB(&pGeode->FBAvail))
683            pGeode->FBAvail = gfx_get_frame_buffer_size();
684    }
685
686    if (pScrni->memPhysBase == 0)
687        pScrni->memPhysBase = gfx_get_frame_buffer_base();
688
689    pScrni->fbOffset = 0;
690
691    if (pGeode->pEnt->device->videoRam == 0)
692        pScrni->videoRam = pGeode->FBAvail / 1024;
693    else
694        pScrni->videoRam = pGeode->pEnt->device->videoRam;
695
696    GeodeClockRange = (ClockRangePtr) xnfcalloc(1, sizeof(ClockRange));
697    GeodeClockRange->next = NULL;
698    GeodeClockRange->minClock = 25175;
699    GeodeClockRange->maxClock = 229500;
700    GeodeClockRange->clockIndex = -1;
701    GeodeClockRange->interlaceAllowed = TRUE;
702    GeodeClockRange->doubleScanAllowed = FALSE;
703
704    pScrni->monitor->DDC = GeodeDoDDC(pScrni, pGeode->pEnt->index);
705
706    /* I'm still not 100% sure this uses the right values */
707
708    modecnt = xf86ValidateModes(pScrni,
709                                pScrni->monitor->Modes,
710                                pScrni->display->modes,
711                                GeodeClockRange,
712                                NULL, GX_MIN_PITCH, GX_MAX_PITCH,
713                                32, GX_MIN_HEIGHT, GX_MAX_HEIGHT,
714                                pScrni->display->virtualX,
715                                pScrni->display->virtualY, pGeode->FBAvail,
716                                LOOKUP_BEST_REFRESH);
717
718    if (modecnt <= 0) {
719        xf86DrvMsg(pScrni->scrnIndex, X_ERROR, "No valid modes were found\n");
720        return FALSE;
721    }
722
723    xf86PruneDriverModes(pScrni);
724
725    if (pScrni->modes == NULL) {
726        xf86DrvMsg(pScrni->scrnIndex, X_ERROR, "No valid modes were found\n");
727        return FALSE;
728    }
729
730    xf86SetCrtcForModes(pScrni, 0);
731    pScrni->currentMode = pScrni->modes;
732
733    xf86PrintModes(pScrni);
734    xf86SetDpi(pScrni, 0, 0);
735
736    /* Load the modules we'll need */
737
738    if (xf86LoadSubModule(pScrni, "fb") == NULL) {
739        return FALSE;
740    }
741
742    if (pGeode->NoAccel == FALSE) {
743        const char *module = (pGeode->useEXA) ? "exa" : "xaa";
744
745        if (!xf86LoadSubModule(pScrni, module)) {
746            return FALSE;
747        }
748    }
749
750    if (pGeode->tryHWCursor == TRUE) {
751        if (!xf86LoadSubModule(pScrni, "ramdac")) {
752            return FALSE;
753        }
754    }
755
756#ifndef XSERVER_LIBPCIACCESS
757    if (xf86RegisterResources(pGeode->pEnt->index, NULL, ResExclusive)) {
758        xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
759                   "Couldn't register the resources.\n");
760        return FALSE;
761    }
762#endif
763    return TRUE;
764}
765
766static void
767GXRestore(ScrnInfoPtr pScrni)
768{
769    GeodeRec *pGeode = GEODEPTR(pScrni);
770
771    if (pGeode->useVGA && pGeode->FBVGAActive) {
772        vgaHWPtr pvgaHW = VGAHWPTR(pScrni);
773
774        vgaHWProtect(pScrni, TRUE);
775        vgaHWRestore(pScrni, &pvgaHW->SavedReg, VGA_SR_ALL);
776        vgaHWProtect(pScrni, FALSE);
777    }
778}
779
780static Bool
781GXUnmapMem(ScrnInfoPtr pScrni)
782{
783    GeodeRec *pGeode = GEODEPTR(pScrni);
784
785    /* unmap all the memory map's */
786#ifndef XSERVER_LIBPCIACCESS
787    xf86UnMapVidMem(pScrni->scrnIndex, gfx_virt_regptr, GX_CPU_REG_SIZE);
788    xf86UnMapVidMem(pScrni->scrnIndex, gfx_virt_gpptr, GX_GP_REG_SIZE);
789    xf86UnMapVidMem(pScrni->scrnIndex, gfx_virt_vidptr, GX_VID_REG_SIZE);
790    xf86UnMapVidMem(pScrni->scrnIndex, gfx_virt_fbptr, pGeode->FBAvail);
791#else
792    pciVideoPtr pci = xf86GetPciInfoForEntity(pGeode->pEnt->index);
793
794    unmap_pci_mem(pScrni, pci, gfx_virt_regptr, GX_CPU_REG_SIZE);
795    unmap_pci_mem(pScrni, pci, gfx_virt_gpptr, GX_GP_REG_SIZE);
796    unmap_pci_mem(pScrni, pci, gfx_virt_vidptr, GX_VID_REG_SIZE);
797    unmap_pci_mem(pScrni, pci, gfx_virt_fbptr, pGeode->FBAvail);
798
799    munmap(XpressROMPtr, 0x10000);
800#endif
801    return TRUE;
802}
803
804static void
805GXSetDvLineSize(unsigned int pitch)
806{
807    unsigned long temp, dv_size = MDC_DV_LINE_SIZE_1024;
808
809    if (pitch > 1024) {
810        dv_size = MDC_DV_LINE_SIZE_2048;
811    }
812    if (pitch > 2048) {
813        dv_size = MDC_DV_LINE_SIZE_4096;
814    }
815    if (pitch > 4096) {
816        dv_size = MDC_DV_LINE_SIZE_8192;
817    }
818
819    /* WRITE DIRTY/VALID CONTROL WITH LINE LENGTH */
820
821    temp = READ_REG32(MDC_DV_CTL);
822    WRITE_REG32(MDC_DV_CTL, (temp & ~MDC_DV_LINE_SIZE_MASK) | dv_size);
823}
824
825/* XXX - this is nothing like the original function - not sure exactly what the purpose is for this quite yet */
826
827static void
828GXAdjustFrame(ADJUST_FRAME_ARGS_DECL)
829{
830    SCRN_INFO_PTR(arg);
831    GeodeRec *pGeode = GEODEPTR(pScrni);
832    unsigned long offset;
833
834    offset = y * pGeode->Pitch + x * (pScrni->bitsPerPixel >> 3);
835
836    gfx_set_display_offset(offset);
837}
838
839static Bool
840GXSetVideoMode(ScrnInfoPtr pScrni, DisplayModePtr pMode)
841{
842    GeodeRec *pGeode = GEODEPTR(pScrni);
843    int flags = 0;
844    int custom = 0;
845
846    pScrni->vtSema = TRUE;
847
848    gx_disable_dac_power();
849
850    if (pMode->Flags & V_NHSYNC)
851        flags |= 1;
852    if (pMode->Flags & V_NVSYNC)
853        flags |= 2;
854
855    /* Check to see if we should use custom or built-in timings */
856
857    if (pGeode->Panel)
858        custom = (pMode->type & M_T_USERDEF);
859    else
860        custom = !(pMode->type & (M_T_BUILTIN | M_T_DEFAULT));
861
862    /* If we're not doing a custom mode, then just set the fixed timings,
863     * otherwise, do the whole shooting match */
864
865    if (!custom) {
866        GFX(set_fixed_timings(pGeode->PanelX, pGeode->PanelY,
867                              pMode->CrtcHDisplay, pMode->CrtcVDisplay,
868                              pScrni->bitsPerPixel));
869    }
870    else {
871        if (pGeode->Panel)
872            GFX(set_panel_present(pGeode->PanelX, pGeode->PanelY,
873                                  pMode->CrtcHDisplay, pMode->CrtcVDisplay,
874                                  pScrni->bitsPerPixel));
875
876        GFX(set_display_timings(pScrni->bitsPerPixel, flags,
877                                pMode->CrtcHDisplay, pMode->CrtcHBlankStart,
878                                pMode->CrtcHSyncStart, pMode->CrtcHSyncEnd,
879                                pMode->CrtcHBlankEnd, pMode->CrtcHTotal,
880                                pMode->CrtcVDisplay, pMode->CrtcVBlankStart,
881                                pMode->CrtcVSyncStart, pMode->CrtcVSyncEnd,
882                                pMode->CrtcVBlankEnd, pMode->CrtcVTotal,
883                                (int) ((pMode->SynthClock / 1000.0) *
884                                       0x10000)));
885    }
886
887    GFX(set_crt_enable(CRT_ENABLE));
888    GFX(set_display_pitch(pGeode->displayPitch));
889    GFX(set_display_offset(0L));
890    GFX(wait_vertical_blank());
891
892    if (pGeode->Compression) {
893        GXSetDvLineSize(pGeode->Pitch);
894
895        gfx_set_compression_offset(pGeode->CBData.compression_offset);
896        gfx_set_compression_pitch(GX_CB_PITCH);
897        gfx_set_compression_size(GX_CB_SIZE);
898
899        gfx_set_compression_enable(1);
900    }
901
902    if (pGeode->HWCursor && !(pMode->Flags & V_DBLSCAN)) {
903        GXLoadCursorImage(pScrni, NULL);
904        GFX(set_cursor_position(pGeode->CursorStartOffset, 0, 0, 0, 0));
905        GXShowCursor(pScrni);
906    }
907    else {
908        GFX(set_cursor_enable(0));
909        pGeode->HWCursor = FALSE;
910    }
911
912    GXAdjustFrame(ADJUST_FRAME_ARGS(pScrni->frameX0, pScrni->frameY0));
913    gx_enable_dac_power();
914
915    return TRUE;
916}
917
918static Bool
919GXSwitchMode(SWITCH_MODE_ARGS_DECL)
920{
921    SCRN_INFO_PTR(arg);
922    GeodeRec *pGeode = GEODEPTR(pScrni);
923    int ret = TRUE;
924    int rotate;
925
926    /* Syn the engine and shutdown the DAC momentarily */
927
928    gfx_wait_until_idle();
929
930    /* Set up the memory for the new mode */
931    rotate = GXGetRotation(pScrni->pScreen);
932    ret = GXAllocateMemory(pScrni->pScreen, pScrni, rotate);
933
934    if (ret) {
935        if (pGeode->curMode != pMode)
936            ret = GXSetVideoMode(pScrni, pMode);
937    }
938
939    if (ret)
940        ret = GXRotate(pScrni, pMode);
941
942    /* Go back the way it was */
943
944    if (ret == FALSE) {
945        if (!GXSetVideoMode(pScrni, pGeode->curMode))
946            xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
947                       "Could not restore the previous mode\n");
948    }
949    else
950        pGeode->curMode = pMode;
951
952    return ret;
953}
954
955static void
956GXLeaveGraphics(ScrnInfoPtr pScrni)
957{
958    GeodeRec *pGeode = GEODEPTR(pScrni);
959
960    gfx_wait_until_idle();
961
962    /* Restore VG registers */
963    gfx_set_display_timings(pGeode->FBgfxdisplaytiming.wBpp,
964                            pGeode->FBgfxdisplaytiming.wPolarity,
965                            pGeode->FBgfxdisplaytiming.wHActive,
966                            pGeode->FBgfxdisplaytiming.wHBlankStart,
967                            pGeode->FBgfxdisplaytiming.wHSyncStart,
968                            pGeode->FBgfxdisplaytiming.wHSyncEnd,
969                            pGeode->FBgfxdisplaytiming.wHBlankEnd,
970                            pGeode->FBgfxdisplaytiming.wHTotal,
971                            pGeode->FBgfxdisplaytiming.wVActive,
972                            pGeode->FBgfxdisplaytiming.wVBlankStart,
973                            pGeode->FBgfxdisplaytiming.wVSyncStart,
974                            pGeode->FBgfxdisplaytiming.wVSyncEnd,
975                            pGeode->FBgfxdisplaytiming.wVBlankEnd,
976                            pGeode->FBgfxdisplaytiming.wVTotal,
977                            pGeode->FBgfxdisplaytiming.dwDotClock);
978
979    gfx_set_compression_enable(0);
980
981    /* Restore the previous Compression state */
982    if (pGeode->FBCompressionEnable) {
983        gfx_set_compression_offset(pGeode->FBCompressionOffset);
984        gfx_set_compression_pitch(pGeode->FBCompressionPitch);
985        gfx_set_compression_size(pGeode->FBCompressionSize);
986        gfx_set_compression_enable(1);
987    }
988
989    gfx_set_display_pitch(pGeode->FBgfxdisplaytiming.wPitch);
990
991    gfx_set_display_offset(pGeode->FBDisplayOffset);
992
993    /* Restore Cursor */
994    gfx_set_cursor_position(pGeode->FBCursorOffset, 0, 0, 0, 0);
995
996    if (pGeode->useVGA) {
997        pGeode->vesa->pInt->num = 0x10;
998        pGeode->vesa->pInt->ax = 0x0 | pGeode->FBBIOSMode;
999        pGeode->vesa->pInt->bx = 0;
1000        xf86ExecX86int10(pGeode->vesa->pInt);
1001        gfx_delay_milliseconds(3);
1002    }
1003
1004    GXRestore(pScrni);
1005
1006    gx_enable_dac_power();
1007}
1008
1009static Bool
1010GXCloseScreen(CLOSE_SCREEN_ARGS_DECL)
1011{
1012    ScrnInfoPtr pScrni = xf86ScreenToScrn(pScrn);
1013    GeodeRec *pGeode = GEODEPTR(pScrni);
1014
1015    if (pScrni->vtSema)
1016        GXLeaveGraphics(pScrni);
1017
1018#ifdef XF86XAA
1019    if (pGeode->AccelInfoRec)
1020        XAADestroyInfoRec(pGeode->AccelInfoRec);
1021#endif
1022
1023    if (pGeode->AccelImageWriteBuffers) {
1024        free(pGeode->AccelImageWriteBuffers[0]);
1025        free(pGeode->AccelImageWriteBuffers);
1026        pGeode->AccelImageWriteBuffers = NULL;
1027    }
1028
1029    if (pGeode->AccelColorExpandBuffers) {
1030        free(pGeode->AccelColorExpandBuffers);
1031        pGeode->AccelColorExpandBuffers = NULL;
1032    }
1033
1034    if (pGeode->pExa) {
1035        exaDriverFini(pScrn);
1036        free(pGeode->pExa);
1037        pGeode->pExa = NULL;
1038    }
1039
1040    pScrni->vtSema = FALSE;
1041
1042    GXUnmapMem(pScrni);
1043
1044    pScrni->PointerMoved = pGeode->PointerMoved;
1045    pScrn->CloseScreen = pGeode->CloseScreen;
1046
1047    if (pScrn->CloseScreen)
1048        return (*pScrn->CloseScreen) (CLOSE_SCREEN_ARGS);
1049
1050    return TRUE;
1051}
1052
1053static Bool
1054GXEnterGraphics(ScreenPtr pScrn, ScrnInfoPtr pScrni)
1055{
1056    GeodeRec *pGeode = GEODEPTR(pScrni);
1057
1058    if (!GXMapMem(pScrni))
1059        return FALSE;
1060
1061    if (pGeode->useVGA)
1062        pGeode->FBVGAActive = gu2_get_vga_active();
1063
1064    gfx_wait_until_idle();
1065
1066    /* Save off the current state (should this be somewhere else)? */
1067
1068    pGeode->FBgfxdisplaytiming.dwDotClock = gfx_get_clock_frequency();
1069    pGeode->FBgfxdisplaytiming.wPitch = gfx_get_display_pitch();
1070    pGeode->FBgfxdisplaytiming.wBpp = gfx_get_display_bpp();
1071    pGeode->FBgfxdisplaytiming.wHTotal = gfx_get_htotal();
1072    pGeode->FBgfxdisplaytiming.wHActive = gfx_get_hactive();
1073    pGeode->FBgfxdisplaytiming.wHSyncStart = gfx_get_hsync_start();
1074    pGeode->FBgfxdisplaytiming.wHSyncEnd = gfx_get_hsync_end();
1075    pGeode->FBgfxdisplaytiming.wHBlankStart = gfx_get_hblank_start();
1076    pGeode->FBgfxdisplaytiming.wHBlankEnd = gfx_get_hblank_end();
1077    pGeode->FBgfxdisplaytiming.wVTotal = gfx_get_vtotal();
1078    pGeode->FBgfxdisplaytiming.wVActive = gfx_get_vactive();
1079    pGeode->FBgfxdisplaytiming.wVSyncStart = gfx_get_vsync_start();
1080    pGeode->FBgfxdisplaytiming.wVSyncEnd = gfx_get_vsync_end();
1081    pGeode->FBgfxdisplaytiming.wVBlankStart = gfx_get_vblank_start();
1082    pGeode->FBgfxdisplaytiming.wVBlankEnd = gfx_get_vblank_end();
1083    pGeode->FBgfxdisplaytiming.wPolarity = gfx_get_sync_polarities();
1084
1085    pGeode->FBDisplayOffset = gfx_get_display_offset();
1086
1087    if (pGeode->useVGA) {
1088        vgaHWPtr pvgaHW = VGAHWPTR(pScrni);
1089
1090        pGeode->FBBIOSMode = pvgaHW->readCrtc(pvgaHW, 0x040);
1091    }
1092
1093    pGeode->FBCompressionEnable = gfx_get_compression_enable();
1094    pGeode->FBCompressionOffset = gfx_get_compression_offset();
1095    pGeode->FBCompressionPitch = gfx_get_compression_pitch();
1096    pGeode->FBCompressionSize = gfx_get_compression_size();
1097
1098#ifdef PNL_SUP
1099    Pnl_SavePanelState();
1100#endif
1101
1102    /* Turn off the VGA */
1103
1104    if (pGeode->useVGA && pGeode->FBVGAActive) {
1105        unsigned short sequencer;
1106        vgaHWPtr pvgaHW = VGAHWPTR(pScrni);
1107
1108        /* Map VGA aperture */
1109        if (!vgaHWMapMem(pScrni))
1110            return FALSE;
1111
1112        /* Unlock VGA registers */
1113        vgaHWUnlock(pvgaHW);
1114
1115        /* Save the current state and setup the current mode */
1116        vgaHWSave(pScrni, &VGAHWPTR(pScrni)->SavedReg, VGA_SR_ALL);
1117
1118        /* DISABLE VGA SEQUENCER */
1119        /* This allows the VGA state machine to terminate. We must delay */
1120        /* such that there are no pending MBUS requests.  */
1121
1122        gfx_outb(MDC_SEQUENCER_INDEX, MDC_SEQUENCER_CLK_MODE);
1123        sequencer = gfx_inb(MDC_SEQUENCER_DATA);
1124        sequencer |= MDC_CLK_MODE_SCREEN_OFF;
1125        gfx_outb(MDC_SEQUENCER_DATA, sequencer);
1126
1127        gfx_delay_milliseconds(1);
1128
1129        /* BLANK THE VGA DISPLAY */
1130        gfx_outw(MDC_SEQUENCER_INDEX, MDC_SEQUENCER_RESET);
1131        sequencer = gfx_inb(MDC_SEQUENCER_DATA);
1132        sequencer &= ~MDC_RESET_VGA_DISP_ENABLE;
1133        gfx_outb(MDC_SEQUENCER_DATA, sequencer);
1134
1135        gfx_delay_milliseconds(1);
1136    }
1137
1138    /* Set up the memory */
1139    /* XXX - FIXME - when we alow inital rotation, it should be here */
1140    GXAllocateMemory(pScrn, pScrni, pGeode->rotation);
1141
1142    /* Clear the framebuffer */
1143    memset(pGeode->FBBase + pGeode->displayOffset, 0, pGeode->displaySize);
1144
1145    /* Set up the video mode */
1146    GXSetVideoMode(pScrni, pScrni->currentMode);
1147    pGeode->curMode = pScrni->currentMode;
1148
1149    return TRUE;
1150}
1151
1152static void
1153GXLoadPalette(ScrnInfoPtr pScrni,
1154              int numColors, int *indizes, LOCO * colors, VisualPtr pVisual)
1155{
1156    int i, index, color;
1157
1158    for (i = 0; i < numColors; i++) {
1159        index = indizes[i] & 0xFF;
1160        color = (((unsigned long) (colors[index].red & 0xFF)) << 16) |
1161            (((unsigned long) (colors[index].green & 0xFF)) << 8) |
1162            ((unsigned long) (colors[index].blue & 0xFF));
1163
1164        GFX(set_display_palette_entry(index, color));
1165    }
1166}
1167
1168#ifdef DPMSExtension
1169static void
1170GXPanelPower(int enable)
1171{
1172    unsigned long power = READ_VID32(RCDF_POWER_MANAGEMENT);
1173
1174    if (enable != 0)
1175        power |= RCDF_PM_PANEL_POWER_ON;
1176    else
1177        power &= ~RCDF_PM_PANEL_POWER_ON;
1178
1179    WRITE_VID32(RCDF_POWER_MANAGEMENT, power);
1180}
1181
1182static void
1183GXDPMSSet(ScrnInfoPtr pScrni, int mode, int flags)
1184{
1185    GeodeRec *pGeode;
1186
1187    pGeode = GEODEPTR(pScrni);
1188
1189    if (!pScrni->vtSema)
1190        return;
1191
1192    switch (mode) {
1193    case DPMSModeOn:
1194        /* Screen: On; HSync: On; VSync: On */
1195        GFX(set_crt_enable(CRT_ENABLE));
1196#if defined(PNL_SUP)
1197        if (pGeode->Panel) {
1198            Pnl_PowerUp();
1199            GXPanelPower(1);
1200        }
1201#endif
1202        break;
1203
1204    case DPMSModeStandby:
1205        /* Screen: Off; HSync: Off; VSync: On */
1206        GFX(set_crt_enable(CRT_STANDBY));
1207#if defined(PNL_SUP)
1208        if (pGeode->Panel) {
1209            Pnl_PowerDown();
1210            GXPanelPower(0);
1211        }
1212#endif
1213        break;
1214
1215    case DPMSModeSuspend:
1216        /* Screen: Off; HSync: On; VSync: Off */
1217        GFX(set_crt_enable(CRT_SUSPEND));
1218#if defined(PNL_SUP)
1219        if (pGeode->Panel) {
1220            Pnl_PowerDown();
1221            GXPanelPower(0);
1222        }
1223#endif
1224        break;
1225
1226    case DPMSModeOff:
1227        /* Screen: Off; HSync: Off; VSync: Off */
1228        GFX(set_crt_enable(CRT_DISABLE));
1229#if defined(PNL_SUP)
1230        if (pGeode->Panel) {
1231            Pnl_PowerDown();
1232            GXPanelPower(0);
1233        }
1234#endif
1235        break;
1236    }
1237}
1238#endif
1239
1240static Bool
1241GXCreateScreenResources(ScreenPtr pScreen)
1242{
1243    ScrnInfoPtr pScrni = xf86ScreenToScrn(pScreen);
1244    GeodeRec *pGeode = GEODEPTR(pScrni);
1245
1246    pScreen->CreateScreenResources = pGeode->CreateScreenResources;
1247    if (!(*pScreen->CreateScreenResources) (pScreen))
1248        return FALSE;
1249
1250    if (xf86LoaderCheckSymbol("GXRandRSetConfig")
1251        && pGeode->rotation != RR_Rotate_0) {
1252        Rotation(*GXRandRSetConfig) (ScreenPtr pScreen, Rotation rr, int rate,
1253                                     RRScreenSizePtr pSize) = NULL;
1254
1255        RRScreenSize p;
1256        Rotation requestedRotation = pGeode->rotation;
1257
1258        pGeode->rotation = RR_Rotate_0;
1259
1260        /* Just setup enough for an initial rotate */
1261
1262        p.width = pScreen->width;
1263        p.height = pScreen->height;
1264        p.mmWidth = pScreen->mmWidth;
1265        p.mmHeight = pScreen->mmHeight;
1266
1267        GXRandRSetConfig = LoaderSymbol("GXRandRSetConfig");
1268        if (GXRandRSetConfig) {
1269            pGeode->starting = TRUE;
1270            (*GXRandRSetConfig) (pScreen, requestedRotation, 0, &p);
1271            pGeode->starting = FALSE;
1272        }
1273    }
1274
1275    return TRUE;
1276}
1277
1278static Bool
1279GXScreenInit(SCREEN_INIT_ARGS_DECL)
1280{
1281    ScrnInfoPtr pScrni = xf86ScreenToScrn(pScrn);
1282    GeodeRec *pGeode = GEODEPTR(pScrni);
1283    XF86ModReqInfo shadowReq;
1284    int maj, min, ret, rotate;
1285
1286    pGeode->starting = TRUE;
1287
1288    /* If we are using VGA then go ahead and map the memory */
1289
1290    if (pGeode->useVGA) {
1291
1292        if (!vgaHWMapMem(pScrni))
1293            return FALSE;
1294
1295        vgaHWGetIOBase(VGAHWPTR(pScrni));
1296    }
1297
1298    if (!pGeode->NoAccel) {
1299
1300        if (pGeode->useEXA) {
1301
1302            if (!(pGeode->pExa = exaDriverAlloc())) {
1303                xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
1304                           "Couldn't allocate the EXA structure.\n");
1305                pGeode->NoAccel = TRUE;
1306            }
1307            else {
1308                ExaDriverPtr pExa = pGeode->pExa;
1309
1310                /* THis is set in GXAllocMem */
1311                pExa->memoryBase = 0;
1312
1313                /* This is set in GXAllocateMemory */
1314                pExa->memorySize = 0;
1315
1316                pExa->pixmapOffsetAlign = 32;
1317                pExa->pixmapPitchAlign = 32;
1318                pExa->flags = EXA_OFFSCREEN_PIXMAPS;
1319                pExa->maxX = GX_MAX_WIDTH - 1;
1320                pExa->maxY = GX_MAX_HEIGHT - 1;
1321            }
1322        }
1323        else {
1324            pGeode->AccelImageWriteBuffers =
1325                calloc(pGeode->NoOfImgBuffers,
1326                       sizeof(pGeode->AccelImageWriteBuffers[0]));
1327            pGeode->AccelColorExpandBuffers =
1328                calloc(pGeode->NoOfColorExpandLines,
1329                       sizeof(pGeode->AccelColorExpandBuffers[0]));
1330        }
1331    }
1332
1333    /* XXX FIXME - Take down any of the structures on failure? */
1334
1335    if (!GXEnterGraphics(pScrn, pScrni))
1336        return FALSE;
1337
1338    miClearVisualTypes();
1339
1340    /* XXX Again - take down anything? */
1341
1342    if (pScrni->bitsPerPixel > 8) {
1343        if (!miSetVisualTypes(pScrni->depth,
1344                              TrueColorMask, pScrni->rgbBits,
1345                              pScrni->defaultVisual)) {
1346            return FALSE;
1347        }
1348    }
1349    else {
1350        if (!miSetVisualTypes(pScrni->depth,
1351                              miGetDefaultVisualMask(pScrni->depth),
1352                              pScrni->rgbBits, pScrni->defaultVisual)) {
1353            return FALSE;
1354        }
1355    }
1356
1357    miSetPixmapDepths();
1358
1359    /* Point at the visible area to start */
1360
1361    ret = fbScreenInit(pScrn, pGeode->FBBase + pGeode->displayOffset,
1362                       pScrni->virtualX, pScrni->virtualY,
1363                       pScrni->xDpi, pScrni->yDpi, pGeode->displayWidth,
1364                       pScrni->bitsPerPixel);
1365
1366    if (!ret)
1367        return FALSE;
1368
1369    xf86SetBlackWhitePixels(pScrn);
1370
1371    /* Set up the color ordering */
1372
1373    if (pScrni->bitsPerPixel > 8) {
1374        VisualPtr visual = pScrn->visuals + pScrn->numVisuals;
1375
1376        while (--visual >= pScrn->visuals) {
1377            if ((visual->class | DynamicClass) == DirectColor) {
1378                visual->offsetRed = pScrni->offset.red;
1379                visual->offsetGreen = pScrni->offset.green;
1380                visual->offsetBlue = pScrni->offset.blue;
1381                visual->redMask = pScrni->mask.red;
1382                visual->greenMask = pScrni->mask.green;
1383                visual->blueMask = pScrni->mask.blue;
1384            }
1385        }
1386    }
1387
1388    /* Must follow the color ordering */
1389    fbPictureInit(pScrn, 0, 0);
1390
1391    if (!pGeode->NoAccel)
1392        GXAccelInit(pScrn);
1393
1394    xf86SetBackingStore(pScrn);
1395
1396    /* Set up the soft cursor */
1397    miDCInitialize(pScrn, xf86GetPointerScreenFuncs());
1398
1399    /* Set up the HW cursor - must follow the soft cursor init */
1400
1401    if (pGeode->tryHWCursor) {
1402        if (!GXHWCursorInit(pScrn))
1403            xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
1404                       "Hardware cursor initialization failed.\n");
1405    }
1406
1407    /* Set up the color map */
1408
1409    if (!miCreateDefColormap(pScrn))
1410        return FALSE;
1411
1412    if (pScrni->bitsPerPixel == 8) {
1413        /* Must follow initialization of the default colormap */
1414
1415        if (!xf86HandleColormaps(pScrn, 256, 8,
1416                                 GXLoadPalette, NULL,
1417                                 CMAP_PALETTED_TRUECOLOR |
1418                                 CMAP_RELOAD_ON_MODE_SWITCH)) {
1419            return FALSE;
1420        }
1421    }
1422#ifdef DPMSExtension
1423    xf86DPMSInit(pScrn, GXDPMSSet, 0);
1424#endif
1425
1426    GXInitVideo(pScrn);
1427
1428    /* Set up RandR */
1429
1430    xf86DisableRandR();         /* We provide our own RandR goodness */
1431
1432    /* Try to set up the shadow FB for rotation */
1433
1434    memset(&shadowReq, 0, sizeof(shadowReq));
1435    shadowReq.majorversion = 1;
1436    shadowReq.minorversion = 1;
1437
1438    if (LoadSubModule(pScrni->module, "shadow",
1439                      NULL, NULL, NULL, &shadowReq, &maj, &min)) {
1440
1441        rotate = RR_Rotate_0 | RR_Rotate_90 | RR_Rotate_180 | RR_Rotate_270;
1442        shadowSetup(pScrn);
1443    }
1444    else {
1445        LoaderErrorMsg(NULL, "shadow", maj, min);
1446        xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
1447                   "Error loading shadow - rotation not available.\n");
1448
1449        if (pGeode->rotation != RR_Rotate_0)
1450            xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
1451                       "Reverting back to normal rotation.\n");
1452
1453        rotate = pGeode->rotation = RR_Rotate_0;
1454    }
1455
1456    GXRandRInit(pScrn, rotate);
1457
1458    pGeode->PointerMoved = pScrni->PointerMoved;
1459    pScrni->PointerMoved = GeodePointerMoved;
1460
1461    pGeode->CreateScreenResources = pScrn->CreateScreenResources;
1462    pScrn->CreateScreenResources = GXCreateScreenResources;
1463
1464    pGeode->CloseScreen = pScrn->CloseScreen;
1465    pScrn->CloseScreen = GXCloseScreen;
1466    pScrn->SaveScreen = GXSaveScreen;
1467
1468    if (serverGeneration == 1)
1469        xf86ShowUnusedOptions(pScrni->scrnIndex, pScrni->options);
1470
1471    pGeode->starting = FALSE;
1472
1473    return TRUE;
1474}
1475
1476static int
1477GXValidMode(VALID_MODE_ARGS_DECL)
1478{
1479    SCRN_INFO_PTR(arg);
1480    GeodeRec *pGeode = GEODEPTR(pScrni);
1481    int p;
1482    int custom = 0;
1483
1484    if (pGeode->Panel)
1485        custom = (pMode->type & M_T_USERDEF);
1486    else
1487        custom = (pMode->type & (M_T_BUILTIN | M_T_DEFAULT));
1488
1489    /* Use the durango lookup for !custom modes */
1490
1491    if (!custom && pGeode->Panel) {
1492        if (pMode->CrtcHDisplay > pGeode->PanelX ||
1493            pMode->CrtcVDisplay > pGeode->PanelY ||
1494            gfx_is_panel_mode_supported(pGeode->PanelX,
1495                                        pGeode->PanelY,
1496                                        pMode->CrtcHDisplay,
1497                                        pMode->CrtcVDisplay,
1498                                        pScrni->bitsPerPixel) < 0) {
1499
1500            return MODE_BAD;
1501        }
1502    }
1503
1504    if (gfx_is_display_mode_supported(pMode->CrtcHDisplay,
1505                                      pMode->CrtcVDisplay,
1506                                      pScrni->bitsPerPixel,
1507                                      GeodeGetRefreshRate(pMode)) < 0) {
1508        return MODE_BAD;
1509    }
1510
1511    if (pMode->Flags & V_INTERLACE)
1512        return MODE_NO_INTERLACE;
1513
1514    if (pGeode->tryCompression)
1515        p = GeodeCalculatePitchBytes(pMode->CrtcHDisplay, pScrni->bitsPerPixel);
1516    else
1517        p = ((pMode->CrtcHDisplay + 3) & ~3) * (pScrni->bitsPerPixel >> 3);
1518
1519    if (p * pMode->CrtcVDisplay > pGeode->FBAvail)
1520        return MODE_MEM;
1521
1522    return MODE_OK;
1523}
1524
1525/* XXX - Way more to do here */
1526
1527static Bool
1528GXEnterVT(VT_FUNC_ARGS_DECL)
1529{
1530    SCRN_INFO_PTR(arg);
1531    return GXEnterGraphics(NULL, pScrni);
1532}
1533
1534static void
1535GXLeaveVT(VT_FUNC_ARGS_DECL)
1536{
1537    SCRN_INFO_PTR(arg);
1538    GeodeRec *pGeode = GEODEPTR(pScrni);
1539
1540    pGeode->PrevDisplayOffset = gfx_get_display_offset();
1541    GXLeaveGraphics(pScrni);
1542}
1543
1544void
1545GXSetupChipsetFPtr(ScrnInfoPtr pScrn)
1546{
1547    pScrn->PreInit = GXPreInit;
1548    pScrn->ScreenInit = GXScreenInit;
1549    pScrn->SwitchMode = GXSwitchMode;
1550    pScrn->AdjustFrame = GXAdjustFrame;
1551    pScrn->EnterVT = GXEnterVT;
1552    pScrn->LeaveVT = GXLeaveVT;
1553    pScrn->FreeScreen = GeodeFreeScreen;
1554    pScrn->ValidMode = GXValidMode;
1555}
1556
1557/* ====== Common functions ======
1558 * These are all the common functions that we use for both GX and LX - They live here
1559 * because most of them came along for the GX first, and then were adapted to the LX.
1560 *  We could move these to a common function, but there is no hurry
1561 * ============================== */
1562
1563void
1564GeodePointerMoved(POINTER_MOVED_ARGS_DECL)
1565{
1566    SCRN_INFO_PTR(arg);
1567    GeodeRec *pGeode = GEODEPTR(pScrni);
1568
1569    int newX = x, newY = y;
1570
1571    switch (pGeode->rotation) {
1572    case RR_Rotate_0:
1573        break;
1574    case RR_Rotate_90:
1575        newX = y;
1576        newY = pScrni->pScreen->width - x - 1;
1577        break;
1578    case RR_Rotate_180:
1579        newX = pScrni->pScreen->width - x - 1;
1580        newY = pScrni->pScreen->height - y - 1;
1581        break;
1582    case RR_Rotate_270:
1583        newX = pScrni->pScreen->height - y - 1;
1584        newY = x;
1585        break;
1586    }
1587
1588    (*pGeode->PointerMoved) (POINTER_MOVED_ARGS(newX, newY));
1589}
1590
1591int
1592GeodeGetFPGeometry(const char *str, int *width, int *height)
1593{
1594
1595    int ret = sscanf(str, "%dx%d", width, height);
1596
1597    return (ret == 2) ? 0 : 1;
1598}
1599
1600static void
1601GeodeFreeRec(ScrnInfoPtr pScrni)
1602{
1603    if (pScrni->driverPrivate != NULL) {
1604        free(pScrni->driverPrivate);
1605        pScrni->driverPrivate = NULL;
1606    }
1607}
1608
1609void
1610GeodeFreeScreen(FREE_SCREEN_ARGS_DECL)
1611{
1612    SCRN_INFO_PTR(arg);
1613    GeodeRec *pGeode = GEODEPTR(pScrni);
1614
1615    if (pGeode == NULL)
1616        return;
1617
1618    if (pGeode->useVGA) {
1619        if (xf86LoaderCheckSymbol("vgaHWFreeHWRec"))
1620            vgaHWFreeHWRec(pScrni);
1621    }
1622
1623    GeodeFreeRec(pScrni);
1624}
1625
1626int
1627GeodeCalculatePitchBytes(unsigned int width, unsigned int bpp)
1628{
1629
1630    int delta = width * (bpp >> 3);
1631
1632    /* Less then 640 has doubling enabled */
1633
1634    if (width < 640)
1635        delta <<= 1;
1636
1637    /* Calculate the pitch (compression rquires a power of 2) */
1638
1639    if (delta > 4096)
1640        delta = 8192;
1641    else if (delta > 2048)
1642        delta = 4096;
1643    else if (delta > 1024)
1644        delta = 2048;
1645    else
1646        delta = 1024;
1647
1648    return delta;
1649}
1650