xref: /aosp_15_r20/external/coreboot/payloads/libpayload/arch/x86/timer.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /*
2  *
3  * Copyright (C) 2008 Advanced Micro Devices, Inc.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. The name of the author may not be used to endorse or promote products
14  *    derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 /**
30  * @file x86/timer.c
31  * x86 specific timer routines
32  */
33 
34 #include <libpayload.h>
35 #include <arch/rdtsc.h>
36 #include <arch/cpuid.h>
37 #include <arch/msr.h>
38 
39 #define MSR_PLATFORM_INFO		0xce
40 
41 /**
42  * @ingroup arch
43  * Global variable containing the speed of the processor in KHz.
44  */
45 uint32_t cpu_khz;
46 
47 /**
48  * @brief Measure the speed of the processor for use in delays
49  *
50  * @return The CPU speed in kHz.
51  */
calibrate_pit(void)52 static unsigned int calibrate_pit(void)
53 {
54 	unsigned long long start, end;
55 	const uint32_t clock_rate = 1193182; // 1.193182 MHz
56 	const uint16_t interval = (2 * clock_rate) / 1000; // 2 ms
57 
58 	/* Set up the PPC port - disable the speaker, enable the T2 gate. */
59 	outb((inb(0x61) & ~0x02) | 0x01, 0x61);
60 
61 	/* Set the PIT to Mode 0, counter 2, word access. */
62 	outb(0xB0, 0x43);
63 
64 	/* Load the interval into the counter. */
65 	outb(interval & 0xff, 0x42);
66 	outb((interval >> 8) & 0xff, 0x42);
67 
68 	/* Read the number of ticks during the period. */
69 	start = rdtsc();
70 	while (!(inb(0x61) & 0x20)) ;
71 	end = rdtsc();
72 
73 	/*
74 	 * The number of milliseconds for a period is
75 	 * clock_rate / (interval * 1000). Multiply that by the number of
76 	 * measured clocks to get the kHz value.
77 	 */
78 	return (end - start) * clock_rate / (1000 * interval);
79 }
80 
81 /**
82  * @brief Calculates the core clock frequency via CPUID 0x15
83  *
84  * Newer Intel CPUs report their core clock in CPUID leaf 0x15. Early models
85  * supporting this leaf didn't provide the nominal crystal frequency in ecx,
86  * hence we use hard coded values for them.
87  */
get_cpu_khz_xtal(void)88 static int get_cpu_khz_xtal(void)
89 {
90 	uint32_t ecx, edx, num, denom;
91 	uint64_t nominal;
92 
93 	if (cpuid_max() < 0x15)
94 		return -1;
95 	cpuid(0x15, denom, num, ecx, edx);
96 
97 	if (denom == 0 || num == 0)
98 		return -1;
99 
100 	if (ecx != 0) {
101 		nominal = ecx;
102 	} else {
103 		if (cpuid_family() != 6)
104 			return -1;
105 
106 		switch (cpuid_model()) {
107 		case SKYLAKE_U_Y:
108 		case SKYLAKE_S_H:
109 		case KABYLAKE_U_Y:
110 		case KABYLAKE_S_H:
111 			nominal = 24000000;
112 			break;
113 		case APOLLOLAKE:
114 			nominal = 19200000;
115 			break;
116 		default:
117 			return -1;
118 		}
119 	}
120 
121 	return nominal * num / denom / 1000;
122 }
123 
124 /**
125  * @brief Returns three times the bus clock in kHz
126  *
127  * The result of calculations with the returned value shall be divided by 3.
128  * This helps to avoid rounding errors.
129  */
get_bus_khz_x3(void)130 static int get_bus_khz_x3(void)
131 {
132 	if (cpuid_family() != 6)
133 		return -1;
134 
135 	switch (cpuid_model()) {
136 	case NEHALEM:
137 		return 400 * 1000; /* 133 MHz */
138 	case SANDYBRIDGE:
139 	case IVYBRIDGE:
140 	case HASWELL:
141 	case HASWELL_U:
142 	case HASWELL_GT3E:
143 	case BROADWELL:
144 	case BROADWELL_U:
145 		return 300 * 1000; /* 100 MHz */
146 	default:
147 		return -1;
148 	}
149 }
150 
151 /**
152  * @brief Returns the calculated CPU frequency
153  *
154  * Over the years, multiple ways to discover the CPU frequency have been
155  * exposed through CPUID and MSRs. Try the most recent and accurate first
156  * (crystal information in CPUID leaf 0x15) and then fall back to older
157  * methods.
158  *
159  * This should cover all Intel Core i processors at least. For older
160  * processors we fall back to the PIT calibration.
161  */
get_cpu_khz_fast(void)162 static int get_cpu_khz_fast(void)
163 {
164 	/* Try core crystal clock frequency first (supposed to be more accurate). */
165 	const int cpu_khz_xtal = get_cpu_khz_xtal();
166 	if (cpu_khz_xtal > 0)
167 		return cpu_khz_xtal;
168 
169 	/* Try `bus clock * speedstep multiplier`. */
170 	const int bus_x3 = get_bus_khz_x3();
171 	if (bus_x3 <= 0)
172 		return -1;
173 	/*
174 	 * Systems with an invariant TSC report the multiplier (maximum
175 	 * non-turbo ratio) in MSR_PLATFORM_INFO[15:8].
176 	 */
177 	const unsigned int mult = _rdmsr(MSR_PLATFORM_INFO) >> 8 & 0xff;
178 	return bus_x3 * mult / 3;
179 }
180 
get_cpu_speed(void)181 unsigned int get_cpu_speed(void)
182 {
183 	const int cpu_khz_fast = get_cpu_khz_fast();
184 	if (cpu_khz_fast > 0)
185 		cpu_khz = (unsigned int)cpu_khz_fast;
186 	else
187 		cpu_khz = calibrate_pit();
188 
189 	return cpu_khz;
190 }
191