diff --git a/plat/st/common/include/stm32mp_common.h b/plat/st/common/include/stm32mp_common.h index 750800462..cc06f5cb2 100644 --- a/plat/st/common/include/stm32mp_common.h +++ b/plat/st/common/include/stm32mp_common.h @@ -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); diff --git a/plat/st/common/include/stm32mp_dt.h b/plat/st/common/include/stm32mp_dt.h index a87f94185..b7bf1d012 100644 --- a/plat/st/common/include/stm32mp_dt.h +++ b/plat/st/common/include/stm32mp_dt.h @@ -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 */ diff --git a/plat/st/common/stm32mp_common.c b/plat/st/common/stm32mp_common.c index fb8e08ebd..2297cd615 100644 --- a/plat/st/common/stm32mp_common.c +++ b/plat/st/common/stm32mp_common.c @@ -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) { diff --git a/plat/st/common/stm32mp_dt.c b/plat/st/common/stm32mp_dt.c index 863a90fb6..cf6c6e728 100644 --- a/plat/st/common/stm32mp_dt.c +++ b/plat/st/common/stm32mp_dt.c @@ -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. diff --git a/plat/st/stm32mp1/stm32mp1_boot_device.c b/plat/st/stm32mp1/stm32mp1_boot_device.c index 6a0570795..714ab80c5 100644 --- a/plat/st/stm32mp1/stm32mp1_boot_device.c +++ b/plat/st/stm32mp1/stm32mp1_boot_device.c @@ -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; } diff --git a/plat/st/stm32mp1/stm32mp1_def.h b/plat/st/stm32mp1/stm32mp1_def.h index 5d418987f..fb3e13471 100644 --- a/plat/st/stm32mp1/stm32mp1_def.h +++ b/plat/st/stm32mp1/stm32mp1_def.h @@ -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) diff --git a/plat/st/stm32mp1/stm32mp1_private.c b/plat/st/stm32mp1/stm32mp1_private.c index ceb7024bf..075d1d7fa 100644 --- a/plat/st/stm32mp1/stm32mp1_private.c +++ b/plat/st/stm32mp1/stm32mp1_private.c @@ -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; } diff --git a/plat/st/stm32mp1/stm32mp1_syscfg.c b/plat/st/stm32mp1/stm32mp1_syscfg.c index 01a643914..3f34af15b 100644 --- a/plat/st/stm32mp1/stm32mp1_syscfg.c +++ b/plat/st/stm32mp1/stm32mp1_syscfg.c @@ -7,11 +7,11 @@ #include #include #include -#include #include #include #include +#include #include #include @@ -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"); diff --git a/plat/st/stm32mp1/stm32mp1_usb_dfu.c b/plat/st/stm32mp1/stm32mp1_usb_dfu.c index 70fbba6db..33b12d046 100644 --- a/plat/st/stm32mp1/stm32mp1_usb_dfu.c +++ b/plat/st/stm32mp1/stm32mp1_usb_dfu.c @@ -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 */