summaryrefslogtreecommitdiff
path: root/arch/riscv/lib
diff options
context:
space:
mode:
Diffstat (limited to 'arch/riscv/lib')
-rw-r--r--arch/riscv/lib/bootm.c97
-rw-r--r--arch/riscv/lib/cache.c36
-rw-r--r--arch/riscv/lib/interrupts.c31
-rw-r--r--arch/riscv/lib/setjmp.S2
4 files changed, 125 insertions, 41 deletions
diff --git a/arch/riscv/lib/bootm.c b/arch/riscv/lib/bootm.c
index 2b5ccce933..124aeefff8 100644
--- a/arch/riscv/lib/bootm.c
+++ b/arch/riscv/lib/bootm.c
@@ -8,6 +8,8 @@
#include <common.h>
#include <command.h>
+#include <dm.h>
+#include <dm/root.h>
#include <image.h>
#include <asm/byteorder.h>
#include <asm/csr.h>
@@ -26,26 +28,41 @@ int arch_fixup_fdt(void *blob)
return 0;
}
-int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
+/**
+ * announce_and_cleanup() - Print message and prepare for kernel boot
+ *
+ * @fake: non-zero to do everything except actually boot
+ */
+static void announce_and_cleanup(int fake)
{
- void (*kernel)(ulong hart, void *dtb);
-
- /*
- * allow the PREP bootm subcommand, it is required for bootm to work
- */
- if (flag & BOOTM_STATE_OS_PREP)
- return 0;
+ printf("\nStarting kernel ...%s\n\n", fake ?
+ "(fake run for tracing)" : "");
+ bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel");
+#ifdef CONFIG_BOOTSTAGE_FDT
+ bootstage_fdt_add_report();
+#endif
+#ifdef CONFIG_BOOTSTAGE_REPORT
+ bootstage_report();
+#endif
- if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
- return 1;
+#ifdef CONFIG_USB_DEVICE
+ udc_disconnect();
+#endif
- kernel = (void (*)(ulong, void *))images->ep;
+ board_quiesce_devices();
- bootstage_mark(BOOTSTAGE_ID_RUN_OS);
+ /*
+ * Call remove function of all devices with a removal flag set.
+ * This may be useful for last-stage operations, like cancelling
+ * of DMA operation or releasing device internal buffers.
+ */
+ dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL);
- debug("## Transferring control to Linux (at address %08lx) ...\n",
- (ulong)kernel);
+ cleanup_before_linux();
+}
+static void boot_prep_linux(bootm_headers_t *images)
+{
if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) {
#ifdef CONFIG_OF_LIBFDT
debug("using: FDT\n");
@@ -54,24 +71,50 @@ int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
hang();
}
#endif
+ } else {
+ printf("Device tree not found or missing FDT support\n");
+ hang();
}
+}
- /* we assume that the kernel is in place */
- printf("\nStarting kernel ...\n\n");
+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);
- /*
- * Call remove function of all devices with a removal flag set.
- * This may be useful for last-stage operations, like cancelling
- * of DMA operation or releasing device internal buffers.
- */
- dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL);
+ kernel = (void (*)(ulong, void *))images->ep;
- cleanup_before_linux();
+ bootstage_mark(BOOTSTAGE_ID_RUN_OS);
+
+ debug("## Transferring control to Linux (at address %08lx) ...\n",
+ (ulong)kernel);
- if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len)
- kernel(csr_read(mhartid), images->ft_addr);
+ announce_and_cleanup(fake);
- /* does not return */
+ if (!fake) {
+ if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len)
+ kernel(csr_read(mhartid), images->ft_addr);
+ }
+}
+
+int do_bootm_linux(int flag, int argc, char * const argv[],
+ bootm_headers_t *images)
+{
+ /* No need for those on RISC-V */
+ if (flag & BOOTM_STATE_OS_BD_T || flag & BOOTM_STATE_OS_CMDLINE)
+ return -1;
- return 1;
+ if (flag & BOOTM_STATE_OS_PREP) {
+ boot_prep_linux(images);
+ return 0;
+ }
+
+ if (flag & (BOOTM_STATE_OS_GO | BOOTM_STATE_OS_FAKE_GO)) {
+ boot_jump_linux(images, flag);
+ return 0;
+ }
+
+ boot_prep_linux(images);
+ boot_jump_linux(images, flag);
+ return 0;
}
diff --git a/arch/riscv/lib/cache.c b/arch/riscv/lib/cache.c
index 1d67c49c2c..ae5c60716f 100644
--- a/arch/riscv/lib/cache.c
+++ b/arch/riscv/lib/cache.c
@@ -6,44 +6,68 @@
#include <common.h>
+void invalidate_icache_all(void)
+{
+ asm volatile ("fence.i" ::: "memory");
+}
+
+void flush_dcache_all(void)
+{
+ asm volatile ("fence" :::"memory");
+}
void flush_dcache_range(unsigned long start, unsigned long end)
{
+ flush_dcache_all();
}
void invalidate_icache_range(unsigned long start, unsigned long end)
{
+ /*
+ * RISC-V does not have an instruction for invalidating parts of the
+ * instruction cache. Invalidate all of it instead.
+ */
+ invalidate_icache_all();
}
void invalidate_dcache_range(unsigned long start, unsigned long end)
{
+ flush_dcache_all();
+}
+
+void cache_flush(void)
+{
+ invalidate_icache_all();
+ flush_dcache_all();
}
void flush_cache(unsigned long addr, unsigned long size)
{
+ invalidate_icache_all();
+ flush_dcache_all();
}
-void icache_enable(void)
+__weak void icache_enable(void)
{
}
-void icache_disable(void)
+__weak void icache_disable(void)
{
}
-int icache_status(void)
+__weak int icache_status(void)
{
return 0;
}
-void dcache_enable(void)
+__weak void dcache_enable(void)
{
}
-void dcache_disable(void)
+__weak void dcache_disable(void)
{
}
-int dcache_status(void)
+__weak int dcache_status(void)
{
return 0;
}
diff --git a/arch/riscv/lib/interrupts.c b/arch/riscv/lib/interrupts.c
index 0a0995a7af..903a1c4cd5 100644
--- a/arch/riscv/lib/interrupts.c
+++ b/arch/riscv/lib/interrupts.c
@@ -12,7 +12,7 @@
#include <asm/system.h>
#include <asm/encoding.h>
-static void _exit_trap(int code, uint epc, struct pt_regs *regs);
+static void _exit_trap(ulong code, ulong epc, struct pt_regs *regs);
int interrupt_init(void)
{
@@ -34,9 +34,9 @@ int disable_interrupts(void)
return 0;
}
-uint handle_trap(uint mcause, uint epc, struct pt_regs *regs)
+ulong handle_trap(ulong mcause, ulong epc, struct pt_regs *regs)
{
- uint is_int;
+ ulong is_int;
is_int = (mcause & MCAUSE_INT);
if ((is_int) && ((mcause & MCAUSE_CAUSE) == IRQ_M_EXT))
@@ -60,16 +60,33 @@ __attribute__((weak)) void timer_interrupt(struct pt_regs *regs)
{
}
-static void _exit_trap(int code, uint epc, struct pt_regs *regs)
+static void _exit_trap(ulong code, ulong epc, struct pt_regs *regs)
{
static const char * const exception_code[] = {
"Instruction address misaligned",
"Instruction access fault",
"Illegal instruction",
"Breakpoint",
- "Load address misaligned"
+ "Load address misaligned",
+ "Load access fault",
+ "Store/AMO address misaligned",
+ "Store/AMO access fault",
+ "Environment call from U-mode",
+ "Environment call from S-mode",
+ "Reserved",
+ "Environment call from M-mode",
+ "Instruction page fault",
+ "Load page fault",
+ "Reserved",
+ "Store/AMO page fault",
};
- printf("exception code: %d , %s , epc %08x , ra %08lx\n",
- code, exception_code[code], epc, regs->ra);
+ if (code < ARRAY_SIZE(exception_code)) {
+ printf("exception code: %ld , %s , epc %lx , ra %lx\n",
+ code, exception_code[code], epc, regs->ra);
+ } else {
+ printf("Reserved\n");
+ }
+
+ hang();
}
diff --git a/arch/riscv/lib/setjmp.S b/arch/riscv/lib/setjmp.S
index 8f5a6a23aa..72bc9241f6 100644
--- a/arch/riscv/lib/setjmp.S
+++ b/arch/riscv/lib/setjmp.S
@@ -6,7 +6,7 @@
#include <config.h>
#include <linux/linkage.h>
-#ifdef CONFIG_CPU_RISCV_64
+#ifdef CONFIG_ARCH_RV64I
#define STORE_IDX(reg, idx) sd reg, (idx*8)(a0)
#define LOAD_IDX(reg, idx) ld reg, (idx*8)(a0)
#else