1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2020, Sean Anderson <seanga2@gmail.com>
4  * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
5  */
6 
7 #include <common.h>
8 #include <clk.h>
9 #include <dm.h>
10 #include <timer.h>
11 #include <asm/io.h>
12 #include <dm/device-internal.h>
13 #include <linux/err.h>
14 
15 /* mtime register */
16 #define MTIME_REG(base)			((ulong)(base) + 0xbff8)
17 
sifive_clint_get_count(struct udevice * dev)18 static u64 notrace sifive_clint_get_count(struct udevice *dev)
19 {
20 	return readq((void __iomem *)MTIME_REG(dev_get_priv(dev)));
21 }
22 
23 #if CONFIG_IS_ENABLED(RISCV_MMODE) && IS_ENABLED(CONFIG_TIMER_EARLY)
24 /**
25  * timer_early_get_rate() - Get the timer rate before driver model
26  */
timer_early_get_rate(void)27 unsigned long notrace timer_early_get_rate(void)
28 {
29 	return RISCV_MMODE_TIMER_FREQ;
30 }
31 
32 /**
33  * timer_early_get_count() - Get the timer count before driver model
34  *
35  */
timer_early_get_count(void)36 u64 notrace timer_early_get_count(void)
37 {
38 	return readq((void __iomem *)MTIME_REG(RISCV_MMODE_TIMERBASE));
39 }
40 #endif
41 
42 static const struct timer_ops sifive_clint_ops = {
43 	.get_count = sifive_clint_get_count,
44 };
45 
sifive_clint_probe(struct udevice * dev)46 static int sifive_clint_probe(struct udevice *dev)
47 {
48 	dev_set_priv(dev, dev_read_addr_ptr(dev));
49 	if (!dev_get_priv(dev))
50 		return -EINVAL;
51 
52 	return timer_timebase_fallback(dev);
53 }
54 
55 static const struct udevice_id sifive_clint_ids[] = {
56 	{ .compatible = "riscv,clint0" },
57 	{ }
58 };
59 
60 U_BOOT_DRIVER(sifive_clint) = {
61 	.name		= "sifive_clint",
62 	.id		= UCLASS_TIMER,
63 	.of_match	= sifive_clint_ids,
64 	.probe		= sifive_clint_probe,
65 	.ops		= &sifive_clint_ops,
66 	.flags		= DM_FLAG_PRE_RELOC,
67 };
68