diff options
author | Vincent Palatin <vpalatin@chromium.org> | 2017-03-16 18:06:39 +0100 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2017-03-28 03:47:41 -0700 |
commit | bbd8daec122cb985c8b1f7de49afd04d7bb9c603 (patch) | |
tree | 20f246fa39e9e57c317fcbf56e9dd4be4af474fe | |
parent | 891c48239b618ee2c33adff328bedb658b01d1b4 (diff) | |
download | chrome-ec-bbd8daec122cb985c8b1f7de49afd04d7bb9c603.tar.gz |
stm32mon: add support for SPI flashing mode
Allow to flash an STM32 in bootloader mode through its SPI slave
interface.
Signed-off-by: Vincent Palatin <vpalatin@chromium.org>
BRANCH=none
BUG=b:36125319
TEST=run from Eve AP:
export SPIDEV="/dev/spidev32765.0"
export GPIO_NRST=418
export GPIO_BOOT0=419
echo ${GPIO_BOOT0} > /sys/class/gpio/export
echo "out" > /sys/class/gpio/gpio${GPIO_BOOT0}/direction
echo ${GPIO_NRST} > /sys/class/gpio/export
echo "out" > /sys/class/gpio/gpio${GPIO_NRST}/direction
echo 1 > /sys/class/gpio/gpio${GPIO_BOOT0}/value
echo 0 > /sys/class/gpio/gpio${GPIO_NRST}/value
echo 1 > /sys/class/gpio/gpio${GPIO_NRST}/value
stm32mon -s ${SPIDEV} -r /tmp/mcu-image.bin
echo 0 > /sys/class/gpio/gpio${GPIO_BOOT0}/value
echo 0 > /sys/class/gpio/gpio${GPIO_NRST}/value
echo 1 > /sys/class/gpio/gpio${GPIO_NRST}/value
echo "in" > /sys/class/gpio/gpio${GPIO_BOOT0}/direction
echo "in" > /sys/class/gpio/gpio${GPIO_NRST}/direction
re-verify UART flashing mode with 'flash_ec --board=eve_fp'
Change-Id: Ic268dd9e62a2f279dd7992a4bbcf16fcf44c5f9e
Reviewed-on: https://chromium-review.googlesource.com/456596
Commit-Ready: Vincent Palatin <vpalatin@chromium.org>
Tested-by: Vincent Palatin <vpalatin@chromium.org>
Reviewed-by: Todd Broch <tbroch@chromium.org>
-rw-r--r-- | util/stm32mon.c | 115 |
1 files changed, 99 insertions, 16 deletions
diff --git a/util/stm32mon.c b/util/stm32mon.c index aa395534ab..2ff127b358 100644 --- a/util/stm32mon.c +++ b/util/stm32mon.c @@ -27,6 +27,7 @@ #include <sys/ioctl.h> #include <sys/stat.h> #include <linux/i2c-dev.h> +#include <linux/spi/spidev.h> #include <termios.h> #include <time.h> #include <unistd.h> @@ -50,11 +51,17 @@ #define RESP_NACK 0x1f #define RESP_ACK 0x79 +/* SPI Start of Frame */ +#define SOF 0x5A + /* Extended erase special parameters */ #define ERASE_ALL 0xffff #define ERASE_BANK1 0xfffe #define ERASE_BANK2 0xfffd +/* Upper bound of fully erasing the flash and rebooting the monitor */ +#define MAX_DELAY_MASS_ERASE_REBOOT 100000 /* us */ + /* known STM32 SoC parameters */ struct stm32_def { uint16_t id; @@ -83,9 +90,16 @@ struct stm32_def { #define PAGE_SIZE 256 #define INVALID_I2C_ADAPTER -1 +enum interface_mode { + MODE_SERIAL, + MODE_I2C, + MODE_SPI, +} mode = MODE_SERIAL; + /* store custom parameters */ speed_t baudrate = DEFAULT_BAUDRATE; int i2c_adapter = INVALID_I2C_ADAPTER; +const char *spi_adapter; const char *serial_port = "/dev/ttyUSB1"; const char *input_filename; const char *output_filename; @@ -202,14 +216,43 @@ int open_i2c(const int port) return fd; } +int open_spi(const char *port) +{ + int fd; + int res; + uint32_t mode = SPI_MODE_0; + uint8_t bits = 8; + + fd = open(port, O_RDWR); + if (fd == -1) { + perror("Unable to open SPI controller"); + return -1; + } + + res = ioctl(fd, SPI_IOC_WR_MODE32, &mode); + if (res == -1) { + perror("Cannot set SPI mode"); + close(fd); + return -1; + } + + res = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits); + if (res == -1) { + perror("Cannot set SPI bits per word"); + close(fd); + return -1; + } + + return fd; +} static void discard_input(int fd) { uint8_t buffer[64]; int res, i; - /* Skip in i2c mode */ - if (i2c_adapter != INVALID_I2C_ADAPTER) + /* Skip in i2c and spi modes */ + if (mode != MODE_SERIAL) return; /* eat trailing garbage */ @@ -229,6 +272,7 @@ int wait_for_ack(int fd) uint8_t resp; int res; time_t deadline = time(NULL) + DEFAULT_TIMEOUT; + uint8_t ack = RESP_ACK; while (time(NULL) < deadline) { res = read(fd, &resp, 1); @@ -237,14 +281,22 @@ int wait_for_ack(int fd) return -EIO; } if (res == 1) { - if (resp == RESP_ACK) + if (resp == RESP_ACK) { + if (mode == MODE_SPI) /* Ack the ACK */ + if (write(fd, &ack, 1) != 1) + return -EIO; return 0; - else if (resp == RESP_NACK) { + } else if (resp == RESP_NACK) { fprintf(stderr, "NACK\n"); + if (mode == MODE_SPI) /* Ack the NACK */ + if (write(fd, &ack, 1) != 1) + return -EIO; discard_input(fd); return -EINVAL; } else { - fprintf(stderr, "Receive junk: %02x\n", resp); + if (mode == MODE_SERIAL) + fprintf(stderr, "Receive junk: %02x\n", + resp); } } } @@ -258,10 +310,12 @@ int send_command(int fd, uint8_t cmd, payload_t *loads, int cnt, int res, i, c; payload_t *p; int readcnt = 0; - uint8_t cmd_frame[] = { cmd, 0xff ^ cmd }; /* XOR checksum */ + uint8_t cmd_frame[] = { SOF, cmd, 0xff ^ cmd }; /* XOR checksum */ + /* only the SPI mode needs the Start Of Frame byte */ + int cmd_off = mode == MODE_SPI ? 0 : 1; /* Send the command index */ - res = write(fd, cmd_frame, 2); + res = write(fd, cmd_frame + cmd_off, sizeof(cmd_frame) - cmd_off); if (res <= 0) { perror("Failed to write command frame"); return -1; @@ -315,6 +369,9 @@ int send_command(int fd, uint8_t cmd, payload_t *loads, int cnt, /* Read the answer payload */ if (resp) { + if (mode == MODE_SPI) /* ignore dummy byte */ + if (read(fd, resp, 1) < 0) + return -1; while ((resp_size > 0) && (res = read(fd, resp, resp_size))) { if (res < 0) { perror("Failed to read payload"); @@ -368,10 +425,10 @@ struct stm32_def *command_get_id(int fd) int init_monitor(int fd) { int res; - uint8_t init = CMD_INIT; + uint8_t init = mode == MODE_SPI ? SOF : CMD_INIT; /* Skip in i2c mode */ - if (i2c_adapter != INVALID_I2C_ADAPTER) + if (mode == MODE_I2C) return 0; printf("Waiting for the monitor startup ..."); @@ -435,7 +492,7 @@ int command_get_commands(int fd, struct stm32_def *chip) printf("%02x ", cmds[i]); } - if (i2c_adapter != INVALID_I2C_ADAPTER) + if (mode == MODE_I2C) erase = command_erase_i2c; printf("\n"); @@ -632,7 +689,13 @@ int command_read_unprotect(int fd) } printf("Flash read unprotected.\n"); - /* This commands triggers a reset */ + /* + * This command triggers a reset. + * + * Wait at least the 'mass-erase' delay, else we could reconnect + * before the actual reset depending on the bootloader. + */ + usleep(MAX_DELAY_MASS_ERASE_REBOOT); if (init_monitor(fd) < 0) { fprintf(stderr, "Cannot recover after RP reset\n"); return -EIO; @@ -656,7 +719,13 @@ int command_write_unprotect(int fd) } printf("Flash write unprotected.\n"); - /* This commands triggers a reset */ + /* + * This command triggers a reset. + * + * Wait at least the 'mass-erase' delay, else we could reconnect + * before the actual reset depending on the bootloader. + */ + usleep(MAX_DELAY_MASS_ERASE_REBOOT); if (init_monitor(fd) < 0) { fprintf(stderr, "Cannot recover after WP reset\n"); return -EIO; @@ -779,6 +848,7 @@ static const struct option longopts[] = { {"unprotect", 0, 0, 'u'}, {"baudrate", 1, 0, 'b'}, {"adapter", 1, 0, 'a'}, + {"spi", 1, 0, 's'}, {NULL, 0, 0, 0} }; @@ -799,6 +869,7 @@ void display_usage(char *program) fprintf(stderr, "--e[rase] : erase all the flash content\n"); fprintf(stderr, "--r[ead] <file> : read the flash content and " "write it into <file>\n"); + fprintf(stderr, "--s[pi] </dev/spi> : use SPI adapter on </dev>.\n"); fprintf(stderr, "--w[rite] <file|-> : read <file> or\n\t" "standard input and write it to flash\n"); fprintf(stderr, "--g[o] : jump to execute flash entrypoint\n"); @@ -833,17 +904,19 @@ int parse_parameters(int argc, char **argv) int opt, idx; int flags = 0; - while ((opt = getopt_long(argc, argv, "a:b:d:eghr:w:uU?", + while ((opt = getopt_long(argc, argv, "a:b:d:eghr:s:w:uU?", longopts, &idx)) != -1) { switch (opt) { case 'a': i2c_adapter = atoi(optarg); + mode = MODE_I2C; break; case 'b': baudrate = parse_baudrate(optarg); break; case 'd': serial_port = optarg; + mode = MODE_SERIAL; break; case 'e': flags |= FLAG_ERASE; @@ -858,6 +931,10 @@ int parse_parameters(int argc, char **argv) case 'r': input_filename = optarg; break; + case 's': + spi_adapter = optarg; + mode = MODE_SPI; + break; case 'w': output_filename = optarg; break; @@ -882,11 +959,17 @@ int main(int argc, char **argv) /* Parse command line options */ flags = parse_parameters(argc, argv); - if (i2c_adapter == INVALID_I2C_ADAPTER) { + switch (mode) { + case MODE_SPI: + ser = open_spi(spi_adapter); + break; + case MODE_I2C: + ser = open_i2c(i2c_adapter); + break; + case MODE_SERIAL: + default: /* Open the serial port tty */ ser = open_serial(serial_port); - } else { - ser = open_i2c(i2c_adapter); } if (ser < 0) return 1; |