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  * Copyright (C) 2018, Anup Patel <anup@brainfault.org>
6  * Copyright (C) 2012 Regents of the University of California
7  *
8  * RISC-V architecturally-defined generic timer driver
9  *
10  * This driver provides generic timer support for S-mode U-Boot.
11  */
12 
13 #include <common.h>
14 #include <dm.h>
15 #include <errno.h>
16 #include <timer.h>
17 #include <asm/csr.h>
18 
riscv_timer_get_count(struct udevice * dev)19 static u64 notrace riscv_timer_get_count(struct udevice *dev)
20 {
21 	__maybe_unused u32 hi, lo;
22 
23 	if (IS_ENABLED(CONFIG_64BIT))
24 		return csr_read(CSR_TIME);
25 
26 	do {
27 		hi = csr_read(CSR_TIMEH);
28 		lo = csr_read(CSR_TIME);
29 	} while (hi != csr_read(CSR_TIMEH));
30 
31 	return ((u64)hi << 32) | lo;
32 }
33 
34 #if CONFIG_IS_ENABLED(RISCV_SMODE) && IS_ENABLED(CONFIG_TIMER_EARLY)
35 /**
36  * timer_early_get_rate() - Get the timer rate before driver model
37  */
timer_early_get_rate(void)38 unsigned long notrace timer_early_get_rate(void)
39 {
40 	return RISCV_SMODE_TIMER_FREQ;
41 }
42 
43 /**
44  * timer_early_get_count() - Get the timer count before driver model
45  *
46  */
timer_early_get_count(void)47 u64 notrace timer_early_get_count(void)
48 {
49 	return riscv_timer_get_count(NULL);
50 }
51 #endif
52 
riscv_timer_probe(struct udevice * dev)53 static int riscv_timer_probe(struct udevice *dev)
54 {
55 	struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
56 
57 	/* clock frequency was passed from the cpu driver as driver data */
58 	uc_priv->clock_rate = dev->driver_data;
59 
60 	return 0;
61 }
62 
63 static const struct timer_ops riscv_timer_ops = {
64 	.get_count = riscv_timer_get_count,
65 };
66 
67 U_BOOT_DRIVER(riscv_timer) = {
68 	.name = "riscv_timer",
69 	.id = UCLASS_TIMER,
70 	.probe = riscv_timer_probe,
71 	.ops = &riscv_timer_ops,
72 	.flags = DM_FLAG_PRE_RELOC,
73 };
74