xf86-video-intel: src/bios_reader/bios_reader.c src/i830_bios.c src/i830_bios.h src/i830_driver.c src/i830_dvo.c src/i830.h src/i830_lvds.c src/i830_tv.c

Jesse Barnes jbarnes at kemper.freedesktop.org
Tue Aug 5 13:46:13 PDT 2008


 src/bios_reader/bios_reader.c |  291 +++++++++++++++++++++---------
 src/i830.h                    |    6 
 src/i830_bios.c               |  401 ++++++++++++------------------------------
 src/i830_bios.h               |   72 ++++---
 src/i830_driver.c             |    8 
 src/i830_dvo.c                |   43 ++--
 src/i830_lvds.c               |  158 +++++++---------
 src/i830_tv.c                 |    1 
 8 files changed, 469 insertions(+), 511 deletions(-)

New commits:
commit a21d4794b6812ce05d08f06dc47b26c4fb1c1fef
Author: Jesse Barnes <jbarnes at jbarnes-t61.(none)>
Date:   Tue Aug 5 13:37:38 2008 -0700

    Reorganize VBIOS code
    
    Make VBT parsing happen at driver init time rather than in each output init
    function, to save time and better separate VBIOS code into i830_bios.[ch].  The
    changes end up touching the output files due to field name changes, and allow
    us to reorder & simplify our LFP mode detection code.

diff --git a/src/bios_reader/bios_reader.c b/src/bios_reader/bios_reader.c
index ffa27f0..dbcd150 100644
--- a/src/bios_reader/bios_reader.c
+++ b/src/bios_reader/bios_reader.c
@@ -25,11 +25,17 @@
  *
  */
 
+#include <errno.h>
+#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
 #include <sys/types.h>
 
+
 #include "../i830_bios.h"
 
 #define _PARSE_EDID_
@@ -51,108 +57,223 @@ struct _fake_i830 *pI830 = &I830;
 				 (pI830->VBIOS[_addr + 2] << 16) \
 				 (pI830->VBIOS[_addr + 3] << 24))
 
+#define YESNO(val) ((val) ? "yes" : "no")
+
+static int tv_present;
+static int lvds_present;
+static int panel_type;
+
+static void *find_section(struct bdb_header *bdb, int section_id)
+{
+	unsigned char *base = (unsigned char *)bdb;
+	int index = 0;
+	uint16_t total, current_size;
+	unsigned char current_id;
+
+	/* skip to first section */
+	index += bdb->header_size;
+	total = bdb->bdb_size;
+
+	/* walk the sections looking for section_id */
+	while (index < total) {
+		current_id = *(base + index);
+		index++;
+		current_size = *((uint16_t *)(base + index));
+		index += 2;
+		if (current_id == section_id)
+			return base + index;
+		index += current_size;
+	}
+
+	return NULL;
+}
+
+static void dump_general_features(void *data)
+{
+    struct bdb_general_features *features = data;
+
+    if (!data)
+	return;
+
+    printf("General features block:\n");
+
+    printf("\tPanel fitting: ");
+    switch (features->panel_fitting) {
+    case 0:
+	printf("disabled\n");
+	break;
+    case 1:
+	printf("text only\n");
+	break;
+    case 2:
+	printf("graphics only\n");
+	break;
+    case 3:
+	printf("text & graphics\n");
+	break;
+    }
+    printf("\tFlexaim: %s\n", YESNO(features->flexaim));
+    printf("\tMessage: %s\n", YESNO(features->msg_enable));
+    printf("\tClear screen: %d\n", features->clear_screen);
+    printf("\tDVO color flip required: %s\n", YESNO(features->color_flip));
+    printf("\tExternal VBT: %s\n", YESNO(features->download_ext_vbt));
+    printf("\tEnable SSC: %s\n", YESNO(features->enable_ssc));
+    if (features->enable_ssc)
+	printf("\tSSC frequency: %s\n", features->ssc_freq ?
+	       "100 MHz (66 MHz on 855)" : "96 MHz (48 MHz on 855)");
+    printf("\tLFP on override: %s\n", YESNO(features->enable_lfp_on_override));
+    printf("\tDisable SSC on clone: %s\n", YESNO(features->disable_ssc_ddt));
+    printf("\tDisable smooth vision: %s\n",
+	   YESNO(features->disable_smooth_vision));
+    printf("\tSingle DVI for CRT/DVI: %s\n", YESNO(features->single_dvi));
+    printf("\tLegacy monitor detect: %s\n",
+	   YESNO(features->legacy_monitor_detect));
+    printf("\tIntegrated CRT: %s\n", YESNO(features->int_crt_support));
+    printf("\tIntegrated TV: %s\n", YESNO(features->int_tv_support));
+
+    tv_present = 1; /* should be based on whether TV DAC exists */
+    lvds_present = 1; /* should be based on IS_MOBILE() */
+}
+
+static void dump_general_definitions(void *data)
+{
+    struct bdb_general_definitions *defs = data;
+    unsigned char *lvds_data = defs->tv_or_lvds_info;
+
+    if (!data)
+	return;
+
+    printf("General definitions block:\n");
+
+    printf("\tCRT DDC GMBUS addr: 0x%02x\n", defs->crt_ddc_gmbus_pin);
+    printf("\tUse ACPI DPMS CRT power states: %s\n", YESNO(defs->dpms_acpi));
+    printf("\tSkip CRT detect at boot: %s\n",
+	   YESNO(defs->skip_boot_crt_detect));
+    printf("\tUse DPMS on AIM devices: %s\n", YESNO(defs->dpms_aim));
+    printf("\tBoot display type: 0x%02x%02x\n", defs->boot_display[1],
+	   defs->boot_display[0]);
+    printf("\tTV data block present: %s\n", YESNO(tv_present));
+    if (tv_present)
+	lvds_data += 33;
+    if (lvds_present)
+	printf("\tLFP DDC GMBUS addr: 0x%02x\n", lvds_data[19]);
+}
+
+static void dump_lvds_options(void *data)
+{
+    struct bdb_lvds_options *options = data;
+
+    if (!data)
+	return;
+
+    printf("LVDS options block:\n");
+
+    panel_type = options->panel_type;
+    printf("\tPanel type: %d\n", panel_type);
+    printf("\tLVDS EDID available: %s\n", YESNO(options->lvds_edid));
+    printf("\tPixel dither: %s\n", YESNO(options->pixel_dither));
+    printf("\tPFIT auto ratio: %s\n", YESNO(options->pfit_ratio_auto));
+    printf("\tPFIT enhanced graphics mode: %s\n",
+	   YESNO(options->pfit_gfx_mode_enhanced));
+    printf("\tPFIT enhanced text mode: %s\n",
+	   YESNO(options->pfit_text_mode_enhanced));
+    printf("\tPFIT mode: %d\n", options->pfit_mode);
+}
+
+static void dump_lvds_data(void *data, unsigned char *base)
+{
+    struct bdb_lvds_lfp_data *lvds_data = data;
+    int i;
+
+    if (!data)
+	return;
+
+    printf("LVDS panel data block (preferred block marked with '*'):\n");
+
+    for (i = 0; i < 16; i++) {
+	struct bdb_lvds_lfp_data_entry *lfp_data = &lvds_data->data[i];
+	uint8_t *timing_data = (uint8_t *)&lfp_data->dvo_timing;
+	char marker;
+
+	if (i == panel_type)
+	    marker = '*';
+	else
+	    marker = ' ';
+
+	printf("%c\tpanel type %02i: %dx%d clock %d\n", marker,
+	       i, lfp_data->fp_timing.x_res, lfp_data->fp_timing.y_res,
+	       _PIXEL_CLOCK(timing_data));
+	printf("\t\ttimings: %d %d %d %d %d %d %d %d\n",
+	       _H_ACTIVE(timing_data),
+	       _H_BLANK(timing_data),
+	       _H_SYNC_OFF(timing_data),
+	       _H_SYNC_WIDTH(timing_data),
+	       _V_ACTIVE(timing_data),
+	       _V_BLANK(timing_data),
+	       _V_SYNC_OFF(timing_data),
+	       _V_SYNC_WIDTH(timing_data));
+    }
+
+}
+
 int main(int argc, char **argv)
 {
-    FILE *f;
-    int bios_size = 65536;
-    struct vbt_header *vbt;
+    int fd;
+    struct vbt_header *vbt = NULL;
     struct bdb_header *bdb;
-    int vbt_off, bdb_off, bdb_block_off, block_size;
-    int panel_type = -1, i;
+    int vbt_off, bdb_off, i;
     char *filename = "bios";
+    struct stat finfo;
 
-    if (argc == 2)
-	filename = argv[1];
+    if (argc != 2) {
+	printf("usage: %s <rom file>\n", argv[0]);
+	return 1;
+    }
+	
+    filename = argv[1];
 
-    f = fopen(filename, "r");
-    if (!f) {
-	printf("Couldn't open %s\n", filename);
+    fd = open(filename, O_RDONLY);
+    if (fd == -1) {
+	printf("Couldn't open \"%s\": %s\n", filename, strerror(errno));
 	return 1;
     }
 
-    pI830->VBIOS = calloc(1, bios_size);
-    if (fread(pI830->VBIOS, 1, bios_size, f) != bios_size)
+    if (stat(filename, &finfo)) {
+	printf("failed to stat \"%s\": %s\n", filename, strerror(errno));
 	return 1;
+    }
+
+    pI830->VBIOS = mmap(NULL, finfo.st_size, PROT_READ, MAP_SHARED, fd, 0);
+    if (pI830->VBIOS == MAP_FAILED) {
+	printf("failed to map \"%s\": %s\n", filename, strerror(errno));
+	return 1;
+    }
+
+    /* Scour memory looking for the VBT signature */
+    for (i = 0; i + 4 < finfo.st_size; i++) {
+	if (!memcmp(pI830->VBIOS + i, "$VBT", 4)) {
+	    vbt_off = i;
+	    vbt = (struct vbt_header *)(pI830->VBIOS + i);
+	    break;
+	}
+    }
+
+    if (!vbt) {
+	printf("VBT signature missing\n");
+	return 1;
+    }
 
-    vbt_off = INTEL_BIOS_16(0x1a);
-    printf("VBT offset: %08x\n", vbt_off);
-    vbt = (struct vbt_header *)(pI830->VBIOS + vbt_off);
-    printf("VBT sig: %20s\n", vbt->signature);
     printf("VBT vers: %d.%d\n", vbt->version / 100, vbt->version % 100);
 
     bdb_off = vbt_off + vbt->bdb_offset;
     bdb = (struct bdb_header *)(pI830->VBIOS + bdb_off);
     printf("BDB sig: %16s\n", bdb->signature);
     printf("BDB vers: %d.%d\n", bdb->version / 100, bdb->version % 100);
-    for (bdb_block_off = bdb->header_size; bdb_block_off < bdb->bdb_size;
-	 bdb_block_off += block_size)
-    {
-	int start = bdb_off + bdb_block_off;
-	int id;
-	struct lvds_bdb_1 *lvds1;
-	struct lvds_bdb_2 *lvds2;
-	struct lvds_bdb_2_fp_params *fpparam;
-	struct lvds_bdb_2_fp_edid_dtd *fptiming;
-	uint8_t *timing_ptr;
-
-	id = INTEL_BIOS_8(start);
-	block_size = INTEL_BIOS_16(start + 1) + 3;
-	printf("BDB block type %03d size %d\n", id, block_size);
-	switch (id) {
-	case 40:
-	    lvds1 = (struct lvds_bdb_1 *)(pI830->VBIOS + start);
-	    panel_type = lvds1->panel_type;
-	    printf("Panel type: %d, caps %04x\n", panel_type, lvds1->caps);
-	    break;
-	case 41:
-	    if (panel_type == -1) {
-		printf("Found panel block with no panel type\n");
-		break;
-	    }
-
-	    lvds2 = (struct lvds_bdb_2 *)(pI830->VBIOS + start);
-
-	    printf("Entries per table: %d\n", lvds2->table_size);
-	    for (i = 0; i < 16; i++) {
-		char marker;
-		fpparam = (struct lvds_bdb_2_fp_params *)(pI830->VBIOS +
-		    bdb_off + lvds2->panels[i].fp_params_offset);
-		fptiming = (struct lvds_bdb_2_fp_edid_dtd *)(pI830->VBIOS +
-		    bdb_off + lvds2->panels[i].fp_edid_dtd_offset);
-		timing_ptr = pI830->VBIOS + bdb_off +
-		    lvds2->panels[i].fp_edid_dtd_offset;
-		if (fpparam->terminator != 0xffff) {
-		    /* Apparently the offsets are wrong for some BIOSes, so we
-		     * try the other offsets if we find a bad terminator.
-		     */
-		    fpparam = (struct lvds_bdb_2_fp_params *)(pI830->VBIOS +
-			bdb_off + lvds2->panels[i].fp_params_offset + 8);
-		    fptiming = (struct lvds_bdb_2_fp_edid_dtd *)(pI830->VBIOS +
-			bdb_off + lvds2->panels[i].fp_edid_dtd_offset + 8);
-		    timing_ptr = pI830->VBIOS + bdb_off +
-			lvds2->panels[i].fp_edid_dtd_offset + 8;
-
-		    if (fpparam->terminator != 0xffff)
-			continue;
-		}
-		if (i == panel_type)
-		    marker = '*';
-		else
-		    marker = ' ';
-		printf("%c Panel index %02i xres %d yres %d clock %d\n", marker,
-		       i, fpparam->x_res, fpparam->y_res,
-		       _PIXEL_CLOCK(timing_ptr));
-		printf("        %d %d %d %d %d %d %d %d\n",
-		       _H_ACTIVE(timing_ptr), _H_BLANK(timing_ptr),
-		       _H_SYNC_OFF(timing_ptr), _H_SYNC_WIDTH(timing_ptr),
-		       _V_ACTIVE(timing_ptr), _V_BLANK(timing_ptr),
-		       _V_SYNC_OFF(timing_ptr), _V_SYNC_WIDTH(timing_ptr));
-	    }
-
-	    printf("Panel of size %dx%d\n", fpparam->x_res, fpparam->y_res);
-	    break;
-	}
-    }
+
+    dump_general_features(find_section(bdb, BDB_GENERAL_FEATURES));
+    dump_general_definitions(find_section(bdb, BDB_GENERAL_DEFINITIONS));
+    dump_lvds_options(find_section(bdb, BDB_LVDS_OPTIONS));
+    dump_lvds_data(find_section(bdb, BDB_LVDS_LFP_DATA), bdb);
 
     return 0;
 }
diff --git a/src/i830.h b/src/i830.h
index 68690f7..6a5de6b 100644
--- a/src/i830.h
+++ b/src/i830.h
@@ -251,8 +251,6 @@ struct _I830DVODriver {
    I830I2CVidOutputRec *vid_rec;
    void *dev_priv;
    pointer modhandle;
-   DisplayModePtr panel_fixed_mode;
-   Bool panel_wants_dither;
 };
 
 extern const char *i830_output_type_names[];
@@ -556,6 +554,9 @@ typedef struct _I830Rec {
    Bool lvds_24_bit_mode;
    Bool lvds_use_ssc;
    int lvds_ssc_freq; /* in MHz */
+   Bool lvds_dither;
+   DisplayModePtr lvds_fixed_mode;
+   Bool skip_panel_detect;
 
    Bool tv_present; /* TV connector present (from VBIOS) */
 
@@ -663,7 +664,6 @@ typedef struct _I830Rec {
 
    /** Enables logging of debug output related to mode switching. */
    Bool debug_modes;
-   Bool lvds_fixed_mode;
    unsigned int quirk_flag;
 } I830Rec;
 
diff --git a/src/i830_bios.c b/src/i830_bios.c
index a8193fc..fe55d23 100644
--- a/src/i830_bios.c
+++ b/src/i830_bios.c
@@ -40,84 +40,152 @@
 #include "edid.h"
 
 #define INTEL_BIOS_8(_addr)	(bios[_addr])
-#define INTEL_BIOS_16(_addr)	(bios[_addr] | \
+#define INTEL_BIOS_16(_addr)	(bios[_addr] |			\
 				 (bios[_addr + 1] << 8))
-#define INTEL_BIOS_32(_addr)	(bios[_addr] | \
-				 (bios[_addr + 1] << 8) \
-				 (bios[_addr + 2] << 16) \
+#define INTEL_BIOS_32(_addr)	(bios[_addr] |			\
+				 (bios[_addr + 1] << 8)		\
+				 (bios[_addr + 2] << 16)	\
 				 (bios[_addr + 3] << 24))
 
 /* XXX */
 #define INTEL_VBIOS_SIZE (64 * 1024)
 
+static void *
+find_section(struct bdb_header *bdb, int section_id)
+{
+    unsigned char *base = (unsigned char *)bdb;
+    int index = 0;
+    uint16_t total, current_size;
+    unsigned char current_id;
+
+    /* skip to first section */
+    index += bdb->header_size;
+    total = bdb->bdb_size;
+
+    /* walk the sections looking for section_id */
+    while (index < total) {
+	current_id = *(base + index);
+	index++;
+	current_size = *((uint16_t *)(base + index));
+	index += 2;
+	if (current_id == section_id)
+	    return base + index;
+	index += current_size;
+    }
+
+    return NULL;
+}
+
+/**
+ * Returns the BIOS's fixed panel mode.
+ *
+ * Note that many BIOSes will have the appropriate tables for a panel even when
+ * a panel is not attached.  Additionally, many BIOSes adjust table sizes or
+ * offsets, such that this parsing fails.  Thus, almost any other method for
+ * detecting the panel mode is preferable.
+ */
 static void
-i830DumpBIOSToFile(ScrnInfoPtr pScrn, unsigned char *bios)
+parse_panel_data(I830Ptr pI830, struct bdb_header *bdb)
 {
-    const char *filename = "/tmp/xf86-video-intel-VBIOS";
-    FILE *f;
+    struct bdb_lvds_options *lvds_options;
+    struct bdb_lvds_lfp_data *lvds_lfp_data;
+    struct bdb_lvds_lfp_data_entry *entry;
+    DisplayModePtr fixed_mode;
+    unsigned char *timing_ptr;
 
-    f = fopen(filename, "w");
-    if (f == NULL) {
-	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Couldn't open %s\n", filename);
+    /* Defaults if we can't find VBT info */
+    pI830->lvds_dither = 0;
+
+    lvds_options = find_section(bdb, BDB_LVDS_OPTIONS);
+    if (!lvds_options)
+	return;
+
+    pI830->lvds_dither = lvds_options->pixel_dither;
+    if (lvds_options->panel_type == 0xff)
+	return;
+
+    lvds_lfp_data = find_section(bdb, BDB_LVDS_LFP_DATA);
+    if (!lvds_lfp_data)
 	return;
-    }
-    if (fwrite(bios, INTEL_VBIOS_SIZE, 1, f) != 1) {
-	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Couldn't write BIOS data\n");
-    }
 
-    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Wrote BIOS contents to %s\n",
-	       filename);
-    fclose(f);
+    entry = &lvds_lfp_data->data[lvds_options->panel_type];
+    timing_ptr = (unsigned char *)&entry->dvo_timing;
+
+    fixed_mode = xnfalloc(sizeof(DisplayModeRec));
+    memset(fixed_mode, 0, sizeof(*fixed_mode));
+
+    /* Since lvds_bdb_2_fp_edid_dtd is just an EDID detailed timing
+     * block, pull the contents out using EDID macros.
+     */
+    fixed_mode->HDisplay   = _H_ACTIVE(timing_ptr);
+    fixed_mode->VDisplay   = _V_ACTIVE(timing_ptr);
+    fixed_mode->HSyncStart = fixed_mode->HDisplay +
+	_H_SYNC_OFF(timing_ptr);
+    fixed_mode->HSyncEnd   = fixed_mode->HSyncStart +
+	_H_SYNC_WIDTH(timing_ptr);
+    fixed_mode->HTotal     = fixed_mode->HDisplay +
+	_H_BLANK(timing_ptr);
+    fixed_mode->VSyncStart = fixed_mode->VDisplay +
+	_V_SYNC_OFF(timing_ptr);
+    fixed_mode->VSyncEnd   = fixed_mode->VSyncStart +
+	_V_SYNC_WIDTH(timing_ptr);
+    fixed_mode->VTotal     = fixed_mode->VDisplay +
+	_V_BLANK(timing_ptr);
+    fixed_mode->Clock      = _PIXEL_CLOCK(timing_ptr) / 1000;
+    fixed_mode->type       = M_T_PREFERRED;
+
+    xf86SetModeDefaultName(fixed_mode);
+
+    pI830->lvds_fixed_mode = fixed_mode;
 }
 
-static void *
-find_section(struct bdb_header *bdb, int section_id)
+static void
+parse_general_features(I830Ptr pI830, struct bdb_header *bdb)
 {
-	unsigned char *base = (unsigned char *)bdb;
-	int index = 0;
-	uint16_t total, current_size;
-	unsigned char current_id;
-
-	/* skip to first section */
-	index += bdb->header_size;
-	total = bdb->bdb_size;
-
-	/* walk the sections looking for section_id */
-	while (index < total) {
-		current_id = *(base + index);
-		index++;
-		current_size = *((uint16_t *)(base + index));
-		index += 2;
-		if (current_id == section_id)
-			return base + index;
-		index += current_size;
-	}
-
-	return NULL;
+    struct bdb_general_features *general;
+
+    /* Set sensible defaults in case we can't find the general block */
+    pI830->tv_present = 1;
+
+    general = find_section(bdb, BDB_GENERAL_FEATURES);
+    if (!general)
+	return;
+
+    pI830->tv_present = general->int_tv_support;
+    pI830->lvds_use_ssc = general->enable_ssc;
+    if (pI830->lvds_use_ssc) {
+	if (IS_I855(pI830))
+	    pI830->lvds_ssc_freq = general->ssc_freq ? 66 : 48;
+	else
+	    pI830->lvds_ssc_freq = general->ssc_freq ? 100 : 96;
+    }
 }
 
 /**
- * Loads the Video BIOS and checks that the VBT exists.
+ * i830_bios_init - map VBIOS, find VBT
  *
  * VBT existence is a sanity check that is relied on by other i830_bios.c code.
  * Note that it would be better to use a BIOS call to get the VBT, as BIOSes may
  * feed an updated VBT back through that, compared to what we'll fetch using
  * this method of groping around in the BIOS data.
+ *
+ * Returns 0 on success, nonzero on failure.
  */
-unsigned char *
-i830_bios_get (ScrnInfoPtr pScrn)
+int
+i830_bios_init(ScrnInfoPtr pScrn)
 {
     I830Ptr pI830 = I830PTR(pScrn);
     struct vbt_header *vbt;
-    int vbt_off;
+    struct bdb_header *bdb;
+    int vbt_off, bdb_off;
     unsigned char *bios;
     vbeInfoPtr	pVbe;
 
     bios = xalloc(INTEL_VBIOS_SIZE);
     if (bios == NULL)
-	return NULL;
+	return -1;
 
-    pVbe = VBEInit (NULL, pI830->pEnt->index);
+    pVbe = VBEInit(NULL, pI830->pEnt->index);
     if (pVbe != NULL) {
 	memcpy(bios, xf86int10Addr(pVbe->pInt10,
 				   pVbe->pInt10->BIOSseg << 4),
@@ -131,15 +199,12 @@ i830_bios_get (ScrnInfoPtr pScrn)
 #endif
     }
 
-    if (0)
-	i830DumpBIOSToFile(pScrn, bios);
-
     vbt_off = INTEL_BIOS_16(0x1a);
     if (vbt_off >= INTEL_VBIOS_SIZE) {
 	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Bad VBT offset: 0x%x\n",
 		   vbt_off);
 	xfree(bios);
-	return NULL;
+	return -1;
     }
 
     vbt = (struct vbt_header *)(bios + vbt_off);
@@ -147,243 +212,17 @@ i830_bios_get (ScrnInfoPtr pScrn)
     if (memcmp(vbt->signature, "$VBT", 4) != 0) {
 	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Bad VBT signature\n");
 	xfree(bios);
-	return NULL;
+	return -1;
     }
 
-    return bios;
-}
-
-void
-i830_bios_get_ssc(ScrnInfoPtr pScrn)
-{
-    I830Ptr pI830 = I830PTR(pScrn);
-    struct vbt_header *vbt;
-    struct bdb_header *bdb;
-    struct bdb_general_features *bdb_features;
-    int vbt_off, bdb_off;
-    unsigned char *bios;
-
-    bios = i830_bios_get(pScrn);
-
-    if (bios == NULL)
-	return;
-
-    vbt_off = INTEL_BIOS_16(0x1a);
-    vbt = (struct vbt_header *)(bios + vbt_off);
+    /* Now that we've found the VBIOS, go scour the VBTs */
     bdb_off = vbt_off + vbt->bdb_offset;
     bdb = (struct bdb_header *)(bios + bdb_off);
 
-    bdb_features = find_section(bdb, BDB_GENERAL_FEATURES);
-    if (!bdb_features)
-	return;
-
-    pI830->lvds_use_ssc = bdb_features->enable_ssc;
-    if (pI830->lvds_use_ssc) {
-	if (IS_I855(pI830))
-	    pI830->lvds_ssc_freq = bdb_features->ssc_freq ? 66 : 48;
-	else
-	    pI830->lvds_ssc_freq = bdb_features->ssc_freq ? 100 : 96;
-    }
+    parse_general_features(pI830, bdb);
+    parse_panel_data(pI830, bdb);
 
     xfree(bios);
-}
 
-void
-i830_bios_get_tv(ScrnInfoPtr pScrn)
-{
-    I830Ptr pI830 = I830PTR(pScrn);
-    struct vbt_header *vbt;
-    struct bdb_header *bdb;
-    struct bdb_general_features *bdb_features;
-    int vbt_off, bdb_off;
-    unsigned char *bios;
-
-    bios = i830_bios_get(pScrn);
-
-    if (bios == NULL)
-	return;
-
-    vbt_off = INTEL_BIOS_16(0x1a);
-    vbt = (struct vbt_header *)(bios + vbt_off);
-    bdb_off = vbt_off + vbt->bdb_offset;
-    bdb = (struct bdb_header *)(bios + bdb_off);
-
-    bdb_features = find_section(bdb, BDB_GENERAL_FEATURES);
-    if (!bdb_features)
-	return;
-
-    pI830->tv_present = bdb_features->int_tv_support;
-
-    xfree(bios);
-}
-
-/**
- * Returns the BIOS's fixed panel mode.
- *
- * Note that many BIOSes will have the appropriate tables for a panel even when
- * a panel is not attached.  Additionally, many BIOSes adjust table sizes or
- * offsets, such that this parsing fails.  Thus, almost any other method for
- * detecting the panel mode is preferable.
- */
-DisplayModePtr
-i830_bios_get_panel_mode(ScrnInfoPtr pScrn, Bool *wants_dither)
-{
-    I830Ptr pI830 = I830PTR(pScrn);
-    struct vbt_header *vbt;
-    struct bdb_header *bdb;
-    int vbt_off, bdb_off, bdb_block_off, block_size;
-    int panel_type = -1;
-    unsigned char *bios;
-
-    bios = i830_bios_get (pScrn);
-
-    if (bios == NULL)
-	return NULL;
-
-    vbt_off = INTEL_BIOS_16(0x1a);
-    vbt = (struct vbt_header *)(bios + vbt_off);
-    bdb_off = vbt_off + vbt->bdb_offset;
-    bdb = (struct bdb_header *)(bios + bdb_off);
-
-    if (memcmp(bdb->signature, "BIOS_DATA_BLOCK ", 16) != 0) {
-	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Bad BDB signature\n");
-	xfree(bios);
-	return NULL;
-    }
-
-    *wants_dither = FALSE;
-    for (bdb_block_off = bdb->header_size; bdb_block_off < bdb->bdb_size;
-	 bdb_block_off += block_size)
-    {
-	int start = bdb_off + bdb_block_off;
-	int id;
-	struct lvds_bdb_1 *lvds1;
-	struct lvds_bdb_2 *lvds2;
-	struct lvds_bdb_2_fp_params *fpparam;
-	struct lvds_bdb_2_fp_edid_dtd *fptiming;
-	DisplayModePtr fixed_mode;
-	uint8_t *timing_ptr;
-
-	id = INTEL_BIOS_8(start);
-	block_size = INTEL_BIOS_16(start + 1) + 3;
-	switch (id) {
-	case 40:
-	    lvds1 = (struct lvds_bdb_1 *)(bios + start);
-	    panel_type = lvds1->panel_type;
-	    if (lvds1->caps & LVDS_CAP_DITHER)
-		*wants_dither = TRUE;
-	    break;
-	case 41:
-	    if (panel_type == -1)
-		break;
-
-	    lvds2 = (struct lvds_bdb_2 *)(bios + start);
-	    fpparam = (struct lvds_bdb_2_fp_params *)(bios +
-		bdb_off + lvds2->panels[panel_type].fp_params_offset);
-	    fptiming = (struct lvds_bdb_2_fp_edid_dtd *)(bios +
-		bdb_off + lvds2->panels[panel_type].fp_edid_dtd_offset);
-	    timing_ptr = bios + bdb_off +
-	        lvds2->panels[panel_type].fp_edid_dtd_offset;
-
-	    if (fpparam->terminator != 0xffff) {
-		/* Apparently the offsets are wrong for some BIOSes, so we
-		 * try the other offsets if we find a bad terminator.
-		 */
-		fpparam = (struct lvds_bdb_2_fp_params *)(bios +
-		    bdb_off + lvds2->panels[panel_type].fp_params_offset + 8);
-		fptiming = (struct lvds_bdb_2_fp_edid_dtd *)(bios +
-		    bdb_off + lvds2->panels[panel_type].fp_edid_dtd_offset + 8);
-		timing_ptr = bios + bdb_off +
-	            lvds2->panels[panel_type].fp_edid_dtd_offset + 8;
-
-		if (fpparam->terminator != 0xffff)
-		    continue;
-	    }
-
-	    fixed_mode = xnfalloc(sizeof(DisplayModeRec));
-	    memset(fixed_mode, 0, sizeof(*fixed_mode));
-
-	    /* Since lvds_bdb_2_fp_edid_dtd is just an EDID detailed timing
-	     * block, pull the contents out using EDID macros.
-	     */
-	    fixed_mode->HDisplay   = _H_ACTIVE(timing_ptr);
-	    fixed_mode->VDisplay   = _V_ACTIVE(timing_ptr);
-	    fixed_mode->HSyncStart = fixed_mode->HDisplay +
-		_H_SYNC_OFF(timing_ptr);
-	    fixed_mode->HSyncEnd   = fixed_mode->HSyncStart +
-		_H_SYNC_WIDTH(timing_ptr);
-	    fixed_mode->HTotal     = fixed_mode->HDisplay +
-	        _H_BLANK(timing_ptr);
-	    fixed_mode->VSyncStart = fixed_mode->VDisplay +
-		_V_SYNC_OFF(timing_ptr);
-	    fixed_mode->VSyncEnd   = fixed_mode->VSyncStart +
-		_V_SYNC_WIDTH(timing_ptr);
-	    fixed_mode->VTotal     = fixed_mode->VDisplay +
-	        _V_BLANK(timing_ptr);
-	    fixed_mode->Clock      = _PIXEL_CLOCK(timing_ptr) / 1000;
-	    fixed_mode->type       = M_T_PREFERRED;
-
-	    xf86SetModeDefaultName(fixed_mode);
-
-	    if (pI830->debug_modes) {
-		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
-			   "Found panel mode in BIOS VBT tables:\n");
-		xf86PrintModeline(pScrn->scrnIndex, fixed_mode);
-	    }
-
-	    xfree(bios);
-	    return fixed_mode;
-	}
-    }
-
-    xfree(bios);
-    return NULL;
-}
-
-unsigned char *
-i830_bios_get_aim_data_block (ScrnInfoPtr pScrn, int aim, int data_block)
-{
-    unsigned char   *bios;
-    int		    bdb_off;
-    int		    vbt_off;
-    int		    aim_off;
-    struct vbt_header *vbt;
-    struct aimdb_header *aimdb;
-    struct aimdb_block *aimdb_block;
-
-    bios = i830_bios_get (pScrn);
-    if (!bios)
-	return NULL;
-
-    vbt_off = INTEL_BIOS_16(0x1a);
-    vbt = (struct vbt_header *)(bios + vbt_off);
-
-    aim_off = vbt->aim_offset[aim];
-    if (!aim_off)
-    {
-	free (bios);
-	return NULL;
-    }
-    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "aim_off %d\n", aim_off);
-    aimdb = (struct aimdb_header *) (bios + vbt_off + aim_off);
-    bdb_off = aimdb->aimdb_header_size;
-    while (bdb_off < aimdb->aimdb_size)
-    {
-	aimdb_block = (struct aimdb_block *) (bios + vbt_off + aim_off + bdb_off);
-	if (aimdb_block->aimdb_id == data_block)
-	{
-	    unsigned char   *aim = malloc (aimdb_block->aimdb_size + sizeof (struct aimdb_block));
-	    if (!aim)
-	    {
-		free (bios);
-		return NULL;
-	    }
-	    memcpy (aim, aimdb_block, aimdb_block->aimdb_size + sizeof (struct aimdb_block));
-	    free (bios);
-	    return aim;
-	}
-	bdb_off += aimdb_block->aimdb_size + sizeof (struct aimdb_block);
-    }
-    free (bios);
-    return NULL;
+    return 0;
 }
diff --git a/src/i830_bios.h b/src/i830_bios.h
index c1ba50d..a8d9add 100644
--- a/src/i830_bios.h
+++ b/src/i830_bios.h
@@ -147,15 +147,22 @@ struct bdb_general_definitions {
 #define LVDS_CAP_PFIT_TEXT_MODE		(1 << 2)
 #define LVDS_CAP_PFIT_GRAPHICS		(1 << 1)
 #define LVDS_CAP_PFIT_TEXT		(1 << 0)
-struct lvds_bdb_1 {
-    uint8_t id;				/**< 40 */
-    uint16_t size;
+
+struct bdb_lvds_options {
     uint8_t panel_type;
-    uint8_t reserved0;
-    uint16_t caps;
+    uint8_t rsvd1;
+    /* LVDS capabilities, stored in a dword */
+    uint8_t rsvd2:1;
+    uint8_t lvds_edid:1;
+    uint8_t pixel_dither:1;
+    uint8_t pfit_ratio_auto:1;
+    uint8_t pfit_gfx_mode_enhanced:1;
+    uint8_t pfit_text_mode_enhanced:1;
+    uint8_t pfit_mode:2;
+    uint8_t rsvd4;
 } __attribute__((packed));
 
-struct lvds_bdb_2_fp_params {
+struct lvds_fp_timing {
     uint16_t x_res;
     uint16_t y_res;
     uint32_t lvds_reg;
@@ -171,7 +178,7 @@ struct lvds_bdb_2_fp_params {
     uint16_t terminator;
 } __attribute__((packed));
 
-struct lvds_bdb_2_fp_edid_dtd {
+struct lvds_dvo_timing {
     uint16_t dclk;		/**< In 10khz */
     uint8_t hactive;
     uint8_t hblank;
@@ -193,20 +200,37 @@ struct lvds_bdb_2_fp_edid_dtd {
 #define FP_EDID_FLAG_HSYNC_POSITIVE	(1 << 1)
 } __attribute__((packed));
 
-struct lvds_bdb_2_entry {
-    uint16_t fp_params_offset;		/**< From beginning of BDB */
-    uint8_t fp_params_size;
-    uint16_t fp_edid_dtd_offset;
-    uint8_t fp_edid_dtd_size;
-    uint16_t fp_edid_pid_offset;
-    uint8_t fp_edid_pid_size;
+struct lvds_pnp_id {
+    uint16_t mfg_name;
+    uint16_t product_code;
+    uint32_t serial;
+    uint8_t mfg_week;
+    uint8_t mfg_year;
+} __attribute__((packed));;
+
+/* LFP pointer table contains entries to the struct below */
+struct bdb_lvds_lfp_data_ptr {
+    uint16_t fp_timing_offset; /* offsets are from start of bdb */
+    uint8_t fp_table_size;
+    uint16_t dvo_timing_offset;
+    uint8_t dvo_table_size;
+    uint16_t panel_pnp_id_offset;
+    uint8_t pnp_table_size;
+} __attribute__((packed));
+
+struct bdb_lvds_lfp_data_ptrs {
+    uint8_t lvds_entries;
+    struct bdb_lvds_lfp_data_ptr ptr[16];
 } __attribute__((packed));
 
-struct lvds_bdb_2 {
-    uint8_t id;			/**< 41 */
-    uint16_t size;
-    uint8_t table_size;	/* not sure on this one */
-    struct lvds_bdb_2_entry panels[16];
+struct bdb_lvds_lfp_data_entry {
+    struct lvds_fp_timing fp_timing;
+    struct lvds_dvo_timing dvo_timing;
+    struct lvds_pnp_id pnp_id;
+} __attribute__((packed));
+
+struct bdb_lvds_lfp_data {
+    struct bdb_lvds_lfp_data_entry data[16];
 } __attribute__((packed));
 
 struct aimdb_header {
@@ -238,14 +262,6 @@ struct vch_bdb_22 {
     struct vch_panel_data   panels[16];
 } __attribute__((packed));
 
-unsigned char *
-i830_bios_get (ScrnInfoPtr pScrn);
-
-void i830_bios_get_ssc(ScrnInfoPtr pScrn);
-void i830_bios_get_tv(ScrnInfoPtr pScrn);
-DisplayModePtr i830_bios_get_panel_mode(ScrnInfoPtr pScrn, Bool *wants_dither);
-
-unsigned char *
-i830_bios_get_aim_data_block (ScrnInfoPtr pScrn, int aim, int data_block);
+int i830_bios_init(ScrnInfoPtr pScrn);
 
 #endif /* _I830_BIOS_H_ */
diff --git a/src/i830_driver.c b/src/i830_driver.c
index f5aa114..79a4359 100644
--- a/src/i830_driver.c
+++ b/src/i830_driver.c
@@ -1503,9 +1503,9 @@ I830PreInit(ScrnInfoPtr pScrn, int flags)
    }
 
    if (xf86ReturnOptValBool(pI830->Options, OPTION_LVDSFIXEDMODE, TRUE)) {
-      pI830->lvds_fixed_mode = TRUE;
+      pI830->skip_panel_detect = TRUE;
    } else {
-      pI830->lvds_fixed_mode = FALSE;
+      pI830->skip_panel_detect = FALSE;
    }
 
    if (xf86ReturnOptValBool(pI830->Options, OPTION_FORCEENABLEPIPEA, FALSE))
@@ -1635,6 +1635,10 @@ I830PreInit(ScrnInfoPtr pScrn, int flags)
    
 #endif
 
+   if (i830_bios_init(pScrn))
+      xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+		 "VBIOS initialization failed.\n");
+
    I830PreInitDDC(pScrn);
    for (i = 0; i < num_pipe; i++) {
        i830_crtc_init(pScrn, i);
diff --git a/src/i830_dvo.c b/src/i830_dvo.c
index 9e82171..832c762 100644
--- a/src/i830_dvo.c
+++ b/src/i830_dvo.c
@@ -165,8 +165,9 @@ i830_dvo_restore(xf86OutputPtr output)
 static int
 i830_dvo_mode_valid(xf86OutputPtr output, DisplayModePtr pMode)
 {
+    ScrnInfoPtr		    pScrn = output->scrn;
+    I830Ptr		    pI830 = I830PTR(pScrn);
     I830OutputPrivatePtr    intel_output = output->driver_private;
-    struct _I830DVODriver   *drv = intel_output->i2c_drv;
     void		    *dev_priv = intel_output->i2c_drv->dev_priv;
 
     if (pMode->Flags & V_DBLSCAN)
@@ -174,10 +175,10 @@ i830_dvo_mode_valid(xf86OutputPtr output, DisplayModePtr pMode)
 
     /* XXX: Validate clock range */
 
-    if (drv->panel_fixed_mode) {
-	if (pMode->HDisplay > drv->panel_fixed_mode->HDisplay)
+    if (pI830->lvds_fixed_mode) {
+	if (pMode->HDisplay > pI830->lvds_fixed_mode->HDisplay)
 	    return MODE_PANEL;
-	if (pMode->VDisplay > drv->panel_fixed_mode->VDisplay)
+	if (pMode->VDisplay > pI830->lvds_fixed_mode->VDisplay)
 	    return MODE_PANEL;
     }
 
@@ -188,24 +189,25 @@ static Bool
 i830_dvo_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
 		    DisplayModePtr adjusted_mode)
 {
+    ScrnInfoPtr		    pScrn = output->scrn;
+    I830Ptr		    pI830 = I830PTR(pScrn);
     I830OutputPrivatePtr    intel_output = output->driver_private;
-    struct _I830DVODriver   *drv = intel_output->i2c_drv;
 
     /* If we have timings from the BIOS for the panel, put them in
      * to the adjusted mode.  The CRTC will be set up for this mode,
      * with the panel scaling set up to source from the H/VDisplay
      * of the original mode.
      */
-    if (drv->panel_fixed_mode != NULL) {
-	adjusted_mode->HDisplay = drv->panel_fixed_mode->HDisplay;
-	adjusted_mode->HSyncStart = drv->panel_fixed_mode->HSyncStart;
-	adjusted_mode->HSyncEnd = drv->panel_fixed_mode->HSyncEnd;
-	adjusted_mode->HTotal = drv->panel_fixed_mode->HTotal;
-	adjusted_mode->VDisplay = drv->panel_fixed_mode->VDisplay;
-	adjusted_mode->VSyncStart = drv->panel_fixed_mode->VSyncStart;
-	adjusted_mode->VSyncEnd = drv->panel_fixed_mode->VSyncEnd;
-	adjusted_mode->VTotal = drv->panel_fixed_mode->VTotal;
-	adjusted_mode->Clock = drv->panel_fixed_mode->Clock;
+    if (pI830->lvds_fixed_mode != NULL) {
+	adjusted_mode->HDisplay = pI830->lvds_fixed_mode->HDisplay;
+	adjusted_mode->HSyncStart = pI830->lvds_fixed_mode->HSyncStart;
+	adjusted_mode->HSyncEnd = pI830->lvds_fixed_mode->HSyncEnd;
+	adjusted_mode->HTotal = pI830->lvds_fixed_mode->HTotal;
+	adjusted_mode->VDisplay = pI830->lvds_fixed_mode->VDisplay;
+	adjusted_mode->VSyncStart = pI830->lvds_fixed_mode->VSyncStart;
+	adjusted_mode->VSyncEnd = pI830->lvds_fixed_mode->VSyncEnd;
+	adjusted_mode->VTotal = pI830->lvds_fixed_mode->VTotal;
+	adjusted_mode->Clock = pI830->lvds_fixed_mode->Clock;
 	xf86SetModeCrtc(adjusted_mode, INTERLACE_HALVE_V);
     }
 
@@ -287,8 +289,9 @@ i830_dvo_detect(xf86OutputPtr output)
 static DisplayModePtr
 i830_dvo_get_modes(xf86OutputPtr output)
 {
+    ScrnInfoPtr	pScrn = output->scrn;
+    I830Ptr pI830 = I830PTR(pScrn);
     I830OutputPrivatePtr    intel_output = output->driver_private;
-    struct _I830DVODriver   *drv = intel_output->i2c_drv;
     DisplayModePtr	    modes;
 
     /* We should probably have an i2c driver get_modes function for those
@@ -307,8 +310,8 @@ i830_dvo_get_modes(xf86OutputPtr output)
 	    return modes;
     }
 
-    if (drv->panel_fixed_mode != NULL)
-	return xf86DuplicateMode(drv->panel_fixed_mode);
+    if (pI830->lvds_fixed_mode != NULL)
+	return xf86DuplicateMode(pI830->lvds_fixed_mode);
 
     return NULL;
 }
@@ -530,8 +533,8 @@ i830_dvo_init(ScrnInfoPtr pScrn)
 		 * so for now, just get the current mode being output through
 		 * DVO.
 		 */
-		drv->panel_fixed_mode = i830_dvo_get_current_mode(output);
-		drv->panel_wants_dither = TRUE;
+		pI830->lvds_fixed_mode = i830_dvo_get_current_mode(output);
+		pI830->lvds_dither = TRUE;
 	    }
 
 	    return;
diff --git a/src/i830_lvds.c b/src/i830_lvds.c
index c7f2434..9f20579 100644
--- a/src/i830_lvds.c
+++ b/src/i830_lvds.c
@@ -57,12 +57,6 @@ enum pfit_mode {
 };
 
 struct i830_lvds_priv {
-    /* The BIOS's fixed timings for the LVDS */
-    DisplayModePtr panel_fixed_mode;
-    
-    /* The panel needs dithering enabled */
-    Bool	    panel_wants_dither;
-
     /* The panel is in DPMS off */
     Bool           dpmsoff;
 
@@ -486,9 +480,9 @@ i830_lvds_restore(xf86OutputPtr output)
 static int
 i830_lvds_mode_valid(xf86OutputPtr output, DisplayModePtr pMode)
 {
-    I830OutputPrivatePtr    intel_output = output->driver_private;
-    struct i830_lvds_priv   *dev_priv = intel_output->dev_priv;
-    DisplayModePtr	    pFixedMode = dev_priv->panel_fixed_mode;
+    ScrnInfoPtr	pScrn = output->scrn;
+    I830Ptr	pI830 = I830PTR(pScrn);
+    DisplayModePtr	    pFixedMode = pI830->lvds_fixed_mode;
 
     if (pFixedMode)
     {
@@ -536,7 +530,7 @@ i830_lvds_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
     }
 
     /* If we don't have a panel mode there's not much we can do */
-    if (dev_priv->panel_fixed_mode == NULL)
+    if (pI830->lvds_fixed_mode == NULL)
 	return TRUE;
 
     /* If we have timings from the BIOS for the panel, put them in
@@ -544,19 +538,19 @@ i830_lvds_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
      * with the panel scaling set up to source from the H/VDisplay
      * of the original mode.
      */
-    adjusted_mode->HDisplay = dev_priv->panel_fixed_mode->HDisplay;
-    adjusted_mode->HSyncStart = dev_priv->panel_fixed_mode->HSyncStart;
-    adjusted_mode->HSyncEnd = dev_priv->panel_fixed_mode->HSyncEnd;
-    adjusted_mode->HTotal = dev_priv->panel_fixed_mode->HTotal;
-    adjusted_mode->VDisplay = dev_priv->panel_fixed_mode->VDisplay;
-    adjusted_mode->VSyncStart = dev_priv->panel_fixed_mode->VSyncStart;
-    adjusted_mode->VSyncEnd = dev_priv->panel_fixed_mode->VSyncEnd;
-    adjusted_mode->VTotal = dev_priv->panel_fixed_mode->VTotal;
-    adjusted_mode->Clock = dev_priv->panel_fixed_mode->Clock;
+    adjusted_mode->HDisplay = pI830->lvds_fixed_mode->HDisplay;
+    adjusted_mode->HSyncStart = pI830->lvds_fixed_mode->HSyncStart;
+    adjusted_mode->HSyncEnd = pI830->lvds_fixed_mode->HSyncEnd;
+    adjusted_mode->HTotal = pI830->lvds_fixed_mode->HTotal;
+    adjusted_mode->VDisplay = pI830->lvds_fixed_mode->VDisplay;
+    adjusted_mode->VSyncStart = pI830->lvds_fixed_mode->VSyncStart;
+    adjusted_mode->VSyncEnd = pI830->lvds_fixed_mode->VSyncEnd;
+    adjusted_mode->VTotal = pI830->lvds_fixed_mode->VTotal;
+    adjusted_mode->Clock = pI830->lvds_fixed_mode->Clock;
     xf86SetModeCrtc(adjusted_mode, INTERLACE_HALVE_V);
 
     /* Make sure pre-965s set dither correctly */
-    if (!IS_I965G(pI830) && dev_priv->panel_wants_dither)
+    if (!IS_I965G(pI830) && pI830->lvds_dither)
 	pfit_control |= PANEL_8TO6_DITHER_ENABLE;
 
     /* Native modes don't need fitting */
@@ -597,12 +591,12 @@ i830_lvds_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
 	 * LVDS borders are enabled (see i830_display.c).
 	 */
 	left_border =
-	    (dev_priv->panel_fixed_mode->HDisplay - mode->HDisplay) / 2;
+	    (pI830->lvds_fixed_mode->HDisplay - mode->HDisplay) / 2;
 	right_border = left_border;
 	if (mode->HDisplay & 1)
 	    right_border++;
 	top_border =
-	    (dev_priv->panel_fixed_mode->VDisplay - mode->VDisplay) / 2;
+	    (pI830->lvds_fixed_mode->VDisplay - mode->VDisplay) / 2;
 	bottom_border = top_border;
 	if (mode->VDisplay & 1)
 	    bottom_border++;
@@ -661,7 +655,7 @@ i830_lvds_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
 		    HORIZ_INTERP_BILINEAR;
 
 		/* Pillar will have left/right borders */
-		left_border =  (dev_priv->panel_fixed_mode->HDisplay -
+		left_border =  (pI830->lvds_fixed_mode->HDisplay -
 				scaled_width) / 2;
 		right_border = left_border;
 		if (mode->HDisplay & 1) /* odd resolutions */
@@ -684,7 +678,7 @@ i830_lvds_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
 		    HORIZ_INTERP_BILINEAR;
 
 		/* Letterbox will have top/bottom borders */
-		top_border = (dev_priv->panel_fixed_mode->VDisplay -
+		top_border = (pI830->lvds_fixed_mode->VDisplay -
 			      scaled_height) / 2;
 		bottom_border = top_border;
 		if (mode->VDisplay & 1)
@@ -786,8 +780,9 @@ i830_lvds_detect(xf86OutputPtr output)
 static DisplayModePtr
 i830_lvds_get_modes(xf86OutputPtr output)
 {
+    ScrnInfoPtr	pScrn = output->scrn;
+    I830Ptr	pI830 = I830PTR(pScrn);
     I830OutputPrivatePtr    intel_output = output->driver_private;
-    struct i830_lvds_priv   *dev_priv = intel_output->dev_priv;
     xf86MonPtr		    edid_mon;
     DisplayModePtr	    modes;
 
@@ -816,8 +811,8 @@ i830_lvds_get_modes(xf86OutputPtr output)
 	}
     }
 
-    if (dev_priv->panel_fixed_mode != NULL)
-	return xf86DuplicateMode(dev_priv->panel_fixed_mode);
+    if (pI830->lvds_fixed_mode != NULL)
+	return xf86DuplicateMode(pI830->lvds_fixed_mode);
 
     return NULL;
 }
@@ -825,13 +820,13 @@ i830_lvds_get_modes(xf86OutputPtr output)
 static void
 i830_lvds_destroy (xf86OutputPtr output)
 {
+    ScrnInfoPtr	pScrn = output->scrn;
+    I830Ptr	pI830 = I830PTR(pScrn);
     I830OutputPrivatePtr    intel_output = output->driver_private;
 
-    if (intel_output)
+    if (pI830->lvds_fixed_mode)
     {
-	struct i830_lvds_priv	*dev_priv = intel_output->dev_priv;
-	
-        xf86DeleteMode (&dev_priv->panel_fixed_mode, dev_priv->panel_fixed_mode);
+        xf86DeleteMode (&pI830->lvds_fixed_mode, pI830->lvds_fixed_mode);
 	xfree (intel_output);
     }
 }
@@ -1217,7 +1212,8 @@ i830_lvds_init(ScrnInfoPtr pScrn)
     I830Ptr		    pI830 = I830PTR(pScrn);
     xf86OutputPtr	    output;
     I830OutputPrivatePtr    intel_output;
-    DisplayModePtr	    modes, scan, bios_mode;
+    DisplayModePtr	    modes, scan;
+    DisplayModePtr	    lvds_ddc_mode;
     struct i830_lvds_priv   *dev_priv;
 
     if (pI830->quirk_flag & QUIRK_IGNORE_LVDS)
@@ -1244,17 +1240,27 @@ i830_lvds_init(ScrnInfoPtr pScrn)
 
     dev_priv = (struct i830_lvds_priv *) (intel_output + 1);
     intel_output->dev_priv = dev_priv;
+    
+    /*
+     * Mode detection algorithms for LFP:
+     *  1) if EDID present, use it, done
+     *  2) if VBT present, use it, done
+     *  3) if current mode is programmed, use it, done
+     *  4) check for Mac mini & other quirks
+     *  4) fail, assume no LFP
+     */
 
     /* Set up the LVDS DDC channel.  Most panels won't support it, but it can
      * be useful if available.
      */
     I830I2CInit(pScrn, &intel_output->pDDCBus, GPIOC, "LVDSDDC_C");
 
-    if (!pI830->lvds_fixed_mode) {
+    if (!pI830->skip_panel_detect) {
 	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
 		   "Skipping any attempt to determine panel fixed mode.\n");
-	goto skip_panel_fixed_mode_setup;
+	goto found_mode;
     }
+
     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
 	       "Attempting to determine panel fixed mode.\n");
 
@@ -1274,77 +1280,47 @@ i830_lvds_init(ScrnInfoPtr pScrn)
 	    scan->prev = scan->next;
 	if (scan->next != NULL)
 	    scan->next = scan->prev;
-	dev_priv->panel_fixed_mode = scan;
+	lvds_ddc_mode = scan;
     }
     /* Delete the mode list */
     while (modes != NULL)
 	xf86DeleteMode(&modes, modes);
 
-    /* If we didn't get EDID, try checking if the panel is already turned on.
-     * If so, assume that whatever is currently programmed is the correct mode.
-     */
-    if (dev_priv->panel_fixed_mode == NULL) {
-	uint32_t lvds = INREG(LVDS);
-	int pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0;
-	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
-	xf86CrtcPtr crtc = xf86_config->crtc[pipe];
-
-	if (lvds & LVDS_PORT_EN) {
-	    dev_priv->panel_fixed_mode = i830_crtc_mode_get(pScrn, crtc);
-	    if (dev_priv->panel_fixed_mode != NULL)
-		dev_priv->panel_fixed_mode->type |= M_T_PREFERRED;
-	}
+    if (lvds_ddc_mode) {
+	    pI830->lvds_fixed_mode = lvds_ddc_mode;
+	    goto found_mode;
     }
 
     /* Get the LVDS fixed mode out of the BIOS.  We should support LVDS with
      * the BIOS being unavailable or broken, but lack the configuration options
      * for now.
      */
-    bios_mode = i830_bios_get_panel_mode(pScrn, &dev_priv->panel_wants_dither);
-    if (bios_mode != NULL) {
-	if (dev_priv->panel_fixed_mode != NULL) {
-	    /* Fixup for a 1280x768 panel with the horizontal trimmed
-	     * down to 1024 for text mode.
-	     */
-	    if (!xf86ModesEqual(dev_priv->panel_fixed_mode, bios_mode) &&
-		dev_priv->panel_fixed_mode->HDisplay == 1024 &&
-		dev_priv->panel_fixed_mode->HSyncStart == 1200 &&
-		dev_priv->panel_fixed_mode->HSyncEnd == 1312 &&
-		dev_priv->panel_fixed_mode->HTotal == 1688 &&
-		dev_priv->panel_fixed_mode->VDisplay == 768)
-	    {
-		dev_priv->panel_fixed_mode->HDisplay = 1280;
-		dev_priv->panel_fixed_mode->HSyncStart = 1328;
-		dev_priv->panel_fixed_mode->HSyncEnd = 1440;
-		dev_priv->panel_fixed_mode->HTotal = 1688;
-	    }
+    if (pI830->lvds_fixed_mode)
+	    goto found_mode;
+
+    /* If we *still* don't have a mode, try checking if the panel is already
+     * turned on.  If so, assume that whatever is currently programmed is the
+     * correct mode.
+     */
+    if (!pI830->lvds_fixed_mode) {
+	uint32_t lvds = INREG(LVDS);
+	int pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0;
+	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+	xf86CrtcPtr crtc = xf86_config->crtc[pipe];
 
-	    if (pI830->debug_modes &&
-		!xf86ModesEqual(dev_priv->panel_fixed_mode, bios_mode))
-	    {
-		xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
-			   "BIOS panel mode data doesn't match probed data, "
-			   "continuing with probed.\n");
-		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "BIOS mode:\n");
-		xf86PrintModeline(pScrn->scrnIndex, bios_mode);
-		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "probed mode:\n");
-		xf86PrintModeline(pScrn->scrnIndex, dev_priv->panel_fixed_mode);
-		xfree(bios_mode->name);
-		xfree(bios_mode);
+	if (lvds & LVDS_PORT_EN) {
+	    pI830->lvds_fixed_mode = i830_crtc_mode_get(pScrn, crtc);
+	    if (pI830->lvds_fixed_mode != NULL) {
+		pI830->lvds_fixed_mode->type |= M_T_PREFERRED;
+		goto found_mode;
 	    }
-	}  else {
-	    dev_priv->panel_fixed_mode = bios_mode;
 	}
-    } else {
-	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
-		   "Couldn't detect panel mode.  Disabling panel\n");
-	goto disable_exit;
     }
 
-    /* Update pI830 w/SSC info, if any */
-    i830_bios_get_ssc(pScrn);
+    if (!pI830->lvds_fixed_mode)
+	    goto disable_exit;
 
- skip_panel_fixed_mode_setup:
+found_mode:
 
     /* Blacklist machines with BIOSes that list an LVDS panel without actually
      * having one.
@@ -1359,9 +1335,9 @@ i830_lvds_init(ScrnInfoPtr pScrn)
 	 * display.
 	 */
 
-	if (dev_priv->panel_fixed_mode != NULL &&
-		dev_priv->panel_fixed_mode->HDisplay == 800 &&
-		dev_priv->panel_fixed_mode->VDisplay == 600)
+	if (pI830->lvds_fixed_mode != NULL &&
+		pI830->lvds_fixed_mode->HDisplay == 800 &&
+		pI830->lvds_fixed_mode->VDisplay == 600)
 	{
 	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
 		    "Suspected Mac Mini, ignoring the LVDS\n");
diff --git a/src/i830_tv.c b/src/i830_tv.c
index 1022c46..0a33357 100644
--- a/src/i830_tv.c
+++ b/src/i830_tv.c
@@ -1716,7 +1716,6 @@ i830_tv_init(ScrnInfoPtr pScrn)
 	    (tv_dac_off & TVDAC_STATE_CHG_EN) != 0)
 	return;
 
-    i830_bios_get_tv(pScrn);
     if (!pI830->tv_present) /* VBIOS claims no TV connector */
 	return;
 


More information about the xorg-commit mailing list