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>
This commit is contained in:
Vincent Palatin
2017-03-16 18:06:39 +01:00
committed by chrome-bot
parent 891c48239b
commit bbd8daec12

View File

@@ -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;