summaryrefslogtreecommitdiff
path: root/arch/riscv/lib
diff options
context:
space:
mode:
Diffstat (limited to 'arch/riscv/lib')
-rw-r--r--arch/riscv/lib/Makefile2
-rw-r--r--arch/riscv/lib/asm-offsets.c19
-rw-r--r--arch/riscv/lib/bootm.c2
-rw-r--r--arch/riscv/lib/interrupts.c62
-rw-r--r--arch/riscv/lib/rdtime.c38
-rw-r--r--arch/riscv/lib/sifive_clint.c84
6 files changed, 174 insertions, 33 deletions
diff --git a/arch/riscv/lib/Makefile b/arch/riscv/lib/Makefile
index b58db89752..edfa61690c 100644
--- a/arch/riscv/lib/Makefile
+++ b/arch/riscv/lib/Makefile
@@ -9,6 +9,8 @@
obj-$(CONFIG_CMD_BOOTM) += bootm.o
obj-$(CONFIG_CMD_GO) += boot.o
obj-y += cache.o
+obj-$(CONFIG_RISCV_RDTIME) += rdtime.o
+obj-$(CONFIG_SIFIVE_CLINT) += sifive_clint.o
obj-y += interrupts.o
obj-y += reset.o
obj-y += setjmp.o
diff --git a/arch/riscv/lib/asm-offsets.c b/arch/riscv/lib/asm-offsets.c
new file mode 100644
index 0000000000..e0b71f5691
--- /dev/null
+++ b/arch/riscv/lib/asm-offsets.c
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
+ *
+ * From arch/x86/lib/asm-offsets.c
+ *
+ * This program is used to generate definitions needed by
+ * assembly language modules.
+ */
+
+#include <common.h>
+#include <linux/kbuild.h>
+
+int main(void)
+{
+ DEFINE(GD_BOOT_HART, offsetof(gd_t, arch.boot_hart));
+
+ return 0;
+}
diff --git a/arch/riscv/lib/bootm.c b/arch/riscv/lib/bootm.c
index 124aeefff8..60b32cca81 100644
--- a/arch/riscv/lib/bootm.c
+++ b/arch/riscv/lib/bootm.c
@@ -93,7 +93,7 @@ static void boot_jump_linux(bootm_headers_t *images, int flag)
if (!fake) {
if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len)
- kernel(csr_read(mhartid), images->ft_addr);
+ kernel(gd->arch.boot_hart, images->ft_addr);
}
}
diff --git a/arch/riscv/lib/interrupts.c b/arch/riscv/lib/interrupts.c
index 3aff006977..e185933b01 100644
--- a/arch/riscv/lib/interrupts.c
+++ b/arch/riscv/lib/interrupts.c
@@ -12,7 +12,36 @@
#include <asm/system.h>
#include <asm/encoding.h>
-static void _exit_trap(ulong code, ulong 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 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",
+ };
+
+ 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();
+}
int interrupt_init(void)
{
@@ -72,34 +101,3 @@ __attribute__((weak)) void external_interrupt(struct pt_regs *regs)
__attribute__((weak)) void timer_interrupt(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 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",
- };
-
- 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/rdtime.c b/arch/riscv/lib/rdtime.c
new file mode 100644
index 0000000000..e128d7fce6
--- /dev/null
+++ b/arch/riscv/lib/rdtime.c
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018, Anup Patel <anup@brainfault.org>
+ * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
+ *
+ * The riscv_get_time() API implementation that is using the
+ * standard rdtime instruction.
+ */
+
+#include <common.h>
+
+/* Implement the API required by RISC-V timer driver */
+int riscv_get_time(u64 *time)
+{
+#ifdef CONFIG_64BIT
+ u64 n;
+
+ __asm__ __volatile__ (
+ "rdtime %0"
+ : "=r" (n));
+
+ *time = n;
+#else
+ u32 lo, hi, tmp;
+
+ __asm__ __volatile__ (
+ "1:\n"
+ "rdtimeh %0\n"
+ "rdtime %1\n"
+ "rdtimeh %2\n"
+ "bne %0, %2, 1b"
+ : "=&r" (hi), "=&r" (lo), "=&r" (tmp));
+
+ *time = ((u64)hi << 32) | lo;
+#endif
+
+ return 0;
+}
diff --git a/arch/riscv/lib/sifive_clint.c b/arch/riscv/lib/sifive_clint.c
new file mode 100644
index 0000000000..d24e0d585b
--- /dev/null
+++ b/arch/riscv/lib/sifive_clint.c
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
+ *
+ * U-Boot syscon driver for SiFive's Core Local Interruptor (CLINT).
+ * The CLINT block holds memory-mapped control and status registers
+ * associated with software and timer interrupts.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <asm/io.h>
+#include <asm/syscon.h>
+
+/* MSIP registers */
+#define MSIP_REG(base, hart) ((ulong)(base) + (hart) * 4)
+/* mtime compare register */
+#define MTIMECMP_REG(base, hart) ((ulong)(base) + 0x4000 + (hart) * 8)
+/* mtime register */
+#define MTIME_REG(base) ((ulong)(base) + 0xbff8)
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define CLINT_BASE_GET(void) \
+ do { \
+ long *ret; \
+ \
+ if (!gd->arch.clint) { \
+ ret = syscon_get_first_range(RISCV_SYSCON_CLINT); \
+ if (IS_ERR(ret)) \
+ return PTR_ERR(ret); \
+ gd->arch.clint = ret; \
+ } \
+ } while (0)
+
+int riscv_get_time(u64 *time)
+{
+ CLINT_BASE_GET();
+
+ *time = readq((void __iomem *)MTIME_REG(gd->arch.clint));
+
+ return 0;
+}
+
+int riscv_set_timecmp(int hart, u64 cmp)
+{
+ CLINT_BASE_GET();
+
+ writeq(cmp, (void __iomem *)MTIMECMP_REG(gd->arch.clint, hart));
+
+ return 0;
+}
+
+int riscv_send_ipi(int hart)
+{
+ CLINT_BASE_GET();
+
+ writel(1, (void __iomem *)MSIP_REG(gd->arch.clint, hart));
+
+ return 0;
+}
+
+int riscv_clear_ipi(int hart)
+{
+ CLINT_BASE_GET();
+
+ writel(0, (void __iomem *)MSIP_REG(gd->arch.clint, hart));
+
+ return 0;
+}
+
+static const struct udevice_id sifive_clint_ids[] = {
+ { .compatible = "riscv,clint0", .data = RISCV_SYSCON_CLINT },
+ { }
+};
+
+U_BOOT_DRIVER(sifive_clint) = {
+ .name = "sifive_clint",
+ .id = UCLASS_SYSCON,
+ .of_match = sifive_clint_ids,
+ .flags = DM_FLAG_PRE_RELOC,
+};