diff --git a/uboot-riscv-apr8-smp.patch b/uboot-riscv-apr8-smp.patch new file mode 100644 index 0000000..e95c585 --- /dev/null +++ b/uboot-riscv-apr8-smp.patch @@ -0,0 +1,1863 @@ +From fa33f08fd657b8568ede929df8a79bd113e9c5b1 Mon Sep 17 00:00:00 2001 +From: Lukas Auer +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 +Reviewed-by: Anup Patel +Reviewed-by: Bin Meng +Tested-by: Bin Meng +--- + 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 ++ + /* 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 +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 ++ */ ++ ++#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 ++ */ ++ ++#include ++#include ++#include ++#include ++ ++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", ®); ++ 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 +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 +Reviewed-by: Anup Patel +Reviewed-by: Bin Meng +Reviewed-by: Atish Patra +--- + 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 ++ ++#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 +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 +Reviewed-by: Anup Patel +Reviewed-by: Bin Meng +Reviewed-by: Atish Patra +Tested-by: Bin Meng +--- + 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 ++ */ ++ ++#include ++#include ++ ++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 +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 +Reviewed-by: Anup Patel +Reviewed-by: Bin Meng +--- + 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 +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 +Reviewed-by: Bin Meng +Reviewed-by: Rick Chen +Reviewed-by: Anup Patel +--- + 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 +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 +Reviewed-by: Anup Patel +Reviewed-by: Bin Meng +Tested-by: Bin Meng +--- + 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 + + /* +- * 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 + #include + #include ++#include + #include + #include + +@@ -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 +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 +Reviewed-by: Anup Patel +Reviewed-by: Bin Meng +Tested-by: Bin Meng +--- + 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 + #include + #include ++#include + #include + #include + #include +@@ -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 +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 +Signed-off-by: Lukas Auer +Reviewed-by: Anup Patel +Reviewed-by: Atish Patra +Reviewed-by: Bin Meng +Tested-by: Bin Meng +Reviewed-by: Rick Chen +Tested-by: Rick Chen +--- + 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 +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 +Reviewed-by: Bin Meng +Tested-by: Bin Meng +Reviewed-by: Anup Patel +--- + 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 +Date: Sun, 17 Mar 2019 19:28:41 +0100 +Subject: [PATCH 10/18] riscv: fu540: enable SMP + +Signed-off-by: Lukas Auer +Reviewed-by: Anup Patel +Reviewed-by: Bin Meng +--- + 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 +Date: Sun, 17 Mar 2019 19:28:42 +0100 +Subject: [PATCH 11/18] riscv: qemu: enable SMP + +Signed-off-by: Lukas Auer +Reviewed-by: Anup Patel +Reviewed-by: Bin Meng +Tested-by: Bin Meng +--- + 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 +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 +Cc: Greentime Hu +Reviewed-by: Bin Meng +Reviewed-by: Lukas Auer +--- + 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 ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* 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 +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 +Cc: Greentime Hu +Reviewed-by: Bin Meng +Reviewed-by: Lukas Auer +--- + 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 ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++ ++/* 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 +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 +Cc: Greentime Hu +Reviewed-by: Bin Meng +Reviewed-by: Lukas Auer +--- + 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 +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 +Cc: Greentime Hu +Reviewed-by: Bin Meng +Reviewed-by: Lukas Auer +--- + 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 +Date: Tue, 2 Apr 2019 15:56:43 +0800 +Subject: [PATCH 16/18] riscv: dts: ae350 support SMP + +Signed-off-by: Rick Chen +Cc: Greentime Hu +Reviewed-by: Bin Meng +Reviewed-by: Lukas Auer +--- + 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 +Date: Tue, 2 Apr 2019 15:56:44 +0800 +Subject: [PATCH 17/18] riscv: ae350: enable SMP + +Signed-off-by: Rick Chen +Cc: Greentime Hu +Reviewed-by: Bin Meng +Reviewed-by: Lukas Auer +--- + 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 +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 +Cc: Greentime Hu +Reviewed-by: Bin Meng +Reviewed-by: Lukas Auer +--- + 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 + diff --git a/uboot-tools.spec b/uboot-tools.spec index 7836da4..0c29573 100644 --- a/uboot-tools.spec +++ b/uboot-tools.spec @@ -2,7 +2,7 @@ Name: uboot-tools Version: 2019.04 -Release: 0.6%{?candidate:.%{candidate}}.4.riscv64%{?dist} +Release: 0.6%{?candidate:.%{candidate}}.5.riscv64%{?dist} Summary: U-Boot utilities License: GPLv2+ BSD LGPL-2.1+ LGPL-2.0+ URL: http://www.denx.de/wiki/U-Boot @@ -32,6 +32,8 @@ Patch14: net-eth-uclass-Write-MAC-address-to-hardware-after-probe.patch # RISC-V (riscv64) Patch30: u-boot-2019.04-rc4-riscv.patch +# See: https://lists.denx.de/pipermail/u-boot/2019-April/364281.html +Patch31: uboot-riscv-apr8-smp.patch BuildRequires: bc BuildRequires: dtc @@ -352,6 +354,10 @@ cp -p board/warp7/README builds/docs/README.warp7 %endif %changelog +* Mon Apr 08 2019 David Abdurachmanov 2019.04-0.6-rc4.5.riscv64 +- Apply pull request which incl. SMP support + See: https://lists.denx.de/pipermail/u-boot/2019-April/364281.html + * Fri Apr 05 2019 David Abdurachmanov 2019.04-0.6-rc4.3.riscv64 - Set CONFIG_SYS_BOOTM_LEN to SZ_64M for qemu-riscv