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