summaryrefslogtreecommitdiff
path: root/util/stm32mon.c
diff options
context:
space:
mode:
Diffstat (limited to 'util/stm32mon.c')
-rw-r--r--util/stm32mon.c1758
1 files changed, 0 insertions, 1758 deletions
diff --git a/util/stm32mon.c b/util/stm32mon.c
deleted file mode 100644
index 7be802b1ed..0000000000
--- a/util/stm32mon.c
+++ /dev/null
@@ -1,1758 +0,0 @@
-/* Copyright 2012 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- *
- * STM32 SoC system monitor interface tool
- * For Serial, implement protocol v2.0 as defined in:
- * http://www.st.com/st-web-ui/static/active/en/resource/technical/\
- * document/application_note/CD00264342.pdf
- *
- * For i2C, implement protocol v1.0 as defined in:
- * http://www.st.com/st-web-ui/static/active/en/resource/technical/\
- * document/application_note/DM00072315.pdf
- *
- * For SPI, implement protocol v1.1 as defined in:
- * https://www.st.com/resource/en/application_note/dm00081379.pdf
- */
-
-/* use cfmakeraw() */
-#define _DEFAULT_SOURCE /* Newer glibc */
-#define _BSD_SOURCE /* Older glibc */
-
-#include <arpa/inet.h>
-#include <compile_time_macros.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#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>
-
-#include "ec_version.h"
-
-#define KBYTES_TO_BYTES 1024
-
-/*
- * Some Ubuntu versions do not export SPI_IOC_WR_MODE32 even though
- * the kernel shipped on those supports it.
- */
-#ifndef SPI_IOC_WR_MODE32
-#define SPI_IOC_WR_MODE32 _IOW(SPI_IOC_MAGIC, 5, __u32)
-#endif
-
-/* Monitor command set */
-#define CMD_INIT 0x7f /* Starts the monitor */
-
-#define CMD_GETCMD 0x00 /* Gets the allowed commands */
-#define CMD_GETVER 0x01 /* Gets the bootloader version */
-#define CMD_GETID 0x02 /* Gets the Chip ID */
-#define CMD_READMEM 0x11 /* Reads memory */
-#define CMD_GO 0x21 /* Jumps to user code */
-#define CMD_WRITEMEM 0x31 /* Writes memory (SRAM or Flash) */
-#define CMD_ERASE 0x43 /* Erases n pages of Flash memory */
-#define CMD_EXTERASE 0x44 /* Erases n pages of Flash memory */
-#define CMD_NO_STRETCH_ERASE 0x45 /* Erases while sending busy frame */
-#define CMD_WP 0x63 /* Enables write protect */
-#define CMD_WU 0x73 /* Disables write protect */
-#define CMD_RP 0x82 /* Enables the read protection */
-#define CMD_RU 0x92 /* Disables the read protection */
-
-#define CMD_LOOKUP_ENTRY(COMMAND) {CMD_##COMMAND, #COMMAND}
-const struct {
- const uint8_t cmd;
- const char *name;
-} cmd_lookup_table[] = {
- CMD_LOOKUP_ENTRY(INIT),
- CMD_LOOKUP_ENTRY(GETCMD),
- CMD_LOOKUP_ENTRY(GETVER),
- CMD_LOOKUP_ENTRY(GETID),
- CMD_LOOKUP_ENTRY(READMEM),
- CMD_LOOKUP_ENTRY(GO),
- CMD_LOOKUP_ENTRY(WRITEMEM),
- CMD_LOOKUP_ENTRY(ERASE),
- CMD_LOOKUP_ENTRY(EXTERASE),
- CMD_LOOKUP_ENTRY(NO_STRETCH_ERASE),
- CMD_LOOKUP_ENTRY(WP),
- CMD_LOOKUP_ENTRY(WU),
- CMD_LOOKUP_ENTRY(RP),
- CMD_LOOKUP_ENTRY(RU),
-};
-
-const char *cmd_lookup_name(uint8_t cmd)
-{
- int i;
- for (i = 0; i < ARRAY_SIZE(cmd_lookup_table); i++) {
- if (cmd_lookup_table[i].cmd == cmd)
- return cmd_lookup_table[i].name;
- }
-
- return NULL;
-}
-
-#define RESP_NACK 0x1f
-#define RESP_ACK 0x79 /* 0b 0111 1001 */
-#define RESP_BUSY 0x76
-#define RESP_DAMAGED_ACK 0xBC /* 0b 1011 1100, 1 bit shifted REST_ACK */
-
-/* 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 rebooting the monitor */
-#define MAX_DELAY_REBOOT 100000 /* us */
-
-/* Standard addresses common across various ST chips */
-#define STM32_MAIN_MEMORY_ADDR 0x08000000
-#define STM32_SYSTEM_MEMORY_ADDR 0x1FFF0000
-
-#define STM32_UNIQUE_ID_SIZE_BYTES 12
-
-/*
- * Device electronic signature contains factory-programmed identification
- * and calibration data to automatically match the characteristics of the
- * microcontroller.
- */
-struct stm32_device_signature {
- /*
- * Address of the Unique Device ID register. This register contains a
- * 96-bit value that is unique across all chips.
- * Zero means ignore/unknown.
- */
- uint32_t unique_device_id_addr;
- /*
- * Address of the Flash Size register. This 16-bit register contains the
- * flash size in KB.
- * Zero means ignore/unknown.
- */
- uint32_t flash_size_addr;
- /*
- * Address of the Package Data register. This 16-bit register contains a
- * value that differentiates between package types of a given chip.
- * Zero means ignore/unknown.
- */
- uint32_t package_data_addr;
-};
-
-struct memory_info {
- /* Zero means ignore/unknown/not-applicable */
- uint32_t addr;
- /* If addr is non-zero
- * - zero here means value is dynamic and will be read from bootloader.
- * If addr is zero,
- * - zero here means ignore/unknown/not-applicable.
- */
- uint32_t size_bytes;
-};
-
-struct memory_layout {
- struct memory_info main_memory;
- struct memory_info system_memory;
- struct memory_info otp_area;
- struct memory_info option_bytes;
-};
-
-/* known STM32 SoC parameters */
-struct stm32_def {
- uint16_t id;
- const char *name;
- uint32_t flash_size;
- uint32_t page_size;
- uint32_t cmds_len[2];
- const struct memory_layout memory_layout;
- const struct stm32_device_signature device_signature;
-} chip_defs[] = {
- {0x416, "STM32L15xxB", 0x20000, 256, {13, 13}, { { 0 } }, { 0 } },
- {0x429, "STM32L15xxB-A", 0x20000, 256, {13, 13}, { { 0 } }, { 0 } },
- {0x427, "STM32L15xxC", 0x40000, 256, {13, 13}, { { 0 } }, { 0 } },
- {0x435, "STM32L44xx", 0x40000, 2048, {13, 13}, { { 0 } }, { 0 } },
- {0x420, "STM32F100xx", 0x20000, 1024, {13, 13}, { { 0 } }, { 0 } },
- {0x410, "STM32F102R8", 0x10000, 1024, {13, 13}, { { 0 } }, { 0 } },
- {0x440, "STM32F05x", 0x10000, 1024, {13, 13}, { { 0 } }, { 0 } },
- {0x444, "STM32F03x", 0x08000, 1024, {13, 13}, { { 0 } }, { 0 } },
- {0x448, "STM32F07xB", 0x20000, 2048, {13, 13}, { { 0 } }, { 0 } },
- {0x432, "STM32F37xx", 0x40000, 2048, {13, 13}, { { 0 } }, { 0 } },
- {0x442, "STM32F09x", 0x40000, 2048, {13, 13}, { { 0 } }, { 0 } },
- {0x431, "STM32F411", 0x80000, 16384, {13, 19}, { { 0 } }, { 0 } },
- {
- .id = 0x441,
- .name = "STM32F412",
- .flash_size = 0x100000,
- .page_size = 16384,
- .cmds_len = {13, 19},
- /*
- * STM32F412:
- * See https://www.st.com/resource/en/reference_manual/dm00180369.pdf
- * Section 3.3 Table 5 Flash module organization
- */
- .memory_layout = {
- .main_memory = {
- .addr = STM32_MAIN_MEMORY_ADDR,
- .size_bytes = 0, /* set by flash reg read */
- },
- .system_memory = {
- .addr = STM32_SYSTEM_MEMORY_ADDR,
- .size_bytes = 30 * KBYTES_TO_BYTES,
- },
- .otp_area = {
- .addr = 0x1FFF7800,
- .size_bytes = 528,
- },
- .option_bytes = {
- .addr = 0x1FFFC000,
- .size_bytes = 16,
- }
- },
- /*
- * STM32F412:
- * See https://www.st.com/resource/en/reference_manual/dm00180369.pdf
- * Section 31 Device electronic signature
- */
- .device_signature = {
- .unique_device_id_addr = 0x1FFF7A10,
- .flash_size_addr = 0x1FFF7A22,
- /*
- * Out of range for bootloader on this chip, so we don't
- * attempt to read.
- */
- .package_data_addr = 0, /* 0x1FFF7BF0 */
- }
- },
- {0x450, "STM32H74x", 0x200000, 131768, {13, 19}, { { 0 } }, { 0 } },
- {0x451, "STM32F76x", 0x200000, 32768, {13, 19}, { { 0 } }, { 0 } },
- {
- .id = 0x460,
- .name = "STM32G071xx",
- .flash_size = 0x20000,
- .page_size = 2048,
- .cmds_len = {13, 13},
- /*
- * STM32G0x1:
- * See https://www.st.com/resource/en/reference_manual/dm00371828.pdf
- * Section 3.3.1 Table 6 Flash module organization
- */
- .memory_layout = {
- .main_memory = {
- .addr = STM32_MAIN_MEMORY_ADDR,
- .size_bytes = 0, /* set by flash reg read */
- },
- .system_memory = {
- .addr = STM32_SYSTEM_MEMORY_ADDR,
- .size_bytes = 28 * KBYTES_TO_BYTES,
- },
- .otp_area = {
- .addr = 0x1FFF7000,
- .size_bytes = 1024,
- },
- .option_bytes = {
- .addr = 0x1FFF7800,
- .size_bytes = 128,
- }
- },
- /*
- * STM32G0x1:
- * See https://www.st.com/resource/en/reference_manual/dm00371828.pdf
- * Section 38 Device electronic signature
- */
- .device_signature = {
- .unique_device_id_addr = 0x1FFF7590,
- .flash_size_addr = 0x1FFF75E0,
- /*
- * Datasheet litst as same address as e.g. STM32F412,
- * hence declaring as zero as for that other chip.
- */
- .package_data_addr = 0, /* 0x1FFF7500 */
- }
- },
- { 0 }
-};
-
-#define DEFAULT_CONNECT_RETRIES 5
-#define DEFAULT_TIMEOUT 4 /* seconds */
-#define EXT_ERASE_TIMEOUT 20 /* seconds */
-#define DEFAULT_BAUDRATE B38400
-#define PAGE_SIZE 256
-#define INVALID_I2C_ADAPTER -1
-#define MAX_ACK_RETRY_COUNT (EXT_ERASE_TIMEOUT / DEFAULT_TIMEOUT)
-#define MAX_RETRY_COUNT 3
-
-enum interface_mode {
- MODE_SERIAL,
- MODE_I2C,
- MODE_SPI,
-} mode = MODE_SERIAL;
-
-/* I2c address the EC is listening depends on the device:
- * stm32f07xxx: 0x76
- * stm32f411xx: 0x72
- */
-#define DEFAULT_I2C_SLAVE_ADDRESS 0x76
-
-/* store custom parameters */
-speed_t baudrate = DEFAULT_BAUDRATE;
-int connect_retries = DEFAULT_CONNECT_RETRIES;
-int i2c_adapter = INVALID_I2C_ADAPTER;
-const char *spi_adapter;
-int i2c_slave_address = DEFAULT_I2C_SLAVE_ADDRESS;
-uint8_t boot_loader_version;
-const char *serial_port = "/dev/ttyUSB1";
-const char *input_filename;
-const char *output_filename;
-uint32_t offset = 0x08000000, length = 0;
-int retry_on_damaged_ack;
-
-/* STM32MON function return values */
-enum {
- STM32_SUCCESS = 0,
- STM32_EIO = -1, /* IO error */
- STM32_EINVAL = -2, /* Got a faulty response from device */
- STM32_ETIMEDOUT = -3, /* Device didn't respond in a time window. */
- STM32_ENOMEM = -4, /* Failed to allocate memory. */
- STM32_ENACK = -5, /* Got NACK. */
- STM32_EDACK = -6, /* Got a damanged ACK. */
-};
-BUILD_ASSERT(STM32_SUCCESS == 0);
-#define IS_STM32_ERROR(res) ((res) < STM32_SUCCESS)
-
-/* optional command flags */
-enum {
- FLAG_UNPROTECT = 0x01,
- FLAG_ERASE = 0x02,
- FLAG_GO = 0x04,
- FLAG_READ_UNPROTECT = 0x08,
- FLAG_CR50_MODE = 0x10,
-};
-
-typedef struct {
- int size;
- uint8_t *data;
-} payload_t;
-
-/* List all possible flash erase functions */
-typedef int command_erase_t(int fd, uint16_t count, uint16_t start);
-command_erase_t command_erase;
-command_erase_t command_ext_erase;
-command_erase_t command_erase_i2c;
-
-command_erase_t *erase;
-
-static void discard_input(int);
-
-#define MIN(a, b) ((a) < (b) ? (a) : (b))
-
-/* On user request save all data exchange with the target in this log file. */
-static FILE *log_file;
-
-/* Statistic data structure for response kind. */
-struct {
- const char * const event_name;
- uint32_t event_count;
-} stat_resp[] = {
- { "RESP_ACK", 0 },
- { "RESP_NACK", 0 },
- { "RESP_BUSY", 0 },
- { "RESP_DAMAGED_ACK", 0 },
- { "JUNK", 0 },
-};
-
-enum {
- RESP_ACK_IDX = 0,
- RESP_NACK_IDX,
- RESP_BUSY_IDX,
- RESP_DAMAGED_ACK_IDX,
- JUNK_IDX,
- MAX_EVENT_IDX
-};
-
-BUILD_ASSERT(ARRAY_SIZE(stat_resp) == MAX_EVENT_IDX);
-
-/*
- * Print data into the log file, in hex, 16 bytes per line, prefix the first
- * line with the value supplied by the caller (usually 'r' or 'w' for
- * read/write).
- */
-static void dump_log(const char *prefix, const void *data, size_t count)
-{
- size_t i;
-
- fprintf(log_file, "%s: ", prefix);
- for (i = 0; i < count; i++) {
- if (i && !(i % 16))
- fprintf(log_file, "\n ");
- fprintf(log_file, " %02x", ((uint8_t *)data)[i]);
- }
-
- if (count % 16)
- fprintf(log_file, "\n");
-
- /* Make sure all data is there even in case of aborts/crashes. */
- fflush(log_file);
-}
-
-/*
- * Wrappers for standard library read() and write() functions. Add transferred
- * data to the log if log file is opened.
- */
-static ssize_t read_wrapper(int fd, void *buf, size_t count)
-{
- ssize_t rv = read(fd, buf, count);
-
- if (log_file && (rv > 0))
- dump_log("r", buf, rv);
-
- return rv;
-}
-
-static ssize_t write_wrapper(int fd, const void *buf, size_t count)
-{
- ssize_t rv;
-
- rv = write(fd, buf, count);
-
- if (log_file && (rv > 0))
- dump_log("w", buf, rv);
-
- return rv;
-}
-
-int open_serial(const char *port, int cr50_mode)
-{
- int fd, res;
- struct termios cfg, cfg_copy;
-
- fd = open(port, O_RDWR | O_NOCTTY);
- if (fd == -1) {
- perror("Unable to open serial port");
- return -1;
- }
-
- /* put the tty in "raw" mode at the defined baudrate */
- res = tcgetattr(fd, &cfg);
- if (res == -1) {
- perror("Cannot read tty attributes");
- close(fd);
- return -1;
- }
- cfmakeraw(&cfg);
-
- /* Don't bother setting speed and parity when programming over Cr50. */
- if (!cr50_mode) {
- cfsetspeed(&cfg, baudrate);
- /* serial mode should be 8e1 */
- cfg.c_cflag |= PARENB;
- }
-
- /* 200 ms timeout */
- cfg.c_cc[VTIME] = 2;
- cfg.c_cc[VMIN] = 0;
- memcpy(&cfg_copy, &cfg, sizeof(cfg_copy));
-
- /*
- * tcsetattr() returns success if any of the modifications succeed, so
- * its return value of zero is not an indication of success, one needs
- * to check the result explicitly.
- */
- tcsetattr(fd, TCSANOW, &cfg);
- if (tcgetattr(fd, &cfg)) {
- perror("Failed to re-read tty attributes");
- close(fd);
- return -1;
- }
-
- if (memcmp(&cfg, &cfg_copy, sizeof(cfg))) {
- /*
- * On some systems the setting which does not come through is
- * the parity. We can try continuing without it when using
- * certain interfaces, let's try.
- */
- cfg_copy.c_cflag &= ~PARENB;
- if (memcmp(&cfg, &cfg_copy, sizeof(cfg))) {
- /*
- * Something other than parity failed to get set, this
- * is an error.
- */
- perror("Cannot set tty attributes");
- close(fd);
- return -1;
- } else {
- fprintf(stderr, "Failed to enable parity\n");
- }
- }
-
- discard_input(fd); /* in case were were invoked soon after reset */
- return fd;
-}
-
-int open_i2c(const int port)
-{
- int fd;
- char filename[20];
-
- snprintf(filename, 19, "/dev/i2c-%d", port);
- fd = open(filename, O_RDWR);
- if (fd < 0) {
- perror("Unable to open i2c adapter");
- return -1;
- }
- if (ioctl(fd, I2C_SLAVE, i2c_slave_address >> 1) < 0) {
- perror("Unable to select proper address");
- close(fd);
- return -1;
- }
-
- 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;
- int count_of_zeros;
-
- /* Skip in i2c and spi modes */
- if (mode != MODE_SERIAL)
- return;
-
- /* eat trailing garbage */
- count_of_zeros = 0;
- do {
- res = read_wrapper(fd, buffer, sizeof(buffer));
- if (res > 0) {
-
- /* Discard zeros in the beginning of the buffer. */
- for (i = 0; i < res; i++)
- if (buffer[i])
- break;
-
- count_of_zeros += i;
- if (i == res) {
- /* Only zeros, nothing to print out. */
- continue;
- }
-
- /* Discard zeros in the end of the buffer. */
- while (!buffer[res - 1]) {
- count_of_zeros++;
- res--;
- }
-
- printf("Recv[%d]:", res - i);
- for (; i < res; i++)
- printf("%02x ", buffer[i]);
- printf("\n");
- }
- } while (res > 0);
-
- if (count_of_zeros)
- printf("%d zeros ignored\n", count_of_zeros);
-}
-
-int wait_for_ack(int fd)
-{
- uint8_t resp;
- int res;
- time_t deadline = time(NULL) + DEFAULT_TIMEOUT;
- const uint8_t ack = RESP_ACK;
-
- while (time(NULL) < deadline) {
- res = read_wrapper(fd, &resp, 1);
- if ((res < 0) && (errno != EAGAIN)) {
- perror("Failed to read answer");
- return STM32_EIO;
- }
-
- if (res != 1)
- continue;
-
- switch (resp) {
- case RESP_ACK:
- stat_resp[RESP_ACK_IDX].event_count++;
- if (mode == MODE_SPI) /* Ack the ACK */
- if (write_wrapper(fd, &ack, 1) != 1)
- return STM32_EIO;
- return STM32_SUCCESS;
-
- case RESP_NACK:
- stat_resp[RESP_NACK_IDX].event_count++;
- fprintf(stderr, "NACK\n");
- if (mode == MODE_SPI) /* Ack the NACK */
- if (write_wrapper(fd, &ack, 1) != 1)
- return STM32_EIO;
- discard_input(fd);
- return STM32_ENACK;
-
- case RESP_BUSY:
- stat_resp[RESP_BUSY_IDX].event_count++;
- /* I2C Boot protocol 1.1 */
- deadline = time(NULL) + DEFAULT_TIMEOUT;
- break;
-
- case RESP_DAMAGED_ACK:
- if (retry_on_damaged_ack) {
- /* It is a damaged ACK. However, device is
- * likely to believe it sent ACK, so let's not
- * treat it as junk.
- */
- stat_resp[RESP_DAMAGED_ACK_IDX].event_count++;
- fprintf(stderr, "DAMAGED_ACK\n");
- return STM32_EDACK;
- }
-
- /* Do not break so that it can be handled as junk */
- default:
- stat_resp[JUNK_IDX].event_count++;
- if (mode == MODE_SERIAL)
- fprintf(stderr, "Receive junk: %02x\n", resp);
- break;
- }
- }
- fprintf(stderr, "Timeout\n");
- return STM32_ETIMEDOUT;
-}
-
-int send_command(int fd, uint8_t cmd, payload_t *loads, int cnt,
- uint8_t *resp, int resp_size, int ack_requested)
-{
- int res, i, c;
- payload_t *p;
- int readcnt = 0;
-
- uint8_t cmd_frame[] = { SOF, cmd,
- /* XOR checksum */
- (uint8_t)(0xff ^ cmd) };
- /* only the SPI mode needs the Start Of Frame byte */
- int cmd_off = mode == MODE_SPI ? 0 : 1;
- int count_damaged_ack = 0;
-
- /* Send the command index */
- res = write_wrapper(fd, cmd_frame + cmd_off,
- sizeof(cmd_frame) - cmd_off);
- if (res <= 0) {
- perror("Failed to write command frame");
- return STM32_EIO;
- }
-
- /* Wait for the ACK */
- res = wait_for_ack(fd);
- if (res == STM32_EDACK) {
- ++count_damaged_ack;
- } else if (IS_STM32_ERROR(res)) {
- const char *name = cmd_lookup_name(cmd);
- char hex[sizeof("0xFF")];
- snprintf(hex, sizeof(hex), "0x%02x", cmd);
- fprintf(stderr, "Failed to get command %s ACK\n",
- name ? name : hex);
- return res;
- }
-
- /* Send the command payloads */
- for (p = loads, c = 0; c < cnt; c++, p++) {
- uint8_t crc = 0;
- int size = p->size;
- uint8_t *data = (uint8_t *)(malloc(size + 1)), *data_ptr;
-
- if (data == NULL) {
- fprintf(stderr,
- "Failed to allocate memory for load %d\n", c);
- return STM32_ENOMEM;
- }
- memcpy(data, p->data, size);
- for (i = 0; i < size; i++)
- crc ^= data[i];
- if (size == 1)
- crc = 0xff ^ crc;
- data[size] = crc;
- size++;
- data_ptr = data;
- while (size) {
- res = write_wrapper(fd, data_ptr, size);
- if (res < 0) {
- perror("Failed to write command payload");
- free(data);
- return STM32_EIO;
- }
- size -= res;
- data_ptr += res;
- }
- free(data);
-
- /* Wait for the ACK */
- res = wait_for_ack(fd);
- if (res == STM32_EDACK) {
- ++count_damaged_ack;
- } else if (IS_STM32_ERROR(res)) {
- if (res != STM32_ETIMEDOUT)
- fprintf(stderr,
- "payload %d ACK failed for CMD%02x\n",
- c, cmd);
- return res;
- }
- }
-
- /* Read the answer payload */
- if (resp) {
- if (mode == MODE_SPI) /* ignore extra byte */
- if (read_wrapper(fd, resp, 1) < 0)
- return STM32_EIO;
- while ((resp_size > 0) &&
- (res = read_wrapper(fd, resp, resp_size))) {
- if (res < 0) {
- perror("Failed to read payload");
- return STM32_EIO;
- }
- readcnt += res;
- resp += res;
- resp_size -= res;
- }
-
- /* Wait for the ACK */
- if (ack_requested) {
- res = wait_for_ack(fd);
- if (res == STM32_EDACK) {
- ++count_damaged_ack;
- } else if (IS_STM32_ERROR(res)) {
- fprintf(stderr,
- "Failed to get response to command"
- " 0x%02x ACK\n", cmd);
- return res;
- }
- }
- }
-
- if (count_damaged_ack)
- return STM32_EDACK;
-
- return readcnt;
-}
-
-int send_command_retry(int fd, uint8_t cmd, payload_t *loads,
- int cnt, uint8_t *resp, int resp_size, int ack_requested)
-{
- int res;
- int retries = MAX_RETRY_COUNT;
-
- do {
- int ack_tries = MAX_ACK_RETRY_COUNT;
-
- res = send_command(fd, cmd, loads, cnt, resp, resp_size,
- ack_requested);
-
- while (res == STM32_ETIMEDOUT && ack_tries--) {
- if (cmd == CMD_WRITEMEM) {
- /* send garbage byte */
- res = write_wrapper(fd, loads->data, 1);
- /* Don't care much since it is a garbage
- * transfer to let the device not wait for
- * any missing data, if any.
- */
- if (res < 0)
- fprintf(stderr, "warn: write failed\n");
- }
- res = wait_for_ack(fd);
- }
- } while ((res == STM32_ENACK || res == STM32_EDACK) && retries--);
-
- return res;
-}
-
-struct stm32_def *command_get_id(int fd)
-{
- int res;
- uint8_t id[3];
- uint16_t chipid;
- struct stm32_def *def;
-
- res = send_command(fd, CMD_GETID, NULL, 0, id, sizeof(id), 1);
- if (res > 0) {
- if (id[0] != 1) {
- fprintf(stderr, "unknown ID : %02x %02x %02x\n",
- id[0], id[1], id[2]);
- return NULL;
- }
- chipid = (id[1] << 8) | id[2];
- for (def = chip_defs; def->id; def++)
- if (def->id == chipid)
- break;
- if (def->id == 0)
- def = NULL;
- printf("ChipID 0x%03x : %s\n", chipid, def ? def->name : "???");
- return def;
- }
-
- return NULL;
-}
-
-int init_monitor(int fd)
-{
- int res = 0;
- int attempts = connect_retries + 1;
- uint8_t init = mode == MODE_SPI ? SOF : CMD_INIT;
-
- /* Skip in i2c mode */
- if (mode == MODE_I2C)
- return STM32_SUCCESS;
-
- printf("Waiting for the monitor startup ...");
- fflush(stdout);
-
- while (connect_retries < 0 || attempts--) {
- /* Send the command index */
- res = write_wrapper(fd, &init, 1);
- if (res <= 0) {
- perror("Failed to write command");
- return STM32_EIO;
- }
- /* Wait for the ACK */
- res = wait_for_ack(fd);
- if (res == STM32_SUCCESS)
- break;
- if (res == STM32_ENACK) {
- /* we got NACK'ed, the loader might be already started
- * let's ping it to check
- */
- if (command_get_id(fd)) {
- printf("Monitor already started.\n");
- return STM32_SUCCESS;
- }
- }
- if (IS_STM32_ERROR(res) && res != STM32_ETIMEDOUT)
- return res;
- fflush(stdout);
- }
-
- if (IS_STM32_ERROR(res)) {
- printf("Giving up after %d attempts.\n", connect_retries + 1);
- return res;
- }
-
- printf("Done.\n");
-
- /* read trailing chars */
- discard_input(fd);
-
- return STM32_SUCCESS;
-}
-
-int command_get_commands(int fd, struct stm32_def *chip)
-{
- int res, i;
- uint8_t cmds[64];
-
- /*
- * For i2c, we have to request the exact amount of bytes we expect.
- */
- res = send_command(fd, CMD_GETCMD, NULL, 0, cmds,
- chip->cmds_len[(mode == MODE_I2C ? 1 : 0)], 1);
- if (res > 0) {
- if (cmds[0] > sizeof(cmds) - 2) {
- fprintf(stderr, "invalid GET answer (%02x...)\n",
- cmds[0]);
- return STM32_EINVAL;
- }
- printf("Bootloader v%d.%d, commands : ",
- cmds[1] >> 4, cmds[1] & 0xf);
- boot_loader_version = cmds[1];
-
- erase = command_erase;
- for (i = 2; i < 2 + cmds[0]; i++) {
- const char *name;
- if (cmds[i] == CMD_EXTERASE)
- erase = command_ext_erase;
- name = cmd_lookup_name(cmds[i]);
- if (name)
- printf("%s ", name);
- else
- printf("0x%02x ", cmds[i]);
- }
-
- if (mode == MODE_I2C)
- erase = command_erase_i2c;
- printf("\n");
-
- return STM32_SUCCESS;
- }
-
- fprintf(stderr, "Cannot get bootloader command list.\n");
- return STM32_EINVAL;
-}
-
-static int use_progressbar;
-static int windex;
-static const char wheel[] = {'|', '/', '-', '\\' };
-static void draw_spinner(uint32_t remaining, uint32_t size)
-{
- int percent = (size - remaining)*100/size;
- if (use_progressbar) {
- int dots = percent / 4;
-
- while (dots > windex) {
- putchar('#');
- windex++;
- }
- } else {
- printf("\r%c%3d%%", wheel[windex++], percent);
- windex %= sizeof(wheel);
- }
- fflush(stdout);
-}
-
-int command_read_mem(int fd, uint32_t address, uint32_t size, uint8_t *buffer)
-{
- int res;
- uint32_t remaining = size;
- uint32_t addr_be;
- uint8_t cnt;
- payload_t loads[2] = {
- {4, (uint8_t *)&addr_be},
- {1, &cnt}
- };
-
- while (remaining) {
- uint32_t bytes = MIN(remaining, PAGE_SIZE);
-
- cnt = (uint8_t) (bytes - 1);
- addr_be = htonl(address);
-
- draw_spinner(remaining, size);
-
- res = send_command_retry(fd, CMD_READMEM, loads, 2, buffer,
- bytes, 0);
- if (IS_STM32_ERROR(res))
- return STM32_EIO;
-
- buffer += bytes;
- address += bytes;
- remaining -= bytes;
- }
-
- return size;
-}
-
-int command_write_mem(int fd, uint32_t address, uint32_t size, uint8_t *buffer)
-{
- int res = 0;
- int i;
- uint32_t remaining = size;
- uint32_t addr_be;
- uint32_t cnt;
- uint8_t outbuf[257];
- payload_t loads[2] = {
- {4, (uint8_t *)&addr_be},
- {sizeof(outbuf), outbuf}
- };
-
- while (remaining) {
- cnt = MIN(remaining, PAGE_SIZE);
- /* skip empty blocks to save time */
- for (i = 0; i < cnt && buffer[i] == 0xff; i++)
- ;
- if (i != cnt) {
- addr_be = htonl(address);
- outbuf[0] = cnt - 1;
- loads[1].size = cnt + 1;
- memcpy(outbuf + 1, buffer, cnt);
-
- draw_spinner(remaining, size);
-
- res = send_command_retry(fd, CMD_WRITEMEM, loads, 2,
- NULL, 0, 1);
- if (IS_STM32_ERROR(res))
- return STM32_EIO;
- }
- buffer += cnt;
- address += cnt;
- remaining -= cnt;
- }
-
- return size;
-}
-
-int command_ext_erase(int fd, uint16_t count, uint16_t start)
-{
- int res;
- uint16_t count_be = htons(count);
- payload_t load = { 2, (uint8_t *)&count_be };
- uint16_t *pages = NULL;
-
- if (count < 0xfff0) {
- int i;
- /* not a special value : build a list of pages */
- load.size = 2 * (count + 1);
- pages = (uint16_t *)(malloc(load.size));
- if (!pages)
- return STM32_ENOMEM;
- load.data = (uint8_t *)pages;
- pages[0] = htons(count - 1);
- for (i = 0; i < count; i++)
- pages[i+1] = htons(start + i);
- }
-
- printf("Erasing...\n");
- res = send_command_retry(fd, CMD_EXTERASE, &load, 1, NULL, 0, 1);
- if (!IS_STM32_ERROR(res))
- printf("Flash erased.\n");
-
- if (pages)
- free(pages);
- return res;
-}
-
-int command_erase_i2c(int fd, uint16_t count, uint16_t start)
-{
- int res;
- uint8_t erase_cmd;
- uint16_t count_be = htons(count);
- payload_t load[2] = {
- { 2, (uint8_t *)&count_be},
- { 0, NULL},
- };
- int load_cnt = 1;
- uint16_t *pages = NULL;
-
- if (count < 0xfff) {
- int i;
- /* not a special value : build a list of pages */
- /*
- * I2c protocol requires 2 messages, the count has to be acked
- * before the addresses can be sent.
- * TODO(gwendal): Still broken on i2c.
- */
- load_cnt = 2;
- load[1].size = 2 * count;
- pages = (uint16_t *)(malloc(load[1].size));
- if (!pages)
- return STM32_ENOMEM;
- load[1].data = (uint8_t *)pages;
- count_be = htons(count - 1);
- for (i = 0; i < count; i++)
- pages[i] = htons(start + i);
- }
-
- erase_cmd = (boot_loader_version == 0x10) ? CMD_EXTERASE :
- CMD_NO_STRETCH_ERASE;
-
- printf("Erasing...\n");
- res = send_command(fd, erase_cmd, load, load_cnt, NULL, 0, 1);
- if (!IS_STM32_ERROR(res))
- printf("Flash erased.\n");
-
- if (pages)
- free(pages);
- return res;
-}
-
-
-int command_erase(int fd, uint16_t count, uint16_t start)
-{
- int res;
- uint8_t count_8bit = count;
- payload_t load = { 1, &count_8bit };
- uint8_t *pages = NULL;
-
- if (count < 0xff) {
- int i;
- /* not a special value : build a list of pages */
- load.size = count + 1;
- pages = (uint8_t *)(malloc(load.size));
- if (!pages)
- return STM32_ENOMEM;
- load.data = (uint8_t *)pages;
- pages[0] = count - 1;
- for (i = 0; i < count; i++)
- pages[i+1] = start + i;
- }
-
- printf("Erasing...\n");
- res = send_command(fd, CMD_ERASE, &load, 1, NULL, 0, 1);
- if (!IS_STM32_ERROR(res))
- printf("Flash erased.\n");
-
- if (pages)
- free(pages);
- return res;
-}
-
-int command_read_unprotect(int fd)
-{
- int res;
- int retries = MAX_ACK_RETRY_COUNT;
-
- printf("Unprotecting flash read...\n");
-
- res = send_command(fd, CMD_RU, NULL, 0, NULL, 0, 1);
- /*
- * Read unprotect can trigger a mass erase, which can take long time
- * (e.g. 13s+ on STM32H7)
- */
- do {
- res = wait_for_ack(fd);
- } while ((res == STM32_ETIMEDOUT) && --retries);
-
- if (IS_STM32_ERROR(res)) {
- fprintf(stderr, "Failed to get read-protect ACK\n");
- return res;
- }
- printf("Flash read unprotected.\n");
-
- /*
- * This command triggers a reset.
- *
- * Wait at least the reboot delay, else we could reconnect
- * before the actual reset depending on the bootloader.
- */
- usleep(MAX_DELAY_REBOOT);
- if (IS_STM32_ERROR(init_monitor(fd))) {
- fprintf(stderr, "Cannot recover after RU reset\n");
- return STM32_EIO;
- }
-
- return STM32_SUCCESS;
-}
-
-int command_write_unprotect(int fd)
-{
- int res;
-
- res = send_command(fd, CMD_WU, NULL, 0, NULL, 0, 1);
- if (IS_STM32_ERROR(res))
- return STM32_EIO;
-
- /* Wait for the ACK */
- if (wait_for_ack(fd) < 0) {
- fprintf(stderr, "Failed to get write-protect ACK\n");
- return STM32_EINVAL;
- }
- printf("Flash write unprotected.\n");
-
- /*
- * This command triggers a reset.
- *
- * Wait at least the reboot delay, else we could reconnect
- * before the actual reset depending on the bootloader.
- */
- usleep(MAX_DELAY_REBOOT);
- if (IS_STM32_ERROR(init_monitor(fd))) {
- fprintf(stderr, "Cannot recover after WP reset\n");
- return STM32_EIO;
- }
-
- return STM32_SUCCESS;
-}
-
-int command_go(int fd, uint32_t address)
-{
- int res;
- uint32_t addr_be = htonl(address);
- payload_t load = { 4, (uint8_t *)&addr_be };
-
- res = send_command(fd, CMD_GO, &load, 1, NULL, 0, 1);
- if (IS_STM32_ERROR(res))
- return STM32_EIO;
-
-#if 0 /* this ACK should exist according to the documentation ... */
- /* Wait for the ACK */
- if (wait_for_ack(fd) < 0) {
- fprintf(stderr, "Failed to get GO ACK\n");
- return -EINVAL;
- }
-#endif
-
- printf("Program started at 0x%08x.\n", address);
- return STM32_SUCCESS;
-}
-
-/*
- * The bootloader does not allow reading directly from the "device signature"
- * registers. However, it does allow reading the OTP region, so this function
- * starts a read from the last byte in that region and reads an additional
- * number of bytes to read the requested register.
- *
- * Example:
- *
- * Given a chip with OTP region starting at address 0x1FFF7800 with a size of
- * 528 bytes and a register that we want to read at address 0x1FFF7A10 with a
- * size of 12 bytes:
- *
- * We start the read at the last byte in the OTP region:
- *
- * 0x1FFF7800 + 528 - 1 = 0x1FFF7A0F
- *
- * From 0x1FFF7A0F we perform a read of (12 + 1) = 13 bytes in order to read the
- * 12 bytes starting at 0x1FFF7A10 (the actual register we care about).
- *
- * Returns zero on success, negative on failure.
- */
-int read_device_signature_register(int fd, const struct stm32_def *chip,
- uint32_t addr, uint32_t size_bytes,
- uint8_t *out_buffer)
-{
- int res;
- uint8_t *buffer;
- struct memory_info otp = chip->memory_layout.otp_area;
- uint32_t otp_end_addr = otp.addr + otp.size_bytes - 1;
- uint32_t offset = addr - otp_end_addr;
- uint32_t read_size_bytes = offset + size_bytes;
-
- if (!otp.addr) {
- fprintf(stderr, "No otp_area.addr specified for given chip.\n");
- return STM32_EINVAL;
- }
-
- if (addr <= otp_end_addr) {
- fprintf(stderr, "Attempting to read from invalid address: "
- "%08X\n", addr);
- return STM32_EINVAL;
- }
-
- /*
- * The USART/SPI/I2C bootloader can only read at most 256 bytes in a
- * single read command (see AN4286 section 2.5 or AN3155 section 3.4).
- *
- * command_read_mem will correctly chunk larger requests, but the
- * subsequent reads will fail because the bootloader won't allow reads
- * from a starting address that is beyond the OTP region.
- */
- if (read_size_bytes > PAGE_SIZE) {
- fprintf(stderr,
- "Requested register 0x%08X is outside read range.\n",
- addr);
- return STM32_EINVAL;
- }
-
- buffer = (uint8_t *)(malloc(read_size_bytes));
- if (!buffer) {
- fprintf(stderr, "Cannot allocate %" PRIu32 " bytes\n",
- read_size_bytes);
- return STM32_ENOMEM;
- }
-
- res = command_read_mem(fd, otp_end_addr, read_size_bytes, buffer);
- if (res == read_size_bytes)
- memcpy(out_buffer, buffer + offset, size_bytes);
- else
- fprintf(stderr,
- "Cannot read %" PRIu32 " bytes from address 0x%08X",
- read_size_bytes, otp_end_addr);
-
- free(buffer);
- return IS_STM32_ERROR(res) ? res : STM32_SUCCESS;
-}
-
-/* Return zero on success, a negative error value on failures. */
-int read_flash_size_register(int fd, struct stm32_def *chip,
- uint16_t *flash_size_kbytes)
-{
- int res;
- uint32_t flash_size_addr = chip->device_signature.flash_size_addr;
-
- if (!flash_size_addr)
- return STM32_EINVAL;
-
- res = read_device_signature_register(fd, chip,
- flash_size_addr, sizeof(*flash_size_kbytes),
- (uint8_t *)flash_size_kbytes);
-
- if (!IS_STM32_ERROR(res))
- printf("Flash size: %" PRIu16 " KB\n", *flash_size_kbytes);
- else
- fprintf(stderr,
- "Unable to read flash size register (0x%08X).\n",
- flash_size_addr);
-
- return res;
-}
-
-/* Return zero on success, a negative error value on failures. */
-int read_unique_device_id_register(int fd, struct stm32_def *chip,
- uint8_t device_id[STM32_UNIQUE_ID_SIZE_BYTES])
-{
- int i;
- int res;
- uint32_t unique_device_id_addr =
- chip->device_signature.unique_device_id_addr;
-
- if (!unique_device_id_addr)
- return STM32_EINVAL;
-
- res = read_device_signature_register(fd, chip, unique_device_id_addr,
- STM32_UNIQUE_ID_SIZE_BYTES, device_id);
-
- if (!IS_STM32_ERROR(res)) {
- printf("Unique Device ID: 0x");
- for (i = STM32_UNIQUE_ID_SIZE_BYTES - 1; i >= 0; i--)
- printf("%02X", device_id[i]);
- printf("\n");
- } else {
- fprintf(stderr,
- "Unable to read unique device ID register (0x%08X). "
- "Ignoring non-critical failure.\n",
- unique_device_id_addr);
- }
-
- return res;
-}
-
-/* Return zero on success, a negative error value on failures. */
-int read_package_data_register(int fd, struct stm32_def *chip,
- uint16_t *package_data)
-{
- int res;
- uint32_t package_data_addr = chip->device_signature.package_data_addr;
-
- if (!package_data_addr)
- return STM32_EINVAL;
-
- res = read_device_signature_register(fd, chip, package_data_addr,
- sizeof(*package_data),
- (uint8_t *)package_data);
-
- if (!IS_STM32_ERROR(res))
- printf("Package data register: %04X\n", *package_data);
- else
- fprintf(stderr,
- "Failed to read package data register (0x%08X). "
- "Ignoring non-critical failure.\n", package_data_addr);
-
- return res;
-}
-
-/* Return zero on success, a negative error value on failures. */
-int read_flash(int fd, struct stm32_def *chip, const char *filename,
- uint32_t offset, uint32_t size)
-{
- int res;
- FILE *hnd;
- uint8_t *buffer;
-
- if (!size)
- size = chip->flash_size;
- buffer = (uint8_t *)(malloc(size));
- if (!buffer) {
- fprintf(stderr, "Cannot allocate %d bytes\n", size);
- return STM32_ENOMEM;
- }
-
- hnd = fopen(filename, "w");
- if (!hnd) {
- fprintf(stderr, "Cannot open file %s for writing\n", filename);
- free(buffer);
- return STM32_EIO;
- }
-
- printf("Reading %d bytes at 0x%08x\n", size, offset);
- res = command_read_mem(fd, offset, size, buffer);
- if (res > 0) {
- if (fwrite(buffer, res, 1, hnd) != 1)
- fprintf(stderr, "Cannot write %s\n", filename);
- }
- printf("\r %d bytes read.\n", res);
-
- fclose(hnd);
- free(buffer);
- return IS_STM32_ERROR(res) ? res : STM32_SUCCESS;
-}
-
-/* Return zero on success, a negative error value on failures. */
-int write_flash(int fd, struct stm32_def *chip, const char *filename,
- uint32_t offset)
-{
- int res, written;
- FILE *hnd;
- int size = chip->flash_size;
- uint8_t *buffer = (uint8_t *)(malloc(size));
-
- if (!buffer) {
- fprintf(stderr, "Cannot allocate %d bytes\n", size);
- return STM32_ENOMEM;
- }
-
- if (!strncmp(filename, "-", sizeof("-")))
- hnd = fdopen(STDIN_FILENO, "r");
- else
- hnd = fopen(filename, "r");
- if (!hnd) {
- fprintf(stderr, "Cannot open file %s for reading\n", filename);
- free(buffer);
- return STM32_EIO;
- }
- res = fread(buffer, 1, size, hnd);
- fclose(hnd);
- if (res <= 0) {
- fprintf(stderr, "Cannot read %s\n", filename);
- free(buffer);
- return STM32_EIO;
- }
-
- /* faster write: skip empty trailing space */
- while (res && buffer[res - 1] == 0xff)
- res--;
- /* ensure 'res' is multiple of 4 given 'size' is and res <= size */
- res = (res + 3) & ~3;
-
- printf("Writing %d bytes at 0x%08x\n", res, offset);
- written = command_write_mem(fd, offset, res, buffer);
- if (written != res) {
- fprintf(stderr, "Error writing to flash\n");
- free(buffer);
- return STM32_EIO;
- }
- printf("\r %d bytes written.\n", written);
-
- free(buffer);
- return STM32_SUCCESS;
-}
-
-static const struct option longopts[] = {
- {"adapter", 1, 0, 'a'},
- {"baudrate", 1, 0, 'b'},
- {"cr50", 0, 0, 'c'},
- {"device", 1, 0, 'd'},
- {"erase", 0, 0, 'e'},
- {"go", 0, 0, 'g'},
- {"help", 0, 0, 'h'},
- {"length", 1, 0, 'n'},
- {"location", 1, 0, 'l'},
- {"logfile", 1, 0, 'L'},
- {"offset", 1, 0, 'o'},
- {"progressbar", 0, 0, 'p'},
- {"read", 1, 0, 'r'},
- {"retries", 1, 0, 'R'},
- {"spi", 1, 0, 's'},
- {"unprotect", 0, 0, 'u'},
- {"version", 0, 0, 'v'},
- {"write", 1, 0, 'w'},
- {NULL, 0, 0, 0}
-};
-
-void display_usage(char *program)
-{
- fprintf(stderr,
- "Usage: %s [-a <i2c_adapter> [-l address ]] | [-s]"
- " [-d <tty>] [-b <baudrate>]] [-u] [-e] [-U]"
- " [-r <file>] [-w <file>] [-o offset] [-n length] [-g] [-p]"
- " [-L <log_file>] [-c] [-v]\n",
- program);
- fprintf(stderr, "Can access the controller via serial port or i2c\n");
- fprintf(stderr, "Serial port mode:\n");
- fprintf(stderr, "--d[evice] <tty> : use <tty> as the serial port\n");
- fprintf(stderr, "--b[audrate] <baudrate> : set serial port speed "
- "to <baudrate> bauds\n");
- fprintf(stderr, "i2c mode:\n");
- fprintf(stderr, "--a[dapter] <id> : use i2c adapter <id>.\n");
- fprintf(stderr, "--l[ocation] <address> : use address <address>.\n");
- fprintf(stderr, "--s[pi]: use spi mode.\n");
- fprintf(stderr, "--u[nprotect] : remove flash write protect\n");
- fprintf(stderr, "--U[nprotect] : remove flash read protect\n");
- 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, "--o[ffset] : offset to read/write/start from/to\n");
- fprintf(stderr, "--n[length] : amount to read/write\n");
- fprintf(stderr, "--g[o] : jump to execute flash entrypoint\n");
- fprintf(stderr, "--p[rogressbar] : use a progress bar instead of "
- "the spinner\n");
- fprintf(stderr, "--R[etries] <num> : limit connect retries to num\n");
- fprintf(stderr, "-L[ogfile] <file> : save all communications exchange "
- "in a log file\n");
- fprintf(stderr, "-c[r50_mode] : consider device to be a Cr50 interface,"
- " no need to set UART port attributes\n");
- fprintf(stderr, "--v[ersion] : print version and exit\n");
-
- exit(2);
-}
-
-void display_version(const char *exe_name)
-{
- printf("%s version: %s %s %s\n", exe_name, CROS_STM32MON_VERSION, DATE,
- BUILDER);
-}
-
-speed_t parse_baudrate(const char *value)
-{
- int rate = atoi(value);
-
- switch (rate) {
- case 9600:
- return B9600;
- case 19200:
- return B19200;
- case 38400:
- return B38400;
- case 57600:
- return B57600;
- case 115200:
- return B115200;
- default:
- fprintf(stderr, "Invalid baudrate %s, using %d\n",
- value, DEFAULT_BAUDRATE);
- return DEFAULT_BAUDRATE;
- }
-}
-
-int parse_parameters(int argc, char **argv)
-{
- int opt, idx;
- int flags = 0;
- const char *log_file_name = NULL;
-
- while ((opt = getopt_long(argc, argv, "a:l:b:cd:eghL:n:o:pr:R:s:w:uUv?",
- longopts, &idx)) != -1) {
- switch (opt) {
- case 'a':
- i2c_adapter = atoi(optarg);
- mode = MODE_I2C;
- break;
- case 'l':
- i2c_slave_address = strtol(optarg, NULL, 0);
- break;
- case 'b':
- baudrate = parse_baudrate(optarg);
- break;
- case 'c':
- flags |= FLAG_CR50_MODE;
- break;
- case 'd':
- serial_port = optarg;
- mode = MODE_SERIAL;
- break;
- case 'e':
- flags |= FLAG_ERASE;
- break;
- case 'g':
- flags |= FLAG_GO;
- break;
- case 'h':
- case '?':
- display_usage(argv[0]);
- break;
- case 'L':
- log_file_name = optarg;
- break;
- case 'n':
- length = strtol(optarg, NULL, 0);
- break;
- case 'o':
- offset = strtol(optarg, NULL, 0);
- break;
- case 'p':
- use_progressbar = 1;
- break;
- case 'r':
- input_filename = optarg;
- break;
- case 'R':
- connect_retries = atoi(optarg);
- break;
- case 's':
- spi_adapter = optarg;
- mode = MODE_SPI;
- break;
- case 'w':
- output_filename = optarg;
- break;
- case 'u':
- flags |= FLAG_UNPROTECT;
- break;
- case 'U':
- flags |= FLAG_READ_UNPROTECT;
- break;
- case 'v':
- display_version(argv[0]);
- exit(0);
- }
- }
-
- if (log_file_name) {
- log_file = fopen(log_file_name, "w");
- if (!log_file) {
- fprintf(stderr, "failed to open %s for writing\n",
- log_file_name);
- exit(2);
- }
- }
- return flags;
-}
-
-static void display_stat_response(void)
-{
- uint32_t total_events = MAX_EVENT_IDX;
- uint32_t idx;
-
- printf("--\n");
- for (idx = 0; idx < total_events; ++idx) {
- printf("%-18s %d\n", stat_resp[idx].event_name,
- stat_resp[idx].event_count);
- }
- printf("--\n");
-}
-
-int main(int argc, char **argv)
-{
- int ser;
- struct stm32_def *chip;
- int ret = STM32_EIO;
- int res;
- int flags;
- uint16_t flash_size_kbytes = 0;
- uint8_t unique_device_id[STM32_UNIQUE_ID_SIZE_BYTES] = { 0 };
- uint16_t package_data_reg = 0;
-
- /* Parse command line options */
- flags = parse_parameters(argc, argv);
-
- display_version(argv[0]);
-
- retry_on_damaged_ack = !!(flags & FLAG_CR50_MODE);
-
- 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, !!(flags & FLAG_CR50_MODE));
- }
- if (ser < 0)
- return 1;
- /* Trigger embedded monitor detection */
- res = init_monitor(ser);
- if (IS_STM32_ERROR(res))
- goto terminate;
-
- chip = command_get_id(ser);
- if (!chip)
- goto terminate;
-
- if (command_get_commands(ser, chip) < 0)
- goto terminate;
-
- if (flags & FLAG_READ_UNPROTECT)
- command_read_unprotect(ser);
-
- /*
- * Use the actual size if we were able to read it since some chips
- * have the same chip ID, but different flash sizes based on the
- * package.
- */
- res = read_flash_size_register(ser, chip, &flash_size_kbytes);
- if (!IS_STM32_ERROR(res))
- chip->flash_size = flash_size_kbytes * KBYTES_TO_BYTES;
-
- /*
- * This is simply informative at the moment, so we don't care about the
- * return value.
- */
- (void)read_unique_device_id_register(ser, chip, unique_device_id);
-
- /*
- * This is simply informative at the moment, so we don't care about the
- * return value.
- */
- (void)read_package_data_register(ser, chip, &package_data_reg);
-
- if (flags & FLAG_UNPROTECT)
- command_write_unprotect(ser);
-
- if (flags & FLAG_ERASE || output_filename) {
- if ((!strncmp("STM32L15", chip->name, 8)) ||
- (!strncmp("STM32F411", chip->name, 9))) {
- /* Mass erase is not supported on these chips*/
- int i, page_count = chip->flash_size / chip->page_size;
- for (i = 0; i < page_count; i += 128) {
- int count = MIN(128, page_count - i);
- ret = erase(ser, count, i);
- if (IS_STM32_ERROR(ret))
- goto terminate;
- }
- } else {
- ret = erase(ser, 0xFFFF, 0);
- if (IS_STM32_ERROR(ret))
- goto terminate;
- }
- }
-
- if (input_filename) {
- ret = read_flash(ser, chip, input_filename, offset, length);
- if (IS_STM32_ERROR(ret))
- goto terminate;
- }
-
- if (output_filename) {
- ret = write_flash(ser, chip, output_filename, offset);
- if (IS_STM32_ERROR(ret))
- goto terminate;
- }
-
- /* Run the program from flash */
- if (flags & FLAG_GO)
- command_go(ser, offset);
-
- /* Normal exit */
- ret = STM32_SUCCESS;
-terminate:
- if (log_file)
- fclose(log_file);
-
- /* Close serial port */
- close(ser);
-
- if (retry_on_damaged_ack)
- display_stat_response();
-
- if (IS_STM32_ERROR(ret)) {
- fprintf(stderr, "Failed: %d\n", ret);
- return 1;
- }
-
- printf("Done.\n");
- return 0;
-}