/* * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and * VA Linux Systems Inc., Fremont, California. * * All Rights Reserved. * * 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 on 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 (including the * next paragraph) 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 * NON-INFRINGEMENT. IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR * THEIR SUPPLIERS 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. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* * Authors: * Kevin E. Martin * Rickard E. Faith * Alan Hourihane * * Credits: * * Thanks to Ani Joshi for providing source * code to his Radeon driver. Portions of this file are based on the * initialization code for that driver. * * References: * * !!!! FIXME !!!! * RAGE 128 VR/ RAGE 128 GL Register Reference Manual (Technical * Reference Manual P/N RRG-G04100-C Rev. 0.04), ATI Technologies: April * 1999. * * RAGE 128 Software Development Manual (Technical Reference Manual P/N * SDK-G04000 Rev. 0.01), ATI Technologies: June 1999. * * This server does not yet support these XFree86 4.0 features: * !!!! FIXME !!!! * DDC1 & DDC2 * shadowfb * overlay planes * * Modified by Marc Aurele La France (tsi@xfree86.org) for ATI driver merge. * * Mergedfb and pseudo xinerama support added by Alex Deucher (agd5f@yahoo.com) * based on the sis driver by Thomas Winischhofer. * */ #include #include /* Driver data structures */ #include "radeon.h" #include "radeon_reg.h" #include "radeon_macros.h" #include "radeon_probe.h" #include "radeon_version.h" #include "radeon_atombios.h" #ifdef XF86DRI #define _XF86DRI_SERVER_ #include "radeon_dri.h" #include "radeon_drm.h" #include "sarea.h" #endif #include "fb.h" /* colormap initialization */ #include "micmap.h" #include "dixstruct.h" /* X and server generic header files */ #include "xf86.h" #include "xf86_OSproc.h" #include "xf86RandR12.h" #if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 6 #include "xf86RAC.h" #include "xf86Resources.h" #endif #include "xf86cmap.h" #include "vbe.h" #include "shadow.h" /* vgaHW definitions */ #ifdef WITH_VGAHW #include "vgaHW.h" #endif #ifdef HAVE_XEXTPROTO_71 #include #else #define DPMS_SERVER #include #endif #include "atipciids.h" #include "radeon_chipset_gen.h" #include "radeon_chipinfo_gen.h" /* Forward definitions for driver functions */ static Bool RADEONCloseScreen(int scrnIndex, ScreenPtr pScreen); static Bool RADEONSaveScreen(ScreenPtr pScreen, int mode); static void RADEONSave(ScrnInfoPtr pScrn); static void RADEONSaveMemMapRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save); static void RADEONSaveBIOSRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save); #ifdef XF86DRI static void RADEONAdjustMemMapRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save); #endif static const OptionInfoRec RADEONOptions[] = { { OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_DAC_6BIT, "Dac6Bit", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_DAC_8BIT, "Dac8Bit", OPTV_BOOLEAN, {0}, TRUE }, #ifdef XF86DRI { OPTION_BUS_TYPE, "BusType", OPTV_ANYSTR, {0}, FALSE }, { OPTION_CP_PIO, "CPPIOMode", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_USEC_TIMEOUT, "CPusecTimeout", OPTV_INTEGER, {0}, FALSE }, { OPTION_AGP_MODE, "AGPMode", OPTV_INTEGER, {0}, FALSE }, { OPTION_AGP_FW, "AGPFastWrite", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_GART_SIZE_OLD, "AGPSize", OPTV_INTEGER, {0}, FALSE }, { OPTION_GART_SIZE, "GARTSize", OPTV_INTEGER, {0}, FALSE }, { OPTION_RING_SIZE, "RingSize", OPTV_INTEGER, {0}, FALSE }, { OPTION_BUFFER_SIZE, "BufferSize", OPTV_INTEGER, {0}, FALSE }, { OPTION_DEPTH_MOVE, "EnableDepthMoves", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_PAGE_FLIP, "EnablePageFlip", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_NO_BACKBUFFER, "NoBackBuffer", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_XV_DMA, "DMAForXv", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_FBTEX_PERCENT, "FBTexPercent", OPTV_INTEGER, {0}, FALSE }, { OPTION_DEPTH_BITS, "DepthBits", OPTV_INTEGER, {0}, FALSE }, { OPTION_PCIAPER_SIZE, "PCIAPERSize", OPTV_INTEGER, {0}, FALSE }, #ifdef USE_EXA { OPTION_ACCEL_DFS, "AccelDFS", OPTV_BOOLEAN, {0}, FALSE }, #endif #endif { OPTION_IGNORE_EDID, "IgnoreEDID", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_CUSTOM_EDID, "CustomEDID", OPTV_ANYSTR, {0}, FALSE }, { OPTION_DISP_PRIORITY, "DisplayPriority", OPTV_ANYSTR, {0}, FALSE }, { OPTION_PANEL_SIZE, "PanelSize", OPTV_ANYSTR, {0}, FALSE }, { OPTION_MIN_DOTCLOCK, "ForceMinDotClock", OPTV_FREQ, {0}, FALSE }, { OPTION_COLOR_TILING, "ColorTiling", OPTV_BOOLEAN, {0}, FALSE }, #ifdef XvExtension { OPTION_VIDEO_KEY, "VideoKey", OPTV_INTEGER, {0}, FALSE }, { OPTION_RAGE_THEATRE_CRYSTAL, "RageTheatreCrystal", OPTV_INTEGER, {0}, FALSE }, { OPTION_RAGE_THEATRE_TUNER_PORT, "RageTheatreTunerPort", OPTV_INTEGER, {0}, FALSE }, { OPTION_RAGE_THEATRE_COMPOSITE_PORT, "RageTheatreCompositePort", OPTV_INTEGER, {0}, FALSE }, { OPTION_RAGE_THEATRE_SVIDEO_PORT, "RageTheatreSVideoPort", OPTV_INTEGER, {0}, FALSE }, { OPTION_TUNER_TYPE, "TunerType", OPTV_INTEGER, {0}, FALSE }, { OPTION_RAGE_THEATRE_MICROC_PATH, "RageTheatreMicrocPath", OPTV_STRING, {0}, FALSE }, { OPTION_RAGE_THEATRE_MICROC_TYPE, "RageTheatreMicrocType", OPTV_STRING, {0}, FALSE }, { OPTION_SCALER_WIDTH, "ScalerWidth", OPTV_INTEGER, {0}, FALSE }, #endif #ifdef RENDER { OPTION_RENDER_ACCEL, "RenderAccel", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_SUBPIXEL_ORDER, "SubPixelOrder", OPTV_ANYSTR, {0}, FALSE }, #endif { OPTION_CLOCK_GATING, "ClockGating", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_VGA_ACCESS, "VGAAccess", OPTV_BOOLEAN, {0}, TRUE }, { OPTION_REVERSE_DDC, "ReverseDDC", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_LVDS_PROBE_PLL, "LVDSProbePLL", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_ACCELMETHOD, "AccelMethod", OPTV_STRING, {0}, FALSE }, { OPTION_DRI, "DRI", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_CONNECTORTABLE, "ConnectorTable", OPTV_STRING, {0}, FALSE }, { OPTION_DEFAULT_CONNECTOR_TABLE, "DefaultConnectorTable", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_DEFAULT_TMDS_PLL, "DefaultTMDSPLL", OPTV_BOOLEAN, {0}, FALSE }, #if defined(__powerpc__) { OPTION_MAC_MODEL, "MacModel", OPTV_STRING, {0}, FALSE }, #endif { OPTION_TVDAC_LOAD_DETECT, "TVDACLoadDetect", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_FORCE_TVOUT, "ForceTVOut", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_TVSTD, "TVStandard", OPTV_STRING, {0}, FALSE }, { OPTION_IGNORE_LID_STATUS, "IgnoreLidStatus", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_DEFAULT_TVDAC_ADJ, "DefaultTVDACAdj", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_INT10, "Int10", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_EXA_VSYNC, "EXAVSync", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_ATOM_TVOUT, "ATOMTVOut", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_R4XX_ATOM, "R4xxATOM", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_FORCE_LOW_POWER, "ForceLowPowerMode", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_DYNAMIC_PM, "DynamicPM", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_NEW_PLL, "NewPLL", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_ZAPHOD_HEADS, "ZaphodHeads", OPTV_STRING, {0}, FALSE }, { -1, NULL, OPTV_NONE, {0}, FALSE } }; const OptionInfoRec *RADEONOptionsWeak(void) { return RADEONOptions; } extern _X_EXPORT int gRADEONEntityIndex; static int getRADEONEntityIndex(void) { return gRADEONEntityIndex; } struct RADEONInt10Save { uint32_t MEM_CNTL; uint32_t MEMSIZE; uint32_t MPP_TB_CONFIG; }; static Bool RADEONMapMMIO(ScrnInfoPtr pScrn); static Bool RADEONUnmapMMIO(ScrnInfoPtr pScrn); static void * radeonShadowWindow(ScreenPtr screen, CARD32 row, CARD32 offset, int mode, CARD32 *size, void *closure) { ScrnInfoPtr pScrn = xf86Screens[screen->myNum]; RADEONInfoPtr info = RADEONPTR(pScrn); int stride; stride = (pScrn->displayWidth * pScrn->bitsPerPixel) / 8; *size = stride; return ((uint8_t *)info->FB + pScrn->fbOffset + row * stride + offset); } static Bool RADEONCreateScreenResources (ScreenPtr pScreen) { ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; RADEONInfoPtr info = RADEONPTR(pScrn); PixmapPtr pixmap; pScreen->CreateScreenResources = info->CreateScreenResources; if (!(*pScreen->CreateScreenResources)(pScreen)) return FALSE; pScreen->CreateScreenResources = RADEONCreateScreenResources; if (info->r600_shadow_fb) { pixmap = pScreen->GetScreenPixmap(pScreen); if (!shadowAdd(pScreen, pixmap, shadowUpdatePackedWeak(), radeonShadowWindow, 0, NULL)) return FALSE; } return TRUE; } RADEONEntPtr RADEONEntPriv(ScrnInfoPtr pScrn) { DevUnion *pPriv; RADEONInfoPtr info = RADEONPTR(pScrn); pPriv = xf86GetEntityPrivate(info->pEnt->index, getRADEONEntityIndex()); return pPriv->ptr; } static void RADEONPreInt10Save(ScrnInfoPtr pScrn, void **pPtr) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; uint32_t CardTmp; static struct RADEONInt10Save SaveStruct = { 0, 0, 0 }; if (!IS_AVIVO_VARIANT) { /* Save the values and zap MEM_CNTL */ SaveStruct.MEM_CNTL = INREG(RADEON_MEM_CNTL); SaveStruct.MEMSIZE = INREG(RADEON_CONFIG_MEMSIZE); SaveStruct.MPP_TB_CONFIG = INREG(RADEON_MPP_TB_CONFIG); /* * Zap MEM_CNTL and set MPP_TB_CONFIG<31:24> to 4 */ OUTREG(RADEON_MEM_CNTL, 0); CardTmp = SaveStruct.MPP_TB_CONFIG & 0x00ffffffu; CardTmp |= 0x04 << 24; OUTREG(RADEON_MPP_TB_CONFIG, CardTmp); } *pPtr = (void *)&SaveStruct; } static void RADEONPostInt10Check(ScrnInfoPtr pScrn, void *ptr) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; struct RADEONInt10Save *pSave = ptr; uint32_t CardTmp; /* If we don't have a valid (non-zero) saved MEM_CNTL, get out now */ if (!pSave || !pSave->MEM_CNTL) return; if (IS_AVIVO_VARIANT) return; /* * If either MEM_CNTL is currently zero or inconistent (configured for * two channels with the two channels configured differently), restore * the saved registers. */ CardTmp = INREG(RADEON_MEM_CNTL); if (!CardTmp || ((CardTmp & 1) && (((CardTmp >> 8) & 0xff) != ((CardTmp >> 24) & 0xff)))) { /* Restore the saved registers */ xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Restoring MEM_CNTL (%08lx), setting to %08lx\n", (unsigned long)CardTmp, (unsigned long)pSave->MEM_CNTL); OUTREG(RADEON_MEM_CNTL, pSave->MEM_CNTL); CardTmp = INREG(RADEON_CONFIG_MEMSIZE); if (CardTmp != pSave->MEMSIZE) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Restoring CONFIG_MEMSIZE (%08lx), setting to %08lx\n", (unsigned long)CardTmp, (unsigned long)pSave->MEMSIZE); OUTREG(RADEON_CONFIG_MEMSIZE, pSave->MEMSIZE); } } CardTmp = INREG(RADEON_MPP_TB_CONFIG); if ((CardTmp & 0xff000000u) != (pSave->MPP_TB_CONFIG & 0xff000000u)) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Restoring MPP_TB_CONFIG<31:24> (%02lx), setting to %02lx\n", (unsigned long)CardTmp >> 24, (unsigned long)pSave->MPP_TB_CONFIG >> 24); CardTmp &= 0x00ffffffu; CardTmp |= (pSave->MPP_TB_CONFIG & 0xff000000u); OUTREG(RADEON_MPP_TB_CONFIG, CardTmp); } } /* Allocate our private RADEONInfoRec */ Bool RADEONGetRec(ScrnInfoPtr pScrn) { if (pScrn->driverPrivate) return TRUE; pScrn->driverPrivate = xnfcalloc(sizeof(RADEONInfoRec), 1); return TRUE; } /* Free our private RADEONInfoRec */ void RADEONFreeRec(ScrnInfoPtr pScrn) { RADEONInfoPtr info; int i; if (!pScrn || !pScrn->driverPrivate) return; info = RADEONPTR(pScrn); if (info->cp) { free(info->cp); info->cp = NULL; } if (info->dri) { free(info->dri); info->dri = NULL; } if (info->accel_state) { free(info->accel_state); info->accel_state = NULL; } for (i = 0; i < RADEON_MAX_BIOS_CONNECTOR; i++) { if (info->encoders[i]) { if (info->encoders[i]->dev_priv) { free(info->encoders[i]->dev_priv); info->encoders[i]->dev_priv = NULL; } free(info->encoders[i]); info->encoders[i]= NULL; } } free(pScrn->driverPrivate); pScrn->driverPrivate = NULL; } /* Memory map the MMIO region. Used during pre-init and by RADEONMapMem, * below */ static Bool RADEONMapMMIO(ScrnInfoPtr pScrn) { #ifdef XSERVER_LIBPCIACCESS int err; #endif RADEONInfoPtr info = RADEONPTR(pScrn); RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); if (pRADEONEnt->MMIO) { pRADEONEnt->MMIO_cnt++; info->MMIO = pRADEONEnt->MMIO; return TRUE; } #ifndef XSERVER_LIBPCIACCESS info->MMIO = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO | VIDMEM_READSIDEEFFECT, info->PciTag, info->MMIOAddr, info->MMIOSize); if (!info->MMIO) return FALSE; #else err = pci_device_map_range(info->PciInfo, info->MMIOAddr, info->MMIOSize, PCI_DEV_MAP_FLAG_WRITABLE, &info->MMIO); if (err) { xf86DrvMsg (pScrn->scrnIndex, X_ERROR, "Unable to map MMIO aperture. %s (%d)\n", strerror (err), err); return FALSE; } #endif pRADEONEnt->MMIO = info->MMIO; pRADEONEnt->MMIO_cnt = 1; return TRUE; } /* Unmap the MMIO region. Used during pre-init and by RADEONUnmapMem, * below */ static Bool RADEONUnmapMMIO(ScrnInfoPtr pScrn) { RADEONInfoPtr info = RADEONPTR(pScrn); RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); /* refcount for zaphod */ if (--pRADEONEnt->MMIO_cnt != 0) { info->MMIO = NULL; return TRUE; } #ifndef XSERVER_LIBPCIACCESS xf86UnMapVidMem(pScrn->scrnIndex, info->MMIO, info->MMIOSize); #else pci_device_unmap_range(info->PciInfo, info->MMIO, info->MMIOSize); #endif pRADEONEnt->MMIO = NULL; info->MMIO = NULL; return TRUE; } /* Memory map the frame buffer. Used by RADEONMapMem, below. */ static Bool RADEONMapFB(ScrnInfoPtr pScrn) { #ifdef XSERVER_LIBPCIACCESS int err; #endif RADEONInfoPtr info = RADEONPTR(pScrn); RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); if (pRADEONEnt->FB) { pRADEONEnt->FB_cnt++; info->FB = pRADEONEnt->FB; return TRUE; } xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "Map: 0x%016llx, 0x%08lx\n", info->LinearAddr, info->FbMapSize); #ifndef XSERVER_LIBPCIACCESS info->FB = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER, info->PciTag, info->LinearAddr, info->FbMapSize); if (!info->FB) return FALSE; #else err = pci_device_map_range(info->PciInfo, info->LinearAddr, info->FbMapSize, PCI_DEV_MAP_FLAG_WRITABLE | PCI_DEV_MAP_FLAG_WRITE_COMBINE, &info->FB); if (err) { xf86DrvMsg (pScrn->scrnIndex, X_ERROR, "Unable to map FB aperture. %s (%d)\n", strerror (err), err); return FALSE; } #endif pRADEONEnt->FB = info->FB; pRADEONEnt->FB_cnt = 1; return TRUE; } /* Unmap the frame buffer. Used by RADEONUnmapMem, below. */ static Bool RADEONUnmapFB(ScrnInfoPtr pScrn) { RADEONInfoPtr info = RADEONPTR(pScrn); RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); /* refcount for zaphod */ if (--pRADEONEnt->FB_cnt != 0) { info->FB = NULL; return TRUE; } #ifndef XSERVER_LIBPCIACCESS xf86UnMapVidMem(pScrn->scrnIndex, info->FB, info->FbMapSize); #else pci_device_unmap_range(info->PciInfo, info->FB, info->FbMapSize); #endif pRADEONEnt->FB = NULL; info->FB = NULL; return TRUE; } /* Memory map the MMIO region and the frame buffer */ static Bool RADEONMapMem(ScrnInfoPtr pScrn) { if (!RADEONMapMMIO(pScrn)) return FALSE; if (!RADEONMapFB(pScrn)) { RADEONUnmapMMIO(pScrn); return FALSE; } return TRUE; } /* Unmap the MMIO region and the frame buffer */ static Bool RADEONUnmapMem(ScrnInfoPtr pScrn) { if (!RADEONUnmapMMIO(pScrn) || !RADEONUnmapFB(pScrn)) return FALSE; return TRUE; } void RADEONPllErrataAfterIndex(RADEONInfoPtr info) { unsigned char *RADEONMMIO = info->MMIO; if (!(info->ChipErrata & CHIP_ERRATA_PLL_DUMMYREADS)) return; /* This workaround is necessary on rv200 and RS200 or PLL * reads may return garbage (among others...) */ (void)INREG(RADEON_CLOCK_CNTL_DATA); (void)INREG(RADEON_CRTC_GEN_CNTL); } void RADEONPllErrataAfterData(RADEONInfoPtr info) { unsigned char *RADEONMMIO = info->MMIO; /* This workarounds is necessary on RV100, RS100 and RS200 chips * or the chip could hang on a subsequent access */ if (info->ChipErrata & CHIP_ERRATA_PLL_DELAY) { /* we can't deal with posted writes here ... */ usleep(5000); } /* This function is required to workaround 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. */ if (info->ChipErrata & CHIP_ERRATA_R300_CG) { uint32_t save, tmp; save = INREG(RADEON_CLOCK_CNTL_INDEX); tmp = save & ~(0x3f | RADEON_PLL_WR_EN); OUTREG(RADEON_CLOCK_CNTL_INDEX, tmp); tmp = INREG(RADEON_CLOCK_CNTL_DATA); OUTREG(RADEON_CLOCK_CNTL_INDEX, save); } } /* Read PLL register */ unsigned RADEONINPLL(ScrnInfoPtr pScrn, int addr) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; uint32_t data; OUTREG8(RADEON_CLOCK_CNTL_INDEX, addr & 0x3f); RADEONPllErrataAfterIndex(info); data = INREG(RADEON_CLOCK_CNTL_DATA); RADEONPllErrataAfterData(info); return data; } /* Write PLL information */ void RADEONOUTPLL(ScrnInfoPtr pScrn, int addr, uint32_t data) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; OUTREG8(RADEON_CLOCK_CNTL_INDEX, (((addr) & 0x3f) | RADEON_PLL_WR_EN)); RADEONPllErrataAfterIndex(info); OUTREG(RADEON_CLOCK_CNTL_DATA, data); RADEONPllErrataAfterData(info); } /* Read MC register */ unsigned RADEONINMC(ScrnInfoPtr pScrn, int addr) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; uint32_t data; if ((info->ChipFamily == CHIP_FAMILY_RS690) || (info->ChipFamily == CHIP_FAMILY_RS740)) { OUTREG(RS690_MC_INDEX, (addr & RS690_MC_INDEX_MASK)); data = INREG(RS690_MC_DATA); } else if (info->ChipFamily == CHIP_FAMILY_RS600) { OUTREG(RS600_MC_INDEX, ((addr & RS600_MC_ADDR_MASK) | RS600_MC_IND_CITF_ARB0)); data = INREG(RS600_MC_DATA); } else if ((info->ChipFamily == CHIP_FAMILY_RS780) || (info->ChipFamily == CHIP_FAMILY_RS880)) { OUTREG(RS780_MC_INDEX, (addr & RS780_MC_INDEX_MASK)); data = INREG(RS780_MC_DATA); } else if (info->ChipFamily >= CHIP_FAMILY_R600) { data = 0; } else if (IS_AVIVO_VARIANT) { OUTREG(AVIVO_MC_INDEX, (addr & 0xff) | 0x7f0000); (void)INREG(AVIVO_MC_INDEX); data = INREG(AVIVO_MC_DATA); OUTREG(AVIVO_MC_INDEX, 0); (void)INREG(AVIVO_MC_INDEX); } else { OUTREG(R300_MC_IND_INDEX, addr & 0x3f); (void)INREG(R300_MC_IND_INDEX); data = INREG(R300_MC_IND_DATA); OUTREG(R300_MC_IND_INDEX, 0); (void)INREG(R300_MC_IND_INDEX); } return data; } /* Write MC information */ void RADEONOUTMC(ScrnInfoPtr pScrn, int addr, uint32_t data) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; if ((info->ChipFamily == CHIP_FAMILY_RS690) || (info->ChipFamily == CHIP_FAMILY_RS740)) { OUTREG(RS690_MC_INDEX, ((addr & RS690_MC_INDEX_MASK) | RS690_MC_INDEX_WR_EN)); OUTREG(RS690_MC_DATA, data); OUTREG(RS690_MC_INDEX, RS690_MC_INDEX_WR_ACK); } else if (info->ChipFamily == CHIP_FAMILY_RS600) { OUTREG(RS600_MC_INDEX, ((addr & RS600_MC_ADDR_MASK) | RS600_MC_IND_CITF_ARB0 | RS600_MC_IND_WR_EN)); OUTREG(RS600_MC_DATA, data); } else if ((info->ChipFamily == CHIP_FAMILY_RS780) || (info->ChipFamily == CHIP_FAMILY_RS880)) { OUTREG(RS780_MC_INDEX, ((addr & RS780_MC_INDEX_MASK) | RS780_MC_INDEX_WR_EN)); OUTREG(RS780_MC_DATA, data); } else if (info->ChipFamily >= CHIP_FAMILY_R600) { // do nothing } else if (IS_AVIVO_VARIANT) { OUTREG(AVIVO_MC_INDEX, (addr & 0xff) | 0xff0000); (void)INREG(AVIVO_MC_INDEX); OUTREG(AVIVO_MC_DATA, data); OUTREG(AVIVO_MC_INDEX, 0); (void)INREG(AVIVO_MC_INDEX); } else { OUTREG(R300_MC_IND_INDEX, (((addr) & 0x3f) | R300_MC_IND_WR_EN)); (void)INREG(R300_MC_IND_INDEX); OUTREG(R300_MC_IND_DATA, data); OUTREG(R300_MC_IND_INDEX, 0); (void)INREG(R300_MC_IND_INDEX); } } /* Read PCIE register */ unsigned RADEONINPCIE(ScrnInfoPtr pScrn, int addr) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; CARD32 data; OUTREG(RADEON_PCIE_INDEX, addr & 0xff); data = INREG(RADEON_PCIE_DATA); return data; } /* Write PCIE register */ void RADEONOUTPCIE(ScrnInfoPtr pScrn, int addr, uint32_t data) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; OUTREG(RADEON_PCIE_INDEX, ((addr) & 0xff)); OUTREG(RADEON_PCIE_DATA, data); } /* Read PCIE PORT register */ unsigned R600INPCIE_PORT(ScrnInfoPtr pScrn, int addr) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; CARD32 data; OUTREG(R600_PCIE_PORT_INDEX, addr & 0xff); data = INREG(R600_PCIE_PORT_DATA); return data; } /* Write PCIE PORT register */ void R600OUTPCIE_PORT(ScrnInfoPtr pScrn, int addr, uint32_t data) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; OUTREG(R600_PCIE_PORT_INDEX, ((addr) & 0xff)); OUTREG(R600_PCIE_PORT_DATA, data); } static Bool radeon_get_mc_idle(ScrnInfoPtr pScrn) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; if (info->ChipFamily >= CHIP_FAMILY_CEDAR) { if (INREG(R600_SRBM_STATUS) & 0x1f00) return FALSE; else return TRUE; } else if (info->ChipFamily >= CHIP_FAMILY_R600) { if (INREG(R600_SRBM_STATUS) & 0x3f00) return FALSE; else return TRUE; } else if (info->ChipFamily == CHIP_FAMILY_RV515) { if (INMC(pScrn, RV515_MC_STATUS) & RV515_MC_STATUS_IDLE) return TRUE; else return FALSE; } else if (info->ChipFamily == CHIP_FAMILY_RS600) { if (INMC(pScrn, RS600_MC_STATUS) & RS600_MC_IDLE) return TRUE; else return FALSE; } else if ((info->ChipFamily == CHIP_FAMILY_RS690) || (info->ChipFamily == CHIP_FAMILY_RS740)) { if (INMC(pScrn, RS690_MC_STATUS) & RS690_MC_STATUS_IDLE) return TRUE; else return FALSE; } else if (info->ChipFamily >= CHIP_FAMILY_R520) { if (INMC(pScrn, R520_MC_STATUS) & R520_MC_STATUS_IDLE) return TRUE; else return FALSE; } else if ((info->ChipFamily == CHIP_FAMILY_RS400) || (info->ChipFamily == CHIP_FAMILY_RS480)) { if (INREG(RADEON_MC_STATUS) & RADEON_MC_IDLE) return TRUE; else return FALSE; } else if (IS_R300_VARIANT) { if (INREG(RADEON_MC_STATUS) & R300_MC_IDLE) return TRUE; else return FALSE; } else { if (INREG(RADEON_MC_STATUS) & RADEON_MC_IDLE) return TRUE; else return FALSE; } } #define LOC_FB 0x1 #define LOC_AGP 0x2 static void radeon_write_mc_fb_agp_location(ScrnInfoPtr pScrn, int mask, uint32_t fb_loc, uint32_t agp_loc, uint32_t agp_loc_hi) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; /* evergreen is same as r7xx */ if (info->ChipFamily >= CHIP_FAMILY_RV770) { if (mask & LOC_FB) OUTREG(R700_MC_VM_FB_LOCATION, fb_loc); if (mask & LOC_AGP) { OUTREG(R700_MC_VM_AGP_BOT, agp_loc); OUTREG(R700_MC_VM_AGP_TOP, agp_loc_hi); } } else if (info->ChipFamily >= CHIP_FAMILY_R600) { if (mask & LOC_FB) OUTREG(R600_MC_VM_FB_LOCATION, fb_loc); if (mask & LOC_AGP) { OUTREG(R600_MC_VM_AGP_BOT, agp_loc); OUTREG(R600_MC_VM_AGP_TOP, agp_loc_hi); } } else if (info->ChipFamily == CHIP_FAMILY_RV515) { if (mask & LOC_FB) OUTMC(pScrn, RV515_MC_FB_LOCATION, fb_loc); if (mask & LOC_AGP) OUTMC(pScrn, RV515_MC_AGP_LOCATION, agp_loc); (void)INMC(pScrn, RV515_MC_AGP_LOCATION); } else if (info->ChipFamily == CHIP_FAMILY_RS600) { if (mask & LOC_FB) OUTMC(pScrn, RS600_MC_FB_LOCATION, fb_loc); if (mask & LOC_AGP) OUTMC(pScrn, RS600_MC_AGP_LOCATION, agp_loc); } else if ((info->ChipFamily == CHIP_FAMILY_RS690) || (info->ChipFamily == CHIP_FAMILY_RS740)) { if (mask & LOC_FB) OUTMC(pScrn, RS690_MC_FB_LOCATION, fb_loc); if (mask & LOC_AGP) OUTMC(pScrn, RS690_MC_AGP_LOCATION, agp_loc); } else if (info->ChipFamily >= CHIP_FAMILY_R520) { if (mask & LOC_FB) OUTMC(pScrn, R520_MC_FB_LOCATION, fb_loc); if (mask & LOC_AGP) OUTMC(pScrn, R520_MC_AGP_LOCATION, agp_loc); (void)INMC(pScrn, R520_MC_FB_LOCATION); } else { if (mask & LOC_FB) OUTREG(RADEON_MC_FB_LOCATION, fb_loc); if (mask & LOC_AGP) OUTREG(RADEON_MC_AGP_LOCATION, agp_loc); } } static void radeon_read_mc_fb_agp_location(ScrnInfoPtr pScrn, int mask, uint32_t *fb_loc, uint32_t *agp_loc, uint32_t *agp_loc_hi) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; /* evergreen is same as r7xx */ if (info->ChipFamily >= CHIP_FAMILY_RV770) { if (mask & LOC_FB) *fb_loc = INREG(R700_MC_VM_FB_LOCATION); if (mask & LOC_AGP) { *agp_loc = INREG(R700_MC_VM_AGP_BOT); *agp_loc_hi = INREG(R700_MC_VM_AGP_TOP); } } else if (info->ChipFamily >= CHIP_FAMILY_R600) { if (mask & LOC_FB) *fb_loc = INREG(R600_MC_VM_FB_LOCATION); if (mask & LOC_AGP) { *agp_loc = INREG(R600_MC_VM_AGP_BOT); *agp_loc_hi = INREG(R600_MC_VM_AGP_TOP); } } else if (info->ChipFamily == CHIP_FAMILY_RV515) { if (mask & LOC_FB) *fb_loc = INMC(pScrn, RV515_MC_FB_LOCATION); if (mask & LOC_AGP) { *agp_loc = INMC(pScrn, RV515_MC_AGP_LOCATION); *agp_loc_hi = 0; } } else if (info->ChipFamily == CHIP_FAMILY_RS600) { if (mask & LOC_FB) *fb_loc = INMC(pScrn, RS600_MC_FB_LOCATION); if (mask & LOC_AGP) { *agp_loc = INMC(pScrn, RS600_MC_AGP_LOCATION); *agp_loc_hi = 0; } } else if ((info->ChipFamily == CHIP_FAMILY_RS690) || (info->ChipFamily == CHIP_FAMILY_RS740)) { if (mask & LOC_FB) *fb_loc = INMC(pScrn, RS690_MC_FB_LOCATION); if (mask & LOC_AGP) { *agp_loc = INMC(pScrn, RS690_MC_AGP_LOCATION); *agp_loc_hi = 0; } } else if (info->ChipFamily >= CHIP_FAMILY_R520) { if (mask & LOC_FB) *fb_loc = INMC(pScrn, R520_MC_FB_LOCATION); if (mask & LOC_AGP) { *agp_loc = INMC(pScrn, R520_MC_AGP_LOCATION); *agp_loc_hi = 0; } } else { if (mask & LOC_FB) *fb_loc = INREG(RADEON_MC_FB_LOCATION); if (mask & LOC_AGP) *agp_loc = INREG(RADEON_MC_AGP_LOCATION); } } #if 0 /* Read PAL information (only used for debugging) */ static int RADEONINPAL(int idx) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; OUTREG(RADEON_PALETTE_INDEX, idx << 16); return INREG(RADEON_PALETTE_DATA); } #endif /* Wait for vertical sync on primary CRTC */ void RADEONWaitForVerticalSync(ScrnInfoPtr pScrn) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; uint32_t crtc_gen_cntl; struct timeval timeout; crtc_gen_cntl = INREG(RADEON_CRTC_GEN_CNTL); if ((crtc_gen_cntl & RADEON_CRTC_DISP_REQ_EN_B) || !(crtc_gen_cntl & RADEON_CRTC_EN)) return; /* Clear the CRTC_VBLANK_SAVE bit */ OUTREG(RADEON_CRTC_STATUS, RADEON_CRTC_VBLANK_SAVE_CLEAR); /* Wait for it to go back up */ radeon_init_timeout(&timeout, RADEON_VSYNC_TIMEOUT); while (!(INREG(RADEON_CRTC_STATUS) & RADEON_CRTC_VBLANK_SAVE) && !radeon_timedout(&timeout)) usleep(100); } /* Wait for vertical sync on secondary CRTC */ void RADEONWaitForVerticalSync2(ScrnInfoPtr pScrn) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; uint32_t crtc2_gen_cntl; struct timeval timeout; crtc2_gen_cntl = INREG(RADEON_CRTC2_GEN_CNTL); if ((crtc2_gen_cntl & RADEON_CRTC2_DISP_REQ_EN_B) || !(crtc2_gen_cntl & RADEON_CRTC2_EN)) return; /* Clear the CRTC2_VBLANK_SAVE bit */ OUTREG(RADEON_CRTC2_STATUS, RADEON_CRTC2_VBLANK_SAVE_CLEAR); /* Wait for it to go back up */ radeon_init_timeout(&timeout, RADEON_VSYNC_TIMEOUT); while (!(INREG(RADEON_CRTC2_STATUS) & RADEON_CRTC2_VBLANK_SAVE) && !radeon_timedout(&timeout)) usleep(100); } /* Compute log base 2 of val */ int RADEONMinBits(int val) { int bits; if (!val) return 1; for (bits = 0; val; val >>= 1, ++bits); return bits; } /* Compute n/d with rounding */ static int RADEONDiv(int n, int d) { return (n + (d / 2)) / d; } static Bool RADEONProbePLLParameters(ScrnInfoPtr pScrn) { RADEONInfoPtr info = RADEONPTR(pScrn); RADEONPLLPtr pll = &info->pll; unsigned char *RADEONMMIO = info->MMIO; unsigned char ppll_div_sel; unsigned mpll_fb_div, spll_fb_div, M; unsigned xclk, tmp, ref_div; int hTotal, vTotal, num, denom, m, n; float hz, prev_xtal, vclk, xtal, mpll, spll; long total_usecs; struct timeval start, stop, to1, to2; unsigned int f1, f2, f3; int tries = 0; prev_xtal = 0; again: xtal = 0; if (++tries > 10) goto failed; gettimeofday(&to1, NULL); f1 = INREG(RADEON_CRTC_CRNT_FRAME); for (;;) { f2 = INREG(RADEON_CRTC_CRNT_FRAME); if (f1 != f2) break; gettimeofday(&to2, NULL); if ((to2.tv_sec - to1.tv_sec) > 1) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Clock not counting...\n"); goto failed; } } gettimeofday(&start, NULL); for(;;) { f3 = INREG(RADEON_CRTC_CRNT_FRAME); if (f3 != f2) break; gettimeofday(&to2, NULL); if ((to2.tv_sec - start.tv_sec) > 1) goto failed; } gettimeofday(&stop, NULL); if ((stop.tv_sec - start.tv_sec) != 0) goto again; total_usecs = abs(stop.tv_usec - start.tv_usec); if (total_usecs == 0) goto again; hz = 1000000.0/(float)total_usecs; hTotal = ((INREG(RADEON_CRTC_H_TOTAL_DISP) & 0x3ff) + 1) * 8; vTotal = ((INREG(RADEON_CRTC_V_TOTAL_DISP) & 0xfff) + 1); vclk = (float)(hTotal * (float)(vTotal * hz)); switch((INPLL(pScrn, RADEON_PPLL_REF_DIV) & 0x30000) >> 16) { case 0: default: num = 1; denom = 1; break; case 1: n = ((INPLL(pScrn, RADEON_X_MPLL_REF_FB_DIV) >> 16) & 0xff); m = (INPLL(pScrn, RADEON_X_MPLL_REF_FB_DIV) & 0xff); num = 2*n; denom = 2*m; break; case 2: n = ((INPLL(pScrn, RADEON_X_MPLL_REF_FB_DIV) >> 8) & 0xff); m = (INPLL(pScrn, RADEON_X_MPLL_REF_FB_DIV) & 0xff); num = 2*n; denom = 2*m; break; } ppll_div_sel = INREG8(RADEON_CLOCK_CNTL_INDEX + 1) & 0x3; RADEONPllErrataAfterIndex(info); n = (INPLL(pScrn, RADEON_PPLL_DIV_0 + ppll_div_sel) & 0x7ff); m = (INPLL(pScrn, RADEON_PPLL_REF_DIV) & 0x3ff); num *= n; denom *= m; switch ((INPLL(pScrn, RADEON_PPLL_DIV_0 + ppll_div_sel) >> 16) & 0x7) { case 1: denom *= 2; break; case 2: denom *= 4; break; case 3: denom *= 8; break; case 4: denom *= 3; break; case 6: denom *= 6; break; case 7: denom *= 12; break; } xtal = (int)(vclk *(float)denom/(float)num); if ((xtal > 26900000) && (xtal < 27100000)) xtal = 2700; else if ((xtal > 14200000) && (xtal < 14400000)) xtal = 1432; else if ((xtal > 29400000) && (xtal < 29600000)) xtal = 2950; else goto again; failed: if (xtal == 0) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Failed to probe xtal value ! " "Using default 27Mhz\n"); xtal = 2700; } else { if (prev_xtal == 0) { prev_xtal = xtal; tries = 0; goto again; } else if (prev_xtal != xtal) { prev_xtal = 0; goto again; } } tmp = INPLL(pScrn, RADEON_X_MPLL_REF_FB_DIV); ref_div = INPLL(pScrn, RADEON_PPLL_REF_DIV) & 0x3ff; /* Some sanity check based on the BIOS code .... */ if (ref_div < 2) { uint32_t tmp; tmp = INPLL(pScrn, RADEON_PPLL_REF_DIV); if (IS_R300_VARIANT || (info->ChipFamily == CHIP_FAMILY_RS300) || (info->ChipFamily == CHIP_FAMILY_RS400) || (info->ChipFamily == CHIP_FAMILY_RS480)) ref_div = (tmp & R300_PPLL_REF_DIV_ACC_MASK) >> R300_PPLL_REF_DIV_ACC_SHIFT; else ref_div = tmp & RADEON_PPLL_REF_DIV_MASK; if (ref_div < 2) ref_div = 12; } /* Calculate "base" xclk straight from MPLL, though that isn't * really useful (hopefully). This isn't called XCLK anymore on * radeon's... */ mpll_fb_div = (tmp & 0xff00) >> 8; spll_fb_div = (tmp & 0xff0000) >> 16; M = (tmp & 0xff); xclk = RADEONDiv((2 * mpll_fb_div * xtal), (M)); /* * Calculate MCLK based on MCLK-A */ mpll = (2.0 * (float)mpll_fb_div * (xtal / 100.0)) / (float)M; spll = (2.0 * (float)spll_fb_div * (xtal / 100.0)) / (float)M; tmp = INPLL(pScrn, RADEON_MCLK_CNTL) & 0x7; switch(tmp) { case 1: info->mclk = mpll; break; case 2: info->mclk = mpll / 2.0; break; case 3: info->mclk = mpll / 4.0; break; case 4: info->mclk = mpll / 8.0; break; case 7: info->mclk = spll; break; default: info->mclk = 200.00; xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Unsupported MCLKA source" " setting %d, can't probe MCLK value !\n", tmp); } /* * Calculate SCLK */ tmp = INPLL(pScrn, RADEON_SCLK_CNTL) & 0x7; switch(tmp) { case 1: info->sclk = spll; break; case 2: info->sclk = spll / 2.0; break; case 3: info->sclk = spll / 4.0; break; case 4: info->sclk = spll / 8.0; break; case 7: info->sclk = mpll; break; default: info->sclk = 200.00; xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Unsupported SCLK source" " setting %d, can't probe SCLK value !\n", tmp); } /* we're done, hopefully these are sane values */ pll->reference_div = ref_div; pll->xclk = xclk; pll->reference_freq = xtal; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Probed PLL values: xtal: %f Mhz, " "sclk: %f Mhz, mclk: %f Mhz\n", xtal/100.0, info->sclk, info->mclk); return TRUE; } static void RADEONGetClockInfo(ScrnInfoPtr pScrn) { RADEONInfoPtr info = RADEONPTR (pScrn); RADEONPLLPtr pll = &info->pll; double min_dotclock; if (RADEONGetClockInfoFromBIOS(pScrn)) { if (pll->reference_div < 2) { /* retrive it from register setting for fitting into current PLL algorithm. We'll probably need a new routine to calculate the best ref_div from BIOS provided min_input_pll and max_input_pll */ if (!IS_AVIVO_VARIANT) { uint32_t tmp; tmp = INPLL(pScrn, RADEON_PPLL_REF_DIV); if (IS_R300_VARIANT || (info->ChipFamily == CHIP_FAMILY_RS300) || (info->ChipFamily == CHIP_FAMILY_RS400) || (info->ChipFamily == CHIP_FAMILY_RS480)) { pll->reference_div = (tmp & R300_PPLL_REF_DIV_ACC_MASK) >> R300_PPLL_REF_DIV_ACC_SHIFT; } else { pll->reference_div = tmp & RADEON_PPLL_REF_DIV_MASK; } } if (pll->reference_div < 2) pll->reference_div = 12; } } else { xf86DrvMsg (pScrn->scrnIndex, X_WARNING, "Video BIOS not detected, using default clock settings!\n"); /* Default min/max PLL values */ if (info->ChipFamily == CHIP_FAMILY_R420 || info->ChipFamily == CHIP_FAMILY_RV410) { pll->pll_in_min = 100; pll->pll_in_max = 1350; pll->pll_out_min = 20000; pll->pll_out_max = 50000; } else { pll->pll_in_min = 40; pll->pll_in_max = 500; pll->pll_out_min = 12500; pll->pll_out_max = 35000; } if (!RADEONProbePLLParameters(pScrn)) { if (info->IsIGP) pll->reference_freq = 1432; else pll->reference_freq = 2700; pll->reference_div = 12; pll->xclk = 10300; info->sclk = 200.00; info->mclk = 200.00; } } /* card limits for computing PLLs */ if (IS_AVIVO_VARIANT) { pll->min_post_div = 2; pll->max_post_div = 0x7f; pll->min_frac_feedback_div = 0; pll->max_frac_feedback_div = 9; } else { pll->min_post_div = 1; pll->max_post_div = 12; //16 on crtc0 pll->min_frac_feedback_div = 0; pll->max_frac_feedback_div = 0; } pll->min_ref_div = 2; pll->max_ref_div = 0x3ff; pll->min_feedback_div = 4; pll->max_feedback_div = 0x7ff; pll->best_vco = 0; xf86DrvMsg (pScrn->scrnIndex, X_INFO, "PLL parameters: rf=%u rd=%u min=%u max=%u; xclk=%u\n", pll->reference_freq, pll->reference_div, (unsigned)pll->pll_out_min, (unsigned)pll->pll_out_max, pll->xclk); /* (Some?) Radeon BIOSes seem too lie about their minimum dot * clocks. Allow users to override the detected minimum dot clock * value (e.g., and allow it to be suitable for TV sets). */ if (xf86GetOptValFreq(info->Options, OPTION_MIN_DOTCLOCK, OPTUNITS_MHZ, &min_dotclock)) { if (min_dotclock < 12 || min_dotclock*100 >= pll->pll_out_max) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Illegal minimum dotclock specified %.2f MHz " "(option ignored)\n", min_dotclock); } else { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Forced minimum dotclock to %.2f MHz " "(instead of detected %.2f MHz)\n", min_dotclock, ((double)pll->pll_out_min/1000)); pll->pll_out_min = min_dotclock * 1000; } } } /* This is called by RADEONPreInit to set up the default visual */ Bool RADEONPreInitVisual(ScrnInfoPtr pScrn) { RADEONInfoPtr info = RADEONPTR(pScrn); if (!xf86SetDepthBpp(pScrn, 0, 0, 0, Support32bppFb)) return FALSE; switch (pScrn->depth) { case 8: case 15: case 16: case 24: break; default: xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Given depth (%d) is not supported by %s driver\n", pScrn->depth, RADEON_DRIVER_NAME); return FALSE; } xf86PrintDepthBpp(pScrn); info->pix24bpp = xf86GetBppFromDepth(pScrn, pScrn->depth); info->CurrentLayout.bitsPerPixel = pScrn->bitsPerPixel; info->CurrentLayout.depth = pScrn->depth; info->CurrentLayout.pixel_bytes = pScrn->bitsPerPixel / 8; info->CurrentLayout.pixel_code = (pScrn->bitsPerPixel != 16 ? pScrn->bitsPerPixel : pScrn->depth); if (info->pix24bpp == 24) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Radeon does NOT support 24bpp\n"); return FALSE; } xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Pixel depth = %d bits stored in %d byte%s (%d bpp pixmaps)\n", pScrn->depth, info->CurrentLayout.pixel_bytes, info->CurrentLayout.pixel_bytes > 1 ? "s" : "", info->pix24bpp); if (!xf86SetDefaultVisual(pScrn, -1)) return FALSE; if (pScrn->depth > 8 && pScrn->defaultVisual != TrueColor) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Default visual (%s) is not supported at depth %d\n", xf86GetVisualName(pScrn->defaultVisual), pScrn->depth); return FALSE; } return TRUE; } /* This is called by RADEONPreInit to handle all color weight issues */ Bool RADEONPreInitWeight(ScrnInfoPtr pScrn) { RADEONInfoPtr info = RADEONPTR(pScrn); /* Save flag for 6 bit DAC to use for setting CRTC registers. Otherwise use an 8 bit DAC, even if xf86SetWeight sets pScrn->rgbBits to some value other than 8. */ info->dac6bits = FALSE; if (pScrn->depth > 8) { rgb defaultWeight = { 0, 0, 0 }; if (!xf86SetWeight(pScrn, defaultWeight, defaultWeight)) return FALSE; } else { pScrn->rgbBits = 8; if (xf86ReturnOptValBool(info->Options, OPTION_DAC_6BIT, FALSE)) { pScrn->rgbBits = 6; info->dac6bits = TRUE; } } xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using %d bits per RGB (%d bit DAC)\n", pScrn->rgbBits, info->dac6bits ? 6 : 8); return TRUE; } void RADEONInitMemMapRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save, RADEONInfoPtr info) { save->mc_fb_location = info->mc_fb_location; save->mc_agp_location = info->mc_agp_location; if (IS_AVIVO_VARIANT) { save->mc_agp_location_hi = info->mc_agp_location_hi; } else { save->display_base_addr = info->fbLocation; save->display2_base_addr = info->fbLocation; save->ov0_base_addr = info->fbLocation; } } static void RADEONInitMemoryMap(ScrnInfoPtr pScrn) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; uint64_t mem_size; uint64_t aper_size; radeon_read_mc_fb_agp_location(pScrn, LOC_FB | LOC_AGP, &info->mc_fb_location, &info->mc_agp_location, &info->mc_agp_location_hi); /* We shouldn't use info->videoRam here which might have been clipped * but the real video RAM instead */ if (info->ChipFamily >= CHIP_FAMILY_PALM) { /* size in bytes on fusion */ mem_size = INREG(R600_CONFIG_MEMSIZE); /* size in MB on fusion */ aper_size = INREG(R600_CONFIG_APER_SIZE) * 1024 * 1024; } else if (info->ChipFamily >= CHIP_FAMILY_CEDAR) { /* size in MB on evergreen */ /* XXX watch for overflow!!! */ mem_size = INREG(R600_CONFIG_MEMSIZE) * 1024 * 1024; aper_size = INREG(R600_CONFIG_APER_SIZE) * 1024 * 1024; } else if (info->ChipFamily >= CHIP_FAMILY_R600) { mem_size = INREG(R600_CONFIG_MEMSIZE); aper_size = INREG(R600_CONFIG_APER_SIZE); } else { mem_size = INREG(RADEON_CONFIG_MEMSIZE); aper_size = INREG(RADEON_CONFIG_APER_SIZE); } if (mem_size == 0) mem_size = 0x800000; /* Fix for RN50, M6, M7 with 8/16/32(??) MBs of VRAM - Novell bug 204882 + along with lots of ubuntu ones */ if (aper_size > mem_size) mem_size = aper_size; /* don't map the whole FB in the internal address space. * we don't currently use fb space larger than the aperture * size and on cards with more than 512 MB of vram, this can overflow * the internal top of gart calculation on some systems. * Limit it to cards with more than 512 MB as this causes problems * on some other cards due to the way the ddx and drm set up the * internal memory map. * See fdo bug 24301. */ if (mem_size > 0x20000000) mem_size = aper_size; #ifdef XF86DRI /* Apply memory map limitation if using an old DRI */ if (info->directRenderingEnabled && !info->dri->newMemoryMap) { if (aper_size < mem_size) mem_size = aper_size; } #endif if ((info->ChipFamily != CHIP_FAMILY_RS600) && (info->ChipFamily != CHIP_FAMILY_RS690) && (info->ChipFamily != CHIP_FAMILY_RS740) && (info->ChipFamily != CHIP_FAMILY_RS780) && (info->ChipFamily != CHIP_FAMILY_RS880) && (info->ChipFamily != CHIP_FAMILY_PALM)) { if (info->IsIGP) info->mc_fb_location = INREG(RADEON_NB_TOM); else #ifdef XF86DRI /* Old DRI has restrictions on the memory map */ if ( info->directRenderingEnabled && info->dri->pKernelDRMVersion->version_minor < 10 ) info->mc_fb_location = (mem_size - 1) & 0xffff0000U; else #endif { uint64_t aper0_base; if (info->ChipFamily >= CHIP_FAMILY_R600) { aper0_base = INREG(R600_CONFIG_F0_BASE); } else { aper0_base = INREG(RADEON_CONFIG_APER_0_BASE); } /* Recent chips have an "issue" with the memory controller, the * location must be aligned to the size. We just align it down, * too bad if we walk over the top of system memory, we don't * use DMA without a remapped anyway. * Affected chips are rv280, all r3xx, and all r4xx, but not IGP */ if (info->ChipFamily == CHIP_FAMILY_RV280 || info->ChipFamily == CHIP_FAMILY_R300 || info->ChipFamily == CHIP_FAMILY_R350 || info->ChipFamily == CHIP_FAMILY_RV350 || info->ChipFamily == CHIP_FAMILY_RV380 || info->ChipFamily == CHIP_FAMILY_R420 || info->ChipFamily == CHIP_FAMILY_RV410) aper0_base &= ~(mem_size - 1); if (info->ChipFamily >= CHIP_FAMILY_R600) { uint64_t mc_fb = ((aper0_base >> 24) & 0xffff) | (((aper0_base + mem_size - 1) >> 8) & 0xffff0000); info->mc_fb_location = mc_fb & 0xffffffff; ErrorF("mc fb loc is %08x\n", (unsigned int)info->mc_fb_location); } else { uint64_t mc_fb = ((aper0_base >> 16) & 0xffff) | ((aper0_base + mem_size - 1) & 0xffff0000U); info->mc_fb_location = mc_fb & 0xffffffff; } } } if (info->ChipFamily >= CHIP_FAMILY_R600) { info->fbLocation = ((uint64_t)info->mc_fb_location & 0xffff) << 24; } else { info->fbLocation = ((uint64_t)info->mc_fb_location & 0xffff) << 16; } /* Just disable the damn AGP apertures for now, it may be * re-enabled later by the DRM */ if (IS_AVIVO_VARIANT) info->mc_agp_location = 0x003f0000; else info->mc_agp_location = 0xffffffc0; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "RADEONInitMemoryMap() : \n"); xf86DrvMsg(pScrn->scrnIndex, X_INFO, " mem_size : 0x%08x\n", (unsigned)mem_size); xf86DrvMsg(pScrn->scrnIndex, X_INFO, " MC_FB_LOCATION : 0x%08x\n", (unsigned)info->mc_fb_location); xf86DrvMsg(pScrn->scrnIndex, X_INFO, " MC_AGP_LOCATION : 0x%08x\n", (unsigned)info->mc_agp_location); } static void RADEONGetVRamType(ScrnInfoPtr pScrn) { RADEONInfoPtr info = RADEONPTR(pScrn); RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); unsigned char *RADEONMMIO = info->MMIO; uint32_t tmp; if (info->IsIGP || (info->ChipFamily >= CHIP_FAMILY_R300)) info->IsDDR = TRUE; else if (INREG(RADEON_MEM_SDRAM_MODE_REG) & RADEON_MEM_CFG_TYPE_DDR) info->IsDDR = TRUE; else info->IsDDR = FALSE; if ((info->ChipFamily >= CHIP_FAMILY_R600) && (info->ChipFamily <= CHIP_FAMILY_RV635)) { int chansize; /* r6xx */ tmp = INREG(R600_RAMCFG); if (tmp & R600_CHANSIZE_OVERRIDE) chansize = 16; else if (tmp & R600_CHANSIZE) chansize = 64; else chansize = 32; if (info->ChipFamily == CHIP_FAMILY_R600) info->RamWidth = 8 * chansize; else if (info->ChipFamily == CHIP_FAMILY_RV670) info->RamWidth = 4 * chansize; else if ((info->ChipFamily == CHIP_FAMILY_RV610) || (info->ChipFamily == CHIP_FAMILY_RV620)) info->RamWidth = chansize; else if ((info->ChipFamily == CHIP_FAMILY_RV630) || (info->ChipFamily == CHIP_FAMILY_RV635)) info->RamWidth = 2 * chansize; } else if (info->ChipFamily == CHIP_FAMILY_RV515) { /* rv515/rv550 */ tmp = INMC(pScrn, RV515_MC_CNTL); tmp &= RV515_MEM_NUM_CHANNELS_MASK; switch (tmp) { case 0: info->RamWidth = 64; break; case 1: info->RamWidth = 128; break; default: info->RamWidth = 128; break; } } else if ((info->ChipFamily >= CHIP_FAMILY_R520) && (info->ChipFamily <= CHIP_FAMILY_RV570)){ /* r520/rv530/rv560/rv570/r580 */ tmp = INMC(pScrn, R520_MC_CNTL0); switch ((tmp & R520_MEM_NUM_CHANNELS_MASK) >> R520_MEM_NUM_CHANNELS_SHIFT) { case 0: info->RamWidth = 32; break; case 1: info->RamWidth = 64; break; case 2: info->RamWidth = 128; break; case 3: info->RamWidth = 256; break; default: info->RamWidth = 64; break; } if (tmp & R520_MC_CHANNEL_SIZE) { info->RamWidth *= 2; } } else if ((info->ChipFamily >= CHIP_FAMILY_R300) && (info->ChipFamily <= CHIP_FAMILY_RV410)) { /* r3xx, r4xx */ tmp = INREG(RADEON_MEM_CNTL); tmp &= R300_MEM_NUM_CHANNELS_MASK; switch (tmp) { case 0: info->RamWidth = 64; break; case 1: info->RamWidth = 128; break; case 2: info->RamWidth = 256; break; default: info->RamWidth = 128; break; } } else if ((info->ChipFamily == CHIP_FAMILY_RV100) || (info->ChipFamily == CHIP_FAMILY_RS100) || (info->ChipFamily == CHIP_FAMILY_RS200)){ tmp = INREG(RADEON_MEM_CNTL); if (tmp & RV100_HALF_MODE) info->RamWidth = 32; else info->RamWidth = 64; if (!pRADEONEnt->HasCRTC2) { info->RamWidth /= 4; info->IsDDR = TRUE; } } else if (info->ChipFamily <= CHIP_FAMILY_RV280) { tmp = INREG(RADEON_MEM_CNTL); if (tmp & RADEON_MEM_NUM_CHANNELS_MASK) info->RamWidth = 128; else info->RamWidth = 64; } else { /* newer IGPs */ info->RamWidth = 128; } /* This may not be correct, as some cards can have half of channel disabled * ToDo: identify these cases */ } /* * Depending on card genertation, chipset bugs, etc... the amount of vram * accessible to the CPU can vary. This function is our best shot at figuring * it out. Returns a value in KB. */ static uint32_t RADEONGetAccessibleVRAM(ScrnInfoPtr pScrn) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; uint32_t aper_size; unsigned char byte; if (info->ChipFamily >= CHIP_FAMILY_CEDAR) /* size in MB on evergreen and fusion */ aper_size = INREG(R600_CONFIG_APER_SIZE) * 1024; else if (info->ChipFamily >= CHIP_FAMILY_R600) aper_size = INREG(R600_CONFIG_APER_SIZE) / 1024; else aper_size = INREG(RADEON_CONFIG_APER_SIZE) / 1024; #ifdef XF86DRI /* If we use the DRI, we need to check if it's a version that has the * bug of always cropping MC_FB_LOCATION to one aperture, in which case * we need to limit the amount of accessible video memory */ if (info->directRenderingEnabled && info->dri->pKernelDRMVersion->version_minor < 23) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "[dri] limiting video memory to one aperture of %uK\n", (unsigned)aper_size); xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "[dri] detected radeon kernel module version 1.%d but" " 1.23 or newer is required for full memory mapping.\n", info->dri->pKernelDRMVersion->version_minor); info->dri->newMemoryMap = FALSE; return aper_size; } info->dri->newMemoryMap = TRUE; #endif /* XF86DRI */ if (info->ChipFamily >= CHIP_FAMILY_R600) return aper_size; /* Set HDP_APER_CNTL only on cards that are known not to be broken, * that is has the 2nd generation multifunction PCI interface */ if (info->ChipFamily == CHIP_FAMILY_RV280 || info->ChipFamily == CHIP_FAMILY_RV350 || info->ChipFamily == CHIP_FAMILY_RV380 || info->ChipFamily == CHIP_FAMILY_R420 || info->ChipFamily == CHIP_FAMILY_RV410 || IS_AVIVO_VARIANT) { OUTREGP (RADEON_HOST_PATH_CNTL, RADEON_HDP_APER_CNTL, ~RADEON_HDP_APER_CNTL); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Generation 2 PCI interface, using max accessible memory\n"); return aper_size * 2; } /* Older cards have all sorts of funny issues to deal with. First * check if it's a multifunction card by reading the PCI config * header type... Limit those to one aperture size */ PCI_READ_BYTE(info->PciInfo, &byte, 0xe); if (byte & 0x80) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Generation 1 PCI interface in multifunction mode" ", accessible memory limited to one aperture\n"); return aper_size; } /* Single function older card. We read HDP_APER_CNTL to see how the BIOS * have set it up. We don't write this as it's broken on some ASICs but * we expect the BIOS to have done the right thing (might be too optimistic...) */ if (INREG(RADEON_HOST_PATH_CNTL) & RADEON_HDP_APER_CNTL) return aper_size * 2; return aper_size; } static Bool RADEONPreInitVRAM(ScrnInfoPtr pScrn) { RADEONInfoPtr info = RADEONPTR(pScrn); EntityInfoPtr pEnt = info->pEnt; GDevPtr dev = pEnt->device; unsigned char *RADEONMMIO = info->MMIO; MessageType from = X_PROBED; uint32_t accessible, bar_size; if ((!IS_AVIVO_VARIANT) && info->IsIGP) { uint32_t tom = INREG(RADEON_NB_TOM); pScrn->videoRam = (((tom >> 16) - (tom & 0xffff) + 1) << 6); OUTREG(RADEON_CONFIG_MEMSIZE, pScrn->videoRam * 1024); } else { if (info->ChipFamily >= CHIP_FAMILY_PALM) /* R600_CONFIG_MEMSIZE is bytes on fusion */ pScrn->videoRam = INREG(R600_CONFIG_MEMSIZE) / 1024; else if (info->ChipFamily >= CHIP_FAMILY_CEDAR) /* R600_CONFIG_MEMSIZE is MB on evergreen */ /* XXX watch for overflow!!! */ pScrn->videoRam = INREG(R600_CONFIG_MEMSIZE) * 1024; else if (info->ChipFamily >= CHIP_FAMILY_R600) pScrn->videoRam = INREG(R600_CONFIG_MEMSIZE) / 1024; else { /* Read VRAM size from card */ pScrn->videoRam = INREG(RADEON_CONFIG_MEMSIZE) / 1024; /* Some production boards of m6 will return 0 if it's 8 MB */ if (pScrn->videoRam == 0) { pScrn->videoRam = 8192; OUTREG(RADEON_CONFIG_MEMSIZE, 0x800000); } } } /* Get accessible memory */ accessible = RADEONGetAccessibleVRAM(pScrn); /* Crop it to the size of the PCI BAR */ bar_size = PCI_REGION_SIZE(info->PciInfo, 0) / 1024; if (bar_size == 0) bar_size = 0x20000; if (accessible > bar_size) accessible = bar_size; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Detected total video RAM=%dK, accessible=%uK (PCI BAR=%uK)\n", pScrn->videoRam, (unsigned)accessible, (unsigned)bar_size); if (pScrn->videoRam > accessible) pScrn->videoRam = accessible; if (!IS_AVIVO_VARIANT) { info->MemCntl = INREG(RADEON_SDRAM_MODE_REG); info->BusCntl = INREG(RADEON_BUS_CNTL); } RADEONGetVRamType(pScrn); if (dev->videoRam) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Video RAM override, using %d kB instead of %d kB\n", dev->videoRam, pScrn->videoRam); from = X_CONFIG; pScrn->videoRam = dev->videoRam; } xf86DrvMsg(pScrn->scrnIndex, from, "Mapped VideoRAM: %d kByte (%d bit %s SDRAM)\n", pScrn->videoRam, info->RamWidth, info->IsDDR?"DDR":"SDR"); /* Do this before we truncate since we only map fb once */ info->FbMapSize = (pScrn->videoRam & ~1023) * 1024; if (info->IsPrimary) { pScrn->videoRam /= 2; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using %dk of videoram for primary head\n", pScrn->videoRam); } else if (info->IsSecondary) { pScrn->videoRam /= 2; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using %dk of videoram for secondary head\n", pScrn->videoRam); } pScrn->videoRam &= ~1023; /* if the card is PCI Express reserve the last 32k for the gart table */ #ifdef XF86DRI if (info->cardType == CARD_PCIE && info->directRenderingEnabled) /* work out the size of pcie aperture */ info->FbSecureSize = RADEONDRIGetPciAperTableSize(pScrn); else #endif info->FbSecureSize = 0; return TRUE; } /* This is called by RADEONPreInit to handle config file overrides for * things like chipset and memory regions. Also determine memory size * and type. If memory type ever needs an override, put it in this * routine. */ static Bool RADEONPreInitChipType(ScrnInfoPtr pScrn) { RADEONInfoPtr info = RADEONPTR(pScrn); RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); EntityInfoPtr pEnt = info->pEnt; GDevPtr dev = pEnt->device; unsigned char *RADEONMMIO = info->MMIO; MessageType from = X_PROBED; int i; #ifdef XF86DRI const char *s; uint32_t cmd_stat; #endif /* Chipset */ from = X_PROBED; if (dev->chipset && *dev->chipset) { info->Chipset = xf86StringToToken(RADEONChipsets, dev->chipset); from = X_CONFIG; } else if (dev->chipID >= 0) { info->Chipset = dev->chipID; from = X_CONFIG; } else { info->Chipset = PCI_DEV_DEVICE_ID(info->PciInfo); } pScrn->chipset = (char *)xf86TokenToString(RADEONChipsets, info->Chipset); if (!pScrn->chipset) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "ChipID 0x%04x is not recognized\n", info->Chipset); return FALSE; } if (info->Chipset < 0) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Chipset \"%s\" is not recognized\n", pScrn->chipset); return FALSE; } xf86DrvMsg(pScrn->scrnIndex, from, "Chipset: \"%s\" (ChipID = 0x%04x)\n", pScrn->chipset, info->Chipset); pRADEONEnt->HasCRTC2 = TRUE; info->IsMobility = FALSE; info->IsIGP = FALSE; info->IsDellServer = FALSE; info->HasSingleDAC = FALSE; info->InternalTVOut = TRUE; info->get_hardcoded_edid_from_bios = FALSE; for (i = 0; i < sizeof(RADEONCards) / sizeof(RADEONCardInfo); i++) { if (info->Chipset == RADEONCards[i].pci_device_id) { RADEONCardInfo *card = &RADEONCards[i]; info->ChipFamily = card->chip_family; info->IsMobility = card->mobility; info->IsIGP = card->igp; pRADEONEnt->HasCRTC2 = !card->nocrtc2; info->HasSingleDAC = card->singledac; info->InternalTVOut = !card->nointtvout; break; } } if (IS_DCE5_VARIANT) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Chipset: \"%s\" (ChipID = 0x%04x) requires KMS\n", pScrn->chipset, info->Chipset); return FALSE; } switch (info->Chipset) { case PCI_CHIP_RN50_515E: /* RN50 is based on the RV100 but 3D isn't guaranteed to work. YMMV. */ case PCI_CHIP_RN50_5969: /* Some Sun servers have a hardcoded edid so KVMs work properly */ if ((PCI_SUB_VENDOR_ID(info->PciInfo) == 0x108e) && (PCI_SUB_DEVICE_ID(info->PciInfo) == 0x4133)) info->get_hardcoded_edid_from_bios = TRUE; case PCI_CHIP_RV100_QY: case PCI_CHIP_RV100_QZ: /* DELL triple-head configuration. */ if (((PCI_SUB_VENDOR_ID(info->PciInfo) == PCI_VENDOR_DELL) && ((PCI_SUB_DEVICE_ID(info->PciInfo) == 0x016c) || (PCI_SUB_DEVICE_ID(info->PciInfo) == 0x016d) || (PCI_SUB_DEVICE_ID(info->PciInfo) == 0x016e) || (PCI_SUB_DEVICE_ID(info->PciInfo) == 0x016f) || (PCI_SUB_DEVICE_ID(info->PciInfo) == 0x0170) || (PCI_SUB_DEVICE_ID(info->PciInfo) == 0x017d) || (PCI_SUB_DEVICE_ID(info->PciInfo) == 0x017e) || (PCI_SUB_DEVICE_ID(info->PciInfo) == 0x0183) || (PCI_SUB_DEVICE_ID(info->PciInfo) == 0x018a) || (PCI_SUB_DEVICE_ID(info->PciInfo) == 0x019a) || (PCI_SUB_DEVICE_ID(info->PciInfo) == 0x01b1) || (PCI_SUB_DEVICE_ID(info->PciInfo) == 0x01b2) || (PCI_SUB_DEVICE_ID(info->PciInfo) == 0x0205))) || ((PCI_SUB_VENDOR_ID(info->PciInfo) == PCI_VENDOR_HP) && (PCI_SUB_DEVICE_ID(info->PciInfo) == 0x31fb))) { info->IsDellServer = TRUE; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "DELL/HP server detected, force to special setup\n"); } break; case PCI_CHIP_RS482_5974: /* RH BZ 444586 - non mobility version * Dell appear to have the Vostro 1100 with a mobility part with the same pci-id */ if ((PCI_SUB_VENDOR_ID(info->PciInfo) == 0x1462) && (PCI_SUB_DEVICE_ID(info->PciInfo) == 0x7141)) { info->IsMobility = FALSE; } default: break; } from = X_PROBED; info->LinearAddr = PCI_REGION_BASE(info->PciInfo, 0, REGION_MEM) & ~0x1ffffffULL; pScrn->memPhysBase = info->LinearAddr; if (dev->MemBase) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Linear address override, using 0x%016lx instead of 0x%016llx\n", dev->MemBase, info->LinearAddr); info->LinearAddr = dev->MemBase; from = X_CONFIG; } else if (!info->LinearAddr) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid linear framebuffer address\n"); return FALSE; } xf86DrvMsg(pScrn->scrnIndex, from, "Linear framebuffer at 0x%016llx\n", info->LinearAddr); #ifndef XSERVER_LIBPCIACCESS /* BIOS */ from = X_PROBED; info->BIOSAddr = info->PciInfo->biosBase & 0xfffe0000; if (info->BIOSAddr) { xf86DrvMsg(pScrn->scrnIndex, from, "BIOS at 0x%08lx\n", (unsigned long)info->BIOSAddr); } #endif /* Read registers used to determine options */ /* Check chip errata */ info->ChipErrata = 0; if (info->ChipFamily == CHIP_FAMILY_R300 && (INREG(RADEON_CONFIG_CNTL) & RADEON_CFG_ATI_REV_ID_MASK) == RADEON_CFG_ATI_REV_A11) info->ChipErrata |= CHIP_ERRATA_R300_CG; if (info->ChipFamily == CHIP_FAMILY_RV200 || info->ChipFamily == CHIP_FAMILY_RS200) info->ChipErrata |= CHIP_ERRATA_PLL_DUMMYREADS; if (info->ChipFamily == CHIP_FAMILY_RV100 || info->ChipFamily == CHIP_FAMILY_RS100 || info->ChipFamily == CHIP_FAMILY_RS200) info->ChipErrata |= CHIP_ERRATA_PLL_DELAY; #ifdef XF86DRI /* AGP/PCI */ /* Proper autodetection of an AGP capable device requires examining * PCI config registers to determine if the device implements extended * PCI capabilities, and then walking the capability list as indicated * in the PCI 2.2 and AGP 2.0 specifications, to determine if AGP * capability is present. The procedure is outlined as follows: * * 1) Test bit 4 (CAP_LIST) of the PCI status register of the device * to determine wether or not this device implements any extended * capabilities. If this bit is zero, then the device is a PCI 2.1 * or earlier device and is not AGP capable, and we can conclude it * to be a PCI device. * * 2) If bit 4 of the status register is set, then the device implements * extended capabilities. There is an 8 bit wide capabilities pointer * register located at offset 0x34 in PCI config space which points to * the first capability in a linked list of extended capabilities that * this device implements. The lower two bits of this register are * reserved and MBZ so must be masked out. * * 3) The extended capabilities list is formed by one or more extended * capabilities structures which are aligned on DWORD boundaries. * The first byte of the structure is the capability ID (CAP_ID) * indicating what extended capability this structure refers to. The * second byte of the structure is an offset from the beginning of * PCI config space pointing to the next capability in the linked * list (NEXT_PTR) or NULL (0x00) at the end of the list. The lower * two bits of this pointer are reserved and MBZ. By examining the * CAP_ID of each capability and walking through the list, we will * either find the AGP_CAP_ID (0x02) indicating this device is an * AGP device, or we'll reach the end of the list, indicating it is * a PCI device. * * Mike A. Harris * * References: * - PCI Local Bus Specification Revision 2.2, Chapter 6 * - AGP Interface Specification Revision 2.0, Section 6.1.5 */ info->cardType = CARD_PCI; PCI_READ_LONG(info->PciInfo, &cmd_stat, PCI_CMD_STAT_REG); if (cmd_stat & RADEON_CAP_LIST) { uint32_t cap_ptr, cap_id; PCI_READ_LONG(info->PciInfo, &cap_ptr, RADEON_CAPABILITIES_PTR_PCI_CONFIG); cap_ptr &= RADEON_CAP_PTR_MASK; while(cap_ptr != RADEON_CAP_ID_NULL) { PCI_READ_LONG(info->PciInfo, &cap_id, cap_ptr); if ((cap_id & 0xff)== RADEON_CAP_ID_AGP) { info->cardType = CARD_AGP; break; } if ((cap_id & 0xff)== RADEON_CAP_ID_EXP) { info->cardType = CARD_PCIE; break; } cap_ptr = (cap_id >> 8) & RADEON_CAP_PTR_MASK; } } xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s card detected\n", (info->cardType==CARD_PCI) ? "PCI" : (info->cardType==CARD_PCIE) ? "PCIE" : "AGP"); /* treat PCIE IGP cards as PCI */ if (info->cardType == CARD_PCIE && info->IsIGP) info->cardType = CARD_PCI; /* some rs4xx cards report as agp */ if ((info->ChipFamily == CHIP_FAMILY_RS400) || (info->ChipFamily == CHIP_FAMILY_RS480)) info->cardType = CARD_PCI; if ((info->ChipFamily >= CHIP_FAMILY_R600) && info->IsIGP) info->cardType = CARD_PCIE; /* not sure about gart table requirements */ if ((info->ChipFamily == CHIP_FAMILY_RS600) && info->IsIGP) info->cardType = CARD_PCIE; if ((s = xf86GetOptValString(info->Options, OPTION_BUS_TYPE))) { if (strcmp(s, "AGP") == 0) { info->cardType = CARD_AGP; xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Forced into AGP mode\n"); } else if ((strcmp(s, "PCI") == 0) || (strcmp(s, "PCIE") == 0)) { if ((info->ChipFamily == CHIP_FAMILY_RS400) || (info->ChipFamily == CHIP_FAMILY_RS480) || (info->ChipFamily == CHIP_FAMILY_RS690) || (info->ChipFamily == CHIP_FAMILY_RS740)) { info->cardType = CARD_PCI; xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Forced into PCI mode\n"); } else if (info->ChipFamily >= CHIP_FAMILY_RV380) { info->cardType = CARD_PCIE; xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Forced into PCI Express mode\n"); } else { info->cardType = CARD_PCI; xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Forced into PCI mode\n"); } } else { xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Invalid BusType option, using detected type\n"); } } #endif #ifdef RENDER info->RenderAccel = xf86ReturnOptValBool(info->Options, OPTION_RENDER_ACCEL, info->Chipset != PCI_CHIP_RN50_515E && info->Chipset != PCI_CHIP_RN50_5969); #endif info->r4xx_atom = FALSE; if (((info->ChipFamily == CHIP_FAMILY_R420) || (info->ChipFamily == CHIP_FAMILY_RV410)) && xf86ReturnOptValBool(info->Options, OPTION_R4XX_ATOM, FALSE)) { info->r4xx_atom = TRUE; xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Using ATOMBIOS for R4xx chip\n"); } return TRUE; } static void RADEONPreInitDDC(ScrnInfoPtr pScrn) { RADEONInfoPtr info = RADEONPTR(pScrn); /* vbeInfoPtr pVbe; */ info->ddc1 = FALSE; info->ddc_bios = FALSE; if (!xf86LoadSubModule(pScrn, "ddc")) { info->ddc2 = FALSE; } else { info->ddc2 = TRUE; } /* DDC can use I2C bus */ /* Load I2C if we have the code to use it */ if (info->ddc2) { xf86LoadSubModule(pScrn, "i2c"); } } /* This is called by RADEONPreInit to initialize gamma correction */ static Bool RADEONPreInitGamma(ScrnInfoPtr pScrn) { Gamma zeros = { 0.0, 0.0, 0.0 }; if (!xf86SetGamma(pScrn, zeros)) return FALSE; return TRUE; } /* This is called by RADEONPreInit to initialize the hardware cursor */ static Bool RADEONPreInitCursor(ScrnInfoPtr pScrn) { RADEONInfoPtr info = RADEONPTR(pScrn); if (!xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE)) { if (!xf86LoadSubModule(pScrn, "ramdac")) return FALSE; } return TRUE; } /* This is called by RADEONPreInit to initialize hardware acceleration */ static Bool RADEONPreInitAccel(ScrnInfoPtr pScrn) { RADEONInfoPtr info = RADEONPTR(pScrn); MessageType from; #if defined(USE_EXA) && defined(USE_XAA) char *optstr; #endif #ifdef XF86DRI /* zaphod FbMapSize is wrong, but no dri then */ int maxy = info->FbMapSize / (pScrn->displayWidth * info->CurrentLayout.pixel_bytes); #endif if (!(info->accel_state = calloc(1, sizeof(struct radeon_accel_state)))) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unable to allocate accel_state rec!\n"); return FALSE; } info->accel_state->fifo_slots = 0; if ((info->ChipFamily == CHIP_FAMILY_RS100) || (info->ChipFamily == CHIP_FAMILY_RS200) || (info->ChipFamily == CHIP_FAMILY_RS300) || (info->ChipFamily == CHIP_FAMILY_RS400) || (info->ChipFamily == CHIP_FAMILY_RS480) || (info->ChipFamily == CHIP_FAMILY_RS600) || (info->ChipFamily == CHIP_FAMILY_RS690) || (info->ChipFamily == CHIP_FAMILY_RS740)) info->accel_state->has_tcl = FALSE; else { info->accel_state->has_tcl = TRUE; } /* if we have shadow fb bail */ if (info->r600_shadow_fb) { info->useEXA = FALSE; return TRUE; } #ifdef XF86DRI if ((!info->directRenderingEnabled) || (maxy <= pScrn->virtualY * 3) || (pScrn->videoRam <= 32768)) info->useEXA = FALSE; else info->useEXA = TRUE; #else info->useEXA = FALSE; #endif if (!xf86ReturnOptValBool(info->Options, OPTION_NOACCEL, FALSE)) { int errmaj = 0, errmin = 0; from = X_DEFAULT; #if defined(USE_EXA) #if defined(USE_XAA) optstr = (char *)xf86GetOptValString(info->Options, OPTION_ACCELMETHOD); if (optstr != NULL) { if (xf86NameCmp(optstr, "EXA") == 0) { from = X_CONFIG; info->useEXA = TRUE; } else if (xf86NameCmp(optstr, "XAA") == 0) { from = X_CONFIG; if (info->ChipFamily < CHIP_FAMILY_R600) info->useEXA = FALSE; } } #else /* USE_XAA */ info->useEXA = TRUE; #endif /* !USE_XAA */ #else info->useEXA = FALSE; #endif /* USE_EXA */ if (info->ChipFamily < CHIP_FAMILY_R600) xf86DrvMsg(pScrn->scrnIndex, from, "Using %s acceleration architecture\n", info->useEXA ? "EXA" : "XAA"); else xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "Will attempt to use R6xx/R7xx EXA support if DRI is enabled.\n"); #ifdef USE_EXA if (info->useEXA) { info->exaReq.majorversion = EXA_VERSION_MAJOR; info->exaReq.minorversion = EXA_VERSION_MINOR; if (!LoadSubModule(pScrn->module, "exa", NULL, NULL, NULL, &info->exaReq, &errmaj, &errmin)) { LoaderErrorMsg(NULL, "exa", errmaj, errmin); return FALSE; } } #endif /* USE_EXA */ #ifdef USE_XAA if (!info->useEXA) { info->xaaReq.majorversion = 1; info->xaaReq.minorversion = 2; if (!LoadSubModule(pScrn->module, "xaa", NULL, NULL, NULL, &info->xaaReq, &errmaj, &errmin)) { info->xaaReq.minorversion = 1; if (!LoadSubModule(pScrn->module, "xaa", NULL, NULL, NULL, &info->xaaReq, &errmaj, &errmin)) { info->xaaReq.minorversion = 0; if (!LoadSubModule(pScrn->module, "xaa", NULL, NULL, NULL, &info->xaaReq, &errmaj, &errmin)) { LoaderErrorMsg(NULL, "xaa", errmaj, errmin); return FALSE; } } } } #endif /* USE_XAA */ } else { /* NoAccel */ info->useEXA = FALSE; } return TRUE; } static Bool RADEONPreInitInt10(ScrnInfoPtr pScrn, xf86Int10InfoPtr *ppInt10) { #if (!defined(__powerpc__) && !defined(__sparc__)) || \ (defined(XSERVER_LIBPCIACCESS) && HAVE_PCI_DEVICE_ENABLE) RADEONInfoPtr info = RADEONPTR(pScrn); #endif #if !defined(__powerpc__) && !defined(__sparc__) unsigned char *RADEONMMIO = info->MMIO; uint32_t fp2_gen_ctl_save = 0; #endif #ifdef XSERVER_LIBPCIACCESS #if HAVE_PCI_DEVICE_ENABLE pci_device_enable(info->PciInfo); #endif #endif #if !defined(__powerpc__) && !defined(__sparc__) /* don't need int10 on atom cards. * in theory all radeons, but the older stuff * isn't 100% yet * secondary atom cards tend to hang when initializing int10, * however, on some stom cards, you can't read the bios without * intitializing int10. */ if (!xf86ReturnOptValBool(info->Options, OPTION_INT10, TRUE)) return TRUE; if (xf86LoadSubModule(pScrn, "int10")) { /* The VGA BIOS on the RV100/QY cannot be read when the digital output * is enabled. Clear and restore FP2_ON around int10 to avoid this. */ if (PCI_DEV_DEVICE_ID(info->PciInfo) == PCI_CHIP_RV100_QY) { fp2_gen_ctl_save = INREG(RADEON_FP2_GEN_CNTL); if (fp2_gen_ctl_save & RADEON_FP2_ON) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "disabling digital out\n"); OUTREG(RADEON_FP2_GEN_CNTL, fp2_gen_ctl_save & ~RADEON_FP2_ON); } } xf86DrvMsg(pScrn->scrnIndex,X_INFO,"initializing int10\n"); *ppInt10 = xf86InitInt10(info->pEnt->index); if (PCI_DEV_DEVICE_ID(info->PciInfo) == PCI_CHIP_RV100_QY) { if (fp2_gen_ctl_save & RADEON_FP2_ON) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "re-enabling digital out\n"); OUTREG(RADEON_FP2_GEN_CNTL, fp2_gen_ctl_save); } } } #endif return TRUE; } #ifdef XF86DRI static Bool RADEONPreInitDRI(ScrnInfoPtr pScrn) { RADEONInfoPtr info = RADEONPTR(pScrn); MessageType from; char *reason; info->directRenderingEnabled = FALSE; info->directRenderingInited = FALSE; if (!(info->dri = calloc(1, sizeof(struct radeon_dri)))) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR,"Unable to allocate dri rec!\n"); return FALSE; } if (!(info->cp = calloc(1, sizeof(struct radeon_cp)))) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR,"Unable to allocate cp rec!\n"); return FALSE; } info->cp->CPInUse = FALSE; info->cp->CPStarted = FALSE; info->cp->CPusecTimeout = RADEON_DEFAULT_CP_TIMEOUT; if (xf86IsEntityShared(info->pEnt->index)) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Direct Rendering Disabled -- " "Zaphod Dual-head configuration is not working with " "DRI at present.\n" "Please use the xrandr 1.2 if you " "want Dual-head with DRI.\n"); return FALSE; } if (info->IsSecondary) return FALSE; if (info->ChipFamily >= CHIP_FAMILY_CEDAR) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "No DRI yet on Evergreen\n"); return FALSE; } if (info->Chipset == PCI_CHIP_RN50_515E || info->Chipset == PCI_CHIP_RN50_5969) { if (xf86ReturnOptValBool(info->Options, OPTION_DRI, FALSE)) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Direct rendering for RN50 forced on -- " "This is NOT officially supported at the hardware level " "and may cause instability or lockups\n"); } else { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Direct rendering not officially supported on RN50\n"); return FALSE; } } if (!xf86ReturnOptValBool(info->Options, OPTION_DRI, TRUE)) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Direct rendering forced off\n"); return FALSE; } if (xf86ReturnOptValBool(info->Options, OPTION_NOACCEL, FALSE)) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "[dri] Acceleration disabled, not initializing the DRI\n"); return FALSE; } info->dri->pLibDRMVersion = NULL; info->dri->pKernelDRMVersion = NULL; if (!RADEONDRIGetVersion(pScrn)) return FALSE; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[dri] Found DRI library version %d.%d.%d and kernel" " module version %d.%d.%d\n", info->dri->pLibDRMVersion->version_major, info->dri->pLibDRMVersion->version_minor, info->dri->pLibDRMVersion->version_patchlevel, info->dri->pKernelDRMVersion->version_major, info->dri->pKernelDRMVersion->version_minor, info->dri->pKernelDRMVersion->version_patchlevel); if (info->Chipset == PCI_CHIP_RS400_5A41 || info->Chipset == PCI_CHIP_RS400_5A42 || info->Chipset == PCI_CHIP_RC410_5A61 || info->Chipset == PCI_CHIP_RC410_5A62 || info->Chipset == PCI_CHIP_RS480_5954 || info->Chipset == PCI_CHIP_RS480_5955 || info->Chipset == PCI_CHIP_RS482_5974 || info->Chipset == PCI_CHIP_RS485_5975) { if (info->dri->pKernelDRMVersion->version_minor < 27) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Direct rendering broken on XPRESS 200 and 200M with DRI less than 1.27\n"); return FALSE; } xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Direct rendering experimental on RS400/Xpress 200 enabled\n"); } if (info->ChipFamily >= CHIP_FAMILY_R300) info->dri->gartSize = R300_DEFAULT_GART_SIZE; else info->dri->gartSize = RADEON_DEFAULT_GART_SIZE; info->dri->ringSize = RADEON_DEFAULT_RING_SIZE; info->dri->bufSize = RADEON_DEFAULT_BUFFER_SIZE; info->dri->gartTexSize = RADEON_DEFAULT_GART_TEX_SIZE; info->dri->pciAperSize = RADEON_DEFAULT_PCI_APER_SIZE; info->cp->CPusecTimeout = RADEON_DEFAULT_CP_TIMEOUT; if ((xf86GetOptValInteger(info->Options, OPTION_GART_SIZE, (int *)&(info->dri->gartSize))) || (xf86GetOptValInteger(info->Options, OPTION_GART_SIZE_OLD, (int *)&(info->dri->gartSize)))) { switch (info->dri->gartSize) { case 4: case 8: case 16: case 32: case 64: case 128: case 256: break; default: xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Illegal GART size: %d MB\n", info->dri->gartSize); return FALSE; } } if (xf86GetOptValInteger(info->Options, OPTION_RING_SIZE, &(info->dri->ringSize))) { if (info->dri->ringSize < 1 || info->dri->ringSize >= (int)info->dri->gartSize) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Illegal ring buffer size: %d MB\n", info->dri->ringSize); return FALSE; } } if (xf86GetOptValInteger(info->Options, OPTION_PCIAPER_SIZE, &(info->dri->pciAperSize))) { switch(info->dri->pciAperSize) { case 32: case 64: case 128: case 256: break; default: xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Illegal pci aper size: %d MB\n", info->dri->pciAperSize); return FALSE; } } if (xf86GetOptValInteger(info->Options, OPTION_BUFFER_SIZE, &(info->dri->bufSize))) { if (info->dri->bufSize < 1 || info->dri->bufSize >= (int)info->dri->gartSize) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Illegal vertex/indirect buffers size: %d MB\n", info->dri->bufSize); return FALSE; } if (info->dri->bufSize > 2) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Illegal vertex/indirect buffers size: %d MB\n", info->dri->bufSize); xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Clamping vertex/indirect buffers size to 2 MB\n"); info->dri->bufSize = 2; } } if (info->dri->ringSize + info->dri->bufSize + info->dri->gartTexSize > (int)info->dri->gartSize) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Buffers are too big for requested GART space\n"); return FALSE; } info->dri->gartTexSize = info->dri->gartSize - (info->dri->ringSize + info->dri->bufSize); if (xf86GetOptValInteger(info->Options, OPTION_USEC_TIMEOUT, &(info->cp->CPusecTimeout))) { /* This option checked by the RADEON DRM kernel module */ } /* Two options to try and squeeze as much texture memory as possible * for dedicated 3d rendering boxes */ info->dri->noBackBuffer = xf86ReturnOptValBool(info->Options, OPTION_NO_BACKBUFFER, FALSE); info->dri->allowPageFlip = 0; #ifdef DAMAGE if (info->dri->noBackBuffer) { from = X_DEFAULT; reason = " because back buffer disabled"; } else { from = xf86GetOptValBool(info->Options, OPTION_PAGE_FLIP, &info->dri->allowPageFlip) ? X_CONFIG : X_DEFAULT; if (IS_AVIVO_VARIANT) { info->dri->allowPageFlip = 0; reason = " on r5xx and newer chips.\n"; } else { reason = ""; } } #else from = X_DEFAULT; reason = " because Damage layer not available at build time"; #endif xf86DrvMsg(pScrn->scrnIndex, from, "Page Flipping %sabled%s\n", info->dri->allowPageFlip ? "en" : "dis", reason); /* AGP seems to have problems with gart transfers */ if ((info->ChipFamily >= CHIP_FAMILY_R600) && (info->cardType == CARD_AGP)) info->DMAForXv = FALSE; else info->DMAForXv = TRUE; from = xf86GetOptValBool(info->Options, OPTION_XV_DMA, &info->DMAForXv) ? X_CONFIG : X_INFO; xf86DrvMsg(pScrn->scrnIndex, from, "Will %stry to use DMA for Xv image transfers\n", info->DMAForXv ? "" : "not "); return TRUE; } #endif /* XF86DRI */ static void RADEONPreInitColorTiling(ScrnInfoPtr pScrn) { RADEONInfoPtr info = RADEONPTR(pScrn); info->allowColorTiling = xf86ReturnOptValBool(info->Options, OPTION_COLOR_TILING, TRUE); if (IS_R300_VARIANT || IS_AVIVO_VARIANT) { /* this may be 4096 on r4xx -- need to double check */ info->MaxSurfaceWidth = 3968; /* one would have thought 4096...*/ info->MaxLines = 4096; } else { info->MaxSurfaceWidth = 2048; info->MaxLines = 2048; } if (!info->allowColorTiling) return; if (info->ChipFamily >= CHIP_FAMILY_R600) info->allowColorTiling = FALSE; /* for zaphod disable tiling for now */ if (info->IsPrimary || info->IsSecondary) info->allowColorTiling = FALSE; #ifdef XF86DRI if (info->directRenderingEnabled && info->dri->pKernelDRMVersion->version_minor < 14) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "[dri] color tiling disabled because of version " "mismatch.\n" "[dri] radeon.o kernel module version is %d.%d.%d but " "1.14.0 or later is required for color tiling.\n", info->dri->pKernelDRMVersion->version_major, info->dri->pKernelDRMVersion->version_minor, info->dri->pKernelDRMVersion->version_patchlevel); info->allowColorTiling = FALSE; return; } #endif /* XF86DRI */ if (info->allowColorTiling) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Color tiling enabled by default\n"); } else { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Color tiling disabled\n"); } } static Bool RADEONPreInitXv(ScrnInfoPtr pScrn) { RADEONInfoPtr info = RADEONPTR(pScrn); uint16_t mm_table; uint16_t bios_header; uint16_t pll_info_block; #ifdef XvExtension char* microc_path = NULL; char* microc_type = NULL; MessageType from; if (xf86GetOptValInteger(info->Options, OPTION_VIDEO_KEY, &(info->videoKey))) { xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "video key set to 0x%x\n", info->videoKey); } else { info->videoKey = 0x1E; } if(xf86GetOptValInteger(info->Options, OPTION_RAGE_THEATRE_CRYSTAL, &(info->RageTheatreCrystal))) { xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Rage Theatre Crystal frequency was specified as %d.%d Mhz\n", info->RageTheatreCrystal/100, info->RageTheatreCrystal % 100); } else { info->RageTheatreCrystal=-1; } if(xf86GetOptValInteger(info->Options, OPTION_RAGE_THEATRE_TUNER_PORT, &(info->RageTheatreTunerPort))) { xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Rage Theatre tuner port was specified as %d\n", info->RageTheatreTunerPort); } else { info->RageTheatreTunerPort=-1; } if(info->RageTheatreTunerPort>5){ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Attempt to assign Rage Theatre tuner port to invalid value. Disabling setting\n"); info->RageTheatreTunerPort=-1; } if(xf86GetOptValInteger(info->Options, OPTION_RAGE_THEATRE_COMPOSITE_PORT, &(info->RageTheatreCompositePort))) { xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Rage Theatre composite port was specified as %d\n", info->RageTheatreCompositePort); } else { info->RageTheatreCompositePort=-1; } if(info->RageTheatreCompositePort>6){ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Attempt to assign Rage Theatre composite port to invalid value. Disabling setting\n"); info->RageTheatreCompositePort=-1; } if(xf86GetOptValInteger(info->Options, OPTION_RAGE_THEATRE_SVIDEO_PORT, &(info->RageTheatreSVideoPort))) { xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Rage Theatre SVideo Port was specified as %d\n", info->RageTheatreSVideoPort); } else { info->RageTheatreSVideoPort=-1; } if(info->RageTheatreSVideoPort>6){ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Attempt to assign Rage Theatre SVideo port to invalid value. Disabling setting\n"); info->RageTheatreSVideoPort=-1; } if(xf86GetOptValInteger(info->Options, OPTION_TUNER_TYPE, &(info->tunerType))) { xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Tuner type was specified as %d\n", info->tunerType); } else { info->tunerType=-1; } if(info->tunerType>31){ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Attempt to set tuner type to invalid value. Disabling setting\n"); info->tunerType=-1; } if((microc_path = xf86GetOptValString(info->Options, OPTION_RAGE_THEATRE_MICROC_PATH)) != NULL) { xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Rage Theatre Microcode path was specified as %s\n", microc_path); info->RageTheatreMicrocPath = microc_path; } else { info->RageTheatreMicrocPath= NULL; } if((microc_type = xf86GetOptValString(info->Options, OPTION_RAGE_THEATRE_MICROC_TYPE)) != NULL) { xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Rage Theatre Microcode type was specified as %s\n", microc_type); info->RageTheatreMicrocType = microc_type; } else { info->RageTheatreMicrocType= NULL; } if(xf86GetOptValInteger(info->Options, OPTION_SCALER_WIDTH, &(info->overlay_scaler_buffer_width))) { if ((info->overlay_scaler_buffer_width < 1024) || (info->overlay_scaler_buffer_width > 2048) || ((info->overlay_scaler_buffer_width % 64) != 0)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Attempt to set illegal scaler width. Using default\n"); from = X_DEFAULT; info->overlay_scaler_buffer_width = 0; } else from = X_CONFIG; } else { from = X_DEFAULT; info->overlay_scaler_buffer_width = 0; } if (!info->overlay_scaler_buffer_width) { /* overlay scaler line length differs for different revisions this needs to be maintained by hand */ switch(info->ChipFamily){ case CHIP_FAMILY_R200: case CHIP_FAMILY_R300: case CHIP_FAMILY_R350: case CHIP_FAMILY_RV350: case CHIP_FAMILY_RV380: case CHIP_FAMILY_R420: case CHIP_FAMILY_RV410: info->overlay_scaler_buffer_width = 1920; break; default: info->overlay_scaler_buffer_width = 1536; } } xf86DrvMsg(pScrn->scrnIndex, from, "Assuming overlay scaler buffer width is %d\n", info->overlay_scaler_buffer_width); #endif /* Rescue MM_TABLE before VBIOS is freed */ info->MM_TABLE_valid = FALSE; if((info->VBIOS==NULL)||(info->VBIOS[0]!=0x55)||(info->VBIOS[1]!=0xaa)){ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Cannot access BIOS or it is not valid.\n" "\t\tIf your card is TV-in capable you will need to specify options RageTheatreCrystal, RageTheatreTunerPort, \n" "\t\tRageTheatreSVideoPort and TunerType in /etc/X11/xorg.conf.\n" ); info->MM_TABLE_valid = FALSE; return TRUE; } bios_header=info->VBIOS[0x48]; bios_header+=(((int)info->VBIOS[0x49]+0)<<8); mm_table=info->VBIOS[bios_header+0x38]; if(mm_table==0) { xf86DrvMsg(pScrn->scrnIndex,X_INFO,"No MM_TABLE found - assuming CARD is not TV-in capable.\n"); info->MM_TABLE_valid = FALSE; return TRUE; } mm_table+=(((int)info->VBIOS[bios_header+0x39]+0)<<8)-2; if(mm_table>0) { memcpy(&(info->MM_TABLE), &(info->VBIOS[mm_table]), sizeof(info->MM_TABLE)); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "MM_TABLE: %02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x\n", info->MM_TABLE.table_revision, info->MM_TABLE.table_size, info->MM_TABLE.tuner_type, info->MM_TABLE.audio_chip, info->MM_TABLE.product_id, info->MM_TABLE.tuner_voltage_teletext_fm, info->MM_TABLE.i2s_config, info->MM_TABLE.video_decoder_type, info->MM_TABLE.video_decoder_host_config, info->MM_TABLE.input[0], info->MM_TABLE.input[1], info->MM_TABLE.input[2], info->MM_TABLE.input[3], info->MM_TABLE.input[4]); /* Is it an MM_TABLE we know about ? */ if(info->MM_TABLE.table_size != 0xc){ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "This card has MM_TABLE we do not recognize.\n" "\t\tIf your card is TV-in capable you will need to specify options RageTheatreCrystal, RageTheatreTunerPort, \n" "\t\tRageTheatreSVideoPort and TunerType in /etc/X11/xorg.conf.\n" ); info->MM_TABLE_valid = FALSE; return TRUE; } info->MM_TABLE_valid = TRUE; } else { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "No MM_TABLE found - assuming card is not TV-in capable (mm_table=%d).\n", mm_table); info->MM_TABLE_valid = FALSE; } pll_info_block=info->VBIOS[bios_header+0x30]; pll_info_block+=(((int)info->VBIOS[bios_header+0x31]+0)<<8); info->video_decoder_type=info->VBIOS[pll_info_block+0x08]; info->video_decoder_type+=(((int)info->VBIOS[pll_info_block+0x09]+0)<<8); return TRUE; } static Bool RADEONPreInitBIOS(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10) { RADEONInfoPtr info = RADEONPTR(pScrn); if (!RADEONGetBIOSInfo(pScrn, pInt10)) { /* Avivo chips require bios for atom */ if (IS_AVIVO_VARIANT) return FALSE; } return TRUE; } Bool RADEONZaphodStringMatches(ScrnInfoPtr pScrn, const char *s, char *output_name) { int i = 0; char s1[20]; do { switch(*s) { case ',': s1[i] = '\0'; i = 0; if (strcmp(s1, output_name) == 0) return TRUE; break; case ' ': case '\t': case '\n': case '\r': break; default: s1[i] = *s; i++; break; } } while(*s++); s1[i] = '\0'; if (strcmp(s1, output_name) == 0) return TRUE; return FALSE; } static void RADEONFixZaphodOutputs(ScrnInfoPtr pScrn) { RADEONInfoPtr info = RADEONPTR(pScrn); xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); int o; char *s; if ((s = xf86GetOptValString(info->Options, OPTION_ZAPHOD_HEADS))) { for (o = config->num_output; o > 0; o--) { if (!RADEONZaphodStringMatches(pScrn, s, config->output[o - 1]->name)) xf86OutputDestroy(config->output[o - 1]); } } else { if (info->IsPrimary) { xf86OutputDestroy(config->output[0]); while (config->num_output > 1) { xf86OutputDestroy(config->output[1]); } } else { while (config->num_output > 1) { xf86OutputDestroy(config->output[1]); } } } } static Bool RADEONPreInitControllers(ScrnInfoPtr pScrn) { xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); RADEONInfoPtr info = RADEONPTR(pScrn); int i; int mask; int found = 0; if (info->IsPrimary) mask = 1; else if (info->IsSecondary) mask = 2; else mask = 3; if (!RADEONAllocateControllers(pScrn, mask)) return FALSE; RADEONGetClockInfo(pScrn); if (info->IsAtomBios && info->IsIGP) RADEONATOMGetIGPInfo(pScrn); if (!RADEONSetupConnectors(pScrn)) { return FALSE; } if (info->IsPrimary || info->IsSecondary) { /* fixup outputs for zaphod */ RADEONFixZaphodOutputs(pScrn); } RADEONPrintPortMap(pScrn); info->first_load_no_devices = FALSE; for (i = 0; i < config->num_output; i++) { xf86OutputPtr output = config->output[i]; output->status = (*output->funcs->detect) (output); ErrorF("finished output detect: %d\n", i); if (info->IsPrimary || info->IsSecondary) { if (output->status != XF86OutputStatusConnected) return FALSE; } if (output->status != XF86OutputStatusDisconnected) found++; } if (!found) { /* nothing connected, light up some defaults so the server comes up */ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No connected devices found!\n"); info->first_load_no_devices = TRUE; } ErrorF("finished all detect\n"); return TRUE; } static void RADEONProbeDDC(ScrnInfoPtr pScrn, int indx) { vbeInfoPtr pVbe; if (xf86LoadSubModule(pScrn, "vbe")) { pVbe = VBEInit(NULL,indx); ConfiguredMonitor = vbeDoEDID(pVbe, NULL); vbeFree(pVbe); } } static Bool RADEONCRTCResize(ScrnInfoPtr scrn, int width, int height) { scrn->virtualX = width; scrn->virtualY = height; /* RADEONSetPitch(scrn); */ return TRUE; } static const xf86CrtcConfigFuncsRec RADEONCRTCResizeFuncs = { RADEONCRTCResize }; Bool RADEONPreInit(ScrnInfoPtr pScrn, int flags) { xf86CrtcConfigPtr xf86_config; RADEONInfoPtr info; xf86Int10InfoPtr pInt10 = NULL; void *int10_save = NULL; const char *s; RADEONEntPtr pRADEONEnt; DevUnion* pPriv; xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "RADEONPreInit\n"); if (pScrn->numEntities != 1) return FALSE; if (!RADEONGetRec(pScrn)) return FALSE; info = RADEONPTR(pScrn); info->MMIO = NULL; info->IsSecondary = FALSE; info->IsPrimary = FALSE; info->kms_enabled = FALSE; info->pEnt = xf86GetEntityInfo(pScrn->entityList[pScrn->numEntities - 1]); if (info->pEnt->location.type != BUS_PCI) goto fail; pPriv = xf86GetEntityPrivate(pScrn->entityList[0], getRADEONEntityIndex()); pRADEONEnt = pPriv->ptr; if(xf86IsEntityShared(pScrn->entityList[0])) { if(xf86IsPrimInitDone(pScrn->entityList[0])) { info->IsSecondary = TRUE; pRADEONEnt->pSecondaryScrn = pScrn; info->SavedReg = &pRADEONEnt->SavedReg; info->ModeReg = &pRADEONEnt->ModeReg; } else { info->IsPrimary = TRUE; xf86SetPrimInitDone(pScrn->entityList[0]); pRADEONEnt->pPrimaryScrn = pScrn; pRADEONEnt->HasSecondary = FALSE; info->SavedReg = &pRADEONEnt->SavedReg; info->ModeReg = &pRADEONEnt->ModeReg; } } else { info->SavedReg = &pRADEONEnt->SavedReg; info->ModeReg = &pRADEONEnt->ModeReg; } info->PciInfo = xf86GetPciInfoForEntity(info->pEnt->index); info->PciTag = pciTag(PCI_DEV_BUS(info->PciInfo), PCI_DEV_DEV(info->PciInfo), PCI_DEV_FUNC(info->PciInfo)); info->MMIOAddr = PCI_REGION_BASE(info->PciInfo, 2, REGION_MEM) & ~0xffULL; info->MMIOSize = PCI_REGION_SIZE(info->PciInfo, 2); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "TOTO SAYS %016llx\n", (unsigned long long)PCI_REGION_BASE(info->PciInfo, 2, REGION_MEM)); if (info->pEnt->device->IOBase) { xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "MMIO address override, using 0x%08lx instead of 0x%016llx\n", info->pEnt->device->IOBase, info->MMIOAddr); info->MMIOAddr = info->pEnt->device->IOBase; } else if (!info->MMIOAddr) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid MMIO address\n"); goto fail1; } xf86DrvMsg(pScrn->scrnIndex, X_INFO, "MMIO registers at 0x%016llx: size %ldKB\n", info->MMIOAddr, info->MMIOSize / 1024); if(!RADEONMapMMIO(pScrn)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Memory map the MMIO region failed\n"); goto fail1; } #if !defined(__alpha__) if ( #ifndef XSERVER_LIBPCIACCESS xf86GetPciDomain(info->PciTag) || #endif !xf86IsPrimaryPci(info->PciInfo)) RADEONPreInt10Save(pScrn, &int10_save); #else /* [Alpha] On the primary, the console already ran the BIOS and we're * going to run it again - so make sure to "fix up" the card * so that (1) we can read the BIOS ROM and (2) the BIOS will * get the memory config right. */ RADEONPreInt10Save(pScrn, &int10_save); #endif if (flags & PROBE_DETECT) { RADEONProbeDDC(pScrn, info->pEnt->index); RADEONPostInt10Check(pScrn, int10_save); if(info->MMIO) RADEONUnmapMMIO(pScrn); return TRUE; } xf86DrvMsg(pScrn->scrnIndex, X_INFO, "PCI bus %d card %d func %d\n", PCI_DEV_BUS(info->PciInfo), PCI_DEV_DEV(info->PciInfo), PCI_DEV_FUNC(info->PciInfo)); #ifndef XSERVER_LIBPCIACCESS if (xf86RegisterResources(info->pEnt->index, 0, ResExclusive)) goto fail; xf86SetOperatingState(resVga, info->pEnt->index, ResUnusedOpr); pScrn->racMemFlags = RAC_FB | RAC_COLORMAP | RAC_VIEWPORT | RAC_CURSOR; #endif pScrn->monitor = pScrn->confScreen->monitor; /* Allocate an xf86CrtcConfig */ xf86CrtcConfigInit (pScrn, &RADEONCRTCResizeFuncs); xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); if (!RADEONPreInitVisual(pScrn)) goto fail; /* We can't do this until we have a pScrn->display. */ xf86CollectOptions(pScrn, NULL); if (!(info->Options = malloc(sizeof(RADEONOptions)))) goto fail; memcpy(info->Options, RADEONOptions, sizeof(RADEONOptions)); xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, info->Options); /* By default, don't do VGA IOs on ppc/sparc */ #if defined(__powerpc__) || defined(__sparc__) || !defined(WITH_VGAHW) info->VGAAccess = FALSE; #else info->VGAAccess = TRUE; #endif #ifdef WITH_VGAHW xf86GetOptValBool(info->Options, OPTION_VGA_ACCESS, &info->VGAAccess); if (info->VGAAccess) { if (!xf86LoadSubModule(pScrn, "vgahw")) info->VGAAccess = FALSE; else { if (!vgaHWGetHWRec(pScrn)) info->VGAAccess = FALSE; } if (!info->VGAAccess) xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Loading VGA module failed," " trying to run without it\n"); } else xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VGAAccess option set to FALSE," " VGA module load skipped\n"); if (info->VGAAccess) vgaHWGetIOBase(VGAHWPTR(pScrn)); #endif if (!RADEONPreInitWeight(pScrn)) goto fail; info->DispPriority = 1; if ((s = xf86GetOptValString(info->Options, OPTION_DISP_PRIORITY))) { if (strcmp(s, "AUTO") == 0) { info->DispPriority = 1; } else if (strcmp(s, "BIOS") == 0) { info->DispPriority = 0; } else if (strcmp(s, "HIGH") == 0) { info->DispPriority = 2; } else info->DispPriority = 1; } if (!RADEONPreInitChipType(pScrn)) goto fail; if (!RADEONPreInitInt10(pScrn, &pInt10)) goto fail; RADEONPostInt10Check(pScrn, int10_save); if (!RADEONPreInitBIOS(pScrn, pInt10)) goto fail; /* Save BIOS scratch registers */ RADEONSaveBIOSRegisters(pScrn, info->SavedReg); #ifdef XF86DRI /* PreInit DRI first of all since we need that for getting a proper * memory map */ info->directRenderingEnabled = RADEONPreInitDRI(pScrn); #endif if (!info->directRenderingEnabled) { if (info->ChipFamily >= CHIP_FAMILY_R600) { info->r600_shadow_fb = TRUE; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "using shadow framebuffer\n"); if (!xf86LoadSubModule(pScrn, "shadow")) info->r600_shadow_fb = FALSE; } } if (!RADEONPreInitVRAM(pScrn)) goto fail; RADEONPreInitColorTiling(pScrn); if (IS_AVIVO_VARIANT) xf86CrtcSetSizeRange (pScrn, 320, 200, 8192, 8192); else xf86CrtcSetSizeRange (pScrn, 320, 200, 4096, 4096); RADEONPreInitDDC(pScrn); if (!RADEONPreInitControllers(pScrn)) goto fail; if (!xf86InitialConfiguration (pScrn, FALSE)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes.\n"); goto fail; } /* fix up cloning on rn50 cards * since they only have one crtc sometimes the xserver doesn't assign * a crtc to one of the outputs even though both outputs have common modes * which results in only one monitor being enabled. Assign a crtc here so * that both outputs light up. */ if (info->ChipFamily == CHIP_FAMILY_RV100 && !pRADEONEnt->HasCRTC2) { int i; for (i = 0; i < xf86_config->num_output; i++) { xf86OutputPtr output = xf86_config->output[i]; /* XXX: double check crtc mode */ if ((output->probed_modes != NULL) && (output->crtc == NULL)) output->crtc = xf86_config->crtc[0]; } } RADEONSetPitch(pScrn); /* Set display resolution */ xf86SetDpi(pScrn, 0, 0); /* Get ScreenInit function */ if (!xf86LoadSubModule(pScrn, "fb")) return FALSE; if (!RADEONPreInitGamma(pScrn)) goto fail; if (!RADEONPreInitCursor(pScrn)) goto fail; if (!RADEONPreInitAccel(pScrn)) goto fail; if (!IS_AVIVO_VARIANT) { if (!RADEONPreInitXv(pScrn)) goto fail; } if (!xf86RandR12PreInit (pScrn)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "RandR initialization failure\n"); goto fail; } if (pScrn->modes == NULL) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes.\n"); goto fail; } /* Free int10 info */ if (pInt10) xf86FreeInt10(pInt10); if(info->MMIO) RADEONUnmapMMIO(pScrn); info->MMIO = NULL; xf86DrvMsg(pScrn->scrnIndex, X_NOTICE, "MergedFB support has been removed and replaced with" " xrandr 1.2 support\n"); return TRUE; fail: /* Pre-init failed. */ /* Free the video bios (if applicable) */ if (info->VBIOS) { free(info->VBIOS); info->VBIOS = NULL; } /* Free int10 info */ if (pInt10) xf86FreeInt10(pInt10); #ifdef WITH_VGAHW if (info->VGAAccess) vgaHWFreeHWRec(pScrn); #endif if(info->MMIO) RADEONUnmapMMIO(pScrn); info->MMIO = NULL; fail1: RADEONFreeRec(pScrn); return FALSE; } /* Load a palette */ static void RADEONLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO *colors, VisualPtr pVisual) { RADEONInfoPtr info = RADEONPTR(pScrn); xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); int i; int index, j; uint16_t lut_r[256], lut_g[256], lut_b[256]; int c; #ifdef XF86DRI if (info->cp->CPStarted && pScrn->pScreen) DRILock(pScrn->pScreen, 0); #endif if (info->accelOn && pScrn->pScreen) RADEON_SYNC(info, pScrn); { for (c = 0; c < xf86_config->num_crtc; c++) { xf86CrtcPtr crtc = xf86_config->crtc[c]; RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private; for (i = 0 ; i < 256; i++) { lut_r[i] = radeon_crtc->lut_r[i] << 6; lut_g[i] = radeon_crtc->lut_g[i] << 6; lut_b[i] = radeon_crtc->lut_b[i] << 6; } switch (info->CurrentLayout.depth) { case 15: for (i = 0; i < numColors; i++) { index = indices[i]; for (j = 0; j < 8; j++) { lut_r[index * 8 + j] = colors[index].red << 6; lut_g[index * 8 + j] = colors[index].green << 6; lut_b[index * 8 + j] = colors[index].blue << 6; } } case 16: for (i = 0; i < numColors; i++) { index = indices[i]; if (i <= 31) { for (j = 0; j < 8; j++) { lut_r[index * 8 + j] = colors[index].red << 6; lut_b[index * 8 + j] = colors[index].blue << 6; } } for (j = 0; j < 4; j++) { lut_g[index * 4 + j] = colors[index].green << 6; } } default: for (i = 0; i < numColors; i++) { index = indices[i]; lut_r[index] = colors[index].red << 6; lut_g[index] = colors[index].green << 6; lut_b[index] = colors[index].blue << 6; } break; } /* Make the change through RandR */ #ifdef RANDR_12_INTERFACE if (crtc->randr_crtc) RRCrtcGammaSet(crtc->randr_crtc, lut_r, lut_g, lut_b); else #endif crtc->funcs->gamma_set(crtc, lut_r, lut_g, lut_b, 256); } } #ifdef XF86DRI if (info->cp->CPStarted && pScrn->pScreen) DRIUnlock(pScrn->pScreen); #endif } static void RADEONBlockHandler(int i, pointer blockData, pointer pTimeout, pointer pReadmask) { ScreenPtr pScreen = screenInfo.screens[i]; ScrnInfoPtr pScrn = xf86Screens[i]; RADEONInfoPtr info = RADEONPTR(pScrn); pScreen->BlockHandler = info->BlockHandler; (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask); pScreen->BlockHandler = RADEONBlockHandler; if (info->VideoTimerCallback) (*info->VideoTimerCallback)(pScrn, currentTime.milliseconds); #if defined(RENDER) && defined(USE_XAA) if(info->accel_state->RenderCallback) (*info->accel_state->RenderCallback)(pScrn); #endif #ifdef USE_EXA info->accel_state->engineMode = EXA_ENGINEMODE_UNKNOWN; #endif if (info->pm.dynamic_mode_enabled) RADEONPMBlockHandler(pScrn); } static void RADEONInitBIOSRegisters(ScrnInfoPtr pScrn) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; RADEONSavePtr save = info->ModeReg; save->bios_0_scratch = info->SavedReg->bios_0_scratch; save->bios_1_scratch = info->SavedReg->bios_1_scratch; save->bios_2_scratch = info->SavedReg->bios_2_scratch; save->bios_3_scratch = info->SavedReg->bios_3_scratch; save->bios_4_scratch = info->SavedReg->bios_4_scratch; save->bios_5_scratch = info->SavedReg->bios_5_scratch; save->bios_6_scratch = info->SavedReg->bios_6_scratch; save->bios_7_scratch = info->SavedReg->bios_7_scratch; if (info->IsAtomBios) { /* let the bios control the backlight */ save->bios_2_scratch &= ~ATOM_S2_VRI_BRIGHT_ENABLE; /* tell the bios not to handle mode switching */ save->bios_6_scratch |= (ATOM_S6_ACC_BLOCK_DISPLAY_SWITCH | ATOM_S6_ACC_MODE); if (info->ChipFamily >= CHIP_FAMILY_R600) { OUTREG(R600_BIOS_2_SCRATCH, save->bios_2_scratch); OUTREG(R600_BIOS_6_SCRATCH, save->bios_6_scratch); } else { OUTREG(RADEON_BIOS_2_SCRATCH, save->bios_2_scratch); OUTREG(RADEON_BIOS_6_SCRATCH, save->bios_6_scratch); } } else { /* let the bios control the backlight */ save->bios_0_scratch &= ~RADEON_DRIVER_BRIGHTNESS_EN; /* tell the bios not to handle mode switching */ save->bios_6_scratch |= (RADEON_DISPLAY_SWITCHING_DIS | RADEON_ACC_MODE_CHANGE); /* tell the bios a driver is loaded */ save->bios_7_scratch |= RADEON_DRV_LOADED; OUTREG(RADEON_BIOS_0_SCRATCH, save->bios_0_scratch); OUTREG(RADEON_BIOS_6_SCRATCH, save->bios_6_scratch); //OUTREG(RADEON_BIOS_7_SCRATCH, save->bios_7_scratch); } } /* Called at the start of each server generation. */ Bool RADEONScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) { ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; RADEONInfoPtr info = RADEONPTR(pScrn); int hasDRI = 0; #ifdef RENDER int subPixelOrder = SubPixelUnknown; char* s; #endif info->accelOn = FALSE; #ifdef USE_XAA info->accel_state->accel = NULL; #endif #ifdef XF86DRI pScrn->fbOffset = info->dri->frontOffset; #endif if (info->IsSecondary) pScrn->fbOffset = pScrn->videoRam * 1024; #ifdef XF86DRI xf86DrvMsg(pScrn->scrnIndex, X_INFO, "RADEONScreenInit %lx %ld %d\n", pScrn->memPhysBase, pScrn->fbOffset, info->dri->frontOffset); #else xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "RADEONScreenInit %lx %ld\n", pScrn->memPhysBase, pScrn->fbOffset); #endif if (!RADEONMapMem(pScrn)) return FALSE; #ifdef XF86DRI info->dri->fbX = 0; info->dri->fbY = 0; #endif info->PaletteSavedOnVT = FALSE; info->crtc_on = FALSE; info->crtc2_on = FALSE; /* save the real front buffer size * it changes with randr, rotation, etc. */ info->virtualX = pScrn->virtualX; info->virtualY = pScrn->virtualY; RADEONSave(pScrn); /* set initial bios scratch reg state */ RADEONInitBIOSRegisters(pScrn); /* blank the outputs/crtcs */ RADEONBlank(pScrn); RADEONPMInit(pScrn); if (info->allowColorTiling && (pScrn->virtualX > info->MaxSurfaceWidth)) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Color tiling not supported with virtual x resolutions larger than %d, disabling\n", info->MaxSurfaceWidth); info->allowColorTiling = FALSE; } if (info->allowColorTiling) { info->tilingEnabled = (pScrn->currentMode->Flags & (V_DBLSCAN | V_INTERLACE)) ? FALSE : TRUE; } /* Visual setup */ miClearVisualTypes(); if (!miSetVisualTypes(pScrn->depth, miGetDefaultVisualMask(pScrn->depth), pScrn->rgbBits, pScrn->defaultVisual)) return FALSE; miSetPixmapDepths (); #ifdef XF86DRI if (info->directRenderingEnabled) { MessageType from; info->dri->depthBits = pScrn->depth; from = xf86GetOptValInteger(info->Options, OPTION_DEPTH_BITS, &info->dri->depthBits) ? X_CONFIG : X_DEFAULT; if (info->dri->depthBits != 16 && info->dri->depthBits != 24) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Value for Option \"DepthBits\" must be 16 or 24\n"); info->dri->depthBits = pScrn->depth; from = X_DEFAULT; } xf86DrvMsg(pScrn->scrnIndex, from, "Using %d bit depth buffer\n", info->dri->depthBits); } hasDRI = info->directRenderingEnabled; #endif /* XF86DRI */ /* Initialize the memory map, this basically calculates the values * we'll use later on for MC_FB_LOCATION & MC_AGP_LOCATION */ RADEONInitMemoryMap(pScrn); /* empty the surfaces */ if (info->ChipFamily < CHIP_FAMILY_R600) { unsigned char *RADEONMMIO = info->MMIO; unsigned int j; for (j = 0; j < 8; j++) { OUTREG(RADEON_SURFACE0_INFO + 16 * j, 0); OUTREG(RADEON_SURFACE0_LOWER_BOUND + 16 * j, 0); OUTREG(RADEON_SURFACE0_UPPER_BOUND + 16 * j, 0); } } #ifdef XF86DRI /* Depth moves are disabled by default since they are extremely slow */ info->dri->depthMoves = xf86ReturnOptValBool(info->Options, OPTION_DEPTH_MOVE, FALSE); if (info->dri->depthMoves && info->allowColorTiling) { xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Enabling depth moves\n"); } else if (info->dri->depthMoves) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Depth moves don't work without color tiling, disabled\n"); info->dri->depthMoves = FALSE; } else { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Depth moves disabled by default\n"); } #endif /* Initial setup of surfaces */ if (info->ChipFamily < CHIP_FAMILY_R600) { xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "Setting up initial surfaces\n"); RADEONChangeSurfaces(pScrn); } /* Memory manager setup */ xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "Setting up accel memmap\n"); #ifdef USE_EXA if (info->useEXA) { #ifdef XF86DRI if (hasDRI) { info->accelDFS = xf86ReturnOptValBool(info->Options, OPTION_ACCEL_DFS, info->cardType != CARD_AGP); /* Reserve approx. half of offscreen memory for local textures by * default, can be overridden with Option "FBTexPercent". * Round down to a whole number of texture regions. */ info->dri->textureSize = 50; if (xf86GetOptValInteger(info->Options, OPTION_FBTEX_PERCENT, &(info->dri->textureSize))) { if (info->dri->textureSize < 0 || info->dri->textureSize > 100) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Illegal texture memory percentage: %dx, setting to default 50%%\n", info->dri->textureSize); info->dri->textureSize = 50; } } } #endif /* XF86DRI */ if (!RADEONSetupMemEXA(pScreen)) return FALSE; } #endif #if defined(XF86DRI) && defined(USE_XAA) if (!info->useEXA && hasDRI) { info->dri->textureSize = -1; if (xf86GetOptValInteger(info->Options, OPTION_FBTEX_PERCENT, &(info->dri->textureSize))) { if (info->dri->textureSize < 0 || info->dri->textureSize > 100) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Illegal texture memory percentage: %dx, using default behaviour\n", info->dri->textureSize); info->dri->textureSize = -1; } } if (!RADEONSetupMemXAA_DRI(scrnIndex, pScreen)) return FALSE; pScrn->fbOffset = info->dri->frontOffset; } #endif #ifdef USE_XAA if (!info->useEXA && !hasDRI && !RADEONSetupMemXAA(scrnIndex, pScreen)) return FALSE; #endif info->accel_state->dst_pitch_offset = (((pScrn->displayWidth * info->CurrentLayout.pixel_bytes / 64) << 22) | ((info->fbLocation + pScrn->fbOffset) >> 10)); /* Setup DRI after visuals have been established, but before fbScreenInit is * called. fbScreenInit will eventually call the driver's InitGLXVisuals * call back. */ #ifdef XF86DRI if (info->directRenderingEnabled) { /* FIXME: When we move to dynamic allocation of back and depth * buffers, we will want to revisit the following check for 3 * times the virtual size of the screen below. */ int width_bytes = (pScrn->displayWidth * info->CurrentLayout.pixel_bytes); int maxy = info->FbMapSize / width_bytes; if (maxy <= pScrn->virtualY * 3) { xf86DrvMsg(scrnIndex, X_ERROR, "Static buffer allocation failed. Disabling DRI.\n"); xf86DrvMsg(scrnIndex, X_ERROR, "At least %d kB of video memory needed at this " "resolution and depth.\n", (pScrn->displayWidth * pScrn->virtualY * info->CurrentLayout.pixel_bytes * 3 + 1023) / 1024); info->directRenderingEnabled = FALSE; } else { info->directRenderingEnabled = RADEONDRIScreenInit(pScreen); } } /* Tell DRI about new memory map */ if (info->directRenderingEnabled && info->dri->newMemoryMap) { if (RADEONDRISetParam(pScrn, RADEON_SETPARAM_NEW_MEMMAP, 1) < 0) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "[drm] failed to enable new memory map\n"); RADEONDRICloseScreen(pScreen); info->directRenderingEnabled = FALSE; } } #endif xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "Initializing fb layer\n"); if (info->r600_shadow_fb) { info->fb_shadow = calloc(1, pScrn->displayWidth * pScrn->virtualY * ((pScrn->bitsPerPixel + 7) >> 3)); if (info->fb_shadow == NULL) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to allocate shadow framebuffer\n"); info->r600_shadow_fb = FALSE; } else { if (!fbScreenInit(pScreen, info->fb_shadow, pScrn->virtualX, pScrn->virtualY, pScrn->xDpi, pScrn->yDpi, pScrn->displayWidth, pScrn->bitsPerPixel)) return FALSE; } } if (info->r600_shadow_fb == FALSE) { /* Init fb layer */ if (!fbScreenInit(pScreen, info->FB + pScrn->fbOffset, pScrn->virtualX, pScrn->virtualY, pScrn->xDpi, pScrn->yDpi, pScrn->displayWidth, pScrn->bitsPerPixel)) return FALSE; } xf86SetBlackWhitePixels(pScreen); if (pScrn->bitsPerPixel > 8) { VisualPtr visual; visual = pScreen->visuals + pScreen->numVisuals; while (--visual >= pScreen->visuals) { if ((visual->class | DynamicClass) == DirectColor) { visual->offsetRed = pScrn->offset.red; visual->offsetGreen = pScrn->offset.green; visual->offsetBlue = pScrn->offset.blue; visual->redMask = pScrn->mask.red; visual->greenMask = pScrn->mask.green; visual->blueMask = pScrn->mask.blue; } } } /* Must be after RGB order fixed */ fbPictureInit (pScreen, 0, 0); #ifdef RENDER if ((s = xf86GetOptValString(info->Options, OPTION_SUBPIXEL_ORDER))) { if (strcmp(s, "RGB") == 0) subPixelOrder = SubPixelHorizontalRGB; else if (strcmp(s, "BGR") == 0) subPixelOrder = SubPixelHorizontalBGR; else if (strcmp(s, "NONE") == 0) subPixelOrder = SubPixelNone; PictureSetSubpixelOrder (pScreen, subPixelOrder); } #endif pScrn->vtSema = TRUE; /* restore the memory map here otherwise we may get a hang when * initializing the drm below */ RADEONInitMemMapRegisters(pScrn, info->ModeReg, info); RADEONRestoreMemMapRegisters(pScrn, info->ModeReg); /* Backing store setup */ xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "Initializing backing store\n"); miInitializeBackingStore(pScreen); xf86SetBackingStore(pScreen); /* DRI finalisation */ #ifdef XF86DRI if (info->directRenderingEnabled && info->cardType==CARD_PCIE && info->dri->pKernelDRMVersion->version_minor >= 19) { if (RADEONDRISetParam(pScrn, RADEON_SETPARAM_PCIGART_LOCATION, info->dri->pciGartOffset) < 0) xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "[drm] failed set pci gart location\n"); if (info->dri->pKernelDRMVersion->version_minor >= 26) { if (RADEONDRISetParam(pScrn, RADEON_SETPARAM_PCIGART_TABLE_SIZE, info->dri->pciGartSize) < 0) xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "[drm] failed set pci gart table size\n"); } } if (info->directRenderingEnabled) { xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "DRI Finishing init !\n"); info->directRenderingEnabled = RADEONDRIFinishScreenInit(pScreen); } if (info->directRenderingEnabled) { /* DRI final init might have changed the memory map, we need to adjust * our local image to make sure we restore them properly on mode * changes or VT switches */ RADEONAdjustMemMapRegisters(pScrn, info->ModeReg); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Direct rendering enabled\n"); /* we might already be in tiled mode, tell drm about it */ if (info->directRenderingEnabled && info->tilingEnabled) { if (RADEONDRISetParam(pScrn, RADEON_SETPARAM_SWITCH_TILING, (info->tilingEnabled ? 1 : 0)) < 0) xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "[drm] failed changing tiling status\n"); } } else { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Direct rendering disabled\n"); } #endif /* Make sure surfaces are allright since DRI setup may have changed them */ if (info->ChipFamily < CHIP_FAMILY_R600) { xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "Setting up final surfaces\n"); RADEONChangeSurfaces(pScrn); } /* Enable aceleration */ if (!xf86ReturnOptValBool(info->Options, OPTION_NOACCEL, FALSE)) { xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "Initializing Acceleration\n"); if (RADEONAccelInit(pScreen)) { xf86DrvMsg(scrnIndex, X_INFO, "Acceleration enabled\n"); info->accelOn = TRUE; } else { xf86DrvMsg(scrnIndex, X_ERROR, "Acceleration initialization failed\n"); xf86DrvMsg(scrnIndex, X_INFO, "Acceleration disabled\n"); info->accelOn = FALSE; } } else { xf86DrvMsg(scrnIndex, X_INFO, "Acceleration disabled\n"); info->accelOn = FALSE; } /* Init DPMS */ xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "Initializing DPMS\n"); xf86DPMSInit(pScreen, xf86DPMSSet, 0); xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "Initializing Cursor\n"); /* Set Silken Mouse */ xf86SetSilkenMouse(pScreen); /* Cursor setup */ miDCInitialize(pScreen, xf86GetPointerScreenFuncs()); /* Hardware cursor setup */ if (!xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE)) { if (RADEONCursorInit(pScreen)) { #ifdef USE_XAA if (!info->useEXA) { int width, height; if (xf86QueryLargestOffscreenArea(pScreen, &width, &height, 0, 0, 0)) { xf86DrvMsg(scrnIndex, X_INFO, "Largest offscreen area available: %d x %d\n", width, height); } } #endif /* USE_XAA */ } else { xf86DrvMsg(scrnIndex, X_ERROR, "Hardware cursor initialization failed\n"); xf86DrvMsg(scrnIndex, X_INFO, "Using software cursor\n"); } } else { xf86DrvMsg(scrnIndex, X_INFO, "Using software cursor\n"); } /* DGA setup */ #ifdef XFreeXDGA xf86DiDGAInit(pScreen, info->LinearAddr + pScrn->fbOffset); #endif /* Init Xv */ xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "Initializing Xv\n"); RADEONInitVideo(pScreen); if (info->r600_shadow_fb == TRUE) { if (!shadowSetup(pScreen)) { return FALSE; } } /* Clear the framebuffer */ memset(info->FB + pScrn->fbOffset, 0, pScrn->virtualY * pScrn->displayWidth * info->CurrentLayout.pixel_bytes); pScrn->pScreen = pScreen; /* set the modes with desired rotation, etc. */ if (!xf86SetDesiredModes (pScrn)) return FALSE; /* Provide SaveScreen & wrap BlockHandler and CloseScreen */ /* Wrap CloseScreen */ info->CloseScreen = pScreen->CloseScreen; pScreen->CloseScreen = RADEONCloseScreen; pScreen->SaveScreen = RADEONSaveScreen; info->BlockHandler = pScreen->BlockHandler; pScreen->BlockHandler = RADEONBlockHandler; info->CreateScreenResources = pScreen->CreateScreenResources; pScreen->CreateScreenResources = RADEONCreateScreenResources; if (!xf86CrtcScreenInit (pScreen)) return FALSE; /* Colormap setup */ xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "Initializing color map\n"); if (!miCreateDefColormap(pScreen)) return FALSE; /* all radeons support 10 bit CLUTs */ if (!xf86HandleColormaps(pScreen, 256, 10, RADEONLoadPalette, NULL, CMAP_PALETTED_TRUECOLOR #if 0 /* This option messes up text mode! (eich@suse.de) */ | CMAP_LOAD_EVEN_IF_OFFSCREEN #endif | CMAP_RELOAD_ON_MODE_SWITCH)) return FALSE; /* Note unused options */ if (serverGeneration == 1) xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options); xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "RADEONScreenInit finished\n"); return TRUE; } /* Write memory mapping registers */ void RADEONRestoreMemMapRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore) { RADEONInfoPtr info = RADEONPTR(pScrn); RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); unsigned char *RADEONMMIO = info->MMIO; int timeout; uint32_t mc_fb_loc, mc_agp_loc, mc_agp_loc_hi; radeon_read_mc_fb_agp_location(pScrn, LOC_FB | LOC_AGP, &mc_fb_loc, &mc_agp_loc, &mc_agp_loc_hi); if (info->IsSecondary) return; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "RADEONRestoreMemMapRegisters() : \n"); xf86DrvMsg(pScrn->scrnIndex, X_INFO, " MC_FB_LOCATION : 0x%08x 0x%08x\n", (unsigned)restore->mc_fb_location, (unsigned int)mc_fb_loc); xf86DrvMsg(pScrn->scrnIndex, X_INFO, " MC_AGP_LOCATION : 0x%08x\n", (unsigned)restore->mc_agp_location); if (IS_DCE4_VARIANT) { if (mc_fb_loc != restore->mc_fb_location || mc_agp_loc != restore->mc_agp_location) { uint32_t tmp; //XXX //RADEONWaitForIdleMMIO(pScrn); /* disable VGA rendering core */ OUTREG(AVIVO_VGA_RENDER_CONTROL, INREG(AVIVO_VGA_RENDER_CONTROL) & ~AVIVO_VGA_VSTATUS_CNTL_MASK); OUTREG(AVIVO_D1VGA_CONTROL, INREG(AVIVO_D1VGA_CONTROL) & ~AVIVO_DVGA_CONTROL_MODE_ENABLE); OUTREG(AVIVO_D2VGA_CONTROL, INREG(AVIVO_D2VGA_CONTROL) & ~AVIVO_DVGA_CONTROL_MODE_ENABLE); OUTREG(EVERGREEN_D3VGA_CONTROL, INREG(EVERGREEN_D3VGA_CONTROL) & ~AVIVO_DVGA_CONTROL_MODE_ENABLE); OUTREG(EVERGREEN_D4VGA_CONTROL, INREG(EVERGREEN_D4VGA_CONTROL) & ~AVIVO_DVGA_CONTROL_MODE_ENABLE); OUTREG(EVERGREEN_D5VGA_CONTROL, INREG(EVERGREEN_D5VGA_CONTROL) & ~AVIVO_DVGA_CONTROL_MODE_ENABLE); OUTREG(EVERGREEN_D6VGA_CONTROL, INREG(EVERGREEN_D6VGA_CONTROL) & ~AVIVO_DVGA_CONTROL_MODE_ENABLE); /* Stop display & memory access */ tmp = INREG(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET); OUTREG(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, tmp & ~EVERGREEN_CRTC_MASTER_EN); tmp = INREG(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET); tmp = INREG(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET); OUTREG(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, tmp & ~EVERGREEN_CRTC_MASTER_EN); tmp = INREG(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET); if (!IS_DCE41_VARIANT) { tmp = INREG(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET); OUTREG(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, tmp & ~EVERGREEN_CRTC_MASTER_EN); tmp = INREG(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET); tmp = INREG(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET); OUTREG(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, tmp & ~EVERGREEN_CRTC_MASTER_EN); tmp = INREG(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET); tmp = INREG(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET); OUTREG(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, tmp & ~EVERGREEN_CRTC_MASTER_EN); tmp = INREG(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET); tmp = INREG(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET); OUTREG(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, tmp & ~EVERGREEN_CRTC_MASTER_EN); tmp = INREG(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET); } usleep(10000); timeout = 0; while (!(radeon_get_mc_idle(pScrn))) { if (++timeout > 1000000) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Timeout trying to update memory controller settings !\n"); xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "You will probably crash now ... \n"); /* Nothing we can do except maybe try to kill the server, * let's wait 2 seconds to leave the above message a chance * to maybe hit the disk and continue trying to setup despite * the MC being non-idle */ usleep(2000000); } usleep(10); } radeon_write_mc_fb_agp_location(pScrn, LOC_FB | LOC_AGP, restore->mc_fb_location, restore->mc_agp_location, restore->mc_agp_location_hi); OUTREG(R600_HDP_NONSURFACE_BASE, (restore->mc_fb_location & 0xffff) << 16); } } else if (IS_AVIVO_VARIANT) { if (mc_fb_loc != restore->mc_fb_location || mc_agp_loc != restore->mc_agp_location) { uint32_t tmp; RADEONWaitForIdleMMIO(pScrn); /* disable VGA rendering core */ OUTREG(AVIVO_VGA_RENDER_CONTROL, INREG(AVIVO_VGA_RENDER_CONTROL) &~ AVIVO_VGA_VSTATUS_CNTL_MASK); OUTREG(AVIVO_D1VGA_CONTROL, INREG(AVIVO_D1VGA_CONTROL) & ~AVIVO_DVGA_CONTROL_MODE_ENABLE); OUTREG(AVIVO_D2VGA_CONTROL, INREG(AVIVO_D2VGA_CONTROL) & ~AVIVO_DVGA_CONTROL_MODE_ENABLE); /* Stop display & memory access */ tmp = INREG(AVIVO_D1CRTC_CONTROL); OUTREG(AVIVO_D1CRTC_CONTROL, tmp & ~AVIVO_CRTC_EN); tmp = INREG(AVIVO_D2CRTC_CONTROL); OUTREG(AVIVO_D2CRTC_CONTROL, tmp & ~AVIVO_CRTC_EN); tmp = INREG(AVIVO_D2CRTC_CONTROL); usleep(10000); timeout = 0; while (!(radeon_get_mc_idle(pScrn))) { if (++timeout > 1000000) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Timeout trying to update memory controller settings !\n"); xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "You will probably crash now ... \n"); /* Nothing we can do except maybe try to kill the server, * let's wait 2 seconds to leave the above message a chance * to maybe hit the disk and continue trying to setup despite * the MC being non-idle */ usleep(2000000); } usleep(10); } radeon_write_mc_fb_agp_location(pScrn, LOC_FB | LOC_AGP, restore->mc_fb_location, restore->mc_agp_location, restore->mc_agp_location_hi); if (info->ChipFamily < CHIP_FAMILY_R600) { OUTREG(AVIVO_HDP_FB_LOCATION, restore->mc_fb_location); } else { OUTREG(R600_HDP_NONSURFACE_BASE, (restore->mc_fb_location << 16) & 0xff0000); } /* Reset the engine and HDP */ if (info->ChipFamily < CHIP_FAMILY_R600) RADEONEngineReset(pScrn); } } else { /* Write memory mapping registers only if their value change * since we must ensure no access is done while they are * reprogrammed */ if (mc_fb_loc != restore->mc_fb_location || mc_agp_loc != restore->mc_agp_location) { uint32_t crtc_ext_cntl, crtc_gen_cntl, crtc2_gen_cntl=0, ov0_scale_cntl; uint32_t old_mc_status; xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, " Map Changed ! Applying ...\n"); /* Make sure engine is idle. We assume the CCE is stopped * at this point */ RADEONWaitForIdleMMIO(pScrn); if (info->IsIGP) goto igp_no_mcfb; /* Capture MC_STATUS in case things go wrong ... */ old_mc_status = INREG(RADEON_MC_STATUS); /* Stop display & memory access */ ov0_scale_cntl = INREG(RADEON_OV0_SCALE_CNTL); OUTREG(RADEON_OV0_SCALE_CNTL, ov0_scale_cntl & ~RADEON_SCALER_ENABLE); crtc_ext_cntl = INREG(RADEON_CRTC_EXT_CNTL); OUTREG(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl | RADEON_CRTC_DISPLAY_DIS); crtc_gen_cntl = INREG(RADEON_CRTC_GEN_CNTL); RADEONWaitForVerticalSync(pScrn); OUTREG(RADEON_CRTC_GEN_CNTL, (crtc_gen_cntl & ~(RADEON_CRTC_CUR_EN | RADEON_CRTC_ICON_EN)) | RADEON_CRTC_DISP_REQ_EN_B | RADEON_CRTC_EXT_DISP_EN); if (pRADEONEnt->HasCRTC2) { crtc2_gen_cntl = INREG(RADEON_CRTC2_GEN_CNTL); RADEONWaitForVerticalSync2(pScrn); OUTREG(RADEON_CRTC2_GEN_CNTL, (crtc2_gen_cntl & ~(RADEON_CRTC2_CUR_EN | RADEON_CRTC2_ICON_EN)) | RADEON_CRTC2_DISP_REQ_EN_B); } /* Make sure the chip settles down (paranoid !) */ usleep(100000); timeout = 0; while (!(radeon_get_mc_idle(pScrn))) { if (++timeout > 1000000) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Timeout trying to update memory controller settings !\n"); xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "MC_STATUS = 0x%08x (on entry = 0x%08x)\n", (unsigned int)INREG(RADEON_MC_STATUS), (unsigned int)old_mc_status); xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "You will probably crash now ... \n"); /* Nothing we can do except maybe try to kill the server, * let's wait 2 seconds to leave the above message a chance * to maybe hit the disk and continue trying to setup despite * the MC being non-idle */ usleep(2000000); } usleep(10); } /* Update maps, first clearing out AGP to make sure we don't get * a temporary overlap */ OUTREG(RADEON_MC_AGP_LOCATION, 0xfffffffc); OUTREG(RADEON_MC_FB_LOCATION, restore->mc_fb_location); radeon_write_mc_fb_agp_location(pScrn, LOC_FB | LOC_AGP, restore->mc_fb_location, 0xfffffffc, 0); igp_no_mcfb: radeon_write_mc_fb_agp_location(pScrn, LOC_AGP, 0, restore->mc_agp_location, 0); /* Make sure map fully reached the chip */ (void)INREG(RADEON_MC_FB_LOCATION); xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, " Map applied, resetting engine ...\n"); /* Reset the engine and HDP */ RADEONEngineReset(pScrn); /* Make sure we have sane offsets before re-enabling the CRTCs, disable * stereo, clear offsets, and wait for offsets to catch up with hw */ OUTREG(RADEON_CRTC_OFFSET_CNTL, RADEON_CRTC_OFFSET_FLIP_CNTL); OUTREG(RADEON_CRTC_OFFSET, 0); OUTREG(RADEON_CUR_OFFSET, 0); timeout = 0; while(INREG(RADEON_CRTC_OFFSET) & RADEON_CRTC_OFFSET__GUI_TRIG_OFFSET) { if (timeout++ > 1000000) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Timeout waiting for CRTC offset to update !\n"); break; } usleep(1000); } if (pRADEONEnt->HasCRTC2) { OUTREG(RADEON_CRTC2_OFFSET_CNTL, RADEON_CRTC2_OFFSET_FLIP_CNTL); OUTREG(RADEON_CRTC2_OFFSET, 0); OUTREG(RADEON_CUR2_OFFSET, 0); timeout = 0; while(INREG(RADEON_CRTC2_OFFSET) & RADEON_CRTC2_OFFSET__GUI_TRIG_OFFSET) { if (timeout++ > 1000000) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Timeout waiting for CRTC2 offset to update !\n"); break; } usleep(1000); } } } xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "Updating display base addresses...\n"); OUTREG(RADEON_DISPLAY_BASE_ADDR, restore->display_base_addr); if (pRADEONEnt->HasCRTC2) OUTREG(RADEON_DISPLAY2_BASE_ADDR, restore->display2_base_addr); OUTREG(RADEON_OV0_BASE_ADDR, restore->ov0_base_addr); (void)INREG(RADEON_OV0_BASE_ADDR); /* More paranoia delays, wait 100ms */ usleep(100000); xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "Memory map updated.\n"); } } #ifdef XF86DRI static void RADEONAdjustMemMapRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save) { RADEONInfoPtr info = RADEONPTR(pScrn); uint32_t fb, agp, agp_hi; int changed = 0; if (info->IsSecondary) return; radeon_read_mc_fb_agp_location(pScrn, LOC_FB | LOC_AGP, &fb, &agp, &agp_hi); if (fb != save->mc_fb_location || agp != save->mc_agp_location || agp_hi != save->mc_agp_location_hi) changed = 1; if (changed) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "DRI init changed memory map, adjusting ...\n"); xf86DrvMsg(pScrn->scrnIndex, X_WARNING, " MC_FB_LOCATION was: 0x%08lx is: 0x%08lx\n", (long unsigned int)info->mc_fb_location, (long unsigned int)fb); xf86DrvMsg(pScrn->scrnIndex, X_WARNING, " MC_AGP_LOCATION was: 0x%08lx is: 0x%08lx\n", (long unsigned int)info->mc_agp_location, (long unsigned int)agp); info->mc_fb_location = fb; info->mc_agp_location = agp; if (info->ChipFamily >= CHIP_FAMILY_R600) info->fbLocation = ((uint64_t)info->mc_fb_location & 0xffff) << 24; else info->fbLocation = ((uint64_t)info->mc_fb_location & 0xffff) << 16; info->accel_state->dst_pitch_offset = (((pScrn->displayWidth * info->CurrentLayout.pixel_bytes / 64) << 22) | ((info->fbLocation + pScrn->fbOffset) >> 10)); RADEONInitMemMapRegisters(pScrn, save, info); RADEONRestoreMemMapRegisters(pScrn, save); } #ifdef USE_EXA if (info->accelDFS || (info->ChipFamily >= CHIP_FAMILY_R600)) { drm_radeon_getparam_t gp; int gart_base; memset(&gp, 0, sizeof(gp)); gp.param = RADEON_PARAM_GART_BASE; gp.value = &gart_base; if (drmCommandWriteRead(info->dri->drmFD, DRM_RADEON_GETPARAM, &gp, sizeof(gp)) < 0) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to determine GART area MC location, not using " "accelerated DownloadFromScreen hook!\n"); info->accelDFS = FALSE; } else { info->gartLocation = gart_base; } } #endif /* USE_EXA */ } #endif /* restore original surface info (for fb console). */ static void RADEONRestoreSurfaces(ScrnInfoPtr pScrn, RADEONSavePtr restore) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; unsigned int surfnr; for ( surfnr = 0; surfnr < 8; surfnr++ ) { OUTREG(RADEON_SURFACE0_INFO + 16 * surfnr, restore->surfaces[surfnr][0]); OUTREG(RADEON_SURFACE0_LOWER_BOUND + 16 * surfnr, restore->surfaces[surfnr][1]); OUTREG(RADEON_SURFACE0_UPPER_BOUND + 16 * surfnr, restore->surfaces[surfnr][2]); } } /* save original surface info (for fb console). */ static void RADEONSaveSurfaces(ScrnInfoPtr pScrn, RADEONSavePtr save) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; unsigned int surfnr; for ( surfnr = 0; surfnr < 8; surfnr++ ) { save->surfaces[surfnr][0] = INREG(RADEON_SURFACE0_INFO + 16 * surfnr); save->surfaces[surfnr][1] = INREG(RADEON_SURFACE0_LOWER_BOUND + 16 * surfnr); save->surfaces[surfnr][2] = INREG(RADEON_SURFACE0_UPPER_BOUND + 16 * surfnr); } } void RADEONChangeSurfaces(ScrnInfoPtr pScrn) { /* the idea here is to only set up front buffer as tiled, and back/depth buffer when needed. Everything else is left as untiled. This means we need to use eplicit src/dst pitch control when blitting, based on the src/target address, and can no longer use a default offset. But OTOH we don't need to dynamically change surfaces (for xv for instance), and some ugly offset / fb reservation (cursor) is gone. And as a bonus, everything actually works... For simplicity, just always update everything (just let the ioctl fail - could do better). All surface addresses are relative to RADEON_MC_FB_LOCATION */ RADEONInfoPtr info = RADEONPTR(pScrn); int cpp = info->CurrentLayout.pixel_bytes; /* depth/front/back pitch must be identical (and the same as displayWidth) */ int width_bytes = pScrn->displayWidth * cpp; int bufferSize = RADEON_ALIGN((RADEON_ALIGN(pScrn->virtualY, 16)) * width_bytes, RADEON_GPU_PAGE_SIZE); unsigned int color_pattern, swap_pattern; if (!info->allowColorTiling) return; swap_pattern = 0; #if X_BYTE_ORDER == X_BIG_ENDIAN switch (pScrn->bitsPerPixel) { case 16: swap_pattern = RADEON_SURF_AP0_SWP_16BPP | RADEON_SURF_AP1_SWP_16BPP; break; case 32: swap_pattern = RADEON_SURF_AP0_SWP_32BPP | RADEON_SURF_AP1_SWP_32BPP; break; } #endif if (info->ChipFamily < CHIP_FAMILY_R200) { color_pattern = RADEON_SURF_TILE_COLOR_MACRO; } else if (IS_R300_VARIANT || IS_AVIVO_VARIANT) { color_pattern = R300_SURF_TILE_COLOR_MACRO; } else { color_pattern = R200_SURF_TILE_COLOR_MACRO; } #ifdef XF86DRI if (info->directRenderingInited) { drm_radeon_surface_free_t drmsurffree; drm_radeon_surface_alloc_t drmsurfalloc; int retvalue; int depthCpp = (info->dri->depthBits - 8) / 4; int depth_width_bytes = pScrn->displayWidth * depthCpp; int depthBufferSize = RADEON_ALIGN((RADEON_ALIGN(pScrn->virtualY, 16)) * depth_width_bytes, RADEON_GPU_PAGE_SIZE); unsigned int depth_pattern; drmsurffree.address = info->dri->frontOffset; retvalue = drmCommandWrite(info->dri->drmFD, DRM_RADEON_SURF_FREE, &drmsurffree, sizeof(drmsurffree)); if (!((info->ChipFamily == CHIP_FAMILY_RV100) || (info->ChipFamily == CHIP_FAMILY_RS100) || (info->ChipFamily == CHIP_FAMILY_RS200))) { drmsurffree.address = info->dri->depthOffset; retvalue = drmCommandWrite(info->dri->drmFD, DRM_RADEON_SURF_FREE, &drmsurffree, sizeof(drmsurffree)); } if (!info->dri->noBackBuffer) { drmsurffree.address = info->dri->backOffset; retvalue = drmCommandWrite(info->dri->drmFD, DRM_RADEON_SURF_FREE, &drmsurffree, sizeof(drmsurffree)); } drmsurfalloc.size = bufferSize; drmsurfalloc.address = info->dri->frontOffset; drmsurfalloc.flags = swap_pattern; if (info->tilingEnabled) { if (IS_R300_VARIANT || IS_AVIVO_VARIANT) drmsurfalloc.flags |= (width_bytes / 8) | color_pattern; else drmsurfalloc.flags |= (width_bytes / 16) | color_pattern; } retvalue = drmCommandWrite(info->dri->drmFD, DRM_RADEON_SURF_ALLOC, &drmsurfalloc, sizeof(drmsurfalloc)); if (retvalue < 0) xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "drm: could not allocate surface for front buffer!\n"); if ((info->dri->have3DWindows) && (!info->dri->noBackBuffer)) { drmsurfalloc.address = info->dri->backOffset; retvalue = drmCommandWrite(info->dri->drmFD, DRM_RADEON_SURF_ALLOC, &drmsurfalloc, sizeof(drmsurfalloc)); if (retvalue < 0) xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "drm: could not allocate surface for back buffer!\n"); } if (info->ChipFamily < CHIP_FAMILY_R200) { if (depthCpp == 2) depth_pattern = RADEON_SURF_TILE_DEPTH_16BPP; else depth_pattern = RADEON_SURF_TILE_DEPTH_32BPP; } else if (IS_R300_VARIANT || IS_AVIVO_VARIANT) { if (depthCpp == 2) depth_pattern = R300_SURF_TILE_COLOR_MACRO; else depth_pattern = R300_SURF_TILE_COLOR_MACRO | R300_SURF_TILE_DEPTH_32BPP; } else { if (depthCpp == 2) depth_pattern = R200_SURF_TILE_DEPTH_16BPP; else depth_pattern = R200_SURF_TILE_DEPTH_32BPP; } /* rv100 and probably the derivative igps don't have depth tiling on all the time? */ if (info->dri->have3DWindows && (!((info->ChipFamily == CHIP_FAMILY_RV100) || (info->ChipFamily == CHIP_FAMILY_RS100) || (info->ChipFamily == CHIP_FAMILY_RS200)))) { drm_radeon_surface_alloc_t drmsurfalloc; drmsurfalloc.size = depthBufferSize; drmsurfalloc.address = info->dri->depthOffset; if (IS_R300_VARIANT || IS_AVIVO_VARIANT) drmsurfalloc.flags = swap_pattern | (depth_width_bytes / 8) | depth_pattern; else drmsurfalloc.flags = swap_pattern | (depth_width_bytes / 16) | depth_pattern; retvalue = drmCommandWrite(info->dri->drmFD, DRM_RADEON_SURF_ALLOC, &drmsurfalloc, sizeof(drmsurfalloc)); if (retvalue < 0) xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "drm: could not allocate surface for depth buffer!\n"); } } else #endif { unsigned int surf_info = swap_pattern; unsigned char *RADEONMMIO = info->MMIO; /* we don't need anything like WaitForFifo, no? */ if (info->tilingEnabled) { if (IS_R300_VARIANT || IS_AVIVO_VARIANT) surf_info |= (width_bytes / 8) | color_pattern; else surf_info |= (width_bytes / 16) | color_pattern; } OUTREG(RADEON_SURFACE0_INFO, surf_info); OUTREG(RADEON_SURFACE0_LOWER_BOUND, 0); OUTREG(RADEON_SURFACE0_UPPER_BOUND, bufferSize - 1); /* xf86DrvMsg(pScrn->scrnIndex, X_INFO, "surface0 set to %x, LB 0x%x UB 0x%x\n", surf_info, 0, bufferSize - 1024);*/ } /* Update surface images */ if (info->ChipFamily < CHIP_FAMILY_R600) RADEONSaveSurfaces(pScrn, info->ModeReg); } /* Read memory map */ static void RADEONSaveMemMapRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; radeon_read_mc_fb_agp_location(pScrn, LOC_FB | LOC_AGP, &save->mc_fb_location, &save->mc_agp_location, &save->mc_agp_location_hi); if (!IS_AVIVO_VARIANT) { save->display_base_addr = INREG(RADEON_DISPLAY_BASE_ADDR); save->display2_base_addr = INREG(RADEON_DISPLAY2_BASE_ADDR); save->ov0_base_addr = INREG(RADEON_OV0_BASE_ADDR); } } /* Read palette data */ static void RADEONSavePalette(ScrnInfoPtr pScrn, RADEONSavePtr save) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; int i; PAL_SELECT(1); INPAL_START(0); for (i = 0; i < 256; i++) { save->palette2[i] = INREG(RADEON_PALETTE_30_DATA); } PAL_SELECT(0); INPAL_START(0); for (i = 0; i < 256; i++) { save->palette[i] = INREG(RADEON_PALETTE_30_DATA); } } static void RADEONRestorePalette(ScrnInfoPtr pScrn, RADEONSavePtr restore) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; int i; PAL_SELECT(1); OUTPAL_START(0); for (i = 0; i < 256; i++) { OUTREG(RADEON_PALETTE_30_DATA, restore->palette2[i]); } PAL_SELECT(0); OUTPAL_START(0); for (i = 0; i < 256; i++) { OUTREG(RADEON_PALETTE_30_DATA, restore->palette[i]); } } static void dce4_save_grph(ScrnInfoPtr pScrn, struct dce4_main_block_state *state, uint32_t offset) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; state->grph.enable = INREG(offset + EVERGREEN_GRPH_ENABLE); state->grph.control = INREG(offset + EVERGREEN_GRPH_CONTROL); state->grph.swap_control = INREG(offset + EVERGREEN_GRPH_SWAP_CONTROL); state->grph.prim_surf_addr = INREG(offset + EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS); state->grph.sec_surf_addr = INREG(offset + EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS); state->grph.pitch = INREG(offset + EVERGREEN_GRPH_PITCH); state->grph.prim_surf_addr_hi = INREG(offset + EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH); state->grph.sec_surf_addr_hi = INREG(offset + EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH); state->grph.x_offset = INREG(offset + EVERGREEN_GRPH_SURFACE_OFFSET_X); state->grph.y_offset = INREG(offset + EVERGREEN_GRPH_SURFACE_OFFSET_Y); state->grph.x_start = INREG(offset + EVERGREEN_GRPH_X_START); state->grph.y_start = INREG(offset + EVERGREEN_GRPH_Y_START); state->grph.x_end = INREG(offset + EVERGREEN_GRPH_X_END); state->grph.y_end = INREG(offset + EVERGREEN_GRPH_Y_END); state->grph.desktop_height = INREG(offset + EVERGREEN_DESKTOP_HEIGHT); state->grph.viewport_start = INREG(offset + EVERGREEN_VIEWPORT_START); state->grph.viewport_size = INREG(offset + EVERGREEN_VIEWPORT_SIZE); state->grph.mode_data_format = INREG(offset + EVERGREEN_DATA_FORMAT); } static void dce4_restore_grph(ScrnInfoPtr pScrn, struct dce4_main_block_state *state, uint32_t offset) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; OUTREG(offset + EVERGREEN_GRPH_ENABLE, state->grph.enable); OUTREG(offset + EVERGREEN_GRPH_CONTROL, state->grph.control); OUTREG(offset + EVERGREEN_GRPH_SWAP_CONTROL, state->grph.swap_control); OUTREG(offset + EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS, state->grph.prim_surf_addr); OUTREG(offset + EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS, state->grph.sec_surf_addr); OUTREG(offset + EVERGREEN_GRPH_PITCH, state->grph.pitch); OUTREG(offset + EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, state->grph.prim_surf_addr_hi); OUTREG(offset + EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, state->grph.sec_surf_addr_hi); OUTREG(offset + EVERGREEN_GRPH_SURFACE_OFFSET_X, state->grph.x_offset); OUTREG(offset + EVERGREEN_GRPH_SURFACE_OFFSET_Y, state->grph.y_offset); OUTREG(offset + EVERGREEN_GRPH_X_START, state->grph.x_start); OUTREG(offset + EVERGREEN_GRPH_Y_START, state->grph.y_start); OUTREG(offset + EVERGREEN_GRPH_X_END, state->grph.x_end); OUTREG(offset + EVERGREEN_GRPH_Y_END, state->grph.y_end); OUTREG(offset + EVERGREEN_DESKTOP_HEIGHT, state->grph.desktop_height); OUTREG(offset + EVERGREEN_VIEWPORT_START, state->grph.viewport_start); OUTREG(offset + EVERGREEN_VIEWPORT_SIZE, state->grph.viewport_size); OUTREG(offset + EVERGREEN_DATA_FORMAT, state->grph.mode_data_format); } static uint32_t dce4_dac_regs[] = { 0x6690, 0x6694, 0x66b0, 0x66cc, 0x66d0, 0x66d4, 0x66d8 }; static uint32_t dce4_scl_regs[] = { 0x6d08, 0x6d0c, 0x6d14, 0x6d1c }; static uint32_t dce4_dig_regs[] = { 0x7000, 0x7004, 0x7008, 0x700c, 0x7010, 0x7014, 0x71f0, 0x71f4, 0x71f8, 0x71fc, 0x7200, 0x7204, 0x7208, 0x720c, 0x7210, 0x7218, 0x721c, 0x7220, 0x7230}; static uint32_t dce4_crtc_regs[] = { 0x6e00, 0x6e04, 0x6e08, 0x6e0c, 0x6e1c, 0x6e34, 0x6e38, 0x6e3c, 0x6e70, 0x6e74, 0x6e78}; #define DCE4_REG_SCL_NUM (sizeof(dce4_scl_regs)/sizeof(uint32_t)) #define DCE4_REG_CRTC_NUM (sizeof(dce4_crtc_regs)/sizeof(uint32_t)) #define DCE4_REG_DIG_NUM (sizeof(dce4_dig_regs)/sizeof(uint32_t)) #define DCE4_DAC_NUM (sizeof(dce4_dac_regs)/sizeof(uint32_t)) static void dce4_save_crtc(ScrnInfoPtr pScrn, struct dce4_main_block_state *state, uint32_t offset) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; int i; for (i = 0; i < DCE4_REG_CRTC_NUM; i++) state->crtc[i] = INREG(offset + dce4_crtc_regs[i]); } static void dce4_restore_crtc(ScrnInfoPtr pScrn, struct dce4_main_block_state *state, uint32_t offset) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; int i; for (i = 0; i < DCE4_REG_CRTC_NUM; i++) OUTREG(offset + dce4_crtc_regs[i], state->crtc[i]); } static void dce4_save_scl(ScrnInfoPtr pScrn, struct dce4_main_block_state *state, uint32_t offset) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; int i; for (i = 0; i < DCE4_REG_SCL_NUM; i++) state->scl[i] = INREG(offset + dce4_scl_regs[i]); } static void dce4_restore_scl(ScrnInfoPtr pScrn, struct dce4_main_block_state *state, uint32_t offset) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; int i; for (i = 0; i < DCE4_REG_SCL_NUM; i++) OUTREG(offset + dce4_scl_regs[i], state->scl[i]); } static void dce4_save_fmt(ScrnInfoPtr pScrn, struct dce4_main_block_state *state, uint32_t offset) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; int i, index = 0; for (i = 0x6fb4; i <= 0x6fd4; i += 4) state->fmt[index++] = INREG(offset + i); } static void dce4_restore_fmt(ScrnInfoPtr pScrn, struct dce4_main_block_state *state, uint32_t offset) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; int i, index = 0; for (i = 0x6fb4; i <= 0x6fd4; i += 4) OUTREG(offset + i, state->fmt[index++]); } static void dce4_save_dig(ScrnInfoPtr pScrn, struct dce4_main_block_state *state, uint32_t offset) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; int i; for (i = 0; i < DCE4_REG_DIG_NUM; i++) state->dig[i] = INREG(offset + dce4_dig_regs[i]); } static void dce4_restore_dig(ScrnInfoPtr pScrn, struct dce4_main_block_state *state, uint32_t offset) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; int i; for (i = 0; i < DCE4_REG_DIG_NUM; i++) OUTREG(offset + dce4_dig_regs[i], state->dig[i]); } static void dce4_save_block(ScrnInfoPtr pScrn, struct dce4_main_block_state *state, uint32_t offset) { dce4_save_grph(pScrn, state, offset); dce4_save_crtc(pScrn, state, offset); dce4_save_scl(pScrn, state, offset); dce4_save_dig(pScrn, state, offset); dce4_save_fmt(pScrn, state, offset); } static void dce4_restore_block(ScrnInfoPtr pScrn, struct dce4_main_block_state *state, uint32_t offset) { dce4_restore_grph(pScrn, state, offset); dce4_restore_crtc(pScrn, state, offset); dce4_restore_scl(pScrn, state, offset); dce4_restore_dig(pScrn, state, offset); dce4_restore_fmt(pScrn, state, offset); } static void dce4_save_uniphy(ScrnInfoPtr pScrn, struct dce4_state *state, int index) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; uint32_t uniphy_offset[6] = {0x0, 0x30, 0x60, 0x100, 0x130, 0x160 }; int i, ri = 0; for (i = 0; i < 0x18; i+=4) state->uniphy[index][ri++] = INREG(0x6600 + uniphy_offset[index] + i); } static void dce4_restore_uniphy(ScrnInfoPtr pScrn, struct dce4_state *state, int index) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; uint32_t uniphy_offset[6] = {0x0, 0x30, 0x60, 0x100, 0x130, 0x160 }; int i, ri = 0; for (i = 0; i <= 0x18; i+=4) OUTREG(0x6600 + uniphy_offset[index] + i, state->uniphy[index][ri++]); } static void dce4_save_dig_regs(ScrnInfoPtr pScrn, struct dce4_state *state) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; int i, ri = 0; for (i = 0x6578; i <= 0x6598; i += 4) state->dig[ri++] = INREG(i); for (i = 0x65ac; i <= 0x65d8; i += 4) state->dig[ri++] = INREG(i); } static void dce4_restore_dig_regs(ScrnInfoPtr pScrn, struct dce4_state *state) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; int i, ri = 0; for (i = 0x6578; i <= 0x6598; i += 4) OUTREG(i, state->dig[ri++]); for (i = 0x65ac; i <= 0x65d8; i += 4) OUTREG(i, state->dig[ri++]); } static void dce4_save_pll_regs(ScrnInfoPtr pScrn, struct dce4_state *state) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; int i, ri = 0; for (i = 0x360; i <= 0x368; i += 4) state->vga_pll[0][ri++] = INREG(i); ri = 0; for (i = 0x370; i <= 0x378; i += 4) state->vga_pll[1][ri++] = INREG(i); ri = 0; for (i = 0x390; i <= 0x398; i += 4) state->vga_pll[2][ri++] = INREG(i); ri = 0; for (i = 0x400; i <= 0x408; i += 4) state->pll[0][ri++] = INREG(i); for (i = 0x410; i <= 0x43c; i += 4) state->pll[0][ri++] = INREG(i); ri = 0; for (i = 0x440; i <= 0x448; i += 4) state->pll[1][ri++] = INREG(i); for (i = 0x450; i <= 0x47c; i += 4) state->pll[1][ri++] = INREG(i); ri = 0; for (i = 0x500; i <= 0x550; i += 0x10) state->pll_route[ri++] = INREG(i); } static void dce4_restore_pll_regs(ScrnInfoPtr pScrn, struct dce4_state *state) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; int i, ri = 0; for (i = 0x360; i <= 0x368; i += 4) OUTREG(i, state->vga_pll[0][ri++]); ri = 0; for (i = 0x370; i <= 0x378; i += 4) OUTREG(i, state->vga_pll[1][ri++]); ri = 0; for (i = 0x390; i <= 0x398; i += 4) OUTREG(i, state->vga_pll[2][ri++]); ri = 0; for (i = 0x400; i <= 0x408; i += 4) OUTREG(i, state->pll[0][ri++]); for (i = 0x410; i <= 0x43c; i += 4) OUTREG(i, state->pll[0][ri++]); ri = 0; for (i = 0x440; i <= 0x448; i += 4) OUTREG(i, state->pll[1][ri++]); for (i = 0x450; i <= 0x47c; i += 4) OUTREG(i, state->pll[1][ri++]); ri = 0; for (i = 0x500; i <= 0x550; i += 0x10) OUTREG(i, state->pll_route[ri++]); } static void dce4_save(ScrnInfoPtr pScrn, RADEONSavePtr save) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; struct dce4_state *state = &save->dce4; int i, j; uint32_t crtc_offset[] = {EVERGREEN_CRTC0_REGISTER_OFFSET, EVERGREEN_CRTC1_REGISTER_OFFSET, EVERGREEN_CRTC2_REGISTER_OFFSET, EVERGREEN_CRTC3_REGISTER_OFFSET, EVERGREEN_CRTC4_REGISTER_OFFSET, EVERGREEN_CRTC5_REGISTER_OFFSET}; state->vga1_cntl = INREG(AVIVO_D1VGA_CONTROL); state->vga2_cntl = INREG(AVIVO_D2VGA_CONTROL); state->vga3_cntl = INREG(EVERGREEN_D3VGA_CONTROL); state->vga4_cntl = INREG(EVERGREEN_D4VGA_CONTROL); state->vga5_cntl = INREG(EVERGREEN_D5VGA_CONTROL); state->vga6_cntl = INREG(EVERGREEN_D6VGA_CONTROL); state->vga_render_control = INREG(AVIVO_VGA_RENDER_CONTROL); dce4_save_pll_regs(pScrn, state); dce4_save_dig_regs(pScrn, state); for (i = 0; i < 6; i++) dce4_save_block(pScrn, &state->block[i], crtc_offset[i]); for (i = 0; i < 6; i++) dce4_save_uniphy(pScrn, state, i); for (i = 0; i < 2; i++) { for (j = 0; j < DCE4_DAC_NUM; j++) { uint32_t offset = i ? 0x100 : 0x0; state->dac[i][j] = INREG(dce4_dac_regs[j] + offset); } } } static void dce4_restore(ScrnInfoPtr pScrn, RADEONSavePtr restore) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; struct dce4_state *state = &restore->dce4; int i, j; uint32_t crtc_offset[] = {EVERGREEN_CRTC0_REGISTER_OFFSET, EVERGREEN_CRTC1_REGISTER_OFFSET, EVERGREEN_CRTC2_REGISTER_OFFSET, EVERGREEN_CRTC3_REGISTER_OFFSET, EVERGREEN_CRTC4_REGISTER_OFFSET, EVERGREEN_CRTC5_REGISTER_OFFSET}; OUTREG(AVIVO_D1VGA_CONTROL, state->vga1_cntl); OUTREG(AVIVO_D2VGA_CONTROL, state->vga2_cntl);; OUTREG(EVERGREEN_D3VGA_CONTROL, state->vga3_cntl); OUTREG(EVERGREEN_D4VGA_CONTROL, state->vga4_cntl); OUTREG(EVERGREEN_D5VGA_CONTROL, state->vga5_cntl); OUTREG(EVERGREEN_D6VGA_CONTROL, state->vga6_cntl); OUTREG(AVIVO_VGA_RENDER_CONTROL, state->vga_render_control); dce4_restore_dig_regs(pScrn, state); dce4_restore_pll_regs(pScrn, state); for (i = 0; i < 6; i++) dce4_restore_uniphy(pScrn, state, i); for (i = 0; i < 6; i++) dce4_restore_block(pScrn, &state->block[i], crtc_offset[i]); for (i = 0; i < 2; i++) { for (j = 0; j < DCE4_DAC_NUM; j++) { uint32_t offset = i ? 0x100 : 0x0; OUTREG(dce4_dac_regs[j] + offset, state->dac[i][j]); } } } static void avivo_save(ScrnInfoPtr pScrn, RADEONSavePtr save) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; struct avivo_state *state = &save->avivo; int i, j; // state->vga_memory_base = INREG(AVIVO_VGA_MEMORY_BASE); // state->vga_fb_start = INREG(AVIVO_VGA_FB_START); state->vga1_cntl = INREG(AVIVO_D1VGA_CONTROL); state->vga2_cntl = INREG(AVIVO_D2VGA_CONTROL); state->vga_render_control = INREG(AVIVO_VGA_RENDER_CONTROL); state->crtc_master_en = INREG(AVIVO_DC_CRTC_MASTER_EN); state->crtc_tv_control = INREG(AVIVO_DC_CRTC_TV_CONTROL); state->dc_lb_memory_split = INREG(AVIVO_DC_LB_MEMORY_SPLIT); state->pll[0].ref_div_src = INREG(AVIVO_EXT1_PPLL_REF_DIV_SRC); state->pll[0].ref_div = INREG(AVIVO_EXT1_PPLL_REF_DIV); state->pll[0].fb_div = INREG(AVIVO_EXT1_PPLL_FB_DIV); state->pll[0].post_div_src = INREG(AVIVO_EXT1_PPLL_POST_DIV_SRC); state->pll[0].post_div = INREG(AVIVO_EXT1_PPLL_POST_DIV); state->pll[0].ext_ppll_cntl = INREG(AVIVO_EXT1_PPLL_CNTL); state->pll[0].pll_cntl = INREG(AVIVO_P1PLL_CNTL); state->pll[0].int_ss_cntl = INREG(AVIVO_P1PLL_INT_SS_CNTL); state->pll[1].ref_div_src = INREG(AVIVO_EXT1_PPLL_REF_DIV_SRC); state->pll[1].ref_div = INREG(AVIVO_EXT2_PPLL_REF_DIV); state->pll[1].fb_div = INREG(AVIVO_EXT2_PPLL_FB_DIV); state->pll[1].post_div_src = INREG(AVIVO_EXT2_PPLL_POST_DIV_SRC); state->pll[1].post_div = INREG(AVIVO_EXT2_PPLL_POST_DIV); state->pll[1].ext_ppll_cntl = INREG(AVIVO_EXT2_PPLL_CNTL); state->pll[1].pll_cntl = INREG(AVIVO_P2PLL_CNTL); state->pll[1].int_ss_cntl = INREG(AVIVO_P2PLL_INT_SS_CNTL); state->vga25_ppll.ref_div_src = INREG(AVIVO_VGA25_PPLL_REF_DIV_SRC); state->vga25_ppll.ref_div = INREG(AVIVO_VGA25_PPLL_REF_DIV); state->vga25_ppll.fb_div = INREG(AVIVO_VGA25_PPLL_FB_DIV); state->vga25_ppll.post_div_src = INREG(AVIVO_VGA25_PPLL_POST_DIV_SRC); state->vga25_ppll.post_div = INREG(AVIVO_VGA25_PPLL_POST_DIV); state->vga25_ppll.pll_cntl = INREG(AVIVO_VGA25_PPLL_CNTL); state->vga28_ppll.ref_div_src = INREG(AVIVO_VGA28_PPLL_REF_DIV_SRC); state->vga28_ppll.ref_div = INREG(AVIVO_VGA28_PPLL_REF_DIV); state->vga28_ppll.fb_div = INREG(AVIVO_VGA28_PPLL_FB_DIV); state->vga28_ppll.post_div_src = INREG(AVIVO_VGA28_PPLL_POST_DIV_SRC); state->vga28_ppll.post_div = INREG(AVIVO_VGA28_PPLL_POST_DIV); state->vga28_ppll.pll_cntl = INREG(AVIVO_VGA28_PPLL_CNTL); state->vga41_ppll.ref_div_src = INREG(AVIVO_VGA41_PPLL_REF_DIV_SRC); state->vga41_ppll.ref_div = INREG(AVIVO_VGA41_PPLL_REF_DIV); state->vga41_ppll.fb_div = INREG(AVIVO_VGA41_PPLL_FB_DIV); state->vga41_ppll.post_div_src = INREG(AVIVO_VGA41_PPLL_POST_DIV_SRC); state->vga41_ppll.post_div = INREG(AVIVO_VGA41_PPLL_POST_DIV); state->vga41_ppll.pll_cntl = INREG(AVIVO_VGA41_PPLL_CNTL); state->crtc[0].pll_source = INREG(AVIVO_PCLK_CRTC1_CNTL); state->crtc[0].h_total = INREG(AVIVO_D1CRTC_H_TOTAL); state->crtc[0].h_blank_start_end = INREG(AVIVO_D1CRTC_H_BLANK_START_END); state->crtc[0].h_sync_a = INREG(AVIVO_D1CRTC_H_SYNC_A); state->crtc[0].h_sync_a_cntl = INREG(AVIVO_D1CRTC_H_SYNC_A_CNTL); state->crtc[0].h_sync_b = INREG(AVIVO_D1CRTC_H_SYNC_B); state->crtc[0].h_sync_b_cntl = INREG(AVIVO_D1CRTC_H_SYNC_B_CNTL); state->crtc[0].v_total = INREG(AVIVO_D1CRTC_V_TOTAL); state->crtc[0].v_blank_start_end = INREG(AVIVO_D1CRTC_V_BLANK_START_END); state->crtc[0].v_sync_a = INREG(AVIVO_D1CRTC_V_SYNC_A); state->crtc[0].v_sync_a_cntl = INREG(AVIVO_D1CRTC_V_SYNC_A_CNTL); state->crtc[0].v_sync_b = INREG(AVIVO_D1CRTC_V_SYNC_B); state->crtc[0].v_sync_b_cntl = INREG(AVIVO_D1CRTC_V_SYNC_B_CNTL); state->crtc[0].control = INREG(AVIVO_D1CRTC_CONTROL); state->crtc[0].blank_control = INREG(AVIVO_D1CRTC_BLANK_CONTROL); state->crtc[0].interlace_control = INREG(AVIVO_D1CRTC_INTERLACE_CONTROL); state->crtc[0].stereo_control = INREG(AVIVO_D1CRTC_STEREO_CONTROL); state->crtc[0].cursor_control = INREG(AVIVO_D1CUR_CONTROL); state->grph[0].enable = INREG(AVIVO_D1GRPH_ENABLE); state->grph[0].control = INREG(AVIVO_D1GRPH_CONTROL); state->grph[0].control = INREG(AVIVO_D1GRPH_CONTROL); state->grph[0].prim_surf_addr = INREG(AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS); state->grph[0].sec_surf_addr = INREG(AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS); state->grph[0].pitch = INREG(AVIVO_D1GRPH_PITCH); state->grph[0].x_offset = INREG(AVIVO_D1GRPH_SURFACE_OFFSET_X); state->grph[0].y_offset = INREG(AVIVO_D1GRPH_SURFACE_OFFSET_Y); state->grph[0].x_start = INREG(AVIVO_D1GRPH_X_START); state->grph[0].y_start = INREG(AVIVO_D1GRPH_Y_START); state->grph[0].x_end = INREG(AVIVO_D1GRPH_X_END); state->grph[0].y_end = INREG(AVIVO_D1GRPH_Y_END); state->grph[0].desktop_height = INREG(AVIVO_D1MODE_DESKTOP_HEIGHT); state->grph[0].viewport_start = INREG(AVIVO_D1MODE_VIEWPORT_START); state->grph[0].viewport_size = INREG(AVIVO_D1MODE_VIEWPORT_SIZE); state->grph[0].mode_data_format = INREG(AVIVO_D1MODE_DATA_FORMAT); state->crtc[1].pll_source = INREG(AVIVO_PCLK_CRTC2_CNTL); state->crtc[1].h_total = INREG(AVIVO_D2CRTC_H_TOTAL); state->crtc[1].h_blank_start_end = INREG(AVIVO_D2CRTC_H_BLANK_START_END); state->crtc[1].h_sync_a = INREG(AVIVO_D2CRTC_H_SYNC_A); state->crtc[1].h_sync_a_cntl = INREG(AVIVO_D2CRTC_H_SYNC_A_CNTL); state->crtc[1].h_sync_b = INREG(AVIVO_D2CRTC_H_SYNC_B); state->crtc[1].h_sync_b_cntl = INREG(AVIVO_D2CRTC_H_SYNC_B_CNTL); state->crtc[1].v_total = INREG(AVIVO_D2CRTC_V_TOTAL); state->crtc[1].v_blank_start_end = INREG(AVIVO_D2CRTC_V_BLANK_START_END); state->crtc[1].v_sync_a = INREG(AVIVO_D2CRTC_V_SYNC_A); state->crtc[1].v_sync_a_cntl = INREG(AVIVO_D2CRTC_V_SYNC_A_CNTL); state->crtc[1].v_sync_b = INREG(AVIVO_D2CRTC_V_SYNC_B); state->crtc[1].v_sync_b_cntl = INREG(AVIVO_D2CRTC_V_SYNC_B_CNTL); state->crtc[1].control = INREG(AVIVO_D2CRTC_CONTROL); state->crtc[1].blank_control = INREG(AVIVO_D2CRTC_BLANK_CONTROL); state->crtc[1].interlace_control = INREG(AVIVO_D2CRTC_INTERLACE_CONTROL); state->crtc[1].stereo_control = INREG(AVIVO_D2CRTC_STEREO_CONTROL); state->crtc[1].cursor_control = INREG(AVIVO_D2CUR_CONTROL); state->grph[1].enable = INREG(AVIVO_D2GRPH_ENABLE); state->grph[1].control = INREG(AVIVO_D2GRPH_CONTROL); state->grph[1].control = INREG(AVIVO_D2GRPH_CONTROL); state->grph[1].prim_surf_addr = INREG(AVIVO_D2GRPH_PRIMARY_SURFACE_ADDRESS); state->grph[1].sec_surf_addr = INREG(AVIVO_D2GRPH_SECONDARY_SURFACE_ADDRESS); state->grph[1].pitch = INREG(AVIVO_D2GRPH_PITCH); state->grph[1].x_offset = INREG(AVIVO_D2GRPH_SURFACE_OFFSET_X); state->grph[1].y_offset = INREG(AVIVO_D2GRPH_SURFACE_OFFSET_Y); state->grph[1].x_start = INREG(AVIVO_D2GRPH_X_START); state->grph[1].y_start = INREG(AVIVO_D2GRPH_Y_START); state->grph[1].x_end = INREG(AVIVO_D2GRPH_X_END); state->grph[1].y_end = INREG(AVIVO_D2GRPH_Y_END); state->grph[1].desktop_height = INREG(AVIVO_D2MODE_DESKTOP_HEIGHT); state->grph[1].viewport_start = INREG(AVIVO_D2MODE_VIEWPORT_START); state->grph[1].viewport_size = INREG(AVIVO_D2MODE_VIEWPORT_SIZE); state->grph[1].mode_data_format = INREG(AVIVO_D2MODE_DATA_FORMAT); if (IS_DCE3_VARIANT) { /* save DVOA regs */ state->dvoa[0] = INREG(0x7080); state->dvoa[1] = INREG(0x7084); state->dvoa[2] = INREG(0x708c); state->dvoa[3] = INREG(0x7090); state->dvoa[4] = INREG(0x7094); state->dvoa[5] = INREG(0x70ac); state->dvoa[6] = INREG(0x70b0); j = 0; /* save DAC regs */ for (i = 0x7000; i <= 0x7040; i += 4) { state->daca[j] = INREG(i); state->dacb[j] = INREG(i + 0x100); j++; } for (i = 0x7058; i <= 0x7060; i += 4) { state->daca[j] = INREG(i); state->dacb[j] = INREG(i + 0x100); j++; } for (i = 0x7068; i <= 0x706c; i += 4) { state->daca[j] = INREG(i); state->dacb[j] = INREG(i + 0x100); j++; } for (i = 0x7ef0; i <= 0x7ef8; i += 4) { state->daca[j] = INREG(i); state->dacb[j] = INREG(i + 0x100); j++; } state->daca[j] = INREG(0x7050); state->dacb[j] = INREG(0x7050 + 0x100); j = 0; /* save FMT regs */ for (i = 0x6700; i <= 0x6744; i += 4) { state->fmt1[j] = INREG(i); state->fmt2[j] = INREG(i + 0x800); j++; } j = 0; /* save DIG regs */ for (i = 0x75a0; i <= 0x75e0; i += 4) { state->dig1[j] = INREG(i); state->dig2[j] = INREG(i + 0x400); j++; } for (i = 0x75e8; i <= 0x75ec; i += 4) { state->dig1[j] = INREG(i); state->dig2[j] = INREG(i + 0x400); j++; } j = 0; /* save HDMI regs */ for (i = 0x7400; i <= 0x741c; i += 4) { state->hdmi1[j] = INREG(i); state->hdmi2[j] = INREG(i + 0x400); j++; } for (i = 0x7430; i <= 0x74ec; i += 4) { state->hdmi1[j] = INREG(i); state->hdmi2[j] = INREG(i + 0x400); j++; } state->hdmi1[j] = INREG(0x7428); state->hdmi2[j] = INREG(0x7828); j = 0; /* save AUX regs */ for (i = 0x7780; i <= 0x77b4; i += 4) { state->aux_cntl1[j] = INREG(i); state->aux_cntl2[j] = INREG(i + 0x040); state->aux_cntl3[j] = INREG(i + 0x400); state->aux_cntl4[j] = INREG(i + 0x440); if (IS_DCE32_VARIANT) { state->aux_cntl5[j] = INREG(i + 0x500); state->aux_cntl6[j] = INREG(i + 0x540); } j++; } j = 0; /* save UNIPHY regs */ if (IS_DCE32_VARIANT) { for (i = 0x7680; i <= 0x7690; i += 4) { state->uniphy1[j] = INREG(i); state->uniphy2[j] = INREG(i + 0x20); state->uniphy3[j] = INREG(i + 0x400); state->uniphy4[j] = INREG(i + 0x420); state->uniphy5[j] = INREG(i + 0x840); state->uniphy6[j] = INREG(i + 0x940); j++; } for (i = 0x7698; i <= 0x769c; i += 4) { state->uniphy1[j] = INREG(i); state->uniphy2[j] = INREG(i + 0x20); state->uniphy3[j] = INREG(i + 0x400); state->uniphy4[j] = INREG(i + 0x420); state->uniphy5[j] = INREG(i + 0x840); state->uniphy6[j] = INREG(i + 0x940); j++; } } else { for (i = 0x7ec0; i <= 0x7edc; i += 4) { state->uniphy1[j] = INREG(i); state->uniphy2[j] = INREG(i + 0x100); j++; } } j = 0; /* save PHY,LINK regs */ for (i = 0x7f20; i <= 0x7f34; i += 4) { state->phy[j] = INREG(i); j++; } for (i = 0x7f9c; i <= 0x7fa4; i += 4) { state->phy[j] = INREG(i); j++; } state->phy[j] = INREG(0x7f40); j = 0; /* save LVTMA regs */ for (i = 0x7f00; i <= 0x7f1c; i += 4) { state->lvtma[j] = INREG(i); j++; } for (i = 0x7f80; i <= 0x7f98; i += 4) { state->lvtma[j] = INREG(i); j++; } } else { j = 0; /* save DVOA regs */ for (i = 0x7980; i <= 0x79bc; i += 4) { state->dvoa[j] = INREG(i); j++; } j = 0; /* save DAC regs */ for (i = 0x7800; i <= 0x782c; i += 4) { state->daca[j] = INREG(i); state->dacb[j] = INREG(i + 0x200); j++; } for (i = 0x7834; i <= 0x7840; i += 4) { state->daca[j] = INREG(i); state->dacb[j] = INREG(i + 0x200); j++; } for (i = 0x7850; i <= 0x7868; i += 4) { state->daca[j] = INREG(i); state->dacb[j] = INREG(i + 0x200); j++; } j = 0; /* save TMDSA regs */ for (i = 0x7880; i <= 0x78e0; i += 4) { state->tmdsa[j] = INREG(i); j++; } for (i = 0x7904; i <= 0x7918; i += 4) { state->tmdsa[j] = INREG(i); j++; } j = 0; /* save LVTMA regs */ for (i = 0x7a80; i <= 0x7b18; i += 4) { state->lvtma[j] = INREG(i); j++; } if ((info->ChipFamily == CHIP_FAMILY_RS600) || (info->ChipFamily == CHIP_FAMILY_RS690) || (info->ChipFamily == CHIP_FAMILY_RS740)) { j = 0; /* save DDIA regs */ for (i = 0x7200; i <= 0x7290; i += 4) { state->ddia[j] = INREG(i); j++; } } } /* scalers */ j = 0; for (i = 0x6578; i <= 0x65e4; i += 4) { state->d1scl[j] = INREG(i); state->d2scl[j] = INREG(i + 0x800); j++; } for (i = 0x6600; i <= 0x662c; i += 4) { state->d1scl[j] = INREG(i); state->d2scl[j] = INREG(i + 0x800); j++; } j = 0; for (i = 0x66e8; i <= 0x66fc; i += 4) { state->dxscl[j] = INREG(i); j++; } state->dxscl[6] = INREG(0x6e30); state->dxscl[7] = INREG(0x6e34); if (state->crtc[0].control & AVIVO_CRTC_EN) info->crtc_on = TRUE; if (state->crtc[1].control & AVIVO_CRTC_EN) info->crtc2_on = TRUE; } static void avivo_restore(ScrnInfoPtr pScrn, RADEONSavePtr restore) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; struct avivo_state *state = &restore->avivo; int i, j; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "avivo_restore !\n"); /* Disable VGA control for now.. maybe needs to be changed */ OUTREG(AVIVO_D1VGA_CONTROL, 0); OUTREG(AVIVO_D2VGA_CONTROL, 0); /* Disable CRTCs */ OUTREG(AVIVO_D1CRTC_CONTROL, (INREG(AVIVO_D1CRTC_CONTROL) & ~0x300) | 0x01000000); OUTREG(AVIVO_D2CRTC_CONTROL, (INREG(AVIVO_D2CRTC_CONTROL) & ~0x300) | 0x01000000); OUTREG(AVIVO_D1CRTC_CONTROL, INREG(AVIVO_D1CRTC_CONTROL) & ~0x1); OUTREG(AVIVO_D2CRTC_CONTROL, INREG(AVIVO_D2CRTC_CONTROL) & ~0x1); OUTREG(AVIVO_D1CRTC_CONTROL, INREG(AVIVO_D1CRTC_CONTROL) | 0x100); OUTREG(AVIVO_D2CRTC_CONTROL, INREG(AVIVO_D2CRTC_CONTROL) | 0x100); /* Lock graph registers */ OUTREG(AVIVO_D1GRPH_UPDATE, AVIVO_D1GRPH_UPDATE_LOCK); OUTREG(AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS, state->grph[0].prim_surf_addr); OUTREG(AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS, state->grph[0].sec_surf_addr); OUTREG(AVIVO_D1GRPH_CONTROL, state->grph[0].control); OUTREG(AVIVO_D1GRPH_SURFACE_OFFSET_X, state->grph[0].x_offset); OUTREG(AVIVO_D1GRPH_SURFACE_OFFSET_Y, state->grph[0].y_offset); OUTREG(AVIVO_D1GRPH_X_START, state->grph[0].x_start); OUTREG(AVIVO_D1GRPH_Y_START, state->grph[0].y_start); OUTREG(AVIVO_D1GRPH_X_END, state->grph[0].x_end); OUTREG(AVIVO_D1GRPH_Y_END, state->grph[0].y_end); OUTREG(AVIVO_D1GRPH_PITCH, state->grph[0].pitch); OUTREG(AVIVO_D1GRPH_ENABLE, state->grph[0].enable); OUTREG(AVIVO_D1GRPH_UPDATE, 0); OUTREG(AVIVO_D2GRPH_UPDATE, AVIVO_D1GRPH_UPDATE_LOCK); OUTREG(AVIVO_D2GRPH_PRIMARY_SURFACE_ADDRESS, state->grph[1].prim_surf_addr); OUTREG(AVIVO_D2GRPH_SECONDARY_SURFACE_ADDRESS, state->grph[1].sec_surf_addr); OUTREG(AVIVO_D2GRPH_CONTROL, state->grph[1].control); OUTREG(AVIVO_D2GRPH_SURFACE_OFFSET_X, state->grph[1].x_offset); OUTREG(AVIVO_D2GRPH_SURFACE_OFFSET_Y, state->grph[1].y_offset); OUTREG(AVIVO_D2GRPH_X_START, state->grph[1].x_start); OUTREG(AVIVO_D2GRPH_Y_START, state->grph[1].y_start); OUTREG(AVIVO_D2GRPH_X_END, state->grph[1].x_end); OUTREG(AVIVO_D2GRPH_Y_END, state->grph[1].y_end); OUTREG(AVIVO_D2GRPH_PITCH, state->grph[1].pitch); OUTREG(AVIVO_D2GRPH_ENABLE, state->grph[1].enable); OUTREG(AVIVO_D2GRPH_UPDATE, 0); /* Whack some mode regs too */ OUTREG(AVIVO_D1SCL_UPDATE, AVIVO_D1SCL_UPDATE_LOCK); OUTREG(AVIVO_D1MODE_DESKTOP_HEIGHT, state->grph[0].desktop_height); OUTREG(AVIVO_D1MODE_VIEWPORT_START, state->grph[0].viewport_start); OUTREG(AVIVO_D1MODE_VIEWPORT_SIZE, state->grph[0].viewport_size); OUTREG(AVIVO_D1MODE_DATA_FORMAT, state->grph[0].mode_data_format); OUTREG(AVIVO_D1SCL_UPDATE, 0); OUTREG(AVIVO_D2SCL_UPDATE, AVIVO_D1SCL_UPDATE_LOCK); OUTREG(AVIVO_D2MODE_DESKTOP_HEIGHT, state->grph[1].desktop_height); OUTREG(AVIVO_D2MODE_VIEWPORT_START, state->grph[1].viewport_start); OUTREG(AVIVO_D2MODE_VIEWPORT_SIZE, state->grph[1].viewport_size); OUTREG(AVIVO_D2MODE_DATA_FORMAT, state->grph[1].mode_data_format); OUTREG(AVIVO_D2SCL_UPDATE, 0); /* Set the PLL */ OUTREG(AVIVO_EXT1_PPLL_REF_DIV_SRC, state->pll[0].ref_div_src); OUTREG(AVIVO_EXT1_PPLL_REF_DIV, state->pll[0].ref_div); OUTREG(AVIVO_EXT1_PPLL_FB_DIV, state->pll[0].fb_div); OUTREG(AVIVO_EXT1_PPLL_POST_DIV_SRC, state->pll[0].post_div_src); OUTREG(AVIVO_EXT1_PPLL_POST_DIV, state->pll[0].post_div); OUTREG(AVIVO_EXT1_PPLL_CNTL, state->pll[0].ext_ppll_cntl); OUTREG(AVIVO_P1PLL_CNTL, state->pll[0].pll_cntl); OUTREG(AVIVO_P1PLL_INT_SS_CNTL, state->pll[0].int_ss_cntl); OUTREG(AVIVO_EXT2_PPLL_REF_DIV_SRC, state->pll[1].ref_div_src); OUTREG(AVIVO_EXT2_PPLL_REF_DIV, state->pll[1].ref_div); OUTREG(AVIVO_EXT2_PPLL_FB_DIV, state->pll[1].fb_div); OUTREG(AVIVO_EXT2_PPLL_POST_DIV_SRC, state->pll[1].post_div_src); OUTREG(AVIVO_EXT2_PPLL_POST_DIV, state->pll[1].post_div); OUTREG(AVIVO_EXT2_PPLL_CNTL, state->pll[1].ext_ppll_cntl); OUTREG(AVIVO_P2PLL_CNTL, state->pll[1].pll_cntl); OUTREG(AVIVO_P2PLL_INT_SS_CNTL, state->pll[1].int_ss_cntl); OUTREG(AVIVO_PCLK_CRTC1_CNTL, state->crtc[0].pll_source); OUTREG(AVIVO_PCLK_CRTC2_CNTL, state->crtc[1].pll_source); /* Set the vga PLL */ OUTREG(AVIVO_VGA25_PPLL_REF_DIV_SRC, state->vga25_ppll.ref_div_src); OUTREG(AVIVO_VGA25_PPLL_REF_DIV, state->vga25_ppll.ref_div); OUTREG(AVIVO_VGA25_PPLL_FB_DIV, state->vga25_ppll.fb_div); OUTREG(AVIVO_VGA25_PPLL_POST_DIV_SRC, state->vga25_ppll.post_div_src); OUTREG(AVIVO_VGA25_PPLL_POST_DIV, state->vga25_ppll.post_div); OUTREG(AVIVO_VGA25_PPLL_CNTL, state->vga25_ppll.pll_cntl); OUTREG(AVIVO_VGA28_PPLL_REF_DIV_SRC, state->vga28_ppll.ref_div_src); OUTREG(AVIVO_VGA28_PPLL_REF_DIV, state->vga28_ppll.ref_div); OUTREG(AVIVO_VGA28_PPLL_FB_DIV, state->vga28_ppll.fb_div); OUTREG(AVIVO_VGA28_PPLL_POST_DIV_SRC, state->vga28_ppll.post_div_src); OUTREG(AVIVO_VGA28_PPLL_POST_DIV, state->vga28_ppll.post_div); OUTREG(AVIVO_VGA28_PPLL_CNTL, state->vga28_ppll.pll_cntl); OUTREG(AVIVO_VGA41_PPLL_REF_DIV_SRC, state->vga41_ppll.ref_div_src); OUTREG(AVIVO_VGA41_PPLL_REF_DIV, state->vga41_ppll.ref_div); OUTREG(AVIVO_VGA41_PPLL_FB_DIV, state->vga41_ppll.fb_div); OUTREG(AVIVO_VGA41_PPLL_POST_DIV_SRC, state->vga41_ppll.post_div_src); OUTREG(AVIVO_VGA41_PPLL_POST_DIV, state->vga41_ppll.post_div); OUTREG(AVIVO_VGA41_PPLL_CNTL, state->vga41_ppll.pll_cntl); /* Set the CRTC */ OUTREG(AVIVO_D1CRTC_H_TOTAL, state->crtc[0].h_total); OUTREG(AVIVO_D1CRTC_H_BLANK_START_END, state->crtc[0].h_blank_start_end); OUTREG(AVIVO_D1CRTC_H_SYNC_A, state->crtc[0].h_sync_a); OUTREG(AVIVO_D1CRTC_H_SYNC_A_CNTL, state->crtc[0].h_sync_a_cntl); OUTREG(AVIVO_D1CRTC_H_SYNC_B, state->crtc[0].h_sync_b); OUTREG(AVIVO_D1CRTC_H_SYNC_B_CNTL, state->crtc[0].h_sync_b_cntl); OUTREG(AVIVO_D1CRTC_V_TOTAL, state->crtc[0].v_total); OUTREG(AVIVO_D1CRTC_V_BLANK_START_END, state->crtc[0].v_blank_start_end); OUTREG(AVIVO_D1CRTC_V_SYNC_A, state->crtc[0].v_sync_a); OUTREG(AVIVO_D1CRTC_V_SYNC_A_CNTL, state->crtc[0].v_sync_a_cntl); OUTREG(AVIVO_D1CRTC_V_SYNC_B, state->crtc[0].v_sync_b); OUTREG(AVIVO_D1CRTC_V_SYNC_B_CNTL, state->crtc[0].v_sync_b_cntl); OUTREG(AVIVO_D1CRTC_INTERLACE_CONTROL, state->crtc[0].interlace_control); OUTREG(AVIVO_D1CRTC_STEREO_CONTROL, state->crtc[0].stereo_control); OUTREG(AVIVO_D1CUR_CONTROL, state->crtc[0].cursor_control); /* XXX Fix scaler */ OUTREG(AVIVO_D2CRTC_H_TOTAL, state->crtc[1].h_total); OUTREG(AVIVO_D2CRTC_H_BLANK_START_END, state->crtc[1].h_blank_start_end); OUTREG(AVIVO_D2CRTC_H_SYNC_A, state->crtc[1].h_sync_a); OUTREG(AVIVO_D2CRTC_H_SYNC_A_CNTL, state->crtc[1].h_sync_a_cntl); OUTREG(AVIVO_D2CRTC_H_SYNC_B, state->crtc[1].h_sync_b); OUTREG(AVIVO_D2CRTC_H_SYNC_B_CNTL, state->crtc[1].h_sync_b_cntl); OUTREG(AVIVO_D2CRTC_V_TOTAL, state->crtc[1].v_total); OUTREG(AVIVO_D2CRTC_V_BLANK_START_END, state->crtc[1].v_blank_start_end); OUTREG(AVIVO_D2CRTC_V_SYNC_A, state->crtc[1].v_sync_a); OUTREG(AVIVO_D2CRTC_V_SYNC_A_CNTL, state->crtc[1].v_sync_a_cntl); OUTREG(AVIVO_D2CRTC_V_SYNC_B, state->crtc[1].v_sync_b); OUTREG(AVIVO_D2CRTC_V_SYNC_B_CNTL, state->crtc[1].v_sync_b_cntl); OUTREG(AVIVO_D2CRTC_INTERLACE_CONTROL, state->crtc[1].interlace_control); OUTREG(AVIVO_D2CRTC_STEREO_CONTROL, state->crtc[1].stereo_control); OUTREG(AVIVO_D2CUR_CONTROL, state->crtc[1].cursor_control); if (IS_DCE3_VARIANT) { /* DVOA regs */ OUTREG(0x7080, state->dvoa[0]); OUTREG(0x7084, state->dvoa[1]); OUTREG(0x708c, state->dvoa[2]); OUTREG(0x7090, state->dvoa[3]); OUTREG(0x7094, state->dvoa[4]); OUTREG(0x70ac, state->dvoa[5]); OUTREG(0x70b0, state->dvoa[6]); j = 0; /* DAC regs */ for (i = 0x7000; i <= 0x7040; i += 4) { OUTREG(i, state->daca[j]); OUTREG((i + 0x100), state->dacb[j]); j++; } for (i = 0x7058; i <= 0x7060; i += 4) { OUTREG(i, state->daca[j]); OUTREG((i + 0x100), state->dacb[j]); j++; } for (i = 0x7068; i <= 0x706c; i += 4) { OUTREG(i, state->daca[j]); OUTREG((i + 0x100), state->dacb[j]); j++; } for (i = 0x7ef0; i <= 0x7ef8; i += 4) { OUTREG(i, state->daca[j]); OUTREG((i + 0x100), state->dacb[j]); j++; } OUTREG(0x7050, state->daca[j]); OUTREG((0x7050 + 0x100), state->dacb[j]); j = 0; /* FMT regs */ for (i = 0x6700; i <= 0x6744; i += 4) { OUTREG(i, state->fmt1[j]); OUTREG((i + 0x800), state->fmt2[j]); j++; } j = 0; /* DIG regs */ for (i = 0x75a0; i <= 0x75e0; i += 4) { OUTREG(i, state->dig1[j]); OUTREG((i + 0x400), state->dig2[j]); j++; } for (i = 0x75e8; i <= 0x75ec; i += 4) { OUTREG(i, state->dig1[j]); OUTREG((i + 0x400), state->dig2[j]); j++; } j = 0; /* HDMI regs */ for (i = 0x7400; i <= 0x741c; i += 4) { OUTREG(i, state->hdmi1[j]); OUTREG((i + 0x400), state->hdmi2[j]); j++; } for (i = 0x7430; i <= 0x74ec; i += 4) { OUTREG(i, state->hdmi1[j]); OUTREG((i + 0x400), state->hdmi2[j]); j++; } OUTREG(0x7428, state->hdmi1[j]); OUTREG((0x7428 + 0x400), state->hdmi2[j]); j = 0; /* save AUX regs */ for (i = 0x7780; i <= 0x77b4; i += 4) { OUTREG(i, state->aux_cntl1[j]); OUTREG((i + 0x040), state->aux_cntl2[j]); OUTREG((i + 0x400), state->aux_cntl3[j]); OUTREG((i + 0x440), state->aux_cntl4[j]); if (IS_DCE32_VARIANT) { OUTREG((i + 0x500), state->aux_cntl5[j]); OUTREG((i + 0x540), state->aux_cntl6[j]); } j++; } j = 0; /* save UNIPHY regs */ if (IS_DCE32_VARIANT) { for (i = 0x7680; i <= 0x7690; i += 4) { OUTREG(i, state->uniphy1[j]); OUTREG((i + 0x20), state->uniphy2[j]); OUTREG((i + 0x400), state->uniphy3[j]); OUTREG((i + 0x420), state->uniphy4[j]); OUTREG((i + 0x840), state->uniphy5[j]); OUTREG((i + 0x940), state->uniphy6[j]); j++; } for (i = 0x7698; i <= 0x769c; i += 4) { OUTREG(i, state->uniphy1[j]); OUTREG((i + 0x20), state->uniphy2[j]); OUTREG((i + 0x400), state->uniphy3[j]); OUTREG((i + 0x420), state->uniphy4[j]); OUTREG((i + 0x840), state->uniphy5[j]); OUTREG((i + 0x940), state->uniphy6[j]); j++; } } else { for (i = 0x7ec0; i <= 0x7edc; i += 4) { OUTREG(i, state->uniphy1[j]); OUTREG((i + 0x100), state->uniphy2[j]); j++; } } j = 0; /* save PHY,LINK regs */ for (i = 0x7f20; i <= 0x7f34; i += 4) { OUTREG(i, state->phy[j]); j++; } for (i = 0x7f9c; i <= 0x7fa4; i += 4) { OUTREG(i, state->phy[j]); j++; } state->phy[j] = INREG(0x7f40); j = 0; /* save LVTMA regs */ for (i = 0x7f00; i <= 0x7f1c; i += 4) { OUTREG(i, state->lvtma[j]); j++; } for (i = 0x7f80; i <= 0x7f98; i += 4) { OUTREG(i, state->lvtma[j]); j++; } } else { j = 0; /* DVOA regs */ for (i = 0x7980; i <= 0x79bc; i += 4) { OUTREG(i, state->dvoa[j]); j++; } j = 0; /* DAC regs */ /* -- MIGHT NEED ORDERING FIX & DELAYS -- */ for (i = 0x7800; i <= 0x782c; i += 4) { OUTREG(i, state->daca[j]); OUTREG((i + 0x200), state->dacb[j]); j++; } for (i = 0x7834; i <= 0x7840; i += 4) { OUTREG(i, state->daca[j]); OUTREG((i + 0x200), state->dacb[j]); j++; } for (i = 0x7850; i <= 0x7868; i += 4) { OUTREG(i, state->daca[j]); OUTREG((i + 0x200), state->dacb[j]); j++; } j = 0; /* TMDSA regs */ for (i = 0x7880; i <= 0x78e0; i += 4) { OUTREG(i, state->tmdsa[j]); j++; } for (i = 0x7904; i <= 0x7918; i += 4) { OUTREG(i, state->tmdsa[j]); j++; } j = 0; /* LVTMA regs */ for (i = 0x7a80; i <= 0x7b18; i += 4) { OUTREG(i, state->lvtma[j]); j++; } /* DDIA regs */ if ((info->ChipFamily == CHIP_FAMILY_RS600) || (info->ChipFamily == CHIP_FAMILY_RS690) || (info->ChipFamily == CHIP_FAMILY_RS740)) { j = 0; for (i = 0x7200; i <= 0x7290; i += 4) { OUTREG(i, state->ddia[j]); j++; } } } /* scalers */ j = 0; for (i = 0x6578; i <= 0x65e4; i += 4) { OUTREG(i, state->d1scl[j]); OUTREG((i + 0x800), state->d2scl[j]); j++; } for (i = 0x6600; i <= 0x662c; i += 4) { OUTREG(i, state->d1scl[j]); OUTREG((i + 0x800), state->d2scl[j]); j++; } j = 0; for (i = 0x66e8; i <= 0x66fc; i += 4) { OUTREG(i, state->dxscl[j]); j++; } OUTREG(0x6e30, state->dxscl[6]); OUTREG(0x6e34, state->dxscl[7]); /* Enable CRTCs */ if (state->crtc[0].control & 1) { OUTREG(AVIVO_D1CRTC_CONTROL, 0x01000101); INREG(AVIVO_D1CRTC_CONTROL); OUTREG(AVIVO_D1CRTC_CONTROL, 0x00010101); } if (state->crtc[1].control & 1) { OUTREG(AVIVO_D2CRTC_CONTROL, 0x01000101); INREG(AVIVO_D2CRTC_CONTROL); OUTREG(AVIVO_D2CRTC_CONTROL, 0x00010101); } /* Where should that go ? */ OUTREG(AVIVO_DC_CRTC_TV_CONTROL, state->crtc_tv_control); OUTREG(AVIVO_DC_LB_MEMORY_SPLIT, state->dc_lb_memory_split); /* Need fixing too ? */ OUTREG(AVIVO_D1CRTC_BLANK_CONTROL, state->crtc[0].blank_control); OUTREG(AVIVO_D2CRTC_BLANK_CONTROL, state->crtc[1].blank_control); /* Dbl check */ OUTREG(AVIVO_VGA_RENDER_CONTROL, state->vga_render_control); OUTREG(AVIVO_D1VGA_CONTROL, state->vga1_cntl); OUTREG(AVIVO_D2VGA_CONTROL, state->vga2_cntl); /* Should only enable outputs here */ } static void avivo_restore_vga_regs(ScrnInfoPtr pScrn, RADEONSavePtr restore) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; struct avivo_state *state = &restore->avivo; OUTREG(AVIVO_VGA_RENDER_CONTROL, state->vga_render_control); OUTREG(AVIVO_D1VGA_CONTROL, state->vga1_cntl); OUTREG(AVIVO_D2VGA_CONTROL, state->vga2_cntl); } static void dce4_restore_vga_regs(ScrnInfoPtr pScrn, RADEONSavePtr restore) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; struct dce4_state *state = &restore->dce4; OUTREG(AVIVO_VGA_RENDER_CONTROL, state->vga_render_control); OUTREG(AVIVO_D1VGA_CONTROL, state->vga1_cntl); OUTREG(AVIVO_D2VGA_CONTROL, state->vga2_cntl); OUTREG(EVERGREEN_D3VGA_CONTROL, state->vga3_cntl); OUTREG(EVERGREEN_D4VGA_CONTROL, state->vga4_cntl); OUTREG(EVERGREEN_D5VGA_CONTROL, state->vga5_cntl); OUTREG(EVERGREEN_D6VGA_CONTROL, state->vga6_cntl); } static void RADEONRestoreBIOSRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; if (info->ChipFamily >= CHIP_FAMILY_R600) { OUTREG(R600_BIOS_0_SCRATCH, restore->bios_0_scratch); OUTREG(R600_BIOS_1_SCRATCH, restore->bios_1_scratch); OUTREG(R600_BIOS_2_SCRATCH, restore->bios_2_scratch); OUTREG(R600_BIOS_3_SCRATCH, restore->bios_3_scratch); OUTREG(R600_BIOS_4_SCRATCH, restore->bios_4_scratch); OUTREG(R600_BIOS_5_SCRATCH, restore->bios_5_scratch); OUTREG(R600_BIOS_6_SCRATCH, restore->bios_6_scratch); OUTREG(R600_BIOS_7_SCRATCH, restore->bios_7_scratch); } else { OUTREG(RADEON_BIOS_0_SCRATCH, restore->bios_0_scratch); OUTREG(RADEON_BIOS_1_SCRATCH, restore->bios_1_scratch); OUTREG(RADEON_BIOS_2_SCRATCH, restore->bios_2_scratch); OUTREG(RADEON_BIOS_3_SCRATCH, restore->bios_3_scratch); OUTREG(RADEON_BIOS_4_SCRATCH, restore->bios_4_scratch); OUTREG(RADEON_BIOS_5_SCRATCH, restore->bios_5_scratch); OUTREG(RADEON_BIOS_6_SCRATCH, restore->bios_6_scratch); OUTREG(RADEON_BIOS_7_SCRATCH, restore->bios_7_scratch); } } static void RADEONSaveBIOSRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; if (info->ChipFamily >= CHIP_FAMILY_R600) { save->bios_0_scratch = INREG(R600_BIOS_0_SCRATCH); save->bios_1_scratch = INREG(R600_BIOS_1_SCRATCH); save->bios_2_scratch = INREG(R600_BIOS_2_SCRATCH); save->bios_3_scratch = INREG(R600_BIOS_3_SCRATCH); save->bios_4_scratch = INREG(R600_BIOS_4_SCRATCH); save->bios_5_scratch = INREG(R600_BIOS_5_SCRATCH); save->bios_6_scratch = INREG(R600_BIOS_6_SCRATCH); save->bios_7_scratch = INREG(R600_BIOS_7_SCRATCH); } else { save->bios_0_scratch = INREG(RADEON_BIOS_0_SCRATCH); save->bios_1_scratch = INREG(RADEON_BIOS_1_SCRATCH); save->bios_2_scratch = INREG(RADEON_BIOS_2_SCRATCH); save->bios_3_scratch = INREG(RADEON_BIOS_3_SCRATCH); save->bios_4_scratch = INREG(RADEON_BIOS_4_SCRATCH); save->bios_5_scratch = INREG(RADEON_BIOS_5_SCRATCH); save->bios_6_scratch = INREG(RADEON_BIOS_6_SCRATCH); save->bios_7_scratch = INREG(RADEON_BIOS_7_SCRATCH); } } /* Save everything needed to restore the original VC state */ static void RADEONSave(ScrnInfoPtr pScrn) { RADEONInfoPtr info = RADEONPTR(pScrn); RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); unsigned char *RADEONMMIO = info->MMIO; RADEONSavePtr save = info->SavedReg; xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "RADEONSave\n"); #ifdef WITH_VGAHW if (info->VGAAccess) { vgaHWPtr hwp = VGAHWPTR(pScrn); vgaHWUnlock(hwp); # if defined(__powerpc__) /* temporary hack to prevent crashing on PowerMacs when trying to * read VGA fonts and colormap, will find a better solution * in the future. TODO: Check if there's actually some VGA stuff * setup in the card at all !! */ vgaHWSave(pScrn, &hwp->SavedReg, VGA_SR_MODE); /* Save mode only */ # elif defined(__linux__) /* Save only mode * & fonts */ vgaHWSave(pScrn, &hwp->SavedReg, VGA_SR_MODE | VGA_SR_FONTS ); # else /* Save mode * & fonts & cmap */ vgaHWSave(pScrn, &hwp->SavedReg, VGA_SR_ALL); # endif vgaHWLock(hwp); } #endif if (IS_DCE4_VARIANT) { RADEONSaveMemMapRegisters(pScrn, save); dce4_save(pScrn, save); //XXX } else if (IS_AVIVO_VARIANT) { RADEONSaveMemMapRegisters(pScrn, save); avivo_save(pScrn, save); } else { save->dp_datatype = INREG(RADEON_DP_DATATYPE); save->rbbm_soft_reset = INREG(RADEON_RBBM_SOFT_RESET); save->clock_cntl_index = INREG(RADEON_CLOCK_CNTL_INDEX); RADEONPllErrataAfterIndex(info); RADEONSaveMemMapRegisters(pScrn, save); RADEONSaveCommonRegisters(pScrn, save); RADEONSavePLLRegisters(pScrn, save); RADEONSaveCrtcRegisters(pScrn, save); RADEONSaveFPRegisters(pScrn, save); RADEONSaveDACRegisters(pScrn, save); RADEONSavePalette(pScrn, save); if (pRADEONEnt->HasCRTC2) { RADEONSaveCrtc2Registers(pScrn, save); RADEONSavePLL2Registers(pScrn, save); } if (info->InternalTVOut) RADEONSaveTVRegisters(pScrn, save); } if (info->ChipFamily < CHIP_FAMILY_R600) RADEONSaveSurfaces(pScrn, save); } /* Restore the original (text) mode */ static void RADEONRestore(ScrnInfoPtr pScrn) { RADEONInfoPtr info = RADEONPTR(pScrn); RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); unsigned char *RADEONMMIO = info->MMIO; RADEONSavePtr restore = info->SavedReg; xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); xf86CrtcPtr crtc; xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "RADEONRestore\n"); #if X_BYTE_ORDER == X_BIG_ENDIAN if (info->ChipFamily < CHIP_FAMILY_R600) { RADEONWaitForFifo(pScrn, 1); OUTREG(RADEON_RBBM_GUICNTL, RADEON_HOST_DATA_SWAP_NONE); } #endif RADEONBlank(pScrn); if (IS_DCE4_VARIANT) { RADEONRestoreMemMapRegisters(pScrn, restore); dce4_restore(pScrn, restore); //XXX } else if (IS_AVIVO_VARIANT) { RADEONRestoreMemMapRegisters(pScrn, restore); avivo_restore(pScrn, restore); } else { OUTREG(RADEON_CLOCK_CNTL_INDEX, restore->clock_cntl_index); RADEONPllErrataAfterIndex(info); OUTREG(RADEON_RBBM_SOFT_RESET, restore->rbbm_soft_reset); OUTREG(RADEON_DP_DATATYPE, restore->dp_datatype); OUTREG(RADEON_GRPH_BUFFER_CNTL, restore->grph_buffer_cntl); OUTREG(RADEON_GRPH2_BUFFER_CNTL, restore->grph2_buffer_cntl); if (!info->IsSecondary) { RADEONRestoreMemMapRegisters(pScrn, restore); RADEONRestoreCommonRegisters(pScrn, restore); if (pRADEONEnt->HasCRTC2) { RADEONRestoreCrtc2Registers(pScrn, restore); RADEONRestorePLL2Registers(pScrn, restore); } RADEONRestoreCrtcRegisters(pScrn, restore); RADEONRestorePLLRegisters(pScrn, restore); RADEONRestoreRMXRegisters(pScrn, restore); RADEONRestoreFPRegisters(pScrn, restore); RADEONRestoreFP2Registers(pScrn, restore); RADEONRestoreLVDSRegisters(pScrn, restore); if (info->InternalTVOut) RADEONRestoreTVRegisters(pScrn, restore); } RADEONRestoreBIOSRegisters(pScrn, restore); } #if 1 /* Temp fix to "solve" VT switch problems. When switching VTs on * some systems, the console can either hang or the fonts can be * corrupted. This hack solves the problem 99% of the time. A * correct fix is being worked on. */ usleep(100000); #endif if (info->ChipFamily < CHIP_FAMILY_R600) RADEONRestoreSurfaces(pScrn, restore); /* need to make sure we don't enable a crtc by accident or we may get a hang */ if (pRADEONEnt->HasCRTC2 && !info->IsSecondary) { if (info->crtc2_on && xf86_config->num_crtc > 1) { crtc = xf86_config->crtc[1]; crtc->funcs->dpms(crtc, DPMSModeOn); } } if (info->crtc_on) { crtc = xf86_config->crtc[0]; crtc->funcs->dpms(crtc, DPMSModeOn); } #ifdef WITH_VGAHW if (info->VGAAccess) { vgaHWPtr hwp = VGAHWPTR(pScrn); vgaHWUnlock(hwp); # if defined(__powerpc__) /* Temporary hack to prevent crashing on PowerMacs when trying to * write VGA fonts, will find a better solution in the future */ vgaHWRestore(pScrn, &hwp->SavedReg, VGA_SR_MODE ); # elif defined(__linux__) vgaHWRestore(pScrn, &hwp->SavedReg, VGA_SR_MODE | VGA_SR_FONTS ); # else vgaHWRestore(pScrn, &hwp->SavedReg, VGA_SR_ALL ); # endif vgaHWLock(hwp); } #endif /* to restore console mode, DAC registers should be set after every other registers are set, * otherwise,we may get blank screen */ if (IS_DCE4_VARIANT) dce4_restore_vga_regs(pScrn, restore); else if (IS_AVIVO_VARIANT) avivo_restore_vga_regs(pScrn, restore); else { RADEONRestorePalette(pScrn, restore); RADEONRestoreDACRegisters(pScrn, restore); } #if 0 RADEONWaitForVerticalSync(pScrn); #endif } static Bool RADEONSaveScreen(ScreenPtr pScreen, int mode) { ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; Bool unblank; xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "RADEONSaveScreen(%d)\n", mode); unblank = xf86IsUnblank(mode); if (unblank) SetTimeSinceLastInputEvent(); if ((pScrn != NULL) && pScrn->vtSema) { if (unblank) RADEONUnblank(pScrn); else RADEONBlank(pScrn); } return TRUE; } Bool RADEONSwitchMode(int scrnIndex, DisplayModePtr mode, int flags) { ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; RADEONInfoPtr info = RADEONPTR(pScrn); Bool tilingOld = info->tilingEnabled; Bool ret; #ifdef XF86DRI Bool CPStarted = info->cp->CPStarted; if (CPStarted) { DRILock(pScrn->pScreen, 0); RADEONCP_STOP(pScrn, info); } #endif xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "RADEONSwitchMode() !n"); if (info->allowColorTiling) { info->tilingEnabled = (mode->Flags & (V_DBLSCAN | V_INTERLACE)) ? FALSE : TRUE; #ifdef XF86DRI if (info->directRenderingEnabled && (info->tilingEnabled != tilingOld)) { drm_radeon_sarea_t *pSAREAPriv; if (RADEONDRISetParam(pScrn, RADEON_SETPARAM_SWITCH_TILING, (info->tilingEnabled ? 1 : 0)) < 0) xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "[drm] failed changing tiling status\n"); pSAREAPriv = DRIGetSAREAPrivate(pScrn->pScreen); info->tilingEnabled = pSAREAPriv->tiling_enabled ? TRUE : FALSE; } #endif } if (info->accelOn) RADEON_SYNC(info, pScrn); ret = xf86SetSingleMode (pScrn, mode, RR_Rotate_0); if (info->tilingEnabled != tilingOld) { /* need to redraw front buffer, I guess this can be considered a hack ? */ xf86EnableDisableFBAccess(scrnIndex, FALSE); RADEONChangeSurfaces(pScrn); xf86EnableDisableFBAccess(scrnIndex, TRUE); /* xf86SetRootClip would do, but can't access that here */ } if (info->accelOn) { RADEON_SYNC(info, pScrn); if (info->ChipFamily < CHIP_FAMILY_R600) RADEONEngineRestore(pScrn); } #ifdef XF86DRI if (CPStarted) { RADEONCP_START(pScrn, info); DRIUnlock(pScrn->pScreen); } #endif /* reset ecp for overlay */ info->ecp_div = -1; return ret; } #ifdef X_XF86MiscPassMessage Bool RADEONHandleMessage(int scrnIndex, const char* msgtype, const char* msgval, char** retmsg) { ErrorF("RADEONHandleMessage(%d, \"%s\", \"%s\", retmsg)\n", scrnIndex, msgtype, msgval); *retmsg = ""; return 0; } #endif #ifndef HAVE_XF86MODEBANDWIDTH /** Calculates the memory bandwidth (in MiB/sec) of a mode. */ _X_HIDDEN unsigned int xf86ModeBandwidth(DisplayModePtr mode, int depth) { float a_active, a_total, active_percent, pixels_per_second; int bytes_per_pixel = (depth + 7) / 8; if (!mode->HTotal || !mode->VTotal || !mode->Clock) return 0; a_active = mode->HDisplay * mode->VDisplay; a_total = mode->HTotal * mode->VTotal; active_percent = a_active / a_total; pixels_per_second = active_percent * mode->Clock * 1000.0; return (unsigned int)(pixels_per_second * bytes_per_pixel / (1024 * 1024)); } #endif /* Used to disallow modes that are not supported by the hardware */ ModeStatus RADEONValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flag) { ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; RADEONInfoPtr info = RADEONPTR(pScrn); RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); /* * RN50 has effective maximum mode bandwidth of about 300MiB/s. * XXX should really do this for all chips by properly computing * memory bandwidth and an overhead factor. */ if (info->ChipFamily == CHIP_FAMILY_RV100 && !pRADEONEnt->HasCRTC2) { if (xf86ModeBandwidth(mode, pScrn->bitsPerPixel) > 300) return MODE_BANDWIDTH; } /* There are problems with double scan mode at high clocks * They're likely related PLL and display buffer settings. * Disable these modes for now. */ if (mode->Flags & V_DBLSCAN) { if ((mode->CrtcHDisplay >= 1024) || (mode->CrtcVDisplay >= 768)) return MODE_CLOCK_RANGE; } return MODE_OK; } /* Adjust viewport into virtual desktop such that (0,0) in viewport * space is (x,y) in virtual space. */ void RADEONDoAdjustFrame(ScrnInfoPtr pScrn, int x, int y, Bool crtc2) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; int Base, reg, regcntl, crtcoffsetcntl, xytilereg, crtcxytile = 0; #ifdef XF86DRI drm_radeon_sarea_t *pSAREAPriv; XF86DRISAREAPtr pSAREA; #endif #if 0 /* Verbose */ xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "RADEONDoAdjustFrame(%d,%d,%d)\n", x, y, clone); #endif Base = pScrn->fbOffset; /* note we cannot really simply use the info->ModeReg.crtc_offset_cntl value, since the drm might have set FLIP_CNTL since we wrote that. Unfortunately FLIP_CNTL causes flickering when scrolling vertically in a virtual screen, possibly because crtc will pick up the new offset value at the end of each scanline, but the new offset_cntl value only after a vsync. We'd probably need to wait (in drm) for vsync and only then update OFFSET and OFFSET_CNTL, if the y coord has changed. Seems hard to fix. */ if (crtc2) { reg = RADEON_CRTC2_OFFSET; regcntl = RADEON_CRTC2_OFFSET_CNTL; xytilereg = R300_CRTC2_TILE_X0_Y0; } else { reg = RADEON_CRTC_OFFSET; regcntl = RADEON_CRTC_OFFSET_CNTL; xytilereg = R300_CRTC_TILE_X0_Y0; } crtcoffsetcntl = INREG(regcntl) & ~0xf; #if 0 /* try to get rid of flickering when scrolling at least for 2d */ #ifdef XF86DRI if (!info->dri->have3DWindows) #endif crtcoffsetcntl &= ~RADEON_CRTC_OFFSET_FLIP_CNTL; #endif if (info->tilingEnabled) { if (IS_R300_VARIANT || IS_AVIVO_VARIANT) { /* On r300/r400 when tiling is enabled crtc_offset is set to the address of * the surface. the x/y offsets are handled by the X_Y tile reg for each crtc * Makes tiling MUCH easier. */ crtcxytile = x | (y << 16); Base &= ~0x7ff; } else { int byteshift = info->CurrentLayout.bitsPerPixel >> 4; /* crtc uses 256(bytes)x8 "half-tile" start addresses? */ int tile_addr = (((y >> 3) * info->CurrentLayout.displayWidth + x) >> (8 - byteshift)) << 11; Base += tile_addr + ((x << byteshift) % 256) + ((y % 8) << 8); crtcoffsetcntl = crtcoffsetcntl | (y % 16); } } else { int offset = y * info->CurrentLayout.displayWidth + x; switch (info->CurrentLayout.pixel_code) { case 15: case 16: offset *= 2; break; case 24: offset *= 3; break; case 32: offset *= 4; break; } Base += offset; } Base &= ~7; /* 3 lower bits are always 0 */ #ifdef XF86DRI if (info->directRenderingInited) { /* note cannot use pScrn->pScreen since this is unitialized when called from RADEONScreenInit, and we need to call from there to get mergedfb + pageflip working */ /*** NOTE: r3/4xx will need sarea and drm pageflip updates to handle the xytile regs for *** pageflipping! ***/ pSAREAPriv = DRIGetSAREAPrivate(screenInfo.screens[pScrn->scrnIndex]); /* can't get at sarea in a semi-sane way? */ pSAREA = (void *)((char*)pSAREAPriv - sizeof(XF86DRISAREARec)); if (crtc2) { pSAREAPriv->crtc2_base = Base; } else { pSAREA->frame.x = (Base / info->CurrentLayout.pixel_bytes) % info->CurrentLayout.displayWidth; pSAREA->frame.y = (Base / info->CurrentLayout.pixel_bytes) / info->CurrentLayout.displayWidth; pSAREA->frame.width = pScrn->frameX1 - x + 1; pSAREA->frame.height = pScrn->frameY1 - y + 1; } if (pSAREAPriv->pfCurrentPage == 1) { Base += info->dri->backOffset - info->dri->frontOffset; } } #endif if (IS_R300_VARIANT || IS_AVIVO_VARIANT) { OUTREG(xytilereg, crtcxytile); } else { OUTREG(regcntl, crtcoffsetcntl); } OUTREG(reg, Base); } void RADEONAdjustFrame(int scrnIndex, int x, int y, int flags) { ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; RADEONInfoPtr info = RADEONPTR(pScrn); RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); xf86OutputPtr output = config->output[config->compat_output]; xf86CrtcPtr crtc = output->crtc; /* not handled */ if (IS_AVIVO_VARIANT) return; #ifdef XF86DRI if (info->cp->CPStarted && pScrn->pScreen) DRILock(pScrn->pScreen, 0); #endif if (info->accelOn) RADEON_SYNC(info, pScrn); if (crtc && crtc->enabled) { if (crtc == pRADEONEnt->pCrtc[0]) RADEONDoAdjustFrame(pScrn, crtc->desiredX + x, crtc->desiredY + y, FALSE); else RADEONDoAdjustFrame(pScrn, crtc->desiredX + x, crtc->desiredY + y, TRUE); crtc->x = output->initial_x + x; crtc->y = output->initial_y + y; } #ifdef XF86DRI if (info->cp->CPStarted && pScrn->pScreen) DRIUnlock(pScrn->pScreen); #endif } /* Called when VT switching back to the X server. Reinitialize the * video mode. */ Bool RADEONEnterVT(int scrnIndex, int flags) { ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; RADEONInfoPtr info = RADEONPTR(pScrn); xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); int i; xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "RADEONEnterVT\n"); if (!radeon_card_posted(pScrn)) { /* Softboot V_BIOS */ if (info->IsAtomBios) { rhdAtomASICInit(info->atomBIOS); } else { xf86Int10InfoPtr pInt; pInt = xf86InitInt10 (info->pEnt->index); if (pInt) { pInt->num = 0xe6; xf86ExecX86int10 (pInt); xf86FreeInt10 (pInt); } else { RADEONGetBIOSInitTableOffsets(pScrn); RADEONPostCardFromBIOSTables(pScrn); } } } /* Makes sure the engine is idle before doing anything */ RADEONWaitForIdleMMIO(pScrn); RADEONPMEnterVT(pScrn); for (i = 0; i < config->num_crtc; i++) radeon_crtc_modeset_ioctl(config->crtc[i], TRUE); pScrn->vtSema = TRUE; /* Clear the framebuffer */ memset(info->FB + pScrn->fbOffset, 0, pScrn->virtualY * pScrn->displayWidth * info->CurrentLayout.pixel_bytes); if (!xf86SetDesiredModes(pScrn)) return FALSE; if (info->ChipFamily < CHIP_FAMILY_R600) RADEONRestoreSurfaces(pScrn, info->ModeReg); #ifdef XF86DRI if (info->directRenderingEnabled) { if (info->cardType == CARD_PCIE && info->dri->pKernelDRMVersion->version_minor >= 19 && info->FbSecureSize) { #if X_BYTE_ORDER == X_BIG_ENDIAN unsigned char *RADEONMMIO = info->MMIO; unsigned int sctrl = INREG(RADEON_SURFACE_CNTL); /* we need to backup the PCIE GART TABLE from fb memory */ OUTREG(RADEON_SURFACE_CNTL, 0); #endif memcpy(info->FB + info->dri->pciGartOffset, info->dri->pciGartBackup, info->dri->pciGartSize); #if X_BYTE_ORDER == X_BIG_ENDIAN OUTREG(RADEON_SURFACE_CNTL, sctrl); #endif } /* get the DRI back into shape after resume */ RADEONDRISetVBlankInterrupt (pScrn, TRUE); RADEONDRIResume(pScrn->pScreen); RADEONAdjustMemMapRegisters(pScrn, info->ModeReg); } #endif /* this will get XVideo going again, but only if XVideo was initialised during server startup (hence the info->adaptor if). */ if (info->adaptor) RADEONResetVideo(pScrn); if (info->accelOn && (info->ChipFamily < CHIP_FAMILY_R600)) RADEONEngineRestore(pScrn); if (info->accelOn && info->accel_state) info->accel_state->XInited3D = FALSE; #ifdef XF86DRI if (info->directRenderingEnabled) { if (info->ChipFamily >= CHIP_FAMILY_R600) R600LoadShaders(pScrn); RADEONCP_START(pScrn, info); DRIUnlock(pScrn->pScreen); } #endif if (IS_R500_3D || IS_R300_3D) radeon_load_bicubic_texture(pScrn); return TRUE; } /* Called when VT switching away from the X server. Restore the * original text mode. */ void RADEONLeaveVT(int scrnIndex, int flags) { ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; RADEONInfoPtr info = RADEONPTR(pScrn); xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); int i; xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "RADEONLeaveVT\n"); #ifdef XF86DRI if (RADEONPTR(pScrn)->directRenderingInited) { RADEONDRISetVBlankInterrupt (pScrn, FALSE); DRILock(pScrn->pScreen, 0); RADEONCP_STOP(pScrn, info); if (info->cardType == CARD_PCIE && info->dri->pKernelDRMVersion->version_minor >= 19 && info->FbSecureSize) { #if X_BYTE_ORDER == X_BIG_ENDIAN unsigned char *RADEONMMIO = info->MMIO; unsigned int sctrl = INREG(RADEON_SURFACE_CNTL); /* we need to backup the PCIE GART TABLE from fb memory */ OUTREG(RADEON_SURFACE_CNTL, 0); #endif memcpy(info->dri->pciGartBackup, (info->FB + info->dri->pciGartOffset), info->dri->pciGartSize); #if X_BYTE_ORDER == X_BIG_ENDIAN OUTREG(RADEON_SURFACE_CNTL, sctrl); #endif } /* Make sure 3D clients will re-upload textures to video RAM */ if (info->dri->textureSize) { drm_radeon_sarea_t *pSAREAPriv = (drm_radeon_sarea_t*)DRIGetSAREAPrivate(pScrn->pScreen); struct drm_tex_region *list = pSAREAPriv->tex_list[0]; int age = ++pSAREAPriv->tex_age[0]; i = 0; do { list[i].age = age; i = list[i].next; } while (i != 0); } } #endif for (i = 0; i < config->num_crtc; i++) { xf86CrtcPtr crtc = config->crtc[i]; RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private; radeon_crtc->initialized = FALSE; #ifndef HAVE_FREE_SHADOW if (crtc->rotatedPixmap || crtc->rotatedData) { crtc->funcs->shadow_destroy(crtc, crtc->rotatedPixmap, crtc->rotatedData); crtc->rotatedPixmap = NULL; crtc->rotatedData = NULL; } #endif } #ifdef HAVE_FREE_SHADOW xf86RotateFreeShadow(pScrn); #endif xf86_hide_cursors (pScrn); RADEONPMLeaveVT(pScrn); RADEONRestore(pScrn); for (i = 0; i < config->num_crtc; i++) radeon_crtc_modeset_ioctl(config->crtc[i], FALSE); xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "Ok, leaving now...\n"); } /* Called at the end of each server generation. Restore the original * text mode, unmap video memory, and unwrap and call the saved * CloseScreen function. */ static Bool RADEONCloseScreen(int scrnIndex, ScreenPtr pScreen) { ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; RADEONInfoPtr info = RADEONPTR(pScrn); xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); int i; xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "RADEONCloseScreen\n"); RADEONPMFini(pScrn); /* Mark acceleration as stopped or we might try to access the engine at * wrong times, especially if we had DRI, after DRI has been stopped */ info->accelOn = FALSE; for (i = 0; i < config->num_crtc; i++) { xf86CrtcPtr crtc = config->crtc[i]; RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private; radeon_crtc->initialized = FALSE; } #ifdef XF86DRI #ifdef DAMAGE if (info->dri && info->dri->pDamage) { PixmapPtr pPix = pScreen->GetScreenPixmap(pScreen); DamageUnregister(&pPix->drawable, info->dri->pDamage); DamageDestroy(info->dri->pDamage); info->dri->pDamage = NULL; } #endif RADEONDRIStop(pScreen); #endif #ifdef USE_XAA if(!info->useEXA && info->accel_state->RenderTex) { xf86FreeOffscreenLinear(info->accel_state->RenderTex); info->accel_state->RenderTex = NULL; } #endif /* USE_XAA */ if (pScrn->vtSema) { RADEONRestore(pScrn); } xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "Disposing accel...\n"); #ifdef USE_EXA if (info->accel_state->exa) { exaDriverFini(pScreen); free(info->accel_state->exa); info->accel_state->exa = NULL; } #endif /* USE_EXA */ #ifdef USE_XAA if (!info->useEXA) { if (info->accel_state->accel) XAADestroyInfoRec(info->accel_state->accel); info->accel_state->accel = NULL; if (info->accel_state->scratch_save) free(info->accel_state->scratch_save); info->accel_state->scratch_save = NULL; } #endif /* USE_XAA */ xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "Disposing cursor info\n"); if (info->cursor) xf86DestroyCursorInfoRec(info->cursor); info->cursor = NULL; xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "Unmapping memory\n"); RADEONUnmapMem(pScrn); pScrn->vtSema = FALSE; xf86ClearPrimInitDone(info->pEnt->index); pScreen->BlockHandler = info->BlockHandler; pScreen->CloseScreen = info->CloseScreen; return (*pScreen->CloseScreen)(scrnIndex, pScreen); } void RADEONFreeScreen(int scrnIndex, int flags) { ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; RADEONInfoPtr info = RADEONPTR(pScrn); xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "RADEONFreeScreen\n"); /* when server quits at PreInit, we don't need do this anymore*/ if (!info) return; #ifdef WITH_VGAHW if (info->VGAAccess && xf86LoaderCheckSymbol("vgaHWFreeHWRec")) vgaHWFreeHWRec(pScrn); #endif RADEONFreeRec(pScrn); }