config SMP
bool "Symmetric Multi-Processing"
+ depends on SBI_V01 || !RISCV_SMODE
help
This enables support for systems with more than one CPU. If
you say N here, U-Boot will run on single and multiprocessor
machine. If you say Y here, U-Boot will run on many, but not
all, single processor machines.
+config SPL_SMP
+ bool "Symmetric Multi-Processing in SPL"
+ depends on SPL && SPL_RISCV_MMODE
+ default y
+ help
+ This enables support for systems with more than one CPU in SPL.
+ If you say N here, U-Boot SPL will run on single and multiprocessor
+ machines, but will use only one CPU of a multiprocessor
+ machine. If you say Y here, U-Boot SPL 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
+ depends on SMP || SPL_SMP
default 8
help
On multiprocessor machines, U-Boot sets up a stack for each CPU.
bool
default y if RISCV_SMODE || SPL_RISCV_SMODE
+choice
+ prompt "SBI support"
+ default SBI_V02
+
config SBI_V01
bool "SBI v0.1 support"
- default y
depends on SBI
help
This config allows kernel to use SBI v0.1 APIs. This will be
deprecated in future once legacy M-mode software are no longer in use.
+config SBI_V02
+ bool "SBI v0.2 support"
+ depends on SBI
+ help
+ This config allows kernel to use SBI v0.2 APIs. SBI v0.2 is more
+ scalable and extendable to handle future needs for RISC-V supervisor
+ interfaces. For example, with SBI v0.2 HSM extension, only a single
+ hart need to boot and enter operating system. The booting hart can
+ bring up secondary harts one by one afterwards.
+
+ Choose this option if OpenSBI v0.7 or above release is used together
+ with U-Boot.
+
+endchoice
+
config SBI_IPI
bool
depends on SBI
#include <asm/csr.h>
#ifdef CONFIG_RISCV_NDS_CACHE
-#if CONFIG_IS_ENABLED(RISCV_MMODE) || CONFIG_IS_ENABLED(SPL_RISCV_MMODE)
+#if CONFIG_IS_ENABLED(RISCV_MMODE)
/* mcctlcommand */
#define CCTL_REG_MCCTLCOMMAND_NUM 0x7cc
{
#if !CONFIG_IS_ENABLED(SYS_ICACHE_OFF)
#ifdef CONFIG_RISCV_NDS_CACHE
-#if CONFIG_IS_ENABLED(RISCV_MMODE) || CONFIG_IS_ENABLED(SPL_RISCV_MMODE)
+#if CONFIG_IS_ENABLED(RISCV_MMODE)
csr_write(CCTL_REG_MCCTLCOMMAND_NUM, CCTL_L1D_WBINVAL_ALL);
#endif
#endif
{
#if !CONFIG_IS_ENABLED(SYS_ICACHE_OFF)
#ifdef CONFIG_RISCV_NDS_CACHE
-#if CONFIG_IS_ENABLED(RISCV_MMODE) || CONFIG_IS_ENABLED(SPL_RISCV_MMODE)
+#if CONFIG_IS_ENABLED(RISCV_MMODE)
asm volatile (
"csrr t1, mcache_ctl\n\t"
"ori t0, t1, 0x1\n\t"
{
#if !CONFIG_IS_ENABLED(SYS_ICACHE_OFF)
#ifdef CONFIG_RISCV_NDS_CACHE
-#if CONFIG_IS_ENABLED(RISCV_MMODE) || CONFIG_IS_ENABLED(SPL_RISCV_MMODE)
+#if CONFIG_IS_ENABLED(RISCV_MMODE)
asm volatile (
"fence.i\n\t"
"csrr t1, mcache_ctl\n\t"
{
#if !CONFIG_IS_ENABLED(SYS_DCACHE_OFF)
#ifdef CONFIG_RISCV_NDS_CACHE
-#if CONFIG_IS_ENABLED(RISCV_MMODE) || CONFIG_IS_ENABLED(SPL_RISCV_MMODE)
+#if CONFIG_IS_ENABLED(RISCV_MMODE)
asm volatile (
"csrr t1, mcache_ctl\n\t"
"ori t0, t1, 0x2\n\t"
{
#if !CONFIG_IS_ENABLED(SYS_DCACHE_OFF)
#ifdef CONFIG_RISCV_NDS_CACHE
-#if CONFIG_IS_ENABLED(RISCV_MMODE) || CONFIG_IS_ENABLED(SPL_RISCV_MMODE)
+#if CONFIG_IS_ENABLED(RISCV_MMODE)
csr_write(CCTL_REG_MCCTLCOMMAND_NUM, CCTL_L1D_WBINVAL_ALL);
asm volatile (
"csrr t1, mcache_ctl\n\t"
int ret = 0;
#ifdef CONFIG_RISCV_NDS_CACHE
-#if CONFIG_IS_ENABLED(RISCV_MMODE) || CONFIG_IS_ENABLED(SPL_RISCV_MMODE)
+#if CONFIG_IS_ENABLED(RISCV_MMODE)
asm volatile (
"csrr t1, mcache_ctl\n\t"
"andi %0, t1, 0x01\n\t"
int ret = 0;
#ifdef CONFIG_RISCV_NDS_CACHE
-#if CONFIG_IS_ENABLED(RISCV_MMODE) || CONFIG_IS_ENABLED(SPL_RISCV_MMODE)
+#if CONFIG_IS_ENABLED(RISCV_MMODE)
asm volatile (
"csrr t1, mcache_ctl\n\t"
"andi %0, t1, 0x02\n\t"
*/
#include <common.h>
-#include <dm.h>
#include <irq_func.h>
/*
return 0;
}
-
-/* To enumerate devices on the /soc/ node, create a "simple-bus" driver */
-static const struct udevice_id riscv_virtio_soc_ids[] = {
- { .compatible = "riscv-virtio-soc" },
- { }
-};
-
-U_BOOT_DRIVER(riscv_virtio_soc) = {
- .name = "riscv_virtio_soc",
- .id = UCLASS_SIMPLE_BUS,
- .of_match = riscv_virtio_soc_ids,
- .flags = DM_FLAG_PRE_RELOC,
-};
/* mask all interrupts */
csrw MODE_PREFIX(ie), zero
-#ifdef CONFIG_SMP
+#if CONFIG_IS_ENABLED(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 */
#if CONFIG_IS_ENABLED(RISCV_MMODE)
li t0, MIE_MSIE
mv gp, a0
/* setup stack */
-#ifdef CONFIG_SMP
+#if CONFIG_IS_ENABLED(SMP)
/* tp: hart id */
slli t0, tp, CONFIG_STACK_SIZE_SHIFT
sub sp, a0, t0
jal board_init_f_init_reserve
+ SREG s1, GD_FIRMWARE_FDT_ADDR(gp)
/* save the boot hart id to global_data */
SREG tp, GD_BOOT_HART(gp)
mv s0, a0
/* setup stack on main hart */
-#ifdef CONFIG_SMP
+#if CONFIG_IS_ENABLED(SMP)
/* tp: hart id */
slli t0, tp, CONFIG_STACK_SIZE_SHIFT
sub sp, s0, t0
*Set up the stack
*/
stack_setup:
-#ifdef CONFIG_SMP
+#if CONFIG_IS_ENABLED(SMP)
/* tp: hart id */
slli t0, tp, CONFIG_STACK_SIZE_SHIFT
sub sp, s2, t0
blt t0, t1, clbss_l
relocate_secondary_harts:
-#ifdef CONFIG_SMP
+#if CONFIG_IS_ENABLED(SMP)
/* send relocation IPI */
la t0, secondary_hart_relocate
add a0, t0, t6
*/
jr t4 /* jump to board_init_r() */
-#ifdef CONFIG_SMP
+#if CONFIG_IS_ENABLED(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 */
secondary_hart_loop:
wfi
-#ifdef CONFIG_SMP
+#if CONFIG_IS_ENABLED(SMP)
csrr t0, MODE_PREFIX(ip)
#if CONFIG_IS_ENABLED(RISCV_MMODE)
andi t0, t0, MIE_MSIE
/* Architecture-specific global data */
struct arch_global_data {
long boot_hart; /* boot hart id */
+ phys_addr_t firmware_fdt_addr;
#ifdef CONFIG_SIFIVE_CLINT
void __iomem *clint; /* clint base address */
#endif
#ifdef CONFIG_ANDES_PLMT
void __iomem *plmt; /* plmt base address */
#endif
-#ifdef CONFIG_SMP
+#if CONFIG_IS_ENABLED(SMP)
struct ipi_data ipi[CONFIG_NR_CPUS];
#endif
#ifndef CONFIG_XIP
/* board/.../... */
int board_init(void);
void board_quiesce_devices(void);
+int riscv_board_reserved_mem_fixup(void *fdt);
+int riscv_fdt_copy_resv_mem_node(const void *src_fdt, void *dest_fdt);
#endif /* _U_BOOT_RISCV_H_ */
obj-y += interrupts.o
obj-y += reset.o
obj-y += setjmp.o
-obj-$(CONFIG_SMP) += smp.o
+obj-$(CONFIG_$(SPL_)SMP) += smp.o
obj-$(CONFIG_SPL_BUILD) += spl.o
+obj-y += fdt_fixup.o
# For building EFI apps
CFLAGS_$(EFI_CRT0) := $(CFLAGS_EFI)
int main(void)
{
DEFINE(GD_BOOT_HART, offsetof(gd_t, arch.boot_hart));
+ DEFINE(GD_FIRMWARE_FDT_ADDR, offsetof(gd_t, arch.firmware_fdt_addr));
#ifndef CONFIG_XIP
DEFINE(GD_AVAILABLE_HARTS, offsetof(gd_t, arch.available_harts));
#endif
{
}
-int arch_fixup_fdt(void *blob)
-{
- return 0;
-}
-
/**
* announce_and_cleanup() - Print message and prepare for kernel boot
*
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates
+ *
+ */
+
+#include <common.h>
+#include <fdt_support.h>
+#include <mapmem.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/**
+ * riscv_fdt_copy_resv_mem_node() - Copy reserve memory node entry
+ * @src: Pointer to the source device tree from which reserved memory node
+ * needs to be copied.
+ * @dst: Pointer to the destination device tree to which reserved memory node
+ * needs to be copied.
+ *
+ * Return: 0 on success or if source doesn't have reserved memory node.
+ * Error if copy process failed.
+ */
+int riscv_fdt_copy_resv_mem_node(const void *src, void *dst)
+{
+ u32 phandle;
+ struct fdt_memory pmp_mem;
+ fdt_addr_t addr;
+ fdt_size_t size;
+ int offset, node, err, rmem_offset;
+ bool nomap = true;
+ char basename[32] = {0};
+ int bname_len;
+ int max_len = sizeof(basename);
+ const char *name;
+ char *temp;
+
+ offset = fdt_path_offset(src, "/reserved-memory");
+ if (offset < 0) {
+ printf("No reserved memory region found in source FDT\n");
+ return 0;
+ }
+
+ fdt_for_each_subnode(node, src, offset) {
+ name = fdt_get_name(src, node, NULL);
+
+ addr = fdtdec_get_addr_size_auto_noparent(src, node,
+ "reg", 0, &size,
+ false);
+ if (addr == FDT_ADDR_T_NONE) {
+ debug("failed to read address/size for %s\n", name);
+ continue;
+ }
+ strncpy(basename, name, max_len);
+ temp = strchr(basename, '@');
+ if (temp) {
+ bname_len = strnlen(basename, max_len) - strnlen(temp,
+ max_len);
+ *(basename + bname_len) = '\0';
+ }
+ pmp_mem.start = addr;
+ pmp_mem.end = addr + size - 1;
+ err = fdtdec_add_reserved_memory(dst, basename, &pmp_mem,
+ &phandle);
+ if (err < 0) {
+ printf("failed to add reserved memory: %d\n", err);
+ return err;
+ }
+ if (!fdt_getprop(src, node, "no-map", NULL))
+ nomap = false;
+ if (nomap) {
+ rmem_offset = fdt_node_offset_by_phandle(dst, phandle);
+ fdt_setprop_empty(dst, rmem_offset, "no-map");
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * riscv_board_reserved_mem_fixup() - Fix up reserved memory node for a board
+ * @fdt: Pointer to the device tree in which reserved memory node needs to be
+ * added.
+ *
+ * In RISC-V, any board compiled with OF_SEPARATE needs to copy the reserved
+ * memory node from the device tree provided by the firmware to the device tree
+ * used by U-Boot. This is a common function that individual board fixup
+ * functions can invoke.
+ *
+ * Return: 0 on success or error otherwise.
+ */
+int riscv_board_reserved_mem_fixup(void *fdt)
+{
+ int err;
+ void *src_fdt_addr;
+
+ src_fdt_addr = map_sysmem(gd->arch.firmware_fdt_addr, 0);
+ err = riscv_fdt_copy_resv_mem_node(src_fdt_addr, fdt);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+#ifdef CONFIG_OF_BOARD_FIXUP
+int board_fix_fdt(void *fdt)
+{
+ int err;
+
+ err = riscv_board_reserved_mem_fixup(fdt);
+ if (err < 0) {
+ printf("failed to fixup DT for reserved memory: %d\n", err);
+ return err;
+ }
+
+ return 0;
+}
+#endif
+
+int arch_fixup_fdt(void *blob)
+{
+ int err;
+#ifdef CONFIG_EFI_LOADER
+ u32 size;
+ int chosen_offset;
+
+ size = fdt_totalsize(blob);
+ err = fdt_open_into(blob, blob, size + 32);
+ if (err < 0) {
+ printf("Device Tree can't be expanded to accommodate new node");
+ return err;
+ }
+ chosen_offset = fdt_path_offset(blob, "/chosen");
+ if (chosen_offset < 0) {
+ err = fdt_add_subnode(blob, 0, "chosen");
+ if (err < 0) {
+ printf("chosen node can not be added\n");
+ return err;
+ }
+ }
+ /* Overwrite the boot-hartid as U-Boot is the last stage BL */
+ fdt_setprop_u32(blob, chosen_offset, "boot-hartid", gd->arch.boot_hart);
+#endif
+
+ /* Copy the reserved-memory node to the DT used by OS */
+ err = riscv_fdt_copy_resv_mem_node(gd->fdt_blob, blob);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
invalidate_icache_all();
debug("image entry point: 0x%lX\n", spl_image->entry_point);
-#ifdef CONFIG_SMP
+#ifdef CONFIG_SPL_SMP
ret = smp_call_function(spl_image->entry_point, (ulong)fdt_blob, 0, 0);
if (ret)
hang();
imply CMD_EXT4
imply CMD_FAT
imply BOARD_LATE_INIT
- imply OF_BOARD_SETUP
imply SIFIVE_SERIAL
imply SMP
imply PCI
return 0;
}
-/*
- * QEMU specifies the location of Linux (supplied with the -kernel argument)
- * in the device tree using the riscv,kernel-start and riscv,kernel-end
- * properties. We currently rely on the SBI implementation of BBL to run
- * Linux and therefore embed Linux as payload in BBL. This causes an issue,
- * because BBL detects the kernel properties in the device tree and ignores
- * the Linux payload as a result. To work around this issue, we clear the
- * kernel properties before booting Linux.
- *
- * This workaround can be removed, once we do not require BBL for its SBI
- * implementation anymore.
- */
-int ft_board_setup(void *blob, bd_t *bd)
-{
- int chosen_offset, ret;
-
- chosen_offset = fdt_path_offset(blob, "/chosen");
- if (chosen_offset < 0)
- return 0;
-
-#ifdef CONFIG_ARCH_RV64I
- ret = fdt_setprop_u64(blob, chosen_offset, "riscv,kernel-start", 0);
-#else
- ret = fdt_setprop_u32(blob, chosen_offset, "riscv,kernel-start", 0);
-#endif
- if (ret)
- return ret;
-
-#ifdef CONFIG_ARCH_RV64I
- ret = fdt_setprop_u64(blob, chosen_offset, "riscv,kernel-end", 0);
-#else
- ret = fdt_setprop_u32(blob, chosen_offset, "riscv,kernel-end", 0);
-#endif
- if (ret)
- return ret;
-
- return 0;
-}
-
#ifdef CONFIG_SPL
u32 spl_boot_device(void)
{
opensbi_entry = (void (*)(ulong, ulong, ulong))spl_image->entry_point;
invalidate_icache_all();
-#ifdef CONFIG_SMP
+#ifdef CONFIG_SPL_SMP
/*
* Start OpenSBI on all secondary harts and wait for acknowledgment.
*
CONFIG_MISC_INIT_R=y
CONFIG_DISPLAY_CPUINFO=y
CONFIG_DISPLAY_BOARDINFO=y
+CONFIG_OF_BOARD_FIXUP=y
CONFIG_DEFAULT_DEVICE_TREE="hifive-unleashed-a00"
CONFIG_SYS_RELOC_GD_ENV_ADDR=y
CONFIG_DM_MTD=y
with OpenSBI, see the documentation available with OpenSBI:
https://github.com/riscv/opensbi/blob/master/docs/platform/qemu_virt.md
-These have been tested in QEMU 3.0.0.
+These have been tested in QEMU 4.2.0.
Running U-Boot SPL
------------------
continue;
}
- if (addr == carveout->start && (addr + size) == carveout->end) {
+ if (addr == carveout->start && (addr + size - 1) ==
+ carveout->end) {
if (phandlep)
*phandlep = fdt_get_phandle(blob, node);
return 0;