summaryrefslogtreecommitdiff
path: root/util/stm32mon.c
diff options
context:
space:
mode:
authorJack Rosenthal <jrosenth@chromium.org>2021-11-04 12:11:58 -0600
committerCommit Bot <commit-bot@chromium.org>2021-11-05 04:22:34 +0000
commit252457d4b21f46889eebad61d4c0a65331919cec (patch)
tree01856c4d31d710b20e85a74c8d7b5836e35c3b98 /util/stm32mon.c
parent08f5a1e6fc2c9467230444ac9b582dcf4d9f0068 (diff)
downloadchrome-ec-252457d4b21f46889eebad61d4c0a65331919cec.tar.gz
In the interest of making long-term branch maintenance incur as little technical debt on us as possible, we should not maintain any files on the branch we are not actually using. This has the added effect of making it extremely clear when merging CLs from the main branch when changes have the possibility to affect us. The follow-on CL adds a convenience script to actually pull updates from the main branch and generate a CL for the update. BUG=b:204206272 BRANCH=ish TEST=make BOARD=arcada_ish && make BOARD=drallion_ish Signed-off-by: Jack Rosenthal <jrosenth@chromium.org> Change-Id: I17e4694c38219b5a0823e0a3e55a28d1348f4b18 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3262038 Reviewed-by: Jett Rink <jettrink@chromium.org> Reviewed-by: Tom Hughes <tomhughes@chromium.org>
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;
-}