atimach64i2c.c revision 1b12faf6
1/* 2 * Copyright 2003 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org 3 * 4 * Permission to use, copy, modify, distribute, and sell this software and its 5 * documentation for any purpose is hereby granted without fee, provided that 6 * the above copyright notice appear in all copies and that both that copyright 7 * notice and this permission notice appear in supporting documentation, and 8 * that the name of Marc Aurele La France not be used in advertising or 9 * publicity pertaining to distribution of the software without specific, 10 * written prior permission. Marc Aurele La France makes no representations 11 * about the suitability of this software for any purpose. It is provided 12 * "as-is" without express or implied warranty. 13 * 14 * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO 16 * EVENT SHALL MARC AURELE LA FRANCE BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 20 * PERFORMANCE OF THIS SOFTWARE. 21 */ 22 23#ifdef HAVE_CONFIG_H 24#include "config.h" 25#endif 26 27#include "ati.h" 28#include "atichip.h" 29#include "atii2c.h" 30#include "atimach64i2c.h" 31#include "atimach64io.h" 32#include "atituner.h" 33 34/* MPP_CONFIG register values */ 35#define MPP_INIT pATI->NewHW.mpp_config 36 37#define MPP_WRITE (MPP_INIT ) 38#define MPP_WRITEINC (MPP_INIT | (MPP_AUTO_INC_EN )) 39#define MPP_READ (MPP_INIT | ( MPP_BUFFER_MODE_PREFETCH)) 40#define MPP_READINC (MPP_INIT | (MPP_AUTO_INC_EN | MPP_BUFFER_MODE_PREFETCH)) 41 42/* 43 * ATIMach64MPPWaitForIdle -- 44 * 45 * Support function to wait for the Multimedia Peripheral Port to become idle. 46 * Currently, this function's return value indicates whether or not the port 47 * became idle within 512 polling iterations. For now, this value is ignored 48 * by the rest of the code, but might be used in the future. 49 */ 50static Bool 51ATIMach64MPPWaitForIdle 52( 53 ATIPtr pATI 54) 55{ 56 CARD32 Count = 0x0200; 57 58 while (in8(MPP_CONFIG + 3) & GetByte(MPP_BUSY, 3)) 59 { 60 if (!--Count) 61 return FALSE; 62 usleep(1); /* XXX Excessive? */ 63 } 64 65 return TRUE; 66} 67 68/* 69 * ATIMach64MPPSetAddress -- 70 * 71 * Sets a 16-bit ImpacTV address on the Multimedia Peripheral Port. 72 */ 73static void 74ATIMach64MPPSetAddress 75( 76 ATIPtr pATI, 77 CARD16 Address 78) 79{ 80 ATIMach64MPPWaitForIdle(pATI); 81 outr(MPP_CONFIG, MPP_WRITEINC); 82 outr(MPP_ADDR, 0x00000008U); 83 out8(MPP_DATA, (CARD8)Address); 84 ATIMach64MPPWaitForIdle(pATI); 85 out8(MPP_DATA, (CARD8)(Address >> 8)); 86 ATIMach64MPPWaitForIdle(pATI); 87 outr(MPP_CONFIG, MPP_WRITE); 88 outr(MPP_ADDR, 0x00000018U); 89 ATIMach64MPPWaitForIdle(pATI); 90} 91 92/* 93 * ATIMach64ImpacTVProbe -- 94 * 95 * This probes for an ImpacTV chip and returns its chip ID, or 0. 96 */ 97static int 98ATIMach64ImpacTVProbe 99( 100 int iScreen, 101 ATIPtr pATI 102) 103{ 104 CARD8 ChipID = 0; 105 106 /* Assume ATIModePreInit() has already been called */ 107 outr(MPP_STROBE_SEQ, pATI->NewHW.mpp_strobe_seq); 108 outr(TVO_CNTL, pATI->NewHW.tvo_cntl); 109 110 outr(MPP_CONFIG, MPP_READ); 111 ATIMach64MPPWaitForIdle(pATI); 112 outr(MPP_ADDR, 0x0000000AU); 113 if (!(ChipID = in8(MPP_DATA))) 114 { 115 ATIMach64MPPWaitForIdle(pATI); 116 outr(MPP_ADDR, 0x00000023U); 117 if ((ChipID = in8(MPP_DATA)) != 0x54U) 118 { 119 ATIMach64MPPWaitForIdle(pATI); 120 outr(MPP_ADDR, 0x0000000BU); 121 ChipID = in8(MPP_DATA); 122 } 123 } 124 ATIMach64MPPWaitForIdle(pATI); 125 outr(MPP_CONFIG, MPP_WRITE); 126 127 if (ChipID) 128 xf86DrvMsg(iScreen, X_PROBED, "ImpacTV chip ID 0x%02X detected.\n", 129 ChipID); 130 131 return (int)(CARD16)ChipID; 132} 133 134/* 135 * ATIMach64ImpacTVSetBits -- 136 * 137 * Controls I2C SDA and SCL lines through ImpacTV. 138 */ 139static void 140ATIMach64ImpacTVSetBits 141( 142 ATII2CPtr pATII2C, 143 ATIPtr pATI, 144 CARD32 Bits 145) 146{ 147 pATII2C->I2CCur = Bits; 148 149 ATIMach64MPPSetAddress(pATI, IT_I2C_CNTL); 150 151 outr(MPP_CONFIG, MPP_WRITE); 152 153 out8(MPP_DATA, (CARD8)Bits); 154 155 ATIMach64MPPWaitForIdle(pATI); 156} 157 158/* 159 * ATIMach64ImpacTVGetBits -- 160 * 161 * Returns the status of an ImpacTV's I2C control lines. 162 */ 163static CARD32 164ATIMach64ImpacTVGetBits 165( 166 ATIPtr pATI 167) 168{ 169 ATIMach64MPPSetAddress(pATI, IT_I2C_CNTL); 170 171 outr(MPP_CONFIG, MPP_READ); 172 173 ATIMach64MPPWaitForIdle(pATI); 174 175 return in8(MPP_DATA); 176} 177 178/* 179 * ATIMach64I2C_CNTLSetBits -- 180 * 181 * Controls SDA and SCL lines through a 3D Rage Pro's hardware assisted I2C. 182 */ 183static void 184ATIMach64I2C_CNTLSetBits 185( 186 ATII2CPtr pATII2C, 187 ATIPtr pATI, 188 CARD32 Bits 189) 190{ 191 pATII2C->I2CCur = Bits; 192 193 out8(I2C_CNTL_0 + 1, (CARD8)Bits); 194} 195 196/* 197 * ATIMach64I2C_CNTLGetBits -- 198 * 199 * Returns the status of a 3D Rage Pro's hardware assisted I2C control lines. 200 */ 201static CARD32 202ATIMach64I2C_CNTLGetBits 203( 204 ATIPtr pATI 205) 206{ 207 return in8(I2C_CNTL_0 + 1); 208} 209 210/* 211 * ATIMach64GP_IOSetBits -- 212 * 213 * Controls SDA and SCL control lines through a Mach64's GP_IO register. 214 */ 215static void 216ATIMach64GP_IOSetBits 217( 218 ATII2CPtr pATII2C, 219 ATIPtr pATI, 220 CARD32 Bits 221) 222{ 223 pATII2C->I2CCur = Bits; 224 225 outr(GP_IO, Bits); 226} 227 228/* 229 * ATIMach64GP_IOGetBits -- 230 * 231 * Returns the status of I2C control lines through a Mach64's GP_IO register. 232 */ 233static CARD32 234ATIMach64GP_IOGetBits 235( 236 ATIPtr pATI 237) 238{ 239 return inr(GP_IO); 240} 241 242#define GPIO1_MASK \ 243 (DAC_GIO_STATE_1 | DAC_GIO_DIR_1) 244#define GPIO2_MASK \ 245 (GEN_GIO2_DATA_OUT | GEN_GIO2_DATA_IN | GEN_GIO2_WRITE) 246 247/* 248 * ATIMach64DAC_GENSetBits -- 249 * 250 * Controls SDA and SCL control lines through a Mach64's GEN_TEST_CNTL and 251 * DAC_CNTL registers. 252 */ 253static void 254ATIMach64DAC_GENSetBits 255( 256 ATII2CPtr pATII2C, 257 ATIPtr pATI, 258 CARD32 Bits 259) 260{ 261 CARD32 tmp; 262 263 pATII2C->I2CCur = Bits; 264 265 tmp = inr(DAC_CNTL) & ~GPIO1_MASK; 266 outr(DAC_CNTL, tmp | (Bits & GPIO1_MASK)); 267 tmp = inr(GEN_TEST_CNTL) & ~GPIO2_MASK; 268 outr(GEN_TEST_CNTL, tmp | (Bits & GPIO2_MASK)); 269} 270 271/* 272 * ATIMach64DAC_GENGetBits -- 273 * 274 * Returns the status of I2C control lines through a Mach64's GEN_TEST_CNTL and 275 * DAC_CNTL registers. 276 */ 277static CARD32 278ATIMach64DAC_GENGetBits 279( 280 ATIPtr pATI 281) 282{ 283 return (inr(DAC_CNTL) & GPIO1_MASK) | (inr(GEN_TEST_CNTL) & GPIO2_MASK); 284} 285 286/* 287 * ATITVAddOnProbe -- 288 * 289 * Probe for an ATI-TV add-on card at specific addresses on an I2C bus. 290 */ 291static Bool 292ATITVAddOnProbe 293( 294 ScrnInfoPtr pScreenInfo, 295 ATIPtr pATI, 296 I2CBusPtr pI2CBus 297) 298{ 299 I2CDevPtr pI2CDev = xnfcalloc(1, SizeOf(I2CDevRec)); 300 int Index; 301 I2CByte tmp; 302 303 static const CARD8 ATITVAddOnAddresses[] = {0x70, 0x40, 0x78, 0x72, 0x42}; 304 305 pI2CDev->DevName = "ATI-TV Add-on"; 306 pI2CDev->pI2CBus = pI2CBus; 307 pI2CDev->StartTimeout = pI2CBus->StartTimeout; 308 pI2CDev->BitTimeout = pI2CBus->BitTimeout; 309 pI2CDev->AcknTimeout = pI2CBus->AcknTimeout; 310 pI2CDev->ByteTimeout = pI2CBus->ByteTimeout; 311 312 for (Index = 0; Index < NumberOf(ATITVAddOnAddresses); Index++) 313 { 314 pI2CDev->SlaveAddr = ATITVAddOnAddresses[Index]; 315 316 if (xf86I2CFindDev(pI2CBus, pI2CDev->SlaveAddr)) 317 continue; 318 319 tmp = 0xFFU; 320 321 if (!(*pI2CBus->I2CWriteRead)(pI2CDev, &tmp, 1, NULL, 0) || 322 !(*pI2CBus->I2CWriteRead)(pI2CDev, NULL, 0, &tmp, 1) || 323 (tmp == 0xFFU) || ((tmp = tmp & 0x1FU) == /*ATI_TUNER_NONE*/0)) 324 continue; 325 326 if (!xf86I2CDevInit(pI2CDev)) 327 { 328 xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, 329 "Failed to register I2C device for ATI-TV add-on.\n"); 330 break; 331 } 332 333 if (pATI->Tuner != tmp) 334 { 335 if (pATI->Tuner != ATI_TUNER_NONE) 336 xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, 337 "Tuner type mismatch: BIOS 0x%x, ATI-TV 0x%x.\n", 338 pATI->Tuner, tmp); 339 340 pATI->Tuner = tmp; 341 } 342 343 xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED, 344 "%s tuner detected on ATI-TV add-on adapter at I2C bus address" 345 " 0x%2x.\n", ATITuners[pATI->Tuner].name, pI2CDev->SlaveAddr); 346 347 return TRUE; 348 } 349 350 free(pI2CDev); 351 return FALSE; 352} 353 354/* 355 * ATIMach64I2CPreInit -- 356 * 357 * This function potentially allocates an I2CBusRec and initialises it with 358 * ATI-specific and Mach64-specific information. 359 */ 360void 361ATIMach64I2CPreInit 362( 363 ScrnInfoPtr pScreenInfo, 364 ATIPtr pATI 365) 366{ 367 I2CBusPtr pI2CBus; 368 ATII2CPtr pATII2C; 369 370 if ((pATI->Chip < ATI_CHIP_264CT) || (pATI->Chip >= ATI_CHIP_Mach64)) 371 return; 372 373 /* Create an I2CBusRec and generically prime it */ 374 if (!(pI2CBus = ATICreateI2CBusRec(pScreenInfo->scrnIndex, pATI, "Mach64"))) 375 return; 376 377 pATII2C = pI2CBus->DriverPrivate.ptr; 378 379 switch (pATI->Chip) 380 { 381 case ATI_CHIP_264GTPRO: 382 case ATI_CHIP_264LTPRO: 383 case ATI_CHIP_264XL: 384 case ATI_CHIP_MOBILITY: 385 /* 386 * These have I2C-specific registers. Assume older I2C access 387 * mechanisms are inoperative. 388 */ 389 pATII2C->I2CSetBits = ATIMach64I2C_CNTLSetBits; 390 pATII2C->I2CGetBits = ATIMach64I2C_CNTLGetBits; 391 pATII2C->SCLDir = pATII2C->SDADir = 0; 392 pATII2C->SCLGet = pATII2C->SCLSet = GetByte(I2C_CNTL_SCL, 1); 393 pATII2C->SDAGet = pATII2C->SDASet = GetByte(I2C_CNTL_SDA, 1); 394 395 out8(I2C_CNTL_1 + 2, GetByte(I2C_SEL, 2)); 396 out8(I2C_CNTL_0 + 0, 397 GetByte(I2C_CNTL_STAT | I2C_CNTL_HPTR_RST, 0)); 398 break; 399 400 case ATI_CHIP_264VTB: 401 case ATI_CHIP_264GTB: 402 case ATI_CHIP_264VT3: 403 case ATI_CHIP_264GTDVD: 404 case ATI_CHIP_264LT: 405 case ATI_CHIP_264VT4: 406 case ATI_CHIP_264GT2C: 407 /* If an ImpacTV chip is found, use it to provide I2C access */ 408 if (ATIMach64ImpacTVProbe(pScreenInfo->scrnIndex, pATI)) 409 { 410 pATII2C->I2CSetBits = ATIMach64ImpacTVSetBits; 411 pATII2C->I2CGetBits = ATIMach64ImpacTVGetBits; 412 pATII2C->SCLDir = IT_SCL_DIR; 413 pATII2C->SCLGet = IT_SCL_GET; 414 pATII2C->SCLSet = IT_SCL_SET; 415 pATII2C->SDADir = IT_SDA_DIR; 416 pATII2C->SDAGet = IT_SDA_GET; 417 pATII2C->SDASet = IT_SDA_SET; 418 419 ATIMach64MPPSetAddress(pATI, IT_I2C_CNTL); 420 outr(MPP_CONFIG, MPP_WRITEINC); 421 out8(MPP_DATA, 0x00U); 422 out8(MPP_DATA, 0x55U); 423 out8(MPP_DATA, 0x00U); 424 out8(MPP_DATA, 0x00U); 425 ATIMach64MPPWaitForIdle(pATI); 426 break; 427 } 428 /* Otherwise, fall through to the older case */ 429 430 case ATI_CHIP_264VT: 431 case ATI_CHIP_264GT: 432 /* First try GIO pins 11 (clock) and 4 (data) */ 433 pATII2C->I2CSetBits = ATIMach64GP_IOSetBits; 434 pATII2C->I2CGetBits = ATIMach64GP_IOGetBits; 435 pATII2C->SCLDir = GP_IO_DIR_B; 436 pATII2C->SCLGet = pATII2C->SCLSet = GP_IO_B; 437 pATII2C->SDADir = GP_IO_DIR_4; 438 pATII2C->SDAGet = pATII2C->SDASet = GP_IO_4; 439 440 if (ATITVAddOnProbe(pScreenInfo, pATI, pI2CBus)) 441 break; 442 443 /* Next, try pins 10 (clock) and 12 (data) */ 444 pATII2C->SCLDir = GP_IO_DIR_A; 445 pATII2C->SCLGet = pATII2C->SCLSet = GP_IO_A; 446 pATII2C->SDADir = GP_IO_DIR_C; 447 pATII2C->SDAGet = pATII2C->SDASet = GP_IO_C; 448 449 if (ATITVAddOnProbe(pScreenInfo, pATI, pI2CBus)) 450 break; 451 /* Otherwise, fall back to ATI's first I2C implementation */ 452 453 default: 454 /* 455 * First generation integrated controllers access GIO pin 1 (clock) 456 * though DAC_CNTL, and pin 2 (data) through GEN_TEST_CNTL. 457 */ 458 pATII2C->I2CSetBits = ATIMach64DAC_GENSetBits; 459 pATII2C->I2CGetBits = ATIMach64DAC_GENGetBits; 460 pATII2C->SCLDir = DAC_GIO_DIR_1; 461 pATII2C->SCLGet = pATII2C->SCLSet = DAC_GIO_STATE_1; 462 pATII2C->SDADir = GEN_GIO2_WRITE; 463 pATII2C->SDAGet = GEN_GIO2_DATA_IN; 464 pATII2C->SDASet = GEN_GIO2_DATA_OUT; 465 466 (void)ATITVAddOnProbe(pScreenInfo, pATI, pI2CBus); 467 break; 468 } 469} 470