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 +#include #include #include #include +#include +#include +#include #include + #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 \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..8adcde4 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,10 @@ 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; + DisplayModePtr lvds_ddc_mode; + Bool skip_panel_detect; Bool tv_present; /* TV connector present (from VBIOS) */ @@ -663,7 +665,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 c880833..02122d2 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..69e9b96 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,7 @@ i830_lvds_init(ScrnInfoPtr pScrn) I830Ptr pI830 = I830PTR(pScrn); xf86OutputPtr output; I830OutputPrivatePtr intel_output; - DisplayModePtr modes, scan, bios_mode; + DisplayModePtr modes, scan; struct i830_lvds_priv *dev_priv; if (pI830->quirk_flag & QUIRK_IGNORE_LVDS) @@ -1244,17 +1239,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 +1279,47 @@ i830_lvds_init(ScrnInfoPtr pScrn) scan->prev = scan->next; if (scan->next != NULL) scan->next = scan->prev; - dev_priv->panel_fixed_mode = scan; + pI830->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 (pI830->lvds_ddc_mode) { + pI830->lvds_fixed_mode = pI830->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 +1334,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 651f77b..d76764a 100644 --- a/src/i830_tv.c +++ b/src/i830_tv.c @@ -1715,7 +1715,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;