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