
From: Oleksandr Tyshchenko oleksandr_tyshchenko@epam.com
Also enable PSCI support for Stout and Lager boards where actually the r8a7790 SoC is installed.
All secondary CPUs will be switched to a non-secure HYP mode after booting.
Signed-off-by: Oleksandr Tyshchenko oleksandr_tyshchenko@epam.com --- arch/arm/mach-rmobile/Kconfig.32 | 2 + arch/arm/mach-rmobile/Makefile | 6 + arch/arm/mach-rmobile/pm-r8a7790.c | 408 +++++++++++++++++++++++++++++++++++++ arch/arm/mach-rmobile/pm-r8a7790.h | 72 +++++++ arch/arm/mach-rmobile/psci.c | 193 ++++++++++++++++++ include/configs/lager.h | 2 + include/configs/stout.h | 2 + 7 files changed, 685 insertions(+) create mode 100644 arch/arm/mach-rmobile/pm-r8a7790.c create mode 100644 arch/arm/mach-rmobile/pm-r8a7790.h create mode 100644 arch/arm/mach-rmobile/psci.c
diff --git a/arch/arm/mach-rmobile/Kconfig.32 b/arch/arm/mach-rmobile/Kconfig.32 index a2e9e3d..728c323 100644 --- a/arch/arm/mach-rmobile/Kconfig.32 +++ b/arch/arm/mach-rmobile/Kconfig.32 @@ -78,6 +78,7 @@ config TARGET_LAGER imply CMD_DM select CPU_V7_HAS_NONSEC select CPU_V7_HAS_VIRT + select ARCH_SUPPORT_PSCI
config TARGET_KZM9G bool "KZM9D board" @@ -119,6 +120,7 @@ config TARGET_STOUT imply CMD_DM select CPU_V7_HAS_NONSEC select CPU_V7_HAS_VIRT + select ARCH_SUPPORT_PSCI
endchoice
diff --git a/arch/arm/mach-rmobile/Makefile b/arch/arm/mach-rmobile/Makefile index 1f26ada..6f4c513 100644 --- a/arch/arm/mach-rmobile/Makefile +++ b/arch/arm/mach-rmobile/Makefile @@ -13,3 +13,9 @@ obj-$(CONFIG_SH73A0) += lowlevel_init.o cpu_info-sh73a0.o pfc-sh73a0.o obj-$(CONFIG_R8A7740) += lowlevel_init.o cpu_info-r8a7740.o pfc-r8a7740.o obj-$(CONFIG_RCAR_GEN2) += lowlevel_init_ca15.o cpu_info-rcar.o obj-$(CONFIG_RCAR_GEN3) += lowlevel_init_gen3.o cpu_info-rcar.o memmap-gen3.o + +ifndef CONFIG_SPL_BUILD +ifdef CONFIG_R8A7790 +obj-$(CONFIG_ARMV7_PSCI) += psci.o pm-r8a7790.o +endif +endif diff --git a/arch/arm/mach-rmobile/pm-r8a7790.c b/arch/arm/mach-rmobile/pm-r8a7790.c new file mode 100644 index 0000000..c635cf6 --- /dev/null +++ b/arch/arm/mach-rmobile/pm-r8a7790.c @@ -0,0 +1,408 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * CPU power management support for Renesas r8a7790 SoC + * + * Contains functions to control ARM Cortex A15/A7 cores and + * related peripherals basically used for PSCI. + * + * Copyright (C) 2018 EPAM Systems Inc. + * + * Mainly based on Renesas R-Car Gen2 platform code from Linux: + * arch/arm/mach-shmobile/... + */ + +#include <common.h> +#include <asm/secure.h> +#include <asm/io.h> + +#include "pm-r8a7790.h" + +/***************************************************************************** + * APMU definitions + *****************************************************************************/ +#define CA15_APMU_BASE 0xe6152000 +#define CA7_APMU_BASE 0xe6151000 + +/* Wake Up Control Register */ +#define WUPCR_OFFS 0x10 +/* Power Status Register */ +#define PSTR_OFFS 0x40 +/* CPUn Power Status Control Register */ +#define CPUNCR_OFFS(n) (0x100 + (0x10 * (n))) + +#define CPUPWR_STANDBY 0x3 + +/* Debug Resource Reset Control Register */ +#define DBGRCR_OFFS 0x180 + +#define DBGCPUREN BIT(24) /* CPU Other Reset Req Enable */ +#define DBGCPUNREN(n) BIT((n) + 20) /* CPUn Reset Req Enable */ +#define DBGCPUPREN BIT(19) /* CPU Peripheral Reset Req Enable */ + +/***************************************************************************** + * RST definitions + *****************************************************************************/ +#define RST_BASE 0xe6160000 + +/* Boot Address Registers */ +#define CA15BAR 0x20 +#define CA7BAR 0x30 + +/* Reset Control Registers */ +#define CA15RESCNT 0x40 +#define CA7RESCNT 0x44 + +#define CA15RESCNT_CODE 0xa5a50000 +#define CA7RESCNT_CODE 0x5a5a0000 + +/* SYS Boot Address Register */ +#define SBAR_BAREN BIT(4) /* SBAR is valid */ + +/* Watchdog Timer Reset Control Register */ +#define WDTRSTCR 0x54 + +#define WDTRSTCR_CODE 0xa55a0000 + +/***************************************************************************** + * SYSC definitions + *****************************************************************************/ +#define SYSC_BASE 0xe6180000 + +/* SYSC Status Register */ +#define SYSCSR 0x00 +/* Interrupt Status Register */ +#define SYSCISR 0x04 +/* Interrupt Status Clear Register */ +#define SYSCISCR 0x08 +/* Interrupt Enable Register */ +#define SYSCIER 0x0c +/* Interrupt Mask Register */ +#define SYSCIMR 0x10 + +/* Power Status Register */ +#define PWRSR_OFFS 0x00 +/* Power Resume Control Register */ +#define PWRONCR_OFFS 0x0c +/* Power Shutoff/Resume Error Register */ +#define PWRER_OFFS 0x14 + +/* PWRSR5 .. PWRER5 */ +#define CA15_SCU_CHAN_OFFS 0x180 +/* PWRSR3 .. PWRER3 */ +#define CA7_SCU_CHAN_OFFS 0x100 + +#define CA15_SCU_ISR_BIT 12 +#define CA7_SCU_ISR_BIT 21 + +#define SYSCSR_RETRIES 100 +#define SYSCSR_DELAY_US 1 + +#define PWRER_RETRIES 100 +#define PWRER_DELAY_US 1 + +#define SYSCISR_RETRIES 1000 +#define SYSCISR_DELAY_US 1 + +#define CA15_SCU 0 +#define CA7_SCU 1 + +/***************************************************************************** + * CCI-400 definitions + *****************************************************************************/ +#define CCI_BASE 0xf0090000 +#define CCI_SLAVE3 0x4000 +#define CCI_SLAVE4 0x5000 +#define CCI_SNOOP 0x0000 +#define CCI_STATUS 0x000c +#define CCI_ENABLE_REQ 0x0003 + +/***************************************************************************** + * RWDT definitions + *****************************************************************************/ +/* Watchdog Timer Counter Register */ +#define RWTCNT 0x0 +/* Watchdog Timer Control/Status Register A */ +#define RWTCSRA 0x4 + +#define RWTCNT_CODE 0x5a5a0000 +#define RWTCSRA_CODE 0xa5a5a500 + +#define RWTCSRA_WRFLG BIT(5) +#define RWTCSRA_TME BIT(7) + +/***************************************************************************** + * Other definitions + *****************************************************************************/ +/* On-chip RAM */ +#define ICRAM1 0xe63c0000 /* Inter Connect RAM1 (4 KiB) */ + +/* On-chip ROM */ +#define BOOTROM 0xe6340000 + +/***************************************************************************** + * Functions which intended to be called from PSCI handlers. These functions + * marked as __secure and are placed in .secure section. + *****************************************************************************/ +void __secure r8a7790_apmu_power_on(int cpu) +{ + int cluster = r8a7790_cluster_id(cpu); + u32 apmu_base; + + apmu_base = cluster == 0 ? CA15_APMU_BASE : CA7_APMU_BASE; + + /* Request power on */ + writel(BIT(r8a7790_core_id(cpu)), apmu_base + WUPCR_OFFS); + + /* Wait for APMU to finish */ + while (readl(apmu_base + WUPCR_OFFS)) + ; +} + +void __secure r8a7790_apmu_power_off(int cpu) +{ + int cluster = r8a7790_cluster_id(cpu); + u32 apmu_base; + + apmu_base = cluster == 0 ? CA15_APMU_BASE : CA7_APMU_BASE; + + /* Request Core Standby for next WFI */ + writel(CPUPWR_STANDBY, apmu_base + CPUNCR_OFFS(r8a7790_core_id(cpu))); +} + +void __secure r8a7790_assert_reset(int cpu) +{ + int cluster = r8a7790_cluster_id(cpu); + u32 mask, magic, rescnt; + + mask = BIT(3 - r8a7790_core_id(cpu)); + magic = cluster == 0 ? CA15RESCNT_CODE : CA7RESCNT_CODE; + rescnt = RST_BASE + (cluster == 0 ? CA15RESCNT : CA7RESCNT); + writel((readl(rescnt) | mask) | magic, rescnt); +} + +void __secure r8a7790_deassert_reset(int cpu) +{ + int cluster = r8a7790_cluster_id(cpu); + u32 mask, magic, rescnt; + + mask = BIT(3 - r8a7790_core_id(cpu)); + magic = cluster == 0 ? CA15RESCNT_CODE : CA7RESCNT_CODE; + rescnt = RST_BASE + (cluster == 0 ? CA15RESCNT : CA7RESCNT); + writel((readl(rescnt) & ~mask) | magic, rescnt); +} + +void __secure r8a7790_system_reset(void) +{ + u32 bar; + + /* + * Before configuring internal watchdog timer (RWDT) to reboot system + * we need to re-program BAR registers for the boot CPU to jump to + * bootrom code. Without taking care of, the boot CPU will jump to + * the reset vector previously installed in ICRAM1, since BAR registers + * keep their values after watchdog triggered reset. + */ + bar = (BOOTROM >> 8) & 0xfffffc00; + writel(bar, RST_BASE + CA15BAR); + writel(bar | SBAR_BAREN, RST_BASE + CA15BAR); + writel(bar, RST_BASE + CA7BAR); + writel(bar | SBAR_BAREN, RST_BASE + CA7BAR); + dsb(); + + /* Now, configure watchdog timer to reboot the system */ + + /* Trigger reset when counter overflows */ + writel(WDTRSTCR_CODE | 0x2, RST_BASE + WDTRSTCR); + dsb(); + + /* Stop counter */ + writel(RWTCSRA_CODE, RWDT_BASE + RWTCSRA); + + /* Initialize counter with the highest value */ + writel(RWTCNT_CODE | 0xffff, RWDT_BASE + RWTCNT); + + while (readb(RWDT_BASE + RWTCSRA) & RWTCSRA_WRFLG) + ; + + /* Start counter */ + writel(RWTCSRA_CODE | RWTCSRA_TME, RWDT_BASE + RWTCSRA); +} + +/***************************************************************************** + * Functions which intended to be called from PSCI board initialization. + *****************************************************************************/ +static int sysc_power_up(int scu) +{ + u32 status, chan_offs, isr_bit; + int i, j, ret = 0; + + if (scu == CA15_SCU) { + chan_offs = CA15_SCU_CHAN_OFFS; + isr_bit = CA15_SCU_ISR_BIT; + } else { + chan_offs = CA7_SCU_CHAN_OFFS; + isr_bit = CA7_SCU_ISR_BIT; + } + + writel(BIT(isr_bit), SYSC_BASE + SYSCISCR); + + /* Submit power resume request until it was accepted */ + for (i = 0; i < PWRER_RETRIES; i++) { + /* Wait until SYSC is ready to accept a power resume request */ + for (j = 0; j < SYSCSR_RETRIES; j++) { + if (readl(SYSC_BASE + SYSCSR) & BIT(1)) + break; + + udelay(SYSCSR_DELAY_US); + } + + if (j == SYSCSR_RETRIES) + return -EAGAIN; + + /* Submit power resume request */ + writel(BIT(0), SYSC_BASE + chan_offs + PWRONCR_OFFS); + + /* Check if power resume request was accepted */ + status = readl(SYSC_BASE + chan_offs + PWRER_OFFS); + if (!(status & BIT(0))) + break; + + udelay(PWRER_DELAY_US); + } + + if (i == PWRER_RETRIES) + return -EIO; + + /* Wait until the power resume request has completed */ + for (i = 0; i < SYSCISR_RETRIES; i++) { + if (readl(SYSC_BASE + SYSCISR) & BIT(isr_bit)) + break; + udelay(SYSCISR_DELAY_US); + } + + if (i == SYSCISR_RETRIES) + ret = -EIO; + + writel(BIT(isr_bit), SYSC_BASE + SYSCISCR); + + return ret; +} + +static bool sysc_power_is_off(int scu) +{ + u32 status, chan_offs; + + chan_offs = scu == CA15_SCU ? CA15_SCU_CHAN_OFFS : CA7_SCU_CHAN_OFFS; + + /* Check if SCU is in power shutoff state */ + status = readl(SYSC_BASE + chan_offs + PWRSR_OFFS); + if (status & BIT(0)) + return true; + + return false; +} + +static void apmu_setup_debug_mode(int cpu) +{ + int cluster = r8a7790_cluster_id(cpu); + u32 apmu_base, reg; + + apmu_base = cluster == 0 ? CA15_APMU_BASE : CA7_APMU_BASE; + + /* + * Enable reset requests derived from power shutoff to the AP-system + * CPU cores in debug mode. Without taking care of, they may fail to + * resume from the power shutoff state. + */ + reg = readl(apmu_base + DBGRCR_OFFS); + reg |= DBGCPUREN | DBGCPUNREN(r8a7790_core_id(cpu)) | DBGCPUPREN; + writel(reg, apmu_base + DBGRCR_OFFS); +} + +/* + * Reset vector for secondary CPUs. + * This will be mapped at address 0 by SBAR register. + * We need _long_ jump to the physical address. + */ +asm(" .arm\n" + " .align 12\n" + " .globl shmobile_boot_vector\n" + "shmobile_boot_vector:\n" + " ldr r1, 1f\n" + " bx r1\n" + " .type shmobile_boot_vector, %function\n" + " .size shmobile_boot_vector, .-shmobile_boot_vector\n" + " .align 2\n" + " .globl shmobile_boot_fn\n" + "shmobile_boot_fn:\n" + "1: .space 4\n" + " .globl shmobile_boot_size\n" + "shmobile_boot_size:\n" + " .long .-shmobile_boot_vector\n"); + +extern void shmobile_boot_vector(void); +extern unsigned long shmobile_boot_fn; +extern unsigned long shmobile_boot_size; + +void r8a7790_prepare_cpus(unsigned long addr, u32 nr_cpus) +{ + int cpu = get_current_cpu(); + int i, ret = 0; + u32 bar; + + shmobile_boot_fn = addr; + dsb(); + + /* Install reset vector */ + memcpy_toio((void __iomem *)ICRAM1, shmobile_boot_vector, + shmobile_boot_size); + dmb(); + + /* Setup reset vectors */ + bar = (ICRAM1 >> 8) & 0xfffffc00; + writel(bar, RST_BASE + CA15BAR); + writel(bar | SBAR_BAREN, RST_BASE + CA15BAR); + writel(bar, RST_BASE + CA7BAR); + writel(bar | SBAR_BAREN, RST_BASE + CA7BAR); + dsb(); + + /* Perform setup for debug mode for all CPUs */ + for (i = 0; i < nr_cpus; i++) + apmu_setup_debug_mode(i); + + /* + * Indicate the completion status of power shutoff/resume procedure + * for CA15/CA7 SCU. + */ + writel(BIT(CA15_SCU_ISR_BIT) | BIT(CA7_SCU_ISR_BIT), + SYSC_BASE + SYSCIER); + + /* Power on CA15/CA7 SCU */ + if (sysc_power_is_off(CA15_SCU)) + ret += sysc_power_up(CA15_SCU); + if (sysc_power_is_off(CA7_SCU)) + ret += sysc_power_up(CA7_SCU); + if (ret) + printf("warning: some of secondary CPUs may not boot\n"); + + /* Keep secondary CPUs in reset */ + for (i = 0; i < nr_cpus; i++) { + /* Make sure that we don't reset boot CPU */ + if (i == cpu) + continue; + + r8a7790_assert_reset(i); + } + + /* + * Enable snoop requests and DVM message requests for slave interfaces + * S4 (CA7) and S3 (CA15). + */ + writel(readl(CCI_BASE + CCI_SLAVE3 + CCI_SNOOP) | CCI_ENABLE_REQ, + CCI_BASE + CCI_SLAVE3 + CCI_SNOOP); + writel(readl(CCI_BASE + CCI_SLAVE4 + CCI_SNOOP) | CCI_ENABLE_REQ, + CCI_BASE + CCI_SLAVE4 + CCI_SNOOP); + /* Wait for pending bit low */ + while (readl(CCI_BASE + CCI_STATUS)) + ; +} diff --git a/arch/arm/mach-rmobile/pm-r8a7790.h b/arch/arm/mach-rmobile/pm-r8a7790.h new file mode 100644 index 0000000..f649dd8 --- /dev/null +++ b/arch/arm/mach-rmobile/pm-r8a7790.h @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2018 EPAM Systems Inc. + */ + +#ifndef __PM_R8A7790_H__ +#define __PM_R8A7790_H__ + +#include <linux/types.h> + +void r8a7790_apmu_power_on(int cpu); +void r8a7790_apmu_power_off(int cpu); +void r8a7790_assert_reset(int cpu); +void r8a7790_deassert_reset(int cpu); + +void r8a7790_prepare_cpus(unsigned long addr, u32 nr_cpus); +void r8a7790_system_reset(void); + +#define R8A7790_NR_CLUSTERS 2 +#define R8A7790_NR_CPUS_PER_CLUSTER 4 + +/* Convert linear CPU index to core/cluster ID */ +#define r8a7790_cluster_id(cpu) ((cpu) / R8A7790_NR_CPUS_PER_CLUSTER) +#define r8a7790_core_id(cpu) ((cpu) % R8A7790_NR_CPUS_PER_CLUSTER) + +#define MPIDR_AFFLVL_MASK GENMASK(7, 0) +#define MPIDR_AFF0_SHIFT 0 +#define MPIDR_AFF1_SHIFT 8 + +/* All functions are inline so that they can be called from .secure section. */ + +/* + * Convert CPU ID in MPIDR format to linear CPU index. + * + * Below the possible CPU IDs and corresponding CPU indexes: + * CPU ID CPU index + * 0x80000000 - 0x00000000 + * 0x80000001 - 0x00000001 + * 0x80000002 - 0x00000002 + * 0x80000003 - 0x00000003 + * 0x80000100 - 0x00000004 + * 0x80000101 - 0x00000005 + * 0x80000102 - 0x00000006 + * 0x80000103 - 0x00000007 + */ +static inline int mpidr_to_cpu_index(u32 mpidr) +{ + u32 cluster_id, cpu_id; + + cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK; + cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK; + + if (cluster_id >= R8A7790_NR_CLUSTERS) + return -1; + + if (cpu_id >= R8A7790_NR_CPUS_PER_CLUSTER) + return -1; + + return (cpu_id + (cluster_id * R8A7790_NR_CPUS_PER_CLUSTER)); +} + +/* Return an index of the CPU which performs this call */ +static inline int get_current_cpu(void) +{ + u32 mpidr; + + asm volatile("mrc p15, 0, %0, c0, c0, 5" : "=r"(mpidr)); + + return mpidr_to_cpu_index(mpidr); +} + +#endif /* __PM_R8A7790_H__ */ diff --git a/arch/arm/mach-rmobile/psci.c b/arch/arm/mach-rmobile/psci.c new file mode 100644 index 0000000..95850b8 --- /dev/null +++ b/arch/arm/mach-rmobile/psci.c @@ -0,0 +1,193 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * This file implements basic PSCI support for Renesas r8a7790 SoC + * + * Copyright (C) 2018 EPAM Systems Inc. + * + * Based on arch/arm/mach-uniphier/arm32/psci.c + */ + +#include <common.h> +#include <linux/psci.h> +#include <asm/io.h> +#include <asm/psci.h> +#include <asm/secure.h> + +#include "pm-r8a7790.h" + +#define R8A7790_PSCI_NR_CPUS 8 +#if R8A7790_PSCI_NR_CPUS > CONFIG_ARMV7_PSCI_NR_CPUS +#error "invalid value for CONFIG_ARMV7_PSCI_NR_CPUS" +#endif + +#define GICC_CTLR_OFFSET 0x2000 + +/* + * The boot CPU is powered on by default, but it's index is not a const + * value. An index the boot CPU has, depends on whether it is CA15 (index 0) + * or CA7 (index 4). + * So, we update state for the boot CPU during PSCI board initialization. + */ +u8 psci_state[R8A7790_PSCI_NR_CPUS] __secure_data = { + PSCI_AFFINITY_LEVEL_OFF, + PSCI_AFFINITY_LEVEL_OFF, + PSCI_AFFINITY_LEVEL_OFF, + PSCI_AFFINITY_LEVEL_OFF, + PSCI_AFFINITY_LEVEL_OFF, + PSCI_AFFINITY_LEVEL_OFF, + PSCI_AFFINITY_LEVEL_OFF, + PSCI_AFFINITY_LEVEL_OFF}; + +void __secure psci_set_state(int cpu, u8 state) +{ + psci_state[cpu] = state; + dsb(); + isb(); +} + +u32 __secure psci_get_cpu_id(void) +{ + return get_current_cpu(); +} + +void __secure psci_arch_cpu_entry(void) +{ + int cpu = get_current_cpu(); + + psci_set_state(cpu, PSCI_AFFINITY_LEVEL_ON); +} + +int __secure psci_features(u32 function_id, u32 psci_fid) +{ + switch (psci_fid) { + case ARM_PSCI_0_2_FN_PSCI_VERSION: + 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_MIGRATE_INFO_TYPE: + case ARM_PSCI_0_2_FN_SYSTEM_OFF: + case ARM_PSCI_0_2_FN_SYSTEM_RESET: + return 0x0; + } + + return ARM_PSCI_RET_NI; +} + +u32 __secure psci_version(u32 function_id) +{ + return ARM_PSCI_VER_1_0; +} + +int __secure psci_affinity_info(u32 function_id, u32 target_affinity, + u32 lowest_affinity_level) +{ + int cpu; + + if (lowest_affinity_level > 0) + return ARM_PSCI_RET_INVAL; + + cpu = mpidr_to_cpu_index(target_affinity); + if (cpu == -1) + return ARM_PSCI_RET_INVAL; + + /* TODO flush cache */ + return psci_state[cpu]; +} + +int __secure psci_migrate_info_type(u32 function_id) +{ + /* Trusted OS is either not present or does not require migration */ + return 2; +} + +int __secure psci_cpu_on(u32 function_id, u32 target_cpu, u32 entry_point, + u32 context_id) +{ + int cpu; + + cpu = mpidr_to_cpu_index(target_cpu); + if (cpu == -1) + return ARM_PSCI_RET_INVAL; + + if (psci_state[cpu] == PSCI_AFFINITY_LEVEL_ON) + return ARM_PSCI_RET_ALREADY_ON; + + if (psci_state[cpu] == PSCI_AFFINITY_LEVEL_ON_PENDING) + return ARM_PSCI_RET_ON_PENDING; + + psci_save(cpu, entry_point, context_id); + + psci_set_state(cpu, PSCI_AFFINITY_LEVEL_ON_PENDING); + + r8a7790_assert_reset(cpu); + r8a7790_apmu_power_on(cpu); + r8a7790_deassert_reset(cpu); + + return ARM_PSCI_RET_SUCCESS; +} + +int __secure psci_cpu_off(void) +{ + int cpu = get_current_cpu(); + + /* + * Place the CPU interface in a state where it can never make a CPU + * exit WFI as result of an asserted interrupt. + */ + writel(0, CONFIG_ARM_GIC_BASE_ADDRESS + GICC_CTLR_OFFSET); + dsb(); + + /* Select next sleep mode using the APMU */ + r8a7790_apmu_power_off(cpu); + + /* Do ARM specific CPU shutdown */ + psci_cpu_off_common(); + + psci_set_state(cpu, PSCI_AFFINITY_LEVEL_OFF); + + /* Drain the WB before WFI */ + dsb(); + + while (1) + wfi(); +} + +void __secure psci_system_reset(u32 function_id) +{ + r8a7790_system_reset(); + + /* Drain the WB before WFI */ + dsb(); + + /* The system is about to be rebooted, so just waiting for this */ + while (1) + wfi(); +} + +void __secure psci_system_off(u32 function_id) +{ + /* Drain the WB before WFI */ + dsb(); + + /* + * System Off is not implemented yet, so waiting for powering off + * manually + */ + while (1) + wfi(); +} + +void psci_board_init(void) +{ + int cpu = get_current_cpu(); + + /* Update state for the boot CPU */ + psci_set_state(cpu, PSCI_AFFINITY_LEVEL_ON); + + /* + * Perform needed actions for the secondary CPUs to be ready + * for powering on + */ + r8a7790_prepare_cpus((unsigned long)psci_cpu_entry, + R8A7790_PSCI_NR_CPUS); +} diff --git a/include/configs/lager.h b/include/configs/lager.h index d8a0b01..d70c147 100644 --- a/include/configs/lager.h +++ b/include/configs/lager.h @@ -51,4 +51,6 @@ /* The PERIPHBASE in the CBAR register is wrong, so override it */ #define CONFIG_ARM_GIC_BASE_ADDRESS 0xf1000000
+#define CONFIG_ARMV7_PSCI_1_0 + #endif /* __LAGER_H */ diff --git a/include/configs/stout.h b/include/configs/stout.h index 7edb9d7..0b20075 100644 --- a/include/configs/stout.h +++ b/include/configs/stout.h @@ -59,4 +59,6 @@ /* The PERIPHBASE in the CBAR register is wrong, so override it */ #define CONFIG_ARM_GIC_BASE_ADDRESS 0xf1000000
+#define CONFIG_ARMV7_PSCI_1_0 + #endif /* __STOUT_H */