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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 offs;
|
||||
|
@ -52,15 +79,11 @@ int dt_add_psci_node(void *fdt)
|
|||
return -1;
|
||||
if (fdt_setprop_string(fdt, offs, "method", "smc"))
|
||||
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;
|
||||
if (fdt_setprop_u32(fdt, offs, "cpu_off", PSCI_CPU_OFF))
|
||||
return -1;
|
||||
if (fdt_setprop_u32(fdt, offs, "cpu_on", PSCI_CPU_ON_AARCH64))
|
||||
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))
|
||||
if (fdt_setprop_u32(fdt, offs, "cpu_on", PSCI_CPU_ON_FNID))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
@ -113,6 +136,17 @@ static int dt_update_one_cpu_node(void *fdt, int offset)
|
|||
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 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)
|
||||
|
||||
/*******************************************************************************
|
||||
* 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,
|
||||
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 */
|
||||
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,
|
||||
uintptr_t code_start, uintptr_t code_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;
|
||||
|
||||
void rpi3_console_init(void)
|
||||
void rpi3_console_init(unsigned int base_clk_rate)
|
||||
{
|
||||
int console_scope = CONSOLE_FLAG_BOOT;
|
||||
#if RPI3_RUNTIME_UART != -1
|
||||
console_scope |= CONSOLE_FLAG_RUNTIME;
|
||||
#endif
|
||||
int rc = console_16550_register(PLAT_RPI3_UART_BASE,
|
||||
PLAT_RPI3_UART_CLK_IN_HZ,
|
||||
base_clk_rate,
|
||||
PLAT_RPI3_UART_BAUDRATE,
|
||||
&rpi3_console);
|
||||
if (rc == 0) {
|
||||
|
@ -175,18 +175,6 @@ void rpi3_setup_page_tables(uintptr_t total_base, size_t total_size,
|
|||
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
|
||||
******************************************************************************/
|
||||
|
|
|
@ -35,7 +35,7 @@ void bl1_early_platform_setup(void)
|
|||
0x80000000);
|
||||
|
||||
/* 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 */
|
||||
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;
|
||||
|
||||
/* Initialize the console to provide early debug support */
|
||||
rpi3_console_init();
|
||||
rpi3_console_init(PLAT_RPI3_UART_CLK_IN_HZ);
|
||||
|
||||
/* Enable arch timer */
|
||||
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
|
||||
* 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 */
|
||||
rpi3_console_init();
|
||||
rpi3_console_init(PLAT_RPI3_UART_CLK_IN_HZ);
|
||||
|
||||
/*
|
||||
* 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