xf86-video-intel: Branch 'display-port' - 3 commits - src/i830_dp.c

Keith Packard keithp at kemper.freedesktop.org
Wed Mar 18 21:01:22 PDT 2009


 src/i830_dp.c |  234 ++++++++++++++++++++++++++--------------------------------
 1 file changed, 106 insertions(+), 128 deletions(-)

New commits:
commit f2701129303dd97b17f1a170408d5dc946a08447
Author: Keith Packard <keithp at keithp.com>
Date:   Wed Mar 18 20:54:47 2009 -0700

    Use the unified Display Port aux_ch i2c transaction function everywhere
    
    Each transaction had custom code which looked very similar. Replace that
    with a single function which is generalized to handle each case correctly.
    
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/src/i830_dp.c b/src/i830_dp.c
index d0fc8cc..fc1ddff 100644
--- a/src/i830_dp.c
+++ b/src/i830_dp.c
@@ -251,12 +251,19 @@ i830_dp_aux_native_read(ScrnInfoPtr pScrn, uint32_t output_reg,
 }
 
 /* Run a single AUX_CH I2C transaction, writing/reading data as necessary */
+
+enum dp_aux_i2c_mode {
+    aux_i2c_start,
+    aux_i2c_write,
+    aux_i2c_read,
+    aux_i2c_stop
+};
+
 static int
 i830_dp_aux_i2c_transaction(ScrnInfoPtr pScrn, uint32_t output_reg,
 			    uint16_t address,
-			    uint8_t write_byte, Bool has_write_data,
-			    uint8_t *read_byte, Bool has_read_data,
-			    Bool middle_of_transaction)
+			    enum dp_aux_i2c_mode mode,
+			    uint8_t write_byte, uint8_t *read_byte)
 {
     uint8_t msg[5];
     uint8_t reply[2];
@@ -270,7 +277,7 @@ i830_dp_aux_i2c_transaction(ScrnInfoPtr pScrn, uint32_t output_reg,
     else
 	msg[0] = AUX_I2C_WRITE << 4;
 
-    if (middle_of_transaction)
+    if (mode != aux_i2c_stop)
 	msg[0] |= AUX_I2C_MOT << 4;
 
     /* Note that the AUX_CH I2C stuff wants the read/write
@@ -278,17 +285,28 @@ i830_dp_aux_i2c_transaction(ScrnInfoPtr pScrn, uint32_t output_reg,
      */
     msg[1] = address >> 9;
     msg[2] = address >> 1;
-    msg_bytes = 3;
 
-    if (has_write_data) {
+    switch (mode) {
+    case aux_i2c_start:
+        msg_bytes = 3;
+        reply_bytes = 1;
+	break;
+    case aux_i2c_write:
 	msg[3] = 0;
 	msg[4] = write_byte;
 	msg_bytes = 5;
-    }
-
-    reply_bytes = 1;
-    if (has_read_data)
+	reply_bytes = 1;
+	break;
+    case aux_i2c_read:
+	msg[3] = 0;
+	msg_bytes = 4;
 	reply_bytes = 2;
+	break;
+    case aux_i2c_stop:
+        msg_bytes = 3;
+        reply_bytes = 1;
+	break;
+    }
 
     for (;;) {
 	ret = i830_dp_aux_ch(pScrn, output_reg, msg, msg_bytes,
@@ -299,12 +317,12 @@ i830_dp_aux_i2c_transaction(ScrnInfoPtr pScrn, uint32_t output_reg,
 	    return -1;
 	}
 	if ((reply[0] & AUX_I2C_REPLY_MASK) == AUX_I2C_REPLY_ACK) {
-	    if (has_read_data) {
+	    if (mode == aux_i2c_read) {
 		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
 			   "i2c_read: %02x\n", reply[1]);
 		*read_byte = reply[1];
 	    }
-	    return 1;
+	    return reply_bytes - 1;
 	}
 	else if ((reply[0] & AUX_I2C_REPLY_MASK) == AUX_I2C_REPLY_DEFER)
 	    usleep(100);
@@ -316,129 +334,6 @@ i830_dp_aux_i2c_transaction(ScrnInfoPtr pScrn, uint32_t output_reg,
     }
 }
 
-/* Start an i2c transaction by sending the i2c address */
-
-static int
-i830_dp_aux_i2c_start(ScrnInfoPtr scrn, uint32_t output_reg,
-		      uint16_t address)
-{
-    return i830_dp_aux_i2c_transaction (scrn, output_reg, address,
-					0, FALSE,
-					NULL, FALSE,
-					TRUE);
-}
-
-/* Write a single byte to an AUX channel in I2C mode */
-static int
-i830_dp_aux_i2c_write(ScrnInfoPtr pScrn, uint32_t output_reg,
-		      uint16_t address, uint8_t byte)
-{
-    int ret;
-    uint8_t ack;
-    uint8_t msg[5];
-    int msg_bytes;
-
-    msg[0] = (AUX_I2C_WRITE|AUX_I2C_MOT) << 4;
-    msg[1] = address >> 9;
-    msg[2] = address >> 1;
-    msg[3] = 0;
-    msg[4] = byte;
-    msg_bytes = 5;
-    for (;;) {
-	ret = i830_dp_aux_ch(pScrn, output_reg, msg, msg_bytes, &ack, 1);
-	if (ret < 0)
-	    return ret;
-	if ((ack & AUX_I2C_REPLY_MASK) == AUX_I2C_REPLY_ACK)
-	    break;
-	else if ((ack & AUX_I2C_REPLY_MASK) == AUX_I2C_REPLY_DEFER)
-	    usleep(100);
-	else {
-	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
-		       "aux ch i2c write_1 returns %02x\n", ack);
-	    return -1;
-	}
-    }
-    return 1;
-}
-
-/* Read a single byte from an AUX channel in I2C mode */
-static int
-i830_dp_aux_i2c_read(ScrnInfoPtr pScrn, uint32_t output_reg,
-		     uint16_t address, uint8_t *recv)
-{
-    uint8_t msg[4];
-    int msg_bytes;
-    uint8_t reply[2];
-    uint8_t ack;
-    int reply_bytes;
-    int ret;
-
-    msg[0] = (AUX_I2C_READ | AUX_I2C_MOT) << 4;
-    msg[1] = address >> 9;
-    msg[2] = address >> 1;
-    msg[3] = 0;
-    msg_bytes = 4;
-    reply_bytes = 2;
-
-    for (;;) {
-	ret = i830_dp_aux_ch(pScrn, output_reg, msg, msg_bytes,
-			     reply, reply_bytes);
-	if (ret <= 0) {
-	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
-		       "i2c_read: aux_ch error %d\n", ret);
-	    return -1;
-	}
-	ack = reply[0];
-	if ((ack & AUX_I2C_REPLY_MASK) == AUX_I2C_REPLY_ACK) {
-	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
-		       "i2c_read: %02x\n", reply[1]);
-	    recv[0] = reply[1];
-	    return 1;
-	}
-	else if ((ack & AUX_I2C_REPLY_MASK) == AUX_I2C_REPLY_DEFER)
-	    usleep(100);
-	else {
-	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
-		       "aux ch i2c write returns %02x\n", ack);
-	    return -1;
-	}
-    }
-}
-
-/* Finish an I2C transaction on an AUX channel */
-static int
-i830_dp_aux_i2c_stop(ScrnInfoPtr pScrn, uint32_t output_reg,
-			     uint16_t address)
-{
-    int ret;
-    uint8_t ack;
-    uint8_t msg[3];
-    int msg_bytes;
-
-    if (address & 1)
-	msg[0] = (AUX_I2C_READ) << 4;
-    else
-	msg[0] = (AUX_I2C_WRITE) << 4;
-    msg[1] = address >> 9;
-    msg[2] = address >> 1;
-    msg_bytes = 3;
-    for (;;) {
-	ret = i830_dp_aux_ch(pScrn, output_reg, msg, msg_bytes, &ack, 1);
-	if (ret < 0)
-	    return ret;
-	if ((ack & AUX_I2C_REPLY_MASK) == AUX_I2C_REPLY_ACK)
-	    break;
-	else if ((ack & AUX_I2C_REPLY_MASK) == AUX_I2C_REPLY_DEFER)
-	    usleep(100);
-	else {
-	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
-		       "aux ch i2c write_finish returns %02x\n", ack);
-	    return -1;
-	}
-    }
-    return 1;
-}
-
 static void
 i830_dp_mode_set(xf86OutputPtr output, DisplayModePtr mode,
 		   DisplayModePtr adjusted_mode)
@@ -678,7 +573,8 @@ i830_dp_i2c_address(I2CDevPtr dev, I2CSlaveAddr addr)
 
     dev_priv->i2c_address = addr;
     dev_priv->i2c_running = TRUE;
-    return i830_dp_aux_i2c_start(scrn, dev_priv->output_reg, addr) >= 0;
+    return i830_dp_aux_i2c_transaction(scrn, dev_priv->output_reg, addr,
+				       aux_i2c_start, 0, NULL) >= 0;
 }
 
 /* DIX never even calls this function, so it better not be necessary */
@@ -702,8 +598,9 @@ i830_dp_i2c_stop(I2CDevPtr dev)
     struct i830_dp_priv *dev_priv = intel_output->dev_priv;
 
     if (dev_priv->i2c_running)
-	(void) i830_dp_aux_i2c_stop(scrn, dev_priv->output_reg,
-				    dev_priv->i2c_address);
+	(void) i830_dp_aux_i2c_transaction(scrn, dev_priv->output_reg,
+					   dev_priv->i2c_address,
+					   aux_i2c_stop, 0, NULL);
     dev_priv->i2c_running = FALSE;
 }
 
@@ -720,9 +617,9 @@ i830_dp_i2c_put_byte(I2CDevPtr dev, I2CByte byte)
     I830OutputPrivatePtr intel_output = output->driver_private;
     struct i830_dp_priv *dev_priv = intel_output->dev_priv;
 
-    return i830_dp_aux_i2c_write(scrn, dev_priv->output_reg,
-				 dev_priv->i2c_address, byte) >= 0;
-    return TRUE;
+    return i830_dp_aux_i2c_transaction(scrn, dev_priv->output_reg,
+				       dev_priv->i2c_address,
+				       aux_i2c_write, byte, NULL) >= 0;
 }
 
 static Bool
@@ -735,9 +632,9 @@ i830_dp_i2c_get_byte(I2CDevPtr dev, I2CByte *byte_ret, Bool last)
     ScrnInfoPtr scrn = output->scrn;
 
     xf86DrvMsg(scrn->scrnIndex, X_ERROR, "i2c_get_byte %d\n", last);
-    return i830_dp_aux_i2c_read(scrn, dev_priv->output_reg,
-				dev_priv->i2c_address,
-				byte_ret) == 1;
+    return i830_dp_aux_i2c_transaction(scrn, dev_priv->output_reg,
+				       dev_priv->i2c_address,
+				       aux_i2c_read, 0, byte_ret) == 1;
 }
 
 static Bool
commit 6c1d5675f208378af37ced9974e1cdf3b9658d72
Author: Keith Packard <keithp at keithp.com>
Date:   Wed Mar 18 20:48:00 2009 -0700

    Create a unified I2C over DisplayPort AUX_CH function

diff --git a/src/i830_dp.c b/src/i830_dp.c
index 7d4afa7..d0fc8cc 100644
--- a/src/i830_dp.c
+++ b/src/i830_dp.c
@@ -250,50 +250,82 @@ i830_dp_aux_native_read(ScrnInfoPtr pScrn, uint32_t output_reg,
     }
 }
 
-/* Fill-in the first three bytes of an aux i2c message */
-static void
-i830_dp_aux_i2c_header(uint8_t *msg, uint16_t address, Bool middle)
+/* Run a single AUX_CH I2C transaction, writing/reading data as necessary */
+static int
+i830_dp_aux_i2c_transaction(ScrnInfoPtr pScrn, uint32_t output_reg,
+			    uint16_t address,
+			    uint8_t write_byte, Bool has_write_data,
+			    uint8_t *read_byte, Bool has_read_data,
+			    Bool middle_of_transaction)
 {
+    uint8_t msg[5];
+    uint8_t reply[2];
+    int msg_bytes;
+    int reply_bytes;
+    int ret;
+
+    /* Set up the command byte */
     if (address & 1)
-	msg[0] = (AUX_I2C_READ|AUX_I2C_MOT) << 4;
+	msg[0] = AUX_I2C_READ << 4;
     else
-	msg[0] = (AUX_I2C_WRITE|AUX_I2C_MOT) << 4;
-    /*
-     * Note that the AUX_CH I2C stuff wants the read/write
+	msg[0] = AUX_I2C_WRITE << 4;
+
+    if (middle_of_transaction)
+	msg[0] |= AUX_I2C_MOT << 4;
+
+    /* Note that the AUX_CH I2C stuff wants the read/write
      * bit stripped off
      */
     msg[1] = address >> 9;
     msg[2] = address >> 1;
-}
+    msg_bytes = 3;
 
-/* Start an i2c transaction by sending the i2c address */
+    if (has_write_data) {
+	msg[3] = 0;
+	msg[4] = write_byte;
+	msg_bytes = 5;
+    }
 
-static int
-i830_dp_aux_i2c_start(ScrnInfoPtr pScrn, uint32_t output_reg,
-		      uint16_t address)
-{
-    int ret;
-    uint8_t ack;
-    uint8_t msg[3];
-    int msg_bytes;
+    reply_bytes = 1;
+    if (has_read_data)
+	reply_bytes = 2;
 
-    i830_dp_aux_i2c_header(msg, address, TRUE);
-    msg_bytes = 3;
     for (;;) {
-	ret = i830_dp_aux_ch(pScrn, output_reg, msg, msg_bytes, &ack, 1);
-	if (ret < 0)
-	    return ret;
-	if ((ack & AUX_I2C_REPLY_MASK) == AUX_I2C_REPLY_ACK)
-	    break;
-	else if ((ack & AUX_I2C_REPLY_MASK) == AUX_I2C_REPLY_DEFER)
+	ret = i830_dp_aux_ch(pScrn, output_reg, msg, msg_bytes,
+			     reply, reply_bytes);
+	if (ret <= 0) {
+	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+		       "i2c_read: aux_ch error %d\n", ret);
+	    return -1;
+	}
+	if ((reply[0] & AUX_I2C_REPLY_MASK) == AUX_I2C_REPLY_ACK) {
+	    if (has_read_data) {
+		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+			   "i2c_read: %02x\n", reply[1]);
+		*read_byte = reply[1];
+	    }
+	    return 1;
+	}
+	else if ((reply[0] & AUX_I2C_REPLY_MASK) == AUX_I2C_REPLY_DEFER)
 	    usleep(100);
 	else {
 	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
-		       "aux ch i2c address returns %02x\n", ack);
+		       "aux ch i2c write returns %02x\n", reply[0]);
 	    return -1;
 	}
     }
-    return 0;
+}
+
+/* Start an i2c transaction by sending the i2c address */
+
+static int
+i830_dp_aux_i2c_start(ScrnInfoPtr scrn, uint32_t output_reg,
+		      uint16_t address)
+{
+    return i830_dp_aux_i2c_transaction (scrn, output_reg, address,
+					0, FALSE,
+					NULL, FALSE,
+					TRUE);
 }
 
 /* Write a single byte to an AUX channel in I2C mode */
commit 743536300954a12ee579f7bb18b215ff2d71a6a8
Author: Keith Packard <keithp at keithp.com>
Date:   Wed Mar 18 20:32:28 2009 -0700

    Fix Display Port DDC support.
    
    Re-reading the Display Port specification uncovered numerous minor bugs in
    the AUX CH I2C support. The read/write bit is stripped from the address,
    leaving only seven bits in the AUX_CH message. Then, the transaction is
    performed by an address-only packet, followed by data packets, followed by
    another address-only packet.
    
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/src/i830_dp.c b/src/i830_dp.c
index 6a136d1..7d4afa7 100644
--- a/src/i830_dp.c
+++ b/src/i830_dp.c
@@ -42,8 +42,7 @@ struct i830_dp_priv {
     uint8_t  save_link_configuration[0x10];
     Bool has_audio;
     uint16_t i2c_address;
-    uint8_t i2c_put_byte;
-    Bool i2c_has_byte;
+    Bool i2c_running;
 };
 
 static void
@@ -107,6 +106,7 @@ i830_dp_aux_ch(ScrnInfoPtr pScrn, uint32_t output_reg,
     uint32_t	ctl;
     uint32_t	status;
 
+    /* Load the send data into the aux channel data registers */
     for (i = 0; i < send_bytes; i += 4) {
 	uint32_t    d = pack_aux(send + i, send_bytes - i);;
 
@@ -115,12 +115,20 @@ i830_dp_aux_ch(ScrnInfoPtr pScrn, uint32_t output_reg,
 	OUTREG(ch_data + i, d);
     }
 
+    /* The clock divider is based off the hrawclk,
+     * and would like to run at 2MHz. The 133 below assumes
+     * a 266MHz hrawclk; need to figure out how we're supposed
+     * to know what hrawclk is...
+     */
     ctl = (DP_AUX_CH_CTL_SEND_BUSY |
-	   DP_AUX_CH_CTL_TIME_OUT_400us |
+	   DP_AUX_CH_CTL_TIME_OUT_1600us |
 	   (send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
 	   (5 << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) |
-	   (133 << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT));
+	   (133 << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT) |
+	   DP_AUX_CH_CTL_TIME_OUT_ERROR |
+	   DP_AUX_CH_CTL_RECEIVE_ERROR);
 
+    /* Send the command and wait for it to complete */
     OUTREG(ch_ctl, ctl);
     for (;;) {
 	status = INREG(ch_ctl);
@@ -142,6 +150,8 @@ i830_dp_aux_ch(ScrnInfoPtr pScrn, uint32_t output_reg,
 		   status);
 	return -1;
     }
+
+    /* Unload any bytes sent back from the other side */
     recv_bytes = ((status & DP_AUX_CH_CTL_MESSAGE_SIZE_MASK) >>
 		  DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT);
 
@@ -158,6 +168,7 @@ i830_dp_aux_ch(ScrnInfoPtr pScrn, uint32_t output_reg,
     return recv_bytes;
 }
 
+/* Write data to the aux channel in native mode */
 static int
 i830_dp_aux_native_write(ScrnInfoPtr pScrn, uint32_t output_reg,
 			 uint16_t address, uint8_t *send, int send_bytes)
@@ -191,6 +202,7 @@ i830_dp_aux_native_write(ScrnInfoPtr pScrn, uint32_t output_reg,
     return send_bytes;
 }
 
+/* Write a single byte to the aux channel in native mode */
 static int
 i830_dp_aux_native_write_1(ScrnInfoPtr pScrn, uint32_t output_reg,
 			   uint16_t address, uint8_t byte)
@@ -198,18 +210,74 @@ i830_dp_aux_native_write_1(ScrnInfoPtr pScrn, uint32_t output_reg,
     return i830_dp_aux_native_write(pScrn, output_reg, address, &byte, 1);
 }
 
+/* read bytes from a native aux channel */
 static int
-i830_dp_aux_i2c_address(ScrnInfoPtr pScrn, uint32_t output_reg,
-			uint16_t address)
+i830_dp_aux_native_read(ScrnInfoPtr pScrn, uint32_t output_reg,
+			uint16_t address, uint8_t *recv, int recv_bytes)
+{
+    uint8_t msg[4];
+    int msg_bytes;
+    uint8_t reply[20];
+    int reply_bytes;
+    uint8_t ack;
+    int ret;
+
+    msg[0] = AUX_NATIVE_READ << 4;
+    msg[1] = address >> 8;
+    msg[2] = address & 0xff;
+    msg[3] = recv_bytes - 1;
+
+    msg_bytes = 4;
+    reply_bytes = recv_bytes + 1;
+
+    for (;;) {
+	ret = i830_dp_aux_ch(pScrn, output_reg, msg, msg_bytes,
+			     reply, reply_bytes);
+	if (ret <= 0)
+	    return ret;
+	ack = reply[0];
+        if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK) {
+	    memcpy(recv, reply + 1, ret - 1);
+	    return ret - 1;
+	}
+	else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER)
+	    usleep(100);
+	else {
+	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+		       "aux ch native write returns %08x\n", ack);
+	    return -1;
+	}
+    }
+}
+
+/* Fill-in the first three bytes of an aux i2c message */
+static void
+i830_dp_aux_i2c_header(uint8_t *msg, uint16_t address, Bool middle)
+{
+    if (address & 1)
+	msg[0] = (AUX_I2C_READ|AUX_I2C_MOT) << 4;
+    else
+	msg[0] = (AUX_I2C_WRITE|AUX_I2C_MOT) << 4;
+    /*
+     * Note that the AUX_CH I2C stuff wants the read/write
+     * bit stripped off
+     */
+    msg[1] = address >> 9;
+    msg[2] = address >> 1;
+}
+
+/* Start an i2c transaction by sending the i2c address */
+
+static int
+i830_dp_aux_i2c_start(ScrnInfoPtr pScrn, uint32_t output_reg,
+		      uint16_t address)
 {
     int ret;
     uint8_t ack;
     uint8_t msg[3];
     int msg_bytes;
 
-    msg[0] = (AUX_I2C_WRITE|AUX_I2C_MOT) << 4;
-    msg[1] = address >> 8;
-    msg[2] = address;
+    i830_dp_aux_i2c_header(msg, address, TRUE);
     msg_bytes = 3;
     for (;;) {
 	ret = i830_dp_aux_ch(pScrn, output_reg, msg, msg_bytes, &ack, 1);
@@ -228,20 +296,19 @@ i830_dp_aux_i2c_address(ScrnInfoPtr pScrn, uint32_t output_reg,
     return 0;
 }
 
+/* Write a single byte to an AUX channel in I2C mode */
 static int
-i830_dp_aux_i2c_write_1(ScrnInfoPtr pScrn, uint32_t output_reg,
-			uint16_t address, uint8_t byte, Bool last)
+i830_dp_aux_i2c_write(ScrnInfoPtr pScrn, uint32_t output_reg,
+		      uint16_t address, uint8_t byte)
 {
     int ret;
     uint8_t ack;
     uint8_t msg[5];
     int msg_bytes;
 
-    msg[0] = (AUX_I2C_WRITE) << 4;
-    if (!last)
-	msg[0] |= (AUX_I2C_MOT) << 4;
-    msg[1] = address >> 8;
-    msg[2] = address;
+    msg[0] = (AUX_I2C_WRITE|AUX_I2C_MOT) << 4;
+    msg[1] = address >> 9;
+    msg[2] = address >> 1;
     msg[3] = 0;
     msg[4] = byte;
     msg_bytes = 5;
@@ -255,55 +322,17 @@ i830_dp_aux_i2c_write_1(ScrnInfoPtr pScrn, uint32_t output_reg,
 	    usleep(100);
 	else {
 	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
-		       "aux ch i2c write returns %02x\n", ack);
+		       "aux ch i2c write_1 returns %02x\n", ack);
 	    return -1;
 	}
     }
     return 1;
 }
 
+/* Read a single byte from an AUX channel in I2C mode */
 static int
-i830_dp_aux_native_read(ScrnInfoPtr pScrn, uint32_t output_reg,
-			uint16_t address, uint8_t *recv, int recv_bytes)
-{
-    uint8_t msg[4];
-    int msg_bytes;
-    uint8_t reply[20];
-    int reply_bytes;
-    uint8_t ack;
-    int ret;
-
-    msg[0] = AUX_NATIVE_READ << 4;
-    msg[1] = address >> 8;
-    msg[2] = address & 0xff;
-    msg[3] = recv_bytes - 1;
-
-    msg_bytes = 4;
-    reply_bytes = recv_bytes + 1;
-
-    for (;;) {
-	ret = i830_dp_aux_ch(pScrn, output_reg, msg, msg_bytes,
-			     reply, reply_bytes);
-	if (ret <= 0)
-	    return ret;
-	ack = reply[0];
-        if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK) {
-	    memcpy(recv, reply + 1, ret - 1);
-	    return ret - 1;
-	}
-	else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER)
-	    usleep(100);
-	else {
-	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
-		       "aux ch native write returns %08x\n", ack);
-	    return -1;
-	}
-    }
-}
-
-static int
-i830_dp_aux_i2c_read_1(ScrnInfoPtr pScrn, uint32_t output_reg,
-		       uint16_t address, uint8_t *recv, Bool last)
+i830_dp_aux_i2c_read(ScrnInfoPtr pScrn, uint32_t output_reg,
+		     uint16_t address, uint8_t *recv)
 {
     uint8_t msg[4];
     int msg_bytes;
@@ -312,11 +341,9 @@ i830_dp_aux_i2c_read_1(ScrnInfoPtr pScrn, uint32_t output_reg,
     int reply_bytes;
     int ret;
 
-    msg[0] = AUX_I2C_READ << 4;
-    if (!last)
-	msg[0] |= AUX_I2C_MOT << 4;
-    msg[1] = address >> 8;
-    msg[2] = address;
+    msg[0] = (AUX_I2C_READ | AUX_I2C_MOT) << 4;
+    msg[1] = address >> 9;
+    msg[2] = address >> 1;
     msg[3] = 0;
     msg_bytes = 4;
     reply_bytes = 2;
@@ -346,6 +373,40 @@ i830_dp_aux_i2c_read_1(ScrnInfoPtr pScrn, uint32_t output_reg,
     }
 }
 
+/* Finish an I2C transaction on an AUX channel */
+static int
+i830_dp_aux_i2c_stop(ScrnInfoPtr pScrn, uint32_t output_reg,
+			     uint16_t address)
+{
+    int ret;
+    uint8_t ack;
+    uint8_t msg[3];
+    int msg_bytes;
+
+    if (address & 1)
+	msg[0] = (AUX_I2C_READ) << 4;
+    else
+	msg[0] = (AUX_I2C_WRITE) << 4;
+    msg[1] = address >> 9;
+    msg[2] = address >> 1;
+    msg_bytes = 3;
+    for (;;) {
+	ret = i830_dp_aux_ch(pScrn, output_reg, msg, msg_bytes, &ack, 1);
+	if (ret < 0)
+	    return ret;
+	if ((ack & AUX_I2C_REPLY_MASK) == AUX_I2C_REPLY_ACK)
+	    break;
+	else if ((ack & AUX_I2C_REPLY_MASK) == AUX_I2C_REPLY_DEFER)
+	    usleep(100);
+	else {
+	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+		       "aux ch i2c write_finish returns %02x\n", ack);
+	    return -1;
+	}
+    }
+    return 1;
+}
+
 static void
 i830_dp_mode_set(xf86OutputPtr output, DisplayModePtr mode,
 		   DisplayModePtr adjusted_mode)
@@ -569,25 +630,11 @@ i830_dp_link_train(xf86OutputPtr output, uint32_t DP)
  * I2C over AUX CH
  */
 
-static Bool
-i830_dp_i2c_flush(I2CBusPtr bus, Bool last)
-{
-    xf86OutputPtr output = bus->DriverPrivate.ptr;
-    ScrnInfoPtr scrn = output->scrn;
-    I830OutputPrivatePtr intel_output = output->driver_private;
-    struct i830_dp_priv *dev_priv = intel_output->dev_priv;
-
-    if (dev_priv->i2c_has_byte) {
-	xf86DrvMsg(scrn->scrnIndex, X_ERROR,
-		   "i2c_flush %02x\n", dev_priv->i2c_put_byte);
-	dev_priv->i2c_has_byte = FALSE;
-	return i830_dp_aux_i2c_write_1(scrn, dev_priv->output_reg,
-				       dev_priv->i2c_address,
-				       dev_priv->i2c_put_byte, last);
-    }
-    return 0;
-}
-
+/*
+ * Send the address. If the I2C link is running, this 'restarts'
+ * the connection with the new address, this is used for doing
+ * a write followed by a read (as needed for DDC)
+ */
 static Bool
 i830_dp_i2c_address(I2CDevPtr dev, I2CSlaveAddr addr)
 {
@@ -597,35 +644,41 @@ i830_dp_i2c_address(I2CDevPtr dev, I2CSlaveAddr addr)
     struct i830_dp_priv *dev_priv = intel_output->dev_priv;
     ScrnInfoPtr scrn = output->scrn;
 
-    if (i830_dp_i2c_flush(bus, TRUE) < 0)
-	return FALSE;
-    xf86DrvMsg(scrn->scrnIndex, X_ERROR, "i2c_address %04x\n", addr);
     dev_priv->i2c_address = addr;
-    return i830_dp_aux_i2c_address(scrn, dev_priv->output_reg, addr) >= 0;
+    dev_priv->i2c_running = TRUE;
+    return i830_dp_aux_i2c_start(scrn, dev_priv->output_reg, addr) >= 0;
 }
 
+/* DIX never even calls this function, so it better not be necessary */
 static Bool
 i830_dp_i2c_start(I2CBusPtr bus, int timeout)
 {
-    xf86OutputPtr output = bus->DriverPrivate.ptr;
-    ScrnInfoPtr scrn = output->scrn;
-
-    (void) i830_dp_i2c_flush(bus, TRUE);
-    xf86DrvMsg(scrn->scrnIndex, X_ERROR, "i2c_start %d\n", timeout);
     return TRUE;
 }
 
+/*
+ * Stop the I2C transaction. This closes out the link, sending
+ * a bare address packet with the MOT bit turned off
+ */
 static void
 i830_dp_i2c_stop(I2CDevPtr dev)
 {
     I2CBusPtr bus = dev->pI2CBus;
     xf86OutputPtr output = bus->DriverPrivate.ptr;
     ScrnInfoPtr scrn = output->scrn;
+    I830OutputPrivatePtr intel_output = output->driver_private;
+    struct i830_dp_priv *dev_priv = intel_output->dev_priv;
 
-    xf86DrvMsg(scrn->scrnIndex, X_ERROR, "i2c_stop\n");
-    (void) i830_dp_i2c_flush(bus, TRUE);
+    if (dev_priv->i2c_running)
+	(void) i830_dp_aux_i2c_stop(scrn, dev_priv->output_reg,
+				    dev_priv->i2c_address);
+    dev_priv->i2c_running = FALSE;
 }
 
+/*
+ * Write a single byte to the current I2C address, this assumes
+ * that the I2C link is running (or presumably it won't work).
+ */
 static Bool
 i830_dp_i2c_put_byte(I2CDevPtr dev, I2CByte byte)
 {
@@ -635,11 +688,8 @@ i830_dp_i2c_put_byte(I2CDevPtr dev, I2CByte byte)
     I830OutputPrivatePtr intel_output = output->driver_private;
     struct i830_dp_priv *dev_priv = intel_output->dev_priv;
 
-    xf86DrvMsg(scrn->scrnIndex, X_ERROR, "i2c_put_byte 0x%x\n", byte);
-    if (i830_dp_i2c_flush(bus, FALSE) < 0)
-	return FALSE;
-    dev_priv->i2c_put_byte = byte;
-    dev_priv->i2c_has_byte = TRUE;
+    return i830_dp_aux_i2c_write(scrn, dev_priv->output_reg,
+				 dev_priv->i2c_address, byte) >= 0;
     return TRUE;
 }
 
@@ -653,12 +703,11 @@ i830_dp_i2c_get_byte(I2CDevPtr dev, I2CByte *byte_ret, Bool last)
     ScrnInfoPtr scrn = output->scrn;
 
     xf86DrvMsg(scrn->scrnIndex, X_ERROR, "i2c_get_byte %d\n", last);
-    return i830_dp_aux_i2c_read_1(scrn, dev_priv->output_reg,
-				  dev_priv->i2c_address,
-				  byte_ret, last) == 1;
+    return i830_dp_aux_i2c_read(scrn, dev_priv->output_reg,
+				dev_priv->i2c_address,
+				byte_ret) == 1;
 }
 
-
 static Bool
 i830_dp_i2c_init(ScrnInfoPtr pScrn, I2CBusPtr *bus_ptr,
 		 xf86OutputPtr output, char *name)


More information about the xorg-commit mailing list