1f29dbc25Smrg/* Copyright (c) 2003-2007 Advanced Micro Devices, Inc. 2f29dbc25Smrg * 3f29dbc25Smrg * Permission is hereby granted, free of charge, to any person obtaining a copy 4f29dbc25Smrg * of this software and associated documentation files (the "Software"), to 5f29dbc25Smrg * deal in the Software without restriction, including without limitation the 6f29dbc25Smrg * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7f29dbc25Smrg * sell copies of the Software, and to permit persons to whom the Software is 8f29dbc25Smrg * furnished to do so, subject to the following conditions: 9f29dbc25Smrg * 10f29dbc25Smrg * The above copyright notice and this permission notice shall be included in 11f29dbc25Smrg * all copies or substantial portions of the Software. 12f29dbc25Smrg * 13f29dbc25Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14f29dbc25Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15f29dbc25Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16f29dbc25Smrg * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17f29dbc25Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18f29dbc25Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19f29dbc25Smrg * IN THE SOFTWARE. 20f29dbc25Smrg * 21f29dbc25Smrg * Neither the name of the Advanced Micro Devices, Inc. nor the names of its 22f29dbc25Smrg * contributors may be used to endorse or promote products derived from this 23f29dbc25Smrg * software without specific prior written permission. 24f29dbc25Smrg * */ 25f29dbc25Smrg 26f29dbc25Smrg#ifdef HAVE_CONFIG_H 27f29dbc25Smrg#include "config.h" 28f29dbc25Smrg#endif 29f29dbc25Smrg 3000be8644Schristos#include "xorg-server.h" 3100be8644Schristos 32f29dbc25Smrg#include "xf86.h" 33f29dbc25Smrg#include "xf86Modes.h" 34f29dbc25Smrg#include "compiler.h" 35f29dbc25Smrg#include "geode.h" 36f29dbc25Smrg 37f29dbc25Smrg#ifdef XSERVER_LIBPCIACCESS 38f29dbc25Smrg#include <pciaccess.h> 39f29dbc25Smrg#endif 40f29dbc25Smrg 41f29dbc25Smrg/* GPIO Register defines from the CS5536 datasheet */ 42f29dbc25Smrg 43f29dbc25Smrg#define GPIO_OUT 0x00 44f29dbc25Smrg#define GPIO_OUT_ENABLE 0x04 45f29dbc25Smrg#define GPIO_OUT_AUX1 0x10 46f29dbc25Smrg#define GPIO_IN_ENABLE 0x20 47f29dbc25Smrg#define GPIO_IN 0x30 48f29dbc25Smrg#define GPIO_IN_AUX1 0x34 49f29dbc25Smrg 50f29dbc25Smrg/* The DDC pins are defined to be on GPIO pins 3 and 4 */ 51f29dbc25Smrg#define DDC_SCL_PIN (1 << 3) 52f29dbc25Smrg#define DDC_SDA_PIN (1 << 4) 53f29dbc25Smrg 54f29dbc25Smrg#define DDC_DATA_HIGH DDC_SDA_PIN 55f29dbc25Smrg#define DDC_DATA_LOW (DDC_SDA_PIN << 16) 56f29dbc25Smrg 57f29dbc25Smrg#define DDC_CLK_HIGH DDC_SCL_PIN 58f29dbc25Smrg#define DDC_CLK_LOW (DDC_SCL_PIN << 16) 59f29dbc25Smrg 60f29dbc25Smrg#define CS5536_ISA_DEVICE 0x20901022 61f29dbc25Smrg#define CS5535_ISA_DEVICE 0x002b100b 62f29dbc25Smrg 63f29dbc25Smrgstatic unsigned short 64f29dbc25Smrggeode_gpio_iobase(void) 65f29dbc25Smrg{ 66f29dbc25Smrg#ifdef XSERVER_LIBPCIACCESS 67f29dbc25Smrg struct pci_device *pci; 68f29dbc25Smrg 69f29dbc25Smrg /* The CS5536 GPIO device is always in the same slot: 00:0f.0 */ 70f29dbc25Smrg /* The CS5535 device should be in same slot as well */ 71f29dbc25Smrg 72f29dbc25Smrg pci = pci_device_find_by_slot(0, 0, 0xF, 0x0); 73f29dbc25Smrg 74f29dbc25Smrg if (pci == NULL) 7504007ebaSmrg return 0; 76f29dbc25Smrg 77f29dbc25Smrg if (pci_device_probe(pci) != 0) 78f29dbc25Smrg return 0; 79f29dbc25Smrg 80f29dbc25Smrg /* The GPIO I/O address is in resource 1 */ 8104007ebaSmrg return (unsigned short) pci->regions[1].base_addr; 82f29dbc25Smrg#else 83f29dbc25Smrg PCITAG Tag; 84f29dbc25Smrg 85f29dbc25Smrg Tag = pciFindFirst(CS5536_ISA_DEVICE, 0xFFFFFFFF); 86f29dbc25Smrg 87f29dbc25Smrg if (Tag == PCI_NOT_FOUND) { 88f29dbc25Smrg Tag = pciFindFirst(CS5535_ISA_DEVICE, 0xFFFFFFFF); 89f29dbc25Smrg 90f29dbc25Smrg if (Tag == PCI_NOT_FOUND) 9104007ebaSmrg return 0; 92f29dbc25Smrg } 93f29dbc25Smrg 94f29dbc25Smrg /* The GPIO I/O address is in resource 1 */ 9504007ebaSmrg return (unsigned short) (pciReadLong(Tag, 0x14) & ~1); 96f29dbc25Smrg#endif 97f29dbc25Smrg} 98f29dbc25Smrg 99f29dbc25Smrgstatic void 100f29dbc25Smrggeode_ddc_putbits(I2CBusPtr b, int scl, int sda) 101f29dbc25Smrg{ 10204007ebaSmrg unsigned long iobase = (unsigned long) b->DriverPrivate.ptr; 103f29dbc25Smrg unsigned long dat; 104f29dbc25Smrg 105f29dbc25Smrg dat = scl ? DDC_CLK_HIGH : DDC_CLK_LOW; 106f29dbc25Smrg dat |= sda ? DDC_DATA_HIGH : DDC_DATA_LOW; 107f29dbc25Smrg 108f29dbc25Smrg outl(iobase + GPIO_OUT, dat); 109f29dbc25Smrg} 110f29dbc25Smrg 111f29dbc25Smrgstatic void 112f29dbc25Smrggeode_ddc_getbits(I2CBusPtr b, int *scl, int *sda) 113f29dbc25Smrg{ 11404007ebaSmrg unsigned long iobase = (unsigned long) b->DriverPrivate.ptr; 115f29dbc25Smrg unsigned long dat = inl(iobase + GPIO_IN); 116f29dbc25Smrg 117f29dbc25Smrg *scl = (dat & DDC_CLK_HIGH) ? 1 : 0; 118f29dbc25Smrg *sda = (dat & DDC_DATA_HIGH) ? 1 : 0; 119f29dbc25Smrg} 120f29dbc25Smrg 121f29dbc25SmrgBool 122f29dbc25SmrgGeodeI2CInit(ScrnInfoPtr pScrni, I2CBusPtr * ptr, char *name) 123f29dbc25Smrg{ 124f29dbc25Smrg I2CBusPtr bus; 125f29dbc25Smrg unsigned int ddciobase; 126f29dbc25Smrg 127f29dbc25Smrg ddciobase = geode_gpio_iobase(); 128f29dbc25Smrg 129f29dbc25Smrg if (ddciobase == 0) { 13004007ebaSmrg xf86DrvMsg(pScrni->scrnIndex, X_ERROR, 13104007ebaSmrg "Could not find the GPIO I/O base\n"); 13204007ebaSmrg return FALSE; 133f29dbc25Smrg } 134f29dbc25Smrg 135f29dbc25Smrg /* The GPIO pins for DDC are multiplexed with a 136f29dbc25Smrg * serial port. If that serial port is enabled, then 137f29dbc25Smrg * assume that there is no DDC on the board 138f29dbc25Smrg */ 139f29dbc25Smrg 140f29dbc25Smrg if ((inl(ddciobase + GPIO_IN_AUX1) & DDC_CLK_HIGH) || 14104007ebaSmrg (inl(ddciobase + GPIO_OUT_AUX1) & DDC_DATA_HIGH)) { 14204007ebaSmrg xf86DrvMsg(pScrni->scrnIndex, X_ERROR, 14304007ebaSmrg "GPIO pins are in serial mode. Assuming no DDC\n"); 14404007ebaSmrg return FALSE; 145f29dbc25Smrg } 146f29dbc25Smrg 147f29dbc25Smrg outl(ddciobase + GPIO_OUT_ENABLE, DDC_DATA_HIGH | DDC_CLK_HIGH); 148f29dbc25Smrg outl(ddciobase + GPIO_IN_ENABLE, DDC_DATA_HIGH | DDC_CLK_HIGH); 149f29dbc25Smrg 150f29dbc25Smrg bus = xf86CreateI2CBusRec(); 151f29dbc25Smrg 152f29dbc25Smrg if (!bus) 15304007ebaSmrg return FALSE; 154f29dbc25Smrg 155f29dbc25Smrg bus->BusName = name; 156f29dbc25Smrg bus->scrnIndex = pScrni->scrnIndex; 157f29dbc25Smrg 158f29dbc25Smrg bus->I2CGetBits = geode_ddc_getbits; 159f29dbc25Smrg bus->I2CPutBits = geode_ddc_putbits; 16004007ebaSmrg bus->DriverPrivate.ptr = (void *) (unsigned long) (ddciobase); 161f29dbc25Smrg 162f29dbc25Smrg if (!xf86I2CBusInit(bus)) 16304007ebaSmrg return FALSE; 164f29dbc25Smrg 165f29dbc25Smrg *ptr = bus; 166f29dbc25Smrg return TRUE; 167f29dbc25Smrg} 168f29dbc25Smrg 169f29dbc25Smrgstatic xf86MonPtr 170f29dbc25SmrgGeodeGetDDC(ScrnInfoPtr pScrni) 171f29dbc25Smrg{ 172f29dbc25Smrg xf86MonPtr mon = NULL; 173f29dbc25Smrg I2CBusPtr bus; 174f29dbc25Smrg 175f29dbc25Smrg if (!GeodeI2CInit(pScrni, &bus, "CS5536 DDC BUS")) 17604007ebaSmrg return NULL; 177f29dbc25Smrg 17804007ebaSmrg mon = xf86DoEDID_DDC2(DDC_CALL(pScrni), bus); 179f29dbc25Smrg 180f29dbc25Smrg#if (XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,4,99,0,0)) 181f29dbc25Smrg if (mon) 18204007ebaSmrg xf86DDCApplyQuirks(pScrni->scrnIndex, mon); 183f29dbc25Smrg#endif 184f29dbc25Smrg 185f29dbc25Smrg xf86DestroyI2CBusRec(bus, FALSE, FALSE); 186f29dbc25Smrg 187f29dbc25Smrg return mon; 188f29dbc25Smrg} 189f29dbc25Smrg 190f29dbc25Smrgvoid 191f29dbc25SmrgGeodeProbeDDC(ScrnInfoPtr pScrni, int index) 192f29dbc25Smrg{ 193f29dbc25Smrg ConfiguredMonitor = GeodeGetDDC(pScrni); 194f29dbc25Smrg} 195f29dbc25Smrg 196f29dbc25Smrgxf86MonPtr 197f29dbc25SmrgGeodeDoDDC(ScrnInfoPtr pScrni, int index) 198f29dbc25Smrg{ 199f29dbc25Smrg xf86MonPtr info = NULL; 200f29dbc25Smrg 201f29dbc25Smrg info = GeodeGetDDC(pScrni); 202f29dbc25Smrg xf86PrintEDID(info); 203f29dbc25Smrg xf86SetDDCproperties(pScrni, info); 204f29dbc25Smrg return info; 205f29dbc25Smrg} 206