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;
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;
}
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;
#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)
{
PLAT_PARTITION_MAX_ENTRIES := 12
$(eval $(call add_define,PLAT_PARTITION_MAX_ENTRIES))
+- **PLAT_PARTITION_BLOCK_SIZE**
+ The size of partition block. It could be either 512 bytes or 4096 bytes.
+ The default value is 512.
+ `For example, define the build flag in platform.mk`_:
+ PLAT_PARTITION_BLOCK_SIZE := 4096
+ $(eval $(call add_define,PLAT_PARTITION_BLOCK_SIZE))
+
The following constant is optional. It should be defined to override the default
behaviour of the ``assert()`` function (for example, to save memory).
above the CPU might require initialization due to having previously been in
low power states. The generic code expects the handler to succeed.
+plat_psci_ops.pwr_domain_on_finish_late() [optional]
+...........................................................
+
+This optional function is called by the PSCI implementation after the calling
+CPU is fully powered on with respective data caches enabled. The calling CPU and
+the associated cluster are guaranteed to be participating in coherency. This
+function gives the flexibility to perform any platform-specific actions safely,
+such as initialization or modification of shared data structures, without the
+overhead of explicit cache maintainace operations.
+
+The ``target_state`` has a similar meaning as described in the ``pwr_domain_on_finish()``
+operation. The generic code expects the handler to succeed.
+
plat_psci_ops.pwr_domain_suspend_finish()
.........................................
:F: drivers/amlogic/gxl
:F: plat/amlogic/gxl/
+Amlogic Meson S905X2 (G12A) platform port
+---------------------------------------
+:M: Carlo Caione <ccaione@baylibre.com>
+:G: `carlo.caione`_
+:F: docs/plat/meson-g12a.rst
+:F: drivers/amlogic/g12a
+:F: plat/amlogic/g12a/
+
Armv7-A architecture port
-------------------------
:M: Etienne Carriere <etienne.carriere@linaro.org>
--- /dev/null
+Amlogic Meson S905X2 (G12A)
+==========================
+
+The Amlogic Meson S905X2 is a SoC with a quad core Arm Cortex-A53 running at
+~1.8GHz. It also contains a Cortex-M3 used as SCP.
+
+This port is a minimal implementation of BL31 capable of booting mainline U-Boot
+and Linux:
+
+- SCPI support.
+- Basic PSCI support (CPU_ON, CPU_OFF, SYSTEM_RESET, SYSTEM_OFF). Note that CPU0
+ can't be turned off, so there is a workaround to hide this from the caller.
+- GICv2 driver set up.
+- Basic SIP services (read efuse data, enable/disable JTAG).
+
+In order to build it:
+
+.. code:: shell
+
+ CROSS_COMPILE=aarch64-linux-gnu- make DEBUG=1 PLAT=g12a
+
+This port has been tested on a SEI510 board. After building it, follow the
+instructions in the `gxlimg repository` or `U-Boot repository`_, replacing the
+mentioned **bl31.img** by the one built from this port.
+
+.. _gxlimg repository: https://github.com/repk/gxlimg/blob/master/README.g12a
+.. _U-Boot repository: https://github.com/u-boot/u-boot/blob/master/board/amlogic/sei510/README
--- /dev/null
+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.
#include <crypto/sha_dma.h>
#include <lib/mmio.h>
-#define AML_SHA_DMA_BASE 0xc883e000
-
-#define AML_SHA_DMA_DESC (AML_SHA_DMA_BASE + 0x08)
-#define AML_SHA_DMA_STATUS (AML_SHA_DMA_BASE + 0x18)
+#include "aml_private.h"
#define ASD_MODE_SHA224 0x7
#define ASD_MODE_SHA256 0x6
#include "gicv3_private.h"
const gicv3_driver_data_t *gicv3_driver_data;
-static unsigned int gicv2_compat;
/*
* Spinlock to guard registers needing read-modify-write. APIs protected by this
void __init gicv3_driver_init(const gicv3_driver_data_t *plat_driver_data)
{
unsigned int gic_version;
+ unsigned int gicv2_compat;
assert(plat_driver_data != NULL);
assert(plat_driver_data->gicd_base != 0U);
- assert(plat_driver_data->gicr_base != 0U);
assert(plat_driver_data->rdistif_num != 0U);
assert(plat_driver_data->rdistif_base_addrs != NULL);
assert(IS_IN_EL3());
- assert(plat_driver_data->interrupt_props_num > 0 ?
- plat_driver_data->interrupt_props != NULL : 1);
+ assert((plat_driver_data->interrupt_props_num != 0U) ?
+ (plat_driver_data->interrupt_props != NULL) : 1);
/* Check for system register support */
-#ifdef __aarch64__
+#ifndef __aarch64__
+ assert((read_id_pfr1() &
+ (ID_PFR1_GIC_MASK << ID_PFR1_GIC_SHIFT)) != 0U);
+#else
assert((read_id_aa64pfr0_el1() &
(ID_AA64PFR0_GIC_MASK << ID_AA64PFR0_GIC_SHIFT)) != 0U);
-#else
- assert((read_id_pfr1() & (ID_PFR1_GIC_MASK << ID_PFR1_GIC_SHIFT)) != 0U);
-#endif /* __aarch64__ */
+#endif /* !__aarch64__ */
/* The GIC version should be 3.0 */
gic_version = gicd_read_pidr2(plat_driver_data->gicd_base);
- gic_version >>= PIDR2_ARCH_REV_SHIFT;
+ gic_version >>= PIDR2_ARCH_REV_SHIFT;
gic_version &= PIDR2_ARCH_REV_MASK;
assert(gic_version == ARCH_REV_GICV3);
/*
- * Find out whether the GIC supports the GICv2 compatibility mode. The
- * ARE_S bit resets to 0 if supported
+ * Find out whether the GIC supports the GICv2 compatibility mode.
+ * The ARE_S bit resets to 0 if supported
*/
gicv2_compat = gicd_read_ctlr(plat_driver_data->gicd_base);
gicv2_compat >>= CTLR_ARE_S_SHIFT;
- gicv2_compat = !(gicv2_compat & CTLR_ARE_S_MASK);
-
- /*
- * Find the base address of each implemented Redistributor interface.
- * The number of interfaces should be equal to the number of CPUs in the
- * system. The memory for saving these addresses has to be allocated by
- * the platform port
- */
- gicv3_rdistif_base_addrs_probe(plat_driver_data->rdistif_base_addrs,
- plat_driver_data->rdistif_num,
- plat_driver_data->gicr_base,
- plat_driver_data->mpidr_to_core_pos);
-
+ gicv2_compat = gicv2_compat & CTLR_ARE_S_MASK;
+
+ if (plat_driver_data->gicr_base != 0U) {
+ /*
+ * Find the base address of each implemented Redistributor interface.
+ * The number of interfaces should be equal to the number of CPUs in the
+ * system. The memory for saving these addresses has to be allocated by
+ * the platform port
+ */
+ gicv3_rdistif_base_addrs_probe(plat_driver_data->rdistif_base_addrs,
+ plat_driver_data->rdistif_num,
+ plat_driver_data->gicr_base,
+ plat_driver_data->mpidr_to_core_pos);
+#if !HW_ASSISTED_COHERENCY
+ /*
+ * Flush the rdistif_base_addrs[] contents linked to the GICv3 driver.
+ */
+ flush_dcache_range((uintptr_t)(plat_driver_data->rdistif_base_addrs),
+ plat_driver_data->rdistif_num *
+ sizeof(*(plat_driver_data->rdistif_base_addrs)));
+#endif
+ }
gicv3_driver_data = plat_driver_data;
/*
* enabled. When the secondary CPU boots up, it initializes the
* GICC/GICR interface with the caches disabled. Hence flush the
* driver data to ensure coherency. This is not required if the
- * platform has HW_ASSISTED_COHERENCY or WARMBOOT_ENABLE_DCACHE_EARLY
- * enabled.
+ * platform has HW_ASSISTED_COHERENCY enabled.
*/
-#if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY)
- flush_dcache_range((uintptr_t) &gicv3_driver_data,
- sizeof(gicv3_driver_data));
- flush_dcache_range((uintptr_t) gicv3_driver_data,
- sizeof(*gicv3_driver_data));
+#if !HW_ASSISTED_COHERENCY
+ flush_dcache_range((uintptr_t)&gicv3_driver_data,
+ sizeof(gicv3_driver_data));
+ flush_dcache_range((uintptr_t)gicv3_driver_data,
+ sizeof(*gicv3_driver_data));
#endif
- INFO("GICv3 %s legacy support detected."
- " ARM GICV3 driver initialized in EL3\n",
- gicv2_compat ? "with" : "without");
+ INFO("GICv3 with%s legacy support detected."
+ " ARM GICv3 driver initialized in EL3\n",
+ (gicv2_compat == 0U) ? "" : "out");
+
}
/*******************************************************************************
gicv3_rdistif_on(proc_num);
gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+ assert(gicr_base != 0U);
/* Set the default attribute of all SGIs and PPIs */
gicv3_ppi_sgi_config_defaults(gicr_base);
/* Mark the connected core as asleep */
gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+ assert(gicr_base != 0U);
gicv3_rdistif_mark_core_asleep(gicr_base);
}
num_ints &= TYPER_IT_LINES_NO_MASK;
num_ints = (num_ints + 1U) << 5;
- assert(num_ints <= (MAX_SPI_ID + 1U));
+ /* Filter out special INTIDs 1020-1023 */
+ if (num_ints > (MAX_SPI_ID + 1U))
+ num_ints = MAX_SPI_ID + 1U;
/* Wait for pending write to complete */
gicd_wait_for_pending_write(gicd_base);
/* Save the GICD_CTLR */
dist_ctx->gicd_ctlr = gicd_read_ctlr(gicd_base);
- /* Save GICD_IGROUPR for INTIDs 32 - 1020 */
+ /* Save GICD_IGROUPR for INTIDs 32 - 1019 */
SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, igroupr, IGROUPR);
- /* Save GICD_ISENABLER for INT_IDs 32 - 1020 */
+ /* Save GICD_ISENABLER for INT_IDs 32 - 1019 */
SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, isenabler, ISENABLER);
- /* Save GICD_ISPENDR for INTIDs 32 - 1020 */
+ /* Save GICD_ISPENDR for INTIDs 32 - 1019 */
SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, ispendr, ISPENDR);
- /* Save GICD_ISACTIVER for INTIDs 32 - 1020 */
+ /* Save GICD_ISACTIVER for INTIDs 32 - 1019 */
SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, isactiver, ISACTIVER);
- /* Save GICD_IPRIORITYR for INTIDs 32 - 1020 */
+ /* Save GICD_IPRIORITYR for INTIDs 32 - 1019 */
SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, ipriorityr, IPRIORITYR);
- /* Save GICD_ICFGR for INTIDs 32 - 1020 */
+ /* Save GICD_ICFGR for INTIDs 32 - 1019 */
SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, icfgr, ICFGR);
- /* Save GICD_IGRPMODR for INTIDs 32 - 1020 */
+ /* Save GICD_IGRPMODR for INTIDs 32 - 1019 */
SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, igrpmodr, IGRPMODR);
- /* Save GICD_NSACR for INTIDs 32 - 1020 */
+ /* Save GICD_NSACR for INTIDs 32 - 1019 */
SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, nsacr, NSACR);
- /* Save GICD_IROUTER for INTIDs 32 - 1024 */
+ /* Save GICD_IROUTER for INTIDs 32 - 1019 */
SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, irouter, IROUTER);
/*
num_ints &= TYPER_IT_LINES_NO_MASK;
num_ints = (num_ints + 1U) << 5;
- assert(num_ints <= (MAX_SPI_ID + 1U));
+ /* Filter out special INTIDs 1020-1023 */
+ if (num_ints > (MAX_SPI_ID + 1U))
+ num_ints = MAX_SPI_ID + 1U;
- /* Restore GICD_IGROUPR for INTIDs 32 - 1020 */
+ /* Restore GICD_IGROUPR for INTIDs 32 - 1019 */
RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, igroupr, IGROUPR);
- /* Restore GICD_IPRIORITYR for INTIDs 32 - 1020 */
+ /* Restore GICD_IPRIORITYR for INTIDs 32 - 1019 */
RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, ipriorityr, IPRIORITYR);
- /* Restore GICD_ICFGR for INTIDs 32 - 1020 */
+ /* Restore GICD_ICFGR for INTIDs 32 - 1019 */
RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, icfgr, ICFGR);
- /* Restore GICD_IGRPMODR for INTIDs 32 - 1020 */
+ /* Restore GICD_IGRPMODR for INTIDs 32 - 1019 */
RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, igrpmodr, IGRPMODR);
- /* Restore GICD_NSACR for INTIDs 32 - 1020 */
+ /* Restore GICD_NSACR for INTIDs 32 - 1019 */
RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, nsacr, NSACR);
- /* Restore GICD_IROUTER for INTIDs 32 - 1020 */
+ /* Restore GICD_IROUTER for INTIDs 32 - 1019 */
RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, irouter, IROUTER);
/*
* configured.
*/
- /* Restore GICD_ISENABLER for INT_IDs 32 - 1020 */
+ /* Restore GICD_ISENABLER for INT_IDs 32 - 1019 */
RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, isenabler, ISENABLER);
- /* Restore GICD_ISPENDR for INTIDs 32 - 1020 */
+ /* Restore GICD_ISPENDR for INTIDs 32 - 1019 */
RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, ispendr, ISPENDR);
- /* Restore GICD_ISACTIVER for INTIDs 32 - 1020 */
+ /* Restore GICD_ISACTIVER for INTIDs 32 - 1019 */
RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, isactiver, ISACTIVER);
/* Restore the GICD_CTLR */
return old_mask;
}
+
+/*******************************************************************************
+ * This function delegates the responsibility of discovering the corresponding
+ * Redistributor frames to each CPU itself. It is a modified version of
+ * gicv3_rdistif_base_addrs_probe() and is executed by each CPU in the platform
+ * unlike the previous way in which only the Primary CPU did the discovery of
+ * all the Redistributor frames for every CPU. It also handles the scenario in
+ * which the frames of various CPUs are not contiguous in physical memory.
+ ******************************************************************************/
+int gicv3_rdistif_probe(const uintptr_t gicr_frame)
+{
+ u_register_t mpidr;
+ unsigned int proc_num, proc_self;
+ uint64_t typer_val;
+ uintptr_t rdistif_base;
+ bool gicr_frame_found = false;
+
+ assert(gicv3_driver_data->gicr_base == 0U);
+
+ /* Ensure this function is called with Data Cache enabled */
+#ifndef __aarch64__
+ assert((read_sctlr() & SCTLR_C_BIT) != 0U);
+#else
+ assert((read_sctlr_el3() & SCTLR_C_BIT) != 0U);
+#endif /* !__aarch64__ */
+
+ proc_self = gicv3_driver_data->mpidr_to_core_pos(read_mpidr_el1());
+ rdistif_base = gicr_frame;
+ do {
+ typer_val = gicr_read_typer(rdistif_base);
+ if (gicv3_driver_data->mpidr_to_core_pos != NULL) {
+ mpidr = mpidr_from_gicr_typer(typer_val);
+ proc_num = gicv3_driver_data->mpidr_to_core_pos(mpidr);
+ } else {
+ proc_num = (unsigned int)(typer_val >> TYPER_PROC_NUM_SHIFT) &
+ TYPER_PROC_NUM_MASK;
+ }
+ if (proc_num == proc_self) {
+ /* The base address doesn't need to be initialized on
+ * every warm boot.
+ */
+ if (gicv3_driver_data->rdistif_base_addrs[proc_num] != 0U)
+ return 0;
+ gicv3_driver_data->rdistif_base_addrs[proc_num] =
+ rdistif_base;
+ gicr_frame_found = true;
+ break;
+ }
+ rdistif_base += (uintptr_t)(ULL(1) << GICR_PCPUBASE_SHIFT);
+ } while ((typer_val & TYPER_LAST_BIT) == 0U);
+
+ if (!gicr_frame_found)
+ return -1;
+
+ /*
+ * Flush the driver data to ensure coherency. This is
+ * not required if platform has HW_ASSISTED_COHERENCY
+ * enabled.
+ */
+#if !HW_ASSISTED_COHERENCY
+ /*
+ * Flush the rdistif_base_addrs[] contents linked to the GICv3 driver.
+ */
+ flush_dcache_range((uintptr_t)&(gicv3_driver_data->rdistif_base_addrs[proc_num]),
+ sizeof(*(gicv3_driver_data->rdistif_base_addrs)));
+#endif
+ return 0; /* Found matching GICR frame */
+}
if (result != 0) {
return result;
}
- entry->start = (uint64_t)gpt_entry->first_lba * PARTITION_BLOCK_SIZE;
+ entry->start = (uint64_t)gpt_entry->first_lba *
+ PLAT_PARTITION_BLOCK_SIZE;
entry->length = (uint64_t)(gpt_entry->last_lba -
gpt_entry->first_lba + 1) *
- PARTITION_BLOCK_SIZE;
+ PLAT_PARTITION_BLOCK_SIZE;
return 0;
}
#include <drivers/partition/mbr.h>
#include <plat/common/platform.h>
-static uint8_t mbr_sector[PARTITION_BLOCK_SIZE];
+static uint8_t mbr_sector[PLAT_PARTITION_BLOCK_SIZE];
static partition_entry_list_t list;
#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
return result;
}
result = io_read(image_handle, (uintptr_t)&mbr_sector,
- PARTITION_BLOCK_SIZE, &bytes_read);
+ PLAT_PARTITION_BLOCK_SIZE, &bytes_read);
if (result != 0) {
WARN("Failed to read data (%i)\n", result);
return result;
}
/* Check MBR boot signature. */
- if ((mbr_sector[PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) ||
- (mbr_sector[PARTITION_BLOCK_SIZE - 1] != MBR_SIGNATURE_SECOND)) {
+ if ((mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) ||
+ (mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 1] != MBR_SIGNATURE_SECOND)) {
return -ENOENT;
}
offset = (uintptr_t)&mbr_sector + MBR_PRIMARY_ENTRY_OFFSET;
return result;
}
result = io_read(image_handle, (uintptr_t)&mbr_sector,
- PARTITION_BLOCK_SIZE, &bytes_read);
+ PLAT_PARTITION_BLOCK_SIZE, &bytes_read);
if (result != 0) {
WARN("Failed to read data (%i)\n", result);
return result;
}
/* Check MBR boot signature. */
- if ((mbr_sector[PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) ||
- (mbr_sector[PARTITION_BLOCK_SIZE - 1] != MBR_SIGNATURE_SECOND)) {
+ if ((mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) ||
+ (mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 1] != MBR_SIGNATURE_SECOND)) {
return -ENOENT;
}
offset = (uintptr_t)&mbr_sector +
interrupt-parent = <&gic>;
#address-cells = <1>;
#size-cells = <1>;
+
+ psci {
+ compatible = "arm,psci-1.0", "arm,psci-0.2", "arm,psci";
+ method = "smc";
+ cpu_on = <0x84000003>;
+ };
+
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
device_type = "cpu";
compatible = "arm,cortex-a5";
+ enable-method = "psci";
reg = <0>;
};
+ cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a5";
+ enable-method = "psci";
+ reg = <1>;
+ };
+ cpu@2 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a5";
+ enable-method = "psci";
+ reg = <2>;
+ };
+ cpu@3 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a5";
+ enable-method = "psci";
+ reg = <3>;
+ };
};
memory@80000000 {
/*
- * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
* GICv3 EL3 driver API
******************************************************************************/
void gicv3_driver_init(const gicv3_driver_data_t *plat_driver_data);
+int gicv3_rdistif_probe(const uintptr_t gicr_frame);
void gicv3_distif_init(void);
void gicv3_rdistif_init(unsigned int proc_num);
void gicv3_rdistif_on(unsigned int proc_num);
#include <drivers/partition/partition.h>
#define PARTITION_TYPE_GPT 0xee
-#define GPT_HEADER_OFFSET PARTITION_BLOCK_SIZE
+#define GPT_HEADER_OFFSET PLAT_PARTITION_BLOCK_SIZE
#define GPT_ENTRY_OFFSET (GPT_HEADER_OFFSET + \
- PARTITION_BLOCK_SIZE)
+ PLAT_PARTITION_BLOCK_SIZE)
#define GUID_LEN 16
#define GPT_SIGNATURE "EFI PART"
CASSERT(PLAT_PARTITION_MAX_ENTRIES <= 128, assert_plat_partition_max_entries);
-#define PARTITION_BLOCK_SIZE 512
+#if !PLAT_PARTITION_BLOCK_SIZE
+# define PLAT_PARTITION_BLOCK_SIZE 512
+#endif /* PLAT_PARTITION_BLOCK_SIZE */
+
+CASSERT((PLAT_PARTITION_BLOCK_SIZE == 512) ||
+ (PLAT_PARTITION_BLOCK_SIZE == 4096),
+ assert_plat_partition_block_size);
+
+#define LEGACY_PARTITION_BLOCK_SIZE 512
#define EFI_NAMELEN 36
/*
- * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
const psci_power_state_t *target_state);
void (*pwr_domain_suspend)(const psci_power_state_t *target_state);
void (*pwr_domain_on_finish)(const psci_power_state_t *target_state);
+ void (*pwr_domain_on_finish_late)(
+ const psci_power_state_t *target_state);
void (*pwr_domain_suspend_finish)(
const psci_power_state_t *target_state);
void __dead2 (*pwr_domain_pwr_down_wfi)(
int css_pwr_domain_on(u_register_t mpidr);
void css_pwr_domain_on_finish(const psci_power_state_t *target_state);
+void css_pwr_domain_on_finish_late(const psci_power_state_t *target_state);
void css_pwr_domain_off(const psci_power_state_t *target_state);
void css_pwr_domain_suspend(const psci_power_state_t *target_state);
void css_pwr_domain_suspend_finish(
* world, and only for the secure world when CTX_INCLUDE_MTE_REGS is
* set.
*/
- unsigned int mte = get_armv8_5_mte_support();
#if CTX_INCLUDE_MTE_REGS
- assert(mte == MTE_IMPLEMENTED_ELX);
+ assert(get_armv8_5_mte_support() == MTE_IMPLEMENTED_ELX);
scr_el3 |= SCR_ATA_BIT;
#else
+ unsigned int mte = get_armv8_5_mte_support();
if (mte == MTE_IMPLEMENTED_EL0) {
/*
* Can enable MTE across both worlds as no MTE registers are
/*
- * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
psci_do_pwrup_cache_maintenance();
#endif
+ /*
+ * Plat. management: Perform any platform specific actions which
+ * can only be done with the cpu and the cluster guaranteed to
+ * be coherent.
+ */
+ if (psci_plat_pm_ops->pwr_domain_on_finish_late != NULL)
+ psci_plat_pm_ops->pwr_domain_on_finish_late(state_info);
+
/*
* All the platform specific actions for turning this cpu
* on have completed. Perform enough arch.initialization
--- /dev/null
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <common/bl_common.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gicv2.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_mmu_helpers.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#include "aml_private.h"
+
+/*
+ * Placeholder variables for copying the arguments that have been passed to
+ * BL31 from BL2.
+ */
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+static image_info_t bl30_image_info;
+static image_info_t bl301_image_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;
+
+ 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 != 0U)
+ return next_image_info;
+
+ return NULL;
+}
+
+/*******************************************************************************
+ * Perform any BL31 early platform setup. Here is an opportunity to copy
+ * parameters passed by the calling EL (S-EL1 in BL2 & S-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.
+ ******************************************************************************/
+struct g12a_bl31_param {
+ param_header_t h;
+ image_info_t *bl31_image_info;
+ entry_point_info_t *bl32_ep_info;
+ image_info_t *bl32_image_info;
+ entry_point_info_t *bl33_ep_info;
+ image_info_t *bl33_image_info;
+ image_info_t *scp_image_info[];
+};
+
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+ u_register_t arg2, u_register_t arg3)
+{
+ struct g12a_bl31_param *from_bl2;
+
+ /* Initialize the console to provide early debug support */
+ aml_console_init();
+
+ from_bl2 = (struct g12a_bl31_param *)arg0;
+
+ /* Check params passed from BL2 are not NULL. */
+ assert(from_bl2 != NULL);
+ assert(from_bl2->h.type == PARAM_BL31);
+ assert(from_bl2->h.version >= VERSION_1);
+
+ /*
+ * Copy BL32 and BL33 entry point information. It is stored in Secure
+ * RAM, in BL2's address space.
+ */
+ bl32_image_ep_info = *from_bl2->bl32_ep_info;
+ bl33_image_ep_info = *from_bl2->bl33_ep_info;
+
+ if (bl33_image_ep_info.pc == 0U) {
+ ERROR("BL31: BL33 entrypoint not obtained from BL2\n");
+ panic();
+ }
+
+ bl30_image_info = *from_bl2->scp_image_info[0];
+ bl301_image_info = *from_bl2->scp_image_info[1];
+}
+
+void bl31_plat_arch_setup(void)
+{
+ aml_setup_page_tables();
+
+ enable_mmu_el3(0);
+}
+
+/*******************************************************************************
+ * GICv2 driver setup information
+ ******************************************************************************/
+static const interrupt_prop_t g12a_interrupt_props[] = {
+ INTR_PROP_DESC(IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY,
+ GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+ INTR_PROP_DESC(IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY,
+ GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+ INTR_PROP_DESC(IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY,
+ GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+ INTR_PROP_DESC(IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY,
+ GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+ INTR_PROP_DESC(IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY,
+ GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+ INTR_PROP_DESC(IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY,
+ GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+ INTR_PROP_DESC(IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY,
+ GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+ INTR_PROP_DESC(IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY,
+ GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+ INTR_PROP_DESC(IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY,
+ GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL)
+};
+
+static const gicv2_driver_data_t g12a_gic_data = {
+ .gicd_base = AML_GICD_BASE,
+ .gicc_base = AML_GICC_BASE,
+ .interrupt_props = g12a_interrupt_props,
+ .interrupt_props_num = ARRAY_SIZE(g12a_interrupt_props)
+};
+
+void bl31_platform_setup(void)
+{
+ aml_mhu_secure_init();
+
+ gicv2_driver_init(&g12a_gic_data);
+ gicv2_distif_init();
+ gicv2_pcpu_distif_init();
+ gicv2_cpuif_enable();
+}
--- /dev/null
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <bl31/interrupt_mgmt.h>
+#include <common/bl_common.h>
+#include <common/ep_info.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <platform_def.h>
+#include <stdint.h>
+
+/*******************************************************************************
+ * Platform memory map regions
+ ******************************************************************************/
+#define MAP_NSDRAM0 MAP_REGION_FLAT(AML_NSDRAM0_BASE, \
+ AML_NSDRAM0_SIZE, \
+ MT_MEMORY | MT_RW | MT_NS)
+
+#define MAP_NS_SHARE_MEM MAP_REGION_FLAT(AML_NS_SHARE_MEM_BASE, \
+ AML_NS_SHARE_MEM_SIZE, \
+ MT_MEMORY | MT_RW | MT_NS)
+
+#define MAP_SEC_SHARE_MEM MAP_REGION_FLAT(AML_SEC_SHARE_MEM_BASE, \
+ AML_SEC_SHARE_MEM_SIZE, \
+ MT_MEMORY | MT_RW | MT_SECURE)
+
+#define MAP_SEC_DEVICE0 MAP_REGION_FLAT(AML_SEC_DEVICE0_BASE, \
+ AML_SEC_DEVICE0_SIZE, \
+ MT_DEVICE | MT_RW)
+
+#define MAP_HDCP_RX MAP_REGION_FLAT(AML_HDCP_RX_BASE, \
+ AML_HDCP_RX_SIZE, \
+ MT_DEVICE | MT_RW | MT_SECURE)
+
+#define MAP_HDCP_TX MAP_REGION_FLAT(AML_HDCP_TX_BASE, \
+ AML_HDCP_TX_SIZE, \
+ MT_DEVICE | MT_RW | MT_SECURE)
+
+#define MAP_GIC_DEVICE MAP_REGION_FLAT(AML_GIC_DEVICE_BASE, \
+ AML_GIC_DEVICE_SIZE, \
+ MT_DEVICE | MT_RW | MT_SECURE)
+
+#define MAP_SEC_DEVICE1 MAP_REGION_FLAT(AML_SEC_DEVICE1_BASE, \
+ AML_SEC_DEVICE1_SIZE, \
+ MT_DEVICE | MT_RW | MT_SECURE)
+
+#define MAP_SEC_DEVICE2 MAP_REGION_FLAT(AML_SEC_DEVICE2_BASE, \
+ AML_SEC_DEVICE2_SIZE, \
+ MT_DEVICE | MT_RW | MT_SECURE)
+
+#define MAP_TZRAM MAP_REGION_FLAT(AML_TZRAM_BASE, \
+ AML_TZRAM_SIZE, \
+ MT_DEVICE | MT_RW | MT_SECURE)
+
+static const mmap_region_t g12a_mmap[] = {
+ MAP_NSDRAM0,
+ MAP_NS_SHARE_MEM,
+ MAP_SEC_SHARE_MEM,
+ MAP_SEC_DEVICE0,
+ MAP_HDCP_RX,
+ MAP_HDCP_TX,
+ MAP_GIC_DEVICE,
+ MAP_SEC_DEVICE1,
+ MAP_SEC_DEVICE2,
+ MAP_TZRAM,
+ {0}
+};
+
+/*******************************************************************************
+ * Per-image regions
+ ******************************************************************************/
+#define MAP_BL31 MAP_REGION_FLAT(BL31_BASE, \
+ BL31_END - BL31_BASE, \
+ MT_MEMORY | MT_RW | MT_SECURE)
+
+#define MAP_BL_CODE MAP_REGION_FLAT(BL_CODE_BASE, \
+ BL_CODE_END - BL_CODE_BASE, \
+ MT_CODE | MT_SECURE)
+
+#define MAP_BL_RO_DATA MAP_REGION_FLAT(BL_RO_DATA_BASE, \
+ BL_RO_DATA_END - BL_RO_DATA_BASE, \
+ MT_RO_DATA | MT_SECURE)
+
+#define MAP_BL_COHERENT MAP_REGION_FLAT(BL_COHERENT_RAM_BASE, \
+ BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE, \
+ MT_DEVICE | MT_RW | MT_SECURE)
+
+/*******************************************************************************
+ * Function that sets up the translation tables.
+ ******************************************************************************/
+void aml_setup_page_tables(void)
+{
+#if IMAGE_BL31
+ const mmap_region_t g12a_bl_mmap[] = {
+ MAP_BL31,
+ MAP_BL_CODE,
+ MAP_BL_RO_DATA,
+#if USE_COHERENT_MEM
+ MAP_BL_COHERENT,
+#endif
+ {0}
+ };
+#endif
+
+ mmap_add(g12a_bl_mmap);
+
+ mmap_add(g12a_mmap);
+
+ init_xlat_tables();
+}
+
+/*******************************************************************************
+ * Function that returns the system counter frequency
+ ******************************************************************************/
+unsigned int plat_get_syscnt_freq2(void)
+{
+ mmio_clrbits_32(AML_SYS_CPU_CFG7, ~0xFDFFFFFF);
+ mmio_clrbits_32(AML_AO_TIMESTAMP_CNTL, ~0xFFFFFE00);
+
+ return AML_OSC24M_CLK_IN_HZ;
+}
--- /dev/null
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef G12A_DEF_H
+#define G12A_DEF_H
+
+#include <lib/utils_def.h>
+
+/*******************************************************************************
+ * System oscillator
+ ******************************************************************************/
+#define AML_OSC24M_CLK_IN_HZ ULL(24000000) /* 24 MHz */
+
+/*******************************************************************************
+ * Memory regions
+ ******************************************************************************/
+#define AML_HDCP_RX_BASE UL(0xFFE0D000)
+#define AML_HDCP_RX_SIZE UL(0x00002000)
+
+#define AML_HDCP_TX_BASE UL(0xFFE01000)
+#define AML_HDCP_TX_SIZE UL(0x00001000)
+
+#define AML_NS_SHARE_MEM_BASE UL(0x05000000)
+#define AML_NS_SHARE_MEM_SIZE UL(0x00100000)
+
+#define AML_SEC_SHARE_MEM_BASE UL(0x05200000)
+#define AML_SEC_SHARE_MEM_SIZE UL(0x00100000)
+
+#define AML_GIC_DEVICE_BASE UL(0xFFC00000)
+#define AML_GIC_DEVICE_SIZE UL(0x00008000)
+
+#define AML_NSDRAM0_BASE UL(0x01000000)
+#define AML_NSDRAM0_SIZE UL(0x0F000000)
+
+#define BL31_BASE UL(0x05100000)
+#define BL31_SIZE UL(0x00100000)
+#define BL31_LIMIT (BL31_BASE + BL31_SIZE)
+
+/* Shared memory used for SMC services */
+#define AML_SHARE_MEM_INPUT_BASE UL(0x050FE000)
+#define AML_SHARE_MEM_OUTPUT_BASE UL(0x050FF000)
+
+#define AML_SEC_DEVICE0_BASE UL(0xFFD00000)
+#define AML_SEC_DEVICE0_SIZE UL(0x00026000)
+
+#define AML_SEC_DEVICE1_BASE UL(0xFF800000)
+#define AML_SEC_DEVICE1_SIZE UL(0x0000A000)
+
+#define AML_TZRAM_BASE UL(0xFFFA0000)
+#define AML_TZRAM_SIZE UL(0x00048000)
+
+/* Mailboxes */
+#define AML_MHU_SECURE_SCP_TO_AP_PAYLOAD UL(0xFFFE7800)
+#define AML_MHU_SECURE_AP_TO_SCP_PAYLOAD UL(0xFFFE7A00)
+#define AML_PSCI_MAILBOX_BASE UL(0xFFFE7F00)
+
+#define AML_SEC_DEVICE2_BASE UL(0xFF620000)
+#define AML_SEC_DEVICE2_SIZE UL(0x00028000)
+
+/*******************************************************************************
+ * GIC-400 and interrupt handling related constants
+ ******************************************************************************/
+#define AML_GICD_BASE UL(0xFFC01000)
+#define AML_GICC_BASE UL(0xFFC02000)
+
+#define IRQ_SEC_PHY_TIMER 29
+
+#define IRQ_SEC_SGI_0 8
+#define IRQ_SEC_SGI_1 9
+#define IRQ_SEC_SGI_2 10
+#define IRQ_SEC_SGI_3 11
+#define IRQ_SEC_SGI_4 12
+#define IRQ_SEC_SGI_5 13
+#define IRQ_SEC_SGI_6 14
+#define IRQ_SEC_SGI_7 15
+#define IRQ_SEC_SGI_8 16
+
+/*******************************************************************************
+ * UART definitions
+ ******************************************************************************/
+#define AML_UART0_AO_BASE UL(0xFF803000)
+#define AML_UART0_AO_CLK_IN_HZ AML_OSC24M_CLK_IN_HZ
+#define AML_UART_BAUDRATE U(115200)
+
+/*******************************************************************************
+ * Memory-mapped I/O Registers
+ ******************************************************************************/
+#define AML_AO_TIMESTAMP_CNTL UL(0xFF8000B4)
+
+#define AML_SYS_CPU_CFG7 UL(0xFF634664)
+
+#define AML_AO_RTI_STATUS_REG3 UL(0xFF80001C)
+#define AML_AO_RTI_SCP_STAT UL(0xFF80023C)
+#define AML_AO_RTI_SCP_READY_OFF U(0x14)
+#define AML_A0_RTI_SCP_READY_MASK U(3)
+#define AML_AO_RTI_SCP_IS_READY(v) \
+ ((((v) >> AML_AO_RTI_SCP_READY_OFF) & \
+ AML_A0_RTI_SCP_READY_MASK) == AML_A0_RTI_SCP_READY_MASK)
+
+#define AML_HIU_MAILBOX_SET_0 UL(0xFF63C404)
+#define AML_HIU_MAILBOX_STAT_0 UL(0xFF63C408)
+#define AML_HIU_MAILBOX_CLR_0 UL(0xFF63C40C)
+#define AML_HIU_MAILBOX_SET_3 UL(0xFF63C428)
+#define AML_HIU_MAILBOX_STAT_3 UL(0xFF63C42C)
+#define AML_HIU_MAILBOX_CLR_3 UL(0xFF63C430)
+
+#define AML_SHA_DMA_BASE UL(0xFF63E000)
+#define AML_SHA_DMA_DESC (AML_SHA_DMA_BASE + 0x08)
+#define AML_SHA_DMA_STATUS (AML_SHA_DMA_BASE + 0x28)
+
+/*******************************************************************************
+ * System Monitor Call IDs and arguments
+ ******************************************************************************/
+#define AML_SM_GET_SHARE_MEM_INPUT_BASE U(0x82000020)
+#define AML_SM_GET_SHARE_MEM_OUTPUT_BASE U(0x82000021)
+
+#define AML_SM_EFUSE_READ U(0x82000030)
+#define AML_SM_EFUSE_USER_MAX U(0x82000033)
+
+#define AML_SM_JTAG_ON U(0x82000040)
+#define AML_SM_JTAG_OFF U(0x82000041)
+#define AML_SM_GET_CHIP_ID U(0x82000044)
+
+#define AML_JTAG_STATE_ON U(0)
+#define AML_JTAG_STATE_OFF U(1)
+
+#define AML_JTAG_M3_AO U(0)
+#define AML_JTAG_M3_EE U(1)
+#define AML_JTAG_A53_AO U(2)
+#define AML_JTAG_A53_EE U(3)
+
+#endif /* G12A_DEF_H */
--- /dev/null
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <common/debug.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/console.h>
+#include <errno.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#include "aml_private.h"
+
+#define SCPI_POWER_ON 0
+#define SCPI_POWER_RETENTION 1
+#define SCPI_POWER_OFF 3
+
+#define SCPI_SYSTEM_SHUTDOWN 0
+#define SCPI_SYSTEM_REBOOT 1
+
+static uintptr_t g12a_sec_entrypoint;
+static volatile uint32_t g12a_cpu0_go;
+
+static void g12a_pm_set_reset_addr(u_register_t mpidr, uint64_t value)
+{
+ unsigned int core = plat_calc_core_pos(mpidr);
+ uintptr_t cpu_mailbox_addr = AML_PSCI_MAILBOX_BASE + (core << 4);
+
+ mmio_write_64(cpu_mailbox_addr, value);
+}
+
+static void g12a_pm_reset(u_register_t mpidr)
+{
+ unsigned int core = plat_calc_core_pos(mpidr);
+ uintptr_t cpu_mailbox_addr = AML_PSCI_MAILBOX_BASE + (core << 4) + 8;
+
+ mmio_write_32(cpu_mailbox_addr, 0);
+}
+
+static void __dead2 g12a_system_reset(void)
+{
+ INFO("BL31: PSCI_SYSTEM_RESET\n");
+
+ u_register_t mpidr = read_mpidr_el1();
+ uint32_t status = mmio_read_32(AML_AO_RTI_STATUS_REG3);
+ int ret;
+
+ NOTICE("BL31: Reboot reason: 0x%x\n", status);
+
+ status &= 0xFFFF0FF0;
+
+ console_flush();
+
+ mmio_write_32(AML_AO_RTI_STATUS_REG3, status);
+
+ ret = aml_scpi_sys_power_state(SCPI_SYSTEM_REBOOT);
+
+ if (ret != 0) {
+ ERROR("BL31: PSCI_SYSTEM_RESET: SCP error: %i\n", ret);
+ panic();
+ }
+
+ g12a_pm_reset(mpidr);
+
+ wfi();
+
+ ERROR("BL31: PSCI_SYSTEM_RESET: Operation not handled\n");
+ panic();
+}
+
+static void __dead2 g12a_system_off(void)
+{
+ INFO("BL31: PSCI_SYSTEM_OFF\n");
+
+ u_register_t mpidr = read_mpidr_el1();
+ int ret;
+
+ ret = aml_scpi_sys_power_state(SCPI_SYSTEM_SHUTDOWN);
+
+ if (ret != 0) {
+ ERROR("BL31: PSCI_SYSTEM_OFF: SCP error %i\n", ret);
+ panic();
+ }
+
+ g12a_pm_set_reset_addr(mpidr, 0);
+ g12a_pm_reset(mpidr);
+
+ wfi();
+
+ ERROR("BL31: PSCI_SYSTEM_OFF: Operation not handled\n");
+ panic();
+}
+
+static int32_t g12a_pwr_domain_on(u_register_t mpidr)
+{
+ unsigned int core = plat_calc_core_pos(mpidr);
+
+ /* CPU0 can't be turned OFF */
+ if (core == AML_PRIMARY_CPU) {
+ VERBOSE("BL31: Releasing CPU0 from wait loop...\n");
+
+ g12a_cpu0_go = 1;
+ flush_dcache_range((uintptr_t)&g12a_cpu0_go,
+ sizeof(g12a_cpu0_go));
+ dsb();
+ isb();
+
+ sev();
+
+ return PSCI_E_SUCCESS;
+ }
+
+ g12a_pm_set_reset_addr(mpidr, g12a_sec_entrypoint);
+ aml_scpi_set_css_power_state(mpidr,
+ SCPI_POWER_ON, SCPI_POWER_ON, SCPI_POWER_ON);
+ dmbsy();
+ sev();
+
+ return PSCI_E_SUCCESS;
+}
+
+static void g12a_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+ unsigned int core = plat_calc_core_pos(read_mpidr_el1());
+
+ assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] ==
+ PLAT_LOCAL_STATE_OFF);
+
+ if (core == AML_PRIMARY_CPU) {
+ g12a_cpu0_go = 0;
+ flush_dcache_range((uintptr_t)&g12a_cpu0_go,
+ sizeof(g12a_cpu0_go));
+ dsb();
+ isb();
+ }
+
+ gicv2_pcpu_distif_init();
+ gicv2_cpuif_enable();
+}
+
+static void g12a_pwr_domain_off(const psci_power_state_t *target_state)
+{
+ u_register_t mpidr = read_mpidr_el1();
+ unsigned int core = plat_calc_core_pos(mpidr);
+
+ gicv2_cpuif_disable();
+
+ /* CPU0 can't be turned OFF */
+ if (core == AML_PRIMARY_CPU)
+ return;
+
+ aml_scpi_set_css_power_state(mpidr,
+ SCPI_POWER_OFF, SCPI_POWER_ON,
+ SCPI_POWER_ON);
+}
+
+static void __dead2 g12a_pwr_domain_pwr_down_wfi(const psci_power_state_t
+ *target_state)
+{
+ u_register_t mpidr = read_mpidr_el1();
+ unsigned int core = plat_calc_core_pos(mpidr);
+
+ /* CPU0 can't be turned OFF, emulate it with a WFE loop */
+ if (core == AML_PRIMARY_CPU) {
+ VERBOSE("BL31: CPU0 entering wait loop...\n");
+
+ while (g12a_cpu0_go == 0)
+ wfe();
+
+ VERBOSE("BL31: CPU0 resumed.\n");
+
+ /*
+ * Because setting CPU0's warm reset entrypoint through PSCI
+ * mailbox and/or mmio mapped RVBAR (0xda834650) does not seem
+ * to work, jump to it manually.
+ * In order to avoid an assert, MMU has to be disabled.
+ */
+ disable_mmu_el3();
+ ((void(*)(void))g12a_sec_entrypoint)();
+ }
+
+ dsbsy();
+ g12a_pm_set_reset_addr(mpidr, 0);
+ g12a_pm_reset(mpidr);
+
+ for (;;)
+ wfi();
+}
+
+/*******************************************************************************
+ * Platform handlers and setup function.
+ ******************************************************************************/
+static const plat_psci_ops_t g12a_ops = {
+ .pwr_domain_on = g12a_pwr_domain_on,
+ .pwr_domain_on_finish = g12a_pwr_domain_on_finish,
+ .pwr_domain_off = g12a_pwr_domain_off,
+ .pwr_domain_pwr_down_wfi = g12a_pwr_domain_pwr_down_wfi,
+ .system_off = g12a_system_off,
+ .system_reset = g12a_system_reset
+};
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+ const plat_psci_ops_t **psci_ops)
+{
+ g12a_sec_entrypoint = sec_entrypoint;
+ *psci_ops = &g12a_ops;
+ g12a_cpu0_go = 0;
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (c) 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 <lib/utils_def.h>
+
+#include "../g12a_def.h"
+
+#define PLATFORM_LINKER_FORMAT "elf64-littleaarch64"
+#define PLATFORM_LINKER_ARCH aarch64
+
+#define PLATFORM_STACK_SIZE UL(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 AML_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 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)
+
+/* 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 16
+#define MAX_XLAT_TABLES 8
+
+#endif /* PLATFORM_DEF_H */
--- /dev/null
+#
+# Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include lib/xlat_tables_v2/xlat_tables.mk
+
+AML_PLAT := plat/amlogic
+AML_PLAT_SOC := ${AML_PLAT}/${PLAT}
+AML_PLAT_COMMON := ${AML_PLAT}/common
+
+DOIMAGEPATH ?= tools/amlogic
+DOIMAGETOOL ?= ${DOIMAGEPATH}/doimage
+
+PLAT_INCLUDES := -Iinclude/drivers/amlogic/ \
+ -I${AML_PLAT_SOC}/include \
+ -I${AML_PLAT_COMMON}/include
+
+GIC_SOURCES := drivers/arm/gic/common/gic_common.c \
+ drivers/arm/gic/v2/gicv2_main.c \
+ drivers/arm/gic/v2/gicv2_helpers.c \
+ plat/common/plat_gicv2.c
+
+BL31_SOURCES += lib/cpus/aarch64/cortex_a53.S \
+ plat/common/plat_psci_common.c \
+ drivers/amlogic/console/aarch64/meson_console.S \
+ ${AML_PLAT_SOC}/${PLAT}_bl31_setup.c \
+ ${AML_PLAT_SOC}/${PLAT}_pm.c \
+ ${AML_PLAT_SOC}/${PLAT}_common.c \
+ ${AML_PLAT_COMMON}/aarch64/aml_helpers.S \
+ ${AML_PLAT_COMMON}/aml_efuse.c \
+ ${AML_PLAT_COMMON}/aml_mhu.c \
+ ${AML_PLAT_COMMON}/aml_scpi.c \
+ ${AML_PLAT_COMMON}/aml_sip_svc.c \
+ ${AML_PLAT_COMMON}/aml_thermal.c \
+ ${AML_PLAT_COMMON}/aml_topology.c \
+ ${AML_PLAT_COMMON}/aml_console.c \
+ drivers/amlogic/crypto/sha_dma.c \
+ ${XLAT_TABLES_LIB_SRCS} \
+ ${GIC_SOURCES}
+
+# Tune compiler for Cortex-A53
+ifeq ($(notdir $(CC)),armclang)
+ TF_CFLAGS_aarch64 += -mcpu=cortex-a53
+else ifneq ($(findstring clang,$(notdir $(CC))),)
+ TF_CFLAGS_aarch64 += -mcpu=cortex-a53
+else
+ TF_CFLAGS_aarch64 += -mtune=cortex-a53
+endif
+
+# Build config flags
+# ------------------
+
+# Enable all errata workarounds for Cortex-A53
+ERRATA_A53_855873 := 1
+ERRATA_A53_819472 := 1
+ERRATA_A53_824069 := 1
+ERRATA_A53_827319 := 1
+
+WORKAROUND_CVE_2017_5715 := 0
+
+# Have different sections for code and rodata
+SEPARATE_CODE_AND_RODATA := 1
+
+# Use Coherent memory
+USE_COHERENT_MEM := 1
+
+# Verify build config
+# -------------------
+
+ifneq (${RESET_TO_BL31}, 0)
+ $(error Error: ${PLAT} needs RESET_TO_BL31=0)
+endif
+
+ifeq (${ARCH},aarch32)
+ $(error Error: AArch32 not supported on ${PLAT})
+endif
+
+all: ${BUILD_PLAT}/bl31.img
+distclean realclean clean: cleanimage
+
+cleanimage:
+ ${Q}${MAKE} -C ${DOIMAGEPATH} clean
+
+${DOIMAGETOOL}:
+ ${Q}${MAKE} -C ${DOIMAGEPATH}
+
+${BUILD_PLAT}/bl31.img: ${BUILD_PLAT}/bl31.bin ${DOIMAGETOOL}
+ ${DOIMAGETOOL} ${BUILD_PLAT}/bl31.bin ${BUILD_PLAT}/bl31.img
+
#define AML_HIU_MAILBOX_STAT_3 UL(0xDA83C42C)
#define AML_HIU_MAILBOX_CLR_3 UL(0xDA83C430)
+#define AML_SHA_DMA_BASE UL(0xC883E000)
+#define AML_SHA_DMA_DESC (AML_SHA_DMA_BASE + 0x08)
+#define AML_SHA_DMA_STATUS (AML_SHA_DMA_BASE + 0x18)
+
/*******************************************************************************
* System Monitor Call IDs and arguments
******************************************************************************/
BL31_SOURCES += lib/cpus/aarch64/cortex_a53.S \
plat/common/plat_psci_common.c \
drivers/amlogic/console/aarch64/meson_console.S \
- ${AML_PLAT_SOC}/gxbb_bl31_setup.c \
- ${AML_PLAT_SOC}/gxbb_pm.c \
- ${AML_PLAT_SOC}/gxbb_common.c \
+ ${AML_PLAT_SOC}/${PLAT}_bl31_setup.c \
+ ${AML_PLAT_SOC}/${PLAT}_pm.c \
+ ${AML_PLAT_SOC}/${PLAT}_common.c \
${AML_PLAT_COMMON}/aarch64/aml_helpers.S \
${AML_PLAT_COMMON}/aml_efuse.c \
${AML_PLAT_COMMON}/aml_mhu.c \
#define AML_HIU_MAILBOX_STAT_3 UL(0xDA83C42C)
#define AML_HIU_MAILBOX_CLR_3 UL(0xDA83C430)
+#define AML_SHA_DMA_BASE UL(0xC883E000)
+#define AML_SHA_DMA_DESC (AML_SHA_DMA_BASE + 0x08)
+#define AML_SHA_DMA_STATUS (AML_SHA_DMA_BASE + 0x18)
+
/*******************************************************************************
* System Monitor Call IDs and arguments
******************************************************************************/
BL31_SOURCES += lib/cpus/aarch64/cortex_a53.S \
plat/common/plat_psci_common.c \
drivers/amlogic/console/aarch64/meson_console.S \
- ${AML_PLAT_SOC}/gxl_bl31_setup.c \
- ${AML_PLAT_SOC}/gxl_pm.c \
- ${AML_PLAT_SOC}/gxl_common.c \
+ ${AML_PLAT_SOC}/${PLAT}_bl31_setup.c \
+ ${AML_PLAT_SOC}/${PLAT}_pm.c \
+ ${AML_PLAT_SOC}/${PLAT}_common.c \
${AML_PLAT_COMMON}/aarch64/aml_helpers.S \
${AML_PLAT_COMMON}/aml_efuse.c \
${AML_PLAT_COMMON}/aml_mhu.c \
#include <lib/psci/psci.h>
#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <drivers/arm/gicv2.h>
+
+/*******************************************************************************
+ * Platform handler called when a power domain is about to be turned on. The
+ * mpidr determines the CPU to be turned on.
+ ******************************************************************************/
+static int a5ds_pwr_domain_on(u_register_t mpidr)
+{
+ unsigned int pos = plat_core_pos_by_mpidr(mpidr);
+ uint64_t *hold_base = (uint64_t *)A5DS_HOLD_BASE;
+
+ hold_base[pos] = A5DS_HOLD_STATE_GO;
+ dsbish();
+ sev();
+
+ return PSCI_E_SUCCESS;
+}
+
+/*******************************************************************************
+ * Platform handler called when a power domain has just been powered on after
+ * being turned off earlier. The target_state encodes the low power state that
+ * each level has woken up from.
+ ******************************************************************************/
+void a5ds_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+ /* TODO: This setup is needed only after a cold boot*/
+ gicv2_pcpu_distif_init();
+
+ /* Enable the gic cpu interface */
+ gicv2_cpuif_enable();
+}
/*******************************************************************************
* Export the platform handlers via a5ds_psci_pm_ops. The ARM Standard
plat_psci_ops_t a5ds_psci_pm_ops = {
/* dummy struct */
.validate_ns_entrypoint = NULL,
+ .pwr_domain_on = a5ds_pwr_domain_on,
+ .pwr_domain_on_finish = a5ds_pwr_domain_on_finish
};
int __init plat_setup_psci_ops(uintptr_t sec_entrypoint,
const plat_psci_ops_t **psci_ops)
{
+ uintptr_t *mailbox = (void *)A5DS_TRUSTED_MAILBOX_BASE;
+ *mailbox = sec_entrypoint;
+
*psci_ops = &a5ds_psci_pm_ops;
return 0;
.globl plat_get_my_entrypoint
.globl plat_is_my_cpu_primary
- /* --------------------------------------------------------------------
+ /* -----------------------------------------------------
* void plat_secondary_cold_boot_setup (void);
*
- * For AArch32, cold-booting secondary CPUs is not yet
- * implemented and they panic.
- * --------------------------------------------------------------------
+ * 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
-cb_panic:
- wfi
- b cb_panic
+ /* Calculate address of our hold entry */
+ bl plat_my_core_pos
+ lsl r0, r0, #A5DS_HOLD_ENTRY_SHIFT
+ mov_imm r2, A5DS_HOLD_BASE
+ /* Clear the value stored in the hold address for the specific core */
+ mov_imm r3, A5DS_HOLD_STATE_WAIT
+ str r3, [r2, r0]
+ dmb ish
+
+ /* Wait until we have a go */
+poll_mailbox:
+ ldr r1, [r2, r0]
+ cmp r1, #A5DS_HOLD_STATE_WAIT
+ beq 1f
+ mov_imm r0, A5DS_TRUSTED_MAILBOX_BASE
+ ldr r1, [r0]
+ bx r1
+1:
+ wfe
+ b poll_mailbox
endfunc plat_secondary_cold_boot_setup
/* ---------------------------------------------------------------------
movne r0, #0
bx lr
endfunc plat_is_my_cpu_primary
+
+ /* ---------------------------------------------------------------------
+ * Loads MPIDR in r0 and calls plat_arm_calc_core_pos
+ * ---------------------------------------------------------------------
+ */
+func plat_my_core_pos
+ ldcopr r0, MPIDR
+ b plat_arm_calc_core_pos
+
+endfunc plat_my_core_pos
+
+ /* ---------------------------------------------------------------------
+ * unsigned int plat_arm_calc_core_pos(u_register_t mpidr)
+ *
+ * Function to calculate the core position on A5DS.
+ *
+ * (ClusterId * A5DS_MAX_CPUS_PER_CLUSTER * A5DS_MAX_PE_PER_CPU) +
+ * (CPUId * A5DS_MAX_PE_PER_CPU) +
+ * ThreadId
+ *
+ * which can be simplified as:
+ *
+ * ((ClusterId * A5DS_MAX_CPUS_PER_CLUSTER + CPUId) * A5DS_MAX_PE_PER_CPU)
+ * + ThreadId
+ * ---------------------------------------------------------------------
+ */
+func plat_arm_calc_core_pos
+ mov r3, r0
+
+ /*
+ * Check for MT bit in MPIDR. If not set, shift MPIDR to left to make it
+ * look as if in a multi-threaded implementation
+ */
+ tst r0, #MPIDR_MT_MASK
+ lsleq r3, r0, #MPIDR_AFFINITY_BITS
+
+ /* Extract individual affinity fields from MPIDR */
+ ubfx r0, r3, #MPIDR_AFF0_SHIFT, #MPIDR_AFFINITY_BITS
+ ubfx r1, r3, #MPIDR_AFF1_SHIFT, #MPIDR_AFFINITY_BITS
+ ubfx r2, r3, #MPIDR_AFF2_SHIFT, #MPIDR_AFFINITY_BITS
+
+ /* Compute linear position */
+ mov r3, #A5DS_MAX_CPUS_PER_CLUSTER
+ mla r1, r2, r3, r1
+ mov r3, #A5DS_MAX_PE_PER_CPU
+ mla r0, r1, r3, r0
+
+ bx lr
+endfunc plat_arm_calc_core_pos
/* Default number of threads per CPU on A5DS */
#define A5DS_MAX_PE_PER_CPU 1
-#define A5DS_CORE_COUNT 1
+#define A5DS_CORE_COUNT 4
-#define A5DS_PRIMARY_CPU 0x0
+#define A5DS_PRIMARY_CPU 0x0
#define FLASH1_BASE UL(0x8000000)
#define FLASH1_SIZE UL(0x2800000)
#define BL32_LIMIT (ARM_BL_RAM_BASE + ARM_BL_RAM_SIZE)
/* Required platform porting definitions */
-#define PLATFORM_CORE_COUNT 1
-#define PLAT_NUM_PWR_DOMAINS (A5DS_CLUSTER_COUNT + \
+#define PLATFORM_CORE_COUNT A5DS_CORE_COUNT
+#define PLAT_NUM_PWR_DOMAINS (A5DS_CLUSTER_COUNT + \
PLATFORM_CORE_COUNT) + 1
-#define PLAT_MAX_PWR_LVL 2
+#define PLAT_MAX_PWR_LVL 2
/*
* Other platform porting definitions are provided by included headers
/* Mailbox base address */
#define A5DS_TRUSTED_MAILBOX_BASE A5DS_SHARED_RAM_BASE
+#define A5DS_TRUSTED_MAILBOX_SIZE (8 + A5DS_HOLD_SIZE)
+#define A5DS_HOLD_BASE (A5DS_TRUSTED_MAILBOX_BASE + 8)
+#define A5DS_HOLD_SIZE (PLATFORM_CORE_COUNT * \
+ A5DS_HOLD_ENTRY_SIZE)
+#define A5DS_HOLD_ENTRY_SHIFT 3
+#define A5DS_HOLD_ENTRY_SIZE (1 << A5DS_HOLD_ENTRY_SHIFT)
+#define A5DS_HOLD_STATE_WAIT 0
+#define A5DS_HOLD_STATE_GO 1
/*
* GIC related constants to cater for GICv2
/*
- * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
{
fvp_power_domain_on_finish_common(target_state);
- /* Enable the gic cpu interface */
+}
+
+/*******************************************************************************
+ * FVP handler called when a power domain has just been powered on and the cpu
+ * and its cluster are fully participating in coherent transaction on the
+ * interconnect. Data cache must be enabled for CPU at this point.
+ ******************************************************************************/
+static void fvp_pwr_domain_on_finish_late(const psci_power_state_t *target_state)
+{
+ /* Program GIC per-cpu distributor or re-distributor interface */
plat_arm_gic_pcpu_init();
- /* Program the gic per-cpu distributor or re-distributor interface */
+ /* Enable GIC CPU interface */
plat_arm_gic_cpuif_enable();
}
fvp_power_domain_on_finish_common(target_state);
- /* Enable the gic cpu interface */
+ /* Enable GIC CPU interface */
plat_arm_gic_cpuif_enable();
}
.pwr_domain_off = fvp_pwr_domain_off,
.pwr_domain_suspend = fvp_pwr_domain_suspend,
.pwr_domain_on_finish = fvp_pwr_domain_on_finish,
+ .pwr_domain_on_finish_late = fvp_pwr_domain_on_finish_late,
.pwr_domain_suspend_finish = fvp_pwr_domain_suspend_finish,
.system_off = fvp_system_off,
.system_reset = fvp_system_reset,
* SPDX-License-Identifier: BSD-3-Clause
*/
+#include <assert.h>
#include <platform_def.h>
#include <common/interrupt_props.h>
static const gicv3_driver_data_t arm_gic_data __unused = {
.gicd_base = PLAT_ARM_GICD_BASE,
- .gicr_base = PLAT_ARM_GICR_BASE,
+ .gicr_base = 0U,
.interrupt_props = arm_interrupt_props,
.interrupt_props_num = ARRAY_SIZE(arm_interrupt_props),
.rdistif_num = PLATFORM_CORE_COUNT,
#if (!defined(__aarch64__) && defined(IMAGE_BL32)) || \
(defined(__aarch64__) && defined(IMAGE_BL31))
gicv3_driver_init(&arm_gic_data);
+
+ if (gicv3_rdistif_probe(PLAT_ARM_GICR_BASE) == -1) {
+ ERROR("No GICR base frame found for Primary CPU\n");
+ panic();
+ }
#endif
}
}
/******************************************************************************
- * ARM common helper to initialize the per-cpu redistributor interface in GICv3
+ * ARM common helper function to iterate over all GICR frames and discover the
+ * corresponding per-cpu redistributor frame as well as initialize the
+ * corresponding interface in GICv3. At the moment, Arm platforms do not have
+ * non-contiguous GICR frames.
*****************************************************************************/
void plat_arm_gic_pcpu_init(void)
{
+ int result;
+
+ result = gicv3_rdistif_probe(PLAT_ARM_GICR_BASE);
+ if (result == -1) {
+ ERROR("No GICR base frame found for CPU 0x%lx\n", read_mpidr());
+ panic();
+ }
gicv3_rdistif_init(plat_my_core_pos());
}
/*
- * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
{
assert(CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF);
- /* Enable the gic cpu interface */
- plat_arm_gic_cpuif_enable();
-
/*
* Perform the common cluster specific operations i.e enable coherency
* if this cluster was off.
/* Assert that the system power domain need not be initialized */
assert(css_system_pwr_state(target_state) == ARM_LOCAL_STATE_RUN);
+ css_pwr_domain_on_finisher_common(target_state);
+}
+
+/*******************************************************************************
+ * Handler called when a power domain has just been powered on and the cpu
+ * and its cluster are fully participating in coherent transaction on the
+ * interconnect. Data cache must be enabled for CPU at this point.
+ ******************************************************************************/
+void css_pwr_domain_on_finish_late(const psci_power_state_t *target_state)
+{
/* Program the gic per-cpu distributor or re-distributor interface */
plat_arm_gic_pcpu_init();
- css_pwr_domain_on_finisher_common(target_state);
+ /* Enable the gic cpu interface */
+ plat_arm_gic_cpuif_enable();
}
/*******************************************************************************
arm_system_pwr_domain_resume();
css_pwr_domain_on_finisher_common(target_state);
+
+ /* Enable the gic cpu interface */
+ plat_arm_gic_cpuif_enable();
}
/*******************************************************************************
plat_psci_ops_t plat_arm_psci_pm_ops = {
.pwr_domain_on = css_pwr_domain_on,
.pwr_domain_on_finish = css_pwr_domain_on_finish,
+ .pwr_domain_on_finish_late = css_pwr_domain_on_finish_late,
.pwr_domain_off = css_pwr_domain_off,
.cpu_standby = css_cpu_standby,
.pwr_domain_suspend = css_pwr_domain_suspend,
}
#endif /* __aarch64__ */
+int bl2_plat_handle_pre_image_load(unsigned int image_id)
+{
+ return hikey_set_fip_addr(image_id, "fastboot");
+}
+
int hikey_bl2_handle_post_image_load(unsigned int image_id)
{
int err = 0;
#include <drivers/io/io_memmap.h>
#include <drivers/io/io_storage.h>
#include <drivers/mmc.h>
+#include <drivers/partition/partition.h>
#include <lib/mmio.h>
#include <lib/semihosting.h>
#include <tools_share/firmware_image_package.h>
static int check_emmc(const uintptr_t spec);
static int check_fip(const uintptr_t spec);
-static const io_block_spec_t emmc_fip_spec = {
- .offset = HIKEY_FIP_BASE,
- .length = HIKEY_FIP_MAX_SIZE,
+static io_block_spec_t emmc_fip_spec;
+
+static const io_block_spec_t emmc_gpt_spec = {
+ .offset = 0,
+ .length = PLAT_PARTITION_BLOCK_SIZE *
+ (PLAT_PARTITION_MAX_ENTRIES / 4 + 2),
};
static const io_block_dev_spec_t emmc_dev_spec = {
check_fip
},
#endif /* TRUSTED_BOARD_BOOT */
+ [GPT_IMAGE_ID] = {
+ &emmc_dev_handle,
+ (uintptr_t)&emmc_gpt_spec,
+ check_emmc
+ },
};
static int check_emmc(const uintptr_t spec)
(void)result;
}
+int hikey_set_fip_addr(unsigned int image_id, const char *name)
+{
+ const partition_entry_t *entry;
+
+ if (emmc_fip_spec.length == 0) {
+ partition_init(GPT_IMAGE_ID);
+ entry = get_partition_entry(name);
+ if (entry == NULL) {
+ ERROR("Could NOT find the %s partition!\n", name);
+ return -ENOENT;
+ }
+ emmc_fip_spec.offset = entry->start;
+ emmc_fip_spec.length = entry->length;
+ }
+ return 0;
+}
+
/* Return an IO device handle and specification which can be used to access
* an image. Use this to enforce platform load policy
*/
void init_acpu_dvfs(void);
+int hikey_set_fip_addr(unsigned int image_id, const char *name);
+
#endif /* HIKEY_PRIVATE_H */
#define HIKEY_BL1_MMC_DATA_SIZE 0x0000B000
#define EMMC_BASE 0
-#define HIKEY_FIP_BASE (EMMC_BASE + (4 << 20))
-#define HIKEY_FIP_MAX_SIZE (8 << 20)
#define HIKEY_EMMC_RPMB_BASE (EMMC_BASE + 0)
#define HIKEY_EMMC_RPMB_MAX_SIZE (128 << 10)
#define HIKEY_EMMC_USERDATA_BASE (EMMC_BASE + 0)
drivers/io/io_fip.c \
drivers/io/io_storage.c \
drivers/mmc/mmc.c \
+ drivers/partition/gpt.c \
+ drivers/partition/partition.c \
drivers/synopsys/emmc/dw_mmc.c \
lib/cpus/aarch64/cortex_a53.S \
plat/hisilicon/hikey/aarch64/hikey_helpers.S \
#include <drivers/delay_timer.h>
#include <drivers/dw_ufs.h>
#include <drivers/generic_delay_timer.h>
+#include <drivers/partition/partition.h>
#include <drivers/ufs.h>
#include <lib/mmio.h>
#ifdef SPD_opteed
* This function can be used by the platforms to update/use image
* information for given `image_id`.
******************************************************************************/
+int bl2_plat_handle_pre_image_load(unsigned int image_id)
+{
+ return hikey960_set_fip_addr(image_id, "fip");
+}
+
int bl2_plat_handle_post_image_load(unsigned int image_id)
{
return hikey960_bl2_handle_post_image_load(image_id);
#define PL011_UART_CLK_IN_HZ 19200000
#define UFS_BASE 0
-/* FIP partition */
-#define HIKEY960_FIP_BASE (UFS_BASE + 0x1400000)
-#define HIKEY960_FIP_MAX_SIZE (12 << 20)
#define HIKEY960_UFS_DESC_BASE 0x20000000
#define HIKEY960_UFS_DESC_SIZE 0x00200000 /* 2MB */
#include <drivers/io/io_fip.h>
#include <drivers/io/io_memmap.h>
#include <drivers/io/io_storage.h>
+#include <drivers/partition/partition.h>
#include <lib/mmio.h>
#include <lib/semihosting.h>
#include <tools_share/firmware_image_package.h>
size_t ufs_read_lun3_blks(int lba, uintptr_t buf, size_t size);
size_t ufs_write_lun3_blks(int lba, const uintptr_t buf, size_t size);
-static const io_block_spec_t ufs_fip_spec = {
- .offset = HIKEY960_FIP_BASE,
- .length = HIKEY960_FIP_MAX_SIZE,
+static io_block_spec_t ufs_fip_spec;
+
+static const io_block_spec_t ufs_gpt_spec = {
+ .offset = 0,
+ .length = PLAT_PARTITION_BLOCK_SIZE *
+ (PLAT_PARTITION_MAX_ENTRIES / 4 + 2),
};
static const io_block_dev_spec_t ufs_dev_spec = {
check_fip
},
#endif /* TRUSTED_BOARD_BOOT */
+ [GPT_IMAGE_ID] = {
+ &ufs_dev_handle,
+ (uintptr_t)&ufs_gpt_spec,
+ check_ufs
+ },
};
static int check_ufs(const uintptr_t spec)
(void)result;
}
+int hikey960_set_fip_addr(unsigned int image_id, const char *name)
+{
+ const partition_entry_t *entry;
+
+ if (ufs_fip_spec.length == 0) {
+ partition_init(GPT_IMAGE_ID);
+ entry = get_partition_entry(name);
+ if (entry == NULL) {
+ ERROR("Could NOT find the %s partition!\n", name);
+ return -ENOENT;
+ }
+ ufs_fip_spec.offset = entry->start;
+ ufs_fip_spec.length = entry->length;
+ }
+ return 0;
+}
+
/* Return an IO device handle and specification which can be used to access
* an image. Use this to enforce platform load policy
*/
unsigned long coh_limit);
void hikey960_io_setup(void);
int hikey960_read_boardid(unsigned int *id);
+int hikey960_set_fip_addr(unsigned int image_id, const char *name);
void hikey960_clk_init(void);
void hikey960_pmu_init(void);
void hikey960_regulator_enable(void);
PLAT_PL061_MAX_GPIOS := 176
PROGRAMMABLE_RESET_ADDRESS := 1
ENABLE_SVE_FOR_NS := 0
+PLAT_PARTITION_BLOCK_SIZE := 4096
# Process flags
$(eval $(call add_define,HIKEY960_TSP_RAM_LOCATION_ID))
$(eval $(call add_define,CRASH_CONSOLE_BASE))
$(eval $(call add_define,PLAT_PL061_MAX_GPIOS))
+$(eval $(call add_define,PLAT_PARTITION_BLOCK_SIZE))
# Add the build options to pack Trusted OS Extra1 and Trusted OS Extra2 images
# in the FIP if the platform requires.
drivers/io/io_block.c \
drivers/io/io_fip.c \
drivers/io/io_storage.c \
+ drivers/partition/gpt.c \
+ drivers/partition/partition.c \
drivers/synopsys/ufs/dw_ufs.c \
drivers/ufs/ufs.c \
lib/cpus/aarch64/cortex_a53.S \
******************************************************************************/
/* 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
******************************************************************************/
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) {
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
******************************************************************************/
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;
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();
}
}
+/*******************************************************************************
+ * 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
{
/* 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
--- /dev/null
+/*
+ * 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:
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
+}
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+#
+# 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
--- /dev/null
+/*
+ * 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();
+}