mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-17 01:54:22 +00:00
Merge changes from topic "allwinner_h616" into integration
* changes: allwinner: H616: Add reserved-memory node to DT allwinner: Add Allwinner H616 SoC support allwinner: Add H616 SoC ID allwinner: Express memmap more dynamically allwinner: Move sunxi_cpu_power_off_self() into platforms allwinner: Move SEPARATE_NOBITS_REGION to platforms doc: allwinner: Reorder sections, document memory mapping
This commit is contained in:
commit
8078b5c5a0
20 changed files with 484 additions and 151 deletions
|
@ -5,22 +5,8 @@ Trusted Firmware-A (TF-A) implements the EL3 firmware layer for Allwinner
|
|||
SoCs with ARMv8 cores. Only BL31 is used to provide proper EL3 setup and
|
||||
PSCI runtime services.
|
||||
|
||||
U-Boot's SPL acts as a loader, loading both BL31 and BL33 (typically U-Boot).
|
||||
Loading is done from SD card, eMMC or SPI flash, also via an USB debug
|
||||
interface (FEL).
|
||||
|
||||
BL31 lives in SRAM A2, which is documented to be accessible from secure
|
||||
world only.
|
||||
|
||||
Current limitations:
|
||||
|
||||
- Missing PMIC support
|
||||
|
||||
After building bl31.bin, the binary must be fed to the U-Boot build system
|
||||
to include it in the FIT image that the SPL loader will process.
|
||||
bl31.bin can be either copied (or sym-linked) into U-Boot's root directory,
|
||||
or the environment variable BL31 must contain the binary's path.
|
||||
See the respective `U-Boot documentation`_ for more details.
|
||||
Building TF-A
|
||||
-------------
|
||||
|
||||
To build for machines with an A64 or H5 SoC:
|
||||
|
||||
|
@ -34,8 +20,75 @@ To build for machines with an H6 SoC:
|
|||
|
||||
make CROSS_COMPILE=aarch64-linux-gnu- PLAT=sun50i_h6 DEBUG=1 bl31
|
||||
|
||||
To build for machines with an H616 or H313 SoC:
|
||||
|
||||
.. code:: shell
|
||||
|
||||
make CROSS_COMPILE=aarch64-linux-gnu- PLAT=sun50i_h616 DEBUG=1 bl31
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
U-Boot's SPL acts as a loader, loading both BL31 and BL33 (typically U-Boot).
|
||||
Loading is done from SD card, eMMC or SPI flash, also via an USB debug
|
||||
interface (FEL).
|
||||
|
||||
After building bl31.bin, the binary must be fed to the U-Boot build system
|
||||
to include it in the FIT image that the SPL loader will process.
|
||||
bl31.bin can be either copied (or sym-linked) into U-Boot's root directory,
|
||||
or the environment variable BL31 must contain the binary's path.
|
||||
See the respective `U-Boot documentation`_ for more details.
|
||||
|
||||
.. _U-Boot documentation: https://gitlab.denx.de/u-boot/u-boot/-/blob/master/board/sunxi/README.sunxi64
|
||||
|
||||
Memory layout
|
||||
-------------
|
||||
|
||||
A64, H5 and H6 SoCs
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
BL31 lives in SRAM A2, which is documented to be accessible from secure
|
||||
world only. Since this SRAM region is very limited (48 KB), we take
|
||||
several measures to reduce memory consumption. One of them is to confine
|
||||
BL31 to only 28 bits of virtual address space, which reduces the number
|
||||
of required page tables (each occupying 4KB of memory).
|
||||
The mapping we use on those SoCs is as follows:
|
||||
|
||||
::
|
||||
|
||||
0 64K 16M 1GB 1G+160M physical address
|
||||
+-+------+-+---+------+--...---+-------+----+------+----------
|
||||
|B| |S|///| |//...///| |////| |
|
||||
|R| SRAM |C|///| dev |//...///| (sec) |////| BL33 | DRAM ...
|
||||
|O| |P|///| MMIO |//...///| DRAM |////| |
|
||||
|M| | |///| |//...///| (32M) |////| |
|
||||
+-+------+-+---+------+--...---+-------+----+------+----------
|
||||
| | | | | | / / / /
|
||||
| | | | | | / / / /
|
||||
| | | | | | / / / /
|
||||
| | | | | | / // /
|
||||
| | | | | | / / /
|
||||
+-+------+-+---+------+--+-------+------+
|
||||
|B| |S|///| |//| | |
|
||||
|R| SRAM |C|///| dev |//| sec | BL33 |
|
||||
|O| |P|///| MMIO |//| DRAM | |
|
||||
|M| | |///| |//| | |
|
||||
+-+------+-+---+------+--+-------+------+
|
||||
0 64K 16M 160M 192M 256M virtual address
|
||||
|
||||
|
||||
H616 SoC
|
||||
~~~~~~~~
|
||||
|
||||
The H616 lacks the secure SRAM region present on the other SoCs, also
|
||||
lacks the "ARISC" management processor (SCP) we use. BL31 thus needs to
|
||||
run from DRAM, which prevents our compressed virtual memory map described
|
||||
above. Since running in DRAM also lifts the restriction of the limited
|
||||
SRAM size, we use the normal 1:1 mapping with 32 bits worth of virtual
|
||||
address space. So the virtual addresses used in BL31 match the physical
|
||||
addresses as presented above.
|
||||
|
||||
Trusted OS dispatcher
|
||||
---------------------
|
||||
|
||||
|
|
|
@ -85,9 +85,6 @@ PROGRAMMABLE_RESET_ADDRESS := 1
|
|||
# Allow mapping read-only data as execute-never.
|
||||
SEPARATE_CODE_AND_RODATA := 1
|
||||
|
||||
# Put NOBITS memory in SRAM A1, overwriting U-Boot's SPL.
|
||||
SEPARATE_NOBITS_REGION := 1
|
||||
|
||||
# BL31 gets loaded alongside BL33 (U-Boot) by U-Boot's SPL
|
||||
RESET_TO_BL31 := 1
|
||||
|
||||
|
|
|
@ -13,18 +13,36 @@
|
|||
|
||||
#include <sunxi_mmap.h>
|
||||
|
||||
/* The SCP firmware is allocated the last 16KiB of SRAM A2. */
|
||||
#define SUNXI_SCP_SIZE 0x4000
|
||||
|
||||
#ifdef SUNXI_BL31_IN_DRAM
|
||||
|
||||
#define BL31_BASE SUNXI_DRAM_BASE
|
||||
#define BL31_LIMIT (SUNXI_DRAM_BASE + 0x40000)
|
||||
|
||||
#define MAX_XLAT_TABLES 4
|
||||
#define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32)
|
||||
|
||||
#define SUNXI_BL33_VIRT_BASE PRELOADED_BL33_BASE
|
||||
|
||||
#else /* !SUNXI_BL31_IN_DRAM */
|
||||
|
||||
#define BL31_BASE (SUNXI_SRAM_A2_BASE + 0x4000)
|
||||
#define BL31_LIMIT (SUNXI_SRAM_A2_BASE + \
|
||||
SUNXI_SRAM_A2_SIZE - SUNXI_SCP_SIZE)
|
||||
|
||||
/* The SCP firmware is allocated the last 16KiB of SRAM A2. */
|
||||
#define SUNXI_SCP_BASE BL31_LIMIT
|
||||
#define SUNXI_SCP_SIZE 0x4000
|
||||
|
||||
/* Overwrite U-Boot SPL, but reserve the first page for the SPL header. */
|
||||
#define BL31_NOBITS_BASE (SUNXI_SRAM_A1_BASE + 0x1000)
|
||||
#define BL31_NOBITS_LIMIT (SUNXI_SRAM_A1_BASE + SUNXI_SRAM_A1_SIZE)
|
||||
|
||||
#define MAX_XLAT_TABLES 1
|
||||
#define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 28)
|
||||
#define SUNXI_BL33_VIRT_BASE (SUNXI_DRAM_VIRT_BASE + SUNXI_DRAM_SEC_SIZE)
|
||||
|
||||
#endif /* SUNXI_BL31_IN_DRAM */
|
||||
|
||||
/* How much memory to reserve as secure for BL32, if configured */
|
||||
#define SUNXI_DRAM_SEC_SIZE (32U << 20)
|
||||
|
||||
|
@ -35,7 +53,6 @@
|
|||
#define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT)
|
||||
|
||||
#define MAX_MMAP_REGIONS (3 + PLATFORM_MMAP_REGIONS)
|
||||
#define MAX_XLAT_TABLES 1
|
||||
|
||||
#define PLAT_CSS_SCP_COM_SHARED_MEM_BASE \
|
||||
(SUNXI_SRAM_A2_BASE + SUNXI_SRAM_A2_SIZE - 0x200)
|
||||
|
@ -50,7 +67,6 @@
|
|||
PLATFORM_CORE_COUNT)
|
||||
|
||||
#define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32)
|
||||
#define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 28)
|
||||
|
||||
#define PLATFORM_CLUSTER_COUNT U(1)
|
||||
#define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER_COUNT * \
|
||||
|
|
|
@ -17,5 +17,6 @@
|
|||
#define SUNXI_SOC_A64 0x1689
|
||||
#define SUNXI_SOC_H5 0x1718
|
||||
#define SUNXI_SOC_H6 0x1728
|
||||
#define SUNXI_SOC_H616 0x1823
|
||||
|
||||
#endif /* SUNXI_DEF_H */
|
||||
|
|
|
@ -41,4 +41,12 @@ void sunxi_set_gpio_out(char port, int pin, bool level_high);
|
|||
int sunxi_init_platform_r_twi(uint16_t socid, bool use_rsb);
|
||||
void sunxi_execute_arisc_code(uint32_t *code, size_t size, uint16_t param);
|
||||
|
||||
#ifdef SUNXI_BL31_IN_DRAM
|
||||
void sunxi_prepare_dtb(void *fdt);
|
||||
#else
|
||||
static inline void sunxi_prepare_dtb(void *fdt)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SUNXI_PRIVATE_H */
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
#include <arch.h>
|
||||
#include <arch_helpers.h>
|
||||
#include <common/debug.h>
|
||||
#include <common/fdt_fixup.h>
|
||||
#include <common/fdt_wrappers.h>
|
||||
#include <drivers/arm/gicv2.h>
|
||||
#include <drivers/console.h>
|
||||
#include <drivers/generic_delay_timer.h>
|
||||
|
@ -52,7 +54,7 @@ static void *sunxi_find_dtb(void)
|
|||
uint64_t *u_boot_base;
|
||||
int i;
|
||||
|
||||
u_boot_base = (void *)(SUNXI_DRAM_VIRT_BASE + SUNXI_DRAM_SEC_SIZE);
|
||||
u_boot_base = (void *)SUNXI_BL33_VIRT_BASE;
|
||||
|
||||
for (i = 0; i < 2048 / sizeof(uint64_t); i++) {
|
||||
uint32_t *dtb_base;
|
||||
|
@ -123,6 +125,9 @@ void bl31_platform_setup(void)
|
|||
case SUNXI_SOC_H6:
|
||||
soc_name = "H6";
|
||||
break;
|
||||
case SUNXI_SOC_H616:
|
||||
soc_name = "H616";
|
||||
break;
|
||||
default:
|
||||
soc_name = "unknown";
|
||||
break;
|
||||
|
@ -172,6 +177,8 @@ void bl31_platform_setup(void)
|
|||
|
||||
sunxi_pmic_setup(soc_id, fdt);
|
||||
|
||||
sunxi_prepare_dtb(fdt);
|
||||
|
||||
INFO("BL31: Platform setup done\n");
|
||||
}
|
||||
|
||||
|
|
|
@ -6,13 +6,9 @@
|
|||
|
||||
#include <errno.h>
|
||||
|
||||
#include <platform_def.h>
|
||||
|
||||
#include <arch_helpers.h>
|
||||
#include <common/debug.h>
|
||||
#include <lib/mmio.h>
|
||||
#include <lib/xlat_tables/xlat_tables_v2.h>
|
||||
#include <plat/common/platform.h>
|
||||
|
||||
#include <sunxi_def.h>
|
||||
#include <sunxi_mmap.h>
|
||||
|
@ -21,16 +17,16 @@
|
|||
static const mmap_region_t sunxi_mmap[PLATFORM_MMAP_REGIONS + 1] = {
|
||||
MAP_REGION_FLAT(SUNXI_SRAM_BASE, SUNXI_SRAM_SIZE,
|
||||
MT_RW_DATA | MT_SECURE),
|
||||
#ifdef SUNXI_SCP_BASE
|
||||
MAP_REGION_FLAT(SUNXI_SCP_BASE, SUNXI_SCP_SIZE,
|
||||
MT_DEVICE | MT_RW | MT_SECURE | MT_EXECUTE_NEVER),
|
||||
#endif
|
||||
MAP_REGION_FLAT(SUNXI_DEV_BASE, SUNXI_DEV_SIZE,
|
||||
MT_DEVICE | MT_RW | MT_SECURE | MT_EXECUTE_NEVER),
|
||||
MAP_REGION(SUNXI_DRAM_BASE, SUNXI_DRAM_VIRT_BASE, SUNXI_DRAM_SEC_SIZE,
|
||||
MT_RW_DATA | MT_SECURE),
|
||||
MAP_REGION(PRELOADED_BL33_BASE,
|
||||
SUNXI_DRAM_VIRT_BASE + SUNXI_DRAM_SEC_SIZE,
|
||||
SUNXI_DRAM_MAP_SIZE,
|
||||
MT_RO_DATA | MT_NS),
|
||||
MAP_REGION(PRELOADED_BL33_BASE, SUNXI_BL33_VIRT_BASE,
|
||||
SUNXI_DRAM_MAP_SIZE, MT_RW_DATA | MT_NS),
|
||||
{},
|
||||
};
|
||||
|
||||
|
@ -116,6 +112,7 @@ int sunxi_init_platform_r_twi(uint16_t socid, bool use_rsb)
|
|||
device_bit = BIT(6);
|
||||
break;
|
||||
case SUNXI_SOC_H6:
|
||||
case SUNXI_SOC_H616:
|
||||
pin_func = use_rsb ? 0x22 : 0x33;
|
||||
device_bit = BIT(16);
|
||||
reset_offset = use_rsb ? 0x1bc : 0x19c;
|
||||
|
@ -130,7 +127,7 @@ int sunxi_init_platform_r_twi(uint16_t socid, bool use_rsb)
|
|||
}
|
||||
|
||||
/* un-gate R_PIO clock */
|
||||
if (socid != SUNXI_SOC_H6)
|
||||
if (socid != SUNXI_SOC_H6 && socid != SUNXI_SOC_H616)
|
||||
mmio_setbits_32(SUNXI_R_PRCM_BASE + 0x28, BIT(0));
|
||||
|
||||
/* switch pins PL0 and PL1 to the desired function */
|
||||
|
@ -143,7 +140,7 @@ int sunxi_init_platform_r_twi(uint16_t socid, bool use_rsb)
|
|||
mmio_clrsetbits_32(SUNXI_R_PIO_BASE + 0x1c, 0x0fU, 0x5U);
|
||||
|
||||
/* un-gate clock */
|
||||
if (socid != SUNXI_SOC_H6)
|
||||
if (socid != SUNXI_SOC_H6 && socid != SUNXI_SOC_H616)
|
||||
mmio_setbits_32(SUNXI_R_PRCM_BASE + 0x28, device_bit);
|
||||
else
|
||||
mmio_setbits_32(SUNXI_R_PRCM_BASE + reset_offset, BIT(0));
|
||||
|
@ -154,50 +151,3 @@ int sunxi_init_platform_r_twi(uint16_t socid, bool use_rsb)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This lock synchronises access to the arisc management processor. */
|
||||
DEFINE_BAKERY_LOCK(arisc_lock);
|
||||
|
||||
/*
|
||||
* Tell the "arisc" SCP core (an OpenRISC core) to execute some code.
|
||||
* We don't have any service running there, so we place some OpenRISC code
|
||||
* in SRAM, put the address of that into the reset vector and release the
|
||||
* arisc reset line. The SCP will execute that code and pull the line up again.
|
||||
*/
|
||||
void sunxi_execute_arisc_code(uint32_t *code, size_t size, uint16_t param)
|
||||
{
|
||||
uintptr_t arisc_reset_vec = SUNXI_SRAM_A2_BASE + 0x100;
|
||||
|
||||
do {
|
||||
bakery_lock_get(&arisc_lock);
|
||||
/* Wait until the arisc is in reset state. */
|
||||
if (!(mmio_read_32(SUNXI_R_CPUCFG_BASE) & BIT(0)))
|
||||
break;
|
||||
|
||||
bakery_lock_release(&arisc_lock);
|
||||
} while (1);
|
||||
|
||||
/* Patch up the code to feed in an input parameter. */
|
||||
code[0] = (code[0] & ~0xffff) | param;
|
||||
clean_dcache_range((uintptr_t)code, size);
|
||||
|
||||
/*
|
||||
* The OpenRISC unconditional branch has opcode 0, the branch offset
|
||||
* is in the lower 26 bits, containing the distance to the target,
|
||||
* in instruction granularity (32 bits).
|
||||
*/
|
||||
mmio_write_32(arisc_reset_vec, ((uintptr_t)code - arisc_reset_vec) / 4);
|
||||
clean_dcache_range(arisc_reset_vec, 4);
|
||||
|
||||
/* De-assert the arisc reset line to let it run. */
|
||||
mmio_setbits_32(SUNXI_R_CPUCFG_BASE, BIT(0));
|
||||
|
||||
/*
|
||||
* We release the lock here, although the arisc is still busy.
|
||||
* But as long as it runs, the reset line is high, so other users
|
||||
* won't leave the loop above.
|
||||
* Once it has finished, the code is supposed to clear the reset line,
|
||||
* to signal this to other users.
|
||||
*/
|
||||
bakery_lock_release(&arisc_lock);
|
||||
}
|
||||
|
|
|
@ -19,10 +19,6 @@
|
|||
#include <sunxi_mmap.h>
|
||||
#include <sunxi_private.h>
|
||||
|
||||
#ifndef SUNXI_CPUIDLE_EN_REG
|
||||
#include <core_off_arisc.h>
|
||||
#endif
|
||||
|
||||
static void sunxi_cpu_disable_power(unsigned int cluster, unsigned int core)
|
||||
{
|
||||
if (mmio_read_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core)) == 0xff)
|
||||
|
@ -67,32 +63,6 @@ static void sunxi_cpu_off(u_register_t mpidr)
|
|||
sunxi_cpu_disable_power(cluster, core);
|
||||
}
|
||||
|
||||
void sunxi_cpu_power_off_self(void)
|
||||
{
|
||||
u_register_t mpidr = read_mpidr();
|
||||
unsigned int core = MPIDR_AFFLVL0_VAL(mpidr);
|
||||
|
||||
/* Simplifies assembly, all SoCs so far are single cluster anyway. */
|
||||
assert(MPIDR_AFFLVL1_VAL(mpidr) == 0);
|
||||
|
||||
#ifdef SUNXI_CPUIDLE_EN_REG
|
||||
/* Enable the CPUIDLE hardware (only really needs to be done once). */
|
||||
mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0x16aa0000);
|
||||
mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0xaa160001);
|
||||
|
||||
/* Trigger power off for this core. */
|
||||
mmio_write_32(SUNXI_CORE_CLOSE_REG, BIT_32(core));
|
||||
#else
|
||||
/*
|
||||
* If we are supposed to turn ourself off, tell the arisc SCP
|
||||
* to do that work for us. The code expects the core mask to be
|
||||
* patched into the first instruction.
|
||||
*/
|
||||
sunxi_execute_arisc_code(arisc_core_off, sizeof(arisc_core_off),
|
||||
BIT_32(core));
|
||||
#endif
|
||||
}
|
||||
|
||||
void sunxi_cpu_on(u_register_t mpidr)
|
||||
{
|
||||
unsigned int cluster = MPIDR_AFFLVL1_VAL(mpidr);
|
||||
|
|
|
@ -12,3 +12,6 @@ BL31_SOURCES += drivers/allwinner/axp/axp803.c \
|
|||
|
||||
FDT_ASSUME_MASK := "(ASSUME_LATEST | ASSUME_NO_ROLLBACK | ASSUME_LIBFDT_ORDER)"
|
||||
$(eval $(call add_define,FDT_ASSUME_MASK))
|
||||
|
||||
# Put NOBITS memory in SRAM A1, overwriting U-Boot's SPL.
|
||||
SEPARATE_NOBITS_REGION := 1
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <drivers/allwinner/sunxi_rsb.h>
|
||||
#include <lib/mmio.h>
|
||||
|
||||
#include <core_off_arisc.h>
|
||||
#include <sunxi_def.h>
|
||||
#include <sunxi_mmap.h>
|
||||
#include <sunxi_private.h>
|
||||
|
@ -205,3 +206,55 @@ void sunxi_power_down(void)
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
/* This lock synchronises access to the arisc management processor. */
|
||||
static DEFINE_BAKERY_LOCK(arisc_lock);
|
||||
|
||||
/*
|
||||
* If we are supposed to turn ourself off, tell the arisc SCP to do that
|
||||
* work for us. Without any SCPI provider running there, we place some
|
||||
* OpenRISC code into SRAM, put the address of that into the reset vector
|
||||
* and release the arisc reset line. The SCP will wait for the core to enter
|
||||
* WFI, then execute that code and pull the line up again.
|
||||
* The code expects the core mask to be patched into the first instruction.
|
||||
*/
|
||||
void sunxi_cpu_power_off_self(void)
|
||||
{
|
||||
u_register_t mpidr = read_mpidr();
|
||||
unsigned int core = MPIDR_AFFLVL0_VAL(mpidr);
|
||||
uintptr_t arisc_reset_vec = SUNXI_SRAM_A2_BASE + 0x100;
|
||||
uint32_t *code = arisc_core_off;
|
||||
|
||||
do {
|
||||
bakery_lock_get(&arisc_lock);
|
||||
/* Wait until the arisc is in reset state. */
|
||||
if (!(mmio_read_32(SUNXI_R_CPUCFG_BASE) & BIT(0)))
|
||||
break;
|
||||
|
||||
bakery_lock_release(&arisc_lock);
|
||||
} while (1);
|
||||
|
||||
/* Patch up the code to feed in an input parameter. */
|
||||
code[0] = (code[0] & ~0xffff) | BIT_32(core);
|
||||
clean_dcache_range((uintptr_t)code, sizeof(arisc_core_off));
|
||||
|
||||
/*
|
||||
* The OpenRISC unconditional branch has opcode 0, the branch offset
|
||||
* is in the lower 26 bits, containing the distance to the target,
|
||||
* in instruction granularity (32 bits).
|
||||
*/
|
||||
mmio_write_32(arisc_reset_vec, ((uintptr_t)code - arisc_reset_vec) / 4);
|
||||
clean_dcache_range(arisc_reset_vec, 4);
|
||||
|
||||
/* De-assert the arisc reset line to let it run. */
|
||||
mmio_setbits_32(SUNXI_R_CPUCFG_BASE, BIT(0));
|
||||
|
||||
/*
|
||||
* We release the lock here, although the arisc is still busy.
|
||||
* But as long as it runs, the reset line is high, so other users
|
||||
* won't leave the loop above.
|
||||
* Once it has finished, the code is supposed to clear the reset line,
|
||||
* to signal this to other users.
|
||||
*/
|
||||
bakery_lock_release(&arisc_lock);
|
||||
}
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
static uint32_t arisc_core_off[] = {
|
||||
0x18600000, /* l.movhi r3, <corenr> */
|
||||
0x18000000, /* l.movhi r0, 0x0 */
|
||||
0x19a00901, /* l.movhi r13, 0x901 */
|
||||
0x84ad0080, /* l.lwz r5, 0x80(r13) */
|
||||
0xe0a51803, /* l.and r5, r5, r3 */
|
||||
0xe4050000, /* l.sfeq r5, r0 */
|
||||
0x13fffffd, /* l.bf -12 */
|
||||
0xb8c30050, /* l.srli r6, r3, 16 */
|
||||
|
||||
0xbc060001, /* l.sfeqi r6, 1 */
|
||||
0x10000005, /* l.bf +20 */
|
||||
0x19a00700, /* l.movhi r13, 0x700 */
|
||||
0x84ad0444, /* l.lwz r5, 0x0444(r13) */
|
||||
0xe0a53004, /* l.or r5, r5, r6 */
|
||||
0xd40d2c44, /* l.sw 0x0444(r13), r5 */
|
||||
|
||||
0x84ad0440, /* l.lwz r5, 0x0440(r13) */
|
||||
0xacc6ffff, /* l.xori r6, r6, -1 */
|
||||
0xe0a53003, /* l.and r5, r5, r6 */
|
||||
0xd40d2c40, /* l.sw 0x0440(r13), r5 */
|
||||
|
||||
0xe0c3000f, /* l.ff1 r6, r3 */
|
||||
0x9cc6ffef, /* l.addi r6, r6, -17 */
|
||||
0xb8c60002, /* l.slli r6, r6, 2 */
|
||||
0xe0c66800, /* l.add r6, r6, r13 */
|
||||
0xa8a000ff, /* l.ori r5, r0, 0xff */
|
||||
0xd4062c50, /* l.sw 0x0450(r6), r5 */
|
||||
|
||||
0xd40d0400, /* l.sw 0x0400(r13), r0 */
|
||||
0x03ffffff, /* l.j -1 */
|
||||
0x15000000, /* l.nop */
|
||||
};
|
|
@ -9,3 +9,6 @@ include plat/allwinner/common/allwinner-common.mk
|
|||
|
||||
BL31_SOURCES += drivers/allwinner/axp/axp805.c \
|
||||
drivers/allwinner/sunxi_rsb.c
|
||||
|
||||
# Put NOBITS memory in SRAM A1, overwriting U-Boot's SPL.
|
||||
SEPARATE_NOBITS_REGION := 1
|
||||
|
|
|
@ -10,7 +10,9 @@
|
|||
#include <common/debug.h>
|
||||
#include <drivers/allwinner/axp.h>
|
||||
#include <drivers/allwinner/sunxi_rsb.h>
|
||||
#include <lib/mmio.h>
|
||||
|
||||
#include <sunxi_cpucfg.h>
|
||||
#include <sunxi_def.h>
|
||||
#include <sunxi_mmap.h>
|
||||
#include <sunxi_private.h>
|
||||
|
@ -102,3 +104,16 @@ void sunxi_power_down(void)
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void sunxi_cpu_power_off_self(void)
|
||||
{
|
||||
u_register_t mpidr = read_mpidr();
|
||||
unsigned int core = MPIDR_AFFLVL0_VAL(mpidr);
|
||||
|
||||
/* Enable the CPUIDLE hardware (only really needs to be done once). */
|
||||
mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0x16aa0000);
|
||||
mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0xaa160001);
|
||||
|
||||
/* Trigger power off for this core. */
|
||||
mmio_write_32(SUNXI_CORE_CLOSE_REG, BIT_32(core));
|
||||
}
|
||||
|
|
14
plat/allwinner/sun50i_h616/include/sunxi_ccu.h
Normal file
14
plat/allwinner/sun50i_h616/include/sunxi_ccu.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef SUNXI_CCU_H
|
||||
#define SUNXI_CCU_H
|
||||
|
||||
#define SUNXI_CCU_SEC_SWITCH_REG (SUNXI_CCU_BASE + 0x0f00)
|
||||
|
||||
#define SUNXI_R_PRCM_SEC_SWITCH_REG (SUNXI_R_PRCM_BASE + 0x0290)
|
||||
|
||||
#endif /* SUNXI_CCU_H */
|
32
plat/allwinner/sun50i_h616/include/sunxi_cpucfg.h
Normal file
32
plat/allwinner/sun50i_h616/include/sunxi_cpucfg.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (c) 2017-2020, ARM Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef SUNXI_CPUCFG_H
|
||||
#define SUNXI_CPUCFG_H
|
||||
|
||||
#include <sunxi_mmap.h>
|
||||
|
||||
/* c = cluster, n = core */
|
||||
#define SUNXI_CPUCFG_CLS_CTRL_REG0(c) (SUNXI_CPUCFG_BASE + 0x0010 + (c) * 0x10)
|
||||
#define SUNXI_CPUCFG_CLS_CTRL_REG1(c) (SUNXI_CPUCFG_BASE + 0x0014 + (c) * 0x10)
|
||||
#define SUNXI_CPUCFG_CACHE_CFG_REG (SUNXI_CPUCFG_BASE + 0x0024)
|
||||
#define SUNXI_CPUCFG_DBG_REG0 (SUNXI_CPUCFG_BASE + 0x00c0)
|
||||
|
||||
#define SUNXI_CPUCFG_RST_CTRL_REG(c) (SUNXI_CPUCFG_BASE + 0x0000 + (c) * 4)
|
||||
#define SUNXI_CPUCFG_RVBAR_LO_REG(n) (SUNXI_CPUCFG_BASE + 0x0040 + (n) * 8)
|
||||
#define SUNXI_CPUCFG_RVBAR_HI_REG(n) (SUNXI_CPUCFG_BASE + 0x0044 + (n) * 8)
|
||||
|
||||
#define SUNXI_POWERON_RST_REG(c) (SUNXI_R_CPUCFG_BASE + 0x0040 + (c) * 4)
|
||||
#define SUNXI_POWEROFF_GATING_REG(c) (SUNXI_R_CPUCFG_BASE + 0x0044 + (c) * 4)
|
||||
#define SUNXI_CPU_POWER_CLAMP_REG(c, n) (SUNXI_R_CPUCFG_BASE + 0x0050 + \
|
||||
(c) * 0x10 + (n) * 4)
|
||||
|
||||
#define SUNXI_CPUIDLE_EN_REG (SUNXI_R_CPUCFG_BASE + 0x0100)
|
||||
#define SUNXI_CORE_CLOSE_REG (SUNXI_R_CPUCFG_BASE + 0x0104)
|
||||
#define SUNXI_PWR_SW_DELAY_REG (SUNXI_R_CPUCFG_BASE + 0x0140)
|
||||
#define SUNXI_CONFIG_DELAY_REG (SUNXI_R_CPUCFG_BASE + 0x0144)
|
||||
|
||||
#endif /* SUNXI_CPUCFG_H */
|
46
plat/allwinner/sun50i_h616/include/sunxi_mmap.h
Normal file
46
plat/allwinner/sun50i_h616/include/sunxi_mmap.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef SUNXI_MMAP_H
|
||||
#define SUNXI_MMAP_H
|
||||
|
||||
/* Memory regions */
|
||||
#define SUNXI_ROM_BASE 0x00000000
|
||||
#define SUNXI_ROM_SIZE 0x00010000
|
||||
#define SUNXI_SRAM_BASE 0x00020000
|
||||
#define SUNXI_SRAM_SIZE 0x00038000
|
||||
#define SUNXI_SRAM_A1_BASE 0x00020000
|
||||
#define SUNXI_SRAM_A1_SIZE 0x00008000
|
||||
#define SUNXI_SRAM_C_BASE 0x00028000
|
||||
#define SUNXI_SRAM_C_SIZE 0x00030000
|
||||
#define SUNXI_DEV_BASE 0x01000000
|
||||
#define SUNXI_DEV_SIZE 0x09000000
|
||||
#define SUNXI_DRAM_BASE 0x40000000
|
||||
#define SUNXI_DRAM_VIRT_BASE SUNXI_DRAM_BASE
|
||||
|
||||
/* Memory-mapped devices */
|
||||
#define SUNXI_SYSCON_BASE 0x03000000
|
||||
#define SUNXI_CCU_BASE 0x03001000
|
||||
#define SUNXI_DMA_BASE 0x03002000
|
||||
#define SUNXI_SID_BASE 0x03006000
|
||||
#define SUNXI_SPC_BASE 0x03008000
|
||||
#define SUNXI_WDOG_BASE 0x030090a0
|
||||
#define SUNXI_PIO_BASE 0x0300b000
|
||||
#define SUNXI_GICD_BASE 0x03021000
|
||||
#define SUNXI_GICC_BASE 0x03022000
|
||||
#define SUNXI_UART0_BASE 0x05000000
|
||||
#define SUNXI_SPI0_BASE 0x05010000
|
||||
#define SUNXI_R_CPUCFG_BASE 0x07000400
|
||||
#define SUNXI_R_PRCM_BASE 0x07010000
|
||||
//#define SUNXI_R_WDOG_BASE 0x07020400
|
||||
#define SUNXI_R_WDOG_BASE SUNXI_WDOG_BASE
|
||||
#define SUNXI_R_PIO_BASE 0x07022000
|
||||
#define SUNXI_R_UART_BASE 0x07080000
|
||||
#define SUNXI_R_I2C_BASE 0x07081400
|
||||
#define SUNXI_R_RSB_BASE 0x07083000
|
||||
#define SUNXI_CPUCFG_BASE 0x09010000
|
||||
|
||||
#endif /* SUNXI_MMAP_H */
|
16
plat/allwinner/sun50i_h616/include/sunxi_spc.h
Normal file
16
plat/allwinner/sun50i_h616/include/sunxi_spc.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef SUNXI_SPC_H
|
||||
#define SUNXI_SPC_H
|
||||
|
||||
#define SUNXI_SPC_NUM_PORTS 14
|
||||
|
||||
#define SUNXI_SPC_DECPORT_STA_REG(p) (SUNXI_SPC_BASE + 0x0000 + 0x10 * (p))
|
||||
#define SUNXI_SPC_DECPORT_SET_REG(p) (SUNXI_SPC_BASE + 0x0004 + 0x10 * (p))
|
||||
#define SUNXI_SPC_DECPORT_CLR_REG(p) (SUNXI_SPC_BASE + 0x0008 + 0x10 * (p))
|
||||
|
||||
#endif /* SUNXI_SPC_H */
|
24
plat/allwinner/sun50i_h616/platform.mk
Normal file
24
plat/allwinner/sun50i_h616/platform.mk
Normal file
|
@ -0,0 +1,24 @@
|
|||
#
|
||||
# Copyright (c) 2017-2020, ARM Limited. All rights reserved.
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
#
|
||||
|
||||
# Without a management processor there is no SCPI support.
|
||||
SUNXI_PSCI_USE_SCPI := 0
|
||||
SUNXI_PSCI_USE_NATIVE := 1
|
||||
|
||||
# The differences between the platforms are covered by the include files.
|
||||
include plat/allwinner/common/allwinner-common.mk
|
||||
|
||||
# the above could be overwritten on the command line
|
||||
ifeq (${SUNXI_PSCI_USE_SCPI}, 1)
|
||||
$(error "H616 does not support SCPI PSCI ops")
|
||||
endif
|
||||
|
||||
BL31_SOURCES += drivers/allwinner/axp/axp805.c \
|
||||
drivers/allwinner/sunxi_rsb.c \
|
||||
common/fdt_fixup.c \
|
||||
${AW_PLAT}/${PLAT}/prepare_dtb.c
|
||||
|
||||
$(eval $(call add_define,SUNXI_BL31_IN_DRAM))
|
43
plat/allwinner/sun50i_h616/prepare_dtb.c
Normal file
43
plat/allwinner/sun50i_h616/prepare_dtb.c
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (c) 2021, ARM Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <libfdt.h>
|
||||
|
||||
#include <common/debug.h>
|
||||
#include <common/fdt_fixup.h>
|
||||
#include <common/fdt_wrappers.h>
|
||||
|
||||
#include <sunxi_private.h>
|
||||
|
||||
void sunxi_prepare_dtb(void *fdt)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (fdt == NULL || fdt_check_header(fdt) != 0) {
|
||||
return;
|
||||
}
|
||||
ret = fdt_open_into(fdt, fdt, 0x100000);
|
||||
if (ret < 0) {
|
||||
ERROR("Preparing devicetree at %p: error %d\n", fdt, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Reserve memory used by Trusted Firmware. */
|
||||
if (fdt_add_reserved_memory(fdt, "tf-a@40000000", BL31_BASE,
|
||||
BL31_LIMIT - BL31_BASE)) {
|
||||
WARN("Failed to add reserved memory nodes to DT.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = fdt_pack(fdt);
|
||||
if (ret < 0) {
|
||||
ERROR("Failed to pack devicetree at %p: error %d\n",
|
||||
fdt, ret);
|
||||
} else {
|
||||
clean_dcache_range((uintptr_t)fdt, fdt_blob_size(fdt));
|
||||
INFO("Changed devicetree to reserve BL31 memory.\n");
|
||||
}
|
||||
}
|
121
plat/allwinner/sun50i_h616/sunxi_power.c
Normal file
121
plat/allwinner/sun50i_h616/sunxi_power.c
Normal file
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* Copyright (c) 2017-2020, ARM Limited. All rights reserved.
|
||||
* Copyright (c) 2018, Icenowy Zheng <icenowy@aosc.io>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <arch_helpers.h>
|
||||
#include <common/debug.h>
|
||||
#include <drivers/allwinner/axp.h>
|
||||
#include <drivers/allwinner/sunxi_rsb.h>
|
||||
#include <lib/mmio.h>
|
||||
|
||||
#include <sunxi_cpucfg.h>
|
||||
#include <sunxi_def.h>
|
||||
#include <sunxi_mmap.h>
|
||||
#include <sunxi_private.h>
|
||||
|
||||
#define AXP305_I2C_ADDR 0x36
|
||||
#define AXP305_HW_ADDR 0x745
|
||||
#define AXP305_RT_ADDR 0x3a
|
||||
|
||||
static enum pmic_type {
|
||||
UNKNOWN,
|
||||
AXP305,
|
||||
} pmic;
|
||||
|
||||
int axp_read(uint8_t reg)
|
||||
{
|
||||
return rsb_read(AXP305_RT_ADDR, reg);
|
||||
}
|
||||
|
||||
int axp_write(uint8_t reg, uint8_t val)
|
||||
{
|
||||
return rsb_write(AXP305_RT_ADDR, reg, val);
|
||||
}
|
||||
|
||||
static int rsb_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = rsb_init_controller();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Switch to the recommended 3 MHz bus clock. */
|
||||
ret = rsb_set_bus_speed(SUNXI_OSC24M_CLK_IN_HZ, 3000000);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Initiate an I2C transaction to switch the PMIC to RSB mode. */
|
||||
ret = rsb_set_device_mode(AXP20X_MODE_RSB << 16 | AXP20X_MODE_REG << 8);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Associate the 8-bit runtime address with the 12-bit bus address. */
|
||||
ret = rsb_assign_runtime_address(AXP305_HW_ADDR, AXP305_RT_ADDR);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return axp_check_id();
|
||||
}
|
||||
|
||||
int sunxi_pmic_setup(uint16_t socid, const void *fdt)
|
||||
{
|
||||
int ret;
|
||||
|
||||
INFO("PMIC: Probing AXP305 on RSB\n");
|
||||
|
||||
ret = sunxi_init_platform_r_twi(socid, true);
|
||||
if (ret) {
|
||||
INFO("Could not init platform bus: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = rsb_init();
|
||||
if (ret) {
|
||||
INFO("Could not init RSB: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pmic = AXP305;
|
||||
axp_setup_regulators(fdt);
|
||||
|
||||
/* Switch the PMIC back to I2C mode. */
|
||||
ret = axp_write(AXP20X_MODE_REG, AXP20X_MODE_I2C);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sunxi_power_down(void)
|
||||
{
|
||||
switch (pmic) {
|
||||
case AXP305:
|
||||
/* Re-initialise after rich OS might have used it. */
|
||||
sunxi_init_platform_r_twi(SUNXI_SOC_H616, true);
|
||||
rsb_init();
|
||||
axp_power_off();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void sunxi_cpu_power_off_self(void)
|
||||
{
|
||||
u_register_t mpidr = read_mpidr();
|
||||
unsigned int core = MPIDR_AFFLVL0_VAL(mpidr);
|
||||
|
||||
/* Enable the CPUIDLE hardware (only really needs to be done once). */
|
||||
mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0x16aa0000);
|
||||
mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0xaa160001);
|
||||
|
||||
/* Trigger power off for this core. */
|
||||
mmio_write_32(SUNXI_CORE_CLOSE_REG, BIT_32(core));
|
||||
}
|
Loading…
Add table
Reference in a new issue