diff --git a/fdts/stm32mp15-ssp-bl2.dtsi b/fdts/stm32mp15-ssp-bl2.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..107f6e21664bc853c3216965700d8193bfc6edde --- /dev/null +++ b/fdts/stm32mp15-ssp-bl2.dtsi @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2020 - All Rights Reserved + */ + +/ { + cpus { + /delete-node/ cpu@1; + }; + +#if STM32MP_USB_PROGRAMMER + aliases { + /delete-property/ serial1; + }; +#endif + + /delete-node/ cpu0_opp_table; + + nvmem_layout@0 { + /delete-property/ nvmem-cells; + /delete-property/ nvmem-cell-names; + + nvmem-cells = <&cfg0_otp>, + <&part_number_otp>, + <&monotonic_otp>, + <&nand_otp>, + <&uid_otp>, + <&package_otp>, + <&hw2_otp>, + <&pkh_otp>, + <&cfg2_otp>, + <&ssp_otp>, + <&chip_otp>, + <&rma_otp>; + + nvmem-cell-names = "cfg0_otp", + "part_number_otp", + "monotonic_otp", + "nand_otp", + "uid_otp", + "package_otp", + "hw2_otp", + "pkh_otp", + "cfg2_otp", + "ssp_otp", + "chip_otp", + "rma_otp"; + }; + + /delete-node/ psci; + + soc { + efuse@5c005000 { + cfg2_otp: cfg2_otp@8 { + reg = <0x8 0x4>; + }; + + ssp_otp: ssp_otp@20 { + reg = <0x20 0x4>; + }; + + chip_otp: chip_otp@a0 { + reg = <0xa0 0x40>; + }; + + rma_otp: rma_otp@e0 { + reg = <0xe0 0x4>; + }; + }; + + /delete-node/ timer@40006000; + /delete-node/ timer@44006000; + /delete-node/ pwr_mcu@50001014; + /delete-node/ cryp@54001000; + /delete-node/ rng@54003000; + /delete-node/ memory-controller@58002000; + /delete-node/ spi@58003000; + /delete-node/ sdmmc@58005000; + /delete-node/ sdmmc@58007000; + /delete-node/ ddr@5a003000; + /delete-node/ spi@5c001000; + /delete-node/ rtc@5c004000; + /delete-node/ etzpc@5c007000; + /delete-node/ stgen@5c008000; + /delete-node/ i2c@5c009000; + /delete-node/ tamp@5c00a000; +#if STM32MP_USB_PROGRAMMER + /delete-node/ serial@4000e000; + /delete-node/ serial@4000f000; + /delete-node/ serial@40011000; + /delete-node/ serial@40018000; + /delete-node/ serial@40019000; + /delete-node/ serial@44003000; + /delete-node/ serial@5c000000; +#endif +#if STM32MP_UART_PROGRAMMER + /delete-node/ usb-otg@49000000; + /delete-node/ usbphyc@5a006000; +#endif + + pin-controller@50002000 { + /delete-node/ fmc-0; + /delete-node/ qspi-clk-0; + /delete-node/ qspi-bk1-0; + /delete-node/ qspi-bk2-0; + /delete-node/ rtc-out2-rmp-pins-0; + /delete-node/ sdmmc1-b4-0; + /delete-node/ sdmmc1-dir-0; + /delete-node/ sdmmc2-b4-0; + /delete-node/ sdmmc2-b4-1; + /delete-node/ sdmmc2-d47-0; +#if STM32MP_USB_PROGRAMMER + /delete-node/ uart7-0; + /delete-node/ uart7-1; + /delete-node/ usart2-0; + /delete-node/ usart3-0; + /delete-node/ usart3-1; +#endif +#if STM32MP_UART_PROGRAMMER + /delete-node/ usbotg_hs-0; + /delete-node/ usbotg-fs-dp-dm-0; +#endif + }; + }; +}; diff --git a/plat/st/stm32mp1/include/boot_api.h b/plat/st/stm32mp1/include/boot_api.h index 17728005c77dc997f87eb2d0e1ba527b2a462346..8c9d3afb491641e7c8ef58dcce0638f286a06505 100644 --- a/plat/st/stm32mp1/include/boot_api.h +++ b/plat/st/stm32mp1/include/boot_api.h @@ -335,15 +335,278 @@ BOOT_API_MCIC_RETRAM_REGION_TO_HASH_IN_BYTES_TAMP_BCK_REG_IDX 23 /* 'K' 'B' 'U' 'P' -.> 'PUBK' */ #define BOOT_API_CTX_SSP_CMD_CALC_CHIP_PUBK 0x4B425550 +#if STM32MP_SSP +/* 'V' 'O' 'R' 'P' -.> 'PROV' */ +#define BOOT_API_CTX_SSP_CMD_PROV_SECRET 0x564F5250 +/* + * Possible values of boot context field + * 'ssp_config_ptr_in->ssp_cmd' written by bootROM as Acknowledge + * of a request of SSP by FSBL. + */ + +/* Written by bootROM on SSP error */ +#define BOOT_API_CTX_SSP_CMD_INVALID 0x00000000 +/* + * 'A' 'B' 'U' 'P' -.> 'PUBA' : ACK of ECIES_CHIP_PUBK calculation + * request by bootROM. + */ +#define BOOT_API_CTX_SSP_CMD_CALC_CHIP_PUBK_ACK 0x41425550 +/* + * 'A' 'O' 'R' 'P' -.> 'PROA' : ACK of OEM Secret Provisioning request + * by bootROM. + */ +#define BOOT_API_CTX_SSP_CMD_PROV_SECRET_ACK 0x414F5250 + +/* + * Constants required for SSP + */ +/* '.' 'P' 'S' 'S' -.> 'SSP.' */ +#define BOOT_API_SSP_BLOB_LICENSE_TYPE_SSP_NORMAL 0x2E505353 +/* 'L' 'P' 'S' 'S' -.> 'SSPL' */ +#define BOOT_API_SSP_BLOB_LICENSE_TYPE_SSP_LIVE 0x4C505353 +/* version 1 */ +#define BOOT_API_SSP_LICENSE_LAYOUT_VERSION_TO_MATCH 0x00000001 +/* 'P' 'P' 'S' 'S' -.> 'SSPP' */ +#define BOOT_API_SSP_BLOB_PAYLOAD_MAGIC_SSP 0x50505353 +/* IV AES on 128 bits = 16 bytes and KEY AES on 128 bits = 16 bytes */ +#define BOOT_API_SSP_ENCRYPTED_IV_AND_KEY_SIZE_BYTES 32 +/* version 1 */ +#define BOOT_API_SSP_PAYLOAD_PROTOCOL_VERSION_TO_MATCH 0x00000001 +/* + * Scalar in Elliptic curve cryptography is an integer (often a Prime) + * the number of bytes of this scalar is defined below. + */ +#define BOOT_API_SSP_SCALAR_SIZE_BYTES 32 + +/* + * In Elliptic curve cryptography coordinates of points are 2D P + * (Px, Py) as concatenation of two scalars. + */ +#define BOOT_API_SSP_EC_COORDINATE_SIZE_BYTES \ + (2 * BOOT_API_SSP_SCALAR_SIZE_BYTES) + +/* In Elliptic curve cryptography Private Keys are scalars */ +#define BOOT_API_SSP_PRIVK_KEY_SIZE_BYTES \ + BOOT_API_SSP_SCALAR_SIZE_BYTES + +/* + * In ECIES algorithm the Shared Secret (SS) is + * the x coordinate (Px) of a point P(Px,Py) obtained on reference + * chosen NIST-P256 Elliptic curve. + */ +#define BOOT_API_SSP_ECDH_SHARED_SECRET_SIZE_BYTES \ + BOOT_API_SSP_SCALAR_SIZE_BYTES + +/* + * In Elliptic curve cryptography Public Keys are Points on chosen + * Elliptic curve P(x,y). + * Public Key is the x, y coordinates concatenated + * Ecies_eph_pubk and OEM_ECDSA_PUBK are each 64 bytes = 512 bits key + * sizes. + */ +#define BOOT_API_SSP_PUBK_KEY_SIZE_BYTES \ + BOOT_API_SSP_EC_COORDINATE_SIZE_BYTES + +/* + * Size in bytes of ECIES_Chip_pubk obtained from bootROM at end of SSP + * phase 1 : Chip public key calculation. + */ +#define BOOT_API_SSP_ECIES_CHIP_PUBK_SIZE_BYTES \ + BOOT_API_SSP_PUBK_KEY_SIZE_BYTES + +/* AES-GCM authentication tag size is 16 bytes = 128 bits */ +#define BOOT_API_SSP_AES_GCM_AUTH_TAG_SIZE_BYTES 16 + +/* AES-GCM Symmetric Key size is 16 bytes = 128 bits */ +#define BOOT_API_SSP_AES_GCM_KEY_SIZE_BYTES 16 + +/* AES-GCM Initialization Vector (IV) size is of 16 bytes = 128 bits */ +#define BOOT_API_SSP_AES_GCM_IV_SIZE_BYTES 16 + +/* + * 88 bytes (license_type, live_session_id, license_version, + * fsbl_min_version, rfu[8], eph_ecies_pubk[]) + */ +#define BOOT_API_SSP_AES_GCM_LICENSE_AAD_NB_BYTES_FROM_LICENSE 88 + +/* + * 32 bytes AAD License Secret from 2nd round KDF-SHA-256 + * from ECDH Shared Secret hence KDF[32..63] aka "Authorization Token" + */ +#define BOOT_API_SSP_AES_GCM_LICENSE_AAD_NB_BYTES_FROM_KDF 32 + +/* + * Total License AAD size = 88 + 32 = 120 bytes + */ +#define BOOT_API_SSP_AES_GCM_LICENSE_AAD_SIZE_BYTES \ + (BOOT_API_SSP_AES_GCM_LICENSE_AAD_NB_BYTES_FROM_LICENSE + \ + BOOT_API_SSP_AES_GCM_LICENSE_AAD_NB_BYTES_FROM_KDF) + +/* + * AAD for Payload size : composed of : + * payload_magic, payload_protocol_version, oem_ecdsa_pubk[], oem_secret_size + * = 4 + 4 + 64 + 4 = 76 bytes AAD for Payload + */ +#define BOOT_API_SSP_AES_GCM_PAYLOAD_AAD_SIZE_BYTES 76 + +/* + * OEM Secrets max size in bytes : + * [OTP[95:59] + OTP_CFG56 (RMA Unlock and Relock passwords)] x 4 bytes + * by OTP word = 152 bytes + */ +#define BOOT_API_SSP_OEM_SECRETS_MAX_SIZE_BYTES 152 + +/* + * Possible values of boot context field 'ssp_status' + * as can be read by FSBL-SSP + */ +#define BOOT_API_CTX_SSP_STATUS_NO_SSP 0 +#define BOOT_API_CTX_SSP_STATUS_CHIP_PUBK_CALC_FINISHED 1 +#define BOOT_API_CTX_SSP_STATUS_OEM_SEC_PROV_FINISHED 2 +#define BOOT_API_CTX_SSP_STATUS_OEM_SEC_PROV_FORBIDDEN 3 + +/* + * Reserved size for future use + */ +#define BOOT_API_SSP_HSM_OEM_RFU_SIZE 8 + /* * Exported types */ +/* + * SSP related definitions + */ +/* + * SSP BLOB License structure : Binary Large OBject License structure + * Should be written by FSBL-SSP to provide bootROM with SSP OEM Secret + * provisioning. + * License information data, the structure is read by bootROM. + */ +typedef struct { + /* + * License Type provided by HSM-OEM tool + * should match Normal SSP License of Live SSP License. + */ + uint32_t license_type; + + /* Live Session ID provided by HSM-OEM tool */ + uint32_t live_session_id; + + /* + * Version of the License Protocol (Structure) + * should be incremented each time a new. + */ + uint32_t license_version; + + /* + * Minimum FSBL version to be compared + * with FSBL Header field 'imageVersion'. + */ + uint32_t fsbl_min_version; + + /* RFU provided by HSM-OEM tool */ + uint8_t rfu[BOOT_API_SSP_HSM_OEM_RFU_SIZE]; + + /* + * Ephemeral ECIES Public Key from HSM-OEM + * 64 bytes = 512 bits. + */ + uint8_t eph_ecies_pubk[BOOT_API_SSP_PUBK_KEY_SIZE_BYTES]; + + /* + * Encrypted (IV,Key) : with Shared Secret based on + * 'Ephemeral ECIES Key pair' and 'ECIES Chip Key pair'. + */ + uint8_t encrypted_iv_and_key + [BOOT_API_SSP_ENCRYPTED_IV_AND_KEY_SIZE_BYTES]; + + /* + * AUTH_TAG AES-GCM from encryption of (IV, Key) + * in HSM-OEM with License AAD scheme + * License Tag is 16 bytes = 128 bits. + */ + uint8_t license_tag[BOOT_API_SSP_AES_GCM_AUTH_TAG_SIZE_BYTES]; + +} boot_api_ssp_blob_license_t; + +/* + * SSP BLOB Payload structure : Binary Large OBject Payload Structure + * Should be written by FSBL-SSP to provide bootROM with SSP OEM Secret + * provisioning input data, the structure is read by bootROM + * The BLOB Payload size is fixed to a max size of 244 bytes based + * on a max number of bytes of OEM secret derived from OTP upper free + * area in STM32MP15xx cut 2.0.In this table oem_encrypted_secrets[] + * of max size only the first 'p_blob_payload->oem_secret_size_bytes' + * bytes will be considered and used by bootROM. + */ +typedef struct { + /* + * BLOB Payload Magic : for memory validity check of BLOB Payload + * to match against BOOT_API_SSP_BLOB_PAYLOAD_MAGIC_SSP by bootROM. + */ + uint32_t payload_magic; + + /* + * SSP Payload protocol version : on 32 bits + * to be checked by bootROM for equality with + * BOOT_API_SSP_PAYLOAD_PROTOCOL_VERSION_TO_MATCH + * ie : 0x00000001 : version 1 of SSP Payload + */ + uint32_t payload_protocol_version; + + /* + * OEM_ECDSA_PUBK Public Key defined by OEM + * 64 bytes = 512 bits + */ + uint8_t oem_ecdsa_pubk[BOOT_API_SSP_PUBK_KEY_SIZE_BYTES]; + + /* + * Size of Table of OEM Secrets encrypted with AES-GCM (Key,IV) from + * License field 'encrypted_iv_and_key[]' + * should be <= BOOT_API_SSP_OEM_SECRETS_MAX_SIZE_BYTES: + * is verified by bootROM. + */ + uint32_t oem_secret_size_bytes; + + /* + * AUTH_TAG AES-GCM computed by HSM-OEM when encrypting OEM Secrets with + * (Key,IV) using special AAD scheme for Payload. + * 16 bytes = 128 bits + */ + uint8_t payload_tag[BOOT_API_SSP_AES_GCM_AUTH_TAG_SIZE_BYTES]; + + /* + * OEM Secrets encrypted with AES-GCM (IV, Key) from + * License field 'encrypted_iv_and_key[]'. + * The payload size is 'oem_secret_size_bytes' + * should be <= BOOT_API_SSP_OEM_SECRETS_MAX_SIZE_BYTES = + * 152 bytes : OEM Secrets max size in bytes : + * [OTP_CFG56, OTP_CFG59, OTP_CFG60..95] x 4 bytes by OTP word. + */ + uint8_t oem_encrypted_secrets[BOOT_API_SSP_OEM_SECRETS_MAX_SIZE_BYTES]; + +} boot_api_ssp_blob_payload_t; +#endif + /* SSP Configuration structure */ typedef struct { /* SSP Command*/ uint32_t ssp_cmd; +#if STM32MP_SSP + /* ECIES chip public key */ + uint8_t *p_chip_pubk; + /* Blob License Address */ + boot_api_ssp_blob_license_t *p_blob_license; + /* Blob Payload Address */ + boot_api_ssp_blob_payload_t *p_blob_payload; + /* Secrets Decrypted Address */ + uint8_t *p_ssp_oem_secrets_decrypted; + /* Reserved for Future Use (RFU) */ + uint32_t padding_rfu; +#else uint8_t reserved[20]; +#endif } boot_api_ssp_config_t; /* diff --git a/plat/st/stm32mp1/platform.mk b/plat/st/stm32mp1/platform.mk index 3067420d31fb40c5145c328467c3e891247b37be..fba18b4de8dc48a88107cdabb0a7a724e66cb68a 100644 --- a/plat/st/stm32mp1/platform.mk +++ b/plat/st/stm32mp1/platform.mk @@ -38,6 +38,9 @@ STM32MP_DDR_DUAL_AXI_PORT:= 1 STM32_HEADER_VERSION_MAJOR:= 1 STM32_HEADER_VERSION_MINOR:= 0 +# STM32 Secure Secret Provisioning mode (SSP) +STM32MP_SSP ?= 0 + ifeq ($(AARCH32_SP),sp_min) # Disable Neon support: sp_min runtime may conflict with non-secure world TF_CFLAGS += -mfloat-abi=soft @@ -157,6 +160,7 @@ $(eval $(call assert_booleans,\ STM32MP_USB_PROGRAMMER \ STM32MP_USE_STM32IMAGE \ STM32MP_DDR_DUAL_AXI_PORT \ + STM32MP_SSP \ ))) $(eval $(call assert_numerics,\ @@ -181,6 +185,7 @@ $(eval $(call add_defines,\ STM32_TF_VERSION \ STM32MP_USE_STM32IMAGE \ STM32MP_DDR_DUAL_AXI_PORT \ + STM32MP_SSP \ ))) # Include paths and source files @@ -347,6 +352,10 @@ BL2_SOURCES += lib/optee/optee_utils.c BL2_SOURCES += plat/st/stm32mp1/stm32mp1_critic_power.c BL2_SOURCES += plat/st/stm32mp1/stm32mp1_critic_power_wrapper.S +ifeq ($(STM32MP_SSP),1) +include plat/st/stm32mp1/stm32mp1_ssp.mk +endif + # Compilation rules .PHONY: check_dtc_version stm32image clean_stm32image check_boot_device .SUFFIXES: diff --git a/plat/st/stm32mp1/services/bsec_svc.c b/plat/st/stm32mp1/services/bsec_svc.c index e75571f98afcb1dabe971f16e743502cab42b54c..273c1cf9d8ece52d705ba3a2380f72f90aa71f32 100644 --- a/plat/st/stm32mp1/services/bsec_svc.c +++ b/plat/st/stm32mp1/services/bsec_svc.c @@ -27,10 +27,6 @@ #include "bsec_svc.h" -#define SSP_OTP_REQ BIT(BOOT_API_OTP_SSP_REQ_BIT_POS) -#define SSP_OTP_SUCCESS BIT(BOOT_API_OTP_SSP_SUCCESS_BIT_POS) -#define SSP_OTP_MASK (SSP_OTP_REQ | SSP_OTP_SUCCESS) - enum bsec_ssp_status { BSEC_NO_SSP = 0, BSEC_SSP_SET, diff --git a/plat/st/stm32mp1/stm32mp1_def.h b/plat/st/stm32mp1/stm32mp1_def.h index fc5c1183c9b9256092263c3dd81aea7a5df2a87d..b49a0f5b3e0c08ddaf897af5d172e1c74ce90063 100644 --- a/plat/st/stm32mp1/stm32mp1_def.h +++ b/plat/st/stm32mp1/stm32mp1_def.h @@ -130,6 +130,7 @@ enum ddr_type { (STM32MP_PARAM_LOAD_SIZE + \ STM32MP_HEADER_SIZE)) +#if !STM32MP_SSP #if STM32MP_USE_STM32IMAGE #define STM32MP_BL2_SIZE U(0x0001C000) /* 112 KB for BL2 */ @@ -173,6 +174,7 @@ enum ddr_type { #define STM32MP_BL32_SIZE U(0x0001A000) /* 100 KB for BL32 */ #endif #endif /* STM32MP_USE_STM32IMAGE */ +#endif /* STM32MP_SSP */ #if defined(IMAGE_BL2) #define STM32MP_DEFAULT_XLAT U(2) /* 8 KB for mapping */ @@ -212,6 +214,29 @@ enum ddr_type { #endif #endif +#if STM32MP_SSP +#define STM32MP_BL2_DTB_SIZE U(0x00004000) /* 16 KB for DTB */ + +#define STM32MP_BL2_DTB_BASE (STM32MP_SYSRAM_BASE + \ + STM32MP_HEADER_RESERVED_SIZE) + +#define STM32MP_BL2_RO_SIZE U(0x0000C000) /* 48 Ko for BL2 */ + +#define STM32MP_BL2_RO_BASE STM32MP_BL2_DTB_BASE + \ + STM32MP_BL2_DTB_SIZE + +#define STM32MP_BL2_RW_BASE (STM32MP_BL2_RO_BASE + \ + STM32MP_BL2_RO_SIZE) + +#define STM32MP_BL2_RW_SIZE (STM32MP_SYSRAM_BASE + \ + STM32MP_SYSRAM_SIZE - \ + STM32MP_BL2_RW_BASE) + +#define STM32MP_DTB_SIZE STM32MP_BL2_DTB_SIZE +#define STM32MP_DTB_BASE STM32MP_BL2_DTB_BASE + +#define TF_A_MAPPING_START STM32MP_BL2_DTB_BASE +#else #if STM32MP_USE_STM32IMAGE /* DTB initialization value */ #define STM32MP_DTB_SIZE U(0x00006000) /* 24 KB for DTB */ @@ -240,6 +265,7 @@ enum ddr_type { #endif #define TF_A_MAPPING_START STM32MP_BL2_DTB_BASE #endif /* STM32MP_USE_STM32IMAGE */ +#endif /* STM32MP_SSP */ #define STM32MP_FW_CONFIG_BASE (STM32MP_SYSRAM_BASE + \ STM32MP_SYSRAM_SIZE - \ @@ -429,11 +455,35 @@ enum ddr_type { #define UID_OTP "uid_otp" #define PKH_OTP "pkh_otp" #define BOARD_ID_OTP "board_id" +#define CFG2_OTP "cfg2_otp" +#define SSP_OTP "ssp_otp" +#define CHIP_CERTIFICATE_OTP "chip_otp" +#define RMA_OTP "rma_otp" /* OTP mask */ /* CFG0 */ #define CFG0_CLOSED_DEVICE BIT(6) +/* CFG2 */ +#define OTP_CFG2_SEC_COUNTER_MASK GENMASK_32(27, 20) +#define OTP_CFG2_SEC_COUNTER_SHIFT U(20) +#define OTP_CFG2_ST_KEY_MASK GENMASK_32(31, 28) +#define OTP_CFG2_ST_KEY_SHIFT U(28) + +/* SSP */ +#define SSP_OTP_REQ BIT(BOOT_API_OTP_SSP_REQ_BIT_POS) +#define SSP_OTP_SUCCESS BIT(BOOT_API_OTP_SSP_SUCCESS_BIT_POS) +#define SSP_OTP_MASK GENMASK_32(BOOT_API_OTP_SSP_SUCCESS_BIT_POS, \ + BOOT_API_OTP_SSP_REQ_BIT_POS) +#define SSP_OTP_SECRET_BASE U(59) +#define SSP_OTP_SECRET_END U(95) + +/* CHIP_CERT */ +#define CHIP_CERTIFICATE_MAX_SIZE U(0x40) + +/* RMA */ +#define RMA_OTP_MASK GENMASK_32(29, 0) + /* PART NUMBER */ #define PART_NUMBER_OTP_PART_MASK GENMASK_32(7, 0) #define PART_NUMBER_OTP_PART_SHIFT 0 diff --git a/plat/st/stm32mp1/stm32mp1_ssp.c b/plat/st/stm32mp1/stm32mp1_ssp.c new file mode 100644 index 0000000000000000000000000000000000000000..bcbf374782a75a63ee57114e4a2cc0d84fced3e2 --- /dev/null +++ b/plat/st/stm32mp1/stm32mp1_ssp.c @@ -0,0 +1,1039 @@ +/* + * Copyright (c) 2017-2020, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <endian.h> +#include <errno.h> +#include <limits.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include <platform_def.h> + +#include <arch_helpers.h> +#include <drivers/clk.h> +#include <drivers/delay_timer.h> +#include <drivers/generic_delay_timer.h> +#include <drivers/st/bsec.h> +#include <drivers/st/stm32_console.h> +#include <drivers/st/stm32_hash.h> +#include <drivers/st/stm32_iwdg.h> +#include <drivers/st/stm32_uart.h> +#include <drivers/st/stm32mp_pmic.h> +#include <drivers/st/stm32mp_reset.h> +#include <drivers/st/stpmic1.h> +#include <lib/mmio.h> +#include <lib/usb/usb_core.h> +#include <lib/usb/usb_st_dfu.h> +#include <lib/utils.h> +#include <lib/utils_def.h> +#include <lib/xlat_tables/xlat_tables_v2.h> +#include <plat/common/platform.h> + +#include <stm32cubeprogrammer.h> + +#define CERT_CHIP_ID_LEN U(3) +#define CERT_SECURITY_COUNTER_LEN U(2) +#define CERT_SECURITY_COUNTER_SHIFT CERT_CHIP_ID_LEN +#define CERT_RFU_LEN U(1) +#define CERT_RFU_SHIFT (CERT_SECURITY_COUNTER_LEN + \ + CERT_SECURITY_COUNTER_SHIFT) +#define CERT_PRODUCT_KEY_LEN U(2) +#define CERT_PRODUCT_KEY_SHIFT (CERT_RFU_LEN + CERT_RFU_SHIFT) +#define CERT_PRODUCT_ID_SIZE (CERT_PRODUCT_KEY_LEN + \ + CERT_PRODUCT_KEY_SHIFT) +#define CERT_SIGNATURE_LEN CHIP_CERTIFICATE_MAX_SIZE +#define CERT_SIGNATURE_SHIFT (CERT_PRODUCT_ID_SIZE + \ + BOOT_API_SSP_PUBK_KEY_SIZE_BYTES) +#define CERTIFICATE_SIZE (CERT_PRODUCT_ID_SIZE + \ + BOOT_API_SSP_PUBK_KEY_SIZE_BYTES + \ + CERT_SIGNATURE_LEN) /* 136 bytes */ +#define RESET_TIMEOUT_US_1MS U(1000) +#define BLOB_FILE_MAX_ADDR BL2_RW_LIMIT + +/* Local status for SSP processing sequences */ +typedef enum { + SSP_NONE, + SSP_GET_CERT, + SSP_FLASH_OEM, + SSP_DONE, + SSP_ERROR +} ssp_result_e; + +struct otp_val { + uint32_t idx; + uint32_t nb; +}; + +static struct otp_val otp_ssp; +static struct otp_val otp_rma; +static struct otp_val otp_pubkey; + +#if DEBUG +static console_t console; +#endif + +/* Platform empty definition required */ +void bl2_platform_setup(void) {} +struct bl_params *plat_get_next_bl_params(void) { return NULL; } +void plat_flush_next_bl_params(void) {} +struct bl_load_info *plat_get_bl_image_load_info(void) { return NULL; } +int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle, + uintptr_t *image_spec) +{ + return 0; +} + +/* + * Initialized OTP index from device tree. + */ +static int initialize_otp(void) +{ + uint32_t len; + + /* OTP SSP */ + if (stm32_get_otp_index(SSP_OTP, &otp_ssp.idx, NULL) != 0) { + VERBOSE("%s: get index error\n", __func__); + return -EINVAL; + } + + /* OTP public key */ + if (stm32_get_otp_index(PKH_OTP, &otp_pubkey.idx, &len) != 0) { + VERBOSE("%s: get index error\n", __func__); + return -EINVAL; + } + + if (len != (CHAR_BIT * BOOT_API_SHA256_DIGEST_SIZE_IN_BYTES)) { + VERBOSE("%s: length Error\n", __func__); + return -EINVAL; + } + + otp_pubkey.nb = len / __WORD_BIT; + + /* OTP RMA */ + if (stm32_get_otp_index(RMA_OTP, &otp_rma.idx, NULL) != 0) { + VERBOSE("%s: get index error\n", __func__); + return -EINVAL; + } + + return 0; +} + +/* + * Compute HASH from public key and burn it in OTP. + */ +static int ssp_pub_key_prog(boot_api_context_t *boot_context) +{ + uint8_t key_hash[BOOT_API_SHA256_DIGEST_SIZE_IN_BYTES] __aligned(4); + uint8_t *pubk = (uint8_t *) + boot_context->p_ssp_config->p_blob_payload->oem_ecdsa_pubk; + uint32_t *value = (uint32_t *)key_hash; + uint32_t i; + + if (stm32_hash_register() != 0) { + return -EINVAL; + } + + stm32_hash_init(HASH_SHA256); + + if (stm32_hash_final_update(pubk, BOOT_API_SSP_PUBK_KEY_SIZE_BYTES, + key_hash) != 0) { + ERROR("Hash of payload failed\n"); + return -EINVAL; + } + + for (i = otp_pubkey.idx; i < (otp_pubkey.idx + otp_pubkey.nb); i++) { + if (bsec_program_otp(bswap32(*value), i) != BSEC_OK) { + return -EINVAL; + } + + value++; + if (bsec_permanent_lock_otp(i) != BSEC_OK) { + ERROR("Error locking OTP %i\n", i); + panic(); + } + } + + return 0; +} + +/* + * Burn OTP to close device. + */ +static int ssp_close_device(void) +{ + uint32_t otp; + uint32_t value; + + if (stm32_get_otp_index(CFG0_OTP, &otp, NULL) != 0) { + return -EINVAL; + } + + if (bsec_read_otp(&value, otp) != BSEC_OK) { + return -EINVAL; + } + + if ((value & CFG0_CLOSED_DEVICE) != 0U) { + ERROR("Device already closed\n"); + return -EINVAL; + } + + value |= CFG0_CLOSED_DEVICE; + if (bsec_program_otp(value, otp) != BSEC_OK) { + return -EINVAL; + } + + return 0; +} + +/* + * OTP initial check to detect previous values. + */ +static int ssp_secrets_check(boot_api_context_t *boot_ctx) +{ + uint32_t i; + uint32_t check_val; + uint32_t otp_bytes = boot_ctx->p_ssp_config->p_blob_payload->oem_secret_size_bytes; + uint32_t otp_decrypted; + + if (otp_bytes == 0U) { + return -EINVAL; + } + + for (i = otp_pubkey.idx; i < (otp_pubkey.idx + otp_pubkey.nb); i++) { + if (stm32_get_otp_value_from_idx(i, &check_val) != 0) { + return -EINVAL; + } + + if (check_val != 0U) { + ERROR("OTP %u value already programmed\n", i); + return -EINVAL; + } + } + + otp_decrypted = round_up(otp_bytes, sizeof(uint32_t)) / sizeof(uint32_t); + + /* OTP decrypted include RMA password */ + if (otp_decrypted > (2U + SSP_OTP_SECRET_END - SSP_OTP_SECRET_BASE)) { + return -EINVAL; + } + + /* Check RMA password */ + if (stm32_get_otp_value_from_idx(otp_rma.idx, &check_val) != 0) { + return -EINVAL; + } + + if (check_val != 0U) { + ERROR("OTP %s value already programmed\n", RMA_OTP); + return -EINVAL; + } + + /* Check all OTP available */ + for (i = SSP_OTP_SECRET_BASE; i < SSP_OTP_SECRET_BASE + otp_decrypted - 1U; i++) { + if (stm32_get_otp_value_from_idx(i, &check_val) != 0) { + return -EINVAL; + } + + if (check_val != 0U) { + ERROR("OTP %u value already programmed\n", i); + return -EINVAL; + } + } + + return 0; +} + +/* + * Burn OTP with the decrypted secret received. + */ +static int ssp_secrets_flash(boot_api_context_t *boot_ctx) +{ + uint32_t i; + uint32_t *val; + uint32_t otp_bytes = + boot_ctx->p_ssp_config->p_blob_payload->oem_secret_size_bytes; + uint32_t otp_decrypted; + uint32_t otp_mask = 0U; + + if (otp_bytes == 0U) { + return -EINVAL; + } + + if (otp_bytes % sizeof(uint32_t) != 0U) { + otp_mask = GENMASK_32(((otp_bytes % sizeof(uint32_t)) * + sizeof(uint32_t)) - 1, 0); + } + + val = (uint32_t *)boot_ctx->p_ssp_config->p_ssp_oem_secrets_decrypted; + + otp_decrypted = round_up(otp_bytes, sizeof(uint32_t)) / sizeof(uint32_t); + + /* Burn RMA password */ + if (bsec_program_otp((*val & RMA_OTP_MASK), otp_rma.idx) != BSEC_OK) { + WARN("RMA programing failed\n"); + return -EINVAL; + } + + val++; + otp_decrypted--; + for (i = SSP_OTP_SECRET_BASE; i < (SSP_OTP_SECRET_BASE + otp_decrypted - 1U); i++) { + if (*val == 0U) { + val++; + continue; + } + + if (bsec_program_otp(*val, i) != BSEC_OK) { + WARN("Error writing OTP %i\n", i); + return -EINVAL; + } + + if (bsec_permanent_lock_otp(i) != BSEC_OK) { + WARN("Error locking OTP %i\n", i); + return -EINVAL; + } + + val++; + } + + if (*val == 0U) { + return 0; + } + + /* Mask the last OTP value if needed */ + if (otp_mask != 0U) { + *val &= otp_mask; + } + + if (bsec_program_otp(*val, i) != BSEC_OK) { + WARN("Error writing OTP %i\n", i); + return -EINVAL; + } + + if (bsec_permanent_lock_otp(i) != BSEC_OK) { + WARN("Error locking OTP %i\n", i); + return -EINVAL; + } + + return 0; +} + +/* + * Finish SSP processing by fusing OTP SSP success. + */ +static int ssp_finish_process(void) +{ + uint32_t val; + + if (stm32_get_otp_value_from_idx(otp_ssp.idx, &val) != 0) { + return -EINVAL; + } + + if ((val & SSP_OTP_SUCCESS) != 0U) { + WARN("Error while configuring OTP\n"); + return -EINVAL; + } + + val |= SSP_OTP_SUCCESS; + if (bsec_program_otp(val, otp_ssp.idx) != BSEC_OK) { + return -EINVAL; + } + + VERBOSE("Write OTP Success\n"); + + return 0; +} + +/* + * Transform integer to string. + */ +static void itoa(uint32_t num, char *str, int nb) +{ + if (num == 0U) { + while (nb-- != 0U) { + str[nb] = '0'; + } + + return; + } + + while (num != 0U) { + int rem = num % 16; + + str[--nb] = (rem > 9) ? (rem - 10) + 'A' : rem + '0'; + num /= 16; + } + + while (nb != 0) { + str[--nb] = '0'; + } +} + +/* + * Return chip product ID. + */ +static int ssp_get_product_id(char *msg) +{ + uint32_t otp; + uint32_t otp_idx; + uint32_t chip_id; + + if (stm32_get_otp_index(CFG2_OTP, &otp_idx, NULL) != 0) { + VERBOSE("Get index error\n"); + return -EINVAL; + } + + if (stm32_get_otp_value_from_idx(otp_idx, &otp) != 0) { + return -EINVAL; + } + + if (stm32mp1_dbgmcu_get_chip_dev_id(&chip_id) < 0) { + return -EINVAL; + } + + itoa(chip_id, msg, CERT_CHIP_ID_LEN); + itoa((otp & OTP_CFG2_SEC_COUNTER_MASK) >> OTP_CFG2_SEC_COUNTER_SHIFT, + msg + CERT_SECURITY_COUNTER_SHIFT, + CERT_SECURITY_COUNTER_LEN); + + itoa(0, msg + CERT_RFU_SHIFT, CERT_RFU_LEN); + itoa((otp & OTP_CFG2_ST_KEY_MASK) >> OTP_CFG2_ST_KEY_SHIFT, + msg + CERT_PRODUCT_KEY_SHIFT, + CERT_PRODUCT_KEY_LEN); + + return 0; +} + +/* + * Construct SSP certificate. + */ +static int prepare_certificate(uint8_t *cert, const uint8_t *pubkey) +{ + uint32_t i; + uint32_t j; + uint32_t otp; + uint32_t otp_idx; + uint32_t otp_len; + + /* Prepare the ROM Security constant */ + if (ssp_get_product_id((char *)cert) != 0) { + return -EINVAL; + } + + /* Prepare public key and certificate for flashloader */ + /* Read Public Key from boot_context */ + memcpy(cert + CERT_PRODUCT_ID_SIZE, pubkey, BOOT_API_SSP_PUBK_KEY_SIZE_BYTES); + + if (stm32_get_otp_index(CHIP_CERTIFICATE_OTP, + &otp_idx, &otp_len) != 0) { + VERBOSE("Get index error\n"); + return -EINVAL; + } + + if (otp_len != (CHAR_BIT * CHIP_CERTIFICATE_MAX_SIZE)) { + VERBOSE("Length error\n"); + return -EINVAL; + } + + otp_len /= __WORD_BIT; + + /* Read Certificat from OTP */ + for (i = otp_idx, j = 0U; i < (otp_idx + otp_len); i++, j++) { + uint32_t otp_s; + + if (stm32_get_otp_value_from_idx(i, &otp) != 0) { + return -EINVAL; + } + + otp_s = bswap32(otp); + memcpy(&cert[CERT_SIGNATURE_SHIFT + (sizeof(uint32_t) * j)], + &otp_s, sizeof(uint32_t)); + } + + return 0; +} + +/* + * Clean external data and bootrom context secret values. + */ +static void ssp_cleanup(boot_api_context_t *boot_context) +{ + boot_api_ssp_config_t *ssp_config = boot_context->p_ssp_config; + + /* Cleanup boot_context */ + if (ssp_config->p_ssp_oem_secrets_decrypted != NULL) { + zeromem(ssp_config->p_ssp_oem_secrets_decrypted, + BOOT_API_SSP_OEM_SECRETS_MAX_SIZE_BYTES); +#ifndef DCACHE_OFF + flush_dcache_range((uintptr_t)ssp_config->p_ssp_oem_secrets_decrypted, + BOOT_API_SSP_OEM_SECRETS_MAX_SIZE_BYTES); +#endif + ssp_config->p_ssp_oem_secrets_decrypted = NULL; + } + + if (ssp_config->p_chip_pubk != NULL) { + zeromem(ssp_config->p_chip_pubk, + BOOT_API_SSP_PUBK_KEY_SIZE_BYTES); +#ifndef DCACHE_OFF + flush_dcache_range((uintptr_t)ssp_config->p_chip_pubk, + BOOT_API_SSP_PUBK_KEY_SIZE_BYTES); +#endif + ssp_config->p_chip_pubk = NULL; + } + + if (ssp_config->p_blob_license != NULL) { + zeromem(ssp_config->p_blob_license, + sizeof(boot_api_ssp_blob_license_t)); +#ifndef DCACHE_OFF + flush_dcache_range((uintptr_t)ssp_config->p_blob_license, + sizeof(boot_api_ssp_blob_license_t)); +#endif + ssp_config->p_blob_license = NULL; + } + + if (ssp_config->p_blob_payload != NULL) { + zeromem(ssp_config->p_blob_payload, + sizeof(boot_api_ssp_blob_payload_t)); +#ifndef DCACHE_OFF + flush_dcache_range((uintptr_t)ssp_config->p_blob_payload, + sizeof(boot_api_ssp_blob_payload_t)); +#endif + ssp_config->p_blob_payload = NULL; + } + + ssp_config->ssp_cmd = 0U; + +#ifndef DCACHE_OFF + flush_dcache_range((uintptr_t)boot_context->p_ssp_config, + sizeof(boot_api_ssp_config_t)); +#endif +} + +/* + * Send certificate to the programmer and retrieve the associated + * encrypted file. + */ +static int ssp_download_phase(boot_api_context_t *boot_ctx) +{ + uint8_t *blob_file; +#if STM32MP_USB_PROGRAMMER + usb_handle_t *pdev; +#endif +#if STM32MP_UART_PROGRAMMER + uintptr_t uart_base; +#endif + int result = 0; + uint8_t cert[CERTIFICATE_SIZE]; + + blob_file = (uint8_t *)page_align(BLOB_FILE_MAX_ADDR - + sizeof(boot_api_ssp_blob_license_t) - + sizeof(boot_api_ssp_blob_payload_t), + DOWN); + + if (prepare_certificate(cert, boot_ctx->p_ssp_config->p_chip_pubk) != 0) { + return -EINVAL; + } + + switch (boot_ctx->boot_interface_selected) { +#if STM32MP_USB_PROGRAMMER + case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB: + + /* init USB on platform */ + pdev = usb_dfu_plat_init(); + + result = stm32cubeprog_usb_ssp(pdev, (uintptr_t)cert, + sizeof(cert), (uintptr_t)blob_file, + sizeof(boot_api_ssp_blob_license_t) + + sizeof(boot_api_ssp_blob_payload_t)); + if (result != 0) { + return -EINVAL; + } + + break; +#endif + +#if STM32MP_UART_PROGRAMMER + case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART: + uart_base = get_uart_address(boot_ctx->boot_interface_instance); + + if (uart_base == 0U) { + return -EINVAL; + } + + result = stm32cubeprog_uart_ssp(uart_base, (uintptr_t)cert, sizeof(cert), + (uintptr_t)blob_file, + sizeof(boot_api_ssp_blob_license_t) + + sizeof(boot_api_ssp_blob_payload_t)); + if (result != 0) { + return -EINVAL; + } + break; +#endif + default: + return -EINVAL; + } + + boot_ctx->p_ssp_config->p_blob_license = + (boot_api_ssp_blob_license_t *)blob_file; + + /* Payload is concatened with license file */ + boot_ctx->p_ssp_config->p_blob_payload = + (boot_api_ssp_blob_payload_t *)(blob_file + + sizeof(boot_api_ssp_blob_license_t)); + +#ifndef DCACHE_OFF + flush_dcache_range((uintptr_t)blob_file, + sizeof(boot_api_ssp_blob_license_t) + + sizeof(boot_api_ssp_blob_payload_t)); +#endif + + /* Set return address for decrypted_secrets */ + boot_ctx->p_ssp_config->p_ssp_oem_secrets_decrypted = + boot_ctx->p_ssp_config->p_blob_payload->oem_encrypted_secrets; + + return result; +} + +/* + * Burn decrypted secrets into OTP, clean memory and close the device. + */ +static int ssp_secret_programming(boot_api_context_t *boot_context) +{ + int result; + + result = ssp_secrets_check(boot_context); + if (result != 0) { + ERROR("SSP ERROR checking OTP\n"); + goto clean; + } + + result = ssp_pub_key_prog(boot_context); + if (result != 0) { + ERROR("SSP ERROR writing HASH key\n"); + goto clean; + } + + result = ssp_close_device(); + if (result != 0) { + ERROR("SSP close device failed\n"); + goto clean; + } + + result = ssp_secrets_flash(boot_context); + if (result != 0) { + ERROR("SSP Secret flash failed\n"); + } + +clean: + ssp_cleanup(boot_context); + + if (result != 0) { + return result; + } + + return ssp_finish_process(); +} + +/* + * Enable the SSP processing. + */ +static int ssp_enable_processing(boot_api_context_t *boot_context) +{ + uint32_t val; + int result; +#if STM32MP_USB_PROGRAMMER + usb_handle_t *pdev; +#endif +#if STM32MP_UART_PROGRAMMER + uintptr_t uart_base; +#endif + + if (stm32_get_otp_value_from_idx(otp_ssp.idx, &val) != 0) { + return -EINVAL; + } + + if (((val & SSP_OTP_MASK) == SSP_OTP_MASK) || + ((val & SSP_OTP_MASK) == SSP_OTP_SUCCESS)) { + return -EINVAL; + } + + if ((val & SSP_OTP_MASK) == 0U) { + if (bsec_program_otp(SSP_OTP_REQ, otp_ssp.idx) != BSEC_OK) { + return -EINVAL; + } + } + + switch (boot_context->boot_interface_selected) { +#if STM32MP_USB_PROGRAMMER + case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB: + /* init USB on platform */ + pdev = usb_dfu_plat_init(); + + result = stm32cubeprog_usb_ssp(pdev, (uintptr_t)-1, 0, + (uintptr_t)NULL, 0); + if (result != 0) { + return -EINVAL; + } + + break; +#endif + +#if STM32MP_UART_PROGRAMMER + case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART: + uart_base = get_uart_address(boot_context->boot_interface_instance); + if (uart_base == 0U) { + return -EINVAL; + } + + result = stm32cubeprog_uart_ssp(uart_base, (uintptr_t)-1, 0, + (uintptr_t)NULL, 0); + if (result != 0) { + return -EINVAL; + } + break; +#endif + default: + return -EINVAL; + } + + boot_context->p_ssp_config->ssp_cmd = + BOOT_API_CTX_SSP_CMD_CALC_CHIP_PUBK; + + return 0; +} + +/* + * Retrieve the current status of the SSP from bootrom context and OTP value. + */ +static ssp_result_e ssp_check_status(boot_api_context_t *boot_context) +{ + uint32_t otp; + + if (initialize_otp() < 0) { + return SSP_ERROR; + } + + if (stm32_get_otp_value_from_idx(otp_ssp.idx, &otp) != 0) { + return SSP_ERROR; + } + + if ((otp & SSP_OTP_REQ) == 0U) { + return SSP_NONE; + } + + if ((otp & SSP_OTP_SUCCESS) != 0U) { + return SSP_DONE; + } + + VERBOSE("Start Get ssp_cmd : %x\n", + boot_context->p_ssp_config->ssp_cmd); + + switch (boot_context->p_ssp_config->ssp_cmd) { + case BOOT_API_CTX_SSP_CMD_CALC_CHIP_PUBK_ACK: + INFO("Detected start SSP Phase 2\n"); + return SSP_GET_CERT; + case BOOT_API_CTX_SSP_CMD_PROV_SECRET_ACK: + INFO("Detected start SSP Phase 3\n"); + return SSP_FLASH_OEM; + default: + return SSP_NONE; + } +} + +/* + * Start the SSP processing. + */ +static void ssp_start(boot_api_context_t *boot_context) +{ + int result; + uint8_t ssp_phase = ssp_check_status(boot_context); + + switch (ssp_phase) { + case SSP_GET_CERT: + result = ssp_download_phase(boot_context); + if (result != 0) { + /* + * Download Phase failed, clean, reset + */ + ssp_cleanup(boot_context); + + ERROR("SSP_Error: Resetting target\n"); + } else { + /* Process completed, go to Phase 3 */ + boot_context->p_ssp_config->ssp_cmd = + BOOT_API_CTX_SSP_CMD_PROV_SECRET; + } + + break; + + case SSP_FLASH_OEM: + result = ssp_secret_programming(boot_context); + if (result != 0) { + ERROR("Error during provisionning\n"); + } else { + NOTICE("Provisioning completed\n"); + } + + break; + + case SSP_ERROR: + /* + * Error during bootrom SSP processing + */ + result = -EINVAL; + ERROR("SSP_Error: Resetting target\n"); + break; + + case SSP_NONE: + default: + result = ssp_enable_processing(boot_context); + if (result != 0) { + ERROR("Start SSP Failed (%i)\n", result); + } + } + + if ((result != 0) || (ssp_phase == SSP_FLASH_OEM)) { + goto out; + } + + /* + * Keep VDDCORE && VDD enabled if pmic used to generate + * the required MPSYSRST. + */ + if (dt_pmic_status() > 0) { + const char *name; + + name = stm32mp_get_cpu_supply_name(); + if (name == NULL) { + goto out; + } + + if (stpmic1_regulator_mask_reset_set(name) != 0) { + WARN("Failed to write %s reset mask\n", name); + } + + name = stm32mp_get_vdd_supply_name(); + if (name == NULL) { + goto out; + } + + if (stpmic1_regulator_mask_reset_set(name) != 0) { + WARN("Failed to write %s reset mask\n", name); + } + } else { + static const char debug_msg[] = { + "SSP next step will be only guarantee if the VDD\n" + "domain is maintained during system reset\n" + }; + + NOTICE("%s", debug_msg); + } + +out: +#ifndef DCACHE_OFF + if (boot_context->p_ssp_config != NULL) { + flush_dcache_range((uintptr_t)boot_context->p_ssp_config, + sizeof(boot_api_ssp_config_t)); + } +#endif + + stm32mp_system_reset(); +} + +#if DEBUG +static void reset_uart(uint32_t reset) +{ + int ret; + + ret = stm32mp_reset_assert(reset, RESET_TIMEOUT_US_1MS); + if (ret != 0) { + panic(); + } + + udelay(2); + + ret = stm32mp_reset_deassert(reset, RESET_TIMEOUT_US_1MS); + if (ret != 0) { + panic(); + } + + mdelay(1); +} +#endif + +void bl2_el3_early_platform_setup(u_register_t arg0, + u_register_t arg1 __unused, + u_register_t arg2 __unused, + u_register_t arg3 __unused) +{ + stm32mp_save_boot_ctx_address(arg0); +} + +void bl2_el3_plat_arch_setup(void) +{ +#if DEBUG + int32_t result; + struct dt_node_info dt_uart_info; + const char *board_model; + uint32_t clk_rate; +#endif + uintptr_t pwr_base; + uintptr_t rcc_base; + + boot_api_context_t *boot_context = + (boot_api_context_t *)stm32mp_get_boot_ctx_address(); + bool serial_uart_interface __unused = + (boot_context->boot_interface_selected == + BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART); + uintptr_t uart_prog_addr __unused; + + if (bsec_probe() != 0) { + panic(); + } + + mmap_add_region(BL_CODE_BASE, BL_CODE_BASE, + BL_CODE_END - BL_CODE_BASE, + MT_CODE | MT_SECURE); + +#if SEPARATE_CODE_AND_RODATA + mmap_add_region(BL_RO_DATA_BASE, BL_RO_DATA_BASE, + BL_RO_DATA_END - BL_RO_DATA_BASE, + MT_RO_DATA | MT_SECURE); +#endif + + /* Prevent corruption of preloaded Device Tree */ + mmap_add_region(DTB_BASE, DTB_BASE, + DTB_LIMIT - DTB_BASE, + MT_RO_DATA | MT_SECURE); + + configure_mmu(); + + if (dt_open_and_check(STM32MP_DTB_BASE) < 0) { + panic(); + } + + pwr_base = stm32mp_pwr_base(); + rcc_base = stm32mp_rcc_base(); + + /* + * Disable the backup domain write protection. + * The protection is enable at each reset by hardware + * and must be disabled by software. + */ + mmio_setbits_32(pwr_base + PWR_CR1, PWR_CR1_DBP); + + while ((mmio_read_32(pwr_base + PWR_CR1) & PWR_CR1_DBP) == 0U) { + ; + } + + /* Reset backup domain on cold boot cases */ + if ((mmio_read_32(rcc_base + RCC_BDCR) & RCC_BDCR_RTCSRC_MASK) == 0U) { + mmio_setbits_32(rcc_base + RCC_BDCR, RCC_BDCR_VSWRST); + + while ((mmio_read_32(rcc_base + RCC_BDCR) & RCC_BDCR_VSWRST) == + 0U) { + ; + } + + mmio_clrbits_32(rcc_base + RCC_BDCR, RCC_BDCR_VSWRST); + } + + + generic_delay_timer_init(); + +#if STM32MP_UART_PROGRAMMER + uart_prog_addr = get_uart_address(boot_context->boot_interface_instance); + + /* Disable programmer UART before changing clock tree */ + if (serial_uart_interface) { + stm32_uart_stop(uart_prog_addr); + } +#endif + + if (stm32mp1_clk_probe() < 0) { + panic(); + } + + if (dt_pmic_status() > 0) { + initialize_pmic(); + } + +#if DEBUG + result = dt_get_stdout_uart_info(&dt_uart_info); + + if ((result <= 0) || + (dt_uart_info.status == DT_DISABLED) || +#if STM32MP_UART_PROGRAMMER + (serial_uart_interface && + (uart_prog_addr == dt_uart_info.base)) || +#endif + (dt_uart_info.clock < 0) || + (dt_uart_info.reset < 0)) { + goto skip_console_init; + } + + if (dt_set_stdout_pinctrl() != 0) { + goto skip_console_init; + } + + if (dt_uart_info.status == DT_DISABLED) { + panic(); + } + + clk_enable((unsigned long)dt_uart_info.clock); + + reset_uart((uint32_t)dt_uart_info.reset); + + clk_rate = clk_get_rate((unsigned long)dt_uart_info.clock); + + if (console_stm32_register(dt_uart_info.base, clk_rate, + STM32MP_UART_BAUDRATE, &console) == 0) { + panic(); + } + + console_set_scope(&console, CONSOLE_FLAG_BOOT | + CONSOLE_FLAG_CRASH | CONSOLE_FLAG_TRANSLATE_CRLF); + + stm32mp_print_cpuinfo(); + + board_model = dt_get_board_model(); + if (board_model != NULL) { + NOTICE("Model: %s\n", board_model); + } + + if ((boot_context->p_ssp_config == NULL) || + (boot_context->p_ssp_config->ssp_cmd != + BOOT_API_CTX_SSP_CMD_PROV_SECRET_ACK)) { + stm32mp_print_cpuinfo(); + if (!stm32mp_is_auth_supported()) { + ERROR("Chip doesn't support SSP\n"); + panic(); + } + } + +skip_console_init: +#endif + if (stm32mp_is_closed_device()) { + /* Closed chip required authentication */ + ERROR("SSP not supported on closed chip\n"); + panic(); + } + + if (stm32_iwdg_init() < 0) { + panic(); + } + + stm32_iwdg_refresh(); + + if (dt_pmic_status() > 0) { + initialize_pmic(); + print_pmic_info_and_debug(); + } + + ssp_start(boot_context); + + /* This must not be reached */ + panic(); +} diff --git a/plat/st/stm32mp1/stm32mp1_ssp.mk b/plat/st/stm32mp1/stm32mp1_ssp.mk new file mode 100644 index 0000000000000000000000000000000000000000..9041e6a0324bd4b14d4a82cc9fedd9d72fe7a510 --- /dev/null +++ b/plat/st/stm32mp1/stm32mp1_ssp.mk @@ -0,0 +1,84 @@ +# +# Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +ST_VERSION := r1.0-ssp +VERSION_STRING := v${VERSION_MAJOR}.${VERSION_MINOR}-${ST_VERSION}(${BUILD_TYPE}):${BUILD_STRING} + +# Required to use BL2_IN_XIP_MEM +BL2_IN_XIP_MEM := 1 + +SEPARATE_CODE_AND_RODATA := 1 + +TRUSTED_BOARD_BOOT := 0 + +# Macros and rules to build TF-A binary +STM32_TF_STM32 := $(addprefix ${BUILD_PLAT}/tf-a-ssp-, $(patsubst %.dtb,%.stm32,$(DTB_FILE_NAME))) + +PLAT_BL_COMMON_SOURCES := common/fdt_wrappers.c \ + plat/st/common/stm32mp_common.c \ + plat/st/stm32mp1/stm32mp1_private.c + +PLAT_BL_COMMON_SOURCES += ${XLAT_TABLES_LIB_SRCS} + +PLAT_BL_COMMON_SOURCES += lib/cpus/aarch32/cortex_a7.S + +PLAT_BL_COMMON_SOURCES += drivers/st/uart/aarch32/stm32_console.S + +PLAT_BL_COMMON_SOURCES += drivers/arm/tzc/tzc400.c \ + drivers/clk/clk.c \ + drivers/delay_timer/delay_timer.c \ + drivers/delay_timer/generic_delay_timer.c \ + drivers/st/bsec/bsec2.c \ + drivers/st/clk/stm32mp_clkfunc.c \ + drivers/st/gpio/stm32_gpio.c \ + drivers/st/i2c/stm32_i2c.c \ + drivers/st/iwdg/stm32_iwdg.c \ + drivers/st/pmic/stm32mp_pmic.c \ + drivers/st/pmic/stpmic1.c \ + drivers/st/regulator/stm32mp_dummy_regulator.c \ + drivers/st/regulator/stm32mp_regulator.c \ + drivers/st/reset/stm32mp1_reset.c \ + plat/st/common/stm32mp_dt.c \ + plat/st/common/stm32mp_shres_helpers.c \ + plat/st/stm32mp1/stm32mp1_dbgmcu.c \ + plat/st/stm32mp1/stm32mp1_helper.S \ + plat/st/stm32mp1/stm32mp1_syscfg.c + +PLAT_BL_COMMON_SOURCES += drivers/st/clk/stm32mp1_clk.c + +BL2_SOURCES := drivers/io/io_storage.c \ + drivers/st/crypto/stm32_hash.c \ + plat/st/stm32mp1/stm32mp1_ssp.c + +ifeq (${STM32MP_UART_PROGRAMMER},1) +BL2_SOURCES += drivers/st/uart/stm32_uart.c \ + plat/st/common/stm32cubeprogrammer_uart.c +endif + +ifeq (${STM32MP_USB_PROGRAMMER},1) +BL2_SOURCES += drivers/st/usb_dwc2/usb_dwc2.c \ + lib/usb/usb_core.c \ + lib/usb/usb_st_dfu.c \ + plat/st/common/stm32cubeprogrammer_usb.c \ + plat/st/stm32mp1/stm32mp1_usb.c +endif + +BL2_DTSI := stm32mp15-ssp-bl2.dtsi + +check_boot_ssp: + @if ([ ${STM32MP_UART_PROGRAMMER} = 1 ] && [ ${STM32MP_USB_PROGRAMMER} = 1 ]) || \ + ([ ${STM32MP_UART_PROGRAMMER} = 0 ] && [ ${STM32MP_USB_PROGRAMMER} = 0 ]); then \ + echo "Error selecting serial boot device"; \ + false; \ + fi + +bl2: check_boot_ssp + +${BUILD_PLAT}/stm32mp1-ssp-%.o: ${BUILD_PLAT}/fdts/%-bl2.dtb plat/st/stm32mp1/stm32mp1.S bl2 + @echo " SSP AS stm32mp1.S" + ${Q}${AS} ${ASFLAGS} ${TF_CFLAGS} \ + -DDTB_BIN_PATH=\"$<\" \ + -c plat/st/stm32mp1/stm32mp1.S -o $@