diff options
Diffstat (limited to 'arch/riscv/lib')
-rw-r--r-- | arch/riscv/lib/Makefile | 2 | ||||
-rw-r--r-- | arch/riscv/lib/asm-offsets.c | 19 | ||||
-rw-r--r-- | arch/riscv/lib/bootm.c | 2 | ||||
-rw-r--r-- | arch/riscv/lib/interrupts.c | 62 | ||||
-rw-r--r-- | arch/riscv/lib/rdtime.c | 38 | ||||
-rw-r--r-- | arch/riscv/lib/sifive_clint.c | 84 |
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, +}; |