summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tools/intel_vbt_decode.c128
1 files changed, 127 insertions, 1 deletions
diff --git a/tools/intel_vbt_decode.c b/tools/intel_vbt_decode.c
index 2ec99902..e45bab4a 100644
--- a/tools/intel_vbt_decode.c
+++ b/tools/intel_vbt_decode.c
@@ -189,6 +189,121 @@ static size_t lfp_data_min_size(const struct context *context)
return size;
}
+static const uint8_t *find_fp_timing_terminator(const uint8_t *data, int size)
+{
+ if (!data)
+ return NULL;
+
+ for (int i = 0; i < size - 1; i++) {
+ if (data[i] == 0xff && data[i+1] == 0xff)
+ return &data[i];
+ }
+
+ return NULL;
+}
+
+static int make_lvds_data_ptr(struct lvds_lfp_data_ptr_table *table,
+ int table_size, int total_size)
+{
+ if (total_size < table_size)
+ return total_size;
+
+ table->table_size = table_size;
+ table->offset = total_size - table_size;
+
+ return total_size - table_size;
+}
+
+static void next_lvds_data_ptr(struct lvds_lfp_data_ptr_table *next,
+ const struct lvds_lfp_data_ptr_table *prev,
+ int size)
+{
+ next->table_size = prev->table_size;
+ next->offset = prev->offset + size;
+}
+
+static void *generate_lvds_data_ptrs(const struct context *context)
+{
+ int size, table_size, block_size, offset;
+ const void *t0, *t1, *block;
+ struct bdb_lvds_lfp_data_ptrs *ptrs;
+ void *ptrs_block;
+
+ block = find_raw_section(context, BDB_LVDS_LFP_DATA);
+ if (!block)
+ return NULL;
+
+ block_size = get_blocksize(block);
+
+ size = block_size;
+ t0 = find_fp_timing_terminator(block, size);
+ if (!t0)
+ return NULL;
+
+ size -= t0 - block - 2;
+ t1 = find_fp_timing_terminator(t0 + 2, size);
+ if (!t1)
+ return NULL;
+
+ size = t1 - t0;
+ if (size * 16 > block_size)
+ return NULL;
+
+ ptrs_block = calloc(1, sizeof(*ptrs) + 3);
+ if (!ptrs_block)
+ return NULL;
+
+ *(uint8_t *)(ptrs_block + 0) = BDB_LVDS_LFP_DATA_PTRS;
+ *(uint16_t *)(ptrs_block + 1) = sizeof(*ptrs);
+ ptrs = ptrs_block + 3;
+
+ table_size = sizeof(struct lvds_pnp_id);
+ size = make_lvds_data_ptr(&ptrs->ptr[0].panel_pnp_id, table_size, size);
+
+ table_size = sizeof(struct lvds_dvo_timing);
+ size = make_lvds_data_ptr(&ptrs->ptr[0].dvo_timing, table_size, size);
+
+ table_size = t0 - block + 2;
+ size = make_lvds_data_ptr(&ptrs->ptr[0].fp_timing, table_size, size);
+
+ if (ptrs->ptr[0].fp_timing.table_size)
+ ptrs->lvds_entries++;
+ if (ptrs->ptr[0].dvo_timing.table_size)
+ ptrs->lvds_entries++;
+ if (ptrs->ptr[0].panel_pnp_id.table_size)
+ ptrs->lvds_entries++;
+
+ if (size != 0 || ptrs->lvds_entries != 3)
+ return NULL;
+
+ size = t1 - t0;
+ for (int i = 1; i < 16; i++) {
+ next_lvds_data_ptr(&ptrs->ptr[i].fp_timing, &ptrs->ptr[i-1].fp_timing, size);
+ next_lvds_data_ptr(&ptrs->ptr[i].dvo_timing, &ptrs->ptr[i-1].dvo_timing, size);
+ next_lvds_data_ptr(&ptrs->ptr[i].panel_pnp_id, &ptrs->ptr[i-1].panel_pnp_id, size);
+ }
+
+ size = t1 - t0;
+ table_size = sizeof(struct lvds_lfp_panel_name);
+
+ if (16 * (size + table_size) <= block_size) {
+ ptrs->panel_name.table_size = table_size;
+ ptrs->panel_name.offset = size * 16;
+ }
+
+ offset = block - (const void *)context->bdb;
+ for (int i = 0; i < 16; i++) {
+ ptrs->ptr[i].fp_timing.offset += offset;
+ ptrs->ptr[i].dvo_timing.offset += offset;
+ ptrs->ptr[i].panel_pnp_id.offset += offset;
+ }
+
+ if (ptrs->panel_name.offset)
+ ptrs->panel_name.offset += offset;
+
+ return ptrs_block;
+}
+
static size_t block_min_size(const struct context *context, int section_id)
{
switch (section_id) {
@@ -345,23 +460,34 @@ static struct bdb_block *find_section(const struct context *context, int section
{
size_t min_size = block_min_size(context, section_id);
struct bdb_block *block;
+ void *temp_block = NULL;
const void *data;
size_t size;
data = find_raw_section(context, section_id);
+ if (!data && section_id == BDB_LVDS_LFP_DATA_PTRS) {
+ printf("Generating LVDS data table pointers\n");
+ temp_block = generate_lvds_data_ptrs(context);
+ if (temp_block)
+ data = temp_block + 3;
+ }
if (!data)
return NULL;
size = get_blocksize(data);
block = calloc(1, sizeof(*block) + 3 + max(size, min_size));
- if (!block)
+ if (!block) {
+ free(temp_block);
return NULL;
+ }
block->id = section_id;
block->size = size;
memcpy(block->data, data - 3, 3 + size);
+ free(temp_block);
+
if (section_id == BDB_LVDS_LFP_DATA_PTRS &&
!fixup_lfp_data_ptrs(context, 3 + block->data)) {
fprintf(stderr, "VBT has malformed LFP data table pointers\n");