blob: 28a6a6870b8194b9c4443181665cac4cfb0cf2fe [file] [log] [blame]
Bin Meng25399032018-12-12 06:12:27 -08001// SPDX-License-Identifier: GPL-2.0+
2/*
Sean Anderson9baaaef2020-09-28 10:52:21 -04003 * Copyright (C) 2020, Sean Anderson <seanga2@gmail.com>
Bin Meng25399032018-12-12 06:12:27 -08004 * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
Sean Anderson9baaaef2020-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 Meng25399032018-12-12 06:12:27 -08007 *
Sean Anderson9baaaef2020-09-28 10:52:21 -04008 * RISC-V architecturally-defined generic timer driver
Bin Meng25399032018-12-12 06:12:27 -08009 *
Sean Anderson9baaaef2020-09-28 10:52:21 -040010 * This driver provides generic timer support for S-mode U-Boot.
Bin Meng25399032018-12-12 06:12:27 -080011 */
12
13#include <common.h>
14#include <dm.h>
15#include <errno.h>
Torsten Duwe002858c2023-08-14 18:05:28 +020016#include <fdt_support.h>
Bin Meng25399032018-12-12 06:12:27 -080017#include <timer.h>
Sean Anderson9baaaef2020-09-28 10:52:21 -040018#include <asm/csr.h>
Bin Meng25399032018-12-12 06:12:27 -080019
Pragnesh Patel02038c32021-01-17 18:11:25 +053020static u64 notrace riscv_timer_get_count(struct udevice *dev)
Bin Meng25399032018-12-12 06:12:27 -080021{
Sean Anderson947fc2d2020-10-07 14:37:44 -040022 __maybe_unused u32 hi, lo;
Sean Anderson9baaaef2020-09-28 10:52:21 -040023
Sean Anderson947fc2d2020-10-07 14:37:44 -040024 if (IS_ENABLED(CONFIG_64BIT))
25 return csr_read(CSR_TIME);
Sean Anderson9baaaef2020-09-28 10:52:21 -040026
Sean Anderson947fc2d2020-10-07 14:37:44 -040027 do {
28 hi = csr_read(CSR_TIMEH);
29 lo = csr_read(CSR_TIME);
30 } while (hi != csr_read(CSR_TIMEH));
Sean Anderson9baaaef2020-09-28 10:52:21 -040031
Sean Anderson947fc2d2020-10-07 14:37:44 -040032 return ((u64)hi << 32) | lo;
Bin Meng25399032018-12-12 06:12:27 -080033}
34
Pragnesh Patel02038c32021-01-17 18:11:25 +053035#if CONFIG_IS_ENABLED(RISCV_SMODE) && IS_ENABLED(CONFIG_TIMER_EARLY)
36/**
37 * timer_early_get_rate() - Get the timer rate before driver model
38 */
39unsigned long notrace timer_early_get_rate(void)
40{
41 return RISCV_SMODE_TIMER_FREQ;
42}
43
44/**
45 * timer_early_get_count() - Get the timer count before driver model
46 *
47 */
48u64 notrace timer_early_get_count(void)
49{
50 return riscv_timer_get_count(NULL);
51}
52#endif
53
Bin Meng25399032018-12-12 06:12:27 -080054static int riscv_timer_probe(struct udevice *dev)
55{
56 struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
Torsten Duwe002858c2023-08-14 18:05:28 +020057 u32 rate;
Bin Meng25399032018-12-12 06:12:27 -080058
Torsten Duwe002858c2023-08-14 18:05:28 +020059 /* When this function was called from the CPU driver, clock
60 * frequency is passed as driver data.
61 */
62 rate = dev->driver_data;
63
64 /* When called from an FDT match, the rate needs to be looked up. */
65 if (!rate && gd->fdt_blob) {
66 rate = fdt_getprop_u32_default(gd->fdt_blob,
67 "/cpus", "timebase-frequency", 0);
68 }
69
70 uc_priv->clock_rate = rate;
71
72 /* With rate==0, timer uclass post_probe might later fail with -EINVAL.
73 * Give a hint at the cause for debugging.
74 */
75 if (!rate)
76 log_err("riscv_timer_probe with invalid clock rate 0!\n");
Bin Meng25399032018-12-12 06:12:27 -080077
78 return 0;
79}
80
81static const struct timer_ops riscv_timer_ops = {
82 .get_count = riscv_timer_get_count,
83};
84
Torsten Duwe002858c2023-08-14 18:05:28 +020085static const struct udevice_id riscv_timer_ids[] = {
86 { .compatible = "riscv,timer", },
87 { }
88};
89
Bin Meng25399032018-12-12 06:12:27 -080090U_BOOT_DRIVER(riscv_timer) = {
91 .name = "riscv_timer",
92 .id = UCLASS_TIMER,
Torsten Duwe002858c2023-08-14 18:05:28 +020093 .of_match = of_match_ptr(riscv_timer_ids),
Bin Meng25399032018-12-12 06:12:27 -080094 .probe = riscv_timer_probe,
95 .ops = &riscv_timer_ops,
96 .flags = DM_FLAG_PRE_RELOC,
97};