summaryrefslogtreecommitdiff
path: root/linux-core
diff options
context:
space:
mode:
authorJesse Barnes <jbarnes@jbarnes-t61.(none)>2008-05-23 18:42:47 -0700
committerJesse Barnes <jbarnes@virtuousgeek.org>2008-05-23 18:42:47 -0700
commit9fc4ea5c00dfb91ebff893fb5092e768155cc2e2 (patch)
tree7dfdf71aa20e9786f3d50d89ea30614c2a73693f /linux-core
parentb4d8cda8e6d6ea319ab7c471d6d68b8af8693cfe (diff)
i915: do a better job of parsing VBIOS data
Add code to get panel modes from the VBIOS if present and check whether certain outputs exist. Should make our display detection code a little more robust.
Diffstat (limited to 'linux-core')
-rw-r--r--linux-core/i915_drv.c4
-rw-r--r--linux-core/intel_bios.c322
-rw-r--r--linux-core/intel_bios.h312
-rw-r--r--linux-core/intel_lvds.c48
-rw-r--r--linux-core/intel_tv.c2
5 files changed, 444 insertions, 244 deletions
diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c
index 27c239d0..51262d79 100644
--- a/linux-core/i915_drv.c
+++ b/linux-core/i915_drv.c
@@ -387,7 +387,7 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state)
/* Scratch space */
for (i = 0; i < 16; i++) {
- dev_priv->saveSWF0[i] = I915_READ(SWF0 + (i << 2));
+ dev_priv->saveSWF0[i] = I915_READ(SWF00 + (i << 2));
dev_priv->saveSWF1[i] = I915_READ(SWF10 + (i << 2));
}
for (i = 0; i < 3; i++)
@@ -551,7 +551,7 @@ static int i915_resume(struct drm_device *dev)
I915_WRITE (MI_ARB_STATE, dev_priv->saveMI_ARB_STATE | 0xffff0000);
for (i = 0; i < 16; i++) {
- I915_WRITE(SWF0 + (i << 2), dev_priv->saveSWF0[i]);
+ I915_WRITE(SWF00 + (i << 2), dev_priv->saveSWF0[i]);
I915_WRITE(SWF10 + (i << 2), dev_priv->saveSWF1[i+7]);
}
for (i = 0; i < 3; i++)
diff --git a/linux-core/intel_bios.c b/linux-core/intel_bios.c
index 7f8e8513..f124fa1a 100644
--- a/linux-core/intel_bios.c
+++ b/linux-core/intel_bios.c
@@ -30,170 +30,7 @@
#include "i915_drv.h"
#include "intel_bios.h"
-#define VBT_OFFSET 0x1a
-
-/**
- * intel_find_vbt - find the VBT
- * @dev: DRM device
- *
- * Loads the Video BIOS and checks that the VBT exists.
- *
- * 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.
- */
-bool
-intel_find_bios(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct pci_dev *pdev = dev->pdev;
- void __iomem *bios;
- size_t size;
-
- bios = pci_map_rom(pdev, &size);
- if (!bios)
- return NULL;
-
- dev_priv->vbt = (struct vbt_header *)((u8 *)bios + VBT_OFFSET);
- dev_priv->bdb = (struct bdb_header *)((u8 *)bios + VBT_OFFSET +
- dev_priv->vbt->bdb_offset);
-
- if (memcmp(dev_priv->vbt->signature, "$VBT", 4) != 0) {
- DRM_ERROR("Bad VBT signature\n");
- pci_unmap_rom(pdev, bios);
- return NULL;
- }
-
- return bios;
-}
-
#if 0
-/**
- * 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.
- */
-struct drm_display_mode *
-i830_bios_get_panel_mode(struct drm_device *dev, 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;
- CARD8 *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)
{
@@ -242,3 +79,162 @@ i830_bios_get_aim_data_block (ScrnInfoPtr pScrn, int aim, int data_block)
return NULL;
}
#endif
+
+static void *
+find_section(struct bdb_header *bdb, int section_id)
+{
+ u8 *base = (u8 *)bdb;
+ int index = 0;
+ u16 total, current_size;
+ u8 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 = *((u16 *)(base + index));
+ index += 2;
+ if (current_id == section_id)
+ return base + index;
+ index += current_size;
+ }
+
+ return NULL;
+}
+
+/* Try to find panel data */
+static void
+parse_panel_data(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
+{
+ struct bdb_lvds_options *lvds_options;
+ struct bdb_lvds_lfp_data *lvds_lfp_data;
+ struct bdb_lvds_lfp_data_entry *entry;
+ struct lvds_dvo_timing *dvo_timing;
+ struct drm_display_mode *panel_fixed_mode;
+
+ /* Defaults if we can't find VBT info */
+ dev_priv->lvds_dither = 0;
+ dev_priv->lvds_vbt = 0;
+
+ lvds_options = find_section(bdb, BDB_LVDS_OPTIONS);
+ if (!lvds_options)
+ return;
+
+ dev_priv->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;
+
+ dev_priv->lvds_vbt = 1;
+
+ entry = &lvds_lfp_data->data[lvds_options->panel_type];
+ dvo_timing = &entry->dvo_timing;
+
+ panel_fixed_mode = drm_calloc(1, sizeof(*panel_fixed_mode),
+ DRM_MEM_DRIVER);
+
+ panel_fixed_mode->hdisplay = (dvo_timing->hactive_hi << 8) |
+ dvo_timing->hactive_lo;
+ panel_fixed_mode->hsync_start = panel_fixed_mode->hdisplay +
+ ((dvo_timing->hsync_off_hi << 8) | dvo_timing->hsync_off_lo);
+ panel_fixed_mode->hsync_end = panel_fixed_mode->hsync_start +
+ dvo_timing->hsync_pulse_width;
+ panel_fixed_mode->htotal = panel_fixed_mode->hdisplay +
+ ((dvo_timing->hblank_hi << 8) | dvo_timing->hblank_lo);
+
+ panel_fixed_mode->vdisplay = (dvo_timing->vactive_hi << 8) |
+ dvo_timing->vactive_lo;
+ panel_fixed_mode->vsync_start = panel_fixed_mode->vdisplay +
+ dvo_timing->vsync_off;
+ panel_fixed_mode->vsync_end = panel_fixed_mode->vsync_start +
+ dvo_timing->vsync_pulse_width;
+ panel_fixed_mode->vtotal = panel_fixed_mode->vdisplay +
+ ((dvo_timing->vblank_hi << 8) | dvo_timing->vblank_lo);
+ panel_fixed_mode->clock = dvo_timing->clock * 10;
+ panel_fixed_mode->type = DRM_MODE_TYPE_PREFERRED;
+
+ drm_mode_set_name(panel_fixed_mode);
+
+ dev_priv->vbt_mode = panel_fixed_mode;
+
+ DRM_DEBUG("Found panel mode in BIOS VBT tables:\n");
+ drm_mode_debug_printmodeline(panel_fixed_mode);
+
+ return;
+}
+
+static void
+parse_general_features(struct drm_i915_private *dev_priv,
+ struct bdb_header *bdb)
+{
+ struct bdb_general_features *general;
+
+ /* Set sensible defaults in case we can't find the general block */
+ dev_priv->int_tv_support = 1;
+ dev_priv->int_crt_support = 1;
+
+ general = find_section(bdb, BDB_GENERAL_FEATURES);
+ if (general) {
+ dev_priv->int_tv_support = general->int_tv_support;
+ dev_priv->int_crt_support = general->int_crt_support;
+ }
+}
+
+/**
+ * intel_init_bios - initialize VBIOS settings & find VBT
+ * @dev: DRM device
+ *
+ * Loads the Video BIOS and checks that the VBT exists. Sets scratch registers
+ * to appropriate values.
+ *
+ * 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.
+ */
+bool
+intel_init_bios(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct pci_dev *pdev = dev->pdev;
+ struct vbt_header *vbt = NULL;
+ struct bdb_header *bdb;
+ u8 __iomem *bios;
+ size_t size;
+ int i;
+
+ bios = pci_map_rom(pdev, &size);
+ if (!bios)
+ return -1;
+
+ /* Scour memory looking for the VBT signature */
+ for (i = 0; i + 4 < size; i++) {
+ if (!memcmp(bios + i, "$VBT", 4)) {
+ vbt = (struct vbt_header *)(bios + i);
+ break;
+ }
+ }
+
+ if (!vbt) {
+ DRM_ERROR("VBT signature missing\n");
+ pci_unmap_rom(pdev, bios);
+ return -1;
+ }
+
+ bdb = (struct bdb_header *)(bios + i + vbt->bdb_offset);
+
+ /* Grab useful general definitions */
+ parse_general_features(dev_priv, bdb);
+ parse_panel_data(dev_priv, bdb);
+
+ return 0;
+}
diff --git a/linux-core/intel_bios.h b/linux-core/intel_bios.h
index b17856de..5ea715ac 100644
--- a/linux-core/intel_bios.h
+++ b/linux-core/intel_bios.h
@@ -46,6 +46,10 @@ struct bdb_header {
u16 version; /**< decimal */
u16 header_size; /**< in bytes */
u16 bdb_size; /**< in bytes */
+};
+
+/* strictly speaking, this is a "skip" block, but it has interesting info */
+struct vbios_data {
u8 type; /* 0 == desktop, 1 == mobile */
u8 relstage;
u8 chipset;
@@ -58,48 +62,133 @@ struct bdb_header {
u16 code_segment;
u8 dos_boot_mode;
u8 bandwidth_percent;
- u8 rsvd4;
+ u8 rsvd4; /* popup memory size */
u8 resize_pci_bios;
- u8 rsvd5;
- u8 rsvd6[3];
+ u8 rsvd5; /* is crt already on ddc2 */
+} __attribute__((packed));
+
+/*
+ * There are several types of BIOS data blocks (BDBs), each block has
+ * an ID and size in the first 3 bytes (ID in first, size in next 2).
+ * Known types are listed below.
+ */
+#define BDB_GENERAL_FEATURES 1
+#define BDB_GENERAL_DEFINITIONS 2
+#define BDB_OLD_TOGGLE_LIST 3
+#define BDB_MODE_SUPPORT_LIST 4
+#define BDB_GENERIC_MODE_TABLE 5
+#define BDB_EXT_MMIO_REGS 6
+#define BDB_SWF_IO 7
+#define BDB_SWF_MMIO 8
+#define BDB_DOT_CLOCK_TABLE 9
+#define BDB_MODE_REMOVAL_TABLE 10
+#define BDB_CHILD_DEVICE_TABLE 11
+#define BDB_DRIVER_FEATURES 12
+#define BDB_DRIVER_PERSISTENCE 13
+#define BDB_EXT_TABLE_PTRS 14
+#define BDB_DOT_CLOCK_OVERRIDE 15
+#define BDB_DISPLAY_SELECT 16
+/* 17 rsvd */
+#define BDB_DRIVER_ROTATION 18
+#define BDB_DISPLAY_REMOVE 19
+#define BDB_OEM_CUSTOM 20
+#define BDB_EFP_LIST 21 /* workarounds for VGA hsync/vsync */
+#define BDB_SDVO_LVDS_OPTIONS 22
+#define BDB_SDVO_PANEL_DTDS 23
+#define BDB_SDVO_LVDS_PNP_IDS 24
+#define BDB_SDVO_LVDS_POWER_SEQ 25
+#define BDB_TV_OPTIONS 26
+#define BDB_LVDS_OPTIONS 40
+#define BDB_LVDS_LFP_DATA_PTRS 41
+#define BDB_LVDS_LFP_DATA 42
+#define BDB_LVDS_BACKLIGHT 43
+#define BDB_LVDS_POWER 44
+#define BDB_SKIP 254 /* VBIOS private block, ignore */
+
+struct bdb_general_features {
+ /* bits 1 */
u8 panel_fitting:2;
u8 flexaim:1;
u8 msg_enable:1;
- u8 clear_screen:1;
+ u8 clear_screen:3;
u8 color_flip:1;
- u8 rsvd7:2; /* finish byte */
+
+ /* bits 2 */
u8 download_ext_vbt:1;
u8 enable_ssc:1;
u8 ssc_freq:1;
u8 enable_lfp_on_override:1;
u8 disable_ssc_ddt:1;
u8 rsvd8:3; /* finish byte */
+
+ /* bits 3 */
u8 disable_smooth_vision:1;
u8 single_dvi:1;
u8 rsvd9:6; /* finish byte */
- u8 legacy_monitor_detect:1;
- u8 rsvd10:7; /* finish byte */
+
+ /* bits 4 */
+ u8 legacy_monitor_detect;
+
+ /* bits 5 */
u8 int_crt_support:1;
u8 int_tv_support:1;
u8 rsvd11:6; /* finish byte */
} __attribute__((packed));
-#define LVDS_CAP_EDID (1 << 6)
-#define LVDS_CAP_DITHER (1 << 5)
-#define LVDS_CAP_PFIT_AUTO_RATIO (1 << 4)
-#define LVDS_CAP_PFIT_GRAPHICS_MODE (1 << 3)
-#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 {
- u8 id; /**< 40 */
- u16 size;
+struct bdb_general_definitions {
+ /* DDC GPIO */
+ u8 crt_ddc_gmbus_pin;
+
+ /* DPMS bits */
+ u8 dpms_acpi:1;
+ u8 skip_boot_crt_detect:1;
+ u8 dpms_aim:1;
+ u8 rsvd1:5; /* finish byte */
+
+ /* boot device bits */
+ u8 boot_display[2];
+ u8 child_dev_size;
+
+ /* device info */
+ u8 tv_or_lvds_info[33];
+ u8 dev1[33];
+ u8 dev2[33];
+ u8 dev3[33];
+ u8 dev4[33];
+ /* may be another device block here on some platforms */
+};
+
+struct bdb_lvds_options {
u8 panel_type;
- u8 reserved0;
- u16 caps;
+ u8 rsvd1;
+ /* LVDS capabilities, stored in a dword */
+ u8 rsvd2:1;
+ u8 lvds_edid:1;
+ u8 pixel_dither:1;
+ u8 pfit_ratio_auto:1;
+ u8 pfit_gfx_mode_enhanced:1;
+ u8 pfit_text_mode_enhanced:1;
+ u8 pfit_mode:2;
+ u8 rsvd4;
} __attribute__((packed));
-struct lvds_bdb_2_fp_params {
+/* LFP pointer table contains entries to the struct below */
+struct bdb_lvds_lfp_data_ptr {
+ u16 fp_timing_offset; /* offsets are from start of bdb */
+ u8 fp_table_size;
+ u16 dvo_timing_offset;
+ u8 dvo_table_size;
+ u16 panel_pnp_id_offset;
+ u8 pnp_table_size;
+} __attribute__((packed));
+
+struct bdb_lvds_lfp_data_ptrs {
+ u8 lvds_entries; /* followed by one or more lvds_data_ptr structs */
+ struct bdb_lvds_lfp_data_ptr ptr[16];
+} __attribute__((packed));
+
+/* LFP data has 3 blocks per entry */
+struct lvds_fp_timing {
u16 x_res;
u16 y_res;
u32 lvds_reg;
@@ -115,42 +204,50 @@ struct lvds_bdb_2_fp_params {
u16 terminator;
} __attribute__((packed));
-struct lvds_bdb_2_fp_edid_dtd {
- u16 dclk; /**< In 10khz */
- u8 hactive;
- u8 hblank;
- u8 high_h; /**< 7:4 = hactive 11:8, 3:0 = hblank 11:8 */
- u8 vactive;
- u8 vblank;
- u8 high_v; /**< 7:4 = vactive 11:8, 3:0 = vblank 11:8 */
- u8 hsync_off;
+struct lvds_dvo_timing {
+ u16 clock; /**< In 10khz */
+ u8 hactive_lo;
+ u8 hblank_lo;
+ u8 hblank_hi:4;
+ u8 hactive_hi:4;
+ u8 vactive_lo;
+ u8 vblank_lo;
+ u8 vblank_hi:4;
+ u8 vactive_hi:4;
+ u8 hsync_off_lo;
u8 hsync_pulse_width;
- u8 vsync_off;
- u8 high_hsync_off; /**< 7:6 = hsync off 9:8 */
+ u8 vsync_pulse_width:4;
+ u8 vsync_off:4;
+ u8 rsvd0:6;
+ u8 hsync_off_hi:2;
u8 h_image;
u8 v_image;
u8 max_hv;
u8 h_border;
u8 v_border;
- u8 flags;
-#define FP_EDID_FLAG_VSYNC_POSITIVE (1 << 2)
-#define FP_EDID_FLAG_HSYNC_POSITIVE (1 << 1)
+ u8 rsvd1:3;
+ u8 digital:2;
+ u8 vsync_positive:1;
+ u8 hsync_positive:1;
+ u8 rsvd2:1;
+} __attribute__((packed));
+
+struct lvds_pnp_id {
+ u16 mfg_name;
+ u16 product_code;
+ u32 serial;
+ u8 mfg_week;
+ u8 mfg_year;
} __attribute__((packed));
-struct lvds_bdb_2_entry {
- u16 fp_params_offset; /**< From beginning of BDB */
- u8 fp_params_size;
- u16 fp_edid_dtd_offset;
- u8 fp_edid_dtd_size;
- u16 fp_edid_pid_offset;
- u8 fp_edid_pid_size;
+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 lvds_bdb_2 {
- u8 id; /**< 41 */
- u16 size;
- u8 table_size; /* not sure on this one */
- struct lvds_bdb_2_entry panels[16];
+struct bdb_lvds_lfp_data {
+ struct bdb_lvds_lfp_data_entry data[16];
} __attribute__((packed));
struct aimdb_header {
@@ -182,6 +279,127 @@ struct vch_bdb_22 {
struct vch_panel_data panels[16];
} __attribute__((packed));
-bool intel_find_bios(struct drm_device *dev);
+bool intel_init_bios(struct drm_device *dev);
+
+/*
+ * Driver<->VBIOS interaction occurs through scratch bits in
+ * GR18 & SWF*.
+ */
+
+/* GR18 bits are set on display switch and hotkey events */
+#define GR18_DRIVER_SWITCH_EN (1<<7) /* 0: VBIOS control, 1: driver control */
+#define GR18_HOTKEY_MASK 0x78 /* See also SWF4 15:0 */
+#define GR18_HK_NONE (0x0<<3)
+#define GR18_HK_LFP_STRETCH (0x1<<3)
+#define GR18_HK_TOGGLE_DISP (0x2<<3)
+#define GR18_HK_DISP_SWITCH (0x4<<3) /* see SWF14 15:0 for what to enable */
+#define GR18_HK_POPUP_DISABLED (0x6<<3)
+#define GR18_HK_POPUP_ENABLED (0x7<<3)
+#define GR18_HK_PFIT (0x8<<3)
+#define GR18_HK_APM_CHANGE (0xa<<3)
+#define GR18_HK_MULTIPLE (0xc<<3)
+#define GR18_USER_INT_EN (1<<2)
+#define GR18_A0000_FLUSH_EN (1<<1)
+#define GR18_SMM_EN (1<<0)
+
+/* Set by driver, cleared by VBIOS */
+#define SWF00_YRES_SHIFT 16
+#define SWF00_XRES_SHIFT 0
+#define SWF00_RES_MASK 0xffff
+
+/* Set by VBIOS at boot time and driver at runtime */
+#define SWF01_TV2_FORMAT_SHIFT 8
+#define SWF01_TV1_FORMAT_SHIFT 0
+#define SWF01_TV_FORMAT_MASK 0xffff
+
+#define SWF10_VBIOS_BLC_I2C_EN (1<<29)
+#define SWF10_GTT_OVERRIDE_EN (1<<28)
+#define SWF10_LFP_DPMS_OVR (1<<27) /* override DPMS on display switch */
+#define SWF10_ACTIVE_TOGGLE_LIST_MASK (7<<24)
+#define SWF10_OLD_TOGGLE 0x0
+#define SWF10_TOGGLE_LIST_1 0x1
+#define SWF10_TOGGLE_LIST_2 0x2
+#define SWF10_TOGGLE_LIST_3 0x3
+#define SWF10_TOGGLE_LIST_4 0x4
+#define SWF10_PANNING_EN (1<<23)
+#define SWF10_DRIVER_LOADED (1<<22)
+#define SWF10_EXTENDED_DESKTOP (1<<21)
+#define SWF10_EXCLUSIVE_MODE (1<<20)
+#define SWF10_OVERLAY_EN (1<<19)
+#define SWF10_PLANEB_HOLDOFF (1<<18)
+#define SWF10_PLANEA_HOLDOFF (1<<17)
+#define SWF10_VGA_HOLDOFF (1<<16)
+#define SWF10_ACTIVE_DISP_MASK 0xffff
+#define SWF10_PIPEB_LFP2 (1<<15)
+#define SWF10_PIPEB_EFP2 (1<<14)
+#define SWF10_PIPEB_TV2 (1<<13)
+#define SWF10_PIPEB_CRT2 (1<<12)
+#define SWF10_PIPEB_LFP (1<<11)
+#define SWF10_PIPEB_EFP (1<<10)
+#define SWF10_PIPEB_TV (1<<9)
+#define SWF10_PIPEB_CRT (1<<8)
+#define SWF10_PIPEA_LFP2 (1<<7)
+#define SWF10_PIPEA_EFP2 (1<<6)
+#define SWF10_PIPEA_TV2 (1<<5)
+#define SWF10_PIPEA_CRT2 (1<<4)
+#define SWF10_PIPEA_LFP (1<<3)
+#define SWF10_PIPEA_EFP (1<<2)
+#define SWF10_PIPEA_TV (1<<1)
+#define SWF10_PIPEA_CRT (1<<0)
+
+#define SWF11_MEMORY_SIZE_SHIFT 16
+#define SWF11_SV_TEST_EN (1<<15)
+#define SWF11_IS_AGP (1<<14)
+#define SWF11_DISPLAY_HOLDOFF (1<<13)
+#define SWF11_DPMS_REDUCED (1<<12)
+#define SWF11_IS_VBE_MODE (1<<11)
+#define SWF11_PIPEB_ACCESS (1<<10) /* 0 here means pipe a */
+#define SWF11_DPMS_MASK 0x07
+#define SWF11_DPMS_OFF (1<<2)
+#define SWF11_DPMS_SUSPEND (1<<1)
+#define SWF11_DPMS_STANDBY (1<<0)
+#define SWF11_DPMS_ON 0
+
+#define SWF14_GFX_PFIT_EN (1<<31)
+#define SWF14_TEXT_PFIT_EN (1<<30)
+#define SWF14_LID_STATUS_CLOSED (1<<29) /* 0 here means open */
+#define SWF14_POPUP_EN (1<<28)
+#define SWF14_DISPLAY_HOLDOFF (1<<27)
+#define SWF14_DISP_DETECT_EN (1<<26)
+#define SWF14_DOCKING_STATUS_DOCKED (1<<25) /* 0 here means undocked */
+#define SWF14_DRIVER_STATUS (1<<24)
+#define SWF14_OS_TYPE_WIN9X (1<<23)
+#define SWF14_OS_TYPE_WINNT (1<<22)
+/* 21:19 rsvd */
+#define SWF14_PM_TYPE_MASK 0x00070000
+#define SWF14_PM_ACPI_VIDEO (0x4 << 16)
+#define SWF14_PM_ACPI (0x3 << 16)
+#define SWF14_PM_APM_12 (0x2 << 16)
+#define SWF14_PM_APM_11 (0x1 << 16)
+#define SWF14_HK_REQUEST_MASK 0x0000ffff /* see GR18 6:3 for event type */
+ /* if GR18 indicates a display switch */
+#define SWF14_DS_PIPEB_LFP2_EN (1<<15)
+#define SWF14_DS_PIPEB_EFP2_EN (1<<14)
+#define SWF14_DS_PIPEB_TV2_EN (1<<13)
+#define SWF14_DS_PIPEB_CRT2_EN (1<<12)
+#define SWF14_DS_PIPEB_LFP_EN (1<<11)
+#define SWF14_DS_PIPEB_EFP_EN (1<<10)
+#define SWF14_DS_PIPEB_TV_EN (1<<9)
+#define SWF14_DS_PIPEB_CRT_EN (1<<8)
+#define SWF14_DS_PIPEA_LFP2_EN (1<<7)
+#define SWF14_DS_PIPEA_EFP2_EN (1<<6)
+#define SWF14_DS_PIPEA_TV2_EN (1<<5)
+#define SWF14_DS_PIPEA_CRT2_EN (1<<4)
+#define SWF14_DS_PIPEA_LFP_EN (1<<3)
+#define SWF14_DS_PIPEA_EFP_EN (1<<2)
+#define SWF14_DS_PIPEA_TV_EN (1<<1)
+#define SWF14_DS_PIPEA_CRT_EN (1<<0)
+ /* if GR18 indicates a panel fitting request */
+#define SWF14_PFIT_EN (1<<0) /* 0 means disable */
+ /* if GR18 indicates an APM change request */
+#define SWF14_APM_HIBERNATE 0x4
+#define SWF14_APM_SUSPEND 0x3
+#define SWF14_APM_STANDBY 0x1
+#define SWF14_APM_RESTORE 0x0
#endif /* _I830_BIOS_H_ */
diff --git a/linux-core/intel_lvds.c b/linux-core/intel_lvds.c
index 1da95e18..6b6d3162 100644
--- a/linux-core/intel_lvds.c
+++ b/linux-core/intel_lvds.c
@@ -380,6 +380,17 @@ void intel_lvds_init(struct drm_device *dev)
output->interlace_allowed = FALSE;
output->doublescan_allowed = FALSE;
+
+ /*
+ * LVDS discovery:
+ * 1) check for EDID on DDC
+ * 2) check for VBT data
+ * 3) check to see if LVDS is already on
+ * if none of the above, no panel
+ * 4) make sure lid is open
+ * if closed, act like it's not there for now
+ */
+
/* Set up the DDC bus. */
intel_output->ddc_bus = intel_i2c_create(dev, GPIOC, "LVDSDDC_C");
if (!intel_output->ddc_bus) {
@@ -402,6 +413,11 @@ void intel_lvds_init(struct drm_device *dev)
}
}
+ /* Failed to get EDID, what about VBT? */
+ if (dev_priv->vbt_mode)
+ dev_priv->panel_fixed_mode =
+ drm_mode_duplicate(dev, dev_priv->vbt_mode);
+
/*
* 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
@@ -424,38 +440,8 @@ void intel_lvds_init(struct drm_device *dev)
if (!dev_priv->panel_fixed_mode)
goto failed;
- /* FIXME: probe the BIOS for modes and check for LVDS quirks */
#if 0
- /* 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 = intel_bios_get_panel_mode(pScrn);
- if (bios_mode != NULL) {
- if (dev_priv->panel_fixed_mode != NULL) {
- if (dev_priv->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);
- }
- } 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;
- }
-
+ /* FIXME: detect aopen & mac mini type stuff automatically? */
/*
* Blacklist machines with BIOSes that list an LVDS panel without
* actually having one.
diff --git a/linux-core/intel_tv.c b/linux-core/intel_tv.c
index 42f4b10b..650c46f7 100644
--- a/linux-core/intel_tv.c
+++ b/linux-core/intel_tv.c
@@ -1620,7 +1620,7 @@ intel_tv_init(struct drm_device *dev)
return;
/* Even if we have an encoder we may not have a connector */
- if (!dev_priv->bdb->int_tv_support)
+ if (!dev_priv->int_tv_support)
return;
/*