Commit 8078b5c5 authored by André Przywara's avatar André Przywara Committed by TrustedFirmware Code Review
Browse files

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
parents e5fa7459 0be10ee3
......@@ -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);
}
/*
* 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));
}
/*
* 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 */
/*
* 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 */
/*
* 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 */
/*
* 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 */
#
# 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))
/*
* 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");
}
}
/*
* 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));
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment