From 84a856108aaf180a2cfda252a9b952b55062442e Mon Sep 17 00:00:00 2001 From: Christophe Priouzeau Date: Tue, 27 Oct 2020 11:48:20 +0100 Subject: [PATCH 07/10] ARM-v2020.01-stm32mp-r2-MACHINE --- Makefile | 2 +- arch/arm/Kconfig | 28 ++++++++++ arch/arm/include/asm/iproc-common/configs.h | 1 - arch/arm/include/asm/system.h | 11 ++++ arch/arm/lib/cache-cp15.c | 29 +++++++--- arch/arm/lib/cache.c | 13 +++-- arch/arm/mach-stm32mp/Kconfig | 13 +++++ .../mach-stm32mp/cmd_stm32prog/stm32prog.c | 2 +- arch/arm/mach-stm32mp/cpu.c | 53 ++++++++++++++++--- arch/arm/mach-stm32mp/fdt.c | 14 +++-- .../mach-stm32mp/include/mach/stm32mp1_smc.h | 48 ++++++++++++----- .../arm/mach-stm32mp/include/mach/sys_proto.h | 2 + arch/arm/mach-stm32mp/spl.c | 20 +++++++ 13 files changed, 197 insertions(+), 39 deletions(-) diff --git a/Makefile b/Makefile index 8b390bc5a3..64b0560af5 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ VERSION = 2020 PATCHLEVEL = 01 SUBLEVEL = -EXTRAVERSION = -stm32mp-r1 +EXTRAVERSION = -stm32mp-r2 NAME = # *DOCUMENTATION* diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 36c9c2fecd..f04c37c88c 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -329,6 +329,34 @@ config SYS_CACHELINE_SIZE default 64 if SYS_CACHE_SHIFT_6 default 32 if SYS_CACHE_SHIFT_5 +choice + prompt "Select the ARM data write cache policy" + default SYS_ARM_CACHE_WRITETHROUGH if TARGET_BCMCYGNUS || \ + TARGET_BCMNSP || CPU_PXA || RZA1 + default SYS_ARM_CACHE_WRITEBACK + +config SYS_ARM_CACHE_WRITEBACK + bool "Write-back (WB)" + help + A write updates the cache only and marks the cache line as dirty. + External memory is updated only when the line is evicted or explicitly + cleaned. + +config SYS_ARM_CACHE_WRITETHROUGH + bool "Write-through (WT)" + help + A write updates both the cache and the external memory system. + This does not mark the cache line as dirty. + +config SYS_ARM_CACHE_WRITEALLOC + bool "Write allocation (WA)" + help + A cache line is allocated on a write miss. This means that executing a + store instruction on the processor might cause a burst read to occur. + There is a linefill to obtain the data for the cache line, before the + write is performed. +endchoice + config ARCH_CPU_INIT bool "Enable ARCH_CPU_INIT" help diff --git a/arch/arm/include/asm/iproc-common/configs.h b/arch/arm/include/asm/iproc-common/configs.h index 96c4f54f4a..4733c0793c 100644 --- a/arch/arm/include/asm/iproc-common/configs.h +++ b/arch/arm/include/asm/iproc-common/configs.h @@ -10,7 +10,6 @@ /* Architecture, CPU, chip, etc */ #define CONFIG_IPROC -#define CONFIG_SYS_ARM_CACHE_WRITETHROUGH /* Memory Info */ #define CONFIG_SYS_SDRAM_BASE 0x61000000 diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h index a1a5e35ef6..9fd3b321fc 100644 --- a/arch/arm/include/asm/system.h +++ b/arch/arm/include/asm/system.h @@ -447,6 +447,7 @@ static inline void set_dacr(unsigned int val) /* options available for data cache on each page */ enum dcache_option { + INVALID_ENTRY = 0, DCACHE_OFF = TTB_SECT | TTB_SECT_MAIR(0) | TTB_SECT_XN_MASK, DCACHE_WRITETHROUGH = TTB_SECT | TTB_SECT_MAIR(1), DCACHE_WRITEBACK = TTB_SECT | TTB_SECT_MAIR(2), @@ -468,6 +469,7 @@ enum dcache_option { /* options available for data cache on each page */ enum dcache_option { + INVALID_ENTRY = 0, DCACHE_OFF = TTB_SECT_DOMAIN(0) | TTB_SECT_XN_MASK | TTB_SECT, DCACHE_WRITETHROUGH = DCACHE_OFF | TTB_SECT_C_MASK, DCACHE_WRITEBACK = DCACHE_WRITETHROUGH | TTB_SECT_B_MASK, @@ -477,6 +479,7 @@ enum dcache_option { #define TTB_SECT_AP (3 << 10) /* options available for data cache on each page */ enum dcache_option { + INVALID_ENTRY = 0, DCACHE_OFF = 0x12, DCACHE_WRITETHROUGH = 0x1a, DCACHE_WRITEBACK = 0x1e, @@ -484,6 +487,14 @@ enum dcache_option { }; #endif +#if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH) +#define DCACHE_DEFAULT_OPTION DCACHE_WRITETHROUGH +#elif defined(CONFIG_SYS_ARM_CACHE_WRITEALLOC) +#define DCACHE_DEFAULT_OPTION DCACHE_WRITEALLOC +#elif defined(CONFIG_SYS_ARM_CACHE_WRITEBACK) +#define DCACHE_DEFAULT_OPTION DCACHE_WRITEBACK +#endif + /* Size of an MMU section */ enum { #ifdef CONFIG_ARMV7_LPAE diff --git a/arch/arm/lib/cache-cp15.c b/arch/arm/lib/cache-cp15.c index f8d20960da..16067cf8da 100644 --- a/arch/arm/lib/cache-cp15.c +++ b/arch/arm/lib/cache-cp15.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -61,8 +62,11 @@ void mmu_set_region_dcache_behaviour(phys_addr_t start, size_t size, unsigned long startpt, stoppt; unsigned long upto, end; - end = ALIGN(start + size, MMU_SECTION_SIZE) >> MMU_SECTION_SHIFT; + /* div by 2 before start + size to avoid phys_addr_t overflow */ + end = ALIGN((start / 2) + (size / 2), MMU_SECTION_SIZE / 2) + >> (MMU_SECTION_SHIFT - 1); start = start >> MMU_SECTION_SHIFT; + #ifdef CONFIG_ARMV7_LPAE debug("%s: start=%pa, size=%zu, option=%llx\n", __func__, &start, size, option); @@ -89,20 +93,29 @@ void mmu_set_region_dcache_behaviour(phys_addr_t start, size_t size, __weak void dram_bank_mmu_setup(int bank) { bd_t *bd = gd->bd; + struct lmb lmb; int i; + /* bd->bi_dram is available only after relocation */ + if ((gd->flags & GD_FLG_RELOC) == 0) + return; + + /* + * don't allow cache on reserved memory tagged 'no-map' in DT + * => avoid speculative access to "secure" data + */ + lmb_init_and_reserve(&lmb, bd, (void *)gd->fdt_blob); + debug("%s: bank: %d\n", __func__, bank); for (i = bd->bi_dram[bank].start >> MMU_SECTION_SHIFT; i < (bd->bi_dram[bank].start >> MMU_SECTION_SHIFT) + (bd->bi_dram[bank].size >> MMU_SECTION_SHIFT); i++) { -#if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH) - set_section_dcache(i, DCACHE_WRITETHROUGH); -#elif defined(CONFIG_SYS_ARM_CACHE_WRITEALLOC) - set_section_dcache(i, DCACHE_WRITEALLOC); -#else - set_section_dcache(i, DCACHE_WRITEBACK); -#endif + if (lmb_is_reserved_flags(&lmb, i << MMU_SECTION_SHIFT, + LMB_NOMAP)) + set_section_dcache(i, INVALID_ENTRY); + else + set_section_dcache(i, DCACHE_DEFAULT_OPTION); } } diff --git a/arch/arm/lib/cache.c b/arch/arm/lib/cache.c index 007d4ebc49..7f3cfb407c 100644 --- a/arch/arm/lib/cache.c +++ b/arch/arm/lib/cache.c @@ -73,6 +73,15 @@ static unsigned long noncached_start; static unsigned long noncached_end; static unsigned long noncached_next; +void noncached_set_region(void) +{ +#if !CONFIG_IS_ENABLED(SYS_DCACHE_OFF) + mmu_set_region_dcache_behaviour(noncached_start, + noncached_end - noncached_start, + DCACHE_OFF); +#endif +} + void noncached_init(void) { phys_addr_t start, end; @@ -89,9 +98,7 @@ void noncached_init(void) noncached_end = end; noncached_next = start; -#if !CONFIG_IS_ENABLED(SYS_DCACHE_OFF) - mmu_set_region_dcache_behaviour(noncached_start, size, DCACHE_OFF); -#endif + noncached_set_region(); } phys_addr_t noncached_alloc(size_t size, size_t align) diff --git a/arch/arm/mach-stm32mp/Kconfig b/arch/arm/mach-stm32mp/Kconfig index f9f79437e4..c24717d36d 100644 --- a/arch/arm/mach-stm32mp/Kconfig +++ b/arch/arm/mach-stm32mp/Kconfig @@ -103,6 +103,19 @@ config SYS_TEXT_BASE config NR_DRAM_BANKS default 1 +config DDR_CACHEABLE_SIZE + hex "Size of the DDR marked cacheable in pre-reloc stage" + default 0x10000000 if TFABOOT + default 0x40000000 + help + Define the size of the DDR marked as cacheable in U-Boot + pre-reloc stage. + This option can be useful to avoid speculatif access + to secured area of DDR used by TF-A or OP-TEE before U-Boot + initialization. + The areas marked "no-map" in device tree should be located + before this limit: STM32_DDR_BASE + DDR_CACHEABLE_SIZE. + config SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION_MMC2 hex "Partition on MMC2 to use to load U-Boot from" depends on SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c index f2f9ed9f36..531df60404 100644 --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c @@ -560,7 +560,7 @@ static int init_device(struct stm32prog_data *data, #ifdef CONFIG_MMC case STM32PROG_MMC: mmc = find_mmc_device(dev->dev_id); - if (mmc_init(mmc)) { + if (!mmc || mmc_init(mmc)) { stm32prog_err("mmc device %d not found", dev->dev_id); return -ENODEV; } diff --git a/arch/arm/mach-stm32mp/cpu.c b/arch/arm/mach-stm32mp/cpu.c index 305534f2ba..aee0f2bf81 100644 --- a/arch/arm/mach-stm32mp/cpu.c +++ b/arch/arm/mach-stm32mp/cpu.c @@ -76,6 +76,12 @@ #define PKG_SHIFT 27 #define PKG_MASK GENMASK(2, 0) +/* + * early TLB into the .data section so that it not get cleared + * with 16kB allignment (see TTBR0_BASE_ADDR_MASK) + */ +u8 early_tlb[PGTABLE_SIZE] __section(".data") __aligned(0x4000); + #if !defined(CONFIG_SPL) || defined(CONFIG_SPL_BUILD) #ifndef CONFIG_STM32MP1_TRUSTED static void security_init(void) @@ -142,17 +148,17 @@ static void security_init(void) /* * Debug init */ -static void dbgmcu_init(void) +void dbgmcu_init(void) { - setbits_le32(RCC_DBGCFGR, RCC_DBGCFGR_DBGCKEN); - /* * Freeze IWDG2 if Cortex-A7 is in debug mode * done in TF-A for TRUSTED boot and * DBGMCU access is controlled by BSEC_DENABLE.DBGSWENABLE */ - if (!CONFIG_IS_ENABLED(STM32MP1_TRUSTED) && bsec_dbgswenable()) + if (!IS_ENABLED(CONFIG_STM32MP1_TRUSTED) && bsec_dbgswenable()) { + setbits_le32(RCC_DBGCFGR, RCC_DBGCFGR_DBGCKEN); setbits_le32(DBGMCU_APB4FZ1, DBGMCU_APB4FZ1_IWDG2); + } } #endif /* !defined(CONFIG_SPL) || defined(CONFIG_SPL_BUILD) */ @@ -192,6 +198,33 @@ u32 get_bootmode(void) TAMP_BOOT_MODE_SHIFT; } +/* + * initialize the MMU and activate cache in SPL or in U-Boot pre-reloc stage + * MMU/TLB is updated in enable_caches() for U-Boot after relocation + * or is deactivated in U-Boot entry function start.S::cpu_init_cp15 + */ +static void early_enable_caches(void) +{ + /* I-cache is already enabled in start.S: cpu_init_cp15 */ + + if (CONFIG_IS_ENABLED(SYS_DCACHE_OFF)) + return; + + gd->arch.tlb_size = PGTABLE_SIZE; + gd->arch.tlb_addr = (unsigned long)&early_tlb; + + dcache_enable(); + + if (IS_ENABLED(CONFIG_SPL_BUILD)) + mmu_set_region_dcache_behaviour(STM32_SYSRAM_BASE, + STM32_SYSRAM_SIZE, + DCACHE_DEFAULT_OPTION); + else + mmu_set_region_dcache_behaviour(STM32_DDR_BASE, + CONFIG_DDR_CACHEABLE_SIZE, + DCACHE_DEFAULT_OPTION); +} + /* * Early system init */ @@ -199,11 +232,12 @@ int arch_cpu_init(void) { u32 boot_mode; + early_enable_caches(); + /* early armv7 timer init: needed for polling */ timer_init(); #if !defined(CONFIG_SPL) || defined(CONFIG_SPL_BUILD) - dbgmcu_init(); #ifndef CONFIG_STM32MP1_TRUSTED security_init(); update_bootmode(); @@ -231,7 +265,14 @@ int arch_cpu_init(void) void enable_caches(void) { - /* Enable D-cache. I-cache is already enabled in start.S */ + /* I-cache is already enabled in start.S: icache_enable() not needed */ + + /* deactivate the data cache, early enabled in arch_cpu_init() */ + dcache_disable(); + /* + * update MMU after relocation and enable the data cache + * warning: the TLB location udpated in board_f.c::reserve_mmu + */ dcache_enable(); } diff --git a/arch/arm/mach-stm32mp/fdt.c b/arch/arm/mach-stm32mp/fdt.c index 21b5f09728..8d9a58186d 100644 --- a/arch/arm/mach-stm32mp/fdt.c +++ b/arch/arm/mach-stm32mp/fdt.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause /* - * Copyright (C) 2019, STMicroelectronics - All Rights Reserved + * Copyright (C) 2019-2020, STMicroelectronics - All Rights Reserved */ #include @@ -223,19 +223,23 @@ static void stm32_fdt_disable_optee(void *blob) { int off, node; + /* Delete "optee" firmware node */ off = fdt_node_offset_by_compatible(blob, -1, "linaro,optee-tz"); if (off >= 0 && fdtdec_get_is_enabled(blob, off)) - fdt_status_disabled(blob, off); + fdt_del_node(blob, off); - /* Disabled "optee@..." reserved-memory node */ + /* Delete "optee@..." reserved-memory node */ off = fdt_path_offset(blob, "/reserved-memory/"); if (off < 0) return; for (node = fdt_first_subnode(blob, off); node >= 0; node = fdt_next_subnode(blob, node)) { - if (!strncmp(fdt_get_name(blob, node, NULL), "optee@", 6)) - fdt_status_disabled(blob, node); + if (strncmp(fdt_get_name(blob, node, NULL), "optee@", 6)) + continue; + + if (fdt_del_node(blob, node)) + printf("Failed to remove optee reserved-memory node\n"); } } diff --git a/arch/arm/mach-stm32mp/include/mach/stm32mp1_smc.h b/arch/arm/mach-stm32mp/include/mach/stm32mp1_smc.h index dea5b4a6b4..d72747ca31 100644 --- a/arch/arm/mach-stm32mp/include/mach/stm32mp1_smc.h +++ b/arch/arm/mach-stm32mp/include/mach/stm32mp1_smc.h @@ -8,27 +8,53 @@ #include +/* SMC service generic return codes */ +#define STM32_SMC_OK 0x00000000U +#define STM32_SMC_NOT_SUPPORTED 0xFFFFFFFFU +#define STM32_SMC_FAILED 0xFFFFFFFEU +#define STM32_SMC_INVALID_PARAMS 0xFFFFFFFDU + /* - * SMC function IDs for STM32 Service queries + * 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) - * http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html + * for SiP (silicon Partner). + * https://developer.arm.com/docs/den0028/latest */ -#define STM32_SMC_VERSION 0x82000000 /* Secure Service access from Non-secure */ -#define STM32_SMC_RCC 0x82001000 + +/* + * SMC function STM32_SMC_PWR. + * + * Argument a0: (input) SMCC ID. + * (output) Status return code. + * Argument a1: (input) Service ID (STM32_SMC_REG_xxx). + * Argument a2: (input) Register offset or physical address. + * (output) Register read value, if applicable. + * Argument a3: (input) Register target value if applicable. + */ #define STM32_SMC_PWR 0x82001001 -#define STM32_SMC_RTC 0x82001002 + +/* + * SMC functions STM32_SMC_BSEC. + * + * Argument a0: (input) SMCC ID. + * (output) Status return code. + * Argument a1: (input) Service ID (STM32_SMC_READ_xxx/_PROG_xxx/_WRITE_xxx). + * (output) OTP read value, if applicable. + * Argument a2: (input) OTP index. + * Argument a3: (input) OTP value if applicable. + */ #define STM32_SMC_BSEC 0x82001003 -/* Register access service use for RCC/RTC/PWR */ +/* Service ID for STM32_SMC_PWR */ +#define STM32_SMC_REG_READ 0x0 #define STM32_SMC_REG_WRITE 0x1 #define STM32_SMC_REG_SET 0x2 #define STM32_SMC_REG_CLEAR 0x3 -/* Service for BSEC */ +/* Service ID for STM32_SMC_BSEC */ #define STM32_SMC_READ_SHADOW 0x01 #define STM32_SMC_PROG_OTP 0x02 #define STM32_SMC_WRITE_SHADOW 0x03 @@ -37,12 +63,6 @@ #define STM32_SMC_WRITE_ALL 0x06 #define STM32_SMC_WRLOCK_OTP 0x07 -/* SMC error codes */ -#define STM32_SMC_OK 0x0 -#define STM32_SMC_NOT_SUPPORTED -1 -#define STM32_SMC_FAILED -2 -#define STM32_SMC_INVALID_PARAMS -3 - #define stm32_smc_exec(svc, op, data1, data2) \ stm32_smc(svc, op, data1, data2, NULL) diff --git a/arch/arm/mach-stm32mp/include/mach/sys_proto.h b/arch/arm/mach-stm32mp/include/mach/sys_proto.h index b6ad3c67ae..c5cab9f21b 100644 --- a/arch/arm/mach-stm32mp/include/mach/sys_proto.h +++ b/arch/arm/mach-stm32mp/include/mach/sys_proto.h @@ -52,3 +52,5 @@ int setup_mac_address(void); /* board power management : configure vddcore according OPP */ void board_vddcore_init(u32 voltage_mv); int board_vddcore_set(void); + +void dbgmcu_init(void); diff --git a/arch/arm/mach-stm32mp/spl.c b/arch/arm/mach-stm32mp/spl.c index f4b4c3bd82..41f3fd4b7c 100644 --- a/arch/arm/mach-stm32mp/spl.c +++ b/arch/arm/mach-stm32mp/spl.c @@ -4,6 +4,7 @@ */ #include +#include #include #include #include @@ -123,4 +124,23 @@ void board_init_f(ulong dummy) printf("DRAM init failed: %d\n", ret); hang(); } + + /* + * activate cache on DDR only when DDR is fully initialized + * to avoid speculative access and issue in get_ram_size() + */ + if (!CONFIG_IS_ENABLED(SYS_DCACHE_OFF)) + mmu_set_region_dcache_behaviour(STM32_DDR_BASE, + CONFIG_DDR_CACHEABLE_SIZE, + DCACHE_DEFAULT_OPTION); +} + +void spl_board_prepare_for_boot(void) +{ + dcache_disable(); +} + +void spl_board_prepare_for_boot_linux(void) +{ + dcache_disable(); } -- 2.17.1