Commit 309a5702 authored by Ben Skeggs's avatar Ben Skeggs

drm/nouveau/bios: store aux addr independently of i2c

Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent a7468451
...@@ -16,6 +16,7 @@ struct dcb_i2c_entry { ...@@ -16,6 +16,7 @@ struct dcb_i2c_entry {
u8 drive; u8 drive;
u8 sense; u8 sense;
u8 share; u8 share;
u8 auxch;
}; };
u16 dcb_i2c_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len); u16 dcb_i2c_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
......
...@@ -39,6 +39,11 @@ dcb_i2c_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) ...@@ -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); 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) { if (i2c && *ver >= 0x30) {
*ver = nv_ro08(bios, i2c + 0); *ver = nv_ro08(bios, i2c + 0);
*hdr = nv_ro08(bios, i2c + 1); *hdr = nv_ro08(bios, i2c + 1);
...@@ -70,14 +75,19 @@ dcb_i2c_parse(struct nouveau_bios *bios, u8 idx, struct dcb_i2c_entry *info) ...@@ -70,14 +75,19 @@ dcb_i2c_parse(struct nouveau_bios *bios, u8 idx, struct dcb_i2c_entry *info)
u8 ver, len; u8 ver, len;
u16 ent = dcb_i2c_entry(bios, idx, &ver, &len); u16 ent = dcb_i2c_entry(bios, idx, &ver, &len);
if (ent) { if (ent) {
info->type = nv_ro08(bios, ent + 3); if (ver >= 0x30) {
info->share = DCB_I2C_UNUSED; info->type = nv_ro08(bios, ent + 0x03);
if (ver < 0x30) { } else {
info->type &= 0x07; info->type = nv_ro08(bios, ent + 0x03) & 0x07;
if (info->type == 0x07) if (info->type == 0x07)
info->type = DCB_I2C_UNUSED; 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) { switch (info->type) {
case DCB_I2C_NV04_BIT: case DCB_I2C_NV04_BIT:
info->drive = nv_ro08(bios, ent + 0); 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) ...@@ -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); info->drive = nv_ro08(bios, ent + 1);
return 0; return 0;
case DCB_I2C_NVIO_BIT: case DCB_I2C_NVIO_BIT:
case DCB_I2C_NVIO_AUX:
info->drive = nv_ro08(bios, ent + 0) & 0x0f; info->drive = nv_ro08(bios, ent + 0) & 0x0f;
if (nv_ro08(bios, ent + 1) & 0x01) { if (nv_ro08(bios, ent + 1) & 0x01)
info->share = nv_ro08(bios, ent + 1) >> 1; info->share = nv_ro08(bios, ent + 1) >> 1;
info->share &= 0x0f; 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; return 0;
case DCB_I2C_UNUSED: case DCB_I2C_UNUSED:
return 0; return 0;
......
...@@ -473,18 +473,56 @@ nouveau_i2c_extdev_sclass[] = { ...@@ -473,18 +473,56 @@ nouveau_i2c_extdev_sclass[] = {
nouveau_anx9805_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 int
nouveau_i2c_create_(struct nouveau_object *parent, nouveau_i2c_create_(struct nouveau_object *parent,
struct nouveau_object *engine, struct nouveau_object *engine,
struct nouveau_oclass *oclass, struct nouveau_oclass *oclass,
int length, void **pobject) int length, void **pobject)
{ {
const struct nouveau_i2c_impl *impl = (void *)oclass;
struct nouveau_bios *bios = nouveau_bios(parent); struct nouveau_bios *bios = nouveau_bios(parent);
struct nouveau_i2c *i2c; struct nouveau_i2c *i2c;
struct nouveau_object *object; struct nouveau_object *object;
struct dcb_i2c_entry info; struct dcb_i2c_entry info;
int ret, i, j, index = -1, pad; int ret, i, j, index = -1;
struct dcb_output outp; struct dcb_output outp;
u8 ver, hdr; u8 ver, hdr;
u32 data; u32 data;
...@@ -507,36 +545,17 @@ nouveau_i2c_create_(struct nouveau_object *parent, ...@@ -507,36 +545,17 @@ nouveau_i2c_create_(struct nouveau_object *parent,
INIT_LIST_HEAD(&i2c->ports); INIT_LIST_HEAD(&i2c->ports);
while (!dcb_i2c_parse(bios, ++index, &info)) { while (!dcb_i2c_parse(bios, ++index, &info)) {
if (info.type == DCB_I2C_UNUSED) switch (info.type) {
continue; case DCB_I2C_NV04_BIT:
case DCB_I2C_NV4E_BIT:
if (info.share != DCB_I2C_UNUSED) { case DCB_I2C_NVIO_BIT:
if (info.type == DCB_I2C_NVIO_AUX) case DCB_I2C_NVIO_AUX:
pad = info.drive; nouveau_i2c_create_port(i2c, index, info.type, &info);
else break;
pad = info.share; case DCB_I2C_UNUSED:
oclass = impl->pad_s; default:
} else {
pad = 0x100 + info.drive;
oclass = impl->pad_x;
}
ret = nouveau_object_ctor(NULL, *pobject, oclass,
NULL, pad, &parent);
if (ret < 0)
continue; 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 /* in addition to the busses specified in the i2c table, there
......
...@@ -238,8 +238,8 @@ nv94_aux_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -238,8 +238,8 @@ nv94_aux_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret) if (ret)
return ret; return ret;
port->base.aux = info->drive; port->base.aux = info->auxch;
port->addr = info->drive; port->addr = info->auxch;
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment