coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
udelay.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 /*
4  * udelay() implementation for SMI handlers
5  * This is neat in that it never writes to hardware registers, and thus does
6  * not modify the state of the hardware while servicing SMIs.
7  */
8 
9 #include <cpu/x86/msr.h>
10 #include <cpu/amd/msr.h>
11 #include <cpu/x86/tsc.h>
12 #include <delay.h>
13 #include <stdint.h>
14 
15 void udelay(uint32_t us)
16 {
17  uint8_t fid, did, pstate_idx;
18  uint64_t tsc_clock, tsc_start, tsc_now, tsc_wait_ticks;
19  msr_t msr;
20  const uint64_t tsc_base = 100000000;
21 
22  /* Get initial timestamp before we do the math */
23  tsc_start = rdtscll();
24 
25  /* Get the P-state. This determines which MSR to read */
26  msr = rdmsr(PS_STS_REG);
27  pstate_idx = msr.lo & 0x07;
28 
29  /* Get FID and VID for current P-State */
30  msr = rdmsr(PSTATE_0_MSR + pstate_idx);
31 
32  /* Extract the FID and VID values */
33  fid = msr.lo & 0x3f;
34  did = (msr.lo >> 6) & 0x7;
35 
36  /* Calculate the CPU clock (from base freq of 100MHz) */
37  tsc_clock = tsc_base * (fid + 0x10) / (1 << did);
38 
39  /* Now go on and wait */
40  tsc_wait_ticks = (tsc_clock / 1000000) * us;
41 
42  do {
43  tsc_now = rdtscll();
44  } while (tsc_now - tsc_wait_ticks < tsc_start);
45 }
uint16_t did
Definition: tis.c:16
#define PSTATE_0_MSR
Definition: msr.h:42
#define PS_STS_REG
Definition: msr.h:41
static __always_inline msr_t rdmsr(unsigned int index)
Definition: msr.h:146
unsigned int uint32_t
Definition: stdint.h:14
unsigned long long uint64_t
Definition: stdint.h:17
unsigned char uint8_t
Definition: stdint.h:8
unsigned int lo
Definition: msr.h:111
static unsigned long long rdtscll(void)
Definition: tsc.h:49
void udelay(uint32_t us)
Definition: udelay.c:15