diff options
author | Sandrine Bailleux <sandrine.bailleux@arm.com> | 2018-10-09 11:12:55 +0200 |
---|---|---|
committer | Sandrine Bailleux <sandrine.bailleux@arm.com> | 2018-10-10 12:34:34 +0200 |
commit | 3cd87d77947ec4fc04440268ed122b4ed81c7781 (patch) | |
tree | 78fdee12b026b931029e434f29b4fe09835fe4c9 /plat | |
download | tf-a-tests-2.0.tar.gz |
Trusted Firmware-A Tests, version 2.0v2.0
This is the first public version of the tests for the Trusted
Firmware-A project. Please see the documentation provided in the
source tree for more details.
Change-Id: I6f3452046a1351ac94a71b3525c30a4ca8db7867
Signed-off-by: Sandrine Bailleux <sandrine.bailleux@arm.com>
Co-authored-by: amobal01 <amol.balasokamble@arm.com>
Co-authored-by: Antonio Nino Diaz <antonio.ninodiaz@arm.com>
Co-authored-by: Asha R <asha.r@arm.com>
Co-authored-by: Chandni Cherukuri <chandni.cherukuri@arm.com>
Co-authored-by: David Cunado <david.cunado@arm.com>
Co-authored-by: Dimitris Papastamos <dimitris.papastamos@arm.com>
Co-authored-by: Douglas Raillard <douglas.raillard@arm.com>
Co-authored-by: dp-arm <dimitris.papastamos@arm.com>
Co-authored-by: Jeenu Viswambharan <jeenu.viswambharan@arm.com>
Co-authored-by: Jonathan Wright <jonathan.wright@arm.com>
Co-authored-by: Kévin Petit <kevin.petit@arm.com>
Co-authored-by: Roberto Vargas <roberto.vargas@arm.com>
Co-authored-by: Sathees Balya <sathees.balya@arm.com>
Co-authored-by: Shawon Roy <Shawon.Roy@arm.com>
Co-authored-by: Soby Mathew <soby.mathew@arm.com>
Co-authored-by: Thomas Abraham <thomas.abraham@arm.com>
Co-authored-by: Vikram Kanigiri <vikram.kanigiri@arm.com>
Co-authored-by: Yatharth Kochar <yatharth.kochar@arm.com>
Diffstat (limited to 'plat')
38 files changed, 3232 insertions, 0 deletions
diff --git a/plat/arm/board/fvp/aarch32/plat_helpers.S b/plat/arm/board/fvp/aarch32/plat_helpers.S new file mode 100644 index 000000000..2dcc6e9e4 --- /dev/null +++ b/plat/arm/board/fvp/aarch32/plat_helpers.S @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <asm_macros.S> +#include "../fvp_def.h" + + .globl platform_get_core_pos + +/*---------------------------------------------------------------------- + * unsigned int platform_get_core_pos(unsigned long mpid) + * + * Function to calculate the core position on FVP. + * + * (ClusterId * FVP_MAX_CPUS_PER_CLUSTER * FVP_MAX_PE_PER_CPU) + + * (CPUId * FVP_MAX_PE_PER_CPU) + + * ThreadId + * + * which can be simplified as: + * + * ((ClusterId * FVP_MAX_CPUS_PER_CLUSTER + CPUId) * FVP_MAX_PE_PER_CPU) + * + ThreadId + * --------------------------------------------------------------------- + */ +func platform_get_core_pos + /* + * Check for MT bit in MPIDR. If not set, shift MPIDR to left to make it + * look as if in a multi-threaded implementation + */ + tst r0, #MPIDR_MT_MASK + mov r3, r0 + lsleq r3, r0, #MPIDR_AFFINITY_BITS + + /* Extract individual affinity fields from MPIDR */ + ubfx r0, r3, #MPIDR_AFF0_SHIFT, #MPIDR_AFFINITY_BITS + ubfx r1, r3, #MPIDR_AFF1_SHIFT, #MPIDR_AFFINITY_BITS + ubfx r2, r3, #MPIDR_AFF2_SHIFT, #MPIDR_AFFINITY_BITS + + /* Compute linear position */ + mov r3, #FVP_MAX_CPUS_PER_CLUSTER + mla r1, r2, r3, r1 + mov r3, #FVP_MAX_PE_PER_CPU + mla r0, r1, r3, r0 + + bx lr +endfunc platform_get_core_pos diff --git a/plat/arm/board/fvp/aarch64/plat_helpers.S b/plat/arm/board/fvp/aarch64/plat_helpers.S new file mode 100644 index 000000000..bc9f60d39 --- /dev/null +++ b/plat/arm/board/fvp/aarch64/plat_helpers.S @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <asm_macros.S> +#include "../fvp_def.h" + + .globl platform_get_core_pos + +/*---------------------------------------------------------------------- + * unsigned int platform_get_core_pos(unsigned long mpid) + * + * Function to calculate the core position on FVP. + * + * (ClusterId * FVP_MAX_CPUS_PER_CLUSTER * FVP_MAX_PE_PER_CPU) + + * (CPUId * FVP_MAX_PE_PER_CPU) + + * ThreadId + * + * which can be simplified as: + * + * ((ClusterId * FVP_MAX_CPUS_PER_CLUSTER + CPUId) * FVP_MAX_PE_PER_CPU) + * + ThreadId + * --------------------------------------------------------------------- + */ +func platform_get_core_pos + /* + * Check for MT bit in MPIDR. If not set, shift MPIDR to left to make it + * look as if in a multi-threaded implementation. + */ + tst x0, #MPIDR_MT_MASK + lsl x3, x0, #MPIDR_AFFINITY_BITS + csel x3, x3, x0, eq + + /* Extract individual affinity fields from MPIDR */ + ubfx x0, x3, #MPIDR_AFF0_SHIFT, #MPIDR_AFFINITY_BITS + ubfx x1, x3, #MPIDR_AFF1_SHIFT, #MPIDR_AFFINITY_BITS + ubfx x2, x3, #MPIDR_AFF2_SHIFT, #MPIDR_AFFINITY_BITS + + /* Compute linear position */ + mov x3, #FVP_MAX_CPUS_PER_CLUSTER + madd x1, x2, x3, x1 + mov x3, #FVP_MAX_PE_PER_CPU + madd x0, x1, x3, x0 + ret +endfunc platform_get_core_pos diff --git a/plat/arm/board/fvp/fvp_def.h b/plat/arm/board/fvp/fvp_def.h new file mode 100644 index 000000000..a47287f3d --- /dev/null +++ b/plat/arm/board/fvp/fvp_def.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/******************************************************************************* + * FVP specific definitions. Used only by FVP specific code. + ******************************************************************************/ + +#ifndef __FVP_DEF_H__ +#define __FVP_DEF_H__ + +#include <platform_def.h> + +/******************************************************************************* + * Cluster Topology definitions + ******************************************************************************/ +#define FVP_MAX_CPUS_PER_CLUSTER 4 +/* Currently the highest cluster count on the FVP is 4 (Quad cluster) */ +#define FVP_CLUSTER_COUNT 4 +/* Currently multi-threaded CPUs only have a single thread */ +#define FVP_MAX_PE_PER_CPU 1 + +/******************************************************************************* + * FVP memory map related constants + ******************************************************************************/ + +#define DEVICE0_BASE 0x1a000000 +#define DEVICE0_SIZE 0x12200000 + +#define DEVICE1_BASE 0x2f000000 +#define DEVICE1_SIZE 0x400000 + +/******************************************************************************* + * GIC-400 & interrupt handling related constants + ******************************************************************************/ +/* Base FVP compatible GIC memory map */ +#define GICD_BASE 0x2f000000 +#define GICR_BASE 0x2f100000 +#define GICC_BASE 0x2c000000 + +/******************************************************************************* + * PL011 related constants + ******************************************************************************/ +#define PL011_UART0_BASE 0x1c090000 +#define PL011_UART0_CLK_IN_HZ 24000000 + +#define PLAT_ARM_UART_BASE PL011_UART0_BASE +#define PLAT_ARM_UART_CLK_IN_HZ PL011_UART0_CLK_IN_HZ + +#endif /* __FVP_DEF_H__ */ diff --git a/plat/arm/board/fvp/fvp_mem_prot.c b/plat/arm/board/fvp/fvp_mem_prot.c new file mode 100644 index 000000000..6a7d651ef --- /dev/null +++ b/plat/arm/board/fvp/fvp_mem_prot.c @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <platform.h> +#include <psci.h> +#include <utils_def.h> +#include <xlat_tables_v2.h> + +#define NS_IMAGE_OFFSET TFTF_BASE +#define NS_IMAGE_LIMIT (NS_IMAGE_OFFSET + (32 << TWO_MB_SHIFT)) + +static const mem_region_t fvp_ram_ranges[] = { + {NS_IMAGE_LIMIT, 1 << ONE_GB_SHIFT}, +#ifdef AARCH64 + {FVP_DRAM2_BASE, 1 << ONE_GB_SHIFT}, +#endif +}; + +const mem_region_t *plat_get_prot_regions(int *nelem) +{ + *nelem = ARRAY_SIZE(fvp_ram_ranges); + return fvp_ram_ranges; +} diff --git a/plat/arm/board/fvp/fvp_pwr_state.c b/plat/arm/board/fvp/fvp_pwr_state.c new file mode 100644 index 000000000..394818b74 --- /dev/null +++ b/plat/arm/board/fvp/fvp_pwr_state.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <platform.h> +#include <psci.h> +#include <stddef.h> + +/* + * State IDs for local power states on the FVP. + */ +#define FVP_RUN_STATE_ID 0 /* Valid for CPUs and Clusters */ +#define FVP_RETENTION_STATE_ID 1 /* Valid for only CPUs */ +#define FVP_OFF_STATE_ID 2 /* Valid for CPUs and Clusters */ + +/* + * Suspend depth definitions for each power state + */ +typedef enum { + FVP_RUN_DEPTH = 0, + FVP_RETENTION_DEPTH, + FVP_OFF_DEPTH, +} suspend_depth_t; + +/* The state property array with details of idle state possible for the core */ +static const plat_state_prop_t core_state_prop[] = { + {FVP_RETENTION_DEPTH, FVP_RETENTION_STATE_ID, PSTATE_TYPE_STANDBY}, + {FVP_OFF_DEPTH, FVP_OFF_STATE_ID, PSTATE_TYPE_POWERDOWN}, + {0}, +}; + +/* The state property array with details of idle state possible + for the cluster */ +static const plat_state_prop_t cluster_state_prop[] = { + {FVP_OFF_DEPTH, FVP_OFF_STATE_ID, PSTATE_TYPE_POWERDOWN}, + {0}, +}; + +/* The state property array with details of idle state possible + for the system level */ +static const plat_state_prop_t system_state_prop[] = { + {FVP_OFF_DEPTH, FVP_OFF_STATE_ID, PSTATE_TYPE_POWERDOWN}, + {0}, +}; + +const plat_state_prop_t *plat_get_state_prop(unsigned int level) +{ + switch (level) { + case MPIDR_AFFLVL0: + return core_state_prop; + case MPIDR_AFFLVL1: + return cluster_state_prop; + case MPIDR_AFFLVL2: + return system_state_prop; + default: + return NULL; + } +} diff --git a/plat/arm/board/fvp/fvp_topology.c b/plat/arm/board/fvp/fvp_topology.c new file mode 100644 index 000000000..348f8efff --- /dev/null +++ b/plat/arm/board/fvp/fvp_topology.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <assert.h> +#include <mmio.h> +#include <plat_topology.h> +#include <platform_def.h> +#include <stddef.h> +#include <tftf_lib.h> + +/* FVP Power controller based defines */ +#define PWRC_BASE 0x1c100000 +#define PSYSR_OFF 0x10 +#define PSYSR_INVALID 0xffffffff + +static const struct { + unsigned int cluster_id; + unsigned int cpu_id; +} fvp_base_aemv8a_aemv8a_cores[] = { + /* Cluster 0 */ + { 0, 0 }, + { 0, 1 }, + { 0, 2 }, + { 0, 3 }, + /* Cluster 1 */ + { 1, 0 }, + { 1, 1 }, + { 1, 2 }, + { 1, 3 }, + /* Cluster 2 */ + { 2, 0 }, + { 2, 1 }, + { 2, 2 }, + { 2, 3 }, + /* Cluster 3 */ + { 3, 0 }, + { 3, 1 }, + { 3, 2 }, + { 3, 3 }, +}; + +/* + * The FVP power domain tree descriptor. We always construct a topology + * with the maximum number of cluster nodes possible for FVP. During + * TFTF initialization, the actual number of nodes present on the model + * will be queried dynamically using `tftf_plat_get_mpidr()`. + * The FVP power domain tree does not have a single system level power domain + * i.e. a single root node. The first entry in the power domain descriptor + * specifies the number of power domains at the highest power level which + * is equal to FVP_CLUSTER_COUNT. + */ +static const unsigned char fvp_power_domain_tree_desc[] = { + /* Number of system nodes */ + 1, + /* Number of cluster nodes */ + FVP_CLUSTER_COUNT, + /* Number of children for the first node */ + FVP_MAX_CPUS_PER_CLUSTER, + /* Number of children for the second node */ + FVP_MAX_CPUS_PER_CLUSTER, + /* Number of children for the third node */ + FVP_MAX_CPUS_PER_CLUSTER, + /* Number of children for the fourth node */ + FVP_MAX_CPUS_PER_CLUSTER +}; + +const unsigned char *tftf_plat_get_pwr_domain_tree_desc(void) +{ + return fvp_power_domain_tree_desc; +} + +static unsigned int fvp_pwrc_read_psysr(unsigned long mpidr) +{ + unsigned int rc; + mmio_write_32(PWRC_BASE + PSYSR_OFF, (unsigned int) mpidr); + rc = mmio_read_32(PWRC_BASE + PSYSR_OFF); + return rc; +} + +uint64_t tftf_plat_get_mpidr(unsigned int core_pos) +{ + unsigned int mpid; + + assert(core_pos < PLATFORM_CORE_COUNT); + + mpid = make_mpid( + fvp_base_aemv8a_aemv8a_cores[core_pos].cluster_id, + fvp_base_aemv8a_aemv8a_cores[core_pos].cpu_id); + + if (fvp_pwrc_read_psysr(mpid) != PSYSR_INVALID) + return mpid; + + return INVALID_MPID; +} diff --git a/plat/arm/board/fvp/include/platform_def.h b/plat/arm/board/fvp/include/platform_def.h new file mode 100644 index 000000000..f09b6b52d --- /dev/null +++ b/plat/arm/board/fvp/include/platform_def.h @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <arm_def.h> +#include "../fvp_def.h" + +/******************************************************************************* + * Platform definitions used by common code + ******************************************************************************/ + +#ifndef __PLATFORM_DEF_H__ +#define __PLATFORM_DEF_H__ + +/******************************************************************************* + * Platform binary types for linking + ******************************************************************************/ +#ifndef AARCH32 +#define PLATFORM_LINKER_FORMAT "elf64-littleaarch64" +#define PLATFORM_LINKER_ARCH aarch64 +#else +#define PLATFORM_LINKER_FORMAT "elf32-littlearm" +#define PLATFORM_LINKER_ARCH arm +#endif + +/******************************************************************************* + * Run-time address of the TFTF image. + * It has to match the location where the Trusted Firmware-A loads the BL33 + * image. + ******************************************************************************/ +#define TFTF_BASE 0x88000000 + +/* Base address of non-trusted watchdog (SP805) */ +#define SP805_WDOG_BASE 0x1C0F0000 + +/******************************************************************************* + * Base address and size of external NVM flash + ******************************************************************************/ +#define FLASH_BASE 0x08000000 + +/* + * The flash memory in FVP resembles as a SCSP package of 2-die's and + * of a total size of 512Mb, we are using only the main blocks of size + * 128KB for storing results. Also the FVP performs data striping and + * splits the word into half to each flash die's which leads to a + * virtual block size of 256KB to software. + */ +#define NOR_FLASH_BLOCK_SIZE 0x40000 /* 256KB */ +#define NOR_FLASH_BLOCKS_COUNT 255 +#define FLASH_SIZE (NOR_FLASH_BLOCK_SIZE * NOR_FLASH_BLOCKS_COUNT) + +/******************************************************************************* + * Base address and size for the FIP that contains FWU images. + ******************************************************************************/ +#define PLAT_ARM_FWU_FIP_BASE (FLASH_BASE + 0x400000) +#define PLAT_ARM_FWU_FIP_SIZE (0x100000) + +/******************************************************************************* + * Base address and size for non-trusted SRAM. + ******************************************************************************/ +#define NSRAM_BASE (0x2e000000) +#define NSRAM_SIZE (0x00010000) + +/******************************************************************************* + * Corresponds to the function ID of the BL1 SMC handler for FWU process. + ******************************************************************************/ +#define BL1_SMC_CALL_COUNT 0x0 +#define BL1_SMC_UID 0x1 +/* SMC #0x2 reserved */ +#define BL1_SMC_VERSION 0x3 +#define FWU_SMC_IMAGE_COPY 0x10 +#define FWU_SMC_IMAGE_AUTH 0x11 +#define FWU_SMC_IMAGE_EXECUTE 0x12 +#define FWU_SMC_IMAGE_RESUME 0x13 +#define FWU_SMC_SEC_IMAGE_DONE 0x14 +#define FWU_SMC_UPDATE_DONE 0x15 +#define FWU_SMC_IMAGE_RESET 0x16 + + +/******************************************************************************* + * NS_BL1U specific defines. + * NS_BL1U RW data is relocated from NS-ROM to NS-RAM at runtime so we + * need 2 sets of addresses. + ******************************************************************************/ +#define NS_BL1U_RO_BASE (0x08000000 + 0x03EB8000) +#define NS_BL1U_RO_LIMIT (NS_BL1U_RO_BASE + 0xC000) + +/******************************************************************************* + * Put NS_BL1U RW at the top of the Non-Trusted SRAM. NS_BL1U_RW_BASE is + * calculated using the current NS_BL1U RW debug size plus a little space + * for growth. + ******************************************************************************/ +#define NS_BL1U_RW_SIZE (0x7000) +#define NS_BL1U_RW_BASE (NSRAM_BASE) +#define NS_BL1U_RW_LIMIT (NS_BL1U_RW_BASE + NS_BL1U_RW_SIZE) + +/******************************************************************************* + * Platform memory map related constants + ******************************************************************************/ +#define FVP_DRAM1_BASE 0x80000000 +#define FVP_DRAM2_BASE 0x880000000 +#define DRAM_BASE FVP_DRAM1_BASE +#define DRAM_SIZE 0x80000000 + +/******************************************************************************* + * Base address and limit for NS_BL2U image. + ******************************************************************************/ +#define NS_BL2U_BASE DRAM_BASE +#define NS_BL2U_LIMIT (NS_BL2U_BASE + 0x4D000) + +/****************************************************************************** + * Memory mapped Generic timer interfaces + ******************************************************************************/ +/* REFCLK CNTControl, Generic Timer. Secure Access only. */ +#define SYS_CNT_CONTROL_BASE 0x2a430000 +/* REFCLK CNTRead, Generic Timer. */ +#define SYS_CNT_READ_BASE 0x2a800000 +/* AP_REFCLK CNTBase1, Generic Timer. */ +#define SYS_CNT_BASE1 0x2a830000 + +/* V2M motherboard system registers & offsets */ +#define VE_SYSREGS_BASE 0x1c010000 +#define V2M_SYS_LED 0x8 + +/******************************************************************************* + * Generic platform constants + ******************************************************************************/ + +/* Size of cacheable stacks */ +#if IMAGE_NS_BL1U || IMAGE_NS_BL2U +#define PLATFORM_STACK_SIZE 0x1000 +#else +#define PLATFORM_STACK_SIZE 0x1400 +#endif + +/* Size of coherent stacks for debug and release builds */ +#if DEBUG +#define PCPU_DV_MEM_STACK_SIZE 0x600 +#else +#define PCPU_DV_MEM_STACK_SIZE 0x500 +#endif + +#define PLATFORM_CORE_COUNT (FVP_CLUSTER_COUNT * \ + FVP_MAX_CPUS_PER_CLUSTER) +#define PLATFORM_NUM_AFFS (1 + FVP_CLUSTER_COUNT + \ + PLATFORM_CORE_COUNT) +#define PLATFORM_MAX_AFFLVL MPIDR_AFFLVL2 + +/* TODO : Migrate complete TFTF from affinity level to power levels */ +#define PLAT_MAX_PWR_LEVEL PLATFORM_MAX_AFFLVL +#define PLAT_MAX_PWR_STATES_PER_LVL 2 + +#if IMAGE_NS_BL1U +#define MAX_IO_DEVICES 2 +#define MAX_IO_HANDLES 2 +#else +#define MAX_IO_DEVICES 1 +#define MAX_IO_HANDLES 1 +#endif + +/* Local state bit width for each level in the state-ID field of power state */ +#define PLAT_LOCAL_PSTATE_WIDTH 4 + +#if USE_NVM +/* + * The Flash memory is used to store the TFTF data on FVP. + * However, it might contain other data that must not be overwritten. + * For example, when using the Trusted Firmware-A, the FIP image + * (containing the bootloader images) is also stored in Flash. + * Hence, consider the first 40MB of Flash as reserved for firmware usage. + * The TFTF can use the rest of the Flash memory. + */ +#define TFTF_NVM_OFFSET 0x2800000 /* 40 MB */ +#define TFTF_NVM_SIZE (FLASH_SIZE - TFTF_NVM_OFFSET) +#else +/* + * If you want to run without support for non-volatile memory (due to + * e.g. unavailability of a flash driver), DRAM can be used instead as + * a workaround. The TFTF binary itself is loaded at 0x88000000 so the + * first 128MB can be used + * Please note that this won't be suitable for all test scenarios and + * for this reason some tests will be disabled in this configuration. + */ +#define TFTF_NVM_OFFSET 0x0 +#define TFTF_NVM_SIZE (TFTF_BASE - DRAM_BASE - TFTF_NVM_OFFSET) +#endif + +/******************************************************************************* + * Platform specific page table and MMU setup constants + ******************************************************************************/ +#define PLAT_PHY_ADDR_SPACE_SIZE (1ull << 32) +#define PLAT_VIRT_ADDR_SPACE_SIZE (1ull << 32) +#if IMAGE_TFTF +#define MAX_XLAT_TABLES 6 +#define MAX_MMAP_REGIONS 16 +#else +#define MAX_XLAT_TABLES 5 +#define MAX_MMAP_REGIONS 16 +#endif + +/******************************************************************************* + * Used to align variables 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. + ******************************************************************************/ +#define CACHE_WRITEBACK_SHIFT 6 +#define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT) + +/******************************************************************************* + * Non-Secure Software Generated Interupts IDs + ******************************************************************************/ +#define IRQ_NS_SGI_0 0 +#define IRQ_NS_SGI_1 1 +#define IRQ_NS_SGI_2 2 +#define IRQ_NS_SGI_3 3 +#define IRQ_NS_SGI_4 4 +#define IRQ_NS_SGI_5 5 +#define IRQ_NS_SGI_6 6 +#define IRQ_NS_SGI_7 7 + +/* + * On FVP, consider that the last SPI is the Trusted Random Number Generator + * interrupt. + */ +#define PLAT_MAX_SPI_OFFSET_ID 107 + +/* AP_REFCLK, Generic Timer, CNTPSIRQ1. */ +#define IRQ_CNTPSIRQ1 58 +/* Per-CPU Hypervisor Timer Interrupt ID */ +#define IRQ_PCPU_HP_TIMER 26 +/* Per-CPU Non-Secure Timer Interrupt ID */ +#define IRQ_PCPU_NS_TIMER 30 + + +/* Times(in ms) used by test code for completion of different events */ +#define PLAT_SUSPEND_ENTRY_TIME 15 +#define PLAT_SUSPEND_ENTRY_EXIT_TIME 30 + +#endif /* __PLATFORM_DEF_H__ */ diff --git a/plat/arm/board/fvp/plat_setup.c b/plat/arm/board/fvp/plat_setup.c new file mode 100644 index 000000000..0d816863a --- /dev/null +++ b/plat/arm/board/fvp/plat_setup.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arm_gic.h> +#include <plat_arm.h> +#include <platform.h> + +/* + * Table of regions to map using the MMU. + */ +#if IMAGE_NS_BL1U +static const mmap_region_t mmap[] = { + MAP_REGION_FLAT(DEVICE0_BASE, DEVICE0_SIZE, MT_DEVICE | MT_RW | MT_NS), + MAP_REGION_FLAT(FLASH_BASE, FLASH_SIZE, MT_MEMORY | MT_RO | MT_NS), + MAP_REGION_FLAT(DRAM_BASE, DRAM_SIZE, MT_MEMORY | MT_RW | MT_NS), + {0} + }; +#elif IMAGE_NS_BL2U +static const mmap_region_t mmap[] = { + MAP_REGION_FLAT(DEVICE0_BASE, DEVICE0_SIZE, MT_DEVICE | MT_RW | MT_NS), + MAP_REGION_FLAT(DEVICE1_BASE, DEVICE1_SIZE, MT_DEVICE | MT_RW | MT_NS), + MAP_REGION_FLAT(FLASH_BASE, FLASH_SIZE, MT_DEVICE | MT_RW | MT_NS), + MAP_REGION_FLAT(DRAM_BASE, DRAM_SIZE, MT_MEMORY | MT_RW | MT_NS), + {0} +}; +#elif IMAGE_TFTF +static const mmap_region_t mmap[] = { + MAP_REGION_FLAT(DEVICE0_BASE, DEVICE0_SIZE, MT_DEVICE | MT_RW | MT_NS), + MAP_REGION_FLAT(DEVICE1_BASE, DEVICE1_SIZE, MT_DEVICE | MT_RW | MT_NS), +#if USE_NVM + MAP_REGION_FLAT(FLASH_BASE, FLASH_SIZE, MT_DEVICE | MT_RW | MT_NS), +#endif + MAP_REGION_FLAT(DRAM_BASE, TFTF_BASE - DRAM_BASE, MT_MEMORY | MT_RW | MT_NS), + {0} +}; +#endif /* IMAGE_NS_BL1U */ + +const mmap_region_t *tftf_platform_get_mmap(void) +{ + return mmap; +} + +void plat_arm_gic_init(void) +{ + arm_gic_init(GICC_BASE, GICD_BASE, GICR_BASE); +} diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk new file mode 100644 index 000000000..281a5f30c --- /dev/null +++ b/plat/arm/board/fvp/platform.mk @@ -0,0 +1,26 @@ +# +# Copyright (c) 2018, Arm Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +PLAT_INCLUDES := -Iplat/arm/board/fvp/include/ + +PLAT_SOURCES := drivers/arm/gic/arm_gic_v2v3.c \ + drivers/arm/gic/gic_v2.c \ + drivers/arm/gic/gic_v3.c \ + drivers/arm/sp805/sp805.c \ + drivers/arm/timer/private_timer.c \ + drivers/arm/timer/system_timer.c \ + lib/semihosting/${ARCH}/semihosting_call.S \ + lib/semihosting/semihosting.c \ + plat/arm/board/fvp/${ARCH}/plat_helpers.S \ + plat/arm/board/fvp/fvp_pwr_state.c \ + plat/arm/board/fvp/fvp_topology.c \ + plat/arm/board/fvp/fvp_mem_prot.c \ + plat/arm/board/fvp/plat_setup.c + +# Firmware update is implemented on FVP. +FIRMWARE_UPDATE := 1 + +include plat/arm/common/arm_common.mk diff --git a/plat/arm/board/juno/aarch32/plat_helpers.S b/plat/arm/board/juno/aarch32/plat_helpers.S new file mode 100644 index 000000000..6f252c00c --- /dev/null +++ b/plat/arm/board/juno/aarch32/plat_helpers.S @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <asm_macros.S> + + .globl platform_get_core_pos + + /* + * Return 0 to 3 for the Cortex-A53 cores and 4 to 5 for the Cortex-A57 + * cores. + */ +func platform_get_core_pos + and r1, r0, #MPIDR_CPU_MASK + and r0, r0, #MPIDR_CLUSTER_MASK + /* Swap Cortex-A53/Cortex-A57 order. */ + eor r0, r0, #(1 << MPIDR_AFF1_SHIFT) + add r0, r1, r0, LSR #6 + bx lr +endfunc platform_get_core_pos diff --git a/plat/arm/board/juno/aarch64/plat_helpers.S b/plat/arm/board/juno/aarch64/plat_helpers.S new file mode 100644 index 000000000..c51a4d98e --- /dev/null +++ b/plat/arm/board/juno/aarch64/plat_helpers.S @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <asm_macros.S> + + .globl platform_get_core_pos + + /* + * Return 0 to 3 for the Cortex-A53 cores and 4 to 5 for the Cortex-A57 + * cores. + */ +func platform_get_core_pos + and x1, x0, #MPIDR_CPU_MASK + and x0, x0, #MPIDR_CLUSTER_MASK + /* Swap Cortex-A53/Cortex-A57 order. */ + eor x0, x0, #(1 << MPIDR_AFF1_SHIFT) + add x0, x1, x0, LSR #6 + ret +endfunc platform_get_core_pos diff --git a/plat/arm/board/juno/include/platform_def.h b/plat/arm/board/juno/include/platform_def.h new file mode 100644 index 000000000..37b419fc9 --- /dev/null +++ b/plat/arm/board/juno/include/platform_def.h @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <arm_def.h> +#include "../juno_def.h" + +/******************************************************************************* + * Platform definitions used by common code + ******************************************************************************/ + +#ifndef __PLATFORM_DEF_H__ +#define __PLATFORM_DEF_H__ + +/******************************************************************************* + * Platform binary types for linking + ******************************************************************************/ +#ifndef AARCH32 +#define PLATFORM_LINKER_FORMAT "elf64-littleaarch64" +#define PLATFORM_LINKER_ARCH aarch64 +#else +#define PLATFORM_LINKER_FORMAT "elf32-littlearm" +#define PLATFORM_LINKER_ARCH arm +#endif + +/******************************************************************************* + * Run-time address of the TFTF image. + * It has to match the location where the Trusted Firmware-A loads the BL33 + * image. + ******************************************************************************/ +#define TFTF_BASE 0xE0000000 + +#define JUNO_DRAM1_BASE 0x80000000 +#define JUNO_DRAM2_BASE 0x880000000 +#define DRAM_BASE JUNO_DRAM1_BASE +#define DRAM_SIZE 0x80000000 + +/* Base address of non-trusted watchdog (SP805) */ +#define SP805_WDOG_BASE 0x1C0F0000 + +/* Memory mapped Generic timer interfaces */ +#define SYS_CNT_BASE1 0x2a830000 + +/* V2M motherboard system registers & offsets */ +#define VE_SYSREGS_BASE 0x1c010000 +#define V2M_SYS_LED 0x8 + +/******************************************************************************* + * Base address and size of external NVM flash + ******************************************************************************/ +#define FLASH_BASE 0x08000000 + +/* + * The flash chip on Juno is a SCSP package of 2-die's and of a total size of + * 512Mb, we are using only the main blocks of size 128KB for storing results. + * The SMC controller performs data striping and splits the word into half to + * each flash die's which leads to a virtual block size of 256KB to software. + */ +#define NOR_FLASH_BLOCK_SIZE 0x40000 +#define NOR_FLASH_BLOCKS_COUNT 255 +#define FLASH_SIZE (NOR_FLASH_BLOCK_SIZE * NOR_FLASH_BLOCKS_COUNT) + +/******************************************************************************* + * Base address and size for the FIP that contains FWU images. + ******************************************************************************/ +#define PLAT_ARM_FWU_FIP_BASE (FLASH_BASE + 0x400000) +#define PLAT_ARM_FWU_FIP_SIZE (0x100000) + +/******************************************************************************* + * Base address and size for non-trusted SRAM. + ******************************************************************************/ +#define NSRAM_BASE (0x2e000000) +#define NSRAM_SIZE (0x00008000) + +/******************************************************************************* + * Corresponds to the function ID of the BL1 SMC handler for FWU process. + ******************************************************************************/ +#define BL1_SMC_CALL_COUNT 0x0 +#define BL1_SMC_UID 0x1 +/* SMC #0x2 reserved */ +#define BL1_SMC_VERSION 0x3 +#define FWU_SMC_IMAGE_COPY 0x10 +#define FWU_SMC_IMAGE_AUTH 0x11 +#define FWU_SMC_IMAGE_EXECUTE 0x12 +#define FWU_SMC_IMAGE_RESUME 0x13 +#define FWU_SMC_SEC_IMAGE_DONE 0x14 +#define FWU_SMC_UPDATE_DONE 0x15 +#define FWU_SMC_IMAGE_RESET 0x16 + +/******************************************************************************* + * NS_BL1U specific defines. + * NS_BL1U RW data is relocated from NS-ROM to NS-RAM at runtime so we + * need 2 sets of addresses. + ******************************************************************************/ +#define NS_BL1U_RO_BASE (0x08000000 + 0x03EB8000) +#define NS_BL1U_RO_LIMIT (NS_BL1U_RO_BASE + 0xC000) + +/******************************************************************************* + * Put NS_BL1U RW at the top of the Non-Trusted SRAM. NS_BL1U_RW_BASE is + * calculated using the current NS_BL1U RW debug size plus a little space + * for growth. + ******************************************************************************/ +#define NS_BL1U_RW_SIZE (0x7000) +#define NS_BL1U_RW_BASE (NSRAM_BASE) +#define NS_BL1U_RW_LIMIT (NS_BL1U_RW_BASE + NS_BL1U_RW_SIZE) + +/******************************************************************************* + * Base address and limit for NS_BL2U image. + ******************************************************************************/ +#define NS_BL2U_BASE DRAM_BASE +#define NS_BL2U_LIMIT (NS_BL2U_BASE + 0x4D000) + +/******************************************************************************* + * Generic platform constants + ******************************************************************************/ + +/* Size of cacheable stacks */ +#if IMAGE_NS_BL1U +#define PLATFORM_STACK_SIZE 0x1000 +#elif IMAGE_NS_BL2U +#define PLATFORM_STACK_SIZE 0x1000 +#elif IMAGE_TFTF +#define PLATFORM_STACK_SIZE 0x1400 +#endif + +/* Size of coherent stacks for debug and release builds */ +#if DEBUG +#define PCPU_DV_MEM_STACK_SIZE 0x600 +#else +#define PCPU_DV_MEM_STACK_SIZE 0x500 +#endif + +#define PLATFORM_SYSTEM_COUNT 1 +#define PLATFORM_CLUSTER_COUNT 2 +#define PLATFORM_CLUSTER1_CORE_COUNT 4 /* Cortex-A53 Cluster */ +#define PLATFORM_CLUSTER0_CORE_COUNT 2 /* Cortex-A57 Cluster */ +#define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER1_CORE_COUNT + \ + PLATFORM_CLUSTER0_CORE_COUNT) +#define PLATFORM_NUM_AFFS (PLATFORM_SYSTEM_COUNT + \ + PLATFORM_CLUSTER_COUNT + \ + PLATFORM_CORE_COUNT) +#define PLATFORM_MAX_AFFLVL MPIDR_AFFLVL2 +#define PLAT_MAX_PWR_LEVEL PLATFORM_MAX_AFFLVL +#define PLAT_MAX_PWR_STATES_PER_LVL 2 + +/* Local state bit width for each level in the state-ID field of power state */ +#define PLAT_LOCAL_PSTATE_WIDTH 4 + +#if IMAGE_NS_BL1U +#define MAX_IO_DEVICES 2 +#define MAX_IO_HANDLES 2 +#else +#define MAX_IO_DEVICES 1 +#define MAX_IO_HANDLES 1 +#endif + +#if USE_NVM +/* + * The Flash memory is used to store TFTF data on Juno. + * However, it might contain other data that must not be overwritten. + * For example, when using the Trusted Firmware-A, the FIP image + * (containing the bootloader images) is also stored in Flash. + * Hence, consider the first 40MB of Flash as reserved for firmware usage. + * The TFTF can use the rest of the Flash memory. + */ +#define TFTF_NVM_OFFSET 0x2800000 /* 40MB */ +#define TFTF_NVM_SIZE (FLASH_SIZE - TFTF_NVM_OFFSET) +#else +/* + * If you want to run without support for non-volatile memory (due to e.g. + * unavailability of a flash driver), DRAM can be used instead as workaround. + * The TFTF binary itself is loaded at 0xE0000000 so we have plenty of free + * memory at the beginning of the DRAM. Let's use the first 128MB. + * + * Please note that this won't be suitable for all test scenarios and + * for this reason some tests will be disabled in this configuration. + */ +#define TFTF_NVM_OFFSET 0x0 +#define TFTF_NVM_SIZE 0x8000000 /* 128 MB */ +#endif + +/******************************************************************************* + * Platform specific page table and MMU setup constants + ******************************************************************************/ +#define PLAT_PHY_ADDR_SPACE_SIZE (1ull << 32) +#define PLAT_VIRT_ADDR_SPACE_SIZE (1ull << 32) +#define MAX_XLAT_TABLES 5 +#define MAX_MMAP_REGIONS 16 + +/******************************************************************************* + * Used to align variables 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. + ******************************************************************************/ +#define CACHE_WRITEBACK_SHIFT 6 +#define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT) + +/******************************************************************************* + * Non-Secure Software Generated Interupts IDs + ******************************************************************************/ +#define IRQ_NS_SGI_0 0 +#define IRQ_NS_SGI_1 1 +#define IRQ_NS_SGI_2 2 +#define IRQ_NS_SGI_3 3 +#define IRQ_NS_SGI_4 4 +#define IRQ_NS_SGI_5 5 +#define IRQ_NS_SGI_6 6 +#define IRQ_NS_SGI_7 7 + +#define PLAT_MAX_SPI_OFFSET_ID 220 + +/* The IRQ generated by Ethernet controller */ +#define IRQ_ETHERNET 192 + +#define IRQ_CNTPSIRQ1 92 +/* Per-CPU Hypervisor Timer Interrupt ID */ +#define IRQ_PCPU_HP_TIMER 26 +/* Per-CPU Non-Secure Timer Interrupt ID */ +#define IRQ_PCPU_NS_TIMER 30 + +/* + * Times(in ms) used by test code for completion of different events. + * Suspend entry time for debug build is high due to the time taken + * by the VERBOSE/INFO prints. The value considers the worst case scenario + * where all CPUs are going and coming out of suspend continuously. + */ +#if DEBUG +#define PLAT_SUSPEND_ENTRY_TIME 0x100 +#define PLAT_SUSPEND_ENTRY_EXIT_TIME 0x200 +#else +#define PLAT_SUSPEND_ENTRY_TIME 10 +#define PLAT_SUSPEND_ENTRY_EXIT_TIME 20 +#endif + +#endif /* __PLATFORM_DEF_H__ */ diff --git a/plat/arm/board/juno/juno32_tests_to_skip.txt b/plat/arm/board/juno/juno32_tests_to_skip.txt new file mode 100644 index 000000000..078e36351 --- /dev/null +++ b/plat/arm/board/juno/juno32_tests_to_skip.txt @@ -0,0 +1,11 @@ +# +# Copyright (c) 2018, Arm Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +# System suspend is not supported on AArch32 Juno. +PSCI System Suspend Validation +PSCI STAT/Stats test cases after system suspend +IRQ support in TSP/Resume preempted STD SMC after PSCI SYSTEM SUSPEND +PSCI SYSTEM SUSPEND stress tests diff --git a/plat/arm/board/juno/juno_def.h b/plat/arm/board/juno/juno_def.h new file mode 100644 index 000000000..930332fb3 --- /dev/null +++ b/plat/arm/board/juno/juno_def.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __JUNO_DEF_H__ +#define __JUNO_DEF_H__ + +#include <platform_def.h> + +/******************************************************************************* + * Juno memory map related constants + ******************************************************************************/ +/* First peripherals region excluding Non-Trusted ROM and Non-Trusted RAM */ +#define DEVICE0_BASE 0x20000000 +#define DEVICE0_SIZE 0x0e000000 + +/* PCIe expansion region and 2nd peripherals region */ +#define DEVICE1_BASE 0x40000000 +#define DEVICE1_SIZE 0x40000000 + +#define IOFPGA_PERIPHERALS_BASE 0x1c000000 +#define IOFPGA_PERIPHERALS_SIZE 0x3000000 + +/******************************************************************************* + * GIC-400 & interrupt handling related constants + ******************************************************************************/ +#define GICD_BASE 0x2c010000 +#define GICC_BASE 0x2c02f000 +/* Juno doesn't support GIC Redistributor, it's a GICv3 feature */ +#define GICR_BASE 0 + +/******************************************************************************* + * PL011 related constants + ******************************************************************************/ +/* SoC UART0 */ +#define PL011_UART2_BASE 0x7ff80000 +#define PL011_UART2_CLK_IN_HZ 7273800 + +#define PLAT_ARM_UART_BASE PL011_UART2_BASE +#define PLAT_ARM_UART_CLK_IN_HZ PL011_UART2_CLK_IN_HZ + +/******************************************************************************* + * Motherboard timer related constants + ******************************************************************************/ +#define MB_TIMER1_BASE 0x1C120000 +#define MB_TIMER1_IRQ 198 +#define MB_TIMER1_FREQ 32000 + +/******************************************************************************* + * Ethernet controller related constants + ******************************************************************************/ +#define ETHERNET_BASE 0x18000000 +#define ETHERNET_SIZE 0x04000000 +#define ETHERNET_IRQ_CFG_OFFSET 0x54 +#define ETHERNET_IRQ_CFG_VAL 0x11 + +#endif /* __JUNO_DEF_H__ */ + diff --git a/plat/arm/board/juno/juno_mem_prot.c b/plat/arm/board/juno/juno_mem_prot.c new file mode 100644 index 000000000..f0e350673 --- /dev/null +++ b/plat/arm/board/juno/juno_mem_prot.c @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <platform.h> +#include <psci.h> +#include <utils_def.h> +#include <xlat_tables_v2.h> + +#define NS_IMAGE_OFFSET TFTF_BASE +#define NS_IMAGE_LIMIT (NS_IMAGE_OFFSET + (32 << TWO_MB_SHIFT)) + +static const mem_region_t juno_ram_ranges[] = { + {NS_IMAGE_LIMIT, 128 << TWO_MB_SHIFT}, +#ifdef AARCH64 + {JUNO_DRAM2_BASE, 1 << ONE_GB_SHIFT}, +#endif +}; + +const mem_region_t *plat_get_prot_regions(int *nelem) +{ + *nelem = ARRAY_SIZE(juno_ram_ranges); + return juno_ram_ranges; +} diff --git a/plat/arm/board/juno/juno_pwr_state.c b/plat/arm/board/juno/juno_pwr_state.c new file mode 100644 index 000000000..1e067c2a6 --- /dev/null +++ b/plat/arm/board/juno/juno_pwr_state.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <platform.h> +#include <psci.h> +#include <stddef.h> + +/* + * State IDs for local power states on Juno. + */ +#define JUNO_RUN_STATE_ID 0 /* Valid for CPUs and Clusters */ +#define JUNO_RETENTION_STATE_ID 1 /* Valid for only CPUs */ +#define JUNO_OFF_STATE_ID 2 /* Valid for CPUs and Clusters */ + +/* + * Suspend depth definitions for each power state + */ +typedef enum { + JUNO_RUN_DEPTH = 0, + JUNO_RETENTION_DEPTH, + JUNO_OFF_DEPTH, +} suspend_depth_t; + +/* The state property array with details of idle state possible for the core */ +static const plat_state_prop_t core_state_prop[] = { + {JUNO_RETENTION_DEPTH, JUNO_RETENTION_STATE_ID, PSTATE_TYPE_STANDBY}, + {JUNO_OFF_DEPTH, JUNO_OFF_STATE_ID, PSTATE_TYPE_POWERDOWN}, + {0}, +}; + +/* + * The state property array with details of idle state possible + * for the cluster + */ +static const plat_state_prop_t cluster_state_prop[] = { + {JUNO_OFF_DEPTH, JUNO_OFF_STATE_ID, PSTATE_TYPE_POWERDOWN}, + {0}, +}; + +/* + * The state property array with details of idle state possible + * for the system. Currently Juno does not support CPU SUSPEND + * at system power level. + */ +static const plat_state_prop_t system_state_prop[] = { + {JUNO_OFF_DEPTH, JUNO_OFF_STATE_ID, PSTATE_TYPE_POWERDOWN}, + {0}, +}; + +const plat_state_prop_t *plat_get_state_prop(unsigned int level) +{ + switch (level) { + case MPIDR_AFFLVL0: + return core_state_prop; + case MPIDR_AFFLVL1: + return cluster_state_prop; + case MPIDR_AFFLVL2: + return system_state_prop; + default: + return NULL; + } +} diff --git a/plat/arm/board/juno/juno_timers.c b/plat/arm/board/juno/juno_timers.c new file mode 100644 index 000000000..1d1ce4884 --- /dev/null +++ b/plat/arm/board/juno/juno_timers.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <platform.h> +#include <platform_def.h> +#include <sp804.h> +#include <stddef.h> +#include <timer.h> + +static const plat_timer_t plat_timers = { + .program = sp804_timer_program, + .cancel = sp804_timer_cancel, + .handler = sp804_timer_handler, + .timer_step_value = 2, + .timer_irq = MB_TIMER1_IRQ /* Motherboard SP804 timer1 IRQ */ +}; + +int plat_initialise_timer_ops(const plat_timer_t **timer_ops) +{ + assert(timer_ops != NULL); + *timer_ops = &plat_timers; + + /* Initialise the system timer */ + sp804_timer_init(MB_TIMER1_BASE, MB_TIMER1_FREQ); + + return 0; +} diff --git a/plat/arm/board/juno/juno_topology.c b/plat/arm/board/juno/juno_topology.c new file mode 100644 index 000000000..f7e00440e --- /dev/null +++ b/plat/arm/board/juno/juno_topology.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <assert.h> +#include <plat_topology.h> +#include <platform_def.h> +#include <stddef.h> +#include <tftf_lib.h> + +static const struct { + unsigned cluster_id; + unsigned cpu_id; +} juno_cores[] = { + /* Cortex-A53 Cluster: 4 cores*/ + { 1, 0 }, + { 1, 1 }, + { 1, 2 }, + { 1, 3 }, + /* Cortex-A57 Cluster: 2 cores */ + { 0, 0 }, + { 0, 1 }, +}; + +/* + * The Juno power domain tree descriptor. Juno implements a system + * power domain at the level 2. The first entry in the power domain descriptor + * specifies the number of power domains at the highest power level. For Juno + * this is 1 i.e. the number of system power domain. + */ +static const unsigned char juno_power_domain_tree_desc[] = { + /* Number of root nodes */ + PLATFORM_SYSTEM_COUNT, + /* Number of children of root node */ + PLATFORM_CLUSTER_COUNT, + /* Number of children for the first cluster */ + PLATFORM_CLUSTER1_CORE_COUNT, + /* Number of children for the second cluster */ + PLATFORM_CLUSTER0_CORE_COUNT +}; + +const unsigned char *tftf_plat_get_pwr_domain_tree_desc(void) +{ + return juno_power_domain_tree_desc; +} + +uint64_t tftf_plat_get_mpidr(unsigned int core_pos) +{ + assert(core_pos < PLATFORM_CORE_COUNT); + + return make_mpid(juno_cores[core_pos].cluster_id, + juno_cores[core_pos].cpu_id); +} diff --git a/plat/arm/board/juno/plat_setup.c b/plat/arm/board/juno/plat_setup.c new file mode 100644 index 000000000..8792cb343 --- /dev/null +++ b/plat/arm/board/juno/plat_setup.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arm_gic.h> +#include <mmio.h> +#include <plat_arm.h> +#include <platform.h> +#include <xlat_tables_v2.h> + +/* + * Table of regions to map using the MMU. + */ +#if IMAGE_NS_BL1U +static const mmap_region_t mmap[] = { + MAP_REGION_FLAT(DEVICE1_BASE, DEVICE1_SIZE, MT_DEVICE | MT_RW | MT_NS), + MAP_REGION_FLAT(FLASH_BASE, FLASH_SIZE, MT_MEMORY | MT_RO | MT_NS), + MAP_REGION_FLAT(DRAM_BASE, DRAM_SIZE, MT_MEMORY | MT_RW | MT_NS), + {0} +}; +#elif IMAGE_NS_BL2U +static const mmap_region_t mmap[] = { + MAP_REGION_FLAT(DEVICE0_BASE, DEVICE0_SIZE, MT_DEVICE | MT_RW | MT_NS), + MAP_REGION_FLAT(IOFPGA_PERIPHERALS_BASE, IOFPGA_PERIPHERALS_SIZE, + MT_DEVICE | MT_RW | MT_NS), + MAP_REGION_FLAT(DEVICE1_BASE, DEVICE1_SIZE, MT_DEVICE | MT_RW | MT_NS), + MAP_REGION_FLAT(FLASH_BASE, FLASH_SIZE, MT_DEVICE | MT_RW | MT_NS), + MAP_REGION_FLAT(DRAM_BASE, DRAM_SIZE, MT_MEMORY | MT_RW | MT_NS), + {0} +}; +#elif IMAGE_TFTF +static const mmap_region_t mmap[] = { + MAP_REGION_FLAT(DEVICE0_BASE, DEVICE0_SIZE, MT_DEVICE | MT_RW | MT_NS), + MAP_REGION_FLAT(ETHERNET_BASE, ETHERNET_SIZE, MT_DEVICE | MT_RW | MT_NS), + MAP_REGION_FLAT(IOFPGA_PERIPHERALS_BASE, IOFPGA_PERIPHERALS_SIZE, + MT_DEVICE | MT_RW | MT_NS), + MAP_REGION_FLAT(DEVICE1_BASE, DEVICE1_SIZE, MT_DEVICE | MT_RW | MT_NS), +#if USE_NVM + MAP_REGION_FLAT(FLASH_BASE, FLASH_SIZE, MT_DEVICE | MT_RW | MT_NS), +#endif + MAP_REGION_FLAT(DRAM_BASE, TFTF_BASE - DRAM_BASE, MT_MEMORY | MT_RW | MT_NS), + {0} +}; +#endif /* IMAGE_NS_BL1U */ + +const mmap_region_t *tftf_platform_get_mmap(void) +{ + return mmap; +} + +void tftf_platform_setup(void) +{ + arm_platform_setup(); + +#if !IMAGE_NS_BL2U + /* + * The Ethernet IRQ line is high by default which prevents Juno + * from entering system suspend. Configure it to be low. + * + * Interrupts are disabled in NS_BL2U so there's no need to fix this + * as we are not going to suspend the system. + * + * TODO: Currently this needs to be done in a loop for the write + * to IRQ_CFG register to take effect. Need to find the reason for + * this behavior. + */ + int val; + + do { + mmio_write_32(ETHERNET_BASE + ETHERNET_IRQ_CFG_OFFSET, + ETHERNET_IRQ_CFG_VAL); + + val = mmio_read_8(ETHERNET_BASE + ETHERNET_IRQ_CFG_OFFSET); + } while (val != ETHERNET_IRQ_CFG_VAL); +#endif /* IMAGE_NS_BL2U */ +} + +void plat_arm_gic_init(void) +{ + arm_gic_init(GICC_BASE, GICD_BASE, GICR_BASE); +} diff --git a/plat/arm/board/juno/platform.mk b/plat/arm/board/juno/platform.mk new file mode 100644 index 000000000..97172b5a9 --- /dev/null +++ b/plat/arm/board/juno/platform.mk @@ -0,0 +1,42 @@ +# +# Copyright (c) 2018, Arm Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +PLAT_INCLUDES := -Iplat/arm/board/juno/include/ + +PLAT_SOURCES := drivers/arm/gic/arm_gic_v2.c \ + drivers/arm/gic/gic_v2.c \ + drivers/arm/sp805/sp805.c \ + drivers/arm/timer/private_timer.c \ + drivers/arm/timer/sp804.c \ + plat/arm/board/juno/${ARCH}/plat_helpers.S \ + plat/arm/board/juno/juno_pwr_state.c \ + plat/arm/board/juno/juno_timers.c \ + plat/arm/board/juno/juno_topology.c \ + plat/arm/board/juno/juno_mem_prot.c \ + plat/arm/board/juno/plat_setup.c + +TESTS_SOURCES += tftf/tests/runtime_services/trusted_os/tsp/test_irq_spurious_gicv2.c + +# Some tests are not supported on Juno AArch32. +ifeq (${ARCH},aarch32) +PLAT_TESTS_SKIP_LIST := plat/arm/board/juno/juno32_tests_to_skip.txt +endif + +PLAT_SUPPORTS_NS_RESET := 1 + +# Process PLAT_SUPPORTS_NS_RESET flag +$(eval $(call assert_boolean,PLAT_SUPPORTS_NS_RESET)) +$(eval $(call add_define,TFTF_DEFINES,PLAT_SUPPORTS_NS_RESET)) + +ifeq (${ARCH},aarch32) +ifeq (${FIRMWARE_UPDATE},1) +$(error "FIRMWARE_UPDATE is not supported on Juno aarch32") +endif +else +FIRMWARE_UPDATE := 1 +endif + +include plat/arm/common/arm_common.mk diff --git a/plat/arm/board/juno/tests.xml b/plat/arm/board/juno/tests.xml new file mode 100644 index 000000000..8e679c31d --- /dev/null +++ b/plat/arm/board/juno/tests.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- + Copyright (c) 2018, Arm Limited. All rights reserved. + + SPDX-License-Identifier: BSD-3-Clause +--> + +<!-- External references to all individual tests files. --> +<!DOCTYPE testsuites [ + <!ENTITY tests-tftf-validation SYSTEM "../../../../tftf/tests/tests-tftf-validation.xml"> + <!ENTITY tests-boot-req SYSTEM "../../../../tftf/tests/tests-boot-req.xml"> + <!ENTITY tests-psci SYSTEM "../../../../tftf/tests/tests-psci.xml"> + <!ENTITY tests-sdei SYSTEM "../../../../tftf/tests/tests-sdei.xml"> + <!ENTITY tests-rt-instr SYSTEM "../../../../tftf/tests/tests-runtime-instrumentation.xml"> + <!ENTITY tests-tsp SYSTEM "../../../../tftf/tests/tests-tsp.xml"> + <!ENTITY tests-el3-pstate SYSTEM "../../../../tftf/tests/tests-el3-power-state.xml"> + <!ENTITY tests-state-switch SYSTEM "../../../../tftf/tests/tests-arm-state-switch.xml"> + <!ENTITY tests-cpu-extensions SYSTEM "../../../../tftf/tests/tests-cpu-extensions.xml"> + <!ENTITY tests-performance SYSTEM "../../../../tftf/tests/tests-performance.xml"> +]> + +<testsuites> + + &tests-tftf-validation; + &tests-boot-req; + &tests-psci; + &tests-sdei; + &tests-rt-instr; + &tests-tsp; + &tests-el3-pstate; + &tests-state-switch; + &tests-cpu-extensions; + &tests-performance; + + <testsuite name="Juno - IRQ support in TSP" description="Test the normal IRQ preemption support in TSP."> + <testcase name="Juno - Multicore spurious interrupt test" function="test_juno_multicore_spurious_interrupt" /> + </testsuite> + +</testsuites> diff --git a/plat/arm/common/arm_common.mk b/plat/arm/common/arm_common.mk new file mode 100644 index 000000000..73b4690b3 --- /dev/null +++ b/plat/arm/common/arm_common.mk @@ -0,0 +1,18 @@ +# +# Copyright (c) 2018, Arm Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +PLAT_INCLUDES += -Iinclude/plat/arm/common/ + +PLAT_SOURCES += drivers/arm/gic/gic_common.c \ + drivers/arm/pl011/${ARCH}/pl011_console.S \ + plat/arm/common/arm_setup.c \ + plat/arm/common/arm_timers.c + +# Flash driver sources. +PLAT_SOURCES += drivers/io/io_storage.c \ + drivers/io/vexpress_nor/io_vexpress_nor_ops.c \ + drivers/io/vexpress_nor/io_vexpress_nor_hw.c \ + plat/arm/common/arm_io_storage.c diff --git a/plat/arm/common/arm_fwu_io_storage.c b/plat/arm/common/arm_fwu_io_storage.c new file mode 100644 index 000000000..184f2af4d --- /dev/null +++ b/plat/arm/common/arm_fwu_io_storage.c @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch_helpers.h> +#include <assert.h> +#include <debug.h> +#include <firmware_image_package.h> +#include <image_loader.h> +#include <io_driver.h> +#include <io_fip.h> +#include <io_memmap.h> +#include <io_storage.h> +#include <platform.h> +#include <platform_def.h> +#include <string.h> +#include <tftf_lib.h> + +/* May be overridden in specific ARM standard platform */ +#pragma weak plat_arm_fwu_io_setup + +/* IO devices */ +static const io_dev_connector_t *fwu_fip_dev_con; +static uintptr_t fwu_fip_dev_handle; +static const io_dev_connector_t *memmap_dev_con; +static uintptr_t memmap_dev_handle; + +static const io_block_spec_t fwu_fip_block_spec = { + .offset = PLAT_ARM_FWU_FIP_BASE, + .length = PLAT_ARM_FWU_FIP_SIZE +}; +static const io_uuid_spec_t fwu_cert_uuid_spec = { + .uuid = UUID_FIRMWARE_UPDATE_FWU_CERT, +}; +static const io_uuid_spec_t scp_bl2u_uuid_spec = { + .uuid = UUID_FIRMWARE_UPDATE_SCP_BL2U, +}; +static const io_uuid_spec_t bl2u_uuid_spec = { + .uuid = UUID_FIRMWARE_UPDATE_BL2U, +}; +static const io_uuid_spec_t ns_bl2u_uuid_spec = { + .uuid = UUID_FIRMWARE_UPDATE_NS_BL2U, +}; + +static int open_fwu_fip(const uintptr_t spec); +static int open_memmap(const uintptr_t spec); + +struct plat_io_policy { + uintptr_t *dev_handle; + uintptr_t image_spec; + int (*check)(const uintptr_t spec); +}; + +static const struct plat_io_policy policies[] = { + [FWU_FIP_IMAGE_ID] = { + &memmap_dev_handle, + (uintptr_t)&fwu_fip_block_spec, + open_memmap + }, + [FWU_CERT_ID] = { + &fwu_fip_dev_handle, + (uintptr_t)&fwu_cert_uuid_spec, + open_fwu_fip + }, + [SCP_BL2U_IMAGE_ID] = { + &fwu_fip_dev_handle, + (uintptr_t)&scp_bl2u_uuid_spec, + open_fwu_fip + }, + [BL2U_IMAGE_ID] = { + &fwu_fip_dev_handle, + (uintptr_t)&bl2u_uuid_spec, + open_fwu_fip + }, + [NS_BL2U_IMAGE_ID] = { + &fwu_fip_dev_handle, + (uintptr_t)&ns_bl2u_uuid_spec, + open_fwu_fip + }, +}; + + +/* Weak definitions may be overridden in each specific platform */ +#pragma weak plat_get_image_source + +static int open_fwu_fip(const uintptr_t spec) +{ + int result; + uintptr_t local_image_handle; + + /* See if a Firmware Image Package is available */ + result = io_dev_init(fwu_fip_dev_handle, + (uintptr_t)FWU_FIP_IMAGE_ID); + if (result == IO_SUCCESS) { + result = io_open(fwu_fip_dev_handle, spec, + &local_image_handle); + if (result == IO_SUCCESS) { + VERBOSE("Using FIP\n"); + io_close(local_image_handle); + } + } + return result; +} + + +static int open_memmap(const uintptr_t spec) +{ + int result; + uintptr_t local_image_handle; + + result = io_dev_init(memmap_dev_handle, (uintptr_t)NULL); + if (result == IO_SUCCESS) { + result = io_open(memmap_dev_handle, spec, &local_image_handle); + if (result == IO_SUCCESS) { + VERBOSE("Using Memmap\n"); + io_close(local_image_handle); + } + } + return result; +} + + +void plat_arm_fwu_io_setup(void) +{ + int io_result; + + io_result = register_io_dev_fip(&fwu_fip_dev_con); + assert(io_result == IO_SUCCESS); + + io_result = register_io_dev_memmap(&memmap_dev_con); + assert(io_result == IO_SUCCESS); + + /* Open connections to devices and cache the handles */ + io_result = io_dev_open(fwu_fip_dev_con, (uintptr_t)NULL, + &fwu_fip_dev_handle); + assert(io_result == IO_SUCCESS); + + io_result = io_dev_open(memmap_dev_con, (uintptr_t)NULL, + &memmap_dev_handle); + assert(io_result == IO_SUCCESS); + + /* Ignore improbable errors in release builds */ + (void)io_result; +} + + +/* 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 result = IO_FAIL; + const struct plat_io_policy *policy; + + assert(image_id < ARRAY_SIZE(policies)); + + policy = &policies[image_id]; + result = policy->check(policy->image_spec); + if (result == IO_SUCCESS) { + *image_spec = policy->image_spec; + *dev_handle = *(policy->dev_handle); + } + + return result; +} + +void plat_fwu_io_setup(void) +{ + plat_arm_fwu_io_setup(); +} diff --git a/plat/arm/common/arm_io_storage.c b/plat/arm/common/arm_io_storage.c new file mode 100644 index 000000000..d9d8a389c --- /dev/null +++ b/plat/arm/common/arm_io_storage.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <io_driver.h> +#include <io_nor_flash.h> +#include <io_storage.h> +#include <platform.h> +#include <tftf.h> +#include "platform_def.h" + +#pragma weak plat_get_nvm_handle + +/* IO devices */ +static const io_dev_connector_t *flash_dev_con; +static uintptr_t flash_dev_spec; +static uintptr_t flash_init_params; +static uintptr_t flash_dev_handle; +static uintptr_t flash_handle; +static unsigned int flash_init; + +static const io_nor_flash_spec_t flash_main_block_spec = { + .device_address = FLASH_BASE, + .region_address = FLASH_BASE, + .block_size = NOR_FLASH_BLOCK_SIZE, + .block_count = FLASH_SIZE / NOR_FLASH_BLOCK_SIZE +}; + +int arm_io_setup(void) +{ + int io_result; + + io_result = register_io_dev_nor_flash(&flash_dev_con); + if (io_result != IO_SUCCESS) + return io_result; + + io_result = io_dev_open(flash_dev_con, flash_dev_spec, + &flash_dev_handle); + if (io_result != IO_SUCCESS) + return io_result; + + io_result = io_dev_init(flash_dev_handle, flash_init_params); + if (io_result != IO_SUCCESS) + return io_result; + + io_result = io_open(flash_dev_handle, + (uintptr_t)&flash_main_block_spec, + &flash_handle); + + if (io_result == IO_SUCCESS) + flash_init = 1; + return io_result; +} + +void plat_get_nvm_handle(uintptr_t *handle) +{ + assert(handle); + assert(flash_init); + + *handle = flash_handle; +} + diff --git a/plat/arm/common/arm_setup.c b/plat/arm/common/arm_setup.c new file mode 100644 index 000000000..79f463176 --- /dev/null +++ b/plat/arm/common/arm_setup.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arm_gic.h> +#include <console.h> +#include <debug.h> +#include <io_storage.h> +#include <pl011.h> +#include <plat_arm.h> +#include <platform.h> +#include <platform_def.h> + +#pragma weak tftf_platform_setup + +void arm_platform_setup(void) +{ +#if USE_NVM + int ret; + + ret = arm_io_setup(); + if (ret != IO_SUCCESS) + WARN("IO setup failed : 0x%x\n", ret); +#endif + +#if IMAGE_NS_BL2U + /* NS_BL2U is not expecting interrupts. */ + return; +#endif + + plat_arm_gic_init(); + + arm_gic_setup_global(); + arm_gic_setup_local(); +} + +void tftf_platform_setup(void) +{ + arm_platform_setup(); +} + +void tftf_plat_arch_setup(void) +{ + tftf_plat_configure_mmu(); +} + +void tftf_early_platform_setup(void) +{ + console_init(PLAT_ARM_UART_BASE, PLAT_ARM_UART_CLK_IN_HZ, + PL011_BAUDRATE); +} diff --git a/plat/arm/common/arm_timers.c b/plat/arm/common/arm_timers.c new file mode 100644 index 000000000..c84cb845a --- /dev/null +++ b/plat/arm/common/arm_timers.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <platform.h> +#include <stddef.h> +#include <system_timer.h> +#include <timer.h> + +#pragma weak plat_initialise_timer_ops + +static const plat_timer_t plat_timers = { + .program = program_systimer, + .cancel = cancel_systimer, + .handler = handler_systimer, + .timer_step_value = 2, + .timer_irq = IRQ_CNTPSIRQ1 +}; + +int plat_initialise_timer_ops(const plat_timer_t **timer_ops) +{ + assert(timer_ops != NULL); + *timer_ops = &plat_timers; + + /* Initialise the system timer */ + init_systimer(SYS_CNT_BASE1); + + return 0; +} diff --git a/plat/common/aarch32/platform_helpers.S b/plat/common/aarch32/platform_helpers.S new file mode 100644 index 000000000..1a5741868 --- /dev/null +++ b/plat/common/aarch32/platform_helpers.S @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <asm_macros.S> +#include <pl011.h> +#include <platform_def.h> + + .weak platform_get_core_pos + .weak plat_crash_console_init + .weak plat_crash_console_putc + .weak plat_crash_console_flush + + /* ----------------------------------------------------- + * int platform_get_core_pos(u_register_t mpidr); + * With this function: CorePos = (ClusterId * 4) + + * CoreId + * ----------------------------------------------------- + */ +func platform_get_core_pos + and r1, r0, #MPIDR_CPU_MASK + and r0, r0, #MPIDR_CLUSTER_MASK + add r0, r1, r0, LSR #6 + bx lr +endfunc platform_get_core_pos + + /* --------------------------------------------- + * int plat_crash_console_init(void) + * Function to initialize the crash console + * without a C Runtime to print crash report. + * Clobber list : x0 - x4 + * --------------------------------------------- + */ +func plat_crash_console_init + ldr r0, =PLAT_ARM_UART_BASE + ldr r1, =PLAT_ARM_UART_CLK_IN_HZ + ldr r2, =PL011_BAUDRATE + b console_core_init +endfunc plat_crash_console_init + + /* --------------------------------------------- + * int plat_crash_console_putc(int c) + * Function to print a character on the crash + * console without a C Runtime. + * Clobber list : x1, x2 + * --------------------------------------------- + */ +func plat_crash_console_putc + ldr r1, =PLAT_ARM_UART_BASE + b console_core_putc +endfunc plat_crash_console_putc + + /* --------------------------------------------- + * int plat_crash_console_flush() + * Function to force a write of all buffered + * data that hasn't been output. + * Out : return -1 on error else return 0. + * Clobber list : r0 - r1 + * --------------------------------------------- + */ +func plat_crash_console_flush + ldr r1, =PLAT_ARM_UART_BASE + b console_core_flush +endfunc plat_crash_console_flush diff --git a/plat/common/aarch32/platform_mp_stack.S b/plat/common/aarch32/platform_mp_stack.S new file mode 100644 index 000000000..c4ea89584 --- /dev/null +++ b/plat/common/aarch32/platform_mp_stack.S @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <asm_macros.S> +#include <platform_def.h> + + + .local pcpu_dv_mem_stack + .local platform_normal_stacks + .weak platform_set_stack + .weak platform_get_stack + .weak platform_set_coherent_stack + + /* ----------------------------------------------------- + * void platform_set_coherent_stack (unsigned long mpidr) + * + * For a given CPU, this function sets the stack pointer + * to a stack allocated in device memory. This stack can + * be used by C code which enables/disables the SCTLR.M + * SCTLR.C bit e.g. while powering down a cpu + * ----------------------------------------------------- + */ +func platform_set_coherent_stack + mov r9, lr + get_mp_stack pcpu_dv_mem_stack, PCPU_DV_MEM_STACK_SIZE + mov sp, r0 + bx r9 +endfunc platform_set_coherent_stack + + /* ----------------------------------------------------- + * uintptr_t platform_get_stack (u_register_t mpidr) + * + * For a given CPU, this function returns the stack + * pointer for a stack allocated in normal memory. + * ----------------------------------------------------- + */ +func platform_get_stack + mov r9, lr + get_mp_stack platform_normal_stacks, PLATFORM_STACK_SIZE + bx r9 +endfunc platform_get_stack + + /* ----------------------------------------------------- + * void platform_set_stack (u_register_t mpidr) + * + * For a given CPU, this function sets the stack + * pointer to a stack allocated in normal memory. + * ----------------------------------------------------- + */ +func platform_set_stack + mov r9, lr + get_mp_stack platform_normal_stacks, PLATFORM_STACK_SIZE + mov sp, r0 + bx r9 +endfunc platform_set_stack + + /* ----------------------------------------------------- + * Per-cpu stacks in normal memory. + * Used for C code during runtime execution (when coherent + * stacks are not required). + * Each cpu gets a stack of PLATFORM_STACK_SIZE bytes. + * ----------------------------------------------------- + */ +declare_stack platform_normal_stacks, tftf_normal_stacks, \ + PLATFORM_STACK_SIZE, PLATFORM_CORE_COUNT + + /* ----------------------------------------------------- + * Per-cpu stacks in device memory. + * Used for C code just before power down or right after + * power up when the MMU or caches need to be turned on + * or off. + * Each cpu gets a stack of PCPU_DV_MEM_STACK_SIZE bytes. + * ----------------------------------------------------- + */ +declare_stack pcpu_dv_mem_stack, tftf_coherent_stacks, \ + PCPU_DV_MEM_STACK_SIZE, PLATFORM_CORE_COUNT diff --git a/plat/common/aarch32/platform_up_stack.S b/plat/common/aarch32/platform_up_stack.S new file mode 100644 index 000000000..e67ded820 --- /dev/null +++ b/plat/common/aarch32/platform_up_stack.S @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <asm_macros.S> +#include <platform_def.h> + + + .local platform_normal_stacks + .globl platform_set_stack + .globl platform_get_stack + + /* ----------------------------------------------------- + * unsigned long platform_get_stack (unsigned long) + * + * For cold-boot images, only the primary CPU needs a + * stack. This function returns the stack pointer for a + * stack allocated in device memory. + * ----------------------------------------------------- + */ +func platform_get_stack + get_up_stack platform_normal_stacks, PLATFORM_STACK_SIZE + bx lr +endfunc platform_get_stack + + /* ----------------------------------------------------- + * void platform_set_stack (unsigned long) + * + * For cold-boot images, only the primary CPU needs a + * stack. This function sets the stack pointer to a stack + * allocated in normal memory. + * ----------------------------------------------------- + */ +func platform_set_stack + get_up_stack platform_normal_stacks, PLATFORM_STACK_SIZE + mov sp, r0 + bx lr +endfunc platform_set_stack + + /* ----------------------------------------------------- + * Single cpu stack in normal memory. + * Used for C code during boot, PLATFORM_STACK_SIZE bytes + * are allocated + * ----------------------------------------------------- + */ +declare_stack platform_normal_stacks, ns_bl_normal_stacks, \ + PLATFORM_STACK_SIZE, 1 diff --git a/plat/common/aarch64/platform_helpers.S b/plat/common/aarch64/platform_helpers.S new file mode 100644 index 000000000..216163872 --- /dev/null +++ b/plat/common/aarch64/platform_helpers.S @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <asm_macros.S> +#include <pl011.h> +#include <platform_def.h> + + .weak platform_get_core_pos + .weak plat_crash_console_init + .weak plat_crash_console_putc + .weak plat_crash_console_flush + + /* ----------------------------------------------------- + * int platform_get_core_pos(int mpidr); + * With this function: CorePos = (ClusterId * 4) + + * CoreId + * ----------------------------------------------------- + */ +func platform_get_core_pos + and x1, x0, #MPIDR_CPU_MASK + and x0, x0, #MPIDR_CLUSTER_MASK + add x0, x1, x0, LSR #6 + ret +endfunc platform_get_core_pos + + /* --------------------------------------------- + * int plat_crash_console_init(void) + * Function to initialize the crash console + * without a C Runtime to print crash report. + * Clobber list : x0 - x4 + * --------------------------------------------- + */ +func plat_crash_console_init + mov_imm x0, PLAT_ARM_UART_BASE + mov_imm x1, PLAT_ARM_UART_CLK_IN_HZ + mov_imm x2, PL011_BAUDRATE + b console_core_init +endfunc plat_crash_console_init + + /* --------------------------------------------- + * int plat_crash_console_putc(int c) + * Function to print a character on the crash + * console without a C Runtime. + * Clobber list : x1, x2 + * --------------------------------------------- + */ +func plat_crash_console_putc + mov_imm x1, PLAT_ARM_UART_BASE + b console_core_putc +endfunc plat_crash_console_putc + + /* --------------------------------------------- + * int plat_crash_console_flush() + * Function to force a write of all buffered + * data that hasn't been output. + * Out : return -1 on error else return 0. + * Clobber list : r0 - r1 + * --------------------------------------------- + */ +func plat_crash_console_flush + mov_imm x1, PLAT_ARM_UART_BASE + b console_core_flush +endfunc plat_crash_console_flush diff --git a/plat/common/aarch64/platform_mp_stack.S b/plat/common/aarch64/platform_mp_stack.S new file mode 100644 index 000000000..fe167cc9b --- /dev/null +++ b/plat/common/aarch64/platform_mp_stack.S @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <asm_macros.S> +#include <platform_def.h> + + + .local pcpu_dv_mem_stack + .local platform_normal_stacks + .weak platform_set_stack + .weak platform_get_stack + .weak platform_set_coherent_stack + + + /* ----------------------------------------------------- + * void platform_set_coherent_stack (unsigned long mpidr) + * + * For a given CPU, this function sets the stack pointer + * to a stack allocated in device memory. This stack can + * be used by C code which enables/disables the SCTLR.M + * SCTLR.C bit e.g. while powering down a cpu + * ----------------------------------------------------- + */ +func platform_set_coherent_stack + mov x9, x30 // lr + get_mp_stack pcpu_dv_mem_stack, PCPU_DV_MEM_STACK_SIZE + mov sp, x0 + ret x9 +endfunc platform_set_coherent_stack + + /* ----------------------------------------------------- + * unsigned long platform_get_stack (unsigned long mpidr) + * + * For a given CPU, this function returns the stack + * pointer for a stack allocated in device memory. + * ----------------------------------------------------- + */ +func platform_get_stack + mov x10, x30 // lr + get_mp_stack platform_normal_stacks, PLATFORM_STACK_SIZE + ret x10 +endfunc platform_get_stack + + /* ----------------------------------------------------- + * void platform_set_stack (unsigned long mpidr) + * + * For a given CPU, this function sets the stack pointer + * to a stack allocated in normal memory. + * ----------------------------------------------------- + */ +func platform_set_stack + mov x9, x30 // lr + bl platform_get_stack + mov sp, x0 + ret x9 +endfunc platform_set_stack + + /* ----------------------------------------------------- + * Per-cpu stacks in normal memory. + * Used for C code during runtime execution (when coherent + * stacks are not required). + * Each cpu gets a stack of PLATFORM_STACK_SIZE bytes. + * ----------------------------------------------------- + */ +declare_stack platform_normal_stacks, tftf_normal_stacks, \ + PLATFORM_STACK_SIZE, PLATFORM_CORE_COUNT + + /* ----------------------------------------------------- + * Per-cpu stacks in device memory. + * Used for C code just before power down or right after + * power up when the MMU or caches need to be turned on + * or off. + * Each cpu gets a stack of PCPU_DV_MEM_STACK_SIZE bytes. + * ----------------------------------------------------- + */ +declare_stack pcpu_dv_mem_stack, tftf_coherent_stacks, \ + PCPU_DV_MEM_STACK_SIZE, PLATFORM_CORE_COUNT diff --git a/plat/common/aarch64/platform_up_stack.S b/plat/common/aarch64/platform_up_stack.S new file mode 100644 index 000000000..c61b47226 --- /dev/null +++ b/plat/common/aarch64/platform_up_stack.S @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <asm_macros.S> +#include <platform_def.h> + + + .local platform_normal_stacks + .globl platform_set_stack + .globl platform_get_stack + + /* ----------------------------------------------------- + * unsigned long platform_get_stack (unsigned long) + * + * For cold-boot images, only the primary CPU needs a + * stack. This function returns the stack pointer for a + * stack allocated in device memory. + * ----------------------------------------------------- + */ +func platform_get_stack + get_up_stack platform_normal_stacks, PLATFORM_STACK_SIZE + ret +endfunc platform_get_stack + + /* ----------------------------------------------------- + * void platform_set_stack (unsigned long) + * + * For cold-boot images, only the primary CPU needs a + * stack. This function sets the stack pointer to a stack + * allocated in normal memory. + * ----------------------------------------------------- + */ +func platform_set_stack + get_up_stack platform_normal_stacks, PLATFORM_STACK_SIZE + mov sp, x0 + ret +endfunc platform_set_stack + + /* ----------------------------------------------------- + * Single cpu stack in normal memory. + * Used for C code during boot, PLATFORM_STACK_SIZE bytes + * are allocated + * ----------------------------------------------------- + */ +declare_stack platform_normal_stacks, ns_bl_normal_stacks, \ + PLATFORM_STACK_SIZE, 1 diff --git a/plat/common/fwu_nvm_accessors.c b/plat/common/fwu_nvm_accessors.c new file mode 100644 index 000000000..5b32151d4 --- /dev/null +++ b/plat/common/fwu_nvm_accessors.c @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <debug.h> +#include <firmware_image_package.h> +#include <fwu_nvm.h> +#include <io_fip.h> +#include <io_storage.h> +#include <platform.h> +#include <platform_def.h> +#include <status.h> +#include <string.h> +#include <uuid_utils.h> + + +STATUS fwu_nvm_write(unsigned long long offset, const void *buffer, size_t size) +{ + uintptr_t nvm_handle; + int ret; + size_t length_write; + + if (offset + size > FLASH_SIZE) + return STATUS_OUT_OF_RESOURCES; + + /* Obtain a handle to the NVM by querying the platfom layer */ + plat_get_nvm_handle(&nvm_handle); + + /* Seek to the given offset. */ + ret = io_seek(nvm_handle, IO_SEEK_SET, offset); + if (ret != IO_SUCCESS) + return STATUS_FAIL; + + /* Write to the given offset. */ + ret = io_write(nvm_handle, (const uintptr_t)buffer, + size, &length_write); + if ((ret != IO_SUCCESS) || (size != length_write)) + return STATUS_FAIL; + + return STATUS_SUCCESS; +} + +STATUS fwu_nvm_read(unsigned long long offset, void *buffer, size_t size) +{ + uintptr_t nvm_handle; + int ret; + size_t length_read; + + if (offset + size > FLASH_SIZE) + return STATUS_OUT_OF_RESOURCES; + + /* Obtain a handle to the NVM by querying the platform layer */ + plat_get_nvm_handle(&nvm_handle); + + /* Seek to the given offset. */ + ret = io_seek(nvm_handle, IO_SEEK_SET, offset); + if (ret != IO_SUCCESS) + return STATUS_FAIL; + + /* Read from the given offset. */ + ret = io_read(nvm_handle, (const uintptr_t)buffer, + size, &length_read); + if ((ret != IO_SUCCESS) || (size != length_read)) + return STATUS_FAIL; + + return STATUS_SUCCESS; +} + + +STATUS fwu_update_fip(unsigned long fip_addr) +{ + uintptr_t nvm_handle; + int ret; + size_t bytes; + int fip_size; + unsigned int fip_read; + fip_toc_header_t *toc_header; + fip_toc_entry_t *toc_entry; + + /* Obtain a handle to the NVM by querying the platform layer */ + plat_get_nvm_handle(&nvm_handle); + +#if FWU_BL_TEST + /* Read the address of backup fip.bin for Firmware Update. */ + ret = io_seek(nvm_handle, IO_SEEK_SET, + FWU_TFTF_TESTCASE_BUFFER_OFFSET); + if (ret != IO_SUCCESS) + return STATUS_FAIL; + + ret = io_read(nvm_handle, (const uintptr_t)&fip_addr, + sizeof(bytes), &bytes); + if (ret != IO_SUCCESS) + return STATUS_FAIL; +#endif /* FWU_BL_TEST */ + + /* If the new FIP address is 0 it means no update. */ + if (fip_addr == 0) + return STATUS_SUCCESS; + + /* Set the ToC Header at the base of the buffer */ + toc_header = (fip_toc_header_t *)fip_addr; + + /* Check if this FIP is Valid */ + if ((toc_header->name != TOC_HEADER_NAME) || + (toc_header->serial_number == 0)) + return STATUS_LOAD_ERROR; + + /* Get to the last NULL TOC entry */ + toc_entry = (fip_toc_entry_t *)(toc_header + 1); + while (!is_uuid_null(&toc_entry->uuid)) + toc_entry++; + + /* get the total size of this FIP */ + fip_size = (int)toc_entry->offset_address; + + /* Copy the new FIP in DDR. */ + memcpy((void *)FIP_IMAGE_TMP_DDR_ADDRESS, (void *)fip_addr, fip_size); + + /* Update the FIP */ + ret = io_seek(nvm_handle, IO_SEEK_SET, 0); + if (ret != IO_SUCCESS) + return STATUS_FAIL; + + ret = io_write(nvm_handle, (const uintptr_t)FIP_IMAGE_TMP_DDR_ADDRESS, + fip_size, &bytes); + if ((ret != IO_SUCCESS) || fip_size != bytes) + return STATUS_LOAD_ERROR; + + /* Read the TOC header after update. */ + ret = io_seek(nvm_handle, IO_SEEK_SET, 0); + if (ret != IO_SUCCESS) + return STATUS_LOAD_ERROR; + + ret = io_read(nvm_handle, (const uintptr_t)&fip_read, + sizeof(bytes), &bytes); + if (ret != IO_SUCCESS) + return STATUS_FAIL; + + /* Check if this FIP is Valid */ + if (fip_read != TOC_HEADER_NAME) + return STATUS_LOAD_ERROR; + +#if FWU_BL_TEST + unsigned int done_flag = FIP_IMAGE_UPDATE_DONE_FLAG; + /* Update the TFTF test case buffer with DONE flag */ + ret = io_seek(nvm_handle, IO_SEEK_SET, + FWU_TFTF_TESTCASE_BUFFER_OFFSET); + if (ret != IO_SUCCESS) + return STATUS_FAIL; + + ret = io_write(nvm_handle, (const uintptr_t)&done_flag, + 4, &bytes); + if (ret != IO_SUCCESS) + return STATUS_FAIL; +#endif /* FWU_BL_TEST */ + + INFO("FWU Image update success\n"); + + return STATUS_SUCCESS; +} + diff --git a/plat/common/image_loader.c b/plat/common/image_loader.c new file mode 100644 index 000000000..9b27f6f45 --- /dev/null +++ b/plat/common/image_loader.c @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch_helpers.h> +#include <assert.h> +#include <debug.h> +#include <firmware_image_package.h> +#include <image_loader.h> +#include <io_driver.h> +#include <io_fip.h> +#include <io_memmap.h> +#include <io_storage.h> +#include <platform.h> +#include <platform_def.h> +#include <string.h> +#include <tftf_lib.h> + +unsigned long get_image_offset(unsigned int image_id) +{ + uintptr_t dev_handle; + uintptr_t image_handle; + uintptr_t image_spec; + unsigned long img_offset; + int io_result; + io_entity_t *entity; + fip_file_state_t *fp; + + /* Obtain a reference to the image by querying the platform layer */ + io_result = plat_get_image_source(image_id, &dev_handle, &image_spec); + if (io_result != IO_SUCCESS) { + WARN("Failed to obtain reference to image id=%u (%i)\n", + image_id, io_result); + return 0; + } + + /* Attempt to access the image */ + io_result = io_open(dev_handle, image_spec, &image_handle); + if (io_result != IO_SUCCESS) { + WARN("Failed to access image id=%u (%i)\n", + image_id, io_result); + return 0; + } + + entity = (io_entity_t *)image_handle; + + fp = (fip_file_state_t *)entity->info; + img_offset = PLAT_ARM_FWU_FIP_BASE + fp->entry.offset_address; + + (void)io_close(image_handle); + (void)io_dev_close(dev_handle); + + return img_offset; +} + + +unsigned long get_image_size(unsigned int image_id) +{ + uintptr_t dev_handle; + uintptr_t image_handle; + uintptr_t image_spec; + size_t image_size; + int io_result; + + /* Obtain a reference to the image by querying the platform layer */ + io_result = plat_get_image_source(image_id, &dev_handle, &image_spec); + if (io_result != IO_SUCCESS) { + WARN("Failed to obtain reference to image id=%u (%i)\n", + image_id, io_result); + return 0; + } + + /* Attempt to access the image */ + io_result = io_open(dev_handle, image_spec, &image_handle); + if (io_result != IO_SUCCESS) { + WARN("Failed to access image id=%u (%i)\n", + image_id, io_result); + return 0; + } + + /* Find the size of the image */ + io_result = io_size(image_handle, &image_size); + if ((io_result != IO_SUCCESS) || (image_size == 0)) { + WARN("Failed to determine the size of the image id=%u (%i)\n", + image_id, io_result); + } + io_result = io_close(image_handle); + io_result = io_dev_close(dev_handle); + + return image_size; +} + + +int load_image(unsigned int image_id, uintptr_t image_base) +{ + uintptr_t dev_handle; + uintptr_t image_handle; + uintptr_t image_spec; + size_t image_size; + size_t bytes_read; + int io_result; + + /* Obtain a reference to the image by querying the platform layer */ + io_result = plat_get_image_source(image_id, &dev_handle, &image_spec); + if (io_result != IO_SUCCESS) { + WARN("Failed to obtain reference to image id=%u (%i)\n", + image_id, io_result); + return io_result; + } + + /* Attempt to access the image */ + io_result = io_open(dev_handle, image_spec, &image_handle); + if (io_result != IO_SUCCESS) { + WARN("Failed to access image id=%u (%i)\n", + image_id, io_result); + return io_result; + } + + INFO("Loading image id=%u at address %p\n", image_id, (void *)image_base); + + /* Find the size of the image */ + io_result = io_size(image_handle, &image_size); + if ((io_result != IO_SUCCESS) || (image_size == 0)) { + WARN("Failed to determine the size of the image id=%u (%i)\n", + image_id, io_result); + goto exit; + } + + /* Load the image now */ + io_result = io_read(image_handle, image_base, image_size, &bytes_read); + if ((io_result != IO_SUCCESS) || (bytes_read < image_size)) { + WARN("Failed to load image id=%u (%i)\n", image_id, io_result); + goto exit; + } + + /* + * File has been successfully loaded. + * Flush the image so that the next EL can see it. + */ + flush_dcache_range(image_base, image_size); + + INFO("Image id=%u loaded: %p - %p\n", image_id, (void *)image_base, + (void *)(image_base + image_size - 1)); + +exit: + io_close(image_handle); + io_dev_close(dev_handle); + return io_result; +} + + +int load_partial_image(unsigned int image_id, + uintptr_t image_base, + size_t image_size, + unsigned int is_last_block) +{ + static uintptr_t dev_handle; + static uintptr_t image_handle; + uintptr_t image_spec; + size_t bytes_read; + int io_result; + + if (!image_handle) { + /* Obtain a reference to the image by querying the platform layer */ + io_result = plat_get_image_source(image_id, &dev_handle, &image_spec); + if (io_result != IO_SUCCESS) { + WARN("Failed to obtain reference to image id=%u (%i)\n", + image_id, io_result); + return io_result; + } + + /* Attempt to access the image */ + io_result = io_open(dev_handle, image_spec, &image_handle); + if (io_result != IO_SUCCESS) { + WARN("Failed to access image id=%u (%i)\n", + image_id, io_result); + return io_result; + } + } + + INFO("Loading image id=%u at address %p\n", image_id, (void *)image_base); + + io_result = io_read(image_handle, image_base, image_size, &bytes_read); + if ((io_result != IO_SUCCESS) || (bytes_read < image_size)) { + WARN("Failed to load image id=%u (%i)\n", image_id, io_result); + is_last_block = 0; + goto exit; + } + + /* + * File has been successfully loaded. + * Flush the image so that the next EL can see it. + */ + flush_dcache_range(image_base, image_size); + + INFO("Image id=%u loaded: %p - %p\n", image_id, (void *)image_base, + (void *)(image_base + image_size - 1)); + +exit: + + if (is_last_block == 0) { + io_close(image_handle); + io_dev_close(dev_handle); + image_handle = 0; + } + return io_result; +} + diff --git a/plat/common/plat_common.c b/plat/common/plat_common.c new file mode 100644 index 000000000..571387111 --- /dev/null +++ b/plat/common/plat_common.c @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch_helpers.h> +#include <console.h> +#include <debug.h> +#include <platform.h> +#include <sp805.h> +#include <xlat_tables_v2.h> + +/* + * The following platform functions are all weakly defined. They provide typical + * implementations that may be re-used by multiple platforms but may also be + * overridden by a platform if required. + */ + +#pragma weak tftf_platform_end +#pragma weak tftf_platform_watchdog_set +#pragma weak tftf_platform_watchdog_reset +#pragma weak tftf_plat_configure_mmu +#pragma weak tftf_plat_enable_mmu +#pragma weak tftf_plat_reset +#pragma weak plat_get_prot_regions + +#if IMAGE_TFTF + +#define IMAGE_RO_BASE TFTF_BASE +IMPORT_SYM(uintptr_t, __RO_END__, IMAGE_RO_END); + +#define IMAGE_RW_BASE IMAGE_RO_END +IMPORT_SYM(uintptr_t, __TFTF_END__, IMAGE_RW_END); + +IMPORT_SYM(uintptr_t, __COHERENT_RAM_START__, COHERENT_RAM_START); +IMPORT_SYM(uintptr_t, __COHERENT_RAM_END__, COHERENT_RAM_END); + +#elif IMAGE_NS_BL1U + +IMPORT_SYM(uintptr_t, __RO_END__, IMAGE_RO_END_UNALIGNED); +#define IMAGE_RO_BASE NS_BL1U_RO_BASE +#define IMAGE_RO_END round_up(IMAGE_RO_END_UNALIGNED, PAGE_SIZE) + +#define IMAGE_RW_BASE NS_BL1U_RW_BASE +IMPORT_SYM(uintptr_t, __NS_BL1U_RAM_END__, IMAGE_RW_END); + +#elif IMAGE_NS_BL2U + +#define IMAGE_RO_BASE NS_BL2U_BASE +IMPORT_SYM(uintptr_t, __RO_END__, IMAGE_RO_END); + +#define IMAGE_RW_BASE IMAGE_RO_END +IMPORT_SYM(uintptr_t, __NS_BL2U_END__, IMAGE_RW_END_UNALIGNED); +#define IMAGE_RW_END round_up(IMAGE_RW_END_UNALIGNED, PAGE_SIZE) + +#endif + +void tftf_platform_end(void) +{ + /* + * Send EOT (End Of Transmission) on the UART. + * This can be used to shutdown a software model. + */ + static const char ascii_eot = 4; + console_putc(ascii_eot); +} + +void tftf_platform_watchdog_set(void) +{ + /* Placeholder function which should be redefined by each platform */ +} + +void tftf_platform_watchdog_reset(void) +{ + /* Placeholder function which should be redefined by each platform */ +} + +void tftf_plat_configure_mmu(void) +{ + /* RO data + Code */ + mmap_add_region(IMAGE_RO_BASE, IMAGE_RO_BASE, + IMAGE_RO_END - IMAGE_RO_BASE, MT_CODE); + + /* Data + BSS */ + mmap_add_region(IMAGE_RW_BASE, IMAGE_RW_BASE, + IMAGE_RW_END - IMAGE_RW_BASE, MT_RW_DATA); + +#if IMAGE_TFTF + mmap_add_region(COHERENT_RAM_START, COHERENT_RAM_START, + COHERENT_RAM_END - COHERENT_RAM_START, + MT_DEVICE | MT_RW | MT_NS); +#endif + + mmap_add(tftf_platform_get_mmap()); + init_xlat_tables(); + + tftf_plat_enable_mmu(); +} + +void tftf_plat_enable_mmu(void) +{ +#ifndef AARCH32 + if (IS_IN_EL1()) + enable_mmu_el1(0); + else if (IS_IN_EL2()) + enable_mmu_el2(0); + else + panic(); +#else + if (IS_IN_HYP()) + enable_mmu_hyp(0); + else + enable_mmu_svc_mon(0); +#endif +} + +void tftf_plat_reset(void) +{ + /* + * SP805 peripheral interrupt is not serviced in TFTF. The reset signal + * generated by it is used to reset the platform. + */ + sp805_wdog_start(1); + + /* + * Reset might take some execution cycles, Depending on the ratio between + * CPU clock frequency and Watchdog clock frequency + */ + while (1) + ; +} + +const mem_region_t *plat_get_prot_regions(int *nelem) +{ + *nelem = 0; + return NULL; +} diff --git a/plat/common/plat_state_id.c b/plat/common/plat_state_id.c new file mode 100644 index 000000000..ce43ba4a2 --- /dev/null +++ b/plat/common/plat_state_id.c @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <debug.h> +#include <platform.h> +#include <platform_def.h> +#include <psci.h> +#include <tftf.h> + +static unsigned int pstate_initialized; + +/* + * Stores pointer to the state_prop_t for all implemented levels + */ +static const plat_state_prop_t *plat_state_ptr[PLAT_MAX_PWR_LEVEL + 1]; + +/* + * Saves number of implemented power states per level + */ +static unsigned int power_states_per_level[PLAT_MAX_PWR_LEVEL + 1]; + +void tftf_init_pstate_framework(void) +{ + int i, j; + + if (pstate_initialized) + return; + + /* Detect the PSCI power state format used. */ + tftf_detect_psci_pstate_format(); + + /* + * Get and save the pointers to plat_state_prop_t values for all + * levels. Also, store the max number of local states possible for + * each level in power_states_per_level. + */ + for (i = 0; i <= PLAT_MAX_PWR_LEVEL; i++) { + plat_state_ptr[i] = plat_get_state_prop(i); + assert(plat_state_ptr[i]); + + for (j = 0; (plat_state_ptr[i]+j)->state_ID != 0; j++) + ; + + power_states_per_level[i] = j; + } + + pstate_initialized = 1; +} + +void tftf_set_next_state_id_idx(unsigned int power_level, + unsigned int pstate_id_idx[]) +{ + unsigned int i; +#if ENABLE_ASSERTIONS + /* Verify that this is a valid power level. */ + assert(power_level <= PLAT_MAX_PWR_LEVEL); + + /* + * Verify if a level has PWR_STATE_INIT_INDEX index, all higher levels + * have to be in PWR_STATE_INIT_INDEX. Not needed to check the top + * power level in the outer loop. + */ + for (i = 0; i < power_level; i++) { + if (pstate_id_idx[i] == PWR_STATE_INIT_INDEX) { + for ( ; i <= power_level; i++) + assert(pstate_id_idx[i] == PWR_STATE_INIT_INDEX); + } + } +#endif + + /* Increment the pstate_id_idx starting from the lowest power level */ + for (i = 0; i <= power_level; i++) { + pstate_id_idx[i]++; + + /* + * Wraparound index if the maximum power states available for + * that level is reached and proceed to next level. + */ + if (pstate_id_idx[i] == power_states_per_level[i]) + pstate_id_idx[i] = 0; + else + break; + } + + /* + * Check if the requested power level has wrapped around. If it has, + * reset pstate_id_idx. + */ + if (i > power_level) { + for (i = 0; i <= power_level; i++) + pstate_id_idx[i] = PWR_STATE_INIT_INDEX; + } +} + +void tftf_set_deepest_pstate_idx(unsigned int power_level, + unsigned int pstate_id_idx[]) +{ + int i; + + /* Verify that this is a valid power level. */ + assert(power_level <= PLAT_MAX_PWR_LEVEL); + + /* + * Assign the highest pstate_id_idx starting from the lowest power + * level + */ + for (i = 0; i <= power_level; i++) + pstate_id_idx[i] = power_states_per_level[i] - 1; +} + + +int tftf_get_pstate_vars(unsigned int *test_power_level, + unsigned int *test_suspend_type, + unsigned int *suspend_state_id, + unsigned int pstate_id_idx[]) +{ + unsigned int i; + int state_id = 0; + int suspend_type; + int suspend_depth; + int psci_ret = PSCI_E_SUCCESS; + const plat_state_prop_t *local_state; + + /* Atleast one entry should be valid to generate correct power state params */ + assert(pstate_id_idx[0] != PWR_STATE_INIT_INDEX && + pstate_id_idx[0] <= power_states_per_level[0]); + + suspend_depth = (plat_state_ptr[0] + pstate_id_idx[0])->suspend_depth; + suspend_type = (plat_state_ptr[0] + pstate_id_idx[0])->is_pwrdown; + + for (i = 0; i <= PLAT_MAX_PWR_LEVEL; i++) { + + /* Reached all levels with the valid power index values */ + if (pstate_id_idx[i] == PWR_STATE_INIT_INDEX) + break; + + assert(pstate_id_idx[i] <= power_states_per_level[i]); + + local_state = plat_state_ptr[i] + pstate_id_idx[i]; + state_id |= (local_state->state_ID << i * PLAT_LOCAL_PSTATE_WIDTH); + + if (local_state->is_pwrdown > suspend_type) + suspend_type = local_state->is_pwrdown; + + if (local_state->suspend_depth > suspend_depth) + psci_ret = PSCI_E_INVALID_PARAMS; + else + suspend_depth = local_state->suspend_depth; + } + + *test_suspend_type = suspend_type; + *suspend_state_id = state_id; + *test_power_level = --i; + + return psci_ret; +} + +void tftf_set_next_local_state_id_idx(unsigned int power_level, + unsigned int pstate_id_idx[]) +{ + assert(power_level <= PLAT_MAX_PWR_LEVEL); + + if (pstate_id_idx[power_level] + 1 >= power_states_per_level[power_level]) { + pstate_id_idx[power_level] = PWR_STATE_INIT_INDEX; + return; + } + + pstate_id_idx[power_level]++; +} diff --git a/plat/common/plat_topology.c b/plat/common/plat_topology.c new file mode 100644 index 000000000..a7920c37b --- /dev/null +++ b/plat/common/plat_topology.c @@ -0,0 +1,362 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <assert.h> +#include <debug.h> +#include <plat_topology.h> +#include <platform.h> +#include <stdlib.h> + +#define CPU_INDEX_IS_VALID(_cpu_idx) \ + (((_cpu_idx) - tftf_pwr_domain_start_idx[0]) < PLATFORM_CORE_COUNT) + +#define IS_A_CPU_NODE(_cpu_idx) (tftf_pd_nodes[(_cpu_idx)].level == 0) + +#define CPU_NODE_IS_VALID(_cpu_node) \ + (CPU_INDEX_IS_VALID(_cpu_node) && IS_A_CPU_NODE(_cpu_node)) + +/* + * Global variable to check that the platform topology is not queried until it + * has been setup. + */ +static unsigned int topology_setup_done; + +/* + * Store the start indices of power domains at various levels. This array makes it + * easier to traverse the topology tree if the power domain level is known. + */ +unsigned int tftf_pwr_domain_start_idx[PLATFORM_MAX_AFFLVL + 1]; + +/* The grand array to store the platform power domain topology */ +tftf_pwr_domain_node_t tftf_pd_nodes[PLATFORM_NUM_AFFS]; + +#if DEBUG +/* + * Debug function to display the platform topology. + * Does not print absent affinity instances. + */ +static void dump_topology(void) +{ + unsigned int cluster_idx, cpu_idx, count; + + NOTICE("Platform topology:\n"); + + NOTICE(" %u cluster(s)\n", tftf_get_total_clusters_count()); + NOTICE(" %u CPU(s) (total)\n\n", tftf_get_total_cpus_count()); + + for (cluster_idx = PWR_DOMAIN_INIT; + cluster_idx = tftf_get_next_peer_domain(cluster_idx, 1), + cluster_idx != PWR_DOMAIN_INIT;) { + count = 0; + for (cpu_idx = tftf_pd_nodes[cluster_idx].cpu_start_node; + cpu_idx < (tftf_pd_nodes[cluster_idx].cpu_start_node + + tftf_pd_nodes[cluster_idx].ncpus); + cpu_idx++) { + if (tftf_pd_nodes[cpu_idx].is_present) + count++; + } + NOTICE(" Cluster #%u [%u CPUs]\n", + cluster_idx - tftf_pwr_domain_start_idx[1], + count); + for (cpu_idx = PWR_DOMAIN_INIT; + cpu_idx = tftf_get_next_cpu_in_pwr_domain(cluster_idx, cpu_idx), + cpu_idx != PWR_DOMAIN_INIT;) { + NOTICE(" CPU #%u [MPID: 0x%x]\n", + cpu_idx - tftf_pwr_domain_start_idx[0], + tftf_get_mpidr_from_node(cpu_idx)); + } + } + NOTICE("\n"); +} +#endif + +unsigned int tftf_get_total_aff_count(unsigned int aff_lvl) +{ + unsigned int count = 0; + unsigned int node_idx; + + assert(topology_setup_done == 1); + + if (aff_lvl > PLATFORM_MAX_AFFLVL) + return count; + + node_idx = tftf_pwr_domain_start_idx[aff_lvl]; + + while (tftf_pd_nodes[node_idx].level == aff_lvl) { + if (tftf_pd_nodes[node_idx].is_present) + count++; + node_idx++; + } + + return count; +} + +unsigned int tftf_get_next_peer_domain(unsigned int pwr_domain_idx, + unsigned int pwr_lvl) +{ + assert(topology_setup_done == 1); + + assert(pwr_lvl <= PLATFORM_MAX_AFFLVL); + + if (pwr_domain_idx == PWR_DOMAIN_INIT) { + pwr_domain_idx = tftf_pwr_domain_start_idx[pwr_lvl]; + if (tftf_pd_nodes[pwr_domain_idx].is_present) + return pwr_domain_idx; + } + + assert(pwr_domain_idx < PLATFORM_NUM_AFFS && + tftf_pd_nodes[pwr_domain_idx].level == pwr_lvl); + + for (++pwr_domain_idx; (pwr_domain_idx < PLATFORM_NUM_AFFS) + && (tftf_pd_nodes[pwr_domain_idx].level == pwr_lvl); + pwr_domain_idx++) { + if (tftf_pd_nodes[pwr_domain_idx].is_present) + return pwr_domain_idx; + } + + return PWR_DOMAIN_INIT; +} + +unsigned int tftf_get_next_cpu_in_pwr_domain(unsigned int pwr_domain_idx, + unsigned int cpu_node) +{ + unsigned int cpu_end_node; + + assert(topology_setup_done == 1); + assert(pwr_domain_idx != PWR_DOMAIN_INIT + && pwr_domain_idx < PLATFORM_NUM_AFFS); + + if (cpu_node == PWR_DOMAIN_INIT) { + cpu_node = tftf_pd_nodes[pwr_domain_idx].cpu_start_node; + if (tftf_pd_nodes[cpu_node].is_present) + return cpu_node; + } + + assert(CPU_NODE_IS_VALID(cpu_node)); + + cpu_end_node = tftf_pd_nodes[pwr_domain_idx].cpu_start_node + + tftf_pd_nodes[pwr_domain_idx].ncpus - 1; + + assert(cpu_end_node < PLATFORM_NUM_AFFS); + + for (++cpu_node; cpu_node <= cpu_end_node; cpu_node++) { + if (tftf_pd_nodes[cpu_node].is_present) + return cpu_node; + } + + return PWR_DOMAIN_INIT; +} + +/* + * Helper function to get the parent nodes of a particular CPU power + * domain. + */ +static void get_parent_pwr_domain_nodes(unsigned int cpu_node, + unsigned int end_lvl, + unsigned int node_index[]) +{ + unsigned int parent_node = tftf_pd_nodes[cpu_node].parent_node; + unsigned int i; + + for (i = 1; i <= end_lvl; i++) { + node_index[i - 1] = parent_node; + parent_node = tftf_pd_nodes[parent_node].parent_node; + } +} + +/******************************************************************************* + * This function updates cpu_start_node and ncpus field for each of the nodes + * in tftf_pd_nodes[]. It does so by comparing the parent nodes of each of + * the CPUs and check whether they match with the parent of the previous + * CPU. The basic assumption for this work is that children of the same parent + * are allocated adjacent indices. The platform should ensure this through + * proper mapping of the CPUs to indices via platform_get_core_pos() API. + * + * It also updates the 'is_present' field for non-cpu power domains. It does + * this by checking the 'is_present' field of the child cpu nodes and updates + * it if any of the child cpu nodes are present. + *******************************************************************************/ +static void update_pwrlvl_limits(void) +{ + int cpu_id, j, is_present; + unsigned int nodes_idx[PLATFORM_MAX_AFFLVL] = {-1}; + unsigned int temp_index[PLATFORM_MAX_AFFLVL]; + + unsigned int cpu_node_offset = tftf_pwr_domain_start_idx[0]; + + for (cpu_id = 0; cpu_id < PLATFORM_CORE_COUNT; cpu_id++) { + get_parent_pwr_domain_nodes(cpu_id + cpu_node_offset, + PLATFORM_MAX_AFFLVL, + temp_index); + is_present = tftf_pd_nodes[cpu_id + cpu_node_offset].is_present; + + for (j = PLATFORM_MAX_AFFLVL - 1; j >= 0; j--) { + if (temp_index[j] != nodes_idx[j]) { + nodes_idx[j] = temp_index[j]; + tftf_pd_nodes[nodes_idx[j]].cpu_start_node + = cpu_id + cpu_node_offset; + if (!tftf_pd_nodes[nodes_idx[j]].is_present) + tftf_pd_nodes[nodes_idx[j]].is_present = is_present; + } + tftf_pd_nodes[nodes_idx[j]].ncpus++; + } + } +} + +/****************************************************************************** + * This function populates the power domain topology array 'tftf_pd_nodes[]' + * based on the power domain description retrieved from the platform layer. + * It also updates the start index of each power domain level in + * tftf_pwr_domain_start_idx[]. The uninitialized fields of 'tftf_pd_nodes[]' + * for the non CPU power domain will be initialized in update_pwrlvl_limits(). + *****************************************************************************/ +static void populate_power_domain_tree(void) +{ + unsigned int i, j = 0, num_nodes_at_lvl = 1, num_nodes_at_next_lvl, + node_index = 0, parent_idx = 0, num_children; + int num_level = PLATFORM_MAX_AFFLVL; + const unsigned char *plat_array; + + plat_array = tftf_plat_get_pwr_domain_tree_desc(); + + /* + * For each level the inputs are: + * - number of nodes at this level in plat_array i.e. num_nodes_at_lvl + * This is the sum of values of nodes at the parent level. + * - Index of first entry at this level in the plat_array i.e. + * parent_idx. + * - Index of first free entry in tftf_pd_nodes[]. + */ + while (num_level >= 0) { + num_nodes_at_next_lvl = 0; + + /* Store the start index for every level */ + tftf_pwr_domain_start_idx[num_level] = node_index; + + /* + * For each entry (parent node) at this level in the plat_array: + * - Find the number of children + * - Allocate a node in a power domain array for each child + * - Set the parent of the child to the parent_node_index - 1 + * - Increment parent_node_index to point to the next parent + * - Accumulate the number of children at next level. + */ + for (i = 0; i < num_nodes_at_lvl; i++) { + assert(parent_idx <= + PLATFORM_NUM_AFFS - PLATFORM_CORE_COUNT); + num_children = plat_array[parent_idx]; + + for (j = node_index; + j < node_index + num_children; j++) { + /* Initialize the power domain node */ + tftf_pd_nodes[j].parent_node = parent_idx - 1; + tftf_pd_nodes[j].level = num_level; + + /* Additional initializations for CPU power domains */ + if (num_level == 0) { + /* Calculate the cpu id from node index */ + int cpu_id = j - tftf_pwr_domain_start_idx[0]; + + assert(cpu_id < PLATFORM_CORE_COUNT); + + /* Set the mpidr of cpu node */ + tftf_pd_nodes[j].mpidr = + tftf_plat_get_mpidr(cpu_id); + if (tftf_pd_nodes[j].mpidr != INVALID_MPID) + tftf_pd_nodes[j].is_present = 1; + + tftf_pd_nodes[j].cpu_start_node = j; + tftf_pd_nodes[j].ncpus = 1; + } + } + node_index = j; + num_nodes_at_next_lvl += num_children; + parent_idx++; + } + + num_nodes_at_lvl = num_nodes_at_next_lvl; + num_level--; + } + + /* Validate the sanity of array exported by the platform */ + assert(j == PLATFORM_NUM_AFFS); +} + + +void tftf_init_topology(void) +{ + populate_power_domain_tree(); + update_pwrlvl_limits(); + topology_setup_done = 1; +#if DEBUG + dump_topology(); +#endif +} + +unsigned int tftf_topology_next_cpu(unsigned int cpu_node) +{ + assert(topology_setup_done == 1); + + if (cpu_node == PWR_DOMAIN_INIT) { + cpu_node = tftf_pwr_domain_start_idx[0]; + if (tftf_pd_nodes[cpu_node].is_present) + return cpu_node; + } + + assert(CPU_NODE_IS_VALID(cpu_node)); + + for (++cpu_node; cpu_node < PLATFORM_NUM_AFFS; cpu_node++) { + if (tftf_pd_nodes[cpu_node].is_present) + return cpu_node; + } + + return PWR_DOMAIN_INIT; +} + + +unsigned int tftf_get_mpidr_from_node(unsigned int cpu_node) +{ + assert(topology_setup_done == 1); + + assert(CPU_NODE_IS_VALID(cpu_node)); + + if (tftf_pd_nodes[cpu_node].is_present) + return tftf_pd_nodes[cpu_node].mpidr; + + return INVALID_MPID; +} + +unsigned int tftf_find_any_cpu_other_than(unsigned exclude_mpid) +{ + unsigned int cpu_node, mpidr; + + for_each_cpu(cpu_node) { + mpidr = tftf_get_mpidr_from_node(cpu_node); + if (mpidr != exclude_mpid) + return mpidr; + } + + return INVALID_MPID; +} + +unsigned int tftf_find_random_cpu_other_than(unsigned int exclude_mpid) +{ + unsigned int cpu_node, mpidr; + unsigned int possible_cpus_cnt = 0; + unsigned int possible_cpus[PLATFORM_CORE_COUNT]; + + for_each_cpu(cpu_node) { + mpidr = tftf_get_mpidr_from_node(cpu_node); + if (mpidr != exclude_mpid) + possible_cpus[possible_cpus_cnt++] = mpidr; + } + + if (possible_cpus_cnt == 0) + return INVALID_MPID; + + return possible_cpus[rand() % possible_cpus_cnt]; +} diff --git a/plat/common/tftf_nvm_accessors.c b/plat/common/tftf_nvm_accessors.c new file mode 100644 index 000000000..f6d003133 --- /dev/null +++ b/plat/common/tftf_nvm_accessors.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <io_storage.h> +#include <platform.h> +#include <platform_def.h> +#include <spinlock.h> +#include <status.h> +#include <string.h> +#include <tftf_lib.h> + +#if USE_NVM +/* Used to serialize write operations from different CPU's */ +static spinlock_t flash_access_lock; +#endif + +STATUS tftf_nvm_write(unsigned long long offset, const void *buffer, size_t size) +{ +#if USE_NVM + int ret; + uintptr_t nvm_handle; + size_t length_written; +#endif + + if (offset + size > TFTF_NVM_SIZE) + return STATUS_OUT_OF_RESOURCES; + +#if USE_NVM + /* Obtain a handle to the NVM by querying the platfom layer */ + plat_get_nvm_handle(&nvm_handle); + + spin_lock(&flash_access_lock); + + ret = io_seek(nvm_handle, IO_SEEK_SET, + offset + TFTF_NVM_OFFSET); + if (ret != IO_SUCCESS) + goto fail; + + ret = io_write(nvm_handle, (const uintptr_t)buffer, size, + &length_written); + if (ret != IO_SUCCESS) + goto fail; + + assert(length_written == size); +fail: + spin_unlock(&flash_access_lock); + + if (ret != IO_SUCCESS) + return STATUS_FAIL; + +#else + uintptr_t addr = DRAM_BASE + TFTF_NVM_OFFSET + offset; + memcpy((void *)addr, buffer, size); +#endif + + return STATUS_SUCCESS; +} + +STATUS tftf_nvm_read(unsigned long long offset, void *buffer, size_t size) +{ +#if USE_NVM + int ret; + uintptr_t nvm_handle; + size_t length_read; +#endif + + if (offset + size > TFTF_NVM_SIZE) + return STATUS_OUT_OF_RESOURCES; + +#if USE_NVM + /* Obtain a handle to the NVM by querying the platfom layer */ + plat_get_nvm_handle(&nvm_handle); + + spin_lock(&flash_access_lock); + + ret = io_seek(nvm_handle, IO_SEEK_SET, TFTF_NVM_OFFSET + offset); + if (ret != IO_SUCCESS) + goto fail; + + ret = io_read(nvm_handle, (uintptr_t)buffer, size, &length_read); + if (ret != IO_SUCCESS) + goto fail; + + assert(length_read == size); +fail: + spin_unlock(&flash_access_lock); + + if (ret != IO_SUCCESS) + return STATUS_FAIL; +#else + uintptr_t addr = DRAM_BASE + TFTF_NVM_OFFSET + offset; + memcpy(buffer, (void *)addr, size); +#endif + + return STATUS_SUCCESS; +} + |