2021-05-25 16:56:02 +08:00
|
|
|
#include <fel.h>
|
2021-06-04 17:11:28 +08:00
|
|
|
#include <spinor.h>
|
|
|
|
#include <spinand.h>
|
2021-05-25 16:56:02 +08:00
|
|
|
|
2021-06-05 17:18:58 +08:00
|
|
|
static uint64_t file_save(const char * filename, void * buf, uint64_t len)
|
2021-05-25 23:44:28 +08:00
|
|
|
{
|
|
|
|
FILE * out = fopen(filename, "wb");
|
|
|
|
int r;
|
|
|
|
if(!out)
|
|
|
|
{
|
|
|
|
perror("Failed to open output file");
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
r = fwrite(buf, len, 1, out);
|
|
|
|
fclose(out);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2021-06-05 17:18:58 +08:00
|
|
|
static void * file_load(const char * filename, uint64_t * len)
|
2021-05-25 23:44:28 +08:00
|
|
|
{
|
2021-06-05 17:18:58 +08:00
|
|
|
uint64_t offset = 0, bufsize = 8192;
|
2021-05-25 23:44:28 +08:00
|
|
|
char * buf = malloc(bufsize);
|
|
|
|
FILE * in;
|
|
|
|
if(strcmp(filename, "-") == 0)
|
|
|
|
in = stdin;
|
|
|
|
else
|
|
|
|
in = fopen(filename, "rb");
|
|
|
|
if(!in)
|
|
|
|
{
|
|
|
|
perror("Failed to open input file");
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
while(1)
|
|
|
|
{
|
2021-06-05 17:18:58 +08:00
|
|
|
uint64_t len = bufsize - offset;
|
|
|
|
uint64_t n = fread(buf + offset, 1, len, in);
|
2021-05-25 23:44:28 +08:00
|
|
|
offset += n;
|
|
|
|
if(n < len)
|
|
|
|
break;
|
|
|
|
bufsize *= 2;
|
|
|
|
buf = realloc(buf, bufsize);
|
|
|
|
if(!buf)
|
|
|
|
{
|
|
|
|
perror("Failed to resize load_file() buffer");
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(len)
|
|
|
|
*len = offset;
|
|
|
|
if(in != stdin)
|
|
|
|
fclose(in);
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void hexdump(uint32_t addr, void * buf, size_t len)
|
2021-05-25 16:56:02 +08:00
|
|
|
{
|
|
|
|
unsigned char * p = buf;
|
|
|
|
size_t i, j;
|
|
|
|
|
|
|
|
for(j = 0; j < len; j += 16)
|
|
|
|
{
|
2021-08-04 11:48:31 +08:00
|
|
|
printf("%08x: ", (uint32_t)(addr + j));
|
2021-05-25 16:56:02 +08:00
|
|
|
for(i = 0; i < 16; i++)
|
|
|
|
{
|
|
|
|
if(j + i < len)
|
|
|
|
printf("%02x ", p[j + i]);
|
|
|
|
else
|
2021-05-25 23:44:28 +08:00
|
|
|
printf(" ");
|
2021-05-25 16:56:02 +08:00
|
|
|
}
|
|
|
|
putchar(' ');
|
|
|
|
for(i = 0; i < 16; i++)
|
|
|
|
{
|
|
|
|
if(j + i >= len)
|
2021-05-25 23:44:28 +08:00
|
|
|
putchar(' ');
|
2021-05-25 16:56:02 +08:00
|
|
|
else
|
|
|
|
putchar(isprint(p[j + i]) ? p[j + i] : '.');
|
|
|
|
}
|
|
|
|
printf("\r\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void usage(void)
|
|
|
|
{
|
2021-11-08 23:12:52 +08:00
|
|
|
printf("xfel(v1.2.1) - https://github.com/xboot/xfel\r\n");
|
2021-05-25 16:56:02 +08:00
|
|
|
printf("usage:\r\n");
|
2021-06-25 14:16:57 +08:00
|
|
|
printf(" xfel version - Show chip version\r\n");
|
2021-05-26 11:46:27 +08:00
|
|
|
printf(" xfel hexdump <address> <length> - Dumps memory region in hex\r\n");
|
|
|
|
printf(" xfel dump <address> <length> - Binary memory dump to stdout\r\n");
|
|
|
|
printf(" xfel exec <address> - Call function address\r\n");
|
|
|
|
printf(" xfel read32 <address> - Read 32-bits value from device memory\r\n");
|
|
|
|
printf(" xfel write32 <address> <value> - Write 32-bits value to device memory\r\n");
|
|
|
|
printf(" xfel read <address> <length> <file> - Read memory to file\r\n");
|
|
|
|
printf(" xfel write <address> <file> - Write file to memory\r\n");
|
|
|
|
printf(" xfel reset - Reset device using watchdog\r\n");
|
2021-06-25 14:16:57 +08:00
|
|
|
printf(" xfel sid - Show sid information\r\n");
|
2021-05-30 19:42:57 +08:00
|
|
|
printf(" xfel jtag - Enable jtag debug\r\n");
|
|
|
|
printf(" xfel ddr [type] - Initial ddr controller with optional type\r\n");
|
2021-05-26 11:46:27 +08:00
|
|
|
printf(" xfel spinor - Detect spi nor flash\r\n");
|
|
|
|
printf(" xfel spinor read <address> <length> <file> - Read spi nor flash to file\r\n");
|
|
|
|
printf(" xfel spinor write <address> <file> - Write file to spi nor flash\r\n");
|
|
|
|
printf(" xfel spinand - Detect spi nand flash\r\n");
|
|
|
|
printf(" xfel spinand read <address> <length> <file> - Read spi nand flash to file\r\n");
|
|
|
|
printf(" xfel spinand write <address> <file> - Write file to spi nand flash\r\n");
|
2021-05-25 16:56:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char * argv[])
|
|
|
|
{
|
|
|
|
struct xfel_ctx_t ctx;
|
|
|
|
|
|
|
|
if(argc < 2)
|
|
|
|
{
|
|
|
|
usage();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
libusb_init(NULL);
|
|
|
|
ctx.hdl = libusb_open_device_with_vid_pid(NULL, 0x1f3a, 0xefe8);
|
|
|
|
if(!fel_init(&ctx))
|
|
|
|
{
|
|
|
|
printf("ERROR: Can't found any FEL device\r\n");
|
|
|
|
if(ctx.hdl)
|
|
|
|
libusb_close(ctx.hdl);
|
|
|
|
libusb_exit(NULL);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if(!ctx.chip)
|
|
|
|
{
|
|
|
|
printf("WARNNING: Not yet support this device\r\n");
|
2021-05-26 17:49:55 +08:00
|
|
|
printf("%.8s soc=0x%08x 0x%08x ver=0x%04x 0x%02x 0x%02x scratchpad=0x%08x\r\n",
|
2021-05-26 17:22:48 +08:00
|
|
|
ctx.version.magic, ctx.version.id, ctx.version.firmware,
|
|
|
|
ctx.version.protocol, ctx.version.dflag, ctx.version.dlength, ctx.version.scratchpad);
|
2021-05-25 16:56:02 +08:00
|
|
|
if(ctx.hdl)
|
|
|
|
libusb_close(ctx.hdl);
|
|
|
|
libusb_exit(NULL);
|
|
|
|
return -1;
|
|
|
|
}
|
2021-06-07 17:46:00 +08:00
|
|
|
if(!strcmp(argv[1], "version"))
|
2021-05-25 16:56:02 +08:00
|
|
|
{
|
2021-05-26 17:49:55 +08:00
|
|
|
printf("%.8s soc=0x%08x(%s) 0x%08x ver=0x%04x 0x%02x 0x%02x scratchpad=0x%08x\r\n",
|
2021-05-26 17:22:48 +08:00
|
|
|
ctx.version.magic, ctx.version.id, ctx.chip->name, ctx.version.firmware,
|
|
|
|
ctx.version.protocol, ctx.version.dflag, ctx.version.dlength, ctx.version.scratchpad);
|
2021-05-25 16:56:02 +08:00
|
|
|
}
|
|
|
|
else if(!strcmp(argv[1], "hexdump"))
|
|
|
|
{
|
|
|
|
argc -= 2;
|
|
|
|
argv += 2;
|
2021-05-25 23:44:28 +08:00
|
|
|
if(argc == 2)
|
|
|
|
{
|
|
|
|
uint32_t addr = strtoul(argv[0], NULL, 0);
|
|
|
|
size_t len = strtoul(argv[1], NULL, 0);
|
|
|
|
char * buf = malloc(len);
|
|
|
|
if(buf)
|
|
|
|
{
|
2021-06-05 15:03:19 +08:00
|
|
|
fel_read(&ctx, addr, buf, len);
|
2021-05-25 23:44:28 +08:00
|
|
|
hexdump(addr, buf, len);
|
|
|
|
free(buf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
usage();
|
|
|
|
}
|
|
|
|
else if(!strcmp(argv[1], "dump"))
|
|
|
|
{
|
|
|
|
argc -= 2;
|
|
|
|
argv += 2;
|
|
|
|
if(argc == 2)
|
2021-05-25 16:56:02 +08:00
|
|
|
{
|
2021-05-25 23:44:28 +08:00
|
|
|
uint32_t addr = strtoul(argv[0], NULL, 0);
|
2021-05-25 16:56:02 +08:00
|
|
|
size_t len = strtoul(argv[1], NULL, 0);
|
2021-05-25 23:44:28 +08:00
|
|
|
char * buf = malloc(len);
|
|
|
|
if(buf)
|
|
|
|
{
|
2021-06-05 15:03:19 +08:00
|
|
|
fel_read(&ctx, addr, buf, len);
|
2021-05-25 23:44:28 +08:00
|
|
|
fwrite(buf, len, 1, stdout);
|
|
|
|
free(buf);
|
|
|
|
}
|
2021-05-25 16:56:02 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
usage();
|
|
|
|
}
|
2021-05-25 23:44:28 +08:00
|
|
|
else if(!strcmp(argv[1], "exec"))
|
|
|
|
{
|
|
|
|
argc -= 2;
|
|
|
|
argv += 2;
|
|
|
|
if(argc == 1)
|
|
|
|
{
|
|
|
|
uint32_t addr = strtoul(argv[0], NULL, 0);
|
|
|
|
fel_exec(&ctx, addr);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
usage();
|
|
|
|
}
|
|
|
|
else if(!strcmp(argv[1], "read32"))
|
|
|
|
{
|
|
|
|
argc -= 2;
|
|
|
|
argv += 2;
|
|
|
|
if(argc == 1)
|
|
|
|
{
|
|
|
|
uint32_t addr = strtoul(argv[0], NULL, 0);
|
|
|
|
printf("0x%08x\r\n", fel_read32(&ctx, addr));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
usage();
|
|
|
|
}
|
|
|
|
else if(!strcmp(argv[1], "write32"))
|
|
|
|
{
|
|
|
|
argc -= 2;
|
|
|
|
argv += 2;
|
|
|
|
if(argc == 2)
|
|
|
|
{
|
|
|
|
uint32_t addr = strtoul(argv[0], NULL, 0);
|
|
|
|
size_t val = strtoul(argv[1], NULL, 0);
|
|
|
|
fel_write32(&ctx, addr, val);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
usage();
|
|
|
|
}
|
|
|
|
else if(!strcmp(argv[1], "read"))
|
|
|
|
{
|
|
|
|
argc -= 2;
|
|
|
|
argv += 2;
|
|
|
|
if(argc == 3)
|
|
|
|
{
|
|
|
|
uint32_t addr = strtoul(argv[0], NULL, 0);
|
|
|
|
size_t len = strtoul(argv[1], NULL, 0);
|
|
|
|
char * buf = malloc(len);
|
|
|
|
if(buf)
|
|
|
|
{
|
2021-06-05 15:03:19 +08:00
|
|
|
fel_read_progress(&ctx, addr, buf, len);
|
2021-05-25 23:44:28 +08:00
|
|
|
file_save(argv[2], buf, len);
|
|
|
|
free(buf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
usage();
|
|
|
|
}
|
|
|
|
else if(!strcmp(argv[1], "write"))
|
|
|
|
{
|
|
|
|
argc -= 2;
|
|
|
|
argv += 2;
|
|
|
|
if(argc == 2)
|
|
|
|
{
|
|
|
|
uint32_t addr = strtoul(argv[0], NULL, 0);
|
2021-11-28 23:33:55 +08:00
|
|
|
uint64_t len;
|
2021-05-25 23:44:28 +08:00
|
|
|
void * buf = file_load(argv[1], &len);
|
|
|
|
if(buf)
|
|
|
|
{
|
2021-06-05 15:03:19 +08:00
|
|
|
fel_write_progress(&ctx, addr, buf, len);
|
2021-05-25 23:44:28 +08:00
|
|
|
free(buf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
usage();
|
|
|
|
}
|
|
|
|
else if(!strcmp(argv[1], "reset"))
|
|
|
|
{
|
|
|
|
if(!fel_chip_reset(&ctx))
|
2021-05-30 19:42:57 +08:00
|
|
|
printf("The '%s' chip don't support reset command\r\n", ctx.chip->name);
|
2021-05-25 23:44:28 +08:00
|
|
|
}
|
|
|
|
else if(!strcmp(argv[1], "sid"))
|
|
|
|
{
|
2021-06-25 14:16:57 +08:00
|
|
|
char sid[256];
|
2021-05-26 10:42:14 +08:00
|
|
|
if(fel_chip_sid(&ctx, sid))
|
2021-06-25 14:16:57 +08:00
|
|
|
printf("%s\r\n", sid);
|
2021-05-26 10:42:14 +08:00
|
|
|
else
|
2021-05-30 19:42:57 +08:00
|
|
|
printf("The '%s' chip don't support sid command\r\n", ctx.chip->name);
|
2021-05-25 23:44:28 +08:00
|
|
|
}
|
|
|
|
else if(!strcmp(argv[1], "jtag"))
|
|
|
|
{
|
|
|
|
if(!fel_chip_jtag(&ctx))
|
2021-05-30 19:42:57 +08:00
|
|
|
printf("The '%s' chip don't support jtag command\r\n", ctx.chip->name);
|
2021-05-25 23:44:28 +08:00
|
|
|
}
|
|
|
|
else if(!strcmp(argv[1], "ddr"))
|
|
|
|
{
|
2021-05-26 11:26:25 +08:00
|
|
|
argc -= 2;
|
|
|
|
argv += 2;
|
2021-05-30 19:42:57 +08:00
|
|
|
if(fel_chip_ddr(&ctx, (argc == 1) ? argv[0] : NULL))
|
2021-05-30 19:44:18 +08:00
|
|
|
printf("Initial ddr controller sucessed\r\n");
|
2021-05-30 19:42:57 +08:00
|
|
|
else
|
2021-05-30 19:44:18 +08:00
|
|
|
printf("Failed to initial ddr controller\r\n");
|
2021-05-25 23:44:28 +08:00
|
|
|
}
|
2021-05-26 12:09:59 +08:00
|
|
|
else if(!strcmp(argv[1], "spinor"))
|
|
|
|
{
|
|
|
|
argc -= 2;
|
|
|
|
argv += 2;
|
|
|
|
if(argc == 0)
|
|
|
|
{
|
2021-11-01 19:33:09 +08:00
|
|
|
char name[128];
|
|
|
|
uint64_t capacity;
|
|
|
|
|
|
|
|
if(spinor_detect(&ctx, name, &capacity))
|
|
|
|
printf("Found spi nor flash '%s' with %lld bytes\r\n", name, (long long)capacity);
|
2021-05-26 12:09:59 +08:00
|
|
|
else
|
2021-10-27 13:52:12 +08:00
|
|
|
printf("Can't detect any spi nor flash\r\n");
|
2021-05-26 12:09:59 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-06-06 12:24:35 +08:00
|
|
|
if(!strcmp(argv[0], "read") && (argc == 4))
|
2021-05-26 12:09:59 +08:00
|
|
|
{
|
|
|
|
argc -= 1;
|
|
|
|
argv += 1;
|
2021-06-05 17:18:58 +08:00
|
|
|
uint64_t addr = strtoull(argv[0], NULL, 0);
|
|
|
|
uint64_t len = strtoull(argv[1], NULL, 0);
|
2021-05-26 12:09:59 +08:00
|
|
|
char * buf = malloc(len);
|
|
|
|
if(buf)
|
|
|
|
{
|
2021-06-05 17:18:58 +08:00
|
|
|
if(spinor_read(&ctx, addr, buf, len))
|
2021-06-04 17:11:28 +08:00
|
|
|
file_save(argv[2], buf, len);
|
2021-06-05 17:18:58 +08:00
|
|
|
else
|
2021-10-27 13:52:12 +08:00
|
|
|
printf("Can't read spi nor flash\r\n");
|
2021-05-26 12:09:59 +08:00
|
|
|
free(buf);
|
|
|
|
}
|
|
|
|
}
|
2021-06-06 12:24:35 +08:00
|
|
|
else if(!strcmp(argv[0], "write") && (argc == 3))
|
2021-05-26 12:09:59 +08:00
|
|
|
{
|
|
|
|
argc -= 1;
|
|
|
|
argv += 1;
|
2021-06-05 17:18:58 +08:00
|
|
|
uint64_t addr = strtoull(argv[0], NULL, 0);
|
|
|
|
uint64_t len;
|
2021-05-26 12:09:59 +08:00
|
|
|
void * buf = file_load(argv[1], &len);
|
|
|
|
if(buf)
|
|
|
|
{
|
2021-06-05 17:18:58 +08:00
|
|
|
if(!spinor_write(&ctx, addr, buf, len))
|
2021-10-27 13:52:12 +08:00
|
|
|
printf("Can't write spi nor flash\r\n");
|
2021-05-26 12:09:59 +08:00
|
|
|
free(buf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
usage();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(!strcmp(argv[1], "spinand"))
|
|
|
|
{
|
|
|
|
argc -= 2;
|
|
|
|
argv += 2;
|
|
|
|
if(argc == 0)
|
|
|
|
{
|
2021-11-01 19:33:09 +08:00
|
|
|
char name[128];
|
|
|
|
uint64_t capacity;
|
|
|
|
|
|
|
|
if(spinand_detect(&ctx, name, &capacity))
|
|
|
|
printf("Found spi nand flash '%s' with %lld bytes\r\n", name, (long long)capacity);
|
2021-05-26 12:09:59 +08:00
|
|
|
else
|
2021-10-27 13:52:12 +08:00
|
|
|
printf("Can't detect any spi nand flash\r\n");
|
2021-05-26 12:09:59 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-06-06 12:24:35 +08:00
|
|
|
if(!strcmp(argv[0], "read") && (argc == 4))
|
2021-05-26 12:09:59 +08:00
|
|
|
{
|
|
|
|
argc -= 1;
|
|
|
|
argv += 1;
|
2021-06-05 17:18:58 +08:00
|
|
|
uint64_t addr = strtoull(argv[0], NULL, 0);
|
|
|
|
uint64_t len = strtoull(argv[1], NULL, 0);
|
2021-05-26 12:09:59 +08:00
|
|
|
char * buf = malloc(len);
|
|
|
|
if(buf)
|
|
|
|
{
|
2021-06-05 17:18:58 +08:00
|
|
|
if(spinand_read(&ctx, addr, buf, len))
|
2021-06-04 17:11:28 +08:00
|
|
|
file_save(argv[2], buf, len);
|
2021-06-05 17:18:58 +08:00
|
|
|
else
|
2021-10-27 13:52:12 +08:00
|
|
|
printf("Can't read spi nand flash\r\n");
|
2021-05-26 12:09:59 +08:00
|
|
|
free(buf);
|
|
|
|
}
|
|
|
|
}
|
2021-06-06 12:24:35 +08:00
|
|
|
else if(!strcmp(argv[0], "write") && (argc == 3))
|
2021-05-26 12:09:59 +08:00
|
|
|
{
|
|
|
|
argc -= 1;
|
|
|
|
argv += 1;
|
2021-06-05 17:18:58 +08:00
|
|
|
uint64_t addr = strtoull(argv[0], NULL, 0);
|
|
|
|
uint64_t len;
|
2021-05-26 12:09:59 +08:00
|
|
|
void * buf = file_load(argv[1], &len);
|
|
|
|
if(buf)
|
|
|
|
{
|
2021-06-05 17:18:58 +08:00
|
|
|
if(!spinand_write(&ctx, addr, buf, len))
|
2021-10-27 13:52:12 +08:00
|
|
|
printf("Can't write spi nand flash\r\n");
|
2021-05-26 12:09:59 +08:00
|
|
|
free(buf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
usage();
|
|
|
|
}
|
|
|
|
}
|
2021-05-25 16:56:02 +08:00
|
|
|
else
|
|
|
|
usage();
|
|
|
|
if(ctx.hdl)
|
|
|
|
libusb_close(ctx.hdl);
|
|
|
|
libusb_exit(NULL);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|