From 102b0d2daa97dae68d3eed54d8fe37a9cc38a892 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 28 Apr 2024 11:13:47 +0200 Subject: Adding upstream version 2.8.0+dfsg. Signed-off-by: Daniel Baumann --- drivers/st/bsec/bsec2.c | 961 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 961 insertions(+) create mode 100644 drivers/st/bsec/bsec2.c (limited to 'drivers/st/bsec/bsec2.c') diff --git a/drivers/st/bsec/bsec2.c b/drivers/st/bsec/bsec2.c new file mode 100644 index 0000000..68d3a5b --- /dev/null +++ b/drivers/st/bsec/bsec2.c @@ -0,0 +1,961 @@ +/* + * Copyright (c) 2017-2022, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define BSEC_IP_VERSION_1_1 U(0x11) +#define BSEC_IP_VERSION_2_0 U(0x20) +#define BSEC_IP_ID_2 U(0x100032) + +#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) +{ + if (stm32mp_lock_available()) { + spin_lock(&bsec_spinlock); + } +} + +static void bsec_unlock(void) +{ + if (stm32mp_lock_available()) { + spin_unlock(&bsec_spinlock); + } +} + +static bool is_otp_invalid_mode(void) +{ + bool ret = ((bsec_get_status() & BSEC_MODE_INVALID) == BSEC_MODE_INVALID); + + if (ret) { + ERROR("OTP mode is OTP-INVALID\n"); + } + + return ret; +} + +#if defined(IMAGE_BL32) +static int bsec_get_dt_node(struct dt_node_info *info) +{ + int node; + + node = dt_get_node(info, -1, DT_BSEC_COMPAT); + if (node < 0) { + return -FDT_ERR_NOTFOUND; + } + + return node; +} + +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)) != 0U; +} + +static void 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 otp; + uint32_t i; + uint32_t size; + uint32_t offset; + uint32_t length; + + cuint = fdt_getprop(fdt, bsec_subnode, "reg", NULL); + if (cuint == NULL) { + panic(); + } + + offset = fdt32_to_cpu(*cuint); + cuint++; + length = fdt32_to_cpu(*cuint); + + otp = offset / sizeof(uint32_t); + + if (otp < STM32MP1_UPPER_OTP_START) { + unsigned int otp_end = round_up(offset + length, + sizeof(uint32_t)) / + sizeof(uint32_t); + + if (otp_end > STM32MP1_UPPER_OTP_START) { + /* + * OTP crosses Lower/Upper boundary, consider + * only the upper part. + */ + otp = STM32MP1_UPPER_OTP_START; + length -= (STM32MP1_UPPER_OTP_START * + sizeof(uint32_t)) - offset; + offset = STM32MP1_UPPER_OTP_START * + sizeof(uint32_t); + + WARN("OTP crosses Lower/Upper boundary\n"); + } else { + continue; + } + } + + if ((fdt_getprop(fdt, bsec_subnode, + "st,non-secure-otp", NULL)) == NULL) { + continue; + } + + if (((offset % sizeof(uint32_t)) != 0U) || + ((length % sizeof(uint32_t)) != 0U)) { + ERROR("Unaligned non-secure OTP\n"); + panic(); + } + + size = length / sizeof(uint32_t); + + for (i = otp; i < (otp + size); i++) { + enable_non_secure_access(i); + } + } +} + +static void bsec_late_init(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(); + } + + assert(bsec_base == bsec_info.base); + + bsec_dt_otp_nsec_access(fdt, node); +} +#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); +} + +/* + * bsec_check_error: check BSEC error status. + * otp: OTP number. + * check_disturbed: check only error (false), + * or error and disturbed status (true). + * return value: BSEC_OK if no error. + */ +static uint32_t bsec_check_error(uint32_t otp, bool check_disturbed) +{ + uint32_t bit = BIT(otp & BSEC_OTP_MASK); + uint32_t bank = otp_bank_offset(otp); + + if ((mmio_read_32(bsec_base + BSEC_ERROR_OFF + bank) & bit) != 0U) { + return BSEC_ERROR; + } + + if (!check_disturbed) { + return BSEC_OK; + } + + if ((mmio_read_32(bsec_base + BSEC_DISTURBED_OFF + bank) & bit) != 0U) { + return BSEC_DISTURBED; + } + + return BSEC_OK; +} + +/* + * bsec_probe: initialize BSEC driver. + * return value: BSEC_OK if no error. + */ +uint32_t bsec_probe(void) +{ + bsec_base = BSEC_BASE; + + if (is_otp_invalid_mode()) { + return BSEC_ERROR; + } + + if ((((bsec_get_version() & BSEC_IPVR_MSK) != BSEC_IP_VERSION_1_1) && + ((bsec_get_version() & BSEC_IPVR_MSK) != BSEC_IP_VERSION_2_0)) || + (bsec_get_id() != BSEC_IP_ID_2)) { + panic(); + } + +#if defined(IMAGE_BL32) + bsec_late_init(); +#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; + uint32_t result; + + if (is_otp_invalid_mode()) { + return BSEC_ERROR; + } + + 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 value; + bool power_up = false; + + if (is_otp_invalid_mode()) { + return BSEC_ERROR; + } + + result = bsec_read_sr_lock(otp, &value); + if (result != BSEC_OK) { + ERROR("BSEC: %u Sticky-read bit read Error %u\n", otp, result); + return result; + } + + if (value) { + VERBOSE("BSEC: OTP %u 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(); + + 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, true); + + 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) +{ + if (is_otp_invalid_mode()) { + return BSEC_ERROR; + } + + if (otp > STM32MP1_OTP_MAX_ID) { + return BSEC_INVALID_PARAM; + } + + *val = mmio_read_32(bsec_base + BSEC_OTP_DATA_OFF + + (otp * sizeof(uint32_t))); + + return BSEC_OK; +} + +/* + * 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; + bool value; + + if (is_otp_invalid_mode()) { + return BSEC_ERROR; + } + + result = bsec_read_sw_lock(otp, &value); + if (result != BSEC_OK) { + ERROR("BSEC: %u Sticky-write bit read Error %u\n", otp, result); + return result; + } + + if (value) { + VERBOSE("BSEC: OTP %u is locked and write will be ignored\n", + otp); + } + + /* Ensure integrity of each register access sequence */ + bsec_lock(); + + mmio_write_32(bsec_base + BSEC_OTP_DATA_OFF + + (otp * sizeof(uint32_t)), val); + + 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; + bool sp_lock; + bool perm_lock; + + if (is_otp_invalid_mode()) { + return BSEC_ERROR; + } + + result = bsec_read_sp_lock(otp, &sp_lock); + if (result != BSEC_OK) { + ERROR("BSEC: %u Sticky-prog bit read Error %u\n", otp, result); + return result; + } + + result = bsec_read_permanent_lock(otp, &perm_lock); + if (result != BSEC_OK) { + ERROR("BSEC: %u permanent bit read Error %u\n", otp, result); + return result; + } + + if (sp_lock || perm_lock) { + WARN("BSEC: OTP locked, prog will be ignored\n"); + return BSEC_PROG_FAIL; + } + + 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(); + + mmio_write_32(bsec_base + BSEC_OTP_WRDATA_OFF, val); + + 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, true); + } + + 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 (is_otp_invalid_mode()) { + return BSEC_ERROR; + } + + 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(); + + mmio_write_32(bsec_base + BSEC_OTP_WRDATA_OFF, data); + + 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, false); + } + + 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: none. + */ +void bsec_write_debug_conf(uint32_t val) +{ + if (is_otp_invalid_mode()) { + return; + } + + bsec_lock(); + mmio_write_32(bsec_base + BSEC_DEN_OFF, val & BSEC_DEN_ALL_MSK); + bsec_unlock(); +} + +/* + * bsec_read_debug_conf: return debug configuration register value. + */ +uint32_t bsec_read_debug_conf(void) +{ + return mmio_read_32(bsec_base + BSEC_DEN_OFF); +} + +/* + * bsec_write_scratch: write value in scratch register. + * val: value to write. + * return value: none. + */ +void bsec_write_scratch(uint32_t val) +{ +#if defined(IMAGE_BL32) + if (is_otp_invalid_mode()) { + return; + } + + bsec_lock(); + mmio_write_32(bsec_base + BSEC_SCRATCH_OFF, val); + bsec_unlock(); +#else + mmio_write_32(BSEC_BASE + BSEC_SCRATCH_OFF, val); +#endif +} + +/* + * bsec_read_scratch: return scratch register value. + */ +uint32_t bsec_read_scratch(void) +{ + return mmio_read_32(bsec_base + BSEC_SCRATCH_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 register value. + */ +uint32_t bsec_get_hw_conf(void) +{ + return mmio_read_32(bsec_base + BSEC_IPHW_CFG_OFF); +} + +/* + * bsec_get_version: return BSEC version register value. + */ +uint32_t bsec_get_version(void) +{ + return mmio_read_32(bsec_base + BSEC_IPVR_OFF); +} + +/* + * bsec_get_id: return BSEC ID register value. + */ +uint32_t bsec_get_id(void) +{ + return mmio_read_32(bsec_base + BSEC_IP_ID_OFF); +} + +/* + * bsec_get_magic_id: return BSEC magic number register value. + */ +uint32_t bsec_get_magic_id(void) +{ + return mmio_read_32(bsec_base + BSEC_IP_MAGIC_ID_OFF); +} + +/* + * bsec_set_sr_lock: set shadow-read lock. + * otp: OTP number. + * return value: BSEC_OK if no error. + */ +uint32_t bsec_set_sr_lock(uint32_t otp) +{ + uint32_t bank = otp_bank_offset(otp); + uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK); + + if (is_otp_invalid_mode()) { + return BSEC_ERROR; + } + + if (otp > STM32MP1_OTP_MAX_ID) { + return BSEC_INVALID_PARAM; + } + + bsec_lock(); + mmio_write_32(bsec_base + BSEC_SRLOCK_OFF + bank, otp_mask); + bsec_unlock(); + + return BSEC_OK; +} + +/* + * bsec_read_sr_lock: read shadow-read lock. + * otp: OTP number. + * value: read value (true or false). + * return value: BSEC_OK if no error. + */ +uint32_t bsec_read_sr_lock(uint32_t otp, bool *value) +{ + uint32_t bank = otp_bank_offset(otp); + uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK); + uint32_t bank_value; + + if (otp > STM32MP1_OTP_MAX_ID) { + return BSEC_INVALID_PARAM; + } + + bank_value = mmio_read_32(bsec_base + BSEC_SRLOCK_OFF + bank); + + *value = ((bank_value & otp_mask) != 0U); + + return BSEC_OK; +} + +/* + * bsec_set_sw_lock: set shadow-write lock. + * otp: OTP number. + * return value: BSEC_OK if no error. + */ +uint32_t bsec_set_sw_lock(uint32_t otp) +{ + uint32_t bank = otp_bank_offset(otp); + uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK); + + if (is_otp_invalid_mode()) { + return BSEC_ERROR; + } + + if (otp > STM32MP1_OTP_MAX_ID) { + return BSEC_INVALID_PARAM; + } + + bsec_lock(); + mmio_write_32(bsec_base + BSEC_SWLOCK_OFF + bank, otp_mask); + bsec_unlock(); + + return BSEC_OK; +} + +/* + * bsec_read_sw_lock: read shadow-write lock. + * otp: OTP number. + * value: read value (true or false). + * return value: BSEC_OK if no error. + */ +uint32_t bsec_read_sw_lock(uint32_t otp, bool *value) +{ + uint32_t bank = otp_bank_offset(otp); + uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK); + uint32_t bank_value; + + if (otp > STM32MP1_OTP_MAX_ID) { + return BSEC_INVALID_PARAM; + } + + bank_value = mmio_read_32(bsec_base + BSEC_SWLOCK_OFF + bank); + + *value = ((bank_value & otp_mask) != 0U); + + return BSEC_OK; +} + +/* + * bsec_set_sp_lock: set shadow-program lock. + * otp: OTP number. + * return value: BSEC_OK if no error. + */ +uint32_t bsec_set_sp_lock(uint32_t otp) +{ + uint32_t bank = otp_bank_offset(otp); + uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK); + + if (is_otp_invalid_mode()) { + return BSEC_ERROR; + } + + if (otp > STM32MP1_OTP_MAX_ID) { + return BSEC_INVALID_PARAM; + } + + bsec_lock(); + mmio_write_32(bsec_base + BSEC_SPLOCK_OFF + bank, otp_mask); + bsec_unlock(); + + return BSEC_OK; +} + +/* + * bsec_read_sp_lock: read shadow-program lock. + * otp: OTP number. + * value: read value (true or false). + * return value: BSEC_OK if no error. + */ +uint32_t bsec_read_sp_lock(uint32_t otp, bool *value) +{ + uint32_t bank = otp_bank_offset(otp); + uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK); + uint32_t bank_value; + + if (otp > STM32MP1_OTP_MAX_ID) { + return BSEC_INVALID_PARAM; + } + + bank_value = mmio_read_32(bsec_base + BSEC_SPLOCK_OFF + bank); + + *value = ((bank_value & otp_mask) != 0U); + + return BSEC_OK; +} + +/* + * bsec_read_permanent_lock: Read permanent lock status. + * otp: OTP number. + * value: read value (true or false). + * return value: BSEC_OK if no error. + */ +uint32_t bsec_read_permanent_lock(uint32_t otp, bool *value) +{ + uint32_t bank = otp_bank_offset(otp); + uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK); + uint32_t bank_value; + + if (otp > STM32MP1_OTP_MAX_ID) { + return BSEC_INVALID_PARAM; + } + + bank_value = mmio_read_32(bsec_base + BSEC_WRLOCK_OFF + bank); + + *value = ((bank_value & otp_mask) != 0U); + + return BSEC_OK; +} + +/* + * bsec_otp_lock: Lock Upper OTP or Global Programming or Debug Enable. + * service: Service to lock, see header file. + * return value: BSEC_OK if no error. + */ +uint32_t bsec_otp_lock(uint32_t service) +{ + uintptr_t reg = bsec_base + BSEC_OTP_LOCK_OFF; + + if (is_otp_invalid_mode()) { + return BSEC_ERROR; + } + + switch (service) { + case BSEC_LOCK_UPPER_OTP: + mmio_write_32(reg, BIT(BSEC_LOCK_UPPER_OTP)); + break; + case BSEC_LOCK_DEBUG: + mmio_write_32(reg, BIT(BSEC_LOCK_DEBUG)); + break; + case BSEC_LOCK_PROGRAM: + mmio_write_32(reg, BIT(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 value: BSEC_OK if no error. + */ +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); + + 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_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 %u\n", word, result); + return result; + } + + result = bsec_read_otp(otp_value, word); + if (result != BSEC_OK) { + ERROR("BSEC: %u Read Error %u\n", word, result); + } + + return result; +} + +/* + * bsec_check_nsec_access_rights: check non-secure access rights to target OTP. + * otp: OTP number. + * return value: 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) { + if (!non_secure_can_access(otp)) { + return BSEC_ERROR; + } + } +#endif + + return BSEC_OK; +} + -- cgit v1.2.3