mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-16 09:34:18 +00:00
feat(stm32mp1): new way to access platform OTP
Use dt_find_otp_name() to retrieve platform OTP information from device tree, directly or through stm32_get_otp_index() and stm32_get_otp_value() platform services. String definitions replace hard-coded values, they are used to call this new function. Change-Id: I81213e4a9ad08fddadc2c97b064ae057a4c79561 Signed-off-by: Nicolas Le Bayon <nicolas.le.bayon@st.com> Signed-off-by: Yann Gautier <yann.gautier@st.com>
This commit is contained in:
parent
375b79bb4a
commit
ae3ce8b28e
9 changed files with 185 additions and 92 deletions
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2018-2021, STMicroelectronics - All Rights Reserved
|
||||
* Copyright (C) 2018-2022, STMicroelectronics - All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
@ -37,6 +37,11 @@ uintptr_t stm32mp_rcc_base(void);
|
|||
/* Check MMU status to allow spinlock use */
|
||||
bool stm32mp_lock_available(void);
|
||||
|
||||
int stm32_get_otp_index(const char *otp_name, uint32_t *otp_idx,
|
||||
uint32_t *otp_len);
|
||||
int stm32_get_otp_value(const char *otp_name, uint32_t *otp_val);
|
||||
int stm32_get_otp_value_from_idx(const uint32_t otp_idx, uint32_t *otp_val);
|
||||
|
||||
/* Get IWDG platform instance ID from peripheral IO memory base address */
|
||||
uint32_t stm32_iwdg_get_instance(uintptr_t base);
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2021, STMicroelectronics - All Rights Reserved
|
||||
* Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
|
||||
* Copyright (c) 2020-2022, STMicroelectronics - All Rights Reserved
|
||||
* Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
@ -40,6 +40,7 @@ uint32_t dt_get_pwr_vdd_voltage(void);
|
|||
struct rdev *dt_get_vdd_regulator(void);
|
||||
struct rdev *dt_get_cpu_regulator(void);
|
||||
const char *dt_get_board_model(void);
|
||||
int dt_find_otp_name(const char *name, uint32_t *otp, uint32_t *otp_len);
|
||||
int fdt_get_gpio_bank_pin_count(unsigned int bank);
|
||||
|
||||
#endif /* STM32MP_DT_H */
|
||||
|
|
|
@ -135,6 +135,55 @@ int stm32mp_unmap_ddr(void)
|
|||
STM32MP_DDR_MAX_SIZE);
|
||||
}
|
||||
|
||||
int stm32_get_otp_index(const char *otp_name, uint32_t *otp_idx,
|
||||
uint32_t *otp_len)
|
||||
{
|
||||
assert(otp_name != NULL);
|
||||
assert(otp_idx != NULL);
|
||||
|
||||
return dt_find_otp_name(otp_name, otp_idx, otp_len);
|
||||
}
|
||||
|
||||
int stm32_get_otp_value(const char *otp_name, uint32_t *otp_val)
|
||||
{
|
||||
uint32_t otp_idx;
|
||||
|
||||
assert(otp_name != NULL);
|
||||
assert(otp_val != NULL);
|
||||
|
||||
if (stm32_get_otp_index(otp_name, &otp_idx, NULL) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (stm32_get_otp_value_from_idx(otp_idx, otp_val) != 0) {
|
||||
ERROR("BSEC: %s Read Error\n", otp_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stm32_get_otp_value_from_idx(const uint32_t otp_idx, uint32_t *otp_val)
|
||||
{
|
||||
uint32_t ret = BSEC_NOT_SUPPORTED;
|
||||
|
||||
assert(otp_val != NULL);
|
||||
|
||||
#if defined(IMAGE_BL2)
|
||||
ret = bsec_shadow_read_otp(otp_val, otp_idx);
|
||||
#elif defined(IMAGE_BL32)
|
||||
ret = bsec_read_otp(otp_val, otp_idx);
|
||||
#else
|
||||
#error "Not supported"
|
||||
#endif
|
||||
if (ret != BSEC_OK) {
|
||||
ERROR("BSEC: idx=%u Read Error\n", otp_idx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(IMAGE_BL2)
|
||||
static void reset_uart(uint32_t reset)
|
||||
{
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
|
||||
* Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
@ -318,6 +318,73 @@ const char *dt_get_board_model(void)
|
|||
return (const char *)fdt_getprop(fdt, node, "model", NULL);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* dt_find_otp_name: get OTP ID and length in DT.
|
||||
* name: sub-node name to look up.
|
||||
* otp: pointer to read OTP number or NULL.
|
||||
* otp_len: pointer to read OTP length in bits or NULL.
|
||||
* return value: 0 if no error, an FDT error value otherwise.
|
||||
******************************************************************************/
|
||||
int dt_find_otp_name(const char *name, uint32_t *otp, uint32_t *otp_len)
|
||||
{
|
||||
int node;
|
||||
int index, len;
|
||||
const fdt32_t *cuint;
|
||||
|
||||
if ((name == NULL) || (otp == NULL)) {
|
||||
return -FDT_ERR_BADVALUE;
|
||||
}
|
||||
|
||||
node = fdt_node_offset_by_compatible(fdt, -1, DT_NVMEM_LAYOUT_COMPAT);
|
||||
if (node < 0) {
|
||||
return node;
|
||||
}
|
||||
|
||||
index = fdt_stringlist_search(fdt, node, "nvmem-cell-names", name);
|
||||
if (index < 0) {
|
||||
return index;
|
||||
}
|
||||
|
||||
cuint = fdt_getprop(fdt, node, "nvmem-cells", &len);
|
||||
if (cuint == NULL) {
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
}
|
||||
|
||||
if ((index * (int)sizeof(uint32_t)) > len) {
|
||||
return -FDT_ERR_BADVALUE;
|
||||
}
|
||||
|
||||
cuint += index;
|
||||
|
||||
node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint));
|
||||
if (node < 0) {
|
||||
ERROR("Malformed nvmem_layout node: ignored\n");
|
||||
return node;
|
||||
}
|
||||
|
||||
cuint = fdt_getprop(fdt, node, "reg", &len);
|
||||
if ((cuint == NULL) || (len != (2 * (int)sizeof(uint32_t)))) {
|
||||
ERROR("Malformed nvmem_layout node: ignored\n");
|
||||
return -FDT_ERR_BADVALUE;
|
||||
}
|
||||
|
||||
if (fdt32_to_cpu(*cuint) % sizeof(uint32_t)) {
|
||||
ERROR("Misaligned nvmem_layout element: ignored\n");
|
||||
return -FDT_ERR_BADVALUE;
|
||||
}
|
||||
|
||||
if (otp != NULL) {
|
||||
*otp = fdt32_to_cpu(*cuint) / sizeof(uint32_t);
|
||||
}
|
||||
|
||||
if (otp_len != NULL) {
|
||||
cuint++;
|
||||
*otp_len = fdt32_to_cpu(*cuint) * CHAR_BIT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* This function gets the pin count for a GPIO bank based from the FDT.
|
||||
* It also checks node consistency.
|
||||
|
|
|
@ -20,13 +20,11 @@
|
|||
#if STM32MP_RAW_NAND || STM32MP_SPI_NAND
|
||||
static int get_data_from_otp(struct nand_device *nand_dev, bool is_slc)
|
||||
{
|
||||
int result;
|
||||
uint32_t nand_param;
|
||||
|
||||
/* Check if NAND parameters are stored in OTP */
|
||||
result = bsec_shadow_read_otp(&nand_param, NAND_OTP);
|
||||
if (result != BSEC_OK) {
|
||||
ERROR("BSEC: NAND_OTP Error %i\n", result);
|
||||
if (stm32_get_otp_value(NAND_OTP, &nand_param) != 0) {
|
||||
ERROR("BSEC: NAND_OTP Error\n");
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
|
|
|
@ -347,19 +347,18 @@ enum ddr_type {
|
|||
|
||||
#define OTP_MAX_SIZE (STM32MP1_OTP_MAX_ID + 1U)
|
||||
|
||||
/* OTP offsets */
|
||||
#define DATA0_OTP U(0)
|
||||
#define PART_NUMBER_OTP U(1)
|
||||
#define NAND_OTP U(9)
|
||||
#define UID0_OTP U(13)
|
||||
#define UID1_OTP U(14)
|
||||
#define UID2_OTP U(15)
|
||||
#define PACKAGE_OTP U(16)
|
||||
#define HW2_OTP U(18)
|
||||
/* OTP labels */
|
||||
#define CFG0_OTP "cfg0_otp"
|
||||
#define PART_NUMBER_OTP "part_number_otp"
|
||||
#define PACKAGE_OTP "package_otp"
|
||||
#define HW2_OTP "hw2_otp"
|
||||
#define NAND_OTP "nand_otp"
|
||||
#define UID_OTP "uid_otp"
|
||||
#define BOARD_ID_OTP "board_id"
|
||||
|
||||
/* OTP mask */
|
||||
/* DATA0 */
|
||||
#define DATA0_OTP_SECURED BIT(6)
|
||||
/* CFG0 */
|
||||
#define CFG0_CLOSED_DEVICE BIT(6)
|
||||
|
||||
/* PART NUMBER */
|
||||
#define PART_NUMBER_OTP_PART_MASK GENMASK_32(7, 0)
|
||||
|
|
|
@ -278,7 +278,7 @@ static uint32_t get_part_number(void)
|
|||
return part_number;
|
||||
}
|
||||
|
||||
if (bsec_shadow_read_otp(&part_number, PART_NUMBER_OTP) != BSEC_OK) {
|
||||
if (stm32_get_otp_value(PART_NUMBER_OTP, &part_number) != 0) {
|
||||
panic();
|
||||
}
|
||||
|
||||
|
@ -294,7 +294,7 @@ static uint32_t get_cpu_package(void)
|
|||
{
|
||||
uint32_t package;
|
||||
|
||||
if (bsec_shadow_read_otp(&package, PACKAGE_OTP) != BSEC_OK) {
|
||||
if (stm32_get_otp_value(PACKAGE_OTP, &package) != 0) {
|
||||
panic();
|
||||
}
|
||||
|
||||
|
@ -397,35 +397,9 @@ void stm32mp_print_cpuinfo(void)
|
|||
|
||||
void stm32mp_print_boardinfo(void)
|
||||
{
|
||||
uint32_t board_id;
|
||||
uint32_t board_otp;
|
||||
int bsec_node, bsec_board_id_node;
|
||||
void *fdt;
|
||||
const fdt32_t *cuint;
|
||||
uint32_t board_id = 0;
|
||||
|
||||
if (fdt_get_address(&fdt) == 0) {
|
||||
panic();
|
||||
}
|
||||
|
||||
bsec_node = fdt_node_offset_by_compatible(fdt, -1, DT_BSEC_COMPAT);
|
||||
if (bsec_node < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
bsec_board_id_node = fdt_subnode_offset(fdt, bsec_node, "board_id");
|
||||
if (bsec_board_id_node <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
cuint = fdt_getprop(fdt, bsec_board_id_node, "reg", NULL);
|
||||
if (cuint == NULL) {
|
||||
panic();
|
||||
}
|
||||
|
||||
board_otp = fdt32_to_cpu(*cuint) / sizeof(uint32_t);
|
||||
|
||||
if (bsec_shadow_read_otp(&board_id, board_otp) != BSEC_OK) {
|
||||
ERROR("BSEC: PART_NUMBER_OTP Error\n");
|
||||
if (stm32_get_otp_value(BOARD_ID_OTP, &board_id) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -462,12 +436,11 @@ bool stm32mp_is_closed_device(void)
|
|||
{
|
||||
uint32_t value;
|
||||
|
||||
if ((bsec_shadow_register(DATA0_OTP) != BSEC_OK) ||
|
||||
(bsec_read_otp(&value, DATA0_OTP) != BSEC_OK)) {
|
||||
if (stm32_get_otp_value(CFG0_OTP, &value) != 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return (value & DATA0_OTP_SECURED) == DATA0_OTP_SECURED;
|
||||
return (value & CFG0_CLOSED_DEVICE) == CFG0_CLOSED_DEVICE;
|
||||
}
|
||||
|
||||
uint32_t stm32_iwdg_get_instance(uintptr_t base)
|
||||
|
@ -487,13 +460,7 @@ uint32_t stm32_iwdg_get_otp_config(uint32_t iwdg_inst)
|
|||
uint32_t iwdg_cfg = 0U;
|
||||
uint32_t otp_value;
|
||||
|
||||
#if defined(IMAGE_BL2)
|
||||
if (bsec_shadow_register(HW2_OTP) != BSEC_OK) {
|
||||
panic();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (bsec_read_otp(&otp_value, HW2_OTP) != BSEC_OK) {
|
||||
if (stm32_get_otp_value(HW2_OTP, &otp_value) != 0) {
|
||||
panic();
|
||||
}
|
||||
|
||||
|
@ -515,29 +482,34 @@ uint32_t stm32_iwdg_get_otp_config(uint32_t iwdg_inst)
|
|||
#if defined(IMAGE_BL2)
|
||||
uint32_t stm32_iwdg_shadow_update(uint32_t iwdg_inst, uint32_t flags)
|
||||
{
|
||||
uint32_t otp_value;
|
||||
uint32_t otp;
|
||||
uint32_t result;
|
||||
|
||||
if (bsec_shadow_read_otp(&otp, HW2_OTP) != BSEC_OK) {
|
||||
if (stm32_get_otp_index(HW2_OTP, &otp, NULL) != 0) {
|
||||
panic();
|
||||
}
|
||||
|
||||
if ((flags & IWDG_DISABLE_ON_STOP) != 0U) {
|
||||
otp |= BIT(iwdg_inst + HW2_OTP_IWDG_FZ_STOP_POS);
|
||||
if (stm32_get_otp_value(HW2_OTP, &otp_value) != 0) {
|
||||
panic();
|
||||
}
|
||||
|
||||
if ((flags & IWDG_DISABLE_ON_STANDBY) != 0U) {
|
||||
otp |= BIT(iwdg_inst + HW2_OTP_IWDG_FZ_STANDBY_POS);
|
||||
if ((flags & IWDG_DISABLE_ON_STOP) != 0) {
|
||||
otp_value |= BIT(iwdg_inst + HW2_OTP_IWDG_FZ_STOP_POS);
|
||||
}
|
||||
|
||||
result = bsec_write_otp(otp, HW2_OTP);
|
||||
if ((flags & IWDG_DISABLE_ON_STANDBY) != 0) {
|
||||
otp_value |= BIT(iwdg_inst + HW2_OTP_IWDG_FZ_STANDBY_POS);
|
||||
}
|
||||
|
||||
result = bsec_write_otp(otp_value, otp);
|
||||
if (result != BSEC_OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Sticky lock OTP_IWDG (read and write) */
|
||||
if ((bsec_set_sr_lock(HW2_OTP) != BSEC_OK) ||
|
||||
(bsec_set_sw_lock(HW2_OTP) != BSEC_OK)) {
|
||||
if ((bsec_set_sr_lock(otp) != BSEC_OK) ||
|
||||
(bsec_set_sw_lock(otp) != BSEC_OK)) {
|
||||
return BSEC_LOCK_FAIL;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
#include <common/debug.h>
|
||||
#include <drivers/clk.h>
|
||||
#include <drivers/delay_timer.h>
|
||||
#include <drivers/st/bsec.h>
|
||||
#include <drivers/st/stpmic1.h>
|
||||
#include <lib/mmio.h>
|
||||
|
||||
#include <platform_def.h>
|
||||
#include <stm32mp_common.h>
|
||||
#include <stm32mp_dt.h>
|
||||
#include <stm32mp1_private.h>
|
||||
|
||||
|
@ -116,8 +116,9 @@ static void enable_high_speed_mode_low_voltage(void)
|
|||
|
||||
static void stm32mp1_syscfg_set_hslv(void)
|
||||
{
|
||||
uint32_t otp = 0;
|
||||
uint32_t otp_value;
|
||||
uint32_t vdd_voltage;
|
||||
bool product_below_2v5;
|
||||
|
||||
/*
|
||||
* High Speed Low Voltage Pad mode Enable for SPI, SDMMC, ETH, QSPI
|
||||
|
@ -134,26 +135,26 @@ static void stm32mp1_syscfg_set_hslv(void)
|
|||
* => TF-A enables the low power mode only if VDD < 2.7V (in DT)
|
||||
* but this value needs to be consistent with board design.
|
||||
*/
|
||||
if (bsec_read_otp(&otp, HW2_OTP) != BSEC_OK) {
|
||||
if (stm32_get_otp_value(HW2_OTP, &otp_value) != 0) {
|
||||
panic();
|
||||
}
|
||||
|
||||
otp = otp & HW2_OTP_PRODUCT_BELOW_2V5;
|
||||
product_below_2v5 = (otp_value & HW2_OTP_PRODUCT_BELOW_2V5) != 0U;
|
||||
|
||||
/* Get VDD supply */
|
||||
vdd_voltage = dt_get_pwr_vdd_voltage();
|
||||
|
||||
/* Check if VDD is Low Voltage */
|
||||
if (vdd_voltage == 0U) {
|
||||
WARN("VDD unknown");
|
||||
WARN("VDD unknown\n");
|
||||
} else if (vdd_voltage < 2700000U) {
|
||||
enable_high_speed_mode_low_voltage();
|
||||
|
||||
if (otp == 0U) {
|
||||
if (!product_below_2v5) {
|
||||
INFO("Product_below_2v5=0: HSLVEN protected by HW\n");
|
||||
}
|
||||
} else {
|
||||
if (otp != 0U) {
|
||||
if (product_below_2v5) {
|
||||
ERROR("Product_below_2v5=1:\n");
|
||||
ERROR("\tHSLVEN update is destructive,\n");
|
||||
ERROR("\tno update as VDD > 2.7V\n");
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2021, STMicroelectronics - All Rights Reserved
|
||||
* Copyright (c) 2021-2022, STMicroelectronics - All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
@ -157,27 +157,28 @@ static void stm32mp1_get_string(const char *desc, uint8_t *unicode, uint16_t *le
|
|||
static void update_serial_num_string(void)
|
||||
{
|
||||
uint8_t i;
|
||||
uint32_t result;
|
||||
char serial_string[SIZ_STRING_SERIAL + 2U];
|
||||
uint32_t deviceserial[UID_WORD_NB];
|
||||
/* serial number is set to 0 */
|
||||
uint32_t deviceserial[UID_WORD_NB] = {0U, 0U, 0U};
|
||||
uint32_t otp;
|
||||
uint32_t len;
|
||||
uint16_t length;
|
||||
|
||||
for (i = 0U; i < UID_WORD_NB; i++) {
|
||||
result = bsec_shadow_register(i + UID0_OTP);
|
||||
if (result != BSEC_OK) {
|
||||
ERROR("BSEC: UID%d Shadowing Error\n", i);
|
||||
break;
|
||||
}
|
||||
result = bsec_read_otp(&deviceserial[i], i + UID0_OTP);
|
||||
if (result != BSEC_OK) {
|
||||
ERROR("BSEC: UID%d Read Error\n", i);
|
||||
break;
|
||||
}
|
||||
if (stm32_get_otp_index(UID_OTP, &otp, &len) != 0) {
|
||||
ERROR("BSEC: Get UID_OTP number Error\n");
|
||||
return;
|
||||
}
|
||||
/* On bsec error: serial number is set to 0 */
|
||||
if (result != BSEC_OK) {
|
||||
for (i = 0; i < UID_WORD_NB; i++) {
|
||||
deviceserial[i] = 0U;
|
||||
|
||||
if ((len / __WORD_BIT) != UID_WORD_NB) {
|
||||
ERROR("BSEC: Get UID_OTP length Error\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < UID_WORD_NB; i++) {
|
||||
if (bsec_shadow_read_otp(&deviceserial[i], i + otp) !=
|
||||
BSEC_OK) {
|
||||
ERROR("BSEC: UID%d Error\n", i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* build serial number with OTP value as in ROM code */
|
||||
|
|
Loading…
Add table
Reference in a new issue