summaryrefslogtreecommitdiff
path: root/tools/intel_vbt_decode.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/intel_vbt_decode.c')
-rw-r--r--tools/intel_vbt_decode.c91
1 files changed, 91 insertions, 0 deletions
diff --git a/tools/intel_vbt_decode.c b/tools/intel_vbt_decode.c
index 6ad74bd00..2b0847a79 100644
--- a/tools/intel_vbt_decode.c
+++ b/tools/intel_vbt_decode.c
@@ -84,6 +84,12 @@ struct context {
bool hexdump;
};
+struct edid {
+ uint8_t header[8];
+ struct lvds_pnp_id pnpid;
+ /* ... */
+} __packed;
+
static bool dump_panel(const struct context *context, int panel_type)
{
return panel_type == context->panel_type ||
@@ -2513,6 +2519,66 @@ static void dump_compression_parameters(struct context *context,
}
}
+static int get_panel_type_pnpid(const struct context *context,
+ const char *edid_file)
+{
+ struct bdb_block *ptrs_block, *data_block;
+ const struct bdb_lvds_lfp_data *data;
+ const struct bdb_lvds_lfp_data_ptrs *ptrs;
+ struct lvds_pnp_id edid_id, edid_id_nodate;
+ const struct edid *edid;
+ int fd, best = -1;
+
+ fd = open(edid_file, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "Unable to open EDID file %s\n", edid_file);
+ return -1;
+ }
+
+ edid = mmap(NULL, sizeof(*edid), PROT_READ, MAP_SHARED, fd, 0);
+ close(fd);
+ if (edid == MAP_FAILED) {
+ fprintf(stderr, "Unable to read EDID file %s\n", edid_file);
+ return -1;
+ }
+ edid_id = edid->pnpid;
+ munmap((void*)edid, sizeof(*edid));
+
+ edid_id_nodate = edid_id;
+ edid_id_nodate.mfg_week = 0;
+ edid_id_nodate.mfg_year = 0;
+
+ ptrs_block = find_section(context, BDB_LVDS_LFP_DATA_PTRS);
+ if (!ptrs_block)
+ return -1;
+
+ data_block = find_section(context, BDB_LVDS_LFP_DATA);
+ if (!data_block)
+ return -1;
+
+ ptrs = block_data(ptrs_block);
+ data = block_data(data_block);
+
+ for (int i = 0; i < 16; i++) {
+ const struct lvds_pnp_id *vbt_id =
+ (const void*)data + ptrs->ptr[i].panel_pnp_id.offset;
+
+ /* full match? */
+ if (!memcmp(vbt_id, &edid_id, sizeof(*vbt_id)))
+ return i;
+
+ /*
+ * Accept a match w/o date if no full match is found,
+ * and the VBT entry does not specify a date.
+ */
+ if (best < 0 &&
+ !memcmp(vbt_id, &edid_id_nodate, sizeof(*vbt_id)))
+ best = i;
+ }
+
+ return best;
+}
+
/* get panel type from lvds options block, or -1 if block not found */
static int get_panel_type(struct context *context, bool is_panel_type2)
{
@@ -2791,6 +2857,8 @@ enum opt {
OPT_DEVID,
OPT_PANEL_TYPE,
OPT_PANEL_TYPE2,
+ OPT_PANEL_EDID,
+ OPT_PANEL_EDID2,
OPT_ALL_PANELS,
OPT_HEXDUMP,
OPT_BLOCK,
@@ -2806,6 +2874,8 @@ static void usage(const char *toolname)
" [--devid=<device_id>]"
" [--panel-type=<panel_type>]"
" [--panel-type2=<panel_type>]"
+ " [--panel-edid=<edid_file>]"
+ " [--panel-edid2=<edid_file>]"
" [--all-panels]"
" [--hexdump]"
" [--block=<block_no>]"
@@ -2830,6 +2900,7 @@ int main(int argc, char **argv)
.panel_type = -1,
.panel_type2 = -1,
};
+ const char *panel_edid = NULL, *panel_edid2 = NULL;
char *endp;
int block_number = -1;
bool header_only = false, describe = false;
@@ -2838,7 +2909,9 @@ int main(int argc, char **argv)
{ "file", required_argument, NULL, OPT_FILE },
{ "devid", required_argument, NULL, OPT_DEVID },
{ "panel-type", required_argument, NULL, OPT_PANEL_TYPE },
+ { "panel-edid", required_argument, NULL, OPT_PANEL_EDID },
{ "panel-type2", required_argument, NULL, OPT_PANEL_TYPE2 },
+ { "panel-edid2", required_argument, NULL, OPT_PANEL_EDID2 },
{ "all-panels", no_argument, NULL, OPT_ALL_PANELS },
{ "hexdump", no_argument, NULL, OPT_HEXDUMP },
{ "block", required_argument, NULL, OPT_BLOCK },
@@ -2878,6 +2951,12 @@ int main(int argc, char **argv)
return EXIT_FAILURE;
}
break;
+ case OPT_PANEL_EDID:
+ panel_edid = optarg;
+ break;
+ case OPT_PANEL_EDID2:
+ panel_edid2 = optarg;
+ break;
case OPT_ALL_PANELS:
context.dump_all_panel_types = true;
break;
@@ -2996,6 +3075,12 @@ int main(int argc, char **argv)
if (context.panel_type == -1)
context.panel_type = get_panel_type(&context, false);
+ if (context.panel_type == 255 && !panel_edid) {
+ fprintf(stderr, "Warning: panel type depends on EDID (use --panel-edid), ignoring\n");
+ context.panel_type = -1;
+ } else if (context.panel_type == 255) {
+ context.panel_type = get_panel_type_pnpid(&context, panel_edid);
+ }
if (context.panel_type == -1) {
fprintf(stderr, "Warning: panel type not set, using 0\n");
context.panel_type = 0;
@@ -3003,6 +3088,12 @@ int main(int argc, char **argv)
if (context.panel_type2 == -1)
context.panel_type2 = get_panel_type(&context, true);
+ if (context.panel_type2 == 255 && !panel_edid2) {
+ fprintf(stderr, "Warning: panel type2 depends on EDID (use --panel-edid2), ignoring\n");
+ context.panel_type2 = -1;
+ } else if (context.panel_type2 == 255) {
+ context.panel_type2 = get_panel_type_pnpid(&context, panel_edid2);
+ }
if (context.panel_type2 != -1 && context.bdb->version < 212) {
fprintf(stderr, "Warning: panel type2 not valid for BDB version %d\n",
context.bdb->version);