diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2014-08-18 18:14:08 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2014-12-02 00:43:44 -0500 |
commit | 309a5702c23f556d2125c38f7370eab4da0e479d (patch) | |
tree | 4d12741c0bba7cf230483a41d74c4056df87c55f | |
parent | a7468451e3439608692cef303222b64faf75e48b (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.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/subdev/bios/i2c.c | 30 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/subdev/i2c/base.c | 79 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c | 4 |
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 | ||
21 | u16 dcb_i2c_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len); | 22 | u16 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 | ||
476 | static void | ||
477 | nouveau_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 | |||
476 | int | 515 | int |
477 | nouveau_i2c_create_(struct nouveau_object *parent, | 516 | nouveau_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 | ||