spd/lp5: Add Hynix memory part
[coreboot2.git] / src / cpu / x86 / lapic / apic_timer.c
blob2bb66eb8c012ab0b6a9dc151b9fb5aa6b6bf28e6
1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <stdint.h>
4 #include <console/console.h>
5 #include <delay.h>
6 #include <thread.h>
7 #include <cpu/x86/lapic.h>
9 void init_timer(void)
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))
26 return;
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)) {
32 init_timer();
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);
40 do {
41 value = lapic_read(LAPIC_TMCCT);
42 } while ((start - value) < ticks);
45 #if CONFIG(LAPIC_MONOTONIC_TIMER)
46 #include <timer.h>
48 static struct monotonic_counter {
49 int initialized;
50 struct mono_time time;
51 uint32_t last_value;
52 } mono_counter;
54 void timer_monotonic_get(struct mono_time *mt)
56 uint32_t current_tick;
57 uint32_t usecs_elapsed;
58 uint32_t timer_fsb;
60 if (!mono_counter.initialized) {
61 init_timer();
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
65 * around occurs. */
66 if (timer_fsb > 200)
67 printk(BIOS_WARNING,
68 "apic timer freq (%d) may be too fast.\n",
69 timer_fsb);
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. */
80 if (usecs_elapsed) {
81 mono_time_add_usecs(&mono_counter.time, usecs_elapsed);
82 mono_counter.last_value = current_tick;
85 /* Save result. */
86 *mt = mono_counter.time;
88 #endif