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 "xorg-server.h" 31 32 #include "xf86.h" 33 #include "xf86Modes.h" 34 #include "compiler.h" 35 #include "geode.h" 36 37 #ifdef XSERVER_LIBPCIACCESS 38 #include <pciaccess.h> 39 #endif 40 41 /* GPIO Register defines from the CS5536 datasheet */ 42 43 #define GPIO_OUT 0x00 44 #define GPIO_OUT_ENABLE 0x04 45 #define GPIO_OUT_AUX1 0x10 46 #define GPIO_IN_ENABLE 0x20 47 #define GPIO_IN 0x30 48 #define GPIO_IN_AUX1 0x34 49 50 /* The DDC pins are defined to be on GPIO pins 3 and 4 */ 51 #define DDC_SCL_PIN (1 << 3) 52 #define DDC_SDA_PIN (1 << 4) 53 54 #define DDC_DATA_HIGH DDC_SDA_PIN 55 #define DDC_DATA_LOW (DDC_SDA_PIN << 16) 56 57 #define DDC_CLK_HIGH DDC_SCL_PIN 58 #define DDC_CLK_LOW (DDC_SCL_PIN << 16) 59 60 #define CS5536_ISA_DEVICE 0x20901022 61 #define CS5535_ISA_DEVICE 0x002b100b 62 63 static unsigned short 64 geode_gpio_iobase(void) 65 { 66 #ifdef XSERVER_LIBPCIACCESS 67 struct pci_device *pci; 68 69 /* The CS5536 GPIO device is always in the same slot: 00:0f.0 */ 70 /* The CS5535 device should be in same slot as well */ 71 72 pci = pci_device_find_by_slot(0, 0, 0xF, 0x0); 73 74 if (pci == NULL) 75 return 0; 76 77 if (pci_device_probe(pci) != 0) 78 return 0; 79 80 /* The GPIO I/O address is in resource 1 */ 81 return (unsigned short) pci->regions[1].base_addr; 82 #else 83 PCITAG Tag; 84 85 Tag = pciFindFirst(CS5536_ISA_DEVICE, 0xFFFFFFFF); 86 87 if (Tag == PCI_NOT_FOUND) { 88 Tag = pciFindFirst(CS5535_ISA_DEVICE, 0xFFFFFFFF); 89 90 if (Tag == PCI_NOT_FOUND) 91 return 0; 92 } 93 94 /* The GPIO I/O address is in resource 1 */ 95 return (unsigned short) (pciReadLong(Tag, 0x14) & ~1); 96 #endif 97 } 98 99 static void 100 geode_ddc_putbits(I2CBusPtr b, int scl, int sda) 101 { 102 unsigned long iobase = (unsigned long) b->DriverPrivate.ptr; 103 unsigned long dat; 104 105 dat = scl ? DDC_CLK_HIGH : DDC_CLK_LOW; 106 dat |= sda ? DDC_DATA_HIGH : DDC_DATA_LOW; 107 108 outl(iobase + GPIO_OUT, dat); 109 } 110 111 static void 112 geode_ddc_getbits(I2CBusPtr b, int *scl, int *sda) 113 { 114 unsigned long iobase = (unsigned long) b->DriverPrivate.ptr; 115 unsigned long dat = inl(iobase + GPIO_IN); 116 117 *scl = (dat & DDC_CLK_HIGH) ? 1 : 0; 118 *sda = (dat & DDC_DATA_HIGH) ? 1 : 0; 119 } 120 121 Bool 122 GeodeI2CInit(ScrnInfoPtr pScrni, I2CBusPtr * ptr, char *name) 123 { 124 I2CBusPtr bus; 125 unsigned int ddciobase; 126 127 ddciobase = geode_gpio_iobase(); 128 129 if (ddciobase == 0) { 130 xf86DrvMsg(pScrni->scrnIndex, X_ERROR, 131 "Could not find the GPIO I/O base\n"); 132 return FALSE; 133 } 134 135 /* The GPIO pins for DDC are multiplexed with a 136 * serial port. If that serial port is enabled, then 137 * assume that there is no DDC on the board 138 */ 139 140 if ((inl(ddciobase + GPIO_IN_AUX1) & DDC_CLK_HIGH) || 141 (inl(ddciobase + GPIO_OUT_AUX1) & DDC_DATA_HIGH)) { 142 xf86DrvMsg(pScrni->scrnIndex, X_ERROR, 143 "GPIO pins are in serial mode. Assuming no DDC\n"); 144 return FALSE; 145 } 146 147 outl(ddciobase + GPIO_OUT_ENABLE, DDC_DATA_HIGH | DDC_CLK_HIGH); 148 outl(ddciobase + GPIO_IN_ENABLE, DDC_DATA_HIGH | DDC_CLK_HIGH); 149 150 bus = xf86CreateI2CBusRec(); 151 152 if (!bus) 153 return FALSE; 154 155 bus->BusName = name; 156 bus->scrnIndex = pScrni->scrnIndex; 157 158 bus->I2CGetBits = geode_ddc_getbits; 159 bus->I2CPutBits = geode_ddc_putbits; 160 bus->DriverPrivate.ptr = (void *) (unsigned long) (ddciobase); 161 162 if (!xf86I2CBusInit(bus)) 163 return FALSE; 164 165 *ptr = bus; 166 return TRUE; 167 } 168 169 static xf86MonPtr 170 GeodeGetDDC(ScrnInfoPtr pScrni) 171 { 172 xf86MonPtr mon = NULL; 173 I2CBusPtr bus; 174 175 if (!GeodeI2CInit(pScrni, &bus, "CS5536 DDC BUS")) 176 return NULL; 177 178 mon = xf86DoEDID_DDC2(DDC_CALL(pScrni), bus); 179 180 #if (XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,4,99,0,0)) 181 if (mon) 182 xf86DDCApplyQuirks(pScrni->scrnIndex, mon); 183 #endif 184 185 xf86DestroyI2CBusRec(bus, FALSE, FALSE); 186 187 return mon; 188 } 189 190 void 191 GeodeProbeDDC(ScrnInfoPtr pScrni, int index) 192 { 193 ConfiguredMonitor = GeodeGetDDC(pScrni); 194 } 195 196 xf86MonPtr 197 GeodeDoDDC(ScrnInfoPtr pScrni, int index) 198 { 199 xf86MonPtr info = NULL; 200 201 info = GeodeGetDDC(pScrni); 202 xf86PrintEDID(info); 203 xf86SetDDCproperties(pScrni, info); 204 return info; 205 } 206