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;
|
||||
uint32 frame_buffer_offset;
|
||||
|
||||
bool got_vbt;
|
||||
bool single_head_locked;
|
||||
|
||||
struct lock accelerant_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
|
||||
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
|
||||
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)
|
||||
mode.virtual_height = mode.timing.v_display;
|
||||
|
||||
value = read32(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_fill_missing_bits(&mode, controlRegister);
|
||||
|
||||
mode.h_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) {
|
||||
mode.flags |= B_SUPPORTS_OVERLAYS;
|
||||
}
|
||||
@@ -535,12 +557,12 @@ set_frame_buffer_base()
|
||||
uint32 baseRegister;
|
||||
uint32 surfaceRegister;
|
||||
|
||||
if (gInfo->head_mode & HEAD_MODE_A_ANALOG) {
|
||||
baseRegister = INTEL_DISPLAY_A_BASE;
|
||||
surfaceRegister = INTEL_DISPLAY_A_SURFACE;
|
||||
} else {
|
||||
if (gInfo->head_mode & HEAD_MODE_B_DIGITAL) {
|
||||
baseRegister = INTEL_DISPLAY_B_BASE;
|
||||
surfaceRegister = INTEL_DISPLAY_B_SURFACE;
|
||||
} else {
|
||||
baseRegister = INTEL_DISPLAY_A_BASE;
|
||||
surfaceRegister = INTEL_DISPLAY_A_SURFACE;
|
||||
}
|
||||
|
||||
if (sharedInfo.device_type.InGroup(INTEL_TYPE_96x)
|
||||
@@ -578,6 +600,8 @@ create_mode_list(void)
|
||||
if (error == B_OK) {
|
||||
edid_dump(&gInfo->edid_info);
|
||||
gInfo->has_edid = true;
|
||||
if (gInfo->shared_info->single_head_locked)
|
||||
gInfo->head_mode = HEAD_MODE_A_ANALOG;
|
||||
} else {
|
||||
TRACE("getting EDID on port A (analog) failed : %s. "
|
||||
"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
|
||||
// only the mode set up by the BIOS.
|
||||
// TODO: support lower modes via scaling and windowing
|
||||
if ((gInfo->head_mode & HEAD_MODE_LVDS_PANEL) != 0
|
||||
&& (gInfo->head_mode & HEAD_MODE_A_ANALOG) == 0) {
|
||||
if (((gInfo->head_mode & HEAD_MODE_LVDS_PANEL) != 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)
|
||||
& ~(B_PAGE_SIZE - 1);
|
||||
|
||||
@@ -605,7 +631,29 @@ create_mode_list(void)
|
||||
if (area < B_OK)
|
||||
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 = list;
|
||||
@@ -717,12 +765,17 @@ intel_propose_display_mode(display_mode* target, const display_mode* low,
|
||||
status_t
|
||||
intel_set_display_mode(display_mode* mode)
|
||||
{
|
||||
TRACE("%s(%" B_PRIu16 "x%" B_PRIu16 ")\n", __func__,
|
||||
mode->virtual_width, mode->virtual_height);
|
||||
if (display_mode_hook.active) {
|
||||
mode = display_mode_hook.dm;
|
||||
display_mode_hook.active = false;
|
||||
}
|
||||
|
||||
if (mode == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
TRACE("%s(%" B_PRIu16 "x%" B_PRIu16 ")\n", __func__,
|
||||
mode->virtual_width, mode->virtual_height);
|
||||
|
||||
display_mode target = *mode;
|
||||
|
||||
// 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;
|
||||
get_color_space_format(target, colorMode, bytesPerRow, bitsPerPixel);
|
||||
|
||||
// TODO: do not go further if the mode is identical to the current one.
|
||||
// This would avoid the screen being off when switching workspaces when they
|
||||
// have the same resolution.
|
||||
// avoid screen being off when switching workspaces when they 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
|
||||
static bool first = true;
|
||||
static bool first = tru;
|
||||
if (first) {
|
||||
int fd = open("/boot/home/ie_.regs", O_CREAT | O_WRONLY, 0644);
|
||||
if (fd >= 0) {
|
||||
@@ -1174,6 +1230,10 @@ if (first) {
|
||||
sharedInfo.current_mode = target;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ UsePrivateHeaders graphics kernel ;
|
||||
UsePrivateHeaders shared ;
|
||||
|
||||
KernelAddon intel_extreme :
|
||||
bios.cpp
|
||||
driver.cpp
|
||||
device.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->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)) {
|
||||
info.shared_info->pll_info.reference_frequency = 96000; // 96 kHz
|
||||
info.shared_info->pll_info.max_frequency = 400000;
|
||||
|
||||
Reference in New Issue
Block a user