diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2011-11-10 00:42:55 -0500 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2011-12-21 04:01:39 -0500 |
commit | 6b5a81a2e783f26a69fc262b3c393f0b391c8613 (patch) | |
tree | 2989d40f2877c108a7f96f610c420df86674317a /drivers | |
parent | 0f8067c7054d22f240fca376e01430eecdc112df (diff) |
drm/nouveau/bios: start refactoring dcb routines
This primary reason for this was mostly to avoid duplication of some of
this stuff by the MXM-SIS parser. However, some other cleanups will also
follow this as a result.
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_bios.c | 270 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_bios.h | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drv.h | 7 |
3 files changed, 162 insertions, 121 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 61c5c3240e31..c7723fb54077 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c | |||
@@ -6048,6 +6048,109 @@ parse_dcb_connector_table(struct nvbios *bios) | |||
6048 | } | 6048 | } |
6049 | } | 6049 | } |
6050 | 6050 | ||
6051 | void * | ||
6052 | dcb_table(struct drm_device *dev) | ||
6053 | { | ||
6054 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
6055 | u8 *dcb = NULL; | ||
6056 | |||
6057 | if (dev_priv->card_type > NV_04) | ||
6058 | dcb = ROMPTR(dev, dev_priv->vbios.data[0x36]); | ||
6059 | if (!dcb) { | ||
6060 | NV_WARNONCE(dev, "No DCB data found in VBIOS\n"); | ||
6061 | return NULL; | ||
6062 | } | ||
6063 | |||
6064 | if (dcb[0] >= 0x41) { | ||
6065 | NV_WARNONCE(dev, "DCB version 0x%02x unknown\n", dcb[0]); | ||
6066 | return NULL; | ||
6067 | } else | ||
6068 | if (dcb[0] >= 0x30) { | ||
6069 | if (ROM32(dcb[6]) == 0x4edcbdcb) | ||
6070 | return dcb; | ||
6071 | } else | ||
6072 | if (dcb[0] >= 0x20) { | ||
6073 | if (ROM32(dcb[4]) == 0x4edcbdcb) | ||
6074 | return dcb; | ||
6075 | } else | ||
6076 | if (dcb[0] >= 0x15) { | ||
6077 | if (!memcmp(&dcb[-7], "DEV_REC", 7)) | ||
6078 | return dcb; | ||
6079 | } else { | ||
6080 | /* | ||
6081 | * v1.4 (some NV15/16, NV11+) seems the same as v1.5, but | ||
6082 | * always has the same single (crt) entry, even when tv-out | ||
6083 | * present, so the conclusion is this version cannot really | ||
6084 | * be used. | ||
6085 | * | ||
6086 | * v1.2 tables (some NV6/10, and NV15+) normally have the | ||
6087 | * same 5 entries, which are not specific to the card and so | ||
6088 | * no use. | ||
6089 | * | ||
6090 | * v1.2 does have an I2C table that read_dcb_i2c_table can | ||
6091 | * handle, but cards exist (nv11 in #14821) with a bad i2c | ||
6092 | * table pointer, so use the indices parsed in | ||
6093 | * parse_bmp_structure. | ||
6094 | * | ||
6095 | * v1.1 (NV5+, maybe some NV4) is entirely unhelpful | ||
6096 | */ | ||
6097 | NV_WARNONCE(dev, "No useful DCB data in VBIOS\n"); | ||
6098 | return NULL; | ||
6099 | } | ||
6100 | |||
6101 | NV_WARNONCE(dev, "DCB header validation failed\n"); | ||
6102 | return NULL; | ||
6103 | } | ||
6104 | |||
6105 | u8 * | ||
6106 | dcb_outp(struct drm_device *dev, u8 idx) | ||
6107 | { | ||
6108 | u8 *dcb = dcb_table(dev); | ||
6109 | if (dcb && dcb[0] >= 0x30) { | ||
6110 | if (idx < dcb[2]) | ||
6111 | return dcb + dcb[1] + (idx * dcb[3]); | ||
6112 | } else | ||
6113 | if (dcb && dcb[0] >= 0x20) { | ||
6114 | u8 *i2c = ROMPTR(dev, dcb[2]); | ||
6115 | u8 *ent = dcb + 8 + (idx * 8); | ||
6116 | if (i2c && ent < i2c) | ||
6117 | return ent; | ||
6118 | } else | ||
6119 | if (dcb && dcb[0] >= 0x15) { | ||
6120 | u8 *i2c = ROMPTR(dev, dcb[2]); | ||
6121 | u8 *ent = dcb + 4 + (idx * 10); | ||
6122 | if (i2c && ent < i2c) | ||
6123 | return ent; | ||
6124 | } | ||
6125 | |||
6126 | return NULL; | ||
6127 | } | ||
6128 | |||
6129 | int | ||
6130 | dcb_outp_foreach(struct drm_device *dev, void *data, | ||
6131 | int (*exec)(struct drm_device *, void *, int idx, u8 *outp)) | ||
6132 | { | ||
6133 | int ret, idx = -1; | ||
6134 | u8 *outp = NULL; | ||
6135 | while ((outp = dcb_outp(dev, ++idx))) { | ||
6136 | if (ROM32(outp[0]) == 0x00000000) | ||
6137 | break; /* seen on an NV11 with DCB v1.5 */ | ||
6138 | if (ROM32(outp[0]) == 0xffffffff) | ||
6139 | break; /* seen on an NV17 with DCB v2.0 */ | ||
6140 | |||
6141 | if ((outp[0] & 0x0f) == OUTPUT_UNUSED) | ||
6142 | continue; | ||
6143 | if ((outp[0] & 0x0f) == OUTPUT_EOL) | ||
6144 | break; | ||
6145 | |||
6146 | ret = exec(dev, data, idx, outp); | ||
6147 | if (ret) | ||
6148 | return ret; | ||
6149 | } | ||
6150 | |||
6151 | return 0; | ||
6152 | } | ||
6153 | |||
6051 | static struct dcb_entry *new_dcb_entry(struct dcb_table *dcb) | 6154 | static struct dcb_entry *new_dcb_entry(struct dcb_table *dcb) |
6052 | { | 6155 | { |
6053 | struct dcb_entry *entry = &dcb->entry[dcb->entries]; | 6156 | struct dcb_entry *entry = &dcb->entry[dcb->entries]; |
@@ -6251,25 +6354,6 @@ parse_dcb15_entry(struct drm_device *dev, struct dcb_table *dcb, | |||
6251 | return true; | 6354 | return true; |
6252 | } | 6355 | } |
6253 | 6356 | ||
6254 | static bool parse_dcb_entry(struct drm_device *dev, struct dcb_table *dcb, | ||
6255 | uint32_t conn, uint32_t conf) | ||
6256 | { | ||
6257 | struct dcb_entry *entry = new_dcb_entry(dcb); | ||
6258 | bool ret; | ||
6259 | |||
6260 | if (dcb->version >= 0x20) | ||
6261 | ret = parse_dcb20_entry(dev, dcb, conn, conf, entry); | ||
6262 | else | ||
6263 | ret = parse_dcb15_entry(dev, dcb, conn, conf, entry); | ||
6264 | if (!ret) | ||
6265 | return ret; | ||
6266 | |||
6267 | read_dcb_i2c_entry(dev, dcb->version, dcb->i2c_table, | ||
6268 | entry->i2c_index, &dcb->i2c[entry->i2c_index]); | ||
6269 | |||
6270 | return true; | ||
6271 | } | ||
6272 | |||
6273 | static | 6357 | static |
6274 | void merge_like_dcb_entries(struct drm_device *dev, struct dcb_table *dcb) | 6358 | void merge_like_dcb_entries(struct drm_device *dev, struct dcb_table *dcb) |
6275 | { | 6359 | { |
@@ -6446,88 +6530,62 @@ fabricate_dcb_encoder_table(struct drm_device *dev, struct nvbios *bios) | |||
6446 | } | 6530 | } |
6447 | 6531 | ||
6448 | static int | 6532 | static int |
6449 | parse_dcb_table(struct drm_device *dev, struct nvbios *bios) | 6533 | parse_dcb_entry(struct drm_device *dev, void *data, int idx, u8 *outp) |
6450 | { | 6534 | { |
6451 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 6535 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
6452 | struct dcb_table *dcb = &bios->dcb; | 6536 | struct dcb_table *dcb = &dev_priv->vbios.dcb; |
6453 | uint16_t dcbptr = 0, i2ctabptr = 0; | 6537 | u32 conf = (dcb->version >= 0x20) ? ROM32(outp[4]) : ROM32(outp[6]); |
6454 | uint8_t *dcbtable; | 6538 | u32 conn = ROM32(outp[0]); |
6455 | uint8_t headerlen = 0x4, entries = DCB_MAX_NUM_ENTRIES; | 6539 | bool ret; |
6456 | bool configblock = true; | ||
6457 | int recordlength = 8, confofs = 4; | ||
6458 | int i; | ||
6459 | 6540 | ||
6460 | /* get the offset from 0x36 */ | 6541 | if (apply_dcb_encoder_quirks(dev, idx, &conn, &conf)) { |
6461 | if (dev_priv->card_type > NV_04) { | 6542 | struct dcb_entry *entry = new_dcb_entry(dcb); |
6462 | dcbptr = ROM16(bios->data[0x36]); | ||
6463 | if (dcbptr == 0x0000) | ||
6464 | NV_WARN(dev, "No output data (DCB) found in BIOS\n"); | ||
6465 | } | ||
6466 | 6543 | ||
6467 | /* this situation likely means a really old card, pre DCB */ | 6544 | NV_TRACEWARN(dev, "DCB entry %02d: %08x %08x\n", idx, conn, conf); |
6468 | if (dcbptr == 0x0) { | ||
6469 | fabricate_dcb_encoder_table(dev, bios); | ||
6470 | return 0; | ||
6471 | } | ||
6472 | 6545 | ||
6473 | dcbtable = &bios->data[dcbptr]; | 6546 | if (dcb->version >= 0x20) |
6547 | ret = parse_dcb20_entry(dev, dcb, conn, conf, entry); | ||
6548 | else | ||
6549 | ret = parse_dcb15_entry(dev, dcb, conn, conf, entry); | ||
6550 | if (!ret) | ||
6551 | return 1; /* stop parsing */ | ||
6474 | 6552 | ||
6475 | /* get DCB version */ | 6553 | read_dcb_i2c_entry(dev, dcb->version, dcb->i2c_table, |
6476 | dcb->version = dcbtable[0]; | 6554 | entry->i2c_index, |
6477 | NV_TRACE(dev, "Found Display Configuration Block version %d.%d\n", | 6555 | &dcb->i2c[entry->i2c_index]); |
6478 | dcb->version >> 4, dcb->version & 0xf); | 6556 | } |
6479 | 6557 | ||
6480 | if (dcb->version >= 0x20) { /* NV17+ */ | 6558 | return 0; |
6481 | uint32_t sig; | 6559 | } |
6482 | 6560 | ||
6483 | if (dcb->version >= 0x30) { /* NV40+ */ | 6561 | static int |
6484 | headerlen = dcbtable[1]; | 6562 | parse_dcb_table(struct drm_device *dev, struct nvbios *bios) |
6485 | entries = dcbtable[2]; | 6563 | { |
6486 | recordlength = dcbtable[3]; | 6564 | struct dcb_table *dcb = &bios->dcb; |
6487 | i2ctabptr = ROM16(dcbtable[4]); | 6565 | u16 i2ctabptr = 0x0000; |
6488 | sig = ROM32(dcbtable[6]); | 6566 | u8 *dcbt; |
6489 | dcb->gpio_table_ptr = ROM16(dcbtable[10]); | 6567 | |
6490 | dcb->connector_table_ptr = ROM16(dcbtable[20]); | 6568 | dcbt = dcb_table(dev); |
6491 | } else { | 6569 | if (!dcbt) { |
6492 | i2ctabptr = ROM16(dcbtable[2]); | 6570 | /* handle pre-DCB boards */ |
6493 | sig = ROM32(dcbtable[4]); | 6571 | if (bios->type == NVBIOS_BMP) { |
6494 | headerlen = 8; | 6572 | fabricate_dcb_encoder_table(dev, bios); |
6573 | return 0; | ||
6495 | } | 6574 | } |
6496 | 6575 | ||
6497 | if (sig != 0x4edcbdcb) { | 6576 | return -EINVAL; |
6498 | NV_ERROR(dev, "Bad Display Configuration Block " | 6577 | } |
6499 | "signature (%08X)\n", sig); | ||
6500 | return -EINVAL; | ||
6501 | } | ||
6502 | } else if (dcb->version >= 0x15) { /* some NV11 and NV20 */ | ||
6503 | char sig[8] = { 0 }; | ||
6504 | 6578 | ||
6505 | strncpy(sig, (char *)&dcbtable[-7], 7); | 6579 | NV_TRACE(dev, "DCB version %d.%d\n", dcbt[0] >> 4, dcbt[0] & 0xf); |
6506 | i2ctabptr = ROM16(dcbtable[2]); | ||
6507 | recordlength = 10; | ||
6508 | confofs = 6; | ||
6509 | 6580 | ||
6510 | if (strcmp(sig, "DEV_REC")) { | 6581 | dcb->version = dcbt[0]; |
6511 | NV_ERROR(dev, "Bad Display Configuration Block " | 6582 | if (dcb->version >= 0x30) { |
6512 | "signature (%s)\n", sig); | 6583 | i2ctabptr = ROM16(dcbt[4]); |
6513 | return -EINVAL; | 6584 | dcb->gpio_table_ptr = ROM16(dcbt[10]); |
6514 | } | 6585 | dcb->connector_table_ptr = ROM16(dcbt[20]); |
6515 | } else { | 6586 | } else |
6516 | /* | 6587 | if (dcb->version >= 0x15) { |
6517 | * v1.4 (some NV15/16, NV11+) seems the same as v1.5, but always | 6588 | i2ctabptr = ROM16(dcbt[2]); |
6518 | * has the same single (crt) entry, even when tv-out present, so | ||
6519 | * the conclusion is this version cannot really be used. | ||
6520 | * v1.2 tables (some NV6/10, and NV15+) normally have the same | ||
6521 | * 5 entries, which are not specific to the card and so no use. | ||
6522 | * v1.2 does have an I2C table that read_dcb_i2c_table can | ||
6523 | * handle, but cards exist (nv11 in #14821) with a bad i2c table | ||
6524 | * pointer, so use the indices parsed in parse_bmp_structure. | ||
6525 | * v1.1 (NV5+, maybe some NV4) is entirely unhelpful | ||
6526 | */ | ||
6527 | NV_TRACEWARN(dev, "No useful information in BIOS output table; " | ||
6528 | "adding all possible outputs\n"); | ||
6529 | fabricate_dcb_encoder_table(dev, bios); | ||
6530 | return 0; | ||
6531 | } | 6589 | } |
6532 | 6590 | ||
6533 | if (!i2ctabptr) | 6591 | if (!i2ctabptr) |
@@ -6543,44 +6601,14 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios) | |||
6543 | */ | 6601 | */ |
6544 | if (dcb->version >= 0x22) { | 6602 | if (dcb->version >= 0x22) { |
6545 | int idx = (dcb->version >= 0x40 ? | 6603 | int idx = (dcb->version >= 0x40 ? |
6546 | dcb->i2c_default_indices & 0xf : | 6604 | dcb->i2c_default_indices & 0xf : 2); |
6547 | 2); | ||
6548 | 6605 | ||
6549 | read_dcb_i2c_entry(dev, dcb->version, dcb->i2c_table, | 6606 | read_dcb_i2c_entry(dev, dcb->version, dcb->i2c_table, |
6550 | idx, &dcb->i2c[idx]); | 6607 | idx, &dcb->i2c[idx]); |
6551 | } | 6608 | } |
6552 | } | 6609 | } |
6553 | 6610 | ||
6554 | if (entries > DCB_MAX_NUM_ENTRIES) | 6611 | dcb_outp_foreach(dev, NULL, parse_dcb_entry); |
6555 | entries = DCB_MAX_NUM_ENTRIES; | ||
6556 | |||
6557 | for (i = 0; i < entries; i++) { | ||
6558 | uint32_t connection, config = 0; | ||
6559 | |||
6560 | connection = ROM32(dcbtable[headerlen + recordlength * i]); | ||
6561 | if (configblock) | ||
6562 | config = ROM32(dcbtable[headerlen + confofs + recordlength * i]); | ||
6563 | |||
6564 | /* seen on an NV11 with DCB v1.5 */ | ||
6565 | if (connection == 0x00000000) | ||
6566 | break; | ||
6567 | |||
6568 | /* seen on an NV17 with DCB v2.0 */ | ||
6569 | if (connection == 0xffffffff) | ||
6570 | break; | ||
6571 | |||
6572 | if ((connection & 0x0000000f) == 0x0000000f) | ||
6573 | continue; | ||
6574 | |||
6575 | if (!apply_dcb_encoder_quirks(dev, i, &connection, &config)) | ||
6576 | continue; | ||
6577 | |||
6578 | NV_TRACEWARN(dev, "Raw DCB entry %d: %08x %08x\n", | ||
6579 | dcb->entries, connection, config); | ||
6580 | |||
6581 | if (!parse_dcb_entry(dev, dcb, connection, config)) | ||
6582 | break; | ||
6583 | } | ||
6584 | 6612 | ||
6585 | /* | 6613 | /* |
6586 | * apart for v2.1+ not being known for requiring merging, this | 6614 | * apart for v2.1+ not being known for requiring merging, this |
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.h b/drivers/gpu/drm/nouveau/nouveau_bios.h index 5f1258834ec1..b9f2da394f89 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.h +++ b/drivers/gpu/drm/nouveau/nouveau_bios.h | |||
@@ -117,6 +117,7 @@ enum dcb_type { | |||
117 | OUTPUT_LVDS = 3, | 117 | OUTPUT_LVDS = 3, |
118 | OUTPUT_DP = 6, | 118 | OUTPUT_DP = 6, |
119 | OUTPUT_EOL = 14, /* DCB 4.0+, appears to be end-of-list */ | 119 | OUTPUT_EOL = 14, /* DCB 4.0+, appears to be end-of-list */ |
120 | OUTPUT_UNUSED = 15, | ||
120 | OUTPUT_ANY = -1 | 121 | OUTPUT_ANY = -1 |
121 | }; | 122 | }; |
122 | 123 | ||
@@ -339,4 +340,9 @@ struct nvbios { | |||
339 | } legacy; | 340 | } legacy; |
340 | }; | 341 | }; |
341 | 342 | ||
343 | void *dcb_table(struct drm_device *); | ||
344 | u8 *dcb_outp(struct drm_device *, u8 idx); | ||
345 | int dcb_outp_foreach(struct drm_device *, void *data, | ||
346 | int (*)(struct drm_device *, void *, int idx, u8 *outp)); | ||
347 | |||
342 | #endif | 348 | #endif |
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 1e70005d8220..446caedbcff9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h | |||
@@ -1608,6 +1608,13 @@ extern void nv_wo32(struct nouveau_gpuobj *, u32 offset, u32 val); | |||
1608 | #define NV_TRACEWARN(d, fmt, arg...) NV_PRINTK(KERN_NOTICE, d, fmt, ##arg) | 1608 | #define NV_TRACEWARN(d, fmt, arg...) NV_PRINTK(KERN_NOTICE, d, fmt, ##arg) |
1609 | #define NV_TRACE(d, fmt, arg...) NV_PRINTK(KERN_INFO, d, fmt, ##arg) | 1609 | #define NV_TRACE(d, fmt, arg...) NV_PRINTK(KERN_INFO, d, fmt, ##arg) |
1610 | #define NV_WARN(d, fmt, arg...) NV_PRINTK(KERN_WARNING, d, fmt, ##arg) | 1610 | #define NV_WARN(d, fmt, arg...) NV_PRINTK(KERN_WARNING, d, fmt, ##arg) |
1611 | #define NV_WARNONCE(d, fmt, arg...) do { \ | ||
1612 | static int _warned = 0; \ | ||
1613 | if (!_warned) { \ | ||
1614 | NV_WARN(d, fmt, ##arg); \ | ||
1615 | _warned = 1; \ | ||
1616 | } \ | ||
1617 | } while(0) | ||
1611 | 1618 | ||
1612 | /* nouveau_reg_debug bitmask */ | 1619 | /* nouveau_reg_debug bitmask */ |
1613 | enum { | 1620 | enum { |