From 88ef0425da07672bd2e20f548533bdf6f258d888 Mon Sep 17 00:00:00 2001 From: Yann Gautier Date: Thu, 17 Jan 2019 14:52:47 +0100 Subject: [PATCH] stm32mp1: add BSEC driver 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 Signed-off-by: Etienne Carriere Signed-off-by: Lionel Debieve Signed-off-by: Mathieu Belou Signed-off-by: Nicolas Le Bayon --- drivers/st/bsec/bsec.c | 913 ++++++++++++++++++++++++++++++++ include/drivers/st/bsec.h | 206 +++++++ plat/st/stm32mp1/platform.mk | 1 + plat/st/stm32mp1/stm32mp1_def.h | 15 + 4 files changed, 1135 insertions(+) create mode 100644 drivers/st/bsec/bsec.c create mode 100644 include/drivers/st/bsec.h diff --git a/drivers/st/bsec/bsec.c b/drivers/st/bsec/bsec.c new file mode 100644 index 00000000..aaecf1f8 --- /dev/null +++ b/drivers/st/bsec/bsec.c @@ -0,0 +1,913 @@ +/* + * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include + +#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 index 00000000..2171550b --- /dev/null +++ b/include/drivers/st/bsec.h @@ -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 +#include + +#include + +/* + * 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 */ diff --git a/plat/st/stm32mp1/platform.mk b/plat/st/stm32mp1/platform.mk index b5a7a79a..4288f23d 100644 --- a/plat/st/stm32mp1/platform.mk +++ b/plat/st/stm32mp1/platform.mk @@ -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 \ diff --git a/plat/st/stm32mp1/stm32mp1_def.h b/plat/st/stm32mp1/stm32mp1_def.h index 0dd72157..8cd5aeb2 100644 --- a/plat/st/stm32mp1/stm32mp1_def.h +++ b/plat/st/stm32mp1/stm32mp1_def.h @@ -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 ******************************************************************************/ -- 2.30.2