xref: /aosp_15_r20/external/coreboot/src/cpu/x86/tsc/delay_tsc.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <cpu/cpu.h>
4 #include <cpu/x86/tsc.h>
5 #include <delay.h>
6 #include <stdint.h>
7 #include <thread.h>
8 
init_timer(void)9 void init_timer(void)
10 {
11 	(void)tsc_freq_mhz();
12 }
13 
udelay(unsigned int us)14 void udelay(unsigned int us)
15 {
16 	unsigned long long start;
17 	unsigned long long current;
18 	unsigned long long clocks;
19 
20 	if (!thread_yield_microseconds(us))
21 		return;
22 
23 	start = rdtscll();
24 	clocks = us;
25 	clocks *= tsc_freq_mhz();
26 	current = rdtscll();
27 	while ((current - start) < clocks) {
28 		cpu_relax();
29 		current = rdtscll();
30 	}
31 }
32 
33 #if CONFIG(TSC_MONOTONIC_TIMER)
34 #include <timer.h>
35 
36 static struct monotonic_counter {
37 	int initialized;
38 	struct mono_time time;
39 	uint64_t last_value;
40 } mono_counter;
41 
timer_monotonic_get(struct mono_time * mt)42 void timer_monotonic_get(struct mono_time *mt)
43 {
44 	uint64_t current_tick;
45 	uint64_t ticks_elapsed;
46 	unsigned long ticks_per_usec;
47 
48 	if (!mono_counter.initialized) {
49 		init_timer();
50 		mono_counter.last_value = rdtscll();
51 		mono_counter.initialized = 1;
52 	}
53 
54 	current_tick = rdtscll();
55 	ticks_elapsed = current_tick - mono_counter.last_value;
56 	ticks_per_usec = tsc_freq_mhz();
57 
58 	/* Update current time and tick values only if a full tick occurred. */
59 	if (ticks_elapsed >= ticks_per_usec) {
60 		uint64_t usecs_elapsed;
61 
62 		usecs_elapsed = ticks_elapsed / ticks_per_usec;
63 		mono_time_add_usecs(&mono_counter.time, (long)usecs_elapsed);
64 		mono_counter.last_value = current_tick;
65 	}
66 
67 	/* Save result. */
68 	*mt = mono_counter.time;
69 }
70 #endif
71