stm32mp1: add BSEC driver
authorYann Gautier <yann.gautier@st.com>
Thu, 17 Jan 2019 13:52:47 +0000 (14:52 +0100)
committerYann Gautier <yann.gautier@st.com>
Fri, 18 Jan 2019 14:45:08 +0000 (15:45 +0100)
The BSEC (Boot and Security and OTP control) is intended to control an OTP
(one time programmable) fuse box, used for on-chip non-volatile storage
for device configuration and security parameters.

Change-Id: I38c44684c7b9c6a1f24ec0ae3fe99cec481d5a51
Signed-off-by: Yann Gautier <yann.gautier@st.com>
Signed-off-by: Etienne Carriere <etienne.carriere@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>
drivers/st/bsec/bsec.c [new file with mode: 0644]
include/drivers/st/bsec.h [new file with mode: 0644]
plat/st/stm32mp1/platform.mk
plat/st/stm32mp1/stm32mp1_def.h

diff --git a/drivers/st/bsec/bsec.c b/drivers/st/bsec/bsec.c
new file mode 100644 (file)
index 0000000..aaecf1f
--- /dev/null
@@ -0,0 +1,913 @@
+/*
+ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <limits.h>
+
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/st/bsec.h>
+#include <lib/mmio.h>
+#include <lib/spinlock.h>
+
+#define BSEC_IP_VERSION_1_0    0x10
+#define BSEC_COMPAT            "st,stm32mp15-bsec"
+
+#define OTP_ACCESS_SIZE (round_up(OTP_MAX_SIZE, __WORD_BIT) / __WORD_BIT)
+
+static uint32_t otp_nsec_access[OTP_ACCESS_SIZE] __unused;
+
+static uint32_t bsec_power_safmem(bool power);
+
+/* BSEC access protection */
+static spinlock_t bsec_spinlock;
+static uintptr_t bsec_base;
+
+static void bsec_lock(void)
+{
+       const uint32_t mask = SCTLR_M_BIT | SCTLR_C_BIT;
+
+       /* Lock is currently required only when MMU and cache are enabled */
+       if ((read_sctlr() & mask) == mask) {
+               spin_lock(&bsec_spinlock);
+       }
+}
+
+static void bsec_unlock(void)
+{
+       const uint32_t mask = SCTLR_M_BIT | SCTLR_C_BIT;
+
+       /* Unlock is required only when MMU and cache are enabled */
+       if ((read_sctlr() & mask) == mask) {
+               spin_unlock(&bsec_spinlock);
+       }
+}
+
+static int bsec_get_dt_node(struct dt_node_info *info)
+{
+       int node;
+
+       node = dt_get_node(info, -1, BSEC_COMPAT);
+       if (node < 0) {
+               return -FDT_ERR_NOTFOUND;
+       }
+
+       return node;
+}
+
+#if defined(IMAGE_BL32)
+static void enable_non_secure_access(uint32_t otp)
+{
+       otp_nsec_access[otp / __WORD_BIT] |= BIT(otp % __WORD_BIT);
+
+       if (bsec_shadow_register(otp) != BSEC_OK) {
+               panic();
+       }
+}
+
+static bool non_secure_can_access(uint32_t otp)
+{
+       return (otp_nsec_access[otp / __WORD_BIT] &
+               BIT(otp % __WORD_BIT)) != 0;
+}
+
+static int bsec_dt_otp_nsec_access(void *fdt, int bsec_node)
+{
+       int bsec_subnode;
+
+       fdt_for_each_subnode(bsec_subnode, fdt, bsec_node) {
+               const fdt32_t *cuint;
+               uint32_t reg;
+               uint32_t i;
+               uint32_t size;
+               uint8_t status;
+
+               cuint = fdt_getprop(fdt, bsec_subnode, "reg", NULL);
+               if (cuint == NULL) {
+                       panic();
+               }
+
+               reg = fdt32_to_cpu(*cuint) / sizeof(uint32_t);
+               if (reg < STM32MP1_UPPER_OTP_START) {
+                       continue;
+               }
+
+               status = fdt_get_status(bsec_subnode);
+               if ((status & DT_NON_SECURE) == 0U)  {
+                       continue;
+               }
+
+               size = fdt32_to_cpu(*(cuint + 1)) / sizeof(uint32_t);
+
+               if ((fdt32_to_cpu(*(cuint + 1)) % sizeof(uint32_t)) != 0) {
+                       size++;
+               }
+
+               for (i = reg; i < (reg + size); i++) {
+                       enable_non_secure_access(i);
+               }
+       }
+
+       return 0;
+}
+#endif
+
+static uint32_t otp_bank_offset(uint32_t otp)
+{
+       assert(otp <= STM32MP1_OTP_MAX_ID);
+
+       return ((otp & ~BSEC_OTP_MASK) >> BSEC_OTP_BANK_SHIFT) *
+              sizeof(uint32_t);
+}
+
+static uint32_t bsec_check_error(uint32_t otp)
+{
+       uint32_t bit = BIT(otp & BSEC_OTP_MASK);
+       uint32_t bank = otp_bank_offset(otp);
+
+       if ((mmio_read_32(bsec_base + BSEC_DISTURBED_OFF + bank) & bit) != 0U) {
+               return BSEC_DISTURBED;
+       }
+
+       if ((mmio_read_32(bsec_base + BSEC_ERROR_OFF + bank) & bit) != 0U) {
+               return BSEC_ERROR;
+       }
+
+       return BSEC_OK;
+}
+
+/*
+ * bsec_probe: initialize BSEC driver.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_probe(void)
+{
+       void *fdt;
+       int node;
+       struct dt_node_info bsec_info;
+
+       if (fdt_get_address(&fdt) == 0) {
+               panic();
+       }
+
+       node = bsec_get_dt_node(&bsec_info);
+       if (node < 0) {
+               panic();
+       }
+
+       bsec_base = bsec_info.base;
+
+#if defined(IMAGE_BL32)
+       bsec_dt_otp_nsec_access(fdt, node);
+#endif
+       return BSEC_OK;
+}
+
+/*
+ * bsec_get_base: return BSEC base address.
+ */
+uint32_t bsec_get_base(void)
+{
+       return bsec_base;
+}
+
+/*
+ * bsec_set_config: enable and configure BSEC.
+ * cfg: pointer to param structure used to set register.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_set_config(struct bsec_config *cfg)
+{
+       uint32_t value;
+       int32_t result;
+
+       value = ((((uint32_t)cfg->freq << BSEC_CONF_FRQ_SHIFT) &
+                                               BSEC_CONF_FRQ_MASK) |
+                (((uint32_t)cfg->pulse_width << BSEC_CONF_PRG_WIDTH_SHIFT) &
+                                               BSEC_CONF_PRG_WIDTH_MASK) |
+                (((uint32_t)cfg->tread << BSEC_CONF_TREAD_SHIFT) &
+                                               BSEC_CONF_TREAD_MASK));
+
+       bsec_lock();
+
+       mmio_write_32(bsec_base + BSEC_OTP_CONF_OFF, value);
+
+       bsec_unlock();
+
+       result = bsec_power_safmem((bool)cfg->power &
+                                  BSEC_CONF_POWER_UP_MASK);
+       if (result != BSEC_OK) {
+               return result;
+       }
+
+       value = ((((uint32_t)cfg->upper_otp_lock << UPPER_OTP_LOCK_SHIFT) &
+                                               UPPER_OTP_LOCK_MASK) |
+                (((uint32_t)cfg->den_lock << DENREG_LOCK_SHIFT) &
+                                               DENREG_LOCK_MASK) |
+                (((uint32_t)cfg->prog_lock << GPLOCK_LOCK_SHIFT) &
+                                               GPLOCK_LOCK_MASK));
+
+       bsec_lock();
+
+       mmio_write_32(bsec_base + BSEC_OTP_LOCK_OFF, value);
+
+       bsec_unlock();
+
+       return BSEC_OK;
+}
+
+/*
+ * bsec_get_config: return config parameters set in BSEC registers.
+ * cfg: config param return.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_get_config(struct bsec_config *cfg)
+{
+       uint32_t value;
+
+       if (cfg == NULL) {
+               return BSEC_INVALID_PARAM;
+       }
+
+       value = mmio_read_32(bsec_base + BSEC_OTP_CONF_OFF);
+       cfg->power = (uint8_t)((value & BSEC_CONF_POWER_UP_MASK) >>
+                                               BSEC_CONF_POWER_UP_SHIFT);
+       cfg->freq = (uint8_t)((value & BSEC_CONF_FRQ_MASK) >>
+                                               BSEC_CONF_FRQ_SHIFT);
+       cfg->pulse_width = (uint8_t)((value & BSEC_CONF_PRG_WIDTH_MASK) >>
+                                               BSEC_CONF_PRG_WIDTH_SHIFT);
+       cfg->tread = (uint8_t)((value & BSEC_CONF_TREAD_MASK) >>
+                                               BSEC_CONF_TREAD_SHIFT);
+
+       value = mmio_read_32(bsec_base + BSEC_OTP_LOCK_OFF);
+       cfg->upper_otp_lock = (uint8_t)((value & UPPER_OTP_LOCK_MASK) >>
+                                               UPPER_OTP_LOCK_SHIFT);
+       cfg->den_lock = (uint8_t)((value & DENREG_LOCK_MASK) >>
+                                               DENREG_LOCK_SHIFT);
+       cfg->prog_lock = (uint8_t)((value & GPLOCK_LOCK_MASK) >>
+                                               GPLOCK_LOCK_SHIFT);
+
+       return BSEC_OK;
+}
+
+/*
+ * bsec_shadow_register: copy SAFMEM OTP to BSEC data.
+ * otp: OTP number.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_shadow_register(uint32_t otp)
+{
+       uint32_t result;
+       bool power_up = false;
+
+       if (otp > STM32MP1_OTP_MAX_ID) {
+               return BSEC_INVALID_PARAM;
+       }
+
+       /* Check if shadowing of OTP is locked */
+       if (bsec_read_sr_lock(otp)) {
+               VERBOSE("BSEC: OTP %i is locked and will not be refreshed\n",
+                       otp);
+       }
+
+       if ((bsec_get_status() & BSEC_MODE_PWR_MASK) == 0U) {
+               result = bsec_power_safmem(true);
+
+               if (result != BSEC_OK) {
+                       return result;
+               }
+
+               power_up = true;
+       }
+
+       bsec_lock();
+
+       /* Set BSEC_OTP_CTRL_OFF and set ADDR with the OTP value */
+       mmio_write_32(bsec_base + BSEC_OTP_CTRL_OFF, otp | BSEC_READ);
+
+       while ((bsec_get_status() & BSEC_MODE_BUSY_MASK) != 0U) {
+               ;
+       }
+
+       result = bsec_check_error(otp);
+
+       bsec_unlock();
+
+       if (power_up) {
+               if (bsec_power_safmem(false) != BSEC_OK) {
+                       panic();
+               }
+       }
+
+       return result;
+}
+
+/*
+ * bsec_read_otp: read an OTP data value.
+ * val: read value.
+ * otp: OTP number.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_read_otp(uint32_t *val, uint32_t otp)
+{
+       uint32_t result;
+
+       if (otp > STM32MP1_OTP_MAX_ID) {
+               return BSEC_INVALID_PARAM;
+       }
+
+       bsec_lock();
+
+       *val = mmio_read_32(bsec_base + BSEC_OTP_DATA_OFF +
+                           (otp * sizeof(uint32_t)));
+
+       result = bsec_check_error(otp);
+
+       bsec_unlock();
+
+       return result;
+}
+
+/*
+ * bsec_write_otp: write value in BSEC data register.
+ * val: value to write.
+ * otp: OTP number.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_write_otp(uint32_t val, uint32_t otp)
+{
+       uint32_t result;
+
+       if (otp > STM32MP1_OTP_MAX_ID) {
+               return BSEC_INVALID_PARAM;
+       }
+
+       /* Check if programming of OTP is locked */
+       if (bsec_read_sw_lock(otp)) {
+               VERBOSE("BSEC: OTP %i is locked and write will be ignored\n",
+                       otp);
+       }
+
+       bsec_lock();
+
+       mmio_write_32(bsec_base + BSEC_OTP_DATA_OFF +
+                     (otp * sizeof(uint32_t)), val);
+
+       result = bsec_check_error(otp);
+
+       bsec_unlock();
+
+       return result;
+}
+
+/*
+ * bsec_program_otp: program a bit in SAFMEM after the prog.
+ *     The OTP data is not refreshed.
+ * val: value to program.
+ * otp: OTP number.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_program_otp(uint32_t val, uint32_t otp)
+{
+       uint32_t result;
+       bool power_up = false;
+
+       if (otp > STM32MP1_OTP_MAX_ID) {
+               return BSEC_INVALID_PARAM;
+       }
+
+       /* Check if programming of OTP is locked */
+       if (bsec_read_sp_lock(otp)) {
+               WARN("BSEC: OTP locked, prog will be ignored\n");
+       }
+
+       if ((mmio_read_32(bsec_base + BSEC_OTP_LOCK_OFF) &
+            BIT(BSEC_LOCK_PROGRAM)) != 0U) {
+               WARN("BSEC: GPLOCK activated, prog will be ignored\n");
+       }
+
+       if ((bsec_get_status() & BSEC_MODE_PWR_MASK) == 0U) {
+               result = bsec_power_safmem(true);
+
+               if (result != BSEC_OK) {
+                       return result;
+               }
+
+               power_up = true;
+       }
+
+       bsec_lock();
+
+       /* Set value in write register */
+       mmio_write_32(bsec_base + BSEC_OTP_WRDATA_OFF, val);
+
+       /* Set BSEC_OTP_CTRL_OFF and set ADDR with the OTP value */
+       mmio_write_32(bsec_base + BSEC_OTP_CTRL_OFF, otp | BSEC_WRITE);
+
+       while ((bsec_get_status() & BSEC_MODE_BUSY_MASK) != 0U) {
+               ;
+       }
+
+       if ((bsec_get_status() & BSEC_MODE_PROGFAIL_MASK) != 0U) {
+               result = BSEC_PROG_FAIL;
+       } else {
+               result = bsec_check_error(otp);
+       }
+
+       bsec_unlock();
+
+       if (power_up) {
+               if (bsec_power_safmem(false) != BSEC_OK) {
+                       panic();
+               }
+       }
+
+       return result;
+}
+
+/*
+ * bsec_permanent_lock_otp: permanent lock of OTP in SAFMEM.
+ * otp: OTP number.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_permanent_lock_otp(uint32_t otp)
+{
+       uint32_t result;
+       bool power_up = false;
+       uint32_t data;
+       uint32_t addr;
+
+       if (otp > STM32MP1_OTP_MAX_ID) {
+               return BSEC_INVALID_PARAM;
+       }
+
+       if ((bsec_get_status() & BSEC_MODE_PWR_MASK) == 0U) {
+               result = bsec_power_safmem(true);
+
+               if (result != BSEC_OK) {
+                       return result;
+               }
+
+               power_up = true;
+       }
+
+       if (otp < STM32MP1_UPPER_OTP_START) {
+               addr = otp >> ADDR_LOWER_OTP_PERLOCK_SHIFT;
+               data = DATA_LOWER_OTP_PERLOCK_BIT <<
+                      ((otp & DATA_LOWER_OTP_PERLOCK_MASK) << 1U);
+       } else {
+               addr = (otp >> ADDR_UPPER_OTP_PERLOCK_SHIFT) + 2U;
+               data = DATA_UPPER_OTP_PERLOCK_BIT <<
+                      (otp & DATA_UPPER_OTP_PERLOCK_MASK);
+       }
+
+       bsec_lock();
+
+       /* Set value in write register */
+       mmio_write_32(bsec_base + BSEC_OTP_WRDATA_OFF, data);
+
+       /* Set BSEC_OTP_CTRL_OFF and set ADDR with the OTP value */
+       mmio_write_32(bsec_base + BSEC_OTP_CTRL_OFF,
+                     addr | BSEC_WRITE | BSEC_LOCK);
+
+       while ((bsec_get_status() & BSEC_MODE_BUSY_MASK) != 0U) {
+               ;
+       }
+
+       if ((bsec_get_status() & BSEC_MODE_PROGFAIL_MASK) != 0U) {
+               result = BSEC_PROG_FAIL;
+       } else {
+               result = bsec_check_error(otp);
+       }
+
+       bsec_unlock();
+
+       if (power_up) {
+               if (bsec_power_safmem(false) != BSEC_OK) {
+                       panic();
+               }
+       }
+
+       return result;
+}
+
+/*
+ * bsec_write_debug_conf: write value in debug feature
+ *     to enable/disable debug service.
+ * val: value to write.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_write_debug_conf(uint32_t val)
+{
+       uint32_t result = BSEC_ERROR;
+       uint32_t masked_val = val & BSEC_DEN_ALL_MSK;
+
+       bsec_lock();
+
+       mmio_write_32(bsec_base + BSEC_DEN_OFF, masked_val);
+
+       if ((mmio_read_32(bsec_base + BSEC_DEN_OFF) ^ masked_val) == 0U) {
+               result = BSEC_OK;
+       }
+
+       bsec_unlock();
+
+       return result;
+}
+
+/*
+ * bsec_read_debug_conf: read debug configuration.
+ */
+uint32_t bsec_read_debug_conf(void)
+{
+       return mmio_read_32(bsec_base + BSEC_DEN_OFF);
+}
+
+/*
+ * bsec_get_status: return status register value.
+ */
+uint32_t bsec_get_status(void)
+{
+       return mmio_read_32(bsec_base + BSEC_OTP_STATUS_OFF);
+}
+
+/*
+ * bsec_get_hw_conf: return hardware configuration.
+ */
+uint32_t bsec_get_hw_conf(void)
+{
+       return mmio_read_32(bsec_base + BSEC_IPHW_CFG_OFF);
+}
+
+/*
+ * bsec_get_version: return BSEC version.
+ */
+uint32_t bsec_get_version(void)
+{
+       return mmio_read_32(bsec_base + BSEC_IPVR_OFF);
+}
+
+/*
+ * bsec_get_id: return BSEC ID.
+ */
+uint32_t bsec_get_id(void)
+{
+       return mmio_read_32(bsec_base + BSEC_IP_ID_OFF);
+}
+
+/*
+ * bsec_get_magic_id: return BSEC magic number.
+ */
+uint32_t bsec_get_magic_id(void)
+{
+       return mmio_read_32(bsec_base + BSEC_IP_MAGIC_ID_OFF);
+}
+
+/*
+ * bsec_write_sr_lock: write shadow-read lock.
+ * otp: OTP number.
+ * value: value to write in the register.
+ *     Must be always 1.
+ * return: true if OTP is locked, else false.
+ */
+bool bsec_write_sr_lock(uint32_t otp, uint32_t value)
+{
+       bool result = false;
+       uint32_t bank = otp_bank_offset(otp);
+       uint32_t bank_value;
+       uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
+
+       bsec_lock();
+
+       bank_value = mmio_read_32(bsec_base + BSEC_SRLOCK_OFF + bank);
+
+       if ((bank_value & otp_mask) == value) {
+               /*
+                * In case of write don't need to write,
+                * the lock is already set.
+                */
+               if (value != 0U) {
+                       result = true;
+               }
+       } else {
+               if (value != 0U) {
+                       bank_value = bank_value | otp_mask;
+               } else {
+                       bank_value = bank_value & ~otp_mask;
+               }
+
+               /*
+                * We can write 0 in all other OTP
+                * if the lock is activated in one of other OTP.
+                * Write 0 has no effect.
+                */
+               mmio_write_32(bsec_base + BSEC_SRLOCK_OFF + bank, bank_value);
+               result = true;
+       }
+
+       bsec_unlock();
+
+       return result;
+}
+
+/*
+ * bsec_read_sr_lock: read shadow-read lock.
+ * otp: OTP number.
+ * return: true if otp is locked, else false.
+ */
+bool bsec_read_sr_lock(uint32_t otp)
+{
+       uint32_t bank = otp_bank_offset(otp);
+       uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
+       uint32_t bank_value = mmio_read_32(bsec_base + BSEC_SRLOCK_OFF + bank);
+
+       return (bank_value & otp_mask) != 0U;
+}
+
+/*
+ * bsec_write_sw_lock: write shadow-write lock.
+ * otp: OTP number.
+ * value: Value to write in the register.
+ *     Must be always 1.
+ * return: true if OTP is locked, else false.
+ */
+bool bsec_write_sw_lock(uint32_t otp, uint32_t value)
+{
+       bool result = false;
+       uint32_t bank = otp_bank_offset(otp);
+       uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
+       uint32_t bank_value;
+
+       bsec_lock();
+
+       bank_value = mmio_read_32(bsec_base + BSEC_SWLOCK_OFF + bank);
+
+       if ((bank_value & otp_mask) == value) {
+               /*
+                * In case of write don't need to write,
+                * the lock is already set.
+                */
+               if (value != 0U) {
+                       result = true;
+               }
+       } else {
+               if (value != 0U) {
+                       bank_value = bank_value | otp_mask;
+               } else {
+                       bank_value = bank_value & ~otp_mask;
+               }
+
+               /*
+                * We can write 0 in all other OTP
+                * if the lock is activated in one of other OTP.
+                * Write 0 has no effect.
+                */
+               mmio_write_32(bsec_base + BSEC_SWLOCK_OFF + bank, bank_value);
+               result = true;
+       }
+
+       bsec_unlock();
+
+       return result;
+}
+
+/*
+ * bsec_read_sw_lock: read shadow-write lock.
+ * otp: OTP number.
+ * return: true if OTP is locked, else false.
+ */
+bool bsec_read_sw_lock(uint32_t otp)
+{
+       uint32_t bank = otp_bank_offset(otp);
+       uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
+       uint32_t bank_value = mmio_read_32(bsec_base + BSEC_SWLOCK_OFF + bank);
+
+       return (bank_value & otp_mask) != 0U;
+}
+
+/*
+ * bsec_write_sp_lock: write shadow-program lock.
+ * otp: OTP number.
+ * value: Value to write in the register.
+ *     Must be always 1.
+ * return: true if OTP is locked, else false.
+ */
+bool bsec_write_sp_lock(uint32_t otp, uint32_t value)
+{
+       bool result = false;
+       uint32_t bank = otp_bank_offset(otp);
+       uint32_t bank_value;
+       uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
+
+       bsec_lock();
+
+       bank_value = mmio_read_32(bsec_base + BSEC_SPLOCK_OFF + bank);
+
+       if ((bank_value & otp_mask) == value) {
+               /*
+                * In case of write don't need to write,
+                * the lock is already set.
+                */
+               if (value != 0U) {
+                       result = true;
+               }
+       } else {
+               if (value != 0U) {
+                       bank_value = bank_value | otp_mask;
+               } else {
+                       bank_value = bank_value & ~otp_mask;
+               }
+
+               /*
+                * We can write 0 in all other OTP
+                * if the lock is activated in one of other OTP.
+                * Write 0 has no effect.
+                */
+               mmio_write_32(bsec_base + BSEC_SPLOCK_OFF + bank, bank_value);
+               result = true;
+       }
+
+       bsec_unlock();
+
+       return result;
+}
+
+/*
+ * bsec_read_sp_lock: read shadow-program lock.
+ * otp: OTP number.
+ * return: true if OTP is locked, else false.
+ */
+bool bsec_read_sp_lock(uint32_t otp)
+{
+       uint32_t bank = otp_bank_offset(otp);
+       uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
+       uint32_t bank_value = mmio_read_32(bsec_base + BSEC_SPLOCK_OFF + bank);
+
+       return (bank_value & otp_mask) != 0U;
+}
+
+/*
+ * bsec_wr_lock: Read permanent lock status.
+ * otp: OTP number.
+ * return: true if OTP is locked, else false.
+ */
+bool bsec_wr_lock(uint32_t otp)
+{
+       uint32_t bank = otp_bank_offset(otp);
+       uint32_t lock_bit = BIT(otp & BSEC_OTP_MASK);
+
+       if ((mmio_read_32(bsec_base + BSEC_WRLOCK_OFF + bank) &
+            lock_bit) != 0U) {
+               /*
+                * In case of write don't need to write,
+                * the lock is already set.
+                */
+               return true;
+       }
+
+       return false;
+}
+
+/*
+ * bsec_otp_lock: 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: BSEC_OK if succeed.
+ */
+uint32_t bsec_otp_lock(uint32_t service, uint32_t value)
+{
+       uintptr_t reg = bsec_base + BSEC_OTP_LOCK_OFF;
+
+       switch (service) {
+       case BSEC_LOCK_UPPER_OTP:
+               mmio_write_32(reg, value << BSEC_LOCK_UPPER_OTP);
+               break;
+       case BSEC_LOCK_DEBUG:
+               mmio_write_32(reg, value << BSEC_LOCK_DEBUG);
+               break;
+       case BSEC_LOCK_PROGRAM:
+               mmio_write_32(reg, value << BSEC_LOCK_PROGRAM);
+               break;
+       default:
+               return BSEC_INVALID_PARAM;
+       }
+
+       return BSEC_OK;
+}
+
+/*
+ * bsec_power_safmem: Activate or deactivate SAFMEM power.
+ * power: true to power up, false to power down.
+ * return: BSEC_OK if succeed.
+ */
+static uint32_t bsec_power_safmem(bool power)
+{
+       uint32_t register_val;
+       uint32_t timeout = BSEC_TIMEOUT_VALUE;
+
+       bsec_lock();
+
+       register_val = mmio_read_32(bsec_base + BSEC_OTP_CONF_OFF);
+
+       if (power) {
+               register_val |= BSEC_CONF_POWER_UP_MASK;
+       } else {
+               register_val &= ~BSEC_CONF_POWER_UP_MASK;
+       }
+
+       mmio_write_32(bsec_base + BSEC_OTP_CONF_OFF, register_val);
+
+       /* Waiting loop */
+       if (power) {
+               while (((bsec_get_status() & BSEC_MODE_PWR_MASK) == 0U) &&
+                      (timeout != 0U)) {
+                       timeout--;
+               }
+       } else {
+               while (((bsec_get_status() & BSEC_MODE_PWR_MASK) != 0U) &&
+                      (timeout != 0U)) {
+                       timeout--;
+               }
+       }
+
+       bsec_unlock();
+
+       if (timeout == 0U) {
+               return BSEC_TIMEOUT;
+       }
+
+       return BSEC_OK;
+}
+
+/*
+ * bsec_mode_is_closed_device: read OTP secure sub-mode.
+ * return: false if open_device and true of closed_device.
+ */
+bool bsec_mode_is_closed_device(void)
+{
+       uint32_t value;
+
+       if ((bsec_shadow_register(DATA0_OTP) != BSEC_OK) ||
+           (bsec_read_otp(&value, DATA0_OTP) != BSEC_OK)) {
+               return true;
+       }
+
+       return (value & DATA0_OTP_SECURED) == DATA0_OTP_SECURED;
+}
+
+/*
+ * bsec_shadow_read_otp: Load OTP from SAFMEM and provide its value
+ * otp_value: read value.
+ * word: OTP number.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_shadow_read_otp(uint32_t *otp_value, uint32_t word)
+{
+       uint32_t result;
+
+       result = bsec_shadow_register(word);
+       if (result != BSEC_OK) {
+               ERROR("BSEC: %u Shadowing Error %i\n", word, result);
+               return result;
+       }
+
+       result = bsec_read_otp(otp_value, word);
+       if (result != BSEC_OK) {
+               ERROR("BSEC: %u Read Error %i\n", word, result);
+       }
+
+       return result;
+}
+
+/*
+ * bsec_check_nsec_access_rights: check non-secure access rights to target OTP.
+ * otp: OTP number.
+ * return: BSEC_OK if authorized access.
+ */
+uint32_t bsec_check_nsec_access_rights(uint32_t otp)
+{
+#if defined(IMAGE_BL32)
+       if (otp > STM32MP1_OTP_MAX_ID) {
+               return BSEC_INVALID_PARAM;
+       }
+
+       if (otp >= STM32MP1_UPPER_OTP_START) {
+               /* Check if BSEC is in OTP-SECURED closed_device state. */
+               if (bsec_mode_is_closed_device()) {
+                       if (!non_secure_can_access(otp)) {
+                               return BSEC_ERROR;
+                       }
+               }
+       }
+#endif
+
+       return BSEC_OK;
+}
+
diff --git a/include/drivers/st/bsec.h b/include/drivers/st/bsec.h
new file mode 100644 (file)
index 0000000..2171550
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BSEC_H
+#define BSEC_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <lib/utils_def.h>
+
+/*
+ * IP configuration
+ */
+#define BSEC_OTP_MASK                  GENMASK(4, 0)
+#define BSEC_OTP_BANK_SHIFT            5
+#define BSEC_TIMEOUT_VALUE             0xFFFF
+
+#define ADDR_LOWER_OTP_PERLOCK_SHIFT   0x03
+#define DATA_LOWER_OTP_PERLOCK_BIT     0x03U /* 2 significants bits are used */
+#define DATA_LOWER_OTP_PERLOCK_MASK    GENMASK(2, 0)
+#define ADDR_UPPER_OTP_PERLOCK_SHIFT   0x04
+#define DATA_UPPER_OTP_PERLOCK_BIT     0x01U /* 1 significants bits are used */
+#define DATA_UPPER_OTP_PERLOCK_MASK    GENMASK(3, 0)
+
+/*
+ * Return status
+ */
+#define BSEC_OK                                0U
+#define BSEC_ERROR                     0xFFFFFFFFU
+#define BSEC_DISTURBED                 0xFFFFFFFEU
+#define BSEC_INVALID_PARAM             0xFFFFFFFCU
+#define BSEC_PROG_FAIL                 0xFFFFFFFBU
+#define BSEC_LOCK_FAIL                 0xFFFFFFFAU
+#define BSEC_WRITE_FAIL                        0xFFFFFFF9U
+#define BSEC_SHADOW_FAIL               0xFFFFFFF8U
+#define BSEC_TIMEOUT                   0xFFFFFFF7U
+
+/*
+ * BSEC REGISTER OFFSET (base relative)
+ */
+#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_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 /* Safmem permanent lock */
+#define BSEC_WRLOCK1_OFF               0x050U
+#define BSEC_WRLOCK2_OFF               0x054U
+#define BSEC_SPLOCK_OFF                        0x064U /* Program safmem sticky lock */
+#define BSEC_SPLOCK1_OFF               0x068U
+#define BSEC_SPLOCK2_OFF               0x06CU
+#define BSEC_SWLOCK_OFF                        0x07CU /* Write in OTP sticky lock */
+#define BSEC_SWLOCK1_OFF               0x080U
+#define BSEC_SWLOCK2_OFF               0x084U
+#define BSEC_SRLOCK_OFF                        0x094U /* Shadowing sticky lock */
+#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(2, 1)
+#define BSEC_CONF_FRQ_SHIFT            1
+#define BSEC_CONF_PRG_WIDTH_MASK       GENMASK(6, 3)
+#define BSEC_CONF_PRG_WIDTH_SHIFT      3
+#define BSEC_CONF_TREAD_MASK           GENMASK(8, 7)
+#define BSEC_CONF_TREAD_SHIFT          7
+
+/*
+ * BSEC_CONTROL Register
+ */
+#define BSEC_READ                      0x000U
+#define BSEC_WRITE                     0x100U
+#define BSEC_LOCK                      0x200U
+
+/*
+ * BSEC_OTP_LOCK register
+ */
+#define UPPER_OTP_LOCK_MASK            BIT(0)
+#define UPPER_OTP_LOCK_SHIFT           0
+#define DENREG_LOCK_MASK               BIT(2)
+#define DENREG_LOCK_SHIFT              2
+#define GPLOCK_LOCK_MASK               BIT(4)
+#define GPLOCK_LOCK_SHIFT              4
+
+/*
+ * BSEC_OTP_STATUS Register
+ */
+#define BSEC_MODE_STATUS_MASK          GENMASK(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)
+
+/* OTP MODE*/
+#define BSEC_MODE_OPEN1                        0x00
+#define BSEC_MODE_SECURED              0x01
+#define BSEC_MODE_OPEN2                        0x02
+#define BSEC_MODE_INVALID              0x04
+
+/* BSEC_DENABLE Register */
+#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(10, 0)
+
+/* BSEC_FENABLE Register */
+#define BSEC_FEN_ALL_MSK               GENMASK(14, 0)
+
+/*
+ * OTP Lock services definition
+ * Value must corresponding to the bit number in the register
+ */
+#define BSEC_LOCK_UPPER_OTP            0x00
+#define BSEC_LOCK_DEBUG                        0x02
+#define BSEC_LOCK_PROGRAM              0x03
+
+/* Values for struct bsec_config::freq */
+#define FREQ_10_20_MHZ                 0x0
+#define FREQ_20_30_MHZ                 0x1
+#define FREQ_30_45_MHZ                 0x2
+#define FREQ_45_67_MHZ                 0x3
+
+/*
+ * Device info structure, providing device-specific functions and a means of
+ * adding driver-specific state
+ */
+struct bsec_config {
+       uint8_t tread;          /* SAFMEM Reading current level default 0 */
+       uint8_t pulse_width;    /* SAFMEM Programming pulse width default 1 */
+       uint8_t freq;           /* SAFMEM CLOCK see freq value define
+                                * default FREQ_45_67_MHZ
+                                */
+       uint8_t power;          /* Power up SAFMEM. 1 power up, 0 power off */
+       uint8_t prog_lock;      /* Programming Sticky lock
+                                * 1 programming is locked until next reset
+                                */
+       uint8_t den_lock;       /* Debug enable sticky lock
+                                * 1 debug enable is locked until next reset
+                                */
+       uint8_t upper_otp_lock; /* Shadowing of upper OTP sticky lock
+                                * 1 shadowing of upper OTP is locked
+                                * until next reset
+                                */
+};
+
+uint32_t bsec_probe(void);
+uint32_t bsec_get_base(void);
+
+uint32_t bsec_set_config(struct bsec_config *cfg);
+uint32_t bsec_get_config(struct bsec_config *cfg);
+
+uint32_t bsec_shadow_register(uint32_t otp);
+uint32_t bsec_read_otp(uint32_t *val, uint32_t otp);
+uint32_t bsec_write_otp(uint32_t val, uint32_t otp);
+uint32_t bsec_program_otp(uint32_t val, uint32_t otp);
+uint32_t bsec_permanent_lock_otp(uint32_t otp);
+
+uint32_t bsec_write_debug_conf(uint32_t val);
+uint32_t bsec_read_debug_conf(void);
+uint32_t bsec_write_feature_conf(uint32_t val);
+uint32_t bsec_read_feature_conf(uint32_t *val);
+
+uint32_t bsec_get_status(void);
+uint32_t bsec_get_hw_conf(void);
+uint32_t bsec_get_version(void);
+uint32_t bsec_get_id(void);
+uint32_t bsec_get_magic_id(void);
+
+bool bsec_write_sr_lock(uint32_t otp, uint32_t value);
+bool bsec_read_sr_lock(uint32_t otp);
+bool bsec_write_sw_lock(uint32_t otp, uint32_t value);
+bool bsec_read_sw_lock(uint32_t otp);
+bool bsec_write_sp_lock(uint32_t otp, uint32_t value);
+bool bsec_read_sp_lock(uint32_t otp);
+bool bsec_wr_lock(uint32_t otp);
+uint32_t bsec_otp_lock(uint32_t service, uint32_t value);
+
+bool bsec_mode_is_closed_device(void);
+uint32_t bsec_shadow_read_otp(uint32_t *otp_value, uint32_t word);
+uint32_t bsec_check_nsec_access_rights(uint32_t otp);
+
+#endif /* BSEC_H */
index b5a7a79a838d1fd9618ee19a8a9e4446692c243e..4288f23d9140ee574ef02ac99ce0b37375a82b09 100644 (file)
@@ -47,6 +47,7 @@ PLAT_BL_COMMON_SOURCES        +=      ${LIBFDT_SRCS}                                          \
                                drivers/arm/tzc/tzc400.c                                \
                                drivers/delay_timer/delay_timer.c                       \
                                drivers/delay_timer/generic_delay_timer.c               \
+                               drivers/st/bsec/bsec.c                                  \
                                drivers/st/clk/stm32mp1_clk.c                           \
                                drivers/st/clk/stm32mp1_clkfunc.c                       \
                                drivers/st/ddr/stm32mp1_ddr_helpers.c                   \
index 0dd721571153656891e74c9a18b9a1deeafff786..8cd5aeb26c6c368089671d58601b7a5091707aaf 100644 (file)
@@ -202,6 +202,21 @@ enum ddr_type {
 #define STM32MP1_EMMC_NORMAL_SPEED_MAX_FREQ    26000000        /*26 MHz*/
 #define STM32MP1_EMMC_HIGH_SPEED_MAX_FREQ      52000000        /*52 MHz*/
 
+/*******************************************************************************
+ * STM32MP1 BSEC / OTP
+ ******************************************************************************/
+#define STM32MP1_OTP_MAX_ID            0x5FU
+#define STM32MP1_UPPER_OTP_START       0x20U
+
+#define OTP_MAX_SIZE                   (STM32MP1_OTP_MAX_ID + 1U)
+
+/* OTP offsets */
+#define DATA0_OTP                      U(0)
+
+/* OTP mask */
+/* DATA0 */
+#define DATA0_OTP_SECURED              BIT(6)
+
 /*******************************************************************************
  * STM32MP1 TAMP
  ******************************************************************************/