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