aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2014-08-18 18:14:08 -0400
committerBen Skeggs <bskeggs@redhat.com>2014-12-02 00:43:44 -0500
commit309a5702c23f556d2125c38f7370eab4da0e479d (patch)
tree4d12741c0bba7cf230483a41d74c4056df87c55f
parenta7468451e3439608692cef303222b64faf75e48b (diff)
drm/nouveau/bios: store aux addr independently of i2c
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/i2c.h1
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/i2c.c30
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/base.c79
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c4
4 files changed, 73 insertions, 41 deletions
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/i2c.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/i2c.h
index 10b57a19a7de..79c1252e5c34 100644
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/i2c.h
+++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/i2c.h
@@ -16,6 +16,7 @@ struct dcb_i2c_entry {
16 u8 drive; 16 u8 drive;
17 u8 sense; 17 u8 sense;
18 u8 share; 18 u8 share;
19 u8 auxch;
19}; 20};
20 21
21u16 dcb_i2c_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len); 22u16 dcb_i2c_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/i2c.c b/drivers/gpu/drm/nouveau/core/subdev/bios/i2c.c
index cfb9288c6d28..19ac30b28294 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/i2c.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/bios/i2c.c
@@ -39,6 +39,11 @@ dcb_i2c_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
39 i2c = nv_ro16(bios, dcb + 4); 39 i2c = nv_ro16(bios, dcb + 4);
40 } 40 }
41 41
42 if (i2c && *ver >= 0x41) {
43 nv_warn(bios, "ccb %02x not supported\n", *ver);
44 return 0x0000;
45 }
46
42 if (i2c && *ver >= 0x30) { 47 if (i2c && *ver >= 0x30) {
43 *ver = nv_ro08(bios, i2c + 0); 48 *ver = nv_ro08(bios, i2c + 0);
44 *hdr = nv_ro08(bios, i2c + 1); 49 *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 u8 ver, len; 75 u8 ver, len;
71 u16 ent = dcb_i2c_entry(bios, idx, &ver, &len); 76 u16 ent = dcb_i2c_entry(bios, idx, &ver, &len);
72 if (ent) { 77 if (ent) {
73 info->type = nv_ro08(bios, ent + 3); 78 if (ver >= 0x30) {
74 info->share = DCB_I2C_UNUSED; 79 info->type = nv_ro08(bios, ent + 0x03);
75 if (ver < 0x30) { 80 } else {
76 info->type &= 0x07; 81 info->type = nv_ro08(bios, ent + 0x03) & 0x07;
77 if (info->type == 0x07) 82 if (info->type == 0x07)
78 info->type = DCB_I2C_UNUSED; 83 info->type = DCB_I2C_UNUSED;
79 } 84 }
80 85
86 info->drive = DCB_I2C_UNUSED;
87 info->sense = DCB_I2C_UNUSED;
88 info->share = DCB_I2C_UNUSED;
89 info->auxch = DCB_I2C_UNUSED;
90
81 switch (info->type) { 91 switch (info->type) {
82 case DCB_I2C_NV04_BIT: 92 case DCB_I2C_NV04_BIT:
83 info->drive = nv_ro08(bios, ent + 0); 93 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 info->drive = nv_ro08(bios, ent + 1); 97 info->drive = nv_ro08(bios, ent + 1);
88 return 0; 98 return 0;
89 case DCB_I2C_NVIO_BIT: 99 case DCB_I2C_NVIO_BIT:
90 case DCB_I2C_NVIO_AUX:
91 info->drive = nv_ro08(bios, ent + 0) & 0x0f; 100 info->drive = nv_ro08(bios, ent + 0) & 0x0f;
92 if (nv_ro08(bios, ent + 1) & 0x01) { 101 if (nv_ro08(bios, ent + 1) & 0x01)
93 info->share = nv_ro08(bios, ent + 1) >> 1; 102 info->share = nv_ro08(bios, ent + 1) >> 1;
94 info->share &= 0x0f; 103 return 0;
95 } 104 case DCB_I2C_NVIO_AUX:
105 info->auxch = nv_ro08(bios, ent + 0) & 0x0f;
106 if (nv_ro08(bios, ent + 1) & 0x01)
107 info->share = info->auxch;
96 return 0; 108 return 0;
97 case DCB_I2C_UNUSED: 109 case DCB_I2C_UNUSED:
98 return 0; 110 return 0;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c
index 2b1bf545e488..90d1660b8efa 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c
@@ -473,18 +473,56 @@ nouveau_i2c_extdev_sclass[] = {
473 nouveau_anx9805_sclass, 473 nouveau_anx9805_sclass,
474}; 474};
475 475
476static void
477nouveau_i2c_create_port(struct nouveau_i2c *i2c, int index, u8 type,
478 struct dcb_i2c_entry *info)
479{
480 const struct nouveau_i2c_impl *impl = (void *)nv_oclass(i2c);
481 struct nouveau_oclass *oclass;
482 struct nouveau_object *parent;
483 struct nouveau_object *object;
484 int ret, pad;
485
486 if (info->share != DCB_I2C_UNUSED) {
487 pad = info->share;
488 oclass = impl->pad_s;
489 } else {
490 if (type != DCB_I2C_NVIO_AUX)
491 pad = 0x100 + info->drive;
492 else
493 pad = 0x100 + info->auxch;
494 oclass = impl->pad_x;
495 }
496
497 ret = nouveau_object_ctor(NULL, nv_object(i2c), oclass, NULL, pad,
498 &parent);
499 if (ret < 0)
500 return;
501
502 oclass = impl->sclass;
503 do {
504 ret = -EINVAL;
505 if (oclass->handle == type) {
506 ret = nouveau_object_ctor(parent, nv_object(i2c),
507 oclass, info, index,
508 &object);
509 }
510 } while (ret && (++oclass)->handle);
511
512 nouveau_object_ref(NULL, &parent);
513}
514
476int 515int
477nouveau_i2c_create_(struct nouveau_object *parent, 516nouveau_i2c_create_(struct nouveau_object *parent,
478 struct nouveau_object *engine, 517 struct nouveau_object *engine,
479 struct nouveau_oclass *oclass, 518 struct nouveau_oclass *oclass,
480 int length, void **pobject) 519 int length, void **pobject)
481{ 520{
482 const struct nouveau_i2c_impl *impl = (void *)oclass;
483 struct nouveau_bios *bios = nouveau_bios(parent); 521 struct nouveau_bios *bios = nouveau_bios(parent);
484 struct nouveau_i2c *i2c; 522 struct nouveau_i2c *i2c;
485 struct nouveau_object *object; 523 struct nouveau_object *object;
486 struct dcb_i2c_entry info; 524 struct dcb_i2c_entry info;
487 int ret, i, j, index = -1, pad; 525 int ret, i, j, index = -1;
488 struct dcb_output outp; 526 struct dcb_output outp;
489 u8 ver, hdr; 527 u8 ver, hdr;
490 u32 data; 528 u32 data;
@@ -507,36 +545,17 @@ nouveau_i2c_create_(struct nouveau_object *parent,
507 INIT_LIST_HEAD(&i2c->ports); 545 INIT_LIST_HEAD(&i2c->ports);
508 546
509 while (!dcb_i2c_parse(bios, ++index, &info)) { 547 while (!dcb_i2c_parse(bios, ++index, &info)) {
510 if (info.type == DCB_I2C_UNUSED) 548 switch (info.type) {
549 case DCB_I2C_NV04_BIT:
550 case DCB_I2C_NV4E_BIT:
551 case DCB_I2C_NVIO_BIT:
552 case DCB_I2C_NVIO_AUX:
553 nouveau_i2c_create_port(i2c, index, info.type, &info);
554 break;
555 case DCB_I2C_UNUSED:
556 default:
511 continue; 557 continue;
512
513 if (info.share != DCB_I2C_UNUSED) {
514 if (info.type == DCB_I2C_NVIO_AUX)
515 pad = info.drive;
516 else
517 pad = info.share;
518 oclass = impl->pad_s;
519 } else {
520 pad = 0x100 + info.drive;
521 oclass = impl->pad_x;
522 } 558 }
523
524 ret = nouveau_object_ctor(NULL, *pobject, oclass,
525 NULL, pad, &parent);
526 if (ret < 0)
527 continue;
528
529 oclass = impl->sclass;
530 do {
531 ret = -EINVAL;
532 if (oclass->handle == info.type) {
533 ret = nouveau_object_ctor(parent, *pobject,
534 oclass, &info,
535 index, &object);
536 }
537 } while (ret && (++oclass)->handle);
538
539 nouveau_object_ref(NULL, &parent);
540 } 559 }
541 560
542 /* in addition to the busses specified in the i2c table, there 561 /* in addition to the busses specified in the i2c table, there
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c
index 60fdd4884cd9..e383ee81f4d2 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c
@@ -238,8 +238,8 @@ nv94_aux_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
238 if (ret) 238 if (ret)
239 return ret; 239 return ret;
240 240
241 port->base.aux = info->drive; 241 port->base.aux = info->auxch;
242 port->addr = info->drive; 242 port->addr = info->auxch;
243 return 0; 243 return 0;
244} 244}
245 245