mirror of
https://gitlab.freedesktop.org/mesa/drm.git
synced 2026-01-01 18:50:15 +01:00
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:
parent
b4d8cda8e6
commit
9fc4ea5c00
7 changed files with 461 additions and 257 deletions
|
|
@ -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++)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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_ */
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue