diff options
author | Matthieu Herrb <matthieu@cvs.openbsd.org> | 2007-11-24 19:45:09 +0000 |
---|---|---|
committer | Matthieu Herrb <matthieu@cvs.openbsd.org> | 2007-11-24 19:45:09 +0000 |
commit | 621df55ad49646572010dd46760717472a2cf8f4 (patch) | |
tree | a225c44e797ed935a3730d1c30fa22fffc997cea /driver/xf86-video-intel/src/i830_i2c.c | |
parent | 1411a42453b397a8d9010bb67204759600520dcd (diff) |
xf86-video-intel 2.2.0
Diffstat (limited to 'driver/xf86-video-intel/src/i830_i2c.c')
-rw-r--r-- | driver/xf86-video-intel/src/i830_i2c.c | 387 |
1 files changed, 387 insertions, 0 deletions
diff --git a/driver/xf86-video-intel/src/i830_i2c.c b/driver/xf86-video-intel/src/i830_i2c.c new file mode 100644 index 000000000..da8f38e63 --- /dev/null +++ b/driver/xf86-video-intel/src/i830_i2c.c @@ -0,0 +1,387 @@ +/************************************************************************** + + Copyright 2006 Dave Airlie <airlied@linux.ie> + +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +on the rights to use, copy, modify, merge, publish, distribute, sub +license, and/or sell copies of the Software, and to permit persons to whom +the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice (including the next +paragraph) shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +THE COPYRIGHT HOLDERS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86Resources.h" +#include "xf86RAC.h" +#include "xf86cmap.h" +#include "compiler.h" +#include "mibstore.h" +#include "vgaHW.h" +#include "mipointer.h" +#include "micmap.h" +#include "shadowfb.h" +#include <X11/extensions/randr.h> +#include "fb.h" +#include "miscstruct.h" +#include "xf86xv.h" +#include <X11/extensions/Xv.h> +#include "shadow.h" +#include "i830.h" + +#define AIRLIED_I2C 0 + +#if AIRLIED_I2C + +#define I2C_TIMEOUT(x) /*(x)*/ /* Report timeouts */ +#define I2C_TRACE(x) /*(x)*/ /* Report progress */ + +static void i830_setscl(I2CBusPtr b, int state) +{ + ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex]; + I830Ptr pI830 = I830PTR(pScrn); + CARD32 val; + + OUTREG(b->DriverPrivate.uval, + (state ? GPIO_CLOCK_VAL_OUT : 0) | GPIO_CLOCK_DIR_OUT | + GPIO_CLOCK_DIR_MASK | GPIO_CLOCK_VAL_MASK); + val = INREG(b->DriverPrivate.uval); +} + +static void i830_setsda(I2CBusPtr b, int state) +{ + ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex]; + I830Ptr pI830 = I830PTR(pScrn); + CARD32 val; + + OUTREG(b->DriverPrivate.uval, + (state ? GPIO_DATA_VAL_OUT : 0) | GPIO_DATA_DIR_OUT | + GPIO_DATA_DIR_MASK | GPIO_DATA_VAL_MASK); + val = INREG(b->DriverPrivate.uval); +} + +static void i830_getscl(I2CBusPtr b, int *state) +{ + ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex]; + I830Ptr pI830 = I830PTR(pScrn); + CARD32 val; + + OUTREG(b->DriverPrivate.uval, GPIO_CLOCK_DIR_IN | GPIO_CLOCK_DIR_MASK); + OUTREG(b->DriverPrivate.uval, 0); + val = INREG(b->DriverPrivate.uval); + *state = ((val & GPIO_DATA_VAL_IN) != 0); +} + +static int i830_getsda(I2CBusPtr b) + { + ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex]; + I830Ptr pI830 = I830PTR(pScrn); + CARD32 val; + + OUTREG(b->DriverPrivate.uval, GPIO_DATA_DIR_IN | GPIO_DATA_DIR_MASK); + OUTREG(b->DriverPrivate.uval, 0); + val = INREG(b->DriverPrivate.uval); + return ((val & GPIO_DATA_VAL_IN) != 0); +} + +static inline void sdalo(I2CBusPtr b) +{ + i830_setsda(b, 0); + b->I2CUDelay(b, b->RiseFallTime); +} + +static inline void sdahi(I2CBusPtr b) +{ + i830_setsda(b, 1); + b->I2CUDelay(b, b->RiseFallTime); +} + +static inline void scllo(I2CBusPtr b) +{ + i830_setscl(b, 0); + b->I2CUDelay(b, b->RiseFallTime); +} + +static inline int sclhi(I2CBusPtr b, int timeout) +{ + int scl = 0; + int i; + + i830_setscl(b, 1); + b->I2CUDelay(b, b->RiseFallTime); + + for (i = timeout; i > 0; i -= b->RiseFallTime) { + i830_getscl(b, &scl); + if (scl) break; + b->I2CUDelay(b, b->RiseFallTime); + } + + if (i <= 0) { + I2C_TIMEOUT(ErrorF("[I2CRaiseSCL(<%s>, %d) timeout]", + b->BusName, timeout)); + return FALSE; + } + return TRUE; +} + +static Bool +I830I2CGetByte(I2CDevPtr d, I2CByte *data, Bool last) +{ + I2CBusPtr b = d->pI2CBus; + int i, sda; + unsigned char indata = 0; + + sdahi(b); + + for (i = 0; i < 8; i++) { + if (sclhi(b, d->BitTimeout) == FALSE) { + I2C_TRACE(ErrorF("timeout at bit #%d\n", 7-i)); + return FALSE; + }; + indata *= 2; + if (i830_getsda(b)) + indata |= 0x01; + scllo(b); + } + + if (last) { + sdahi(b); + } else { + sdalo(b); + } + + if (sclhi(b, d->BitTimeout) == FALSE) { + sdahi(b); + return FALSE; + }; + + scllo(b); + sdahi(b); + + *data = indata & 0xff; + I2C_TRACE(ErrorF("R%02x ", (int) *data)); + + return TRUE; +} + +static Bool +I830I2CPutByte(I2CDevPtr d, I2CByte c) +{ + Bool r; + int i, scl, sda; + int sb, ack; + I2CBusPtr b = d->pI2CBus; + + for (i = 7; i >= 0; i--) { + sb = c & (1 << i); + i830_setsda(b, sb); + b->I2CUDelay(b, b->RiseFallTime); + + if (sclhi(b, d->ByteTimeout) == FALSE) { + sdahi(b); + return FALSE; + } + + i830_setscl(b, 0); + b->I2CUDelay(b, b->RiseFallTime); + } + sdahi(b); + if (sclhi(b, d->ByteTimeout) == FALSE) { + I2C_TIMEOUT(ErrorF("[I2CPutByte(<%s>, 0x%02x, %d, %d, %d) timeout]", + b->BusName, c, d->BitTimeout, + d->ByteTimeout, d->AcknTimeout)); + return FALSE; + } + ack = i830_getsda(b); + I2C_TRACE(ErrorF("Put byte 0x%02x , getsda() = %d\n", c & 0xff, ack)); + + scllo(b); + return (0 == ack); +} + +static Bool +I830I2CStart(I2CBusPtr b, int timeout) +{ + if (sclhi(b, timeout) == FALSE) + return FALSE; + + sdalo(b); + scllo(b); + + return TRUE; +} + +static void +I830I2CStop(I2CDevPtr d) +{ + I2CBusPtr b = d->pI2CBus; + + sdalo(b); + sclhi(b, d->ByteTimeout); + sdahi(b); +} + +static Bool +I830I2CAddress(I2CDevPtr d, I2CSlaveAddr addr) +{ + if (I830I2CStart(d->pI2CBus, d->StartTimeout)) { + if (I830I2CPutByte(d, addr & 0xFF)) { + if ((addr & 0xF8) != 0xF0 && + (addr & 0xFE) != 0x00) + return TRUE; + + if (I830I2CPutByte(d, (addr >> 8) & 0xFF)) + return TRUE; + } + + I830I2CStop(d); + } + + return FALSE; +} + +#else + +#define I2C_DEBUG 0 + +#if I2C_DEBUG +static Bool first = TRUE; +#endif + +static void +i830I2CGetBits(I2CBusPtr b, int *clock, int *data) +{ + ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex]; + I830Ptr pI830 = I830PTR(pScrn); + CARD32 val; + + val = INREG(b->DriverPrivate.uval); + + /* + * to read valid data, we must have written a 1 to + * the associated bit. Writing a 1 is done by + * tri-stating the bus in PutBits, so we needn't make + * sure that is true here + */ + *data = (val & GPIO_DATA_VAL_IN) != 0; + *clock = (val & GPIO_CLOCK_VAL_IN) != 0; + +#if I2C_DEBUG + ErrorF("Getting %s: %c %c\n", b->BusName, + *clock ? '^' : 'v', + *data ? '^' : 'v'); +#endif +} + +static void +i830I2CPutBits(I2CBusPtr b, int clock, int data) +{ + CARD32 reserved = 0; + CARD32 data_bits, clock_bits; + +#if I2C_DEBUG + int cur_clock, cur_data; +#endif + + ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex]; + I830Ptr pI830 = I830PTR(pScrn); + +#if I2C_DEBUG + i830I2CGetBits(b, &cur_clock, &cur_data); + + if (first) { + ErrorF("%s Debug: C D C D\n", b->BusName); + first = FALSE; + } + + ErrorF("Setting %s 0x%08x to: %c %c\n", b->BusName, + (int)b->DriverPrivate.uval, + clock ? '^' : 'v', + data ? '^' : 'v'); +#endif + + if (!IS_I830(pI830) && !IS_845G(pI830)) { + /* On most chips, these bits must be preserved in software. */ + reserved = INREG(b->DriverPrivate.uval) & + (GPIO_DATA_PULLUP_DISABLE | GPIO_CLOCK_PULLUP_DISABLE); + } + + /* data or clock == 1 means to tristate the bus. otherwise, drive it low */ + if (data) + data_bits = GPIO_DATA_DIR_IN|GPIO_DATA_DIR_MASK; + else + data_bits = GPIO_DATA_DIR_OUT|GPIO_DATA_DIR_MASK|GPIO_DATA_VAL_MASK; + if (clock) + clock_bits = GPIO_CLOCK_DIR_IN|GPIO_CLOCK_DIR_MASK; + else + clock_bits = GPIO_CLOCK_DIR_OUT|GPIO_CLOCK_DIR_MASK|GPIO_CLOCK_VAL_MASK; + + OUTREG(b->DriverPrivate.uval, reserved | data_bits | clock_bits); + POSTING_READ(b->DriverPrivate.uval); +} + +#endif + +/* the i830 has a number of I2C Buses */ +Bool +I830I2CInit(ScrnInfoPtr pScrn, I2CBusPtr *bus_ptr, int i2c_reg, char *name) +{ + I2CBusPtr pI2CBus; + + pI2CBus = xf86CreateI2CBusRec(); + + if (!pI2CBus) + return FALSE; + + pI2CBus->BusName = name; + pI2CBus->scrnIndex = pScrn->scrnIndex; +#if AIRLIED_I2C + pI2CBus->I2CGetByte = I830I2CGetByte; + pI2CBus->I2CPutByte = I830I2CPutByte; + pI2CBus->I2CStart = I830I2CStart; + pI2CBus->I2CStop = I830I2CStop; + pI2CBus->I2CAddress = I830I2CAddress; +#else + pI2CBus->I2CGetBits = i830I2CGetBits; + pI2CBus->I2CPutBits = i830I2CPutBits; +#endif + pI2CBus->DriverPrivate.uval = i2c_reg; + + /* Assume all busses are used for DDCish stuff */ + + /* + * These were set incorrectly in the server pre-1.3, Having + * duplicate settings is sub-optimal, but this lets the driver + * work with older servers + */ + pI2CBus->ByteTimeout = 2200; /* VESA DDC spec 3 p. 43 (+10 %) */ + pI2CBus->StartTimeout = 550; + pI2CBus->BitTimeout = 40; + pI2CBus->AcknTimeout = 40; + pI2CBus->RiseFallTime = 20; + + if (!xf86I2CBusInit(pI2CBus)) + return FALSE; + + *bus_ptr = pI2CBus; + return TRUE; +} |