From: Jan Kiszka <jan.kis...@siemens.com>

This is based on Thierry Reding's work and uses Ian Campell's
preparatory patches. It comes with full support for CPU_ON/OFF PSCI
services. The algorithm used in this version for turning CPUs on and
off was proposed by Thierry Reding in
http://thread.gmane.org/gmane.comp.boot-loaders.u-boot/210881. It
consists of first enabling CPU1..3 via the PMC, just to powergate them
again with the help of the Flow Controller. Once the Flow Controller is
in place, we can leave the PMC alone while processing CPU_ON and CPU_OFF
PSCI requests.

Signed-off-by: Jan Kiszka <jan.kis...@siemens.com>
---
 arch/arm/cpu/armv7/Makefile               |   1 +
 arch/arm/cpu/armv7/tegra-common/Makefile  |   1 +
 arch/arm/cpu/armv7/tegra-common/psci.S    | 101 ++++++++++++++++++++++++++++++
 arch/arm/cpu/armv7/tegra124/Makefile      |   7 +++
 arch/arm/cpu/armv7/tegra124/ap.c          |  44 +++++++++++++
 arch/arm/include/asm/arch-tegra124/flow.h |   5 ++
 6 files changed, 159 insertions(+)
 create mode 100644 arch/arm/cpu/armv7/tegra-common/psci.S
 create mode 100644 arch/arm/cpu/armv7/tegra124/Makefile
 create mode 100644 arch/arm/cpu/armv7/tegra124/ap.c

diff --git a/arch/arm/cpu/armv7/Makefile b/arch/arm/cpu/armv7/Makefile
index 409e6f5..616b6cc 100644
--- a/arch/arm/cpu/armv7/Makefile
+++ b/arch/arm/cpu/armv7/Makefile
@@ -59,6 +59,7 @@ obj-$(CONFIG_SOCFPGA) += socfpga/
 obj-$(if $(filter stv0991,$(SOC)),y) += stv0991/
 obj-$(CONFIG_ARCH_SUNXI) += sunxi/
 obj-$(CONFIG_TEGRA20) += tegra20/
+obj-$(CONFIG_TEGRA124) += tegra124/
 obj-$(CONFIG_U8500) += u8500/
 obj-$(CONFIG_ARCH_UNIPHIER) += uniphier/
 obj-$(CONFIG_VF610) += vf610/
diff --git a/arch/arm/cpu/armv7/tegra-common/Makefile 
b/arch/arm/cpu/armv7/tegra-common/Makefile
index 463c260..89355ca 100644
--- a/arch/arm/cpu/armv7/tegra-common/Makefile
+++ b/arch/arm/cpu/armv7/tegra-common/Makefile
@@ -7,4 +7,5 @@
 # SPDX-License-Identifier:     GPL-2.0+
 #
 
+obj-$(CONFIG_ARMV7_PSCI) += psci.o
 obj-$(CONFIG_CMD_ENTERRCM) += cmd_enterrcm.o
diff --git a/arch/arm/cpu/armv7/tegra-common/psci.S 
b/arch/arm/cpu/armv7/tegra-common/psci.S
new file mode 100644
index 0000000..b63a117
--- /dev/null
+++ b/arch/arm/cpu/armv7/tegra-common/psci.S
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2014, NVIDIA
+ * Copyright (C) 2015, Siemens AG
+ *
+ * Authors:
+ *  Thierry Reding <tred...@nvidia.com>
+ *  Jan Kiszka <jan.kis...@siemens.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <linux/linkage.h>
+#include <asm/psci.h>
+
+       .pushsection ._secure.text, "ax"
+       .arch_extension sec
+
+#define TEGRA_SB_CSR_0                 0x6000c200
+#define NS_RST_VEC_WR_DIS              (1 << 1)
+
+#define TEGRA_RESET_EXCEPTION_VECTOR   0x6000f100
+
+#define TEGRA_FLOW_CTRL_BASE           0x60007000
+#define FLOW_CTRL_CPU_CSR              0x08
+#define CSR_ENABLE                     (1 << 0)
+#define CSR_IMMEDIATE_WAKE             (1 << 3)
+#define CSR_WAIT_WFI_SHIFT             8
+#define FLOW_CTRL_CPU1_CSR             0x18
+
+@ converts CPU ID into FLOW_CTRL_CPUn_CSR offset
+.macro get_csr_reg cpu, ofs, tmp
+       cmp     \cpu, #0                @ CPU0?
+       lsl     \tmp, \cpu, #3  @ multiple by 8 (register offset CPU1-3)
+       moveq   \ofs, #FLOW_CTRL_CPU_CSR
+       addne   \ofs, \tmp, #FLOW_CTRL_CPU1_CSR - 8
+.endm
+
+ENTRY(psci_arch_init)
+       mrc     p15, 0, r5, c1, c1, 0   @ Read SCR
+       bic     r5, r5, #1              @ Secure mode
+       mcr     p15, 0, r5, c1, c1, 0   @ Write SCR
+       isb
+
+       @ lock reset vector
+       ldr     r6, =TEGRA_SB_CSR_0
+       ldr     r5, [r6]
+       orr     r5, r5, #NS_RST_VEC_WR_DIS
+       str     r5, [r6]
+
+       mrc     p15, 0, r4, c0, c0, 5   @ MPIDR
+       and     r4, r4, #7              @ number of CPUs in cluster
+       mov     r5, #400                @ 1 KiB of stack per CPU
+       mul     r4, r4, r5
+
+       adr     r5, text_end            @ end of text
+       add     r5, r5, #0x2000         @ Skip two pages
+       lsr     r5, r5, #12             @ Align to start of page
+       lsl     r5, r5, #12
+       sub     sp, r5, r4              @ here's our stack!
+
+       bx      lr
+ENDPROC(psci_arch_init)
+
+ENTRY(psci_cpu_off)
+       bl psci_cpu_off_common
+
+       mrc     p15, 0, r1, c0, c0, 5           @ MPIDR
+       and     r1, r1, #7                      @ number of CPUs in cluster
+
+       get_csr_reg r1, r2, r3
+
+       ldr     r6, =TEGRA_FLOW_CTRL_BASE
+       mov     r5, #(CSR_ENABLE)
+       add     r5, r1, lsl #CSR_WAIT_WFI_SHIFT
+       str     r5, [r6, r2]
+
+_loop: wfi
+       b       _loop
+ENDPROC(psci_cpu_off)
+
+ENTRY(psci_cpu_on)
+       ldr     r0, =_psci_target_pc
+       str     r2, [r0]
+       dsb
+
+       ldr     r6, =TEGRA_RESET_EXCEPTION_VECTOR
+       ldr     r5, =psci_cpu_entry
+       str     r5, [r6]
+
+       get_csr_reg r1, r2, r3
+
+       ldr     r6, =TEGRA_FLOW_CTRL_BASE
+       mov     r5, #(CSR_IMMEDIATE_WAKE | CSR_ENABLE)
+       str     r5, [r6, r2]
+
+       mov     r0, #ARM_PSCI_RET_SUCCESS       @ Return PSCI_RET_SUCCESS
+       mov     pc, lr
+ENDPROC(psci_cpu_on)
+
+text_end:
+       .popsection
diff --git a/arch/arm/cpu/armv7/tegra124/Makefile 
b/arch/arm/cpu/armv7/tegra124/Makefile
new file mode 100644
index 0000000..b907277
--- /dev/null
+++ b/arch/arm/cpu/armv7/tegra124/Makefile
@@ -0,0 +1,7 @@
+#
+# (C) Copyright 2015, Siemens AG
+#
+# SPDX-License-Identifier:     GPL-2.0+
+#
+
+obj-$(CONFIG_ARMV7_PSCI) += ap.o
diff --git a/arch/arm/cpu/armv7/tegra124/ap.c b/arch/arm/cpu/armv7/tegra124/ap.c
new file mode 100644
index 0000000..eebc0ea
--- /dev/null
+++ b/arch/arm/cpu/armv7/tegra124/ap.c
@@ -0,0 +1,44 @@
+/*
+ * (C) Copyright 2015, Siemens AG
+ * Author: Jan Kiszka <jan.kis...@siemens.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/flow.h>
+#include <asm/arch/powergate.h>
+#include <asm/arch-tegra/ap.h>
+#include <asm/arch-tegra/pmc.h>
+
+static void park_cpu(void)
+{
+       while (1)
+               asm volatile("wfi");
+}
+
+void ap_pm_init(void)
+{
+       struct flow_ctlr *flow = (struct flow_ctlr *)NV_PA_FLOW_BASE;
+       struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+
+       writel((u32)park_cpu, EXCEP_VECTOR_CPU_RESET_VECTOR);
+
+       tegra_powergate_power_on(TEGRA_POWERGATE_CPU1);
+       tegra_powergate_power_on(TEGRA_POWERGATE_CPU2);
+       tegra_powergate_power_on(TEGRA_POWERGATE_CPU3);
+
+       writel((2 << CSR_WAIT_WFI_SHIFT) | CSR_ENABLE, &flow->cpu1_csr);
+       writel((4 << CSR_WAIT_WFI_SHIFT) | CSR_ENABLE, &flow->cpu2_csr);
+       writel((8 << CSR_WAIT_WFI_SHIFT) | CSR_ENABLE, &flow->cpu3_csr);
+
+       writel(EVENT_MODE_STOP, &flow->halt_cpu1_events);
+       writel(EVENT_MODE_STOP, &flow->halt_cpu2_events);
+       writel(EVENT_MODE_STOP, &flow->halt_cpu3_events);
+
+       while (readl(&pmc->pmc_pwrgate_status) & ((1 << TEGRA_POWERGATE_CPU1) |
+                                                 (1 << TEGRA_POWERGATE_CPU2) |
+                                                 (1 << TEGRA_POWERGATE_CPU3)))
+               /* wait */;
+}
diff --git a/arch/arm/include/asm/arch-tegra124/flow.h 
b/arch/arm/include/asm/arch-tegra124/flow.h
index 0db1881..d5f24a0 100644
--- a/arch/arm/include/asm/arch-tegra124/flow.h
+++ b/arch/arm/include/asm/arch-tegra124/flow.h
@@ -37,4 +37,9 @@ struct flow_ctlr {
 /* FLOW_CTLR_CLUSTER_CONTROL_0 0x2c */
 #define ACTIVE_LP              (1 << 0)
 
+/* CPUn_CSR_0 */
+#define CSR_ENABLE             (1 << 0)
+#define CSR_IMMEDIATE_WAKE     (1 << 3)
+#define CSR_WAIT_WFI_SHIFT     8
+
 #endif /*  _TEGRA124_FLOW_H_ */
-- 
2.1.4

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

Reply via email to