When 2 or more EDID extension blocks are present, segment must be
selected prior to reading the extended EDID block over the DDC
channel. Add support for this.

Signed-off-by: Jean Delvare <jdelvare at suse.de>
Cc: Adam Jackson <ajax at redhat.com>
---
This needs testing by someone with access to such a display.

 drivers/gpu/drm/drm_edid.c |   21 +++++++++++++++++++--
 1 file changed, 19 insertions(+), 2 deletions(-)

--- linux-3.2-rc3.orig/drivers/gpu/drm/drm_edid.c       2011-11-09 
15:53:31.000000000 +0100
+++ linux-3.2-rc3/drivers/gpu/drm/drm_edid.c    2011-12-03 10:12:47.000000000 
+0100
@@ -242,7 +242,8 @@ static int
 drm_do_probe_ddc_edid(struct i2c_adapter *adapter, unsigned char *buf,
                      int block, int len)
 {
-       unsigned char start = block * EDID_LENGTH;
+       unsigned char segment = block >> 1;
+       unsigned char start = (block & 0x01) * EDID_LENGTH;
        int ret, retries = 5;

        /* The core i2c driver will automatically retry the transfer if the
@@ -254,6 +255,11 @@ drm_do_probe_ddc_edid(struct i2c_adapter
        do {
                struct i2c_msg msgs[] = {
                        {
+                               .addr   = DDC_SEGMENT_ADDR,
+                               .flags  = 0,
+                               .len    = 1,
+                               .buf    = &segment,
+                       }, {
                                .addr   = DDC_ADDR,
                                .flags  = 0,
                                .len    = 1,
@@ -265,7 +271,18 @@ drm_do_probe_ddc_edid(struct i2c_adapter
                                .buf    = buf,
                        }
                };
-               ret = i2c_transfer(adapter, msgs, 2);
+
+               /* Don't write segment if it is 0, for compatibility */
+               if (segment) {
+                       ret = i2c_transfer(adapter, msgs, 3);
+                       /* The E-DDC specification says that the first ack is
+                        * optional, so retry in ignore-nak mode if we get no
+                        * ack at first.
+                        */
+                       if (ret == -ENXIO)
+                               msgs[0].flags |= I2C_M_IGNORE_NAK;
+               } else
+                       ret = i2c_transfer(adapter, msgs + 1, 2);
        } while (ret != 2 && --retries);

        return ret == 2 ? 0 : -1;

-- 
Jean Delvare
Suse L3

Reply via email to