blob: 31fc24a2e016e132b5eca531d957702297099663 [file] [log] [blame]
Vladimir Serbinenko5a6b8d12014-05-24 16:34:29 +02001/*
2 * Copyright (C) 2014 Vladimir Serbinenko
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
Vladimir Serbinenko5a6b8d12014-05-24 16:34:29 +020012 */
13
14#include <stdio.h>
15#include <sys/mman.h>
16#include <stdint.h>
17#include <string.h>
18#include <stdlib.h>
19#include <unistd.h>
20#include <sys/types.h>
21#include <sys/stat.h>
22#include <fcntl.h>
23#include <errno.h>
24
25typedef uint8_t u8;
26typedef uint16_t u16;
27typedef uint32_t u32;
28
29
30typedef struct {
31 u16 signature;
32 u8 size;
33 u8 reserved[21];
34 u16 pcir_offset;
35 u16 vbt_offset;
36} __attribute__ ((packed)) optionrom_header_t;
37
38struct vbt_header {
39 u8 signature[20];
40 u16 version;
41 u16 header_size;
42 u16 vbt_size;
43 u8 vbt_checksum;
44 u8 reserved0;
45 u32 bdb_offset;
46 u32 aim_offset[4];
47} __attribute__ ((packed));
48
49struct bdb_header {
50 u8 signature[16];
51 u16 version;
52 u16 header_size;
53 u16 bdb_size;
54};
55
56struct vbios_data {
57 u8 type; /* 0 == desktop, 1 == mobile */
58 u8 relstage;
59 u8 chipset;
60 u8 lvds_present:1;
61 u8 tv_present:1;
62 u8 rsvd2:6; /* finish byte */
63 u8 rsvd3[4];
64 u8 signon[155];
65 u8 copyright[61];
66 u16 code_segment;
67 u8 dos_boot_mode;
68 u8 bandwidth_percent;
69 u8 rsvd4; /* popup memory size */
70 u8 resize_pci_bios;
71 u8 rsvd5; /* is crt already on ddc2 */
72} __attribute__ ((packed));
73
74struct bdb_general_features {
75 /* bits 1 */
76 u8 panel_fitting:2;
77 u8 flexaim:1;
78 u8 msg_enable:1;
79 u8 clear_screen:3;
80 u8 color_flip:1;
81
82 /* bits 2 */
83 u8 download_ext_vbt:1;
84 u8 enable_ssc:1;
85 u8 ssc_freq:1;
86 u8 enable_lfp_on_override:1;
87 u8 disable_ssc_ddt:1;
88 u8 rsvd7:1;
89 u8 display_clock_mode:1;
90 u8 rsvd8:1; /* finish byte */
91
92 /* bits 3 */
93 u8 disable_smooth_vision:1;
94 u8 single_dvi:1;
95 u8 rsvd9:1;
96 u8 fdi_rx_polarity_inverted:1;
97 u8 rsvd10:4; /* finish byte */
98
99 /* bits 4 */
100 u8 legacy_monitor_detect;
101
102 /* bits 5 */
103 u8 int_crt_support:1;
104 u8 int_tv_support:1;
105 u8 int_efp_support:1;
106 u8 dp_ssc_enb:1; /* PCH attached eDP supports SSC */
107 u8 dp_ssc_freq:1; /* SSC freq for PCH attached eDP */
108 u8 rsvd11:3; /* finish byte */
109} __attribute__ ((packed));
110
111struct common_child_dev_config {
112 u16 handle;
113 u16 device_type;
114 u8 not_common1[12];
115 u8 dvo_port;
116 u8 i2c_pin;
117 u8 slave_addr;
118 u8 ddc_pin;
119 u16 edid_ptr;
120 u8 not_common3[6];
121 u8 dvo_wiring;
122 u8 not_common4[4];
123} __attribute__ ((packed));
124
125struct bdb_general_definitions {
126 /* DDC GPIO */
127 u8 crt_ddc_gmbus_pin;
128
129 /* DPMS bits */
130 u8 dpms_acpi:1;
131 u8 skip_boot_crt_detect:1;
132 u8 dpms_aim:1;
133 u8 rsvd1:5; /* finish byte */
134
135 /* boot device bits */
136 u8 boot_display[2];
137 u8 child_dev_size;
138
139 /*
140 * Device info:
141 * If TV is present, it'll be at devices[0].
142 * LVDS will be next, either devices[0] or [1], if present.
143 * On some platforms the number of device is 6. But could be as few as
144 * 4 if both TV and LVDS are missing.
145 * And the device num is related with the size of general definition
146 * block. It is obtained by using the following formula:
147 * number = (block_size - sizeof(bdb_general_definitions))/
148 * sizeof(child_device_config);
149 */
150 struct common_child_dev_config devices[0];
151} __attribute__ ((packed));
152
153struct bdb_driver_features {
154 u8 boot_dev_algorithm:1;
155 u8 block_display_switch:1;
156 u8 allow_display_switch:1;
157 u8 hotplug_dvo:1;
158 u8 dual_view_zoom:1;
159 u8 int15h_hook:1;
160 u8 sprite_in_clone:1;
161 u8 primary_lfp_id:1;
162
163 u16 boot_mode_x;
164 u16 boot_mode_y;
165 u8 boot_mode_bpp;
166 u8 boot_mode_refresh;
167
168 u16 enable_lfp_primary:1;
169 u16 selective_mode_pruning:1;
170 u16 dual_frequency:1;
171 u16 render_clock_freq:1; /* 0: high freq; 1: low freq */
172 u16 nt_clone_support:1;
173 u16 power_scheme_ui:1; /* 0: CUI; 1: 3rd party */
174 u16 sprite_display_assign:1; /* 0: secondary; 1: primary */
175 u16 cui_aspect_scaling:1;
176 u16 preserve_aspect_ratio:1;
177 u16 sdvo_device_power_down:1;
178 u16 crt_hotplug:1;
179 u16 lvds_config:2;
180 u16 tv_hotplug:1;
181 u16 hdmi_config:2;
182
183 u8 static_display:1;
184 u8 reserved2:7;
185 u16 legacy_crt_max_x;
186 u16 legacy_crt_max_y;
187 u8 legacy_crt_max_refresh;
188
189 u8 hdmi_termination;
190 u8 custom_vbt_version;
191} __attribute__ ((packed));
192
193struct bdb_lvds_options {
194 u8 panel_type;
195 u8 rsvd1;
196 /* LVDS capabilities, stored in a dword */
197 u8 pfit_mode:2;
198 u8 pfit_text_mode_enhanced:1;
199 u8 pfit_gfx_mode_enhanced:1;
200 u8 pfit_ratio_auto:1;
201 u8 pixel_dither:1;
202 u8 lvds_edid:1;
203 u8 rsvd2:1;
204 u8 rsvd4;
205} __attribute__ ((packed));
206
207struct bdb_sdvo_lvds_options {
208 u8 panel_backlight;
209 u8 h40_set_panel_type;
210 u8 panel_type;
211 u8 ssc_clk_freq;
212 u16 als_low_trip;
213 u16 als_high_trip;
214 u8 sclalarcoeff_tab_row_num;
215 u8 sclalarcoeff_tab_row_size;
216 u8 coefficient[8];
217 u8 panel_misc_bits_1;
218 u8 panel_misc_bits_2;
219 u8 panel_misc_bits_3;
220 u8 panel_misc_bits_4;
221} __attribute__ ((packed));
222
223
224#define BDB_GENERAL_FEATURES 1
225#define BDB_GENERAL_DEFINITIONS 2
226
227#define BDB_DRIVER_FEATURES 12
228#define BDB_SDVO_LVDS_OPTIONS 22
229#define BDB_SDVO_PANEL_DTDS 23
230#define BDB_LVDS_OPTIONS 40
231#define BDB_LVDS_LFP_DATA_PTRS 41
232#define BDB_LVDS_LFP_DATA 42
233
234#define BDB_SKIP 254
235
236static void parse_vbt(const void *vbt)
237{
238 const struct vbt_header *head = vbt;
239 const struct bdb_header *bdb;
240 int i;
241 const u8 *ptr;
242 int is_first_skip = 1;
243
244 if (memcmp(head->signature, "$VBT", 4) != 0) {
245 fprintf(stderr, "invalid VBT signature\n");
246 exit(1);
247 }
248 printf("signature: <%20.20s>\n", head->signature);
249 printf("version: %d.%02d\n", head->version / 100,
250 head->version % 100);
251 if (head->header_size != sizeof(struct vbt_header))
252 printf("header size: 0x%x\n", head->header_size);
253 printf("VBT size: 0x%x\n", head->vbt_size);
254 printf("VBT checksum: 0x%x\n", head->vbt_checksum);
255 if (head->reserved0)
256 printf("header reserved0: 0x%x\n", head->reserved0);
257 if (head->bdb_offset != sizeof(struct vbt_header))
258 printf("BDB offset: 0x%x\n", head->bdb_offset);
259
260 for (i = 0; i < 4; i++)
261 if (head->aim_offset[i])
262 printf("AIM[%d] offset: 0x%x\n", i,
263 head->aim_offset[i]);
264 bdb = (const void *) ((const char *) vbt + head->bdb_offset);
265
266 if (memcmp("BIOS_DATA_BLOCK ", bdb->signature, 16) != 0) {
267 fprintf(stderr, "invalid BDB signature:%s\n",
268 bdb->signature);
269 exit(1);
270 }
271 printf("BDB version: %d.%02d\n", bdb->version / 100,
272 bdb->version % 100);
273 if (bdb->header_size != sizeof(struct bdb_header))
274 printf("BDB header size: 0x%x\n", bdb->header_size);
275 if (bdb->bdb_size != head->vbt_size - head->bdb_offset)
276 printf("BDB size: 0x%x\n", bdb->bdb_size);
277 for (ptr = (const u8 *) bdb + bdb->header_size;
278 ptr < (const u8 *) bdb + bdb->bdb_size;) {
279 u16 secsz = (ptr[1] | (ptr[2] << 8));
280 u8 sectype = ptr[0];
281 const u8 *section = ptr + 3;
282
283 printf("section type %d, size 0x%x\n", sectype, secsz);
284 ptr += secsz + 3;
285 switch (sectype) {
286 case BDB_GENERAL_FEATURES:{
287 const struct bdb_general_features *sec =
288 (const void *) section;
289 printf("General features:\n");
290
291 if (sec->panel_fitting)
292 printf("\tpanel_fitting = 0x%x\n",
293 sec->panel_fitting);
294 if (sec->flexaim)
295 printf("\tflexaim = 0x%x\n",
296 sec->flexaim);
297 if (sec->msg_enable)
298 printf("\tmsg_enable = 0x%x\n",
299 sec->msg_enable);
300 if (sec->clear_screen)
301 printf("\tclear_screen = 0x%x\n",
302 sec->clear_screen);
303 if (sec->color_flip)
304 printf("\tcolor_flip = 0x%x\n",
305 sec->color_flip);
306 if (sec->download_ext_vbt)
307 printf
308 ("\tdownload_ext_vbt = 0x%x\n",
309 sec->download_ext_vbt);
310 printf("\t*enable_ssc = 0x%x\n",
311 sec->enable_ssc);
312 printf("\t*ssc_freq = 0x%x\n",
313 sec->ssc_freq);
314 if (sec->enable_lfp_on_override)
315 printf
316 ("\tenable_lfp_on_override = 0x%x\n",
317 sec->enable_lfp_on_override);
318 if (sec->disable_ssc_ddt)
319 printf
320 ("\tdisable_ssc_ddt = 0x%x\n",
321 sec->disable_ssc_ddt);
322 if (sec->rsvd7)
323 printf("\trsvd7 = 0x%x\n",
324 sec->rsvd7);
325 printf("\t*display_clock_mode = 0x%x\n",
326 sec->display_clock_mode);
327 if (sec->rsvd8)
328 printf("\trsvd8 = 0x%x\n",
329 sec->rsvd8);
330 printf("\tdisable_smooth_vision = 0x%x\n",
331 sec->disable_smooth_vision);
332 if (sec->single_dvi)
333 printf("\tsingle_dvi = 0x%x\n",
334 sec->single_dvi);
335 if (sec->rsvd9)
336 printf("\trsvd9 = 0x%x\n",
337 sec->rsvd9);
338 printf
339 ("\t*fdi_rx_polarity_inverted = 0x%x\n",
340 sec->fdi_rx_polarity_inverted);
341 if (sec->rsvd10)
342 printf("\trsvd10 = 0x%x\n",
343 sec->rsvd10);
344 if (sec->legacy_monitor_detect)
345 printf
346 ("\tlegacy_monitor_detect = 0x%x\n",
347 sec->legacy_monitor_detect);
348 printf("\t*int_crt_support = 0x%x\n",
349 sec->int_crt_support);
350 printf("\t*int_tv_support = 0x%x\n",
351 sec->int_tv_support);
352 if (sec->int_efp_support)
353 printf
354 ("\tint_efp_support = 0x%x\n",
355 sec->int_efp_support);
356 if (sec->dp_ssc_enb)
357 printf("\tdp_ssc_enb = 0x%x\n",
358 sec->dp_ssc_enb);
359 if (sec->dp_ssc_freq)
360 printf("\tdp_ssc_freq = 0x%x\n",
361 sec->dp_ssc_freq);
362 if (sec->rsvd11)
363 printf("\trsvd11 = 0x%x\n",
364 sec->rsvd11);
365 break;
366 }
367 case BDB_DRIVER_FEATURES:{
368 const struct bdb_driver_features *sec =
369 (const void *) section;
370 printf("\t*LVDS config: %d\n",
371 sec->lvds_config);
372 printf("\t*Dual frequency: %d\n",
373 sec->dual_frequency);
374
375 break;
376 }
377 case BDB_SDVO_LVDS_OPTIONS:{
378 const struct bdb_sdvo_lvds_options *sec =
379 (const void *) section;
380 printf("\t*Panel type: %d\n",
381 sec->panel_type);
382
383 break;
384 }
385 case BDB_GENERAL_DEFINITIONS:{
386 const struct bdb_general_definitions *sec =
387 (const void *) section;
388 int ndev;
389 printf("\t*CRT DDC GMBUS pin: %d\n",
390 sec->crt_ddc_gmbus_pin);
391
392 printf("\tDPMS ACPI: %d\n",
393 sec->dpms_acpi);
394 printf("\tSkip boot CRT detect: %d\n",
395 sec->skip_boot_crt_detect);
396 printf("\tDPMS aim: %d\n", sec->dpms_aim);
397 if (sec->rsvd1)
398 printf("\trsvd1: 0x%x\n",
399 sec->rsvd1);
400 printf("\tboot_display: { %x, %x }\n",
401 sec->boot_display[0],
402 sec->boot_display[1]);
403 if (sec->child_dev_size !=
404 sizeof(struct common_child_dev_config))
405 printf("\tchild_dev_size: %d\n",
406 sec->child_dev_size);
407 ndev = (secsz - sizeof(*sec)) /
408 sizeof(struct common_child_dev_config);
409 printf("\t%d devices\n", ndev);
410 for (i = 0; i < ndev; i++) {
411 printf("\t*device type: %x ",
412 sec->devices[i].
413 device_type);
414#define DEVICE_TYPE_INT_LFP 0x1022
415#define DEVICE_TYPE_INT_TV 0x1009
416#define DEVICE_TYPE_EFP_DVI_HOTPLUG_PWR 0x6052
417 switch (sec->devices[i].device_type) {
418 case DEVICE_TYPE_INT_LFP:
419 printf("(flat panel)\n");
420 break;
421 case DEVICE_TYPE_INT_TV:
422 printf("(TV)\n");
423 break;
424 case DEVICE_TYPE_EFP_DVI_HOTPLUG_PWR:
425 printf
426 ("(DVI)\n");
427 break;
428 case 0:
429 printf("(Empty)\n");
430 break;
431 default:
432 printf("(Unknown)\n");
433 break;
434 }
435 if (!sec->devices[i].device_type)
436 continue;
437 printf("\t *dvo_port: %x\n",
438 sec->devices[i].dvo_port);
439 printf("\t *i2c_pin: %x\n",
440 sec->devices[i].i2c_pin);
441 printf("\t *slave_addr: %x\n",
442 sec->devices[i].slave_addr);
443 printf("\t *ddc_pin: %x\n",
444 sec->devices[i].ddc_pin);
445 printf("\t *dvo_wiring: %x\n",
446 sec->devices[i].dvo_wiring);
447 printf("\t edid_ptr: %x\n",
448 sec->devices[i].edid_ptr);
449 }
450
451 break;
452 }
453 case BDB_SKIP:{
454 const struct vbios_data *sec =
455 (const void *) section;
456 if (!is_first_skip)
457 break;
458 is_first_skip = 0;
459 printf("\ttype: %x\n", sec->type);
460 printf("\trelstage: %x\n", sec->relstage);
461 printf("\tchipset: %x\n", sec->chipset);
462 printf(sec->lvds_present ? "\tLVDS\n"
463 : "\tNo LVDS\n");
464 printf(sec->tv_present ? "\tTV\n"
465 : "\tNo TV\n");
466 if (sec->rsvd2)
467 printf("\trsvd2: 0x%x\n",
468 sec->rsvd2);
469 for (i = 0; i < 4; i++)
470 if (sec->rsvd3[i])
471 printf
472 ("\trsvd3[%d]: 0x%x\n",
473 i, sec->rsvd3[i]);
474 printf("\tSignon: %.155s\n", sec->signon);
475 printf("\tCopyright: %.155s\n",
476 sec->copyright);
477 printf("\tCode segment: %x\n",
478 sec->code_segment);
479 printf("\tDOS Boot mode: %x\n",
480 sec->dos_boot_mode);
481 printf("\tBandwidth percent: %x\n",
482 sec->bandwidth_percent);
483 if (sec->rsvd4)
484 printf("\trsvd4: 0x%x\n",
485 sec->rsvd4);
486 printf("\tBandwidth percent: %x\n",
487 sec->resize_pci_bios);
488 if (sec->rsvd5)
489 printf("\trsvd5: 0x%x\n",
490 sec->rsvd5);
491 break;
492 }
493 }
494 }
495
496}
497
498static void parse_vbios(const void *ptr)
499{
500 const optionrom_header_t *oh;
501 oh = ptr;
502 if (oh->signature != 0xaa55) {
503 fprintf(stderr, "bad oprom signature: %x\n",
504 oh->signature);
505 return;
506 }
507 if (!oh->vbt_offset) {
508 fprintf(stderr, "no VBT found\n");
509 return;
510 }
511 parse_vbt((const char *) ptr + oh->vbt_offset);
512}
513
514int main(int argc, char **argv)
515{
516 const void *ptr;
517 int fd;
518 if (argc == 2) {
519 fd = open(argv[1], O_RDONLY);
520 ptr = mmap(0, 65536, PROT_READ, MAP_SHARED, fd, 0);
521 } else {
522 fd = open("/dev/mem", O_RDONLY);
523 ptr = mmap(0, 65536, PROT_READ, MAP_SHARED, fd, 0xc0000);
524 }
525 if (ptr == MAP_FAILED) {
526 fprintf(stderr, "mmap failed: %s\n", strerror(errno));
527 return 1;
528 }
529 parse_vbios(ptr);
530 close(fd);
531 return 0;
532}