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