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