/* * Copyright (c) 2017-2024, 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) /* * IP configuration */ #define BSEC_OTP_MASK GENMASK(4, 0) #define BSEC_OTP_BANK_SHIFT 5 #define BSEC_TIMEOUT_VALUE U(0xFFFF) #define OTP_ACCESS_SIZE (round_up(OTP_MAX_SIZE, __WORD_BIT) / __WORD_BIT) static uint32_t otp_nsec_access[OTP_ACCESS_SIZE] __maybe_unused; static uint32_t bsec_shadow_register(uint32_t otp); static uint32_t bsec_power_safmem(bool power); static uint32_t bsec_get_version(void); static uint32_t bsec_get_id(void); static uint32_t bsec_get_status(void); static uint32_t bsec_read_permanent_lock(uint32_t otp, bool *value); /* BSEC access protection */ static spinlock_t bsec_spinlock; 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_OTP_STATUS_INVALID) == BSEC_OTP_STATUS_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) { EARLY_ERROR("%s: DT not found\n", __func__); panic(); } node = bsec_get_dt_node(&bsec_info); if (node < 0) { EARLY_ERROR("%s: BSEC node not found\n", __func__); panic(); } assert(bsec_info.base == BSEC_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); } static uint32_t otp_bit_mask(uint32_t otp) { return BIT(otp & BSEC_OTP_MASK); } /* * 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 = otp_bit_mask(otp); 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) { uint32_t version; uint32_t id; if (is_otp_invalid_mode()) { EARLY_ERROR("%s: otp_invalid_mod\n", __func__); return BSEC_ERROR; } version = bsec_get_version(); id = bsec_get_id(); if (((version != BSEC_IP_VERSION_1_1) && (version != BSEC_IP_VERSION_2_0)) || (id != BSEC_IP_ID_2)) { EARLY_ERROR("%s: version = 0x%x, id = 0x%x\n", __func__, version, id); panic(); } #if defined(IMAGE_BL32) bsec_late_init(); #endif return BSEC_OK; } /* * bsec_shadow_register: copy SAFMEM OTP to BSEC data. * otp: OTP number. * return value: BSEC_OK if no error. */ static 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_OTP_STATUS_PWRON) == 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_OTP_STATUS_BUSY) != 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) & GPLOCK_LOCK_MASK) != 0U) { WARN("BSEC: GPLOCK activated, prog will be ignored\n"); } if ((bsec_get_status() & BSEC_OTP_STATUS_PWRON) == 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_OTP_STATUS_BUSY) != 0U) { ; } if ((bsec_get_status() & BSEC_OTP_STATUS_PROGFAIL) != 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. */ #if defined(IMAGE_BL32) 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_OTP_STATUS_PWRON) == 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_OTP_STATUS_BUSY) != 0U) { ; } if ((bsec_get_status() & BSEC_OTP_STATUS_PROGFAIL) != 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; } #endif /* * 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_get_status: return status register value. */ static uint32_t bsec_get_status(void) { return mmio_read_32(BSEC_BASE + BSEC_OTP_STATUS_OFF); } /* * bsec_get_version: return BSEC version register value. */ static uint32_t bsec_get_version(void) { return mmio_read_32(BSEC_BASE + BSEC_IPVR_OFF) & BSEC_IPVR_MSK; } /* * bsec_get_id: return BSEC ID register value. */ static uint32_t bsec_get_id(void) { return mmio_read_32(BSEC_BASE + BSEC_IP_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 = otp_bit_mask(otp); 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 = otp_bit_mask(otp); 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 = otp_bit_mask(otp); 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 = otp_bit_mask(otp); 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. */ static uint32_t bsec_read_permanent_lock(uint32_t otp, bool *value) { uint32_t bank = otp_bank_offset(otp); uint32_t otp_mask = otp_bit_mask(otp); 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_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_OTP_STATUS_PWRON) == 0U) && (timeout != 0U)) { timeout--; } } else { while (((bsec_get_status() & BSEC_OTP_STATUS_PWRON) != 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. * val: read value. * otp: OTP number. * return value: BSEC_OK if no error. */ uint32_t bsec_shadow_read_otp(uint32_t *val, uint32_t otp) { uint32_t result; result = bsec_shadow_register(otp); if (result != BSEC_OK) { ERROR("BSEC: %u Shadowing Error %u\n", otp, result); return result; } result = bsec_read_otp(val, otp); if (result != BSEC_OK) { ERROR("BSEC: %u Read Error %u\n", otp, result); } return result; } #if defined(IMAGE_BL32) /* * 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 (otp > STM32MP1_OTP_MAX_ID) { return BSEC_INVALID_PARAM; } if (otp >= STM32MP1_UPPER_OTP_START) { if (!non_secure_can_access(otp)) { return BSEC_ERROR; } } return BSEC_OK; } #endif uint32_t bsec_get_secure_state(void) { uint32_t status = bsec_get_status(); uint32_t result = BSEC_STATE_INVALID; uint32_t otp_enc_id __maybe_unused; uint32_t otp_bit_len __maybe_unused; int res __maybe_unused; if ((status & BSEC_OTP_STATUS_INVALID) != 0U) { result = BSEC_STATE_INVALID; } else { if ((status & BSEC_OTP_STATUS_SECURE) != 0U) { if (stm32mp_check_closed_device() == STM32MP_CHIP_SEC_CLOSED) { result = BSEC_STATE_SEC_CLOSED; } else { result = BSEC_STATE_SEC_OPEN; } } else { /* OTP modes OPEN1 and OPEN2 are not supported */ result = BSEC_STATE_INVALID; } } return result; }