GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)
This commit is contained in:
+114
@@ -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)
|
||||
+28
@@ -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 */
|
||||
+27
@@ -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 */
|
||||
+84
@@ -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 */
|
||||
+26
@@ -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 */
|
||||
+61
@@ -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
|
||||
+204
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+81
@@ -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;
|
||||
}
|
||||
+52
@@ -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;
|
||||
}
|
||||
+39
@@ -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 */
|
||||
};
|
||||
+14
@@ -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 */
|
||||
+39
@@ -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 */
|
||||
+74
@@ -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 */
|
||||
+16
@@ -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
|
||||
+27
@@ -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
|
||||
},
|
||||
{}
|
||||
};
|
||||
+259
@@ -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);
|
||||
}
|
||||
+14
@@ -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 */
|
||||
+35
@@ -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 */
|
||||
+63
@@ -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 */
|
||||
+16
@@ -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
|
||||
+11
@@ -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[] = {
|
||||
{}
|
||||
};
|
||||
+119
@@ -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));
|
||||
}
|
||||
+14
@@ -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 */
|
||||
+35
@@ -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 */
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef SUNXI_MMAP_H
|
||||
#define SUNXI_MMAP_H
|
||||
|
||||
/* Memory regions */
|
||||
#define SUNXI_ROM_BASE 0x00000000
|
||||
#define SUNXI_ROM_SIZE 0x00010000
|
||||
#define SUNXI_SRAM_BASE 0x00020000
|
||||
#define SUNXI_SRAM_SIZE 0x00038000
|
||||
#define SUNXI_SRAM_A1_BASE 0x00020000
|
||||
#define SUNXI_SRAM_A1_SIZE 0x00008000
|
||||
#define SUNXI_SRAM_C_BASE 0x00028000
|
||||
#define SUNXI_SRAM_C_SIZE 0x00030000
|
||||
#define SUNXI_DEV_BASE 0x01000000
|
||||
#define SUNXI_DEV_SIZE 0x09000000
|
||||
#define SUNXI_DRAM_BASE 0x40000000
|
||||
#define SUNXI_DRAM_VIRT_BASE SUNXI_DRAM_BASE
|
||||
|
||||
/* Memory-mapped devices */
|
||||
#define SUNXI_SYSCON_BASE 0x03000000
|
||||
#define SUNXI_CCU_BASE 0x03001000
|
||||
#define SUNXI_DMA_BASE 0x03002000
|
||||
#define SUNXI_SID_BASE 0x03006000
|
||||
#define SUNXI_SPC_BASE 0x03008000
|
||||
#define SUNXI_WDOG_BASE 0x030090a0
|
||||
#define SUNXI_PIO_BASE 0x0300b000
|
||||
#define SUNXI_GICD_BASE 0x03021000
|
||||
#define SUNXI_GICC_BASE 0x03022000
|
||||
#define SUNXI_UART0_BASE 0x05000000
|
||||
#define SUNXI_SPI0_BASE 0x05010000
|
||||
#define SUNXI_R_CPUCFG_BASE 0x07000400
|
||||
#define SUNXI_R_PRCM_BASE 0x07010000
|
||||
//#define SUNXI_R_WDOG_BASE 0x07020400
|
||||
#define SUNXI_R_WDOG_BASE SUNXI_WDOG_BASE
|
||||
#define SUNXI_R_PIO_BASE 0x07022000
|
||||
#define SUNXI_R_UART_BASE 0x07080000
|
||||
#define SUNXI_R_I2C_BASE 0x07081400
|
||||
#define SUNXI_R_RSB_BASE 0x07083000
|
||||
#define SUNXI_CPUCFG_BASE 0x09010000
|
||||
|
||||
#endif /* SUNXI_MMAP_H */
|
||||
+16
@@ -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 \
|
||||
+11
@@ -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[] = {
|
||||
{}
|
||||
};
|
||||
+121
@@ -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));
|
||||
}
|
||||
+14
@@ -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 */
|
||||
+31
@@ -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 */
|
||||
+55
@@ -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 */
|
||||
+17
@@ -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
|
||||
+11
@@ -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[] = {
|
||||
{}
|
||||
};
|
||||
+27
@@ -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 */
|
||||
}
|
||||
Reference in New Issue
Block a user