diff options
Diffstat (limited to 'arch/arm/mach-imx/atf.c')
-rw-r--r-- | arch/arm/mach-imx/atf.c | 333 |
1 files changed, 287 insertions, 46 deletions
diff --git a/arch/arm/mach-imx/atf.c b/arch/arm/mach-imx/atf.c index 5301c0fbe8..8b80460268 100644 --- a/arch/arm/mach-imx/atf.c +++ b/arch/arm/mach-imx/atf.c @@ -3,11 +3,19 @@ #include <asm/sections.h> #include <common.h> #include <firmware.h> -#include <mach/atf.h> -#include <mach/generic.h> -#include <mach/xload.h> -#include <mach/romapi.h> +#include <mach/imx/atf.h> +#include <mach/imx/generic.h> +#include <mach/imx/xload.h> +#include <mach/imx/romapi.h> +#include <mach/imx/esdctl.h> +#include <asm-generic/memory_layout.h> +#include <asm/barebox-arm.h> +#include <mach/imx/imx8m-regs.h> +#include <mach/imx/imx9-regs.h> #include <soc/fsl/fsl_udc.h> +#include <soc/fsl/caam.h> +#include <tee/optee.h> +#include <mach/imx/ele.h> /** * imx8m_atf_load_bl31 - Load ATF BL31 blob and transfer control to it @@ -19,28 +27,30 @@ * This function: * * 1. Copies built-in BL31 blob to an address i.MX8M's BL31 - * expects to be placed + * expects to be placed (TF-A v2.8+ is position-independent) * * 2. Sets up temporary stack pointer for EL2, which is execution * level that BL31 will drop us off at after it completes its * initialization routine * * 3. Transfers control to BL31 - * - * NOTE: This function expects NXP's implementation of ATF that can be - * found at: - * https://source.codeaurora.org/external/imx/imx-atf - * - * any other implementation may or may not work - * */ static __noreturn void imx8m_atf_start_bl31(const void *fw, size_t fw_size, void *atf_dest) { void __noreturn (*bl31)(void) = atf_dest; + int ret; BUG_ON(fw_size > MX8M_ATF_BL31_SIZE_LIMIT); + if (IS_ENABLED(CONFIG_FSL_CAAM_RNG_PBL_INIT)) { + ret = imx_early_caam_init(MX8M_CAAM_BASE_ADDR); + if (ret) + pr_debug("CAAM early init failed: %d\n", ret); + else + pr_debug("CAAM early init successful\n"); + } + memcpy(bl31, fw, fw_size); asm volatile("msr sp_el2, %0" : : @@ -50,26 +60,6 @@ static __noreturn void imx8m_atf_start_bl31(const void *fw, size_t fw_size, void __builtin_unreachable(); } -__noreturn void imx8mm_atf_load_bl31(const void *fw, size_t fw_size) -{ - imx8m_atf_start_bl31(fw, fw_size, (void *)MX8MM_ATF_BL31_BASE_ADDR); -} - -__noreturn void imx8mn_atf_load_bl31(const void *fw, size_t fw_size) -{ - imx8m_atf_start_bl31(fw, fw_size, (void *)MX8MN_ATF_BL31_BASE_ADDR); -} - -__noreturn void imx8mp_atf_load_bl31(const void *fw, size_t fw_size) -{ - imx8m_atf_start_bl31(fw, fw_size, (void *)MX8MP_ATF_BL31_BASE_ADDR); -} - -__noreturn void imx8mq_atf_load_bl31(const void *fw, size_t fw_size) -{ - imx8m_atf_start_bl31(fw, fw_size, (void *)MX8MQ_ATF_BL31_BASE_ADDR); -} - void imx8mm_load_bl33(void *bl33) { enum bootsource src; @@ -78,9 +68,14 @@ void imx8mm_load_bl33(void *bl33) imx8mm_get_boot_source(&src, &instance); switch (src) { case BOOTSOURCE_MMC: - imx8m_esdhc_load_image(instance, false); + imx8m_esdhc_load_image(instance, bl33); break; case BOOTSOURCE_SERIAL: + if (!IS_ENABLED(CONFIG_USB_GADGET_DRIVER_ARC_PBL)) { + printf("Serial bootmode not supported\n"); + break; + } + /* * Traditionally imx-usb-loader sends the PBL twice. The first * PBL is loaded to OCRAM and executed. Then the full barebox @@ -105,8 +100,11 @@ void imx8mm_load_bl33(void *bl33) } break; + case BOOTSOURCE_SPI: + imx8mm_qspi_load_image(instance, bl33); + break; default: - printf("Unhandled bootsource BOOTSOURCE_%d\n", src); + printf("Unsupported bootsource BOOTSOURCE_%d\n", src); hang(); } @@ -121,10 +119,60 @@ void imx8mm_load_bl33(void *bl33) memcpy(bl33, __image_start, barebox_pbl_size); } +static void imx_adjust_optee_memory(void **bl32, void **bl32_image, size_t *bl32_size) +{ + struct optee_header *hdr = *bl32_image; + u64 membase; + + if (optee_verify_header(hdr)) + return; + + imx_scratch_save_optee_hdr(hdr); + + membase = (u64)hdr->init_load_addr_hi << 32; + membase |= hdr->init_load_addr_lo; + + *bl32 = (void *)membase; + *bl32_size -= sizeof(*hdr); + *bl32_image += sizeof(*hdr); +} + __noreturn void imx8mm_load_and_start_image_via_tfa(void) { - imx8mm_load_bl33((void *)MX8M_ATF_BL33_BASE_ADDR); - imx8mm_load_and_start_tfa(imx8mm_bl31_bin); + __imx8mm_load_and_start_image_via_tfa((void *)MX8M_ATF_BL33_BASE_ADDR); +} + +__noreturn void __imx8mm_load_and_start_image_via_tfa(void *bl33) +{ + const void *bl31; + size_t bl31_size; + unsigned long endmem = MX8M_DDR_CSD1_BASE_ADDR + imx8m_barebox_earlymem_size(32); + + imx_set_cpu_type(IMX_CPU_IMX8MM); + imx8mm_init_scratch_space(); + imx8m_save_bootrom_log(); + imx8mm_load_bl33(bl33); + + if (IS_ENABLED(CONFIG_FIRMWARE_IMX8MM_OPTEE)) { + void *bl32 = (void *)arm_mem_optee(endmem); + size_t bl32_size; + void *bl32_image; + + imx8m_tzc380_init(); + get_builtin_firmware_ext(imx8mm_bl32_bin, + bl33, &bl32_image, + &bl32_size); + + imx_adjust_optee_memory(&bl32, &bl32_image, &bl32_size); + + memcpy(bl32, bl32_image, bl32_size); + + get_builtin_firmware(imx8mm_bl31_bin_optee, &bl31, &bl31_size); + } else { + get_builtin_firmware(imx8mm_bl31_bin, &bl31, &bl31_size); + } + + imx8m_atf_start_bl31(bl31, bl31_size, (void *)MX8MM_ATF_BL31_BASE_ADDR); } void imx8mp_load_bl33(void *bl33) @@ -135,10 +183,13 @@ void imx8mp_load_bl33(void *bl33) imx8mp_get_boot_source(&src, &instance); switch (src) { case BOOTSOURCE_MMC: - imx8mp_esdhc_load_image(instance, false); + imx8mp_esdhc_load_image(instance, bl33); break; case BOOTSOURCE_SERIAL: - imx8mp_bootrom_load_image(); + imx8mp_romapi_load_image(bl33); + break; + case BOOTSOURCE_SPI: + imx8mp_qspi_load_image(instance, bl33); break; default: printf("Unhandled bootsource BOOTSOURCE_%d\n", src); @@ -157,12 +208,45 @@ void imx8mp_load_bl33(void *bl33) memcpy(bl33, __image_start, barebox_pbl_size); } -void imx8mp_load_and_start_image_via_tfa(void) +__noreturn void imx8mp_load_and_start_image_via_tfa(void) { - imx8mp_load_bl33((void *)MX8M_ATF_BL33_BASE_ADDR); - imx8mp_load_and_start_tfa(imx8mp_bl31_bin); + __imx8mp_load_and_start_image_via_tfa((void *)MX8M_ATF_BL33_BASE_ADDR); +} + +__noreturn void __imx8mp_load_and_start_image_via_tfa(void *bl33) +{ + const void *bl31; + size_t bl31_size; + unsigned long endmem = MX8M_DDR_CSD1_BASE_ADDR + imx8m_barebox_earlymem_size(32); + + imx_set_cpu_type(IMX_CPU_IMX8MP); + imx8mp_init_scratch_space(); + imx8m_save_bootrom_log(); + imx8mp_load_bl33(bl33); + + if (IS_ENABLED(CONFIG_FIRMWARE_IMX8MP_OPTEE)) { + void *bl32 = (void *)arm_mem_optee(endmem); + size_t bl32_size; + void *bl32_image; + + imx8m_tzc380_init(); + get_builtin_firmware_ext(imx8mp_bl32_bin, + bl33, &bl32_image, + &bl32_size); + + imx_adjust_optee_memory(&bl32, &bl32_image, &bl32_size); + + memcpy(bl32, bl32_image, bl32_size); + + get_builtin_firmware(imx8mp_bl31_bin_optee, &bl31, &bl31_size); + } else { + get_builtin_firmware(imx8mp_bl31_bin, &bl31, &bl31_size); + } + + imx8m_atf_start_bl31(bl31, bl31_size, (void *)MX8MP_ATF_BL31_BASE_ADDR); } + void imx8mn_load_bl33(void *bl33) { enum bootsource src; @@ -171,10 +255,13 @@ void imx8mn_load_bl33(void *bl33) imx8mn_get_boot_source(&src, &instance); switch (src) { case BOOTSOURCE_MMC: - imx8mn_esdhc_load_image(instance, false); + imx8mn_esdhc_load_image(instance, bl33); break; case BOOTSOURCE_SERIAL: - imx8mn_bootrom_load_image(); + imx8mn_romapi_load_image(bl33); + break; + case BOOTSOURCE_SPI: + imx8mn_qspi_load_image(instance, bl33); break; default: printf("Unhandled bootsource BOOTSOURCE_%d\n", src); @@ -193,8 +280,162 @@ void imx8mn_load_bl33(void *bl33) memcpy(bl33, __image_start, barebox_pbl_size); } -void imx8mn_load_and_start_image_via_tfa(void) +__noreturn void imx8mn_load_and_start_image_via_tfa(void) +{ + __imx8mn_load_and_start_image_via_tfa((void *)MX8M_ATF_BL33_BASE_ADDR); +} + +__noreturn void __imx8mn_load_and_start_image_via_tfa(void *bl33) { - imx8mn_load_bl33((void *)MX8M_ATF_BL33_BASE_ADDR); - imx8mn_load_and_start_tfa(imx8mn_bl31_bin); + const void *bl31; + size_t bl31_size; + unsigned long endmem = MX8M_DDR_CSD1_BASE_ADDR + imx8m_barebox_earlymem_size(16); + + imx_set_cpu_type(IMX_CPU_IMX8MN); + imx8mn_init_scratch_space(); + imx8m_save_bootrom_log(); + imx8mn_load_bl33(bl33); + + if (IS_ENABLED(CONFIG_FIRMWARE_IMX8MN_OPTEE)) { + void *bl32 = (void *)arm_mem_optee(endmem); + size_t bl32_size; + void *bl32_image; + + imx8m_tzc380_init(); + get_builtin_firmware_ext(imx8mn_bl32_bin, + bl33, &bl32_image, + &bl32_size); + + imx_adjust_optee_memory(&bl32, &bl32_image, &bl32_size); + + memcpy(bl32, bl32_image, bl32_size); + + get_builtin_firmware(imx8mn_bl31_bin_optee, &bl31, &bl31_size); + } else { + get_builtin_firmware(imx8mn_bl31_bin, &bl31, &bl31_size); + } + + imx8m_atf_start_bl31(bl31, bl31_size, (void *)MX8MN_ATF_BL31_BASE_ADDR); +} + +void imx8mq_load_bl33(void *bl33) +{ + enum bootsource src; + int instance; + + imx8mq_get_boot_source(&src, &instance); + switch (src) { + case BOOTSOURCE_MMC: + imx8m_esdhc_load_image(instance, bl33); + break; + default: + printf("Unhandled bootsource BOOTSOURCE_%d\n", src); + hang(); + } + + + /* + * On completion the TF-A will jump to MX8M_ATF_BL33_BASE_ADDR + * in EL2. Copy the image there, but replace the PBL part of + * that image with ourselves. On a high assurance boot only the + * currently running code is validated and contains the checksum + * for the piggy data, so we need to ensure that we are running + * the same code in DRAM. + */ + memcpy(bl33, __image_start, barebox_pbl_size); +} + +__noreturn void imx8mq_load_and_start_image_via_tfa(void) +{ + __imx8mq_load_and_start_image_via_tfa((void *)MX8M_ATF_BL33_BASE_ADDR); +} + +__noreturn void __imx8mq_load_and_start_image_via_tfa(void *bl33) +{ + const void *bl31; + size_t bl31_size; + unsigned long endmem = MX8M_DDR_CSD1_BASE_ADDR + imx8m_barebox_earlymem_size(32); + + imx_set_cpu_type(IMX_CPU_IMX8MQ); + imx8mq_init_scratch_space(); + imx8m_save_bootrom_log(); + imx8mq_load_bl33(bl33); + + if (IS_ENABLED(CONFIG_FIRMWARE_IMX8MQ_OPTEE)) { + void *bl32 = (void *)arm_mem_optee(endmem); + size_t bl32_size; + void *bl32_image; + + imx8m_tzc380_init(); + get_builtin_firmware_ext(imx8mq_bl32_bin, + bl33, &bl32_image, + &bl32_size); + + imx_adjust_optee_memory(&bl32, &bl32_image, &bl32_size); + + memcpy(bl32, bl32_image, bl32_size); + + get_builtin_firmware(imx8mq_bl31_bin_optee, &bl31, &bl31_size); + } else { + get_builtin_firmware(imx8mq_bl31_bin, &bl31, &bl31_size); + } + + imx8m_atf_start_bl31(bl31, bl31_size, (void *)MX8MQ_ATF_BL31_BASE_ADDR); +} + +void __noreturn imx93_load_and_start_image_via_tfa(void) +{ + unsigned long atf_dest = MX93_ATF_BL31_BASE_ADDR; + void __noreturn (*bl31)(void) = (void *)atf_dest; + const void *tfa; + size_t tfa_size; + void *bl33 = (void *)MX93_ATF_BL33_BASE_ADDR; + unsigned long endmem = MX9_DDR_CSD1_BASE_ADDR + imx9_ddrc_sdram_size(); + + imx_set_cpu_type(IMX_CPU_IMX93); + imx93_init_scratch_space(true); + + /* + * On completion the TF-A will jump to MX93_ATF_BL33_BASE_ADDR + * in EL2. Copy the image there, but replace the PBL part of + * that image with ourselves. On a high assurance boot only the + * currently running code is validated and contains the checksum + * for the piggy data, so we need to ensure that we are running + * the same code in DRAM. + * + * The second purpose of this memcpy is for USB booting. When booting + * from USB the image comes in as a stream, so the PBL is transferred + * only once. As we jump into the PBL again in SDRAM we need to copy + * it there. The USB protocol transfers data in chunks of 1024 bytes, + * so align the copy size up to the next 1KiB boundary. + */ + memcpy((void *)MX93_ATF_BL33_BASE_ADDR, __image_start, ALIGN(barebox_pbl_size, 1024)); + + if (IS_ENABLED(CONFIG_FIRMWARE_IMX93_OPTEE)) { + void *bl32 = (void *)arm_mem_optee(endmem); + size_t bl32_size; + void *bl32_image; + + imx93_ele_load_fw(bl33); + + get_builtin_firmware_ext(imx93_bl32_bin, + bl33, &bl32_image, + &bl32_size); + + imx_adjust_optee_memory(&bl32, &bl32_image, &bl32_size); + + memcpy(bl32, bl32_image, bl32_size); + + get_builtin_firmware(imx93_bl31_bin_optee, &tfa, &tfa_size); + } else { + get_builtin_firmware(imx93_bl31_bin, &tfa, &tfa_size); + } + + memcpy(bl31, tfa, tfa_size); + + asm volatile("msr sp_el2, %0" : : + "r" (MX93_ATF_BL33_BASE_ADDR - 16) : + "cc"); + bl31(); + __builtin_unreachable(); } |