GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)
This commit is contained in:
+167
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* 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 "../fpga_private.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_crash_console_init
|
||||
.globl plat_crash_console_putc
|
||||
.globl plat_crash_console_flush
|
||||
.globl plat_fpga_calc_core_pos
|
||||
|
||||
/* -----------------------------------------------------------------------
|
||||
* 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
|
||||
|
||||
/*
|
||||
* Wait for the primary processor to initialise the .BSS segment
|
||||
* to avoid a race condition that would erase fpga_valid_mpids
|
||||
* if it is populated before the C runtime is ready.
|
||||
*
|
||||
* We cannot use the current spin-lock implementation until the
|
||||
* runtime is up and we should not rely on sevl/wfe instructions as
|
||||
* it is optional whether they are implemented or not, so we use
|
||||
* a global variable as lock and wait for the primary processor to
|
||||
* finish the C runtime bring-up.
|
||||
*/
|
||||
|
||||
ldr w0, =C_RUNTIME_READY_KEY
|
||||
adrp x1, secondary_core_spinlock
|
||||
add x1, x1, :lo12:secondary_core_spinlock
|
||||
1:
|
||||
wfe
|
||||
ldr w2, [x1]
|
||||
cmp w2, w0
|
||||
b.ne 1b
|
||||
/* Prevent reordering of the store into fpga_valid_mpids below */
|
||||
dmb ish
|
||||
|
||||
mov x10, x30
|
||||
bl plat_my_core_pos
|
||||
mov x30, x10
|
||||
|
||||
adrp x4, fpga_valid_mpids
|
||||
add x4, x4, :lo12:fpga_valid_mpids
|
||||
mov x5, #VALID_MPID
|
||||
strb w5, [x4, x0]
|
||||
|
||||
/*
|
||||
* Poll the CPU's hold entry until it indicates to jump
|
||||
* to the entrypoint address.
|
||||
*/
|
||||
|
||||
adrp x1, hold_base
|
||||
add x1, x1, :lo12:hold_base
|
||||
poll_hold_entry:
|
||||
ldr x3, [x1, x0, LSL #PLAT_FPGA_HOLD_ENTRY_SHIFT]
|
||||
cmp x3, #PLAT_FPGA_HOLD_STATE_GO
|
||||
b.ne 1f
|
||||
|
||||
adrp x2, fpga_sec_entrypoint
|
||||
add x2, x2, :lo12:fpga_sec_entrypoint
|
||||
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
|
||||
ldr x1, =(MPID_MASK & ~(MPIDR_AFFLVL_MASK << MPIDR_AFF3_SHIFT))
|
||||
mrs x0, mpidr_el1
|
||||
and x0, x0, x1
|
||||
b plat_fpga_calc_core_pos
|
||||
|
||||
endfunc plat_my_core_pos
|
||||
|
||||
/* -----------------------------------------------------------------------
|
||||
* unsigned int plat_fpga_calc_core_pos (uint32_t mpid)
|
||||
* Clobber registers: x0 to x5
|
||||
* -----------------------------------------------------------------------
|
||||
*/
|
||||
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
|
||||
|
||||
mov x4, #FPGA_MAX_CPUS_PER_CLUSTER
|
||||
mov x5, #FPGA_MAX_PE_PER_CPU
|
||||
|
||||
/* Compute linear position */
|
||||
madd x1, x2, x4, x1
|
||||
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
|
||||
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
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2020, ARM Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Linker script for the Arm Ltd. FPGA boards to generate an ELF file that
|
||||
* contains the ROM trampoline, BL31 and the DTB.
|
||||
*
|
||||
* This allows to pass just one file to the uploader tool, and automatically
|
||||
* provides the correct load addresses.
|
||||
*/
|
||||
|
||||
#include <platform_def.h>
|
||||
|
||||
OUTPUT_FORMAT("elf64-littleaarch64")
|
||||
OUTPUT_ARCH(aarch64)
|
||||
|
||||
INPUT(./rom_trampoline.o)
|
||||
INPUT(./kernel_trampoline.o)
|
||||
|
||||
TARGET(binary)
|
||||
INPUT(./bl31.bin)
|
||||
INPUT(./fdts/arm_fpga.dtb)
|
||||
|
||||
ENTRY(_start)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.rom (0x0): {
|
||||
*rom_trampoline.o(.text*)
|
||||
KEEP(*(.rom))
|
||||
}
|
||||
|
||||
.bl31 (BL31_BASE): {
|
||||
ASSERT(. == ALIGN(PAGE_SIZE), "BL31_BASE is not page aligned");
|
||||
*bl31.bin
|
||||
}
|
||||
|
||||
.dtb (FPGA_PRELOADED_DTB_BASE): {
|
||||
ASSERT(. == ALIGN(8), "DTB address is not 8-byte aligned");
|
||||
*arm_fpga.dtb
|
||||
}
|
||||
|
||||
.kern_tramp (PRELOADED_BL33_BASE): {
|
||||
*kernel_trampoline.o(.text*)
|
||||
KEEP(*(.kern_tramp))
|
||||
}
|
||||
|
||||
/DISCARD/ : { *(stacks) }
|
||||
/DISCARD/ : { *(.debug_*) }
|
||||
/DISCARD/ : { *(.note*) }
|
||||
/DISCARD/ : { *(.comment*) }
|
||||
}
|
||||
+402
@@ -0,0 +1,402 @@
|
||||
/*
|
||||
* Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <common/fdt_fixup.h>
|
||||
#include <common/fdt_wrappers.h>
|
||||
#include <drivers/arm/gicv3.h>
|
||||
#include <drivers/delay_timer.h>
|
||||
#include <drivers/generic_delay_timer.h>
|
||||
#include <lib/extensions/spe.h>
|
||||
#include <lib/mmio.h>
|
||||
#include <libfdt.h>
|
||||
|
||||
#include "fpga_private.h"
|
||||
#include <plat/common/platform.h>
|
||||
#include <platform_def.h>
|
||||
|
||||
static entry_point_info_t bl33_image_ep_info;
|
||||
static unsigned int system_freq;
|
||||
volatile uint32_t secondary_core_spinlock;
|
||||
|
||||
uintptr_t plat_get_ns_image_entrypoint(void)
|
||||
{
|
||||
#ifdef PRELOADED_BL33_BASE
|
||||
return PRELOADED_BL33_BASE;
|
||||
#else
|
||||
return 0ULL;
|
||||
#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)
|
||||
{
|
||||
/* Add this core to the VALID mpids list */
|
||||
fpga_valid_mpids[plat_my_core_pos()] = VALID_MPID;
|
||||
|
||||
/*
|
||||
* Notify the secondary CPUs that the C runtime is ready
|
||||
* so they can announce themselves.
|
||||
*/
|
||||
secondary_core_spinlock = C_RUNTIME_READY_KEY;
|
||||
dsbish();
|
||||
sev();
|
||||
|
||||
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)
|
||||
{
|
||||
/* Write frequency to CNTCRL and initialize timer */
|
||||
generic_delay_timer_init();
|
||||
|
||||
/*
|
||||
* Before doing anything else, wait for some time to ensure that
|
||||
* the secondary CPUs have populated the fpga_valid_mpids array.
|
||||
* As the number of secondary cores is unknown and can even be 0,
|
||||
* it is not possible to rely on any signal from them, so use a
|
||||
* delay instead.
|
||||
*/
|
||||
mdelay(5);
|
||||
|
||||
/*
|
||||
* On the event of a cold reset issued by, for instance, a reset pin
|
||||
* assertion, we cannot guarantee memory to be initialized to zero.
|
||||
* In such scenario, if the secondary cores reached
|
||||
* plat_secondary_cold_boot_setup before the primary one initialized
|
||||
* .BSS, we could end up having a race condition if the spinlock
|
||||
* was not cleared before.
|
||||
*
|
||||
* Similarly, if there were a reset before the spinlock had been
|
||||
* cleared, the secondary cores would find the lock opened before
|
||||
* .BSS is cleared, causing another race condition.
|
||||
*
|
||||
* So clean the spinlock as soon as we think it is safe to reduce the
|
||||
* chances of any race condition on a reset.
|
||||
*/
|
||||
secondary_core_spinlock = 0UL;
|
||||
|
||||
/* Initialize the GIC driver, cpu and distributor interfaces */
|
||||
plat_fpga_gic_init();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Even though we sell the FPGA UART as an SBSA variant, it is actually
|
||||
* a full fledged PL011. So the baudrate divider registers exist.
|
||||
*/
|
||||
#ifndef UARTIBRD
|
||||
#define UARTIBRD 0x024
|
||||
#define UARTFBRD 0x028
|
||||
#endif
|
||||
|
||||
/* Round an integer to the closest multiple of a value. */
|
||||
static unsigned int round_multiple(unsigned int x, unsigned int multiple)
|
||||
{
|
||||
if (multiple < 2) {
|
||||
return x;
|
||||
}
|
||||
|
||||
return ((x + (multiple / 2 - 1)) / multiple) * multiple;
|
||||
}
|
||||
|
||||
#define PL011_FRAC_SHIFT 6
|
||||
#define FPGA_DEFAULT_BAUDRATE 38400
|
||||
#define PL011_OVERSAMPLING 16
|
||||
static unsigned int pl011_freq_from_divider(unsigned int divider)
|
||||
{
|
||||
unsigned int freq;
|
||||
|
||||
freq = divider * FPGA_DEFAULT_BAUDRATE * PL011_OVERSAMPLING;
|
||||
|
||||
return freq >> PL011_FRAC_SHIFT;
|
||||
}
|
||||
|
||||
/*
|
||||
* The FPGAs run most peripherals from one main clock, among them the CPUs,
|
||||
* the arch timer, and the UART baud base clock.
|
||||
* The SCP knows this frequency and programs the UART clock divider for a
|
||||
* 38400 bps baudrate. Recalculate the base input clock from there.
|
||||
*/
|
||||
static unsigned int fpga_get_system_frequency(void)
|
||||
{
|
||||
const void *fdt = (void *)(uintptr_t)FPGA_PRELOADED_DTB_BASE;
|
||||
int node, err;
|
||||
|
||||
/*
|
||||
* If the arch timer DT node has an explicit clock-frequency property
|
||||
* set, use that, to allow people overriding auto-detection.
|
||||
*/
|
||||
node = fdt_node_offset_by_compatible(fdt, 0, "arm,armv8-timer");
|
||||
if (node >= 0) {
|
||||
uint32_t freq;
|
||||
|
||||
err = fdt_read_uint32(fdt, node, "clock-frequency", &freq);
|
||||
if (err >= 0) {
|
||||
return freq;
|
||||
}
|
||||
}
|
||||
|
||||
node = fdt_node_offset_by_compatible(fdt, 0, "arm,pl011");
|
||||
if (node >= 0) {
|
||||
uintptr_t pl011_base;
|
||||
unsigned int divider;
|
||||
|
||||
err = fdt_get_reg_props_by_index(fdt, node, 0,
|
||||
&pl011_base, NULL);
|
||||
if (err >= 0) {
|
||||
divider = mmio_read_32(pl011_base + UARTIBRD);
|
||||
divider <<= PL011_FRAC_SHIFT;
|
||||
divider += mmio_read_32(pl011_base + UARTFBRD);
|
||||
|
||||
/*
|
||||
* The result won't be exact, due to rounding errors,
|
||||
* but the input frequency was a multiple of 250 KHz.
|
||||
*/
|
||||
return round_multiple(pl011_freq_from_divider(divider),
|
||||
250000);
|
||||
} else {
|
||||
WARN("Cannot read PL011 MMIO base\n");
|
||||
}
|
||||
} else {
|
||||
WARN("No PL011 DT node\n");
|
||||
}
|
||||
|
||||
/* No PL011 DT node or calculation failed. */
|
||||
return FPGA_DEFAULT_TIMER_FREQUENCY;
|
||||
}
|
||||
|
||||
unsigned int plat_get_syscnt_freq2(void)
|
||||
{
|
||||
if (system_freq == 0U) {
|
||||
system_freq = fpga_get_system_frequency();
|
||||
}
|
||||
|
||||
return system_freq;
|
||||
}
|
||||
|
||||
static void fpga_dtb_update_clock(void *fdt, unsigned int freq)
|
||||
{
|
||||
uint32_t freq_dtb = fdt32_to_cpu(freq);
|
||||
uint32_t phandle;
|
||||
int node, err;
|
||||
|
||||
node = fdt_node_offset_by_compatible(fdt, 0, "arm,pl011");
|
||||
if (node < 0) {
|
||||
WARN("%s(): No PL011 DT node found\n", __func__);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
err = fdt_read_uint32(fdt, node, "clocks", &phandle);
|
||||
if (err != 0) {
|
||||
WARN("Cannot find clocks property\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
node = fdt_node_offset_by_phandle(fdt, phandle);
|
||||
if (node < 0) {
|
||||
WARN("Cannot get phandle\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
err = fdt_setprop_inplace(fdt, node,
|
||||
"clock-frequency",
|
||||
&freq_dtb,
|
||||
sizeof(freq_dtb));
|
||||
if (err < 0) {
|
||||
WARN("Could not update DT baud clock frequency\n");
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#define CMDLINE_SIGNATURE "CMD:"
|
||||
|
||||
static int fpga_dtb_set_commandline(void *fdt, const char *cmdline)
|
||||
{
|
||||
int chosen;
|
||||
const char *eol;
|
||||
char nul = 0;
|
||||
int slen, err;
|
||||
|
||||
chosen = fdt_add_subnode(fdt, 0, "chosen");
|
||||
if (chosen == -FDT_ERR_EXISTS) {
|
||||
chosen = fdt_path_offset(fdt, "/chosen");
|
||||
}
|
||||
|
||||
if (chosen < 0) {
|
||||
return chosen;
|
||||
}
|
||||
|
||||
/*
|
||||
* There is most likely an EOL at the end of the
|
||||
* command line, make sure we terminate the line there.
|
||||
* We can't replace the EOL with a NUL byte in the
|
||||
* source, as this is in read-only memory. So we first
|
||||
* create the property without any termination, then
|
||||
* append a single NUL byte.
|
||||
*/
|
||||
eol = strchr(cmdline, '\n');
|
||||
if (eol == NULL) {
|
||||
eol = strchr(cmdline, 0);
|
||||
}
|
||||
/* Skip the signature and omit the EOL/NUL byte. */
|
||||
slen = eol - (cmdline + strlen(CMDLINE_SIGNATURE));
|
||||
/*
|
||||
* Let's limit the size of the property, just in case
|
||||
* we find the signature by accident. The Linux kernel
|
||||
* limits to 4096 characters at most (in fact 2048 for
|
||||
* arm64), so that sounds like a reasonable number.
|
||||
*/
|
||||
if (slen > 4095) {
|
||||
slen = 4095;
|
||||
}
|
||||
|
||||
err = fdt_setprop(fdt, chosen, "bootargs",
|
||||
cmdline + strlen(CMDLINE_SIGNATURE), slen);
|
||||
if (err != 0) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return fdt_appendprop(fdt, chosen, "bootargs", &nul, 1);
|
||||
}
|
||||
|
||||
static void fpga_prepare_dtb(void)
|
||||
{
|
||||
void *fdt = (void *)(uintptr_t)FPGA_PRELOADED_DTB_BASE;
|
||||
const char *cmdline = (void *)(uintptr_t)FPGA_PRELOADED_CMD_LINE;
|
||||
int err;
|
||||
|
||||
err = fdt_open_into(fdt, fdt, FPGA_MAX_DTB_SIZE);
|
||||
if (err < 0) {
|
||||
ERROR("cannot open devicetree at %p: %d\n", fdt, err);
|
||||
panic();
|
||||
}
|
||||
|
||||
/* Reserve memory used by Trusted Firmware. */
|
||||
if (fdt_add_reserved_memory(fdt, "tf-a@80000000", BL31_BASE,
|
||||
BL31_LIMIT - BL31_BASE)) {
|
||||
WARN("Failed to add reserved memory node to DT\n");
|
||||
}
|
||||
|
||||
/* Check for the command line signature. */
|
||||
if (!strncmp(cmdline, CMDLINE_SIGNATURE, strlen(CMDLINE_SIGNATURE))) {
|
||||
err = fpga_dtb_set_commandline(fdt, cmdline);
|
||||
if (err == 0) {
|
||||
INFO("using command line at 0x%x\n",
|
||||
FPGA_PRELOADED_CMD_LINE);
|
||||
} else {
|
||||
ERROR("failed to put command line into DTB: %d\n", err);
|
||||
}
|
||||
}
|
||||
|
||||
if (err < 0) {
|
||||
ERROR("Error %d extending Device Tree\n", err);
|
||||
panic();
|
||||
}
|
||||
|
||||
err = fdt_add_cpus_node(fdt, FPGA_MAX_PE_PER_CPU,
|
||||
FPGA_MAX_CPUS_PER_CLUSTER,
|
||||
FPGA_MAX_CLUSTER_COUNT);
|
||||
|
||||
if (err == -EEXIST) {
|
||||
WARN("Not overwriting already existing /cpus node in DTB\n");
|
||||
} else {
|
||||
if (err < 0) {
|
||||
ERROR("Error %d creating the /cpus DT node\n", err);
|
||||
panic();
|
||||
} else {
|
||||
unsigned int nr_cores = fpga_get_nr_gic_cores();
|
||||
|
||||
INFO("Adjusting GICR DT region to cover %u cores\n",
|
||||
nr_cores);
|
||||
err = fdt_adjust_gic_redist(fdt, nr_cores,
|
||||
fpga_get_redist_base(),
|
||||
fpga_get_redist_size());
|
||||
if (err < 0) {
|
||||
ERROR("Error %d fixing up GIC DT node\n", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fpga_dtb_update_clock(fdt, system_freq);
|
||||
|
||||
/* Check whether we support the SPE PMU. Remove the DT node if not. */
|
||||
if (!spe_supported()) {
|
||||
int node = fdt_node_offset_by_compatible(fdt, 0,
|
||||
"arm,statistical-profiling-extension-v1");
|
||||
|
||||
if (node >= 0) {
|
||||
fdt_del_node(fdt, node);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check whether we have an ITS. Remove the DT node if not. */
|
||||
if (!fpga_has_its()) {
|
||||
int node = fdt_node_offset_by_compatible(fdt, 0,
|
||||
"arm,gic-v3-its");
|
||||
|
||||
if (node >= 0) {
|
||||
fdt_del_node(fdt, node);
|
||||
}
|
||||
}
|
||||
|
||||
err = fdt_pack(fdt);
|
||||
if (err < 0) {
|
||||
ERROR("Failed to pack Device Tree at %p: error %d\n", fdt, err);
|
||||
}
|
||||
|
||||
clean_dcache_range((uintptr_t)fdt, fdt_blob_size(fdt));
|
||||
}
|
||||
|
||||
void bl31_plat_runtime_setup(void)
|
||||
{
|
||||
fpga_prepare_dtb();
|
||||
}
|
||||
|
||||
void bl31_plat_enable_mmu(uint32_t flags)
|
||||
{
|
||||
/* TODO: determine if MMU needs to be enabled */
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <common/fdt_wrappers.h>
|
||||
#include <drivers/arm/pl011.h>
|
||||
#include <drivers/console.h>
|
||||
|
||||
#include <platform_def.h>
|
||||
|
||||
static console_t console;
|
||||
|
||||
void fpga_console_init(void)
|
||||
{
|
||||
const void *fdt = (void *)(uintptr_t)FPGA_PRELOADED_DTB_BASE;
|
||||
uintptr_t base_addr = PLAT_FPGA_CRASH_UART_BASE;
|
||||
int node;
|
||||
|
||||
/*
|
||||
* Try to read the UART base address from the DT, by chasing the
|
||||
* stdout-path property of the chosen node.
|
||||
* If this does not work, use the crash console address as a fallback.
|
||||
*/
|
||||
node = fdt_get_stdout_node_offset(fdt);
|
||||
if (node >= 0) {
|
||||
fdt_get_reg_props_by_index(fdt, node, 0, &base_addr, NULL);
|
||||
}
|
||||
|
||||
(void)console_pl011_register(base_addr, 0, 0, &console);
|
||||
|
||||
console_set_scope(&console, CONSOLE_FLAG_BOOT |
|
||||
CONSOLE_FLAG_RUNTIME);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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 4
|
||||
#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, just for the crash console, as a fallback.
|
||||
* The actual console UART address is taken from the DT.
|
||||
*/
|
||||
#define PLAT_FPGA_CRASH_UART_BASE 0x7ff80000
|
||||
|
||||
#define FPGA_DEFAULT_TIMER_FREQUENCY 10000000
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2021, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <common/debug.h>
|
||||
#include <common/fdt_wrappers.h>
|
||||
#include <drivers/arm/arm_gicv3_common.h>
|
||||
#include <drivers/arm/gic_common.h>
|
||||
#include <drivers/arm/gicv3.h>
|
||||
#include <lib/mmio.h>
|
||||
#include <libfdt.h>
|
||||
|
||||
#include <platform_def.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 int nr_itses;
|
||||
|
||||
static unsigned int fpga_mpidr_to_core_pos(unsigned long mpidr)
|
||||
{
|
||||
return (unsigned int)plat_core_pos_by_mpidr(mpidr);
|
||||
}
|
||||
|
||||
static gicv3_driver_data_t fpga_gicv3_driver_data = {
|
||||
.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)
|
||||
{
|
||||
const void *fdt = (void *)(uintptr_t)FPGA_PRELOADED_DTB_BASE;
|
||||
uintptr_t gicr_base = 0U;
|
||||
uint32_t iidr;
|
||||
int node, ret;
|
||||
|
||||
node = fdt_node_offset_by_compatible(fdt, 0, "arm,gic-v3");
|
||||
if (node < 0) {
|
||||
WARN("No \"arm,gic-v3\" compatible node found in DT, no GIC support.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* TODO: Assuming only empty "ranges;" properties up the bus path. */
|
||||
ret = fdt_get_reg_props_by_index(fdt, node, 0,
|
||||
&fpga_gicv3_driver_data.gicd_base, NULL);
|
||||
if (ret < 0) {
|
||||
WARN("Could not read GIC distributor address from DT.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
iidr = mmio_read_32(fpga_gicv3_driver_data.gicd_base + GICD_IIDR);
|
||||
if (((iidr & IIDR_MODEL_MASK) == IIDR_MODEL_ARM_GIC_600) ||
|
||||
((iidr & IIDR_MODEL_MASK) == IIDR_MODEL_ARM_GIC_700)) {
|
||||
unsigned int frame_id;
|
||||
|
||||
/*
|
||||
* According to the GIC TRMs, if there are any ITSes, they
|
||||
* start four 64K pages after the distributor. After all
|
||||
* the ITSes then follow the redistributors.
|
||||
*/
|
||||
gicr_base = fpga_gicv3_driver_data.gicd_base + (4U << 16);
|
||||
|
||||
do {
|
||||
uint64_t its_typer;
|
||||
|
||||
/* Each GIC component can be identified by its ID. */
|
||||
frame_id = gicv3_get_component_partnum(gicr_base);
|
||||
|
||||
if (frame_id == PIDR_COMPONENT_ARM_REDIST) {
|
||||
INFO("Found %d ITSes, redistributors start at 0x%llx\n",
|
||||
nr_itses, (unsigned long long)gicr_base);
|
||||
break;
|
||||
}
|
||||
|
||||
if (frame_id != PIDR_COMPONENT_ARM_ITS) {
|
||||
WARN("GICv3: found unexpected frame 0x%x\n",
|
||||
frame_id);
|
||||
gicr_base = 0U;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Found an ITS, now work out if it supports virtual
|
||||
* SGIs (for direct guest injection). If yes, each
|
||||
* ITS occupies four 64K pages, otherwise just two.
|
||||
*/
|
||||
its_typer = mmio_read_64(gicr_base + GITS_TYPER);
|
||||
if ((its_typer & GITS_TYPER_VSGI) != 0U) {
|
||||
gicr_base += 4U << 16;
|
||||
} else {
|
||||
gicr_base += 2U << 16;
|
||||
}
|
||||
nr_itses++;
|
||||
} while (true);
|
||||
}
|
||||
|
||||
/*
|
||||
* If this is not a GIC-600 or -700, or the autodetection above failed,
|
||||
* use the base address from the device tree.
|
||||
*/
|
||||
if (gicr_base == 0U) {
|
||||
ret = fdt_get_reg_props_by_index(fdt, node, 1,
|
||||
&fpga_gicv3_driver_data.gicr_base,
|
||||
NULL);
|
||||
if (ret < 0) {
|
||||
WARN("Could not read GIC redistributor address from DT.\n");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
fpga_gicv3_driver_data.gicr_base = gicr_base;
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
unsigned int fpga_get_nr_gic_cores(void)
|
||||
{
|
||||
return gicv3_rdistif_get_number_frames(fpga_gicv3_driver_data.gicr_base);
|
||||
}
|
||||
|
||||
uintptr_t fpga_get_redist_size(void)
|
||||
{
|
||||
uint64_t typer_val = mmio_read_64(fpga_gicv3_driver_data.gicr_base +
|
||||
GICR_TYPER);
|
||||
|
||||
return gicv3_redist_size(typer_val);
|
||||
}
|
||||
|
||||
uintptr_t fpga_get_redist_base(void)
|
||||
{
|
||||
return fpga_gicv3_driver_data.gicr_base;
|
||||
}
|
||||
|
||||
bool fpga_has_its(void)
|
||||
{
|
||||
return nr_itses > 0;
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
int pos = plat_core_pos_by_mpidr(mpidr);
|
||||
unsigned long current_mpidr = read_mpidr_el1();
|
||||
|
||||
if (pos < 0) {
|
||||
panic();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef FPGA_PRIVATE_H
|
||||
#define FPGA_PRIVATE_H
|
||||
|
||||
#include "../fpga_def.h"
|
||||
#include <platform_def.h>
|
||||
|
||||
#define C_RUNTIME_READY_KEY (0xaa55aa55)
|
||||
#define VALID_MPID (1U)
|
||||
#define FPGA_MAX_DTB_SIZE 0x10000
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
extern unsigned char fpga_valid_mpids[PLATFORM_CORE_COUNT];
|
||||
|
||||
void fpga_console_init(void);
|
||||
|
||||
void plat_fpga_gic_init(void);
|
||||
void fpga_pwr_gic_on_finish(void);
|
||||
void fpga_pwr_gic_off(void);
|
||||
unsigned int plat_fpga_calc_core_pos(uint32_t mpid);
|
||||
unsigned int fpga_get_nr_gic_cores(void);
|
||||
uintptr_t fpga_get_redist_size(void);
|
||||
uintptr_t fpga_get_redist_base(void);
|
||||
bool fpga_has_its(void);
|
||||
|
||||
#endif /* __ASSEMBLER__ */
|
||||
|
||||
#endif /* FPGA_PRIVATE_H */
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <arch_helpers.h>
|
||||
#include <common/debug.h>
|
||||
#include <lib/spinlock.h>
|
||||
|
||||
#include "fpga_private.h"
|
||||
#include <plat/common/platform.h>
|
||||
#include <platform_def.h>
|
||||
|
||||
unsigned char fpga_power_domain_tree_desc[FPGA_MAX_CLUSTER_COUNT + 2];
|
||||
unsigned char fpga_valid_mpids[PLATFORM_CORE_COUNT];
|
||||
|
||||
const unsigned char *plat_get_power_domain_tree_desc(void)
|
||||
{
|
||||
unsigned 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.
|
||||
*
|
||||
* A description of the topology tree can be found at
|
||||
* https://trustedfirmware-a.readthedocs.io/en/latest/design/psci-pd-tree.html#design
|
||||
*/
|
||||
|
||||
if (fpga_power_domain_tree_desc[0] == 0U) {
|
||||
/*
|
||||
* As fpga_power_domain_tree_desc[0] == 0, assume that the
|
||||
* Power Domain Topology Tree has not been initialized, so
|
||||
* perform the initialization here.
|
||||
*/
|
||||
|
||||
fpga_power_domain_tree_desc[0] = 1U;
|
||||
fpga_power_domain_tree_desc[1] = FPGA_MAX_CLUSTER_COUNT;
|
||||
|
||||
for (i = 0U; i < FPGA_MAX_CLUSTER_COUNT; i++) {
|
||||
fpga_power_domain_tree_desc[2 + i] =
|
||||
(FPGA_MAX_CPUS_PER_CLUSTER *
|
||||
FPGA_MAX_PE_PER_CPU);
|
||||
}
|
||||
}
|
||||
|
||||
return fpga_power_domain_tree_desc;
|
||||
}
|
||||
|
||||
int plat_core_pos_by_mpidr(u_register_t mpidr)
|
||||
{
|
||||
unsigned int core_pos;
|
||||
|
||||
mpidr &= (MPID_MASK & ~(MPIDR_AFFLVL_MASK << MPIDR_AFF3_SHIFT));
|
||||
mpidr |= (read_mpidr_el1() & MPIDR_MT_MASK);
|
||||
|
||||
if ((MPIDR_AFFLVL2_VAL(mpidr) >= FPGA_MAX_CLUSTER_COUNT) ||
|
||||
(MPIDR_AFFLVL1_VAL(mpidr) >= FPGA_MAX_CPUS_PER_CLUSTER) ||
|
||||
(MPIDR_AFFLVL0_VAL(mpidr) >= FPGA_MAX_PE_PER_CPU)) {
|
||||
ERROR ("Invalid mpidr: 0x%08x\n", (uint32_t)mpidr);
|
||||
panic();
|
||||
}
|
||||
|
||||
/* Calculate the core position, based on the maximum topology. */
|
||||
core_pos = plat_fpga_calc_core_pos(mpidr);
|
||||
|
||||
/* Check whether this core is actually present. */
|
||||
if (fpga_valid_mpids[core_pos] != VALID_MPID) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return core_pos;
|
||||
}
|
||||
+13
@@ -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
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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(0x80070000)
|
||||
#else
|
||||
#define BL31_BASE UL(0x0)
|
||||
#define BL31_LIMIT UL(0x01000000)
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
||||
#endif
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2021, ARM Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* The traditional arm64 Linux kernel load address is 512KiB from the
|
||||
* beginning of DRAM, caused by this having been the default value of the
|
||||
* kernel's CONFIG_TEXT_OFFSET Kconfig value.
|
||||
* However kernel version 5.8 changed the default offset (into a 2MB page)
|
||||
* to 0, so TF-A's default assumption is no longer true. Fortunately the
|
||||
* kernel got more relaxed about this offset at the same time, so it
|
||||
* tolerates the wrong offset, but issues a warning:
|
||||
* [Firmware Bug]: Kernel image misaligned at boot, please fix your bootloader!
|
||||
*
|
||||
* We cannot easily change the load address offset in TF-A to be 2MiB, because
|
||||
* this would break older kernels - and they are not as forgiving in this
|
||||
* respect.
|
||||
*
|
||||
* But we can allow users to load the kernel at the right offset, and
|
||||
* offer this trampoline here to transition to this new load address.
|
||||
* Any older kernels, or newer kernels misloaded, will overwrite this code
|
||||
* here, so it does no harm in this case.
|
||||
*/
|
||||
|
||||
#include <asm_macros.S>
|
||||
#include <common/bl_common.ld.h>
|
||||
|
||||
.text
|
||||
.global _tramp_start
|
||||
|
||||
_tramp_start:
|
||||
adr x4, _tramp_start
|
||||
orr x4, x4, #0x1fffff
|
||||
add x4, x4, #1 /* align up to 2MB */
|
||||
br x4
|
||||
@@ -0,0 +1,130 @@
|
||||
#
|
||||
# Copyright (c) 2021-2022, Arm Limited. All rights reserved.
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
#
|
||||
|
||||
include common/fdt_wrappers.mk
|
||||
include lib/libfdt/libfdt.mk
|
||||
|
||||
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
|
||||
|
||||
PRELOADED_BL33_BASE := 0x80080000
|
||||
|
||||
FPGA_PRELOADED_DTB_BASE := 0x80070000
|
||||
$(eval $(call add_define,FPGA_PRELOADED_DTB_BASE))
|
||||
|
||||
FPGA_PRELOADED_CMD_LINE := 0x1000
|
||||
$(eval $(call add_define,FPGA_PRELOADED_CMD_LINE))
|
||||
|
||||
ENABLE_AMU := 1
|
||||
|
||||
# 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
|
||||
|
||||
PL011_GENERIC_UART := 1
|
||||
|
||||
SUPPORT_UNKNOWN_MPID ?= 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/cortex_a78.S \
|
||||
lib/cpus/aarch64/neoverse_n_common.S \
|
||||
lib/cpus/aarch64/neoverse_n1.S \
|
||||
lib/cpus/aarch64/neoverse_n2.S \
|
||||
lib/cpus/aarch64/neoverse_e1.S \
|
||||
lib/cpus/aarch64/neoverse_v1.S \
|
||||
lib/cpus/aarch64/cortex_a78_ae.S \
|
||||
lib/cpus/aarch64/cortex_a65.S \
|
||||
lib/cpus/aarch64/cortex_a65ae.S \
|
||||
lib/cpus/aarch64/cortex_a510.S \
|
||||
lib/cpus/aarch64/cortex_a710.S \
|
||||
lib/cpus/aarch64/cortex_a715.S \
|
||||
lib/cpus/aarch64/cortex_x3.S \
|
||||
lib/cpus/aarch64/cortex_a78c.S
|
||||
|
||||
# AArch64/AArch32 cores
|
||||
FPGA_CPU_LIBS += lib/cpus/aarch64/cortex_a55.S \
|
||||
lib/cpus/aarch64/cortex_a75.S
|
||||
endif
|
||||
|
||||
ifeq (${SUPPORT_UNKNOWN_MPID}, 1)
|
||||
# Add support for unknown/invalid MPIDs (aarch64 only)
|
||||
$(eval $(call add_define,SUPPORT_UNKNOWN_MPID))
|
||||
FPGA_CPU_LIBS += lib/cpus/aarch64/generic.S
|
||||
endif
|
||||
|
||||
# Allow detection of GIC-600
|
||||
GICV3_SUPPORT_GIC600 := 1
|
||||
|
||||
GIC_ENABLE_V4_EXTN := 1
|
||||
|
||||
# Include GICv3 driver files
|
||||
include drivers/arm/gic/v3/gicv3.mk
|
||||
|
||||
FPGA_GIC_SOURCES := ${GICV3_SOURCES} \
|
||||
plat/common/plat_gicv3.c \
|
||||
plat/arm/board/arm_fpga/fpga_gicv3.c
|
||||
|
||||
FDT_SOURCES := fdts/arm_fpga.dts
|
||||
|
||||
PLAT_INCLUDES := -Iplat/arm/board/arm_fpga/include
|
||||
|
||||
PLAT_BL_COMMON_SOURCES := plat/arm/board/arm_fpga/${ARCH}/fpga_helpers.S
|
||||
|
||||
BL31_SOURCES += common/fdt_fixup.c \
|
||||
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}
|
||||
|
||||
BL31_SOURCES += ${FDT_WRAPPERS_SOURCES}
|
||||
|
||||
$(eval $(call MAKE_S,$(BUILD_PLAT),plat/arm/board/arm_fpga/rom_trampoline.S,bl31))
|
||||
$(eval $(call MAKE_S,$(BUILD_PLAT),plat/arm/board/arm_fpga/kernel_trampoline.S,bl31))
|
||||
$(eval $(call MAKE_LD,$(BUILD_PLAT)/build_axf.ld,plat/arm/board/arm_fpga/build_axf.ld.S,bl31))
|
||||
|
||||
bl31.axf: bl31 dtbs ${BUILD_PLAT}/rom_trampoline.o ${BUILD_PLAT}/kernel_trampoline.o ${BUILD_PLAT}/build_axf.ld
|
||||
$(ECHO) " LD $@"
|
||||
$(Q)$(LD) -T ${BUILD_PLAT}/build_axf.ld -L ${BUILD_PLAT} --strip-debug -s -n -o ${BUILD_PLAT}/bl31.axf
|
||||
|
||||
all: bl31.axf
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2020, ARM Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* The Arm Ltd. FPGA images start execution at address 0x0, which is
|
||||
* mapped at an (emulated) ROM image. The payload uploader can write to
|
||||
* this memory, but write access by the CPU cores is prohibited.
|
||||
*
|
||||
* Provide a simple trampoline to start BL31 execution at the actual
|
||||
* load address. We put the DTB address in x0, so any code in DRAM could
|
||||
* make use of that information (not yet used in BL31 right now).
|
||||
*/
|
||||
|
||||
#include <asm_macros.S>
|
||||
#include <common/bl_common.ld.h>
|
||||
|
||||
.text
|
||||
.global _start
|
||||
|
||||
_start:
|
||||
mov_imm x1, BL31_BASE /* beginning of DRAM */
|
||||
mov_imm x0, FPGA_PRELOADED_DTB_BASE
|
||||
br x1
|
||||
Reference in New Issue
Block a user