plat/arm/board/arm_fpga: Add PSCI implementation for FPGA images

This adds a basic PSCI implementation allow secondary CPUs to be
released from an initial state and continue through to the warm boot
entrypoint.

Each secondary CPU is kept in a holding pen, whereby it polls the value
representing its hold state, by reading this from an array that acts as
a table for all the PEs. The hold states are initially set to 0 for all
cores to indicate that the executing core should continue polling.
To prevent the secondary CPUs from interfering with the platform's
initialization, they are only updated by the primary CPU once the cold
boot sequence has completed and fpga_pwr_domain_on(mpidr) is called.
The polling target CPU will then read 1 (which indicates that it should
branch to the warm reset entrypoint) and then jump to that address
rather than continue polling.

In addition to the initial polling behaviour of the secondary CPUs
before their warm boot reset sequence, they are also placed in a
low-power wfe() state at the end of each poll; accordingly, the PSCI
fpga_pwr_domain_on(mpidr) function also signals an event to all cores
(after updating the target CPU's hold entry) to wake them from this
state, allowing any secondary CPUs that are still polling to check
their hold state again.
This method is in accordance with both the PSCI and Linux kernel
recommendations, as the lessened overhead reduces the energy
consumption associated with the busy-loop.

The table of hold entries is implemented by a global array as shared SRAM
(which is used by other platforms in similar implementations) is not
available on the FPGA images.

Signed-off-by: Oliver Swede <oli.swede@arm.com>
Change-Id: I65cfd1892f8be1dfcb285f0e1e94e7a9870cdf5a
diff --git a/plat/arm/board/arm_fpga/aarch64/fpga_helpers.S b/plat/arm/board/arm_fpga/aarch64/fpga_helpers.S
index 57e5320..f350455 100644
--- a/plat/arm/board/arm_fpga/aarch64/fpga_helpers.S
+++ b/plat/arm/board/arm_fpga/aarch64/fpga_helpers.S
@@ -20,8 +20,8 @@
 	.globl	plat_crash_console_flush
 
 /* -----------------------------------------------------------------------
- * unsigned long plat_get_my_entrypoint (void);
- * TODO: determine if warm boot should be supported for FPGA images
+ * Indicate a cold boot for every CPU - warm boot is unsupported for the
+ * holding pen PSCI implementation.
  * -----------------------------------------------------------------------
  */
 func plat_get_my_entrypoint
@@ -31,11 +31,26 @@
 
 /* -----------------------------------------------------------------------
  * void plat_secondary_cold_boot_setup (void);
- * TODO: add placeholder PSCI implementation for FPGA images
  * -----------------------------------------------------------------------
  */
 func plat_secondary_cold_boot_setup
-	ret
+	/*
+	 * 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
 
 /* -----------------------------------------------------------------------
@@ -64,11 +79,30 @@
 
 /* -----------------------------------------------------------------------
  * unsigned int plat_fpga_calc_core_pos(u_register_t mpidr)
- * TODO: add calculation of the core position for FPGA image CPUs
  * -----------------------------------------------------------------------
  */
 func plat_fpga_calc_core_pos
-	mov	x0, #0
+	/*
+	 * 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