1 /*
2 * Copyright � 2006 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *
23 * Authors:
24 * Eric Anholt <eric@anholt.net>
25 *
26 */
27
28 #include <ctype.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <getopt.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <unistd.h>
36 #include <sys/mman.h>
37 #include <sys/stat.h>
38 #include <sys/types.h>
39
40 #include "igt_aux.h"
41 #include "intel_io.h"
42 #include "intel_chipset.h"
43 #include "drmtest.h"
44
45 /* kernel types for intel_vbt_defs.h */
46 typedef uint8_t u8;
47 typedef uint16_t u16;
48 typedef uint32_t u32;
49 typedef uint64_t u64;
50 #define __packed __attribute__ ((packed))
51
52 #define _INTEL_BIOS_PRIVATE
53 #include "intel_vbt_defs.h"
54
55 /* no bother to include "edid.h" */
56 #define _H_ACTIVE(x) (x[2] + ((x[4] & 0xF0) << 4))
57 #define _H_SYNC_OFF(x) (x[8] + ((x[11] & 0xC0) << 2))
58 #define _H_SYNC_WIDTH(x) (x[9] + ((x[11] & 0x30) << 4))
59 #define _H_BLANK(x) (x[3] + ((x[4] & 0x0F) << 8))
60 #define _V_ACTIVE(x) (x[5] + ((x[7] & 0xF0) << 4))
61 #define _V_SYNC_OFF(x) ((x[10] >> 4) + ((x[11] & 0x0C) << 2))
62 #define _V_SYNC_WIDTH(x) ((x[10] & 0x0F) + ((x[11] & 0x03) << 4))
63 #define _V_BLANK(x) (x[6] + ((x[7] & 0x0F) << 8))
64 #define _PIXEL_CLOCK(x) (x[0] + (x[1] << 8)) * 10000
65
66 #define YESNO(val) ((val) ? "yes" : "no")
67
68 /* This is not for mapping to memory layout. */
69 struct bdb_block {
70 uint8_t id;
71 uint32_t size;
72 const void *data;
73 };
74
75 struct context {
76 const struct vbt_header *vbt;
77 const struct bdb_header *bdb;
78 int size;
79
80 uint32_t devid;
81 int panel_type;
82 bool dump_all_panel_types;
83 bool hexdump;
84 };
85
86 /* Get BDB block size given a pointer to Block ID. */
_get_blocksize(const uint8_t * block_base)87 static uint32_t _get_blocksize(const uint8_t *block_base)
88 {
89 /* The MIPI Sequence Block v3+ has a separate size field. */
90 if (*block_base == BDB_MIPI_SEQUENCE && *(block_base + 3) >= 3)
91 return *((const uint32_t *)(block_base + 4));
92 else
93 return *((const uint16_t *)(block_base + 1));
94 }
95
find_section(struct context * context,int section_id)96 static struct bdb_block *find_section(struct context *context, int section_id)
97 {
98 const struct bdb_header *bdb = context->bdb;
99 int length = context->size;
100 struct bdb_block *block;
101 const uint8_t *base = (const uint8_t *)bdb;
102 int index = 0;
103 uint32_t total, current_size;
104 unsigned char current_id;
105
106 /* skip to first section */
107 index += bdb->header_size;
108 total = bdb->bdb_size;
109 if (total > length)
110 total = length;
111
112 block = malloc(sizeof(*block));
113 if (!block) {
114 fprintf(stderr, "out of memory\n");
115 exit(EXIT_FAILURE);
116 }
117
118 /* walk the sections looking for section_id */
119 while (index + 3 < total) {
120 current_id = *(base + index);
121 current_size = _get_blocksize(base + index);
122 index += 3;
123
124 if (index + current_size > total)
125 return NULL;
126
127 if (current_id == section_id) {
128 block->id = current_id;
129 block->size = current_size;
130 block->data = base + index;
131 return block;
132 }
133
134 index += current_size;
135 }
136
137 free(block);
138 return NULL;
139 }
140
dump_general_features(struct context * context,const struct bdb_block * block)141 static void dump_general_features(struct context *context,
142 const struct bdb_block *block)
143 {
144 const struct bdb_general_features *features = block->data;
145
146 printf("\tPanel fitting: ");
147 switch (features->panel_fitting) {
148 case 0:
149 printf("disabled\n");
150 break;
151 case 1:
152 printf("text only\n");
153 break;
154 case 2:
155 printf("graphics only\n");
156 break;
157 case 3:
158 printf("text & graphics\n");
159 break;
160 }
161 printf("\tFlexaim: %s\n", YESNO(features->flexaim));
162 printf("\tMessage: %s\n", YESNO(features->msg_enable));
163 printf("\tClear screen: %d\n", features->clear_screen);
164 printf("\tDVO color flip required: %s\n", YESNO(features->color_flip));
165
166 printf("\tExternal VBT: %s\n", YESNO(features->download_ext_vbt));
167 printf("\tEnable SSC: %s\n", YESNO(features->enable_ssc));
168 if (features->enable_ssc) {
169 if (!context->devid)
170 printf("\tSSC frequency: <unknown platform>\n");
171 else if (IS_VALLEYVIEW(context->devid) ||
172 IS_CHERRYVIEW(context->devid) ||
173 IS_BROXTON(context->devid))
174 printf("\tSSC frequency: 100 MHz\n");
175 else if (HAS_PCH_SPLIT(context->devid))
176 printf("\tSSC frequency: %s\n", features->ssc_freq ?
177 "100 MHz" : "120 MHz");
178 else
179 printf("\tSSC frequency: %s\n", features->ssc_freq ?
180 "100 MHz (66 MHz on 855)" : "96 MHz (48 MHz on 855)");
181 }
182 printf("\tLFP on override: %s\n",
183 YESNO(features->enable_lfp_on_override));
184 printf("\tDisable SSC on clone: %s\n",
185 YESNO(features->disable_ssc_ddt));
186 printf("\tUnderscan support for VGA timings: %s\n",
187 YESNO(features->underscan_vga_timings));
188 if (context->bdb->version >= 183)
189 printf("\tDynamic CD clock: %s\n", YESNO(features->display_clock_mode));
190 printf("\tHotplug support in VBIOS: %s\n",
191 YESNO(features->vbios_hotplug_support));
192
193 printf("\tDisable smooth vision: %s\n",
194 YESNO(features->disable_smooth_vision));
195 printf("\tSingle DVI for CRT/DVI: %s\n", YESNO(features->single_dvi));
196 if (context->bdb->version >= 181)
197 printf("\tEnable 180 degree rotation: %s\n", YESNO(features->rotate_180));
198 printf("\tInverted FDI Rx polarity: %s\n", YESNO(features->fdi_rx_polarity_inverted));
199 if (context->bdb->version >= 160) {
200 printf("\tExtended VBIOS mode: %s\n", YESNO(features->vbios_extended_mode));
201 printf("\tCopy iLFP DTD to SDVO LVDS DTD: %s\n", YESNO(features->copy_ilfp_dtd_to_sdvo_lvds_dtd));
202 printf("\tBest fit panel timing algorithm: %s\n", YESNO(features->panel_best_fit_timing));
203 printf("\tIgnore strap state: %s\n", YESNO(features->ignore_strap_state));
204 }
205
206 printf("\tLegacy monitor detect: %s\n",
207 YESNO(features->legacy_monitor_detect));
208
209 printf("\tIntegrated CRT: %s\n", YESNO(features->int_crt_support));
210 printf("\tIntegrated TV: %s\n", YESNO(features->int_tv_support));
211 printf("\tIntegrated EFP: %s\n", YESNO(features->int_efp_support));
212 printf("\tDP SSC enable: %s\n", YESNO(features->dp_ssc_enable));
213 if (features->dp_ssc_enable) {
214 if (IS_VALLEYVIEW(context->devid) || IS_CHERRYVIEW(context->devid) ||
215 IS_BROXTON(context->devid))
216 printf("\tSSC frequency: 100 MHz\n");
217 else if (HAS_PCH_SPLIT(context->devid))
218 printf("\tSSC frequency: %s\n", features->dp_ssc_freq ?
219 "100 MHz" : "120 MHz");
220 else
221 printf("\tSSC frequency: %s\n", features->dp_ssc_freq ?
222 "100 MHz" : "96 MHz");
223 }
224 printf("\tDP SSC dongle supported: %s\n", YESNO(features->dp_ssc_dongle_supported));
225 }
226
dump_backlight_info(struct context * context,const struct bdb_block * block)227 static void dump_backlight_info(struct context *context,
228 const struct bdb_block *block)
229 {
230 const struct bdb_lfp_backlight_data *backlight = block->data;
231 const struct lfp_backlight_data_entry *blc;
232
233 if (sizeof(*blc) != backlight->entry_size) {
234 printf("\tBacklight struct sizes don't match (expected %zu, got %u), skipping\n",
235 sizeof(*blc), backlight->entry_size);
236 return;
237 }
238
239 blc = &backlight->data[context->panel_type];
240
241 printf("\tInverter type: %d\n", blc->type);
242 printf("\t polarity: %d\n", blc->active_low_pwm);
243 printf("\t PWM freq: %d\n", blc->pwm_freq_hz);
244 printf("\tMinimum brightness: %d\n", blc->min_brightness);
245 }
246
247 static const struct {
248 unsigned short type;
249 const char *name;
250 } child_device_types[] = {
251 { DEVICE_TYPE_NONE, "none" },
252 { DEVICE_TYPE_CRT, "CRT" },
253 { DEVICE_TYPE_TV, "TV" },
254 { DEVICE_TYPE_EFP, "EFP" },
255 { DEVICE_TYPE_LFP, "LFP" },
256 { DEVICE_TYPE_CRT_DPMS, "CRT" },
257 { DEVICE_TYPE_CRT_DPMS_HOTPLUG, "CRT" },
258 { DEVICE_TYPE_TV_COMPOSITE, "TV composite" },
259 { DEVICE_TYPE_TV_MACROVISION, "TV" },
260 { DEVICE_TYPE_TV_RF_COMPOSITE, "TV" },
261 { DEVICE_TYPE_TV_SVIDEO_COMPOSITE, "TV S-Video" },
262 { DEVICE_TYPE_TV_SCART, "TV SCART" },
263 { DEVICE_TYPE_TV_CODEC_HOTPLUG_PWR, "TV" },
264 { DEVICE_TYPE_EFP_HOTPLUG_PWR, "EFP" },
265 { DEVICE_TYPE_EFP_DVI_HOTPLUG_PWR, "DVI" },
266 { DEVICE_TYPE_EFP_DVI_I, "DVI-I" },
267 { DEVICE_TYPE_EFP_DVI_D_DUAL, "DL-DVI-D" },
268 { DEVICE_TYPE_EFP_DVI_D_HDCP, "DVI-D" },
269 { DEVICE_TYPE_OPENLDI_HOTPLUG_PWR, "OpenLDI" },
270 { DEVICE_TYPE_OPENLDI_DUALPIX, "OpenLDI" },
271 { DEVICE_TYPE_LFP_PANELLINK, "PanelLink" },
272 { DEVICE_TYPE_LFP_CMOS_PWR, "CMOS LFP" },
273 { DEVICE_TYPE_LFP_LVDS_PWR, "LVDS" },
274 { DEVICE_TYPE_LFP_LVDS_DUAL, "LVDS" },
275 { DEVICE_TYPE_LFP_LVDS_DUAL_HDCP, "LVDS" },
276 { DEVICE_TYPE_INT_LFP, "LFP" },
277 { DEVICE_TYPE_INT_TV, "TV" },
278 { DEVICE_TYPE_DP, "DisplayPort" },
279 { DEVICE_TYPE_DP_DUAL_MODE, "DisplayPort/HDMI/DVI" },
280 { DEVICE_TYPE_DP_DVI, "DisplayPort/DVI" },
281 { DEVICE_TYPE_HDMI, "HDMI/DVI" },
282 { DEVICE_TYPE_DVI, "DVI" },
283 { DEVICE_TYPE_eDP, "eDP" },
284 { DEVICE_TYPE_MIPI, "MIPI" },
285 };
286 static const int num_child_device_types =
287 sizeof(child_device_types) / sizeof(child_device_types[0]);
288
child_device_type(unsigned short type)289 static const char *child_device_type(unsigned short type)
290 {
291 int i;
292
293 for (i = 0; i < num_child_device_types; i++)
294 if (child_device_types[i].type == type)
295 return child_device_types[i].name;
296
297 return "unknown";
298 }
299
300 static const struct {
301 unsigned short mask;
302 const char *name;
303 } child_device_type_bits[] = {
304 { DEVICE_TYPE_CLASS_EXTENSION, "Class extension" },
305 { DEVICE_TYPE_POWER_MANAGEMENT, "Power management" },
306 { DEVICE_TYPE_HOTPLUG_SIGNALING, "Hotplug signaling" },
307 { DEVICE_TYPE_INTERNAL_CONNECTOR, "Internal connector" },
308 { DEVICE_TYPE_NOT_HDMI_OUTPUT, "HDMI output" }, /* decoded as inverse */
309 { DEVICE_TYPE_MIPI_OUTPUT, "MIPI output" },
310 { DEVICE_TYPE_COMPOSITE_OUTPUT, "Composite output" },
311 { DEVICE_TYPE_DUAL_CHANNEL, "Dual channel" },
312 { 1 << 7, "Content protection" },
313 { DEVICE_TYPE_HIGH_SPEED_LINK, "High speed link" },
314 { DEVICE_TYPE_LVDS_SIGNALING, "LVDS signaling" },
315 { DEVICE_TYPE_TMDS_DVI_SIGNALING, "TMDS/DVI signaling" },
316 { DEVICE_TYPE_VIDEO_SIGNALING, "Video signaling" },
317 { DEVICE_TYPE_DISPLAYPORT_OUTPUT, "DisplayPort output" },
318 { DEVICE_TYPE_DIGITAL_OUTPUT, "Digital output" },
319 { DEVICE_TYPE_ANALOG_OUTPUT, "Analog output" },
320 };
321
dump_child_device_type_bits(uint16_t type)322 static void dump_child_device_type_bits(uint16_t type)
323 {
324 int i;
325
326 type ^= DEVICE_TYPE_NOT_HDMI_OUTPUT;
327
328 for (i = 0; i < ARRAY_SIZE(child_device_type_bits); i++) {
329 if (child_device_type_bits[i].mask & type)
330 printf("\t\t\t%s\n", child_device_type_bits[i].name);
331 }
332 }
333
334 static const struct {
335 unsigned char handle;
336 const char *name;
337 } child_device_handles[] = {
338 { DEVICE_HANDLE_CRT, "CRT" },
339 { DEVICE_HANDLE_EFP1, "EFP 1 (HDMI/DVI/DP)" },
340 { DEVICE_HANDLE_EFP2, "EFP 2 (HDMI/DVI/DP)" },
341 { DEVICE_HANDLE_EFP3, "EFP 3 (HDMI/DVI/DP)" },
342 { DEVICE_HANDLE_EFP4, "EFP 4 (HDMI/DVI/DP)" },
343 { DEVICE_HANDLE_LPF1, "LFP 1 (eDP)" },
344 { DEVICE_HANDLE_LFP2, "LFP 2 (eDP)" },
345 };
346 static const int num_child_device_handles =
347 sizeof(child_device_handles) / sizeof(child_device_handles[0]);
348
child_device_handle(unsigned char handle)349 static const char *child_device_handle(unsigned char handle)
350 {
351 int i;
352
353 for (i = 0; i < num_child_device_handles; i++)
354 if (child_device_handles[i].handle == handle)
355 return child_device_handles[i].name;
356
357 return "unknown";
358 }
359
360 static const char *dvo_port_names[] = {
361 [DVO_PORT_HDMIA] = "HDMI-A",
362 [DVO_PORT_HDMIB] = "HDMI-B",
363 [DVO_PORT_HDMIC] = "HDMI-C",
364 [DVO_PORT_HDMID] = "HDMI-D",
365 [DVO_PORT_LVDS] = "LVDS",
366 [DVO_PORT_TV] = "TV",
367 [DVO_PORT_CRT] = "CRT",
368 [DVO_PORT_DPB] = "DP-B",
369 [DVO_PORT_DPC] = "DP-C",
370 [DVO_PORT_DPD] = "DP-D",
371 [DVO_PORT_DPA] = "DP-A",
372 [DVO_PORT_DPE] = "DP-E",
373 [DVO_PORT_HDMIE] = "HDMI-E",
374 [DVO_PORT_MIPIA] = "MIPI-A",
375 [DVO_PORT_MIPIB] = "MIPI-B",
376 [DVO_PORT_MIPIC] = "MIPI-C",
377 [DVO_PORT_MIPID] = "MIPI-D",
378 };
379
dvo_port(uint8_t type)380 static const char *dvo_port(uint8_t type)
381 {
382 if (type < ARRAY_SIZE(dvo_port_names) && dvo_port_names[type])
383 return dvo_port_names[type];
384 else
385 return "unknown";
386 }
387
mipi_bridge_type(uint8_t type)388 static const char *mipi_bridge_type(uint8_t type)
389 {
390 switch (type) {
391 case 1:
392 return "ASUS";
393 case 2:
394 return "Toshiba";
395 case 3:
396 return "Renesas";
397 default:
398 return "unknown";
399 }
400 }
401
dump_hmdi_max_data_rate(uint8_t hdmi_max_data_rate)402 static void dump_hmdi_max_data_rate(uint8_t hdmi_max_data_rate)
403 {
404 static const uint16_t max_data_rate[] = {
405 [HDMI_MAX_DATA_RATE_PLATFORM] = 0,
406 [HDMI_MAX_DATA_RATE_297] = 297,
407 [HDMI_MAX_DATA_RATE_165] = 165,
408 };
409
410 if (hdmi_max_data_rate >= ARRAY_SIZE(max_data_rate))
411 printf("\t\tHDMI max data rate: <unknown> (0x%02x)\n",
412 hdmi_max_data_rate);
413 else if (hdmi_max_data_rate == HDMI_MAX_DATA_RATE_PLATFORM)
414 printf("\t\tHDMI max data rate: <platform max> (0x%02x)\n",
415 hdmi_max_data_rate);
416 else
417 printf("\t\tHDMI max data rate: %d MHz (0x%02x)\n",
418 max_data_rate[hdmi_max_data_rate],
419 hdmi_max_data_rate);
420 }
421
dump_child_device(struct context * context,const struct child_device_config * child)422 static void dump_child_device(struct context *context,
423 const struct child_device_config *child)
424 {
425 if (!child->device_type)
426 return;
427
428 printf("\tChild device info:\n");
429 printf("\t\tDevice handle: 0x%04x (%s)\n", child->handle,
430 child_device_handle(child->handle));
431 printf("\t\tDevice type: 0x%04x (%s)\n", child->device_type,
432 child_device_type(child->device_type));
433 dump_child_device_type_bits(child->device_type);
434
435 if (context->bdb->version < 152) {
436 printf("\t\tSignature: %.*s\n", (int)sizeof(child->device_id), child->device_id);
437 } else {
438 printf("\t\tI2C speed: 0x%02x\n", child->i2c_speed);
439 printf("\t\tDP onboard redriver: 0x%02x\n", child->dp_onboard_redriver);
440 printf("\t\tDP ondock redriver: 0x%02x\n", child->dp_ondock_redriver);
441 printf("\t\tHDMI level shifter value: 0x%02x\n", child->hdmi_level_shifter_value);
442 dump_hmdi_max_data_rate(child->hdmi_max_data_rate);
443 printf("\t\tOffset to DTD buffer for edidless CHILD: 0x%02x\n", child->dtd_buf_ptr);
444 printf("\t\tEdidless EFP: %s\n", YESNO(child->edidless_efp));
445 printf("\t\tCompression enable: %s\n", YESNO(child->compression_enable));
446 printf("\t\tCompression method CPS: %s\n", YESNO(child->compression_method));
447 printf("\t\tDual pipe ganged eDP: %s\n", YESNO(child->ganged_edp));
448 printf("\t\tCompression structure index: 0x%02x)\n", child->compression_structure_index);
449 printf("\t\tSlave DDI port: 0x%02x (%s)\n", child->slave_port, dvo_port(child->slave_port));
450 }
451
452 printf("\t\tAIM offset: %d\n", child->addin_offset);
453 printf("\t\tDVO Port: 0x%02x (%s)\n", child->dvo_port, dvo_port(child->dvo_port));
454
455 printf("\t\tAIM I2C pin: 0x%02x\n", child->i2c_pin);
456 printf("\t\tAIM Slave address: 0x%02x\n", child->slave_addr);
457 printf("\t\tDDC pin: 0x%02x\n", child->ddc_pin);
458 printf("\t\tEDID buffer ptr: 0x%02x\n", child->edid_ptr);
459 printf("\t\tDVO config: 0x%02x\n", child->dvo_cfg);
460
461 if (context->bdb->version < 155) {
462 printf("\t\tDVO2 Port: 0x%02x (%s)\n", child->dvo2_port, dvo_port(child->dvo2_port));
463 printf("\t\tI2C2 pin: 0x%02x\n", child->i2c2_pin);
464 printf("\t\tSlave2 address: 0x%02x\n", child->slave2_addr);
465 printf("\t\tDDC2 pin: 0x%02x\n", child->ddc2_pin);
466 } else {
467 printf("\t\tEFP routed through dock: %s\n", YESNO(child->efp_routed));
468 printf("\t\tLane reversal: %s\n", YESNO(child->lane_reversal));
469 printf("\t\tOnboard LSPCON: %s\n", YESNO(child->lspcon));
470 printf("\t\tIboost enable: %s\n", YESNO(child->iboost));
471 printf("\t\tHPD sense invert: %s\n", YESNO(child->hpd_invert));
472 printf("\t\tHDMI compatible? %s\n", YESNO(child->hdmi_support));
473 printf("\t\tDP compatible? %s\n", YESNO(child->dp_support));
474 printf("\t\tTMDS compatible? %s\n", YESNO(child->tmds_support));
475 printf("\t\tAux channel: 0x%02x\n", child->aux_channel);
476 printf("\t\tDongle detect: 0x%02x\n", child->dongle_detect);
477 }
478
479 printf("\t\tPipe capabilities: 0x%02x\n", child->pipe_cap);
480 printf("\t\tSDVO stall signal available: %s\n", YESNO(child->sdvo_stall));
481 printf("\t\tHotplug connect status: 0x%02x\n", child->hpd_status);
482 printf("\t\tIntegrated encoder instead of SDVO: %s\n", YESNO(child->integrated_encoder));
483 printf("\t\tDVO wiring: 0x%02x\n", child->dvo_wiring);
484
485 if (context->bdb->version < 171) {
486 printf("\t\tDVO2 wiring: 0x%02x\n", child->dvo2_wiring);
487 } else {
488 printf("\t\tMIPI bridge type: %02x (%s)\n", child->mipi_bridge_type,
489 mipi_bridge_type(child->mipi_bridge_type));
490 }
491
492 printf("\t\tDevice class extension: 0x%02x\n", child->extended_type);
493 printf("\t\tDVO function: 0x%02x\n", child->dvo_function);
494
495 if (context->bdb->version >= 195) {
496 printf("\t\tDP USB type C support: %s\n", YESNO(child->dp_usb_type_c));
497 printf("\t\t2X DP GPIO index: 0x%02x\n", child->dp_gpio_index);
498 printf("\t\t2X DP GPIO pin number: 0x%02x\n", child->dp_gpio_pin_num);
499 }
500
501 if (context->bdb->version >= 196) {
502 printf("\t\tIBoost level for HDMI: 0x%02x\n", child->hdmi_iboost_level);
503 printf("\t\tIBoost level for DP/eDP: 0x%02x\n", child->dp_iboost_level);
504 }
505 }
506
507
dump_child_devices(struct context * context,const uint8_t * devices,uint8_t child_dev_num,uint8_t child_dev_size)508 static void dump_child_devices(struct context *context, const uint8_t *devices,
509 uint8_t child_dev_num, uint8_t child_dev_size)
510 {
511 struct child_device_config *child;
512 int i;
513
514 /*
515 * Use a temp buffer so dump_child_device() doesn't have to worry about
516 * accessing the struct beyond child_dev_size. The tail, if any, remains
517 * initialized to zero.
518 */
519 child = calloc(1, sizeof(*child));
520
521 for (i = 0; i < child_dev_num; i++) {
522 memcpy(child, devices + i * child_dev_size,
523 min(sizeof(*child), child_dev_size));
524
525 dump_child_device(context, child);
526 }
527
528 free(child);
529 }
530
dump_general_definitions(struct context * context,const struct bdb_block * block)531 static void dump_general_definitions(struct context *context,
532 const struct bdb_block *block)
533 {
534 const struct bdb_general_definitions *defs = block->data;
535 int child_dev_num;
536
537 child_dev_num = (block->size - sizeof(*defs)) / defs->child_dev_size;
538
539 printf("\tCRT DDC GMBUS addr: 0x%02x\n", defs->crt_ddc_gmbus_pin);
540 printf("\tUse ACPI DPMS CRT power states: %s\n",
541 YESNO(defs->dpms_acpi));
542 printf("\tSkip CRT detect at boot: %s\n",
543 YESNO(defs->skip_boot_crt_detect));
544 printf("\tUse DPMS on AIM devices: %s\n", YESNO(defs->dpms_aim));
545 printf("\tBoot display type: 0x%02x%02x\n", defs->boot_display[1],
546 defs->boot_display[0]);
547 printf("\tChild device size: %d\n", defs->child_dev_size);
548 printf("\tChild device count: %d\n", child_dev_num);
549
550 dump_child_devices(context, defs->devices,
551 child_dev_num, defs->child_dev_size);
552 }
553
dump_legacy_child_devices(struct context * context,const struct bdb_block * block)554 static void dump_legacy_child_devices(struct context *context,
555 const struct bdb_block *block)
556 {
557 const struct bdb_legacy_child_devices *defs = block->data;
558 int child_dev_num;
559
560 child_dev_num = (block->size - sizeof(*defs)) / defs->child_dev_size;
561
562 printf("\tChild device size: %d\n", defs->child_dev_size);
563 printf("\tChild device count: %d\n", child_dev_num);
564
565 dump_child_devices(context, defs->devices,
566 child_dev_num, defs->child_dev_size);
567 }
568
dump_lvds_options(struct context * context,const struct bdb_block * block)569 static void dump_lvds_options(struct context *context,
570 const struct bdb_block *block)
571 {
572 const struct bdb_lvds_options *options = block->data;
573
574 if (context->panel_type == options->panel_type)
575 printf("\tPanel type: %d\n", options->panel_type);
576 else
577 printf("\tPanel type: %d (override %d)\n",
578 options->panel_type, context->panel_type);
579 printf("\tLVDS EDID available: %s\n", YESNO(options->lvds_edid));
580 printf("\tPixel dither: %s\n", YESNO(options->pixel_dither));
581 printf("\tPFIT auto ratio: %s\n", YESNO(options->pfit_ratio_auto));
582 printf("\tPFIT enhanced graphics mode: %s\n",
583 YESNO(options->pfit_gfx_mode_enhanced));
584 printf("\tPFIT enhanced text mode: %s\n",
585 YESNO(options->pfit_text_mode_enhanced));
586 printf("\tPFIT mode: %d\n", options->pfit_mode);
587 }
588
dump_lvds_ptr_data(struct context * context,const struct bdb_block * block)589 static void dump_lvds_ptr_data(struct context *context,
590 const struct bdb_block *block)
591 {
592 const struct bdb_lvds_lfp_data_ptrs *ptrs = block->data;
593
594 printf("\tNumber of entries: %d\n", ptrs->lvds_entries);
595 }
596
dump_lvds_data(struct context * context,const struct bdb_block * block)597 static void dump_lvds_data(struct context *context,
598 const struct bdb_block *block)
599 {
600 const struct bdb_lvds_lfp_data *lvds_data = block->data;
601 struct bdb_block *ptrs_block;
602 const struct bdb_lvds_lfp_data_ptrs *ptrs;
603 int num_entries;
604 int i;
605 int hdisplay, hsyncstart, hsyncend, htotal;
606 int vdisplay, vsyncstart, vsyncend, vtotal;
607 float clock;
608 int lfp_data_size, dvo_offset;
609
610 ptrs_block = find_section(context, BDB_LVDS_LFP_DATA_PTRS);
611 if (!ptrs_block) {
612 printf("No LVDS ptr block\n");
613 return;
614 }
615
616 ptrs = ptrs_block->data;
617
618 lfp_data_size =
619 ptrs->ptr[1].fp_timing_offset - ptrs->ptr[0].fp_timing_offset;
620 dvo_offset =
621 ptrs->ptr[0].dvo_timing_offset - ptrs->ptr[0].fp_timing_offset;
622
623 num_entries = block->size / lfp_data_size;
624
625 printf(" Number of entries: %d (preferred block marked with '*')\n",
626 num_entries);
627
628 for (i = 0; i < num_entries; i++) {
629 const uint8_t *lfp_data_ptr =
630 (const uint8_t *) lvds_data->data + lfp_data_size * i;
631 const uint8_t *timing_data = lfp_data_ptr + dvo_offset;
632 const struct lvds_lfp_data_entry *lfp_data =
633 (const struct lvds_lfp_data_entry *)lfp_data_ptr;
634 char marker;
635
636 if (i != context->panel_type && !context->dump_all_panel_types)
637 continue;
638
639 if (i == context->panel_type)
640 marker = '*';
641 else
642 marker = ' ';
643
644 hdisplay = _H_ACTIVE(timing_data);
645 hsyncstart = hdisplay + _H_SYNC_OFF(timing_data);
646 hsyncend = hsyncstart + _H_SYNC_WIDTH(timing_data);
647 htotal = hdisplay + _H_BLANK(timing_data);
648
649 vdisplay = _V_ACTIVE(timing_data);
650 vsyncstart = vdisplay + _V_SYNC_OFF(timing_data);
651 vsyncend = vsyncstart + _V_SYNC_WIDTH(timing_data);
652 vtotal = vdisplay + _V_BLANK(timing_data);
653 clock = _PIXEL_CLOCK(timing_data) / 1000;
654
655 printf("%c\tpanel type %02i: %dx%d clock %d\n", marker,
656 i, lfp_data->fp_timing.x_res, lfp_data->fp_timing.y_res,
657 _PIXEL_CLOCK(timing_data));
658 printf("\t\tinfo:\n");
659 printf("\t\t LVDS: 0x%08lx\n",
660 (unsigned long)lfp_data->fp_timing.lvds_reg_val);
661 printf("\t\t PP_ON_DELAYS: 0x%08lx\n",
662 (unsigned long)lfp_data->fp_timing.pp_on_reg_val);
663 printf("\t\t PP_OFF_DELAYS: 0x%08lx\n",
664 (unsigned long)lfp_data->fp_timing.pp_off_reg_val);
665 printf("\t\t PP_DIVISOR: 0x%08lx\n",
666 (unsigned long)lfp_data->fp_timing.pp_cycle_reg_val);
667 printf("\t\t PFIT: 0x%08lx\n",
668 (unsigned long)lfp_data->fp_timing.pfit_reg_val);
669 printf("\t\ttimings: %d %d %d %d %d %d %d %d %.2f (%s)\n",
670 hdisplay, hsyncstart, hsyncend, htotal,
671 vdisplay, vsyncstart, vsyncend, vtotal, clock,
672 (hsyncend > htotal || vsyncend > vtotal) ?
673 "BAD!" : "good");
674 }
675
676 free(ptrs_block);
677 }
678
dump_driver_feature(struct context * context,const struct bdb_block * block)679 static void dump_driver_feature(struct context *context,
680 const struct bdb_block *block)
681 {
682 const struct bdb_driver_features *feature = block->data;
683
684 printf("\tBoot Device Algorithm: %s\n", feature->boot_dev_algorithm ?
685 "driver default" : "os default");
686 printf("\tBlock display switching when DVD active: %s\n",
687 YESNO(feature->block_display_switch));
688 printf("\tAllow display switching when in Full Screen DOS: %s\n",
689 YESNO(feature->allow_display_switch));
690 printf("\tHot Plug DVO: %s\n", YESNO(feature->hotplug_dvo));
691 printf("\tDual View Zoom: %s\n", YESNO(feature->dual_view_zoom));
692 printf("\tDriver INT 15h hook: %s\n", YESNO(feature->int15h_hook));
693 printf("\tEnable Sprite in Clone Mode: %s\n",
694 YESNO(feature->sprite_in_clone));
695 printf("\tUse 00000110h ID for Primary LFP: %s\n",
696 YESNO(feature->primary_lfp_id));
697 printf("\tBoot Mode X: %u\n", feature->boot_mode_x);
698 printf("\tBoot Mode Y: %u\n", feature->boot_mode_y);
699 printf("\tBoot Mode Bpp: %u\n", feature->boot_mode_bpp);
700 printf("\tBoot Mode Refresh: %u\n", feature->boot_mode_refresh);
701 printf("\tEnable LFP as primary: %s\n",
702 YESNO(feature->enable_lfp_primary));
703 printf("\tSelective Mode Pruning: %s\n",
704 YESNO(feature->selective_mode_pruning));
705 printf("\tDual-Frequency Graphics Technology: %s\n",
706 YESNO(feature->dual_frequency));
707 printf("\tDefault Render Clock Frequency: %s\n",
708 feature->render_clock_freq ? "low" : "high");
709 printf("\tNT 4.0 Dual Display Clone Support: %s\n",
710 YESNO(feature->nt_clone_support));
711 printf("\tDefault Power Scheme user interface: %s\n",
712 feature->power_scheme_ui ? "3rd party" : "CUI");
713 printf
714 ("\tSprite Display Assignment when Overlay is Active in Clone Mode: %s\n",
715 feature->sprite_display_assign ? "primary" : "secondary");
716 printf("\tDisplay Maintain Aspect Scaling via CUI: %s\n",
717 YESNO(feature->cui_aspect_scaling));
718 printf("\tPreserve Aspect Ratio: %s\n",
719 YESNO(feature->preserve_aspect_ratio));
720 printf("\tEnable SDVO device power down: %s\n",
721 YESNO(feature->sdvo_device_power_down));
722 printf("\tCRT hotplug: %s\n", YESNO(feature->crt_hotplug));
723 printf("\tLVDS config: ");
724 switch (feature->lvds_config) {
725 case BDB_DRIVER_NO_LVDS:
726 printf("No LVDS\n");
727 break;
728 case BDB_DRIVER_INT_LVDS:
729 printf("Integrated LVDS\n");
730 break;
731 case BDB_DRIVER_SDVO_LVDS:
732 printf("SDVO LVDS\n");
733 break;
734 case BDB_DRIVER_EDP:
735 printf("Embedded DisplayPort\n");
736 break;
737 }
738 printf("\tDefine Display statically: %s\n",
739 YESNO(feature->static_display));
740 printf("\tLegacy CRT max X: %d\n", feature->legacy_crt_max_x);
741 printf("\tLegacy CRT max Y: %d\n", feature->legacy_crt_max_y);
742 printf("\tLegacy CRT max refresh: %d\n",
743 feature->legacy_crt_max_refresh);
744 printf("\tEnable DRRS: %s\n", YESNO(feature->drrs_enabled));
745 printf("\tEnable PSR: %s\n", YESNO(feature->psr_enabled));
746 }
747
dump_edp(struct context * context,const struct bdb_block * block)748 static void dump_edp(struct context *context,
749 const struct bdb_block *block)
750 {
751 const struct bdb_edp *edp = block->data;
752 int bpp, msa;
753 int i;
754
755 for (i = 0; i < 16; i++) {
756 if (i != context->panel_type && !context->dump_all_panel_types)
757 continue;
758
759 printf("\tPanel %d%s\n", i, context->panel_type == i ? " *" : "");
760
761 printf("\t\tPower Sequence: T3 %d T7 %d T9 %d T10 %d T12 %d\n",
762 edp->power_seqs[i].t3,
763 edp->power_seqs[i].t7,
764 edp->power_seqs[i].t9,
765 edp->power_seqs[i].t10,
766 edp->power_seqs[i].t12);
767
768 bpp = (edp->color_depth >> (i * 2)) & 3;
769
770 printf("\t\tPanel color depth: ");
771 switch (bpp) {
772 case EDP_18BPP:
773 printf("18 bpp\n");
774 break;
775 case EDP_24BPP:
776 printf("24 bpp\n");
777 break;
778 case EDP_30BPP:
779 printf("30 bpp\n");
780 break;
781 default:
782 printf("(unknown value %d)\n", bpp);
783 break;
784 }
785
786 msa = (edp->sdrrs_msa_timing_delay >> (i * 2)) & 3;
787 printf("\t\teDP sDRRS MSA Delay: Lane %d\n", msa + 1);
788
789 printf("\t\tFast link params:\n");
790 printf("\t\t\trate: ");
791 if (edp->fast_link_params[i].rate == EDP_RATE_1_62)
792 printf("1.62G\n");
793 else if (edp->fast_link_params[i].rate == EDP_RATE_2_7)
794 printf("2.7G\n");
795 printf("\t\t\tlanes: ");
796 switch (edp->fast_link_params[i].lanes) {
797 case EDP_LANE_1:
798 printf("x1 mode\n");
799 break;
800 case EDP_LANE_2:
801 printf("x2 mode\n");
802 break;
803 case EDP_LANE_4:
804 printf("x4 mode\n");
805 break;
806 default:
807 printf("(unknown value %d)\n",
808 edp->fast_link_params[i].lanes);
809 break;
810 }
811 printf("\t\t\tpre-emphasis: ");
812 switch (edp->fast_link_params[i].preemphasis) {
813 case EDP_PREEMPHASIS_NONE:
814 printf("none\n");
815 break;
816 case EDP_PREEMPHASIS_3_5dB:
817 printf("3.5dB\n");
818 break;
819 case EDP_PREEMPHASIS_6dB:
820 printf("6dB\n");
821 break;
822 case EDP_PREEMPHASIS_9_5dB:
823 printf("9.5dB\n");
824 break;
825 default:
826 printf("(unknown value %d)\n",
827 edp->fast_link_params[i].preemphasis);
828 break;
829 }
830 printf("\t\t\tvswing: ");
831 switch (edp->fast_link_params[i].vswing) {
832 case EDP_VSWING_0_4V:
833 printf("0.4V\n");
834 break;
835 case EDP_VSWING_0_6V:
836 printf("0.6V\n");
837 break;
838 case EDP_VSWING_0_8V:
839 printf("0.8V\n");
840 break;
841 case EDP_VSWING_1_2V:
842 printf("1.2V\n");
843 break;
844 default:
845 printf("(unknown value %d)\n",
846 edp->fast_link_params[i].vswing);
847 break;
848 }
849
850 if (context->bdb->version >= 162) {
851 bool val = (edp->edp_s3d_feature >> i) & 1;
852 printf("\t\tStereo 3D feature: %s\n", YESNO(val));
853 }
854
855 if (context->bdb->version >= 165) {
856 bool val = (edp->edp_t3_optimization >> i) & 1;
857 printf("\t\tT3 optimization: %s\n", YESNO(val));
858 }
859
860 if (context->bdb->version >= 173) {
861 int val = (edp->edp_vswing_preemph >> (i * 4)) & 0xf;
862
863 printf("\t\tVswing/preemphasis table selection: ");
864 switch (val) {
865 case 0:
866 printf("Low power (200 mV)\n");
867 break;
868 case 1:
869 printf("Default (400 mV)\n");
870 break;
871 default:
872 printf("(unknown value %d)\n", val);
873 break;
874 }
875 }
876
877 if (context->bdb->version >= 182) {
878 bool val = (edp->fast_link_training >> i) & 1;
879 printf("\t\tFast link training: %s\n", YESNO(val));
880 }
881
882 if (context->bdb->version >= 185) {
883 bool val = (edp->dpcd_600h_write_required >> i) & 1;
884 printf("\t\tDPCD 600h write required: %s\n", YESNO(val));
885 }
886
887 if (context->bdb->version >= 186) {
888 printf("\t\tPWM delays:\n"
889 "\t\t\tPWM on to backlight enable: %d\n"
890 "\t\t\tBacklight disable to PWM off: %d\n",
891 edp->pwm_delays[i].pwm_on_to_backlight_enable,
892 edp->pwm_delays[i].backlight_disable_to_pwm_off);
893 }
894
895 if (context->bdb->version >= 199) {
896 bool val = (edp->full_link_params_provided >> i) & 1;
897
898 printf("\t\tFull link params provided: %s\n", YESNO(val));
899 printf("\t\tFull link params:\n");
900 printf("\t\t\tpre-emphasis: ");
901 switch (edp->full_link_params[i].preemphasis) {
902 case EDP_PREEMPHASIS_NONE:
903 printf("none\n");
904 break;
905 case EDP_PREEMPHASIS_3_5dB:
906 printf("3.5dB\n");
907 break;
908 case EDP_PREEMPHASIS_6dB:
909 printf("6dB\n");
910 break;
911 case EDP_PREEMPHASIS_9_5dB:
912 printf("9.5dB\n");
913 break;
914 default:
915 printf("(unknown value %d)\n",
916 edp->full_link_params[i].preemphasis);
917 break;
918 }
919 printf("\t\t\tvswing: ");
920 switch (edp->full_link_params[i].vswing) {
921 case EDP_VSWING_0_4V:
922 printf("0.4V\n");
923 break;
924 case EDP_VSWING_0_6V:
925 printf("0.6V\n");
926 break;
927 case EDP_VSWING_0_8V:
928 printf("0.8V\n");
929 break;
930 case EDP_VSWING_1_2V:
931 printf("1.2V\n");
932 break;
933 default:
934 printf("(unknown value %d)\n",
935 edp->full_link_params[i].vswing);
936 break;
937 }
938 }
939 }
940 }
941
dump_psr(struct context * context,const struct bdb_block * block)942 static void dump_psr(struct context *context,
943 const struct bdb_block *block)
944 {
945 const struct bdb_psr *psr_block = block->data;
946 int i;
947 uint32_t psr2_tp_time;
948
949 /* The same block ID was used for something else before? */
950 if (context->bdb->version < 165)
951 return;
952
953 psr2_tp_time = psr_block->psr2_tp2_tp3_wakeup_time;
954 for (i = 0; i < 16; i++) {
955 const struct psr_table *psr = &psr_block->psr_table[i];
956
957 if (i != context->panel_type && !context->dump_all_panel_types)
958 continue;
959
960 printf("\tPanel %d%s\n", i, context->panel_type == i ? " *" : "");
961
962 printf("\t\tFull link: %s\n", YESNO(psr->full_link));
963 printf("\t\tRequire AUX to wakeup: %s\n", YESNO(psr->require_aux_to_wakeup));
964
965 switch (psr->lines_to_wait) {
966 case 0:
967 case 1:
968 printf("\t\tLines to wait before link standby: %d\n",
969 psr->lines_to_wait);
970 break;
971 case 2:
972 case 3:
973 printf("\t\tLines to wait before link standby: %d\n",
974 1 << psr->lines_to_wait);
975 break;
976 default:
977 printf("\t\tLines to wait before link standby: (unknown) (0x%x)\n",
978 psr->lines_to_wait);
979 break;
980 }
981
982 printf("\t\tIdle frames to for PSR enable: %d\n",
983 psr->idle_frames);
984
985 printf("\t\tTP1 wakeup time: %d usec (0x%x)\n",
986 psr->tp1_wakeup_time * 100,
987 psr->tp1_wakeup_time);
988
989 printf("\t\tTP2/TP3 wakeup time: %d usec (0x%x)\n",
990 psr->tp2_tp3_wakeup_time * 100,
991 psr->tp2_tp3_wakeup_time);
992
993 if (context->bdb->version >= 226) {
994 int index;
995 static const uint16_t psr2_tp_times[] = {500, 100, 2500, 5};
996
997 index = (psr2_tp_time >> (i * 2)) & 0x3;
998 printf("\t\tPSR2 TP2/TP3 wakeup time: %d usec (0x%x)\n",
999 psr2_tp_times[index], index);
1000 }
1001 }
1002 }
1003
1004 static void
print_detail_timing_data(const struct lvds_dvo_timing * dvo_timing)1005 print_detail_timing_data(const struct lvds_dvo_timing *dvo_timing)
1006 {
1007 int display, sync_start, sync_end, total;
1008
1009 display = (dvo_timing->hactive_hi << 8) | dvo_timing->hactive_lo;
1010 sync_start = display +
1011 ((dvo_timing->hsync_off_hi << 8) | dvo_timing->hsync_off_lo);
1012 sync_end = sync_start + ((dvo_timing->hsync_pulse_width_hi << 8) |
1013 dvo_timing->hsync_pulse_width_lo);
1014 total = display +
1015 ((dvo_timing->hblank_hi << 8) | dvo_timing->hblank_lo);
1016 printf("\thdisplay: %d\n", display);
1017 printf("\thsync [%d, %d] %s\n", sync_start, sync_end,
1018 dvo_timing->hsync_positive ? "+sync" : "-sync");
1019 printf("\thtotal: %d\n", total);
1020
1021 display = (dvo_timing->vactive_hi << 8) | dvo_timing->vactive_lo;
1022 sync_start = display + ((dvo_timing->vsync_off_hi << 8) |
1023 dvo_timing->vsync_off_lo);
1024 sync_end = sync_start + ((dvo_timing->vsync_pulse_width_hi << 8) |
1025 dvo_timing->vsync_pulse_width_lo);
1026 total = display +
1027 ((dvo_timing->vblank_hi << 8) | dvo_timing->vblank_lo);
1028 printf("\tvdisplay: %d\n", display);
1029 printf("\tvsync [%d, %d] %s\n", sync_start, sync_end,
1030 dvo_timing->vsync_positive ? "+sync" : "-sync");
1031 printf("\tvtotal: %d\n", total);
1032
1033 printf("\tclock: %d\n", dvo_timing->clock * 10);
1034 }
1035
dump_sdvo_panel_dtds(struct context * context,const struct bdb_block * block)1036 static void dump_sdvo_panel_dtds(struct context *context,
1037 const struct bdb_block *block)
1038 {
1039 const struct lvds_dvo_timing *dvo_timing = block->data;
1040 int n, count;
1041
1042 count = block->size / sizeof(struct lvds_dvo_timing);
1043 for (n = 0; n < count; n++) {
1044 printf("%d:\n", n);
1045 print_detail_timing_data(dvo_timing++);
1046 }
1047 }
1048
dump_sdvo_lvds_options(struct context * context,const struct bdb_block * block)1049 static void dump_sdvo_lvds_options(struct context *context,
1050 const struct bdb_block *block)
1051 {
1052 const struct bdb_sdvo_lvds_options *options = block->data;
1053
1054 printf("\tbacklight: %d\n", options->panel_backlight);
1055 printf("\th40 type: %d\n", options->h40_set_panel_type);
1056 printf("\ttype: %d\n", options->panel_type);
1057 printf("\tssc_clk_freq: %d\n", options->ssc_clk_freq);
1058 printf("\tals_low_trip: %d\n", options->als_low_trip);
1059 printf("\tals_high_trip: %d\n", options->als_high_trip);
1060 /*
1061 u8 sclalarcoeff_tab_row_num;
1062 u8 sclalarcoeff_tab_row_size;
1063 u8 coefficient[8];
1064 */
1065 printf("\tmisc[0]: %x\n", options->panel_misc_bits_1);
1066 printf("\tmisc[1]: %x\n", options->panel_misc_bits_2);
1067 printf("\tmisc[2]: %x\n", options->panel_misc_bits_3);
1068 printf("\tmisc[3]: %x\n", options->panel_misc_bits_4);
1069 }
1070
dump_mipi_config(struct context * context,const struct bdb_block * block)1071 static void dump_mipi_config(struct context *context,
1072 const struct bdb_block *block)
1073 {
1074 const struct bdb_mipi_config *start = block->data;
1075 const struct mipi_config *config;
1076 const struct mipi_pps_data *pps;
1077
1078 config = &start->config[context->panel_type];
1079 pps = &start->pps[context->panel_type];
1080
1081 printf("\tGeneral Param\n");
1082 printf("\t\t BTA disable: %s\n", config->bta ? "Disabled" : "Enabled");
1083 printf("\t\t Panel Rotation: %d degrees\n", config->rotation * 90);
1084
1085 printf("\t\t Video Mode Color Format: ");
1086 if (config->videomode_color_format == 0)
1087 printf("Not supported\n");
1088 else if (config->videomode_color_format == 1)
1089 printf("RGB565\n");
1090 else if (config->videomode_color_format == 2)
1091 printf("RGB666\n");
1092 else if (config->videomode_color_format == 3)
1093 printf("RGB666 Loosely Packed\n");
1094 else if (config->videomode_color_format == 4)
1095 printf("RGB888\n");
1096 printf("\t\t PPS GPIO Pins: %s \n", config->pwm_blc ? "Using SOC" : "Using PMIC");
1097 printf("\t\t CABC Support: %s\n", config->cabc ? "supported" : "not supported");
1098 printf("\t\t Mode: %s\n", config->cmd_mode ? "COMMAND" : "VIDEO");
1099 printf("\t\t Video transfer mode: %s (0x%x)\n",
1100 config->vtm == 1 ? "non-burst with sync pulse" :
1101 config->vtm == 2 ? "non-burst with sync events" :
1102 config->vtm == 3 ? "burst" : "<unknown>",
1103 config->vtm);
1104 printf("\t\t Dithering: %s\n", config->dithering ? "done in Display Controller" : "done in Panel Controller");
1105
1106 printf("\tPort Desc\n");
1107 printf("\t\t Pixel overlap: %d\n", config->pixel_overlap);
1108 printf("\t\t Lane Count: %d\n", config->lane_cnt + 1);
1109 printf("\t\t Dual Link Support: ");
1110 if (config->dual_link == 0)
1111 printf("not supported\n");
1112 else if (config->dual_link == 1)
1113 printf("Front Back mode\n");
1114 else
1115 printf("Pixel Alternative Mode\n");
1116
1117 printf("\tDphy Flags\n");
1118 printf("\t\t Clock Stop: %s\n", config->clk_stop ? "ENABLED" : "DISABLED");
1119 printf("\t\t EOT disabled: %s\n\n", config->eot_disabled ? "EOT not to be sent" : "EOT to be sent");
1120
1121 printf("\tHSTxTimeOut: 0x%x\n", config->hs_tx_timeout);
1122 printf("\tLPRXTimeOut: 0x%x\n", config->lp_rx_timeout);
1123 printf("\tTurnAroundTimeOut: 0x%x\n", config->turn_around_timeout);
1124 printf("\tDeviceResetTimer: 0x%x\n", config->device_reset_timer);
1125 printf("\tMasterinitTimer: 0x%x\n", config->master_init_timer);
1126 printf("\tDBIBandwidthTimer: 0x%x\n", config->dbi_bw_timer);
1127 printf("\tLpByteClkValue: 0x%x\n\n", config->lp_byte_clk_val);
1128
1129 printf("\tDphy Params\n");
1130 printf("\t\tExit to zero Count: 0x%x\n", config->exit_zero_cnt);
1131 printf("\t\tTrail Count: 0x%X\n", config->trail_cnt);
1132 printf("\t\tClk zero count: 0x%x\n", config->clk_zero_cnt);
1133 printf("\t\tPrepare count:0x%x\n\n", config->prepare_cnt);
1134
1135 printf("\tClockLaneSwitchingCount: 0x%x\n", config->clk_lane_switch_cnt);
1136 printf("\tHighToLowSwitchingCount: 0x%x\n\n", config->hl_switch_cnt);
1137
1138 printf("\tTimings based on Dphy spec\n");
1139 printf("\t\tTClkMiss: 0x%x\n", config->tclk_miss);
1140 printf("\t\tTClkPost: 0x%x\n", config->tclk_post);
1141 printf("\t\tTClkPre: 0x%x\n", config->tclk_pre);
1142 printf("\t\tTClkPrepare: 0x%x\n", config->tclk_prepare);
1143 printf("\t\tTClkSettle: 0x%x\n", config->tclk_settle);
1144 printf("\t\tTClkTermEnable: 0x%x\n\n", config->tclk_term_enable);
1145
1146 printf("\tTClkTrail: 0x%x\n", config->tclk_trail);
1147 printf("\tTClkPrepareTClkZero: 0x%x\n", config->tclk_prepare_clkzero);
1148 printf("\tTHSExit: 0x%x\n", config->ths_exit);
1149 printf("\tTHsPrepare: 0x%x\n", config->ths_prepare);
1150 printf("\tTHsPrepareTHsZero: 0x%x\n", config->ths_prepare_hszero);
1151 printf("\tTHSSettle: 0x%x\n", config->ths_settle);
1152 printf("\tTHSSkip: 0x%x\n", config->ths_skip);
1153 printf("\tTHsTrail: 0x%x\n", config->ths_trail);
1154 printf("\tTInit: 0x%x\n", config->tinit);
1155 printf("\tTLPX: 0x%x\n", config->tlpx);
1156
1157 printf("\tMIPI PPS\n");
1158 printf("\t\tPanel power ON delay: %d\n", pps->panel_on_delay);
1159 printf("\t\tPanel power on to Backlight enable delay: %d\n", pps->bl_enable_delay);
1160 printf("\t\tBacklight disable to Panel power OFF delay: %d\n", pps->bl_disable_delay);
1161 printf("\t\tPanel power OFF delay: %d\n", pps->panel_off_delay);
1162 printf("\t\tPanel power cycle delay: %d\n", pps->panel_power_cycle_delay);
1163 }
1164
mipi_dump_send_packet(const uint8_t * data,uint8_t seq_version)1165 static const uint8_t *mipi_dump_send_packet(const uint8_t *data, uint8_t seq_version)
1166 {
1167 uint8_t flags, type;
1168 uint16_t len, i;
1169
1170 flags = *data++;
1171 type = *data++;
1172 len = *((const uint16_t *) data);
1173 data += 2;
1174
1175 printf("\t\tSend DCS: Port %s, VC %d, %s, Type %02x, Length %u, Data",
1176 (flags >> 3) & 1 ? "C" : "A",
1177 (flags >> 1) & 3,
1178 flags & 1 ? "HS" : "LP",
1179 type,
1180 len);
1181 for (i = 0; i < len; i++)
1182 printf(" %02x", *data++);
1183 printf("\n");
1184
1185 return data;
1186 }
1187
mipi_dump_delay(const uint8_t * data,uint8_t seq_version)1188 static const uint8_t *mipi_dump_delay(const uint8_t *data, uint8_t seq_version)
1189 {
1190 printf("\t\tDelay: %u us\n", *((const uint32_t *)data));
1191
1192 return data + 4;
1193 }
1194
mipi_dump_gpio(const uint8_t * data,uint8_t seq_version)1195 static const uint8_t *mipi_dump_gpio(const uint8_t *data, uint8_t seq_version)
1196 {
1197 uint8_t index, number, flags;
1198
1199 if (seq_version >= 3) {
1200 index = *data++;
1201 number = *data++;
1202 flags = *data++;
1203
1204 printf("\t\tGPIO index %u, number %u, set %d (0x%02x)\n",
1205 index, number, flags & 1, flags);
1206 } else {
1207 index = *data++;
1208 flags = *data++;
1209
1210 printf("\t\tGPIO index %u, source %d, set %d (0x%02x)\n",
1211 index, (flags >> 1) & 3, flags & 1, flags);
1212 }
1213
1214 return data;
1215 }
1216
mipi_dump_i2c(const uint8_t * data,uint8_t seq_version)1217 static const uint8_t *mipi_dump_i2c(const uint8_t *data, uint8_t seq_version)
1218 {
1219 uint8_t flags, index, bus, offset, len, i;
1220 uint16_t address;
1221
1222 flags = *data++;
1223 index = *data++;
1224 bus = *data++;
1225 address = *((const uint16_t *) data);
1226 data += 2;
1227 offset = *data++;
1228 len = *data++;
1229
1230 printf("\t\tSend I2C: Flags %02x, Index %02x, Bus %02x, Address %04x, Offset %02x, Length %u, Data",
1231 flags, index, bus, address, offset, len);
1232 for (i = 0; i < len; i++)
1233 printf(" %02x", *data++);
1234 printf("\n");
1235
1236 return data;
1237 }
1238
1239 typedef const uint8_t * (*fn_mipi_elem_dump)(const uint8_t *data, uint8_t seq_version);
1240
1241 static const fn_mipi_elem_dump dump_elem[] = {
1242 [MIPI_SEQ_ELEM_SEND_PKT] = mipi_dump_send_packet,
1243 [MIPI_SEQ_ELEM_DELAY] = mipi_dump_delay,
1244 [MIPI_SEQ_ELEM_GPIO] = mipi_dump_gpio,
1245 [MIPI_SEQ_ELEM_I2C] = mipi_dump_i2c,
1246 };
1247
1248 static const char * const seq_name[] = {
1249 [MIPI_SEQ_ASSERT_RESET] = "MIPI_SEQ_ASSERT_RESET",
1250 [MIPI_SEQ_INIT_OTP] = "MIPI_SEQ_INIT_OTP",
1251 [MIPI_SEQ_DISPLAY_ON] = "MIPI_SEQ_DISPLAY_ON",
1252 [MIPI_SEQ_DISPLAY_OFF] = "MIPI_SEQ_DISPLAY_OFF",
1253 [MIPI_SEQ_DEASSERT_RESET] = "MIPI_SEQ_DEASSERT_RESET",
1254 [MIPI_SEQ_BACKLIGHT_ON] = "MIPI_SEQ_BACKLIGHT_ON",
1255 [MIPI_SEQ_BACKLIGHT_OFF] = "MIPI_SEQ_BACKLIGHT_OFF",
1256 [MIPI_SEQ_TEAR_ON] = "MIPI_SEQ_TEAR_ON",
1257 [MIPI_SEQ_TEAR_OFF] = "MIPI_SEQ_TEAR_OFF",
1258 [MIPI_SEQ_POWER_ON] = "MIPI_SEQ_POWER_ON",
1259 [MIPI_SEQ_POWER_OFF] = "MIPI_SEQ_POWER_OFF",
1260 };
1261
sequence_name(enum mipi_seq seq_id)1262 static const char *sequence_name(enum mipi_seq seq_id)
1263 {
1264 if (seq_id < ARRAY_SIZE(seq_name) && seq_name[seq_id])
1265 return seq_name[seq_id];
1266 else
1267 return "(unknown)";
1268 }
1269
dump_sequence(const uint8_t * data,uint8_t seq_version)1270 static const uint8_t *dump_sequence(const uint8_t *data, uint8_t seq_version)
1271 {
1272 fn_mipi_elem_dump mipi_elem_dump;
1273
1274 printf("\tSequence %u - %s\n", *data, sequence_name(*data));
1275
1276 /* Skip Sequence Byte. */
1277 data++;
1278
1279 /* Skip Size of Sequence. */
1280 if (seq_version >= 3)
1281 data += 4;
1282
1283 while (1) {
1284 uint8_t operation_byte = *data++;
1285 uint8_t operation_size = 0;
1286
1287 if (operation_byte == MIPI_SEQ_ELEM_END)
1288 break;
1289
1290 if (operation_byte < ARRAY_SIZE(dump_elem))
1291 mipi_elem_dump = dump_elem[operation_byte];
1292 else
1293 mipi_elem_dump = NULL;
1294
1295 /* Size of Operation. */
1296 if (seq_version >= 3)
1297 operation_size = *data++;
1298
1299 if (mipi_elem_dump) {
1300 const uint8_t *next = data + operation_size;
1301
1302 data = mipi_elem_dump(data, seq_version);
1303
1304 if (operation_size && next != data)
1305 printf("Error: Inconsistent operation size: %d\n",
1306 operation_size);
1307 } else if (operation_size) {
1308 /* We have size, skip. */
1309 data += operation_size;
1310 } else {
1311 /* No size, can't skip without parsing. */
1312 printf("Error: Unsupported MIPI element %u\n",
1313 operation_byte);
1314 return NULL;
1315 }
1316 }
1317
1318 return data;
1319 }
1320
1321 /* Find the sequence block and size for the given panel. */
1322 static const uint8_t *
find_panel_sequence_block(const struct bdb_mipi_sequence * sequence,uint16_t panel_id,uint32_t total,uint32_t * seq_size)1323 find_panel_sequence_block(const struct bdb_mipi_sequence *sequence,
1324 uint16_t panel_id, uint32_t total, uint32_t *seq_size)
1325 {
1326 const uint8_t *data = &sequence->data[0];
1327 uint8_t current_id;
1328 uint32_t current_size;
1329 int header_size = sequence->version >= 3 ? 5 : 3;
1330 int index = 0;
1331 int i;
1332
1333 /* skip new block size */
1334 if (sequence->version >= 3)
1335 data += 4;
1336
1337 for (i = 0; i < MAX_MIPI_CONFIGURATIONS && index < total; i++) {
1338 if (index + header_size > total) {
1339 fprintf(stderr, "Invalid sequence block (header)\n");
1340 return NULL;
1341 }
1342
1343 current_id = *(data + index);
1344 if (sequence->version >= 3)
1345 current_size = *((const uint32_t *)(data + index + 1));
1346 else
1347 current_size = *((const uint16_t *)(data + index + 1));
1348
1349 index += header_size;
1350
1351 if (index + current_size > total) {
1352 fprintf(stderr, "Invalid sequence block\n");
1353 return NULL;
1354 }
1355
1356 if (current_id == panel_id) {
1357 *seq_size = current_size;
1358 return data + index;
1359 }
1360
1361 index += current_size;
1362 }
1363
1364 fprintf(stderr, "Sequence block detected but no valid configuration\n");
1365
1366 return NULL;
1367 }
1368
goto_next_sequence(const uint8_t * data,int index,int total)1369 static int goto_next_sequence(const uint8_t *data, int index, int total)
1370 {
1371 uint16_t len;
1372
1373 /* Skip Sequence Byte. */
1374 for (index = index + 1; index < total; index += len) {
1375 uint8_t operation_byte = *(data + index);
1376 index++;
1377
1378 switch (operation_byte) {
1379 case MIPI_SEQ_ELEM_END:
1380 return index;
1381 case MIPI_SEQ_ELEM_SEND_PKT:
1382 if (index + 4 > total)
1383 return 0;
1384
1385 len = *((const uint16_t *)(data + index + 2)) + 4;
1386 break;
1387 case MIPI_SEQ_ELEM_DELAY:
1388 len = 4;
1389 break;
1390 case MIPI_SEQ_ELEM_GPIO:
1391 len = 2;
1392 break;
1393 case MIPI_SEQ_ELEM_I2C:
1394 if (index + 7 > total)
1395 return 0;
1396 len = *(data + index + 6) + 7;
1397 break;
1398 default:
1399 fprintf(stderr, "Unknown operation byte\n");
1400 return 0;
1401 }
1402 }
1403
1404 return 0;
1405 }
1406
goto_next_sequence_v3(const uint8_t * data,int index,int total)1407 static int goto_next_sequence_v3(const uint8_t *data, int index, int total)
1408 {
1409 int seq_end;
1410 uint16_t len;
1411 uint32_t size_of_sequence;
1412
1413 /*
1414 * Could skip sequence based on Size of Sequence alone, but also do some
1415 * checking on the structure.
1416 */
1417 if (total < 5) {
1418 fprintf(stderr, "Too small sequence size\n");
1419 return 0;
1420 }
1421
1422 /* Skip Sequence Byte. */
1423 index++;
1424
1425 /*
1426 * Size of Sequence. Excludes the Sequence Byte and the size itself,
1427 * includes MIPI_SEQ_ELEM_END byte, excludes the final MIPI_SEQ_END
1428 * byte.
1429 */
1430 size_of_sequence = *((const uint32_t *)(data + index));
1431 index += 4;
1432
1433 seq_end = index + size_of_sequence;
1434 if (seq_end > total) {
1435 fprintf(stderr, "Invalid sequence size\n");
1436 return 0;
1437 }
1438
1439 for (; index < total; index += len) {
1440 uint8_t operation_byte = *(data + index);
1441 index++;
1442
1443 if (operation_byte == MIPI_SEQ_ELEM_END) {
1444 if (index != seq_end) {
1445 fprintf(stderr, "Invalid element structure\n");
1446 return 0;
1447 }
1448 return index;
1449 }
1450
1451 len = *(data + index);
1452 index++;
1453
1454 /*
1455 * FIXME: Would be nice to check elements like for v1/v2 in
1456 * goto_next_sequence() above.
1457 */
1458 switch (operation_byte) {
1459 case MIPI_SEQ_ELEM_SEND_PKT:
1460 case MIPI_SEQ_ELEM_DELAY:
1461 case MIPI_SEQ_ELEM_GPIO:
1462 case MIPI_SEQ_ELEM_I2C:
1463 case MIPI_SEQ_ELEM_SPI:
1464 case MIPI_SEQ_ELEM_PMIC:
1465 break;
1466 default:
1467 fprintf(stderr, "Unknown operation byte %u\n",
1468 operation_byte);
1469 break;
1470 }
1471 }
1472
1473 return 0;
1474 }
1475
dump_mipi_sequence(struct context * context,const struct bdb_block * block)1476 static void dump_mipi_sequence(struct context *context,
1477 const struct bdb_block *block)
1478 {
1479 const struct bdb_mipi_sequence *sequence = block->data;
1480 const uint8_t *data;
1481 uint32_t seq_size;
1482 int index = 0, i;
1483 const uint8_t *sequence_ptrs[MIPI_SEQ_MAX] = {};
1484
1485 /* Check if we have sequence block as well */
1486 if (!sequence) {
1487 printf("No MIPI Sequence found\n");
1488 return;
1489 }
1490
1491 printf("\tSequence block version v%u\n", sequence->version);
1492
1493 /* Fail gracefully for forward incompatible sequence block. */
1494 if (sequence->version >= 4) {
1495 fprintf(stderr, "Unable to parse MIPI Sequence Block v%u\n",
1496 sequence->version);
1497 return;
1498 }
1499
1500 data = find_panel_sequence_block(sequence, context->panel_type,
1501 block->size, &seq_size);
1502 if (!data)
1503 return;
1504
1505 /* Parse the sequences. Corresponds to VBT parsing in the kernel. */
1506 for (;;) {
1507 uint8_t seq_id = *(data + index);
1508 if (seq_id == MIPI_SEQ_END)
1509 break;
1510
1511 if (seq_id >= MIPI_SEQ_MAX) {
1512 fprintf(stderr, "Unknown sequence %u\n", seq_id);
1513 return;
1514 }
1515
1516 sequence_ptrs[seq_id] = data + index;
1517
1518 if (sequence->version >= 3)
1519 index = goto_next_sequence_v3(data, index, seq_size);
1520 else
1521 index = goto_next_sequence(data, index, seq_size);
1522 if (!index) {
1523 fprintf(stderr, "Invalid sequence %u\n", seq_id);
1524 return;
1525 }
1526 }
1527
1528 /* Dump the sequences. Corresponds to sequence execution in kernel. */
1529 for (i = 0; i < ARRAY_SIZE(sequence_ptrs); i++)
1530 if (sequence_ptrs[i])
1531 dump_sequence(sequence_ptrs[i], sequence->version);
1532 }
1533
1534 /* get panel type from lvds options block, or -1 if block not found */
get_panel_type(struct context * context)1535 static int get_panel_type(struct context *context)
1536 {
1537 struct bdb_block *block;
1538 const struct bdb_lvds_options *options;
1539 int panel_type;
1540
1541 block = find_section(context, BDB_LVDS_OPTIONS);
1542 if (!block)
1543 return -1;
1544
1545 options = block->data;
1546 panel_type = options->panel_type;
1547
1548 free(block);
1549
1550 return panel_type;
1551 }
1552
1553 static int
get_device_id(unsigned char * bios,int size)1554 get_device_id(unsigned char *bios, int size)
1555 {
1556 int device;
1557 int offset = (bios[0x19] << 8) + bios[0x18];
1558
1559 if (offset + 7 >= size)
1560 return -1;
1561
1562 if (bios[offset] != 'P' ||
1563 bios[offset+1] != 'C' ||
1564 bios[offset+2] != 'I' ||
1565 bios[offset+3] != 'R')
1566 return -1;
1567
1568 device = (bios[offset+7] << 8) + bios[offset+6];
1569
1570 return device;
1571 }
1572
1573 struct dumper {
1574 uint8_t id;
1575 const char *name;
1576 void (*dump)(struct context *context,
1577 const struct bdb_block *block);
1578 };
1579
1580 struct dumper dumpers[] = {
1581 {
1582 .id = BDB_GENERAL_FEATURES,
1583 .name = "General features block",
1584 .dump = dump_general_features,
1585 },
1586 {
1587 .id = BDB_GENERAL_DEFINITIONS,
1588 .name = "General definitions block",
1589 .dump = dump_general_definitions,
1590 },
1591 {
1592 .id = BDB_CHILD_DEVICE_TABLE,
1593 .name = "Legacy child devices block",
1594 .dump = dump_legacy_child_devices,
1595 },
1596 {
1597 .id = BDB_LVDS_OPTIONS,
1598 .name = "LVDS options block",
1599 .dump = dump_lvds_options,
1600 },
1601 {
1602 .id = BDB_LVDS_LFP_DATA_PTRS,
1603 .name = "LVDS timing pointer data",
1604 .dump = dump_lvds_ptr_data,
1605 },
1606 {
1607 .id = BDB_LVDS_LFP_DATA,
1608 .name = "LVDS panel data block",
1609 .dump = dump_lvds_data,
1610 },
1611 {
1612 .id = BDB_LVDS_BACKLIGHT,
1613 .name = "Backlight info block",
1614 .dump = dump_backlight_info,
1615 },
1616 {
1617 .id = BDB_SDVO_LVDS_OPTIONS,
1618 .name = "SDVO LVDS options block",
1619 .dump = dump_sdvo_lvds_options,
1620 },
1621 {
1622 .id = BDB_SDVO_PANEL_DTDS,
1623 .name = "SDVO panel dtds",
1624 .dump = dump_sdvo_panel_dtds,
1625 },
1626 {
1627 .id = BDB_DRIVER_FEATURES,
1628 .name = "Driver feature data block",
1629 .dump = dump_driver_feature,
1630 },
1631 {
1632 .id = BDB_EDP,
1633 .name = "eDP block",
1634 .dump = dump_edp,
1635 },
1636 {
1637 .id = BDB_PSR,
1638 .name = "PSR block",
1639 .dump = dump_psr,
1640 },
1641 {
1642 .id = BDB_MIPI_CONFIG,
1643 .name = "MIPI configuration block",
1644 .dump = dump_mipi_config,
1645 },
1646 {
1647 .id = BDB_MIPI_SEQUENCE,
1648 .name = "MIPI sequence block",
1649 .dump = dump_mipi_sequence,
1650 },
1651 };
1652
hex_dump(const void * data,uint32_t size)1653 static void hex_dump(const void *data, uint32_t size)
1654 {
1655 int i;
1656 const uint8_t *p = data;
1657
1658 for (i = 0; i < size; i++) {
1659 if (i % 16 == 0)
1660 printf("\t%04x: ", i);
1661 printf("%02x", p[i]);
1662 if (i % 16 == 15) {
1663 if (i + 1 < size)
1664 printf("\n");
1665 } else if (i % 8 == 7) {
1666 printf(" ");
1667 } else {
1668 printf(" ");
1669 }
1670 }
1671 printf("\n\n");
1672 }
1673
hex_dump_block(const struct bdb_block * block)1674 static void hex_dump_block(const struct bdb_block *block)
1675 {
1676 hex_dump(block->data, block->size);
1677 }
1678
dump_section(struct context * context,int section_id)1679 static bool dump_section(struct context *context, int section_id)
1680 {
1681 struct dumper *dumper = NULL;
1682 struct bdb_block *block;
1683 int i;
1684
1685 block = find_section(context, section_id);
1686 if (!block)
1687 return false;
1688
1689 for (i = 0; i < ARRAY_SIZE(dumpers); i++) {
1690 if (block->id == dumpers[i].id) {
1691 dumper = &dumpers[i];
1692 break;
1693 }
1694 }
1695
1696 if (dumper && dumper->name)
1697 printf("BDB block %d - %s:\n", block->id, dumper->name);
1698 else
1699 printf("BDB block %d - Unknown, no decoding available:\n",
1700 block->id);
1701
1702 if (context->hexdump)
1703 hex_dump_block(block);
1704 if (dumper && dumper->dump)
1705 dumper->dump(context, block);
1706 printf("\n");
1707
1708 free(block);
1709
1710 return true;
1711 }
1712
1713 /* print a description of the VBT of the form <bdb-version>-<vbt-signature> */
print_description(struct context * context)1714 static void print_description(struct context *context)
1715 {
1716 const struct vbt_header *vbt = context->vbt;
1717 const struct bdb_header *bdb = context->bdb;
1718 char *desc = strndup((char *)vbt->signature, sizeof(vbt->signature));
1719 char *p;
1720
1721 for (p = desc + strlen(desc) - 1; p >= desc && isspace(*p); p--)
1722 *p = '\0';
1723
1724 for (p = desc; *p; p++) {
1725 if (!isalnum(*p))
1726 *p = '-';
1727 else
1728 *p = tolower(*p);
1729 }
1730
1731 p = desc;
1732 if (strncmp(p, "-vbt-", 5) == 0)
1733 p += 5;
1734
1735 printf("%d-%s\n", bdb->version, p);
1736
1737 free (desc);
1738 }
1739
dump_headers(struct context * context)1740 static void dump_headers(struct context *context)
1741 {
1742 const struct vbt_header *vbt = context->vbt;
1743 const struct bdb_header *bdb = context->bdb;
1744 int i, j = 0;
1745
1746 printf("VBT header:\n");
1747 if (context->hexdump)
1748 hex_dump(vbt, vbt->header_size);
1749
1750 printf("\tVBT signature:\t\t\"%.*s\"\n",
1751 (int)sizeof(vbt->signature), vbt->signature);
1752 printf("\tVBT version:\t\t0x%04x (%d.%d)\n", vbt->version,
1753 vbt->version / 100, vbt->version % 100);
1754 printf("\tVBT header size:\t0x%04x (%u)\n",
1755 vbt->header_size, vbt->header_size);
1756 printf("\tVBT size:\t\t0x%04x (%u)\n", vbt->vbt_size, vbt->vbt_size);
1757 printf("\tVBT checksum:\t\t0x%02x\n", vbt->vbt_checksum);
1758 printf("\tBDB offset:\t\t0x%08x (%u)\n", vbt->bdb_offset, vbt->bdb_offset);
1759
1760 printf("\n");
1761
1762 printf("BDB header:\n");
1763 if (context->hexdump)
1764 hex_dump(bdb, bdb->header_size);
1765
1766 printf("\tBDB signature:\t\t\"%.*s\"\n",
1767 (int)sizeof(bdb->signature), bdb->signature);
1768 printf("\tBDB version:\t\t%d\n", bdb->version);
1769 printf("\tBDB header size:\t0x%04x (%u)\n",
1770 bdb->header_size, bdb->header_size);
1771 printf("\tBDB size:\t\t0x%04x (%u)\n", bdb->bdb_size, bdb->bdb_size);
1772 printf("\n");
1773
1774 printf("BDB blocks present:");
1775 for (i = 0; i < 256; i++) {
1776 struct bdb_block *block;
1777
1778 block = find_section(context, i);
1779 if (!block)
1780 continue;
1781
1782 if (j++ % 16)
1783 printf(" %3d", i);
1784 else
1785 printf("\n\t%3d", i);
1786
1787 free(block);
1788 }
1789 printf("\n\n");
1790 }
1791
1792 enum opt {
1793 OPT_UNKNOWN = '?',
1794 OPT_END = -1,
1795 OPT_FILE,
1796 OPT_DEVID,
1797 OPT_PANEL_TYPE,
1798 OPT_ALL_PANELS,
1799 OPT_HEXDUMP,
1800 OPT_BLOCK,
1801 OPT_USAGE,
1802 OPT_HEADER,
1803 OPT_DESCRIBE,
1804 };
1805
usage(const char * toolname)1806 static void usage(const char *toolname)
1807 {
1808 fprintf(stderr, "usage: %s", toolname);
1809 fprintf(stderr, " --file=<rom_file>"
1810 " [--devid=<device_id>]"
1811 " [--panel-type=<panel_type>]"
1812 " [--all-panels]"
1813 " [--hexdump]"
1814 " [--block=<block_no>]"
1815 " [--header]"
1816 " [--describe]"
1817 " [--help]\n");
1818 }
1819
main(int argc,char ** argv)1820 int main(int argc, char **argv)
1821 {
1822 uint8_t *VBIOS;
1823 int index;
1824 enum opt opt;
1825 int fd;
1826 struct vbt_header *vbt = NULL;
1827 int vbt_off, bdb_off, i;
1828 const char *filename = NULL;
1829 const char *toolname = argv[0];
1830 struct stat finfo;
1831 int size;
1832 struct context context = {
1833 .panel_type = -1,
1834 };
1835 char *endp;
1836 int block_number = -1;
1837 bool header_only = false, describe = false;
1838
1839 static struct option options[] = {
1840 { "file", required_argument, NULL, OPT_FILE },
1841 { "devid", required_argument, NULL, OPT_DEVID },
1842 { "panel-type", required_argument, NULL, OPT_PANEL_TYPE },
1843 { "all-panels", no_argument, NULL, OPT_ALL_PANELS },
1844 { "hexdump", no_argument, NULL, OPT_HEXDUMP },
1845 { "block", required_argument, NULL, OPT_BLOCK },
1846 { "header", no_argument, NULL, OPT_HEADER },
1847 { "describe", no_argument, NULL, OPT_DESCRIBE },
1848 { "help", no_argument, NULL, OPT_USAGE },
1849 { 0 }
1850 };
1851
1852 for (opt = 0; opt != OPT_END; ) {
1853 opt = getopt_long(argc, argv, "", options, &index);
1854
1855 switch (opt) {
1856 case OPT_FILE:
1857 filename = optarg;
1858 break;
1859 case OPT_DEVID:
1860 context.devid = strtoul(optarg, &endp, 16);
1861 if (!context.devid || *endp) {
1862 fprintf(stderr, "invalid devid '%s'\n", optarg);
1863 return EXIT_FAILURE;
1864 }
1865 break;
1866 case OPT_PANEL_TYPE:
1867 context.panel_type = strtoul(optarg, &endp, 0);
1868 if (*endp || context.panel_type > 15) {
1869 fprintf(stderr, "invalid panel type '%s'\n",
1870 optarg);
1871 return EXIT_FAILURE;
1872 }
1873 break;
1874 case OPT_ALL_PANELS:
1875 context.dump_all_panel_types = true;
1876 break;
1877 case OPT_HEXDUMP:
1878 context.hexdump = true;
1879 break;
1880 case OPT_BLOCK:
1881 block_number = strtoul(optarg, &endp, 0);
1882 if (*endp) {
1883 fprintf(stderr, "invalid block number '%s'\n",
1884 optarg);
1885 return EXIT_FAILURE;
1886 }
1887 break;
1888 case OPT_HEADER:
1889 header_only = true;
1890 break;
1891 case OPT_DESCRIBE:
1892 describe = true;
1893 break;
1894 case OPT_END:
1895 break;
1896 case OPT_USAGE: /* fall-through */
1897 case OPT_UNKNOWN:
1898 usage(toolname);
1899 return EXIT_FAILURE;
1900 }
1901 }
1902
1903 argc -= optind;
1904 argv += optind;
1905
1906 if (!filename) {
1907 if (argc == 1) {
1908 /* for backwards compatibility */
1909 filename = argv[0];
1910 } else {
1911 usage(toolname);
1912 return EXIT_FAILURE;
1913 }
1914 }
1915
1916 fd = open(filename, O_RDONLY);
1917 if (fd == -1) {
1918 fprintf(stderr, "Couldn't open \"%s\": %s\n",
1919 filename, strerror(errno));
1920 return EXIT_FAILURE;
1921 }
1922
1923 if (stat(filename, &finfo)) {
1924 fprintf(stderr, "Failed to stat \"%s\": %s\n",
1925 filename, strerror(errno));
1926 return EXIT_FAILURE;
1927 }
1928 size = finfo.st_size;
1929
1930 if (size == 0) {
1931 int len = 0, ret;
1932 size = 8192;
1933 VBIOS = malloc (size);
1934 while ((ret = read(fd, VBIOS + len, size - len))) {
1935 if (ret < 0) {
1936 fprintf(stderr, "Failed to read \"%s\": %s\n",
1937 filename, strerror(errno));
1938 return EXIT_FAILURE;
1939 }
1940
1941 len += ret;
1942 if (len == size) {
1943 size *= 2;
1944 VBIOS = realloc(VBIOS, size);
1945 }
1946 }
1947 } else {
1948 VBIOS = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
1949 if (VBIOS == MAP_FAILED) {
1950 fprintf(stderr, "Failed to map \"%s\": %s\n",
1951 filename, strerror(errno));
1952 return EXIT_FAILURE;
1953 }
1954 }
1955
1956 /* Scour memory looking for the VBT signature */
1957 for (i = 0; i + 4 < size; i++) {
1958 if (!memcmp(VBIOS + i, "$VBT", 4)) {
1959 vbt_off = i;
1960 vbt = (struct vbt_header *)(VBIOS + i);
1961 break;
1962 }
1963 }
1964
1965 if (!vbt) {
1966 fprintf(stderr, "VBT signature missing\n");
1967 return EXIT_FAILURE;
1968 }
1969
1970 bdb_off = vbt_off + vbt->bdb_offset;
1971 if (bdb_off >= size - sizeof(struct bdb_header)) {
1972 fprintf(stderr, "Invalid VBT found, BDB points beyond end of data block\n");
1973 return EXIT_FAILURE;
1974 }
1975
1976 context.vbt = vbt;
1977 context.bdb = (const struct bdb_header *)(VBIOS + bdb_off);
1978 context.size = size;
1979
1980 if (!context.devid) {
1981 const char *devid_string = getenv("DEVICE");
1982 if (devid_string)
1983 context.devid = strtoul(devid_string, NULL, 16);
1984 }
1985 if (!context.devid)
1986 context.devid = get_device_id(VBIOS, size);
1987 if (!context.devid)
1988 fprintf(stderr, "Warning: could not find PCI device ID!\n");
1989
1990 if (context.panel_type == -1)
1991 context.panel_type = get_panel_type(&context);
1992 if (context.panel_type == -1) {
1993 fprintf(stderr, "Warning: panel type not set, using 0\n");
1994 context.panel_type = 0;
1995 }
1996
1997 if (describe) {
1998 print_description(&context);
1999 } else if (header_only) {
2000 dump_headers(&context);
2001 } else if (block_number != -1) {
2002 /* dump specific section only */
2003 if (!dump_section(&context, block_number)) {
2004 fprintf(stderr, "Block %d not found\n", block_number);
2005 return EXIT_FAILURE;
2006 }
2007 } else {
2008 dump_headers(&context);
2009
2010 /* dump all sections */
2011 for (i = 0; i < 256; i++)
2012 dump_section(&context, i);
2013 }
2014
2015 return 0;
2016 }
2017