summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/bios_reader/bios_reader.c291
-rw-r--r--src/i830.h6
-rw-r--r--src/i830_bios.c401
-rw-r--r--src/i830_bios.h72
-rw-r--r--src/i830_driver.c8
-rw-r--r--src/i830_dvo.c43
-rw-r--r--src/i830_lvds.c158
-rw-r--r--src/i830_tv.c1
8 files changed, 469 insertions, 511 deletions
diff --git a/src/bios_reader/bios_reader.c b/src/bios_reader/bios_reader.c
index ffa27f03..dbcd1503 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 68690f7b..6a5de6bc 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 a8193fc5..fe55d239 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 c1ba50d7..a8d9adde 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 f5aa114d..79a43591 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 9e821710..832c7625 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 c7f24342..9f20579a 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 1022c469..0a33357c 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;