commit icesprog v1.1a

This commit is contained in:
wuxx
2021-01-02 16:15:26 +08:00
parent 201b354067
commit 79aa508078
4 changed files with 545 additions and 96 deletions

Binary file not shown.

24
tools/src/README.md Executable file
View File

@@ -0,0 +1,24 @@
# iCELink Tips
## GPIO control
```
$icesprog --gpio PB14 --mode out
$icesprog --gpio PB14 --write 0
$icesprog --gpio PB14 --write 1
$icesprog --gpio PB14 --read
```
## JTAG select (available on iCESugar-pro)
```
$icesprog --jtag-sel ?
$icesprog --jtag-sel 1
$icesprog --jtag-sel 2
```
## MCO config (available on iCESugar-nano)
```
$icesprog --clk-sel ?
$icesprog --clk-sel 1
$icesprog --clk-sel 2
$icesprog --clk-sel 3
$icesprog --clk-sel 4
```

Binary file not shown.

View File

@@ -48,6 +48,7 @@
#define PACKET_SIZE (64 + 1) /* 64 bytes plus report id */
#define USB_TIMEOUT_DEFAULT 1000
#define ID_DAP_Vendor0 0x80U
#define ID_DAP_Vendor13 0x8DU
#define SPI_FLASH_SIZE flash_size
@@ -55,6 +56,13 @@
#define SPI_FLASH_SECTOR_ALIGN_UP(x) ((x + SPI_FLASH_SECTOR_SIZE - 1) & (~(SPI_FLASH_SECTOR_SIZE - 1)))
#define SPI_FLASH_SECTOR_ALIGN_DOWN(x) ((x) & (~(SPI_FLASH_SECTOR_SIZE - 1)))
enum BOARD_TYPE_E {
BT_iCESugar = 0, /* iCE40UP5K */
BT_iCESugar_Pro = 0xa55a0001, /* ECP5 LFE5U-25F-BG256 */
BT_iCESugar_Nano = 0xa55a0002, /* iCE40LP1K */
BT_Unknown = 0xFFFFFFFF,
};
enum ICELINK_CMD_E {
CMD_FLASH_GET_INFO = 0,
CMD_FLASH_TRANSACTION_START,
@@ -64,6 +72,23 @@ enum ICELINK_CMD_E {
CMD_FLASH_WRITE_SECTOR,
CMD_FLASH_READ_SECTOR,
CMD_FLASH_ERASE_CHIP,
CMD_SYS_GET_INFO = 0x80,
CMD_SYS_GPIO_MODE,
CMD_SYS_GPIO_WRITE,
CMD_SYS_GPIO_READ,
CMD_SYS_JTAG_SEL,
CMD_SYS_JTAG_INFO,
CMD_SYS_MCO_SEL,
CMD_SYS_MCO_INFO,
};
enum MCO_SOURCE_E {
MCO_HSI = 1, /* 8MHz */
MCO_HSE, /* 12MHz */
MCO_PLLCLK, /* 36MHz */ /* actually is RCC_CFGR_MCO_PLLCLK_DIV2 */
MCO_SYSCLK, /* 72MHz */
MCO_MAX,
};
struct icelink {
@@ -80,6 +105,8 @@ struct icelink_packet_head {
uint8_t data[0];
};
int32_t board_type = BT_Unknown;
uint32_t flash_id = 0;
uint32_t flash_size = 8 * 1024 * 1024;
@@ -189,7 +216,7 @@ int icelink_usb_xfer_wait(int txlen)
return 0;
}
int icelink_flash_get_info()
int icelink_flash_get_info(int verbose)
{
struct icelink_packet_head *ph;
@@ -198,33 +225,33 @@ int icelink_flash_get_info()
ph->vendor_cmd = ID_DAP_Vendor13;
ph->icelink_cmd = CMD_FLASH_GET_INFO;
if (icelink_usb_xfer(3) != 0) {
if (icelink_usb_xfer_wait(3) != 0) {
fprintf(stderr, "iCELink CMD_FLASH_GET_INFO failed.");
return -1;
}
flash_id = *((uint32_t *)(&(icelink_handle.packet_buffer[2])));
fprintf(stdout, "flash id: 0x%x \n", flash_id);
if (verbose) { fprintf(stdout, "flash id: 0x%x ", flash_id); }
switch (flash_id) {
case (0xEF4015):
fprintf(stdout, "w25q16 (4MB)\n");
if (verbose) { fprintf(stdout, "w25q16 (4MB)\n"); }
flash_size = 4 * 1024 * 1024;
break;
case (0xEF4017):
fprintf(stdout, "w25q64 (8MB)\n");
if (verbose) { fprintf(stdout, "w25q64 (8MB)\n"); }
flash_size = 8 * 1024 * 1024;
break;
case (0xEF4018):
fprintf(stdout, "w25q128 (16MB)\n");
if (verbose) { fprintf(stdout, "w25q128 (16MB)\n"); }
flash_size = 16 * 1024 * 1024;
break;
default:
fprintf(stdout, "unknown (??MB)\n");
if (verbose) { fprintf(stdout, "unknown (??MB)\n"); }
break;
}
return 0;
return flash_id;
}
int icelink_flash_transaction_start()
@@ -479,6 +506,303 @@ int icelink_flash_erase_chip()
return 0;
}
int32_t icelink_sys_get_info()
{
int32_t sys_info;
struct icelink_packet_head *ph;
ph = (struct icelink_packet_head *)&icelink_handle.packet_buffer[1];
ph->vendor_cmd = ID_DAP_Vendor13;
ph->icelink_cmd = CMD_SYS_GET_INFO;
if (icelink_usb_xfer_wait(3) != 0) {
fprintf(stderr, "iCELink CMD_SYS_GET_INFO failed.\n");
return -1;
}
sys_info = *((int32_t *)(&(icelink_handle.packet_buffer[2])));
return sys_info;
}
int32_t icelink_sys_get_id(char *id)
{
int i;
struct icelink_packet_head *ph;
uint8_t *pb;
uint32_t size;
pb = (uint8_t *)&icelink_handle.packet_buffer[1];
//pb[0] = ID_DAP_Vendor0;
pb[0] = 0x00; /* ID_DAP_Info */
pb[1] = 0x03; /* DAP_ID_SER_NUM */
if (icelink_usb_xfer(3) != 0) {
fprintf(stderr, "iCELink ID_DAP_Vendor0 failed.\n");
return -1;
}
pb = &(icelink_handle.packet_buffer[0]);
size = pb[1];
#if 0
for(i = 0; i < 8; i++) {
fprintf(stdout, "pb[%d]: 0x%x\n", i, pb[i]);
}
#endif
memcpy(id, &pb[2], size);
return 0;
}
int icelink_gpio_mode(uint32_t gpio_port, uint32_t gpio_index, uint32_t gpio_mode)
{
struct icelink_packet_head *ph;
ph = (struct icelink_packet_head *)&icelink_handle.packet_buffer[1];
ph->vendor_cmd = ID_DAP_Vendor13;
ph->icelink_cmd = CMD_SYS_GPIO_MODE;
writel(&(ph->data[0]), gpio_port);
writel(&(ph->data[4]), gpio_index);
writel(&(ph->data[8]), gpio_mode);
if (icelink_usb_xfer_wait(15) != 0) {
fprintf(stderr, "iCELink CMD_SYS_GPIO_MODE failed.\n");
return -1;
}
return 0;
}
int32_t icelink_gpio_read(uint32_t gpio_port, uint32_t gpio_index)
{
struct icelink_packet_head *ph;
ph = (struct icelink_packet_head *)&icelink_handle.packet_buffer[1];
ph->vendor_cmd = ID_DAP_Vendor13;
ph->icelink_cmd = CMD_SYS_GPIO_READ;
writel(&(ph->data[0]), gpio_port);
writel(&(ph->data[4]), gpio_index);
if (icelink_usb_xfer_wait(11) != 0) {
fprintf(stderr, "iCELink CMD_SYS_GPIO_MODE failed.\n");
return -1;
}
return readl(&(icelink_handle.packet_buffer[2]));
}
int32_t icelink_gpio_write(uint32_t gpio_port, uint32_t gpio_index, uint32_t gpio_value)
{
struct icelink_packet_head *ph;
ph = (struct icelink_packet_head *)&icelink_handle.packet_buffer[1];
ph->vendor_cmd = ID_DAP_Vendor13;
ph->icelink_cmd = CMD_SYS_GPIO_WRITE;
writel(&(ph->data[0]), gpio_port);
writel(&(ph->data[4]), gpio_index);
writel(&(ph->data[8]), gpio_value);
if (icelink_usb_xfer_wait(15) != 0) {
fprintf(stderr, "iCELink CMD_SYS_GPIO_WRITE failed.\n");
return -1;
}
return 0;
}
int32_t icelink_jtag_info()
{
uint32_t jtag_num;
struct icelink_packet_head *ph;
ph = (struct icelink_packet_head *)&icelink_handle.packet_buffer[1];
ph->vendor_cmd = ID_DAP_Vendor13;
ph->icelink_cmd = CMD_SYS_JTAG_INFO;
if (icelink_usb_xfer_wait(3) != 0) {
fprintf(stderr, "iCELink CMD_SYS_JTAG_INFO failed.\n");
return -1;
}
jtag_num = *((uint32_t *)(&(icelink_handle.packet_buffer[2])));
return jtag_num;
}
int32_t icelink_jtag_select(int jtag_num)
{
struct icelink_packet_head *ph;
ph = (struct icelink_packet_head *)&icelink_handle.packet_buffer[1];
if (board_type == BT_iCESugar_Pro) {
ph->vendor_cmd = ID_DAP_Vendor13;
ph->icelink_cmd = CMD_SYS_JTAG_SEL;
writel(&(ph->data[0]), jtag_num);
if (icelink_usb_xfer_wait(7) != 0) {
fprintf(stderr, "iCELink CMD_SYS_JTAG_SEL failed.\n");
return -1;
}
jtag_num = icelink_jtag_info();
fprintf(stdout, "JTAG --> [JTAG-%d]\n", jtag_num);
fputs (("\
[JTAG-1] \n\
TCK: iCELink-PB4 -- ECP5-JTAG-TCK (25F-BG256-T10) \n\
TMS: iCELink-PA15 -- ECP5-JTAG-TMS (25F-BG256-T11) \n\
TDI: iCELink-PB3 -- ECP5-JTAG-TDI (25F-BG256-R11) \n\
TDO: iCELink-PB5 -- ECP5-JTAG-TDO (25F-BG256-M10) \n\
\n\
[JTAG-2] \n\
TCK: iCELink-PB0 -- ECP5-IO-PL8D (25F-BG256-F5) \n\
TMS: iCELink-PB1 -- ECP5-IO-PL17A (25F-BG256-H5) \n\
TDI: iCELink-PB8 -- ECP5-IO-PL38A (25F-BG256-N4) \n\
TDO: iCELink-PB9 -- ECP5-IO-PL17D (25F-BG256-J5) \n\n\
"), stdout);
} else {
fprintf(stdout, "only iCESugar-Pro support jtag select\r\n");
}
return 0;
}
int32_t icelink_mco_info()
{
int i;
uint32_t mco_source;
struct icelink_packet_head *ph;
char *clk_desc[] = {"dummy", " 8MHz", "12MHz", "36MHz", "72MHz"};
ph = (struct icelink_packet_head *)&icelink_handle.packet_buffer[1];
ph->vendor_cmd = ID_DAP_Vendor13;
ph->icelink_cmd = CMD_SYS_MCO_INFO;
if (icelink_usb_xfer_wait(3) != 0) {
fprintf(stderr, "iCELink CMD_SYS_JTAG_INFO failed.\n");
return -1;
}
mco_source = *((uint32_t *)(&(icelink_handle.packet_buffer[2])));
fprintf(stdout, "CLK -> [%s]\n", clk_desc[mco_source]);
fprintf(stdout, "CLK-SELECT:\n");
for(i = 1; i < MCO_MAX; i++) {
fprintf(stdout, "\t[%d]: %s\n", i, clk_desc[i]);
}
return mco_source;
}
int32_t icelink_mco_select(int mco_source)
{
struct icelink_packet_head *ph;
ph = (struct icelink_packet_head *)&icelink_handle.packet_buffer[1];
if (board_type == BT_iCESugar_Nano) {
ph->vendor_cmd = ID_DAP_Vendor13;
ph->icelink_cmd = CMD_SYS_MCO_SEL;
writel(&(ph->data[0]), mco_source);
if (icelink_usb_xfer_wait(7) != 0) {
fprintf(stderr, "iCELink CMD_SYS_MCO_SEL failed.\n");
return -1;
}
} else {
fprintf(stdout, "only iCESugar-Nano support mco select\r\n");
}
return 0;
}
int32_t icelink_sys_get_board_type()
{
char board_id[128] = {0};
icelink_sys_get_id(board_id);
//fprintf(stdout, "board_id: %s\n", board_id);
if (strncmp(board_id, "0700", 4) == 0) {
board_type = BT_iCESugar;
} else if (strncmp(board_id, "0710", 4) == 0) {
board_type = BT_iCESugar_Pro;
} else if (strncmp(board_id, "0720", 4) == 0) {
board_type = BT_iCESugar_Nano;
} else {
board_type = BT_Unknown;
}
return board_type;
}
int32_t icelink_dump_board_info(uint32_t board_type, uint32_t flash_id)
{
switch (board_type) {
case (BT_iCESugar):
fprintf(stdout, "board: [iCESugar]\n");
break;
case (BT_iCESugar_Pro):
fprintf(stdout, "board: [iCESugar-Pro]\n");
break;
case (BT_iCESugar_Nano):
fprintf(stdout, "board: [iCESugar-Nano]\n");
break;
default:
fprintf(stdout, "board: [Unknown]\n");
break;
}
//fprintf(stdout, "flash id: 0x%x ", flash_id);
switch (flash_id) {
case (0xEF4015):
fprintf(stdout, "flash: [w25q16] (4MB)\n");
flash_size = 4 * 1024 * 1024;
break;
case (0xEF4017):
fprintf(stdout, "flash: [w25q64] (8MB)\n");
flash_size = 8 * 1024 * 1024;
break;
case (0xEF4018):
fprintf(stdout, "flash: [w25q128] (16MB)\n");
flash_size = 16 * 1024 * 1024;
break;
default:
fprintf(stdout, "flash: unknown flash id 0x%x (??MB)\n", flash_id);
break;
}
}
void icelink_close()
{
hid_close(icelink_handle.dev_handle);
@@ -514,30 +838,58 @@ void usage(char *program_name)
{
printf("usage: %s [OPTION] [FILE]\n", program_name);
fputs (("\
-w | --write write spi-flash \n\
-r | --read read spi-flash \n\
-w | --write write spi-flash or gpio \n\
-r | --read read spi-flash or gpio \n\
-e | --erase erase spi-flash \n\
-p | --probe probe spi-flash \n\
-o | --offset spi-flash offset \n\
-l | --len len of write/read \n\
-g | --gpio icelink gpio write/read \n\
-m | --mode icelink gpio mode \n\
-j | --jtag-sel jtag interface select (1 or 2) \n\
-c | --clk-sel clk source select (1 to 4) \n\
-h | --help display help info \n\n\
-- version 1.0 --\n\
-- version 1.1a --\n\
"), stdout);
exit(0);
}
static struct option const long_options[] =
{
{"write", no_argument, NULL, 'w'},
{"read", no_argument, NULL, 'r'},
{"erase", no_argument, NULL, 'e'},
{"probe", no_argument, NULL, 'p'},
{"offset", required_argument, NULL, 'o'},
{"len", required_argument, NULL, 'l'},
{"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0}, // avoid crashes due to unsupported options
{"write", no_argument, NULL, 'w'},
{"read", no_argument, NULL, 'r'},
{"erase", no_argument, NULL, 'e'},
{"probe", no_argument, NULL, 'p'},
{"offset", required_argument, NULL, 'o'},
{"len", required_argument, NULL, 'l'},
/* gpio */
{"gpio", required_argument, NULL, 'g'},
{"mode", required_argument, NULL, 'm'},
/* jtag select */
{"jtag-sel", required_argument, NULL, 'j'},
/* clk select */
{"clk-sel", required_argument, NULL, 'c'},
{"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0 },
};
/* stm32f1xx_hal_gpio.h */
uint32_t gpio_mode_map(char *s)
{
if (strcmp(s, "in") == 0) {
return 0; /* GPIO_MODE_INPUT */
} else if (strcmp(s, "out") == 0) {
return 1; /* GPIO_MODE_OUTPUT_PP */
} else {
fprintf(stderr, "invalid gpio mode %s\n", s);
exit(-1);
}
}
int main(int argc, char **argv)
{
char *ifile = NULL;
@@ -553,27 +905,33 @@ int main(int argc, char **argv)
uint32_t len = 0;
uint32_t flash_offset = 0, sector_num = 0;
int mode = 1; /* read: 0; write: 1; erase all: 2 */
uint32_t gpio_port = 0, gpio_index, gpio_value;
int32_t gpio_mode = -1;
int jtag_sel = -1;
int mco_sel = -1;
int op_mode = 1; /* read: 0; write: 1; erase all: 2 */
if (argc == 1) {
usage(argv[0]);
exit(-1);
}
while ((c = getopt_long (argc, argv, "wrpel:o:h",
while ((c = getopt_long (argc, argv, "wrpel:o:g:m:j:c:h",
long_options, &option_index)) != -1) {
switch (c) {
case ('r'):
mode = 0;
op_mode = 0;
break;
case ('w'):
mode = 1;
op_mode = 1;
break;
case ('e'):
mode = 2;
op_mode = 2;
break;
case ('p'):
mode = 3;
op_mode = 3;
break;
case ('l'):
len = strtoul(optarg, NULL, 0);
@@ -581,12 +939,26 @@ int main(int argc, char **argv)
case ('o'):
flash_offset = strtoul(optarg, NULL, 0);
break;
case ('g'):
//gpio_num = strtoul(&optarg[1], NULL, 16);
gpio_port = 0xA + (optarg[1] - 'A');
gpio_index = strtoul(&optarg[2], NULL, 0);
break;
case ('m'):
gpio_mode = gpio_mode_map(optarg);
break;
case ('j'):
jtag_sel = strtoul(optarg, NULL, 0);
break;
case ('c'):
mco_sel = strtoul(optarg, NULL, 0);
break;
case ('h'):
usage(argv[0]);
break;
exit(0);
default:
usage(argv[0]);
break;
exit(0);
}
}
@@ -601,90 +973,143 @@ int main(int argc, char **argv)
//icelink_flash_get_info();
//icelink_flash_dump_sector(0);
if (mode == 0) { /* read spi-flash */
fprintf(stdout, "flash offset: 0x%08x\r\n", flash_offset);
fprintf(stdout, "read flash (%d (0x%x) Bytes)\r\n", len, len);
if (len == 0) {
fprintf(stderr, "use -l to set read len\r\n");
if (jtag_sel != -1) {
/* jtag select */
if (jtag_sel == 1 || jtag_sel == 2) {
icelink_sys_get_board_type();
icelink_jtag_select(jtag_sel);
} else {
fprintf(stderr, "invalid jtag_num [%d] (should be 1 or 2)\r\n", jtag_sel);
exit(-1);
}
//icelink_flash_get_info();
} else if (mco_sel != -1) {
icelink_sys_get_board_type();
if (mco_sel == 0 || (mco_sel >= MCO_MAX)) {
//fprintf(stdout, "mco_info:\n");
icelink_mco_info();
} else {
icelink_mco_select(mco_sel);
icelink_mco_info();
}
if ((flash_offset + len) > SPI_FLASH_SIZE) {
fprintf(stderr, "invalid read region [0x%08x, 0x%08x]\r\n", flash_offset, flash_offset + len);
} else if (gpio_port != 0) {
/* gpio control */
//fprintf(stdout, "gpio_port P%X\r\n", gpio_port);
//fprintf(stdout, "gpio_index %d\r\n", gpio_index);
if ((gpio_port >= 0xA && gpio_port <=0xF) && (gpio_index >= 0 && gpio_index <= 15)) {
if (gpio_mode != -1) { /* gpio mode */
fprintf(stdout, "gpio mode P%X%d 0x%x\r\n", gpio_port, gpio_index, gpio_mode);
icelink_gpio_mode(gpio_port, gpio_index, gpio_mode);
} else if (op_mode == 0) { /* gpio read */
gpio_value = icelink_gpio_read(gpio_port, gpio_index);
fprintf(stdout, "gpio read P%X%d return %d\r\n", gpio_port, gpio_index, gpio_value);
} else if (op_mode == 1) { /* gpio write */
gpio_value = strtoul(argv[argc - 1], NULL, 0);
fprintf(stdout, "gpio write P%X%d %d\r\n", gpio_port, gpio_index, gpio_value);
icelink_gpio_write(gpio_port, gpio_index, gpio_value);
}
} else {
fprintf(stderr, "invalid gpio_num %X%d\r\n", gpio_port, gpio_index);
exit(-1);
}
if ((flash_buf = malloc(SPI_FLASH_SECTOR_ALIGN_UP(len))) == NULL) {
perror("malloc");
exit(-1);
} else {
/* flash access */
if (op_mode == 0) { /* read spi-flash */
fprintf(stdout, "flash offset: 0x%08x\r\n", flash_offset);
fprintf(stdout, "read flash (%d (0x%x) Bytes)\r\n", len, len);
if (len == 0) {
fprintf(stderr, "use -l to set read len\r\n");
exit(-1);
}
//icelink_flash_get_info();
if ((flash_offset + len) > SPI_FLASH_SIZE) {
fprintf(stderr, "invalid read region [0x%08x, 0x%08x]\r\n", flash_offset, flash_offset + len);
exit(-1);
}
if ((flash_buf = malloc(SPI_FLASH_SECTOR_ALIGN_UP(len))) == NULL) {
perror("malloc");
exit(-1);
}
memset(flash_buf, 0, SPI_FLASH_SECTOR_ALIGN_UP(len));
sector_num = SPI_FLASH_SECTOR_ALIGN_UP(len) / SPI_FLASH_SECTOR_SIZE;
icelink_flash_read_sectors(flash_offset, sector_num, flash_buf);
if ((fd = open(ifile, O_CREAT | O_RDWR | O_TRUNC | O_BINARY, 0664)) == -1) {
perror("open");
exit(-1);
}
if (write(fd, flash_buf, len) != len) {
perror("write");
exit(-1);
}
close(fd);
} else if (op_mode == 1) { /* write spi-flash */
fprintf(stdout, "flash offset: 0x%08x\r\n", flash_offset);
if ((fd = open(ifile, O_RDONLY | O_BINARY)) == -1) {
perror("open");
exit(-1);
}
if ((fstat(fd, &st)) == -1) {
perror("fstat");
exit(-1);
}
fprintf(stdout, "write flash (%d (0x%x) Bytes)\r\n", (uint32_t)st.st_size, (uint32_t)st.st_size);
if ((flash_buf = malloc(SPI_FLASH_SECTOR_ALIGN_UP(st.st_size))) == NULL) {
perror("malloc");
exit(-1);
}
memset(flash_buf, 0, SPI_FLASH_SECTOR_ALIGN_UP(st.st_size));
if (read(fd, flash_buf, st.st_size) != st.st_size) {
perror("read");
exit(-1);
}
/* FIXME: overflow check */
sector_num = SPI_FLASH_SECTOR_ALIGN_UP(st.st_size) / SPI_FLASH_SECTOR_SIZE;
icelink_flash_write_sectors(flash_offset, sector_num, flash_buf);
close(fd);
} else if (op_mode == 2) { /* erase chip */
fprintf(stdout, "erase chip\n");
icelink_flash_erase_chip();
} else if (op_mode == 3) { /* probe chip */
fprintf(stdout, "probe chip\n");
icelink_sys_get_board_type();
icelink_flash_get_info(0);
icelink_dump_board_info(board_type, flash_id);
}
memset(flash_buf, 0, SPI_FLASH_SECTOR_ALIGN_UP(len));
sector_num = SPI_FLASH_SECTOR_ALIGN_UP(len) / SPI_FLASH_SECTOR_SIZE;
icelink_flash_read_sectors(flash_offset, sector_num, flash_buf);
if ((fd = open(ifile, O_CREAT | O_RDWR | O_TRUNC | O_BINARY, 0664)) == -1) {
perror("open");
exit(-1);
}
if (write(fd, flash_buf, len) != len) {
perror("write");
exit(-1);
}
close(fd);
} else if (mode == 1) { /* write spi-flash */
fprintf(stdout, "flash offset: 0x%08x\r\n", flash_offset);
if ((fd = open(ifile, O_RDONLY | O_BINARY)) == -1) {
perror("open");
exit(-1);
}
if ((fstat(fd, &st)) == -1) {
perror("fstat");
exit(-1);
}
fprintf(stdout, "write flash (%d (0x%x) Bytes)\r\n", (uint32_t)st.st_size, (uint32_t)st.st_size);
if ((flash_buf = malloc(SPI_FLASH_SECTOR_ALIGN_UP(st.st_size))) == NULL) {
perror("malloc");
exit(-1);
}
memset(flash_buf, 0, SPI_FLASH_SECTOR_ALIGN_UP(st.st_size));
if (read(fd, flash_buf, st.st_size) != st.st_size) {
perror("read");
exit(-1);
}
/* FIXME: overflow check */
sector_num = SPI_FLASH_SECTOR_ALIGN_UP(st.st_size) / SPI_FLASH_SECTOR_SIZE;
icelink_flash_write_sectors(flash_offset, sector_num, flash_buf);
close(fd);
} else if (mode == 2) { /* erase chip */
fprintf(stdout, "erase chip\n");
icelink_flash_erase_chip();
} else if (mode == 3) { /* probe chip */
fprintf(stdout, "probe chip\n");
icelink_flash_get_info();
}
fprintf(stdout, "done\n");
//icelink_ram_dump();
icelink_close();
free(flash_buf);
if (flash_buf) {
free(flash_buf);
}
return 0;