Intel_extreme: improve i855 support.
https://github.com/druga/haiku-stuff/tree/master/intel_extreme Rebased against current sources. * The BIOS video mode sometimes reports a scaled mode instead of the physical panel dimensions. Get the data from the VBT table as well, and use it if the reported resolution is bigger. * On first boot, force the panel native mode so the user doesn't have to set it manually. * Only allow a single head at a time on i855gm, as the card can't drive both heads at the same time. * Detect when a new requested mode is the same as the current one, and skip modesetting in that case. Avoids screen flickering when changing workspaces. * Fix some cases of misdetecting which pipes to enable
This commit is contained in:
@@ -173,6 +173,9 @@ struct intel_shared_info {
|
|||||||
addr_t frame_buffer;
|
addr_t frame_buffer;
|
||||||
uint32 frame_buffer_offset;
|
uint32 frame_buffer_offset;
|
||||||
|
|
||||||
|
bool got_vbt;
|
||||||
|
bool single_head_locked;
|
||||||
|
|
||||||
struct lock accelerant_lock;
|
struct lock accelerant_lock;
|
||||||
struct lock engine_lock;
|
struct lock engine_lock;
|
||||||
|
|
||||||
|
|||||||
@@ -74,6 +74,20 @@ struct pll_limits {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static struct display_mode_hook {
|
||||||
|
bool active;
|
||||||
|
display_mode *dm;
|
||||||
|
struct {
|
||||||
|
uint16 width;
|
||||||
|
uint16 height;
|
||||||
|
uint16 space;
|
||||||
|
} mode;
|
||||||
|
} display_mode_hook;
|
||||||
|
|
||||||
|
|
||||||
|
static void mode_fill_missing_bits(display_mode *, uint32);
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
get_i2c_signals(void* cookie, int* _clock, int* _data)
|
get_i2c_signals(void* cookie, int* _clock, int* _data)
|
||||||
{
|
{
|
||||||
@@ -282,6 +296,31 @@ compute_pll_divisors(const display_mode ¤t, pll_divisors& divisors,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
mode_fill_missing_bits(display_mode *mode, uint32 cntrl)
|
||||||
|
{
|
||||||
|
uint32 value = read32(cntrl);
|
||||||
|
|
||||||
|
switch (value & DISPLAY_CONTROL_COLOR_MASK) {
|
||||||
|
case DISPLAY_CONTROL_RGB32:
|
||||||
|
default:
|
||||||
|
mode->space = B_RGB32;
|
||||||
|
break;
|
||||||
|
case DISPLAY_CONTROL_RGB16:
|
||||||
|
mode->space = B_RGB16;
|
||||||
|
break;
|
||||||
|
case DISPLAY_CONTROL_RGB15:
|
||||||
|
mode->space = B_RGB15;
|
||||||
|
break;
|
||||||
|
case DISPLAY_CONTROL_CMAP8:
|
||||||
|
mode->space = B_CMAP8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
mode->flags = B_8_BIT_DAC | B_HARDWARE_CURSOR | B_PARALLEL_ACCESS | B_DPMS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
retrieve_current_mode(display_mode& mode, uint32 pllRegister)
|
retrieve_current_mode(display_mode& mode, uint32 pllRegister)
|
||||||
{
|
{
|
||||||
@@ -411,27 +450,10 @@ retrieve_current_mode(display_mode& mode, uint32 pllRegister)
|
|||||||
if (mode.virtual_height < mode.timing.v_display)
|
if (mode.virtual_height < mode.timing.v_display)
|
||||||
mode.virtual_height = mode.timing.v_display;
|
mode.virtual_height = mode.timing.v_display;
|
||||||
|
|
||||||
value = read32(controlRegister);
|
mode_fill_missing_bits(&mode, controlRegister);
|
||||||
switch (value & DISPLAY_CONTROL_COLOR_MASK) {
|
|
||||||
case DISPLAY_CONTROL_RGB32:
|
|
||||||
default:
|
|
||||||
mode.space = B_RGB32;
|
|
||||||
break;
|
|
||||||
case DISPLAY_CONTROL_RGB16:
|
|
||||||
mode.space = B_RGB16;
|
|
||||||
break;
|
|
||||||
case DISPLAY_CONTROL_RGB15:
|
|
||||||
mode.space = B_RGB15;
|
|
||||||
break;
|
|
||||||
case DISPLAY_CONTROL_CMAP8:
|
|
||||||
mode.space = B_CMAP8;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
mode.h_display_start = 0;
|
mode.h_display_start = 0;
|
||||||
mode.v_display_start = 0;
|
mode.v_display_start = 0;
|
||||||
mode.flags = B_8_BIT_DAC | B_HARDWARE_CURSOR | B_PARALLEL_ACCESS
|
|
||||||
| B_DPMS;
|
|
||||||
if (gInfo->overlay_registers != NULL) {
|
if (gInfo->overlay_registers != NULL) {
|
||||||
mode.flags |= B_SUPPORTS_OVERLAYS;
|
mode.flags |= B_SUPPORTS_OVERLAYS;
|
||||||
}
|
}
|
||||||
@@ -535,12 +557,12 @@ set_frame_buffer_base()
|
|||||||
uint32 baseRegister;
|
uint32 baseRegister;
|
||||||
uint32 surfaceRegister;
|
uint32 surfaceRegister;
|
||||||
|
|
||||||
if (gInfo->head_mode & HEAD_MODE_A_ANALOG) {
|
if (gInfo->head_mode & HEAD_MODE_B_DIGITAL) {
|
||||||
baseRegister = INTEL_DISPLAY_A_BASE;
|
|
||||||
surfaceRegister = INTEL_DISPLAY_A_SURFACE;
|
|
||||||
} else {
|
|
||||||
baseRegister = INTEL_DISPLAY_B_BASE;
|
baseRegister = INTEL_DISPLAY_B_BASE;
|
||||||
surfaceRegister = INTEL_DISPLAY_B_SURFACE;
|
surfaceRegister = INTEL_DISPLAY_B_SURFACE;
|
||||||
|
} else {
|
||||||
|
baseRegister = INTEL_DISPLAY_A_BASE;
|
||||||
|
surfaceRegister = INTEL_DISPLAY_A_SURFACE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sharedInfo.device_type.InGroup(INTEL_TYPE_96x)
|
if (sharedInfo.device_type.InGroup(INTEL_TYPE_96x)
|
||||||
@@ -578,6 +600,8 @@ create_mode_list(void)
|
|||||||
if (error == B_OK) {
|
if (error == B_OK) {
|
||||||
edid_dump(&gInfo->edid_info);
|
edid_dump(&gInfo->edid_info);
|
||||||
gInfo->has_edid = true;
|
gInfo->has_edid = true;
|
||||||
|
if (gInfo->shared_info->single_head_locked)
|
||||||
|
gInfo->head_mode = HEAD_MODE_A_ANALOG;
|
||||||
} else {
|
} else {
|
||||||
TRACE("getting EDID on port A (analog) failed : %s. "
|
TRACE("getting EDID on port A (analog) failed : %s. "
|
||||||
"Trying on port C (lvds)\n", strerror(error));
|
"Trying on port C (lvds)\n", strerror(error));
|
||||||
@@ -593,8 +617,10 @@ create_mode_list(void)
|
|||||||
// We could not read any EDID info. Fallback to creating a list with
|
// We could not read any EDID info. Fallback to creating a list with
|
||||||
// only the mode set up by the BIOS.
|
// only the mode set up by the BIOS.
|
||||||
// TODO: support lower modes via scaling and windowing
|
// TODO: support lower modes via scaling and windowing
|
||||||
if ((gInfo->head_mode & HEAD_MODE_LVDS_PANEL) != 0
|
if (((gInfo->head_mode & HEAD_MODE_LVDS_PANEL) != 0
|
||||||
&& (gInfo->head_mode & HEAD_MODE_A_ANALOG) == 0) {
|
&& (gInfo->head_mode & HEAD_MODE_A_ANALOG) == 0)
|
||||||
|
|| ((gInfo->head_mode & HEAD_MODE_LVDS_PANEL) != 0
|
||||||
|
&& gInfo->shared_info->got_vbt)) {
|
||||||
size_t size = (sizeof(display_mode) + B_PAGE_SIZE - 1)
|
size_t size = (sizeof(display_mode) + B_PAGE_SIZE - 1)
|
||||||
& ~(B_PAGE_SIZE - 1);
|
& ~(B_PAGE_SIZE - 1);
|
||||||
|
|
||||||
@@ -605,7 +631,29 @@ create_mode_list(void)
|
|||||||
if (area < B_OK)
|
if (area < B_OK)
|
||||||
return area;
|
return area;
|
||||||
|
|
||||||
memcpy(list, &gInfo->lvds_panel_mode, sizeof(display_mode));
|
// Prefer information dumped directly from VBT, as the BIOS
|
||||||
|
// one may have display scaling, but only do this if the VBT
|
||||||
|
// resolution is higher than the BIOS one.
|
||||||
|
if (gInfo->shared_info->got_vbt
|
||||||
|
&& gInfo->shared_info->current_mode.virtual_width
|
||||||
|
>= gInfo->lvds_panel_mode.virtual_width
|
||||||
|
&& gInfo->shared_info->current_mode.virtual_height
|
||||||
|
>= gInfo->lvds_panel_mode.virtual_height) {
|
||||||
|
memcpy(list, &gInfo->shared_info->current_mode,
|
||||||
|
sizeof(display_mode));
|
||||||
|
mode_fill_missing_bits(list, INTEL_DISPLAY_B_CONTROL);
|
||||||
|
} else {
|
||||||
|
memcpy(list, &gInfo->lvds_panel_mode,
|
||||||
|
sizeof(display_mode));
|
||||||
|
|
||||||
|
if (gInfo->shared_info->got_vbt)
|
||||||
|
TRACE("intel_extreme: ignoring VBT mode.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// We can also make this the default resolution, if the user
|
||||||
|
// didn't pick one yet.
|
||||||
|
display_mode_hook.active = true;
|
||||||
|
display_mode_hook.dm = list;
|
||||||
|
|
||||||
gInfo->mode_list_area = area;
|
gInfo->mode_list_area = area;
|
||||||
gInfo->mode_list = list;
|
gInfo->mode_list = list;
|
||||||
@@ -717,12 +765,17 @@ intel_propose_display_mode(display_mode* target, const display_mode* low,
|
|||||||
status_t
|
status_t
|
||||||
intel_set_display_mode(display_mode* mode)
|
intel_set_display_mode(display_mode* mode)
|
||||||
{
|
{
|
||||||
TRACE("%s(%" B_PRIu16 "x%" B_PRIu16 ")\n", __func__,
|
if (display_mode_hook.active) {
|
||||||
mode->virtual_width, mode->virtual_height);
|
mode = display_mode_hook.dm;
|
||||||
|
display_mode_hook.active = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (mode == NULL)
|
if (mode == NULL)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
TRACE("%s(%" B_PRIu16 "x%" B_PRIu16 ")\n", __func__,
|
||||||
|
mode->virtual_width, mode->virtual_height);
|
||||||
|
|
||||||
display_mode target = *mode;
|
display_mode target = *mode;
|
||||||
|
|
||||||
// TODO: it may be acceptable to continue when using panel fitting or
|
// TODO: it may be acceptable to continue when using panel fitting or
|
||||||
@@ -736,12 +789,15 @@ intel_set_display_mode(display_mode* mode)
|
|||||||
uint32 colorMode, bytesPerRow, bitsPerPixel;
|
uint32 colorMode, bytesPerRow, bitsPerPixel;
|
||||||
get_color_space_format(target, colorMode, bytesPerRow, bitsPerPixel);
|
get_color_space_format(target, colorMode, bytesPerRow, bitsPerPixel);
|
||||||
|
|
||||||
// TODO: do not go further if the mode is identical to the current one.
|
// avoid screen being off when switching workspaces when they have the same
|
||||||
// This would avoid the screen being off when switching workspaces when they
|
// resolution.
|
||||||
// have the same resolution.
|
if (target.virtual_width == display_mode_hook.mode.width
|
||||||
|
&& target.virtual_height == display_mode_hook.mode.height
|
||||||
|
&& target.space == display_mode_hook.mode.space)
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
static bool first = true;
|
static bool first = tru;
|
||||||
if (first) {
|
if (first) {
|
||||||
int fd = open("/boot/home/ie_.regs", O_CREAT | O_WRONLY, 0644);
|
int fd = open("/boot/home/ie_.regs", O_CREAT | O_WRONLY, 0644);
|
||||||
if (fd >= 0) {
|
if (fd >= 0) {
|
||||||
@@ -1174,6 +1230,10 @@ if (first) {
|
|||||||
sharedInfo.current_mode = target;
|
sharedInfo.current_mode = target;
|
||||||
sharedInfo.bits_per_pixel = bitsPerPixel;
|
sharedInfo.bits_per_pixel = bitsPerPixel;
|
||||||
|
|
||||||
|
display_mode_hook.mode.width = target.virtual_width;
|
||||||
|
display_mode_hook.mode.height = target.virtual_height;
|
||||||
|
display_mode_hook.mode.space = target.space;
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ UsePrivateHeaders graphics kernel ;
|
|||||||
UsePrivateHeaders shared ;
|
UsePrivateHeaders shared ;
|
||||||
|
|
||||||
KernelAddon intel_extreme :
|
KernelAddon intel_extreme :
|
||||||
|
bios.cpp
|
||||||
driver.cpp
|
driver.cpp
|
||||||
device.cpp
|
device.cpp
|
||||||
intel_extreme.cpp
|
intel_extreme.cpp
|
||||||
|
|||||||
@@ -0,0 +1,298 @@
|
|||||||
|
/* Written by Artem Falcon <[email protected]> */
|
||||||
|
|
||||||
|
#include <KernelExport.h>
|
||||||
|
#include "intel_extreme.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define TRACE_BIOS 1
|
||||||
|
#ifdef TRACE_BIOS
|
||||||
|
# define TRACE(x) dprintf x
|
||||||
|
#else
|
||||||
|
# define TRACE(x) ;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* for moving into intel_extreme_private.h */
|
||||||
|
#define VBIOS 0xc0000
|
||||||
|
#define INTEL_VBIOS_SIZE (64 * 1024) /* XXX */
|
||||||
|
|
||||||
|
#define INTEL_BIOS_16(_addr) (vbios.memory[_addr] | \
|
||||||
|
(vbios.memory[_addr + 1] << 8))
|
||||||
|
/* */
|
||||||
|
|
||||||
|
/* subject of including into private/graphics/common/edid* */
|
||||||
|
#define _PIXEL_CLOCK_MHZ(x) (x[0] + (x[1] << 8)) / 100
|
||||||
|
|
||||||
|
#define _PIXEL_CLOCK(x) (x[0] + (x[1] << 8)) * 10000
|
||||||
|
#define _H_ACTIVE(x) (x[2] + ((x[4] & 0xF0) << 4))
|
||||||
|
#define _H_BLANK(x) (x[3] + ((x[4] & 0x0F) << 8))
|
||||||
|
#define _H_SYNC_OFF(x) (x[8] + ((x[11] & 0xC0) << 2))
|
||||||
|
#define _H_SYNC_WIDTH(x) (x[9] + ((x[11] & 0x30) << 4))
|
||||||
|
#define _V_ACTIVE(x) (x[5] + ((x[7] & 0xF0) << 4))
|
||||||
|
#define _V_BLANK(x) (x[6] + ((x[7] & 0x0F) << 8))
|
||||||
|
#define _V_SYNC_OFF(x) ((x[10] >> 4) + ((x[11] & 0x0C) << 2))
|
||||||
|
#define _V_SYNC_WIDTH(x) ((x[10] & 0x0F) + ((x[11] & 0x03) << 4))
|
||||||
|
/* */
|
||||||
|
|
||||||
|
struct vbt_header {
|
||||||
|
uint8 signature[20];
|
||||||
|
uint16 version;
|
||||||
|
uint16 header_size;
|
||||||
|
uint16 vbt_size;
|
||||||
|
uint8 vbt_checksum;
|
||||||
|
uint8 reserved0;
|
||||||
|
uint32 bdb_offset;
|
||||||
|
uint32 aim_offset[4];
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct bdb_header {
|
||||||
|
uint8 signature[16];
|
||||||
|
uint16 version;
|
||||||
|
uint16 header_size;
|
||||||
|
uint16 bdb_size;
|
||||||
|
/* cutted */
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct lvds_bdb1 {
|
||||||
|
uint8 id;
|
||||||
|
uint16 size;
|
||||||
|
uint8 panel_type;
|
||||||
|
uint8 reserved0;
|
||||||
|
uint16 caps;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct lvds_bdb2_entry {
|
||||||
|
uint16 lfp_info_offset;
|
||||||
|
uint8 lfp_info_size;
|
||||||
|
uint16 lfp_edid_dtd_offset;
|
||||||
|
uint8 lfp_edid_dtd_size;
|
||||||
|
uint16 lfp_edid_pid_offset;
|
||||||
|
uint8 lfp_edid_pid_size;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct lvds_bdb2 {
|
||||||
|
uint8 id;
|
||||||
|
uint16 size;
|
||||||
|
uint8 table_size; /* unapproved */
|
||||||
|
struct lvds_bdb2_entry panels[16];
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct lvds_bdb2_lfp_info {
|
||||||
|
uint16 x_res;
|
||||||
|
uint16 y_res;
|
||||||
|
uint32 lvds_reg;
|
||||||
|
uint32 lvds_reg_val;
|
||||||
|
uint32 pp_on_reg;
|
||||||
|
uint32 pp_on_reg_val;
|
||||||
|
uint32 pp_off_reg;
|
||||||
|
uint32 pp_off_reg_val;
|
||||||
|
uint32 pp_cycle_reg;
|
||||||
|
uint32 pp_cycle_reg_val;
|
||||||
|
uint32 pfit_reg;
|
||||||
|
uint32 pfit_reg_val;
|
||||||
|
uint16 terminator;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
static struct vbios {
|
||||||
|
area_id area;
|
||||||
|
uint8* memory;
|
||||||
|
display_mode *shared_info;
|
||||||
|
struct {
|
||||||
|
uint16 hsync_start;
|
||||||
|
uint16 hsync_end;
|
||||||
|
uint16 hsync_total;
|
||||||
|
uint16 vsync_start;
|
||||||
|
uint16 vsync_end;
|
||||||
|
uint16 vsync_total;
|
||||||
|
} timings_common;
|
||||||
|
} vbios;
|
||||||
|
|
||||||
|
static inline bool unmap_bios(area_id area, uint8* mem) {
|
||||||
|
delete_area(area);
|
||||||
|
mem = NULL;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TO-DO: move to accelerant code, if possible */
|
||||||
|
|
||||||
|
/* this is reimplementation, Haiku uses BIOS call and gets most
|
||||||
|
* current panel info, we're, otherwise, digging in VBIOS memory
|
||||||
|
* and parsing VBT tables to get native panel timings. This will
|
||||||
|
* allow to get non-updated, PROM-programmed timings info when
|
||||||
|
* compensation mode is off on your machine */
|
||||||
|
static bool
|
||||||
|
get_bios(void)
|
||||||
|
{
|
||||||
|
int vbt_offset;
|
||||||
|
struct vbt_header *vbt;
|
||||||
|
|
||||||
|
/* !!!DANGER!!!: mapping of BIOS using legacy location for now,
|
||||||
|
* hence, if panel mode will be set using info from VBT, it will
|
||||||
|
* be taken from primary card's VBIOS */
|
||||||
|
vbios.area = map_physical_memory("VBIOS mapping",
|
||||||
|
VBIOS, INTEL_VBIOS_SIZE, B_ANY_KERNEL_ADDRESS,
|
||||||
|
B_READ_AREA, (void**)&(vbios.memory));
|
||||||
|
|
||||||
|
if (vbios.area < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
TRACE((DEVICE_NAME ": mapping VBIOS: 0x%x -> %p\n",
|
||||||
|
VBIOS, vbios.memory));
|
||||||
|
|
||||||
|
vbt_offset = INTEL_BIOS_16(0x1a);
|
||||||
|
if (vbt_offset >= INTEL_VBIOS_SIZE) {
|
||||||
|
TRACE(("intel_extreme: bad VBT offset : 0x%x\n",
|
||||||
|
vbt_offset));
|
||||||
|
return unmap_bios(vbios.area, vbios.memory);
|
||||||
|
}
|
||||||
|
|
||||||
|
vbt = (struct vbt_header *)(vbios.memory + vbt_offset);
|
||||||
|
if (memcmp(vbt->signature, "$VBT", 4) != 0) {
|
||||||
|
TRACE(("intel_extreme: bad VBT signature: %20s\n",
|
||||||
|
vbt->signature));
|
||||||
|
return unmap_bios(vbios.area, vbios.memory);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool feed_shared_info(uint8* data)
|
||||||
|
{
|
||||||
|
bool bogus = false;
|
||||||
|
|
||||||
|
/* handle bogus h/vtotal values, if got such */
|
||||||
|
if (vbios.timings_common.hsync_end > vbios.timings_common.hsync_total) {
|
||||||
|
vbios.timings_common.hsync_total =
|
||||||
|
vbios.timings_common.hsync_end + 1;
|
||||||
|
bogus = true;
|
||||||
|
TRACE(("intel_extreme: got bogus htotal. Fixing\n"));
|
||||||
|
}
|
||||||
|
if (vbios.timings_common.vsync_end > vbios.timings_common.vsync_total) {
|
||||||
|
vbios.timings_common.vsync_total =
|
||||||
|
vbios.timings_common.vsync_end + 1;
|
||||||
|
bogus = true;
|
||||||
|
TRACE(("intel_extreme: got bogus vtotal. Fixing\n"));
|
||||||
|
}
|
||||||
|
/* */
|
||||||
|
if (bogus)
|
||||||
|
TRACE(("intel_extreme: adjusted LFP modeline: x%d Hz,\t%d "
|
||||||
|
"%d %d %d %d %d %d %d %d\n",
|
||||||
|
_PIXEL_CLOCK(data) / (
|
||||||
|
(_H_ACTIVE(data) + _H_BLANK(data))
|
||||||
|
* (_V_ACTIVE(data) + _V_BLANK(data))
|
||||||
|
),
|
||||||
|
_PIXEL_CLOCK_MHZ(data),
|
||||||
|
_H_ACTIVE(data), vbios.timings_common.hsync_start,
|
||||||
|
vbios.timings_common.hsync_end, vbios.timings_common.hsync_total,
|
||||||
|
_V_ACTIVE(data), vbios.timings_common.vsync_start,
|
||||||
|
vbios.timings_common.vsync_end, vbios.timings_common.vsync_total
|
||||||
|
));
|
||||||
|
|
||||||
|
/* TO-DO: add retrieved info to edid info struct, not fixed mode struct */
|
||||||
|
|
||||||
|
/* struct display_timing is not packed, so we're end setting of every single elm of it */
|
||||||
|
vbios.shared_info->timing.pixel_clock = _PIXEL_CLOCK(data) / 1000;
|
||||||
|
vbios.shared_info->timing.h_display = vbios.shared_info->virtual_width = _H_ACTIVE(data);
|
||||||
|
vbios.shared_info->timing.h_sync_start = vbios.timings_common.hsync_start;
|
||||||
|
vbios.shared_info->timing.h_sync_end = vbios.timings_common.hsync_end;
|
||||||
|
vbios.shared_info->timing.h_total = vbios.timings_common.hsync_total;
|
||||||
|
vbios.shared_info->timing.v_display = vbios.shared_info->virtual_height = _V_ACTIVE(data);
|
||||||
|
vbios.shared_info->timing.v_sync_start = vbios.timings_common.vsync_start;
|
||||||
|
vbios.shared_info->timing.v_sync_end = vbios.timings_common.vsync_end;
|
||||||
|
vbios.shared_info->timing.v_total = vbios.timings_common.vsync_total;
|
||||||
|
|
||||||
|
unmap_bios(vbios.area, vbios.memory);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get_lvds_mode_from_bios(display_mode *shared_info)
|
||||||
|
{
|
||||||
|
struct vbt_header *vbt;
|
||||||
|
struct bdb_header *bdb;
|
||||||
|
int vbt_offset, bdb_offset, bdb_block_offset, block_size;
|
||||||
|
int panel_type = -1;
|
||||||
|
|
||||||
|
if (!get_bios())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
vbt_offset = INTEL_BIOS_16(0x1a);
|
||||||
|
vbt = (struct vbt_header *)(vbios.memory + vbt_offset);
|
||||||
|
bdb_offset = vbt_offset + vbt->bdb_offset;
|
||||||
|
|
||||||
|
bdb = (struct bdb_header *)(vbios.memory + bdb_offset);
|
||||||
|
if (memcmp(bdb->signature, "BIOS_DATA_BLOCK ", 16) != 0) {
|
||||||
|
TRACE(("intel_extreme: bad BDB signature\n"));
|
||||||
|
return unmap_bios(vbios.area, vbios.memory);
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE(("intel_extreme: parsing BDB blocks\n"));
|
||||||
|
for (bdb_block_offset = bdb->header_size; bdb_block_offset < bdb->bdb_size;
|
||||||
|
bdb_block_offset += block_size) {
|
||||||
|
int start = bdb_offset + bdb_block_offset;
|
||||||
|
int id;
|
||||||
|
struct lvds_bdb1 *lvds1;
|
||||||
|
struct lvds_bdb2 *lvds2;
|
||||||
|
struct lvds_bdb2_lfp_info *lvds2_lfp_info;
|
||||||
|
uint8_t *timing_data;
|
||||||
|
|
||||||
|
id = vbios.memory[start];
|
||||||
|
block_size = INTEL_BIOS_16(start + 1) + 3;
|
||||||
|
//TRACE(("intel_extreme: found BDB block type %d\n", id));
|
||||||
|
switch (id) {
|
||||||
|
case 40:
|
||||||
|
lvds1 = (struct lvds_bdb1 *)(vbios.memory + start);
|
||||||
|
panel_type = lvds1->panel_type;
|
||||||
|
break;
|
||||||
|
case 41:
|
||||||
|
if (panel_type == -1)
|
||||||
|
break;
|
||||||
|
lvds2 = (struct lvds_bdb2 *)(vbios.memory + start);
|
||||||
|
lvds2_lfp_info = (struct lvds_bdb2_lfp_info *)
|
||||||
|
(vbios.memory + bdb_offset +
|
||||||
|
lvds2->panels[panel_type].lfp_info_offset);
|
||||||
|
/* found bad one terminator */
|
||||||
|
if (lvds2_lfp_info->terminator != 0xffff) {
|
||||||
|
return unmap_bios(vbios.area, vbios.memory);
|
||||||
|
}
|
||||||
|
timing_data = vbios.memory + bdb_offset +
|
||||||
|
lvds2->panels[panel_type].lfp_edid_dtd_offset;
|
||||||
|
TRACE(("intel_extreme: found LFP of size %d x %d "
|
||||||
|
"in BIOS VBT tables\n",
|
||||||
|
lvds2_lfp_info->x_res, lvds2_lfp_info->y_res));
|
||||||
|
|
||||||
|
vbios.timings_common.hsync_start = _H_ACTIVE(timing_data) +
|
||||||
|
_H_SYNC_OFF(timing_data);
|
||||||
|
vbios.timings_common.hsync_end = vbios.timings_common.hsync_start
|
||||||
|
+ _H_SYNC_WIDTH(timing_data);
|
||||||
|
vbios.timings_common.hsync_total = _H_ACTIVE(timing_data) +
|
||||||
|
_H_BLANK(timing_data);
|
||||||
|
vbios.timings_common.vsync_start = _V_ACTIVE(timing_data) +
|
||||||
|
_V_SYNC_OFF(timing_data);
|
||||||
|
vbios.timings_common.vsync_end = vbios.timings_common.vsync_start
|
||||||
|
+ _V_SYNC_WIDTH(timing_data);
|
||||||
|
vbios.timings_common.vsync_total = _V_ACTIVE(timing_data) +
|
||||||
|
_V_BLANK(timing_data);
|
||||||
|
|
||||||
|
/* Xfree86 compatible modeline */
|
||||||
|
/*TRACE(("intel_extreme: LFP modeline: x%d Hz,\t%d "
|
||||||
|
"%d %d %d %d %d %d %d %d\n",
|
||||||
|
_PIXEL_CLOCK(timing_data) / (
|
||||||
|
(_H_ACTIVE(timing_data) + _H_BLANK(timing_data))
|
||||||
|
* (_V_ACTIVE(timing_data) + _V_BLANK(timing_data))
|
||||||
|
),
|
||||||
|
_PIXEL_CLOCK_MHZ(timing_data),
|
||||||
|
_H_ACTIVE(timing_data), vbios.timings_common.hsync_start,
|
||||||
|
vbios.timings_common.hsync_end, vbios.timings_common.hsync_total,
|
||||||
|
_V_ACTIVE(timing_data), vbios.timings_common.vsync_start,
|
||||||
|
vbios.timings_common.vsync_end, vbios.timings_common.vsync_total
|
||||||
|
));*/
|
||||||
|
|
||||||
|
vbios.shared_info = shared_info;
|
||||||
|
return feed_shared_info(timing_data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unmap_bios(vbios.area, vbios.memory);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
@@ -333,6 +333,12 @@ intel_extreme_init(intel_info &info)
|
|||||||
info.shared_info->frame_buffer = 0;
|
info.shared_info->frame_buffer = 0;
|
||||||
info.shared_info->dpms_mode = B_DPMS_ON;
|
info.shared_info->dpms_mode = B_DPMS_ON;
|
||||||
|
|
||||||
|
info.shared_info->got_vbt = get_lvds_mode_from_bios(
|
||||||
|
&info.shared_info->current_mode);
|
||||||
|
/* at least 855gm can't drive more than one head at time */
|
||||||
|
if (info.device_type.InFamily(INTEL_TYPE_8xx))
|
||||||
|
info.shared_info->single_head_locked = 1;
|
||||||
|
|
||||||
if (info.device_type.InFamily(INTEL_TYPE_9xx)) {
|
if (info.device_type.InFamily(INTEL_TYPE_9xx)) {
|
||||||
info.shared_info->pll_info.reference_frequency = 96000; // 96 kHz
|
info.shared_info->pll_info.reference_frequency = 96000; // 96 kHz
|
||||||
info.shared_info->pll_info.max_frequency = 400000;
|
info.shared_info->pll_info.max_frequency = 400000;
|
||||||
|
|||||||
Reference in New Issue
Block a user