Some style fixes.

More work is needed for this new file to completely follow the style
guidelines. Also added several FIXMEs and TODOs.

This doesn't seem to break anything on my machine however, and was
confirmed to help by several users, so we may as well use it.
This commit is contained in:
Adrien Destugues
2014-01-17 14:46:42 +01:00
parent a35f568273
commit bb03a92ef6
2 changed files with 137 additions and 130 deletions
@@ -1,27 +1,47 @@
/* Written by Artem Falcon <[email protected]> */ /*
* Copyright 2012-2014, Artem Falcon <[email protected]>
* Distributed under the terms of the MIT License.
*/
#include <KernelExport.h> #include <KernelExport.h>
#include "intel_extreme.h" #include "intel_extreme.h"
#include <string.h> #include <string.h>
#define TRACE_BIOS 1
#define TRACE_BIOS 1
#ifdef TRACE_BIOS #ifdef TRACE_BIOS
# define TRACE(x) dprintf x # define TRACE(x) dprintf x
#else #else
# define TRACE(x) ; # define TRACE(x) ;
#endif #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] | \ static const off_t kVbtPointer = 0x1A;
(vbios.memory[_addr + 1] << 8))
/* */
/* 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 _PIXEL_CLOCK(x) (x[0] + (x[1] << 8)) * 10000
#define _H_ACTIVE(x) (x[2] + ((x[4] & 0xF0) << 4)) #define _H_ACTIVE(x) (x[2] + ((x[4] & 0xF0) << 4))
#define _H_BLANK(x) (x[3] + ((x[4] & 0x0F) << 8)) #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_BLANK(x) (x[6] + ((x[7] & 0x0F) << 8))
#define _V_SYNC_OFF(x) ((x[10] >> 4) + ((x[11] & 0x0C) << 2)) #define _V_SYNC_OFF(x) ((x[10] >> 4) + ((x[11] & 0x0C) << 2))
#define _V_SYNC_WIDTH(x) ((x[10] & 0x0F) + ((x[11] & 0x03) << 4)) #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 { struct lvds_bdb1 {
uint8 id; uint8 id;
@@ -60,6 +61,7 @@ struct lvds_bdb1 {
uint16 caps; uint16 caps;
} __attribute__((packed)); } __attribute__((packed));
struct lvds_bdb2_entry { struct lvds_bdb2_entry {
uint16 lfp_info_offset; uint16 lfp_info_offset;
uint8 lfp_info_size; uint8 lfp_info_size;
@@ -69,6 +71,7 @@ struct lvds_bdb2_entry {
uint8 lfp_edid_pid_size; uint8 lfp_edid_pid_size;
} __attribute__((packed)); } __attribute__((packed));
struct lvds_bdb2 { struct lvds_bdb2 {
uint8 id; uint8 id;
uint16 size; uint16 size;
@@ -76,6 +79,7 @@ struct lvds_bdb2 {
struct lvds_bdb2_entry panels[16]; struct lvds_bdb2_entry panels[16];
} __attribute__((packed)); } __attribute__((packed));
struct lvds_bdb2_lfp_info { struct lvds_bdb2_lfp_info {
uint16 x_res; uint16 x_res;
uint16 y_res; uint16 y_res;
@@ -92,6 +96,7 @@ struct lvds_bdb2_lfp_info {
uint16 terminator; uint16 terminator;
} __attribute__((packed)); } __attribute__((packed));
static struct vbios { static struct vbios {
area_id area; area_id area;
uint8* memory; uint8* memory;
@@ -104,195 +109,196 @@ static struct vbios {
uint16 vsync_end; uint16 vsync_end;
uint16 vsync_total; uint16 vsync_total;
} timings_common; } timings_common;
uint16_t ReadWord(off_t address) {
return memory[address] | memory[address + 1] << 8;
}
} vbios; } 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
/* this is reimplementation, Haiku uses BIOS call and gets most native panel timings. This will allow to get non-updated, PROM-programmed
* current panel info, we're, otherwise, digging in VBIOS memory timings info when compensation mode is off on your machine */
* 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 static bool
get_bios(void) 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; int vbt_offset;
struct vbt_header *vbt; struct vbt_header *vbt;
/* !!!DANGER!!!: mapping of BIOS using legacy location for now, /* !!!DANGER!!!: mapping of BIOS using legacy location for now,
* hence, if panel mode will be set using info from VBT, it will hence, if panel mode will be set using info from VBT, it will
* be taken from primary card's VBIOS */ be taken from primary card's VBIOS */
vbios.area = map_physical_memory("VBIOS mapping", 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)); B_READ_AREA, (void**)&(vbios.memory));
if (vbios.area < 0) if (vbios.area < 0)
return false; return false;
TRACE((DEVICE_NAME ": mapping VBIOS: 0x%x -> %p\n", TRACE((DEVICE_NAME ": mapping VBIOS: 0x%x -> %p\n",
VBIOS, vbios.memory)); kVBIOSAddress, vbios.memory));
vbt_offset = INTEL_BIOS_16(0x1a); vbt_offset = vbios.ReadWord(kVbtPointer);
if (vbt_offset >= INTEL_VBIOS_SIZE) { if (vbt_offset >= kVBIOSSize) {
TRACE(("intel_extreme: bad VBT offset : 0x%x\n", TRACE((DEVICE_NAME": bad VBT offset : 0x%x\n",
vbt_offset)); vbt_offset));
return unmap_bios(vbios.area, vbios.memory); delete_area(vbios.area);
return false;
} }
vbt = (struct vbt_header *)(vbios.memory + vbt_offset); vbt = (struct vbt_header *)(vbios.memory + vbt_offset);
if (memcmp(vbt->signature, "$VBT", 4) != 0) { 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)); vbt->signature));
return unmap_bios(vbios.area, vbios.memory); delete_area(vbios.area);
return false;
} }
return true; 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 */ /* handle bogus h/vtotal values, if got such */
if (vbios.timings_common.hsync_end > vbios.timings_common.hsync_total) { if (vbios.timings_common.hsync_end > vbios.timings_common.hsync_total) {
vbios.timings_common.hsync_total = vbios.timings_common.hsync_total
vbios.timings_common.hsync_end + 1; = vbios.timings_common.hsync_end + 1;
bogus = true; 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) { if (vbios.timings_common.vsync_end > vbios.timings_common.vsync_total) {
vbios.timings_common.vsync_total = vbios.timings_common.vsync_total
vbios.timings_common.vsync_end + 1; = vbios.timings_common.vsync_end + 1;
bogus = true; bogus = true;
TRACE(("intel_extreme: got bogus vtotal. Fixing\n")); TRACE((DEVICE_NAME": got bogus vtotal. Fixing\n"));
} }
/* */ /* */
if (bogus) if (bogus) {
TRACE(("intel_extreme: adjusted LFP modeline: x%d Hz,\t%d " TRACE((DEVICE_NAME": adjusted LFP modeline: x%d Hz,\t"
"%d %d %d %d %d %d %d %d\n", "%d %d %d %d %d %d %d %d\n",
_PIXEL_CLOCK(data) / ( _PIXEL_CLOCK(data) / ((_H_ACTIVE(data) + _H_BLANK(data))
(_H_ACTIVE(data) + _H_BLANK(data)) * (_V_ACTIVE(data) + _V_BLANK(data))),
* (_V_ACTIVE(data) + _V_BLANK(data)) _H_ACTIVE(data),
), vbios.timings_common.hsync_start,
_PIXEL_CLOCK_MHZ(data), vbios.timings_common.hsync_end,
_H_ACTIVE(data), vbios.timings_common.hsync_start, vbios.timings_common.hsync_total,
vbios.timings_common.hsync_end, vbios.timings_common.hsync_total,
_V_ACTIVE(data), vbios.timings_common.vsync_start, _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 */ /* TODO: 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 */ /* 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.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_start = vbios.timings_common.hsync_start;
vbios.shared_info->timing.h_sync_end = vbios.timings_common.hsync_end; 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.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_start = vbios.timings_common.vsync_start;
vbios.shared_info->timing.v_sync_end = vbios.timings_common.vsync_end; vbios.shared_info->timing.v_sync_end = vbios.timings_common.vsync_end;
vbios.shared_info->timing.v_total = vbios.timings_common.vsync_total; vbios.shared_info->timing.v_total = vbios.timings_common.vsync_total;
unmap_bios(vbios.area, vbios.memory); delete_area(vbios.area);
return true; 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 vbt_header *vbt;
struct bdb_header *bdb; struct bdb_header *bdb;
int vbt_offset, bdb_offset, bdb_block_offset, block_size; int vbt_offset, bdb_offset, bdb_block_offset, block_size;
int panel_type = -1; int panel_type = -1;
if (!get_bios()) if (!get_bios())
return false; return false;
vbt_offset = INTEL_BIOS_16(0x1a); vbt_offset = vbios.ReadWord(kVbtPointer);
vbt = (struct vbt_header *)(vbios.memory + vbt_offset); vbt = (struct vbt_header *)(vbios.memory + vbt_offset);
bdb_offset = vbt_offset + vbt->bdb_offset; bdb_offset = vbt_offset + vbt->bdb_offset;
bdb = (struct bdb_header *)(vbios.memory + bdb_offset); bdb = (struct bdb_header *)(vbios.memory + bdb_offset);
if (memcmp(bdb->signature, "BIOS_DATA_BLOCK ", 16) != 0) { if (memcmp(bdb->signature, "BIOS_DATA_BLOCK ", 16) != 0) {
TRACE(("intel_extreme: bad BDB signature\n")); TRACE((DEVICE_NAME": bad BDB signature\n"));
return unmap_bios(vbios.area, vbios.memory); 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; for (bdb_block_offset = bdb->header_size; bdb_block_offset < bdb->bdb_size;
bdb_block_offset += block_size) { bdb_block_offset += block_size) {
int start = bdb_offset + bdb_block_offset; 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]; int id = vbios.memory[start];
block_size = INTEL_BIOS_16(start + 1) + 3; block_size = vbios.ReadWord(start + 1) + 3;
//TRACE(("intel_extreme: found BDB block type %d\n", id)); // TRACE((DEVICE_NAME": found BDB block type %d\n", id));
switch (id) { switch (id) {
case 40: case 40: // FIXME magic numbers
{
struct lvds_bdb1 *lvds1;
lvds1 = (struct lvds_bdb1 *)(vbios.memory + start); lvds1 = (struct lvds_bdb1 *)(vbios.memory + start);
panel_type = lvds1->panel_type; panel_type = lvds1->panel_type;
break; break;
}
case 41: case 41:
{
if (panel_type == -1) if (panel_type == -1)
break; break;
struct lvds_bdb2 *lvds2;
struct lvds_bdb2_lfp_info *lvds2_lfp_info;
lvds2 = (struct lvds_bdb2 *)(vbios.memory + start); lvds2 = (struct lvds_bdb2 *)(vbios.memory + start);
lvds2_lfp_info = (struct lvds_bdb2_lfp_info *) lvds2_lfp_info = (struct lvds_bdb2_lfp_info *)
(vbios.memory + bdb_offset + (vbios.memory + bdb_offset
lvds2->panels[panel_type].lfp_info_offset); + lvds2->panels[panel_type].lfp_info_offset);
/* found bad one terminator */ /* found bad one terminator */
if (lvds2_lfp_info->terminator != 0xffff) { 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 + uint8_t* timing_data = vbios.memory + bdb_offset
lvds2->panels[panel_type].lfp_edid_dtd_offset; + lvds2->panels[panel_type].lfp_edid_dtd_offset;
TRACE(("intel_extreme: found LFP of size %d x %d " TRACE((DEVICE_NAME": found LFP of size %d x %d "
"in BIOS VBT tables\n", "in BIOS VBT tables\n",
lvds2_lfp_info->x_res, lvds2_lfp_info->y_res)); lvds2_lfp_info->x_res, lvds2_lfp_info->y_res));
vbios.timings_common.hsync_start = _H_ACTIVE(timing_data) + vbios.timings_common.hsync_start = _H_ACTIVE(timing_data)
_H_SYNC_OFF(timing_data); + _H_SYNC_OFF(timing_data);
vbios.timings_common.hsync_end = vbios.timings_common.hsync_start vbios.timings_common.hsync_end
= vbios.timings_common.hsync_start
+ _H_SYNC_WIDTH(timing_data); + _H_SYNC_WIDTH(timing_data);
vbios.timings_common.hsync_total = _H_ACTIVE(timing_data) + vbios.timings_common.hsync_total = _H_ACTIVE(timing_data)
_H_BLANK(timing_data); + _H_BLANK(timing_data);
vbios.timings_common.vsync_start = _V_ACTIVE(timing_data) + vbios.timings_common.vsync_start = _V_ACTIVE(timing_data)
_V_SYNC_OFF(timing_data); + _V_SYNC_OFF(timing_data);
vbios.timings_common.vsync_end = vbios.timings_common.vsync_start vbios.timings_common.vsync_end
+ _V_SYNC_WIDTH(timing_data); = vbios.timings_common.vsync_start
vbios.timings_common.vsync_total = _V_ACTIVE(timing_data) + + _V_SYNC_WIDTH(timing_data);
_V_BLANK(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; vbios.shared_info = shared_info;
return feed_shared_info(timing_data); return feed_shared_info(timing_data);
break; }
} }
} }
unmap_bios(vbios.area, vbios.memory); delete_area(vbios.area);
return true; return true;
} }
@@ -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_free_memory(intel_info& info, addr_t offset);
extern status_t intel_allocate_memory(intel_info& info, size_t size, extern status_t intel_allocate_memory(intel_info& info, size_t size,
size_t alignment, uint32 flags, addr_t* _offset, size_t alignment, uint32 flags, addr_t* _offset,