summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nouveau_i2c.c
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2011-11-17 04:56:14 +0100
committerBen Skeggs <bskeggs@redhat.com>2011-12-21 10:01:40 +0100
commit2bdb06e3cff066c546fb41152bc582a5ec73e899 (patch)
tree919e599c07672b170f1a1b6c3ab9d13294974729 /drivers/gpu/drm/nouveau/nouveau_i2c.c
parentdrm/nouveau/i2c: do parsing of i2c-related vbios info in nouveau_i2c.c (diff)
downloadlinux-2bdb06e3cff066c546fb41152bc582a5ec73e899.tar.xz
linux-2bdb06e3cff066c546fb41152bc582a5ec73e899.zip
drm/nouveau/i2c: tidy up bit-bang helpers, also fixing nv50 setsda bug
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>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_i2c.c')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_i2c.c230
1 files changed, 88 insertions, 142 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.c b/drivers/gpu/drm/nouveau/nouveau_i2c.c
index 36ffcb84f55a..d0d581440d5e 100644
--- a/drivers/gpu/drm/nouveau/nouveau_i2c.c
+++ b/drivers/gpu/drm/nouveau/nouveau_i2c.c
@@ -30,132 +30,83 @@
#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;