/* * Copyright © 2003 Eric Anholt * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of Eric Anholt not be used in * advertising or publicity pertaining to distribution of the software without * specific, written prior permission. Eric Anholt makes no * representations about the suitability of this software for any purpose. It * is provided "as is" without express or implied warranty. * * ERIC ANHOLT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO * EVENT SHALL ERIC ANHOLT BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifdef HAVE_CONFIG_H #include #endif #include "ati.h" #include "ati_reg.h" #if defined(USE_DRI) && defined(GLXEXT) #include "ati_sarea.h" #endif static Bool ATIIsAGP(ATICardInfo *atic); #define CAP_SERIESMASK 0xf #define CAP_R128 0x1 /* If it's a Rage 128 */ #define CAP_R100 0x2 /* If it's an r100 series radeon. */ #define CAP_R200 0x3 /* If it's an r200 series radeon. */ #define CAP_R300 0x4 /* If it's an r300 series radeon. */ #define CAP_FEATURESMASK 0xf0 #define CAP_NOAGP 0x10 /* If it's a PCI-only card. */ struct pci_id_entry ati_pci_ids[] = { {0x1002, 0x4136, 0x2, "ATI Radeon RS100"}, {0x1002, 0x4137, 0x2, "ATI Radeon RS200"}, {0x1002, 0x4237, 0x2, "ATI Radeon RS250"}, {0x1002, 0x4144, 0x4, "ATI Radeon R300 AD"}, {0x1002, 0x4145, 0x4, "ATI Radeon R300 AE"}, {0x1002, 0x4146, 0x4, "ATI Radeon R300 AF"}, {0x1002, 0x4147, 0x4, "ATI Radeon R300 AG"}, {0x1002, 0x4148, 0x4, "ATI Radeon R350 AH"}, {0x1002, 0x4149, 0x4, "ATI Radeon R350 AI"}, {0x1002, 0x414a, 0x4, "ATI Radeon R350 AJ"}, {0x1002, 0x414b, 0x4, "ATI Radeon R350 AK"}, {0x1002, 0x4150, 0x4, "ATI Radeon RV350 AP"}, {0x1002, 0x4151, 0x4, "ATI Radeon RV350 AQ"}, {0x1002, 0x4152, 0x4, "ATI Radeon RV350 AR"}, {0x1002, 0x4153, 0x4, "ATI Radeon RV350 AS"}, {0x1002, 0x4154, 0x4, "ATI Radeon RV350 AT"}, {0x1002, 0x4156, 0x4, "ATI Radeon RV350 AV"}, {0x1002, 0x4242, 0x3, "ATI Radeon R200 BB"}, {0x1002, 0x4243, 0x3, "ATI Radeon R200 BC"}, {0x1002, 0x4336, 0x2, "ATI Radeon RS100"}, {0x1002, 0x4337, 0x2, "ATI Radeon RS200"}, {0x1002, 0x4437, 0x2, "ATI Radeon RS250"}, {0x1002, 0x4964, 0x2, "ATI Radeon RV250 Id"}, {0x1002, 0x4965, 0x2, "ATI Radeon RV250 Ie"}, {0x1002, 0x4966, 0x2, "ATI Radeon RV250 If"}, {0x1002, 0x4967, 0x2, "ATI Radeon R250 Ig"}, {0x1002, 0x4c45, 0x11, "ATI Rage 128 LE"}, {0x1002, 0x4c46, 0x1, "ATI Rage 128 LF"}, {0x1002, 0x4c57, 0x2, "ATI Radeon Mobiliy M7 RV200 LW (7500)"}, {0x1002, 0x4c58, 0x2, "ATI Radeon Mobiliy M7 RV200 LX (7500)"}, {0x1002, 0x4c59, 0x2, "ATI Radeon Mobility M6 LY"}, {0x1002, 0x4c5a, 0x2, "ATI Radeon Mobility M6 LZ"}, {0x1002, 0x4c64, 0x3, "ATI Radeon RV250 Ld"}, {0x1002, 0x4c65, 0x3, "ATI Radeon RV250 Le"}, {0x1002, 0x4c66, 0x3, "ATI Radeon Mobility M9 RV250 Lf"}, {0x1002, 0x4c67, 0x3, "ATI Radeon RV250 Lg"}, {0x1002, 0x4d46, 0x1, "ATI Rage 128 MF"}, {0x1002, 0x4d46, 0x1, "ATI Rage 128 ML"}, {0x1002, 0x4e44, 0x4, "ATI Radeon R300 ND"}, {0x1002, 0x4e45, 0x4, "ATI Radeon R300 NE"}, {0x1002, 0x4e46, 0x4, "ATI Radeon R300 NF"}, {0x1002, 0x4e47, 0x4, "ATI Radeon R300 NG"}, {0x1002, 0x4e48, 0x4, "ATI Radeon R350 NH"}, {0x1002, 0x4e49, 0x4, "ATI Radeon R350 NI"}, {0x1002, 0x4e4a, 0x4, "ATI Radeon R350 NJ"}, {0x1002, 0x4e4b, 0x4, "ATI Radeon R350 NK"}, {0x1002, 0x4e50, 0x4, "ATI Radeon Mobility RV350 NP"}, {0x1002, 0x4e51, 0x4, "ATI Radeon Mobility RV350 NQ"}, {0x1002, 0x4e52, 0x4, "ATI Radeon Mobility RV350 NR"}, {0x1002, 0x4e53, 0x4, "ATI Radeon Mobility RV350 NS"}, {0x1002, 0x4e54, 0x4, "ATI Radeon Mobility RV350 NT"}, {0x1002, 0x4e56, 0x4, "ATI Radeon Mobility RV350 NV"}, {0x1002, 0x5041, 0x1, "ATI Rage 128 PA"}, {0x1002, 0x5042, 0x1, "ATI Rage 128 PB"}, {0x1002, 0x5043, 0x1, "ATI Rage 128 PC"}, {0x1002, 0x5044, 0x11, "ATI Rage 128 PD"}, {0x1002, 0x5045, 0x1, "ATI Rage 128 PE"}, {0x1002, 0x5046, 0x1, "ATI Rage 128 PF"}, {0x1002, 0x5047, 0x1, "ATI Rage 128 PG"}, {0x1002, 0x5048, 0x1, "ATI Rage 128 PH"}, {0x1002, 0x5049, 0x1, "ATI Rage 128 PI"}, {0x1002, 0x504a, 0x1, "ATI Rage 128 PJ"}, {0x1002, 0x504b, 0x1, "ATI Rage 128 PK"}, {0x1002, 0x504c, 0x1, "ATI Rage 128 PL"}, {0x1002, 0x504d, 0x1, "ATI Rage 128 PM"}, {0x1002, 0x504e, 0x1, "ATI Rage 128 PN"}, {0x1002, 0x504f, 0x1, "ATI Rage 128 PO"}, {0x1002, 0x5050, 0x11, "ATI Rage 128 PP"}, {0x1002, 0x5051, 0x1, "ATI Rage 128 PQ"}, {0x1002, 0x5052, 0x11, "ATI Rage 128 PR"}, {0x1002, 0x5053, 0x1, "ATI Rage 128 PS"}, {0x1002, 0x5054, 0x1, "ATI Rage 128 PT"}, {0x1002, 0x5055, 0x1, "ATI Rage 128 PU"}, {0x1002, 0x5056, 0x1, "ATI Rage 128 PV"}, {0x1002, 0x5057, 0x1, "ATI Rage 128 PW"}, {0x1002, 0x5058, 0x1, "ATI Rage 128 PX"}, {0x1002, 0x5144, 0x2, "ATI Radeon R100 QD"}, {0x1002, 0x5145, 0x2, "ATI Radeon R100 QE"}, {0x1002, 0x5146, 0x2, "ATI Radeon R100 QF"}, {0x1002, 0x5147, 0x2, "ATI Radeon R100 QG"}, {0x1002, 0x5148, 0x3, "ATI Radeon R200 QH"}, {0x1002, 0x514c, 0x3, "ATI Radeon R200 QL"}, {0x1002, 0x514d, 0x3, "ATI Radeon R200 QM"}, {0x1002, 0x5157, 0x2, "ATI Radeon RV200 QW (7500)"}, {0x1002, 0x5158, 0x2, "ATI Radeon RV200 QX (7500)"}, {0x1002, 0x5159, 0x2, "ATI Radeon RV100 QY"}, {0x1002, 0x515a, 0x2, "ATI Radeon RV100 QZ"}, {0x1002, 0x5245, 0x11, "ATI Rage 128 RE"}, {0x1002, 0x5246, 0x1, "ATI Rage 128 RF"}, {0x1002, 0x5247, 0x1, "ATI Rage 128 RG"}, {0x1002, 0x524b, 0x11, "ATI Rage 128 RK"}, {0x1002, 0x524c, 0x1, "ATI Rage 128 RL"}, {0x1002, 0x5345, 0x1, "ATI Rage 128 SE"}, {0x1002, 0x5346, 0x1, "ATI Rage 128 SF"}, {0x1002, 0x5347, 0x1, "ATI Rage 128 SG"}, {0x1002, 0x5348, 0x1, "ATI Rage 128 SH"}, {0x1002, 0x534b, 0x1, "ATI Rage 128 SK"}, {0x1002, 0x534c, 0x1, "ATI Rage 128 SL"}, {0x1002, 0x534d, 0x1, "ATI Rage 128 SM"}, {0x1002, 0x534e, 0x1, "ATI Rage 128 SN"}, {0x1002, 0x5446, 0x1, "ATI Rage 128 TF"}, {0x1002, 0x544c, 0x1, "ATI Rage 128 TL"}, {0x1002, 0x5452, 0x1, "ATI Rage 128 TR"}, {0x1002, 0x5453, 0x1, "ATI Rage 128 TS"}, {0x1002, 0x5454, 0x1, "ATI Rage 128 TT"}, {0x1002, 0x5455, 0x1, "ATI Rage 128 TU"}, {0x1002, 0x5834, 0x3, "ATI Radeon RS300"}, {0x1002, 0x5835, 0x3, "ATI Radeon RS300 Mobility"}, {0x1002, 0x5941, 0x3, "ATI Radeon RV280 (9200)"}, {0x1002, 0x5961, 0x3, "ATI Radeon RV280 (9200 SE)"}, {0x1002, 0x5964, 0x3, "ATI Radeon RV280 (9200 SE)"}, {0x1002, 0x5c60, 0x3, "ATI Radeon RV280"}, {0x1002, 0x5c61, 0x3, "ATI Radeon RV280 Mobility"}, {0x1002, 0x5c62, 0x3, "ATI Radeon RV280"}, {0x1002, 0x5c63, 0x3, "ATI Radeon RV280 Mobility"}, {0x1002, 0x5c64, 0x3, "ATI Radeon RV280"}, {0, 0, 0, NULL} }; static char * make_busid(KdCardAttr *attr) { char *busid; busid = xalloc(20); if (busid == NULL) return NULL; snprintf(busid, 20, "pci:%04x:%02x:%02x.%d", attr->domain, attr->bus, attr->slot, attr->func); return busid; } static Bool ATICardInit(KdCardInfo *card) { ATICardInfo *atic; int i; Bool initialized = FALSE; atic = xcalloc(sizeof(ATICardInfo), 1); if (atic == NULL) return FALSE; #ifdef KDRIVEFBDEV if (!initialized && fbdevInitialize(card, &atic->backend_priv.fbdev)) { atic->use_fbdev = TRUE; initialized = TRUE; atic->backend_funcs.cardfini = fbdevCardFini; atic->backend_funcs.scrfini = fbdevScreenFini; atic->backend_funcs.initScreen = fbdevInitScreen; atic->backend_funcs.finishInitScreen = fbdevFinishInitScreen; atic->backend_funcs.createRes = fbdevCreateResources; atic->backend_funcs.preserve = fbdevPreserve; atic->backend_funcs.restore = fbdevRestore; atic->backend_funcs.dpms = fbdevDPMS; atic->backend_funcs.enable = fbdevEnable; atic->backend_funcs.disable = fbdevDisable; atic->backend_funcs.getColors = fbdevGetColors; atic->backend_funcs.putColors = fbdevPutColors; #ifdef RANDR atic->backend_funcs.randrSetConfig = fbdevRandRSetConfig; #endif } #endif #ifdef KDRIVEVESA if (!initialized && vesaInitialize(card, &atic->backend_priv.vesa)) { atic->use_vesa = TRUE; initialized = TRUE; atic->backend_funcs.cardfini = vesaCardFini; atic->backend_funcs.scrfini = vesaScreenFini; atic->backend_funcs.initScreen = vesaInitScreen; atic->backend_funcs.finishInitScreen = vesaFinishInitScreen; atic->backend_funcs.createRes = vesaCreateResources; atic->backend_funcs.preserve = vesaPreserve; atic->backend_funcs.restore = vesaRestore; atic->backend_funcs.dpms = vesaDPMS; atic->backend_funcs.enable = vesaEnable; atic->backend_funcs.disable = vesaDisable; atic->backend_funcs.getColors = vesaGetColors; atic->backend_funcs.putColors = vesaPutColors; #ifdef RANDR atic->backend_funcs.randrSetConfig = vesaRandRSetConfig; #endif } #endif if (!initialized || !ATIMapReg(card, atic)) { xfree(atic); return FALSE; } atic->busid = make_busid(&card->attr); if (atic->busid == NULL) { xfree(atic); return FALSE; } #ifdef USE_DRI /* We demand identification by busid, not driver name */ atic->drmFd = drmOpen(NULL, atic->busid); if (atic->drmFd < 0) ErrorF("Failed to open DRM, DRI disabled.\n"); #endif /* USE_DRI */ card->driver = atic; for (i = 0; ati_pci_ids[i].name != NULL; i++) { if (ati_pci_ids[i].device == card->attr.deviceID) { atic->pci_id = &ati_pci_ids[i]; break; } } if ((atic->pci_id->caps & CAP_SERIESMASK) != CAP_R128) atic->is_radeon = TRUE; if ((atic->pci_id->caps & CAP_SERIESMASK) == CAP_R100) atic->is_r100 = TRUE; if ((atic->pci_id->caps & CAP_SERIESMASK) == CAP_R200) atic->is_r200 = TRUE; if ((atic->pci_id->caps & CAP_SERIESMASK) == CAP_R300) atic->is_r300 = TRUE; atic->is_agp = ATIIsAGP(atic); ErrorF("Using ATI card: %s (%s) at %s\n", atic->pci_id->name, atic->is_agp ? "AGP" : "PCI", atic->busid); return TRUE; } static void ATICardFini(KdCardInfo *card) { ATICardInfo *atic = (ATICardInfo *)card->driver; ATIUnmapReg(card, atic); atic->backend_funcs.cardfini(card); } /* * Once screen->off_screen_base is set, this function * allocates the remaining memory appropriately */ static void ATISetOffscreen (KdScreenInfo *screen) { ATICardInfo(screen); #if defined(USE_DRI) && defined(GLXEXT) ATIScreenInfo *atis = (ATIScreenInfo *)screen->driver; int l; #endif int screen_size; char *mmio = atic->reg_base; /* check (and adjust) pitch */ if (mmio) { int byteStride = screen->fb[0].byteStride; int bitStride; int pixelStride; int bpp = screen->fb[0].bitsPerPixel; /* * Ensure frame buffer is correctly aligned */ if (byteStride & 0x3f) { byteStride = (byteStride + 0x3f) & ~0x3f; bitStride = byteStride * 8; pixelStride = bitStride / bpp; screen->fb[0].byteStride = byteStride; screen->fb[0].pixelStride = pixelStride; } } screen_size = screen->fb[0].byteStride * screen->height; screen->off_screen_base = screen_size; #if defined(USE_DRI) && defined(GLXEXT) /* Reserve a static area for the back buffer the same size as the * visible screen. XXX: This would be better initialized in ati_dri.c * when GLX is set up, but the offscreen memory manager's allocations * don't last through VT switches, while the kernel's understanding of * offscreen locations does. */ atis->frontOffset = 0; atis->frontPitch = screen->fb[0].byteStride; if (screen->off_screen_base + screen_size <= screen->memory_size) { atis->backOffset = screen->off_screen_base; atis->backPitch = screen->fb[0].byteStride; screen->off_screen_base += screen_size; } /* Reserve the depth span for Rage 128 */ if (!atic->is_radeon && screen->off_screen_base + screen->fb[0].byteStride <= screen->memory_size) { atis->spanOffset = screen->off_screen_base; screen->off_screen_base += screen->fb[0].byteStride; } /* Reserve the static depth buffer, which happens to be the same * bitsPerPixel as the screen. */ if (screen->off_screen_base + screen_size <= screen->memory_size) { atis->depthOffset = screen->off_screen_base; atis->depthPitch = screen->fb[0].byteStride; screen->off_screen_base += screen_size; } /* Reserve approx. half of remaining offscreen memory for local * textures. Round down to a whole number of texture regions. */ atis->textureSize = (screen->memory_size - screen->off_screen_base) / 2; l = ATILog2(atis->textureSize / ATI_NR_TEX_REGIONS); if (l < ATI_LOG_TEX_GRANULARITY) l = ATI_LOG_TEX_GRANULARITY; atis->textureSize = (atis->textureSize >> l) << l; if (atis->textureSize >= 512 * 1024) { atis->textureOffset = screen->off_screen_base; screen->off_screen_base += atis->textureSize; } else { /* Minimum texture size is for 2 256x256x32bpp textures */ atis->textureSize = 0; } #endif /* USE_DRI && GLXEXT */ } static void ATISetPitch (KdScreenInfo *screen) { ATICardInfo(screen); #if defined(USE_DRI) && defined(GLXEXT) ATIScreenInfo *atis = (ATIScreenInfo *)screen->driver; int l; #endif char *mmio = atic->reg_base; /* check (and adjust) pitch for radeon */ if (mmio) { int byteStride = screen->fb[0].byteStride; int bitStride; int pixelStride; int bpp = screen->fb[0].bitsPerPixel; CARD32 crtc_pitch; CARD32 crtc2_pitch; #if 0 CARD32 crtc_ext_cntl; CARD32 dac_cntl; #endif bitStride = byteStride * 8; pixelStride = bitStride / bpp; crtc_pitch = (pixelStride >> 3); crtc_pitch |= crtc_pitch << 16; crtc2_pitch = (pixelStride >> 3); crtc2_pitch |= crtc2_pitch << 16; #if 0 crtc_ext_cntl = MMIO_IN32 (mmio, ATI_REG_CRTC_EXT_CNTL); dac_cntl = MMIO_IN32 (mmio, ATI_REG_DAC_CNTL); /* Turn off the screen */ MMIO_OUT32 (mmio, ATI_REG_CRTC_EXT_CNTL, crtc_ext_cntl | ATI_CRTC_VSYNC_DIS | ATI_CRTC_HSYNC_DIS | ATI_CRTC_DISPLAY_DIS); MMIO_OUT32 (mmio, ATI_REG_DAC_CNTL, dac_cntl | ATI_DAC_RANGE_CNTL | ATI_DAC_BLANKING); #endif MMIO_OUT32 (mmio, ATI_REG_CRTC_PITCH, crtc_pitch); MMIO_OUT32 (mmio, ATI_REG_CRTC2_PITCH, crtc2_pitch); #if 0 /* Turn the screen back on */ MMIO_OUT32 (mmio, ATI_REG_CRTC_EXT_CNTL, crtc_ext_cntl); MMIO_OUT32 (mmio, ATI_REG_DAC_CNTL, dac_cntl); #endif } } static Bool ATIScreenInit(KdScreenInfo *screen) { ATIScreenInfo *atis; ATICardInfo(screen); Bool success = FALSE; atis = xcalloc(sizeof(ATIScreenInfo), 1); if (atis == NULL) return FALSE; atis->atic = atic; atis->screen = screen; screen->driver = atis; if (screen->fb[0].depth == 0) screen->fb[0].depth = 16; #ifdef KDRIVEFBDEV if (atic->use_fbdev) { success = fbdevScreenInitialize(screen, &atis->backend_priv.fbdev); } #endif #ifdef KDRIVEVESA if (atic->use_vesa) { success = vesaScreenInitialize(screen, &atis->backend_priv.vesa); } #endif if (!success) { screen->driver = NULL; xfree(atis); return FALSE; } ATISetOffscreen (screen); return TRUE; } #ifdef RANDR static Bool ATIRandRSetConfig (ScreenPtr pScreen, Rotation randr, int rate, RRScreenSizePtr pSize) { KdScreenPriv(pScreen); KdScreenInfo *screen = pScreenPriv->screen; ATICardInfo *atic = screen->card->driver; Bool ret; ATIDrawDisable (pScreen); ret = atic->backend_funcs.randrSetConfig(pScreen, randr, rate, pSize); ATISetOffscreen (screen); ATISetPitch (screen); /* * Set frame buffer mapping */ (*pScreen->ModifyPixmapHeader) (fbGetScreenPixmap (pScreen), pScreen->width, pScreen->height, screen->fb[0].depth, screen->fb[0].bitsPerPixel, screen->fb[0].byteStride, screen->fb[0].frameBuffer); ATIDrawEnable (pScreen); return ret; } static Bool ATIRandRInit (ScreenPtr pScreen) { rrScrPrivPtr pScrPriv; pScrPriv = rrGetScrPriv(pScreen); pScrPriv->rrSetConfig = ATIRandRSetConfig; return TRUE; } #endif static void ATIScreenFini(KdScreenInfo *screen) { ATIScreenInfo *atis = (ATIScreenInfo *)screen->driver; ATICardInfo *atic = screen->card->driver; #ifdef XV ATIFiniVideo(screen->pScreen); #endif atic->backend_funcs.scrfini(screen); xfree(atis); screen->driver = 0; } Bool ATIMapReg(KdCardInfo *card, ATICardInfo *atic) { atic->reg_base = (char *)KdMapDevice(ATI_REG_BASE(card), ATI_REG_SIZE(card)); if (atic->reg_base == NULL) return FALSE; KdSetMappedMode(ATI_REG_BASE(card), ATI_REG_SIZE(card), KD_MAPPED_MODE_REGISTERS); return TRUE; } void ATIUnmapReg(KdCardInfo *card, ATICardInfo *atic) { if (atic->reg_base) { KdResetMappedMode(ATI_REG_BASE(card), ATI_REG_SIZE(card), KD_MAPPED_MODE_REGISTERS); KdUnmapDevice((void *)atic->reg_base, ATI_REG_SIZE(card)); atic->reg_base = 0; } } static Bool ATIInitScreen(ScreenPtr pScreen) { KdScreenPriv(pScreen); ATICardInfo(pScreenPriv); #ifdef XV ATIInitVideo(pScreen); #endif return atic->backend_funcs.initScreen(pScreen); } static Bool ATIFinishInitScreen(ScreenPtr pScreen) { KdScreenPriv(pScreen); ATICardInfo(pScreenPriv); if (!atic->backend_funcs.finishInitScreen(pScreen)) return FALSE; #ifdef RANDR if (!ATIRandRInit (pScreen)) return FALSE; #endif return TRUE; } static Bool ATICreateResources(ScreenPtr pScreen) { KdScreenPriv(pScreen); ATICardInfo(pScreenPriv); return atic->backend_funcs.createRes(pScreen); } static void ATIPreserve(KdCardInfo *card) { ATICardInfo *atic = card->driver; char *mmio = atic->reg_base; atic->backend_funcs.preserve(card); if (atic->is_radeon && mmio) { atic->crtc_pitch = MMIO_IN32(mmio, ATI_REG_CRTC_PITCH); atic->crtc2_pitch = MMIO_IN32(mmio, ATI_REG_CRTC2_PITCH); } } static void ATIRestore(KdCardInfo *card) { ATICardInfo *atic = card->driver; char *mmio = atic->reg_base; if (mmio) { MMIO_OUT32(mmio, ATI_REG_CRTC_PITCH, atic->crtc_pitch); MMIO_OUT32(mmio, ATI_REG_CRTC2_PITCH, atic->crtc2_pitch); } ATIUnmapReg(card, atic); atic->backend_funcs.restore(card); } static Bool ATIDPMS(ScreenPtr pScreen, int mode) { KdScreenPriv(pScreen); ATICardInfo(pScreenPriv); return atic->backend_funcs.dpms(pScreen, mode); } static Bool ATIEnable(ScreenPtr pScreen) { KdScreenPriv(pScreen); ATICardInfo(pScreenPriv); if (!atic->backend_funcs.enable(pScreen)) return FALSE; if ((atic->reg_base == NULL) && !ATIMapReg(pScreenPriv->screen->card, atic)) return FALSE; ATISetOffscreen (pScreenPriv->screen); ATISetPitch (pScreenPriv->screen); return TRUE; } static void ATIDisable(ScreenPtr pScreen) { KdScreenPriv(pScreen); #if defined(USE_DRI) && defined(GLXEXT) ATIScreenInfo(pScreenPriv); #endif /* USE_DRI && GLXEXT */ ATICardInfo(pScreenPriv); ATIUnmapReg(pScreenPriv->card, atic); atic->backend_funcs.disable(pScreen); } static void ATIGetColors(ScreenPtr pScreen, int fb, int n, xColorItem *pdefs) { KdScreenPriv(pScreen); ATICardInfo(pScreenPriv); atic->backend_funcs.getColors(pScreen, fb, n, pdefs); } static void ATIPutColors(ScreenPtr pScreen, int fb, int n, xColorItem *pdefs) { KdScreenPriv(pScreen); ATICardInfo(pScreenPriv); atic->backend_funcs.putColors(pScreen, fb, n, pdefs); } /* Compute log base 2 of val. */ int ATILog2(int val) { int bits; for (bits = 0; val != 0; val >>= 1, ++bits) ; return bits - 1; } static Bool ATIIsAGP(ATICardInfo *atic) { char *mmio = atic->reg_base; CARD32 cap_ptr, cap_id; if (mmio == NULL) return FALSE; if (MMIO_IN32(mmio, ATI_REG_PCI_CFG_STATUS) & ATI_CAP_LIST) { cap_ptr = MMIO_IN32(mmio, ATI_REG_PCI_CFG_CAPABILITIES_PTR) & ATI_CAP_PTR_MASK; while (cap_ptr != ATI_CAP_ID_NULL) { cap_id = MMIO_IN32(mmio, ATI_PCI_CFG_OFFSET + cap_ptr); if ((cap_id & 0xff) == ATI_CAP_ID_AGP) return TRUE; cap_ptr = (cap_id >> 8) & ATI_CAP_PTR_MASK; } } return FALSE; } /* This function is required to work around a hardware bug in some (all?) * revisions of the R300. This workaround should be called after every * CLOCK_CNTL_INDEX register access. If not, register reads afterward * may not be correct. */ void R300CGWorkaround(ATIScreenInfo *atis) { ATICardInfo *atic = atis->atic; char *mmio = atic->reg_base; CARD32 save; save = MMIO_IN32(mmio, ATI_REG_CLOCK_CNTL_INDEX); MMIO_OUT32(mmio, ATI_REG_CLOCK_CNTL_INDEX, save & ~(0x3f | ATI_PLL_WR_EN)); MMIO_IN32(mmio, ATI_REG_CLOCK_CNTL_INDEX); MMIO_OUT32(mmio, ATI_REG_CLOCK_CNTL_INDEX, save); } KdCardFuncs ATIFuncs = { ATICardInit, /* cardinit */ ATIScreenInit, /* scrinit */ ATIInitScreen, /* initScreen */ ATIFinishInitScreen, /* finishInitScreen */ ATICreateResources, /* createRes */ ATIPreserve, /* preserve */ ATIEnable, /* enable */ ATIDPMS, /* dpms */ ATIDisable, /* disable */ ATIRestore, /* restore */ ATIScreenFini, /* scrfini */ ATICardFini, /* cardfini */ ATICursorInit, /* initCursor */ ATICursorEnable, /* enableCursor */ ATICursorDisable, /* disableCursor */ ATICursorFini, /* finiCursor */ ATIRecolorCursor, /* recolorCursor */ ATIDrawInit, /* initAccel */ ATIDrawEnable, /* enableAccel */ ATIDrawDisable, /* disableAccel */ ATIDrawFini, /* finiAccel */ ATIGetColors, /* getColors */ ATIPutColors, /* putColors */ };