summaryrefslogtreecommitdiff
path: root/util
diff options
context:
space:
mode:
authorTom Hughes <tomhughes@chromium.org>2019-03-27 09:38:01 -0700
committerchrome-bot <chrome-bot@chromium.org>2019-04-09 06:19:48 -0700
commitb438ce1a026503d37ab14c537b15f3ae49cc44a2 (patch)
tree8d47a7f2bf3236c31323b557475be4f9d85b1b67 /util
parentf923afcc99e6ec0ae15d2adeada09ee4571b8a96 (diff)
downloadchrome-ec-b438ce1a026503d37ab14c537b15f3ae49cc44a2.tar.gz
hatch_fp: STM32F412 can have up to 1 MB Flash (some have less)
For sizes, see: See https://www.st.com/resource/en/reference_manual/dm00180369.pdf Section 3.3 Embedded Flash Memory We read the Flash size data register to get the actual size: See https://www.st.com/resource/en/reference_manual/dm00180369.pdf Section 31 Device electronic signature BRANCH=none BUG=b:126455006,b:124996507 TEST=make BOARD=hatch_fp -j ./build/host/util/stm32mon -b 115200 -d /dev/pts/24 \ -u -e -w ./build/hatch_fp/ec.bin Change-Id: I105840150cde68c7c7579d44c8d8c43b6b567233 Signed-off-by: Tom Hughes <tomhughes@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/1541818 Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com> Reviewed-by: Nicolas Boichat <drinkcat@chromium.org>
Diffstat (limited to 'util')
-rw-r--r--util/stm32mon.c306
1 files changed, 291 insertions, 15 deletions
diff --git a/util/stm32mon.c b/util/stm32mon.c
index 68c7ebc0c3..601a53238e 100644
--- a/util/stm32mon.c
+++ b/util/stm32mon.c
@@ -23,6 +23,7 @@
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
+#include <inttypes.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
@@ -35,6 +36,8 @@
#include <time.h>
#include <unistd.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.
@@ -75,6 +78,56 @@
/* 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;
@@ -82,22 +135,67 @@ struct stm32_def {
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} },
- {0x429, "STM32L15xxB-A", 0x20000, 256, {13, 13} },
- {0x427, "STM32L15xxC", 0x40000, 256, {13, 13} },
- {0x435, "STM32L44xx", 0x40000, 2048, {13, 13} },
- {0x420, "STM32F100xx", 0x20000, 1024, {13, 13} },
- {0x410, "STM32F102R8", 0x10000, 1024, {13, 13} },
- {0x440, "STM32F05x", 0x10000, 1024, {13, 13} },
- {0x444, "STM32F03x", 0x08000, 1024, {13, 13} },
- {0x448, "STM32F07xB", 0x20000, 2048, {13, 13} },
- {0x432, "STM32F37xx", 0x40000, 2048, {13, 13} },
- {0x442, "STM32F09x", 0x40000, 2048, {13, 13} },
- {0x431, "STM32F411", 0x80000, 16384, {13, 19} },
- {0x441, "STM32F412", 0x80000, 16384, {13, 19} },
- {0x450, "STM32H74x", 0x200000, 131768, {13, 19} },
- {0x451, "STM32F76x", 0x200000, 32768, {13, 19} },
+ {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 } },
{ 0 }
};
@@ -899,6 +997,161 @@ int command_go(int fd, uint32_t address)
return 0;
}
+/*
+ * 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 -EINVAL;
+ }
+
+ if (addr <= otp_end_addr) {
+ fprintf(stderr, "Attempting to read from invalid address: "
+ "%08X\n", addr);
+ return -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 -EINVAL;
+ }
+
+ buffer = malloc(read_size_bytes);
+ if (!buffer) {
+ fprintf(stderr, "Cannot allocate %" PRIu32 " bytes\n",
+ read_size_bytes);
+ return -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 (res < 0) ? res : 0;
+}
+
+/* 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 -EINVAL;
+
+ res = read_device_signature_register(fd, chip,
+ flash_size_addr, sizeof(*flash_size_kbytes),
+ (uint8_t *)flash_size_kbytes);
+
+ if (!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 -EINVAL;
+
+ res = read_device_signature_register(fd, chip, unique_device_id_addr,
+ STM32_UNIQUE_ID_SIZE_BYTES, device_id);
+
+ if (!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 -EINVAL;
+
+ res = read_device_signature_register(fd, chip, package_data_addr,
+ sizeof(*package_data),
+ (uint8_t *)package_data);
+
+ if (!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)
@@ -1150,6 +1403,9 @@ int main(int argc, char **argv)
struct stm32_def *chip;
int ret = 1;
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);
@@ -1176,6 +1432,26 @@ int main(int argc, char **argv)
if (!chip)
goto terminate;
+ /*
+ * 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.
+ */
+ if (!read_flash_size_register(ser, chip, &flash_size_kbytes))
+ 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 (command_get_commands(ser, chip) < 0)
goto terminate;