blob: 169c03dcb5c1b90793ab8f350fd58805e41e6617 [file] [log] [blame]
Bin Meng60262cd02018-12-12 06:12:27 -08001// SPDX-License-Identifier: GPL-2.0+
2/*
Sean Andersonc33efaf2020-09-28 10:52:21 -04003 * Copyright (C) 2020, Sean Anderson <seanga2@gmail.com>
Bin Meng60262cd02018-12-12 06:12:27 -08004 * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
Sean Andersonc33efaf2020-09-28 10:52:21 -04005 * Copyright (C) 2018, Anup Patel <anup@brainfault.org>
6 * Copyright (C) 2012 Regents of the University of California
Bin Meng60262cd02018-12-12 06:12:27 -08007 *
Sean Andersonc33efaf2020-09-28 10:52:21 -04008 * RISC-V architecturally-defined generic timer driver
Bin Meng60262cd02018-12-12 06:12:27 -08009 *
Sean Andersonc33efaf2020-09-28 10:52:21 -040010 * This driver provides generic timer support for S-mode U-Boot.
Bin Meng60262cd02018-12-12 06:12:27 -080011 */
12
13#include <common.h>
Chanho Park74fbd742023-09-06 14:18:13 +090014#include <div64.h>
Bin Meng60262cd02018-12-12 06:12:27 -080015#include <dm.h>
16#include <errno.h>
Torsten Duwef39f8f72023-08-14 18:05:28 +020017#include <fdt_support.h>
Bin Meng60262cd02018-12-12 06:12:27 -080018#include <timer.h>
Sean Andersonc33efaf2020-09-28 10:52:21 -040019#include <asm/csr.h>
Bin Meng60262cd02018-12-12 06:12:27 -080020
Pragnesh Patelbc8d12b2021-01-17 18:11:25 +053021static u64 notrace riscv_timer_get_count(struct udevice *dev)
Bin Meng60262cd02018-12-12 06:12:27 -080022{
Sean Anderson8af7bb92020-10-07 14:37:44 -040023 __maybe_unused u32 hi, lo;
Sean Andersonc33efaf2020-09-28 10:52:21 -040024
Sean Anderson8af7bb92020-10-07 14:37:44 -040025 if (IS_ENABLED(CONFIG_64BIT))
26 return csr_read(CSR_TIME);
Sean Andersonc33efaf2020-09-28 10:52:21 -040027
Sean Anderson8af7bb92020-10-07 14:37:44 -040028 do {
29 hi = csr_read(CSR_TIMEH);
30 lo = csr_read(CSR_TIME);
31 } while (hi != csr_read(CSR_TIMEH));
Sean Andersonc33efaf2020-09-28 10:52:21 -040032
Sean Anderson8af7bb92020-10-07 14:37:44 -040033 return ((u64)hi << 32) | lo;
Bin Meng60262cd02018-12-12 06:12:27 -080034}
35
Pragnesh Patelbc8d12b2021-01-17 18:11:25 +053036#if CONFIG_IS_ENABLED(RISCV_SMODE) && IS_ENABLED(CONFIG_TIMER_EARLY)
37/**
38 * timer_early_get_rate() - Get the timer rate before driver model
39 */
40unsigned long notrace timer_early_get_rate(void)
41{
42 return RISCV_SMODE_TIMER_FREQ;
43}
44
45/**
46 * timer_early_get_count() - Get the timer count before driver model
47 *
48 */
49u64 notrace timer_early_get_count(void)
50{
51 return riscv_timer_get_count(NULL);
52}
53#endif
54
Chanho Park74fbd742023-09-06 14:18:13 +090055#if CONFIG_IS_ENABLED(RISCV_SMODE) && CONFIG_IS_ENABLED(BOOTSTAGE)
56ulong timer_get_boot_us(void)
57{
58 int ret;
59 u64 ticks = 0;
60 u32 rate;
61
62 ret = dm_timer_init();
63 if (!ret) {
64 rate = timer_get_rate(gd->timer);
65 timer_get_count(gd->timer, &ticks);
66 } else {
67 rate = RISCV_SMODE_TIMER_FREQ;
68 ticks = riscv_timer_get_count(NULL);
69 }
70
71 /* Below is converted from time(us) = (tick / rate) * 10000000 */
72 return lldiv(ticks * 1000, (rate / 1000));
73}
74#endif
75
Bin Meng60262cd02018-12-12 06:12:27 -080076static int riscv_timer_probe(struct udevice *dev)
77{
78 struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
Torsten Duwef39f8f72023-08-14 18:05:28 +020079 u32 rate;
Bin Meng60262cd02018-12-12 06:12:27 -080080
Torsten Duwef39f8f72023-08-14 18:05:28 +020081 /* When this function was called from the CPU driver, clock
82 * frequency is passed as driver data.
83 */
84 rate = dev->driver_data;
85
86 /* When called from an FDT match, the rate needs to be looked up. */
87 if (!rate && gd->fdt_blob) {
88 rate = fdt_getprop_u32_default(gd->fdt_blob,
89 "/cpus", "timebase-frequency", 0);
90 }
91
92 uc_priv->clock_rate = rate;
93
94 /* With rate==0, timer uclass post_probe might later fail with -EINVAL.
95 * Give a hint at the cause for debugging.
96 */
97 if (!rate)
98 log_err("riscv_timer_probe with invalid clock rate 0!\n");
Bin Meng60262cd02018-12-12 06:12:27 -080099
100 return 0;
101}
102
103static const struct timer_ops riscv_timer_ops = {
104 .get_count = riscv_timer_get_count,
105};
106
Torsten Duwef39f8f72023-08-14 18:05:28 +0200107static const struct udevice_id riscv_timer_ids[] = {
108 { .compatible = "riscv,timer", },
109 { }
110};
111
Bin Meng60262cd02018-12-12 06:12:27 -0800112U_BOOT_DRIVER(riscv_timer) = {
113 .name = "riscv_timer",
114 .id = UCLASS_TIMER,
Torsten Duwef39f8f72023-08-14 18:05:28 +0200115 .of_match = of_match_ptr(riscv_timer_ids),
Bin Meng60262cd02018-12-12 06:12:27 -0800116 .probe = riscv_timer_probe,
117 .ops = &riscv_timer_ops,
118 .flags = DM_FLAG_PRE_RELOC,
119};