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.
This commit is contained in:
Jesse Barnes 2008-05-23 18:42:47 -07:00 committed by Jesse Barnes
parent b4d8cda8e6
commit 9fc4ea5c00
7 changed files with 461 additions and 257 deletions

View 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++)

View file

@ -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;
}

View 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_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 lvds_pnp_id {
u16 mfg_name;
u16 product_code;
u32 serial;
u8 mfg_week;
u8 mfg_year;
} __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_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 {
@ -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_ */

View 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.

View 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;
/*

View 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

View 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;
}