summaryrefslogtreecommitdiffstats
path: root/arch/riscv/boot/board-dt-2nd.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/riscv/boot/board-dt-2nd.c')
-rw-r--r--arch/riscv/boot/board-dt-2nd.c89
1 files changed, 89 insertions, 0 deletions
diff --git a/arch/riscv/boot/board-dt-2nd.c b/arch/riscv/boot/board-dt-2nd.c
new file mode 100644
index 0000000000..f1479d8346
--- /dev/null
+++ b/arch/riscv/boot/board-dt-2nd.c
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <common.h>
+#include <asm/sections.h>
+#include <linux/sizes.h>
+#include <asm/ns16550.h>
+#include <pbl.h>
+#include <fdt.h>
+
+#if __riscv_xlen == 64
+#define IMAGE_LOAD_OFFSET 0x200000 /* Image load offset(2MB) from start of RAM */
+#else
+#define IMAGE_LOAD_OFFSET 0x400000 /* Image load offset(4MB) from start of RAM */
+#endif
+
+/* because we can depend on being loaded at an offset, we can just use
+ * our load address as stack top
+ */
+#define __barebox_riscv_head() \
+ __barebox_riscv_header("auipc sp, 0", IMAGE_LOAD_OFFSET, \
+ RISCV_HEADER_VERSION, "RISCV", RISCV_IMAGE_MAGIC2)
+
+#include <asm/barebox-riscv.h>
+
+static void virt_ns16550_putc(void *base, int ch)
+{
+ early_ns16550_putc(ch, base, 0, readb, writeb);
+}
+
+static void virt_ns16550_init(void)
+{
+ void __iomem *base = IOMEM(0x10000000);
+
+ early_ns16550_init(base, 3686400 / CONFIG_BAUDRATE, 0, writeb);
+ pbl_set_putc(virt_ns16550_putc, base);
+}
+
+static const struct fdt_device_id console_ids[] = {
+ { .compatible = "riscv-virtio", .data = virt_ns16550_init },
+ { /* sentinel */ }
+};
+
+static void noinline __noreturn start_dt_2nd_nonnaked(unsigned long hartid,
+ unsigned long _fdt)
+{
+ unsigned long membase, memsize, endmem, endfdt, uncompressed_len;
+ struct fdt_header *fdt = (void *)_fdt;
+ void (*pbl_uart_init)(void);
+
+ if (!fdt)
+ hang();
+
+ /*
+ * We need to call this here, as a multiplatform build
+ * depends on querying mode for riscv_vendor_id()
+ */
+ riscv_set_flags(RISCV_S_MODE);
+
+ relocate_to_current_adr();
+ setup_c();
+
+ pbl_uart_init = fdt_device_get_match_data(fdt, "/", console_ids);
+ if (pbl_uart_init) {
+ pbl_uart_init();
+ putchar('>');
+ }
+
+ fdt_find_mem(fdt, &membase, &memsize);
+ endmem = membase + memsize;
+ endfdt = _fdt + be32_to_cpu(fdt->totalsize);
+
+ /*
+ * QEMU likes to place the FDT at the end of RAM, where barebox
+ * would normally extract itself to. Accommodate this by moving
+ * memory end, so it doesn't overlap FDT
+ */
+ uncompressed_len = input_data_len() + MAX_BSS_SIZE;
+
+ if (riscv_mem_barebox_image(membase, endmem, uncompressed_len) < endfdt &&
+ _fdt < riscv_mem_stack_top(membase, endmem))
+ memsize = ALIGN_DOWN(_fdt - membase, SZ_1M);
+
+ barebox_riscv_supervisor_entry(membase, memsize, hartid, fdt);
+}
+
+ENTRY_FUNCTION(start_dt_2nd, hartid, _fdt, a2)
+{
+ start_dt_2nd_nonnaked(hartid, _fdt);
+}