xref: /openbmc/u-boot/arch/riscv/lib/sifive_clint.c (revision 7e40d0a3)
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