aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/nouveau/nouveau_bios.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_bios.c')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bios.c390
1 files changed, 43 insertions, 347 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c
index 09fdef23588..8268a4ccac1 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bios.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.c
@@ -28,7 +28,7 @@
#include "nouveau_drm.h"
#include "nouveau_reg.h"
-#include "nouveau_hw.h"
+#include "dispnv04/hw.h"
#include "nouveau_encoder.h"
#include <linux/io-mapping.h>
@@ -127,8 +127,8 @@ static int call_lvds_manufacturer_script(struct drm_device *dev, struct dcb_outp
#ifdef __powerpc__
/* Powerbook specific quirks */
if (script == LVDS_RESET &&
- (dev->pci_device == 0x0179 || dev->pci_device == 0x0189 ||
- dev->pci_device == 0x0329))
+ (dev->pdev->device == 0x0179 || dev->pdev->device == 0x0189 ||
+ dev->pdev->device == 0x0329))
nv_write_tmds(dev, dcbent->or, 0, 0x02, 0x72);
#endif
@@ -624,206 +624,6 @@ int nouveau_bios_parse_lvds_table(struct drm_device *dev, int pxclk, bool *dl, b
return 0;
}
-/* BIT 'U'/'d' table encoder subtables have hashes matching them to
- * a particular set of encoders.
- *
- * This function returns true if a particular DCB entry matches.
- */
-bool
-bios_encoder_match(struct dcb_output *dcb, u32 hash)
-{
- if ((hash & 0x000000f0) != (dcb->location << 4))
- return false;
- if ((hash & 0x0000000f) != dcb->type)
- return false;
- if (!(hash & (dcb->or << 16)))
- return false;
-
- switch (dcb->type) {
- case DCB_OUTPUT_TMDS:
- case DCB_OUTPUT_LVDS:
- case DCB_OUTPUT_DP:
- if (hash & 0x00c00000) {
- if (!(hash & (dcb->sorconf.link << 22)))
- return false;
- }
- default:
- return true;
- }
-}
-
-int
-nouveau_bios_run_display_table(struct drm_device *dev, u16 type, int pclk,
- struct dcb_output *dcbent, int crtc)
-{
- /*
- * The display script table is located by the BIT 'U' table.
- *
- * It contains an array of pointers to various tables describing
- * a particular output type. The first 32-bits of the output
- * tables contains similar information to a DCB entry, and is
- * used to decide whether that particular table is suitable for
- * the output you want to access.
- *
- * The "record header length" field here seems to indicate the
- * offset of the first configuration entry in the output tables.
- * This is 10 on most cards I've seen, but 12 has been witnessed
- * on DP cards, and there's another script pointer within the
- * header.
- *
- * offset + 0 ( 8 bits): version
- * offset + 1 ( 8 bits): header length
- * offset + 2 ( 8 bits): record length
- * offset + 3 ( 8 bits): number of records
- * offset + 4 ( 8 bits): record header length
- * offset + 5 (16 bits): pointer to first output script table
- */
-
- struct nouveau_drm *drm = nouveau_drm(dev);
- struct nvbios *bios = &drm->vbios;
- uint8_t *table = &bios->data[bios->display.script_table_ptr];
- uint8_t *otable = NULL;
- uint16_t script;
- int i;
-
- if (!bios->display.script_table_ptr) {
- NV_ERROR(drm, "No pointer to output script table\n");
- return 1;
- }
-
- /*
- * Nothing useful has been in any of the pre-2.0 tables I've seen,
- * so until they are, we really don't need to care.
- */
- if (table[0] < 0x20)
- return 1;
-
- if (table[0] != 0x20 && table[0] != 0x21) {
- NV_ERROR(drm, "Output script table version 0x%02x unknown\n",
- table[0]);
- return 1;
- }
-
- /*
- * The output script tables describing a particular output type
- * look as follows:
- *
- * offset + 0 (32 bits): output this table matches (hash of DCB)
- * offset + 4 ( 8 bits): unknown
- * offset + 5 ( 8 bits): number of configurations
- * offset + 6 (16 bits): pointer to some script
- * offset + 8 (16 bits): pointer to some script
- *
- * headerlen == 10
- * offset + 10 : configuration 0
- *
- * headerlen == 12
- * offset + 10 : pointer to some script
- * offset + 12 : configuration 0
- *
- * Each config entry is as follows:
- *
- * offset + 0 (16 bits): unknown, assumed to be a match value
- * offset + 2 (16 bits): pointer to script table (clock set?)
- * offset + 4 (16 bits): pointer to script table (reset?)
- *
- * There doesn't appear to be a count value to say how many
- * entries exist in each script table, instead, a 0 value in
- * the first 16-bit word seems to indicate both the end of the
- * list and the default entry. The second 16-bit word in the
- * script tables is a pointer to the script to execute.
- */
-
- NV_DEBUG(drm, "Searching for output entry for %d %d %d\n",
- dcbent->type, dcbent->location, dcbent->or);
- for (i = 0; i < table[3]; i++) {
- otable = ROMPTR(dev, table[table[1] + (i * table[2])]);
- if (otable && bios_encoder_match(dcbent, ROM32(otable[0])))
- break;
- }
-
- if (!otable) {
- NV_DEBUG(drm, "failed to match any output table\n");
- return 1;
- }
-
- if (pclk < -2 || pclk > 0) {
- /* Try to find matching script table entry */
- for (i = 0; i < otable[5]; i++) {
- if (ROM16(otable[table[4] + i*6]) == type)
- break;
- }
-
- if (i == otable[5]) {
- NV_ERROR(drm, "Table 0x%04x not found for %d/%d, "
- "using first\n",
- type, dcbent->type, dcbent->or);
- i = 0;
- }
- }
-
- if (pclk == 0) {
- script = ROM16(otable[6]);
- if (!script) {
- NV_DEBUG(drm, "output script 0 not found\n");
- return 1;
- }
-
- NV_DEBUG(drm, "0x%04X: parsing output script 0\n", script);
- nouveau_bios_run_init_table(dev, script, dcbent, crtc);
- } else
- if (pclk == -1) {
- script = ROM16(otable[8]);
- if (!script) {
- NV_DEBUG(drm, "output script 1 not found\n");
- return 1;
- }
-
- NV_DEBUG(drm, "0x%04X: parsing output script 1\n", script);
- nouveau_bios_run_init_table(dev, script, dcbent, crtc);
- } else
- if (pclk == -2) {
- if (table[4] >= 12)
- script = ROM16(otable[10]);
- else
- script = 0;
- if (!script) {
- NV_DEBUG(drm, "output script 2 not found\n");
- return 1;
- }
-
- NV_DEBUG(drm, "0x%04X: parsing output script 2\n", script);
- nouveau_bios_run_init_table(dev, script, dcbent, crtc);
- } else
- if (pclk > 0) {
- script = ROM16(otable[table[4] + i*6 + 2]);
- if (script)
- script = clkcmptable(bios, script, pclk);
- if (!script) {
- NV_DEBUG(drm, "clock script 0 not found\n");
- return 1;
- }
-
- NV_DEBUG(drm, "0x%04X: parsing clock script 0\n", script);
- nouveau_bios_run_init_table(dev, script, dcbent, crtc);
- } else
- if (pclk < 0) {
- script = ROM16(otable[table[4] + i*6 + 4]);
- if (script)
- script = clkcmptable(bios, script, -pclk);
- if (!script) {
- NV_DEBUG(drm, "clock script 1 not found\n");
- return 1;
- }
-
- NV_DEBUG(drm, "0x%04X: parsing clock script 1\n", script);
- nouveau_bios_run_init_table(dev, script, dcbent, crtc);
- }
-
- return 0;
-}
-
-
int run_tmds_table(struct drm_device *dev, struct dcb_output *dcbent, int head, int pxclk)
{
/*
@@ -878,23 +678,6 @@ int run_tmds_table(struct drm_device *dev, struct dcb_output *dcbent, int head,
return 0;
}
-static void parse_bios_version(struct drm_device *dev, struct nvbios *bios, uint16_t offset)
-{
- /*
- * offset + 0 (8 bits): Micro version
- * offset + 1 (8 bits): Minor version
- * offset + 2 (8 bits): Chip version
- * offset + 3 (8 bits): Major version
- */
- struct nouveau_drm *drm = nouveau_drm(dev);
-
- bios->major_version = bios->data[offset + 3];
- bios->chip_version = bios->data[offset + 2];
- NV_INFO(drm, "Bios version %02x.%02x.%02x.%02x\n",
- bios->data[offset + 3], bios->data[offset + 2],
- bios->data[offset + 1], bios->data[offset]);
-}
-
static void parse_script_table_pointers(struct nvbios *bios, uint16_t offset)
{
/*
@@ -910,12 +693,6 @@ static void parse_script_table_pointers(struct nvbios *bios, uint16_t offset)
*/
bios->init_script_tbls_ptr = ROM16(bios->data[offset]);
- bios->macro_index_tbl_ptr = ROM16(bios->data[offset + 2]);
- bios->macro_tbl_ptr = ROM16(bios->data[offset + 4]);
- bios->condition_tbl_ptr = ROM16(bios->data[offset + 6]);
- bios->io_condition_tbl_ptr = ROM16(bios->data[offset + 8]);
- bios->io_flag_condition_tbl_ptr = ROM16(bios->data[offset + 10]);
- bios->init_function_tbl_ptr = ROM16(bios->data[offset + 12]);
}
static int parse_bit_A_tbl_entry(struct drm_device *dev, struct nvbios *bios, struct bit_entry *bitentry)
@@ -965,25 +742,6 @@ static int parse_bit_A_tbl_entry(struct drm_device *dev, struct nvbios *bios, st
return 0;
}
-static int parse_bit_C_tbl_entry(struct drm_device *dev, struct nvbios *bios, struct bit_entry *bitentry)
-{
- /*
- * offset + 8 (16 bits): PLL limits table pointer
- *
- * There's more in here, but that's unknown.
- */
- struct nouveau_drm *drm = nouveau_drm(dev);
-
- if (bitentry->length < 10) {
- NV_ERROR(drm, "Do not understand BIT C table\n");
- return -EINVAL;
- }
-
- bios->pll_limit_tbl_ptr = ROM16(bios->data[bitentry->offset + 8]);
-
- return 0;
-}
-
static int parse_bit_display_tbl_entry(struct drm_device *dev, struct nvbios *bios, struct bit_entry *bitentry)
{
/*
@@ -1021,12 +779,6 @@ static int parse_bit_init_tbl_entry(struct drm_device *dev, struct nvbios *bios,
}
parse_script_table_pointers(bios, bitentry->offset);
-
- if (bitentry->length >= 16)
- bios->some_script_ptr = ROM16(bios->data[bitentry->offset + 14]);
- if (bitentry->length >= 18)
- bios->init96_tbl_ptr = ROM16(bios->data[bitentry->offset + 16]);
-
return 0;
}
@@ -1052,8 +804,6 @@ static int parse_bit_i_tbl_entry(struct drm_device *dev, struct nvbios *bios, st
return -EINVAL;
}
- parse_bios_version(dev, bios, bitentry->offset);
-
/*
* bit 4 seems to indicate a mobile bios (doesn't suffer from BMP's
* Quadro identity crisis), other bits possibly as for BMP feature byte
@@ -1212,31 +962,6 @@ static int parse_bit_tmds_tbl_entry(struct drm_device *dev, struct nvbios *bios,
return 0;
}
-static int
-parse_bit_U_tbl_entry(struct drm_device *dev, struct nvbios *bios,
- struct bit_entry *bitentry)
-{
- /*
- * Parses the pointer to the G80 output script tables
- *
- * Starting at bitentry->offset:
- *
- * offset + 0 (16 bits): output script table pointer
- */
-
- struct nouveau_drm *drm = nouveau_drm(dev);
- uint16_t outputscripttableptr;
-
- if (bitentry->length != 3) {
- NV_ERROR(drm, "Do not understand BIT U table\n");
- return -EINVAL;
- }
-
- outputscripttableptr = ROM16(bios->data[bitentry->offset]);
- bios->display.script_table_ptr = outputscripttableptr;
- return 0;
-}
-
struct bit_table {
const char id;
int (* const parse_fn)(struct drm_device *, struct nvbios *, struct bit_entry *);
@@ -1303,9 +1028,6 @@ parse_bit_structure(struct nvbios *bios, const uint16_t bitoffset)
return ret;
if (bios->major_version >= 0x60) /* g80+ */
parse_bit_table(bios, bitoffset, &BIT_TABLE('A', A));
- ret = parse_bit_table(bios, bitoffset, &BIT_TABLE('C', C));
- if (ret)
- return ret;
parse_bit_table(bios, bitoffset, &BIT_TABLE('D', display));
ret = parse_bit_table(bios, bitoffset, &BIT_TABLE('I', init));
if (ret)
@@ -1313,7 +1035,6 @@ parse_bit_structure(struct nvbios *bios, const uint16_t bitoffset)
parse_bit_table(bios, bitoffset, &BIT_TABLE('M', M)); /* memory? */
parse_bit_table(bios, bitoffset, &BIT_TABLE('L', lvds));
parse_bit_table(bios, bitoffset, &BIT_TABLE('T', tmds));
- parse_bit_table(bios, bitoffset, &BIT_TABLE('U', U));
return 0;
}
@@ -1454,8 +1175,6 @@ static int parse_bmp_structure(struct drm_device *dev, struct nvbios *bios, unsi
*/
bios->feature_byte = bmp[9];
- parse_bios_version(dev, bios, offset + 10);
-
if (bmp_version_major < 5 || bmp_version_minor < 0x10)
bios->old_style_init = true;
legacy_scripts_offset = 18;
@@ -1502,8 +1221,10 @@ static int parse_bmp_structure(struct drm_device *dev, struct nvbios *bios, unsi
bios->fp.lvdsmanufacturerpointer = ROM16(bmp[117]);
bios->fp.fpxlatemanufacturertableptr = ROM16(bmp[119]);
}
+#if 0
if (bmplength > 143)
bios->pll_limit_tbl_ptr = ROM16(bmp[142]);
+#endif
if (bmplength > 157)
bios->fp.duallink_transition_clk = ROM16(bmp[156]) * 10;
@@ -1748,13 +1469,17 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb,
}
case DCB_OUTPUT_DP:
entry->dpconf.sor.link = (conf & 0x00000030) >> 4;
+ entry->extdev = (conf & 0x0000ff00) >> 8;
switch ((conf & 0x00e00000) >> 21) {
case 0:
entry->dpconf.link_bw = 162000;
break;
- default:
+ case 1:
entry->dpconf.link_bw = 270000;
break;
+ default:
+ entry->dpconf.link_bw = 540000;
+ break;
}
switch ((conf & 0x0f000000) >> 24) {
case 0xf:
@@ -1769,8 +1494,10 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb,
}
break;
case DCB_OUTPUT_TMDS:
- if (dcb->version >= 0x40)
+ if (dcb->version >= 0x40) {
entry->tmdsconf.sor.link = (conf & 0x00000030) >> 4;
+ entry->extdev = (conf & 0x0000ff00) >> 8;
+ }
else if (dcb->version >= 0x30)
entry->tmdsconf.slave_addr = (conf & 0x00000700) >> 8;
else if (dcb->version >= 0x22)
@@ -2154,18 +1881,15 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios)
if (dcb->version < 0x21)
merge_like_dcb_entries(dev, dcb);
- if (!dcb->entries)
- return -ENXIO;
-
/* dump connector table entries to log, if any exist */
idx = -1;
while ((conn = olddcb_conn(dev, ++idx))) {
if (conn[0] != 0xff) {
NV_INFO(drm, "DCB conn %02d: ", idx);
if (olddcb_conntab(dev)[3] < 4)
- printk("%04x\n", ROM16(conn[0]));
+ pr_cont("%04x\n", ROM16(conn[0]));
else
- printk("%08x\n", ROM32(conn[0]));
+ pr_cont("%08x\n", ROM32(conn[0]));
}
}
dcb_fake_connectors(bios);
@@ -2278,45 +2002,29 @@ uint8_t *nouveau_bios_embedded_edid(struct drm_device *dev)
static bool NVInitVBIOS(struct drm_device *dev)
{
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nvbios *bios = &drm->vbios;
-
- memset(bios, 0, sizeof(struct nvbios));
- spin_lock_init(&bios->lock);
- bios->dev = dev;
-
- bios->data = nouveau_bios(drm->device)->data;
- bios->length = nouveau_bios(drm->device)->size;
- return true;
-}
+ struct nouveau_bios *bios = nouveau_bios(drm->device);
+ struct nvbios *legacy = &drm->vbios;
+
+ memset(legacy, 0, sizeof(struct nvbios));
+ spin_lock_init(&legacy->lock);
+ legacy->dev = dev;
+
+ legacy->data = bios->data;
+ legacy->length = bios->size;
+ legacy->major_version = bios->version.major;
+ legacy->chip_version = bios->version.chip;
+ if (bios->bit_offset) {
+ legacy->type = NVBIOS_BIT;
+ legacy->offset = bios->bit_offset;
+ return !parse_bit_structure(legacy, legacy->offset + 6);
+ } else
+ if (bios->bmp_offset) {
+ legacy->type = NVBIOS_BMP;
+ legacy->offset = bios->bmp_offset;
+ return !parse_bmp_structure(dev, legacy, legacy->offset);
+ }
-static int nouveau_parse_vbios_struct(struct drm_device *dev)
-{
- struct nouveau_drm *drm = nouveau_drm(dev);
- struct nvbios *bios = &drm->vbios;
- const uint8_t bit_signature[] = { 0xff, 0xb8, 'B', 'I', 'T' };
- const uint8_t bmp_signature[] = { 0xff, 0x7f, 'N', 'V', 0x0 };
- int offset;
-
- offset = findstr(bios->data, bios->length,
- bit_signature, sizeof(bit_signature));
- if (offset) {
- NV_INFO(drm, "BIT BIOS found\n");
- bios->type = NVBIOS_BIT;
- bios->offset = offset;
- return parse_bit_structure(bios, offset + 6);
- }
-
- offset = findstr(bios->data, bios->length,
- bmp_signature, sizeof(bmp_signature));
- if (offset) {
- NV_INFO(drm, "BMP BIOS found\n");
- bios->type = NVBIOS_BMP;
- bios->offset = offset;
- return parse_bmp_structure(dev, bios, offset);
- }
-
- NV_ERROR(drm, "No known BIOS signature found\n");
- return -ENODEV;
+ return false;
}
int
@@ -2324,7 +2032,7 @@ nouveau_run_vbios_init(struct drm_device *dev)
{
struct nouveau_drm *drm = nouveau_drm(dev);
struct nvbios *bios = &drm->vbios;
- int i, ret = 0;
+ int ret = 0;
/* Reset the BIOS head to 0. */
bios->state.crtchead = 0;
@@ -2337,13 +2045,6 @@ nouveau_run_vbios_init(struct drm_device *dev)
bios->fp.lvds_init_run = false;
}
- if (nv_device(drm->device)->card_type >= NV_50) {
- for (i = 0; bios->execute && i < bios->dcb.entries; i++) {
- nouveau_bios_run_display_table(dev, 0, 0,
- &bios->dcb.entry[i], -1);
- }
- }
-
return ret;
}
@@ -2353,19 +2054,14 @@ nouveau_bios_posted(struct drm_device *dev)
struct nouveau_drm *drm = nouveau_drm(dev);
unsigned htotal;
- if (nv_device(drm->device)->card_type >= NV_50) {
- if (NVReadVgaCrtc(dev, 0, 0x00) == 0 &&
- NVReadVgaCrtc(dev, 0, 0x1a) == 0)
- return false;
+ if (nv_device(drm->device)->card_type >= NV_50)
return true;
- }
htotal = NVReadVgaCrtc(dev, 0, 0x06);
htotal |= (NVReadVgaCrtc(dev, 0, 0x07) & 0x01) << 8;
htotal |= (NVReadVgaCrtc(dev, 0, 0x07) & 0x20) << 4;
htotal |= (NVReadVgaCrtc(dev, 0, 0x25) & 0x01) << 10;
htotal |= (NVReadVgaCrtc(dev, 0, 0x41) & 0x01) << 11;
-
return (htotal != 0);
}
@@ -2376,13 +2072,13 @@ nouveau_bios_init(struct drm_device *dev)
struct nvbios *bios = &drm->vbios;
int ret;
+ /* only relevant for PCI devices */
+ if (!dev->pdev)
+ return 0;
+
if (!NVInitVBIOS(dev))
return -ENODEV;
- ret = nouveau_parse_vbios_struct(dev);
- if (ret)
- return ret;
-
ret = parse_dcb_table(dev, bios);
if (ret)
return ret;