aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEtienne Carriere <etienne.carriere@st.com>2019-02-25 08:09:49 +0100
committerJérôme Forissier <jerome.forissier@linaro.org>2019-02-25 11:11:40 +0100
commitd64485e47cdf982cdbf549ad6213138ca3970949 (patch)
tree0f9463521b3610008139c42dc3394fa6f1190c4b
parent8e897b6b6e11445198de278eaa545cb374494c48 (diff)
stm32_bsec: OTP driver for stm32mp platforms
BSEC is a one time programmable (OTP) memory interface for stm32mp SoCs. OTPs are grouped into 32bit words identified by a incremental ID starting from 0. Shadowed OTPs are loaded in a volatile memory yet used as OTP values by the software. The platform shall implement stm32mp_get_bsec_static_cfg() to provide BSEC driver some information as the BSEC memory size and its lower/upper threshold ID that split non-secure from secure OTPs. Signed-off-by: Etienne Carriere <etienne.carriere@st.com> Signed-off-by: Christophe Montaud <christophe.montaud@st.com> Signed-off-by: Lionel Debieve <lionel.debieve@st.com> Signed-off-by: Mathieu Belou <mathieu.belou@st.com> Signed-off-by: Nicolas Le Bayon <nicolas.le.bayon@st.com> Signed-off-by: Yann Gautier <yann.gautier@st.com> Acked-by: Jens Wiklander <jens.wiklander@linaro.org>
-rw-r--r--core/arch/arm/plat-stm32mp1/stm32_util.h22
-rw-r--r--core/drivers/stm32_bsec.c553
-rw-r--r--core/drivers/sub.mk1
-rw-r--r--core/include/drivers/stm32_bsec.h134
4 files changed, 710 insertions, 0 deletions
diff --git a/core/arch/arm/plat-stm32mp1/stm32_util.h b/core/arch/arm/plat-stm32mp1/stm32_util.h
index 3517ee23..ff5864fe 100644
--- a/core/arch/arm/plat-stm32mp1/stm32_util.h
+++ b/core/arch/arm/plat-stm32mp1/stm32_util.h
@@ -6,6 +6,9 @@
#ifndef __STM32_UTIL_H__
#define __STM32_UTIL_H__
+#include <assert.h>
+#include <drivers/stm32_bsec.h>
+#include <kernel/panic.h>
#include <stdint.h>
/* Backup registers and RAM utils */
@@ -64,4 +67,23 @@ bool stm32_clock_is_enabled(unsigned long id);
void stm32_reset_assert(unsigned int id);
void stm32_reset_deassert(unsigned int id);
+/*
+ * Structure and API function for BSEC driver to get some platform data.
+ *
+ * @base: BSEC interface registers physical base address
+ * @upper_start: Base ID for the BSEC upper words in the platform
+ * @max_id: Max value for BSEC word ID for the platform
+ * @closed_device_id: BSEC word ID storing the "closed_device" OTP bit
+ * @closed_device_position: Bit position of "closed_device" bit in the OTP word
+ */
+struct stm32_bsec_static_cfg {
+ paddr_t base;
+ unsigned int upper_start;
+ unsigned int max_id;
+ unsigned int closed_device_id;
+ unsigned int closed_device_position;
+};
+
+void stm32mp_get_bsec_static_cfg(struct stm32_bsec_static_cfg *cfg);
+
#endif /*__STM32_UTIL_H__*/
diff --git a/core/drivers/stm32_bsec.c b/core/drivers/stm32_bsec.c
new file mode 100644
index 00000000..b6755042
--- /dev/null
+++ b/core/drivers/stm32_bsec.c
@@ -0,0 +1,553 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2017-2019, STMicroelectronics
+ */
+
+#include <assert.h>
+#include <drivers/stm32_bsec.h>
+#include <io.h>
+#include <kernel/delay.h>
+#include <kernel/generic_boot.h>
+#include <kernel/spinlock.h>
+#include <limits.h>
+#include <mm/core_memprot.h>
+#include <platform_config.h>
+#include <stm32_util.h>
+#include <types_ext.h>
+#include <util.h>
+
+#define BSEC_OTP_MASK GENMASK_32(4, 0)
+#define BSEC_OTP_BANK_SHIFT 5
+
+/* Permanent lock bitmasks */
+#define ADDR_LOWER_OTP_PERLOCK_SHIFT 3
+#define DATA_LOWER_OTP_PERLOCK_BIT 3
+#define DATA_LOWER_OTP_PERLOCK_MASK GENMASK_32(2, 0)
+#define ADDR_UPPER_OTP_PERLOCK_SHIFT 4
+#define DATA_UPPER_OTP_PERLOCK_BIT 1
+#define DATA_UPPER_OTP_PERLOCK_MASK GENMASK_32(3, 0)
+
+/* BSEC register offset */
+#define BSEC_OTP_CONF_OFF 0x000U
+#define BSEC_OTP_CTRL_OFF 0x004U
+#define BSEC_OTP_WRDATA_OFF 0x008U
+#define BSEC_OTP_STATUS_OFF 0x00CU
+#define BSEC_OTP_LOCK_OFF 0x010U
+#define BSEC_DEN_OFF 0x014U
+#define BSEC_FEN_OFF 0x018U
+#define BSEC_DISTURBED_OFF 0x01CU
+#define BSEC_DISTURBED1_OFF 0x020U
+#define BSEC_DISTURBED2_OFF 0x024U
+#define BSEC_ERROR_OFF 0x034U
+#define BSEC_ERROR1_OFF 0x038U
+#define BSEC_ERROR2_OFF 0x03CU
+#define BSEC_WRLOCK_OFF 0x04CU
+#define BSEC_WRLOCK1_OFF 0x050U
+#define BSEC_WRLOCK2_OFF 0x054U
+#define BSEC_SPLOCK_OFF 0x064U
+#define BSEC_SPLOCK1_OFF 0x068U
+#define BSEC_SPLOCK2_OFF 0x06CU
+#define BSEC_SWLOCK_OFF 0x07CU
+#define BSEC_SWLOCK1_OFF 0x080U
+#define BSEC_SWLOCK2_OFF 0x084U
+#define BSEC_SRLOCK_OFF 0x094U
+#define BSEC_SRLOCK1_OFF 0x098U
+#define BSEC_SRLOCK2_OFF 0x09CU
+#define BSEC_JTAG_IN_OFF 0x0ACU
+#define BSEC_JTAG_OUT_OFF 0x0B0U
+#define BSEC_SCRATCH_OFF 0x0B4U
+#define BSEC_OTP_DATA_OFF 0x200U
+#define BSEC_IPHW_CFG_OFF 0xFF0U
+#define BSEC_IPVR_OFF 0xFF4U
+#define BSEC_IP_ID_OFF 0xFF8U
+#define BSEC_IP_MAGIC_ID_OFF 0xFFCU
+
+/* BSEC_CONFIGURATION Register */
+#define BSEC_CONF_POWER_UP_MASK BIT(0)
+#define BSEC_CONF_POWER_UP_SHIFT 0
+#define BSEC_CONF_FRQ_MASK GENMASK_32(2, 1)
+#define BSEC_CONF_FRQ_SHIFT 1
+#define BSEC_CONF_PRG_WIDTH_MASK GENMASK_32(6, 3)
+#define BSEC_CONF_PRG_WIDTH_SHIFT 3
+#define BSEC_CONF_TREAD_MASK GENMASK_32(8, 7)
+#define BSEC_CONF_TREAD_SHIFT 7
+
+/* BSEC_CONTROL Register */
+#define BSEC_READ 0x000U
+#define BSEC_WRITE 0x100U
+#define BSEC_LOCK 0x200U
+
+/* BSEC_STATUS Register */
+#define BSEC_MODE_STATUS_MASK GENMASK_32(2, 0)
+#define BSEC_MODE_BUSY_MASK BIT(3)
+#define BSEC_MODE_PROGFAIL_MASK BIT(4)
+#define BSEC_MODE_PWR_MASK BIT(5)
+#define BSEC_MODE_BIST1_LOCK_MASK BIT(6)
+#define BSEC_MODE_BIST2_LOCK_MASK BIT(7)
+
+/* BSEC_DEBUG */
+#define BSEC_HDPEN BIT(4)
+#define BSEC_SPIDEN BIT(5)
+#define BSEC_SPINDEN BIT(6)
+#define BSEC_DBGSWGEN BIT(10)
+#define BSEC_DEN_ALL_MSK GENMASK_32(10, 0)
+
+/*
+ * OTP Lock services definition
+ * Value must corresponding to the bit position in the register
+ */
+#define BSEC_LOCK_UPPER_OTP 0x00
+#define BSEC_LOCK_DEBUG 0x02
+#define BSEC_LOCK_PROGRAM 0x03
+
+/* Timeout when polling on status */
+#define BSEC_TIMEOUT_US 1000
+
+struct bsec_dev {
+ struct io_pa_va base;
+ unsigned int upper_base;
+ unsigned int max_id;
+ bool closed_device;
+};
+
+/* Only 1 instance of BSEC is expected per platform */
+static struct bsec_dev bsec_dev;
+
+/* BSEC access protection */
+static unsigned int lock = SPINLOCK_UNLOCK;
+
+static uint32_t bsec_lock(void)
+{
+ return may_spin_lock(&lock);
+}
+
+static void bsec_unlock(uint32_t exceptions)
+{
+ may_spin_unlock(&lock, exceptions);
+}
+
+static uint32_t otp_max_id(void)
+{
+ return bsec_dev.max_id;
+}
+
+static uint32_t otp_bank_offset(uint32_t otp_id)
+{
+ assert(otp_id <= otp_max_id());
+
+ return ((otp_id & ~BSEC_OTP_MASK) >> BSEC_OTP_BANK_SHIFT) *
+ sizeof(uint32_t);
+}
+
+static vaddr_t bsec_base(void)
+{
+ return io_pa_or_va(&bsec_dev.base);
+}
+
+static uint32_t bsec_status(void)
+{
+ return io_read32(bsec_base() + BSEC_OTP_STATUS_OFF);
+}
+
+static TEE_Result check_no_error(uint32_t otp_id)
+{
+ uint32_t bit = BIT(otp_id & BSEC_OTP_MASK);
+ uint32_t bank = otp_bank_offset(otp_id);
+
+ if (io_read32(bsec_base() + BSEC_DISTURBED_OFF + bank) & bit)
+ return TEE_ERROR_GENERIC;
+
+ if (io_read32(bsec_base() + BSEC_ERROR_OFF + bank) & bit)
+ return TEE_ERROR_GENERIC;
+
+ return TEE_SUCCESS;
+}
+
+static TEE_Result power_up_safmem(void)
+{
+ uint64_t timeout_ref = timeout_init_us(BSEC_TIMEOUT_US);
+
+ io_mask32(bsec_base() + BSEC_OTP_CONF_OFF, BSEC_CONF_POWER_UP_MASK,
+ BSEC_CONF_POWER_UP_MASK);
+
+ /*
+ * If a timeout is detected, test the condition again to consider
+ * cases where timeout is due to the executing TEE thread rescheduling.
+ */
+ while (!timeout_elapsed(timeout_ref))
+ if (bsec_status() & BSEC_MODE_PWR_MASK)
+ break;
+
+ if (bsec_status() & BSEC_MODE_PWR_MASK)
+ return TEE_SUCCESS;
+
+ return TEE_ERROR_GENERIC;
+}
+
+static TEE_Result power_down_safmem(void)
+{
+ uint64_t timeout_ref = timeout_init_us(BSEC_TIMEOUT_US);
+
+ io_mask32(bsec_base() + BSEC_OTP_CONF_OFF, 0, BSEC_CONF_POWER_UP_MASK);
+
+ /*
+ * If a timeout is detected, test the condition again to consider
+ * cases where timeout is due to the executing TEE thread rescheduling.
+ */
+ while (!timeout_elapsed(timeout_ref))
+ if (!(bsec_status() & BSEC_MODE_PWR_MASK))
+ break;
+
+ if (!(bsec_status() & BSEC_MODE_PWR_MASK))
+ return TEE_SUCCESS;
+
+ return TEE_ERROR_GENERIC;
+}
+
+TEE_Result stm32_bsec_shadow_register(uint32_t otp_id)
+{
+ TEE_Result result = 0;
+ uint32_t exceptions = 0;
+ uint64_t timeout_ref = 0;
+
+ if (otp_id > otp_max_id())
+ return TEE_ERROR_BAD_PARAMETERS;
+
+ /* Check if shadowing of OTP is locked */
+ if (stm32_bsec_read_sr_lock(otp_id))
+ IMSG("OTP locked, register will not be refreshed");
+
+ exceptions = bsec_lock();
+
+ result = power_up_safmem();
+ if (result)
+ return result;
+
+ io_write32(bsec_base() + BSEC_OTP_CTRL_OFF, otp_id | BSEC_READ);
+
+ timeout_ref = timeout_init_us(BSEC_TIMEOUT_US);
+ while (!timeout_elapsed(timeout_ref))
+ if (!(bsec_status() & BSEC_MODE_BUSY_MASK))
+ break;
+
+ if (bsec_status() & BSEC_MODE_BUSY_MASK)
+ result = TEE_ERROR_GENERIC;
+ else
+ result = check_no_error(otp_id);
+
+ power_down_safmem();
+
+ bsec_unlock(exceptions);
+
+ return result;
+}
+
+TEE_Result stm32_bsec_read_otp(uint32_t *value, uint32_t otp_id)
+{
+ TEE_Result result = 0;
+ uint32_t exceptions = 0;
+
+ if (otp_id > otp_max_id())
+ return TEE_ERROR_BAD_PARAMETERS;
+
+ exceptions = bsec_lock();
+
+ *value = io_read32(bsec_base() + BSEC_OTP_DATA_OFF +
+ (otp_id * sizeof(uint32_t)));
+
+ result = check_no_error(otp_id);
+
+ bsec_unlock(exceptions);
+
+ return result;
+}
+
+TEE_Result stm32_bsec_shadow_read_otp(uint32_t *otp_value, uint32_t otp_id)
+{
+ TEE_Result result = 0;
+
+ result = stm32_bsec_shadow_register(otp_id);
+ if (result) {
+ EMSG("BSEC %" PRIu32 " Shadowing Error %x", otp_id, result);
+ return result;
+ }
+
+ result = stm32_bsec_read_otp(otp_value, otp_id);
+ if (result)
+ EMSG("BSEC %" PRIu32 " Read Error %x", otp_id, result);
+
+ return result;
+}
+
+TEE_Result stm32_bsec_write_otp(uint32_t value, uint32_t otp_id)
+{
+ TEE_Result result = 0;
+ uint32_t exceptions = 0;
+ vaddr_t otp_data_base = bsec_base() + BSEC_OTP_DATA_OFF;
+
+ if (otp_id > otp_max_id())
+ return TEE_ERROR_BAD_PARAMETERS;
+
+ /* Check if programming of OTP is locked */
+ if (stm32_bsec_read_sw_lock(otp_id))
+ IMSG("OTP locked, write will be ignored");
+
+ exceptions = bsec_lock();
+
+ io_write32(otp_data_base + (otp_id * sizeof(uint32_t)), value);
+
+ result = check_no_error(otp_id);
+
+ bsec_unlock(exceptions);
+
+ return result;
+}
+
+TEE_Result stm32_bsec_program_otp(uint32_t value, uint32_t otp_id)
+{
+ TEE_Result result = 0;
+ uint32_t exceptions = 0;
+ uint64_t timeout_ref;
+
+ if (otp_id > otp_max_id())
+ return TEE_ERROR_BAD_PARAMETERS;
+
+ /* Check if programming of OTP is locked */
+ if (stm32_bsec_read_sp_lock(otp_id))
+ IMSG("OTP locked, prog will be ignored");
+
+ if (io_read32(bsec_base() + BSEC_OTP_LOCK_OFF) & BIT(BSEC_LOCK_PROGRAM))
+ IMSG("GPLOCK activated, prog will be ignored");
+
+ exceptions = bsec_lock();
+
+ result = power_up_safmem();
+ if (result)
+ return result;
+
+ io_write32(bsec_base() + BSEC_OTP_WRDATA_OFF, value);
+ io_write32(bsec_base() + BSEC_OTP_CTRL_OFF, otp_id | BSEC_WRITE);
+
+ timeout_ref = timeout_init_us(BSEC_TIMEOUT_US);
+ while (!timeout_elapsed(timeout_ref))
+ if (!(bsec_status() & BSEC_MODE_BUSY_MASK))
+ break;
+
+ if (bsec_status() & (BSEC_MODE_BUSY_MASK | BSEC_MODE_PROGFAIL_MASK))
+ result = TEE_ERROR_GENERIC;
+ else
+ result = check_no_error(otp_id);
+
+ power_down_safmem();
+
+ bsec_unlock(exceptions);
+
+ return result;
+}
+
+TEE_Result stm32_bsec_permanent_lock_otp(uint32_t otp_id)
+{
+ TEE_Result result = 0;
+ uint32_t data = 0;
+ uint32_t addr = 0;
+ uint32_t exceptions = 0;
+ vaddr_t base = bsec_base();
+ uint64_t timeout_ref;
+
+ if (otp_id > otp_max_id())
+ return TEE_ERROR_BAD_PARAMETERS;
+
+ if (otp_id < bsec_dev.upper_base) {
+ addr = otp_id >> ADDR_LOWER_OTP_PERLOCK_SHIFT;
+ data = DATA_LOWER_OTP_PERLOCK_BIT <<
+ ((otp_id & DATA_LOWER_OTP_PERLOCK_MASK) << 1U);
+ } else {
+ addr = (otp_id >> ADDR_UPPER_OTP_PERLOCK_SHIFT) + 2U;
+ data = DATA_UPPER_OTP_PERLOCK_BIT <<
+ (otp_id & DATA_UPPER_OTP_PERLOCK_MASK);
+ }
+
+ exceptions = bsec_lock();
+
+ result = power_up_safmem();
+ if (result)
+ return result;
+
+ io_write32(base + BSEC_OTP_WRDATA_OFF, data);
+ io_write32(base + BSEC_OTP_CTRL_OFF, addr | BSEC_WRITE | BSEC_LOCK);
+
+ timeout_ref = timeout_init_us(BSEC_TIMEOUT_US);
+ while (!timeout_elapsed(timeout_ref))
+ if (!(bsec_status() & BSEC_MODE_BUSY_MASK))
+ break;
+
+ if (bsec_status() & (BSEC_MODE_BUSY_MASK | BSEC_MODE_PROGFAIL_MASK))
+ result = TEE_ERROR_BAD_PARAMETERS;
+ else
+ result = check_no_error(otp_id);
+
+ power_down_safmem();
+
+ bsec_unlock(exceptions);
+
+ return result;
+}
+
+TEE_Result stm32_bsec_write_debug_conf(uint32_t value)
+{
+ TEE_Result result = TEE_ERROR_GENERIC;
+ uint32_t masked_val = value & BSEC_DEN_ALL_MSK;
+ uint32_t exceptions = 0;
+
+ exceptions = bsec_lock();
+
+ io_write32(bsec_base() + BSEC_DEN_OFF, value);
+
+ if ((io_read32(bsec_base() + BSEC_DEN_OFF) ^ masked_val) == 0U)
+ result = TEE_SUCCESS;
+
+ bsec_unlock(exceptions);
+
+ return result;
+}
+
+uint32_t stm32_bsec_read_debug_conf(void)
+{
+ return io_read32(bsec_base() + BSEC_DEN_OFF);
+}
+
+static bool write_bsec_lock(uint32_t otp_id, uint32_t value, size_t lock_offset)
+{
+ uint32_t bank = otp_bank_offset(otp_id);
+ uint32_t otp_mask = BIT(otp_id & BSEC_OTP_MASK);
+ vaddr_t lock_addr = bsec_base() + bank + lock_offset;
+ uint32_t bank_value = 0;
+ uint32_t exceptions = 0;
+
+ if (!value)
+ return false;
+
+ exceptions = bsec_lock();
+
+ bank_value = io_read32(lock_addr);
+
+ if ((bank_value & otp_mask) != value) {
+ /*
+ * We can write 0 in all other OTP
+ * if the lock is activated in one of other OTP.
+ * Write 0 has no effect.
+ */
+ io_write32(lock_addr, bank_value | otp_mask);
+ }
+
+ bsec_unlock(exceptions);
+
+ return true;
+}
+
+bool stm32_bsec_write_sr_lock(uint32_t otp_id, uint32_t value)
+{
+ return write_bsec_lock(otp_id, value, BSEC_SRLOCK_OFF);
+}
+
+bool stm32_bsec_write_sw_lock(uint32_t otp_id, uint32_t value)
+{
+ return write_bsec_lock(otp_id, value, BSEC_SWLOCK_OFF);
+}
+
+bool stm32_bsec_write_sp_lock(uint32_t otp_id, uint32_t value)
+{
+ return write_bsec_lock(otp_id, value, BSEC_SPLOCK_OFF);
+}
+
+static bool read_bsec_lock(uint32_t otp_id, size_t lock_offset)
+{
+ uint32_t bank = otp_bank_offset(otp_id);
+ uint32_t otp_mask = BIT(otp_id & BSEC_OTP_MASK);
+ vaddr_t lock_addr = bsec_base() + bank + lock_offset;
+
+ return io_read32(lock_addr) & otp_mask;
+}
+
+bool stm32_bsec_read_sr_lock(uint32_t otp_id)
+{
+ return read_bsec_lock(otp_id, BSEC_SRLOCK_OFF);
+}
+
+bool stm32_bsec_read_sw_lock(uint32_t otp_id)
+{
+ return read_bsec_lock(otp_id, BSEC_SWLOCK_OFF);
+}
+
+bool stm32_bsec_read_sp_lock(uint32_t otp_id)
+{
+ return read_bsec_lock(otp_id, BSEC_SPLOCK_OFF);
+}
+
+bool stm32_bsec_wr_lock(uint32_t otp_id)
+{
+ uint32_t bank = otp_bank_offset(otp_id);
+ uint32_t lock_bit = BIT(otp_id & BSEC_OTP_MASK);
+
+ if (io_read32(bsec_base() + BSEC_WRLOCK_OFF + bank) & lock_bit) {
+ /*
+ * In case of write don't need to write,
+ * the lock is already set.
+ */
+ return true;
+ }
+
+ return false;
+}
+
+uint32_t stm32_bsec_otp_lock(uint32_t service, uint32_t value)
+{
+ vaddr_t addr = bsec_base() + BSEC_OTP_LOCK_OFF;
+
+ switch (service) {
+ case BSEC_LOCK_UPPER_OTP:
+ io_write32(addr, value << BSEC_LOCK_UPPER_OTP);
+ break;
+ case BSEC_LOCK_DEBUG:
+ io_write32(addr, value << BSEC_LOCK_DEBUG);
+ break;
+ case BSEC_LOCK_PROGRAM:
+ io_write32(addr, value << BSEC_LOCK_PROGRAM);
+ break;
+ default:
+ return TEE_ERROR_BAD_PARAMETERS;
+ }
+
+ return TEE_SUCCESS;
+}
+
+bool stm32_bsec_nsec_can_access_otp(uint32_t otp_id)
+{
+ if (otp_id > otp_max_id())
+ return false;
+
+ return otp_id < bsec_dev.upper_base || !bsec_dev.closed_device;
+}
+
+static TEE_Result initialize_bsec(void)
+{
+ struct stm32_bsec_static_cfg cfg = { 0 };
+ uint32_t otp = 0;
+ TEE_Result result = 0;
+
+ stm32mp_get_bsec_static_cfg(&cfg);
+
+ bsec_dev.base.pa = cfg.base;
+ bsec_dev.upper_base = cfg.upper_start;
+ bsec_dev.max_id = cfg.max_id;
+ bsec_dev.closed_device = true;
+
+ /* Disable closed device mode upon platform closed device OTP value */
+ result = stm32_bsec_shadow_read_otp(&otp, cfg.closed_device_id);
+ if (!result && !(otp & BIT(cfg.closed_device_position)))
+ bsec_dev.closed_device = false;
+
+ return TEE_SUCCESS;
+}
+
+driver_init(initialize_bsec);
diff --git a/core/drivers/sub.mk b/core/drivers/sub.mk
index dc505d8e..b1d254de 100644
--- a/core/drivers/sub.mk
+++ b/core/drivers/sub.mk
@@ -19,6 +19,7 @@ srcs-$(CFG_DRA7_RNG) += dra7_rng.c
srcs-$(CFG_STIH_UART) += stih_asc.c
srcs-$(CFG_ATMEL_UART) += atmel_uart.c
srcs-$(CFG_MVEBU_UART) += mvebu_uart.c
+srcs-$(CFG_STM32_BSEC) += stm32_bsec.c
srcs-$(CFG_STM32_ETZPC) += stm32_etzpc.c
srcs-$(CFG_STM32_GPIO) += stm32_gpio.c
srcs-$(CFG_STM32_UART) += stm32_uart.c
diff --git a/core/include/drivers/stm32_bsec.h b/core/include/drivers/stm32_bsec.h
new file mode 100644
index 00000000..f6fc3287
--- /dev/null
+++ b/core/include/drivers/stm32_bsec.h
@@ -0,0 +1,134 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2017-2019, STMicroelectronics
+ */
+
+#ifndef __STM32_BSEC_H
+#define __STM32_BSEC_H
+
+#include <stdint.h>
+#include <tee_api.h>
+
+/*
+ * Load OTP from SAFMEM and provide its value
+ * @value: Output read value
+ * @otp_id: OTP number
+ * Return a TEE_Result compliant return value
+ */
+TEE_Result stm32_bsec_shadow_read_otp(uint32_t *value, uint32_t otp_id);
+
+/*
+ * Copy SAFMEM OTP to BSEC data.
+ * @otp_id: OTP number.
+ * Return a TEE_Result compliant return value
+ */
+TEE_Result stm32_bsec_shadow_register(uint32_t otp_id);
+
+/*
+ * Read an OTP data value
+ * @value: Output read value
+ * @otp_id: OTP number
+ * Return a TEE_Result compliant return value
+ */
+TEE_Result stm32_bsec_read_otp(uint32_t *value, uint32_t otp_id);
+
+/*
+ * Write value in BSEC data register
+ * @value: Value to write
+ * @otp_id: OTP number
+ * Return a TEE_Result compliant return value
+ */
+TEE_Result stm32_bsec_write_otp(uint32_t value, uint32_t otp_id);
+
+/*
+ * Program a bit in SAFMEM without BSEC data refresh
+ * @value: Value to program.
+ * @otp_id: OTP number.
+ * Return a TEE_Result compliant return value
+ */
+TEE_Result stm32_bsec_program_otp(uint32_t value, uint32_t otp_id);
+
+/*
+ * Permanent lock of OTP in SAFMEM
+ * @otp_id: OTP number
+ * Return a TEE_Result compliant return value
+ */
+TEE_Result stm32_bsec_permanent_lock_otp(uint32_t otp_id);
+
+/*
+ * Enable/disable debug service
+ * @value: Value to write
+ * Return a TEE_Result compliant return value
+ */
+TEE_Result stm32_bsec_write_debug_conf(uint32_t value);
+
+/* Return debug configuration read from BSEC */
+uint32_t stm32_bsec_read_debug_conf(void);
+
+/*
+ * Write shadow-read lock
+ * @otp_id: OTP number
+ * @value: Value to write in the register, must be non null
+ * Return true if OTP is locked, else false
+ */
+bool stm32_bsec_write_sr_lock(uint32_t otp_id, uint32_t value);
+
+/*
+ * Read shadow-read lock
+ * @otp_id: OTP number
+ * Return true if OTP is locked, else false
+ */
+bool stm32_bsec_read_sr_lock(uint32_t otp_id);
+
+/*
+ * Write shadow-write lock
+ * @otp_id: OTP number
+ * @value: Value to write in the register, must be non null
+ * Return true if OTP is locked, else false
+ */
+bool stm32_bsec_write_sw_lock(uint32_t otp_id, uint32_t value);
+
+/*
+ * Read shadow-write lock
+ * @otp_id: OTP number
+ * Return true if OTP is locked, else false
+ */
+bool stm32_bsec_read_sw_lock(uint32_t otp_id);
+
+/*
+ * Write shadow-program lock
+ * @otp_id: OTP number
+ * @value: Value to write in the register, must be non null
+ * Return true if OTP is locked, else false
+ */
+bool stm32_bsec_write_sp_lock(uint32_t otp_id, uint32_t value);
+
+/*
+ * Read shadow-program lock
+ * @otp_id: OTP number
+ * Return true if OTP is locked, else false
+ */
+bool stm32_bsec_read_sp_lock(uint32_t otp_id);
+
+/*
+ * Read permanent lock status
+ * @otp_id: OTP number
+ * Return true if OTP is locked, else false
+ */
+bool stm32_bsec_wr_lock(uint32_t otp_id);
+
+/*
+ * Lock Upper OTP or Global programming or debug enable
+ * @service: Service to lock, see header file
+ * @value: Value to write must always set to 1 (only use for debug purpose)
+ * Return a TEE_Result compliant return value
+ */
+TEE_Result stm32_bsec_otp_lock(uint32_t service, uint32_t value);
+
+/*
+ * Return true if non-secure world is allowed to read the target OTP
+ * @otp_id: OTP number
+ */
+bool stm32_bsec_nsec_can_access_otp(uint32_t otp_id);
+
+#endif /*__STM32_BSEC_H*/