Merge branch 'patch/h3-scp' into allwinner

This commit is contained in:
Samuel Holland 2022-05-25 22:52:04 -05:00
commit d0e956e3ce
22 changed files with 755 additions and 32 deletions

View File

@ -415,7 +415,7 @@ config BUILD_TARGET
default "u-boot-spl.kwb" if ARCH_MVEBU && SPL default "u-boot-spl.kwb" if ARCH_MVEBU && SPL
default "u-boot-elf.srec" if RCAR_GEN3 default "u-boot-elf.srec" if RCAR_GEN3
default "u-boot.itb" if !BINMAN && SPL_LOAD_FIT && (ARCH_ROCKCHIP || \ default "u-boot.itb" if !BINMAN && SPL_LOAD_FIT && (ARCH_ROCKCHIP || \
ARCH_SUNXI || RISCV || ARCH_ZYNQMP) RISCV || ARCH_ZYNQMP)
default "u-boot.kwb" if ARCH_KIRKWOOD default "u-boot.kwb" if ARCH_KIRKWOOD
default "u-boot-with-spl.bin" if ARCH_AT91 && SPL_NAND_SUPPORT default "u-boot-with-spl.bin" if ARCH_AT91 && SPL_NAND_SUPPORT
default "u-boot-with-spl.imx" if ARCH_MX6 && SPL default "u-boot-with-spl.imx" if ARCH_MX6 && SPL

View File

@ -1005,6 +1005,23 @@ endif
endif endif
endif endif
ifeq ($(CONFIG_MACH_SUN8I_H3)$(CONFIG_ARMV7_PSCI),yy)
INPUTS-$(CONFIG_ARMV7_PSCI) += u-boot-resume.img
MKIMAGEFLAGS_u-boot-resume.img := -B 0x400 -T sunxi_egon
u-boot-resume.img: u-boot-resume.bin
$(call if_changed,mkimage)
OBJCOPYFLAGS_u-boot-resume.bin := -O binary
u-boot-resume.bin: u-boot-resume.o
$(call if_changed,objcopy)
u-boot-resume.S: u-boot
@sed -En 's/(0x[[:xdigit:]]+) +psci_cpu_entry/ldr pc, =\1/p' $<.map > $@
endif
INPUTS-$(CONFIG_X86) += u-boot-x86-start16.bin u-boot-x86-reset16.bin \ INPUTS-$(CONFIG_X86) += u-boot-x86-start16.bin u-boot-x86-reset16.bin \
$(if $(CONFIG_SPL_X86_16BIT_INIT),spl/u-boot-spl.bin) \ $(if $(CONFIG_SPL_X86_16BIT_INIT),spl/u-boot-spl.bin) \
$(if $(CONFIG_TPL_X86_16BIT_INIT),tpl/u-boot-tpl.bin) $(if $(CONFIG_TPL_X86_16BIT_INIT),tpl/u-boot-tpl.bin)

View File

@ -1194,6 +1194,7 @@ config ARCH_SUNXI
imply SPL_GPIO imply SPL_GPIO
imply SPL_LIBCOMMON_SUPPORT imply SPL_LIBCOMMON_SUPPORT
imply SPL_LIBGENERIC_SUPPORT imply SPL_LIBGENERIC_SUPPORT
imply SPL_LOAD_FIT
imply SPL_MMC if MMC imply SPL_MMC if MMC
imply SPL_POWER imply SPL_POWER
imply SPL_SERIAL imply SPL_SERIAL

View File

@ -75,11 +75,14 @@ config ARMV7_PSCI
choice choice
prompt "Supported PSCI version" prompt "Supported PSCI version"
depends on ARMV7_PSCI depends on ARMV7_PSCI
default ARMV7_PSCI_0_1 if ARCH_SUNXI default ARMV7_PSCI_1_1 if ARCH_SUNXI
default ARMV7_PSCI_1_0 default ARMV7_PSCI_1_0
help help
Select the supported PSCI version. Select the supported PSCI version.
config ARMV7_PSCI_1_1
bool "PSCI V1.1"
config ARMV7_PSCI_1_0 config ARMV7_PSCI_1_0
bool "PSCI V1.0" bool "PSCI V1.0"

View File

@ -13,8 +13,12 @@ obj-$(CONFIG_MACH_SUN6I) += sram.o
obj-$(CONFIG_MACH_SUN8I) += sram.o obj-$(CONFIG_MACH_SUN8I) += sram.o
ifndef CONFIG_SPL_BUILD ifndef CONFIG_SPL_BUILD
ifdef CONFIG_MACH_SUN8I_H3
obj-$(CONFIG_ARMV7_PSCI) += psci-scpi.o
else
obj-$(CONFIG_ARMV7_PSCI) += psci.o obj-$(CONFIG_ARMV7_PSCI) += psci.o
endif endif
endif
ifdef CONFIG_SPL_BUILD ifdef CONFIG_SPL_BUILD
obj-y += fel_utils.o obj-y += fel_utils.o

View File

@ -0,0 +1,451 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2016 Chen-Yu Tsai <wens@csie.org>
* Copyright (C) 2018-2021 Samuel Holland <samuel@sholland.org>
*/
#include <common.h>
#include <asm/arch/cpu.h>
#include <asm/arch/cpucfg.h>
#include <asm/armv7.h>
#include <asm/gic.h>
#include <asm/io.h>
#include <asm/psci.h>
#include <asm/secure.h>
#include <asm/system.h>
#define GICD_BASE (SUNXI_GIC400_BASE + GIC_DIST_OFFSET)
#define GICC_BASE (SUNXI_GIC400_BASE + GIC_CPU_OFFSET_A15)
#define HW_ON 0
#define HW_OFF 1
#define HW_STANDBY 2
#define MPIDR_AFFLVL0(mpidr) (mpidr & 0xf)
#define MPIDR_AFFLVL1(mpidr) (mpidr >> 8 & 0xf)
#define SCPI_SHMEM_BASE 0x0004be00
#define SCPI_SHMEM ((struct scpi_shmem *)SCPI_SHMEM_BASE)
#define SCPI_RX_CHANNEL 1
#define SCPI_TX_CHANNEL 0
#define SCPI_VIRTUAL_CHANNEL BIT(0)
#define SCPI_MESSAGE_SIZE 0x100
#define SCPI_PAYLOAD_SIZE (SCPI_MESSAGE_SIZE - sizeof(struct scpi_header))
#define SUNXI_MSGBOX_BASE 0x01c17000
#define REMOTE_IRQ_STAT_REG (SUNXI_MSGBOX_BASE + 0x0050)
#define LOCAL_IRQ_STAT_REG (SUNXI_MSGBOX_BASE + 0x0070)
#define MSG_STAT_REG(n) (SUNXI_MSGBOX_BASE + 0x0140 + 0x4 * (n))
#define MSG_DATA_REG(n) (SUNXI_MSGBOX_BASE + 0x0180 + 0x4 * (n))
#define RX_IRQ(n) BIT(0 + 2 * (n))
#define TX_IRQ(n) BIT(1 + 2 * (n))
enum {
CORE_POWER_LEVEL = 0,
CLUSTER_POWER_LEVEL = 1,
CSS_POWER_LEVEL = 2,
};
enum {
SCPI_CMD_SCP_READY = 0x01,
SCPI_CMD_SET_CSS_POWER_STATE = 0x03,
SCPI_CMD_GET_CSS_POWER_STATE = 0x04,
SCPI_CMD_SET_SYS_POWER_STATE = 0x05,
};
enum {
SCPI_E_OK = 0,
SCPI_E_PARAM = 1,
SCPI_E_ALIGN = 2,
SCPI_E_SIZE = 3,
SCPI_E_HANDLER = 4,
SCPI_E_ACCESS = 5,
SCPI_E_RANGE = 6,
SCPI_E_TIMEOUT = 7,
SCPI_E_NOMEM = 8,
SCPI_E_PWRSTATE = 9,
SCPI_E_SUPPORT = 10,
SCPI_E_DEVICE = 11,
SCPI_E_BUSY = 12,
SCPI_E_OS = 13,
SCPI_E_DATA = 14,
SCPI_E_STATE = 15,
};
enum {
SCPI_POWER_ON = 0x00,
SCPI_POWER_RETENTION = 0x01,
SCPI_POWER_OFF = 0x03,
};
enum {
SCPI_SYSTEM_SHUTDOWN = 0x00,
SCPI_SYSTEM_REBOOT = 0x01,
SCPI_SYSTEM_RESET = 0x02,
};
struct scpi_header {
u8 command;
u8 sender;
u16 size;
u32 status;
};
struct scpi_message {
struct scpi_header header;
u8 payload[SCPI_PAYLOAD_SIZE];
};
struct scpi_shmem {
struct scpi_message rx;
struct scpi_message tx;
};
static bool __secure_data gic_dist_init;
static u32 __secure_data lock;
static inline u32 __secure read_mpidr(void)
{
u32 val;
asm volatile ("mrc p15, 0, %0, c0, c0, 5" : "=r" (val));
return val;
}
static void __secure scpi_begin_command(void)
{
u32 mpidr = read_mpidr();
do {
while (readl(&lock));
writel(mpidr, &lock);
dsb();
} while (readl(&lock) != mpidr);
while (readl(REMOTE_IRQ_STAT_REG) & RX_IRQ(SCPI_TX_CHANNEL));
}
static void __secure scpi_send_command(void)
{
writel(SCPI_VIRTUAL_CHANNEL, MSG_DATA_REG(SCPI_TX_CHANNEL));
}
static void __secure scpi_wait_response(void)
{
while (!readl(MSG_STAT_REG(SCPI_RX_CHANNEL)));
}
static void __secure scpi_end_command(void)
{
while (readl(MSG_STAT_REG(SCPI_RX_CHANNEL)))
readl(MSG_DATA_REG(SCPI_RX_CHANNEL));
writel(RX_IRQ(SCPI_RX_CHANNEL), LOCAL_IRQ_STAT_REG);
writel(0, &lock);
}
static void __secure scpi_set_css_power_state(u32 target_cpu, u32 core_state,
u32 cluster_state, u32 css_state)
{
struct scpi_shmem *shmem = SCPI_SHMEM;
scpi_begin_command();
shmem->tx.header.command = SCPI_CMD_SET_CSS_POWER_STATE;
shmem->tx.header.size = 4;
shmem->tx.payload[0] = target_cpu >> 4 | target_cpu;
shmem->tx.payload[1] = cluster_state << 4 | core_state;
shmem->tx.payload[2] = css_state;
shmem->tx.payload[3] = 0;
scpi_send_command();
scpi_end_command();
}
static s32 __secure scpi_get_css_power_state(u32 target_cpu, u8 *core_states,
u8 *cluster_state)
{
struct scpi_shmem *shmem = SCPI_SHMEM;
u32 cluster = MPIDR_AFFLVL1(target_cpu);
u32 offset;
s32 ret;
scpi_begin_command();
shmem->tx.header.command = SCPI_CMD_GET_CSS_POWER_STATE;
shmem->tx.header.size = 0;
scpi_send_command();
scpi_wait_response();
for (offset = 0; offset < shmem->rx.header.size; offset += 2) {
if ((shmem->rx.payload[offset] & 0xf) == cluster) {
*cluster_state = shmem->rx.payload[offset+0] >> 4;
*core_states = shmem->rx.payload[offset+1];
break;
}
}
ret = shmem->rx.header.status;
scpi_end_command();
return ret;
}
static s32 __secure scpi_set_sys_power_state(u32 sys_state)
{
struct scpi_shmem *shmem = SCPI_SHMEM;
s32 ret;
scpi_begin_command();
shmem->tx.header.command = SCPI_CMD_SET_SYS_POWER_STATE;
shmem->tx.header.size = 1;
shmem->tx.payload[0] = sys_state;
scpi_send_command();
scpi_wait_response();
ret = shmem->rx.header.status;
scpi_end_command();
return ret;
}
void psci_enable_smp(void);
static s32 __secure psci_suspend_common(u32 pc, u32 context_id, u32 core_state,
u32 cluster_state, u32 css_state)
{
u32 target_cpu = read_mpidr();
if (core_state == SCPI_POWER_OFF)
psci_save(MPIDR_AFFLVL0(target_cpu), pc, context_id);
if (css_state == SCPI_POWER_OFF)
gic_dist_init = true;
scpi_set_css_power_state(target_cpu, core_state,
cluster_state, css_state);
psci_cpu_off_common();
wfi();
psci_enable_smp();
return ARM_PSCI_RET_SUCCESS;
}
u32 __secure psci_version(void)
{
return ARM_PSCI_VER_1_1;
}
s32 __secure psci_cpu_suspend(u32 __always_unused function_id,
u32 power_state, u32 pc, u32 context_id)
{
return psci_suspend_common(pc, context_id,
power_state >> 0 & 0xf,
power_state >> 4 & 0xf,
power_state >> 8 & 0xf);
}
s32 __secure psci_cpu_off(void)
{
u32 pc = 0, context_id = 0;
return psci_suspend_common(pc, context_id, SCPI_POWER_OFF,
SCPI_POWER_OFF, SCPI_POWER_ON);
}
s32 __secure psci_cpu_on(u32 __always_unused function_id,
u32 target_cpu, u32 pc, u32 context_id)
{
psci_save(MPIDR_AFFLVL0(target_cpu), pc, context_id);
scpi_set_css_power_state(target_cpu, SCPI_POWER_ON,
SCPI_POWER_ON, SCPI_POWER_ON);
return ARM_PSCI_RET_SUCCESS;
}
s32 __secure psci_affinity_info(u32 function_id,
u32 target_cpu, u32 power_level)
{
if (power_level != CORE_POWER_LEVEL)
return ARM_PSCI_RET_INVAL;
/* This happens to have the same HW_ON/HW_OFF encoding. */
return psci_node_hw_state(function_id, target_cpu, power_level);
}
void __secure psci_system_off(void)
{
scpi_set_sys_power_state(SCPI_SYSTEM_SHUTDOWN);
/* Wait to be turned off. */
for (;;) wfi();
}
void __secure psci_system_reset(void)
{
scpi_set_sys_power_state(SCPI_SYSTEM_REBOOT);
/* Wait to be turned off. */
for (;;) wfi();
}
s32 __secure psci_features(u32 __always_unused function_id,
u32 psci_fid)
{
switch (psci_fid) {
case ARM_PSCI_0_2_FN_PSCI_VERSION:
case ARM_PSCI_0_2_FN_CPU_SUSPEND:
case ARM_PSCI_0_2_FN_CPU_OFF:
case ARM_PSCI_0_2_FN_CPU_ON:
case ARM_PSCI_0_2_FN_AFFINITY_INFO:
case ARM_PSCI_0_2_FN_SYSTEM_OFF:
case ARM_PSCI_0_2_FN_SYSTEM_RESET:
case ARM_PSCI_1_0_FN_PSCI_FEATURES:
case ARM_PSCI_1_0_FN_CPU_DEFAULT_SUSPEND:
case ARM_PSCI_1_0_FN_NODE_HW_STATE:
case ARM_PSCI_1_0_FN_SYSTEM_SUSPEND:
case ARM_PSCI_1_1_FN_SYSTEM_RESET2:
return ARM_PSCI_RET_SUCCESS;
default:
return ARM_PSCI_RET_NI;
}
}
s32 __secure psci_cpu_default_suspend(u32 __always_unused function_id,
u32 pc, u32 context_id)
{
return psci_suspend_common(pc, context_id, SCPI_POWER_OFF,
SCPI_POWER_OFF, SCPI_POWER_RETENTION);
}
s32 __secure psci_node_hw_state(u32 __always_unused function_id,
u32 target_cpu, u32 power_level)
{
u32 core = MPIDR_AFFLVL0(target_cpu);
u8 core_states, cluster_state;
if (power_level >= CSS_POWER_LEVEL)
return HW_ON;
if (scpi_get_css_power_state(target_cpu, &core_states, &cluster_state))
return ARM_PSCI_RET_NI;
if (power_level == CLUSTER_POWER_LEVEL) {
if (cluster_state == SCPI_POWER_ON)
return HW_ON;
if (cluster_state < SCPI_POWER_OFF)
return HW_STANDBY;
return HW_OFF;
}
return (core_states & BIT(core)) ? HW_ON : HW_OFF;
}
s32 __secure psci_system_suspend(u32 __always_unused function_id,
u32 pc, u32 context_id)
{
return psci_suspend_common(pc, context_id, SCPI_POWER_OFF,
SCPI_POWER_OFF, SCPI_POWER_OFF);
}
s32 __secure psci_system_reset2(u32 __always_unused function_id,
u32 reset_type, u32 cookie)
{
s32 ret;
if (reset_type)
return ARM_PSCI_RET_INVAL;
ret = scpi_set_sys_power_state(SCPI_SYSTEM_RESET);
if (ret)
return ARM_PSCI_RET_INVAL;
/* Wait to be turned off. */
for (;;) wfi();
}
/*
* R40 is different from other single cluster SoCs. The secondary core
* entry address register is in the SRAM controller address range.
*/
#define SUN8I_R40_SRAMC_SOFT_ENTRY_REG0 (0xbc)
#ifdef CONFIG_MACH_SUN8I_R40
/* secondary core entry address is programmed differently on R40 */
static void __secure sunxi_set_entry_address(void *entry)
{
writel((u32)entry,
SUNXI_SRAMC_BASE + SUN8I_R40_SRAMC_SOFT_ENTRY_REG0);
}
#else
static void __secure sunxi_set_entry_address(void *entry)
{
struct sunxi_cpucfg_reg *cpucfg =
(struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
writel((u32)entry, &cpucfg->priv0);
if (IS_ENABLED(CONFIG_MACH_SUN8I_H3)) {
/* Redirect CPU 0 to the secure monitor via the resume shim. */
writel(0x16aaefe8, &cpucfg->super_standy_flag);
writel(0xaa16efe8, &cpucfg->super_standy_flag);
writel(SUNXI_RESUME_BASE, &cpucfg->priv1);
}
}
#endif
void __secure psci_arch_init(void)
{
static bool __secure_data one_time_init = true;
if (one_time_init) {
/* Set secondary core power-on PC. */
sunxi_set_entry_address(psci_cpu_entry);
/* Wait for the SCP firmware to boot. */
scpi_begin_command();
scpi_wait_response();
scpi_end_command();
one_time_init = false;
}
/*
* Copied from arch/arm/cpu/armv7/virt-v7.c
* See also gic_resume() in arch/arm/mach-imx/mx7/psci-mx7.c
*/
if (gic_dist_init) {
u32 i, itlinesnr;
/* enable the GIC distributor */
writel(readl(GICD_BASE + GICD_CTLR) | 0x03, GICD_BASE + GICD_CTLR);
/* TYPER[4:0] contains an encoded number of available interrupts */
itlinesnr = readl(GICD_BASE + GICD_TYPER) & 0x1f;
/* set all bits in the GIC group registers to one to allow access
* from non-secure state. The first 32 interrupts are private per
* CPU and will be set later when enabling the GIC for each core
*/
for (i = 1; i <= itlinesnr; i++)
writel((unsigned)-1, GICD_BASE + GICD_IGROUPRn + 4 * i);
gic_dist_init = false;
}
/* Be cool with non-secure. */
writel(0xff, GICC_BASE + GICC_PMR);
}

View File

@ -10,6 +10,7 @@
#include <common.h> #include <common.h>
#include <asm/cache.h> #include <asm/cache.h>
#include <asm/arch/clock.h>
#include <asm/arch/cpu.h> #include <asm/arch/cpu.h>
#include <asm/arch/cpucfg.h> #include <asm/arch/cpucfg.h>
#include <asm/arch/prcm.h> #include <asm/arch/prcm.h>
@ -38,6 +39,15 @@
#define SUN8I_R40_PWR_CLAMP(cpu) (0x120 + (cpu) * 0x4) #define SUN8I_R40_PWR_CLAMP(cpu) (0x120 + (cpu) * 0x4)
#define SUN8I_R40_SRAMC_SOFT_ENTRY_REG0 (0xbc) #define SUN8I_R40_SRAMC_SOFT_ENTRY_REG0 (0xbc)
static inline u32 __secure cp15_read_mpidr(void)
{
u32 val;
asm volatile ("mrc p15, 0, %0, c0, c0, 5" : "=r" (val));
return val;
}
static void __secure cp15_write_cntp_tval(u32 tval) static void __secure cp15_write_cntp_tval(u32 tval)
{ {
asm volatile ("mcr p15, 0, %0, c14, c2, 0" : : "r" (tval)); asm volatile ("mcr p15, 0, %0, c14, c2, 0" : : "r" (tval));
@ -132,6 +142,13 @@ static void __secure sunxi_set_entry_address(void *entry)
(struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE; (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
writel((u32)entry, &cpucfg->priv0); writel((u32)entry, &cpucfg->priv0);
#ifdef CONFIG_MACH_SUN8I_H3
/* Redirect CPU 0 to the secure monitor via the resume shim. */
writel(0x16aaefe8, &cpucfg->super_standy_flag);
writel(0xaa16efe8, &cpucfg->super_standy_flag);
writel(SUNXI_RESUME_BASE, &cpucfg->priv1);
#endif
} }
#endif #endif
@ -246,9 +263,12 @@ out:
int __secure psci_cpu_on(u32 __always_unused unused, u32 mpidr, u32 pc, int __secure psci_cpu_on(u32 __always_unused unused, u32 mpidr, u32 pc,
u32 context_id) u32 context_id)
{ {
struct sunxi_ccm_reg *ccu = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
struct sunxi_cpucfg_reg *cpucfg = struct sunxi_cpucfg_reg *cpucfg =
(struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE; (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
u32 cpu = (mpidr & 0x3); u32 cpu = (mpidr & 0x3);
u32 cpu_clk;
u32 bus_clk;
/* store target PC and context id */ /* store target PC and context id */
psci_save(cpu, pc, context_id); psci_save(cpu, pc, context_id);
@ -265,12 +285,32 @@ int __secure psci_cpu_on(u32 __always_unused unused, u32 mpidr, u32 pc,
/* Lock CPU (Disable external debug access) */ /* Lock CPU (Disable external debug access) */
clrbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu)); clrbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu));
if (IS_ENABLED(CONFIG_MACH_SUN8I_H3) && cpu == 0) {
/* Save registers that will be clobbered by the BROM. */
cpu_clk = readl(&ccu->cpu_axi_cfg);
bus_clk = readl(&ccu->ahb1_apb1_div);
/* Bypass PLL_PERIPH0 so AHB1 frequency does not spike. */
setbits_le32(&ccu->pll6_cfg, BIT(25));
}
/* Power up target CPU */ /* Power up target CPU */
sunxi_cpu_set_power(cpu, true); sunxi_cpu_set_power(cpu, true);
/* De-assert reset on target CPU */ /* De-assert reset on target CPU */
writel(BIT(1) | BIT(0), &cpucfg->cpu[cpu].rst); writel(BIT(1) | BIT(0), &cpucfg->cpu[cpu].rst);
if (IS_ENABLED(CONFIG_MACH_SUN8I_H3) && cpu == 0) {
/* Spin until the BROM has clobbered the clock registers. */
while (readl(&ccu->ahb1_apb1_div) != 0x00001100);
/* Restore the registers and turn off PLL_PERIPH0 bypass. */
writel(cpu_clk, &ccu->cpu_axi_cfg);
writel(bus_clk, &ccu->ahb1_apb1_div);
clrbits_le32(&ccu->pll6_cfg, BIT(25));
}
/* Unlock CPU (Disable external debug access) */ /* Unlock CPU (Disable external debug access) */
setbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu)); setbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu));
@ -281,9 +321,14 @@ s32 __secure psci_cpu_off(void)
{ {
psci_cpu_off_common(); psci_cpu_off_common();
if (cp15_read_mpidr() & 3) {
/* Ask CPU0 via SGI15 to pull the rug... */ /* Ask CPU0 via SGI15 to pull the rug... */
writel(BIT(16) | 15, GICD_BASE + GICD_SGIR); writel(BIT(16) | 15, GICD_BASE + GICD_SGIR);
dsb(); dsb();
} else {
/* Unmask FIQs to service SGI15. */
asm volatile ("cpsie f");
}
/* Wait to be turned off */ /* Wait to be turned off */
while (1) while (1)

View File

@ -103,7 +103,7 @@ void __noreturn psci_system_reset2(u32 reset_level, u32 cookie)
{ {
struct pt_regs regs; struct pt_regs regs;
regs.regs[0] = ARM_PSCI_0_2_FN64_SYSTEM_RESET2; regs.regs[0] = ARM_PSCI_1_1_FN64_SYSTEM_RESET2;
regs.regs[1] = PSCI_RESET2_TYPE_VENDOR | reset_level; regs.regs[1] = PSCI_RESET2_TYPE_VENDOR | reset_level;
regs.regs[2] = cookie; regs.regs[2] = cookie;
if (use_smc_for_psci) if (use_smc_for_psci)

View File

@ -170,6 +170,14 @@
#size-cells = <1>; #size-cells = <1>;
ranges; ranges;
sram_a2: sram@40000 {
compatible = "mmio-sram";
reg = <0x00040000 0xc000>;
#address-cells = <1>;
#size-cells = <1>;
ranges = <0 0x00040000 0xc000>;
};
sram_c: sram@1d00000 { sram_c: sram@1d00000 {
compatible = "mmio-sram"; compatible = "mmio-sram";
reg = <0x01d00000 0x80000>; reg = <0x01d00000 0x80000>;
@ -239,6 +247,12 @@
nvmem-cell-names = "calibration"; nvmem-cell-names = "calibration";
#thermal-sensor-cells = <0>; #thermal-sensor-cells = <0>;
}; };
remoteproc@1f01c00 {
compatible = "allwinner,sun6i-a31-ar100";
reg = <0x01f01c00 0x400>;
sram = <&sram_a2>;
};
}; };
thermal-zones { thermal-zones {

View File

@ -1,13 +1,24 @@
#include <config.h> #include <config.h>
#ifdef CONFIG_MACH_SUN50I_H6 #ifdef CONFIG_ARM64
#define BL31_ADDR 0x104000 #define ARCH "arm64"
#define SCP_ADDR 0x114000 #else
#define ARCH "arm"
#endif
#if defined(CONFIG_MACH_SUN8I_H3)
#ifdef CONFIG_ARMV7_PSCI
#define RESUME_ADDR SUNXI_RESUME_BASE
#define SCP_ADDR SUNXI_SCP_BASE
#endif
#elif defined(CONFIG_MACH_SUN50I) || defined(CONFIG_MACH_SUN50I_H5)
#define BL31_ADDR 0x00044000
#define SCP_ADDR 0x00050000
#elif defined(CONFIG_MACH_SUN50I_H6)
#define BL31_ADDR 0x00104000
#define SCP_ADDR 0x00114000
#elif defined(CONFIG_MACH_SUN50I_H616) #elif defined(CONFIG_MACH_SUN50I_H616)
#define BL31_ADDR 0x40000000 #define BL31_ADDR 0x40000000
#else
#define BL31_ADDR 0x44000
#define SCP_ADDR 0x50000
#endif #endif
/ { / {
@ -34,30 +45,33 @@
filename = "spl/sunxi-spl.bin"; filename = "spl/sunxi-spl.bin";
}; };
#ifdef CONFIG_ARM64 #ifdef CONFIG_SPL_LOAD_FIT
fit { fit {
description = "Configuration to load ATF before U-Boot"; description = "Configuration to load U-Boot and firmware";
offset = <32768>;
#address-cells = <1>; #address-cells = <1>;
fit,fdt-list = "of-list"; fit,fdt-list = "of-list";
images { images {
uboot { uboot {
description = "U-Boot (64-bit)"; description = "U-Boot";
type = "standalone"; type = "standalone";
os = "u-boot"; os = "u-boot";
arch = "arm64"; arch = ARCH;
compression = "none"; compression = "none";
load = <CONFIG_SYS_TEXT_BASE>; load = <CONFIG_SYS_TEXT_BASE>;
entry = <CONFIG_SYS_TEXT_BASE>;
u-boot-nodtb { u-boot-nodtb {
}; };
}; };
#ifdef BL31_ADDR
atf { atf {
description = "ARM Trusted Firmware"; description = "ARM Trusted Firmware";
type = "firmware"; type = "firmware";
os = "arm-trusted-firmware"; os = "arm-trusted-firmware";
arch = "arm64"; arch = ARCH;
compression = "none"; compression = "none";
load = <BL31_ADDR>; load = <BL31_ADDR>;
entry = <BL31_ADDR>; entry = <BL31_ADDR>;
@ -67,6 +81,21 @@
missing-msg = "atf-bl31-sunxi"; missing-msg = "atf-bl31-sunxi";
}; };
}; };
#endif
#ifdef RESUME_ADDR
resume {
description = "Super Standby resume image";
type = "standalone";
arch = ARCH;
compression = "none";
load = <RESUME_ADDR>;
blob-ext {
filename = "u-boot-resume.img";
};
};
#endif
#ifdef SCP_ADDR #ifdef SCP_ADDR
scp { scp {
@ -95,19 +124,26 @@
@config-SEQ { @config-SEQ {
description = "NAME"; description = "NAME";
#ifdef BL31_ADDR
firmware = "atf"; firmware = "atf";
#ifndef SCP_ADDR
loadables = "uboot";
#else #else
loadables = "scp", "uboot"; firmware = "uboot";
#endif #endif
loadables =
#ifdef RESUME_ADDR
"resume",
#endif
#ifdef SCP_ADDR
"scp",
#endif
"uboot";
fdt = "fdt-SEQ"; fdt = "fdt-SEQ";
}; };
}; };
}; };
#else #else
u-boot-img { u-boot-img {
offset = <CONFIG_SPL_PAD_TO>; offset = <32768>;
}; };
#endif #endif
}; };

View File

@ -22,8 +22,9 @@
#include <linux/bitops.h> #include <linux/bitops.h>
#endif #endif
#define ARM_PSCI_VER_1_0 (0x00010000)
#define ARM_PSCI_VER_0_2 (0x00000002) #define ARM_PSCI_VER_0_2 (0x00000002)
#define ARM_PSCI_VER_1_0 (0x00010000)
#define ARM_PSCI_VER_1_1 (0x00010001)
/* PSCI 0.1 interface */ /* PSCI 0.1 interface */
#define ARM_PSCI_FN_BASE 0x95c1ba5e #define ARM_PSCI_FN_BASE 0x95c1ba5e
@ -68,7 +69,6 @@
#define ARM_PSCI_0_2_FN64_AFFINITY_INFO ARM_PSCI_0_2_FN64(4) #define ARM_PSCI_0_2_FN64_AFFINITY_INFO ARM_PSCI_0_2_FN64(4)
#define ARM_PSCI_0_2_FN64_MIGRATE ARM_PSCI_0_2_FN64(5) #define ARM_PSCI_0_2_FN64_MIGRATE ARM_PSCI_0_2_FN64(5)
#define ARM_PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU ARM_PSCI_0_2_FN64(7) #define ARM_PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU ARM_PSCI_0_2_FN64(7)
#define ARM_PSCI_0_2_FN64_SYSTEM_RESET2 ARM_PSCI_0_2_FN64(18)
/* PSCI 1.0 interface */ /* PSCI 1.0 interface */
#define ARM_PSCI_1_0_FN_PSCI_FEATURES ARM_PSCI_0_2_FN(10) #define ARM_PSCI_1_0_FN_PSCI_FEATURES ARM_PSCI_0_2_FN(10)
@ -86,6 +86,11 @@
#define ARM_PSCI_1_0_FN64_STAT_RESIDENCY ARM_PSCI_0_2_FN64(16) #define ARM_PSCI_1_0_FN64_STAT_RESIDENCY ARM_PSCI_0_2_FN64(16)
#define ARM_PSCI_1_0_FN64_STAT_COUNT ARM_PSCI_0_2_FN64(17) #define ARM_PSCI_1_0_FN64_STAT_COUNT ARM_PSCI_0_2_FN64(17)
/* PSCI 1.1 interface */
#define ARM_PSCI_1_1_FN_SYSTEM_RESET2 ARM_PSCI_0_2_FN(18)
#define ARM_PSCI_1_1_FN64_SYSTEM_RESET2 ARM_PSCI_0_2_FN64(18)
/* 1KB stack per core */ /* 1KB stack per core */
#define ARM_PSCI_STACK_SHIFT 10 #define ARM_PSCI_STACK_SHIFT 10
#define ARM_PSCI_STACK_SIZE (1 << ARM_PSCI_STACK_SHIFT) #define ARM_PSCI_STACK_SIZE (1 << ARM_PSCI_STACK_SHIFT)

View File

@ -557,16 +557,20 @@ void mmu_page_table_flush(unsigned long start, unsigned long stop);
#ifdef CONFIG_ARMV7_PSCI #ifdef CONFIG_ARMV7_PSCI
void psci_arch_cpu_entry(void); void psci_arch_cpu_entry(void);
void psci_arch_init(void); void psci_arch_init(void);
u32 psci_version(void); u32 psci_version(void);
s32 psci_features(u32 function_id, u32 psci_fid); s32 psci_cpu_suspend(u32 function_id, u32 power_state, u32 pc, u32 context_id);
s32 psci_cpu_off(void); s32 psci_cpu_off(void);
s32 psci_cpu_on(u32 function_id, u32 target_cpu, u32 pc, s32 psci_cpu_on(u32 function_id, u32 target_cpu, u32 pc, u32 context_id);
u32 context_id); s32 psci_affinity_info(u32 function_id, u32 target_affinity, u32 power_level);
s32 psci_affinity_info(u32 function_id, u32 target_affinity,
u32 lowest_affinity_level);
u32 psci_migrate_info_type(void); u32 psci_migrate_info_type(void);
void psci_system_off(void); void psci_system_off(void);
void psci_system_reset(void); void psci_system_reset(void);
s32 psci_features(u32 function_id, u32 psci_fid);
s32 psci_cpu_default_suspend(u32 function_id, u32 pc, u32 context_id);
s32 psci_node_hw_state(u32 function_id, u32 target_cpu, u32 power_level);
s32 psci_system_suspend(u32 function_id, u32 pc, u32 context_id);
s32 psci_system_reset2(u32 function_id, u32 reset_type, u32 cookie);
#endif #endif
#endif /* __ASSEMBLY__ */ #endif /* __ASSEMBLY__ */

View File

@ -66,6 +66,8 @@ int fdt_psci(void *fdt)
init_psci_node: init_psci_node:
#if CONFIG_IS_ENABLED(ARMV8_SEC_FIRMWARE_SUPPORT) #if CONFIG_IS_ENABLED(ARMV8_SEC_FIRMWARE_SUPPORT)
psci_ver = sec_firmware_support_psci_version(); psci_ver = sec_firmware_support_psci_version();
#elif defined(CONFIG_ARMV7_PSCI_1_1)
psci_ver = ARM_PSCI_VER_1_1;
#elif defined(CONFIG_ARMV7_PSCI_1_0) || defined(CONFIG_ARMV8_PSCI) #elif defined(CONFIG_ARMV7_PSCI_1_0) || defined(CONFIG_ARMV8_PSCI)
psci_ver = ARM_PSCI_VER_1_0; psci_ver = ARM_PSCI_VER_1_0;
#elif defined(CONFIG_ARMV7_PSCI_0_2) #elif defined(CONFIG_ARMV7_PSCI_0_2)

View File

@ -19,6 +19,7 @@
#include <init.h> #include <init.h>
#include <log.h> #include <log.h>
#include <mmc.h> #include <mmc.h>
#include <remoteproc.h>
#include <axp_pmic.h> #include <axp_pmic.h>
#include <generic-phy.h> #include <generic-phy.h>
#include <phy-sun4i-usb.h> #include <phy-sun4i-usb.h>
@ -857,6 +858,13 @@ int board_late_init(void)
usb_ether_init(); usb_ether_init();
#endif #endif
#ifdef SUNXI_SCP_BASE
if (!rproc_load(0, SUNXI_SCP_BASE, SUNXI_SCP_MAX_SIZE)) {
puts("Starting SCP...\n");
rproc_start(0);
}
#endif
return 0; return 0;
} }

View File

@ -477,8 +477,7 @@ config SPL_MD5
config SPL_FIT_IMAGE_TINY config SPL_FIT_IMAGE_TINY
bool "Remove functionality from SPL FIT loading to reduce size" bool "Remove functionality from SPL FIT loading to reduce size"
depends on SPL_FIT depends on SPL_FIT
default y if MACH_SUN50I || MACH_SUN50I_H5 || SUN50I_GEN_H6 default y if ARCH_IMX8M || ARCH_SUNXI
default y if ARCH_IMX8M
help help
Enable this to reduce the size of the FIT image loading code Enable this to reduce the size of the FIT image loading code
in SPL, if space for the SPL binary is very tight. in SPL, if space for the SPL binary is very tight.

View File

@ -6,5 +6,6 @@ CONFIG_MACH_SUN8I_H3=y
CONFIG_DRAM_CLK=672 CONFIG_DRAM_CLK=672
# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
CONFIG_SUN8I_EMAC=y CONFIG_SUN8I_EMAC=y
CONFIG_REMOTEPROC_SUN6I_AR100=y
CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_HCD=y
CONFIG_USB_OHCI_HCD=y CONFIG_USB_OHCI_HCD=y

View File

@ -12,5 +12,6 @@ CONFIG_SPL_SYS_I2C_LEGACY=y
CONFIG_SYS_I2C_MVTWSI=y CONFIG_SYS_I2C_MVTWSI=y
CONFIG_SUN8I_EMAC=y CONFIG_SUN8I_EMAC=y
CONFIG_SY8106A_POWER=y CONFIG_SY8106A_POWER=y
CONFIG_REMOTEPROC_SUN6I_AR100=y
CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_HCD=y
CONFIG_USB_OHCI_HCD=y CONFIG_USB_OHCI_HCD=y

View File

@ -41,6 +41,15 @@ config REMOTEPROC_STM32_COPRO
Say 'y' here to add support for STM32 Cortex-M4 coprocessors via the Say 'y' here to add support for STM32 Cortex-M4 coprocessors via the
remoteproc framework. remoteproc framework.
config REMOTEPROC_SUN6I_AR100
bool "Support for Allwinner AR100 SCP"
select REMOTEPROC
depends on ARCH_SUNXI
help
Say 'y' here to support Allwinner's AR100 System Control Processor
(SCP), found in various sun6i/sun8i/sun50i family SoCs, through the
remoteproc framework.
config REMOTEPROC_TI_K3_ARM64 config REMOTEPROC_TI_K3_ARM64
bool "Support for TI's K3 based ARM64 remoteproc driver" bool "Support for TI's K3 based ARM64 remoteproc driver"
select REMOTEPROC select REMOTEPROC

View File

@ -10,6 +10,7 @@ obj-$(CONFIG_$(SPL_)REMOTEPROC) += rproc-uclass.o rproc-elf-loader.o
obj-$(CONFIG_K3_SYSTEM_CONTROLLER) += k3_system_controller.o obj-$(CONFIG_K3_SYSTEM_CONTROLLER) += k3_system_controller.o
obj-$(CONFIG_REMOTEPROC_SANDBOX) += sandbox_testproc.o obj-$(CONFIG_REMOTEPROC_SANDBOX) += sandbox_testproc.o
obj-$(CONFIG_REMOTEPROC_STM32_COPRO) += stm32_copro.o obj-$(CONFIG_REMOTEPROC_STM32_COPRO) += stm32_copro.o
obj-$(CONFIG_REMOTEPROC_SUN6I_AR100) += sun6i_ar100_rproc.o
obj-$(CONFIG_REMOTEPROC_TI_K3_ARM64) += ti_k3_arm64_rproc.o obj-$(CONFIG_REMOTEPROC_TI_K3_ARM64) += ti_k3_arm64_rproc.o
obj-$(CONFIG_REMOTEPROC_TI_K3_DSP) += ti_k3_dsp_rproc.o obj-$(CONFIG_REMOTEPROC_TI_K3_DSP) += ti_k3_dsp_rproc.o
obj-$(CONFIG_REMOTEPROC_TI_K3_R5F) += ti_k3_r5f_rproc.o obj-$(CONFIG_REMOTEPROC_TI_K3_R5F) += ti_k3_r5f_rproc.o

View File

@ -0,0 +1,111 @@
// SPDX-License-Identifier: GPL-2.0
#include <dm.h>
#include <errno.h>
#include <remoteproc.h>
#include <asm/io.h>
#define SUNXI_SCP_MAGIC 0xb4400012
#define OR1K_VEC_FIRST 0x01
#define OR1K_VEC_LAST 0x0e
#define OR1K_VEC_ADDR(n) (0x100 * (n))
struct sun6i_ar100_rproc_priv {
void *cfg_base;
ulong sram_base;
};
static int sun6i_ar100_rproc_load(struct udevice *dev, ulong addr, ulong size)
{
struct sun6i_ar100_rproc_priv *priv = dev_get_priv(dev);
/* Check for a valid SCP firmware. */
if (readl_relaxed(addr) != SUNXI_SCP_MAGIC)
return -ENOENT;
/* Program exception vectors to the firmware entry point. */
for (u32 i = OR1K_VEC_FIRST; i <= OR1K_VEC_LAST; ++i) {
ulong vector = priv->sram_base + OR1K_VEC_ADDR(i);
ulong offset = addr - vector;
writel_relaxed(offset >> 2, vector);
}
return 0;
}
static int sun6i_ar100_rproc_start(struct udevice *dev)
{
struct sun6i_ar100_rproc_priv *priv = dev_get_priv(dev);
setbits_le32(priv->cfg_base, BIT(0));
return 0;
}
static int sun6i_ar100_rproc_stop(struct udevice *dev)
{
struct sun6i_ar100_rproc_priv *priv = dev_get_priv(dev);
clrbits_le32(priv->cfg_base, BIT(0));
return 0;
}
static int sun6i_ar100_rproc_reset(struct udevice *dev)
{
int ret;
ret = sun6i_ar100_rproc_stop(dev);
if (ret)
return ret;
return sun6i_ar100_rproc_start(dev);
}
static int sun6i_ar100_rproc_is_running(struct udevice *dev)
{
struct sun6i_ar100_rproc_priv *priv = dev_get_priv(dev);
return !(readl_relaxed(priv->cfg_base) & BIT(0));
}
static const struct dm_rproc_ops sun6i_ar100_rproc_ops = {
.load = sun6i_ar100_rproc_load,
.start = sun6i_ar100_rproc_start,
.stop = sun6i_ar100_rproc_stop,
.reset = sun6i_ar100_rproc_reset,
.is_running = sun6i_ar100_rproc_is_running,
};
static int sun6i_ar100_rproc_probe(struct udevice *dev)
{
struct sun6i_ar100_rproc_priv *priv = dev_get_priv(dev);
struct ofnode_phandle_args sram_handle;
int ret;
priv->cfg_base = dev_read_addr_ptr(dev);
ret = dev_read_phandle_with_args(dev, "sram", NULL, 0, 0, &sram_handle);
if (ret)
return ret;
priv->sram_base = ofnode_get_addr(sram_handle.node);
return 0;
}
static const struct udevice_id sun6i_ar100_rproc_ids[] = {
{ .compatible = "allwinner,sun6i-a31-ar100" },
{ }
};
U_BOOT_DRIVER(sun6i_ar100_rproc) = {
.name = "sun6i_ar100_rproc",
.id = UCLASS_REMOTEPROC,
.of_match = sun6i_ar100_rproc_ids,
.probe = sun6i_ar100_rproc_probe,
.priv_auto = sizeof(struct sun6i_ar100_rproc_priv),
.ops = &sun6i_ar100_rproc_ops,
};

View File

@ -14,6 +14,15 @@
#include <asm/arch/cpu.h> #include <asm/arch/cpu.h>
#ifdef SUNXI_SRAM_A2_SIZE
#define SUNXI_RESUME_BASE (CONFIG_ARMV7_SECURE_BASE + \
CONFIG_ARMV7_SECURE_MAX_SIZE)
#define SUNXI_RESUME_SIZE 1024
#define SUNXI_SCP_BASE (SUNXI_RESUME_BASE + SUNXI_RESUME_SIZE)
#define SUNXI_SCP_MAX_SIZE (16 * 1024)
#endif
/* /*
* Include common sunxi configuration where most the settings are * Include common sunxi configuration where most the settings are
*/ */

View File

@ -465,6 +465,8 @@ class Entry(object):
if self.offset_unset: if self.offset_unset:
self.Raise('No offset set with offset-unset: should another ' self.Raise('No offset set with offset-unset: should another '
'entry provide this correct offset?') 'entry provide this correct offset?')
elif self.offset > offset:
offset = self.offset
self.offset = tools.align(offset, self.align) self.offset = tools.align(offset, self.align)
needed = self.pad_before + self.contents_size + self.pad_after needed = self.pad_before + self.contents_size + self.pad_after
needed = tools.align(needed, self.align_size) needed = tools.align(needed, self.align_size)