xf86-video-intel: Branch 'modesetting' - src/i830_driver.c src/i830_sdvo.c

Eric Anholt anholt at kemper.freedesktop.org
Mon Apr 24 22:22:03 EEST 2006


 src/i830_driver.c |   10 +---
 src/i830_sdvo.c   |  122 ++++++++++++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 116 insertions(+), 16 deletions(-)

New commits:
diff-tree d32514aee4b00b035652830e8b5e6c0b43cf159c (from effab21c3d108fac7a4e28ae4dabb0b5f74a5380)
Author: Eric Anholt <anholt at FreeBSD.org>
Date:   Mon Apr 24 12:21:45 2006 -0700

    Start trying to implement DDC over SDVO.  It's slightly tricky because the
    control bus will reset from DDC mode to internal-registers mode after every
    Stop afer a Start on the DDC bus.  The xf86 DDC code causes multiple Start/Stops
    in one probe.  So, we create a wrapper bus that does the control bus switch at
    every Start.  It's not working yet on my hardware, but I'm pretty sure this is
    the right way to go.

diff --git a/src/i830_driver.c b/src/i830_driver.c
index 3f67106..7c6de99 100644
--- a/src/i830_driver.c
+++ b/src/i830_driver.c
@@ -1462,16 +1462,12 @@ void I830DetectMonitors(ScrnInfoPtr pScr
       break;
       case I830_OUTPUT_SDVO:
 	 if (pI830->output[i].sdvo_drv != NULL) {
-#if 0
-	    I830SDVOSetupDDC(pI830->output[i].sdvo_drv);
-
 	    pI830->output[i].MonInfo = xf86DoEDID_DDC2(pScrn->scrnIndex,
-						       pI830->output[i].pI2CBus);
+						       pI830->output[i].pDDCBus);
 
-	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "DDC SDVO %d, %08X\n", i,
-		       pI830->output[i].pI2CBus->DriverPrivate.uval);
+	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "DDC SDVO %d, %08lX\n", i,
+		       pI830->output[i].pDDCBus->DriverPrivate.uval);
 	    xf86PrintEDID(pI830->output[i].MonInfo);
-#endif
 	 }
 	 break;
       case I830_OUTPUT_UNUSED:
diff --git a/src/i830_sdvo.c b/src/i830_sdvo.c
index 0578461..412d798 100644
--- a/src/i830_sdvo.c
+++ b/src/i830_sdvo.c
@@ -100,21 +100,19 @@ I830SDVOReadInputRegs(I830SDVOPtr s)
     ErrorF("\n");
 }
 
+/* Sets the control bus switch to either point at one of the DDC buses or the
+ * PROM.  It resets from the DDC bus back to internal registers at the next I2C
+ * STOP.  PROM access is terminated by accessing an internal register.
+ */
 Bool
-I830SDVOSetupDDC(I830SDVOPtr s, int enable)
+I830SDVOSetControlBusSwitch(I830SDVOPtr s, CARD8 target)
 {
     memset(s->sdvo_regs, 0, 9);
 
     s->sdvo_regs[SDVO_I2C_OPCODE] = SDVO_CMD_SET_CONTROL_BUS_SWITCH;
-    s->sdvo_regs[SDVO_I2C_ARG_0] = SDVO_CONTROL_BUS_DDC2;
+    s->sdvo_regs[SDVO_I2C_ARG_0] = target;
 
     I830SDVOWriteOutputs(s, 7);
-
-    sReadByte(s, SDVO_I2C_CMD_STATUS, &s->sdvo_regs[SDVO_I2C_CMD_STATUS]);
-
-    ErrorF("SDVO: R: ");
-    ErrorF("%02X ", s->sdvo_regs[SDVO_I2C_CMD_STATUS]);
-    ErrorF("\n");
     return TRUE;
 }
 
@@ -532,6 +530,80 @@ I830SDVOPostSetMode(I830SDVOPtr s, Displ
     return ret;
 }
 
+static Bool
+I830SDVODDCI2CGetByte(I2CDevPtr d, I2CByte *data, Bool last)
+{
+    I830SDVOPtr sdvo = d->pI2CBus->DriverPrivate.ptr;
+    I2CBusPtr i2cbus = sdvo->d.pI2CBus, savebus;
+    Bool ret;
+
+    savebus = d->pI2CBus;
+    d->pI2CBus = i2cbus;
+    ret = i2cbus->I2CGetByte(d, data, last);
+    d->pI2CBus = savebus;
+
+    return ret;
+}
+
+static Bool
+I830SDVODDCI2CPutByte(I2CDevPtr d, I2CByte c)
+{
+    I830SDVOPtr sdvo = d->pI2CBus->DriverPrivate.ptr;
+    I2CBusPtr i2cbus = sdvo->d.pI2CBus, savebus;
+    Bool ret;
+
+    savebus = d->pI2CBus;
+    d->pI2CBus = i2cbus;
+    ret = i2cbus->I2CPutByte(d, c);
+    d->pI2CBus = savebus;
+
+    return ret;
+}
+
+static Bool
+I830SDVODDCI2CStart(I2CBusPtr b, int timeout)
+{
+    I830SDVOPtr sdvo = b->DriverPrivate.ptr;
+    I2CBusPtr i2cbus = sdvo->d.pI2CBus;
+
+    I830SDVOSetControlBusSwitch(sdvo, SDVO_CONTROL_BUS_DDC1);
+    return i2cbus->I2CStart(i2cbus, timeout);
+}
+
+static void
+I830SDVODDCI2CStop(I2CDevPtr d)
+{
+    I830SDVOPtr sdvo = d->pI2CBus->DriverPrivate.ptr;
+    I2CBusPtr i2cbus = sdvo->d.pI2CBus, savebus;
+
+    savebus = d->pI2CBus;
+    d->pI2CBus = i2cbus;
+    i2cbus->I2CStop(d);
+    d->pI2CBus = savebus;
+}
+
+/* It's a shame that xf86i2c.c's I2CAddress() doesn't use the bus's pointers,
+ * so it's useless to us here.
+ */
+static Bool
+I830SDVODDCI2CAddress(I2CDevPtr d, I2CSlaveAddr addr)
+{
+    if (d->pI2CBus->I2CStart(d->pI2CBus, d->StartTimeout)) {
+	if (d->pI2CBus->I2CPutByte(d, addr & 0xFF)) {
+	    if ((addr & 0xF8) != 0xF0 &&
+		(addr & 0xFE) != 0x00)
+		return TRUE;
+
+	    if (d->pI2CBus->I2CPutByte(d, (addr >> 8) & 0xFF))
+		return TRUE;
+	}
+
+	d->pI2CBus->I2CStop(d);
+    }
+
+    return FALSE;
+}
+
 I830SDVOPtr
 I830SDVOInit(ScrnInfoPtr pScrn, int output_index, CARD32 output_device)
 {
@@ -539,6 +611,9 @@ I830SDVOInit(ScrnInfoPtr pScrn, int outp
     I830SDVOPtr sdvo;
     int i;
     unsigned char ch[0x40];
+    I2CBusPtr i2cbus, ddcbus;
+
+    i2cbus = pI830->output[output_index].pI2CBus;
 
     sdvo = xcalloc(1, sizeof(I830SDVORec));
     if (sdvo == NULL)
@@ -551,7 +626,7 @@ I830SDVOInit(ScrnInfoPtr pScrn, int outp
 	sdvo->d.DevName = "SDVO Controller C";
 	sdvo->d.SlaveAddr = 0x72;
     }
-    sdvo->d.pI2CBus = pI830->output[output_index].pI2CBus;
+    sdvo->d.pI2CBus = i2cbus;
     sdvo->d.DriverPrivate.ptr = sdvo;
     sdvo->output_device = output_device;
 
@@ -563,9 +638,38 @@ I830SDVOInit(ScrnInfoPtr pScrn, int outp
 	return NULL;
     }
 
+    /* Set up our wrapper I2C bus for DDC.  It acts just like the regular I2C
+     * bus, except that it does the control bus switch to DDC mode before every
+     * Start.  While we only need to do it at Start after every Stop after a
+     * Start, extra attempts should be harmless.
+     */
+    ddcbus = xf86CreateI2CBusRec();
+    if (ddcbus == NULL) {
+	xf86DestroyI2CDevRec(&sdvo->d, 0);
+	xfree(sdvo);
+	return NULL;
+    }
+    ddcbus->BusName = "SDVO DDC Bus";
+    ddcbus->scrnIndex = i2cbus->scrnIndex;
+    ddcbus->I2CGetByte = I830SDVODDCI2CGetByte;
+    ddcbus->I2CPutByte = I830SDVODDCI2CPutByte;
+    ddcbus->I2CStart = I830SDVODDCI2CStart;
+    ddcbus->I2CStop = I830SDVODDCI2CStop;
+    ddcbus->I2CAddress = I830SDVODDCI2CAddress;
+    ddcbus->DriverPrivate.ptr = sdvo;
+    if (!xf86I2CBusInit(ddcbus)) {
+	xf86DestroyI2CDevRec(&sdvo->d, 0);
+	xfree(sdvo);
+	return NULL;
+    }
+
+    pI830->output[output_index].pDDCBus = ddcbus;
+
     /* Read the regs to test if we can talk to the device */
     for (i = 0; i < 0x40; i++) {
 	if (!sReadByte(sdvo, i, &ch[i])) {
+	    xf86DestroyI2CBusRec(pI830->output[output_index].pDDCBus, FALSE,
+		FALSE);
 	    xf86DestroyI2CDevRec(&sdvo->d, 0);
 	    xfree(sdvo);
 	    return NULL;



More information about the xorg-commit mailing list