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