1 /* SPDX-License-Identifier: GPL-2.0-only */
4 #include <console/console.h>
7 #include <cpu/x86/lapic.h>
11 /* Set the APIC timer to no interrupts and periodic mode */
12 lapic_write(LAPIC_LVTT
, (LAPIC_LVT_TIMER_PERIODIC
| LAPIC_LVT_MASKED
));
14 /* Set the divider to 1, no divider */
15 lapic_write(LAPIC_TDCR
, LAPIC_TDR_DIV_1
);
17 /* Set the initial counter to 0xffffffff */
18 lapic_write(LAPIC_TMICT
, 0xffffffff);
21 void udelay(u32 usecs
)
23 u32 start
, value
, ticks
, timer_fsb
;
25 if (!thread_yield_microseconds(usecs
))
28 timer_fsb
= get_timer_fsb();
29 if (!timer_fsb
|| (lapic_read(LAPIC_LVTT
) &
30 (LAPIC_LVT_TIMER_PERIODIC
| LAPIC_LVT_MASKED
)) !=
31 (LAPIC_LVT_TIMER_PERIODIC
| LAPIC_LVT_MASKED
)) {
33 timer_fsb
= get_timer_fsb();
36 /* Calculate the number of ticks to run, our FSB runs at timer_fsb MHz
38 ticks
= usecs
* timer_fsb
;
39 start
= lapic_read(LAPIC_TMCCT
);
41 value
= lapic_read(LAPIC_TMCCT
);
42 } while ((start
- value
) < ticks
);
45 #if CONFIG(LAPIC_MONOTONIC_TIMER)
48 static struct monotonic_counter
{
50 struct mono_time time
;
54 void timer_monotonic_get(struct mono_time
*mt
)
56 uint32_t current_tick
;
57 uint32_t usecs_elapsed
;
60 if (!mono_counter
.initialized
) {
62 timer_fsb
= get_timer_fsb();
63 /* An FSB frequency of 200Mhz provides a 20 second polling
64 * interval between timer_monotonic_get() calls before wrap
68 "apic timer freq (%d) may be too fast.\n",
70 mono_counter
.last_value
= lapic_read(LAPIC_TMCCT
);
71 mono_counter
.initialized
= 1;
74 timer_fsb
= get_timer_fsb();
75 current_tick
= lapic_read(LAPIC_TMCCT
);
76 /* Note that the APIC timer counts down. */
77 usecs_elapsed
= (mono_counter
.last_value
- current_tick
) / timer_fsb
;
79 /* Update current time and tick values only if a full tick occurred. */
81 mono_time_add_usecs(&mono_counter
.time
, usecs_elapsed
);
82 mono_counter
.last_value
= current_tick
;
86 *mt
= mono_counter
.time
;