diff options
Diffstat (limited to 'src/lx_driver.c')
-rw-r--r-- | src/lx_driver.c | 1528 |
1 files changed, 1528 insertions, 0 deletions
diff --git a/src/lx_driver.c b/src/lx_driver.c new file mode 100644 index 0000000..aa8145e --- /dev/null +++ b/src/lx_driver.c @@ -0,0 +1,1528 @@ +/* Copyright (c) 2003-2007 Advanced Micro Devices, Inc. + * + * Portioned modeled from xf86-video-intel/src/i830_driver.c + * Copyright 2001 VA Linux Systems Inc., Fremont, California. + * Copyright \ufffd 2002 by David Dawes + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Neither the name of the Advanced Micro Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + */ + +/* TODO: + TV out support + Detect panels better + Better VGA support + GX: cursor position needs to be correctly set + use CB data wrapper to save a variable + consolidate the saved timings + implement panning +*/ + +/* The effort to make things common: + define CmdBfrSize in the GX + add the output flag to GX +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <string.h> + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86Resources.h" +#include "xf86cmap.h" +#include "compiler.h" +#include "mipointer.h" +#include <shadow.h> /* setupShadow() */ +#include <X11/extensions/randr.h> +#include "fb.h" +#include "miscstruct.h" +#include "micmap.h" +#include "vbe.h" +#include "fb.h" +#include "randrstr.h" +#include "cim_defs.h" +#include "cim_regs.h" +#include "geode.h" + +/* Bring in VGA functions */ +#include "lx_vga.c" + +/* Chipset types */ + +#define LX_MIN_PITCH 1024 +#define LX_MAX_PITCH 8192 +#define LX_MAX_WIDTH 1940 +#define LX_MIN_HEIGHT 400 +#define LX_MAX_HEIGHT 1600 +#define LX_CB_PITCH 544 +#define LX_CB_SIZE 544 + +#define LX_GP_REG_SIZE 0x4000 +#define LX_VG_REG_SIZE 0x4000 +#define LX_VID_REG_SIZE 0x4000 +#define LX_VIP_REG_SIZE 0x4000 + +extern OptionInfoRec LX_GeodeOptions[]; + +extern const char *amdVgahwSymbols[]; +extern const char *amdVbeSymbols[]; +extern const char *amdInt10Symbols[]; +extern const char *amdFbSymbols[]; +extern const char *amdExaSymbols[]; +extern const char *amdRamdacSymbols[]; + +unsigned char *XpressROMPtr; + +/* Reference: Video Graphics Suite Specification: + * VG Config Register (0x00) page 16 + * VG FP Register (0x02) page 18 + */ + +#define LX_READ_VG(reg) \ + (outw(0xAC1C,0xFC53), outw(0xAC1C,0x0200|(reg)), inw(0xAC1E)) + +static inline void +lx_enable_dac_power(ScrnInfoPtr pScrni, int option) +{ + GeodeRec *pGeode = GEODEPTR(pScrni); + + df_set_crt_enable(DF_CRT_ENABLE); + + /* Turn off the DAC if we don't need the CRT */ + + if (option && (!(pGeode->Output & OUTPUT_CRT))) { + unsigned int misc = READ_VID32(DF_VID_MISC); + misc |= DF_DAC_POWER_DOWN; + WRITE_VID32(DF_VID_MISC, misc); + } + + if (pGeode->Output & OUTPUT_PANEL) + df_set_panel_enable(1); +} + +static inline void +lx_disable_dac_power(ScrnInfoPtr pScrni, int option) +{ + GeodeRec *pGeode = GEODEPTR(pScrni); + + if (pGeode->Output & OUTPUT_PANEL) + df_set_panel_enable(0); + + if (pGeode->Output & OUTPUT_CRT) { + + /* Wait for the panel to finish its procedure */ + + if (pGeode->Output & OUTPUT_PANEL) + while ((READ_VID32(DF_POWER_MANAGEMENT) & 2) == 0); + df_set_crt_enable(option); + } +} + +static int +lx_get_panel(int *xres, int *yres) +{ + static struct { + int xres, yres; + } fpres[] = { + { 320, 240 }, { 640, 480 }, { 800, 600 }, { 1024, 768 }, + { 1152, 864 }, { 1280, 1024 }, { 1600, 1200 } }; + + unsigned short reg = LX_READ_VG(0x00); + unsigned char ret = (reg >> 8) & 0x07; + + if ((ret == 1 || ret == 5)) { + + reg = LX_READ_VG(0x02); + ret = (reg >> 3) & 0x07; + + /* 7 is a "reserved" value - if we get it, we can only assume that + a panel doesn't exist (or it hasn't been configured in the BIOS) + */ + + if (ret < 7) { + *xres = fpres[ret].xres; + *yres = fpres[ret].yres; + + return TRUE; + } + } + + return FALSE; +} + +static int +lx_set_custom_mode(GeodeRec *pGeode, DisplayModePtr pMode, int bpp) +{ + VG_DISPLAY_MODE mode; + int hsync, vsync; + + memset(&mode, 0, sizeof(mode)); + + /* Cimarron purposely swaps the sync when panels are enabled -this is + * presumably to allow for "default" panels which are normally active + * low, so we need to swizzle the flags + */ + + hsync = (pMode->Flags & V_NHSYNC) ? 1 : 0; + vsync = (pMode->Flags & V_NVSYNC) ? 1 : 0; + + if (pGeode->Output & OUTPUT_PANEL) { + hsync = !vsync; + vsync = !vsync; + } + + mode.flags |= (hsync) ? VG_MODEFLAG_NEG_HSYNC : 0; + mode.flags |= (vsync) ? VG_MODEFLAG_NEG_VSYNC : 0; + + mode.flags |= pGeode->Output & OUTPUT_CRT ? VG_MODEFLAG_CRT_AND_FP : 0; + + if (pGeode->Output & OUTPUT_PANEL) { + mode.panel_width = mode.mode_width = pGeode->PanelX; + mode.panel_height = mode.mode_height = pGeode->PanelY; + + mode.flags |= VG_MODEFLAG_PANELOUT; + mode.flags |= pGeode->Output & OUTPUT_CRT ? VG_MODEFLAG_CRT_AND_FP : 0; + } + else { + mode.mode_width = pMode->CrtcHDisplay; + mode.mode_height = pMode->CrtcVDisplay; + } + + mode.src_width = pMode->CrtcHDisplay; + mode.src_height = pMode->CrtcVDisplay; + + mode.hactive = pMode->CrtcHDisplay; + mode.hblankstart = pMode->CrtcHBlankStart; + mode.hsyncstart = pMode->CrtcHSyncStart; + mode.hsyncend = pMode->CrtcHSyncEnd; + mode.hblankend = pMode->CrtcHBlankEnd; + mode.htotal = pMode->CrtcHTotal; + + mode.vactive = pMode->CrtcVDisplay; + mode.vblankstart = pMode->CrtcVBlankStart; + mode.vsyncstart = pMode->CrtcVSyncStart; + mode.vsyncend = pMode->CrtcVSyncEnd; + mode.vblankend = pMode->CrtcVBlankEnd; + mode.vtotal = pMode->CrtcVTotal; + + mode.vactive_even = pMode->CrtcVDisplay; + mode.vblankstart_even = pMode->CrtcVBlankStart; + mode.vsyncstart_even = pMode->CrtcVSyncStart; + mode.vsyncend_even = pMode->CrtcVSyncEnd; + mode.vblankend_even = pMode->CrtcVBlankEnd; + mode.vtotal_even = pMode->CrtcVTotal; + + mode.frequency = (int)((pMode->SynthClock / 1000.0) * 0x10000); + + return vg_set_custom_mode(&mode, bpp); +} + +static Bool +LXAllocateMemory(ScreenPtr pScrn, ScrnInfoPtr pScrni, int rotate) +{ + GeodePtr pGeode = GEODEPTR(pScrni); + + unsigned int fboffset, fbavail; + unsigned int size; + unsigned int bytpp = (pScrni->bitsPerPixel + 7) / 8; + Bool ret = TRUE; + + if (pGeode->tryCompression) + pGeode->displayPitch = + GeodeCalculatePitchBytes(pScrni->virtualX, pScrni->bitsPerPixel); + else + pGeode->displayPitch = + ((pScrni->virtualX + 3) & ~3) * (pScrni->bitsPerPixel >> 3); + + pGeode->displayWidth = pGeode->displayPitch / bytpp; + + + /* Sets pGeode->Pitch and pScrni->displayWidth based on the rotate settings */ + LXSetRotatePitch(pScrni); + + fbavail = pGeode->FBAvail - GP3_SCRATCH_BUFFER_SIZE; + + pGeode->displayOffset = fboffset = 0; + pGeode->displaySize = pScrni->virtualY * pGeode->displayPitch; + + fbavail -= pGeode->displaySize; + fboffset += pGeode->displaySize; + + if (pGeode->tryCompression) { + size = pScrni->virtualY * LX_CB_PITCH; + + if (size <= fbavail) { + pGeode->CBData.compression_offset = fboffset; + pGeode->CBData.size = LX_CB_PITCH; + pGeode->CBData.pitch = LX_CB_PITCH; + fboffset += size; + fbavail -= size; + + pGeode->Compression = TRUE; + } else { + xf86DrvMsg(pScrni->scrnIndex, X_ERROR, + "Not enough memory for compression\n"); + pGeode->Compression = FALSE; + } + } + + if (pGeode->tryHWCursor) { + pGeode->CursorSize = 1024; + + if (pGeode->CursorSize <= fbavail) { + pGeode->CursorStartOffset = fboffset; + fboffset += pGeode->CursorSize; + fbavail -= pGeode->CursorSize; + pGeode->HWCursor = TRUE; + } else { + xf86DrvMsg(pScrni->scrnIndex, X_ERROR, + "Not enough memory for the hardware cursor\n"); + pGeode->HWCursor = FALSE; + } + } + + /* Try to set up some EXA scratch memory for blending */ + + pGeode->exaBfrOffset = 0; + + if (!pGeode->NoAccel) { + if (pGeode->exaBfrSz > 0 && pGeode->exaBfrSz <= fbavail) { + pGeode->exaBfrOffset = fboffset; + fboffset += pGeode->exaBfrSz; + fbavail -= pGeode->exaBfrSz; + } + } + + /* Adjust the available EXA offscreen space to account for the buffer */ + + if (!pGeode->NoAccel && pGeode->pExa) { + pGeode->pExa->offScreenBase = fboffset; + pGeode->pExa->memorySize = fboffset + fbavail; + } + + return ret; +} + +static Bool +LXSaveScreen(ScreenPtr pScrn, int mode) +{ + ScrnInfoPtr pScrni = xf86Screens[pScrn->myNum]; + GeodePtr pGeode = GEODEPTR(pScrni); + + if (pGeode->useVGA && !pScrni->vtSema) + return vgaHWSaveScreen(pScrn, mode); + + return TRUE; +} + +/* This is an overly complex MSR read mechanism */ + +/* From Cimarron - the VSAII read/write methods - we use these as fallback */ + +#define LX_MSR_READ(adr,lo,hi) \ + __asm__ __volatile__( \ + " mov $0x0AC1C, %%edx\n" \ + " mov $0xFC530007, %%eax\n" \ + " out %%eax,%%dx\n" \ + " add $2,%%dl\n" \ + " in %%dx, %%ax" \ + : "=a" (lo), "=d" (hi) \ + : "c" (adr)) + +#define LX_MSR_WRITE(adr,low,high) \ + { int d0, d1, d2, d3, d4; \ + __asm__ __volatile__( \ + " push %%ebx\n" \ + " mov $0x0AC1C, %%edx\n" \ + " mov $0xFC530007, %%eax\n" \ + " out %%eax,%%dx\n" \ + " add $2,%%dl\n" \ + " mov %6, %%ebx\n" \ + " mov %7, %0\n" \ + " mov %5, %3\n" \ + " xor %2, %2\n" \ + " xor %1, %1\n" \ + " out %%ax, %%dx\n" \ + " pop %%ebx\n" \ + : "=a"(d0),"=&D"(d1),"=&S"(d2), \ + "=c"(d3),"=d"(d4) \ + : "1"(adr),"2"(high),"3"(low)); \ + } + +static void +LXReadMSR(unsigned long addr, unsigned long *lo, unsigned long *hi) +{ + if (GeodeReadMSR(addr, lo, hi) == -1) { + unsigned int l, h; + + LX_MSR_READ(addr, l, h); + *lo = l; + *hi = h; + } +} + +static void +LXWriteMSR(unsigned long addr, unsigned long lo, unsigned long hi) +{ + if (GeodeWriteMSR(addr, lo, hi) == -1) + LX_MSR_WRITE(addr, lo, hi); +} + +#ifdef XSERVER_LIBPCIACCESS +static inline void * map_pci_mem(ScrnInfoPtr pScrni, int vram, + struct pci_device *dev, + int bar, int size) +{ + void *ptr; + void** result = (void**)&ptr; + int map_size = size ? size : dev->regions[bar].size; + + int err = pci_device_map_range(dev, + dev->regions[bar].base_addr, + map_size, + PCI_DEV_MAP_FLAG_WRITABLE | + (vram ? PCI_DEV_MAP_FLAG_WRITE_COMBINE : 0), + result); + + if (err) + return NULL; + return ptr; +} +#endif + +static Bool +LXMapMem(ScrnInfoPtr pScrni) +{ + GeodeRec *pGeode = GEODEPTR(pScrni); + int index = pScrni->scrnIndex; + unsigned long cmd_bfr_phys; + + pciVideoPtr pci = xf86GetPciInfoForEntity(pGeode->pEnt->index); + +#ifndef XSERVER_LIBPCIACCESS + PCITAG tag; + + tag = pciTag(pci->bus, pci->device, pci->func); + + cim_gp_ptr = (unsigned char *)xf86MapPciMem(index, VIDMEM_MMIO, + tag, pci->memBase[1], LX_GP_REG_SIZE); + + cim_vg_ptr = (unsigned char *)xf86MapPciMem(index, VIDMEM_MMIO, + tag, pci->memBase[2], LX_VG_REG_SIZE); + + cim_vid_ptr = (unsigned char *)xf86MapPciMem(index, VIDMEM_MMIO, + tag, pci->memBase[3], LX_VID_REG_SIZE); + + cim_vip_ptr = (unsigned char *)xf86MapPciMem(index, VIDMEM_MMIO, + tag, pci->memBase[4], LX_VIP_REG_SIZE); + + cim_fb_ptr = (unsigned char *)xf86MapPciMem(index, VIDMEM_FRAMEBUFFER, + tag, pci->memBase[0], pGeode->FBAvail + CIM_CMD_BFR_SZ); +#else + cim_gp_ptr = map_pci_mem(pScrni, 0, pci, 1, LX_GP_REG_SIZE); + cim_vg_ptr = map_pci_mem(pScrni, 0, pci, 2, LX_VG_REG_SIZE); + cim_vid_ptr = map_pci_mem(pScrni, 0, pci, 3, LX_VID_REG_SIZE); + cim_vip_ptr = map_pci_mem(pScrni, 0, pci, 4, LX_VIP_REG_SIZE); + cim_fb_ptr = map_pci_mem(pScrni, 1, pci, 0, pGeode->FBAvail + CIM_CMD_BFR_SZ); +#endif + + if (pScrni->memPhysBase == 0) + pScrni->memPhysBase = PCI_REGION_BASE(pci, 0, REGION_MEM); + + + cmd_bfr_phys = PCI_REGION_BASE(pci, 0, REGION_MEM) + pGeode->CmdBfrOffset; + cim_cmd_base_ptr = cim_fb_ptr + pGeode->CmdBfrOffset; + + if (!cim_gp_ptr || !cim_vg_ptr || !cim_vid_ptr || !cim_fb_ptr || + !cim_vip_ptr) + return FALSE; + + gp_set_frame_buffer_base(PCI_REGION_BASE(pci, 0, REGION_MEM), pGeode->FBAvail); + gp_set_command_buffer_base(cmd_bfr_phys, 0, pGeode->CmdBfrSize); + + XpressROMPtr = xf86MapVidMem(index, VIDMEM_FRAMEBUFFER, 0xF0000, 0x10000); + + pGeode->FBBase = cim_fb_ptr; + + if (!pGeode->NoAccel) + pGeode->pExa->memoryBase = pGeode->FBBase; + + xf86DrvMsg(index, X_INFO, "Geode LX video memory %x bytes at %p\n", + pGeode->FBAvail, pGeode->FBBase); + + return TRUE; +} + +/* Check to see if VGA exists - we map the space and look for a + signature - if it doesn't match exactly, then we assume no VGA. +*/ + +static Bool +LXCheckVGA(ScrnInfoPtr pScrni) { + + unsigned char *ptr; + const char *vgasig = "IBM VGA Compatible"; + int ret; + + ptr = xf86MapVidMem(pScrni->scrnIndex, VIDMEM_FRAMEBUFFER, 0xC001E, strlen(vgasig)); + + if (ptr == NULL) + return FALSE; + + ret = memcmp(ptr, vgasig, strlen(vgasig)); + xf86UnMapVidMem(pScrni->scrnIndex, (pointer) ptr, strlen(vgasig)); + + return ret ? FALSE : TRUE; +} + +static Bool +LXPreInit(ScrnInfoPtr pScrni, int flags) +{ + GeodePtr pGeode; + ClockRangePtr GeodeClockRange; + EntityInfoPtr pEnt; + OptionInfoRec *GeodeOptions = &LX_GeodeOptions[0]; + rgb defaultWeight = { 0, 0, 0 }; + int modecnt; + char *s, *panelgeo = NULL; + Bool useVGA; + + if (pScrni->numEntities != 1) + return FALSE; + + pEnt = xf86GetEntityInfo(pScrni->entityList[0]); + + if (pEnt->resources) + return FALSE; + + useVGA = LXCheckVGA(pScrni); + + if (flags & PROBE_DETECT) { + if (useVGA) + GeodeProbeDDC(pScrni, pEnt->index); + + return TRUE; + } + + pGeode = pScrni->driverPrivate = xnfcalloc(sizeof(GeodeRec), 1); + + if (pGeode == NULL) + return FALSE; + + pGeode->useVGA = useVGA; + pGeode->VGAActive = FALSE; + pGeode->pEnt = pEnt; + + if (pGeode->useVGA) { + if (!xf86LoadSubModule(pScrni, "vgahw") || + !vgaHWGetHWRec(pScrni)) + pGeode->useVGA = FALSE; + + pGeode->vesa = xcalloc(sizeof(VESARec), 1); + } + + cim_rdmsr = LXReadMSR; + cim_wrmsr = LXWriteMSR; + + /* Set up the Cimarron MSR tables */ + msr_init_table(); + + /* By default, we support panel and CRT - the config file should + * disable the ones we don't want + */ + + pGeode->Output = OUTPUT_PANEL | OUTPUT_CRT; + + /* Fill in the monitor information */ + pScrni->monitor = pScrni->confScreen->monitor; + + if (!xf86SetDepthBpp(pScrni, 16, 16, 16, Support24bppFb | Support32bppFb)) + return FALSE; + + switch (pScrni->depth) { + case 8: + pScrni->rgbBits = 8; + case 16: + case 24: + case 32: + break; + default: + xf86DrvMsg(pScrni->scrnIndex, X_ERROR, + "The driver does not support %d as a depth.\n", pScrni->depth); + return FALSE; + } + + xf86PrintDepthBpp(pScrni); + + if (!xf86SetWeight(pScrni, defaultWeight, defaultWeight)) + return FALSE; + + if (!xf86SetDefaultVisual(pScrni, -1)) + return FALSE; + + /* + * If the driver can do gamma correction, it should call xf86SetGamma() + * here. + */ + { + Gamma zeros = { 0.0, 0.0, 0.0 }; + + if (!xf86SetGamma(pScrni, zeros)) { + return FALSE; + } + } + + pScrni->progClock = TRUE; + xf86CollectOptions(pScrni, NULL); + xf86ProcessOptions(pScrni->scrnIndex, pScrni->options, GeodeOptions); + + /* Set up our various options that may get reversed as we go on */ + + pGeode->tryHWCursor = TRUE; + pGeode->tryCompression = TRUE; + + /* Protect against old versions of EXA */ + +#if (EXA_VERSION_MAJOR < 2) + pGeode->NoAccel = TRUE; + xf86DrvMsg(pScrni->scrnIndex, X_ERROR, + "*** This driver was compiled with EXA version %d\n"); + xf86DrvMsg(pScrni->scrnIndex, X_ERROR, + "*** we need version 2 or greater\n"); + xf86DrvMsg(pScrni->scrnIndex, X_ERROR, + "*** All accelerations are being turned off.\n"); +#else + pGeode->NoAccel = FALSE; +#endif + + pGeode->exaBfrSz = DEFAULT_EXA_SCRATCH_BFRSZ; + + xf86GetOptValBool(GeodeOptions, LX_OPTION_HW_CURSOR, + &pGeode->tryHWCursor); + + if (!xf86GetOptValInteger(GeodeOptions, LX_OPTION_FBSIZE, + &(pGeode->FBAvail))) + pGeode->FBAvail = 0; + + /* For compatability - allow SWCursor too */ + + if (xf86ReturnOptValBool(GeodeOptions, LX_OPTION_SW_CURSOR, FALSE)) + pGeode->tryHWCursor = FALSE; + + if (xf86ReturnOptValBool(GeodeOptions, LX_OPTION_NOCOMPRESSION, FALSE)) + pGeode->tryCompression = FALSE; + + if (xf86ReturnOptValBool(GeodeOptions, LX_OPTION_NOACCEL, FALSE)) + pGeode->NoAccel = TRUE; + + pGeode->rotation = RR_Rotate_0; + + if ((s = xf86GetOptValString(GeodeOptions, LX_OPTION_ROTATE))) { + + if (!xf86NameCmp(s, "LEFT")) + pGeode->rotation = RR_Rotate_90; + else if (!xf86NameCmp(s, "INVERT")) + pGeode->rotation = RR_Rotate_180; + else if (!xf86NameCmp(s, "CCW")) + pGeode->rotation = RR_Rotate_270; + else + xf86DrvMsg(pScrni->scrnIndex, X_ERROR, + "Invalid rotation %s.\n", s); + } + + xf86GetOptValInteger(GeodeOptions, LX_OPTION_EXA_SCRATCH_BFRSZ, + &(pGeode->exaBfrSz)); + + if (pGeode->exaBfrSz <= 0) + pGeode->exaBfrSz = 0; + + if (pGeode->Output & OUTPUT_PANEL) { + if (xf86ReturnOptValBool(GeodeOptions, LX_OPTION_NOPANEL, FALSE)) + pGeode->Output &= ~OUTPUT_PANEL; + } + + panelgeo = xf86GetOptValString(GeodeOptions, LX_OPTION_PANEL_GEOMETRY); + + /* Get the panel information - if it is specified on the command line, + * then go with that - otherwise try to determine it by probing the + * BIOS - the BIOS may tell us that the panel doesn't exist, so the + * value of the output bitmask may change + */ + + if (dcon_init(pScrni)) { + pGeode->Output = OUTPUT_PANEL; + } else if (pGeode->Output & OUTPUT_PANEL) { + if (panelgeo != NULL) + GeodeGetFPGeometry(panelgeo, &pGeode->PanelX, &pGeode->PanelY); + else { + Bool ret = lx_get_panel(&pGeode->PanelX, &pGeode->PanelY); + if (ret == FALSE) + pGeode->Output &= ~OUTPUT_PANEL; + } + } + + xf86DrvMsg(pScrni->scrnIndex, X_INFO, "LX output options:\n"); + xf86DrvMsg(pScrni->scrnIndex, X_INFO, " CRT: %s\n", + pGeode->Output & OUTPUT_CRT ? "YES" : "NO"); + + xf86DrvMsg(pScrni->scrnIndex, X_INFO, " PANEL: %s\n", + pGeode->Output & OUTPUT_PANEL ? "YES" : "NO"); + + xf86DrvMsg(pScrni->scrnIndex, X_INFO, " VGA: %s\n", + pGeode->useVGA ? "YES" : "NO"); + + /* Set up VGA */ + if (pGeode->useVGA) { + xf86LoaderReqSymLists(amdVgahwSymbols, NULL); + + VESARec *pVesa; + + if (!xf86LoadSubModule(pScrni, "int10")) + return FALSE; + + xf86LoaderReqSymLists(amdInt10Symbols, NULL); + + pVesa = pGeode->vesa; + + if ((pVesa->pInt = xf86InitInt10(pGeode->pEnt->index)) == NULL) { + xf86DrvMsg(pScrni->scrnIndex, X_ERROR, + "Unable to initialize 1NT10 support\n"); + pGeode->useVGA = FALSE; + } + } + + /* Read the amount of framebuffer memory */ + /* First try to read it from the framebuffer, and if that fails, + * do it the legacy way + */ + + if (pGeode->FBAvail == 0) { + if (GeodeGetSizeFromFB(&pGeode->FBAvail)) { + unsigned long value; + cim_outw(0xAC1C, 0xFC53); + cim_outw(0xAC1C, 0x0200); + + value = (unsigned long)(cim_inw(0xAC1E)) & 0xFE; + pGeode->FBAvail = value << 20; + } + } + + pScrni->fbOffset = 0; + + if (pGeode->pEnt->device->videoRam == 0) + pScrni->videoRam = pGeode->FBAvail / 1024; + else { + pScrni->videoRam = pGeode->pEnt->device->videoRam; + pGeode->FBAvail = pScrni->videoRam << 10; + } + + /* Carve out some memory for the command buffer */ + + pGeode->CmdBfrSize = CIM_CMD_BFR_SZ; + pGeode->FBAvail -= CIM_CMD_BFR_SZ; + + pGeode->CmdBfrOffset = pGeode->FBAvail; + + pGeode->maxWidth = LX_MAX_WIDTH; + pGeode->maxHeight = LX_MAX_HEIGHT; + + GeodeClockRange = (ClockRangePtr) xnfcalloc(sizeof(ClockRange), 1); + GeodeClockRange->next = NULL; + GeodeClockRange->minClock = 25175; + GeodeClockRange->maxClock = 229500; + GeodeClockRange->clockIndex = -1; + GeodeClockRange->interlaceAllowed = TRUE; + GeodeClockRange->doubleScanAllowed = FALSE; + + if (pGeode->useVGA && (pGeode->Output & OUTPUT_CRT)) + pScrni->monitor->DDC = GeodeDoDDC(pScrni, pGeode->pEnt->index); + else + pScrni->monitor->DDC = NULL; + + /* I'm still not 100% sure this uses the right values */ + + modecnt = xf86ValidateModes(pScrni, + pScrni->monitor->Modes, + pScrni->display->modes, + GeodeClockRange, + NULL, LX_MIN_PITCH, LX_MAX_PITCH, + 32, LX_MIN_HEIGHT, LX_MAX_HEIGHT, + pScrni->display->virtualX, + pScrni->display->virtualY, pGeode->FBAvail, LOOKUP_BEST_REFRESH); + + if (modecnt <= 0) { + xf86DrvMsg(pScrni->scrnIndex, X_ERROR, "No valid modes were found\n"); + return FALSE; + } + + xf86PruneDriverModes(pScrni); + + if (pScrni->modes == NULL) { + xf86DrvMsg(pScrni->scrnIndex, X_ERROR, "No valid modes were found\n"); + return FALSE; + } + + xf86SetCrtcForModes(pScrni, 0); + pScrni->currentMode = pScrni->modes; + + xf86PrintModes(pScrni); + xf86SetDpi(pScrni, 0, 0); + + /* Load the modules we'll need */ + + if (xf86LoadSubModule(pScrni, "fb") == NULL) { + return FALSE; + } + + xf86LoaderReqSymLists(amdFbSymbols, NULL); + + if (!pGeode->NoAccel) { + if (!xf86LoadSubModule(pScrni, "exa")) + return FALSE; + + xf86LoaderReqSymLists(&amdExaSymbols[0], NULL); + } + + if (pGeode->tryHWCursor == TRUE) { + if (!xf86LoadSubModule(pScrni, "ramdac")) { + return FALSE; + } + + xf86LoaderReqSymLists(amdRamdacSymbols, NULL); + } + + if (xf86RegisterResources(pGeode->pEnt->index, NULL, ResExclusive)) { + xf86DrvMsg(pScrni->scrnIndex, X_ERROR, + "Couldn't register the resources.\n"); + return FALSE; + } + + return TRUE; +} + +static void +LXRestore(ScrnInfoPtr pScrni) +{ + GeodeRec *pGeode = GEODEPTR(pScrni); + + if (pGeode->useVGA) { + vgaHWPtr pvgaHW = VGAHWPTR(pScrni); + + vgaHWProtect(pScrni, TRUE); + vgaHWRestore(pScrni, &pvgaHW->SavedReg, VGA_SR_ALL); + vgaHWProtect(pScrni, FALSE); + } +} + +static Bool +LXUnmapMem(ScrnInfoPtr pScrni) +{ + GeodeRec *pGeode = GEODEPTR(pScrni); + + xf86UnMapVidMem(pScrni->scrnIndex, (pointer) cim_gp_ptr, LX_GP_REG_SIZE); + xf86UnMapVidMem(pScrni->scrnIndex, (pointer) cim_vg_ptr, LX_VG_REG_SIZE); + xf86UnMapVidMem(pScrni->scrnIndex, (pointer) cim_vid_ptr, LX_VID_REG_SIZE); + xf86UnMapVidMem(pScrni->scrnIndex, (pointer) cim_vip_ptr, LX_VIP_REG_SIZE); + + xf86UnMapVidMem(pScrni->scrnIndex, cim_fb_ptr, pGeode->FBAvail); + xf86UnMapVidMem(pScrni->scrnIndex, XpressROMPtr, 0x10000); + + return TRUE; +} + +/* These should be correctly accounted for rotation */ + +static void +LXAdjustFrame(int scrnIndex, int x, int y, int flags) +{ + ScrnInfoPtr pScrni = xf86Screens[scrnIndex]; + GeodeRec *pGeode = GEODEPTR(pScrni); + + unsigned long offset; + + /* XXX: Is pitch correct here? */ + + offset = pGeode->FBOffset + (y * pGeode->Pitch); + offset += x * (pScrni->bitsPerPixel >> 3); + + vg_set_display_offset(offset); +} + +static Bool +LXSetVideoMode(ScrnInfoPtr pScrni, DisplayModePtr pMode) +{ + GeodeRec *pGeode = GEODEPTR(pScrni); + DF_VIDEO_SOURCE_PARAMS vs_odd, vs_even; + int flags = 0; + int video_enable; + unsigned long video_flags; + + df_get_video_enable(&video_enable, &video_flags); + + if (video_enable != 0) + df_set_video_enable(0, 0); + + df_get_video_source_configuration(&vs_odd, &vs_even); + lx_disable_dac_power(pScrni, DF_CRT_DISABLE); + vg_set_compression_enable(0); + + /* If the mode is a default one, then set the mode with the Cimarron + * tables */ + + if ((pMode->type & M_T_BUILTIN) || (pMode->type & M_T_DEFAULT)) { + if (pMode->Flags & V_NHSYNC) + flags |= VG_MODEFLAG_NEG_HSYNC; + if (pMode->Flags & V_NVSYNC) + flags |= VG_MODEFLAG_NEG_VSYNC; + + if (pGeode->Output & OUTPUT_PANEL) { + int activex = pGeode->PanelX; + int activey = pGeode->PanelY; + + flags = pGeode->Output & OUTPUT_CRT ? VG_MODEFLAG_CRT_AND_FP : 0; + + if (pMode->CrtcHDisplay > 1024 && + pMode->CrtcHDisplay != pGeode->PanelX) { + ErrorF("The source is greater then 1024 - scaling is disabled.\n"); + activex = pMode->CrtcHDisplay; + activey = pMode->CrtcVDisplay; + + vg_set_border_color(0); + } + + vg_set_panel_mode(pMode->CrtcHDisplay, pMode->CrtcVDisplay, + activex, activey, activex, activey, + pScrni->bitsPerPixel, flags); + } + else { + vg_set_display_mode(pMode->CrtcHDisplay, pMode->CrtcVDisplay, + pMode->CrtcHDisplay, pMode->CrtcVDisplay, + pScrni->bitsPerPixel, GeodeGetRefreshRate(pMode), + 0); + } + } + else { + /* For anything other then a default mode - use the passed in + * timings */ + + lx_set_custom_mode(pGeode, pMode, pScrni->bitsPerPixel); + } + + if (pGeode->Output & OUTPUT_PANEL) + df_set_output_path((pGeode->Output & OUTPUT_CRT) ? DF_DISPLAY_CRT_FP : DF_DISPLAY_FP); + else + df_set_output_path(DF_DISPLAY_CRT); + + vg_set_display_pitch(pGeode->Pitch); + gp_set_bpp(pScrni->bitsPerPixel); + + vg_set_display_offset(0); + vg_wait_vertical_blank(); + + if (pGeode->Compression) { + vg_configure_compression(&(pGeode->CBData)); + vg_set_compression_enable(1); + } + + if (pGeode->HWCursor && !(pMode->Flags & V_DBLSCAN)) { + VG_PANNING_COORDINATES panning; + + LXLoadCursorImage(pScrni, NULL); + vg_set_cursor_position(0, 0, &panning); + LXShowCursor(pScrni); + } else { + vg_set_cursor_enable(0); + pGeode->HWCursor = FALSE; + } + + LXAdjustFrame(pScrni->scrnIndex, pScrni->frameX0, pScrni->frameY0, 0); + + df_configure_video_source(&vs_odd, &vs_even); + + if (video_enable != 0) + df_set_video_enable(video_enable, video_flags); + + lx_enable_dac_power(pScrni, 1); + + return TRUE; +} + +static Bool +LXSwitchMode(int index, DisplayModePtr pMode, int flags) +{ + ScrnInfoPtr pScrni = xf86Screens[index]; + GeodeRec *pGeode = GEODEPTR(pScrni); + int ret = TRUE; + int rotate; + + /* Syn the engine and shutdown the DAC momentarily */ + gp_wait_until_idle(); + + /* Set up the memory for the new mode */ + rotate = LXGetRotation(pScrni->pScreen); + ret = LXAllocateMemory(pScrni->pScreen, pScrni, rotate); + + if (ret) { + if (pGeode->curMode != pMode) + ret = LXSetVideoMode(pScrni, pMode); + } + + if (ret) + ret = LXRotate(pScrni, pMode); + + /* Go back the way it was */ + + if (ret == FALSE) { + if (!LXSetVideoMode(pScrni, pGeode->curMode)) + xf86DrvMsg(pScrni->scrnIndex, X_ERROR, + "Could not restore the previous mode\n"); + } else + pGeode->curMode = pMode; + + return ret; +} + +static void +LXLeaveGraphics(ScrnInfoPtr pScrni) +{ + GeodeRec *pGeode = GEODEPTR(pScrni); + VG_PANNING_COORDINATES panning; + + gp_wait_until_idle(); + + lx_disable_dac_power(pScrni, DF_CRT_DISABLE); + + vg_set_custom_mode(&(pGeode->FBcimdisplaytiming.vgDisplayMode), + pGeode->FBcimdisplaytiming.wBpp); + + vg_set_compression_enable(0); + + /* Restore the previous Compression state */ + if (pGeode->FBCompressionEnable) { + vg_configure_compression(&(pGeode->FBCBData)); + vg_set_compression_enable(1); + } + + vg_set_display_pitch(pGeode->FBcimdisplaytiming.wPitch); + vg_set_display_offset(pGeode->FBDisplayOffset); + + /* Restore Cursor */ + vg_set_cursor_position(pGeode->FBCursor.cursor_x, + pGeode->FBCursor.cursor_y, &panning); + + LXRestore(pScrni); + + if (pGeode->useVGA && pGeode->VGAActive) { + pGeode->vesa->pInt->num = 0x10; + pGeode->vesa->pInt->ax = 0x0 | pGeode->FBBIOSMode; + pGeode->vesa->pInt->bx = 0; + xf86ExecX86int10(pGeode->vesa->pInt); + vg_delay_milliseconds(3); + } + + + lx_enable_dac_power(pScrni, 1); + pScrni->vtSema = FALSE; +} + +static Bool +LXCloseScreen(int scrnIndex, ScreenPtr pScrn) +{ + ScrnInfoPtr pScrni = xf86Screens[scrnIndex]; + GeodeRec *pGeode = GEODEPTR(pScrni); + + if (pScrni->vtSema) + LXLeaveGraphics(pScrni); + + if (pGeode->pExa) { + exaDriverFini(pScrn); + xfree(pGeode->pExa); + pGeode->pExa = NULL; + } + + LXUnmapMem(pScrni); + + if (pGeode->useVGA) + vgaHWUnmapMem(pScrni); + + pScrni->PointerMoved = pGeode->PointerMoved; + pScrn->CloseScreen = pGeode->CloseScreen; + + if (pScrn->CloseScreen) + return (*pScrn->CloseScreen)(scrnIndex, pScrn); + + return TRUE; +} + +static Bool +LXEnterGraphics(ScreenPtr pScrn, ScrnInfoPtr pScrni) +{ + int bpp; + GeodeRec *pGeode = GEODEPTR(pScrni); + + pGeode->curMode = NULL; + + pGeode->VGAActive = gu3_get_vga_active(); + + gp_wait_until_idle(); + + //lx_disable_dac_power(pScrni, DF_CRT_DISABLE); + + vg_get_current_display_mode(&pGeode->FBcimdisplaytiming.vgDisplayMode, &bpp); + + //dump_previous(&pGeode->FBcimdisplaytiming.vgDisplayMode); + + pGeode->FBcimdisplaytiming.wBpp = bpp; + pGeode->FBcimdisplaytiming.wPitch = vg_get_display_pitch(); + + pGeode->FBDisplayOffset = vg_get_display_offset(); + + if (pGeode->useVGA && pGeode->VGAActive) { + vgaHWPtr pvgaHW = VGAHWPTR(pScrni); + pGeode->FBBIOSMode = pvgaHW->readCrtc(pvgaHW, 0x040); + } + + pGeode->FBCompressionEnable = vg_get_compression_enable(); + vg_get_compression_info(&(pGeode->FBCBData)); + + /* Save Cursor offset */ + vg_get_cursor_info(&pGeode->FBCursor); + + /* Turn off the VGA */ + + if (pGeode->useVGA) { + unsigned short sequencer; + vgaHWPtr pvgaHW = VGAHWPTR(pScrni); + + /* Unlock VGA registers */ + vgaHWUnlock(pvgaHW); + + /* Save the current state and setup the current mode */ + vgaHWSave(pScrni, &VGAHWPTR(pScrni)->SavedReg, VGA_SR_ALL); + + /* DISABLE VGA SEQUENCER */ + /* This allows the VGA state machine to terminate. We must delay */ + /* such that there are no pending MBUS requests. */ + + cim_outb(DC3_SEQUENCER_INDEX, DC3_SEQUENCER_CLK_MODE); + sequencer = cim_inb(DC3_SEQUENCER_DATA); + sequencer |= DC3_CLK_MODE_SCREEN_OFF; + cim_outb(DC3_SEQUENCER_DATA, sequencer); + + vg_delay_milliseconds(1); + + /* BLANK THE VGA DISPLAY */ + cim_outw(DC3_SEQUENCER_INDEX, DC3_SEQUENCER_RESET); + sequencer = cim_inb(DC3_SEQUENCER_DATA); + sequencer &= ~DC3_RESET_VGA_DISP_ENABLE; + cim_outb(DC3_SEQUENCER_DATA, sequencer); + + vg_delay_milliseconds(1); + } + + /* Set up the memory */ + /* XXX - FIXME - when we alow inital rotation, it should be here */ + LXAllocateMemory(pScrn, pScrni, pGeode->rotation); + + /* Clear the framebuffer */ + memset(pGeode->FBBase + pGeode->displayOffset, 0, pGeode->displaySize); + + /* Set the video mode */ + LXSetVideoMode(pScrni, pScrni->currentMode); + + pGeode->curMode = pScrni->currentMode; + pScrni->vtSema = TRUE; + + return TRUE; +} + +static void +LXLoadPalette(ScrnInfoPtr pScrni, + int numColors, int *indizes, LOCO * colors, VisualPtr pVisual) +{ + int i, index, color; + + for (i = 0; i < numColors; i++) { + index = indizes[i] & 0xFF; + color = (((unsigned long)(colors[index].red & 0xFF)) << 16) | + (((unsigned long)(colors[index].green & 0xFF)) << 8) | + ((unsigned long)(colors[index].blue & 0xFF)); + + vg_set_display_palette_entry(index, color); + } +} + +#ifdef DPMSExtension + +static void +LXDPMSSet(ScrnInfoPtr pScrni, int mode, int flags) +{ + GeodeRec *pGeode = GEODEPTR(pScrni); + + if (!pScrni->vtSema) + return; + + switch (mode) { + case DPMSModeOn: + lx_enable_dac_power(pScrni, 1); + break; + + case DPMSModeStandby: + lx_disable_dac_power(pScrni, DF_CRT_STANDBY); + break; + + case DPMSModeSuspend: + lx_disable_dac_power(pScrni, DF_CRT_SUSPEND); + break; + + case DPMSModeOff: + lx_disable_dac_power(pScrni, DF_CRT_DISABLE); + break; + } +} + +#endif + +static Bool +LXCreateScreenResources(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrni = xf86Screens[pScreen->myNum]; + GeodeRec *pGeode = GEODEPTR(pScrni); + + pScreen->CreateScreenResources = pGeode->CreateScreenResources; + if (!(*pScreen->CreateScreenResources) (pScreen)) + return FALSE; + + if (xf86LoaderCheckSymbol("LXRandRSetConfig") + && pGeode->rotation != RR_Rotate_0) { + Rotation(*LXRandRSetConfig) (ScreenPtr pScreen, Rotation rr, int rate, + RRScreenSizePtr pSize) = NULL; + RRScreenSize p; + Rotation requestedRotation = pGeode->rotation; + + pGeode->rotation = RR_Rotate_0; + + /* Just setup enough for an initial rotate */ + + p.width = pScreen->width; + p.height = pScreen->height; + p.mmWidth = pScreen->mmWidth; + p.mmHeight = pScreen->mmHeight; + + LXRandRSetConfig = LoaderSymbol("LXRandRSetConfig"); + if (LXRandRSetConfig) { + pGeode->starting = TRUE; + (*LXRandRSetConfig) (pScreen, requestedRotation, 0, &p); + pGeode->starting = FALSE; + } + } + + return TRUE; +} + +static Bool +LXScreenInit(int scrnIndex, ScreenPtr pScrn, int argc, char **argv) +{ + ScrnInfoPtr pScrni = xf86Screens[scrnIndex]; + GeodeRec *pGeode = GEODEPTR(pScrni); + XF86ModReqInfo shadowReq; + int maj, min, ret, rotate; + + pGeode->starting = TRUE; + + /* If we are using VGA then go ahead and map the memory */ + + if (pGeode->useVGA) { + + if (!vgaHWMapMem(pScrni)) + return FALSE; + + vgaHWGetIOBase(VGAHWPTR(pScrni)); + } + + if (!pGeode->NoAccel) { + + pGeode->pExa = xnfcalloc(sizeof(ExaDriverRec), 1); + + if (pGeode->pExa) { + + /* THis is set in LXAllocMem */ + pGeode->pExa->memoryBase = 0; + + /* This is set in LXAllocateMemory */ + pGeode->pExa->memorySize = 0; + + pGeode->pExa->pixmapOffsetAlign = 32; + pGeode->pExa->pixmapPitchAlign = 32; + pGeode->pExa->flags = EXA_OFFSCREEN_PIXMAPS; + pGeode->pExa->maxX = pGeode->maxWidth - 1; + pGeode->pExa->maxY = pGeode->maxHeight - 1; + } + else { + xf86DrvMsg(scrnIndex, X_ERROR, "Couldn't allocate the EXA structure.\n"); + pGeode->NoAccel = TRUE; + } + } + + /* Map the memory here before doing anything else */ + + if (!LXMapMem(pScrni)) + return FALSE; + + /* XXX FIXME - Take down any of the structures on failure? */ + if (!LXEnterGraphics(pScrn, pScrni)) + return FALSE; + + miClearVisualTypes(); + + /* XXX Again - take down anything? */ + + if (pScrni->bitsPerPixel > 8) { + if (!miSetVisualTypes(pScrni->depth, + TrueColorMask, pScrni->rgbBits, pScrni->defaultVisual)) { + return FALSE; + } + } else { + if (!miSetVisualTypes(pScrni->depth, + miGetDefaultVisualMask(pScrni->depth), + pScrni->rgbBits, pScrni->defaultVisual)) { + return FALSE; + } + } + + miSetPixmapDepths(); + + /* Point at the visible area to start */ + + ret = fbScreenInit(pScrn, pGeode->FBBase + pGeode->displayOffset, + pScrni->virtualX, pScrni->virtualY, + pScrni->xDpi, pScrni->yDpi, pGeode->displayWidth, + pScrni->bitsPerPixel); + + if (!ret) + return FALSE; + + xf86SetBlackWhitePixels(pScrn); + + /* Set up the color ordering */ + if (pScrni->bitsPerPixel > 8) { + VisualPtr visual = pScrn->visuals + pScrn->numVisuals; + + while (--visual >= pScrn->visuals) { + if ((visual->class | DynamicClass) == DirectColor) { + visual->offsetRed = pScrni->offset.red; + visual->offsetGreen = pScrni->offset.green; + visual->offsetBlue = pScrni->offset.blue; + visual->redMask = pScrni->mask.red; + visual->greenMask = pScrni->mask.green; + visual->blueMask = pScrni->mask.blue; + } + } + } + + /* Must follow the color ordering */ + fbPictureInit(pScrn, 0, 0); + + if (!pGeode->NoAccel) + pGeode->NoAccel = LXExaInit(pScrn) ? FALSE : TRUE; + + miInitializeBackingStore(pScrn); + xf86SetBackingStore(pScrn); + + /* Set up the soft cursor */ + miDCInitialize(pScrn, xf86GetPointerScreenFuncs()); + + /* Set up the HW cursor - must follow the soft cursor init */ + + if (pGeode->tryHWCursor) { + if (!LXHWCursorInit(pScrn)) + xf86DrvMsg(scrnIndex, X_ERROR, + "Hardware cursor initialization failed.\n"); + } + + /* Set up the color map */ + + if (!miCreateDefColormap(pScrn)) + return FALSE; + + if (pScrni->bitsPerPixel == 8) { + /* Must follow initialization of the default colormap */ + + if (!xf86HandleColormaps(pScrn, 256, 8, + LXLoadPalette, NULL, + CMAP_PALETTED_TRUECOLOR | CMAP_RELOAD_ON_MODE_SWITCH)) { + return FALSE; + } + } +#ifdef DPMSExtension + xf86DPMSInit(pScrn, LXDPMSSet, 0); +#endif + + LXInitVideo(pScrn); + + /* Set up RandR */ + /* We provide our own RandR goodness - disable the default */ + xf86DisableRandR(); + + memset(&shadowReq, 0, sizeof(shadowReq)); + shadowReq.majorversion = 1; + shadowReq.minorversion = 1; + + if (LoadSubModule(pScrni->module, "shadow", + NULL, NULL, NULL, &shadowReq, &maj, &min)) { + + rotate = RR_Rotate_0 | RR_Rotate_90 | RR_Rotate_180 | RR_Rotate_270; + shadowSetup(pScrn); + } else { + LoaderErrorMsg(NULL, "shadow", maj, min); + xf86DrvMsg(pScrni->scrnIndex, X_ERROR, + "Error loading shadow - rotation not available.\n"); + + if (pGeode->rotation != RR_Rotate_0) + xf86DrvMsg(pScrni->scrnIndex, X_ERROR, + "Reverting back to normal rotation.\n"); + + rotate = pGeode->rotation = RR_Rotate_0; + } + + LXRandRInit(pScrn, rotate); + + pGeode->PointerMoved = pScrni->PointerMoved; + pScrni->PointerMoved = GeodePointerMoved; + pGeode->CreateScreenResources = pScrn->CreateScreenResources; + pScrn->CreateScreenResources = LXCreateScreenResources; + + pGeode->CloseScreen = pScrn->CloseScreen; + pScrn->CloseScreen = LXCloseScreen; + pScrn->SaveScreen = LXSaveScreen; + + if (serverGeneration == 1) + xf86ShowUnusedOptions(pScrni->scrnIndex, pScrni->options); + + pGeode->starting = FALSE; + + return TRUE; +} + +static int +LXValidMode(int scrnIndex, DisplayModePtr pMode, Bool Verbose, int flags) +{ + ScrnInfoPtr pScrni = xf86Screens[scrnIndex]; + GeodeRec *pGeode = GEODEPTR(pScrni); + int p, ret; + VG_QUERY_MODE vgQueryMode; + + memset(&vgQueryMode, 0, sizeof(vgQueryMode)); + + /* For builtin and default modes, try to look up the mode in Cimarron */ + + if ((pMode->type & M_T_BUILTIN) || (pMode->type & M_T_DEFAULT)) { + + if (pGeode->Output & OUTPUT_PANEL) { + + /* Can't scale this mode */ + + if ((pGeode->PanelY != pMode->CrtcHDisplay) && + pMode->CrtcHDisplay > 1024) + return MODE_NOMODE; + + vgQueryMode.panel_width = pGeode->PanelX; + vgQueryMode.panel_height = pGeode->PanelY; + + vgQueryMode.query_flags |= VG_QUERYFLAG_PANELWIDTH | VG_QUERYFLAG_PANELHEIGHT; + } + + vgQueryMode.active_width = pMode->CrtcHDisplay; + vgQueryMode.active_height = pMode->CrtcVDisplay; + vgQueryMode.bpp = pScrni->bitsPerPixel; + vgQueryMode.hz = GeodeGetRefreshRate(pMode); + vgQueryMode.query_flags |= VG_QUERYFLAG_REFRESH | VG_QUERYFLAG_BPP | + VG_QUERYFLAG_ACTIVEWIDTH | VG_QUERYFLAG_ACTIVEHEIGHT; + + ret = vg_get_display_mode_index(&vgQueryMode); + + if (ret < 0) + return MODE_BAD; + } + + if (pGeode->tryCompression) + p = GeodeCalculatePitchBytes(pMode->CrtcHDisplay, pScrni->bitsPerPixel); + else + p = ((pMode->CrtcHDisplay + 3) & ~3) * (pScrni->bitsPerPixel >> 3); + + if (p * pMode->CrtcVDisplay > pGeode->FBAvail) + return MODE_MEM; + + return MODE_OK; +} + +/* XXX - Way more to do here */ + +static Bool +LXEnterVT(int scrnIndex, int flags) +{ + ScrnInfoPtr pScrni = xf86Screens[scrnIndex]; + Bool ret = LXEnterGraphics(NULL, pScrni); + + /* Reallocate a shadow area, if we need it */ + + if (ret == TRUE) + ret = LXAllocShadow(pScrni); + + return ret; +} + +static void +LXLeaveVT(int scrnIndex, int flags) +{ + ScrnInfoPtr pScrni = xf86Screens[scrnIndex]; + GeodeRec *pGeode = GEODEPTR(pScrni); + + pGeode->PrevDisplayOffset = vg_get_display_offset(); + LXLeaveGraphics(xf86Screens[scrnIndex]); + + /* Destroy any shadow area, if we have it */ + + if (pGeode->shadowArea != NULL) { + exaOffscreenFree(pScrni->pScreen, pGeode->shadowArea); + pGeode->shadowArea = NULL; + } +} + +void +LXSetupChipsetFPtr(ScrnInfoPtr pScrn) +{ + pScrn->PreInit = LXPreInit; + pScrn->ScreenInit = LXScreenInit; + pScrn->SwitchMode = LXSwitchMode; + pScrn->AdjustFrame = LXAdjustFrame; + pScrn->EnterVT = LXEnterVT; + pScrn->LeaveVT = LXLeaveVT; + pScrn->FreeScreen = GeodeFreeScreen; + pScrn->ValidMode = LXValidMode; +} + + |