xref: /illumos-gate/usr/src/lib/libjedec/common/libjedec_spd_ddr5.c (revision e8d3efa1c56e5f2b5368600a2baeb7b1d54a07f8)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2026 Oxide Computer Company
14  */
15 
16 /*
17  * DDR5-specific SPD processing logic. For an overview of the processing design
18  * please see libjedec_spd.c. Note, this currently does not handle NVDIMMs.
19  */
20 
21 #include <sys/sysmacros.h>
22 #include <sys/debug.h>
23 #include "libjedec_spd.h"
24 
25 static const spd_value_map_t spd_ddr5_nbytes_total_map[] = {
26 	{ SPD_DDR5_NBYTES_TOTAL_UNDEF, 0, true },
27 	{ SPD_DDR5_NBYTES_TOTAL_256, 256, false },
28 	{ SPD_DDR5_NBYTES_TOTAL_512, 512, false },
29 	{ SPD_DDR5_NBYTES_TOTAL_1024, 1024, false },
30 	{ SPD_DDR5_NBYTES_TOTAL_2048, 2048, false }
31 };
32 
33 static void
34 spd_parse_ddr5_nbytes(spd_info_t *si, uint32_t off, uint32_t len,
35     const char *key)
36 {
37 	const uint8_t data = si->si_data[off];
38 	const uint8_t total = SPD_DDR5_NBYTES_TOTAL(data);
39 	uint8_t beta = SPD_DDR5_NBYTES_BETA(data);
40 	beta = bitset8(beta, 4, 4, SPD_DDR5_NBYTES_BETAHI(data));
41 
42 	spd_nvl_insert_u32(si, SPD_KEY_BETA, beta);
43 	spd_insert_map(si, SPD_KEY_NBYTES_TOTAL, total,
44 	    spd_ddr5_nbytes_total_map, ARRAY_SIZE(spd_ddr5_nbytes_total_map));
45 }
46 
47 static const spd_value_map_t spd_ddr5_mod_type_map[] = {
48 	{ SPD_DDR5_MOD_TYPE_TYPE_RDIMM, SPD_MOD_TYPE_RDIMM, false },
49 	{ SPD_DDR5_MOD_TYPE_TYPE_UDIMM, SPD_MOD_TYPE_UDIMM, false },
50 	{ SPD_DDR5_MOD_TYPE_TYPE_SODIMM, SPD_MOD_TYPE_SODIMM, false },
51 	{ SPD_DDR5_MOD_TYPE_TYPE_LRDIMM, SPD_MOD_TYPE_LRDIMM, false },
52 	{ SPD_DDR5_MOD_TYPE_TYPE_CUDIMM, SPD_MOD_TYPE_CUDIMM, false },
53 	{ SPD_DDR5_MOD_TYPE_TYPE_CSODIMM, SPD_MOD_TYPE_CSODIMM, false },
54 	{ SPD_DDR5_MOD_TYPE_TYPE_MRDIMM, SPD_MOD_TYPE_MRDIMM, false },
55 	{ SPD_DDR5_MOD_TYPE_TYPE_CAMM2, SPD_MOD_TYPE_CAMM2, false },
56 	{ SPD_DDR5_MOD_TYPE_TYPE_SOCAMM2, SPD_MOD_TYPE_SOCAMM2, false },
57 	{ SPD_DDR5_MOD_TYPE_TYPE_DDIMM, SPD_MOD_TYPE_DDIMM, false },
58 	{ SPD_DDR5_MOD_TYPE_TYPE_SOLDER, SPD_MOD_TYPE_SOLDER, false }
59 };
60 
61 static const spd_value_map_t spd_ddr5_mod_is_hybrid_map[] = {
62 	{ 0, SPD_MOD_NOT_HYBRID, false },
63 	{ 1, SPD_MOD_HYBRID_NVDIMMM, false }
64 };
65 
66 static const spd_value_map_t spd_ddr5_mod_hybrid_map[] = {
67 	{ SPD_DDR5_MOD_TYPE_HYBRID_NVDIMM_N, SPD_MOD_TYPE_NVDIMM_N, false },
68 	{ SPD_DDR5_MOD_TYPE_HYBRID_NVDIMM_P, SPD_MOD_TYPE_NVDIMM_P, false }
69 };
70 
71 /*
72  * This is shared between DDR5 and LPDDR5 as they end up using the same
73  * definitions for module types.
74  */
75 void
76 spd_parse_ddr5_mod_type(spd_info_t *si, uint32_t off, uint32_t len,
77     const char *key)
78 {
79 	const uint8_t data = si->si_data[off];
80 	const uint8_t type = SPD_DDR5_MOD_TYPE_TYPE(data);
81 	const uint8_t is_hyb = SPD_DDR5_MOD_TYPE_ISHYBRID(data);
82 	const uint8_t hybrid = SPD_DDR5_MOD_TYPE_HYBRID(data);
83 
84 	spd_insert_map(si, SPD_KEY_MOD_HYBRID_TYPE, is_hyb,
85 	    spd_ddr5_mod_is_hybrid_map, ARRAY_SIZE(spd_ddr5_mod_is_hybrid_map));
86 
87 	if (is_hyb != 0) {
88 		spd_insert_map(si, SPD_KEY_MOD_NVDIMM_TYPE, hybrid,
89 		    spd_ddr5_mod_hybrid_map,
90 		    ARRAY_SIZE(spd_ddr5_mod_hybrid_map));
91 	}
92 
93 	spd_insert_map(si, SPD_KEY_MOD_TYPE, type, spd_ddr5_mod_type_map,
94 	    ARRAY_SIZE(spd_ddr5_mod_type_map));
95 }
96 
97 static bool
98 spd_parse_ddr5_isassym(spd_info_t *si)
99 {
100 	ASSERT3U(si->si_size, >, SPD_DDR5_COM_ORG);
101 	const uint8_t data = si->si_data[SPD_DDR5_COM_ORG];
102 	const uint8_t is_asym = SPD_DDR5_COM_ORG_MIX(data);
103 
104 	return (is_asym == SPD_DDR5_COM_ORG_MIX_ASYM);
105 }
106 
107 static const spd_value_map64_t spd_ddr5_density_map[] = {
108 	{ SPD_DDR5_DENPKG_DPD_4Gb, 4ULL * 1024ULL * 1024ULL * 1024ULL, false },
109 	{ SPD_DDR5_DENPKG_DPD_8Gb, 8ULL * 1024ULL * 1024ULL * 1024ULL, false },
110 	{ SPD_DDR5_DENPKG_DPD_12Gb, 12ULL * 1024ULL * 1024ULL * 1024ULL,
111 	    false },
112 	{ SPD_DDR5_DENPKG_DPD_16Gb, 16ULL * 1024ULL * 1024ULL * 1024ULL,
113 	    false },
114 	{ SPD_DDR5_DENPKG_DPD_24Gb, 24ULL * 1024ULL * 1024ULL * 1024ULL,
115 	    false },
116 	{ SPD_DDR5_DENPKG_DPD_32Gb, 32ULL * 1024ULL * 1024ULL * 1024ULL,
117 	    false },
118 	{ SPD_DDR5_DENPKG_DPD_48Gb, 48ULL * 1024ULL * 1024ULL * 1024ULL,
119 	    false },
120 	{ SPD_DDR5_DENPKG_DPD_64Gb, 64ULL * 1024ULL * 1024ULL * 1024ULL,
121 	    false },
122 };
123 
124 static const spd_value_map_t spd_ddr5_ndies_map[] = {
125 	{ SPD_DDR5_DENPKG_DPP_MONO, 1, false },
126 	{ SPD_DDR5_DENPKG_DPP_DDP, 2, false },
127 	{ SPD_DDR5_DENPKG_DPP_2H3DS, 2, false },
128 	{ SPD_DDR5_DENPKG_DPP_4H3DS, 4, false },
129 	{ SPD_DDR5_DENPKG_DPP_8H3DS, 8, false },
130 	{ SPD_DDR5_DENPKG_DPP_16H3DS, 16, false },
131 };
132 
133 static const spd_value_map_t spd_ddr5_sl_map[] = {
134 	{ SPD_DDR5_DENPKG_DPP_MONO, SPD_SL_UNSPECIFIED, false },
135 	{ SPD_DDR5_DENPKG_DPP_DDP, SPD_SL_UNSPECIFIED, false },
136 	{ SPD_DDR5_DENPKG_DPP_2H3DS, SPD_SL_3DS, false },
137 	{ SPD_DDR5_DENPKG_DPP_4H3DS, SPD_SL_3DS, false },
138 	{ SPD_DDR5_DENPKG_DPP_8H3DS, SPD_SL_3DS, false },
139 	{ SPD_DDR5_DENPKG_DPP_16H3DS, SPD_SL_3DS, false },
140 };
141 
142 static void
143 spd_parse_ddr5_denpkg(spd_info_t *si, uint8_t data, const char *ndie_key,
144     const char *den_key, const char *sl_key)
145 {
146 	const uint8_t ndie = SPD_DDR5_DENPKG_DPP(data);
147 	const uint8_t dens = SPD_DDR5_DENPKG_DPD(data);
148 
149 	spd_insert_map(si, ndie_key, ndie, spd_ddr5_ndies_map,
150 	    ARRAY_SIZE(spd_ddr5_ndies_map));
151 	spd_insert_map(si, sl_key, ndie, spd_ddr5_sl_map,
152 	    ARRAY_SIZE(spd_ddr5_sl_map));
153 	spd_insert_map64(si, den_key, dens, spd_ddr5_density_map,
154 	    ARRAY_SIZE(spd_ddr5_density_map));
155 }
156 
157 static void
158 spd_parse_ddr5_denpkg_pri(spd_info_t *si, uint32_t off, uint32_t len,
159     const char *key)
160 {
161 	spd_parse_ddr5_denpkg(si, si->si_data[off], SPD_KEY_PKG_NDIE,
162 	    SPD_KEY_DIE_SIZE, SPD_KEY_PKG_SL);
163 }
164 
165 static void
166 spd_parse_ddr5_denpkg_sec(spd_info_t *si, uint32_t off, uint32_t len,
167     const char *key)
168 {
169 	if (!spd_parse_ddr5_isassym(si))
170 		return;
171 
172 	spd_parse_ddr5_denpkg(si, si->si_data[off], SPD_KEY_SEC_PKG_NDIE,
173 	    SPD_KEY_SEC_DIE_SIZE, SPD_KEY_SEC_PKG_SL);
174 }
175 
176 static const spd_value_range_t spd_ddr5_nrow_range = {
177 	.svr_max = SPD_DDR5_ADDR_NROWS_MAX,
178 	.svr_base = SPD_DDR5_ADDR_NROWS_BASE
179 };
180 
181 static const spd_value_range_t spd_ddr5_ncol_range = {
182 	.svr_max = SPD_DDR5_ADDR_NCOLS_MAX,
183 	.svr_base = SPD_DDR5_ADDR_NCOLS_BASE
184 };
185 
186 static void
187 spd_parse_ddr5_addr(spd_info_t *si, uint8_t data, const char *row_key,
188     const char *col_key)
189 {
190 	const uint8_t ncols = SPD_DDR5_ADDR_NCOLS(data);
191 	const uint8_t nrows = SPD_DDR5_ADDR_NROWS(data);
192 
193 	spd_insert_range(si, col_key, ncols, &spd_ddr5_ncol_range);
194 	spd_insert_range(si, row_key, nrows, &spd_ddr5_nrow_range);
195 }
196 
197 static void
198 spd_parse_ddr5_addr_pri(spd_info_t *si, uint32_t off, uint32_t len,
199     const char *key)
200 {
201 	spd_parse_ddr5_addr(si, si->si_data[off], SPD_KEY_NROW_BITS,
202 	    SPD_KEY_NCOL_BITS);
203 }
204 
205 static void
206 spd_parse_ddr5_addr_sec(spd_info_t *si, uint32_t off, uint32_t len,
207     const char *key)
208 {
209 	if (!spd_parse_ddr5_isassym(si))
210 		return;
211 
212 	spd_parse_ddr5_addr(si, si->si_data[off], SPD_KEY_SEC_NROW_BITS,
213 	    SPD_KEY_SEC_NCOL_BITS);
214 }
215 
216 static const spd_value_map_t spd_ddr5_width_map[] = {
217 	{ SPD_DDR5_WIDTH_X4, 4, false },
218 	{ SPD_DDR5_WIDTH_X8, 8, false },
219 	{ SPD_DDR5_WIDTH_X16, 16, false },
220 	{ SPD_DDR5_WIDTH_X32, 32, false }
221 };
222 
223 static void
224 spd_parse_ddr5_width(spd_info_t *si, uint8_t data, const char *key)
225 {
226 	const uint8_t width = SPD_DDR5_WIDTH_WIDTH(data);
227 
228 	spd_insert_map(si, key, width, spd_ddr5_width_map,
229 	    ARRAY_SIZE(spd_ddr5_width_map));
230 }
231 
232 static void
233 spd_parse_ddr5_width_pri(spd_info_t *si, uint32_t off, uint32_t len,
234     const char *key)
235 {
236 	spd_parse_ddr5_width(si, si->si_data[off], SPD_KEY_DRAM_WIDTH);
237 }
238 
239 static void
240 spd_parse_ddr5_width_sec(spd_info_t *si, uint32_t off, uint32_t len,
241     const char *key)
242 {
243 	if (!spd_parse_ddr5_isassym(si))
244 		return;
245 
246 	spd_parse_ddr5_width(si, si->si_data[off], SPD_KEY_SEC_DRAM_WIDTH);
247 }
248 
249 static const spd_value_range_t spd_ddr5_nbg_range = {
250 	.svr_max = SPD_DDR5_BANKS_NBG_BITS_MAX
251 };
252 
253 static const spd_value_range_t spd_ddr5_nba_range = {
254 	.svr_max = SPD_DDR5_BANKS_NBA_BITS_MAX
255 };
256 
257 static void
258 spd_parse_ddr5_banks(spd_info_t *si, uint8_t data, const char *bg_key,
259     const char *ba_key)
260 {
261 	const uint8_t nbg = SPD_DDR5_BANKS_NBG_BITS(data);
262 	const uint8_t nba = SPD_DDR5_BANKS_NBA_BITS(data);
263 
264 	spd_insert_range(si, bg_key, nbg, &spd_ddr5_nbg_range);
265 	spd_insert_range(si, ba_key, nba, &spd_ddr5_nba_range);
266 }
267 
268 static void
269 spd_parse_ddr5_banks_pri(spd_info_t *si, uint32_t off, uint32_t len,
270     const char *key)
271 {
272 	spd_parse_ddr5_banks(si, si->si_data[off], SPD_KEY_NBGRP_BITS,
273 	    SPD_KEY_NBANK_BITS);
274 }
275 
276 static void
277 spd_parse_ddr5_banks_sec(spd_info_t *si, uint32_t off, uint32_t len,
278     const char *key)
279 {
280 	if (!spd_parse_ddr5_isassym(si))
281 		return;
282 
283 	spd_parse_ddr5_banks(si, si->si_data[off], SPD_KEY_SEC_NBGRP_BITS,
284 	    SPD_KEY_SEC_NBANK_BITS);
285 }
286 
287 static void
288 spd_parse_ddr5_ppr(spd_info_t *si, uint32_t off, uint32_t len,
289     const char *key)
290 {
291 	const uint8_t data = si->si_data[off];
292 	spd_ppr_flags_t flags = SPD_PPR_F_HARD_PPR | SPD_PPR_F_SOFT_PPR;
293 
294 	if (SPD_DDR5_PPR_GRAN(data) == SPD_DDR5_PPR_GRAN_BGRP) {
295 		spd_nvl_insert_u32(si, SPD_KEY_PPR_GRAN,
296 		    SPD_PPR_GRAN_BANK_GROUP);
297 	} else {
298 		spd_nvl_insert_u32(si, SPD_KEY_PPR_GRAN,
299 		    SPD_PPR_GRAN_BANK);
300 	}
301 
302 	if (SPD_DDR5_PPR_LOCK_SUP(data) != 0)
303 		flags |= SPD_PPR_F_PPR_UNDO;
304 	if (SPD_DDR5_PPR_MPPR_SUP(data) != 0)
305 		flags |= SPD_PPR_F_MBIST_PPR;
306 	spd_nvl_insert_u32(si, SPD_KEY_PPR, flags);
307 
308 	if (SPD_DDR5_PPR_BL32_SUP(data) != 0)
309 		spd_nvl_insert_key(si, SPD_KEY_DDR5_BL32);
310 }
311 
312 static const spd_value_map_t spd_ddr5_dca_map[] = {
313 	{ SPD_DDR5_SPD_DCA_TYPE_UNSUP, SPD_DCA_UNSPPORTED, false },
314 	{ SPD_DDR5_SPD_DCA_TYPE_1_2P, SPD_DCA_1_OR_2_PHASE, false },
315 	{ SPD_DDR5_SPD_DCA_TYPE_4P, SPD_DCA_4_PHASE, false }
316 };
317 
318 static void
319 spd_parse_ddr5_dca(spd_info_t *si, uint32_t off, uint32_t len,
320     const char *key)
321 {
322 	const uint8_t data = si->si_data[off];
323 	const uint8_t dca = SPD_DDR5_SPD_DCA_TYPE(data);
324 
325 	if (SPD_DDR5_SPD_DCA_PASR(data) != 0)
326 		spd_nvl_insert_key(si, SPD_KEY_DDR_PASR);
327 
328 	spd_insert_map(si, SPD_KEY_DDR5_DCA, dca, spd_ddr5_dca_map,
329 	    ARRAY_SIZE(spd_ddr5_dca_map));
330 }
331 
332 static void
333 spd_parse_ddr5_flt(spd_info_t *si, uint32_t off, uint32_t len,
334     const char *key)
335 {
336 	const uint8_t data = si->si_data[off];
337 	spd_fault_t flt = 0;
338 
339 	if (SPD_DDR5_FLT_PRAC_ABO(data))
340 		spd_nvl_insert_key(si, SPD_KEY_DDR5_PRAC);
341 
342 	if (SPD_DDR5_FLT_WIDE_TS(data) != 0)
343 		spd_nvl_insert_key(si, SPD_KEY_DDR5_WIDE_TS);
344 
345 	if (SPD_DDR5_FLT_WBSUPR_SUP(data) != 0) {
346 		if (SPD_DDR5_FLT_WBSUPR_SEL(data) ==
347 		    SPD_DDR5_FLT_WBSUPR_SEL_MR15) {
348 			flt |= SPD_FLT_WRSUP_MR15;
349 		} else {
350 			flt |= SPD_FLT_WRSUP_MR9;
351 		}
352 	}
353 
354 	if (SPD_DDR5_FLT_BFLT(data))
355 		flt |= SPD_FLT_BOUNDED;
356 	if (flt != 0)
357 		spd_nvl_insert_u32(si, SPD_KEY_DDR5_FLT, flt);
358 }
359 
360 /*
361  * Voltages support describing the nominal, operational, and endurant ranges.
362  * Currently we only encode the nominal values.
363  */
364 static void
365 spd_parse_ddr5_voltage(spd_info_t *si, uint8_t data, const char *key,
366     uint32_t *mv, uint32_t nmv)
367 {
368 	const uint8_t nom_idx = SPD_DDR5_DRAM_VOLT_NOM(data);
369 
370 	if (nom_idx >= nmv) {
371 		spd_nvl_err(si, key, SPD_ERROR_NO_XLATE,
372 		    "encountered unknown value: 0x%x", nom_idx);
373 	} else {
374 		spd_nvl_insert_u32_array(si, key, &mv[nom_idx], 1);
375 	}
376 }
377 
378 static void
379 spd_parse_ddr5_vdd(spd_info_t *si, uint32_t off, uint32_t len,
380     const char *key)
381 {
382 	uint32_t volts[] = { 1100 };
383 	return (spd_parse_ddr5_voltage(si, si->si_data[off], key, volts,
384 	    ARRAY_SIZE(volts)));
385 }
386 
387 static void
388 spd_parse_ddr5_vddq(spd_info_t *si, uint32_t off, uint32_t len,
389     const char *key)
390 {
391 	uint32_t volts[] = { 1100 };
392 	return (spd_parse_ddr5_voltage(si, si->si_data[off], key, volts,
393 	    ARRAY_SIZE(volts)));
394 }
395 
396 static void
397 spd_parse_ddr5_vpp(spd_info_t *si, uint32_t off, uint32_t len,
398     const char *key)
399 {
400 	uint32_t volts[] = { 1800 };
401 	return (spd_parse_ddr5_voltage(si, si->si_data[off], key, volts,
402 	    ARRAY_SIZE(volts)));
403 }
404 
405 static void
406 spd_parse_ddr5_time(spd_info_t *si, uint32_t off, uint32_t len,
407     const char *key)
408 {
409 	const uint8_t data = si->si_data[off];
410 
411 	if (SPD_DDR5_TIME_STD(data) == SPD_DDR5_TIME_STD_NON)
412 		spd_nvl_insert_key(si, SPD_KEY_DDR5_NONSTD_TIME);
413 }
414 
415 /*
416  * Time in picoseconds. The LSB is at off. The MSB is at off + 1.
417  */
418 static void
419 spd_parse_ddr5_ps(spd_info_t *si, uint32_t off, uint32_t len,
420     const char *key)
421 {
422 	uint64_t ps;
423 
424 	ASSERT3U(len, ==, 2);
425 	ps = (uint64_t)si->si_data[off];
426 	ps |= (uint64_t)si->si_data[off + 1] << 8;
427 
428 	if (ps == 0) {
429 		spd_nvl_err(si, key, SPD_ERROR_NO_XLATE,
430 		    "encountered unexpected zero time value");
431 		return;
432 	}
433 
434 	spd_nvl_insert_u64(si, key, ps);
435 }
436 
437 /*
438  * Time in nanoseconds. The LSB is at off. The MSB is at off + 1. We normalize
439  * all times to ps.
440  */
441 static void
442 spd_parse_ddr5_ns(spd_info_t *si, uint32_t off, uint32_t len,
443     const char *key)
444 {
445 	uint64_t ns, ps;
446 
447 	ASSERT3U(len, ==, 2);
448 	ns = (uint64_t)si->si_data[off];
449 	ns |= (uint64_t)si->si_data[off + 1] << 8;
450 
451 	if (ns == 0) {
452 		spd_nvl_err(si, key, SPD_ERROR_NO_XLATE,
453 		    "encountered unexpected zero time value");
454 		return;
455 	}
456 
457 	ps = ns * 1000;
458 	spd_nvl_insert_u64(si, key, ps);
459 }
460 
461 /*
462  * Several DDR5 timing properties are only valid for 3DS type DIMMs. So we
463  * double check the actual DIMM type before we proceed to parse this.
464  */
465 static void
466 spd_parse_ddr5_3ds_ns(spd_info_t *si, uint32_t off, uint32_t len,
467     const char *key)
468 {
469 	ASSERT3U(off, >=, SPD_DDR5_DENPKG1);
470 	uint32_t val;
471 
472 	if (nvlist_lookup_uint32(si->si_nvl, SPD_KEY_PKG_SL, &val) != 0 ||
473 	    val != SPD_SL_3DS) {
474 		return;
475 	}
476 
477 	spd_parse_ddr5_ns(si, off, len, key);
478 }
479 
480 static void
481 spd_parse_ddr5_nck(spd_info_t *si, uint32_t off, uint32_t len,
482     const char *key)
483 {
484 	const uint8_t data = si->si_data[off];
485 
486 	if (data == 0) {
487 		spd_nvl_err(si, key, SPD_ERROR_NO_XLATE,
488 		    "encountered unexpected zero clock value");
489 		return;
490 	}
491 
492 	spd_nvl_insert_u32(si, key, data);
493 }
494 
495 static void
496 spd_parse_ddr5_cas(spd_info_t *si, uint32_t off, uint32_t len,
497     const char *key)
498 {
499 	uint32_t cas[40] = { 0 };
500 	uint_t ncas = 0;
501 	uint32_t cas_base = 20;
502 
503 	ASSERT3U(len, ==, 5);
504 
505 	for (uint32_t byte = 0; byte < len; byte++) {
506 		uint32_t data = si->si_data[off + byte];
507 
508 		for (uint32_t i = 0; i < NBBY; i++) {
509 			if (bitx8(data, i, i) == 1) {
510 				cas[ncas] = cas_base + 2 * (i + NBBY * byte);
511 				ncas++;
512 			}
513 		}
514 	}
515 
516 	spd_nvl_insert_u32_array(si, key, cas, ncas);
517 }
518 
519 static const spd_value_range_t spd_ddr5_raammt_norm_range = {
520 	.svr_min = SPD_DDR5_RFM0_RAAMMT_NORM_MIN,
521 	.svr_max = SPD_DDR5_RFM0_RAAMMT_NORM_MAX,
522 	.svr_mult = SPD_DDR5_RFM0_RAAMMT_NORM_MULT
523 };
524 
525 static const spd_value_range_t spd_ddr5_raammt_fgr_range = {
526 	.svr_min = SPD_DDR5_RFM0_RAAMMT_FGR_MIN,
527 	.svr_max = SPD_DDR5_RFM0_RAAMMT_FGR_MAX,
528 	.svr_mult = SPD_DDR5_RFM0_RAAMMT_FGR_MULT
529 };
530 
531 static const spd_value_range_t spd_ddr5_raaimt_norm_range = {
532 	.svr_min = SPD_DDR5_RFM0_RAAIMT_NORM_MIN,
533 	.svr_max = SPD_DDR5_RFM0_RAAIMT_NORM_MAX,
534 	.svr_mult = SPD_DDR5_RFM0_RAAIMT_NORM_MULT
535 };
536 
537 static const spd_value_range_t spd_ddr5_raaimt_fgr_range = {
538 	.svr_min = SPD_DDR5_RFM0_RAAIMT_FGR_MIN,
539 	.svr_max = SPD_DDR5_RFM0_RAAIMT_FGR_MAX,
540 	.svr_mult = SPD_DDR5_RFM0_RAAIMT_FGR_MULT
541 };
542 
543 static const spd_value_range_t spd_ddr5_brc_cfg_range = {
544 	.svr_max = SPD_DDR5_RFM1_BRC_CFG_MAX,
545 	.svr_base = SPD_DDR5_RFM1_BRC_CFG_BASE
546 };
547 
548 static const spd_value_map_t spd_ddr5_raa_ctr_map[] = {
549 	{ SPD_DDR5_RFM1_CTR_1X, 1, false },
550 	{ SPD_DDR5_RFM1_CTR_2X, 2, false }
551 };
552 
553 static void
554 spd_parse_ddr5_rfm_flags(spd_info_t *si, uint8_t rfm0, uint8_t rfm1,
555     const char *key)
556 {
557 	spd_rfm_flags_t flags = 0;
558 
559 	if (SPD_DDR5_RFM0_RFM_REQ(rfm0) != 0)
560 		flags |= SPD_RFM_F_REQUIRED;
561 	if (SPD_DDR5_RFM1_DRFM_SUP(rfm1) != 0)
562 		flags |= SPD_RFM_F_DRFM_SUP;
563 
564 	spd_nvl_insert_u32(si, key, flags);
565 }
566 
567 static void
568 spd_parse_ddr5_arfm_flags(spd_info_t *si, uint8_t rfm1, const char *key)
569 {
570 	spd_rfm_flags_t flags = 0;
571 
572 	if (SPD_DDR5_RFM1_DRFM_SUP(rfm1) != 0)
573 		flags |= SPD_RFM_F_DRFM_SUP;
574 
575 	spd_nvl_insert_u32(si, key, flags);
576 }
577 
578 static void
579 spd_parse_ddr5_rfm_common(spd_info_t *si, uint8_t rfm0, uint8_t rfm1,
580     const char *raaimt_key, const char *raaimt_fgr_key, const char *raammt_key,
581     const char *raammt_fgr_key, const char *brc_cfg_key,
582     const char *brc_sup_key, const char *raa_ctr_key)
583 {
584 	const uint8_t raammt = SPD_DDR5_RFM0_RAAMMT_NORM(rfm0);
585 	const uint8_t raammt_fgr = SPD_DDR5_RFM0_RAAMMT_FGR(rfm0);
586 	const uint8_t raaimt = SPD_DDR5_RFM0_RAAIMT_NORM(rfm0);
587 	const uint8_t raaimt_fgr = SPD_DDR5_RFM0_RAAIMT_FGR(rfm0);
588 	const uint8_t brc_cfg = SPD_DDR5_RFM1_BRC_CFG(rfm1);
589 	const uint8_t brc_sup = SPD_DDR5_RFM1_BRC_SUP(rfm1);
590 	const uint8_t raa_ctr = SPD_DDR5_RFM1_CTR(rfm1);
591 	spd_brc_flags_t brc_flags = SPD_BRC_F_LVL_2;
592 
593 	if (brc_sup == SPD_DDR5_RFM1_BRC_SUP_234)
594 		brc_flags |= SPD_BRC_F_LVL_3 | SPD_BRC_F_LVL_4;
595 
596 	if (SPD_DDR5_RFM0_RFM_REQ(rfm0) != 0) {
597 		spd_insert_range(si, raaimt_key, raaimt,
598 		    &spd_ddr5_raaimt_norm_range);
599 		spd_insert_range(si, raaimt_fgr_key, raaimt_fgr,
600 		    &spd_ddr5_raaimt_fgr_range);
601 		spd_insert_range(si, raammt_key, raammt,
602 		    &spd_ddr5_raammt_norm_range);
603 		spd_insert_range(si, raammt_fgr_key, raammt_fgr,
604 		    &spd_ddr5_raammt_fgr_range);
605 		spd_insert_map(si, raa_ctr_key, raa_ctr, spd_ddr5_raa_ctr_map,
606 		    ARRAY_SIZE(spd_ddr5_raa_ctr_map));
607 	}
608 
609 	if (SPD_DDR5_RFM1_DRFM_SUP(rfm1) != 0) {
610 		spd_insert_range(si, brc_cfg_key, brc_cfg,
611 		    &spd_ddr5_brc_cfg_range);
612 		spd_nvl_insert_u32(si, brc_sup_key, brc_flags);
613 	}
614 }
615 
616 static void
617 spd_parse_ddr5_rfm_pri(spd_info_t *si, uint32_t off, uint32_t len,
618     const char *key)
619 {
620 	ASSERT3U(len, ==, 2);
621 
622 	spd_parse_ddr5_rfm_flags(si, si->si_data[off], si->si_data[off + 1],
623 	    SPD_KEY_DDR5_RFM_FLAGS_PRI);
624 	spd_parse_ddr5_rfm_common(si, si->si_data[off], si->si_data[off + 1],
625 	    SPD_KEY_DDR5_RFM_RAAIMT_PRI, SPD_KEY_DDR5_RFM_RAAIMT_FGR_PRI,
626 	    SPD_KEY_DDR5_RFM_RAAMMT_PRI, SPD_KEY_DDR5_RFM_RAAMMT_FGR_PRI,
627 	    SPD_KEY_DDR5_RFM_BRC_CFG_PRI, SPD_KEY_DDR5_RFM_BRC_SUP_PRI,
628 	    SPD_KEY_DDR5_RFM_RAA_DEC_PRI);
629 }
630 
631 static void
632 spd_parse_ddr5_rfm_sec(spd_info_t *si, uint32_t off, uint32_t len,
633     const char *key)
634 {
635 	if (!spd_parse_ddr5_isassym(si))
636 		return;
637 
638 	spd_parse_ddr5_rfm_flags(si, si->si_data[off], si->si_data[off + 1],
639 	    SPD_KEY_DDR5_RFM_FLAGS_SEC);
640 	spd_parse_ddr5_rfm_common(si, si->si_data[off], si->si_data[off + 1],
641 	    SPD_KEY_DDR5_RFM_RAAIMT_SEC, SPD_KEY_DDR5_RFM_RAAIMT_FGR_SEC,
642 	    SPD_KEY_DDR5_RFM_RAAMMT_SEC, SPD_KEY_DDR5_RFM_RAAMMT_FGR_SEC,
643 	    SPD_KEY_DDR5_RFM_BRC_CFG_SEC, SPD_KEY_DDR5_RFM_BRC_SUP_SEC,
644 	    SPD_KEY_DDR5_RFM_RAA_DEC_SEC);
645 }
646 
647 static void
648 spd_parse_ddr5_arfma_pri(spd_info_t *si, uint32_t off, uint32_t len,
649     const char *key)
650 {
651 	ASSERT3U(len, ==, 2);
652 
653 	if (SPD_DDR5_ARFM_SUP(si->si_data[off]) == 0)
654 		return;
655 
656 	spd_parse_ddr5_arfm_flags(si, si->si_data[off + 1],
657 	    SPD_KEY_DDR5_ARFMA_FLAGS_PRI);
658 	spd_parse_ddr5_rfm_common(si, si->si_data[off], si->si_data[off + 1],
659 	    SPD_KEY_DDR5_ARFMA_RAAIMT_PRI, SPD_KEY_DDR5_ARFMA_RAAIMT_FGR_PRI,
660 	    SPD_KEY_DDR5_ARFMA_RAAMMT_PRI, SPD_KEY_DDR5_ARFMA_RAAMMT_FGR_PRI,
661 	    SPD_KEY_DDR5_ARFMA_BRC_CFG_PRI, SPD_KEY_DDR5_ARFMA_BRC_SUP_PRI,
662 	    SPD_KEY_DDR5_ARFMA_RAA_DEC_PRI);
663 }
664 
665 static void
666 spd_parse_ddr5_arfma_sec(spd_info_t *si, uint32_t off, uint32_t len,
667     const char *key)
668 {
669 	if (!spd_parse_ddr5_isassym(si))
670 		return;
671 
672 	if (SPD_DDR5_ARFM_SUP(si->si_data[off]) == 0)
673 		return;
674 
675 	spd_parse_ddr5_arfm_flags(si, si->si_data[off + 1],
676 	    SPD_KEY_DDR5_ARFMA_FLAGS_SEC);
677 	spd_parse_ddr5_rfm_common(si, si->si_data[off], si->si_data[off + 1],
678 	    SPD_KEY_DDR5_ARFMA_RAAIMT_SEC, SPD_KEY_DDR5_ARFMA_RAAIMT_FGR_SEC,
679 	    SPD_KEY_DDR5_ARFMA_RAAMMT_SEC, SPD_KEY_DDR5_ARFMA_RAAMMT_FGR_SEC,
680 	    SPD_KEY_DDR5_ARFMA_BRC_CFG_SEC, SPD_KEY_DDR5_ARFMA_BRC_SUP_SEC,
681 	    SPD_KEY_DDR5_ARFMA_RAA_DEC_SEC);
682 }
683 
684 static void
685 spd_parse_ddr5_arfmb_pri(spd_info_t *si, uint32_t off, uint32_t len,
686     const char *key)
687 {
688 	ASSERT3U(len, ==, 2);
689 
690 	if (SPD_DDR5_ARFM_SUP(si->si_data[off]) == 0)
691 		return;
692 
693 	spd_parse_ddr5_arfm_flags(si, si->si_data[off + 1],
694 	    SPD_KEY_DDR5_ARFMB_FLAGS_PRI);
695 	spd_parse_ddr5_rfm_common(si, si->si_data[off], si->si_data[off + 1],
696 	    SPD_KEY_DDR5_ARFMB_RAAIMT_PRI, SPD_KEY_DDR5_ARFMB_RAAIMT_FGR_PRI,
697 	    SPD_KEY_DDR5_ARFMB_RAAMMT_PRI, SPD_KEY_DDR5_ARFMB_RAAMMT_FGR_PRI,
698 	    SPD_KEY_DDR5_ARFMB_BRC_CFG_PRI, SPD_KEY_DDR5_ARFMB_BRC_SUP_PRI,
699 	    SPD_KEY_DDR5_ARFMB_RAA_DEC_PRI);
700 }
701 
702 static void
703 spd_parse_ddr5_arfmb_sec(spd_info_t *si, uint32_t off, uint32_t len,
704     const char *key)
705 {
706 	if (!spd_parse_ddr5_isassym(si))
707 		return;
708 
709 	if (SPD_DDR5_ARFM_SUP(si->si_data[off]) == 0)
710 		return;
711 
712 	spd_parse_ddr5_arfm_flags(si, si->si_data[off + 1],
713 	    SPD_KEY_DDR5_ARFMB_FLAGS_SEC);
714 	spd_parse_ddr5_rfm_common(si, si->si_data[off], si->si_data[off + 1],
715 	    SPD_KEY_DDR5_ARFMB_RAAIMT_SEC, SPD_KEY_DDR5_ARFMB_RAAIMT_FGR_SEC,
716 	    SPD_KEY_DDR5_ARFMB_RAAMMT_SEC, SPD_KEY_DDR5_ARFMB_RAAMMT_FGR_SEC,
717 	    SPD_KEY_DDR5_ARFMB_BRC_CFG_SEC, SPD_KEY_DDR5_ARFMB_BRC_SUP_SEC,
718 	    SPD_KEY_DDR5_ARFMB_RAA_DEC_SEC);
719 }
720 
721 static void
722 spd_parse_ddr5_arfmc_pri(spd_info_t *si, uint32_t off, uint32_t len,
723     const char *key)
724 {
725 	ASSERT3U(len, ==, 2);
726 
727 	if (SPD_DDR5_ARFM_SUP(si->si_data[off]) == 0)
728 		return;
729 
730 	spd_parse_ddr5_arfm_flags(si, si->si_data[off + 1],
731 	    SPD_KEY_DDR5_ARFMC_FLAGS_PRI);
732 	spd_parse_ddr5_rfm_common(si, si->si_data[off], si->si_data[off + 1],
733 	    SPD_KEY_DDR5_ARFMC_RAAIMT_PRI, SPD_KEY_DDR5_ARFMC_RAAIMT_FGR_PRI,
734 	    SPD_KEY_DDR5_ARFMC_RAAMMT_PRI, SPD_KEY_DDR5_ARFMC_RAAMMT_FGR_PRI,
735 	    SPD_KEY_DDR5_ARFMC_BRC_CFG_PRI, SPD_KEY_DDR5_ARFMC_BRC_SUP_PRI,
736 	    SPD_KEY_DDR5_ARFMC_RAA_DEC_PRI);
737 }
738 
739 static void
740 spd_parse_ddr5_arfmc_sec(spd_info_t *si, uint32_t off, uint32_t len,
741     const char *key)
742 {
743 	if (!spd_parse_ddr5_isassym(si))
744 		return;
745 
746 	if (SPD_DDR5_ARFM_SUP(si->si_data[off]) == 0)
747 		return;
748 
749 	spd_parse_ddr5_arfm_flags(si, si->si_data[off + 1],
750 	    SPD_KEY_DDR5_ARFMC_FLAGS_SEC);
751 	spd_parse_ddr5_rfm_common(si, si->si_data[off], si->si_data[off + 1],
752 	    SPD_KEY_DDR5_ARFMC_RAAIMT_SEC, SPD_KEY_DDR5_ARFMC_RAAIMT_FGR_SEC,
753 	    SPD_KEY_DDR5_ARFMC_RAAMMT_SEC, SPD_KEY_DDR5_ARFMC_RAAMMT_FGR_SEC,
754 	    SPD_KEY_DDR5_ARFMC_BRC_CFG_SEC, SPD_KEY_DDR5_ARFMC_BRC_SUP_SEC,
755 	    SPD_KEY_DDR5_ARFMC_RAA_DEC_SEC);
756 }
757 
758 static const spd_parse_t spd_ddr5_base[] = {
759 	{ .sp_off = SPD_DDR5_NBYTES, .sp_parse = spd_parse_ddr5_nbytes },
760 	{ .sp_off = SPD_DDR5_SPD_REV, .sp_parse = spd_parse_rev },
761 	/*
762 	 * We have previously validated that the DRAM type is something that we
763 	 * understand. We pass through the raw enum to users here.
764 	 */
765 	{ .sp_off = SPD_DDR5_DRAM_TYPE, .sp_key = SPD_KEY_DRAM_TYPE,
766 	    .sp_parse = spd_parse_raw_u8 },
767 	{ .sp_off = SPD_DDR5_MOD_TYPE, .sp_parse = spd_parse_ddr5_mod_type },
768 	/*
769 	 * All secondary values must check whether an asymmetrical module is
770 	 * present in Byte 234. As such, for the secondary versions we set LEN
771 	 * to include that value. They then move to a common function.
772 	 */
773 	{ .sp_off = SPD_DDR5_DENPKG1, .sp_parse = spd_parse_ddr5_denpkg_pri },
774 	{ .sp_off = SPD_DDR5_DENPKG2, .sp_parse = spd_parse_ddr5_denpkg_sec,
775 	    .sp_len = SPD_DDR5_COM_ORG - SPD_DDR5_DENPKG2 + 1 },
776 	{ .sp_off = SPD_DDR5_ADDR1, .sp_parse = spd_parse_ddr5_addr_pri },
777 	{ .sp_off = SPD_DDR5_ADDR2, .sp_parse = spd_parse_ddr5_addr_sec,
778 	    .sp_len = SPD_DDR5_COM_ORG - SPD_DDR5_ADDR2 + 1 },
779 	{ .sp_off = SPD_DDR5_WIDTH1, .sp_parse = spd_parse_ddr5_width_pri },
780 	{ .sp_off = SPD_DDR5_WIDTH2, .sp_parse = spd_parse_ddr5_width_sec,
781 	    .sp_len = SPD_DDR5_COM_ORG - SPD_DDR5_WIDTH2 + 1 },
782 	{ .sp_off = SPD_DDR5_BANKS1, .sp_parse = spd_parse_ddr5_banks_pri },
783 	{ .sp_off = SPD_DDR5_BANKS2, .sp_parse = spd_parse_ddr5_banks_sec,
784 	    .sp_len = SPD_DDR5_COM_ORG - SPD_DDR5_BANKS2 + 1 },
785 	{ .sp_off = SPD_DDR5_PPR, .sp_parse = spd_parse_ddr5_ppr },
786 	{ .sp_off = SPD_DDR5_SDA, .sp_parse = spd_parse_ddr5_dca },
787 	{ .sp_off = SPD_DDR5_FLT, .sp_parse = spd_parse_ddr5_flt },
788 	{ .sp_off = SPD_DDR5_DRAM_VDD, .sp_key = SPD_KEY_NOM_VDD,
789 	    .sp_parse = spd_parse_ddr5_vdd },
790 	{ .sp_off = SPD_DDR5_DRAM_VDDQ, .sp_key = SPD_KEY_NOM_VDDQ,
791 	    .sp_parse = spd_parse_ddr5_vddq },
792 	{ .sp_off = SPD_DDR5_DRAM_VPP, .sp_key = SPD_KEY_NOM_VPP,
793 	    .sp_parse = spd_parse_ddr5_vpp },
794 	{ .sp_off = SPD_DDR5_TIME, .sp_parse = spd_parse_ddr5_time },
795 	{ .sp_off = SPD_DDR5_TCKAVG_MIN_LSB, .sp_len = 2,
796 	    .sp_key = SPD_KEY_TCKAVG_MIN, .sp_parse = spd_parse_ddr5_ps },
797 	{ .sp_off = SPD_DDR5_TCKAVG_MAX_LSB, .sp_len = 2,
798 	    .sp_key = SPD_KEY_TCKAVG_MAX, .sp_parse = spd_parse_ddr5_ps },
799 	{ .sp_off = SPD_DDR5_CAS_SUP0, .sp_len = 5, .sp_key = SPD_KEY_CAS,
800 	    .sp_parse = spd_parse_ddr5_cas },
801 	{ .sp_off = SPD_DDR5_TAA_LSB, .sp_len = 2,
802 	    .sp_key = SPD_KEY_TAA_MIN, .sp_parse = spd_parse_ddr5_ps },
803 	{ .sp_off = SPD_DDR5_TRCD_LSB, .sp_len = 2,
804 	    .sp_key = SPD_KEY_TRCD_MIN, .sp_parse = spd_parse_ddr5_ps },
805 	{ .sp_off = SPD_DDR5_TRP_LSB, .sp_len = 2,
806 	    .sp_key = SPD_KEY_TRP_MIN, .sp_parse = spd_parse_ddr5_ps },
807 	{ .sp_off = SPD_DDR5_TRAS_LSB, .sp_len = 2,
808 	    .sp_key = SPD_KEY_TRAS_MIN, .sp_parse = spd_parse_ddr5_ps },
809 	{ .sp_off = SPD_DDR5_TRC_LSB, .sp_len = 2,
810 	    .sp_key = SPD_KEY_TRC_MIN, .sp_parse = spd_parse_ddr5_ps },
811 	{ .sp_off = SPD_DDR5_TWR_LSB, .sp_len = 2,
812 	    .sp_key = SPD_KEY_TWR_MIN, .sp_parse = spd_parse_ddr5_ps },
813 	{ .sp_off = SPD_DDR5_TRFC1_LSB, .sp_len = 2,
814 	    .sp_key = SPD_KEY_TRFC1_MIN, .sp_parse = spd_parse_ddr5_ns },
815 	{ .sp_off = SPD_DDR5_TRFC2_LSB, .sp_len = 2,
816 	    .sp_key = SPD_KEY_TRFC2_MIN, .sp_parse = spd_parse_ddr5_ns },
817 	{ .sp_off = SPD_DDR5_TRFCSB_LSB, .sp_len = 2,
818 	    .sp_key = SPD_KEY_TRFCSB, .sp_parse = spd_parse_ddr5_ns },
819 	{ .sp_off = SPD_DDR5_3DS_TRFC1_LSB, .sp_len = 2,
820 	    .sp_key = SPD_KEY_TRFC1_DLR, .sp_parse = spd_parse_ddr5_3ds_ns },
821 	{ .sp_off = SPD_DDR5_3DS_TRFC2_LSB, .sp_len = 2,
822 	    .sp_key = SPD_KEY_TRFC2_DLR, .sp_parse = spd_parse_ddr5_3ds_ns },
823 	{ .sp_off = SPD_DDR5_3DS_TRFCSB_LSB, .sp_len = 2,
824 	    .sp_key = SPD_KEY_TRFCSB_DLR, .sp_parse = spd_parse_ddr5_3ds_ns },
825 	{ .sp_off = SPD_DDR5_RFM0_SDRAM0, .sp_len = 2,
826 	    .sp_parse = spd_parse_ddr5_rfm_pri },
827 	{ .sp_off = SPD_DDR5_RFM0_SDRAM1, .sp_parse = spd_parse_ddr5_rfm_sec,
828 	    .sp_len = SPD_DDR5_COM_ORG - SPD_DDR5_RFM0_SDRAM1 + 1 },
829 	{ .sp_off = SPD_DDR5_ARFM0_A_SDRAM0, .sp_len = 2,
830 	    .sp_parse = spd_parse_ddr5_arfma_pri },
831 	{ .sp_off = SPD_DDR5_ARFM0_A_SDRAM1,
832 	    .sp_len = SPD_DDR5_COM_ORG - SPD_DDR5_ARFM0_A_SDRAM1 + 1,
833 	    .sp_parse = spd_parse_ddr5_arfma_sec },
834 	{ .sp_off = SPD_DDR5_ARFM0_B_SDRAM0, .sp_len = 2,
835 	    .sp_parse = spd_parse_ddr5_arfmb_pri },
836 	{ .sp_off = SPD_DDR5_ARFM0_B_SDRAM1,
837 	    .sp_len = SPD_DDR5_COM_ORG - SPD_DDR5_ARFM0_B_SDRAM1 + 1,
838 	    .sp_parse = spd_parse_ddr5_arfmb_sec },
839 	{ .sp_off = SPD_DDR5_ARFM0_C_SDRAM0, .sp_len = 2,
840 	    .sp_parse = spd_parse_ddr5_arfmc_pri },
841 	{ .sp_off = SPD_DDR5_ARFM0_C_SDRAM1,
842 	    .sp_len = SPD_DDR5_COM_ORG - SPD_DDR5_ARFM0_C_SDRAM1 + 1,
843 	    .sp_parse = spd_parse_ddr5_arfmc_sec },
844 	{ .sp_off = SPD_DDR5_TRRD_L_LSB, .sp_len = 2,
845 	    .sp_key = SPD_KEY_TRRD_L_MIN, .sp_parse = spd_parse_ddr5_ps },
846 	{ .sp_off = SPD_DDR5_TRRD_L_NCK, .sp_key = SPD_KEY_TRRD_L_NCK,
847 	    .sp_parse = spd_parse_ddr5_nck },
848 	{ .sp_off = SPD_DDR5_TCCD_L_LSB, .sp_len = 2,
849 	    .sp_key = SPD_KEY_TCCD_L_MIN, .sp_parse = spd_parse_ddr5_ps },
850 	{ .sp_off = SPD_DDR5_TCCD_L_NCK, .sp_key = SPD_KEY_TCCD_L_NCK,
851 	    .sp_parse = spd_parse_ddr5_nck },
852 	{ .sp_off = SPD_DDR5_TCCD_L_WR_LSB, .sp_len = 2,
853 	    .sp_key = SPD_KEY_TCCDLWR, .sp_parse = spd_parse_ddr5_ps },
854 	{ .sp_off = SPD_DDR5_TCCD_L_WR_NCK, .sp_key = SPD_KEY_TCCDLWR_NCK,
855 	    .sp_parse = spd_parse_ddr5_nck },
856 	{ .sp_off = SPD_DDR5_TCCD_L_WR2_LSB, .sp_len = 2,
857 	    .sp_key = SPD_KEY_TCCDLWR2, .sp_parse = spd_parse_ddr5_ps },
858 	{ .sp_off = SPD_DDR5_TCCD_L_WR2_NCK, .sp_key = SPD_KEY_TCCDLWR2_NCK,
859 	    .sp_parse = spd_parse_ddr5_nck },
860 	{ .sp_off = SPD_DDR5_TFAW_LSB, .sp_len = 2,
861 	    .sp_key = SPD_KEY_TFAW, .sp_parse = spd_parse_ddr5_ps },
862 	{ .sp_off = SPD_DDR5_TFAW_NCK, .sp_key = SPD_KEY_TFAW_NCK,
863 	    .sp_parse = spd_parse_ddr5_nck },
864 	{ .sp_off = SPD_DDR5_TCCD_L_WTR_LSB, .sp_len = 2,
865 	    .sp_key = SPD_KEY_TCCDLWTR, .sp_parse = spd_parse_ddr5_ps },
866 	{ .sp_off = SPD_DDR5_TCCD_L_WTR_NCK, .sp_key = SPD_KEY_TCCDLWTR_NCK,
867 	    .sp_parse = spd_parse_ddr5_nck },
868 	{ .sp_off = SPD_DDR5_TCCD_S_WTR_LSB, .sp_len = 2,
869 	    .sp_key = SPD_KEY_TCCDSWTR, .sp_parse = spd_parse_ddr5_ps },
870 	{ .sp_off = SPD_DDR5_TCCD_S_WTR_NCK, .sp_key = SPD_KEY_TCCDSWTR_NCK,
871 	    .sp_parse = spd_parse_ddr5_nck },
872 	{ .sp_off = SPD_DDR5_TRTP_LSB, .sp_len = 2,
873 	    .sp_key = SPD_KEY_TRTP, .sp_parse = spd_parse_ddr5_ps },
874 	{ .sp_off = SPD_DDR5_TRTP_NCK, .sp_key = SPD_KEY_TRTP_NCK,
875 	    .sp_parse = spd_parse_ddr5_nck }
876 };
877 
878 /*
879  * These are additional fields that were added in v1.2 of the SPD data.
880  */
881 static const spd_parse_t spd_ddr5_base_1v2[] = {
882 	{ .sp_off = SPD_DDR5_TCCD_M_LSB, .sp_len = 2,
883 	    .sp_key = SPD_KEY_TCCDM, .sp_parse = spd_parse_ddr5_ps },
884 	{ .sp_off = SPD_DDR5_TCCD_M_NCK, .sp_key = SPD_KEY_TCCDM_NCK,
885 	    .sp_parse = spd_parse_ddr5_nck },
886 	{ .sp_off = SPD_DDR5_TCCD_M_WR_LSB, .sp_len = 2,
887 	    .sp_key = SPD_KEY_TCCDMWR, .sp_parse = spd_parse_ddr5_ps },
888 	{ .sp_off = SPD_DDR5_TCCD_M_WR_NCK, .sp_key = SPD_KEY_TCCDMWR_NCK,
889 	    .sp_parse = spd_parse_ddr5_nck },
890 	{ .sp_off = SPD_DDR5_TCCD_M_WTR_LSB, .sp_len = 2,
891 	    .sp_key = SPD_KEY_TCCDMWTR, .sp_parse = spd_parse_ddr5_ps },
892 	{ .sp_off = SPD_DDR5_TCCD_M_WTR_NCK, .sp_key = SPD_KEY_TCCDMWTR_NCK,
893 	    .sp_parse = spd_parse_ddr5_nck }
894 };
895 
896 static void
897 spd_parse_ddr5_mod_rev(spd_info_t *si, uint32_t off, uint32_t len,
898     const char *key)
899 {
900 	const uint8_t data = si->si_data[off];
901 	const uint8_t enc = SPD_DDR5_SPD_REV_ENC(data);
902 	const uint8_t add = SPD_DDR5_SPD_REV_ADD(data);
903 
904 	spd_nvl_insert_u32(si, SPD_KEY_MOD_REV_ENC, enc);
905 	spd_nvl_insert_u32(si, SPD_KEY_MOD_REV_ADD, add);
906 }
907 
908 static const spd_value_map_t spd_ddr5_hash_map[] = {
909 	{ SPD_DDR5_COM_HASH_NONE, 0, true },
910 	{ SPD_DDR5_COM_HASH_ALG1, SPD_HASH_SEQ_ALG_1, false }
911 };
912 
913 static void
914 spd_parse_ddr5_hash_seq(spd_info_t *si, uint32_t off, uint32_t len,
915     const char *key)
916 {
917 	const uint8_t data = si->si_data[off];
918 	const uint8_t alg = SPD_DDR5_COM_HASH_HASH(data);
919 
920 	spd_insert_map(si, key, alg, spd_ddr5_hash_map,
921 	    ARRAY_SIZE(spd_ddr5_hash_map));
922 }
923 
924 static void
925 spd_parse_ddr5_dev_common(spd_info_t *si, uint32_t off, spd_device_t flags,
926     const char *id_key, const char *id_str_key, const char *rev_key,
927     const char *type_key, const spd_value_map_t *type_map, size_t ntypes)
928 {
929 	const uint8_t type = SPD_DDR5_COM_INFO_TYPE(si->si_data[off + 2]);
930 
931 	spd_parse_jedec_id(si, off, 2, id_key);
932 	spd_parse_jedec_id_str(si, off, 2, id_str_key);
933 	spd_parse_hex_vers(si, off + 3, 1, rev_key);
934 	spd_upsert_flag(si, SPD_KEY_DEVS, flags);
935 	spd_insert_map(si, type_key, type, type_map, ntypes);
936 }
937 
938 static const spd_value_map_t spd_ddr5_spd_type_map[] = {
939 	{ SPD_DDR5_COM_INFO_TYPE_SPD5118, SPD_SPD_T_SPD5118, false },
940 	{ SPD_DDR5_COM_INFO_TYPE_ESPD5216, SPD_SPD_T_ESPD5216, false }
941 };
942 
943 static void
944 spd_parse_ddr5_spd(spd_info_t *si, uint32_t off, uint32_t len, const char *key)
945 {
946 	ASSERT3U(len, ==, 4);
947 	const uint8_t type = si->si_data[off + 2];
948 	if (SPD_DDR5_COM_INFO_PRES(type) == 0)
949 		return;
950 
951 	spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_SPD, SPD_KEY_DEV_SPD_MFG,
952 	    SPD_KEY_DEV_SPD_MFG_NAME, SPD_KEY_DEV_SPD_REV, SPD_KEY_DEV_SPD_TYPE,
953 	    spd_ddr5_spd_type_map, ARRAY_SIZE(spd_ddr5_spd_type_map));
954 }
955 
956 static const spd_value_map_t spd_ddr5_pmic_type_map[] = {
957 	{ SPD_DDR5_COM_INFO_TYPE_PMIC5000, SPD_PMIC_T_PMIC5000, false },
958 	{ SPD_DDR5_COM_INFO_TYPE_PMIC5010, SPD_PMIC_T_PMIC5010, false },
959 	{ SPD_DDR5_COM_INFO_TYPE_PMIC5100, SPD_PMIC_T_PMIC5100, false },
960 	{ SPD_DDR5_COM_INFO_TYPE_PMIC5020, SPD_PMIC_T_PMIC5020, false },
961 	{ SPD_DDR5_COM_INFO_TYPE_PMIC5120, SPD_PMIC_T_PMIC5120, false },
962 	{ SPD_DDR5_COM_INFO_TYPE_PMIC5200, SPD_PMIC_T_PMIC5200, false },
963 	{ SPD_DDR5_COM_INFO_TYPE_PMIC5030, SPD_PMIC_T_PMIC5030, false },
964 };
965 
966 static void
967 spd_parse_ddr5_pmic0(spd_info_t *si, uint32_t off, uint32_t len,
968     const char *key)
969 {
970 	ASSERT3U(len, ==, 4);
971 	const uint8_t type = si->si_data[off + 2];
972 	if (SPD_DDR5_COM_INFO_PRES(type) == 0)
973 		return;
974 
975 	spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_PMIC_0,
976 	    SPD_KEY_DEV_PMIC0_MFG, SPD_KEY_DEV_PMIC0_MFG_NAME,
977 	    SPD_KEY_DEV_PMIC0_REV, SPD_KEY_DEV_PMIC0_TYPE,
978 	    spd_ddr5_pmic_type_map, ARRAY_SIZE(spd_ddr5_pmic_type_map));
979 }
980 
981 static void
982 spd_parse_ddr5_pmic1(spd_info_t *si, uint32_t off, uint32_t len,
983     const char *key)
984 {
985 	ASSERT3U(len, ==, 4);
986 	const uint8_t type = si->si_data[off + 2];
987 	if (SPD_DDR5_COM_INFO_PRES(type) == 0)
988 		return;
989 
990 	spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_PMIC_1,
991 	    SPD_KEY_DEV_PMIC1_MFG, SPD_KEY_DEV_PMIC1_MFG_NAME,
992 	    SPD_KEY_DEV_PMIC1_REV, SPD_KEY_DEV_PMIC1_TYPE,
993 	    spd_ddr5_pmic_type_map, ARRAY_SIZE(spd_ddr5_pmic_type_map));
994 }
995 
996 static void
997 spd_parse_ddr5_pmic2(spd_info_t *si, uint32_t off, uint32_t len,
998     const char *key)
999 {
1000 	ASSERT3U(len, ==, 4);
1001 	const uint8_t type = si->si_data[off + 2];
1002 	if (SPD_DDR5_COM_INFO_PRES(type) == 0)
1003 		return;
1004 
1005 	spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_PMIC_2,
1006 	    SPD_KEY_DEV_PMIC2_MFG, SPD_KEY_DEV_PMIC2_MFG_NAME,
1007 	    SPD_KEY_DEV_PMIC2_REV, SPD_KEY_DEV_PMIC2_TYPE,
1008 	    spd_ddr5_pmic_type_map, ARRAY_SIZE(spd_ddr5_pmic_type_map));
1009 }
1010 
1011 static const spd_value_map_t spd_ddr5_temp_type_map[] = {
1012 	{ SPD_DDR5_COM_INFO_TYPE_TS5111, SPD_TEMP_T_TS5111, false },
1013 	{ SPD_DDR5_COM_INFO_TYPE_TS5110, SPD_TEMP_T_TS5110, false },
1014 	{ SPD_DDR5_COM_INFO_TYPE_TS5211, SPD_TEMP_T_TS5211, false },
1015 	{ SPD_DDR5_COM_INFO_TYPE_TS5210, SPD_TEMP_T_TS5210, false }
1016 };
1017 
1018 static void
1019 spd_parse_ddr5_ts(spd_info_t *si, uint32_t off, uint32_t len, const char *key)
1020 {
1021 	ASSERT3U(len, ==, 4);
1022 	const uint8_t type = si->si_data[off + 2];
1023 	spd_device_t flags = 0;
1024 	if (SPD_DDR5_COM_INFO_PRES(type) != 0)
1025 		flags |= SPD_DEVICE_TEMP_1;
1026 	if (SPD_DDR5_COM_INFO_TS1_PRES(type) != 0)
1027 		flags |= SPD_DEVICE_TEMP_2;
1028 	if (flags == 0)
1029 		return;
1030 
1031 	spd_parse_ddr5_dev_common(si, off, flags, SPD_KEY_DEV_TEMP_MFG,
1032 	    SPD_KEY_DEV_TEMP_MFG_NAME, SPD_KEY_DEV_TEMP_REV,
1033 	    SPD_KEY_DEV_TEMP_TYPE, spd_ddr5_temp_type_map,
1034 	    ARRAY_SIZE(spd_ddr5_temp_type_map));
1035 }
1036 
1037 /*
1038  * This key presents a number of additional devices. It was added in DDR5 1.3
1039  * and LPDDR 1.2. Because this requires a non-zero value that should have been
1040  * reserved to be interpreted, we don't currently constrain based on the
1041  * version.
1042  */
1043 static void
1044 spd_parse_ddr5_add_dev(spd_info_t *si, uint32_t off, uint32_t len,
1045     const char *key)
1046 {
1047 	const uint8_t data = si->si_data[off];
1048 	spd_fuse_t fuse = 0;
1049 	spd_tvs_t tvs = 0;
1050 
1051 	if (SPD_DDR5_COM_ADDDEV_TVS_MGMT(data))
1052 		tvs |= SPD_TVS_VIN_MGMT;
1053 
1054 	if (SPD_DDR5_COM_ADDDEV_TVS_BULK(data))
1055 		tvs |= SPD_TVS_VIN_BULK;
1056 
1057 	if (SPD_DDR5_COM_ADDDEV_FUSE_BULK(data))
1058 		fuse |= SPD_FUSE_VIN_BULK;
1059 
1060 	if (fuse != 0)
1061 		spd_nvl_insert_u32(si, SPD_KEY_DEV_FUSE, fuse);
1062 
1063 	if (tvs != 0)
1064 		spd_nvl_insert_u32(si, SPD_KEY_DEV_TVS, tvs);
1065 }
1066 
1067 /*
1068  * While DDR5 uses similar constants as earlier DDR standards, less values have
1069  * been officially defined yet so we use a different table from the others.
1070  */
1071 static const spd_str_map_t spd_ddr5_design_map[] = {
1072 	{ 0, "A", false },
1073 	{ 1, "B", false },
1074 	{ 2, "C", false },
1075 	{ 3, "D", false },
1076 	{ 4, "E", false },
1077 	{ 5, "F", false },
1078 	{ 6, "G", false },
1079 	{ 7, "H", false },
1080 	{ 8, "J", false },
1081 	{ 9, "K", false },
1082 	{ 10, "L", false },
1083 	{ 11, "M", false },
1084 	{ 12, "N", false },
1085 	{ 13, "P", false },
1086 	{ 14, "R", false },
1087 	{ 15, "T", false },
1088 	{ 16, "U", false },
1089 	{ 17, "V", false },
1090 	{ 18, "W", false },
1091 	{ 19, "Y", false },
1092 	{ 20, "AA", false },
1093 	{ 21, "AB", false },
1094 	{ 22, "AC", false },
1095 	{ 23, "AD", false },
1096 	{ 24, "AE", false },
1097 	{ 25, "AF", false },
1098 	{ 26, "AG", false },
1099 	{ 27, "AH", false },
1100 	{ 28, "AJ", false },
1101 	{ 29, "AK", false },
1102 	{ 31, "ZZ", false }
1103 };
1104 
1105 static const spd_value_range_t spd_ddr5_design_rev_range = {
1106 	.svr_max = SPD_DDR5_COM_REF_REV_MAX
1107 };
1108 
1109 static void
1110 spd_parse_ddr5_design(spd_info_t *si, uint32_t off, uint32_t len,
1111     const char *key)
1112 {
1113 	const uint8_t data = si->si_data[off];
1114 	const uint8_t rev = SPD_DDR5_COM_REF_REV(data);
1115 	const uint8_t card = SPD_DDR5_COM_REF_CARD(data);
1116 
1117 	spd_insert_str_map(si, SPD_KEY_MOD_REF_DESIGN, card,
1118 	    spd_ddr5_design_map, ARRAY_SIZE(spd_ddr5_design_map));
1119 	spd_insert_range(si, SPD_KEY_MOD_DESIGN_REV, rev,
1120 	    &spd_ddr5_design_rev_range);
1121 }
1122 
1123 static const spd_value_map_t spd_ddr5_attr_nrows_map[] = {
1124 	{ SPD_DDR5_COM_ATTR_NROWS_UNDEF, 0, true },
1125 	{ SPD_DDR5_COM_ATTR_NROWS_1, 1, false },
1126 	{ SPD_DDR5_COM_ATTR_NROWS_2, 2, false },
1127 	{ SPD_DDR5_COM_ATTR_NROWS_3, 3, false },
1128 	{ SPD_DDR5_COM_ATTR_NROWS_4, 4, false }
1129 };
1130 
1131 static const spd_value_map_t spd_ddr5_attr_otr_map[] = {
1132 	{ SPD_DDR5_COM_ATTR_OTR_A1T, JEDEC_TEMP_CASE_A1T, false },
1133 	{ SPD_DDR5_COM_ATTR_OTR_A2T, JEDEC_TEMP_CASE_A2T, false },
1134 	{ SPD_DDR5_COM_ATTR_OTR_A3T, JEDEC_TEMP_CASE_A3T, false },
1135 	{ SPD_DDR5_COM_ATTR_OTR_IT, JEDEC_TEMP_CASE_IT, false },
1136 	{ SPD_DDR5_COM_ATTR_OTR_ST, JEDEC_TEMP_CASE_ST, false },
1137 	{ SPD_DDR5_COM_ATTR_OTR_ET, JEDEC_TEMP_CASE_ET, false },
1138 	{ SPD_DDR5_COM_ATTR_OTR_RT, JEDEC_TEMP_CASE_RT, false },
1139 	{ SPD_DDR5_COM_ATTR_OTR_NT, JEDEC_TEMP_CASE_NT, false },
1140 	{ SPD_DDR5_COM_ATTR_OTR_XT, JEDEC_TEMP_CASE_XT, false }
1141 };
1142 
1143 static void
1144 spd_parse_ddr5_attr(spd_info_t *si, uint32_t off, uint32_t len,
1145     const char *key)
1146 {
1147 	const uint8_t data = si->si_data[off];
1148 	const uint8_t otr = SPD_DDR5_COM_ATTR_OTR(data);
1149 	const uint8_t nrows = SPD_DDR5_COM_ATTR_NROWS(data);
1150 
1151 	if (SPD_DDR5_COM_ATTR_SPREAD(data) != 0)
1152 		spd_upsert_flag(si, SPD_KEY_DEVS, SPD_DEVICE_HS);
1153 	spd_insert_map(si, SPD_KEY_MOD_NROWS, nrows,
1154 	    spd_ddr5_attr_nrows_map, ARRAY_SIZE(spd_ddr5_attr_nrows_map));
1155 	spd_insert_map(si, SPD_KEY_MOD_OPER_TEMP, otr,
1156 	    spd_ddr5_attr_otr_map, ARRAY_SIZE(spd_ddr5_attr_otr_map));
1157 }
1158 
1159 static const spd_value_range_t spd_ddr5_nrank_range = {
1160 	.svr_base = SPD_DDR5_COM_ORG_NRANK_BASE
1161 };
1162 
1163 static void
1164 spd_parse_ddr5_mod_org(spd_info_t *si, uint32_t off, uint32_t len,
1165     const char *key)
1166 {
1167 	const uint8_t data = si->si_data[off];
1168 	const uint8_t nranks = SPD_DDR4_MOD_ORG_NPKG_RANK(data);
1169 
1170 	if (SPD_DDR5_COM_ORG_MIX(data) == SPD_DDR5_COM_ORG_MIX_ASYM)
1171 		spd_nvl_insert_key(si, SPD_KEY_RANK_ASYM);
1172 	spd_insert_range(si, SPD_KEY_NRANKS, nranks, &spd_ddr5_nrank_range);
1173 }
1174 
1175 static const spd_value_map_t spd_ddr5_ext_width[] = {
1176 	{ SPD_DDR5_COM_BUS_WIDTH_EXT_NONE, 0, false },
1177 	{ SPD_DDR5_COM_BUS_WIDTH_EXT_4b, 4, false },
1178 	{ SPD_DDR5_COM_BUS_WIDTH_EXT_8b, 8, false }
1179 };
1180 
1181 static const spd_value_map_t spd_ddr5_pri_width[] = {
1182 	{ SPD_DDR5_COM_BUS_WIDTH_PRI_8b, 8, false },
1183 	{ SPD_DDR5_COM_BUS_WIDTH_PRI_16b, 16, false },
1184 	{ SPD_DDR5_COM_BUS_WIDTH_PRI_32b, 32, false },
1185 	{ SPD_DDR5_COM_BUS_WIDTH_PRI_64b, 64, false },
1186 };
1187 
1188 static const spd_value_range_t spd_ddr5_nsc_range = {
1189 	.svr_max = SPD_DDR5_COM_BUS_WIDTH_NSC_MAX,
1190 	.svr_exp = true
1191 };
1192 
1193 static void
1194 spd_parse_ddr5_bus_width(spd_info_t *si, uint32_t off, uint32_t len,
1195     const char *key)
1196 {
1197 	const uint8_t data = si->si_data[off];
1198 	const uint8_t nsc = SPD_DDR5_COM_BUS_WIDTH_NSC(data);
1199 	const uint8_t ext = SPD_DDR5_COM_BUS_WIDTH_EXT(data);
1200 	const uint8_t pri = SPD_DDR5_COM_BUS_WIDTH_PRI(data);
1201 
1202 	spd_insert_range(si, SPD_KEY_NSUBCHAN, nsc, &spd_ddr5_nsc_range);
1203 	spd_nvl_insert_u32(si, SPD_KEY_DRAM_NCHAN, 1);
1204 	spd_insert_map(si, SPD_KEY_ECC_WIDTH, ext, spd_ddr5_ext_width,
1205 	    ARRAY_SIZE(spd_ddr5_ext_width));
1206 	spd_insert_map(si, SPD_KEY_DATA_WIDTH, pri, spd_ddr5_pri_width,
1207 	    ARRAY_SIZE(spd_ddr5_pri_width));
1208 }
1209 
1210 static const spd_parse_t spd_ddr5_module[] = {
1211 	{ .sp_off = SPD_DDR5_COM_REV, .sp_parse = spd_parse_ddr5_mod_rev },
1212 	{ .sp_off = SPD_DDR5_COM_HASH, .sp_parse = spd_parse_ddr5_hash_seq,
1213 	    .sp_key = SPD_KEY_HASH_SEQ },
1214 	{ .sp_off = SPD_DDR5_COM_MFG_ID0_SPD, .sp_len = 4,
1215 	    .sp_parse = spd_parse_ddr5_spd },
1216 	{ .sp_off = SPD_DDR5_COM_MFG_ID0_PMIC0, .sp_len = 4,
1217 	    .sp_parse = spd_parse_ddr5_pmic0 },
1218 	{ .sp_off = SPD_DDR5_COM_MFG_ID0_PMIC1, .sp_len = 4,
1219 	    .sp_parse = spd_parse_ddr5_pmic1 },
1220 	{ .sp_off = SPD_DDR5_COM_MFG_ID0_PMIC2, .sp_len = 4,
1221 	    .sp_parse = spd_parse_ddr5_pmic2 },
1222 	{ .sp_off = SPD_DDR5_COM_MFG_ID0_TS, .sp_len = 4,
1223 	    .sp_parse = spd_parse_ddr5_ts },
1224 	{ .sp_off = SPD_DDR5_COM_ADDDEV, .sp_parse = spd_parse_ddr5_add_dev },
1225 	{ .sp_off = SPD_DDR5_COM_HEIGHT, .sp_key = SPD_KEY_MOD_HEIGHT,
1226 	    .sp_parse = spd_parse_height },
1227 	{ .sp_off = SPD_DDR5_COM_THICK, .sp_parse = spd_parse_thickness },
1228 	{ .sp_off = SPD_DDR5_COM_REF, .sp_parse = spd_parse_ddr5_design },
1229 	{ .sp_off = SPD_DDR5_COM_ATTR, .sp_parse = spd_parse_ddr5_attr },
1230 	{ .sp_off = SPD_DDR5_COM_ORG, .sp_parse = spd_parse_ddr5_mod_org },
1231 	{ .sp_off = SPD_DDR5_COM_BUS_WIDTH,
1232 	    .sp_parse = spd_parse_ddr5_bus_width },
1233 	/* We include the DDR5 CRC in this group as it's considered common */
1234 	{ .sp_len = SPD_DDR5_CRC_MSB + 1, .sp_key = SPD_KEY_CRC_DDR5,
1235 	    .sp_parse = spd_parse_crc },
1236 };
1237 
1238 static const spd_parse_t spd_ddr5_mfg[] = {
1239 	{ .sp_off = SPD_DDR5_MOD_MFG_ID0, .sp_len = 2,
1240 	    .sp_key = SPD_KEY_MFG_MOD_MFG_ID, .sp_parse = spd_parse_jedec_id },
1241 	{ .sp_off = SPD_DDR5_MOD_MFG_ID0, .sp_len = 2,
1242 	    .sp_key = SPD_KEY_MFG_MOD_MFG_NAME,
1243 	    .sp_parse = spd_parse_jedec_id_str },
1244 	{ .sp_off = SPD_DDR5_DRAM_MFG_ID0, .sp_len = 2,
1245 	    .sp_key = SPD_KEY_MFG_DRAM_MFG_ID, .sp_parse = spd_parse_jedec_id },
1246 	{ .sp_off = SPD_DDR5_DRAM_MFG_ID0, .sp_len = 2,
1247 	    .sp_key = SPD_KEY_MFG_DRAM_MFG_NAME,
1248 	    .sp_parse = spd_parse_jedec_id_str },
1249 	{ .sp_off = SPD_DDR5_MOD_MFG_LOC, .sp_key = SPD_KEY_MFG_MOD_LOC_ID,
1250 	    .sp_parse = spd_parse_raw_u8 },
1251 	{ .sp_off = SPD_DDR5_MOD_MFG_YEAR, .sp_key = SPD_KEY_MFG_MOD_YEAR,
1252 	    .sp_parse = spd_parse_hex_string },
1253 	{ .sp_off = SPD_DDR5_MOD_MFG_WEEK, .sp_key = SPD_KEY_MFG_MOD_WEEK,
1254 	    .sp_parse = spd_parse_hex_string },
1255 	{ .sp_off = SPD_DDR5_MOD_SN, .sp_len = SPD_DDR5_MOD_SN_LEN,
1256 	    .sp_key = SPD_KEY_MFG_MOD_SN, .sp_parse = spd_parse_hex_string },
1257 	{ .sp_off = SPD_DDR5_MOD_PN, .sp_len = SPD_DDR5_MOD_PN_LEN,
1258 	    .sp_key = SPD_KEY_MFG_MOD_PN, .sp_parse = spd_parse_string },
1259 	{ .sp_off = SPD_DDR5_MOD_REV, .sp_key = SPD_KEY_MFG_MOD_REV,
1260 	    .sp_parse = spd_parse_dram_step },
1261 	{ .sp_off = SPD_DDR5_DRAM_STEP, .sp_key = SPD_KEY_MFG_DRAM_STEP,
1262 	    .sp_parse = spd_parse_dram_step }
1263 };
1264 
1265 /*
1266  * Annex A.2 UDIMM and SODIMM specific processing.
1267  */
1268 
1269 static const spd_value_map_t spd_ddr5_cd_type_map[] = {
1270 	{ SPD_DDR5_UDIMM_INFO_TYPE_DDR5CK01, SPD_CD_T_DDR5CK01, false }
1271 };
1272 
1273 static void
1274 spd_parse_ddr5_udimm_cd(spd_info_t *si, uint32_t off, uint32_t len,
1275     const char *key)
1276 {
1277 	ASSERT3U(len, ==, 4);
1278 	const uint8_t type = si->si_data[off + 2];
1279 	if (SPD_DDR5_COM_INFO_PRES(type) == 0)
1280 		return;
1281 
1282 	spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_CD_0,
1283 	    SPD_KEY_DEV_CD0_MFG, SPD_KEY_DEV_CD0_MFG_NAME,
1284 	    SPD_KEY_DEV_CD0_REV, SPD_KEY_DEV_CD0_TYPE,
1285 	    spd_ddr5_cd_type_map, ARRAY_SIZE(spd_ddr5_cd_type_map));
1286 }
1287 
1288 /*
1289  * The various clock driver routines are shared between CAMM2 and UDIMMs as they
1290  * are based on the shared CKD01 spec.
1291  */
1292 static void
1293 spd_parse_ddr5_ckd_cfg(spd_info_t *si, uint32_t off, const char *chack0,
1294     const char *chack1, const char *ckbck0, const char *chbck1)
1295 {
1296 	const uint8_t data = si->si_data[off];
1297 
1298 	if (SPD_DDR5_UDIMM_CKD_CFG_CHAQCK0(data) == 0)
1299 		spd_nvl_insert_key(si, chack0);
1300 	if (SPD_DDR5_UDIMM_CKD_CFG_CHAQCK1(data) == 0)
1301 		spd_nvl_insert_key(si, chack1);
1302 	if (SPD_DDR5_UDIMM_CKD_CFG_CHBQCK0(data) == 0)
1303 		spd_nvl_insert_key(si, chbck1);
1304 	if (SPD_DDR5_UDIMM_CKD_CFG_CHBQCK1(data) == 0)
1305 		spd_nvl_insert_key(si, chbck1);
1306 }
1307 
1308 static void
1309 spd_parse_ddr5_ckd_cfg_ckd0(spd_info_t *si, uint32_t off, uint32_t len,
1310     const char *key)
1311 {
1312 	return (spd_parse_ddr5_ckd_cfg(si, off, SPD_KEY_DDR5_CKD_CHAQCK0_EN,
1313 	    SPD_KEY_DDR5_CKD_CHAQCK1_EN, SPD_KEY_DDR5_CKD_CHBQCK0_EN,
1314 	    SPD_KEY_DDR5_CKD_CHBQCK1_EN));
1315 }
1316 
1317 static void
1318 spd_parse_ddr5_ckd_cfg_ckd1(spd_info_t *si, uint32_t off, uint32_t len,
1319     const char *key)
1320 {
1321 	return (spd_parse_ddr5_ckd_cfg(si, off, SPD_KEY_DDR5_CKD1_CHAQCK0_EN,
1322 	    SPD_KEY_DDR5_CKD1_CHAQCK1_EN, SPD_KEY_DDR5_CKD1_CHBQCK0_EN,
1323 	    SPD_KEY_DDR5_CKD1_CHBQCK1_EN));
1324 }
1325 
1326 static const spd_value_map_t spd_ddr5_ckd_ds_map[] = {
1327 	{ SPD_DDR5_UDIMM_CKD_DRV_LIGHT, SPD_DRIVE_LIGHT, false },
1328 	{ SPD_DDR5_UDIMM_CKD_DRV_MODERATE, SPD_DRIVE_MODERATE, false },
1329 	{ SPD_DDR5_UDIMM_CKD_DRV_STRONG, SPD_DRIVE_STRONG, false },
1330 	{ SPD_DDR5_UDIMM_CKD_DRV_WEAK, SPD_DRIVE_WEAK, false }
1331 };
1332 
1333 static void
1334 spd_parse_ddr5_ckd_drv(spd_info_t *si, uint32_t off, const char *qck0a_key,
1335     const char *qck1a_key, const char *qck0b_key, const char *qck1b_key)
1336 {
1337 	const uint8_t data = si->si_data[off];
1338 	const uint8_t qck0a = SPD_DDR5_UDIMM_CKD_DRV_CHAQCK0_DRIVE(data);
1339 	const uint8_t qck1a = SPD_DDR5_UDIMM_CKD_DRV_CHAQCK1_DRIVE(data);
1340 	const uint8_t qck0b = SPD_DDR5_UDIMM_CKD_DRV_CHBQCK0_DRIVE(data);
1341 	const uint8_t qck1b = SPD_DDR5_UDIMM_CKD_DRV_CHBQCK1_DRIVE(data);
1342 
1343 	spd_insert_map(si, qck0a_key, qck0a, spd_ddr5_ckd_ds_map,
1344 	    ARRAY_SIZE(spd_ddr5_ckd_ds_map));
1345 	spd_insert_map(si, qck1a_key, qck1a, spd_ddr5_ckd_ds_map,
1346 	    ARRAY_SIZE(spd_ddr5_ckd_ds_map));
1347 	spd_insert_map(si, qck0b_key, qck0b, spd_ddr5_ckd_ds_map,
1348 	    ARRAY_SIZE(spd_ddr5_ckd_ds_map));
1349 	spd_insert_map(si, qck1b_key, qck1b, spd_ddr5_ckd_ds_map,
1350 	    ARRAY_SIZE(spd_ddr5_ckd_ds_map));
1351 }
1352 
1353 static void
1354 spd_parse_ddr5_ckd_drv_ckd0(spd_info_t *si, uint32_t off, uint32_t len,
1355     const char *key)
1356 {
1357 	return (spd_parse_ddr5_ckd_drv(si, off, SPD_KEY_DDR5_CKD_CHAQCK0_DS,
1358 	    SPD_KEY_DDR5_CKD_CHAQCK1_DS, SPD_KEY_DDR5_CKD_CHBQCK0_DS,
1359 	    SPD_KEY_DDR5_CKD_CHBQCK1_DS));
1360 }
1361 
1362 static void
1363 spd_parse_ddr5_ckd_drv_ckd1(spd_info_t *si, uint32_t off, uint32_t len,
1364     const char *key)
1365 {
1366 	return (spd_parse_ddr5_ckd_drv(si, off, SPD_KEY_DDR5_CKD1_CHAQCK0_DS,
1367 	    SPD_KEY_DDR5_CKD1_CHAQCK1_DS, SPD_KEY_DDR5_CKD1_CHBQCK0_DS,
1368 	    SPD_KEY_DDR5_CKD1_CHBQCK1_DS));
1369 }
1370 
1371 static const spd_value_map_t spd_ddr5_ckd_slew_map[] = {
1372 	{ SPD_DDR5_UDIMM_CKD_SLEW_SLEW_MODERATE, SPD_SLEW_MODERATE, false },
1373 	{ SPD_DDR5_UDIMM_CKD_SLEW_SLEW_FAST, SPD_SLEW_FAST, false }
1374 };
1375 
1376 static void
1377 spd_parse_ddr5_ckd_slew(spd_info_t *si, uint32_t off,
1378     const char *qcka_key, const char *qckb_key)
1379 {
1380 	const uint8_t data = si->si_data[off];
1381 	const uint8_t qcka = SPD_DDR5_UDIMM_CKD_SLEW_CHAQCK_SLEW(data);
1382 	const uint8_t qckb = SPD_DDR5_UDIMM_CKD_SLEW_CHBQCK_SLEW(data);
1383 
1384 	spd_insert_map(si, qcka_key, qcka,
1385 	    spd_ddr5_ckd_slew_map, ARRAY_SIZE(spd_ddr5_ckd_slew_map));
1386 	spd_insert_map(si, qckb_key, qckb,
1387 	    spd_ddr5_ckd_slew_map, ARRAY_SIZE(spd_ddr5_ckd_slew_map));
1388 }
1389 
1390 static void
1391 spd_parse_ddr5_ckd_slew_ckd0(spd_info_t *si, uint32_t off, uint32_t len,
1392     const char *key)
1393 {
1394 	return (spd_parse_ddr5_ckd_slew(si, off, SPD_KEY_DDR5_CKD_CHAQCK_SLEW,
1395 	    SPD_KEY_DDR5_CKD_CHBQCK_SLEW));
1396 }
1397 
1398 static void
1399 spd_parse_ddr5_ckd_slew_ckd1(spd_info_t *si, uint32_t off, uint32_t len,
1400     const char *key)
1401 {
1402 	return (spd_parse_ddr5_ckd_slew(si, off, SPD_KEY_DDR5_CKD1_CHAQCK_SLEW,
1403 	    SPD_KEY_DDR5_CKD1_CHBQCK_SLEW));
1404 }
1405 
1406 static const spd_parse_t spd_ddr5_udimm[] = {
1407 	{ .sp_off = SPD_DDR5_COM_MFG_ID0_TS, .sp_len = 4,
1408 	    .sp_parse = spd_parse_ddr5_udimm_cd }
1409 };
1410 
1411 static const spd_parse_t spd_ddr5_udimm_1v1[] = {
1412 	{ .sp_off = SPD_DDR5_UDIMM_CKD_CFG,
1413 	    .sp_parse = spd_parse_ddr5_ckd_cfg_ckd0 },
1414 	{ .sp_off = SPD_DDR5_UDIMM_CKD_DRV,
1415 	    .sp_parse = spd_parse_ddr5_ckd_drv_ckd0 },
1416 	{ .sp_off = SPD_DDR5_UDIMM_CKD_SLEW,
1417 	    .sp_parse = spd_parse_ddr5_ckd_slew_ckd0 }
1418 };
1419 
1420 /*
1421  * Annex A.3 RDIMM and LRDIMM specific processing. Because certain fields are
1422  * LRDIMM-only, we use two different top-level tables to drive them; however,
1423  * they generally overlap otherwise. Items that are LRDIMM only will contain
1424  * lrdimm in the name. All items named rdimm are shared between both the LRDIMM
1425  * and RDIMM processing.
1426  */
1427 static const spd_value_map_t spd_ddr5_rcd_type_map[] = {
1428 	{ SPD_DDR5_RDIMM_INFO_TYPE_RCD01, SPD_RCD_T_DDR5RCD01, false },
1429 	{ SPD_DDR5_RDIMM_INFO_TYPE_RCD02, SPD_RCD_T_DDR5RCD02, false },
1430 	{ SPD_DDR5_RDIMM_INFO_TYPE_RCD03, SPD_RCD_T_DDR5RCD03, false },
1431 	{ SPD_DDR5_RDIMM_INFO_TYPE_RCD04, SPD_RCD_T_DDR5RCD04, false },
1432 	{ SPD_DDR5_RDIMM_INFO_TYPE_RCD05, SPD_RCD_T_DDR5RCD05, false },
1433 	{ SPD_DDR5_RDIMM_INFO_TYPE_RCD06, SPD_RCD_T_DDR5RCD06, false }
1434 };
1435 
1436 static const spd_value_map_t spd_ddr5_db_type_map[] = {
1437 	{ SPD_DDR5_RDIMM_INFO_TYPE_DB01, SPD_DB_T_DDR5DB01, false },
1438 	{ SPD_DDR5_RDIMM_INFO_TYPE_DB02, SPD_DB_T_DDR5DB02, false }
1439 };
1440 
1441 static void
1442 spd_parse_ddr5_rdimm_rcd(spd_info_t *si, uint32_t off, uint32_t len,
1443     const char *key)
1444 {
1445 	ASSERT3U(len, ==, 4);
1446 	const uint8_t type = si->si_data[off + 2];
1447 	if (SPD_DDR5_COM_INFO_PRES(type) == 0)
1448 		return;
1449 
1450 	spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_RCD,
1451 	    SPD_KEY_DEV_RCD_MFG, SPD_KEY_DEV_RCD_MFG_NAME,
1452 	    SPD_KEY_DEV_RCD_REV, SPD_KEY_DEV_RCD_TYPE,
1453 	    spd_ddr5_rcd_type_map, ARRAY_SIZE(spd_ddr5_rcd_type_map));
1454 }
1455 
1456 static void
1457 spd_parse_ddr5_lrdimm_db(spd_info_t *si, uint32_t off, uint32_t len,
1458     const char *key)
1459 {
1460 	ASSERT3U(len, ==, 4);
1461 	const uint8_t type = si->si_data[off + 2];
1462 	if (SPD_DDR5_COM_INFO_PRES(type) == 0)
1463 		return;
1464 
1465 	spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_DB,
1466 	    SPD_KEY_DEV_DB_MFG, SPD_KEY_DEV_DB_MFG_NAME,
1467 	    SPD_KEY_DEV_DB_REV, SPD_KEY_DEV_DB_TYPE,
1468 	    spd_ddr5_db_type_map, ARRAY_SIZE(spd_ddr5_db_type_map));
1469 }
1470 
1471 static void
1472 spd_parse_ddr5_rdimm_clken(spd_info_t *si, uint32_t off, uint32_t len,
1473     const char *key)
1474 {
1475 	const uint8_t data = si->si_data[off];
1476 
1477 	if (SPD_DDR5_RDIMM_CLKEN_QACK(data) == 0)
1478 		spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_QACK_EN);
1479 	if (SPD_DDR5_RDIMM_CLKEN_QBCK(data) == 0)
1480 		spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_QBCK_EN);
1481 	if (SPD_DDR5_RDIMM_CLKEN_QCCK(data) == 0)
1482 		spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_QCCK_EN);
1483 	if (SPD_DDR5_RDIMM_CLKEN_QDCK(data) == 0)
1484 		spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_QDCK_EN);
1485 	if (SPD_DDR5_RDIMM_CLKEN_BCK(data) == 0)
1486 		spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_BCK_EN);
1487 }
1488 
1489 static void
1490 spd_parse_ddr5_rdimm_rwen(spd_info_t *si, uint32_t off, uint32_t len,
1491     const char *key)
1492 {
1493 	const uint8_t data = si->si_data[off];
1494 
1495 	if (SPD_DDR5_RDIMM_RW09_QBCS(data) == 0)
1496 		spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_QBCS_EN);
1497 	if (SPD_DDR5_RDIMM_RW09_QACS(data) == 0)
1498 		spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_QACS_EN);
1499 	if (SPD_DDR5_RDIMM_RW09_QXCA13(data) == 0)
1500 		spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_QxCA13_EN);
1501 	if (SPD_DDR5_RDIMM_RW09_BCS(data) == 0)
1502 		spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_BCS_EN);
1503 	if (SPD_DDR5_RDIMM_RW09_DCS(data) == 0)
1504 		spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_QxCS_EN);
1505 	if (SPD_DDR5_RDIMM_RW09_QBCA(data) == 0)
1506 		spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_QBCA_EN);
1507 	if (SPD_DDR5_RDIMM_RW09_QACA(data) == 0)
1508 		spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_QACA_EN);
1509 }
1510 
1511 static const spd_value_map_t spd_ddr5_ds_map[] = {
1512 	{ SPD_DDR5_RDIMM_DRV_LIGHT, SPD_DRIVE_LIGHT, false },
1513 	{ SPD_DDR5_RDIMM_DRV_MODERATE, SPD_DRIVE_MODERATE, false },
1514 	{ SPD_DDR5_RDIMM_DRV_STRONG, SPD_DRIVE_STRONG, false }
1515 };
1516 
1517 static void
1518 spd_parse_ddr5_rdimm_clkimp(spd_info_t *si, uint32_t off, uint32_t len,
1519     const char *key)
1520 {
1521 	const uint8_t data = si->si_data[off];
1522 	const uint8_t qack = SPD_DDR5_RDIMM_QCK_DRV_QACK(data);
1523 	const uint8_t qbck = SPD_DDR5_RDIMM_QCK_DRV_QBCK(data);
1524 	const uint8_t qcck = SPD_DDR5_RDIMM_QCK_DRV_QCCK(data);
1525 	const uint8_t qdck = SPD_DDR5_RDIMM_QCK_DRV_QDCK(data);
1526 
1527 	spd_insert_map(si, SPD_KEY_DDR5_RCD_QACK_DS, qack, spd_ddr5_ds_map,
1528 	    ARRAY_SIZE(spd_ddr5_ds_map));
1529 	spd_insert_map(si, SPD_KEY_DDR5_RCD_QBCK_DS, qbck, spd_ddr5_ds_map,
1530 	    ARRAY_SIZE(spd_ddr5_ds_map));
1531 	spd_insert_map(si, SPD_KEY_DDR5_RCD_QCCK_DS, qcck, spd_ddr5_ds_map,
1532 	    ARRAY_SIZE(spd_ddr5_ds_map));
1533 	spd_insert_map(si, SPD_KEY_DDR5_RCD_QDCK_DS, qdck, spd_ddr5_ds_map,
1534 	    ARRAY_SIZE(spd_ddr5_ds_map));
1535 }
1536 
1537 static void
1538 spd_parse_ddr5_rdimm_casimp(spd_info_t *si, uint32_t off, uint32_t len,
1539     const char *key)
1540 {
1541 	const uint8_t data = si->si_data[off];
1542 	const uint8_t cs = SPD_DDR5_RDIMM_QCA_DRV_CS(data);
1543 	const uint8_t ca = SPD_DDR5_RDIMM_QCA_DRV_CA(data);
1544 
1545 	spd_insert_map(si, SPD_KEY_DDR5_RCD_QxCS_DS, cs, spd_ddr5_ds_map,
1546 	    ARRAY_SIZE(spd_ddr5_ds_map));
1547 	spd_insert_map(si, SPD_KEY_DDR5_RCD_CA_DS, ca, spd_ddr5_ds_map,
1548 	    ARRAY_SIZE(spd_ddr5_ds_map));
1549 }
1550 
1551 static void
1552 spd_parse_ddr5_lrdimm_dbimp(spd_info_t *si, uint32_t off, uint32_t len,
1553     const char *key)
1554 {
1555 	const uint8_t data = si->si_data[off];
1556 	const uint8_t bck = SPD_DDR5_LRDIMM_DB_DRV_BCK(data);
1557 	const uint8_t bcom = SPD_DDR5_LRDIMM_DB_DRV_BCOM(data);
1558 
1559 	spd_insert_map(si, SPD_KEY_DDR5_RCD_BCK_DS, bck, spd_ddr5_ds_map,
1560 	    ARRAY_SIZE(spd_ddr5_ds_map));
1561 	spd_insert_map(si, SPD_KEY_DDR5_RCD_BCOM_DS, bcom, spd_ddr5_ds_map,
1562 	    ARRAY_SIZE(spd_ddr5_ds_map));
1563 }
1564 
1565 static const spd_value_map_t spd_ddr5_rcd_slew_map[] = {
1566 	{ SPD_DDR5_RDIMM_SLEW_MODERTE, SPD_SLEW_MODERATE, false },
1567 	{ SPD_DDR5_RDIMM_SLEW_FAST, SPD_SLEW_FAST, false },
1568 	{ SPD_DDR5_RDIMM_SLEW_SLOW, SPD_SLEW_SLOW, false }
1569 };
1570 
1571 static void
1572 spd_parse_ddr5_rdimm_qslew(spd_info_t *si, uint32_t off, uint32_t len,
1573     const char *key)
1574 {
1575 	const uint8_t data = si->si_data[off];
1576 	const uint8_t qcs = SPD_DDR5_RDIMM_QXX_SLEW_QCS(data);
1577 	const uint8_t qca = SPD_DDR5_RDIMM_QXX_SLEW_QCA(data);
1578 	const uint8_t qck = SPD_DDR5_RDIMM_QXX_SLEW_QCK(data);
1579 
1580 	spd_insert_map(si, SPD_KEY_DDR5_RCD_QCK_SLEW, qck,
1581 	    spd_ddr5_rcd_slew_map, ARRAY_SIZE(spd_ddr5_rcd_slew_map));
1582 	spd_insert_map(si, SPD_KEY_DDR5_RCD_QCA_SLEW, qca,
1583 	    spd_ddr5_rcd_slew_map, ARRAY_SIZE(spd_ddr5_rcd_slew_map));
1584 	spd_insert_map(si, SPD_KEY_DDR5_RCD_QCS_SLEW, qcs,
1585 	    spd_ddr5_rcd_slew_map, ARRAY_SIZE(spd_ddr5_rcd_slew_map));
1586 }
1587 
1588 static void
1589 spd_parse_ddr5_lrdimm_bslew(spd_info_t *si, uint32_t off, uint32_t len,
1590     const char *key)
1591 {
1592 	const uint8_t data = si->si_data[off];
1593 	const uint8_t bck = SPD_DDR5_LRDIMM_BXX_SLEW_BCK(data);
1594 	const uint8_t bcom = SPD_DDR5_LRDIMM_BXX_SLEW_BCOM(data);
1595 
1596 	spd_insert_map(si, SPD_KEY_DDR5_RCD_BCK_SLEW, bck,
1597 	    spd_ddr5_rcd_slew_map, ARRAY_SIZE(spd_ddr5_rcd_slew_map));
1598 	spd_insert_map(si, SPD_KEY_DDR5_RCD_BCOM_SLEW, bcom,
1599 	    spd_ddr5_rcd_slew_map, ARRAY_SIZE(spd_ddr5_rcd_slew_map));
1600 }
1601 
1602 static const spd_value_map_t spd_ddr5_rtt_term_map[] = {
1603 	{ SPD_DDR5_LDRIMM_PARK_OFF, 0, true },
1604 	{ SPD_DDR5_LDRIMM_PARK_240R, 240, false },
1605 	{ SPD_DDR5_LDRIMM_PARK_120R, 120, false },
1606 	{ SPD_DDR5_LDRIMM_PARK_80R, 80, false },
1607 	{ SPD_DDR5_LDRIMM_PARK_60R, 60, false },
1608 	{ SPD_DDR5_LDRIMM_PARK_48R, 48, false },
1609 	{ SPD_DDR5_LDRIMM_PARK_40R, 40, false },
1610 	{ SPD_DDR5_LDRIMM_PARK_34R, 34, false }
1611 };
1612 
1613 static void
1614 spd_parse_ddr5_lrdimm_rtt(spd_info_t *si, uint32_t off, uint32_t len,
1615     const char *key)
1616 {
1617 	const uint8_t data = si->si_data[off];
1618 	const uint8_t rtt = SPD_DDR5_LRDIMM_PARK_TERM(data);
1619 
1620 	spd_insert_map(si, SPD_KEY_DDR5_RCD_RTT_TERM, rtt,
1621 	    spd_ddr5_rtt_term_map, ARRAY_SIZE(spd_ddr5_rtt_term_map));
1622 }
1623 
1624 static const spd_parse_t spd_ddr5_rdimm[] = {
1625 	{ .sp_off = SPD_DDR5_RDIMM_MFG_ID0_RCD, .sp_len = 4,
1626 	    .sp_parse = spd_parse_ddr5_rdimm_rcd },
1627 	{ .sp_off = SPD_DDR5_RDIMM_CLKEN,
1628 	    .sp_parse = spd_parse_ddr5_rdimm_clken },
1629 	{ .sp_off = SPD_DDR5_RDIMM_RW09,
1630 	    .sp_parse = spd_parse_ddr5_rdimm_rwen },
1631 	{ .sp_off = SPD_DDR5_RDIMM_QCK_DRV,
1632 	    .sp_parse = spd_parse_ddr5_rdimm_clkimp },
1633 	{ .sp_off = SPD_DDR5_RDIMM_QCA_DRV,
1634 	    .sp_parse = spd_parse_ddr5_rdimm_casimp },
1635 	{ .sp_off = SPD_DDR5_RDIMM_QXX_SLEW,
1636 	    .sp_parse = spd_parse_ddr5_rdimm_qslew }
1637 };
1638 
1639 static const spd_parse_t spd_ddr5_lrdimm[] = {
1640 	{ .sp_off = SPD_DDR5_RDIMM_MFG_ID0_RCD, .sp_len = 4,
1641 	    .sp_parse = spd_parse_ddr5_rdimm_rcd },
1642 	{ .sp_off = SPD_DDR5_RDIMM_MFG_ID0_DB, .sp_len = 4,
1643 	    .sp_parse = spd_parse_ddr5_lrdimm_db },
1644 	{ .sp_off = SPD_DDR5_RDIMM_CLKEN,
1645 	    .sp_parse = spd_parse_ddr5_rdimm_clken },
1646 	{ .sp_off = SPD_DDR5_RDIMM_RW09,
1647 	    .sp_parse = spd_parse_ddr5_rdimm_rwen },
1648 	{ .sp_off = SPD_DDR5_RDIMM_QCK_DRV,
1649 	    .sp_parse = spd_parse_ddr5_rdimm_clkimp },
1650 	{ .sp_off = SPD_DDR5_RDIMM_QCA_DRV,
1651 	    .sp_parse = spd_parse_ddr5_rdimm_casimp },
1652 	{ .sp_off = SPD_DDR5_LRDIMM_DB_DRV,
1653 	    .sp_parse = spd_parse_ddr5_lrdimm_dbimp },
1654 	{ .sp_off = SPD_DDR5_RDIMM_QXX_SLEW,
1655 	    .sp_parse = spd_parse_ddr5_rdimm_qslew },
1656 	{ .sp_off = SPD_DDR5_LRDIMM_BXX_SLEW,
1657 	    .sp_parse = spd_parse_ddr5_lrdimm_bslew },
1658 	{ .sp_off = SPD_DDR5_LRDIMM_PARK,
1659 	    .sp_parse = spd_parse_ddr5_lrdimm_rtt },
1660 };
1661 
1662 /*
1663  * Annex A.4 MRDIMM specific processing.
1664  */
1665 static const spd_value_map_t spd_ddr5_mrcd_type_map[] = {
1666 	{ SPD_DDR5_MRDIMM_INFO_TYPE_MRCD01, SPD_MRCD_T_DDR5MRCD01, false },
1667 	{ SPD_DDR5_MRDIMM_INFO_TYPE_MRCD02, SPD_MRCD_T_DDR5MRCD02, false },
1668 	{ SPD_DDR5_MRDIMM_INFO_TYPE_MRCD03, SPD_MRCD_T_DDR5MRCD03, false }
1669 };
1670 
1671 static const spd_value_map_t spd_ddr5_mdb_type_map[] = {
1672 	{ SPD_DDR5_MRDIMM_INFO_TYPE_MDB01, SPD_MDB_T_DDR5MDB01, false },
1673 	{ SPD_DDR5_MRDIMM_INFO_TYPE_MDB02, SPD_MDB_T_DDR5MDB02, false },
1674 	{ SPD_DDR5_MRDIMM_INFO_TYPE_MDB03, SPD_MDB_T_DDR5MDB03, false }
1675 };
1676 
1677 static void
1678 spd_parse_ddr5_mrdimm_mrcd(spd_info_t *si, uint32_t off, uint32_t len,
1679     const char *key)
1680 {
1681 	ASSERT3U(len, ==, 4);
1682 	const uint8_t type = si->si_data[off + 2];
1683 	if (SPD_DDR5_COM_INFO_PRES(type) == 0)
1684 		return;
1685 
1686 	spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_MRCD,
1687 	    SPD_KEY_DEV_MRCD_MFG, SPD_KEY_DEV_MRCD_MFG_NAME,
1688 	    SPD_KEY_DEV_MRCD_REV, SPD_KEY_DEV_MRCD_TYPE,
1689 	    spd_ddr5_mrcd_type_map, ARRAY_SIZE(spd_ddr5_mrcd_type_map));
1690 }
1691 
1692 static void
1693 spd_parse_ddr5_mrdimm_mdb(spd_info_t *si, uint32_t off, uint32_t len,
1694     const char *key)
1695 {
1696 	ASSERT3U(len, ==, 4);
1697 	const uint8_t type = si->si_data[off + 2];
1698 	if (SPD_DDR5_COM_INFO_PRES(type) == 0)
1699 		return;
1700 
1701 	spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_MDB,
1702 	    SPD_KEY_DEV_MDB_MFG, SPD_KEY_DEV_MDB_MFG_NAME,
1703 	    SPD_KEY_DEV_MDB_REV, SPD_KEY_DEV_MDB_TYPE,
1704 	    spd_ddr5_mdb_type_map, ARRAY_SIZE(spd_ddr5_mdb_type_map));
1705 }
1706 
1707 static const spd_parse_t spd_ddr5_mrdimm[] = {
1708 	{ .sp_off = SPD_DDR5_MRDIMM_MFG_ID0_MRCD, .sp_len = 4,
1709 	    .sp_parse = spd_parse_ddr5_mrdimm_mrcd },
1710 	{ .sp_off = SPD_DDR5_MRDIMM_MFG_ID0_MDB, .sp_len = 4,
1711 	    .sp_parse = spd_parse_ddr5_mrdimm_mdb }
1712 };
1713 
1714 static void
1715 spd_parse_ddr5_mrdimm_cden(spd_info_t *si, uint32_t off, uint32_t len,
1716     const char *key)
1717 {
1718 	const uint8_t data = si->si_data[off];
1719 
1720 	if (SPD_DDR5_MRDIMM_CDEN_QACK(data) == 0)
1721 		spd_nvl_insert_key(si, SPD_KEY_DDR5_MRCD_QACK_EN);
1722 	if (SPD_DDR5_MRDIMM_CDEN_QBCK(data) == 0)
1723 		spd_nvl_insert_key(si, SPD_KEY_DDR5_MRCD_QBCK_EN);
1724 	if (SPD_DDR5_MRDIMM_CDEN_QCCK(data) == 0)
1725 		spd_nvl_insert_key(si, SPD_KEY_DDR5_MRCD_QCCK_EN);
1726 	if (SPD_DDR5_MRDIMM_CDEN_QDCK(data) == 0)
1727 		spd_nvl_insert_key(si, SPD_KEY_DDR5_MRCD_QDCK_EN);
1728 	if (SPD_DDR5_MRDIMM_CDEN_BCK(data) == 0)
1729 		spd_nvl_insert_key(si, SPD_KEY_DDR5_MRCD_BCK_EN);
1730 }
1731 
1732 static void
1733 spd_parse_ddr5_mrdimm_oacen(spd_info_t *si, uint32_t off, uint32_t len,
1734     const char *key)
1735 {
1736 	const uint8_t data = si->si_data[off];
1737 
1738 	if (SPD_DDR5_MRDIMM_CDEN_QACA(data) == 0)
1739 		spd_nvl_insert_key(si, SPD_KEY_DDR5_MRCD_QACA_EN);
1740 	if (SPD_DDR5_MRDIMM_CDEN_QBCA(data) == 0)
1741 		spd_nvl_insert_key(si, SPD_KEY_DDR5_MRCD_QBCA_EN);
1742 	if (SPD_DDR5_MRDIMM_CDEN_QxCS1(data) == 0)
1743 		spd_nvl_insert_key(si, SPD_KEY_DDR5_MRCD_QxCS_EN);
1744 	if (SPD_DDR5_MRDIMM_CDEN_BCS(data) == 0)
1745 		spd_nvl_insert_key(si, SPD_KEY_DDR5_MRCD_BCS_EN);
1746 	if (SPD_DDR5_MRDIMM_CDEN_QCA13(data) == 0)
1747 		spd_nvl_insert_key(si, SPD_KEY_DDR5_MRCD_QxCA13_EN);
1748 	if (SPD_DDR5_MRDIMM_CDEN_QACS(data) == 0)
1749 		spd_nvl_insert_key(si, SPD_KEY_DDR5_MRCD_QACS_EN);
1750 	if (SPD_DDR5_MRDIMM_CDEN_QBCS(data) == 0)
1751 		spd_nvl_insert_key(si, SPD_KEY_DDR5_MRCD_QBCS_EN);
1752 	if (SPD_DDR5_MRDIMM_CDEN_DCS1(data) == 0)
1753 		spd_nvl_insert_key(si, SPD_KEY_DDR5_MRCD_DCS1_EN);
1754 }
1755 
1756 static const spd_value_map_t spd_ddr5_mrcd_ds_map[] = {
1757 	{ SPD_DDR5_MRDIMM_DRV_LIGHT, SPD_DRIVE_LIGHT, false },
1758 	{ SPD_DDR5_MRDIMM_DRV_MODERATE, SPD_DRIVE_MODERATE, false },
1759 	{ SPD_DDR5_MRDIMM_DRV_STRONG, SPD_DRIVE_STRONG, false }
1760 };
1761 
1762 static void
1763 spd_parse_ddr5_mrdimm_qck_drv(spd_info_t *si, uint32_t off, uint32_t len,
1764     const char *key)
1765 {
1766 	const uint8_t data = si->si_data[off];
1767 	const uint8_t qack = SPD_DDR5_MRDIMM_QCK_DRV_QACK(data);
1768 	const uint8_t qbck = SPD_DDR5_MRDIMM_QCK_DRV_QBCK(data);
1769 	const uint8_t qcck = SPD_DDR5_MRDIMM_QCK_DRV_QCCK(data);
1770 	const uint8_t qdck = SPD_DDR5_MRDIMM_QCK_DRV_QDCK(data);
1771 
1772 	spd_insert_map(si, SPD_KEY_DDR5_RCD_QACK_DS, qack, spd_ddr5_mrcd_ds_map,
1773 	    ARRAY_SIZE(spd_ddr5_mrcd_ds_map));
1774 	spd_insert_map(si, SPD_KEY_DDR5_RCD_QBCK_DS, qbck, spd_ddr5_mrcd_ds_map,
1775 	    ARRAY_SIZE(spd_ddr5_mrcd_ds_map));
1776 	spd_insert_map(si, SPD_KEY_DDR5_RCD_QCCK_DS, qcck, spd_ddr5_mrcd_ds_map,
1777 	    ARRAY_SIZE(spd_ddr5_mrcd_ds_map));
1778 	spd_insert_map(si, SPD_KEY_DDR5_RCD_QDCK_DS, qdck, spd_ddr5_mrcd_ds_map,
1779 	    ARRAY_SIZE(spd_ddr5_mrcd_ds_map));
1780 
1781 }
1782 
1783 static const spd_value_map_t spd_ddr5_mrcd_out[] = {
1784 	{ SPD_DDR5_MRDIMM_QCA_DRV_QCS1_OUT_NORM, SPD_MRCD_OUT_NORMAL, false },
1785 	{ SPD_DDR5_MRDIMM_QCA_DRV_QCS1_OUT_DIS, SPD_MRCD_OUT_DISABLED, false },
1786 	{ SPD_DDR5_MRDIMM_QCA_DRV_QCS1_OUT_LOW, SPD_MRCD_OUT_LOW, false }
1787 };
1788 
1789 static void
1790 spd_parse_ddr5_mrdimm_qca_drv(spd_info_t *si, uint32_t off, uint32_t len,
1791     const char *key)
1792 {
1793 	const uint8_t data = si->si_data[off];
1794 	const uint8_t cs = SPD_DDR5_MRDIMM_QCA_DRV_CS(data);
1795 	const uint8_t ca = SPD_DDR5_MRDIMM_QCA_DRV_CA(data);
1796 	const uint8_t out = SPD_DDR5_MRDIMM_QCA_DRV_QCS1_OUT(data);
1797 
1798 	spd_insert_map(si, SPD_KEY_DDR5_MRCD_QxCS_DS, cs, spd_ddr5_mrcd_ds_map,
1799 	    ARRAY_SIZE(spd_ddr5_mrcd_ds_map));
1800 	spd_insert_map(si, SPD_KEY_DDR5_MRCD_CA_DS, ca, spd_ddr5_mrcd_ds_map,
1801 	    ARRAY_SIZE(spd_ddr5_mrcd_ds_map));
1802 	spd_insert_map(si, SPD_KEY_DDR5_MRCD_QxCS_OUT, out, spd_ddr5_mrcd_out,
1803 	    ARRAY_SIZE(spd_ddr5_mrcd_out));
1804 }
1805 
1806 static void
1807 spd_parse_ddr5_mrdimm_db_drv(spd_info_t *si, uint32_t off, uint32_t len,
1808     const char *key)
1809 {
1810 	const uint8_t data = si->si_data[off];
1811 	const uint8_t bck = SPD_DDR5_MRDIMM_DB_DRV_BCK(data);
1812 	const uint8_t bcom = SPD_DDR5_MRDIMM_DB_DRV_BCOM(data);
1813 
1814 	spd_insert_map(si, SPD_KEY_DDR5_MRCD_BCK_DS, bck, spd_ddr5_mrcd_ds_map,
1815 	    ARRAY_SIZE(spd_ddr5_mrcd_ds_map));
1816 	spd_insert_map(si, SPD_KEY_DDR5_MRCD_BCOM_DS, bcom,
1817 	    spd_ddr5_mrcd_ds_map, ARRAY_SIZE(spd_ddr5_mrcd_ds_map));
1818 }
1819 
1820 static const spd_value_map_t spd_ddr5_mrcd_slew_map[] = {
1821 	{ SPD_DDR5_MRDIMM_SLEW_MODERTE, SPD_SLEW_MODERATE, false },
1822 	{ SPD_DDR5_MRDIMM_SLEW_FAST, SPD_SLEW_FAST, false },
1823 	{ SPD_DDR5_MRDIMM_SLEW_SLOW, SPD_SLEW_SLOW, false }
1824 };
1825 
1826 static void
1827 spd_parse_ddr5_mrdimm_qxx_slew(spd_info_t *si, uint32_t off, uint32_t len,
1828     const char *key)
1829 {
1830 	const uint8_t data = si->si_data[off];
1831 	const uint8_t qcs = SPD_DDR5_MRDIMM_QXX_SLEW_QCS(data);
1832 	const uint8_t qca = SPD_DDR5_MRDIMM_QXX_SLEW_QCA(data);
1833 	const uint8_t qck = SPD_DDR5_MRDIMM_QXX_SLEW_QCK(data);
1834 
1835 	spd_insert_map(si, SPD_KEY_DDR5_MRCD_QCK_SLEW, qck,
1836 	    spd_ddr5_mrcd_slew_map, ARRAY_SIZE(spd_ddr5_mrcd_slew_map));
1837 	spd_insert_map(si, SPD_KEY_DDR5_MRCD_QCA_SLEW, qca,
1838 	    spd_ddr5_mrcd_slew_map, ARRAY_SIZE(spd_ddr5_mrcd_slew_map));
1839 	spd_insert_map(si, SPD_KEY_DDR5_MRCD_QCS_SLEW, qcs,
1840 	    spd_ddr5_mrcd_slew_map, ARRAY_SIZE(spd_ddr5_mrcd_slew_map));
1841 }
1842 
1843 static void
1844 spd_parse_ddr5_mrdimm_bxx_slew(spd_info_t *si, uint32_t off, uint32_t len,
1845     const char *key)
1846 {
1847 	const uint8_t data = si->si_data[off];
1848 	const uint8_t bck = SPD_DDR5_MRDIMM_BXX_SLEW_BCK(data);
1849 	const uint8_t bcom = SPD_DDR5_MRDIMM_BXX_SLEW_BCOM(data);
1850 
1851 	spd_insert_map(si, SPD_KEY_DDR5_MRCD_BCK_SLEW, bck,
1852 	    spd_ddr5_mrcd_slew_map, ARRAY_SIZE(spd_ddr5_mrcd_slew_map));
1853 	spd_insert_map(si, SPD_KEY_DDR5_MRCD_BCOM_SLEW, bcom,
1854 	    spd_ddr5_mrcd_slew_map, ARRAY_SIZE(spd_ddr5_mrcd_slew_map));
1855 
1856 }
1857 
1858 static const spd_value_map_t spd_ddr5_mrcd_dca_map[] = {
1859 	{ 0, SPD_MRCD_DCA_CFG_0, false },
1860 	{ 1, SPD_MRCD_DCA_CFG_1, false }
1861 };
1862 
1863 static void
1864 spd_parse_ddr5_mrdimm_dca_cfg(spd_info_t *si, uint32_t off, uint32_t len,
1865     const char *key)
1866 {
1867 	const uint8_t data = si->si_data[off];
1868 	const uint8_t cfg = SPD_DDR5_MRDIMM_DCA_CFG_CFG(data);
1869 
1870 	spd_insert_map(si, SPD_KEY_DDR5_MRCD_DCA_CFG, cfg,
1871 	    spd_ddr5_mrcd_dca_map, ARRAY_SIZE(spd_ddr5_mrcd_dca_map));
1872 }
1873 
1874 static const spd_value_map_t spd_ddr5_mrdimm_irxt_map[] = {
1875 	{ SPD_DDR5_MRDIMM_IRXTYPE_TYPE_UNMATCHED, SPD_MRDIMM_IRXT_UNMATCHED,
1876 	    false },
1877 	{ SPD_DDR5_MRDIMM_IRXTYPE_TYPE_MATCHED, SPD_MRDIMM_IRXT_MATCHED,
1878 	    false }
1879 };
1880 
1881 static void
1882 spd_parse_ddr5_mrdimm_irxtype(spd_info_t *si, uint32_t off, uint32_t len,
1883     const char *key)
1884 {
1885 	const uint8_t data = si->si_data[off];
1886 	const uint8_t irxt = SPD_DDR5_MRDIMM_IRXTYPE_TYPE(data);
1887 
1888 	spd_insert_map(si, SPD_KEY_DDR5_MRDIMM_IRXT, irxt,
1889 	    spd_ddr5_mrdimm_irxt_map, ARRAY_SIZE(spd_ddr5_mrdimm_irxt_map));
1890 }
1891 
1892 static const spd_parse_t spd_ddr5_mrdimm_1v1[] = {
1893 	{ .sp_off = SPD_DDR5_MRDIMM_CDEN,
1894 	    .sp_parse = spd_parse_ddr5_mrdimm_cden },
1895 	{ .sp_off = SPD_DDR5_MRDIMM_OACEN,
1896 	    .sp_parse = spd_parse_ddr5_mrdimm_oacen },
1897 	{ .sp_off = SPD_DDR5_MRDIMM_QCK_DRV,
1898 	    .sp_parse = spd_parse_ddr5_mrdimm_qck_drv },
1899 	{ .sp_off = SPD_DDR5_MRDIMM_QCA_DRV,
1900 	    .sp_parse = spd_parse_ddr5_mrdimm_qca_drv },
1901 	{ .sp_off = SPD_DDR5_MRDIMM_DB_DRV,
1902 	    .sp_parse = spd_parse_ddr5_mrdimm_db_drv },
1903 	{ .sp_off = SPD_DDR5_MRDIMM_QXX_SLEW,
1904 	    .sp_parse = spd_parse_ddr5_mrdimm_qxx_slew },
1905 	{ .sp_off = SPD_DDR5_MRDIMM_BXX_SLEW,
1906 	    .sp_parse = spd_parse_ddr5_mrdimm_bxx_slew },
1907 	{ .sp_off = SPD_DDR5_MRDIMM_DCA_CFG,
1908 	    .sp_parse = spd_parse_ddr5_mrdimm_dca_cfg },
1909 	{ .sp_off = SPD_DDR5_MRDIMM_IRXTYPE,
1910 	    .sp_parse = spd_parse_ddr5_mrdimm_irxtype }
1911 };
1912 
1913 /*
1914  * Annex A.5 DDIMM specific processing.
1915  */
1916 static const spd_value_map_t spd_ddr5_dmb_type_map[] = {
1917 	{ SPD_DDR5_DDIMM_INFO_TYPE_DMB501, SPD_DMB_T_DMB5011, false }
1918 };
1919 
1920 static void
1921 spd_parse_ddr5_ddimm_dmb(spd_info_t *si, uint32_t off, uint32_t len,
1922     const char *key)
1923 {
1924 	ASSERT3U(len, ==, 4);
1925 	const uint8_t type = si->si_data[off + 2];
1926 	if (SPD_DDR5_COM_INFO_PRES(type) == 0)
1927 		return;
1928 
1929 	spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_DMB,
1930 	    SPD_KEY_DEV_DMB_MFG, SPD_KEY_DEV_DMB_MFG_NAME,
1931 	    SPD_KEY_DEV_DMB_REV, SPD_KEY_DEV_DMB_TYPE,
1932 	    spd_ddr5_dmb_type_map, ARRAY_SIZE(spd_ddr5_dmb_type_map));
1933 }
1934 
1935 static const spd_parse_t spd_ddr5_ddimm[] = {
1936 	{ .sp_off = SPD_DDR5_DDIMM_MFG_ID0_DMB, .sp_len = 4,
1937 	    .sp_parse = spd_parse_ddr5_ddimm_dmb },
1938 };
1939 
1940 /*
1941  * Annex A.8 CAMM2 specific processing.
1942  */
1943 static void
1944 spd_parse_ddr5_camm2_ckd0(spd_info_t *si, uint32_t off, uint32_t len,
1945     const char *key)
1946 {
1947 	ASSERT3U(len, ==, 4);
1948 	const uint8_t type = si->si_data[off + 2];
1949 	if (SPD_DDR5_COM_INFO_PRES(type) == 0)
1950 		return;
1951 
1952 	spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_CD_0,
1953 	    SPD_KEY_DEV_CD0_MFG, SPD_KEY_DEV_CD0_MFG_NAME,
1954 	    SPD_KEY_DEV_CD0_REV, SPD_KEY_DEV_CD0_TYPE,
1955 	    spd_ddr5_cd_type_map, ARRAY_SIZE(spd_ddr5_cd_type_map));
1956 }
1957 
1958 static void
1959 spd_parse_ddr5_camm2_ckd1(spd_info_t *si, uint32_t off, uint32_t len,
1960     const char *key)
1961 {
1962 	ASSERT3U(len, ==, 4);
1963 	const uint8_t type = si->si_data[off + 2];
1964 	if (SPD_DDR5_COM_INFO_PRES(type) == 0)
1965 		return;
1966 
1967 	spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_CD_1,
1968 	    SPD_KEY_DEV_CD1_MFG, SPD_KEY_DEV_CD1_MFG_NAME,
1969 	    SPD_KEY_DEV_CD1_REV, SPD_KEY_DEV_CD1_TYPE,
1970 	    spd_ddr5_cd_type_map, ARRAY_SIZE(spd_ddr5_cd_type_map));
1971 }
1972 
1973 static const spd_parse_t spd_ddr5_camm2[] = {
1974 	{ .sp_off = SPD_DDR5_CAMM2_MFG_ID0_CKD0, .sp_len = 4,
1975 	    .sp_parse = spd_parse_ddr5_camm2_ckd0 },
1976 	{ .sp_off = SPD_DDR5_CAMM2_MFG_ID0_CKD1, .sp_len = 4,
1977 	    .sp_parse = spd_parse_ddr5_camm2_ckd1 },
1978 };
1979 
1980 static const spd_parse_t spd_ddr5_camm2_1v1[] = {
1981 	{ .sp_off = SPD_DDR5_CAMM2_CKD_CFG_CKD0,
1982 	    .sp_parse = spd_parse_ddr5_ckd_cfg_ckd0 },
1983 	{ .sp_off = SPD_DDR5_CAMM2_CKD_DRV_CKD0,
1984 	    .sp_parse = spd_parse_ddr5_ckd_drv_ckd0 },
1985 	{ .sp_off = SPD_DDR5_CAMM2_CKD_SLEW_CKD0,
1986 	    .sp_parse = spd_parse_ddr5_ckd_slew_ckd0 },
1987 	{ .sp_off = SPD_DDR5_CAMM2_CKD_CFG_CKD1,
1988 	    .sp_parse = spd_parse_ddr5_ckd_cfg_ckd1 },
1989 	{ .sp_off = SPD_DDR5_CAMM2_CKD_DRV_CKD1,
1990 	    .sp_parse = spd_parse_ddr5_ckd_drv_ckd1 },
1991 	{ .sp_off = SPD_DDR5_CAMM2_CKD_SLEW_CKD1,
1992 	    .sp_parse = spd_parse_ddr5_ckd_slew_ckd1 },
1993 };
1994 
1995 static void
1996 spd_parse_ddr5_camm2_mod_cap(spd_info_t *si, uint32_t off, uint32_t len,
1997     const char *key)
1998 {
1999 	const uint8_t data = si->si_data[off];
2000 	const uint8_t nom = SPD_DDR5_CAMM2_MOD_CAP_VDDQ_NOM(data);
2001 	if (nom == SPD_DDR5_CAMM2_MOD_CAP_VDDQ_NOM_UNSPEC)
2002 		return;
2003 
2004 	if (nom > SPD_DDR5_CAMM2_MOD_CAP_VDDQ_NOM_MAX) {
2005 		spd_nvl_err(si, key, SPD_ERROR_NO_XLATE,
2006 		    "encountered unknown value: 0x%x", nom);
2007 	}
2008 
2009 	uint32_t cap = SPD_DDR5_CAMM2_MOD_CAP_VDDQ_NOM_BASE +
2010 	    (nom - 1) * SPD_DDR5_CAMM2_MOD_CAP_VDDQ_NOM_STEP;
2011 	spd_nvl_insert_u32(si, key, cap);
2012 }
2013 
2014 static const spd_parse_t spd_ddr5_camm2_1v2[] = {
2015 	{ .sp_off = SPD_DDR5_CAMM2_MOD_CAP_VDDQ,
2016 	    .sp_key = SPD_KEY_DDR5_CAMM2_MOD_CAP,
2017 	    .sp_parse = spd_parse_ddr5_camm2_mod_cap }
2018 };
2019 
2020 static void
2021 spd_parse_ddr5_socamm2_vr(spd_info_t *si, uint32_t off, spd_device_t flags,
2022     const char *id_key, const char *id_str_key, const char *rev_key,
2023     const char *src_key)
2024 {
2025 	const uint8_t data = si->si_data[off + 2];
2026 	spd_vr_rail_source_t src = 0;
2027 
2028 	if (!SPD_DDR5_SOCAMM2_SRC_VR_PRES(data))
2029 		return;
2030 
2031 	spd_parse_jedec_id(si, off, 2, id_key);
2032 	spd_parse_jedec_id_str(si, off, 2, id_str_key);
2033 	spd_parse_hex_vers(si, off + 3, 1, rev_key);
2034 	spd_upsert_flag(si, SPD_KEY_DEVS, flags);
2035 
2036 	if (SPD_DDR5_SOCAMM2_SRC_VR_VDDQ(data))
2037 		src |= SPD_VR_SRC_VDDQ;
2038 	if (SPD_DDR5_SOCAMM2_SRC_VR_VDD2(data))
2039 		src |= SPD_VR_SRC_VDD2;
2040 	if (SPD_DDR5_SOCAMM2_SRC_VR_VDD2L(data))
2041 		src |= SPD_VR_SRC_VDD2L;
2042 	if (SPD_DDR5_SOCAMM2_SRC_VR_VDD2H(data))
2043 		src |= SPD_VR_SRC_VDD2H;
2044 	if (SPD_DDR5_SOCAMM2_SRC_VR_VDD1(data))
2045 		src |= SPD_VR_SRC_VDD1;
2046 	spd_nvl_insert_u32(si, src_key, src);
2047 }
2048 
2049 static void
2050 spd_parse_ddr5_socamm_vr0(spd_info_t *si, uint32_t off, uint32_t len,
2051     const char *key)
2052 {
2053 	return (spd_parse_ddr5_socamm2_vr(si, off, SPD_DEVICE_VR_0,
2054 	    SPD_KEY_DEV_VR0_MFG, SPD_KEY_DEV_VR0_MFG_NAME,
2055 	    SPD_KEY_DEV_VR0_REV, SPD_KEY_DEV_VR0_SRC));
2056 }
2057 
2058 static void
2059 spd_parse_ddr5_socamm_vr1(spd_info_t *si, uint32_t off, uint32_t len,
2060     const char *key)
2061 {
2062 	return (spd_parse_ddr5_socamm2_vr(si, off, SPD_DEVICE_VR_1,
2063 	    SPD_KEY_DEV_VR1_MFG, SPD_KEY_DEV_VR1_MFG_NAME,
2064 	    SPD_KEY_DEV_VR1_REV, SPD_KEY_DEV_VR1_SRC));
2065 }
2066 
2067 static void
2068 spd_parse_ddr5_socamm_vr2(spd_info_t *si, uint32_t off, uint32_t len,
2069     const char *key)
2070 {
2071 	return (spd_parse_ddr5_socamm2_vr(si, off, SPD_DEVICE_VR_2,
2072 	    SPD_KEY_DEV_VR2_MFG, SPD_KEY_DEV_VR2_MFG_NAME,
2073 	    SPD_KEY_DEV_VR2_REV, SPD_KEY_DEV_VR2_SRC));
2074 }
2075 
2076 static void
2077 spd_parse_ddr5_socamm_vr3(spd_info_t *si, uint32_t off, uint32_t len,
2078     const char *key)
2079 {
2080 	return (spd_parse_ddr5_socamm2_vr(si, off, SPD_DEVICE_VR_3,
2081 	    SPD_KEY_DEV_VR3_MFG, SPD_KEY_DEV_VR3_MFG_NAME,
2082 	    SPD_KEY_DEV_VR3_REV, SPD_KEY_DEV_VR3_SRC));
2083 }
2084 
2085 static const spd_parse_t spd_ddr5_socamm2[] = {
2086 	{ .sp_off = SPD_DDR5_SOCAMM2_MFG_ID0_VR0, .sp_len = 4,
2087 	    .sp_parse = spd_parse_ddr5_socamm_vr0 },
2088 	{ .sp_off = SPD_DDR5_SOCAMM2_MFG_ID0_VR1, .sp_len = 4,
2089 	    .sp_parse = spd_parse_ddr5_socamm_vr1 },
2090 	{ .sp_off = SPD_DDR5_SOCAMM2_MFG_ID0_VR2, .sp_len = 4,
2091 	    .sp_parse = spd_parse_ddr5_socamm_vr2 },
2092 	{ .sp_off = SPD_DDR5_SOCAMM2_MFG_ID0_VR3, .sp_len = 4,
2093 	    .sp_parse = spd_parse_ddr5_socamm_vr3 }
2094 };
2095 
2096 static void
2097 spd_parse_ddr5_mod_specific(spd_info_t *si)
2098 {
2099 	uint32_t type;
2100 
2101 	if (nvlist_lookup_uint32(si->si_nvl, SPD_KEY_MOD_TYPE, &type) != 0)
2102 		return;
2103 
2104 	switch (type) {
2105 	case SPD_MOD_TYPE_RDIMM:
2106 		spd_parse(si, spd_ddr5_rdimm, ARRAY_SIZE(spd_ddr5_rdimm));
2107 		break;
2108 	case SPD_MOD_TYPE_LRDIMM:
2109 		spd_parse(si, spd_ddr5_lrdimm, ARRAY_SIZE(spd_ddr5_lrdimm));
2110 		break;
2111 	case SPD_MOD_TYPE_UDIMM:
2112 	case SPD_MOD_TYPE_SODIMM:
2113 	case SPD_MOD_TYPE_CUDIMM:
2114 	case SPD_MOD_TYPE_CSODIMM:
2115 		spd_parse(si, spd_ddr5_udimm, ARRAY_SIZE(spd_ddr5_udimm));
2116 		if (SPD_DDR5_SPD_REV_ADD(si->si_data[SPD_DDR5_COM_REV]) >= 1) {
2117 			spd_parse(si, spd_ddr5_udimm_1v1,
2118 			    ARRAY_SIZE(spd_ddr5_udimm_1v1));
2119 		}
2120 		break;
2121 	case SPD_MOD_TYPE_MRDIMM:
2122 		spd_parse(si, spd_ddr5_mrdimm, ARRAY_SIZE(spd_ddr5_mrdimm));
2123 		if (SPD_DDR5_SPD_REV_ADD(si->si_data[SPD_DDR5_COM_REV]) >= 1) {
2124 			spd_parse(si, spd_ddr5_mrdimm_1v1,
2125 			    ARRAY_SIZE(spd_ddr5_mrdimm_1v1));
2126 		}
2127 		break;
2128 	case SPD_MOD_TYPE_DDIMM:
2129 		spd_parse(si, spd_ddr5_ddimm, ARRAY_SIZE(spd_ddr5_ddimm));
2130 		break;
2131 	case SPD_MOD_TYPE_CAMM2:
2132 		spd_parse(si, spd_ddr5_camm2, ARRAY_SIZE(spd_ddr5_camm2));
2133 		/*
2134 		 * CAMM2 defines the following in version 1.1 in the DDR5 SPD
2135 		 * spec that only applies to DDR5 memory. LP5 explicitly does
2136 		 * not define this.
2137 		 */
2138 		if (si->si_dram == SPD_DT_DDR5_SDRAM &&
2139 		    SPD_DDR5_SPD_REV_ADD(si->si_data[SPD_DDR5_COM_REV]) >= 1) {
2140 			spd_parse(si, spd_ddr5_camm2_1v1,
2141 			    ARRAY_SIZE(spd_ddr5_camm2_1v1));
2142 		}
2143 
2144 		/*
2145 		 * However, the capacitance value is defined in the LP5 spec for
2146 		 * both LP5 and DDR5 in version 1.2. DDR5 1.4 doesn't contain
2147 		 * CAMM2 annex 1.2, only 1.1. So we believe LP5 and parse this
2148 		 * for everything.
2149 		 */
2150 		if (SPD_DDR5_SPD_REV_ADD(si->si_data[SPD_DDR5_COM_REV]) >= 2) {
2151 			spd_parse(si, spd_ddr5_camm2_1v2,
2152 			    ARRAY_SIZE(spd_ddr5_camm2_1v2));
2153 		}
2154 		break;
2155 	case SPD_MOD_TYPE_SOCAMM2:
2156 		spd_parse(si, spd_ddr5_socamm2, ARRAY_SIZE(spd_ddr5_socamm2));
2157 		break;
2158 	/*
2159 	 * Soldered DIMMs don't have any data.
2160 	 */
2161 	case SPD_MOD_TYPE_SOLDER:
2162 	default:
2163 		break;
2164 	}
2165 }
2166 
2167 /*
2168  * This is a common entry point for all of the common pieces of DDR5 and LPDDR5.
2169  * They use the same offsets and meanings and therefore this is called by both.
2170  * While strictly speaking LPDDR5 doesn't support all of the different types of
2171  * module types that DDR5 does, we will parse whatever is claimed.
2172  */
2173 void
2174 spd_parse_ddr5_common(spd_info_t *si)
2175 {
2176 	spd_parse(si, spd_ddr5_module, ARRAY_SIZE(spd_ddr5_module));
2177 	spd_parse(si, spd_ddr5_mfg, ARRAY_SIZE(spd_ddr5_mfg));
2178 	spd_parse_ddr5_mod_specific(si);
2179 }
2180 
2181 /*
2182  * DDR5 has two different revisions. One that is present in the base region and
2183  * one that is present in the common module region that covers the
2184  * module-related pieces. We check that both are present and go from there. We
2185  * may want to relax this in the future so that it's easier to just decode a
2186  * subset of this, but for the time being, we require both.
2187  */
2188 void
2189 spd_parse_ddr5(spd_info_t *si)
2190 {
2191 	if (SPD_DDR5_SPD_REV_ENC(si->si_data[SPD_DDR5_SPD_REV]) !=
2192 	    SPD_DDR5_SPD_REV_V1) {
2193 		si->si_error = LIBJEDEC_SPD_UNSUP_REV;
2194 		return;
2195 	}
2196 
2197 	if (si->si_nbytes <= SPD_DDR5_COM_REV) {
2198 		si->si_error = LIBJEDEC_SPD_TOOSHORT;
2199 		return;
2200 	}
2201 
2202 	if (SPD_DDR5_SPD_REV_ENC(si->si_data[SPD_DDR5_COM_REV]) !=
2203 	    SPD_DDR5_SPD_REV_V1) {
2204 		si->si_error = LIBJEDEC_SPD_UNSUP_REV;
2205 		return;
2206 	}
2207 
2208 	spd_parse(si, spd_ddr5_base, ARRAY_SIZE(spd_ddr5_base));
2209 	if (SPD_DDR5_SPD_REV_ADD(si->si_data[SPD_DDR5_SPD_REV]) >= 2)
2210 		spd_parse(si, spd_ddr5_base_1v2, ARRAY_SIZE(spd_ddr5_base_1v2));
2211 	spd_parse_ddr5_common(si);
2212 }
2213