i830_i2c.c revision fa225cbc
1/************************************************************************** 2 3 Copyright 2006 Dave Airlie <airlied@linux.ie> 4 5All Rights Reserved. 6 7Permission is hereby granted, free of charge, to any person obtaining a 8copy of this software and associated documentation files (the "Software"), 9to deal in the Software without restriction, including without limitation 10on the rights to use, copy, modify, merge, publish, distribute, sub 11license, and/or sell copies of the Software, and to permit persons to whom 12the Software is furnished to do so, subject to the following conditions: 13 14The above copyright notice and this permission notice (including the next 15paragraph) shall be included in all copies or substantial portions of the 16Software. 17 18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 21THE COPYRIGHT HOLDERS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 22DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 23OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 24USE OR OTHER DEALINGS IN THE SOFTWARE. 25 26**************************************************************************/ 27 28#ifdef HAVE_CONFIG_H 29#include "config.h" 30#endif 31 32#include "xf86.h" 33#include "xf86_OSproc.h" 34#include "xf86cmap.h" 35#include "compiler.h" 36#include "mibstore.h" 37#include "vgaHW.h" 38#include "mipointer.h" 39#include "micmap.h" 40#include "shadowfb.h" 41#include <X11/extensions/randr.h> 42#include "fb.h" 43#include "miscstruct.h" 44#include "xf86xv.h" 45#include <X11/extensions/Xv.h> 46#include "shadow.h" 47#include "i830.h" 48 49#define AIRLIED_I2C 0 50 51#if AIRLIED_I2C 52 53#define I2C_TIMEOUT(x) /*(x)*/ /* Report timeouts */ 54#define I2C_TRACE(x) /*(x)*/ /* Report progress */ 55 56static void i830_setscl(I2CBusPtr b, int state) 57{ 58 ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex]; 59 I830Ptr pI830 = I830PTR(pScrn); 60 uint32_t val; 61 62 OUTREG(b->DriverPrivate.uval, 63 (state ? GPIO_CLOCK_VAL_OUT : 0) | GPIO_CLOCK_DIR_OUT | 64 GPIO_CLOCK_DIR_MASK | GPIO_CLOCK_VAL_MASK); 65 val = INREG(b->DriverPrivate.uval); 66} 67 68static void i830_setsda(I2CBusPtr b, int state) 69{ 70 ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex]; 71 I830Ptr pI830 = I830PTR(pScrn); 72 uint32_t val; 73 74 OUTREG(b->DriverPrivate.uval, 75 (state ? GPIO_DATA_VAL_OUT : 0) | GPIO_DATA_DIR_OUT | 76 GPIO_DATA_DIR_MASK | GPIO_DATA_VAL_MASK); 77 val = INREG(b->DriverPrivate.uval); 78} 79 80static void i830_getscl(I2CBusPtr b, int *state) 81{ 82 ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex]; 83 I830Ptr pI830 = I830PTR(pScrn); 84 uint32_t val; 85 86 OUTREG(b->DriverPrivate.uval, GPIO_CLOCK_DIR_IN | GPIO_CLOCK_DIR_MASK); 87 OUTREG(b->DriverPrivate.uval, 0); 88 val = INREG(b->DriverPrivate.uval); 89 *state = ((val & GPIO_CLOCK_VAL_IN) != 0); 90} 91 92static int i830_getsda(I2CBusPtr b) 93 { 94 ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex]; 95 I830Ptr pI830 = I830PTR(pScrn); 96 uint32_t val; 97 98 OUTREG(b->DriverPrivate.uval, GPIO_DATA_DIR_IN | GPIO_DATA_DIR_MASK); 99 OUTREG(b->DriverPrivate.uval, 0); 100 val = INREG(b->DriverPrivate.uval); 101 return ((val & GPIO_DATA_VAL_IN) != 0); 102} 103 104static inline void sdalo(I2CBusPtr b) 105{ 106 i830_setsda(b, 0); 107 b->I2CUDelay(b, b->RiseFallTime); 108} 109 110static inline void sdahi(I2CBusPtr b) 111{ 112 i830_setsda(b, 1); 113 b->I2CUDelay(b, b->RiseFallTime); 114} 115 116static inline void scllo(I2CBusPtr b) 117{ 118 i830_setscl(b, 0); 119 b->I2CUDelay(b, b->RiseFallTime); 120} 121 122static inline int sclhi(I2CBusPtr b, int timeout) 123{ 124 int scl = 0; 125 int i; 126 127 i830_setscl(b, 1); 128 b->I2CUDelay(b, b->RiseFallTime); 129 130 for (i = timeout; i > 0; i -= b->RiseFallTime) { 131 i830_getscl(b, &scl); 132 if (scl) break; 133 b->I2CUDelay(b, b->RiseFallTime); 134 } 135 136 if (i <= 0) { 137 I2C_TIMEOUT(ErrorF("[I2CRaiseSCL(<%s>, %d) timeout]", 138 b->BusName, timeout)); 139 return FALSE; 140 } 141 return TRUE; 142} 143 144static Bool 145I830I2CGetByte(I2CDevPtr d, I2CByte *data, Bool last) 146{ 147 I2CBusPtr b = d->pI2CBus; 148 int i, sda; 149 unsigned char indata = 0; 150 151 sdahi(b); 152 153 for (i = 0; i < 8; i++) { 154 if (sclhi(b, d->BitTimeout) == FALSE) { 155 I2C_TRACE(ErrorF("timeout at bit #%d\n", 7-i)); 156 return FALSE; 157 }; 158 indata *= 2; 159 if (i830_getsda(b)) 160 indata |= 0x01; 161 scllo(b); 162 } 163 164 if (last) { 165 sdahi(b); 166 } else { 167 sdalo(b); 168 } 169 170 if (sclhi(b, d->BitTimeout) == FALSE) { 171 sdahi(b); 172 return FALSE; 173 }; 174 175 scllo(b); 176 sdahi(b); 177 178 *data = indata & 0xff; 179 I2C_TRACE(ErrorF("R%02x ", (int) *data)); 180 181 return TRUE; 182} 183 184static Bool 185I830I2CPutByte(I2CDevPtr d, I2CByte c) 186{ 187 Bool r; 188 int i, scl, sda; 189 int sb, ack; 190 I2CBusPtr b = d->pI2CBus; 191 192 for (i = 7; i >= 0; i--) { 193 sb = c & (1 << i); 194 i830_setsda(b, sb); 195 b->I2CUDelay(b, b->RiseFallTime); 196 197 if (sclhi(b, d->ByteTimeout) == FALSE) { 198 sdahi(b); 199 return FALSE; 200 } 201 202 i830_setscl(b, 0); 203 b->I2CUDelay(b, b->RiseFallTime); 204 } 205 sdahi(b); 206 if (sclhi(b, d->ByteTimeout) == FALSE) { 207 I2C_TIMEOUT(ErrorF("[I2CPutByte(<%s>, 0x%02x, %d, %d, %d) timeout]", 208 b->BusName, c, d->BitTimeout, 209 d->ByteTimeout, d->AcknTimeout)); 210 return FALSE; 211 } 212 ack = i830_getsda(b); 213 I2C_TRACE(ErrorF("Put byte 0x%02x , getsda() = %d\n", c & 0xff, ack)); 214 215 scllo(b); 216 return (0 == ack); 217} 218 219static Bool 220I830I2CStart(I2CBusPtr b, int timeout) 221{ 222 if (sclhi(b, timeout) == FALSE) 223 return FALSE; 224 225 sdalo(b); 226 scllo(b); 227 228 return TRUE; 229} 230 231static void 232I830I2CStop(I2CDevPtr d) 233{ 234 I2CBusPtr b = d->pI2CBus; 235 236 sdalo(b); 237 sclhi(b, d->ByteTimeout); 238 sdahi(b); 239} 240 241static Bool 242I830I2CAddress(I2CDevPtr d, I2CSlaveAddr addr) 243{ 244 if (I830I2CStart(d->pI2CBus, d->StartTimeout)) { 245 if (I830I2CPutByte(d, addr & 0xFF)) { 246 if ((addr & 0xF8) != 0xF0 && 247 (addr & 0xFE) != 0x00) 248 return TRUE; 249 250 if (I830I2CPutByte(d, (addr >> 8) & 0xFF)) 251 return TRUE; 252 } 253 254 I830I2CStop(d); 255 } 256 257 return FALSE; 258} 259 260#else 261 262#define I2C_DEBUG 0 263 264#if I2C_DEBUG 265static Bool first = TRUE; 266#endif 267 268static void 269i830I2CGetBits(I2CBusPtr b, int *clock, int *data) 270{ 271 ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex]; 272 I830Ptr pI830 = I830PTR(pScrn); 273 uint32_t val; 274 275 val = INREG(b->DriverPrivate.uval); 276 277 /* 278 * to read valid data, we must have written a 1 to 279 * the associated bit. Writing a 1 is done by 280 * tri-stating the bus in PutBits, so we needn't make 281 * sure that is true here 282 */ 283 *data = (val & GPIO_DATA_VAL_IN) != 0; 284 *clock = (val & GPIO_CLOCK_VAL_IN) != 0; 285 286#if I2C_DEBUG 287 ErrorF("Getting %s: %c %c\n", b->BusName, 288 *clock ? '^' : 'v', 289 *data ? '^' : 'v'); 290#endif 291} 292 293static void 294i830I2CPutBits(I2CBusPtr b, int clock, int data) 295{ 296 uint32_t reserved = 0; 297 uint32_t data_bits, clock_bits; 298 299#if I2C_DEBUG 300 int cur_clock, cur_data; 301#endif 302 303 ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex]; 304 I830Ptr pI830 = I830PTR(pScrn); 305 306#if I2C_DEBUG 307 i830I2CGetBits(b, &cur_clock, &cur_data); 308 309 if (first) { 310 ErrorF("%s Debug: C D C D\n", b->BusName); 311 first = FALSE; 312 } 313 314 ErrorF("Setting %s 0x%08x to: %c %c\n", b->BusName, 315 (int)b->DriverPrivate.uval, 316 clock ? '^' : 'v', 317 data ? '^' : 'v'); 318#endif 319 320 if (!IS_I830(pI830) && !IS_845G(pI830)) { 321 /* On most chips, these bits must be preserved in software. */ 322 reserved = INREG(b->DriverPrivate.uval) & 323 (GPIO_DATA_PULLUP_DISABLE | GPIO_CLOCK_PULLUP_DISABLE); 324 } 325 326 /* data or clock == 1 means to tristate the bus. otherwise, drive it low */ 327 if (data) 328 data_bits = GPIO_DATA_DIR_IN|GPIO_DATA_DIR_MASK; 329 else 330 data_bits = GPIO_DATA_DIR_OUT|GPIO_DATA_DIR_MASK|GPIO_DATA_VAL_MASK; 331 if (clock) 332 clock_bits = GPIO_CLOCK_DIR_IN|GPIO_CLOCK_DIR_MASK; 333 else 334 clock_bits = GPIO_CLOCK_DIR_OUT|GPIO_CLOCK_DIR_MASK|GPIO_CLOCK_VAL_MASK; 335 336 OUTREG(b->DriverPrivate.uval, reserved | data_bits | clock_bits); 337 POSTING_READ(b->DriverPrivate.uval); 338} 339 340#endif 341 342/* the i830 has a number of I2C Buses */ 343Bool 344I830I2CInit(ScrnInfoPtr pScrn, I2CBusPtr *bus_ptr, int i2c_reg, char *name) 345{ 346 I2CBusPtr pI2CBus; 347 I830Ptr pI830 = I830PTR(pScrn); 348 349 pI2CBus = xf86CreateI2CBusRec(); 350 351 if (!pI2CBus) 352 return FALSE; 353 354 pI2CBus->BusName = name; 355 pI2CBus->scrnIndex = pScrn->scrnIndex; 356#if AIRLIED_I2C 357 pI2CBus->I2CGetByte = I830I2CGetByte; 358 pI2CBus->I2CPutByte = I830I2CPutByte; 359 pI2CBus->I2CStart = I830I2CStart; 360 pI2CBus->I2CStop = I830I2CStop; 361 pI2CBus->I2CAddress = I830I2CAddress; 362#else 363 pI2CBus->I2CGetBits = i830I2CGetBits; 364 pI2CBus->I2CPutBits = i830I2CPutBits; 365#endif 366 pI2CBus->DriverPrivate.uval = i2c_reg; 367 368 /* Assume all busses are used for DDCish stuff */ 369 370 /* 371 * These were set incorrectly in the server pre-1.3, Having 372 * duplicate settings is sub-optimal, but this lets the driver 373 * work with older servers 374 */ 375 pI2CBus->ByteTimeout = 2200; /* VESA DDC spec 3 p. 43 (+10 %) */ 376 pI2CBus->StartTimeout = 550; 377 pI2CBus->BitTimeout = 40; 378 pI2CBus->AcknTimeout = 40; 379 pI2CBus->RiseFallTime = 20; 380 381 /* Disable the GMBUS, which we won't use. If it is left enabled (for 382 * example, by Mac Mini EFI initialization), GPIO access to the pins it 383 * uses gets disabled. 384 */ 385 OUTREG(GMBUS0, 0); 386 387 if (!xf86I2CBusInit(pI2CBus)) 388 return FALSE; 389 390 *bus_ptr = pI2CBus; 391 return TRUE; 392} 393