/* Copyright (c) 2003-2007 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Neither the name of the Advanced Micro Devices, Inc. nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "xorg-server.h" #include "xf86.h" #include "xf86Modes.h" #include "compiler.h" #include "geode.h" #ifdef XSERVER_LIBPCIACCESS #include #endif /* GPIO Register defines from the CS5536 datasheet */ #define GPIO_OUT 0x00 #define GPIO_OUT_ENABLE 0x04 #define GPIO_OUT_AUX1 0x10 #define GPIO_IN_ENABLE 0x20 #define GPIO_IN 0x30 #define GPIO_IN_AUX1 0x34 /* The DDC pins are defined to be on GPIO pins 3 and 4 */ #define DDC_SCL_PIN (1 << 3) #define DDC_SDA_PIN (1 << 4) #define DDC_DATA_HIGH DDC_SDA_PIN #define DDC_DATA_LOW (DDC_SDA_PIN << 16) #define DDC_CLK_HIGH DDC_SCL_PIN #define DDC_CLK_LOW (DDC_SCL_PIN << 16) #define CS5536_ISA_DEVICE 0x20901022 #define CS5535_ISA_DEVICE 0x002b100b static unsigned short geode_gpio_iobase(void) { #ifdef XSERVER_LIBPCIACCESS struct pci_device *pci; /* The CS5536 GPIO device is always in the same slot: 00:0f.0 */ /* The CS5535 device should be in same slot as well */ pci = pci_device_find_by_slot(0, 0, 0xF, 0x0); if (pci == NULL) return 0; if (pci_device_probe(pci) != 0) return 0; /* The GPIO I/O address is in resource 1 */ return (unsigned short) pci->regions[1].base_addr; #else PCITAG Tag; Tag = pciFindFirst(CS5536_ISA_DEVICE, 0xFFFFFFFF); if (Tag == PCI_NOT_FOUND) { Tag = pciFindFirst(CS5535_ISA_DEVICE, 0xFFFFFFFF); if (Tag == PCI_NOT_FOUND) return 0; } /* The GPIO I/O address is in resource 1 */ return (unsigned short) (pciReadLong(Tag, 0x14) & ~1); #endif } static void geode_ddc_putbits(I2CBusPtr b, int scl, int sda) { unsigned long iobase = (unsigned long) b->DriverPrivate.ptr; unsigned long dat; dat = scl ? DDC_CLK_HIGH : DDC_CLK_LOW; dat |= sda ? DDC_DATA_HIGH : DDC_DATA_LOW; outl(iobase + GPIO_OUT, dat); } static void geode_ddc_getbits(I2CBusPtr b, int *scl, int *sda) { unsigned long iobase = (unsigned long) b->DriverPrivate.ptr; unsigned long dat = inl(iobase + GPIO_IN); *scl = (dat & DDC_CLK_HIGH) ? 1 : 0; *sda = (dat & DDC_DATA_HIGH) ? 1 : 0; } Bool GeodeI2CInit(ScrnInfoPtr pScrni, I2CBusPtr * ptr, char *name) { I2CBusPtr bus; unsigned int ddciobase; ddciobase = geode_gpio_iobase(); if (ddciobase == 0) { xf86DrvMsg(pScrni->scrnIndex, X_ERROR, "Could not find the GPIO I/O base\n"); return FALSE; } /* The GPIO pins for DDC are multiplexed with a * serial port. If that serial port is enabled, then * assume that there is no DDC on the board */ if ((inl(ddciobase + GPIO_IN_AUX1) & DDC_CLK_HIGH) || (inl(ddciobase + GPIO_OUT_AUX1) & DDC_DATA_HIGH)) { xf86DrvMsg(pScrni->scrnIndex, X_ERROR, "GPIO pins are in serial mode. Assuming no DDC\n"); return FALSE; } outl(ddciobase + GPIO_OUT_ENABLE, DDC_DATA_HIGH | DDC_CLK_HIGH); outl(ddciobase + GPIO_IN_ENABLE, DDC_DATA_HIGH | DDC_CLK_HIGH); bus = xf86CreateI2CBusRec(); if (!bus) return FALSE; bus->BusName = name; bus->scrnIndex = pScrni->scrnIndex; bus->I2CGetBits = geode_ddc_getbits; bus->I2CPutBits = geode_ddc_putbits; bus->DriverPrivate.ptr = (void *) (unsigned long) (ddciobase); if (!xf86I2CBusInit(bus)) return FALSE; *ptr = bus; return TRUE; } static xf86MonPtr GeodeGetDDC(ScrnInfoPtr pScrni) { xf86MonPtr mon = NULL; I2CBusPtr bus; if (!GeodeI2CInit(pScrni, &bus, "CS5536 DDC BUS")) return NULL; mon = xf86DoEDID_DDC2(DDC_CALL(pScrni), bus); #if (XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,4,99,0,0)) if (mon) xf86DDCApplyQuirks(pScrni->scrnIndex, mon); #endif xf86DestroyI2CBusRec(bus, FALSE, FALSE); return mon; } void GeodeProbeDDC(ScrnInfoPtr pScrni, int index) { ConfiguredMonitor = GeodeGetDDC(pScrni); } xf86MonPtr GeodeDoDDC(ScrnInfoPtr pScrni, int index) { xf86MonPtr info = NULL; info = GeodeGetDDC(pScrni); xf86PrintEDID(info); xf86SetDDCproperties(pScrni, info); return info; }