summaryrefslogtreecommitdiff
path: root/tools/intel_vbt_decode.c
diff options
context:
space:
mode:
authorVille Syrjälä <ville.syrjala@linux.intel.com>2024-03-22 18:15:05 +0200
committerVille Syrjälä <ville.syrjala@linux.intel.com>2024-03-26 14:55:53 +0200
commit2d69518333bed6c2ec24402618ebe969e91f82e2 (patch)
tree477a79bf27050e593ba0e8f54ea29ae38dbb1400 /tools/intel_vbt_decode.c
parent486ef6fde89b2988643144dfe50155ec3fea46cb (diff)
tools/intel_vbt_decode: Optionally determine panel type from EDID
VBT may declare panel type as 255, which means we should match the EDID PnP ID against the panel entries in the VBT to determine the correct panel type. Implement support for this by allowing the user to optionally provide the EDID via a command like parameter. v2: Drop extra ' ' and some lefover debug junk (Jani) v3: s/0/NULL/ for mmap() s/ /_/ in usage() for consistency Reviewed-by: Jani Nikula <jani.nikula@intel.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
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);