blob: 850142da37d70f3d0cd2db89588827aa4757a0ec [file] [log] [blame]
Raymond Maodaf00072024-12-06 14:54:24 -08001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (c) 2024 Linaro Limited
4 * Author: Raymond Mao <raymond.mao@linaro.org>
5 */
6#include <dm.h>
7#include <smbios_plat.h>
8#include <stdio.h>
9#include <sysinfo.h>
10
11union ccsidr_el1 {
12 struct {
13 u64 linesize:3;
14 u64 associativity:10;
15 u64 numsets:15;
16 u64 unknown:4;
17 u64 reserved:32;
18 } no_ccidx;
19 struct {
20 u64 linesize:3;
21 u64 associativity:21;
22 u64 reserved1:8;
23 u64 numsets:24;
24 u64 reserved2:8;
25 } ccidx_aarch64;
26 struct {
27 u64 linesize:3;
28 u64 associativity:21;
29 u64 reserved:8;
30 u64 unallocated:32;
31 } ccidx_aarch32;
32 u64 data;
33};
34
35union midr_el1 {
36 struct {
37 u64 revision:4;
38 u64 partnum:12;
39 u64 architecture:4;
40 u64 variant:4;
41 u64 implementer:8;
42 u64 reserved:32;
43 } fields;
44 u64 data;
45};
46
47enum {
48 CACHE_NONE,
49 CACHE_INST_ONLY,
50 CACHE_DATA_ONLY,
51 CACHE_INST_WITH_DATA,
52 CACHE_UNIFIED,
53};
54
55enum {
56 CACHE_ASSOC_DIRECT_MAPPED = 1,
57 CACHE_ASSOC_2WAY = 2,
58 CACHE_ASSOC_4WAY = 4,
59 CACHE_ASSOC_8WAY = 8,
60 CACHE_ASSOC_16WAY = 16,
61 CACHE_ASSOC_12WAY = 12,
62 CACHE_ASSOC_24WAY = 24,
63 CACHE_ASSOC_32WAY = 32,
64 CACHE_ASSOC_48WAY = 48,
65 CACHE_ASSOC_64WAY = 64,
66 CACHE_ASSOC_20WAY = 20,
67};
68
69enum {
70 VENDOR_RESERVED = 0,
71 VENDOR_ARM = 0x41,
72 VENDOR_BROADCOM = 0x42,
73 VENDOR_CAVIUM = 0x43,
74 VENDOR_DEC = 0x44,
75 VENDOR_FUJITSU = 0x46,
76 VENDOR_INFINEON = 0x49,
77 VENDOR_FREESCALE = 0x4d,
78 VENDOR_NVIDIA = 0x4e,
79 VENDOR_AMCC = 0x50,
80 VENDOR_QUALCOMM = 0x51,
81 VENDOR_MARVELL = 0x56,
82 VENDOR_INTEL = 0x69,
83 VENDOR_AMPERE = 0xc0,
84};
85
86/*
87 * TODO:
88 * To support ARMv8.3, we need to read "CCIDX, bits [23:20]" from
89 * ID_AA64MMFR2_EL1 to get the format of CCSIDR_EL1:
90 *
91 * 0b0000 - 32-bit format implemented for all levels of the CCSIDR_EL1.
92 * 0b0001 - 64-bit format implemented for all levels of the CCSIDR_EL1.
93 *
94 * Here we assume to use CCSIDR_EL1 in no CCIDX layout:
95 * NumSets, bits [27:13]: (Number of sets in cache) - 1
96 * Associativity, bits [12:3]: (Associativity of cache) - 1
97 * LineSize, bits [2:0]: (Log2(Number of bytes in cache line)) - 4
98 */
99int sysinfo_get_cache_info(u8 level, struct cache_info *cinfo)
100{
101 u64 clidr_el1;
102 u32 csselr_el1;
103 u32 num_sets;
104 union ccsidr_el1 creg;
105 int cache_type;
106
107 sysinfo_cache_info_default(cinfo);
108
109 /* Read CLIDR_EL1 */
110 asm volatile("mrs %0, clidr_el1" : "=r" (clidr_el1));
111 debug("CLIDR_EL1: 0x%llx\n", clidr_el1);
112
113 cache_type = (clidr_el1 >> (3 * level)) & 0x7;
114 if (cache_type == CACHE_NONE) /* level does not exist */
115 return -1;
116
117 switch (cache_type) {
118 case CACHE_INST_ONLY:
119 cinfo->cache_type = SMBIOS_CACHE_SYSCACHE_TYPE_INST;
120 break;
121 case CACHE_DATA_ONLY:
122 cinfo->cache_type = SMBIOS_CACHE_SYSCACHE_TYPE_DATA;
123 break;
124 case CACHE_UNIFIED:
125 cinfo->cache_type = SMBIOS_CACHE_SYSCACHE_TYPE_UNIFIED;
126 break;
127 case CACHE_INST_WITH_DATA:
128 cinfo->cache_type = SMBIOS_CACHE_SYSCACHE_TYPE_OTHER;
129 break;
130 default:
131 cinfo->cache_type = SMBIOS_CACHE_SYSCACHE_TYPE_UNKNOWN;
132 break;
133 }
134
135 /* Select cache level */
136 csselr_el1 = (level << 1);
137 asm volatile("msr csselr_el1, %0" : : "r" (csselr_el1));
138
139 /* Read CCSIDR_EL1 */
140 asm volatile("mrs %0, ccsidr_el1" : "=r" (creg.data));
141 debug("CCSIDR_EL1 (Level %d): 0x%llx\n", level + 1, creg.data);
142
143 /* Extract cache size and associativity */
144 cinfo->line_size = 1 << (creg.no_ccidx.linesize + 4);
145
146 /* Map the associativity value */
147 switch (creg.no_ccidx.associativity + 1) {
148 case CACHE_ASSOC_DIRECT_MAPPED:
149 cinfo->associativity = SMBIOS_CACHE_ASSOC_DMAPPED;
150 break;
151 case CACHE_ASSOC_2WAY:
152 cinfo->associativity = SMBIOS_CACHE_ASSOC_2WAY;
153 break;
154 case CACHE_ASSOC_4WAY:
155 cinfo->associativity = SMBIOS_CACHE_ASSOC_4WAY;
156 break;
157 case CACHE_ASSOC_8WAY:
158 cinfo->associativity = SMBIOS_CACHE_ASSOC_8WAY;
159 break;
160 case CACHE_ASSOC_16WAY:
161 cinfo->associativity = SMBIOS_CACHE_ASSOC_16WAY;
162 break;
163 case CACHE_ASSOC_12WAY:
164 cinfo->associativity = SMBIOS_CACHE_ASSOC_12WAY;
165 break;
166 case CACHE_ASSOC_24WAY:
167 cinfo->associativity = SMBIOS_CACHE_ASSOC_24WAY;
168 break;
169 case CACHE_ASSOC_32WAY:
170 cinfo->associativity = SMBIOS_CACHE_ASSOC_32WAY;
171 break;
172 case CACHE_ASSOC_48WAY:
173 cinfo->associativity = SMBIOS_CACHE_ASSOC_48WAY;
174 break;
175 case CACHE_ASSOC_64WAY:
176 cinfo->associativity = SMBIOS_CACHE_ASSOC_64WAY;
177 break;
178 case CACHE_ASSOC_20WAY:
179 cinfo->associativity = SMBIOS_CACHE_ASSOC_20WAY;
180 break;
181 default:
182 cinfo->associativity = SMBIOS_CACHE_ASSOC_UNKNOWN;
183 break;
184 }
185
186 num_sets = creg.no_ccidx.numsets + 1;
187 /* Size in KB */
188 cinfo->max_size = (cinfo->associativity * num_sets * cinfo->line_size) /
189 1024;
190
191 debug("L%d Cache:\n", level + 1);
192 debug("Number of bytes in cache line:%u\n", cinfo->line_size);
193 debug("Associativity of cache:%u\n", cinfo->associativity);
194 debug("Number of sets in cache:%u\n", num_sets);
195 debug("Cache size in KB:%u\n", cinfo->max_size);
196
197 cinfo->inst_size = cinfo->max_size;
198
199 /*
200 * Below fields with common values are placed under DT smbios node
201 * socket-design, config
202 * Other fields are typically specific to the implementation of the ARM
203 * processor by the silicon vendor:
204 * supp_sram_type, curr_sram_type, speed, err_corr_type
205 */
206
207 return 0;
208}
209
210int sysinfo_get_processor_info(struct processor_info *pinfo)
211{
212 u64 mpidr, core_count;
213 union midr_el1 midr;
214
215 /* Read the MIDR_EL1 register */
216 asm volatile("mrs %0, MIDR_EL1" : "=r"(midr.data));
217 /* Read the MPIDR_EL1 register */
218 asm volatile("mrs %0, MPIDR_EL1" : "=r"(mpidr));
219
220 debug("MIDR: 0x%016llx\n", midr.data);
221 debug("MPIDR: 0x%016llx\n", mpidr);
222 debug("CPU Implementer: 0x%02x\n", midr.fields.implementer);
223
224 switch (midr.fields.implementer) {
225 case VENDOR_ARM:
226 pinfo->manufacturer = "ARM Limited";
227 break;
228 case VENDOR_BROADCOM:
229 pinfo->manufacturer = "Broadcom Corporation";
230 break;
231 case VENDOR_CAVIUM:
232 pinfo->manufacturer = "Cavium Inc";
233 break;
234 case VENDOR_DEC:
235 pinfo->manufacturer = "Digital Equipment Corporation";
236 break;
237 case VENDOR_FUJITSU:
238 pinfo->manufacturer = "Fujitsu Ltd";
239 break;
240 case VENDOR_INFINEON:
241 pinfo->manufacturer = "Infineon Technologies AG";
242 break;
243 case VENDOR_FREESCALE:
244 pinfo->manufacturer = "Freescale Semiconductor Inc";
245 break;
246 case VENDOR_NVIDIA:
247 pinfo->manufacturer = "NVIDIA Corporation";
248 break;
249 case VENDOR_AMCC:
250 pinfo->manufacturer =
251 "Applied Micro Circuits Corporation";
252 break;
253 case VENDOR_QUALCOMM:
254 pinfo->manufacturer = "Qualcomm Inc";
255 break;
256 case VENDOR_MARVELL:
257 pinfo->manufacturer = "Marvell International Ltd";
258 break;
259 case VENDOR_INTEL:
260 pinfo->manufacturer = "Intel Corporation";
261 break;
262 case VENDOR_AMPERE:
263 pinfo->manufacturer = "Ampere Computing";
264 break;
265 default:
266 pinfo->manufacturer = "Unknown";
267 break;
268 }
269 debug("CPU part number: 0x%x\n", midr.fields.partnum);
270 debug("CPU revision: 0x%x\n", midr.fields.revision);
271 debug("CPU architecture: 0x%x\n", midr.fields.architecture);
272 debug("CPU variant: 0x%x\n", midr.fields.variant);
273
274 /* Extract number of cores */
275 core_count = (mpidr >> 0) & 0xFF;
276 pinfo->core_count = core_count + 1;
277 debug("CPU Core Count: %d\n", pinfo->core_count);
278
279 pinfo->core_enabled = pinfo->core_count;
280 pinfo->characteristics = SMBIOS_PROCESSOR_64BIT |
281 SMBIOS_PROCESSOR_ARM64_SOCID;
282 if (pinfo->core_count > 1)
283 pinfo->characteristics |= SMBIOS_PROCESSOR_MULTICORE;
284
285 /*
286 * Below fields with common values are placed under DT smbios node
287 * version, processor-type, processor-status, upgrade, family2,
288 * socket-design, serial, asset-tag, part-number
289 */
290
291 return 0;
292}