* The boot loader now creates a CRTCInfoBlock structure when detailed EDID
mode informations are available. * This is passed to the graphics card when the mode is set in the hopes that it will be more conforming. * Not yet tested on real hardware, though, therefore the VESA driver doesn't do anything like this yet. I will test next, but please report any problems with this nonetheless. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@28390 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
** Copyright 2004, Axel Dörfler, [email protected]. All rights reserved.
|
* Copyright 2004-2008, Axel Dörfler, [email protected].
|
||||||
** Distributed under the terms of the OpenBeOS License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
#ifndef VESA_H
|
#ifndef VESA_H
|
||||||
#define VESA_H
|
#define VESA_H
|
||||||
|
|
||||||
@@ -119,6 +119,28 @@ struct vbe_mode_info {
|
|||||||
#define SET_MODE_DONT_CLEAR_MEMORY (1 << 15)
|
#define SET_MODE_DONT_CLEAR_MEMORY (1 << 15)
|
||||||
|
|
||||||
|
|
||||||
|
/* CRTC info block structure */
|
||||||
|
|
||||||
|
struct crtc_info_block {
|
||||||
|
uint16 horizontal_total;
|
||||||
|
uint16 horizontal_sync_start;
|
||||||
|
uint16 horizontal_sync_end;
|
||||||
|
uint16 vertical_total;
|
||||||
|
uint16 vertical_sync_start;
|
||||||
|
uint16 vertical_sync_end;
|
||||||
|
uint8 flags;
|
||||||
|
uint32 pixel_clock; // in Hz
|
||||||
|
uint16 refresh_rate; // in 0.01 Hz
|
||||||
|
|
||||||
|
uint8 _reserved[40];
|
||||||
|
} _PACKED;
|
||||||
|
|
||||||
|
#define CRTC_DOUBLE_SCAN 0x01
|
||||||
|
#define CRTC_INTERLACED 0x02
|
||||||
|
#define CRTC_NEGATIVE_HSYNC 0x04
|
||||||
|
#define CRTC_NEGATIVE_VSYNC 0x08
|
||||||
|
|
||||||
|
|
||||||
/* VBE 3.0 protected mode interface
|
/* VBE 3.0 protected mode interface
|
||||||
* The BIOS area can be scanned for the protected mode
|
* The BIOS area can be scanned for the protected mode
|
||||||
* signature that identifies the structure below.
|
* signature that identifies the structure below.
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ struct video_mode {
|
|||||||
uint16 mode;
|
uint16 mode;
|
||||||
uint16 width, height, bits_per_pixel;
|
uint16 width, height, bits_per_pixel;
|
||||||
uint32 bytes_per_row;
|
uint32 bytes_per_row;
|
||||||
|
crtc_info_block* timing;
|
||||||
};
|
};
|
||||||
|
|
||||||
static vbe_info_block sInfo;
|
static vbe_info_block sInfo;
|
||||||
@@ -149,40 +150,99 @@ closest_video_mode(int32 width, int32 height, int32 depth)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static video_mode *
|
static crtc_info_block*
|
||||||
find_edid_mode(edid1_info &info, bool allowPalette)
|
get_crtc_info_block(edid1_detailed_timing& timing)
|
||||||
|
{
|
||||||
|
// Copy timing structure to set the mode with
|
||||||
|
crtc_info_block* crtcInfo = (crtc_info_block*)malloc(
|
||||||
|
sizeof(crtc_info_block));
|
||||||
|
if (crtcInfo == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
memset(crtcInfo, 0, sizeof(crtc_info_block));
|
||||||
|
crtcInfo->horizontal_sync_start = timing.h_active + timing.h_sync_off;
|
||||||
|
crtcInfo->horizontal_sync_end = crtcInfo->horizontal_sync_start
|
||||||
|
+ timing.h_sync_width;
|
||||||
|
crtcInfo->horizontal_total = timing.h_active + timing.h_blank;
|
||||||
|
crtcInfo->vertical_sync_start = timing.v_active + timing.v_sync_off;
|
||||||
|
crtcInfo->vertical_sync_end = crtcInfo->vertical_sync_start
|
||||||
|
+ timing.v_sync_width;
|
||||||
|
crtcInfo->vertical_total = timing.v_active + timing.v_blank;
|
||||||
|
crtcInfo->pixel_clock = timing.pixel_clock * 10000L;
|
||||||
|
crtcInfo->refresh_rate = crtcInfo->pixel_clock
|
||||||
|
/ (crtcInfo->horizontal_total / 10)
|
||||||
|
/ (crtcInfo->vertical_total / 10);
|
||||||
|
|
||||||
|
crtcInfo->flags = 0;
|
||||||
|
if (timing.sync == 3) {
|
||||||
|
// TODO: this switches the default sync when sync != 3 (compared to
|
||||||
|
// create_display_modes().
|
||||||
|
if ((timing.misc & 1) == 0)
|
||||||
|
crtcInfo->flags |= CRTC_NEGATIVE_HSYNC;
|
||||||
|
if ((timing.misc & 2) == 0)
|
||||||
|
crtcInfo->flags |= CRTC_NEGATIVE_VSYNC;
|
||||||
|
}
|
||||||
|
if (timing.interlaced)
|
||||||
|
crtcInfo->flags |= CRTC_INTERLACED;
|
||||||
|
|
||||||
|
return crtcInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static crtc_info_block*
|
||||||
|
get_crtc_info_block(edid1_std_timing& timing)
|
||||||
|
{
|
||||||
|
// TODO: implement me!
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static video_mode*
|
||||||
|
find_edid_mode(edid1_info& info, bool allowPalette)
|
||||||
{
|
{
|
||||||
video_mode *mode = NULL;
|
video_mode *mode = NULL;
|
||||||
|
|
||||||
// try detailed timing first
|
// try detailed timing first
|
||||||
for (int32 i = 0; i < EDID1_NUM_DETAILED_MONITOR_DESC; i++) {
|
for (int32 i = 0; i < EDID1_NUM_DETAILED_MONITOR_DESC; i++) {
|
||||||
edid1_detailed_monitor &monitor = info.detailed_monitor[i];
|
edid1_detailed_monitor& monitor = info.detailed_monitor[i];
|
||||||
|
|
||||||
if (monitor.monitor_desc_type == EDID1_IS_DETAILED_TIMING) {
|
if (monitor.monitor_desc_type == EDID1_IS_DETAILED_TIMING) {
|
||||||
mode = find_video_mode(monitor.data.detailed_timing.h_active,
|
mode = find_video_mode(monitor.data.detailed_timing.h_active,
|
||||||
monitor.data.detailed_timing.v_active, allowPalette);
|
monitor.data.detailed_timing.v_active, allowPalette);
|
||||||
if (mode != NULL)
|
if (mode != NULL) {
|
||||||
|
mode->timing
|
||||||
|
= get_crtc_info_block(monitor.data.detailed_timing);
|
||||||
return mode;
|
return mode;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32 best = -1;
|
||||||
|
|
||||||
// try standard timings next
|
// try standard timings next
|
||||||
for (int32 i = 0; i < EDID1_NUM_STD_TIMING; i++) {
|
for (int32 i = 0; i < EDID1_NUM_STD_TIMING; i++) {
|
||||||
if (info.std_timing[i].h_size <= 256)
|
if (info.std_timing[i].h_size <= 256)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
video_mode *found = find_video_mode(info.std_timing[i].h_size,
|
video_mode* found = find_video_mode(info.std_timing[i].h_size,
|
||||||
info.std_timing[i].v_size, allowPalette);
|
info.std_timing[i].v_size, allowPalette);
|
||||||
if (found != NULL) {
|
if (found != NULL) {
|
||||||
if (mode != NULL) {
|
if (mode != NULL) {
|
||||||
// prefer higher resolutions
|
// prefer higher resolutions
|
||||||
if (found->width > mode->width)
|
if (found->width > mode->width) {
|
||||||
mode = found;
|
mode = found;
|
||||||
} else
|
best = i;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
mode = found;
|
mode = found;
|
||||||
|
best = i;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (best >= 0)
|
||||||
|
mode->timing = get_crtc_info_block(info.std_timing[best]);
|
||||||
|
|
||||||
return mode;
|
return mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -413,6 +473,8 @@ vesa_init(vbe_info_block *info, video_mode **_standardMode)
|
|||||||
videoMode->width = modeInfo.width;
|
videoMode->width = modeInfo.width;
|
||||||
videoMode->height = modeInfo.height;
|
videoMode->height = modeInfo.height;
|
||||||
videoMode->bits_per_pixel = modeInfo.bits_per_pixel;
|
videoMode->bits_per_pixel = modeInfo.bits_per_pixel;
|
||||||
|
videoMode->timing = NULL;
|
||||||
|
|
||||||
if (modeInfo.bits_per_pixel == 16
|
if (modeInfo.bits_per_pixel == 16
|
||||||
&& modeInfo.red_mask_size + modeInfo.green_mask_size
|
&& modeInfo.red_mask_size + modeInfo.green_mask_size
|
||||||
+ modeInfo.blue_mask_size == 15) {
|
+ modeInfo.blue_mask_size == 15) {
|
||||||
@@ -472,11 +534,18 @@ vesa_get_mode(uint16 *_mode)
|
|||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
vesa_set_mode(uint16 mode)
|
vesa_set_mode(video_mode* mode)
|
||||||
{
|
{
|
||||||
struct bios_regs regs;
|
struct bios_regs regs;
|
||||||
regs.eax = 0x4f02;
|
regs.eax = 0x4f02;
|
||||||
regs.ebx = (mode & SET_MODE_MASK) | SET_MODE_LINEAR_BUFFER;
|
regs.ebx = (mode->mode & SET_MODE_MASK) | SET_MODE_LINEAR_BUFFER;
|
||||||
|
|
||||||
|
if (mode->timing != NULL) {
|
||||||
|
regs.ebx |= SET_MODE_SPECIFY_CRTC;
|
||||||
|
regs.es = ADDRESS_SEGMENT(mode->timing);
|
||||||
|
regs.edi = ADDRESS_OFFSET(mode->timing);
|
||||||
|
}
|
||||||
|
|
||||||
call_bios(0x10, ®s);
|
call_bios(0x10, ®s);
|
||||||
|
|
||||||
if ((regs.eax & 0xffff) != 0x4f)
|
if ((regs.eax & 0xffff) != 0x4f)
|
||||||
@@ -904,7 +973,7 @@ platform_switch_to_logo(void)
|
|||||||
// getting the EDID data and setting the video mode. As such we wait here briefly to give
|
// getting the EDID data and setting the video mode. As such we wait here briefly to give
|
||||||
// everything enough time to settle.
|
// everything enough time to settle.
|
||||||
spin(1000);
|
spin(1000);
|
||||||
if (vesa_set_mode(sMode->mode) != B_OK)
|
if (vesa_set_mode(sMode) != B_OK)
|
||||||
goto fallback;
|
goto fallback;
|
||||||
|
|
||||||
struct vbe_mode_info modeInfo;
|
struct vbe_mode_info modeInfo;
|
||||||
|
|||||||
Reference in New Issue
Block a user