xf86-video-intel: Branch 'xf86-video-intel-2.4-branch' - 9 commits - man/intel.man src/bios_reader/bios_reader.c src/i830_bios.c src/i830_bios.h src/i830_display.c src/i830_driver.c src/i830_dvo.c src/i830.h src/i830_lvds.c src/i830_quirks.c src/i830_tv.c
Zhenyu Wang
zhen at kemper.freedesktop.org
Thu Aug 14 22:19:02 PDT 2008
man/intel.man | 65 +++++-
src/bios_reader/bios_reader.c | 291 +++++++++++++++++++++---------
src/i830.h | 6
src/i830_bios.c | 401 ++++++++++++------------------------------
src/i830_bios.h | 72 ++++---
src/i830_display.c | 57 ++---
src/i830_driver.c | 8
src/i830_dvo.c | 43 ++--
src/i830_lvds.c | 158 ++++++----------
src/i830_quirks.c | 1
src/i830_tv.c | 1
11 files changed, 553 insertions(+), 550 deletions(-)
New commits:
commit 01bbdbc6d83a526654abf501bd6cd203f8373774
Author: Alan Coopersmith <alan.coopersmith at sun.com>
Date: Thu Jul 31 20:02:21 2008 -0700
Man page typo fixes
(cherry picked from commit 27e9506fda86e90fd67de1715fa32d23aaa8a683)
diff --git a/man/intel.man b/man/intel.man
index f363ab1..e9ae240 100644
--- a/man/intel.man
+++ b/man/intel.man
@@ -382,9 +382,9 @@ what is needed. Set LVDSFixedMode to false and then the user has full
control over the resolution and timings sent to the LVDS-connected
device, through the usual means in xorg.
-.SH MUTLIHEAD CONFIGURATIONS
+.SH MULTIHEAD CONFIGURATIONS
-The number of independent outputs is dicated by the number of CRTCs
+The number of independent outputs is dictated by the number of CRTCs
(in X parlance) a given chip supports. Most recent Intel chips have
two CRTCs, meaning that two separate framebuffers can be displayed
simultaneously, in an extended desktop configuration. If a chip
commit 4ac91c2eb6b539fa23d218ca714cadf998ae8eb6
Author: Jesse Barnes <jbarnes at eee.(none)>
Date: Thu Jul 31 19:21:36 2008 -0700
Update man page
Add example dual head config, add info on bug reporting.
(cherry picked from commit da2eb83fb9a52291ea98f3285aee7bee2d55e0ca)
diff --git a/man/intel.man b/man/intel.man
index aac0efa..f363ab1 100644
--- a/man/intel.man
+++ b/man/intel.man
@@ -33,10 +33,10 @@ details. This section only covers configuration details specific to this
driver.
.PP
The Intel 8xx and 9xx families of integrated graphics chipsets have a unified
-memory architecture and uses system memory for video ram. For the i810 and
-i815 family of chipset, operating system support for allocating system
-memory for video use is required in order to use this driver. For the 830M
-and later, this is required in order for the driver to use more video ram
+memory architecture meaning that system memory is used as video RAM. For the
+i810 and i815 family of chipsets, operating system support for allocating system
+memory is required in order to use this driver. For the 830M
+and later, this is required in order for the driver to use more video RAM
than has been pre-allocated at boot time by the BIOS. This is usually
achieved with an "agpgart" or "agp" kernel driver. Linux, FreeBSD, OpenBSD,
NetBSD, and Solaris have such kernel drivers available.
@@ -44,7 +44,7 @@ NetBSD, and Solaris have such kernel drivers available.
By default, the i810 will use 8 megabytes
of system memory for graphics. For the 830M and later, the driver will
automatically size its memory allocation according to the features it will
-support. The
+support. Therefore, the
.B VideoRam
option, which in the past had been necessary to allow more than some small
amount of memory to be allocated, is now ignored.
@@ -84,7 +84,8 @@ Default: enabled on supported configurations.
.TP
.BI "Option \*qTiling\*q \*q" boolean \*q
This option controls whether memory buffers are allocated in tiled mode. In
-many cases (especially for complex rendering), tiling can improve performance.
+most cases (especially for complex rendering), tiling dramatically improves
+performance.
Default: enabled.
.TP
.BI "Option \*qDRI\*q \*q" boolean \*q
@@ -180,8 +181,7 @@ the server log.
Force the driver to leave pipe A enabled. May be necessary in configurations
where the BIOS accesses pipe registers during display hotswitch or lid close,
causing a crash. If you find that your platform needs this option, please file
-a bug against xf86-video-intel at http://bugs.freedesktop.org which includes
-the output of 'lspci -v' and 'lspci -vn'.
+a bug (see REPORTING BUGS below) including the output of 'lspci -v' and 'lspci -vn'.
.TP
.BI "Option \*qLVDS24Bit\*q \*q" boolean \*q
Specify 24 bit pixel format (i.e. 8 bits per color) to be used for the
@@ -220,7 +220,7 @@ detected outputs. You can use the
.B xrandr
tool to control outputs on the command line. Each output listed below may have
one or more properties associated with it (like a binary EDID block if one is
-found). Some outputs have unique properties which are described below.
+found). Some outputs have unique properties which are described below. See the "MULTIHEAD CONFIGURATIONS" section below for additional information.
.SS "VGA"
VGA output port (typically exposed via an HD15 connector).
@@ -382,6 +382,53 @@ what is needed. Set LVDSFixedMode to false and then the user has full
control over the resolution and timings sent to the LVDS-connected
device, through the usual means in xorg.
+.SH MUTLIHEAD CONFIGURATIONS
+
+The number of independent outputs is dicated by the number of CRTCs
+(in X parlance) a given chip supports. Most recent Intel chips have
+two CRTCs, meaning that two separate framebuffers can be displayed
+simultaneously, in an extended desktop configuration. If a chip
+supports more outputs than it has CRTCs (say local flat panel, VGA and
+TV in the case of many outputs), two of the outputs will have to be
+"cloned", meaning that they display the same framebuffer contents (or
+one displays a subset of another's framebuffer if the modes aren't
+equal).
+
+You can use the "xrandr" tool, or various desktop utilities, to change
+your output configuration at runtime. To statically configure your
+outputs, you can use the "Monitor-<type>" options along with
+additional monitor sections in your xorg.conf to create your screen
+topology. The example below puts the VGA output to the right of the
+builtin laptop screen, both running at 1024x768.
+
+.nf
+.B "Section \*qMonitor\*q"
+.BI " Identifier \*qLaptop FooBar Internal Display\*q"
+.BI " Option \*qPosition\*q \*q0 0\*q"
+.B "EndSection"
+
+.B "Section \*qMonitor\*q"
+.BI " Identifier \*qSome Random CRT\*q"
+.BI " Option \*qPosition\*q \*q1024 0\*q"
+.BI " Option \*qRightOf\*q \*qLaptop FoodBar Internal Display\*q"
+.B "EndSection"
+
+.B "Section \*qDevice\*q"
+.BI " Driver \*qintel\*q"
+.BI " Option \*qmonitor-LVDS\*q \*qLaptop FooBar Internal Display\*q"
+.BI " Option \*qmonitor-VGA\*q \*qSome Random CRT\*q"
+.B "EndSection"
+
+.SH REPORTING BUGS
+
+The xf86-video-intel driver is part of the X.Org and Freedesktop.org
+umbrella projects. Details on bug reporting can be found at
+http://www.intellinuxgraphics.org/how_to_report_bug.html. Mailing
+lists are also commonly used to report experiences and ask questions
+about configuration and other topics. See lists.freedesktop.org for
+more information (the xorg at lists.freedesktop.org mailing list is the
+most appropriate place to ask X.Org and driver related questions).
+
.SH "SEE ALSO"
__xservername__(__appmansuffix__), __xconfigfile__(__filemansuffix__), xorgconfig(__appmansuffix__), Xserver(__appmansuffix__), X(__miscmansuffix__)
.SH AUTHORS
commit 280be2a193063c9e2f062cbab9fa967a408dc290
Author: Zhenyu Wang <zhenyu.z.wang at intel.com>
Date: Fri Aug 15 10:10:43 2008 +0800
Always check and free driver private in LVDS destroy
(cherry picked from commit ed7269e0a377b3135b06cacecc59119f06958feb)
diff --git a/src/i830_lvds.c b/src/i830_lvds.c
index 78fd2d8..96e9f00 100644
--- a/src/i830_lvds.c
+++ b/src/i830_lvds.c
@@ -824,11 +824,9 @@ i830_lvds_destroy (xf86OutputPtr output)
I830Ptr pI830 = I830PTR(pScrn);
I830OutputPrivatePtr intel_output = output->driver_private;
- if (pI830->lvds_fixed_mode)
- {
- xf86DeleteMode (&pI830->lvds_fixed_mode, pI830->lvds_fixed_mode);
+ xf86DeleteMode (&pI830->lvds_fixed_mode, pI830->lvds_fixed_mode);
+ if (intel_output)
xfree (intel_output);
- }
}
#ifdef RANDR_12_INTERFACE
commit 1f558fab4eef3b54de4853bc5247fbd0d24b68bf
Author: Zhenyu Wang <zhenyu.z.wang at intel.com>
Date: Fri Aug 15 10:02:44 2008 +0800
Make skip_panel_detect clear for its meaning
(cherry picked from commit f4cb9a135dca9279af8186a9b18bf62ef7351019)
diff --git a/src/i830_driver.c b/src/i830_driver.c
index 64d0db1..6f87c51 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->skip_panel_detect = TRUE;
- } else {
pI830->skip_panel_detect = FALSE;
+ } else {
+ pI830->skip_panel_detect = TRUE;
}
if (xf86ReturnOptValBool(pI830->Options, OPTION_FORCEENABLEPIPEA, FALSE))
diff --git a/src/i830_lvds.c b/src/i830_lvds.c
index a885627..78fd2d8 100644
--- a/src/i830_lvds.c
+++ b/src/i830_lvds.c
@@ -1255,7 +1255,7 @@ i830_lvds_init(ScrnInfoPtr pScrn)
*/
I830I2CInit(pScrn, &intel_output->pDDCBus, GPIOC, "LVDSDDC_C");
- if (!pI830->skip_panel_detect) {
+ if (pI830->skip_panel_detect) {
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Skipping any attempt to determine panel fixed mode.\n");
goto found_mode;
commit 532e47a4a169e829ad34fdc8bb85e4eb81721af3
Author: Jesse Barnes <jbarnes at virtuousgeek.org>
Date: Thu Aug 14 16:02:37 2008 -0700
Fix pipe A force quirk
Last commit introduced a logic buglet, we went from (foo & BLAH) -> (!foo &
BLAH) rather than !(foo & BLAH), so fix it up to make my laptop work again.
(cherry picked from commit 22918f62c89a4314fb5d01c58f22fee5b9a15a27)
diff --git a/src/i830_display.c b/src/i830_display.c
index 622209b..2f1e7ab 100644
--- a/src/i830_display.c
+++ b/src/i830_display.c
@@ -858,7 +858,7 @@ i830_crtc_dpms(xf86CrtcPtr crtc, int mode)
OUTREG(VGACNTRL, VGA_DISP_DISABLE);
/* May need to leave pipe A on */
- if ((pipe != 0) || (!pI830->quirk_flag & QUIRK_PIPEA_FORCE))
+ if ((pipe != 0) || !(pI830->quirk_flag & QUIRK_PIPEA_FORCE))
{
/* Disable display plane */
temp = INREG(dspcntr_reg);
commit ac740398569dfa02d3d26a2abeb5c848717e6c03
Author: Olivier Fourdan <ofourdan at redhat.com>
Date: Mon Aug 11 12:07:32 2008 -0400
Fix DPMS off in the presence of the pipe A quirk.
Still turn off the VGA plane, and also handle the DRI path at the end.
(cherry picked from commit 9ec36e0c8bd8a4bd7c40569412fc1a21219b5af9)
diff --git a/src/i830_display.c b/src/i830_display.c
index e1dad03..622209b 100644
--- a/src/i830_display.c
+++ b/src/i830_display.c
@@ -854,44 +854,43 @@ i830_crtc_dpms(xf86CrtcPtr crtc, int mode)
/* Give the overlay scaler a chance to disable if it's on this pipe */
i830_crtc_dpms_video(crtc, FALSE);
- /* May need to leave pipe A on */
- if ((pipe == 0) && (pI830->quirk_flag & QUIRK_PIPEA_FORCE))
- return;
-
/* Disable the VGA plane that we never use */
OUTREG(VGACNTRL, VGA_DISP_DISABLE);
- /* Disable display plane */
- temp = INREG(dspcntr_reg);
- if ((temp & DISPLAY_PLANE_ENABLE) != 0)
+ /* May need to leave pipe A on */
+ if ((pipe != 0) || (!pI830->quirk_flag & QUIRK_PIPEA_FORCE))
{
- OUTREG(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE);
- /* Flush the plane changes */
- OUTREG(dspbase_reg, INREG(dspbase_reg));
- POSTING_READ(dspbase_reg);
- }
+ /* Disable display plane */
+ temp = INREG(dspcntr_reg);
+ if ((temp & DISPLAY_PLANE_ENABLE) != 0)
+ {
+ OUTREG(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE);
+ /* Flush the plane changes */
+ OUTREG(dspbase_reg, INREG(dspbase_reg));
+ POSTING_READ(dspbase_reg);
+ }
- if (!IS_I9XX(pI830)) {
- /* Wait for vblank for the disable to take effect */
- i830WaitForVblank(pScrn);
- }
+ if (!IS_I9XX(pI830)) {
+ /* Wait for vblank for the disable to take effect */
+ i830WaitForVblank(pScrn);
+ }
- /* Next, disable display pipes */
- temp = INREG(pipeconf_reg);
- if ((temp & PIPEACONF_ENABLE) != 0) {
- OUTREG(pipeconf_reg, temp & ~PIPEACONF_ENABLE);
- POSTING_READ(pipeconf_reg);
- }
+ /* Next, disable display pipes */
+ temp = INREG(pipeconf_reg);
+ if ((temp & PIPEACONF_ENABLE) != 0) {
+ OUTREG(pipeconf_reg, temp & ~PIPEACONF_ENABLE);
+ POSTING_READ(pipeconf_reg);
+ }
- /* Wait for vblank for the disable to take effect. */
- i830WaitForVblank(pScrn);
+ /* Wait for vblank for the disable to take effect. */
+ i830WaitForVblank(pScrn);
- temp = INREG(dpll_reg);
- if ((temp & DPLL_VCO_ENABLE) != 0) {
- OUTREG(dpll_reg, temp & ~DPLL_VCO_ENABLE);
- POSTING_READ(dpll_reg);
+ temp = INREG(dpll_reg);
+ if ((temp & DPLL_VCO_ENABLE) != 0) {
+ OUTREG(dpll_reg, temp & ~DPLL_VCO_ENABLE);
+ POSTING_READ(dpll_reg);
+ }
}
-
/* Wait for the clocks to turn off. */
usleep(150);
break;
commit 9b03fd49b0f27c9add19dece55d00a58ed73c978
Author: Olivier Fourdan <ofourdan at redhat.com>
Date: Mon Aug 11 11:30:51 2008 -0400
Apply pipe A quirk to 845 as well.
(cherry picked from commit 445c2e9ef8fc1d49bbb03e07bf36e0339be16a80)
diff --git a/src/i830_quirks.c b/src/i830_quirks.c
index 6fc8e53..a3ed044 100644
--- a/src/i830_quirks.c
+++ b/src/i830_quirks.c
@@ -315,6 +315,7 @@ static i830_quirk i830_quirk_list[] = {
/* 855 & before need to leave pipe A & dpll A up */
{ PCI_CHIP_I855_GM, SUBSYS_ANY, SUBSYS_ANY, quirk_pipea_force },
+ { PCI_CHIP_845_G, SUBSYS_ANY, SUBSYS_ANY, quirk_pipea_force },
{ 0, 0, 0, NULL },
};
commit d1b47cf0cb66fb1b7c991fbd4f4518c6ccdbc643
Author: Eric Anholt <eric at anholt.net>
Date: Fri Aug 8 16:35:25 2008 -0700
Set lvds_ddc_mode before use to avoid a segfault on mac mini.
(cherry picked from commit fe90c0522f65f60c4c431787c889b7fb639ab61b)
diff --git a/src/i830_lvds.c b/src/i830_lvds.c
index 9f20579..a885627 100644
--- a/src/i830_lvds.c
+++ b/src/i830_lvds.c
@@ -1213,7 +1213,7 @@ i830_lvds_init(ScrnInfoPtr pScrn)
xf86OutputPtr output;
I830OutputPrivatePtr intel_output;
DisplayModePtr modes, scan;
- DisplayModePtr lvds_ddc_mode;
+ DisplayModePtr lvds_ddc_mode = NULL;
struct i830_lvds_priv *dev_priv;
if (pI830->quirk_flag & QUIRK_IGNORE_LVDS)
commit 86b10601e8798974240ae17539b413c1798d34e1
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.
(cherry picked from commit a21d4794b6812ce05d08f06dc47b26c4fb1c1fef)
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 f27d957..64d0db1 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