arm-trusted-firmware/plat/arm/board/arm_fpga/aarch64/fpga_helpers.S

125 lines
3.3 KiB
ArmAsm
Raw Normal View History

/*
* 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
/* -----------------------------------------------------------------------
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
2019-12-02 13:21:52 +00:00
* 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
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
2019-12-02 13:21:52 +00:00
/*
* 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
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
2019-12-02 13:21:52 +00:00
/*
* 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