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:
Soby Mathew 2019-09-27 09:45:42 +00:00 committed by TrustedFirmware Code Review
commit 17b0bb6cf5
15 changed files with 1062 additions and 24 deletions

View File

@ -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)
{

85
docs/plat/rpi4.rst Normal file
View File

@ -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.

View File

@ -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

View File

@ -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
******************************************************************************/

View File

@ -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;

View File

@ -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();

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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
}

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

103
plat/rpi/rpi4/platform.mk Normal file
View File

@ -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

View File

@ -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();
}