1
2
3
4
5
6#include <common.h>
7#include <clk.h>
8#include <cpu.h>
9#include <dm.h>
10#include <asm/global_data.h>
11#include <dm/lists.h>
12#include <dm/device_compat.h>
13#include <dm/device-internal.h>
14#include <dm/root.h>
15#include <errno.h>
16#include <init.h>
17#include <timer.h>
18#include <linux/err.h>
19
20DECLARE_GLOBAL_DATA_PTR;
21
22
23
24
25
26
27
28
29
30
31int notrace timer_get_count(struct udevice *dev, u64 *count)
32{
33 const struct timer_ops *ops = device_get_ops(dev);
34
35 if (!ops->get_count)
36 return -ENOSYS;
37
38 *count = ops->get_count(dev);
39 return 0;
40}
41
42unsigned long notrace timer_get_rate(struct udevice *dev)
43{
44 struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
45
46 return uc_priv->clock_rate;
47}
48
49static int timer_pre_probe(struct udevice *dev)
50{
51#if !CONFIG_IS_ENABLED(OF_PLATDATA)
52 struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
53 struct clk timer_clk;
54 int err;
55 ulong ret;
56
57
58 if (!dev_has_ofnode(dev))
59 return 0;
60
61 err = clk_get_by_index(dev, 0, &timer_clk);
62 if (!err) {
63 ret = clk_get_rate(&timer_clk);
64 if (IS_ERR_VALUE(ret))
65 return ret;
66 uc_priv->clock_rate = ret;
67 } else {
68 uc_priv->clock_rate =
69 dev_read_u32_default(dev, "clock-frequency", 0);
70 }
71#endif
72
73 return 0;
74}
75
76static int timer_post_probe(struct udevice *dev)
77{
78 struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
79
80 if (!uc_priv->clock_rate)
81 return -EINVAL;
82
83 return 0;
84}
85
86#if CONFIG_IS_ENABLED(CPU)
87int timer_timebase_fallback(struct udevice *dev)
88{
89 struct udevice *cpu;
90 struct cpu_plat *cpu_plat;
91 struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
92
93
94 if (uc_priv->clock_rate)
95 return 0;
96
97
98 dev_dbg(dev, "missing clocks or clock-frequency property; falling back on timebase-frequency\n");
99 cpu = cpu_get_current_dev();
100 if (!cpu)
101 return -ENODEV;
102
103 cpu_plat = dev_get_parent_plat(cpu);
104 if (!cpu_plat)
105 return -ENODEV;
106
107 uc_priv->clock_rate = cpu_plat->timebase_freq;
108 return 0;
109}
110#endif
111
112u64 timer_conv_64(u32 count)
113{
114
115 if (count < gd->timebase_l)
116 gd->timebase_h++;
117 gd->timebase_l = count;
118 return ((u64)gd->timebase_h << 32) | gd->timebase_l;
119}
120
121int notrace dm_timer_init(void)
122{
123 struct udevice *dev = NULL;
124 __maybe_unused ofnode node;
125 int ret;
126
127 if (gd->timer)
128 return 0;
129
130
131
132
133
134 if (gd->dm_root == NULL)
135 return -EAGAIN;
136
137#if !CONFIG_IS_ENABLED(OF_PLATDATA)
138
139 node = ofnode_get_chosen_node("tick-timer");
140
141 if (ofnode_valid(node) &&
142 uclass_get_device_by_ofnode(UCLASS_TIMER, node, &dev)) {
143
144
145
146
147 if (!lists_bind_fdt(dm_root(), node, &dev, false)) {
148 ret = device_probe(dev);
149 if (ret)
150 return ret;
151 }
152 }
153#endif
154
155 if (!dev) {
156
157 ret = uclass_first_device_err(UCLASS_TIMER, &dev);
158 if (ret)
159 return ret;
160 }
161
162 if (dev) {
163 gd->timer = dev;
164 return 0;
165 }
166
167 return -ENODEV;
168}
169
170UCLASS_DRIVER(timer) = {
171 .id = UCLASS_TIMER,
172 .name = "timer",
173 .pre_probe = timer_pre_probe,
174 .flags = DM_UC_FLAG_SEQ_ALIAS,
175 .post_probe = timer_post_probe,
176 .per_device_auto = sizeof(struct timer_dev_priv),
177};
178