diff options
Diffstat (limited to 'src/ct_ddc.c')
-rw-r--r-- | src/ct_ddc.c | 282 |
1 files changed, 282 insertions, 0 deletions
diff --git a/src/ct_ddc.c b/src/ct_ddc.c new file mode 100644 index 0000000..0286685 --- /dev/null +++ b/src/ct_ddc.c @@ -0,0 +1,282 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/chips/ct_ddc.c,v 1.8 2001/05/09 19:57:04 dbateman Exp $ */ + +/* All drivers should typically include these */ +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86_ansic.h" + +/* Everything using inb/outb, etc needs "compiler.h" */ +#include "compiler.h" + +/* Drivers for PCI hardware need this */ +#include "xf86PciInfo.h" + +/* Drivers that need to access the PCI config space directly need this */ +#include "xf86Pci.h" + +#include "ct_driver.h" + +static Bool chips_TestI2C(int scrnIndex); +static Bool chips_setI2CBits(I2CBusPtr I2CPtr, ScrnInfoPtr pScrn); + +static unsigned int +chips_ddc1Read(ScrnInfoPtr pScrn) +{ + unsigned char ddc_mask = ((CHIPSPtr)pScrn->driverPrivate)->ddc_mask; + CHIPSPtr cPtr = CHIPSPTR(pScrn); + vgaHWPtr hwp = VGAHWPTR(pScrn); + + register unsigned int tmp; + + while ((hwp->readST01(hwp)) & 0x08){}; + while (!(hwp->readST01(hwp)) & 0x08){}; + tmp = cPtr->readXR(cPtr, 0x63); + return (tmp & ddc_mask); +} + +void +chips_ddc1(ScrnInfoPtr pScrn) +{ + unsigned char FR0B, FR0C, XR62; + unsigned char mask_c = 0x00; + unsigned char val, tmp_val; + int i; + CHIPSPtr cPtr = CHIPSPTR(pScrn); + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Probing for DDC1\n"); + + FR0C = cPtr->readFR(cPtr, 0x0C); + XR62 = cPtr->readXR(cPtr, 0x62); + switch (cPtr->Chipset) { + case CHIPS_CT65550: + cPtr->ddc_mask = 0x1F; /* GPIO 0-4 */ + FR0B = cPtr->readFR(cPtr, 0x0B); + if (!(FR0B & 0x10)) /* GPIO 2 is used as 32 kHz input */ + cPtr->ddc_mask &= 0xFB; + if (cPtr->Bus == ChipsVLB) /* GPIO 3-7 are used as address bits */ + cPtr->ddc_mask &= 0x07; + break; + case CHIPS_CT65554: + case CHIPS_CT65555: + case CHIPS_CT68554: + cPtr->ddc_mask = 0x0F; /* GPIO 0-3 */ + break; + case CHIPS_CT69000: + case CHIPS_CT69030: + cPtr->ddc_mask = 0x9F; /* GPIO 0-4,7? */ + break; + default: + cPtr->ddc_mask = 0x0C; /* GPIO 2,3 */ + break; + } + if (!(FR0C & 0x80)) { /* GPIO 1 is not available */ + mask_c |= 0xC0; + cPtr->ddc_mask &= 0xFE; + } + if (!(FR0C & 0x10)) { /* GPIO 0 is not available */ + mask_c |= 0x18; + cPtr->ddc_mask &= 0xFD; + } + + /* set GPIO 0,1 to read if available */ + cPtr->writeFR(cPtr, 0x0C, (FR0C & mask_c) | (~mask_c & 0x90)); + /* set remaining GPIO to read */ + cPtr->writeXR(cPtr, 0x62, 0x00); + + val = chips_ddc1Read(pScrn); + for (i = 0; i < 70; i++) { + tmp_val = chips_ddc1Read(pScrn); + if (tmp_val != val) + break; + } + cPtr->ddc_mask = val ^ tmp_val; + if (cPtr->ddc_mask) + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "DDC1 found\n"); + else return; + + xf86PrintEDID(xf86DoEDID_DDC1(pScrn->scrnIndex,vgaHWddc1SetSpeed, + chips_ddc1Read)); + + /* restore */ + cPtr->writeFR(cPtr, 0x0C, FR0C); + cPtr->writeXR(cPtr, 0x62, XR62); +} + +static void +chips_I2CGetBits(I2CBusPtr b, int *clock, int *data) +{ + CHIPSI2CPtr pI2C_c = (CHIPSI2CPtr) (b->DriverPrivate.ptr); + unsigned char FR0C, XR62, val; + + FR0C = pI2C_c->cPtr->readFR(pI2C_c->cPtr, 0x0C); + if (pI2C_c->i2cDataBit & 0x01 || pI2C_c->i2cClockBit & 0x01) + FR0C = (FR0C & 0xE7) | 0x10; + if (pI2C_c->i2cDataBit & 0x02 || pI2C_c->i2cClockBit & 0x02) + FR0C = (FR0C & 0x3F) | 0x80; + XR62 = pI2C_c->cPtr->readXR(pI2C_c->cPtr, 0x62); + XR62 &= (~pI2C_c->i2cDataBit) & (~pI2C_c->i2cClockBit); + pI2C_c->cPtr->writeFR(pI2C_c->cPtr, 0x0C, FR0C); + pI2C_c->cPtr->writeXR(pI2C_c->cPtr, 0x62, XR62); + val = pI2C_c->cPtr->readXR(pI2C_c->cPtr, 0x63); + *clock = (val & pI2C_c->i2cClockBit) != 0; + *data = (val & pI2C_c->i2cDataBit) != 0; +} + +static void +chips_I2CPutBits(I2CBusPtr b, int clock, int data) +{ + CHIPSI2CPtr pI2C_c = (CHIPSI2CPtr) (b->DriverPrivate.ptr); + unsigned char FR0C, XR62, val; + + FR0C = pI2C_c->cPtr->readFR(pI2C_c->cPtr, 0x0C); + if (((pI2C_c->i2cDataBit & 0x01) && data) + || ((pI2C_c->i2cClockBit & 0x01) && clock)) + FR0C |= 0x18; + else if ((pI2C_c->i2cDataBit & 0x01) + || (pI2C_c->i2cClockBit & 0x01)) + FR0C |= 0x10; + if (((pI2C_c->i2cDataBit & 0x02) && data) + || ((pI2C_c->i2cClockBit & 0x02) && clock)) + FR0C |= 0xC0; + else if ((pI2C_c->i2cDataBit & 0x02) + || (pI2C_c->i2cClockBit & 0x02)) + FR0C |= 0x80; + XR62 = pI2C_c->cPtr->readXR(pI2C_c->cPtr, 0x62); + XR62 = (XR62 & ~pI2C_c->i2cClockBit) | (clock ? pI2C_c->i2cClockBit : 0); + XR62 = (XR62 & ~pI2C_c->i2cDataBit) | (data ? pI2C_c->i2cDataBit : 0); + pI2C_c->cPtr->writeFR(pI2C_c->cPtr, 0x0C, FR0C); + pI2C_c->cPtr->writeXR(pI2C_c->cPtr, 0x62, XR62); + val = pI2C_c->cPtr->readXR(pI2C_c->cPtr, 0x63); + val = (val & ~pI2C_c->i2cClockBit) | (clock ? pI2C_c->i2cClockBit : 0); + val = (val & ~pI2C_c->i2cDataBit) | (data ? pI2C_c->i2cDataBit : 0); + pI2C_c->cPtr->writeXR(pI2C_c->cPtr, 0x63, val); +} + + +Bool +chips_i2cInit(ScrnInfoPtr pScrn) +{ + CHIPSPtr cPtr = CHIPSPTR(pScrn); + I2CBusPtr I2CPtr; + + I2CPtr = xf86CreateI2CBusRec(); + if(!I2CPtr) return FALSE; + + cPtr->I2C = I2CPtr; + + I2CPtr->BusName = "DDC"; + I2CPtr->scrnIndex = pScrn->scrnIndex; + I2CPtr->I2CPutBits = chips_I2CPutBits; + I2CPtr->I2CGetBits = chips_I2CGetBits; + I2CPtr->DriverPrivate.ptr = xalloc(sizeof(CHIPSI2CRec)); + ((CHIPSI2CPtr)(I2CPtr->DriverPrivate.ptr))->cPtr = cPtr; + + if (!xf86I2CBusInit(I2CPtr)) + return FALSE; + + if (!chips_setI2CBits(I2CPtr, pScrn)) + return FALSE; + + return TRUE; +} + +static Bool +chips_setI2CBits(I2CBusPtr b, ScrnInfoPtr pScrn) +{ + CHIPSPtr cPtr = CHIPSPTR(pScrn); + CHIPSI2CPtr pI2C_c = (CHIPSI2CPtr) (b->DriverPrivate.ptr); + unsigned char FR0B, FR0C; + unsigned char bits, data_bits, clock_bits; + int i,j; + + FR0C = cPtr->readFR(cPtr, 0x0C); + switch (cPtr->Chipset) { + case CHIPS_CT65550: + bits = 0x1F; /* GPIO 0-4 */ + FR0B = cPtr->readFR(cPtr, 0x0B); + if (!(FR0B & 0x10)) /* GPIO 2 is used as 32 kHz input */ + bits &= 0xFB; + pI2C_c->i2cDataBit = 0x01; + pI2C_c->i2cClockBit = 0x02; + if (cPtr->Bus == ChipsVLB) /* GPIO 3-7 are used as address bits */ + bits &= 0x07; + break; + case CHIPS_CT65554: + case CHIPS_CT65555: + case CHIPS_CT68554: + bits = 0x0F; /* GPIO 0-3 */ + pI2C_c->i2cDataBit = 0x04; + pI2C_c->i2cClockBit = 0x08; + break; + case CHIPS_CT69000: + case CHIPS_CT69030: + bits = 0x9F; /* GPIO 0-4,7? */ + pI2C_c->i2cDataBit = 0x04; + pI2C_c->i2cClockBit = 0x08; + break; + default: + bits = 0x0C; /* GPIO 2,3 */ + pI2C_c->i2cDataBit = 0x04; + pI2C_c->i2cClockBit = 0x08; + break; + } + if (!(FR0C & 0x80)) { /* GPIO 1 is not available */ + bits &= 0xFE; + } + if (!(FR0C & 0x10)) { /* GPIO 0 is not available */ + bits &= 0xFD; + } + pI2C_c->i2cClockBit &= bits; + pI2C_c->i2cDataBit &= bits; + /* + * first we test out the "favorite" GPIO bits ie. the ones suggested + * by the data book; if we don't succeed test all other combinations + * of possible GPIO pins as data/clock lines as the manufacturer might + * have its own ideas. + */ + if (chips_TestI2C(pScrn->scrnIndex)) return TRUE; + + data_bits = bits; + pI2C_c->i2cDataBit = 0x01; + for (i = 0; i<8; i++) { + if (data_bits & 0x01) { + clock_bits = bits; + pI2C_c->i2cClockBit = 0x01; + for (j = 0; j<8; j++) { + if (clock_bits & 0x01) + if (chips_TestI2C(pScrn->scrnIndex)) return TRUE; + clock_bits >>= 1; + pI2C_c->i2cClockBit <<= 1; + } + } + data_bits >>= 1; + pI2C_c->i2cDataBit <<= 1; + } + /* + * We haven't found a valid clock/data line combination - that + * doesn't mean there aren't any. We just haven't received an + * answer from the relevant DDC I2C addresses. We'll have to wait + * and see, if this is too restrictive (eg one wants to use I2C + * for something else than DDC we might have to probe more addresses + * or just fall back to the "favorite" GPIO lines. + */ + return FALSE; +} + +static Bool +chips_TestI2C(int scrnIndex) +{ + int i; + I2CBusPtr b; + + b = xf86I2CFindBus(scrnIndex, "DDC"); + if (b == NULL) return FALSE; + else { + for(i = 0xA0; i < 0xA8; i += 2) + if(xf86I2CProbeAddress(b, i)) + return TRUE; + } + return FALSE; +} + + |