blob: c4d30a2c06cdfd393fc29bbf03e996c256d7d444 [file] [log] [blame]
Patrick Georgi11f00792020-03-04 15:10:45 +01001/* SPDX-License-Identifier: GPL-2.0-only */
Martin Roth9df9e9392016-01-12 15:55:28 -07002
Lee Leahy2da95242015-06-12 17:30:33 -07003#include <cpu/cpu.h>
Elyes Haouasae1ca822022-10-07 10:02:38 +02004#include <types.h>
Lee Leahy2da95242015-06-12 17:30:33 -07005
Patrick Rudolphadcf7822020-08-27 20:50:18 +02006#if ENV_X86_32
Lee Leahy2da95242015-06-12 17:30:33 -07007/* Standard macro to see if a specific flag is changeable */
8static inline int flag_is_changeable_p(uint32_t flag)
9{
10 uint32_t f1, f2;
11
12 asm(
13 "pushfl\n\t"
14 "pushfl\n\t"
15 "popl %0\n\t"
16 "movl %0,%1\n\t"
17 "xorl %2,%0\n\t"
18 "pushl %0\n\t"
19 "popfl\n\t"
20 "pushfl\n\t"
21 "popl %0\n\t"
22 "popfl\n\t"
23 : "=&r" (f1), "=&r" (f2)
24 : "ir" (flag));
25 return ((f1^f2) & flag) != 0;
26}
27
28/* Probe for the CPUID instruction */
29int cpu_have_cpuid(void)
30{
31 return flag_is_changeable_p(X86_EFLAGS_ID);
32}
33
Stefan Reinauer96938852015-06-18 01:23:48 -070034#else
35
36int cpu_have_cpuid(void)
37{
38 return 1;
39}
40#endif
41
Elyes HAOUAS1c9bd9c2019-06-26 17:49:31 +020042unsigned int cpu_cpuid_extended_level(void)
Lee Leahy2da95242015-06-12 17:30:33 -070043{
44 return cpuid_eax(0x80000000);
45}
46
Felix Heldff4d6be2023-09-12 14:18:49 +020047unsigned int cpu_phys_address_size(void)
Lee Leahy2da95242015-06-12 17:30:33 -070048{
49 if (!(cpu_have_cpuid()))
50 return 32;
51
Jeremy Compostella1eff77b2023-09-07 10:33:30 -070052 if (cpu_cpuid_extended_level() >= 0x80000008) {
53 int size = cpuid_eax(0x80000008) & 0xff;
54 size -= get_reserved_phys_addr_bits();
55 return size;
56 }
Lee Leahy2da95242015-06-12 17:30:33 -070057
58 if (cpuid_edx(1) & (CPUID_FEATURE_PAE | CPUID_FEATURE_PSE36))
59 return 36;
60 return 32;
61}
Subrata Banik53b08c32018-12-10 14:11:35 +053062
Jeremy Compostellaba757a72023-12-20 09:07:04 -080063unsigned int soc_phys_address_size(void)
64{
65 if (CONFIG_SOC_PHYSICAL_ADDRESS_WIDTH)
66 return CONFIG_SOC_PHYSICAL_ADDRESS_WIDTH;
67
68 return cpu_phys_address_size();
69}
70
Subrata Banik53b08c32018-12-10 14:11:35 +053071/*
72 * Get processor id using cpuid eax=1
73 * return value in EAX register
74 */
75uint32_t cpu_get_cpuid(void)
76{
77 return cpuid_eax(1);
78}
79
80/*
81 * Get processor feature flag using cpuid eax=1
82 * return value in ECX register
83 */
84uint32_t cpu_get_feature_flags_ecx(void)
85{
86 return cpuid_ecx(1);
87}
88
89/*
90 * Get processor feature flag using cpuid eax=1
91 * return value in EDX register
92 */
93uint32_t cpu_get_feature_flags_edx(void)
94{
95 return cpuid_edx(1);
96}
Subrata Banik0c6c0da2021-07-23 21:00:58 +053097
98enum cpu_type cpu_check_deterministic_cache_cpuid_supported(void)
99{
Subrata Banik0c6c0da2021-07-23 21:00:58 +0530100 if (cpu_is_intel()) {
Felix Held3581a682023-09-23 03:44:55 +0200101 if (cpuid_get_max_func() < 4)
Subrata Banik0c6c0da2021-07-23 21:00:58 +0530102 return CPUID_COMMAND_UNSUPPORTED;
103 return CPUID_TYPE_INTEL;
104 } else if (cpu_is_amd()) {
Felix Held9acae392023-09-21 20:33:10 +0200105 if (cpu_cpuid_extended_level() < 0x80000001)
Subrata Banik0c6c0da2021-07-23 21:00:58 +0530106 return CPUID_COMMAND_UNSUPPORTED;
107
Felix Held1d466f22023-09-21 20:34:43 +0200108 if (!(cpuid_ecx(0x80000001) & (1 << 22)))
Subrata Banik0c6c0da2021-07-23 21:00:58 +0530109 return CPUID_COMMAND_UNSUPPORTED;
110
111 return CPUID_TYPE_AMD;
112 } else {
113 return CPUID_TYPE_INVALID;
114 }
115}
116
117static uint32_t cpu_get_cache_info_leaf(void)
118{
Subrata Banik72f1e622021-09-01 12:35:15 +0530119 uint32_t leaf = (cpu_check_deterministic_cache_cpuid_supported() == CPUID_TYPE_AMD) ?
120 DETERMINISTIC_CACHE_PARAMETERS_CPUID_AMD :
121 DETERMINISTIC_CACHE_PARAMETERS_CPUID_IA;
122
123 return leaf;
Subrata Banik0c6c0da2021-07-23 21:00:58 +0530124}
125
126size_t cpu_get_cache_ways_assoc_info(const struct cpu_cache_info *info)
127{
128 if (!info)
129 return 0;
130
131 return info->num_ways;
132}
133
134uint8_t cpu_get_cache_type(const struct cpu_cache_info *info)
135{
136 if (!info)
137 return 0;
138
139 return info->type;
140}
141
142uint8_t cpu_get_cache_level(const struct cpu_cache_info *info)
143{
144 if (!info)
145 return 0;
146
147 return info->level;
148}
149
150size_t cpu_get_cache_phy_partition_info(const struct cpu_cache_info *info)
151{
152 if (!info)
153 return 0;
154
155 return info->physical_partitions;
156}
157
158size_t cpu_get_cache_line_size(const struct cpu_cache_info *info)
159{
160 if (!info)
161 return 0;
162
163 return info->line_size;
164}
165
166size_t cpu_get_cache_sets(const struct cpu_cache_info *info)
167{
168 if (!info)
169 return 0;
170
171 return info->num_sets;
172}
173
174bool cpu_is_cache_full_assoc(const struct cpu_cache_info *info)
175{
176 if (!info)
177 return false;
178
179 return info->fully_associative;
180}
181
182size_t cpu_get_max_cache_share(const struct cpu_cache_info *info)
183{
184 if (!info)
185 return 0;
186
187 return info->num_cores_shared;
188}
189
190size_t get_cache_size(const struct cpu_cache_info *info)
191{
192 if (!info)
193 return 0;
194
195 return info->num_ways * info->physical_partitions * info->line_size * info->num_sets;
196}
197
Patrick Rudolph6a13b522023-10-03 18:03:51 +0200198/*
199 * Returns the sub-states supported by the specified CPU
200 * C-state level.
201 *
202 * Level 0 corresponds to the lowest C-state (C0).
203 * Higher levels are processor specific.
204 */
205uint8_t cpu_get_c_substate_support(const int state)
206{
207 if ((cpuid_get_max_func() < 5) ||
208 !(cpuid_ecx(5) & CPUID_FEATURE_MONITOR_MWAIT) || (state > 4))
209 return 0;
210
211 return (cpuid_edx(5) >> (state * 4)) & 0xf;
212}
213
Subrata Banik0c6c0da2021-07-23 21:00:58 +0530214bool fill_cpu_cache_info(uint8_t level, struct cpu_cache_info *info)
215{
216 if (!info)
217 return false;
218
219 uint32_t leaf = cpu_get_cache_info_leaf();
220 if (!leaf)
221 return false;
222
223 struct cpuid_result cache_info_res = cpuid_ext(leaf, level);
224
225 info->type = CPUID_CACHE_TYPE(cache_info_res);
226 info->level = CPUID_CACHE_LEVEL(cache_info_res);
227 info->num_ways = CPUID_CACHE_WAYS_OF_ASSOC(cache_info_res) + 1;
228 info->num_sets = CPUID_CACHE_NO_OF_SETS(cache_info_res) + 1;
229 info->line_size = CPUID_CACHE_COHER_LINE(cache_info_res) + 1;
230 info->physical_partitions = CPUID_CACHE_PHYS_LINE(cache_info_res) + 1;
231 info->num_cores_shared = CPUID_CACHE_SHARING_CACHE(cache_info_res) + 1;
232 info->fully_associative = CPUID_CACHE_FULL_ASSOC(cache_info_res);
233 info->size = get_cache_size(info);
234
235 return true;
236}