Skip to content

Commit

Permalink
drm/nouveau/i2c: tidy up bit-bang helpers, also fixing nv50 setsda bug
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Ben Skeggs committed Dec 21, 2011
1 parent 486a45c commit 2bdb06e
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 148 deletions.
6 changes: 3 additions & 3 deletions drivers/gpu/drm/nouveau/nouveau_dp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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
Expand Down
230 changes: 88 additions & 142 deletions drivers/gpu/drm/nouveau/nouveau_i2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -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[] = {
Expand Down Expand Up @@ -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;
}
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
6 changes: 3 additions & 3 deletions drivers/gpu/drm/nouveau/nouveau_i2c.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 *);
Expand Down

0 comments on commit 2bdb06e

Please sign in to comment.