diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_bios.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_bios.c | 1390 |
1 files changed, 890 insertions, 500 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 8dbeeea..729d5fd 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -27,7 +27,6 @@ #include "nouveau_drv.h" #include "nouveau_hw.h" #include "nouveau_encoder.h" -#include "nouveau_gpio.h" #include <linux/io-mapping.h> @@ -35,6 +34,9 @@ #define NV_CIO_CRE_44_HEADA 0x0 #define NV_CIO_CRE_44_HEADB 0x3 #define FEATURE_MOBILE 0x10 /* also FEATURE_QUADRO for BMP */ +#define LEGACY_I2C_CRT 0x80 +#define LEGACY_I2C_PANEL 0x81 +#define LEGACY_I2C_TV 0x82 #define EDID1_LEN 128 @@ -65,232 +67,194 @@ static bool nv_cksum(const uint8_t *data, unsigned int length) } static int -score_vbios(struct nvbios *bios, const bool writeable) +score_vbios(struct drm_device *dev, const uint8_t *data, const bool writeable) { - if (!bios->data || bios->data[0] != 0x55 || bios->data[1] != 0xAA) { - NV_TRACEWARN(bios->dev, "... BIOS signature not found\n"); + if (!(data[0] == 0x55 && data[1] == 0xAA)) { + NV_TRACEWARN(dev, "... BIOS signature not found\n"); return 0; } - if (nv_cksum(bios->data, bios->data[2] * 512)) { - NV_TRACEWARN(bios->dev, "... BIOS checksum invalid\n"); + if (nv_cksum(data, data[2] * 512)) { + NV_TRACEWARN(dev, "... BIOS checksum invalid\n"); /* if a ro image is somewhat bad, it's probably all rubbish */ return writeable ? 2 : 1; - } + } else + NV_TRACE(dev, "... appears to be valid\n"); - NV_TRACE(bios->dev, "... appears to be valid\n"); return 3; } -static void -bios_shadow_prom(struct nvbios *bios) +static void load_vbios_prom(struct drm_device *dev, uint8_t *data) { - struct drm_device *dev = bios->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; - u32 pcireg, access; - u16 pcir; + uint32_t pci_nv_20, save_pci_nv_20; + int pcir_ptr; int i; - /* enable access to rom */ if (dev_priv->card_type >= NV_50) - pcireg = 0x088050; + pci_nv_20 = 0x88050; else - pcireg = NV_PBUS_PCI_NV_20; - access = nv_mask(dev, pcireg, 0x00000001, 0x00000000); + pci_nv_20 = NV_PBUS_PCI_NV_20; - /* bail if no rom signature, with a workaround for a PROM reading - * issue on some chipsets. the first read after a period of - * inactivity returns the wrong result, so retry the first header - * byte a few times before giving up as a workaround - */ - i = 16; - do { - if (nv_rd08(dev, NV_PROM_OFFSET + 0) == 0x55) - break; - } while (i--); + /* enable ROM access */ + save_pci_nv_20 = nvReadMC(dev, pci_nv_20); + nvWriteMC(dev, pci_nv_20, + save_pci_nv_20 & ~NV_PBUS_PCI_NV_20_ROM_SHADOW_ENABLED); - if (!i || nv_rd08(dev, NV_PROM_OFFSET + 1) != 0xaa) + /* bail if no rom signature */ + if (nv_rd08(dev, NV_PROM_OFFSET) != 0x55 || + nv_rd08(dev, NV_PROM_OFFSET + 1) != 0xaa) goto out; /* additional check (see note below) - read PCI record header */ - pcir = nv_rd08(dev, NV_PROM_OFFSET + 0x18) | - nv_rd08(dev, NV_PROM_OFFSET + 0x19) << 8; - if (nv_rd08(dev, NV_PROM_OFFSET + pcir + 0) != 'P' || - nv_rd08(dev, NV_PROM_OFFSET + pcir + 1) != 'C' || - nv_rd08(dev, NV_PROM_OFFSET + pcir + 2) != 'I' || - nv_rd08(dev, NV_PROM_OFFSET + pcir + 3) != 'R') + pcir_ptr = nv_rd08(dev, NV_PROM_OFFSET + 0x18) | + nv_rd08(dev, NV_PROM_OFFSET + 0x19) << 8; + if (nv_rd08(dev, NV_PROM_OFFSET + pcir_ptr) != 'P' || + nv_rd08(dev, NV_PROM_OFFSET + pcir_ptr + 1) != 'C' || + nv_rd08(dev, NV_PROM_OFFSET + pcir_ptr + 2) != 'I' || + nv_rd08(dev, NV_PROM_OFFSET + pcir_ptr + 3) != 'R') goto out; - /* read entire bios image to system memory */ - bios->length = nv_rd08(dev, NV_PROM_OFFSET + 2) * 512; - bios->data = kmalloc(bios->length, GFP_KERNEL); - if (bios->data) { - for (i = 0; i < bios->length; i++) - bios->data[i] = nv_rd08(dev, NV_PROM_OFFSET + i); - } + /* on some 6600GT/6800LE prom reads are messed up. nvclock alleges a + * a good read may be obtained by waiting or re-reading (cargocult: 5x) + * each byte. we'll hope pramin has something usable instead + */ + for (i = 0; i < NV_PROM_SIZE; i++) + data[i] = nv_rd08(dev, NV_PROM_OFFSET + i); out: - /* disable access to rom */ - nv_wr32(dev, pcireg, access); + /* disable ROM access */ + nvWriteMC(dev, pci_nv_20, + save_pci_nv_20 | NV_PBUS_PCI_NV_20_ROM_SHADOW_ENABLED); } -static void -bios_shadow_pramin(struct nvbios *bios) +static void load_vbios_pramin(struct drm_device *dev, uint8_t *data) { - struct drm_device *dev = bios->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; - u32 bar0 = 0; + uint32_t old_bar0_pramin = 0; int i; if (dev_priv->card_type >= NV_50) { - u64 addr = (u64)(nv_rd32(dev, 0x619f04) & 0xffffff00) << 8; - if (!addr) { - addr = (u64)nv_rd32(dev, 0x001700) << 16; - addr += 0xf0000; - } + uint32_t vbios_vram = (nv_rd32(dev, 0x619f04) & ~0xff) << 8; + + if (!vbios_vram) + vbios_vram = (nv_rd32(dev, 0x1700) << 16) + 0xf0000; - bar0 = nv_mask(dev, 0x001700, 0xffffffff, addr >> 16); + old_bar0_pramin = nv_rd32(dev, 0x1700); + nv_wr32(dev, 0x1700, vbios_vram >> 16); } /* bail if no rom signature */ - if (nv_rd08(dev, NV_PRAMIN_OFFSET + 0) != 0x55 || + if (nv_rd08(dev, NV_PRAMIN_OFFSET) != 0x55 || nv_rd08(dev, NV_PRAMIN_OFFSET + 1) != 0xaa) goto out; - bios->length = nv_rd08(dev, NV_PRAMIN_OFFSET + 2) * 512; - bios->data = kmalloc(bios->length, GFP_KERNEL); - if (bios->data) { - for (i = 0; i < bios->length; i++) - bios->data[i] = nv_rd08(dev, NV_PRAMIN_OFFSET + i); - } + for (i = 0; i < NV_PROM_SIZE; i++) + data[i] = nv_rd08(dev, NV_PRAMIN_OFFSET + i); out: if (dev_priv->card_type >= NV_50) - nv_wr32(dev, 0x001700, bar0); + nv_wr32(dev, 0x1700, old_bar0_pramin); } -static void -bios_shadow_pci(struct nvbios *bios) -{ - struct pci_dev *pdev = bios->dev->pdev; - size_t length; - - if (!pci_enable_rom(pdev)) { - void __iomem *rom = pci_map_rom(pdev, &length); - if (rom) { - bios->data = kmalloc(length, GFP_KERNEL); - if (bios->data) { - memcpy_fromio(bios->data, rom, length); - bios->length = length; - } - pci_unmap_rom(pdev, rom); - } - - pci_disable_rom(pdev); - } -} - -static void -bios_shadow_acpi(struct nvbios *bios) +static void load_vbios_pci(struct drm_device *dev, uint8_t *data) { - struct pci_dev *pdev = bios->dev->pdev; - int ptr, len, ret; - u8 data[3]; + void __iomem *rom = NULL; + size_t rom_len; + int ret; - if (!nouveau_acpi_rom_supported(pdev)) + ret = pci_enable_rom(dev->pdev); + if (ret) return; - ret = nouveau_acpi_get_bios_chunk(data, 0, sizeof(data)); - if (ret != sizeof(data)) - return; + rom = pci_map_rom(dev->pdev, &rom_len); + if (!rom) + goto out; + memcpy_fromio(data, rom, rom_len); + pci_unmap_rom(dev->pdev, rom); - bios->length = min(data[2] * 512, 65536); - bios->data = kmalloc(bios->length, GFP_KERNEL); - if (!bios->data) - return; +out: + pci_disable_rom(dev->pdev); +} - len = bios->length; - ptr = 0; - while (len) { - int size = (len > ROM_BIOS_PAGE) ? ROM_BIOS_PAGE : len; +static void load_vbios_acpi(struct drm_device *dev, uint8_t *data) +{ + int i; + int ret; + int size = 64 * 1024; - ret = nouveau_acpi_get_bios_chunk(bios->data, ptr, size); - if (ret != size) { - kfree(bios->data); - bios->data = NULL; - return; - } + if (!nouveau_acpi_rom_supported(dev->pdev)) + return; - len -= size; - ptr += size; + for (i = 0; i < (size / ROM_BIOS_PAGE); i++) { + ret = nouveau_acpi_get_bios_chunk(data, + (i * ROM_BIOS_PAGE), + ROM_BIOS_PAGE); + if (ret <= 0) + break; } + return; } struct methods { const char desc[8]; - void (*shadow)(struct nvbios *); + void (*loadbios)(struct drm_device *, uint8_t *); const bool rw; - int score; - u32 size; - u8 *data; }; -static bool -bios_shadow(struct drm_device *dev) -{ - struct methods shadow_methods[] = { - { "PRAMIN", bios_shadow_pramin, true, 0, 0, NULL }, - { "PROM", bios_shadow_prom, false, 0, 0, NULL }, - { "ACPI", bios_shadow_acpi, true, 0, 0, NULL }, - { "PCIROM", bios_shadow_pci, true, 0, 0, NULL }, - {} - }; - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nvbios *bios = &dev_priv->vbios; - struct methods *mthd, *best; +static struct methods shadow_methods[] = { + { "PRAMIN", load_vbios_pramin, true }, + { "PROM", load_vbios_prom, false }, + { "PCIROM", load_vbios_pci, true }, + { "ACPI", load_vbios_acpi, true }, +}; +#define NUM_SHADOW_METHODS ARRAY_SIZE(shadow_methods) + +static bool NVShadowVBIOS(struct drm_device *dev, uint8_t *data) +{ + struct methods *methods = shadow_methods; + int testscore = 3; + int scores[NUM_SHADOW_METHODS], i; if (nouveau_vbios) { - mthd = shadow_methods; - do { - if (strcasecmp(nouveau_vbios, mthd->desc)) - continue; - NV_INFO(dev, "VBIOS source: %s\n", mthd->desc); + for (i = 0; i < NUM_SHADOW_METHODS; i++) + if (!strcasecmp(nouveau_vbios, methods[i].desc)) + break; - mthd->shadow(bios); - mthd->score = score_vbios(bios, mthd->rw); - if (mthd->score) + if (i < NUM_SHADOW_METHODS) { + NV_INFO(dev, "Attempting to use BIOS image from %s\n", + methods[i].desc); + + methods[i].loadbios(dev, data); + if (score_vbios(dev, data, methods[i].rw)) return true; - } while ((++mthd)->shadow); + } NV_ERROR(dev, "VBIOS source \'%s\' invalid\n", nouveau_vbios); } - mthd = shadow_methods; - do { - NV_TRACE(dev, "Checking %s for VBIOS\n", mthd->desc); - mthd->shadow(bios); - mthd->score = score_vbios(bios, mthd->rw); - mthd->size = bios->length; - mthd->data = bios->data; - } while (mthd->score != 3 && (++mthd)->shadow); - - mthd = shadow_methods; - best = mthd; - do { - if (mthd->score > best->score) { - kfree(best->data); - best = mthd; - } - } while ((++mthd)->shadow); + for (i = 0; i < NUM_SHADOW_METHODS; i++) { + NV_TRACE(dev, "Attempting to load BIOS image from %s\n", + methods[i].desc); + data[0] = data[1] = 0; /* avoid reuse of previous image */ + methods[i].loadbios(dev, data); + scores[i] = score_vbios(dev, data, methods[i].rw); + if (scores[i] == testscore) + return true; + } - if (best->score) { - NV_TRACE(dev, "Using VBIOS from %s\n", best->desc); - bios->length = best->size; - bios->data = best->data; - return true; + while (--testscore > 0) { + for (i = 0; i < NUM_SHADOW_METHODS; i++) { + if (scores[i] == testscore) { + NV_TRACE(dev, "Using BIOS image from %s\n", + methods[i].desc); + methods[i].loadbios(dev, data); + return true; + } + } } - NV_ERROR(dev, "No valid VBIOS image found\n"); + NV_ERROR(dev, "No valid BIOS image found\n"); return false; } @@ -331,11 +295,6 @@ munge_reg(struct nvbios *bios, uint32_t reg) if (dev_priv->card_type < NV_50) return reg; - if (reg & 0x80000000) { - BUG_ON(bios->display.crtc < 0); - reg += bios->display.crtc * 0x800; - } - if (reg & 0x40000000) { BUG_ON(!dcbent); @@ -344,7 +303,7 @@ munge_reg(struct nvbios *bios, uint32_t reg) reg += 0x00000080; } - reg &= ~0xe0000000; + reg &= ~0x60000000; return reg; } @@ -675,9 +634,10 @@ static int nv50_pll_set(struct drm_device *dev, uint32_t reg, uint32_t clk) { struct drm_nouveau_private *dev_priv = dev->dev_private; + uint32_t reg0 = nv_rd32(dev, reg + 0); + uint32_t reg1 = nv_rd32(dev, reg + 4); struct nouveau_pll_vals pll; struct pll_lims pll_limits; - u32 ctrl, mask, coef; int ret; ret = get_pll_limits(dev, reg, &pll_limits); @@ -688,20 +648,15 @@ nv50_pll_set(struct drm_device *dev, uint32_t reg, uint32_t clk) if (!clk) return -ERANGE; - coef = pll.N1 << 8 | pll.M1; - ctrl = pll.log2P << 16; - mask = 0x00070000; - if (reg == 0x004008) { - mask |= 0x01f80000; - ctrl |= (pll_limits.log2p_bias << 19); - ctrl |= (pll.log2P << 22); - } + reg0 = (reg0 & 0xfff8ffff) | (pll.log2P << 16); + reg1 = (reg1 & 0xffff0000) | (pll.N1 << 8) | pll.M1; - if (!dev_priv->vbios.execute) - return 0; + if (dev_priv->vbios.execute) { + still_alive(); + nv_wr32(dev, reg + 4, reg1); + nv_wr32(dev, reg + 0, reg0); + } - nv_mask(dev, reg + 0, mask, ctrl); - nv_wr32(dev, reg + 4, coef); return 0; } @@ -758,19 +713,115 @@ static int dcb_entry_idx_from_crtchead(struct drm_device *dev) return dcb_entry; } +static int +read_dcb_i2c_entry(struct drm_device *dev, int dcb_version, uint8_t *i2ctable, int index, struct dcb_i2c_entry *i2c) +{ + uint8_t dcb_i2c_ver = dcb_version, headerlen = 0, entry_len = 4; + int i2c_entries = DCB_MAX_NUM_I2C_ENTRIES; + int recordoffset = 0, rdofs = 1, wrofs = 0; + uint8_t port_type = 0; + + if (!i2ctable) + return -EINVAL; + + if (dcb_version >= 0x30) { + if (i2ctable[0] != dcb_version) /* necessary? */ + NV_WARN(dev, + "DCB I2C table version mismatch (%02X vs %02X)\n", + i2ctable[0], dcb_version); + dcb_i2c_ver = i2ctable[0]; + headerlen = i2ctable[1]; + if (i2ctable[2] <= DCB_MAX_NUM_I2C_ENTRIES) + i2c_entries = i2ctable[2]; + else + NV_WARN(dev, + "DCB I2C table has more entries than indexable " + "(%d entries, max %d)\n", i2ctable[2], + DCB_MAX_NUM_I2C_ENTRIES); + entry_len = i2ctable[3]; + /* [4] is i2c_default_indices, read in parse_dcb_table() */ + } + /* + * It's your own fault if you call this function on a DCB 1.1 BIOS -- + * the test below is for DCB 1.2 + */ + if (dcb_version < 0x14) { + recordoffset = 2; + rdofs = 0; + wrofs = 1; + } + + if (index == 0xf) + return 0; + if (index >= i2c_entries) { + NV_ERROR(dev, "DCB I2C index too big (%d >= %d)\n", + index, i2ctable[2]); + return -ENOENT; + } + if (i2ctable[headerlen + entry_len * index + 3] == 0xff) { + NV_ERROR(dev, "DCB I2C entry invalid\n"); + return -EINVAL; + } + + if (dcb_i2c_ver >= 0x30) { + port_type = i2ctable[headerlen + recordoffset + 3 + entry_len * index]; + + /* + * Fixup for chips using same address offset for read and + * write. + */ + if (port_type == 4) /* seen on C51 */ + rdofs = wrofs = 1; + if (port_type >= 5) /* G80+ */ + rdofs = wrofs = 0; + } + + if (dcb_i2c_ver >= 0x40) { + if (port_type != 5 && port_type != 6) + NV_WARN(dev, "DCB I2C table has port type %d\n", port_type); + + i2c->entry = ROM32(i2ctable[headerlen + recordoffset + entry_len * index]); + } + + i2c->port_type = port_type; + i2c->read = i2ctable[headerlen + recordoffset + rdofs + entry_len * index]; + i2c->write = i2ctable[headerlen + recordoffset + wrofs + entry_len * index]; + + return 0; +} + static struct nouveau_i2c_chan * init_i2c_device_find(struct drm_device *dev, int i2c_index) { + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct dcb_table *dcb = &dev_priv->vbios.dcb; + if (i2c_index == 0xff) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct dcb_table *dcb = &dev_priv->vbios.dcb; /* note: dcb_entry_idx_from_crtchead needs pre-script set-up */ - int idx = dcb_entry_idx_from_crtchead(dev); + int idx = dcb_entry_idx_from_crtchead(dev), shift = 0; + int default_indices = dcb->i2c_default_indices; - i2c_index = NV_I2C_DEFAULT(0); if (idx != 0x7f && dcb->entry[idx].i2c_upper_default) - i2c_index = NV_I2C_DEFAULT(1); + shift = 4; + + i2c_index = (default_indices >> shift) & 0xf; } + if (i2c_index == 0x80) /* g80+ */ + i2c_index = dcb->i2c_default_indices & 0xf; + else + if (i2c_index == 0x81) + i2c_index = (dcb->i2c_default_indices & 0xf0) >> 4; + + if (i2c_index >= DCB_MAX_NUM_I2C_ENTRIES) { + NV_ERROR(dev, "invalid i2c_index 0x%x\n", i2c_index); + return NULL; + } + + /* Make sure i2c table entry has been parsed, it may not + * have been if this is a bus not referenced by a DCB encoder + */ + read_dcb_i2c_entry(dev, dcb->version, dcb->i2c_table, + i2c_index, &dcb->i2c[i2c_index]); return nouveau_i2c_find(dev, i2c_index); } @@ -1122,29 +1173,36 @@ init_dp_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) * */ + struct bit_displayport_encoder_table *dpe = NULL; struct dcb_entry *dcb = bios->display.output; struct drm_device *dev = bios->dev; uint8_t cond = bios->data[offset + 1]; - uint8_t *table, *entry; + int dummy; BIOSLOG(bios, "0x%04X: subop 0x%02X\n", offset, cond); if (!iexec->execute) return 3; - table = nouveau_dp_bios_data(dev, dcb, &entry); - if (!table) + dpe = nouveau_bios_dp_table(dev, dcb, &dummy); + if (!dpe) { + NV_ERROR(dev, "0x%04X: INIT_3A: no encoder table!!\n", offset); return 3; + } switch (cond) { case 0: - entry = dcb_conn(dev, dcb->connector); - if (!entry || entry[0] != DCB_CONNECTOR_eDP) + { + struct dcb_connector_table_entry *ent = + &bios->dcb.connector.entry[dcb->connector]; + + if (ent->type != DCB_CONNECTOR_eDP) iexec->execute = false; + } break; case 1: case 2: - if (!(entry[5] & cond)) + if (!(dpe->unknown & cond)) iexec->execute = false; break; case 5: @@ -3174,8 +3232,49 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) * each GPIO according to various values listed in each entry */ - if (iexec->execute && bios->execute) - nouveau_gpio_reset(bios->dev); + struct drm_nouveau_private *dev_priv = bios->dev->dev_private; + struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; + const uint32_t nv50_gpio_ctl[2] = { 0xe100, 0xe28c }; + int i; + + if (dev_priv->card_type < NV_50) { + NV_ERROR(bios->dev, "INIT_GPIO on unsupported chipset\n"); + return 1; + } + + if (!iexec->execute) + return 1; + + for (i = 0; i < bios->dcb.gpio.entries; i++) { + struct dcb_gpio_entry *gpio = &bios->dcb.gpio.entry[i]; + uint32_t r, s, v; + + BIOSLOG(bios, "0x%04X: Entry: 0x%08X\n", offset, gpio->entry); + + BIOSLOG(bios, "0x%04X: set gpio 0x%02x, state %d\n", + offset, gpio->tag, gpio->state_default); + if (bios->execute) + pgpio->set(bios->dev, gpio->tag, gpio->state_default); + + /* The NVIDIA binary driver doesn't appear to actually do + * any of this, my VBIOS does however. + */ + /* Not a clue, needs de-magicing */ + r = nv50_gpio_ctl[gpio->line >> 4]; + s = (gpio->line & 0x0f); + v = bios_rd32(bios, r) & ~(0x00010001 << s); + switch ((gpio->entry & 0x06000000) >> 25) { + case 1: + v |= (0x00000001 << s); + break; + case 2: + v |= (0x00010000 << s); + break; + default: + break; + } + bios_wr32(bios, r, v); + } return 1; } @@ -3637,10 +3736,6 @@ parse_init_table(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) int count = 0, i, ret; uint8_t id; - /* catch NULL script pointers */ - if (offset == 0) - return 0; - /* * Loop until INIT_DONE causes us to break out of the loop * (or until offset > bios length just in case... ) @@ -4272,6 +4367,18 @@ int nouveau_bios_parse_lvds_table(struct drm_device *dev, int pxclk, bool *dl, b break; } + /* Dell Latitude D620 reports a too-high value for the dual-link + * transition freq, causing us to program the panel incorrectly. + * + * It doesn't appear the VBIOS actually uses its transition freq + * (90000kHz), instead it uses the "Number of LVDS channels" field + * out of the panel ID structure (http://www.spwg.org/). + * + * For the moment, a quirk will do :) + */ + if (nv_match_device(dev, 0x01d7, 0x1028, 0x01c2)) + bios->fp.duallink_transition_clk = 80000; + /* set dual_link flag for EDID case */ if (pxclk && (chip_version < 0x25 || chip_version > 0x28)) bios->fp.dual_link = (pxclk >= bios->fp.duallink_transition_clk); @@ -4281,37 +4388,86 @@ 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_entry *dcb, u32 hash) +static uint8_t * +bios_output_config_match(struct drm_device *dev, struct dcb_entry *dcbent, + uint16_t record, int record_len, int record_nr, + bool match_link) { - if ((hash & 0x000000f0) != (dcb->location << 4)) - return false; - if ((hash & 0x0000000f) != dcb->type) - return false; - if (!(hash & (dcb->or << 16))) - return false; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nvbios *bios = &dev_priv->vbios; + uint32_t entry; + uint16_t table; + int i, v; - switch (dcb->type) { + switch (dcbent->type) { case OUTPUT_TMDS: case OUTPUT_LVDS: case OUTPUT_DP: - if (hash & 0x00c00000) { - if (!(hash & (dcb->sorconf.link << 22))) - return false; - } + break; default: - return true; + match_link = false; + break; } + + for (i = 0; i < record_nr; i++, record += record_len) { + table = ROM16(bios->data[record]); + if (!table) + continue; + entry = ROM32(bios->data[table]); + + if (match_link) { + v = (entry & 0x00c00000) >> 22; + if (!(v & dcbent->sorconf.link)) + continue; + } + + v = (entry & 0x000f0000) >> 16; + if (!(v & dcbent->or)) + continue; + + v = (entry & 0x000000f0) >> 4; + if (v != dcbent->location) + continue; + + v = (entry & 0x0000000f); + if (v != dcbent->type) + continue; + + return &bios->data[table]; + } + + return NULL; +} + +void * +nouveau_bios_dp_table(struct drm_device *dev, struct dcb_entry *dcbent, + int *length) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nvbios *bios = &dev_priv->vbios; + uint8_t *table; + + if (!bios->display.dp_table_ptr) { + NV_ERROR(dev, "No pointer to DisplayPort table\n"); + return NULL; + } + table = &bios->data[bios->display.dp_table_ptr]; + + if (table[0] != 0x20 && table[0] != 0x21) { + NV_ERROR(dev, "DisplayPort table version 0x%02x unknown\n", + table[0]); + return NULL; + } + + *length = table[4]; + return bios_output_config_match(dev, dcbent, + bios->display.dp_table_ptr + table[1], + table[2], table[3], table[0] >= 0x21); } int -nouveau_bios_run_display_table(struct drm_device *dev, u16 type, int pclk, - struct dcb_entry *dcbent, int crtc) +nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, + uint32_t sub, int pxclk) { /* * The display script table is located by the BIT 'U' table. @@ -4341,7 +4497,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, u16 type, int pclk, uint8_t *table = &bios->data[bios->display.script_table_ptr]; uint8_t *otable = NULL; uint16_t script; - int i; + int i = 0; if (!bios->display.script_table_ptr) { NV_ERROR(dev, "No pointer to output script table\n"); @@ -4393,33 +4549,30 @@ nouveau_bios_run_display_table(struct drm_device *dev, u16 type, int pclk, NV_DEBUG_KMS(dev, "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; - } - + otable = bios_output_config_match(dev, dcbent, table[1] + + bios->display.script_table_ptr, + table[2], table[3], table[0] >= 0x21); if (!otable) { NV_DEBUG_KMS(dev, "failed to match any output table\n"); return 1; } - if (pclk < -2 || pclk > 0) { + if (pxclk < -2 || pxclk > 0) { /* Try to find matching script table entry */ for (i = 0; i < otable[5]; i++) { - if (ROM16(otable[table[4] + i*6]) == type) + if (ROM16(otable[table[4] + i*6]) == sub) break; } if (i == otable[5]) { NV_ERROR(dev, "Table 0x%04x not found for %d/%d, " "using first\n", - type, dcbent->type, dcbent->or); + sub, dcbent->type, dcbent->or); i = 0; } } - if (pclk == 0) { + if (pxclk == 0) { script = ROM16(otable[6]); if (!script) { NV_DEBUG_KMS(dev, "output script 0 not found\n"); @@ -4427,9 +4580,9 @@ nouveau_bios_run_display_table(struct drm_device *dev, u16 type, int pclk, } NV_DEBUG_KMS(dev, "0x%04X: parsing output script 0\n", script); - nouveau_bios_run_init_table(dev, script, dcbent, crtc); + nouveau_bios_run_init_table(dev, script, dcbent); } else - if (pclk == -1) { + if (pxclk == -1) { script = ROM16(otable[8]); if (!script) { NV_DEBUG_KMS(dev, "output script 1 not found\n"); @@ -4437,9 +4590,9 @@ nouveau_bios_run_display_table(struct drm_device *dev, u16 type, int pclk, } NV_DEBUG_KMS(dev, "0x%04X: parsing output script 1\n", script); - nouveau_bios_run_init_table(dev, script, dcbent, crtc); + nouveau_bios_run_init_table(dev, script, dcbent); } else - if (pclk == -2) { + if (pxclk == -2) { if (table[4] >= 12) script = ROM16(otable[10]); else @@ -4450,31 +4603,31 @@ nouveau_bios_run_display_table(struct drm_device *dev, u16 type, int pclk, } NV_DEBUG_KMS(dev, "0x%04X: parsing output script 2\n", script); - nouveau_bios_run_init_table(dev, script, dcbent, crtc); + nouveau_bios_run_init_table(dev, script, dcbent); } else - if (pclk > 0) { + if (pxclk > 0) { script = ROM16(otable[table[4] + i*6 + 2]); if (script) - script = clkcmptable(bios, script, pclk); + script = clkcmptable(bios, script, pxclk); if (!script) { NV_DEBUG_KMS(dev, "clock script 0 not found\n"); return 1; } NV_DEBUG_KMS(dev, "0x%04X: parsing clock script 0\n", script); - nouveau_bios_run_init_table(dev, script, dcbent, crtc); + nouveau_bios_run_init_table(dev, script, dcbent); } else - if (pclk < 0) { + if (pxclk < 0) { script = ROM16(otable[table[4] + i*6 + 4]); if (script) - script = clkcmptable(bios, script, -pclk); + script = clkcmptable(bios, script, -pxclk); if (!script) { NV_DEBUG_KMS(dev, "clock script 1 not found\n"); return 1; } NV_DEBUG_KMS(dev, "0x%04X: parsing clock script 1\n", script); - nouveau_bios_run_init_table(dev, script, dcbent, crtc); + nouveau_bios_run_init_table(dev, script, dcbent); } return 0; @@ -4572,7 +4725,7 @@ static struct pll_mapping nv84_pll_mapping[] = { { PLL_CORE , 0x004028 }, { PLL_SHADER, 0x004020 }, { PLL_MEMORY, 0x004008 }, - { PLL_VDEC , 0x004030 }, + { PLL_UNK05 , 0x004030 }, { PLL_UNK41 , 0x00e818 }, { PLL_VPLL0 , 0x614100 }, { PLL_VPLL1 , 0x614900 }, @@ -5033,7 +5186,7 @@ static int parse_bit_A_tbl_entry(struct drm_device *dev, struct nvbios *bios, st load_table_ptr = ROM16(bios->data[bitentry->offset]); if (load_table_ptr == 0x0) { - NV_DEBUG(dev, "Pointer to BIT loadval table invalid\n"); + NV_ERROR(dev, "Pointer to BIT loadval table invalid\n"); return -EINVAL; } @@ -5324,6 +5477,14 @@ parse_bit_U_tbl_entry(struct drm_device *dev, struct nvbios *bios, return 0; } +static int +parse_bit_displayport_tbl_entry(struct drm_device *dev, struct nvbios *bios, + struct bit_entry *bitentry) +{ + bios->display.dp_table_ptr = ROM16(bios->data[bitentry->offset]); + return 0; +} + struct bit_table { const char id; int (* const parse_fn)(struct drm_device *, struct nvbios *, struct bit_entry *); @@ -5338,9 +5499,6 @@ bit_table(struct drm_device *dev, u8 id, struct bit_entry *bit) struct nvbios *bios = &dev_priv->vbios; u8 entries, *entry; - if (bios->type != NVBIOS_BIT) - return -ENODEV; - entries = bios->data[bios->offset + 10]; entry = &bios->data[bios->offset + 12]; while (entries--) { @@ -5349,7 +5507,7 @@ bit_table(struct drm_device *dev, u8 id, struct bit_entry *bit) bit->version = entry[1]; bit->length = ROM16(entry[2]); bit->offset = ROM16(entry[4]); - bit->data = ROMPTR(dev, entry[4]); + bit->data = ROMPTR(bios, entry[4]); return 0; } @@ -5400,6 +5558,7 @@ parse_bit_structure(struct nvbios *bios, const uint16_t bitoffset) 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)); + parse_bit_table(bios, bitoffset, &BIT_TABLE('d', displayport)); return 0; } @@ -5454,6 +5613,10 @@ static int parse_bmp_structure(struct drm_device *dev, struct nvbios *bios, unsi uint16_t legacy_scripts_offset, legacy_i2c_offset; /* load needed defaults in case we can't parse this info */ + bios->dcb.i2c[0].write = NV_CIO_CRE_DDC_WR__INDEX; + bios->dcb.i2c[0].read = NV_CIO_CRE_DDC_STATUS__INDEX; + bios->dcb.i2c[1].write = NV_CIO_CRE_DDC0_WR__INDEX; + bios->dcb.i2c[1].read = NV_CIO_CRE_DDC0_STATUS__INDEX; bios->digital_min_front_porch = 0x4b; bios->fmaxvco = 256000; bios->fminvco = 128000; @@ -5561,6 +5724,14 @@ static int parse_bmp_structure(struct drm_device *dev, struct nvbios *bios, unsi bios->legacy.i2c_indices.crt = bios->data[legacy_i2c_offset]; bios->legacy.i2c_indices.tv = bios->data[legacy_i2c_offset + 1]; bios->legacy.i2c_indices.panel = bios->data[legacy_i2c_offset + 2]; + if (bios->data[legacy_i2c_offset + 4]) + bios->dcb.i2c[0].write = bios->data[legacy_i2c_offset + 4]; + if (bios->data[legacy_i2c_offset + 5]) + bios->dcb.i2c[0].read = bios->data[legacy_i2c_offset + 5]; + if (bios->data[legacy_i2c_offset + 6]) + bios->dcb.i2c[1].write = bios->data[legacy_i2c_offset + 6]; + if (bios->data[legacy_i2c_offset + 7]) + bios->dcb.i2c[1].read = bios->data[legacy_i2c_offset + 7]; if (bmplength > 74) { bios->fmaxvco = ROM32(bmp[67]); @@ -5611,128 +5782,274 @@ static uint16_t findstr(uint8_t *data, int n, const uint8_t *str, int len) return 0; } -void * -dcb_table(struct drm_device *dev) +static struct dcb_gpio_entry * +new_gpio_entry(struct nvbios *bios) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - u8 *dcb = NULL; + struct drm_device *dev = bios->dev; + struct dcb_gpio_table *gpio = &bios->dcb.gpio; - if (dev_priv->card_type > NV_04) - dcb = ROMPTR(dev, dev_priv->vbios.data[0x36]); - if (!dcb) { - NV_WARNONCE(dev, "No DCB data found in VBIOS\n"); + if (gpio->entries >= DCB_MAX_NUM_GPIO_ENTRIES) { + NV_ERROR(dev, "exceeded maximum number of gpio entries!!\n"); return NULL; } - if (dcb[0] >= 0x41) { - NV_WARNONCE(dev, "DCB version 0x%02x unknown\n", dcb[0]); - return NULL; - } else - if (dcb[0] >= 0x30) { - if (ROM32(dcb[6]) == 0x4edcbdcb) - return dcb; - } else - if (dcb[0] >= 0x20) { - if (ROM32(dcb[4]) == 0x4edcbdcb) - return dcb; - } else - if (dcb[0] >= 0x15) { - if (!memcmp(&dcb[-7], "DEV_REC", 7)) - return dcb; - } else { - /* - * v1.4 (some NV15/16, NV11+) seems the same as v1.5, but - * always has the same single (crt) entry, even when tv-out - * present, so the conclusion is this version cannot really - * be used. - * - * v1.2 tables (some NV6/10, and NV15+) normally have the - * same 5 entries, which are not specific to the card and so - * no use. - * - * v1.2 does have an I2C table that read_dcb_i2c_table can - * handle, but cards exist (nv11 in #14821) with a bad i2c - * table pointer, so use the indices parsed in - * parse_bmp_structure. - * - * v1.1 (NV5+, maybe some NV4) is entirely unhelpful - */ - NV_WARNONCE(dev, "No useful DCB data in VBIOS\n"); - return NULL; + return &gpio->entry[gpio->entries++]; +} + +struct dcb_gpio_entry * +nouveau_bios_gpio_entry(struct drm_device *dev, enum dcb_gpio_tag tag) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nvbios *bios = &dev_priv->vbios; + int i; + + for (i = 0; i < bios->dcb.gpio.entries; i++) { + if (bios->dcb.gpio.entry[i].tag != tag) + continue; + + return &bios->dcb.gpio.entry[i]; } - NV_WARNONCE(dev, "DCB header validation failed\n"); return NULL; } -void * -dcb_outp(struct drm_device *dev, u8 idx) +static void +parse_dcb_gpio_table(struct nvbios *bios) { - u8 *dcb = dcb_table(dev); - if (dcb && dcb[0] >= 0x30) { - if (idx < dcb[2]) - return dcb + dcb[1] + (idx * dcb[3]); + struct drm_device *dev = bios->dev; + struct dcb_gpio_entry *e; + u8 headerlen, entries, recordlen; + u8 *dcb, *gpio = NULL, *entry; + int i; + + dcb = ROMPTR(bios, bios->data[0x36]); + if (dcb[0] >= 0x30) { + gpio = ROMPTR(bios, dcb[10]); + if (!gpio) + goto no_table; + + headerlen = gpio[1]; + entries = gpio[2]; + recordlen = gpio[3]; } else - if (dcb && dcb[0] >= 0x20) { - u8 *i2c = ROMPTR(dev, dcb[2]); - u8 *ent = dcb + 8 + (idx * 8); - if (i2c && ent < i2c) - return ent; + if (dcb[0] >= 0x22 && dcb[-1] >= 0x13) { + gpio = ROMPTR(bios, dcb[-15]); + if (!gpio) + goto no_table; + + headerlen = 3; + entries = gpio[2]; + recordlen = gpio[1]; } else - if (dcb && dcb[0] >= 0x15) { - u8 *i2c = ROMPTR(dev, dcb[2]); - u8 *ent = dcb + 4 + (idx * 10); - if (i2c && ent < i2c) - return ent; + if (dcb[0] >= 0x22) { + /* No GPIO table present, parse the TVDAC GPIO data. */ + uint8_t *tvdac_gpio = &dcb[-5]; + + if (tvdac_gpio[0] & 1) { + e = new_gpio_entry(bios); + e->tag = DCB_GPIO_TVDAC0; + e->line = tvdac_gpio[1] >> 4; + e->invert = tvdac_gpio[0] & 2; + } + + goto no_table; + } else { + NV_DEBUG(dev, "no/unknown gpio table on DCB 0x%02x\n", dcb[0]); + goto no_table; } - return NULL; + entry = gpio + headerlen; + for (i = 0; i < entries; i++, entry += recordlen) { + e = new_gpio_entry(bios); + if (!e) + break; + + if (gpio[0] < 0x40) { + e->entry = ROM16(entry[0]); + e->tag = (e->entry & 0x07e0) >> 5; + if (e->tag == 0x3f) { + bios->dcb.gpio.entries--; + continue; + } + + e->line = (e->entry & 0x001f); + e->invert = ((e->entry & 0xf800) >> 11) != 4; + } else { + e->entry = ROM32(entry[0]); + e->tag = (e->entry & 0x0000ff00) >> 8; + if (e->tag == 0xff) { + bios->dcb.gpio.entries--; + continue; + } + + e->line = (e->entry & 0x0000001f) >> 0; + e->state_default = (e->entry & 0x01000000) >> 24; + e->state[0] = (e->entry & 0x18000000) >> 27; + e->state[1] = (e->entry & 0x60000000) >> 29; + } + } + +no_table: + /* Apple iMac G4 NV18 */ + if (nv_match_device(dev, 0x0189, 0x10de, 0x0010)) { + e = new_gpio_entry(bios); + if (e) { + e->tag = DCB_GPIO_TVDAC0; + e->line = 4; + } + } } -int -dcb_outp_foreach(struct drm_device *dev, void *data, - int (*exec)(struct drm_device *, void *, int idx, u8 *outp)) -{ - int ret, idx = -1; - u8 *outp = NULL; - while ((outp = dcb_outp(dev, ++idx))) { - if (ROM32(outp[0]) == 0x00000000) - break; /* seen on an NV11 with DCB v1.5 */ - if (ROM32(outp[0]) == 0xffffffff) - break; /* seen on an NV17 with DCB v2.0 */ - - if ((outp[0] & 0x0f) == OUTPUT_UNUSED) - continue; - if ((outp[0] & 0x0f) == OUTPUT_EOL) - break; +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; - ret = exec(dev, data, idx, outp); - if (ret) - return ret; + 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); } - return 0; + 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; } -u8 * -dcb_conntab(struct drm_device *dev) +static void +apply_dcb_connector_quirks(struct nvbios *bios, int idx) { - 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; + 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; } - return NULL; } -u8 * -dcb_conn(struct drm_device *dev, u8 idx) +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) { - u8 *conntab = dcb_conntab(dev); - if (conntab && idx < conntab[2]) - return conntab + conntab[1] + (idx * conntab[3]); - return NULL; + 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); + } + + } } static struct dcb_entry *new_dcb_entry(struct dcb_table *dcb) @@ -5765,7 +6082,8 @@ 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; - entry->connector = (conn >> 12) & 0xf; + if (dcb->version >= 0x40) + entry->connector = (conn >> 12) & 0xf; entry->bus = (conn >> 16) & 0xf; entry->location = (conn >> 20) & 0x3; entry->or = (conn >> 24) & 0xf; @@ -5831,14 +6149,7 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb, } case OUTPUT_DP: entry->dpconf.sor.link = (conf & 0x00000030) >> 4; - switch ((conf & 0x00e00000) >> 21) { - case 0: - entry->dpconf.link_bw = 162000; - break; - default: - entry->dpconf.link_bw = 270000; - break; - } + entry->dpconf.link_bw = (conf & 0x00e00000) >> 21; switch ((conf & 0x0f000000) >> 24) { case 0xf: entry->dpconf.link_nr = 4; @@ -5937,6 +6248,25 @@ parse_dcb15_entry(struct drm_device *dev, struct dcb_table *dcb, return true; } +static bool parse_dcb_entry(struct drm_device *dev, struct dcb_table *dcb, + uint32_t conn, uint32_t conf) +{ + struct dcb_entry *entry = new_dcb_entry(dcb); + bool ret; + + 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 ret; + + read_dcb_i2c_entry(dev, dcb->version, dcb->i2c_table, + entry->i2c_index, &dcb->i2c[entry->i2c_index]); + + return true; +} + static void merge_like_dcb_entries(struct drm_device *dev, struct dcb_table *dcb) { @@ -6047,37 +6377,6 @@ apply_dcb_encoder_quirks(struct drm_device *dev, int idx, u32 *conn, u32 *conf) } } - /* Some other twisted XFX board (rhbz#694914) - * - * The DVI/VGA encoder combo that's supposed to represent the - * DVI-I connector actually point at two different ones, and - * the HDMI connector ends up paired with the VGA instead. - * - * Connector table is missing anything for VGA at all, pointing it - * an invalid conntab entry 2 so we figure it out ourself. - */ - if (nv_match_device(dev, 0x0615, 0x1682, 0x2605)) { - if (idx == 0) { - *conn = 0x02002300; /* VGA, connector 2 */ - *conf = 0x00000028; - } else - if (idx == 1) { - *conn = 0x01010312; /* DVI, connector 0 */ - *conf = 0x00020030; - } else - if (idx == 2) { - *conn = 0x04020310; /* VGA, connector 0 */ - *conf = 0x00000028; - } else - if (idx == 3) { - *conn = 0x02021322; /* HDMI, connector 1 */ - *conf = 0x00020010; - } else { - *conn = 0x0000000e; /* EOL */ - *conf = 0x00000000; - } - } - return true; } @@ -6097,118 +6396,154 @@ fabricate_dcb_encoder_table(struct drm_device *dev, struct nvbios *bios) #endif /* Make up some sane defaults */ - fabricate_dcb_output(dcb, OUTPUT_ANALOG, - bios->legacy.i2c_indices.crt, 1, 1); + fabricate_dcb_output(dcb, OUTPUT_ANALOG, LEGACY_I2C_CRT, 1, 1); if (nv04_tv_identify(dev, bios->legacy.i2c_indices.tv) >= 0) - fabricate_dcb_output(dcb, OUTPUT_TV, - bios->legacy.i2c_indices.tv, + fabricate_dcb_output(dcb, OUTPUT_TV, LEGACY_I2C_TV, all_heads, 0); else if (bios->tmds.output0_script_ptr || bios->tmds.output1_script_ptr) - fabricate_dcb_output(dcb, OUTPUT_TMDS, - bios->legacy.i2c_indices.panel, + fabricate_dcb_output(dcb, OUTPUT_TMDS, LEGACY_I2C_PANEL, all_heads, 1); } static int -parse_dcb_entry(struct drm_device *dev, void *data, int idx, u8 *outp) +parse_dcb_table(struct drm_device *dev, struct nvbios *bios) { struct drm_nouveau_private *dev_priv = dev->dev_private; - struct dcb_table *dcb = &dev_priv->vbios.dcb; - u32 conf = (dcb->version >= 0x20) ? ROM32(outp[4]) : ROM32(outp[6]); - u32 conn = ROM32(outp[0]); - bool ret; - - if (apply_dcb_encoder_quirks(dev, idx, &conn, &conf)) { - struct dcb_entry *entry = new_dcb_entry(dcb); - - NV_TRACEWARN(dev, "DCB outp %02d: %08x %08x\n", idx, conn, conf); + struct dcb_table *dcb = &bios->dcb; + uint16_t dcbptr = 0, i2ctabptr = 0; + uint8_t *dcbtable; + uint8_t headerlen = 0x4, entries = DCB_MAX_NUM_ENTRIES; + bool configblock = true; + int recordlength = 8, confofs = 4; + int i; - 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 */ + /* get the offset from 0x36 */ + if (dev_priv->card_type > NV_04) { + dcbptr = ROM16(bios->data[0x36]); + if (dcbptr == 0x0000) + NV_WARN(dev, "No output data (DCB) found in BIOS\n"); + } - /* 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; + /* this situation likely means a really old card, pre DCB */ + if (dcbptr == 0x0) { + fabricate_dcb_encoder_table(dev, bios); + return 0; } - return 0; -} + dcbtable = &bios->data[dcbptr]; -static void -dcb_fake_connectors(struct nvbios *bios) -{ - struct dcb_table *dcbt = &bios->dcb; - u8 map[16] = { }; - int i, idx = 0; + /* get DCB version */ + dcb->version = dcbtable[0]; + NV_TRACE(dev, "Found Display Configuration Block version %d.%d\n", + dcb->version >> 4, dcb->version & 0xf); - /* 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; - } + if (dcb->version >= 0x20) { /* NV17+ */ + uint32_t sig; - /* 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++; + if (dcb->version >= 0x30) { /* NV40+ */ + headerlen = dcbtable[1]; + entries = dcbtable[2]; + recordlength = dcbtable[3]; + i2ctabptr = ROM16(dcbtable[4]); + sig = ROM32(dcbtable[6]); + dcb->gpio_table_ptr = ROM16(dcbtable[10]); + dcb->connector_table_ptr = ROM16(dcbtable[20]); } else { - if (!map[i2c]) - map[i2c] = ++idx; - dcbt->entry[i].connector = map[i2c] - 1; + i2ctabptr = ROM16(dcbtable[2]); + sig = ROM32(dcbtable[4]); + headerlen = 8; } - } - /* 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; - } -} + if (sig != 0x4edcbdcb) { + NV_ERROR(dev, "Bad Display Configuration Block " + "signature (%08X)\n", sig); + return -EINVAL; + } + } else if (dcb->version >= 0x15) { /* some NV11 and NV20 */ + char sig[8] = { 0 }; -static int -parse_dcb_table(struct drm_device *dev, struct nvbios *bios) -{ - struct dcb_table *dcb = &bios->dcb; - u8 *dcbt, *conn; - int idx; - - dcbt = dcb_table(dev); - if (!dcbt) { - /* handle pre-DCB boards */ - if (bios->type == NVBIOS_BMP) { - fabricate_dcb_encoder_table(dev, bios); - return 0; + strncpy(sig, (char *)&dcbtable[-7], 7); + i2ctabptr = ROM16(dcbtable[2]); + recordlength = 10; + confofs = 6; + + if (strcmp(sig, "DEV_REC")) { + NV_ERROR(dev, "Bad Display Configuration Block " + "signature (%s)\n", sig); + return -EINVAL; } + } else { + /* + * v1.4 (some NV15/16, NV11+) seems the same as v1.5, but always + * has the same single (crt) entry, even when tv-out present, so + * the conclusion is this version cannot really be used. + * v1.2 tables (some NV6/10, and NV15+) normally have the same + * 5 entries, which are not specific to the card and so no use. + * v1.2 does have an I2C table that read_dcb_i2c_table can + * handle, but cards exist (nv11 in #14821) with a bad i2c table + * pointer, so use the indices parsed in parse_bmp_structure. + * v1.1 (NV5+, maybe some NV4) is entirely unhelpful + */ + NV_TRACEWARN(dev, "No useful information in BIOS output table; " + "adding all possible outputs\n"); + fabricate_dcb_encoder_table(dev, bios); + return 0; + } - return -EINVAL; + if (!i2ctabptr) + NV_WARN(dev, "No pointer to DCB I2C port table\n"); + else { + dcb->i2c_table = &bios->data[i2ctabptr]; + if (dcb->version >= 0x30) + dcb->i2c_default_indices = dcb->i2c_table[4]; + + /* + * Parse the "management" I2C bus, used for hardware + * monitoring and some external TMDS transmitters. + */ + if (dcb->version >= 0x22) { + int idx = (dcb->version >= 0x40 ? + dcb->i2c_default_indices & 0xf : + 2); + + read_dcb_i2c_entry(dev, dcb->version, dcb->i2c_table, + idx, &dcb->i2c[idx]); + } } - NV_TRACE(dev, "DCB version %d.%d\n", dcbt[0] >> 4, dcbt[0] & 0xf); + if (entries > DCB_MAX_NUM_ENTRIES) + entries = DCB_MAX_NUM_ENTRIES; + + for (i = 0; i < entries; i++) { + uint32_t connection, config = 0; - dcb->version = dcbt[0]; - dcb_outp_foreach(dev, NULL, parse_dcb_entry); + connection = ROM32(dcbtable[headerlen + recordlength * i]); + if (configblock) + config = ROM32(dcbtable[headerlen + confofs + recordlength * i]); + + /* seen on an NV11 with DCB v1.5 */ + if (connection == 0x00000000) + break; + + /* seen on an NV17 with DCB v2.0 */ + if (connection == 0xffffffff) + break; + + if ((connection & 0x0000000f) == 0x0000000f) + continue; + + if (!apply_dcb_encoder_quirks(dev, i, &connection, &config)) + continue; + + NV_TRACEWARN(dev, "Raw DCB entry %d: %08x %08x\n", + dcb->entries, connection, config); + + if (!parse_dcb_entry(dev, dcb, connection, config)) + break; + } /* * apart for v2.1+ not being known for requiring merging, this @@ -6220,19 +6555,77 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios) if (!dcb->entries) return -ENXIO; - /* 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])); + 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; } + + dcb->entry[i].connector = dcb->connector.entries++; + if (i2c != 0xf) + i2c_conn[i2c] = dcb->connector.entries; + } + + /* 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; + } +} + +static void +fixup_legacy_i2c(struct nvbios *bios) +{ + struct dcb_table *dcb = &bios->dcb; + int i; + + for (i = 0; i < dcb->entries; i++) { + if (dcb->entry[i].i2c_index == LEGACY_I2C_CRT) + dcb->entry[i].i2c_index = bios->legacy.i2c_indices.crt; + if (dcb->entry[i].i2c_index == LEGACY_I2C_PANEL) + dcb->entry[i].i2c_index = bios->legacy.i2c_indices.panel; + if (dcb->entry[i].i2c_index == LEGACY_I2C_TV) + dcb->entry[i].i2c_index = bios->legacy.i2c_indices.tv; } - dcb_fake_connectors(bios); - return 0; } static int load_nv17_hwsq_ucode_entry(struct drm_device *dev, struct nvbios *bios, uint16_t hwsq_offset, int entry) @@ -6338,7 +6731,7 @@ uint8_t *nouveau_bios_embedded_edid(struct drm_device *dev) void nouveau_bios_run_init_table(struct drm_device *dev, uint16_t table, - struct dcb_entry *dcbent, int crtc) + struct dcb_entry *dcbent) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nvbios *bios = &dev_priv->vbios; @@ -6346,22 +6739,11 @@ nouveau_bios_run_init_table(struct drm_device *dev, uint16_t table, spin_lock_bh(&bios->lock); bios->display.output = dcbent; - bios->display.crtc = crtc; parse_init_table(bios, table, &iexec); bios->display.output = NULL; spin_unlock_bh(&bios->lock); } -void -nouveau_bios_init_exec(struct drm_device *dev, uint16_t table) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nvbios *bios = &dev_priv->vbios; - struct init_exec iexec = { true, false }; - - parse_init_table(bios, table, &iexec); -} - static bool NVInitVBIOS(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; @@ -6371,7 +6753,11 @@ static bool NVInitVBIOS(struct drm_device *dev) spin_lock_init(&bios->lock); bios->dev = dev; - return bios_shadow(dev); + if (!NVShadowVBIOS(dev, bios->data)) + return false; + + bios->length = NV_PROM_SIZE; + return true; } static int nouveau_parse_vbios_struct(struct drm_device *dev) @@ -6439,14 +6825,28 @@ nouveau_run_vbios_init(struct drm_device *dev) if (dev_priv->card_type >= NV_50) { for (i = 0; i < bios->dcb.entries; i++) { - nouveau_bios_run_display_table(dev, 0, 0, - &bios->dcb.entry[i], -1); + nouveau_bios_run_display_table(dev, + &bios->dcb.entry[i], + 0, 0); } } return ret; } +static void +nouveau_bios_i2c_devices_takedown(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nvbios *bios = &dev_priv->vbios; + struct dcb_i2c_entry *entry; + int i; + + entry = &bios->dcb.i2c[0]; + for (i = 0; i < DCB_MAX_NUM_I2C_ENTRIES; i++, entry++) + nouveau_i2c_fini(dev, entry); +} + static bool nouveau_bios_posted(struct drm_device *dev) { @@ -6483,18 +6883,13 @@ nouveau_bios_init(struct drm_device *dev) if (ret) return ret; - ret = nouveau_i2c_init(dev); - if (ret) - return ret; - - ret = nouveau_mxm_init(dev); - if (ret) - return ret; - ret = parse_dcb_table(dev, bios); if (ret) return ret; + fixup_legacy_i2c(bios); + fixup_legacy_connector(bios); + if (!bios->major_version) /* we don't run version 0 bios */ return 0; @@ -6531,10 +6926,5 @@ nouveau_bios_init(struct drm_device *dev) void nouveau_bios_takedown(struct drm_device *dev) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - - nouveau_mxm_fini(dev); - nouveau_i2c_fini(dev); - - kfree(dev_priv->vbios.data); + nouveau_bios_i2c_devices_takedown(dev); } |