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