blob: f82de095100f6e3d0f44721661215c9dce1720ea [file] [log] [blame]
// SPDX-License-Identifier: BSD-3-Clause
/*
* Copyright (c) 2017-2019, STMicroelectronics
*/
#include <assert.h>
#include <drivers/stm32_bsec.h>
#include <io.h>
#include <kernel/delay.h>
#include <kernel/generic_boot.h>
#include <kernel/spinlock.h>
#include <limits.h>
#include <mm/core_memprot.h>
#include <platform_config.h>
#include <stm32_util.h>
#include <types_ext.h>
#include <util.h>
#define BSEC_OTP_MASK GENMASK_32(4, 0)
#define BSEC_OTP_BANK_SHIFT 5
/* Permanent lock bitmasks */
#define ADDR_LOWER_OTP_PERLOCK_SHIFT 3
#define DATA_LOWER_OTP_PERLOCK_BIT 3
#define DATA_LOWER_OTP_PERLOCK_MASK GENMASK_32(2, 0)
#define ADDR_UPPER_OTP_PERLOCK_SHIFT 4
#define DATA_UPPER_OTP_PERLOCK_BIT 1
#define DATA_UPPER_OTP_PERLOCK_MASK GENMASK_32(3, 0)
/* BSEC register offset */
#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_FEN_OFF 0x018U
#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
#define BSEC_WRLOCK1_OFF 0x050U
#define BSEC_WRLOCK2_OFF 0x054U
#define BSEC_SPLOCK_OFF 0x064U
#define BSEC_SPLOCK1_OFF 0x068U
#define BSEC_SPLOCK2_OFF 0x06CU
#define BSEC_SWLOCK_OFF 0x07CU
#define BSEC_SWLOCK1_OFF 0x080U
#define BSEC_SWLOCK2_OFF 0x084U
#define BSEC_SRLOCK_OFF 0x094U
#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_32(2, 1)
#define BSEC_CONF_FRQ_SHIFT 1
#define BSEC_CONF_PRG_WIDTH_MASK GENMASK_32(6, 3)
#define BSEC_CONF_PRG_WIDTH_SHIFT 3
#define BSEC_CONF_TREAD_MASK GENMASK_32(8, 7)
#define BSEC_CONF_TREAD_SHIFT 7
/* BSEC_CONTROL Register */
#define BSEC_READ 0x000U
#define BSEC_WRITE 0x100U
#define BSEC_LOCK 0x200U
/* BSEC_STATUS Register */
#define BSEC_MODE_STATUS_MASK GENMASK_32(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)
/* BSEC_DEBUG */
#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_32(10, 0)
/*
* OTP Lock services definition
* Value must corresponding to the bit position in the register
*/
#define BSEC_LOCK_UPPER_OTP 0x00
#define BSEC_LOCK_DEBUG 0x02
#define BSEC_LOCK_PROGRAM 0x03
/* Timeout when polling on status */
#define BSEC_TIMEOUT_US 1000
struct bsec_dev {
struct io_pa_va base;
unsigned int upper_base;
unsigned int max_id;
bool closed_device;
};
/* Only 1 instance of BSEC is expected per platform */
static struct bsec_dev bsec_dev;
/* BSEC access protection */
static unsigned int lock = SPINLOCK_UNLOCK;
static uint32_t bsec_lock(void)
{
return may_spin_lock(&lock);
}
static void bsec_unlock(uint32_t exceptions)
{
may_spin_unlock(&lock, exceptions);
}
static uint32_t otp_max_id(void)
{
return bsec_dev.max_id;
}
static uint32_t otp_bank_offset(uint32_t otp_id)
{
assert(otp_id <= otp_max_id());
return ((otp_id & ~BSEC_OTP_MASK) >> BSEC_OTP_BANK_SHIFT) *
sizeof(uint32_t);
}
static vaddr_t bsec_base(void)
{
return io_pa_or_va_secure(&bsec_dev.base);
}
static uint32_t bsec_status(void)
{
return io_read32(bsec_base() + BSEC_OTP_STATUS_OFF);
}
static TEE_Result check_no_error(uint32_t otp_id)
{
uint32_t bit = BIT(otp_id & BSEC_OTP_MASK);
uint32_t bank = otp_bank_offset(otp_id);
if (io_read32(bsec_base() + BSEC_DISTURBED_OFF + bank) & bit)
return TEE_ERROR_GENERIC;
if (io_read32(bsec_base() + BSEC_ERROR_OFF + bank) & bit)
return TEE_ERROR_GENERIC;
return TEE_SUCCESS;
}
static TEE_Result power_up_safmem(void)
{
uint64_t timeout_ref = timeout_init_us(BSEC_TIMEOUT_US);
io_mask32(bsec_base() + BSEC_OTP_CONF_OFF, BSEC_CONF_POWER_UP_MASK,
BSEC_CONF_POWER_UP_MASK);
/*
* If a timeout is detected, test the condition again to consider
* cases where timeout is due to the executing TEE thread rescheduling.
*/
while (!timeout_elapsed(timeout_ref))
if (bsec_status() & BSEC_MODE_PWR_MASK)
break;
if (bsec_status() & BSEC_MODE_PWR_MASK)
return TEE_SUCCESS;
return TEE_ERROR_GENERIC;
}
static TEE_Result power_down_safmem(void)
{
uint64_t timeout_ref = timeout_init_us(BSEC_TIMEOUT_US);
io_mask32(bsec_base() + BSEC_OTP_CONF_OFF, 0, BSEC_CONF_POWER_UP_MASK);
/*
* If a timeout is detected, test the condition again to consider
* cases where timeout is due to the executing TEE thread rescheduling.
*/
while (!timeout_elapsed(timeout_ref))
if (!(bsec_status() & BSEC_MODE_PWR_MASK))
break;
if (!(bsec_status() & BSEC_MODE_PWR_MASK))
return TEE_SUCCESS;
return TEE_ERROR_GENERIC;
}
TEE_Result stm32_bsec_shadow_register(uint32_t otp_id)
{
TEE_Result result = 0;
uint32_t exceptions = 0;
uint64_t timeout_ref = 0;
if (otp_id > otp_max_id())
return TEE_ERROR_BAD_PARAMETERS;
/* Check if shadowing of OTP is locked */
if (stm32_bsec_read_sr_lock(otp_id))
IMSG("OTP locked, register will not be refreshed");
exceptions = bsec_lock();
result = power_up_safmem();
if (result)
return result;
io_write32(bsec_base() + BSEC_OTP_CTRL_OFF, otp_id | BSEC_READ);
timeout_ref = timeout_init_us(BSEC_TIMEOUT_US);
while (!timeout_elapsed(timeout_ref))
if (!(bsec_status() & BSEC_MODE_BUSY_MASK))
break;
if (bsec_status() & BSEC_MODE_BUSY_MASK)
result = TEE_ERROR_GENERIC;
else
result = check_no_error(otp_id);
power_down_safmem();
bsec_unlock(exceptions);
return result;
}
TEE_Result stm32_bsec_read_otp(uint32_t *value, uint32_t otp_id)
{
TEE_Result result = 0;
uint32_t exceptions = 0;
if (otp_id > otp_max_id())
return TEE_ERROR_BAD_PARAMETERS;
exceptions = bsec_lock();
*value = io_read32(bsec_base() + BSEC_OTP_DATA_OFF +
(otp_id * sizeof(uint32_t)));
result = check_no_error(otp_id);
bsec_unlock(exceptions);
return result;
}
TEE_Result stm32_bsec_shadow_read_otp(uint32_t *otp_value, uint32_t otp_id)
{
TEE_Result result = 0;
result = stm32_bsec_shadow_register(otp_id);
if (result) {
EMSG("BSEC %" PRIu32 " Shadowing Error %x", otp_id, result);
return result;
}
result = stm32_bsec_read_otp(otp_value, otp_id);
if (result)
EMSG("BSEC %" PRIu32 " Read Error %x", otp_id, result);
return result;
}
TEE_Result stm32_bsec_write_otp(uint32_t value, uint32_t otp_id)
{
TEE_Result result = 0;
uint32_t exceptions = 0;
vaddr_t otp_data_base = bsec_base() + BSEC_OTP_DATA_OFF;
if (otp_id > otp_max_id())
return TEE_ERROR_BAD_PARAMETERS;
/* Check if programming of OTP is locked */
if (stm32_bsec_read_sw_lock(otp_id))
IMSG("OTP locked, write will be ignored");
exceptions = bsec_lock();
io_write32(otp_data_base + (otp_id * sizeof(uint32_t)), value);
result = check_no_error(otp_id);
bsec_unlock(exceptions);
return result;
}
TEE_Result stm32_bsec_program_otp(uint32_t value, uint32_t otp_id)
{
TEE_Result result = 0;
uint32_t exceptions = 0;
uint64_t timeout_ref;
if (otp_id > otp_max_id())
return TEE_ERROR_BAD_PARAMETERS;
/* Check if programming of OTP is locked */
if (stm32_bsec_read_sp_lock(otp_id))
IMSG("OTP locked, prog will be ignored");
if (io_read32(bsec_base() + BSEC_OTP_LOCK_OFF) & BIT(BSEC_LOCK_PROGRAM))
IMSG("GPLOCK activated, prog will be ignored");
exceptions = bsec_lock();
result = power_up_safmem();
if (result)
return result;
io_write32(bsec_base() + BSEC_OTP_WRDATA_OFF, value);
io_write32(bsec_base() + BSEC_OTP_CTRL_OFF, otp_id | BSEC_WRITE);
timeout_ref = timeout_init_us(BSEC_TIMEOUT_US);
while (!timeout_elapsed(timeout_ref))
if (!(bsec_status() & BSEC_MODE_BUSY_MASK))
break;
if (bsec_status() & (BSEC_MODE_BUSY_MASK | BSEC_MODE_PROGFAIL_MASK))
result = TEE_ERROR_GENERIC;
else
result = check_no_error(otp_id);
power_down_safmem();
bsec_unlock(exceptions);
return result;
}
TEE_Result stm32_bsec_permanent_lock_otp(uint32_t otp_id)
{
TEE_Result result = 0;
uint32_t data = 0;
uint32_t addr = 0;
uint32_t exceptions = 0;
vaddr_t base = bsec_base();
uint64_t timeout_ref;
if (otp_id > otp_max_id())
return TEE_ERROR_BAD_PARAMETERS;
if (otp_id < bsec_dev.upper_base) {
addr = otp_id >> ADDR_LOWER_OTP_PERLOCK_SHIFT;
data = DATA_LOWER_OTP_PERLOCK_BIT <<
((otp_id & DATA_LOWER_OTP_PERLOCK_MASK) << 1U);
} else {
addr = (otp_id >> ADDR_UPPER_OTP_PERLOCK_SHIFT) + 2U;
data = DATA_UPPER_OTP_PERLOCK_BIT <<
(otp_id & DATA_UPPER_OTP_PERLOCK_MASK);
}
exceptions = bsec_lock();
result = power_up_safmem();
if (result)
return result;
io_write32(base + BSEC_OTP_WRDATA_OFF, data);
io_write32(base + BSEC_OTP_CTRL_OFF, addr | BSEC_WRITE | BSEC_LOCK);
timeout_ref = timeout_init_us(BSEC_TIMEOUT_US);
while (!timeout_elapsed(timeout_ref))
if (!(bsec_status() & BSEC_MODE_BUSY_MASK))
break;
if (bsec_status() & (BSEC_MODE_BUSY_MASK | BSEC_MODE_PROGFAIL_MASK))
result = TEE_ERROR_BAD_PARAMETERS;
else
result = check_no_error(otp_id);
power_down_safmem();
bsec_unlock(exceptions);
return result;
}
TEE_Result stm32_bsec_write_debug_conf(uint32_t value)
{
TEE_Result result = TEE_ERROR_GENERIC;
uint32_t masked_val = value & BSEC_DEN_ALL_MSK;
uint32_t exceptions = 0;
exceptions = bsec_lock();
io_write32(bsec_base() + BSEC_DEN_OFF, value);
if ((io_read32(bsec_base() + BSEC_DEN_OFF) ^ masked_val) == 0U)
result = TEE_SUCCESS;
bsec_unlock(exceptions);
return result;
}
uint32_t stm32_bsec_read_debug_conf(void)
{
return io_read32(bsec_base() + BSEC_DEN_OFF);
}
static bool write_bsec_lock(uint32_t otp_id, uint32_t value, size_t lock_offset)
{
uint32_t bank = otp_bank_offset(otp_id);
uint32_t otp_mask = BIT(otp_id & BSEC_OTP_MASK);
vaddr_t lock_addr = bsec_base() + bank + lock_offset;
uint32_t bank_value = 0;
uint32_t exceptions = 0;
if (!value)
return false;
exceptions = bsec_lock();
bank_value = io_read32(lock_addr);
if ((bank_value & otp_mask) != value) {
/*
* We can write 0 in all other OTP
* if the lock is activated in one of other OTP.
* Write 0 has no effect.
*/
io_write32(lock_addr, bank_value | otp_mask);
}
bsec_unlock(exceptions);
return true;
}
bool stm32_bsec_write_sr_lock(uint32_t otp_id, uint32_t value)
{
return write_bsec_lock(otp_id, value, BSEC_SRLOCK_OFF);
}
bool stm32_bsec_write_sw_lock(uint32_t otp_id, uint32_t value)
{
return write_bsec_lock(otp_id, value, BSEC_SWLOCK_OFF);
}
bool stm32_bsec_write_sp_lock(uint32_t otp_id, uint32_t value)
{
return write_bsec_lock(otp_id, value, BSEC_SPLOCK_OFF);
}
static bool read_bsec_lock(uint32_t otp_id, size_t lock_offset)
{
uint32_t bank = otp_bank_offset(otp_id);
uint32_t otp_mask = BIT(otp_id & BSEC_OTP_MASK);
vaddr_t lock_addr = bsec_base() + bank + lock_offset;
return io_read32(lock_addr) & otp_mask;
}
bool stm32_bsec_read_sr_lock(uint32_t otp_id)
{
return read_bsec_lock(otp_id, BSEC_SRLOCK_OFF);
}
bool stm32_bsec_read_sw_lock(uint32_t otp_id)
{
return read_bsec_lock(otp_id, BSEC_SWLOCK_OFF);
}
bool stm32_bsec_read_sp_lock(uint32_t otp_id)
{
return read_bsec_lock(otp_id, BSEC_SPLOCK_OFF);
}
bool stm32_bsec_wr_lock(uint32_t otp_id)
{
uint32_t bank = otp_bank_offset(otp_id);
uint32_t lock_bit = BIT(otp_id & BSEC_OTP_MASK);
if (io_read32(bsec_base() + BSEC_WRLOCK_OFF + bank) & lock_bit) {
/*
* In case of write don't need to write,
* the lock is already set.
*/
return true;
}
return false;
}
uint32_t stm32_bsec_otp_lock(uint32_t service, uint32_t value)
{
vaddr_t addr = bsec_base() + BSEC_OTP_LOCK_OFF;
switch (service) {
case BSEC_LOCK_UPPER_OTP:
io_write32(addr, value << BSEC_LOCK_UPPER_OTP);
break;
case BSEC_LOCK_DEBUG:
io_write32(addr, value << BSEC_LOCK_DEBUG);
break;
case BSEC_LOCK_PROGRAM:
io_write32(addr, value << BSEC_LOCK_PROGRAM);
break;
default:
return TEE_ERROR_BAD_PARAMETERS;
}
return TEE_SUCCESS;
}
bool stm32_bsec_nsec_can_access_otp(uint32_t otp_id)
{
if (otp_id > otp_max_id())
return false;
return otp_id < bsec_dev.upper_base || !bsec_dev.closed_device;
}
static TEE_Result initialize_bsec(void)
{
struct stm32_bsec_static_cfg cfg = { 0 };
uint32_t otp = 0;
TEE_Result result = 0;
stm32mp_get_bsec_static_cfg(&cfg);
bsec_dev.base.pa = cfg.base;
bsec_dev.upper_base = cfg.upper_start;
bsec_dev.max_id = cfg.max_id;
bsec_dev.closed_device = true;
/* Disable closed device mode upon platform closed device OTP value */
result = stm32_bsec_shadow_read_otp(&otp, cfg.closed_device_id);
if (!result && !(otp & BIT(cfg.closed_device_position)))
bsec_dev.closed_device = false;
return TEE_SUCCESS;
}
driver_init(initialize_bsec);