/* * Copyright 2007-2009 Luc Verhaegen * Copyright 2007-2009 Matthias Hopf * Copyright 2007-2009 Egbert Eich * Copyright 2009 Hans Ulrich Niedermann * Copyright 2007-2009 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 #ifdef ATOM_BIOS_PARSER # define ATOM_ASIC_INIT #endif #define MODULEVENDORSTRING "AMD GPG" /* @@@ */ #include "xf86.h" #include "xf86_OSproc.h" /* For PIO/MMIO */ #include "compiler.h" #if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 6 #include "xf86Resources.h" /* Needed by Resources Access Control (RAC) */ #include "xf86RAC.h" #endif #include "xf86PciInfo.h" /* do we need to access PCI config space directly? */ #include "xf86Pci.h" /* Memory manager */ #include "xf86fbman.h" /* For SW cursor */ #include "mipointer.h" /* For HW cursor */ #include "xf86Cursor.h" /* optional backing store */ #include "mibstore.h" /* mi colormap manipulation */ #include "micmap.h" #include "xf86cmap.h" #include "fb.h" #ifdef HAVE_XEXTPROTO_71 #include "X11/extensions/dpmsconst.h" #else #define DPMS_SERVER #include "X11/extensions/dpms.h" #endif /* int10 - for now at least */ #include "xf86int10.h" #include "vbe.h" /* Needed for Device Data Channel (DDC) support */ #include "xf86DDC.h" #include "picturestr.h" #ifdef USE_DRI #define _XF86DRI_SERVER_ #include "dri.h" #ifdef HAVE_XF86DRMMODE_H #include "xf86drmMode.h" #endif #endif #if HAVE_XF86_ANSIC_H # include "xf86_ansic.h" #else # include # include # include # include # define stat_t struct stat #endif /* * Driver data structures. */ #include "rhd.h" #include "rhd_regs.h" #include "rhd_cursor.h" #include "rhd_atombios.h" #include "rhd_connector.h" #include "rhd_output.h" #include "rhd_biosscratch.h" #include "rhd_pll.h" #include "rhd_vga.h" #include "rhd_mc.h" #include "rhd_monitor.h" #include "rhd_crtc.h" #include "rhd_modes.h" #include "rhd_lut.h" #include "rhd_i2c.h" #include "rhd_shadow.h" #include "rhd_card.h" #include "rhd_randr.h" #include "rhd_cs.h" #include "rhd_audio.h" #include "rhd_pm.h" #include "r5xx_accel.h" #include "rhd_video.h" #ifdef USE_DRI #include "r6xx_accel.h" #include "rhd_dri.h" #endif /* ??? */ #include "servermd.h" /* Mandatory functions */ static const OptionInfoRec * RHDAvailableOptions(int chipid, int busid); #ifdef XSERVER_LIBPCIACCESS static Bool RHDPciProbe(DriverPtr drv, int entityNum, struct pci_device *dev, intptr_t matchData); #else static Bool RHDProbe(DriverPtr drv, int flags); #endif static Bool RHDPreInit(ScrnInfoPtr pScrn, int flags); static Bool RHDScreenInit(int Index, ScreenPtr pScreen, int argc, char **argv); static Bool RHDEnterVT(int scrnIndex, int flags); static void RHDLeaveVT(int scrnIndex, int flags); static Bool RHDCloseScreen(int scrnIndex, ScreenPtr pScreen); static void RHDFreeScreen(int scrnIndex, int flags); static Bool RHDSwitchMode(int scrnIndex, DisplayModePtr mode, int flags); static void RHDAdjustFrame(int scrnIndex, int x, int y, int flags); static void RHDDisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode, int flags); static void RHDLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO *colors, VisualPtr pVisual); static Bool RHDSaveScreen(ScreenPtr pScrn, int on); static void rhdProcessOptions(ScrnInfoPtr pScrn); static void rhdSave(RHDPtr rhdPtr); static void rhdRestore(RHDPtr rhdPtr); static Bool rhdModeLayoutSelect(RHDPtr rhdPtr); static void rhdModeLayoutPrint(RHDPtr rhdPtr); static void rhdModeDPISet(ScrnInfoPtr pScrn); static Bool rhdAllIdle(RHDPtr rhdPtr); static void rhdModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode); static void rhdSetMode(ScrnInfoPtr pScrn, DisplayModePtr mode); static Bool rhdMapMMIO(RHDPtr rhdPtr); static void rhdUnmapMMIO(RHDPtr rhdPtr); static Bool rhdMapFB(RHDPtr rhdPtr); static void rhdUnmapFB(RHDPtr rhdPtr); static CARD32 rhdGetVideoRamSize(RHDPtr rhdPtr); static void rhdFbOffscreenGrab(ScrnInfoPtr pScrn); static void rhdGetIGPNorthBridgeInfo(RHDPtr rhdPtr); static enum rhdCardType rhdGetCardType(RHDPtr rhdPtr); /* rhd_id.c */ extern SymTabRec RHDChipsets[]; extern PciChipsets RHDPCIchipsets[]; extern void RHDIdentify(int flags); extern struct rhdCard *RHDCardIdentify(ScrnInfoPtr pScrn); #ifdef XSERVER_LIBPCIACCESS extern const struct pci_id_match RHDDeviceMatch[]; #endif /* keep accross drivers */ static int pix24bpp = 0; /* required for older X.Org releases */ #ifndef _X_EXPORT #define _X_EXPORT #endif #ifdef __linux__ # define FGLRX_SYS_PATH "/sys/module/fglrx" #endif #if XORG_VERSION_CURRENT >= 6 * 10000000 static const char *xaaSymbols[] = { "XAACreateInfoRec", "XAADestroyInfoRec", "XAAInit", NULL }; # ifdef USE_EXA static const char *exaSymbols[] = { "exaDriverAlloc", "exaDriverFini", "exaDriverInit", "exaGetPixmapOffset", "exaGetPixmapPitch", "exaMarkSync", "exaWaitSync", NULL }; # endif /* USE_EXA */ #endif _X_EXPORT DriverRec RADEONHD = { RHD_VERSION, RHD_DRIVER_NAME, RHDIdentify, #ifdef XSERVER_LIBPCIACCESS NULL, #else RHDProbe, #endif RHDAvailableOptions, NULL, 0, NULL, #ifdef XSERVER_LIBPCIACCESS RHDDeviceMatch, RHDPciProbe #endif }; typedef enum { OPTION_NOACCEL, OPTION_ACCELMETHOD, OPTION_OFFSCREENSIZE, OPTION_SW_CURSOR, OPTION_IGNORECONNECTOR, OPTION_FORCEREDUCED, OPTION_FORCEDPI, OPTION_USECONFIGUREDMONITOR, OPTION_HPD, OPTION_NORANDR, OPTION_RROUTPUTORDER, OPTION_DRI, OPTION_TV_MODE, OPTION_SCALE_TYPE, #ifdef ATOM_BIOS OPTION_USE_ATOMBIOS, OPTION_ATOMBIOS, /* only for testing, don't document in man page! */ #endif OPTION_UNVERIFIED_FEAT, OPTION_AUDIO, OPTION_AUDIO_WORKAROUND, OPTION_HDMI, OPTION_COHERENT, OPTION_FORCE_LOW_POWER, OPTION_LOW_POWER_CLOCK } RHDOpts; static const OptionInfoRec RHDOptions[] = { /* See above definition of enum RHDOpts for which options need * documentation and which ones should not be documented in the * man page. */ { OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_ACCELMETHOD, "AccelMethod", OPTV_ANYSTR, {0}, FALSE }, { OPTION_OFFSCREENSIZE, "offscreensize", OPTV_ANYSTR, {0}, FALSE }, { OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_IGNORECONNECTOR, "ignoreconnector", OPTV_ANYSTR, {0}, FALSE }, { OPTION_FORCEREDUCED, "forcereduced", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_FORCEDPI, "forcedpi", OPTV_INTEGER, {0}, FALSE }, { OPTION_USECONFIGUREDMONITOR, "useconfiguredmonitor", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_HPD, "HPD", OPTV_STRING, {0}, FALSE }, { OPTION_NORANDR, "NoRandr", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_RROUTPUTORDER, "RROutputOrder", OPTV_ANYSTR, {0}, FALSE }, { OPTION_DRI, "DRI", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_TV_MODE, "TVMode", OPTV_ANYSTR, {0}, FALSE }, { OPTION_SCALE_TYPE, "ScaleType", OPTV_ANYSTR, {0}, FALSE }, #ifdef ATOM_BIOS { OPTION_USE_ATOMBIOS, "UseAtomBIOS", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_ATOMBIOS, "AtomBIOS", OPTV_ANYSTR, {0}, FALSE }, #endif { OPTION_UNVERIFIED_FEAT, "UnverifiedFeatures", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_AUDIO, "Audio", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_AUDIO_WORKAROUND, "AudioStreamSilence", OPTV_ANYSTR, {0}, FALSE }, { OPTION_HDMI, "HDMI", OPTV_ANYSTR, {0}, FALSE }, { OPTION_COHERENT, "COHERENT", OPTV_ANYSTR, {0}, FALSE }, { OPTION_FORCE_LOW_POWER, "ForceLowPowerMode", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_LOW_POWER_CLOCK, "LowPowerModeEngineClock", OPTV_INTEGER, {0}, FALSE }, { -1, NULL, OPTV_NONE, {0}, FALSE } }; static MODULESETUPPROTO(rhdSetup); static XF86ModuleVersionInfo rhdVersRec = { "radeonhd", MODULEVENDORSTRING, MODINFOSTRING1, MODINFOSTRING2, XORG_VERSION_CURRENT, RHD_MAJOR_VERSION, RHD_MINOR_VERSION, RHD_PATCHLEVEL, ABI_CLASS_VIDEODRV, ABI_VIDEODRV_VERSION, MOD_CLASS_VIDEODRV, {0,0,0,0} }; _X_EXPORT XF86ModuleData radeonhdModuleData = { &rhdVersRec, rhdSetup, NULL }; static pointer rhdSetup(pointer module, pointer opts, int *errmaj, int *errmin) { static Bool setupDone = FALSE; if (!setupDone) { setupDone = TRUE; xf86AddDriver(&RADEONHD, module, HaveDriverFuncs); #if 0 /* @@@ */ LoaderRefSymLists(NULL); #endif /* return non-NULL even with no teardown */ return (pointer)1; } else { if (errmaj) *errmaj = LDR_ONCEONLY; return NULL; } } static Bool RHDGetRec(ScrnInfoPtr pScrn) { if (pScrn->driverPrivate != NULL) return TRUE; pScrn->driverPrivate = xnfcalloc(sizeof(RHDRec), 1); if (pScrn->driverPrivate == NULL) return FALSE; RHDPTR(pScrn)->scrnIndex = pScrn->scrnIndex; return TRUE; } static void RHDFreeRec(ScrnInfoPtr pScrn) { RHDPtr rhdPtr; if (pScrn->driverPrivate == NULL) return; rhdPtr = RHDPTR(pScrn); xfree(rhdPtr->Options); RHDMCDestroy(rhdPtr); RHDVGADestroy(rhdPtr); RHDPLLsDestroy(rhdPtr); RHDAudioDestroy(rhdPtr); RHDLUTsDestroy(rhdPtr); RHDOutputsDestroy(rhdPtr); RHDConnectorsDestroy(rhdPtr); RHDCursorsDestroy(rhdPtr); RHDCrtcsDestroy(rhdPtr); RHDI2CFunc(pScrn->scrnIndex, rhdPtr->I2C, RHD_I2C_TEARDOWN, NULL); #ifdef ATOM_BIOS RHDAtomBiosFunc(pScrn->scrnIndex, rhdPtr->atomBIOS, ATOM_TEARDOWN, NULL); #endif RHDShadowDestroy(rhdPtr); if (rhdPtr->CursorInfo) xf86DestroyCursorInfoRec(rhdPtr->CursorInfo); xfree(pScrn->driverPrivate); /* == rhdPtr */ pScrn->driverPrivate = NULL; } static const OptionInfoRec * RHDAvailableOptions(int chipid, int busid) { return RHDOptions; } /* * */ #ifdef XSERVER_LIBPCIACCESS static Bool RHDPciProbe(DriverPtr drv, int entityNum, struct pci_device *dev, intptr_t matchData) { ScrnInfoPtr pScrn; RHDPtr rhdPtr; pScrn = xf86ConfigPciEntity(NULL, 0, entityNum, NULL, RES_SHARED_VGA, NULL, NULL, NULL, NULL); if (pScrn != NULL) { #ifdef USE_DRI if (dev) { Bool kms = RHDKMSEnabled(pScrn, dev); if (kms) { xf86DrvMsgVerb(pScrn->scrnIndex, X_ERROR, 0, "FATAL: RadeonHD presently does not work with kernel modesetting (KMS).\n" "Please disable KMS in your kernel.\n"); return FALSE; } else { xf86DrvMsgVerb(pScrn->scrnIndex, X_ERROR, 0, "KMS is disabled. This is good for us, because RADEONHD conflicts with KMS.\n"); } } #endif pScrn->driverVersion = RHD_VERSION; pScrn->driverName = RHD_DRIVER_NAME; pScrn->name = RHD_NAME; pScrn->Probe = NULL; pScrn->PreInit = RHDPreInit; pScrn->ScreenInit = RHDScreenInit; pScrn->SwitchMode = RHDSwitchMode; pScrn->AdjustFrame = RHDAdjustFrame; pScrn->EnterVT = RHDEnterVT; pScrn->LeaveVT = RHDLeaveVT; pScrn->FreeScreen = RHDFreeScreen; pScrn->ValidMode = NULL; /* we do our own validation */ if (!RHDGetRec(pScrn)) return FALSE; rhdPtr = RHDPTR(pScrn); rhdPtr->PciInfo = dev; rhdPtr->ChipSet = matchData; } return (pScrn != NULL); } #else static Bool RHDProbe(DriverPtr drv, int flags) { Bool foundScreen = FALSE; int numDevSections, numUsed; GDevPtr *devSections; int *usedChips; int i; if ((numDevSections = xf86MatchDevice(RHD_DRIVER_NAME, &devSections)) <= 0) { return FALSE; } /* PCI BUS */ if (xf86GetPciVideoInfo() ) { numUsed = xf86MatchPciInstances(RHD_NAME, PCI_VENDOR_ATI, RHDChipsets, RHDPCIchipsets, devSections,numDevSections, drv, &usedChips); if (numUsed > 0) { if (flags & PROBE_DETECT) foundScreen = TRUE; else for (i = 0; i < numUsed; i++) { ScrnInfoPtr pScrn = NULL; if ((pScrn = xf86ConfigPciEntity(pScrn, 0, usedChips[i], RHDPCIchipsets,NULL, NULL, NULL, NULL, NULL))) { pScrn->driverVersion = RHD_VERSION; pScrn->driverName = RHD_DRIVER_NAME; pScrn->name = RHD_NAME; pScrn->Probe = RHDProbe; pScrn->PreInit = RHDPreInit; pScrn->ScreenInit = RHDScreenInit; pScrn->SwitchMode = RHDSwitchMode; pScrn->AdjustFrame = RHDAdjustFrame; pScrn->EnterVT = RHDEnterVT; pScrn->LeaveVT = RHDLeaveVT; pScrn->FreeScreen = RHDFreeScreen; pScrn->ValidMode = NULL; /* we do our own validation */ foundScreen = TRUE; } } xfree(usedChips); } } xfree(devSections); return foundScreen; } #endif /* * */ static Bool RHDPreInit(ScrnInfoPtr pScrn, int flags) { RHDPtr rhdPtr; Bool ret = FALSE; RHDI2CDataArg i2cArg; DisplayModePtr Modes; /* Non-RandR-case only */ stat_t statbuf; if (flags & PROBE_DETECT) { /* do dynamic mode probing */ return TRUE; } #ifdef FGLRX_SYS_PATH /* check for fglrx kernel module */ if (stat (FGLRX_SYS_PATH, &statbuf) == 0) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "The fglrx kernel module is loaded. This can have obvious\n" " or subtle side effects. See radeonhd(4) for details.\n"); } #endif #ifndef XSERVER_LIBPCIACCESS /* * Allocate the RhdRec driverPrivate * (for the PCIACCESS case this is done in Probe already) */ if (!RHDGetRec(pScrn)) { return FALSE; } #endif rhdPtr = RHDPTR(pScrn); /* Get server verbosity level */ rhdPtr->verbosity = xf86GetVerbosity(); /* This driver doesn't expect more than one entity per screen */ if (pScrn->numEntities > 1) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Driver doesn't support more than one entity per screen\n"); goto error0; } /* @@@ move to Probe? */ if (!(rhdPtr->pEnt = xf86GetEntityInfo(pScrn->entityList[0]))) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unable to get entity info\n"); goto error0; } #ifndef XSERVER_LIBPCIACCESS if (rhdPtr->pEnt->resources) { xfree(rhdPtr->pEnt); goto error0; } #endif pScrn->videoRam = rhdPtr->pEnt->device->videoRam; rhdPtr->entityIndex = rhdPtr->pEnt->index; #ifndef XSERVER_LIBPCIACCESS rhdPtr->ChipSet = rhdPtr->pEnt->chipset; rhdPtr->PciInfo = xf86GetPciInfoForEntity(rhdPtr->pEnt->index); rhdPtr->PciTag = pciTag(rhdPtr->PciInfo->bus, rhdPtr->PciInfo->device, rhdPtr->PciInfo->func); /* #else: RHDPciProbe() did this for us already */ #endif if (RHDIsIGP(rhdPtr->ChipSet)) rhdGetIGPNorthBridgeInfo(rhdPtr); pScrn->chipset = (char *)xf86TokenToString(RHDChipsets, rhdPtr->ChipSet); #ifndef XSERVER_LIBPCIACCESS /* We will disable access to VGA legacy resources emulation and save/restore VGA thru MMIO when necessary */ if (xf86RegisterResources(rhdPtr->entityIndex, NULL, ResNone)) goto error0; #endif #ifndef ATOM_ASIC_INIT if (xf86LoadSubModule(pScrn, "int10")) { xf86Int10InfoPtr Int10; xf86DrvMsg(pScrn->scrnIndex,X_INFO,"Initializing INT10\n"); if ((Int10 = xf86InitInt10(rhdPtr->entityIndex))) { /* * here we kludge to get a copy of V_BIOS for * the AtomBIOS code. After POSTing a PCI BIOS * is not accessible any more. On a non-primary * card it's lost after we do xf86FreeInt10(), * so we save it here before we kill int10. * This still begs the question what to do * on a non-primary card that has been POSTed * by an earlier Xserver start. */ if ((rhdPtr->BIOSCopy = xalloc(RHD_VBIOS_SIZE))) { (void)memcpy(rhdPtr->BIOSCopy, xf86int10Addr(Int10, Int10->BIOSseg << 4), RHD_VBIOS_SIZE); } xf86FreeInt10(Int10); } } #endif /* xf86CollectOptions cluelessly depends on these and will SIGSEGV otherwise */ pScrn->monitor = pScrn->confScreen->monitor; if (!xf86SetDepthBpp(pScrn, 24, 0, 0, Support32bppFb)) { goto error0; } else { /* Check that the returned depth is one we support */ 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 this driver\n", pScrn->depth); goto error0; } } xf86PrintDepthBpp(pScrn); rhdProcessOptions(pScrn); /* Now check whether we know this card */ rhdPtr->Card = RHDCardIdentify(pScrn); if (rhdPtr->Card) xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Detected an %s on a %s\n", pScrn->chipset, rhdPtr->Card->name); else xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Detected an %s on an " "unidentified card\n", pScrn->chipset); if (rhdPtr->Card && rhdPtr->Card->flags & RHD_CARD_FLAG_HPDSWAP && rhdPtr->hpdUsage == RHD_HPD_USAGE_AUTO) rhdPtr->hpdUsage = RHD_HPD_USAGE_AUTO_SWAP; if (rhdPtr->Card && rhdPtr->Card->flags & RHD_CARD_FLAG_HPDOFF && rhdPtr->hpdUsage == RHD_HPD_USAGE_AUTO) rhdPtr->hpdUsage = RHD_HPD_USAGE_AUTO_OFF; /* We need access to IO space already */ if (!rhdMapMMIO(rhdPtr)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to map MMIO.\n"); goto error0; } rhdPtr->cardType = rhdGetCardType(rhdPtr); #ifdef ATOM_BIOS { AtomBiosArgRec atomBiosArg; if (RHDAtomBiosFunc(pScrn->scrnIndex, NULL, ATOM_INIT, &atomBiosArg) == ATOM_SUCCESS) { rhdPtr->atomBIOS = atomBiosArg.atomhandle; } else { if (RHDUseAtom(rhdPtr, NULL, atomUsageAny)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No AtomBIOS image found but required for AtomBIOS based mode setting\n"); goto error0; /* @@@ No blacklist handling. So far no blacklists are used for any subsystem */ } } } #else xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "**************************************************\n"); xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "** Code has been built without AtomBIOS support **\n"); xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "** this may seriously affect the functionality ***\n"); xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "** of this driver ***\n"); xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "**************************************************\n"); if (RHDUseAtom(rhdPtr, NULL, atomUsageAny)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No AtomBIOS support compiled in but required for this chipset/ current settings\n"); goto error0; } #endif rhdPtr->tvMode = RHD_TV_NONE; { const struct { char *name; enum RHD_TV_MODE mode; } rhdTVModeMapName[] = { {"NTSC", RHD_TV_NTSC}, {"NTSCJ", RHD_TV_NTSCJ}, {"PAL", RHD_TV_PAL}, {"PALM", RHD_TV_PALM}, {"PALCN", RHD_TV_PALCN}, {"PALN", RHD_TV_PALN}, {"PAL60", RHD_TV_PAL60}, {"SECAM", RHD_TV_SECAM}, {"CV", RHD_TV_CV}, {NULL, RHD_TV_NONE} }; if (rhdPtr->tvModeName.set) { int i = 0; while (rhdTVModeMapName[i].name) { if (!strcmp(rhdTVModeMapName[i].name, rhdPtr->tvModeName.val.string)) { rhdPtr->tvMode = rhdTVModeMapName[i].mode; break; } i++; } if (rhdPtr->tvMode == RHD_TV_NONE) { xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "Specified TV Mode %s is invalid\n", rhdPtr->tvModeName.val.string); } } #ifdef ATOM_BIOS if (rhdPtr->tvMode == RHD_TV_NONE) { AtomBiosArgRec atomBiosArg; int i = 0; if (RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS, ATOM_ANALOG_TV_DEFAULT_MODE, &atomBiosArg) == ATOM_SUCCESS) { rhdPtr->tvMode = atomBiosArg.tvMode; while (rhdTVModeMapName[i].name) { if (rhdTVModeMapName[i].mode == rhdPtr->tvMode) { xf86DrvMsg(rhdPtr->scrnIndex, X_INFO, "Found default TV Mode %s\n",rhdTVModeMapName[i].name); break; } i++; } } } #endif } /* We can use a register which is programmed by the BIOS to find out the size of our framebuffer */ if (!pScrn->videoRam) { pScrn->videoRam = rhdGetVideoRamSize(rhdPtr); if (!pScrn->videoRam) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No Video RAM detected.\n"); goto error1; } } xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "VideoRAM: %d kByte\n", pScrn->videoRam); rhdPtr->FbFreeStart = 0; rhdPtr->FbFreeSize = pScrn->videoRam * 1024; #ifdef ATOM_BIOS if (rhdPtr->atomBIOS) { /* for testing functions */ AtomBiosArgRec atomBiosArg; atomBiosArg.fb.start = rhdPtr->FbFreeStart; atomBiosArg.fb.size = rhdPtr->FbFreeSize; if (RHDAtomBiosFunc(pScrn->scrnIndex, rhdPtr->atomBIOS, ATOM_ALLOCATE_FB_SCRATCH, &atomBiosArg) == ATOM_SUCCESS) { rhdPtr->FbFreeStart = atomBiosArg.fb.start; rhdPtr->FbFreeSize = atomBiosArg.fb.size; } RHDAtomBiosFunc(pScrn->scrnIndex, rhdPtr->atomBIOS, ATOM_GET_DEFAULT_ENGINE_CLOCK, &atomBiosArg); RHDAtomBiosFunc(pScrn->scrnIndex, rhdPtr->atomBIOS, ATOM_GET_DEFAULT_MEMORY_CLOCK, &atomBiosArg); RHDAtomBiosFunc(pScrn->scrnIndex, rhdPtr->atomBIOS, ATOM_GET_MAX_PIXEL_CLOCK_PLL_OUTPUT, &atomBiosArg); RHDAtomBiosFunc(pScrn->scrnIndex, rhdPtr->atomBIOS, ATOM_GET_MIN_PIXEL_CLOCK_PLL_OUTPUT, &atomBiosArg); RHDAtomBiosFunc(pScrn->scrnIndex, rhdPtr->atomBIOS, ATOM_GET_MAX_PIXEL_CLOCK_PLL_INPUT, &atomBiosArg); RHDAtomBiosFunc(pScrn->scrnIndex, rhdPtr->atomBIOS, ATOM_GET_MIN_PIXEL_CLOCK_PLL_INPUT, &atomBiosArg); RHDAtomBiosFunc(pScrn->scrnIndex, rhdPtr->atomBIOS, ATOM_GET_MAX_PIXEL_CLK, &atomBiosArg); RHDAtomBiosFunc(pScrn->scrnIndex, rhdPtr->atomBIOS, ATOM_GET_REF_CLOCK, &atomBiosArg); } #endif if (rhdPtr->ChipSet >= RHD_R600 && rhdPtr->AccelMethod == RHD_ACCEL_XAA) { rhdPtr->AccelMethod = RHD_ACCEL_EXA; xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Accel Method XAA not supported on this chipset generation." " Defaulting to EXA\n"); } #ifdef USE_DRI ret = RHDDRIPreInit(pScrn); if (!ret && rhdPtr->ChipSet >= RHD_R600 && rhdPtr->AccelMethod > RHD_ACCEL_SHADOWFB) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Falling back to ShadowFB acceleration\n"); rhdPtr->AccelMethod = RHD_ACCEL_SHADOWFB; } #else xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "DRI support has been disabled at compile time\n"); if (rhdPtr->ChipSet >= RHD_R600 && rhdPtr->AccelMethod == RHD_ACCEL_EXA) { rhdPtr->AccelMethod = RHD_ACCEL_SHADOWFB; xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Accel Method EXA requires DRI on this chip. Falling back to SHADOW_FB.\n"); } #endif if (rhdPtr->AccelMethod == RHD_ACCEL_FORCE_SHADOWFB) rhdPtr->AccelMethod = RHD_ACCEL_SHADOWFB; if (xf86LoadSubModule(pScrn, "i2c")) { if (RHDI2CFunc(pScrn->scrnIndex, NULL, RHD_I2C_INIT, &i2cArg) == RHD_I2C_SUCCESS) { rhdPtr->I2C = i2cArg.I2CBusList; if (!xf86LoadSubModule(pScrn, "ddc")) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "%s: Failed to load DDC module\n",__func__); goto error1; } } else { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "I2C init failed\n"); goto error1; } } else { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "%s: Failed to load I2C module\n",__func__); goto error1; } /* Init modesetting structures */ RHDVGAInit(rhdPtr); RHDMCInit(rhdPtr); if (!RHDCrtcsInit(rhdPtr)) RHDAtomCrtcsInit(rhdPtr); if (!RHDPLLsInit(rhdPtr)) RHDAtomPLLsInit(rhdPtr); RHDAudioInit(rhdPtr); RHDLUTsInit(rhdPtr); RHDCursorsInit(rhdPtr); /* do this irrespective of hw/sw cursor setting */ RHDPmInit(rhdPtr); if (!RHDConnectorsInit(rhdPtr, rhdPtr->Card)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Card information has invalid connector information\n"); goto error1; } { #ifdef ATOM_BIOS struct rhdAtomOutputDeviceList *OutputDeviceList = NULL; if (rhdPtr->Card && rhdPtr->Card->ConnectorInfo[0].Type != RHD_CONNECTOR_NONE && (rhdPtr->Card->DeviceInfo[0][0] != atomNone || rhdPtr->Card->DeviceInfo[0][1] != atomNone)) { int i, k = 0; for (i = 0; i < RHD_CONNECTORS_MAX; i++) { int j; if (rhdPtr->Card->ConnectorInfo[i].Type == RHD_CONNECTOR_NONE) break; for (j = 0; j < MAX_OUTPUTS_PER_CONNECTOR; j++) { if (rhdPtr->Card->ConnectorInfo[i].Output[j] != RHD_OUTPUT_NONE) { if (!(OutputDeviceList = (struct rhdAtomOutputDeviceList *)xrealloc( OutputDeviceList, sizeof (struct rhdAtomOutputDeviceList) * (k + 1)))) break; OutputDeviceList[k].ConnectorType = rhdPtr->Card->ConnectorInfo[i].Type; OutputDeviceList[k].DeviceId = rhdPtr->Card->DeviceInfo[i][j]; OutputDeviceList[k].OutputType = rhdPtr->Card->ConnectorInfo[i].Output[j]; RHDDebug(rhdPtr->scrnIndex, "OutputDevice: C: 0x%2.2x O: 0x%2.2x DevID: 0x%2.2x\n", OutputDeviceList[k].ConnectorType, OutputDeviceList[k].OutputType, OutputDeviceList[k].DeviceId); k++; } } } } else { AtomBiosArgRec data; data.chipset = rhdPtr->ChipSet; if (RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS, ATOM_GET_OUTPUT_DEVICE_LIST, &data) == ATOM_SUCCESS) OutputDeviceList = data.OutputDeviceList; } if (OutputDeviceList) { struct rhdOutput *Output; for (Output = rhdPtr->Outputs; Output; Output = Output->Next) RHDAtomSetupOutputDriverPrivate(OutputDeviceList, Output); xfree(OutputDeviceList); } #endif } /* * Set this here as we might need it for the validation of a fixed mode in * rhdModeLayoutSelect(). Later it is used for Virtual selection and mode * pool creation. * For Virtual selection, the scanout area is all the free space we have. */ rhdPtr->FbScanoutStart = rhdPtr->FbFreeStart; rhdPtr->FbScanoutSize = rhdPtr->FbFreeSize; RHDRandrPreInit(pScrn); if (!rhdPtr->randr) { Bool configured; /* Pick anything for now */ if (!rhdModeLayoutSelect(rhdPtr)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to detect a connected monitor\n"); goto error1; } /* set up rhdPtr->ConfigMonitor */ if (!xf86GetOptValBool(rhdPtr->Options, OPTION_USECONFIGUREDMONITOR, &configured)) configured = FALSE; RHDConfigMonitorSet(pScrn->scrnIndex, configured); rhdModeLayoutPrint(rhdPtr); } /* @@@ rgb bits boilerplate */ if (pScrn->depth == 8) pScrn->rgbBits = 8; /* Get the depth24 pixmap format */ if (pScrn->depth == 24 && pix24bpp == 0) pix24bpp = xf86GetBppFromDepth(pScrn, 24); /* * This must happen after pScrn->display has been set because * xf86SetWeight references it. */ if (pScrn->depth > 8) { /* The defaults are OK for us */ rgb zeros = {0, 0, 0}; if (!xf86SetWeight(pScrn, zeros, zeros)) { goto error1; } else { /* XXX check that weight returned is supported */ ; } } if (!xf86SetDefaultVisual(pScrn, -1)) { goto error1; } else { /* We don't currently support DirectColor at > 8bpp */ if (pScrn->depth > 8 && pScrn->defaultVisual != TrueColor) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Given default visual" " (%s) is not supported at depth %d\n", xf86GetVisualName(pScrn->defaultVisual), pScrn->depth); goto error1; } } if (pScrn->depth > 1) { Gamma zeros = {0.0, 0.0, 0.0}; /* @@@ */ if (!xf86SetGamma(pScrn, zeros)) { goto error1; } } /* @@@ need this? */ pScrn->progClock = TRUE; if (pScrn->display->virtualX && pScrn->display->virtualY) if (!RHDGetVirtualFromConfig(pScrn)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unable to find valid framebuffer dimensions\n"); goto error1; } if (! rhdPtr->randr) { Modes = RHDModesPoolCreate(pScrn, FALSE); if (!Modes) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n"); goto error1; } if (!pScrn->virtualX || !pScrn->virtualY) RHDGetVirtualFromModesAndFilter(pScrn, Modes, FALSE); RHDModesAttach(pScrn, Modes); rhdModeDPISet(pScrn); } xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using %dx%d Framebuffer with %d pitch\n", pScrn->virtualX, pScrn->virtualY, pScrn->displayWidth); /* grab the real scanout area and adjust the free space */ rhdPtr->FbScanoutSize = RHD_FB_CHUNK(pScrn->displayWidth * pScrn->bitsPerPixel * pScrn->virtualY / 8); rhdPtr->FbScanoutStart = RHDAllocFb(rhdPtr, rhdPtr->FbScanoutSize, "ScanoutBuffer"); ASSERT(rhdPtr->FbScanoutStart != (unsigned)-1); if (!rhdPtr->randr) xf86PrintModes(pScrn); else /* If monitor resolution is set on the command line, use it */ xf86SetDpi(pScrn, 0, 0); if (xf86LoadSubModule(pScrn, "fb") == NULL) { goto error1; } if (!rhdPtr->swCursor.val.bool) { if (!xf86LoadSubModule(pScrn, "ramdac")) { goto error1; } } /* try to load the XAA module here */ if (rhdPtr->AccelMethod == RHD_ACCEL_XAA) { if (!xf86LoadSubModule(pScrn, "xaa")) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to load XAA module." " Falling back to ShadowFB.\n"); rhdPtr->AccelMethod = RHD_ACCEL_SHADOWFB; } /* This is functionally void since 7.0 (old version scheme, * and removed since 1.6.99.1 (new version scheme) */ /* Assume anything >= 6.* is old version scheme */ #if XORG_VERSION_CURRENT >= 6 * 10000000 else xf86LoaderReqSymLists(xaaSymbols, NULL); #endif } #ifdef USE_EXA /* try to load the EXA module here */ if (rhdPtr->AccelMethod == RHD_ACCEL_EXA) { if (!xf86LoadSubModule(pScrn, "exa")) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to load EXA module." " Falling back to ShadowFB.\n"); rhdPtr->AccelMethod = RHD_ACCEL_SHADOWFB; } /* This is functionally void since 7.0 (old version scheme, * and removed since 1.6.99.1 (new version scheme) */ /* Assume anything >= 6.* is old version scheme */ #if XORG_VERSION_CURRENT >= 6 * 10000000 else xf86LoaderReqSymLists(exaSymbols, NULL); #endif } #endif /* USE_EXA */ /* Last resort: try shadowFB */ if (rhdPtr->AccelMethod == RHD_ACCEL_SHADOWFB) RHDShadowPreInit(pScrn); if ((rhdPtr->AccelMethod == RHD_ACCEL_XAA) || (rhdPtr->AccelMethod == RHD_ACCEL_EXA)) rhdFbOffscreenGrab(pScrn); #ifdef USE_DRI if (rhdPtr->dri) RHDDRIAllocateBuffers(pScrn); #endif RHDDebug(pScrn->scrnIndex, "Free FB offset 0x%08X (size = 0x%08X)\n", rhdPtr->FbFreeStart, rhdPtr->FbFreeSize); ret = TRUE; error1: rhdUnmapMMIO(rhdPtr); error0: if (!ret) RHDFreeRec(pScrn); return ret; } /* Mandatory */ static Bool RHDScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) { ScrnInfoPtr pScrn; RHDPtr rhdPtr; VisualPtr visual; #ifndef XSERVER_LIBPCIACCESS unsigned int racflag = 0; #endif #ifdef USE_DRI Bool DriScreenInited = FALSE; #endif pScrn = xf86Screens[pScreen->myNum]; rhdPtr = RHDPTR(pScrn); RHDFUNC(pScrn); /* map IO and FB */ if (!rhdMapMMIO(rhdPtr)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to map MMIO.\n"); return FALSE; } if (!rhdMapFB(rhdPtr)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to map FB.\n"); return FALSE; } /* save previous mode */ rhdSave(rhdPtr); /* init DIX */ miClearVisualTypes(); /* Setup the visuals we support. */ if (!miSetVisualTypes(pScrn->depth, miGetDefaultVisualMask(pScrn->depth), pScrn->rgbBits, pScrn->defaultVisual)) return FALSE; if (!miSetPixmapDepths()) return FALSE; /* Setup memory to which we draw; either shadow (RAM) or scanout (FB) */ if (rhdPtr->AccelMethod == RHD_ACCEL_SHADOWFB) { if (!RHDShadowScreenInit(pScreen)) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "ShadowFB initialisation failed." " Continuing without ShadowFB.\n"); rhdPtr->AccelMethod = RHD_ACCEL_NONE; } } /* disable all memory accesses for MC setup */ RHDVGADisable(rhdPtr); if (!rhdAllIdle(rhdPtr)) return FALSE; /* now set up the MC - has to be done after AllIdle and before DRI init */ if (!RHDMCSetupFBLocation(rhdPtr, rhdPtr->FbIntAddress, rhdPtr->FbIntSize)) return FALSE; #ifdef USE_DRI /* Setup DRI after visuals have been established, but before fbScreenInit is * called. */ if (rhdPtr->dri) DriScreenInited = RHDDRIScreenInit(pScreen); #endif /* shadowfb is allowed to fail gracefully too */ if ((rhdPtr->AccelMethod != RHD_ACCEL_SHADOWFB) && !fbScreenInit(pScreen, (CARD8 *) rhdPtr->FbBase + rhdPtr->FbScanoutStart, pScrn->virtualX, pScrn->virtualY, pScrn->xDpi, pScrn->yDpi, pScrn->displayWidth, pScrn->bitsPerPixel)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "%s: fbScreenInit failed.\n", __func__); return FALSE; } /* must be done after fbScreenInit() */ if (pScrn->depth > 8) { /* Fixup RGB ordering */ visual = pScreen->visuals + pScreen->numVisuals; while (--visual >= pScreen->visuals) { if ((visual->class | DynamicClass) == DirectColor && visual->nplanes > 8) { 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 ordering fixed */ fbPictureInit(pScreen, 0, 0); xf86SetBlackWhitePixels(pScreen); /* Static power management */ if (rhdPtr->Pm) rhdPtr->Pm->SelectState (rhdPtr, RHD_PM_IDLE); #ifdef USE_DRI if (DriScreenInited) rhdPtr->directRenderingEnabled = RHDDRIFinishScreenInit(pScreen); #endif /* Initialize command submission backend */ RHDCSInit(pScrn); if (rhdPtr->CS) RHDCSStart(rhdPtr->CS); /* Init 2D after DRI is set up */ switch (rhdPtr->AccelMethod) { case RHD_ACCEL_SHADOWFB: if (!RHDShadowSetup(pScreen)) /* No safetynet anymore */ return FALSE; break; case RHD_ACCEL_XAA: if (rhdPtr->ChipSet < RHD_R600) { if (!R5xxXAAInit(pScrn, pScreen)) { rhdPtr->AccelMethod = RHD_ACCEL_NONE; xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Failed to initalize XAA; disabling acceleration.\n"); } } else { rhdPtr->AccelMethod = RHD_ACCEL_NONE; xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "XAA is not supported on R600 and above; disabling acceleration.\n"); } break; #ifdef USE_DRI case RHD_ACCEL_EXA: if (rhdPtr->ChipSet < RHD_R600) { if (!R5xxEXAInit(pScrn, pScreen)) { rhdPtr->AccelMethod = RHD_ACCEL_NONE; xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Failed to initalize EXA; disabling acceleration.\n"); } } else { if (!R6xxEXAInit(pScrn, pScreen)) { rhdPtr->AccelMethod = RHD_ACCEL_NONE; xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Failed to initalize EXA; disabling acceleration.\n"); } } break; #endif /* USE_DRI */ default: rhdPtr->AccelMethod = RHD_ACCEL_NONE; break; } if (rhdPtr->ChipSet < RHD_R600) { if (rhdPtr->TwoDPrivate) R5xx2DStart(pScrn); R5xxEngineWaitIdleFull(rhdPtr->CS); } miInitializeBackingStore(pScreen); xf86SetBackingStore(pScreen); xf86SetSilkenMouse(pScreen); /* init randr */ if (rhdPtr->randr && !RHDRandrScreenInit (pScreen)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "RandrScreenInit failed. Try Option \"noRandr\"\n"); return FALSE; } #ifdef ATOM_BIOS /* Set accelerator mode in the BIOSScratch registers */ RHDAtomBIOSScratchSetAccelratorMode(rhdPtr, TRUE); #endif RHDPrepareMode(rhdPtr); /* now init the new mode */ if (rhdPtr->randr) RHDRandrModeInit(pScrn); else rhdModeInit(pScrn, pScrn->currentMode); /* fix viewport */ RHDAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); /* enable/disable audio */ RHDAudioSetEnable(rhdPtr, rhdPtr->audio.val.bool); /* Initialise cursor functions */ miDCInitialize (pScreen, xf86GetPointerScreenFuncs()); /* Inititalize HW cursor */ if (!rhdPtr->swCursor.val.bool) { Bool ret; if (rhdPtr->randr == NULL) ret = RHDxf86InitCursor(pScreen); else ret = RHDRRInitCursor(pScreen); if (!ret) xf86DrvMsg(scrnIndex, X_ERROR, "Hardware cursor initialization failed\n"); } /* default colormap */ if(!miCreateDefColormap(pScreen)) return FALSE; /* fixme */ /* Support 10-bits of precision in LUT */ if (!xf86HandleColormaps(pScreen, 256, 10, RHDLoadPalette, NULL, CMAP_PALETTED_TRUECOLOR | CMAP_RELOAD_ON_MODE_SWITCH)) return FALSE; #ifndef XSERVER_LIBPCIACCESS pScrn->racIoFlags = pScrn->racMemFlags = racflag; #endif /* Function to unblank, so that we don't show an uninitialised FB */ pScreen->SaveScreen = RHDSaveScreen; /* Setup DPMS mode */ xf86DPMSInit(pScreen, (DPMSSetProcPtr)RHDDisplayPowerManagementSet,0); pScrn->memPhysBase = rhdPtr->FbPhysAddress + rhdPtr->FbScanoutStart; if (rhdPtr->TwoDPrivate) RHDInitVideo(pScreen); /* Wrap the current CloseScreen function */ rhdPtr->CloseScreen = pScreen->CloseScreen; pScreen->CloseScreen = RHDCloseScreen; /* Report any unused options (only for the first generation) */ if (serverGeneration == 1) { xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options); } return TRUE; } static Bool rhdAllIdle(RHDPtr rhdPtr) { int i; /* Make sure that VGA has been disabled before calling AllIdle() */ ASSERT(RHD_CHECKDEBUGFLAG(rhdPtr, VGA_SETUP)); /* stop scanout */ for (i = 0; i < 2; i++) if (!rhdPtr->Crtc[i]->Power(rhdPtr->Crtc[i], RHD_POWER_RESET)) { xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "%s: unable to stop CRTC: cannot idle MC\n", __func__); return FALSE; } if (!RHDMCIdleWait(rhdPtr, 1000)) { xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "MC not idle\n"); return FALSE; } return TRUE; } /* * */ static void rhdEngineIdle(ScrnInfoPtr pScrn) { RHDPtr rhdPtr = RHDPTR(pScrn); struct RhdCS *CS = rhdPtr->CS; if (CS) { if (rhdPtr->ChipSet < RHD_R600) { R5xxDstCacheFlush(CS); R5xxEngineWaitIdleFull(CS); } RHDCSFlush(CS); RHDCSIdle(CS); } if (rhdPtr->TwoDPrivate) { #ifdef USE_DRI if (rhdPtr->ChipSet >= RHD_R600) R6xxIdle(pScrn); else #endif /* USE_DRI */ R5xx2DIdle(pScrn); } } /* Mandatory */ static Bool RHDCloseScreen(int scrnIndex, ScreenPtr pScreen) { ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; RHDPtr rhdPtr = RHDPTR(pScrn); Bool Idle = TRUE; /* yes, this is correct! */ RHDFUNC(rhdPtr); /* Make sure our CS and 2D status is clean before destroying it */ if (pScrn->vtSema) rhdEngineIdle(pScrn); /* tear down 2d accel infrastructure */ if (rhdPtr->AccelMethod == RHD_ACCEL_SHADOWFB) RHDShadowCloseScreen(pScreen); #ifdef USE_DRI else if (rhdPtr->AccelMethod == RHD_ACCEL_EXA) { if (rhdPtr->ChipSet < RHD_R600) { R5xxEXACloseScreen(pScreen); R5xxEXADestroy(pScrn); } else { R6xxEXACloseScreen(pScreen); R6xxEXADestroy(pScrn); } } else #endif /* USE_DRI */ if (rhdPtr->AccelMethod == RHD_ACCEL_XAA) { if (rhdPtr->ChipSet < RHD_R600) R5xxXAADestroy(pScrn); } if ((rhdPtr->ChipSet < RHD_R600) && rhdPtr->ThreeDPrivate) R5xx3DDestroy(pScrn); if (rhdPtr->CS) RHDCSStop(rhdPtr->CS); if (pScrn->vtSema) Idle = rhdAllIdle(rhdPtr); #ifdef USE_DRI if (rhdPtr->dri) { if (Idle) RHDDRICloseScreen(pScreen); else xf86DrvMsg(scrnIndex, X_ERROR, "MC not idle, cannot close DRI\n"); } #endif if (pScrn->vtSema) rhdRestore(rhdPtr); rhdUnmapFB(rhdPtr); rhdUnmapMMIO(rhdPtr); pScrn->vtSema = FALSE; pScreen->CloseScreen = rhdPtr->CloseScreen; return (*pScreen->CloseScreen)(scrnIndex, pScreen); } /* Optional */ static void RHDFreeScreen(int scrnIndex, int flags) { RHDFreeRec(xf86Screens[scrnIndex]); } /* Mandatory */ static Bool RHDEnterVT(int scrnIndex, int flags) { ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; RHDPtr rhdPtr = RHDPTR(pScrn); RHDFUNC(rhdPtr); rhdSave(rhdPtr); /* disable all memory accesses for MC setup */ RHDVGADisable(rhdPtr); if (!rhdAllIdle(rhdPtr)) return FALSE; /* now set up the MC - has to be done before DRI init */ RHDMCSetupFBLocation(rhdPtr, rhdPtr->FbIntAddress, rhdPtr->FbIntSize); #ifdef ATOM_BIOS /* Set accelerator mode in the BIOSScratch registers */ RHDAtomBIOSScratchSetAccelratorMode(rhdPtr, TRUE); #endif if (rhdPtr->randr) RHDRandrModeInit(pScrn); else rhdModeInit(pScrn, pScrn->currentMode); /* @@@ video overlays can be initialized here */ if (rhdPtr->CursorInfo) rhdReloadCursor(pScrn); /* rhdShowCursor() done by AdjustFrame */ RHDAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); /* enable/disable audio */ RHDAudioSetEnable(rhdPtr, rhdPtr->audio.val.bool); /* Static power management */ if (rhdPtr->Pm) rhdPtr->Pm->SelectState (rhdPtr, RHD_PM_IDLE); #ifdef USE_DRI if (rhdPtr->dri) RHDDRIEnterVT(pScrn->pScreen); #endif if (rhdPtr->CS) { #ifdef USE_DRI if (rhdPtr->ChipSet >= RHD_R600) { if (rhdPtr->TwoDPrivate) { R600LoadShaders(pScrn); R6xxIdle(pScrn); ((struct r6xx_accel_state *) rhdPtr->TwoDPrivate)->XHas3DEngineState = FALSE; } } else { #endif if (rhdPtr->TwoDPrivate) { R5xx2DSetup(pScrn); R5xx2DIdle(pScrn); } if (rhdPtr->ThreeDPrivate) ((struct R5xx3D *) rhdPtr->ThreeDPrivate)->XHas3DEngineState = FALSE; #ifdef USE_DRI } #endif RHDCSStart(rhdPtr->CS); if (rhdPtr->ChipSet < RHD_R600) R5xxEngineWaitIdleFull(rhdPtr->CS); RHDCSFlush(rhdPtr->CS); RHDCSIdle(rhdPtr->CS); } #ifdef USE_DRI if (rhdPtr->dri) { DRIUnlock(pScrn->pScreen); } #endif return TRUE; } /* Mandatory */ static void RHDLeaveVT(int scrnIndex, int flags) { ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; RHDPtr rhdPtr = RHDPTR(pScrn); RHDFUNC(rhdPtr); #ifdef USE_DRI if (rhdPtr->dri) RHDDRILeaveVT(pScrn->pScreen); #endif rhdEngineIdle(pScrn); if (rhdPtr->CS) RHDCSStop(rhdPtr->CS); rhdAllIdle(rhdPtr); if (rhdPtr->randr) RHDRRFreeShadow(pScrn); rhdRestore(rhdPtr); } static Bool RHDSwitchMode(int scrnIndex, DisplayModePtr mode, int flags) { ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; RHDPtr rhdPtr = RHDPTR(pScrn); RHDFUNC(rhdPtr); rhdEngineIdle(pScrn); if (rhdPtr->randr) RHDRandrSwitchMode(pScrn, mode); else { RHDPrepareMode(rhdPtr); rhdSetMode(xf86Screens[scrnIndex], mode); } return TRUE; } /* * High level bit banging functions */ static void RHDAdjustFrame(int scrnIndex, int x, int y, int flags) { ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; RHDPtr rhdPtr = RHDPTR(pScrn); struct rhdCrtc *Crtc; if (! rhdPtr->randr) { Crtc = rhdPtr->Crtc[0]; if ((Crtc->scrnIndex == scrnIndex) && Crtc->Active) Crtc->FrameSet(Crtc, x, y); Crtc = rhdPtr->Crtc[1]; if ((Crtc->scrnIndex == scrnIndex) && Crtc->Active) Crtc->FrameSet(Crtc, x, y); } if (rhdPtr->CursorInfo) rhdShowCursor(pScrn); } static void RHDDisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode, int flags) { RHDPtr rhdPtr = RHDPTR(pScrn); struct rhdOutput *Output; struct rhdCrtc *Crtc1, *Crtc2; RHDFUNC(rhdPtr); if (!pScrn->vtSema) return; Crtc1 = rhdPtr->Crtc[0]; Crtc2 = rhdPtr->Crtc[1]; switch (PowerManagementMode) { case DPMSModeOn: if (Crtc1->Active) { Crtc1->Power(Crtc1, RHD_POWER_ON); for (Output = rhdPtr->Outputs; Output; Output = Output->Next) if (Output->Power && Output->Active && (Output->Crtc == Crtc1)) { Output->Power(Output, RHD_POWER_ON); #ifdef ATOM_BIOS RHDAtomBIOSScratchPMState(rhdPtr, Output, PowerManagementMode); #endif } Crtc1->Blank(Crtc1, FALSE); } if (Crtc2->Active) { Crtc2->Power(Crtc2, RHD_POWER_ON); for (Output = rhdPtr->Outputs; Output; Output = Output->Next) if (Output->Power && Output->Active && (Output->Crtc == Crtc2)) { Output->Power(Output, RHD_POWER_ON); #ifdef ATOM_BIOS RHDAtomBIOSScratchPMState(rhdPtr, Output, PowerManagementMode); #endif } Crtc2->Blank(Crtc2, FALSE); } break; case DPMSModeStandby: case DPMSModeSuspend: case DPMSModeOff: if (Crtc1->Active) { Crtc1->Blank(Crtc1, TRUE); for (Output = rhdPtr->Outputs; Output; Output = Output->Next) if (Output->Power && Output->Active && (Output->Crtc == Crtc1)) { Output->Power(Output, RHD_POWER_RESET); #ifdef ATOM_BIOS RHDAtomBIOSScratchPMState(rhdPtr, Output, PowerManagementMode); #endif } Crtc1->Power(Crtc1, RHD_POWER_RESET); } if (Crtc2->Active) { Crtc2->Blank(Crtc2, TRUE); for (Output = rhdPtr->Outputs; Output; Output = Output->Next) if (Output->Power && Output->Active && (Output->Crtc == Crtc2)) { Output->Power(Output, RHD_POWER_RESET); #ifdef ATOM_BIOS RHDAtomBIOSScratchPMState(rhdPtr, Output, PowerManagementMode); #endif } Crtc2->Power(Crtc2, RHD_POWER_RESET); } break; } } /* * */ static void RHDLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO *colors, VisualPtr pVisual) { RHDPtr rhdPtr = RHDPTR(pScrn); struct rhdCrtc *Crtc; CARD16 red[256], green[256], blue[256]; int i, index, j, n; Bool partial_table = FALSE; switch (pScrn->depth) { case 8: case 24: case 32: if (numColors < 256) { partial_table = TRUE; break; } for (i = 0; i < numColors; i++) { index = indices[i]; red[index] = colors[index].red << 6; green[index] = colors[index].green << 6; blue[index] = colors[index].blue << 6; } break; case 16: if (numColors < 64) { partial_table = TRUE; break; } /* 6 bits of green, 5 bits of red and blue each */ for (i = 0; i < numColors; i++) { index = indices[i]; n = index * 4; for (j = 0; j < 4; j++) { red[n + j] = colors[index/2].red << 6; green[n + j] = colors[index].green << 6; blue[n + j] = colors[index/2].blue << 6; } } break; case 15: if (numColors < 32) { partial_table = TRUE; break; } /* 5 bits each */ for (i = 0; i < numColors; i++) { int j, n; index = indices[i]; n = index * 8; for (j = 0; j < 8; j++) { red[n + j] = colors[index].red << 6; green[n + j] = colors[index].green << 6; blue[n+ j] = colors[index].blue << 6; } } break; } for (i = 0; i < 2; i++) { Crtc = rhdPtr->Crtc[i]; if ((pScrn->scrnIndex == Crtc->scrnIndex) && Crtc->Active) { if (!partial_table) Crtc->LUT->Set(Crtc->LUT, red, green, blue); else Crtc->LUT->SetRows(Crtc->LUT, numColors, indices, colors); } } } /* * */ static Bool RHDSaveScreen(ScreenPtr pScreen, int on) { ScrnInfoPtr pScrn; RHDPtr rhdPtr; struct rhdCrtc *Crtc; Bool unblank; unblank = xf86IsUnblank(on); if (unblank) SetTimeSinceLastInputEvent(); if (pScreen == NULL) return TRUE; pScrn = xf86Screens[pScreen->myNum]; if (pScrn == NULL) return TRUE; RHDFUNC(pScrn); rhdPtr = RHDPTR(pScrn); if (!pScrn->vtSema) return TRUE; Crtc = rhdPtr->Crtc[0]; if (pScreen->myNum == Crtc->scrnIndex) Crtc->Blank(Crtc, !unblank); Crtc = rhdPtr->Crtc[1]; if (pScreen->myNum == Crtc->scrnIndex) Crtc->Blank(Crtc, !unblank); return TRUE; } /* * */ Bool RHDScalePolicy(struct rhdMonitor *Monitor, struct rhdConnector *Connector) { if (!Monitor || !Monitor->UseFixedModes || !Monitor->NativeMode) return FALSE; if (Connector->Type != RHD_CONNECTOR_PANEL) return FALSE; return TRUE; } /* * */ static Bool rhdMapMMIO(RHDPtr rhdPtr) { RHDFUNC(rhdPtr); #ifdef XSERVER_LIBPCIACCESS rhdPtr->MMIOMapSize = rhdPtr->PciInfo->regions[RHD_MMIO_BAR].size; rhdPtr->MMIOPCIAddress = rhdPtr->PciInfo->regions[RHD_MMIO_BAR].base_addr; if (pci_device_map_range(rhdPtr->PciInfo, rhdPtr->MMIOPCIAddress, rhdPtr->MMIOMapSize, PCI_DEV_MAP_FLAG_WRITABLE, &rhdPtr->MMIOBase)) rhdPtr->MMIOBase = NULL; #else rhdPtr->MMIOMapSize = 1 << rhdPtr->PciInfo->size[RHD_MMIO_BAR]; rhdPtr->MMIOPCIAddress = rhdPtr->PciInfo->memBase[RHD_MMIO_BAR]; rhdPtr->MMIOBase = xf86MapPciMem(rhdPtr->scrnIndex, VIDMEM_MMIO, rhdPtr->PciTag, rhdPtr->MMIOPCIAddress, rhdPtr->MMIOMapSize); #endif if (!rhdPtr->MMIOBase) return FALSE; xf86DrvMsg(rhdPtr->scrnIndex, X_INFO, "Mapped IO @ 0x%x to %p (size 0x%08X)\n", rhdPtr->MMIOPCIAddress, rhdPtr->MMIOBase, rhdPtr->MMIOMapSize); return TRUE; } /* * */ static void rhdUnmapMMIO(RHDPtr rhdPtr) { RHDFUNC(rhdPtr); #ifdef XSERVER_LIBPCIACCESS pci_device_unmap_range(rhdPtr->PciInfo, (pointer)rhdPtr->MMIOBase, rhdPtr->MMIOMapSize); #else xf86UnMapVidMem(rhdPtr->scrnIndex, (pointer)rhdPtr->MMIOBase, rhdPtr->MMIOMapSize); #endif rhdPtr->MMIOBase = 0; } /* * */ static CARD32 rhdGetVideoRamSize(RHDPtr rhdPtr) { CARD32 RamSize, BARSize; RHDFUNC(rhdPtr); if (rhdPtr->ChipSet < RHD_R600) RamSize = (RHDRegRead(rhdPtr, R5XX_CONFIG_MEMSIZE)) >> 10; else RamSize = (RHDRegRead(rhdPtr, R6XX_CONFIG_MEMSIZE)) >> 10; #ifdef XSERVER_LIBPCIACCESS BARSize = rhdPtr->PciInfo->regions[RHD_FB_BAR].size >> 10; #else BARSize = 1 << (rhdPtr->PciInfo->size[RHD_FB_BAR] - 10); #endif if (RamSize > BARSize) { xf86DrvMsg(rhdPtr->scrnIndex, X_INFO, "The detected amount of videoram" " exceeds the PCI BAR aperture.\n"); xf86DrvMsg(rhdPtr->scrnIndex, X_INFO, "Mapping only %dkB of the total " "%dkB, remaining memory is reserved for GPU.\n", (int) BARSize, (int) RamSize); return BARSize; } else return RamSize; } /* * */ static Bool rhdMapFB(RHDPtr rhdPtr) { ScrnInfoPtr pScrn = xf86Screens[rhdPtr->scrnIndex]; RHDFUNC(rhdPtr); rhdPtr->FbBase = NULL; #ifdef XSERVER_LIBPCIACCESS rhdPtr->FbPCIAddress = rhdPtr->PciInfo->regions[RHD_FB_BAR].base_addr; rhdPtr->FbMapSize = rhdPtr->PciInfo->regions[RHD_FB_BAR].size; #else rhdPtr->FbPCIAddress = rhdPtr->PciInfo->memBase[RHD_FB_BAR]; rhdPtr->FbMapSize = 1 << rhdPtr->PciInfo->size[RHD_FB_BAR]; #endif /* some IGPs are special cases */ switch (rhdPtr->ChipSet) { case RHD_RS690: case RHD_RS740: rhdPtr->FbPhysAddress = RHDReadMC(rhdPtr, RS69_K8_FB_LOCATION); break; case RHD_RS780: rhdPtr->FbPhysAddress = RHDReadMC(rhdPtr, RS78_K8_FB_LOCATION); break; default: rhdPtr->FbPhysAddress = 0; break; } if (rhdPtr->FbPhysAddress) { Bool SetIGPMemory = TRUE; CARD32 option = X_DEFAULT; if (rhdPtr->unverifiedFeatures.set) { option = X_CONFIG; SetIGPMemory = rhdPtr->unverifiedFeatures.val.bool; } if (SetIGPMemory && ! RHD_MC_IGP_SideportMemoryPresent(rhdPtr)) { SetIGPMemory = FALSE; option = X_DEFAULT; } if (SetIGPMemory) { CARD32 tmp = 0xfffffc00; CARD32 s = pScrn->videoRam; while (! (s & 0x1)) { s >>= 1; tmp <<= 1; } if (rhdPtr->FbPhysAddress & ~tmp) { xf86DrvMsg(rhdPtr->scrnIndex, X_WARNING, "IGP memory base 0x%8.8x seems to be bogus.\n", rhdPtr->FbPhysAddress); SetIGPMemory = FALSE; option = X_DEFAULT; } } if (SetIGPMemory) { CARD32 FbMapSizePCI = rhdPtr->FbMapSize; xf86DrvMsg(rhdPtr->scrnIndex, option, "Mapping IGP memory @ 0x%8.8x\n",rhdPtr->FbPhysAddress); rhdPtr->FbMapSize = pScrn->videoRam * 1024; #ifdef XSERVER_LIBPCIACCESS if (pci_device_map_range(rhdPtr->PciInfo, rhdPtr->FbPhysAddress, rhdPtr->FbMapSize, PCI_DEV_MAP_FLAG_WRITABLE | PCI_DEV_MAP_FLAG_WRITE_COMBINE, &rhdPtr->FbBase)) rhdPtr->FbBase = NULL; #else rhdPtr->FbBase = xf86MapPciMem(rhdPtr->scrnIndex, VIDMEM_FRAMEBUFFER, rhdPtr->PciTag, rhdPtr->FbPhysAddress, rhdPtr->FbMapSize); #endif /* If mapping was unsuccessful restore old size */ if (!rhdPtr->FbBase) rhdPtr->FbMapSize = FbMapSizePCI; } else { xf86DrvMsg(rhdPtr->scrnIndex, option, "Not Mapping IGP memory\n"); } } /* go through the BAR */ if (!rhdPtr->FbBase) { rhdPtr->FbPhysAddress = rhdPtr->FbPCIAddress; if (rhdPtr->FbMapSize > (unsigned) pScrn->videoRam * 1024) rhdPtr->FbMapSize = pScrn->videoRam * 1024; #ifdef XSERVER_LIBPCIACCESS if (pci_device_map_range(rhdPtr->PciInfo, rhdPtr->FbPhysAddress, rhdPtr->FbMapSize, PCI_DEV_MAP_FLAG_WRITABLE | PCI_DEV_MAP_FLAG_WRITE_COMBINE, &rhdPtr->FbBase)) rhdPtr->FbBase = NULL; #else rhdPtr->FbBase = xf86MapPciMem(rhdPtr->scrnIndex, VIDMEM_FRAMEBUFFER, rhdPtr->PciTag, rhdPtr->FbPhysAddress, rhdPtr->FbMapSize); #endif } RHDDebug(rhdPtr->scrnIndex, "Physical FB Address: 0x%08X (PCI BAR: 0x%08X)\n", rhdPtr->FbPhysAddress, rhdPtr->FbPCIAddress); if (!rhdPtr->FbBase) return FALSE; xf86DrvMsg(rhdPtr->scrnIndex, X_INFO, "Mapped FB @ 0x%x to %p (size 0x%08X)\n", rhdPtr->FbPhysAddress, rhdPtr->FbBase, rhdPtr->FbMapSize); return TRUE; } /* * */ static void rhdUnmapFB(RHDPtr rhdPtr) { RHDFUNC(rhdPtr); if (!rhdPtr->FbBase) return; #ifdef XSERVER_LIBPCIACCESS pci_device_unmap_range(rhdPtr->PciInfo, (pointer)rhdPtr->FbBase, rhdPtr->FbMapSize); #else xf86UnMapVidMem(rhdPtr->scrnIndex, (pointer)rhdPtr->FbBase, rhdPtr->FbMapSize); #endif rhdPtr->FbBase = NULL; } /* * */ static void rhdFbOffscreenGrab(ScrnInfoPtr pScrn) { RHDPtr rhdPtr = RHDPTR(pScrn); RHDOpt Option = rhdPtr->OffscreenOption; int tmp; unsigned int size = 0; if (Option.set) { if ((sscanf(Option.val.string, "%dm", &tmp) == 1) || (sscanf(Option.val.string, "%dM", &tmp) == 1)) { /* "...m" or "...M" means megabyte. */ size = tmp << 20; } else if (sscanf(Option.val.string, "%d%%", &tmp) == 1) { /* "...%" of total framebuffer memory */ size = tmp * pScrn->videoRam / 100; } else xf86DrvMsg(rhdPtr->scrnIndex, X_WARNING, "Option OffscreenSize: " "Unable to parse \"%s\".\n", Option.val.string); } if (!size) size = pScrn->videoRam * 1024 / 10; if (size > rhdPtr->FbFreeSize) size = rhdPtr->FbFreeSize; /* calculate the number of lines our frontbuffer and offscreen have */ tmp = rhdPtr->FbScanoutSize + size; tmp /= (pScrn->displayWidth * pScrn->bitsPerPixel >> 3); if (rhdPtr->ChipSet < RHD_R600) { if (tmp > 0x1FFF) /* cannot go beyond 8k lines on R5xx */ tmp = 0x1FFF; } else { if (tmp > 0x7FFF) /* X limit (signed short). */ tmp = 0x7FFF; } tmp -= pScrn->virtualY; /* get our actual size */ tmp *= (pScrn->displayWidth * pScrn->bitsPerPixel >> 3); tmp = RHD_FB_CHUNK(tmp); rhdPtr->FbOffscreenSize = tmp; rhdPtr->FbOffscreenStart = RHDAllocFb(rhdPtr, tmp, "Offscreen Buffer"); ASSERT(rhdPtr->FbOffscreenStart != (unsigned)-1); } /* * */ static void rhdOutputConnectorCheck(struct rhdConnector *Connector) { struct rhdOutput *Output; int i; /* First, try to sense */ for (i = 0; i < 2; i++) { Output = Connector->Output[i]; if (Output && Output->Sense) { /* * This is ugly and needs to change when the TV support patches are in. * The problem here is that the Output struct can be used for two connectors * and thus two different devices */ if (Output->SensedType == RHD_SENSED_NONE) { /* Do this before sensing as AtomBIOS sense needs this info */ if ((Output->SensedType = Output->Sense(Output, Connector)) != RHD_SENSED_NONE) { RHDOutputPrintSensedType(Output); RHDOutputAttachConnector(Output, Connector); break; } } } } if (i == 2) { /* now just enable the ones without sensing */ for (i = 0; i < 2; i++) { Output = Connector->Output[i]; if (Output && !Output->Sense) { RHDOutputAttachConnector(Output, Connector); break; } } } } /* * */ static Bool rhdModeLayoutSelect(RHDPtr rhdPtr) { struct rhdOutput *Output; struct rhdConnector *Connector; Bool Found = FALSE; RHDOpt ignore; Bool ConnectorIsDMS59 = FALSE; int i = 0; RHDFUNC(rhdPtr); /* housekeeping */ rhdPtr->Crtc[0]->PLL = rhdPtr->PLLs[0]; rhdPtr->Crtc[0]->LUT = rhdPtr->LUT[0]; rhdPtr->Crtc[1]->PLL = rhdPtr->PLLs[1]; rhdPtr->Crtc[1]->LUT = rhdPtr->LUT[1]; /* start layout afresh */ for (Output = rhdPtr->Outputs; Output; Output = Output->Next) { Output->Active = FALSE; Output->Crtc = NULL; Output->Connector = NULL; } /* quick and dirty option so that some output choice exists */ RhdGetOptValString (rhdPtr->Options, OPTION_IGNORECONNECTOR, &ignore, ""); /* handle cards with DMS-59 connectors appropriately. The DMS-59 to VGA adapter does not raise HPD at all, so we need a fallback there. */ if (rhdPtr->Card) { ConnectorIsDMS59 = rhdPtr->Card->flags & RHD_CARD_FLAG_DMS59; if (ConnectorIsDMS59) xf86DrvMsg(rhdPtr->scrnIndex, X_INFO, "Card %s has a DMS-59" " connector.\n", rhdPtr->Card->name); } /* Check on the basis of Connector->HPD */ for (i = 0; i < RHD_CONNECTORS_MAX; i++) { Connector = rhdPtr->Connector[i]; if (!Connector) continue; switch(RhdParseBooleanOption(&ignore, Connector->Name)) { case RHD_OPTION_ON: case RHD_OPTION_DEFAULT: xf86DrvMsg(rhdPtr->scrnIndex, X_INFO, "Skipping connector \"%s\"\n", Connector->Name); continue; case RHD_OPTION_OFF: case RHD_OPTION_NOT_SET: break; } if (Connector->HPDCheck) { if (Connector->HPDCheck(Connector)) { Connector->HPDAttached = TRUE; rhdOutputConnectorCheck(Connector); } else { Connector->HPDAttached = FALSE; if (ConnectorIsDMS59) rhdOutputConnectorCheck(Connector); } } else rhdOutputConnectorCheck(Connector); } i = 0; /* counter for CRTCs */ for (Output = rhdPtr->Outputs; Output; Output = Output->Next) if (Output->Connector) { struct rhdMonitor *Monitor = NULL; Connector = Output->Connector; Monitor = RHDMonitorInit(Connector); if (!Monitor && (Connector->Type == RHD_CONNECTOR_PANEL)) { xf86DrvMsg(rhdPtr->scrnIndex, X_WARNING, "Unable to attach a" " monitor to connector \"%s\"\n", Connector->Name); Output->Active = FALSE; } else if (!Output->AllocFree || Output->AllocFree(Output, RHD_OUTPUT_ALLOC)){ Connector->Monitor = Monitor; Output->Active = TRUE; Output->Crtc = rhdPtr->Crtc[i & 1]; /* ;) */ i++; Output->Crtc->Active = TRUE; if (RHDScalePolicy(Monitor, Connector)) { Output->Crtc->ScaledToMode = RHDModeCopy(Monitor->NativeMode); xf86DrvMsg(rhdPtr->scrnIndex, X_INFO, "Crtc[%i]: found native mode from Monitor[%s]: ", Output->Crtc->Id, Monitor->Name); RHDPrintModeline(Output->Crtc->ScaledToMode); } Found = TRUE; if (Monitor) { /* If this is a DVI attached monitor, enable reduced blanking. * TODO: iiyama vm pro 453: CRT with DVI-D == No reduced. */ if ((Output->Id == RHD_OUTPUT_TMDSA) || (Output->Id == RHD_OUTPUT_LVTMA) || (Output->Id == RHD_OUTPUT_KLDSKP_LVTMA) || (Output->Id == RHD_OUTPUT_UNIPHYA) || (Output->Id == RHD_OUTPUT_UNIPHYB)) Monitor->ReducedAllowed = TRUE; /* allow user to override settings globally */ if (rhdPtr->forceReduced.set) Monitor->ReducedAllowed = rhdPtr->forceReduced.val.bool; xf86DrvMsg(rhdPtr->scrnIndex, X_INFO, "Connector \"%s\" uses Monitor \"%s\":\n", Connector->Name, Monitor->Name); RHDMonitorPrint(Monitor); } else xf86DrvMsg(rhdPtr->scrnIndex, X_WARNING, "Connector \"%s\": Failed to retrieve Monitor" " information.\n", Connector->Name); } } /* Now validate the scaled modes attached to crtcs */ for (i = 0; i < 2; i++) { struct rhdCrtc *crtc = rhdPtr->Crtc[i]; if (crtc->ScaledToMode && RHDValidateScaledToMode(crtc, crtc->ScaledToMode) != MODE_OK) { xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "Crtc[%i]: scaled mode invalid.\n", crtc->Id); xfree(crtc->ScaledToMode); crtc->ScaledToMode = NULL; } } return Found; } /* * Calculating DPI will never be good. But here we attempt to make it work, * somewhat, with multiple monitors. * * The real solution for the DPI problem cannot be something statically, * as DPI varies with resolutions chosen and with displays attached/detached. */ static void rhdModeDPISet(ScrnInfoPtr pScrn) { RHDPtr rhdPtr = RHDPTR(pScrn); /* first cleanse the option to at least be reasonable */ if (rhdPtr->forceDPI.set) if ((rhdPtr->forceDPI.val.integer < 20) || (rhdPtr->forceDPI.val.integer > 1000)) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Option ForceDPI got passed" " an insane value: %d. Ignoring.\n", rhdPtr->forceDPI.val.integer); rhdPtr->forceDPI.set = FALSE; } /* monitorResolution is the DPI that was passed as a server option. * This has been available all the way back to the original Xorg import */ if (monitorResolution > 0) { RHDDebug(pScrn->scrnIndex, "%s: Forcing DPI through xserver argument.\n", __func__); pScrn->xDpi = monitorResolution; pScrn->yDpi = monitorResolution; } else if (rhdPtr->forceDPI.set) { RHDDebug(pScrn->scrnIndex, "%s: Forcing DPI through configuration option.\n", __func__); pScrn->xDpi = rhdPtr->forceDPI.val.integer; pScrn->yDpi = rhdPtr->forceDPI.val.integer; } else { /* go over the monitors */ struct rhdCrtc *Crtc; struct rhdOutput *Output; struct rhdMonitor *Monitor; /* we need to use split counters, x or y might fail separately */ int i, xcount, ycount; pScrn->xDpi = 0; pScrn->yDpi = 0; xcount = 0; ycount = 0; for (i = 0; i < 2; i++) { Crtc = rhdPtr->Crtc[i]; if (Crtc->Active) { for (Output = rhdPtr->Outputs; Output; Output = Output->Next) { if (Output->Active && (Output->Crtc == Crtc)) { if (Output->Connector && Output->Connector->Monitor) { Monitor = Output->Connector->Monitor; if (Monitor->xDpi) { pScrn->xDpi += (Monitor->xDpi - pScrn->xDpi) / (xcount + 1); xcount++; } if (Monitor->yDpi) { pScrn->yDpi += (Monitor->yDpi - pScrn->yDpi) / (ycount + 1); ycount++; } } } } } } /* make sure that we have at least some value */ if (!pScrn->xDpi || !pScrn->yDpi) { if (pScrn->xDpi) pScrn->yDpi = pScrn->xDpi; else if (pScrn->yDpi) pScrn->xDpi = pScrn->yDpi; else { pScrn->xDpi = 96; pScrn->yDpi = 96; } } } #ifndef MMPERINCH #define MMPERINCH 25.4 #endif pScrn->widthmm = pScrn->virtualX * MMPERINCH / pScrn->xDpi; pScrn->heightmm = pScrn->virtualY * MMPERINCH / pScrn->yDpi; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using %dx%d DPI.\n", pScrn->xDpi, pScrn->yDpi); } /* * */ static void rhdModeLayoutPrint(RHDPtr rhdPtr) { struct rhdCrtc *Crtc; struct rhdOutput *Output; Bool Found; xf86DrvMsg(rhdPtr->scrnIndex, X_INFO, "Listing modesetting layout:\n\n"); /* CRTC 1 */ Crtc = rhdPtr->Crtc[0]; if (Crtc->Active) { xf86Msg(X_NONE, "\t%s: tied to %s and %s:\n", Crtc->Name, Crtc->PLL->Name, Crtc->LUT->Name); Found = FALSE; for (Output = rhdPtr->Outputs; Output; Output = Output->Next) if (Output->Active && (Output->Crtc == Crtc)) { if (!Found) { xf86Msg(X_NONE, "\t\tOutputs: %s (%s)", Output->Name, Output->Connector->Name); Found = TRUE; } else xf86Msg(X_NONE, ", %s (%s)", Output->Name, Output->Connector->Name); } if (!Found) xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "%s is active without outputs\n", Crtc->Name); else xf86Msg(X_NONE, "\n"); } else xf86Msg(X_NONE, "\t%s: unused\n", Crtc->Name); xf86Msg(X_NONE, "\n"); /* CRTC 2 */ Crtc = rhdPtr->Crtc[1]; if (Crtc->Active) { xf86Msg(X_NONE, "\t%s: tied to %s and %s:\n", Crtc->Name, Crtc->PLL->Name, Crtc->LUT->Name); Found = FALSE; for (Output = rhdPtr->Outputs; Output; Output = Output->Next) if (Output->Active && (Output->Crtc == Crtc)) { if (!Found) { xf86Msg(X_NONE, "\t\tOutputs: %s (%s)", Output->Name, Output->Connector->Name); Found = TRUE; } else xf86Msg(X_NONE, ", %s (%s)", Output->Name, Output->Connector->Name); } if (!Found) xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "%s is active without outputs\n", Crtc->Name); else xf86Msg(X_NONE, "\n"); } else xf86Msg(X_NONE, "\t%s: unused\n", Crtc->Name); xf86Msg(X_NONE, "\n"); /* Print out unused Outputs */ Found = FALSE; for (Output = rhdPtr->Outputs; Output; Output = Output->Next) if (!Output->Active) { if (!Found) { xf86Msg(X_NONE, "\t\tUnused Outputs: %s", Output->Name); Found = TRUE; } else xf86Msg(X_NONE, ", %s", Output->Name); } if (Found) xf86Msg(X_NONE, "\n"); xf86Msg(X_NONE, "\n"); } /* * */ void RHDPrepareMode(RHDPtr rhdPtr) { RHDFUNC(rhdPtr); /* Stop crap from being shown: gets reenabled through SaveScreen */ rhdPtr->Crtc[0]->Blank(rhdPtr->Crtc[0], TRUE); rhdPtr->Crtc[1]->Blank(rhdPtr->Crtc[1], TRUE); /* no active outputs == no mess */ RHDOutputsPower(rhdPtr, RHD_POWER_RESET); } /* * */ static void rhdModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode) { RHDPtr rhdPtr = RHDPTR(pScrn); RHDFUNC(rhdPtr); pScrn->vtSema = TRUE; rhdSetMode(pScrn, mode); } /* * */ static void rhdSetMode(ScrnInfoPtr pScrn, DisplayModePtr mode) { RHDPtr rhdPtr = RHDPTR(pScrn); int i; RHDFUNC(rhdPtr); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Setting up \"%s\" (%dx%d@%3.1fHz)\n", mode->name, mode->CrtcHDisplay, mode->CrtcVDisplay, mode->VRefresh); /* Set up D1/D2 and appendages */ for (i = 0; i < 2; i++) { struct rhdCrtc *Crtc; Crtc = rhdPtr->Crtc[i]; if (Crtc->Active) { Crtc->FBSet(Crtc, pScrn->displayWidth, pScrn->virtualX, pScrn->virtualY, pScrn->depth, rhdPtr->FbScanoutStart); if (Crtc->ScaledToMode) { Crtc->ModeSet(Crtc, Crtc->ScaledToMode); if (Crtc->ScaleSet) Crtc->ScaleSet(Crtc, Crtc->ScaleType, mode, Crtc->ScaledToMode); } else { Crtc->ModeSet(Crtc, mode); if (Crtc->ScaleSet) Crtc->ScaleSet(Crtc, RHD_CRTC_SCALE_TYPE_NONE, mode, NULL); } RHDPLLSet(Crtc->PLL, mode->Clock); Crtc->LUTSelect(Crtc, Crtc->LUT); RHDOutputsMode(rhdPtr, Crtc, Crtc->ScaledToMode ? Crtc->ScaledToMode : mode); } } /* shut down that what we don't use */ RHDPLLsShutdownInactive(rhdPtr); RHDOutputsShutdownInactive(rhdPtr); if (rhdPtr->Crtc[0]->Active) rhdPtr->Crtc[0]->Power(rhdPtr->Crtc[0], RHD_POWER_ON); else rhdPtr->Crtc[0]->Power(rhdPtr->Crtc[0], RHD_POWER_SHUTDOWN); if (rhdPtr->Crtc[1]->Active) rhdPtr->Crtc[1]->Power(rhdPtr->Crtc[1], RHD_POWER_ON); else rhdPtr->Crtc[1]->Power(rhdPtr->Crtc[1], RHD_POWER_SHUTDOWN); RHDOutputsPower(rhdPtr, RHD_POWER_ON); } /* * */ static void rhdSave(RHDPtr rhdPtr) { ScrnInfoPtr pScrn = xf86Screens[rhdPtr->scrnIndex]; RHDFUNC(rhdPtr); RHDMCSave(rhdPtr); RHDVGASave(rhdPtr); RHDOutputsSave(rhdPtr); #ifdef ATOM_BIOS rhdPtr->BIOSScratch = RHDSaveBiosScratchRegisters(rhdPtr); #endif RHDPLLsSave(rhdPtr); RHDAudioSave(rhdPtr); RHDLUTsSave(rhdPtr); RHDCrtcSave(rhdPtr->Crtc[0]); RHDCrtcSave(rhdPtr->Crtc[1]); rhdSaveCursor(pScrn); RHDPmSave(rhdPtr); } /* * */ static void rhdRestore(RHDPtr rhdPtr) { ScrnInfoPtr pScrn = xf86Screens[rhdPtr->scrnIndex]; RHDFUNC(rhdPtr); RHDMCRestore(rhdPtr); rhdRestoreCursor(pScrn); RHDPLLsRestore(rhdPtr); RHDAudioRestore(rhdPtr); RHDLUTsRestore(rhdPtr); RHDVGARestore(rhdPtr); /* restore after restoring CRTCs - check rhd_crtc.c for why */ RHDCrtcRestore(rhdPtr->Crtc[0]); RHDCrtcRestore(rhdPtr->Crtc[1]); RHDPmRestore(rhdPtr); RHDOutputsRestore(rhdPtr); #ifdef ATOM_BIOS RHDRestoreBiosScratchRegisters(rhdPtr, rhdPtr->BIOSScratch); #endif } #ifdef RHD_DEBUG /* * */ CARD32 _RHDRegReadD(int scrnIndex, CARD16 offset) { CARD32 tmp = MMIO_IN32(RHDPTR(xf86Screens[scrnIndex])->MMIOBase, offset); xf86DrvMsg(scrnIndex, X_INFO, "RHDRegRead(0x%4.4x) = 0x%4.4x\n",offset,tmp); return tmp; } /* * */ void _RHDRegWriteD(int scrnIndex, CARD16 offset, CARD32 value) { xf86DrvMsg(scrnIndex, X_INFO, "RHDRegWrite(0x%4.4x,0x%4.4x)\n",offset,tmp); MMIO_OUT32(RHDPTR(xf86Screens[scrnIndex])->MMIOBase, offset, value); } /* * */ void _RHDRegMaskD(int scrnIndex, CARD16 offset, CARD32 value, CARD32 mask) { CARD32 tmp; tmp = _RHDRegReadD(scrnIndex, offset); tmp &= ~mask; tmp |= (value & mask); _RHDRegWriteD(scrnIndex, offset, tmp); } #endif /* RHD_DEBUG */ /* The following two are R5XX only. R6XX doesn't require these */ CARD32 _RHDReadMC(int scrnIndex, CARD32 addr) { RHDPtr rhdPtr = RHDPTR(xf86Screens[scrnIndex]); CARD32 ret = 0; if (rhdPtr->ChipSet < RHD_RS600) { RHDRegWrite(rhdPtr, MC_IND_INDEX, addr); ret = RHDRegRead(rhdPtr, MC_IND_DATA); } else if (rhdPtr->ChipSet == RHD_RS600) { RHDRegWrite(rhdPtr, RS600_MC_INDEX, ((addr & RS600_MC_INDEX_ADDR_MASK) | RS600_MC_INDEX_CITF_ARB0)); ret = RHDRegRead(rhdPtr, RS600_MC_DATA); } else if (rhdPtr->ChipSet == RHD_RS690 || rhdPtr->ChipSet == RHD_RS740) { RHDRegWrite(rhdPtr, RS690_MC_INDEX, (addr & RS690_MC_INDEX_ADDR_MASK)); ret = RHDRegRead(rhdPtr, RS690_MC_DATA); } else if (rhdPtr->ChipSet == RHD_RS780 || rhdPtr->ChipSet == RHD_RS880) { RHDRegWrite(rhdPtr, RS780_MC_INDEX, (addr & RS780_MC_INDEX_ADDR_MASK)); ret = RHDRegRead(rhdPtr, RS780_MC_DATA); } else { xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "%s: shouldn't be here\n", __func__); } #ifdef RHD_DEBUG RHDDebug(scrnIndex,"%s(0x%08X) = 0x%08X\n",__func__,(unsigned int)addr, (unsigned int)ret); #endif return ret; } void _RHDWriteMC(int scrnIndex, CARD32 addr, CARD32 data) { RHDPtr rhdPtr = RHDPTR(xf86Screens[scrnIndex]); #ifdef RHD_DEBUG RHDDebug(scrnIndex,"%s(0x%08X, 0x%08X)\n",__func__,(unsigned int)addr, (unsigned int)data); #endif if (rhdPtr->ChipSet < RHD_RS600) { RHDRegWrite(rhdPtr, MC_IND_INDEX, addr | MC_IND_WR_EN); RHDRegWrite(rhdPtr, MC_IND_DATA, data); } else if (rhdPtr->ChipSet == RHD_RS600) { RHDRegWrite(rhdPtr, RS600_MC_INDEX, ((addr & RS600_MC_INDEX_ADDR_MASK) | RS600_MC_INDEX_CITF_ARB0 | RS600_MC_INDEX_WR_EN)); RHDRegWrite(rhdPtr, RS600_MC_DATA, data); } else if (rhdPtr->ChipSet == RHD_RS690 || rhdPtr->ChipSet == RHD_RS740) { RHDRegWrite(rhdPtr, RS690_MC_INDEX, ((addr & RS690_MC_INDEX_ADDR_MASK) | RS690_MC_INDEX_WR_EN)); RHDRegWrite(rhdPtr, RS690_MC_DATA, data); RHDRegWrite(rhdPtr, RS690_MC_INDEX, RS690_MC_INDEX_WR_ACK); } else if (rhdPtr->ChipSet == RHD_RS780 || rhdPtr->ChipSet == RHD_RS880) { RHDRegWrite(rhdPtr, RS780_MC_INDEX, ((addr & RS780_MC_INDEX_ADDR_MASK) | RS780_MC_INDEX_WR_EN)); RHDRegWrite(rhdPtr, RS780_MC_DATA, data); } else { xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "%s: shouldn't be here\n", __func__); } } CARD32 _RHDReadPLL(int scrnIndex, CARD16 offset) { RHDPtr rhdPtr = RHDPTR(xf86Screens[scrnIndex]); RHDRegWrite(rhdPtr, CLOCK_CNTL_INDEX, (offset & PLL_ADDR)); return RHDRegRead(rhdPtr, CLOCK_CNTL_DATA); } void _RHDWritePLL(int scrnIndex, CARD16 offset, CARD32 data) { RHDPtr rhdPtr = RHDPTR(xf86Screens[scrnIndex]); RHDRegWrite(rhdPtr, CLOCK_CNTL_INDEX, (offset & PLL_ADDR) | PLL_WR_EN); RHDRegWrite(rhdPtr, CLOCK_CNTL_DATA, data); } /* * Apart from handling the respective option, this also tries to map out * what method is supported on which chips. */ static void rhdAccelOptionsHandle(ScrnInfoPtr pScrn) { RHDPtr rhdPtr = RHDPTR(pScrn); RHDOpt method, noAccel; /* first grab our options */ RhdGetOptValBool(rhdPtr->Options, OPTION_NOACCEL, &noAccel, FALSE); RhdGetOptValString(rhdPtr->Options, OPTION_ACCELMETHOD, &method, "default"); RhdGetOptValString (rhdPtr->Options, OPTION_OFFSCREENSIZE, &rhdPtr->OffscreenOption, "default"); if (method.set) { if (!strcasecmp(method.val.string, "none")) rhdPtr->AccelMethod = RHD_ACCEL_NONE; else if (!strcasecmp(method.val.string, "force-shadowfb")) rhdPtr->AccelMethod = RHD_ACCEL_FORCE_SHADOWFB; else if (!strcasecmp(method.val.string, "shadowfb")) rhdPtr->AccelMethod = RHD_ACCEL_SHADOWFB; else if (!strcasecmp(method.val.string, "xaa")) rhdPtr->AccelMethod = RHD_ACCEL_XAA; #ifdef USE_EXA else if (!strcasecmp(method.val.string, "exa")) rhdPtr->AccelMethod = RHD_ACCEL_EXA; #endif /* USE_EXA */ else if (!strcasecmp(method.val.string, "default")) rhdPtr->AccelMethod = RHD_ACCEL_DEFAULT; else { xf86DrvMsg(rhdPtr->scrnIndex, X_WARNING, "Unknown AccelMethod \"%s\".\n", method.val.string); rhdPtr->AccelMethod = RHD_ACCEL_DEFAULT; } } else rhdPtr->AccelMethod = RHD_ACCEL_DEFAULT; if (rhdPtr->AccelMethod == RHD_ACCEL_DEFAULT) { #ifdef USE_EXA rhdPtr->AccelMethod = RHD_ACCEL_EXA; #else if (rhdPtr->ChipSet < RHD_R600) rhdPtr->AccelMethod = RHD_ACCEL_XAA; else rhdPtr->AccelMethod = RHD_ACCEL_SHADOWFB; #endif /* USE_EXA */ /* RV740: EXA is extremely slow due to DFS breaking for <32x32 images * and Composite breaking with partial DFS */ if (rhdPtr->ChipSet == RHD_RV740) rhdPtr->AccelMethod = RHD_ACCEL_SHADOWFB; } if (noAccel.set && noAccel.val.bool && (rhdPtr->AccelMethod > RHD_ACCEL_SHADOWFB)) { xf86DrvMsg(rhdPtr->scrnIndex, X_INFO, "Disabling HW 2D acceleration.\n"); rhdPtr->AccelMethod = RHD_ACCEL_SHADOWFB; } /* Now for some pretty print */ switch (rhdPtr->AccelMethod) { #ifdef USE_EXA case RHD_ACCEL_EXA: xf86DrvMsg(rhdPtr->scrnIndex, X_CONFIG, "Selected EXA 2D acceleration.\n"); break; #endif /* USE_EXA */ case RHD_ACCEL_XAA: xf86DrvMsg(rhdPtr->scrnIndex, X_CONFIG, "Selected XAA 2D acceleration.\n"); break; case RHD_ACCEL_FORCE_SHADOWFB: xf86DrvMsg(rhdPtr->scrnIndex, X_WARNING, "Selected forced ShadowFB (even with DRI). Known to have issues.\n"); break; case RHD_ACCEL_SHADOWFB: xf86DrvMsg(rhdPtr->scrnIndex, X_CONFIG, "Selected ShadowFB.\n"); break; case RHD_ACCEL_NONE: default: xf86DrvMsg(rhdPtr->scrnIndex, X_WARNING, /* corny */ "All methods of acceleration have been disabled.\n"); break; } /* If shadowfb is explicitely selected AND dri is not explicitely asked * for, disable dri as they don't go along */ if (rhdPtr->AccelMethod == RHD_ACCEL_SHADOWFB && ! rhdPtr->useDRI.set) { xf86DrvMsg(rhdPtr->scrnIndex, X_CONFIG, "Disabling DRI by default with AccelMethod shadowfb.\n"); rhdPtr->useDRI.val.bool = FALSE; } } /* * breakout functions */ static void rhdProcessOptions(ScrnInfoPtr pScrn) { RHDPtr rhdPtr = RHDPTR(pScrn); RHDOpt hpd; #ifdef ATOM_BIOS RHDOpt atombios; #endif /* Collect all of the relevant option flags (fill in pScrn->options) */ xf86CollectOptions(pScrn, NULL); rhdPtr->Options = xnfcalloc(sizeof(RHDOptions), 1); memcpy(rhdPtr->Options, RHDOptions, sizeof(RHDOptions)); /* Process the options */ xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, rhdPtr->Options); RhdGetOptValBool (rhdPtr->Options, OPTION_SW_CURSOR, &rhdPtr->swCursor, FALSE); RhdGetOptValBool (rhdPtr->Options, OPTION_FORCEREDUCED, &rhdPtr->forceReduced, FALSE); RhdGetOptValInteger(rhdPtr->Options, OPTION_FORCEDPI, &rhdPtr->forceDPI, 0); RhdGetOptValString (rhdPtr->Options, OPTION_HPD, &hpd, "auto"); RhdGetOptValBool (rhdPtr->Options, OPTION_NORANDR, &rhdPtr->noRandr, FALSE); RhdGetOptValString (rhdPtr->Options, OPTION_RROUTPUTORDER, &rhdPtr->rrOutputOrder, NULL); RhdGetOptValBool (rhdPtr->Options, OPTION_DRI, &rhdPtr->useDRI, TRUE); RhdGetOptValString (rhdPtr->Options, OPTION_TV_MODE, &rhdPtr->tvModeName, NULL); RhdGetOptValString (rhdPtr->Options, OPTION_SCALE_TYPE, &rhdPtr->scaleTypeOpt, "default"); RhdGetOptValBool (rhdPtr->Options, OPTION_UNVERIFIED_FEAT, &rhdPtr->unverifiedFeatures, FALSE); RhdGetOptValBool (rhdPtr->Options, OPTION_AUDIO, &rhdPtr->audio, TRUE); RhdGetOptValString (rhdPtr->Options, OPTION_AUDIO_WORKAROUND, &rhdPtr->audioWorkaround, "none"); RhdGetOptValString (rhdPtr->Options, OPTION_HDMI, &rhdPtr->hdmi, "none"); RhdGetOptValString(rhdPtr->Options, OPTION_COHERENT, &rhdPtr->coherent, NULL); RhdGetOptValBool (rhdPtr->Options, OPTION_FORCE_LOW_POWER, &rhdPtr->lowPowerMode, FALSE); RhdGetOptValInteger(rhdPtr->Options, OPTION_LOW_POWER_CLOCK, &rhdPtr->lowPowerModeEngineClock, 0); #ifdef ATOM_BIOS RhdGetOptValBool (rhdPtr->Options, OPTION_USE_ATOMBIOS, &rhdPtr->UseAtomBIOS, FALSE); RhdGetOptValString (rhdPtr->Options, OPTION_ATOMBIOS, &atombios, NULL); if (atombios.set && atombios.val.string) { if (! rhdUpdateAtomBIOSUsage (rhdPtr, atombios.val.string)) xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "Cannot parse AtomBIOS usage string: %s\n", atombios.val.string); } #endif rhdAccelOptionsHandle(pScrn); rhdPtr->hpdUsage = RHD_HPD_USAGE_AUTO; if (strcasecmp(hpd.val.string, "off") == 0) { rhdPtr->hpdUsage = RHD_HPD_USAGE_OFF; } else if (strcasecmp(hpd.val.string, "normal") == 0) { rhdPtr->hpdUsage = RHD_HPD_USAGE_NORMAL; } else if (strcasecmp(hpd.val.string, "swap") == 0) { rhdPtr->hpdUsage = RHD_HPD_USAGE_SWAP; } else if (strcasecmp(hpd.val.string, "auto") != 0) { xf86DrvMsgVerb(rhdPtr->scrnIndex, X_ERROR, 0, "Unknown HPD Option \"%s\"", hpd.val.string); } if (rhdPtr->hpdUsage != RHD_HPD_USAGE_AUTO) xf86DrvMsgVerb(rhdPtr->scrnIndex, X_WARNING, 0, "!!! Option HPD is set !!!\n" " This shall only be used to work around broken connector tables.\n" " Please report your findings to radeonhd@opensuse.org\n"); } /* * rhdDoReadPCIBios(): do the actual reading, return size and copy in ptr */ static unsigned int rhdDoReadPCIBios(RHDPtr rhdPtr, unsigned char **ptr) { #ifdef XSERVER_LIBPCIACCESS unsigned int size = rhdPtr->PciInfo->rom_size; #else unsigned int size = 1 << rhdPtr->PciInfo->biosSize; int read_len; #endif if (!(*ptr = xcalloc(1, size))) { xf86DrvMsg(rhdPtr->scrnIndex,X_ERROR, "Cannot allocate %i bytes of memory " "for BIOS image\n",size); return 0; } xf86DrvMsg(rhdPtr->scrnIndex,X_INFO,"Getting BIOS copy from PCI ROM\n"); #ifdef XSERVER_LIBPCIACCESS if (pci_device_read_rom(rhdPtr->PciInfo, *ptr)) { xf86DrvMsg(rhdPtr->scrnIndex,X_ERROR, "Cannot read BIOS image\n"); xfree(*ptr); return 0; } #else if ((read_len = xf86ReadPciBIOS(0, rhdPtr->PciTag, -1, *ptr, size)) <= 0) { xf86DrvMsg(rhdPtr->scrnIndex,X_ERROR, "Cannot read BIOS image\n"); xfree(*ptr); return 0; } else if ((unsigned int)read_len != size) { xf86DrvMsg(rhdPtr->scrnIndex,X_WARNING, "Read only %i of %i bytes of BIOS image\n", read_len, size); return (unsigned int)read_len; } #endif return size; } /* * rhdR5XXDoReadPCIBios(): enables access to R5xx BIOS, wraps rhdDoReadPCIBios() */ unsigned int RHDReadPCIBios(RHDPtr rhdPtr, unsigned char **ptr) { unsigned int ret; CARD32 save_seprom_cntl1 = 0, save_gpiopad_a, save_gpiopad_en, save_gpiopad_mask, save_viph_cntl, save_bus_cntl, save_d1vga_control, save_d2vga_control, save_vga_render_control, save_rom_cntl = 0, save_gen_pwrmgt = 0, save_low_vid_lower_gpio_cntl = 0, save_med_vid_lower_gpio_cntl = 0, save_high_vid_lower_gpio_cntl = 0, save_ctxsw_vid_lower_gpio_cntl = 0, save_lower_gpio_en = 0; if (rhdPtr->ChipSet < RHD_R600) save_seprom_cntl1 = RHDRegRead(rhdPtr, SEPROM_CNTL1); save_gpiopad_en = RHDRegRead(rhdPtr, GPIOPAD_EN); save_gpiopad_a = RHDRegRead(rhdPtr, GPIOPAD_A); save_gpiopad_mask = RHDRegRead(rhdPtr, GPIOPAD_MASK); save_viph_cntl = RHDRegRead(rhdPtr, VIPH_CONTROL); save_bus_cntl = RHDRegRead(rhdPtr, BUS_CNTL); save_d1vga_control = RHDRegRead(rhdPtr, D1VGA_CONTROL); save_d2vga_control = RHDRegRead(rhdPtr, D2VGA_CONTROL); save_vga_render_control = RHDRegRead(rhdPtr, VGA_RENDER_CONTROL); if (rhdPtr->ChipSet >= RHD_R600) { save_rom_cntl = RHDRegRead(rhdPtr, ROM_CNTL); save_gen_pwrmgt = RHDRegRead(rhdPtr, GENERAL_PWRMGT); save_low_vid_lower_gpio_cntl = RHDRegRead(rhdPtr, LOW_VID_LOWER_GPIO_CNTL); save_med_vid_lower_gpio_cntl = RHDRegRead(rhdPtr, MEDIUM_VID_LOWER_GPIO_CNTL); save_high_vid_lower_gpio_cntl = RHDRegRead(rhdPtr, HIGH_VID_LOWER_GPIO_CNTL); save_ctxsw_vid_lower_gpio_cntl = RHDRegRead(rhdPtr, CTXSW_VID_LOWER_GPIO_CNTL); save_lower_gpio_en = RHDRegRead(rhdPtr, LOWER_GPIO_ENABLE); } /* Set SPI ROM prescale value to change the SCK period */ if (rhdPtr->ChipSet < RHD_R600) RHDRegMask(rhdPtr, SEPROM_CNTL1, 0x0C << 24, SCK_PRESCALE); /* Let chip control GPIO pads - this is the default state after power up */ RHDRegWrite(rhdPtr, GPIOPAD_EN, 0); RHDRegWrite(rhdPtr, GPIOPAD_A, 0); /* Put GPIO pads in read mode */ RHDRegWrite(rhdPtr, GPIOPAD_MASK, 0); /* Disable VIP Host port */ RHDRegMask(rhdPtr, VIPH_CONTROL, 0, VIPH_EN); /* Enable BIOS ROM */ RHDRegMask(rhdPtr, BUS_CNTL, 0, BIOS_ROM_DIS); /* Disable VGA and select extended timings */ RHDRegMask(rhdPtr, D1VGA_CONTROL, 0, D1VGA_MODE_ENABLE | D1VGA_TIMING_SELECT); RHDRegMask(rhdPtr, D2VGA_CONTROL, 0, D2VGA_MODE_ENABLE | D2VGA_TIMING_SELECT); RHDRegMask(rhdPtr, VGA_RENDER_CONTROL, 0, VGA_VSTATUS_CNTL); if (rhdPtr->ChipSet >= RHD_R600) { RHDRegMask(rhdPtr, ROM_CNTL, SCK_OVERWRITE | 1 << SCK_PRESCALE_CRYSTAL_CLK_SHIFT, SCK_OVERWRITE | 1 << SCK_PRESCALE_CRYSTAL_CLK_SHIFT); RHDRegMask(rhdPtr, GENERAL_PWRMGT, 0, OPEN_DRAIN_PADS); RHDRegMask(rhdPtr, LOW_VID_LOWER_GPIO_CNTL, 0, 0x400); RHDRegMask(rhdPtr, MEDIUM_VID_LOWER_GPIO_CNTL, 0, 0x400); RHDRegMask(rhdPtr, HIGH_VID_LOWER_GPIO_CNTL, 0, 0x400); RHDRegMask(rhdPtr, CTXSW_VID_LOWER_GPIO_CNTL, 0, 0x400); RHDRegMask(rhdPtr, LOWER_GPIO_ENABLE, 0x400, 0x400); } ret = rhdDoReadPCIBios(rhdPtr, ptr); if (rhdPtr->ChipSet < RHD_R600) RHDRegWrite(rhdPtr, SEPROM_CNTL1, save_seprom_cntl1); RHDRegWrite(rhdPtr, GPIOPAD_EN, save_gpiopad_en); RHDRegWrite(rhdPtr, GPIOPAD_A, save_gpiopad_a); RHDRegWrite(rhdPtr, GPIOPAD_MASK, save_gpiopad_mask); RHDRegWrite(rhdPtr, VIPH_CONTROL, save_viph_cntl); RHDRegWrite(rhdPtr, BUS_CNTL, save_bus_cntl); RHDRegWrite(rhdPtr, D1VGA_CONTROL, save_d1vga_control); RHDRegWrite(rhdPtr, D2VGA_CONTROL, save_d2vga_control); RHDRegWrite(rhdPtr, VGA_RENDER_CONTROL, save_vga_render_control); if (rhdPtr->ChipSet >= RHD_R600) { RHDRegWrite(rhdPtr, ROM_CNTL, save_rom_cntl); RHDRegWrite(rhdPtr, GENERAL_PWRMGT, save_gen_pwrmgt); RHDRegWrite(rhdPtr, LOW_VID_LOWER_GPIO_CNTL, save_low_vid_lower_gpio_cntl); RHDRegWrite(rhdPtr, MEDIUM_VID_LOWER_GPIO_CNTL, save_med_vid_lower_gpio_cntl); RHDRegWrite(rhdPtr, HIGH_VID_LOWER_GPIO_CNTL, save_high_vid_lower_gpio_cntl); RHDRegWrite(rhdPtr, CTXSW_VID_LOWER_GPIO_CNTL, save_ctxsw_vid_lower_gpio_cntl); RHDRegWrite(rhdPtr, LOWER_GPIO_ENABLE, save_lower_gpio_en); } return ret; } /* * */ static void rhdGetIGPNorthBridgeInfo(RHDPtr rhdPtr) { switch (rhdPtr->ChipSet) { case RHD_RS600: break; case RHD_RS690: case RHD_RS740: case RHD_RS780: #ifdef XSERVER_LIBPCIACCESS rhdPtr->NBPciInfo = pci_device_find_by_slot(0,0,0,0); #else rhdPtr->NBPciTag = pciTag(0,0,0); #endif break; default: break; } } /* * */ static enum rhdCardType rhdGetCardType(RHDPtr rhdPtr) { uint32_t cmd_stat; if ((rhdPtr->ChipSet == RHD_RS780) || (rhdPtr->ChipSet == RHD_RS880)) return RHD_CARD_PCIE; #ifdef XSERVER_LIBPCIACCESS pci_device_cfg_read_u32(rhdPtr->PciInfo, &cmd_stat, PCI_CMD_STAT_REG); #else cmd_stat = pciReadLong(rhdPtr->PciTag, PCI_CMD_STAT_REG); #endif if (cmd_stat & 0x100000) { uint32_t cap_ptr, cap_id; #ifdef XSERVER_LIBPCIACCESS pci_device_cfg_read_u32(rhdPtr->PciInfo, &cap_ptr, 0x34); #else cap_ptr = pciReadLong(rhdPtr->PciTag, 0x34); #endif cap_ptr &= 0xfc; while (cap_ptr) { #ifdef XSERVER_LIBPCIACCESS pci_device_cfg_read_u32(rhdPtr->PciInfo, &cap_id, cap_ptr); #else cap_id = pciReadLong(rhdPtr->PciTag, cap_ptr); #endif switch (cap_id & 0xff) { case RHD_PCI_CAPID_AGP: xf86DrvMsg(rhdPtr->scrnIndex, X_INFO, "AGP Card Detected\n"); return RHD_CARD_AGP; case RHD_PCI_CAPID_PCIE: xf86DrvMsg(rhdPtr->scrnIndex, X_INFO, "PCIE Card Detected\n"); return RHD_CARD_PCIE; } cap_ptr = (cap_id >> 8) & 0xff; } } return RHD_CARD_NONE; } /* Allocate a chunk of the framebuffer. -1 on fail. So far no free()! */ unsigned int RHDAllocFb(RHDPtr rhdPtr, unsigned int size, const char *name) { unsigned int chunk; size = RHD_FB_CHUNK(size); if (rhdPtr->FbFreeSize < size) { xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "FB: Failed allocating %s (%d KB)\n", name, size/1024); return -1; } chunk = rhdPtr->FbFreeStart; rhdPtr->FbFreeStart += size; rhdPtr->FbFreeSize -= size; xf86DrvMsg(rhdPtr->scrnIndex, X_INFO, "FB: Allocated %s at offset 0x%08X (size = 0x%08X)\n", name, chunk, size); return chunk; }