From b4c8ccc37273f10de5212ec7c7199fff43054339 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= <axeld@pinc-software.de> Date: Fri, 31 Oct 2008 09:52:57 +0000 Subject: [PATCH] * 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 --- headers/private/graphics/vesa/vesa.h | 28 +++++- src/system/boot/platform/bios_ia32/video.cpp | 89 +++++++++++++++++--- 2 files changed, 104 insertions(+), 13 deletions(-) diff --git a/headers/private/graphics/vesa/vesa.h b/headers/private/graphics/vesa/vesa.h index 069bb2b0dc..55a17052af 100644 --- a/headers/private/graphics/vesa/vesa.h +++ b/headers/private/graphics/vesa/vesa.h @@ -1,7 +1,7 @@ /* -** Copyright 2004, Axel Dörfler, axeld@pinc-software.de. All rights reserved. -** Distributed under the terms of the OpenBeOS License. -*/ + * Copyright 2004-2008, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + */ #ifndef VESA_H #define VESA_H @@ -119,6 +119,28 @@ struct vbe_mode_info { #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 * The BIOS area can be scanned for the protected mode * signature that identifies the structure below. diff --git a/src/system/boot/platform/bios_ia32/video.cpp b/src/system/boot/platform/bios_ia32/video.cpp index 3a3eefd311..d4720ee061 100644 --- a/src/system/boot/platform/bios_ia32/video.cpp +++ b/src/system/boot/platform/bios_ia32/video.cpp @@ -42,6 +42,7 @@ struct video_mode { uint16 mode; uint16 width, height, bits_per_pixel; uint32 bytes_per_row; + crtc_info_block* timing; }; static vbe_info_block sInfo; @@ -149,40 +150,99 @@ closest_video_mode(int32 width, int32 height, int32 depth) } -static video_mode * -find_edid_mode(edid1_info &info, bool allowPalette) +static crtc_info_block* +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; // try detailed timing first 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) { mode = find_video_mode(monitor.data.detailed_timing.h_active, 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; + } } } + int32 best = -1; + // try standard timings next for (int32 i = 0; i < EDID1_NUM_STD_TIMING; i++) { if (info.std_timing[i].h_size <= 256) 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); if (found != NULL) { if (mode != NULL) { // prefer higher resolutions - if (found->width > mode->width) + if (found->width > mode->width) { mode = found; - } else + best = i; + } + } else { mode = found; + best = i; + } } } + if (best >= 0) + mode->timing = get_crtc_info_block(info.std_timing[best]); + return mode; } @@ -413,6 +473,8 @@ vesa_init(vbe_info_block *info, video_mode **_standardMode) videoMode->width = modeInfo.width; videoMode->height = modeInfo.height; videoMode->bits_per_pixel = modeInfo.bits_per_pixel; + videoMode->timing = NULL; + if (modeInfo.bits_per_pixel == 16 && modeInfo.red_mask_size + modeInfo.green_mask_size + modeInfo.blue_mask_size == 15) { @@ -472,11 +534,18 @@ vesa_get_mode(uint16 *_mode) static status_t -vesa_set_mode(uint16 mode) +vesa_set_mode(video_mode* mode) { struct bios_regs regs; 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); 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 // everything enough time to settle. spin(1000); - if (vesa_set_mode(sMode->mode) != B_OK) + if (vesa_set_mode(sMode) != B_OK) goto fallback; struct vbe_mode_info modeInfo;