Merge changes from topic "raspberry-pi-4-support" into integration
* changes: rpi4: Add initial documentation file rpi4: Add stdout-path to device tree rpi4: Add GIC maintenance interrupt to GIC DT node rpi4: Cleanup memory regions, move pens to first page rpi4: Reserve resident BL31 region from non-secure world rpi4: Amend DTB to advertise PSCI rpi4: Determine BL33 entry point at runtime rpi4: Accommodate "armstub8.bin" header at the beginning of BL31 image Add basic support for Raspberry Pi 4 rpi3: Allow runtime determination of UART base clock rate FDT helper functions: Respect architecture in PSCI function IDs FDT helper functions: Add function documentation
This commit is contained in:
commit
17b0bb6cf5
|
@ -29,6 +29,33 @@ static int append_psci_compatible(void *fdt, int offs, const char *str)
|
||||||
return fdt_appendprop(fdt, offs, "compatible", str, strlen(str) + 1);
|
return fdt_appendprop(fdt, offs, "compatible", str, strlen(str) + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Those defines are for PSCI v0.1 legacy clients, which we expect to use
|
||||||
|
* the same execution state (AArch32/AArch64) as TF-A.
|
||||||
|
* Kernels running in AArch32 on an AArch64 TF-A should use PSCI v0.2.
|
||||||
|
*/
|
||||||
|
#ifdef __aarch64__
|
||||||
|
#define PSCI_CPU_SUSPEND_FNID PSCI_CPU_SUSPEND_AARCH64
|
||||||
|
#define PSCI_CPU_ON_FNID PSCI_CPU_ON_AARCH64
|
||||||
|
#else
|
||||||
|
#define PSCI_CPU_SUSPEND_FNID PSCI_CPU_SUSPEND_AARCH32
|
||||||
|
#define PSCI_CPU_ON_FNID PSCI_CPU_ON_AARCH32
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* dt_add_psci_node() - Add a PSCI node into an existing device tree
|
||||||
|
* @fdt: pointer to the device tree blob in memory
|
||||||
|
*
|
||||||
|
* Add a device tree node describing PSCI into the root level of an existing
|
||||||
|
* device tree blob in memory.
|
||||||
|
* This will add v0.1, v0.2 and v1.0 compatible strings and the standard
|
||||||
|
* function IDs for v0.1 compatibility.
|
||||||
|
* An existing PSCI node will not be touched, the function will return success
|
||||||
|
* in this case. This function will not touch the /cpus enable methods, use
|
||||||
|
* dt_add_psci_cpu_enable_methods() for that.
|
||||||
|
*
|
||||||
|
* Return: 0 on success, -1 otherwise.
|
||||||
|
******************************************************************************/
|
||||||
int dt_add_psci_node(void *fdt)
|
int dt_add_psci_node(void *fdt)
|
||||||
{
|
{
|
||||||
int offs;
|
int offs;
|
||||||
|
@ -52,15 +79,11 @@ int dt_add_psci_node(void *fdt)
|
||||||
return -1;
|
return -1;
|
||||||
if (fdt_setprop_string(fdt, offs, "method", "smc"))
|
if (fdt_setprop_string(fdt, offs, "method", "smc"))
|
||||||
return -1;
|
return -1;
|
||||||
if (fdt_setprop_u32(fdt, offs, "cpu_suspend", PSCI_CPU_SUSPEND_AARCH64))
|
if (fdt_setprop_u32(fdt, offs, "cpu_suspend", PSCI_CPU_SUSPEND_FNID))
|
||||||
return -1;
|
return -1;
|
||||||
if (fdt_setprop_u32(fdt, offs, "cpu_off", PSCI_CPU_OFF))
|
if (fdt_setprop_u32(fdt, offs, "cpu_off", PSCI_CPU_OFF))
|
||||||
return -1;
|
return -1;
|
||||||
if (fdt_setprop_u32(fdt, offs, "cpu_on", PSCI_CPU_ON_AARCH64))
|
if (fdt_setprop_u32(fdt, offs, "cpu_on", PSCI_CPU_ON_FNID))
|
||||||
return -1;
|
|
||||||
if (fdt_setprop_u32(fdt, offs, "sys_poweroff", PSCI_SYSTEM_OFF))
|
|
||||||
return -1;
|
|
||||||
if (fdt_setprop_u32(fdt, offs, "sys_reset", PSCI_SYSTEM_RESET))
|
|
||||||
return -1;
|
return -1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -113,6 +136,17 @@ static int dt_update_one_cpu_node(void *fdt, int offset)
|
||||||
return offs;
|
return offs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* dt_add_psci_cpu_enable_methods() - switch CPU nodes in DT to use PSCI
|
||||||
|
* @fdt: pointer to the device tree blob in memory
|
||||||
|
*
|
||||||
|
* Iterate over all CPU device tree nodes (/cpus/cpu@x) in memory to change
|
||||||
|
* the enable-method to PSCI. This will add the enable-method properties, if
|
||||||
|
* required, or will change existing properties to read "psci".
|
||||||
|
*
|
||||||
|
* Return: 0 on success, or a negative error value otherwise.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
int dt_add_psci_cpu_enable_methods(void *fdt)
|
int dt_add_psci_cpu_enable_methods(void *fdt)
|
||||||
{
|
{
|
||||||
int offs, ret;
|
int offs, ret;
|
||||||
|
@ -130,6 +164,25 @@ int dt_add_psci_cpu_enable_methods(void *fdt)
|
||||||
|
|
||||||
#define HIGH_BITS(x) ((sizeof(x) > 4) ? ((x) >> 32) : (typeof(x))0)
|
#define HIGH_BITS(x) ((sizeof(x) > 4) ? ((x) >> 32) : (typeof(x))0)
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* fdt_add_reserved_memory() - reserve (secure) memory regions in DT
|
||||||
|
* @dtb: pointer to the device tree blob in memory
|
||||||
|
* @node_name: name of the subnode to be used
|
||||||
|
* @base: physical base address of the reserved region
|
||||||
|
* @size: size of the reserved region
|
||||||
|
*
|
||||||
|
* Add a region of memory to the /reserved-memory node in a device tree in
|
||||||
|
* memory, creating that node if required. Each region goes into a subnode
|
||||||
|
* of that node and has a @node_name, a @base address and a @size.
|
||||||
|
* This will prevent any device tree consumer from using that memory. It
|
||||||
|
* can be used to announce secure memory regions, as it adds the "no-map"
|
||||||
|
* property to prevent mapping and speculative operations on that region.
|
||||||
|
*
|
||||||
|
* See reserved-memory/reserved-memory.txt in the (Linux kernel) DT binding
|
||||||
|
* documentation for details.
|
||||||
|
*
|
||||||
|
* Return: 0 on success, a negative error value otherwise.
|
||||||
|
******************************************************************************/
|
||||||
int fdt_add_reserved_memory(void *dtb, const char *node_name,
|
int fdt_add_reserved_memory(void *dtb, const char *node_name,
|
||||||
uintptr_t base, size_t size)
|
uintptr_t base, size_t size)
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
Raspberry Pi 4
|
||||||
|
==============
|
||||||
|
|
||||||
|
The `Raspberry Pi 4`_ is an inexpensive single-board computer that contains four
|
||||||
|
Arm Cortex-A72 cores. Also in contrast to previous Raspberry Pi versions this
|
||||||
|
model has a GICv2 interrupt controller.
|
||||||
|
|
||||||
|
This port is a minimal port to support loading non-secure EL2 payloads such
|
||||||
|
as a 64-bit Linux kernel. Other payloads such as U-Boot or EDK-II should work
|
||||||
|
as well, but have not been tested at this point.
|
||||||
|
|
||||||
|
**IMPORTANT NOTE**: This port isn't secure. All of the memory used is DRAM,
|
||||||
|
which is available from both the Non-secure and Secure worlds. The SoC does
|
||||||
|
not seem to feature a secure memory controller of any kind, so portions of
|
||||||
|
DRAM can't be protected properly from the Non-secure world.
|
||||||
|
|
||||||
|
Build Instructions
|
||||||
|
------------------
|
||||||
|
|
||||||
|
There are no real configuration options at this point, so there is only
|
||||||
|
one universal binary (bl31.bin), which can be built with:
|
||||||
|
|
||||||
|
.. code:: shell
|
||||||
|
|
||||||
|
CROSS_COMPILE=aarch64-linux-gnu- make PLAT=rpi4 DEBUG=1
|
||||||
|
|
||||||
|
Copy the generated build/rpi4/debug/bl31.bin to the SD card, either
|
||||||
|
renaming it to ``armstub8.bin`` or adding an entry starting with ``armstub=``,
|
||||||
|
then followed by the respective file name to ``config.txt``.
|
||||||
|
You should have AArch64 code in the file loaded as the "kernel", as BL31
|
||||||
|
will drop into AArch64/EL2 to the respective load address.
|
||||||
|
arm64 Linux kernels are known to work this way.
|
||||||
|
|
||||||
|
Other options that should be set in ``config.txt`` to properly boot 64-bit
|
||||||
|
kernels are:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
enable_uart=1
|
||||||
|
arm_64bit=1
|
||||||
|
enable_gic=1
|
||||||
|
|
||||||
|
The BL31 code will patch the provided device tree blob in memory to advertise
|
||||||
|
PSCI support, also will add a reserved-memory node to the DT to tell the
|
||||||
|
non-secure payload to not touch the resident TF-A code.
|
||||||
|
|
||||||
|
If you connect a serial cable between the Mini UART and your computer, and
|
||||||
|
connect to it (for example, with ``screen /dev/ttyUSB0 115200``) you should
|
||||||
|
see some text from BL31, followed by the output of the EL2 payload.
|
||||||
|
The command line provided is read from the ``cmdline.txt`` file on the SD card.
|
||||||
|
|
||||||
|
TF-A port design
|
||||||
|
----------------
|
||||||
|
|
||||||
|
In contrast to the existing Raspberry Pi 3 port this one here is a BL31-only
|
||||||
|
port, also it deviates quite a lot from the RPi3 port in many other ways.
|
||||||
|
There is not so much difference between the two models, so eventually those
|
||||||
|
two could be (more) unified in the future.
|
||||||
|
|
||||||
|
As with the previous models, the GPU and its firmware are the first entity to
|
||||||
|
run after the SoC gets its power. The on-chip Boot ROM loads the next stage
|
||||||
|
(bootcode.bin) from flash (EEPROM), which is again GPU code.
|
||||||
|
This part knows how to access the MMC controller and how to parse a FAT
|
||||||
|
filesystem, so it will load further compononents and configuration files
|
||||||
|
from the first FAT partition on the SD card.
|
||||||
|
|
||||||
|
To accommodate this existing way of configuring and setting up the board,
|
||||||
|
we use as much of this workflow as possible.
|
||||||
|
If bootcode.bin finds a file called ``armstub8.bin`` on the SD card or it gets
|
||||||
|
pointed to such code by finding a ``armstub=`` key in ``config.txt``, it will
|
||||||
|
load this file to the beginning of DRAM (address 0) and execute it in
|
||||||
|
AArch64 EL3.
|
||||||
|
But before doing that, it will also load a "kernel" and the device tree into
|
||||||
|
memory. The load addresses have a default, but can also be changed by
|
||||||
|
setting them in ``config.txt``. If the GPU firmware finds a magic value in the
|
||||||
|
armstub image file, it will put those two load addresses in memory locations
|
||||||
|
near the beginning of memory, where TF-A code picks them up.
|
||||||
|
|
||||||
|
To keep things simple, we will just use the kernel load address as the BL33
|
||||||
|
entry point, also put the DTB address in the x0 register, as requested by
|
||||||
|
the arm64 Linux kernel boot protocol. This does not necessarily mean that
|
||||||
|
the EL2 payload needs to be a Linux kernel, a bootloader or any other kernel
|
||||||
|
would work as well, as long as it can cope with having the DT address in
|
||||||
|
register x0. If the payload has other means of finding the device tree, it
|
||||||
|
could ignore this address as well.
|
|
@ -14,7 +14,7 @@
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
/* Utility functions */
|
/* Utility functions */
|
||||||
void rpi3_console_init(void);
|
void rpi3_console_init(unsigned int base_clk_rate);
|
||||||
void rpi3_setup_page_tables(uintptr_t total_base, size_t total_size,
|
void rpi3_setup_page_tables(uintptr_t total_base, size_t total_size,
|
||||||
uintptr_t code_start, uintptr_t code_limit,
|
uintptr_t code_start, uintptr_t code_limit,
|
||||||
uintptr_t rodata_start, uintptr_t rodata_limit
|
uintptr_t rodata_start, uintptr_t rodata_limit
|
||||||
|
|
|
@ -104,14 +104,14 @@ static const mmap_region_t plat_rpi3_mmap[] = {
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
static console_16550_t rpi3_console;
|
static console_16550_t rpi3_console;
|
||||||
|
|
||||||
void rpi3_console_init(void)
|
void rpi3_console_init(unsigned int base_clk_rate)
|
||||||
{
|
{
|
||||||
int console_scope = CONSOLE_FLAG_BOOT;
|
int console_scope = CONSOLE_FLAG_BOOT;
|
||||||
#if RPI3_RUNTIME_UART != -1
|
#if RPI3_RUNTIME_UART != -1
|
||||||
console_scope |= CONSOLE_FLAG_RUNTIME;
|
console_scope |= CONSOLE_FLAG_RUNTIME;
|
||||||
#endif
|
#endif
|
||||||
int rc = console_16550_register(PLAT_RPI3_UART_BASE,
|
int rc = console_16550_register(PLAT_RPI3_UART_BASE,
|
||||||
PLAT_RPI3_UART_CLK_IN_HZ,
|
base_clk_rate,
|
||||||
PLAT_RPI3_UART_BAUDRATE,
|
PLAT_RPI3_UART_BAUDRATE,
|
||||||
&rpi3_console);
|
&rpi3_console);
|
||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
|
@ -175,18 +175,6 @@ void rpi3_setup_page_tables(uintptr_t total_base, size_t total_size,
|
||||||
init_xlat_tables();
|
init_xlat_tables();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
* Return entrypoint of BL33.
|
|
||||||
******************************************************************************/
|
|
||||||
uintptr_t plat_get_ns_image_entrypoint(void)
|
|
||||||
{
|
|
||||||
#ifdef PRELOADED_BL33_BASE
|
|
||||||
return PRELOADED_BL33_BASE;
|
|
||||||
#else
|
|
||||||
return PLAT_RPI3_NS_IMAGE_OFFSET;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Gets SPSR for BL32 entry
|
* Gets SPSR for BL32 entry
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
|
@ -35,7 +35,7 @@ void bl1_early_platform_setup(void)
|
||||||
0x80000000);
|
0x80000000);
|
||||||
|
|
||||||
/* Initialize the console to provide early debug support */
|
/* Initialize the console to provide early debug support */
|
||||||
rpi3_console_init();
|
rpi3_console_init(PLAT_RPI3_UART_CLK_IN_HZ);
|
||||||
|
|
||||||
/* Allow BL1 to see the whole Trusted RAM */
|
/* Allow BL1 to see the whole Trusted RAM */
|
||||||
bl1_tzram_layout.total_base = BL_RAM_BASE;
|
bl1_tzram_layout.total_base = BL_RAM_BASE;
|
||||||
|
|
|
@ -62,7 +62,7 @@ void bl2_early_platform_setup2(u_register_t arg0, u_register_t arg1,
|
||||||
meminfo_t *mem_layout = (meminfo_t *) arg1;
|
meminfo_t *mem_layout = (meminfo_t *) arg1;
|
||||||
|
|
||||||
/* Initialize the console to provide early debug support */
|
/* Initialize the console to provide early debug support */
|
||||||
rpi3_console_init();
|
rpi3_console_init(PLAT_RPI3_UART_CLK_IN_HZ);
|
||||||
|
|
||||||
/* Enable arch timer */
|
/* Enable arch timer */
|
||||||
generic_delay_timer_init();
|
generic_delay_timer_init();
|
||||||
|
|
|
@ -47,6 +47,18 @@ entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Return entrypoint of BL33.
|
||||||
|
******************************************************************************/
|
||||||
|
uintptr_t plat_get_ns_image_entrypoint(void)
|
||||||
|
{
|
||||||
|
#ifdef PRELOADED_BL33_BASE
|
||||||
|
return PRELOADED_BL33_BASE;
|
||||||
|
#else
|
||||||
|
return PLAT_RPI3_NS_IMAGE_OFFSET;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Perform any BL31 early platform setup. Here is an opportunity to copy
|
* Perform any BL31 early platform setup. Here is an opportunity to copy
|
||||||
* parameters passed by the calling EL (S-EL1 in BL2 & EL3 in BL1) before
|
* parameters passed by the calling EL (S-EL1 in BL2 & EL3 in BL1) before
|
||||||
|
@ -60,7 +72,7 @@ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
|
||||||
|
|
||||||
{
|
{
|
||||||
/* Initialize the console to provide early debug support */
|
/* Initialize the console to provide early debug support */
|
||||||
rpi3_console_init();
|
rpi3_console_init(PLAT_RPI3_UART_CLK_IN_HZ);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In debug builds, a special value is passed in 'arg1' to verify
|
* In debug builds, a special value is passed in 'arg1' to verify
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* armstub8.bin header to let the GPU firmware recognise this code.
|
||||||
|
* It will then write the load address of the kernel image and the DT
|
||||||
|
* after the header magic in RAM, so we can read those addresses at runtime.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.text
|
||||||
|
b armstub8_end
|
||||||
|
|
||||||
|
.global stub_magic
|
||||||
|
.global dtb_ptr32
|
||||||
|
.global kernel_entry32
|
||||||
|
|
||||||
|
.org 0xf0
|
||||||
|
armstub8:
|
||||||
|
stub_magic:
|
||||||
|
.word 0x5afe570b
|
||||||
|
stub_version:
|
||||||
|
.word 0
|
||||||
|
dtb_ptr32:
|
||||||
|
.word 0x0
|
||||||
|
kernel_entry32:
|
||||||
|
.word 0x0
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Technically an offset of 0x100 would suffice, but the follow-up code
|
||||||
|
* (bl31_entrypoint.S at BL31_BASE) needs to be page aligned, so pad here
|
||||||
|
* till the end of the first 4K page.
|
||||||
|
*/
|
||||||
|
.org 0x1000
|
||||||
|
armstub8_end:
|
|
@ -0,0 +1,187 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <arch.h>
|
||||||
|
#include <asm_macros.S>
|
||||||
|
#include <assert_macros.S>
|
||||||
|
#include <platform_def.h>
|
||||||
|
#include <cortex_a72.h>
|
||||||
|
|
||||||
|
#include "../include/rpi_hw.h"
|
||||||
|
|
||||||
|
.globl plat_crash_console_flush
|
||||||
|
.globl plat_crash_console_init
|
||||||
|
.globl plat_crash_console_putc
|
||||||
|
.globl platform_mem_init
|
||||||
|
.globl plat_get_my_entrypoint
|
||||||
|
.globl plat_is_my_cpu_primary
|
||||||
|
.globl plat_my_core_pos
|
||||||
|
.globl plat_reset_handler
|
||||||
|
.globl plat_rpi3_calc_core_pos
|
||||||
|
.globl plat_secondary_cold_boot_setup
|
||||||
|
|
||||||
|
/* -----------------------------------------------------
|
||||||
|
* unsigned int plat_my_core_pos(void)
|
||||||
|
*
|
||||||
|
* This function uses the plat_rpi3_calc_core_pos()
|
||||||
|
* definition to get the index of the calling CPU.
|
||||||
|
* -----------------------------------------------------
|
||||||
|
*/
|
||||||
|
func plat_my_core_pos
|
||||||
|
mrs x0, mpidr_el1
|
||||||
|
b plat_rpi3_calc_core_pos
|
||||||
|
endfunc plat_my_core_pos
|
||||||
|
|
||||||
|
/* -----------------------------------------------------
|
||||||
|
* unsigned int plat_rpi3_calc_core_pos(u_register_t mpidr);
|
||||||
|
*
|
||||||
|
* CorePos = (ClusterId * 4) + CoreId
|
||||||
|
* -----------------------------------------------------
|
||||||
|
*/
|
||||||
|
func plat_rpi3_calc_core_pos
|
||||||
|
and x1, x0, #MPIDR_CPU_MASK
|
||||||
|
and x0, x0, #MPIDR_CLUSTER_MASK
|
||||||
|
add x0, x1, x0, LSR #6
|
||||||
|
ret
|
||||||
|
endfunc plat_rpi3_calc_core_pos
|
||||||
|
|
||||||
|
/* -----------------------------------------------------
|
||||||
|
* 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
|
||||||
|
and x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
|
||||||
|
cmp x0, #RPI4_PRIMARY_CPU
|
||||||
|
cset w0, eq
|
||||||
|
ret
|
||||||
|
endfunc plat_is_my_cpu_primary
|
||||||
|
|
||||||
|
/* -----------------------------------------------------
|
||||||
|
* void plat_secondary_cold_boot_setup (void);
|
||||||
|
*
|
||||||
|
* This function performs any platform specific actions
|
||||||
|
* needed for a secondary cpu after a cold reset e.g
|
||||||
|
* mark the cpu's presence, mechanism to place it in a
|
||||||
|
* holding pen etc.
|
||||||
|
* -----------------------------------------------------
|
||||||
|
*/
|
||||||
|
func plat_secondary_cold_boot_setup
|
||||||
|
/* Calculate address of our hold entry */
|
||||||
|
bl plat_my_core_pos
|
||||||
|
lsl x0, x0, #3
|
||||||
|
mov_imm x2, PLAT_RPI3_TM_HOLD_BASE
|
||||||
|
add x0, x0, x2
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code runs way before requesting the warmboot of this core,
|
||||||
|
* so it is possible to clear the mailbox before getting a request
|
||||||
|
* to boot.
|
||||||
|
*/
|
||||||
|
mov x1, PLAT_RPI3_TM_HOLD_STATE_WAIT
|
||||||
|
str x1,[x0]
|
||||||
|
|
||||||
|
/* Wait until we have a go */
|
||||||
|
poll_mailbox:
|
||||||
|
wfe
|
||||||
|
ldr x1, [x0]
|
||||||
|
cmp x1, PLAT_RPI3_TM_HOLD_STATE_GO
|
||||||
|
bne poll_mailbox
|
||||||
|
|
||||||
|
/* Jump to the provided entrypoint */
|
||||||
|
mov_imm x0, PLAT_RPI3_TM_ENTRYPOINT
|
||||||
|
ldr x1, [x0]
|
||||||
|
br x1
|
||||||
|
endfunc plat_secondary_cold_boot_setup
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------------
|
||||||
|
* uintptr_t plat_get_my_entrypoint (void);
|
||||||
|
*
|
||||||
|
* Main job of this routine is to distinguish between a cold and a warm
|
||||||
|
* boot.
|
||||||
|
*
|
||||||
|
* This functions returns:
|
||||||
|
* - 0 for a cold boot.
|
||||||
|
* - Any other value for a warm boot.
|
||||||
|
* ---------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
func plat_get_my_entrypoint
|
||||||
|
/* TODO: support warm boot */
|
||||||
|
mov x0, #0
|
||||||
|
ret
|
||||||
|
endfunc plat_get_my_entrypoint
|
||||||
|
|
||||||
|
/* ---------------------------------------------
|
||||||
|
* void platform_mem_init (void);
|
||||||
|
*
|
||||||
|
* No need to carry out any memory initialization.
|
||||||
|
* ---------------------------------------------
|
||||||
|
*/
|
||||||
|
func platform_mem_init
|
||||||
|
ret
|
||||||
|
endfunc platform_mem_init
|
||||||
|
|
||||||
|
/* ---------------------------------------------
|
||||||
|
* int plat_crash_console_init(void)
|
||||||
|
* Function to initialize the crash console
|
||||||
|
* without a C Runtime to print crash report.
|
||||||
|
* Clobber list : x0 - x3
|
||||||
|
* ---------------------------------------------
|
||||||
|
*/
|
||||||
|
func plat_crash_console_init
|
||||||
|
mov_imm x0, PLAT_RPI3_UART_BASE
|
||||||
|
mov_imm x1, PLAT_RPI4_VPU_CLK_RATE
|
||||||
|
mov_imm x2, PLAT_RPI3_UART_BAUDRATE
|
||||||
|
b console_16550_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_RPI3_UART_BASE
|
||||||
|
b console_16550_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 : x0, x1
|
||||||
|
* ---------------------------------------------
|
||||||
|
*/
|
||||||
|
func plat_crash_console_flush
|
||||||
|
mov_imm x0, PLAT_RPI3_UART_BASE
|
||||||
|
b console_16550_core_flush
|
||||||
|
endfunc plat_crash_console_flush
|
||||||
|
|
||||||
|
/* ---------------------------------------------
|
||||||
|
* void plat_reset_handler(void);
|
||||||
|
* ---------------------------------------------
|
||||||
|
*/
|
||||||
|
func plat_reset_handler
|
||||||
|
/* ------------------------------------------------
|
||||||
|
* Set L2 read/write cache latency:
|
||||||
|
* - L2 Data RAM latency: 3 cycles (0b010)
|
||||||
|
* - L2 Data RAM setup: 1 cycle (bit 5)
|
||||||
|
* ------------------------------------------------
|
||||||
|
*/
|
||||||
|
mrs x0, CORTEX_A72_L2CTLR_EL1
|
||||||
|
mov x1, #0x22
|
||||||
|
orr x0, x0, x1
|
||||||
|
msr CORTEX_A72_L2CTLR_EL1, x0
|
||||||
|
isb
|
||||||
|
|
||||||
|
ret
|
||||||
|
endfunc plat_reset_handler
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*
|
||||||
|
* Stub linker script to provide the armstub8.bin header before the actual
|
||||||
|
* code. If the GPU firmware finds a magic value at offset 240 in
|
||||||
|
* armstub8.bin, it will put the DTB and kernel load address in subsequent
|
||||||
|
* words. We can then read those values to find the proper NS entry point
|
||||||
|
* and find our DTB more flexibly.
|
||||||
|
*/
|
||||||
|
|
||||||
|
MEMORY {
|
||||||
|
PRERAM (rwx): ORIGIN = 0, LENGTH = 4096
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
.armstub8 . : {
|
||||||
|
*armstub8_header.o(.text*)
|
||||||
|
KEEP(*(.armstub8))
|
||||||
|
} >PRERAM
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
#ifndef PLAT_MACROS_S
|
||||||
|
#define PLAT_MACROS_S
|
||||||
|
|
||||||
|
/* ---------------------------------------------
|
||||||
|
* The below required platform porting macro
|
||||||
|
* prints out relevant platform registers
|
||||||
|
* whenever an unhandled exception is taken in
|
||||||
|
* BL31.
|
||||||
|
* Clobbers: x0 - x10, x16, x17, sp
|
||||||
|
* ---------------------------------------------
|
||||||
|
*/
|
||||||
|
.macro plat_crash_print_regs
|
||||||
|
.endm
|
||||||
|
|
||||||
|
#endif /* PLAT_MACROS_S */
|
|
@ -0,0 +1,137 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015-2019, 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 <common/tbbr/tbbr_img_def.h>
|
||||||
|
#include <lib/utils_def.h>
|
||||||
|
#include <plat/common/common_def.h>
|
||||||
|
|
||||||
|
#include "rpi_hw.h"
|
||||||
|
|
||||||
|
/* Special value used to verify platform parameters from BL2 to BL31 */
|
||||||
|
#define RPI3_BL31_PLAT_PARAM_VAL ULL(0x0F1E2D3C4B5A6978)
|
||||||
|
|
||||||
|
#define PLATFORM_STACK_SIZE ULL(0x1000)
|
||||||
|
|
||||||
|
#define PLATFORM_MAX_CPUS_PER_CLUSTER U(4)
|
||||||
|
#define PLATFORM_CLUSTER_COUNT U(1)
|
||||||
|
#define PLATFORM_CLUSTER0_CORE_COUNT PLATFORM_MAX_CPUS_PER_CLUSTER
|
||||||
|
#define PLATFORM_CORE_COUNT PLATFORM_CLUSTER0_CORE_COUNT
|
||||||
|
|
||||||
|
#define RPI4_PRIMARY_CPU U(0)
|
||||||
|
|
||||||
|
#define PLAT_MAX_PWR_LVL MPIDR_AFFLVL1
|
||||||
|
#define PLAT_NUM_PWR_DOMAINS (PLATFORM_CLUSTER_COUNT + \
|
||||||
|
PLATFORM_CORE_COUNT)
|
||||||
|
|
||||||
|
#define PLAT_MAX_RET_STATE U(1)
|
||||||
|
#define PLAT_MAX_OFF_STATE U(2)
|
||||||
|
|
||||||
|
/* Local power state for power domains in Run state. */
|
||||||
|
#define PLAT_LOCAL_STATE_RUN U(0)
|
||||||
|
/* Local power state for retention. Valid only for CPU power domains */
|
||||||
|
#define PLAT_LOCAL_STATE_RET U(1)
|
||||||
|
/*
|
||||||
|
* Local power state for OFF/power-down. Valid for CPU and cluster power
|
||||||
|
* domains.
|
||||||
|
*/
|
||||||
|
#define PLAT_LOCAL_STATE_OFF U(2)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Macros used to parse state information from State-ID if it is using the
|
||||||
|
* recommended encoding for State-ID.
|
||||||
|
*/
|
||||||
|
#define PLAT_LOCAL_PSTATE_WIDTH U(4)
|
||||||
|
#define PLAT_LOCAL_PSTATE_MASK ((U(1) << PLAT_LOCAL_PSTATE_WIDTH) - 1)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some data must be aligned 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 U(6)
|
||||||
|
#define CACHE_WRITEBACK_GRANULE (U(1) << CACHE_WRITEBACK_SHIFT)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* I/O registers.
|
||||||
|
*/
|
||||||
|
#define DEVICE0_BASE RPI_IO_BASE
|
||||||
|
#define DEVICE0_SIZE RPI_IO_SIZE
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mailbox to control the secondary cores. All secondary cores are held in a
|
||||||
|
* wait loop in cold boot. To release them perform the following steps (plus
|
||||||
|
* any additional barriers that may be needed):
|
||||||
|
*
|
||||||
|
* uint64_t *entrypoint = (uint64_t *)PLAT_RPI3_TM_ENTRYPOINT;
|
||||||
|
* *entrypoint = ADDRESS_TO_JUMP_TO;
|
||||||
|
*
|
||||||
|
* uint64_t *mbox_entry = (uint64_t *)PLAT_RPI3_TM_HOLD_BASE;
|
||||||
|
* mbox_entry[cpu_id] = PLAT_RPI3_TM_HOLD_STATE_GO;
|
||||||
|
*
|
||||||
|
* sev();
|
||||||
|
*/
|
||||||
|
/* The secure entry point to be used on warm reset by all CPUs. */
|
||||||
|
#define PLAT_RPI3_TM_ENTRYPOINT 0x100
|
||||||
|
#define PLAT_RPI3_TM_ENTRYPOINT_SIZE ULL(8)
|
||||||
|
|
||||||
|
/* Hold entries for each CPU. */
|
||||||
|
#define PLAT_RPI3_TM_HOLD_BASE (PLAT_RPI3_TM_ENTRYPOINT + \
|
||||||
|
PLAT_RPI3_TM_ENTRYPOINT_SIZE)
|
||||||
|
#define PLAT_RPI3_TM_HOLD_ENTRY_SIZE ULL(8)
|
||||||
|
#define PLAT_RPI3_TM_HOLD_SIZE (PLAT_RPI3_TM_HOLD_ENTRY_SIZE * \
|
||||||
|
PLATFORM_CORE_COUNT)
|
||||||
|
|
||||||
|
#define PLAT_RPI3_TRUSTED_MAILBOX_SIZE (PLAT_RPI3_TM_ENTRYPOINT_SIZE + \
|
||||||
|
PLAT_RPI3_TM_HOLD_SIZE)
|
||||||
|
|
||||||
|
#define PLAT_RPI3_TM_HOLD_STATE_WAIT ULL(0)
|
||||||
|
#define PLAT_RPI3_TM_HOLD_STATE_GO ULL(1)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* BL31 specific defines.
|
||||||
|
*
|
||||||
|
* Put BL31 at the top of the Trusted SRAM. BL31_BASE is calculated using the
|
||||||
|
* current BL31 debug size plus a little space for growth.
|
||||||
|
*/
|
||||||
|
#define PLAT_MAX_BL31_SIZE ULL(0x80000)
|
||||||
|
|
||||||
|
#define BL31_BASE ULL(0x1000)
|
||||||
|
#define BL31_LIMIT ULL(0x80000)
|
||||||
|
#define BL31_PROGBITS_LIMIT ULL(0x80000)
|
||||||
|
|
||||||
|
#define SEC_SRAM_ID 0
|
||||||
|
#define SEC_DRAM_ID 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Other memory-related defines.
|
||||||
|
*/
|
||||||
|
#define PLAT_PHY_ADDR_SPACE_SIZE (ULL(1) << 32)
|
||||||
|
#define PLAT_VIRT_ADDR_SPACE_SIZE (ULL(1) << 32)
|
||||||
|
|
||||||
|
#define MAX_MMAP_REGIONS 8
|
||||||
|
#define MAX_XLAT_TABLES 4
|
||||||
|
|
||||||
|
#define MAX_IO_DEVICES U(3)
|
||||||
|
#define MAX_IO_HANDLES U(4)
|
||||||
|
|
||||||
|
#define MAX_IO_BLOCK_DEVICES U(1)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Serial-related constants.
|
||||||
|
*/
|
||||||
|
#define PLAT_RPI3_UART_BASE RPI3_MINI_UART_BASE
|
||||||
|
#define PLAT_RPI3_UART_BAUDRATE ULL(115200)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* System counter
|
||||||
|
*/
|
||||||
|
#define SYS_COUNTER_FREQ_IN_TICKS ULL(54000000)
|
||||||
|
|
||||||
|
#endif /* PLATFORM_DEF_H */
|
|
@ -0,0 +1,115 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RPI_HW_H
|
||||||
|
#define RPI_HW_H
|
||||||
|
|
||||||
|
#include <lib/utils_def.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Peripherals
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define RPI_IO_BASE ULL(0xFE000000)
|
||||||
|
#define RPI_IO_SIZE ULL(0x02000000)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ARM <-> VideoCore mailboxes
|
||||||
|
*/
|
||||||
|
#define RPI3_MBOX_OFFSET ULL(0x0000B880)
|
||||||
|
#define RPI3_MBOX_BASE (RPI_IO_BASE + RPI3_MBOX_OFFSET)
|
||||||
|
/* VideoCore -> ARM */
|
||||||
|
#define RPI3_MBOX0_READ_OFFSET ULL(0x00000000)
|
||||||
|
#define RPI3_MBOX0_PEEK_OFFSET ULL(0x00000010)
|
||||||
|
#define RPI3_MBOX0_SENDER_OFFSET ULL(0x00000014)
|
||||||
|
#define RPI3_MBOX0_STATUS_OFFSET ULL(0x00000018)
|
||||||
|
#define RPI3_MBOX0_CONFIG_OFFSET ULL(0x0000001C)
|
||||||
|
/* ARM -> VideoCore */
|
||||||
|
#define RPI3_MBOX1_WRITE_OFFSET ULL(0x00000020)
|
||||||
|
#define RPI3_MBOX1_PEEK_OFFSET ULL(0x00000030)
|
||||||
|
#define RPI3_MBOX1_SENDER_OFFSET ULL(0x00000034)
|
||||||
|
#define RPI3_MBOX1_STATUS_OFFSET ULL(0x00000038)
|
||||||
|
#define RPI3_MBOX1_CONFIG_OFFSET ULL(0x0000003C)
|
||||||
|
/* Mailbox status constants */
|
||||||
|
#define RPI3_MBOX_STATUS_FULL_MASK U(0x80000000) /* Set if full */
|
||||||
|
#define RPI3_MBOX_STATUS_EMPTY_MASK U(0x40000000) /* Set if empty */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Power management, reset controller, watchdog.
|
||||||
|
*/
|
||||||
|
#define RPI3_IO_PM_OFFSET ULL(0x00100000)
|
||||||
|
#define RPI3_PM_BASE (RPI_IO_BASE + RPI3_IO_PM_OFFSET)
|
||||||
|
/* Registers on top of RPI3_PM_BASE. */
|
||||||
|
#define RPI3_PM_RSTC_OFFSET ULL(0x0000001C)
|
||||||
|
#define RPI3_PM_RSTS_OFFSET ULL(0x00000020)
|
||||||
|
#define RPI3_PM_WDOG_OFFSET ULL(0x00000024)
|
||||||
|
/* Watchdog constants */
|
||||||
|
#define RPI3_PM_PASSWORD U(0x5A000000)
|
||||||
|
#define RPI3_PM_RSTC_WRCFG_MASK U(0x00000030)
|
||||||
|
#define RPI3_PM_RSTC_WRCFG_FULL_RESET U(0x00000020)
|
||||||
|
/*
|
||||||
|
* The RSTS register is used by the VideoCore firmware when booting the
|
||||||
|
* Raspberry Pi to know which partition to boot from. The partition value is
|
||||||
|
* formed by bits 0, 2, 4, 6, 8 and 10. Partition 63 is used by said firmware
|
||||||
|
* to indicate halt.
|
||||||
|
*/
|
||||||
|
#define RPI3_PM_RSTS_WRCFG_HALT U(0x00000555)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clock controller
|
||||||
|
*/
|
||||||
|
#define RPI4_IO_CLOCK_OFFSET ULL(0x00101000)
|
||||||
|
#define RPI4_CLOCK_BASE (RPI_IO_BASE + RPI4_IO_CLOCK_OFFSET)
|
||||||
|
#define RPI4_VPU_CLOCK_DIVIDER ULL(0x0000000c)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hardware random number generator.
|
||||||
|
*/
|
||||||
|
#define RPI3_IO_RNG_OFFSET ULL(0x00104000)
|
||||||
|
#define RPI3_RNG_BASE (RPI_IO_BASE + RPI3_IO_RNG_OFFSET)
|
||||||
|
#define RPI3_RNG_CTRL_OFFSET ULL(0x00000000)
|
||||||
|
#define RPI3_RNG_STATUS_OFFSET ULL(0x00000004)
|
||||||
|
#define RPI3_RNG_DATA_OFFSET ULL(0x00000008)
|
||||||
|
#define RPI3_RNG_INT_MASK_OFFSET ULL(0x00000010)
|
||||||
|
/* Enable/disable RNG */
|
||||||
|
#define RPI3_RNG_CTRL_ENABLE U(0x1)
|
||||||
|
#define RPI3_RNG_CTRL_DISABLE U(0x0)
|
||||||
|
/* Number of currently available words */
|
||||||
|
#define RPI3_RNG_STATUS_NUM_WORDS_SHIFT U(24)
|
||||||
|
#define RPI3_RNG_STATUS_NUM_WORDS_MASK U(0xFF)
|
||||||
|
/* Value to mask interrupts caused by the RNG */
|
||||||
|
#define RPI3_RNG_INT_MASK_DISABLE U(0x1)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Serial port (called 'Mini UART' in the Broadcom documentation).
|
||||||
|
*/
|
||||||
|
#define RPI3_IO_MINI_UART_OFFSET ULL(0x00215040)
|
||||||
|
#define RPI3_MINI_UART_BASE (RPI_IO_BASE + RPI3_IO_MINI_UART_OFFSET)
|
||||||
|
#define PLAT_RPI4_VPU_CLK_RATE ULL(1000000000)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GPIO controller
|
||||||
|
*/
|
||||||
|
#define RPI3_IO_GPIO_OFFSET ULL(0x00200000)
|
||||||
|
#define RPI3_GPIO_BASE (RPI_IO_BASE + RPI3_IO_GPIO_OFFSET)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SDHost controller
|
||||||
|
*/
|
||||||
|
#define RPI3_IO_SDHOST_OFFSET ULL(0x00202000)
|
||||||
|
#define RPI3_SDHOST_BASE (RPI_IO_BASE + RPI3_IO_SDHOST_OFFSET)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GIC interrupt controller
|
||||||
|
*/
|
||||||
|
#define RPI_HAVE_GIC
|
||||||
|
#define RPI4_GIC_GICD_BASE ULL(0xff841000)
|
||||||
|
#define RPI4_GIC_GICC_BASE ULL(0xff842000)
|
||||||
|
|
||||||
|
#define RPI4_LOCAL_CONTROL_BASE_ADDRESS ULL(0xff800000)
|
||||||
|
#define RPI4_LOCAL_CONTROL_PRESCALER ULL(0xff800008)
|
||||||
|
|
||||||
|
#endif /* RPI_HW_H */
|
|
@ -0,0 +1,103 @@
|
||||||
|
#
|
||||||
|
# Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
#
|
||||||
|
|
||||||
|
include lib/libfdt/libfdt.mk
|
||||||
|
include lib/xlat_tables_v2/xlat_tables.mk
|
||||||
|
|
||||||
|
PLAT_INCLUDES := -Iplat/rpi/common/include \
|
||||||
|
-Iplat/rpi/rpi4/include
|
||||||
|
|
||||||
|
PLAT_BL_COMMON_SOURCES := drivers/ti/uart/aarch64/16550_console.S \
|
||||||
|
plat/rpi/common/rpi3_common.c \
|
||||||
|
${XLAT_TABLES_LIB_SRCS}
|
||||||
|
|
||||||
|
BL31_SOURCES += lib/cpus/aarch64/cortex_a72.S \
|
||||||
|
plat/rpi/rpi4/aarch64/plat_helpers.S \
|
||||||
|
plat/rpi/rpi4/aarch64/armstub8_header.S \
|
||||||
|
drivers/arm/gic/common/gic_common.c \
|
||||||
|
drivers/arm/gic/v2/gicv2_helpers.c \
|
||||||
|
drivers/arm/gic/v2/gicv2_main.c \
|
||||||
|
plat/common/plat_gicv2.c \
|
||||||
|
plat/rpi/rpi4/rpi4_bl31_setup.c \
|
||||||
|
plat/rpi/common/rpi3_pm.c \
|
||||||
|
plat/common/plat_psci_common.c \
|
||||||
|
plat/rpi/common/rpi3_topology.c \
|
||||||
|
common/fdt_fixup.c \
|
||||||
|
${LIBFDT_SRCS}
|
||||||
|
|
||||||
|
# For now we only support BL31, using the kernel loaded by the GPU firmware.
|
||||||
|
RESET_TO_BL31 := 1
|
||||||
|
|
||||||
|
# All CPUs enter armstub8.bin.
|
||||||
|
COLD_BOOT_SINGLE_CPU := 0
|
||||||
|
|
||||||
|
# Tune compiler for Cortex-A72
|
||||||
|
ifeq ($(notdir $(CC)),armclang)
|
||||||
|
TF_CFLAGS_aarch64 += -mcpu=cortex-a72
|
||||||
|
else ifneq ($(findstring clang,$(notdir $(CC))),)
|
||||||
|
TF_CFLAGS_aarch64 += -mcpu=cortex-a72
|
||||||
|
else
|
||||||
|
TF_CFLAGS_aarch64 += -mtune=cortex-a72
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Add support for platform supplied linker script for BL31 build
|
||||||
|
$(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT))
|
||||||
|
|
||||||
|
# Enable all errata workarounds for Cortex-A72
|
||||||
|
ERRATA_A72_859971 := 1
|
||||||
|
|
||||||
|
WORKAROUND_CVE_2017_5715 := 1
|
||||||
|
|
||||||
|
# Add new default target when compiling this platform
|
||||||
|
all: bl31
|
||||||
|
|
||||||
|
# Build config flags
|
||||||
|
# ------------------
|
||||||
|
|
||||||
|
# Disable stack protector by default
|
||||||
|
ENABLE_STACK_PROTECTOR := 0
|
||||||
|
|
||||||
|
# Have different sections for code and rodata
|
||||||
|
SEPARATE_CODE_AND_RODATA := 1
|
||||||
|
|
||||||
|
# Use Coherent memory
|
||||||
|
USE_COHERENT_MEM := 1
|
||||||
|
|
||||||
|
# Platform build flags
|
||||||
|
# --------------------
|
||||||
|
|
||||||
|
# There is not much else than a Linux kernel to load at the moment.
|
||||||
|
RPI3_DIRECT_LINUX_BOOT := 1
|
||||||
|
|
||||||
|
# BL33 images are in AArch64 by default
|
||||||
|
RPI3_BL33_IN_AARCH32 := 0
|
||||||
|
|
||||||
|
# UART to use at runtime. -1 means the runtime UART is disabled.
|
||||||
|
# Any other value means the default UART will be used.
|
||||||
|
RPI3_RUNTIME_UART := 0
|
||||||
|
|
||||||
|
# Use normal memory mapping for ROM, FIP, SRAM and DRAM
|
||||||
|
RPI3_USE_UEFI_MAP := 0
|
||||||
|
|
||||||
|
# Process platform flags
|
||||||
|
# ----------------------
|
||||||
|
|
||||||
|
$(eval $(call add_define,RPI3_BL33_IN_AARCH32))
|
||||||
|
$(eval $(call add_define,RPI3_DIRECT_LINUX_BOOT))
|
||||||
|
ifdef RPI3_PRELOADED_DTB_BASE
|
||||||
|
$(eval $(call add_define,RPI3_PRELOADED_DTB_BASE))
|
||||||
|
endif
|
||||||
|
$(eval $(call add_define,RPI3_RUNTIME_UART))
|
||||||
|
$(eval $(call add_define,RPI3_USE_UEFI_MAP))
|
||||||
|
|
||||||
|
ifeq (${ARCH},aarch32)
|
||||||
|
$(error Error: AArch32 not supported on rpi4)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(ENABLE_STACK_PROTECTOR), 0)
|
||||||
|
PLAT_BL_COMMON_SOURCES += drivers/rpi3/rng/rpi3_rng.c \
|
||||||
|
plat/rpi/common/rpi3_stack_protector.c
|
||||||
|
endif
|
|
@ -0,0 +1,278 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include <libfdt.h>
|
||||||
|
|
||||||
|
#include <platform_def.h>
|
||||||
|
#include <arch_helpers.h>
|
||||||
|
#include <common/bl_common.h>
|
||||||
|
#include <lib/mmio.h>
|
||||||
|
#include <lib/xlat_tables/xlat_mmu_helpers.h>
|
||||||
|
#include <lib/xlat_tables/xlat_tables_defs.h>
|
||||||
|
#include <lib/xlat_tables/xlat_tables_v2.h>
|
||||||
|
#include <plat/common/platform.h>
|
||||||
|
#include <common/fdt_fixup.h>
|
||||||
|
#include <libfdt.h>
|
||||||
|
|
||||||
|
#include <drivers/arm/gicv2.h>
|
||||||
|
|
||||||
|
#include <rpi_shared.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fields at the beginning of armstub8.bin.
|
||||||
|
* While building the BL31 image, we put the stub magic into the binary.
|
||||||
|
* The GPU firmware detects this at boot time, clears that field as a
|
||||||
|
* confirmation and puts the kernel and DT address in the following words.
|
||||||
|
*/
|
||||||
|
extern uint32_t stub_magic;
|
||||||
|
extern uint32_t dtb_ptr32;
|
||||||
|
extern uint32_t kernel_entry32;
|
||||||
|
|
||||||
|
static const gicv2_driver_data_t rpi4_gic_data = {
|
||||||
|
.gicd_base = RPI4_GIC_GICD_BASE,
|
||||||
|
.gicc_base = RPI4_GIC_GICC_BASE,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* To be filled by the code below. At the moment BL32 is not supported.
|
||||||
|
* In the future these might be passed down from BL2.
|
||||||
|
*/
|
||||||
|
static entry_point_info_t bl32_image_ep_info;
|
||||||
|
static entry_point_info_t bl33_image_ep_info;
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Return a pointer to the 'entry_point_info' structure of the next image for
|
||||||
|
* the security state specified. BL33 corresponds to the non-secure image type
|
||||||
|
* while BL32 corresponds to the secure image type. A NULL pointer is returned
|
||||||
|
* if the image does not exist.
|
||||||
|
******************************************************************************/
|
||||||
|
entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
|
||||||
|
{
|
||||||
|
entry_point_info_t *next_image_info;
|
||||||
|
|
||||||
|
assert(sec_state_is_valid(type) != 0);
|
||||||
|
|
||||||
|
next_image_info = (type == NON_SECURE)
|
||||||
|
? &bl33_image_ep_info : &bl32_image_ep_info;
|
||||||
|
|
||||||
|
/* None of the images can have 0x0 as the entrypoint. */
|
||||||
|
if (next_image_info->pc) {
|
||||||
|
return next_image_info;
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t plat_get_ns_image_entrypoint(void)
|
||||||
|
{
|
||||||
|
#ifdef PRELOADED_BL33_BASE
|
||||||
|
return PRELOADED_BL33_BASE;
|
||||||
|
#else
|
||||||
|
/* Cleared by the GPU if kernel address is valid. */
|
||||||
|
if (stub_magic == 0)
|
||||||
|
return kernel_entry32;
|
||||||
|
|
||||||
|
WARN("Stub magic failure, using default kernel address 0x80000\n");
|
||||||
|
return 0x80000;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static uintptr_t rpi4_get_dtb_address(void)
|
||||||
|
{
|
||||||
|
#ifdef RPI3_PRELOADED_DTB_BASE
|
||||||
|
return RPI3_PRELOADED_DTB_BASE;
|
||||||
|
#else
|
||||||
|
/* Cleared by the GPU if DTB address is valid. */
|
||||||
|
if (stub_magic == 0)
|
||||||
|
return dtb_ptr32;
|
||||||
|
|
||||||
|
WARN("Stub magic failure, DTB address unknown\n");
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ldelay(register_t delay)
|
||||||
|
{
|
||||||
|
__asm__ volatile (
|
||||||
|
"1:\tcbz %0, 2f\n\t"
|
||||||
|
"sub %0, %0, #1\n\t"
|
||||||
|
"b 1b\n"
|
||||||
|
"2:"
|
||||||
|
: "=&r" (delay) : "0" (delay)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Perform any BL31 early platform setup. Here is an opportunity to copy
|
||||||
|
* parameters passed by the calling EL (S-EL1 in BL2 & EL3 in BL1) before
|
||||||
|
* they are lost (potentially). This needs to be done before the MMU is
|
||||||
|
* initialized so that the memory layout can be used while creating page
|
||||||
|
* tables. BL2 has flushed this information to memory, so we are guaranteed
|
||||||
|
* to pick up good data.
|
||||||
|
******************************************************************************/
|
||||||
|
void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
|
||||||
|
u_register_t arg2, u_register_t arg3)
|
||||||
|
|
||||||
|
{
|
||||||
|
uint32_t div_reg;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* LOCAL_CONTROL:
|
||||||
|
* Bit 9 clear: Increment by 1 (vs. 2).
|
||||||
|
* Bit 8 clear: Timer source is 19.2MHz crystal (vs. APB).
|
||||||
|
*/
|
||||||
|
mmio_write_32(RPI4_LOCAL_CONTROL_BASE_ADDRESS, 0);
|
||||||
|
|
||||||
|
/* LOCAL_PRESCALER; divide-by (0x80000000 / register_val) == 1 */
|
||||||
|
mmio_write_32(RPI4_LOCAL_CONTROL_PRESCALER, 0x80000000);
|
||||||
|
|
||||||
|
/* Early GPU firmware revisions need a little break here. */
|
||||||
|
ldelay(100000);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize the console to provide early debug support.
|
||||||
|
* Different GPU firmware revisions set up the VPU divider differently,
|
||||||
|
* so read the actual divider register to learn the UART base clock
|
||||||
|
* rate. The divider is encoded as a 12.12 fixed point number, but we
|
||||||
|
* just care about the integer part of it.
|
||||||
|
*/
|
||||||
|
div_reg = mmio_read_32(RPI4_CLOCK_BASE + RPI4_VPU_CLOCK_DIVIDER);
|
||||||
|
div_reg = (div_reg >> 12) & 0xfff;
|
||||||
|
if (div_reg == 0)
|
||||||
|
div_reg = 1;
|
||||||
|
rpi3_console_init(PLAT_RPI4_VPU_CLK_RATE / div_reg);
|
||||||
|
|
||||||
|
bl33_image_ep_info.pc = plat_get_ns_image_entrypoint();
|
||||||
|
bl33_image_ep_info.spsr = rpi3_get_spsr_for_bl33_entry();
|
||||||
|
SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
|
||||||
|
|
||||||
|
#if RPI3_DIRECT_LINUX_BOOT
|
||||||
|
# if RPI3_BL33_IN_AARCH32
|
||||||
|
/*
|
||||||
|
* According to the file ``Documentation/arm/Booting`` of the Linux
|
||||||
|
* kernel tree, Linux expects:
|
||||||
|
* r0 = 0
|
||||||
|
* r1 = machine type number, optional in DT-only platforms (~0 if so)
|
||||||
|
* r2 = Physical address of the device tree blob
|
||||||
|
*/
|
||||||
|
VERBOSE("rpi4: Preparing to boot 32-bit Linux kernel\n");
|
||||||
|
bl33_image_ep_info.args.arg0 = 0U;
|
||||||
|
bl33_image_ep_info.args.arg1 = ~0U;
|
||||||
|
bl33_image_ep_info.args.arg2 = rpi4_get_dtb_address();
|
||||||
|
# else
|
||||||
|
/*
|
||||||
|
* According to the file ``Documentation/arm64/booting.txt`` of the
|
||||||
|
* Linux kernel tree, Linux expects the physical address of the device
|
||||||
|
* tree blob (DTB) in x0, while x1-x3 are reserved for future use and
|
||||||
|
* must be 0.
|
||||||
|
*/
|
||||||
|
VERBOSE("rpi4: Preparing to boot 64-bit Linux kernel\n");
|
||||||
|
bl33_image_ep_info.args.arg0 = rpi4_get_dtb_address();
|
||||||
|
bl33_image_ep_info.args.arg1 = 0ULL;
|
||||||
|
bl33_image_ep_info.args.arg2 = 0ULL;
|
||||||
|
bl33_image_ep_info.args.arg3 = 0ULL;
|
||||||
|
# endif /* RPI3_BL33_IN_AARCH32 */
|
||||||
|
#endif /* RPI3_DIRECT_LINUX_BOOT */
|
||||||
|
}
|
||||||
|
|
||||||
|
void bl31_plat_arch_setup(void)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Is the dtb_ptr32 pointer valid? If yes, map the DTB region.
|
||||||
|
* We map the 2MB region the DTB start address lives in, plus
|
||||||
|
* the next 2MB, to have enough room for expansion.
|
||||||
|
*/
|
||||||
|
if (stub_magic == 0) {
|
||||||
|
unsigned long long dtb_region = dtb_ptr32;
|
||||||
|
|
||||||
|
dtb_region &= ~0x1fffff; /* Align to 2 MB. */
|
||||||
|
mmap_add_region(dtb_region, dtb_region, 4U << 20,
|
||||||
|
MT_MEMORY | MT_RW | MT_NS);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Add the first page of memory, which holds the stub magic,
|
||||||
|
* the kernel and the DT address.
|
||||||
|
* This also holds the secondary CPU's entrypoints and mailboxes.
|
||||||
|
*/
|
||||||
|
mmap_add_region(0, 0, 4096, MT_NON_CACHEABLE | MT_RW | MT_SECURE);
|
||||||
|
|
||||||
|
rpi3_setup_page_tables(BL31_BASE, BL31_END - BL31_BASE,
|
||||||
|
BL_CODE_BASE, BL_CODE_END,
|
||||||
|
BL_RO_DATA_BASE, BL_RO_DATA_END
|
||||||
|
#if USE_COHERENT_MEM
|
||||||
|
, BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
|
||||||
|
enable_mmu_el3(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t dtb_size(const void *dtb)
|
||||||
|
{
|
||||||
|
const uint32_t *dtb_header = dtb;
|
||||||
|
|
||||||
|
return fdt32_to_cpu(dtb_header[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rpi4_prepare_dtb(void)
|
||||||
|
{
|
||||||
|
void *dtb = (void *)rpi4_get_dtb_address();
|
||||||
|
uint32_t gic_int_prop[3];
|
||||||
|
int ret, offs;
|
||||||
|
|
||||||
|
/* Return if no device tree is detected */
|
||||||
|
if (fdt_check_header(dtb) != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ret = fdt_open_into(dtb, dtb, 0x100000);
|
||||||
|
if (ret < 0) {
|
||||||
|
ERROR("Invalid Device Tree at %p: error %d\n", dtb, ret);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dt_add_psci_node(dtb)) {
|
||||||
|
ERROR("Failed to add PSCI Device Tree node\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dt_add_psci_cpu_enable_methods(dtb)) {
|
||||||
|
ERROR("Failed to add PSCI cpu enable methods in Device Tree\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reserve memory used by Trusted Firmware. */
|
||||||
|
if (fdt_add_reserved_memory(dtb, "atf@0", 0, 0x80000))
|
||||||
|
WARN("Failed to add reserved memory nodes to DT.\n");
|
||||||
|
|
||||||
|
offs = fdt_node_offset_by_compatible(dtb, 0, "arm,gic-400");
|
||||||
|
gic_int_prop[0] = cpu_to_fdt32(1); // PPI
|
||||||
|
gic_int_prop[1] = cpu_to_fdt32(9); // PPI #9
|
||||||
|
gic_int_prop[2] = cpu_to_fdt32(0x0f04); // all cores, level high
|
||||||
|
fdt_setprop(dtb, offs, "interrupts", gic_int_prop, 12);
|
||||||
|
|
||||||
|
offs = fdt_path_offset(dtb, "/chosen");
|
||||||
|
fdt_setprop_string(dtb, offs, "stdout-path", "serial0");
|
||||||
|
|
||||||
|
ret = fdt_pack(dtb);
|
||||||
|
if (ret < 0)
|
||||||
|
ERROR("Failed to pack Device Tree at %p: error %d\n", dtb, ret);
|
||||||
|
|
||||||
|
clean_dcache_range((uintptr_t)dtb, dtb_size(dtb));
|
||||||
|
INFO("Changed device tree to advertise PSCI.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void bl31_platform_setup(void)
|
||||||
|
{
|
||||||
|
rpi4_prepare_dtb();
|
||||||
|
|
||||||
|
/* Configure the interrupt controller */
|
||||||
|
gicv2_driver_init(&rpi4_gic_data);
|
||||||
|
gicv2_distif_init();
|
||||||
|
gicv2_pcpu_distif_init();
|
||||||
|
gicv2_cpuif_enable();
|
||||||
|
}
|
Loading…
Reference in New Issue