GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)
This commit is contained in:
+37
@@ -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,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,140 @@
|
||||
/*
|
||||
* 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 RPI_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)
|
||||
#define PLAT_RPI3_TM_HOLD_STATE_BSP_OFF ULL(2)
|
||||
|
||||
/*
|
||||
* 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_RPI_MINI_UART_BASE RPI4_MINI_UART_BASE
|
||||
#define PLAT_RPI_PL011_UART_BASE RPI4_PL011_UART_BASE
|
||||
#define PLAT_RPI_PL011_UART_CLOCK RPI4_PL011_UART_CLOCK
|
||||
#define PLAT_RPI_UART_BAUDRATE ULL(115200)
|
||||
|
||||
/*
|
||||
* System counter
|
||||
*/
|
||||
#define SYS_COUNTER_FREQ_IN_TICKS ULL(54000000)
|
||||
|
||||
#endif /* PLATFORM_DEF_H */
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2021, 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(0xFC000000)
|
||||
#define RPI_IO_SIZE ULL(0x04000000)
|
||||
|
||||
#define RPI_LEGACY_BASE (ULL(0x02000000) + RPI_IO_BASE)
|
||||
|
||||
/*
|
||||
* ARM <-> VideoCore mailboxes
|
||||
*/
|
||||
#define RPI3_MBOX_OFFSET ULL(0x0000B880)
|
||||
#define RPI3_MBOX_BASE (RPI_LEGACY_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_LEGACY_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)
|
||||
|
||||
/*
|
||||
* Hardware random number generator.
|
||||
*/
|
||||
#define RPI3_IO_RNG_OFFSET ULL(0x00104000)
|
||||
#define RPI3_RNG_BASE (RPI_LEGACY_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 ports:
|
||||
* 'Mini UART' in the BCM docucmentation is the 8250 compatible UART.
|
||||
* There is also a PL011 UART, multiplexed to the same pins.
|
||||
*/
|
||||
#define RPI4_IO_MINI_UART_OFFSET ULL(0x00215040)
|
||||
#define RPI4_MINI_UART_BASE (RPI_LEGACY_BASE + RPI4_IO_MINI_UART_OFFSET)
|
||||
#define RPI4_IO_PL011_UART_OFFSET ULL(0x00201000)
|
||||
#define RPI4_PL011_UART_BASE (RPI_LEGACY_BASE + RPI4_IO_PL011_UART_OFFSET)
|
||||
#define RPI4_PL011_UART_CLOCK ULL(48000000)
|
||||
|
||||
/*
|
||||
* GPIO controller
|
||||
*/
|
||||
#define RPI3_IO_GPIO_OFFSET ULL(0x00200000)
|
||||
#define RPI3_GPIO_BASE (RPI_LEGACY_BASE + RPI3_IO_GPIO_OFFSET)
|
||||
|
||||
/*
|
||||
* SDHost controller
|
||||
*/
|
||||
#define RPI3_IO_SDHOST_OFFSET ULL(0x00202000)
|
||||
#define RPI3_SDHOST_BASE (RPI_LEGACY_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,116 @@
|
||||
#
|
||||
# Copyright (c) 2013-2021, 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
|
||||
|
||||
include drivers/arm/gic/v2/gicv2.mk
|
||||
|
||||
PLAT_INCLUDES := -Iplat/rpi/common/include \
|
||||
-Iplat/rpi/rpi4/include
|
||||
|
||||
PLAT_BL_COMMON_SOURCES := drivers/ti/uart/aarch64/16550_console.S \
|
||||
drivers/arm/pl011/aarch64/pl011_console.S \
|
||||
plat/rpi/common/rpi3_common.c \
|
||||
${XLAT_TABLES_LIB_SRCS}
|
||||
|
||||
BL31_SOURCES += lib/cpus/aarch64/cortex_a72.S \
|
||||
plat/rpi/common/aarch64/plat_helpers.S \
|
||||
plat/rpi/rpi4/aarch64/armstub8_header.S \
|
||||
drivers/delay_timer/delay_timer.c \
|
||||
drivers/gpio/gpio.c \
|
||||
drivers/rpi3/gpio/rpi3_gpio.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} \
|
||||
${GICV2_SOURCES}
|
||||
|
||||
# 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
|
||||
|
||||
# SMCCC PCI support (should be enabled for ACPI builds)
|
||||
SMC_PCI_SUPPORT := 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))
|
||||
$(eval $(call add_define,SMC_PCI_SUPPORT))
|
||||
|
||||
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
|
||||
|
||||
ifeq ($(SMC_PCI_SUPPORT), 1)
|
||||
BL31_SOURCES += plat/rpi/rpi4/rpi4_pci_svc.c
|
||||
endif
|
||||
|
||||
@@ -0,0 +1,304 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdint.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 <common/fdt_wrappers.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)
|
||||
|
||||
{
|
||||
/*
|
||||
* 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. */
|
||||
rpi3_console_init();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove the FDT /memreserve/ entry that covers the region at the very
|
||||
* beginning of memory (if that exists). This is where the secondaries
|
||||
* originally spin, but we pull them out there.
|
||||
* Having overlapping /reserved-memory and /memreserve/ regions confuses
|
||||
* the Linux kernel, so we need to get rid of this one.
|
||||
*/
|
||||
static void remove_spintable_memreserve(void *dtb)
|
||||
{
|
||||
uint64_t addr, size;
|
||||
int regions = fdt_num_mem_rsv(dtb);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < regions; i++) {
|
||||
if (fdt_get_mem_rsv(dtb, i, &addr, &size) != 0) {
|
||||
return;
|
||||
}
|
||||
if (size == 0U) {
|
||||
return;
|
||||
}
|
||||
/* We only look for the region at the beginning of DRAM. */
|
||||
if (addr != 0U) {
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* Currently the region in the existing DTs is exactly 4K
|
||||
* in size. Should this value ever change, there is probably
|
||||
* a reason for that, so inform the user about this.
|
||||
*/
|
||||
if (size == 4096U) {
|
||||
fdt_del_mem_rsv(dtb, i);
|
||||
return;
|
||||
}
|
||||
WARN("Keeping unknown /memreserve/ region at 0, size: %" PRId64 "\n",
|
||||
size);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove the original reserved region (used for the spintable), and
|
||||
* replace it with a region describing the whole of Trusted Firmware.
|
||||
*/
|
||||
remove_spintable_memreserve(dtb);
|
||||
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, fdt_blob_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();
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* The RPi4 has a single nonstandard PCI config region. It is broken into two
|
||||
* pieces, the root port config registers and a window to a single device's
|
||||
* config space which can move between devices. There isn't (yet) an
|
||||
* authoritative public document on this since the available BCM2711 reference
|
||||
* notes that there is a PCIe root port in the memory map but doesn't describe
|
||||
* it. Given that it's not ECAM compliant yet reasonably simple, it makes for
|
||||
* an excellent example of the PCI SMCCC interface.
|
||||
*
|
||||
* The PCI SMCCC interface is described in DEN0115 availabe from:
|
||||
* https://developer.arm.com/documentation/den0115/latest
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <common/debug.h>
|
||||
#include <common/runtime_svc.h>
|
||||
#include <lib/pmf/pmf.h>
|
||||
#include <lib/runtime_instr.h>
|
||||
#include <services/pci_svc.h>
|
||||
#include <services/sdei.h>
|
||||
#include <services/std_svc.h>
|
||||
#include <smccc_helpers.h>
|
||||
|
||||
#include <lib/mmio.h>
|
||||
|
||||
static spinlock_t pci_lock;
|
||||
|
||||
#define PCIE_REG_BASE U(RPI_IO_BASE + 0x01500000)
|
||||
#define PCIE_MISC_PCIE_STATUS 0x4068
|
||||
#define PCIE_EXT_CFG_INDEX 0x9000
|
||||
/* A small window pointing at the ECAM of the device selected by CFG_INDEX */
|
||||
#define PCIE_EXT_CFG_DATA 0x8000
|
||||
#define INVALID_PCI_ADDR 0xFFFFFFFF
|
||||
|
||||
#define PCIE_EXT_BUS_SHIFT 20
|
||||
#define PCIE_EXT_DEV_SHIFT 15
|
||||
#define PCIE_EXT_FUN_SHIFT 12
|
||||
|
||||
|
||||
static uint64_t pci_segment_lib_get_base(uint32_t address, uint32_t offset)
|
||||
{
|
||||
uint64_t base;
|
||||
uint32_t bus, dev, fun;
|
||||
uint32_t status;
|
||||
|
||||
base = PCIE_REG_BASE;
|
||||
|
||||
offset &= PCI_OFFSET_MASK; /* Pick off the 4k register offset */
|
||||
|
||||
/* The root port is at the base of the PCIe register space */
|
||||
if (address != 0U) {
|
||||
/*
|
||||
* The current device must be at CFG_DATA, a 4K window mapped,
|
||||
* via CFG_INDEX, to the device we are accessing. At the same
|
||||
* time we must avoid accesses to certain areas of the cfg
|
||||
* space via CFG_DATA. Detect those accesses and report that
|
||||
* the address is invalid.
|
||||
*/
|
||||
base += PCIE_EXT_CFG_DATA;
|
||||
bus = PCI_ADDR_BUS(address);
|
||||
dev = PCI_ADDR_DEV(address);
|
||||
fun = PCI_ADDR_FUN(address);
|
||||
address = (bus << PCIE_EXT_BUS_SHIFT) |
|
||||
(dev << PCIE_EXT_DEV_SHIFT) |
|
||||
(fun << PCIE_EXT_FUN_SHIFT);
|
||||
|
||||
/* Allow only dev = 0 on root port and bus 1 */
|
||||
if ((bus < 2U) && (dev > 0U)) {
|
||||
return INVALID_PCI_ADDR;
|
||||
}
|
||||
|
||||
/* Assure link up before reading bus 1 */
|
||||
status = mmio_read_32(PCIE_REG_BASE + PCIE_MISC_PCIE_STATUS);
|
||||
if ((status & 0x30) != 0x30) {
|
||||
return INVALID_PCI_ADDR;
|
||||
}
|
||||
|
||||
/* Adjust which device the CFG_DATA window is pointing at */
|
||||
mmio_write_32(PCIE_REG_BASE + PCIE_EXT_CFG_INDEX, address);
|
||||
}
|
||||
return base + offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* pci_read_config() - Performs a config space read at addr
|
||||
* @addr: 32-bit, segment, BDF of requested function encoded per DEN0115
|
||||
* @off: register offset of function described by @addr to read
|
||||
* @sz: size of read (8,16,32) bits.
|
||||
* @val: returned zero extended value read from config space
|
||||
*
|
||||
* sz bits of PCI config space is read at addr:offset, and the value
|
||||
* is returned in val. Invalid segment/offset values return failure.
|
||||
* Reads to valid functions that don't exist return INVALID_PCI_ADDR
|
||||
* as is specified by PCI for requests that aren't completed by EPs.
|
||||
* The boilerplate in pci_svc.c tends to do basic segment, off
|
||||
* and sz validation. This routine should avoid duplicating those
|
||||
* checks.
|
||||
*
|
||||
* This function maps directly to the PCI_READ function in DEN0115
|
||||
* where detailed requirements may be found.
|
||||
*
|
||||
* Return: SMC_PCI_CALL_SUCCESS with val set
|
||||
* SMC_PCI_CALL_INVAL_PARAM, on parameter error
|
||||
*/
|
||||
uint32_t pci_read_config(uint32_t addr, uint32_t off, uint32_t sz, uint32_t *val)
|
||||
{
|
||||
uint32_t ret = SMC_PCI_CALL_SUCCESS;
|
||||
uint64_t base;
|
||||
|
||||
spin_lock(&pci_lock);
|
||||
base = pci_segment_lib_get_base(addr, off);
|
||||
|
||||
if (base == INVALID_PCI_ADDR) {
|
||||
*val = base;
|
||||
} else {
|
||||
switch (sz) {
|
||||
case SMC_PCI_SZ_8BIT:
|
||||
*val = mmio_read_8(base);
|
||||
break;
|
||||
case SMC_PCI_SZ_16BIT:
|
||||
*val = mmio_read_16(base);
|
||||
break;
|
||||
case SMC_PCI_SZ_32BIT:
|
||||
*val = mmio_read_32(base);
|
||||
break;
|
||||
default: /* should be unreachable */
|
||||
*val = 0;
|
||||
ret = SMC_PCI_CALL_INVAL_PARAM;
|
||||
}
|
||||
}
|
||||
spin_unlock(&pci_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* pci_write_config() - Performs a config space write at addr
|
||||
* @addr: 32-bit, segment, BDF of requested function encoded per DEN0115
|
||||
* @off: register offset of function described by @addr to write
|
||||
* @sz: size of write (8,16,32) bits.
|
||||
* @val: value to be written
|
||||
*
|
||||
* sz bits of PCI config space is written at addr:offset. Invalid
|
||||
* segment/BDF values return failure. Writes to valid functions
|
||||
* without valid EPs are ignored, as is specified by PCI.
|
||||
* The boilerplate in pci_svc.c tends to do basic segment, off
|
||||
* and sz validation, so it shouldn't need to be repeated here.
|
||||
*
|
||||
* This function maps directly to the PCI_WRITE function in DEN0115
|
||||
* where detailed requirements may be found.
|
||||
*
|
||||
* Return: SMC_PCI_CALL_SUCCESS
|
||||
* SMC_PCI_CALL_INVAL_PARAM, on parameter error
|
||||
*/
|
||||
uint32_t pci_write_config(uint32_t addr, uint32_t off, uint32_t sz, uint32_t val)
|
||||
{
|
||||
uint32_t ret = SMC_PCI_CALL_SUCCESS;
|
||||
uint64_t base;
|
||||
|
||||
spin_lock(&pci_lock);
|
||||
base = pci_segment_lib_get_base(addr, off);
|
||||
|
||||
if (base != INVALID_PCI_ADDR) {
|
||||
switch (sz) {
|
||||
case SMC_PCI_SZ_8BIT:
|
||||
mmio_write_8(base, val);
|
||||
break;
|
||||
case SMC_PCI_SZ_16BIT:
|
||||
mmio_write_16(base, val);
|
||||
break;
|
||||
case SMC_PCI_SZ_32BIT:
|
||||
mmio_write_32(base, val);
|
||||
break;
|
||||
default: /* should be unreachable */
|
||||
ret = SMC_PCI_CALL_INVAL_PARAM;
|
||||
}
|
||||
}
|
||||
spin_unlock(&pci_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* pci_get_bus_for_seg() - returns the start->end bus range for a segment
|
||||
* @seg: segment being queried
|
||||
* @bus_range: returned bus begin + (end << 8)
|
||||
* @nseg: returns next segment in this machine or 0 for end
|
||||
*
|
||||
* pci_get_bus_for_seg is called to check if a given segment is
|
||||
* valid on this machine. If it is valid, then its bus ranges are
|
||||
* returned along with the next valid segment on the machine. If
|
||||
* this is the last segment, then nseg must be 0.
|
||||
*
|
||||
* This function maps directly to the PCI_GET_SEG_INFO function
|
||||
* in DEN0115 where detailed requirements may be found.
|
||||
*
|
||||
* Return: SMC_PCI_CALL_SUCCESS, and appropriate bus_range and nseg
|
||||
* SMC_PCI_CALL_NOT_IMPL, if the segment is invalid
|
||||
*/
|
||||
uint32_t pci_get_bus_for_seg(uint32_t seg, uint32_t *bus_range, uint32_t *nseg)
|
||||
{
|
||||
uint32_t ret = SMC_PCI_CALL_SUCCESS;
|
||||
*nseg = 0U; /* only a single segment */
|
||||
if (seg == 0U) {
|
||||
*bus_range = 0xFF00; /* start 0, end 255 */
|
||||
} else {
|
||||
*bus_range = 0U;
|
||||
ret = SMC_PCI_CALL_NOT_IMPL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
Reference in New Issue
Block a user