Vladimir Serbinenko (phcoder@gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/5842
-gerrit
commit 167a202fc809a1de00fb569143f4a6bf110e360b Author: Vladimir Serbinenko phcoder@gmail.com Date: Sat May 24 16:34:29 2014 +0200
VBT parser.
Change-Id: I32f6505dbf683478bf5a25b73db7ab0c60eff29c Signed-off-by: Vladimir Serbinenko phcoder@gmail.com --- util/intelvbttool/intelvbttool.c | 441 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 441 insertions(+)
diff --git a/util/intelvbttool/intelvbttool.c b/util/intelvbttool/intelvbttool.c new file mode 100644 index 0000000..3ac2fd7 --- /dev/null +++ b/util/intelvbttool/intelvbttool.c @@ -0,0 +1,441 @@ +#include <stdio.h> +#include <sys/mman.h> +#include <stdint.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; + + +typedef struct { + u16 signature; + u8 size; + u8 reserved[21]; + u16 pcir_offset; + u16 vbt_offset; +} __attribute__((packed)) optionrom_header_t; + +struct vbt_header { + u8 signature[20]; + u16 version; + u16 header_size; + u16 vbt_size; + u8 vbt_checksum; + u8 reserved0; + u32 bdb_offset; + u32 aim_offset[4]; +} __attribute__((packed)); + +struct bdb_header { + u8 signature[16]; + u16 version; + u16 header_size; + u16 bdb_size; +}; + +struct vbios_data { + u8 type; /* 0 == desktop, 1 == mobile */ + u8 relstage; + u8 chipset; + u8 lvds_present:1; + u8 tv_present:1; + u8 rsvd2:6; /* finish byte */ + u8 rsvd3[4]; + u8 signon[155]; + u8 copyright[61]; + u16 code_segment; + u8 dos_boot_mode; + u8 bandwidth_percent; + u8 rsvd4; /* popup memory size */ + u8 resize_pci_bios; + u8 rsvd5; /* is crt already on ddc2 */ +} __attribute__((packed)); + +struct bdb_general_features { + /* bits 1 */ + u8 panel_fitting:2; + u8 flexaim:1; + u8 msg_enable:1; + u8 clear_screen:3; + u8 color_flip:1; + + /* bits 2 */ + u8 download_ext_vbt:1; + u8 enable_ssc:1; + u8 ssc_freq:1; + u8 enable_lfp_on_override:1; + u8 disable_ssc_ddt:1; + u8 rsvd7:1; + u8 display_clock_mode:1; + u8 rsvd8:1; /* finish byte */ + + /* bits 3 */ + u8 disable_smooth_vision:1; + u8 single_dvi:1; + u8 rsvd9:1; + u8 fdi_rx_polarity_inverted:1; + u8 rsvd10:4; /* finish byte */ + + /* bits 4 */ + u8 legacy_monitor_detect; + + /* bits 5 */ + u8 int_crt_support:1; + u8 int_tv_support:1; + u8 int_efp_support:1; + u8 dp_ssc_enb:1; /* PCH attached eDP supports SSC */ + u8 dp_ssc_freq:1; /* SSC freq for PCH attached eDP */ + u8 rsvd11:3; /* finish byte */ +} __attribute__((packed)); + +struct common_child_dev_config { + u16 handle; + u16 device_type; + u8 not_common1[12]; + u8 dvo_port; + u8 i2c_pin; + u8 slave_addr; + u8 ddc_pin; + u16 edid_ptr; + u8 not_common3[6]; + u8 dvo_wiring; + u8 not_common4[4]; +} __attribute__((packed)); + +struct bdb_general_definitions { + /* DDC GPIO */ + u8 crt_ddc_gmbus_pin; + + /* DPMS bits */ + u8 dpms_acpi:1; + u8 skip_boot_crt_detect:1; + u8 dpms_aim:1; + u8 rsvd1:5; /* finish byte */ + + /* boot device bits */ + u8 boot_display[2]; + u8 child_dev_size; + + /* + * Device info: + * If TV is present, it'll be at devices[0]. + * LVDS will be next, either devices[0] or [1], if present. + * On some platforms the number of device is 6. But could be as few as + * 4 if both TV and LVDS are missing. + * And the device num is related with the size of general definition + * block. It is obtained by using the following formula: + * number = (block_size - sizeof(bdb_general_definitions))/ + * sizeof(child_device_config); + */ + struct common_child_dev_config devices[0]; +} __attribute__((packed)); + +struct bdb_driver_features { + u8 boot_dev_algorithm:1; + u8 block_display_switch:1; + u8 allow_display_switch:1; + u8 hotplug_dvo:1; + u8 dual_view_zoom:1; + u8 int15h_hook:1; + u8 sprite_in_clone:1; + u8 primary_lfp_id:1; + + u16 boot_mode_x; + u16 boot_mode_y; + u8 boot_mode_bpp; + u8 boot_mode_refresh; + + u16 enable_lfp_primary:1; + u16 selective_mode_pruning:1; + u16 dual_frequency:1; + u16 render_clock_freq:1; /* 0: high freq; 1: low freq */ + u16 nt_clone_support:1; + u16 power_scheme_ui:1; /* 0: CUI; 1: 3rd party */ + u16 sprite_display_assign:1; /* 0: secondary; 1: primary */ + u16 cui_aspect_scaling:1; + u16 preserve_aspect_ratio:1; + u16 sdvo_device_power_down:1; + u16 crt_hotplug:1; + u16 lvds_config:2; + u16 tv_hotplug:1; + u16 hdmi_config:2; + + u8 static_display:1; + u8 reserved2:7; + u16 legacy_crt_max_x; + u16 legacy_crt_max_y; + u8 legacy_crt_max_refresh; + + u8 hdmi_termination; + u8 custom_vbt_version; +} __attribute__((packed)); + +struct bdb_lvds_options { + u8 panel_type; + u8 rsvd1; + /* LVDS capabilities, stored in a dword */ + u8 pfit_mode:2; + u8 pfit_text_mode_enhanced:1; + u8 pfit_gfx_mode_enhanced:1; + u8 pfit_ratio_auto:1; + u8 pixel_dither:1; + u8 lvds_edid:1; + u8 rsvd2:1; + u8 rsvd4; +} __attribute__((packed)); + +struct bdb_sdvo_lvds_options { + u8 panel_backlight; + u8 h40_set_panel_type; + u8 panel_type; + u8 ssc_clk_freq; + u16 als_low_trip; + u16 als_high_trip; + u8 sclalarcoeff_tab_row_num; + u8 sclalarcoeff_tab_row_size; + u8 coefficient[8]; + u8 panel_misc_bits_1; + u8 panel_misc_bits_2; + u8 panel_misc_bits_3; + u8 panel_misc_bits_4; +} __attribute__((packed)); + + +#define BDB_GENERAL_FEATURES 1 +#define BDB_GENERAL_DEFINITIONS 2 + +#define BDB_DRIVER_FEATURES 12 +#define BDB_SDVO_LVDS_OPTIONS 22 +#define BDB_SDVO_PANEL_DTDS 23 +#define BDB_LVDS_OPTIONS 40 +#define BDB_LVDS_LFP_DATA_PTRS 41 +#define BDB_LVDS_LFP_DATA 42 + +#define BDB_SKIP 254 + +static void parse_vbt(const void *vbt) +{ + const struct vbt_header *head = vbt; + const struct bdb_header *bdb; + int i; + const u8 *ptr; + int is_first_skip = 1; + + if (memcmp(head->signature, "$VBT", 4) != 0) { + fprintf (stderr, "invalid VBT signature\n"); + exit(1); + } + printf ("signature: <%20.20s>\n", head->signature); + printf ("version: %d.%02d\n", head->version / 100, + head->version % 100); + if (head->header_size != sizeof (struct vbt_header)) + printf ("header size: 0x%x\n", head->header_size); + printf ("VBT size: 0x%x\n", head->vbt_size); + printf ("VBT checksum: 0x%x\n", head->vbt_checksum); + if (head->reserved0) + printf ("header reserved0: 0x%x\n", head->reserved0); + if (head->bdb_offset != sizeof (struct vbt_header)) + printf ("BDB offset: 0x%x\n", head->bdb_offset); + + for (i = 0; i < 4; i++) + if (head->aim_offset[i]) + printf ("AIM[%d] offset: 0x%x\n", i, + head->aim_offset[i]); + bdb = (const void *) ((const char *) vbt + head->bdb_offset); + + if (memcmp ("BIOS_DATA_BLOCK ", bdb->signature, 16) != 0) { + fprintf(stderr, "invalid BDB signature:%s\n", + bdb->signature); + exit (1); + } + printf ("BDB version: %d.%02d\n", bdb->version / 100, + bdb->version % 100); + if (bdb->header_size != sizeof (struct bdb_header)) + printf ("BDB header size: 0x%x\n", bdb->header_size); + if (bdb->bdb_size != head->vbt_size - head->bdb_offset) + printf ("BDB size: 0x%x\n", bdb->bdb_size); + for (ptr = (const u8 *) bdb + bdb->header_size; + ptr < (const u8 *) bdb + bdb->bdb_size;) { + u16 secsz = (ptr[1] | (ptr[2] << 8)); + u8 sectype = ptr[0]; + const u8 *section = ptr + 3; + + printf ("section type %d, size 0x%x\n", sectype, secsz); + ptr += secsz + 3; + switch(sectype) + { + case BDB_GENERAL_FEATURES: { + const struct bdb_general_features *sec = (const void *) section; + printf ("General features:\n"); + + if(sec->panel_fitting) printf("\tpanel_fitting = 0x%x\n", sec->panel_fitting); + if(sec->flexaim) printf("\tflexaim = 0x%x\n", sec->flexaim); + if(sec->msg_enable) printf("\tmsg_enable = 0x%x\n", sec->msg_enable); + if(sec->clear_screen) printf("\tclear_screen = 0x%x\n", sec->clear_screen); + if(sec->color_flip) printf("\tcolor_flip = 0x%x\n", sec->color_flip); + if(sec->download_ext_vbt) printf("\tdownload_ext_vbt = 0x%x\n", sec->download_ext_vbt); + printf("\t*enable_ssc = 0x%x\n", sec->enable_ssc); + printf("\t*ssc_freq = 0x%x\n", sec->ssc_freq); + if(sec->enable_lfp_on_override) printf("\tenable_lfp_on_override = 0x%x\n", sec->enable_lfp_on_override); + if(sec->disable_ssc_ddt) printf("\tdisable_ssc_ddt = 0x%x\n", sec->disable_ssc_ddt); + if(sec->rsvd7) printf("\trsvd7 = 0x%x\n", sec->rsvd7); + printf("\t*display_clock_mode = 0x%x\n", sec->display_clock_mode); + if(sec->rsvd8) printf("\trsvd8 = 0x%x\n", sec->rsvd8); + printf("\tdisable_smooth_vision = 0x%x\n", sec->disable_smooth_vision); + if(sec->single_dvi) printf("\tsingle_dvi = 0x%x\n", sec->single_dvi); + if(sec->rsvd9) printf("\trsvd9 = 0x%x\n", sec->rsvd9); + printf("\t*fdi_rx_polarity_inverted = 0x%x\n", sec->fdi_rx_polarity_inverted); + if(sec->rsvd10) printf("\trsvd10 = 0x%x\n", sec->rsvd10); + if(sec->legacy_monitor_detect) printf("\tlegacy_monitor_detect = 0x%x\n", sec->legacy_monitor_detect); + printf("\t*int_crt_support = 0x%x\n", sec->int_crt_support); + printf("\t*int_tv_support = 0x%x\n", sec->int_tv_support); + if(sec->int_efp_support) printf("\tint_efp_support = 0x%x\n", sec->int_efp_support); + if(sec->dp_ssc_enb) printf("\tdp_ssc_enb = 0x%x\n", sec->dp_ssc_enb); + if(sec->dp_ssc_freq) printf("\tdp_ssc_freq = 0x%x\n", sec->dp_ssc_freq); + if(sec->rsvd11) printf("\trsvd11 = 0x%x\n", sec->rsvd11); + break; + } + case BDB_DRIVER_FEATURES: { + const struct bdb_driver_features *sec = (const void *) section; + printf("\t*LVDS config: %d\n", sec->lvds_config); + printf("\t*Dual frequency: %d\n", sec->dual_frequency); + + break; + } + case BDB_SDVO_LVDS_OPTIONS: { + const struct bdb_sdvo_lvds_options *sec = (const void *) section; + printf("\t*Panel type: %d\n", sec->panel_type); + + break; + } + case BDB_GENERAL_DEFINITIONS: { + const struct bdb_general_definitions *sec = (const void *) section; + printf("\t*CRT DDC GMBUS pin: %d\n", sec->crt_ddc_gmbus_pin); + + printf("\tDPMS ACPI: %d\n", sec->dpms_acpi); + printf("\tSkip boot CRT detect: %d\n", + sec->skip_boot_crt_detect); + printf("\tDPMS aim: %d\n", + sec->dpms_aim); + if(sec->rsvd1) + printf("\trsvd1: 0x%x\n", sec->rsvd1); + printf("\tboot_display: { %x, %x }\n", + sec->boot_display[0], sec->boot_display[1]); + if (sec->child_dev_size != sizeof(struct common_child_dev_config)) + printf("\tchild_dev_size: %d\n", + sec->child_dev_size); + printf("\t%d devices\n", (secsz - sizeof (*sec)) / sizeof(struct common_child_dev_config)); + for (i = 0; i < (secsz - sizeof (*sec)) / sizeof(struct common_child_dev_config); i++) { + printf ("\t*device type: %x ", + sec->devices[i].device_type); +#define DEVICE_TYPE_INT_LFP 0x1022 +#define DEVICE_TYPE_INT_TV 0x1009 +#define DEVICE_TYPE_EFP_DVI_HOTPLUG_PWR 0x6052 + switch (sec->devices[i].device_type) { + case DEVICE_TYPE_INT_LFP: + printf("(flat panel)\n"); + break; + case DEVICE_TYPE_INT_TV: + printf("(TV)\n"); + break; + case DEVICE_TYPE_EFP_DVI_HOTPLUG_PWR: + printf("(DVI)\n"); + break; + case 0: + printf("(Empty)\n"); + break; + default: + printf("(Unknown)\n"); + break; + } + if (!sec->devices[i].device_type) + continue; + printf ("\t *dvo_port: %x\n", sec->devices[i].dvo_port); + printf ("\t *i2c_pin: %x\n", sec->devices[i].i2c_pin); + printf ("\t *slave_addr: %x\n", sec->devices[i].slave_addr); + printf ("\t *ddc_pin: %x\n", sec->devices[i].ddc_pin); + printf ("\t *dvo_wiring: %x\n", sec->devices[i].dvo_wiring); + printf ("\t edid_ptr: %x\n", sec->devices[i].edid_ptr); + } + + break; + } + case BDB_SKIP: { + const struct vbios_data *sec = (const void *) section; + if (!is_first_skip) + break; + is_first_skip = 0; + printf("\ttype: %x\n", sec->type); + printf("\trelstage: %x\n", sec->relstage); + printf("\tchipset: %x\n", sec->chipset); + printf(sec->lvds_present ? "\tLVDS\n" + : "\tNo LVDS\n"); + printf(sec->tv_present ? "\tTV\n" + : "\tNo TV\n"); + if (sec->rsvd2) + printf("\trsvd2: 0x%x\n", sec->rsvd2); + for (i = 0; i < 4; i++) + if (sec->rsvd3[i]) + printf("\trsvd3[%d]: 0x%x\n", i, + sec->rsvd3[i]); + printf("\tSignon: %.155s\n", sec->signon); + printf("\tCopyright: %.155s\n", sec->copyright); + printf("\tCode segment: %x\n", sec->code_segment); + printf("\tDOS Boot mode: %x\n", sec->dos_boot_mode); + printf("\tBandwidth percent: %x\n", + sec->bandwidth_percent); + if (sec->rsvd4) + printf("\trsvd4: 0x%x\n", sec->rsvd4); + printf("\tBandwidth percent: %x\n", + sec->resize_pci_bios); + if (sec->rsvd5) + printf("\trsvd5: 0x%x\n", sec->rsvd5); + break; + } + } + } + +} + +static void parse_vbios(const void *ptr) +{ + const optionrom_header_t *oh; + oh = ptr; + if (oh->signature != 0xaa55) { + fprintf(stderr, "bad oprom signature: %x\n", oh->signature); + return; + } + if (!oh->vbt_offset) { + fprintf(stderr, "no VBT found\n"); + return; + } + parse_vbt((const char *) ptr + oh->vbt_offset); +} + +int +main (int argc, char **argv) +{ + const void *ptr; + int fd; + if (argc == 2) { + fd = open(argv[1], O_RDONLY); + ptr = mmap(0, 65536, PROT_READ, MAP_SHARED, fd, 0); + } else { + fd = open("/dev/mem", O_RDONLY); + ptr = mmap(0, 65536, PROT_READ, MAP_SHARED, fd, 0xc0000); + } + if (ptr == MAP_FAILED) { + fprintf (stderr, "mmap failed: %s\n", strerror (errno)); + return 1; + } + parse_vbios(ptr); + close (fd); + return 0; +}