Merge changes from topic "os/bl31-fpga-port" into integration
* changes:
plat/arm/board/arm_fpga: Compile with additional CPU libraries
plat/arm/board/arm_fpga: Enable position-independent execution
plat/arm/board/arm_fpga: Enable port for alternative cluster configurations
plat/arm/board/arm_fpga: Initialize the Generic Interrupt Controller
plat/arm/board/arm_fpga: Initialize the System Counter
plat/arm/board/arm_fpga: Add PSCI implementation for FPGA images
plat/arm/board/arm_fpga: Use preloaded BL33 alternative boot flow
plat/arm/board/arm_fpga: Enable basic BL31 port for an FPGA image
diff --git a/plat/arm/board/arm_fpga/aarch64/fpga_helpers.S b/plat/arm/board/arm_fpga/aarch64/fpga_helpers.S
new file mode 100644
index 0000000..f350455
--- /dev/null
+++ b/plat/arm/board/arm_fpga/aarch64/fpga_helpers.S
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <platform_def.h>
+
+ .globl plat_get_my_entrypoint
+ .globl plat_secondary_cold_boot_setup
+ .globl plat_is_my_cpu_primary
+ .globl platform_mem_init
+ .globl plat_my_core_pos
+ .globl plat_fpga_calc_core_pos
+ .globl plat_crash_console_init
+ .globl plat_crash_console_putc
+ .globl plat_crash_console_flush
+
+/* -----------------------------------------------------------------------
+ * Indicate a cold boot for every CPU - warm boot is unsupported for the
+ * holding pen PSCI implementation.
+ * -----------------------------------------------------------------------
+ */
+func plat_get_my_entrypoint
+ mov x0, #0
+ ret
+endfunc plat_get_my_entrypoint
+
+/* -----------------------------------------------------------------------
+ * void plat_secondary_cold_boot_setup (void);
+ * -----------------------------------------------------------------------
+ */
+func plat_secondary_cold_boot_setup
+ /*
+ * Poll the CPU's hold entry until it indicates to jump
+ * to the entrypoint address.
+ */
+ bl plat_my_core_pos
+ lsl x0, x0, #PLAT_FPGA_HOLD_ENTRY_SHIFT
+ ldr x1, =hold_base
+ ldr x2, =fpga_sec_entrypoint
+poll_hold_entry:
+ ldr x3, [x1, x0]
+ cmp x3, #PLAT_FPGA_HOLD_STATE_GO
+ b.ne 1f
+ ldr x3, [x2]
+ br x3
+1:
+ wfe
+ b poll_hold_entry
+endfunc plat_secondary_cold_boot_setup
+
+/* -----------------------------------------------------------------------
+ * unsigned int plat_is_my_cpu_primary (void);
+ *
+ * Find out whether the current cpu is the primary cpu
+ * -----------------------------------------------------------------------
+ */
+func plat_is_my_cpu_primary
+ mrs x0, mpidr_el1
+ mov_imm x1, MPIDR_AFFINITY_MASK
+ and x0, x0, x1
+ cmp x0, #FPGA_PRIMARY_CPU
+ cset w0, eq
+ ret
+endfunc plat_is_my_cpu_primary
+
+func platform_mem_init
+ ret
+endfunc platform_mem_init
+
+func plat_my_core_pos
+ mrs x0, mpidr_el1
+ b plat_fpga_calc_core_pos
+endfunc plat_my_core_pos
+
+/* -----------------------------------------------------------------------
+ * unsigned int plat_fpga_calc_core_pos(u_register_t mpidr)
+ * -----------------------------------------------------------------------
+ */
+func plat_fpga_calc_core_pos
+ /*
+ * Check for MT bit in MPIDR, which may be either value for images
+ * running on the FPGA.
+ *
+ * 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 x4, #FPGA_MAX_CPUS_PER_CLUSTER
+ madd x1, x2, x4, x1
+ mov x5, #FPGA_MAX_PE_PER_CPU
+ madd x0, x1, x5, x0
+ ret
+endfunc plat_fpga_calc_core_pos
+
+func plat_crash_console_init
+ mov_imm x0, PLAT_FPGA_CRASH_UART_BASE
+ mov_imm x1, PLAT_FPGA_CRASH_UART_CLK_IN_HZ
+ mov_imm x2, PLAT_FPGA_CONSOLE_BAUDRATE
+ b console_pl011_core_init
+endfunc plat_crash_console_init
+
+func plat_crash_console_putc
+ mov_imm x1, PLAT_FPGA_CRASH_UART_BASE
+ b console_pl011_core_putc
+endfunc plat_crash_console_putc
+
+func plat_crash_console_flush
+ mov_imm x0, PLAT_FPGA_CRASH_UART_BASE
+ b console_pl011_core_flush
+endfunc plat_crash_console_flush
diff --git a/plat/arm/board/arm_fpga/fpga_bl31_setup.c b/plat/arm/board/arm_fpga/fpga_bl31_setup.c
new file mode 100644
index 0000000..d499379
--- /dev/null
+++ b/plat/arm/board/arm_fpga/fpga_bl31_setup.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <lib/mmio.h>
+#include <drivers/generic_delay_timer.h>
+
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#include "fpga_private.h"
+
+static entry_point_info_t bl33_image_ep_info;
+
+uintptr_t plat_get_ns_image_entrypoint(void)
+{
+#ifdef PRELOADED_BL33_BASE
+ return PRELOADED_BL33_BASE;
+#else
+ return 0;
+#endif
+}
+
+uint32_t fpga_get_spsr_for_bl33_entry(void)
+{
+ return SPSR_64(MODE_EL2, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
+}
+
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+ u_register_t arg2, u_register_t arg3)
+{
+ fpga_console_init();
+
+ bl33_image_ep_info.pc = plat_get_ns_image_entrypoint();
+ bl33_image_ep_info.spsr = fpga_get_spsr_for_bl33_entry();
+ SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
+
+ /* Set x0-x3 for the primary CPU as expected by the kernel */
+ bl33_image_ep_info.args.arg0 = (u_register_t)FPGA_PRELOADED_DTB_BASE;
+ bl33_image_ep_info.args.arg1 = 0U;
+ bl33_image_ep_info.args.arg2 = 0U;
+ bl33_image_ep_info.args.arg3 = 0U;
+}
+
+void bl31_plat_arch_setup(void)
+{
+}
+
+void bl31_platform_setup(void)
+{
+ /* Initialize the GIC driver, cpu and distributor interfaces */
+ plat_fpga_gic_init();
+
+ /* Write frequency to CNTCRL and initialize timer */
+ generic_delay_timer_init();
+ mmio_write_32(FPGA_TIMER_BASE, ((1 << 8) | 1UL));
+}
+
+entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+ entry_point_info_t *next_image_info;
+ next_image_info = &bl33_image_ep_info;
+
+ /* Only expecting BL33: the kernel will run in EL2NS */
+ assert(type == NON_SECURE);
+
+ /* None of the images can have 0x0 as the entrypoint */
+ if (next_image_info->pc) {
+ return next_image_info;
+ } else {
+ return NULL;
+ }
+}
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+ return FPGA_TIMER_FREQUENCY;
+}
+
+void bl31_plat_enable_mmu(uint32_t flags)
+{
+ /* TODO: determine if MMU needs to be enabled */
+}
diff --git a/plat/arm/board/arm_fpga/fpga_console.c b/plat/arm/board/arm_fpga/fpga_console.c
new file mode 100644
index 0000000..b4ebf34
--- /dev/null
+++ b/plat/arm/board/arm_fpga/fpga_console.c
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/console.h>
+#include <drivers/arm/pl011.h>
+
+#include <platform_def.h>
+
+static console_t console;
+
+void fpga_console_init(void)
+{
+ (void)console_pl011_register(PLAT_FPGA_BOOT_UART_BASE,
+ PLAT_FPGA_BOOT_UART_CLK_IN_HZ,
+ PLAT_FPGA_CONSOLE_BAUDRATE,
+ &console);
+
+ console_set_scope(&console, CONSOLE_FLAG_BOOT |
+ CONSOLE_FLAG_RUNTIME);
+}
diff --git a/plat/arm/board/arm_fpga/fpga_def.h b/plat/arm/board/arm_fpga/fpga_def.h
new file mode 100644
index 0000000..56ee166
--- /dev/null
+++ b/plat/arm/board/arm_fpga/fpga_def.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/utils_def.h>
+
+#ifndef FPGA_DEF_H
+#define FPGA_DEF_H
+
+/*
+ * These are set to large values to account for images describing systems with
+ * larger cluster configurations.
+ *
+ * For cases where the number of clusters, cores or threads is smaller than a
+ * maximum value below, this does not affect the PSCI functionality as any PEs
+ * that are present will still be indexed appropriately regardless of any empty
+ * entries in the array used to represent the topology.
+ */
+#define FPGA_MAX_CLUSTER_COUNT 2
+#define FPGA_MAX_CPUS_PER_CLUSTER 8
+#define FPGA_MAX_PE_PER_CPU 4
+
+#define FPGA_PRIMARY_CPU 0x0
+
+/*******************************************************************************
+ * FPGA image memory map related constants
+ ******************************************************************************/
+
+/* UART base address and clock frequency, as configured by the image */
+#define PLAT_FPGA_BOOT_UART_BASE 0x7ff80000
+#define PLAT_FPGA_BOOT_UART_CLK_IN_HZ 10000000
+
+#define PLAT_FPGA_CRASH_UART_BASE PLAT_FPGA_BOOT_UART_BASE
+#define PLAT_FPGA_CRASH_UART_CLK_IN_HZ PLAT_FPGA_BOOT_UART_CLK_IN_HZ
+
+#define FPGA_TIMER_FREQUENCY 10000000
+#define FPGA_TIMER_BASE 0x2a830000
+
+#endif
diff --git a/plat/arm/board/arm_fpga/fpga_gicv3.c b/plat/arm/board/arm_fpga/fpga_gicv3.c
new file mode 100644
index 0000000..be1684e
--- /dev/null
+++ b/plat/arm/board/arm_fpga/fpga_gicv3.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/arm/gicv3.h>
+#include <drivers/arm/gic_common.h>
+
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+static const interrupt_prop_t fpga_interrupt_props[] = {
+ PLATFORM_G1S_PROPS(INTR_GROUP1S),
+ PLATFORM_G0_PROPS(INTR_GROUP0)
+};
+
+static uintptr_t fpga_rdistif_base_addrs[PLATFORM_CORE_COUNT];
+
+static unsigned int fpga_mpidr_to_core_pos(unsigned long mpidr)
+{
+ return (unsigned int)plat_core_pos_by_mpidr(mpidr);
+}
+
+static const gicv3_driver_data_t fpga_gicv3_driver_data = {
+ .gicd_base = GICD_BASE,
+ .gicr_base = GICR_BASE,
+ .interrupt_props = fpga_interrupt_props,
+ .interrupt_props_num = ARRAY_SIZE(fpga_interrupt_props),
+ .rdistif_num = PLATFORM_CORE_COUNT,
+ .rdistif_base_addrs = fpga_rdistif_base_addrs,
+ .mpidr_to_core_pos = fpga_mpidr_to_core_pos
+};
+
+void plat_fpga_gic_init(void)
+{
+ gicv3_driver_init(&fpga_gicv3_driver_data);
+ gicv3_distif_init();
+ gicv3_rdistif_init(plat_my_core_pos());
+ gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+void fpga_pwr_gic_on_finish(void)
+{
+ gicv3_rdistif_init(plat_my_core_pos());
+ gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+void fpga_pwr_gic_off(void)
+{
+ gicv3_cpuif_disable(plat_my_core_pos());
+ gicv3_rdistif_off(plat_my_core_pos());
+}
diff --git a/plat/arm/board/arm_fpga/fpga_pm.c b/plat/arm/board/arm_fpga/fpga_pm.c
new file mode 100644
index 0000000..4c37217
--- /dev/null
+++ b/plat/arm/board/arm_fpga/fpga_pm.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <lib/psci/psci.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+#include "fpga_private.h"
+#include <platform_def.h>
+
+/*
+ * This is a basic PSCI implementation that allows secondary CPUs to be
+ * released from their initial state and continue to the warm boot entrypoint.
+ *
+ * The secondary CPUs are placed in a holding pen and released by calls
+ * to fpga_pwr_domain_on(mpidr), which updates the hold entry for the CPU
+ * specified by the mpidr argument - the (polling) target CPU will then branch
+ * to the BL31 warm boot sequence at the entrypoint address.
+ *
+ * Additionally, the secondary CPUs are kept in a low-power wfe() state
+ * (placed there at the end of each poll) and woken when necessary through
+ * calls to sev() in fpga_pwr_domain_on(mpidr), once the hold state for the
+ * relevant CPU has been updated.
+ *
+ * Hotplug is currently implemented using a wfi-loop, which removes the
+ * dependencies on any power controllers or other mechanism that is specific
+ * to the running system as specified by the FPGA image.
+ */
+
+uint64_t hold_base[PLATFORM_CORE_COUNT];
+uintptr_t fpga_sec_entrypoint;
+
+/*
+ * Calls to the CPU specified by the mpidr will set its hold entry to a value
+ * indicating that it should stop polling and branch off to the warm entrypoint.
+ */
+static int fpga_pwr_domain_on(u_register_t mpidr)
+{
+ unsigned int pos = plat_core_pos_by_mpidr(mpidr);
+ unsigned long current_mpidr = read_mpidr_el1();
+
+ if (mpidr == current_mpidr) {
+ return PSCI_E_ALREADY_ON;
+ }
+ hold_base[pos] = PLAT_FPGA_HOLD_STATE_GO;
+ flush_dcache_range((uintptr_t)&hold_base[pos], sizeof(uint64_t));
+ sev(); /* Wake any CPUs from wfe */
+
+ return PSCI_E_SUCCESS;
+}
+
+void fpga_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+ fpga_pwr_gic_on_finish();
+}
+
+static void fpga_pwr_domain_off(const psci_power_state_t *target_state)
+{
+ fpga_pwr_gic_off();
+
+ while (1) {
+ wfi();
+ }
+}
+
+static void fpga_cpu_standby(plat_local_state_t cpu_state)
+{
+ /*
+ * Enter standby state
+ * dsb is good practice before using wfi to enter low power states
+ */
+ u_register_t scr = read_scr_el3();
+ write_scr_el3(scr|SCR_IRQ_BIT);
+ dsb();
+ wfi();
+ write_scr_el3(scr);
+}
+
+plat_psci_ops_t plat_fpga_psci_pm_ops = {
+ .pwr_domain_on = fpga_pwr_domain_on,
+ .pwr_domain_on_finish = fpga_pwr_domain_on_finish,
+ .pwr_domain_off = fpga_pwr_domain_off,
+ .cpu_standby = fpga_cpu_standby
+};
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+ const plat_psci_ops_t **psci_ops)
+{
+ fpga_sec_entrypoint = sec_entrypoint;
+ flush_dcache_range((uint64_t)&fpga_sec_entrypoint,
+ sizeof(fpga_sec_entrypoint));
+ *psci_ops = &plat_fpga_psci_pm_ops;
+ return 0;
+}
diff --git a/plat/arm/board/arm_fpga/fpga_private.h b/plat/arm/board/arm_fpga/fpga_private.h
new file mode 100644
index 0000000..7545bd1
--- /dev/null
+++ b/plat/arm/board/arm_fpga/fpga_private.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FPGA_PRIVATE_H
+#define FPGA_PRIVATE_H
+
+unsigned int plat_fpga_calc_core_pos(u_register_t mpidr);
+
+void fpga_console_init(void);
+
+void plat_fpga_gic_init(void);
+void fpga_pwr_gic_on_finish(void);
+void fpga_pwr_gic_off(void);
+
+#endif
diff --git a/plat/arm/board/arm_fpga/fpga_topology.c b/plat/arm/board/arm_fpga/fpga_topology.c
new file mode 100644
index 0000000..a705429
--- /dev/null
+++ b/plat/arm/board/arm_fpga/fpga_topology.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+
+#include "fpga_private.h"
+#include <platform_def.h>
+
+static unsigned char fpga_power_domain_tree_desc[FPGA_MAX_CLUSTER_COUNT + 2];
+
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+ int i;
+ /*
+ * The highest level is the system level. The next level is constituted
+ * by clusters and then cores in clusters.
+ *
+ * This description of the power domain topology is aligned with the CPU
+ * indices returned by the plat_core_pos_by_mpidr() and plat_my_core_pos()
+ * APIs.
+ */
+ fpga_power_domain_tree_desc[0] = 1;
+ fpga_power_domain_tree_desc[1] = FPGA_MAX_CLUSTER_COUNT;
+
+ for (i = 0; i < FPGA_MAX_CLUSTER_COUNT; i++) {
+ fpga_power_domain_tree_desc[i + 2] = FPGA_MAX_CPUS_PER_CLUSTER;
+ }
+
+ return fpga_power_domain_tree_desc;
+}
+
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+ unsigned int cluster_id, cpu_id, thread_id;
+
+ mpidr &= MPIDR_AFFINITY_MASK;
+ if (mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)) {
+ return -1;
+ }
+
+ if (mpidr & MPIDR_MT_MASK) {
+ thread_id = MPIDR_AFFLVL0_VAL(mpidr);
+ } else {
+ thread_id = 0;
+ }
+
+ cpu_id = MPIDR_AFFLVL1_VAL(mpidr);
+ cluster_id = MPIDR_AFFLVL2_VAL(mpidr);
+
+ if (cluster_id >= FPGA_MAX_CLUSTER_COUNT) {
+ return -1;
+ } else if (cpu_id >= FPGA_MAX_CPUS_PER_CLUSTER) {
+ return -1;
+ } else if (thread_id >= FPGA_MAX_PE_PER_CPU) {
+ return -1;
+ }
+
+ /*
+ * The image running on the FPGA may or may not implement multithreading,
+ * and it shouldn't be assumed this is consistent across all CPUs.
+ * This ensures that any passed mpidr values reflect the status of the
+ * primary CPU's MT bit.
+ */
+ mpidr |= (read_mpidr_el1() & MPIDR_MT_MASK);
+
+ /* Calculate the correct core, catering for multi-threaded images */
+ return (int) plat_fpga_calc_core_pos(mpidr);
+}
diff --git a/plat/arm/board/arm_fpga/include/plat_macros.S b/plat/arm/board/arm_fpga/include/plat_macros.S
new file mode 100644
index 0000000..44cddeb
--- /dev/null
+++ b/plat/arm/board/arm_fpga/include/plat_macros.S
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+.macro plat_crash_print_regs
+.endm
+
+#endif
diff --git a/plat/arm/board/arm_fpga/include/platform_def.h b/plat/arm/board/arm_fpga/include/platform_def.h
new file mode 100644
index 0000000..5c8aff6
--- /dev/null
+++ b/plat/arm/board/arm_fpga/include/platform_def.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include <plat/common/common_def.h>
+#include <platform_def.h>
+#include "../fpga_def.h"
+
+#define PLATFORM_LINKER_FORMAT "elf64-littleaarch64"
+
+#define PLATFORM_LINKER_ARCH aarch64
+
+#define PLATFORM_STACK_SIZE UL(0x800)
+
+#define CACHE_WRITEBACK_SHIFT U(6)
+#define CACHE_WRITEBACK_GRANULE (U(1) << CACHE_WRITEBACK_SHIFT)
+
+#define PLATFORM_CORE_COUNT \
+ (FPGA_MAX_CLUSTER_COUNT * FPGA_MAX_CPUS_PER_CLUSTER * FPGA_MAX_PE_PER_CPU)
+
+#define PLAT_NUM_PWR_DOMAINS (FPGA_MAX_CLUSTER_COUNT + \
+ PLATFORM_CORE_COUNT) + 1
+
+#if !ENABLE_PIE
+#define BL31_BASE UL(0x80000000)
+#define BL31_LIMIT UL(0x80100000)
+#else
+#define BL31_BASE UL(0x0)
+#define BL31_LIMIT UL(0x01000000)
+#endif
+
+#define GICD_BASE 0x30000000
+#define GICR_BASE 0x30040000
+
+#define PLAT_SDEI_NORMAL_PRI 0x70
+
+#define ARM_IRQ_SEC_PHY_TIMER 29
+
+#define ARM_IRQ_SEC_SGI_0 8
+#define ARM_IRQ_SEC_SGI_1 9
+#define ARM_IRQ_SEC_SGI_2 10
+#define ARM_IRQ_SEC_SGI_3 11
+#define ARM_IRQ_SEC_SGI_4 12
+#define ARM_IRQ_SEC_SGI_5 13
+#define ARM_IRQ_SEC_SGI_6 14
+#define ARM_IRQ_SEC_SGI_7 15
+
+/*
+ * Define a list of Group 1 Secure and Group 0 interrupt properties as per GICv3
+ * terminology. On a GICv2 system or mode, the lists will be merged and treated
+ * as Group 0 interrupts.
+ */
+#define PLATFORM_G1S_PROPS(grp) \
+ INTR_PROP_DESC(ARM_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, (grp), \
+ GIC_INTR_CFG_LEVEL), \
+ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, (grp), \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, (grp), \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, (grp), \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, (grp), \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, (grp), \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, (grp), \
+ GIC_INTR_CFG_EDGE)
+
+#define PLATFORM_G0_PROPS(grp) \
+ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_0, PLAT_SDEI_NORMAL_PRI, (grp), \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, (grp), \
+ GIC_INTR_CFG_EDGE)
+
+#define PLAT_MAX_RET_STATE 1
+#define PLAT_MAX_OFF_STATE 2
+
+#define PLAT_MAX_PWR_LVL MPIDR_AFFLVL2
+
+#define PLAT_FPGA_HOLD_ENTRY_SHIFT 3
+#define PLAT_FPGA_HOLD_STATE_WAIT 0
+#define PLAT_FPGA_HOLD_STATE_GO 1
+
+#define PLAT_FPGA_CONSOLE_BAUDRATE 38400
+
+#endif
diff --git a/plat/arm/board/arm_fpga/platform.mk b/plat/arm/board/arm_fpga/platform.mk
new file mode 100644
index 0000000..b4f38fa
--- /dev/null
+++ b/plat/arm/board/arm_fpga/platform.mk
@@ -0,0 +1,93 @@
+#
+# Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+RESET_TO_BL31 := 1
+ifeq (${RESET_TO_BL31}, 0)
+$(error "This is a BL31-only port; RESET_TO_BL31 must be enabled")
+endif
+
+ifeq (${ENABLE_PIE}, 1)
+override SEPARATE_CODE_AND_RODATA := 1
+endif
+
+CTX_INCLUDE_AARCH32_REGS := 0
+ifeq (${CTX_INCLUDE_AARCH32_REGS}, 1)
+$(error "This is an AArch64-only port; CTX_INCLUDE_AARCH32_REGS must be disabled")
+endif
+
+ifeq (${TRUSTED_BOARD_BOOT}, 1)
+$(error "TRUSTED_BOARD_BOOT must be disabled")
+endif
+
+ifndef PRELOADED_BL33_BASE
+$(error "PRELOADED_BL33_BASE is not set")
+endif
+
+ifndef FPGA_PRELOADED_DTB_BASE
+$(error "FPGA_PRELOADED_DTB_BASE is not set")
+else
+$(eval $(call add_define,FPGA_PRELOADED_DTB_BASE))
+endif
+
+# Treating this as a memory-constrained port for now
+USE_COHERENT_MEM := 0
+
+# This can be overridden depending on CPU(s) used in the FPGA image
+HW_ASSISTED_COHERENCY := 1
+
+FPGA_CPU_LIBS := lib/cpus/${ARCH}/aem_generic.S
+
+# select a different set of CPU files, depending on whether we compile for
+# hardware assisted coherency cores or not
+ifeq (${HW_ASSISTED_COHERENCY}, 0)
+# Cores used without DSU
+ FPGA_CPU_LIBS += lib/cpus/aarch64/cortex_a35.S \
+ lib/cpus/aarch64/cortex_a53.S \
+ lib/cpus/aarch64/cortex_a57.S \
+ lib/cpus/aarch64/cortex_a72.S \
+ lib/cpus/aarch64/cortex_a73.S
+else
+# AArch64-only cores
+ FPGA_CPU_LIBS += lib/cpus/aarch64/cortex_a76.S \
+ lib/cpus/aarch64/cortex_a76ae.S \
+ lib/cpus/aarch64/cortex_a77.S \
+ lib/cpus/aarch64/neoverse_n1.S \
+ lib/cpus/aarch64/neoverse_e1.S \
+ lib/cpus/aarch64/neoverse_zeus.S \
+ lib/cpus/aarch64/cortex_hercules.S \
+ lib/cpus/aarch64/cortex_hercules_ae.S \
+ lib/cpus/aarch64/cortex_a65.S \
+ lib/cpus/aarch64/cortex_a65ae.S
+# AArch64/AArch32 cores
+ FPGA_CPU_LIBS += lib/cpus/aarch64/cortex_a55.S \
+ lib/cpus/aarch64/cortex_a75.S
+endif
+
+FPGA_GIC_SOURCES := drivers/arm/gic/v3/gicv3_helpers.c \
+ drivers/arm/gic/v3/gicdv3_helpers.c \
+ drivers/arm/gic/v3/gicrv3_helpers.c \
+ drivers/arm/gic/v3/gicv3_main.c \
+ drivers/arm/gic/v3/gic600.c \
+ drivers/arm/gic/common/gic_common.c \
+ plat/common/plat_gicv3.c \
+ plat/arm/board/arm_fpga/fpga_gicv3.c
+
+PLAT_INCLUDES := -Iplat/arm/board/arm_fpga/include
+
+PLAT_BL_COMMON_SOURCES := plat/arm/board/arm_fpga/${ARCH}/fpga_helpers.S
+
+BL31_SOURCES += drivers/delay_timer/delay_timer.c \
+ drivers/delay_timer/generic_delay_timer.c \
+ drivers/arm/pl011/${ARCH}/pl011_console.S \
+ plat/common/plat_psci_common.c \
+ plat/arm/board/arm_fpga/fpga_pm.c \
+ plat/arm/board/arm_fpga/fpga_topology.c \
+ plat/arm/board/arm_fpga/fpga_console.c \
+ plat/arm/board/arm_fpga/fpga_bl31_setup.c \
+ ${FPGA_CPU_LIBS} \
+ ${FPGA_GIC_SOURCES}
+
+all: bl31