diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.c b/drivers/gpu/drm/nouveau/nouveau_i2c.c index f0162c4..d724985 100644 --- a/drivers/gpu/drm/nouveau/nouveau_i2c.c +++ b/drivers/gpu/drm/nouveau/nouveau_i2c.c @@ -67,6 +67,76 @@ nv04_i2c_getsda(void *data) return !!(NVReadVgaCrtc(dev, 0, i2c->rd) & 8); } +static int +nv1a_i2c_base(struct drm_device *dev) +{ + uint32_t crtc_38, save_5, save_3; + int port; + + crtc_38 = NVReadVgaCrtc(dev, 0, 0x38); + NVWriteVgaCrtc(dev, 0, 0x38, 0x5); + save_5 = inw(0x3d0); + NVWriteVgaCrtc(dev, 0, 0x38, 0x3); + save_3 = inl(0x3d0); + + outl(0x3d0, 0x1858); + + NVWriteVgaCrtc(dev, 0, 0x38, 0x5); + port = inl(0x3d0); + + NVWriteVgaCrtc(dev, 0, 0x38, 0x3); + outl(0x3d0, save_3); + NVWriteVgaCrtc(dev, 0, 0x38, 0x7); + outw(0x3d0, save_5); + NVWriteVgaCrtc(dev, 0, 0x38, crtc_38); + + return port; +} + +static void +nv1a_i2c_setscl(void *data, int state) +{ + struct nouveau_i2c_chan *i2c = data; + struct drm_device *dev = i2c->dev; + int port = nv1a_i2c_base(dev) + 1; + uint8_t val; + + val = (inb(port) & 0xd0) | (state ? 0x20 : 0); + outb(port, val | 0x01); +} + +static void +nv1a_i2c_setsda(void *data, int state) +{ + struct nouveau_i2c_chan *i2c = data; + struct drm_device *dev = i2c->dev; + int port = nv1a_i2c_base(dev) + 1; + uint8_t val; + + val = (inb(port) & 0xe0) | (state ? 0x10 : 0); + outb(port, val | 0x01); +} + +static int +nv1a_i2c_getscl(void *data) +{ + struct nouveau_i2c_chan *i2c = data; + struct drm_device *dev = i2c->dev; + int port = nv1a_i2c_base(dev); + + return !!(inb(port) & 4); +} + +static int +nv1a_i2c_getsda(void *data) +{ + struct nouveau_i2c_chan *i2c = data; + struct drm_device *dev = i2c->dev; + int port = nv1a_i2c_base(dev); + + return !!(inb(port) & 8); +} + static void nv4e_i2c_setscl(void *data, int state) { @@ -174,10 +244,20 @@ nouveau_i2c_init(struct drm_device *dev, struct dcb_i2c_entry *entry, int index) switch (entry->port_type) { case 0: - i2c->algo.bit.setsda = nv04_i2c_setsda; - i2c->algo.bit.setscl = nv04_i2c_setscl; - i2c->algo.bit.getsda = nv04_i2c_getsda; - i2c->algo.bit.getscl = nv04_i2c_getscl; + if (dev_priv->chipset == 0x1a && index == 0) { + printk("nv1a i2c base: %x\n", nv1a_i2c_base(dev)); + + i2c->algo.bit.setsda = nv1a_i2c_setsda; + i2c->algo.bit.setscl = nv1a_i2c_setscl; + i2c->algo.bit.getsda = nv1a_i2c_getsda; + i2c->algo.bit.getscl = nv1a_i2c_getscl; + } else { + i2c->algo.bit.setsda = nv04_i2c_setsda; + i2c->algo.bit.setscl = nv04_i2c_setscl; + i2c->algo.bit.getsda = nv04_i2c_getsda; + i2c->algo.bit.getscl = nv04_i2c_getscl; + } + i2c->rd = entry->read; i2c->wr = entry->write; break;