glider/utils/mxc_waveform_dump/main.c

309 lines
9.6 KiB
C

/*******************************************************************************
* Freescale/NXP EPDC waveform firmware dumper
* Based on https://github.com/julbouln/ice40_eink_controller
*
* This is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 2 of the License, or (at your option) any later
* version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* the software. If not, see <http://www.gnu.org/licenses/>.
*
* This file is partially derived from Linux kernel driver, with the following
* copyright information:
* Copyright (C) 2014-2016 Freescale Semiconductor, Inc.
* Copyright 2017 NXP
******************************************************************************/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <inttypes.h>
struct waveform_data_header {
unsigned int wi0;
unsigned int wi1;
unsigned int wi2;
unsigned int wi3;
unsigned int wi4;
unsigned int wi5;
unsigned int wi6;
unsigned int xwia: 24;
unsigned int cs1: 8;
unsigned int wmta: 24;
unsigned int fvsn: 8;
unsigned int luts: 8;
unsigned int mc: 8;
unsigned int trc: 8;
unsigned int advanced_wfm_flags: 8;
unsigned int eb: 8;
unsigned int sb: 8;
unsigned int reserved0_1: 8;
unsigned int reserved0_2: 8;
unsigned int reserved0_3: 8;
unsigned int reserved0_4: 8;
unsigned int reserved0_5: 8;
unsigned int cs2: 8;
};
struct mxcfb_waveform_data_file {
struct waveform_data_header wdh;
uint32_t *data; /* Temperature Range Table + Waveform Data */
};
static uint64_t read_uint64_le(uint8_t* src) {
return ((uint64_t)src[7] << 56) |
((uint64_t)src[6] << 48) |
((uint64_t)src[5] << 40) |
((uint64_t)src[4] << 32) |
((uint64_t)src[3] << 24) |
((uint64_t)src[2] << 16) |
((uint64_t)src[1] << 8) |
(uint64_t)src[0];
}
static uint8_t read_uint4(uint8_t* src, size_t addr) {
uint8_t val = src[addr >> 1];
if (addr & 1)
val = (val >> 4) & 0xf;
else
val = val & 0xf;
return val;
}
void dump_phases(FILE* fp, uint8_t* buffer, int phases, int ver) {
int i, j, k, l, x, y;
uint8_t luts[phases][16][16];
k = 0;
for (i = 0; i < phases * 256; i += 256) {
j = 0;
for (x = 0; x < 16; x++) {
for (y = 0; y < 16; y++) {
uint8_t val;
if (ver == 2)
val = read_uint4(buffer + 8, i + j);
else
val = buffer[8 + i + j];
luts[k][y][x] = val;
j++;
}
}
k++;
}
for (i = 0; i < 16; i++) {
for (j = 0; j < 16; j++) {
fprintf(fp, "%d,%d,", i, j);
for (k = 0; k < phases; k++) {
fprintf(fp, "%d,", luts[k][i][j]);
}
fprintf(fp, "\n");
}
}
}
int main(int argc, char **argv) {
fprintf(stderr, "MXC EPDC waveform dumper\n");
if (argc < 4) {
fprintf(stderr, "Usage: mxc_wvfm_dump version input_file output_prefix\n");
fprintf(stderr, "version: EPDC version, possible values: v1, v2\n");
fprintf(stderr, "input_file: MXC EPDC firmware file, in .fw format\n");
fprintf(stderr, "output_prefix: Prefix for output file name, without extension\n");
fprintf(stderr, "Example: mxc_wvfm_dump v1 epdc_E060SCM.fw e060scm\n");
return 1;
}
char *ver_string = argv[1];
char *fw = argv[2];
char *prefix = argv[3];
int ver;
if (strcmp(ver_string, "v1") == 0) {
ver = 1;
}
else if (strcmp(ver_string, "v2") == 0) {
ver = 2;
}
else {
fprintf(stderr, "Invalid EPDC version %s\n", ver_string);
fprintf(stderr, "Possible values: v1, v2.\n");
fprintf(stderr, "i.MX6DL/SL uses EPDCv1, i.MX7D uses EPDCv2. i.MX5 EPDC is not supported.\n");
return 1;
}
FILE * fp;
size_t file_size;
char * file_buffer;
size_t result;
fp = fopen(fw, "rb");
assert(fp);
// obtain file size:
fseek(fp, 0, SEEK_END);
file_size = ftell(fp);
fseek(fp, 0, SEEK_SET);
// allocate memory to contain the whole file:
file_buffer = (char*)malloc(sizeof(char) * file_size);
assert(file_buffer);
// copy the file into the buffer:
assert(fread(file_buffer, file_size, 1, fp) == 1);
fclose(fp);
/* the whole file is now loaded in the memory buffer. */
struct mxcfb_waveform_data_file *wv_file;
wv_file = (struct mxcfb_waveform_data_file *)file_buffer;
printf("wi0: %08x\n", wv_file->wdh.wi0);
printf("wi1: %08x\n", wv_file->wdh.wi1);
printf("wi2: %08x\n", wv_file->wdh.wi2);
printf("wi3: %08x\n", wv_file->wdh.wi3);
printf("wi4: %08x\n", wv_file->wdh.wi4);
printf("wi5: %08x\n", wv_file->wdh.wi5);
printf("wi6: %08x\n", wv_file->wdh.wi6);
printf("xwia: %d\n", wv_file->wdh.xwia);
printf("cs1: %d\n", wv_file->wdh.cs1);
printf("wmta: %d\n", wv_file->wdh.wmta);
printf("fvsn: %d\n", wv_file->wdh.fvsn);
printf("luts: %d\n", wv_file->wdh.luts);
printf("mc: %d\n", wv_file->wdh.mc);
printf("trc: %d\n", wv_file->wdh.trc);
printf("advanced_wfm_flags: %d\n", wv_file->wdh.advanced_wfm_flags);
printf("eb: %d\n", wv_file->wdh.eb);
printf("sb: %d\n", wv_file->wdh.sb);
printf("reserved0_1: %d\n", wv_file->wdh.reserved0_1);
printf("reserved0_2: %d\n", wv_file->wdh.reserved0_2);
printf("reserved0_3: %d\n", wv_file->wdh.reserved0_3);
printf("reserved0_4: %d\n", wv_file->wdh.reserved0_4);
printf("reserved0_5: %d\n", wv_file->wdh.reserved0_5);
printf("cs2: %d\n", wv_file->wdh.cs2);
int i, j;
int trt_entries; // temperature range table
int wv_data_offs; // offset for waveform data
int waveform_buffer_size; // size for waveform data
int mode_count = wv_file->wdh.mc + 1;
uint8_t *temp_range_bounds;
trt_entries = wv_file->wdh.trc + 1;
printf("Temperatures count: %d\n", trt_entries);
temp_range_bounds = (uint8_t*)malloc(trt_entries);
memcpy(temp_range_bounds, &wv_file->data, trt_entries);
for (i = 0; i < trt_entries; i++) {
printf("Temperature %d = %d°C\n", i, temp_range_bounds[i]);
}
wv_data_offs = sizeof(wv_file->wdh) + trt_entries + 1;
waveform_buffer_size = file_size - wv_data_offs;
printf("Waveform data offset: %d, size: %d\n", wv_data_offs, waveform_buffer_size);
if ((wv_file->wdh.luts & 0xC) == 0x4) {
printf("waveform 5bit\n");
} else {
printf("waveform 4bit\n");
}
uint8_t *waveform_buffer;
waveform_buffer = (uint8_t *)malloc(waveform_buffer_size);
memcpy(waveform_buffer, (uint8_t *)(file_buffer) + wv_data_offs,
waveform_buffer_size);
uint64_t* wv_modes = malloc(sizeof(uint64_t) * mode_count);
uint64_t addr;
// get modes addr
for (i = 0; i < mode_count; i++) {
addr = read_uint64_le(&waveform_buffer[i * 8]);
printf("wave #%d addr: %08"PRIx64"\n", i, addr);
wv_modes[i] = addr;
}
// get modes temp addr
uint64_t* wv_modes_temps = malloc(sizeof(uint64_t) * mode_count * trt_entries);
uint64_t* frame_counts = malloc(sizeof(uint64_t) * mode_count * trt_entries);
uint64_t last_addr = wv_modes[0];
for (i = 0; i < mode_count; i++) {
uint64_t m = wv_modes[i];
for (j = 0; j < trt_entries; j++) {
addr = read_uint64_le(&waveform_buffer[m + j * 8]);
wv_modes_temps[i * trt_entries + j] = addr;
uint64_t frame_count = read_uint64_le(&waveform_buffer[addr]);
frame_counts[i * trt_entries + j] = frame_count;
printf("wave #%d, temp #%d addr: %08"PRIx64", %"PRId64" phases (Addr diff = %"PRId64", Size = %"PRId64")\n", i, j,
addr, frame_count, addr - last_addr, frame_count * 256);
last_addr = addr;
}
}
char* fn = malloc(strlen(prefix) + 14);
sprintf(fn, "%s_desc.iwf", prefix);
fp = fopen(fn, "w");
assert(fp);
fprintf(fp, "[WAVEFORM]\n");
fprintf(fp, "VERSION = 1.0\n");
fprintf(fp, "PREFIX = %s\n", prefix);
fprintf(fp, "MODES = %d\n", mode_count);
fprintf(fp, "TEMPS = %d\n", trt_entries);
fprintf(fp, "\n");
for (int i = 0; i < trt_entries; i++) {
fprintf(fp, "T%dRANGE = %d\n", i, temp_range_bounds[i]);
}
fprintf(fp, "\n");
for (int i = 0; i < mode_count; i++) {
fprintf(fp, "[MODE%d]\n", i);
for (int j = 0; j < trt_entries; j++) {
fprintf(fp, "T%dFC = %"PRId64"\n", j, frame_counts[i * trt_entries + j]);
}
fprintf(fp, "\n");
}
fclose(fp);
for (int i = 0; i < mode_count; i++) {
for (int j = 0; j < trt_entries; j++) {
sprintf(fn, "%s_M%d_T%d.csv", prefix, i, j);
fp = fopen(fn, "w");
assert(fp);
size_t index = i * trt_entries + j;
uint64_t frame_count = frame_counts[index];
uint8_t* lut = &waveform_buffer[wv_modes_temps[index]];
dump_phases(fp, lut, frame_count, ver);
fclose(fp);
}
}
free(fn);
free(temp_range_bounds);
free(waveform_buffer);
free(frame_counts);
free(wv_modes);
free(wv_modes_temps);
free(file_buffer);
return 0;
}