xenocara/driver/xf86-video-geode/src/gx_driver.c
2008-06-14 22:15:30 +00:00

1597 lines
40 KiB
C

/* 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) {
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;
pScrni->monitor->DDC = GeodeDoDDC(pScrni, pGeode->pEnt->index);
/* 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);
}
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;
}