Merge branch 'next'
[platform/kernel/u-boot.git] / lib / time.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2000-2009
4  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5  */
6
7 #include <common.h>
8 #include <bootstage.h>
9 #include <dm.h>
10 #include <errno.h>
11 #include <init.h>
12 #include <spl.h>
13 #include <time.h>
14 #include <timer.h>
15 #include <watchdog.h>
16 #include <div64.h>
17 #include <asm/io.h>
18 #include <linux/delay.h>
19
20 #ifndef CONFIG_WD_PERIOD
21 # define CONFIG_WD_PERIOD       (10 * 1000 * 1000)      /* 10 seconds default */
22 #endif
23
24 DECLARE_GLOBAL_DATA_PTR;
25
26 #ifdef CONFIG_SYS_TIMER_RATE
27 /* Returns tick rate in ticks per second */
28 ulong notrace get_tbclk(void)
29 {
30         return CONFIG_SYS_TIMER_RATE;
31 }
32 #endif
33
34 #ifdef CONFIG_SYS_TIMER_COUNTER
35 unsigned long notrace timer_read_counter(void)
36 {
37 #ifdef CONFIG_SYS_TIMER_COUNTS_DOWN
38         return ~readl(CONFIG_SYS_TIMER_COUNTER);
39 #else
40         return readl(CONFIG_SYS_TIMER_COUNTER);
41 #endif
42 }
43
44 ulong timer_get_boot_us(void)
45 {
46         ulong count = timer_read_counter();
47
48 #if CONFIG_SYS_TIMER_RATE == 1000000
49         return count;
50 #elif CONFIG_SYS_TIMER_RATE > 1000000
51         return lldiv(count, CONFIG_SYS_TIMER_RATE / 1000000);
52 #elif defined(CONFIG_SYS_TIMER_RATE)
53         return (unsigned long long)count * 1000000 / CONFIG_SYS_TIMER_RATE;
54 #else
55         /* Assume the counter is in microseconds */
56         return count;
57 #endif
58 }
59
60 #else
61 extern unsigned long __weak timer_read_counter(void);
62 #endif
63
64 #if CONFIG_IS_ENABLED(TIMER)
65 ulong notrace get_tbclk(void)
66 {
67         if (!gd->timer) {
68 #ifdef CONFIG_TIMER_EARLY
69                 return timer_early_get_rate();
70 #else
71                 int ret;
72
73                 ret = dm_timer_init();
74                 if (ret)
75                         return ret;
76 #endif
77         }
78
79         return timer_get_rate(gd->timer);
80 }
81
82 uint64_t notrace get_ticks(void)
83 {
84         u64 count;
85         int ret;
86
87         if (!gd->timer) {
88 #ifdef CONFIG_TIMER_EARLY
89                 return timer_early_get_count();
90 #else
91                 int ret;
92
93                 ret = dm_timer_init();
94                 if (ret)
95                         panic("Could not initialize timer (err %d)\n", ret);
96 #endif
97         }
98
99         ret = timer_get_count(gd->timer, &count);
100         if (ret) {
101                 if (spl_phase() > PHASE_TPL)
102                         panic("Could not read count from timer (err %d)\n",
103                               ret);
104                 else
105                         panic("no timer (err %d)\n", ret);
106         }
107
108         return count;
109 }
110
111 #else /* !CONFIG_TIMER */
112
113 uint64_t __weak notrace get_ticks(void)
114 {
115         unsigned long now = timer_read_counter();
116
117         /* increment tbu if tbl has rolled over */
118         if (now < gd->timebase_l)
119                 gd->timebase_h++;
120         gd->timebase_l = now;
121         return ((uint64_t)gd->timebase_h << 32) | gd->timebase_l;
122 }
123
124 #endif /* CONFIG_TIMER */
125
126 /* Returns time in milliseconds */
127 static uint64_t notrace tick_to_time(uint64_t tick)
128 {
129         ulong div = get_tbclk();
130
131         tick *= CONFIG_SYS_HZ;
132         do_div(tick, div);
133         return tick;
134 }
135
136 int __weak timer_init(void)
137 {
138         return 0;
139 }
140
141 /* Returns time in milliseconds */
142 ulong __weak get_timer(ulong base)
143 {
144         return tick_to_time(get_ticks()) - base;
145 }
146
147 static uint64_t notrace tick_to_time_us(uint64_t tick)
148 {
149         ulong div = get_tbclk() / 1000;
150
151         tick *= CONFIG_SYS_HZ;
152         do_div(tick, div);
153         return tick;
154 }
155
156 uint64_t __weak get_timer_us(uint64_t base)
157 {
158         return tick_to_time_us(get_ticks()) - base;
159 }
160
161 unsigned long __weak get_timer_us_long(unsigned long base)
162 {
163         return timer_get_us() - base;
164 }
165
166 unsigned long __weak notrace timer_get_us(void)
167 {
168         return tick_to_time(get_ticks() * 1000);
169 }
170
171 uint64_t usec_to_tick(unsigned long usec)
172 {
173         uint64_t tick = usec;
174         tick *= get_tbclk();
175         do_div(tick, 1000000);
176         return tick;
177 }
178
179 void __weak __udelay(unsigned long usec)
180 {
181         uint64_t tmp;
182
183         tmp = get_ticks() + usec_to_tick(usec); /* get current timestamp */
184
185         while (get_ticks() < tmp+1)     /* loop till event */
186                  /*NOP*/;
187 }
188
189 /* ------------------------------------------------------------------------- */
190
191 void udelay(unsigned long usec)
192 {
193         ulong kv;
194
195         do {
196                 WATCHDOG_RESET();
197                 kv = usec > CONFIG_WD_PERIOD ? CONFIG_WD_PERIOD : usec;
198                 __udelay(kv);
199                 usec -= kv;
200         } while(usec);
201 }