uboot-tools/uboot-riscv-apr8-smp.patch

1864 lines
50 KiB
Diff

From fa33f08fd657b8568ede929df8a79bd113e9c5b1 Mon Sep 17 00:00:00 2001
From: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
Date: Sun, 17 Mar 2019 19:28:32 +0100
Subject: [PATCH 01/18] riscv: add infrastructure for calling functions on
other harts
Harts on RISC-V boot independently, U-Boot is responsible for managing
them. Functions are called on other harts with smp_call_function(),
which sends inter-processor interrupts (IPIs) to all other available
harts. Available harts are those marked as available in the device tree
and present in the available_harts mask stored in global data. The
available_harts mask is used to register all harts that have entered
U-Boot. Functions are specified with their address and two function
arguments (argument 2 and 3). The first function argument is always the
hart ID of the hart calling the function. On the other harts, the IPI
interrupt handler handle_ipi() must be called on software interrupts to
handle the request and call the specified function.
Functions are stored in the ipi_data data structure. Every hart has its
own data structure in global data. While this is not required at the
moment (all harts are expected to boot Linux), this does allow future
expansion, where other harts may be used for monitoring or other tasks.
Signed-off-by: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Tested-by: Bin Meng <bmeng.cn@gmail.com>
---
arch/riscv/Kconfig | 19 +++++
arch/riscv/include/asm/global_data.h | 6 ++
arch/riscv/include/asm/smp.h | 53 ++++++++++++
arch/riscv/lib/Makefile | 1 +
arch/riscv/lib/smp.c | 118 +++++++++++++++++++++++++++
5 files changed, 197 insertions(+)
create mode 100644 arch/riscv/include/asm/smp.h
create mode 100644 arch/riscv/lib/smp.c
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 36512a8995..4d7a115569 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -120,4 +120,23 @@ config RISCV_RDTIME
config SYS_MALLOC_F_LEN
default 0x1000
+config SMP
+ bool "Symmetric Multi-Processing"
+ help
+ This enables support for systems with more than one CPU. If
+ you say N here, U-Boot will run on single and multiprocessor
+ machines, but will use only one CPU of a multiprocessor
+ machine. If you say Y here, U-Boot will run on many, but not
+ all, single processor machines.
+
+config NR_CPUS
+ int "Maximum number of CPUs (2-32)"
+ range 2 32
+ depends on SMP
+ default 8
+ help
+ On multiprocessor machines, U-Boot sets up a stack for each CPU.
+ Stack memory is pre-allocated. U-Boot must therefore know the
+ maximum number of CPUs that may be present.
+
endmenu
diff --git a/arch/riscv/include/asm/global_data.h b/arch/riscv/include/asm/global_data.h
index a3a342c6e1..80e3165e39 100644
--- a/arch/riscv/include/asm/global_data.h
+++ b/arch/riscv/include/asm/global_data.h
@@ -10,12 +10,18 @@
#ifndef __ASM_GBL_DATA_H
#define __ASM_GBL_DATA_H
+#include <asm/smp.h>
+
/* Architecture-specific global data */
struct arch_global_data {
long boot_hart; /* boot hart id */
#ifdef CONFIG_SIFIVE_CLINT
void __iomem *clint; /* clint base address */
#endif
+#ifdef CONFIG_SMP
+ struct ipi_data ipi[CONFIG_NR_CPUS];
+#endif
+ ulong available_harts;
};
#include <asm-generic/global_data.h>
diff --git a/arch/riscv/include/asm/smp.h b/arch/riscv/include/asm/smp.h
new file mode 100644
index 0000000000..bc863fdbaf
--- /dev/null
+++ b/arch/riscv/include/asm/smp.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2019 Fraunhofer AISEC,
+ * Lukas Auer <lukas.auer@aisec.fraunhofer.de>
+ */
+
+#ifndef _ASM_RISCV_SMP_H
+#define _ASM_RISCV_SMP_H
+
+/**
+ * struct ipi_data - Inter-processor interrupt (IPI) data structure
+ *
+ * IPIs are used for SMP support to communicate to other harts what function to
+ * call. Functions are in the form
+ * void (*addr)(ulong hart, ulong arg0, ulong arg1).
+ *
+ * The function address and the two arguments, arg0 and arg1, are stored in the
+ * IPI data structure. The hart ID is inserted by the hart handling the IPI and
+ * calling the function.
+ *
+ * @addr: Address of function
+ * @arg0: First argument of function
+ * @arg1: Second argument of function
+ */
+struct ipi_data {
+ ulong addr;
+ ulong arg0;
+ ulong arg1;
+};
+
+/**
+ * handle_ipi() - interrupt handler for software interrupts
+ *
+ * The IPI interrupt handler must be called to handle software interrupts. It
+ * calls the function specified in the hart's IPI data structure.
+ *
+ * @hart: Hart ID of the current hart
+ */
+void handle_ipi(ulong hart);
+
+/**
+ * smp_call_function() - Call a function on all other harts
+ *
+ * Send IPIs with the specified function call to all harts.
+ *
+ * @addr: Address of function
+ * @arg0: First argument of function
+ * @arg1: Second argument of function
+ * @return 0 if OK, -ve on error
+ */
+int smp_call_function(ulong addr, ulong arg0, ulong arg1);
+
+#endif
diff --git a/arch/riscv/lib/Makefile b/arch/riscv/lib/Makefile
index edfa61690c..19370f9749 100644
--- a/arch/riscv/lib/Makefile
+++ b/arch/riscv/lib/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_SIFIVE_CLINT) += sifive_clint.o
obj-y += interrupts.o
obj-y += reset.o
obj-y += setjmp.o
+obj-$(CONFIG_SMP) += smp.o
# For building EFI apps
CFLAGS_$(EFI_CRT0) := $(CFLAGS_EFI)
diff --git a/arch/riscv/lib/smp.c b/arch/riscv/lib/smp.c
new file mode 100644
index 0000000000..caa292ccd2
--- /dev/null
+++ b/arch/riscv/lib/smp.c
@@ -0,0 +1,118 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Fraunhofer AISEC,
+ * Lukas Auer <lukas.auer@aisec.fraunhofer.de>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <asm/barrier.h>
+#include <asm/smp.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/**
+ * riscv_send_ipi() - Send inter-processor interrupt (IPI)
+ *
+ * Platform code must provide this function.
+ *
+ * @hart: Hart ID of receiving hart
+ * @return 0 if OK, -ve on error
+ */
+extern int riscv_send_ipi(int hart);
+
+/**
+ * riscv_clear_ipi() - Clear inter-processor interrupt (IPI)
+ *
+ * Platform code must provide this function.
+ *
+ * @hart: Hart ID of hart to be cleared
+ * @return 0 if OK, -ve on error
+ */
+extern int riscv_clear_ipi(int hart);
+
+static int send_ipi_many(struct ipi_data *ipi)
+{
+ ofnode node, cpus;
+ u32 reg;
+ int ret;
+
+ cpus = ofnode_path("/cpus");
+ if (!ofnode_valid(cpus)) {
+ pr_err("Can't find cpus node!\n");
+ return -EINVAL;
+ }
+
+ ofnode_for_each_subnode(node, cpus) {
+ /* skip if hart is marked as not available in the device tree */
+ if (!ofnode_is_available(node))
+ continue;
+
+ /* read hart ID of CPU */
+ ret = ofnode_read_u32(node, "reg", &reg);
+ if (ret)
+ continue;
+
+ /* skip if it is the hart we are running on */
+ if (reg == gd->arch.boot_hart)
+ continue;
+
+ if (reg >= CONFIG_NR_CPUS) {
+ pr_err("Hart ID %d is out of range, increase CONFIG_NR_CPUS\n",
+ reg);
+ continue;
+ }
+
+ /* skip if hart is not available */
+ if (!(gd->arch.available_harts & (1 << reg)))
+ continue;
+
+ gd->arch.ipi[reg].addr = ipi->addr;
+ gd->arch.ipi[reg].arg0 = ipi->arg0;
+ gd->arch.ipi[reg].arg1 = ipi->arg1;
+
+ ret = riscv_send_ipi(reg);
+ if (ret) {
+ pr_err("Cannot send IPI to hart %d\n", reg);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+void handle_ipi(ulong hart)
+{
+ int ret;
+ void (*smp_function)(ulong hart, ulong arg0, ulong arg1);
+
+ if (hart >= CONFIG_NR_CPUS)
+ return;
+
+ ret = riscv_clear_ipi(hart);
+ if (ret) {
+ pr_err("Cannot clear IPI of hart %ld\n", hart);
+ return;
+ }
+
+ __smp_mb();
+
+ smp_function = (void (*)(ulong, ulong, ulong))gd->arch.ipi[hart].addr;
+ invalidate_icache_all();
+
+ smp_function(hart, gd->arch.ipi[hart].arg0, gd->arch.ipi[hart].arg1);
+}
+
+int smp_call_function(ulong addr, ulong arg0, ulong arg1)
+{
+ int ret = 0;
+ struct ipi_data ipi;
+
+ ipi.addr = addr;
+ ipi.arg0 = arg0;
+ ipi.arg1 = arg1;
+
+ ret = send_ipi_many(&ipi);
+
+ return ret;
+}
--
2.20.1
From 34a0626fc344f51cd768efecdd52628b677fb9a8 Mon Sep 17 00:00:00 2001
From: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
Date: Sun, 17 Mar 2019 19:28:33 +0100
Subject: [PATCH 02/18] riscv: import the supervisor binary interface header
file
Import the supervisor binary interface (SBI) header file from Linux
(arch/riscv/include/asm/sbi.h). The last change to it was in commit
6d60b6ee0c97 ("RISC-V: Device, timer, IRQs, and the SBI").
Signed-off-by: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
---
arch/riscv/include/asm/sbi.h | 94 ++++++++++++++++++++++++++++++++++++
1 file changed, 94 insertions(+)
create mode 100644 arch/riscv/include/asm/sbi.h
diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h
new file mode 100644
index 0000000000..ced57defdd
--- /dev/null
+++ b/arch/riscv/include/asm/sbi.h
@@ -0,0 +1,94 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2015 Regents of the University of California
+ *
+ * Taken from Linux arch/riscv/include/asm/sbi.h
+ */
+
+#ifndef _ASM_RISCV_SBI_H
+#define _ASM_RISCV_SBI_H
+
+#include <linux/types.h>
+
+#define SBI_SET_TIMER 0
+#define SBI_CONSOLE_PUTCHAR 1
+#define SBI_CONSOLE_GETCHAR 2
+#define SBI_CLEAR_IPI 3
+#define SBI_SEND_IPI 4
+#define SBI_REMOTE_FENCE_I 5
+#define SBI_REMOTE_SFENCE_VMA 6
+#define SBI_REMOTE_SFENCE_VMA_ASID 7
+#define SBI_SHUTDOWN 8
+
+#define SBI_CALL(which, arg0, arg1, arg2) ({ \
+ register uintptr_t a0 asm ("a0") = (uintptr_t)(arg0); \
+ register uintptr_t a1 asm ("a1") = (uintptr_t)(arg1); \
+ register uintptr_t a2 asm ("a2") = (uintptr_t)(arg2); \
+ register uintptr_t a7 asm ("a7") = (uintptr_t)(which); \
+ asm volatile ("ecall" \
+ : "+r" (a0) \
+ : "r" (a1), "r" (a2), "r" (a7) \
+ : "memory"); \
+ a0; \
+})
+
+/* Lazy implementations until SBI is finalized */
+#define SBI_CALL_0(which) SBI_CALL(which, 0, 0, 0)
+#define SBI_CALL_1(which, arg0) SBI_CALL(which, arg0, 0, 0)
+#define SBI_CALL_2(which, arg0, arg1) SBI_CALL(which, arg0, arg1, 0)
+
+static inline void sbi_console_putchar(int ch)
+{
+ SBI_CALL_1(SBI_CONSOLE_PUTCHAR, ch);
+}
+
+static inline int sbi_console_getchar(void)
+{
+ return SBI_CALL_0(SBI_CONSOLE_GETCHAR);
+}
+
+static inline void sbi_set_timer(uint64_t stime_value)
+{
+#if __riscv_xlen == 32
+ SBI_CALL_2(SBI_SET_TIMER, stime_value, stime_value >> 32);
+#else
+ SBI_CALL_1(SBI_SET_TIMER, stime_value);
+#endif
+}
+
+static inline void sbi_shutdown(void)
+{
+ SBI_CALL_0(SBI_SHUTDOWN);
+}
+
+static inline void sbi_clear_ipi(void)
+{
+ SBI_CALL_0(SBI_CLEAR_IPI);
+}
+
+static inline void sbi_send_ipi(const unsigned long *hart_mask)
+{
+ SBI_CALL_1(SBI_SEND_IPI, hart_mask);
+}
+
+static inline void sbi_remote_fence_i(const unsigned long *hart_mask)
+{
+ SBI_CALL_1(SBI_REMOTE_FENCE_I, hart_mask);
+}
+
+static inline void sbi_remote_sfence_vma(const unsigned long *hart_mask,
+ unsigned long start,
+ unsigned long size)
+{
+ SBI_CALL_1(SBI_REMOTE_SFENCE_VMA, hart_mask);
+}
+
+static inline void sbi_remote_sfence_vma_asid(const unsigned long *hart_mask,
+ unsigned long start,
+ unsigned long size,
+ unsigned long asid)
+{
+ SBI_CALL_1(SBI_REMOTE_SFENCE_VMA_ASID, hart_mask);
+}
+
+#endif
--
2.20.1
From f152febb2a97696f7c7e6df46bf585cfc962a835 Mon Sep 17 00:00:00 2001
From: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
Date: Sun, 17 Mar 2019 19:28:34 +0100
Subject: [PATCH 03/18] riscv: implement IPI platform functions using SBI
The supervisor binary interface (SBI) provides the necessary functions
to implement the platform IPI functions riscv_send_ipi() and
riscv_clear_ipi(). Use it to implement them.
This adds support for inter-processor interrupts (IPIs) on RISC-V CPUs
running in supervisor mode. Support for machine mode is already
available for CPUs that include the SiFive CLINT.
Signed-off-by: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
Tested-by: Bin Meng <bmeng.cn@gmail.com>
---
arch/riscv/Kconfig | 5 +++++
arch/riscv/lib/Makefile | 1 +
arch/riscv/lib/sbi_ipi.c | 25 +++++++++++++++++++++++++
3 files changed, 31 insertions(+)
create mode 100644 arch/riscv/lib/sbi_ipi.c
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 4d7a115569..9da609b33b 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -139,4 +139,9 @@ config NR_CPUS
Stack memory is pre-allocated. U-Boot must therefore know the
maximum number of CPUs that may be present.
+config SBI_IPI
+ bool
+ default y if RISCV_SMODE
+ depends on SMP
+
endmenu
diff --git a/arch/riscv/lib/Makefile b/arch/riscv/lib/Makefile
index 19370f9749..35dbf643e4 100644
--- a/arch/riscv/lib/Makefile
+++ b/arch/riscv/lib/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_RISCV_RDTIME) += rdtime.o
obj-$(CONFIG_SIFIVE_CLINT) += sifive_clint.o
obj-y += interrupts.o
obj-y += reset.o
+obj-$(CONFIG_SBI_IPI) += sbi_ipi.o
obj-y += setjmp.o
obj-$(CONFIG_SMP) += smp.o
diff --git a/arch/riscv/lib/sbi_ipi.c b/arch/riscv/lib/sbi_ipi.c
new file mode 100644
index 0000000000..170346da68
--- /dev/null
+++ b/arch/riscv/lib/sbi_ipi.c
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Fraunhofer AISEC,
+ * Lukas Auer <lukas.auer@aisec.fraunhofer.de>
+ */
+
+#include <common.h>
+#include <asm/sbi.h>
+
+int riscv_send_ipi(int hart)
+{
+ ulong mask;
+
+ mask = 1UL << hart;
+ sbi_send_ipi(&mask);
+
+ return 0;
+}
+
+int riscv_clear_ipi(int hart)
+{
+ sbi_clear_ipi();
+
+ return 0;
+}
--
2.20.1
From 2503ccc55ff2031ae2ff476fb06f666e6d1c7a64 Mon Sep 17 00:00:00 2001
From: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
Date: Sun, 17 Mar 2019 19:28:35 +0100
Subject: [PATCH 04/18] riscv: delay initialization of caches and debug UART
Move the initialization of the caches and the debug UART until after
board_init_f_init_reserve. This is in preparation for SMP support, where
code prior to this point will be executed by all harts. This ensures
that initialization will only be performed once on the main hart running
U-Boot.
Signed-off-by: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
---
arch/riscv/cpu/start.S | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/arch/riscv/cpu/start.S b/arch/riscv/cpu/start.S
index 81ea52b170..a30f6f7194 100644
--- a/arch/riscv/cpu/start.S
+++ b/arch/riscv/cpu/start.S
@@ -45,10 +45,6 @@ _start:
/* mask all interrupts */
csrw MODE_PREFIX(ie), zero
- /* Enable cache */
- jal icache_enable
- jal dcache_enable
-
/*
* Set stackpointer in internal/ex RAM to call board_init_f
*/
@@ -57,10 +53,6 @@ call_board_init_f:
li t1, CONFIG_SYS_INIT_SP_ADDR
and sp, t1, t0 /* force 16 byte alignment */
-#ifdef CONFIG_DEBUG_UART
- jal debug_uart_init
-#endif
-
call_board_init_f_0:
mv a0, sp
jal board_init_f_alloc_reserve
@@ -74,6 +66,14 @@ call_board_init_f_0:
/* save the boot hart id to global_data */
SREG s0, GD_BOOT_HART(gp)
+ /* Enable cache */
+ jal icache_enable
+ jal dcache_enable
+
+#ifdef CONFIG_DEBUG_UART
+ jal debug_uart_init
+#endif
+
mv a0, zero /* a0 <-- boot_flags = 0 */
la t5, board_init_f
jr t5 /* jump to board_init_f() */
--
2.20.1
From 1446b26f7652124f0e3e98c348cdbc4fc55eb0cb Mon Sep 17 00:00:00 2001
From: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
Date: Sun, 17 Mar 2019 19:28:36 +0100
Subject: [PATCH 05/18] riscv: save hart ID in register tp instead of s0
The hart ID passed by the previous boot stage is currently stored in
register s0. If we divert the control flow inside a function, which is
required as part of multi-hart support, the function epilog may not be
called, clobbering register s0. Save the hart ID in the unallocatable
register tp instead to protect the hart ID.
Signed-off-by: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Rick Chen <rick@andestech.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
---
arch/riscv/cpu/start.S | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/riscv/cpu/start.S b/arch/riscv/cpu/start.S
index a30f6f7194..bcc0ff696d 100644
--- a/arch/riscv/cpu/start.S
+++ b/arch/riscv/cpu/start.S
@@ -36,7 +36,7 @@
.globl _start
_start:
/* save hart id and dtb pointer */
- mv s0, a0
+ mv tp, a0
mv s1, a1
la t0, trap_entry
@@ -64,7 +64,7 @@ call_board_init_f_0:
jal board_init_f_init_reserve
/* save the boot hart id to global_data */
- SREG s0, GD_BOOT_HART(gp)
+ SREG tp, GD_BOOT_HART(gp)
/* Enable cache */
jal icache_enable
--
2.20.1
From 3dea63c8445b25eb3de471410bbafcf54c9f0e9b Mon Sep 17 00:00:00 2001
From: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
Date: Sun, 17 Mar 2019 19:28:37 +0100
Subject: [PATCH 06/18] riscv: add support for multi-hart systems
On RISC-V, all harts boot independently. To be able to run on a
multi-hart system, U-Boot must be extended with the functionality to
manage all harts in the system. All harts entering U-Boot are registered
in the available_harts mask stored in global data. A hart lottery system
as used in the Linux kernel selects the hart U-Boot runs on. All other
harts are halted. U-Boot can delegate functions to them using
smp_call_function().
Every hart has a valid pointer to the global data structure and a 8KiB
stack by default. The stack size is set with CONFIG_STACK_SIZE_SHIFT.
Signed-off-by: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Tested-by: Bin Meng <bmeng.cn@gmail.com>
---
arch/riscv/Kconfig | 4 ++
arch/riscv/cpu/cpu.c | 9 ++-
arch/riscv/cpu/start.S | 134 ++++++++++++++++++++++++++++++++++-
arch/riscv/include/asm/csr.h | 1 +
arch/riscv/lib/asm-offsets.c | 1 +
5 files changed, 147 insertions(+), 2 deletions(-)
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 9da609b33b..3a4470daf3 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -144,4 +144,8 @@ config SBI_IPI
default y if RISCV_SMODE
depends on SMP
+config STACK_SIZE_SHIFT
+ int
+ default 13
+
endmenu
diff --git a/arch/riscv/cpu/cpu.c b/arch/riscv/cpu/cpu.c
index e662140427..c32de8a4c3 100644
--- a/arch/riscv/cpu/cpu.c
+++ b/arch/riscv/cpu/cpu.c
@@ -12,10 +12,17 @@
#include <dm/uclass-internal.h>
/*
- * prior_stage_fdt_address must be stored in the data section since it is used
+ * The variables here must be stored in the data section since they are used
* before the bss section is available.
*/
phys_addr_t prior_stage_fdt_address __attribute__((section(".data")));
+u32 hart_lottery __attribute__((section(".data"))) = 0;
+
+/*
+ * The main hart running U-Boot has acquired available_harts_lock until it has
+ * finished initialization of global data.
+ */
+u32 available_harts_lock = 1;
static inline bool supports_extension(char ext)
{
diff --git a/arch/riscv/cpu/start.S b/arch/riscv/cpu/start.S
index bcc0ff696d..f55b8cbc37 100644
--- a/arch/riscv/cpu/start.S
+++ b/arch/riscv/cpu/start.S
@@ -13,6 +13,7 @@
#include <config.h>
#include <common.h>
#include <elf.h>
+#include <asm/csr.h>
#include <asm/encoding.h>
#include <generated/asm-offsets.h>
@@ -45,6 +46,23 @@ _start:
/* mask all interrupts */
csrw MODE_PREFIX(ie), zero
+#ifdef CONFIG_SMP
+ /* check if hart is within range */
+ /* tp: hart id */
+ li t0, CONFIG_NR_CPUS
+ bge tp, t0, hart_out_of_bounds_loop
+#endif
+
+#ifdef CONFIG_SMP
+ /* set xSIE bit to receive IPIs */
+#ifdef CONFIG_RISCV_MMODE
+ li t0, MIE_MSIE
+#else
+ li t0, SIE_SSIE
+#endif
+ csrs MODE_PREFIX(ie), t0
+#endif
+
/*
* Set stackpointer in internal/ex RAM to call board_init_f
*/
@@ -56,7 +74,30 @@ call_board_init_f:
call_board_init_f_0:
mv a0, sp
jal board_init_f_alloc_reserve
+
+ /*
+ * Set global data pointer here for all harts, uninitialized at this
+ * point.
+ */
+ mv gp, a0
+
+ /* setup stack */
+#ifdef CONFIG_SMP
+ /* tp: hart id */
+ slli t0, tp, CONFIG_STACK_SIZE_SHIFT
+ sub sp, a0, t0
+#else
mv sp, a0
+#endif
+
+ /*
+ * Pick hart to initialize global data and run U-Boot. The other harts
+ * wait for initialization to complete.
+ */
+ la t0, hart_lottery
+ li s2, 1
+ amoswap.w s2, t1, 0(t0)
+ bnez s2, wait_for_gd_init
la t0, prior_stage_fdt_address
SREG s1, 0(t0)
@@ -66,6 +107,33 @@ call_board_init_f_0:
/* save the boot hart id to global_data */
SREG tp, GD_BOOT_HART(gp)
+ la t0, available_harts_lock
+ fence rw, w
+ amoswap.w zero, zero, 0(t0)
+
+wait_for_gd_init:
+ la t0, available_harts_lock
+ li t1, 1
+1: amoswap.w t1, t1, 0(t0)
+ fence r, rw
+ bnez t1, 1b
+
+ /* register available harts in the available_harts mask */
+ li t1, 1
+ sll t1, t1, tp
+ LREG t2, GD_AVAILABLE_HARTS(gp)
+ or t2, t2, t1
+ SREG t2, GD_AVAILABLE_HARTS(gp)
+
+ fence rw, w
+ amoswap.w zero, zero, 0(t0)
+
+ /*
+ * Continue on hart lottery winner, others branch to
+ * secondary_hart_loop.
+ */
+ bnez s2, secondary_hart_loop
+
/* Enable cache */
jal icache_enable
jal dcache_enable
@@ -95,7 +163,14 @@ relocate_code:
*Set up the stack
*/
stack_setup:
+#ifdef CONFIG_SMP
+ /* tp: hart id */
+ slli t0, tp, CONFIG_STACK_SIZE_SHIFT
+ sub sp, s2, t0
+#else
mv sp, s2
+#endif
+
la t0, _start
sub t6, s4, t0 /* t6 <- relocation offset */
beq t0, s4, clear_bss /* skip relocation */
@@ -175,13 +250,30 @@ clear_bss:
add t0, t0, t6 /* t0 <- rel __bss_start in RAM */
la t1, __bss_end /* t1 <- rel __bss_end in FLASH */
add t1, t1, t6 /* t1 <- rel __bss_end in RAM */
- beq t0, t1, call_board_init_r
+ beq t0, t1, relocate_secondary_harts
clbss_l:
SREG zero, 0(t0) /* clear loop... */
addi t0, t0, REGBYTES
bne t0, t1, clbss_l
+relocate_secondary_harts:
+#ifdef CONFIG_SMP
+ /* send relocation IPI */
+ la t0, secondary_hart_relocate
+ add a0, t0, t6
+
+ /* store relocation offset */
+ mv s5, t6
+
+ mv a1, s2
+ mv a2, s3
+ jal smp_call_function
+
+ /* restore relocation offset */
+ mv t6, s5
+#endif
+
/*
* We are done. Do not return, instead branch to second part of board
* initialization, now running from RAM.
@@ -202,3 +294,43 @@ call_board_init_r:
* jump to it ...
*/
jr t4 /* jump to board_init_r() */
+
+#ifdef CONFIG_SMP
+hart_out_of_bounds_loop:
+ /* Harts in this loop are out of bounds, increase CONFIG_NR_CPUS. */
+ wfi
+ j hart_out_of_bounds_loop
+#endif
+
+#ifdef CONFIG_SMP
+/* SMP relocation entry */
+secondary_hart_relocate:
+ /* a1: new sp */
+ /* a2: new gd */
+ /* tp: hart id */
+
+ /* setup stack */
+ slli t0, tp, CONFIG_STACK_SIZE_SHIFT
+ sub sp, a1, t0
+
+ /* update global data pointer */
+ mv gp, a2
+#endif
+
+secondary_hart_loop:
+ wfi
+
+#ifdef CONFIG_SMP
+ csrr t0, MODE_PREFIX(ip)
+#ifdef CONFIG_RISCV_MMODE
+ andi t0, t0, MIE_MSIE
+#else
+ andi t0, t0, SIE_SSIE
+#endif
+ beqz t0, secondary_hart_loop
+
+ mv a0, tp
+ jal handle_ipi
+#endif
+
+ j secondary_hart_loop
diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h
index 86136f542c..644e6baa15 100644
--- a/arch/riscv/include/asm/csr.h
+++ b/arch/riscv/include/asm/csr.h
@@ -46,6 +46,7 @@
#endif
/* Interrupt Enable and Interrupt Pending flags */
+#define MIE_MSIE _AC(0x00000008, UL) /* Software Interrupt Enable */
#define SIE_SSIE _AC(0x00000002, UL) /* Software Interrupt Enable */
#define SIE_STIE _AC(0x00000020, UL) /* Timer Interrupt Enable */
diff --git a/arch/riscv/lib/asm-offsets.c b/arch/riscv/lib/asm-offsets.c
index e0b71f5691..f998402bd1 100644
--- a/arch/riscv/lib/asm-offsets.c
+++ b/arch/riscv/lib/asm-offsets.c
@@ -14,6 +14,7 @@
int main(void)
{
DEFINE(GD_BOOT_HART, offsetof(gd_t, arch.boot_hart));
+ DEFINE(GD_AVAILABLE_HARTS, offsetof(gd_t, arch.available_harts));
return 0;
}
--
2.20.1
From f28ad250e6ef95ca58490b4e8651749d4f7e5c06 Mon Sep 17 00:00:00 2001
From: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
Date: Sun, 17 Mar 2019 19:28:38 +0100
Subject: [PATCH 07/18] riscv: boot images passed to bootm on all harts
Signed-off-by: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Tested-by: Bin Meng <bmeng.cn@gmail.com>
---
arch/riscv/lib/bootm.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/arch/riscv/lib/bootm.c b/arch/riscv/lib/bootm.c
index f36b8702ef..efbd3e23e7 100644
--- a/arch/riscv/lib/bootm.c
+++ b/arch/riscv/lib/bootm.c
@@ -13,6 +13,7 @@
#include <image.h>
#include <asm/byteorder.h>
#include <asm/csr.h>
+#include <asm/smp.h>
#include <dm/device.h>
#include <dm/root.h>
#include <u-boot/zlib.h>
@@ -81,6 +82,9 @@ static void boot_jump_linux(bootm_headers_t *images, int flag)
{
void (*kernel)(ulong hart, void *dtb);
int fake = (flag & BOOTM_STATE_OS_FAKE_GO);
+#ifdef CONFIG_SMP
+ int ret;
+#endif
kernel = (void (*)(ulong, void *))images->ep;
@@ -92,8 +96,15 @@ static void boot_jump_linux(bootm_headers_t *images, int flag)
announce_and_cleanup(fake);
if (!fake) {
- if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len)
+ if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) {
+#ifdef CONFIG_SMP
+ ret = smp_call_function(images->ep,
+ (ulong)images->ft_addr, 0);
+ if (ret)
+ hang();
+#endif
kernel(gd->arch.boot_hart, images->ft_addr);
+ }
}
}
--
2.20.1
From e04324025275dee6e3e9a968c8d12e98c9b47567 Mon Sep 17 00:00:00 2001
From: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
Date: Sun, 17 Mar 2019 19:28:39 +0100
Subject: [PATCH 08/18] riscv: do not rely on hart ID passed by previous boot
stage
RISC-V U-Boot expects the hart ID to be passed to it via register a0 by
the previous boot stage. Machine mode firmware such as BBL and OpenSBI
do this when starting their payload (U-Boot) in supervisor mode. If
U-Boot is running in machine mode, this task must be handled by the boot
ROM. Explicitly populate register a0 with the hart ID from the mhartid
CSR to avoid possible problems on RISC-V processors with a boot ROM that
does not handle this task.
Suggested-by: Rick Chen <rick@andestech.com>
Signed-off-by: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Tested-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Rick Chen <rick@andestech.com>
Tested-by: Rick Chen <rick@andestech.com>
---
arch/riscv/cpu/start.S | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/arch/riscv/cpu/start.S b/arch/riscv/cpu/start.S
index f55b8cbc37..5ac899b141 100644
--- a/arch/riscv/cpu/start.S
+++ b/arch/riscv/cpu/start.S
@@ -36,6 +36,10 @@
.section .text
.globl _start
_start:
+#ifdef CONFIG_RISCV_MMODE
+ csrr a0, mhartid
+#endif
+
/* save hart id and dtb pointer */
mv tp, a0
mv s1, a1
--
2.20.1
From 8ac39e2974d9f1395969a500e692f45717c4ccf2 Mon Sep 17 00:00:00 2001
From: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
Date: Sun, 17 Mar 2019 19:28:40 +0100
Subject: [PATCH 09/18] riscv: hang if relocation of secondary harts fails
Print an error message and hang if smp_call_function() returns an error,
indicating that relocation of the secondary harts has failed.
Signed-off-by: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Tested-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
---
arch/riscv/cpu/start.S | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/arch/riscv/cpu/start.S b/arch/riscv/cpu/start.S
index 5ac899b141..a4433fbd6b 100644
--- a/arch/riscv/cpu/start.S
+++ b/arch/riscv/cpu/start.S
@@ -33,6 +33,10 @@
#define SYM_SIZE 0x18
#endif
+.section .data
+secondary_harts_relocation_error:
+ .ascii "Relocation of secondary harts has failed, error %d\n"
+
.section .text
.globl _start
_start:
@@ -274,8 +278,15 @@ relocate_secondary_harts:
mv a2, s3
jal smp_call_function
+ /* hang if relocation of secondary harts has failed */
+ beqz a0, 1f
+ mv a1, a0
+ la a0, secondary_harts_relocation_error
+ jal printf
+ jal hang
+
/* restore relocation offset */
- mv t6, s5
+1: mv t6, s5
#endif
/*
--
2.20.1
From 0ed93a8c59d7c100241390d912329e3e45382977 Mon Sep 17 00:00:00 2001
From: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
Date: Sun, 17 Mar 2019 19:28:41 +0100
Subject: [PATCH 10/18] riscv: fu540: enable SMP
Signed-off-by: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
---
board/sifive/fu540/Kconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/board/sifive/fu540/Kconfig b/board/sifive/fu540/Kconfig
index 6be3d88144..f46437901d 100644
--- a/board/sifive/fu540/Kconfig
+++ b/board/sifive/fu540/Kconfig
@@ -38,5 +38,6 @@ config BOARD_SPECIFIC_OPTIONS # dummy
imply PHY_LIB
imply PHY_MSCC
imply SIFIVE_SERIAL
+ imply SMP
endif
--
2.20.1
From d0a8fd3e4d2a5ab19b8f2d27d40dacb4942ba5a4 Mon Sep 17 00:00:00 2001
From: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
Date: Sun, 17 Mar 2019 19:28:42 +0100
Subject: [PATCH 11/18] riscv: qemu: enable SMP
Signed-off-by: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Tested-by: Bin Meng <bmeng.cn@gmail.com>
---
board/emulation/qemu-riscv/Kconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/board/emulation/qemu-riscv/Kconfig b/board/emulation/qemu-riscv/Kconfig
index 88d07d568e..cf057e7de6 100644
--- a/board/emulation/qemu-riscv/Kconfig
+++ b/board/emulation/qemu-riscv/Kconfig
@@ -34,5 +34,6 @@ config BOARD_SPECIFIC_OPTIONS # dummy
imply BOARD_LATE_INIT
imply OF_BOARD_SETUP
imply SIFIVE_SERIAL
+ imply SMP
endif
--
2.20.1
From 0d389468e2144f3ba3bdbc566c05c0c05dc14fc6 Mon Sep 17 00:00:00 2001
From: Rick Chen <rick@andestech.com>
Date: Tue, 2 Apr 2019 15:56:39 +0800
Subject: [PATCH 12/18] riscv: Add a SYSCON driver for Andestech's PLIC
The Platform-Level Interrupt Controller (PLIC)
block holds memory-mapped claim and pending registers
associated with software interrupt. It is required
for handling IPI.
Signed-off-by: Rick Chen <rick@andestech.com>
Cc: Greentime Hu <greentime@andestech.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
---
arch/riscv/Kconfig | 9 +++
arch/riscv/include/asm/global_data.h | 3 +
arch/riscv/include/asm/syscon.h | 3 +-
arch/riscv/lib/Makefile | 1 +
arch/riscv/lib/andes_plic.c | 113 +++++++++++++++++++++++++++
5 files changed, 127 insertions(+), 2 deletions(-)
create mode 100644 arch/riscv/lib/andes_plic.c
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 3a4470daf3..511768befc 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -109,6 +109,15 @@ config SIFIVE_CLINT
The SiFive CLINT block holds memory-mapped control and status registers
associated with software and timer interrupts.
+config ANDES_PLIC
+ bool
+ depends on RISCV_MMODE
+ select REGMAP
+ select SYSCON
+ help
+ The Andes PLIC block holds memory-mapped claim and pending registers
+ associated with software interrupt.
+
config RISCV_RDTIME
bool
default y if RISCV_SMODE
diff --git a/arch/riscv/include/asm/global_data.h b/arch/riscv/include/asm/global_data.h
index 80e3165e39..b86791094b 100644
--- a/arch/riscv/include/asm/global_data.h
+++ b/arch/riscv/include/asm/global_data.h
@@ -18,6 +18,9 @@ struct arch_global_data {
#ifdef CONFIG_SIFIVE_CLINT
void __iomem *clint; /* clint base address */
#endif
+#ifdef CONFIG_ANDES_PLIC
+ void __iomem *plic; /* plic base address */
+#endif
#ifdef CONFIG_SMP
struct ipi_data ipi[CONFIG_NR_CPUS];
#endif
diff --git a/arch/riscv/include/asm/syscon.h b/arch/riscv/include/asm/syscon.h
index d311ee6b45..a086208261 100644
--- a/arch/riscv/include/asm/syscon.h
+++ b/arch/riscv/include/asm/syscon.h
@@ -8,12 +8,11 @@
/*
* System controllers in a RISC-V system
- *
- * So far only SiFive's Core Local Interruptor (CLINT) is defined.
*/
enum {
RISCV_NONE,
RISCV_SYSCON_CLINT, /* Core Local Interruptor (CLINT) */
+ RISCV_SYSCON_PLIC, /* Platform Level Interrupt Controller (PLIC) */
};
#endif /* _ASM_SYSCON_H */
diff --git a/arch/riscv/lib/Makefile b/arch/riscv/lib/Makefile
index 35dbf643e4..1bf554bad5 100644
--- a/arch/riscv/lib/Makefile
+++ b/arch/riscv/lib/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_CMD_GO) += boot.o
obj-y += cache.o
obj-$(CONFIG_RISCV_RDTIME) += rdtime.o
obj-$(CONFIG_SIFIVE_CLINT) += sifive_clint.o
+obj-$(CONFIG_ANDES_PLIC) += andes_plic.o
obj-y += interrupts.o
obj-y += reset.o
obj-$(CONFIG_SBI_IPI) += sbi_ipi.o
diff --git a/arch/riscv/lib/andes_plic.c b/arch/riscv/lib/andes_plic.c
new file mode 100644
index 0000000000..2ffe49ac90
--- /dev/null
+++ b/arch/riscv/lib/andes_plic.c
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019, Rick Chen <rick@andestech.com>
+ *
+ * U-Boot syscon driver for Andes's Platform Level Interrupt Controller (PLIC).
+ * The PLIC block holds memory-mapped claim and pending registers
+ * associated with software interrupt.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/uclass-internal.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <asm/io.h>
+#include <asm/syscon.h>
+#include <cpu.h>
+
+/* pending register */
+#define PENDING_REG(base, hart) ((ulong)(base) + 0x1000 + (hart) * 8)
+/* enable register */
+#define ENABLE_REG(base, hart) ((ulong)(base) + 0x2000 + (hart) * 0x80)
+/* claim register */
+#define CLAIM_REG(base, hart) ((ulong)(base) + 0x200004 + (hart) * 0x1000)
+
+#define ENABLE_HART_IPI (0x80808080)
+#define SEND_IPI_TO_HART(hart) (0x80 >> (hart))
+
+DECLARE_GLOBAL_DATA_PTR;
+static int init_plic(void);
+
+#define PLIC_BASE_GET(void) \
+ do { \
+ long *ret; \
+ \
+ if (!gd->arch.plic) { \
+ ret = syscon_get_first_range(RISCV_SYSCON_PLIC); \
+ if (IS_ERR(ret)) \
+ return PTR_ERR(ret); \
+ gd->arch.plic = ret; \
+ init_plic(); \
+ } \
+ } while (0)
+
+static int enable_ipi(int harts)
+{
+ int i;
+ int en = ENABLE_HART_IPI;
+
+ for (i = 0; i < harts; i++) {
+ en = en >> i;
+ writel(en, (void __iomem *)ENABLE_REG(gd->arch.plic, i));
+ }
+
+ return 0;
+}
+
+static int init_plic(void)
+{
+ struct udevice *dev;
+ int ret;
+
+ ret = uclass_find_first_device(UCLASS_CPU, &dev);
+ if (ret)
+ return ret;
+
+ if (ret == 0 && dev) {
+ ret = cpu_get_count(dev);
+ if (ret < 0)
+ return ret;
+
+ enable_ipi(ret);
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
+int riscv_send_ipi(int hart)
+{
+ PLIC_BASE_GET();
+
+ writel(SEND_IPI_TO_HART(hart),
+ (void __iomem *)PENDING_REG(gd->arch.plic, gd->arch.boot_hart));
+
+ return 0;
+}
+
+int riscv_clear_ipi(int hart)
+{
+ u32 source_id;
+
+ PLIC_BASE_GET();
+
+ source_id = readl((void __iomem *)CLAIM_REG(gd->arch.plic, hart));
+ writel(source_id, (void __iomem *)CLAIM_REG(gd->arch.plic, hart));
+
+ return 0;
+}
+
+static const struct udevice_id andes_plic_ids[] = {
+ { .compatible = "riscv,plic1", .data = RISCV_SYSCON_PLIC },
+ { }
+};
+
+U_BOOT_DRIVER(andes_plic) = {
+ .name = "andes_plic",
+ .id = UCLASS_SYSCON,
+ .of_match = andes_plic_ids,
+ .flags = DM_FLAG_PRE_RELOC,
+};
--
2.20.1
From a1f24875c346a1bf8940b793a27364631d9aabf7 Mon Sep 17 00:00:00 2001
From: Rick Chen <rick@andestech.com>
Date: Tue, 2 Apr 2019 15:56:40 +0800
Subject: [PATCH 13/18] riscv: Add a SYSCON driver for Andestech's PLMT
The platform-Level Machine Timer (PLMT) block
holds memory-mapped mtime register associated
with timer tick.
This driver implements the riscv_get_time() which
is required by the generic RISC-V timer driver.
Signed-off-by: Rick Chen <rick@andestech.com>
Cc: Greentime Hu <greentime@andestech.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
---
arch/riscv/Kconfig | 9 +++++
arch/riscv/include/asm/global_data.h | 3 ++
arch/riscv/include/asm/syscon.h | 1 +
arch/riscv/lib/Makefile | 1 +
arch/riscv/lib/andes_plmt.c | 53 ++++++++++++++++++++++++++++
5 files changed, 67 insertions(+)
create mode 100644 arch/riscv/lib/andes_plmt.c
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 511768befc..ae8ff7b765 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -118,6 +118,15 @@ config ANDES_PLIC
The Andes PLIC block holds memory-mapped claim and pending registers
associated with software interrupt.
+config ANDES_PLMT
+ bool
+ depends on RISCV_MMODE
+ select REGMAP
+ select SYSCON
+ help
+ The Andes PLMT block holds memory-mapped mtime register
+ associated with timer tick.
+
config RISCV_RDTIME
bool
default y if RISCV_SMODE
diff --git a/arch/riscv/include/asm/global_data.h b/arch/riscv/include/asm/global_data.h
index b86791094b..dffcd45bf0 100644
--- a/arch/riscv/include/asm/global_data.h
+++ b/arch/riscv/include/asm/global_data.h
@@ -21,6 +21,9 @@ struct arch_global_data {
#ifdef CONFIG_ANDES_PLIC
void __iomem *plic; /* plic base address */
#endif
+#ifdef CONFIG_ANDES_PLMT
+ void __iomem *plmt; /* plmt base address */
+#endif
#ifdef CONFIG_SMP
struct ipi_data ipi[CONFIG_NR_CPUS];
#endif
diff --git a/arch/riscv/include/asm/syscon.h b/arch/riscv/include/asm/syscon.h
index a086208261..26a008ca59 100644
--- a/arch/riscv/include/asm/syscon.h
+++ b/arch/riscv/include/asm/syscon.h
@@ -13,6 +13,7 @@ enum {
RISCV_NONE,
RISCV_SYSCON_CLINT, /* Core Local Interruptor (CLINT) */
RISCV_SYSCON_PLIC, /* Platform Level Interrupt Controller (PLIC) */
+ RISCV_SYSCON_PLMT, /* Platform Level Machine Timer (PLMT) */
};
#endif /* _ASM_SYSCON_H */
diff --git a/arch/riscv/lib/Makefile b/arch/riscv/lib/Makefile
index 1bf554bad5..1c332db436 100644
--- a/arch/riscv/lib/Makefile
+++ b/arch/riscv/lib/Makefile
@@ -12,6 +12,7 @@ obj-y += cache.o
obj-$(CONFIG_RISCV_RDTIME) += rdtime.o
obj-$(CONFIG_SIFIVE_CLINT) += sifive_clint.o
obj-$(CONFIG_ANDES_PLIC) += andes_plic.o
+obj-$(CONFIG_ANDES_PLMT) += andes_plmt.o
obj-y += interrupts.o
obj-y += reset.o
obj-$(CONFIG_SBI_IPI) += sbi_ipi.o
diff --git a/arch/riscv/lib/andes_plmt.c b/arch/riscv/lib/andes_plmt.c
new file mode 100644
index 0000000000..84f4607500
--- /dev/null
+++ b/arch/riscv/lib/andes_plmt.c
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019, Rick Chen <rick@andestech.com>
+ *
+ * U-Boot syscon driver for Andes's Platform Level Machine Timer (PLMT).
+ * The PLMT block holds memory-mapped mtime register
+ * associated with timer tick.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <asm/io.h>
+#include <asm/syscon.h>
+
+/* mtime register */
+#define MTIME_REG(base) ((ulong)(base))
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define PLMT_BASE_GET(void) \
+ do { \
+ long *ret; \
+ \
+ if (!gd->arch.plmt) { \
+ ret = syscon_get_first_range(RISCV_SYSCON_PLMT); \
+ if (IS_ERR(ret)) \
+ return PTR_ERR(ret); \
+ gd->arch.plmt = ret; \
+ } \
+ } while (0)
+
+int riscv_get_time(u64 *time)
+{
+ PLMT_BASE_GET();
+
+ *time = readq((void __iomem *)MTIME_REG(gd->arch.plmt));
+
+ return 0;
+}
+
+static const struct udevice_id andes_plmt_ids[] = {
+ { .compatible = "riscv,plmt0", .data = RISCV_SYSCON_PLMT },
+ { }
+};
+
+U_BOOT_DRIVER(andes_plmt) = {
+ .name = "andes_plmt",
+ .id = UCLASS_SYSCON,
+ .of_match = andes_plmt_ids,
+ .flags = DM_FLAG_PRE_RELOC,
+};
--
2.20.1
From 8848474c5e9093ac27f6b7cc8be156629c7d0bad Mon Sep 17 00:00:00 2001
From: Rick Chen <rick@andestech.com>
Date: Tue, 2 Apr 2019 15:56:41 +0800
Subject: [PATCH 14/18] riscv: ax25: Add platform-specific Kconfig options
Add ax25 RISC-V platform-specific Kconfig options,
to include CPU and timer drivers. Also disable
ATCPIT100 SoC timer and replace by PLMT.
Signed-off-by: Rick Chen <rick@andestech.com>
Cc: Greentime Hu <greentime@andestech.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
---
arch/riscv/cpu/ax25/Kconfig | 6 ++++++
configs/ae350_rv32_defconfig | 1 -
configs/ae350_rv64_defconfig | 1 -
3 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/arch/riscv/cpu/ax25/Kconfig b/arch/riscv/cpu/ax25/Kconfig
index e9dbca2fae..68bd4e9419 100644
--- a/arch/riscv/cpu/ax25/Kconfig
+++ b/arch/riscv/cpu/ax25/Kconfig
@@ -1,5 +1,11 @@
config RISCV_NDS
bool
+ select ARCH_EARLY_INIT_R
+ imply CPU
+ imply CPU_RISCV
+ imply RISCV_TIMER
+ imply ANDES_PLIC if RISCV_MMODE
+ imply ANDES_PLMT if RISCV_MMODE
help
Run U-Boot on AndeStar V5 platforms and use some specific features
which are provided by Andes Technology AndeStar V5 families.
diff --git a/configs/ae350_rv32_defconfig b/configs/ae350_rv32_defconfig
index 6e0be88d7c..f02945599f 100644
--- a/configs/ae350_rv32_defconfig
+++ b/configs/ae350_rv32_defconfig
@@ -34,4 +34,3 @@ CONFIG_BAUDRATE=38400
CONFIG_SYS_NS16550=y
CONFIG_SPI=y
CONFIG_ATCSPI200_SPI=y
-CONFIG_ATCPIT100_TIMER=y
diff --git a/configs/ae350_rv64_defconfig b/configs/ae350_rv64_defconfig
index b472a76d17..98635a2ff9 100644
--- a/configs/ae350_rv64_defconfig
+++ b/configs/ae350_rv64_defconfig
@@ -35,4 +35,3 @@ CONFIG_BAUDRATE=38400
CONFIG_SYS_NS16550=y
CONFIG_SPI=y
CONFIG_ATCSPI200_SPI=y
-CONFIG_ATCPIT100_TIMER=y
--
2.20.1
From dda00ae4ef357233a72c74e6c02d27b70c844422 Mon Sep 17 00:00:00 2001
From: Rick Chen <rick@andestech.com>
Date: Tue, 2 Apr 2019 15:56:42 +0800
Subject: [PATCH 15/18] riscv: ax25: Andes specific cache shall only support in
M-mode
Limit the cache configuration only can be supported in M mode.
It can not be manipulated in S mode.
Signed-off-by: Rick Chen <rick@andestech.com>
Cc: Greentime Hu <greentime@andestech.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
---
arch/riscv/cpu/ax25/Kconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/riscv/cpu/ax25/Kconfig b/arch/riscv/cpu/ax25/Kconfig
index 68bd4e9419..6b4b92e692 100644
--- a/arch/riscv/cpu/ax25/Kconfig
+++ b/arch/riscv/cpu/ax25/Kconfig
@@ -14,6 +14,7 @@ if RISCV_NDS
config RISCV_NDS_CACHE
bool "AndeStar V5 families specific cache support"
+ depends on RISCV_MMODE
help
Provide Andes Technology AndeStar V5 families specific cache support.
--
2.20.1
From a1ce531ab24b1ef5e69dbf29ecbfc6898b454ec1 Mon Sep 17 00:00:00 2001
From: Rick Chen <rick@andestech.com>
Date: Tue, 2 Apr 2019 15:56:43 +0800
Subject: [PATCH 16/18] riscv: dts: ae350 support SMP
Signed-off-by: Rick Chen <rick@andestech.com>
Cc: Greentime Hu <greentime@andestech.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
---
arch/riscv/dts/ae350_32.dts | 81 +++++++++++++++++++++++++++----------
arch/riscv/dts/ae350_64.dts | 81 +++++++++++++++++++++++++++----------
2 files changed, 118 insertions(+), 44 deletions(-)
diff --git a/arch/riscv/dts/ae350_32.dts b/arch/riscv/dts/ae350_32.dts
index 0679827313..2ec01a5ce7 100644
--- a/arch/riscv/dts/ae350_32.dts
+++ b/arch/riscv/dts/ae350_32.dts
@@ -26,16 +26,49 @@
status = "okay";
compatible = "riscv";
riscv,isa = "rv32imafdc";
+ riscv,priv-major = <1>;
+ riscv,priv-minor = <10>;
mmu-type = "riscv,sv32";
clock-frequency = <60000000>;
+ i-cache-size = <0x8000>;
+ i-cache-line-size = <32>;
d-cache-size = <0x8000>;
d-cache-line-size = <32>;
+ next-level-cache = <&L2>;
CPU0_intc: interrupt-controller {
#interrupt-cells = <1>;
interrupt-controller;
compatible = "riscv,cpu-intc";
};
};
+ CPU1: cpu@1 {
+ device_type = "cpu";
+ reg = <1>;
+ status = "okay";
+ compatible = "riscv";
+ riscv,isa = "rv32imafdc";
+ riscv,priv-major = <1>;
+ riscv,priv-minor = <10>;
+ mmu-type = "riscv,sv32";
+ clock-frequency = <60000000>;
+ i-cache-size = <0x8000>;
+ i-cache-line-size = <32>;
+ d-cache-size = <0x8000>;
+ d-cache-line-size = <32>;
+ next-level-cache = <&L2>;
+ CPU1_intc: interrupt-controller {
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ compatible = "riscv,cpu-intc";
+ };
+ };
+
+ L2: l2-cache@e0500000 {
+ compatible = "cache";
+ cache-level = <2>;
+ cache-size = <0x40000>;
+ reg = <0x0 0xe0500000 0x0 0x40000>;
+ };
};
memory@0 {
@@ -46,32 +79,32 @@
soc {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "andestech,riscv-ae350-soc";
+ compatible = "simple-bus";
ranges;
- plic0: interrupt-controller@e4000000 {
- compatible = "riscv,plic0";
- #address-cells = <1>;
- #interrupt-cells = <1>;
- interrupt-controller;
- reg = <0xe4000000 0x2000000>;
- riscv,ndev=<71>;
- interrupts-extended = <&CPU0_intc 11 &CPU0_intc 9>;
- };
+ plic0: interrupt-controller@e4000000 {
+ compatible = "riscv,plic0";
+ #address-cells = <1>;
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ reg = <0xe4000000 0x2000000>;
+ riscv,ndev=<71>;
+ interrupts-extended = <&CPU0_intc 11 &CPU0_intc 9 &CPU1_intc 11 &CPU1_intc 9>;
+ };
- plic1: interrupt-controller@e6400000 {
- compatible = "riscv,plic1";
- #address-cells = <1>;
- #interrupt-cells = <1>;
- interrupt-controller;
- reg = <0xe6400000 0x400000>;
- riscv,ndev=<1>;
- interrupts-extended = <&CPU0_intc 3>;
- };
+ plic1: interrupt-controller@e6400000 {
+ compatible = "riscv,plic1";
+ #address-cells = <1>;
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ reg = <0xe6400000 0x400000>;
+ riscv,ndev=<2>;
+ interrupts-extended = <&CPU0_intc 3 &CPU1_intc 3>;
+ };
- plmt0@e6000000 {
- compatible = "riscv,plmt0";
- interrupts-extended = <&CPU0_intc 7>;
+ plmt0@e6000000 {
+ compatible = "riscv,plmt0";
+ interrupts-extended = <&CPU0_intc 7 &CPU1_intc 7>;
reg = <0xe6000000 0x100000>;
};
};
@@ -146,6 +179,10 @@
interrupt-parent = <&plic0>;
};
+ pmu {
+ compatible = "riscv,base-pmu";
+ };
+
virtio_mmio@fe007000 {
interrupts = <0x17 0x4>;
interrupt-parent = <0x2>;
diff --git a/arch/riscv/dts/ae350_64.dts b/arch/riscv/dts/ae350_64.dts
index e48c298645..cde5cdeff8 100644
--- a/arch/riscv/dts/ae350_64.dts
+++ b/arch/riscv/dts/ae350_64.dts
@@ -26,16 +26,49 @@
status = "okay";
compatible = "riscv";
riscv,isa = "rv64imafdc";
+ riscv,priv-major = <1>;
+ riscv,priv-minor = <10>;
mmu-type = "riscv,sv39";
clock-frequency = <60000000>;
+ i-cache-size = <0x8000>;
+ i-cache-line-size = <32>;
d-cache-size = <0x8000>;
d-cache-line-size = <32>;
+ next-level-cache = <&L2>;
CPU0_intc: interrupt-controller {
#interrupt-cells = <1>;
interrupt-controller;
compatible = "riscv,cpu-intc";
};
};
+ CPU1: cpu@1 {
+ device_type = "cpu";
+ reg = <1>;
+ status = "okay";
+ compatible = "riscv";
+ riscv,isa = "rv64imafdc";
+ riscv,priv-major = <1>;
+ riscv,priv-minor = <10>;
+ mmu-type = "riscv,sv39";
+ clock-frequency = <60000000>;
+ i-cache-size = <0x8000>;
+ i-cache-line-size = <32>;
+ d-cache-size = <0x8000>;
+ d-cache-line-size = <32>;
+ next-level-cache = <&L2>;
+ CPU1_intc: interrupt-controller {
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ compatible = "riscv,cpu-intc";
+ };
+ };
+
+ L2: l2-cache@e0500000 {
+ compatible = "cache";
+ cache-level = <2>;
+ cache-size = <0x40000>;
+ reg = <0x0 0xe0500000 0x0 0x40000>;
+ };
};
memory@0 {
@@ -46,32 +79,32 @@
soc {
#address-cells = <2>;
#size-cells = <2>;
- compatible = "andestech,riscv-ae350-soc";
+ compatible = "simple-bus";
ranges;
- plic0: interrupt-controller@e4000000 {
- compatible = "riscv,plic0";
- #address-cells = <2>;
- #interrupt-cells = <2>;
- interrupt-controller;
- reg = <0x0 0xe4000000 0x0 0x2000000>;
- riscv,ndev=<71>;
- interrupts-extended = <&CPU0_intc 11 &CPU0_intc 9>;
- };
+ plic0: interrupt-controller@e4000000 {
+ compatible = "riscv,plic0";
+ #address-cells = <2>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ reg = <0x0 0xe4000000 0x0 0x2000000>;
+ riscv,ndev=<71>;
+ interrupts-extended = <&CPU0_intc 11 &CPU0_intc 9 &CPU1_intc 11 &CPU1_intc 9>;
+ };
- plic1: interrupt-controller@e6400000 {
- compatible = "riscv,plic1";
- #address-cells = <2>;
- #interrupt-cells = <2>;
- interrupt-controller;
- reg = <0x0 0xe6400000 0x0 0x400000>;
- riscv,ndev=<1>;
- interrupts-extended = <&CPU0_intc 3>;
- };
+ plic1: interrupt-controller@e6400000 {
+ compatible = "riscv,plic1";
+ #address-cells = <2>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ reg = <0x0 0xe6400000 0x0 0x400000>;
+ riscv,ndev=<2>;
+ interrupts-extended = <&CPU0_intc 3 &CPU1_intc 3>;
+ };
- plmt0@e6000000 {
- compatible = "riscv,plmt0";
- interrupts-extended = <&CPU0_intc 7>;
+ plmt0@e6000000 {
+ compatible = "riscv,plmt0";
+ interrupts-extended = <&CPU0_intc 7 &CPU1_intc 7>;
reg = <0x0 0xe6000000 0x0 0x100000>;
};
};
@@ -146,6 +179,10 @@
interrupt-parent = <&plic0>;
};
+ pmu {
+ compatible = "riscv,base-pmu";
+ };
+
virtio_mmio@fe007000 {
interrupts = <0x17 0x4>;
interrupt-parent = <0x2>;
--
2.20.1
From 076b845893f3bb59dfad80b012d28191c19e2f7b Mon Sep 17 00:00:00 2001
From: Rick Chen <rick@andestech.com>
Date: Tue, 2 Apr 2019 15:56:44 +0800
Subject: [PATCH 17/18] riscv: ae350: enable SMP
Signed-off-by: Rick Chen <rick@andestech.com>
Cc: Greentime Hu <greentime@andestech.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
---
board/AndesTech/ax25-ae350/Kconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/board/AndesTech/ax25-ae350/Kconfig b/board/AndesTech/ax25-ae350/Kconfig
index 44cb302f70..5e682b679d 100644
--- a/board/AndesTech/ax25-ae350/Kconfig
+++ b/board/AndesTech/ax25-ae350/Kconfig
@@ -24,5 +24,6 @@ config ENV_OFFSET
config BOARD_SPECIFIC_OPTIONS # dummy
def_bool y
select RISCV_NDS
+ imply SMP
endif
--
2.20.1
From 48b90d9db5d32e587901c4f33175488dd20fe0a5 Mon Sep 17 00:00:00 2001
From: Rick Chen <rick@andestech.com>
Date: Wed, 3 Apr 2019 10:43:37 +0800
Subject: [PATCH 18/18] riscv: dts: fix CONFIG_DEFAULT_DEVICE_TREE failure
It occurs since commit 27cb7300ffda
("Ensure device tree DTS is compiled").
More details can refer to
89c2b5c02049aea746b1edee0b4e1d8519dec2f4
ARM: fix arch/arm/dts/Makefile
Signed-off-by: Rick Chen <rick@andestech.com>
Cc: Greentime Hu <greentime@andestech.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
---
arch/riscv/dts/Makefile | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/riscv/dts/Makefile b/arch/riscv/dts/Makefile
index b400defb38..f9cd606a9a 100644
--- a/arch/riscv/dts/Makefile
+++ b/arch/riscv/dts/Makefile
@@ -1,5 +1,7 @@
# SPDX-License-Identifier: GPL-2.0+
+dtb-$(CONFIG_TARGET_AX25_AE350) += ae350_32.dtb ae350_64.dtb
+
targets += $(dtb-y)
DTC_FLAGS += -R 4 -p 0x1000
--
2.20.1