diff options
Diffstat (limited to '')
57 files changed, 11693 insertions, 0 deletions
diff --git a/plat/st/common/bl2_io_storage.c b/plat/st/common/bl2_io_storage.c new file mode 100644 index 0000000..b271ed6 --- /dev/null +++ b/plat/st/common/bl2_io_storage.c @@ -0,0 +1,731 @@ +/* + * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <string.h> + +#include <arch_helpers.h> +#include <common/debug.h> +#include <common/desc_image_load.h> +#include <drivers/fwu/fwu.h> +#include <drivers/fwu/fwu_metadata.h> +#include <drivers/io/io_block.h> +#include <drivers/io/io_driver.h> +#include <drivers/io/io_encrypted.h> +#include <drivers/io/io_fip.h> +#include <drivers/io/io_memmap.h> +#include <drivers/io/io_mtd.h> +#include <drivers/io/io_storage.h> +#include <drivers/mmc.h> +#include <drivers/partition/efi.h> +#include <drivers/partition/partition.h> +#include <drivers/raw_nand.h> +#include <drivers/spi_nand.h> +#include <drivers/spi_nor.h> +#include <drivers/st/io_mmc.h> +#include <drivers/st/stm32_fmc2_nand.h> +#include <drivers/st/stm32_qspi.h> +#include <drivers/st/stm32_sdmmc2.h> +#include <drivers/usb_device.h> +#include <lib/fconf/fconf.h> +#include <lib/mmio.h> +#include <lib/utils.h> +#include <plat/common/platform.h> +#include <tools_share/firmware_image_package.h> + +#include <platform_def.h> +#include <stm32cubeprogrammer.h> +#include <stm32mp_efi.h> +#include <stm32mp_fconf_getter.h> +#include <stm32mp_io_storage.h> +#include <usb_dfu.h> + +/* IO devices */ +uintptr_t fip_dev_handle; +uintptr_t storage_dev_handle; + +static const io_dev_connector_t *fip_dev_con; + +#ifndef DECRYPTION_SUPPORT_none +static const io_dev_connector_t *enc_dev_con; +uintptr_t enc_dev_handle; +#endif + +#if STM32MP_SDMMC || STM32MP_EMMC +static struct mmc_device_info mmc_info; + +static uint32_t block_buffer[MMC_BLOCK_SIZE] __aligned(MMC_BLOCK_SIZE); + +static io_block_dev_spec_t mmc_block_dev_spec = { + /* It's used as temp buffer in block driver */ + .buffer = { + .offset = (size_t)&block_buffer, + .length = MMC_BLOCK_SIZE, + }, + .ops = { + .read = mmc_read_blocks, + .write = NULL, + }, + .block_size = MMC_BLOCK_SIZE, +}; + +static const io_dev_connector_t *mmc_dev_con; +#endif /* STM32MP_SDMMC || STM32MP_EMMC */ + +#if STM32MP_SPI_NOR +static io_mtd_dev_spec_t spi_nor_dev_spec = { + .ops = { + .init = spi_nor_init, + .read = spi_nor_read, + }, +}; +#endif + +#if STM32MP_RAW_NAND +static io_mtd_dev_spec_t nand_dev_spec = { + .ops = { + .init = nand_raw_init, + .read = nand_read, + .seek = nand_seek_bb + }, +}; + +static const io_dev_connector_t *nand_dev_con; +#endif + +#if STM32MP_SPI_NAND +static io_mtd_dev_spec_t spi_nand_dev_spec = { + .ops = { + .init = spi_nand_init, + .read = nand_read, + .seek = nand_seek_bb + }, +}; +#endif + +#if STM32MP_SPI_NAND || STM32MP_SPI_NOR +static const io_dev_connector_t *spi_dev_con; +#endif + +#if STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER +static const io_dev_connector_t *memmap_dev_con; +#endif + +io_block_spec_t image_block_spec = { + .offset = 0U, + .length = 0U, +}; + +int open_fip(const uintptr_t spec) +{ + return io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID); +} + +#ifndef DECRYPTION_SUPPORT_none +int open_enc_fip(const uintptr_t spec) +{ + int result; + uintptr_t local_image_handle; + + result = io_dev_init(enc_dev_handle, (uintptr_t)ENC_IMAGE_ID); + if (result != 0) { + return result; + } + + result = io_open(enc_dev_handle, spec, &local_image_handle); + if (result != 0) { + return result; + } + + VERBOSE("Using encrypted FIP\n"); + io_close(local_image_handle); + + return 0; +} +#endif + +int open_storage(const uintptr_t spec) +{ + return io_dev_init(storage_dev_handle, 0); +} + +#if STM32MP_EMMC_BOOT +static uint32_t get_boot_part_fip_header(void) +{ + io_block_spec_t emmc_boot_fip_block_spec = { + .offset = STM32MP_EMMC_BOOT_FIP_OFFSET, + .length = MMC_BLOCK_SIZE, /* We are interested only in first 4 bytes */ + }; + uint32_t magic = 0U; + int io_result; + size_t bytes_read; + uintptr_t fip_hdr_handle; + + io_result = io_open(storage_dev_handle, (uintptr_t)&emmc_boot_fip_block_spec, + &fip_hdr_handle); + assert(io_result == 0); + + io_result = io_read(fip_hdr_handle, (uintptr_t)&magic, sizeof(magic), + &bytes_read); + if ((io_result != 0) || (bytes_read != sizeof(magic))) { + panic(); + } + + io_close(fip_hdr_handle); + + VERBOSE("%s: eMMC boot magic at offset 256K: %08x\n", + __func__, magic); + + return magic; +} +#endif + +static void print_boot_device(boot_api_context_t *boot_context) +{ + switch (boot_context->boot_interface_selected) { + case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_SD: + INFO("Using SDMMC\n"); + break; + case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_EMMC: + INFO("Using EMMC\n"); + break; + case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NOR_QSPI: + INFO("Using QSPI NOR\n"); + break; + case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_FMC: + INFO("Using FMC NAND\n"); + break; + case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_QSPI: + INFO("Using SPI NAND\n"); + break; + case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART: + INFO("Using UART\n"); + break; + case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB: + INFO("Using USB\n"); + break; + default: + ERROR("Boot interface %u not found\n", + boot_context->boot_interface_selected); + panic(); + break; + } + + if (boot_context->boot_interface_instance != 0U) { + INFO(" Instance %d\n", boot_context->boot_interface_instance); + } +} + +#if STM32MP_SDMMC || STM32MP_EMMC +static void boot_mmc(enum mmc_device_type mmc_dev_type, + uint16_t boot_interface_instance) +{ + int io_result __unused; + struct stm32_sdmmc2_params params; + + zeromem(¶ms, sizeof(struct stm32_sdmmc2_params)); + + mmc_info.mmc_dev_type = mmc_dev_type; + + switch (boot_interface_instance) { + case 1: + params.reg_base = STM32MP_SDMMC1_BASE; + break; + case 2: + params.reg_base = STM32MP_SDMMC2_BASE; + break; + case 3: + params.reg_base = STM32MP_SDMMC3_BASE; + break; + default: + WARN("SDMMC instance not found, using default\n"); + if (mmc_dev_type == MMC_IS_SD) { + params.reg_base = STM32MP_SDMMC1_BASE; + } else { + params.reg_base = STM32MP_SDMMC2_BASE; + } + break; + } + + if (mmc_dev_type != MMC_IS_EMMC) { + params.flags = MMC_FLAG_SD_CMD6; + } + + params.device_info = &mmc_info; + if (stm32_sdmmc2_mmc_init(¶ms) != 0) { + ERROR("SDMMC%u init failed\n", boot_interface_instance); + panic(); + } + + /* Open MMC as a block device to read FIP */ + io_result = register_io_dev_block(&mmc_dev_con); + if (io_result != 0) { + panic(); + } + + io_result = io_dev_open(mmc_dev_con, (uintptr_t)&mmc_block_dev_spec, + &storage_dev_handle); + assert(io_result == 0); + +#if STM32MP_EMMC_BOOT + if (mmc_dev_type == MMC_IS_EMMC) { + io_result = mmc_part_switch_current_boot(); + assert(io_result == 0); + + if (get_boot_part_fip_header() != TOC_HEADER_NAME) { + WARN("%s: Can't find FIP header on eMMC boot partition. Trying GPT\n", + __func__); + io_result = mmc_part_switch_user(); + assert(io_result == 0); + return; + } + + VERBOSE("%s: FIP header found on eMMC boot partition\n", + __func__); + image_block_spec.offset = STM32MP_EMMC_BOOT_FIP_OFFSET; + image_block_spec.length = mmc_boot_part_size() - STM32MP_EMMC_BOOT_FIP_OFFSET; + } +#endif +} +#endif /* STM32MP_SDMMC || STM32MP_EMMC */ + +#if STM32MP_SPI_NOR +static void boot_spi_nor(boot_api_context_t *boot_context) +{ + int io_result __unused; + + io_result = stm32_qspi_init(); + assert(io_result == 0); + + io_result = register_io_dev_mtd(&spi_dev_con); + assert(io_result == 0); + + /* Open connections to device */ + io_result = io_dev_open(spi_dev_con, + (uintptr_t)&spi_nor_dev_spec, + &storage_dev_handle); + assert(io_result == 0); +} +#endif /* STM32MP_SPI_NOR */ + +#if STM32MP_RAW_NAND +static void boot_fmc2_nand(boot_api_context_t *boot_context) +{ + int io_result __unused; + + io_result = stm32_fmc2_init(); + assert(io_result == 0); + + /* Register the IO device on this platform */ + io_result = register_io_dev_mtd(&nand_dev_con); + assert(io_result == 0); + + /* Open connections to device */ + io_result = io_dev_open(nand_dev_con, (uintptr_t)&nand_dev_spec, + &storage_dev_handle); + assert(io_result == 0); +} +#endif /* STM32MP_RAW_NAND */ + +#if STM32MP_SPI_NAND +static void boot_spi_nand(boot_api_context_t *boot_context) +{ + int io_result __unused; + + io_result = stm32_qspi_init(); + assert(io_result == 0); + + io_result = register_io_dev_mtd(&spi_dev_con); + assert(io_result == 0); + + /* Open connections to device */ + io_result = io_dev_open(spi_dev_con, + (uintptr_t)&spi_nand_dev_spec, + &storage_dev_handle); + assert(io_result == 0); +} +#endif /* STM32MP_SPI_NAND */ + +#if STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER +static void mmap_io_setup(void) +{ + int io_result __unused; + + io_result = register_io_dev_memmap(&memmap_dev_con); + assert(io_result == 0); + + io_result = io_dev_open(memmap_dev_con, (uintptr_t)NULL, + &storage_dev_handle); + assert(io_result == 0); +} + +#if STM32MP_UART_PROGRAMMER +static void stm32cubeprogrammer_uart(void) +{ + int ret __unused; + boot_api_context_t *boot_context = + (boot_api_context_t *)stm32mp_get_boot_ctx_address(); + uintptr_t uart_base; + + uart_base = get_uart_address(boot_context->boot_interface_instance); + ret = stm32cubeprog_uart_load(uart_base, DWL_BUFFER_BASE, DWL_BUFFER_SIZE); + assert(ret == 0); +} +#endif + +#if STM32MP_USB_PROGRAMMER +static void stm32cubeprogrammer_usb(void) +{ + int ret __unused; + struct usb_handle *pdev; + + /* Init USB on platform */ + pdev = usb_dfu_plat_init(); + + ret = stm32cubeprog_usb_load(pdev, DWL_BUFFER_BASE, DWL_BUFFER_SIZE); + assert(ret == 0); +} +#endif +#endif /* STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER */ + + +void stm32mp_io_setup(void) +{ + int io_result __unused; + boot_api_context_t *boot_context = + (boot_api_context_t *)stm32mp_get_boot_ctx_address(); + + print_boot_device(boot_context); + + if ((boot_context->boot_partition_used_toboot == 1U) || + (boot_context->boot_partition_used_toboot == 2U)) { + INFO("Boot used partition fsbl%u\n", + boot_context->boot_partition_used_toboot); + } + + io_result = register_io_dev_fip(&fip_dev_con); + assert(io_result == 0); + + io_result = io_dev_open(fip_dev_con, (uintptr_t)NULL, + &fip_dev_handle); + +#ifndef DECRYPTION_SUPPORT_none + io_result = register_io_dev_enc(&enc_dev_con); + assert(io_result == 0); + + io_result = io_dev_open(enc_dev_con, (uintptr_t)NULL, + &enc_dev_handle); + assert(io_result == 0); +#endif + + switch (boot_context->boot_interface_selected) { +#if STM32MP_SDMMC + case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_SD: + dmbsy(); + boot_mmc(MMC_IS_SD, boot_context->boot_interface_instance); + break; +#endif +#if STM32MP_EMMC + case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_EMMC: + dmbsy(); + boot_mmc(MMC_IS_EMMC, boot_context->boot_interface_instance); + break; +#endif +#if STM32MP_SPI_NOR + case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NOR_QSPI: + dmbsy(); + boot_spi_nor(boot_context); + break; +#endif +#if STM32MP_RAW_NAND + case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_FMC: + dmbsy(); + boot_fmc2_nand(boot_context); + break; +#endif +#if STM32MP_SPI_NAND + case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_QSPI: + dmbsy(); + boot_spi_nand(boot_context); + break; +#endif +#if STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER +#if STM32MP_UART_PROGRAMMER + case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART: +#endif +#if STM32MP_USB_PROGRAMMER + case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB: +#endif + dmbsy(); + mmap_io_setup(); + break; +#endif + + default: + ERROR("Boot interface %d not supported\n", + boot_context->boot_interface_selected); + panic(); + break; + } +} + +int bl2_plat_handle_pre_image_load(unsigned int image_id) +{ + static bool gpt_init_done __unused; + uint16_t boot_itf = stm32mp_get_boot_itf_selected(); + + switch (boot_itf) { +#if STM32MP_SDMMC || STM32MP_EMMC + case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_EMMC: +#if STM32MP_EMMC_BOOT + if (image_block_spec.offset == STM32MP_EMMC_BOOT_FIP_OFFSET) { + break; + } +#endif + /* fallthrough */ + case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_SD: + if (!gpt_init_done) { +/* + * With FWU Multi Bank feature enabled, the selection of + * the image to boot will be done by fwu_init calling the + * platform hook, plat_fwu_set_images_source. + */ +#if !PSA_FWU_SUPPORT + const partition_entry_t *entry; + const struct efi_guid img_type_guid = STM32MP_FIP_GUID; + uuid_t img_type_uuid; + + guidcpy(&img_type_uuid, &img_type_guid); + partition_init(GPT_IMAGE_ID); + entry = get_partition_entry_by_type(&img_type_uuid); + if (entry == NULL) { + entry = get_partition_entry(FIP_IMAGE_NAME); + if (entry == NULL) { + ERROR("Could NOT find the %s partition!\n", + FIP_IMAGE_NAME); + + return -ENOENT; + } + } + + image_block_spec.offset = entry->start; + image_block_spec.length = entry->length; +#endif + gpt_init_done = true; + } else { + bl_mem_params_node_t *bl_mem_params = get_bl_mem_params_node(image_id); + assert(bl_mem_params != NULL); + + mmc_block_dev_spec.buffer.offset = bl_mem_params->image_info.image_base; + mmc_block_dev_spec.buffer.length = bl_mem_params->image_info.image_max_size; + } + + break; +#endif + +#if STM32MP_RAW_NAND || STM32MP_SPI_NAND +#if STM32MP_RAW_NAND + case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_FMC: +#endif +#if STM32MP_SPI_NAND + case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_QSPI: +#endif + image_block_spec.offset = STM32MP_NAND_FIP_OFFSET; + break; +#endif + +#if STM32MP_SPI_NOR + case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NOR_QSPI: + image_block_spec.offset = STM32MP_NOR_FIP_OFFSET; + break; +#endif + +#if STM32MP_UART_PROGRAMMER + case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART: + if (image_id == FW_CONFIG_ID) { + stm32cubeprogrammer_uart(); + /* FIP loaded at DWL address */ + image_block_spec.offset = DWL_BUFFER_BASE; + image_block_spec.length = DWL_BUFFER_SIZE; + } + break; +#endif +#if STM32MP_USB_PROGRAMMER + case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB: + if (image_id == FW_CONFIG_ID) { + stm32cubeprogrammer_usb(); + /* FIP loaded at DWL address */ + image_block_spec.offset = DWL_BUFFER_BASE; + image_block_spec.length = DWL_BUFFER_SIZE; + } + break; +#endif + + default: + ERROR("FIP Not found\n"); + panic(); + } + + return 0; +} + +/* + * Return an IO device handle and specification which can be used to access + * an image. Use this to enforce platform load policy. + */ +int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle, + uintptr_t *image_spec) +{ + int rc; + const struct plat_io_policy *policy; + + policy = FCONF_GET_PROPERTY(stm32mp, io_policies, image_id); + rc = policy->check(policy->image_spec); + if (rc == 0) { + *image_spec = policy->image_spec; + *dev_handle = *(policy->dev_handle); + } + + return rc; +} + +#if (STM32MP_SDMMC || STM32MP_EMMC) && PSA_FWU_SUPPORT +/* + * In each boot in non-trial mode, we set the BKP register to + * FWU_MAX_TRIAL_REBOOT, and return the active_index from metadata. + * + * As long as the update agent didn't update the "accepted" field in metadata + * (i.e. we are in trial mode), we select the new active_index. + * To avoid infinite boot loop at trial boot we decrement a BKP register. + * If this counter is 0: + * - an unexpected TAMPER event raised (that resets the BKP registers to 0) + * - a power-off occurs before the update agent was able to update the + * "accepted' field + * - we already boot FWU_MAX_TRIAL_REBOOT times in trial mode. + * we select the previous_active_index. + */ +#define INVALID_BOOT_IDX 0xFFFFFFFF + +uint32_t plat_fwu_get_boot_idx(void) +{ + /* + * Select boot index and update boot counter only once per boot + * even if this function is called several times. + */ + static uint32_t boot_idx = INVALID_BOOT_IDX; + const struct fwu_metadata *data; + + data = fwu_get_metadata(); + + if (boot_idx == INVALID_BOOT_IDX) { + boot_idx = data->active_index; + if (fwu_is_trial_run_state()) { + if (stm32_get_and_dec_fwu_trial_boot_cnt() == 0U) { + WARN("Trial FWU fails %u times\n", + FWU_MAX_TRIAL_REBOOT); + boot_idx = data->previous_active_index; + } + } else { + stm32_set_max_fwu_trial_boot_cnt(); + } + } + + return boot_idx; +} + +static void *stm32_get_image_spec(const uuid_t *img_type_uuid) +{ + unsigned int i; + + for (i = 0U; i < MAX_NUMBER_IDS; i++) { + if ((guidcmp(&policies[i].img_type_guid, img_type_uuid)) == 0) { + return (void *)policies[i].image_spec; + } + } + + return NULL; +} + +void plat_fwu_set_images_source(const struct fwu_metadata *metadata) +{ + unsigned int i; + uint32_t boot_idx; + const partition_entry_t *entry; + const uuid_t *img_type_uuid, *img_uuid; + io_block_spec_t *image_spec; + + boot_idx = plat_fwu_get_boot_idx(); + assert(boot_idx < NR_OF_FW_BANKS); + + for (i = 0U; i < NR_OF_IMAGES_IN_FW_BANK; i++) { + img_type_uuid = &metadata->img_entry[i].img_type_uuid; + image_spec = stm32_get_image_spec(img_type_uuid); + if (image_spec == NULL) { + ERROR("Unable to get image spec for the image in the metadata\n"); + panic(); + } + + img_uuid = + &metadata->img_entry[i].img_props[boot_idx].img_uuid; + + entry = get_partition_entry_by_uuid(img_uuid); + if (entry == NULL) { + ERROR("Unable to find the partition with the uuid mentioned in metadata\n"); + panic(); + } + + image_spec->offset = entry->start; + image_spec->length = entry->length; + } +} + +static int plat_set_image_source(unsigned int image_id, + uintptr_t *handle, + uintptr_t *image_spec, + const char *part_name) +{ + struct plat_io_policy *policy; + io_block_spec_t *spec; + const partition_entry_t *entry = get_partition_entry(part_name); + + if (entry == NULL) { + ERROR("Unable to find the %s partition\n", part_name); + return -ENOENT; + } + + policy = &policies[image_id]; + + spec = (io_block_spec_t *)policy->image_spec; + spec->offset = entry->start; + spec->length = entry->length; + + *image_spec = policy->image_spec; + *handle = *policy->dev_handle; + + return 0; +} + +int plat_fwu_set_metadata_image_source(unsigned int image_id, + uintptr_t *handle, + uintptr_t *image_spec) +{ + char *part_name; + + assert((image_id == FWU_METADATA_IMAGE_ID) || + (image_id == BKUP_FWU_METADATA_IMAGE_ID)); + + partition_init(GPT_IMAGE_ID); + + if (image_id == FWU_METADATA_IMAGE_ID) { + part_name = METADATA_PART_1; + } else { + part_name = METADATA_PART_2; + } + + return plat_set_image_source(image_id, handle, image_spec, + part_name); +} +#endif /* (STM32MP_SDMMC || STM32MP_EMMC) && PSA_FWU_SUPPORT */ diff --git a/plat/st/common/include/stm32cubeprogrammer.h b/plat/st/common/include/stm32cubeprogrammer.h new file mode 100644 index 0000000..0f5a64d --- /dev/null +++ b/plat/st/common/include/stm32cubeprogrammer.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2021, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef STM32CUBEPROGRAMMER_H +#define STM32CUBEPROGRAMMER_H + +#include <stdint.h> + +#include <usb_dfu.h> + +/* Phase definition */ +#define PHASE_FLASHLAYOUT 0U +#define PHASE_SSBL 3U +#define PHASE_CMD 0xF1U +#define PHASE_RESET 0xFFU + +/* Functions provided by plat */ +uint8_t usb_dfu_get_phase(uint8_t alt); + +int stm32cubeprog_usb_load(struct usb_handle *usb_core_handle, + uintptr_t ssbl_base, + size_t ssbl_len); + +int stm32cubeprog_uart_load(uintptr_t instance, uintptr_t base, size_t len); + +#endif /* STM32CUBEPROGRAMMER_H */ diff --git a/plat/st/common/include/stm32mp_common.h b/plat/st/common/include/stm32mp_common.h new file mode 100644 index 0000000..a5316b6 --- /dev/null +++ b/plat/st/common/include/stm32mp_common.h @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2018-2022, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef STM32MP_COMMON_H +#define STM32MP_COMMON_H + +#include <stdbool.h> + +#include <platform_def.h> + +#define JEDEC_ST_BKID U(0x0) +#define JEDEC_ST_MFID U(0x20) + +/* Functions to save and get boot context address given by ROM code */ +void stm32mp_save_boot_ctx_address(uintptr_t address); +uintptr_t stm32mp_get_boot_ctx_address(void); +uint16_t stm32mp_get_boot_itf_selected(void); + +bool stm32mp_is_single_core(void); +bool stm32mp_is_closed_device(void); +bool stm32mp_is_auth_supported(void); + +/* Return the base address of the DDR controller */ +uintptr_t stm32mp_ddrctrl_base(void); + +/* Return the base address of the DDR PHY */ +uintptr_t stm32mp_ddrphyc_base(void); + +/* Return the base address of the PWR peripheral */ +uintptr_t stm32mp_pwr_base(void); + +/* Return the base address of the RCC peripheral */ +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); + +/* Return bitflag mask for expected IWDG configuration from OTP content */ +uint32_t stm32_iwdg_get_otp_config(uint32_t iwdg_inst); + +#if defined(IMAGE_BL2) +/* Update OTP shadow registers with IWDG configuration from device tree */ +uint32_t stm32_iwdg_shadow_update(uint32_t iwdg_inst, uint32_t flags); +#endif + +#if STM32MP_UART_PROGRAMMER || !defined(IMAGE_BL2) +/* Get the UART address from its instance number */ +uintptr_t get_uart_address(uint32_t instance_nb); +#endif + +/* Setup the UART console */ +int stm32mp_uart_console_setup(void); + +#if STM32MP_EARLY_CONSOLE +void stm32mp_setup_early_console(void); +#else +static inline void stm32mp_setup_early_console(void) +{ +} +#endif + +/* + * Platform util functions for the GPIO driver + * @bank: Target GPIO bank ID as per DT bindings + * + * Platform shall implement these functions to provide to stm32_gpio + * driver the resource reference for a target GPIO bank. That are + * memory mapped interface base address, interface offset (see below) + * and clock identifier. + * + * stm32_get_gpio_bank_offset() returns a bank offset that is used to + * check DT configuration matches platform implementation of the banks + * description. + */ +uintptr_t stm32_get_gpio_bank_base(unsigned int bank); +unsigned long stm32_get_gpio_bank_clock(unsigned int bank); +uint32_t stm32_get_gpio_bank_offset(unsigned int bank); +bool stm32_gpio_is_secure_at_reset(unsigned int bank); + +/* Return node offset for target GPIO bank ID @bank or a FDT error code */ +int stm32_get_gpio_bank_pinctrl_node(void *fdt, unsigned int bank); + +/* Get the chip revision */ +uint32_t stm32mp_get_chip_version(void); +/* Get the chip device ID */ +uint32_t stm32mp_get_chip_dev_id(void); + +/* Get SOC name */ +#define STM32_SOC_NAME_SIZE 20 +void stm32mp_get_soc_name(char name[STM32_SOC_NAME_SIZE]); + +/* Print CPU information */ +void stm32mp_print_cpuinfo(void); + +/* Print board information */ +void stm32mp_print_boardinfo(void); + +/* Initialise the IO layer and register platform IO devices */ +void stm32mp_io_setup(void); + +/* Functions to map DDR in MMU with non-cacheable attribute, and unmap it */ +int stm32mp_map_ddr_non_cacheable(void); +int stm32mp_unmap_ddr(void); + +/* Functions to save and get boot peripheral info */ +void stm32_save_boot_interface(uint32_t interface, uint32_t instance); +void stm32_get_boot_interface(uint32_t *interface, uint32_t *instance); + +/* Functions to save and get boot authentication status and partition used */ +void stm32_save_boot_auth(uint32_t auth_status, uint32_t boot_partition); + +#if PSA_FWU_SUPPORT +void stm32mp1_fwu_set_boot_idx(void); +uint32_t stm32_get_and_dec_fwu_trial_boot_cnt(void); +void stm32_set_max_fwu_trial_boot_cnt(void); +#endif /* PSA_FWU_SUPPORT */ + +#endif /* STM32MP_COMMON_H */ diff --git a/plat/st/common/include/stm32mp_dt.h b/plat/st/common/include/stm32mp_dt.h new file mode 100644 index 0000000..b7bf1d0 --- /dev/null +++ b/plat/st/common/include/stm32mp_dt.h @@ -0,0 +1,46 @@ +/* + * 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 + */ + +#ifndef STM32MP_DT_H +#define STM32MP_DT_H + +#include <stdbool.h> +#include <stdint.h> + +#define DT_DISABLED U(0) +#define DT_NON_SECURE U(1) +#define DT_SECURE U(2) +#define DT_SHARED (DT_NON_SECURE | DT_SECURE) + +struct dt_node_info { + uint32_t base; + int32_t clock; + int32_t reset; + uint32_t status; +}; + +/******************************************************************************* + * Function and variable prototypes + ******************************************************************************/ +int dt_open_and_check(uintptr_t dt_addr); +int fdt_get_address(void **fdt_addr); +bool fdt_check_node(int node); +uint8_t fdt_get_status(int node); +int dt_set_stdout_pinctrl(void); +void dt_fill_device_info(struct dt_node_info *info, int node); +int dt_get_node(struct dt_node_info *info, int offset, const char *compat); +int dt_get_stdout_uart_info(struct dt_node_info *info); +int dt_match_instance_by_compatible(const char *compatible, uintptr_t address); +uint32_t dt_get_ddr_size(void); +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/include/stm32mp_efi.h b/plat/st/common/include/stm32mp_efi.h new file mode 100644 index 0000000..490560f --- /dev/null +++ b/plat/st/common/include/stm32mp_efi.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright (c) 2021, Linaro Limited + */ + +#ifndef STM32MP_EFI_H +#define STM32MP_EFI_H + +#include <drivers/partition/efi.h> + +#define STM32MP_FIP_GUID \ + EFI_GUID(0x19d5df83, 0x11b0, 0x457b, \ + 0xbe, 0x2c, 0x75, 0x59, 0xc1, 0x31, 0x42, 0xa5) + +#endif /* STM32MP_EFI_H */ diff --git a/plat/st/common/include/stm32mp_fconf_getter.h b/plat/st/common/include/stm32mp_fconf_getter.h new file mode 100644 index 0000000..18884ae --- /dev/null +++ b/plat/st/common/include/stm32mp_fconf_getter.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2021, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef STM32MP_FCONF_GETTER +#define STM32MP_FCONF_GETTER + +#include <assert.h> + +#include <lib/fconf/fconf.h> +#include <tools_share/uuid.h> + +/* IO policies */ +#define stm32mp__io_policies_getter(id) __extension__ ({ \ + assert((id) < MAX_NUMBER_IDS); \ + &policies[id]; \ +}) + +struct plat_io_policy { + uintptr_t *dev_handle; + uintptr_t image_spec; + struct efi_guid img_type_guid; + int (*check)(const uintptr_t spec); +}; + +extern struct plat_io_policy policies[]; +int fconf_populate_stm32mp_io_policies(uintptr_t config); + +#endif /* STM32MP_FCONF_GETTER */ diff --git a/plat/st/common/include/stm32mp_io_storage.h b/plat/st/common/include/stm32mp_io_storage.h new file mode 100644 index 0000000..3c04c47 --- /dev/null +++ b/plat/st/common/include/stm32mp_io_storage.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2021-2022, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef STM32MP_IO_STORAGE_H +#define STM32MP_IO_STORAGE_H + +#include <stdint.h> + +#include <drivers/io/io_storage.h> + +/* IO devices handle */ +extern uintptr_t storage_dev_handle; +extern uintptr_t fip_dev_handle; +extern uintptr_t enc_dev_handle; + +extern io_block_spec_t image_block_spec; + +/* Function declarations */ +int open_fip(const uintptr_t spec); +#ifndef DECRYPTION_SUPPORT_none +int open_enc_fip(const uintptr_t spec); +#endif +int open_storage(const uintptr_t spec); + +#endif /* STM32MP_IO_STORAGE_H */ diff --git a/plat/st/common/include/stm32mp_shared_resources.h b/plat/st/common/include/stm32mp_shared_resources.h new file mode 100644 index 0000000..13f4b13 --- /dev/null +++ b/plat/st/common/include/stm32mp_shared_resources.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2017-2020, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef STM32MP_SHARED_RESOURCES_H +#define STM32MP_SHARED_RESOURCES_H + +#include <stdbool.h> +#include <stdint.h> + +#ifdef STM32MP_SHARED_RESOURCES +enum stm32mp_shres; + +/* Return true if @clock_id is shared by secure and non-secure worlds */ +bool stm32mp_nsec_can_access_clock(unsigned long clock_id); + +/* Return true if and only if @reset_id relates to a non-secure peripheral */ +bool stm32mp_nsec_can_access_reset(unsigned int reset_id); + +/* Register a shared resource assigned to the secure world */ +void stm32mp_register_secure_periph(enum stm32mp_shres id); + +/* Register a shared resource assigned to the non-secure world */ +void stm32mp_register_non_secure_periph(enum stm32mp_shres id); + +/* Register a peripheral as secure or non-secure based on IO base address */ +void stm32mp_register_secure_periph_iomem(uintptr_t base); +void stm32mp_register_non_secure_periph_iomem(uintptr_t base); + +/* Register a GPIO as secure or non-secure based on its bank and pin numbers */ +void stm32mp_register_secure_gpio(unsigned int bank, unsigned int pin); +void stm32mp_register_non_secure_gpio(unsigned int bank, unsigned int pin); + +/* Consolidate peripheral states and lock against new peripheral registering */ +void stm32mp_lock_periph_registering(void); +#else +static inline void stm32mp_register_secure_periph_iomem(uintptr_t base __unused) +{ +} + +static inline +void stm32mp_register_non_secure_periph_iomem(uintptr_t base __unused) +{ +} + +static inline void stm32mp_register_secure_gpio(unsigned int bank __unused, + unsigned int pin __unused) +{ +} + +static inline void stm32mp_register_non_secure_gpio(unsigned int bank __unused, + unsigned int pin __unused) +{ +} +#endif /* STM32MP_SHARED_RESOURCES */ +#endif /* STM32MP_SHARED_RESOURCES_H */ diff --git a/plat/st/common/include/usb_dfu.h b/plat/st/common/include/usb_dfu.h new file mode 100644 index 0000000..f7d4245 --- /dev/null +++ b/plat/st/common/include/usb_dfu.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2021, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef USB_DFU_H +#define USB_DFU_H + +#include <stdint.h> + +#include <drivers/usb_device.h> + +#define DFU_DESCRIPTOR_TYPE 0x21U + +/* Max DFU Packet Size = 1024 bytes */ +#define USBD_DFU_XFER_SIZE 1024U + +#define TRANSFER_SIZE_BYTES(size) \ + ((uint8_t)((size) & 0xFF)), /* XFERSIZEB0 */\ + ((uint8_t)((size) >> 8)) /* XFERSIZEB1 */ + +/* + * helper for descriptor of DFU interface 0 Alternate setting n + * with iInterface = index of string descriptor, assumed Nth user string + */ +#define USBD_DFU_IF_DESC(n) 0x09U, /* Interface Descriptor size */\ + USB_DESC_TYPE_INTERFACE, /* descriptor type */\ + 0x00U, /* Number of Interface */\ + (n), /* Alternate setting */\ + 0x00U, /* bNumEndpoints*/\ + 0xFEU, /* Application Specific Class Code */\ + 0x01U, /* Device Firmware Upgrade Code */\ + 0x02U, /* DFU mode protocol */ \ + USBD_IDX_USER0_STR + (n) /* iInterface */ + +/* DFU1.1 Standard */ +#define USB_DFU_VERSION 0x0110U +#define USB_DFU_ITF_SIZ 9U +#define USB_DFU_DESC_SIZ(itf) (USB_DFU_ITF_SIZ * ((itf) + 2U)) + +/* + * bmAttribute value for DFU: + * bitCanDnload = 1(bit 0) + * bitCanUpload = 1(bit 1) + * bitManifestationTolerant = 1 (bit 2) + * bitWillDetach = 1(bit 3) + * Reserved (bit4-6) + * bitAcceleratedST = 0(bit 7) + */ +#define DFU_BM_ATTRIBUTE 0x0FU + +#define DFU_STATUS_SIZE 6U + +/* Callback for media access */ +struct usb_dfu_media { + int (*upload)(uint8_t alt, uintptr_t *buffer, uint32_t *len, + void *user_data); + int (*download)(uint8_t alt, uintptr_t *buffer, uint32_t *len, + void *user_data); + int (*manifestation)(uint8_t alt, void *user_data); +}; + +/* Internal DFU handle */ +struct usb_dfu_handle { + uint8_t status[DFU_STATUS_SIZE]; + uint8_t dev_state; + uint8_t dev_status; + uint8_t alt_setting; + const struct usb_dfu_media *callback; +}; + +void usb_dfu_register(struct usb_handle *pdev, struct usb_dfu_handle *phandle); + +int usb_dfu_loop(struct usb_handle *pdev, const struct usb_dfu_media *pmedia); + +/* Function provided by plat */ +struct usb_handle *usb_dfu_plat_init(void); + +#endif /* USB_DFU_H */ diff --git a/plat/st/common/stm32cubeprogrammer_uart.c b/plat/st/common/stm32cubeprogrammer_uart.c new file mode 100644 index 0000000..d004dcf --- /dev/null +++ b/plat/st/common/stm32cubeprogrammer_uart.c @@ -0,0 +1,520 @@ +/* + * Copyright (c) 2021-2022, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <endian.h> +#include <errno.h> +#include <string.h> + +#include <arch_helpers.h> +#include <common/debug.h> +#include <drivers/delay_timer.h> +#include <drivers/st/stm32_iwdg.h> +#include <drivers/st/stm32_uart.h> +#include <drivers/st/stm32_uart_regs.h> +#include <lib/mmio.h> +#include <tools_share/firmware_image_package.h> + +#include <platform_def.h> +#include <stm32cubeprogrammer.h> + +/* USART bootloader protocol version V4.0 */ +#define USART_BL_VERSION 0x40U + +/* Command definition */ +#define GET_CMD_COMMAND 0x00U +#define GET_VER_COMMAND 0x01U +#define GET_ID_COMMAND 0x02U +#define PHASE_COMMAND 0x03U +#define READ_PART_COMMAND 0x12U +#define START_COMMAND 0x21U +#define DOWNLOAD_COMMAND 0x31U + +/* Answer defines */ +#define INIT_BYTE 0x7FU +#define ACK_BYTE 0x79U +#define NACK_BYTE 0x1FU +#define ABORT 0x5FU + +#define UNDEFINED_DOWN_ADDR U(0xFFFFFFFF) +#define PROGRAMMER_TIMEOUT_US 20000U + +static const uint8_t command_tab[] = { + GET_CMD_COMMAND, + GET_VER_COMMAND, + GET_ID_COMMAND, + PHASE_COMMAND, + START_COMMAND, + DOWNLOAD_COMMAND +}; + +/* STM32CubeProgrammer over UART handle */ +struct stm32prog_uart_handle_s { + struct stm32_uart_handle_s uart; + uint32_t packet; + uint8_t *addr; + uint32_t len; + uint8_t phase; + /* Error msg buffer: max 255 in UART protocol, reduced in TF-A */ + uint8_t error[64]; +} handle; + +/* Trace and handle unrecoverable UART protocol error */ +#define STM32PROG_ERROR(...) \ + { \ + ERROR(__VA_ARGS__); \ + if (handle.phase != PHASE_RESET) { \ + snprintf((char *)&handle.error, sizeof(handle.error), __VA_ARGS__); \ + handle.phase = PHASE_RESET; \ + handle.addr = (uint8_t *)UNDEFINED_DOWN_ADDR; \ + handle.len = 0U; \ + handle.packet = 0U; \ + } \ + } + +static int uart_write(const uint8_t *addr, uint16_t size) +{ + while (size != 0U) { + if (stm32_uart_putc(&handle.uart, *addr) != 0) { + return -EIO; + } + size--; + addr++; + } + + return 0; +} + +static int uart_write_8(uint8_t byte) +{ + return stm32_uart_putc(&handle.uart, byte); +} + +static int uart_write_32(uint32_t value) +{ + return uart_write((uint8_t *)&value, 4U); +} + +static int uart_read_8(uint8_t *byte) +{ + int ret; + uint64_t timeout_ref = timeout_init_us(PROGRAMMER_TIMEOUT_US); + + do { + ret = stm32_uart_getc(&handle.uart); + if (ret == -EAGAIN) { + if (timeout_elapsed(timeout_ref)) { + return -ETIMEDOUT; + } + } else if (ret < 0) { + return ret; + } + } while (ret == -EAGAIN); + + *byte = (uint8_t)ret; + + return 0; +} + +static int uart_send_result(uint8_t byte) +{ + int ret; + + /* Always flush fifo before to send result = read all pending data */ + do { + ret = stm32_uart_getc(&handle.uart); + } while (ret >= 0); + + return uart_write_8(byte); +} + +static bool is_valid_header(fip_toc_header_t *header) +{ + return (header->name == TOC_HEADER_NAME) && + (header->serial_number != 0U); +} + +static int uart_receive_command(uint8_t *command) +{ + uint8_t byte = 0U; + uint8_t xor = 0U; + unsigned int count; + bool found = false; + int ret; + + /* Repeat read until something is received */ + do { + stm32_iwdg_refresh(); + ret = uart_read_8(&byte); + } while (ret == -ETIMEDOUT); + + if (ret != 0) { + return ret; + } + + /* Handle reconnection request */ + if (byte == INIT_BYTE) { + *command = byte; + return 0; + } + + for (count = 0U; count < ARRAY_SIZE(command_tab); count++) { + if (command_tab[count] == byte) { + found = true; + break; + } + } + if (!found) { + VERBOSE("UART: Command unknown (byte=0x%x)\n", byte); + return -EPROTO; + } + + ret = uart_read_8(&xor); + if (ret != 0) { + return ret; + } + if ((byte ^ xor) != 0xFF) { + VERBOSE("UART: Command XOR check fail (byte=0x%x, xor=0x%x)\n", + byte, xor); + return -EPROTO; + } + + *command = byte; + + return 0; +} + +static int get_cmd_command(void) +{ + const uint8_t msg[2] = { + sizeof(command_tab), /* Length of data - 1 */ + USART_BL_VERSION + }; + int ret; + + ret = uart_write(msg, sizeof(msg)); + if (ret != 0) { + return ret; + } + + return uart_write(command_tab, sizeof(command_tab)); +} + +static int get_version_command(void) +{ + return uart_write_8(STM32_TF_VERSION); +} + +static int get_id_command(void) +{ + uint8_t msg[3] = { + sizeof(msg) - 1 /* Length of data - 1 */ + }; + uint32_t chip_id = stm32mp_get_chip_dev_id(); + + be16enc(&msg[1], chip_id); + + return uart_write(msg, sizeof(msg)); +} + +static int uart_send_phase(uint32_t address) +{ + int ret; + uint8_t msg_size = 5U; /* Length of data - 1 */ + uint8_t error_size = 0U; + + /* Additional information only for RESET phase */ + if (handle.phase == PHASE_RESET) { + error_size = strnlen((char *)&handle.error, sizeof(handle.error)); + } + ret = uart_write_8(msg_size + error_size); + if (ret != 0) { + return ret; + } + + /* Send the ID of next partition */ + ret = uart_write_8(handle.phase); + if (ret != 0) { + return ret; + } + + /* Destination address */ + ret = uart_write_32(address); + if (ret != 0) { + return ret; + } + + ret = uart_write_8(error_size); + if (ret != 0) { + return ret; + } + + /* Additional information: message error */ + if (error_size > 0U) { + ret = uart_write(handle.error, error_size); + } + + return ret; +} + +static int uart_download_part(void) +{ + uint8_t operation = 0U; + uint8_t xor; + uint8_t byte = 0U; + uint32_t packet_number = 0U; + uint32_t packet_size = 0U; + uint32_t i = 0U; + int ret; + + /* Get operation number */ + ret = uart_read_8(&operation); + if (ret != 0) { + return ret; + } + + xor = operation; + + /* Get packet number */ + for (i = 3U; i != 0U; i--) { + ret = uart_read_8(&byte); + if (ret != 0) { + return ret; + } + + xor ^= byte; + packet_number = (packet_number << 8) | byte; + } + + if (packet_number != handle.packet) { + WARN("UART: Bad packet number receive: %u, expected %u\n", + packet_number, handle.packet); + return -EPROTO; + } + + /* Checksum */ + ret = uart_read_8(&byte); + if (ret != 0) { + return ret; + } + if (xor != byte) { + VERBOSE("UART: Download Command checksum xor: %x, received %x\n", + xor, byte); + return -EPROTO; + } + + ret = uart_send_result(ACK_BYTE); + if (ret != 0) { + return ret; + } + + ret = uart_read_8(&byte); + if (ret != 0) { + return ret; + } + xor = byte; + packet_size = byte + 1U; + if (handle.len < packet_size) { + STM32PROG_ERROR("Download overflow at %p\n", handle.addr + packet_size); + return 0; + } + + for (i = 0U; i < packet_size; i++) { + ret = uart_read_8(&byte); + if (ret != 0) { + return ret; + } + + *(handle.addr + i) = byte; + xor ^= byte; + } + + /* Checksum */ + ret = uart_read_8(&byte) != 0; + if (ret != 0) { + return ret; + } + if (xor != byte) { + VERBOSE("UART: Download Data checksum xor: %x, received %x\n", + xor, byte); + return -EPROTO; + } + + /* Packet treated */ + handle.packet++; + handle.addr += packet_size; + handle.len -= packet_size; + + return 0; +} + +static int uart_start_cmd(uintptr_t buffer) +{ + uint8_t byte = 0U; + uint8_t xor = 0U; + uint32_t i; + uint32_t start_address = 0U; + int ret; + + /* Get address */ + for (i = 4U; i != 0U; i--) { + ret = uart_read_8(&byte); + if (ret != 0U) { + return ret; + } + + xor ^= byte; + start_address = (start_address << 8) | byte; + } + + /* Checksum */ + ret = uart_read_8(&byte); + if (ret != 0) { + return ret; + } + + if (xor != byte) { + VERBOSE("UART: Start Command checksum xor: %x, received %x\n", + xor, byte); + return -EPROTO; + } + + if (start_address != UNDEFINED_DOWN_ADDR) { + STM32PROG_ERROR("Invalid start at %x, for phase %u\n", + start_address, handle.phase); + return 0; + } + + if (!is_valid_header((fip_toc_header_t *)buffer)) { + STM32PROG_ERROR("FIP Header check failed %lx, for phase %u\n", + buffer, handle.phase); + return -EIO; + } + VERBOSE("FIP header looks OK.\n"); + + return 0; +} + +static int uart_read(uint8_t id, uintptr_t buffer, size_t length) +{ + bool start_done = false; + int ret; + uint8_t command = 0U; + + handle.phase = id; + handle.packet = 0U; + handle.addr = (uint8_t *)buffer; + handle.len = length; + + INFO("UART: read phase %u at 0x%lx size 0x%x\n", + id, buffer, length); + while (!start_done) { + ret = uart_receive_command(&command); + if (ret != 0) { + /* Delay to wait STM32CubeProgrammer end of transmission */ + mdelay(3); + + ret = uart_send_result(NACK_BYTE); + if (ret != 0U) { + return ret; + } + + continue; + } + + uart_send_result(ACK_BYTE); + + switch (command) { + case INIT_BYTE: + INFO("UART: Connected\n"); + /* Nothing to do */ + continue; + + case GET_CMD_COMMAND: + ret = get_cmd_command(); + break; + + case GET_VER_COMMAND: + ret = get_version_command(); + break; + + case GET_ID_COMMAND: + ret = get_id_command(); + break; + + case PHASE_COMMAND: + ret = uart_send_phase((uint32_t)buffer); + if ((ret == 0) && (handle.phase == PHASE_RESET)) { + start_done = true; + INFO("UART: Reset\n"); + } + break; + + case DOWNLOAD_COMMAND: + ret = uart_download_part(); + break; + + case START_COMMAND: + ret = uart_start_cmd(buffer); + if ((ret == 0) && (handle.phase == id)) { + INFO("UART: Start phase %u\n", handle.phase); + start_done = true; + } + break; + + default: + WARN("UART: Unknown command\n"); + ret = -EINVAL; + break; + } + + if (ret == 0) { + ret = uart_send_result(ACK_BYTE); + } else { + ret = uart_send_result(NACK_BYTE); + } + if (ret != 0) { + return ret; + } + } + + return 0; +} + +/* Init UART: 115200, 8bit 1stop parity even and enable FIFO mode */ +const struct stm32_uart_init_s init = { + .baud_rate = STM32MP_UART_BAUDRATE, + .word_length = STM32_UART_WORDLENGTH_9B, + .stop_bits = STM32_UART_STOPBITS_1, + .parity = STM32_UART_PARITY_EVEN, + .hw_flow_control = STM32_UART_HWCONTROL_NONE, + .mode = STM32_UART_MODE_TX_RX, + .fifo_mode = STM32_UART_FIFOMODE_EN, +}; + +int stm32cubeprog_uart_load(uintptr_t instance, uintptr_t base, size_t len) +{ + int ret; + + if (stm32_uart_init(&handle.uart, instance, &init) != 0) { + return -EIO; + } + + /* + * The following NACK_BYTE is written because STM32CubeProgrammer has + * already sent its command before TF-A has reached this point, and + * because FIFO was not configured by BootROM. + * The byte in the UART_RX register is then the checksum and not the + * command. NACK_BYTE has to be written, so that the programmer will + * re-send the good command. + */ + ret = uart_send_result(NACK_BYTE); + if (ret != 0) { + return ret; + } + + return uart_read(PHASE_SSBL, base, len); +} diff --git a/plat/st/common/stm32cubeprogrammer_usb.c b/plat/st/common/stm32cubeprogrammer_usb.c new file mode 100644 index 0000000..75e8038 --- /dev/null +++ b/plat/st/common/stm32cubeprogrammer_usb.c @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2021-2022, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <errno.h> +#include <string.h> + +#include <tools_share/firmware_image_package.h> + +#include <stm32cubeprogrammer.h> +#include <usb_dfu.h> + +/* Undefined download address */ +#define UNDEFINED_DOWN_ADDR 0xFFFFFFFF + +struct dfu_state { + uint8_t phase; + uintptr_t base; + size_t len; + uintptr_t address; + /* working buffer */ + uint8_t buffer[UCHAR_MAX]; +}; + +static struct dfu_state dfu_state; + +/* minimal size of Get Pḧase = offset for additionnl information */ +#define GET_PHASE_LEN 9 + +#define DFU_ERROR(...) \ + { \ + ERROR(__VA_ARGS__); \ + if (dfu->phase != PHASE_RESET) { \ + snprintf((char *)&dfu->buffer[GET_PHASE_LEN], \ + sizeof(dfu->buffer) - GET_PHASE_LEN, \ + __VA_ARGS__); \ + dfu->phase = PHASE_RESET; \ + dfu->address = UNDEFINED_DOWN_ADDR; \ + dfu->len = 0; \ + } \ + } + +static bool is_valid_header(fip_toc_header_t *header) +{ + if ((header->name == TOC_HEADER_NAME) && (header->serial_number != 0U)) { + return true; + } + + return false; +} + +static int dfu_callback_upload(uint8_t alt, uintptr_t *buffer, uint32_t *len, + void *user_data) +{ + int result = 0; + uint32_t length = 0; + struct dfu_state *dfu = (struct dfu_state *)user_data; + + switch (usb_dfu_get_phase(alt)) { + case PHASE_CMD: + /* Get Pḧase */ + dfu->buffer[0] = dfu->phase; + dfu->buffer[1] = (uint8_t)(dfu->address); + dfu->buffer[2] = (uint8_t)(dfu->address >> 8); + dfu->buffer[3] = (uint8_t)(dfu->address >> 16); + dfu->buffer[4] = (uint8_t)(dfu->address >> 24); + dfu->buffer[5] = 0x00; + dfu->buffer[6] = 0x00; + dfu->buffer[7] = 0x00; + dfu->buffer[8] = 0x00; + length = GET_PHASE_LEN; + if (dfu->phase == PHASE_FLASHLAYOUT && + dfu->address == UNDEFINED_DOWN_ADDR) { + INFO("Send detach request\n"); + dfu->buffer[length++] = 0x01; + } + if (dfu->phase == PHASE_RESET) { + /* error information is added by DFU_ERROR macro */ + length += strnlen((char *)&dfu->buffer[GET_PHASE_LEN], + sizeof(dfu->buffer) - GET_PHASE_LEN) + - 1; + } + break; + + default: + DFU_ERROR("phase ID :%i, alternate %i for phase %i\n", + dfu->phase, alt, usb_dfu_get_phase(alt)); + result = -EIO; + break; + } + + if (result == 0) { + *len = length; + *buffer = (uintptr_t)dfu->buffer; + } + + return result; +} + +static int dfu_callback_download(uint8_t alt, uintptr_t *buffer, uint32_t *len, + void *user_data) +{ + struct dfu_state *dfu = (struct dfu_state *)user_data; + + if ((dfu->phase != usb_dfu_get_phase(alt)) || + (dfu->address == UNDEFINED_DOWN_ADDR)) { + DFU_ERROR("phase ID :%i, alternate %i, address %x\n", + dfu->phase, alt, (uint32_t)dfu->address); + return -EIO; + } + + VERBOSE("Download %d %lx %x\n", alt, dfu->address, *len); + *buffer = dfu->address; + dfu->address += *len; + + if (dfu->address - dfu->base > dfu->len) { + return -EIO; + } + + return 0; +} + +static int dfu_callback_manifestation(uint8_t alt, void *user_data) +{ + struct dfu_state *dfu = (struct dfu_state *)user_data; + + if (dfu->phase != usb_dfu_get_phase(alt)) { + ERROR("Manifestation phase ID :%i, alternate %i, address %lx\n", + dfu->phase, alt, dfu->address); + return -EIO; + } + + INFO("phase ID :%i, Manifestation %d at %lx\n", + dfu->phase, alt, dfu->address); + + switch (dfu->phase) { + case PHASE_SSBL: + if (!is_valid_header((fip_toc_header_t *)dfu->base)) { + DFU_ERROR("FIP Header check failed for phase %d\n", alt); + return -EIO; + } + VERBOSE("FIP header looks OK.\n"); + + /* Configure End with request detach */ + dfu->phase = PHASE_FLASHLAYOUT; + dfu->address = UNDEFINED_DOWN_ADDR; + dfu->len = 0; + break; + default: + DFU_ERROR("Unknown phase\n"); + } + + return 0; +} + +/* Open a connection to the USB device */ +static const struct usb_dfu_media usb_dfu_fops = { + .upload = dfu_callback_upload, + .download = dfu_callback_download, + .manifestation = dfu_callback_manifestation, +}; + +int stm32cubeprog_usb_load(struct usb_handle *usb_core_handle, + uintptr_t base, + size_t len) +{ + int ret; + + usb_core_handle->user_data = (void *)&dfu_state; + + INFO("DFU USB START...\n"); + ret = usb_core_start(usb_core_handle); + if (ret != USBD_OK) { + return -EIO; + } + + dfu_state.phase = PHASE_SSBL; + dfu_state.address = base; + dfu_state.base = base; + dfu_state.len = len; + + ret = usb_dfu_loop(usb_core_handle, &usb_dfu_fops); + if (ret != USBD_OK) { + return -EIO; + } + + INFO("DFU USB STOP...\n"); + ret = usb_core_stop(usb_core_handle); + if (ret != USBD_OK) { + return -EIO; + } + + return 0; +} diff --git a/plat/st/common/stm32mp_common.c b/plat/st/common/stm32mp_common.c new file mode 100644 index 0000000..bb56bac --- /dev/null +++ b/plat/st/common/stm32mp_common.c @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <errno.h> + +#include <arch_helpers.h> +#include <common/debug.h> +#include <drivers/clk.h> +#include <drivers/delay_timer.h> +#include <drivers/st/stm32_console.h> +#include <drivers/st/stm32mp_clkfunc.h> +#include <drivers/st/stm32mp_reset.h> +#include <lib/smccc.h> +#include <lib/xlat_tables/xlat_tables_v2.h> +#include <plat/common/platform.h> +#include <services/arm_arch_svc.h> + +#include <platform_def.h> + +#define HEADER_VERSION_MAJOR_MASK GENMASK(23, 16) +#define RESET_TIMEOUT_US_1MS 1000U + +static console_t console; + +uintptr_t plat_get_ns_image_entrypoint(void) +{ + return BL33_BASE; +} + +unsigned int plat_get_syscnt_freq2(void) +{ + return read_cntfrq_el0(); +} + +static uintptr_t boot_ctx_address; +static uint16_t boot_itf_selected; + +void stm32mp_save_boot_ctx_address(uintptr_t address) +{ + boot_api_context_t *boot_context = (boot_api_context_t *)address; + + boot_ctx_address = address; + boot_itf_selected = boot_context->boot_interface_selected; +} + +uintptr_t stm32mp_get_boot_ctx_address(void) +{ + return boot_ctx_address; +} + +uint16_t stm32mp_get_boot_itf_selected(void) +{ + return boot_itf_selected; +} + +uintptr_t stm32mp_ddrctrl_base(void) +{ + return DDRCTRL_BASE; +} + +uintptr_t stm32mp_ddrphyc_base(void) +{ + return DDRPHYC_BASE; +} + +uintptr_t stm32mp_pwr_base(void) +{ + return PWR_BASE; +} + +uintptr_t stm32mp_rcc_base(void) +{ + return RCC_BASE; +} + +bool stm32mp_lock_available(void) +{ + const uint32_t c_m_bits = SCTLR_M_BIT | SCTLR_C_BIT; + + /* The spinlocks are used only when MMU and data cache are enabled */ + return (read_sctlr() & c_m_bits) == c_m_bits; +} + +int stm32mp_map_ddr_non_cacheable(void) +{ + return mmap_add_dynamic_region(STM32MP_DDR_BASE, STM32MP_DDR_BASE, + STM32MP_DDR_MAX_SIZE, + MT_NON_CACHEABLE | MT_RW | MT_SECURE); +} + +int stm32mp_unmap_ddr(void) +{ + return mmap_remove_dynamic_region(STM32MP_DDR_BASE, + 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) +{ + 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 + +static void set_console(uintptr_t base, uint32_t clk_rate) +{ + unsigned int console_flags; + + if (console_stm32_register(base, clk_rate, + (uint32_t)STM32MP_UART_BAUDRATE, &console) == 0) { + panic(); + } + + console_flags = CONSOLE_FLAG_BOOT | CONSOLE_FLAG_CRASH | + CONSOLE_FLAG_TRANSLATE_CRLF; +#if !defined(IMAGE_BL2) && defined(DEBUG) + console_flags |= CONSOLE_FLAG_RUNTIME; +#endif + + console_set_scope(&console, console_flags); +} + +int stm32mp_uart_console_setup(void) +{ + struct dt_node_info dt_uart_info; + uint32_t clk_rate = 0U; + int result; + uint32_t boot_itf __unused; + uint32_t boot_instance __unused; + + result = dt_get_stdout_uart_info(&dt_uart_info); + + if ((result <= 0) || + (dt_uart_info.status == DT_DISABLED)) { + return -ENODEV; + } + +#if defined(IMAGE_BL2) + if ((dt_uart_info.clock < 0) || + (dt_uart_info.reset < 0)) { + return -ENODEV; + } +#endif + +#if STM32MP_UART_PROGRAMMER || !defined(IMAGE_BL2) + stm32_get_boot_interface(&boot_itf, &boot_instance); + + if ((boot_itf == BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART) && + (get_uart_address(boot_instance) == dt_uart_info.base)) { + return -EACCES; + } +#endif + +#if defined(IMAGE_BL2) + if (dt_set_stdout_pinctrl() != 0) { + return -ENODEV; + } + + 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); +#endif + + set_console(dt_uart_info.base, clk_rate); + + return 0; +} + +#if STM32MP_EARLY_CONSOLE +void stm32mp_setup_early_console(void) +{ +#if defined(IMAGE_BL2) || STM32MP_RECONFIGURE_CONSOLE + plat_crash_console_init(); +#endif + set_console(STM32MP_DEBUG_USART_BASE, STM32MP_DEBUG_USART_CLK_FRQ); + NOTICE("Early console setup\n"); +} +#endif /* STM32MP_EARLY_CONSOLE */ + +/***************************************************************************** + * plat_is_smccc_feature_available() - This function checks whether SMCCC + * feature is availabile for platform. + * @fid: SMCCC function id + * + * Return SMC_ARCH_CALL_SUCCESS if SMCCC feature is available and + * SMC_ARCH_CALL_NOT_SUPPORTED otherwise. + *****************************************************************************/ +int32_t plat_is_smccc_feature_available(u_register_t fid) +{ + switch (fid) { + case SMCCC_ARCH_SOC_ID: + return SMC_ARCH_CALL_SUCCESS; + default: + return SMC_ARCH_CALL_NOT_SUPPORTED; + } +} + +/* Get SOC version */ +int32_t plat_get_soc_version(void) +{ + uint32_t chip_id = stm32mp_get_chip_dev_id(); + uint32_t manfid = SOC_ID_SET_JEP_106(JEDEC_ST_BKID, JEDEC_ST_MFID); + + return (int32_t)(manfid | (chip_id & SOC_ID_IMPL_DEF_MASK)); +} + +/* Get SOC revision */ +int32_t plat_get_soc_revision(void) +{ + return (int32_t)(stm32mp_get_chip_version() & SOC_ID_REV_MASK); +} diff --git a/plat/st/common/stm32mp_crypto_lib.c b/plat/st/common/stm32mp_crypto_lib.c new file mode 100644 index 0000000..d644242 --- /dev/null +++ b/plat/st/common/stm32mp_crypto_lib.c @@ -0,0 +1,661 @@ +/* + * Copyright (c) 2022, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <endian.h> +#include <errno.h> + +#include <common/debug.h> +#include <drivers/auth/crypto_mod.h> +#include <drivers/io/io_storage.h> +#include <drivers/st/bsec.h> +#include <drivers/st/stm32_hash.h> +#include <drivers/st/stm32_pka.h> +#include <drivers/st/stm32_rng.h> +#include <drivers/st/stm32_saes.h> +#include <lib/xlat_tables/xlat_tables_v2.h> +#include <mbedtls/asn1.h> +#include <mbedtls/md.h> +#include <mbedtls/oid.h> +#include <mbedtls/platform.h> +#include <mbedtls/x509.h> +#include <plat/common/platform.h> +#include <tools_share/firmware_encrypted.h> + +#include <platform_def.h> + +#define CRYPTO_HASH_MAX_SIZE 32U +#define CRYPTO_SIGN_MAX_SIZE 64U +#define CRYPTO_PUBKEY_MAX_SIZE 64U +#define CRYPTO_MAX_TAG_SIZE 16U + +/* brainpoolP256t1 OID is not defined in mbedTLS */ +#define OID_EC_GRP_BP256T1 MBEDTLS_OID_EC_BRAINPOOL_V1 "\x08" + +#if STM32MP_CRYPTO_ROM_LIB +struct stm32mp_auth_ops { + uint32_t (*verify_signature)(uint8_t *hash_in, uint8_t *pubkey_in, + uint8_t *signature, uint32_t ecc_algo); +}; + +static struct stm32mp_auth_ops auth_ops; +#endif + +static void crypto_lib_init(void) +{ + boot_api_context_t *boot_context __maybe_unused; + int ret; + + NOTICE("TRUSTED_BOARD_BOOT support enabled\n"); + + ret = stm32_hash_register(); + if (ret != 0) { + ERROR("HASH init (%d)\n", ret); + panic(); + } + + if (stm32mp_is_closed_device() || stm32mp_is_auth_supported()) { +#if STM32MP_CRYPTO_ROM_LIB + boot_context = (boot_api_context_t *)stm32mp_get_boot_ctx_address(); + auth_ops.verify_signature = boot_context->bootrom_ecdsa_verify_signature; +#else + /* Use hardware peripherals */ + if (stm32_rng_init() != 0) { + panic(); + } + + if (stm32_saes_driver_init() != 0) { + panic(); + } + + if (stm32_pka_init() != 0) { + panic(); + } +#endif + } +} + +int get_plain_pk_from_asn1(void *pk_ptr, unsigned int pk_len, void **plain_pk, + unsigned int *len, int *pk_alg) +{ + int ret; + mbedtls_pk_context mbedtls_pk = {0}; + unsigned char *p, *end; + mbedtls_asn1_buf alg_params = {0}; + mbedtls_asn1_buf alg_oid = {0}; + + *plain_pk = NULL; + *len = 0U; + + /* Parse the public key */ + mbedtls_pk_init(&mbedtls_pk); + p = (unsigned char *)pk_ptr; + end = (unsigned char *)(p + pk_len); + + ret = mbedtls_asn1_get_tag(&p, end, len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); + if (ret != 0) { + return -EINVAL; + } + + end = p + *len; + ret = mbedtls_asn1_get_alg(&p, end, &alg_oid, &alg_params); + if (ret != 0) { + VERBOSE("%s: mbedtls_asn1_get_alg (%d)\n", __func__, ret); + return -EINVAL; + } + + if (pk_alg != NULL) { + if ((strlen(MBEDTLS_OID_EC_GRP_SECP256R1) == alg_params.len) && + (memcmp(MBEDTLS_OID_EC_GRP_SECP256R1, alg_params.p, alg_params.len) == 0)) { + *pk_alg = BOOT_API_ECDSA_ALGO_TYPE_P256NIST; + } else if ((strlen(OID_EC_GRP_BP256T1) == alg_params.len) && + (memcmp(OID_EC_GRP_BP256T1, alg_params.p, alg_params.len) == 0)) { + *pk_alg = BOOT_API_ECDSA_ALGO_TYPE_BRAINPOOL256; + } else { + ERROR("%s: Algorithm is not supported\n", __func__); + return -EINVAL; + } + } + + ret = mbedtls_asn1_get_bitstring_null(&p, end, len); + if (ret != 0) { + VERBOSE("%s: mbedtls_asn1_get_bitstring_null (%d)\n", __func__, ret); + return -EINVAL; + } + + /* We remove the ident (0x04) first byte. */ + if ((*len < 1U) || (p[0] != MBEDTLS_ASN1_OCTET_STRING)) { + VERBOSE("%s: not expected len or tag\n", __func__); + return -EINVAL; + } + + *len = *len - 1U; + *plain_pk = p + 1U; + + return 0; +} + +#if STM32MP_CRYPTO_ROM_LIB +uint32_t verify_signature(uint8_t *hash_in, uint8_t *pubkey_in, + uint8_t *signature, uint32_t ecc_algo) +{ + int ret; + + ret = mmap_add_dynamic_region(STM32MP_ROM_BASE, STM32MP_ROM_BASE, + STM32MP_ROM_SIZE_2MB_ALIGNED, MT_CODE | MT_SECURE); + if (ret != 0) { + VERBOSE("%s: mmap_add_dynamic_region (%d)\n", __func__, ret); + return CRYPTO_ERR_SIGNATURE; + } + + ret = auth_ops.verify_signature(hash_in, pubkey_in, signature, ecc_algo); + + if (ret != BOOT_API_RETURN_OK) { + VERBOSE("%s: auth_ops.verify_sign (%d)\n", __func__, ret); + ret = CRYPTO_ERR_SIGNATURE; + } else { + ret = 0; + } + + mmap_remove_dynamic_region(STM32MP_ROM_BASE, STM32MP_ROM_SIZE_2MB_ALIGNED); + + return ret; +} + +int plat_convert_pk(void *full_pk_ptr, unsigned int full_pk_len, + void **hashed_pk_ptr, unsigned int *hashed_pk_len) +{ + return get_plain_pk_from_asn1(full_pk_ptr, full_pk_len, hashed_pk_ptr, hashed_pk_len, NULL); +} +#else /* STM32MP_CRYPTO_ROM_LIB*/ +static uint32_t verify_signature(uint8_t *hash_in, uint8_t *pubkey_in, + uint8_t *signature, uint32_t ecc_algo) +{ + int ret = -1; + enum stm32_pka_ecdsa_curve_id cid; + + switch (ecc_algo) { + case BOOT_API_ECDSA_ALGO_TYPE_P256NIST: +#if PKA_USE_NIST_P256 + cid = PKA_NIST_P256; + ret = 0; +#else + WARN("%s nist_p256 requested but not included\n", __func__); +#endif + break; + case BOOT_API_ECDSA_ALGO_TYPE_BRAINPOOL256: +#if PKA_USE_BRAINPOOL_P256T1 + cid = PKA_BRAINPOOL_P256T1; + ret = 0; +#else + WARN("%s brainpool_p256t1 requested but not included\n", __func__); +#endif + break; + default: + WARN("%s unexpected ecc_algo(%u)\n", __func__, ecc_algo); + break; + } + + if (ret < 0) { + return CRYPTO_ERR_SIGNATURE; + } + + ret = stm32_pka_ecdsa_verif(hash_in, + BOOT_API_SHA256_DIGEST_SIZE_IN_BYTES, + signature, BOOT_API_ECDSA_SIGNATURE_LEN_IN_BYTES / 2U, + signature + BOOT_API_ECDSA_SIGNATURE_LEN_IN_BYTES / 2U, + BOOT_API_ECDSA_SIGNATURE_LEN_IN_BYTES / 2U, + pubkey_in, BOOT_API_ECDSA_PUB_KEY_LEN_IN_BYTES / 2U, + pubkey_in + BOOT_API_ECDSA_PUB_KEY_LEN_IN_BYTES / 2U, + BOOT_API_ECDSA_PUB_KEY_LEN_IN_BYTES / 2U, cid); + if (ret < 0) { + return CRYPTO_ERR_SIGNATURE; + } + + return 0; +} + +int plat_convert_pk(void *full_pk_ptr, unsigned int full_pk_len, + void **hashed_pk_ptr, unsigned int *hashed_pk_len) +{ + static uint8_t st_pk[CRYPTO_PUBKEY_MAX_SIZE + sizeof(uint32_t)]; + int ret; + void *plain_pk; + unsigned int len; + int curve_id; + uint32_t cid; + + ret = get_plain_pk_from_asn1(full_pk_ptr, full_pk_len, &plain_pk, &len, &curve_id); + if ((ret != 0) || (len > CRYPTO_PUBKEY_MAX_SIZE)) { + return -EINVAL; + } + + cid = curve_id; /* we want value of curve_id (1 or 2) in a uint32_t */ + + memcpy(st_pk, &cid, sizeof(cid)); + memcpy(st_pk + sizeof(cid), plain_pk, len); + + *hashed_pk_ptr = st_pk; + *hashed_pk_len = len + sizeof(cid); + + return 0; +} +#endif /* STM32MP_CRYPTO_ROM_LIB */ + +static int get_plain_digest_from_asn1(void *digest_ptr, unsigned int digest_len, + uint8_t **out, size_t *out_len, mbedtls_md_type_t *md_alg) +{ + int ret; + mbedtls_asn1_buf hash_oid, params; + size_t len; + unsigned char *p, *end; + + *out = NULL; + *out_len = 0U; + + /* Digest info should be an MBEDTLS_ASN1_SEQUENCE */ + p = (unsigned char *)digest_ptr; + end = p + digest_len; + ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE); + if (ret != 0) { + return ret; + } + + /* Get the hash algorithm */ + ret = mbedtls_asn1_get_alg(&p, end, &hash_oid, ¶ms); + if (ret != 0) { + return ret; + } + + ret = mbedtls_oid_get_md_alg(&hash_oid, md_alg); + if (ret != 0) { + return ret; + } + + ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OCTET_STRING); + if (ret != 0) { + return ret; + } + + /* Length of hash must match the algorithm's size */ + if (len != BOOT_API_SHA256_DIGEST_SIZE_IN_BYTES) { + return -1; + } + + *out = p; + *out_len = len; + + return 0; +} + +static int crypto_verify_signature(void *data_ptr, unsigned int data_len, + void *sig_ptr, unsigned int sig_len, + void *sig_alg, unsigned int sig_alg_len, + void *pk_ptr, unsigned int pk_len) +{ + uint8_t image_hash[CRYPTO_HASH_MAX_SIZE] = {0}; + uint8_t sig[CRYPTO_SIGN_MAX_SIZE]; + uint8_t my_pk[CRYPTO_PUBKEY_MAX_SIZE]; + int ret; + size_t len; + mbedtls_asn1_sequence seq; + mbedtls_asn1_sequence *cur; + unsigned char *p, *end; + int curve_id; + mbedtls_asn1_buf sig_oid, sig_params; + mbedtls_md_type_t md_alg; + mbedtls_pk_type_t pk_alg; + size_t bignum_len = sizeof(sig) / 2U; + unsigned int seq_num = 0U; + + if (!stm32mp_is_closed_device() && !stm32mp_is_auth_supported()) { + return CRYPTO_SUCCESS; + } + + /* Get pointers to signature OID and parameters */ + p = (unsigned char *)sig_alg; + end = (unsigned char *)(p + sig_alg_len); + ret = mbedtls_asn1_get_alg(&p, end, &sig_oid, &sig_params); + if (ret != 0) { + VERBOSE("%s: mbedtls_asn1_get_alg (%d)\n", __func__, ret); + return CRYPTO_ERR_SIGNATURE; + } + + /* Get the actual signature algorithm (MD + PK) */ + ret = mbedtls_oid_get_sig_alg(&sig_oid, &md_alg, &pk_alg); + if (ret != 0) { + VERBOSE("%s: mbedtls_oid_get_sig_alg (%d)\n", __func__, ret); + return CRYPTO_ERR_SIGNATURE; + } + + if ((md_alg != MBEDTLS_MD_SHA256) || (pk_alg != MBEDTLS_PK_ECDSA)) { + VERBOSE("%s: md_alg=%u pk_alg=%u\n", __func__, md_alg, pk_alg); + return CRYPTO_ERR_SIGNATURE; + } + + ret = get_plain_pk_from_asn1(pk_ptr, pk_len, &pk_ptr, &pk_len, &curve_id); + if (ret != 0) { + VERBOSE("%s: get_plain_pk_from_asn1 (%d)\n", __func__, ret); + return CRYPTO_ERR_SIGNATURE; + } + + /* We expect a known pk_len */ + if (pk_len != sizeof(my_pk)) { + VERBOSE("%s: pk_len=%u sizeof(my_pk)=%zu)\n", __func__, pk_len, sizeof(my_pk)); + return CRYPTO_ERR_SIGNATURE; + } + + /* Need to copy as auth_ops.verify_signature + * expects aligned public key. + */ + memcpy(my_pk, pk_ptr, sizeof(my_pk)); + + /* Get the signature (bitstring) */ + p = (unsigned char *)sig_ptr; + end = (unsigned char *)(p + sig_len); + ret = mbedtls_asn1_get_bitstring_null(&p, end, &len); + if (ret != 0) { + VERBOSE("%s: mbedtls_asn1_get_bitstring_null (%d)\n", __func__, ret); + return CRYPTO_ERR_SIGNATURE; + } + + /* Get r and s from sequence */ + ret = mbedtls_asn1_get_sequence_of(&p, end, &seq, MBEDTLS_ASN1_INTEGER); + if (ret != 0) { + VERBOSE("%s: mbedtls_asn1_get_sequence_of (%d)\n", __func__, ret); + return CRYPTO_ERR_SIGNATURE; + } + + /* We expect only 2 integers (r and s) from the sequence */ + if (seq.next->next != NULL) { + cur = seq.next; + mbedtls_asn1_sequence *next; + + VERBOSE("%s: nb seq != 2\n", __func__); + /* Free all the sequences */ + while (cur != NULL) { + next = cur->next; + mbedtls_free(cur); + cur = next; + } + + return CRYPTO_ERR_SIGNATURE; + } + + /* + * ECDSA signatures are composed of a tuple (R,S) where R and S are between 0 and n. + * This means that the R and S can have a maximum of 32 each, but can also be smaller. + * Also seen the integer sequence may (sometime) start with 0x00 as MSB, but we can only + * manage exactly 2*32 bytes, we remove this higher byte if there are not 00, + * we will fail either. + */ + cur = &seq; + memset(sig, 0U, sizeof(sig)); + + while (cur != NULL) { + size_t skip = 0U; + size_t seek = seq_num * bignum_len; + + if (cur->buf.len > bignum_len) { + /* Remove extra 0x00 bytes */ + skip = cur->buf.len - bignum_len; + } else if (cur->buf.len < bignum_len) { + /* Add padding to match HW required size */ + seek += (bignum_len % cur->buf.len); + } + + if (seek + cur->buf.len > sizeof(sig) + skip) { + panic(); + } + + memcpy(sig + seek, cur->buf.p + skip, cur->buf.len - skip); + cur = cur->next; + seq_num++; + } + + /* Need to free allocated 'next' in mbedtls_asn1_get_sequence_of */ + mbedtls_free(seq.next); + + /* Compute hash for the data covered by the signature */ + stm32_hash_init(HASH_SHA256); + + ret = stm32_hash_final_update((uint8_t *)data_ptr, data_len, image_hash); + if (ret != 0) { + VERBOSE("%s: stm32_hash_final_update (%d)\n", __func__, ret); + return CRYPTO_ERR_SIGNATURE; + } + + return verify_signature(image_hash, my_pk, sig, curve_id); +} + +static int crypto_verify_hash(void *data_ptr, unsigned int data_len, + void *digest_info_ptr, + unsigned int digest_info_len) +{ + int ret; + uint8_t calc_hash[BOOT_API_SHA256_DIGEST_SIZE_IN_BYTES]; + unsigned char *p; + mbedtls_md_type_t md_alg; + size_t len; + + /* we receive an asn1 encapsulated digest, we flatten it */ + ret = get_plain_digest_from_asn1(digest_info_ptr, + digest_info_len, &p, &len, + &md_alg); + if ((ret != 0) || (md_alg != MBEDTLS_MD_SHA256) || (len != sizeof(calc_hash))) { + return CRYPTO_ERR_HASH; + } + + digest_info_ptr = p; + digest_info_len = len; + + stm32_hash_init(HASH_SHA256); + + ret = stm32_hash_final_update(data_ptr, data_len, calc_hash); + if (ret != 0) { + VERBOSE("%s: hash failed\n", __func__); + return CRYPTO_ERR_HASH; + } + + ret = memcmp(calc_hash, digest_info_ptr, digest_info_len); + if (ret != 0) { + VERBOSE("%s: not expected digest\n", __func__); + ret = CRYPTO_ERR_HASH; + } + + return ret; +} + +#if !defined(DECRYPTION_SUPPORT_none) +static int derive_key(uint8_t *key, size_t *key_len, size_t len, + unsigned int *flags, const uint8_t *img_id, size_t img_id_len) +{ + size_t i, j; + + assert(*key_len >= 32U); + + /* + * Not a real derivation yet + * + * But we expect a 32 bytes key, and OTP is only 16 bytes + * => duplicate. + */ + for (i = 0U, j = len; j < 32U; + i += sizeof(uint32_t), j += sizeof(uint32_t)) { + memcpy(key + j, key + i, sizeof(uint32_t)); + } + + *key_len = 32U; + /* Variable 'key' store a real key */ + *flags = 0U; + + return 0; +} + +int plat_get_enc_key_info(enum fw_enc_status_t fw_enc_status, uint8_t *key, + size_t *key_len, unsigned int *flags, + const uint8_t *img_id, size_t img_id_len) +{ + uint32_t otp_idx; + uint32_t otp_len; + size_t read_len; + size_t i; + + if (fw_enc_status == FW_ENC_WITH_BSSK) { + return -EINVAL; + } + + if (stm32_get_otp_index(ENCKEY_OTP, &otp_idx, &otp_len) != 0) { + VERBOSE("%s: get %s index error\n", __func__, ENCKEY_OTP); + return -EINVAL; + } + + if (otp_len > (*key_len * CHAR_BIT)) { + VERBOSE("%s: length Error otp_len=%u key_len=%u\n", __func__, + otp_len, *key_len * CHAR_BIT); + return -EINVAL; + } + + read_len = otp_len / CHAR_BIT; + assert(read_len % sizeof(uint32_t) == 0); + + for (i = 0U; i < read_len / sizeof(uint32_t); i++) { + uint32_t tmp; + uint32_t otp_val; + + if (stm32_get_otp_value_from_idx(otp_idx + i, &otp_val) != 0) { + zeromem(key, *key_len); + VERBOSE("%s: unable to read from otp\n", __func__); + return -EINVAL; + } + + tmp = bswap32(otp_val); + memcpy(key + i * sizeof(uint32_t), &tmp, sizeof(tmp)); + } + + /* Now we have the OTP values in key till read_len */ + + if (derive_key(key, key_len, read_len, flags, img_id, + img_id_len) != 0) { + zeromem(key, *key_len); + return -EINVAL; + } + + return 0; +} + +static enum stm32_saes_key_selection select_key(unsigned int key_flags) +{ + if ((key_flags & ENC_KEY_IS_IDENTIFIER) != 0U) { + panic(); + } + + /* Use the provided key buffer */ + return STM32_SAES_KEY_SOFT; +} + +static int stm32_decrypt_aes_gcm(void *data, size_t data_len, + const void *key, unsigned int key_len, + unsigned int key_flags, + const void *iv, unsigned int iv_len, + const void *tag, unsigned int tag_len) +{ + int ret; + struct stm32_saes_context ctx; + unsigned char tag_buf[CRYPTO_MAX_TAG_SIZE]; + enum stm32_saes_key_selection key_mode; + unsigned int diff = 0U; + unsigned int i; + + key_mode = select_key(key_flags); + + ret = stm32_saes_init(&ctx, true, STM32_SAES_MODE_GCM, key_mode, key, + key_len, iv, iv_len); + if (ret != 0) { + return CRYPTO_ERR_INIT; + } + + ret = stm32_saes_update_assodata(&ctx, true, NULL, 0U); + if (ret != 0) { + return CRYPTO_ERR_DECRYPTION; + } + + ret = stm32_saes_update_load(&ctx, true, data, data, data_len); + if (ret != 0) { + return CRYPTO_ERR_DECRYPTION; + } + + ret = stm32_saes_final(&ctx, tag_buf, sizeof(tag_buf)); + if (ret != 0) { + return CRYPTO_ERR_DECRYPTION; + } + + /* Check tag in "constant-time" */ + for (i = 0U; i < tag_len; i++) { + diff |= ((const unsigned char *)tag)[i] ^ tag_buf[i]; + } + + if (diff != 0U) { + return CRYPTO_ERR_DECRYPTION; + } + + return CRYPTO_SUCCESS; +} + +/* + * Authenticated decryption of an image + * + */ +static int crypto_auth_decrypt(enum crypto_dec_algo dec_algo, void *data_ptr, size_t len, + const void *key, unsigned int key_len, unsigned int key_flags, + const void *iv, unsigned int iv_len, const void *tag, + unsigned int tag_len) +{ + int rc = -1; + uint32_t real_iv[4]; + + switch (dec_algo) { + case CRYPTO_GCM_DECRYPT: + /* + * GCM expect a Nonce + * The AES IV is the nonce (a uint32_t[3]) + * then a counter (a uint32_t big endian) + * The counter starts at 2. + */ + memcpy(real_iv, iv, iv_len); + real_iv[3] = htobe32(0x2U); + + rc = stm32_decrypt_aes_gcm(data_ptr, len, key, key_len, key_flags, + real_iv, sizeof(real_iv), tag, tag_len); + break; + default: + rc = CRYPTO_ERR_DECRYPTION; + break; + } + + if (rc != 0) { + return rc; + } + + return CRYPTO_SUCCESS; +} + +REGISTER_CRYPTO_LIB("stm32_crypto_lib", + crypto_lib_init, + crypto_verify_signature, + crypto_verify_hash, + crypto_auth_decrypt); + +#else /* No decryption support */ +REGISTER_CRYPTO_LIB("stm32_crypto_lib", + crypto_lib_init, + crypto_verify_signature, + crypto_verify_hash, + NULL); + +#endif diff --git a/plat/st/common/stm32mp_dt.c b/plat/st/common/stm32mp_dt.c new file mode 100644 index 0000000..c9efeb5 --- /dev/null +++ b/plat/st/common/stm32mp_dt.c @@ -0,0 +1,429 @@ +/* + * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <errno.h> + +#include <common/debug.h> +#include <common/fdt_wrappers.h> +#include <drivers/st/regulator.h> +#include <drivers/st/stm32_gpio.h> +#include <libfdt.h> + +#include <platform_def.h> +#include <stm32mp_dt.h> + +static void *fdt; + +/******************************************************************************* + * This function checks device tree file with its header. + * Returns 0 on success and a negative FDT error code on failure. + ******************************************************************************/ +int dt_open_and_check(uintptr_t dt_addr) +{ + int ret; + + ret = fdt_check_header((void *)dt_addr); + if (ret == 0) { + fdt = (void *)dt_addr; + } + + return ret; +} + +/******************************************************************************* + * This function gets the address of the DT. + * If DT is OK, fdt_addr is filled with DT address. + * Returns 1 if success, 0 otherwise. + ******************************************************************************/ +int fdt_get_address(void **fdt_addr) +{ + if (fdt == NULL) { + return 0; + } + + *fdt_addr = fdt; + + return 1; +} + +/******************************************************************************* + * This function check the presence of a node (generic use of fdt library). + * Returns true if present, else return false. + ******************************************************************************/ +bool fdt_check_node(int node) +{ + int len; + const char *cchar; + + cchar = fdt_get_name(fdt, node, &len); + + return (cchar != NULL) && (len >= 0); +} + +/******************************************************************************* + * This function return global node status (generic use of fdt library). + ******************************************************************************/ +uint8_t fdt_get_status(int node) +{ + uint8_t status = DT_DISABLED; + const char *cchar; + + cchar = fdt_getprop(fdt, node, "status", NULL); + if ((cchar == NULL) || + (strncmp(cchar, "okay", strlen("okay")) == 0)) { + status |= DT_NON_SECURE; + } + + cchar = fdt_getprop(fdt, node, "secure-status", NULL); + if (cchar == NULL) { + if (status == DT_NON_SECURE) { + status |= DT_SECURE; + } + } else if (strncmp(cchar, "okay", strlen("okay")) == 0) { + status |= DT_SECURE; + } + + return status; +} + +#if ENABLE_ASSERTIONS +/******************************************************************************* + * This function returns the address cells from the node parent. + * Returns: + * - #address-cells value if success. + * - invalid value if error. + * - a default value if undefined #address-cells property as per libfdt + * implementation. + ******************************************************************************/ +static int fdt_get_node_parent_address_cells(int node) +{ + int parent; + + parent = fdt_parent_offset(fdt, node); + if (parent < 0) { + return -FDT_ERR_NOTFOUND; + } + + return fdt_address_cells(fdt, parent); +} +#endif + +/******************************************************************************* + * This function gets the stdout pin configuration information from the DT. + * And then calls the sub-function to treat it and set GPIO registers. + * Returns 0 on success and a negative FDT error code on failure. + ******************************************************************************/ +int dt_set_stdout_pinctrl(void) +{ + int node; + + node = fdt_get_stdout_node_offset(fdt); + if (node < 0) { + return -FDT_ERR_NOTFOUND; + } + + return dt_set_pinctrl_config(node); +} + +/******************************************************************************* + * This function fills the generic information from a given node. + ******************************************************************************/ +void dt_fill_device_info(struct dt_node_info *info, int node) +{ + const fdt32_t *cuint; + + assert(fdt_get_node_parent_address_cells(node) == 1); + + cuint = fdt_getprop(fdt, node, "reg", NULL); + if (cuint != NULL) { + info->base = fdt32_to_cpu(*cuint); + } else { + info->base = 0; + } + + cuint = fdt_getprop(fdt, node, "clocks", NULL); + if (cuint != NULL) { + cuint++; + info->clock = (int)fdt32_to_cpu(*cuint); + } else { + info->clock = -1; + } + + cuint = fdt_getprop(fdt, node, "resets", NULL); + if (cuint != NULL) { + cuint++; + info->reset = (int)fdt32_to_cpu(*cuint); + } else { + info->reset = -1; + } + + info->status = fdt_get_status(node); +} + +/******************************************************************************* + * This function retrieve the generic information from DT. + * Returns node on success and a negative FDT error code on failure. + ******************************************************************************/ +int dt_get_node(struct dt_node_info *info, int offset, const char *compat) +{ + int node; + + node = fdt_node_offset_by_compatible(fdt, offset, compat); + if (node < 0) { + return -FDT_ERR_NOTFOUND; + } + + dt_fill_device_info(info, node); + + return node; +} + +/******************************************************************************* + * This function gets the UART instance info of stdout from the DT. + * Returns node on success and a negative FDT error code on failure. + ******************************************************************************/ +int dt_get_stdout_uart_info(struct dt_node_info *info) +{ + int node; + + node = fdt_get_stdout_node_offset(fdt); + if (node < 0) { + return -FDT_ERR_NOTFOUND; + } + + dt_fill_device_info(info, node); + + return node; +} + +/******************************************************************************* + * This function returns the node offset matching compatible string in the DT, + * and also matching the reg property with the given address. + * Returns value on success, and error value on failure. + ******************************************************************************/ +int dt_match_instance_by_compatible(const char *compatible, uintptr_t address) +{ + int node; + + fdt_for_each_compatible_node(fdt, node, compatible) { + const fdt32_t *cuint; + + assert(fdt_get_node_parent_address_cells(node) == 1); + + cuint = fdt_getprop(fdt, node, "reg", NULL); + if (cuint == NULL) { + continue; + } + + if ((uintptr_t)fdt32_to_cpu(*cuint) == address) { + return node; + } + } + + return -FDT_ERR_NOTFOUND; +} + +/******************************************************************************* + * This function gets DDR size information from the DT. + * Returns value in bytes on success, and 0 on failure. + ******************************************************************************/ +uint32_t dt_get_ddr_size(void) +{ + static uint32_t size; + int node; + + if (size != 0U) { + return size; + } + + node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT); + if (node < 0) { + INFO("%s: Cannot read DDR node in DT\n", __func__); + return 0; + } + + size = fdt_read_uint32_default(fdt, node, "st,mem-size", 0U); + + flush_dcache_range((uintptr_t)&size, sizeof(uint32_t)); + + return size; +} + +/******************************************************************************* + * This function gets PWR VDD regulator voltage information from the DT. + * Returns value in microvolts on success, and 0 on failure. + ******************************************************************************/ +uint32_t dt_get_pwr_vdd_voltage(void) +{ + struct rdev *regul = dt_get_vdd_regulator(); + uint16_t min; + + if (regul == NULL) { + return 0; + } + + regulator_get_range(regul, &min, NULL); + + return (uint32_t)min * 1000U; +} + +/******************************************************************************* + * This function retrieves VDD supply regulator from DT. + * Returns an rdev taken from supply node, NULL otherwise. + ******************************************************************************/ +struct rdev *dt_get_vdd_regulator(void) +{ + int node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT); + + if (node < 0) { + return NULL; + } + + return regulator_get_by_supply_name(fdt, node, "vdd"); +} + +/******************************************************************************* + * This function retrieves CPU supply regulator from DT. + * Returns an rdev taken from supply node, NULL otherwise. + ******************************************************************************/ +struct rdev *dt_get_cpu_regulator(void) +{ + int node = fdt_path_offset(fdt, "/cpus/cpu@0"); + + if (node < 0) { + return NULL; + } + + return regulator_get_by_supply_name(fdt, node, "cpu"); +} + +/******************************************************************************* + * This function retrieves board model from DT + * Returns string taken from model node, NULL otherwise + ******************************************************************************/ +const char *dt_get_board_model(void) +{ + int node = fdt_path_offset(fdt, "/"); + + if (node < 0) { + return NULL; + } + + 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 len; + const fdt32_t *cuint; + + if ((name == NULL) || (otp == NULL)) { + return -FDT_ERR_BADVALUE; + } + + node = fdt_node_offset_by_compatible(fdt, -1, DT_BSEC_COMPAT); + if (node < 0) { + return node; + } + + node = fdt_subnode_offset(fdt, node, name); + if (node < 0) { + ERROR("nvmem node %s not found\n", name); + return node; + } + + cuint = fdt_getprop(fdt, node, "reg", &len); + if ((cuint == NULL) || (len != (2 * (int)sizeof(uint32_t)))) { + ERROR("Malformed nvmem node %s: ignored\n", name); + return -FDT_ERR_BADVALUE; + } + + if (fdt32_to_cpu(*cuint) % sizeof(uint32_t)) { + ERROR("Misaligned nvmem %s element: ignored\n", name); + 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. + ******************************************************************************/ +int fdt_get_gpio_bank_pin_count(unsigned int bank) +{ + int pinctrl_node; + int node; + uint32_t bank_offset; + + pinctrl_node = stm32_get_gpio_bank_pinctrl_node(fdt, bank); + if (pinctrl_node < 0) { + return -FDT_ERR_NOTFOUND; + } + + bank_offset = stm32_get_gpio_bank_offset(bank); + + fdt_for_each_subnode(node, fdt, pinctrl_node) { + const fdt32_t *cuint; + int pin_count; + int len; + int i; + + if (fdt_getprop(fdt, node, "gpio-controller", NULL) == NULL) { + continue; + } + + cuint = fdt_getprop(fdt, node, "reg", NULL); + if (cuint == NULL) { + continue; + } + + if (fdt32_to_cpu(*cuint) != bank_offset) { + continue; + } + + if (fdt_get_status(node) == DT_DISABLED) { + return 0; + } + + /* Parse gpio-ranges with its 4 parameters */ + cuint = fdt_getprop(fdt, node, "gpio-ranges", &len); + len /= sizeof(*cuint); + if ((len % 4) != 0) { + return -FDT_ERR_BADVALUE; + } + + /* Get the last defined gpio line (offset + nb of pins) */ + pin_count = fdt32_to_cpu(*(cuint + 1)) + fdt32_to_cpu(*(cuint + 3)); + for (i = 0; i < len / 4; i++) { + pin_count = MAX(pin_count, (int)(fdt32_to_cpu(*(cuint + 1)) + + fdt32_to_cpu(*(cuint + 3)))); + cuint += 4; + } + + return pin_count; + } + + return 0; +} diff --git a/plat/st/common/stm32mp_fconf_io.c b/plat/st/common/stm32mp_fconf_io.c new file mode 100644 index 0000000..0b6cc78 --- /dev/null +++ b/plat/st/common/stm32mp_fconf_io.c @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2021-2022, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> + +#include <common/debug.h> +#include <common/fdt_wrappers.h> +#include <drivers/io/io_storage.h> +#include <drivers/mmc.h> +#include <lib/fconf/fconf.h> +#include <lib/object_pool.h> +#include <libfdt.h> +#include <tools_share/firmware_image_package.h> + +#include <platform_def.h> +#include <stm32mp_efi.h> +#include <stm32mp_fconf_getter.h> +#include <stm32mp_io_storage.h> + +#if STM32MP_SDMMC || STM32MP_EMMC +static io_block_spec_t gpt_block_spec = { + .offset = 0U, + .length = 34U * MMC_BLOCK_SIZE, /* Size of GPT table */ +}; +#endif + +#if (STM32MP_SDMMC || STM32MP_EMMC) && PSA_FWU_SUPPORT +io_block_spec_t metadata_block_spec = { + .offset = 0, /* To be filled at runtime */ + .length = 0, /* To be filled at runtime */ +}; +#endif /* (STM32MP_SDMMC || STM32MP_EMMC) && PSA_FWU_SUPPORT */ + +/* By default, STM32 platforms load images from the FIP */ +struct plat_io_policy policies[MAX_NUMBER_IDS] = { + [FIP_IMAGE_ID] = { + .dev_handle = &storage_dev_handle, + .image_spec = (uintptr_t)&image_block_spec, + .img_type_guid = STM32MP_FIP_GUID, + .check = open_storage + }, +#ifndef DECRYPTION_SUPPORT_none + [ENC_IMAGE_ID] = { + .dev_handle = &fip_dev_handle, + .image_spec = (uintptr_t)NULL, + .img_type_guid = NULL_GUID, + .check = open_fip + }, +#endif +#if STM32MP_SDMMC || STM32MP_EMMC + [GPT_IMAGE_ID] = { + .dev_handle = &storage_dev_handle, + .image_spec = (uintptr_t)&gpt_block_spec, + .img_type_guid = NULL_GUID, + .check = open_storage + }, +#endif +#if (STM32MP_SDMMC || STM32MP_EMMC) && PSA_FWU_SUPPORT + [FWU_METADATA_IMAGE_ID] = { + .dev_handle = &storage_dev_handle, + .image_spec = (uintptr_t)&metadata_block_spec, + .img_type_guid = NULL_GUID, + .check = open_storage + }, + [BKUP_FWU_METADATA_IMAGE_ID] = { + .dev_handle = &storage_dev_handle, + .image_spec = (uintptr_t)&metadata_block_spec, + .img_type_guid = NULL_GUID, + .check = open_storage + }, +#endif /* (STM32MP_SDMMC || STM32MP_EMMC) && PSA_FWU_SUPPORT */ +}; + +#define DEFAULT_UUID_NUMBER U(7) + +#if TRUSTED_BOARD_BOOT +#define TBBR_UUID_NUMBER U(6) +#else +#define TBBR_UUID_NUMBER U(0) +#endif + +#define FCONF_ST_IO_UUID_NUMBER (DEFAULT_UUID_NUMBER + \ + TBBR_UUID_NUMBER) + +static io_uuid_spec_t fconf_stm32mp_uuids[FCONF_ST_IO_UUID_NUMBER]; +static OBJECT_POOL_ARRAY(fconf_stm32mp_uuids_pool, fconf_stm32mp_uuids); + +struct policies_load_info { + unsigned int image_id; + const char *name; +}; + +/* image id to property name table */ +static const struct policies_load_info load_info[FCONF_ST_IO_UUID_NUMBER] = { + {FW_CONFIG_ID, "fw_cfg_uuid"}, + {BL32_IMAGE_ID, "bl32_uuid"}, + {BL32_EXTRA1_IMAGE_ID, "bl32_extra1_uuid"}, + {BL32_EXTRA2_IMAGE_ID, "bl32_extra2_uuid"}, + {BL33_IMAGE_ID, "bl33_uuid"}, + {HW_CONFIG_ID, "hw_cfg_uuid"}, + {TOS_FW_CONFIG_ID, "tos_fw_cfg_uuid"}, +#if TRUSTED_BOARD_BOOT + {STM32MP_CONFIG_CERT_ID, "stm32mp_cfg_cert_uuid"}, + {TRUSTED_KEY_CERT_ID, "t_key_cert_uuid"}, + {TRUSTED_OS_FW_KEY_CERT_ID, "tos_fw_key_cert_uuid"}, + {NON_TRUSTED_FW_KEY_CERT_ID, "nt_fw_key_cert_uuid"}, + {TRUSTED_OS_FW_CONTENT_CERT_ID, "tos_fw_content_cert_uuid"}, + {NON_TRUSTED_FW_CONTENT_CERT_ID, "nt_fw_content_cert_uuid"}, +#endif /* TRUSTED_BOARD_BOOT */ +}; + +int fconf_populate_stm32mp_io_policies(uintptr_t config) +{ + int node; + unsigned int i; + + /* As libfdt uses void *, we can't avoid this cast */ + const void *dtb = (void *)config; + + /* Assert the node offset point to "st,io-fip-handle" compatible property */ + const char *compatible_str = "st,io-fip-handle"; + + node = fdt_node_offset_by_compatible(dtb, -1, compatible_str); + if (node < 0) { + ERROR("FCONF: Can't find %s compatible in dtb\n", compatible_str); + return node; + } + + /* Locate the uuid cells and read the value for all the load info uuid */ + for (i = 0U; i < FCONF_ST_IO_UUID_NUMBER; i++) { + union uuid_helper_t uuid_helper; + io_uuid_spec_t *uuid_ptr; + int err; + + uuid_ptr = pool_alloc(&fconf_stm32mp_uuids_pool); + err = fdtw_read_uuid(dtb, node, load_info[i].name, 16, + (uint8_t *)&uuid_helper); + if (err < 0) { + WARN("FCONF: Read cell failed for %s\n", load_info[i].name); + return err; + } + + VERBOSE("FCONF: stm32mp-io_policies.%s cell found with value = " + "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", + load_info[i].name, + uuid_helper.uuid_struct.time_low[0], uuid_helper.uuid_struct.time_low[1], + uuid_helper.uuid_struct.time_low[2], uuid_helper.uuid_struct.time_low[3], + uuid_helper.uuid_struct.time_mid[0], uuid_helper.uuid_struct.time_mid[1], + uuid_helper.uuid_struct.time_hi_and_version[0], + uuid_helper.uuid_struct.time_hi_and_version[1], + uuid_helper.uuid_struct.clock_seq_hi_and_reserved, + uuid_helper.uuid_struct.clock_seq_low, + uuid_helper.uuid_struct.node[0], uuid_helper.uuid_struct.node[1], + uuid_helper.uuid_struct.node[2], uuid_helper.uuid_struct.node[3], + uuid_helper.uuid_struct.node[4], uuid_helper.uuid_struct.node[5]); + + uuid_ptr->uuid = uuid_helper.uuid_struct; + policies[load_info[i].image_id].image_spec = (uintptr_t)uuid_ptr; + switch (load_info[i].image_id) { +#if ENCRYPT_BL32 && !defined(DECRYPTION_SUPPORT_none) + case BL32_IMAGE_ID: + case BL32_EXTRA1_IMAGE_ID: + case BL32_EXTRA2_IMAGE_ID: + policies[load_info[i].image_id].dev_handle = &enc_dev_handle; + policies[load_info[i].image_id].check = open_enc_fip; + break; +#endif + default: + policies[load_info[i].image_id].dev_handle = &fip_dev_handle; + policies[load_info[i].image_id].check = open_fip; + break; + } + } + + return 0; +} + +FCONF_REGISTER_POPULATOR(TB_FW, stm32mp_io, fconf_populate_stm32mp_io_policies); diff --git a/plat/st/common/stm32mp_trusted_boot.c b/plat/st/common/stm32mp_trusted_boot.c new file mode 100644 index 0000000..051d6fc --- /dev/null +++ b/plat/st/common/stm32mp_trusted_boot.c @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2022, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <endian.h> +#include <errno.h> +#include <limits.h> + +#include <common/debug.h> +#include <common/tbbr/cot_def.h> +#include <drivers/st/stm32_hash.h> +#include <lib/fconf/fconf.h> +#include <lib/fconf/fconf_dyn_cfg_getter.h> +#include <lib/fconf/fconf_tbbr_getter.h> +#include <lib/mmio.h> +#include <lib/xlat_tables/xlat_tables_v2.h> +#include <plat/common/platform.h> + +#include <boot_api.h> +#include <platform_def.h> + +#define HEADER_AND_EXT_TOTAL_SIZE 512 + +static uint8_t der_sha256_header[] = {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, + 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20}; +static uint8_t root_pk_hash[HASH_DER_LEN]; + +static int copy_hash_from_otp(const char *otp_name, uint8_t *hash, size_t len) +{ + uint32_t otp_idx; + uint32_t otp_len; + size_t i; + bool valid = false; + + assert(len % sizeof(uint32_t) == 0); + + if (stm32_get_otp_index(otp_name, &otp_idx, &otp_len) != 0) { + VERBOSE("%s: get %s index error\n", __func__, otp_name); + return -EINVAL; + } + if (otp_len != (len * CHAR_BIT)) { + VERBOSE("%s: length Error\n", __func__); + return -EINVAL; + } + + for (i = 0U; i < len / sizeof(uint32_t); i++) { + uint32_t tmp; + uint32_t otp_val; + uint32_t first; + + if (stm32_get_otp_value_from_idx(otp_idx + i, &otp_val) != 0) { + VERBOSE("%s: unable to read from otp\n", __func__); + return -EINVAL; + } + + tmp = bswap32(otp_val); + memcpy(hash + i * sizeof(uint32_t), &tmp, sizeof(tmp)); + + if (i == 0U) { + first = tmp; + } + + /* + * Check if key hash values in OTP are 0 or 0xFFFFFFFFF + * programmed : Invalid Key + */ + if (!stm32mp_is_closed_device() && !valid) { + if ((tmp != 0U) && (tmp != 0xFFFFFFFFU) && (tmp != first)) { + valid = true; + } + } + } + + if (!stm32mp_is_closed_device() && !valid) { + return 0; + } + + return len; +} + +#if STM32_HEADER_VERSION_MAJOR == 1 +static int get_rotpk_hash(void *cookie, uint8_t *hash, size_t len) +{ + if (cookie != NULL) { + return -EINVAL; + } + + return copy_hash_from_otp(PKH_OTP, hash, len); +} +#else +static int get_rotpk_hash(void *cookie, uint8_t *hash, size_t len) +{ + int ret; + uint32_t pk_idx = 0U; + uint8_t calc_hash[BOOT_API_SHA256_DIGEST_SIZE_IN_BYTES]; + uint8_t otp_hash[BOOT_API_SHA256_DIGEST_SIZE_IN_BYTES]; + boot_api_image_header_t *hdr = (boot_api_image_header_t *)(SRAM3_BASE + SRAM3_SIZE - + HEADER_AND_EXT_TOTAL_SIZE); + boot_extension_header_t *ext_header = (boot_extension_header_t *)hdr->ext_header; + boot_ext_header_params_authentication_t *param; + + if (cookie != NULL) { + return -EINVAL; + } + + if (hdr->header_version != BOOT_API_HEADER_VERSION) { + VERBOSE("%s: unexpected header_version\n", __func__); + return -EINVAL; + } + + param = (boot_ext_header_params_authentication_t *)ext_header->params; + + pk_idx = param->pk_idx; + + stm32_hash_init(HASH_SHA256); + ret = stm32_hash_final_update((uint8_t *)param->pk_hashes, + param->nb_pk * sizeof(boot_api_sha256_t), calc_hash); + if (ret != 0) { + VERBOSE("%s: hash failed\n", __func__); + return -EINVAL; + } + + ret = copy_hash_from_otp(PKH_OTP, otp_hash, len); + if (ret < 0) { + return -EINVAL; + } + + if (ret != 0) { + ret = memcmp(calc_hash, otp_hash, sizeof(calc_hash)); + if (ret != 0) { + VERBOSE("%s: not expected digest\n", __func__); + return -EINVAL; + } + + ret = sizeof(otp_hash); + } + + memcpy(hash, param->pk_hashes[pk_idx], sizeof(otp_hash)); + + return ret; +} +#endif + +int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len, + unsigned int *flags) +{ + size_t start_copy_idx = 0U; + int res; + + memcpy(root_pk_hash, der_sha256_header, sizeof(der_sha256_header)); + start_copy_idx = sizeof(der_sha256_header); + + res = get_rotpk_hash(cookie, root_pk_hash + start_copy_idx, + BOOT_API_SHA256_DIGEST_SIZE_IN_BYTES); + if (res < 0) { + return -EINVAL; + } + + *key_len = HASH_DER_LEN; + *key_ptr = &root_pk_hash; + *flags = ROTPK_IS_HASH; + + if ((res == 0) && !stm32mp_is_closed_device()) { + *flags |= ROTPK_NOT_DEPLOYED; + } + + return 0; +} + +int plat_get_nv_ctr(void *cookie, unsigned int *nv_ctr) +{ + *nv_ctr = mmio_read_32(TAMP_BASE + TAMP_COUNTR); + + return 0; +} + +int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr) +{ + while (mmio_read_32(TAMP_BASE + TAMP_COUNTR) != nv_ctr) { + mmio_write_32(TAMP_BASE + TAMP_COUNTR, 1U); + } + + return 0; +} + +int plat_get_mbedtls_heap(void **heap_addr, size_t *heap_size) +{ + assert(heap_addr != NULL); + assert(heap_size != NULL); + +#if STM32MP_USE_EXTERNAL_HEAP + /* Retrieve the already allocated heap's info from DTB */ + *heap_addr = FCONF_GET_PROPERTY(tbbr, dyn_config, mbedtls_heap_addr); + *heap_size = FCONF_GET_PROPERTY(tbbr, dyn_config, mbedtls_heap_size); + + /* We expect heap already statically mapped */ + + return 0; +#else + return get_mbedtls_heap_helper(heap_addr, heap_size); +#endif +} diff --git a/plat/st/common/usb_dfu.c b/plat/st/common/usb_dfu.c new file mode 100644 index 0000000..8bb0994 --- /dev/null +++ b/plat/st/common/usb_dfu.c @@ -0,0 +1,538 @@ +/* + * Copyright (c) 2021, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <errno.h> +#include <string.h> + +#include <common/debug.h> + +#include <platform_def.h> +#include <usb_dfu.h> + +/* Device states as defined in DFU spec */ +#define STATE_APP_IDLE 0 +#define STATE_APP_DETACH 1 +#define STATE_DFU_IDLE 2 +#define STATE_DFU_DNLOAD_SYNC 3 +#define STATE_DFU_DNLOAD_BUSY 4 +#define STATE_DFU_DNLOAD_IDLE 5 +#define STATE_DFU_MANIFEST_SYNC 6 +#define STATE_DFU_MANIFEST 7 +#define STATE_DFU_MANIFEST_WAIT_RESET 8 +#define STATE_DFU_UPLOAD_IDLE 9 +#define STATE_DFU_ERROR 10 + +/* DFU errors */ +#define DFU_ERROR_NONE 0x00 +#define DFU_ERROR_TARGET 0x01 +#define DFU_ERROR_FILE 0x02 +#define DFU_ERROR_WRITE 0x03 +#define DFU_ERROR_ERASE 0x04 +#define DFU_ERROR_CHECK_ERASED 0x05 +#define DFU_ERROR_PROG 0x06 +#define DFU_ERROR_VERIFY 0x07 +#define DFU_ERROR_ADDRESS 0x08 +#define DFU_ERROR_NOTDONE 0x09 +#define DFU_ERROR_FIRMWARE 0x0A +#define DFU_ERROR_VENDOR 0x0B +#define DFU_ERROR_USB 0x0C +#define DFU_ERROR_POR 0x0D +#define DFU_ERROR_UNKNOWN 0x0E +#define DFU_ERROR_STALLEDPKT 0x0F + +/* DFU request */ +#define DFU_DETACH 0 +#define DFU_DNLOAD 1 +#define DFU_UPLOAD 2 +#define DFU_GETSTATUS 3 +#define DFU_CLRSTATUS 4 +#define DFU_GETSTATE 5 +#define DFU_ABORT 6 + +static bool usb_dfu_detach_req; + +/* + * usb_dfu_init + * Initialize the DFU interface + * pdev: device instance + * cfgidx: Configuration index + * return: status + */ +static uint8_t usb_dfu_init(struct usb_handle *pdev, uint8_t cfgidx) +{ + (void)pdev; + (void)cfgidx; + + /* Nothing to do in this stage */ + return USBD_OK; +} + +/* + * usb_dfu_de_init + * De-Initialize the DFU layer + * pdev: device instance + * cfgidx: Configuration index + * return: status + */ +static uint8_t usb_dfu_de_init(struct usb_handle *pdev, uint8_t cfgidx) +{ + (void)pdev; + (void)cfgidx; + + /* Nothing to do in this stage */ + return USBD_OK; +} + +/* + * usb_dfu_data_in + * handle data IN Stage + * pdev: device instance + * epnum: endpoint index + * return: status + */ +static uint8_t usb_dfu_data_in(struct usb_handle *pdev, uint8_t epnum) +{ + (void)pdev; + (void)epnum; + + return USBD_OK; +} + +/* + * usb_dfu_ep0_rx_ready + * handle EP0 Rx Ready event + * pdev: device + * return: status + */ +static uint8_t usb_dfu_ep0_rx_ready(struct usb_handle *pdev) +{ + (void)pdev; + + return USBD_OK; +} + +/* + * usb_dfu_ep0_tx_ready + * handle EP0 TRx Ready event + * pdev: device instance + * return: status + */ +static uint8_t usb_dfu_ep0_tx_ready(struct usb_handle *pdev) +{ + (void)pdev; + + return USBD_OK; +} + +/* + * usb_dfu_sof + * handle SOF event + * pdev: device instance + * return: status + */ +static uint8_t usb_dfu_sof(struct usb_handle *pdev) +{ + (void)pdev; + + return USBD_OK; +} + +/* + * usb_dfu_iso_in_incomplete + * handle data ISO IN Incomplete event + * pdev: device instance + * epnum: endpoint index + * return: status + */ +static uint8_t usb_dfu_iso_in_incomplete(struct usb_handle *pdev, uint8_t epnum) +{ + (void)pdev; + (void)epnum; + + return USBD_OK; +} + +/* + * usb_dfu_iso_out_incomplete + * handle data ISO OUT Incomplete event + * pdev: device instance + * epnum: endpoint index + * return: status + */ +static uint8_t usb_dfu_iso_out_incomplete(struct usb_handle *pdev, + uint8_t epnum) +{ + (void)pdev; + (void)epnum; + + return USBD_OK; +} + +/* + * usb_dfu_data_out + * handle data OUT Stage + * pdev: device instance + * epnum: endpoint index + * return: status + */ +static uint8_t usb_dfu_data_out(struct usb_handle *pdev, uint8_t epnum) +{ + (void)pdev; + (void)epnum; + + return USBD_OK; +} + +/* + * usb_dfu_detach + * Handles the DFU DETACH request. + * pdev: device instance + * req: pointer to the request structure. + */ +static void usb_dfu_detach(struct usb_handle *pdev, struct usb_setup_req *req) +{ + struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data; + + INFO("Receive DFU Detach\n"); + + if ((hdfu->dev_state == STATE_DFU_IDLE) || + (hdfu->dev_state == STATE_DFU_DNLOAD_SYNC) || + (hdfu->dev_state == STATE_DFU_DNLOAD_IDLE) || + (hdfu->dev_state == STATE_DFU_MANIFEST_SYNC) || + (hdfu->dev_state == STATE_DFU_UPLOAD_IDLE)) { + /* Update the state machine */ + hdfu->dev_state = STATE_DFU_IDLE; + hdfu->dev_status = DFU_ERROR_NONE; + } + + usb_dfu_detach_req = true; +} + +/* + * usb_dfu_download + * Handles the DFU DNLOAD request. + * pdev: device instance + * req: pointer to the request structure + */ +static void usb_dfu_download(struct usb_handle *pdev, struct usb_setup_req *req) +{ + struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data; + uintptr_t data_ptr; + uint32_t length; + int ret; + + /* Data setup request */ + if (req->length > 0) { + /* Unsupported state */ + if ((hdfu->dev_state != STATE_DFU_IDLE) && + (hdfu->dev_state != STATE_DFU_DNLOAD_IDLE)) { + /* Call the error management function (command will be nacked) */ + usb_core_ctl_error(pdev); + return; + } + + /* Get the data address */ + length = req->length; + ret = hdfu->callback->download(hdfu->alt_setting, &data_ptr, + &length, pdev->user_data); + if (ret == 0U) { + /* Update the state machine */ + hdfu->dev_state = STATE_DFU_DNLOAD_SYNC; + /* Start the transfer */ + usb_core_receive_ep0(pdev, (uint8_t *)data_ptr, length); + } else { + usb_core_ctl_error(pdev); + } + } else { + /* End of DNLOAD operation*/ + if (hdfu->dev_state != STATE_DFU_DNLOAD_IDLE) { + /* Call the error management function (command will be nacked) */ + usb_core_ctl_error(pdev); + return; + } + /* End of DNLOAD operation*/ + hdfu->dev_state = STATE_DFU_MANIFEST_SYNC; + ret = hdfu->callback->manifestation(hdfu->alt_setting, pdev->user_data); + if (ret == 0U) { + hdfu->dev_state = STATE_DFU_MANIFEST_SYNC; + } else { + usb_core_ctl_error(pdev); + } + } +} + +/* + * usb_dfu_upload + * Handles the DFU UPLOAD request. + * pdev: instance + * req: pointer to the request structure + */ +static void usb_dfu_upload(struct usb_handle *pdev, struct usb_setup_req *req) +{ + struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data; + uintptr_t data_ptr; + uint32_t length; + int ret; + + /* Data setup request */ + if (req->length == 0) { + /* No Data setup request */ + hdfu->dev_state = STATE_DFU_IDLE; + return; + } + + /* Unsupported state */ + if ((hdfu->dev_state != STATE_DFU_IDLE) && (hdfu->dev_state != STATE_DFU_UPLOAD_IDLE)) { + ERROR("UPLOAD : Unsupported State\n"); + /* Call the error management function (command will be nacked) */ + usb_core_ctl_error(pdev); + return; + } + + /* Update the data address */ + length = req->length; + ret = hdfu->callback->upload(hdfu->alt_setting, &data_ptr, &length, pdev->user_data); + if (ret == 0U) { + /* Short frame */ + hdfu->dev_state = (req->length > length) ? STATE_DFU_IDLE : STATE_DFU_UPLOAD_IDLE; + + /* Start the transfer */ + usb_core_transmit_ep0(pdev, (uint8_t *)data_ptr, length); + } else { + ERROR("UPLOAD : bad block %i on alt %i\n", req->value, req->index); + hdfu->dev_state = STATE_DFU_ERROR; + hdfu->dev_status = DFU_ERROR_STALLEDPKT; + + /* Call the error management function (command will be nacked) */ + usb_core_ctl_error(pdev); + } +} + +/* + * usb_dfu_get_status + * Handles the DFU GETSTATUS request. + * pdev: instance + */ +static void usb_dfu_get_status(struct usb_handle *pdev) +{ + struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data; + + hdfu->status[0] = hdfu->dev_status; /* bStatus */ + hdfu->status[1] = 0; /* bwPollTimeout[3] */ + hdfu->status[2] = 0; + hdfu->status[3] = 0; + hdfu->status[4] = hdfu->dev_state; /* bState */ + hdfu->status[5] = 0; /* iString */ + + /* next step */ + switch (hdfu->dev_state) { + case STATE_DFU_DNLOAD_SYNC: + hdfu->dev_state = STATE_DFU_DNLOAD_IDLE; + break; + case STATE_DFU_MANIFEST_SYNC: + /* the device is 'ManifestationTolerant' */ + hdfu->status[4] = STATE_DFU_MANIFEST; + hdfu->status[1] = 1U; /* bwPollTimeout = 1ms */ + hdfu->dev_state = STATE_DFU_IDLE; + break; + + default: + break; + } + + /* Start the transfer */ + usb_core_transmit_ep0(pdev, (uint8_t *)&hdfu->status[0], sizeof(hdfu->status)); +} + +/* + * usb_dfu_clear_status + * Handles the DFU CLRSTATUS request. + * pdev: device instance + */ +static void usb_dfu_clear_status(struct usb_handle *pdev) +{ + struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data; + + if (hdfu->dev_state == STATE_DFU_ERROR) { + hdfu->dev_state = STATE_DFU_IDLE; + hdfu->dev_status = DFU_ERROR_NONE; + } else { + /* State Error */ + hdfu->dev_state = STATE_DFU_ERROR; + hdfu->dev_status = DFU_ERROR_UNKNOWN; + } +} + +/* + * usb_dfu_get_state + * Handles the DFU GETSTATE request. + * pdev: device instance + */ +static void usb_dfu_get_state(struct usb_handle *pdev) +{ + struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data; + + /* Return the current state of the DFU interface */ + usb_core_transmit_ep0(pdev, &hdfu->dev_state, 1); +} + +/* + * usb_dfu_abort + * Handles the DFU ABORT request. + * pdev: device instance + */ +static void usb_dfu_abort(struct usb_handle *pdev) +{ + struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data; + + if ((hdfu->dev_state == STATE_DFU_IDLE) || + (hdfu->dev_state == STATE_DFU_DNLOAD_SYNC) || + (hdfu->dev_state == STATE_DFU_DNLOAD_IDLE) || + (hdfu->dev_state == STATE_DFU_MANIFEST_SYNC) || + (hdfu->dev_state == STATE_DFU_UPLOAD_IDLE)) { + hdfu->dev_state = STATE_DFU_IDLE; + hdfu->dev_status = DFU_ERROR_NONE; + } +} + +/* + * usb_dfu_setup + * Handle the DFU specific requests + * pdev: instance + * req: usb requests + * return: status + */ +static uint8_t usb_dfu_setup(struct usb_handle *pdev, struct usb_setup_req *req) +{ + uint8_t *pbuf = NULL; + uint16_t len = 0U; + uint8_t ret = USBD_OK; + struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data; + + switch (req->bm_request & USB_REQ_TYPE_MASK) { + case USB_REQ_TYPE_CLASS: + switch (req->b_request) { + case DFU_DNLOAD: + usb_dfu_download(pdev, req); + break; + + case DFU_UPLOAD: + usb_dfu_upload(pdev, req); + break; + + case DFU_GETSTATUS: + usb_dfu_get_status(pdev); + break; + + case DFU_CLRSTATUS: + usb_dfu_clear_status(pdev); + break; + + case DFU_GETSTATE: + usb_dfu_get_state(pdev); + break; + + case DFU_ABORT: + usb_dfu_abort(pdev); + break; + + case DFU_DETACH: + usb_dfu_detach(pdev, req); + break; + + default: + ERROR("unknown request %x on alternate %i\n", + req->b_request, hdfu->alt_setting); + usb_core_ctl_error(pdev); + ret = USBD_FAIL; + break; + } + break; + case USB_REQ_TYPE_STANDARD: + switch (req->b_request) { + case USB_REQ_GET_DESCRIPTOR: + if (HIBYTE(req->value) == DFU_DESCRIPTOR_TYPE) { + pbuf = pdev->desc->get_config_desc(&len); + /* DFU descriptor at the end of the USB */ + pbuf += len - 9U; + len = 9U; + len = MIN(len, req->length); + } + + /* Start the transfer */ + usb_core_transmit_ep0(pdev, pbuf, len); + + break; + + case USB_REQ_GET_INTERFACE: + /* Start the transfer */ + usb_core_transmit_ep0(pdev, (uint8_t *)&hdfu->alt_setting, 1U); + break; + + case USB_REQ_SET_INTERFACE: + hdfu->alt_setting = LOBYTE(req->value); + break; + + default: + usb_core_ctl_error(pdev); + ret = USBD_FAIL; + break; + } + default: + break; + } + + return ret; +} + +static const struct usb_class usb_dfu = { + .init = usb_dfu_init, + .de_init = usb_dfu_de_init, + .setup = usb_dfu_setup, + .ep0_tx_sent = usb_dfu_ep0_tx_ready, + .ep0_rx_ready = usb_dfu_ep0_rx_ready, + .data_in = usb_dfu_data_in, + .data_out = usb_dfu_data_out, + .sof = usb_dfu_sof, + .iso_in_incomplete = usb_dfu_iso_in_incomplete, + .iso_out_incomplete = usb_dfu_iso_out_incomplete, +}; + +void usb_dfu_register(struct usb_handle *pdev, struct usb_dfu_handle *phandle) +{ + pdev->class = (struct usb_class *)&usb_dfu; + pdev->class_data = phandle; + + phandle->dev_state = STATE_DFU_IDLE; + phandle->dev_status = DFU_ERROR_NONE; +} + +int usb_dfu_loop(struct usb_handle *pdev, const struct usb_dfu_media *pmedia) +{ + uint32_t it_count; + enum usb_status ret; + struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data; + + hdfu->callback = pmedia; + usb_dfu_detach_req = false; + /* Continue to handle USB core IT to assure complete data transmission */ + it_count = 100U; + + /* DFU infinite loop until DETACH_REQ */ + while (it_count != 0U) { + ret = usb_core_handle_it(pdev); + if (ret != USBD_OK) { + return -EIO; + } + + /* Detach request received */ + if (usb_dfu_detach_req) { + it_count--; + } + } + + return 0; +} diff --git a/plat/st/stm32mp1/bl2_plat_setup.c b/plat/st/stm32mp1/bl2_plat_setup.c new file mode 100644 index 0000000..4f04a6f --- /dev/null +++ b/plat/st/stm32mp1/bl2_plat_setup.c @@ -0,0 +1,562 @@ +/* + * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <errno.h> +#include <string.h> + +#include <arch_helpers.h> +#include <common/bl_common.h> +#include <common/debug.h> +#include <common/desc_image_load.h> +#include <drivers/generic_delay_timer.h> +#include <drivers/mmc.h> +#include <drivers/st/bsec.h> +#include <drivers/st/regulator_fixed.h> +#include <drivers/st/stm32_iwdg.h> +#include <drivers/st/stm32_rng.h> +#include <drivers/st/stm32_uart.h> +#include <drivers/st/stm32mp1_clk.h> +#include <drivers/st/stm32mp1_pwr.h> +#include <drivers/st/stm32mp1_ram.h> +#include <drivers/st/stm32mp_pmic.h> +#include <lib/fconf/fconf.h> +#include <lib/fconf/fconf_dyn_cfg_getter.h> +#include <lib/mmio.h> +#include <lib/optee_utils.h> +#include <lib/xlat_tables/xlat_tables_v2.h> +#include <plat/common/platform.h> + +#include <platform_def.h> +#include <stm32mp_common.h> +#include <stm32mp1_dbgmcu.h> + +#if DEBUG +static const char debug_msg[] = { + "***************************************************\n" + "** DEBUG ACCESS PORT IS OPEN! **\n" + "** This boot image is only for debugging purpose **\n" + "** and is unsafe for production use. **\n" + "** **\n" + "** If you see this message and you are not **\n" + "** debugging report this immediately to your **\n" + "** vendor! **\n" + "***************************************************\n" +}; +#endif + +static void print_reset_reason(void) +{ + uint32_t rstsr = mmio_read_32(stm32mp_rcc_base() + RCC_MP_RSTSCLRR); + + if (rstsr == 0U) { + WARN("Reset reason unknown\n"); + return; + } + + INFO("Reset reason (0x%x):\n", rstsr); + + if ((rstsr & RCC_MP_RSTSCLRR_PADRSTF) == 0U) { + if ((rstsr & RCC_MP_RSTSCLRR_STDBYRSTF) != 0U) { + INFO("System exits from STANDBY\n"); + return; + } + + if ((rstsr & RCC_MP_RSTSCLRR_CSTDBYRSTF) != 0U) { + INFO("MPU exits from CSTANDBY\n"); + return; + } + } + + if ((rstsr & RCC_MP_RSTSCLRR_PORRSTF) != 0U) { + INFO(" Power-on Reset (rst_por)\n"); + return; + } + + if ((rstsr & RCC_MP_RSTSCLRR_BORRSTF) != 0U) { + INFO(" Brownout Reset (rst_bor)\n"); + return; + } + +#if STM32MP15 + if ((rstsr & RCC_MP_RSTSCLRR_MCSYSRSTF) != 0U) { + if ((rstsr & RCC_MP_RSTSCLRR_PADRSTF) != 0U) { + INFO(" System reset generated by MCU (MCSYSRST)\n"); + } else { + INFO(" Local reset generated by MCU (MCSYSRST)\n"); + } + return; + } +#endif + + if ((rstsr & RCC_MP_RSTSCLRR_MPSYSRSTF) != 0U) { + INFO(" System reset generated by MPU (MPSYSRST)\n"); + return; + } + + if ((rstsr & RCC_MP_RSTSCLRR_HCSSRSTF) != 0U) { + INFO(" Reset due to a clock failure on HSE\n"); + return; + } + + if ((rstsr & RCC_MP_RSTSCLRR_IWDG1RSTF) != 0U) { + INFO(" IWDG1 Reset (rst_iwdg1)\n"); + return; + } + + if ((rstsr & RCC_MP_RSTSCLRR_IWDG2RSTF) != 0U) { + INFO(" IWDG2 Reset (rst_iwdg2)\n"); + return; + } + + if ((rstsr & RCC_MP_RSTSCLRR_MPUP0RSTF) != 0U) { + INFO(" MPU Processor 0 Reset\n"); + return; + } + +#if STM32MP15 + if ((rstsr & RCC_MP_RSTSCLRR_MPUP1RSTF) != 0U) { + INFO(" MPU Processor 1 Reset\n"); + return; + } +#endif + + if ((rstsr & RCC_MP_RSTSCLRR_PADRSTF) != 0U) { + INFO(" Pad Reset from NRST\n"); + return; + } + + if ((rstsr & RCC_MP_RSTSCLRR_VCORERSTF) != 0U) { + INFO(" Reset due to a failure of VDD_CORE\n"); + return; + } + + ERROR(" Unidentified reset reason\n"); +} + +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_setup_early_console(); + + stm32mp_save_boot_ctx_address(arg0); +} + +void bl2_platform_setup(void) +{ + int ret; + + ret = stm32mp1_ddr_probe(); + if (ret < 0) { + ERROR("Invalid DDR init: error %d\n", ret); + panic(); + } + + /* Map DDR for binary load, now with cacheable attribute */ + ret = mmap_add_dynamic_region(STM32MP_DDR_BASE, STM32MP_DDR_BASE, + STM32MP_DDR_MAX_SIZE, MT_MEMORY | MT_RW | MT_SECURE); + if (ret < 0) { + ERROR("DDR mapping: error %d\n", ret); + panic(); + } +} + +#if STM32MP15 +static void update_monotonic_counter(void) +{ + uint32_t version; + uint32_t otp; + + CASSERT(STM32_TF_VERSION <= MAX_MONOTONIC_VALUE, + assert_stm32mp1_monotonic_counter_reach_max); + + /* Check if monotonic counter needs to be incremented */ + if (stm32_get_otp_index(MONOTONIC_OTP, &otp, NULL) != 0) { + panic(); + } + + if (stm32_get_otp_value_from_idx(otp, &version) != 0) { + panic(); + } + + if ((version + 1U) < BIT(STM32_TF_VERSION)) { + uint32_t result; + + /* Need to increment the monotonic counter. */ + version = BIT(STM32_TF_VERSION) - 1U; + + result = bsec_program_otp(version, otp); + if (result != BSEC_OK) { + ERROR("BSEC: MONOTONIC_OTP program Error %u\n", + result); + panic(); + } + INFO("Monotonic counter has been incremented (value 0x%x)\n", + version); + } +} +#endif + +void bl2_el3_plat_arch_setup(void) +{ + const char *board_model; + boot_api_context_t *boot_context = + (boot_api_context_t *)stm32mp_get_boot_ctx_address(); + uintptr_t pwr_base; + uintptr_t rcc_base; + + if (bsec_probe() != 0U) { + panic(); + } + + mmap_add_region(BL_CODE_BASE, BL_CODE_BASE, + BL_CODE_END - BL_CODE_BASE, + MT_CODE | MT_SECURE); + + /* 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); + } + +#if STM32MP15 + /* Disable MCKPROT */ + mmio_clrbits_32(rcc_base + RCC_TZCR, RCC_TZCR_MCKPROT); +#endif + + /* + * Set minimum reset pulse duration to 31ms for discrete power + * supplied boards. + */ + if (dt_pmic_status() <= 0) { + mmio_clrsetbits_32(rcc_base + RCC_RDLSICR, + RCC_RDLSICR_MRD_MASK, + 31U << RCC_RDLSICR_MRD_SHIFT); + } + + generic_delay_timer_init(); + +#if STM32MP_UART_PROGRAMMER + /* Disable programmer UART before changing clock tree */ + if (boot_context->boot_interface_selected == + BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART) { + uintptr_t uart_prog_addr = + get_uart_address(boot_context->boot_interface_instance); + + stm32_uart_stop(uart_prog_addr); + } +#endif + if (stm32mp1_clk_probe() < 0) { + panic(); + } + + if (stm32mp1_clk_init() < 0) { + panic(); + } + + stm32_save_boot_interface(boot_context->boot_interface_selected, + boot_context->boot_interface_instance); + stm32_save_boot_auth(boot_context->auth_status, + boot_context->boot_partition_used_toboot); + +#if STM32MP_USB_PROGRAMMER && STM32MP15 + /* Deconfigure all UART RX pins configured by ROM code */ + stm32mp1_deconfigure_uart_pins(); +#endif + + if (stm32mp_uart_console_setup() != 0) { + goto skip_console_init; + } + + stm32mp_print_cpuinfo(); + + board_model = dt_get_board_model(); + if (board_model != NULL) { + NOTICE("Model: %s\n", board_model); + } + + stm32mp_print_boardinfo(); + + if (boot_context->auth_status != BOOT_API_CTX_AUTH_NO) { + NOTICE("Bootrom authentication %s\n", + (boot_context->auth_status == BOOT_API_CTX_AUTH_FAILED) ? + "failed" : "succeeded"); + } + +skip_console_init: +#if !TRUSTED_BOARD_BOOT + if (stm32mp_is_closed_device()) { + /* Closed chip mandates authentication */ + ERROR("Secure chip: TRUSTED_BOARD_BOOT must be enabled\n"); + panic(); + } +#endif + + if (fixed_regulator_register() != 0) { + panic(); + } + + if (dt_pmic_status() > 0) { + initialize_pmic(); + if (pmic_voltages_init() != 0) { + ERROR("PMIC voltages init failed\n"); + panic(); + } + print_pmic_info_and_debug(); + } + + stm32mp1_syscfg_init(); + + if (stm32_iwdg_init() < 0) { + panic(); + } + + stm32_iwdg_refresh(); + + if (bsec_read_debug_conf() != 0U) { + if (stm32mp_is_closed_device()) { +#if DEBUG + WARN("\n%s", debug_msg); +#else + ERROR("***Debug opened on closed chip***\n"); +#endif + } + } + +#if STM32MP13 + if (stm32_rng_init() != 0) { + panic(); + } +#endif + + stm32mp1_arch_security_setup(); + + print_reset_reason(); + +#if STM32MP15 + update_monotonic_counter(); +#endif + + stm32mp1_syscfg_enable_io_compensation_finish(); + + fconf_populate("TB_FW", STM32MP_DTB_BASE); + + stm32mp_io_setup(); +} + +/******************************************************************************* + * This function can be used by the platforms to update/use image + * information for given `image_id`. + ******************************************************************************/ +int bl2_plat_handle_post_image_load(unsigned int image_id) +{ + int err = 0; + bl_mem_params_node_t *bl_mem_params = get_bl_mem_params_node(image_id); + bl_mem_params_node_t *bl32_mem_params; + bl_mem_params_node_t *pager_mem_params __unused; + bl_mem_params_node_t *paged_mem_params __unused; + const struct dyn_cfg_dtb_info_t *config_info; + bl_mem_params_node_t *tos_fw_mem_params; + unsigned int i; + unsigned int idx; + unsigned long long ddr_top __unused; + const unsigned int image_ids[] = { + BL32_IMAGE_ID, + BL33_IMAGE_ID, + HW_CONFIG_ID, + TOS_FW_CONFIG_ID, + }; + + assert(bl_mem_params != NULL); + + switch (image_id) { + case FW_CONFIG_ID: + /* Set global DTB info for fixed fw_config information */ + set_config_info(STM32MP_FW_CONFIG_BASE, ~0UL, STM32MP_FW_CONFIG_MAX_SIZE, + FW_CONFIG_ID); + fconf_populate("FW_CONFIG", STM32MP_FW_CONFIG_BASE); + + idx = dyn_cfg_dtb_info_get_index(TOS_FW_CONFIG_ID); + + /* Iterate through all the fw config IDs */ + for (i = 0U; i < ARRAY_SIZE(image_ids); i++) { + if ((image_ids[i] == TOS_FW_CONFIG_ID) && (idx == FCONF_INVALID_IDX)) { + continue; + } + + bl_mem_params = get_bl_mem_params_node(image_ids[i]); + assert(bl_mem_params != NULL); + + config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, image_ids[i]); + if (config_info == NULL) { + continue; + } + + bl_mem_params->image_info.image_base = config_info->config_addr; + bl_mem_params->image_info.image_max_size = config_info->config_max_size; + + bl_mem_params->image_info.h.attr &= ~IMAGE_ATTRIB_SKIP_LOADING; + + switch (image_ids[i]) { + case BL32_IMAGE_ID: + bl_mem_params->ep_info.pc = config_info->config_addr; + + /* In case of OPTEE, initialize address space with tos_fw addr */ + pager_mem_params = get_bl_mem_params_node(BL32_EXTRA1_IMAGE_ID); + assert(pager_mem_params != NULL); + pager_mem_params->image_info.image_base = config_info->config_addr; + pager_mem_params->image_info.image_max_size = + config_info->config_max_size; + + /* Init base and size for pager if exist */ + paged_mem_params = get_bl_mem_params_node(BL32_EXTRA2_IMAGE_ID); + if (paged_mem_params != NULL) { + paged_mem_params->image_info.image_base = STM32MP_DDR_BASE + + (dt_get_ddr_size() - STM32MP_DDR_S_SIZE - + STM32MP_DDR_SHMEM_SIZE); + paged_mem_params->image_info.image_max_size = + STM32MP_DDR_S_SIZE; + } + break; + + case BL33_IMAGE_ID: + bl_mem_params->ep_info.pc = config_info->config_addr; + break; + + case HW_CONFIG_ID: + case TOS_FW_CONFIG_ID: + break; + + default: + return -EINVAL; + } + } + break; + + case BL32_IMAGE_ID: + if (optee_header_is_valid(bl_mem_params->image_info.image_base)) { + image_info_t *paged_image_info = NULL; + + /* BL32 is OP-TEE header */ + bl_mem_params->ep_info.pc = bl_mem_params->image_info.image_base; + pager_mem_params = get_bl_mem_params_node(BL32_EXTRA1_IMAGE_ID); + assert(pager_mem_params != NULL); + + paged_mem_params = get_bl_mem_params_node(BL32_EXTRA2_IMAGE_ID); + if (paged_mem_params != NULL) { + paged_image_info = &paged_mem_params->image_info; + } + + err = parse_optee_header(&bl_mem_params->ep_info, + &pager_mem_params->image_info, + paged_image_info); + if (err != 0) { + ERROR("OPTEE header parse error.\n"); + panic(); + } + + /* Set optee boot info from parsed header data */ + if (paged_mem_params != NULL) { + bl_mem_params->ep_info.args.arg0 = + paged_mem_params->image_info.image_base; + } else { + bl_mem_params->ep_info.args.arg0 = 0U; + } + + bl_mem_params->ep_info.args.arg1 = 0U; /* Unused */ + bl_mem_params->ep_info.args.arg2 = 0U; /* No DT supported */ + } else { + bl_mem_params->ep_info.pc = bl_mem_params->image_info.image_base; + tos_fw_mem_params = get_bl_mem_params_node(TOS_FW_CONFIG_ID); + assert(tos_fw_mem_params != NULL); + bl_mem_params->image_info.image_max_size += + tos_fw_mem_params->image_info.image_max_size; + bl_mem_params->ep_info.args.arg0 = 0; + } + break; + + case BL33_IMAGE_ID: + bl32_mem_params = get_bl_mem_params_node(BL32_IMAGE_ID); + assert(bl32_mem_params != NULL); + bl32_mem_params->ep_info.lr_svc = bl_mem_params->ep_info.pc; +#if PSA_FWU_SUPPORT + stm32mp1_fwu_set_boot_idx(); +#endif /* PSA_FWU_SUPPORT */ + break; + + default: + /* Do nothing in default case */ + break; + } + +#if STM32MP_SDMMC || STM32MP_EMMC + /* + * Invalidate remaining data read from MMC but not flushed by load_image_flush(). + * We take the worst case which is 2 MMC blocks. + */ + if ((image_id != FW_CONFIG_ID) && + ((bl_mem_params->image_info.h.attr & IMAGE_ATTRIB_SKIP_LOADING) == 0U)) { + inv_dcache_range(bl_mem_params->image_info.image_base + + bl_mem_params->image_info.image_size, + 2U * MMC_BLOCK_SIZE); + } +#endif /* STM32MP_SDMMC || STM32MP_EMMC */ + + return err; +} + +void bl2_el3_plat_prepare_exit(void) +{ + uint16_t boot_itf = stm32mp_get_boot_itf_selected(); + + switch (boot_itf) { +#if STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER + case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART: + case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB: + /* Invalidate the downloaded buffer used with io_memmap */ + inv_dcache_range(DWL_BUFFER_BASE, DWL_BUFFER_SIZE); + break; +#endif /* STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER */ + default: + /* Do nothing in default case */ + break; + } + + stm32mp1_security_setup(); +} diff --git a/plat/st/stm32mp1/cert_create_tbbr.mk b/plat/st/stm32mp1/cert_create_tbbr.mk new file mode 100644 index 0000000..5b1a3ed --- /dev/null +++ b/plat/st/stm32mp1/cert_create_tbbr.mk @@ -0,0 +1,19 @@ +# +# Copyright (c) 2022, STMicroelectronics - All Rights Reserved +# +# SPDX-License-Identifier: BSD-3-Clause +# + +# Override TBBR Cert to update generic certificate + +$(eval $(call add_define,PDEF_CERTS)) + +PLAT_INCLUDE += -I${PLAT_DIR}include + +src/stm32mp1_tbb_cert.o: ${PLAT_DIR}stm32mp1_tbb_cert.c + ${Q}${HOSTCC} -c ${HOSTCCFLAGS} ${INC_DIR} $< -o $@ + +PLAT_OBJECTS = src/stm32mp1_tbb_cert.o + +OBJECTS += $(PLAT_OBJECTS) + diff --git a/plat/st/stm32mp1/include/boot_api.h b/plat/st/stm32mp1/include/boot_api.h new file mode 100644 index 0000000..1054609 --- /dev/null +++ b/plat/st/stm32mp1/include/boot_api.h @@ -0,0 +1,409 @@ +/* + * Copyright (c) 2017-2022, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef BOOT_API_H +#define BOOT_API_H + +#include <stdint.h> +#include <stdio.h> + +/* + * Possible value of boot context field 'auth_status' + */ +#if STM32MP13 + /* No authentication done */ +#define BOOT_API_CTX_AUTH_NO 0x7CFDD351U + /* Authentication done and failed */ +#define BOOT_API_CTX_AUTH_FAILED 0x51330884U + /* Authentication done and success */ +#define BOOT_API_CTX_AUTH_SUCCESS 0x67E8CAE1U +#endif +#if STM32MP15 +/* No authentication done */ +#define BOOT_API_CTX_AUTH_NO 0x0U +/* Authentication done and failed */ +#define BOOT_API_CTX_AUTH_FAILED 0x1U +/* Authentication done and succeeded */ +#define BOOT_API_CTX_AUTH_SUCCESS 0x2U +#endif + +/* + * Possible value of boot context field 'boot_interface_sel' + */ + +/* Value of field 'boot_interface_sel' when no boot occurred */ +#define BOOT_API_CTX_BOOT_INTERFACE_SEL_NO 0x0U + +/* Boot occurred on SD */ +#define BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_SD 0x1U + +/* Boot occurred on EMMC */ +#define BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_EMMC 0x2U + +/* Boot occurred on FMC */ +#define BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_FMC 0x3U + +/* Boot occurred on QSPI NOR */ +#define BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NOR_QSPI 0x4U + +/* Boot occurred on UART */ +#define BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART 0x5U + +/* Boot occurred on USB */ +#define BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB 0x6U + +/* Boot occurred on QSPI NAND */ +#define BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_QSPI 0x7U + +/** + * @brief Possible value of boot context field 'EmmcXferStatus' + */ +/* + * Possible value of boot context field 'emmc_xfer_status' + */ +#define BOOT_API_CTX_EMMC_XFER_STATUS_NOT_STARTED 0x0U +#define BOOT_API_CTX_EMMC_XFER_STATUS_DATAEND_DETECTED 0x1U +#define BOOT_API_CTX_EMMC_XFER_STATUS_XFER_OVERALL_TIMEOUT_DETECTED 0x2U +#define BOOT_API_CTX_EMMC_XFER_STATUS_XFER_DATA_TIMEOUT 0x3U + +/* + * Possible value of boot context field 'emmc_error_status' + */ +#define BOOT_API_CTX_EMMC_ERROR_STATUS_NONE 0x0U +#define BOOT_API_CTX_EMMC_ERROR_STATUS_CMD_TIMEOUT 0x1U +#define BOOT_API_CTX_EMMC_ERROR_STATUS_ACK_TIMEOUT 0x2U +#define BOOT_API_CTX_EMMC_ERROR_STATUS_DATA_CRC_FAIL 0x3U +#define BOOT_API_CTX_EMMC_ERROR_STATUS_NOT_ENOUGH_BOOT_DATA_RX 0x4U +#define BOOT_API_CTX_EMMC_ERROR_STATUS_HEADER_NOT_FOUND 0x5U +#define BOOT_API_CTX_EMMC_ERROR_STATUS_HEADER_SIZE_ZERO 0x6U +#define BOOT_API_CTX_EMMC_ERROR_STATUS_IMAGE_NOT_COMPLETE 0x7U +#define BOOT_API_CTX_EMMC_ERROR_STATUS_ACK_ERROR 0x8U + +/* Image Header related definitions */ + +/* Definition of header version */ +#if STM32MP13 +#define BOOT_API_HEADER_VERSION 0x00020000U +#endif +#if STM32MP15 +#define BOOT_API_HEADER_VERSION 0x00010000U +#endif + +/* + * Magic number used to detect header in memory + * Its value must be 'S' 'T' 'M' 0x32, i.e 0x324D5453 as field + * 'bootapi_image_header_t.magic' + * This identifies the start of a boot image. + */ +#define BOOT_API_IMAGE_HEADER_MAGIC_NB 0x324D5453U + +/* Definitions related to Authentication used in image header structure */ +#define BOOT_API_ECDSA_PUB_KEY_LEN_IN_BYTES 64 +#define BOOT_API_ECDSA_SIGNATURE_LEN_IN_BYTES 64 +#define BOOT_API_SHA256_DIGEST_SIZE_IN_BYTES 32 + +/* Possible values of the field 'boot_api_image_header_t.ecc_algo_type' */ +#define BOOT_API_ECDSA_ALGO_TYPE_P256NIST 1 +#define BOOT_API_ECDSA_ALGO_TYPE_BRAINPOOL256 2 + +/* + * Extension headers related definitions + */ +/* 'bootapi_image_header_t.extension_flag' used for authentication feature */ +#define BOOT_API_AUTHENTICATION_EXTENSION_BIT BIT(0) +/* 'bootapi_image_header_t.extension_flag' used for FSBL decryption feature */ +#define BOOT_API_FSBL_DECRYPTION_EXTENSION_BIT BIT(1) +/* 'bootapi_image_header_t.extension_flag' used for padding header feature */ +#define BOOT_API_PADDING_EXTENSION_BIT BIT(31) +/* + * mask of bits of field 'bootapi_image_header_t.extension_flag' + * used for extension headers + */ +#define BOOT_API_ALL_EXTENSIONS_MASK \ + (BOOT_API_AUTHENTICATION_EXTENSION_BIT | \ + BOOT_API_FSBL_DECRYPTION_EXTENSION_BIT | \ + BOOT_API_PADDING_EXTENSION_BIT) +/* + * Magic number of FSBL decryption extension header + * The value shall gives the four bytes 'S','T',0x00,0x01 in memory + */ +#define BOOT_API_FSBL_DECRYPTION_HEADER_MAGIC_NB 0x01005453U + +/* + * Magic number of PKH revocation extension header + * The value shall gives the four bytes 'S','T',0x00,0x02 in memory + */ +#define BOOT_API_AUTHENTICATION_HEADER_MAGIC_NB 0x02005453U + +/* Max number of ECDSA public key hash in table */ +#define BOOT_API_AUTHENTICATION_NB_PKH_MAX 8U + +/* ECDSA public key hash table size in bytes */ +#define BOOT_API_AUTHENTICATION_TABLE_SIZE_BYTES \ + (BOOT_API_AUTHENTICATION_NB_PKH_MAX * \ + BOOT_API_SHA256_DIGEST_SIZE_IN_BYTES) + +/* + * Magic number of padding extension header + * The value shall gives the four bytes 'S','T',0xFF,0xFF in memory + */ +#define BOOT_API_PADDING_HEADER_MAGIC_NB 0xFFFF5453U + +/* + * Cores secure magic numbers + * Constant to be stored in bakcup register + * BOOT_API_MAGIC_NUMBER_TAMP_BCK_REG_IDX + */ +#define BOOT_API_A7_CORE0_MAGIC_NUMBER 0xCA7FACE0U +#define BOOT_API_A7_CORE1_MAGIC_NUMBER 0xCA7FACE1U + +/* + * TAMP_BCK4R register index + * This register is used to write a Magic Number in order to restart + * Cortex A7 Core 1 and make it execute @ branch address from TAMP_BCK5R + */ +#define BOOT_API_CORE1_MAGIC_NUMBER_TAMP_BCK_REG_IDX 4U + +/* + * TAMP_BCK5R register index + * This register is used to contain the branch address of + * Cortex A7 Core 1 when restarted by a TAMP_BCK4R magic number writing + */ +#define BOOT_API_CORE1_BRANCH_ADDRESS_TAMP_BCK_REG_IDX 5U + +/* + * Possible value of boot context field 'hse_clock_value_in_hz' + */ +#define BOOT_API_CTX_HSE_CLOCK_VALUE_UNDEFINED 0U +#define BOOT_API_CTX_HSE_CLOCK_VALUE_24_MHZ 24000000U +#define BOOT_API_CTX_HSE_CLOCK_VALUE_25_MHZ 25000000U +#define BOOT_API_CTX_HSE_CLOCK_VALUE_26_MHZ 26000000U + +/* + * Possible value of boot context field 'boot_partition_used_toboot' + */ +#define BOOT_API_CTX_BOOT_PARTITION_UNDEFINED 0U + +/* Used FSBL1 to boot */ +#define BOOT_API_CTX_BOOT_PARTITION_FSBL1 1U + +/* Used FSBL2 to boot */ +#define BOOT_API_CTX_BOOT_PARTITION_FSBL2 2U + +/* OTP_CFG0 */ +#define BOOT_API_OTP_MODE_WORD_NB 0 +/* Closed = OTP_CFG0[6] */ +#define BOOT_API_OTP_MODE_CLOSED_BIT_POS 6 + +#define BOOT_API_RETURN_OK 0x77U + +/* + * Boot Context related definitions + */ + +/* + * Boot core boot configuration structure + * Specifies all items of the cold boot configuration + * Memory and peripheral part. + */ +typedef struct { + /* + * Boot interface used to boot : take values from defines + * BOOT_API_CTX_BOOT_INTERFACE_SEL_XXX above + */ + uint16_t boot_interface_selected; + uint16_t boot_interface_instance; +#if STM32MP13 + uint32_t reserved1[12]; +#endif +#if STM32MP15 + uint32_t reserved1[13]; +#endif + uint32_t otp_afmux_values[3]; + uint32_t reserved[3]; +#if STM32MP15 + uint32_t reserved2[2]; +#endif + uint32_t auth_status; + +#if STM32MP15 + /* + * Pointers to bootROM External Secure Services + * - ECDSA verify signature + */ + uint32_t reserved3; + uint32_t (*bootrom_ecdsa_verify_signature)(uint8_t *hash_in, + uint8_t *pubkey_in, + uint8_t *signature, + uint32_t ecc_algo); + uint32_t reserved4; +#endif + /* + * Information specific to an SD boot + * Updated each time an SD boot is at least attempted, + * even if not successful + * Note : This is useful to understand why an SD boot failed + * in particular + */ + uint32_t sd_err_internal_timeout_cnt; + uint32_t sd_err_dcrc_fail_cnt; + uint32_t sd_err_dtimeout_cnt; + uint32_t sd_err_ctimeout_cnt; + uint32_t sd_err_ccrc_fail_cnt; + uint32_t sd_overall_retry_cnt; + /* + * Information specific to an eMMC boot + * Updated each time an eMMC boot is at least attempted, + * even if not successful + * Note : This is useful to understand why an eMMC boot failed + * in particular + */ + uint32_t emmc_xfer_status; + uint32_t emmc_error_status; + uint32_t emmc_nbbytes_rxcopied_tosysram_download_area; + uint32_t hse_clock_value_in_hz; + /* + * Boot partition : + * ie FSBL partition on which the boot was successful + */ + uint32_t boot_partition_used_toboot; + +} __packed boot_api_context_t; + +/* + * Image Header related definitions + */ + +/* + * Structure used to define the common Header format used for FSBL, xloader, + * ... and in particular used by bootROM for FSBL header readout. + * FSBL header size is 256 Bytes = 0x100 + */ +typedef struct { + /* BOOT_API_IMAGE_HEADER_MAGIC_NB */ + uint32_t magic; + uint8_t image_signature[BOOT_API_ECDSA_SIGNATURE_LEN_IN_BYTES]; + /* + * Checksum of payload + * 32-bit sum all payload bytes considered as 8 bit unsigned + * numbers, discarding any overflow bits. + * Use to check UART/USB downloaded image integrity when signature + * is not used + */ + uint32_t payload_checksum; + /* Image header version : should have value BOOT_API_HEADER_VERSION */ + uint32_t header_version; + /* Image length in bytes */ + uint32_t image_length; + /* + * Image Entry point address : should be in the SYSRAM area + * and at least within the download area range + */ + uint32_t image_entry_point; + /* Reserved */ + uint32_t reserved1; + /* + * Image load address : not used by bootROM but to be consistent + * with header format for other packages (xloader, ...) + */ + uint32_t load_address; + /* Reserved */ + uint32_t reserved2; + /* Image version to be compared by bootROM with monotonic + * counter value in OTP_CFG4 prior executing the downloaded image + */ + uint32_t image_version; + +#if STM32MP13 + /* + * Extension flags : + * + * Bit 0 : Authentication extension header + * value 0 : No signature check request + * Bit 1 : Encryption extension header + * Bit 2 : Padding extension header + */ + uint32_t extension_flags; + /* Length in bytes of all extension headers */ + uint32_t extension_headers_length; + /* Add binary type information */ + uint32_t binary_type; + /* Pad up to 128 byte total size */ + uint8_t pad[16]; + /* Followed by extension header */ + uint8_t ext_header[]; +#endif +#if STM32MP15 + /* + * Option flags: + * Bit 0 : No signature check request : 'No_sig_check' + * value 1 : for No signature check request + * value 0 : No request to bypass the signature check + * Note : No signature check is never allowed on a Secured chip + */ + uint32_t option_flags; + /* + * Type of ECC algorithm to use : + * value 1 : for P-256 NIST algorithm + * value 2 : for Brainpool 256 algorithm + * See definitions 'BOOT_API_ECDSA_ALGO_TYPE_XXX' above. + */ + uint32_t ecc_algo_type; + /* + * OEM ECC Public Key (aka Root pubk) provided in header on 512 bits. + * The SHA-256 hash of the OEM ECC pubk must match the one stored + * in OTP cells. + */ + uint8_t ecc_pubk[BOOT_API_ECDSA_PUB_KEY_LEN_IN_BYTES]; + /* Pad up to 256 byte total size */ + uint8_t pad[83]; + /* Add binary type information */ + uint8_t binary_type; +#endif +} __packed boot_api_image_header_t; + +typedef uint8_t boot_api_sha256_t[BOOT_API_SHA256_DIGEST_SIZE_IN_BYTES]; + +typedef struct { + /* Extension header type: + * BOOT_API_FSBL_DECRYPTION_HEADER_MAGIC_NB or + * BOOT_API_AUTHENTICATION_HEADER_MAGIC_NB + * BOOT_API_PADDING_HEADER_MAGIC_NB + */ + uint32_t type; + /* Extension header len in byte */ + uint32_t len; + /* parameters of this extension */ + uint8_t params[]; +} __packed boot_extension_header_t; + +typedef struct { + /* Idx of ECDSA public key to be used in table */ + uint32_t pk_idx; + /* Number of ECDSA public key in table */ + uint32_t nb_pk; + /* + * Type of ECC algorithm to use : + * value 1 : for P-256 NIST algorithm + * value 2 : for Brainpool 256 algorithm + * See definitions 'BOOT_API_ECDSA_ALGO_TYPE_XXX' above. + */ + uint32_t ecc_algo_type; + /* ECDSA public key to be used to check signature. */ + uint8_t ecc_pubk[BOOT_API_ECDSA_PUB_KEY_LEN_IN_BYTES]; + /* table of Hash of Algo+ECDSA public key */ + boot_api_sha256_t pk_hashes[]; +} __packed boot_ext_header_params_authentication_t; + +typedef struct { + /* Size of encryption key (128 or 256) */ + uint32_t key_size; + uint32_t derivation_cont; + /* 128 msb bits of plain payload SHA256 */ + uint32_t hash[4]; +} __packed boot_ext_header_params_encrypted_fsbl_t; + +#endif /* BOOT_API_H */ diff --git a/plat/st/stm32mp1/include/plat_def_fip_uuid.h b/plat/st/stm32mp1/include/plat_def_fip_uuid.h new file mode 100644 index 0000000..e5fbc2d --- /dev/null +++ b/plat/st/stm32mp1/include/plat_def_fip_uuid.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2021-2022, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef PLAT_DEF_FIP_UUID_H +#define PLAT_DEF_FIP_UUID_H + +#define UUID_STM32MP_CONFIG_CERT \ + {{0x50, 0x1d, 0x8d, 0xd2}, {0x8b, 0xce}, {0x49, 0xa5}, 0x84, 0xeb, \ + {0x55, 0x9a, 0x9f, 0x2e, 0xae, 0xaf} } +#endif /* PLAT_DEF_FIP_UUID_H */ + diff --git a/plat/st/stm32mp1/include/plat_tbbr_img_def.h b/plat/st/stm32mp1/include/plat_tbbr_img_def.h new file mode 100644 index 0000000..984aae8 --- /dev/null +++ b/plat/st/stm32mp1/include/plat_tbbr_img_def.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2022, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef STM32MP1_IMG_DEF_H +#define STM32MP1_IMG_DEF_H + +#include <export/common/tbbr/tbbr_img_def_exp.h> + +/* Undef the existing values */ +#undef BL32_EXTRA1_IMAGE_ID +#undef BL32_EXTRA2_IMAGE_ID +#undef TOS_FW_CONFIG_ID +#undef TRUSTED_BOOT_FW_CERT_ID +#undef FWU_METADATA_IMAGE_ID +#undef BKUP_FWU_METADATA_IMAGE_ID +#undef FW_CONFIG_ID +#undef HW_CONFIG_ID +#undef GPT_IMAGE_ID +#undef ENC_IMAGE_ID + +/* Define the STM32MP1 used ID */ +#define FW_CONFIG_ID U(1) +#define HW_CONFIG_ID U(2) +#define GPT_IMAGE_ID U(3) +#define ENC_IMAGE_ID U(6) +#define BL32_EXTRA1_IMAGE_ID U(8) +#define BL32_EXTRA2_IMAGE_ID U(9) +#define FWU_METADATA_IMAGE_ID U(12) +#define BKUP_FWU_METADATA_IMAGE_ID U(13) +#define TOS_FW_CONFIG_ID U(16) +#define STM32MP_CONFIG_CERT_ID U(17) + +/* Increase the MAX_NUMBER_IDS to match the authentication pool required */ +#define MAX_NUMBER_IDS U(19) + +#endif /* STM32MP1_IMG_DEF_H */ diff --git a/plat/st/stm32mp1/include/platform_def.h b/plat/st/stm32mp1/include/platform_def.h new file mode 100644 index 0000000..61b847f --- /dev/null +++ b/plat/st/stm32mp1/include/platform_def.h @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef PLATFORM_DEF_H +#define PLATFORM_DEF_H + +#include <arch.h> +#include <drivers/arm/gic_common.h> +#include <lib/utils_def.h> +#include <plat/common/common_def.h> + +#include "../stm32mp1_def.h" + +/******************************************************************************* + * Generic platform constants + ******************************************************************************/ + +/* Size of cacheable stacks */ +#if defined(IMAGE_BL32) +#define PLATFORM_STACK_SIZE 0x600 +#else +#define PLATFORM_STACK_SIZE 0xC00 +#endif + +#define FIP_IMAGE_NAME "fip" +#define METADATA_PART_1 "metadata1" +#define METADATA_PART_2 "metadata2" + +#define STM32MP_PRIMARY_CPU U(0x0) +#define STM32MP_SECONDARY_CPU U(0x1) + +#define PLATFORM_CLUSTER_COUNT U(1) +#define PLATFORM_CLUSTER0_CORE_COUNT U(2) +#define PLATFORM_CLUSTER1_CORE_COUNT U(0) +#define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER1_CORE_COUNT + \ + PLATFORM_CLUSTER0_CORE_COUNT) +#define PLATFORM_MAX_CPUS_PER_CLUSTER 2 + +#define MAX_IO_DEVICES U(4) +#define MAX_IO_HANDLES U(4) +#define MAX_IO_BLOCK_DEVICES U(1) +#define MAX_IO_MTD_DEVICES U(1) + +/******************************************************************************* + * BL2 specific defines. + ******************************************************************************/ +/* + * Put BL2 just below BL3-1. BL2_BASE is calculated using the current BL2 debug + * size plus a little space for growth. + */ +#define BL2_BASE STM32MP_BL2_BASE +#define BL2_LIMIT (STM32MP_BL2_BASE + \ + STM32MP_BL2_SIZE) + +#define BL2_RO_BASE STM32MP_BL2_RO_BASE +#define BL2_RO_LIMIT (STM32MP_BL2_RO_BASE + \ + STM32MP_BL2_RO_SIZE) + +#define BL2_RW_BASE STM32MP_BL2_RW_BASE +#define BL2_RW_LIMIT (STM32MP_BL2_RW_BASE + \ + STM32MP_BL2_RW_SIZE) +/******************************************************************************* + * BL32 specific defines. + ******************************************************************************/ +#if defined(IMAGE_BL32) +#if ENABLE_PIE +#define BL32_BASE 0 +#define BL32_LIMIT STM32MP_BL32_SIZE +#else +#define BL32_BASE STM32MP_BL32_BASE +#define BL32_LIMIT (STM32MP_BL32_BASE + \ + STM32MP_BL32_SIZE) +#endif +#endif /* defined(IMAGE_BL32) */ + +/******************************************************************************* + * BL33 specific defines. + ******************************************************************************/ +#define BL33_BASE STM32MP_BL33_BASE + +/* + * Load address of BL33 for this platform port + */ +#define PLAT_STM32MP_NS_IMAGE_OFFSET BL33_BASE + +/* Needed by STM32CubeProgrammer support */ +#define DWL_BUFFER_SIZE U(0x01000000) + +/* + * SSBL offset in case it's stored in eMMC boot partition. + * We can fix it to 256K because TF-A size can't be bigger than SRAM + */ +#define PLAT_EMMC_BOOT_SSBL_OFFSET U(0x40000) + +/******************************************************************************* + * DTB specific defines. + ******************************************************************************/ +#define DTB_BASE STM32MP_DTB_BASE +#define DTB_LIMIT (STM32MP_DTB_BASE + \ + STM32MP_DTB_SIZE) + +/******************************************************************************* + * Platform specific page table and MMU setup constants + ******************************************************************************/ +#define PLAT_PHY_ADDR_SPACE_SIZE (ULL(1) << 32) +#define PLAT_VIRT_ADDR_SPACE_SIZE (ULL(1) << 32) + +/******************************************************************************* + * Declarations and constants to access the mailboxes safely. Each mailbox is + * aligned on the biggest cache line size in the platform. This is known only + * to the platform as it might have a combination of integrated and external + * caches. Such alignment ensures that two maiboxes do not sit on the same cache + * line at any cache level. They could belong to different cpus/clusters & + * get written while being protected by different locks causing corruption of + * a valid mailbox address. + ******************************************************************************/ +#define CACHE_WRITEBACK_SHIFT 6 +#define CACHE_WRITEBACK_GRANULE (U(1) << CACHE_WRITEBACK_SHIFT) + +/* + * Secure Interrupt: based on the standard ARM mapping + */ +#define ARM_IRQ_SEC_PHY_TIMER U(29) + +#define ARM_IRQ_SEC_SGI_0 U(8) +#define ARM_IRQ_SEC_SGI_1 U(9) +#define ARM_IRQ_SEC_SGI_2 U(10) +#define ARM_IRQ_SEC_SGI_3 U(11) +#define ARM_IRQ_SEC_SGI_4 U(12) +#define ARM_IRQ_SEC_SGI_5 U(13) +#define ARM_IRQ_SEC_SGI_6 U(14) +#define ARM_IRQ_SEC_SGI_7 U(15) + +#define STM32MP1_IRQ_TZC400 U(36) +#define STM32MP1_IRQ_TAMPSERRS U(229) +#define STM32MP1_IRQ_AXIERRIRQ U(244) + +/* + * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3 + * terminology. On a GICv2 system or mode, the lists will be merged and treated + * as Group 0 interrupts. + */ +#define PLATFORM_G1S_PROPS(grp) \ + INTR_PROP_DESC(ARM_IRQ_SEC_PHY_TIMER, \ + GIC_HIGHEST_SEC_PRIORITY, \ + grp, GIC_INTR_CFG_LEVEL), \ + INTR_PROP_DESC(STM32MP1_IRQ_AXIERRIRQ, \ + GIC_HIGHEST_SEC_PRIORITY, \ + grp, GIC_INTR_CFG_LEVEL), \ + INTR_PROP_DESC(STM32MP1_IRQ_TZC400, \ + GIC_HIGHEST_SEC_PRIORITY, \ + grp, GIC_INTR_CFG_LEVEL), \ + INTR_PROP_DESC(ARM_IRQ_SEC_SGI_1, \ + GIC_HIGHEST_SEC_PRIORITY, \ + grp, GIC_INTR_CFG_EDGE), \ + INTR_PROP_DESC(ARM_IRQ_SEC_SGI_2, \ + GIC_HIGHEST_SEC_PRIORITY, \ + grp, GIC_INTR_CFG_EDGE), \ + INTR_PROP_DESC(ARM_IRQ_SEC_SGI_3, \ + GIC_HIGHEST_SEC_PRIORITY, \ + grp, GIC_INTR_CFG_EDGE), \ + INTR_PROP_DESC(ARM_IRQ_SEC_SGI_4, \ + GIC_HIGHEST_SEC_PRIORITY, \ + grp, GIC_INTR_CFG_EDGE), \ + INTR_PROP_DESC(ARM_IRQ_SEC_SGI_5, \ + GIC_HIGHEST_SEC_PRIORITY, \ + grp, GIC_INTR_CFG_EDGE), \ + INTR_PROP_DESC(ARM_IRQ_SEC_SGI_7, \ + GIC_HIGHEST_SEC_PRIORITY, \ + grp, GIC_INTR_CFG_EDGE) + +#define PLATFORM_G0_PROPS(grp) \ + INTR_PROP_DESC(ARM_IRQ_SEC_SGI_0, \ + GIC_HIGHEST_SEC_PRIORITY, \ + grp, GIC_INTR_CFG_EDGE), \ + INTR_PROP_DESC(ARM_IRQ_SEC_SGI_6, \ + GIC_HIGHEST_SEC_PRIORITY, \ + grp, GIC_INTR_CFG_EDGE) + +/* + * Power + */ +#define PLAT_MAX_PWR_LVL U(1) + +/* Local power state for power domains in Run state. */ +#define ARM_LOCAL_STATE_RUN U(0) +/* Local power state for retention. Valid only for CPU power domains */ +#define ARM_LOCAL_STATE_RET U(1) +/* Local power state for power-down. Valid for CPU and cluster power domains */ +#define ARM_LOCAL_STATE_OFF U(2) +/* + * This macro defines the deepest retention state possible. + * A higher state id will represent an invalid or a power down state. + */ +#define PLAT_MAX_RET_STATE ARM_LOCAL_STATE_RET +/* + * This macro defines the deepest power down states possible. Any state ID + * higher than this is invalid. + */ +#define PLAT_MAX_OFF_STATE ARM_LOCAL_STATE_OFF + +/******************************************************************************* + * Size of the per-cpu data in bytes that should be reserved in the generic + * per-cpu data structure for the FVP port. + ******************************************************************************/ +#define PLAT_PCPU_DATA_SIZE 2 + +/******************************************************************************* + * Number of parallel entry slots in SMT SCMI server entry context. For this + * platform, SCMI server is reached through SMC only, hence the number of + * entry slots. + ******************************************************************************/ +#define PLAT_SMT_ENTRY_COUNT PLATFORM_CORE_COUNT + +#endif /* PLATFORM_DEF_H */ diff --git a/plat/st/stm32mp1/include/stm32mp1_dbgmcu.h b/plat/st/stm32mp1/include/stm32mp1_dbgmcu.h new file mode 100644 index 0000000..3663bce --- /dev/null +++ b/plat/st/stm32mp1/include/stm32mp1_dbgmcu.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2015-2021, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef STM32MP1_DBGMCU_H +#define STM32MP1_DBGMCU_H + +#include <stdint.h> + +/* Get chip version and ID from DBGMCU registers */ +int stm32mp1_dbgmcu_get_chip_version(uint32_t *chip_version); +int stm32mp1_dbgmcu_get_chip_dev_id(uint32_t *chip_dev_id); + +#endif /* STM32MP1_DBGMCU_H */ diff --git a/plat/st/stm32mp1/include/stm32mp1_mbedtls_config.h b/plat/st/stm32mp1/include/stm32mp1_mbedtls_config.h new file mode 100644 index 0000000..2f07621 --- /dev/null +++ b/plat/st/stm32mp1/include/stm32mp1_mbedtls_config.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2022, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef MBEDTLS_CONFIG_H +#define MBEDTLS_CONFIG_H + +/* + * Key algorithms currently supported on mbed TLS libraries + */ +#define TF_MBEDTLS_USE_RSA 0 +#define TF_MBEDTLS_USE_ECDSA 1 + +/* + * Hash algorithms currently supported on mbed TLS libraries + */ +#define TF_MBEDTLS_SHA256 1 +#define TF_MBEDTLS_SHA384 2 +#define TF_MBEDTLS_SHA512 3 + +/* + * Configuration file to build mbed TLS with the required features for + * Trusted Boot + */ + +#define MBEDTLS_PLATFORM_MEMORY +#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS +/* Prevent mbed TLS from using snprintf so that it can use tf_snprintf. */ +#define MBEDTLS_PLATFORM_SNPRINTF_ALT + +#define MBEDTLS_PKCS1_V21 + +#define MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION +#define MBEDTLS_X509_CHECK_KEY_USAGE +#define MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE + +#define MBEDTLS_ASN1_PARSE_C +#define MBEDTLS_ASN1_WRITE_C + +#define MBEDTLS_BASE64_C +#define MBEDTLS_BIGNUM_C + +#define MBEDTLS_ERROR_C +#define MBEDTLS_MD_C + +#define MBEDTLS_MEMORY_BUFFER_ALLOC_C +#define MBEDTLS_OID_C + +#define MBEDTLS_PK_C +#define MBEDTLS_PK_PARSE_C +#define MBEDTLS_PK_WRITE_C + +#define MBEDTLS_PLATFORM_C + +#if TF_MBEDTLS_USE_ECDSA +#define MBEDTLS_ECDSA_C +#define MBEDTLS_ECP_C +#define MBEDTLS_ECP_DP_SECP256R1_ENABLED +#define MBEDTLS_ECP_NO_INTERNAL_RNG +#endif +#if TF_MBEDTLS_USE_RSA +#define MBEDTLS_RSA_C +#define MBEDTLS_X509_RSASSA_PSS_SUPPORT +#endif + +#define MBEDTLS_SHA256_C +#if (TF_MBEDTLS_HASH_ALG_ID != TF_MBEDTLS_SHA256) +#define MBEDTLS_SHA512_C +#endif + +#define MBEDTLS_VERSION_C + +#define MBEDTLS_X509_USE_C +#define MBEDTLS_X509_CRT_PARSE_C + +#if TF_MBEDTLS_USE_AES_GCM +#define MBEDTLS_AES_C +#define MBEDTLS_CIPHER_C +#define MBEDTLS_GCM_C +#endif + +/* MPI / BIGNUM options */ +#define MBEDTLS_MPI_WINDOW_SIZE 2 + +#if TF_MBEDTLS_USE_RSA +#if TF_MBEDTLS_KEY_SIZE <= 2048 +#define MBEDTLS_MPI_MAX_SIZE 256 +#else +#define MBEDTLS_MPI_MAX_SIZE 512 +#endif +#else +#define MBEDTLS_MPI_MAX_SIZE 256 +#endif + +/* Memory buffer allocator options */ +#define MBEDTLS_MEMORY_ALIGN_MULTIPLE 8 + +/* + * Prevent the use of 128-bit division which + * creates dependency on external libraries. + */ +#define MBEDTLS_NO_UDBL_DIVISION + +#ifndef __ASSEMBLER__ +/* System headers required to build mbed TLS with the current configuration */ +#include <stdlib.h> +#include <mbedtls/check_config.h> +#endif + +/* + * Mbed TLS heap size is smal as we only use the asn1 + * parsing functions + * digest, signature and crypto algorithm are done by + * other library. + */ + +#define TF_MBEDTLS_HEAP_SIZE U(5120) +#endif /* MBEDTLS_CONFIG_H */ diff --git a/plat/st/stm32mp1/include/stm32mp1_private.h b/plat/st/stm32mp1/include/stm32mp1_private.h new file mode 100644 index 0000000..21ef60d --- /dev/null +++ b/plat/st/stm32mp1/include/stm32mp1_private.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef STM32MP1_PRIVATE_H +#define STM32MP1_PRIVATE_H + +#include <stdint.h> + +void configure_mmu(void); + +void stm32mp1_arch_security_setup(void); +void stm32mp1_security_setup(void); + +void stm32mp1_gic_pcpu_init(void); +void stm32mp1_gic_init(void); + +void stm32mp1_syscfg_init(void); +void stm32mp1_syscfg_enable_io_compensation_start(void); +void stm32mp1_syscfg_enable_io_compensation_finish(void); +void stm32mp1_syscfg_disable_io_compensation(void); +uint32_t stm32mp1_syscfg_get_chip_version(void); +uint32_t stm32mp1_syscfg_get_chip_dev_id(void); +#if STM32MP13 +void stm32mp1_syscfg_boot_mode_enable(void); +void stm32mp1_syscfg_boot_mode_disable(void); +#endif +#if STM32MP15 +static inline void stm32mp1_syscfg_boot_mode_enable(void){} +static inline void stm32mp1_syscfg_boot_mode_disable(void){} +#endif + +void stm32mp1_deconfigure_uart_pins(void); + +void stm32mp1_init_scmi_server(void); +#endif /* STM32MP1_PRIVATE_H */ diff --git a/plat/st/stm32mp1/include/stm32mp1_shared_resources.h b/plat/st/stm32mp1/include/stm32mp1_shared_resources.h new file mode 100644 index 0000000..3f6367e --- /dev/null +++ b/plat/st/stm32mp1/include/stm32mp1_shared_resources.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2017-2020, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef STM32MP1_SHARED_RESOURCES_H +#define STM32MP1_SHARED_RESOURCES_H + +#include <stm32mp_shared_resources.h> + +#define STM32MP1_SHRES_GPIOZ(i) (STM32MP1_SHRES_GPIOZ_0 + (i)) + +enum stm32mp_shres { + STM32MP1_SHRES_CRYP1, + STM32MP1_SHRES_GPIOZ_0, + STM32MP1_SHRES_GPIOZ_1, + STM32MP1_SHRES_GPIOZ_2, + STM32MP1_SHRES_GPIOZ_3, + STM32MP1_SHRES_GPIOZ_4, + STM32MP1_SHRES_GPIOZ_5, + STM32MP1_SHRES_GPIOZ_6, + STM32MP1_SHRES_GPIOZ_7, + STM32MP1_SHRES_HASH1, + STM32MP1_SHRES_I2C4, + STM32MP1_SHRES_I2C6, + STM32MP1_SHRES_IWDG1, + STM32MP1_SHRES_MCU, + STM32MP1_SHRES_MDMA, + STM32MP1_SHRES_PLL3, + STM32MP1_SHRES_RNG1, + STM32MP1_SHRES_RTC, + STM32MP1_SHRES_SPI6, + STM32MP1_SHRES_USART1, + + STM32MP1_SHRES_COUNT +}; +#endif /* STM32MP1_SHARED_RESOURCES_H */ diff --git a/plat/st/stm32mp1/include/stm32mp1_smc.h b/plat/st/stm32mp1/include/stm32mp1_smc.h new file mode 100644 index 0000000..52088de --- /dev/null +++ b/plat/st/stm32mp1/include/stm32mp1_smc.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2016-2021, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef STM32MP1_SMC_H +#define STM32MP1_SMC_H + +/* + * SMC function IDs for STM32 Service queries + * STM32 SMC services use the space between 0x82000000 and 0x8200FFFF + * like this is defined in SMC calling Convention by ARM + * for SiP (silicon Partner) + * https://developer.arm.com/docs/den0028/latest + */ + +/* Secure Service access from Non-secure */ + +/* + * STM32_SMC_BSEC call API + * + * Argument a0: (input) SMCC ID + * (output) status return code + * Argument a1: (input) Service ID (STM32_SMC_BSEC_xxx) + * Argument a2: (input) OTP index + * (output) OTP read value, if applicable + * Argument a3: (input) OTP value if applicable + */ +#define STM32_SMC_BSEC 0x82001003 + +/* + * STM32_SIP_SMC_SCMI_AGENT0 + * STM32_SIP_SMC_SCMI_AGENT1 + * Process SCMI message pending in SCMI shared memory buffer. + * + * Argument a0: (input) SMCC ID + */ +#define STM32_SIP_SMC_SCMI_AGENT0 0x82002000 +#define STM32_SIP_SMC_SCMI_AGENT1 0x82002001 + +/* SMC function IDs for SiP Service queries */ +#define STM32_SIP_SVC_CALL_COUNT 0x8200ff00 +#define STM32_SIP_SVC_UID 0x8200ff01 +/* 0x8200ff02 is reserved */ +#define STM32_SIP_SVC_VERSION 0x8200ff03 + +/* STM32 SiP Service Calls version numbers */ +#define STM32_SIP_SVC_VERSION_MAJOR 0x0 +#define STM32_SIP_SVC_VERSION_MINOR 0x1 + +/* Number of STM32 SiP Calls implemented */ +#define STM32_COMMON_SIP_NUM_CALLS 3 + +/* Service for BSEC */ +#define STM32_SMC_READ_SHADOW 0x01 +#define STM32_SMC_PROG_OTP 0x02 +#define STM32_SMC_WRITE_SHADOW 0x03 +#define STM32_SMC_READ_OTP 0x04 + +/* SMC error codes */ +#define STM32_SMC_OK 0x00000000U +#define STM32_SMC_NOT_SUPPORTED 0xFFFFFFFFU +#define STM32_SMC_FAILED 0xFFFFFFFEU +#define STM32_SMC_INVALID_PARAMS 0xFFFFFFFDU + +#endif /* STM32MP1_SMC_H */ diff --git a/plat/st/stm32mp1/include/tbbr/stm32mp1_tbb_cert.h b/plat/st/stm32mp1/include/tbbr/stm32mp1_tbb_cert.h new file mode 100644 index 0000000..2cc1e19 --- /dev/null +++ b/plat/st/stm32mp1/include/tbbr/stm32mp1_tbb_cert.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef STM32MP1_TBB_CERT_H +#define STM32MP1_TBB_CERT_H + +#include <tbbr/tbb_cert.h> + +/* + * Enumerate the certificates that are used to establish the chain of trust + */ +enum { + STM32MP_CONFIG_CERT = FWU_CERT + 1 +}; + +#endif /* STM32MP1_TBB_CERT_H */ diff --git a/plat/st/stm32mp1/plat_bl2_mem_params_desc.c b/plat/st/stm32mp1/plat_bl2_mem_params_desc.c new file mode 100644 index 0000000..9ca0930 --- /dev/null +++ b/plat/st/stm32mp1/plat_bl2_mem_params_desc.c @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <common/bl_common.h> +#include <common/desc_image_load.h> +#include <plat/common/platform.h> + +#include <platform_def.h> + +/******************************************************************************* + * Following descriptor provides BL image/ep information that gets used + * by BL2 to load the images and also subset of this information is + * passed to next BL image. The image loading sequence is managed by + * populating the images in required loading order. The image execution + * sequence is managed by populating the `next_handoff_image_id` with + * the next executable image id. + ******************************************************************************/ +static bl_mem_params_node_t bl2_mem_params_descs[] = { + /* Fill FW_CONFIG related information if it exists */ + { + .image_id = FW_CONFIG_ID, + SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY, + VERSION_2, entry_point_info_t, + SECURE | NON_EXECUTABLE), + SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY, + VERSION_2, image_info_t, + IMAGE_ATTRIB_PLAT_SETUP), + + .image_info.image_base = STM32MP_FW_CONFIG_BASE, + .image_info.image_max_size = STM32MP_FW_CONFIG_MAX_SIZE, + + .next_handoff_image_id = INVALID_IMAGE_ID, + }, + + /* Fill BL32 related information */ + { + .image_id = BL32_IMAGE_ID, + + SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, + VERSION_2, entry_point_info_t, + SECURE | EXECUTABLE | EP_FIRST_EXE), + + .ep_info.spsr = SPSR_MODE32(MODE32_svc, SPSR_T_ARM, + SPSR_E_LITTLE, + DISABLE_ALL_EXCEPTIONS), + + SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, + VERSION_2, image_info_t, + IMAGE_ATTRIB_SKIP_LOADING), + + .next_handoff_image_id = BL33_IMAGE_ID, + }, + + /* Fill BL32 external 1 image related information */ + { + .image_id = BL32_EXTRA1_IMAGE_ID, + + SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, + VERSION_2, entry_point_info_t, + SECURE | NON_EXECUTABLE), + + SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, + VERSION_2, image_info_t, + IMAGE_ATTRIB_SKIP_LOADING), + + .next_handoff_image_id = INVALID_IMAGE_ID, + }, +#if STM32MP15 + /* Fill BL32 external 2 image related information */ + { + .image_id = BL32_EXTRA2_IMAGE_ID, + + SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, + VERSION_2, entry_point_info_t, + SECURE | NON_EXECUTABLE), + + SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, + VERSION_2, image_info_t, + IMAGE_ATTRIB_SKIP_LOADING), + + .next_handoff_image_id = INVALID_IMAGE_ID, + }, +#endif + + /* Fill HW_CONFIG related information if it exists */ + { + .image_id = HW_CONFIG_ID, + SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY, + VERSION_2, entry_point_info_t, + NON_SECURE | NON_EXECUTABLE), + SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY, + VERSION_2, image_info_t, + IMAGE_ATTRIB_SKIP_LOADING), + + .next_handoff_image_id = INVALID_IMAGE_ID, + }, + + /* Fill TOS_FW_CONFIG related information if it exists */ + { + .image_id = TOS_FW_CONFIG_ID, + SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY, + VERSION_2, entry_point_info_t, + SECURE | NON_EXECUTABLE), + SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY, + VERSION_2, image_info_t, + IMAGE_ATTRIB_SKIP_LOADING), + + .next_handoff_image_id = INVALID_IMAGE_ID, + }, + + /* Fill BL33 related information */ + { + .image_id = BL33_IMAGE_ID, + + SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, + VERSION_2, entry_point_info_t, + NON_SECURE | EXECUTABLE), + + .ep_info.spsr = SPSR_MODE32(MODE32_svc, SPSR_T_ARM, + SPSR_E_LITTLE, + DISABLE_ALL_EXCEPTIONS), + + SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, + VERSION_2, image_info_t, + IMAGE_ATTRIB_SKIP_LOADING), + + .next_handoff_image_id = INVALID_IMAGE_ID, + } +}; + +REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs) diff --git a/plat/st/stm32mp1/plat_def_uuid_config.c b/plat/st/stm32mp1/plat_def_uuid_config.c new file mode 100644 index 0000000..efaf567 --- /dev/null +++ b/plat/st/stm32mp1/plat_def_uuid_config.c @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2022, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <firmware_image_package.h> + +#include "tbbr_config.h" + +toc_entry_t plat_def_toc_entries[] = { + { + .name = "STM32MP CONFIG CERT", + .uuid = UUID_STM32MP_CONFIG_CERT, + .cmdline_name = "stm32mp-cfg-cert" + } +}; + diff --git a/plat/st/stm32mp1/plat_fiptool.mk b/plat/st/stm32mp1/plat_fiptool.mk new file mode 100644 index 0000000..00570c2 --- /dev/null +++ b/plat/st/stm32mp1/plat_fiptool.mk @@ -0,0 +1,25 @@ +# +# Copyright (c) 2021-2022, STMicroelectronics - All Rights Reserved +# +# SPDX-License-Identifier: BSD-3-Clause +# + +# Name of the platform defined source file name, +# which contains platform defined UUID entries populated +# in the plat_def_toc_entries[]. +PLAT_DEF_UUID_FILE_NAME := plat_def_uuid_config + +INCLUDE_PATHS += -I${PLAT_DIR}/include -I./ + +PLAT_DEF_UUID := yes + +ifeq (${PLAT_DEF_UUID},yes) +HOSTCCFLAGS += -DPLAT_DEF_FIP_UUID + +${PLAT_DEF_UUID_FILE_NAME}.o: ${PLAT_DIR}${PLAT_DEF_UUID_FILE_NAME}.c + ${HOSTCC} -c ${CPPFLAGS} ${HOSTCCFLAGS} ${INCLUDE_PATHS} $< -o $@ + +PLAT_OBJECTS += ${PLAT_DEF_UUID_FILE_NAME}.o +endif + +OBJECTS += ${PLAT_OBJECTS} diff --git a/plat/st/stm32mp1/plat_image_load.c b/plat/st/stm32mp1/plat_image_load.c new file mode 100644 index 0000000..c4048fc --- /dev/null +++ b/plat/st/stm32mp1/plat_image_load.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <common/desc_image_load.h> + +/******************************************************************************* + * This function flushes the data structures so that they are visible + * in memory for the next BL image. + ******************************************************************************/ +void plat_flush_next_bl_params(void) +{ + flush_bl_params_desc(); +} + +/******************************************************************************* + * This function returns the list of loadable images. + ******************************************************************************/ +bl_load_info_t *plat_get_bl_image_load_info(void) +{ + return get_bl_load_info_from_mem_params_desc(); +} + +/******************************************************************************* + * This function returns the list of executable images. + ******************************************************************************/ +bl_params_t *plat_get_next_bl_params(void) +{ + bl_params_t *bl_params = get_next_bl_params_from_mem_params_desc(); + + populate_next_bl_params_config(bl_params); + + return bl_params; +} diff --git a/plat/st/stm32mp1/platform.mk b/plat/st/stm32mp1/platform.mk new file mode 100644 index 0000000..7eecf30 --- /dev/null +++ b/plat/st/stm32mp1/platform.mk @@ -0,0 +1,553 @@ +# +# Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +ARM_CORTEX_A7 := yes +ARM_WITH_NEON := yes +BL2_AT_EL3 := 1 +USE_COHERENT_MEM := 0 + +STM32MP_EARLY_CONSOLE ?= 0 +STM32MP_RECONFIGURE_CONSOLE ?= 0 +STM32MP_UART_BAUDRATE ?= 115200 + +TRUSTED_BOARD_BOOT ?= 0 +STM32MP_USE_EXTERNAL_HEAP ?= 0 + +# Use secure library from the ROM code for authentication +STM32MP_CRYPTO_ROM_LIB ?= 0 + +# Please don't increment this value without good understanding of +# the monotonic counter +STM32_TF_VERSION ?= 0 + +# Enable dynamic memory mapping +PLAT_XLAT_TABLES_DYNAMIC := 1 + +# Default Device tree +DTB_FILE_NAME ?= stm32mp157c-ev1.dtb + +STM32MP13 ?= 0 +STM32MP15 ?= 0 + +ifeq ($(STM32MP13),1) +ifeq ($(STM32MP15),1) +$(error Cannot enable both flags STM32MP13 and STM32MP15) +endif +STM32MP13 := 1 +STM32MP15 := 0 +else ifeq ($(STM32MP15),1) +STM32MP13 := 0 +STM32MP15 := 1 +else ifneq ($(findstring stm32mp13,$(DTB_FILE_NAME)),) +STM32MP13 := 1 +STM32MP15 := 0 +else ifneq ($(findstring stm32mp15,$(DTB_FILE_NAME)),) +STM32MP13 := 0 +STM32MP15 := 1 +endif + +ifeq ($(STM32MP13),1) +# Will use SRAM2 as mbedtls heap +STM32MP_USE_EXTERNAL_HEAP := 1 + +# DDR controller with single AXI port and 16-bit interface +STM32MP_DDR_DUAL_AXI_PORT:= 0 +STM32MP_DDR_32BIT_INTERFACE:= 0 + +ifeq (${TRUSTED_BOARD_BOOT},1) +# PKA algo to include +PKA_USE_NIST_P256 := 1 +PKA_USE_BRAINPOOL_P256T1:= 1 +endif + +# STM32 image header version v2.0 +STM32_HEADER_VERSION_MAJOR:= 2 +STM32_HEADER_VERSION_MINOR:= 0 +endif + +ifeq ($(STM32MP15),1) +# DDR controller with dual AXI port and 32-bit interface +STM32MP_DDR_DUAL_AXI_PORT:= 1 +STM32MP_DDR_32BIT_INTERFACE:= 1 + +# STM32 image header version v1.0 +STM32_HEADER_VERSION_MAJOR:= 1 +STM32_HEADER_VERSION_MINOR:= 0 + +# Add OP-TEE reserved shared memory area in mapping +STM32MP15_OPTEE_RSV_SHM := 1 +$(eval $(call add_defines,STM32MP15_OPTEE_RSV_SHM)) + +STM32MP_CRYPTO_ROM_LIB := 1 + +# Decryption support +ifneq ($(DECRYPTION_SUPPORT),none) +$(error "DECRYPTION_SUPPORT not supported on STM32MP15") +endif +endif + +# STM32 image header binary type for BL2 +STM32_HEADER_BL2_BINARY_TYPE:= 0x10 + +ifeq ($(AARCH32_SP),sp_min) +# Disable Neon support: sp_min runtime may conflict with non-secure world +TF_CFLAGS += -mfloat-abi=soft +endif + +TF_CFLAGS += -Wsign-compare +TF_CFLAGS += -Wformat-signedness + +# Not needed for Cortex-A7 +WORKAROUND_CVE_2017_5715:= 0 +WORKAROUND_CVE_2022_23960:= 0 + +# Number of TF-A copies in the device +STM32_TF_A_COPIES := 2 + +# PLAT_PARTITION_MAX_ENTRIES must take care of STM32_TF-A_COPIES and other partitions +# such as metadata (2) to find all the FIP partitions (default is 2). +PLAT_PARTITION_MAX_ENTRIES := $(shell echo $$(($(STM32_TF_A_COPIES) + 4))) + +ifeq (${PSA_FWU_SUPPORT},1) +# Number of banks of updatable firmware +NR_OF_FW_BANKS := 2 +NR_OF_IMAGES_IN_FW_BANK := 1 + +FWU_MAX_PART = $(shell echo $$(($(STM32_TF_A_COPIES) + 2 + $(NR_OF_FW_BANKS)))) +ifeq ($(shell test $(FWU_MAX_PART) -gt $(PLAT_PARTITION_MAX_ENTRIES); echo $$?),0) +$(error "Required partition number is $(FWU_MAX_PART) where PLAT_PARTITION_MAX_ENTRIES is only \ +$(PLAT_PARTITION_MAX_ENTRIES)") +endif +endif + +ifeq ($(STM32MP13),1) +STM32_HASH_VER := 4 +STM32_RNG_VER := 4 +else # Assuming STM32MP15 +STM32_HASH_VER := 2 +STM32_RNG_VER := 2 +endif + +# Boot devices +STM32MP_EMMC ?= 0 +STM32MP_SDMMC ?= 0 +STM32MP_RAW_NAND ?= 0 +STM32MP_SPI_NAND ?= 0 +STM32MP_SPI_NOR ?= 0 +STM32MP_EMMC_BOOT ?= 0 + +# Serial boot devices +STM32MP_USB_PROGRAMMER ?= 0 +STM32MP_UART_PROGRAMMER ?= 0 + +# Download load address for serial boot devices +DWL_BUFFER_BASE ?= 0xC7000000 + +# Device tree +ifeq ($(STM32MP13),1) +BL2_DTSI := stm32mp13-bl2.dtsi +FDT_SOURCES := $(addprefix ${BUILD_PLAT}/fdts/, $(patsubst %.dtb,%-bl2.dts,$(DTB_FILE_NAME))) +else +BL2_DTSI := stm32mp15-bl2.dtsi +FDT_SOURCES := $(addprefix ${BUILD_PLAT}/fdts/, $(patsubst %.dtb,%-bl2.dts,$(DTB_FILE_NAME))) +ifeq ($(AARCH32_SP),sp_min) +BL32_DTSI := stm32mp15-bl32.dtsi +FDT_SOURCES += $(addprefix ${BUILD_PLAT}/fdts/, $(patsubst %.dtb,%-bl32.dts,$(DTB_FILE_NAME))) +endif +endif + +$(eval DTC_V = $(shell $(DTC) -v | awk '{print $$NF}')) +$(eval DTC_VERSION = $(shell printf "%d" $(shell echo ${DTC_V} | cut -d- -f1 | sed "s/\./0/g" | grep -o "[0-9]*"))) +DTC_CPPFLAGS += ${INCLUDES} +DTC_FLAGS += -Wno-unit_address_vs_reg +ifeq ($(shell test $(DTC_VERSION) -ge 10601; echo $$?),0) +DTC_FLAGS += -Wno-interrupt_provider +endif + +# Macros and rules to build TF binary +STM32_TF_ELF_LDFLAGS := --hash-style=gnu --as-needed +STM32_TF_STM32 := $(addprefix ${BUILD_PLAT}/tf-a-, $(patsubst %.dtb,%.stm32,$(DTB_FILE_NAME))) +STM32_TF_LINKERFILE := ${BUILD_PLAT}/stm32mp1.ld + +ASFLAGS += -DBL2_BIN_PATH=\"${BUILD_PLAT}/bl2.bin\" +ifeq ($(AARCH32_SP),sp_min) +# BL32 is built only if using SP_MIN +BL32_DEP := bl32 +ASFLAGS += -DBL32_BIN_PATH=\"${BUILD_PLAT}/bl32.bin\" +endif + +# Variables for use with stm32image +STM32IMAGEPATH ?= tools/stm32image +STM32IMAGE ?= ${STM32IMAGEPATH}/stm32image${BIN_EXT} +STM32IMAGE_SRC := ${STM32IMAGEPATH}/stm32image.c + +FIP_DEPS += dtbs +STM32MP_HW_CONFIG := ${BL33_CFG} +STM32MP_FW_CONFIG_NAME := $(patsubst %.dtb,%-fw-config.dtb,$(DTB_FILE_NAME)) +STM32MP_FW_CONFIG := ${BUILD_PLAT}/fdts/$(STM32MP_FW_CONFIG_NAME) +ifneq (${AARCH32_SP},none) +FDT_SOURCES += $(addprefix fdts/, $(patsubst %.dtb,%.dts,$(STM32MP_FW_CONFIG_NAME))) +endif +# Add the FW_CONFIG to FIP and specify the same to certtool +$(eval $(call TOOL_ADD_PAYLOAD,${STM32MP_FW_CONFIG},--fw-config)) +# Add the HW_CONFIG to FIP and specify the same to certtool +$(eval $(call TOOL_ADD_PAYLOAD,${STM32MP_HW_CONFIG},--hw-config)) +ifeq ($(GENERATE_COT),1) +STM32MP_CFG_CERT := $(BUILD_PLAT)/stm32mp_cfg_cert.crt +# Add the STM32MP_CFG_CERT to FIP and specify the same to certtool +$(eval $(call TOOL_ADD_PAYLOAD,${STM32MP_CFG_CERT},--stm32mp-cfg-cert)) +endif +ifeq ($(AARCH32_SP),sp_min) +STM32MP_TOS_FW_CONFIG := $(addprefix ${BUILD_PLAT}/fdts/, $(patsubst %.dtb,%-bl32.dtb,$(DTB_FILE_NAME))) +$(eval $(call TOOL_ADD_PAYLOAD,${STM32MP_TOS_FW_CONFIG},--tos-fw-config)) +else +# Add the build options to pack Trusted OS Extra1 and Trusted OS Extra2 images +# in the FIP if the platform requires. +ifneq ($(BL32_EXTRA1),) +$(eval $(call TOOL_ADD_IMG,BL32_EXTRA1,--tos-fw-extra1,,$(ENCRYPT_BL32))) +endif +ifneq ($(BL32_EXTRA2),) +$(eval $(call TOOL_ADD_IMG,BL32_EXTRA2,--tos-fw-extra2,,$(ENCRYPT_BL32))) +endif +endif + +# Enable flags for C files +$(eval $(call assert_booleans,\ + $(sort \ + PKA_USE_BRAINPOOL_P256T1 \ + PKA_USE_NIST_P256 \ + PLAT_TBBR_IMG_DEF \ + PLAT_XLAT_TABLES_DYNAMIC \ + STM32MP_CRYPTO_ROM_LIB \ + STM32MP_DDR_32BIT_INTERFACE \ + STM32MP_DDR_DUAL_AXI_PORT \ + STM32MP_EARLY_CONSOLE \ + STM32MP_EMMC \ + STM32MP_EMMC_BOOT \ + STM32MP_RAW_NAND \ + STM32MP_RECONFIGURE_CONSOLE \ + STM32MP_SDMMC \ + STM32MP_SPI_NAND \ + STM32MP_SPI_NOR \ + STM32MP_UART_PROGRAMMER \ + STM32MP_USB_PROGRAMMER \ + STM32MP_USE_EXTERNAL_HEAP \ + STM32MP13 \ + STM32MP15 \ +))) + +$(eval $(call assert_numerics,\ + $(sort \ + PLAT_PARTITION_MAX_ENTRIES \ + STM32_HASH_VER \ + STM32_HEADER_VERSION_MAJOR \ + STM32_RNG_VER \ + STM32_TF_A_COPIES \ + STM32_TF_VERSION \ + STM32MP_UART_BAUDRATE \ +))) + +$(eval $(call add_defines,\ + $(sort \ + DWL_BUFFER_BASE \ + PKA_USE_BRAINPOOL_P256T1 \ + PKA_USE_NIST_P256 \ + PLAT_PARTITION_MAX_ENTRIES \ + PLAT_TBBR_IMG_DEF \ + PLAT_XLAT_TABLES_DYNAMIC \ + STM32_HASH_VER \ + STM32_HEADER_VERSION_MAJOR \ + STM32_RNG_VER \ + STM32_TF_A_COPIES \ + STM32_TF_VERSION \ + STM32MP_CRYPTO_ROM_LIB \ + STM32MP_DDR_32BIT_INTERFACE \ + STM32MP_DDR_DUAL_AXI_PORT \ + STM32MP_EARLY_CONSOLE \ + STM32MP_EMMC \ + STM32MP_EMMC_BOOT \ + STM32MP_RAW_NAND \ + STM32MP_RECONFIGURE_CONSOLE \ + STM32MP_SDMMC \ + STM32MP_SPI_NAND \ + STM32MP_SPI_NOR \ + STM32MP_UART_BAUDRATE \ + STM32MP_UART_PROGRAMMER \ + STM32MP_USB_PROGRAMMER \ + STM32MP_USE_EXTERNAL_HEAP \ + STM32MP13 \ + STM32MP15 \ +))) + +# Include paths and source files +PLAT_INCLUDES := -Iplat/st/common/include/ +PLAT_INCLUDES += -Iplat/st/stm32mp1/include/ + +include lib/fconf/fconf.mk +include lib/libfdt/libfdt.mk + +PLAT_BL_COMMON_SOURCES := common/uuid.c \ + plat/st/common/stm32mp_common.c \ + plat/st/stm32mp1/stm32mp1_private.c + +PLAT_BL_COMMON_SOURCES += drivers/st/uart/aarch32/stm32_console.S + +ifneq (${ENABLE_STACK_PROTECTOR},0) +PLAT_BL_COMMON_SOURCES += plat/st/stm32mp1/stm32mp1_stack_protector.c +endif + +include lib/xlat_tables_v2/xlat_tables.mk +PLAT_BL_COMMON_SOURCES += ${XLAT_TABLES_LIB_SRCS} + +PLAT_BL_COMMON_SOURCES += lib/cpus/aarch32/cortex_a7.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/ddr/stm32mp_ddr.c \ + drivers/st/ddr/stm32mp1_ddr_helpers.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/regulator_core.c \ + drivers/st/regulator/regulator_fixed.c \ + drivers/st/reset/stm32mp1_reset.c \ + plat/st/common/stm32mp_dt.c \ + plat/st/stm32mp1/stm32mp1_dbgmcu.c \ + plat/st/stm32mp1/stm32mp1_helper.S \ + plat/st/stm32mp1/stm32mp1_syscfg.c + +ifeq ($(STM32MP13),1) +PLAT_BL_COMMON_SOURCES += drivers/st/clk/clk-stm32-core.c \ + drivers/st/clk/clk-stm32mp13.c \ + drivers/st/crypto/stm32_rng.c +else +PLAT_BL_COMMON_SOURCES += drivers/st/clk/stm32mp1_clk.c +endif + +BL2_SOURCES += ${FCONF_SOURCES} ${FCONF_DYN_SOURCES} + +BL2_SOURCES += drivers/io/io_fip.c \ + plat/st/common/bl2_io_storage.c \ + plat/st/common/stm32mp_fconf_io.c \ + plat/st/stm32mp1/plat_bl2_mem_params_desc.c \ + plat/st/stm32mp1/stm32mp1_fconf_firewall.c + +include lib/zlib/zlib.mk + +ifeq (${PSA_FWU_SUPPORT},1) +include drivers/fwu/fwu.mk +endif + + +BL2_SOURCES += $(ZLIB_SOURCES) + +BL2_SOURCES += drivers/io/io_block.c \ + drivers/io/io_mtd.c \ + drivers/io/io_storage.c \ + drivers/st/crypto/stm32_hash.c \ + plat/st/stm32mp1/bl2_plat_setup.c + +ifneq (${DECRYPTION_SUPPORT},none) +BL2_SOURCES += drivers/io/io_encrypted.c +endif + +ifeq (${TRUSTED_BOARD_BOOT},1) +AUTH_SOURCES := drivers/auth/auth_mod.c \ + drivers/auth/crypto_mod.c \ + drivers/auth/img_parser_mod.c + +ifeq (${GENERATE_COT},1) +TFW_NVCTR_VAL := 0 +NTFW_NVCTR_VAL := 0 +KEY_SIZE := +KEY_ALG := ecdsa +HASH_ALG := sha256 + +ifeq (${SAVE_KEYS},1) +TRUSTED_WORLD_KEY ?= ${BUILD_PLAT}/trusted.pem +NON_TRUSTED_WORLD_KEY ?= ${BUILD_PLAT}/non-trusted.pem +BL32_KEY ?= ${BUILD_PLAT}/trusted_os.pem +BL33_KEY ?= ${BUILD_PLAT}/non-trusted_os.pem +endif + +endif +TF_MBEDTLS_KEY_ALG := ecdsa +MBEDTLS_CONFIG_FILE ?= "<stm32mp1_mbedtls_config.h>" + +include drivers/auth/mbedtls/mbedtls_x509.mk + +COT_DESC_IN_DTB := 1 +AUTH_SOURCES += lib/fconf/fconf_cot_getter.c \ + lib/fconf/fconf_tbbr_getter.c \ + plat/st/common/stm32mp_crypto_lib.c + +ifeq ($(STM32MP13),1) +AUTH_SOURCES += drivers/st/crypto/stm32_pka.c +AUTH_SOURCES += drivers/st/crypto/stm32_saes.c +endif + +BL2_SOURCES += $(AUTH_SOURCES) \ + plat/st/common/stm32mp_trusted_boot.c +endif + +ifneq ($(filter 1,${STM32MP_EMMC} ${STM32MP_SDMMC}),) +BL2_SOURCES += drivers/mmc/mmc.c \ + drivers/partition/gpt.c \ + drivers/partition/partition.c \ + drivers/st/io/io_mmc.c \ + drivers/st/mmc/stm32_sdmmc2.c +endif + +ifeq (${STM32MP_RAW_NAND},1) +$(eval $(call add_define_val,NAND_ONFI_DETECT,1)) +BL2_SOURCES += drivers/mtd/nand/raw_nand.c \ + drivers/st/fmc/stm32_fmc2_nand.c +endif + +ifeq (${STM32MP_SPI_NAND},1) +BL2_SOURCES += drivers/mtd/nand/spi_nand.c +endif + +ifeq (${STM32MP_SPI_NOR},1) +ifneq (${STM32MP_FORCE_MTD_START_OFFSET},) +$(eval $(call add_define_val,STM32MP_NOR_FIP_OFFSET,${STM32MP_FORCE_MTD_START_OFFSET})) +endif +BL2_SOURCES += drivers/mtd/nor/spi_nor.c +endif + +ifneq ($(filter 1,${STM32MP_SPI_NAND} ${STM32MP_SPI_NOR}),) +BL2_SOURCES += drivers/mtd/spi-mem/spi_mem.c \ + drivers/st/spi/stm32_qspi.c +endif + +ifneq ($(filter 1,${STM32MP_RAW_NAND} ${STM32MP_SPI_NAND}),) +ifneq (${STM32MP_FORCE_MTD_START_OFFSET},) +$(eval $(call add_define_val,STM32MP_NAND_FIP_OFFSET,${STM32MP_FORCE_MTD_START_OFFSET})) +endif +BL2_SOURCES += drivers/mtd/nand/core.c +endif + +ifneq ($(filter 1,${STM32MP_RAW_NAND} ${STM32MP_SPI_NAND} ${STM32MP_SPI_NOR}),) +BL2_SOURCES += plat/st/stm32mp1/stm32mp1_boot_device.c +endif + +ifneq ($(filter 1,${STM32MP_UART_PROGRAMMER} ${STM32MP_USB_PROGRAMMER}),) +BL2_SOURCES += drivers/io/io_memmap.c +endif + +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) +#The DFU stack uses only one end point, reduce the USB stack footprint +$(eval $(call add_define_val,CONFIG_USBD_EP_NB,1U)) +BL2_SOURCES += drivers/st/usb/stm32mp1_usb.c \ + drivers/usb/usb_device.c \ + plat/st/common/stm32cubeprogrammer_usb.c \ + plat/st/common/usb_dfu.c \ + plat/st/stm32mp1/stm32mp1_usb_dfu.c +endif + +BL2_SOURCES += drivers/st/ddr/stm32mp_ddr_test.c \ + drivers/st/ddr/stm32mp_ram.c \ + drivers/st/ddr/stm32mp1_ddr.c \ + drivers/st/ddr/stm32mp1_ram.c + +BL2_SOURCES += common/desc_image_load.c \ + plat/st/stm32mp1/plat_image_load.c + +BL2_SOURCES += lib/optee/optee_utils.c + +# Compilation rules +.PHONY: check_dtc_version stm32image clean_stm32image check_boot_device +.SUFFIXES: + +all: check_dtc_version stm32image ${STM32_TF_STM32} + +distclean realclean clean: clean_stm32image + +bl2: check_boot_device + +check_boot_device: + @if [ ${STM32MP_EMMC} != 1 ] && \ + [ ${STM32MP_SDMMC} != 1 ] && \ + [ ${STM32MP_RAW_NAND} != 1 ] && \ + [ ${STM32MP_SPI_NAND} != 1 ] && \ + [ ${STM32MP_SPI_NOR} != 1 ] && \ + [ ${STM32MP_UART_PROGRAMMER} != 1 ] && \ + [ ${STM32MP_USB_PROGRAMMER} != 1 ]; then \ + echo "No boot device driver is enabled"; \ + false; \ + fi + +stm32image: ${STM32IMAGE} + +${STM32IMAGE}: ${STM32IMAGE_SRC} + ${Q}${MAKE} CPPFLAGS="" --no-print-directory -C ${STM32IMAGEPATH} + +clean_stm32image: + ${Q}${MAKE} --no-print-directory -C ${STM32IMAGEPATH} clean + +check_dtc_version: + @if [ ${DTC_VERSION} -lt 10404 ]; then \ + echo "dtc version too old (${DTC_V}), you need at least version 1.4.4"; \ + false; \ + fi + +# Create DTB file for BL2 +${BUILD_PLAT}/fdts/%-bl2.dts: fdts/%.dts fdts/${BL2_DTSI} | ${BUILD_PLAT} fdt_dirs + @echo '#include "$(patsubst fdts/%,%,$<)"' > $@ + @echo '#include "${BL2_DTSI}"' >> $@ + +${BUILD_PLAT}/fdts/%-bl2.dtb: ${BUILD_PLAT}/fdts/%-bl2.dts + +ifeq ($(AARCH32_SP),sp_min) +# Create DTB file for BL32 +${BUILD_PLAT}/fdts/%-bl32.dts: fdts/%.dts fdts/${BL32_DTSI} | ${BUILD_PLAT} fdt_dirs + @echo '#include "$(patsubst fdts/%,%,$<)"' > $@ + @echo '#include "${BL32_DTSI}"' >> $@ + +${BUILD_PLAT}/fdts/%-bl32.dtb: ${BUILD_PLAT}/fdts/%-bl32.dts +endif + +${BUILD_PLAT}/stm32mp1-%.o: ${BUILD_PLAT}/fdts/%-bl2.dtb plat/st/stm32mp1/stm32mp1.S bl2 + @echo " AS stm32mp1.S" + ${Q}${AS} ${ASFLAGS} ${TF_CFLAGS} \ + -DDTB_BIN_PATH=\"$<\" \ + -c plat/st/stm32mp1/stm32mp1.S -o $@ + +$(eval $(call MAKE_LD,${STM32_TF_LINKERFILE},plat/st/stm32mp1/stm32mp1.ld.S,bl2)) + +tf-a-%.elf: stm32mp1-%.o ${STM32_TF_LINKERFILE} + @echo " LDS $<" + ${Q}${LD} -o $@ ${STM32_TF_ELF_LDFLAGS} -Map=$(@:.elf=.map) --script ${STM32_TF_LINKERFILE} $< + +tf-a-%.bin: tf-a-%.elf + ${Q}${OC} -O binary $< $@ + @echo + @echo "Built $@ successfully" + @echo + +tf-a-%.stm32: ${STM32IMAGE} tf-a-%.bin + @echo + @echo "Generate $@" + $(eval LOADADDR = $(shell cat $(@:.stm32=.map) | grep RAM | awk '{print $$2}')) + $(eval ENTRY = $(shell cat $(@:.stm32=.map) | grep "__BL2_IMAGE_START" | awk '{print $$1}')) + ${Q}${STM32IMAGE} -s $(word 2,$^) -d $@ \ + -l $(LOADADDR) -e ${ENTRY} \ + -v ${STM32_TF_VERSION} \ + -m ${STM32_HEADER_VERSION_MAJOR} \ + -n ${STM32_HEADER_VERSION_MINOR} \ + -b ${STM32_HEADER_BL2_BINARY_TYPE} + @echo diff --git a/plat/st/stm32mp1/services/bsec_svc.c b/plat/st/stm32mp1/services/bsec_svc.c new file mode 100644 index 0000000..1fb44b4 --- /dev/null +++ b/plat/st/stm32mp1/services/bsec_svc.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2016-2022, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <platform_def.h> + +#include <common/debug.h> +#include <drivers/st/bsec.h> +#include <drivers/st/bsec2_reg.h> + +#include <stm32mp1_smc.h> + +#include "bsec_svc.h" + +uint32_t bsec_main(uint32_t x1, uint32_t x2, uint32_t x3, + uint32_t *ret_otp_value) +{ + uint32_t result; + uint32_t tmp_data = 0U; + + switch (x1) { + case STM32_SMC_READ_SHADOW: + result = bsec_read_otp(ret_otp_value, x2); + break; + case STM32_SMC_PROG_OTP: + *ret_otp_value = 0U; + result = bsec_program_otp(x3, x2); + break; + case STM32_SMC_WRITE_SHADOW: + *ret_otp_value = 0U; + result = bsec_write_otp(x3, x2); + break; + case STM32_SMC_READ_OTP: + *ret_otp_value = 0U; + result = bsec_read_otp(&tmp_data, x2); + if (result != BSEC_OK) { + break; + } + + result = bsec_shadow_register(x2); + if (result != BSEC_OK) { + break; + } + + result = bsec_read_otp(ret_otp_value, x2); + if (result != BSEC_OK) { + break; + } + + result = bsec_write_otp(tmp_data, x2); + break; + + default: + return STM32_SMC_INVALID_PARAMS; + } + + return (result == BSEC_OK) ? STM32_SMC_OK : STM32_SMC_FAILED; +} diff --git a/plat/st/stm32mp1/services/bsec_svc.h b/plat/st/stm32mp1/services/bsec_svc.h new file mode 100644 index 0000000..06752ef --- /dev/null +++ b/plat/st/stm32mp1/services/bsec_svc.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2016-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef BSEC_SVC_H +#define BSEC_SVC_H + +#include <stdint.h> + +/* version of this service */ +/* must be increase at each structure modification */ +#define BSEC_SERVICE_VERSION 0x01U + +uint32_t bsec_main(uint32_t x1, uint32_t x2, uint32_t x3, + uint32_t *ret_otp_value); + +#endif /* BSEC_SVC_H */ diff --git a/plat/st/stm32mp1/services/stm32mp1_svc_setup.c b/plat/st/stm32mp1/services/stm32mp1_svc_setup.c new file mode 100644 index 0000000..ed8a448 --- /dev/null +++ b/plat/st/stm32mp1/services/stm32mp1_svc_setup.c @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2014-2021, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <stdbool.h> +#include <stdint.h> + +#include <common/debug.h> +#include <common/runtime_svc.h> +#include <drivers/scmi-msg.h> +#include <lib/psci/psci.h> +#include <tools_share/uuid.h> + +#include <stm32mp1_smc.h> + +#include "bsec_svc.h" + +/* STM32 SiP Service UUID */ +DEFINE_SVC_UUID2(stm32_sip_svc_uid, + 0xa778aa50, 0xf49b, 0x144a, 0x8a, 0x5e, + 0x26, 0x4d, 0x59, 0x94, 0xc2, 0x14); + +/* Setup STM32MP1 Standard Services */ +static int32_t stm32mp1_svc_setup(void) +{ + /* + * PSCI is the only specification implemented as a Standard Service. + * Invoke PSCI setup from here. + */ + return 0; +} + +/* + * Top-level Standard Service SMC handler. This handler will in turn dispatch + * calls to PSCI SMC handler. + */ +static uintptr_t stm32mp1_svc_smc_handler(uint32_t smc_fid, u_register_t x1, + u_register_t x2, u_register_t x3, + u_register_t x4, void *cookie, + void *handle, u_register_t flags) +{ + uint32_t ret1 = 0U, ret2 = 0U; + bool ret_uid = false, ret2_enabled = false; + + switch (smc_fid) { + case STM32_SIP_SVC_CALL_COUNT: + ret1 = STM32_COMMON_SIP_NUM_CALLS; + break; + + case STM32_SIP_SVC_UID: + /* Return UUID to the caller */ + ret_uid = true; + break; + + case STM32_SIP_SVC_VERSION: + /* Return the version of current implementation */ + ret1 = STM32_SIP_SVC_VERSION_MAJOR; + ret2 = STM32_SIP_SVC_VERSION_MINOR; + ret2_enabled = true; + break; + + case STM32_SMC_BSEC: + ret1 = bsec_main(x1, x2, x3, &ret2); + ret2_enabled = true; + break; + + case STM32_SIP_SMC_SCMI_AGENT0: + scmi_smt_fastcall_smc_entry(0); + break; + case STM32_SIP_SMC_SCMI_AGENT1: + scmi_smt_fastcall_smc_entry(1); + break; + + default: + WARN("Unimplemented STM32MP1 Service Call: 0x%x\n", smc_fid); + ret1 = STM32_SMC_NOT_SUPPORTED; + break; + } + + if (ret_uid) { + SMC_UUID_RET(handle, stm32_sip_svc_uid); + } + + if (ret2_enabled) { + SMC_RET2(handle, ret1, ret2); + } + + SMC_RET1(handle, ret1); +} + +/* Register Standard Service Calls as runtime service */ +DECLARE_RT_SVC(stm32mp1_sip_svc, + OEN_SIP_START, + OEN_SIP_END, + SMC_TYPE_FAST, + stm32mp1_svc_setup, + stm32mp1_svc_smc_handler +); diff --git a/plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk b/plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk new file mode 100644 index 0000000..1d754d9 --- /dev/null +++ b/plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk @@ -0,0 +1,53 @@ +# +# Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +ifeq ($(STM32MP13),1) +$(error "SP_min is not supported on STM32MP13 platform") +endif + +SP_MIN_WITH_SECURE_FIQ := 1 + +override ENABLE_PIE := 1 +BL32_CFLAGS += -fpie -DENABLE_PIE +BL32_LDFLAGS += $(PIE_LDFLAGS) + +BL32_CFLAGS += -DSTM32MP_SHARED_RESOURCES + +BL32_SOURCES += drivers/st/etzpc/etzpc.c \ + plat/common/aarch32/platform_mp_stack.S \ + plat/st/stm32mp1/sp_min/sp_min_setup.c \ + plat/st/stm32mp1/stm32mp1_pm.c \ + plat/st/stm32mp1/stm32mp1_shared_resources.c \ + plat/st/stm32mp1/stm32mp1_topology.c + +# FDT wrappers +include common/fdt_wrappers.mk +BL32_SOURCES += ${FDT_WRAPPERS_SOURCES} + +# Generic GIC v2 +include drivers/arm/gic/v2/gicv2.mk + +BL32_SOURCES += ${GICV2_SOURCES} \ + plat/common/plat_gicv2.c \ + plat/st/stm32mp1/stm32mp1_gic.c + +# Generic PSCI +BL32_SOURCES += plat/common/plat_psci_common.c + +# SCMI server drivers +BL32_SOURCES += drivers/scmi-msg/base.c \ + drivers/scmi-msg/clock.c \ + drivers/scmi-msg/entry.c \ + drivers/scmi-msg/reset_domain.c \ + drivers/scmi-msg/smt.c + +# stm32mp1 specific services +BL32_SOURCES += plat/st/stm32mp1/services/bsec_svc.c \ + plat/st/stm32mp1/services/stm32mp1_svc_setup.c \ + plat/st/stm32mp1/stm32mp1_scmi.c + +# Arm Archtecture services +BL32_SOURCES += services/arm_arch_svc/arm_arch_svc_setup.c diff --git a/plat/st/stm32mp1/sp_min/sp_min_setup.c b/plat/st/stm32mp1/sp_min/sp_min_setup.c new file mode 100644 index 0000000..50b0794 --- /dev/null +++ b/plat/st/stm32mp1/sp_min/sp_min_setup.c @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <string.h> + +#include <platform_def.h> + +#include <arch_helpers.h> +#include <common/bl_common.h> +#include <common/debug.h> +#include <context.h> +#include <drivers/arm/gicv2.h> +#include <drivers/arm/tzc400.h> +#include <drivers/generic_delay_timer.h> +#include <drivers/st/bsec.h> +#include <drivers/st/etzpc.h> +#include <drivers/st/stm32_gpio.h> +#include <drivers/st/stm32_iwdg.h> +#include <drivers/st/stm32mp1_clk.h> +#include <dt-bindings/clock/stm32mp1-clks.h> +#include <lib/el3_runtime/context_mgmt.h> +#include <lib/mmio.h> +#include <lib/xlat_tables/xlat_tables_v2.h> +#include <plat/common/platform.h> + +#include <platform_sp_min.h> + +/****************************************************************************** + * Placeholder variables for copying the arguments that have been passed to + * BL32 from BL2. + ******************************************************************************/ +static entry_point_info_t bl33_image_ep_info; + +/******************************************************************************* + * Interrupt handler for FIQ (secure IRQ) + ******************************************************************************/ +void sp_min_plat_fiq_handler(uint32_t id) +{ + (void)plat_crash_console_init(); + + switch (id & INT_ID_MASK) { + case STM32MP1_IRQ_TZC400: + tzc400_init(STM32MP1_TZC_BASE); + (void)tzc400_it_handler(); + panic(); + break; + case STM32MP1_IRQ_AXIERRIRQ: + ERROR("STM32MP1_IRQ_AXIERRIRQ generated\n"); + panic(); + break; + default: + ERROR("SECURE IT handler not define for it : %u\n", id); + break; + } +} + +/******************************************************************************* + * Return a pointer to the 'entry_point_info' structure of the next image for + * the security state specified. BL33 corresponds to the non-secure image type + * while BL32 corresponds to the secure image type. A NULL pointer is returned + * if the image does not exist. + ******************************************************************************/ +entry_point_info_t *sp_min_plat_get_bl33_ep_info(void) +{ + entry_point_info_t *next_image_info; + + next_image_info = &bl33_image_ep_info; + + if (next_image_info->pc == 0U) { + return NULL; + } + + return next_image_info; +} + +CASSERT((STM32MP_SEC_SYSRAM_BASE == STM32MP_SYSRAM_BASE) && + ((STM32MP_SEC_SYSRAM_BASE + STM32MP_SEC_SYSRAM_SIZE) <= + (STM32MP_SYSRAM_BASE + STM32MP_SYSRAM_SIZE)), + assert_secure_sysram_fits_at_begining_of_sysram); + +#ifdef STM32MP_NS_SYSRAM_BASE +CASSERT((STM32MP_NS_SYSRAM_BASE >= STM32MP_SEC_SYSRAM_BASE) && + ((STM32MP_NS_SYSRAM_BASE + STM32MP_NS_SYSRAM_SIZE) == + (STM32MP_SYSRAM_BASE + STM32MP_SYSRAM_SIZE)), + assert_non_secure_sysram_fits_at_end_of_sysram); + +CASSERT((STM32MP_NS_SYSRAM_BASE & (PAGE_SIZE_4KB - U(1))) == 0U, + assert_non_secure_sysram_base_is_4kbyte_aligned); + +#define TZMA1_SECURE_RANGE \ + (((STM32MP_NS_SYSRAM_BASE - STM32MP_SYSRAM_BASE) >> FOUR_KB_SHIFT) - 1U) +#else +#define TZMA1_SECURE_RANGE STM32MP1_ETZPC_TZMA_ALL_SECURE +#endif /* STM32MP_NS_SYSRAM_BASE */ +#define TZMA0_SECURE_RANGE STM32MP1_ETZPC_TZMA_ALL_SECURE + +static void stm32mp1_etzpc_early_setup(void) +{ + if (etzpc_init() != 0) { + panic(); + } + + etzpc_configure_tzma(STM32MP1_ETZPC_TZMA_ROM, TZMA0_SECURE_RANGE); + etzpc_configure_tzma(STM32MP1_ETZPC_TZMA_SYSRAM, TZMA1_SECURE_RANGE); +} + +/******************************************************************************* + * Perform any BL32 specific platform actions. + ******************************************************************************/ +void sp_min_early_platform_setup2(u_register_t arg0, u_register_t arg1, + u_register_t arg2, u_register_t arg3) +{ + bl_params_t *params_from_bl2 = (bl_params_t *)arg0; + uintptr_t dt_addr = arg1; + + stm32mp_setup_early_console(); + + /* Imprecise aborts can be masked in NonSecure */ + write_scr(read_scr() | SCR_AW_BIT); + + mmap_add_region(BL_CODE_BASE, BL_CODE_BASE, + BL_CODE_END - BL_CODE_BASE, + MT_CODE | MT_SECURE); + + configure_mmu(); + + assert(params_from_bl2 != NULL); + assert(params_from_bl2->h.type == PARAM_BL_PARAMS); + assert(params_from_bl2->h.version >= VERSION_2); + + bl_params_node_t *bl_params = params_from_bl2->head; + + /* + * Copy BL33 entry point information. + * They are stored in Secure RAM, in BL2's address space. + */ + while (bl_params != NULL) { + if (bl_params->image_id == BL33_IMAGE_ID) { + bl33_image_ep_info = *bl_params->ep_info; + /* + * Check if hw_configuration is given to BL32 and + * share it to BL33. + */ + if (arg2 != 0U) { + bl33_image_ep_info.args.arg0 = 0U; + bl33_image_ep_info.args.arg1 = 0U; + bl33_image_ep_info.args.arg2 = arg2; + } + + break; + } + + bl_params = bl_params->next_params_info; + } + + if (dt_open_and_check(dt_addr) < 0) { + panic(); + } + + if (bsec_probe() != 0) { + panic(); + } + + if (stm32mp1_clk_probe() < 0) { + panic(); + } + + (void)stm32mp_uart_console_setup(); + + stm32mp1_etzpc_early_setup(); +} + +/******************************************************************************* + * Initialize the MMU, security and the GIC. + ******************************************************************************/ +void sp_min_platform_setup(void) +{ + generic_delay_timer_init(); + + stm32mp1_gic_init(); + + if (stm32_iwdg_init() < 0) { + panic(); + } + + stm32mp_lock_periph_registering(); + + stm32mp1_init_scmi_server(); +} + +void sp_min_plat_arch_setup(void) +{ +} diff --git a/plat/st/stm32mp1/stm32mp1.S b/plat/st/stm32mp1/stm32mp1.S new file mode 100644 index 0000000..aee4f0e --- /dev/null +++ b/plat/st/stm32mp1/stm32mp1.S @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +.section .bl2_image +.incbin BL2_BIN_PATH + +.section .dtb_image +.incbin DTB_BIN_PATH diff --git a/plat/st/stm32mp1/stm32mp1.ld.S b/plat/st/stm32mp1/stm32mp1.ld.S new file mode 100644 index 0000000..1be8219 --- /dev/null +++ b/plat/st/stm32mp1/stm32mp1.ld.S @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef STM32MP1_LD_S +#define STM32MP1_LD_S + +#include <lib/xlat_tables/xlat_tables_defs.h> +#include <platform_def.h> + +OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT) +OUTPUT_ARCH(PLATFORM_LINKER_ARCH) + +ENTRY(__BL2_IMAGE_START__) + +MEMORY { + HEADER (rw) : ORIGIN = 0x00000000, LENGTH = STM32MP_HEADER_RESERVED_SIZE + RAM (rwx) : ORIGIN = STM32MP_BINARY_BASE, LENGTH = STM32MP_BINARY_SIZE +} + +SECTIONS +{ + /* + * TF mapping must conform to ROM code specification. + */ + .header : { + __HEADER_START__ = .; + KEEP(*(.header)) + . = ALIGN(4); + __HEADER_END__ = .; + } >HEADER + + . = STM32MP_BINARY_BASE; + .data . : { + . = ALIGN(PAGE_SIZE); + __DATA_START__ = .; + *(.data*) + + /* + * dtb. + * The strongest and only alignment contraint is MMU 4K page. + * Indeed as images below will be removed, 4K pages will be re-used. + */ + . = ( STM32MP_BL2_DTB_BASE - STM32MP_BINARY_BASE ); + __DTB_IMAGE_START__ = .; + *(.dtb_image*) + __DTB_IMAGE_END__ = .; + + /* + * bl2. + * The strongest and only alignment contraint is MMU 4K page. + * Indeed as images below will be removed, 4K pages will be re-used. + */ +#if SEPARATE_CODE_AND_RODATA + . = ( STM32MP_BL2_RO_BASE - STM32MP_BINARY_BASE ); +#else + . = ( STM32MP_BL2_BASE - STM32MP_BINARY_BASE ); +#endif + __BL2_IMAGE_START__ = .; + *(.bl2_image*) + __BL2_IMAGE_END__ = .; + + __DATA_END__ = .; + } >RAM + + __TF_END__ = .; + +} +#endif /* STM32MP1_LD_S */ diff --git a/plat/st/stm32mp1/stm32mp1_boot_device.c b/plat/st/stm32mp1/stm32mp1_boot_device.c new file mode 100644 index 0000000..3a8a27a --- /dev/null +++ b/plat/st/stm32mp1/stm32mp1_boot_device.c @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2019-2022, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <errno.h> + +#include <common/debug.h> +#include <drivers/nand.h> +#include <drivers/raw_nand.h> +#include <drivers/spi_nand.h> +#include <drivers/spi_nor.h> +#include <lib/utils.h> +#include <plat/common/platform.h> + +#if STM32MP_RAW_NAND || STM32MP_SPI_NAND +#if STM32MP13 +void plat_get_scratch_buffer(void **buffer_addr, size_t *buf_size) +{ + assert(buffer_addr != NULL); + assert(buf_size != NULL); + + *buffer_addr = (void *)STM32MP_MTD_BUFFER; + *buf_size = PLATFORM_MTD_MAX_PAGE_SIZE; +} +#endif + +static int get_data_from_otp(struct nand_device *nand_dev, bool is_slc) +{ + uint32_t nand_param; + uint32_t nand2_param __maybe_unused; + + /* Check if NAND parameters are stored in OTP */ + if (stm32_get_otp_value(NAND_OTP, &nand_param) != 0) { + ERROR("BSEC: NAND_OTP Error\n"); + return -EACCES; + } + + if (nand_param == 0U) { +#if STM32MP13 + if (is_slc) { + return 0; + } +#endif +#if STM32MP15 + return 0; +#endif + } + + if ((nand_param & NAND_PARAM_STORED_IN_OTP) == 0U) { +#if STM32MP13 + if (is_slc) { + goto ecc; + } +#endif +#if STM32MP15 + goto ecc; +#endif + } + +#if STM32MP13 + if (stm32_get_otp_value(NAND2_OTP, &nand2_param) != 0) { + ERROR("BSEC: NAND_OTP Error\n"); + return -EACCES; + } + + /* Check OTP configuration for this device */ + if ((((nand2_param & NAND2_CONFIG_DISTRIB) == NAND2_PNAND_NAND1_SNAND_NAND2) && !is_slc) || + (((nand2_param & NAND2_CONFIG_DISTRIB) == NAND2_PNAND_NAND2_SNAND_NAND1) && is_slc)) { + nand_param = nand2_param << (NAND_PAGE_SIZE_SHIFT - NAND2_PAGE_SIZE_SHIFT); + } +#endif + + /* NAND parameter shall be read from OTP */ + if ((nand_param & NAND_WIDTH_MASK) != 0U) { + nand_dev->buswidth = NAND_BUS_WIDTH_16; + } else { + nand_dev->buswidth = NAND_BUS_WIDTH_8; + } + + switch ((nand_param & NAND_PAGE_SIZE_MASK) >> NAND_PAGE_SIZE_SHIFT) { + case NAND_PAGE_SIZE_2K: + nand_dev->page_size = 0x800U; + break; + + case NAND_PAGE_SIZE_4K: + nand_dev->page_size = 0x1000U; + break; + + case NAND_PAGE_SIZE_8K: + nand_dev->page_size = 0x2000U; + break; + + default: + ERROR("Cannot read NAND page size\n"); + return -EINVAL; + } + + switch ((nand_param & NAND_BLOCK_SIZE_MASK) >> NAND_BLOCK_SIZE_SHIFT) { + case NAND_BLOCK_SIZE_64_PAGES: + nand_dev->block_size = 64U * nand_dev->page_size; + break; + + case NAND_BLOCK_SIZE_128_PAGES: + nand_dev->block_size = 128U * nand_dev->page_size; + break; + + case NAND_BLOCK_SIZE_256_PAGES: + nand_dev->block_size = 256U * nand_dev->page_size; + break; + + default: + ERROR("Cannot read NAND block size\n"); + return -EINVAL; + } + + nand_dev->size = ((nand_param & NAND_BLOCK_NB_MASK) >> + NAND_BLOCK_NB_SHIFT) * + NAND_BLOCK_NB_UNIT * nand_dev->block_size; + +ecc: + if (is_slc) { + switch ((nand_param & NAND_ECC_BIT_NB_MASK) >> + NAND_ECC_BIT_NB_SHIFT) { + case NAND_ECC_BIT_NB_1_BITS: + nand_dev->ecc.max_bit_corr = 1U; + break; + + case NAND_ECC_BIT_NB_4_BITS: + nand_dev->ecc.max_bit_corr = 4U; + break; + + case NAND_ECC_BIT_NB_8_BITS: + nand_dev->ecc.max_bit_corr = 8U; + break; + + case NAND_ECC_ON_DIE: + nand_dev->ecc.mode = NAND_ECC_ONDIE; + break; + + default: + if (nand_dev->ecc.max_bit_corr == 0U) { + ERROR("No valid eccbit number\n"); + return -EINVAL; + } + } + } else { + /* Selected multiple plane NAND */ + if ((nand_param & NAND_PLANE_BIT_NB_MASK) != 0U) { + nand_dev->nb_planes = 2U; + } else { + nand_dev->nb_planes = 1U; + } + } + + VERBOSE("OTP: Block %u Page %u Size %llu\n", nand_dev->block_size, + nand_dev->page_size, nand_dev->size); + + return 0; +} +#endif /* STM32MP_RAW_NAND || STM32MP_SPI_NAND */ + +#if STM32MP_RAW_NAND +int plat_get_raw_nand_data(struct rawnand_device *device) +{ + device->nand_dev->ecc.mode = NAND_ECC_HW; + device->nand_dev->ecc.size = SZ_512; + + return get_data_from_otp(device->nand_dev, true); +} +#endif + +#if STM32MP_SPI_NAND +int plat_get_spi_nand_data(struct spinand_device *device) +{ + zeromem(&device->spi_read_cache_op, sizeof(struct spi_mem_op)); + device->spi_read_cache_op.cmd.opcode = SPI_NAND_OP_READ_FROM_CACHE_4X; + device->spi_read_cache_op.cmd.buswidth = SPI_MEM_BUSWIDTH_1_LINE; + device->spi_read_cache_op.addr.nbytes = 2U; + device->spi_read_cache_op.addr.buswidth = SPI_MEM_BUSWIDTH_1_LINE; + device->spi_read_cache_op.dummy.nbytes = 1U; + device->spi_read_cache_op.dummy.buswidth = SPI_MEM_BUSWIDTH_1_LINE; + device->spi_read_cache_op.data.buswidth = SPI_MEM_BUSWIDTH_4_LINE; + device->spi_read_cache_op.data.dir = SPI_MEM_DATA_IN; + + return get_data_from_otp(device->nand_dev, false); +} +#endif + +#if STM32MP_SPI_NOR +int plat_get_nor_data(struct nor_device *device) +{ + device->size = SZ_64M; + + zeromem(&device->read_op, sizeof(struct spi_mem_op)); + device->read_op.cmd.opcode = SPI_NOR_OP_READ_1_1_4; + device->read_op.cmd.buswidth = SPI_MEM_BUSWIDTH_1_LINE; + device->read_op.addr.nbytes = 3U; + device->read_op.addr.buswidth = SPI_MEM_BUSWIDTH_1_LINE; + device->read_op.dummy.nbytes = 1U; + device->read_op.dummy.buswidth = SPI_MEM_BUSWIDTH_1_LINE; + device->read_op.data.buswidth = SPI_MEM_BUSWIDTH_4_LINE; + device->read_op.data.dir = SPI_MEM_DATA_IN; + + return 0; +} +#endif diff --git a/plat/st/stm32mp1/stm32mp1_dbgmcu.c b/plat/st/stm32mp1/stm32mp1_dbgmcu.c new file mode 100644 index 0000000..08e332a --- /dev/null +++ b/plat/st/stm32mp1/stm32mp1_dbgmcu.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2016-2022, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <errno.h> + +#include <common/debug.h> +#include <drivers/st/bsec.h> +#include <drivers/st/bsec2_reg.h> +#include <drivers/st/stm32mp1_rcc.h> +#include <lib/mmio.h> +#include <lib/utils_def.h> + +#include <platform_def.h> +#include <stm32mp1_dbgmcu.h> + +#define DBGMCU_IDC U(0x00) + +#define DBGMCU_IDC_DEV_ID_MASK GENMASK(11, 0) +#define DBGMCU_IDC_REV_ID_MASK GENMASK(31, 16) +#define DBGMCU_IDC_REV_ID_SHIFT 16 + +static int stm32mp1_dbgmcu_init(void) +{ + if ((bsec_read_debug_conf() & BSEC_DBGSWGEN) == 0U) { + INFO("Software access to all debug components is disabled\n"); + return -1; + } + + mmio_setbits_32(RCC_BASE + RCC_DBGCFGR, RCC_DBGCFGR_DBGCKEN); + + return 0; +} + +/* + * @brief Get silicon revision from DBGMCU registers. + * @param chip_version: pointer to the read value. + * @retval 0 on success, negative value on failure. + */ +int stm32mp1_dbgmcu_get_chip_version(uint32_t *chip_version) +{ + assert(chip_version != NULL); + + if (stm32mp1_dbgmcu_init() != 0) { + return -EPERM; + } + + *chip_version = (mmio_read_32(DBGMCU_BASE + DBGMCU_IDC) & + DBGMCU_IDC_REV_ID_MASK) >> DBGMCU_IDC_REV_ID_SHIFT; + + return 0; +} + +/* + * @brief Get device ID from DBGMCU registers. + * @param chip_dev_id: pointer to the read value. + * @retval 0 on success, negative value on failure. + */ +int stm32mp1_dbgmcu_get_chip_dev_id(uint32_t *chip_dev_id) +{ + assert(chip_dev_id != NULL); + + if (stm32mp1_dbgmcu_init() != 0) { + return -EPERM; + } + + *chip_dev_id = mmio_read_32(DBGMCU_BASE + DBGMCU_IDC) & + DBGMCU_IDC_DEV_ID_MASK; + + return 0; +} diff --git a/plat/st/stm32mp1/stm32mp1_def.h b/plat/st/stm32mp1/stm32mp1_def.h new file mode 100644 index 0000000..f0d8526 --- /dev/null +++ b/plat/st/stm32mp1/stm32mp1_def.h @@ -0,0 +1,669 @@ +/* + * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef STM32MP1_DEF_H +#define STM32MP1_DEF_H + +#include <common/tbbr/tbbr_img_def.h> +#include <drivers/st/stm32mp1_rcc.h> +#include <dt-bindings/clock/stm32mp1-clks.h> +#include <dt-bindings/reset/stm32mp1-resets.h> +#include <lib/utils_def.h> +#include <lib/xlat_tables/xlat_tables_defs.h> + +#ifndef __ASSEMBLER__ +#include <drivers/st/bsec.h> +#include <drivers/st/stm32mp1_clk.h> + +#include <boot_api.h> +#include <stm32mp_common.h> +#include <stm32mp_dt.h> +#include <stm32mp1_dbgmcu.h> +#include <stm32mp1_private.h> +#include <stm32mp1_shared_resources.h> +#endif + +#include "stm32mp1_fip_def.h" + +/******************************************************************************* + * CHIP ID + ******************************************************************************/ +#if STM32MP13 +#define STM32MP1_CHIP_ID U(0x501) + +#define STM32MP135C_PART_NB U(0x05010000) +#define STM32MP135A_PART_NB U(0x05010001) +#define STM32MP133C_PART_NB U(0x050100C0) +#define STM32MP133A_PART_NB U(0x050100C1) +#define STM32MP131C_PART_NB U(0x050106C8) +#define STM32MP131A_PART_NB U(0x050106C9) +#define STM32MP135F_PART_NB U(0x05010800) +#define STM32MP135D_PART_NB U(0x05010801) +#define STM32MP133F_PART_NB U(0x050108C0) +#define STM32MP133D_PART_NB U(0x050108C1) +#define STM32MP131F_PART_NB U(0x05010EC8) +#define STM32MP131D_PART_NB U(0x05010EC9) +#endif +#if STM32MP15 +#define STM32MP1_CHIP_ID U(0x500) + +#define STM32MP157C_PART_NB U(0x05000000) +#define STM32MP157A_PART_NB U(0x05000001) +#define STM32MP153C_PART_NB U(0x05000024) +#define STM32MP153A_PART_NB U(0x05000025) +#define STM32MP151C_PART_NB U(0x0500002E) +#define STM32MP151A_PART_NB U(0x0500002F) +#define STM32MP157F_PART_NB U(0x05000080) +#define STM32MP157D_PART_NB U(0x05000081) +#define STM32MP153F_PART_NB U(0x050000A4) +#define STM32MP153D_PART_NB U(0x050000A5) +#define STM32MP151F_PART_NB U(0x050000AE) +#define STM32MP151D_PART_NB U(0x050000AF) +#endif + +#define STM32MP1_REV_B U(0x2000) +#if STM32MP13 +#define STM32MP1_REV_Y U(0x1003) +#define STM32MP1_REV_Z U(0x1001) +#endif +#if STM32MP15 +#define STM32MP1_REV_Z U(0x2001) +#endif + +/******************************************************************************* + * PACKAGE ID + ******************************************************************************/ +#if STM32MP15 +#define PKG_AA_LFBGA448 U(4) +#define PKG_AB_LFBGA354 U(3) +#define PKG_AC_TFBGA361 U(2) +#define PKG_AD_TFBGA257 U(1) +#endif + +/******************************************************************************* + * STM32MP1 memory map related constants + ******************************************************************************/ +#define STM32MP_ROM_BASE U(0x00000000) +#define STM32MP_ROM_SIZE U(0x00020000) +#define STM32MP_ROM_SIZE_2MB_ALIGNED U(0x00200000) + +#if STM32MP13 +#define STM32MP_SYSRAM_BASE U(0x2FFE0000) +#define STM32MP_SYSRAM_SIZE U(0x00020000) +#define SRAM1_BASE U(0x30000000) +#define SRAM1_SIZE U(0x00004000) +#define SRAM2_BASE U(0x30004000) +#define SRAM2_SIZE U(0x00002000) +#define SRAM3_BASE U(0x30006000) +#define SRAM3_SIZE U(0x00002000) +#define SRAMS_BASE SRAM1_BASE +#define SRAMS_SIZE_2MB_ALIGNED U(0x00200000) +#endif /* STM32MP13 */ +#if STM32MP15 +#define STM32MP_SYSRAM_BASE U(0x2FFC0000) +#define STM32MP_SYSRAM_SIZE U(0x00040000) +#endif /* STM32MP15 */ + +#define STM32MP_NS_SYSRAM_SIZE PAGE_SIZE +#define STM32MP_NS_SYSRAM_BASE (STM32MP_SYSRAM_BASE + \ + STM32MP_SYSRAM_SIZE - \ + STM32MP_NS_SYSRAM_SIZE) + +#define STM32MP_SCMI_NS_SHM_BASE STM32MP_NS_SYSRAM_BASE +#define STM32MP_SCMI_NS_SHM_SIZE STM32MP_NS_SYSRAM_SIZE + +#define STM32MP_SEC_SYSRAM_BASE STM32MP_SYSRAM_BASE +#define STM32MP_SEC_SYSRAM_SIZE (STM32MP_SYSRAM_SIZE - \ + STM32MP_NS_SYSRAM_SIZE) + +/* DDR configuration */ +#define STM32MP_DDR_BASE U(0xC0000000) +#define STM32MP_DDR_MAX_SIZE U(0x40000000) /* Max 1GB */ + +/* DDR power initializations */ +#ifndef __ASSEMBLER__ +enum ddr_type { + STM32MP_DDR3, + STM32MP_LPDDR2, + STM32MP_LPDDR3 +}; +#endif + +/* Section used inside TF binaries */ +#if STM32MP13 +/* 512 Octets reserved for header */ +#define STM32MP_HEADER_RESERVED_SIZE U(0x200) + +#define STM32MP_BINARY_BASE STM32MP_SEC_SYSRAM_BASE + +#define STM32MP_BINARY_SIZE STM32MP_SEC_SYSRAM_SIZE +#endif +#if STM32MP15 +#define STM32MP_PARAM_LOAD_SIZE U(0x00002400) /* 9 KB for param */ +/* 256 Octets reserved for header */ +#define STM32MP_HEADER_SIZE U(0x00000100) +/* round_up(STM32MP_PARAM_LOAD_SIZE + STM32MP_HEADER_SIZE, PAGE_SIZE) */ +#define STM32MP_HEADER_RESERVED_SIZE U(0x3000) + +#define STM32MP_BINARY_BASE (STM32MP_SEC_SYSRAM_BASE + \ + STM32MP_PARAM_LOAD_SIZE + \ + STM32MP_HEADER_SIZE) + +#define STM32MP_BINARY_SIZE (STM32MP_SEC_SYSRAM_SIZE - \ + (STM32MP_PARAM_LOAD_SIZE + \ + STM32MP_HEADER_SIZE)) +#endif + +/* BL2 and BL32/sp_min require finer granularity tables */ +#if defined(IMAGE_BL2) +#define MAX_XLAT_TABLES U(2) /* 8 KB for mapping */ +#endif + +#if defined(IMAGE_BL32) +#define MAX_XLAT_TABLES U(4) /* 16 KB for mapping */ +#endif + +/* + * MAX_MMAP_REGIONS is usually: + * BL stm32mp1_mmap size + mmap regions in *_plat_arch_setup + */ +#if defined(IMAGE_BL2) + #if STM32MP_USB_PROGRAMMER + #define MAX_MMAP_REGIONS 8 + #else + #define MAX_MMAP_REGIONS 7 + #endif +#endif + +#if STM32MP13 +#define STM32MP_BL33_BASE STM32MP_DDR_BASE +#endif +#if STM32MP15 +#define STM32MP_BL33_BASE (STM32MP_DDR_BASE + U(0x100000)) +#endif +#define STM32MP_BL33_MAX_SIZE U(0x400000) + +/* Define maximum page size for NAND devices */ +#define PLATFORM_MTD_MAX_PAGE_SIZE U(0x1000) + +/* Define location for the MTD scratch buffer */ +#if STM32MP13 +#define STM32MP_MTD_BUFFER (SRAM1_BASE + \ + SRAM1_SIZE - \ + PLATFORM_MTD_MAX_PAGE_SIZE) +#endif +/******************************************************************************* + * STM32MP1 device/io map related constants (used for MMU) + ******************************************************************************/ +#define STM32MP1_DEVICE1_BASE U(0x40000000) +#define STM32MP1_DEVICE1_SIZE U(0x40000000) + +#define STM32MP1_DEVICE2_BASE U(0x80000000) +#define STM32MP1_DEVICE2_SIZE U(0x40000000) + +/******************************************************************************* + * STM32MP1 RCC + ******************************************************************************/ +#define RCC_BASE U(0x50000000) + +/******************************************************************************* + * STM32MP1 PWR + ******************************************************************************/ +#define PWR_BASE U(0x50001000) + +/******************************************************************************* + * STM32MP1 GPIO + ******************************************************************************/ +#define GPIOA_BASE U(0x50002000) +#define GPIOB_BASE U(0x50003000) +#define GPIOC_BASE U(0x50004000) +#define GPIOD_BASE U(0x50005000) +#define GPIOE_BASE U(0x50006000) +#define GPIOF_BASE U(0x50007000) +#define GPIOG_BASE U(0x50008000) +#define GPIOH_BASE U(0x50009000) +#define GPIOI_BASE U(0x5000A000) +#if STM32MP15 +#define GPIOJ_BASE U(0x5000B000) +#define GPIOK_BASE U(0x5000C000) +#define GPIOZ_BASE U(0x54004000) +#endif +#define GPIO_BANK_OFFSET U(0x1000) + +/* Bank IDs used in GPIO driver API */ +#define GPIO_BANK_A U(0) +#define GPIO_BANK_B U(1) +#define GPIO_BANK_C U(2) +#define GPIO_BANK_D U(3) +#define GPIO_BANK_E U(4) +#define GPIO_BANK_F U(5) +#define GPIO_BANK_G U(6) +#define GPIO_BANK_H U(7) +#define GPIO_BANK_I U(8) +#if STM32MP15 +#define GPIO_BANK_J U(9) +#define GPIO_BANK_K U(10) +#define GPIO_BANK_Z U(25) + +#define STM32MP_GPIOZ_PIN_MAX_COUNT 8 +#endif + +/******************************************************************************* + * STM32MP1 UART + ******************************************************************************/ +#if STM32MP13 +#define USART1_BASE U(0x4C000000) +#define USART2_BASE U(0x4C001000) +#endif +#if STM32MP15 +#define USART1_BASE U(0x5C000000) +#define USART2_BASE U(0x4000E000) +#endif +#define USART3_BASE U(0x4000F000) +#define UART4_BASE U(0x40010000) +#define UART5_BASE U(0x40011000) +#define USART6_BASE U(0x44003000) +#define UART7_BASE U(0x40018000) +#define UART8_BASE U(0x40019000) + +/* For UART crash console */ +#define STM32MP_DEBUG_USART_BASE UART4_BASE +#if STM32MP13 +/* UART4 on HSI@64MHz, TX on GPIOF12 Alternate 8 (Disco board) */ +#define STM32MP_DEBUG_USART_CLK_FRQ 64000000 +#define DEBUG_UART_TX_GPIO_BANK_ADDRESS GPIOD_BASE +#define DEBUG_UART_TX_GPIO_BANK_CLK_REG RCC_MP_S_AHB4ENSETR +#define DEBUG_UART_TX_GPIO_BANK_CLK_EN RCC_MP_S_AHB4ENSETR_GPIODEN +#define DEBUG_UART_TX_GPIO_PORT 6 +#define DEBUG_UART_TX_GPIO_ALTERNATE 8 +#define DEBUG_UART_TX_CLKSRC_REG RCC_UART4CKSELR +#define DEBUG_UART_TX_CLKSRC RCC_UART4CKSELR_HSI +#endif /* STM32MP13 */ +#if STM32MP15 +/* UART4 on HSI@64MHz, TX on GPIOG11 Alternate 6 */ +#define STM32MP_DEBUG_USART_CLK_FRQ 64000000 +#define DEBUG_UART_TX_GPIO_BANK_ADDRESS GPIOG_BASE +#define DEBUG_UART_TX_GPIO_BANK_CLK_REG RCC_MP_AHB4ENSETR +#define DEBUG_UART_TX_GPIO_BANK_CLK_EN RCC_MP_AHB4ENSETR_GPIOGEN +#define DEBUG_UART_TX_GPIO_PORT 11 +#define DEBUG_UART_TX_GPIO_ALTERNATE 6 +#define DEBUG_UART_TX_CLKSRC_REG RCC_UART24CKSELR +#define DEBUG_UART_TX_CLKSRC RCC_UART24CKSELR_HSI +#endif /* STM32MP15 */ +#define DEBUG_UART_TX_EN_REG RCC_MP_APB1ENSETR +#define DEBUG_UART_TX_EN RCC_MP_APB1ENSETR_UART4EN +#define DEBUG_UART_RST_REG RCC_APB1RSTSETR +#define DEBUG_UART_RST_BIT RCC_APB1RSTSETR_UART4RST + +/******************************************************************************* + * STM32MP1 ETZPC + ******************************************************************************/ +#define STM32MP1_ETZPC_BASE U(0x5C007000) + +/* ETZPC TZMA IDs */ +#define STM32MP1_ETZPC_TZMA_ROM U(0) +#define STM32MP1_ETZPC_TZMA_SYSRAM U(1) + +#define STM32MP1_ETZPC_TZMA_ALL_SECURE GENMASK_32(9, 0) + +/* ETZPC DECPROT IDs */ +#define STM32MP1_ETZPC_STGENC_ID 0 +#define STM32MP1_ETZPC_BKPSRAM_ID 1 +#define STM32MP1_ETZPC_IWDG1_ID 2 +#define STM32MP1_ETZPC_USART1_ID 3 +#define STM32MP1_ETZPC_SPI6_ID 4 +#define STM32MP1_ETZPC_I2C4_ID 5 +#define STM32MP1_ETZPC_RNG1_ID 7 +#define STM32MP1_ETZPC_HASH1_ID 8 +#define STM32MP1_ETZPC_CRYP1_ID 9 +#define STM32MP1_ETZPC_DDRCTRL_ID 10 +#define STM32MP1_ETZPC_DDRPHYC_ID 11 +#define STM32MP1_ETZPC_I2C6_ID 12 +#define STM32MP1_ETZPC_SEC_ID_LIMIT 13 + +#define STM32MP1_ETZPC_TIM2_ID 16 +#define STM32MP1_ETZPC_TIM3_ID 17 +#define STM32MP1_ETZPC_TIM4_ID 18 +#define STM32MP1_ETZPC_TIM5_ID 19 +#define STM32MP1_ETZPC_TIM6_ID 20 +#define STM32MP1_ETZPC_TIM7_ID 21 +#define STM32MP1_ETZPC_TIM12_ID 22 +#define STM32MP1_ETZPC_TIM13_ID 23 +#define STM32MP1_ETZPC_TIM14_ID 24 +#define STM32MP1_ETZPC_LPTIM1_ID 25 +#define STM32MP1_ETZPC_WWDG1_ID 26 +#define STM32MP1_ETZPC_SPI2_ID 27 +#define STM32MP1_ETZPC_SPI3_ID 28 +#define STM32MP1_ETZPC_SPDIFRX_ID 29 +#define STM32MP1_ETZPC_USART2_ID 30 +#define STM32MP1_ETZPC_USART3_ID 31 +#define STM32MP1_ETZPC_UART4_ID 32 +#define STM32MP1_ETZPC_UART5_ID 33 +#define STM32MP1_ETZPC_I2C1_ID 34 +#define STM32MP1_ETZPC_I2C2_ID 35 +#define STM32MP1_ETZPC_I2C3_ID 36 +#define STM32MP1_ETZPC_I2C5_ID 37 +#define STM32MP1_ETZPC_CEC_ID 38 +#define STM32MP1_ETZPC_DAC_ID 39 +#define STM32MP1_ETZPC_UART7_ID 40 +#define STM32MP1_ETZPC_UART8_ID 41 +#define STM32MP1_ETZPC_MDIOS_ID 44 +#define STM32MP1_ETZPC_TIM1_ID 48 +#define STM32MP1_ETZPC_TIM8_ID 49 +#define STM32MP1_ETZPC_USART6_ID 51 +#define STM32MP1_ETZPC_SPI1_ID 52 +#define STM32MP1_ETZPC_SPI4_ID 53 +#define STM32MP1_ETZPC_TIM15_ID 54 +#define STM32MP1_ETZPC_TIM16_ID 55 +#define STM32MP1_ETZPC_TIM17_ID 56 +#define STM32MP1_ETZPC_SPI5_ID 57 +#define STM32MP1_ETZPC_SAI1_ID 58 +#define STM32MP1_ETZPC_SAI2_ID 59 +#define STM32MP1_ETZPC_SAI3_ID 60 +#define STM32MP1_ETZPC_DFSDM_ID 61 +#define STM32MP1_ETZPC_TT_FDCAN_ID 62 +#define STM32MP1_ETZPC_LPTIM2_ID 64 +#define STM32MP1_ETZPC_LPTIM3_ID 65 +#define STM32MP1_ETZPC_LPTIM4_ID 66 +#define STM32MP1_ETZPC_LPTIM5_ID 67 +#define STM32MP1_ETZPC_SAI4_ID 68 +#define STM32MP1_ETZPC_VREFBUF_ID 69 +#define STM32MP1_ETZPC_DCMI_ID 70 +#define STM32MP1_ETZPC_CRC2_ID 71 +#define STM32MP1_ETZPC_ADC_ID 72 +#define STM32MP1_ETZPC_HASH2_ID 73 +#define STM32MP1_ETZPC_RNG2_ID 74 +#define STM32MP1_ETZPC_CRYP2_ID 75 +#define STM32MP1_ETZPC_SRAM1_ID 80 +#define STM32MP1_ETZPC_SRAM2_ID 81 +#define STM32MP1_ETZPC_SRAM3_ID 82 +#define STM32MP1_ETZPC_SRAM4_ID 83 +#define STM32MP1_ETZPC_RETRAM_ID 84 +#define STM32MP1_ETZPC_OTG_ID 85 +#define STM32MP1_ETZPC_SDMMC3_ID 86 +#define STM32MP1_ETZPC_DLYBSD3_ID 87 +#define STM32MP1_ETZPC_DMA1_ID 88 +#define STM32MP1_ETZPC_DMA2_ID 89 +#define STM32MP1_ETZPC_DMAMUX_ID 90 +#define STM32MP1_ETZPC_FMC_ID 91 +#define STM32MP1_ETZPC_QSPI_ID 92 +#define STM32MP1_ETZPC_DLYBQ_ID 93 +#define STM32MP1_ETZPC_ETH_ID 94 +#define STM32MP1_ETZPC_RSV_ID 95 + +#define STM32MP_ETZPC_MAX_ID 96 + +/******************************************************************************* + * STM32MP1 TZC (TZ400) + ******************************************************************************/ +#define STM32MP1_TZC_BASE U(0x5C006000) + +#if STM32MP13 +#define STM32MP1_FILTER_BIT_ALL TZC_400_REGION_ATTR_FILTER_BIT(0) +#endif +#if STM32MP15 +#define STM32MP1_FILTER_BIT_ALL (TZC_400_REGION_ATTR_FILTER_BIT(0) | \ + TZC_400_REGION_ATTR_FILTER_BIT(1)) +#endif + +/******************************************************************************* + * STM32MP1 SDMMC + ******************************************************************************/ +#define STM32MP_SDMMC1_BASE U(0x58005000) +#define STM32MP_SDMMC2_BASE U(0x58007000) +#define STM32MP_SDMMC3_BASE U(0x48004000) + +#define STM32MP_MMC_INIT_FREQ U(400000) /*400 KHz*/ +#define STM32MP_SD_NORMAL_SPEED_MAX_FREQ U(25000000) /*25 MHz*/ +#define STM32MP_SD_HIGH_SPEED_MAX_FREQ U(50000000) /*50 MHz*/ +#define STM32MP_EMMC_NORMAL_SPEED_MAX_FREQ U(26000000) /*26 MHz*/ +#define STM32MP_EMMC_HIGH_SPEED_MAX_FREQ U(52000000) /*52 MHz*/ + +/******************************************************************************* + * STM32MP1 BSEC / OTP + ******************************************************************************/ +#define STM32MP1_OTP_MAX_ID 0x5FU +#define STM32MP1_UPPER_OTP_START 0x20U + +#define OTP_MAX_SIZE (STM32MP1_OTP_MAX_ID + 1U) + +/* OTP labels */ +#define CFG0_OTP "cfg0_otp" +#define PART_NUMBER_OTP "part_number_otp" +#if STM32MP15 +#define PACKAGE_OTP "package_otp" +#endif +#define HW2_OTP "hw2_otp" +#if STM32MP13 +#define NAND_OTP "cfg9_otp" +#define NAND2_OTP "cfg10_otp" +#endif +#if STM32MP15 +#define NAND_OTP "nand_otp" +#endif +#define MONOTONIC_OTP "monotonic_otp" +#define UID_OTP "uid_otp" +#define PKH_OTP "pkh_otp" +#define ENCKEY_OTP "enckey_otp" +#define BOARD_ID_OTP "board_id" + +/* OTP mask */ +/* CFG0 */ +#if STM32MP13 +#define CFG0_OTP_MODE_MASK GENMASK_32(9, 0) +#define CFG0_OTP_MODE_SHIFT 0 +#define CFG0_OPEN_DEVICE 0x17U +#define CFG0_CLOSED_DEVICE 0x3FU +#define CFG0_CLOSED_DEVICE_NO_BOUNDARY_SCAN 0x17FU +#define CFG0_CLOSED_DEVICE_NO_JTAG 0x3FFU +#endif +#if STM32MP15 +#define CFG0_CLOSED_DEVICE BIT(6) +#endif + +/* PART NUMBER */ +#if STM32MP13 +#define PART_NUMBER_OTP_PART_MASK GENMASK_32(11, 0) +#endif +#if STM32MP15 +#define PART_NUMBER_OTP_PART_MASK GENMASK_32(7, 0) +#endif +#define PART_NUMBER_OTP_PART_SHIFT 0 + +/* PACKAGE */ +#if STM32MP15 +#define PACKAGE_OTP_PKG_MASK GENMASK_32(29, 27) +#define PACKAGE_OTP_PKG_SHIFT 27 +#endif + +/* IWDG OTP */ +#define HW2_OTP_IWDG_HW_POS U(3) +#define HW2_OTP_IWDG_FZ_STOP_POS U(5) +#define HW2_OTP_IWDG_FZ_STANDBY_POS U(7) + +/* HW2 OTP */ +#define HW2_OTP_PRODUCT_BELOW_2V5 BIT(13) + +/* NAND OTP */ +/* NAND parameter storage flag */ +#define NAND_PARAM_STORED_IN_OTP BIT(31) + +/* NAND page size in bytes */ +#define NAND_PAGE_SIZE_MASK GENMASK_32(30, 29) +#define NAND_PAGE_SIZE_SHIFT 29 +#define NAND_PAGE_SIZE_2K U(0) +#define NAND_PAGE_SIZE_4K U(1) +#define NAND_PAGE_SIZE_8K U(2) + +/* NAND block size in pages */ +#define NAND_BLOCK_SIZE_MASK GENMASK_32(28, 27) +#define NAND_BLOCK_SIZE_SHIFT 27 +#define NAND_BLOCK_SIZE_64_PAGES U(0) +#define NAND_BLOCK_SIZE_128_PAGES U(1) +#define NAND_BLOCK_SIZE_256_PAGES U(2) + +/* NAND number of block (in unit of 256 blocks) */ +#define NAND_BLOCK_NB_MASK GENMASK_32(26, 19) +#define NAND_BLOCK_NB_SHIFT 19 +#define NAND_BLOCK_NB_UNIT U(256) + +/* NAND bus width in bits */ +#define NAND_WIDTH_MASK BIT(18) +#define NAND_WIDTH_SHIFT 18 + +/* NAND number of ECC bits per 512 bytes */ +#define NAND_ECC_BIT_NB_MASK GENMASK_32(17, 15) +#define NAND_ECC_BIT_NB_SHIFT 15 +#define NAND_ECC_BIT_NB_UNSET U(0) +#define NAND_ECC_BIT_NB_1_BITS U(1) +#define NAND_ECC_BIT_NB_4_BITS U(2) +#define NAND_ECC_BIT_NB_8_BITS U(3) +#define NAND_ECC_ON_DIE U(4) + +/* NAND number of planes */ +#define NAND_PLANE_BIT_NB_MASK BIT(14) + +/* NAND2 OTP */ +#define NAND2_PAGE_SIZE_SHIFT 16 + +/* NAND2 config distribution */ +#define NAND2_CONFIG_DISTRIB BIT(0) +#define NAND2_PNAND_NAND2_SNAND_NAND1 U(0) +#define NAND2_PNAND_NAND1_SNAND_NAND2 U(1) + +/* MONOTONIC OTP */ +#define MAX_MONOTONIC_VALUE 32 + +/* UID OTP */ +#define UID_WORD_NB U(3) + +/* FWU configuration (max supported value is 15) */ +#define FWU_MAX_TRIAL_REBOOT U(3) + +/******************************************************************************* + * STM32MP1 TAMP + ******************************************************************************/ +#define TAMP_BASE U(0x5C00A000) +#define TAMP_BKP_REGISTER_BASE (TAMP_BASE + U(0x100)) +#define TAMP_COUNTR U(0x40) + +#if !(defined(__LINKER__) || defined(__ASSEMBLER__)) +static inline uintptr_t tamp_bkpr(uint32_t idx) +{ + return TAMP_BKP_REGISTER_BASE + (idx << 2); +} +#endif + +/******************************************************************************* + * STM32MP1 USB + ******************************************************************************/ +#define USB_OTG_BASE U(0x49000000) + +/******************************************************************************* + * STM32MP1 DDRCTRL + ******************************************************************************/ +#define DDRCTRL_BASE U(0x5A003000) + +/******************************************************************************* + * STM32MP1 DDRPHYC + ******************************************************************************/ +#define DDRPHYC_BASE U(0x5A004000) + +/******************************************************************************* + * STM32MP1 IWDG + ******************************************************************************/ +#define IWDG_MAX_INSTANCE U(2) +#define IWDG1_INST U(0) +#define IWDG2_INST U(1) + +#define IWDG1_BASE U(0x5C003000) +#define IWDG2_BASE U(0x5A002000) + +/******************************************************************************* + * Miscellaneous STM32MP1 peripherals base address + ******************************************************************************/ +#define BSEC_BASE U(0x5C005000) +#if STM32MP13 +#define CRYP_BASE U(0x54002000) +#endif +#if STM32MP15 +#define CRYP1_BASE U(0x54001000) +#endif +#define DBGMCU_BASE U(0x50081000) +#if STM32MP13 +#define HASH_BASE U(0x54003000) +#endif +#if STM32MP15 +#define HASH1_BASE U(0x54002000) +#endif +#if STM32MP13 +#define I2C3_BASE U(0x4C004000) +#define I2C4_BASE U(0x4C005000) +#define I2C5_BASE U(0x4C006000) +#endif +#if STM32MP15 +#define I2C4_BASE U(0x5C002000) +#define I2C6_BASE U(0x5c009000) +#endif +#if STM32MP13 +#define RNG_BASE U(0x54004000) +#endif +#if STM32MP15 +#define RNG1_BASE U(0x54003000) +#endif +#define RTC_BASE U(0x5c004000) +#if STM32MP13 +#define SPI4_BASE U(0x4C002000) +#define SPI5_BASE U(0x4C003000) +#endif +#if STM32MP15 +#define SPI6_BASE U(0x5c001000) +#endif +#define STGEN_BASE U(0x5c008000) +#define SYSCFG_BASE U(0x50020000) + +/******************************************************************************* + * STM32MP13 SAES + ******************************************************************************/ +#define SAES_BASE U(0x54005000) + +/******************************************************************************* + * STM32MP13 PKA + ******************************************************************************/ +#define PKA_BASE U(0x54006000) + +/******************************************************************************* + * REGULATORS + ******************************************************************************/ +/* 3 PWR + 1 VREFBUF + 14 PMIC regulators + 1 FIXED */ +#define PLAT_NB_RDEVS U(19) +/* 2 FIXED */ +#define PLAT_NB_FIXED_REGS U(2) + +/******************************************************************************* + * Device Tree defines + ******************************************************************************/ +#define DT_BSEC_COMPAT "st,stm32mp15-bsec" +#if STM32MP13 +#define DT_DDR_COMPAT "st,stm32mp13-ddr" +#endif +#if STM32MP15 +#define DT_DDR_COMPAT "st,stm32mp1-ddr" +#endif +#define DT_IWDG_COMPAT "st,stm32mp1-iwdg" +#define DT_PWR_COMPAT "st,stm32mp1,pwr-reg" +#if STM32MP13 +#define DT_RCC_CLK_COMPAT "st,stm32mp13-rcc" +#define DT_RCC_SEC_CLK_COMPAT "st,stm32mp13-rcc-secure" +#endif +#if STM32MP15 +#define DT_RCC_CLK_COMPAT "st,stm32mp1-rcc" +#define DT_RCC_SEC_CLK_COMPAT "st,stm32mp1-rcc-secure" +#endif +#define DT_SDMMC2_COMPAT "st,stm32-sdmmc2" +#define DT_UART_COMPAT "st,stm32h7-uart" + +#endif /* STM32MP1_DEF_H */ diff --git a/plat/st/stm32mp1/stm32mp1_fconf_firewall.c b/plat/st/stm32mp1/stm32mp1_fconf_firewall.c new file mode 100644 index 0000000..f2568ab --- /dev/null +++ b/plat/st/stm32mp1/stm32mp1_fconf_firewall.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2021-2022, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> + +#include <common/debug.h> +#include <common/fdt_wrappers.h> +#include <drivers/arm/tzc400.h> +#include <drivers/clk.h> +#include <dt-bindings/clock/stm32mp1-clks.h> +#include <lib/fconf/fconf.h> +#include <lib/object_pool.h> +#include <libfdt.h> +#include <tools_share/firmware_image_package.h> + +#include <platform_def.h> +#include <stm32mp_fconf_getter.h> + +#define STM32MP_REGION_PARAMS 4 +#define STM32MP_MAX_REGIONS 8 +#define FORCE_SEC_REGION BIT(31) + +static uint32_t nb_regions; + +struct dt_id_attr { + fdt32_t id_attr[STM32MP_MAX_REGIONS]; +}; + +void stm32mp1_arch_security_setup(void) +{ +#if STM32MP13 + clk_enable(TZC); +#endif +#if STM32MP15 + clk_enable(TZC1); + clk_enable(TZC2); +#endif + + tzc400_init(STM32MP1_TZC_BASE); + tzc400_disable_filters(); + + /* + * Region 0 set to cover all DRAM at 0xC000_0000 + * Only secure access is granted in read/write. + */ + tzc400_configure_region0(TZC_REGION_S_RDWR, 0); + + tzc400_set_action(TZC_ACTION_ERR); + tzc400_enable_filters(); +} + +void stm32mp1_security_setup(void) +{ + uint8_t i; + + assert(nb_regions > 0U); + + tzc400_init(STM32MP1_TZC_BASE); + tzc400_disable_filters(); + + /* + * Region 0 set to cover all DRAM at 0xC000_0000 + * No access is allowed. + */ + tzc400_configure_region0(TZC_REGION_S_NONE, 0); + + for (i = 1U; i <= nb_regions; i++) { + tzc400_update_filters(i, STM32MP1_FILTER_BIT_ALL); + } + + tzc400_set_action(TZC_ACTION_INT); + tzc400_enable_filters(); +} + +static int fconf_populate_stm32mp1_firewall(uintptr_t config) +{ + int node, len; + unsigned int i; + const struct dt_id_attr *conf_list; + const void *dtb = (const void *)config; + + /* Assert the node offset point to "st,mem-firewall" compatible property */ + const char *compatible_str = "st,mem-firewall"; + + node = fdt_node_offset_by_compatible(dtb, -1, compatible_str); + if (node < 0) { + ERROR("FCONF: Can't find %s compatible in dtb\n", compatible_str); + return node; + } + + conf_list = (const struct dt_id_attr *)fdt_getprop(dtb, node, "memory-ranges", &len); + if (conf_list == NULL) { + WARN("FCONF: Read cell failed for %s\n", "memory-ranges"); + return -1; + } + + /* Locate the memory cells and read all values */ + for (i = 0U; i < (unsigned int)(len / (sizeof(uint32_t) * STM32MP_REGION_PARAMS)); i++) { + uint32_t base; + uint32_t size; + uint32_t sec_attr; + uint32_t nsaid; + + base = fdt32_to_cpu(conf_list->id_attr[i * STM32MP_REGION_PARAMS]); + size = fdt32_to_cpu(conf_list->id_attr[i * STM32MP_REGION_PARAMS + 1]); + sec_attr = fdt32_to_cpu(conf_list->id_attr[i * STM32MP_REGION_PARAMS + 2]); + nsaid = fdt32_to_cpu(conf_list->id_attr[i * STM32MP_REGION_PARAMS + 3]); + + VERBOSE("FCONF: stm32mp1-firewall cell found with value = 0x%x 0x%x 0x%x 0x%x\n", + base, size, sec_attr, nsaid); + + nb_regions++; + + /* Configure region but keep disabled for secure access for BL2 load */ + tzc400_configure_region(0U, nb_regions, (unsigned long long)base, + (unsigned long long)base + size - 1ULL, sec_attr, nsaid); + } + + /* Force flush as the value will be used cache off */ + flush_dcache_range((uintptr_t)&nb_regions, sizeof(uint32_t)); + + return 0; +} + +FCONF_REGISTER_POPULATOR(FW_CONFIG, stm32mp1_firewall, fconf_populate_stm32mp1_firewall); diff --git a/plat/st/stm32mp1/stm32mp1_fip_def.h b/plat/st/stm32mp1/stm32mp1_fip_def.h new file mode 100644 index 0000000..4098386 --- /dev/null +++ b/plat/st/stm32mp1/stm32mp1_fip_def.h @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2021-2022, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef STM32MP1_FIP_DEF_H +#define STM32MP1_FIP_DEF_H + +#if STM32MP15_OPTEE_RSV_SHM +#define STM32MP_DDR_S_SIZE U(0x01E00000) /* 30 MB */ +#define STM32MP_DDR_SHMEM_SIZE U(0x00200000) /* 2 MB */ +#else +#define STM32MP_DDR_S_SIZE U(0x02000000) /* 32 MB */ +#define STM32MP_DDR_SHMEM_SIZE U(0) /* empty */ +#endif + +#if TRUSTED_BOARD_BOOT && !STM32MP_USE_EXTERNAL_HEAP +#if STM32MP15 +#define STM32MP_BL2_RO_SIZE U(0x00014000) /* 80 KB */ +#define STM32MP_BL2_SIZE U(0x0001B000) /* 108 KB for BL2 */ +#endif /* STM32MP15 */ +#else /* TRUSTED_BOARD_BOOT && !STM32MP_USE_EXTERNAL_HEAP */ +#if STM32MP13 +#if BL2_IN_XIP_MEM +#define STM32MP_BL2_RO_SIZE U(0x00015000) /* 84 KB */ +#define STM32MP_BL2_SIZE U(0x00017000) /* 92 KB for BL2 */ +#else +/* STM32MP_BL2_RO_SIZE not used if !BL2_IN_XIP_MEM */ +#define STM32MP_BL2_SIZE U(0x0001B000) /* 108KB for BL2 */ + /* with 20KB for DTB, SYSRAM is full */ +#endif +#endif /* STM32MP13 */ +#if STM32MP15 +#define STM32MP_BL2_RO_SIZE U(0x00011000) /* 68 KB */ +#define STM32MP_BL2_SIZE U(0x00016000) /* 88 KB for BL2 */ +#endif /* STM32MP15 */ +#endif /* TRUSTED_BOARD_BOOT && !STM32MP_USE_EXTERNAL_HEAP */ + +#if STM32MP13 +#if TRUSTED_BOARD_BOOT +#define STM32MP_BL2_DTB_SIZE U(0x00005000) /* 20 KB for DTB */ +#else /* TRUSTED_BOARD_BOOT */ +#define STM32MP_BL2_DTB_SIZE U(0x00004000) /* 16 KB for DTB */ +#endif /* TRUSTED_BOARD_BOOT */ +#endif /* STM32MP13 */ +#if STM32MP15 +#define STM32MP_BL2_DTB_SIZE U(0x00007000) /* 28 KB for DTB */ +#endif /* STM32MP15 */ +#define STM32MP_BL32_SIZE U(0x0001B000) /* 108 KB for BL32 */ +#define STM32MP_BL32_DTB_SIZE U(0x00005000) /* 20 KB for DTB */ +#define STM32MP_FW_CONFIG_MAX_SIZE PAGE_SIZE /* 4 KB for FCONF DTB */ +#define STM32MP_HW_CONFIG_MAX_SIZE U(0x40000) /* 256 KB for HW config DTB */ + +#if STM32MP13 +#define STM32MP_BL2_BASE (STM32MP_BL2_DTB_BASE + \ + STM32MP_BL2_DTB_SIZE) +#endif /* STM32MP13 */ +#if STM32MP15 +#define STM32MP_BL2_BASE (STM32MP_SEC_SYSRAM_BASE + \ + STM32MP_SEC_SYSRAM_SIZE - \ + STM32MP_BL2_SIZE) +#endif /* STM32MP15 */ + +#define STM32MP_BL2_RO_BASE STM32MP_BL2_BASE + +#define STM32MP_BL2_RW_BASE (STM32MP_BL2_RO_BASE + \ + STM32MP_BL2_RO_SIZE) + +#if STM32MP13 +#define STM32MP_BL2_RW_SIZE (STM32MP_SYSRAM_BASE + \ + STM32MP_SYSRAM_SIZE - \ + STM32MP_BL2_RW_BASE) + +#define STM32MP_BL2_DTB_BASE STM32MP_SEC_SYSRAM_BASE +#endif /* STM32MP13 */ +#if STM32MP15 +#define STM32MP_BL2_RW_SIZE (STM32MP_SEC_SYSRAM_BASE + \ + STM32MP_SEC_SYSRAM_SIZE - \ + STM32MP_BL2_RW_BASE) + +#define STM32MP_BL2_DTB_BASE (STM32MP_BL2_BASE - \ + STM32MP_BL2_DTB_SIZE) +#endif /* STM32MP15 */ + +#define STM32MP_BL32_DTB_BASE STM32MP_SYSRAM_BASE + +#define STM32MP_BL32_BASE (STM32MP_BL32_DTB_BASE + \ + STM32MP_BL32_DTB_SIZE) + + +#if defined(IMAGE_BL2) +#define STM32MP_DTB_SIZE STM32MP_BL2_DTB_SIZE +#define STM32MP_DTB_BASE STM32MP_BL2_DTB_BASE +#endif +#if defined(IMAGE_BL32) +#define STM32MP_DTB_SIZE STM32MP_BL32_DTB_SIZE +#define STM32MP_DTB_BASE STM32MP_BL32_DTB_BASE +#endif + +#ifdef AARCH32_SP_OPTEE +#define STM32MP_OPTEE_BASE STM32MP_SEC_SYSRAM_BASE + +#define STM32MP_OPTEE_SIZE (STM32MP_BL2_DTB_BASE - \ + STM32MP_OPTEE_BASE) +#endif + +#if STM32MP13 +#define STM32MP_FW_CONFIG_BASE SRAM3_BASE +#endif /* STM32MP13 */ +#if STM32MP15 +#define STM32MP_FW_CONFIG_BASE (STM32MP_SYSRAM_BASE + \ + STM32MP_SYSRAM_SIZE - \ + PAGE_SIZE) +#endif /* STM32MP15 */ +#define STM32MP_HW_CONFIG_BASE (STM32MP_BL33_BASE + \ + STM32MP_BL33_MAX_SIZE) + +/* + * MAX_MMAP_REGIONS is usually: + * BL stm32mp1_mmap size + mmap regions in *_plat_arch_setup + */ +#if defined(IMAGE_BL32) +#define MAX_MMAP_REGIONS 10 +#endif + +/******************************************************************************* + * STM32MP1 RAW partition offset for devices without GPT + ******************************************************************************/ +#define STM32MP_EMMC_BOOT_FIP_OFFSET U(0x00040000) +#ifndef STM32MP_NOR_FIP_OFFSET +#define STM32MP_NOR_FIP_OFFSET U(0x00080000) +#endif +#ifndef STM32MP_NAND_FIP_OFFSET +#define STM32MP_NAND_FIP_OFFSET U(0x00200000) +#endif + +#endif /* STM32MP1_FIP_DEF_H */ diff --git a/plat/st/stm32mp1/stm32mp1_gic.c b/plat/st/stm32mp1/stm32mp1_gic.c new file mode 100644 index 0000000..851a9cf --- /dev/null +++ b/plat/st/stm32mp1/stm32mp1_gic.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <libfdt.h> + +#include <platform_def.h> + +#include <common/bl_common.h> +#include <common/debug.h> +#include <drivers/arm/gicv2.h> +#include <dt-bindings/interrupt-controller/arm-gic.h> +#include <lib/utils.h> +#include <plat/common/platform.h> + +struct stm32_gic_instance { + uint32_t cells; + uint32_t phandle_node; +}; + +/****************************************************************************** + * On a GICv2 system, the Group 1 secure interrupts are treated as Group 0 + * interrupts. + *****************************************************************************/ +static const interrupt_prop_t stm32mp1_interrupt_props[] = { + PLATFORM_G1S_PROPS(GICV2_INTR_GROUP0), + PLATFORM_G0_PROPS(GICV2_INTR_GROUP0) +}; + +/* Fix target_mask_array as secondary core is not able to initialize it */ +static unsigned int target_mask_array[PLATFORM_CORE_COUNT] = {1, 2}; + +static gicv2_driver_data_t platform_gic_data = { + .interrupt_props = stm32mp1_interrupt_props, + .interrupt_props_num = ARRAY_SIZE(stm32mp1_interrupt_props), + .target_masks = target_mask_array, + .target_masks_num = ARRAY_SIZE(target_mask_array), +}; + +static struct stm32_gic_instance stm32_gic; + +void stm32mp1_gic_init(void) +{ + int node; + void *fdt; + const fdt32_t *cuint; + struct dt_node_info dt_gic; + + if (fdt_get_address(&fdt) == 0) { + panic(); + } + + node = dt_get_node(&dt_gic, -1, "arm,cortex-a7-gic"); + if (node < 0) { + panic(); + } + + platform_gic_data.gicd_base = dt_gic.base; + + cuint = fdt_getprop(fdt, node, "reg", NULL); + if (cuint == NULL) { + panic(); + } + + platform_gic_data.gicc_base = fdt32_to_cpu(*(cuint + 2)); + + cuint = fdt_getprop(fdt, node, "#interrupt-cells", NULL); + if (cuint == NULL) { + panic(); + } + + stm32_gic.cells = fdt32_to_cpu(*cuint); + + stm32_gic.phandle_node = fdt_get_phandle(fdt, node); + if (stm32_gic.phandle_node == 0U) { + panic(); + } + + gicv2_driver_init(&platform_gic_data); + gicv2_distif_init(); + + stm32mp1_gic_pcpu_init(); +} + +void stm32mp1_gic_pcpu_init(void) +{ + gicv2_pcpu_distif_init(); + gicv2_set_pe_target_mask(plat_my_core_pos()); + gicv2_cpuif_enable(); +} diff --git a/plat/st/stm32mp1/stm32mp1_helper.S b/plat/st/stm32mp1/stm32mp1_helper.S new file mode 100644 index 0000000..eb8823b --- /dev/null +++ b/plat/st/stm32mp1/stm32mp1_helper.S @@ -0,0 +1,336 @@ +/* + * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <platform_def.h> + +#include <arch.h> +#include <asm_macros.S> +#include <common/bl_common.h> +#include <drivers/st/stm32_gpio.h> + +#define GPIO_TX_SHIFT (DEBUG_UART_TX_GPIO_PORT << 1) + + .globl platform_mem_init + .globl plat_report_exception + .globl plat_report_prefetch_abort + .globl plat_report_data_abort + .globl plat_get_my_entrypoint + .globl plat_secondary_cold_boot_setup + .globl plat_reset_handler + .globl plat_is_my_cpu_primary + .globl plat_my_core_pos + .globl plat_crash_console_init + .globl plat_crash_console_flush + .globl plat_crash_console_putc + .globl plat_panic_handler + +func platform_mem_init + /* Nothing to do, don't need to init SYSRAM */ + bx lr +endfunc platform_mem_init + +#if DEBUG +func plat_report_exception + mov r8, lr + + /* + * Test if an abort occurred + * In this case the error message has already been displayed + * by dedicated functions + */ + cmp r0, #MODE32_abt + beq 1f + + /* Test for an undefined instruction */ + cmp r0, #MODE32_und + bne other_exception_lbl + ldr r4, =undefined_str + bl asm_print_str + mrs r4, lr_und + b print_exception_info + +other_exception_lbl: + /* Other exceptions */ + mov r9, r0 + ldr r4, =exception_start_str + bl asm_print_str + mov r4, r9 + bl asm_print_hex + ldr r4, =exception_end_str + bl asm_print_str + mov r4, r6 + +print_exception_info: + bl asm_print_hex + + ldr r4, =end_error_str + bl asm_print_str + +1: + bx r8 +endfunc plat_report_exception + +func plat_report_prefetch_abort + mov r8, lr + mov r9, r0 + + ldr r4, =prefetch_abort_str + bl asm_print_str + + mov r4, r9 + sub r4, r4, #4 + bl asm_print_hex + + ldr r4, =ifsr_str + bl asm_print_str + + ldcopr r4, IFSR + bl asm_print_hex + + ldr r4, =ifar_str + bl asm_print_str + + ldcopr r4, IFAR + bl asm_print_hex + + ldr r4, =end_error_str + bl asm_print_str + + bx r8 +endfunc plat_report_prefetch_abort + +func plat_report_data_abort + mov r8, lr + mov r9, r0 + + ldr r4, =data_abort_str + bl asm_print_str + + mov r4, r9 + sub r4, r4, #8 + bl asm_print_hex + + ldr r4, =dfsr_str + bl asm_print_str + + ldcopr r4, DFSR + bl asm_print_hex + + ldr r4, =dfar_str + bl asm_print_str + + ldcopr r4, DFAR + bl asm_print_hex + + ldr r4, =end_error_str + bl asm_print_str + + bx r8 +endfunc plat_report_data_abort +#endif /* DEBUG */ + +func plat_reset_handler + bx lr +endfunc plat_reset_handler + + /* ------------------------------------------------------------------ + * unsigned long plat_get_my_entrypoint (void); + * + * Main job of this routine is to distinguish between a cold and warm + * boot. + * + * Currently supports only cold boot + * ------------------------------------------------------------------ + */ +func plat_get_my_entrypoint + mov r0, #0 + bx lr +endfunc plat_get_my_entrypoint + + /* --------------------------------------------- + * void plat_secondary_cold_boot_setup (void); + * + * Cold-booting secondary CPUs is not supported. + * --------------------------------------------- + */ +func plat_secondary_cold_boot_setup + b . +endfunc plat_secondary_cold_boot_setup + + /* ----------------------------------------------------- + * unsigned int plat_is_my_cpu_primary (void); + * + * Find out whether the current cpu is the primary cpu. + * ----------------------------------------------------- + */ +func plat_is_my_cpu_primary + ldcopr r0, MPIDR + ldr r1, =(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK) + and r0, r1 + cmp r0, #STM32MP_PRIMARY_CPU + moveq r0, #1 + movne r0, #0 + bx lr +endfunc plat_is_my_cpu_primary + + /* ------------------------------------------- + * int plat_stm32mp1_get_core_pos(int mpidr); + * + * Return CorePos = (ClusterId * 4) + CoreId + * ------------------------------------------- + */ +func plat_stm32mp1_get_core_pos + and r1, r0, #MPIDR_CPU_MASK + and r0, r0, #MPIDR_CLUSTER_MASK + add r0, r1, r0, LSR #6 + bx lr +endfunc plat_stm32mp1_get_core_pos + + /* ------------------------------------ + * unsigned int plat_my_core_pos(void) + * ------------------------------------ + */ +func plat_my_core_pos + ldcopr r0, MPIDR + b plat_stm32mp1_get_core_pos +endfunc plat_my_core_pos + + /* --------------------------------------------- + * int plat_crash_console_init(void) + * + * Initialize the crash console without a C Runtime stack. + * --------------------------------------------- + */ +func plat_crash_console_init + /* Reset UART peripheral */ + ldr r1, =(RCC_BASE + DEBUG_UART_RST_REG) + ldr r2, =DEBUG_UART_RST_BIT + str r2, [r1] +1: + ldr r0, [r1] + ands r2, r0, r2 + beq 1b + str r2, [r1, #4] /* RSTCLR register */ +2: + ldr r0, [r1] + ands r2, r0, r2 + bne 2b + /* Enable GPIOs for UART TX */ + ldr r1, =(RCC_BASE + DEBUG_UART_TX_GPIO_BANK_CLK_REG) + ldr r2, [r1] + /* Configure GPIO */ + orr r2, r2, #DEBUG_UART_TX_GPIO_BANK_CLK_EN + str r2, [r1] + ldr r1, =DEBUG_UART_TX_GPIO_BANK_ADDRESS + /* Set GPIO mode alternate */ + ldr r2, [r1, #GPIO_MODE_OFFSET] + bic r2, r2, #(GPIO_MODE_MASK << GPIO_TX_SHIFT) + orr r2, r2, #(GPIO_MODE_ALTERNATE << GPIO_TX_SHIFT) + str r2, [r1, #GPIO_MODE_OFFSET] + /* Set GPIO speed low */ + ldr r2, [r1, #GPIO_SPEED_OFFSET] + bic r2, r2, #(GPIO_SPEED_MASK << GPIO_TX_SHIFT) + str r2, [r1, #GPIO_SPEED_OFFSET] + /* Set no-pull */ + ldr r2, [r1, #GPIO_PUPD_OFFSET] + bic r2, r2, #(GPIO_PULL_MASK << GPIO_TX_SHIFT) + str r2, [r1, #GPIO_PUPD_OFFSET] + /* Set alternate */ +#if DEBUG_UART_TX_GPIO_PORT >= GPIO_ALT_LOWER_LIMIT + ldr r2, [r1, #GPIO_AFRH_OFFSET] + bic r2, r2, #(GPIO_ALTERNATE_MASK << \ + ((DEBUG_UART_TX_GPIO_PORT - GPIO_ALT_LOWER_LIMIT) << 2)) + orr r2, r2, #(DEBUG_UART_TX_GPIO_ALTERNATE << \ + ((DEBUG_UART_TX_GPIO_PORT - GPIO_ALT_LOWER_LIMIT) << 2)) + str r2, [r1, #GPIO_AFRH_OFFSET] +#else + ldr r2, [r1, #GPIO_AFRL_OFFSET] + bic r2, r2, #(GPIO_ALTERNATE_MASK << (DEBUG_UART_TX_GPIO_PORT << 2)) + orr r2, r2, #(DEBUG_UART_TX_GPIO_ALTERNATE << (DEBUG_UART_TX_GPIO_PORT << 2)) + str r2, [r1, #GPIO_AFRL_OFFSET] +#endif + /* Enable UART clock, with its source */ + ldr r1, =(RCC_BASE + DEBUG_UART_TX_CLKSRC_REG) + mov r2, #DEBUG_UART_TX_CLKSRC + str r2, [r1] + ldr r1, =(RCC_BASE + DEBUG_UART_TX_EN_REG) + ldr r2, [r1] + orr r2, r2, #DEBUG_UART_TX_EN + str r2, [r1] + + ldr r0, =STM32MP_DEBUG_USART_BASE + ldr r1, =STM32MP_DEBUG_USART_CLK_FRQ + ldr r2, =STM32MP_UART_BAUDRATE + b console_stm32_core_init +endfunc plat_crash_console_init + + /* --------------------------------------------- + * void plat_crash_console_flush(void) + * + * Flush the crash console without a C Runtime stack. + * --------------------------------------------- + */ +func plat_crash_console_flush + ldr r0, =STM32MP_DEBUG_USART_BASE + b console_stm32_core_flush +endfunc plat_crash_console_flush + + /* --------------------------------------------- + * int plat_crash_console_putc(int c) + * + * Print a character on the crash console without a C Runtime stack. + * Clobber list : r1 - r3 + * + * In case of bootloading through uart, we keep console crash as this. + * Characters could be sent to the programmer, but will be ignored. + * No specific code in that case. + * --------------------------------------------- + */ +func plat_crash_console_putc + ldr r1, =STM32MP_DEBUG_USART_BASE + b console_stm32_core_putc +endfunc plat_crash_console_putc + + /* ---------------------------------------------------------- + * void plat_panic_handler(void) __dead2; + * Report exception + endless loop. + * + * r6 holds the address where the fault occurred. + * Filling lr with this value allows debuggers to reconstruct + * the backtrace. + * ---------------------------------------------------------- + */ +func plat_panic_handler + mrs r0, cpsr + and r0, #MODE32_MASK + bl plat_report_exception + mov lr, r6 + b . +endfunc plat_panic_handler + +#if DEBUG +.section .rodata.rev_err_str, "aS" +prefetch_abort_str: + .asciz "\nPrefetch Abort at: 0x" +data_abort_str: + .asciz "\nData Abort at: 0x" +undefined_str: + .asciz "\nUndefined instruction at: 0x" +exception_start_str: + .asciz "\nException mode=0x" +exception_end_str: + .asciz " at: 0x" +dfsr_str: + .asciz " DFSR = 0x" +dfar_str: + .asciz " DFAR = 0x" +ifsr_str: + .asciz " IFSR = 0x" +ifar_str: + .asciz " IFAR = 0x" +end_error_str: + .asciz "\n\r" +#endif diff --git a/plat/st/stm32mp1/stm32mp1_pm.c b/plat/st/stm32mp1/stm32mp1_pm.c new file mode 100644 index 0000000..6e438c4 --- /dev/null +++ b/plat/st/stm32mp1/stm32mp1_pm.c @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <errno.h> + +#include <arch_helpers.h> +#include <bl32/sp_min/platform_sp_min.h> +#include <common/debug.h> +#include <drivers/arm/gic_common.h> +#include <drivers/arm/gicv2.h> +#include <drivers/clk.h> +#include <dt-bindings/clock/stm32mp1-clks.h> +#include <lib/mmio.h> +#include <lib/psci/psci.h> +#include <plat/common/platform.h> + +#include <platform_def.h> + +static uintptr_t stm32_sec_entrypoint; +static uint32_t cntfrq_core0; + +/******************************************************************************* + * STM32MP1 handler called when a CPU is about to enter standby. + * call by core 1 to enter in wfi + ******************************************************************************/ +static void stm32_cpu_standby(plat_local_state_t cpu_state) +{ + uint32_t interrupt = GIC_SPURIOUS_INTERRUPT; + + assert(cpu_state == ARM_LOCAL_STATE_RET); + + /* + * Enter standby state + * dsb is good practice before using wfi to enter low power states + */ + isb(); + dsb(); + while (interrupt == GIC_SPURIOUS_INTERRUPT) { + wfi(); + + /* Acknoledge IT */ + interrupt = gicv2_acknowledge_interrupt(); + /* If Interrupt == 1022 it will be acknowledged by non secure */ + if ((interrupt != PENDING_G1_INTID) && + (interrupt != GIC_SPURIOUS_INTERRUPT)) { + gicv2_end_of_interrupt(interrupt); + } + } +} + +/******************************************************************************* + * STM32MP1 handler called when a power domain is about to be turned on. The + * mpidr determines the CPU to be turned on. + * call by core 0 to activate core 1 + ******************************************************************************/ +static int stm32_pwr_domain_on(u_register_t mpidr) +{ + unsigned long current_cpu_mpidr = read_mpidr_el1(); + uintptr_t bkpr_core1_addr = + tamp_bkpr(BOOT_API_CORE1_BRANCH_ADDRESS_TAMP_BCK_REG_IDX); + uintptr_t bkpr_core1_magic = + tamp_bkpr(BOOT_API_CORE1_MAGIC_NUMBER_TAMP_BCK_REG_IDX); + + if (mpidr == current_cpu_mpidr) { + return PSCI_E_INVALID_PARAMS; + } + + /* Only one valid entry point */ + if (stm32_sec_entrypoint != (uintptr_t)&sp_min_warm_entrypoint) { + return PSCI_E_INVALID_ADDRESS; + } + + clk_enable(RTCAPB); + + cntfrq_core0 = read_cntfrq_el0(); + + /* Write entrypoint in backup RAM register */ + mmio_write_32(bkpr_core1_addr, stm32_sec_entrypoint); + + /* Write magic number in backup register */ + mmio_write_32(bkpr_core1_magic, BOOT_API_A7_CORE1_MAGIC_NUMBER); + + clk_disable(RTCAPB); + + /* Generate an IT to core 1 */ + gicv2_raise_sgi(ARM_IRQ_SEC_SGI_0, false, STM32MP_SECONDARY_CPU); + + return PSCI_E_SUCCESS; +} + +/******************************************************************************* + * STM32MP1 handler called when a power domain is about to be turned off. The + * target_state encodes the power state that each level should transition to. + ******************************************************************************/ +static void stm32_pwr_domain_off(const psci_power_state_t *target_state) +{ + /* Nothing to do */ +} + +/******************************************************************************* + * STM32MP1 handler called when a power domain is about to be suspended. The + * target_state encodes the power state that each level should transition to. + ******************************************************************************/ +static void stm32_pwr_domain_suspend(const psci_power_state_t *target_state) +{ + /* Nothing to do, power domain is not disabled */ +} + +/******************************************************************************* + * STM32MP1 handler called when a power domain has just been powered on after + * being turned off earlier. The target_state encodes the low power state that + * each level has woken up from. + * call by core 1 just after wake up + ******************************************************************************/ +static void stm32_pwr_domain_on_finish(const psci_power_state_t *target_state) +{ + stm32mp1_gic_pcpu_init(); + + write_cntfrq_el0(cntfrq_core0); +} + +/******************************************************************************* + * STM32MP1 handler called when a power domain has just been powered on after + * having been suspended earlier. The target_state encodes the low power state + * that each level has woken up from. + ******************************************************************************/ +static void stm32_pwr_domain_suspend_finish(const psci_power_state_t + *target_state) +{ + /* Nothing to do, power domain is not disabled */ +} + +static void __dead2 stm32_pwr_domain_pwr_down_wfi(const psci_power_state_t + *target_state) +{ + ERROR("stm32mpu1 Power Down WFI: operation not handled.\n"); + panic(); +} + +static void __dead2 stm32_system_off(void) +{ + ERROR("stm32mpu1 System Off: operation not handled.\n"); + panic(); +} + +static void __dead2 stm32_system_reset(void) +{ + mmio_setbits_32(stm32mp_rcc_base() + RCC_MP_GRSTCSETR, + RCC_MP_GRSTCSETR_MPSYSRST); + + /* Loop in case system reset is not immediately caught */ + for ( ; ; ) { + ; + } +} + +static int stm32_validate_power_state(unsigned int power_state, + psci_power_state_t *req_state) +{ + int pstate = psci_get_pstate_type(power_state); + + if (pstate != 0) { + return PSCI_E_INVALID_PARAMS; + } + + if (psci_get_pstate_pwrlvl(power_state)) { + return PSCI_E_INVALID_PARAMS; + } + + if (psci_get_pstate_id(power_state)) { + return PSCI_E_INVALID_PARAMS; + } + + req_state->pwr_domain_state[0] = ARM_LOCAL_STATE_RET; + req_state->pwr_domain_state[1] = ARM_LOCAL_STATE_RUN; + + return PSCI_E_SUCCESS; +} + +static int stm32_validate_ns_entrypoint(uintptr_t entrypoint) +{ + /* The non-secure entry point must be in DDR */ + if (entrypoint < STM32MP_DDR_BASE) { + return PSCI_E_INVALID_ADDRESS; + } + + return PSCI_E_SUCCESS; +} + +static int stm32_node_hw_state(u_register_t target_cpu, + unsigned int power_level) +{ + /* + * The format of 'power_level' is implementation-defined, but 0 must + * mean a CPU. Only allow level 0. + */ + if (power_level != MPIDR_AFFLVL0) { + return PSCI_E_INVALID_PARAMS; + } + + /* + * From psci view the CPU 0 is always ON, + * CPU 1 can be SUSPEND or RUNNING. + * Therefore do not manage POWER OFF state and always return HW_ON. + */ + + return (int)HW_ON; +} + +/******************************************************************************* + * Export the platform handlers. The ARM Standard platform layer will take care + * of registering the handlers with PSCI. + ******************************************************************************/ +static const plat_psci_ops_t stm32_psci_ops = { + .cpu_standby = stm32_cpu_standby, + .pwr_domain_on = stm32_pwr_domain_on, + .pwr_domain_off = stm32_pwr_domain_off, + .pwr_domain_suspend = stm32_pwr_domain_suspend, + .pwr_domain_on_finish = stm32_pwr_domain_on_finish, + .pwr_domain_suspend_finish = stm32_pwr_domain_suspend_finish, + .pwr_domain_pwr_down_wfi = stm32_pwr_domain_pwr_down_wfi, + .system_off = stm32_system_off, + .system_reset = stm32_system_reset, + .validate_power_state = stm32_validate_power_state, + .validate_ns_entrypoint = stm32_validate_ns_entrypoint, + .get_node_hw_state = stm32_node_hw_state +}; + +/******************************************************************************* + * Export the platform specific power ops. + ******************************************************************************/ +int plat_setup_psci_ops(uintptr_t sec_entrypoint, + const plat_psci_ops_t **psci_ops) +{ + stm32_sec_entrypoint = sec_entrypoint; + *psci_ops = &stm32_psci_ops; + + return 0; +} diff --git a/plat/st/stm32mp1/stm32mp1_private.c b/plat/st/stm32mp1/stm32mp1_private.c new file mode 100644 index 0000000..9bdb075 --- /dev/null +++ b/plat/st/stm32mp1/stm32mp1_private.c @@ -0,0 +1,788 @@ +/* + * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> + +#include <drivers/clk.h> +#include <drivers/st/stm32_gpio.h> +#include <drivers/st/stm32_iwdg.h> +#include <lib/mmio.h> +#include <lib/xlat_tables/xlat_tables_v2.h> +#include <libfdt.h> + +#include <plat/common/platform.h> +#include <platform_def.h> + +/* Internal layout of the 32bit OTP word board_id */ +#define BOARD_ID_BOARD_NB_MASK GENMASK(31, 16) +#define BOARD_ID_BOARD_NB_SHIFT 16 +#define BOARD_ID_VARCPN_MASK GENMASK(15, 12) +#define BOARD_ID_VARCPN_SHIFT 12 +#define BOARD_ID_REVISION_MASK GENMASK(11, 8) +#define BOARD_ID_REVISION_SHIFT 8 +#define BOARD_ID_VARFG_MASK GENMASK(7, 4) +#define BOARD_ID_VARFG_SHIFT 4 +#define BOARD_ID_BOM_MASK GENMASK(3, 0) + +#define BOARD_ID2NB(_id) (((_id) & BOARD_ID_BOARD_NB_MASK) >> \ + BOARD_ID_BOARD_NB_SHIFT) +#define BOARD_ID2VARCPN(_id) (((_id) & BOARD_ID_VARCPN_MASK) >> \ + BOARD_ID_VARCPN_SHIFT) +#define BOARD_ID2REV(_id) (((_id) & BOARD_ID_REVISION_MASK) >> \ + BOARD_ID_REVISION_SHIFT) +#define BOARD_ID2VARFG(_id) (((_id) & BOARD_ID_VARFG_MASK) >> \ + BOARD_ID_VARFG_SHIFT) +#define BOARD_ID2BOM(_id) ((_id) & BOARD_ID_BOM_MASK) + +#if STM32MP13 +#define TAMP_BOOT_MODE_BACKUP_REG_ID U(30) +#endif +#if STM32MP15 +#define TAMP_BOOT_MODE_BACKUP_REG_ID U(20) +#endif +#define TAMP_BOOT_MODE_ITF_MASK GENMASK(15, 8) +#define TAMP_BOOT_MODE_ITF_SHIFT 8 +#define TAMP_BOOT_MODE_AUTH_MASK GENMASK(23, 16) +#define TAMP_BOOT_MODE_AUTH_SHIFT 16 + +/* + * Backup register to store fwu update information. + * It should be writeable only by secure world, but also readable by non secure + * (so it should be in Zone 2). + */ +#define TAMP_BOOT_FWU_INFO_REG_ID U(10) +#define TAMP_BOOT_FWU_INFO_IDX_MSK GENMASK(3, 0) +#define TAMP_BOOT_FWU_INFO_IDX_OFF U(0) +#define TAMP_BOOT_FWU_INFO_CNT_MSK GENMASK(7, 4) +#define TAMP_BOOT_FWU_INFO_CNT_OFF U(4) + +#if defined(IMAGE_BL2) +#define MAP_SEC_SYSRAM MAP_REGION_FLAT(STM32MP_SYSRAM_BASE, \ + STM32MP_SYSRAM_SIZE, \ + MT_MEMORY | \ + MT_RW | \ + MT_SECURE | \ + MT_EXECUTE_NEVER) +#elif defined(IMAGE_BL32) +#define MAP_SEC_SYSRAM MAP_REGION_FLAT(STM32MP_SEC_SYSRAM_BASE, \ + STM32MP_SEC_SYSRAM_SIZE, \ + MT_MEMORY | \ + MT_RW | \ + MT_SECURE | \ + MT_EXECUTE_NEVER) + +/* Non-secure SYSRAM is used a uncached memory for SCMI message transfer */ +#define MAP_NS_SYSRAM MAP_REGION_FLAT(STM32MP_NS_SYSRAM_BASE, \ + STM32MP_NS_SYSRAM_SIZE, \ + MT_DEVICE | \ + MT_RW | \ + MT_NS | \ + MT_EXECUTE_NEVER) +#endif + +#if STM32MP13 +#define MAP_SRAM_ALL MAP_REGION_FLAT(SRAMS_BASE, \ + SRAMS_SIZE_2MB_ALIGNED, \ + MT_MEMORY | \ + MT_RW | \ + MT_SECURE | \ + MT_EXECUTE_NEVER) +#endif + +#define MAP_DEVICE1 MAP_REGION_FLAT(STM32MP1_DEVICE1_BASE, \ + STM32MP1_DEVICE1_SIZE, \ + MT_DEVICE | \ + MT_RW | \ + MT_SECURE | \ + MT_EXECUTE_NEVER) + +#define MAP_DEVICE2 MAP_REGION_FLAT(STM32MP1_DEVICE2_BASE, \ + STM32MP1_DEVICE2_SIZE, \ + MT_DEVICE | \ + MT_RW | \ + MT_SECURE | \ + MT_EXECUTE_NEVER) + +#if defined(IMAGE_BL2) +static const mmap_region_t stm32mp1_mmap[] = { + MAP_SEC_SYSRAM, +#if STM32MP13 + MAP_SRAM_ALL, +#endif + MAP_DEVICE1, +#if STM32MP_RAW_NAND + MAP_DEVICE2, +#endif + {0} +}; +#endif +#if defined(IMAGE_BL32) +static const mmap_region_t stm32mp1_mmap[] = { + MAP_SEC_SYSRAM, + MAP_NS_SYSRAM, + MAP_DEVICE1, + MAP_DEVICE2, + {0} +}; +#endif + +void configure_mmu(void) +{ + mmap_add(stm32mp1_mmap); + init_xlat_tables(); + + enable_mmu_svc_mon(0); +} + +uintptr_t stm32_get_gpio_bank_base(unsigned int bank) +{ +#if STM32MP13 + assert(GPIO_BANK_A == 0 && bank <= GPIO_BANK_I); +#endif +#if STM32MP15 + if (bank == GPIO_BANK_Z) { + return GPIOZ_BASE; + } + + assert(GPIO_BANK_A == 0 && bank <= GPIO_BANK_K); +#endif + + return GPIOA_BASE + (bank * GPIO_BANK_OFFSET); +} + +uint32_t stm32_get_gpio_bank_offset(unsigned int bank) +{ +#if STM32MP13 + assert(GPIO_BANK_A == 0 && bank <= GPIO_BANK_I); +#endif +#if STM32MP15 + if (bank == GPIO_BANK_Z) { + return 0; + } + + assert(GPIO_BANK_A == 0 && bank <= GPIO_BANK_K); +#endif + + return bank * GPIO_BANK_OFFSET; +} + +bool stm32_gpio_is_secure_at_reset(unsigned int bank) +{ +#if STM32MP13 + return true; +#endif +#if STM32MP15 + if (bank == GPIO_BANK_Z) { + return true; + } + + return false; +#endif +} + +unsigned long stm32_get_gpio_bank_clock(unsigned int bank) +{ +#if STM32MP13 + assert(GPIO_BANK_A == 0 && bank <= GPIO_BANK_I); +#endif +#if STM32MP15 + if (bank == GPIO_BANK_Z) { + return GPIOZ; + } + + assert(GPIO_BANK_A == 0 && bank <= GPIO_BANK_K); +#endif + + return GPIOA + (bank - GPIO_BANK_A); +} + +int stm32_get_gpio_bank_pinctrl_node(void *fdt, unsigned int bank) +{ + const char *node_compatible = NULL; + + switch (bank) { + case GPIO_BANK_A: + case GPIO_BANK_B: + case GPIO_BANK_C: + case GPIO_BANK_D: + case GPIO_BANK_E: + case GPIO_BANK_F: + case GPIO_BANK_G: + case GPIO_BANK_H: + case GPIO_BANK_I: +#if STM32MP13 + node_compatible = "st,stm32mp135-pinctrl"; + break; +#endif +#if STM32MP15 + case GPIO_BANK_J: + case GPIO_BANK_K: + node_compatible = "st,stm32mp157-pinctrl"; + break; + case GPIO_BANK_Z: + node_compatible = "st,stm32mp157-z-pinctrl"; + break; +#endif + default: + panic(); + } + + return fdt_node_offset_by_compatible(fdt, -1, node_compatible); +} + +#if STM32MP_UART_PROGRAMMER || !defined(IMAGE_BL2) +/* + * UART Management + */ +static const uintptr_t stm32mp1_uart_addresses[8] = { + USART1_BASE, + USART2_BASE, + USART3_BASE, + UART4_BASE, + UART5_BASE, + USART6_BASE, + UART7_BASE, + UART8_BASE, +}; + +uintptr_t get_uart_address(uint32_t instance_nb) +{ + if ((instance_nb == 0U) || + (instance_nb > ARRAY_SIZE(stm32mp1_uart_addresses))) { + return 0U; + } + + return stm32mp1_uart_addresses[instance_nb - 1U]; +} +#endif + +#if STM32MP_USB_PROGRAMMER +struct gpio_bank_pin_list { + uint32_t bank; + uint32_t pin; +}; + +static const struct gpio_bank_pin_list gpio_list[] = { + { /* USART2_RX: GPIOA3 */ + .bank = 0U, + .pin = 3U, + }, + { /* USART3_RX: GPIOB12 */ + .bank = 1U, + .pin = 12U, + }, + { /* UART4_RX: GPIOB2 */ + .bank = 1U, + .pin = 2U, + }, + { /* UART5_RX: GPIOB4 */ + .bank = 1U, + .pin = 5U, + }, + { /* USART6_RX: GPIOC7 */ + .bank = 2U, + .pin = 7U, + }, + { /* UART7_RX: GPIOF6 */ + .bank = 5U, + .pin = 6U, + }, + { /* UART8_RX: GPIOE0 */ + .bank = 4U, + .pin = 0U, + }, +}; + +void stm32mp1_deconfigure_uart_pins(void) +{ + size_t i; + + for (i = 0U; i < ARRAY_SIZE(gpio_list); i++) { + set_gpio_reset_cfg(gpio_list[i].bank, gpio_list[i].pin); + } +} +#endif + +uint32_t stm32mp_get_chip_version(void) +{ +#if STM32MP13 + return stm32mp1_syscfg_get_chip_version(); +#endif +#if STM32MP15 + uint32_t version = 0U; + + if (stm32mp1_dbgmcu_get_chip_version(&version) < 0) { + INFO("Cannot get CPU version, debug disabled\n"); + return 0U; + } + + return version; +#endif +} + +uint32_t stm32mp_get_chip_dev_id(void) +{ +#if STM32MP13 + return stm32mp1_syscfg_get_chip_dev_id(); +#endif +#if STM32MP15 + uint32_t dev_id; + + if (stm32mp1_dbgmcu_get_chip_dev_id(&dev_id) < 0) { + INFO("Use default chip ID, debug disabled\n"); + dev_id = STM32MP1_CHIP_ID; + } + + return dev_id; +#endif +} + +static uint32_t get_part_number(void) +{ + static uint32_t part_number; + + if (part_number != 0U) { + return part_number; + } + + if (stm32_get_otp_value(PART_NUMBER_OTP, &part_number) != 0) { + panic(); + } + + part_number = (part_number & PART_NUMBER_OTP_PART_MASK) >> + PART_NUMBER_OTP_PART_SHIFT; + + part_number |= stm32mp_get_chip_dev_id() << 16; + + return part_number; +} + +#if STM32MP15 +static uint32_t get_cpu_package(void) +{ + uint32_t package; + + if (stm32_get_otp_value(PACKAGE_OTP, &package) != 0) { + panic(); + } + + package = (package & PACKAGE_OTP_PKG_MASK) >> + PACKAGE_OTP_PKG_SHIFT; + + return package; +} +#endif + +void stm32mp_get_soc_name(char name[STM32_SOC_NAME_SIZE]) +{ + char *cpu_s, *cpu_r, *pkg; + + /* MPUs Part Numbers */ + switch (get_part_number()) { +#if STM32MP13 + case STM32MP135F_PART_NB: + cpu_s = "135F"; + break; + case STM32MP135D_PART_NB: + cpu_s = "135D"; + break; + case STM32MP135C_PART_NB: + cpu_s = "135C"; + break; + case STM32MP135A_PART_NB: + cpu_s = "135A"; + break; + case STM32MP133F_PART_NB: + cpu_s = "133F"; + break; + case STM32MP133D_PART_NB: + cpu_s = "133D"; + break; + case STM32MP133C_PART_NB: + cpu_s = "133C"; + break; + case STM32MP133A_PART_NB: + cpu_s = "133A"; + break; + case STM32MP131F_PART_NB: + cpu_s = "131F"; + break; + case STM32MP131D_PART_NB: + cpu_s = "131D"; + break; + case STM32MP131C_PART_NB: + cpu_s = "131C"; + break; + case STM32MP131A_PART_NB: + cpu_s = "131A"; + break; +#endif +#if STM32MP15 + case STM32MP157C_PART_NB: + cpu_s = "157C"; + break; + case STM32MP157A_PART_NB: + cpu_s = "157A"; + break; + case STM32MP153C_PART_NB: + cpu_s = "153C"; + break; + case STM32MP153A_PART_NB: + cpu_s = "153A"; + break; + case STM32MP151C_PART_NB: + cpu_s = "151C"; + break; + case STM32MP151A_PART_NB: + cpu_s = "151A"; + break; + case STM32MP157F_PART_NB: + cpu_s = "157F"; + break; + case STM32MP157D_PART_NB: + cpu_s = "157D"; + break; + case STM32MP153F_PART_NB: + cpu_s = "153F"; + break; + case STM32MP153D_PART_NB: + cpu_s = "153D"; + break; + case STM32MP151F_PART_NB: + cpu_s = "151F"; + break; + case STM32MP151D_PART_NB: + cpu_s = "151D"; + break; +#endif + default: + cpu_s = "????"; + break; + } + + /* Package */ +#if STM32MP13 + /* On STM32MP13, package is not present in OTP */ + pkg = ""; +#endif +#if STM32MP15 + switch (get_cpu_package()) { + case PKG_AA_LFBGA448: + pkg = "AA"; + break; + case PKG_AB_LFBGA354: + pkg = "AB"; + break; + case PKG_AC_TFBGA361: + pkg = "AC"; + break; + case PKG_AD_TFBGA257: + pkg = "AD"; + break; + default: + pkg = "??"; + break; + } +#endif + + /* REVISION */ + switch (stm32mp_get_chip_version()) { + case STM32MP1_REV_B: + cpu_r = "B"; + break; +#if STM32MP13 + case STM32MP1_REV_Y: + cpu_r = "Y"; + break; +#endif + case STM32MP1_REV_Z: + cpu_r = "Z"; + break; + default: + cpu_r = "?"; + break; + } + + snprintf(name, STM32_SOC_NAME_SIZE, + "STM32MP%s%s Rev.%s", cpu_s, pkg, cpu_r); +} + +void stm32mp_print_cpuinfo(void) +{ + char name[STM32_SOC_NAME_SIZE]; + + stm32mp_get_soc_name(name); + NOTICE("CPU: %s\n", name); +} + +void stm32mp_print_boardinfo(void) +{ + uint32_t board_id = 0; + + if (stm32_get_otp_value(BOARD_ID_OTP, &board_id) != 0) { + return; + } + + if (board_id != 0U) { + char rev[2]; + + rev[0] = BOARD_ID2REV(board_id) - 1 + 'A'; + rev[1] = '\0'; + NOTICE("Board: MB%04x Var%u.%u Rev.%s-%02u\n", + BOARD_ID2NB(board_id), + BOARD_ID2VARCPN(board_id), + BOARD_ID2VARFG(board_id), + rev, + BOARD_ID2BOM(board_id)); + } +} + +/* Return true when SoC provides a single Cortex-A7 core, and false otherwise */ +bool stm32mp_is_single_core(void) +{ +#if STM32MP13 + return true; +#endif +#if STM32MP15 + bool single_core = false; + + switch (get_part_number()) { + case STM32MP151A_PART_NB: + case STM32MP151C_PART_NB: + case STM32MP151D_PART_NB: + case STM32MP151F_PART_NB: + single_core = true; + break; + default: + break; + } + + return single_core; +#endif +} + +/* Return true when device is in closed state */ +bool stm32mp_is_closed_device(void) +{ + uint32_t value; + + if (stm32_get_otp_value(CFG0_OTP, &value) != 0) { + return true; + } + +#if STM32MP13 + value = (value & CFG0_OTP_MODE_MASK) >> CFG0_OTP_MODE_SHIFT; + + switch (value) { + case CFG0_OPEN_DEVICE: + return false; + case CFG0_CLOSED_DEVICE: + case CFG0_CLOSED_DEVICE_NO_BOUNDARY_SCAN: + case CFG0_CLOSED_DEVICE_NO_JTAG: + return true; + default: + panic(); + } +#endif +#if STM32MP15 + return (value & CFG0_CLOSED_DEVICE) == CFG0_CLOSED_DEVICE; +#endif +} + +/* Return true when device supports secure boot */ +bool stm32mp_is_auth_supported(void) +{ + bool supported = false; + + switch (get_part_number()) { +#if STM32MP13 + case STM32MP131C_PART_NB: + case STM32MP131F_PART_NB: + case STM32MP133C_PART_NB: + case STM32MP133F_PART_NB: + case STM32MP135C_PART_NB: + case STM32MP135F_PART_NB: +#endif +#if STM32MP15 + case STM32MP151C_PART_NB: + case STM32MP151F_PART_NB: + case STM32MP153C_PART_NB: + case STM32MP153F_PART_NB: + case STM32MP157C_PART_NB: + case STM32MP157F_PART_NB: +#endif + supported = true; + break; + default: + break; + } + + return supported; +} + +uint32_t stm32_iwdg_get_instance(uintptr_t base) +{ + switch (base) { + case IWDG1_BASE: + return IWDG1_INST; + case IWDG2_BASE: + return IWDG2_INST; + default: + panic(); + } +} + +uint32_t stm32_iwdg_get_otp_config(uint32_t iwdg_inst) +{ + uint32_t iwdg_cfg = 0U; + uint32_t otp_value; + + if (stm32_get_otp_value(HW2_OTP, &otp_value) != 0) { + panic(); + } + + if ((otp_value & BIT(iwdg_inst + HW2_OTP_IWDG_HW_POS)) != 0U) { + iwdg_cfg |= IWDG_HW_ENABLED; + } + + if ((otp_value & BIT(iwdg_inst + HW2_OTP_IWDG_FZ_STOP_POS)) != 0U) { + iwdg_cfg |= IWDG_DISABLE_ON_STOP; + } + + if ((otp_value & BIT(iwdg_inst + HW2_OTP_IWDG_FZ_STANDBY_POS)) != 0U) { + iwdg_cfg |= IWDG_DISABLE_ON_STANDBY; + } + + return iwdg_cfg; +} + +#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 (stm32_get_otp_index(HW2_OTP, &otp, NULL) != 0) { + panic(); + } + + if (stm32_get_otp_value(HW2_OTP, &otp_value) != 0) { + panic(); + } + + if ((flags & IWDG_DISABLE_ON_STOP) != 0) { + otp_value |= BIT(iwdg_inst + HW2_OTP_IWDG_FZ_STOP_POS); + } + + 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(otp) != BSEC_OK) || + (bsec_set_sw_lock(otp) != BSEC_OK)) { + return BSEC_LOCK_FAIL; + } + + return BSEC_OK; +} +#endif + +void stm32_save_boot_interface(uint32_t interface, uint32_t instance) +{ + uintptr_t bkpr_itf_idx = tamp_bkpr(TAMP_BOOT_MODE_BACKUP_REG_ID); + + clk_enable(RTCAPB); + + mmio_clrsetbits_32(bkpr_itf_idx, + TAMP_BOOT_MODE_ITF_MASK, + ((interface << 4) | (instance & 0xFU)) << + TAMP_BOOT_MODE_ITF_SHIFT); + + clk_disable(RTCAPB); +} + +void stm32_get_boot_interface(uint32_t *interface, uint32_t *instance) +{ + static uint32_t itf; + + if (itf == 0U) { + uintptr_t bkpr = tamp_bkpr(TAMP_BOOT_MODE_BACKUP_REG_ID); + + clk_enable(RTCAPB); + + itf = (mmio_read_32(bkpr) & TAMP_BOOT_MODE_ITF_MASK) >> + TAMP_BOOT_MODE_ITF_SHIFT; + + clk_disable(RTCAPB); + } + + *interface = itf >> 4; + *instance = itf & 0xFU; +} + +void stm32_save_boot_auth(uint32_t auth_status, uint32_t boot_partition) +{ + uint32_t boot_status = tamp_bkpr(TAMP_BOOT_MODE_BACKUP_REG_ID); + + clk_enable(RTCAPB); + + mmio_clrsetbits_32(boot_status, + TAMP_BOOT_MODE_AUTH_MASK, + ((auth_status << 4) | (boot_partition & 0xFU)) << + TAMP_BOOT_MODE_AUTH_SHIFT); + + clk_disable(RTCAPB); +} + +#if PSA_FWU_SUPPORT +void stm32mp1_fwu_set_boot_idx(void) +{ + clk_enable(RTCAPB); + mmio_clrsetbits_32(tamp_bkpr(TAMP_BOOT_FWU_INFO_REG_ID), + TAMP_BOOT_FWU_INFO_IDX_MSK, + (plat_fwu_get_boot_idx() << TAMP_BOOT_FWU_INFO_IDX_OFF) & + TAMP_BOOT_FWU_INFO_IDX_MSK); + clk_disable(RTCAPB); +} + +uint32_t stm32_get_and_dec_fwu_trial_boot_cnt(void) +{ + uintptr_t bkpr_fwu_cnt = tamp_bkpr(TAMP_BOOT_FWU_INFO_REG_ID); + uint32_t try_cnt; + + clk_enable(RTCAPB); + try_cnt = (mmio_read_32(bkpr_fwu_cnt) & TAMP_BOOT_FWU_INFO_CNT_MSK) >> + TAMP_BOOT_FWU_INFO_CNT_OFF; + + assert(try_cnt <= FWU_MAX_TRIAL_REBOOT); + + if (try_cnt != 0U) { + mmio_clrsetbits_32(bkpr_fwu_cnt, TAMP_BOOT_FWU_INFO_CNT_MSK, + (try_cnt - 1U) << TAMP_BOOT_FWU_INFO_CNT_OFF); + } + clk_disable(RTCAPB); + + return try_cnt; +} + +void stm32_set_max_fwu_trial_boot_cnt(void) +{ + uintptr_t bkpr_fwu_cnt = tamp_bkpr(TAMP_BOOT_FWU_INFO_REG_ID); + + clk_enable(RTCAPB); + mmio_clrsetbits_32(bkpr_fwu_cnt, TAMP_BOOT_FWU_INFO_CNT_MSK, + (FWU_MAX_TRIAL_REBOOT << TAMP_BOOT_FWU_INFO_CNT_OFF) & + TAMP_BOOT_FWU_INFO_CNT_MSK); + clk_disable(RTCAPB); +} +#endif /* PSA_FWU_SUPPORT */ diff --git a/plat/st/stm32mp1/stm32mp1_scmi.c b/plat/st/stm32mp1/stm32mp1_scmi.c new file mode 100644 index 0000000..98585dc --- /dev/null +++ b/plat/st/stm32mp1/stm32mp1_scmi.c @@ -0,0 +1,479 @@ +/* + * Copyright (c) 2019-2021, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#include <assert.h> +#include <stdint.h> + +#include <platform_def.h> + +#include <drivers/clk.h> +#include <drivers/scmi-msg.h> +#include <drivers/scmi.h> +#include <drivers/st/stm32mp1_clk.h> +#include <drivers/st/stm32mp_reset.h> +#include <dt-bindings/clock/stm32mp1-clks.h> +#include <dt-bindings/reset/stm32mp1-resets.h> + +#define TIMEOUT_US_1MS 1000U + +#define SCMI_CLOCK_NAME_SIZE 16U +#define SCMI_RSTD_NAME_SIZE 16U + +/* + * struct stm32_scmi_clk - Data for the exposed clock + * @clock_id: Clock identifier in RCC clock driver + * @name: Clock string ID exposed to agent + * @enabled: State of the SCMI clock + */ +struct stm32_scmi_clk { + unsigned long clock_id; + const char *name; + bool enabled; +}; + +/* + * struct stm32_scmi_rstd - Data for the exposed reset controller + * @reset_id: Reset identifier in RCC reset driver + * @name: Reset string ID exposed to agent + */ +struct stm32_scmi_rstd { + unsigned long reset_id; + const char *name; +}; + +/* Locate all non-secure SMT message buffers in last page of SYSRAM */ +#define SMT_BUFFER_BASE STM32MP_SCMI_NS_SHM_BASE +#define SMT_BUFFER0_BASE SMT_BUFFER_BASE +#define SMT_BUFFER1_BASE (SMT_BUFFER_BASE + 0x200) + +CASSERT((STM32MP_SCMI_NS_SHM_BASE + STM32MP_SCMI_NS_SHM_SIZE) >= + (SMT_BUFFER1_BASE + SMT_BUF_SLOT_SIZE), + assert_scmi_non_secure_shm_fits_scmi_overall_buffer_size); + +static struct scmi_msg_channel scmi_channel[] = { + [0] = { + .shm_addr = SMT_BUFFER0_BASE, + .shm_size = SMT_BUF_SLOT_SIZE, + }, + [1] = { + .shm_addr = SMT_BUFFER1_BASE, + .shm_size = SMT_BUF_SLOT_SIZE, + }, +}; + +struct scmi_msg_channel *plat_scmi_get_channel(unsigned int agent_id) +{ + assert(agent_id < ARRAY_SIZE(scmi_channel)); + + return &scmi_channel[agent_id]; +} + +#define CLOCK_CELL(_scmi_id, _id, _name, _init_enabled) \ + [_scmi_id] = { \ + .clock_id = _id, \ + .name = _name, \ + .enabled = _init_enabled, \ + } + +static struct stm32_scmi_clk stm32_scmi0_clock[] = { + CLOCK_CELL(CK_SCMI0_HSE, CK_HSE, "ck_hse", true), + CLOCK_CELL(CK_SCMI0_HSI, CK_HSI, "ck_hsi", true), + CLOCK_CELL(CK_SCMI0_CSI, CK_CSI, "ck_csi", true), + CLOCK_CELL(CK_SCMI0_LSE, CK_LSE, "ck_lse", true), + CLOCK_CELL(CK_SCMI0_LSI, CK_LSI, "ck_lsi", true), + CLOCK_CELL(CK_SCMI0_PLL2_Q, PLL2_Q, "pll2_q", true), + CLOCK_CELL(CK_SCMI0_PLL2_R, PLL2_R, "pll2_r", true), + CLOCK_CELL(CK_SCMI0_MPU, CK_MPU, "ck_mpu", true), + CLOCK_CELL(CK_SCMI0_AXI, CK_AXI, "ck_axi", true), + CLOCK_CELL(CK_SCMI0_BSEC, BSEC, "bsec", true), + CLOCK_CELL(CK_SCMI0_CRYP1, CRYP1, "cryp1", false), + CLOCK_CELL(CK_SCMI0_GPIOZ, GPIOZ, "gpioz", false), + CLOCK_CELL(CK_SCMI0_HASH1, HASH1, "hash1", false), + CLOCK_CELL(CK_SCMI0_I2C4, I2C4_K, "i2c4_k", false), + CLOCK_CELL(CK_SCMI0_I2C6, I2C6_K, "i2c6_k", false), + CLOCK_CELL(CK_SCMI0_IWDG1, IWDG1, "iwdg1", false), + CLOCK_CELL(CK_SCMI0_RNG1, RNG1_K, "rng1_k", true), + CLOCK_CELL(CK_SCMI0_RTC, RTC, "ck_rtc", true), + CLOCK_CELL(CK_SCMI0_RTCAPB, RTCAPB, "rtcapb", true), + CLOCK_CELL(CK_SCMI0_SPI6, SPI6_K, "spi6_k", false), + CLOCK_CELL(CK_SCMI0_USART1, USART1_K, "usart1_k", false), +}; + +static struct stm32_scmi_clk stm32_scmi1_clock[] = { + CLOCK_CELL(CK_SCMI1_PLL3_Q, PLL3_Q, "pll3_q", true), + CLOCK_CELL(CK_SCMI1_PLL3_R, PLL3_R, "pll3_r", true), + CLOCK_CELL(CK_SCMI1_MCU, CK_MCU, "ck_mcu", false), +}; + +#define RESET_CELL(_scmi_id, _id, _name) \ + [_scmi_id] = { \ + .reset_id = _id, \ + .name = _name, \ + } + +static struct stm32_scmi_rstd stm32_scmi0_reset_domain[] = { + RESET_CELL(RST_SCMI0_SPI6, SPI6_R, "spi6"), + RESET_CELL(RST_SCMI0_I2C4, I2C4_R, "i2c4"), + RESET_CELL(RST_SCMI0_I2C6, I2C6_R, "i2c6"), + RESET_CELL(RST_SCMI0_USART1, USART1_R, "usart1"), + RESET_CELL(RST_SCMI0_STGEN, STGEN_R, "stgen"), + RESET_CELL(RST_SCMI0_GPIOZ, GPIOZ_R, "gpioz"), + RESET_CELL(RST_SCMI0_CRYP1, CRYP1_R, "cryp1"), + RESET_CELL(RST_SCMI0_HASH1, HASH1_R, "hash1"), + RESET_CELL(RST_SCMI0_RNG1, RNG1_R, "rng1"), + RESET_CELL(RST_SCMI0_MDMA, MDMA_R, "mdma"), + RESET_CELL(RST_SCMI0_MCU, MCU_R, "mcu"), +}; + +struct scmi_agent_resources { + struct stm32_scmi_clk *clock; + size_t clock_count; + struct stm32_scmi_rstd *rstd; + size_t rstd_count; +}; + +static const struct scmi_agent_resources agent_resources[] = { + [0] = { + .clock = stm32_scmi0_clock, + .clock_count = ARRAY_SIZE(stm32_scmi0_clock), + .rstd = stm32_scmi0_reset_domain, + .rstd_count = ARRAY_SIZE(stm32_scmi0_reset_domain), + }, + [1] = { + .clock = stm32_scmi1_clock, + .clock_count = ARRAY_SIZE(stm32_scmi1_clock), + }, +}; + +static const struct scmi_agent_resources *find_resource(unsigned int agent_id) +{ + assert(agent_id < ARRAY_SIZE(agent_resources)); + + return &agent_resources[agent_id]; +} + +#if ENABLE_ASSERTIONS +static size_t plat_scmi_protocol_count_paranoid(void) +{ + unsigned int n = 0U; + unsigned int count = 0U; + + for (n = 0U; n < ARRAY_SIZE(agent_resources); n++) { + if (agent_resources[n].clock_count) { + count++; + break; + } + } + + for (n = 0U; n < ARRAY_SIZE(agent_resources); n++) { + if (agent_resources[n].rstd_count) { + count++; + break; + } + } + + return count; +} +#endif + +static const char vendor[] = "ST"; +static const char sub_vendor[] = ""; + +const char *plat_scmi_vendor_name(void) +{ + return vendor; +} + +const char *plat_scmi_sub_vendor_name(void) +{ + return sub_vendor; +} + +/* Currently supporting Clocks and Reset Domains */ +static const uint8_t plat_protocol_list[] = { + SCMI_PROTOCOL_ID_CLOCK, + SCMI_PROTOCOL_ID_RESET_DOMAIN, + 0U /* Null termination */ +}; + +size_t plat_scmi_protocol_count(void) +{ + const size_t count = ARRAY_SIZE(plat_protocol_list) - 1U; + + assert(count == plat_scmi_protocol_count_paranoid()); + + return count; +} + +const uint8_t *plat_scmi_protocol_list(unsigned int agent_id __unused) +{ + assert(plat_scmi_protocol_count_paranoid() == + (ARRAY_SIZE(plat_protocol_list) - 1U)); + + return plat_protocol_list; +} + +/* + * Platform SCMI clocks + */ +static struct stm32_scmi_clk *find_clock(unsigned int agent_id, + unsigned int scmi_id) +{ + const struct scmi_agent_resources *resource = find_resource(agent_id); + size_t n = 0U; + + if (resource != NULL) { + for (n = 0U; n < resource->clock_count; n++) { + if (n == scmi_id) { + return &resource->clock[n]; + } + } + } + + return NULL; +} + +size_t plat_scmi_clock_count(unsigned int agent_id) +{ + const struct scmi_agent_resources *resource = find_resource(agent_id); + + if (resource == NULL) { + return 0U; + } + + return resource->clock_count; +} + +const char *plat_scmi_clock_get_name(unsigned int agent_id, + unsigned int scmi_id) +{ + struct stm32_scmi_clk *clock = find_clock(agent_id, scmi_id); + + if ((clock == NULL) || + !stm32mp_nsec_can_access_clock(clock->clock_id)) { + return NULL; + } + + return clock->name; +} + +int32_t plat_scmi_clock_rates_array(unsigned int agent_id, unsigned int scmi_id, + unsigned long *array, size_t *nb_elts) +{ + struct stm32_scmi_clk *clock = find_clock(agent_id, scmi_id); + + if (clock == NULL) { + return SCMI_NOT_FOUND; + } + + if (!stm32mp_nsec_can_access_clock(clock->clock_id)) { + return SCMI_DENIED; + } + + if (array == NULL) { + *nb_elts = 1U; + } else if (*nb_elts == 1U) { + *array = clk_get_rate(clock->clock_id); + } else { + return SCMI_GENERIC_ERROR; + } + + return SCMI_SUCCESS; +} + +unsigned long plat_scmi_clock_get_rate(unsigned int agent_id, + unsigned int scmi_id) +{ + struct stm32_scmi_clk *clock = find_clock(agent_id, scmi_id); + + if ((clock == NULL) || + !stm32mp_nsec_can_access_clock(clock->clock_id)) { + return 0U; + } + + return clk_get_rate(clock->clock_id); +} + +int32_t plat_scmi_clock_get_state(unsigned int agent_id, unsigned int scmi_id) +{ + struct stm32_scmi_clk *clock = find_clock(agent_id, scmi_id); + + if ((clock == NULL) || + !stm32mp_nsec_can_access_clock(clock->clock_id)) { + return 0U; + } + + return (int32_t)clock->enabled; +} + +int32_t plat_scmi_clock_set_state(unsigned int agent_id, unsigned int scmi_id, + bool enable_not_disable) +{ + struct stm32_scmi_clk *clock = find_clock(agent_id, scmi_id); + + if (clock == NULL) { + return SCMI_NOT_FOUND; + } + + if (!stm32mp_nsec_can_access_clock(clock->clock_id)) { + return SCMI_DENIED; + } + + if (enable_not_disable) { + if (!clock->enabled) { + VERBOSE("SCMI clock %u enable\n", scmi_id); + clk_enable(clock->clock_id); + clock->enabled = true; + } + } else { + if (clock->enabled) { + VERBOSE("SCMI clock %u disable\n", scmi_id); + clk_disable(clock->clock_id); + clock->enabled = false; + } + } + + return SCMI_SUCCESS; +} + +/* + * Platform SCMI reset domains + */ +static struct stm32_scmi_rstd *find_rstd(unsigned int agent_id, + unsigned int scmi_id) +{ + const struct scmi_agent_resources *resource = find_resource(agent_id); + size_t n; + + if (resource != NULL) { + for (n = 0U; n < resource->rstd_count; n++) { + if (n == scmi_id) { + return &resource->rstd[n]; + } + } + } + + return NULL; +} + +const char *plat_scmi_rstd_get_name(unsigned int agent_id, unsigned int scmi_id) +{ + const struct stm32_scmi_rstd *rstd = find_rstd(agent_id, scmi_id); + + if (rstd == NULL) { + return NULL; + } + + return rstd->name; +} + +size_t plat_scmi_rstd_count(unsigned int agent_id) +{ + const struct scmi_agent_resources *resource = find_resource(agent_id); + + if (resource == NULL) { + return 0U; + } + + return resource->rstd_count; +} + +int32_t plat_scmi_rstd_autonomous(unsigned int agent_id, unsigned int scmi_id, + uint32_t state) +{ + const struct stm32_scmi_rstd *rstd = find_rstd(agent_id, scmi_id); + + if (rstd == NULL) { + return SCMI_NOT_FOUND; + } + + if (!stm32mp_nsec_can_access_reset(rstd->reset_id)) { + return SCMI_DENIED; + } + + /* Supports only reset with context loss */ + if (state != 0U) { + return SCMI_NOT_SUPPORTED; + } + + VERBOSE("SCMI reset %lu cycle\n", rstd->reset_id); + + if (stm32mp_reset_assert(rstd->reset_id, TIMEOUT_US_1MS)) { + return SCMI_HARDWARE_ERROR; + } + + if (stm32mp_reset_deassert(rstd->reset_id, TIMEOUT_US_1MS)) { + return SCMI_HARDWARE_ERROR; + } + + return SCMI_SUCCESS; +} + +int32_t plat_scmi_rstd_set_state(unsigned int agent_id, unsigned int scmi_id, + bool assert_not_deassert) +{ + const struct stm32_scmi_rstd *rstd = find_rstd(agent_id, scmi_id); + + if (rstd == NULL) { + return SCMI_NOT_FOUND; + } + + if (!stm32mp_nsec_can_access_reset(rstd->reset_id)) { + return SCMI_DENIED; + } + + if (assert_not_deassert) { + VERBOSE("SCMI reset %lu set\n", rstd->reset_id); + stm32mp_reset_set(rstd->reset_id); + } else { + VERBOSE("SCMI reset %lu release\n", rstd->reset_id); + stm32mp_reset_release(rstd->reset_id); + } + + return SCMI_SUCCESS; +} + +/* + * Initialize platform SCMI resources + */ +void stm32mp1_init_scmi_server(void) +{ + size_t i; + + for (i = 0U; i < ARRAY_SIZE(scmi_channel); i++) { + scmi_smt_init_agent_channel(&scmi_channel[i]); + } + + for (i = 0U; i < ARRAY_SIZE(agent_resources); i++) { + const struct scmi_agent_resources *res = &agent_resources[i]; + size_t j; + + for (j = 0U; j < res->clock_count; j++) { + struct stm32_scmi_clk *clk = &res->clock[j]; + + if ((clk->name == NULL) || + (strlen(clk->name) >= SCMI_CLOCK_NAME_SIZE)) { + ERROR("Invalid SCMI clock name\n"); + panic(); + } + + /* Sync SCMI clocks with their targeted initial state */ + if (clk->enabled && + stm32mp_nsec_can_access_clock(clk->clock_id)) { + clk_enable(clk->clock_id); + } + } + + for (j = 0U; j < res->rstd_count; j++) { + struct stm32_scmi_rstd *rstd = &res->rstd[j]; + + if ((rstd->name == NULL) || + (strlen(rstd->name) >= SCMI_RSTD_NAME_SIZE)) { + ERROR("Invalid SCMI reset domain name\n"); + panic(); + } + } + } +} diff --git a/plat/st/stm32mp1/stm32mp1_shared_resources.c b/plat/st/stm32mp1/stm32mp1_shared_resources.c new file mode 100644 index 0000000..a0ca697 --- /dev/null +++ b/plat/st/stm32mp1/stm32mp1_shared_resources.c @@ -0,0 +1,596 @@ +/* + * Copyright (c) 2017-2022, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <stdint.h> + +#include <common/debug.h> +#include <drivers/st/etzpc.h> +#include <drivers/st/stm32_gpio.h> + +#include <platform_def.h> +#include <stm32mp_shared_resources.h> + +/* + * Once one starts to get the resource registering state, one cannot register + * new resources. This ensures resource state cannot change. + */ +static bool registering_locked; + +/* + * Shared peripherals and resources registration + * + * Each resource assignation is stored in a table. The state defaults + * to PERIPH_UNREGISTERED if the resource is not explicitly assigned. + * + * Resource driver that as not embedded (a.k.a their related CFG_xxx build + * directive is disabled) are assigned to the non-secure world. + * + * Each pin of the GPIOZ bank can be secure or non-secure. + * + * It is the platform responsibility the ensure resource assignation + * matches the access permission firewalls configuration. + */ +enum shres_state { + SHRES_UNREGISTERED = 0, + SHRES_SECURE, + SHRES_NON_SECURE, +}; + +/* Force uint8_t array for array of enum shres_state for size considerations */ +static uint8_t shres_state[STM32MP1_SHRES_COUNT]; + +static const char *shres2str_id_tbl[STM32MP1_SHRES_COUNT] __unused = { + [STM32MP1_SHRES_GPIOZ(0)] = "GPIOZ0", + [STM32MP1_SHRES_GPIOZ(1)] = "GPIOZ1", + [STM32MP1_SHRES_GPIOZ(2)] = "GPIOZ2", + [STM32MP1_SHRES_GPIOZ(3)] = "GPIOZ3", + [STM32MP1_SHRES_GPIOZ(4)] = "GPIOZ4", + [STM32MP1_SHRES_GPIOZ(5)] = "GPIOZ5", + [STM32MP1_SHRES_GPIOZ(6)] = "GPIOZ6", + [STM32MP1_SHRES_GPIOZ(7)] = "GPIOZ7", + [STM32MP1_SHRES_IWDG1] = "IWDG1", + [STM32MP1_SHRES_USART1] = "USART1", + [STM32MP1_SHRES_SPI6] = "SPI6", + [STM32MP1_SHRES_I2C4] = "I2C4", + [STM32MP1_SHRES_RNG1] = "RNG1", + [STM32MP1_SHRES_HASH1] = "HASH1", + [STM32MP1_SHRES_CRYP1] = "CRYP1", + [STM32MP1_SHRES_I2C6] = "I2C6", + [STM32MP1_SHRES_RTC] = "RTC", + [STM32MP1_SHRES_MCU] = "MCU", + [STM32MP1_SHRES_MDMA] = "MDMA", + [STM32MP1_SHRES_PLL3] = "PLL3", +}; + +static const char __unused *shres2str_id(enum stm32mp_shres id) +{ + assert(id < ARRAY_SIZE(shres2str_id_tbl)); + + return shres2str_id_tbl[id]; +} + +static const char __unused *shres2str_state_tbl[] = { + [SHRES_UNREGISTERED] = "unregistered", + [SHRES_NON_SECURE] = "non-secure", + [SHRES_SECURE] = "secure", +}; + +static const char __unused *shres2str_state(unsigned int state) +{ + assert(state < ARRAY_SIZE(shres2str_state_tbl)); + + return shres2str_state_tbl[state]; +} + +/* Get resource state: these accesses lock the registering support */ +static void lock_registering(void) +{ + registering_locked = true; +} + +static bool periph_is_non_secure(enum stm32mp_shres id) +{ + lock_registering(); + + return (shres_state[id] == SHRES_NON_SECURE) || + (shres_state[id] == SHRES_UNREGISTERED); +} + +static bool periph_is_secure(enum stm32mp_shres id) +{ + return !periph_is_non_secure(id); +} + +/* GPIOZ pin count is saved in RAM to prevent parsing FDT several times */ +static int8_t gpioz_nbpin = -1; + +static unsigned int get_gpio_nbpin(unsigned int bank) +{ + if (bank != GPIO_BANK_Z) { + int count = fdt_get_gpio_bank_pin_count(bank); + + assert((count >= 0) && ((unsigned int)count <= (GPIO_PIN_MAX + 1))); + + return (unsigned int)count; + } + + if (gpioz_nbpin < 0) { + int count = fdt_get_gpio_bank_pin_count(GPIO_BANK_Z); + + assert((count == 0) || (count == STM32MP_GPIOZ_PIN_MAX_COUNT)); + + gpioz_nbpin = count; + } + + return (unsigned int)gpioz_nbpin; +} + +static unsigned int get_gpioz_nbpin(void) +{ + return get_gpio_nbpin(GPIO_BANK_Z); +} + +static void register_periph(enum stm32mp_shres id, unsigned int state) +{ + assert((id < STM32MP1_SHRES_COUNT) && + ((state == SHRES_SECURE) || (state == SHRES_NON_SECURE))); + + if (registering_locked) { + if (shres_state[id] == state) { + return; + } + panic(); + } + + if ((shres_state[id] != SHRES_UNREGISTERED) && + (shres_state[id] != state)) { + VERBOSE("Cannot change %s from %s to %s\n", + shres2str_id(id), + shres2str_state(shres_state[id]), + shres2str_state(state)); + panic(); + } + + if (shres_state[id] == SHRES_UNREGISTERED) { + VERBOSE("Register %s as %s\n", + shres2str_id(id), shres2str_state(state)); + } + + if ((id >= STM32MP1_SHRES_GPIOZ(0)) && + (id <= STM32MP1_SHRES_GPIOZ(7)) && + ((unsigned int)(id - STM32MP1_SHRES_GPIOZ(0)) >= get_gpioz_nbpin())) { + ERROR("Invalid GPIO pin %d, %u pin(s) available\n", + (int)(id - STM32MP1_SHRES_GPIOZ(0)), get_gpioz_nbpin()); + panic(); + } + + shres_state[id] = (uint8_t)state; + + /* Explore clock tree to lock dependencies */ + if (state == SHRES_SECURE) { + enum stm32mp_shres clock_res_id; + + switch (id) { + case STM32MP1_SHRES_GPIOZ(0): + case STM32MP1_SHRES_GPIOZ(1): + case STM32MP1_SHRES_GPIOZ(2): + case STM32MP1_SHRES_GPIOZ(3): + case STM32MP1_SHRES_GPIOZ(4): + case STM32MP1_SHRES_GPIOZ(5): + case STM32MP1_SHRES_GPIOZ(6): + case STM32MP1_SHRES_GPIOZ(7): + clock_res_id = GPIOZ; + break; + case STM32MP1_SHRES_IWDG1: + clock_res_id = IWDG1; + break; + case STM32MP1_SHRES_USART1: + clock_res_id = USART1_K; + break; + case STM32MP1_SHRES_SPI6: + clock_res_id = SPI6_K; + break; + case STM32MP1_SHRES_I2C4: + clock_res_id = I2C4_K; + break; + case STM32MP1_SHRES_RNG1: + clock_res_id = RNG1_K; + break; + case STM32MP1_SHRES_HASH1: + clock_res_id = HASH1; + break; + case STM32MP1_SHRES_CRYP1: + clock_res_id = CRYP1; + break; + case STM32MP1_SHRES_I2C6: + clock_res_id = I2C6_K; + break; + case STM32MP1_SHRES_RTC: + clock_res_id = RTC; + break; + default: + /* No clock resource dependency */ + return; + } + + stm32mp1_register_clock_parents_secure(clock_res_id); + } +} + +/* Register resource by ID */ +void stm32mp_register_secure_periph(enum stm32mp_shres id) +{ + register_periph(id, SHRES_SECURE); +} + +void stm32mp_register_non_secure_periph(enum stm32mp_shres id) +{ + register_periph(id, SHRES_NON_SECURE); +} + +static void register_periph_iomem(uintptr_t base, unsigned int state) +{ + enum stm32mp_shres id; + + switch (base) { + case CRYP1_BASE: + id = STM32MP1_SHRES_CRYP1; + break; + case HASH1_BASE: + id = STM32MP1_SHRES_HASH1; + break; + case I2C4_BASE: + id = STM32MP1_SHRES_I2C4; + break; + case I2C6_BASE: + id = STM32MP1_SHRES_I2C6; + break; + case IWDG1_BASE: + id = STM32MP1_SHRES_IWDG1; + break; + case RNG1_BASE: + id = STM32MP1_SHRES_RNG1; + break; + case RTC_BASE: + id = STM32MP1_SHRES_RTC; + break; + case SPI6_BASE: + id = STM32MP1_SHRES_SPI6; + break; + case USART1_BASE: + id = STM32MP1_SHRES_USART1; + break; + + case GPIOA_BASE: + case GPIOB_BASE: + case GPIOC_BASE: + case GPIOD_BASE: + case GPIOE_BASE: + case GPIOF_BASE: + case GPIOG_BASE: + case GPIOH_BASE: + case GPIOI_BASE: + case GPIOJ_BASE: + case GPIOK_BASE: + case USART2_BASE: + case USART3_BASE: + case UART4_BASE: + case UART5_BASE: + case USART6_BASE: + case UART7_BASE: + case UART8_BASE: + case IWDG2_BASE: + /* Allow drivers to register some non-secure resources */ + VERBOSE("IO for non-secure resource 0x%x\n", + (unsigned int)base); + if (state != SHRES_NON_SECURE) { + panic(); + } + + return; + + default: + panic(); + } + + register_periph(id, state); +} + +void stm32mp_register_secure_periph_iomem(uintptr_t base) +{ + register_periph_iomem(base, SHRES_SECURE); +} + +void stm32mp_register_non_secure_periph_iomem(uintptr_t base) +{ + register_periph_iomem(base, SHRES_NON_SECURE); +} + +void stm32mp_register_secure_gpio(unsigned int bank, unsigned int pin) +{ + switch (bank) { + case GPIO_BANK_Z: + register_periph(STM32MP1_SHRES_GPIOZ(pin), SHRES_SECURE); + break; + default: + ERROR("GPIO bank %u cannot be secured\n", bank); + panic(); + } +} + +void stm32mp_register_non_secure_gpio(unsigned int bank, unsigned int pin) +{ + switch (bank) { + case GPIO_BANK_Z: + register_periph(STM32MP1_SHRES_GPIOZ(pin), SHRES_NON_SECURE); + break; + default: + break; + } +} + +static bool stm32mp_gpio_bank_is_non_secure(unsigned int bank) +{ + unsigned int non_secure = 0U; + unsigned int i; + + lock_registering(); + + if (bank != GPIO_BANK_Z) { + return true; + } + + for (i = 0U; i < get_gpioz_nbpin(); i++) { + if (periph_is_non_secure(STM32MP1_SHRES_GPIOZ(i))) { + non_secure++; + } + } + + return non_secure == get_gpioz_nbpin(); +} + +static bool stm32mp_gpio_bank_is_secure(unsigned int bank) +{ + unsigned int secure = 0U; + unsigned int i; + + lock_registering(); + + if (bank != GPIO_BANK_Z) { + return false; + } + + for (i = 0U; i < get_gpioz_nbpin(); i++) { + if (periph_is_secure(STM32MP1_SHRES_GPIOZ(i))) { + secure++; + } + } + + return secure == get_gpioz_nbpin(); +} + +bool stm32mp_nsec_can_access_clock(unsigned long clock_id) +{ + enum stm32mp_shres shres_id = STM32MP1_SHRES_COUNT; + + switch (clock_id) { + case CK_CSI: + case CK_HSE: + case CK_HSE_DIV2: + case CK_HSI: + case CK_LSE: + case CK_LSI: + case PLL1_P: + case PLL1_Q: + case PLL1_R: + case PLL2_P: + case PLL2_Q: + case PLL2_R: + case PLL3_P: + case PLL3_Q: + case PLL3_R: + case RTCAPB: + return true; + case GPIOZ: + /* Allow clock access if at least one pin is non-secure */ + return !stm32mp_gpio_bank_is_secure(GPIO_BANK_Z); + case CRYP1: + shres_id = STM32MP1_SHRES_CRYP1; + break; + case HASH1: + shres_id = STM32MP1_SHRES_HASH1; + break; + case I2C4_K: + shres_id = STM32MP1_SHRES_I2C4; + break; + case I2C6_K: + shres_id = STM32MP1_SHRES_I2C6; + break; + case IWDG1: + shres_id = STM32MP1_SHRES_IWDG1; + break; + case RNG1_K: + shres_id = STM32MP1_SHRES_RNG1; + break; + case RTC: + shres_id = STM32MP1_SHRES_RTC; + break; + case SPI6_K: + shres_id = STM32MP1_SHRES_SPI6; + break; + case USART1_K: + shres_id = STM32MP1_SHRES_USART1; + break; + default: + return false; + } + + return periph_is_non_secure(shres_id); +} + +bool stm32mp_nsec_can_access_reset(unsigned int reset_id) +{ + enum stm32mp_shres shres_id = STM32MP1_SHRES_COUNT; + + switch (reset_id) { + case CRYP1_R: + shres_id = STM32MP1_SHRES_CRYP1; + break; + case GPIOZ_R: + /* GPIOZ reset mandates all pins are non-secure */ + return stm32mp_gpio_bank_is_non_secure(GPIO_BANK_Z); + case HASH1_R: + shres_id = STM32MP1_SHRES_HASH1; + break; + case I2C4_R: + shres_id = STM32MP1_SHRES_I2C4; + break; + case I2C6_R: + shres_id = STM32MP1_SHRES_I2C6; + break; + case MCU_R: + shres_id = STM32MP1_SHRES_MCU; + break; + case MDMA_R: + shres_id = STM32MP1_SHRES_MDMA; + break; + case RNG1_R: + shres_id = STM32MP1_SHRES_RNG1; + break; + case SPI6_R: + shres_id = STM32MP1_SHRES_SPI6; + break; + case USART1_R: + shres_id = STM32MP1_SHRES_USART1; + break; + default: + return false; + } + + return periph_is_non_secure(shres_id); +} + +static bool mckprot_protects_periph(enum stm32mp_shres id) +{ + switch (id) { + case STM32MP1_SHRES_MCU: + case STM32MP1_SHRES_PLL3: + return true; + default: + return false; + } +} + +/* ETZPC configuration at drivers initialization completion */ +static enum etzpc_decprot_attributes shres2decprot_attr(enum stm32mp_shres id) +{ + assert((id < STM32MP1_SHRES_GPIOZ(0)) || + (id > STM32MP1_SHRES_GPIOZ(7))); + + if (periph_is_non_secure(id)) { + return ETZPC_DECPROT_NS_RW; + } + + return ETZPC_DECPROT_S_RW; +} + +static void set_etzpc_secure_configuration(void) +{ + /* Some system peripherals shall be secure */ + etzpc_configure_decprot(STM32MP1_ETZPC_STGENC_ID, ETZPC_DECPROT_S_RW); + etzpc_configure_decprot(STM32MP1_ETZPC_BKPSRAM_ID, ETZPC_DECPROT_S_RW); + etzpc_configure_decprot(STM32MP1_ETZPC_DDRCTRL_ID, + ETZPC_DECPROT_NS_R_S_W); + etzpc_configure_decprot(STM32MP1_ETZPC_DDRPHYC_ID, + ETZPC_DECPROT_NS_R_S_W); + + /* Configure ETZPC with peripheral registering */ + etzpc_configure_decprot(STM32MP1_ETZPC_CRYP1_ID, + shres2decprot_attr(STM32MP1_SHRES_CRYP1)); + etzpc_configure_decprot(STM32MP1_ETZPC_HASH1_ID, + shres2decprot_attr(STM32MP1_SHRES_HASH1)); + etzpc_configure_decprot(STM32MP1_ETZPC_I2C4_ID, + shres2decprot_attr(STM32MP1_SHRES_I2C4)); + etzpc_configure_decprot(STM32MP1_ETZPC_I2C6_ID, + shres2decprot_attr(STM32MP1_SHRES_I2C6)); + etzpc_configure_decprot(STM32MP1_ETZPC_IWDG1_ID, + shres2decprot_attr(STM32MP1_SHRES_IWDG1)); + etzpc_configure_decprot(STM32MP1_ETZPC_RNG1_ID, + shres2decprot_attr(STM32MP1_SHRES_RNG1)); + etzpc_configure_decprot(STM32MP1_ETZPC_USART1_ID, + shres2decprot_attr(STM32MP1_SHRES_USART1)); + etzpc_configure_decprot(STM32MP1_ETZPC_SPI6_ID, + shres2decprot_attr(STM32MP1_SHRES_SPI6)); +} + +static void check_rcc_secure_configuration(void) +{ + uint32_t n; + uint32_t error = 0U; + bool mckprot = stm32mp1_rcc_is_mckprot(); + bool secure = stm32mp1_rcc_is_secure(); + + for (n = 0U; n < ARRAY_SIZE(shres_state); n++) { + if (shres_state[n] != SHRES_SECURE) { + continue; + } + + if (!secure || (mckprot_protects_periph(n) && (!mckprot))) { + ERROR("RCC %s MCKPROT %s and %s secure\n", + secure ? "secure" : "non-secure", + mckprot ? "set" : "not set", + shres2str_id(n)); + error++; + } + } + + if (error != 0U) { + panic(); + } +} + +static void set_gpio_secure_configuration(void) +{ + uint32_t pin; + + for (pin = 0U; pin < get_gpioz_nbpin(); pin++) { + bool secure_state = periph_is_secure(STM32MP1_SHRES_GPIOZ(pin)); + + set_gpio_secure_cfg(GPIO_BANK_Z, pin, secure_state); + } +} + +static void print_shared_resources_state(void) +{ + unsigned int id; + + for (id = 0U; id < STM32MP1_SHRES_COUNT; id++) { + switch (shres_state[id]) { + case SHRES_SECURE: + INFO("stm32mp1 %s is secure\n", shres2str_id(id)); + break; + case SHRES_NON_SECURE: + case SHRES_UNREGISTERED: + VERBOSE("stm32mp %s is non-secure\n", shres2str_id(id)); + break; + default: + VERBOSE("stm32mp %s is invalid\n", shres2str_id(id)); + panic(); + } + } +} + +void stm32mp_lock_periph_registering(void) +{ + registering_locked = true; + + print_shared_resources_state(); + + check_rcc_secure_configuration(); + set_etzpc_secure_configuration(); + set_gpio_secure_configuration(); +} diff --git a/plat/st/stm32mp1/stm32mp1_stack_protector.c b/plat/st/stm32mp1/stm32mp1_stack_protector.c new file mode 100644 index 0000000..14e8e16 --- /dev/null +++ b/plat/st/stm32mp1/stm32mp1_stack_protector.c @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <stdint.h> + +#include <arch_helpers.h> +#include <plat/common/platform.h> + +#define RANDOM_CANARY_VALUE 2144346116U + +u_register_t plat_get_stack_protector_canary(void) +{ + /* + * Ideally, a random number should be returned instead of the + * combination of a timer's value and a compile-time constant. + */ + return RANDOM_CANARY_VALUE ^ (u_register_t)read_cntpct_el0(); +} + diff --git a/plat/st/stm32mp1/stm32mp1_syscfg.c b/plat/st/stm32mp1/stm32mp1_syscfg.c new file mode 100644 index 0000000..ff79428 --- /dev/null +++ b/plat/st/stm32mp1/stm32mp1_syscfg.c @@ -0,0 +1,411 @@ +/* + * Copyright (c) 2019-2022, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <errno.h> + +#include <common/debug.h> +#include <drivers/clk.h> +#include <drivers/delay_timer.h> +#include <drivers/st/stpmic1.h> +#include <lib/mmio.h> +#include <lib/utils_def.h> +#include <libfdt.h> + +#include <platform_def.h> +#include <stm32mp_common.h> +#include <stm32mp_dt.h> +#include <stm32mp1_private.h> + +/* + * SYSCFG REGISTER OFFSET (base relative) + */ +#define SYSCFG_BOOTR 0x00U +#define SYSCFG_BOOTCR 0x0CU +#if STM32MP15 +#define SYSCFG_IOCTRLSETR 0x18U +#define SYSCFG_ICNR 0x1CU +#endif +#define SYSCFG_CMPCR 0x20U +#define SYSCFG_CMPENSETR 0x24U +#define SYSCFG_CMPENCLRR 0x28U +#if STM32MP13 +#define SYSCFG_CMPSD1CR 0x30U +#define SYSCFG_CMPSD1ENSETR 0x34U +#define SYSCFG_CMPSD1ENCLRR 0x38U +#define SYSCFG_CMPSD2CR 0x40U +#define SYSCFG_CMPSD2ENSETR 0x44U +#define SYSCFG_CMPSD2ENCLRR 0x48U +#define SYSCFG_HSLVEN0R 0x50U +#endif +#define SYSCFG_IDC 0x380U + +#define CMPCR_CMPENSETR_OFFSET 0x4U +#define CMPCR_CMPENCLRR_OFFSET 0x8U + +/* + * SYSCFG_BOOTR Register + */ +#define SYSCFG_BOOTR_BOOT_MASK GENMASK(2, 0) +#if STM32MP15 +#define SYSCFG_BOOTR_BOOTPD_MASK GENMASK(6, 4) +#define SYSCFG_BOOTR_BOOTPD_SHIFT 4 +#endif + +/* + * SYSCFG_BOOTCR Register + */ +#define SYSCFG_BOOTCR_BMEN BIT(0) + +/* + * SYSCFG_IOCTRLSETR Register + */ +#define SYSCFG_IOCTRLSETR_HSLVEN_TRACE BIT(0) +#define SYSCFG_IOCTRLSETR_HSLVEN_QUADSPI BIT(1) +#define SYSCFG_IOCTRLSETR_HSLVEN_ETH BIT(2) +#define SYSCFG_IOCTRLSETR_HSLVEN_SDMMC BIT(3) +#define SYSCFG_IOCTRLSETR_HSLVEN_SPI BIT(4) + +/* + * SYSCFG_ICNR Register + */ +#define SYSCFG_ICNR_AXI_M9 BIT(9) + +/* + * SYSCFG_CMPCR Register + */ +#define SYSCFG_CMPCR_SW_CTRL BIT(1) +#define SYSCFG_CMPCR_READY BIT(8) +#define SYSCFG_CMPCR_RANSRC GENMASK(19, 16) +#define SYSCFG_CMPCR_RANSRC_SHIFT 16 +#define SYSCFG_CMPCR_RAPSRC GENMASK(23, 20) +#define SYSCFG_CMPCR_ANSRC_SHIFT 24 + +#define SYSCFG_CMPCR_READY_TIMEOUT_US 10000U + +/* + * SYSCFG_CMPENSETR Register + */ +#define SYSCFG_CMPENSETR_MPU_EN BIT(0) + +/* + * HSLV definitions + */ +#define HSLV_IDX_TPIU 0U +#define HSLV_IDX_QSPI 1U +#define HSLV_IDX_ETH1 2U +#define HSLV_IDX_ETH2 3U +#define HSLV_IDX_SDMMC1 4U +#define HSLV_IDX_SDMMC2 5U +#define HSLV_IDX_SPI1 6U +#define HSLV_IDX_SPI2 7U +#define HSLV_IDX_SPI3 8U +#define HSLV_IDX_SPI4 9U +#define HSLV_IDX_SPI5 10U +#define HSLV_IDX_LTDC 11U +#define HSLV_NB_IDX 12U + +#define HSLV_KEY 0x1018U + +/* + * SYSCFG_IDC Register + */ +#define SYSCFG_IDC_DEV_ID_MASK GENMASK(11, 0) +#define SYSCFG_IDC_REV_ID_MASK GENMASK(31, 16) +#define SYSCFG_IDC_REV_ID_SHIFT 16 + +static void enable_io_comp_cell_finish(uintptr_t cmpcr_off) +{ + uint64_t start; + + start = timeout_init_us(SYSCFG_CMPCR_READY_TIMEOUT_US); + + while ((mmio_read_32(SYSCFG_BASE + cmpcr_off) & SYSCFG_CMPCR_READY) == 0U) { + if (timeout_elapsed(start)) { + /* Failure on IO compensation enable is not a issue: warn only. */ + WARN("IO compensation cell not ready\n"); + break; + } + } + + mmio_clrbits_32(SYSCFG_BASE + cmpcr_off, SYSCFG_CMPCR_SW_CTRL); +} + +static void disable_io_comp_cell(uintptr_t cmpcr_off) +{ + uint32_t value; + + if (((mmio_read_32(SYSCFG_BASE + cmpcr_off) & SYSCFG_CMPCR_READY) == 0U) || + ((mmio_read_32(SYSCFG_BASE + cmpcr_off + CMPCR_CMPENSETR_OFFSET) & + SYSCFG_CMPENSETR_MPU_EN) == 0U)) { + return; + } + + value = mmio_read_32(SYSCFG_BASE + cmpcr_off) >> SYSCFG_CMPCR_ANSRC_SHIFT; + + mmio_clrbits_32(SYSCFG_BASE + cmpcr_off, SYSCFG_CMPCR_RANSRC | SYSCFG_CMPCR_RAPSRC); + + value <<= SYSCFG_CMPCR_RANSRC_SHIFT; + value |= mmio_read_32(SYSCFG_BASE + cmpcr_off); + + mmio_write_32(SYSCFG_BASE + cmpcr_off, value | SYSCFG_CMPCR_SW_CTRL); + + mmio_setbits_32(SYSCFG_BASE + cmpcr_off + CMPCR_CMPENCLRR_OFFSET, SYSCFG_CMPENSETR_MPU_EN); +} + +#if STM32MP13 +static int get_regu_max_voltage(void *fdt, int sdmmc_node, + const char *regu_name, uint32_t *regu_val) +{ + int node; + const fdt32_t *cuint; + + cuint = fdt_getprop(fdt, sdmmc_node, regu_name, NULL); + if (cuint == NULL) { + return -ENODEV; + } + + node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint)); + if (node < 0) { + return -ENODEV; + } + + cuint = fdt_getprop(fdt, node, "regulator-max-microvolt", NULL); + if (cuint == NULL) { + return -ENODEV; + } + + *regu_val = fdt32_to_cpu(*cuint); + + return 0; +} + +static bool sdmmc_is_low_voltage(uintptr_t sdmmc_base) +{ + int ret; + int node; + void *fdt = NULL; + uint32_t regu_max_val; + + if (fdt_get_address(&fdt) == 0) { + return false; + } + + if (fdt == NULL) { + return false; + } + + node = dt_match_instance_by_compatible(DT_SDMMC2_COMPAT, sdmmc_base); + if (node < 0) { + /* No SD or eMMC device on this instance, enable HSLV */ + return true; + } + + ret = get_regu_max_voltage(fdt, node, "vqmmc-supply", ®u_max_val); + if ((ret < 0) || (regu_max_val > 1800000U)) { + /* + * The vqmmc-supply property should always be present for eMMC. + * For SD-card, if it is not, then the card only supports 3.3V. + */ + return false; + } + + return true; +} + +static void enable_hslv_by_index(uint32_t index) +{ + bool apply_hslv; + + assert(index < HSLV_NB_IDX); + + switch (index) { + case HSLV_IDX_SDMMC1: + apply_hslv = sdmmc_is_low_voltage(STM32MP_SDMMC1_BASE); + break; + case HSLV_IDX_SDMMC2: + apply_hslv = sdmmc_is_low_voltage(STM32MP_SDMMC2_BASE); + break; + default: + apply_hslv = true; + break; + } + + if (apply_hslv) { + mmio_write_32(SYSCFG_BASE + SYSCFG_HSLVEN0R + index * sizeof(uint32_t), HSLV_KEY); + } +} +#endif + +static void enable_high_speed_mode_low_voltage(void) +{ +#if STM32MP13 + uint32_t idx; + + for (idx = 0U; idx < HSLV_NB_IDX; idx++) { + enable_hslv_by_index(idx); + } +#endif +#if STM32MP15 + mmio_write_32(SYSCFG_BASE + SYSCFG_IOCTRLSETR, + SYSCFG_IOCTRLSETR_HSLVEN_TRACE | + SYSCFG_IOCTRLSETR_HSLVEN_QUADSPI | + SYSCFG_IOCTRLSETR_HSLVEN_ETH | + SYSCFG_IOCTRLSETR_HSLVEN_SDMMC | + SYSCFG_IOCTRLSETR_HSLVEN_SPI); +#endif +} + +static void stm32mp1_syscfg_set_hslv(void) +{ + uint32_t otp_value; + uint32_t vdd_voltage; + bool product_below_2v5; + + /* + * High Speed Low Voltage Pad mode Enable for SPI, SDMMC, ETH, QSPI + * and TRACE. Needed above ~50MHz and conditioned by AFMUX selection. + * It could be disabled for low frequencies or if AFMUX is selected + * but the function is not used, typically for TRACE. + * If high speed low voltage pad mode is node enable, platform will + * over consume. + * + * WARNING: + * Enabling High Speed mode while VDD > 2.7V + * with the OTP product_below_2v5 (OTP 18, BIT 13) + * erroneously set to 1 can damage the SoC! + * => 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 (stm32_get_otp_value(HW2_OTP, &otp_value) != 0) { + panic(); + } + + 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\n"); + } else if (vdd_voltage < 2700000U) { + enable_high_speed_mode_low_voltage(); + + if (!product_below_2v5) { + INFO("Product_below_2v5=0: HSLVEN protected by HW\n"); + } + } else { + if (product_below_2v5) { + ERROR("Product_below_2v5=1:\n"); + ERROR("\tHSLVEN update is destructive,\n"); + ERROR("\tno update as VDD > 2.7V\n"); + panic(); + } + } +} + +void stm32mp1_syscfg_init(void) +{ +#if STM32MP15 + uint32_t bootr; + + /* + * Interconnect update : select master using the port 1. + * LTDC = AXI_M9. + */ + mmio_write_32(SYSCFG_BASE + SYSCFG_ICNR, SYSCFG_ICNR_AXI_M9); + + /* Disable Pull-Down for boot pin connected to VDD */ + bootr = mmio_read_32(SYSCFG_BASE + SYSCFG_BOOTR) & + SYSCFG_BOOTR_BOOT_MASK; + mmio_clrsetbits_32(SYSCFG_BASE + SYSCFG_BOOTR, SYSCFG_BOOTR_BOOTPD_MASK, + bootr << SYSCFG_BOOTR_BOOTPD_SHIFT); +#endif + + stm32mp1_syscfg_set_hslv(); + + stm32mp1_syscfg_enable_io_compensation_start(); +} + +void stm32mp1_syscfg_enable_io_compensation_start(void) +{ + /* + * Activate automatic I/O compensation. + * Warning: need to ensure CSI enabled and ready in clock driver. + * Enable non-secure clock, we assume non-secure is suspended. + */ + clk_enable(SYSCFG); + + mmio_setbits_32(SYSCFG_BASE + CMPCR_CMPENSETR_OFFSET + SYSCFG_CMPCR, + SYSCFG_CMPENSETR_MPU_EN); +#if STM32MP13 + mmio_setbits_32(SYSCFG_BASE + CMPCR_CMPENSETR_OFFSET + SYSCFG_CMPSD1CR, + SYSCFG_CMPENSETR_MPU_EN); + mmio_setbits_32(SYSCFG_BASE + CMPCR_CMPENSETR_OFFSET + SYSCFG_CMPSD2CR, + SYSCFG_CMPENSETR_MPU_EN); + +#endif +} + +void stm32mp1_syscfg_enable_io_compensation_finish(void) +{ + enable_io_comp_cell_finish(SYSCFG_CMPCR); +#if STM32MP13 + enable_io_comp_cell_finish(SYSCFG_CMPSD1CR); + enable_io_comp_cell_finish(SYSCFG_CMPSD2CR); +#endif +} + +void stm32mp1_syscfg_disable_io_compensation(void) +{ + clk_enable(SYSCFG); + + /* + * Deactivate automatic I/O compensation. + * Warning: CSI is disabled automatically in STOP if not + * requested for other usages and always OFF in STANDBY. + * Disable non-secure SYSCFG clock, we assume non-secure is suspended. + */ + disable_io_comp_cell(SYSCFG_CMPCR); +#if STM32MP13 + disable_io_comp_cell(SYSCFG_CMPSD1CR); + disable_io_comp_cell(SYSCFG_CMPSD2CR); +#endif + + clk_disable(SYSCFG); +} + +/* + * @brief Get silicon revision from SYSCFG registers. + * @retval chip version (REV_ID). + */ +uint32_t stm32mp1_syscfg_get_chip_version(void) +{ + return (mmio_read_32(SYSCFG_BASE + SYSCFG_IDC) & + SYSCFG_IDC_REV_ID_MASK) >> SYSCFG_IDC_REV_ID_SHIFT; +} + +/* + * @brief Get device ID from SYSCFG registers. + * @retval device ID (DEV_ID). + */ +uint32_t stm32mp1_syscfg_get_chip_dev_id(void) +{ + return mmio_read_32(SYSCFG_BASE + SYSCFG_IDC) & SYSCFG_IDC_DEV_ID_MASK; +} + +#if STM32MP13 +void stm32mp1_syscfg_boot_mode_enable(void) +{ + mmio_setbits_32(SYSCFG_BASE + SYSCFG_BOOTCR, SYSCFG_BOOTCR_BMEN); +} + +void stm32mp1_syscfg_boot_mode_disable(void) +{ + mmio_clrbits_32(SYSCFG_BASE + SYSCFG_BOOTCR, SYSCFG_BOOTCR_BMEN); +} +#endif diff --git a/plat/st/stm32mp1/stm32mp1_tbb_cert.c b/plat/st/stm32mp1/stm32mp1_tbb_cert.c new file mode 100644 index 0000000..0e77397 --- /dev/null +++ b/plat/st/stm32mp1/stm32mp1_tbb_cert.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "tbbr/tbb_ext.h" +#include "tbbr/tbb_key.h" + +#include "tbbr/stm32mp1_tbb_cert.h" + +/* + * Certificates used in the chain of trust + * + * The order of the certificates must follow the enumeration specified in + * stm32mp1_tbb_cert.h. All certificates are self-signed, so the issuer certificate + * field points to itself. + */ +static cert_t stm32mp1_tbb_certs[] = { + [0] = { + .id = STM32MP_CONFIG_CERT, + .opt = "stm32mp-cfg-cert", + .help_msg = "STM32MP Config Certificate (output file)", + .fn = NULL, + .cn = "STM32MP config FW Certificate", + .key = ROT_KEY, + .issuer = STM32MP_CONFIG_CERT, + .ext = { + TRUSTED_FW_NVCOUNTER_EXT, + HW_CONFIG_HASH_EXT, + FW_CONFIG_HASH_EXT + }, + .num_ext = 3 + }, +}; + +PLAT_REGISTER_COT(stm32mp1_tbb_certs); diff --git a/plat/st/stm32mp1/stm32mp1_topology.c b/plat/st/stm32mp1/stm32mp1_topology.c new file mode 100644 index 0000000..59a0c17 --- /dev/null +++ b/plat/st/stm32mp1/stm32mp1_topology.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <platform_def.h> + +#include <lib/psci/psci.h> +#include <plat/common/platform.h> + +/* 1 cluster, all cores into */ +static const unsigned char stm32mp1_power_domain_tree_desc[] = { + PLATFORM_CLUSTER_COUNT, + PLATFORM_CORE_COUNT, +}; + +/* This function returns the platform topology */ +const unsigned char *plat_get_power_domain_tree_desc(void) +{ + return stm32mp1_power_domain_tree_desc; +} + +/******************************************************************************* + * This function implements a part of the critical interface between the psci + * generic layer and the platform that allows the former to query the platform + * to convert an MPIDR to a unique linear index. An error code (-1) is returned + * in case the MPIDR is invalid. + ******************************************************************************/ +int plat_core_pos_by_mpidr(u_register_t mpidr) +{ + unsigned int cluster_id, cpu_id; + u_register_t mpidr_copy = mpidr; + + mpidr_copy &= MPIDR_AFFINITY_MASK; + + if ((mpidr_copy & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)) != 0U) { + return -1; + } + + cluster_id = (mpidr_copy >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK; + cpu_id = (mpidr_copy >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK; + + if (cluster_id >= PLATFORM_CLUSTER_COUNT) { + return -1; + } + + /* + * Validate cpu_id by checking whether it represents a CPU in one + * of the two clusters present on the platform. + */ + if (cpu_id >= PLATFORM_CORE_COUNT) { + return -1; + } + + return (int)cpu_id; +} diff --git a/plat/st/stm32mp1/stm32mp1_usb_dfu.c b/plat/st/stm32mp1/stm32mp1_usb_dfu.c new file mode 100644 index 0000000..0fe2d24 --- /dev/null +++ b/plat/st/stm32mp1/stm32mp1_usb_dfu.c @@ -0,0 +1,423 @@ +/* + * Copyright (c) 2021-2022, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <limits.h> +#include <string.h> + +#include <common/debug.h> +#include <drivers/st/bsec.h> +#include <drivers/st/stm32mp1_usb.h> +#include <drivers/usb_device.h> + +#include <platform_def.h> +#include <stm32cubeprogrammer.h> +#include <stm32mp_common.h> +#include <usb_dfu.h> + +/* String size (1 byte) + type (1 byte) + 24 UTF16 characters: 2 bytes each */ +#define SIZ_STRING_SERIAL U(24) +#define USB_SIZ_STRING_SERIAL (1U + 1U + (SIZ_STRING_SERIAL * 2U)) +#define USBD_MAX_STR_DESC_SIZ 0x100 +#define USBD_VID 0x0483 +#define USBD_PID 0xDF11 +#define USBD_LANGID_STRING 0x409 +#define USBD_MANUFACTURER_STRING "STMicroelectronics" +#define USBD_CONFIGURATION_STRING "DFU Config" +#define USBD_INTERFACE_STRING "DFU Interface" + +#if STM32MP13 +#define USB_DFU_ITF_NUM 2 +#endif +#if STM32MP15 +#define USB_DFU_ITF_NUM 6 +#endif + +#define USB_DFU_CONFIG_DESC_SIZ USB_DFU_DESC_SIZ(USB_DFU_ITF_NUM) + +/* DFU devices */ +static struct usb_dfu_handle usb_dfu_handle; + +/* USB Standard Device Descriptor */ +static const uint8_t usb_stm32mp1_desc[USB_LEN_DEV_DESC] = { + USB_LEN_DEV_DESC, /* bLength */ + USB_DESC_TYPE_DEVICE, /* bDescriptorType */ + 0x00, /* bcdUSB */ + 0x02, /* version */ + 0x00, /* bDeviceClass */ + 0x00, /* bDeviceSubClass */ + 0x00, /* bDeviceProtocol */ + USB_MAX_EP0_SIZE, /* bMaxPacketSize */ + LOBYTE(USBD_VID), /* idVendor */ + HIBYTE(USBD_VID), /* idVendor */ + LOBYTE(USBD_PID), /* idVendor */ + HIBYTE(USBD_PID), /* idVendor */ + 0x00, /* bcdDevice rel. 2.00 */ + 0x02, + USBD_IDX_MFC_STR, /* Index of manufacturer string */ + USBD_IDX_PRODUCT_STR, /* Index of product string */ + USBD_IDX_SERIAL_STR, /* Index of serial number string */ + USBD_MAX_NUM_CONFIGURATION /* bNumConfigurations */ +}; /* USB_DeviceDescriptor */ + +/* USB Standard String Descriptor */ +static const uint8_t usb_stm32mp1_lang_id_desc[USB_LEN_LANGID_STR_DESC] = { + USB_LEN_LANGID_STR_DESC, + USB_DESC_TYPE_STRING, + LOBYTE(USBD_LANGID_STRING), + HIBYTE(USBD_LANGID_STRING), +}; + +/* USB Standard Device Descriptor */ +static const uint8_t +usbd_stm32mp1_qualifier_desc[USB_LEN_DEV_QUALIFIER_DESC] = { + USB_LEN_DEV_QUALIFIER_DESC, + USB_DESC_TYPE_DEVICE_QUALIFIER, + 0x00, + 0x02, + 0x00, + 0x00, + 0x00, + 0x40, + 0x01, + 0x00, +}; + +/* USB serial number: build dynamically */ +static uint8_t usb_stm32mp1_serial[USB_SIZ_STRING_SERIAL + 1]; + +/* USB DFU device Configuration Descriptor */ +static const uint8_t usb_stm32mp1_config_desc[USB_DFU_CONFIG_DESC_SIZ] = { + 0x09, /* bLength: Configuration Descriptor size */ + USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */ + USB_DFU_CONFIG_DESC_SIZ, /* wTotalLength: Bytes returned */ + 0x00, + 0x01, /* bNumInterfaces: 1 interface */ + 0x01, /* bConfigurationValue: Configuration value */ + 0x02, /* iConfiguration: Index of string descriptor for configuration */ + 0xC0, /* bmAttributes: bus powered and Supprts Remote Wakeup */ + 0x32, /* MaxPower 100 mA: this current is used for detecting Vbus */ + + /* Descriptor of DFU interface 0 Alternate setting 0..N */ + USBD_DFU_IF_DESC(0), + USBD_DFU_IF_DESC(1), +#if USB_DFU_ITF_NUM > 2 + USBD_DFU_IF_DESC(2), +#endif +#if USB_DFU_ITF_NUM > 3 + USBD_DFU_IF_DESC(3), +#endif +#if USB_DFU_ITF_NUM > 4 + USBD_DFU_IF_DESC(4), +#endif +#if USB_DFU_ITF_NUM > 5 + USBD_DFU_IF_DESC(5), +#endif + /* DFU Functional Descriptor */ + 0x09, /* blength = 9 Bytes */ + DFU_DESCRIPTOR_TYPE, /* DFU Functional Descriptor */ + DFU_BM_ATTRIBUTE, /* bmAttribute for DFU */ + 0xFF, /* DetachTimeOut = 255 ms */ + 0x00, + TRANSFER_SIZE_BYTES(USBD_DFU_XFER_SIZE), /* TransferSize = 1024 Byte */ + ((USB_DFU_VERSION >> 0) & 0xFF), /* bcdDFUVersion */ + ((USB_DFU_VERSION >> 8) & 0xFF) +}; + +/* The user strings: one by alternate as defined in USBD_DFU_IF_DESC */ +#if STM32MP13 +const char *const if_desc_string[USB_DFU_ITF_NUM] = { + "@SSBL /0x03/1*16Me", + "@virtual /0xF1/1*512Ba" +}; +#endif +#if STM32MP15 +const char *const if_desc_string[USB_DFU_ITF_NUM] = { + "@Partition0 /0x00/1*256Ke", + "@FSBL /0x01/1*1Me", + "@Partition2 /0x02/1*1Me", + "@Partition3 /0x03/1*16Me", + "@Partition4 /0x04/1*16Me", + "@virtual /0xF1/1*512Ba" +}; +#endif + +/* Buffer to build the unicode string provided to USB device stack */ +static uint8_t usb_str_dec[USBD_MAX_STR_DESC_SIZ]; + +/* + * Convert Ascii string into unicode one + * desc : descriptor buffer + * unicode : Formatted string buffer (unicode) + * len : descriptor length + */ +static void stm32mp1_get_string(const char *desc, uint8_t *unicode, uint16_t *len) +{ + uint8_t idx = 0U; + + if (desc == NULL) { + return; + } + + *len = strlen(desc) * 2U + 2U; + unicode[idx++] = *len; + unicode[idx++] = USB_DESC_TYPE_STRING; + + while (*desc != '\0') { + unicode[idx++] = *desc++; + unicode[idx++] = 0x00U; + } +} + +/* + * Create the serial number string descriptor + */ +static void update_serial_num_string(void) +{ + uint8_t i; + char serial_string[SIZ_STRING_SERIAL + 2U]; + /* serial number is set to 0 */ + uint32_t deviceserial[UID_WORD_NB] = {0U, 0U, 0U}; + uint32_t otp; + uint32_t len; + uint16_t length; + + if (stm32_get_otp_index(UID_OTP, &otp, &len) != 0) { + ERROR("BSEC: Get UID_OTP number Error\n"); + return; + } + + 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 */ + snprintf(serial_string, sizeof(serial_string), "%08X%08X%08X", + deviceserial[0], deviceserial[1], deviceserial[2]); + + length = USB_SIZ_STRING_SERIAL; + stm32mp1_get_string(serial_string, usb_stm32mp1_serial, &length); +} + +/* + * Return Device Qualifier descriptor + * length : pointer data length + * return : pointer to descriptor buffer + */ +static uint8_t *stm32mp1_get_qualifier_desc(uint16_t *length) +{ + *length = sizeof(usbd_stm32mp1_qualifier_desc); + + return (uint8_t *)usbd_stm32mp1_qualifier_desc; +} + +/* + * Return configuration descriptor + * length : pointer data length + * return : pointer to descriptor buffer + */ +static uint8_t *stm32mp1_get_config_desc(uint16_t *length) +{ + *length = sizeof(usb_stm32mp1_config_desc); + + return (uint8_t *)usb_stm32mp1_config_desc; +} + +/* + * Returns the device descriptor. + * length: Pointer to data length variable + * return : Pointer to descriptor buffer + */ +static uint8_t *stm32mp1_device_desc(uint16_t *length) +{ + *length = sizeof(usb_stm32mp1_desc); + + return (uint8_t *)usb_stm32mp1_desc; +} + +/* + * Returns the LangID string descriptor. + * length: Pointer to data length variable + * return : Pointer to descriptor buffer + */ +static uint8_t *stm32mp1_lang_id_desc(uint16_t *length) +{ + *length = sizeof(usb_stm32mp1_lang_id_desc); + + return (uint8_t *)usb_stm32mp1_lang_id_desc; +} + +/* + * Returns the product string descriptor. + * length: Pointer to data length variable + * return : Pointer to descriptor buffer + */ +static uint8_t *stm32mp1_product_desc(uint16_t *length) +{ + char name[STM32_SOC_NAME_SIZE]; + char product[128]; + uint32_t chip_id; + uint32_t chip_version; + + stm32mp_get_soc_name(name); + chip_id = stm32mp_get_chip_dev_id(); + chip_version = stm32mp_get_chip_version(); + + snprintf(product, sizeof(product), + "DFU @Device ID /0x%03X, @Revision ID /0x%04X, @Name /%s,", + chip_id, chip_version, name); + + stm32mp1_get_string(product, usb_str_dec, length); + + return usb_str_dec; +} + +/* + * Returns the manufacturer string descriptor. + * length: Pointer to data length variable + * return : Pointer to descriptor buffer + */ +static uint8_t *stm32mp1_manufacturer_desc(uint16_t *length) +{ + stm32mp1_get_string(USBD_MANUFACTURER_STRING, usb_str_dec, length); + + return usb_str_dec; +} + +/* + * Returns the serial number string descriptor. + * length: Pointer to data length variable + * return : Pointer to descriptor buffer + */ +static uint8_t *stm32mp1_serial_desc(uint16_t *length) +{ + *length = USB_SIZ_STRING_SERIAL; + + return (uint8_t *)usb_stm32mp1_serial; +} + +/* + * Returns the configuration string descriptor. + * length: Pointer to data length variable + * return : Pointer to descriptor buffer + */ +static uint8_t *stm32mp1_config_desc(uint16_t *length) +{ + stm32mp1_get_string(USBD_CONFIGURATION_STRING, usb_str_dec, length); + + return usb_str_dec; +} + +/* + * Returns the interface string descriptor. + * length : Pointer to data length variable + * return : Pointer to descriptor buffer + */ +static uint8_t *stm32mp1_interface_desc(uint16_t *length) +{ + stm32mp1_get_string(USBD_INTERFACE_STRING, usb_str_dec, length); + + return usb_str_dec; +} + +/* + * Manages the transfer of memory interfaces string descriptors. + * index: descriptor index + * length : pointer data length + * return : pointer to the descriptor table or NULL if the descriptor + * is not supported. + */ +static uint8_t *stm32mp1_get_usr_desc(uint8_t index, uint16_t *length) +{ + if (index >= ARRAY_SIZE(if_desc_string)) { + return NULL; + } + + stm32mp1_get_string(if_desc_string[index], usb_str_dec, length); + + return usb_str_dec; +} + +static const struct usb_desc dfu_desc = { + .get_device_desc = stm32mp1_device_desc, + .get_lang_id_desc = stm32mp1_lang_id_desc, + .get_manufacturer_desc = stm32mp1_manufacturer_desc, + .get_product_desc = stm32mp1_product_desc, + .get_configuration_desc = stm32mp1_config_desc, + .get_serial_desc = stm32mp1_serial_desc, + .get_interface_desc = stm32mp1_interface_desc, + .get_usr_desc = stm32mp1_get_usr_desc, + .get_config_desc = stm32mp1_get_config_desc, + .get_device_qualifier_desc = stm32mp1_get_qualifier_desc, + /* only HS is supported, as ROM code */ + .get_other_speed_config_desc = NULL, +}; + +static struct usb_handle usb_core_handle; +static struct pcd_handle pcd_handle; + +struct usb_handle *usb_dfu_plat_init(void) +{ + /* Prepare USB Driver */ + pcd_handle.in_ep[0].maxpacket = USB_MAX_EP0_SIZE; + pcd_handle.out_ep[0].maxpacket = USB_MAX_EP0_SIZE; + stm32mp1_usb_init_driver(&usb_core_handle, &pcd_handle, + (uint32_t *)USB_OTG_BASE); + +#if STM32MP15 + /* STM32MP15 = keep the configuration from ROM code */ + usb_core_handle.ep0_state = USBD_EP0_DATA_IN; + usb_core_handle.dev_state = USBD_STATE_CONFIGURED; +#endif + + /* Update the serial number string descriptor from the unique ID */ + update_serial_num_string(); + + /* Prepare USB DFU stack */ + usb_dfu_register(&usb_core_handle, &usb_dfu_handle); + + /* Register DFU descriptor in USB stack */ + register_platform(&usb_core_handle, &dfu_desc); + + return &usb_core_handle; +} + +/* Link between USB alternate and STM32CubeProgramer phase */ +uint8_t usb_dfu_get_phase(uint8_t alt) +{ + uint8_t ret; + + switch (alt) { +#if STM32MP13 + case 0: + ret = PHASE_SSBL; + break; + case 1: + ret = PHASE_CMD; + break; +#endif +#if STM32MP15 + case 3: + ret = PHASE_SSBL; + break; + case 5: + ret = PHASE_CMD; + break; +#endif + default: + ret = PHASE_RESET; + break; + } + + return ret; +} |