summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent Palatin <vpalatin@chromium.org>2017-03-16 18:06:39 +0100
committerchrome-bot <chrome-bot@chromium.org>2017-03-28 03:47:41 -0700
commitbbd8daec122cb985c8b1f7de49afd04d7bb9c603 (patch)
tree20f246fa39e9e57c317fcbf56e9dd4be4af474fe
parent891c48239b618ee2c33adff328bedb658b01d1b4 (diff)
downloadchrome-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.c115
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;