OSDN Git Service

i915: do a better job of parsing VBIOS data
authorJesse Barnes <jbarnes@jbarnes-t61.(none)>
Sat, 24 May 2008 01:42:47 +0000 (18:42 -0700)
committerJesse Barnes <jbarnes@virtuousgeek.org>
Sat, 24 May 2008 01:42:47 +0000 (18:42 -0700)
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.

linux-core/i915_drv.c
linux-core/intel_bios.c
linux-core/intel_bios.h
linux-core/intel_lvds.c
linux-core/intel_tv.c
shared-core/i915_drv.h
shared-core/i915_init.c

index 27c239d..51262d7 100644 (file)
@@ -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++)
index 7f8e851..f124fa1 100644 (file)
 #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;
+}
index b17856d..5ea715a 100644 (file)
@@ -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_ */
index 1da95e1..6b6d316 100644 (file)
@@ -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.
index 42f4b10..650c46f 100644 (file)
@@ -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;
 
        /*
index 84cc60f..c5e22f7 100644 (file)
@@ -174,14 +174,17 @@ struct drm_i915_private {
        int backlight_duty_cycle;  /* restore backlight to this value */
        bool panel_wants_dither;
        struct drm_display_mode *panel_fixed_mode;
+       struct drm_display_mode *vbt_mode; /* if any */
 
        /* DRI2 sarea */
        struct drm_buffer_object *sarea_bo;
        struct drm_bo_kmap_obj sarea_kmap;
 
-       /* BIOS data */
-       struct vbt_header *vbt;
-       struct bdb_header *bdb;
+       /* Feature bits from the VBIOS */
+       int int_tv_support:1;
+       int lvds_dither:1;
+       int lvds_vbt:1;
+       int int_crt_support:1;
 
        /* Register state */
        u8 saveLBB;
@@ -1680,15 +1683,16 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
 #define DSPATILEOFF            0x701A4 /* 965+ only */
 
 /* VBIOS flags */
-#define SWF0                   0x71410
-#define SWF1                   0x71414
-#define SWF2                   0x71418
-#define SWF3                   0x7141c
-#define SWF4                   0x71420
-#define SWF5                   0x71424
-#define SWF6                   0x71428
-
+#define SWF00                  0x71410
+#define SWF01                  0x71414
+#define SWF02                  0x71418
+#define SWF03                  0x7141c
+#define SWF04                  0x71420
+#define SWF05                  0x71424
+#define SWF06                  0x71428
 #define SWF10                  0x70410
+#define SWF11                  0x70414
+#define SWF14                  0x71420
 #define SWF30                  0x72414
 #define SWF31                  0x72418
 #define SWF32                  0x7241c
index f5fe5ba..bda15e0 100644 (file)
@@ -224,9 +224,9 @@ int i915_load_modeset_init(struct drm_device *dev)
                goto destroy_hws;
        }
 
-       ret = intel_find_bios(dev);
+       ret = intel_init_bios(dev);
        if (ret) {
-               DRM_ERROR("failed to find VBT\n");
+               DRM_ERROR("failed to find VBIOS tables\n");
                ret = -ENODEV;
                goto destroy_wq;
        }