diff options
Diffstat (limited to 'src/cir_driver.c')
-rw-r--r-- | src/cir_driver.c | 430 |
1 files changed, 430 insertions, 0 deletions
diff --git a/src/cir_driver.c b/src/cir_driver.c new file mode 100644 index 0000000..5468b6b --- /dev/null +++ b/src/cir_driver.c @@ -0,0 +1,430 @@ +/* + * 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 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* All drivers should typically include these */ +#include "xf86.h" +#include "xf86_OSproc.h" + +#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 6 +#include "xf86Resources.h" +#endif +/* All drivers need this */ + +/* Drivers that need to access the PCI config space directly need this */ +#include "xf86Pci.h" + +#include "cir.h" +#include "alp.h" +#include "lg.h" + +#include "vbe.h" + +/* + * Forward definitions for the functions that make up the driver. + */ + +/* Mandatory functions */ + +static const OptionInfoRec * CIRAvailableOptions(int chipid, int busid); +static void CIRIdentify(int flags); +static Bool CIRProbe(DriverPtr drv, int flags); + +static Bool lg_loaded = FALSE; +static Bool alp_loaded = FALSE; + +#define CIR_VERSION 4000 +#define CIR_NAME "CIRRUS" +#define CIR_DRIVER_NAME "cirrus" +#define CIR_MAJOR_VERSION PACKAGE_VERSION_MAJOR +#define CIR_MINOR_VERSION PACKAGE_VERSION_MINOR +#define CIR_PATCHLEVEL PACKAGE_VERSION_PATCHLEVEL + +/* + * This contains the functions needed by the server after loading the + * driver module. It must be supplied, and gets added to the driver list by + * the Module Setup function in the dynamic case. In the static case a + * reference to this is compiled in, and this requires that the name of + * this DriverRec be an upper-case version of the driver name. + */ + +_X_EXPORT DriverRec CIRRUS = { + CIR_VERSION, + CIR_DRIVER_NAME, + CIRIdentify, + CIRProbe, + CIRAvailableOptions, + NULL, + 0 +}; + +/* Supported chipsets */ +SymTabRec CIRChipsets[] = { + { PCI_CHIP_GD5430, "CLGD5430" }, + { PCI_CHIP_GD5434_4, "CLGD5434-4" }, + { PCI_CHIP_GD5434_8, "CLGD5434-8" }, + { PCI_CHIP_GD5436, "CLGD5436" }, +/* { PCI_CHIP_GD5440, "CLGD5440" }, */ + { PCI_CHIP_GD5446, "CLGD5446" }, + { PCI_CHIP_GD5480, "CLGD5480" }, + { PCI_CHIP_GD5462, "CL-GD5462" }, + { PCI_CHIP_GD5464, "CL-GD5464" }, + { PCI_CHIP_GD5464BD, "CL-GD5464BD" }, + { PCI_CHIP_GD5465, "CL-GD5465" }, + { PCI_CHIP_GD7548, "CL-GD7548" }, + { PCI_CHIP_GD7555, "CL-GD7555" }, + { PCI_CHIP_GD7556, "CL-GD7556" }, + {-1, NULL } +}; + +/* List of PCI chipset names */ +_X_EXPORT PciChipsets CIRPciChipsets[] = { + { PCI_CHIP_GD5430, PCI_CHIP_GD5430, RES_SHARED_VGA }, + { PCI_CHIP_GD5434_4,PCI_CHIP_GD5434_4, RES_SHARED_VGA }, + { PCI_CHIP_GD5434_8,PCI_CHIP_GD5434_8, RES_SHARED_VGA }, + { PCI_CHIP_GD5436, PCI_CHIP_GD5436, RES_SHARED_VGA }, +/* { PCI_CHIP_GD5440, PCI_CHIP_GD5440, RES_SHARED_VGA }, */ + { PCI_CHIP_GD5446, PCI_CHIP_GD5446, RES_SHARED_VGA }, + { PCI_CHIP_GD5480, PCI_CHIP_GD5480, RES_SHARED_VGA }, + { PCI_CHIP_GD5462, PCI_CHIP_GD5462, RES_SHARED_VGA }, + { PCI_CHIP_GD5464, PCI_CHIP_GD5464, RES_SHARED_VGA }, + { PCI_CHIP_GD5464BD,PCI_CHIP_GD5464BD, RES_SHARED_VGA }, + { PCI_CHIP_GD5465, PCI_CHIP_GD5465, RES_SHARED_VGA }, + { PCI_CHIP_GD7548, PCI_CHIP_GD7548, RES_SHARED_VGA }, + { PCI_CHIP_GD7555, PCI_CHIP_GD7555, RES_SHARED_VGA }, + { PCI_CHIP_GD7556, PCI_CHIP_GD7556, RES_SHARED_VGA }, + { -1, -1, RES_UNDEFINED} +}; + +#ifdef XFree86LOADER + +static MODULESETUPPROTO(cirSetup); + +static XF86ModuleVersionInfo cirVersRec = +{ + "cirrus", + MODULEVENDORSTRING, + MODINFOSTRING1, + MODINFOSTRING2, + XORG_VERSION_CURRENT, + CIR_MAJOR_VERSION, CIR_MINOR_VERSION, CIR_PATCHLEVEL, + ABI_CLASS_VIDEODRV, /* This is a video driver */ + ABI_VIDEODRV_VERSION, + MOD_CLASS_VIDEODRV, + {0,0,0,0} +}; + +/* + * This is the module init data. + * Its name has to be the driver name followed by ModuleData. + */ +_X_EXPORT XF86ModuleData cirrusModuleData = { &cirVersRec, cirSetup, NULL }; + +static pointer +cirSetup(pointer module, pointer opts, int *errmaj, int *errmin) +{ + static Bool setupDone = FALSE; + + /* This module should be loaded only once, but check to be sure. */ + + if (!setupDone) { + setupDone = TRUE; + xf86AddDriver(&CIRRUS, module, 0); + + return (pointer)1; + } + if (errmaj) *errmaj = LDR_ONCEONLY; + return NULL; +} + +#endif /* XFree86LOADER */ + +/* Mandatory */ +static void +CIRIdentify(int flags) +{ + xf86PrintChipsets(CIR_NAME, "driver for Cirrus chipsets", CIRChipsets); +} + +static const OptionInfoRec * +CIRAvailableOptions(int chipid, int busid) +{ + int chip = chipid & 0xffff; + + switch (chip) + { + case PCI_CHIP_GD5462: + case PCI_CHIP_GD5464: + case PCI_CHIP_GD5464BD: + case PCI_CHIP_GD5465: + if (lg_loaded) + return LgAvailableOptions(chipid); + else + return NULL; + + default: + if (alp_loaded) + return AlpAvailableOptions(chipid); + else + return NULL; + } +} + +static Bool +CIRProbe(DriverPtr drv, int flags) +{ + int i; + GDevPtr *devSections; + pciVideoPtr pPci; + int *usedChips; + int numDevSections; + int numUsed; + Bool foundScreen = FALSE; + ScrnInfoPtr pScrn; + +#ifdef CIR_DEBUG + ErrorF("CirProbe\n"); +#endif + + /* + * For PROBE_DETECT, make sure both sub-modules are loaded before + * calling xf86MatchPciInstances(), because the AvailableOptions() + * functions may be called before xf86MatchPciInstances() returns. + */ + + if (flags & PROBE_DETECT) { + if (!lg_loaded) { + if (xf86LoadDrvSubModule(drv, "cirrus_laguna")) { + lg_loaded = TRUE; + } + } + if (!alp_loaded) { + if (xf86LoadDrvSubModule(drv, "cirrus_alpine")) { + alp_loaded = TRUE; + } + } + } + + if ((numDevSections = xf86MatchDevice(CIR_DRIVER_NAME, + &devSections)) <= 0) { + return FALSE; + } + +#ifndef XSERVER_LIBPCIACCESS + if (xf86GetPciVideoInfo() == NULL) { + /* + * We won't let anything in the config file override finding no + * PCI video cards at all. This seems reasonable now, but we'll see. + */ + return FALSE; + } +#endif + + numUsed = xf86MatchPciInstances(CIR_NAME, PCI_VENDOR_CIRRUS, + CIRChipsets, CIRPciChipsets, devSections, + numDevSections, drv, &usedChips); + /* Free it since we don't need that list after this */ + free(devSections); + if (numUsed <= 0) + return FALSE; + if (flags & PROBE_DETECT) + foundScreen = TRUE; + else for (i = 0; i < numUsed; i++) { + /* The Laguna family of chips is so different from the Alpine + family that we won't share even the highest-level of + functions. But, the Laguna chips /are/ Cirrus chips, so + they should be handled in this driver (as opposed to their + own driver). */ + pPci = xf86GetPciInfoForEntity(usedChips[i]); + +#ifdef XSERVER_LIBPCIACCESS + if (pci_device_has_kernel_driver(pPci)) { + xf86DrvMsg(0, X_ERROR, + "cirrus: The PCI device 0x%x at %2.2d@%2.2d:%2.2d:%1.1d has a kernel module claiming it.\n", + pPci->device_id, pPci->bus, pPci->domain, pPci->dev, pPci->func); + xf86DrvMsg(0, X_ERROR, + "cirrus: This driver cannot operate until it has been unloaded.\n"); + return FALSE; + } +#endif + pScrn = NULL; + if (pPci && (PCI_DEV_DEVICE_ID(pPci) == PCI_CHIP_GD5462 || + PCI_DEV_DEVICE_ID(pPci) == PCI_CHIP_GD5464 || + PCI_DEV_DEVICE_ID(pPci) == PCI_CHIP_GD5464BD || + PCI_DEV_DEVICE_ID(pPci) == PCI_CHIP_GD5465)) { + + if (!lg_loaded) { + if (!xf86LoadDrvSubModule(drv, "cirrus_laguna")) + continue; + lg_loaded = TRUE; + } + pScrn = LgProbe(usedChips[i]); + } else { + if (!alp_loaded) { + if (!xf86LoadDrvSubModule(drv, "cirrus_alpine")) + continue; + alp_loaded = TRUE; + } + pScrn = AlpProbe(usedChips[i]); + } + + if (pScrn) { + foundScreen = TRUE; + /* Fill in what we can of the ScrnInfoRec */ + pScrn->driverVersion = CIR_VERSION; + pScrn->driverName = CIR_DRIVER_NAME; + pScrn->name = CIR_NAME; + pScrn->Probe = NULL; + } + } + free(usedChips); + + return foundScreen; +} + +/* + * Map the framebuffer and MMIO memory. + */ + +_X_EXPORT Bool +CirMapMem(CirPtr pCir, int scrnIndex) +{ + int mmioFlags; + +#ifdef CIR_DEBUG + ErrorF("CirMapMem\n"); +#endif + + /* + * Map the frame buffer. + */ + if (pCir->FbMapSize) { + +#ifndef XSERVER_LIBPCIACCESS + + pCir->FbBase = xf86MapPciMem(scrnIndex, VIDMEM_FRAMEBUFFER, + pCir->PciTag, pCir->FbAddress, + pCir->FbMapSize); + if (pCir->FbBase == NULL) + return FALSE; + +#else + void** result = (void**)&pCir->FbBase; + int err = pci_device_map_range(pCir->PciInfo, + pCir->FbAddress, + pCir->FbMapSize, + PCI_DEV_MAP_FLAG_WRITABLE | + PCI_DEV_MAP_FLAG_WRITE_COMBINE, + result); + + if (err) + return FALSE; +#endif + } + +#ifdef CIR_DEBUG + ErrorF("CirMapMem pCir->FbBase=0x%08x\n", pCir->FbBase); +#endif + + /* + * Map IO registers to virtual address space + */ + if (pCir->IOAddress == 0) { + pCir->IOBase = NULL; /* Until we are ready to use MMIO */ + } else { + +#ifndef XSERVER_LIBPCIACCESS + mmioFlags = VIDMEM_MMIO; + /* + * For Alpha, we need to map SPARSE memory, since we need + * byte/short access. Common-level will automatically use + * sparse mapping for MMIO. + */ + + pCir->IOBase = + xf86MapPciMem(scrnIndex, mmioFlags, pCir->PciTag, + pCir->IOAddress, pCir->IoMapSize); + if (pCir->IOBase == NULL) + return FALSE; + +#else + void** result = (void**)&pCir->IOBase; + int err = pci_device_map_range(pCir->PciInfo, + pCir->IOAddress, + pCir->IoMapSize, + PCI_DEV_MAP_FLAG_WRITABLE, + result); + + if (err) + return FALSE; + +#endif + } + +#ifdef CIR_DEBUG + ErrorF("CirMapMem pCir->IOBase=0x%08x [length=%08x] from PCI=%08x\n", + pCir->IOBase, pCir->IoMapSize, pCir->IOAddress); + ErrorF("MMIO[GR31] = %2X\n", (int) + ((volatile unsigned char*) pCir->IOBase)[0x40]); +#endif + + return TRUE; +} + + +/* + * Unmap the framebuffer and MMIO memory. + */ + +_X_EXPORT Bool +CirUnmapMem(CirPtr pCir, int scrnIndex) +{ +#ifdef CIR_DEBUG + ErrorF("CirUnmapMem\n"); +#endif + + if (pCir->IOBase != NULL) { + /* + * Unmap IO registers to virtual address space + */ +#ifndef XSERVER_LIBPCIACCESS + xf86UnMapVidMem(scrnIndex, (pointer)pCir->IOBase, pCir->IoMapSize); +#else + pci_device_unmap_range(pCir->PciInfo, (pointer)pCir->IOBase, pCir->IoMapSize); +#endif + pCir->IOBase = NULL; + } + +#ifndef XSERVER_LIBPCIACCESS + xf86UnMapVidMem(scrnIndex, (pointer)pCir->FbBase, pCir->FbMapSize); +#else + pci_device_unmap_range(pCir->PciInfo, (pointer)pCir->FbBase, pCir->FbMapSize); +#endif + pCir->FbBase = NULL; + return TRUE; +} + +_X_EXPORT void +cirProbeDDC(ScrnInfoPtr pScrn, int index) +{ + vbeInfoPtr pVbe; + + if (xf86LoadSubModule(pScrn, "vbe")) { + pVbe = VBEInit(NULL,index); + ConfiguredMonitor = vbeDoEDID(pVbe, NULL); + vbeFree(pVbe); + } +} |