drm/nouveau/i2c: tidy up bit-bang helpers, also fixing nv50 setsda bug
authorBen Skeggs <bskeggs@redhat.com>
Thu, 17 Nov 2011 03:56:14 +0000 (13:56 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Wed, 21 Dec 2011 09:01:40 +0000 (19:01 +1000)
Was using nv_mask, which is bad.  Reading the reg senses the current line
states, which aren't necessarily the states we're trying to drive the
lines to.

Fixed to store SCL driver state just as we already do for SDA.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/nouveau_dp.c
drivers/gpu/drm/nouveau/nouveau_i2c.c
drivers/gpu/drm/nouveau/nouveau_i2c.h

index 5722fd55764b0a47f3861e59cadca99ea169bcf4..07bac3602453bd2f724447730acfab1c51f5ddd7 100644 (file)
@@ -578,7 +578,7 @@ nouveau_dp_link_train(struct drm_encoder *encoder, u32 datarate)
 
        dp.dcb = nv_encoder->dcb;
        dp.crtc = nv_crtc->index;
-       dp.auxch = auxch->rd;
+       dp.auxch = auxch->drive;
        dp.or = nv_encoder->or;
        dp.link = !(nv_encoder->dcb->sorconf.link & 1);
        dp.dpcd = nv_encoder->dp.dpcd;
@@ -653,7 +653,7 @@ nouveau_dp_detect(struct drm_encoder *encoder)
        if (!auxch)
                return false;
 
-       ret = auxch_tx(dev, auxch->rd, 9, DP_DPCD_REV, dpcd, 8);
+       ret = auxch_tx(dev, auxch->drive, 9, DP_DPCD_REV, dpcd, 8);
        if (ret)
                return false;
 
@@ -681,7 +681,7 @@ int
 nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr,
                 uint8_t *data, int data_nr)
 {
-       return auxch_tx(auxch->dev, auxch->rd, cmd, addr, data, data_nr);
+       return auxch_tx(auxch->dev, auxch->drive, cmd, addr, data, data_nr);
 }
 
 static int
index 36ffcb84f55ad6d8fe534b71279971c3e1b18ca6..d0d581440d5ec5cfb996496b26a60c808a03ed79 100644 (file)
 #include "nouveau_hw.h"
 
 static void
-nv04_i2c_setscl(void *data, int state)
+i2c_drive_scl(void *data, int state)
 {
-       struct nouveau_i2c_chan *i2c = data;
-       struct drm_device *dev = i2c->dev;
-       uint8_t val;
-
-       val = (NVReadVgaCrtc(dev, 0, i2c->wr) & 0xd0) | (state ? 0x20 : 0);
-       NVWriteVgaCrtc(dev, 0, i2c->wr, val | 0x01);
-}
-
-static void
-nv04_i2c_setsda(void *data, int state)
-{
-       struct nouveau_i2c_chan *i2c = data;
-       struct drm_device *dev = i2c->dev;
-       uint8_t val;
-
-       val = (NVReadVgaCrtc(dev, 0, i2c->wr) & 0xe0) | (state ? 0x10 : 0);
-       NVWriteVgaCrtc(dev, 0, i2c->wr, val | 0x01);
-}
-
-static int
-nv04_i2c_getscl(void *data)
-{
-       struct nouveau_i2c_chan *i2c = data;
-       struct drm_device *dev = i2c->dev;
-
-       return !!(NVReadVgaCrtc(dev, 0, i2c->rd) & 4);
-}
-
-static int
-nv04_i2c_getsda(void *data)
-{
-       struct nouveau_i2c_chan *i2c = data;
-       struct drm_device *dev = i2c->dev;
-
-       return !!(NVReadVgaCrtc(dev, 0, i2c->rd) & 8);
-}
-
-static void
-nv4e_i2c_setscl(void *data, int state)
-{
-       struct nouveau_i2c_chan *i2c = data;
-       struct drm_device *dev = i2c->dev;
-       uint8_t val;
-
-       val = (nv_rd32(dev, i2c->wr) & 0xd0) | (state ? 0x20 : 0);
-       nv_wr32(dev, i2c->wr, val | 0x01);
-}
-
-static void
-nv4e_i2c_setsda(void *data, int state)
-{
-       struct nouveau_i2c_chan *i2c = data;
-       struct drm_device *dev = i2c->dev;
-       uint8_t val;
-
-       val = (nv_rd32(dev, i2c->wr) & 0xe0) | (state ? 0x10 : 0);
-       nv_wr32(dev, i2c->wr, val | 0x01);
-}
-
-static int
-nv4e_i2c_getscl(void *data)
-{
-       struct nouveau_i2c_chan *i2c = data;
-       struct drm_device *dev = i2c->dev;
-
-       return !!((nv_rd32(dev, i2c->rd) >> 16) & 4);
-}
-
-static int
-nv4e_i2c_getsda(void *data)
-{
-       struct nouveau_i2c_chan *i2c = data;
-       struct drm_device *dev = i2c->dev;
-
-       return !!((nv_rd32(dev, i2c->rd) >> 16) & 8);
-}
-
-static int
-nv50_i2c_getscl(void *data)
-{
-       struct nouveau_i2c_chan *i2c = data;
-       struct drm_device *dev = i2c->dev;
-
-       return !!(nv_rd32(dev, i2c->rd) & 1);
-}
-
-static int
-nv50_i2c_getsda(void *data)
-{
-       struct nouveau_i2c_chan *i2c = data;
-       struct drm_device *dev = i2c->dev;
-
-       return !!(nv_rd32(dev, i2c->rd) & 2);
-}
-
-static void
-nv50_i2c_setscl(void *data, int state)
-{
-       struct nouveau_i2c_chan *i2c = data;
-
-       nv_wr32(i2c->dev, i2c->wr, 4 | (i2c->data ? 2 : 0) | (state ? 1 : 0));
+       struct nouveau_i2c_chan *port = data;
+       if (port->type == 0) {
+               u8 val = NVReadVgaCrtc(port->dev, 0, port->drive);
+               if (state) val |= 0x20;
+               else       val &= 0xdf;
+               NVWriteVgaCrtc(port->dev, 0, port->drive, val | 0x01);
+       } else
+       if (port->type == 4) {
+               nv_mask(port->dev, port->drive, 0x2f, state ? 0x21 : 0x01);
+       } else
+       if (port->type == 5) {
+               if (state) port->state |= 0x01;
+               else       port->state &= 0xfe;
+               nv_wr32(port->dev, port->drive, 4 | port->state);
+       }
 }
 
 static void
-nv50_i2c_setsda(void *data, int state)
+i2c_drive_sda(void *data, int state)
 {
-       struct nouveau_i2c_chan *i2c = data;
-
-       nv_mask(i2c->dev, i2c->wr, 0x00000006, 4 | (state ? 2 : 0));
-       i2c->data = state;
+       struct nouveau_i2c_chan *port = data;
+       if (port->type == 0) {
+               u8 val = NVReadVgaCrtc(port->dev, 0, port->drive);
+               if (state) val |= 0x10;
+               else       val &= 0xef;
+               NVWriteVgaCrtc(port->dev, 0, port->drive, val | 0x01);
+       } else
+       if (port->type == 4) {
+               nv_mask(port->dev, port->drive, 0x1f, state ? 0x11 : 0x01);
+       } else
+       if (port->type == 5) {
+               if (state) port->state |= 0x02;
+               else       port->state &= 0xfd;
+               nv_wr32(port->dev, port->drive, 4 | port->state);
+       }
 }
 
 static int
-nvd0_i2c_getscl(void *data)
+i2c_sense_scl(void *data)
 {
-       struct nouveau_i2c_chan *i2c = data;
-       return !!(nv_rd32(i2c->dev, i2c->rd) & 0x10);
+       struct nouveau_i2c_chan *port = data;
+       struct drm_nouveau_private *dev_priv = port->dev->dev_private;
+       if (port->type == 0) {
+               return !!(NVReadVgaCrtc(port->dev, 0, port->sense) & 0x04);
+       } else
+       if (port->type == 4) {
+               return !!(nv_rd32(port->dev, port->sense) & 0x00040000);
+       } else
+       if (port->type == 5) {
+               if (dev_priv->card_type < NV_D0)
+                       return !!(nv_rd32(port->dev, port->sense) & 0x01);
+               else
+                       return !!(nv_rd32(port->dev, port->sense) & 0x10);
+       }
+       return 0;
 }
 
 static int
-nvd0_i2c_getsda(void *data)
+i2c_sense_sda(void *data)
 {
-       struct nouveau_i2c_chan *i2c = data;
-       return !!(nv_rd32(i2c->dev, i2c->rd) & 0x20);
+       struct nouveau_i2c_chan *port = data;
+       struct drm_nouveau_private *dev_priv = port->dev->dev_private;
+       if (port->type == 0) {
+               return !!(NVReadVgaCrtc(port->dev, 0, port->sense) & 0x08);
+       } else
+       if (port->type == 4) {
+               return !!(nv_rd32(port->dev, port->sense) & 0x00080000);
+       } else
+       if (port->type == 5) {
+               if (dev_priv->card_type < NV_D0)
+                       return !!(nv_rd32(port->dev, port->sense) & 0x02);
+               else
+                       return !!(nv_rd32(port->dev, port->sense) & 0x20);
+       }
+       return 0;
 }
 
 static const uint32_t nv50_i2c_port[] = {
@@ -258,51 +209,37 @@ nouveau_i2c_init(struct drm_device *dev)
 
                switch (port->type) {
                case 0: /* NV04:NV50 */
-                       port->wr = entry[0];
-                       port->rd = entry[1];
-                       port->bit.setsda = nv04_i2c_setsda;
-                       port->bit.setscl = nv04_i2c_setscl;
-                       port->bit.getsda = nv04_i2c_getsda;
-                       port->bit.getscl = nv04_i2c_getscl;
+                       port->drive = entry[0];
+                       port->sense = entry[1];
                        break;
                case 4: /* NV4E */
-                       port->wr = 0x600800 + entry[1];
-                       port->rd = port->wr;
-                       port->bit.setsda = nv4e_i2c_setsda;
-                       port->bit.setscl = nv4e_i2c_setscl;
-                       port->bit.getsda = nv4e_i2c_getsda;
-                       port->bit.getscl = nv4e_i2c_getscl;
+                       port->drive = 0x600800 + entry[1];
+                       port->sense = port->drive;
                        break;
                case 5: /* NV50- */
-                       port->wr = entry[0] & 0x0f;
+                       port->drive = entry[0] & 0x0f;
                        if (dev_priv->card_type < NV_D0) {
-                               if (port->wr >= ARRAY_SIZE(nv50_i2c_port))
+                               if (port->drive >= ARRAY_SIZE(nv50_i2c_port))
                                        break;
-                               port->wr = nv50_i2c_port[port->wr];
-                               port->rd = port->wr;
-                               port->bit.getsda = nv50_i2c_getsda;
-                               port->bit.getscl = nv50_i2c_getscl;
+                               port->drive = nv50_i2c_port[port->drive];
+                               port->sense = port->drive;
                        } else {
-                               port->wr = 0x00d014 + (port->wr * 0x20);
-                               port->rd = port->wr;
-                               port->bit.getsda = nvd0_i2c_getsda;
-                               port->bit.getscl = nvd0_i2c_getscl;
+                               port->drive = 0x00d014 + (port->drive * 0x20);
+                               port->sense = port->drive;
                        }
-                       port->bit.setsda = nv50_i2c_setsda;
-                       port->bit.setscl = nv50_i2c_setscl;
                        break;
                case 6: /* NV50- DP AUX */
-                       port->wr = entry[0];
-                       port->rd = port->wr;
+                       port->drive = entry[0];
+                       port->sense = port->drive;
                        port->adapter.algo = &nouveau_dp_i2c_algo;
                        break;
                default:
                        break;
                }
 
-               if (!port->adapter.algo && !port->wr) {
+               if (!port->adapter.algo && !port->drive) {
                        NV_ERROR(dev, "I2C%d: type %d index %x/%x unknown\n",
-                                i, port->type, port->wr, port->rd);
+                                i, port->type, port->drive, port->sense);
                        kfree(port);
                        continue;
                }
@@ -321,6 +258,15 @@ nouveau_i2c_init(struct drm_device *dev)
                        port->bit.udelay = 40;
                        port->bit.timeout = usecs_to_jiffies(5000);
                        port->bit.data = port;
+                       port->bit.setsda = i2c_drive_sda;
+                       port->bit.setscl = i2c_drive_scl;
+                       port->bit.getsda = i2c_sense_sda;
+                       port->bit.getscl = i2c_sense_scl;
+
+                       i2c_drive_scl(port, 0);
+                       i2c_drive_sda(port, 1);
+                       i2c_drive_scl(port, 1);
+
                        ret = i2c_bit_add_bus(&port->adapter);
                } else {
                        port->adapter.algo = &nouveau_dp_i2c_algo;
@@ -381,7 +327,7 @@ nouveau_i2c_find(struct drm_device *dev, u8 index)
        if (dev_priv->card_type >= NV_50 && (port->dcb & 0x00000100)) {
                u32 reg = 0x00e500, val;
                if (port->type == 6) {
-                       reg += port->rd * 0x50;
+                       reg += port->drive * 0x50;
                        val  = 0x2002;
                } else {
                        reg += ((port->dcb & 0x1e00) >> 9) * 0x50;
index cf5f67d51fbac2e21bd4bc31e49c8b5b50420c28..1d083893a4d74b29b853a6baf4ba898c4e1a0db4 100644 (file)
@@ -39,9 +39,9 @@ struct nouveau_i2c_chan {
        u8  index;
        u8  type;
        u32 dcb;
-       unsigned rd;
-       unsigned wr;
-       unsigned data;
+       u32 drive;
+       u32 sense;
+       u32 state;
 };
 
 int  nouveau_i2c_init(struct drm_device *);