• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <commonlib/helpers.h>
4 #include <console/console.h>
5 #include <cpu/cpu.h>
6 #include <cpu/intel/fsb.h>
7 #include <cpu/intel/speedstep.h>
8 #include <cpu/x86/msr.h>
9 #include <cpu/x86/tsc.h>
10 #include <delay.h>
11 #include <stdint.h>
12 
13 static u32 timer_fsb;
14 static u32 timer_tsc;
15 
16 /* This is not an architectural MSR. */
17 #define MSR_PLATFORM_INFO 0xce
18 
get_fsb_tsc(int * fsb,int * ratio)19 static int get_fsb_tsc(int *fsb, int *ratio)
20 {
21 	struct cpuinfo_x86 c;
22 	static const short core_fsb[8] = { -1, 133, -1, 166, -1, 100, -1, -1 };
23 	static const short core2_fsb[8] = { 266, 133, 200, 166, 333, 100, 400, -1 };
24 	static const short f2x_fsb[8] = { 100, 133, 200, 166, 333, -1, -1, -1 };
25 	static const short rangeley_fsb[4] = { 83, 100, 133, 116 };
26 	msr_t msr;
27 
28 	get_fms(&c, cpuid_eax(1));
29 	switch (c.x86) {
30 	case 0x6:
31 		switch (c.x86_model) {
32 		case 0xe:  /* Core Solo/Duo */
33 		case 0x1c: /* Atom */
34 			*fsb = core_fsb[rdmsr(MSR_FSB_FREQ).lo & 7];
35 			*ratio = (rdmsr(IA32_PERF_STATUS).hi >> 8) & 0x1f;
36 			break;
37 		case 0xf:  /* Core 2 or Xeon */
38 		case 0x17: /* Enhanced Core */
39 			*fsb = core2_fsb[rdmsr(MSR_FSB_FREQ).lo & 7];
40 			*ratio = (rdmsr(IA32_PERF_STATUS).hi >> 8) & 0x1f;
41 			break;
42 		case 0x25: /* Arrandale BCLK fixed at 133MHz */
43 			*fsb = 133;
44 			*ratio = (rdmsr(MSR_PLATFORM_INFO).lo >> 8) & 0xff;
45 			break;
46 		case 0x2a: /* SandyBridge BCLK fixed at 100MHz */
47 		case 0x3a: /* IvyBridge BCLK fixed at 100MHz */
48 		case 0x3c: /* Haswell BCLK fixed at 100MHz */
49 		case 0x3d: /* Broadwell-ULT BCLK fixed at 100MHz */
50 		case 0x45: /* Haswell-ULT BCLK fixed at 100MHz */
51 		case 0x46: /* Haswell-GT3e BCLK fixed at 100MHz */
52 		case 0x47: /* Broadwell BCLK fixed at 100MHz */
53 			*fsb = 100;
54 			*ratio = (rdmsr(MSR_PLATFORM_INFO).lo >> 8) & 0xff;
55 			break;
56 		case 0x4d: /* Rangeley */
57 			*fsb = rangeley_fsb[rdmsr(MSR_FSB_FREQ).lo & 3];
58 			*ratio = (rdmsr(MSR_PLATFORM_INFO).lo >> 8) & 0xff;
59 			break;
60 		default:
61 			return -2;
62 		}
63 		break;
64 	case 0xf: /* Netburst */
65 		msr = rdmsr(MSR_EBC_FREQUENCY_ID);
66 		*ratio = msr.lo >> 24;
67 		switch (c.x86_model) {
68 		case 0x2:
69 			*fsb = f2x_fsb[(msr.lo >> 16) & 7];
70 			break;
71 		case 0x3:
72 		case 0x4:
73 		case 0x6:
74 			*fsb = core2_fsb[(msr.lo >> 16) & 7];
75 			break;
76 		default:
77 			return -2;
78 		}
79 		break;
80 	default:
81 		return -2;
82 	}
83 	if (*fsb > 0)
84 		return 0;
85 	return -1;
86 }
87 
resolve_timebase(void)88 static void resolve_timebase(void)
89 {
90 	int ret, fsb, ratio;
91 
92 	ret = get_fsb_tsc(&fsb, &ratio);
93 	if (ret == 0) {
94 		u32 tsc = 100 * DIV_ROUND_CLOSEST(ratio * fsb, 100);
95 		timer_fsb = fsb;
96 		timer_tsc = tsc;
97 		return;
98 	}
99 
100 	if (ret == -1)
101 		printk(BIOS_ERR, "FSB not found\n");
102 	if (ret == -2)
103 		printk(BIOS_ERR, "CPU not supported\n");
104 
105 	/* Set some semi-ridiculous defaults. */
106 	timer_fsb = 500;
107 	timer_tsc = 5000;
108 }
109 
get_timer_fsb(void)110 u32 get_timer_fsb(void)
111 {
112 	if (timer_fsb > 0)
113 		return timer_fsb;
114 
115 	resolve_timebase();
116 	return timer_fsb;
117 }
118 
tsc_freq_mhz(void)119 unsigned long tsc_freq_mhz(void)
120 {
121 	if (timer_tsc > 0)
122 		return timer_tsc;
123 
124 	resolve_timebase();
125 	return timer_tsc;
126 }
127 
128 /**
129  * @brief Returns three times the FSB clock in MHz
130  *
131  * The result of calculations with the returned value shall be divided by 3.
132  * This helps to avoid rounding errors.
133  */
get_ia32_fsb_x3(void)134 int get_ia32_fsb_x3(void)
135 {
136 	const int fsb = get_timer_fsb();
137 
138 	if (fsb > 0)
139 		return 100 * DIV_ROUND_CLOSEST(3 * fsb, 100);
140 
141 	printk(BIOS_ERR, "FSB not supported or not found\n");
142 	return -1;
143 }
144