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