summaryrefslogtreecommitdiff
path: root/src/ct_ddc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ct_ddc.c')
-rw-r--r--src/ct_ddc.c282
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;
+}
+
+