From: Oleksandr Tyshchenko <oleksandr_tyshche...@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_tyshche...@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 */
-- 
2.7.4

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
https://lists.denx.de/listinfo/u-boot

Reply via email to