drm/nouveau/i2c: do parsing of i2c-related vbios info in nouveau_i2c.c
authorBen Skeggs <bskeggs@redhat.com>
Fri, 11 Nov 2011 00:22:19 +0000 (10:22 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Wed, 21 Dec 2011 09:01:40 +0000 (19:01 +1000)
Not much point parsing the vbios data into a struct which is only used once
to parse the data into another struct, go directly from vbios to
nouveau_i2c_chan.

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

index c7723fb54077fb5cc62663b5598e57060bae2d71..7922bb969d25d96a02b8e8ebdaa654912be9ab19 100644 (file)
@@ -720,116 +720,20 @@ static int dcb_entry_idx_from_crtchead(struct drm_device *dev)
        return dcb_entry;
 }
 
-static int
-read_dcb_i2c_entry(struct drm_device *dev, int dcb_version, uint8_t *i2ctable, int index, struct dcb_i2c_entry *i2c)
-{
-       uint8_t dcb_i2c_ver = dcb_version, headerlen = 0, entry_len = 4;
-       int i2c_entries = DCB_MAX_NUM_I2C_ENTRIES;
-       int recordoffset = 0, rdofs = 1, wrofs = 0;
-       uint8_t port_type = 0;
-
-       if (!i2ctable)
-               return -EINVAL;
-
-       if (dcb_version >= 0x30) {
-               if (i2ctable[0] != dcb_version) /* necessary? */
-                       NV_WARN(dev,
-                               "DCB I2C table version mismatch (%02X vs %02X)\n",
-                               i2ctable[0], dcb_version);
-               dcb_i2c_ver = i2ctable[0];
-               headerlen = i2ctable[1];
-               if (i2ctable[2] <= DCB_MAX_NUM_I2C_ENTRIES)
-                       i2c_entries = i2ctable[2];
-               else
-                       NV_WARN(dev,
-                               "DCB I2C table has more entries than indexable "
-                               "(%d entries, max %d)\n", i2ctable[2],
-                               DCB_MAX_NUM_I2C_ENTRIES);
-               entry_len = i2ctable[3];
-               /* [4] is i2c_default_indices, read in parse_dcb_table() */
-       }
-       /*
-        * It's your own fault if you call this function on a DCB 1.1 BIOS --
-        * the test below is for DCB 1.2
-        */
-       if (dcb_version < 0x14) {
-               recordoffset = 2;
-               rdofs = 0;
-               wrofs = 1;
-       }
-
-       if (index == 0xf)
-               return 0;
-       if (index >= i2c_entries) {
-               NV_ERROR(dev, "DCB I2C index too big (%d >= %d)\n",
-                        index, i2ctable[2]);
-               return -ENOENT;
-       }
-       if (i2ctable[headerlen + entry_len * index + 3] == 0xff) {
-               NV_ERROR(dev, "DCB I2C entry invalid\n");
-               return -EINVAL;
-       }
-
-       if (dcb_i2c_ver >= 0x30) {
-               port_type = i2ctable[headerlen + recordoffset + 3 + entry_len * index];
-
-               /*
-                * Fixup for chips using same address offset for read and
-                * write.
-                */
-               if (port_type == 4)     /* seen on C51 */
-                       rdofs = wrofs = 1;
-               if (port_type >= 5)     /* G80+ */
-                       rdofs = wrofs = 0;
-       }
-
-       if (dcb_i2c_ver >= 0x40) {
-               if (port_type != 5 && port_type != 6)
-                       NV_WARN(dev, "DCB I2C table has port type %d\n", port_type);
-
-               i2c->entry = ROM32(i2ctable[headerlen + recordoffset + entry_len * index]);
-       }
-
-       i2c->port_type = port_type;
-       i2c->read = i2ctable[headerlen + recordoffset + rdofs + entry_len * index];
-       i2c->write = i2ctable[headerlen + recordoffset + wrofs + entry_len * index];
-
-       return 0;
-}
-
 static struct nouveau_i2c_chan *
 init_i2c_device_find(struct drm_device *dev, int i2c_index)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct dcb_table *dcb = &dev_priv->vbios.dcb;
-
        if (i2c_index == 0xff) {
+               struct drm_nouveau_private *dev_priv = dev->dev_private;
+               struct dcb_table *dcb = &dev_priv->vbios.dcb;
                /* note: dcb_entry_idx_from_crtchead needs pre-script set-up */
-               int idx = dcb_entry_idx_from_crtchead(dev), shift = 0;
-               int default_indices = dcb->i2c_default_indices;
+               int idx = dcb_entry_idx_from_crtchead(dev);
 
+               i2c_index = NV_I2C_DEFAULT(0);
                if (idx != 0x7f && dcb->entry[idx].i2c_upper_default)
-                       shift = 4;
-
-               i2c_index = (default_indices >> shift) & 0xf;
-       }
-       if (i2c_index == 0x80)  /* g80+ */
-               i2c_index = dcb->i2c_default_indices & 0xf;
-       else
-       if (i2c_index == 0x81)
-               i2c_index = (dcb->i2c_default_indices & 0xf0) >> 4;
-
-       if (i2c_index >= DCB_MAX_NUM_I2C_ENTRIES) {
-               NV_ERROR(dev, "invalid i2c_index 0x%x\n", i2c_index);
-               return NULL;
+                       i2c_index = NV_I2C_DEFAULT(1);
        }
 
-       /* Make sure i2c table entry has been parsed, it may not
-        * have been if this is a bus not referenced by a DCB encoder
-        */
-       read_dcb_i2c_entry(dev, dcb->version, dcb->i2c_table,
-                          i2c_index, &dcb->i2c[i2c_index]);
-
        return nouveau_i2c_find(dev, i2c_index);
 }
 
@@ -5595,10 +5499,6 @@ static int parse_bmp_structure(struct drm_device *dev, struct nvbios *bios, unsi
        uint16_t legacy_scripts_offset, legacy_i2c_offset;
 
        /* load needed defaults in case we can't parse this info */
-       bios->dcb.i2c[0].write = NV_CIO_CRE_DDC_WR__INDEX;
-       bios->dcb.i2c[0].read = NV_CIO_CRE_DDC_STATUS__INDEX;
-       bios->dcb.i2c[1].write = NV_CIO_CRE_DDC0_WR__INDEX;
-       bios->dcb.i2c[1].read = NV_CIO_CRE_DDC0_STATUS__INDEX;
        bios->digital_min_front_porch = 0x4b;
        bios->fmaxvco = 256000;
        bios->fminvco = 128000;
@@ -5706,14 +5606,6 @@ static int parse_bmp_structure(struct drm_device *dev, struct nvbios *bios, unsi
        bios->legacy.i2c_indices.crt = bios->data[legacy_i2c_offset];
        bios->legacy.i2c_indices.tv = bios->data[legacy_i2c_offset + 1];
        bios->legacy.i2c_indices.panel = bios->data[legacy_i2c_offset + 2];
-       if (bios->data[legacy_i2c_offset + 4])
-               bios->dcb.i2c[0].write = bios->data[legacy_i2c_offset + 4];
-       if (bios->data[legacy_i2c_offset + 5])
-               bios->dcb.i2c[0].read = bios->data[legacy_i2c_offset + 5];
-       if (bios->data[legacy_i2c_offset + 6])
-               bios->dcb.i2c[1].write = bios->data[legacy_i2c_offset + 6];
-       if (bios->data[legacy_i2c_offset + 7])
-               bios->dcb.i2c[1].read = bios->data[legacy_i2c_offset + 7];
 
        if (bmplength > 74) {
                bios->fmaxvco = ROM32(bmp[67]);
@@ -6549,10 +6441,6 @@ parse_dcb_entry(struct drm_device *dev, void *data, int idx, u8 *outp)
                        ret = parse_dcb15_entry(dev, dcb, conn, conf, entry);
                if (!ret)
                        return 1; /* stop parsing */
-
-               read_dcb_i2c_entry(dev, dcb->version, dcb->i2c_table,
-                                  entry->i2c_index,
-                                  &dcb->i2c[entry->i2c_index]);
        }
 
        return 0;
@@ -6562,7 +6450,6 @@ static int
 parse_dcb_table(struct drm_device *dev, struct nvbios *bios)
 {
        struct dcb_table *dcb = &bios->dcb;
-       u16 i2ctabptr = 0x0000;
        u8 *dcbt;
 
        dcbt = dcb_table(dev);
@@ -6580,32 +6467,8 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios)
 
        dcb->version = dcbt[0];
        if (dcb->version >= 0x30) {
-               i2ctabptr = ROM16(dcbt[4]);
                dcb->gpio_table_ptr = ROM16(dcbt[10]);
                dcb->connector_table_ptr = ROM16(dcbt[20]);
-       } else
-       if (dcb->version >= 0x15) {
-               i2ctabptr = ROM16(dcbt[2]);
-       }
-
-       if (!i2ctabptr)
-               NV_WARN(dev, "No pointer to DCB I2C port table\n");
-       else {
-               dcb->i2c_table = &bios->data[i2ctabptr];
-               if (dcb->version >= 0x30)
-                       dcb->i2c_default_indices = dcb->i2c_table[4];
-
-               /*
-                * Parse the "management" I2C bus, used for hardware
-                * monitoring and some external TMDS transmitters.
-                */
-               if (dcb->version >= 0x22) {
-                       int idx = (dcb->version >= 0x40 ?
-                                  dcb->i2c_default_indices & 0xf : 2);
-
-                       read_dcb_i2c_entry(dev, dcb->version, dcb->i2c_table,
-                                          idx, &dcb->i2c[idx]);
-               }
        }
 
        dcb_outp_foreach(dev, NULL, parse_dcb_entry);
@@ -6893,19 +6756,6 @@ nouveau_run_vbios_init(struct drm_device *dev)
        return ret;
 }
 
-static void
-nouveau_bios_i2c_devices_takedown(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nvbios *bios = &dev_priv->vbios;
-       struct dcb_i2c_entry *entry;
-       int i;
-
-       entry = &bios->dcb.i2c[0];
-       for (i = 0; i < DCB_MAX_NUM_I2C_ENTRIES; i++, entry++)
-               nouveau_i2c_fini(dev, entry);
-}
-
 static bool
 nouveau_bios_posted(struct drm_device *dev)
 {
@@ -6942,6 +6792,10 @@ nouveau_bios_init(struct drm_device *dev)
        if (ret)
                return ret;
 
+       ret = nouveau_i2c_init(dev);
+       if (ret)
+               return ret;
+
        ret = parse_dcb_table(dev, bios);
        if (ret)
                return ret;
@@ -6984,5 +6838,5 @@ nouveau_bios_init(struct drm_device *dev)
 void
 nouveau_bios_takedown(struct drm_device *dev)
 {
-       nouveau_bios_i2c_devices_takedown(dev);
+       nouveau_i2c_fini(dev);
 }
index b9f2da394f89a93c3279953ebc20c9e253f6250e..a0e9c2c7ae8cf0ca7519b61832597cdfef8cacab 100644 (file)
@@ -53,13 +53,6 @@ struct bit_entry {
 
 int bit_table(struct drm_device *, u8 id, struct bit_entry *);
 
-struct dcb_i2c_entry {
-       uint32_t entry;
-       uint8_t port_type;
-       uint8_t read, write;
-       struct nouveau_i2c_chan *chan;
-};
-
 enum dcb_gpio_tag {
        DCB_GPIO_TVDAC0 = 0xc,
        DCB_GPIO_TVDAC1 = 0x2d,
@@ -166,10 +159,6 @@ struct dcb_table {
        int entries;
        struct dcb_entry entry[DCB_MAX_NUM_ENTRIES];
 
-       uint8_t *i2c_table;
-       uint8_t i2c_default_indices;
-       struct dcb_i2c_entry i2c[DCB_MAX_NUM_I2C_ENTRIES];
-
        uint16_t gpio_table_ptr;
        struct dcb_gpio_table gpio;
        uint16_t connector_table_ptr;
index 446caedbcff9ae4a0325cd6f71e5a97f9394851a..fb126c1508b5010bb42619014279466dca4b3bb0 100644 (file)
@@ -793,6 +793,7 @@ struct drm_nouveau_private {
        struct nouveau_vm *chan_vm;
 
        struct nvbios vbios;
+       struct list_head i2c_ports;
 
        struct nv04_mode_state mode_reg;
        struct nv04_mode_state saved_reg;
index d39b2202b197521473129d8c5e3cf1ccd6d34031..36ffcb84f55ad6d8fe534b71279971c3e1b18ca6 100644 (file)
@@ -109,13 +109,6 @@ nv4e_i2c_getsda(void *data)
        return !!((nv_rd32(dev, i2c->rd) >> 16) & 8);
 }
 
-static const uint32_t nv50_i2c_port[] = {
-       0x00e138, 0x00e150, 0x00e168, 0x00e180,
-       0x00e254, 0x00e274, 0x00e764, 0x00e780,
-       0x00e79c, 0x00e7b8
-};
-#define NV50_I2C_PORTS ARRAY_SIZE(nv50_i2c_port)
-
 static int
 nv50_i2c_getscl(void *data)
 {
@@ -125,7 +118,6 @@ nv50_i2c_getscl(void *data)
        return !!(nv_rd32(dev, i2c->rd) & 1);
 }
 
-
 static int
 nv50_i2c_getsda(void *data)
 {
@@ -166,125 +158,233 @@ nvd0_i2c_getsda(void *data)
        return !!(nv_rd32(i2c->dev, i2c->rd) & 0x20);
 }
 
+static const uint32_t nv50_i2c_port[] = {
+       0x00e138, 0x00e150, 0x00e168, 0x00e180,
+       0x00e254, 0x00e274, 0x00e764, 0x00e780,
+       0x00e79c, 0x00e7b8
+};
+
+static u8 *
+i2c_table(struct drm_device *dev, u8 *version)
+{
+       u8 *dcb = dcb_table(dev), *i2c = NULL;
+       if (dcb) {
+               if (dcb[0] >= 0x15)
+                       i2c = ROMPTR(dev, dcb[2]);
+               if (dcb[0] >= 0x30)
+                       i2c = ROMPTR(dev, dcb[4]);
+       }
+
+       /* early revisions had no version number, use dcb version */
+       if (i2c) {
+               *version = dcb[0];
+               if (*version >= 0x30)
+                       *version = i2c[0];
+       }
+
+       return i2c;
+}
+
 int
-nouveau_i2c_init(struct drm_device *dev, struct dcb_i2c_entry *entry, int index)
+nouveau_i2c_init(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_i2c_chan *i2c;
-       int ret;
-
-       if (entry->chan)
-               return -EEXIST;
+       struct nvbios *bios = &dev_priv->vbios;
+       struct nouveau_i2c_chan *port;
+       u8 *i2c, *entry, legacy[2][4] = {};
+       u8 version, entries, recordlen;
+       int ret, i;
+
+       INIT_LIST_HEAD(&dev_priv->i2c_ports);
+
+       i2c = i2c_table(dev, &version);
+       if (!i2c) {
+               u8 *bmp = &bios->data[bios->offset];
+               if (bios->type != NVBIOS_BMP)
+                       return -ENODEV;
+
+               legacy[0][0] = NV_CIO_CRE_DDC_WR__INDEX;
+               legacy[0][1] = NV_CIO_CRE_DDC_STATUS__INDEX;
+               legacy[1][0] = NV_CIO_CRE_DDC0_WR__INDEX;
+               legacy[1][1] = NV_CIO_CRE_DDC0_STATUS__INDEX;
+
+               /* BMP (from v4.0) has i2c info in the structure, it's in a
+                * fixed location on earlier VBIOS
+                */
+               if (bmp[5] < 4)
+                       i2c = &bios->data[0x48];
+               else
+                       i2c = &bmp[0x36];
+
+               if (i2c[4]) legacy[0][0] = i2c[4];
+               if (i2c[5]) legacy[0][1] = i2c[5];
+               if (i2c[6]) legacy[1][0] = i2c[6];
+               if (i2c[7]) legacy[1][1] = i2c[7];
+       }
 
-       if (dev_priv->card_type >= NV_50 &&
-           dev_priv->card_type <= NV_C0 && entry->read >= NV50_I2C_PORTS) {
-               NV_ERROR(dev, "unknown i2c port %d\n", entry->read);
-               return -EINVAL;
+       if (i2c && version >= 0x30) {
+               entry     = i2c[1] + i2c;
+               entries   = i2c[2];
+               recordlen = i2c[3];
+       } else
+       if (i2c) {
+               entry     = i2c;
+               entries   = 16;
+               recordlen = 4;
+       } else {
+               entry     = legacy[0];
+               entries   = 2;
+               recordlen = 4;
        }
 
-       i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
-       if (i2c == NULL)
-               return -ENOMEM;
-
-       switch (entry->port_type) {
-       case 0:
-               i2c->bit.setsda = nv04_i2c_setsda;
-               i2c->bit.setscl = nv04_i2c_setscl;
-               i2c->bit.getsda = nv04_i2c_getsda;
-               i2c->bit.getscl = nv04_i2c_getscl;
-               i2c->rd = entry->read;
-               i2c->wr = entry->write;
-               break;
-       case 4:
-               i2c->bit.setsda = nv4e_i2c_setsda;
-               i2c->bit.setscl = nv4e_i2c_setscl;
-               i2c->bit.getsda = nv4e_i2c_getsda;
-               i2c->bit.getscl = nv4e_i2c_getscl;
-               i2c->rd = 0x600800 + entry->read;
-               i2c->wr = 0x600800 + entry->write;
-               break;
-       case 5:
-               i2c->bit.setsda = nv50_i2c_setsda;
-               i2c->bit.setscl = nv50_i2c_setscl;
-               if (dev_priv->card_type < NV_D0) {
-                       i2c->bit.getsda = nv50_i2c_getsda;
-                       i2c->bit.getscl = nv50_i2c_getscl;
-                       i2c->rd = nv50_i2c_port[entry->read];
-                       i2c->wr = i2c->rd;
+       for (i = 0; i < entries; i++, entry += recordlen) {
+               port = kzalloc(sizeof(*port), GFP_KERNEL);
+               if (port == NULL) {
+                       nouveau_i2c_fini(dev);
+                       return -ENOMEM;
+               }
+
+               port->type = entry[3];
+               if (version < 0x30) {
+                       port->type &= 0x07;
+                       if (port->type == 0x07)
+                               port->type = 0xff;
+               }
+
+               if (port->type == 0xff) {
+                       kfree(port);
+                       continue;
+               }
+
+               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;
+                       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;
+                       break;
+               case 5: /* NV50- */
+                       port->wr = entry[0] & 0x0f;
+                       if (dev_priv->card_type < NV_D0) {
+                               if (port->wr >= 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;
+                       } else {
+                               port->wr = 0x00d014 + (port->wr * 0x20);
+                               port->rd = port->wr;
+                               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;
+               case 6: /* NV50- DP AUX */
+                       port->wr = entry[0];
+                       port->rd = port->wr;
+                       port->adapter.algo = &nouveau_dp_i2c_algo;
+                       break;
+               default:
+                       break;
+               }
+
+               if (!port->adapter.algo && !port->wr) {
+                       NV_ERROR(dev, "I2C%d: type %d index %x/%x unknown\n",
+                                i, port->type, port->wr, port->rd);
+                       kfree(port);
+                       continue;
+               }
+
+               snprintf(port->adapter.name, sizeof(port->adapter.name),
+                        "nouveau-%s-%d", pci_name(dev->pdev), i);
+               port->adapter.owner = THIS_MODULE;
+               port->adapter.dev.parent = &dev->pdev->dev;
+               port->dev = dev;
+               port->index = i;
+               port->dcb = ROM32(entry[0]);
+               i2c_set_adapdata(&port->adapter, i2c);
+
+               if (port->adapter.algo != &nouveau_dp_i2c_algo) {
+                       port->adapter.algo_data = &port->bit;
+                       port->bit.udelay = 40;
+                       port->bit.timeout = usecs_to_jiffies(5000);
+                       port->bit.data = port;
+                       ret = i2c_bit_add_bus(&port->adapter);
                } else {
-                       i2c->bit.getsda = nvd0_i2c_getsda;
-                       i2c->bit.getscl = nvd0_i2c_getscl;
-                       i2c->rd = 0x00d014 + (entry->read * 0x20);
-                       i2c->wr = i2c->rd;
+                       port->adapter.algo = &nouveau_dp_i2c_algo;
+                       ret = i2c_add_adapter(&port->adapter);
                }
-               break;
-       case 6:
-               i2c->rd = entry->read;
-               i2c->wr = entry->write;
-               break;
-       default:
-               NV_ERROR(dev, "DCB I2C port type %d unknown\n",
-                        entry->port_type);
-               kfree(i2c);
-               return -EINVAL;
-       }
 
-       snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),
-                "nouveau-%s-%d", pci_name(dev->pdev), index);
-       i2c->adapter.owner = THIS_MODULE;
-       i2c->adapter.dev.parent = &dev->pdev->dev;
-       i2c->dev = dev;
-       i2c_set_adapdata(&i2c->adapter, i2c);
-
-       if (entry->port_type < 6) {
-               i2c->adapter.algo_data = &i2c->bit;
-               i2c->bit.udelay = 40;
-               i2c->bit.timeout = usecs_to_jiffies(5000);
-               i2c->bit.data = i2c;
-               ret = i2c_bit_add_bus(&i2c->adapter);
-       } else {
-               i2c->adapter.algo = &nouveau_dp_i2c_algo;
-               ret = i2c_add_adapter(&i2c->adapter);
-       }
+               if (ret) {
+                       NV_ERROR(dev, "I2C%d: failed register: %d\n", i, ret);
+                       kfree(port);
+                       continue;
+               }
 
-       if (ret) {
-               NV_ERROR(dev, "Failed to register i2c %d\n", index);
-               kfree(i2c);
-               return ret;
+               list_add_tail(&port->head, &dev_priv->i2c_ports);
        }
 
-       entry->chan = i2c;
        return 0;
 }
 
 void
-nouveau_i2c_fini(struct drm_device *dev, struct dcb_i2c_entry *entry)
+nouveau_i2c_fini(struct drm_device *dev)
 {
-       if (!entry->chan)
-               return;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_i2c_chan *port, *tmp;
 
-       i2c_del_adapter(&entry->chan->adapter);
-       kfree(entry->chan);
-       entry->chan = NULL;
+       list_for_each_entry_safe(port, tmp, &dev_priv->i2c_ports, head) {
+               i2c_del_adapter(&port->adapter);
+               kfree(port);
+       }
 }
 
 struct nouveau_i2c_chan *
-nouveau_i2c_find(struct drm_device *dev, int index)
+nouveau_i2c_find(struct drm_device *dev, u8 index)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct dcb_i2c_entry *i2c = &dev_priv->vbios.dcb.i2c[index];
+       struct nouveau_i2c_chan *port;
+
+       if (index == NV_I2C_DEFAULT(0) ||
+           index == NV_I2C_DEFAULT(1)) {
+               u8 version, *i2c = i2c_table(dev, &version);
+               if (i2c && version >= 0x30) {
+                       if (index == NV_I2C_DEFAULT(0))
+                               index = (i2c[4] & 0x0f);
+                       else
+                               index = (i2c[4] & 0xf0) >> 4;
+               } else {
+                       index = 2;
+               }
+       }
 
-       if (index >= DCB_MAX_NUM_I2C_ENTRIES)
-               return NULL;
+       list_for_each_entry(port, &dev_priv->i2c_ports, head) {
+               if (port->index == index)
+                       break;
+       }
 
-       if (dev_priv->card_type >= NV_50 && (i2c->entry & 0x00000100)) {
-               uint32_t reg = 0xe500, val;
+       if (&port->head == &dev_priv->i2c_ports)
+               return NULL;
 
-               if (i2c->port_type == 6) {
-                       reg += i2c->read * 0x50;
+       if (dev_priv->card_type >= NV_50 && (port->dcb & 0x00000100)) {
+               u32 reg = 0x00e500, val;
+               if (port->type == 6) {
+                       reg += port->rd * 0x50;
                        val  = 0x2002;
                } else {
-                       reg += ((i2c->entry & 0x1e00) >> 9) * 0x50;
+                       reg += ((port->dcb & 0x1e00) >> 9) * 0x50;
                        val  = 0xe001;
                }
 
@@ -294,9 +394,7 @@ nouveau_i2c_find(struct drm_device *dev, int index)
                nv_mask(dev, reg + 0x00, 0x0000f003, val);
        }
 
-       if (!i2c->chan && nouveau_i2c_init(dev, i2c, index))
-               return NULL;
-       return i2c->chan;
+       return port;
 }
 
 bool
index 422b62fd8272487dd78bb3d276dbfe70dd8e80fe..cf5f67d51fbac2e21bd4bc31e49c8b5b50420c28 100644 (file)
 #include <linux/i2c-algo-bit.h>
 #include "drm_dp_helper.h"
 
-struct dcb_i2c_entry;
+#define NV_I2C_PORT(n)    (0x00 + (n))
+#define NV_I2C_PORT_NUM    0x10
+#define NV_I2C_DEFAULT(n) (0x80 + (n))
 
 struct nouveau_i2c_chan {
        struct i2c_adapter adapter;
        struct drm_device *dev;
        struct i2c_algo_bit_data bit;
+       struct list_head head;
+       u8  index;
+       u8  type;
+       u32 dcb;
        unsigned rd;
        unsigned wr;
        unsigned data;
 };
 
-int nouveau_i2c_init(struct drm_device *, struct dcb_i2c_entry *, int index);
-void nouveau_i2c_fini(struct drm_device *, struct dcb_i2c_entry *);
-struct nouveau_i2c_chan *nouveau_i2c_find(struct drm_device *, int index);
+int  nouveau_i2c_init(struct drm_device *);
+void nouveau_i2c_fini(struct drm_device *);
+struct nouveau_i2c_chan *nouveau_i2c_find(struct drm_device *, u8 index);
 bool nouveau_probe_i2c_addr(struct nouveau_i2c_chan *i2c, int addr);
 int nouveau_i2c_identify(struct drm_device *dev, const char *what,
                         struct i2c_board_info *info,
index 4c46adeb0715e5b29f780203454f277e1e787bfb..0f5a301605569988231365f48af9cab73a9bce2f 100644 (file)
@@ -286,8 +286,6 @@ probe_monitoring_device(struct nouveau_i2c_chan *i2c,
 static void
 nouveau_temp_probe_i2c(struct drm_device *dev)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct dcb_table *dcb = &dev_priv->vbios.dcb;
        struct i2c_board_info info[] = {
                { I2C_BOARD_INFO("w83l785ts", 0x2d) },
                { I2C_BOARD_INFO("w83781d", 0x2d) },
@@ -296,11 +294,9 @@ nouveau_temp_probe_i2c(struct drm_device *dev)
                { I2C_BOARD_INFO("lm99", 0x4c) },
                { }
        };
-       int idx = (dcb->version >= 0x40 ?
-                  dcb->i2c_default_indices & 0xf : 2);
 
        nouveau_i2c_identify(dev, "monitoring device", info,
-                            probe_monitoring_device, idx);
+                            probe_monitoring_device, NV_I2C_DEFAULT(0));
 }
 
 void