aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2011-11-10 00:42:55 -0500
committerBen Skeggs <bskeggs@redhat.com>2011-12-21 04:01:39 -0500
commit6b5a81a2e783f26a69fc262b3c393f0b391c8613 (patch)
tree2989d40f2877c108a7f96f610c420df86674317a
parent0f8067c7054d22f240fca376e01430eecdc112df (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>
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bios.c270
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bios.h6
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h7
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
6051void *
6052dcb_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
6105u8 *
6106dcb_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
6129int
6130dcb_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
6051static struct dcb_entry *new_dcb_entry(struct dcb_table *dcb) 6154static 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
6254static 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
6273static 6357static
6274void merge_like_dcb_entries(struct drm_device *dev, struct dcb_table *dcb) 6358void 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
6448static int 6532static int
6449parse_dcb_table(struct drm_device *dev, struct nvbios *bios) 6533parse_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+ */ 6561static int
6484 headerlen = dcbtable[1]; 6562parse_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
343void *dcb_table(struct drm_device *);
344u8 *dcb_outp(struct drm_device *, u8 idx);
345int 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 */
1613enum { 1620enum {