diff options
Diffstat (limited to 'src/gx_driver.c')
-rw-r--r-- | src/gx_driver.c | 1636 |
1 files changed, 1636 insertions, 0 deletions
diff --git a/src/gx_driver.c b/src/gx_driver.c new file mode 100644 index 0000000..1a8eff4 --- /dev/null +++ b/src/gx_driver.c @@ -0,0 +1,1636 @@ +/* Copyright (c) 2003-2006 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86Resources.h" +#include "xf86cmap.h" +#include "compiler.h" +#include "mipointer.h" +#include "shadow.h" +#include <X11/extensions/randr.h> +#include "fb.h" +#include "miscstruct.h" +#include "micmap.h" +#include "vbe.h" +#include "fb.h" +#include "randrstr.h" + +#include "geode.h" +#include "gfx_defs.h" +#include "gfx_regs.h" +#include "panel.h" + +/* Bring in VGA functions */ +#include "gx_vga.c" + +#define GX_MIN_PITCH 1024 +#define GX_MAX_PITCH 8192 +#define GX_MAX_WIDTH 1600 +#define GX_MIN_HEIGHT 400 +#define GX_MAX_HEIGHT 1200 +#define GX_CB_PITCH 544 +#define GX_CB_SIZE 544 + +#define GX_CPU_REG_SIZE 0x4000 +#define GX_GP_REG_SIZE 0x4000 +#define GX_VID_REG_SIZE 0x4000 + +extern OptionInfoRec GX_GeodeOptions[]; + +extern const char *amdVgahwSymbols[]; +extern const char *amdVbeSymbols[]; +extern const char *amdInt10Symbols[]; +extern const char *amdFbSymbols[]; +extern const char *amdXaaSymbols[]; +extern const char *amdExaSymbols[]; +extern const char *amdRamdacSymbols[]; + +unsigned char *XpressROMPtr; + +static inline void +gx_enable_dac_power(void) +{ + gfx_write_vid32(RCDF_VID_MISC, + gfx_read_vid32(RCDF_VID_MISC) & RCDF_GAMMA_BYPASS_BOTH); +} + +static inline void +gx_disable_dac_power(void) +{ + gfx_write_vid32(RCDF_VID_MISC, + RCDF_DAC_POWER_DOWN | RCDF_ANALOG_POWER_DOWN | + (gfx_read_vid32(RCDF_VID_MISC) & RCDF_GAMMA_BYPASS_BOTH)); +} + + + + +static void +GXInitEXAMemory(ScrnInfoPtr pScrni, unsigned int *offset, unsigned int *avail) +{ + GeodePtr pGeode = GEODEPTR(pScrni); + + if (pGeode->exaBfrSz > 0 && pGeode->exaBfrSz <= *avail) { + pGeode->exaBfrOffset = *offset; + *offset += pGeode->exaBfrOffset; + *avail -= pGeode->exaBfrOffset; + } +} + +static void +GXInitXAAMemory(ScrnInfoPtr pScrni, unsigned int *offset, unsigned int *avail) +{ + GeodePtr pGeode = GEODEPTR(pScrni); + unsigned int size, i, pitch; + + /* XXX - FIXME - What if we are out of room? Then what? */ + /* For now, we NULL them all out. */ + + if (pGeode->NoOfImgBuffers > 0) { + size = pGeode->displayPitch * pGeode->NoOfImgBuffers; + if (size <= *avail) { + for (i = 0; i < pGeode->NoOfImgBuffers; i++) { + pGeode->AccelImageWriteBuffers[i] = pGeode->FBBase + *offset; + *offset += pGeode->displayPitch; + *avail -= pGeode->displayPitch; + } + } else { + xf86DrvMsg(pScrni->scrnIndex, X_ERROR, + "Not enough memory for image write buffers.\n"); + + for (i = 0; i < pGeode->NoOfImgBuffers; i++) + pGeode->AccelImageWriteBuffers[i] = NULL; + } + } + + if (pGeode->NoOfColorExpandLines > 0) { + pitch = ((pGeode->displayPitch + 31) >> 5) << 2; + size = pitch * pGeode->NoOfColorExpandLines; + + if (size <= *avail) { + for (i = 0; i < pGeode->NoOfColorExpandLines; i++) { + pGeode->AccelColorExpandBuffers[i] = pGeode->FBBase + *offset; + *offset += pitch; + *avail -= pitch; + } + } else { + xf86DrvMsg(pScrni->scrnIndex, X_ERROR, + "Not enough memory for color expansion buffers.\n"); + + for (i = 0; i < pGeode->NoOfImgBuffers; i++) + pGeode->AccelColorExpandBuffers[i] = NULL; + } + } +} + +static Bool +GXAllocateMemory(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->Pitch = pGeode->displayPitch; + pGeode->displayWidth = pGeode->displayPitch / bytpp; + pScrni->displayWidth = pGeode->displayWidth; + + fbavail = pGeode->FBAvail - 0x4000; + + pGeode->displayOffset = fboffset = 0; + pGeode->displaySize = pScrni->virtualY * pGeode->displayPitch; + + fbavail -= pGeode->displaySize; + fboffset += pGeode->displaySize; + + if (pGeode->tryCompression) { + size = pScrni->virtualY * GX_CB_PITCH; + + if (size <= fbavail) { + pGeode->CBData.compression_offset = fboffset; + + 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; + } + } + + if (!pGeode->NoAccel) { + if (pGeode->useEXA) + GXInitEXAMemory(pScrni, &fboffset, &fbavail); + else + GXInitXAAMemory(pScrni, &fboffset, &fbavail); + } + + pGeode->shadowSize = 0; + + if (rotate != RR_Rotate_0) { + if (rotate & (RR_Rotate_90 | RR_Rotate_270)) + size = pGeode->displayPitch * pScrni->virtualX; + else + size = pGeode->displayPitch * pScrni->virtualY; + + if (size <= fbavail) { + pGeode->shadowOffset = fboffset; + pGeode->shadowSize = size; + + fboffset += size; + fbavail -= size; + } else { + xf86DrvMsg(pScrni->scrnIndex, X_ERROR, + "Not enough memory for the shadow framebuffer\n"); + ret = FALSE; + } + } + + /* XAA always exists - we can't remove it on demand like we can with EXA. + So we assume the worse, and only give XAA enough offspace room to + account for any eventuality that RandR might throw at us. */ + + if (!pGeode->NoAccel) { + + if (pGeode->useEXA && pGeode->pExa) { + ExaDriverPtr pExa = pGeode->pExa; + + pExa->offScreenBase = fboffset; + pExa->memorySize = fboffset + fbavail; + } + + if (!pGeode->useEXA) { + + if (!xf86FBManagerRunning(pScrn)) { + + unsigned int offset = fboffset; + unsigned int avail = fbavail; + RegionRec OffscreenRegion; + BoxRec AvailBox; + + /* Assume the shadow FB exists even if it doesnt */ + + if (pGeode->shadowSize == 0) { + size = (pScrn->width * bytpp) * pScrni->virtualX; + offset += size; + avail -= size; + } + + AvailBox.x1 = 0; + AvailBox.y1 = + (offset + pGeode->displayPitch - + 1) / pGeode->displayPitch; + + AvailBox.x2 = pGeode->displayWidth; + AvailBox.y2 = (offset + avail) / pGeode->displayPitch; + + if (AvailBox.y1 < AvailBox.y2) { + REGION_INIT(pScrn, &OffscreenRegion, &AvailBox, 2); + + if (!xf86InitFBManagerRegion(pScrn, &OffscreenRegion)) + xf86DrvMsg(pScrni->scrnIndex, X_ERROR, + "Memory manager initialization failed.\n"); + + REGION_UNINIT(pScrn, &OffscreenRegion); + } else + xf86DrvMsg(pScrni->scrnIndex, X_INFO, + "Cache disabled - no offscreen memory available.\n"); + } else + xf86DrvMsg(pScrni->scrnIndex, X_INFO, + "XAA offscreen memory has already been allocated.\n"); + } + } + return ret; +} + +static Bool +GXSaveScreen(ScreenPtr pScrn, int mode) +{ + ScrnInfoPtr pScrni = xf86Screens[pScrn->myNum]; + GeodePtr pGeode = GEODEPTR(pScrni); + + if (pGeode->useVGA && !pScrni->vtSema) + return vgaHWSaveScreen(pScrn, mode); + + return TRUE; +} + + + +/* Common function - used by the LX too */ +#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 + + +extern unsigned long gfx_gx2_scratch_base; + +static Bool +GXMapMem(ScrnInfoPtr pScrni) +{ + GeodeRec *pGeode = GEODEPTR(pScrni); + int index = pScrni->scrnIndex; + + pciVideoPtr pci = xf86GetPciInfoForEntity(pGeode->pEnt->index); + +#ifndef XSERVER_LIBPCIACCESS + gfx_virt_regptr = (unsigned char *)xf86MapVidMem(index, VIDMEM_MMIO, + pci->memBase[2], pci->size[2]); + + gfx_virt_gpptr = (unsigned char *)xf86MapVidMem(index, VIDMEM_MMIO, + pci->memBase[1], pci->size[1]); + + gfx_virt_vidptr = (unsigned char *)xf86MapVidMem(index, VIDMEM_MMIO, + pci->memBase[3], pci->size[3]); + + gfx_virt_fbptr = (unsigned char *)xf86MapVidMem(index, VIDMEM_FRAMEBUFFER, + pci->memBase[0], pGeode->FBAvail); +#else + gfx_virt_regptr = map_pci_mem(pScrni, 0, pci, 2, 0); + gfx_virt_gpptr = map_pci_mem(pScrni, 0, pci, 1, 0); + gfx_virt_vidptr = map_pci_mem(pScrni, 0, pci, 3, 0); + gfx_virt_fbptr = map_pci_mem(pScrni, 1, pci, 0, pGeode->FBAvail); +#endif + + gfx_gx2_scratch_base = pGeode->FBAvail - 0x4000; + + XpressROMPtr = xf86MapVidMem(index, VIDMEM_FRAMEBUFFER, 0xF0000, 0x10000); + + pGeode->FBBase = gfx_virt_fbptr; + + if ((!gfx_virt_regptr) || (!gfx_virt_gpptr) || + (!gfx_virt_vidptr) || (!gfx_virt_fbptr)) + return FALSE; + + if (!pGeode->NoAccel && pGeode->useEXA) + pGeode->pExa->memoryBase = pGeode->FBBase; + + xf86DrvMsg(index, X_INFO, "Found Geode %x %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 +GXCheckVGA(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 +GXPreInit(ScrnInfoPtr pScrni, int flags) +{ + GeodePtr pGeode; + ClockRangePtr GeodeClockRange; + OptionInfoRec *GeodeOptions = &GX_GeodeOptions[0]; + int ret; + QQ_WORD msrValue; + EntityInfoPtr pEnt; + rgb defaultWeight = { 0, 0, 0 }; + int modecnt; + char *s, *panelgeo; + Bool useVGA; + + if (pScrni->numEntities != 1) + return FALSE; + + pEnt = xf86GetEntityInfo(pScrni->entityList[0]); + if (pEnt->resources) + return FALSE; + + pGeode = pScrni->driverPrivate = xnfcalloc(sizeof(GeodeRec), 1); + + if (pGeode == NULL) + return FALSE; + + useVGA = GXCheckVGA(pScrni); + + if (flags & PROBE_DETECT) { + if (useVGA) + GeodeProbeDDC(pScrni, pEnt->index); + return TRUE; + } + + /* Probe for VGA */ + pGeode->useVGA = useVGA; + pGeode->pEnt = pEnt; + + if (pGeode->useVGA) { + if (!xf86LoadSubModule(pScrni, "vgahw") || !vgaHWGetHWRec(pScrni)) + pGeode->useVGA = FALSE; + +#if INT10_SUPPORT + pGeode->vesa = xcalloc(sizeof(VESARec), 1); +#endif + } + + gfx_msr_init(); + + ret = gfx_msr_read(RC_ID_DF, MBD_MSR_CONFIG, &msrValue); + + if (!ret) { + pGeode->Output = + ((msrValue.low & RCDF_CONFIG_FMT_MASK) == + RCDF_CONFIG_FMT_FP) ? 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->FBVGAActive = FALSE; + pGeode->tryHWCursor = TRUE; + pGeode->tryCompression = TRUE; + + pGeode->NoAccel = FALSE; + pGeode->useEXA = TRUE; + + pGeode->Panel = (pGeode->Output & OUTPUT_PANEL) ? TRUE : FALSE; + + pGeode->NoOfImgBuffers = DEFAULT_IMG_LINE_BUFS; + pGeode->NoOfColorExpandLines = DEFAULT_CLR_LINE_BUFS; + pGeode->exaBfrSz = DEFAULT_EXA_SCRATCH_BFRSZ; + + xf86GetOptValBool(GeodeOptions, GX_OPTION_HW_CURSOR, + &pGeode->tryHWCursor); + + if (!xf86GetOptValInteger(GeodeOptions, GX_OPTION_FBSIZE, + (int *)&(pGeode->FBAvail))) + pGeode->FBAvail = 0; + + /* For compatability - allow SWCursor too */ + + if (xf86ReturnOptValBool(GeodeOptions, GX_OPTION_SW_CURSOR, FALSE)) + pGeode->tryHWCursor = FALSE; + + if (xf86ReturnOptValBool(GeodeOptions, GX_OPTION_NOCOMPRESSION, FALSE)) + pGeode->tryCompression = FALSE; + + if (xf86ReturnOptValBool(GeodeOptions, GX_OPTION_NOACCEL, FALSE)) + pGeode->NoAccel = TRUE; + + pGeode->rotation = RR_Rotate_0; + + if ((s = xf86GetOptValString(GeodeOptions, GX_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, GX_OPTION_OSM_IMG_BUFS, + &(pGeode->NoOfImgBuffers)); + + if (pGeode->NoOfImgBuffers <= 0) + pGeode->NoOfImgBuffers = 0; + + xf86GetOptValInteger(GeodeOptions, GX_OPTION_OSM_CLR_BUFS, + &(pGeode->NoOfColorExpandLines)); + + if (pGeode->NoOfColorExpandLines <= 0) + pGeode->NoOfColorExpandLines = 0; + + xf86GetOptValInteger(GeodeOptions, GX_OPTION_OSM_CLR_BUFS, + (int *)&(pGeode->exaBfrSz)); + + if (pGeode->exaBfrSz <= 0) + pGeode->exaBfrSz = 0; + + if (pGeode->Panel == TRUE) { + if (xf86ReturnOptValBool(GeodeOptions, GX_OPTION_NOPANEL, FALSE)) + pGeode->Panel = FALSE; + } + + panelgeo = xf86GetOptValString(GeodeOptions, GX_OPTION_PANEL_GEOMETRY); + + if ((s = xf86GetOptValString(GeodeOptions, GX_OPTION_ACCEL_METHOD))) { + if (!xf86NameCmp(s, "XAA")) + pGeode->useEXA = FALSE; + else if (xf86NameCmp(s, "EXA")) + xf86DrvMsg(pScrni->scrnIndex, X_ERROR, + "Unknown accleration method %s. Defaulting to EXA.\n", s); + } + + xf86DrvMsg(pScrni->scrnIndex, X_INFO, + "Using %s acceleration architecture\n", + pGeode->useEXA ? "EXA" : "XAA"); + + /* Set up the panel */ + + if (pGeode->Panel) { + if (panelgeo != NULL) { + if (GeodeGetFPGeometry(panelgeo, &pGeode->PanelX, &pGeode->PanelY)) + pGeode->Panel = FALSE; + } +#ifdef PNL_SUP + else { + int b, f; + + /* The bitdepth and refresh isn't used anywhere else in the driver */ + + if ((pGeode->Panel = Pnl_IsPanelEnabledInBIOS())) + Pnl_GetPanelInfoFromBIOS(&pGeode->PanelX, &pGeode->PanelY, &b, + &f); + } +#endif + } + + /* Set up the VGA */ + + if (pGeode->useVGA) { +#if INT10_SUPPORT + 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; + } +#endif + } + + /* First try to get the framebuffer size from the framebuffer, + * and if that fails, revert all the way back to the legacy + * method + */ + + if (pGeode->FBAvail == 0) { + if (GeodeGetSizeFromFB(&pGeode->FBAvail)) + pGeode->FBAvail = gfx_get_frame_buffer_size(); + } + + if (pScrni->memPhysBase == 0) + pScrni->memPhysBase = gfx_get_frame_buffer_base(); + + pScrni->fbOffset = 0; + + if (pGeode->pEnt->device->videoRam == 0) + pScrni->videoRam = pGeode->FBAvail / 1024; + else + pScrni->videoRam = pGeode->pEnt->device->videoRam; + + pGeode->maxWidth = GX_MAX_WIDTH; + pGeode->maxHeight = GX_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) + 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, GX_MIN_PITCH, GX_MAX_PITCH, + 32, GX_MIN_HEIGHT, GX_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 == FALSE) { + const char *module = (pGeode->useEXA) ? "exa" : "xaa"; + const char **symbols = (pGeode->useEXA) ? + &amdExaSymbols[0] : &amdXaaSymbols[0]; + + if (!xf86LoadSubModule(pScrni, module)) { + return FALSE; + } + + xf86LoaderReqSymLists(symbols, 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 +GXRestore(ScrnInfoPtr pScrni) +{ + GeodeRec *pGeode = GEODEPTR(pScrni); + + if (pGeode->useVGA && pGeode->FBVGAActive) { + vgaHWPtr pvgaHW = VGAHWPTR(pScrni); + + vgaHWProtect(pScrni, TRUE); + vgaHWRestore(pScrni, &pvgaHW->SavedReg, VGA_SR_ALL); + vgaHWProtect(pScrni, FALSE); + } +} + +static Bool +GXUnmapMem(ScrnInfoPtr pScrni) +{ + GeodeRec *pGeode = GEODEPTR(pScrni); + + /* unmap all the memory map's */ + + xf86UnMapVidMem(pScrni->scrnIndex, gfx_virt_regptr, GX_CPU_REG_SIZE); + xf86UnMapVidMem(pScrni->scrnIndex, gfx_virt_gpptr, GX_GP_REG_SIZE); + xf86UnMapVidMem(pScrni->scrnIndex, gfx_virt_vidptr, GX_VID_REG_SIZE); + xf86UnMapVidMem(pScrni->scrnIndex, gfx_virt_fbptr, pGeode->FBAvail); + return TRUE; +} + +static void +GXSetDvLineSize(unsigned int pitch) +{ + unsigned long temp, dv_size = MDC_DV_LINE_SIZE_1024; + + if (pitch > 1024) { + dv_size = MDC_DV_LINE_SIZE_2048; + } + if (pitch > 2048) { + dv_size = MDC_DV_LINE_SIZE_4096; + } + if (pitch > 4096) { + dv_size = MDC_DV_LINE_SIZE_8192; + } + + /* WRITE DIRTY/VALID CONTROL WITH LINE LENGTH */ + + temp = READ_REG32(MDC_DV_CTL); + WRITE_REG32(MDC_DV_CTL, (temp & ~MDC_DV_LINE_SIZE_MASK) | dv_size); +} + +/* XXX - this is nothing like the original function - not sure exactly what the purpose is for this quite yet */ + +static void +GXAdjustFrame(int scrnIndex, int x, int y, int flags) +{ + ScrnInfoPtr pScrni = xf86Screens[scrnIndex]; + GeodeRec *pGeode = GEODEPTR(pScrni); + unsigned long offset; + + offset = + pGeode->FBOffset + y * pGeode->Pitch + + x * (pScrni->bitsPerPixel >> 3); + + gfx_set_display_offset(offset); +} + +static Bool +GXSetVideoMode(ScrnInfoPtr pScrni, DisplayModePtr pMode) +{ + GeodeRec *pGeode = GEODEPTR(pScrni); + int flags = 0; + int custom = 0; + + pScrni->vtSema = TRUE; + + gx_disable_dac_power(); + + if (pMode->Flags & V_NHSYNC) + flags |= 1; + if (pMode->Flags & V_NVSYNC) + flags |= 2; + + /* Check to see if we should use custom or built-in timings */ + + if (pGeode->Panel) + custom = (pMode->type & M_T_USERDEF); + else + custom = !(pMode->type & (M_T_BUILTIN | M_T_DEFAULT)); + + /* If we're not doing a custom mode, then just set the fixed timings, + * otherwise, do the whole shooting match */ + + if (!custom) { + GFX(set_fixed_timings(pGeode->PanelX, pGeode->PanelY, + pMode->CrtcHDisplay, pMode->CrtcVDisplay, + pScrni->bitsPerPixel)); + } else { + if (pGeode->Panel) + GFX(set_panel_present(pGeode->PanelX, pGeode->PanelY, + pMode->CrtcHDisplay, pMode->CrtcVDisplay, + pScrni->bitsPerPixel)); + + GFX(set_display_timings(pScrni->bitsPerPixel, flags, + pMode->CrtcHDisplay, pMode->CrtcHBlankStart, + pMode->CrtcHSyncStart, pMode->CrtcHSyncEnd, + pMode->CrtcHBlankEnd, pMode->CrtcHTotal, + pMode->CrtcVDisplay, pMode->CrtcVBlankStart, + pMode->CrtcVSyncStart, pMode->CrtcVSyncEnd, + pMode->CrtcVBlankEnd, pMode->CrtcVTotal, + (int)((pMode->SynthClock / 1000.0) * 0x10000))); + } + + GFX(set_crt_enable(CRT_ENABLE)); + GFX(set_display_pitch(pGeode->displayPitch)); + GFX(set_display_offset(0L)); + GFX(wait_vertical_blank()); + + if (pGeode->Compression) { + GXSetDvLineSize(pGeode->Pitch); + + gfx_set_compression_offset(pGeode->CBData.compression_offset); + gfx_set_compression_pitch(GX_CB_PITCH); + gfx_set_compression_size(GX_CB_SIZE); + + gfx_set_compression_enable(1); + } + + if (pGeode->HWCursor && !(pMode->Flags & V_DBLSCAN)) { + GXLoadCursorImage(pScrni, NULL); + GFX(set_cursor_position(pGeode->CursorStartOffset, 0, 0, 0, 0)); + GXShowCursor(pScrni); + } else { + GFX(set_cursor_enable(0)); + pGeode->HWCursor = FALSE; + } + + GXAdjustFrame(pScrni->scrnIndex, pScrni->frameX0, pScrni->frameY0, 0); + gx_enable_dac_power(); + + return TRUE; +} + +static Bool +GXSwitchMode(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 */ + + gfx_wait_until_idle(); + + /* Set up the memory for the new mode */ + rotate = GXGetRotation(pScrni->pScreen); + ret = GXAllocateMemory(pScrni->pScreen, pScrni, rotate); + + if (ret) { + if (pGeode->curMode != pMode) + ret = GXSetVideoMode(pScrni, pMode); + } + + if (ret) + ret = GXRotate(pScrni, pMode); + + /* Go back the way it was */ + + if (ret == FALSE) { + if (!GXSetVideoMode(pScrni, pGeode->curMode)) + xf86DrvMsg(pScrni->scrnIndex, X_ERROR, + "Could not restore the previous mode\n"); + } else + pGeode->curMode = pMode; + + return ret; +} + +static void +GXLeaveGraphics(ScrnInfoPtr pScrni) +{ + GeodeRec *pGeode = GEODEPTR(pScrni); + + gfx_wait_until_idle(); + + /* Restore VG registers */ + gfx_set_display_timings(pGeode->FBgfxdisplaytiming.wBpp, + pGeode->FBgfxdisplaytiming.wPolarity, + pGeode->FBgfxdisplaytiming.wHActive, + pGeode->FBgfxdisplaytiming.wHBlankStart, + pGeode->FBgfxdisplaytiming.wHSyncStart, + pGeode->FBgfxdisplaytiming.wHSyncEnd, + pGeode->FBgfxdisplaytiming.wHBlankEnd, + pGeode->FBgfxdisplaytiming.wHTotal, + pGeode->FBgfxdisplaytiming.wVActive, + pGeode->FBgfxdisplaytiming.wVBlankStart, + pGeode->FBgfxdisplaytiming.wVSyncStart, + pGeode->FBgfxdisplaytiming.wVSyncEnd, + pGeode->FBgfxdisplaytiming.wVBlankEnd, + pGeode->FBgfxdisplaytiming.wVTotal, + pGeode->FBgfxdisplaytiming.dwDotClock); + + gfx_set_compression_enable(0); + + /* Restore the previous Compression state */ + if (pGeode->FBCompressionEnable) { + gfx_set_compression_offset(pGeode->FBCompressionOffset); + gfx_set_compression_pitch(pGeode->FBCompressionPitch); + gfx_set_compression_size(pGeode->FBCompressionSize); + gfx_set_compression_enable(1); + } + + gfx_set_display_pitch(pGeode->FBgfxdisplaytiming.wPitch); + + gfx_set_display_offset(pGeode->FBDisplayOffset); + + /* Restore Cursor */ + gfx_set_cursor_position(pGeode->FBCursorOffset, 0, 0, 0, 0); + + if (pGeode->useVGA) { + pGeode->vesa->pInt->num = 0x10; + pGeode->vesa->pInt->ax = 0x0 | pGeode->FBBIOSMode; + pGeode->vesa->pInt->bx = 0; + xf86ExecX86int10(pGeode->vesa->pInt); + gfx_delay_milliseconds(3); + } + + GXRestore(pScrni); + + gx_enable_dac_power(); +} + +static Bool +GXCloseScreen(int scrnIndex, ScreenPtr pScrn) +{ + ScrnInfoPtr pScrni = xf86Screens[scrnIndex]; + GeodeRec *pGeode = GEODEPTR(pScrni); + + if (pScrni->vtSema) + GXLeaveGraphics(pScrni); + + if (pGeode->AccelInfoRec) + XAADestroyInfoRec(pGeode->AccelInfoRec); + + if (pGeode->AccelImageWriteBuffers) { + xfree(pGeode->AccelImageWriteBuffers[0]); + xfree(pGeode->AccelImageWriteBuffers); + pGeode->AccelImageWriteBuffers = NULL; + } + + if (pGeode->AccelColorExpandBuffers) { + xfree(pGeode->AccelColorExpandBuffers); + pGeode->AccelColorExpandBuffers = NULL; + } + + if (pGeode->pExa) { + exaDriverFini(pScrn); + xfree(pGeode->pExa); + pGeode->pExa = NULL; + } + + pScrni->vtSema = FALSE; + + GXUnmapMem(pScrni); + + + pScrni->PointerMoved = pGeode->PointerMoved; + pScrn->CloseScreen = pGeode->CloseScreen; + + if (pScrn->CloseScreen) + return (*pScrn->CloseScreen)(scrnIndex, pScrn); + + return TRUE; +} + +static Bool +GXEnterGraphics(ScreenPtr pScrn, ScrnInfoPtr pScrni) +{ + GeodeRec *pGeode = GEODEPTR(pScrni); + + if (!GXMapMem(pScrni)) + return FALSE; + + if (pGeode->useVGA) + pGeode->FBVGAActive = gu2_get_vga_active(); + + gfx_wait_until_idle(); + + /* Save off the current state (should this be somewhere else)? */ + + pGeode->FBgfxdisplaytiming.dwDotClock = gfx_get_clock_frequency(); + pGeode->FBgfxdisplaytiming.wPitch = gfx_get_display_pitch(); + pGeode->FBgfxdisplaytiming.wBpp = gfx_get_display_bpp(); + pGeode->FBgfxdisplaytiming.wHTotal = gfx_get_htotal(); + pGeode->FBgfxdisplaytiming.wHActive = gfx_get_hactive(); + pGeode->FBgfxdisplaytiming.wHSyncStart = gfx_get_hsync_start(); + pGeode->FBgfxdisplaytiming.wHSyncEnd = gfx_get_hsync_end(); + pGeode->FBgfxdisplaytiming.wHBlankStart = gfx_get_hblank_start(); + pGeode->FBgfxdisplaytiming.wHBlankEnd = gfx_get_hblank_end(); + pGeode->FBgfxdisplaytiming.wVTotal = gfx_get_vtotal(); + pGeode->FBgfxdisplaytiming.wVActive = gfx_get_vactive(); + pGeode->FBgfxdisplaytiming.wVSyncStart = gfx_get_vsync_start(); + pGeode->FBgfxdisplaytiming.wVSyncEnd = gfx_get_vsync_end(); + pGeode->FBgfxdisplaytiming.wVBlankStart = gfx_get_vblank_start(); + pGeode->FBgfxdisplaytiming.wVBlankEnd = gfx_get_vblank_end(); + pGeode->FBgfxdisplaytiming.wPolarity = gfx_get_sync_polarities(); + + pGeode->FBDisplayOffset = gfx_get_display_offset(); + + if (pGeode->useVGA) { + vgaHWPtr pvgaHW = VGAHWPTR(pScrni); + pGeode->FBBIOSMode = pvgaHW->readCrtc(pvgaHW, 0x040); + } + + pGeode->FBCompressionEnable = gfx_get_compression_enable(); + pGeode->FBCompressionOffset = gfx_get_compression_offset(); + pGeode->FBCompressionPitch = gfx_get_compression_pitch(); + pGeode->FBCompressionSize = gfx_get_compression_size(); + +#ifdef PNL_SUP + Pnl_SavePanelState(); +#endif + + /* Turn off the VGA */ + + if (pGeode->useVGA && pGeode->FBVGAActive) { + unsigned short sequencer; + vgaHWPtr pvgaHW = VGAHWPTR(pScrni); + + /* Map VGA aperture */ + if (!vgaHWMapMem(pScrni)) + return FALSE; + + /* 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. */ + + gfx_outb(MDC_SEQUENCER_INDEX, MDC_SEQUENCER_CLK_MODE); + sequencer = gfx_inb(MDC_SEQUENCER_DATA); + sequencer |= MDC_CLK_MODE_SCREEN_OFF; + gfx_outb(MDC_SEQUENCER_DATA, sequencer); + + gfx_delay_milliseconds(1); + + /* BLANK THE VGA DISPLAY */ + gfx_outw(MDC_SEQUENCER_INDEX, MDC_SEQUENCER_RESET); + sequencer = gfx_inb(MDC_SEQUENCER_DATA); + sequencer &= ~MDC_RESET_VGA_DISP_ENABLE; + gfx_outb(MDC_SEQUENCER_DATA, sequencer); + + gfx_delay_milliseconds(1); + } + + /* Set up the memory */ + /* XXX - FIXME - when we alow inital rotation, it should be here */ + GXAllocateMemory(pScrn, pScrni, pGeode->rotation); + + /* Clear the framebuffer */ + memset(pGeode->FBBase + pGeode->displayOffset, 0, pGeode->displaySize); + + /* Set up the video mode */ + GXSetVideoMode(pScrni, pScrni->currentMode); + pGeode->curMode = pScrni->currentMode; + + return TRUE; +} + +static void +GXLoadPalette(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)); + + GFX(set_display_palette_entry(index, color)); + } +} + +#ifdef DPMSExtension +static void +GXPanelPower(int enable) +{ + unsigned long power = READ_VID32(RCDF_POWER_MANAGEMENT); + + if (enable != 0) + power |= RCDF_PM_PANEL_POWER_ON; + else + power &= ~RCDF_PM_PANEL_POWER_ON; + + WRITE_VID32(RCDF_POWER_MANAGEMENT, power); +} + +static void +GXDPMSSet(ScrnInfoPtr pScrni, int mode, int flags) +{ + GeodeRec *pGeode; + + pGeode = GEODEPTR(pScrni); + + if (!pScrni->vtSema) + return; + + switch (mode) { + case DPMSModeOn: + /* Screen: On; HSync: On; VSync: On */ + GFX(set_crt_enable(CRT_ENABLE)); +#if defined(PNL_SUP) + if (pGeode->Panel) { + Pnl_PowerUp(); + GXPanelPower(1); + } +#endif + break; + + case DPMSModeStandby: + /* Screen: Off; HSync: Off; VSync: On */ + GFX(set_crt_enable(CRT_STANDBY)); +#if defined(PNL_SUP) + if (pGeode->Panel) { + Pnl_PowerDown(); + GXPanelPower(0); + } +#endif + break; + + case DPMSModeSuspend: + /* Screen: Off; HSync: On; VSync: Off */ + GFX(set_crt_enable(CRT_SUSPEND)); +#if defined(PNL_SUP) + if (pGeode->Panel) { + Pnl_PowerDown(); + GXPanelPower(0); + } +#endif + break; + + case DPMSModeOff: + /* Screen: Off; HSync: Off; VSync: Off */ + GFX(set_crt_enable(CRT_DISABLE)); +#if defined(PNL_SUP) + if (pGeode->Panel) { + Pnl_PowerDown(); + GXPanelPower(0); + } +#endif + break; + } +} +#endif + +static Bool +GXCreateScreenResources(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrni = xf86Screens[pScreen->myNum]; + GeodeRec *pGeode = GEODEPTR(pScrni); + + pScreen->CreateScreenResources = pGeode->CreateScreenResources; + if (!(*pScreen->CreateScreenResources) (pScreen)) + return FALSE; + + if (xf86LoaderCheckSymbol("GXRandRSetConfig") + && pGeode->rotation != RR_Rotate_0) { + Rotation(*GXRandRSetConfig) (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; + + GXRandRSetConfig = LoaderSymbol("GXRandRSetConfig"); + if (GXRandRSetConfig) { + pGeode->starting = TRUE; + (*GXRandRSetConfig) (pScreen, requestedRotation, 0, &p); + pGeode->starting = FALSE; + } + } + + return TRUE; +} + +static Bool +GXScreenInit(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) { + + if (pGeode->useEXA) { + + if (!(pGeode->pExa = xnfcalloc(sizeof(ExaDriverRec), 1))) { + xf86DrvMsg(scrnIndex, X_ERROR, + "Couldn't allocate the EXA structure.\n"); + pGeode->NoAccel = TRUE; + } else { + ExaDriverPtr pExa = pGeode->pExa; + + /* THis is set in GXAllocMem */ + pExa->memoryBase = 0; + + /* This is set in GXAllocateMemory */ + pExa->memorySize = 0; + + pExa->pixmapOffsetAlign = 32; + pExa->pixmapPitchAlign = 32; + pExa->flags = EXA_OFFSCREEN_PIXMAPS; + pExa->maxX = pGeode->maxWidth - 1; + pExa->maxY = pGeode->maxHeight - 1; + } + } else { + pGeode->AccelImageWriteBuffers = + xcalloc(sizeof(pGeode->AccelImageWriteBuffers[0]), + pGeode->NoOfImgBuffers); + pGeode->AccelColorExpandBuffers = + xcalloc(sizeof(pGeode->AccelColorExpandBuffers[0]), + pGeode->NoOfColorExpandLines); + } + } + + /* XXX FIXME - Take down any of the structures on failure? */ + + if (!GXEnterGraphics(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) + GXAccelInit(pScrn); + + 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 (!GXHWCursorInit(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, + GXLoadPalette, NULL, + CMAP_PALETTED_TRUECOLOR | CMAP_RELOAD_ON_MODE_SWITCH)) { + return FALSE; + } + } +#ifdef DPMSExtension + xf86DPMSInit(pScrn, GXDPMSSet, 0); +#endif + + GXInitVideo(pScrn); + + /* Set up RandR */ + + xf86DisableRandR(); /* We provide our own RandR goodness */ + + /* Try to set up the shadow FB for rotation */ + + 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; + } + + GXRandRInit(pScrn, rotate); + + pGeode->PointerMoved = pScrni->PointerMoved; + pScrni->PointerMoved = GeodePointerMoved; + + pGeode->CreateScreenResources = pScrn->CreateScreenResources; + pScrn->CreateScreenResources = GXCreateScreenResources; + + pGeode->CloseScreen = pScrn->CloseScreen; + pScrn->CloseScreen = GXCloseScreen; + pScrn->SaveScreen = GXSaveScreen; + + if (serverGeneration == 1) + xf86ShowUnusedOptions(pScrni->scrnIndex, pScrni->options); + + pGeode->starting = FALSE; + + return TRUE; +} + +static int +GXValidMode(int scrnIndex, DisplayModePtr pMode, Bool Verbose, int flags) +{ + ScrnInfoPtr pScrni = xf86Screens[scrnIndex]; + GeodeRec *pGeode = GEODEPTR(pScrni); + int p, ret; + int custom = 0; + + if (pGeode->Panel) + custom = (pMode->type & M_T_USERDEF); + else + custom = (pMode->type & (M_T_BUILTIN | M_T_DEFAULT)); + + /* Use the durango lookup for !custom modes */ + + if (!custom) { + if (pGeode->Panel) { + if (pMode->CrtcHDisplay > pGeode->PanelX || + pMode->CrtcVDisplay > pGeode->PanelY || + gfx_is_panel_mode_supported(pGeode->PanelX, pGeode->PanelY, + pMode->CrtcHDisplay, pMode->CrtcVDisplay, + pScrni->bitsPerPixel) < 0) { + + return MODE_BAD; + } + } + + ret = gfx_is_display_mode_supported(pMode->CrtcHDisplay, + pMode->CrtcVDisplay, + pScrni->bitsPerPixel, + GeodeGetRefreshRate(pMode)); + if (ret < 0) + return MODE_BAD; + } + + if (pMode->Flags & V_INTERLACE) + return MODE_NO_INTERLACE; + + 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 +GXEnterVT(int scrnIndex, int flags) +{ + return GXEnterGraphics(NULL, xf86Screens[scrnIndex]); +} + +static void +GXLeaveVT(int scrnIndex, int flags) +{ + ScrnInfoPtr pScrni = xf86Screens[scrnIndex]; + GeodeRec *pGeode = GEODEPTR(pScrni); + + pGeode->PrevDisplayOffset = gfx_get_display_offset(); + GXLeaveGraphics(xf86Screens[scrnIndex]); +} + +void +GXSetupChipsetFPtr(ScrnInfoPtr pScrn) +{ + pScrn->PreInit = GXPreInit; + pScrn->ScreenInit = GXScreenInit; + pScrn->SwitchMode = GXSwitchMode; + pScrn->AdjustFrame = GXAdjustFrame; + pScrn->EnterVT = GXEnterVT; + pScrn->LeaveVT = GXLeaveVT; + pScrn->FreeScreen = GeodeFreeScreen; + pScrn->ValidMode = GXValidMode; +} + +/* ====== Common functions ====== + * These are all the common functions that we use for both GX and LX - They live here + * because most of them came along for the GX first, and then were adapted to the LX. + * We could move these to a common function, but there is no hurry + * ============================== */ + + +void +GeodePointerMoved(int index, int x, int y) +{ + ScrnInfoPtr pScrni = xf86Screens[index]; + GeodeRec *pGeode = GEODEPTR(pScrni); + + int newX = x, newY = y; + + switch (pGeode->rotation) { + case RR_Rotate_0: + break; + case RR_Rotate_90: + newX = y; + newY = pScrni->pScreen->width - x - 1; + break; + case RR_Rotate_180: + newX = pScrni->pScreen->width - x - 1; + newY = pScrni->pScreen->height - y - 1; + break; + case RR_Rotate_270: + newX = pScrni->pScreen->height - y - 1; + newY = x; + break; + } + + (*pGeode->PointerMoved)(index, newX, newY); +} + +void +GeodeProbeDDC(ScrnInfoPtr pScrni, int index) +{ + vbeInfoPtr pVbe; + + if (xf86LoadSubModule(pScrni, "vbe")) { + pVbe = VBEInit(NULL, index); + ConfiguredMonitor = vbeDoEDID(pVbe, NULL); + vbeFree(pVbe); + } +} + +xf86MonPtr +GeodeDoDDC(ScrnInfoPtr pScrni, int index) +{ + vbeInfoPtr pVbe; + xf86MonPtr info = NULL; + + if (xf86LoadSubModule(pScrni, "vbe") && + (pVbe = VBEInit(NULL, index))) { + xf86LoaderReqSymLists(amdVbeSymbols, NULL); + info = vbeDoEDID(pVbe, NULL); + xf86PrintEDID(info); + xf86SetDDCproperties(pScrni, info); + vbeFree(pVbe); + } else + xf86DrvMsg(pScrni->scrnIndex, X_INFO, + "We cannot do DDC without VBE.\n"); + + return info; +} + +int +GeodeGetFPGeometry(const char *str, int *width, int *height) +{ + + int ret = sscanf(str, "%dx%d", width, height); + + return (ret == 2) ? 0 : 1; +} + +static void +GeodeFreeRec(ScrnInfoPtr pScrni) +{ + if (pScrni->driverPrivate != NULL) { + xfree(pScrni->driverPrivate); + pScrni->driverPrivate = NULL; + } +} + +void +GeodeFreeScreen(int scrnIndex, int flags) +{ + GeodeRec *pGeode = GEODEPTR(xf86Screens[scrnIndex]); + + if (pGeode == NULL) + return; + + if (pGeode->useVGA) { + if (xf86LoaderCheckSymbol("vgaHWFreeHWRec")) + vgaHWFreeHWRec(xf86Screens[scrnIndex]); + } + + GeodeFreeRec(xf86Screens[scrnIndex]); +} + +int +GeodeCalculatePitchBytes(unsigned int width, unsigned int bpp) +{ + + int delta = width * (bpp >> 3); + + /* Less then 640 has doubling enabled */ + + if (width < 640) + delta <<= 1; + + /* Calculate the pitch (compression rquires a power of 2) */ + + if (delta > 4096) + delta = 8192; + else if (delta > 2048) + delta = 4096; + else if (delta > 1024) + delta = 2048; + else + delta = 1024; + + return delta; +} + |