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