/* * Driver for CL-GD5480. * Itai Nahshon. * * Support for the CL-GD7548: David Monniaux * * This is mainly a cut & paste from the MGA driver. * Original autors and contributors list include: * Radoslaw Kapitan, Andrew Vanderstock, Dirk Hohndel, * David Dawes, Andrew E. Mileski, Leonard N. Zubkoff, * Guy DESBIEF */ /* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/cirrus/alp_driver.c,v 1.32 2003/08/23 16:09:16 dawes Exp $ */ /* All drivers should typically include these */ #include "xf86.h" #include "xf86_OSproc.h" /* All drivers need this */ #include "xf86_ansic.h" /* Everything using inb/outb, etc needs "compiler.h" */ #include "compiler.h" /* Drivers for PCI hardware need this */ #include "xf86PciInfo.h" /* Drivers that need to access the PCI config space directly need this */ #include "xf86Pci.h" /* All drivers using the vgahw module need this */ /* This driver needs to be modified to not use vgaHW for multihead operation */ #include "vgaHW.h" #include "xf86RAC.h" #include "xf86Resources.h" /* All drivers initialising the SW cursor need this */ #include "mipointer.h" /* All drivers implementing backing store need this */ #include "mibstore.h" #include "micmap.h" /* Needed by the Shadow Framebuffer */ #include "shadowfb.h" /* Note: can HWCUR64 be set even though the hw cursor is disabled for want of memory ? */ /* Framebuffer memory manager */ #include "xf86fbman.h" #include "xf4bpp.h" #include "xf1bpp.h" #include "fb.h" #include "xf86DDC.h" #include "xf86int10.h" #include "cir.h" #define _ALP_PRIVATE_ #include "alp.h" #include "xf86xv.h" #include "Xv.h" #ifdef ALPPROBEI2C /* For debugging... should go away. */ static void AlpProbeI2C(int scrnIndex); #endif /* * Forward definitions for the functions that make up the driver. */ /* Mandatory functions */ Bool AlpPreInit(ScrnInfoPtr pScrn, int flags); Bool AlpScreenInit(int Index, ScreenPtr pScreen, int argc, char **argv); Bool AlpEnterVT(int scrnIndex, int flags); void AlpLeaveVT(int scrnIndex, int flags); static Bool AlpCloseScreen(int scrnIndex, ScreenPtr pScreen); static Bool AlpSaveScreen(ScreenPtr pScreen, int mode); /* Required if the driver supports mode switching */ Bool AlpSwitchMode(int scrnIndex, DisplayModePtr mode, int flags); /* Required if the driver supports moving the viewport */ void AlpAdjustFrame(int scrnIndex, int x, int y, int flags); /* Optional functions */ void AlpFreeScreen(int scrnIndex, int flags); int AlpValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags); /* Internally used functions */ static void AlpSave(ScrnInfoPtr pScrn); static void AlpRestore(ScrnInfoPtr pScrn); static Bool AlpModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode); static void AlpProbeLCD(ScrnInfoPtr pScrn); static void AlpSetClock(CirPtr pCir, vgaHWPtr hwp, int freq); static void AlpOffscreenAccelInit(ScrnInfoPtr pScrn); static void AlpDisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode, int flags); /* * This is intentionally screen-independent. It indicates the binding * choice made in the first PreInit. */ static int pix24bpp = 0; typedef enum { OPTION_HW_CURSOR, OPTION_PCI_RETRY, OPTION_NOACCEL, OPTION_MMIO, OPTION_ROTATE, OPTION_SHADOW_FB, OPTION_MEMCFG1, OPTION_MEMCFG2 } CirOpts; static const OptionInfoRec CirOptions[] = { { OPTION_HW_CURSOR, "HWcursor", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_MMIO, "MMIO", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_SHADOW_FB, "ShadowFB", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_ROTATE, "Rotate", OPTV_ANYSTR, {0}, FALSE }, { OPTION_MEMCFG1, "MemCFG1", OPTV_INTEGER, {0}, -1 }, { OPTION_MEMCFG2, "MemCFG2", OPTV_INTEGER, {0}, -1 }, { -1, NULL, OPTV_NONE, {0}, FALSE } }; /* 1/4bpp 8bpp 15/16bpp 24bpp 32bpp static int unsupp_MaxClocks[] = { 0, 0, 0, 0, 0 }; */ static int gd5430_MaxClocks[] = { 85500, 85500, 50000, 28500, 0 }; static int gd5446_MaxClocks[] = { 135100, 135100, 85500, 85500, 0 }; static int gd5480_MaxClocks[] = { 135100, 200000, 200000, 135100, 135100 }; static int gd7548_MaxClocks[] = { 80100, 80100, 80100, 80100, 80100 }; /* * List of symbols from other modules that this module references. This * list is used to tell the loader that it is OK for symbols here to be * unresolved providing that it hasn't been told that they haven't been * told that they are essential via a call to xf86LoaderReqSymbols() or * xf86LoaderReqSymLists(). The purpose is this is to avoid warnings about * unresolved symbols that are not required. */ static const char *vgahwSymbols[] = { "vgaHWFreeHWRec", "vgaHWGetHWRec", "vgaHWGetIOBase", "vgaHWGetIndex", "vgaHWHandleColormaps", "vgaHWInit", "vgaHWLock", "vgaHWMapMem", "vgaHWProtect", "vgaHWRestore", "vgaHWSave", "vgaHWSaveScreen", "vgaHWSetMmioFuncs", "vgaHWSetStdFuncs", "vgaHWUnlock", NULL }; #ifdef XFree86LOADER static const char *miscfbSymbols[] = { "xf1bppScreenInit", "xf4bppScreenInit", NULL }; #endif static const char *fbSymbols[] = { "fbScreenInit", "fbPictureInit", NULL }; static const char *xaaSymbols[] = { "XAACreateInfoRec", "XAADestroyInfoRec", "XAAInit", NULL }; static const char *ramdacSymbols[] = { "xf86CreateCursorInfoRec", "xf86DestroyCursorInfoRec", "xf86InitCursor", NULL }; static const char *int10Symbols[] = { "xf86FreeInt10", "xf86InitInt10", NULL }; static const char *shadowSymbols[] = { "ShadowFBInit", NULL }; static const char *ddcSymbols[] = { "xf86PrintEDID", "xf86DoEDID_DDC2", "xf86SetDDCproperties", NULL }; static const char *i2cSymbols[] = { "xf86CreateI2CBusRec", "xf86I2CBusInit", NULL }; #ifdef XFree86LOADER #define ALP_MAJOR_VERSION 1 #define ALP_MINOR_VERSION 0 #define ALP_PATCHLEVEL 0 static MODULESETUPPROTO(alpSetup); static XF86ModuleVersionInfo alpVersRec = { "cirrus_alpine", MODULEVENDORSTRING, MODINFOSTRING1, MODINFOSTRING2, XF86_VERSION_CURRENT, ALP_MAJOR_VERSION, ALP_MINOR_VERSION, ALP_PATCHLEVEL, ABI_CLASS_VIDEODRV, /* This is a video driver */ ABI_VIDEODRV_VERSION, MOD_CLASS_NONE, {0,0,0,0} }; /* * This is the module init data. * Its name has to be the driver name followed by ModuleData. */ XF86ModuleData cirrus_alpineModuleData = { &alpVersRec, alpSetup, NULL }; static pointer alpSetup(pointer module, pointer opts, int *errmaj, int *errmin) { static Bool setupDone = FALSE; if (!setupDone) { setupDone = TRUE; LoaderRefSymLists(vgahwSymbols, fbSymbols, xaaSymbols, miscfbSymbols, ramdacSymbols,int10Symbols, ddcSymbols, i2cSymbols, shadowSymbols, NULL); } return (pointer)1; } #endif /* XFree86LOADER */ const OptionInfoRec * AlpAvailableOptions(int chipid) { return CirOptions; } ScrnInfoPtr AlpProbe(int entity) { ScrnInfoPtr pScrn = NULL; if ((pScrn = xf86ConfigPciEntity(pScrn, 0, entity, CIRPciChipsets, NULL,NULL, NULL, NULL, NULL))) { pScrn->PreInit = AlpPreInit; pScrn->ScreenInit = AlpScreenInit; pScrn->SwitchMode = AlpSwitchMode; pScrn->AdjustFrame = AlpAdjustFrame; pScrn->EnterVT = AlpEnterVT; pScrn->LeaveVT = AlpLeaveVT; pScrn->FreeScreen = AlpFreeScreen; pScrn->ValidMode = AlpValidMode; } return pScrn; } static Bool AlpGetRec(ScrnInfoPtr pScrn) { #ifdef ALP_DEBUG ErrorF("AlpGetRec\n"); #endif if (pScrn->driverPrivate != NULL) return TRUE; pScrn->driverPrivate = xnfcalloc(sizeof(CirRec), 1); ((CirPtr)pScrn->driverPrivate)->chip.alp = xnfcalloc(sizeof(AlpRec),1); #ifdef ALP_DEBUG ErrorF("AlpGetRec 0x%x\n", CIRPTR(pScrn)); #endif return TRUE; } static void AlpFreeRec(ScrnInfoPtr pScrn) { if (pScrn->driverPrivate == NULL) return; xfree(pScrn->driverPrivate); pScrn->driverPrivate = NULL; } /* * AlpCountRAM -- * * Counts amount of installed RAM * * XXX Can use options to configure memory on non-primary cards. */ static int AlpCountRam(ScrnInfoPtr pScrn) { CirPtr pCir = CIRPTR(pScrn); vgaHWPtr hwp = VGAHWPTR(pScrn); MessageType from; int videoram = 0; /* Map the Alp memory and MMIO areas */ pCir->FbMapSize = 1024*1024; /* XX temp */ pCir->IoMapSize = 0x4000; /* 16K for moment */ if (!CirMapMem(pCir, pScrn->scrnIndex)) return 0; /* The 754x supports MMIO for the BitBlt engine but not for the VGA registers */ switch (pCir->Chipset) { case PCI_CHIP_GD7548: break; default: if (pCir->UseMMIO) vgaHWSetMmioFuncs(hwp, pCir->IOBase, -0x3C0); } if (pCir->chip.alp->sr0f != (CARD32)-1) { from = X_CONFIG; hwp->writeSeq(hwp, 0x0F, pCir->chip.alp->sr0f); } else { from = X_PROBED; pCir->chip.alp->sr0f = hwp->readSeq(hwp, 0x0F); } xf86DrvMsg(pScrn->scrnIndex, from, "Memory Config reg 1 is 0x%02X\n", pCir->chip.alp->sr0f); switch (pCir->Chipset) { case PCI_CHIP_GD5430: /* case PCI_CHIP_GD5440: */ switch (pCir->chip.alp->sr0f & 0x18) { case 0x08: videoram = 512; break; case 0x10: videoram = 1024; break; case 0x18: videoram = 2048; break; } break; case PCI_CHIP_GD5434_4: case PCI_CHIP_GD5434_8: case PCI_CHIP_GD5436: switch (pCir->chip.alp->sr0f & 0x18) { case 0x10: videoram = 1024; break; case 0x18: videoram = 2048; if (pCir->chip.alp->sr0f & 0x80) videoram = 4096; break; } case PCI_CHIP_GD5446: videoram = 1024; if (pCir->chip.alp->sr17 != (CARD32)-1) { from = X_CONFIG; hwp->writeSeq(hwp, 0x17, pCir->chip.alp->sr17); } else { from = X_PROBED; pCir->chip.alp->sr17 = hwp->readSeq(hwp, 0x17); } xf86DrvMsg(pScrn->scrnIndex, from, "Memory Config reg 2 is 0x%02X\n", pCir->chip.alp->sr17); if ((pCir->chip.alp->sr0f & 0x18) == 0x18) { if (pCir->chip.alp->sr0f & 0x80) { if (pCir->chip.alp->sr17 & 0x80) videoram = 2048; else if (pCir->chip.alp->sr17 & 0x02) videoram = 3072; else videoram = 4096; } else { if ((pCir->chip.alp->sr17 & 80) == 0) videoram = 2048; } } break; case PCI_CHIP_GD5480: if (pCir->chip.alp->sr17 != (CARD32)-1) { from = X_CONFIG; hwp->writeSeq(hwp, 0x17, pCir->chip.alp->sr17); } else { from = X_PROBED; pCir->chip.alp->sr17 = hwp->readSeq(hwp, 0x17); } xf86DrvMsg(pScrn->scrnIndex, from, "Memory Config reg 2 is 0x%02X\n", pCir->chip.alp->sr17); videoram = 1024; if ((pCir->chip.alp->sr0f & 0x18) == 0x18) { /* 2 or 4 MB */ videoram = 2048; if (pCir->chip.alp->sr0f & 0x80) /* Second bank enable */ videoram = 4096; } if (pCir->chip.alp->sr17 & 0x80) videoram <<= 1; break; case PCI_CHIP_GD7548: videoram = 1024; switch (pCir->chip.alp->sr0f & 0x90) { case 0x10: /* TODO: 2 256K X 16 DRAMs (1024) or 4 512K X 8 DRAMs (2048)? */ break; case 0x90: videoram <<= 1; break; } break; } /* UNMap the Alp memory and MMIO areas */ if (!CirUnmapMem(pCir, pScrn->scrnIndex)) return 0; vgaHWSetStdFuncs(hwp); return videoram; } /* * 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 i, n = 0; CirPtr pCir = CIRPTR(pScrn); /* XXX ajv - 512, 576, and 1536 may not be supported line pitches. see sdk pp 4-59 for more details. Why anyone would want less than 640 is bizarre. (maybe lots of pixels tall?) */ /* The only line pitches the accelerator supports */ #if 1 int accelWidths[] = { 640, 768, 800, 960, 1024, 1152, 1280, 1600, 1920, 2048, 0 }; #else int accelWidths[] = { 512, 576, 640, 768, 800, 960, 1024, 1152, 1280, 1536, 1600, 1920, 2048, 0 }; #endif for (i = 0; accelWidths[i] != 0; i++) { if (accelWidths[i] % pCir->Rounding == 0) { n++; linePitches = xnfrealloc(linePitches, n * sizeof(int)); linePitches[n - 1] = accelWidths[i]; } } /* Mark the end of the list */ if (n > 0) { linePitches = xnfrealloc(linePitches, (n + 1) * sizeof(int)); linePitches[n] = 0; } return linePitches; } /* Mandatory */ Bool AlpPreInit(ScrnInfoPtr pScrn, int flags) { CirPtr pCir; vgaHWPtr hwp; MessageType from, from1; int i; ClockRangePtr clockRanges; char *s; xf86Int10InfoPtr pInt = NULL; if (flags & PROBE_DETECT) { cirProbeDDC( pScrn, xf86GetEntityInfo(pScrn->entityList[0])->index ); return TRUE; } #ifdef ALP_DEBUG ErrorF("AlpPreInit\n"); #endif /* Check the number of entities, and fail if it isn't one. */ if (pScrn->numEntities != 1) return FALSE; if (!xf86LoadSubModule(pScrn, "vgahw")) return FALSE; xf86LoaderReqSymLists(vgahwSymbols, NULL); /* * Allocate a vgaHWRec */ if (!vgaHWGetHWRec(pScrn)) return FALSE; hwp = VGAHWPTR(pScrn); vgaHWGetIOBase(hwp); /* Allocate the AlpRec driverPrivate */ if (!AlpGetRec(pScrn)) return FALSE; pCir = CIRPTR(pScrn); pCir->pScrn = pScrn; pCir->PIOReg = hwp->PIOOffset + 0x3CE; /* Get the entity, and make sure it is PCI. */ pCir->pEnt = xf86GetEntityInfo(pScrn->entityList[0]); if (pCir->pEnt->location.type != BUS_PCI) { xfree(pCir->pEnt); return FALSE; } pCir->Chipset = pCir->pEnt->chipset; /* Find the PCI info for this screen */ pCir->PciInfo = xf86GetPciInfoForEntity(pCir->pEnt->index); pCir->PciTag = pciTag(pCir->PciInfo->bus, pCir->PciInfo->device, pCir->PciInfo->func); if (xf86LoadSubModule(pScrn, "int10")) { xf86LoaderReqSymLists(int10Symbols,NULL); xf86DrvMsg(pScrn->scrnIndex,X_INFO,"initializing int10\n"); pInt = xf86InitInt10(pCir->pEnt->index); xf86FreeInt10(pInt); /* * This is a hack: We restore the PCI base regs as some Colorgraphic * BIOSes tend to mess them up */ pciWriteLong(pCir->PciTag,0x10,pCir->PciInfo->memBase[0]); pciWriteLong(pCir->PciTag,0x14,pCir->PciInfo->memBase[1]); } /* Set pScrn->monitor */ pScrn->monitor = pScrn->confScreen->monitor; /* * The first thing we should figure out is the depth, bpp, etc. * We support both 24bpp and 32bpp layouts, so indicate that. */ if (!xf86SetDepthBpp(pScrn, 0, 0, 0, Support24bppFb | Support32bppFb | SupportConvert32to24 | PreferConvert32to24)) { return FALSE; } else { /* Check that the returned depth is one we support */ switch (pScrn->depth) { case 1: 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); /* 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)) { return FALSE; } else { /* XXX check that weight returned is supported */ ; } } if (!xf86SetDefaultVisual(pScrn, -1)) { return FALSE; } /* Collect all of the relevant option flags (fill in pScrn->options) */ xf86CollectOptions(pScrn, NULL); /* Process the options */ if (!(pCir->Options = xalloc(sizeof(CirOptions)))) return FALSE; memcpy(pCir->Options, CirOptions, sizeof(CirOptions)); xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pCir->Options); if (!xf86IsPrimaryPci(pCir->PciInfo) && !(pInt || (xf86IsOptionSet(pCir->Options,OPTION_MEMCFG1) && xf86IsOptionSet(pCir->Options,OPTION_MEMCFG2)))) return FALSE; if (pScrn->depth == 8) pScrn->rgbBits = 6; from = X_DEFAULT; pCir->HWCursor = FALSE; if (xf86GetOptValBool(pCir->Options, OPTION_HW_CURSOR, &pCir->HWCursor)) from = X_CONFIG; xf86DrvMsg(pScrn->scrnIndex, from, "Using %s cursor\n", pCir->HWCursor ? "HW" : "SW"); if (xf86ReturnOptValBool(pCir->Options, OPTION_NOACCEL, FALSE)) { pCir->NoAccel = TRUE; xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Acceleration disabled\n"); } if(pScrn->bitsPerPixel < 8) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Cannot use accelerations in less than 8 bpp\n"); pCir->NoAccel = TRUE; } /* * Set the ChipRev, allowing config file entries to * override. */ if (pCir->pEnt->device->chipRev >= 0) { pCir->ChipRev = pCir->pEnt->device->chipRev; xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n", pCir->ChipRev); } else { pCir->ChipRev = pCir->PciInfo->chipRev; } /* Find the frame buffer base address */ if (pCir->pEnt->device->MemBase != 0) { if (!xf86CheckPciMemBase(pCir->PciInfo, pCir->pEnt->device->MemBase)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "MemBase 0x%08lX doesn't match any PCI base register.\n", pCir->pEnt->device->MemBase); return FALSE; } pCir->FbAddress = pCir->pEnt->device->MemBase; from = X_CONFIG; } else { if (pCir->PciInfo->memBase[0] != 0) { /* 5446B and 5480 use mask of 0xfe000000. 5446A uses 0xff000000. */ pCir->FbAddress = pCir->PciInfo->memBase[0] & 0xff000000; from = X_PROBED; } else { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid FB address in PCI config space\n"); AlpFreeRec(pScrn); return FALSE; } } xf86DrvMsg(pScrn->scrnIndex, from, "Linear framebuffer at 0x%lX\n", (unsigned long)pCir->FbAddress); if (pCir->pEnt->device->IOBase != 0) { /* Require that the config file value matches one of the PCI values. */ if (!xf86CheckPciMemBase(pCir->PciInfo, pCir->pEnt->device->IOBase)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "IOBase 0x%08lX doesn't match any PCI base register.\n", pCir->pEnt->device->IOBase); return FALSE; } pCir->IOAddress = pCir->pEnt->device->IOBase; from = X_CONFIG; } else { if (pCir->PciInfo->memBase[1] != 0) { pCir->IOAddress = pCir->PciInfo->memBase[1] & 0xfffff000; from = X_PROBED; } else { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid MMIO address in PCI config space\n"); /* 5446 rev A do not use a separate MMIO segment */ /* We do not really need that YET. */ } } /* User options can override the MMIO default */ #if 0 /* Will we ever support MMIO on 5446A or older? */ if (xf86ReturnOptValBool(pCir->Options, OPTION_MMIO, FALSE)) { pCir->UseMMIO = TRUE; from = X_CONFIG; } #endif if (!xf86ReturnOptValBool(pCir->Options, OPTION_MMIO, TRUE)) { pCir->UseMMIO = FALSE; from1 = X_CONFIG; } else if (pCir->IOAddress) { /* Default to MMIO if we have a separate IOAddress and not in monochrome mode (IO 0x3Bx is not relocated!) */ if (pScrn->bitsPerPixel != 1) { pCir->UseMMIO = TRUE; from1 = X_PROBED; } else { pCir->UseMMIO = FALSE; from1 = X_PROBED; } } else { pCir->UseMMIO = FALSE; from1 = X_PROBED; } if (pCir->UseMMIO) { xf86DrvMsg(pScrn->scrnIndex, from1, "Using MMIO\n"); xf86DrvMsg(pScrn->scrnIndex, from, "MMIO registers at 0x%lX\n", (unsigned long)pCir->IOAddress); } else xf86DrvMsg(pScrn->scrnIndex, from1, "Not Using MMIO\n"); /* * XXX Check if this is correct */ if (!pCir->UseMMIO) { pScrn->racIoFlags = RAC_COLORMAP | RAC_CURSOR | RAC_VIEWPORT | RAC_FB; xf86SetOperatingState(resVgaMem, pCir->pEnt->index, ResUnusedOpr); } else { xf86SetOperatingState(resVga, pCir->pEnt->index, ResUnusedOpr); } /* Register the PCI-assigned resources. */ if (xf86RegisterResources(pCir->pEnt->index, NULL, ResExclusive)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "xf86RegisterResources() found resource conflicts\n"); return FALSE; } if (!xf86LoadSubModule(pScrn, "i2c")) { AlpFreeRec(pScrn); return FALSE; } xf86LoaderReqSymLists(i2cSymbols,NULL); if (!xf86LoadSubModule(pScrn, "ddc")) { AlpFreeRec(pScrn); return FALSE; } xf86LoaderReqSymLists(ddcSymbols, NULL); if(!AlpI2CInit(pScrn)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "I2C initialization failed\n"); } else xf86SetDDCproperties(pScrn,xf86PrintEDID( xf86DoEDID_DDC2(pScrn->scrnIndex,pCir->I2CPtr1))); /* Probe the possible LCD display */ AlpProbeLCD(pScrn); #ifdef CIRPROBEI2C CirProbeI2C(pScrn->scrnIndex); #endif /* 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; } /* XXX If UseMMIO == TRUE and for any reason we cannot do MMIO, abort here */ if (xf86GetOptValBool(pCir->Options, OPTION_SHADOW_FB,&pCir->shadowFB)) xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ShadowFB %s.\n", pCir->shadowFB ? "enabled" : "disabled"); if ((s = xf86GetOptValString(pCir->Options, OPTION_ROTATE))) { if(!xf86NameCmp(s, "CW")) { /* accel is disabled below for shadowFB */ pCir->shadowFB = TRUE; pCir->rotate = 1; xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Rotating screen clockwise - acceleration disabled\n"); } else if(!xf86NameCmp(s, "CCW")) { pCir->shadowFB = TRUE; pCir->rotate = -1; xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Rotating screen" "counter clockwise - acceleration disabled\n"); } else { xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "\"%s\" is not a valid" "value for Option \"Rotate\"\n", s); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Valid options are \"CW\" or \"CCW\"\n"); } } if (pCir->shadowFB && (pScrn->depth < 8)) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "shadowFB not supported at this depth.\n"); pCir->shadowFB = FALSE; pCir->rotate = 0; } if (pCir->shadowFB && !pCir->NoAccel) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "HW acceleration not supported with \"shadowFB\".\n"); pCir->NoAccel = TRUE; } if (pCir->rotate && pCir->HWCursor) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "HW cursor not supported with \"rotate\".\n"); pCir->HWCursor = FALSE; } /* XXX We do not know yet how to configure memory on this card. Use options MemCFG1 and MemCFG2 to set registers SR0F and SR17 before trying to count ram size. */ pCir->chip.alp->sr0f = (CARD32)-1; pCir->chip.alp->sr17 = (CARD32)-1; (void) xf86GetOptValULong(pCir->Options, OPTION_MEMCFG1, (unsigned long *)&pCir->chip.alp->sr0f); (void) xf86GetOptValULong(pCir->Options, OPTION_MEMCFG2, (unsigned long *)&pCir->chip.alp->sr17); /* * If the user has specified the amount of memory in the XF86Config * file, we respect that setting. */ if (pCir->pEnt->device->videoRam != 0) { pScrn->videoRam = pCir->pEnt->device->videoRam; pCir->IoMapSize = 0x4000; /* 16K for moment */ from = X_CONFIG; } else { pScrn->videoRam = AlpCountRam(pScrn); from = X_PROBED; } xf86DrvMsg(pScrn->scrnIndex, from, "VideoRAM: %d kByte\n", pScrn->videoRam); pCir->FbMapSize = pScrn->videoRam * 1024; /* properties */ pCir->properties = 0; if ((pCir->chip.alp->sr0f & 0x18) > 0x8) pCir->properties |= HWCUR64; switch (pCir->Chipset) { case PCI_CHIP_GD7548: pCir->properties |= HWCUR64; pCir->properties |= ACCEL_AUTOSTART; break; case PCI_CHIP_GD5436: case PCI_CHIP_GD5480: pCir->properties |= ACCEL_AUTOSTART; break; default: break; } /* We use a programmable clock */ pScrn->progClock = TRUE; /* XXX Set HW cursor use */ /* Set the min pixel clock */ pCir->MinClock = 12000; /* XXX Guess, need to check this */ xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "Min pixel clock is %d MHz\n", pCir->MinClock / 1000); /* * If the user has specified ramdac speed in the XF86Config * file, we respect that setting. */ if (pCir->pEnt->device->dacSpeeds[0]) { ErrorF("Do not specily a Clocks line for Cirrus chips\n"); return FALSE; } else { int speed; int *p = NULL; switch (pCir->Chipset) { case PCI_CHIP_GD5430: case PCI_CHIP_GD5434_4: case PCI_CHIP_GD5434_8: case PCI_CHIP_GD5436: /* case PCI_CHIP_GD5440: */ p = gd5430_MaxClocks; break; case PCI_CHIP_GD5446: p = gd5446_MaxClocks; break; case PCI_CHIP_GD5480: p = gd5480_MaxClocks; break; case PCI_CHIP_GD7548: p = gd7548_MaxClocks; break; } if (!p) return FALSE; switch(pScrn->bitsPerPixel) { case 1: case 4: speed = p[0]; break; case 8: speed = p[1]; break; case 15: case 16: speed = p[2]; break; case 24: speed = p[3]; break; case 32: speed = p[4]; break; default: /* Should not get here */ speed = 0; break; } pCir->MaxClock = speed; from = X_PROBED; } xf86DrvMsg(pScrn->scrnIndex, from, "Max pixel clock is %d MHz\n", pCir->MaxClock / 1000); /* * Setup the ClockRanges, which describe what clock ranges are available, * and what sort of modes they can be used for. */ clockRanges = xnfcalloc(sizeof(ClockRange), 1); clockRanges->next = NULL; clockRanges->minClock = pCir->MinClock; clockRanges->maxClock = pCir->MaxClock; clockRanges->clockIndex = -1; /* programmable */ clockRanges->interlaceAllowed = FALSE; /* XXX check this */ clockRanges->doubleScanAllowed = FALSE; /* XXX check this */ clockRanges->doubleScanAllowed = FALSE; /* XXX check this */ clockRanges->doubleScanAllowed = FALSE; /* XXX check this */ clockRanges->ClockMulFactor = 1; clockRanges->ClockDivFactor = 1; clockRanges->PrivFlags = 0; switch (pCir->Chipset) { case PCI_CHIP_GD7548: pCir->Rounding = 1; break; default: pCir->Rounding = 128 >> pCir->BppShift; } #if 0 if (pCir->Chipset != PCI_CHIP_GD5446 && pCir->Chipset != PCI_CHIP_GD5480) { /* XXX Kludge */ pCir->NoAccel = TRUE; } #endif /* * xf86ValidateModes will check that the mode HTotal and VTotal values * don't exceed the chipset's limit if pScrn->maxHValue and * pScrn->maxVValue are set. Since our AlpValidMode() already takes * care of this, we don't worry about setting them here. */ /* Select valid modes from those available */ if (pCir->NoAccel) { /* * XXX Assuming min pitch 256, max 2048 * XXX Assuming min height 128, max 2048 */ i = xf86ValidateModes(pScrn, pScrn->monitor->Modes, pScrn->display->modes, clockRanges, NULL, 256, 2048, pCir->Rounding * pScrn->bitsPerPixel, 128, 2048, pScrn->display->virtualX, pScrn->display->virtualY, pCir->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, pCir->Rounding * pScrn->bitsPerPixel, 128, 2048, pScrn->display->virtualX, pScrn->display->virtualY, pCir->FbMapSize, LOOKUP_BEST_REFRESH); } if (i == -1) { AlpFreeRec(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"); AlpFreeRec(pScrn); return FALSE; } /* * Set the CRTC parameters for all of the modes based on the type * of mode, and the chipset's interlace requirements. * * Calling this is required if the mode->Crtc* values are used by the * driver and if the driver doesn't provide code to set them. They * are not pre-initialised at all. */ 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 1: if (xf86LoadSubModule(pScrn, "xf1bpp") == NULL) { AlpFreeRec(pScrn); return FALSE; } xf86LoaderReqSymbols("xf1bppScreenInit",NULL); break; case 4: if (xf86LoadSubModule(pScrn, "xf4bpp") == NULL) { AlpFreeRec(pScrn); return FALSE; } xf86LoaderReqSymbols("xf4bppScreenInit",NULL); break; case 8: case 16: case 24: case 32: if (xf86LoadSubModule(pScrn, "fb") == NULL) { AlpFreeRec(pScrn); return FALSE; } xf86LoaderReqSymLists(fbSymbols, NULL); break; } /* Load XAA if needed */ if (!pCir->NoAccel) { if (!xf86LoadSubModule(pScrn, "xaa")) { AlpFreeRec(pScrn); return FALSE; } xf86LoaderReqSymLists(xaaSymbols, NULL); } /* Load ramdac if needed */ if (pCir->HWCursor) { if (!xf86LoadSubModule(pScrn, "ramdac")) { AlpFreeRec(pScrn); return FALSE; } xf86LoaderReqSymLists(ramdacSymbols, NULL); } if (pCir->shadowFB) { if (!xf86LoadSubModule(pScrn, "shadowfb")) { AlpFreeRec(pScrn); return FALSE; } xf86LoaderReqSymLists(shadowSymbols, NULL); } return TRUE; } /* * This function saves the video state. */ static void AlpSave(ScrnInfoPtr pScrn) { CirPtr pCir = CIRPTR(pScrn); vgaHWPtr hwp = VGAHWPTR(pScrn); #ifdef ALP_DEBUG ErrorF("AlpSave\n"); #endif vgaHWSave(pScrn, &VGAHWPTR(pScrn)->SavedReg, VGA_SR_ALL); pCir->chip.alp->ModeReg.ExtVga[CR1A] = pCir->chip.alp->SavedReg.ExtVga[CR1A] = hwp->readCrtc(hwp, 0x1A); pCir->chip.alp->ModeReg.ExtVga[CR1B] = pCir->chip.alp->SavedReg.ExtVga[CR1B] = hwp->readCrtc(hwp, 0x1B); pCir->chip.alp->ModeReg.ExtVga[CR1D] = pCir->chip.alp->SavedReg.ExtVga[CR1D] = hwp->readCrtc(hwp, 0x1D); pCir->chip.alp->ModeReg.ExtVga[SR07] = pCir->chip.alp->SavedReg.ExtVga[SR07] = hwp->readSeq(hwp, 0x07); pCir->chip.alp->ModeReg.ExtVga[SR0E] = pCir->chip.alp->SavedReg.ExtVga[SR0E] = hwp->readSeq(hwp, 0x0E); pCir->chip.alp->ModeReg.ExtVga[SR12] = pCir->chip.alp->SavedReg.ExtVga[SR12] = hwp->readSeq(hwp, 0x12); pCir->chip.alp->ModeReg.ExtVga[SR13] = pCir->chip.alp->SavedReg.ExtVga[SR13] = hwp->readSeq(hwp, 0x13); pCir->chip.alp->ModeReg.ExtVga[SR17] = pCir->chip.alp->SavedReg.ExtVga[SR17] = hwp->readSeq(hwp, 0x17); pCir->chip.alp->ModeReg.ExtVga[SR1E] = pCir->chip.alp->SavedReg.ExtVga[SR1E] = hwp->readSeq(hwp, 0x1E); pCir->chip.alp->ModeReg.ExtVga[SR21] = pCir->chip.alp->SavedReg.ExtVga[SR21] = hwp->readSeq(hwp, 0x21); pCir->chip.alp->ModeReg.ExtVga[SR2D] = pCir->chip.alp->SavedReg.ExtVga[SR2D] = hwp->readSeq(hwp, 0x2D); pCir->chip.alp->ModeReg.ExtVga[GR17] = pCir->chip.alp->SavedReg.ExtVga[GR17] = hwp->readGr(hwp, 0x17); pCir->chip.alp->ModeReg.ExtVga[GR18] = pCir->chip.alp->SavedReg.ExtVga[GR18] = hwp->readGr(hwp, 0x18); /* The first 4 reads are for the pixel mask register. After 4 times that this register is accessed in succession reading/writing this address accesses the HDR. */ hwp->readDacMask(hwp); hwp->readDacMask(hwp); hwp->readDacMask(hwp); hwp->readDacMask(hwp); pCir->chip.alp->ModeReg.ExtVga[HDR] = pCir->chip.alp->SavedReg.ExtVga[HDR] = hwp->readDacMask(hwp); } /* XXX */ static void AlpFix1bppColorMap(ScrnInfoPtr pScrn) { vgaHWPtr hwp = VGAHWPTR(pScrn); /* In 1 bpp we have color 0 at LUT 0 and color 1 at LUT 0x3f. This makes white and black look right (otherwise they were both black. I'm sure there's a better way to do that, just lazy to search the docs. */ hwp->writeDacWriteAddr(hwp, 0x00); hwp->writeDacData(hwp, 0x00); hwp->writeDacData(hwp, 0x00); hwp->writeDacData(hwp, 0x00); hwp->writeDacWriteAddr(hwp, 0x3F); hwp->writeDacData(hwp, 0x3F); hwp->writeDacData(hwp, 0x3F); hwp->writeDacData(hwp, 0x3F); } static void alpRestore(vgaHWPtr hwp, AlpRegPtr cirReg) { hwp->writeCrtc(hwp, 0x1A, cirReg->ExtVga[CR1A]); hwp->writeCrtc(hwp, 0x1B, cirReg->ExtVga[CR1B]); hwp->writeCrtc(hwp, 0x1D, cirReg->ExtVga[CR1D]); hwp->writeSeq(hwp, 0x07, cirReg->ExtVga[SR07]); hwp->writeSeq(hwp, 0x0E, cirReg->ExtVga[SR0E]); hwp->writeSeq(hwp, 0x12, cirReg->ExtVga[SR12]); hwp->writeSeq(hwp, 0x13, cirReg->ExtVga[SR13]); hwp->writeSeq(hwp, 0x17, cirReg->ExtVga[SR17]); hwp->writeSeq(hwp, 0x1E, cirReg->ExtVga[SR1E]); hwp->writeSeq(hwp, 0x21, cirReg->ExtVga[SR21]); hwp->writeSeq(hwp, 0x2D, cirReg->ExtVga[SR2D]); hwp->writeGr(hwp, 0x17, cirReg->ExtVga[GR17]); hwp->writeGr(hwp, 0x18, cirReg->ExtVga[GR18]); /* The first 4 reads are for the pixel mask register. After 4 times that this register is accessed in succession reading/writing this address accesses the HDR. */ hwp->readDacMask(hwp); hwp->readDacMask(hwp); hwp->readDacMask(hwp); hwp->readDacMask(hwp); hwp->writeDacMask(hwp, cirReg->ExtVga[HDR ]); } /* * Initialise a new mode. This is currently still using the old * "initialise struct, restore/write struct to HW" model. That could * be changed. * Why?? (EE) */ static Bool AlpModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode) { vgaHWPtr hwp; vgaRegPtr vgaReg; CirPtr pCir; int depthcode; int width; Bool HDiv2 = FALSE, VDiv2 = FALSE; #ifdef ALP_DEBUG ErrorF("AlpModeInit %d bpp, %d %d %d %d %d %d %d %d %d\n", pScrn->bitsPerPixel, mode->Clock, mode->HDisplay, mode->HSyncStart, mode->HSyncEnd, mode->HTotal, mode->VDisplay, mode->VSyncStart, mode->VSyncEnd, mode->VTotal); ErrorF("AlpModeInit: depth %d bits\n", pScrn->depth); #endif pCir = CIRPTR(pScrn); hwp = VGAHWPTR(pScrn); vgaHWUnlock(hwp); pCir->pitch = pScrn->displayWidth * pScrn->bitsPerPixel >> 3; depthcode = pScrn->depth; if (pScrn->bitsPerPixel == 32) depthcode = 32; if ((pCir->Chipset == PCI_CHIP_GD5480 && mode->Clock > 135100) || (pCir->Chipset == PCI_CHIP_GD5446 && mode->Clock > 85500)) { /* The actual DAC register value is set later. */ /* The CRTC is clocked at VCLK / 2, so we must half the */ /* horizontal timings. */ if (!mode->CrtcHAdjusted) { mode->CrtcHDisplay >>= 1; mode->CrtcHSyncStart >>= 1; mode->CrtcHTotal >>= 1; mode->CrtcHSyncEnd >>= 1; mode->SynthClock >>= 1; mode->CrtcHAdjusted = TRUE; } depthcode += 64; HDiv2 = TRUE; } if (mode->VTotal >= 1024 && !(mode->Flags & V_INTERLACE)) { /* For non-interlaced vertical timing >= 1024, the vertical timings */ /* are divided by 2 and VGA CRTC 0x17 bit 2 is set. */ if (!mode->CrtcVAdjusted) { mode->CrtcVDisplay >>= 1; mode->CrtcVSyncStart >>= 1; mode->CrtcVSyncEnd >>= 1; mode->CrtcVTotal >>= 1; mode->CrtcVAdjusted = TRUE; } VDiv2 = TRUE; } /* Initialise the ModeReg values */ if (!vgaHWInit(pScrn, mode)) return FALSE; pScrn->vtSema = TRUE; /* Turn off HW cursor, gamma correction, overscan color protect. */ pCir->chip.alp->ModeReg.ExtVga[SR12] = 0; if ((pCir->properties & HWCUR64) == HWCUR64) { pCir->chip.alp->ModeReg.ExtVga[SR12] = 0x4; switch (pCir->Chipset) { case PCI_CHIP_GD7548: pCir->chip.alp->ModeReg.ExtVga[SR21] |= 0x10; break; } } else pCir->chip.alp->ModeReg.ExtVga[SR12] = 0; if(VDiv2) hwp->ModeReg.CRTC[0x17] |= 0x04; #ifdef ALP_DEBUG ErrorF("SynthClock = %d\n", mode->SynthClock); #endif /* Disable DCLK pin driver, interrupts. */ pCir->chip.alp->ModeReg.ExtVga[GR17] |= 0x08; pCir->chip.alp->ModeReg.ExtVga[GR17] &= ~0x04; vgaReg = &hwp->ModeReg; pCir->chip.alp->ModeReg.ExtVga[HDR] = 0; /* Enable linear mode and high-res packed pixel mode */ pCir->chip.alp->ModeReg.ExtVga[SR07] &= 0xe0; #ifdef ALP_DEBUG ErrorF("depthcode = %d\n", depthcode); #endif if (pScrn->bitsPerPixel == 1) { hwp->IOBase = 0x3B0; hwp->ModeReg.MiscOutReg &= ~0x01; } else { hwp->IOBase = 0x3D0; hwp->ModeReg.MiscOutReg |= 0x01; } switch (depthcode) { case 1: case 4: pCir->chip.alp->ModeReg.ExtVga[SR07] |= 0x10; break; case 8: pCir->chip.alp->ModeReg.ExtVga[SR07] |= 0x11; break; case 64+8: pCir->chip.alp->ModeReg.ExtVga[SR07] |= 0x17; break; case 15: pCir->chip.alp->ModeReg.ExtVga[SR07] |= 0x17; pCir->chip.alp->ModeReg.ExtVga[HDR ] = 0xC0; break; case 64+15: pCir->chip.alp->ModeReg.ExtVga[SR07] |= 0x19; pCir->chip.alp->ModeReg.ExtVga[HDR ] = 0xC0; break; case 16: pCir->chip.alp->ModeReg.ExtVga[SR07] |= 0x17; pCir->chip.alp->ModeReg.ExtVga[HDR ] = 0xC1; break; case 64+16: pCir->chip.alp->ModeReg.ExtVga[SR07] |= 0x19; pCir->chip.alp->ModeReg.ExtVga[HDR ] = 0xC1; break; case 24: pCir->chip.alp->ModeReg.ExtVga[SR07] |= 0x15; pCir->chip.alp->ModeReg.ExtVga[HDR ] = 0xC5; break; case 32: pCir->chip.alp->ModeReg.ExtVga[SR07] |= 0x19; pCir->chip.alp->ModeReg.ExtVga[HDR ] = 0xC5; break; default: ErrorF("X11: Internal error: AlpModeInit: Cannot Initialize display to requested mode\n"); #ifdef ALP_DEBUG ErrorF("AlpModeInit returning FALSE on depthcode %d\n", depthcode); #endif return FALSE; } if (HDiv2) pCir->chip.alp->ModeReg.ExtVga[GR18] |= 0x20; else pCir->chip.alp->ModeReg.ExtVga[GR18] &= ~0x20; /* Some extra init stuff */ switch (pCir->Chipset) { case PCI_CHIP_GD7548: /* Do we use MMIO ? If we do and we are on a 7548, we need to tell the board that we want MMIO. */ if (pCir->UseMMIO) { pCir->chip.alp->ModeReg.ExtVga[SR17] = (pCir->chip.alp->ModeReg.ExtVga[SR17] & ~0x40) | 4; ErrorF("UseMMIO: SR17=%2X\n", (int) (pCir->chip.alp->ModeReg.ExtVga[SR17])); } #ifdef ALP_SETUP ErrorF("SR2D=%2X\n", (int) (pCir->chip.alp->ModeReg.ExtVga[SR17])); #endif pCir->chip.alp->ModeReg.ExtVga[SR2D] |= 0xC0; break; } /* No support for interlace (yet) */ pCir->chip.alp->ModeReg.ExtVga[CR1A] = 0x00; width = pScrn->displayWidth * pScrn->bitsPerPixel / 8; if (pScrn->bitsPerPixel == 1) width <<= 2; hwp->ModeReg.CRTC[0x13] = width >> 3; /* Offset extension (see CR13) */ pCir->chip.alp->ModeReg.ExtVga[CR1B] &= 0xAF; pCir->chip.alp->ModeReg.ExtVga[CR1B] |= (width >> (3+4)) & 0x10; pCir->chip.alp->ModeReg.ExtVga[CR1B] |= (width >> (3+3)) & 0x40; pCir->chip.alp->ModeReg.ExtVga[CR1B] |= 0x22; /* Programme the registers */ vgaHWProtect(pScrn, TRUE); hwp->writeMiscOut(hwp, hwp->ModeReg.MiscOutReg); alpRestore(hwp,&pCir->chip.alp->ModeReg); AlpSetClock(pCir, hwp, mode->SynthClock); vgaHWRestore(pScrn, &hwp->ModeReg, VGA_SR_MODE | VGA_SR_CMAP); /* XXX */ if (pScrn->bitsPerPixel == 1) AlpFix1bppColorMap(pScrn); vgaHWProtect(pScrn, FALSE); return TRUE; } /* * Restore the initial (text) mode. */ static void AlpRestore(ScrnInfoPtr pScrn) { vgaHWPtr hwp; vgaRegPtr vgaReg; CirPtr pCir; AlpRegPtr alpReg; #ifdef ALP_DEBUG ErrorF("AlpRestore\n"); #endif hwp = VGAHWPTR(pScrn); pCir = CIRPTR(pScrn); vgaReg = &hwp->SavedReg; alpReg = &pCir->chip.alp->SavedReg; vgaHWProtect(pScrn, TRUE); alpRestore(hwp,alpReg); vgaHWRestore(pScrn, vgaReg, VGA_SR_ALL); vgaHWProtect(pScrn, FALSE); } /* Mandatory */ /* This gets called at the start of each server generation */ Bool AlpScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) { ScrnInfoPtr pScrn; vgaHWPtr hwp; CirPtr pCir; AlpPtr pAlp; int i, ret; int init_picture = 0; VisualPtr visual; int displayWidth,width,height; unsigned char * FbBase = NULL; int cursor_size = 0; #ifdef ALP_DEBUG ErrorF("AlpScreenInit\n"); #endif /* * First get the ScrnInfoRec */ pScrn = xf86Screens[pScreen->myNum]; hwp = VGAHWPTR(pScrn); pCir = CIRPTR(pScrn); pAlp = ALPPTR(pCir); /* Map the VGA memory when the primary video */ if (!vgaHWMapMem(pScrn)) return FALSE; /* Map the Alp memory and MMIO areas */ if (!CirMapMem(pCir, pScrn->scrnIndex)) return FALSE; /* The 754x supports MMIO for the BitBlt engine but not for the VGA registers */ switch (pCir->Chipset) { case PCI_CHIP_GD7548: break; default: if(pCir->UseMMIO) vgaHWSetMmioFuncs(hwp, pCir->IOBase, -0x3C0); } vgaHWGetIOBase(hwp); /* Save the current state */ AlpSave(pScrn); /* Initialise the first mode */ if (!AlpModeInit(pScrn, pScrn->currentMode)) return FALSE; /* Set the viewport */ AlpAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); /* * The next step is to setup the screen's visuals, and initialise the * framebuffer code. In cases where the framebuffer's default * choices for things like visual layouts and bits per RGB are OK, * this may be as simple as calling the framebuffer's ScreenInit() * function. If not, the visuals will need to be setup before calling * a fb ScreenInit() function and fixed up after. * */ /* * Reset the visual list. */ miClearVisualTypes(); /* Setup the visuals we support. */ if (!miSetVisualTypes(pScrn->depth, miGetDefaultVisualMask(pScrn->depth), pScrn->rgbBits, pScrn->defaultVisual)) return FALSE; miSetPixmapDepths (); displayWidth = pScrn->displayWidth; if (pCir->rotate) { height = pScrn->virtualX; width = pScrn->virtualY; } else { width = pScrn->virtualX; height = pScrn->virtualY; } if(pCir->shadowFB) { pCir->ShadowPitch = BitmapBytePad(pScrn->bitsPerPixel * width); pCir->ShadowPtr = xalloc(pCir->ShadowPitch * height); displayWidth = pCir->ShadowPitch / (pScrn->bitsPerPixel >> 3); FbBase = pCir->ShadowPtr; } else { pCir->ShadowPtr = NULL; FbBase = pCir->FbBase; } /* * Call the framebuffer layer's ScreenInit function, and fill in other * pScreen fields. */ switch (pScrn->bitsPerPixel) { case 1: ret = xf1bppScreenInit(pScreen, FbBase, width, height, pScrn->xDpi, pScrn->yDpi, displayWidth); break; case 4: ret = xf4bppScreenInit(pScreen, FbBase, width, height, pScrn->xDpi, pScrn->yDpi, displayWidth); break; case 8: case 16: case 24: case 32: ret = fbScreenInit(pScreen, FbBase, width,height, pScrn->xDpi, pScrn->yDpi, displayWidth,pScrn->bitsPerPixel); init_picture = 1; break; default: xf86DrvMsg(scrnIndex, X_ERROR, "X11: Internal error: invalid bpp (%d) in AlpScreenInit\n", pScrn->bitsPerPixel); ret = FALSE; break; } if (!ret) return FALSE; #ifdef ALP_DEBUG ErrorF("AlpScreenInit after depth dependent init\n"); #endif /* Override the default mask/offset settings */ if (pScrn->bitsPerPixel > 8) { for (i = 0; i < pScreen->numVisuals; i++) { visual = &pScreen->visuals[i]; if ((visual->class | DynamicClass) == DirectColor) { visual->offsetRed = pScrn->offset.red; visual->offsetGreen = pScrn->offset.green; visual->offsetBlue = pScrn->offset.blue; visual->redMask = pScrn->mask.red; visual->greenMask = pScrn->mask.green; visual->blueMask = pScrn->mask.blue; } } } /* must be after RGB ordering fixed */ if (init_picture) fbPictureInit (pScreen, 0, 0); miInitializeBackingStore(pScreen); /* * Set initial black & white colourmap indices. */ xf86SetBlackWhitePixels(pScreen); /* Allocation of off-screen memory to various stuff (hardware cursor, 8x8 mono pattern...) Allocation goes top-down in memory, since the cursor *must* be in the last videoram locations */ pCir->offscreen_offset = pScrn->videoRam*1024; pCir->offscreen_size = pScrn->videoRam * 1024 - pScrn->virtualY * (BitmapBytePad(pScrn->displayWidth * pScrn->bitsPerPixel)); #ifdef ALP_DEBUG ErrorF("offscreen_offset=%d, offscreen_size=%d\n", pCir->offscreen_offset, pCir->offscreen_size); #endif /* Initialise cursor functions */ if (pCir->HWCursor) { /* Initialize HW cursor layer */ if ((pCir->properties & HWCUR64) && (pCir->offscreen_size >= 64*8*2)) { cursor_size = 64; pCir->offscreen_size -= 64*8*2; pCir->offscreen_offset -= 64*8*2; } else if (pCir->offscreen_size >= 32*4*2) { cursor_size = 32; pCir->offscreen_size -= 32*8*2; pCir->offscreen_offset -= 32*8*2; } } if (!pCir->NoAccel) { /* Initialize XAA functions */ AlpOffscreenAccelInit(pScrn); if (!(pCir->UseMMIO ? AlpXAAInitMMIO(pScreen) : AlpXAAInit(pScreen))) xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Could not initialize XAA\n"); } #if 1 pCir->DGAModeInit = AlpModeInit; if (!CirDGAInit(pScreen)) xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "DGA initialization failed\n"); #endif xf86SetSilkenMouse(pScreen); /* Initialise cursor functions */ miDCInitialize(pScreen, xf86GetPointerScreenFuncs()); if (pCir->HWCursor) { if (!AlpHWCursorInit(pScreen, cursor_size)) xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Hardware cursor initialization failed\n"); #ifdef ALP_DEBUG ErrorF("AlpHWCursorInit() complete\n"); #endif } if (pCir->shadowFB) { RefreshAreaFuncPtr refreshArea = cirRefreshArea; if(pCir->rotate) { if (!pCir->PointerMoved) { pCir->PointerMoved = pScrn->PointerMoved; pScrn->PointerMoved = cirPointerMoved; } switch(pScrn->bitsPerPixel) { case 8: refreshArea = cirRefreshArea8; break; case 16: refreshArea = cirRefreshArea16; break; case 24: refreshArea = cirRefreshArea24; break; case 32: refreshArea = cirRefreshArea32; break; } } ShadowFBInit(pScreen, refreshArea); } /* Initialise default colourmap */ if (!miCreateDefColormap(pScreen)) return FALSE; if (pScrn->bitsPerPixel > 1 && pScrn->bitsPerPixel <= 8) vgaHWHandleColormaps(pScreen); xf86DPMSInit(pScreen, AlpDisplayPowerManagementSet, 0); pScrn->memPhysBase = pCir->FbAddress; pScrn->fbOffset = 0; { XF86VideoAdaptorPtr *ptr; int n; n = xf86XVListGenericAdaptors(pScrn,&ptr); if (n) xf86XVScreenInit(pScreen, ptr, n); } /* * Wrap the CloseScreen vector and set SaveScreen. */ pScreen->SaveScreen = AlpSaveScreen; pCir->CloseScreen = pScreen->CloseScreen; pScreen->CloseScreen = AlpCloseScreen; /* Report any unused options (only for the first generation) */ if (serverGeneration == 1) xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options); /* Done */ return TRUE; } /* Usually mandatory */ Bool AlpSwitchMode(int scrnIndex, DisplayModePtr mode, int flags) { return AlpModeInit(xf86Screens[scrnIndex], mode); } /* * This function is used to initialize the Start Address - the first * displayed location in the video memory. */ /* Usually mandatory */ void AlpAdjustFrame(int scrnIndex, int x, int y, int flags) { ScrnInfoPtr pScrn; int Base, tmp; vgaHWPtr hwp; pScrn = xf86Screens[scrnIndex]; hwp = VGAHWPTR(pScrn); Base = ((y * pScrn->displayWidth + x) / 8); if (pScrn->bitsPerPixel != 1) Base *= (pScrn->bitsPerPixel/4); #ifdef ALP_DEBUG ErrorF("AlpAdjustFrame %d %d 0x%x %d %x\n", x, y, flags, Base, Base); #endif if ((Base & ~0x000FFFFF) != 0) { ErrorF("X11: Internal error: AlpAdjustFrame: cannot handle overflow\n"); return; } hwp->writeCrtc(hwp, 0x0C, (Base >> 8) & 0xff); hwp->writeCrtc(hwp, 0x0D, Base & 0xff); tmp = hwp->readCrtc(hwp, 0x1B); tmp &= 0xF2; tmp |= (Base >> 16) & 0x01; tmp |= (Base >> 15) & 0x0C; hwp->writeCrtc(hwp, 0x1B, tmp); tmp = hwp->readCrtc(hwp, 0x1D); tmp &= 0x7F; tmp |= (Base >> 12) & 0x80; hwp->writeCrtc(hwp, 0x1D, tmp); } /* * 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 */ Bool AlpEnterVT(int scrnIndex, int flags) { ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; CirPtr pCir = CIRPTR(pScrn); Bool ret; #ifdef ALP_DEBUG ErrorF("AlpEnterVT\n"); #endif /* Should we re-save the text mode on each VT enter? */ if (!(ret = AlpModeInit(pScrn, pScrn->currentMode))) return FALSE; if (!pCir->NoAccel) pCir->InitAccel(pScrn); return ret; } /* * This is called when VT switching away from the X server. Its job is * to restore the previous (text) mode. * * We may wish to remap video/MMIO memory too. */ /* Mandatory */ void AlpLeaveVT(int scrnIndex, int flags) { ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; vgaHWPtr hwp = VGAHWPTR(pScrn); #ifdef ALP_DEBUG ErrorF("AlpLeaveVT\n"); #endif AlpRestore(pScrn); vgaHWLock(hwp); } /* * This is called at the end of each server generation. It restores the * original (text) mode. It should also unmap the video memory, and free * any per-generation data allocated by the driver. It should finish * by unwrapping and calling the saved CloseScreen function. */ /* Mandatory */ static Bool AlpCloseScreen(int scrnIndex, ScreenPtr pScreen) { ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; vgaHWPtr hwp = VGAHWPTR(pScrn); CirPtr pCir = CIRPTR(pScrn); if(pScrn->vtSema) { AlpRestore(pScrn); vgaHWLock(hwp); CirUnmapMem(pCir, pScrn->scrnIndex); } if (pCir->AccelInfoRec) XAADestroyInfoRec(pCir->AccelInfoRec); pCir->AccelInfoRec = NULL; if (pCir->CursorInfoRec) xf86DestroyCursorInfoRec(pCir->CursorInfoRec); pCir->CursorInfoRec = NULL; if (pCir->DGAModes) xfree(pCir->DGAModes); pCir->DGAnumModes = 0; pCir->DGAModes = NULL; pScrn->vtSema = FALSE; pScreen->CloseScreen = pCir->CloseScreen; return (*pScreen->CloseScreen)(scrnIndex, pScreen); } /* Free up any persistent data structures */ /* Optional */ void AlpFreeScreen(int scrnIndex, int flags) { #ifdef ALP_DEBUG ErrorF("AlpFreeScreen\n"); #endif /* * This only gets called when a screen is being deleted. It does not * get called routinely at the end of a server generation. */ if (xf86LoaderCheckSymbol("vgaHWFreeHWRec")) vgaHWFreeHWRec(xf86Screens[scrnIndex]); AlpFreeRec(xf86Screens[scrnIndex]); } /* Checks if a mode is suitable for the selected chipset. */ /* Optional */ int AlpValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags) { int lace; lace = 1 + ((mode->Flags & V_INTERLACE) != 0); if ((mode->CrtcHDisplay <= 2048) && (mode->CrtcHSyncStart <= 4096) && (mode->CrtcHSyncEnd <= 4096) && (mode->CrtcHTotal <= 4096) && (mode->CrtcVDisplay <= 2048 * lace) && (mode->CrtcVSyncStart <= 4096 * lace) && (mode->CrtcVSyncEnd <= 4096 * lace) && (mode->CrtcVTotal <= 4096 * lace)) { return(MODE_OK); } else { return(MODE_BAD); } } /* Do screen blanking */ /* Mandatory */ static Bool AlpSaveScreen(ScreenPtr pScreen, int mode) { return vgaHWSaveScreen(pScreen, mode); } /* * Set the clock to the requested frequency. If the MCLK is very close * to the requested frequency, it sets a flag so that the MCLK can be used * as VCLK. However this flag is not yet acted upon. */ static void AlpSetClock(CirPtr pCir, vgaHWPtr hwp, int freq) { int num, den, ffreq, usemclk, diff, mclk; CARD8 tmp; #ifdef ALP_DEBUG ErrorF("AlpSetClock freq=%d.%03dMHz\n", freq / 1000, freq % 1000); #endif ffreq = freq; if (!CirrusFindClock(&ffreq, pCir->MaxClock, &num, &den)) return; /* Calculate the MCLK. */ mclk = 14318 * (hwp->readSeq(hwp, 0x1F) & 0x3F) / 8; /* XXX */ /* * Favour MCLK as VLCK if it matches as good as the found clock, * or if it is within 0.2 MHz of the request clock. A VCLK close * to MCLK can cause instability. */ diff = abs(freq - ffreq); if (abs(mclk - ffreq) <= diff + 10 || abs(mclk - freq) <= 200) usemclk = TRUE; else usemclk = FALSE; #ifdef ALP_DEBUG ErrorF("AlpSetClock: nom=%x den=%x ffreq=%d.%03dMHz usemclk=%x\n", num, den, ffreq / 1000, ffreq % 1000, usemclk); #endif /* So - how do we use MCLK here for the VCLK ? */ /* Set VCLK3. */ tmp = hwp->readSeq(hwp, 0x0E); hwp->writeSeq(hwp, 0x0E, (tmp & 0x80) | num); hwp->writeSeq(hwp, 0x1E, den); } /* * AlpDisplayPowerManagementSet -- * * Sets VESA Display Power Management Signaling (DPMS) Mode. */ static void AlpDisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode, int flags) { unsigned char sr01, gr0e; vgaHWPtr hwp; #ifdef ALP_DEBUG ErrorF("AlpDisplayPowerManagementSet\n"); #endif hwp = VGAHWPTR(pScrn); #ifdef ALP_DEBUG ErrorF("AlpDisplayPowerManagementSet: %d\n", PowerManagementMode); #endif switch (PowerManagementMode) { case DPMSModeOn: /* Screen: On; HSync: On, VSync: On */ sr01 = 0x00; gr0e = 0x00; break; case DPMSModeStandby: /* Screen: Off; HSync: Off, VSync: On */ sr01 = 0x20; gr0e = 0x02; break; case DPMSModeSuspend: /* Screen: Off; HSync: On, VSync: Off */ sr01 = 0x20; gr0e = 0x04; break; case DPMSModeOff: /* Screen: Off; HSync: Off, VSync: Off */ sr01 = 0x20; gr0e = 0x06; break; default: return; } sr01 |= hwp->readSeq(hwp, 0x01) & ~0x20; hwp->writeSeq(hwp, 0x01, sr01); gr0e |= hwp->readGr(hwp, 0x0E) & ~0x06; hwp->writeGr(hwp, 0x0E, gr0e); } #ifdef ALPPROBEI2C static void AlpProbeI2C(int scrnIndex) { int i; I2CBusPtr b; b = xf86I2CFindBus(scrnIndex, "I2C bus 1"); if (b == NULL) ErrorF("Could not find I2C bus \"%s\"\n", "I2C bus 1"); else { for (i = 2; i < 256; i += 2) if (xf86I2CProbeAddress(b, i)) ErrorF("Found device 0x%02x on bus \"%s\"\n", i, b->BusName); } b = xf86I2CFindBus(scrnIndex, "I2C bus 2"); if (b == NULL) ErrorF("Could not find I2C bus \"%s\"\n", "I2C bus 2"); else { for (i = 2; i < 256; i += 2) if (xf86I2CProbeAddress(b, i)) ErrorF("Found device 0x%02x on bus \"%s\"\n", i, b->BusName); } } #endif static void AlpProbeLCD(ScrnInfoPtr pScrn) { CirPtr pCir = CIRPTR(pScrn); AlpPtr pAlp = ALPPTR(pCir); vgaHWPtr hwp = VGAHWPTR(pScrn); CARD8 lcdCrtl; static const char* lcd_type_names[] = { "none", "dual-scan monochrome", "unknown", "DSTN (dual scan color)", "TFT (active matrix)" }; pAlp->lcdType = LCD_NONE; switch (pCir->Chipset) { case PCI_CHIP_GD7548: switch (hwp->readCrtc(hwp, 0x2C) >> 6) { case 0: pAlp->lcdType = LCD_DUAL_MONO; break; case 1: pAlp->lcdType = LCD_UNKNOWN; break; case 2: pAlp->lcdType = LCD_DSTN; break; case 3: pAlp->lcdType = LCD_TFT; break; } /* Enable LCD control registers instead of normal CRTC registers */ lcdCrtl = hwp->readCrtc(hwp, 0x2D); hwp->writeCrtc(hwp, 0x2D, lcdCrtl | 0x80); switch ((hwp->readCrtc(hwp, 0x9) >> 2) & 3) { case 0: pAlp->lcdWidth = 640; pAlp->lcdHeight = 480; break; case 1: pAlp->lcdWidth = 800; pAlp->lcdHeight = 600; break; case 2: pAlp->lcdWidth = 1024; pAlp->lcdHeight = 768; break; case 3: pAlp->lcdWidth = 0; pAlp->lcdHeight = 0; break; } /* Disable LCD control registers */ hwp->writeCrtc(hwp, 0x2D, lcdCrtl); break; } if (pAlp->lcdType != LCD_NONE) { xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "LCD display: %dx%d %s\n", pAlp->lcdWidth, pAlp->lcdHeight, lcd_type_names[pAlp->lcdType]); } } static void AlpOffscreenAccelInit(ScrnInfoPtr pScrn) { CirPtr pCir = CIRPTR(pScrn); AlpPtr pAlp = ALPPTR(pCir); if (pCir->offscreen_size >= 8 && pCir->Chipset == PCI_CHIP_GD7548) { pCir->offscreen_offset -= 8; pCir->offscreen_size -= 8; pAlp->monoPattern8x8 = pCir->offscreen_offset; #ifdef ALP_DEBUG ErrorF("monoPattern8x8=%d\n", pAlp->monoPattern8x8); #endif } else pAlp->monoPattern8x8 = 0; { /* TODO: probably not correct if rotated */ BoxRec box; box.x1=0; box.y1=0; box.x2=pScrn->virtualX; box.y2= pCir->offscreen_offset / pCir->pitch; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using %d lines for offscreen memory\n", box.y2 - pScrn->virtualY); } }