* Add PSCI support
@ 2017-02-07 8:43 Sascha Hauer
2017-02-07 8:43 ` [PATCH 1/4] ARM: Add UNWIND macro Sascha Hauer
` (3 more replies)
0 siblings, 4 replies; 8+ messages in thread
From: Sascha Hauer @ 2017-02-07 8:43 UTC (permalink / raw)
To: Barebox List
This series implements the ARM "Power State Coordination Interface"
(PSCI). This is needed to enable SMP on some SoCs like the i.MX7 with
a mainline Kernel. Currently only the bare minimum is supported, just
enough to enable and disable the secondary CPU.
----------------------------------------------------------------
Sascha Hauer (4):
ARM: Add UNWIND macro
ARM: Add smc call support
ARM: Add PSCI support
ARM: i.MX7: Add PSCI support
arch/arm/Kconfig | 23 +++
arch/arm/cpu/Makefile | 3 +
arch/arm/cpu/psci.c | 311 +++++++++++++++++++++++++++++++++++++++
arch/arm/cpu/sm.c | 266 +++++++++++++++++++++++++++++++++
arch/arm/cpu/sm_as.S | 168 +++++++++++++++++++++
arch/arm/cpu/smccc-call.S | 64 ++++++++
arch/arm/include/asm/arm-smccc.h | 104 +++++++++++++
arch/arm/include/asm/armlinux.h | 4 +-
arch/arm/include/asm/gic.h | 110 ++++++++++++++
arch/arm/include/asm/psci.h | 140 ++++++++++++++++++
arch/arm/include/asm/ptrace.h | 1 +
arch/arm/include/asm/secure.h | 39 +++++
arch/arm/include/asm/unwind.h | 6 +
arch/arm/lib/bootm.c | 14 +-
arch/arm/lib32/armlinux.c | 15 +-
arch/arm/lib32/barebox.lds.S | 10 ++
arch/arm/mach-imx/imx7.c | 77 ++++++++++
17 files changed, 1352 insertions(+), 3 deletions(-)
create mode 100644 arch/arm/cpu/psci.c
create mode 100644 arch/arm/cpu/sm.c
create mode 100644 arch/arm/cpu/sm_as.S
create mode 100644 arch/arm/cpu/smccc-call.S
create mode 100644 arch/arm/include/asm/arm-smccc.h
create mode 100644 arch/arm/include/asm/gic.h
create mode 100644 arch/arm/include/asm/psci.h
create mode 100644 arch/arm/include/asm/secure.h
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 1/4] ARM: Add UNWIND macro
2017-02-07 8:43 Add PSCI support Sascha Hauer
@ 2017-02-07 8:43 ` Sascha Hauer
2017-02-07 8:43 ` [PATCH 2/4] ARM: Add smc call support Sascha Hauer
` (2 subsequent siblings)
3 siblings, 0 replies; 8+ messages in thread
From: Sascha Hauer @ 2017-02-07 8:43 UTC (permalink / raw)
To: Barebox List
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
arch/arm/include/asm/unwind.h | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/arch/arm/include/asm/unwind.h b/arch/arm/include/asm/unwind.h
index 311ad3d66..a6f3a9174 100644
--- a/arch/arm/include/asm/unwind.h
+++ b/arch/arm/include/asm/unwind.h
@@ -48,4 +48,10 @@ extern void unwind_backtrace(struct pt_regs *regs);
#endif /* !__ASSEMBLY__ */
+#ifdef CONFIG_ARM_UNWIND
+#define UNWIND(code...) code
+#else
+#define UNWIND(code...)
+#endif
+
#endif /* __ASM_UNWIND_H */
--
2.11.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 2/4] ARM: Add smc call support
2017-02-07 8:43 Add PSCI support Sascha Hauer
2017-02-07 8:43 ` [PATCH 1/4] ARM: Add UNWIND macro Sascha Hauer
@ 2017-02-07 8:43 ` Sascha Hauer
2017-02-07 8:43 ` [PATCH 3/4] ARM: Add PSCI support Sascha Hauer
2017-02-07 8:43 ` [PATCH 4/4] ARM: i.MX7: " Sascha Hauer
3 siblings, 0 replies; 8+ messages in thread
From: Sascha Hauer @ 2017-02-07 8:43 UTC (permalink / raw)
To: Barebox List
Taken from the Kernel: A wrapper to make a smc call from C.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
arch/arm/cpu/Makefile | 2 +
arch/arm/cpu/smccc-call.S | 64 ++++++++++++++++++++++++
arch/arm/include/asm/arm-smccc.h | 104 +++++++++++++++++++++++++++++++++++++++
3 files changed, 170 insertions(+)
create mode 100644 arch/arm/cpu/smccc-call.S
create mode 100644 arch/arm/include/asm/arm-smccc.h
diff --git a/arch/arm/cpu/Makefile b/arch/arm/cpu/Makefile
index d8cb1871a..e542f1741 100644
--- a/arch/arm/cpu/Makefile
+++ b/arch/arm/cpu/Makefile
@@ -34,6 +34,8 @@ ifeq ($(CONFIG_MMU),)
obj-y += no-mmu.o
endif
+obj-$(CONFIG_ARM_SECURE_MONITOR) += smccc-call.o
+
obj-$(CONFIG_CPU_32v4T) += cache-armv4.o
pbl-$(CONFIG_CPU_32v4T) += cache-armv4.o
obj-$(CONFIG_CPU_32v5) += cache-armv5.o
diff --git a/arch/arm/cpu/smccc-call.S b/arch/arm/cpu/smccc-call.S
new file mode 100644
index 000000000..c2781b1ab
--- /dev/null
+++ b/arch/arm/cpu/smccc-call.S
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2015, Linaro Limited
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/linkage.h>
+
+#include <asm/unwind.h>
+
+ .arch_extension sec
+ .arch_extension virt
+ .arm
+
+ /*
+ * Wrap c macros in asm macros to delay expansion until after the
+ * SMCCC asm macro is expanded.
+ */
+ .macro SMCCC_SMC
+ smc #0
+ .endm
+
+ .macro SMCCC_HVC
+ hvc #0
+ .endm
+
+ .macro SMCCC instr
+UNWIND( .fnstart)
+ mov r12, sp
+ push {r4-r7}
+UNWIND( .save {r4-r7})
+ ldm r12, {r4-r7}
+ \instr
+ pop {r4-r7}
+ ldr r12, [sp, #(4 * 4)]
+ stm r12, {r0-r3}
+ bx lr
+UNWIND( .fnend)
+ .endm
+
+/*
+ * void smccc_smc(unsigned long a0, unsigned long a1, unsigned long a2,
+ * unsigned long a3, unsigned long a4, unsigned long a5,
+ * unsigned long a6, unsigned long a7, struct arm_smccc_res *res)
+ */
+ENTRY(arm_smccc_smc)
+ SMCCC SMCCC_SMC
+ENDPROC(arm_smccc_smc)
+
+/*
+ * void smccc_hvc(unsigned long a0, unsigned long a1, unsigned long a2,
+ * unsigned long a3, unsigned long a4, unsigned long a5,
+ * unsigned long a6, unsigned long a7, struct arm_smccc_res *res)
+ */
+ENTRY(arm_smccc_hvc)
+ SMCCC SMCCC_HVC
+ENDPROC(arm_smccc_hvc)
diff --git a/arch/arm/include/asm/arm-smccc.h b/arch/arm/include/asm/arm-smccc.h
new file mode 100644
index 000000000..b5abfda80
--- /dev/null
+++ b/arch/arm/include/asm/arm-smccc.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2015, Linaro Limited
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __LINUX_ARM_SMCCC_H
+#define __LINUX_ARM_SMCCC_H
+
+#include <linux/linkage.h>
+#include <linux/types.h>
+
+/*
+ * This file provides common defines for ARM SMC Calling Convention as
+ * specified in
+ * http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html
+ */
+
+#define ARM_SMCCC_STD_CALL 0
+#define ARM_SMCCC_FAST_CALL 1
+#define ARM_SMCCC_TYPE_SHIFT 31
+
+#define ARM_SMCCC_SMC_32 0
+#define ARM_SMCCC_SMC_64 1
+#define ARM_SMCCC_CALL_CONV_SHIFT 30
+
+#define ARM_SMCCC_OWNER_MASK 0x3F
+#define ARM_SMCCC_OWNER_SHIFT 24
+
+#define ARM_SMCCC_FUNC_MASK 0xFFFF
+
+#define ARM_SMCCC_IS_FAST_CALL(smc_val) \
+ ((smc_val) & (ARM_SMCCC_FAST_CALL << ARM_SMCCC_TYPE_SHIFT))
+#define ARM_SMCCC_IS_64(smc_val) \
+ ((smc_val) & (ARM_SMCCC_SMC_64 << ARM_SMCCC_CALL_CONV_SHIFT))
+#define ARM_SMCCC_FUNC_NUM(smc_val) ((smc_val) & ARM_SMCCC_FUNC_MASK)
+#define ARM_SMCCC_OWNER_NUM(smc_val) \
+ (((smc_val) >> ARM_SMCCC_OWNER_SHIFT) & ARM_SMCCC_OWNER_MASK)
+
+#define ARM_SMCCC_CALL_VAL(type, calling_convention, owner, func_num) \
+ (((type) << ARM_SMCCC_TYPE_SHIFT) | \
+ ((calling_convention) << ARM_SMCCC_CALL_CONV_SHIFT) | \
+ (((owner) & ARM_SMCCC_OWNER_MASK) << ARM_SMCCC_OWNER_SHIFT) | \
+ ((func_num) & ARM_SMCCC_FUNC_MASK))
+
+#define ARM_SMCCC_OWNER_ARCH 0
+#define ARM_SMCCC_OWNER_CPU 1
+#define ARM_SMCCC_OWNER_SIP 2
+#define ARM_SMCCC_OWNER_OEM 3
+#define ARM_SMCCC_OWNER_STANDARD 4
+#define ARM_SMCCC_OWNER_TRUSTED_APP 48
+#define ARM_SMCCC_OWNER_TRUSTED_APP_END 49
+#define ARM_SMCCC_OWNER_TRUSTED_OS 50
+#define ARM_SMCCC_OWNER_TRUSTED_OS_END 63
+
+/**
+ * struct arm_smccc_res - Result from SMC/HVC call
+ * @a0-a3 result values from registers 0 to 3
+ */
+struct arm_smccc_res {
+ unsigned long a0;
+ unsigned long a1;
+ unsigned long a2;
+ unsigned long a3;
+};
+
+/**
+ * arm_smccc_smc() - make SMC calls
+ * @a0-a7: arguments passed in registers 0 to 7
+ * @res: result values from registers 0 to 3
+ *
+ * This function is used to make SMC calls following SMC Calling Convention.
+ * The content of the supplied param are copied to registers 0 to 7 prior
+ * to the SMC instruction. The return values are updated with the content
+ * from register 0 to 3 on return from the SMC instruction.
+ */
+asmlinkage void arm_smccc_smc(unsigned long a0, unsigned long a1,
+ unsigned long a2, unsigned long a3, unsigned long a4,
+ unsigned long a5, unsigned long a6, unsigned long a7,
+ struct arm_smccc_res *res);
+
+/**
+ * arm_smccc_hvc() - make HVC calls
+ * @a0-a7: arguments passed in registers 0 to 7
+ * @res: result values from registers 0 to 3
+ *
+ * This function is used to make HVC calls following SMC Calling
+ * Convention. The content of the supplied param are copied to registers 0
+ * to 7 prior to the HVC instruction. The return values are updated with
+ * the content from register 0 to 3 on return from the HVC instruction.
+ */
+asmlinkage void arm_smccc_hvc(unsigned long a0, unsigned long a1,
+ unsigned long a2, unsigned long a3, unsigned long a4,
+ unsigned long a5, unsigned long a6, unsigned long a7,
+ struct arm_smccc_res *res);
+
+#endif /*__LINUX_ARM_SMCCC_H*/
--
2.11.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 3/4] ARM: Add PSCI support
2017-02-07 8:43 Add PSCI support Sascha Hauer
2017-02-07 8:43 ` [PATCH 1/4] ARM: Add UNWIND macro Sascha Hauer
2017-02-07 8:43 ` [PATCH 2/4] ARM: Add smc call support Sascha Hauer
@ 2017-02-07 8:43 ` Sascha Hauer
2017-02-07 8:43 ` [PATCH 4/4] ARM: i.MX7: " Sascha Hauer
3 siblings, 0 replies; 8+ messages in thread
From: Sascha Hauer @ 2017-02-07 8:43 UTC (permalink / raw)
To: Barebox List
This patch contains the barebox implementation for the ARM
"Power State Coordination Interface" (PSCI).
The interface is aimed at the generalization of code in the following
power management scenarios:
* Core idle management.
* Dynamic addition and removal of cores, and secondary core boot.
* big.LITTLE migration.
* System shutdown and reset.
In practice, all that's currently implemented is a way to enable the
secondary core one some SoCs.
With PSCI the Kernel is either started in nonsecure or in Hypervisor
mode and PSCI is used to apply power to the secondary cores.
The start mode is passed in the global.bootm.secure_state variable. This
enum can contain "secure" (Kernel is started in secure mode, means no
PSCI), "nonsecure" (Kernel is started in nonsecure mode, PSCI available)
or "hyp" (Kernel is started in hyp mode, meaning it can support
virtualization).
We currently only support putting the secure monitor code into SDRAM,
which means we always steal some amount of memory from the Kernel.
To keep things simple for now we simply keep the whole barebox binary in
memory
The PSCI support has been tested on i.MX7 only so far. The only
supported operations are CPU_ON and CPU_OFF.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
arch/arm/Kconfig | 23 ++++
arch/arm/cpu/Makefile | 1 +
arch/arm/cpu/psci.c | 298 ++++++++++++++++++++++++++++++++++++++++
arch/arm/cpu/sm.c | 266 +++++++++++++++++++++++++++++++++++
arch/arm/cpu/sm_as.S | 168 ++++++++++++++++++++++
arch/arm/include/asm/armlinux.h | 4 +-
arch/arm/include/asm/gic.h | 110 +++++++++++++++
arch/arm/include/asm/psci.h | 140 +++++++++++++++++++
arch/arm/include/asm/ptrace.h | 1 +
arch/arm/include/asm/secure.h | 39 ++++++
arch/arm/lib/bootm.c | 14 +-
arch/arm/lib32/armlinux.c | 15 +-
arch/arm/lib32/barebox.lds.S | 10 ++
arch/arm/mach-imx/imx7.c | 1 +
14 files changed, 1087 insertions(+), 3 deletions(-)
create mode 100644 arch/arm/cpu/psci.c
create mode 100644 arch/arm/cpu/sm.c
create mode 100644 arch/arm/cpu/sm_as.S
create mode 100644 arch/arm/include/asm/gic.h
create mode 100644 arch/arm/include/asm/psci.h
create mode 100644 arch/arm/include/asm/secure.h
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 3e8ccf766..e4663ea26 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -383,6 +383,29 @@ config ARM_SEMIHOSTING
the data on the host computer connected to the target via
debugging channel (JTAG, SWD). If unsure say N
+config ARM_SECURE_MONITOR
+ bool
+
+config ARM_PSCI
+ bool "enable Power State Coordination Interface (PSCI) support"
+ depends on CPU_V7
+ select ARM_SECURE_MONITOR
+ help
+ PSCI is used for controlling secondary CPU cores on some systems. Say
+ yes here if you have one of these.
+
+config ARM_PSCI_DEBUG
+ bool "Enable PSCI debugging"
+ depends on ARM_PSCI
+ help
+ This enables debug output from the PSCI functions during runtime of the
+ Kernel. This needs board specific help, the board needs to provide a putc
+ function using psci_set_putc(). This putc function will then be called
+ during runtime of the Kernel, so it must be able to cope with that. It may
+ happen for example that the Kernel has turned off some clocks needed in the
+ putc function.
+ Only use for debugging.
+
endmenu
source common/Kconfig
diff --git a/arch/arm/cpu/Makefile b/arch/arm/cpu/Makefile
index e542f1741..6e4043915 100644
--- a/arch/arm/cpu/Makefile
+++ b/arch/arm/cpu/Makefile
@@ -35,6 +35,7 @@ obj-y += no-mmu.o
endif
obj-$(CONFIG_ARM_SECURE_MONITOR) += smccc-call.o
+obj-$(CONFIG_ARM_SECURE_MONITOR) += sm.o sm_as.o
obj-$(CONFIG_CPU_32v4T) += cache-armv4.o
pbl-$(CONFIG_CPU_32v4T) += cache-armv4.o
diff --git a/arch/arm/cpu/psci.c b/arch/arm/cpu/psci.c
new file mode 100644
index 000000000..745b8495e
--- /dev/null
+++ b/arch/arm/cpu/psci.c
@@ -0,0 +1,298 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "psci: " fmt
+
+#include <common.h>
+#include <asm/psci.h>
+#include <asm/arm-smccc.h>
+#include <asm/secure.h>
+#include <asm/system.h>
+#include <restart.h>
+#include <globalvar.h>
+#include <init.h>
+#include <magicvar.h>
+
+#ifdef CONFIG_ARM_PSCI_DEBUG
+static void (*__putc)(void *ctx, int c);
+static void *putc_ctx;
+
+void psci_set_putc(void (*putcf)(void *ctx, int c), void *ctx)
+{
+ __putc = putcf;
+ putc_ctx = ctx;
+}
+
+void psci_putc(char c)
+{
+ if (__putc)
+ __putc(putc_ctx, c);
+}
+
+int psci_puts(const char *str)
+{
+ int n = 0;
+
+ while (*str) {
+ if (*str == '\n')
+ psci_putc('\r');
+
+ psci_putc(*str);
+ str++;
+ n++;
+ }
+
+ return n;
+}
+
+int psci_printf(const char *fmt, ...)
+{
+ va_list args;
+ uint i;
+ char printbuffer[128];
+
+ va_start(args, fmt);
+ i = vsprintf(printbuffer, fmt, args);
+ va_end(args);
+
+ psci_puts(printbuffer);
+
+ return i;
+}
+#endif
+
+static struct psci_ops *psci_ops;
+
+void psci_set_ops(struct psci_ops *ops)
+{
+ psci_ops = ops;
+}
+
+static unsigned long psci_version(void)
+{
+ psci_printf("%s\n", __func__);
+ return ARM_PSCI_VER_1_0;
+}
+
+static unsigned long psci_cpu_suspend(u32 power_state, unsigned long entry,
+ u32 context_id)
+{
+ psci_printf("%s\n", __func__);
+
+ if (psci_ops->cpu_off)
+ return psci_ops->cpu_suspend(power_state, entry, context_id);
+
+ return ARM_PSCI_RET_NOT_SUPPORTED;
+}
+
+static unsigned long psci_cpu_off(void)
+{
+ psci_printf("%s\n", __func__);
+
+ if (psci_ops->cpu_off)
+ return psci_ops->cpu_off();
+
+ return ARM_PSCI_RET_NOT_SUPPORTED;
+}
+
+static unsigned long cpu_entry[ARM_SECURE_MAX_CPU];
+static unsigned long context[ARM_SECURE_MAX_CPU];
+
+static unsigned long psci_cpu_on(u32 cpu_id, unsigned long entry, u32 context_id)
+{
+ psci_printf("%s: %d 0x%08lx\n", __func__, cpu_id, entry);
+
+ if (cpu_id >= ARM_SECURE_MAX_CPU)
+ return ARM_PSCI_RET_INVAL;
+
+ cpu_entry[cpu_id] = entry;
+ context[cpu_id] = context_id;
+ dsb();
+
+ if (psci_ops->cpu_on)
+ return psci_ops->cpu_on(cpu_id);
+
+ return ARM_PSCI_RET_NOT_SUPPORTED;
+}
+
+static unsigned long psci_system_off(void)
+{
+ psci_printf("%s\n", __func__);
+
+ if (psci_ops->system_reset)
+ psci_ops->system_reset();
+
+ while(1);
+
+ return 0;
+}
+
+static unsigned long psci_system_reset(void)
+{
+ psci_printf("%s\n", __func__);
+
+ if (psci_ops->system_reset)
+ psci_ops->system_reset();
+
+ restart_machine();
+}
+
+void psci_entry(u32 r0, u32 r1, u32 r2, u32 r3, u32 r4, u32 r5, u32 r6,
+ struct arm_smccc_res *res)
+{
+ int mmuon;
+ unsigned long ttb;
+
+ mmuon = get_cr() & CR_M;
+ asm volatile ("mrc p15, 0, %0, c2, c0, 0" : "=r"(ttb));
+
+ psci_printf("%s entry, function: 0x%08x\n", __func__, r0);
+
+ switch (r0) {
+ case ARM_PSCI_0_2_FN_PSCI_VERSION:
+ res->a0 = psci_version();
+ break;
+ case ARM_PSCI_0_2_FN_CPU_SUSPEND:
+ res->a0 = psci_cpu_suspend(r1, r2, r3);
+ break;
+ case ARM_PSCI_0_2_FN_CPU_OFF:
+ res->a0 = psci_cpu_off();
+ break;
+ case ARM_PSCI_0_2_FN_CPU_ON:
+ res->a0 = psci_cpu_on(r1, r2, r3);
+ break;
+ case ARM_PSCI_0_2_FN_SYSTEM_OFF:
+ psci_system_off();
+ break;
+ case ARM_PSCI_0_2_FN_SYSTEM_RESET:
+ psci_system_reset();
+ break;
+ default:
+ res->a0 = ARM_PSCI_RET_NOT_SUPPORTED;
+ break;
+ }
+}
+
+static int of_psci_fixup(struct device_node *root, void *unused)
+{
+ struct device_node *psci;
+ int ret;
+
+ if (bootm_arm_security_state() < ARM_STATE_NONSECURE)
+ return 0;
+
+ psci = of_create_node(root, "/psci");
+ if (!psci)
+ return -EINVAL;
+
+ ret = of_set_property(psci, "compatible", "arm,psci-1.0",
+ strlen("arm,psci-1.0") + 1, 1);
+ if (ret)
+ return ret;
+
+ ret = of_set_property(psci, "method", "smc",
+ strlen("smc") + 1, 1);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+int psci_cpu_entry_c(void)
+{
+ void (*entry)(u32 context);
+ int cpu;
+ u32 context_id;
+
+ __armv7_secure_monitor_install();
+ cpu = psci_get_cpu_id();
+ entry = (void *)cpu_entry[cpu];
+ context_id = context[cpu];
+
+ if (bootm_arm_security_state() == ARM_STATE_HYP)
+ armv7_switch_to_hyp();
+
+ entry(context_id);
+
+ while (1);
+}
+
+static int armv7_psci_init(void)
+{
+ return of_register_fixup(of_psci_fixup, NULL);
+}
+device_initcall(armv7_psci_init);
+
+#ifdef DEBUG
+
+#include <command.h>
+#include <getopt.h>
+#include "mmu.h"
+
+void second_entry(void)
+{
+ struct arm_smccc_res res;
+
+ psci_printf("2nd CPU online, now turn off again\n");
+
+ arm_smccc_smc(ARM_PSCI_0_2_FN_CPU_OFF,
+ 0, 0, 0, 0, 0, 0, 0, &res);
+
+ psci_printf("2nd CPU still alive?\n");
+
+ while (1);
+}
+
+static int do_smc(int argc, char *argv[])
+{
+ int opt;
+ struct arm_smccc_res res = {
+ .a0 = 0xdeadbee0,
+ .a1 = 0xdeadbee1,
+ .a2 = 0xdeadbee2,
+ .a3 = 0xdeadbee3,
+ };
+
+ while ((opt = getopt(argc, argv, "nicz")) > 0) {
+ switch (opt) {
+ case 'n':
+ armv7_secure_monitor_install();
+ break;
+ case 'i':
+ arm_smccc_smc(ARM_PSCI_0_2_FN_PSCI_VERSION,
+ 0, 0, 0, 0, 0, 0, 0, &res);
+ printf("found psci version %ld.%ld\n", res.a0 >> 16, res.a0 & 0xffff);
+ break;
+ case 'c':
+ arm_smccc_smc(ARM_PSCI_0_2_FN_CPU_ON,
+ 1, (unsigned long)second_entry, 0, 0, 0, 0, 0, &res);
+ break;
+ }
+ }
+
+
+ return 0;
+}
+BAREBOX_CMD_HELP_START(smc)
+BAREBOX_CMD_HELP_TEXT("Secure monitor code test command")
+BAREBOX_CMD_HELP_TEXT("")
+BAREBOX_CMD_HELP_TEXT("Options:")
+BAREBOX_CMD_HELP_OPT ("-n", "Install secure monitor and switch to nonsecure mode")
+BAREBOX_CMD_HELP_OPT ("-i", "Show information about installed PSCI version")
+BAREBOX_CMD_HELP_OPT ("-c", "Start secondary CPU core")
+BAREBOX_CMD_HELP_OPT ("-z", "Turn off secondary CPU core")
+BAREBOX_CMD_HELP_END
+
+BAREBOX_CMD_START(smc)
+ .cmd = do_smc,
+ BAREBOX_CMD_DESC("secure monitor test command")
+BAREBOX_CMD_END
+#endif
\ No newline at end of file
diff --git a/arch/arm/cpu/sm.c b/arch/arm/cpu/sm.c
new file mode 100644
index 000000000..5808dfd92
--- /dev/null
+++ b/arch/arm/cpu/sm.c
@@ -0,0 +1,266 @@
+/*
+ * (C) Copyright 2013
+ * Andre Przywara, Linaro <andre.przywara@linaro.org>
+ *
+ * Routines to transition ARMv7 processors from secure into non-secure state
+ * and from non-secure SVC into HYP mode
+ * needed to enable ARMv7 virtualization for current hypervisors
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#define pr_fmt(fmt) "secure: " fmt
+
+#include <common.h>
+#include <io.h>
+#include <asm/gic.h>
+#include <asm/system.h>
+#include <init.h>
+#include <globalvar.h>
+#include <asm/arm-smccc.h>
+#include <asm-generic/sections.h>
+#include <asm/secure.h>
+
+#include "mmu.h"
+
+/* valid bits in CBAR register / PERIPHBASE value */
+#define CBAR_MASK 0xFFFF8000
+
+static unsigned int read_id_pfr1(void)
+{
+ unsigned int reg;
+
+ asm("mrc p15, 0, %0, c0, c1, 1\n" : "=r"(reg));
+ return reg;
+}
+
+static u32 read_nsacr(void)
+{
+ unsigned int reg;
+
+ asm("mrc p15, 0, %0, c1, c1, 2\n" : "=r"(reg));
+ return reg;
+}
+
+static void write_nsacr(u32 val)
+{
+ asm("mcr p15, 0, %0, c1, c1, 2" : : "r"(val));
+}
+
+static void write_mvbar(u32 val)
+{
+ asm("mcr p15, 0, %0, c12, c0, 1" : : "r"(val));
+}
+
+static unsigned long get_cbar(void)
+{
+ unsigned periphbase;
+
+ /* get the GIC base address from the CBAR register */
+ asm("mrc p15, 4, %0, c15, c0, 0\n" : "=r" (periphbase));
+
+ /* the PERIPHBASE can be mapped above 4 GB (lower 8 bits used to
+ * encode this). Bail out here since we cannot access this without
+ * enabling paging.
+ */
+ if ((periphbase & 0xff) != 0) {
+ pr_err("PERIPHBASE is above 4 GB, no access.\n");
+ return -1;
+ }
+
+ return periphbase & CBAR_MASK;
+}
+
+static unsigned long get_gicd_base_address(void)
+{
+ return get_cbar() + GIC_DIST_OFFSET;
+}
+
+static int cpu_is_virt_capable(void)
+{
+ return read_id_pfr1() & (1 << 12);
+}
+
+static unsigned long get_gicc_base_address(void)
+{
+ unsigned long adr = get_cbar();
+
+ if (cpu_is_virt_capable())
+ adr += GIC_CPU_OFFSET_A15;
+ else
+ adr += GIC_CPU_OFFSET_A9;
+
+ return adr;
+}
+
+#define GICD_IGROUPRn 0x0080
+
+int armv7_init_nonsec(void)
+{
+ void __iomem *gicd = IOMEM(get_gicd_base_address());
+ unsigned itlinesnr, i;
+ u32 val;
+
+ /*
+ * the SCR register will be set directly in the monitor mode handler,
+ * according to the spec one should not tinker with it in secure state
+ * in SVC mode. Do not try to read it once in non-secure state,
+ * any access to it will trap.
+ */
+
+ /* enable the GIC distributor */
+ val = readl(gicd + GICD_CTLR);
+ val |= 0x3;
+ writel(val, gicd + GICD_CTLR);
+
+ /* TYPER[4:0] contains an encoded number of available interrupts */
+ itlinesnr = readl(gicd + 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(0xffffffff, gicd + GICD_IGROUPRn + 4 * i);
+
+ return 0;
+}
+
+/*
+ * armv7_secure_monitor_install - install secure monitor
+ *
+ * This function is entered in secure mode. It installs the secure
+ * monitor code and enters it using a smc call. This function is executed
+ * on every CPU. We leave this function returns in nonsecure mode.
+ */
+int __armv7_secure_monitor_install(void)
+{
+ struct arm_smccc_res res;
+ void __iomem *gicd = IOMEM(get_gicd_base_address());
+ void __iomem *gicc = IOMEM(get_gicc_base_address());
+ u32 nsacr;
+
+ writel(0xffffffff, gicd + GICD_IGROUPRn);
+
+ writel(0x3, gicc + GICC_CTLR);
+ writel(0xff, gicc + GICC_PMR);
+
+ nsacr = read_nsacr();
+ nsacr |= 0x00043fff; /* all copros allowed in non-secure mode */
+ write_nsacr(nsacr);
+
+ write_mvbar((unsigned long)secure_monitor_init_vectors);
+
+ isb();
+
+ /* Initialize the secure monitor */
+ arm_smccc_smc(0, 0, 0, 0, 0, 0, 0, 0, &res);
+
+ /* We're in nonsecure mode now */
+
+ return 0;
+}
+
+static bool armv7_have_security_extensions(void)
+{
+ return (read_id_pfr1() & 0xf0) != 0;
+}
+
+/*
+ * armv7_secure_monitor_install - install secure monitor
+ *
+ * This function is entered in secure mode. It installs the secure
+ * monitor code and enters it using a smc call. This function is executed
+ * once on the primary CPU only. We leave this function returns in nonsecure
+ * mode.
+ */
+int armv7_secure_monitor_install(void)
+{
+ int mmuon;
+ unsigned long ttb, vbar;
+
+ if (!armv7_have_security_extensions()) {
+ pr_err("Security extensions not implemented.\n");
+ return -EINVAL;
+ }
+
+ mmuon = get_cr() & CR_M;
+
+ vbar = get_vbar();
+
+ asm volatile ("mrc p15, 0, %0, c2, c0, 0" : "=r"(ttb));
+
+ armv7_init_nonsec();
+ __armv7_secure_monitor_install();
+
+ asm volatile ("mcr p15, 0, %0, c2, c0, 0" : : "r"(ttb));
+
+ set_vbar(vbar);
+
+ if (mmuon) {
+ /*
+ * If the MMU was already turned on in secure mode, enable it in
+ * non-secure mode aswell
+ */
+ __mmu_cache_on();
+ }
+
+ pr_debug("Initialized secure monitor\n");
+
+ return 0;
+}
+
+/*
+ * of_secure_monitor_fixup - reserve memory region for secure monitor
+ *
+ * We currently do not support putting the secure monitor into onchip RAM,
+ * hence it runs in SDRAM and we must reserve the memory region so that we
+ * won't get overwritten from the Kernel.
+ * Beware: despite the name this is not secure in any way. The Kernel obeys
+ * the reserve map, but only because it's nice. It could always overwrite the
+ * secure monitor and hijack secure mode.
+ */
+static int of_secure_monitor_fixup(struct device_node *root, void *unused)
+{
+ unsigned long res_start, res_end;
+
+ res_start = (unsigned long)_stext;
+ res_end = (unsigned long)__bss_stop;
+
+ of_add_reserve_entry(res_start, res_end);
+
+ pr_debug("Reserved memory range from 0x%08lx to 0x%08lx\n", res_start, res_end);
+
+ return 0;
+}
+
+static enum arm_security_state bootm_secure_state;
+
+static const char * const bootm_secure_state_names[] = {
+ [ARM_STATE_SECURE] = "secure",
+ [ARM_STATE_NONSECURE] = "nonsecure",
+ [ARM_STATE_HYP] = "hyp",
+};
+
+enum arm_security_state bootm_arm_security_state(void)
+{
+ return bootm_secure_state;
+}
+
+const char *bootm_arm_security_state_name(enum arm_security_state state)
+{
+ return bootm_secure_state_names[state];
+}
+
+static int sm_init(void)
+{
+ of_register_fixup(of_secure_monitor_fixup, NULL);
+
+ globalvar_add_simple_enum("bootm.secure_state",
+ (unsigned int *)&bootm_secure_state,
+ bootm_secure_state_names,
+ ARRAY_SIZE(bootm_secure_state_names));
+
+ return 0;
+}
+device_initcall(sm_init);
\ No newline at end of file
diff --git a/arch/arm/cpu/sm_as.S b/arch/arm/cpu/sm_as.S
new file mode 100644
index 000000000..09580e75d
--- /dev/null
+++ b/arch/arm/cpu/sm_as.S
@@ -0,0 +1,168 @@
+#include <linux/linkage.h>
+#include <asm/ptrace.h>
+#include <asm-generic/memory_layout.h>
+#include <asm/secure.h>
+#include <asm/system.h>
+
+.arch_extension sec
+.arch_extension virt
+
+ .section ".text","ax"
+ .arm
+
+ .align 5
+.globl secure_monitor_init_vectors
+secure_monitor_init_vectors:
+1: b 1b /* reset */
+1: b 1b /* undefined instruction */
+ b secure_monitor_init /* software interrupt (SWI) */
+1: b 1b /* prefetch abort */
+1: b 1b /* data abort */
+1: b 1b /* (reserved) */
+1: b 1b /* irq (interrupt) */
+1: b 1b /* fiq (fast interrupt) */
+
+#define CPUID_ARM_GENTIMER_MASK (0xF << CPUID_ARM_GENTIMER_SHIFT)
+#define CPUID_ARM_GENTIMER_SHIFT 16
+
+#define CPUID_ARM_VIRT_MASK (0xF << CPUID_ARM_VIRT_SHIFT)
+#define CPUID_ARM_VIRT_SHIFT 12
+
+.macro is_cpu_virt_capable tmp
+ mrc p15, 0, \tmp, c0, c1, 1 @ read ID_PFR1
+ and \tmp, \tmp, #CPUID_ARM_VIRT_MASK @ mask virtualization bits
+ cmp \tmp, #(1 << CPUID_ARM_VIRT_SHIFT)
+.endm
+
+@ Requires dense and single-cluster CPU ID space
+ENTRY(psci_get_cpu_id)
+ mrc p15, 0, r0, c0, c0, 5 /* read MPIDR */
+ and r0, r0, #0xff /* return CPU ID in cluster */
+ bx lr
+ENDPROC(psci_get_cpu_id)
+
+ENTRY(secure_monitor_stack_setup)
+ mrc p15, 0, r0, c0, c0, 5 /* read MPIDR */
+ and r0, r0, #0xff /* CPU ID => r0 */
+
+ @ stack top = __secure_stack_end - (cpuid << ARM_PSCI_STACK_SHIFT)
+ ldr r1, =__secure_stack_end
+ sub r0, r1, r0, LSL #ARM_SECURE_STACK_SHIFT
+ sub r0, r0, #4 @ Save space for target PC
+
+ mov sp, r0
+ bx lr
+ENDPROC(secure_monitor_stack_setup)
+
+secure_monitor_init:
+ mov r3, lr
+
+ bl secure_monitor_stack_setup
+
+ push {r4-r7}
+ mov r7, r3
+ ldr r5, =secure_monitor_vectors @ Switch MVBAR to secure_monitor_vectors
+ mcr p15, 0, r5, c12, c0, 1
+ isb
+
+#ifdef CONFIG_MMU
+ mrc p15, 0, r5, c1, c0, 0
+ tst r5, #CR_M
+ beq 1f
+ bl __mmu_cache_off
+1:
+#endif
+ mrc p15, 0, r5, c1, c1, 0 @ read SCR
+ bic r5, r5, #0x4a @ clear IRQ, EA, nET bits
+ orr r5, r5, #0x31 @ enable NS, AW, FW bits
+ @ FIQ preserved for secure mode
+ mov r6, #SVC_MODE @ default mode is SVC
+
+ is_cpu_virt_capable r4
+
+ orreq r5, r5, #0x100 @ allow HVC instruction
+
+ mcr p15, 0, r5, c1, c1, 0 @ write SCR (with NS bit set)
+ isb
+
+ mrceq p15, 0, r0, c12, c0, 1 @ get MVBAR value
+ mcreq p15, 4, r0, c12, c0, 0 @ write HVBAR
+
+ bne 1f
+
+ @ Reset CNTVOFF to 0 before leaving monitor mode
+ mrc p15, 0, r4, c0, c1, 1 @ read ID_PFR1
+ ands r4, r4, #CPUID_ARM_GENTIMER_MASK @ test arch timer bits
+ movne r4, #0
+ mcrrne p15, 4, r4, r4, c14 @ Reset CNTVOFF to zero
+1:
+ mov lr, r7
+ mov ip, #(PSR_F_BIT | PSR_I_BIT | PSR_A_BIT) @ Set A, I and F
+ tst lr, #1 @ Check for Thumb PC
+ orrne ip, ip, #PSR_T_BIT @ Set T if Thumb
+ orr ip, ip, r6 @ Slot target mode in
+ msr spsr_cxfs, ip @ Set full SPSR
+ pop {r4-r7}
+ movs pc, lr @ ERET to non-secure
+
+ .align 5
+secure_monitor_vectors:
+1: b 1b /* reset */
+1: b 1b /* undefined instruction */
+ b secure_monitor /* software interrupt (SWI) */
+1: b 1b /* prefetch abort */
+1: b 1b /* data abort */
+1: b hyp_trap /* (reserved) */
+1: b 1b /* irq (interrupt) */
+1: b 1b /* fiq (fast interrupt) */
+
+secure_monitor:
+ push {r4-r7,lr}
+
+ @ Switch to secure mode
+ mrc p15, 0, r7, c1, c1, 0
+ bic r4, r7, #1
+ mcr p15, 0, r4, c1, c1, 0
+ isb
+
+ /* r0-r6: Arguments */
+ sub sp, sp, #4*4 @ allocate result structure on stack
+ mov r12, sp
+ push {r4-r6, r12}
+ bl psci_entry
+ pop {r4-r6, r12}
+ ldm r12, {r0-r3}
+ add sp, sp, #4*4
+ /* r0-r3: results, r4-r14: preserved */
+
+ @ back to non-secure
+ mcr p15, 0, r7, c1, c1, 0
+
+ pop {r4-r7, lr}
+ movs pc, lr
+
+hyp_trap:
+ mrs lr, elr_hyp @ for older asm: .byte 0x00, 0xe3, 0x0e, 0xe1
+ mov pc, lr @ do no switch modes, but
+ @ return to caller
+
+ENTRY(armv7_switch_to_hyp)
+ mov r0, lr
+ mov r1, sp @ save SVC copy of LR and SP
+ isb
+ hvc #0 @ for older asm: .byte 0x70, 0x00, 0x40, 0xe1
+ mov sp, r1
+ mov lr, r0 @ restore SVC copy of LR and SP
+
+ bx lr
+ENDPROC(armv7_switch_to_hyp)
+
+ENTRY(psci_cpu_entry)
+ mrc p15, 0, r0, c1, c0, 1 @ ACTLR
+ orr r0, r0, #(1 << 6) @ Set SMP bit
+ mcr p15, 0, r0, c1, c0, 1 @ ACTLR
+
+ bl secure_monitor_stack_setup
+ bl psci_cpu_entry_c
+
+ENDPROC(psci_cpu_entry)
diff --git a/arch/arm/include/asm/armlinux.h b/arch/arm/include/asm/armlinux.h
index 07479fb15..5c39200a0 100644
--- a/arch/arm/include/asm/armlinux.h
+++ b/arch/arm/include/asm/armlinux.h
@@ -3,6 +3,7 @@
#include <asm/memory.h>
#include <asm/setup.h>
+#include <asm/secure.h>
#if defined CONFIG_ARM_LINUX
void armlinux_set_bootparams(void *params);
@@ -38,6 +39,7 @@ static inline void armlinux_set_atag_appender(struct tag *(*func)(struct tag *))
struct image_data;
void start_linux(void *adr, int swap, unsigned long initrd_address,
- unsigned long initrd_size, void *oftree);
+ unsigned long initrd_size, void *oftree,
+ enum arm_security_state);
#endif /* __ARCH_ARMLINUX_H */
diff --git a/arch/arm/include/asm/gic.h b/arch/arm/include/asm/gic.h
new file mode 100644
index 000000000..bd3a80cdf
--- /dev/null
+++ b/arch/arm/include/asm/gic.h
@@ -0,0 +1,110 @@
+#ifndef __GIC_H__
+#define __GIC_H__
+
+/* Register offsets for the ARM generic interrupt controller (GIC) */
+
+#define GIC_DIST_OFFSET 0x1000
+#define GIC_CPU_OFFSET_A9 0x0100
+#define GIC_CPU_OFFSET_A15 0x2000
+
+/* Distributor Registers */
+#define GICD_CTLR 0x0000
+#define GICD_TYPER 0x0004
+#define GICD_IIDR 0x0008
+#define GICD_STATUSR 0x0010
+#define GICD_SETSPI_NSR 0x0040
+#define GICD_CLRSPI_NSR 0x0048
+#define GICD_SETSPI_SR 0x0050
+#define GICD_CLRSPI_SR 0x0058
+#define GICD_SEIR 0x0068
+#define GICD_IGROUPRn 0x0080
+#define GICD_ISENABLERn 0x0100
+#define GICD_ICENABLERn 0x0180
+#define GICD_ISPENDRn 0x0200
+#define GICD_ICPENDRn 0x0280
+#define GICD_ISACTIVERn 0x0300
+#define GICD_ICACTIVERn 0x0380
+#define GICD_IPRIORITYRn 0x0400
+#define GICD_ITARGETSRn 0x0800
+#define GICD_ICFGR 0x0c00
+#define GICD_IGROUPMODRn 0x0d00
+#define GICD_NSACRn 0x0e00
+#define GICD_SGIR 0x0f00
+#define GICD_CPENDSGIRn 0x0f10
+#define GICD_SPENDSGIRn 0x0f20
+#define GICD_IROUTERn 0x6000
+
+/* Cpu Interface Memory Mapped Registers */
+#define GICC_CTLR 0x0000
+#define GICC_PMR 0x0004
+#define GICC_BPR 0x0008
+#define GICC_IAR 0x000C
+#define GICC_EOIR 0x0010
+#define GICC_RPR 0x0014
+#define GICC_HPPIR 0x0018
+#define GICC_ABPR 0x001c
+#define GICC_AIAR 0x0020
+#define GICC_AEOIR 0x0024
+#define GICC_AHPPIR 0x0028
+#define GICC_APRn 0x00d0
+#define GICC_NSAPRn 0x00e0
+#define GICC_IIDR 0x00fc
+#define GICC_DIR 0x1000
+
+/* ReDistributor Registers for Control and Physical LPIs */
+#define GICR_CTLR 0x0000
+#define GICR_IIDR 0x0004
+#define GICR_TYPER 0x0008
+#define GICR_STATUSR 0x0010
+#define GICR_WAKER 0x0014
+#define GICR_SETLPIR 0x0040
+#define GICR_CLRLPIR 0x0048
+#define GICR_SEIR 0x0068
+#define GICR_PROPBASER 0x0070
+#define GICR_PENDBASER 0x0078
+#define GICR_INVLPIR 0x00a0
+#define GICR_INVALLR 0x00b0
+#define GICR_SYNCR 0x00c0
+#define GICR_MOVLPIR 0x0100
+#define GICR_MOVALLR 0x0110
+
+/* ReDistributor Registers for SGIs and PPIs */
+#define GICR_IGROUPRn 0x0080
+#define GICR_ISENABLERn 0x0100
+#define GICR_ICENABLERn 0x0180
+#define GICR_ISPENDRn 0x0200
+#define GICR_ICPENDRn 0x0280
+#define GICR_ISACTIVERn 0x0300
+#define GICR_ICACTIVERn 0x0380
+#define GICR_IPRIORITYRn 0x0400
+#define GICR_ICFGR0 0x0c00
+#define GICR_ICFGR1 0x0c04
+#define GICR_IGROUPMODRn 0x0d00
+#define GICR_NSACRn 0x0e00
+
+/* Cpu Interface System Registers */
+#define ICC_IAR0_EL1 S3_0_C12_C8_0
+#define ICC_IAR1_EL1 S3_0_C12_C12_0
+#define ICC_EOIR0_EL1 S3_0_C12_C8_1
+#define ICC_EOIR1_EL1 S3_0_C12_C12_1
+#define ICC_HPPIR0_EL1 S3_0_C12_C8_2
+#define ICC_HPPIR1_EL1 S3_0_C12_C12_2
+#define ICC_BPR0_EL1 S3_0_C12_C8_3
+#define ICC_BPR1_EL1 S3_0_C12_C12_3
+#define ICC_DIR_EL1 S3_0_C12_C11_1
+#define ICC_PMR_EL1 S3_0_C4_C6_0
+#define ICC_RPR_EL1 S3_0_C12_C11_3
+#define ICC_CTLR_EL1 S3_0_C12_C12_4
+#define ICC_CTLR_EL3 S3_6_C12_C12_4
+#define ICC_SRE_EL1 S3_0_C12_C12_5
+#define ICC_SRE_EL2 S3_4_C12_C9_5
+#define ICC_SRE_EL3 S3_6_C12_C12_5
+#define ICC_IGRPEN0_EL1 S3_0_C12_C12_6
+#define ICC_IGRPEN1_EL1 S3_0_C12_C12_7
+#define ICC_IGRPEN1_EL3 S3_6_C12_C12_7
+#define ICC_SEIEN_EL1 S3_0_C12_C13_0
+#define ICC_SGI0R_EL1 S3_0_C12_C11_7
+#define ICC_SGI1R_EL1 S3_0_C12_C11_5
+#define ICC_ASGI1R_EL1 S3_0_C12_C11_6
+
+#endif /* __GIC_H__ */
diff --git a/arch/arm/include/asm/psci.h b/arch/arm/include/asm/psci.h
new file mode 100644
index 000000000..e0c452538
--- /dev/null
+++ b/arch/arm/include/asm/psci.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2013 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ARM_PSCI_H__
+#define __ARM_PSCI_H__
+
+#define ARM_PSCI_VER_1_0 (0x00010000)
+#define ARM_PSCI_VER_0_2 (0x00000002)
+
+/* PSCI 0.1 interface */
+#define ARM_PSCI_FN_BASE 0x95c1ba5e
+#define ARM_PSCI_FN(n) (ARM_PSCI_FN_BASE + (n))
+
+#define ARM_PSCI_FN_CPU_SUSPEND ARM_PSCI_FN(0)
+#define ARM_PSCI_FN_CPU_OFF ARM_PSCI_FN(1)
+#define ARM_PSCI_FN_CPU_ON ARM_PSCI_FN(2)
+#define ARM_PSCI_FN_MIGRATE ARM_PSCI_FN(3)
+
+#define ARM_PSCI_RET_SUCCESS 0
+#define ARM_PSCI_RET_NOT_SUPPORTED (-1)
+#define ARM_PSCI_RET_INVAL (-2)
+#define ARM_PSCI_RET_DENIED (-3)
+#define ARM_PSCI_RET_ALREADY_ON (-4)
+#define ARM_PSCI_RET_ON_PENDING (-5)
+#define ARM_PSCI_RET_INTERNAL_FAILURE (-6)
+#define ARM_PSCI_RET_NOT_PRESENT (-7)
+#define ARM_PSCI_RET_DISABLED (-8)
+#define ARM_PSCI_RET_INVALID_ADDRESS (-9)
+
+/* PSCI 0.2 interface */
+#define ARM_PSCI_0_2_FN_BASE 0x84000000
+#define ARM_PSCI_0_2_FN(n) (ARM_PSCI_0_2_FN_BASE + (n))
+
+#define ARM_PSCI_0_2_FN64_BASE 0xC4000000
+#define ARM_PSCI_0_2_FN64(n) (ARM_PSCI_0_2_FN64_BASE + (n))
+
+#define ARM_PSCI_0_2_FN_PSCI_VERSION ARM_PSCI_0_2_FN(0)
+#define ARM_PSCI_0_2_FN_CPU_SUSPEND ARM_PSCI_0_2_FN(1)
+#define ARM_PSCI_0_2_FN_CPU_OFF ARM_PSCI_0_2_FN(2)
+#define ARM_PSCI_0_2_FN_CPU_ON ARM_PSCI_0_2_FN(3)
+#define ARM_PSCI_0_2_FN_AFFINITY_INFO ARM_PSCI_0_2_FN(4)
+#define ARM_PSCI_0_2_FN_MIGRATE ARM_PSCI_0_2_FN(5)
+#define ARM_PSCI_0_2_FN_MIGRATE_INFO_TYPE ARM_PSCI_0_2_FN(6)
+#define ARM_PSCI_0_2_FN_MIGRATE_INFO_UP_CPU ARM_PSCI_0_2_FN(7)
+#define ARM_PSCI_0_2_FN_SYSTEM_OFF ARM_PSCI_0_2_FN(8)
+#define ARM_PSCI_0_2_FN_SYSTEM_RESET ARM_PSCI_0_2_FN(9)
+
+#define ARM_PSCI_0_2_FN64_CPU_SUSPEND ARM_PSCI_0_2_FN64(1)
+#define ARM_PSCI_0_2_FN64_CPU_ON ARM_PSCI_0_2_FN64(3)
+#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_INFO_UP_CPU ARM_PSCI_0_2_FN64(7)
+
+/* PSCI 1.0 interface */
+#define ARM_PSCI_1_0_FN_PSCI_FEATURES ARM_PSCI_0_2_FN(10)
+#define ARM_PSCI_1_0_FN_CPU_FREEZE ARM_PSCI_0_2_FN(11)
+#define ARM_PSCI_1_0_FN_CPU_DEFAULT_SUSPEND ARM_PSCI_0_2_FN(12)
+#define ARM_PSCI_1_0_FN_NODE_HW_STATE ARM_PSCI_0_2_FN(13)
+#define ARM_PSCI_1_0_FN_SYSTEM_SUSPEND ARM_PSCI_0_2_FN(14)
+#define ARM_PSCI_1_0_FN_SET_SUSPEND_MODE ARM_PSCI_0_2_FN(15)
+#define ARM_PSCI_1_0_FN_STAT_RESIDENCY ARM_PSCI_0_2_FN(16)
+#define ARM_PSCI_1_0_FN_STAT_COUNT ARM_PSCI_0_2_FN(17)
+
+#define ARM_PSCI_1_0_FN64_CPU_DEFAULT_SUSPEND ARM_PSCI_0_2_FN64(12)
+#define ARM_PSCI_1_0_FN64_NODE_HW_STATE ARM_PSCI_0_2_FN64(13)
+#define ARM_PSCI_1_0_FN64_SYSTEM_SUSPEND ARM_PSCI_0_2_FN64(14)
+#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)
+
+/* PSCI affinity level state returned by AFFINITY_INFO */
+#define PSCI_AFFINITY_LEVEL_ON 0
+#define PSCI_AFFINITY_LEVEL_OFF 1
+#define PSCI_AFFINITY_LEVEL_ON_PENDING 2
+
+struct psci_ops {
+ int (*cpu_suspend)(u32 power_state, unsigned long entry, u32 context_id);
+ int (*cpu_off)(void);
+ int (*cpu_on)(u32 cpu_id);
+ int (*affinity_info)(u32 affinity, u32 lowest_affinity_level);
+ int (*migrate)(u32 cpu_id);
+ int (*migrate_info_type)(void);
+ int (*migrate_info_up_cpu)(void);
+ void (*system_off)(void);
+ void (*system_reset)(void);
+};
+
+#ifdef CONFIG_ARM_PSCI
+void psci_set_ops(struct psci_ops *ops);
+#else
+static inline void psci_set_ops(struct psci_ops *ops)
+{
+}
+#endif
+
+void psci_cpu_entry(void);
+
+#ifdef CONFIG_ARM_PSCI_DEBUG
+void psci_set_putc(void (*putcf)(void *ctx, int c), void *ctx);
+void psci_putc(char c);
+int psci_puts(const char *str);
+int psci_printf(const char *fmt, ...)
+ __attribute__ ((format(__printf__, 1, 2)));
+#else
+
+static inline void psci_set_putc(void (*putcf)(void *ctx, int c), void *ctx)
+{
+}
+
+static inline void psci_putc(char c)
+{
+}
+
+static inline int psci_puts(const char *str)
+{
+ return 0;
+}
+
+static inline int psci_printf(const char *fmt, ...)
+{
+ return 0;
+}
+#endif
+
+int psci_get_cpu_id(void);
+
+#endif /* __ARM_PSCI_H__ */
diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h
index 022d365b2..6520a0a73 100644
--- a/arch/arm/include/asm/ptrace.h
+++ b/arch/arm/include/asm/ptrace.h
@@ -32,6 +32,7 @@
#define IRQ_MODE 0x00000012
#define SVC_MODE 0x00000013
#define ABT_MODE 0x00000017
+#define HYP_MODE 0x0000001a
#define UND_MODE 0x0000001b
#define SYSTEM_MODE 0x0000001f
#define MODE32_BIT 0x00000010
diff --git a/arch/arm/include/asm/secure.h b/arch/arm/include/asm/secure.h
new file mode 100644
index 000000000..a4cb1f6c1
--- /dev/null
+++ b/arch/arm/include/asm/secure.h
@@ -0,0 +1,39 @@
+#ifndef __ASM_ARM_SECURE_H
+#define __ASM_ARM_SECURE_H
+
+#ifndef __ASSEMBLY__
+
+int armv7_secure_monitor_install(void);
+int __armv7_secure_monitor_install(void);
+void armv7_switch_to_hyp(void);
+
+extern unsigned char secure_monitor_init_vectors[];
+
+enum arm_security_state {
+ ARM_STATE_SECURE,
+ ARM_STATE_NONSECURE,
+ ARM_STATE_HYP,
+};
+
+#ifdef CONFIG_ARM_SECURE_MONITOR
+enum arm_security_state bootm_arm_security_state(void);
+const char *bootm_arm_security_state_name(enum arm_security_state state);
+#else
+static inline enum arm_security_state bootm_arm_security_state(void)
+{
+ return ARM_STATE_SECURE;
+}
+
+static inline const char *bootm_arm_security_state_name(
+ enum arm_security_state state)
+{
+ return "secure";
+}
+#endif
+
+#endif /* __ASSEMBLY__ */
+
+#define ARM_SECURE_STACK_SHIFT 10
+#define ARM_SECURE_MAX_CPU 8
+
+#endif /* __ASM_ARM_SECURE_H */
diff --git a/arch/arm/lib/bootm.c b/arch/arm/lib/bootm.c
index 9bd92f618..8068a53be 100644
--- a/arch/arm/lib/bootm.c
+++ b/arch/arm/lib/bootm.c
@@ -18,6 +18,7 @@
#include <magicvar.h>
#include <binfmt.h>
#include <restart.h>
+#include <globalvar.h>
#include <asm/byteorder.h>
#include <asm/setup.h>
@@ -133,6 +134,7 @@ static int __do_bootm_linux(struct image_data *data, unsigned long free_mem, int
{
unsigned long kernel;
unsigned long initrd_start = 0, initrd_size = 0, initrd_end = 0;
+ enum arm_security_state state = bootm_arm_security_state();
int ret;
kernel = data->os_res->start + data->os_entry;
@@ -174,10 +176,20 @@ static int __do_bootm_linux(struct image_data *data, unsigned long free_mem, int
printf("...\n");
}
+ if (IS_ENABLED(CONFIG_ARM_SECURE_MONITOR)) {
+ if (file_detect_type((void *)data->os_res->start, 0x100) ==
+ filetype_arm_barebox)
+ state = ARM_STATE_SECURE;
+
+ printf("Starting kernel in %s mode\n",
+ bootm_arm_security_state_name(state));
+ }
+
if (data->dryrun)
return 0;
- start_linux((void *)kernel, swap, initrd_start, initrd_size, data->oftree);
+ start_linux((void *)kernel, swap, initrd_start, initrd_size, data->oftree,
+ state);
restart_machine();
diff --git a/arch/arm/lib32/armlinux.c b/arch/arm/lib32/armlinux.c
index 6c7bd101c..fd7938b10 100644
--- a/arch/arm/lib32/armlinux.c
+++ b/arch/arm/lib32/armlinux.c
@@ -38,6 +38,7 @@
#include <asm/barebox-arm.h>
#include <asm/armlinux.h>
#include <asm/system.h>
+#include <asm/secure.h>
static struct tag *params;
static void *armlinux_bootparams = NULL;
@@ -258,11 +259,19 @@ static void setup_tags(unsigned long initrd_address,
}
void start_linux(void *adr, int swap, unsigned long initrd_address,
- unsigned long initrd_size, void *oftree)
+ unsigned long initrd_size, void *oftree,
+ enum arm_security_state state)
{
void (*kernel)(int zero, int arch, void *params) = adr;
void *params = NULL;
int architecture;
+ int ret;
+
+ if (state > ARM_STATE_SECURE) {
+ ret = armv7_secure_monitor_install();
+ if (ret)
+ pr_err("Failed to install secure monitor\n");
+ }
if (oftree) {
pr_debug("booting kernel with devicetree\n");
@@ -274,6 +283,10 @@ void start_linux(void *adr, int swap, unsigned long initrd_address,
architecture = armlinux_get_architecture();
shutdown_barebox();
+
+ if (state == ARM_STATE_HYP)
+ armv7_switch_to_hyp();
+
if (swap) {
u32 reg;
__asm__ __volatile__("mrc p15, 0, %0, c1, c0" : "=r" (reg));
diff --git a/arch/arm/lib32/barebox.lds.S b/arch/arm/lib32/barebox.lds.S
index 6dc8bd2f3..ff088b302 100644
--- a/arch/arm/lib32/barebox.lds.S
+++ b/arch/arm/lib32/barebox.lds.S
@@ -19,6 +19,7 @@
*/
#include <asm-generic/barebox.lds.h>
+#include <asm/secure.h>
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
@@ -121,6 +122,15 @@ SECTIONS
__bss_start = .;
.bss : { *(.bss*) }
__bss_stop = .;
+
+#ifdef CONFIG_ARM_SECURE_MONITOR
+ . = ALIGN(16);
+ __secure_stack_start = .;
+ . = . + (ARM_SECURE_MAX_CPU << ARM_SECURE_STACK_SHIFT);
+ __secure_stack_end = .;
+ __secure_end = .;
+#endif
+
_end = .;
_barebox_image_size = __bss_start - TEXT_BASE;
}
diff --git a/arch/arm/mach-imx/imx7.c b/arch/arm/mach-imx/imx7.c
index 96a9dd244..1cd27a0db 100644
--- a/arch/arm/mach-imx/imx7.c
+++ b/arch/arm/mach-imx/imx7.c
@@ -15,6 +15,7 @@
#include <common.h>
#include <io.h>
#include <linux/sizes.h>
+#include <asm/psci.h>
#include <mach/imx7.h>
#include <mach/generic.h>
#include <mach/revision.h>
--
2.11.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 4/4] ARM: i.MX7: Add PSCI support
2017-02-07 8:43 Add PSCI support Sascha Hauer
` (2 preceding siblings ...)
2017-02-07 8:43 ` [PATCH 3/4] ARM: Add PSCI support Sascha Hauer
@ 2017-02-07 8:43 ` Sascha Hauer
2017-02-09 19:13 ` Andrey Smirnov
3 siblings, 1 reply; 8+ messages in thread
From: Sascha Hauer @ 2017-02-07 8:43 UTC (permalink / raw)
To: Barebox List
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
arch/arm/cpu/psci.c | 13 +++++++++
arch/arm/mach-imx/imx7.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 89 insertions(+)
diff --git a/arch/arm/cpu/psci.c b/arch/arm/cpu/psci.c
index 745b8495e..d650c23ea 100644
--- a/arch/arm/cpu/psci.c
+++ b/arch/arm/cpu/psci.c
@@ -22,6 +22,17 @@
#include <magicvar.h>
#ifdef CONFIG_ARM_PSCI_DEBUG
+
+/*
+ * PSCI debugging functions. Board code can specify a putc() function
+ * which is used for debugging output. Beware that this function is
+ * called while the kernel is running. This means the kernel could have
+ * turned off clocks, configured other baudrates and other stuff that
+ * might confuse the putc function. So it can well be that the debugging
+ * code itself is the problem when somethings not working. You have been
+ * warned.
+ */
+
static void (*__putc)(void *ctx, int c);
static void *putc_ctx;
@@ -220,6 +231,8 @@ int psci_cpu_entry_c(void)
if (bootm_arm_security_state() == ARM_STATE_HYP)
armv7_switch_to_hyp();
+ psci_printf("core #%d enter function 0x%p\n", cpu, entry);
+
entry(context_id);
while (1);
diff --git a/arch/arm/mach-imx/imx7.c b/arch/arm/mach-imx/imx7.c
index 1cd27a0db..c4b9b2815 100644
--- a/arch/arm/mach-imx/imx7.c
+++ b/arch/arm/mach-imx/imx7.c
@@ -92,6 +92,80 @@ static void imx7_init_csu(void)
writel(CSU_INIT_SEC_LEVEL0, csu + i * 4);
}
+#define GPC_CPU_PGC_SW_PDN_REQ 0xfc
+#define GPC_CPU_PGC_SW_PUP_REQ 0xf0
+#define GPC_PGC_C1 0x840
+
+#define BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7 0x2
+
+/* below is for i.MX7D */
+#define SRC_GPR1_MX7D 0x074
+#define SRC_A7RCR0 0x004
+#define SRC_A7RCR1 0x008
+
+static void imx_gpcv2_set_core1_power(bool pdn)
+{
+ void __iomem *gpc = IOMEM(MX7_GPC_BASE_ADDR);
+
+ u32 reg = pdn ? GPC_CPU_PGC_SW_PUP_REQ : GPC_CPU_PGC_SW_PDN_REQ;
+ u32 val;
+
+ writel(1, gpc + GPC_PGC_C1);
+
+ val = readl(gpc + reg);
+ val |= BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7;
+ writel(val, gpc + reg);
+
+ while ((readl(gpc + reg) &
+ BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7) != 0)
+ ;
+
+ writel(0, gpc + GPC_PGC_C1);
+}
+
+static int imx7_cpu_on(u32 cpu_id)
+{
+ void __iomem *src = IOMEM(MX7_SRC_BASE_ADDR);
+ u32 val;
+
+ writel(psci_cpu_entry, src + cpu_id * 8 + SRC_GPR1_MX7D);
+ imx_gpcv2_set_core1_power(true);
+
+ val = readl(src + SRC_A7RCR1);
+ val |= 1 << cpu_id;
+ writel(val, src + SRC_A7RCR1);
+
+ return 0;
+}
+
+static int imx7_cpu_off(void)
+{
+ void __iomem *src = IOMEM(MX7_SRC_BASE_ADDR);
+ u32 val;
+ int cpu_id = 1;
+
+ val = readl(src + SRC_A7RCR1);
+ val &= ~(1 << cpu_id);
+ writel(val, src + SRC_A7RCR1);
+
+ /*
+ * FIXME: This reads nice and symmetrically to cpu_on above,
+ * but of course this will never be reached as we have just
+ * put the CPU we are currently running on into reset.
+ */
+
+ imx_gpcv2_set_core1_power(false);
+
+ while (1);
+
+ return 0;
+}
+
+static struct psci_ops imx7_psci_ops = {
+ .cpu_on = imx7_cpu_on,
+ .cpu_off = imx7_cpu_off,
+};
+
int imx7_init(void)
{
const char *cputypestr;
@@ -107,6 +181,8 @@ int imx7_init(void)
imx7_silicon_revision = imx7_cpu_revision();
+ psci_set_ops(&imx7_psci_ops);
+
switch (imx7_cpu_type()) {
case IMX7_CPUTYPE_IMX7D:
cputypestr = "i.MX7d";
--
2.11.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 4/4] ARM: i.MX7: Add PSCI support
2017-02-07 8:43 ` [PATCH 4/4] ARM: i.MX7: " Sascha Hauer
@ 2017-02-09 19:13 ` Andrey Smirnov
2017-02-13 7:45 ` Sascha Hauer
0 siblings, 1 reply; 8+ messages in thread
From: Andrey Smirnov @ 2017-02-09 19:13 UTC (permalink / raw)
To: Sascha Hauer; +Cc: Barebox List
On Tue, Feb 7, 2017 at 12:43 AM, Sascha Hauer <s.hauer@pengutronix.de> wrote:
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
> arch/arm/cpu/psci.c | 13 +++++++++
> arch/arm/mach-imx/imx7.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 89 insertions(+)
>
> diff --git a/arch/arm/cpu/psci.c b/arch/arm/cpu/psci.c
> index 745b8495e..d650c23ea 100644
> --- a/arch/arm/cpu/psci.c
> +++ b/arch/arm/cpu/psci.c
> @@ -22,6 +22,17 @@
> #include <magicvar.h>
>
> #ifdef CONFIG_ARM_PSCI_DEBUG
> +
> +/*
> + * PSCI debugging functions. Board code can specify a putc() function
> + * which is used for debugging output. Beware that this function is
> + * called while the kernel is running. This means the kernel could have
> + * turned off clocks, configured other baudrates and other stuff that
> + * might confuse the putc function. So it can well be that the debugging
> + * code itself is the problem when somethings not working. You have been
> + * warned.
> + */
> +
> static void (*__putc)(void *ctx, int c);
> static void *putc_ctx;
>
> @@ -220,6 +231,8 @@ int psci_cpu_entry_c(void)
> if (bootm_arm_security_state() == ARM_STATE_HYP)
> armv7_switch_to_hyp();
>
> + psci_printf("core #%d enter function 0x%p\n", cpu, entry);
> +
> entry(context_id);
>
> while (1);
> diff --git a/arch/arm/mach-imx/imx7.c b/arch/arm/mach-imx/imx7.c
> index 1cd27a0db..c4b9b2815 100644
> --- a/arch/arm/mach-imx/imx7.c
> +++ b/arch/arm/mach-imx/imx7.c
> @@ -92,6 +92,80 @@ static void imx7_init_csu(void)
> writel(CSU_INIT_SEC_LEVEL0, csu + i * 4);
> }
>
> +#define GPC_CPU_PGC_SW_PDN_REQ 0xfc
> +#define GPC_CPU_PGC_SW_PUP_REQ 0xf0
> +#define GPC_PGC_C1 0x840
Maybe convert this to something like:
#define PGC_C(n) (0x800 + (n) * 0x40)
... more domain offsets if needed ...
#define GPC_PGC_nCTRL(d) ((d) + 0x00)
and use as:
GPC_PGC_nCTRL(PGC_C(1))
?
> +
> +#define BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7 0x2
> +
> +/* below is for i.MX7D */
> +#define SRC_GPR1_MX7D 0x074
> +#define SRC_A7RCR0 0x004
This constant doesn't seem to be used anywhere, is that intentional?
> +#define SRC_A7RCR1 0x008
> +
> +static void imx_gpcv2_set_core1_power(bool pdn)
> +{
Did you not make this function more generic and take core number as a
parameter on purpose? It just seems like it would be trivial code
change, but maybe I am mistaken
> + void __iomem *gpc = IOMEM(MX7_GPC_BASE_ADDR);
> +
> + u32 reg = pdn ? GPC_CPU_PGC_SW_PUP_REQ : GPC_CPU_PGC_SW_PDN_REQ;
> + u32 val;
> +
> + writel(1, gpc + GPC_PGC_C1);
GPC_PGC_nCTRL_PCR instead of "1"?
> +
> + val = readl(gpc + reg);
> + val |= BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7;
> + writel(val, gpc + reg);
> +
> + while ((readl(gpc + reg) &
> + BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7) != 0)
> + ;
> +
> + writel(0, gpc + GPC_PGC_C1);
> +}
> +
> +static int imx7_cpu_on(u32 cpu_id)
> +{
> + void __iomem *src = IOMEM(MX7_SRC_BASE_ADDR);
> + u32 val;
> +
> + writel(psci_cpu_entry, src + cpu_id * 8 + SRC_GPR1_MX7D);
> + imx_gpcv2_set_core1_power(true);
> +
> + val = readl(src + SRC_A7RCR1);
> + val |= 1 << cpu_id;
BIT(cpu_id)?
> + writel(val, src + SRC_A7RCR1);
Hmm, this function doesn't look like it supports turning on CPU 0, am
I missing something? If not shouldn't it return NOT_SUPPORTED in case
cpu_id is 0?
> +
> + return 0;
> +}
> +
> +static int imx7_cpu_off(void)
> +{
> + void __iomem *src = IOMEM(MX7_SRC_BASE_ADDR);
> + u32 val;
> + int cpu_id = 1;
> +
I have only a very brief familiarity with PCSI, so pleasw bear with me
if what I am asking is dumb, but isn't CPU_OFF operation supposed to
power off current CPU? This function looks like it will power down
core 1 regardless of who's executing the code.
> + val = readl(src + SRC_A7RCR1);
> + val &= ~(1 << cpu_id);
BIT(cpu_id)?
> + writel(val, src + SRC_A7RCR1);
> +
> + /*
> + * FIXME: This reads nice and symmetrically to cpu_on above,
> + * but of course this will never be reached as we have just
> + * put the CPU we are currently running on into reset.
> + */
> +
> + imx_gpcv2_set_core1_power(false);
> +
> + while (1);
> +
> + return 0;
> +}
> +
> +static struct psci_ops imx7_psci_ops = {
> + .cpu_on = imx7_cpu_on,
> + .cpu_off = imx7_cpu_off,
> +};
> +
> int imx7_init(void)
> {
> const char *cputypestr;
> @@ -107,6 +181,8 @@ int imx7_init(void)
>
> imx7_silicon_revision = imx7_cpu_revision();
>
> + psci_set_ops(&imx7_psci_ops);
> +
> switch (imx7_cpu_type()) {
> case IMX7_CPUTYPE_IMX7D:
> cputypestr = "i.MX7d";
> --
> 2.11.0
>
>
> _______________________________________________
> barebox mailing list
> barebox@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 4/4] ARM: i.MX7: Add PSCI support
2017-02-09 19:13 ` Andrey Smirnov
@ 2017-02-13 7:45 ` Sascha Hauer
2017-02-13 18:38 ` Andrey Smirnov
0 siblings, 1 reply; 8+ messages in thread
From: Sascha Hauer @ 2017-02-13 7:45 UTC (permalink / raw)
To: Andrey Smirnov; +Cc: Barebox List
Hi Andrey,
On Thu, Feb 09, 2017 at 11:13:25AM -0800, Andrey Smirnov wrote:
> On Tue, Feb 7, 2017 at 12:43 AM, Sascha Hauer <s.hauer@pengutronix.de> wrote:
> > Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> > ---
> > arch/arm/cpu/psci.c | 13 +++++++++
> > arch/arm/mach-imx/imx7.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++
> > 2 files changed, 89 insertions(+)
> >
> > diff --git a/arch/arm/cpu/psci.c b/arch/arm/cpu/psci.c
> > index 745b8495e..d650c23ea 100644
> > --- a/arch/arm/cpu/psci.c
> > +++ b/arch/arm/cpu/psci.c
> > @@ -22,6 +22,17 @@
> > #include <magicvar.h>
> >
> > #ifdef CONFIG_ARM_PSCI_DEBUG
> > +
> > +/*
> > + * PSCI debugging functions. Board code can specify a putc() function
> > + * which is used for debugging output. Beware that this function is
> > + * called while the kernel is running. This means the kernel could have
> > + * turned off clocks, configured other baudrates and other stuff that
> > + * might confuse the putc function. So it can well be that the debugging
> > + * code itself is the problem when somethings not working. You have been
> > + * warned.
> > + */
> > +
> > static void (*__putc)(void *ctx, int c);
> > static void *putc_ctx;
> >
> > @@ -220,6 +231,8 @@ int psci_cpu_entry_c(void)
> > if (bootm_arm_security_state() == ARM_STATE_HYP)
> > armv7_switch_to_hyp();
> >
> > + psci_printf("core #%d enter function 0x%p\n", cpu, entry);
> > +
> > entry(context_id);
> >
> > while (1);
> > diff --git a/arch/arm/mach-imx/imx7.c b/arch/arm/mach-imx/imx7.c
> > index 1cd27a0db..c4b9b2815 100644
> > --- a/arch/arm/mach-imx/imx7.c
> > +++ b/arch/arm/mach-imx/imx7.c
> > @@ -92,6 +92,80 @@ static void imx7_init_csu(void)
> > writel(CSU_INIT_SEC_LEVEL0, csu + i * 4);
> > }
> >
> > +#define GPC_CPU_PGC_SW_PDN_REQ 0xfc
> > +#define GPC_CPU_PGC_SW_PUP_REQ 0xf0
> > +#define GPC_PGC_C1 0x840
>
> Maybe convert this to something like:
>
> #define PGC_C(n) (0x800 + (n) * 0x40)
>
> ... more domain offsets if needed ...
>
> #define GPC_PGC_nCTRL(d) ((d) + 0x00)
>
> and use as:
>
> GPC_PGC_nCTRL(PGC_C(1))
>
> ?
>
> > +
> > +#define BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7 0x2
> > +
> > +/* below is for i.MX7D */
> > +#define SRC_GPR1_MX7D 0x074
> > +#define SRC_A7RCR0 0x004
>
> This constant doesn't seem to be used anywhere, is that intentional?
>
> > +#define SRC_A7RCR1 0x008
> > +
> > +static void imx_gpcv2_set_core1_power(bool pdn)
> > +{
>
> Did you not make this function more generic and take core number as a
> parameter on purpose? It just seems like it would be trivial code
> change, but maybe I am mistaken
>
> > + void __iomem *gpc = IOMEM(MX7_GPC_BASE_ADDR);
> > +
> > + u32 reg = pdn ? GPC_CPU_PGC_SW_PUP_REQ : GPC_CPU_PGC_SW_PDN_REQ;
> > + u32 val;
> > +
> > + writel(1, gpc + GPC_PGC_C1);
>
> GPC_PGC_nCTRL_PCR instead of "1"?
>
> > +
> > + val = readl(gpc + reg);
> > + val |= BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7;
> > + writel(val, gpc + reg);
> > +
> > + while ((readl(gpc + reg) &
> > + BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7) != 0)
> > + ;
> > +
> > + writel(0, gpc + GPC_PGC_C1);
> > +}
> > +
> > +static int imx7_cpu_on(u32 cpu_id)
> > +{
> > + void __iomem *src = IOMEM(MX7_SRC_BASE_ADDR);
> > + u32 val;
> > +
> > + writel(psci_cpu_entry, src + cpu_id * 8 + SRC_GPR1_MX7D);
> > + imx_gpcv2_set_core1_power(true);
> > +
> > + val = readl(src + SRC_A7RCR1);
> > + val |= 1 << cpu_id;
>
> BIT(cpu_id)?
>
> > + writel(val, src + SRC_A7RCR1);
>
> Hmm, this function doesn't look like it supports turning on CPU 0, am
> I missing something? If not shouldn't it return NOT_SUPPORTED in case
> cpu_id is 0?
>
> > +
> > + return 0;
> > +}
> > +
> > +static int imx7_cpu_off(void)
> > +{
> > + void __iomem *src = IOMEM(MX7_SRC_BASE_ADDR);
> > + u32 val;
> > + int cpu_id = 1;
> > +
>
> I have only a very brief familiarity with PCSI, so pleasw bear with me
> if what I am asking is dumb, but isn't CPU_OFF operation supposed to
> power off current CPU? This function looks like it will power down
> core 1 regardless of who's executing the code.
This patch is only tested up to the point where the secondary CPU comes
up. In a dual core system we only ever have to enable the CPU1. I didn't
test CPU hotplug, so Linux won't turn off a CPU, be it core 0 or core 1.
I updated the patch to pass the core number around so it *shoul* work,
but I haven't tested it.
Sascha
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 4/4] ARM: i.MX7: Add PSCI support
2017-02-13 7:45 ` Sascha Hauer
@ 2017-02-13 18:38 ` Andrey Smirnov
0 siblings, 0 replies; 8+ messages in thread
From: Andrey Smirnov @ 2017-02-13 18:38 UTC (permalink / raw)
To: Sascha Hauer; +Cc: Barebox List
On Sun, Feb 12, 2017 at 11:45 PM, Sascha Hauer <s.hauer@pengutronix.de> wrote:
> Hi Andrey,
>
> On Thu, Feb 09, 2017 at 11:13:25AM -0800, Andrey Smirnov wrote:
>> On Tue, Feb 7, 2017 at 12:43 AM, Sascha Hauer <s.hauer@pengutronix.de> wrote:
>> > Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
>> > ---
>> > arch/arm/cpu/psci.c | 13 +++++++++
>> > arch/arm/mach-imx/imx7.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++
>> > 2 files changed, 89 insertions(+)
>> >
>> > diff --git a/arch/arm/cpu/psci.c b/arch/arm/cpu/psci.c
>> > index 745b8495e..d650c23ea 100644
>> > --- a/arch/arm/cpu/psci.c
>> > +++ b/arch/arm/cpu/psci.c
>> > @@ -22,6 +22,17 @@
>> > #include <magicvar.h>
>> >
>> > #ifdef CONFIG_ARM_PSCI_DEBUG
>> > +
>> > +/*
>> > + * PSCI debugging functions. Board code can specify a putc() function
>> > + * which is used for debugging output. Beware that this function is
>> > + * called while the kernel is running. This means the kernel could have
>> > + * turned off clocks, configured other baudrates and other stuff that
>> > + * might confuse the putc function. So it can well be that the debugging
>> > + * code itself is the problem when somethings not working. You have been
>> > + * warned.
>> > + */
>> > +
>> > static void (*__putc)(void *ctx, int c);
>> > static void *putc_ctx;
>> >
>> > @@ -220,6 +231,8 @@ int psci_cpu_entry_c(void)
>> > if (bootm_arm_security_state() == ARM_STATE_HYP)
>> > armv7_switch_to_hyp();
>> >
>> > + psci_printf("core #%d enter function 0x%p\n", cpu, entry);
>> > +
>> > entry(context_id);
>> >
>> > while (1);
>> > diff --git a/arch/arm/mach-imx/imx7.c b/arch/arm/mach-imx/imx7.c
>> > index 1cd27a0db..c4b9b2815 100644
>> > --- a/arch/arm/mach-imx/imx7.c
>> > +++ b/arch/arm/mach-imx/imx7.c
>> > @@ -92,6 +92,80 @@ static void imx7_init_csu(void)
>> > writel(CSU_INIT_SEC_LEVEL0, csu + i * 4);
>> > }
>> >
>> > +#define GPC_CPU_PGC_SW_PDN_REQ 0xfc
>> > +#define GPC_CPU_PGC_SW_PUP_REQ 0xf0
>> > +#define GPC_PGC_C1 0x840
>>
>> Maybe convert this to something like:
>>
>> #define PGC_C(n) (0x800 + (n) * 0x40)
>>
>> ... more domain offsets if needed ...
>>
>> #define GPC_PGC_nCTRL(d) ((d) + 0x00)
>>
>> and use as:
>>
>> GPC_PGC_nCTRL(PGC_C(1))
>>
>> ?
>>
>> > +
>> > +#define BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7 0x2
>> > +
>> > +/* below is for i.MX7D */
>> > +#define SRC_GPR1_MX7D 0x074
>> > +#define SRC_A7RCR0 0x004
>>
>> This constant doesn't seem to be used anywhere, is that intentional?
>>
>> > +#define SRC_A7RCR1 0x008
>> > +
>> > +static void imx_gpcv2_set_core1_power(bool pdn)
>> > +{
>>
>> Did you not make this function more generic and take core number as a
>> parameter on purpose? It just seems like it would be trivial code
>> change, but maybe I am mistaken
>>
>> > + void __iomem *gpc = IOMEM(MX7_GPC_BASE_ADDR);
>> > +
>> > + u32 reg = pdn ? GPC_CPU_PGC_SW_PUP_REQ : GPC_CPU_PGC_SW_PDN_REQ;
>> > + u32 val;
>> > +
>> > + writel(1, gpc + GPC_PGC_C1);
>>
>> GPC_PGC_nCTRL_PCR instead of "1"?
>>
>> > +
>> > + val = readl(gpc + reg);
>> > + val |= BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7;
>> > + writel(val, gpc + reg);
>> > +
>> > + while ((readl(gpc + reg) &
>> > + BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7) != 0)
>> > + ;
>> > +
>> > + writel(0, gpc + GPC_PGC_C1);
>> > +}
>> > +
>> > +static int imx7_cpu_on(u32 cpu_id)
>> > +{
>> > + void __iomem *src = IOMEM(MX7_SRC_BASE_ADDR);
>> > + u32 val;
>> > +
>> > + writel(psci_cpu_entry, src + cpu_id * 8 + SRC_GPR1_MX7D);
>> > + imx_gpcv2_set_core1_power(true);
>> > +
>> > + val = readl(src + SRC_A7RCR1);
>> > + val |= 1 << cpu_id;
>>
>> BIT(cpu_id)?
>>
>> > + writel(val, src + SRC_A7RCR1);
>>
>> Hmm, this function doesn't look like it supports turning on CPU 0, am
>> I missing something? If not shouldn't it return NOT_SUPPORTED in case
>> cpu_id is 0?
>>
>> > +
>> > + return 0;
>> > +}
>> > +
>> > +static int imx7_cpu_off(void)
>> > +{
>> > + void __iomem *src = IOMEM(MX7_SRC_BASE_ADDR);
>> > + u32 val;
>> > + int cpu_id = 1;
>> > +
>>
>> I have only a very brief familiarity with PCSI, so pleasw bear with me
>> if what I am asking is dumb, but isn't CPU_OFF operation supposed to
>> power off current CPU? This function looks like it will power down
>> core 1 regardless of who's executing the code.
>
> This patch is only tested up to the point where the secondary CPU comes
> up. In a dual core system we only ever have to enable the CPU1. I didn't
> test CPU hotplug, so Linux won't turn off a CPU, be it core 0 or core 1.
>
Yeah, I guess that was the case and that's fair. I am only concerned
about cases like that where such a discrepancy between what code
should do and what it was implemented to do is not documented in
comments. I'd rather avoid putting future readers in a position where
they have to determine if it is the code or their mental model of the
code is incorrect.
> I updated the patch to pass the core number around so it *shoul* work,
> but I haven't tested it.
That should work too. Thanks.
>
> Sascha
>
>
> --
> Pengutronix e.K. | |
> Industrial Linux Solutions | http://www.pengutronix.de/ |
> Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
> Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2017-02-13 18:39 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-02-07 8:43 Add PSCI support Sascha Hauer
2017-02-07 8:43 ` [PATCH 1/4] ARM: Add UNWIND macro Sascha Hauer
2017-02-07 8:43 ` [PATCH 2/4] ARM: Add smc call support Sascha Hauer
2017-02-07 8:43 ` [PATCH 3/4] ARM: Add PSCI support Sascha Hauer
2017-02-07 8:43 ` [PATCH 4/4] ARM: i.MX7: " Sascha Hauer
2017-02-09 19:13 ` Andrey Smirnov
2017-02-13 7:45 ` Sascha Hauer
2017-02-13 18:38 ` Andrey Smirnov
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox