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