Signed-off-by: Gaurav K Singh <gaurav.k.singh@xxxxxxxxx> --- tools/intel_bios.h | 26 +++++ tools/intel_bios_reader.c | 272 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 298 insertions(+) diff --git a/tools/intel_bios.h b/tools/intel_bios.h index 752379a..aedc5fc 100644 --- a/tools/intel_bios.h +++ b/tools/intel_bios.h @@ -30,6 +30,7 @@ #include <stdint.h> + struct vbt_header { char signature[20]; /**< Always starts with 'VBT$' */ uint16_t version; /**< decimal */ @@ -729,6 +730,31 @@ struct bdb_mipi_config { struct mipi_pps_data pps[MAX_MIPI_CONFIGURATIONS]; } __attribute__ ((packed)); +/* variable number of these - max 6 */ +struct bdb_mipi_sequence { + uint8_t version; + uint8_t data[0]; +} __attribute__ ((packed)); + +/* MIPI Sequnece Block definitions */ +enum MIPI_SEQ { + MIPI_SEQ_UNDEFINED = 0, + MIPI_SEQ_ASSERT_RESET, + MIPI_SEQ_INIT_OTP, + MIPI_SEQ_DISPLAY_ON, + MIPI_SEQ_DISPLAY_OFF, + MIPI_SEQ_DEASSERT_RESET, + MIPI_SEQ_MAX +}; + +enum MIPI_SEQ_ELEMENT { + MIPI_SEQ_ELEM_UNDEFINED = 0, + MIPI_SEQ_ELEM_SEND_PKT, + MIPI_SEQ_ELEM_DELAY, + MIPI_SEQ_ELEM_GPIO, + MIPI_SEQ_ELEM_MAX +}; + /* * Driver<->VBIOS interaction occurs through scratch bits in * GR18 & SWF*. diff --git a/tools/intel_bios_reader.c b/tools/intel_bios_reader.c index 9f82481..4fa47a9 100644 --- a/tools/intel_bios_reader.c +++ b/tools/intel_bios_reader.c @@ -71,6 +71,15 @@ struct bdb_block { void *data; }; +static const char * const seq_name[] = { + "UNDEFINED", + "MIPI_SEQ_ASSERT_RESET", + "MIPI_SEQ_INIT_OTP", + "MIPI_SEQ_DISPLAY_ON", + "MIPI_SEQ_DISPLAY_OFF", + "MIPI_SEQ_DEASSERT_RESET", +}; + struct bdb_header *bdb; struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs; static int tv_present; @@ -784,6 +793,263 @@ static void dump_mipi_config(const struct bdb_block *block) printf("\t\tPanel power cycle delay: %d\n", pps->panel_power_cycle_delay); } +static uint8_t *mipi_dump_send_packet(uint8_t *data) +{ + uint8_t type, byte, count; + uint16_t len; + + byte = *data++; + /* get packet type and increment the pointer */ + type = *data++; + + len = *((uint16_t *) data); + data += 2; + printf("\t\t SEND COMMAND: "); + printf("0x%x 0x%x 0x%x", byte, type, len); + for (count = 0; count < len; count++) + printf(" 0x%x",*(data+count)); + printf("\n"); + data += len; + return data; +} + +static uint8_t *mipi_dump_delay(uint8_t *data) +{ + printf("\t\t Delay : 0x%x 0x%x 0x%x 0x%x\n", data[0], data[1], data[2], data[3]); + data += 4; + return data; +} + +static uint8_t *mipi_dump_gpio(uint8_t *data) +{ + uint8_t gpio, action; + + printf("\t\t GPIO value:"); + gpio = *data++; + + /* pull up/down */ + action = *data++; + printf(" 0x%x 0x%x\n", gpio, action); + return data; +} + +typedef uint8_t * (*fn_mipi_elem_dump)(uint8_t *data); + +static const fn_mipi_elem_dump dump_elem[] = { + NULL, /* reserved */ + mipi_dump_send_packet, + mipi_dump_delay, + mipi_dump_gpio, + NULL, /* status read; later */ +}; + +static void dump_sequence(uint8_t *sequence) +{ + uint8_t *data = sequence; + fn_mipi_elem_dump mipi_elem_dump; + int index_no; + + if (!sequence) + return; + + printf("\tSequence Name: %s\n", seq_name[*data]); + + /* go to the first element of the sequence */ + data++; + + /* parse each byte till we reach end of sequence byte - 0x00 */ + while (1) { + index_no = *data; + mipi_elem_dump = dump_elem[index_no]; + if (!mipi_elem_dump) { + printf("Error: Unsupported MIPI element, skipping sequence execution\n"); + return; + } + /* goto element payload */ + data++; + + /* execute the element specifc rotines */ + data = mipi_elem_dump(data); + + /* + * After processing the element, data should point to + * next element or end of sequence + * check if have we reached end of sequence + */ + + if (*data == 0x00) + break; + } +} + +static uint8_t *goto_next_sequence(uint8_t *data, int *size) +{ + uint16_t len; + int tmp = *size; + + if (--tmp < 0) + return NULL; + + /* goto first element */ + data++; + while (1) { + switch (*data) { + case MIPI_SEQ_ELEM_SEND_PKT: + /* + * skip by this element payload size + * skip elem id, command flag and data type + */ + tmp -= 5; + if (tmp < 0) + return NULL; + + data += 3; + len = *((uint16_t *)data); + + tmp -= len; + if (tmp < 0) + return NULL; + + /* skip by len */ + data = data + 2 + len; + break; + case MIPI_SEQ_ELEM_DELAY: + /* skip by elem id, and delay is 4 bytes */ + tmp -= 5; + if (tmp < 0) + return NULL; + + data += 5; + break; + case MIPI_SEQ_ELEM_GPIO: + tmp -= 3; + if (tmp < 0) + return NULL; + + data += 3; + break; + default: + printf("Unknown element\n"); + return NULL; + } + + /* end of sequence ? */ + if (*data == 0) + break; + } + + /* goto next sequence or end of block byte */ + if (--tmp < 0) + return NULL; + + data++; + + /* update amount of data left for the sequence block to be parsed */ + *size = tmp; + return data; +} + +static uint16_t get_blocksize(void *p) +{ + uint16_t *block_ptr, block_size; + + block_ptr = (uint16_t *)((char *)p - 2); + block_size = *block_ptr; + return block_size; +} + +static void dump_mipi_sequence(const struct bdb_block *block) +{ + struct bdb_mipi_sequence *sequence = block->data; + uint8_t *data, *seq_data; + int i, panel_id, seq_size; + uint16_t block_size; + + /* Check if we have sequence block as well */ + if (!sequence) { + printf("No MIPI Sequence found\n"); + return; + } + + block_size = get_blocksize(sequence); + + /* + * parse the sequence block for individual sequences + */ + seq_data = &sequence->data[0]; + + /* + * sequence block is variable length and hence we need to parse and + * get the sequence data for specific panel id + */ + for (i = 0; i < MAX_MIPI_CONFIGURATIONS; i++) { + panel_id = *seq_data; + seq_size = *((uint16_t *) (seq_data + 1)); + if (panel_id == panel_type) + break; + + /* skip the sequence including seq header of 3 bytes */ + seq_data = seq_data + 3 + seq_size; + if ((seq_data - &sequence->data[0]) > block_size) { + printf("Sequence start is beyond sequence block size, corrupted sequence block\n"); + return; + } + } + + if (i == MAX_MIPI_CONFIGURATIONS) { + printf("Sequence block detected but no valid configuration\n"); + return; + } + + /* check if found sequence is completely within the sequence block + * just being paranoid */ + if (seq_size > block_size) { + printf("Corrupted sequence/size, bailing out\n"); + return; + } + + /* skip the panel id(1 byte) and seq size(2 bytes) */ + data = (uint8_t *) calloc(1, seq_size); + if (data) + memmove(data, seq_data + 3, seq_size); + else { + printf("Memory not allocated for sequence data\n"); + return; + } + /* + * loop into the sequence data and split into multiple sequneces + * There are only 5 types of sequences as of now + */ + + /* two consecutive 0x00 indicate end of all sequences */ + while (1) { + int seq_id = *data; + if (MIPI_SEQ_MAX > seq_id && seq_id > MIPI_SEQ_UNDEFINED) + dump_sequence(data); + else { + printf("Error:undefined sequence\n"); + goto err; + } + + /* partial parsing to skip elements */ + data = goto_next_sequence(data, &seq_size); + + if (data == NULL) { + printf("Sequence elements going beyond block itself. Sequence block parsing failed\n"); + goto err; + } + + if (*data == 0) + break; /* end of sequence reached */ + } + return; + +err: + free(data); + data = NULL; +} + + static int get_device_id(unsigned char *bios) { @@ -868,6 +1134,11 @@ struct dumper dumpers[] = { .name = "MIPI configuration block", .dump = dump_mipi_config, }, + { + .id = BDB_MIPI_SEQUENCE, + .name = "MIPI sequence block", + .dump = dump_mipi_sequence, + }, }; static void hex_dump(const struct bdb_block *block) @@ -1042,6 +1313,7 @@ int main(int argc, char **argv) dump_section(BDB_DRIVER_FEATURES, size); dump_section(BDB_EDP, size); dump_section(BDB_MIPI_CONFIG, size); + dump_section(BDB_MIPI_SEQUENCE, size); for (i = 0; i < 256; i++) dump_section(i, size); -- 1.7.9.5 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx