GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)

This commit is contained in:
lai
2026-09-06 03:52:57 +08:00
commit b1928b41c0
21813 changed files with 4413081 additions and 0 deletions
@@ -0,0 +1,114 @@
#
# Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
include lib/xlat_tables_v2/xlat_tables.mk
include lib/libfdt/libfdt.mk
include drivers/arm/gic/v2/gicv2.mk
AW_PLAT := plat/allwinner
PLAT_INCLUDES := -Iinclude/plat/arm/common/aarch64 \
-I${AW_PLAT}/common/include \
-I${AW_PLAT}/${PLAT}/include
PLAT_BL_COMMON_SOURCES := drivers/ti/uart/${ARCH}/16550_console.S \
${XLAT_TABLES_LIB_SRCS} \
${AW_PLAT}/common/plat_helpers.S \
${AW_PLAT}/common/sunxi_common.c
BL31_SOURCES += drivers/allwinner/axp/common.c \
${GICV2_SOURCES} \
drivers/delay_timer/delay_timer.c \
drivers/delay_timer/generic_delay_timer.c \
lib/cpus/${ARCH}/cortex_a53.S \
plat/common/plat_gicv2.c \
plat/common/plat_psci_common.c \
${AW_PLAT}/common/sunxi_bl31_setup.c \
${AW_PLAT}/${PLAT}/sunxi_idle_states.c \
${AW_PLAT}/common/sunxi_pm.c \
${AW_PLAT}/${PLAT}/sunxi_power.c \
${AW_PLAT}/common/sunxi_security.c \
${AW_PLAT}/common/sunxi_topology.c
# By default, attempt to use SCPI to the ARISC management processor. If SCPI
# is not enabled or SCP firmware is not loaded, fall back to a simpler native
# implementation that does not support CPU or system suspend.
#
# If SCP firmware will always be present (or absent), the unused implementation
# can be compiled out.
SUNXI_PSCI_USE_NATIVE ?= 1
SUNXI_PSCI_USE_SCPI ?= 1
$(eval $(call assert_boolean,SUNXI_PSCI_USE_NATIVE))
$(eval $(call assert_boolean,SUNXI_PSCI_USE_SCPI))
$(eval $(call add_define,SUNXI_PSCI_USE_NATIVE))
$(eval $(call add_define,SUNXI_PSCI_USE_SCPI))
ifeq (${SUNXI_PSCI_USE_NATIVE}${SUNXI_PSCI_USE_SCPI},00)
$(error "At least one of SCPI or native PSCI ops must be enabled")
endif
ifeq (${SUNXI_PSCI_USE_NATIVE},1)
BL31_SOURCES += ${AW_PLAT}/common/sunxi_cpu_ops.c \
${AW_PLAT}/common/sunxi_native_pm.c
endif
ifeq (${SUNXI_PSCI_USE_SCPI},1)
BL31_SOURCES += drivers/allwinner/sunxi_msgbox.c \
drivers/arm/css/scpi/css_scpi.c \
${AW_PLAT}/common/sunxi_scpi_pm.c
endif
SUNXI_SETUP_REGULATORS ?= 1
$(eval $(call assert_boolean,SUNXI_SETUP_REGULATORS))
$(eval $(call add_define,SUNXI_SETUP_REGULATORS))
SUNXI_BL31_IN_DRAM ?= 0
$(eval $(call assert_boolean,SUNXI_BL31_IN_DRAM))
ifeq (${SUNXI_BL31_IN_DRAM},1)
SUNXI_AMEND_DTB := 1
$(eval $(call add_define,SUNXI_BL31_IN_DRAM))
endif
SUNXI_AMEND_DTB ?= 0
$(eval $(call assert_boolean,SUNXI_AMEND_DTB))
$(eval $(call add_define,SUNXI_AMEND_DTB))
ifeq (${SUNXI_AMEND_DTB},1)
BL31_SOURCES += common/fdt_fixup.c \
${AW_PLAT}/common/sunxi_prepare_dtb.c
endif
# The bootloader is guaranteed to only run on CPU 0 by the boot ROM.
COLD_BOOT_SINGLE_CPU := 1
# Do not enable SPE (not supported on ARM v8.0).
ENABLE_SPE_FOR_LOWER_ELS := 0
# Do not enable SVE (not supported on ARM v8.0).
ENABLE_SVE_FOR_NS := 0
# Enable workarounds for Cortex-A53 errata. Allwinner uses at least r0p4.
ERRATA_A53_835769 := 1
ERRATA_A53_843419 := 1
ERRATA_A53_855873 := 1
ERRATA_A53_1530924 := 1
# The traditional U-Boot load address is 160MB into DRAM.
PRELOADED_BL33_BASE ?= 0x4a000000
# The reset vector can be changed for each CPU.
PROGRAMMABLE_RESET_ADDRESS := 1
# Allow mapping read-only data as execute-never.
SEPARATE_CODE_AND_RODATA := 1
# BL31 gets loaded alongside BL33 (U-Boot) by U-Boot's SPL
RESET_TO_BL31 := 1
# This platform is single-cluster and does not require coherency setup.
WARMBOOT_ENABLE_DCACHE_EARLY := 1
@@ -0,0 +1,115 @@
# turn_off_core.S
#
# Copyright (c) 2018, Andre Przywara <osp@andrep.de>
# SPDX-License-Identifier: BSD-3-Clause
#
# OpenRISC assembly to turn off an ARM core on an Allwinner SoC from
# the arisc management controller.
# Generate a binary representation with:
# $ or1k-elf-as -c -o turn_off_core.o turn_off_core.S
# $ or1k-elf-objcopy -O binary --reverse-bytes=4 turn_off_core.o \
# turn_off_core.bin
# The encoded instructions go into an array defined in
# plat/allwinner/sun50i_*/include/core_off_arisc.h, to be handed off to
# the arisc processor.
#
# This routine is meant to be called directly from arisc reset (put the
# start address in the reset vector), to be actually triggered by that
# very ARM core to be turned off.
# It expects the core number presented as a mask in the upper half of
# r3, so to be patched in the lower 16 bits of the first instruction,
# overwriting the 0 in this code here.
# The code will do the following:
# - Read the C_CPU_STATUS register, which contains the status of the WFI
# lines of each of the four A53 cores.
# - Loop until the core in question reaches WFI.
# - Using that mask, activate the core output clamps by setting the
# respective core bit in CPUX_PWROFF_GATING_REG (0x1f01500).
# Note that the clamp for core 0 covers more than just the core, activating
# it hangs the whole system. So we skip this step for core 0.
# - Using the negated mask, assert the core's reset line by clearing the
# respective bit in C_RST_CTRL (0x1f01c30).
# - Finally turn off the core's power switch by writing 0xff to the
# respective CPUx_PWR_SWITCH_REG (0x1f01540 ff.)
# - Assert the arisc's own reset to end execution.
# This also signals other arisc users that the chip is free again.
# So in C this would look like:
# while (!(readl(0x1700030) & (1U << core_nr)))
# ;
# if (core_nr != 0)
# writel(readl(0x1f01500) | (1U << core_nr), 0x1f01500);
# writel(readl(0x1f01c30) & ~(1U << core_nr), 0x1f01c30);
# writel(0xff, 0x1f01540 + (core_nr * 4));
# (using A64/H5 addresses)
.text
_start:
l.movhi r3, 0 # FIXUP! with core mask
l.movhi r0, 0 # clear r0
l.movhi r13, 0x170 # r13: CPU_CFG_BASE=0x01700000
wait_wfi:
l.lwz r5, 0x30(r13) # load C_CPU_STATUS
l.and r5, r5, r3 # mask requested core
l.sfeq r5, r0 # is it not yet in WFI?
l.bf wait_wfi # try again
l.srli r6, r3, 16 # move mask to lower 16 bits
l.sfeqi r6, 1 # core 0 is special
l.bf 1f # don't touch the bit for core 0
l.movhi r13, 0x1f0 # address of R_CPUCFG (delay)
l.lwz r5, 0x1500(r13) # core output clamps
l.or r5, r5, r6 # set bit to ...
l.sw 0x1500(r13), r5 # ... activate for our core
1: l.lwz r5, 0x1c30(r13) # CPU power-on reset
l.xori r6, r6, -1 # negate core mask
l.and r5, r5, r6 # clear bit to ...
l.sw 0x1c30(r13), r5 # ... assert for our core
l.ff1 r6, r3 # get core number from high mask
l.addi r6, r6, -17 # convert to 0-3
l.slli r6, r6, 2 # r5: core number*4 (0-12)
l.add r6, r6, r13 # add to base address
l.ori r5, r0, 0xff # 0xff means all switches off
l.sw 0x1540(r6), r5 # core power switch registers
reset: l.sw 0x1c00(r13),r0 # pull down our own reset line
l.j reset # just in case ....
l.nop 0x0 # (delay slot)
# same as above, but with the MMIO addresses matching the H6 SoC
_start_h6:
l.movhi r3, 0 # FIXUP! with core mask
l.movhi r0, 0 # clear r0
l.movhi r13, 0x901 # r13: CPU_CFG_BASE=0x09010000
1:
l.lwz r5, 0x80(r13) # load C_CPU_STATUS
l.and r5, r5, r3 # mask requested core
l.sfeq r5, r0 # is it not yet in WFI?
l.bf 1b # try again
l.srli r6, r3, 16 # move mask to lower 16 bits(ds)
l.sfeqi r6, 1 # core 0 is special
l.bf 1f # don't touch the bit for core 0
l.movhi r13, 0x700 # address of R_CPUCFG (ds)
l.lwz r5, 0x0444(r13) # core output clamps
l.or r5, r5, r6 # set bit to ...
l.sw 0x0444(r13), r5 # ... activate for our core
1: l.lwz r5, 0x0440(r13) # CPU power-on reset
l.xori r6, r6, -1 # negate core mask
l.and r5, r5, r6 # clear bit to ...
l.sw 0x0440(r13), r5 # ... assert for our core
l.ff1 r6, r3 # get core number from high mask
l.addi r6, r6, -17 # convert to 0-3
l.slli r6, r6, 2 # r5: core number*4 (0-12)
l.add r6, r6, r13 # add to base address
l.ori r5, r0, 0xff # 0xff means all switches off
l.sw 0x0450(r6), r5 # core power switch registers
1: l.sw 0x0400(r13),r0 # pull down our own reset line
l.j 1b # just in case ...
l.nop 0x0 # (delay slot)
@@ -0,0 +1,28 @@
/*
* Copyright (C) 2018 Icenowy Zheng <icenowy@aosc.io>
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
/* This driver provides I2C support for Allwinner sunXi SoCs */
#ifndef MENTOR_I2C_PLAT_H
#define MENTOR_I2C_PLAT_H
#define CONFIG_SYS_TCLK 24000000
#define CONFIG_SYS_I2C_SPEED 100000
#define CONFIG_SYS_I2C_SLAVE 0
#define I2C_INTERRUPT_CLEAR_INVERTED
struct mentor_i2c_regs {
uint32_t slave_address;
uint32_t xtnd_slave_addr;
uint32_t data;
uint32_t control;
uint32_t status;
uint32_t baudrate;
uint32_t soft_reset;
};
#endif /* MENTOR_I2C_PLAT_H */
@@ -0,0 +1,27 @@
/*
* Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef PLAT_MACROS_S
#define PLAT_MACROS_S
#include <arm_macros.S>
#include <sunxi_mmap.h>
/* ---------------------------------------------
* The below required platform porting macro
* prints out relevant GIC and CCI registers
* whenever an unhandled exception is taken in
* BL31.
* Clobbers: x0 - x10, x16, x17, sp
* ---------------------------------------------
*/
.macro plat_crash_print_regs
mov_imm x17, SUNXI_GICC_BASE
mov_imm x16, SUNXI_GICD_BASE
arm_print_gic_regs
.endm
#endif /* PLAT_MACROS_S */
@@ -0,0 +1,84 @@
/*
* Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef PLATFORM_DEF_H
#define PLATFORM_DEF_H
#include <common/tbbr/tbbr_img_def.h>
#include <lib/utils_def.h>
#include <plat/common/common_def.h>
#include <sunxi_mmap.h>
#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 + \
SUNXI_SRAM_A2_BL31_OFFSET)
#define BL31_LIMIT (SUNXI_SRAM_A2_BASE + \
SUNXI_SRAM_A2_SIZE - SUNXI_SCP_SIZE)
/* 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
/* The SCP firmware is allocated the last 16KiB of SRAM A2. */
#define SUNXI_SCP_BASE BL31_LIMIT
#define SUNXI_SCP_SIZE 0x4000
#endif /* SUNXI_BL31_IN_DRAM */
/* How much DRAM to map (to map BL33, for fetching the DTB from U-Boot) */
#define SUNXI_DRAM_MAP_SIZE (64U << 20)
#define CACHE_WRITEBACK_SHIFT 6
#define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT)
#define MAX_STATIC_MMAP_REGIONS 3
#define MAX_MMAP_REGIONS (5 + MAX_STATIC_MMAP_REGIONS)
#define PLAT_CSS_SCP_COM_SHARED_MEM_BASE \
(SUNXI_SRAM_A2_BASE + SUNXI_SRAM_A2_SIZE - 0x200)
/* These states are used directly for SCPI communication. */
#define PLAT_MAX_PWR_LVL_STATES U(3)
#define PLAT_MAX_RET_STATE U(1)
#define PLAT_MAX_OFF_STATE U(3)
#define PLAT_MAX_PWR_LVL U(2)
#define PLAT_NUM_PWR_DOMAINS (U(1) + \
PLATFORM_CLUSTER_COUNT + \
PLATFORM_CORE_COUNT)
#define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32)
#define PLATFORM_CLUSTER_COUNT U(1)
#define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER_COUNT * \
PLATFORM_MAX_CPUS_PER_CLUSTER)
#define PLATFORM_MAX_CPUS_PER_CLUSTER U(4)
#define PLATFORM_STACK_SIZE (0x1000 / PLATFORM_CORE_COUNT)
#ifndef SPD_none
#ifndef BL32_BASE
#define BL32_BASE SUNXI_DRAM_BASE
#endif
#endif
#endif /* PLATFORM_DEF_H */
@@ -0,0 +1,26 @@
/*
* Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef SUNXI_DEF_H
#define SUNXI_DEF_H
/* Clock configuration */
#define SUNXI_OSC24M_CLK_IN_HZ 24000000
/* UART configuration */
#define SUNXI_UART0_BAUDRATE 115200
#define SUNXI_UART0_CLK_IN_HZ SUNXI_OSC24M_CLK_IN_HZ
#define SUNXI_SOC_A64 0x1689
#define SUNXI_SOC_H5 0x1718
#define SUNXI_SOC_H6 0x1728
#define SUNXI_SOC_H616 0x1823
#define SUNXI_SOC_R329 0x1851
#define JEDEC_ALLWINNER_BKID 9U
#define JEDEC_ALLWINNER_MFID 0x9eU
#endif /* SUNXI_DEF_H */
@@ -0,0 +1,61 @@
/*
* Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef SUNXI_PRIVATE_H
#define SUNXI_PRIVATE_H
#include <common/fdt_fixup.h>
#include <lib/psci/psci.h>
extern const struct psci_cpu_idle_state sunxi_idle_states[];
void sunxi_configure_mmu_el3(int flags);
void sunxi_cpu_on(u_register_t mpidr);
void sunxi_cpu_power_off_others(void);
void sunxi_cpu_power_off_self(void);
void sunxi_power_down(void);
#if SUNXI_PSCI_USE_NATIVE
void sunxi_set_native_psci_ops(const plat_psci_ops_t **psci_ops);
#else
static inline void sunxi_set_native_psci_ops(const plat_psci_ops_t **psci_ops)
{
}
#endif
#if SUNXI_PSCI_USE_SCPI
bool sunxi_psci_is_scpi(void);
int sunxi_set_scpi_psci_ops(const plat_psci_ops_t **psci_ops);
#else
static inline bool sunxi_psci_is_scpi(void)
{
return false;
}
static inline int sunxi_set_scpi_psci_ops(const plat_psci_ops_t **psci_ops)
{
return -1;
}
#endif
int sunxi_validate_ns_entrypoint(uintptr_t ns_entrypoint);
int sunxi_pmic_setup(uint16_t socid, const void *fdt);
void sunxi_security_setup(void);
uint16_t sunxi_read_soc_id(void);
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);
#if SUNXI_AMEND_DTB
void sunxi_prepare_dtb(void *fdt);
#else
static inline void sunxi_prepare_dtb(void *fdt)
{
}
#endif
#endif /* SUNXI_PRIVATE_H */
@@ -0,0 +1,49 @@
/*
* Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <asm_macros.S>
#include <sunxi_def.h>
#include <sunxi_mmap.h>
.globl plat_crash_console_init
.globl plat_crash_console_putc
.globl plat_crash_console_flush
.globl plat_my_core_pos
.globl platform_mem_init
.globl plat_report_exception
func plat_crash_console_init
mov_imm x0, SUNXI_UART0_BASE
mov_imm x1, SUNXI_UART0_CLK_IN_HZ
mov_imm x2, SUNXI_UART0_BAUDRATE
b console_16550_core_init
endfunc plat_crash_console_init
func plat_crash_console_putc
mov_imm x1, SUNXI_UART0_BASE
b console_16550_core_putc
endfunc plat_crash_console_putc
func plat_crash_console_flush
ret
endfunc plat_crash_console_flush
func plat_my_core_pos
mrs x0, mpidr_el1
and x1, x0, #MPIDR_CLUSTER_MASK
and x0, x0, #MPIDR_CPU_MASK
add x0, x0, x1, LSR #6
ret
endfunc plat_my_core_pos
func platform_mem_init
ret
endfunc platform_mem_init
func plat_report_exception
ret
endfunc plat_report_exception
@@ -0,0 +1,204 @@
/*
* Copyright (c) 2017-2022, 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.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>
#include <drivers/ti/uart/uart_16550.h>
#include <lib/mmio.h>
#include <plat/common/platform.h>
#include <sunxi_def.h>
#include <sunxi_mmap.h>
#include <sunxi_private.h>
static entry_point_info_t bl32_image_ep_info;
static entry_point_info_t bl33_image_ep_info;
static console_t console;
static void *fdt;
static const gicv2_driver_data_t sunxi_gic_data = {
.gicd_base = SUNXI_GICD_BASE,
.gicc_base = SUNXI_GICC_BASE,
};
/*
* Try to find a DTB loaded in memory by previous stages.
*
* At the moment we implement a heuristic to find the DTB attached to U-Boot:
* U-Boot appends its DTB to the end of the image. Assuming that BL33 is
* U-Boot, try to find the size of the U-Boot image to learn the DTB address.
* The generic ARMv8 U-Boot image contains the load address and its size
* as u64 variables at the beginning of the image. There might be padding
* or other headers before that data, so scan the first 2KB after the BL33
* entry point to find the load address, which should be followed by the
* size. Adding those together gives us the address of the DTB.
*/
static void sunxi_find_dtb(void)
{
uint64_t *u_boot_base;
int i;
u_boot_base = (void *)SUNXI_BL33_VIRT_BASE;
for (i = 0; i < 2048 / sizeof(uint64_t); i++) {
void *dtb_base;
if (u_boot_base[i] != PRELOADED_BL33_BASE)
continue;
/* Does the suspected U-Boot size look anyhow reasonable? */
if (u_boot_base[i + 1] >= 256 * 1024 * 1024)
continue;
/* end of the image: base address + size */
dtb_base = (char *)u_boot_base + u_boot_base[i + 1];
if (fdt_check_header(dtb_base) == 0) {
fdt = dtb_base;
return;
}
}
}
void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
u_register_t arg2, u_register_t arg3)
{
/* Initialize the debug console as soon as possible */
console_16550_register(SUNXI_UART0_BASE, SUNXI_UART0_CLK_IN_HZ,
SUNXI_UART0_BAUDRATE, &console);
#ifdef BL32_BASE
/* Populate entry point information for BL32 */
SET_PARAM_HEAD(&bl32_image_ep_info, PARAM_EP, VERSION_1, 0);
SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE);
bl32_image_ep_info.pc = BL32_BASE;
#endif
/* Populate entry point information for BL33 */
SET_PARAM_HEAD(&bl33_image_ep_info, PARAM_EP, VERSION_1, 0);
/*
* Tell BL31 where the non-trusted software image
* is located and the entry state information
*/
bl33_image_ep_info.pc = PRELOADED_BL33_BASE;
bl33_image_ep_info.spsr = SPSR_64(MODE_EL2, MODE_SP_ELX,
DISABLE_ALL_EXCEPTIONS);
SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
}
void bl31_plat_arch_setup(void)
{
sunxi_configure_mmu_el3(0);
}
void bl31_platform_setup(void)
{
const char *soc_name;
uint16_t soc_id = sunxi_read_soc_id();
switch (soc_id) {
case SUNXI_SOC_A64:
soc_name = "A64/H64/R18";
break;
case SUNXI_SOC_H5:
soc_name = "H5";
break;
case SUNXI_SOC_H6:
soc_name = "H6";
break;
case SUNXI_SOC_H616:
soc_name = "H616";
break;
case SUNXI_SOC_R329:
soc_name = "R329";
break;
default:
soc_name = "unknown";
break;
}
NOTICE("BL31: Detected Allwinner %s SoC (%04x)\n", soc_name, soc_id);
generic_delay_timer_init();
sunxi_find_dtb();
if (fdt) {
const char *model;
int length;
model = fdt_getprop(fdt, 0, "model", &length);
NOTICE("BL31: Found U-Boot DTB at %p, model: %s\n", fdt,
model ?: "unknown");
} else {
NOTICE("BL31: No DTB found.\n");
}
/* Configure the interrupt controller */
gicv2_driver_init(&sunxi_gic_data);
gicv2_distif_init();
gicv2_pcpu_distif_init();
gicv2_cpuif_enable();
sunxi_security_setup();
/*
* On the A64 U-Boot's SPL sets the bus clocks to some conservative
* values, to work around FEL mode instabilities with SRAM C accesses.
* FEL mode is gone when we reach ATF, so bring the AHB1 bus
* (the "main" bus) clock frequency back to the recommended 200MHz,
* for improved performance.
*/
if (soc_id == SUNXI_SOC_A64)
mmio_write_32(SUNXI_CCU_BASE + 0x54, 0x00003180);
/*
* U-Boot or the kernel don't setup AHB2, which leaves it at the
* AHB1 frequency (200 MHz, see above). However Allwinner recommends
* 300 MHz, for improved Ethernet and USB performance. Switch the
* clock to use "PLL_PERIPH0 / 2".
*/
if (soc_id == SUNXI_SOC_A64 || soc_id == SUNXI_SOC_H5)
mmio_write_32(SUNXI_CCU_BASE + 0x5c, 0x1);
sunxi_pmic_setup(soc_id, fdt);
INFO("BL31: Platform setup done\n");
}
void bl31_plat_runtime_setup(void)
{
/* Change the DTB if the configuration requires so. */
sunxi_prepare_dtb(fdt);
console_switch_state(CONSOLE_FLAG_RUNTIME);
}
entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
{
assert(sec_state_is_valid(type) != 0);
if (type == NON_SECURE)
return &bl33_image_ep_info;
if ((type == SECURE) && bl32_image_ep_info.pc)
return &bl32_image_ep_info;
return NULL;
}
@@ -0,0 +1,187 @@
/*
* Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <errno.h>
#include <common/debug.h>
#include <lib/mmio.h>
#include <lib/smccc.h>
#include <lib/xlat_tables/xlat_tables_v2.h>
#include <services/arm_arch_svc.h>
#include <sunxi_def.h>
#include <sunxi_mmap.h>
#include <sunxi_private.h>
static const mmap_region_t sunxi_mmap[MAX_STATIC_MMAP_REGIONS + 1] = {
MAP_REGION_FLAT(SUNXI_SRAM_BASE, SUNXI_SRAM_SIZE,
MT_DEVICE | MT_RW | MT_SECURE | MT_EXECUTE_NEVER),
MAP_REGION_FLAT(SUNXI_DEV_BASE, SUNXI_DEV_SIZE,
MT_DEVICE | MT_RW | MT_SECURE | MT_EXECUTE_NEVER),
MAP_REGION(PRELOADED_BL33_BASE, SUNXI_BL33_VIRT_BASE,
SUNXI_DRAM_MAP_SIZE, MT_RW_DATA | MT_NS),
{},
};
unsigned int plat_get_syscnt_freq2(void)
{
return SUNXI_OSC24M_CLK_IN_HZ;
}
void sunxi_configure_mmu_el3(int flags)
{
mmap_add_region(BL_CODE_BASE, BL_CODE_BASE,
BL_CODE_END - BL_CODE_BASE,
MT_CODE | MT_SECURE);
mmap_add_region(BL_CODE_END, BL_CODE_END,
BL_END - BL_CODE_END,
MT_RW_DATA | MT_SECURE);
#if SEPARATE_CODE_AND_RODATA
mmap_add_region(BL_RO_DATA_BASE, BL_RO_DATA_BASE,
BL_RO_DATA_END - BL_RO_DATA_BASE,
MT_RO_DATA | MT_SECURE);
#endif
#if SEPARATE_NOBITS_REGION
mmap_add_region(BL_NOBITS_BASE, BL_NOBITS_BASE,
BL_NOBITS_END - BL_NOBITS_BASE,
MT_RW_DATA | MT_SECURE);
#endif
#if USE_COHERENT_MEM
mmap_add_region(BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_BASE,
BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE,
MT_DEVICE | MT_RW | MT_SECURE | MT_EXECUTE_NEVER);
#endif
mmap_add(sunxi_mmap);
init_xlat_tables();
enable_mmu_el3(0);
}
#define SRAM_VER_REG (SUNXI_SYSCON_BASE + 0x24)
uint16_t sunxi_read_soc_id(void)
{
uint32_t reg = mmio_read_32(SRAM_VER_REG);
/* Set bit 15 to prepare for the SOCID read. */
mmio_write_32(SRAM_VER_REG, reg | BIT(15));
reg = mmio_read_32(SRAM_VER_REG);
/* deactivate the SOCID access again */
mmio_write_32(SRAM_VER_REG, reg & ~BIT(15));
return reg >> 16;
}
/*
* Configure a given pin to the GPIO-OUT function and sets its level.
* The port is given as a capital letter, the pin is the number within
* this port group.
* So to set pin PC7 to high, use: sunxi_set_gpio_out('C', 7, true);
*/
void sunxi_set_gpio_out(char port, int pin, bool level_high)
{
uintptr_t port_base;
if (port < 'A' || port > 'L')
return;
if (port == 'L')
port_base = SUNXI_R_PIO_BASE;
else
port_base = SUNXI_PIO_BASE + (port - 'A') * 0x24;
/* Set the new level first before configuring the pin. */
if (level_high)
mmio_setbits_32(port_base + 0x10, BIT(pin));
else
mmio_clrbits_32(port_base + 0x10, BIT(pin));
/* configure pin as GPIO out (4(3) bits per pin, 1: GPIO out */
mmio_clrsetbits_32(port_base + (pin / 8) * 4,
0x7 << ((pin % 8) * 4),
0x1 << ((pin % 8) * 4));
}
int sunxi_init_platform_r_twi(uint16_t socid, bool use_rsb)
{
uint32_t pin_func = 0x77;
uint32_t device_bit;
unsigned int reset_offset = 0xb0;
switch (socid) {
case SUNXI_SOC_H5:
if (use_rsb)
return -ENODEV;
pin_func = 0x22;
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;
break;
case SUNXI_SOC_A64:
pin_func = use_rsb ? 0x22 : 0x33;
device_bit = use_rsb ? BIT(3) : BIT(6);
break;
default:
INFO("R_I2C/RSB on Allwinner 0x%x SoC not supported\n", socid);
return -ENODEV;
}
/* un-gate R_PIO clock */
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 */
mmio_clrsetbits_32(SUNXI_R_PIO_BASE + 0x00, 0xffU, pin_func);
/* level 2 drive strength */
mmio_clrsetbits_32(SUNXI_R_PIO_BASE + 0x14, 0x0fU, 0xaU);
/* set both pins to pull-up */
mmio_clrsetbits_32(SUNXI_R_PIO_BASE + 0x1c, 0x0fU, 0x5U);
/* un-gate clock */
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));
/* assert, then de-assert reset of I2C/RSB controller */
mmio_clrbits_32(SUNXI_R_PRCM_BASE + reset_offset, device_bit);
mmio_setbits_32(SUNXI_R_PRCM_BASE + reset_offset, device_bit);
return 0;
}
int32_t plat_is_smccc_feature_available(u_register_t fid)
{
switch (fid) {
case SMCCC_ARCH_SOC_ID:
return SMC_ARCH_CALL_SUCCESS;
default:
return SMC_ARCH_CALL_NOT_SUPPORTED;
}
}
int32_t plat_get_soc_version(void)
{
int32_t ret;
ret = SOC_ID_SET_JEP_106(JEDEC_ALLWINNER_BKID, JEDEC_ALLWINNER_MFID);
return ret | (sunxi_read_soc_id() & SOC_ID_IMPL_DEF_MASK);
}
int32_t plat_get_soc_revision(void)
{
uint32_t reg = mmio_read_32(SRAM_VER_REG);
return reg & GENMASK_32(7, 0);
}
@@ -0,0 +1,108 @@
/*
* Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <platform_def.h>
#include <arch_helpers.h>
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <lib/mmio.h>
#include <lib/utils_def.h>
#include <plat/common/platform.h>
#include <sunxi_cpucfg.h>
#include <sunxi_mmap.h>
#include <sunxi_private.h>
static void sunxi_cpu_disable_power(unsigned int cluster, unsigned int core)
{
if (mmio_read_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core)) == 0xff)
return;
VERBOSE("PSCI: Disabling power to cluster %d core %d\n", cluster, core);
mmio_write_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core), 0xff);
}
static void sunxi_cpu_enable_power(unsigned int cluster, unsigned int core)
{
if (mmio_read_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core)) == 0)
return;
VERBOSE("PSCI: Enabling power to cluster %d core %d\n", cluster, core);
/* Power enable sequence from original Allwinner sources */
mmio_write_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core), 0xfe);
mmio_write_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core), 0xf8);
mmio_write_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core), 0xe0);
mmio_write_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core), 0x80);
mmio_write_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core), 0x00);
udelay(1);
}
/* We can't turn ourself off like this, but it works for other cores. */
static void sunxi_cpu_off(u_register_t mpidr)
{
unsigned int cluster = MPIDR_AFFLVL1_VAL(mpidr);
unsigned int core = MPIDR_AFFLVL0_VAL(mpidr);
VERBOSE("PSCI: Powering off cluster %d core %d\n", cluster, core);
/* Deassert DBGPWRDUP */
mmio_clrbits_32(SUNXI_CPUCFG_DBG_REG0, BIT(core));
/* Activate the core output clamps, but not for core 0. */
if (core != 0)
mmio_setbits_32(SUNXI_POWEROFF_GATING_REG(cluster), BIT(core));
/* Assert CPU power-on reset */
mmio_clrbits_32(SUNXI_POWERON_RST_REG(cluster), BIT(core));
/* Remove power from the CPU */
sunxi_cpu_disable_power(cluster, core);
}
void sunxi_cpu_on(u_register_t mpidr)
{
unsigned int cluster = MPIDR_AFFLVL1_VAL(mpidr);
unsigned int core = MPIDR_AFFLVL0_VAL(mpidr);
VERBOSE("PSCI: Powering on cluster %d core %d\n", cluster, core);
/* Assert CPU core reset */
mmio_clrbits_32(SUNXI_CPUCFG_RST_CTRL_REG(cluster), BIT(core));
/* Assert CPU power-on reset */
mmio_clrbits_32(SUNXI_POWERON_RST_REG(cluster), BIT(core));
/* Set CPU to start in AArch64 mode */
mmio_setbits_32(SUNXI_AA64nAA32_REG(cluster),
BIT(SUNXI_AA64nAA32_OFFSET + core));
/* Apply power to the CPU */
sunxi_cpu_enable_power(cluster, core);
/* Release the core output clamps */
mmio_clrbits_32(SUNXI_POWEROFF_GATING_REG(cluster), BIT(core));
/* Deassert CPU power-on reset */
mmio_setbits_32(SUNXI_POWERON_RST_REG(cluster), BIT(core));
/* Deassert CPU core reset */
mmio_setbits_32(SUNXI_CPUCFG_RST_CTRL_REG(cluster), BIT(core));
/* Assert DBGPWRDUP */
mmio_setbits_32(SUNXI_CPUCFG_DBG_REG0, BIT(core));
}
void sunxi_cpu_power_off_others(void)
{
u_register_t self = read_mpidr();
unsigned int cluster;
unsigned int core;
for (cluster = 0; cluster < PLATFORM_CLUSTER_COUNT; ++cluster) {
for (core = 0; core < PLATFORM_MAX_CPUS_PER_CLUSTER; ++core) {
u_register_t mpidr = (cluster << MPIDR_AFF1_SHIFT) |
(core << MPIDR_AFF0_SHIFT) |
BIT(31);
if (mpidr != self)
sunxi_cpu_off(mpidr);
}
}
}
@@ -0,0 +1,81 @@
/*
* Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <common/debug.h>
#include <drivers/arm/gicv2.h>
#include <drivers/delay_timer.h>
#include <lib/mmio.h>
#include <lib/psci/psci.h>
#include <sunxi_mmap.h>
#include <sunxi_private.h>
#define SUNXI_WDOG0_CTRL_REG (SUNXI_R_WDOG_BASE + 0x0010)
#define SUNXI_WDOG0_CFG_REG (SUNXI_R_WDOG_BASE + 0x0014)
#define SUNXI_WDOG0_MODE_REG (SUNXI_R_WDOG_BASE + 0x0018)
static int sunxi_pwr_domain_on(u_register_t mpidr)
{
sunxi_cpu_on(mpidr);
return PSCI_E_SUCCESS;
}
static void sunxi_pwr_domain_off(const psci_power_state_t *target_state)
{
gicv2_cpuif_disable();
sunxi_cpu_power_off_self();
}
static void sunxi_pwr_domain_on_finish(const psci_power_state_t *target_state)
{
gicv2_pcpu_distif_init();
gicv2_cpuif_enable();
}
static void __dead2 sunxi_system_off(void)
{
gicv2_cpuif_disable();
/* Attempt to power down the board (may not return) */
sunxi_power_down();
/* Turn off all CPUs */
sunxi_cpu_power_off_others();
sunxi_cpu_power_off_self();
psci_power_down_wfi();
}
static void __dead2 sunxi_system_reset(void)
{
gicv2_cpuif_disable();
/* Reset the whole system when the watchdog times out */
mmio_write_32(SUNXI_WDOG0_CFG_REG, 1);
/* Enable the watchdog with the shortest timeout (0.5 seconds) */
mmio_write_32(SUNXI_WDOG0_MODE_REG, (0 << 4) | 1);
/* Wait for twice the watchdog timeout before panicking */
mdelay(1000);
ERROR("PSCI: System reset failed\n");
panic();
}
static const plat_psci_ops_t sunxi_native_psci_ops = {
.pwr_domain_on = sunxi_pwr_domain_on,
.pwr_domain_off = sunxi_pwr_domain_off,
.pwr_domain_on_finish = sunxi_pwr_domain_on_finish,
.system_off = sunxi_system_off,
.system_reset = sunxi_system_reset,
.validate_ns_entrypoint = sunxi_validate_ns_entrypoint,
};
void sunxi_set_native_psci_ops(const plat_psci_ops_t **psci_ops)
{
*psci_ops = &sunxi_native_psci_ops;
}
@@ -0,0 +1,60 @@
/*
* Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <platform_def.h>
#include <common/debug.h>
#include <common/fdt_fixup.h>
#include <lib/mmio.h>
#include <lib/psci/psci.h>
#include <sunxi_cpucfg.h>
#include <sunxi_private.h>
static bool psci_is_scpi;
#if SUNXI_PSCI_USE_SCPI
bool sunxi_psci_is_scpi(void)
{
return psci_is_scpi;
}
#endif
int sunxi_validate_ns_entrypoint(uintptr_t ns_entrypoint)
{
/* The non-secure entry point must be in DRAM */
if (ns_entrypoint < SUNXI_DRAM_BASE) {
return PSCI_E_INVALID_ADDRESS;
}
return PSCI_E_SUCCESS;
}
int plat_setup_psci_ops(uintptr_t sec_entrypoint,
const plat_psci_ops_t **psci_ops)
{
assert(psci_ops);
/* Program all CPU entry points. */
for (unsigned int cpu = 0; cpu < PLATFORM_CORE_COUNT; ++cpu) {
mmio_write_32(SUNXI_CPUCFG_RVBAR_LO_REG(cpu),
sec_entrypoint & 0xffffffff);
mmio_write_32(SUNXI_CPUCFG_RVBAR_HI_REG(cpu),
sec_entrypoint >> 32);
}
if (sunxi_set_scpi_psci_ops(psci_ops) == 0) {
INFO("PSCI: Suspend is available via SCPI\n");
psci_is_scpi = true;
} else {
INFO("PSCI: Suspend is unavailable\n");
sunxi_set_native_psci_ops(psci_ops);
}
return 0;
}
@@ -0,0 +1,52 @@
/*
* 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, 0x10000);
if (ret < 0) {
ERROR("Preparing devicetree at %p: error %d\n", fdt, ret);
return;
}
#ifdef SUNXI_BL31_IN_DRAM
/* 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");
}
#endif
if (sunxi_psci_is_scpi()) {
ret = fdt_add_cpu_idle_states(fdt, sunxi_idle_states);
if (ret < 0) {
WARN("Failed to add idle states to DT: %d\n", ret);
}
}
ret = fdt_pack(fdt);
if (ret < 0) {
ERROR("Failed to pack devicetree at %p: error %d\n",
fdt, ret);
}
clean_dcache_range((uintptr_t)fdt, fdt_blob_size(fdt));
INFO("Changed devicetree.\n");
}
@@ -0,0 +1,207 @@
/*
* Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <platform_def.h>
#include <arch_helpers.h>
#include <common/debug.h>
#include <drivers/arm/css/css_scpi.h>
#include <drivers/arm/gicv2.h>
#include <lib/mmio.h>
#include <lib/psci/psci.h>
#include <sunxi_mmap.h>
#include <sunxi_private.h>
/*
* The addresses for the SCP exception vectors are defined in the or1k
* architecture specification.
*/
#define OR1K_VEC_FIRST 0x01
#define OR1K_VEC_LAST 0x0e
#define OR1K_VEC_ADDR(n) (0x100 * (n))
/*
* This magic value is the little-endian representation of the or1k
* instruction "l.mfspr r2, r0, 0x12", which is guaranteed to be the
* first instruction in the SCP firmware.
*/
#define SCP_FIRMWARE_MAGIC 0xb4400012
#define PLAT_LOCAL_PSTATE_WIDTH U(4)
#define PLAT_LOCAL_PSTATE_MASK ((U(1) << PLAT_LOCAL_PSTATE_WIDTH) - 1)
#define CPU_PWR_LVL MPIDR_AFFLVL0
#define CLUSTER_PWR_LVL MPIDR_AFFLVL1
#define SYSTEM_PWR_LVL MPIDR_AFFLVL2
#define CPU_PWR_STATE(state) \
((state)->pwr_domain_state[CPU_PWR_LVL])
#define CLUSTER_PWR_STATE(state) \
((state)->pwr_domain_state[CLUSTER_PWR_LVL])
#define SYSTEM_PWR_STATE(state) \
((state)->pwr_domain_state[SYSTEM_PWR_LVL])
static void sunxi_cpu_standby(plat_local_state_t cpu_state)
{
u_register_t scr = read_scr_el3();
assert(is_local_state_retn(cpu_state));
write_scr_el3(scr | SCR_IRQ_BIT);
wfi();
write_scr_el3(scr);
}
static int sunxi_pwr_domain_on(u_register_t mpidr)
{
scpi_set_css_power_state(mpidr,
scpi_power_on,
scpi_power_on,
scpi_power_on);
return PSCI_E_SUCCESS;
}
static void sunxi_pwr_domain_off(const psci_power_state_t *target_state)
{
plat_local_state_t cpu_pwr_state = CPU_PWR_STATE(target_state);
plat_local_state_t cluster_pwr_state = CLUSTER_PWR_STATE(target_state);
plat_local_state_t system_pwr_state = SYSTEM_PWR_STATE(target_state);
if (is_local_state_off(cpu_pwr_state)) {
gicv2_cpuif_disable();
}
scpi_set_css_power_state(read_mpidr(),
cpu_pwr_state,
cluster_pwr_state,
system_pwr_state);
}
static void sunxi_pwr_domain_on_finish(const psci_power_state_t *target_state)
{
if (is_local_state_off(SYSTEM_PWR_STATE(target_state))) {
gicv2_distif_init();
}
if (is_local_state_off(CPU_PWR_STATE(target_state))) {
gicv2_pcpu_distif_init();
gicv2_cpuif_enable();
}
}
static void __dead2 sunxi_system_off(void)
{
uint32_t ret;
gicv2_cpuif_disable();
/* Send the power down request to the SCP. */
ret = scpi_sys_power_state(scpi_system_shutdown);
if (ret != SCP_OK) {
ERROR("PSCI: SCPI %s failed: %d\n", "shutdown", ret);
}
psci_power_down_wfi();
}
static void __dead2 sunxi_system_reset(void)
{
uint32_t ret;
gicv2_cpuif_disable();
/* Send the system reset request to the SCP. */
ret = scpi_sys_power_state(scpi_system_reboot);
if (ret != SCP_OK) {
ERROR("PSCI: SCPI %s failed: %d\n", "reboot", ret);
}
psci_power_down_wfi();
}
static int sunxi_validate_power_state(unsigned int power_state,
psci_power_state_t *req_state)
{
unsigned int power_level = psci_get_pstate_pwrlvl(power_state);
unsigned int state_id = psci_get_pstate_id(power_state);
unsigned int type = psci_get_pstate_type(power_state);
unsigned int i;
assert(req_state != NULL);
if (power_level > PLAT_MAX_PWR_LVL) {
return PSCI_E_INVALID_PARAMS;
}
if (type == PSTATE_TYPE_STANDBY) {
return PSCI_E_INVALID_PARAMS;
}
/* Pass through the requested PSCI state as-is. */
for (i = 0; i <= power_level; ++i) {
unsigned int local_pstate = state_id & PLAT_LOCAL_PSTATE_MASK;
req_state->pwr_domain_state[i] = local_pstate;
state_id >>= PLAT_LOCAL_PSTATE_WIDTH;
}
/* Higher power domain levels should all remain running */
for (; i <= PLAT_MAX_PWR_LVL; ++i) {
req_state->pwr_domain_state[i] = PSCI_LOCAL_STATE_RUN;
}
return PSCI_E_SUCCESS;
}
static void sunxi_get_sys_suspend_power_state(psci_power_state_t *req_state)
{
assert(req_state != NULL);
for (unsigned int i = 0; i <= PLAT_MAX_PWR_LVL; ++i) {
req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
}
}
static const plat_psci_ops_t sunxi_scpi_psci_ops = {
.cpu_standby = sunxi_cpu_standby,
.pwr_domain_on = sunxi_pwr_domain_on,
.pwr_domain_off = sunxi_pwr_domain_off,
.pwr_domain_suspend = sunxi_pwr_domain_off,
.pwr_domain_on_finish = sunxi_pwr_domain_on_finish,
.pwr_domain_suspend_finish = sunxi_pwr_domain_on_finish,
.system_off = sunxi_system_off,
.system_reset = sunxi_system_reset,
.validate_power_state = sunxi_validate_power_state,
.validate_ns_entrypoint = sunxi_validate_ns_entrypoint,
.get_sys_suspend_power_state = sunxi_get_sys_suspend_power_state,
};
int sunxi_set_scpi_psci_ops(const plat_psci_ops_t **psci_ops)
{
*psci_ops = &sunxi_scpi_psci_ops;
/* Check for a valid SCP firmware. */
if (mmio_read_32(SUNXI_SCP_BASE) != SCP_FIRMWARE_MAGIC) {
return -1;
}
/* Program SCP exception vectors to the firmware entrypoint. */
for (unsigned int i = OR1K_VEC_FIRST; i <= OR1K_VEC_LAST; ++i) {
uint32_t vector = SUNXI_SRAM_A2_BASE + OR1K_VEC_ADDR(i);
uint32_t offset = SUNXI_SCP_BASE - vector;
mmio_write_32(vector, offset >> 2);
}
/* Take the SCP out of reset. */
mmio_setbits_32(SUNXI_R_CPUCFG_BASE, BIT(0));
/* Wait for the SCP firmware to boot. */
return scpi_wait_ready();
}
@@ -0,0 +1,40 @@
/*
* Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <common/debug.h>
#include <lib/mmio.h>
#include <sunxi_ccu.h>
#include <sunxi_mmap.h>
#include <sunxi_private.h>
#include <sunxi_spc.h>
#define DMA_SEC_REG 0x20
/*
* Setup the peripherals to be accessible by non-secure world.
* This will not work for the Secure Peripherals Controller (SPC) unless
* a fuse it burnt (seems to be an erratum), but we do it nevertheless,
* to allow booting on boards using secure boot.
*/
void sunxi_security_setup(void)
{
int i;
INFO("Configuring SPC Controller\n");
/* SPC setup: set all devices to non-secure */
for (i = 0; i < SUNXI_SPC_NUM_PORTS; i++)
mmio_write_32(SUNXI_SPC_DECPORT_SET_REG(i), 0xffffffff);
/* set MBUS clocks, bus clocks (AXI/AHB/APB) and PLLs to non-secure */
mmio_write_32(SUNXI_CCU_SEC_SWITCH_REG, 0x7);
/* Set R_PRCM bus clocks to non-secure */
mmio_write_32(SUNXI_R_PRCM_SEC_SWITCH_REG, 0x1);
/* Set all DMA channels (16 max.) to non-secure */
mmio_write_32(SUNXI_DMA_BASE + DMA_SEC_REG, 0xffff);
}
@@ -0,0 +1,39 @@
/*
* Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <platform_def.h>
#include <arch.h>
#include <plat/common/platform.h>
static const unsigned char plat_power_domain_tree_desc[PLAT_MAX_PWR_LVL + 1] = {
/* One root node for the SoC */
1,
/* One node for each cluster */
PLATFORM_CLUSTER_COUNT,
/* One set of CPUs per cluster */
PLATFORM_MAX_CPUS_PER_CLUSTER,
};
int plat_core_pos_by_mpidr(u_register_t mpidr)
{
unsigned int cluster = MPIDR_AFFLVL1_VAL(mpidr);
unsigned int core = MPIDR_AFFLVL0_VAL(mpidr);
if (MPIDR_AFFLVL3_VAL(mpidr) > 0 ||
MPIDR_AFFLVL2_VAL(mpidr) > 0 ||
cluster >= PLATFORM_CLUSTER_COUNT ||
core >= PLATFORM_MAX_CPUS_PER_CLUSTER) {
return -1;
}
return cluster * PLATFORM_MAX_CPUS_PER_CLUSTER + core;
}
const unsigned char *plat_get_power_domain_tree_desc(void)
{
return plat_power_domain_tree_desc;
}
@@ -0,0 +1,39 @@
/*
* 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 */
0x19a00170, /* l.movhi r13, 0x170 */
0x84ad0030, /* l.lwz r5, 0x30(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 */
0x19a001f0, /* l.movhi r13, 0x1f0 */
0x84ad1500, /* l.lwz r5, 0x1500(r13) */
0xe0a53004, /* l.or r5, r5, r6 */
0xd44d2d00, /* l.sw 0x1500(r13), r5 */
0x84ad1c30, /* l.lwz r5, 0x1c30(r13) */
0xacc6ffff, /* l.xori r6, r6, -1 */
0xe0a53003, /* l.and r5, r5, r6 */
0xd46d2c30, /* l.sw 0x1c30(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 */
0xd4462d40, /* l.sw 0x1540(r6), r5 */
0xd46d0400, /* l.sw 0x1c00(r13), r0 */
0x03ffffff, /* l.j -1 */
0x15000000, /* l.nop */
};
@@ -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 + 0x02f0)
#define SUNXI_R_PRCM_SEC_SWITCH_REG (SUNXI_R_PRCM_BASE + 0x01d0)
#endif /* SUNXI_CCU_H */
@@ -0,0 +1,39 @@
/*
* Copyright (c) 2017-2018, ARM Limited and Contributors. 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 + 0x0000 + (c) * 16)
#define SUNXI_CPUCFG_CLS_CTRL_REG1(c) (SUNXI_CPUCFG_BASE + 0x0004 + (c) * 16)
#define SUNXI_CPUCFG_CACHE_CFG_REG0 (SUNXI_CPUCFG_BASE + 0x0008)
#define SUNXI_CPUCFG_CACHE_CFG_REG1 (SUNXI_CPUCFG_BASE + 0x000c)
#define SUNXI_CPUCFG_DBG_REG0 (SUNXI_CPUCFG_BASE + 0x0020)
#define SUNXI_CPUCFG_GLB_CTRL_REG (SUNXI_CPUCFG_BASE + 0x0028)
#define SUNXI_CPUCFG_CPU_STS_REG(c) (SUNXI_CPUCFG_BASE + 0x0030 + (c) * 4)
#define SUNXI_CPUCFG_L2_STS_REG (SUNXI_CPUCFG_BASE + 0x003c)
#define SUNXI_CPUCFG_RST_CTRL_REG(c) (SUNXI_CPUCFG_BASE + 0x0080 + (c) * 4)
#define SUNXI_CPUCFG_RVBAR_LO_REG(n) (SUNXI_CPUCFG_BASE + 0x00a0 + (n) * 8)
#define SUNXI_CPUCFG_RVBAR_HI_REG(n) (SUNXI_CPUCFG_BASE + 0x00a4 + (n) * 8)
#define SUNXI_CPU_POWER_CLAMP_REG(c, n) (SUNXI_R_PRCM_BASE + 0x0140 + \
(c) * 16 + (n) * 4)
#define SUNXI_POWEROFF_GATING_REG(c) (SUNXI_R_PRCM_BASE + 0x0100 + (c) * 4)
#define SUNXI_R_CPUCFG_CPUS_RST_REG (SUNXI_R_CPUCFG_BASE + 0x0000)
#define SUNXI_POWERON_RST_REG(c) (SUNXI_R_CPUCFG_BASE + 0x0030 + (c) * 4)
#define SUNXI_R_CPUCFG_SYS_RST_REG (SUNXI_R_CPUCFG_BASE + 0x0140)
#define SUNXI_R_CPUCFG_SS_FLAG_REG (SUNXI_R_CPUCFG_BASE + 0x01a0)
#define SUNXI_R_CPUCFG_CPU_ENTRY_REG (SUNXI_R_CPUCFG_BASE + 0x01a4)
#define SUNXI_R_CPUCFG_SS_ENTRY_REG (SUNXI_R_CPUCFG_BASE + 0x01a8)
#define SUNXI_R_CPUCFG_HP_FLAG_REG (SUNXI_R_CPUCFG_BASE + 0x01ac)
#define SUNXI_AA64nAA32_REG SUNXI_CPUCFG_CLS_CTRL_REG0
#define SUNXI_AA64nAA32_OFFSET 24
#endif /* SUNXI_CPUCFG_H */
@@ -0,0 +1,74 @@
/*
* 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 0x00010000
#define SUNXI_SRAM_SIZE 0x00044000
#define SUNXI_SRAM_A1_BASE 0x00010000
#define SUNXI_SRAM_A1_SIZE 0x00008000
#define SUNXI_SRAM_A2_BASE 0x00040000
#define SUNXI_SRAM_A2_BL31_OFFSET 0x00004000
#define SUNXI_SRAM_A2_SIZE 0x00014000
#define SUNXI_SRAM_C_BASE 0x00018000
#define SUNXI_SRAM_C_SIZE 0x0001c000
#define SUNXI_DEV_BASE 0x01000000
#define SUNXI_DEV_SIZE 0x01000000
#define SUNXI_DRAM_BASE 0x40000000
#define SUNXI_DRAM_VIRT_BASE 0x02000000
/* Memory-mapped devices */
#define SUNXI_CPU_MBIST_BASE 0x01502000
#define SUNXI_CPUCFG_BASE 0x01700000
#define SUNXI_SYSCON_BASE 0x01c00000
#define SUNXI_DMA_BASE 0x01c02000
#define SUNXI_KEYMEM_BASE 0x01c0b000
#define SUNXI_SMHC0_BASE 0x01c0f000
#define SUNXI_SMHC1_BASE 0x01c10000
#define SUNXI_SMHC2_BASE 0x01c11000
#define SUNXI_SID_BASE 0x01c14000
#define SUNXI_MSGBOX_BASE 0x01c17000
#define SUNXI_SPINLOCK_BASE 0x01c18000
#define SUNXI_CCU_BASE 0x01c20000
#define SUNXI_PIO_BASE 0x01c20800
#define SUNXI_TIMER_BASE 0x01c20c00
#define SUNXI_WDOG_BASE 0x01c20ca0
#define SUNXI_SPC_BASE 0x01c23400
#define SUNXI_THS_BASE 0x01c25000
#define SUNXI_UART0_BASE 0x01c28000
#define SUNXI_UART1_BASE 0x01c28400
#define SUNXI_UART2_BASE 0x01c28800
#define SUNXI_UART3_BASE 0x01c28c00
#define SUNXI_I2C0_BASE 0x01c2ac00
#define SUNXI_I2C1_BASE 0x01c2b000
#define SUNXI_I2C2_BASE 0x01c2b400
#define SUNXI_DRAMCOM_BASE 0x01c62000
#define SUNXI_DRAMCTL_BASE 0x01c63000
#define SUNXI_DRAMPHY_BASE 0x01c65000
#define SUNXI_SPI0_BASE 0x01c68000
#define SUNXI_SPI1_BASE 0x01c69000
#define SUNXI_SCU_BASE 0x01c80000
#define SUNXI_GICD_BASE 0x01c81000
#define SUNXI_GICC_BASE 0x01c82000
#define SUNXI_RTC_BASE 0x01f00000
#define SUNXI_R_TIMER_BASE 0x01f00800
#define SUNXI_R_INTC_BASE 0x01f00c00
#define SUNXI_R_WDOG_BASE 0x01f01000
#define SUNXI_R_PRCM_BASE 0x01f01400
#define SUNXI_R_TWD_BASE 0x01f01800
#define SUNXI_R_CPUCFG_BASE 0x01f01c00
#define SUNXI_R_CIR_BASE 0x01f02000
#define SUNXI_R_I2C_BASE 0x01f02400
#define SUNXI_R_UART_BASE 0x01f02800
#define SUNXI_R_PIO_BASE 0x01f02c00
#define SUNXI_R_RSB_BASE 0x01f03400
#define SUNXI_R_PWM_BASE 0x01f03800
#endif /* SUNXI_MMAP_H */
@@ -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 6
#define SUNXI_SPC_DECPORT_STA_REG(p) (SUNXI_SPC_BASE + 0x0004 + 0x0c * (p))
#define SUNXI_SPC_DECPORT_SET_REG(p) (SUNXI_SPC_BASE + 0x0008 + 0x0c * (p))
#define SUNXI_SPC_DECPORT_CLR_REG(p) (SUNXI_SPC_BASE + 0x000c + 0x0c * (p))
#endif /* SUNXI_SPC_H */
@@ -0,0 +1,17 @@
#
# Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
# The differences between the platform are covered by the include files.
include plat/allwinner/common/allwinner-common.mk
BL31_SOURCES += drivers/allwinner/axp/axp803.c \
drivers/allwinner/sunxi_rsb.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
@@ -0,0 +1,27 @@
/*
* Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <sunxi_private.h>
const struct psci_cpu_idle_state sunxi_idle_states[] = {
{
.name = "cpu-sleep",
.power_state = 0x00010003,
.local_timer_stop = true,
.entry_latency_us = 800,
.exit_latency_us = 1500,
.min_residency_us = 25000
},
{
.name = "cluster-sleep",
.power_state = 0x01010013,
.local_timer_stop = true,
.entry_latency_us = 850,
.exit_latency_us = 1500,
.min_residency_us = 50000
},
{}
};
@@ -0,0 +1,259 @@
/*
* Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2018, Icenowy Zheng <icenowy@aosc.io>
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <errno.h>
#include <platform_def.h>
#include <common/debug.h>
#include <drivers/allwinner/axp.h>
#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>
static enum pmic_type {
UNKNOWN,
GENERIC_H5,
GENERIC_A64,
REF_DESIGN_H5, /* regulators controlled by GPIO pins on port L */
AXP803_RSB, /* PMIC connected via RSB on most A64 boards */
} pmic;
#define AXP803_HW_ADDR 0x3a3
#define AXP803_RT_ADDR 0x2d
/*
* On boards without a proper PMIC we struggle to turn off the system properly.
* Try to turn off as much off the system as we can, to reduce power
* consumption. This should be entered with only one core running and SMP
* disabled.
* This function only cares about peripherals.
*/
static void sunxi_turn_off_soc(uint16_t socid)
{
int i;
/** Turn off most peripherals, most importantly DRAM users. **/
/* Keep DRAM controller running for now. */
mmio_clrbits_32(SUNXI_CCU_BASE + 0x2c0, ~BIT_32(14));
mmio_clrbits_32(SUNXI_CCU_BASE + 0x60, ~BIT_32(14));
/* Contains msgbox (bit 21) and spinlock (bit 22) */
mmio_write_32(SUNXI_CCU_BASE + 0x2c4, 0);
mmio_write_32(SUNXI_CCU_BASE + 0x64, 0);
mmio_write_32(SUNXI_CCU_BASE + 0x2c8, 0);
/* Keep PIO controller running for now. */
mmio_clrbits_32(SUNXI_CCU_BASE + 0x68, ~(BIT_32(5)));
mmio_write_32(SUNXI_CCU_BASE + 0x2d0, 0);
/* Contains UART0 (bit 16) */
mmio_write_32(SUNXI_CCU_BASE + 0x2d8, 0);
mmio_write_32(SUNXI_CCU_BASE + 0x6c, 0);
mmio_write_32(SUNXI_CCU_BASE + 0x70, 0);
/** Turn off DRAM controller. **/
mmio_clrbits_32(SUNXI_CCU_BASE + 0x2c0, BIT_32(14));
mmio_clrbits_32(SUNXI_CCU_BASE + 0x60, BIT_32(14));
/** Migrate CPU and bus clocks away from the PLLs. **/
/* AHB1: use OSC24M/1, APB1 = AHB1 / 2 */
mmio_write_32(SUNXI_CCU_BASE + 0x54, 0x1000);
/* APB2: use OSC24M */
mmio_write_32(SUNXI_CCU_BASE + 0x58, 0x1000000);
/* AHB2: use AHB1 clock */
mmio_write_32(SUNXI_CCU_BASE + 0x5c, 0);
/* CPU: use OSC24M */
mmio_write_32(SUNXI_CCU_BASE + 0x50, 0x10000);
/** Turn off PLLs. **/
for (i = 0; i < 6; i++)
mmio_clrbits_32(SUNXI_CCU_BASE + i * 8, BIT(31));
switch (socid) {
case SUNXI_SOC_H5:
mmio_clrbits_32(SUNXI_CCU_BASE + 0x44, BIT(31));
break;
case SUNXI_SOC_A64:
mmio_clrbits_32(SUNXI_CCU_BASE + 0x2c, BIT(31));
mmio_clrbits_32(SUNXI_CCU_BASE + 0x4c, BIT(31));
break;
}
}
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(AXP803_HW_ADDR,
AXP803_RT_ADDR);
if (ret)
return ret;
return axp_check_id();
}
int axp_read(uint8_t reg)
{
return rsb_read(AXP803_RT_ADDR, reg);
}
int axp_write(uint8_t reg, uint8_t val)
{
return rsb_write(AXP803_RT_ADDR, reg, val);
}
int sunxi_pmic_setup(uint16_t socid, const void *fdt)
{
int ret;
switch (socid) {
case SUNXI_SOC_H5:
NOTICE("PMIC: Assuming H5 reference regulator design\n");
pmic = REF_DESIGN_H5;
break;
case SUNXI_SOC_A64:
pmic = GENERIC_A64;
INFO("PMIC: Probing AXP803 on RSB\n");
ret = sunxi_init_platform_r_twi(socid, true);
if (ret)
return ret;
ret = rsb_init();
if (ret)
return ret;
pmic = AXP803_RSB;
axp_setup_regulators(fdt);
/* Switch the PMIC back to I2C mode. */
ret = axp_write(AXP20X_MODE_REG, AXP20X_MODE_I2C);
if (ret)
return ret;
break;
default:
return -ENODEV;
}
return 0;
}
void sunxi_power_down(void)
{
switch (pmic) {
case GENERIC_H5:
/* Turn off as many peripherals and clocks as we can. */
sunxi_turn_off_soc(SUNXI_SOC_H5);
/* Turn off the pin controller now. */
mmio_write_32(SUNXI_CCU_BASE + 0x68, 0);
break;
case GENERIC_A64:
/* Turn off as many peripherals and clocks as we can. */
sunxi_turn_off_soc(SUNXI_SOC_A64);
/* Turn off the pin controller now. */
mmio_write_32(SUNXI_CCU_BASE + 0x68, 0);
break;
case REF_DESIGN_H5:
sunxi_turn_off_soc(SUNXI_SOC_H5);
/*
* Switch PL pins to power off the board:
* - PL5 (VCC_IO) -> high
* - PL8 (PWR-STB = CPU power supply) -> low
* - PL9 (PWR-DRAM) ->low
* - PL10 (power LED) -> low
* Note: Clearing PL8 will reset the board, so keep it up.
*/
sunxi_set_gpio_out('L', 5, 1);
sunxi_set_gpio_out('L', 9, 0);
sunxi_set_gpio_out('L', 10, 0);
/* Turn off pin controller now. */
mmio_write_32(SUNXI_CCU_BASE + 0x68, 0);
break;
case AXP803_RSB:
/* (Re-)init RSB in case the rich OS has disabled it. */
sunxi_init_platform_r_twi(SUNXI_SOC_A64, true);
rsb_init();
axp_power_off();
break;
default:
break;
}
}
/* 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);
/* 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);
}
@@ -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 */
@@ -0,0 +1,35 @@
/*
* Copyright (c) 2017-2021, ARM Limited and Contributors. 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)
#define SUNXI_AA64nAA32_REG SUNXI_CPUCFG_CLS_CTRL_REG0
#define SUNXI_AA64nAA32_OFFSET 24
#endif /* SUNXI_CPUCFG_H */
@@ -0,0 +1,63 @@
/*
* 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 0x000f8000
#define SUNXI_SRAM_A1_BASE 0x00020000
#define SUNXI_SRAM_A1_SIZE 0x00008000
#define SUNXI_SRAM_A2_BASE 0x00100000
#define SUNXI_SRAM_A2_BL31_OFFSET 0x00004000
#define SUNXI_SRAM_A2_SIZE 0x00018000
#define SUNXI_SRAM_C_BASE 0x00028000
#define SUNXI_SRAM_C_SIZE 0x0001e000
#define SUNXI_DEV_BASE 0x01000000
#define SUNXI_DEV_SIZE 0x09000000
#define SUNXI_DRAM_BASE 0x40000000
#define SUNXI_DRAM_VIRT_BASE 0x0a000000
/* Memory-mapped devices */
#define SUNXI_SYSCON_BASE 0x03000000
#define SUNXI_CPUCFG_BASE 0x09010000
#define SUNXI_SID_BASE 0x03006000
#define SUNXI_DMA_BASE 0x03002000
#define SUNXI_MSGBOX_BASE 0x03003000
#define SUNXI_CCU_BASE 0x03001000
#define SUNXI_PIO_BASE 0x0300b000
#define SUNXI_SPC_BASE 0x03008000
#define SUNXI_TIMER_BASE 0x03009000
#define SUNXI_WDOG_BASE 0x030090a0
#define SUNXI_THS_BASE 0x05070400
#define SUNXI_UART0_BASE 0x05000000
#define SUNXI_UART1_BASE 0x05000400
#define SUNXI_UART2_BASE 0x05000800
#define SUNXI_UART3_BASE 0x05000c00
#define SUNXI_I2C0_BASE 0x05002000
#define SUNXI_I2C1_BASE 0x05002400
#define SUNXI_I2C2_BASE 0x05002800
#define SUNXI_I2C3_BASE 0x05002c00
#define SUNXI_SPI0_BASE 0x05010000
#define SUNXI_SPI1_BASE 0x05011000
#define SUNXI_SCU_BASE 0x03020000
#define SUNXI_GICD_BASE 0x03021000
#define SUNXI_GICC_BASE 0x03022000
#define SUNXI_R_TIMER_BASE 0x07020000
#define SUNXI_R_INTC_BASE 0x07021000
#define SUNXI_R_WDOG_BASE 0x07020400
#define SUNXI_R_PRCM_BASE 0x07010000
#define SUNXI_R_TWD_BASE 0x07020800
#define SUNXI_R_CPUCFG_BASE 0x07000400
#define SUNXI_R_I2C_BASE 0x07081400
#define SUNXI_R_RSB_BASE 0x07083000
#define SUNXI_R_UART_BASE 0x07080000
#define SUNXI_R_PIO_BASE 0x07022000
#endif /* SUNXI_MMAP_H */
@@ -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 */
@@ -0,0 +1,14 @@
#
# Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
# The differences between the platform are covered by the include files.
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
@@ -0,0 +1,11 @@
/*
* Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <sunxi_private.h>
const struct psci_cpu_idle_state sunxi_idle_states[] = {
{}
};
@@ -0,0 +1,119 @@
/*
* Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2018, Icenowy Zheng <icenowy@aosc.io>
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <errno.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 AXP805_HW_ADDR 0x745
#define AXP805_RT_ADDR 0x3a
static enum pmic_type {
UNKNOWN,
AXP805,
} pmic;
int axp_read(uint8_t reg)
{
return rsb_read(AXP805_RT_ADDR, reg);
}
int axp_write(uint8_t reg, uint8_t val)
{
return rsb_write(AXP805_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(AXP805_HW_ADDR, AXP805_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 AXP805 on RSB\n");
ret = sunxi_init_platform_r_twi(socid, true);
if (ret)
return ret;
ret = rsb_init();
if (ret)
return ret;
/* Switch the AXP805 to master/single-PMIC mode. */
ret = axp_write(0xff, 0x0);
if (ret)
return ret;
pmic = AXP805;
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 AXP805:
/* (Re-)init RSB in case the rich OS has disabled it. */
sunxi_init_platform_r_twi(SUNXI_SOC_H6, 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));
}
@@ -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 */
@@ -0,0 +1,35 @@
/*
* 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)
#define SUNXI_AA64nAA32_REG SUNXI_CPUCFG_CLS_CTRL_REG0
#define SUNXI_AA64nAA32_OFFSET 24
#endif /* SUNXI_CPUCFG_H */
@@ -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 */
@@ -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 */
@@ -0,0 +1,22 @@
#
# Copyright (c) 2017-2020, ARM Limited. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
SUNXI_BL31_IN_DRAM := 1
# 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 \
@@ -0,0 +1,11 @@
/*
* Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <sunxi_private.h>
const struct psci_cpu_idle_state sunxi_idle_states[] = {
{}
};
@@ -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));
}
@@ -0,0 +1,14 @@
/*
* Copyright (c) 2021 Sipeed
*
* 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 */
@@ -0,0 +1,31 @@
/*
* Copyright (c) 2021 Sipeed
*
* 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_C0_CPUXCFG_BASE + 0x0010)
#define SUNXI_CPUCFG_CLS_CTRL_REG1(c) (SUNXI_C0_CPUXCFG_BASE + 0x0014)
#define SUNXI_CPUCFG_CACHE_CFG_REG (SUNXI_C0_CPUXCFG_BASE + 0x0024)
#define SUNXI_CPUCFG_DBG_REG0 (SUNXI_C0_CPUXCFG_BASE + 0x00c0)
#define SUNXI_CPUCFG_RST_CTRL_REG(c) (SUNXI_C0_CPUXCFG_BASE + 0x0000)
#define SUNXI_CPUCFG_GEN_CTRL_REG0(c) (SUNXI_CPUCFG_BASE + 0x0000)
#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_AA64nAA32_REG SUNXI_CPUCFG_GEN_CTRL_REG0
#define SUNXI_AA64nAA32_OFFSET 4
#endif /* SUNXI_CPUCFG_H */
@@ -0,0 +1,55 @@
/*
* 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
/*
* In fact all SRAM from 0x100000 is SRAM A2. However as it's too big for
* firmware, and the user manual gives a tip on a 2*64K/27*64K partition,
* only use the first 2*64K for firmwares now, with the SPL using the first
* 64K and BL3-1 using the second one.
*
* Only the used 2*64K SRAM is defined here, to prevent a gaint translation
* table to be generated.
*/
#define SUNXI_SRAM_BASE 0x00100000
#define SUNXI_SRAM_SIZE 0x00020000
#define SUNXI_SRAM_A1_BASE 0x00100000
#define SUNXI_SRAM_A1_SIZE 0x00010000
#define SUNXI_SRAM_A2_BASE 0x00110000
#define SUNXI_SRAM_A2_BL31_OFFSET 0x00000000
#define SUNXI_SRAM_A2_SIZE 0x00010000
#define SUNXI_DEV_BASE 0x01000000
#define SUNXI_DEV_SIZE 0x09000000
#define SUNXI_DRAM_BASE 0x40000000
#define SUNXI_DRAM_VIRT_BASE 0x0a000000
/* Memory-mapped devices */
#define SUNXI_WDOG_BASE 0x020000a0
#define SUNXI_R_WDOG_BASE SUNXI_WDOG_BASE
#define SUNXI_PIO_BASE 0x02000400
#define SUNXI_SPC_BASE 0x02000800
#define SUNXI_CCU_BASE 0x02001000
#define SUNXI_UART0_BASE 0x02500000
#define SUNXI_SYSCON_BASE 0x03000000
#define SUNXI_DMA_BASE 0x03002000
#define SUNXI_SID_BASE 0x03006000
#define SUNXI_GICD_BASE 0x03021000
#define SUNXI_GICC_BASE 0x03022000
#define SUNXI_SPI0_BASE 0x04025000
#define SUNXI_R_CPUCFG_BASE 0x07000400
#define SUNXI_R_PRCM_BASE 0x07010000
#define SUNXI_R_PIO_BASE 0x07022000
#define SUNXI_R_UART_BASE 0x07080000
#define SUNXI_R_I2C_BASE 0x07081400
#define SUNXI_CPUCFG_BASE 0x08100000
#define SUNXI_C0_CPUXCFG_BASE 0x09010000
#endif /* SUNXI_MMAP_H */
@@ -0,0 +1,17 @@
/*
* Copyright (c) 2021 Sipeed
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef SUNXI_SPC_H
#define SUNXI_SPC_H
/* Get by REing stock ATF and checking initialization loop boundary */
#define SUNXI_SPC_NUM_PORTS 11
#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 */
@@ -0,0 +1,20 @@
#
# Copyright (c) 2021 Sipeed
#
# 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 "R329 does not support SCPI PSCI ops")
endif
# Put NOBITS memory in the first 64K of SRAM A2, overwriting U-Boot's SPL.
SEPARATE_NOBITS_REGION := 1
@@ -0,0 +1,11 @@
/*
* Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <sunxi_private.h>
const struct psci_cpu_idle_state sunxi_idle_states[] = {
{}
};
@@ -0,0 +1,27 @@
/*
* Copyright (c) 2021 Sipeed
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <platform_def.h>
#include <sunxi_mmap.h>
#include <sunxi_cpucfg.h>
#include <sunxi_private.h>
int sunxi_pmic_setup(uint16_t socid, const void *fdt)
{
/* Currently known hardware has no PMIC */
return 0;
}
void sunxi_power_down(void)
{
}
void sunxi_cpu_power_off_self(void)
{
/* TODO: It's still unknown whether CPUIDLE exists on R329 */
}