Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 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 | |
Jani Nikula | 37bd27f | 2017-10-20 16:24:50 +0300 | [diff] [blame] | 28 | #include <ctype.h> |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 29 | #include <errno.h> |
| 30 | #include <fcntl.h> |
Jani Nikula | 8a06cc1 | 2016-05-03 11:29:43 +0300 | [diff] [blame] | 31 | #include <getopt.h> |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 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 | |
Jani Nikula | da4b9fe | 2017-08-29 11:34:04 +0300 | [diff] [blame] | 40 | #include "igt_aux.h" |
Daniel Vetter | c03c6ce | 2014-03-22 21:34:29 +0100 | [diff] [blame] | 41 | #include "intel_io.h" |
Daniel Vetter | 6cfcd71 | 2014-03-22 20:07:35 +0100 | [diff] [blame] | 42 | #include "intel_chipset.h" |
| 43 | #include "drmtest.h" |
Zhenyu Wang | 581205d | 2010-06-03 10:31:04 +0800 | [diff] [blame] | 44 | |
Jani Nikula | 09f35ea | 2017-08-25 15:56:19 +0300 | [diff] [blame] | 45 | /* kernel types for intel_vbt_defs.h */ |
| 46 | typedef uint8_t u8; |
| 47 | typedef uint16_t u16; |
| 48 | typedef uint32_t u32; |
Jani Nikula | 66d88e6 | 2017-08-25 17:15:43 +0300 | [diff] [blame] | 49 | typedef uint64_t u64; |
Jani Nikula | 09f35ea | 2017-08-25 15:56:19 +0300 | [diff] [blame] | 50 | #define __packed __attribute__ ((packed)) |
| 51 | |
| 52 | #define _INTEL_BIOS_PRIVATE |
| 53 | #include "intel_vbt_defs.h" |
| 54 | |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 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 | |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 66 | #define YESNO(val) ((val) ? "yes" : "no") |
| 67 | |
Jani Nikula | d9588c8 | 2016-01-14 15:48:13 +0200 | [diff] [blame] | 68 | /* This is not for mapping to memory layout. */ |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 69 | struct bdb_block { |
| 70 | uint8_t id; |
Jani Nikula | d9588c8 | 2016-01-14 15:48:13 +0200 | [diff] [blame] | 71 | uint32_t size; |
Jani Nikula | b263934 | 2016-01-14 16:08:55 +0200 | [diff] [blame] | 72 | const void *data; |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 73 | }; |
| 74 | |
Jani Nikula | 76a0462 | 2016-05-02 18:33:19 +0300 | [diff] [blame] | 75 | struct context { |
Jani Nikula | f482e23 | 2016-05-12 14:28:50 +0300 | [diff] [blame] | 76 | const struct vbt_header *vbt; |
Jani Nikula | 76a0462 | 2016-05-02 18:33:19 +0300 | [diff] [blame] | 77 | const struct bdb_header *bdb; |
| 78 | int size; |
Jani Nikula | 76a0462 | 2016-05-02 18:33:19 +0300 | [diff] [blame] | 79 | |
Jani Nikula | b6ccc55 | 2016-05-12 14:02:05 +0300 | [diff] [blame] | 80 | uint32_t devid; |
Jani Nikula | 3a81cf5 | 2016-05-03 11:44:32 +0300 | [diff] [blame] | 81 | int panel_type; |
Jani Nikula | 96647f1 | 2016-05-03 12:36:32 +0300 | [diff] [blame] | 82 | bool dump_all_panel_types; |
Jani Nikula | b0a8b08 | 2016-05-03 12:17:16 +0300 | [diff] [blame] | 83 | bool hexdump; |
Jani Nikula | 3a81cf5 | 2016-05-03 11:44:32 +0300 | [diff] [blame] | 84 | }; |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 85 | |
Jani Nikula | d9588c8 | 2016-01-14 15:48:13 +0200 | [diff] [blame] | 86 | /* Get BDB block size given a pointer to Block ID. */ |
| 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 | |
Jani Nikula | 76a0462 | 2016-05-02 18:33:19 +0300 | [diff] [blame] | 96 | static struct bdb_block *find_section(struct context *context, int section_id) |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 97 | { |
Jani Nikula | 76a0462 | 2016-05-02 18:33:19 +0300 | [diff] [blame] | 98 | const struct bdb_header *bdb = context->bdb; |
| 99 | int length = context->size; |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 100 | struct bdb_block *block; |
Jani Nikula | b263934 | 2016-01-14 16:08:55 +0200 | [diff] [blame] | 101 | const uint8_t *base = (const uint8_t *)bdb; |
Jani Nikula | d9588c8 | 2016-01-14 15:48:13 +0200 | [diff] [blame] | 102 | int index = 0; |
| 103 | uint32_t total, current_size; |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 104 | unsigned char current_id; |
| 105 | |
| 106 | /* skip to first section */ |
Jani Nikula | d9588c8 | 2016-01-14 15:48:13 +0200 | [diff] [blame] | 107 | index += bdb->header_size; |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 108 | total = bdb->bdb_size; |
Chris Wilson | 1ffe6b0 | 2012-01-25 10:11:49 +0000 | [diff] [blame] | 109 | if (total > length) |
| 110 | total = length; |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 111 | |
| 112 | block = malloc(sizeof(*block)); |
| 113 | if (!block) { |
| 114 | fprintf(stderr, "out of memory\n"); |
Jani Nikula | 1dd3ff0 | 2016-05-12 15:35:37 +0300 | [diff] [blame] | 115 | exit(EXIT_FAILURE); |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 116 | } |
| 117 | |
| 118 | /* walk the sections looking for section_id */ |
Jani Nikula | d9588c8 | 2016-01-14 15:48:13 +0200 | [diff] [blame] | 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) |
Chris Wilson | 1ffe6b0 | 2012-01-25 10:11:49 +0000 | [diff] [blame] | 125 | return NULL; |
| 126 | |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 127 | if (current_id == section_id) { |
| 128 | block->id = current_id; |
| 129 | block->size = current_size; |
Jani Nikula | d9588c8 | 2016-01-14 15:48:13 +0200 | [diff] [blame] | 130 | block->data = base + index; |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 131 | return block; |
| 132 | } |
Chris Wilson | 1ffe6b0 | 2012-01-25 10:11:49 +0000 | [diff] [blame] | 133 | |
Jani Nikula | d9588c8 | 2016-01-14 15:48:13 +0200 | [diff] [blame] | 134 | index += current_size; |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 135 | } |
| 136 | |
| 137 | free(block); |
| 138 | return NULL; |
| 139 | } |
| 140 | |
Jani Nikula | 76a0462 | 2016-05-02 18:33:19 +0300 | [diff] [blame] | 141 | static void dump_general_features(struct context *context, |
Jani Nikula | 2e2fffa | 2016-01-14 15:27:50 +0200 | [diff] [blame] | 142 | const struct bdb_block *block) |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 143 | { |
Jani Nikula | b263934 | 2016-01-14 16:08:55 +0200 | [diff] [blame] | 144 | const struct bdb_general_features *features = block->data; |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 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)); |
Ville Syrjälä | cdee980 | 2016-02-29 20:31:05 +0200 | [diff] [blame] | 165 | |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 166 | printf("\tExternal VBT: %s\n", YESNO(features->download_ext_vbt)); |
| 167 | printf("\tEnable SSC: %s\n", YESNO(features->enable_ssc)); |
Zhenyu Wang | 581205d | 2010-06-03 10:31:04 +0800 | [diff] [blame] | 168 | if (features->enable_ssc) { |
Jani Nikula | b6ccc55 | 2016-05-12 14:02:05 +0300 | [diff] [blame] | 169 | if (!context->devid) |
Jani Nikula | 4d4b1c2 | 2016-05-02 18:15:55 +0300 | [diff] [blame] | 170 | printf("\tSSC frequency: <unknown platform>\n"); |
Jani Nikula | b6ccc55 | 2016-05-12 14:02:05 +0300 | [diff] [blame] | 171 | else if (IS_VALLEYVIEW(context->devid) || |
| 172 | IS_CHERRYVIEW(context->devid) || |
| 173 | IS_BROXTON(context->devid)) |
Imre Deak | 1dc4884 | 2015-03-31 20:32:29 +0300 | [diff] [blame] | 174 | printf("\tSSC frequency: 100 MHz\n"); |
Jani Nikula | b6ccc55 | 2016-05-12 14:02:05 +0300 | [diff] [blame] | 175 | else if (HAS_PCH_SPLIT(context->devid)) |
Zhenyu Wang | 581205d | 2010-06-03 10:31:04 +0800 | [diff] [blame] | 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 | } |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 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)); |
Ville Syrjälä | cdee980 | 2016-02-29 20:31:05 +0200 | [diff] [blame] | 186 | printf("\tUnderscan support for VGA timings: %s\n", |
| 187 | YESNO(features->underscan_vga_timings)); |
| 188 | if (context->bdb->version >= 183) |
Jani Nikula | 09f35ea | 2017-08-25 15:56:19 +0300 | [diff] [blame] | 189 | printf("\tDynamic CD clock: %s\n", YESNO(features->display_clock_mode)); |
Ville Syrjälä | cdee980 | 2016-02-29 20:31:05 +0200 | [diff] [blame] | 190 | printf("\tHotplug support in VBIOS: %s\n", |
| 191 | YESNO(features->vbios_hotplug_support)); |
| 192 | |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 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)); |
Ville Syrjälä | cdee980 | 2016-02-29 20:31:05 +0200 | [diff] [blame] | 196 | if (context->bdb->version >= 181) |
| 197 | printf("\tEnable 180 degree rotation: %s\n", YESNO(features->rotate_180)); |
Jani Nikula | 09f35ea | 2017-08-25 15:56:19 +0300 | [diff] [blame] | 198 | printf("\tInverted FDI Rx polarity: %s\n", YESNO(features->fdi_rx_polarity_inverted)); |
Ville Syrjälä | cdee980 | 2016-02-29 20:31:05 +0200 | [diff] [blame] | 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 | |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 206 | printf("\tLegacy monitor detect: %s\n", |
| 207 | YESNO(features->legacy_monitor_detect)); |
Ville Syrjälä | cdee980 | 2016-02-29 20:31:05 +0200 | [diff] [blame] | 208 | |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 209 | printf("\tIntegrated CRT: %s\n", YESNO(features->int_crt_support)); |
| 210 | printf("\tIntegrated TV: %s\n", YESNO(features->int_tv_support)); |
Ville Syrjälä | cdee980 | 2016-02-29 20:31:05 +0200 | [diff] [blame] | 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)); |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 225 | } |
| 226 | |
Jani Nikula | 76a0462 | 2016-05-02 18:33:19 +0300 | [diff] [blame] | 227 | static void dump_backlight_info(struct context *context, |
Jani Nikula | 2e2fffa | 2016-01-14 15:27:50 +0200 | [diff] [blame] | 228 | const struct bdb_block *block) |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 229 | { |
Jani Nikula | 2cbcc0b | 2017-08-28 15:13:40 +0300 | [diff] [blame] | 230 | const struct bdb_lfp_backlight_data *backlight = block->data; |
| 231 | const struct bdb_lfp_backlight_data_entry *blc; |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 232 | |
Jani Nikula | 2cbcc0b | 2017-08-28 15:13:40 +0300 | [diff] [blame] | 233 | if (sizeof(*blc) != backlight->entry_size) { |
Chris Wilson | 592b1a5 | 2011-02-10 11:00:49 +0000 | [diff] [blame] | 234 | printf("\tBacklight struct sizes don't match (expected %zu, got %u), skipping\n", |
Jani Nikula | 2cbcc0b | 2017-08-28 15:13:40 +0300 | [diff] [blame] | 235 | sizeof(*blc), backlight->entry_size); |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 236 | return; |
| 237 | } |
| 238 | |
Jani Nikula | 2cbcc0b | 2017-08-28 15:13:40 +0300 | [diff] [blame] | 239 | blc = &backlight->data[context->panel_type]; |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 240 | |
Jani Nikula | 2cbcc0b | 2017-08-28 15:13:40 +0300 | [diff] [blame] | 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); |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 244 | printf("\tMinimum brightness: %d\n", blc->min_brightness); |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 245 | } |
| 246 | |
Adam Jackson | a52cbcb | 2010-04-22 15:37:49 -0400 | [diff] [blame] | 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" }, |
Adam Jackson | a52cbcb | 2010-04-22 15:37:49 -0400 | [diff] [blame] | 278 | { DEVICE_TYPE_DP, "DisplayPort" }, |
Jani Nikula | 09f35ea | 2017-08-25 15:56:19 +0300 | [diff] [blame] | 279 | { DEVICE_TYPE_DP_DUAL_MODE, "DisplayPort/HDMI/DVI" }, |
Jesse Barnes | 3225630 | 2010-12-21 12:06:00 -0800 | [diff] [blame] | 280 | { DEVICE_TYPE_DP_DVI, "DisplayPort/DVI" }, |
Jani Nikula | 09f35ea | 2017-08-25 15:56:19 +0300 | [diff] [blame] | 281 | { DEVICE_TYPE_HDMI, "HDMI/DVI" }, |
Jesse Barnes | 3225630 | 2010-12-21 12:06:00 -0800 | [diff] [blame] | 282 | { DEVICE_TYPE_DVI, "DVI" }, |
Adam Jackson | a52cbcb | 2010-04-22 15:37:49 -0400 | [diff] [blame] | 283 | { DEVICE_TYPE_eDP, "eDP" }, |
Ville Syrjälä | 2155d1e | 2015-09-11 15:27:32 +0300 | [diff] [blame] | 284 | { DEVICE_TYPE_MIPI, "MIPI" }, |
Adam Jackson | a52cbcb | 2010-04-22 15:37:49 -0400 | [diff] [blame] | 285 | }; |
| 286 | static const int num_child_device_types = |
| 287 | sizeof(child_device_types) / sizeof(child_device_types[0]); |
| 288 | |
| 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 | |
Jani Nikula | 3b163c4 | 2017-08-28 15:07:35 +0300 | [diff] [blame] | 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" }, |
Adam Jackson | 51b2ce5 | 2017-12-15 14:59:36 -0500 | [diff] [blame] | 313 | { DEVICE_TYPE_HIGH_SPEED_LINK, "High speed link" }, |
| 314 | { DEVICE_TYPE_LVDS_SIGNALING, "LVDS signaling" }, |
Jani Nikula | 3b163c4 | 2017-08-28 15:07:35 +0300 | [diff] [blame] | 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" }, |
Ville Syrjälä | d8313c3 | 2015-09-11 15:01:16 +0300 | [diff] [blame] | 320 | }; |
| 321 | |
| 322 | static void dump_child_device_type_bits(uint16_t type) |
| 323 | { |
Jani Nikula | 3b163c4 | 2017-08-28 15:07:35 +0300 | [diff] [blame] | 324 | int i; |
Ville Syrjälä | d8313c3 | 2015-09-11 15:01:16 +0300 | [diff] [blame] | 325 | |
Jani Nikula | 3b163c4 | 2017-08-28 15:07:35 +0300 | [diff] [blame] | 326 | type ^= DEVICE_TYPE_NOT_HDMI_OUTPUT; |
Ville Syrjälä | d8313c3 | 2015-09-11 15:01:16 +0300 | [diff] [blame] | 327 | |
Jani Nikula | 3b163c4 | 2017-08-28 15:07:35 +0300 | [diff] [blame] | 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); |
Ville Syrjälä | d8313c3 | 2015-09-11 15:01:16 +0300 | [diff] [blame] | 331 | } |
| 332 | } |
| 333 | |
Jesse Barnes | 3225630 | 2010-12-21 12:06:00 -0800 | [diff] [blame] | 334 | static const struct { |
Ville Syrjälä | a023052 | 2015-09-11 14:47:59 +0300 | [diff] [blame] | 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 | |
| 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 | |
Jani Nikula | 48bf7bc | 2017-09-21 15:08:11 +0300 | [diff] [blame] | 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", |
Jesse Barnes | 3225630 | 2010-12-21 12:06:00 -0800 | [diff] [blame] | 378 | }; |
Jesse Barnes | 3225630 | 2010-12-21 12:06:00 -0800 | [diff] [blame] | 379 | |
Jani Nikula | 48bf7bc | 2017-09-21 15:08:11 +0300 | [diff] [blame] | 380 | static const char *dvo_port(uint8_t type) |
Jesse Barnes | 3225630 | 2010-12-21 12:06:00 -0800 | [diff] [blame] | 381 | { |
Jani Nikula | 48bf7bc | 2017-09-21 15:08:11 +0300 | [diff] [blame] | 382 | if (type < ARRAY_SIZE(dvo_port_names) && dvo_port_names[type]) |
| 383 | return dvo_port_names[type]; |
| 384 | else |
| 385 | return "unknown"; |
Jesse Barnes | 3225630 | 2010-12-21 12:06:00 -0800 | [diff] [blame] | 386 | } |
| 387 | |
Jani Nikula | 7e4cd23 | 2017-09-21 16:44:55 +0300 | [diff] [blame] | 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 | |
Ville Syrjälä | cc41f4c | 2017-10-30 16:38:46 +0200 | [diff] [blame] | 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 | |
Jani Nikula | 76a0462 | 2016-05-02 18:33:19 +0300 | [diff] [blame] | 422 | static void dump_child_device(struct context *context, |
Chris Wilson | dc3fcd9 | 2016-11-30 19:37:37 +0000 | [diff] [blame] | 423 | const struct child_device_config *child) |
Adam Jackson | a52cbcb | 2010-04-22 15:37:49 -0400 | [diff] [blame] | 424 | { |
Adam Jackson | a52cbcb | 2010-04-22 15:37:49 -0400 | [diff] [blame] | 425 | if (!child->device_type) |
| 426 | return; |
| 427 | |
Jani Nikula | 1b4478c | 2017-09-21 16:57:57 +0300 | [diff] [blame] | 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 | |
Jani Nikula | 76a0462 | 2016-05-02 18:33:19 +0300 | [diff] [blame] | 435 | if (context->bdb->version < 152) { |
Jani Nikula | ee7a0fe | 2017-09-21 16:28:48 +0300 | [diff] [blame] | 436 | printf("\t\tSignature: %.*s\n", (int)sizeof(child->device_id), child->device_id); |
Jani Nikula | 1b4478c | 2017-09-21 16:57:57 +0300 | [diff] [blame] | 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); |
Ville Syrjälä | cc41f4c | 2017-10-30 16:38:46 +0200 | [diff] [blame] | 442 | dump_hmdi_max_data_rate(child->hdmi_max_data_rate); |
Jani Nikula | 1b4478c | 2017-09-21 16:57:57 +0300 | [diff] [blame] | 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)); |
Ville Syrjälä | 86a546f | 2016-02-29 21:35:39 +0200 | [diff] [blame] | 450 | } |
| 451 | |
Jani Nikula | 1b4478c | 2017-09-21 16:57:57 +0300 | [diff] [blame] | 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 | |
Jani Nikula | 1b4478c | 2017-09-21 16:57:57 +0300 | [diff] [blame] | 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 | |
Ville Syrjälä | 86a546f | 2016-02-29 21:35:39 +0200 | [diff] [blame] | 495 | if (context->bdb->version >= 195) { |
Jani Nikula | 1b4478c | 2017-09-21 16:57:57 +0300 | [diff] [blame] | 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); |
Ville Syrjälä | 86a546f | 2016-02-29 21:35:39 +0200 | [diff] [blame] | 499 | } |
| 500 | |
| 501 | if (context->bdb->version >= 196) { |
Jani Nikula | 1b4478c | 2017-09-21 16:57:57 +0300 | [diff] [blame] | 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); |
Jesse Barnes | 3225630 | 2010-12-21 12:06:00 -0800 | [diff] [blame] | 504 | } |
Adam Jackson | a52cbcb | 2010-04-22 15:37:49 -0400 | [diff] [blame] | 505 | } |
| 506 | |
Jani Nikula | 9ba736a | 2017-09-27 16:24:31 +0300 | [diff] [blame] | 507 | |
| 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 | |
Jani Nikula | 76a0462 | 2016-05-02 18:33:19 +0300 | [diff] [blame] | 531 | static void dump_general_definitions(struct context *context, |
Jani Nikula | 2e2fffa | 2016-01-14 15:27:50 +0200 | [diff] [blame] | 532 | const struct bdb_block *block) |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 533 | { |
Jani Nikula | b263934 | 2016-01-14 16:08:55 +0200 | [diff] [blame] | 534 | const struct bdb_general_definitions *defs = block->data; |
Jani Nikula | 9ba736a | 2017-09-27 16:24:31 +0300 | [diff] [blame] | 535 | int child_dev_num; |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 536 | |
Jani Nikula | 743cbb0 | 2017-10-20 16:07:01 +0300 | [diff] [blame] | 537 | child_dev_num = (block->size - sizeof(*defs)) / defs->child_dev_size; |
| 538 | |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 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]); |
Ville Syrjälä | b1e7564 | 2015-03-25 13:36:52 +0200 | [diff] [blame] | 547 | printf("\tChild device size: %d\n", defs->child_dev_size); |
Jani Nikula | 743cbb0 | 2017-10-20 16:07:01 +0300 | [diff] [blame] | 548 | printf("\tChild device count: %d\n", child_dev_num); |
Jani Nikula | da4b9fe | 2017-08-29 11:34:04 +0300 | [diff] [blame] | 549 | |
Jani Nikula | 9ba736a | 2017-09-27 16:24:31 +0300 | [diff] [blame] | 550 | dump_child_devices(context, defs->devices, |
| 551 | child_dev_num, defs->child_dev_size); |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 552 | } |
| 553 | |
Jani Nikula | dff8b30 | 2017-08-25 12:30:20 +0300 | [diff] [blame] | 554 | static void dump_legacy_child_devices(struct context *context, |
| 555 | const struct bdb_block *block) |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 556 | { |
Jani Nikula | d1f8db5 | 2017-09-27 17:53:02 +0300 | [diff] [blame] | 557 | const struct bdb_legacy_child_devices *defs = block->data; |
Jani Nikula | 9ba736a | 2017-09-27 16:24:31 +0300 | [diff] [blame] | 558 | int child_dev_num; |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 559 | |
Jani Nikula | 9ba736a | 2017-09-27 16:24:31 +0300 | [diff] [blame] | 560 | child_dev_num = (block->size - sizeof(*defs)) / defs->child_dev_size; |
Jani Nikula | 743cbb0 | 2017-10-20 16:07:01 +0300 | [diff] [blame] | 561 | |
| 562 | printf("\tChild device size: %d\n", defs->child_dev_size); |
| 563 | printf("\tChild device count: %d\n", child_dev_num); |
| 564 | |
Jani Nikula | 9ba736a | 2017-09-27 16:24:31 +0300 | [diff] [blame] | 565 | dump_child_devices(context, defs->devices, |
| 566 | child_dev_num, defs->child_dev_size); |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 567 | } |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 568 | |
Jani Nikula | 76a0462 | 2016-05-02 18:33:19 +0300 | [diff] [blame] | 569 | static void dump_lvds_options(struct context *context, |
Jani Nikula | 2e2fffa | 2016-01-14 15:27:50 +0200 | [diff] [blame] | 570 | const struct bdb_block *block) |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 571 | { |
Jani Nikula | b263934 | 2016-01-14 16:08:55 +0200 | [diff] [blame] | 572 | const struct bdb_lvds_options *options = block->data; |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 573 | |
Jani Nikula | 21467dc | 2016-05-03 12:07:30 +0300 | [diff] [blame] | 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); |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 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); |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 587 | } |
| 588 | |
Jani Nikula | 76a0462 | 2016-05-02 18:33:19 +0300 | [diff] [blame] | 589 | static void dump_lvds_ptr_data(struct context *context, |
Jani Nikula | 2e2fffa | 2016-01-14 15:27:50 +0200 | [diff] [blame] | 590 | const struct bdb_block *block) |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 591 | { |
Jani Nikula | b263934 | 2016-01-14 16:08:55 +0200 | [diff] [blame] | 592 | const struct bdb_lvds_lfp_data_ptrs *ptrs = block->data; |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 593 | |
Jani Nikula | a4180df | 2013-10-08 21:15:27 +0300 | [diff] [blame] | 594 | printf("\tNumber of entries: %d\n", ptrs->lvds_entries); |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 595 | } |
| 596 | |
Jani Nikula | 76a0462 | 2016-05-02 18:33:19 +0300 | [diff] [blame] | 597 | static void dump_lvds_data(struct context *context, |
Jani Nikula | 2e2fffa | 2016-01-14 15:27:50 +0200 | [diff] [blame] | 598 | const struct bdb_block *block) |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 599 | { |
Jani Nikula | b263934 | 2016-01-14 16:08:55 +0200 | [diff] [blame] | 600 | const struct bdb_lvds_lfp_data *lvds_data = block->data; |
Jani Nikula | 17ae0a6 | 2016-05-03 11:52:12 +0300 | [diff] [blame] | 601 | struct bdb_block *ptrs_block; |
| 602 | const struct bdb_lvds_lfp_data_ptrs *ptrs; |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 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 | |
Jani Nikula | 17ae0a6 | 2016-05-03 11:52:12 +0300 | [diff] [blame] | 610 | ptrs_block = find_section(context, BDB_LVDS_LFP_DATA_PTRS); |
| 611 | if (!ptrs_block) { |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 612 | printf("No LVDS ptr block\n"); |
| 613 | return; |
| 614 | } |
Jani Nikula | a4180df | 2013-10-08 21:15:27 +0300 | [diff] [blame] | 615 | |
Jani Nikula | 17ae0a6 | 2016-05-03 11:52:12 +0300 | [diff] [blame] | 616 | ptrs = ptrs_block->data; |
| 617 | |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 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; |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 622 | |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 623 | num_entries = block->size / lfp_data_size; |
| 624 | |
Jani Nikula | a4180df | 2013-10-08 21:15:27 +0300 | [diff] [blame] | 625 | printf(" Number of entries: %d (preferred block marked with '*')\n", |
| 626 | num_entries); |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 627 | |
| 628 | for (i = 0; i < num_entries; i++) { |
Jani Nikula | b263934 | 2016-01-14 16:08:55 +0200 | [diff] [blame] | 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 bdb_lvds_lfp_data_entry *lfp_data = |
| 633 | (const struct bdb_lvds_lfp_data_entry *)lfp_data_ptr; |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 634 | char marker; |
| 635 | |
Jani Nikula | 96647f1 | 2016-05-03 12:36:32 +0300 | [diff] [blame] | 636 | if (i != context->panel_type && !context->dump_all_panel_types) |
| 637 | continue; |
| 638 | |
Jani Nikula | 3a81cf5 | 2016-05-03 11:44:32 +0300 | [diff] [blame] | 639 | if (i == context->panel_type) |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 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 | } |
Jani Nikula | 17ae0a6 | 2016-05-03 11:52:12 +0300 | [diff] [blame] | 675 | |
| 676 | free(ptrs_block); |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 677 | } |
| 678 | |
Jani Nikula | 76a0462 | 2016-05-02 18:33:19 +0300 | [diff] [blame] | 679 | static void dump_driver_feature(struct context *context, |
Jani Nikula | 2e2fffa | 2016-01-14 15:27:50 +0200 | [diff] [blame] | 680 | const struct bdb_block *block) |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 681 | { |
Jani Nikula | 09f35ea | 2017-08-25 15:56:19 +0300 | [diff] [blame] | 682 | const struct bdb_driver_features *feature = block->data; |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 683 | |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 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); |
Dhinakaran Pandiyan | cffe915 | 2018-05-08 17:48:55 -0700 | [diff] [blame] | 744 | printf("\tEnable DRRS: %s\n", YESNO(feature->drrs_enabled)); |
| 745 | printf("\tEnable PSR: %s\n", YESNO(feature->psr_enabled)); |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 746 | } |
| 747 | |
Jani Nikula | 76a0462 | 2016-05-02 18:33:19 +0300 | [diff] [blame] | 748 | static void dump_edp(struct context *context, |
Jani Nikula | 2e2fffa | 2016-01-14 15:27:50 +0200 | [diff] [blame] | 749 | const struct bdb_block *block) |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 750 | { |
Jani Nikula | b263934 | 2016-01-14 16:08:55 +0200 | [diff] [blame] | 751 | const struct bdb_edp *edp = block->data; |
Jani Nikula | 419d053 | 2013-10-08 21:15:29 +0300 | [diff] [blame] | 752 | int bpp, msa; |
| 753 | int i; |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 754 | |
Jani Nikula | 419d053 | 2013-10-08 21:15:29 +0300 | [diff] [blame] | 755 | for (i = 0; i < 16; i++) { |
Jani Nikula | 96647f1 | 2016-05-03 12:36:32 +0300 | [diff] [blame] | 756 | if (i != context->panel_type && !context->dump_all_panel_types) |
| 757 | continue; |
| 758 | |
Jani Nikula | 3a81cf5 | 2016-05-03 11:44:32 +0300 | [diff] [blame] | 759 | printf("\tPanel %d%s\n", i, context->panel_type == i ? " *" : ""); |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 760 | |
Jani Nikula | 419d053 | 2013-10-08 21:15:29 +0300 | [diff] [blame] | 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); |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 767 | |
Jani Nikula | 419d053 | 2013-10-08 21:15:29 +0300 | [diff] [blame] | 768 | bpp = (edp->color_depth >> (i * 2)) & 3; |
Jani Nikula | a4180df | 2013-10-08 21:15:27 +0300 | [diff] [blame] | 769 | |
Jani Nikula | 419d053 | 2013-10-08 21:15:29 +0300 | [diff] [blame] | 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 | |
Ville Syrjälä | 2ed42d3 | 2016-06-21 17:52:37 +0300 | [diff] [blame] | 789 | printf("\t\tFast link params:\n"); |
Jani Nikula | 419d053 | 2013-10-08 21:15:29 +0300 | [diff] [blame] | 790 | printf("\t\t\trate: "); |
Ville Syrjälä | 2ed42d3 | 2016-06-21 17:52:37 +0300 | [diff] [blame] | 791 | if (edp->fast_link_params[i].rate == EDP_RATE_1_62) |
Jani Nikula | 419d053 | 2013-10-08 21:15:29 +0300 | [diff] [blame] | 792 | printf("1.62G\n"); |
Ville Syrjälä | 2ed42d3 | 2016-06-21 17:52:37 +0300 | [diff] [blame] | 793 | else if (edp->fast_link_params[i].rate == EDP_RATE_2_7) |
Jani Nikula | 419d053 | 2013-10-08 21:15:29 +0300 | [diff] [blame] | 794 | printf("2.7G\n"); |
| 795 | printf("\t\t\tlanes: "); |
Ville Syrjälä | 2ed42d3 | 2016-06-21 17:52:37 +0300 | [diff] [blame] | 796 | switch (edp->fast_link_params[i].lanes) { |
Jani Nikula | 419d053 | 2013-10-08 21:15:29 +0300 | [diff] [blame] | 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", |
Ville Syrjälä | 2ed42d3 | 2016-06-21 17:52:37 +0300 | [diff] [blame] | 808 | edp->fast_link_params[i].lanes); |
Jani Nikula | 419d053 | 2013-10-08 21:15:29 +0300 | [diff] [blame] | 809 | break; |
| 810 | } |
| 811 | printf("\t\t\tpre-emphasis: "); |
Ville Syrjälä | 2ed42d3 | 2016-06-21 17:52:37 +0300 | [diff] [blame] | 812 | switch (edp->fast_link_params[i].preemphasis) { |
Jani Nikula | 419d053 | 2013-10-08 21:15:29 +0300 | [diff] [blame] | 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", |
Ville Syrjälä | 2ed42d3 | 2016-06-21 17:52:37 +0300 | [diff] [blame] | 827 | edp->fast_link_params[i].preemphasis); |
Jani Nikula | 419d053 | 2013-10-08 21:15:29 +0300 | [diff] [blame] | 828 | break; |
| 829 | } |
| 830 | printf("\t\t\tvswing: "); |
Ville Syrjälä | 2ed42d3 | 2016-06-21 17:52:37 +0300 | [diff] [blame] | 831 | switch (edp->fast_link_params[i].vswing) { |
Jani Nikula | 419d053 | 2013-10-08 21:15:29 +0300 | [diff] [blame] | 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", |
Ville Syrjälä | 2ed42d3 | 2016-06-21 17:52:37 +0300 | [diff] [blame] | 846 | edp->fast_link_params[i].vswing); |
Jani Nikula | 419d053 | 2013-10-08 21:15:29 +0300 | [diff] [blame] | 847 | break; |
| 848 | } |
Ville Syrjälä | 2ed42d3 | 2016-06-21 17:52:37 +0300 | [diff] [blame] | 849 | |
| 850 | if (context->bdb->version >= 162) { |
Jani Nikula | 66d88e6 | 2017-08-25 17:15:43 +0300 | [diff] [blame] | 851 | bool val = (edp->edp_s3d_feature >> i) & 1; |
Ville Syrjälä | 2ed42d3 | 2016-06-21 17:52:37 +0300 | [diff] [blame] | 852 | printf("\t\tStereo 3D feature: %s\n", YESNO(val)); |
| 853 | } |
| 854 | |
| 855 | if (context->bdb->version >= 165) { |
Jani Nikula | 66d88e6 | 2017-08-25 17:15:43 +0300 | [diff] [blame] | 856 | bool val = (edp->edp_t3_optimization >> i) & 1; |
Ville Syrjälä | 2ed42d3 | 2016-06-21 17:52:37 +0300 | [diff] [blame] | 857 | printf("\t\tT3 optimization: %s\n", YESNO(val)); |
| 858 | } |
| 859 | |
| 860 | if (context->bdb->version >= 173) { |
Jani Nikula | 66d88e6 | 2017-08-25 17:15:43 +0300 | [diff] [blame] | 861 | int val = (edp->edp_vswing_preemph >> (i * 4)) & 0xf; |
Ville Syrjälä | 2ed42d3 | 2016-06-21 17:52:37 +0300 | [diff] [blame] | 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 | } |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 939 | } |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 940 | } |
| 941 | |
Ville Syrjälä | 8e4ce75 | 2016-09-12 13:34:53 +0300 | [diff] [blame] | 942 | static void dump_psr(struct context *context, |
| 943 | const struct bdb_block *block) |
| 944 | { |
Jani Nikula | e1db4c4 | 2017-08-25 16:10:53 +0300 | [diff] [blame] | 945 | const struct bdb_psr *psr_block = block->data; |
Ville Syrjälä | 8e4ce75 | 2016-09-12 13:34:53 +0300 | [diff] [blame] | 946 | 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 Nikula | e1db4c4 | 2017-08-25 16:10:53 +0300 | [diff] [blame] | 953 | const struct psr_table *psr = &psr_block->psr_table[i]; |
| 954 | |
Ville Syrjälä | 8e4ce75 | 2016-09-12 13:34:53 +0300 | [diff] [blame] | 955 | 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 Nikula | e1db4c4 | 2017-08-25 16:10:53 +0300 | [diff] [blame] | 960 | 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ä | 8e4ce75 | 2016-09-12 13:34:53 +0300 | [diff] [blame] | 962 | |
Jani Nikula | e1db4c4 | 2017-08-25 16:10:53 +0300 | [diff] [blame] | 963 | switch (psr->lines_to_wait) { |
Ville Syrjälä | 8e4ce75 | 2016-09-12 13:34:53 +0300 | [diff] [blame] | 964 | case 0: |
| 965 | case 1: |
| 966 | printf("\t\tLines to wait before link standby: %d\n", |
Jani Nikula | e1db4c4 | 2017-08-25 16:10:53 +0300 | [diff] [blame] | 967 | psr->lines_to_wait); |
Ville Syrjälä | 8e4ce75 | 2016-09-12 13:34:53 +0300 | [diff] [blame] | 968 | break; |
| 969 | case 2: |
| 970 | case 3: |
| 971 | printf("\t\tLines to wait before link standby: %d\n", |
Jani Nikula | e1db4c4 | 2017-08-25 16:10:53 +0300 | [diff] [blame] | 972 | 1 << psr->lines_to_wait); |
Ville Syrjälä | 8e4ce75 | 2016-09-12 13:34:53 +0300 | [diff] [blame] | 973 | break; |
| 974 | default: |
| 975 | printf("\t\tLines to wait before link standby: (unknown) (0x%x)\n", |
Jani Nikula | e1db4c4 | 2017-08-25 16:10:53 +0300 | [diff] [blame] | 976 | psr->lines_to_wait); |
Ville Syrjälä | 8e4ce75 | 2016-09-12 13:34:53 +0300 | [diff] [blame] | 977 | break; |
| 978 | } |
| 979 | |
| 980 | printf("\t\tIdle frames to for PSR enable: %d\n", |
Jani Nikula | e1db4c4 | 2017-08-25 16:10:53 +0300 | [diff] [blame] | 981 | psr->idle_frames); |
Ville Syrjälä | 8e4ce75 | 2016-09-12 13:34:53 +0300 | [diff] [blame] | 982 | |
| 983 | printf("\t\tTP1 wakeup time: %d usec (0x%x)\n", |
Jani Nikula | e1db4c4 | 2017-08-25 16:10:53 +0300 | [diff] [blame] | 984 | psr->tp1_wakeup_time * 100, |
| 985 | psr->tp1_wakeup_time); |
Ville Syrjälä | 8e4ce75 | 2016-09-12 13:34:53 +0300 | [diff] [blame] | 986 | |
| 987 | printf("\t\tTP2/TP3 wakeup time: %d usec (0x%x)\n", |
Jani Nikula | e1db4c4 | 2017-08-25 16:10:53 +0300 | [diff] [blame] | 988 | psr->tp2_tp3_wakeup_time * 100, |
| 989 | psr->tp2_tp3_wakeup_time); |
Ville Syrjälä | 8e4ce75 | 2016-09-12 13:34:53 +0300 | [diff] [blame] | 990 | } |
| 991 | } |
| 992 | |
Chris Wilson | 281285e | 2011-01-29 16:12:38 +0000 | [diff] [blame] | 993 | static void |
Jani Nikula | 25a7117 | 2017-08-25 13:41:05 +0300 | [diff] [blame] | 994 | print_detail_timing_data(const struct lvds_dvo_timing *dvo_timing) |
Chris Wilson | 281285e | 2011-01-29 16:12:38 +0000 | [diff] [blame] | 995 | { |
| 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 Nikula | ef52ae2 | 2017-08-25 13:51:25 +0300 | [diff] [blame] | 1001 | sync_end = sync_start + ((dvo_timing->hsync_pulse_width_hi << 8) | |
| 1002 | dvo_timing->hsync_pulse_width_lo); |
Chris Wilson | 281285e | 2011-01-29 16:12:38 +0000 | [diff] [blame] | 1003 | 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 Nikula | ef52ae2 | 2017-08-25 13:51:25 +0300 | [diff] [blame] | 1011 | 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 Wilson | 281285e | 2011-01-29 16:12:38 +0000 | [diff] [blame] | 1015 | 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 Nikula | 76a0462 | 2016-05-02 18:33:19 +0300 | [diff] [blame] | 1025 | static void dump_sdvo_panel_dtds(struct context *context, |
Jani Nikula | 2e2fffa | 2016-01-14 15:27:50 +0200 | [diff] [blame] | 1026 | const struct bdb_block *block) |
Chris Wilson | 281285e | 2011-01-29 16:12:38 +0000 | [diff] [blame] | 1027 | { |
Jani Nikula | 25a7117 | 2017-08-25 13:41:05 +0300 | [diff] [blame] | 1028 | const struct lvds_dvo_timing *dvo_timing = block->data; |
Chris Wilson | 281285e | 2011-01-29 16:12:38 +0000 | [diff] [blame] | 1029 | int n, count; |
| 1030 | |
Jani Nikula | 25a7117 | 2017-08-25 13:41:05 +0300 | [diff] [blame] | 1031 | count = block->size / sizeof(struct lvds_dvo_timing); |
Chris Wilson | 281285e | 2011-01-29 16:12:38 +0000 | [diff] [blame] | 1032 | for (n = 0; n < count; n++) { |
| 1033 | printf("%d:\n", n); |
| 1034 | print_detail_timing_data(dvo_timing++); |
| 1035 | } |
Chris Wilson | 281285e | 2011-01-29 16:12:38 +0000 | [diff] [blame] | 1036 | } |
| 1037 | |
Jani Nikula | 76a0462 | 2016-05-02 18:33:19 +0300 | [diff] [blame] | 1038 | static void dump_sdvo_lvds_options(struct context *context, |
Jani Nikula | 2e2fffa | 2016-01-14 15:27:50 +0200 | [diff] [blame] | 1039 | const struct bdb_block *block) |
Chris Wilson | 281285e | 2011-01-29 16:12:38 +0000 | [diff] [blame] | 1040 | { |
Jani Nikula | b263934 | 2016-01-14 16:08:55 +0200 | [diff] [blame] | 1041 | const struct bdb_sdvo_lvds_options *options = block->data; |
Chris Wilson | 281285e | 2011-01-29 16:12:38 +0000 | [diff] [blame] | 1042 | |
Chris Wilson | 281285e | 2011-01-29 16:12:38 +0000 | [diff] [blame] | 1043 | 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 Wilson | 281285e | 2011-01-29 16:12:38 +0000 | [diff] [blame] | 1058 | } |
| 1059 | |
Jani Nikula | 76a0462 | 2016-05-02 18:33:19 +0300 | [diff] [blame] | 1060 | static void dump_mipi_config(struct context *context, |
Jani Nikula | 2e2fffa | 2016-01-14 15:27:50 +0200 | [diff] [blame] | 1061 | const struct bdb_block *block) |
Gaurav K Singh | 525044b | 2014-07-16 19:39:32 +0530 | [diff] [blame] | 1062 | { |
Jani Nikula | b263934 | 2016-01-14 16:08:55 +0200 | [diff] [blame] | 1063 | const struct bdb_mipi_config *start = block->data; |
| 1064 | const struct mipi_config *config; |
| 1065 | const struct mipi_pps_data *pps; |
Gaurav K Singh | 525044b | 2014-07-16 19:39:32 +0530 | [diff] [blame] | 1066 | |
Jani Nikula | 3a81cf5 | 2016-05-03 11:44:32 +0300 | [diff] [blame] | 1067 | config = &start->config[context->panel_type]; |
| 1068 | pps = &start->pps[context->panel_type]; |
Gaurav K Singh | 525044b | 2014-07-16 19:39:32 +0530 | [diff] [blame] | 1069 | |
| 1070 | printf("\tGeneral Param\n"); |
| 1071 | printf("\t\t BTA disable: %s\n", config->bta ? "Disabled" : "Enabled"); |
Ville Syrjälä | 835f3d1 | 2018-10-19 15:36:48 +0300 | [diff] [blame] | 1072 | printf("\t\t Panel Rotation: %d degrees\n", config->rotation * 90); |
Gaurav K Singh | 525044b | 2014-07-16 19:39:32 +0530 | [diff] [blame] | 1073 | |
| 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 Singh | 525044b | 2014-07-16 19:39:32 +0530 | [diff] [blame] | 1087 | printf("\t\t Mode: %s\n", config->cmd_mode ? "COMMAND" : "VIDEO"); |
Ville Syrjälä | d07a3c8 | 2016-12-13 17:40:03 +0200 | [diff] [blame] | 1088 | 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 Singh | 525044b | 2014-07-16 19:39:32 +0530 | [diff] [blame] | 1093 | 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ä | d07a3c8 | 2016-12-13 17:40:03 +0200 | [diff] [blame] | 1096 | printf("\t\t Pixel overlap: %d\n", config->pixel_overlap); |
Gaurav K Singh | 525044b | 2014-07-16 19:39:32 +0530 | [diff] [blame] | 1097 | 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 Kahola | fe7a42b | 2016-01-15 10:24:55 +0200 | [diff] [blame] | 1148 | printf("\t\tPanel power on to Backlight enable delay: %d\n", pps->bl_enable_delay); |
Gaurav K Singh | 525044b | 2014-07-16 19:39:32 +0530 | [diff] [blame] | 1149 | 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 Nikula | 9c4aa07 | 2015-12-21 16:18:20 +0200 | [diff] [blame] | 1154 | static const uint8_t *mipi_dump_send_packet(const uint8_t *data) |
Gaurav K Singh | ac31f19 | 2014-07-16 19:39:33 +0530 | [diff] [blame] | 1155 | { |
Jani Nikula | cb89add | 2015-12-21 16:36:32 +0200 | [diff] [blame] | 1156 | uint8_t flags, type; |
| 1157 | uint16_t len, i; |
Gaurav K Singh | ac31f19 | 2014-07-16 19:39:33 +0530 | [diff] [blame] | 1158 | |
Jani Nikula | cb89add | 2015-12-21 16:36:32 +0200 | [diff] [blame] | 1159 | flags = *data++; |
Gaurav K Singh | ac31f19 | 2014-07-16 19:39:33 +0530 | [diff] [blame] | 1160 | type = *data++; |
Chris Wilson | dc3fcd9 | 2016-11-30 19:37:37 +0000 | [diff] [blame] | 1161 | len = *((const uint16_t *) data); |
Gaurav K Singh | ac31f19 | 2014-07-16 19:39:33 +0530 | [diff] [blame] | 1162 | data += 2; |
Jani Nikula | cb89add | 2015-12-21 16:36:32 +0200 | [diff] [blame] | 1163 | |
| 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 Singh | ac31f19 | 2014-07-16 19:39:33 +0530 | [diff] [blame] | 1172 | printf("\n"); |
Jani Nikula | cb89add | 2015-12-21 16:36:32 +0200 | [diff] [blame] | 1173 | |
Gaurav K Singh | ac31f19 | 2014-07-16 19:39:33 +0530 | [diff] [blame] | 1174 | return data; |
| 1175 | } |
| 1176 | |
Jani Nikula | 9c4aa07 | 2015-12-21 16:18:20 +0200 | [diff] [blame] | 1177 | static const uint8_t *mipi_dump_delay(const uint8_t *data) |
Gaurav K Singh | ac31f19 | 2014-07-16 19:39:33 +0530 | [diff] [blame] | 1178 | { |
Jani Nikula | cb89add | 2015-12-21 16:36:32 +0200 | [diff] [blame] | 1179 | printf("\t\tDelay: %u us\n", *((const uint32_t *)data)); |
| 1180 | |
| 1181 | return data + 4; |
Gaurav K Singh | ac31f19 | 2014-07-16 19:39:33 +0530 | [diff] [blame] | 1182 | } |
| 1183 | |
Jani Nikula | 9c4aa07 | 2015-12-21 16:18:20 +0200 | [diff] [blame] | 1184 | static const uint8_t *mipi_dump_gpio(const uint8_t *data) |
Gaurav K Singh | ac31f19 | 2014-07-16 19:39:33 +0530 | [diff] [blame] | 1185 | { |
Jani Nikula | cb89add | 2015-12-21 16:36:32 +0200 | [diff] [blame] | 1186 | uint8_t index, flags; |
Gaurav K Singh | ac31f19 | 2014-07-16 19:39:33 +0530 | [diff] [blame] | 1187 | |
Jani Nikula | cb89add | 2015-12-21 16:36:32 +0200 | [diff] [blame] | 1188 | index = *data++; |
| 1189 | flags = *data++; |
Gaurav K Singh | ac31f19 | 2014-07-16 19:39:33 +0530 | [diff] [blame] | 1190 | |
Jani Nikula | cb89add | 2015-12-21 16:36:32 +0200 | [diff] [blame] | 1191 | printf("\t\tGPIO index %u, source %d, set %d\n", |
| 1192 | index, |
| 1193 | (flags >> 1) & 3, |
| 1194 | flags & 1); |
| 1195 | |
Gaurav K Singh | ac31f19 | 2014-07-16 19:39:33 +0530 | [diff] [blame] | 1196 | return data; |
| 1197 | } |
| 1198 | |
Jani Nikula | 9764247 | 2015-12-21 16:50:47 +0200 | [diff] [blame] | 1199 | static 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 Wilson | dc3fcd9 | 2016-11-30 19:37:37 +0000 | [diff] [blame] | 1207 | address = *((const uint16_t *) data); |
Jani Nikula | 9764247 | 2015-12-21 16:50:47 +0200 | [diff] [blame] | 1208 | 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 Nikula | 9c4aa07 | 2015-12-21 16:18:20 +0200 | [diff] [blame] | 1221 | typedef const uint8_t * (*fn_mipi_elem_dump)(const uint8_t *data); |
Gaurav K Singh | ac31f19 | 2014-07-16 19:39:33 +0530 | [diff] [blame] | 1222 | |
| 1223 | static const fn_mipi_elem_dump dump_elem[] = { |
Jani Nikula | 9c4aa07 | 2015-12-21 16:18:20 +0200 | [diff] [blame] | 1224 | [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 Nikula | 9764247 | 2015-12-21 16:50:47 +0200 | [diff] [blame] | 1227 | [MIPI_SEQ_ELEM_I2C] = mipi_dump_i2c, |
Gaurav K Singh | ac31f19 | 2014-07-16 19:39:33 +0530 | [diff] [blame] | 1228 | }; |
| 1229 | |
Jani Nikula | 9c4aa07 | 2015-12-21 16:18:20 +0200 | [diff] [blame] | 1230 | static 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 | |
| 1244 | static const char *sequence_name(enum mipi_seq seq_id) |
Gaurav K Singh | ac31f19 | 2014-07-16 19:39:33 +0530 | [diff] [blame] | 1245 | { |
Jani Nikula | 9c4aa07 | 2015-12-21 16:18:20 +0200 | [diff] [blame] | 1246 | if (seq_id < ARRAY_SIZE(seq_name) && seq_name[seq_id]) |
| 1247 | return seq_name[seq_id]; |
| 1248 | else |
| 1249 | return "(unknown)"; |
Gaurav K Singh | ac31f19 | 2014-07-16 19:39:33 +0530 | [diff] [blame] | 1250 | } |
| 1251 | |
Jani Nikula | 480479d | 2016-01-14 17:43:06 +0200 | [diff] [blame] | 1252 | static const uint8_t *dump_sequence(const uint8_t *data, uint8_t seq_version) |
Gaurav K Singh | ac31f19 | 2014-07-16 19:39:33 +0530 | [diff] [blame] | 1253 | { |
Jani Nikula | 9c4aa07 | 2015-12-21 16:18:20 +0200 | [diff] [blame] | 1254 | fn_mipi_elem_dump mipi_elem_dump; |
Gaurav K Singh | ac31f19 | 2014-07-16 19:39:33 +0530 | [diff] [blame] | 1255 | |
Jani Nikula | 9c4aa07 | 2015-12-21 16:18:20 +0200 | [diff] [blame] | 1256 | printf("\tSequence %u - %s\n", *data, sequence_name(*data)); |
Gaurav K Singh | ac31f19 | 2014-07-16 19:39:33 +0530 | [diff] [blame] | 1257 | |
Jani Nikula | 9c4aa07 | 2015-12-21 16:18:20 +0200 | [diff] [blame] | 1258 | /* Skip Sequence Byte. */ |
Gaurav K Singh | ac31f19 | 2014-07-16 19:39:33 +0530 | [diff] [blame] | 1259 | data++; |
Jani Nikula | 9c4aa07 | 2015-12-21 16:18:20 +0200 | [diff] [blame] | 1260 | |
Jani Nikula | 480479d | 2016-01-14 17:43:06 +0200 | [diff] [blame] | 1261 | /* Skip Size of Sequence. */ |
| 1262 | if (seq_version >= 3) |
| 1263 | data += 4; |
| 1264 | |
Gaurav K Singh | ac31f19 | 2014-07-16 19:39:33 +0530 | [diff] [blame] | 1265 | while (1) { |
Jani Nikula | 9c4aa07 | 2015-12-21 16:18:20 +0200 | [diff] [blame] | 1266 | uint8_t operation_byte = *data++; |
Jani Nikula | 480479d | 2016-01-14 17:43:06 +0200 | [diff] [blame] | 1267 | uint8_t operation_size = 0; |
Gaurav K Singh | ac31f19 | 2014-07-16 19:39:33 +0530 | [diff] [blame] | 1268 | |
Jani Nikula | 9c4aa07 | 2015-12-21 16:18:20 +0200 | [diff] [blame] | 1269 | if (operation_byte == MIPI_SEQ_ELEM_END) |
Gaurav K Singh | ac31f19 | 2014-07-16 19:39:33 +0530 | [diff] [blame] | 1270 | break; |
Gaurav K Singh | ac31f19 | 2014-07-16 19:39:33 +0530 | [diff] [blame] | 1271 | |
Jani Nikula | 480479d | 2016-01-14 17:43:06 +0200 | [diff] [blame] | 1272 | if (operation_byte < ARRAY_SIZE(dump_elem)) |
Jani Nikula | 9c4aa07 | 2015-12-21 16:18:20 +0200 | [diff] [blame] | 1273 | mipi_elem_dump = dump_elem[operation_byte]; |
| 1274 | else |
| 1275 | mipi_elem_dump = NULL; |
Gaurav K Singh | ac31f19 | 2014-07-16 19:39:33 +0530 | [diff] [blame] | 1276 | |
Jani Nikula | 480479d | 2016-01-14 17:43:06 +0200 | [diff] [blame] | 1277 | /* Size of Operation. */ |
| 1278 | if (seq_version >= 3) |
| 1279 | operation_size = *data++; |
| 1280 | |
Jani Nikula | 9c4aa07 | 2015-12-21 16:18:20 +0200 | [diff] [blame] | 1281 | if (mipi_elem_dump) { |
| 1282 | data = mipi_elem_dump(data); |
Jani Nikula | 480479d | 2016-01-14 17:43:06 +0200 | [diff] [blame] | 1283 | } else if (operation_size) { |
| 1284 | /* We have size, skip. */ |
| 1285 | data += operation_size; |
Jani Nikula | 9c4aa07 | 2015-12-21 16:18:20 +0200 | [diff] [blame] | 1286 | } else { |
Jani Nikula | 480479d | 2016-01-14 17:43:06 +0200 | [diff] [blame] | 1287 | /* No size, can't skip without parsing. */ |
Jani Nikula | 9c4aa07 | 2015-12-21 16:18:20 +0200 | [diff] [blame] | 1288 | printf("Error: Unsupported MIPI element %u\n", |
| 1289 | operation_byte); |
Gaurav K Singh | ac31f19 | 2014-07-16 19:39:33 +0530 | [diff] [blame] | 1290 | return NULL; |
Jani Nikula | 9c4aa07 | 2015-12-21 16:18:20 +0200 | [diff] [blame] | 1291 | } |
| 1292 | } |
Gaurav K Singh | ac31f19 | 2014-07-16 19:39:33 +0530 | [diff] [blame] | 1293 | |
Gaurav K Singh | ac31f19 | 2014-07-16 19:39:33 +0530 | [diff] [blame] | 1294 | return data; |
| 1295 | } |
| 1296 | |
Jani Nikula | 7d1a372 | 2016-01-14 16:24:11 +0200 | [diff] [blame] | 1297 | /* Find the sequence block and size for the given panel. */ |
| 1298 | static const uint8_t * |
| 1299 | find_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 Nikula | 70dc8c8 | 2016-01-14 16:41:53 +0200 | [diff] [blame] | 1345 | static 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 | |
| 1383 | static 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 Nikula | 76a0462 | 2016-05-02 18:33:19 +0300 | [diff] [blame] | 1452 | static void dump_mipi_sequence(struct context *context, |
Jani Nikula | 2e2fffa | 2016-01-14 15:27:50 +0200 | [diff] [blame] | 1453 | const struct bdb_block *block) |
Gaurav K Singh | ac31f19 | 2014-07-16 19:39:33 +0530 | [diff] [blame] | 1454 | { |
Jani Nikula | b263934 | 2016-01-14 16:08:55 +0200 | [diff] [blame] | 1455 | const struct bdb_mipi_sequence *sequence = block->data; |
Jani Nikula | 9c4aa07 | 2015-12-21 16:18:20 +0200 | [diff] [blame] | 1456 | const uint8_t *data; |
Jani Nikula | 7d1a372 | 2016-01-14 16:24:11 +0200 | [diff] [blame] | 1457 | uint32_t seq_size; |
Jani Nikula | 480479d | 2016-01-14 17:43:06 +0200 | [diff] [blame] | 1458 | int index = 0, i; |
| 1459 | const uint8_t *sequence_ptrs[MIPI_SEQ_MAX] = {}; |
Gaurav K Singh | ac31f19 | 2014-07-16 19:39:33 +0530 | [diff] [blame] | 1460 | |
| 1461 | /* Check if we have sequence block as well */ |
| 1462 | if (!sequence) { |
| 1463 | printf("No MIPI Sequence found\n"); |
| 1464 | return; |
| 1465 | } |
| 1466 | |
Jani Nikula | 68cfe4b | 2015-12-21 15:51:10 +0200 | [diff] [blame] | 1467 | printf("\tSequence block version v%u\n", sequence->version); |
| 1468 | |
Jani Nikula | 70dc8c8 | 2016-01-14 16:41:53 +0200 | [diff] [blame] | 1469 | /* 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 Nikula | 68cfe4b | 2015-12-21 15:51:10 +0200 | [diff] [blame] | 1473 | return; |
Jani Nikula | 70dc8c8 | 2016-01-14 16:41:53 +0200 | [diff] [blame] | 1474 | } |
Jani Nikula | 68cfe4b | 2015-12-21 15:51:10 +0200 | [diff] [blame] | 1475 | |
Jani Nikula | 3a81cf5 | 2016-05-03 11:44:32 +0300 | [diff] [blame] | 1476 | data = find_panel_sequence_block(sequence, context->panel_type, |
Jani Nikula | 7d1a372 | 2016-01-14 16:24:11 +0200 | [diff] [blame] | 1477 | block->size, &seq_size); |
| 1478 | if (!data) |
Gaurav K Singh | ac31f19 | 2014-07-16 19:39:33 +0530 | [diff] [blame] | 1479 | return; |
Gaurav K Singh | ac31f19 | 2014-07-16 19:39:33 +0530 | [diff] [blame] | 1480 | |
Jani Nikula | 70dc8c8 | 2016-01-14 16:41:53 +0200 | [diff] [blame] | 1481 | /* 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 Nikula | 480479d | 2016-01-14 17:43:06 +0200 | [diff] [blame] | 1492 | sequence_ptrs[seq_id] = data + index; |
| 1493 | |
Jani Nikula | 70dc8c8 | 2016-01-14 16:41:53 +0200 | [diff] [blame] | 1494 | 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 Nikula | 480479d | 2016-01-14 17:43:06 +0200 | [diff] [blame] | 1504 | /* 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 Singh | ac31f19 | 2014-07-16 19:39:33 +0530 | [diff] [blame] | 1508 | } |
| 1509 | |
Jani Nikula | 21467dc | 2016-05-03 12:07:30 +0300 | [diff] [blame] | 1510 | /* get panel type from lvds options block, or -1 if block not found */ |
| 1511 | static 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 Jackson | 4f12d8a | 2010-09-08 14:39:12 -0400 | [diff] [blame] | 1529 | static int |
Ville Syrjälä | b701bb1 | 2015-03-25 20:23:30 +0200 | [diff] [blame] | 1530 | get_device_id(unsigned char *bios, int size) |
Adam Jackson | 4f12d8a | 2010-09-08 14:39:12 -0400 | [diff] [blame] | 1531 | { |
| 1532 | int device; |
| 1533 | int offset = (bios[0x19] << 8) + bios[0x18]; |
| 1534 | |
Ville Syrjälä | b701bb1 | 2015-03-25 20:23:30 +0200 | [diff] [blame] | 1535 | if (offset + 7 >= size) |
| 1536 | return -1; |
| 1537 | |
Adam Jackson | 4f12d8a | 2010-09-08 14:39:12 -0400 | [diff] [blame] | 1538 | 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 Nikula | a4180df | 2013-10-08 21:15:27 +0300 | [diff] [blame] | 1549 | struct dumper { |
| 1550 | uint8_t id; |
| 1551 | const char *name; |
Jani Nikula | 76a0462 | 2016-05-02 18:33:19 +0300 | [diff] [blame] | 1552 | void (*dump)(struct context *context, |
Jani Nikula | 2e2fffa | 2016-01-14 15:27:50 +0200 | [diff] [blame] | 1553 | const struct bdb_block *block); |
Jani Nikula | a4180df | 2013-10-08 21:15:27 +0300 | [diff] [blame] | 1554 | }; |
| 1555 | |
| 1556 | struct 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 Nikula | dff8b30 | 2017-08-25 12:30:20 +0300 | [diff] [blame] | 1569 | .name = "Legacy child devices block", |
| 1570 | .dump = dump_legacy_child_devices, |
Jani Nikula | a4180df | 2013-10-08 21:15:27 +0300 | [diff] [blame] | 1571 | }, |
| 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 Singh | 525044b | 2014-07-16 19:39:32 +0530 | [diff] [blame] | 1612 | { |
Ville Syrjälä | 8e4ce75 | 2016-09-12 13:34:53 +0300 | [diff] [blame] | 1613 | .id = BDB_PSR, |
| 1614 | .name = "PSR block", |
| 1615 | .dump = dump_psr, |
| 1616 | }, |
| 1617 | { |
Gaurav K Singh | 525044b | 2014-07-16 19:39:32 +0530 | [diff] [blame] | 1618 | .id = BDB_MIPI_CONFIG, |
| 1619 | .name = "MIPI configuration block", |
| 1620 | .dump = dump_mipi_config, |
| 1621 | }, |
Gaurav K Singh | ac31f19 | 2014-07-16 19:39:33 +0530 | [diff] [blame] | 1622 | { |
| 1623 | .id = BDB_MIPI_SEQUENCE, |
| 1624 | .name = "MIPI sequence block", |
| 1625 | .dump = dump_mipi_sequence, |
| 1626 | }, |
Jani Nikula | a4180df | 2013-10-08 21:15:27 +0300 | [diff] [blame] | 1627 | }; |
| 1628 | |
Jani Nikula | 295cd2c | 2017-01-24 11:48:55 +0200 | [diff] [blame] | 1629 | static void hex_dump(const void *data, uint32_t size) |
Jani Nikula | a4180df | 2013-10-08 21:15:27 +0300 | [diff] [blame] | 1630 | { |
| 1631 | int i; |
Jani Nikula | 295cd2c | 2017-01-24 11:48:55 +0200 | [diff] [blame] | 1632 | const uint8_t *p = data; |
Jani Nikula | a4180df | 2013-10-08 21:15:27 +0300 | [diff] [blame] | 1633 | |
Jani Nikula | 295cd2c | 2017-01-24 11:48:55 +0200 | [diff] [blame] | 1634 | for (i = 0; i < size; i++) { |
Jani Nikula | a4180df | 2013-10-08 21:15:27 +0300 | [diff] [blame] | 1635 | if (i % 16 == 0) |
| 1636 | printf("\t%04x: ", i); |
| 1637 | printf("%02x", p[i]); |
| 1638 | if (i % 16 == 15) { |
Jani Nikula | 295cd2c | 2017-01-24 11:48:55 +0200 | [diff] [blame] | 1639 | if (i + 1 < size) |
Jani Nikula | a4180df | 2013-10-08 21:15:27 +0300 | [diff] [blame] | 1640 | printf("\n"); |
| 1641 | } else if (i % 8 == 7) { |
| 1642 | printf(" "); |
| 1643 | } else { |
| 1644 | printf(" "); |
| 1645 | } |
| 1646 | } |
| 1647 | printf("\n\n"); |
| 1648 | } |
| 1649 | |
Jani Nikula | 295cd2c | 2017-01-24 11:48:55 +0200 | [diff] [blame] | 1650 | static void hex_dump_block(const struct bdb_block *block) |
| 1651 | { |
| 1652 | hex_dump(block->data, block->size); |
| 1653 | } |
| 1654 | |
Jani Nikula | 1c33231 | 2016-05-03 12:26:22 +0300 | [diff] [blame] | 1655 | static bool dump_section(struct context *context, int section_id) |
Jani Nikula | a4180df | 2013-10-08 21:15:27 +0300 | [diff] [blame] | 1656 | { |
| 1657 | struct dumper *dumper = NULL; |
Jani Nikula | b4f96db | 2016-05-03 12:48:38 +0300 | [diff] [blame] | 1658 | struct bdb_block *block; |
Jani Nikula | a4180df | 2013-10-08 21:15:27 +0300 | [diff] [blame] | 1659 | int i; |
| 1660 | |
Jani Nikula | 76a0462 | 2016-05-02 18:33:19 +0300 | [diff] [blame] | 1661 | block = find_section(context, section_id); |
Jani Nikula | a360e39 | 2013-10-08 21:15:28 +0300 | [diff] [blame] | 1662 | if (!block) |
Jani Nikula | 1c33231 | 2016-05-03 12:26:22 +0300 | [diff] [blame] | 1663 | return false; |
Jani Nikula | a4180df | 2013-10-08 21:15:27 +0300 | [diff] [blame] | 1664 | |
| 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 Nikula | 56cbe6b | 2017-01-24 12:07:01 +0200 | [diff] [blame] | 1675 | printf("BDB block %d - Unknown, no decoding available:\n", |
| 1676 | block->id); |
Jani Nikula | a4180df | 2013-10-08 21:15:27 +0300 | [diff] [blame] | 1677 | |
Jani Nikula | b0a8b08 | 2016-05-03 12:17:16 +0300 | [diff] [blame] | 1678 | if (context->hexdump) |
Jani Nikula | 295cd2c | 2017-01-24 11:48:55 +0200 | [diff] [blame] | 1679 | hex_dump_block(block); |
Jani Nikula | a4180df | 2013-10-08 21:15:27 +0300 | [diff] [blame] | 1680 | if (dumper && dumper->dump) |
Jani Nikula | 76a0462 | 2016-05-02 18:33:19 +0300 | [diff] [blame] | 1681 | dumper->dump(context, block); |
Jani Nikula | a4180df | 2013-10-08 21:15:27 +0300 | [diff] [blame] | 1682 | printf("\n"); |
Jani Nikula | 1c33231 | 2016-05-03 12:26:22 +0300 | [diff] [blame] | 1683 | |
Jani Nikula | b4f96db | 2016-05-03 12:48:38 +0300 | [diff] [blame] | 1684 | free(block); |
| 1685 | |
Jani Nikula | 1c33231 | 2016-05-03 12:26:22 +0300 | [diff] [blame] | 1686 | return true; |
Jani Nikula | a4180df | 2013-10-08 21:15:27 +0300 | [diff] [blame] | 1687 | } |
| 1688 | |
Jani Nikula | 37bd27f | 2017-10-20 16:24:50 +0300 | [diff] [blame] | 1689 | /* print a description of the VBT of the form <bdb-version>-<vbt-signature> */ |
| 1690 | static 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 Nikula | f482e23 | 2016-05-12 14:28:50 +0300 | [diff] [blame] | 1716 | static void dump_headers(struct context *context) |
| 1717 | { |
Jani Nikula | 4daac35 | 2016-05-12 15:25:13 +0300 | [diff] [blame] | 1718 | const struct vbt_header *vbt = context->vbt; |
| 1719 | const struct bdb_header *bdb = context->bdb; |
| 1720 | int i, j = 0; |
Jani Nikula | f482e23 | 2016-05-12 14:28:50 +0300 | [diff] [blame] | 1721 | |
Jani Nikula | 42b80a1 | 2017-01-24 11:56:25 +0200 | [diff] [blame] | 1722 | printf("VBT header:\n"); |
Jani Nikula | cb55d6c | 2017-01-24 11:59:06 +0200 | [diff] [blame] | 1723 | if (context->hexdump) |
| 1724 | hex_dump(vbt, vbt->header_size); |
Jani Nikula | f482e23 | 2016-05-12 14:28:50 +0300 | [diff] [blame] | 1725 | |
Jani Nikula | 311e75d | 2017-01-24 12:20:27 +0200 | [diff] [blame] | 1726 | printf("\tVBT signature:\t\t\"%.*s\"\n", |
Jani Nikula | 42b80a1 | 2017-01-24 11:56:25 +0200 | [diff] [blame] | 1727 | (int)sizeof(vbt->signature), vbt->signature); |
Jani Nikula | 311e75d | 2017-01-24 12:20:27 +0200 | [diff] [blame] | 1728 | 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 Nikula | 42b80a1 | 2017-01-24 11:56:25 +0200 | [diff] [blame] | 1736 | printf("\n"); |
| 1737 | |
| 1738 | printf("BDB header:\n"); |
Jani Nikula | cb55d6c | 2017-01-24 11:59:06 +0200 | [diff] [blame] | 1739 | if (context->hexdump) |
| 1740 | hex_dump(bdb, bdb->header_size); |
Jani Nikula | 42b80a1 | 2017-01-24 11:56:25 +0200 | [diff] [blame] | 1741 | |
Jani Nikula | 311e75d | 2017-01-24 12:20:27 +0200 | [diff] [blame] | 1742 | printf("\tBDB signature:\t\t\"%.*s\"\n", |
Jani Nikula | 4daac35 | 2016-05-12 15:25:13 +0300 | [diff] [blame] | 1743 | (int)sizeof(bdb->signature), bdb->signature); |
Jani Nikula | 311e75d | 2017-01-24 12:20:27 +0200 | [diff] [blame] | 1744 | 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 Nikula | 42b80a1 | 2017-01-24 11:56:25 +0200 | [diff] [blame] | 1748 | printf("\n"); |
Jani Nikula | f482e23 | 2016-05-12 14:28:50 +0300 | [diff] [blame] | 1749 | |
Jani Nikula | 4daac35 | 2016-05-12 15:25:13 +0300 | [diff] [blame] | 1750 | printf("BDB blocks present:"); |
Jani Nikula | f482e23 | 2016-05-12 14:28:50 +0300 | [diff] [blame] | 1751 | for (i = 0; i < 256; i++) { |
| 1752 | struct bdb_block *block; |
| 1753 | |
| 1754 | block = find_section(context, i); |
| 1755 | if (!block) |
| 1756 | continue; |
Jani Nikula | 4daac35 | 2016-05-12 15:25:13 +0300 | [diff] [blame] | 1757 | |
| 1758 | if (j++ % 16) |
| 1759 | printf(" %3d", i); |
| 1760 | else |
| 1761 | printf("\n\t%3d", i); |
| 1762 | |
Jani Nikula | f482e23 | 2016-05-12 14:28:50 +0300 | [diff] [blame] | 1763 | free(block); |
| 1764 | } |
Jani Nikula | 4daac35 | 2016-05-12 15:25:13 +0300 | [diff] [blame] | 1765 | printf("\n\n"); |
Jani Nikula | f482e23 | 2016-05-12 14:28:50 +0300 | [diff] [blame] | 1766 | } |
| 1767 | |
Jani Nikula | 8a06cc1 | 2016-05-03 11:29:43 +0300 | [diff] [blame] | 1768 | enum opt { |
| 1769 | OPT_UNKNOWN = '?', |
| 1770 | OPT_END = -1, |
| 1771 | OPT_FILE, |
Jani Nikula | 4d4b1c2 | 2016-05-02 18:15:55 +0300 | [diff] [blame] | 1772 | OPT_DEVID, |
Jani Nikula | 21467dc | 2016-05-03 12:07:30 +0300 | [diff] [blame] | 1773 | OPT_PANEL_TYPE, |
Jani Nikula | 96647f1 | 2016-05-03 12:36:32 +0300 | [diff] [blame] | 1774 | OPT_ALL_PANELS, |
Jani Nikula | b0a8b08 | 2016-05-03 12:17:16 +0300 | [diff] [blame] | 1775 | OPT_HEXDUMP, |
Jani Nikula | 1c33231 | 2016-05-03 12:26:22 +0300 | [diff] [blame] | 1776 | OPT_BLOCK, |
Marius Vlad | ec77945 | 2016-05-04 20:35:18 +0300 | [diff] [blame] | 1777 | OPT_USAGE, |
Jani Nikula | 7c8b863 | 2017-10-20 16:19:33 +0300 | [diff] [blame] | 1778 | OPT_HEADER, |
Jani Nikula | 37bd27f | 2017-10-20 16:24:50 +0300 | [diff] [blame] | 1779 | OPT_DESCRIBE, |
Jani Nikula | 8a06cc1 | 2016-05-03 11:29:43 +0300 | [diff] [blame] | 1780 | }; |
| 1781 | |
Marius Vlad | ec77945 | 2016-05-04 20:35:18 +0300 | [diff] [blame] | 1782 | static 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 Nikula | 7c8b863 | 2017-10-20 16:19:33 +0300 | [diff] [blame] | 1791 | " [--header]" |
Jani Nikula | 37bd27f | 2017-10-20 16:24:50 +0300 | [diff] [blame] | 1792 | " [--describe]" |
Marius Vlad | ec77945 | 2016-05-04 20:35:18 +0300 | [diff] [blame] | 1793 | " [--help]\n"); |
| 1794 | } |
| 1795 | |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 1796 | int main(int argc, char **argv) |
| 1797 | { |
Jani Nikula | 1272b9c | 2016-05-03 11:29:25 +0300 | [diff] [blame] | 1798 | uint8_t *VBIOS; |
Jani Nikula | 8a06cc1 | 2016-05-03 11:29:43 +0300 | [diff] [blame] | 1799 | int index; |
| 1800 | enum opt opt; |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 1801 | int fd; |
| 1802 | struct vbt_header *vbt = NULL; |
| 1803 | int vbt_off, bdb_off, i; |
Jani Nikula | 8a06cc1 | 2016-05-03 11:29:43 +0300 | [diff] [blame] | 1804 | const char *filename = NULL; |
| 1805 | const char *toolname = argv[0]; |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 1806 | struct stat finfo; |
Jani Nikula | 8596a4b | 2013-10-08 21:15:26 +0300 | [diff] [blame] | 1807 | int size; |
Jani Nikula | 21467dc | 2016-05-03 12:07:30 +0300 | [diff] [blame] | 1808 | struct context context = { |
| 1809 | .panel_type = -1, |
| 1810 | }; |
Jani Nikula | 4d4b1c2 | 2016-05-02 18:15:55 +0300 | [diff] [blame] | 1811 | char *endp; |
Jani Nikula | 1c33231 | 2016-05-03 12:26:22 +0300 | [diff] [blame] | 1812 | int block_number = -1; |
Jani Nikula | 37bd27f | 2017-10-20 16:24:50 +0300 | [diff] [blame] | 1813 | bool header_only = false, describe = false; |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 1814 | |
Jani Nikula | 8a06cc1 | 2016-05-03 11:29:43 +0300 | [diff] [blame] | 1815 | static struct option options[] = { |
| 1816 | { "file", required_argument, NULL, OPT_FILE }, |
Jani Nikula | 4d4b1c2 | 2016-05-02 18:15:55 +0300 | [diff] [blame] | 1817 | { "devid", required_argument, NULL, OPT_DEVID }, |
Jani Nikula | 21467dc | 2016-05-03 12:07:30 +0300 | [diff] [blame] | 1818 | { "panel-type", required_argument, NULL, OPT_PANEL_TYPE }, |
Jani Nikula | 96647f1 | 2016-05-03 12:36:32 +0300 | [diff] [blame] | 1819 | { "all-panels", no_argument, NULL, OPT_ALL_PANELS }, |
Jani Nikula | b0a8b08 | 2016-05-03 12:17:16 +0300 | [diff] [blame] | 1820 | { "hexdump", no_argument, NULL, OPT_HEXDUMP }, |
Jani Nikula | 1c33231 | 2016-05-03 12:26:22 +0300 | [diff] [blame] | 1821 | { "block", required_argument, NULL, OPT_BLOCK }, |
Jani Nikula | 7c8b863 | 2017-10-20 16:19:33 +0300 | [diff] [blame] | 1822 | { "header", no_argument, NULL, OPT_HEADER }, |
Jani Nikula | 37bd27f | 2017-10-20 16:24:50 +0300 | [diff] [blame] | 1823 | { "describe", no_argument, NULL, OPT_DESCRIBE }, |
Marius Vlad | ec77945 | 2016-05-04 20:35:18 +0300 | [diff] [blame] | 1824 | { "help", no_argument, NULL, OPT_USAGE }, |
Jani Nikula | 8a06cc1 | 2016-05-03 11:29:43 +0300 | [diff] [blame] | 1825 | { 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 Nikula | 4d4b1c2 | 2016-05-02 18:15:55 +0300 | [diff] [blame] | 1835 | case OPT_DEVID: |
Jani Nikula | b6ccc55 | 2016-05-12 14:02:05 +0300 | [diff] [blame] | 1836 | context.devid = strtoul(optarg, &endp, 16); |
| 1837 | if (!context.devid || *endp) { |
Jani Nikula | 4d4b1c2 | 2016-05-02 18:15:55 +0300 | [diff] [blame] | 1838 | fprintf(stderr, "invalid devid '%s'\n", optarg); |
| 1839 | return EXIT_FAILURE; |
| 1840 | } |
| 1841 | break; |
Jani Nikula | 21467dc | 2016-05-03 12:07:30 +0300 | [diff] [blame] | 1842 | 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 Nikula | 96647f1 | 2016-05-03 12:36:32 +0300 | [diff] [blame] | 1850 | case OPT_ALL_PANELS: |
| 1851 | context.dump_all_panel_types = true; |
| 1852 | break; |
Jani Nikula | b0a8b08 | 2016-05-03 12:17:16 +0300 | [diff] [blame] | 1853 | case OPT_HEXDUMP: |
| 1854 | context.hexdump = true; |
| 1855 | break; |
Jani Nikula | 1c33231 | 2016-05-03 12:26:22 +0300 | [diff] [blame] | 1856 | 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 Nikula | 7c8b863 | 2017-10-20 16:19:33 +0300 | [diff] [blame] | 1864 | case OPT_HEADER: |
| 1865 | header_only = true; |
| 1866 | break; |
Jani Nikula | 37bd27f | 2017-10-20 16:24:50 +0300 | [diff] [blame] | 1867 | case OPT_DESCRIBE: |
| 1868 | describe = true; |
| 1869 | break; |
Jani Nikula | 8a06cc1 | 2016-05-03 11:29:43 +0300 | [diff] [blame] | 1870 | case OPT_END: |
| 1871 | break; |
Marius Vlad | ec77945 | 2016-05-04 20:35:18 +0300 | [diff] [blame] | 1872 | case OPT_USAGE: /* fall-through */ |
Jani Nikula | 8a06cc1 | 2016-05-03 11:29:43 +0300 | [diff] [blame] | 1873 | case OPT_UNKNOWN: |
Marius Vlad | ec77945 | 2016-05-04 20:35:18 +0300 | [diff] [blame] | 1874 | usage(toolname); |
Jani Nikula | 8a06cc1 | 2016-05-03 11:29:43 +0300 | [diff] [blame] | 1875 | 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 Vlad | ec77945 | 2016-05-04 20:35:18 +0300 | [diff] [blame] | 1887 | usage(toolname); |
Jani Nikula | 8a06cc1 | 2016-05-03 11:29:43 +0300 | [diff] [blame] | 1888 | return EXIT_FAILURE; |
| 1889 | } |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 1890 | } |
| 1891 | |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 1892 | fd = open(filename, O_RDONLY); |
| 1893 | if (fd == -1) { |
Jani Nikula | 1dd3ff0 | 2016-05-12 15:35:37 +0300 | [diff] [blame] | 1894 | fprintf(stderr, "Couldn't open \"%s\": %s\n", |
| 1895 | filename, strerror(errno)); |
| 1896 | return EXIT_FAILURE; |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 1897 | } |
| 1898 | |
| 1899 | if (stat(filename, &finfo)) { |
Jani Nikula | 1dd3ff0 | 2016-05-12 15:35:37 +0300 | [diff] [blame] | 1900 | fprintf(stderr, "Failed to stat \"%s\": %s\n", |
| 1901 | filename, strerror(errno)); |
| 1902 | return EXIT_FAILURE; |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 1903 | } |
Jani Nikula | 8596a4b | 2013-10-08 21:15:26 +0300 | [diff] [blame] | 1904 | size = finfo.st_size; |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 1905 | |
Jani Nikula | 8596a4b | 2013-10-08 21:15:26 +0300 | [diff] [blame] | 1906 | if (size == 0) { |
Chris Wilson | 281285e | 2011-01-29 16:12:38 +0000 | [diff] [blame] | 1907 | int len = 0, ret; |
Jani Nikula | 8596a4b | 2013-10-08 21:15:26 +0300 | [diff] [blame] | 1908 | size = 8192; |
| 1909 | VBIOS = malloc (size); |
| 1910 | while ((ret = read(fd, VBIOS + len, size - len))) { |
Chris Wilson | 281285e | 2011-01-29 16:12:38 +0000 | [diff] [blame] | 1911 | if (ret < 0) { |
Jani Nikula | 1dd3ff0 | 2016-05-12 15:35:37 +0300 | [diff] [blame] | 1912 | fprintf(stderr, "Failed to read \"%s\": %s\n", |
| 1913 | filename, strerror(errno)); |
| 1914 | return EXIT_FAILURE; |
Chris Wilson | 281285e | 2011-01-29 16:12:38 +0000 | [diff] [blame] | 1915 | } |
| 1916 | |
| 1917 | len += ret; |
Jani Nikula | 8596a4b | 2013-10-08 21:15:26 +0300 | [diff] [blame] | 1918 | if (len == size) { |
| 1919 | size *= 2; |
| 1920 | VBIOS = realloc(VBIOS, size); |
Chris Wilson | 281285e | 2011-01-29 16:12:38 +0000 | [diff] [blame] | 1921 | } |
| 1922 | } |
| 1923 | } else { |
Jani Nikula | 8596a4b | 2013-10-08 21:15:26 +0300 | [diff] [blame] | 1924 | VBIOS = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); |
Chris Wilson | 281285e | 2011-01-29 16:12:38 +0000 | [diff] [blame] | 1925 | if (VBIOS == MAP_FAILED) { |
Jani Nikula | 1dd3ff0 | 2016-05-12 15:35:37 +0300 | [diff] [blame] | 1926 | fprintf(stderr, "Failed to map \"%s\": %s\n", |
| 1927 | filename, strerror(errno)); |
| 1928 | return EXIT_FAILURE; |
Chris Wilson | 281285e | 2011-01-29 16:12:38 +0000 | [diff] [blame] | 1929 | } |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 1930 | } |
| 1931 | |
| 1932 | /* Scour memory looking for the VBT signature */ |
Jani Nikula | 8596a4b | 2013-10-08 21:15:26 +0300 | [diff] [blame] | 1933 | for (i = 0; i + 4 < size; i++) { |
Chris Wilson | 281285e | 2011-01-29 16:12:38 +0000 | [diff] [blame] | 1934 | if (!memcmp(VBIOS + i, "$VBT", 4)) { |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 1935 | vbt_off = i; |
Chris Wilson | 281285e | 2011-01-29 16:12:38 +0000 | [diff] [blame] | 1936 | vbt = (struct vbt_header *)(VBIOS + i); |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 1937 | break; |
| 1938 | } |
| 1939 | } |
| 1940 | |
| 1941 | if (!vbt) { |
Jani Nikula | 1dd3ff0 | 2016-05-12 15:35:37 +0300 | [diff] [blame] | 1942 | fprintf(stderr, "VBT signature missing\n"); |
| 1943 | return EXIT_FAILURE; |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 1944 | } |
| 1945 | |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 1946 | bdb_off = vbt_off + vbt->bdb_offset; |
Jani Nikula | 8596a4b | 2013-10-08 21:15:26 +0300 | [diff] [blame] | 1947 | if (bdb_off >= size - sizeof(struct bdb_header)) { |
Jani Nikula | 1dd3ff0 | 2016-05-12 15:35:37 +0300 | [diff] [blame] | 1948 | fprintf(stderr, "Invalid VBT found, BDB points beyond end of data block\n"); |
| 1949 | return EXIT_FAILURE; |
Chris Wilson | 1ffe6b0 | 2012-01-25 10:11:49 +0000 | [diff] [blame] | 1950 | } |
| 1951 | |
Jani Nikula | f482e23 | 2016-05-12 14:28:50 +0300 | [diff] [blame] | 1952 | context.vbt = vbt; |
| 1953 | context.bdb = (const struct bdb_header *)(VBIOS + bdb_off); |
Jani Nikula | 76a0462 | 2016-05-02 18:33:19 +0300 | [diff] [blame] | 1954 | context.size = size; |
Jani Nikula | a4180df | 2013-10-08 21:15:27 +0300 | [diff] [blame] | 1955 | |
Jani Nikula | b6ccc55 | 2016-05-12 14:02:05 +0300 | [diff] [blame] | 1956 | if (!context.devid) { |
Jani Nikula | 4d4b1c2 | 2016-05-02 18:15:55 +0300 | [diff] [blame] | 1957 | const char *devid_string = getenv("DEVICE"); |
| 1958 | if (devid_string) |
Jani Nikula | b6ccc55 | 2016-05-12 14:02:05 +0300 | [diff] [blame] | 1959 | context.devid = strtoul(devid_string, NULL, 16); |
Jani Nikula | 4d4b1c2 | 2016-05-02 18:15:55 +0300 | [diff] [blame] | 1960 | } |
Jani Nikula | b6ccc55 | 2016-05-12 14:02:05 +0300 | [diff] [blame] | 1961 | if (!context.devid) |
| 1962 | context.devid = get_device_id(VBIOS, size); |
| 1963 | if (!context.devid) |
Jani Nikula | 4d4b1c2 | 2016-05-02 18:15:55 +0300 | [diff] [blame] | 1964 | fprintf(stderr, "Warning: could not find PCI device ID!\n"); |
Zhenyu Wang | 581205d | 2010-06-03 10:31:04 +0800 | [diff] [blame] | 1965 | |
Jani Nikula | 21467dc | 2016-05-03 12:07:30 +0300 | [diff] [blame] | 1966 | 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 Nikula | 37bd27f | 2017-10-20 16:24:50 +0300 | [diff] [blame] | 1973 | if (describe) { |
| 1974 | print_description(&context); |
| 1975 | } else if (header_only) { |
Jani Nikula | 7c8b863 | 2017-10-20 16:19:33 +0300 | [diff] [blame] | 1976 | dump_headers(&context); |
| 1977 | } else if (block_number != -1) { |
Jani Nikula | 1c33231 | 2016-05-03 12:26:22 +0300 | [diff] [blame] | 1978 | /* 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 Nikula | 4daac35 | 2016-05-12 15:25:13 +0300 | [diff] [blame] | 1984 | dump_headers(&context); |
| 1985 | |
Jani Nikula | 1c33231 | 2016-05-03 12:26:22 +0300 | [diff] [blame] | 1986 | /* dump all sections */ |
| 1987 | for (i = 0; i < 256; i++) |
| 1988 | dump_section(&context, i); |
| 1989 | } |
Jani Nikula | a360e39 | 2013-10-08 21:15:28 +0300 | [diff] [blame] | 1990 | |
Zhenyu Wang | 97ffee6 | 2010-01-12 14:04:43 +0800 | [diff] [blame] | 1991 | return 0; |
| 1992 | } |