FreeCalypso > hg > freecalypso-tools
diff loadtools/flprogbin.c @ 0:e7502631a0f9
initial import from freecalypso-sw rev 1033:5ab737ac3ad7
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sat, 11 Jun 2016 00:13:35 +0000 |
parents | |
children | 0dd2c87c1b63 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/flprogbin.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,200 @@ +/* + * This module implements the flash program-bin command: + * programming flash using a binary file as the data source. + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <time.h> +#include "flash.h" + +extern struct flash_bank_info flash_bank_info[2]; +extern uint32_t crc32_table[]; + +flashcmd_progbin(argc, argv, bank) + char **argv; +{ + struct flash_bank_info *bi; + u_long flashoff, fileoff, len, origlen, bytesdone; + u_long crc_base_addr, crc_from_target; + uint32_t crcaccum; + char *strtoul_endp; + FILE *binf; + struct stat filestat; + char *targv[4], shortarg[10], longarg[513]; + u_char databuf[256]; + int reclen, cc, i; + time_t curtime, last_time; + + if (argc < 4 || argc > 6) { +inv: fprintf(stderr, + "usage: %s %s flash-offset binfile [file-offset [length]]\n", + argv[0], argv[1]); + return(-1); + } + flashoff = strtoul(argv[2], &strtoul_endp, 16); + if (*strtoul_endp) + goto inv; + if (flash_get_cfi(bank) < 0) + return(-1); + bi = flash_bank_info + bank; + if (flashoff >= bi->geom->total_size) { + fprintf(stderr, + "error: specified flash offset exceeds bank size (0x%lx)\n", + (u_long) bi->geom->total_size); + return(-1); + } + if (flashoff & 1) { + fprintf(stderr, "error: flash offset must be even\n"); + return(-1); + } + binf = fopen(argv[3], "r"); + if (!binf) { + perror(argv[3]); + return(-1); + } + fstat(fileno(binf), &filestat); + if (!S_ISREG(filestat.st_mode)) { + fprintf(stderr, "%s is not a regular file\n", argv[3]); + fclose(binf); + return(-1); + } + if (argc > 4) { + fileoff = strtoul(argv[4], &strtoul_endp, 16); + if (*strtoul_endp) { + fclose(binf); + goto inv; + } + if (fileoff > filestat.st_size) { + fprintf(stderr, + "error: specified file offset exceeds file length\n"); + fclose(binf); + return(-1); + } + } else + fileoff = 0; + if (argc > 5) { + len = strtoul(argv[5], &strtoul_endp, 16); + if (*strtoul_endp) { + fclose(binf); + goto inv; + } + if (len > filestat.st_size - fileoff) { + fprintf(stderr, + "error: specified file offset+length exceed file length\n"); + fclose(binf); + return(-1); + } + } else + len = filestat.st_size - fileoff; + if (!len) { + printf("Length is zero - nothing to do!\n"); + fclose(binf); + return(0); + } + if (len > bi->geom->total_size - flashoff) { + fprintf(stderr, + "error: specified flash offset+length exceed bank size (0x%lx)\n", + (u_long) bi->geom->total_size); + fclose(binf); + return(-1); + } + if (len & 1) { + fprintf(stderr, "error: program length must be even\n"); + fclose(binf); + return(-1); + } + + /* finally done with the arg parsing etc, can get to work now */ + if (flash_id_check(bank, 0) < 0) { + fclose(binf); + return(-1); + } + crc_base_addr = bi->base_addr + flashoff; + sprintf(shortarg, "%lx", (u_long) bi->base_addr); + targv[0] = bi->ops->loadagent_setbase_cmd; + targv[1] = shortarg; + targv[2] = 0; + printf("Setting flash base address: %s %s\n", targv[0], targv[1]); + tpinterf_make_cmd(targv); + if (tpinterf_send_cmd() < 0) { + fclose(binf); + return(-1); + } + cc = tpinterf_pass_output(1); + if (cc) { + fclose(binf); + return(cc); + } + if (bi->ops->prep_for_program(bi) < 0) { + fclose(binf); + return(-1); + } + fseek(binf, fileoff, SEEK_SET); + targv[0] = bi->ops->loadagent_program_cmd; + targv[1] = shortarg; + targv[2] = longarg; + targv[3] = 0; + printf("Programming flash: %lu (0x%lx) bytes\n", len, len); + origlen = len; + bytesdone = 0; + last_time = 0; + crcaccum = 0xFFFFFFFF; + while (len) { + if (len >= 256) + reclen = 256; + else + reclen = len; + cc = fread(databuf, 1, reclen, binf); + if (cc != reclen) { + fclose(binf); + fprintf(stderr, "error reading from %s\n", argv[3]); + return(-1); + } + for (i = 0; i < reclen; i++) /* update running CRC */ + crcaccum = crc32_table[crcaccum & 0xFF ^ databuf[i]] + ^ (crcaccum >> 8); + sprintf(shortarg, "%lx", flashoff); + build_flashw_hex_string(databuf, longarg, reclen >> 1, 0); + tpinterf_make_cmd(targv); + if (tpinterf_send_cmd() < 0) { + fclose(binf); + return(-1); + } + i = tpinterf_pass_output(8); /* 8 s timeout */ + if (i) { + fclose(binf); + return(i); + } + flashoff += reclen; + len -= reclen; + bytesdone += reclen; + cc = bytesdone * 100 / origlen; + time(&curtime); + if (curtime != last_time || cc == 100) { + printf("\r0x%lx bytes programmed (%i%%)", + bytesdone, cc); + fflush(stdout); + } + last_time = curtime; + } + putchar('\n'); + fclose(binf); + + /* reset flash to read mode */ + if (bi->ops->reset_cmd(bi) < 0) + return(-1); + printf("Verifying CRC-32 of programmed flash area\n"); + if (crc32_on_target(crc_base_addr, origlen, &crc_from_target) < 0) + return(-1); + if (crc_from_target == crcaccum) { + printf("match (%08lX)\n", crc_from_target); + return(0); + } else { + fprintf(stderr, "error: CRC mismatch!\n"); + return(-1); + } +}