coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
tsc_freq.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include <cpu/x86/msr.h>
4 #include <cpu/amd/msr.h>
5 #include <cpu/x86/tsc.h>
6 #include <console/console.h>
7 
8 static unsigned long mhz;
9 
10 /* Use this default TSC frequency when it can not be correctly calculated.
11  Higher numbers are safer as it will result in longer delays using TSC */
12 #define TSC_DEFAULT_FREQ_MHZ 4000
13 
14 unsigned long tsc_freq_mhz(void)
15 {
16  msr_t msr;
17  uint8_t cpufid;
18  uint8_t cpudid;
19  uint8_t high_state;
20 
21  if (mhz)
22  return mhz;
23 
24  high_state = rdmsr(PS_LIM_REG).lo & 0x7;
25  msr = rdmsr(PSTATE_0_MSR + high_state);
26  if (!(msr.hi & 0x80000000))
27  die("Unknown error: cannot determine P-state 0\n");
28 
29  cpufid = (msr.lo & 0xff);
30  cpudid = (msr.lo & 0x3f00) >> 8;
31 
32  /* normally core frequency is calculated as (fid * 25) / (did / 8) */
33  if (!cpudid) {
35  printk(BIOS_ERR, "Invalid divisor, set TSC frequency to %ldMHz\n", mhz);
36  } else if ((cpudid >= 8) && (cpudid <= 0x30)) {
37  mhz = (200 * cpufid) / cpudid;
38  } else {
39  mhz = 25 * cpufid;
40  printk(BIOS_ERR, "Invalid frequency divisor 0x%x, assume 1\n", cpudid);
41  }
42 
43  return mhz;
44 }
unsigned long tsc_freq_mhz(void)
Definition: tsc_freq.c:14
static unsigned long mhz
Definition: tsc_freq.c:8
#define TSC_DEFAULT_FREQ_MHZ
Definition: tsc_freq.c:12
#define printk(level,...)
Definition: stdlib.h:16
void __noreturn die(const char *fmt,...)
Definition: die.c:17
#define PSTATE_0_MSR
Definition: msr.h:42
#define PS_LIM_REG
Definition: msr.h:28
static __always_inline msr_t rdmsr(unsigned int index)
Definition: msr.h:146
#define BIOS_ERR
BIOS_ERR - System in incomplete state.
Definition: loglevel.h:72
unsigned char uint8_t
Definition: stdint.h:8
unsigned int hi
Definition: msr.h:112
unsigned int lo
Definition: msr.h:111