summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGwendal Grignou <gwendal@chromium.org>2017-07-20 10:15:40 -0700
committerchrome-bot <chrome-bot@chromium.org>2017-07-28 17:45:13 -0700
commita35218e20499a95ec7706f87cb48ff39c5451663 (patch)
treee99e8d4d9d25b9f00d20cdf447da750397f14c7d
parent1b25735b732e7766aceb3f060e4ca205aba6d358 (diff)
downloadchrome-ec-a35218e20499a95ec7706f87cb48ff39c5451663.tar.gz
stm32f4: Add OTP support.
Add support for OTP memory: if needed store serial number in first bank. BUG=chromium:746471 BRANCH=none TEST=On sweetberry, check we can write serial number with serialno command. Check serial number survive a firmware update. First, check without write protect, check we can write 0s (but not 1s) serialno Serial number: NNNNNNNNNNNNNNNNNNNNNN > > serial set MMMMMMMMMMMMMMMMMMMMMMMMMMMMM Saving serial number Serial number: LLLLLLLLLLLLLLLLLLLLLL After lock enabled, check we can not overwrite. > serial set AMMMMMMMMMMMMMMMMMMMMMMMMMMMM Saving serial number Serial number: LLLLLLLLLLLLLLLLLLLLLL Access Denied Check that serialno returns "Uninitialized" if it was never set. Change-Id: I9ab08486a7c3e1958e964649640d69b5b70947e3 Signed-off-by: Gwendal Grignou <gwendal@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/580290 Reviewed-by: Nick Sanders <nsanders@chromium.org>
-rw-r--r--chip/stm32/build.mk1
-rw-r--r--chip/stm32/config-stm32f446.h3
-rw-r--r--chip/stm32/otp-stm32f4.c119
-rw-r--r--chip/stm32/registers.h13
4 files changed, 136 insertions, 0 deletions
diff --git a/chip/stm32/build.mk b/chip/stm32/build.mk
index b44b3ac2fe..c339885816 100644
--- a/chip/stm32/build.mk
+++ b/chip/stm32/build.mk
@@ -56,6 +56,7 @@ endif
chip-$(CONFIG_ADC)+=adc-$(CHIP_FAMILY).o
chip-$(CONFIG_STM32_CHARGER_DETECT)+=charger_detect.o
chip-$(CONFIG_DEBUG_PRINTF)+=debug_printf.o
+chip-$(CONFIG_OTP)+=otp-$(CHIP_FAMILY).o
chip-$(CONFIG_PWM)+=pwm.o
chip-$(CONFIG_RNG)+=trng.o
diff --git a/chip/stm32/config-stm32f446.h b/chip/stm32/config-stm32f446.h
index 27ee939521..ee43b4fb9b 100644
--- a/chip/stm32/config-stm32f446.h
+++ b/chip/stm32/config-stm32f446.h
@@ -54,5 +54,8 @@
#define CONFIG_FLASH_PSTATE
#undef CONFIG_FLASH_PSTATE_BANK
+/* Use OTP regions */
+#define CONFIG_OTP
+
/* Number of IRQ vectors on the NVIC */
#define CONFIG_IRQ_COUNT 97
diff --git a/chip/stm32/otp-stm32f4.c b/chip/stm32/otp-stm32f4.c
new file mode 100644
index 0000000000..a993af7042
--- /dev/null
+++ b/chip/stm32/otp-stm32f4.c
@@ -0,0 +1,119 @@
+/* Copyright 2017 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.
+ */
+
+/* OTP implementation for STM32F411 */
+
+#include "common.h"
+#include "console.h"
+#include "flash.h"
+#include "otp.h"
+#include "registers.h"
+#include "util.h"
+
+/*
+ * OTP is only used for saving the USB serial number.
+ */
+#ifdef CONFIG_SERIALNO_LEN
+/* Which block to use */
+#define OTP_SERIAL_BLOCK 0
+#define OTP_SERIAL_ADDR \
+ REG32_ADDR(STM32_OTP_BLOCK_DATA(OTP_SERIAL_BLOCK, 0))
+
+/* Number of word used in the block */
+#define OTP_SERIAL_BLOCK_SIZE (CONFIG_SERIALNO_LEN / sizeof(uint32_t))
+BUILD_ASSERT(CONFIG_SERIALNO_LEN % sizeof(uint32_t) == 0);
+BUILD_ASSERT(OTP_SERIAL_BLOCK_SIZE < STM32_OTP_BLOCK_SIZE);
+
+/*
+ * Write an OTP block
+ *
+ * @param block block to write.
+ * @param size Number of words to write.
+ * @param data Destination buffer for data.
+ */
+static int otp_write(uint8_t block, int size, const char *data)
+{
+ if (block >= STM32_OTP_BLOCK_NB)
+ return EC_ERROR_PARAM1;
+ if (size >= STM32_OTP_BLOCK_SIZE)
+ return EC_ERROR_PARAM2;
+ return flash_physical_write(STM32_OTP_BLOCK_DATA(block, 0) -
+ CONFIG_PROGRAM_MEMORY_BASE,
+ size * sizeof(uint32_t), data);
+}
+
+/*
+ * Check if an OTP block is protected.
+ *
+ * @param block protected block.
+ * @return non-zero if that block is read only.
+ */
+static int otp_get_protect(uint8_t block)
+{
+ uint32_t lock;
+
+ lock = REG32(STM32_OTP_LOCK(block));
+ return ((lock & STM32_OPT_LOCK_MASK(block)) == 0);
+}
+
+/*
+ * Set a particular OTP block as read only.
+ *
+ * @param block block to protect.
+ */
+static int otp_set_protect(uint8_t block)
+{
+ int rv;
+ uint32_t lock;
+
+ if (otp_get_protect(block))
+ return EC_SUCCESS;
+
+ lock = REG32(STM32_OTP_LOCK(block));
+ lock &= ~STM32_OPT_LOCK_MASK(block);
+ rv = flash_physical_write(STM32_OTP_LOCK(block) -
+ CONFIG_PROGRAM_MEMORY_BASE,
+ sizeof(uint32_t), (char *)&lock);
+ if (rv)
+ return rv;
+ else
+ return EC_SUCCESS;
+}
+
+const char *otp_read_serial(void)
+{
+ int i;
+
+ for (i = 0; i < OTP_SERIAL_BLOCK_SIZE; i++) {
+ if (OTP_SERIAL_ADDR[i] != -1)
+ return (char *)OTP_SERIAL_ADDR;
+ }
+ return NULL;
+}
+
+int otp_write_serial(const char *serialno)
+{
+ int i, ret;
+ char otp_serial[CONFIG_SERIALNO_LEN];
+
+ if (otp_get_protect(OTP_SERIAL_BLOCK))
+ return EC_ERROR_ACCESS_DENIED;
+
+ /* Copy in serialno. */
+ for (i = 0; i < CONFIG_SERIALNO_LEN - 1; i++) {
+ otp_serial[i] = serialno[i];
+ if (serialno[i] == 0)
+ break;
+ }
+ for (; i < CONFIG_SERIALNO_LEN; i++)
+ otp_serial[i] = 0;
+
+ ret = otp_write(OTP_SERIAL_BLOCK, OTP_SERIAL_BLOCK_SIZE, otp_serial);
+ if (ret == EC_SUCCESS)
+ return otp_set_protect(OTP_SERIAL_BLOCK);
+ else
+ return ret;
+}
+#endif
diff --git a/chip/stm32/registers.h b/chip/stm32/registers.h
index 764dc79af6..3e1bf1df14 100644
--- a/chip/stm32/registers.h
+++ b/chip/stm32/registers.h
@@ -1479,6 +1479,19 @@ typedef volatile struct stm32_spi_regs stm32_spi_regs_t;
#define STM32_OPTB_COMPL_SHIFT 8
+#define STM32_OTP_BASE 0x1FFF7800
+#define STM32_OTP_BLOCK_NB 16
+#define STM32_OTP_BLOCK_SIZE 32
+#define STM32_OTP_BLOCK_DATA(_block, _offset) \
+ (STM32_OTP_BASE + STM32_OTP_BLOCK_SIZE * (_block) + (_offset) * 4)
+#define STM32_OTP_UNLOCK_BYTE 0x00
+#define STM32_OTP_LOCK_BYTE 0xFF
+#define STM32_OTP_LOCK_BASE \
+ (STM32_OTP_BASE + STM32_OTP_BLOCK_NB * STM32_OTP_BLOCK_SIZE)
+#define STM32_OTP_LOCK(_block) \
+ (STM32_OTP_LOCK_BASE + ((_block) / 4) * 4)
+#define STM32_OPT_LOCK_MASK(_block) ((0xFF << ((_block) % 4) * 8))
+
#else
#error Unsupported chip variant
#endif