Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 282643
b: refs/heads/master
c: befb51e
h: refs/heads/master
i:
  282641: 26abd4a
  282639: e3bdd69
v: v3
  • Loading branch information
Ben Skeggs committed Dec 21, 2011
1 parent 7aabc94 commit a44e8f0
Show file tree
Hide file tree
Showing 8 changed files with 241 additions and 329 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: f553b79c03f0dbd52f6f03abe8233a2bef8cbd0d
refs/heads/master: befb51e9c97e783c86a1da27bdda3a638d2f02c7
315 changes: 90 additions & 225 deletions trunk/drivers/gpu/drm/nouveau/nouveau_bios.c
Original file line number Diff line number Diff line change
Expand Up @@ -1100,13 +1100,9 @@ init_dp_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)

switch (cond) {
case 0:
{
struct dcb_connector_table_entry *ent =
&bios->dcb.connector.entry[dcb->connector];

if (ent->type != DCB_CONNECTOR_eDP)
entry = dcb_conn(dev, dcb->connector);
if (!entry || entry[0] != DCB_CONNECTOR_eDP)
iexec->execute = false;
}
break;
case 1:
case 2:
Expand Down Expand Up @@ -5782,164 +5778,6 @@ parse_dcb_gpio_table(struct nvbios *bios)
}
}

struct dcb_connector_table_entry *
nouveau_bios_connector_entry(struct drm_device *dev, int index)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nvbios *bios = &dev_priv->vbios;
struct dcb_connector_table_entry *cte;

if (index >= bios->dcb.connector.entries)
return NULL;

cte = &bios->dcb.connector.entry[index];
if (cte->type == 0xff)
return NULL;

return cte;
}

static enum dcb_connector_type
divine_connector_type(struct nvbios *bios, int index)
{
struct dcb_table *dcb = &bios->dcb;
unsigned encoders = 0, type = DCB_CONNECTOR_NONE;
int i;

for (i = 0; i < dcb->entries; i++) {
if (dcb->entry[i].connector == index)
encoders |= (1 << dcb->entry[i].type);
}

if (encoders & (1 << OUTPUT_DP)) {
if (encoders & (1 << OUTPUT_TMDS))
type = DCB_CONNECTOR_DP;
else
type = DCB_CONNECTOR_eDP;
} else
if (encoders & (1 << OUTPUT_TMDS)) {
if (encoders & (1 << OUTPUT_ANALOG))
type = DCB_CONNECTOR_DVI_I;
else
type = DCB_CONNECTOR_DVI_D;
} else
if (encoders & (1 << OUTPUT_ANALOG)) {
type = DCB_CONNECTOR_VGA;
} else
if (encoders & (1 << OUTPUT_LVDS)) {
type = DCB_CONNECTOR_LVDS;
} else
if (encoders & (1 << OUTPUT_TV)) {
type = DCB_CONNECTOR_TV_0;
}

return type;
}

static void
apply_dcb_connector_quirks(struct nvbios *bios, int idx)
{
struct dcb_connector_table_entry *cte = &bios->dcb.connector.entry[idx];
struct drm_device *dev = bios->dev;

/* Gigabyte NX85T */
if (nv_match_device(dev, 0x0421, 0x1458, 0x344c)) {
if (cte->type == DCB_CONNECTOR_HDMI_1)
cte->type = DCB_CONNECTOR_DVI_I;
}

/* Gigabyte GV-NX86T512H */
if (nv_match_device(dev, 0x0402, 0x1458, 0x3455)) {
if (cte->type == DCB_CONNECTOR_HDMI_1)
cte->type = DCB_CONNECTOR_DVI_I;
}
}

static const u8 hpd_gpio[16] = {
0xff, 0x07, 0x08, 0xff, 0xff, 0x51, 0x52, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0x5e, 0x5f, 0x60,
};

static void
parse_dcb_connector_table(struct nvbios *bios)
{
struct drm_device *dev = bios->dev;
struct dcb_connector_table *ct = &bios->dcb.connector;
struct dcb_connector_table_entry *cte;
uint8_t *conntab = &bios->data[bios->dcb.connector_table_ptr];
uint8_t *entry;
int i;

if (!bios->dcb.connector_table_ptr) {
NV_DEBUG_KMS(dev, "No DCB connector table present\n");
return;
}

NV_INFO(dev, "DCB connector table: VHER 0x%02x %d %d %d\n",
conntab[0], conntab[1], conntab[2], conntab[3]);
if ((conntab[0] != 0x30 && conntab[0] != 0x40) ||
(conntab[3] != 2 && conntab[3] != 4)) {
NV_ERROR(dev, " Unknown! Please report.\n");
return;
}

ct->entries = conntab[2];

entry = conntab + conntab[1];
cte = &ct->entry[0];
for (i = 0; i < conntab[2]; i++, entry += conntab[3], cte++) {
cte->index = i;
if (conntab[3] == 2)
cte->entry = ROM16(entry[0]);
else
cte->entry = ROM32(entry[0]);

cte->type = (cte->entry & 0x000000ff) >> 0;
cte->index2 = (cte->entry & 0x00000f00) >> 8;

cte->gpio_tag = ffs((cte->entry & 0x07033000) >> 12);
cte->gpio_tag = hpd_gpio[cte->gpio_tag];

if (cte->type == 0xff)
continue;

apply_dcb_connector_quirks(bios, i);

NV_INFO(dev, " %d: 0x%08x: type 0x%02x idx %d tag 0x%02x\n",
i, cte->entry, cte->type, cte->index, cte->gpio_tag);

/* check for known types, fallback to guessing the type
* from attached encoders if we hit an unknown.
*/
switch (cte->type) {
case DCB_CONNECTOR_VGA:
case DCB_CONNECTOR_TV_0:
case DCB_CONNECTOR_TV_1:
case DCB_CONNECTOR_TV_3:
case DCB_CONNECTOR_DVI_I:
case DCB_CONNECTOR_DVI_D:
case DCB_CONNECTOR_LVDS:
case DCB_CONNECTOR_LVDS_SPWG:
case DCB_CONNECTOR_DP:
case DCB_CONNECTOR_eDP:
case DCB_CONNECTOR_HDMI_0:
case DCB_CONNECTOR_HDMI_1:
break;
default:
cte->type = divine_connector_type(bios, cte->index);
NV_WARN(dev, "unknown type, using 0x%02x\n", cte->type);
break;
}

if (nouveau_override_conntype) {
int type = divine_connector_type(bios, cte->index);
if (type != cte->type)
NV_WARN(dev, " -> type 0x%02x\n", cte->type);
}

}
}

void *
dcb_table(struct drm_device *dev)
{
Expand Down Expand Up @@ -6043,6 +5881,27 @@ dcb_outp_foreach(struct drm_device *dev, void *data,
return 0;
}

u8 *
dcb_conntab(struct drm_device *dev)
{
u8 *dcb = dcb_table(dev);
if (dcb && dcb[0] >= 0x30 && dcb[1] >= 0x16) {
u8 *conntab = ROMPTR(dev, dcb[0x14]);
if (conntab && conntab[0] >= 0x30 && conntab[0] <= 0x40)
return conntab;
}
return NULL;
}

u8 *
dcb_conn(struct drm_device *dev, u8 idx)
{
u8 *conntab = dcb_conntab(dev);
if (conntab && idx < conntab[2])
return conntab + conntab[1] + (idx * conntab[3]);
return NULL;
}

static struct dcb_entry *new_dcb_entry(struct dcb_table *dcb)
{
struct dcb_entry *entry = &dcb->entry[dcb->entries];
Expand Down Expand Up @@ -6073,8 +5932,7 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb,
entry->type = conn & 0xf;
entry->i2c_index = (conn >> 4) & 0xf;
entry->heads = (conn >> 8) & 0xf;
if (dcb->version >= 0x40)
entry->connector = (conn >> 12) & 0xf;
entry->connector = (conn >> 12) & 0xf;
entry->bus = (conn >> 16) & 0xf;
entry->location = (conn >> 20) & 0x3;
entry->or = (conn >> 24) & 0xf;
Expand Down Expand Up @@ -6433,24 +6291,75 @@ parse_dcb_entry(struct drm_device *dev, void *data, int idx, u8 *outp)
if (apply_dcb_encoder_quirks(dev, idx, &conn, &conf)) {
struct dcb_entry *entry = new_dcb_entry(dcb);

NV_TRACEWARN(dev, "DCB entry %02d: %08x %08x\n", idx, conn, conf);
NV_TRACEWARN(dev, "DCB outp %02d: %08x %08x\n", idx, conn, conf);

if (dcb->version >= 0x20)
ret = parse_dcb20_entry(dev, dcb, conn, conf, entry);
else
ret = parse_dcb15_entry(dev, dcb, conn, conf, entry);
if (!ret)
return 1; /* stop parsing */

/* Ignore the I2C index for on-chip TV-out, as there
* are cards with bogus values (nv31m in bug 23212),
* and it's otherwise useless.
*/
if (entry->type == OUTPUT_TV &&
entry->location == DCB_LOC_ON_CHIP)
entry->i2c_index = 0x0f;
}

return 0;
}

static void
dcb_fake_connectors(struct nvbios *bios)
{
struct dcb_table *dcbt = &bios->dcb;
u8 map[16] = { };
int i, idx = 0;

/* heuristic: if we ever get a non-zero connector field, assume
* that all the indices are valid and we don't need fake them.
*/
for (i = 0; i < dcbt->entries; i++) {
if (dcbt->entry[i].connector)
return;
}

/* no useful connector info available, we need to make it up
* ourselves. the rule here is: anything on the same i2c bus
* is considered to be on the same connector. any output
* without an associated i2c bus is assigned its own unique
* connector index.
*/
for (i = 0; i < dcbt->entries; i++) {
u8 i2c = dcbt->entry[i].i2c_index;
if (i2c == 0x0f) {
dcbt->entry[i].connector = idx++;
} else {
if (!map[i2c])
map[i2c] = ++idx;
dcbt->entry[i].connector = map[i2c] - 1;
}
}

/* if we created more than one connector, destroy the connector
* table - just in case it has random, rather than stub, entries.
*/
if (i > 1) {
u8 *conntab = dcb_conntab(bios->dev);
if (conntab)
conntab[0] = 0x00;
}
}

static int
parse_dcb_table(struct drm_device *dev, struct nvbios *bios)
{
struct dcb_table *dcb = &bios->dcb;
u8 *dcbt;
u8 *dcbt, *conn;
int idx;

dcbt = dcb_table(dev);
if (!dcbt) {
Expand All @@ -6466,10 +6375,8 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios)
NV_TRACE(dev, "DCB version %d.%d\n", dcbt[0] >> 4, dcbt[0] & 0xf);

dcb->version = dcbt[0];
if (dcb->version >= 0x30) {
if (dcb->version >= 0x30)
dcb->gpio_table_ptr = ROM16(dcbt[10]);
dcb->connector_table_ptr = ROM16(dcbt[20]);
}

dcb_outp_foreach(dev, NULL, parse_dcb_entry);

Expand All @@ -6483,61 +6390,21 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios)
if (!dcb->entries)
return -ENXIO;

parse_dcb_gpio_table(bios);
parse_dcb_connector_table(bios);
return 0;
}

static void
fixup_legacy_connector(struct nvbios *bios)
{
struct dcb_table *dcb = &bios->dcb;
int i, i2c, i2c_conn[DCB_MAX_NUM_I2C_ENTRIES] = { };

/*
* DCB 3.0 also has the table in most cases, but there are some cards
* where the table is filled with stub entries, and the DCB entriy
* indices are all 0. We don't need the connector indices on pre-G80
* chips (yet?) so limit the use to DCB 4.0 and above.
*/
if (dcb->version >= 0x40)
return;

dcb->connector.entries = 0;

/*
* No known connector info before v3.0, so make it up. the rule here
* is: anything on the same i2c bus is considered to be on the same
* connector. any output without an associated i2c bus is assigned
* its own unique connector index.
*/
for (i = 0; i < dcb->entries; i++) {
/*
* Ignore the I2C index for on-chip TV-out, as there
* are cards with bogus values (nv31m in bug 23212),
* and it's otherwise useless.
*/
if (dcb->entry[i].type == OUTPUT_TV &&
dcb->entry[i].location == DCB_LOC_ON_CHIP)
dcb->entry[i].i2c_index = 0xf;
i2c = dcb->entry[i].i2c_index;

if (i2c_conn[i2c]) {
dcb->entry[i].connector = i2c_conn[i2c] - 1;
continue;
/* dump connector table entries to log, if any exist */
idx = -1;
while ((conn = dcb_conn(dev, ++idx))) {
if (conn[0] != 0xff) {
NV_TRACE(dev, "DCB conn %02d: ", idx);
if (dcb_conntab(dev)[3] < 4)
printk("%04x\n", ROM16(conn[0]));
else
printk("%08x\n", ROM32(conn[0]));
}

dcb->entry[i].connector = dcb->connector.entries++;
if (i2c != 0xf)
i2c_conn[i2c] = dcb->connector.entries;
}
dcb_fake_connectors(bios);

/* Fake the connector table as well as just connector indices */
for (i = 0; i < dcb->connector.entries; i++) {
dcb->connector.entry[i].index = i;
dcb->connector.entry[i].type = divine_connector_type(bios, i);
dcb->connector.entry[i].gpio_tag = 0xff;
}
parse_dcb_gpio_table(bios);
return 0;
}

static int load_nv17_hwsq_ucode_entry(struct drm_device *dev, struct nvbios *bios, uint16_t hwsq_offset, int entry)
Expand Down Expand Up @@ -6800,8 +6667,6 @@ nouveau_bios_init(struct drm_device *dev)
if (ret)
return ret;

fixup_legacy_connector(bios);

if (!bios->major_version) /* we don't run version 0 bios */
return 0;

Expand Down
Loading

0 comments on commit a44e8f0

Please sign in to comment.