mirror of
https://github.com/torvalds/linux
synced 2024-09-23 21:07:52 +00:00
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>
This commit is contained in:
parent
486a45c2a6
commit
2bdb06e3cf
|
@ -578,7 +578,7 @@ nouveau_dp_link_train(struct drm_encoder *encoder, u32 datarate)
|
||||||
|
|
||||||
dp.dcb = nv_encoder->dcb;
|
dp.dcb = nv_encoder->dcb;
|
||||||
dp.crtc = nv_crtc->index;
|
dp.crtc = nv_crtc->index;
|
||||||
dp.auxch = auxch->rd;
|
dp.auxch = auxch->drive;
|
||||||
dp.or = nv_encoder->or;
|
dp.or = nv_encoder->or;
|
||||||
dp.link = !(nv_encoder->dcb->sorconf.link & 1);
|
dp.link = !(nv_encoder->dcb->sorconf.link & 1);
|
||||||
dp.dpcd = nv_encoder->dp.dpcd;
|
dp.dpcd = nv_encoder->dp.dpcd;
|
||||||
|
@ -653,7 +653,7 @@ nouveau_dp_detect(struct drm_encoder *encoder)
|
||||||
if (!auxch)
|
if (!auxch)
|
||||||
return false;
|
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)
|
if (ret)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -681,7 +681,7 @@ int
|
||||||
nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr,
|
nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr,
|
||||||
uint8_t *data, int data_nr)
|
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
|
static int
|
||||||
|
|
|
@ -30,132 +30,83 @@
|
||||||
#include "nouveau_hw.h"
|
#include "nouveau_hw.h"
|
||||||
|
|
||||||
static void
|
static void
|
||||||
nv04_i2c_setscl(void *data, int state)
|
i2c_drive_scl(void *data, int state)
|
||||||
{
|
{
|
||||||
struct nouveau_i2c_chan *i2c = data;
|
struct nouveau_i2c_chan *port = data;
|
||||||
struct drm_device *dev = i2c->dev;
|
if (port->type == 0) {
|
||||||
uint8_t val;
|
u8 val = NVReadVgaCrtc(port->dev, 0, port->drive);
|
||||||
|
if (state) val |= 0x20;
|
||||||
val = (NVReadVgaCrtc(dev, 0, i2c->wr) & 0xd0) | (state ? 0x20 : 0);
|
else val &= 0xdf;
|
||||||
NVWriteVgaCrtc(dev, 0, i2c->wr, val | 0x01);
|
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
|
static void
|
||||||
nv04_i2c_setsda(void *data, int state)
|
i2c_drive_sda(void *data, int state)
|
||||||
{
|
{
|
||||||
struct nouveau_i2c_chan *i2c = data;
|
struct nouveau_i2c_chan *port = data;
|
||||||
struct drm_device *dev = i2c->dev;
|
if (port->type == 0) {
|
||||||
uint8_t val;
|
u8 val = NVReadVgaCrtc(port->dev, 0, port->drive);
|
||||||
|
if (state) val |= 0x10;
|
||||||
val = (NVReadVgaCrtc(dev, 0, i2c->wr) & 0xe0) | (state ? 0x10 : 0);
|
else val &= 0xef;
|
||||||
NVWriteVgaCrtc(dev, 0, i2c->wr, val | 0x01);
|
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
|
static int
|
||||||
nv04_i2c_getscl(void *data)
|
i2c_sense_scl(void *data)
|
||||||
{
|
{
|
||||||
struct nouveau_i2c_chan *i2c = data;
|
struct nouveau_i2c_chan *port = data;
|
||||||
struct drm_device *dev = i2c->dev;
|
struct drm_nouveau_private *dev_priv = port->dev->dev_private;
|
||||||
|
if (port->type == 0) {
|
||||||
return !!(NVReadVgaCrtc(dev, 0, i2c->rd) & 4);
|
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
|
static int
|
||||||
nv04_i2c_getsda(void *data)
|
i2c_sense_sda(void *data)
|
||||||
{
|
{
|
||||||
struct nouveau_i2c_chan *i2c = data;
|
struct nouveau_i2c_chan *port = data;
|
||||||
struct drm_device *dev = i2c->dev;
|
struct drm_nouveau_private *dev_priv = port->dev->dev_private;
|
||||||
|
if (port->type == 0) {
|
||||||
return !!(NVReadVgaCrtc(dev, 0, i2c->rd) & 8);
|
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 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));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
nv50_i2c_setsda(void *data, int state)
|
|
||||||
{
|
|
||||||
struct nouveau_i2c_chan *i2c = data;
|
|
||||||
|
|
||||||
nv_mask(i2c->dev, i2c->wr, 0x00000006, 4 | (state ? 2 : 0));
|
|
||||||
i2c->data = state;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
nvd0_i2c_getscl(void *data)
|
|
||||||
{
|
|
||||||
struct nouveau_i2c_chan *i2c = data;
|
|
||||||
return !!(nv_rd32(i2c->dev, i2c->rd) & 0x10);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
nvd0_i2c_getsda(void *data)
|
|
||||||
{
|
|
||||||
struct nouveau_i2c_chan *i2c = data;
|
|
||||||
return !!(nv_rd32(i2c->dev, i2c->rd) & 0x20);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const uint32_t nv50_i2c_port[] = {
|
static const uint32_t nv50_i2c_port[] = {
|
||||||
|
@ -258,51 +209,37 @@ nouveau_i2c_init(struct drm_device *dev)
|
||||||
|
|
||||||
switch (port->type) {
|
switch (port->type) {
|
||||||
case 0: /* NV04:NV50 */
|
case 0: /* NV04:NV50 */
|
||||||
port->wr = entry[0];
|
port->drive = entry[0];
|
||||||
port->rd = entry[1];
|
port->sense = 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;
|
|
||||||
break;
|
break;
|
||||||
case 4: /* NV4E */
|
case 4: /* NV4E */
|
||||||
port->wr = 0x600800 + entry[1];
|
port->drive = 0x600800 + entry[1];
|
||||||
port->rd = port->wr;
|
port->sense = port->drive;
|
||||||
port->bit.setsda = nv4e_i2c_setsda;
|
|
||||||
port->bit.setscl = nv4e_i2c_setscl;
|
|
||||||
port->bit.getsda = nv4e_i2c_getsda;
|
|
||||||
port->bit.getscl = nv4e_i2c_getscl;
|
|
||||||
break;
|
break;
|
||||||
case 5: /* NV50- */
|
case 5: /* NV50- */
|
||||||
port->wr = entry[0] & 0x0f;
|
port->drive = entry[0] & 0x0f;
|
||||||
if (dev_priv->card_type < NV_D0) {
|
if (dev_priv->card_type < NV_D0) {
|
||||||
if (port->wr >= ARRAY_SIZE(nv50_i2c_port))
|
if (port->drive >= ARRAY_SIZE(nv50_i2c_port))
|
||||||
break;
|
break;
|
||||||
port->wr = nv50_i2c_port[port->wr];
|
port->drive = nv50_i2c_port[port->drive];
|
||||||
port->rd = port->wr;
|
port->sense = port->drive;
|
||||||
port->bit.getsda = nv50_i2c_getsda;
|
|
||||||
port->bit.getscl = nv50_i2c_getscl;
|
|
||||||
} else {
|
} else {
|
||||||
port->wr = 0x00d014 + (port->wr * 0x20);
|
port->drive = 0x00d014 + (port->drive * 0x20);
|
||||||
port->rd = port->wr;
|
port->sense = port->drive;
|
||||||
port->bit.getsda = nvd0_i2c_getsda;
|
|
||||||
port->bit.getscl = nvd0_i2c_getscl;
|
|
||||||
}
|
}
|
||||||
port->bit.setsda = nv50_i2c_setsda;
|
|
||||||
port->bit.setscl = nv50_i2c_setscl;
|
|
||||||
break;
|
break;
|
||||||
case 6: /* NV50- DP AUX */
|
case 6: /* NV50- DP AUX */
|
||||||
port->wr = entry[0];
|
port->drive = entry[0];
|
||||||
port->rd = port->wr;
|
port->sense = port->drive;
|
||||||
port->adapter.algo = &nouveau_dp_i2c_algo;
|
port->adapter.algo = &nouveau_dp_i2c_algo;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
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",
|
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);
|
kfree(port);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -321,6 +258,15 @@ nouveau_i2c_init(struct drm_device *dev)
|
||||||
port->bit.udelay = 40;
|
port->bit.udelay = 40;
|
||||||
port->bit.timeout = usecs_to_jiffies(5000);
|
port->bit.timeout = usecs_to_jiffies(5000);
|
||||||
port->bit.data = port;
|
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);
|
ret = i2c_bit_add_bus(&port->adapter);
|
||||||
} else {
|
} else {
|
||||||
port->adapter.algo = &nouveau_dp_i2c_algo;
|
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)) {
|
if (dev_priv->card_type >= NV_50 && (port->dcb & 0x00000100)) {
|
||||||
u32 reg = 0x00e500, val;
|
u32 reg = 0x00e500, val;
|
||||||
if (port->type == 6) {
|
if (port->type == 6) {
|
||||||
reg += port->rd * 0x50;
|
reg += port->drive * 0x50;
|
||||||
val = 0x2002;
|
val = 0x2002;
|
||||||
} else {
|
} else {
|
||||||
reg += ((port->dcb & 0x1e00) >> 9) * 0x50;
|
reg += ((port->dcb & 0x1e00) >> 9) * 0x50;
|
||||||
|
|
|
@ -39,9 +39,9 @@ struct nouveau_i2c_chan {
|
||||||
u8 index;
|
u8 index;
|
||||||
u8 type;
|
u8 type;
|
||||||
u32 dcb;
|
u32 dcb;
|
||||||
unsigned rd;
|
u32 drive;
|
||||||
unsigned wr;
|
u32 sense;
|
||||||
unsigned data;
|
u32 state;
|
||||||
};
|
};
|
||||||
|
|
||||||
int nouveau_i2c_init(struct drm_device *);
|
int nouveau_i2c_init(struct drm_device *);
|
||||||
|
|
Loading…
Reference in a new issue