#ifdef HAVE_CONFIG_H #include "config.h" #endif #include "apm.h" #include "xf86cmap.h" #include "shadowfb.h" #if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 6 #include "xf86Resources.h" #include "xf86RAC.h" #endif #include "xf86int10.h" #include "vbe.h" #include "opaque.h" #ifdef HAVE_XEXTPROTO_71 #include #else #define DPMS_SERVER #include #endif #define APM_VERSION 4000 #define APM_NAME "APM" #define APM_DRIVER_NAME "apm" #define APM_MAJOR_VERSION PACKAGE_VERSION_MAJOR #define APM_MINOR_VERSION PACKAGE_VERSION_MINOR #define APM_PATCHLEVEL PACKAGE_VERSION_PATCHLEVEL #define PCI_VENDOR_ALLIANCE 0x1142 #define PCI_CHIP_AP6422 0x6422 #define PCI_CHIP_AT24 0x6424 #define PCI_CHIP_AT3D 0x643D /* bytes to save for text/font data */ #define TEXT_AMOUNT 32768 /* Mandatory functions */ static const OptionInfoRec * ApmAvailableOptions(int chipid, int busid); static void ApmIdentify(int flags); static Bool ApmProbe(DriverPtr drv, int flags); static Bool ApmPreInit(ScrnInfoPtr pScrn, int flags); static Bool ApmScreenInit(SCREEN_INIT_ARGS_DECL); static Bool ApmEnterVT(VT_FUNC_ARGS_DECL); static void ApmLeaveVT(VT_FUNC_ARGS_DECL); static Bool ApmCloseScreen(CLOSE_SCREEN_ARGS_DECL); static void ApmFreeScreen(FREE_SCREEN_ARGS_DECL); static ModeStatus ApmValidMode(SCRN_ARG_TYPE arg, DisplayModePtr mode, Bool verbose, int flags); static Bool ApmSaveScreen(ScreenPtr pScreen, int mode); static void ApmUnlock(ApmPtr pApm); static void ApmLock(ApmPtr pApm); static void ApmRestore(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, ApmRegPtr ApmReg); static void ApmLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO *colors, VisualPtr pVisual); static void ApmDisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode, int flags); static void ApmProbeDDC(ScrnInfoPtr pScrn, int index); #ifdef XF86RUSH int ApmPixmapIndex = -1; static unsigned long ApmGeneration = 0; #endif _X_EXPORT DriverRec APM = { APM_VERSION, APM_DRIVER_NAME, ApmIdentify, ApmProbe, ApmAvailableOptions, NULL, 0 }; static SymTabRec ApmChipsets[] = { { AP6422, "AP6422" }, { AT24, "AT24" }, { AT3D, "AT3D" }, { -1, NULL } }; static PciChipsets ApmPciChipsets[] = { { PCI_CHIP_AP6422, PCI_CHIP_AP6422, RES_SHARED_VGA }, { PCI_CHIP_AT24, PCI_CHIP_AT24, RES_SHARED_VGA }, { PCI_CHIP_AT3D, PCI_CHIP_AT3D, RES_SHARED_VGA }, { -1, -1, RES_UNDEFINED } }; typedef enum { OPTION_SET_MCLK, OPTION_SW_CURSOR, OPTION_HW_CURSOR, OPTION_NOLINEAR, OPTION_NOACCEL, OPTION_SHADOW_FB, OPTION_PCI_BURST, OPTION_REMAP_DPMS_ON, OPTION_REMAP_DPMS_STANDBY, OPTION_REMAP_DPMS_SUSPEND, OPTION_REMAP_DPMS_OFF, OPTION_PCI_RETRY } ApmOpts; static const OptionInfoRec ApmOptions[] = { {OPTION_SET_MCLK, "SetMclk", OPTV_FREQ, {0}, FALSE}, {OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE}, {OPTION_HW_CURSOR, "HWcursor", OPTV_BOOLEAN, {0}, TRUE}, {OPTION_NOLINEAR, "NoLinear", OPTV_BOOLEAN, {0}, FALSE}, {OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN, {0}, FALSE}, {OPTION_SHADOW_FB, "ShadowFB", OPTV_BOOLEAN, {0}, FALSE}, {OPTION_PCI_BURST, "pci_burst", OPTV_BOOLEAN, {0}, FALSE}, {OPTION_REMAP_DPMS_ON, "Remap_DPMS_On", OPTV_ANYSTR, {0}, FALSE}, {OPTION_REMAP_DPMS_STANDBY, "Remap_DPMS_Standby", OPTV_ANYSTR, {0}, FALSE}, {OPTION_REMAP_DPMS_SUSPEND, "Remap_DPMS_Suspend", OPTV_ANYSTR, {0}, FALSE}, {OPTION_REMAP_DPMS_OFF, "Remap_DPMS_Off", OPTV_ANYSTR, {0}, FALSE}, {OPTION_PCI_RETRY, "PciRetry", OPTV_BOOLEAN, {0}, FALSE}, {-1, NULL, OPTV_NONE, {0}, FALSE} }; #ifdef XFree86LOADER static XF86ModuleVersionInfo apmVersRec = { "apm", MODULEVENDORSTRING, MODINFOSTRING1, MODINFOSTRING2, XORG_VERSION_CURRENT, APM_MAJOR_VERSION, APM_MINOR_VERSION, APM_PATCHLEVEL, ABI_CLASS_VIDEODRV, /* This is a video driver */ ABI_VIDEODRV_VERSION, MOD_CLASS_VIDEODRV, {0,0,0,0} }; static MODULESETUPPROTO(apmSetup); /* * This is the module init data. * Its name has to be the driver name followed by ModuleData. */ _X_EXPORT XF86ModuleData apmModuleData = { &apmVersRec, apmSetup, NULL }; static pointer apmSetup(pointer module, pointer opts, int *errmaj, int *errmain) { static Bool setupDone = FALSE; if (!setupDone) { setupDone = TRUE; xf86AddDriver(&APM, module, 0); return (pointer)1; } else { if (errmaj) *errmaj = LDR_ONCEONLY; return NULL; } } #endif static Bool ApmGetRec(ScrnInfoPtr pScrn) { if (pScrn->driverPrivate) return TRUE; pScrn->driverPrivate = xnfcalloc(sizeof(ApmRec), 1); /* pScrn->driverPrivate != NULL at this point */ return TRUE; } static void ApmFreeRec(ScrnInfoPtr pScrn) { free(pScrn->driverPrivate); pScrn->driverPrivate = NULL; } /* unlock Alliance registers */ static void ApmUnlock(ApmPtr pApm) { if (pApm->Chipset >= AT3D) ApmWriteSeq(0x10, 0x12); else wrinx(pApm->xport, 0x10, 0x12); } /* lock Alliance registers */ static void ApmLock(ApmPtr pApm) { if (pApm->Chipset >= AT3D) ApmWriteSeq(0x10, pApm->savedSR10 ? 0 : 0x12); else wrinx(pApm->xport, 0x10, pApm->savedSR10 ? 0 : 0x12); } static void ApmIdentify(int flags) { xf86PrintChipsets(APM_NAME, "driver for the Alliance chipsets", ApmChipsets); } static const OptionInfoRec * ApmAvailableOptions(int chipid, int busid) { return ApmOptions; } static void ApmAssignFPtr(ScrnInfoPtr pScrn) { pScrn->driverVersion = APM_VERSION; pScrn->driverName = APM_DRIVER_NAME; pScrn->name = APM_NAME; pScrn->Probe = ApmProbe; pScrn->PreInit = ApmPreInit; pScrn->ScreenInit = ApmScreenInit; pScrn->SwitchMode = ApmSwitchMode; pScrn->AdjustFrame = ApmAdjustFrame; pScrn->EnterVT = ApmEnterVT; pScrn->LeaveVT = ApmLeaveVT; pScrn->FreeScreen = ApmFreeScreen; pScrn->ValidMode = ApmValidMode; } static Bool ApmProbe(DriverPtr drv, int flags) { int numDevSections, numUsed, i; GDevPtr *DevSections; int *usedChips; int foundScreen = FALSE; /* * Check if there is a chipset override in the config file */ if ((numDevSections = xf86MatchDevice(APM_DRIVER_NAME, &DevSections)) <= 0) return FALSE; /* * We need to probe the hardware first. We then need to see how this * fits in with what is given in the config file, and allow the config * file info to override any contradictions. */ #ifndef XSERVER_LIBPCIACCESS if (xf86GetPciVideoInfo() == NULL) { return FALSE; } #endif numUsed = xf86MatchPciInstances(APM_NAME, PCI_VENDOR_ALLIANCE, ApmChipsets, ApmPciChipsets, DevSections, numDevSections, drv, &usedChips); if (numUsed > 0) { if (flags & PROBE_DETECT) foundScreen = TRUE; else for (i = 0; i < numUsed; i++) { ScrnInfoPtr pScrn; /* * Allocate a ScrnInfoRec and claim the slot */ pScrn = NULL; if ((pScrn = xf86ConfigPciEntity(pScrn, 0, usedChips[i], ApmPciChipsets, NULL, NULL,NULL,NULL,NULL))){ /* * Fill in what we can of the ScrnInfoRec */ ApmAssignFPtr(pScrn); foundScreen = TRUE; } } } free(DevSections); return foundScreen; } /* * GetAccelPitchValues - * * This function returns a list of display width (pitch) values that can * be used in accelerated mode. */ static int * GetAccelPitchValues(ScrnInfoPtr pScrn) { int *linePitches = NULL; int linep[] = {640, 800, 1024, 1152, 1280, 0}; if (sizeof linep > 0) { linePitches = (int *)xnfalloc(sizeof linep); memcpy(linePitches, linep, sizeof linep); } return linePitches; } static unsigned int ddc1Read(ScrnInfoPtr pScrn) { APMDECL(pScrn); unsigned char tmp; tmp = RDXB_IOP(0xD0); WRXB_IOP(0xD0, tmp & 0x07); while (STATUS_IOP() & 0x800); while (!(STATUS_IOP() & 0x800)); return (STATUS_IOP() & STATUS_SDA) != 0; } static void ApmProbeDDC(ScrnInfoPtr pScrn, int index) { vbeInfoPtr pVbe; if (xf86LoadSubModule(pScrn, "vbe")) { pVbe = VBEInit(NULL, index); ConfiguredMonitor = vbeDoEDID(pVbe, NULL); vbeFree(pVbe); } } static Bool ApmPreInit(ScrnInfoPtr pScrn, int flags) { APMDECL(pScrn); EntityInfoPtr pEnt; vgaHWPtr hwp; MessageType from; char *mod = NULL; const char *s; ClockRangePtr clockRanges; int i; xf86MonPtr MonInfo = NULL; double real; /* * Note: This function is only called once at server startup, and * not at the start of each server generation. This means that * only things that are persistent across server generations can * be initialised here. xf86Screens[] is (pScrn is a pointer to one * of these). Privates allocated using xf86AllocateScrnInfoPrivateIndex() * are too, and should be used for data that must persist across * server generations. * * Per-generation data should be allocated with * AllocateScreenPrivateIndex() from the ScreenInit() function. */ /* Check the number of entities, and fail if it isn't one. */ if (pScrn->numEntities != 1) return FALSE; /* Allocate the ApmRec driverPrivate */ if (!ApmGetRec(pScrn)) { return FALSE; } pApm = APMPTR(pScrn); /* Get the entity */ pEnt = pApm->pEnt = xf86GetEntityInfo(pScrn->entityList[0]); if (pEnt->location.type == BUS_PCI) { pApm->PciInfo = xf86GetPciInfoForEntity(pEnt->index); #ifndef XSERVER_LIBPCIACCESS pApm->PciTag = pciTag(pApm->PciInfo->bus, pApm->PciInfo->device, pApm->PciInfo->func); #endif } else { pApm->PciInfo = NULL; #ifndef XSERVER_LIBPCIACCESS pApm->PciTag = 0; #endif } if (flags & PROBE_DETECT) { ApmProbeDDC(pScrn, pEnt->index); return TRUE; } /* The vgahw module should be allocated here when needed */ if (!xf86LoadSubModule(pScrn, "vgahw")) return FALSE; /* * Allocate a vgaHWRec */ if (!vgaHWGetHWRec(pScrn)) return FALSE; hwp = VGAHWPTR(pScrn); vgaHWSetStdFuncs(hwp); vgaHWGetIOBase(hwp); #if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 12 #define PIOOFFSET hwp->PIOOffset #else /* FIXME reintroduce domain support */ #define PIOOFFSET 0 #endif pApm->iobase = PIOOFFSET; pApm->xport = PIOOFFSET + 0x3C4; /* Set pScrn->monitor */ pScrn->monitor = pScrn->confScreen->monitor; /* XXX: Access funcs */ /* * The first thing we should figure out is the depth, bpp, etc. */ if (!xf86SetDepthBpp(pScrn, 0, 0, 0, Support24bppFb | Support32bppFb)) { return FALSE; } else { /* Check that the returned depth is one we support */ switch (pScrn->depth) { case 4: case 8: case 15: case 16: case 24: /* OK */ break; default: xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Given depth (%d) is not supported by this driver\n", pScrn->depth); return FALSE; } } xf86PrintDepthBpp(pScrn); /* * 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)) { return FALSE; } else { /* XXX check that weight returned is supported */ ; } } if (!xf86SetDefaultVisual(pScrn, -1)) { return FALSE; } else { 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); return FALSE; } } /* We use a programmable clock */ pScrn->progClock = TRUE; /* Collect all of the relevant option flags (fill in pScrn->options) */ xf86CollectOptions(pScrn, NULL); /* Process the options */ if (!(pApm->Options = malloc(sizeof(ApmOptions)))) return FALSE; memcpy(pApm->Options, ApmOptions, sizeof(ApmOptions)); xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pApm->Options); pApm->scrnIndex = pScrn->scrnIndex; /* Set the bits per RGB for 8bpp mode */ if (pScrn->depth > 1 && pScrn->depth <= 8) { /* Default to 8 */ pScrn->rgbBits = 8; } from = X_DEFAULT; pApm->hwCursor = FALSE; if (xf86GetOptValBool(pApm->Options, OPTION_HW_CURSOR, &pApm->hwCursor)) from = X_CONFIG; if (xf86ReturnOptValBool(pApm->Options, OPTION_SW_CURSOR, FALSE)) { from = X_CONFIG; pApm->hwCursor = FALSE; } xf86DrvMsg(pScrn->scrnIndex, from, "Using %s cursor\n", pApm->hwCursor ? "HW" : "SW"); from = X_DEFAULT; if (pScrn->bitsPerPixel < 8) pApm->NoAccel = TRUE; if (xf86ReturnOptValBool(pApm->Options, OPTION_NOACCEL, FALSE)) { from = X_CONFIG; pApm->NoAccel = TRUE; } if (pApm->NoAccel) xf86DrvMsg(pScrn->scrnIndex, from, "Acceleration disabled\n"); if (xf86GetOptValFreq(pApm->Options, OPTION_SET_MCLK, OPTUNITS_MHZ, &real)) { xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "MCLK used is %.1f MHz\n", real); pApm->MemClk = (int)(real * 1000.0); } if (xf86ReturnOptValBool(pApm->Options, OPTION_SHADOW_FB, FALSE)) { pApm->ShadowFB = TRUE; pApm->NoAccel = TRUE; xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Using \"Shadow Framebuffer\" - acceleration disabled\n"); } if (xf86ReturnOptValBool(pApm->Options, OPTION_PCI_RETRY, FALSE)) { if (xf86ReturnOptValBool(pApm->Options, OPTION_PCI_BURST, FALSE)) { pApm->UsePCIRetry = TRUE; xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "PCI retry enabled\n"); } else xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "\"pci_retry\" option requires pci_burst \"on\".\n"); } pApm->DPMSMask[DPMSModeOn] = DPMSModeOn; pApm->DPMSMask[DPMSModeStandby] = DPMSModeStandby; pApm->DPMSMask[DPMSModeSuspend] = DPMSModeSuspend; pApm->DPMSMask[DPMSModeOff] = DPMSModeOff; if ((s = xf86GetOptValString(pApm->Options, OPTION_REMAP_DPMS_ON))) { if (!strcmp(s, "on")) pApm->DPMSMask[DPMSModeOn] = DPMSModeOn; else if (!strcmp(s, "standby")) pApm->DPMSMask[DPMSModeOn] = DPMSModeStandby; else if (!strcmp(s, "suspend")) pApm->DPMSMask[DPMSModeOn] = DPMSModeSuspend; else if (!strcmp(s, "off")) pApm->DPMSMask[DPMSModeOn] = DPMSModeOff; else if (s[0] >= '0' && s[0] <= '9') { pApm->DPMSMask[DPMSModeOn] = strtol(s, NULL, 0); if (pApm->DPMSMask[DPMSModeOn] > (sizeof pApm->DPMSMask)-1) pApm->DPMSMask[DPMSModeOn] = (sizeof pApm->DPMSMask) - 1; } } if ((s = xf86GetOptValString(pApm->Options, OPTION_REMAP_DPMS_STANDBY))) { if (!strcmp(s, "on")) pApm->DPMSMask[DPMSModeStandby] = DPMSModeOn; else if (!strcmp(s, "standby")) pApm->DPMSMask[DPMSModeStandby] = DPMSModeStandby; else if (!strcmp(s, "suspend")) pApm->DPMSMask[DPMSModeStandby] = DPMSModeSuspend; else if (!strcmp(s, "off")) pApm->DPMSMask[DPMSModeStandby] = DPMSModeOff; else if (s[0] >= '0' && s[0] <= '9') { pApm->DPMSMask[DPMSModeStandby] = strtol(s, NULL, 0); if (pApm->DPMSMask[DPMSModeStandby] > (sizeof pApm->DPMSMask)-1) pApm->DPMSMask[DPMSModeStandby] = (sizeof pApm->DPMSMask) - 1; } } if ((s = xf86GetOptValString(pApm->Options, OPTION_REMAP_DPMS_SUSPEND))) { if (!strcmp(s, "on")) pApm->DPMSMask[DPMSModeSuspend] = DPMSModeOn; else if (!strcmp(s, "standby")) pApm->DPMSMask[DPMSModeSuspend] = DPMSModeStandby; else if (!strcmp(s, "suspend")) pApm->DPMSMask[DPMSModeSuspend] = DPMSModeSuspend; else if (!strcmp(s, "off")) pApm->DPMSMask[DPMSModeSuspend] = DPMSModeOff; else if (s[0] >= '0' && s[0] <= '9') { pApm->DPMSMask[DPMSModeSuspend] = strtol(s, NULL, 0); if (pApm->DPMSMask[DPMSModeSuspend] > (sizeof pApm->DPMSMask)-1) pApm->DPMSMask[DPMSModeSuspend] = (sizeof pApm->DPMSMask) - 1; } } if ((s = xf86GetOptValString(pApm->Options, OPTION_REMAP_DPMS_OFF))) { if (!strcmp(s, "on")) pApm->DPMSMask[DPMSModeOff] = DPMSModeOn; else if (!strcmp(s, "standby")) pApm->DPMSMask[DPMSModeOff] = DPMSModeStandby; else if (!strcmp(s, "suspend")) pApm->DPMSMask[DPMSModeOff] = DPMSModeSuspend; else if (!strcmp(s, "off")) pApm->DPMSMask[DPMSModeOff] = DPMSModeOff; else if (s[0] >= '0' && s[0] <= '9') { pApm->DPMSMask[DPMSModeOff] = strtol(s, NULL, 0); if (pApm->DPMSMask[DPMSModeOff] > (sizeof pApm->DPMSMask)-1) pApm->DPMSMask[DPMSModeOff] = (sizeof pApm->DPMSMask) - 1; } } /* * Set the Chipset and ChipRev, allowing config file entries to * override. */ if (pEnt->device->chipset && *pEnt->device->chipset) { pScrn->chipset = pEnt->device->chipset; pApm->Chipset = xf86StringToToken(ApmChipsets, pScrn->chipset); from = X_CONFIG; } else if (pEnt->device->chipID >= 0) { pApm->Chipset = pEnt->device->chipID; pScrn->chipset = (char *)xf86TokenToString(ApmChipsets, pApm->Chipset); from = X_CONFIG; xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipID override: 0x%04X\n", pApm->Chipset); } else { from = X_PROBED; if (pApm->PciInfo) pApm->Chipset = PCI_DEV_DEVICE_ID(pApm->PciInfo); else pApm->Chipset = pEnt->chipset; pScrn->chipset = (char *)xf86TokenToString(ApmChipsets, pApm->Chipset); } if (pScrn->bitsPerPixel == 24 && pApm->Chipset < AT24) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Given depth (%d) is not supported by this driver\n", pScrn->depth); return FALSE; } if (pEnt->device->chipRev >= 0) { pApm->ChipRev = pEnt->device->chipRev; xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n", pApm->ChipRev); } else if (pApm->PciInfo) { pApm->ChipRev = PCI_DEV_REVISION(pApm->PciInfo); } /* * This shouldn't happen because such problems should be caught in * ApmProbe(), but check it just in case. */ if (pScrn->chipset == NULL) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "ChipID 0x%04X is not recognised\n", pApm->Chipset); return FALSE; } if (pApm->Chipset < 0) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Chipset \"%s\" is not recognised\n", pScrn->chipset); return FALSE; } xf86DrvMsg(pScrn->scrnIndex, from, "Chipset: \"%s\"\n", pScrn->chipset); if (pEnt->device->MemBase != 0) { pApm->LinAddress = pEnt->device->MemBase; from = X_CONFIG; } else if (pApm->PciInfo) { pApm->LinAddress = PCI_REGION_BASE(pApm->PciInfo, 0, REGION_MEM) & 0xFF800000; from = X_PROBED; } else { /* * VESA local bus. * Pray that 2048MB works. */ pApm->LinAddress = 0x80000000; } xf86DrvMsg(pScrn->scrnIndex, from, "Linear framebuffer at 0x%lX\n", (unsigned long)pApm->LinAddress); if (xf86LoadSubModule(pScrn, "ddc")) { if (xf86LoadSubModule(pScrn, "i2c")) { pApm->I2C = TRUE; } } if (pApm->Chipset >= AT3D) pApm->LinMapSize = 16 * 1024 * 1024; else pApm->LinMapSize = 6 * 1024 * 1024; pApm->FbMapSize = 4 * 1024 * 1024; if (xf86LoadSubModule(pScrn, "int10")) { void *ptr; xf86DrvMsg(pScrn->scrnIndex,X_INFO,"initializing int10\n"); ptr = xf86InitInt10(pEnt->index); if (ptr) xf86FreeInt10(ptr); } #ifndef XSERVER_LIBPCIACCESS xf86RegisterResources(pEnt->index, NULL, ResNone); xf86SetOperatingState(resVga, pEnt->index, ResDisableOpr); pScrn->racMemFlags = 0; /* For noLinear, access to 0xA0000 */ if (pApm->VGAMap) pScrn->racIoFlags = 0; else pScrn->racIoFlags = RAC_COLORMAP | RAC_VIEWPORT; #endif if (pEnt->device->videoRam != 0) { pScrn->videoRam = pEnt->device->videoRam; from = X_CONFIG; } else if (pApm->Chipset >= AT3D) { unsigned char d9, db, uc; /*unsigned long save;*/ volatile unsigned char *LinMap; #ifndef XSERVER_LIBPCIACCESS LinMap = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO, pApm->PciTag, pApm->LinAddress, pApm->LinMapSize); #else { void** result = (void**)&LinMap; int err = pci_device_map_range(pApm->PciInfo, pApm->LinAddress, pApm->LinMapSize, PCI_DEV_MAP_FLAG_WRITABLE, result); if (err) return FALSE; } #endif /*save = pciReadLong(pApm->PciTag, PCI_CMD_STAT_REG); pciWriteLong(pApm->PciTag, PCI_CMD_STAT_REG, save | PCI_CMD_MEM_ENABLE);*/ d9 = LinMap[0xFFECD9]; db = LinMap[0xFFECDB]; LinMap[0xFFECDB] = (db & 0xF4) | 0x0A; LinMap[0xFFECD9] = (d9 & 0xCF) | 0x20; LinMap[0xFFF3C4] = 0x1C; uc = LinMap[0xFFF3C5]; LinMap[0xFFF3C5] = 0x3F; LinMap[0xFFF3C4] = 0x20; pScrn->videoRam = LinMap[0xFFF3C5] * 64; LinMap[0xFFF3C4] = 0x10; pApm->savedSR10 = LinMap[0xFFF3C5]; LinMap[0xFFF3C4] = 0x1E; pApm->xbase = LinMap[0xFFF3C5]; LinMap[0xFFF3C4] = 0x1F; pApm->xbase |= LinMap[0xFFF3C5] << 8; LinMap[0xFFF3C4] = 0x1C; LinMap[0xFFF3C5] = uc; LinMap[0xFFECDB] = db; LinMap[0xFFECD9] = d9; /*pciWriteLong(pApm->PciTag, PCI_CMD_STAT_REG, save);*/ #ifndef XSERVER_LIBPCIACCESS xf86UnMapVidMem(pScrn->scrnIndex, (pointer)LinMap, pApm->LinMapSize); #else pci_device_unmap_range(pApm->PciInfo, (pointer)LinMap, pApm->LinMapSize); #endif from = X_PROBED; } else { /*unsigned long save; save = pciReadLong(pApm->PciTag, PCI_CMD_STAT_REG); pciWriteLong(pApm->PciTag, PCI_CMD_STAT_REG, save | PCI_CMD_IO_ENABLE);*/ pApm->savedSR10 = rdinx(pApm->xport, 0x10); wrinx(pApm->xport, 0x10, 0x12); pScrn->videoRam = rdinx(pApm->xport, 0x20) * 64; pApm->xbase = rdinx(pApm->xport, 0x1F) << 8; pApm->xbase |= rdinx(pApm->xport, 0x1E); pApm->xbase += pApm->iobase; wrinx(pApm->xport, 0x10, pApm->savedSR10 ? 0 : 0x12); /*pciWriteLong(pApm->PciTag, PCI_CMD_STAT_REG, save);*/ from = X_PROBED; } if (pApm->Chipset < AT3D && pScrn->videoRam >= 4096) pScrn->videoRam -= 32; xf86DrvMsg(pScrn->scrnIndex, from, "VideoRAM: %d kByte\n", pScrn->videoRam); #if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 12 if (!xf86IsPc98()) #endif { hwp->MapSize = 0x10000; vgaHWMapMem(pScrn); if (pApm->I2C) { if (!ApmI2CInit(pScrn)) { xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"I2C initialization failed\n"); } else { MonInfo = xf86DoEDID_DDC2(XF86_SCRN_ARG(pScrn),pApm->I2CPtr); } } if (0 && !MonInfo) MonInfo = xf86DoEDID_DDC1(XF86_SCRN_ARG(pScrn),vgaHWddc1SetSpeed,ddc1Read); if (MonInfo) { xf86PrintEDID(MonInfo); xf86SetDDCproperties(pScrn, MonInfo); } pScrn->monitor->DDC = MonInfo; } /* The gamma fields must be initialised when using the new cmap code */ if (pScrn->depth > 1) { Gamma zeros = {0.0, 0.0, 0.0}; if (!xf86SetGamma(pScrn, zeros)) { return FALSE; } } pApm->MinClock = 23125; xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "Min pixel clock set to %d MHz\n", pApm->MinClock / 1000); /* * If the user has specified ramdac speed in the XF86Config * file, we respect that setting. */ from = X_DEFAULT; if (pEnt->device->dacSpeeds[0]) { int speed = 0; switch (pScrn->bitsPerPixel) { case 4: case 8: speed = pEnt->device->dacSpeeds[DAC_BPP8]; break; case 16: speed = pEnt->device->dacSpeeds[DAC_BPP16]; break; case 24: speed = pEnt->device->dacSpeeds[DAC_BPP24]; break; case 32: speed = pEnt->device->dacSpeeds[DAC_BPP32]; break; } if (speed == 0) pApm->MaxClock = pEnt->device->dacSpeeds[0]; else pApm->MaxClock = speed; from = X_CONFIG; } else { switch(pApm->Chipset) { /* These values come from the Manual for AT24 and AT3D in the overview of various modes. I've taken the largest number for the different modes. Alliance wouldn't tell me what the maximum frequency was, so... */ case AT24: switch(pScrn->bitsPerPixel) { case 4: case 8: pApm->MaxClock = 160000; break; case 16: pApm->MaxClock = 144000; break; case 24: pApm->MaxClock = 75000; /* Hmm. */ break; case 32: pApm->MaxClock = 94500; break; default: return FALSE; } break; case AT3D: switch(pScrn->bitsPerPixel) { case 4: case 8: pApm->MaxClock = 175500; break; case 16: pApm->MaxClock = 144000; break; case 24: pApm->MaxClock = 94000; /* Changed from 75000 by GreniƩ */ break; case 32: pApm->MaxClock = 94500; break; default: return FALSE; } break; case AP6422: switch(pScrn->bitsPerPixel) { case 4: case 8: pApm->MaxClock = 135000; break; case 16: pApm->MaxClock = 75000; break; case 32: pApm->MaxClock = 60000; break; default: return FALSE; } break; default: pApm->MaxClock = 135000; break; } } xf86DrvMsg(pScrn->scrnIndex, from, "Max pixel clock is %d MHz\n", pApm->MaxClock / 1000); /* * Setup the ClockRanges, which describe what clock ranges are available, * and what sort of modes they can be used for. */ clockRanges = (ClockRangePtr)xnfcalloc(sizeof(ClockRange), 1); clockRanges->next = NULL; clockRanges->minClock = pApm->MinClock; clockRanges->maxClock = pApm->MaxClock; clockRanges->clockIndex = -1; /* programmable */ clockRanges->interlaceAllowed = FALSE; /* XXX change this */ clockRanges->doubleScanAllowed = FALSE; /* XXX check this */ /* Select valid modes from those available */ if (pApm->NoAccel) { /* * XXX Assuming min pitch 256, max 2048 * XXX Assuming min height 128, max 1024 (changed EE) */ i = xf86ValidateModes(pScrn, pScrn->monitor->Modes, pScrn->display->modes, clockRanges, NULL, 256, 2048, pScrn->bitsPerPixel, 128, 1024, pScrn->display->virtualX, pScrn->display->virtualY, pApm->FbMapSize, LOOKUP_BEST_REFRESH); } else { /* * XXX Assuming min height 128, max 2048 */ i = xf86ValidateModes(pScrn, pScrn->monitor->Modes, pScrn->display->modes, clockRanges, GetAccelPitchValues(pScrn), 0, 0, pScrn->bitsPerPixel, 128, 1024, pScrn->display->virtualX, pScrn->display->virtualY, pApm->FbMapSize, LOOKUP_BEST_REFRESH); } if (i == -1) { ApmFreeRec(pScrn); return FALSE; } /* Prune the modes marked as invalid */ xf86PruneDriverModes(pScrn); if (i == 0 || pScrn->modes == NULL) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n"); ApmFreeRec(pScrn); return FALSE; } xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V); /* Set the current mode to the first in the list */ pScrn->currentMode = pScrn->modes; /* Print the list of modes being used */ xf86PrintModes(pScrn); /* Set display resolution */ xf86SetDpi(pScrn, 0, 0); /* Load bpp-specific modules */ switch (pScrn->bitsPerPixel) { case 8: case 16: case 24: case 32: mod = "fb"; break; } if (mod && xf86LoadSubModule(pScrn, mod) == NULL) { ApmFreeRec(pScrn); return FALSE; } /* Load XAA if needed */ if (!pApm->NoAccel) { #ifdef HAVE_XAA_H if (!xf86LoadSubModule(pScrn, "xaa")) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Falling back to shadowfb\n"); pApm->NoAccel = TRUE; pApm->ShadowFB = TRUE; } #else pApm->NoAccel = TRUE; pApm->ShadowFB = TRUE; #endif } /* Load ramdac if needed */ if (pApm->hwCursor) { if (!xf86LoadSubModule(pScrn, "ramdac")) { ApmFreeRec(pScrn); return FALSE; } } /* Load shadowfb if needed */ if (pApm->ShadowFB) { if (!xf86LoadSubModule(pScrn, "shadowfb")) { ApmFreeRec(pScrn); return FALSE; } } pApm->CurrentLayout.displayWidth = pScrn->virtualX; pApm->CurrentLayout.displayHeight = pScrn->virtualY; pApm->CurrentLayout.bitsPerPixel = pScrn->bitsPerPixel; pApm->CurrentLayout.bytesPerScanline= (pApm->CurrentLayout.displayWidth * pApm->CurrentLayout.bitsPerPixel) >> 3; pApm->CurrentLayout.depth = pScrn->depth; pApm->CurrentLayout.Scanlines = 2 * (pScrn->videoRam << 10) / pApm->CurrentLayout.bytesPerScanline; if (pScrn->bitsPerPixel == 24) pApm->CurrentLayout.mask32 = 3; else pApm->CurrentLayout.mask32 = 32 / pScrn->bitsPerPixel - 1; return TRUE; } /* * Map the framebuffer and MMIO memory. */ static Bool ApmMapMem(ScrnInfoPtr pScrn) { APMDECL(pScrn); vgaHWPtr hwp = VGAHWPTR(pScrn); #ifndef XSERVER_LIBPCIACCESS pApm->LinMap = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER, pApm->PciTag, (unsigned long)pApm->LinAddress, pApm->LinMapSize); #else { void** result = (void**)&pApm->LinMap; int err = pci_device_map_range(pApm->PciInfo, pApm->LinAddress, pApm->LinMapSize, PCI_DEV_MAP_FLAG_WRITABLE | PCI_DEV_MAP_FLAG_WRITE_COMBINE, result); if (err) return FALSE; } #endif if (pApm->LinMap == NULL) return FALSE; if (pApm->Chipset >= AT3D) { pApm->FbBase = (void *)(((char *)pApm->LinMap) + 0x800000); pApm->VGAMap = ((char *)pApm->LinMap) + 0xFFF000; pApm->MemMap = ((char *)pApm->LinMap) + 0xFFEC00; pApm->BltMap = (void *)(((char *)pApm->LinMap) + 0x3F8000); } else { pApm->FbBase = (void *)pApm->LinMap; pApm->VGAMap = NULL; if (pScrn->videoRam == 6 * 1024 - 32) { pApm->MemMap = ((char *)pApm->LinMap) + 0x5FF800; pApm->BltMap = (void *)(((char *)pApm->LinMap) + 0x5F8000); } else { pApm->MemMap = ((char *)pApm->LinMap) + 0x3FF800; pApm->BltMap = (void *)(((char *)pApm->LinMap) + 0x3F8000); } } /* * Initialize chipset */ pApm->c9 = RDXB(0xC9); if (pApm->Chipset >= AT3D) { pApm->d9 = RDXB(0xD9); pApm->db = RDXB(0xDB); /* If you change these two, change them also in apm_funcs.c */ WRXB(0xDB, (pApm->db & 0xF4) | 0x0A); WRXB(0xD9, (pApm->d9 & 0xCF) | 0x20); vgaHWSetMmioFuncs(hwp, (CARD8 *)pApm->LinMap, 0xFFF000); } if (pApm->Chipset >= AP6422) WRXB(0xC9, pApm->c9 | 0x10); /* * Save color mode */ pApm->MiscOut = hwp->readMiscOut(hwp); return TRUE; } /* * Unmap the framebuffer and MMIO memory */ static Bool ApmUnmapMem(ScrnInfoPtr pScrn) { APMDECL(pScrn); vgaHWPtr hwp = VGAHWPTR(pScrn); /* * Reset color mode */ hwp->writeMiscOut(hwp, pApm->MiscOut); if (pApm->LinMap) { if (pApm->Chipset >= AT3D) { WRXB(0xD9, pApm->d9); WRXB(0xDB, pApm->db); } WRXB(0xC9, pApm->c9); #ifndef XSERVER_LIBPCIACCESS xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pApm->LinMap, pApm->LinMapSize); #else pci_device_unmap_range(pApm->PciInfo, (pointer)pApm->LinMap, pApm->LinMapSize); #endif pApm->LinMap = NULL; } else if (pApm->FbBase) #ifndef XSERVER_LIBPCIACCESS xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pApm->LinMap, 0x10000); #else pci_device_unmap_range(pApm->PciInfo, (pointer)pApm->LinMap, 0x10000); #endif return TRUE; } /* * This function saves the video state. */ static void ApmSave(ScrnInfoPtr pScrn) { APMDECL(pScrn); ApmRegPtr ApmReg = &pApm->SavedReg; vgaHWPtr hwp = VGAHWPTR(pScrn); if (pApm->VGAMap) { ApmReg->SEQ[0x1B] = ApmReadSeq(0x1B); ApmReg->SEQ[0x1C] = ApmReadSeq(0x1C); /* * Save fonts */ if (!(hwp->SavedReg.Attribute[0x10] & 1)) { if (pApm->FontInfo || (pApm->FontInfo = malloc(TEXT_AMOUNT))) { int locked; locked = ApmReadSeq(0x10); if (locked) ApmWriteSeq(0x10, 0x12); ApmWriteSeq(0x1C, 0x3F); memcpy(pApm->FontInfo, pApm->FbBase, TEXT_AMOUNT); ApmWriteSeq(0x1C, ApmReg->SEQ[0x1C]); if (locked) ApmWriteSeq(0x10, 0); } } /* * This function will handle creating the data structure and filling * in the generic VGA portion. */ vgaHWSave(pScrn, &hwp->SavedReg, VGA_SR_MODE | VGA_SR_CMAP); /* Hardware cursor registers. */ ApmReg->EX[XR140] = RDXL(0x140); ApmReg->EX[XR144] = RDXW(0x144); ApmReg->EX[XR148] = RDXL(0x148); ApmReg->EX[XR14C] = RDXW(0x14C); ApmReg->CRT[0x19] = ApmReadCrtc(0x19); ApmReg->CRT[0x1A] = ApmReadCrtc(0x1A); ApmReg->CRT[0x1B] = ApmReadCrtc(0x1B); ApmReg->CRT[0x1C] = ApmReadCrtc(0x1C); ApmReg->CRT[0x1D] = ApmReadCrtc(0x1D); ApmReg->CRT[0x1E] = ApmReadCrtc(0x1E); /* RAMDAC registers. */ ApmReg->EX[XRE8] = RDXL(0xE8); ApmReg->EX[XREC] = RDXL(0xEC); /* Color correction */ ApmReg->EX[XRE0] = RDXL(0xE0); ApmReg->EX[XR80] = RDXB(0x80); } else { /* * This function will handle creating the data structure and filling * in the generic VGA portion. */ vgaHWSave(pScrn, &hwp->SavedReg, VGA_SR_ALL); ApmReg->SEQ[0x1B] = rdinx(pApm->xport, 0x1B); ApmReg->SEQ[0x1C] = rdinx(pApm->xport, 0x1C); /* Hardware cursor registers. */ ApmReg->EX[XR140] = RDXL(0x140); ApmReg->EX[XR144] = RDXW(0x144); ApmReg->EX[XR148] = RDXL(0x148); ApmReg->EX[XR14C] = RDXW(0x14C); ApmReg->CRT[0x19] = rdinx(pApm->iobase + 0x3D4, 0x19); ApmReg->CRT[0x1A] = rdinx(pApm->iobase + 0x3D4, 0x1A); ApmReg->CRT[0x1B] = rdinx(pApm->iobase + 0x3D4, 0x1B); ApmReg->CRT[0x1C] = rdinx(pApm->iobase + 0x3D4, 0x1C); ApmReg->CRT[0x1D] = rdinx(pApm->iobase + 0x3D4, 0x1D); ApmReg->CRT[0x1E] = rdinx(pApm->iobase + 0x3D4, 0x1E); /* RAMDAC registers. */ ApmReg->EX[XRE8] = RDXL(0xE8); ApmReg->EX[XREC] = RDXL(0xEC); /* Color correction */ ApmReg->EX[XRE0] = RDXL(0xE0); ApmReg->EX[XR80] = RDXB(0x80); } } #define WITHIN(v,c1,c2) (((v) >= (c1)) && ((v) <= (c2))) static unsigned comp_lmn(ApmPtr pApm, long clock) { int n, m, l, f; double fvco; double fout; double fmax, fmin; double fref; double fvco_goal; double k, c; double fout_best = 0; unsigned int best = 0; if (pApm->Chipset >= AT3D) fmax = 370000.0; else fmax = 250000.0; fref = 14318.0; fmin = fmax / 2.0; for (m = 1; m <= 5; m++) { for (l = 3; l >= 0; l--) { for (n = 8; n <= 127; n++) { fout = ((double)(n + 1) * fref)/((double)(m + 1) * (1 << l)); fvco_goal = (double)clock * (double)(1 << l); fvco = fout * (double)(1 << l); if (!WITHIN(fvco, 0.99*fvco_goal, 1.01*fvco_goal)) continue; if (!WITHIN(fvco, fmin, fmax)) continue; if (!WITHIN(fvco / (double)(n+1), 300.0, 300000.0)) continue; if (!WITHIN(fref / (double)(m+1), 300.0, 300000.0)) continue; if (fout_best != 0) { double diff_new = clock - fout; double diff_old = clock - best; diff_new = diff_new < 0 ? -diff_new : diff_new; diff_old = diff_old < 0 ? -diff_old : diff_old; if (diff_new > diff_old) continue; } fout_best = fout; /* The following formula was empirically derived by matching a number of fvco values with acceptable values of f. (fvco can be 185MHz - 370MHz on AT3D) (fvco can be 125MHz - 250MHz on AT24/AP6422) The table that was measured up follows: AT3D fvco f (125) (x-7) guess 200 5-7 219 4-7 253 3-6 289 2-5 320 0-4 (400) (0-x) guess AT24 fvco f 126 7 200 5-7 211 4-7 AP6422 fvco f 126 7 169 5-7 200 4-5 211 4-5 From this, a function "f = k * fvco + c" was derived. For AT3D, this table was measured with MCLK == 50MHz. The driver has since been set to use MCLK == 57.3MHz for, but I don't think that makes a difference here. */ if (pApm->Chipset >= AT24) { k = 7.0 / (175.0 - 380.0); c = -k * 380.0; f = (int)(k * fvco/1000.0 + c + 0.5); if (f > 7) f = 7; if (f < 0) f = 0; } else { /* i.e AP6422 */ c = (211.0*6.0-169.0*4.5)/(211.0-169.0); k = (4.5-c)/211.0; f = (int)(k * fvco/1000.0 + c + 0.5); if (f > 7) f = 7; if (f < 0) f = 0; } best = (n << 16) | (m << 8) | (l << 2) | (f << 4); } } } if (fout_best != 0) return best; xf86DrvMsg(pApm->scrnIndex, X_PROBED, "Cannot find register values for clock %6.2f MHz. " "Please use a (slightly) different clock.\n", (double)clock / 1000.0); return 0; } /* * Initialise a new mode. This is currently still using the old * "initialise struct, restore/write struct to HW" model. That could * be changed. */ static Bool ApmModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode) { APMDECL(pScrn); ApmRegPtr ApmReg = &pApm->ModeReg; vgaHWPtr hwp; /* set clockIndex to "2" for programmable clocks */ if (pScrn->progClock) mode->ClockIndex = 2; /* prepare standard VGA register contents */ if (!vgaHWInit(pScrn, mode)) return FALSE; pScrn->vtSema = TRUE; hwp = VGAHWPTR(pScrn); hwp->writeMiscOut(hwp, pApm->MiscOut | 0x0F); #if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 12 if (xf86IsPc98()) outb(0xFAC, 0xFF); #endif memcpy(ApmReg, &pApm->SavedReg, sizeof pApm->SavedReg); /* * The APM chips have a scale factor of 8 for the * scanline offset. There are four extended bit in addition * to the 8 VGA bits. */ { int offset; offset = (pApm->CurrentLayout.displayWidth * pApm->CurrentLayout.bitsPerPixel / 8) >> 3; hwp->ModeReg.CRTC[0x13] = offset; /* Bit 8 resides at CR1C bits 7:4. */ ApmReg->CRT[0x1C] = (offset & 0xF00) >> 4; } /* Set pixel depth. */ switch(pApm->CurrentLayout.bitsPerPixel) { case 4: ApmReg->EX[XR80] = 0x01; break; case 8: ApmReg->EX[XR80] = 0x02; break; case 16: if (pApm->CurrentLayout.depth == 15) ApmReg->EX[XR80] = 0x0C; else ApmReg->EX[XR80] = 0x0D; break; case 24: ApmReg->EX[XR80] = 0x0E; break; case 32: ApmReg->EX[XR80] = 0x0F; break; default: FatalError("Unsupported bit depth %d\n", pApm->CurrentLayout.depth); break; } /* Set banking register to zero. */ ApmReg->EX[XRC0] = 0; /* Handle the CRTC overflow bits. */ { unsigned char val; /* Vertical Overflow. */ val = 0; if ((mode->CrtcVTotal - 2) & 0x400) val |= 0x01; if ((mode->CrtcVDisplay - 1) & 0x400) val |= 0x02; /* VBlankStart is equal to VSyncStart + 1. */ if (mode->CrtcVSyncStart & 0x400) val |= 0x04; /* VRetraceStart is equal to VSyncStart + 1. */ if (mode->CrtcVSyncStart & 0x400) val |= 0x08; ApmReg->CRT[0x1A] = val; /* Horizontal Overflow. */ val = 0; if ((mode->CrtcHTotal / 8 - 5) & 0x100) val |= 1; if ((mode->CrtcHDisplay / 8 - 1) & 0x100) val |= 2; /* HBlankStart is equal to HSyncStart - 1. */ if ((mode->CrtcHSyncStart / 8 - 1) & 0x100) val |= 4; /* HRetraceStart is equal to HSyncStart. */ if ((mode->CrtcHSyncStart / 8) & 0x100) val |= 8; ApmReg->CRT[0x1B] = val; /* Assume the CRTC is not KGA (see vgaHWInit) */ hwp->ModeReg.CRTC[3] = (hwp->ModeReg.CRTC[3] & 0xE0) | (((mode->CrtcHBlankEnd >> 3) - 1) & 0x1F); hwp->ModeReg.CRTC[5] = ((((mode->CrtcHBlankEnd >> 3) - 1) & 0x20) << 2) | (hwp->ModeReg.CRTC[5] & 0x7F); hwp->ModeReg.CRTC[22] = (mode->CrtcVBlankEnd - 1) & 0xFF; } ApmReg->CRT[0x1E] = 1; /* disable autoreset feature */ /* Program clock select. */ ApmReg->EX[XREC] = comp_lmn(pApm, mode->Clock); if (!ApmReg->EX[XREC]) return FALSE; hwp->ModeReg.MiscOutReg |= 0x0C; /* Set up the RAMDAC registers. */ if (pApm->CurrentLayout.bitsPerPixel > 8) /* Get rid of white border. */ hwp->ModeReg.Attribute[0x11] = 0x00; else hwp->ModeReg.Attribute[0x11] = 0xFF; if (pApm->MemClk) ApmReg->EX[XRE8] = comp_lmn(pApm, pApm->MemClk); else if (pApm->Chipset >= AT3D) ApmReg->EX[XRE8] = 0x071F01E8; /* Enable 58MHz MCLK (actually 57.3 MHz) This is what is used in the Windows drivers. The BIOS sets it to 50MHz. */ else ApmReg->EX[XRE8] = RDXL(0xE8); /* No change */ ApmReg->EX[XRE0] = 0x10; /* If you change it, change in apm_funcs.c as well */ if (pApm->Chipset >= AT3D) { ApmReg->SEQ[0x1B] = 0x20; ApmReg->SEQ[0x1C] = 0x2F; } else { ApmReg->SEQ[0x1B] = 0x24; if (pScrn->videoRam >= 6 * 1024) ApmReg->SEQ[0x1C] = 0x2F; else ApmReg->SEQ[0x1C] = 0x2D; } /* ICICICICI */ ApmRestore(pScrn, &hwp->ModeReg, ApmReg); return TRUE; } /* * Restore the initial mode. */ static void ApmRestore(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, ApmRegPtr ApmReg) { APMDECL(pScrn); vgaHWProtect(pScrn, TRUE); ApmUnlock(pApm); if (pApm->VGAMap) { /* * Restore fonts */ if (!(vgaReg->Attribute[0x10] & 1) && pApm->FontInfo) { ApmWriteSeq(0x1C, 0x3F); memcpy(pApm->FbBase, pApm->FontInfo, TEXT_AMOUNT); } /* Set aperture index to 0. */ WRXW(0xC0, 0); /* * Write the extended registers first */ ApmWriteSeq(0x1B, ApmReg->SEQ[0x1B]); ApmWriteSeq(0x1C, ApmReg->SEQ[0x1C]); /* Hardware cursor registers. */ WRXL(0x140, ApmReg->EX[XR140]); WRXW(0x144, ApmReg->EX[XR144]); WRXL(0x148, ApmReg->EX[XR148]); WRXW(0x14C, ApmReg->EX[XR14C]); ApmWriteCrtc(0x19, ApmReg->CRT[0x19]); ApmWriteCrtc(0x1A, ApmReg->CRT[0x1A]); ApmWriteCrtc(0x1B, ApmReg->CRT[0x1B]); ApmWriteCrtc(0x1D, ApmReg->CRT[0x1D]); ApmWriteCrtc(0x1E, ApmReg->CRT[0x1E]); /* RAMDAC registers. */ WRXL(0xE8, ApmReg->EX[XRE8]); WRXL(0xEC, ApmReg->EX[XREC] & ~(1 << 7)); WRXL(0xEC, ApmReg->EX[XREC] | (1 << 7)); /* Do a PLL resync */ /* Color correction */ WRXL(0xE0, ApmReg->EX[XRE0]); /* * This function handles restoring the generic VGA registers. */ vgaHWRestore(pScrn, vgaReg, VGA_SR_MODE | VGA_SR_CMAP); /* set these after setting the default VGA registers */ ApmWriteCrtc(0x1C, ApmReg->CRT[0x1C]); WRXB(0x80, ApmReg->EX[XR80]); } else { /* Set aperture index to 0. */ WRXW(0xC0, 0); /* * Write the extended registers first */ wrinx(pApm->xport, 0x1B, ApmReg->SEQ[0x1B]); wrinx(pApm->xport, 0x1C, ApmReg->SEQ[0x1C]); /* Hardware cursor registers. */ WRXL(0x140, ApmReg->EX[XR140]); WRXW(0x144, ApmReg->EX[XR144]); WRXL(0x148, ApmReg->EX[XR148]); WRXW(0x14C, ApmReg->EX[XR14C]); wrinx(pApm->iobase + 0x3D4, 0x19, ApmReg->CRT[0x19]); wrinx(pApm->iobase + 0x3D4, 0x1A, ApmReg->CRT[0x1A]); wrinx(pApm->iobase + 0x3D4, 0x1B, ApmReg->CRT[0x1B]); wrinx(pApm->iobase + 0x3D4, 0x1C, ApmReg->CRT[0x1C]); wrinx(pApm->iobase + 0x3D4, 0x1D, ApmReg->CRT[0x1D]); wrinx(pApm->iobase + 0x3D4, 0x1E, ApmReg->CRT[0x1E]); /* RAMDAC registers. */ WRXL(0xE8, ApmReg->EX[XRE8]); WRXL(0xEC, ApmReg->EX[XREC] & ~(1 << 7)); WRXL(0xEC, ApmReg->EX[XREC] | (1 << 7)); /* Do a PLL resync */ /* Color correction */ WRXL(0xE0, ApmReg->EX[XRE0]); WRXB(0x80, ApmReg->EX[XR80]); /* * This function handles restoring the generic VGA registers. */ vgaHWRestore(pScrn, vgaReg, VGA_SR_ALL); } vgaHWProtect(pScrn, FALSE); } /* Refresh a region of the shadow framebuffer to the screen */ static void ApmRefreshArea(ScrnInfoPtr pScrn, int num, BoxPtr pbox) { APMDECL(pScrn); int width, height, Bpp, FBPitch; unsigned char *src, *dst; Bpp = pApm->CurrentLayout.bitsPerPixel >> 3; FBPitch = pApm->CurrentLayout.bytesPerScanline; while(num--) { width = (pbox->x2 - pbox->x1) * Bpp; height = pbox->y2 - pbox->y1; src = pApm->ShadowPtr + (pbox->y1 * pApm->ShadowPitch) + (pbox->x1 * Bpp); dst = (unsigned char *)pApm->FbBase + (pbox->y1 * FBPitch) + (pbox->x1 * Bpp); while(height--) { memcpy(dst, src, width); dst += FBPitch; src += pApm->ShadowPitch; } pbox++; } } /* Mandatory */ /* This gets called at the start of each server generation */ static Bool ApmScreenInit(SCREEN_INIT_ARGS_DECL) { ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); APMDECL(pScrn); int ret; unsigned char *FbBase; pApm->pScreen = pScreen; /* Map the chip memory and MMIO areas */ if (!ApmMapMem(pScrn)) return FALSE; /* No memory reserved yet */ pApm->OffscreenReserved = 0; /* Save the current state */ ApmSave(pScrn); /* Initialise the first mode */ ApmModeInit(pScrn, pScrn->currentMode); pApm->CurrentLayout.pMode = pScrn->currentMode; /* Darken the screen for aesthetic reasons and set the viewport */ ApmSaveScreen(pScreen, SCREEN_SAVER_ON); ApmAdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0)); /* * Reset fb's visual list. */ miClearVisualTypes(); /* Setup the visuals we support. */ /* * For bpp > 8, the default visuals are not acceptable because we only * support TrueColor and not DirectColor. To deal with this, call * miSetVisualTypes for each visual supported. */ if (pApm->CurrentLayout.bitsPerPixel > 8) { if (!miSetVisualTypes(pScrn->depth, TrueColorMask, pScrn->rgbBits, pScrn->defaultVisual)) return FALSE; } else { if (!miSetVisualTypes(pScrn->depth, miGetDefaultVisualMask(pScrn->depth), pScrn->rgbBits, pScrn->defaultVisual)) return FALSE; } /* * Call the framebuffer layer's ScreenInit function, and fill in other * pScreen fields. */ if(pApm->ShadowFB) { pApm->ShadowPitch = ((pScrn->virtualX * pScrn->bitsPerPixel >> 3) + 3) & ~3L; pApm->ShadowPtr = malloc(pApm->ShadowPitch * pScrn->virtualY); FbBase = pApm->ShadowPtr; } else { pApm->ShadowPtr = NULL; FbBase = pApm->FbBase; } /* Reserve memory */ ApmHWCursorReserveSpace(pApm); ApmAccelReserveSpace(pApm); miSetPixmapDepths(); switch (pScrn->bitsPerPixel) { case 8: case 16: case 24: case 32: ret = fbScreenInit(pScreen, FbBase, pScrn->virtualX, pScrn->virtualY, pScrn->xDpi, pScrn->yDpi, pScrn->displayWidth, pScrn->bitsPerPixel); break; default: xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Internal error: invalid bpp (%d) in ApmScrnInit\n", pScrn->bitsPerPixel); ret = FALSE; break; } if (!ret) return FALSE; if (pScrn->bitsPerPixel > 8) { VisualPtr visual; /* Fixup RGB ordering */ 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 visual RGB order fixed */ if (pScrn->bitsPerPixel > 4) fbPictureInit(pScreen, 0, 0); xf86SetBlackWhitePixels(pScreen); if (!pApm->ShadowFB) { /* hardware cursor needs to wrap this layer */ if(!ApmDGAInit(pScreen)) { xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"DGA initialization failed\n"); } } /* * Initialize the acceleration interface. */ #ifdef HAVE_XAA_H if (!pApm->NoAccel) { ApmAccelInit(pScreen); /* set up XAA interface */ } #endif xf86SetBackingStore(pScreen); xf86SetSilkenMouse(pScreen); /* Initialise cursor functions */ miDCInitialize (pScreen, xf86GetPointerScreenFuncs()); /* Initialize HW cursor layer (after DGA and SW cursor) */ if (pApm->hwCursor) { if (!ApmHWCursorInit(pScreen)) xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Hardware cursor initialization failed\n"); } /* Initialise default colourmap */ if (!miCreateDefColormap(pScreen)) return FALSE; /* * Initialize colormap layer. * Must follow initialization of the default colormap. */ if (!xf86HandleColormaps(pScreen, 256, 8, ApmLoadPalette, NULL, CMAP_RELOAD_ON_MODE_SWITCH)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Colormap initialization failed\n"); return FALSE; } if (pApm->ShadowFB) ShadowFBInit(pScreen, ApmRefreshArea); xf86DPMSInit(pScreen, ApmDisplayPowerManagementSet, 0); ApmInitVideo(pScreen); pScreen->SaveScreen = ApmSaveScreen; pApm->CloseScreen = pScreen->CloseScreen; pScreen->CloseScreen = ApmCloseScreen; pScrn->memPhysBase = pApm->LinAddress; pScrn->fbOffset = (((char *)pApm->FbBase) - ((char *)pApm->LinMap)); /* Report any unused options (only for the first generation) */ if (serverGeneration == 1) { xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options); } #ifdef XF86RUSH if (ApmGeneration != serverGeneration) { if ((ApmPixmapIndex = AllocatePixmapPrivateIndex()) < 0) return FALSE; ApmGeneration = serverGeneration; } if (!AllocatePixmapPrivate(pScreen, ApmPixmapIndex, sizeof(ApmPixmapRec))) return FALSE; #endif /* Done */ return TRUE; } /* mandatory */ static void ApmLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO *colors, VisualPtr pVisual) { APMDECL(pScrn); int i, index, last = -1; if (pApm->VGAMap) { for (i = 0; i < numColors; i++) { index = indices[i]; if (index != last) ApmWriteDacWriteAddr(index); last = index + 1; ApmWriteDacData(colors[index].red); ApmWriteDacData(colors[index].green); ApmWriteDacData(colors[index].blue); } } else { for (i = 0; i < numColors; i++) { index = indices[i]; if (index != last) outb(pApm->iobase + 0x3C8, index); last = index + 1; outb(pApm->iobase + 0x3C9, colors[index].red); outb(pApm->iobase + 0x3C9, colors[index].green); outb(pApm->iobase + 0x3C9, colors[index].blue); } } } /* Usually mandatory */ Bool ApmSwitchMode(SWITCH_MODE_ARGS_DECL) { SCRN_INFO_PTR(arg); return ApmModeInit(pScrn, mode); } /* * This function is used to initialize the Start Address - the first * displayed location in the video memory. */ /* Usually mandatory */ void ApmAdjustFrame(ADJUST_FRAME_ARGS_DECL) { SCRN_INFO_PTR(arg); APMDECL(pScrn); int Base; if (pApm->CurrentLayout.bitsPerPixel == 24) x = (x + 3) & ~3; Base = ((y * pApm->CurrentLayout.displayWidth + x) * (pApm->CurrentLayout.bitsPerPixel / 8)) >> 2; /* * These are the generic starting address registers. */ if (pApm->VGAMap) { ApmWriteCrtc(0x0C, Base >> 8); ApmWriteCrtc(0x0D, Base); /* * Here the high-order bits are masked and shifted, and put into * the appropriate extended registers. */ ApmWriteCrtc(0x1C, (ApmReadCrtc(0x1C) & 0xF0) | ((Base & 0x0F0000) >> 16)); } else { outw(pApm->iobase + 0x3D4, (Base & 0x00FF00) | 0x0C); outw(pApm->iobase + 0x3D4, ((Base & 0x00FF) << 8) | 0x0D); /* * Here the high-order bits are masked and shifted, and put into * the appropriate extended registers. */ modinx(pApm->iobase + 0x3D4, 0x1C, 0x0F, (Base & 0x0F0000) >> 16); } } /* * This is called when VT switching back to the X server. Its job is * to reinitialise the video mode. * * We may wish to unmap video/MMIO memory too. */ /* Mandatory */ static Bool ApmEnterVT(VT_FUNC_ARGS_DECL) { SCRN_INFO_PTR(arg); APMDECL(pScrn); vgaHWPtr hwp = VGAHWPTR(pScrn); if (pApm->Chipset >= AT3D) { /* If you change it, change it also in apm_funcs.c */ WRXB(0xDB, (pApm->db & 0xF4) | 0x0A | pApm->Rush); WRXB(0xD9, (pApm->d9 & 0xCF) | 0x20); } if (pApm->Chipset >= AP6422) WRXB(0xC9, pApm->c9 | 0x10); ApmUnlock(APMPTR(pScrn)); vgaHWUnlock(hwp); /* * Set color mode */ hwp->writeMiscOut(hwp, pApm->MiscOut | 0x0F); if (!ApmModeInit(pScrn, pScrn->currentMode)) return FALSE; ApmAdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0)); return TRUE; } /* Mandatory */ static void ApmLeaveVT(VT_FUNC_ARGS_DECL) { SCRN_INFO_PTR(arg); APMDECL(pScrn); vgaHWPtr hwp = VGAHWPTR(pScrn); ApmRestore(pScrn, &hwp->SavedReg, &pApm->SavedReg); /* * Reset color mode */ (*hwp->writeMiscOut)(hwp, pApm->MiscOut); vgaHWLock(hwp); ApmLock(pApm); if (pApm->Chipset >= AT3D) { WRXB(0xD9, pApm->d9); WRXB(0xDB, pApm->db); } WRXB(0xC9, pApm->c9); #if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 12 if (xf86IsPc98()) outb(0xFAC, 0xFE); #endif } /* * This is called at the end of each server generation. It restores the * original (text) mode. It should really also unmap the video memory too. */ /* Mandatory */ static Bool ApmCloseScreen(CLOSE_SCREEN_ARGS_DECL) { ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); vgaHWPtr hwp = VGAHWPTR(pScrn); APMDECL(pScrn); if (pScrn->vtSema) { ApmRestore(pScrn, &hwp->SavedReg, &pApm->SavedReg); vgaHWLock(hwp); ApmUnmapMem(pScrn); } #ifdef HAVE_XAA_H if(pApm->AccelInfoRec) XAADestroyInfoRec(pApm->AccelInfoRec); if(pApm->DGAXAAInfo) XAADestroyInfoRec(pApm->DGAXAAInfo); pApm->AccelInfoRec = NULL; #endif if(pApm->CursorInfoRec) xf86DestroyCursorInfoRec(pApm->CursorInfoRec); pApm->CursorInfoRec = NULL; free(pApm->DGAModes); free(pApm->adaptor); pScrn->vtSema = FALSE; #if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 12 if (xf86IsPc98()) outb(0xFAC, 0xFE); #endif pScreen->CloseScreen = pApm->CloseScreen; return (*pScreen->CloseScreen)(CLOSE_SCREEN_ARGS); } /* Free up any per-generation data structures */ /* Optional */ static void ApmFreeScreen(FREE_SCREEN_ARGS_DECL) { SCRN_INFO_PTR(arg); vgaHWFreeHWRec(pScrn); ApmFreeRec(pScrn); } /* Checks if a mode is suitable for the selected chipset. */ /* Optional */ static ModeStatus ApmValidMode(SCRN_ARG_TYPE arg, DisplayModePtr mode, Bool verbose, int flags) { if (mode->Flags & V_INTERLACE) return(MODE_BAD); return(MODE_OK); } /* * ApmDisplayPowerManagementSet -- * * Sets VESA Display Power Management Signaling (DPMS) Mode. */ static void ApmDisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode, int flags) { APMDECL(pScrn); unsigned char dpmsreg, tmp; if (PowerManagementMode < sizeof pApm->DPMSMask && PowerManagementMode >= 0) PowerManagementMode = pApm->DPMSMask[PowerManagementMode]; switch (PowerManagementMode) { case DPMSModeOn: /* Screen: On; HSync: On, VSync: On */ dpmsreg = 0x00; break; case DPMSModeStandby: /* Screen: Off; HSync: Off, VSync: On */ dpmsreg = 0x01; break; case DPMSModeSuspend: /* Screen: Off; HSync: On, VSync: Off */ dpmsreg = 0x02; break; case DPMSModeOff: /* Screen: Off; HSync: Off, VSync: Off */ dpmsreg = 0x03; break; default: dpmsreg = 0; } tmp = RDXB(0xD0); WRXB(0xD0, (tmp & 0xFC) | dpmsreg); } static Bool ApmSaveScreen(ScreenPtr pScreen, int mode) { ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); Bool unblank; unblank = xf86IsUnblank(mode); if (unblank) SetTimeSinceLastInputEvent(); if (pScrn->vtSema) vgaHWBlankScreen(pScrn, unblank); return TRUE; } #ifdef APM_DEBUG unsigned char _L_ACR(unsigned char *x); unsigned char _L_ACR(unsigned char *x) { return *x; } unsigned short _L_ASR(unsigned short *x); unsigned short _L_ASR(unsigned short *x) { return *x; } unsigned int _L_AIR(unsigned int *x); unsigned int _L_AIR(unsigned int *x) { return *x; } void _L_ACW(char *x, char y); void _L_ACW(char *x, char y) { *x = y; } void _L_ASW(short *x, short y); void _L_ASW(short *x, short y) { *x = y; } void _L_AIW(int *x, int y); void _L_AIW(int *x, int y) { *x = y; } #endif