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