From 10bd7818351bfa5237c43148d811f089f22f16fa Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Tue, 10 Feb 2009 20:06:38 +0100 Subject: [PATCH] bios: A better attempt at g80+ lvds without ddc capability. --- src/nv_bios.c | 80 +++++++++++++++++++++++++++++++------------------------- src/nv_type.h | 1 + 2 files changed, 45 insertions(+), 36 deletions(-) diff --git a/src/nv_bios.c b/src/nv_bios.c index 7b98473..c328f03 100644 --- a/src/nv_bios.c +++ b/src/nv_bios.c @@ -3267,36 +3267,25 @@ static int parse_fp_mode_table(ScrnInfoPtr pScrn, bios_t *bios) fpstrapping = get_fp_strap(pScrn, bios); if (lth.lvds_ver == 0x40) { - /* Query all modes and find one with a matching clock. */ - /* Note that this only serves as a backup solution if ddc fails. */ - - uint32_t clock, needed_clock; - int i, index = 0xF, matches = 0; - needed_clock = nv32_rd(pScrn, 0x00616404) & 0xFFFFF; - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "LVDS clock seems to be %d KHz.\n", needed_clock); - - for (i = 0; i < fpentries; i++) { - modeofs = headerlen + recordlen * i; - clock = le16_to_cpu(*(uint16_t *)&fptable[modeofs]) * 10; - if (clock == needed_clock) { - matches++; - index = i; - } - } - - if (matches == 1) - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Found a mode with matching clock\n"); + /* Time for another story. + * (0x00616404 &0xFFFFF) doesn't always hold the correct clock for some reason. + * I have one bios that reports no i2c capabilities (index 0xf). + * It iterates from 0xa to 0x6 in the dcb_table, and uses the last result as the "fpstrapping". + * There is an explicit check for dcb type 0xe, and it is used as a (premature) terminator. + * Most roms don't access fptable, but instead use some strange and very low default clock. + * They do have this iteration over the dcb table, but don't use it for this purpose. + * Do *NOT* trust this on panels that have ddc capability. + * This special bios (with no i2c on lvds) is unique in not having conf bit16 and having conf bit0. + */ + NVPtr pNv = NVPTR(pScrn); + /* parse_dcb_table() sets this in advance. */ + if (!bios->fp.ddc_permitted) + fpstrapping = pNv->dcb_table.claimed_entries - pNv->dcb_table.entries; else - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Found %d modes, this is not useful\n", matches); - - if (matches != 1) - index = 0xF; + fpstrapping = 0xF; + } - fpindex = bios->data[bios->fp.fpxlatetableptr + index * bios->fp.xlatwidth]; - /* strapping only set as a hack for DDC test below */ - fpstrapping = fpindex & 0xf; - } else - fpindex = bios->data[bios->fp.fpxlatetableptr + fpstrapping * bios->fp.xlatwidth]; + fpindex = bios->data[bios->fp.fpxlatetableptr + fpstrapping * bios->fp.xlatwidth]; if (fpindex > fpentries) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, @@ -4462,14 +4451,29 @@ parse_dcb_entry(ScrnInfoPtr pScrn, int index, uint8_t dcb_version, uint16_t i2ct mask = ~0x5; if (conf & 0x4) entry->lvdsconf.use_power_scripts = true; - } - if (conf & mask) { - /* I'm bored of getting this reported; left as a reminder for someone to fix it */ if (dcb_version >= 0x40) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "G80+ LVDS not initialized by driver; ignoring conf bits\n"); - break; + /* This is based on a sample set of about 6-7 roms. + * All have this bit set, except one that doesn't do ddc. + * This rom is also the only one with bit0 set, so i am not + * excluding the possibility of correlation there. + * No idea what bit4 and 5 do. + */ + mask ^= 0x10030; + if (conf & 0x10000) + pNv->VBIOS.fp.ddc_permitted = true; + else + pNv->VBIOS.fp.ddc_permitted = false; + + if ((entry->i2c_index == 0xF ? 0 : 1) ^ pNv->VBIOS.fp.ddc_permitted) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Unknown LVDS i2c configuration, please report\n"); + /* cause output setting to fail, so message is seen */ + pNv->dcb_table.entries = 0; + return false; + } } + } + if (conf & mask) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unknown LVDS configuration bits, please report\n"); /* cause output setting to fail, so message is seen */ @@ -4676,6 +4680,9 @@ static int parse_dcb_table(ScrnInfoPtr pScrn, bios_t *bios) if (entries >= MAX_NUM_DCB_ENTRIES) entries = MAX_NUM_DCB_ENTRIES; + /* Needed for G80+. */ + pNv->dcb_table.claimed_entries = entries; + for (i = 0; i < entries; i++) { uint32_t connection, config = 0; @@ -4884,11 +4891,12 @@ int NVParseBios(ScrnInfoPtr pScrn) nv32_wr(pScrn, NV_PEXTDEV_BOOT_0, saved_nv_pextdev_boot_0); + /* G80+ LVDS needs some info from the dcb table later on. */ + parse_dcb_table(pScrn, &pNv->VBIOS); + if ((ret = NVRunVBIOSInit(pScrn))) return ret; - parse_dcb_table(pScrn, &pNv->VBIOS); - for (i = 0 ; i < pNv->dcb_table.entries; i++) if (pNv->dcb_table.entry[i].type == OUTPUT_LVDS) call_lvds_script(pScrn, &pNv->dcb_table.entry[i], nv_get_digital_bound_head(pNv, pNv->dcb_table.entry[i].or), LVDS_INIT, 0); diff --git a/src/nv_type.h b/src/nv_type.h index 6da8561..21d72b8 100644 --- a/src/nv_type.h +++ b/src/nv_type.h @@ -336,6 +336,7 @@ typedef struct _NVRec { struct { int entries; + int claimed_entries; /* based on header, typically 10 */ struct dcb_entry entry[MAX_NUM_DCB_ENTRIES]; uint8_t i2c_default_indices; struct dcb_i2c_entry i2c[MAX_NUM_DCB_ENTRIES]; -- 1.6.1.2