blob: e6e06b1b56184b78b34db2c6e93aa8d32d0fab8c [file] [log] [blame]
Zhenyu Wang97ffee62010-01-12 14:04:43 +08001/*
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
Jani Nikula37bd27f2017-10-20 16:24:50 +030028#include <ctype.h>
Zhenyu Wang97ffee62010-01-12 14:04:43 +080029#include <errno.h>
30#include <fcntl.h>
Jani Nikula8a06cc12016-05-03 11:29:43 +030031#include <getopt.h>
Zhenyu Wang97ffee62010-01-12 14:04:43 +080032#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
Jani Nikulada4b9fe2017-08-29 11:34:04 +030040#include "igt_aux.h"
Daniel Vetterc03c6ce2014-03-22 21:34:29 +010041#include "intel_io.h"
Daniel Vetter6cfcd712014-03-22 20:07:35 +010042#include "intel_chipset.h"
43#include "drmtest.h"
Zhenyu Wang581205d2010-06-03 10:31:04 +080044
Jani Nikula09f35ea2017-08-25 15:56:19 +030045/* kernel types for intel_vbt_defs.h */
46typedef uint8_t u8;
47typedef uint16_t u16;
48typedef uint32_t u32;
Jani Nikula66d88e62017-08-25 17:15:43 +030049typedef uint64_t u64;
Jani Nikula09f35ea2017-08-25 15:56:19 +030050#define __packed __attribute__ ((packed))
51
52#define _INTEL_BIOS_PRIVATE
53#include "intel_vbt_defs.h"
54
Zhenyu Wang97ffee62010-01-12 14:04:43 +080055/* 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
Zhenyu Wang97ffee62010-01-12 14:04:43 +080066#define YESNO(val) ((val) ? "yes" : "no")
67
Jani Nikulad9588c82016-01-14 15:48:13 +020068/* This is not for mapping to memory layout. */
Zhenyu Wang97ffee62010-01-12 14:04:43 +080069struct bdb_block {
70 uint8_t id;
Jani Nikulad9588c82016-01-14 15:48:13 +020071 uint32_t size;
Jani Nikulab2639342016-01-14 16:08:55 +020072 const void *data;
Zhenyu Wang97ffee62010-01-12 14:04:43 +080073};
74
Jani Nikula76a04622016-05-02 18:33:19 +030075struct context {
Jani Nikulaf482e232016-05-12 14:28:50 +030076 const struct vbt_header *vbt;
Jani Nikula76a04622016-05-02 18:33:19 +030077 const struct bdb_header *bdb;
78 int size;
Jani Nikula76a04622016-05-02 18:33:19 +030079
Jani Nikulab6ccc552016-05-12 14:02:05 +030080 uint32_t devid;
Jani Nikula3a81cf52016-05-03 11:44:32 +030081 int panel_type;
Jani Nikula96647f12016-05-03 12:36:32 +030082 bool dump_all_panel_types;
Jani Nikulab0a8b082016-05-03 12:17:16 +030083 bool hexdump;
Jani Nikula3a81cf52016-05-03 11:44:32 +030084};
Zhenyu Wang97ffee62010-01-12 14:04:43 +080085
Jani Nikulad9588c82016-01-14 15:48:13 +020086/* Get BDB block size given a pointer to Block ID. */
87static 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
Jani Nikula76a04622016-05-02 18:33:19 +030096static struct bdb_block *find_section(struct context *context, int section_id)
Zhenyu Wang97ffee62010-01-12 14:04:43 +080097{
Jani Nikula76a04622016-05-02 18:33:19 +030098 const struct bdb_header *bdb = context->bdb;
99 int length = context->size;
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800100 struct bdb_block *block;
Jani Nikulab2639342016-01-14 16:08:55 +0200101 const uint8_t *base = (const uint8_t *)bdb;
Jani Nikulad9588c82016-01-14 15:48:13 +0200102 int index = 0;
103 uint32_t total, current_size;
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800104 unsigned char current_id;
105
106 /* skip to first section */
Jani Nikulad9588c82016-01-14 15:48:13 +0200107 index += bdb->header_size;
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800108 total = bdb->bdb_size;
Chris Wilson1ffe6b02012-01-25 10:11:49 +0000109 if (total > length)
110 total = length;
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800111
112 block = malloc(sizeof(*block));
113 if (!block) {
114 fprintf(stderr, "out of memory\n");
Jani Nikula1dd3ff02016-05-12 15:35:37 +0300115 exit(EXIT_FAILURE);
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800116 }
117
118 /* walk the sections looking for section_id */
Jani Nikulad9588c82016-01-14 15:48:13 +0200119 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)
Chris Wilson1ffe6b02012-01-25 10:11:49 +0000125 return NULL;
126
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800127 if (current_id == section_id) {
128 block->id = current_id;
129 block->size = current_size;
Jani Nikulad9588c82016-01-14 15:48:13 +0200130 block->data = base + index;
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800131 return block;
132 }
Chris Wilson1ffe6b02012-01-25 10:11:49 +0000133
Jani Nikulad9588c82016-01-14 15:48:13 +0200134 index += current_size;
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800135 }
136
137 free(block);
138 return NULL;
139}
140
Jani Nikula76a04622016-05-02 18:33:19 +0300141static void dump_general_features(struct context *context,
Jani Nikula2e2fffa2016-01-14 15:27:50 +0200142 const struct bdb_block *block)
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800143{
Jani Nikulab2639342016-01-14 16:08:55 +0200144 const struct bdb_general_features *features = block->data;
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800145
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));
Ville Syrjäläcdee9802016-02-29 20:31:05 +0200165
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800166 printf("\tExternal VBT: %s\n", YESNO(features->download_ext_vbt));
167 printf("\tEnable SSC: %s\n", YESNO(features->enable_ssc));
Zhenyu Wang581205d2010-06-03 10:31:04 +0800168 if (features->enable_ssc) {
Jani Nikulab6ccc552016-05-12 14:02:05 +0300169 if (!context->devid)
Jani Nikula4d4b1c22016-05-02 18:15:55 +0300170 printf("\tSSC frequency: <unknown platform>\n");
Jani Nikulab6ccc552016-05-12 14:02:05 +0300171 else if (IS_VALLEYVIEW(context->devid) ||
172 IS_CHERRYVIEW(context->devid) ||
173 IS_BROXTON(context->devid))
Imre Deak1dc48842015-03-31 20:32:29 +0300174 printf("\tSSC frequency: 100 MHz\n");
Jani Nikulab6ccc552016-05-12 14:02:05 +0300175 else if (HAS_PCH_SPLIT(context->devid))
Zhenyu Wang581205d2010-06-03 10:31:04 +0800176 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 }
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800182 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));
Ville Syrjäläcdee9802016-02-29 20:31:05 +0200186 printf("\tUnderscan support for VGA timings: %s\n",
187 YESNO(features->underscan_vga_timings));
188 if (context->bdb->version >= 183)
Jani Nikula09f35ea2017-08-25 15:56:19 +0300189 printf("\tDynamic CD clock: %s\n", YESNO(features->display_clock_mode));
Ville Syrjäläcdee9802016-02-29 20:31:05 +0200190 printf("\tHotplug support in VBIOS: %s\n",
191 YESNO(features->vbios_hotplug_support));
192
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800193 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));
Ville Syrjäläcdee9802016-02-29 20:31:05 +0200196 if (context->bdb->version >= 181)
197 printf("\tEnable 180 degree rotation: %s\n", YESNO(features->rotate_180));
Jani Nikula09f35ea2017-08-25 15:56:19 +0300198 printf("\tInverted FDI Rx polarity: %s\n", YESNO(features->fdi_rx_polarity_inverted));
Ville Syrjäläcdee9802016-02-29 20:31:05 +0200199 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
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800206 printf("\tLegacy monitor detect: %s\n",
207 YESNO(features->legacy_monitor_detect));
Ville Syrjäläcdee9802016-02-29 20:31:05 +0200208
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800209 printf("\tIntegrated CRT: %s\n", YESNO(features->int_crt_support));
210 printf("\tIntegrated TV: %s\n", YESNO(features->int_tv_support));
Ville Syrjäläcdee9802016-02-29 20:31:05 +0200211 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));
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800225}
226
Jani Nikula76a04622016-05-02 18:33:19 +0300227static void dump_backlight_info(struct context *context,
Jani Nikula2e2fffa2016-01-14 15:27:50 +0200228 const struct bdb_block *block)
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800229{
Jani Nikula2cbcc0b2017-08-28 15:13:40 +0300230 const struct bdb_lfp_backlight_data *backlight = block->data;
231 const struct bdb_lfp_backlight_data_entry *blc;
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800232
Jani Nikula2cbcc0b2017-08-28 15:13:40 +0300233 if (sizeof(*blc) != backlight->entry_size) {
Chris Wilson592b1a52011-02-10 11:00:49 +0000234 printf("\tBacklight struct sizes don't match (expected %zu, got %u), skipping\n",
Jani Nikula2cbcc0b2017-08-28 15:13:40 +0300235 sizeof(*blc), backlight->entry_size);
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800236 return;
237 }
238
Jani Nikula2cbcc0b2017-08-28 15:13:40 +0300239 blc = &backlight->data[context->panel_type];
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800240
Jani Nikula2cbcc0b2017-08-28 15:13:40 +0300241 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);
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800244 printf("\tMinimum brightness: %d\n", blc->min_brightness);
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800245}
246
Adam Jacksona52cbcb2010-04-22 15:37:49 -0400247static 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" },
Adam Jacksona52cbcb2010-04-22 15:37:49 -0400278 { DEVICE_TYPE_DP, "DisplayPort" },
Jani Nikula09f35ea2017-08-25 15:56:19 +0300279 { DEVICE_TYPE_DP_DUAL_MODE, "DisplayPort/HDMI/DVI" },
Jesse Barnes32256302010-12-21 12:06:00 -0800280 { DEVICE_TYPE_DP_DVI, "DisplayPort/DVI" },
Jani Nikula09f35ea2017-08-25 15:56:19 +0300281 { DEVICE_TYPE_HDMI, "HDMI/DVI" },
Jesse Barnes32256302010-12-21 12:06:00 -0800282 { DEVICE_TYPE_DVI, "DVI" },
Adam Jacksona52cbcb2010-04-22 15:37:49 -0400283 { DEVICE_TYPE_eDP, "eDP" },
Ville Syrjälä2155d1e2015-09-11 15:27:32 +0300284 { DEVICE_TYPE_MIPI, "MIPI" },
Adam Jacksona52cbcb2010-04-22 15:37:49 -0400285};
286static const int num_child_device_types =
287 sizeof(child_device_types) / sizeof(child_device_types[0]);
288
289static 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
Jani Nikula3b163c42017-08-28 15:07:35 +0300300static 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" },
Adam Jackson51b2ce52017-12-15 14:59:36 -0500313 { DEVICE_TYPE_HIGH_SPEED_LINK, "High speed link" },
314 { DEVICE_TYPE_LVDS_SIGNALING, "LVDS signaling" },
Jani Nikula3b163c42017-08-28 15:07:35 +0300315 { 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" },
Ville Syrjäläd8313c32015-09-11 15:01:16 +0300320};
321
322static void dump_child_device_type_bits(uint16_t type)
323{
Jani Nikula3b163c42017-08-28 15:07:35 +0300324 int i;
Ville Syrjäläd8313c32015-09-11 15:01:16 +0300325
Jani Nikula3b163c42017-08-28 15:07:35 +0300326 type ^= DEVICE_TYPE_NOT_HDMI_OUTPUT;
Ville Syrjäläd8313c32015-09-11 15:01:16 +0300327
Jani Nikula3b163c42017-08-28 15:07:35 +0300328 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);
Ville Syrjäläd8313c32015-09-11 15:01:16 +0300331 }
332}
333
Jesse Barnes32256302010-12-21 12:06:00 -0800334static const struct {
Ville Syrjäläa0230522015-09-11 14:47:59 +0300335 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};
346static const int num_child_device_handles =
347 sizeof(child_device_handles) / sizeof(child_device_handles[0]);
348
349static 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
Jani Nikula48bf7bc2017-09-21 15:08:11 +0300360static 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",
Jesse Barnes32256302010-12-21 12:06:00 -0800378};
Jesse Barnes32256302010-12-21 12:06:00 -0800379
Jani Nikula48bf7bc2017-09-21 15:08:11 +0300380static const char *dvo_port(uint8_t type)
Jesse Barnes32256302010-12-21 12:06:00 -0800381{
Jani Nikula48bf7bc2017-09-21 15:08:11 +0300382 if (type < ARRAY_SIZE(dvo_port_names) && dvo_port_names[type])
383 return dvo_port_names[type];
384 else
385 return "unknown";
Jesse Barnes32256302010-12-21 12:06:00 -0800386}
387
Jani Nikula7e4cd232017-09-21 16:44:55 +0300388static 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
Ville Syrjäläcc41f4c2017-10-30 16:38:46 +0200402static 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
Jani Nikula76a04622016-05-02 18:33:19 +0300422static void dump_child_device(struct context *context,
Chris Wilsondc3fcd92016-11-30 19:37:37 +0000423 const struct child_device_config *child)
Adam Jacksona52cbcb2010-04-22 15:37:49 -0400424{
Adam Jacksona52cbcb2010-04-22 15:37:49 -0400425 if (!child->device_type)
426 return;
427
Jani Nikula1b4478c2017-09-21 16:57:57 +0300428 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
Jani Nikula76a04622016-05-02 18:33:19 +0300435 if (context->bdb->version < 152) {
Jani Nikulaee7a0fe2017-09-21 16:28:48 +0300436 printf("\t\tSignature: %.*s\n", (int)sizeof(child->device_id), child->device_id);
Jani Nikula1b4478c2017-09-21 16:57:57 +0300437 } 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);
Ville Syrjäläcc41f4c2017-10-30 16:38:46 +0200442 dump_hmdi_max_data_rate(child->hdmi_max_data_rate);
Jani Nikula1b4478c2017-09-21 16:57:57 +0300443 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));
Ville Syrjälä86a546f2016-02-29 21:35:39 +0200450 }
451
Jani Nikula1b4478c2017-09-21 16:57:57 +0300452 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
Jani Nikula1b4478c2017-09-21 16:57:57 +0300455 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
Ville Syrjälä86a546f2016-02-29 21:35:39 +0200495 if (context->bdb->version >= 195) {
Jani Nikula1b4478c2017-09-21 16:57:57 +0300496 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);
Ville Syrjälä86a546f2016-02-29 21:35:39 +0200499 }
500
501 if (context->bdb->version >= 196) {
Jani Nikula1b4478c2017-09-21 16:57:57 +0300502 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);
Jesse Barnes32256302010-12-21 12:06:00 -0800504 }
Adam Jacksona52cbcb2010-04-22 15:37:49 -0400505}
506
Jani Nikula9ba736a2017-09-27 16:24:31 +0300507
508static 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
Jani Nikula76a04622016-05-02 18:33:19 +0300531static void dump_general_definitions(struct context *context,
Jani Nikula2e2fffa2016-01-14 15:27:50 +0200532 const struct bdb_block *block)
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800533{
Jani Nikulab2639342016-01-14 16:08:55 +0200534 const struct bdb_general_definitions *defs = block->data;
Jani Nikula9ba736a2017-09-27 16:24:31 +0300535 int child_dev_num;
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800536
Jani Nikula743cbb02017-10-20 16:07:01 +0300537 child_dev_num = (block->size - sizeof(*defs)) / defs->child_dev_size;
538
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800539 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]);
Ville Syrjäläb1e75642015-03-25 13:36:52 +0200547 printf("\tChild device size: %d\n", defs->child_dev_size);
Jani Nikula743cbb02017-10-20 16:07:01 +0300548 printf("\tChild device count: %d\n", child_dev_num);
Jani Nikulada4b9fe2017-08-29 11:34:04 +0300549
Jani Nikula9ba736a2017-09-27 16:24:31 +0300550 dump_child_devices(context, defs->devices,
551 child_dev_num, defs->child_dev_size);
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800552}
553
Jani Nikuladff8b302017-08-25 12:30:20 +0300554static void dump_legacy_child_devices(struct context *context,
555 const struct bdb_block *block)
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800556{
Jani Nikulad1f8db52017-09-27 17:53:02 +0300557 const struct bdb_legacy_child_devices *defs = block->data;
Jani Nikula9ba736a2017-09-27 16:24:31 +0300558 int child_dev_num;
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800559
Jani Nikula9ba736a2017-09-27 16:24:31 +0300560 child_dev_num = (block->size - sizeof(*defs)) / defs->child_dev_size;
Jani Nikula743cbb02017-10-20 16:07:01 +0300561
562 printf("\tChild device size: %d\n", defs->child_dev_size);
563 printf("\tChild device count: %d\n", child_dev_num);
564
Jani Nikula9ba736a2017-09-27 16:24:31 +0300565 dump_child_devices(context, defs->devices,
566 child_dev_num, defs->child_dev_size);
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800567}
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800568
Jani Nikula76a04622016-05-02 18:33:19 +0300569static void dump_lvds_options(struct context *context,
Jani Nikula2e2fffa2016-01-14 15:27:50 +0200570 const struct bdb_block *block)
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800571{
Jani Nikulab2639342016-01-14 16:08:55 +0200572 const struct bdb_lvds_options *options = block->data;
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800573
Jani Nikula21467dc2016-05-03 12:07:30 +0300574 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);
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800579 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);
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800587}
588
Jani Nikula76a04622016-05-02 18:33:19 +0300589static void dump_lvds_ptr_data(struct context *context,
Jani Nikula2e2fffa2016-01-14 15:27:50 +0200590 const struct bdb_block *block)
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800591{
Jani Nikulab2639342016-01-14 16:08:55 +0200592 const struct bdb_lvds_lfp_data_ptrs *ptrs = block->data;
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800593
Jani Nikulaa4180df2013-10-08 21:15:27 +0300594 printf("\tNumber of entries: %d\n", ptrs->lvds_entries);
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800595}
596
Jani Nikula76a04622016-05-02 18:33:19 +0300597static void dump_lvds_data(struct context *context,
Jani Nikula2e2fffa2016-01-14 15:27:50 +0200598 const struct bdb_block *block)
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800599{
Jani Nikulab2639342016-01-14 16:08:55 +0200600 const struct bdb_lvds_lfp_data *lvds_data = block->data;
Jani Nikula17ae0a62016-05-03 11:52:12 +0300601 struct bdb_block *ptrs_block;
602 const struct bdb_lvds_lfp_data_ptrs *ptrs;
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800603 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
Jani Nikula17ae0a62016-05-03 11:52:12 +0300610 ptrs_block = find_section(context, BDB_LVDS_LFP_DATA_PTRS);
611 if (!ptrs_block) {
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800612 printf("No LVDS ptr block\n");
613 return;
614 }
Jani Nikulaa4180df2013-10-08 21:15:27 +0300615
Jani Nikula17ae0a62016-05-03 11:52:12 +0300616 ptrs = ptrs_block->data;
617
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800618 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;
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800622
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800623 num_entries = block->size / lfp_data_size;
624
Jani Nikulaa4180df2013-10-08 21:15:27 +0300625 printf(" Number of entries: %d (preferred block marked with '*')\n",
626 num_entries);
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800627
628 for (i = 0; i < num_entries; i++) {
Jani Nikulab2639342016-01-14 16:08:55 +0200629 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 bdb_lvds_lfp_data_entry *lfp_data =
633 (const struct bdb_lvds_lfp_data_entry *)lfp_data_ptr;
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800634 char marker;
635
Jani Nikula96647f12016-05-03 12:36:32 +0300636 if (i != context->panel_type && !context->dump_all_panel_types)
637 continue;
638
Jani Nikula3a81cf52016-05-03 11:44:32 +0300639 if (i == context->panel_type)
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800640 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 }
Jani Nikula17ae0a62016-05-03 11:52:12 +0300675
676 free(ptrs_block);
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800677}
678
Jani Nikula76a04622016-05-02 18:33:19 +0300679static void dump_driver_feature(struct context *context,
Jani Nikula2e2fffa2016-01-14 15:27:50 +0200680 const struct bdb_block *block)
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800681{
Jani Nikula09f35ea2017-08-25 15:56:19 +0300682 const struct bdb_driver_features *feature = block->data;
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800683
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800684 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);
Dhinakaran Pandiyancffe9152018-05-08 17:48:55 -0700744 printf("\tEnable DRRS: %s\n", YESNO(feature->drrs_enabled));
745 printf("\tEnable PSR: %s\n", YESNO(feature->psr_enabled));
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800746}
747
Jani Nikula76a04622016-05-02 18:33:19 +0300748static void dump_edp(struct context *context,
Jani Nikula2e2fffa2016-01-14 15:27:50 +0200749 const struct bdb_block *block)
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800750{
Jani Nikulab2639342016-01-14 16:08:55 +0200751 const struct bdb_edp *edp = block->data;
Jani Nikula419d0532013-10-08 21:15:29 +0300752 int bpp, msa;
753 int i;
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800754
Jani Nikula419d0532013-10-08 21:15:29 +0300755 for (i = 0; i < 16; i++) {
Jani Nikula96647f12016-05-03 12:36:32 +0300756 if (i != context->panel_type && !context->dump_all_panel_types)
757 continue;
758
Jani Nikula3a81cf52016-05-03 11:44:32 +0300759 printf("\tPanel %d%s\n", i, context->panel_type == i ? " *" : "");
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800760
Jani Nikula419d0532013-10-08 21:15:29 +0300761 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);
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800767
Jani Nikula419d0532013-10-08 21:15:29 +0300768 bpp = (edp->color_depth >> (i * 2)) & 3;
Jani Nikulaa4180df2013-10-08 21:15:27 +0300769
Jani Nikula419d0532013-10-08 21:15:29 +0300770 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
Ville Syrjälä2ed42d32016-06-21 17:52:37 +0300789 printf("\t\tFast link params:\n");
Jani Nikula419d0532013-10-08 21:15:29 +0300790 printf("\t\t\trate: ");
Ville Syrjälä2ed42d32016-06-21 17:52:37 +0300791 if (edp->fast_link_params[i].rate == EDP_RATE_1_62)
Jani Nikula419d0532013-10-08 21:15:29 +0300792 printf("1.62G\n");
Ville Syrjälä2ed42d32016-06-21 17:52:37 +0300793 else if (edp->fast_link_params[i].rate == EDP_RATE_2_7)
Jani Nikula419d0532013-10-08 21:15:29 +0300794 printf("2.7G\n");
795 printf("\t\t\tlanes: ");
Ville Syrjälä2ed42d32016-06-21 17:52:37 +0300796 switch (edp->fast_link_params[i].lanes) {
Jani Nikula419d0532013-10-08 21:15:29 +0300797 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",
Ville Syrjälä2ed42d32016-06-21 17:52:37 +0300808 edp->fast_link_params[i].lanes);
Jani Nikula419d0532013-10-08 21:15:29 +0300809 break;
810 }
811 printf("\t\t\tpre-emphasis: ");
Ville Syrjälä2ed42d32016-06-21 17:52:37 +0300812 switch (edp->fast_link_params[i].preemphasis) {
Jani Nikula419d0532013-10-08 21:15:29 +0300813 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",
Ville Syrjälä2ed42d32016-06-21 17:52:37 +0300827 edp->fast_link_params[i].preemphasis);
Jani Nikula419d0532013-10-08 21:15:29 +0300828 break;
829 }
830 printf("\t\t\tvswing: ");
Ville Syrjälä2ed42d32016-06-21 17:52:37 +0300831 switch (edp->fast_link_params[i].vswing) {
Jani Nikula419d0532013-10-08 21:15:29 +0300832 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",
Ville Syrjälä2ed42d32016-06-21 17:52:37 +0300846 edp->fast_link_params[i].vswing);
Jani Nikula419d0532013-10-08 21:15:29 +0300847 break;
848 }
Ville Syrjälä2ed42d32016-06-21 17:52:37 +0300849
850 if (context->bdb->version >= 162) {
Jani Nikula66d88e62017-08-25 17:15:43 +0300851 bool val = (edp->edp_s3d_feature >> i) & 1;
Ville Syrjälä2ed42d32016-06-21 17:52:37 +0300852 printf("\t\tStereo 3D feature: %s\n", YESNO(val));
853 }
854
855 if (context->bdb->version >= 165) {
Jani Nikula66d88e62017-08-25 17:15:43 +0300856 bool val = (edp->edp_t3_optimization >> i) & 1;
Ville Syrjälä2ed42d32016-06-21 17:52:37 +0300857 printf("\t\tT3 optimization: %s\n", YESNO(val));
858 }
859
860 if (context->bdb->version >= 173) {
Jani Nikula66d88e62017-08-25 17:15:43 +0300861 int val = (edp->edp_vswing_preemph >> (i * 4)) & 0xf;
Ville Syrjälä2ed42d32016-06-21 17:52:37 +0300862
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 }
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800939 }
Zhenyu Wang97ffee62010-01-12 14:04:43 +0800940}
941
Ville Syrjälä8e4ce752016-09-12 13:34:53 +0300942static void dump_psr(struct context *context,
943 const struct bdb_block *block)
944{
Jani Nikulae1db4c42017-08-25 16:10:53 +0300945 const struct bdb_psr *psr_block = block->data;
Ville Syrjälä8e4ce752016-09-12 13:34:53 +0300946 int i;
947
948 /* The same block ID was used for something else before? */
949 if (context->bdb->version < 165)
950 return;
951
952 for (i = 0; i < 16; i++) {
Jani Nikulae1db4c42017-08-25 16:10:53 +0300953 const struct psr_table *psr = &psr_block->psr_table[i];
954
Ville Syrjälä8e4ce752016-09-12 13:34:53 +0300955 if (i != context->panel_type && !context->dump_all_panel_types)
956 continue;
957
958 printf("\tPanel %d%s\n", i, context->panel_type == i ? " *" : "");
959
Jani Nikulae1db4c42017-08-25 16:10:53 +0300960 printf("\t\tFull link: %s\n", YESNO(psr->full_link));
961 printf("\t\tRequire AUX to wakeup: %s\n", YESNO(psr->require_aux_to_wakeup));
Ville Syrjälä8e4ce752016-09-12 13:34:53 +0300962
Jani Nikulae1db4c42017-08-25 16:10:53 +0300963 switch (psr->lines_to_wait) {
Ville Syrjälä8e4ce752016-09-12 13:34:53 +0300964 case 0:
965 case 1:
966 printf("\t\tLines to wait before link standby: %d\n",
Jani Nikulae1db4c42017-08-25 16:10:53 +0300967 psr->lines_to_wait);
Ville Syrjälä8e4ce752016-09-12 13:34:53 +0300968 break;
969 case 2:
970 case 3:
971 printf("\t\tLines to wait before link standby: %d\n",
Jani Nikulae1db4c42017-08-25 16:10:53 +0300972 1 << psr->lines_to_wait);
Ville Syrjälä8e4ce752016-09-12 13:34:53 +0300973 break;
974 default:
975 printf("\t\tLines to wait before link standby: (unknown) (0x%x)\n",
Jani Nikulae1db4c42017-08-25 16:10:53 +0300976 psr->lines_to_wait);
Ville Syrjälä8e4ce752016-09-12 13:34:53 +0300977 break;
978 }
979
980 printf("\t\tIdle frames to for PSR enable: %d\n",
Jani Nikulae1db4c42017-08-25 16:10:53 +0300981 psr->idle_frames);
Ville Syrjälä8e4ce752016-09-12 13:34:53 +0300982
983 printf("\t\tTP1 wakeup time: %d usec (0x%x)\n",
Jani Nikulae1db4c42017-08-25 16:10:53 +0300984 psr->tp1_wakeup_time * 100,
985 psr->tp1_wakeup_time);
Ville Syrjälä8e4ce752016-09-12 13:34:53 +0300986
987 printf("\t\tTP2/TP3 wakeup time: %d usec (0x%x)\n",
Jani Nikulae1db4c42017-08-25 16:10:53 +0300988 psr->tp2_tp3_wakeup_time * 100,
989 psr->tp2_tp3_wakeup_time);
Ville Syrjälä8e4ce752016-09-12 13:34:53 +0300990 }
991}
992
Chris Wilson281285e2011-01-29 16:12:38 +0000993static void
Jani Nikula25a71172017-08-25 13:41:05 +0300994print_detail_timing_data(const struct lvds_dvo_timing *dvo_timing)
Chris Wilson281285e2011-01-29 16:12:38 +0000995{
996 int display, sync_start, sync_end, total;
997
998 display = (dvo_timing->hactive_hi << 8) | dvo_timing->hactive_lo;
999 sync_start = display +
1000 ((dvo_timing->hsync_off_hi << 8) | dvo_timing->hsync_off_lo);
Jani Nikulaef52ae22017-08-25 13:51:25 +03001001 sync_end = sync_start + ((dvo_timing->hsync_pulse_width_hi << 8) |
1002 dvo_timing->hsync_pulse_width_lo);
Chris Wilson281285e2011-01-29 16:12:38 +00001003 total = display +
1004 ((dvo_timing->hblank_hi << 8) | dvo_timing->hblank_lo);
1005 printf("\thdisplay: %d\n", display);
1006 printf("\thsync [%d, %d] %s\n", sync_start, sync_end,
1007 dvo_timing->hsync_positive ? "+sync" : "-sync");
1008 printf("\thtotal: %d\n", total);
1009
1010 display = (dvo_timing->vactive_hi << 8) | dvo_timing->vactive_lo;
Jani Nikulaef52ae22017-08-25 13:51:25 +03001011 sync_start = display + ((dvo_timing->vsync_off_hi << 8) |
1012 dvo_timing->vsync_off_lo);
1013 sync_end = sync_start + ((dvo_timing->vsync_pulse_width_hi << 8) |
1014 dvo_timing->vsync_pulse_width_lo);
Chris Wilson281285e2011-01-29 16:12:38 +00001015 total = display +
1016 ((dvo_timing->vblank_hi << 8) | dvo_timing->vblank_lo);
1017 printf("\tvdisplay: %d\n", display);
1018 printf("\tvsync [%d, %d] %s\n", sync_start, sync_end,
1019 dvo_timing->vsync_positive ? "+sync" : "-sync");
1020 printf("\tvtotal: %d\n", total);
1021
1022 printf("\tclock: %d\n", dvo_timing->clock * 10);
1023}
1024
Jani Nikula76a04622016-05-02 18:33:19 +03001025static void dump_sdvo_panel_dtds(struct context *context,
Jani Nikula2e2fffa2016-01-14 15:27:50 +02001026 const struct bdb_block *block)
Chris Wilson281285e2011-01-29 16:12:38 +00001027{
Jani Nikula25a71172017-08-25 13:41:05 +03001028 const struct lvds_dvo_timing *dvo_timing = block->data;
Chris Wilson281285e2011-01-29 16:12:38 +00001029 int n, count;
1030
Jani Nikula25a71172017-08-25 13:41:05 +03001031 count = block->size / sizeof(struct lvds_dvo_timing);
Chris Wilson281285e2011-01-29 16:12:38 +00001032 for (n = 0; n < count; n++) {
1033 printf("%d:\n", n);
1034 print_detail_timing_data(dvo_timing++);
1035 }
Chris Wilson281285e2011-01-29 16:12:38 +00001036}
1037
Jani Nikula76a04622016-05-02 18:33:19 +03001038static void dump_sdvo_lvds_options(struct context *context,
Jani Nikula2e2fffa2016-01-14 15:27:50 +02001039 const struct bdb_block *block)
Chris Wilson281285e2011-01-29 16:12:38 +00001040{
Jani Nikulab2639342016-01-14 16:08:55 +02001041 const struct bdb_sdvo_lvds_options *options = block->data;
Chris Wilson281285e2011-01-29 16:12:38 +00001042
Chris Wilson281285e2011-01-29 16:12:38 +00001043 printf("\tbacklight: %d\n", options->panel_backlight);
1044 printf("\th40 type: %d\n", options->h40_set_panel_type);
1045 printf("\ttype: %d\n", options->panel_type);
1046 printf("\tssc_clk_freq: %d\n", options->ssc_clk_freq);
1047 printf("\tals_low_trip: %d\n", options->als_low_trip);
1048 printf("\tals_high_trip: %d\n", options->als_high_trip);
1049 /*
1050 u8 sclalarcoeff_tab_row_num;
1051 u8 sclalarcoeff_tab_row_size;
1052 u8 coefficient[8];
1053 */
1054 printf("\tmisc[0]: %x\n", options->panel_misc_bits_1);
1055 printf("\tmisc[1]: %x\n", options->panel_misc_bits_2);
1056 printf("\tmisc[2]: %x\n", options->panel_misc_bits_3);
1057 printf("\tmisc[3]: %x\n", options->panel_misc_bits_4);
Chris Wilson281285e2011-01-29 16:12:38 +00001058}
1059
Jani Nikula76a04622016-05-02 18:33:19 +03001060static void dump_mipi_config(struct context *context,
Jani Nikula2e2fffa2016-01-14 15:27:50 +02001061 const struct bdb_block *block)
Gaurav K Singh525044b2014-07-16 19:39:32 +05301062{
Jani Nikulab2639342016-01-14 16:08:55 +02001063 const struct bdb_mipi_config *start = block->data;
1064 const struct mipi_config *config;
1065 const struct mipi_pps_data *pps;
Gaurav K Singh525044b2014-07-16 19:39:32 +05301066
Jani Nikula3a81cf52016-05-03 11:44:32 +03001067 config = &start->config[context->panel_type];
1068 pps = &start->pps[context->panel_type];
Gaurav K Singh525044b2014-07-16 19:39:32 +05301069
1070 printf("\tGeneral Param\n");
1071 printf("\t\t BTA disable: %s\n", config->bta ? "Disabled" : "Enabled");
Ville Syrjälä835f3d12018-10-19 15:36:48 +03001072 printf("\t\t Panel Rotation: %d degrees\n", config->rotation * 90);
Gaurav K Singh525044b2014-07-16 19:39:32 +05301073
1074 printf("\t\t Video Mode Color Format: ");
1075 if (config->videomode_color_format == 0)
1076 printf("Not supported\n");
1077 else if (config->videomode_color_format == 1)
1078 printf("RGB565\n");
1079 else if (config->videomode_color_format == 2)
1080 printf("RGB666\n");
1081 else if (config->videomode_color_format == 3)
1082 printf("RGB666 Loosely Packed\n");
1083 else if (config->videomode_color_format == 4)
1084 printf("RGB888\n");
1085 printf("\t\t PPS GPIO Pins: %s \n", config->pwm_blc ? "Using SOC" : "Using PMIC");
1086 printf("\t\t CABC Support: %s\n", config->cabc ? "supported" : "not supported");
Gaurav K Singh525044b2014-07-16 19:39:32 +05301087 printf("\t\t Mode: %s\n", config->cmd_mode ? "COMMAND" : "VIDEO");
Ville Syrjäläd07a3c82016-12-13 17:40:03 +02001088 printf("\t\t Video transfer mode: %s (0x%x)\n",
1089 config->vtm == 1 ? "non-burst with sync pulse" :
1090 config->vtm == 2 ? "non-burst with sync events" :
1091 config->vtm == 3 ? "burst" : "<unknown>",
1092 config->vtm);
Gaurav K Singh525044b2014-07-16 19:39:32 +05301093 printf("\t\t Dithering: %s\n", config->dithering ? "done in Display Controller" : "done in Panel Controller");
1094
1095 printf("\tPort Desc\n");
Ville Syrjäläd07a3c82016-12-13 17:40:03 +02001096 printf("\t\t Pixel overlap: %d\n", config->pixel_overlap);
Gaurav K Singh525044b2014-07-16 19:39:32 +05301097 printf("\t\t Lane Count: %d\n", config->lane_cnt + 1);
1098 printf("\t\t Dual Link Support: ");
1099 if (config->dual_link == 0)
1100 printf("not supported\n");
1101 else if (config->dual_link == 1)
1102 printf("Front Back mode\n");
1103 else
1104 printf("Pixel Alternative Mode\n");
1105
1106 printf("\tDphy Flags\n");
1107 printf("\t\t Clock Stop: %s\n", config->clk_stop ? "ENABLED" : "DISABLED");
1108 printf("\t\t EOT disabled: %s\n\n", config->eot_disabled ? "EOT not to be sent" : "EOT to be sent");
1109
1110 printf("\tHSTxTimeOut: 0x%x\n", config->hs_tx_timeout);
1111 printf("\tLPRXTimeOut: 0x%x\n", config->lp_rx_timeout);
1112 printf("\tTurnAroundTimeOut: 0x%x\n", config->turn_around_timeout);
1113 printf("\tDeviceResetTimer: 0x%x\n", config->device_reset_timer);
1114 printf("\tMasterinitTimer: 0x%x\n", config->master_init_timer);
1115 printf("\tDBIBandwidthTimer: 0x%x\n", config->dbi_bw_timer);
1116 printf("\tLpByteClkValue: 0x%x\n\n", config->lp_byte_clk_val);
1117
1118 printf("\tDphy Params\n");
1119 printf("\t\tExit to zero Count: 0x%x\n", config->exit_zero_cnt);
1120 printf("\t\tTrail Count: 0x%X\n", config->trail_cnt);
1121 printf("\t\tClk zero count: 0x%x\n", config->clk_zero_cnt);
1122 printf("\t\tPrepare count:0x%x\n\n", config->prepare_cnt);
1123
1124 printf("\tClockLaneSwitchingCount: 0x%x\n", config->clk_lane_switch_cnt);
1125 printf("\tHighToLowSwitchingCount: 0x%x\n\n", config->hl_switch_cnt);
1126
1127 printf("\tTimings based on Dphy spec\n");
1128 printf("\t\tTClkMiss: 0x%x\n", config->tclk_miss);
1129 printf("\t\tTClkPost: 0x%x\n", config->tclk_post);
1130 printf("\t\tTClkPre: 0x%x\n", config->tclk_pre);
1131 printf("\t\tTClkPrepare: 0x%x\n", config->tclk_prepare);
1132 printf("\t\tTClkSettle: 0x%x\n", config->tclk_settle);
1133 printf("\t\tTClkTermEnable: 0x%x\n\n", config->tclk_term_enable);
1134
1135 printf("\tTClkTrail: 0x%x\n", config->tclk_trail);
1136 printf("\tTClkPrepareTClkZero: 0x%x\n", config->tclk_prepare_clkzero);
1137 printf("\tTHSExit: 0x%x\n", config->ths_exit);
1138 printf("\tTHsPrepare: 0x%x\n", config->ths_prepare);
1139 printf("\tTHsPrepareTHsZero: 0x%x\n", config->ths_prepare_hszero);
1140 printf("\tTHSSettle: 0x%x\n", config->ths_settle);
1141 printf("\tTHSSkip: 0x%x\n", config->ths_skip);
1142 printf("\tTHsTrail: 0x%x\n", config->ths_trail);
1143 printf("\tTInit: 0x%x\n", config->tinit);
1144 printf("\tTLPX: 0x%x\n", config->tlpx);
1145
1146 printf("\tMIPI PPS\n");
1147 printf("\t\tPanel power ON delay: %d\n", pps->panel_on_delay);
Mika Kaholafe7a42b2016-01-15 10:24:55 +02001148 printf("\t\tPanel power on to Backlight enable delay: %d\n", pps->bl_enable_delay);
Gaurav K Singh525044b2014-07-16 19:39:32 +05301149 printf("\t\tBacklight disable to Panel power OFF delay: %d\n", pps->bl_disable_delay);
1150 printf("\t\tPanel power OFF delay: %d\n", pps->panel_off_delay);
1151 printf("\t\tPanel power cycle delay: %d\n", pps->panel_power_cycle_delay);
1152}
1153
Jani Nikula9c4aa072015-12-21 16:18:20 +02001154static const uint8_t *mipi_dump_send_packet(const uint8_t *data)
Gaurav K Singhac31f192014-07-16 19:39:33 +05301155{
Jani Nikulacb89add2015-12-21 16:36:32 +02001156 uint8_t flags, type;
1157 uint16_t len, i;
Gaurav K Singhac31f192014-07-16 19:39:33 +05301158
Jani Nikulacb89add2015-12-21 16:36:32 +02001159 flags = *data++;
Gaurav K Singhac31f192014-07-16 19:39:33 +05301160 type = *data++;
Chris Wilsondc3fcd92016-11-30 19:37:37 +00001161 len = *((const uint16_t *) data);
Gaurav K Singhac31f192014-07-16 19:39:33 +05301162 data += 2;
Jani Nikulacb89add2015-12-21 16:36:32 +02001163
1164 printf("\t\tSend DCS: Port %s, VC %d, %s, Type %02x, Length %u, Data",
1165 (flags >> 3) & 1 ? "C" : "A",
1166 (flags >> 1) & 3,
1167 flags & 1 ? "HS" : "LP",
1168 type,
1169 len);
1170 for (i = 0; i < len; i++)
1171 printf(" %02x", *data++);
Gaurav K Singhac31f192014-07-16 19:39:33 +05301172 printf("\n");
Jani Nikulacb89add2015-12-21 16:36:32 +02001173
Gaurav K Singhac31f192014-07-16 19:39:33 +05301174 return data;
1175}
1176
Jani Nikula9c4aa072015-12-21 16:18:20 +02001177static const uint8_t *mipi_dump_delay(const uint8_t *data)
Gaurav K Singhac31f192014-07-16 19:39:33 +05301178{
Jani Nikulacb89add2015-12-21 16:36:32 +02001179 printf("\t\tDelay: %u us\n", *((const uint32_t *)data));
1180
1181 return data + 4;
Gaurav K Singhac31f192014-07-16 19:39:33 +05301182}
1183
Jani Nikula9c4aa072015-12-21 16:18:20 +02001184static const uint8_t *mipi_dump_gpio(const uint8_t *data)
Gaurav K Singhac31f192014-07-16 19:39:33 +05301185{
Jani Nikulacb89add2015-12-21 16:36:32 +02001186 uint8_t index, flags;
Gaurav K Singhac31f192014-07-16 19:39:33 +05301187
Jani Nikulacb89add2015-12-21 16:36:32 +02001188 index = *data++;
1189 flags = *data++;
Gaurav K Singhac31f192014-07-16 19:39:33 +05301190
Jani Nikulacb89add2015-12-21 16:36:32 +02001191 printf("\t\tGPIO index %u, source %d, set %d\n",
1192 index,
1193 (flags >> 1) & 3,
1194 flags & 1);
1195
Gaurav K Singhac31f192014-07-16 19:39:33 +05301196 return data;
1197}
1198
Jani Nikula97642472015-12-21 16:50:47 +02001199static const uint8_t *mipi_dump_i2c(const uint8_t *data)
1200{
1201 uint8_t flags, index, bus, offset, len, i;
1202 uint16_t address;
1203
1204 flags = *data++;
1205 index = *data++;
1206 bus = *data++;
Chris Wilsondc3fcd92016-11-30 19:37:37 +00001207 address = *((const uint16_t *) data);
Jani Nikula97642472015-12-21 16:50:47 +02001208 data += 2;
1209 offset = *data++;
1210 len = *data++;
1211
1212 printf("\t\tSend I2C: Flags %02x, Index %02x, Bus %02x, Address %04x, Offset %02x, Length %u, Data",
1213 flags, index, bus, address, offset, len);
1214 for (i = 0; i < len; i++)
1215 printf(" %02x", *data++);
1216 printf("\n");
1217
1218 return data;
1219}
1220
Jani Nikula9c4aa072015-12-21 16:18:20 +02001221typedef const uint8_t * (*fn_mipi_elem_dump)(const uint8_t *data);
Gaurav K Singhac31f192014-07-16 19:39:33 +05301222
1223static const fn_mipi_elem_dump dump_elem[] = {
Jani Nikula9c4aa072015-12-21 16:18:20 +02001224 [MIPI_SEQ_ELEM_SEND_PKT] = mipi_dump_send_packet,
1225 [MIPI_SEQ_ELEM_DELAY] = mipi_dump_delay,
1226 [MIPI_SEQ_ELEM_GPIO] = mipi_dump_gpio,
Jani Nikula97642472015-12-21 16:50:47 +02001227 [MIPI_SEQ_ELEM_I2C] = mipi_dump_i2c,
Gaurav K Singhac31f192014-07-16 19:39:33 +05301228};
1229
Jani Nikula9c4aa072015-12-21 16:18:20 +02001230static const char * const seq_name[] = {
1231 [MIPI_SEQ_ASSERT_RESET] = "MIPI_SEQ_ASSERT_RESET",
1232 [MIPI_SEQ_INIT_OTP] = "MIPI_SEQ_INIT_OTP",
1233 [MIPI_SEQ_DISPLAY_ON] = "MIPI_SEQ_DISPLAY_ON",
1234 [MIPI_SEQ_DISPLAY_OFF] = "MIPI_SEQ_DISPLAY_OFF",
1235 [MIPI_SEQ_DEASSERT_RESET] = "MIPI_SEQ_DEASSERT_RESET",
1236 [MIPI_SEQ_BACKLIGHT_ON] = "MIPI_SEQ_BACKLIGHT_ON",
1237 [MIPI_SEQ_BACKLIGHT_OFF] = "MIPI_SEQ_BACKLIGHT_OFF",
1238 [MIPI_SEQ_TEAR_ON] = "MIPI_SEQ_TEAR_ON",
1239 [MIPI_SEQ_TEAR_OFF] = "MIPI_SEQ_TEAR_OFF",
1240 [MIPI_SEQ_POWER_ON] = "MIPI_SEQ_POWER_ON",
1241 [MIPI_SEQ_POWER_OFF] = "MIPI_SEQ_POWER_OFF",
1242};
1243
1244static const char *sequence_name(enum mipi_seq seq_id)
Gaurav K Singhac31f192014-07-16 19:39:33 +05301245{
Jani Nikula9c4aa072015-12-21 16:18:20 +02001246 if (seq_id < ARRAY_SIZE(seq_name) && seq_name[seq_id])
1247 return seq_name[seq_id];
1248 else
1249 return "(unknown)";
Gaurav K Singhac31f192014-07-16 19:39:33 +05301250}
1251
Jani Nikula480479d2016-01-14 17:43:06 +02001252static const uint8_t *dump_sequence(const uint8_t *data, uint8_t seq_version)
Gaurav K Singhac31f192014-07-16 19:39:33 +05301253{
Jani Nikula9c4aa072015-12-21 16:18:20 +02001254 fn_mipi_elem_dump mipi_elem_dump;
Gaurav K Singhac31f192014-07-16 19:39:33 +05301255
Jani Nikula9c4aa072015-12-21 16:18:20 +02001256 printf("\tSequence %u - %s\n", *data, sequence_name(*data));
Gaurav K Singhac31f192014-07-16 19:39:33 +05301257
Jani Nikula9c4aa072015-12-21 16:18:20 +02001258 /* Skip Sequence Byte. */
Gaurav K Singhac31f192014-07-16 19:39:33 +05301259 data++;
Jani Nikula9c4aa072015-12-21 16:18:20 +02001260
Jani Nikula480479d2016-01-14 17:43:06 +02001261 /* Skip Size of Sequence. */
1262 if (seq_version >= 3)
1263 data += 4;
1264
Gaurav K Singhac31f192014-07-16 19:39:33 +05301265 while (1) {
Jani Nikula9c4aa072015-12-21 16:18:20 +02001266 uint8_t operation_byte = *data++;
Jani Nikula480479d2016-01-14 17:43:06 +02001267 uint8_t operation_size = 0;
Gaurav K Singhac31f192014-07-16 19:39:33 +05301268
Jani Nikula9c4aa072015-12-21 16:18:20 +02001269 if (operation_byte == MIPI_SEQ_ELEM_END)
Gaurav K Singhac31f192014-07-16 19:39:33 +05301270 break;
Gaurav K Singhac31f192014-07-16 19:39:33 +05301271
Jani Nikula480479d2016-01-14 17:43:06 +02001272 if (operation_byte < ARRAY_SIZE(dump_elem))
Jani Nikula9c4aa072015-12-21 16:18:20 +02001273 mipi_elem_dump = dump_elem[operation_byte];
1274 else
1275 mipi_elem_dump = NULL;
Gaurav K Singhac31f192014-07-16 19:39:33 +05301276
Jani Nikula480479d2016-01-14 17:43:06 +02001277 /* Size of Operation. */
1278 if (seq_version >= 3)
1279 operation_size = *data++;
1280
Jani Nikula9c4aa072015-12-21 16:18:20 +02001281 if (mipi_elem_dump) {
1282 data = mipi_elem_dump(data);
Jani Nikula480479d2016-01-14 17:43:06 +02001283 } else if (operation_size) {
1284 /* We have size, skip. */
1285 data += operation_size;
Jani Nikula9c4aa072015-12-21 16:18:20 +02001286 } else {
Jani Nikula480479d2016-01-14 17:43:06 +02001287 /* No size, can't skip without parsing. */
Jani Nikula9c4aa072015-12-21 16:18:20 +02001288 printf("Error: Unsupported MIPI element %u\n",
1289 operation_byte);
Gaurav K Singhac31f192014-07-16 19:39:33 +05301290 return NULL;
Jani Nikula9c4aa072015-12-21 16:18:20 +02001291 }
1292 }
Gaurav K Singhac31f192014-07-16 19:39:33 +05301293
Gaurav K Singhac31f192014-07-16 19:39:33 +05301294 return data;
1295}
1296
Jani Nikula7d1a3722016-01-14 16:24:11 +02001297/* Find the sequence block and size for the given panel. */
1298static const uint8_t *
1299find_panel_sequence_block(const struct bdb_mipi_sequence *sequence,
1300 uint16_t panel_id, uint32_t total, uint32_t *seq_size)
1301{
1302 const uint8_t *data = &sequence->data[0];
1303 uint8_t current_id;
1304 uint32_t current_size;
1305 int header_size = sequence->version >= 3 ? 5 : 3;
1306 int index = 0;
1307 int i;
1308
1309 /* skip new block size */
1310 if (sequence->version >= 3)
1311 data += 4;
1312
1313 for (i = 0; i < MAX_MIPI_CONFIGURATIONS && index < total; i++) {
1314 if (index + header_size > total) {
1315 fprintf(stderr, "Invalid sequence block (header)\n");
1316 return NULL;
1317 }
1318
1319 current_id = *(data + index);
1320 if (sequence->version >= 3)
1321 current_size = *((const uint32_t *)(data + index + 1));
1322 else
1323 current_size = *((const uint16_t *)(data + index + 1));
1324
1325 index += header_size;
1326
1327 if (index + current_size > total) {
1328 fprintf(stderr, "Invalid sequence block\n");
1329 return NULL;
1330 }
1331
1332 if (current_id == panel_id) {
1333 *seq_size = current_size;
1334 return data + index;
1335 }
1336
1337 index += current_size;
1338 }
1339
1340 fprintf(stderr, "Sequence block detected but no valid configuration\n");
1341
1342 return NULL;
1343}
1344
Jani Nikula70dc8c82016-01-14 16:41:53 +02001345static int goto_next_sequence(const uint8_t *data, int index, int total)
1346{
1347 uint16_t len;
1348
1349 /* Skip Sequence Byte. */
1350 for (index = index + 1; index < total; index += len) {
1351 uint8_t operation_byte = *(data + index);
1352 index++;
1353
1354 switch (operation_byte) {
1355 case MIPI_SEQ_ELEM_END:
1356 return index;
1357 case MIPI_SEQ_ELEM_SEND_PKT:
1358 if (index + 4 > total)
1359 return 0;
1360
1361 len = *((const uint16_t *)(data + index + 2)) + 4;
1362 break;
1363 case MIPI_SEQ_ELEM_DELAY:
1364 len = 4;
1365 break;
1366 case MIPI_SEQ_ELEM_GPIO:
1367 len = 2;
1368 break;
1369 case MIPI_SEQ_ELEM_I2C:
1370 if (index + 7 > total)
1371 return 0;
1372 len = *(data + index + 6) + 7;
1373 break;
1374 default:
1375 fprintf(stderr, "Unknown operation byte\n");
1376 return 0;
1377 }
1378 }
1379
1380 return 0;
1381}
1382
1383static int goto_next_sequence_v3(const uint8_t *data, int index, int total)
1384{
1385 int seq_end;
1386 uint16_t len;
1387 uint32_t size_of_sequence;
1388
1389 /*
1390 * Could skip sequence based on Size of Sequence alone, but also do some
1391 * checking on the structure.
1392 */
1393 if (total < 5) {
1394 fprintf(stderr, "Too small sequence size\n");
1395 return 0;
1396 }
1397
1398 /* Skip Sequence Byte. */
1399 index++;
1400
1401 /*
1402 * Size of Sequence. Excludes the Sequence Byte and the size itself,
1403 * includes MIPI_SEQ_ELEM_END byte, excludes the final MIPI_SEQ_END
1404 * byte.
1405 */
1406 size_of_sequence = *((const uint32_t *)(data + index));
1407 index += 4;
1408
1409 seq_end = index + size_of_sequence;
1410 if (seq_end > total) {
1411 fprintf(stderr, "Invalid sequence size\n");
1412 return 0;
1413 }
1414
1415 for (; index < total; index += len) {
1416 uint8_t operation_byte = *(data + index);
1417 index++;
1418
1419 if (operation_byte == MIPI_SEQ_ELEM_END) {
1420 if (index != seq_end) {
1421 fprintf(stderr, "Invalid element structure\n");
1422 return 0;
1423 }
1424 return index;
1425 }
1426
1427 len = *(data + index);
1428 index++;
1429
1430 /*
1431 * FIXME: Would be nice to check elements like for v1/v2 in
1432 * goto_next_sequence() above.
1433 */
1434 switch (operation_byte) {
1435 case MIPI_SEQ_ELEM_SEND_PKT:
1436 case MIPI_SEQ_ELEM_DELAY:
1437 case MIPI_SEQ_ELEM_GPIO:
1438 case MIPI_SEQ_ELEM_I2C:
1439 case MIPI_SEQ_ELEM_SPI:
1440 case MIPI_SEQ_ELEM_PMIC:
1441 break;
1442 default:
1443 fprintf(stderr, "Unknown operation byte %u\n",
1444 operation_byte);
1445 break;
1446 }
1447 }
1448
1449 return 0;
1450}
1451
Jani Nikula76a04622016-05-02 18:33:19 +03001452static void dump_mipi_sequence(struct context *context,
Jani Nikula2e2fffa2016-01-14 15:27:50 +02001453 const struct bdb_block *block)
Gaurav K Singhac31f192014-07-16 19:39:33 +05301454{
Jani Nikulab2639342016-01-14 16:08:55 +02001455 const struct bdb_mipi_sequence *sequence = block->data;
Jani Nikula9c4aa072015-12-21 16:18:20 +02001456 const uint8_t *data;
Jani Nikula7d1a3722016-01-14 16:24:11 +02001457 uint32_t seq_size;
Jani Nikula480479d2016-01-14 17:43:06 +02001458 int index = 0, i;
1459 const uint8_t *sequence_ptrs[MIPI_SEQ_MAX] = {};
Gaurav K Singhac31f192014-07-16 19:39:33 +05301460
1461 /* Check if we have sequence block as well */
1462 if (!sequence) {
1463 printf("No MIPI Sequence found\n");
1464 return;
1465 }
1466
Jani Nikula68cfe4b2015-12-21 15:51:10 +02001467 printf("\tSequence block version v%u\n", sequence->version);
1468
Jani Nikula70dc8c82016-01-14 16:41:53 +02001469 /* Fail gracefully for forward incompatible sequence block. */
1470 if (sequence->version >= 4) {
1471 fprintf(stderr, "Unable to parse MIPI Sequence Block v%u\n",
1472 sequence->version);
Jani Nikula68cfe4b2015-12-21 15:51:10 +02001473 return;
Jani Nikula70dc8c82016-01-14 16:41:53 +02001474 }
Jani Nikula68cfe4b2015-12-21 15:51:10 +02001475
Jani Nikula3a81cf52016-05-03 11:44:32 +03001476 data = find_panel_sequence_block(sequence, context->panel_type,
Jani Nikula7d1a3722016-01-14 16:24:11 +02001477 block->size, &seq_size);
1478 if (!data)
Gaurav K Singhac31f192014-07-16 19:39:33 +05301479 return;
Gaurav K Singhac31f192014-07-16 19:39:33 +05301480
Jani Nikula70dc8c82016-01-14 16:41:53 +02001481 /* Parse the sequences. Corresponds to VBT parsing in the kernel. */
1482 for (;;) {
1483 uint8_t seq_id = *(data + index);
1484 if (seq_id == MIPI_SEQ_END)
1485 break;
1486
1487 if (seq_id >= MIPI_SEQ_MAX) {
1488 fprintf(stderr, "Unknown sequence %u\n", seq_id);
1489 return;
1490 }
1491
Jani Nikula480479d2016-01-14 17:43:06 +02001492 sequence_ptrs[seq_id] = data + index;
1493
Jani Nikula70dc8c82016-01-14 16:41:53 +02001494 if (sequence->version >= 3)
1495 index = goto_next_sequence_v3(data, index, seq_size);
1496 else
1497 index = goto_next_sequence(data, index, seq_size);
1498 if (!index) {
1499 fprintf(stderr, "Invalid sequence %u\n", seq_id);
1500 return;
1501 }
1502 }
1503
Jani Nikula480479d2016-01-14 17:43:06 +02001504 /* Dump the sequences. Corresponds to sequence execution in kernel. */
1505 for (i = 0; i < ARRAY_SIZE(sequence_ptrs); i++)
1506 if (sequence_ptrs[i])
1507 dump_sequence(sequence_ptrs[i], sequence->version);
Gaurav K Singhac31f192014-07-16 19:39:33 +05301508}
1509
Jani Nikula21467dc2016-05-03 12:07:30 +03001510/* get panel type from lvds options block, or -1 if block not found */
1511static int get_panel_type(struct context *context)
1512{
1513 struct bdb_block *block;
1514 const struct bdb_lvds_options *options;
1515 int panel_type;
1516
1517 block = find_section(context, BDB_LVDS_OPTIONS);
1518 if (!block)
1519 return -1;
1520
1521 options = block->data;
1522 panel_type = options->panel_type;
1523
1524 free(block);
1525
1526 return panel_type;
1527}
1528
Adam Jackson4f12d8a2010-09-08 14:39:12 -04001529static int
Ville Syrjäläb701bb12015-03-25 20:23:30 +02001530get_device_id(unsigned char *bios, int size)
Adam Jackson4f12d8a2010-09-08 14:39:12 -04001531{
1532 int device;
1533 int offset = (bios[0x19] << 8) + bios[0x18];
1534
Ville Syrjäläb701bb12015-03-25 20:23:30 +02001535 if (offset + 7 >= size)
1536 return -1;
1537
Adam Jackson4f12d8a2010-09-08 14:39:12 -04001538 if (bios[offset] != 'P' ||
1539 bios[offset+1] != 'C' ||
1540 bios[offset+2] != 'I' ||
1541 bios[offset+3] != 'R')
1542 return -1;
1543
1544 device = (bios[offset+7] << 8) + bios[offset+6];
1545
1546 return device;
1547}
1548
Jani Nikulaa4180df2013-10-08 21:15:27 +03001549struct dumper {
1550 uint8_t id;
1551 const char *name;
Jani Nikula76a04622016-05-02 18:33:19 +03001552 void (*dump)(struct context *context,
Jani Nikula2e2fffa2016-01-14 15:27:50 +02001553 const struct bdb_block *block);
Jani Nikulaa4180df2013-10-08 21:15:27 +03001554};
1555
1556struct dumper dumpers[] = {
1557 {
1558 .id = BDB_GENERAL_FEATURES,
1559 .name = "General features block",
1560 .dump = dump_general_features,
1561 },
1562 {
1563 .id = BDB_GENERAL_DEFINITIONS,
1564 .name = "General definitions block",
1565 .dump = dump_general_definitions,
1566 },
1567 {
1568 .id = BDB_CHILD_DEVICE_TABLE,
Jani Nikuladff8b302017-08-25 12:30:20 +03001569 .name = "Legacy child devices block",
1570 .dump = dump_legacy_child_devices,
Jani Nikulaa4180df2013-10-08 21:15:27 +03001571 },
1572 {
1573 .id = BDB_LVDS_OPTIONS,
1574 .name = "LVDS options block",
1575 .dump = dump_lvds_options,
1576 },
1577 {
1578 .id = BDB_LVDS_LFP_DATA_PTRS,
1579 .name = "LVDS timing pointer data",
1580 .dump = dump_lvds_ptr_data,
1581 },
1582 {
1583 .id = BDB_LVDS_LFP_DATA,
1584 .name = "LVDS panel data block",
1585 .dump = dump_lvds_data,
1586 },
1587 {
1588 .id = BDB_LVDS_BACKLIGHT,
1589 .name = "Backlight info block",
1590 .dump = dump_backlight_info,
1591 },
1592 {
1593 .id = BDB_SDVO_LVDS_OPTIONS,
1594 .name = "SDVO LVDS options block",
1595 .dump = dump_sdvo_lvds_options,
1596 },
1597 {
1598 .id = BDB_SDVO_PANEL_DTDS,
1599 .name = "SDVO panel dtds",
1600 .dump = dump_sdvo_panel_dtds,
1601 },
1602 {
1603 .id = BDB_DRIVER_FEATURES,
1604 .name = "Driver feature data block",
1605 .dump = dump_driver_feature,
1606 },
1607 {
1608 .id = BDB_EDP,
1609 .name = "eDP block",
1610 .dump = dump_edp,
1611 },
Gaurav K Singh525044b2014-07-16 19:39:32 +05301612 {
Ville Syrjälä8e4ce752016-09-12 13:34:53 +03001613 .id = BDB_PSR,
1614 .name = "PSR block",
1615 .dump = dump_psr,
1616 },
1617 {
Gaurav K Singh525044b2014-07-16 19:39:32 +05301618 .id = BDB_MIPI_CONFIG,
1619 .name = "MIPI configuration block",
1620 .dump = dump_mipi_config,
1621 },
Gaurav K Singhac31f192014-07-16 19:39:33 +05301622 {
1623 .id = BDB_MIPI_SEQUENCE,
1624 .name = "MIPI sequence block",
1625 .dump = dump_mipi_sequence,
1626 },
Jani Nikulaa4180df2013-10-08 21:15:27 +03001627};
1628
Jani Nikula295cd2c2017-01-24 11:48:55 +02001629static void hex_dump(const void *data, uint32_t size)
Jani Nikulaa4180df2013-10-08 21:15:27 +03001630{
1631 int i;
Jani Nikula295cd2c2017-01-24 11:48:55 +02001632 const uint8_t *p = data;
Jani Nikulaa4180df2013-10-08 21:15:27 +03001633
Jani Nikula295cd2c2017-01-24 11:48:55 +02001634 for (i = 0; i < size; i++) {
Jani Nikulaa4180df2013-10-08 21:15:27 +03001635 if (i % 16 == 0)
1636 printf("\t%04x: ", i);
1637 printf("%02x", p[i]);
1638 if (i % 16 == 15) {
Jani Nikula295cd2c2017-01-24 11:48:55 +02001639 if (i + 1 < size)
Jani Nikulaa4180df2013-10-08 21:15:27 +03001640 printf("\n");
1641 } else if (i % 8 == 7) {
1642 printf(" ");
1643 } else {
1644 printf(" ");
1645 }
1646 }
1647 printf("\n\n");
1648}
1649
Jani Nikula295cd2c2017-01-24 11:48:55 +02001650static void hex_dump_block(const struct bdb_block *block)
1651{
1652 hex_dump(block->data, block->size);
1653}
1654
Jani Nikula1c332312016-05-03 12:26:22 +03001655static bool dump_section(struct context *context, int section_id)
Jani Nikulaa4180df2013-10-08 21:15:27 +03001656{
1657 struct dumper *dumper = NULL;
Jani Nikulab4f96db2016-05-03 12:48:38 +03001658 struct bdb_block *block;
Jani Nikulaa4180df2013-10-08 21:15:27 +03001659 int i;
1660
Jani Nikula76a04622016-05-02 18:33:19 +03001661 block = find_section(context, section_id);
Jani Nikulaa360e392013-10-08 21:15:28 +03001662 if (!block)
Jani Nikula1c332312016-05-03 12:26:22 +03001663 return false;
Jani Nikulaa4180df2013-10-08 21:15:27 +03001664
1665 for (i = 0; i < ARRAY_SIZE(dumpers); i++) {
1666 if (block->id == dumpers[i].id) {
1667 dumper = &dumpers[i];
1668 break;
1669 }
1670 }
1671
1672 if (dumper && dumper->name)
1673 printf("BDB block %d - %s:\n", block->id, dumper->name);
1674 else
Jani Nikula56cbe6b2017-01-24 12:07:01 +02001675 printf("BDB block %d - Unknown, no decoding available:\n",
1676 block->id);
Jani Nikulaa4180df2013-10-08 21:15:27 +03001677
Jani Nikulab0a8b082016-05-03 12:17:16 +03001678 if (context->hexdump)
Jani Nikula295cd2c2017-01-24 11:48:55 +02001679 hex_dump_block(block);
Jani Nikulaa4180df2013-10-08 21:15:27 +03001680 if (dumper && dumper->dump)
Jani Nikula76a04622016-05-02 18:33:19 +03001681 dumper->dump(context, block);
Jani Nikulaa4180df2013-10-08 21:15:27 +03001682 printf("\n");
Jani Nikula1c332312016-05-03 12:26:22 +03001683
Jani Nikulab4f96db2016-05-03 12:48:38 +03001684 free(block);
1685
Jani Nikula1c332312016-05-03 12:26:22 +03001686 return true;
Jani Nikulaa4180df2013-10-08 21:15:27 +03001687}
1688
Jani Nikula37bd27f2017-10-20 16:24:50 +03001689/* print a description of the VBT of the form <bdb-version>-<vbt-signature> */
1690static void print_description(struct context *context)
1691{
1692 const struct vbt_header *vbt = context->vbt;
1693 const struct bdb_header *bdb = context->bdb;
1694 char *desc = strndup((char *)vbt->signature, sizeof(vbt->signature));
1695 char *p;
1696
1697 for (p = desc + strlen(desc) - 1; p >= desc && isspace(*p); p--)
1698 *p = '\0';
1699
1700 for (p = desc; *p; p++) {
1701 if (!isalnum(*p))
1702 *p = '-';
1703 else
1704 *p = tolower(*p);
1705 }
1706
1707 p = desc;
1708 if (strncmp(p, "-vbt-", 5) == 0)
1709 p += 5;
1710
1711 printf("%d-%s\n", bdb->version, p);
1712
1713 free (desc);
1714}
1715
Jani Nikulaf482e232016-05-12 14:28:50 +03001716static void dump_headers(struct context *context)
1717{
Jani Nikula4daac352016-05-12 15:25:13 +03001718 const struct vbt_header *vbt = context->vbt;
1719 const struct bdb_header *bdb = context->bdb;
1720 int i, j = 0;
Jani Nikulaf482e232016-05-12 14:28:50 +03001721
Jani Nikula42b80a12017-01-24 11:56:25 +02001722 printf("VBT header:\n");
Jani Nikulacb55d6c2017-01-24 11:59:06 +02001723 if (context->hexdump)
1724 hex_dump(vbt, vbt->header_size);
Jani Nikulaf482e232016-05-12 14:28:50 +03001725
Jani Nikula311e75d2017-01-24 12:20:27 +02001726 printf("\tVBT signature:\t\t\"%.*s\"\n",
Jani Nikula42b80a12017-01-24 11:56:25 +02001727 (int)sizeof(vbt->signature), vbt->signature);
Jani Nikula311e75d2017-01-24 12:20:27 +02001728 printf("\tVBT version:\t\t0x%04x (%d.%d)\n", vbt->version,
1729 vbt->version / 100, vbt->version % 100);
1730 printf("\tVBT header size:\t0x%04x (%u)\n",
1731 vbt->header_size, vbt->header_size);
1732 printf("\tVBT size:\t\t0x%04x (%u)\n", vbt->vbt_size, vbt->vbt_size);
1733 printf("\tVBT checksum:\t\t0x%02x\n", vbt->vbt_checksum);
1734 printf("\tBDB offset:\t\t0x%08x (%u)\n", vbt->bdb_offset, vbt->bdb_offset);
1735
Jani Nikula42b80a12017-01-24 11:56:25 +02001736 printf("\n");
1737
1738 printf("BDB header:\n");
Jani Nikulacb55d6c2017-01-24 11:59:06 +02001739 if (context->hexdump)
1740 hex_dump(bdb, bdb->header_size);
Jani Nikula42b80a12017-01-24 11:56:25 +02001741
Jani Nikula311e75d2017-01-24 12:20:27 +02001742 printf("\tBDB signature:\t\t\"%.*s\"\n",
Jani Nikula4daac352016-05-12 15:25:13 +03001743 (int)sizeof(bdb->signature), bdb->signature);
Jani Nikula311e75d2017-01-24 12:20:27 +02001744 printf("\tBDB version:\t\t%d\n", bdb->version);
1745 printf("\tBDB header size:\t0x%04x (%u)\n",
1746 bdb->header_size, bdb->header_size);
1747 printf("\tBDB size:\t\t0x%04x (%u)\n", bdb->bdb_size, bdb->bdb_size);
Jani Nikula42b80a12017-01-24 11:56:25 +02001748 printf("\n");
Jani Nikulaf482e232016-05-12 14:28:50 +03001749
Jani Nikula4daac352016-05-12 15:25:13 +03001750 printf("BDB blocks present:");
Jani Nikulaf482e232016-05-12 14:28:50 +03001751 for (i = 0; i < 256; i++) {
1752 struct bdb_block *block;
1753
1754 block = find_section(context, i);
1755 if (!block)
1756 continue;
Jani Nikula4daac352016-05-12 15:25:13 +03001757
1758 if (j++ % 16)
1759 printf(" %3d", i);
1760 else
1761 printf("\n\t%3d", i);
1762
Jani Nikulaf482e232016-05-12 14:28:50 +03001763 free(block);
1764 }
Jani Nikula4daac352016-05-12 15:25:13 +03001765 printf("\n\n");
Jani Nikulaf482e232016-05-12 14:28:50 +03001766}
1767
Jani Nikula8a06cc12016-05-03 11:29:43 +03001768enum opt {
1769 OPT_UNKNOWN = '?',
1770 OPT_END = -1,
1771 OPT_FILE,
Jani Nikula4d4b1c22016-05-02 18:15:55 +03001772 OPT_DEVID,
Jani Nikula21467dc2016-05-03 12:07:30 +03001773 OPT_PANEL_TYPE,
Jani Nikula96647f12016-05-03 12:36:32 +03001774 OPT_ALL_PANELS,
Jani Nikulab0a8b082016-05-03 12:17:16 +03001775 OPT_HEXDUMP,
Jani Nikula1c332312016-05-03 12:26:22 +03001776 OPT_BLOCK,
Marius Vladec779452016-05-04 20:35:18 +03001777 OPT_USAGE,
Jani Nikula7c8b8632017-10-20 16:19:33 +03001778 OPT_HEADER,
Jani Nikula37bd27f2017-10-20 16:24:50 +03001779 OPT_DESCRIBE,
Jani Nikula8a06cc12016-05-03 11:29:43 +03001780};
1781
Marius Vladec779452016-05-04 20:35:18 +03001782static void usage(const char *toolname)
1783{
1784 fprintf(stderr, "usage: %s", toolname);
1785 fprintf(stderr, " --file=<rom_file>"
1786 " [--devid=<device_id>]"
1787 " [--panel-type=<panel_type>]"
1788 " [--all-panels]"
1789 " [--hexdump]"
1790 " [--block=<block_no>]"
Jani Nikula7c8b8632017-10-20 16:19:33 +03001791 " [--header]"
Jani Nikula37bd27f2017-10-20 16:24:50 +03001792 " [--describe]"
Marius Vladec779452016-05-04 20:35:18 +03001793 " [--help]\n");
1794}
1795
Zhenyu Wang97ffee62010-01-12 14:04:43 +08001796int main(int argc, char **argv)
1797{
Jani Nikula1272b9c2016-05-03 11:29:25 +03001798 uint8_t *VBIOS;
Jani Nikula8a06cc12016-05-03 11:29:43 +03001799 int index;
1800 enum opt opt;
Zhenyu Wang97ffee62010-01-12 14:04:43 +08001801 int fd;
1802 struct vbt_header *vbt = NULL;
1803 int vbt_off, bdb_off, i;
Jani Nikula8a06cc12016-05-03 11:29:43 +03001804 const char *filename = NULL;
1805 const char *toolname = argv[0];
Zhenyu Wang97ffee62010-01-12 14:04:43 +08001806 struct stat finfo;
Jani Nikula8596a4b2013-10-08 21:15:26 +03001807 int size;
Jani Nikula21467dc2016-05-03 12:07:30 +03001808 struct context context = {
1809 .panel_type = -1,
1810 };
Jani Nikula4d4b1c22016-05-02 18:15:55 +03001811 char *endp;
Jani Nikula1c332312016-05-03 12:26:22 +03001812 int block_number = -1;
Jani Nikula37bd27f2017-10-20 16:24:50 +03001813 bool header_only = false, describe = false;
Zhenyu Wang97ffee62010-01-12 14:04:43 +08001814
Jani Nikula8a06cc12016-05-03 11:29:43 +03001815 static struct option options[] = {
1816 { "file", required_argument, NULL, OPT_FILE },
Jani Nikula4d4b1c22016-05-02 18:15:55 +03001817 { "devid", required_argument, NULL, OPT_DEVID },
Jani Nikula21467dc2016-05-03 12:07:30 +03001818 { "panel-type", required_argument, NULL, OPT_PANEL_TYPE },
Jani Nikula96647f12016-05-03 12:36:32 +03001819 { "all-panels", no_argument, NULL, OPT_ALL_PANELS },
Jani Nikulab0a8b082016-05-03 12:17:16 +03001820 { "hexdump", no_argument, NULL, OPT_HEXDUMP },
Jani Nikula1c332312016-05-03 12:26:22 +03001821 { "block", required_argument, NULL, OPT_BLOCK },
Jani Nikula7c8b8632017-10-20 16:19:33 +03001822 { "header", no_argument, NULL, OPT_HEADER },
Jani Nikula37bd27f2017-10-20 16:24:50 +03001823 { "describe", no_argument, NULL, OPT_DESCRIBE },
Marius Vladec779452016-05-04 20:35:18 +03001824 { "help", no_argument, NULL, OPT_USAGE },
Jani Nikula8a06cc12016-05-03 11:29:43 +03001825 { 0 }
1826 };
1827
1828 for (opt = 0; opt != OPT_END; ) {
1829 opt = getopt_long(argc, argv, "", options, &index);
1830
1831 switch (opt) {
1832 case OPT_FILE:
1833 filename = optarg;
1834 break;
Jani Nikula4d4b1c22016-05-02 18:15:55 +03001835 case OPT_DEVID:
Jani Nikulab6ccc552016-05-12 14:02:05 +03001836 context.devid = strtoul(optarg, &endp, 16);
1837 if (!context.devid || *endp) {
Jani Nikula4d4b1c22016-05-02 18:15:55 +03001838 fprintf(stderr, "invalid devid '%s'\n", optarg);
1839 return EXIT_FAILURE;
1840 }
1841 break;
Jani Nikula21467dc2016-05-03 12:07:30 +03001842 case OPT_PANEL_TYPE:
1843 context.panel_type = strtoul(optarg, &endp, 0);
1844 if (*endp || context.panel_type > 15) {
1845 fprintf(stderr, "invalid panel type '%s'\n",
1846 optarg);
1847 return EXIT_FAILURE;
1848 }
1849 break;
Jani Nikula96647f12016-05-03 12:36:32 +03001850 case OPT_ALL_PANELS:
1851 context.dump_all_panel_types = true;
1852 break;
Jani Nikulab0a8b082016-05-03 12:17:16 +03001853 case OPT_HEXDUMP:
1854 context.hexdump = true;
1855 break;
Jani Nikula1c332312016-05-03 12:26:22 +03001856 case OPT_BLOCK:
1857 block_number = strtoul(optarg, &endp, 0);
1858 if (*endp) {
1859 fprintf(stderr, "invalid block number '%s'\n",
1860 optarg);
1861 return EXIT_FAILURE;
1862 }
1863 break;
Jani Nikula7c8b8632017-10-20 16:19:33 +03001864 case OPT_HEADER:
1865 header_only = true;
1866 break;
Jani Nikula37bd27f2017-10-20 16:24:50 +03001867 case OPT_DESCRIBE:
1868 describe = true;
1869 break;
Jani Nikula8a06cc12016-05-03 11:29:43 +03001870 case OPT_END:
1871 break;
Marius Vladec779452016-05-04 20:35:18 +03001872 case OPT_USAGE: /* fall-through */
Jani Nikula8a06cc12016-05-03 11:29:43 +03001873 case OPT_UNKNOWN:
Marius Vladec779452016-05-04 20:35:18 +03001874 usage(toolname);
Jani Nikula8a06cc12016-05-03 11:29:43 +03001875 return EXIT_FAILURE;
1876 }
1877 }
1878
1879 argc -= optind;
1880 argv += optind;
1881
1882 if (!filename) {
1883 if (argc == 1) {
1884 /* for backwards compatibility */
1885 filename = argv[0];
1886 } else {
Marius Vladec779452016-05-04 20:35:18 +03001887 usage(toolname);
Jani Nikula8a06cc12016-05-03 11:29:43 +03001888 return EXIT_FAILURE;
1889 }
Zhenyu Wang97ffee62010-01-12 14:04:43 +08001890 }
1891
Zhenyu Wang97ffee62010-01-12 14:04:43 +08001892 fd = open(filename, O_RDONLY);
1893 if (fd == -1) {
Jani Nikula1dd3ff02016-05-12 15:35:37 +03001894 fprintf(stderr, "Couldn't open \"%s\": %s\n",
1895 filename, strerror(errno));
1896 return EXIT_FAILURE;
Zhenyu Wang97ffee62010-01-12 14:04:43 +08001897 }
1898
1899 if (stat(filename, &finfo)) {
Jani Nikula1dd3ff02016-05-12 15:35:37 +03001900 fprintf(stderr, "Failed to stat \"%s\": %s\n",
1901 filename, strerror(errno));
1902 return EXIT_FAILURE;
Zhenyu Wang97ffee62010-01-12 14:04:43 +08001903 }
Jani Nikula8596a4b2013-10-08 21:15:26 +03001904 size = finfo.st_size;
Zhenyu Wang97ffee62010-01-12 14:04:43 +08001905
Jani Nikula8596a4b2013-10-08 21:15:26 +03001906 if (size == 0) {
Chris Wilson281285e2011-01-29 16:12:38 +00001907 int len = 0, ret;
Jani Nikula8596a4b2013-10-08 21:15:26 +03001908 size = 8192;
1909 VBIOS = malloc (size);
1910 while ((ret = read(fd, VBIOS + len, size - len))) {
Chris Wilson281285e2011-01-29 16:12:38 +00001911 if (ret < 0) {
Jani Nikula1dd3ff02016-05-12 15:35:37 +03001912 fprintf(stderr, "Failed to read \"%s\": %s\n",
1913 filename, strerror(errno));
1914 return EXIT_FAILURE;
Chris Wilson281285e2011-01-29 16:12:38 +00001915 }
1916
1917 len += ret;
Jani Nikula8596a4b2013-10-08 21:15:26 +03001918 if (len == size) {
1919 size *= 2;
1920 VBIOS = realloc(VBIOS, size);
Chris Wilson281285e2011-01-29 16:12:38 +00001921 }
1922 }
1923 } else {
Jani Nikula8596a4b2013-10-08 21:15:26 +03001924 VBIOS = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
Chris Wilson281285e2011-01-29 16:12:38 +00001925 if (VBIOS == MAP_FAILED) {
Jani Nikula1dd3ff02016-05-12 15:35:37 +03001926 fprintf(stderr, "Failed to map \"%s\": %s\n",
1927 filename, strerror(errno));
1928 return EXIT_FAILURE;
Chris Wilson281285e2011-01-29 16:12:38 +00001929 }
Zhenyu Wang97ffee62010-01-12 14:04:43 +08001930 }
1931
1932 /* Scour memory looking for the VBT signature */
Jani Nikula8596a4b2013-10-08 21:15:26 +03001933 for (i = 0; i + 4 < size; i++) {
Chris Wilson281285e2011-01-29 16:12:38 +00001934 if (!memcmp(VBIOS + i, "$VBT", 4)) {
Zhenyu Wang97ffee62010-01-12 14:04:43 +08001935 vbt_off = i;
Chris Wilson281285e2011-01-29 16:12:38 +00001936 vbt = (struct vbt_header *)(VBIOS + i);
Zhenyu Wang97ffee62010-01-12 14:04:43 +08001937 break;
1938 }
1939 }
1940
1941 if (!vbt) {
Jani Nikula1dd3ff02016-05-12 15:35:37 +03001942 fprintf(stderr, "VBT signature missing\n");
1943 return EXIT_FAILURE;
Zhenyu Wang97ffee62010-01-12 14:04:43 +08001944 }
1945
Zhenyu Wang97ffee62010-01-12 14:04:43 +08001946 bdb_off = vbt_off + vbt->bdb_offset;
Jani Nikula8596a4b2013-10-08 21:15:26 +03001947 if (bdb_off >= size - sizeof(struct bdb_header)) {
Jani Nikula1dd3ff02016-05-12 15:35:37 +03001948 fprintf(stderr, "Invalid VBT found, BDB points beyond end of data block\n");
1949 return EXIT_FAILURE;
Chris Wilson1ffe6b02012-01-25 10:11:49 +00001950 }
1951
Jani Nikulaf482e232016-05-12 14:28:50 +03001952 context.vbt = vbt;
1953 context.bdb = (const struct bdb_header *)(VBIOS + bdb_off);
Jani Nikula76a04622016-05-02 18:33:19 +03001954 context.size = size;
Jani Nikulaa4180df2013-10-08 21:15:27 +03001955
Jani Nikulab6ccc552016-05-12 14:02:05 +03001956 if (!context.devid) {
Jani Nikula4d4b1c22016-05-02 18:15:55 +03001957 const char *devid_string = getenv("DEVICE");
1958 if (devid_string)
Jani Nikulab6ccc552016-05-12 14:02:05 +03001959 context.devid = strtoul(devid_string, NULL, 16);
Jani Nikula4d4b1c22016-05-02 18:15:55 +03001960 }
Jani Nikulab6ccc552016-05-12 14:02:05 +03001961 if (!context.devid)
1962 context.devid = get_device_id(VBIOS, size);
1963 if (!context.devid)
Jani Nikula4d4b1c22016-05-02 18:15:55 +03001964 fprintf(stderr, "Warning: could not find PCI device ID!\n");
Zhenyu Wang581205d2010-06-03 10:31:04 +08001965
Jani Nikula21467dc2016-05-03 12:07:30 +03001966 if (context.panel_type == -1)
1967 context.panel_type = get_panel_type(&context);
1968 if (context.panel_type == -1) {
1969 fprintf(stderr, "Warning: panel type not set, using 0\n");
1970 context.panel_type = 0;
1971 }
1972
Jani Nikula37bd27f2017-10-20 16:24:50 +03001973 if (describe) {
1974 print_description(&context);
1975 } else if (header_only) {
Jani Nikula7c8b8632017-10-20 16:19:33 +03001976 dump_headers(&context);
1977 } else if (block_number != -1) {
Jani Nikula1c332312016-05-03 12:26:22 +03001978 /* dump specific section only */
1979 if (!dump_section(&context, block_number)) {
1980 fprintf(stderr, "Block %d not found\n", block_number);
1981 return EXIT_FAILURE;
1982 }
1983 } else {
Jani Nikula4daac352016-05-12 15:25:13 +03001984 dump_headers(&context);
1985
Jani Nikula1c332312016-05-03 12:26:22 +03001986 /* dump all sections */
1987 for (i = 0; i < 256; i++)
1988 dump_section(&context, i);
1989 }
Jani Nikulaa360e392013-10-08 21:15:28 +03001990
Zhenyu Wang97ffee62010-01-12 14:04:43 +08001991 return 0;
1992}