1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com> 4 * 5 * U-Boot syscon driver for SiFive's Core Local Interruptor (CLINT). 6 * The CLINT block holds memory-mapped control and status registers 7 * associated with software and timer interrupts. 8 */ 9 10 #include <common.h> 11 #include <dm.h> 12 #include <regmap.h> 13 #include <syscon.h> 14 #include <asm/io.h> 15 #include <asm/syscon.h> 16 17 /* MSIP registers */ 18 #define MSIP_REG(base, hart) ((ulong)(base) + (hart) * 4) 19 /* mtime compare register */ 20 #define MTIMECMP_REG(base, hart) ((ulong)(base) + 0x4000 + (hart) * 8) 21 /* mtime register */ 22 #define MTIME_REG(base) ((ulong)(base) + 0xbff8) 23 24 DECLARE_GLOBAL_DATA_PTR; 25 26 #define CLINT_BASE_GET(void) \ 27 do { \ 28 long *ret; \ 29 \ 30 if (!gd->arch.clint) { \ 31 ret = syscon_get_first_range(RISCV_SYSCON_CLINT); \ 32 if (IS_ERR(ret)) \ 33 return PTR_ERR(ret); \ 34 gd->arch.clint = ret; \ 35 } \ 36 } while (0) 37 38 int riscv_get_time(u64 *time) 39 { 40 CLINT_BASE_GET(); 41 42 *time = readq((void __iomem *)MTIME_REG(gd->arch.clint)); 43 44 return 0; 45 } 46 47 int riscv_set_timecmp(int hart, u64 cmp) 48 { 49 CLINT_BASE_GET(); 50 51 writeq(cmp, (void __iomem *)MTIMECMP_REG(gd->arch.clint, hart)); 52 53 return 0; 54 } 55 56 int riscv_send_ipi(int hart) 57 { 58 CLINT_BASE_GET(); 59 60 writel(1, (void __iomem *)MSIP_REG(gd->arch.clint, hart)); 61 62 return 0; 63 } 64 65 int riscv_clear_ipi(int hart) 66 { 67 CLINT_BASE_GET(); 68 69 writel(0, (void __iomem *)MSIP_REG(gd->arch.clint, hart)); 70 71 return 0; 72 } 73 74 static const struct udevice_id sifive_clint_ids[] = { 75 { .compatible = "riscv,clint0", .data = RISCV_SYSCON_CLINT }, 76 { } 77 }; 78 79 U_BOOT_DRIVER(sifive_clint) = { 80 .name = "sifive_clint", 81 .id = UCLASS_SYSCON, 82 .of_match = sifive_clint_ids, 83 .flags = DM_FLAG_PRE_RELOC, 84 }; 85