diff --git a/src/add-ons/kernel/drivers/graphics/intel_extreme/bios.cpp b/src/add-ons/kernel/drivers/graphics/intel_extreme/bios.cpp index f62992892f..877f7dad48 100644 --- a/src/add-ons/kernel/drivers/graphics/intel_extreme/bios.cpp +++ b/src/add-ons/kernel/drivers/graphics/intel_extreme/bios.cpp @@ -1,27 +1,47 @@ -/* Written by Artem Falcon */ +/* + * Copyright 2012-2014, Artem Falcon + * Distributed under the terms of the MIT License. + */ + #include #include "intel_extreme.h" #include -#define TRACE_BIOS 1 + +#define TRACE_BIOS 1 #ifdef TRACE_BIOS -# define TRACE(x) dprintf x -#else +# 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)) -/* */ +static const off_t kVbtPointer = 0x1A; -/* subject of including into private/graphics/common/edid* */ -#define _PIXEL_CLOCK_MHZ(x) (x[0] + (x[1] << 8)) / 100 +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; +} __attribute__((packed)); + + +// FIXME the struct definition for the bdb_header is not complete, so we rely +// on direct access with hardcoded offsets to get the timings out of it. #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)) @@ -31,26 +51,7 @@ #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; @@ -60,6 +61,7 @@ struct lvds_bdb1 { uint16 caps; } __attribute__((packed)); + struct lvds_bdb2_entry { uint16 lfp_info_offset; uint8 lfp_info_size; @@ -69,6 +71,7 @@ struct lvds_bdb2_entry { uint8 lfp_edid_pid_size; } __attribute__((packed)); + struct lvds_bdb2 { uint8 id; uint16 size; @@ -76,6 +79,7 @@ struct lvds_bdb2 { struct lvds_bdb2_entry panels[16]; } __attribute__((packed)); + struct lvds_bdb2_lfp_info { uint16 x_res; uint16 y_res; @@ -92,6 +96,7 @@ struct lvds_bdb2_lfp_info { uint16 terminator; } __attribute__((packed)); + static struct vbios { area_id area; uint8* memory; @@ -104,195 +109,196 @@ static struct vbios { uint16 vsync_end; uint16 vsync_total; } timings_common; + + uint16_t ReadWord(off_t address) { + return memory[address] | memory[address + 1] << 8; + } } vbios; -static inline bool unmap_bios(area_id area, uint8* mem) { - delete_area(area); - mem = NULL; - return false; -} +/* TODO: move code to accelerant, if possible */ -/* 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 */ +/* 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) { + static const uint64_t kVBIOSAddress = 0xc0000; + static const size_t kVBIOSSize = 64 * 1024; + // FIXME: is this the same for all cards? + 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 */ + 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, + kVBIOSAddress, kVBIOSSize, 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)); + kVBIOSAddress, 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 = vbios.ReadWord(kVbtPointer); + if (vbt_offset >= kVBIOSSize) { + TRACE((DEVICE_NAME": bad VBT offset : 0x%x\n", vbt_offset)); - return unmap_bios(vbios.area, vbios.memory); + delete_area(vbios.area); + return false; } vbt = (struct vbt_header *)(vbios.memory + vbt_offset); if (memcmp(vbt->signature, "$VBT", 4) != 0) { - TRACE(("intel_extreme: bad VBT signature: %20s\n", + TRACE((DEVICE_NAME": bad VBT signature: %20s\n", vbt->signature)); - return unmap_bios(vbios.area, vbios.memory); + delete_area(vbios.area); + return false; } return true; } -static bool feed_shared_info(uint8* data) + +static bool +feed_shared_info(uint8* data) { - bool bogus = false; + 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; + vbios.timings_common.hsync_total + = vbios.timings_common.hsync_end + 1; bogus = true; - TRACE(("intel_extreme: got bogus htotal. Fixing\n")); + TRACE((DEVICE_NAME": 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; + vbios.timings_common.vsync_total + = vbios.timings_common.vsync_end + 1; bogus = true; - TRACE(("intel_extreme: got bogus vtotal. Fixing\n")); + TRACE((DEVICE_NAME": got bogus vtotal. Fixing\n")); } /* */ - if (bogus) - TRACE(("intel_extreme: adjusted LFP modeline: x%d Hz,\t%d " + if (bogus) { + TRACE((DEVICE_NAME": adjusted LFP modeline: x%d Hz,\t" "%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, + _PIXEL_CLOCK(data) / ((_H_ACTIVE(data) + _H_BLANK(data)) + * (_V_ACTIVE(data) + _V_BLANK(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 - )); + 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 */ + /* TODO: add retrieved info to edid info struct, not fixed mode struct */ + + /* struct display_timing is not packed, so we have to set elements + individually */ 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_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_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); + delete_area(vbios.area); return true; } -bool get_lvds_mode_from_bios(display_mode *shared_info) + +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; + if (!get_bios()) + return false; - vbt_offset = INTEL_BIOS_16(0x1a); + vbt_offset = vbios.ReadWord(kVbtPointer); 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((DEVICE_NAME": bad BDB signature\n")); + delete_area(vbios.area); } - TRACE(("intel_extreme: parsing BDB blocks\n")); + TRACE((DEVICE_NAME": 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)); + int id = vbios.memory[start]; + block_size = vbios.ReadWord(start + 1) + 3; + // TRACE((DEVICE_NAME": found BDB block type %d\n", id)); switch (id) { - case 40: + case 40: // FIXME magic numbers + { + struct lvds_bdb1 *lvds1; lvds1 = (struct lvds_bdb1 *)(vbios.memory + start); panel_type = lvds1->panel_type; - break; + break; + } case 41: + { if (panel_type == -1) break; + struct lvds_bdb2 *lvds2; + struct lvds_bdb2_lfp_info *lvds2_lfp_info; + 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); + (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); + delete_area(vbios.area); + return false; } - timing_data = vbios.memory + bdb_offset + - lvds2->panels[panel_type].lfp_edid_dtd_offset; - TRACE(("intel_extreme: found LFP of size %d x %d " + uint8_t* timing_data = vbios.memory + bdb_offset + + lvds2->panels[panel_type].lfp_edid_dtd_offset; + TRACE((DEVICE_NAME": 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 + 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.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); vbios.shared_info = shared_info; return feed_shared_info(timing_data); - break; + } } } - unmap_bios(vbios.area, vbios.memory); - return true; + delete_area(vbios.area); + return true; } diff --git a/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme_private.h b/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme_private.h index 58c9fbaf33..45d6b2f9ae 100644 --- a/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme_private.h +++ b/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme_private.h @@ -70,6 +70,7 @@ find_reg(const intel_info& info, uint32 target) } +extern bool get_lvds_mode_from_bios(display_mode *shared_info); extern status_t intel_free_memory(intel_info& info, addr_t offset); extern status_t intel_allocate_memory(intel_info& info, size_t size, size_t alignment, uint32 flags, addr_t* _offset,