123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533 |
- /*
- * Copyright (c) 2024, STMicroelectronics - All Rights Reserved
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
- #include <assert.h>
- #include <limits.h>
- #include <arch_helpers.h>
- #include <common/debug.h>
- #include <drivers/st/bsec.h>
- #include <drivers/st/bsec3_reg.h>
- #include <drivers/st/stm32mp_reset.h>
- #include <lib/mmio.h>
- #include <lib/spinlock.h>
- #include <libfdt.h>
- #include <platform_def.h>
- #define BSEC_IP_VERSION_1_0 U(0x10)
- #define BSEC_IP_ID_3 U(0x100033)
- #define MAX_NB_TRIES U(3)
- /*
- * IP configuration
- */
- #define BSEC_OTP_MASK GENMASK_32(4, 0)
- #define BSEC_OTP_BANK_SHIFT U(5)
- #define BSEC_TIMEOUT_VALUE U(0x800000) /* ~7sec @1.2GHz */
- /* Magic use to indicated valid SHADOW = 'B' 'S' 'E' 'C' */
- #define BSEC_MAGIC U(0x42534543)
- #define OTP_MAX_SIZE (STM32MP2_OTP_MAX_ID + U(1))
- struct bsec_shadow {
- uint32_t magic;
- uint32_t state;
- uint32_t value[OTP_MAX_SIZE];
- uint32_t status[OTP_MAX_SIZE];
- };
- static uint32_t otp_bank(uint32_t otp)
- {
- if (otp > STM32MP2_OTP_MAX_ID) {
- panic();
- }
- return (otp & ~BSEC_OTP_MASK) >> BSEC_OTP_BANK_SHIFT;
- }
- static uint32_t otp_bit_mask(uint32_t otp)
- {
- return BIT(otp & BSEC_OTP_MASK);
- }
- /*
- * bsec_get_status: return status register value.
- */
- static uint32_t bsec_get_status(void)
- {
- return mmio_read_32(BSEC_BASE + BSEC_OTPSR);
- }
- /*
- * bsec_get_version: return BSEC version.
- */
- static uint32_t bsec_get_version(void)
- {
- return mmio_read_32(BSEC_BASE + BSEC_VERR) & BSEC_VERR_MASK;
- }
- /*
- * bsec_get_id: return BSEC ID.
- */
- static uint32_t bsec_get_id(void)
- {
- return mmio_read_32(BSEC_BASE + BSEC_IPIDR);
- }
- static bool is_fuse_shadowed(uint32_t otp)
- {
- uint32_t bank = otp_bank(otp);
- uint32_t otp_mask = otp_bit_mask(otp);
- uint32_t bank_value;
- bank_value = mmio_read_32(BSEC_BASE + BSEC_SFSR(bank));
- if ((bank_value & otp_mask) != 0U) {
- return true;
- }
- return false;
- }
- static void poll_otp_status_busy(void)
- {
- uint32_t timeout = BSEC_TIMEOUT_VALUE;
- while (((bsec_get_status() & BSEC_OTPSR_BUSY) != 0U) && (timeout != 0U)) {
- timeout--;
- }
- if ((bsec_get_status() & BSEC_OTPSR_BUSY) != 0U) {
- ERROR("BSEC timeout\n");
- panic();
- }
- }
- static uint32_t check_read_error(uint32_t otp)
- {
- uint32_t status = bsec_get_status();
- if ((status & BSEC_OTPSR_SECF) != 0U) {
- VERBOSE("BSEC read %u single error correction detected\n", otp);
- }
- if ((status & BSEC_OTPSR_PPLF) != 0U) {
- VERBOSE("BSEC read %u permanent programming lock detected.\n", otp);
- }
- if ((status & BSEC_OTPSR_PPLMF) != 0U) {
- ERROR("BSEC read %u error 0x%x\n", otp, status);
- return BSEC_ERROR;
- }
- if ((status & (BSEC_OTPSR_DISTURBF | BSEC_OTPSR_DEDF | BSEC_OTPSR_AMEF)) != 0U) {
- ERROR("BSEC read %u error 0x%x with invalid FVR\n", otp, status);
- return BSEC_RETRY;
- }
- return BSEC_OK;
- }
- static uint32_t check_program_error(uint32_t otp)
- {
- uint32_t status = bsec_get_status();
- if ((status & BSEC_OTPSR_PROGFAIL) != 0U) {
- ERROR("BSEC program %u error 0x%x\n", otp, status);
- return BSEC_RETRY;
- }
- return BSEC_OK;
- }
- static void check_reset_error(void)
- {
- uint32_t status = bsec_get_status();
- /* check initial status reporting */
- if ((status & BSEC_OTPSR_BUSY) != 0U) {
- VERBOSE("BSEC reset and busy when OTPSR read\n");
- }
- if ((status & BSEC_OTPSR_HIDEUP) != 0U) {
- VERBOSE("BSEC upper fuse are not accessible (HIDEUP)\n");
- }
- if ((status & BSEC_OTPSR_OTPSEC) != 0U) {
- VERBOSE("BSEC reset single error correction detected\n");
- }
- if ((status & BSEC_OTPSR_OTPNVIR) == 0U) {
- VERBOSE("BSEC reset first fuse word 0 is detected zero\n");
- }
- if ((status & BSEC_OTPSR_OTPERR) != 0U) {
- ERROR("BSEC reset critical error 0x%x\n", status);
- panic();
- }
- if ((status & BSEC_OTPSR_FUSEOK) != BSEC_OTPSR_FUSEOK) {
- ERROR("BSEC reset critical error 0x%x\n", status);
- panic();
- }
- }
- static bool is_bsec_write_locked(void)
- {
- return (mmio_read_32(BSEC_BASE + BSEC_LOCKR) & BSEC_LOCKR_GWLOCK_MASK) != 0U;
- }
- /*
- * bsec_probe: initialize BSEC driver.
- * return value: BSEC_OK if no error.
- */
- uint32_t bsec_probe(void)
- {
- uint32_t version = bsec_get_version();
- uint32_t id = bsec_get_id();
- if ((version != BSEC_IP_VERSION_1_0) || (id != BSEC_IP_ID_3)) {
- EARLY_ERROR("%s: version = 0x%x, id = 0x%x\n", __func__, version, id);
- panic();
- }
- check_reset_error();
- 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;
- uint32_t i;
- bool value;
- result = bsec_read_sr_lock(otp, &value);
- if (result != BSEC_OK) {
- WARN("BSEC: %u Sticky-read bit read Error %u\n", otp, result);
- } else if (value) {
- VERBOSE("BSEC: OTP %u is locked and will not be refreshed\n", otp);
- }
- for (i = 0U; i < MAX_NB_TRIES; i++) {
- mmio_write_32(BSEC_BASE + BSEC_OTPCR, otp);
- poll_otp_status_busy();
- result = check_read_error(otp);
- if (result != BSEC_RETRY) {
- break;
- }
- }
- return result;
- }
- /*
- * bsec_write_otp: write a value in shadow OTP.
- * val: value to program.
- * otp: OTP number.
- * return value: BSEC_OK if no error.
- */
- uint32_t bsec_write_otp(uint32_t val, uint32_t otp)
- {
- bool state;
- uint32_t result;
- if (otp > STM32MP2_OTP_MAX_ID) {
- panic();
- }
- if (!is_fuse_shadowed(otp)) {
- return BSEC_ERROR;
- }
- if (is_bsec_write_locked()) {
- return BSEC_WRITE_LOCKED;
- }
- result = bsec_read_sw_lock(otp, &state);
- if (result != BSEC_OK) {
- WARN("Shadow register is SW locked\n");
- return result;
- }
- mmio_write_32(BSEC_BASE + BSEC_FVR(otp), val);
- return BSEC_OK;
- }
- /*
- * 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;
- uint32_t i;
- bool value;
- if (otp > STM32MP2_OTP_MAX_ID) {
- panic();
- }
- if (is_bsec_write_locked() == true) {
- return BSEC_WRITE_LOCKED;
- }
- result = bsec_read_sp_lock(otp, &value);
- if (result != BSEC_OK) {
- WARN("BSEC: %u Sticky-prog bit read Error %u\n", otp, result);
- } else if (value) {
- WARN("BSEC: OTP locked, prog will be ignored\n");
- return BSEC_WRITE_LOCKED;
- }
- mmio_write_32(BSEC_BASE + BSEC_WDR, val);
- for (i = 0U; i < MAX_NB_TRIES; i++) {
- mmio_write_32(BSEC_BASE + BSEC_OTPCR, otp | BSEC_OTPCR_PROG);
- poll_otp_status_busy();
- result = check_program_error(otp);
- if (result != BSEC_RETRY) {
- break;
- }
- }
- return result;
- }
- /*
- * bsec_read_debug_conf: read debug configuration.
- */
- uint32_t bsec_read_debug_conf(void)
- {
- return mmio_read_32(BSEC_BASE + BSEC_DENR);
- }
- static uint32_t bsec_lock_register_set(uint32_t offset, uint32_t mask)
- {
- uint32_t value = mmio_read_32(BSEC_BASE + offset);
- /* The lock is already set */
- if ((value & mask) != 0U) {
- return BSEC_OK;
- }
- if (is_bsec_write_locked()) {
- return BSEC_WRITE_LOCKED;
- }
- value |= mask;
- mmio_write_32(BSEC_BASE + offset, value);
- return BSEC_OK;
- }
- static bool bsec_lock_register_get(uint32_t offset, uint32_t mask)
- {
- uint32_t value = mmio_read_32(BSEC_BASE + offset);
- return (value & mask) != 0U;
- }
- /*
- * 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(otp);
- uint32_t otp_mask = otp_bit_mask(otp);
- if (otp > STM32MP2_OTP_MAX_ID) {
- panic();
- }
- return bsec_lock_register_set(BSEC_SRLOCK(bank), otp_mask);
- }
- /*
- * 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(otp);
- uint32_t otp_mask = otp_bit_mask(otp);
- assert(value != NULL);
- if (otp > STM32MP2_OTP_MAX_ID) {
- panic();
- }
- *value = bsec_lock_register_get(BSEC_SRLOCK(bank), otp_mask);
- 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(otp);
- uint32_t otp_mask = otp_bit_mask(otp);
- if (otp > STM32MP2_OTP_MAX_ID) {
- panic();
- }
- return bsec_lock_register_set(BSEC_SWLOCK(bank), otp_mask);
- }
- /*
- * 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(otp);
- uint32_t otp_mask = otp_bit_mask(otp);
- assert(value != NULL);
- if (otp > STM32MP2_OTP_MAX_ID) {
- panic();
- }
- *value = bsec_lock_register_get(BSEC_SWLOCK(bank), otp_mask);
- 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(otp);
- uint32_t otp_mask = otp_bit_mask(otp);
- if (otp > STM32MP2_OTP_MAX_ID) {
- panic();
- }
- return bsec_lock_register_set(BSEC_SPLOCK(bank), otp_mask);
- }
- /*
- * 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(otp);
- uint32_t otp_mask = otp_bit_mask(otp);
- assert(value != NULL);
- if (otp > STM32MP2_OTP_MAX_ID) {
- panic();
- }
- *value = bsec_lock_register_get(BSEC_SPLOCK(bank), otp_mask);
- return BSEC_OK;
- }
- /*
- * bsec_get_secure_state: read state in BSEC status register.
- * return: secure state
- */
- uint32_t bsec_get_secure_state(void)
- {
- uint32_t state = BSEC_STATE_INVALID;
- uint32_t status = bsec_get_status();
- uint32_t bsec_sr = mmio_read_32(BSEC_BASE + BSEC_SR);
- if ((status & BSEC_OTPSR_FUSEOK) == BSEC_OTPSR_FUSEOK) {
- /* NVSTATE is only valid if FUSEOK */
- uint32_t nvstates = (bsec_sr & BSEC_SR_NVSTATE_MASK) >> BSEC_SR_NVSTATE_SHIFT;
- if (nvstates == BSEC_SR_NVSTATE_OPEN) {
- state = BSEC_STATE_SEC_OPEN;
- } else if (nvstates == BSEC_SR_NVSTATE_CLOSED) {
- state = BSEC_STATE_SEC_CLOSED;
- } else {
- VERBOSE("%s nvstates = %u\n", __func__, nvstates);
- }
- }
- return state;
- }
- /*
- * 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)
- {
- assert(val != NULL);
- if (otp > STM32MP2_OTP_MAX_ID) {
- panic();
- }
- *val = 0U;
- if (is_bsec_write_locked()) {
- return BSEC_WRITE_LOCKED;
- }
- if (!is_fuse_shadowed(otp)) {
- uint32_t result = bsec_shadow_register(otp);
- if (result != BSEC_OK) {
- ERROR("BSEC: %u Shadowing Error %u\n", otp, result);
- return result;
- }
- }
- *val = mmio_read_32(BSEC_BASE + BSEC_FVR(otp));
- return BSEC_OK;
- }
- /*
- * 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)
- {
- assert(val != NULL);
- if (otp > STM32MP2_OTP_MAX_ID) {
- panic();
- }
- return bsec_shadow_read_otp(val, otp);
- }
|