Merge tag 'ti-v2020.07-rc3' of https://gitlab.denx.de/u-boot/custodians/u-boot-ti
[oweals/u-boot.git] / drivers / timer / timer-uclass.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2015 Thomas Chou <thomas@wytron.com.tw>
4  */
5
6 #include <common.h>
7 #include <dm.h>
8 #include <init.h>
9 #include <dm/lists.h>
10 #include <dm/device-internal.h>
11 #include <dm/root.h>
12 #include <clk.h>
13 #include <errno.h>
14 #include <timer.h>
15 #include <linux/err.h>
16
17 DECLARE_GLOBAL_DATA_PTR;
18
19 /*
20  * Implement a timer uclass to work with lib/time.c. The timer is usually
21  * a 32/64 bits free-running up counter. The get_rate() method is used to get
22  * the input clock frequency of the timer. The get_count() method is used
23  * to get the current 64 bits count value. If the hardware is counting down,
24  * the value should be inversed inside the method. There may be no real
25  * tick, and no timer interrupt.
26  */
27
28 int notrace timer_get_count(struct udevice *dev, u64 *count)
29 {
30         const struct timer_ops *ops = device_get_ops(dev);
31
32         if (!ops->get_count)
33                 return -ENOSYS;
34
35         return ops->get_count(dev, count);
36 }
37
38 unsigned long notrace timer_get_rate(struct udevice *dev)
39 {
40         struct timer_dev_priv *uc_priv = dev->uclass_priv;
41
42         return uc_priv->clock_rate;
43 }
44
45 static int timer_pre_probe(struct udevice *dev)
46 {
47 #if !CONFIG_IS_ENABLED(OF_PLATDATA)
48         struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
49         struct clk timer_clk;
50         int err;
51         ulong ret;
52
53         /* It is possible that a timer device has a null ofnode */
54         if (!dev_of_valid(dev))
55                 return 0;
56
57         err = clk_get_by_index(dev, 0, &timer_clk);
58         if (!err) {
59                 ret = clk_get_rate(&timer_clk);
60                 if (IS_ERR_VALUE(ret))
61                         return ret;
62                 uc_priv->clock_rate = ret;
63         } else {
64                 uc_priv->clock_rate =
65                         dev_read_u32_default(dev, "clock-frequency", 0);
66         }
67 #endif
68
69         return 0;
70 }
71
72 static int timer_post_probe(struct udevice *dev)
73 {
74         struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
75
76         if (!uc_priv->clock_rate)
77                 return -EINVAL;
78
79         return 0;
80 }
81
82 u64 timer_conv_64(u32 count)
83 {
84         /* increment tbh if tbl has rolled over */
85         if (count < gd->timebase_l)
86                 gd->timebase_h++;
87         gd->timebase_l = count;
88         return ((u64)gd->timebase_h << 32) | gd->timebase_l;
89 }
90
91 int notrace dm_timer_init(void)
92 {
93         struct udevice *dev = NULL;
94         __maybe_unused ofnode node;
95         int ret;
96
97         if (gd->timer)
98                 return 0;
99
100         /*
101          * Directly access gd->dm_root to suppress error messages, if the
102          * virtual root driver does not yet exist.
103          */
104         if (gd->dm_root == NULL)
105                 return -EAGAIN;
106
107 #if !CONFIG_IS_ENABLED(OF_PLATDATA)
108         /* Check for a chosen timer to be used for tick */
109         node = ofnode_get_chosen_node("tick-timer");
110
111         if (ofnode_valid(node) &&
112             uclass_get_device_by_ofnode(UCLASS_TIMER, node, &dev)) {
113                 /*
114                  * If the timer is not marked to be bound before
115                  * relocation, bind it anyway.
116                  */
117                 if (!lists_bind_fdt(dm_root(), node, &dev, false)) {
118                         ret = device_probe(dev);
119                         if (ret)
120                                 return ret;
121                 }
122         }
123 #endif
124
125         if (!dev) {
126                 /* Fall back to the first available timer */
127                 ret = uclass_first_device_err(UCLASS_TIMER, &dev);
128                 if (ret)
129                         return ret;
130         }
131
132         if (dev) {
133                 gd->timer = dev;
134                 return 0;
135         }
136
137         return -ENODEV;
138 }
139
140 UCLASS_DRIVER(timer) = {
141         .id             = UCLASS_TIMER,
142         .name           = "timer",
143         .pre_probe      = timer_pre_probe,
144         .flags          = DM_UC_FLAG_SEQ_ALIAS,
145         .post_probe     = timer_post_probe,
146         .per_device_auto_alloc_size = sizeof(struct timer_dev_priv),
147 };