drm/nouveau/bios: store aux addr independently of i2c
authorBen Skeggs <bskeggs@redhat.com>
Mon, 18 Aug 2014 22:14:08 +0000 (08:14 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Tue, 2 Dec 2014 05:43:44 +0000 (15:43 +1000)
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/core/include/subdev/bios/i2c.h
drivers/gpu/drm/nouveau/core/subdev/bios/i2c.c
drivers/gpu/drm/nouveau/core/subdev/i2c/base.c
drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c

index 10b57a1..79c1252 100644 (file)
@@ -16,6 +16,7 @@ struct dcb_i2c_entry {
        u8 drive;
        u8 sense;
        u8 share;
+       u8 auxch;
 };
 
 u16 dcb_i2c_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
index cfb9288..19ac30b 100644 (file)
@@ -39,6 +39,11 @@ dcb_i2c_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
                        i2c = nv_ro16(bios, dcb + 4);
        }
 
+       if (i2c && *ver >= 0x41) {
+               nv_warn(bios, "ccb %02x not supported\n", *ver);
+               return 0x0000;
+       }
+
        if (i2c && *ver >= 0x30) {
                *ver = nv_ro08(bios, i2c + 0);
                *hdr = nv_ro08(bios, i2c + 1);
@@ -70,14 +75,19 @@ dcb_i2c_parse(struct nouveau_bios *bios, u8 idx, struct dcb_i2c_entry *info)
        u8  ver, len;
        u16 ent = dcb_i2c_entry(bios, idx, &ver, &len);
        if (ent) {
-               info->type  = nv_ro08(bios, ent + 3);
-               info->share = DCB_I2C_UNUSED;
-               if (ver < 0x30) {
-                       info->type &= 0x07;
+               if (ver >= 0x30) {
+                       info->type = nv_ro08(bios, ent + 0x03);
+               } else {
+                       info->type = nv_ro08(bios, ent + 0x03) & 0x07;
                        if (info->type == 0x07)
                                info->type = DCB_I2C_UNUSED;
                }
 
+               info->drive = DCB_I2C_UNUSED;
+               info->sense = DCB_I2C_UNUSED;
+               info->share = DCB_I2C_UNUSED;
+               info->auxch = DCB_I2C_UNUSED;
+
                switch (info->type) {
                case DCB_I2C_NV04_BIT:
                        info->drive = nv_ro08(bios, ent + 0);
@@ -87,12 +97,14 @@ dcb_i2c_parse(struct nouveau_bios *bios, u8 idx, struct dcb_i2c_entry *info)
                        info->drive = nv_ro08(bios, ent + 1);
                        return 0;
                case DCB_I2C_NVIO_BIT:
-               case DCB_I2C_NVIO_AUX:
                        info->drive = nv_ro08(bios, ent + 0) & 0x0f;
-                       if (nv_ro08(bios, ent + 1) & 0x01) {
-                               info->share  = nv_ro08(bios, ent + 1) >> 1;
-                               info->share &= 0x0f;
-                       }
+                       if (nv_ro08(bios, ent + 1) & 0x01)
+                               info->share = nv_ro08(bios, ent + 1) >> 1;
+                       return 0;
+               case DCB_I2C_NVIO_AUX:
+                       info->auxch = nv_ro08(bios, ent + 0) & 0x0f;
+                       if (nv_ro08(bios, ent + 1) & 0x01)
+                               info->share = info->auxch;
                        return 0;
                case DCB_I2C_UNUSED:
                        return 0;
index 2b1bf54..90d1660 100644 (file)
@@ -473,18 +473,56 @@ nouveau_i2c_extdev_sclass[] = {
        nouveau_anx9805_sclass,
 };
 
+static void
+nouveau_i2c_create_port(struct nouveau_i2c *i2c, int index, u8 type,
+                       struct dcb_i2c_entry *info)
+{
+       const struct nouveau_i2c_impl *impl = (void *)nv_oclass(i2c);
+       struct nouveau_oclass *oclass;
+       struct nouveau_object *parent;
+       struct nouveau_object *object;
+       int ret, pad;
+
+       if (info->share != DCB_I2C_UNUSED) {
+               pad    = info->share;
+               oclass = impl->pad_s;
+       } else {
+               if (type != DCB_I2C_NVIO_AUX)
+                       pad = 0x100 + info->drive;
+               else
+                       pad = 0x100 + info->auxch;
+               oclass = impl->pad_x;
+       }
+
+       ret = nouveau_object_ctor(NULL, nv_object(i2c), oclass, NULL, pad,
+                                &parent);
+       if (ret < 0)
+               return;
+
+       oclass = impl->sclass;
+       do {
+               ret = -EINVAL;
+               if (oclass->handle == type) {
+                       ret = nouveau_object_ctor(parent, nv_object(i2c),
+                                                 oclass, info, index,
+                                                &object);
+               }
+       } while (ret && (++oclass)->handle);
+
+       nouveau_object_ref(NULL, &parent);
+}
+
 int
 nouveau_i2c_create_(struct nouveau_object *parent,
                    struct nouveau_object *engine,
                    struct nouveau_oclass *oclass,
                    int length, void **pobject)
 {
-       const struct nouveau_i2c_impl *impl = (void *)oclass;
        struct nouveau_bios *bios = nouveau_bios(parent);
        struct nouveau_i2c *i2c;
        struct nouveau_object *object;
        struct dcb_i2c_entry info;
-       int ret, i, j, index = -1, pad;
+       int ret, i, j, index = -1;
        struct dcb_output outp;
        u8  ver, hdr;
        u32 data;
@@ -507,36 +545,17 @@ nouveau_i2c_create_(struct nouveau_object *parent,
        INIT_LIST_HEAD(&i2c->ports);
 
        while (!dcb_i2c_parse(bios, ++index, &info)) {
-               if (info.type == DCB_I2C_UNUSED)
+               switch (info.type) {
+               case DCB_I2C_NV04_BIT:
+               case DCB_I2C_NV4E_BIT:
+               case DCB_I2C_NVIO_BIT:
+               case DCB_I2C_NVIO_AUX:
+                       nouveau_i2c_create_port(i2c, index, info.type, &info);
+                       break;
+               case DCB_I2C_UNUSED:
+               default:
                        continue;
-
-               if (info.share != DCB_I2C_UNUSED) {
-                       if (info.type == DCB_I2C_NVIO_AUX)
-                               pad = info.drive;
-                       else
-                               pad = info.share;
-                       oclass = impl->pad_s;
-               } else {
-                       pad = 0x100 + info.drive;
-                       oclass = impl->pad_x;
                }
-
-               ret = nouveau_object_ctor(NULL, *pobject, oclass,
-                                         NULL, pad, &parent);
-               if (ret < 0)
-                       continue;
-
-               oclass = impl->sclass;
-               do {
-                       ret = -EINVAL;
-                       if (oclass->handle == info.type) {
-                               ret = nouveau_object_ctor(parent, *pobject,
-                                                         oclass, &info,
-                                                         index, &object);
-                       }
-               } while (ret && (++oclass)->handle);
-
-               nouveau_object_ref(NULL, &parent);
        }
 
        /* in addition to the busses specified in the i2c table, there
index 60fdd48..e383ee8 100644 (file)
@@ -238,8 +238,8 @@ nv94_aux_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        if (ret)
                return ret;
 
-       port->base.aux = info->drive;
-       port->addr = info->drive;
+       port->base.aux = info->auxch;
+       port->addr = info->auxch;
        return 0;
 }