]> Git Repo - u-boot.git/blame - drivers/timer/timer-uclass.c
dtoc: Tidy up more Python style in dtb_platdata
[u-boot.git] / drivers / timer / timer-uclass.c
CommitLineData
83d290c5 1// SPDX-License-Identifier: GPL-2.0+
c8a7ba9e
TC
2/*
3 * Copyright (C) 2015 Thomas Chou <[email protected]>
c8a7ba9e
TC
4 */
5
6#include <common.h>
a5d4f861 7#include <clk.h>
35761216 8#include <cpu.h>
c8a7ba9e 9#include <dm.h>
c8336975 10#include <dm/lists.h>
a5d4f861 11#include <dm/device_compat.h>
c8336975 12#include <dm/device-internal.h>
b61e8b0c 13#include <dm/root.h>
c8a7ba9e 14#include <errno.h>
a5d4f861 15#include <init.h>
c8a7ba9e 16#include <timer.h>
61b29b82 17#include <linux/err.h>
c8a7ba9e 18
579eb5a0
BM
19DECLARE_GLOBAL_DATA_PTR;
20
c8a7ba9e 21/*
435ae76e 22 * Implement a timer uclass to work with lib/time.c. The timer is usually
9ca07ebb 23 * a 32/64 bits free-running up counter. The get_rate() method is used to get
c8a7ba9e 24 * the input clock frequency of the timer. The get_count() method is used
9ca07ebb 25 * to get the current 64 bits count value. If the hardware is counting down,
c8a7ba9e
TC
26 * the value should be inversed inside the method. There may be no real
27 * tick, and no timer interrupt.
28 */
29
4f051824 30int notrace timer_get_count(struct udevice *dev, u64 *count)
c8a7ba9e
TC
31{
32 const struct timer_ops *ops = device_get_ops(dev);
33
34 if (!ops->get_count)
35 return -ENOSYS;
36
8af7bb91
SA
37 *count = ops->get_count(dev);
38 return 0;
c8a7ba9e
TC
39}
40
4f051824 41unsigned long notrace timer_get_rate(struct udevice *dev)
c8a7ba9e 42{
4f051824 43 struct timer_dev_priv *uc_priv = dev->uclass_priv;
c8a7ba9e
TC
44
45 return uc_priv->clock_rate;
46}
47
579eb5a0
BM
48static int timer_pre_probe(struct udevice *dev)
49{
b1a16002 50#if !CONFIG_IS_ENABLED(OF_PLATDATA)
579eb5a0 51 struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
a5acafb2
ZV
52 struct clk timer_clk;
53 int err;
54 ulong ret;
579eb5a0 55
7efb4a6e
BM
56 /* It is possible that a timer device has a null ofnode */
57 if (!dev_of_valid(dev))
58 return 0;
59
a5acafb2
ZV
60 err = clk_get_by_index(dev, 0, &timer_clk);
61 if (!err) {
62 ret = clk_get_rate(&timer_clk);
63 if (IS_ERR_VALUE(ret))
64 return ret;
65 uc_priv->clock_rate = ret;
b61e8b0c
PT
66 } else {
67 uc_priv->clock_rate =
68 dev_read_u32_default(dev, "clock-frequency", 0);
69 }
b1a16002 70#endif
579eb5a0
BM
71
72 return 0;
73}
74
0a7edce0
SW
75static int timer_post_probe(struct udevice *dev)
76{
77 struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
78
79 if (!uc_priv->clock_rate)
80 return -EINVAL;
81
82 return 0;
83}
84
35761216
SA
85/*
86 * TODO: should be CONFIG_IS_ENABLED(CPU), but the SPL config has _SUPPORT on
87 * the end...
88 */
89#if defined(CONFIG_CPU) || defined(CONFIG_SPL_CPU_SUPPORT)
90int timer_timebase_fallback(struct udevice *dev)
91{
92 struct udevice *cpu;
93 struct cpu_platdata *cpu_plat;
94 struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
95
96 /* Did we get our clock rate from the device tree? */
97 if (uc_priv->clock_rate)
98 return 0;
99
100 /* Fall back to timebase-frequency */
101 dev_dbg(dev, "missing clocks or clock-frequency property; falling back on timebase-frequency\n");
102 cpu = cpu_get_current_dev();
103 if (!cpu)
104 return -ENODEV;
105
106 cpu_plat = dev_get_parent_platdata(cpu);
107 if (!cpu_plat)
108 return -ENODEV;
109
110 uc_priv->clock_rate = cpu_plat->timebase_freq;
111 return 0;
112}
113#endif
114
9ca07ebb
BM
115u64 timer_conv_64(u32 count)
116{
117 /* increment tbh if tbl has rolled over */
118 if (count < gd->timebase_l)
119 gd->timebase_h++;
120 gd->timebase_l = count;
121 return ((u64)gd->timebase_h << 32) | gd->timebase_l;
122}
123
c8336975
M
124int notrace dm_timer_init(void)
125{
c8336975 126 struct udevice *dev = NULL;
b61e8b0c 127 __maybe_unused ofnode node;
c8336975
M
128 int ret;
129
130 if (gd->timer)
131 return 0;
132
af823151
PT
133 /*
134 * Directly access gd->dm_root to suppress error messages, if the
135 * virtual root driver does not yet exist.
136 */
137 if (gd->dm_root == NULL)
138 return -EAGAIN;
139
b1a16002 140#if !CONFIG_IS_ENABLED(OF_PLATDATA)
c8336975 141 /* Check for a chosen timer to be used for tick */
b61e8b0c
PT
142 node = ofnode_get_chosen_node("tick-timer");
143
144 if (ofnode_valid(node) &&
145 uclass_get_device_by_ofnode(UCLASS_TIMER, node, &dev)) {
146 /*
147 * If the timer is not marked to be bound before
148 * relocation, bind it anyway.
149 */
8d773c4a 150 if (!lists_bind_fdt(dm_root(), node, &dev, false)) {
b61e8b0c
PT
151 ret = device_probe(dev);
152 if (ret)
153 return ret;
154 }
155 }
b1a16002 156#endif
b61e8b0c
PT
157
158 if (!dev) {
159 /* Fall back to the first available timer */
3f603cbb 160 ret = uclass_first_device_err(UCLASS_TIMER, &dev);
c8336975
M
161 if (ret)
162 return ret;
c8336975
M
163 }
164
165 if (dev) {
166 gd->timer = dev;
167 return 0;
168 }
169
170 return -ENODEV;
171}
172
c8a7ba9e
TC
173UCLASS_DRIVER(timer) = {
174 .id = UCLASS_TIMER,
175 .name = "timer",
579eb5a0 176 .pre_probe = timer_pre_probe,
a5d80113 177 .flags = DM_UC_FLAG_SEQ_ALIAS,
0a7edce0 178 .post_probe = timer_post_probe,
c8a7ba9e
TC
179 .per_device_auto_alloc_size = sizeof(struct timer_dev_priv),
180};
This page took 0.224402 seconds and 4 git commands to generate.