| /* |
| * 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; |
| } |
| |