lx_driver.c revision 04007eba
1/* Copyright (c) 2003-2008 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 <string.h>
36
37#include "xf86.h"
38#include "xf86_OSproc.h"
39#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 6
40#include "xf86Resources.h"
41#endif
42#include "xf86i2c.h"
43#include "xf86Crtc.h"
44#include "xf86cmap.h"
45#include "compiler.h"
46#include "mipointer.h"
47#include "fb.h"
48#include "miscstruct.h"
49#include "micmap.h"
50#include "vbe.h"
51#include "fb.h"
52#include "cim_defs.h"
53#include "cim_regs.h"
54#include "geode.h"
55
56/* Bring in VGA functions */
57#include "lx_vga.c"
58
59#define LX_MAX_WIDTH  1940
60#define LX_MAX_HEIGHT 1600
61
62/* Size of the register blocks */
63
64#define LX_GP_REG_SIZE  0x4000
65#define LX_VG_REG_SIZE  0x4000
66#define LX_VID_REG_SIZE 0x4000
67#define LX_VIP_REG_SIZE 0x4000
68
69/* Size of the Cimarron command buffer */
70#define CIM_CMD_BFR_SZ 0x200000
71
72extern OptionInfoRec LX_GeodeOptions[];
73
74unsigned char *XpressROMPtr;
75
76static Bool
77LXSaveScreen(ScreenPtr pScrn, int mode)
78{
79    ScrnInfoPtr pScrni = xf86ScreenToScrn(pScrn);
80    GeodePtr pGeode = GEODEPTR(pScrni);
81
82    if (pGeode->useVGA && !pScrni->vtSema)
83        return vgaHWSaveScreen(pScrn, mode);
84
85    return TRUE;
86}
87
88/* This is an overly complex MSR read mechanism */
89
90/* From Cimarron - the VSAII read/write methods - we use these as fallback */
91
92#define LX_MSR_READ(adr,lo,hi)              \
93     __asm__ __volatile__(                      \
94        " mov $0x0AC1C, %%edx\n"                \
95        " mov $0xFC530007, %%eax\n"             \
96        " out %%eax,%%dx\n"                     \
97        " add $2,%%dl\n"                        \
98        " in %%dx, %%ax"                        \
99        : "=a" (lo), "=d" (hi)                  \
100        : "c" (adr))
101
102#define LX_MSR_WRITE(adr,low,high) \
103  { int d0, d1, d2, d3, d4;        \
104  __asm__ __volatile__(            \
105    " push %%ebx\n"                \
106    " mov $0x0AC1C, %%edx\n"       \
107    " mov $0xFC530007, %%eax\n"    \
108    " out %%eax,%%dx\n"            \
109    " add $2,%%dl\n"               \
110    " mov %6, %%ebx\n"             \
111    " mov %7, %0\n"                \
112    " mov %5, %3\n"                \
113    " xor %2, %2\n"                \
114    " xor %1, %1\n"                \
115    " out %%ax, %%dx\n"            \
116    " pop %%ebx\n"                 \
117    : "=a"(d0),"=&D"(d1),"=&S"(d2), \
118      "=c"(d3),"=d"(d4)  \
119    : "1"(adr),"2"(high),"3"(low)); \
120  }
121
122static void
123LXReadMSR(unsigned long addr, unsigned long *lo, unsigned long *hi)
124{
125    if (GeodeReadMSR(addr, lo, hi) == -1) {
126        unsigned int l, h;
127
128        LX_MSR_READ(addr, l, h);
129        *lo = l;
130        *hi = h;
131    }
132}
133
134static void
135LXWriteMSR(unsigned long addr, unsigned long lo, unsigned long hi)
136{
137    if (GeodeWriteMSR(addr, lo, hi) == -1)
138        LX_MSR_WRITE(addr, lo, hi);
139}
140
141static unsigned int
142LXCalcPitch(ScrnInfoPtr pScrni)
143{
144    GeodeRec *pGeode = GEODEPTR(pScrni);
145
146    if (pGeode->tryCompression)
147        return GeodeCalculatePitchBytes(pScrni->virtualX, pScrni->bitsPerPixel);
148    else
149        return ((pScrni->virtualX + 3) & ~3) * (pScrni->bitsPerPixel >> 3);
150}
151
152#ifdef XSERVER_LIBPCIACCESS
153static inline void *
154map_pci_mem(ScrnInfoPtr pScrni, int vram,
155            struct pci_device *dev, int bar, int size)
156{
157    void *ptr;
158    void **result = (void **) &ptr;
159    int map_size = size ? size : dev->regions[bar].size;
160
161    int err = pci_device_map_range(dev,
162                                   dev->regions[bar].base_addr,
163                                   map_size,
164                                   PCI_DEV_MAP_FLAG_WRITABLE |
165                                   (vram ? PCI_DEV_MAP_FLAG_WRITE_COMBINE : 0),
166                                   result);
167
168    if (err)
169        return NULL;
170    return ptr;
171}
172
173static inline int
174unmap_pci_mem(ScrnInfoPtr pScrni, struct pci_device *dev, void *ptr, int size)
175{
176    return pci_device_unmap_range(dev, ptr, size);
177}
178
179#endif
180
181static Bool
182LXMapMem(ScrnInfoPtr pScrni)
183{
184    GeodeRec *pGeode = GEODEPTR(pScrni);
185    int index = pScrni->scrnIndex;
186    unsigned long cmd_bfr_phys;
187
188    pciVideoPtr pci = xf86GetPciInfoForEntity(pGeode->pEnt->index);
189
190#ifndef XSERVER_LIBPCIACCESS
191    PCITAG tag;
192
193    tag = pciTag(pci->bus, pci->device, pci->func);
194
195    cim_gp_ptr = (unsigned char *) xf86MapPciMem(index, VIDMEM_MMIO,
196                                                 tag, pci->memBase[1],
197                                                 LX_GP_REG_SIZE);
198
199    cim_vg_ptr = (unsigned char *) xf86MapPciMem(index, VIDMEM_MMIO,
200                                                 tag, pci->memBase[2],
201                                                 LX_VG_REG_SIZE);
202
203    cim_vid_ptr = (unsigned char *) xf86MapPciMem(index, VIDMEM_MMIO,
204                                                  tag, pci->memBase[3],
205                                                  LX_VID_REG_SIZE);
206
207    cim_vip_ptr = (unsigned char *) xf86MapPciMem(index, VIDMEM_MMIO,
208                                                  tag, pci->memBase[4],
209                                                  LX_VIP_REG_SIZE);
210
211    cim_fb_ptr = (unsigned char *) xf86MapPciMem(index, VIDMEM_FRAMEBUFFER,
212                                                 tag, pci->memBase[0],
213                                                 pGeode->FBAvail +
214                                                 CIM_CMD_BFR_SZ);
215#else
216    cim_gp_ptr = map_pci_mem(pScrni, 0, pci, 1, LX_GP_REG_SIZE);
217    cim_vg_ptr = map_pci_mem(pScrni, 0, pci, 2, LX_VG_REG_SIZE);
218    cim_vid_ptr = map_pci_mem(pScrni, 0, pci, 3, LX_VID_REG_SIZE);
219    cim_vip_ptr = map_pci_mem(pScrni, 0, pci, 4, LX_VIP_REG_SIZE);
220    cim_fb_ptr =
221        map_pci_mem(pScrni, 1, pci, 0, pGeode->FBAvail + CIM_CMD_BFR_SZ);
222#endif
223
224    if (pScrni->memPhysBase == 0)
225        pScrni->memPhysBase = PCI_REGION_BASE(pci, 0, REGION_MEM);
226
227    cmd_bfr_phys = PCI_REGION_BASE(pci, 0, REGION_MEM) + pGeode->CmdBfrOffset;
228    cim_cmd_base_ptr = cim_fb_ptr + pGeode->CmdBfrOffset;
229
230    if (!cim_gp_ptr || !cim_vg_ptr || !cim_vid_ptr || !cim_fb_ptr ||
231        !cim_vip_ptr)
232        return FALSE;
233
234    gp_set_frame_buffer_base(PCI_REGION_BASE(pci, 0, REGION_MEM),
235                             pGeode->FBAvail);
236    gp_set_command_buffer_base(cmd_bfr_phys, 0, pGeode->CmdBfrSize);
237
238    XpressROMPtr = xf86MapVidMem(index, VIDMEM_FRAMEBUFFER, 0xF0000, 0x10000);
239
240    pGeode->FBBase = cim_fb_ptr;
241
242    if (!pGeode->NoAccel)
243        pGeode->pExa->memoryBase = pGeode->FBBase;
244
245    xf86DrvMsg(index, X_INFO, "Geode LX video memory %x bytes at %p\n",
246               pGeode->FBAvail, pGeode->FBBase);
247
248    return TRUE;
249}
250
251/* Check to see if VGA exists - we map the space and look for a
252   signature - if it doesn't match exactly, then we assume no VGA.
253*/
254
255static Bool
256LXCheckVGA(ScrnInfoPtr pScrni)
257{
258
259    unsigned char *ptr;
260    const char *vgasig = "IBM VGA Compatible";
261    int ret;
262
263    ptr =
264        xf86MapVidMem(pScrni->scrnIndex, VIDMEM_FRAMEBUFFER, 0xC001E,
265                      strlen(vgasig));
266
267    if (ptr == NULL)
268        return FALSE;
269
270    ret = memcmp(ptr, vgasig, strlen(vgasig));
271    xf86UnMapVidMem(pScrni->scrnIndex, (pointer) ptr, strlen(vgasig));
272
273    return ret ? FALSE : TRUE;
274}
275
276static Bool
277LXCrtcResize(ScrnInfoPtr pScrni, int width, int height)
278{
279    return TRUE;
280}
281
282static const xf86CrtcConfigFuncsRec lx_xf86crtc_config_funcs = {
283    LXCrtcResize,
284};
285
286static Bool
287LXPreInit(ScrnInfoPtr pScrni, int flags)
288{
289    GeodePtr pGeode;
290    EntityInfoPtr pEnt;
291    OptionInfoRec *GeodeOptions = &LX_GeodeOptions[0];
292    rgb defaultWeight = { 0, 0, 0 };
293    char *s;
294
295    if (pScrni->numEntities != 1)
296        return FALSE;
297
298    pEnt = xf86GetEntityInfo(pScrni->entityList[0]);
299#ifndef XSERVER_LIBPCIACCESS
300    if (pEnt->resources)
301        return FALSE;
302#endif
303    if (flags & PROBE_DETECT) {
304        GeodeProbeDDC(pScrni, pEnt->index);
305        return TRUE;
306    }
307
308    pGeode = pScrni->driverPrivate = xnfcalloc(1, sizeof(GeodeRec));
309
310    if (pGeode == NULL)
311        return FALSE;
312
313    pGeode->useVGA = LXCheckVGA(pScrni);
314    pGeode->VGAActive = FALSE;
315    pGeode->pEnt = pEnt;
316
317    if (pGeode->useVGA) {
318        if (!xf86LoadSubModule(pScrni, "vgahw") || !vgaHWGetHWRec(pScrni))
319            pGeode->useVGA = FALSE;
320        else
321            vgaHWSetStdFuncs(VGAHWPTR(pScrni));
322
323        pGeode->vesa = calloc(1, sizeof(VESARec));
324    }
325
326    cim_rdmsr = LXReadMSR;
327    cim_wrmsr = LXWriteMSR;
328
329    /* Set up the Cimarron MSR tables */
330    msr_init_table();
331
332    /* By default, we support panel and CRT - the config file should
333     * disable the ones we don't want
334     */
335
336    pGeode->Output = OUTPUT_PANEL | OUTPUT_CRT;
337
338    /* Fill in the monitor information */
339    pScrni->monitor = pScrni->confScreen->monitor;
340
341    if (!xf86SetDepthBpp(pScrni, 16, 16, 16, Support24bppFb | Support32bppFb))
342        return FALSE;
343
344    switch (pScrni->depth) {
345    case 8:
346        pScrni->rgbBits = 8;
347    case 16:
348    case 24:
349    case 32:
350        break;
351    default:
352        xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
353                   "The driver does not support %d as a depth.\n",
354                   pScrni->depth);
355        return FALSE;
356    }
357
358    xf86PrintDepthBpp(pScrni);
359
360    if (!xf86SetWeight(pScrni, defaultWeight, defaultWeight))
361        return FALSE;
362
363    if (!xf86SetDefaultVisual(pScrni, -1))
364        return FALSE;
365
366    /*
367     * If the driver can do gamma correction, it should call xf86SetGamma()
368     * here.
369     */
370    {
371        Gamma zeros = { 0.0, 0.0, 0.0 };
372
373        if (!xf86SetGamma(pScrni, zeros)) {
374            return FALSE;
375        }
376    }
377
378    pScrni->progClock = TRUE;
379    xf86CollectOptions(pScrni, NULL);
380    xf86ProcessOptions(pScrni->scrnIndex, pScrni->options, GeodeOptions);
381
382    /* Set up our various options that may get reversed as we go on */
383
384    pGeode->tryHWCursor = TRUE;
385    pGeode->tryCompression = TRUE;
386
387    /* Protect against old versions of EXA */
388
389#if (EXA_VERSION_MAJOR < 2)
390    pGeode->NoAccel = TRUE;
391    xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
392               "*** This driver was compiled with EXA version %d\n");
393    xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
394               "*** we need version 2 or greater\n");
395    xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
396               "*** All accelerations are being turned off.\n");
397#else
398    pGeode->NoAccel = FALSE;
399#endif
400
401    pGeode->exaBfrSz = DEFAULT_EXA_SCRATCH_BFRSZ;
402
403    xf86GetOptValBool(GeodeOptions, LX_OPTION_HW_CURSOR, &pGeode->tryHWCursor);
404
405    if (!xf86GetOptValInteger(GeodeOptions, LX_OPTION_FBSIZE,
406                              (int *) &(pGeode->FBAvail)))
407        pGeode->FBAvail = 0;
408
409    /* For compatability - allow SWCursor too */
410
411    if (xf86ReturnOptValBool(GeodeOptions, LX_OPTION_SW_CURSOR, FALSE))
412        pGeode->tryHWCursor = FALSE;
413
414    if (xf86ReturnOptValBool(GeodeOptions, LX_OPTION_NOCOMPRESSION, FALSE))
415        pGeode->tryCompression = FALSE;
416
417    if (xf86ReturnOptValBool(GeodeOptions, LX_OPTION_NOACCEL, FALSE))
418        pGeode->NoAccel = TRUE;
419
420    pGeode->rotation = RR_Rotate_0;
421
422    if ((s = xf86GetOptValString(GeodeOptions, LX_OPTION_ROTATE))) {
423
424        if (!xf86NameCmp(s, "LEFT"))
425            pGeode->rotation = RR_Rotate_90;
426        else if (!xf86NameCmp(s, "INVERT"))
427            pGeode->rotation = RR_Rotate_180;
428        else if (!xf86NameCmp(s, "CCW"))
429            pGeode->rotation = RR_Rotate_270;
430        else
431            xf86DrvMsg(pScrni->scrnIndex, X_ERROR, "Invalid rotation %s.\n", s);
432    }
433
434    xf86GetOptValInteger(GeodeOptions, LX_OPTION_EXA_SCRATCH_BFRSZ,
435                         (int *) &(pGeode->exaBfrSz));
436
437    if (pGeode->exaBfrSz <= 0)
438        pGeode->exaBfrSz = 0;
439
440    if (pGeode->Output & OUTPUT_PANEL) {
441        if (xf86ReturnOptValBool(GeodeOptions, LX_OPTION_NOPANEL, FALSE))
442            pGeode->Output &= ~OUTPUT_PANEL;
443    }
444
445    /* Panel detection code -
446     * 1.  See if an OLPC DCON is attached - we can make some assumptions
447     * about the panel if so.
448     * 2.  Use panel mode specified in the config
449     * 3.  "Autodetect" the panel through VSA
450     */
451
452    if (dcon_init(pScrni)) {
453        pGeode->Output = OUTPUT_PANEL | OUTPUT_DCON;
454    }
455    else if (pGeode->Output & OUTPUT_PANEL) {
456        char *pmode = xf86GetOptValString(GeodeOptions, LX_OPTION_PANEL_MODE);
457
458        if (pmode != NULL)
459            pGeode->panelMode = LXGetManualPanelMode(pmode);
460
461        if (pGeode->panelMode == NULL)
462            pGeode->panelMode = LXGetLegacyPanelMode(pScrni);
463
464        if (pGeode->panelMode == NULL)
465            pGeode->Output &= ~OUTPUT_PANEL;
466    }
467
468    /* Default to turn scaling on for panels */
469
470    if (pGeode->Output & OUTPUT_PANEL)
471        pGeode->Scale = TRUE;
472
473    xf86DrvMsg(pScrni->scrnIndex, X_INFO, "LX output options:\n");
474    xf86DrvMsg(pScrni->scrnIndex, X_INFO, " CRT: %s\n",
475               pGeode->Output & OUTPUT_CRT ? "YES" : "NO");
476
477    xf86DrvMsg(pScrni->scrnIndex, X_INFO, " PANEL: %s\n",
478               pGeode->Output & OUTPUT_PANEL ? "YES" : "NO");
479
480    xf86DrvMsg(pScrni->scrnIndex, X_INFO, " DCON: %s\n",
481               pGeode->Output & OUTPUT_DCON ? "YES" : "NO");
482
483    xf86DrvMsg(pScrni->scrnIndex, X_INFO, " VGA: %s\n",
484               pGeode->useVGA ? "YES" : "NO");
485
486    /* Set up VGA */
487
488    if (pGeode->useVGA) {
489        VESARec *pVesa;
490
491        if (!xf86LoadSubModule(pScrni, "int10"))
492            return FALSE;
493
494        pVesa = pGeode->vesa;
495
496        if ((pVesa->pInt = xf86InitInt10(pGeode->pEnt->index)) == NULL) {
497            xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
498                       "Unable to initialize 1NT10 support\n");
499            pGeode->useVGA = FALSE;
500        }
501    }
502
503    /* Read the amount of framebuffer memory */
504    /* First try to read it from the framebuffer, and if that fails,
505     * do it the legacy way
506     */
507
508    if (pGeode->FBAvail == 0) {
509        if (GeodeGetSizeFromFB(&pGeode->FBAvail)) {
510            unsigned long value;
511
512            cim_outw(0xAC1C, 0xFC53);
513            cim_outw(0xAC1C, 0x0200);
514
515            value = (unsigned long) (cim_inw(0xAC1E)) & 0xFE;
516            pGeode->FBAvail = value << 20;
517        }
518    }
519
520    pScrni->fbOffset = 0;
521
522    if (pGeode->pEnt->device->videoRam == 0)
523        pScrni->videoRam = pGeode->FBAvail / 1024;
524    else {
525        pScrni->videoRam = pGeode->pEnt->device->videoRam;
526        pGeode->FBAvail = pScrni->videoRam << 10;
527    }
528
529    /* If we have <= 16Mb of memory then compression is going
530       to hurt - so warn and disable */
531
532    if (pGeode->tryCompression && pGeode->FBAvail <= 0x1000000) {
533        xf86DrvMsg(pScrni->scrnIndex, X_INFO,
534                   "%x bytes of video memory is less then optimal\n",
535                   pGeode->FBAvail);
536        xf86DrvMsg(pScrni->scrnIndex, X_INFO,
537                   "when compression is on. Disabling compression.\n");
538        pGeode->tryCompression = FALSE;
539    }
540
541    /* Carve out some memory for the command buffer */
542
543    pGeode->CmdBfrSize = CIM_CMD_BFR_SZ;
544    pGeode->FBAvail -= CIM_CMD_BFR_SZ;
545
546    pGeode->CmdBfrOffset = pGeode->FBAvail;
547
548    /* Allocate a a CRTC config structure */
549    xf86CrtcConfigInit(pScrni, &lx_xf86crtc_config_funcs);
550
551    /* Set up the GPU CRTC */
552    LXSetupCrtc(pScrni);
553
554    xf86CrtcSetSizeRange(pScrni, 320, 200, LX_MAX_WIDTH, LX_MAX_HEIGHT);
555
556    /* Setup the output */
557    LXSetupOutput(pScrni);
558
559    if (!xf86InitialConfiguration(pScrni, FALSE)) {
560        xf86DrvMsg(pScrni->scrnIndex, X_ERROR, "No valid modes.\n");
561        return FALSE;
562    }
563
564    xf86PrintModes(pScrni);
565
566    pScrni->currentMode = pScrni->modes;
567
568    pGeode->Pitch = LXCalcPitch(pScrni);
569
570    xf86SetDpi(pScrni, 0, 0);
571
572    /* Load the modules we'll need */
573
574    if (xf86LoadSubModule(pScrni, "fb") == NULL) {
575        return FALSE;
576    }
577
578    if (!pGeode->NoAccel) {
579        if (!xf86LoadSubModule(pScrni, "exa"))
580            return FALSE;
581    }
582#ifndef XSERVER_LIBPCIACCESS
583    if (xf86RegisterResources(pGeode->pEnt->index, NULL, ResExclusive)) {
584        xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
585                   "Couldn't register the resources.\n");
586        return FALSE;
587    }
588#endif
589    return TRUE;
590}
591
592static void
593LXRestore(ScrnInfoPtr pScrni)
594{
595    GeodeRec *pGeode = GEODEPTR(pScrni);
596
597    if (pGeode->useVGA) {
598        vgaHWPtr pvgaHW = VGAHWPTR(pScrni);
599
600        vgaHWProtect(pScrni, TRUE);
601        vgaHWRestore(pScrni, &pvgaHW->SavedReg, VGA_SR_ALL);
602        vgaHWProtect(pScrni, FALSE);
603    }
604}
605
606static Bool
607LXUnmapMem(ScrnInfoPtr pScrni)
608{
609#ifndef XSERVER_LIBPCIACCESS
610    xf86UnMapVidMem(pScrni->scrnIndex, (pointer) cim_gp_ptr, LX_GP_REG_SIZE);
611    xf86UnMapVidMem(pScrni->scrnIndex, (pointer) cim_vg_ptr, LX_VG_REG_SIZE);
612    xf86UnMapVidMem(pScrni->scrnIndex, (pointer) cim_vid_ptr, LX_VID_REG_SIZE);
613    xf86UnMapVidMem(pScrni->scrnIndex, (pointer) cim_vip_ptr, LX_VIP_REG_SIZE);
614#else
615    GeodeRec *pGeode = GEODEPTR(pScrni);
616    pciVideoPtr pci = xf86GetPciInfoForEntity(pGeode->pEnt->index);
617
618    unmap_pci_mem(pScrni, pci, cim_gp_ptr, LX_GP_REG_SIZE);
619    unmap_pci_mem(pScrni, pci, cim_vg_ptr, LX_VG_REG_SIZE);
620    unmap_pci_mem(pScrni, pci, cim_vid_ptr, LX_VID_REG_SIZE);
621    unmap_pci_mem(pScrni, pci, cim_vip_ptr, LX_VIP_REG_SIZE);
622    unmap_pci_mem(pScrni, pci, cim_fb_ptr, pGeode->FBAvail + CIM_CMD_BFR_SZ);
623#endif
624
625    xf86UnMapVidMem(pScrni->scrnIndex, XpressROMPtr, 0x10000);
626
627    return TRUE;
628}
629
630/* These should be correctly accounted for rotation */
631
632void
633LXAdjustFrame(ADJUST_FRAME_ARGS_DECL)
634{
635    SCRN_INFO_PTR(arg);
636    GeodeRec *pGeode = GEODEPTR(pScrni);
637
638    unsigned long offset;
639
640    offset = (y * pGeode->Pitch);
641    offset += x * (pScrni->bitsPerPixel >> 3);
642
643    vg_set_display_offset(offset);
644}
645
646static Bool
647LXSwitchMode(SWITCH_MODE_ARGS_DECL)
648{
649    SCRN_INFO_PTR(arg);
650    GeodeRec *pGeode = GEODEPTR(pScrni);
651
652    /* Set the new mode */
653    return xf86SetSingleMode(pScrni, pMode, pGeode->rotation);
654}
655
656static void
657LXLeaveGraphics(ScrnInfoPtr pScrni)
658{
659    GeodeRec *pGeode = GEODEPTR(pScrni);
660    VG_PANNING_COORDINATES panning;
661
662    gp_wait_until_idle();
663
664    vg_set_custom_mode(&(pGeode->FBcimdisplaytiming.vgDisplayMode),
665                       pGeode->FBcimdisplaytiming.wBpp);
666
667    vg_set_compression_enable(0);
668
669    /* Restore the previous Compression state */
670    if (pGeode->FBCompressionEnable) {
671        vg_configure_compression(&(pGeode->FBCBData));
672        vg_set_compression_enable(1);
673    }
674
675    vg_set_display_pitch(pGeode->FBcimdisplaytiming.wPitch);
676    vg_set_display_offset(pGeode->FBDisplayOffset);
677
678    /* Restore Cursor */
679    vg_set_cursor_position(pGeode->FBCursor.cursor_x,
680                           pGeode->FBCursor.cursor_y, &panning);
681
682    LXRestore(pScrni);
683
684    if (pGeode->useVGA && pGeode->VGAActive) {
685        pGeode->vesa->pInt->num = 0x10;
686        pGeode->vesa->pInt->ax = 0x0 | pGeode->FBBIOSMode;
687        pGeode->vesa->pInt->bx = 0;
688        xf86ExecX86int10(pGeode->vesa->pInt);
689        vg_delay_milliseconds(3);
690    }
691
692    pScrni->vtSema = FALSE;
693}
694
695static Bool
696LXCloseScreen(CLOSE_SCREEN_ARGS_DECL)
697{
698    ScrnInfoPtr pScrni = xf86ScreenToScrn(pScrn);
699    GeodeRec *pGeode = GEODEPTR(pScrni);
700
701    if (pScrni->vtSema)
702        LXLeaveGraphics(pScrni);
703
704    if (pGeode->pExa) {
705        exaDriverFini(pScrn);
706        free(pGeode->pExa);
707        pGeode->pExa = NULL;
708    }
709
710    /* Unmap the offscreen allocations */
711    GeodeCloseOffscreen(pScrni);
712
713    LXUnmapMem(pScrni);
714
715    if (pGeode->useVGA)
716        vgaHWUnmapMem(pScrni);
717
718    pScrni->PointerMoved = pGeode->PointerMoved;
719    pScrn->CloseScreen = pGeode->CloseScreen;
720
721    if (pScrn->CloseScreen)
722        return (*pScrn->CloseScreen) (CLOSE_SCREEN_ARGS);
723
724    return TRUE;
725}
726
727static Bool
728LXEnterGraphics(ScreenPtr pScrn, ScrnInfoPtr pScrni)
729{
730    int bpp;
731    GeodeRec *pGeode = GEODEPTR(pScrni);
732
733    pGeode->VGAActive = gu3_get_vga_active();
734
735    gp_wait_until_idle();
736
737    vg_get_current_display_mode(&pGeode->FBcimdisplaytiming.vgDisplayMode,
738                                &bpp);
739
740    pGeode->FBcimdisplaytiming.wBpp = bpp;
741    pGeode->FBcimdisplaytiming.wPitch = vg_get_display_pitch();
742
743    pGeode->FBDisplayOffset = vg_get_display_offset();
744
745    if (pGeode->useVGA && pGeode->VGAActive) {
746        vgaHWPtr pvgaHW = VGAHWPTR(pScrni);
747
748        pGeode->FBBIOSMode = pvgaHW->readCrtc(pvgaHW, 0x040);
749    }
750
751    pGeode->FBCompressionEnable = vg_get_compression_enable();
752    vg_get_compression_info(&(pGeode->FBCBData));
753
754    /* Save Cursor offset */
755    vg_get_cursor_info(&pGeode->FBCursor);
756
757    /* Turn off the VGA */
758
759    if (pGeode->useVGA) {
760        unsigned short sequencer;
761        vgaHWPtr pvgaHW = VGAHWPTR(pScrni);
762
763        /* Unlock VGA registers */
764        vgaHWUnlock(pvgaHW);
765
766        /* Save the current state and setup the current mode */
767        vgaHWSave(pScrni, &VGAHWPTR(pScrni)->SavedReg, VGA_SR_ALL);
768
769        /* DISABLE VGA SEQUENCER */
770        /* This allows the VGA state machine to terminate. We must delay */
771        /* such that there are no pending MBUS requests.  */
772
773        cim_outb(DC3_SEQUENCER_INDEX, DC3_SEQUENCER_CLK_MODE);
774        sequencer = cim_inb(DC3_SEQUENCER_DATA);
775        sequencer |= DC3_CLK_MODE_SCREEN_OFF;
776        cim_outb(DC3_SEQUENCER_DATA, sequencer);
777
778        vg_delay_milliseconds(1);
779
780        /* BLANK THE VGA DISPLAY */
781        cim_outw(DC3_SEQUENCER_INDEX, DC3_SEQUENCER_RESET);
782        sequencer = cim_inb(DC3_SEQUENCER_DATA);
783        sequencer &= ~DC3_RESET_VGA_DISP_ENABLE;
784        cim_outb(DC3_SEQUENCER_DATA, sequencer);
785
786        vg_delay_milliseconds(1);
787    }
788
789    /* Clear the framebuffer */
790    memset(pGeode->FBBase, 0, pGeode->displaySize);
791
792    /* Set the modes */
793    if (!xf86SetDesiredModes(pScrni))
794        return FALSE;
795
796    pScrni->vtSema = TRUE;
797
798    return TRUE;
799}
800
801static void
802LXLoadPalette(ScrnInfoPtr pScrni,
803              int numColors, int *indizes, LOCO * colors, VisualPtr pVisual)
804{
805    int i, index, color;
806
807    for (i = 0; i < numColors; i++) {
808        index = indizes[i] & 0xFF;
809        color = (((unsigned long) (colors[index].red & 0xFF)) << 16) |
810            (((unsigned long) (colors[index].green & 0xFF)) << 8) |
811            ((unsigned long) (colors[index].blue & 0xFF));
812
813        vg_set_display_palette_entry(index, color);
814    }
815}
816
817static Bool
818LXScreenInit(SCREEN_INIT_ARGS_DECL)
819{
820    ScrnInfoPtr pScrni = xf86ScreenToScrn(pScrn);
821    GeodeRec *pGeode = GEODEPTR(pScrni);
822    int ret;
823    unsigned int dwidth;
824
825    pGeode->starting = TRUE;
826
827    /* If we are using VGA then go ahead and map the memory */
828
829    if (pGeode->useVGA) {
830
831        if (!vgaHWMapMem(pScrni))
832            return FALSE;
833
834        vgaHWGetIOBase(VGAHWPTR(pScrni));
835    }
836
837    if (!pGeode->NoAccel) {
838
839        pGeode->pExa = exaDriverAlloc();
840
841        if (pGeode->pExa) {
842
843            pGeode->pExa->memoryBase = 0;
844            pGeode->pExa->memorySize = 0;
845
846            pGeode->pExa->pixmapOffsetAlign = 32;
847            pGeode->pExa->pixmapPitchAlign = 32;
848            pGeode->pExa->flags = EXA_OFFSCREEN_PIXMAPS;
849            pGeode->pExa->maxX = LX_MAX_WIDTH - 1;
850            pGeode->pExa->maxY = LX_MAX_HEIGHT - 1;
851        }
852        else {
853            xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
854                       "Couldn't allocate the EXA structure.\n");
855            pGeode->NoAccel = TRUE;
856        }
857    }
858
859    /* Map the memory here before doing anything else */
860
861    if (!LXMapMem(pScrni))
862        return FALSE;
863
864    LXInitOffscreen(pScrni);
865
866    /* XXX FIXME - Take down any of the structures on failure? */
867    if (!LXEnterGraphics(pScrn, pScrni))
868        return FALSE;
869
870    miClearVisualTypes();
871
872    /* XXX Again - take down anything? */
873
874    if (pScrni->bitsPerPixel > 8) {
875        if (!miSetVisualTypes(pScrni->depth,
876                              TrueColorMask, pScrni->rgbBits,
877                              pScrni->defaultVisual)) {
878            return FALSE;
879        }
880    }
881    else {
882        if (!miSetVisualTypes(pScrni->depth,
883                              miGetDefaultVisualMask(pScrni->depth),
884                              pScrni->rgbBits, pScrni->defaultVisual)) {
885            return FALSE;
886        }
887    }
888
889    miSetPixmapDepths();
890
891    if (pScrni->virtualX > pScrni->displayWidth)
892        pScrni->displayWidth = pScrni->virtualX;
893
894    /* Point at the visible area to start */
895
896    /* fbScreenInit assumes that the stride is display width *
897     * bytes per pixel.  If compression is on, then our stride might
898     * be completely different, so we divide the pitch by the
899     * bytes per pixel to fake fbScreenInit into doing the right thing */
900
901    dwidth = pGeode->Pitch / ((pScrni->bitsPerPixel + 7) / 8);
902
903    ret = fbScreenInit(pScrn, pGeode->FBBase,
904                       pScrni->virtualX, pScrni->virtualY,
905                       pScrni->xDpi, pScrni->yDpi, dwidth,
906                       pScrni->bitsPerPixel);
907
908    if (!ret)
909        return FALSE;
910
911    xf86SetBlackWhitePixels(pScrn);
912
913    /* Set up the color ordering */
914    if (pScrni->bitsPerPixel > 8) {
915        VisualPtr visual = pScrn->visuals + pScrn->numVisuals;
916
917        while (--visual >= pScrn->visuals) {
918            if ((visual->class | DynamicClass) == DirectColor) {
919                visual->offsetRed = pScrni->offset.red;
920                visual->offsetGreen = pScrni->offset.green;
921                visual->offsetBlue = pScrni->offset.blue;
922                visual->redMask = pScrni->mask.red;
923                visual->greenMask = pScrni->mask.green;
924                visual->blueMask = pScrni->mask.blue;
925            }
926        }
927    }
928
929    /* Must follow the color ordering */
930    fbPictureInit(pScrn, 0, 0);
931
932    if (!pGeode->NoAccel)
933        pGeode->NoAccel = LXExaInit(pScrn) ? FALSE : TRUE;
934
935    xf86SetBackingStore(pScrn);
936
937    /* Set up the soft cursor */
938    miDCInitialize(pScrn, xf86GetPointerScreenFuncs());
939
940    /* Set up the HW cursor - must follow the soft cursor init */
941
942    if (pGeode->tryHWCursor) {
943        if (!LXCursorInit(pScrn))
944            xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
945                       "Hardware cursor initialization failed.\n");
946    }
947
948    /* Set up the color map */
949
950    if (!miCreateDefColormap(pScrn))
951        return FALSE;
952
953    if (pScrni->bitsPerPixel == 8) {
954        /* Must follow initialization of the default colormap */
955
956        if (!xf86HandleColormaps(pScrn, 256, 8,
957                                 LXLoadPalette, NULL,
958                                 CMAP_PALETTED_TRUECOLOR |
959                                 CMAP_RELOAD_ON_MODE_SWITCH)) {
960            return FALSE;
961        }
962    }
963    xf86DPMSInit(pScrn, xf86DPMSSet, 0);
964
965    LXInitVideo(pScrn);
966
967    pGeode->PointerMoved = pScrni->PointerMoved;
968    pScrni->PointerMoved = GeodePointerMoved;
969
970    pGeode->CloseScreen = pScrn->CloseScreen;
971    pScrn->CloseScreen = LXCloseScreen;
972    pScrn->SaveScreen = LXSaveScreen;
973
974    if (!xf86CrtcScreenInit(pScrn)) {
975        xf86DrvMsg(pScrni->scrnIndex, X_ERROR, "CRTCScreenInit failed.\n");
976        return FALSE;
977    }
978
979    if (serverGeneration == 1)
980        xf86ShowUnusedOptions(pScrni->scrnIndex, pScrni->options);
981
982    pGeode->starting = FALSE;
983
984    return TRUE;
985}
986
987static int
988LXValidMode(VALID_MODE_ARGS_DECL)
989{
990    return MODE_OK;
991}
992
993static Bool
994LXEnterVT(VT_FUNC_ARGS_DECL)
995{
996    SCRN_INFO_PTR(arg);
997    return LXEnterGraphics(NULL, pScrni);
998}
999
1000static void
1001LXLeaveVT(VT_FUNC_ARGS_DECL)
1002{
1003    SCRN_INFO_PTR(arg);
1004    GeodeRec *pGeode = GEODEPTR(pScrni);
1005
1006    pGeode->PrevDisplayOffset = vg_get_display_offset();
1007    LXLeaveGraphics(pScrni);
1008}
1009
1010void
1011LXSetupChipsetFPtr(ScrnInfoPtr pScrn)
1012{
1013    pScrn->PreInit = LXPreInit;
1014    pScrn->ScreenInit = LXScreenInit;
1015    pScrn->SwitchMode = LXSwitchMode;
1016    pScrn->AdjustFrame = LXAdjustFrame;
1017    pScrn->EnterVT = LXEnterVT;
1018    pScrn->LeaveVT = LXLeaveVT;
1019    pScrn->FreeScreen = GeodeFreeScreen;
1020    pScrn->ValidMode = LXValidMode;
1021}
1022