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