xref: /illumos-gate/usr/src/lib/libjedec/common/libjedec_spd_ddr4.c (revision e00bdde3c6d406f40f53f3025defadc22f7ec31a)
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 2023 Oxide Computer Company
14  */
15 
16 /*
17  * DDR4-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_ddr4_nbytes_used_map[] = {
26 	{ SPD_DDR4_NBYTES_USED_UNDEF, 0, true },
27 	{ SPD_DDR4_NBYTES_USED_128, 128, false },
28 	{ SPD_DDR4_NBYTES_USED_256, 256, false },
29 	{ SPD_DDR4_NBYTES_USED_384, 384, false },
30 	{ SPD_DDR4_NBYTES_USED_512, 512, false }
31 };
32 
33 static const spd_value_map_t spd_ddr4_nbytes_total_map[] = {
34 	{ SPD_DDR4_NBYTES_TOTAL_UNDEF, 0, true },
35 	{ SPD_DDR4_NBYTES_TOTAL_256, 256, false },
36 	{ SPD_DDR4_NBYTES_TOTAL_512, 512, false }
37 };
38 
39 static void
40 spd_parse_ddr4_nbytes(spd_info_t *si, uint32_t off, uint32_t len,
41     const char *key)
42 {
43 	const uint8_t data = si->si_data[off];
44 	const uint8_t used = SPD_DDR4_NBYTES_USED(data);
45 	const uint8_t total = SPD_DDR4_NBYTES_TOTAL(data);
46 
47 	spd_insert_map(si, SPD_KEY_NBYTES_USED, used, spd_ddr4_nbytes_used_map,
48 	    ARRAY_SIZE(spd_ddr4_nbytes_used_map));
49 	spd_insert_map(si, SPD_KEY_NBYTES_TOTAL, total,
50 	    spd_ddr4_nbytes_total_map, ARRAY_SIZE(spd_ddr4_nbytes_total_map));
51 
52 	/*
53 	 * Unlike DDR5, there is no specific definition to indicate that the SPD
54 	 * is present or what type of device it is. There is only one standard
55 	 * DDR4 EEPROM, EE1004, so we note that it's here when we process this.
56 	 */
57 	spd_upsert_flag(si, SPD_KEY_DEVS, SPD_DEVICE_SPD);
58 	spd_nvl_insert_u32(si, SPD_KEY_DEV_SPD_TYPE, SPD_SPD_T_EE1004);
59 }
60 
61 /*
62  * DDR4 has a type value that we leave out: SPD_DDR4_MOD_TYPE_TYPE_EXT. The
63  * external type says to look in another register; however, all types in that
64  * register are reserved. So we just let it be flagged as an unknown value right
65  * now. Which is mostly kind of right.
66  */
67 static const spd_value_map_t spd_ddr4_mod_type_map[] = {
68 	{ SPD_DDR4_MOD_TYPE_TYPE_RDIMM, SPD_MOD_TYPE_RDIMM, false },
69 	{ SPD_DDR4_MOD_TYPE_TYPE_UDIMM, SPD_MOD_TYPE_UDIMM, false },
70 	{ SPD_DDR4_MOD_TYPE_TYPE_SODIMM, SPD_MOD_TYPE_SODIMM, false },
71 	{ SPD_DDR4_MOD_TYPE_TYPE_LRDIMM, SPD_MOD_TYPE_LRDIMM, false },
72 	{ SPD_DDR4_MOD_TYPE_TYPE_MINI_RDIMM, SPD_MOD_TYPE_MINI_RDIMM, false },
73 	{ SPD_DDR4_MOD_TYPE_TYPE_MINI_UDIMM, SPD_MOD_TYPE_MINI_UDIMM, false },
74 	{ SPD_DDR4_MOD_TYPE_TYPE_72b_SORDIMM, SPD_MOD_TYPE_72b_SO_RDIMM,
75 	    false },
76 	{ SPD_DDR4_MOD_TYPE_TYPE_72b_SOUDIMM, SPD_MOD_TYPE_72b_SO_UDIMM,
77 	    false },
78 	{ SPD_DDR4_MOD_TYPE_TYPE_16b_SODIMM, SPD_MOD_TYPE_16b_SO_DIMM, false },
79 	{ SPD_DDR4_MOD_TYPE_TYPE_32b_SODIMM, SPD_MOD_TYPE_32b_SO_DIMM, false }
80 };
81 
82 static const spd_value_map_t spd_ddr4_mod_is_hybrid_map[] = {
83 	{ 0, SPD_MOD_NOT_HYBRID, false },
84 	{ 1, SPD_MOD_HYBRID_NVDIMMM, false }
85 };
86 
87 static const spd_value_map_t spd_ddr4_mod_hybrid_map[] = {
88 	{ SPD_DDR4_MOD_TYPE_HYBRID_NVDIMM_NF, SPD_MOD_TYPE_NVDIMM_N, false },
89 	{ SPD_DDR4_MOD_TYPE_HYBRID_NVDIMM_P, SPD_MOD_TYPE_NVDIMM_P, false },
90 	{ SPD_DDR4_MOD_TYPE_HYBRID_NVDIMM_H, SPD_MOD_TYPE_NVDIMM_H, false }
91 };
92 
93 static void
94 spd_parse_ddr4_mod_type(spd_info_t *si, uint32_t off, uint32_t len,
95     const char *key)
96 {
97 	const uint8_t data = si->si_data[off];
98 	const uint8_t type = SPD_DDR4_MOD_TYPE_TYPE(data);
99 	const uint8_t is_hyb = SPD_DDR4_MOD_TYPE_ISHYBRID(data);
100 	const uint8_t hybrid = SPD_DDR4_MOD_TYPE_HYBRID(data);
101 
102 	spd_insert_map(si, SPD_KEY_MOD_HYBRID_TYPE, is_hyb,
103 	    spd_ddr4_mod_is_hybrid_map, ARRAY_SIZE(spd_ddr4_mod_is_hybrid_map));
104 
105 	if (is_hyb != 0) {
106 		spd_insert_map(si, SPD_KEY_MOD_NVDIMM_TYPE, hybrid,
107 		    spd_ddr4_mod_hybrid_map,
108 		    ARRAY_SIZE(spd_ddr4_mod_hybrid_map));
109 	}
110 
111 	spd_insert_map(si, SPD_KEY_MOD_TYPE, type, spd_ddr4_mod_type_map,
112 	    ARRAY_SIZE(spd_ddr4_mod_type_map));
113 }
114 
115 static const spd_value_map64_t spd_ddr4_density_map[] = {
116 	{ SPD_DDR4_DENSITY_DENSITY_256Mb, 256ULL * 1024ULL * 1024ULL, false },
117 	{ SPD_DDR4_DENSITY_DENSITY_512Mb, 512ULL * 1024ULL * 1024ULL, false },
118 	{ SPD_DDR4_DENSITY_DENSITY_1Gb, 1024ULL * 1024ULL * 1024ULL, false },
119 	{ SPD_DDR4_DENSITY_DENSITY_2Gb, 2ULL * 1024ULL * 1024ULL * 1024ULL,
120 	    false },
121 	{ SPD_DDR4_DENSITY_DENSITY_4Gb, 4ULL * 1024ULL * 1024ULL * 1024ULL,
122 	    false },
123 	{ SPD_DDR4_DENSITY_DENSITY_8Gb, 8ULL * 1024ULL * 1024ULL * 1024ULL,
124 	    false },
125 	{ SPD_DDR4_DENSITY_DENSITY_16Gb, 16ULL * 1024ULL * 1024ULL * 1024ULL,
126 	    false },
127 	{ SPD_DDR4_DENSITY_DENSITY_32Gb, 32ULL * 1024ULL * 1024ULL * 1024ULL,
128 	    false },
129 	{ SPD_DDR4_DENSITY_DENSITY_12Gb, 12ULL * 1024ULL * 1024ULL * 1024ULL,
130 	    false },
131 	{ SPD_DDR4_DENSITY_DENSITY_24Gb, 24ULL * 1024ULL * 1024ULL * 1024ULL,
132 	    false },
133 };
134 
135 static const spd_value_range_t spd_ddr4_nbgrp_range = {
136 	.svr_max = SPD_DDR4_DENSITY_NBG_BITS_MAX
137 };
138 
139 static const spd_value_range_t spd_ddr4_nba_range = {
140 	.svr_max = SPD_DDR4_DENSITY_NBA_BITS_MAX,
141 	.svr_base = SPD_DDR4_DENSITY_NBA_BITS_BASE
142 };
143 
144 static void
145 spd_parse_ddr4_density(spd_info_t *si, uint32_t off, uint32_t len,
146     const char *key)
147 {
148 	const uint8_t data = si->si_data[off];
149 	const uint8_t nbg = SPD_DDR4_DENSITY_NBG_BITS(data);
150 	const uint8_t nbank = SPD_DDR4_DENSITY_NBA_BITS(data);
151 	const uint8_t dens = SPD_DDR4_DENSITY_DENSITY(data);
152 
153 	spd_insert_range(si, SPD_KEY_NBGRP_BITS, nbg, &spd_ddr4_nbgrp_range);
154 	spd_insert_range(si, SPD_KEY_NBANK_BITS, nbank, &spd_ddr4_nba_range);
155 	spd_insert_map64(si, SPD_KEY_DIE_SIZE, dens, spd_ddr4_density_map,
156 	    ARRAY_SIZE(spd_ddr4_density_map));
157 }
158 
159 static const spd_value_range_t spd_ddr4_nrow_range = {
160 	.svr_max = SPD_DDR4_ADDR_NROWS_MAX,
161 	.svr_base = SPD_DDR4_ADDR_NROWS_BASE
162 };
163 
164 static const spd_value_range_t spd_ddr4_ncol_range = {
165 	.svr_max = SPD_DDR4_ADDR_NCOLS_MAX,
166 	.svr_base = SPD_DDR4_ADDR_NCOLS_BASE
167 };
168 
169 static void
170 spd_parse_ddr4_addr(spd_info_t *si, uint32_t off, uint32_t len, const char *key)
171 {
172 	const uint8_t data = si->si_data[off];
173 	const uint8_t nrows = SPD_DDR4_ADDR_NROWS(data);
174 	const uint8_t ncols = SPD_DDR4_ADDR_NCOLS(data);
175 
176 	spd_insert_range(si, SPD_KEY_NROW_BITS, nrows, &spd_ddr4_nrow_range);
177 	spd_insert_range(si, SPD_KEY_NCOL_BITS, ncols, &spd_ddr4_ncol_range);
178 }
179 
180 static const spd_value_map_t spd_ddr4_sl_map[] = {
181 	{ SPD_DDR4_PKG_SIG_LOAD_UNSPEC, SPD_SL_UNSPECIFIED, false },
182 	{ SPD_DDR4_PKG_SIG_LOAD_MULTI, SPD_SL_MUTLI_STACK, false },
183 	{ SPD_DDR4_PKG_SIG_LOAD_SINGLE, SPD_SL_3DS, false }
184 };
185 
186 static void
187 spd_parse_ddr4_pkg_common(spd_info_t *si, uint8_t data, const char *die_key,
188     const char *sl_key)
189 {
190 	const uint8_t ndie = SPD_DDR4_PKG_DIE_CNT(data) +
191 	    SPD_DDR4_PKG_DIE_CNT_BASE;
192 	const uint8_t sl = SPD_DDR4_PKG_SIG_LOAD(data);
193 
194 	spd_nvl_insert_u32(si, die_key, ndie);
195 	spd_insert_map(si, sl_key, sl, spd_ddr4_sl_map,
196 	    ARRAY_SIZE(spd_ddr4_sl_map));
197 }
198 
199 static void
200 spd_parse_ddr4_pri_pkg(spd_info_t *si, uint32_t off, uint32_t len,
201     const char *key)
202 {
203 	const uint8_t data = si->si_data[off];
204 	if (SPD_DDR4_PKG_TYPE(data) == SPD_DDR4_PKG_TYPE_NOT) {
205 		spd_nvl_insert_key(si, SPD_KEY_PKG_NOT_MONO);
206 	}
207 
208 	return (spd_parse_ddr4_pkg_common(si, si->si_data[off],
209 	    SPD_KEY_PKG_NDIE, SPD_KEY_PKG_SL));
210 }
211 
212 static void
213 spd_parse_ddr4_sec_pkg(spd_info_t *si, uint32_t off, uint32_t len,
214     const char *key)
215 {
216 	ASSERT3U(off, >=, SPD_DDR4_PRI_PKG);
217 
218 	if (SPD_DDR4_PKG_TYPE(si->si_data[SPD_DDR4_PRI_PKG]) ==
219 	    SPD_DDR4_PKG_TYPE_MONO) {
220 		return;
221 	}
222 
223 	return (spd_parse_ddr4_pkg_common(si, si->si_data[off],
224 	    SPD_KEY_SEC_PKG_NDIE, SPD_KEY_SEC_PKG_SL));
225 }
226 
227 static const spd_value_map_t spd_ddr4_maw_map[] = {
228 	{ SPD_DDR4_OPT_FEAT_MAW_8192X, 8192, false },
229 	{ SPD_DDR4_OPT_FEAT_MAW_4096X, 4096, false },
230 	{ SPD_DDR4_OPT_FEAT_MAW_2048X, 2048, false }
231 };
232 
233 static const spd_value_map_t spd_ddr4_mac_map[] = {
234 	{ SPD_DDR4_OPT_FEAT_MAC_UNTESTED, 0, true},
235 	{ SPD_DDR4_OPT_FEAT_MAC_700K, 700000, false },
236 	{ SPD_DDR4_OPT_FEAT_MAC_600K, 600000, false },
237 	{ SPD_DDR4_OPT_FEAT_MAC_500K, 500000, false },
238 	{ SPD_DDR4_OPT_FEAT_MAC_400K, 400000, false },
239 	{ SPD_DDR4_OPT_FEAT_MAC_300K, 300000, false },
240 	{ SPD_DDR4_OPT_FEAT_MAC_200K, 200000, false },
241 	{ SPD_DDR4_OPT_FEAT_MAC_UNLIMITED, SPD_KEY_DDR4_MAC_UNLIMITED, false }
242 };
243 
244 static void
245 spd_parse_ddr4_feat(spd_info_t *si, uint32_t off, uint32_t len, const char *key)
246 {
247 	const uint8_t data = si->si_data[off];
248 	const uint8_t maw = SPD_DDR4_OPT_FEAT_MAW(data);
249 	const uint8_t mac = SPD_DDR4_OPT_FEAT_MAC(data);
250 
251 	spd_insert_map(si, SPD_KEY_DDR4_MAW, maw, spd_ddr4_maw_map,
252 	    ARRAY_SIZE(spd_ddr4_maw_map));
253 	spd_insert_map(si, SPD_KEY_DDR4_MAC, mac, spd_ddr4_mac_map,
254 	    ARRAY_SIZE(spd_ddr4_mac_map));
255 }
256 
257 static void
258 spd_parse_ddr4_feat2(spd_info_t *si, uint32_t off, uint32_t len,
259     const char *key)
260 {
261 	const uint8_t data = si->si_data[off];
262 	const uint8_t ppr_sup = SPD_DDR4_OPT_FEAT2_PPR(data);
263 	spd_ppr_flags_t flags = 0;
264 
265 	switch (ppr_sup) {
266 	case SPD_DDR4_OPT_FEAT2_PPR_1RPBG:
267 		spd_nvl_insert_u32(si, SPD_KEY_PPR_GRAN,
268 		    SPD_PPR_GRAN_BANK_GROUP);
269 		flags |= SPD_PPR_F_HARD_PPR;
270 		break;
271 	case SPD_DDR4_OPT_FEAT2_PPR_NOTSUP:
272 		/*
273 		 * No PPR, nothing to do.
274 		 */
275 		return;
276 	default:
277 		/*
278 		 * Unknown PPR value.
279 		 */
280 		spd_nvl_err(si, SPD_KEY_PPR, SPD_ERROR_NO_XLATE,
281 		    "encountered unknown value: 0x%x", ppr_sup);
282 		return;
283 	}
284 
285 	if (SPD_DDR4_OPT_FEAT2_SOFT_PPR(data))
286 		flags |= SPD_PPR_F_SOFT_PPR;
287 	if (SPD_DDR4_OPT_FEAT2_MBIST_PPR(data))
288 		flags |= SPD_PPR_F_MBIST_PPR;
289 	spd_nvl_insert_u32(si, SPD_KEY_PPR, flags);
290 }
291 
292 static void
293 spd_parse_ddr4_volt(spd_info_t *si, uint32_t off, uint32_t len, const char *key)
294 {
295 	const uint8_t data = si->si_data[off];
296 	uint32_t volts[] = { 1200 };
297 
298 	if (SPD_DDR4_VOLT_V1P2_OPER(data) == 0)
299 		return;
300 	spd_nvl_insert_u32_array(si, key, volts, ARRAY_SIZE(volts));
301 }
302 
303 static const spd_value_map_t spd_ddr4_dram_width[] = {
304 	{ SPD_DDR4_MOD_ORG_WIDTH_4b, 4, false },
305 	{ SPD_DDR4_MOD_ORG_WIDTH_8b, 8, false },
306 	{ SPD_DDR4_MOD_ORG_WIDTH_16b, 16, false },
307 	{ SPD_DDR4_MOD_ORG_WIDTH_32b, 32, false }
308 };
309 
310 static const spd_value_range_t spd_ddr4_nrank_range = {
311 	.svr_base = SPD_DDR4_MOD_ORG_NPKG_RANK_BASE
312 };
313 
314 static void
315 spd_parse_ddr4_mod_org(spd_info_t *si, uint32_t off, uint32_t len,
316     const char *key)
317 {
318 	const uint8_t data = si->si_data[off];
319 	const uint8_t mix = SPD_DDR4_MOD_ORG_RANK_MIX(data);
320 	const uint8_t nranks = SPD_DDR4_MOD_ORG_NPKG_RANK(data);
321 	const uint8_t width = SPD_DDR4_MOD_ORG_WIDTH(data);
322 
323 	if (mix == SPD_DDR4_MOD_ORG_RANK_MIX_ASYM)
324 		spd_nvl_insert_key(si, SPD_KEY_RANK_ASYM);
325 	spd_insert_range(si, SPD_KEY_NRANKS, nranks, &spd_ddr4_nrank_range);
326 	spd_insert_map(si, SPD_KEY_DRAM_WIDTH, width, spd_ddr4_dram_width,
327 	    ARRAY_SIZE(spd_ddr4_dram_width));
328 }
329 
330 static const spd_value_map_t spd_ddr4_ext_width[] = {
331 	{ SPD_DDR4_MOD_BUS_WIDTH_EXT_NONE, 0, false },
332 	{ SPD_DDR4_MOD_BUS_WIDTH_EXT_8b, 8, false }
333 };
334 
335 static const spd_value_map_t spd_ddr4_pri_width[] = {
336 	{ SPD_DDR4_MOD_BUS_WIDTH_PRI_8b, 8, false },
337 	{ SPD_DDR4_MOD_BUS_WIDTH_PRI_16b, 16, false },
338 	{ SPD_DDR4_MOD_BUS_WIDTH_PRI_32b, 32, false },
339 	{ SPD_DDR4_MOD_BUS_WIDTH_PRI_64b, 64, false },
340 };
341 
342 static void
343 spd_parse_ddr4_bus_width(spd_info_t *si, uint32_t off, uint32_t len,
344     const char *key)
345 {
346 	const uint8_t data = si->si_data[off];
347 	const uint8_t ext = SPD_DDR4_MOD_BUS_WIDTH_EXT(data);
348 	const uint8_t pri = SPD_DDR4_MOD_BUS_WIDTH_PRI(data);
349 
350 	/* Only DDR5 has multiple subchannels */
351 	spd_nvl_insert_u32(si, SPD_KEY_NSUBCHAN, 1);
352 	spd_insert_map(si, SPD_KEY_DATA_WIDTH, pri, spd_ddr4_pri_width,
353 	    ARRAY_SIZE(spd_ddr4_pri_width));
354 	spd_insert_map(si, SPD_KEY_ECC_WIDTH, ext, spd_ddr4_ext_width,
355 	    ARRAY_SIZE(spd_ddr4_ext_width));
356 }
357 
358 static void
359 spd_parse_ddr4_therm(spd_info_t *si, uint32_t off, uint32_t len,
360     const char *key)
361 {
362 	const uint8_t data = si->si_data[off];
363 
364 	if (SPD_DDR4_MOD_THERM_PRES(data) != 0)
365 		spd_upsert_flag(si, key, SPD_DEVICE_TEMP_1);
366 	/*
367 	 * In DDR4, there is only a single standard temperature device. It is
368 	 * often integrated into the EEPROM, but from a JEDEC perspective these
369 	 * each have their own device type.
370 	 */
371 	spd_nvl_insert_u32(si, SPD_KEY_DEV_TEMP_TYPE, SPD_TEMP_T_TSE2004av);
372 }
373 
374 static const spd_value_map_t spd_ddr4_ts_mtb[] = {
375 	{ SPD_DDR4_TIMEBASE_MTB_125ps, SPD_DDR4_MTB_PS, false }
376 };
377 
378 static const spd_value_map_t spd_ddr4_ts_ftb[] = {
379 	{ SPD_DDR4_TIMEBASE_FTB_1ps, SPD_DDR4_FTB_PS, false }
380 };
381 
382 static void
383 spd_parse_ddr4_ts(spd_info_t *si, uint32_t off, uint32_t len,
384     const char *key)
385 {
386 	const uint8_t data = si->si_data[off];
387 	const uint8_t mtb = SPD_DDR4_TIMEBASE_MTB(data);
388 	const uint8_t ftb = SPD_DDR4_TIMEBASE_FTB(data);
389 
390 
391 	spd_insert_map(si, SPD_KEY_MTB, mtb, spd_ddr4_ts_mtb,
392 	    ARRAY_SIZE(spd_ddr4_ts_mtb));
393 	spd_insert_map(si, SPD_KEY_FTB, ftb, spd_ddr4_ts_ftb,
394 	    ARRAY_SIZE(spd_ddr4_ts_ftb));
395 }
396 
397 /*
398  * Calculate a full timestamp from a given number of FTB units and either an
399  * 8-bit, 12-bit, or 16-bit number of MTB units. The FTB units value is actually
400  * a signed two's complement value that we use to adjust things. We need to
401  * check for two illegal values:
402  *
403  * 1. That the value as a whole after adjustment is non-zero.
404  * 2. That the fine adjustment does not cause us to underflow (i.e. unit values
405  *    for the MTB of 1 and the FTB of -126).
406  */
407 static void
408 spd_parse_ddr4_time(spd_info_t *si, const char *key, uint8_t up_nib,
409     uint8_t mtb, uint8_t ftb)
410 {
411 	uint64_t ps = ((up_nib << 4) + mtb) * SPD_DDR4_MTB_PS;
412 	int8_t adj = (int8_t)ftb;
413 
414 	if (ps == 125 && adj <= -125) {
415 		spd_nvl_err(si, key, SPD_ERROR_BAD_DATA,
416 		    "MTB (%" PRIu64 "ps) and FTB (%dps) would cause underflow",
417 		    ps, adj);
418 		return;
419 	}
420 
421 	ps += adj;
422 	if (ps == 0) {
423 		spd_nvl_err(si, key, SPD_ERROR_NO_XLATE,
424 		    "encountered unexpected zero time value");
425 		return;
426 	}
427 	spd_nvl_insert_u64(si, key, ps);
428 }
429 
430 /*
431  * Parse a pair of the MTB and FTB. The MTB is the lower byte in off. The FTB is
432  * at off + len.
433  */
434 static void
435 spd_parse_ddr4_mtb_ftb(spd_info_t *si, uint32_t off, uint32_t len,
436     const char *key)
437 {
438 	return (spd_parse_ddr4_time(si, key, 0, si->si_data[off],
439 	    si->si_data[off + len]));
440 }
441 
442 /*
443  * Parse a pair of values where the MTB is split across two uint8_t's. The LSB
444  * is in off and the MSB is in off+1.
445  */
446 static void
447 spd_parse_ddr4_mtb_pair(spd_info_t *si, uint32_t off, uint32_t len,
448     const char *key)
449 {
450 	ASSERT3U(len, ==, 2);
451 	return (spd_parse_ddr4_time(si, key, si->si_data[off + 1],
452 	    si->si_data[off], 0));
453 }
454 
455 /*
456  * t~RAS~ consists of the upper nibble at off and the MTB at off + 1.
457  */
458 static void
459 spd_parse_ddr4_tras(spd_info_t *si, uint32_t off, uint32_t len,
460     const char *key)
461 {
462 	const uint8_t ras_nib = SPD_DDR4_RAS_RC_UPPER_RAS(si->si_data[off]);
463 	ASSERT3U(len, ==, 2);
464 
465 	return (spd_parse_ddr4_time(si, key, ras_nib, si->si_data[off], 0));
466 }
467 
468 /*
469  * t~RC~ consists of an upper 4-bit nibble at off. Its MTB is at off + 2. The
470  * FTB is at off + len.
471  */
472 static void
473 spd_parse_ddr4_trc(spd_info_t *si, uint32_t off, uint32_t len,
474     const char *key)
475 {
476 	const uint8_t rc_nib = SPD_DDR4_RAS_RC_UPPER_RC(si->si_data[off]);
477 
478 	return (spd_parse_ddr4_time(si, key, rc_nib, si->si_data[off + 2],
479 	    si->si_data[off + len]));
480 }
481 
482 /*
483  * Upper nibble in off, MTB in off + 1, no FTB.
484  */
485 static void
486 spd_parse_ddr4_tfaw(spd_info_t *si, uint32_t off, uint32_t len,
487     const char *key)
488 {
489 	const uint8_t faw_nib = SPD_DDR4_TFAW_UPPER_FAW(si->si_data[off]);
490 	return (spd_parse_ddr4_time(si, key, faw_nib, si->si_data[off + 1], 0));
491 }
492 
493 static void
494 spd_parse_ddr4_twr(spd_info_t *si, uint32_t off, uint32_t len,
495     const char *key)
496 {
497 	const uint8_t twr_nib = SPD_DDR4_TWR_MIN_UPPER_TWR(si->si_data[off]);
498 	return (spd_parse_ddr4_time(si, key, twr_nib, si->si_data[off + 1], 0));
499 }
500 
501 static void
502 spd_parse_ddr4_twtrs(spd_info_t *si, uint32_t off, uint32_t len,
503     const char *key)
504 {
505 	const uint8_t twtrs_nib = SPD_DDR4_TWRT_UPPER_TWRS(si->si_data[off]);
506 	return (spd_parse_ddr4_time(si, key, twtrs_nib, si->si_data[off + 1],
507 	    0));
508 }
509 
510 static void
511 spd_parse_ddr4_twtrl(spd_info_t *si, uint32_t off, uint32_t len,
512     const char *key)
513 {
514 	const uint8_t twtrl_nib = SPD_DDR4_TWRT_UPPER_TWRL(si->si_data[off]);
515 	return (spd_parse_ddr4_time(si, key, twtrl_nib, si->si_data[off + 2],
516 	    0));
517 }
518 
519 static void
520 spd_parse_ddr4_cas(spd_info_t *si, uint32_t off, uint32_t len,
521     const char *key)
522 {
523 	uint32_t cas[32] = { 0 };
524 	uint_t ncas = 0;
525 	uint32_t cas_base;
526 
527 	ASSERT3U(len, ==, 4);
528 	if (SPD_DDR4_CAS_SUP3_RANGE(si->si_data[off + 3]) ==
529 	    SPD_DDR4_CAS_SUP3_RANGE_7) {
530 		cas_base = 7;
531 	} else {
532 		cas_base = 23;
533 	}
534 
535 	for (uint32_t byte = 0; byte < len; byte++) {
536 		uint32_t data = si->si_data[off];
537 		uint32_t nbits = NBBY;
538 
539 		/*
540 		 * The last byte reserves the last two bits.
541 		 */
542 		if (byte == len - 1)
543 			nbits -= 2;
544 
545 		for (uint32_t i = 0; i < nbits; i++) {
546 			if (bitx8(data, i, i) == 1) {
547 				cas[ncas] = cas_base + i + NBBY * byte;
548 				ncas++;
549 			}
550 		}
551 	}
552 
553 	spd_nvl_insert_u32_array(si, key, cas, ncas);
554 }
555 
556 static const uint32_t spd_ddr4_nib_map[0x18][0x4] = {
557 	{ 0, 1, 2, 3 },
558 	{ 0, 1, 3, 2 },
559 	{ 0, 2, 1, 3 },
560 	{ 0, 2, 3, 1 },
561 	{ 0, 3, 1, 2 },
562 	{ 0, 3, 2, 1 },
563 	{ 1, 0, 2, 3 },
564 	{ 1, 0, 3, 2 },
565 	{ 1, 2, 0, 3 },
566 	{ 1, 2, 3, 0 },
567 	{ 1, 3, 0, 2 },
568 	{ 1, 3, 2, 0 },
569 	{ 2, 0, 1, 3 },
570 	{ 2, 0, 3, 1 },
571 	{ 2, 1, 0, 3 },
572 	{ 2, 1, 3, 0 },
573 	{ 2, 3, 0, 1 },
574 	{ 2, 3, 1, 0 },
575 	{ 3, 0, 1, 2 },
576 	{ 3, 0, 2, 1 },
577 	{ 3, 1, 0, 2 },
578 	{ 3, 1, 2, 0 },
579 	{ 3, 2, 0, 1 },
580 	{ 3, 2, 1, 0 }
581 };
582 
583 static void
584 spd_parse_ddr4_nib_map(spd_info_t *si, uint32_t off, uint32_t len,
585     const char *key)
586 {
587 	const uint8_t data = si->si_data[off];
588 	const uint8_t pkg = SPD_DDR4_MAP_PKG(data);
589 	const uint8_t nib = SPD_DDR4_MAP_NIBBLE(data);
590 	uint8_t idx = SPD_DDR4_MAP_IDX(data);
591 	uint32_t bits[4];
592 
593 	/*
594 	 * Because there is only a single legal value we don't make a specific
595 	 * nvlist key for it; however, if it is incorrect we will complain about
596 	 * it!
597 	 */
598 	if (pkg != SPD_DDR4_MAP_PKG_FLIP) {
599 		spd_nvl_err(si, key, SPD_ERROR_NO_XLATE,
600 		    "encountered bad package value: 0x%x", pkg);
601 	}
602 
603 	if (idx == SPD_DDR4_MAP_IDX_UNSPEC)
604 		return;
605 	idx--;
606 
607 	if (idx >= ARRAY_SIZE(spd_ddr4_nib_map)) {
608 		spd_nvl_err(si, key, SPD_ERROR_NO_XLATE,
609 		    "encountered bad nibble mapping value: 0x%x", idx);
610 		return;
611 	}
612 
613 	if (nib == 1) {
614 		bits[0] = spd_ddr4_nib_map[idx][0] + 4;
615 		bits[1] = spd_ddr4_nib_map[idx][1] + 4;
616 		bits[2] = spd_ddr4_nib_map[idx][2] + 4;
617 		bits[3] = spd_ddr4_nib_map[idx][3] + 4;
618 	} else {
619 		bits[0] = spd_ddr4_nib_map[idx][0];
620 		bits[1] = spd_ddr4_nib_map[idx][1];
621 		bits[2] = spd_ddr4_nib_map[idx][2];
622 		bits[3] = spd_ddr4_nib_map[idx][3];
623 	};
624 
625 	spd_nvl_insert_u32_array(si, key, bits, ARRAY_SIZE(bits));
626 }
627 
628 static const spd_parse_t spd_ddr4_common[] = {
629 	{ .sp_off = SPD_DDR4_NBYTES, .sp_parse = spd_parse_ddr4_nbytes },
630 	{ .sp_off = SPD_DDR4_SPD_REV, .sp_parse = spd_parse_rev },
631 	/*
632 	 * We have previously validated that the DRAM type is something that we
633 	 * understand. We pass through the raw enum to users here.
634 	 */
635 	{ .sp_off = SPD_DDR4_DRAM_TYPE, .sp_key = SPD_KEY_DRAM_TYPE,
636 	    .sp_parse = spd_parse_raw_u8 },
637 	{ .sp_off = SPD_DDR4_MOD_TYPE, .sp_parse = spd_parse_ddr4_mod_type },
638 	{ .sp_off = SPD_DDR4_DENSITY, .sp_parse = spd_parse_ddr4_density },
639 	{ .sp_off = SPD_DDR4_ADDR, .sp_parse = spd_parse_ddr4_addr },
640 	{ .sp_off = SPD_DDR4_PRI_PKG, .sp_parse = spd_parse_ddr4_pri_pkg },
641 	{ .sp_off = SPD_DDR4_SEC_PKG, .sp_parse = spd_parse_ddr4_sec_pkg },
642 	{ .sp_off = SPD_DDR4_OPT_FEAT, .sp_parse = spd_parse_ddr4_feat },
643 	{ .sp_off = SPD_DDR4_OPT_FEAT2, .sp_parse = spd_parse_ddr4_feat2 },
644 	{ .sp_off = SPD_DDR4_VOLT, .sp_key = SPD_KEY_NOM_VDD,
645 	    .sp_parse = spd_parse_ddr4_volt },
646 	{ .sp_off = SPD_DDR4_MOD_ORG, .sp_parse = spd_parse_ddr4_mod_org },
647 	{ .sp_off = SPD_DDR4_MOD_BUS_WIDTH,
648 	    .sp_parse = spd_parse_ddr4_bus_width },
649 	{ .sp_off = SPD_DDR4_MOD_THERM, .sp_key = SPD_KEY_DEVS,
650 	    .sp_parse = spd_parse_ddr4_therm },
651 	/*
652 	 * Because there is only one set of valid time bases, we assume that
653 	 * as part of the rest of the time construction.
654 	 */
655 	{ .sp_off = SPD_DDR4_TIMEBASE, .sp_parse = spd_parse_ddr4_ts },
656 	{ .sp_off = SPD_DDR4_TCKAVG_MIN, .sp_key = SPD_KEY_TCKAVG_MIN,
657 	    .sp_len = SPD_DDR4_TCKAVG_MIN_FINE - SPD_DDR4_TCKAVG_MIN + 1,
658 	    .sp_parse = spd_parse_ddr4_mtb_ftb },
659 	{ .sp_off = SPD_DDR4_TCKAVG_MAX, .sp_key = SPD_KEY_TCKAVG_MAX,
660 	    .sp_len = SPD_DDR4_TCKAVG_MAX_FINE - SPD_DDR4_TCKAVG_MAX + 1,
661 	    .sp_parse = spd_parse_ddr4_mtb_ftb },
662 	{ .sp_off = SPD_DDR4_CAS_SUP0, .sp_key = SPD_KEY_CAS,
663 	    .sp_len = SPD_DDR4_CAS_SUP3 - SPD_DDR4_CAS_SUP0 + 1,
664 	    .sp_parse = spd_parse_ddr4_cas },
665 	{ .sp_off = SPD_DDR4_TAA_MIN, .sp_key = SPD_KEY_TAA_MIN,
666 	    .sp_len = SPD_DDR4_TAA_MIN_FINE - SPD_DDR4_TAA_MIN + 1,
667 	    .sp_parse = spd_parse_ddr4_mtb_ftb },
668 	{ .sp_off = SPD_DDR4_TRCD_MIN, .sp_key = SPD_KEY_TRCD_MIN,
669 	    .sp_len = SPD_DDR4_TRCD_MIN_FINE - SPD_DDR4_TRCD_MIN + 1,
670 	    .sp_parse = spd_parse_ddr4_mtb_ftb },
671 	{ .sp_off = SPD_DDR4_TRP_MIN, .sp_key = SPD_KEY_TRP_MIN,
672 	    .sp_len = SPD_DDR4_TRP_MIN_FINE - SPD_DDR4_TRP_MIN + 1,
673 	    .sp_parse = spd_parse_ddr4_mtb_ftb },
674 	{ .sp_off = SPD_DDR4_RAS_RC_UPPER, .sp_len = 2,
675 	    .sp_key = SPD_KEY_TRAS_MIN, .sp_parse = spd_parse_ddr4_tras },
676 	{ .sp_off = SPD_DDR4_RAS_RC_UPPER, .sp_key = SPD_KEY_TRC_MIN,
677 	    .sp_len = SPD_DDR4_TRC_MIN_FINE - SPD_DDR4_RAS_RC_UPPER + 1,
678 	    .sp_parse = spd_parse_ddr4_trc },
679 	{ .sp_off = SPD_DDR4_TRFC1_MIN_LSB, .sp_len = 2,
680 	    .sp_key = SPD_KEY_TRFC1_MIN, .sp_parse = spd_parse_ddr4_mtb_pair },
681 	{ .sp_off = SPD_DDR4_TRFC2_MIN_LSB, .sp_len = 2,
682 	    .sp_key = SPD_KEY_TRFC2_MIN, .sp_parse = spd_parse_ddr4_mtb_pair },
683 	{ .sp_off = SPD_DDR4_TRFC4_MIN_LSB, .sp_len = 2,
684 	    .sp_key = SPD_KEY_TRFC4_MIN, .sp_parse = spd_parse_ddr4_mtb_pair },
685 	{ .sp_off = SPD_DDR4_TFAW_UPPER, .sp_len = 2, .sp_key = SPD_KEY_TFAW,
686 	    .sp_parse = spd_parse_ddr4_tfaw },
687 	{ .sp_off = SPD_DDR4_TRRDS_MIN, .sp_key = SPD_KEY_TRRD_S_MIN,
688 	    .sp_len = SPD_DDR4_TRRDS_MIN_FINE - SPD_DDR4_TRRDS_MIN + 1,
689 	    .sp_parse = spd_parse_ddr4_mtb_ftb },
690 	{ .sp_off = SPD_DDR4_TRRDL_MIN, .sp_key = SPD_KEY_TRRD_L_MIN,
691 	    .sp_len = SPD_DDR4_TRRDL_MIN_FINE - SPD_DDR4_TRRDL_MIN + 1,
692 	    .sp_parse = spd_parse_ddr4_mtb_ftb },
693 	{ .sp_off = SPD_DDR4_TCCDL_MIN, .sp_key = SPD_KEY_TCCD_L_MIN,
694 	    .sp_len = SPD_DDR4_TCCDL_MIN_FINE - SPD_DDR4_TCCDL_MIN + 1,
695 	    .sp_parse = spd_parse_ddr4_mtb_ftb },
696 	{ .sp_off = SPD_DDR4_TWR_MIN_UPPER, .sp_len = 2,
697 	    .sp_key = SPD_KEY_TWR_MIN, .sp_parse = spd_parse_ddr4_twr },
698 	{ .sp_off = SPD_DDR4_TWRT_UPPER, .sp_len = 2,
699 	    .sp_key = SPD_KEY_TWTRS_MIN, .sp_parse = spd_parse_ddr4_twtrs },
700 	{ .sp_off = SPD_DDR4_TWRT_UPPER, .sp_len = 3,
701 	    .sp_key = SPD_KEY_TWTRL_MIN, .sp_parse = spd_parse_ddr4_twtrl },
702 	{ .sp_off = SPD_DDR4_MAP_DQ0, .sp_key = SPD_KEY_DDR4_MAP_DQ0,
703 	    .sp_parse = spd_parse_ddr4_nib_map },
704 	{ .sp_off = SPD_DDR4_MAP_DQ4, .sp_key = SPD_KEY_DDR4_MAP_DQ4,
705 	    .sp_parse = spd_parse_ddr4_nib_map },
706 	{ .sp_off = SPD_DDR4_MAP_DQ8, .sp_key = SPD_KEY_DDR4_MAP_DQ8,
707 	    .sp_parse = spd_parse_ddr4_nib_map },
708 	{ .sp_off = SPD_DDR4_MAP_DQ12, .sp_key = SPD_KEY_DDR4_MAP_DQ12,
709 	    .sp_parse = spd_parse_ddr4_nib_map },
710 	{ .sp_off = SPD_DDR4_MAP_DQ16, .sp_key = SPD_KEY_DDR4_MAP_DQ16,
711 	    .sp_parse = spd_parse_ddr4_nib_map },
712 	{ .sp_off = SPD_DDR4_MAP_DQ20, .sp_key = SPD_KEY_DDR4_MAP_DQ20,
713 	    .sp_parse = spd_parse_ddr4_nib_map },
714 	{ .sp_off = SPD_DDR4_MAP_DQ24, .sp_key = SPD_KEY_DDR4_MAP_DQ24,
715 	    .sp_parse = spd_parse_ddr4_nib_map },
716 	{ .sp_off = SPD_DDR4_MAP_DQ28, .sp_key = SPD_KEY_DDR4_MAP_DQ28,
717 	    .sp_parse = spd_parse_ddr4_nib_map },
718 	{ .sp_off = SPD_DDR4_MAP_CB0, .sp_key = SPD_KEY_DDR4_MAP_CB0,
719 	    .sp_parse = spd_parse_ddr4_nib_map },
720 	{ .sp_off = SPD_DDR4_MAP_CB4, .sp_key = SPD_KEY_DDR4_MAP_CB4,
721 	    .sp_parse = spd_parse_ddr4_nib_map },
722 	{ .sp_off = SPD_DDR4_MAP_DQ32, .sp_key = SPD_KEY_DDR4_MAP_DQ32,
723 	    .sp_parse = spd_parse_ddr4_nib_map },
724 	{ .sp_off = SPD_DDR4_MAP_DQ36, .sp_key = SPD_KEY_DDR4_MAP_DQ36,
725 	    .sp_parse = spd_parse_ddr4_nib_map },
726 	{ .sp_off = SPD_DDR4_MAP_DQ40, .sp_key = SPD_KEY_DDR4_MAP_DQ40,
727 	    .sp_parse = spd_parse_ddr4_nib_map },
728 	{ .sp_off = SPD_DDR4_MAP_DQ44, .sp_key = SPD_KEY_DDR4_MAP_DQ44,
729 	    .sp_parse = spd_parse_ddr4_nib_map },
730 	{ .sp_off = SPD_DDR4_MAP_DQ48, .sp_key = SPD_KEY_DDR4_MAP_DQ48,
731 	    .sp_parse = spd_parse_ddr4_nib_map },
732 	{ .sp_off = SPD_DDR4_MAP_DQ52, .sp_key = SPD_KEY_DDR4_MAP_DQ52,
733 	    .sp_parse = spd_parse_ddr4_nib_map },
734 	{ .sp_off = SPD_DDR4_MAP_DQ56, .sp_key = SPD_KEY_DDR4_MAP_DQ56,
735 	    .sp_parse = spd_parse_ddr4_nib_map },
736 	{ .sp_off = SPD_DDR4_MAP_DQ60, .sp_key = SPD_KEY_DDR4_MAP_DQ60,
737 	    .sp_parse = spd_parse_ddr4_nib_map },
738 	{ .sp_len = SPD_DDR4_CRC_MSB + 1, .sp_key = SPD_KEY_CRC_DDR4_BASE,
739 	    .sp_parse = spd_parse_crc },
740 };
741 
742 static const spd_parse_t spd_ddr4_mfg[] = {
743 	{ .sp_off = SPD_DDR4_MOD_MFG_ID0, .sp_len = 2,
744 	    .sp_key = SPD_KEY_MFG_MOD_MFG_ID,
745 	    .sp_parse = spd_parse_jedec_id },
746 	{ .sp_off = SPD_DDR4_MOD_MFG_ID0, .sp_len = 2,
747 	    .sp_key = SPD_KEY_MFG_MOD_MFG_NAME,
748 	    .sp_parse = spd_parse_jedec_id_str },
749 	{ .sp_off = SPD_DDR4_DRAM_MFG_ID0, .sp_len = 2,
750 	    .sp_key = SPD_KEY_MFG_DRAM_MFG_ID,
751 	    .sp_parse = spd_parse_jedec_id },
752 	{ .sp_off = SPD_DDR4_DRAM_MFG_ID0, .sp_len = 2,
753 	    .sp_key = SPD_KEY_MFG_DRAM_MFG_NAME,
754 	    .sp_parse = spd_parse_jedec_id_str },
755 	{ .sp_off = SPD_DDR4_MOD_MFG_LOC, .sp_key = SPD_KEY_MFG_MOD_LOC_ID,
756 	    .sp_parse = spd_parse_raw_u8 },
757 	{ .sp_off = SPD_DDR4_MOD_MFG_YEAR, .sp_key = SPD_KEY_MFG_MOD_YEAR,
758 	    .sp_parse = spd_parse_hex_string },
759 	{ .sp_off = SPD_DDR4_MOD_MFG_WEEK, .sp_key = SPD_KEY_MFG_MOD_WEEK,
760 	    .sp_parse = spd_parse_hex_string },
761 	{ .sp_off = SPD_DDR4_MOD_SN, .sp_len = SPD_DDR4_MOD_SN_LEN,
762 	    .sp_key = SPD_KEY_MFG_MOD_SN, .sp_parse = spd_parse_hex_string },
763 	{ .sp_off = SPD_DDR4_MOD_PN, .sp_len = SPD_DDR4_MOD_PN_LEN,
764 	    .sp_key = SPD_KEY_MFG_MOD_PN, .sp_parse = spd_parse_string },
765 	{ .sp_off = SPD_DDR4_MOD_REV, .sp_key = SPD_KEY_MFG_MOD_REV,
766 	    .sp_parse = spd_parse_dram_step },
767 	{ .sp_off = SPD_DDR4_DRAM_STEP, .sp_key = SPD_KEY_MFG_DRAM_STEP,
768 	    .sp_parse = spd_parse_dram_step },
769 };
770 
771 static const spd_str_map_t spd_ddr4_design_map0[] = {
772 	{ 0, "A", false },
773 	{ 1, "B", false },
774 	{ 2, "C", false },
775 	{ 3, "D", false },
776 	{ 4, "E", false },
777 	{ 5, "F", false },
778 	{ 6, "G", false },
779 	{ 7, "H", false },
780 	{ 8, "J", false },
781 	{ 9, "K", false },
782 	{ 10, "L", false },
783 	{ 11, "M", false },
784 	{ 12, "N", false },
785 	{ 13, "P", false },
786 	{ 14, "R", false },
787 	{ 15, "T", false },
788 	{ 16, "U", false },
789 	{ 17, "V", false },
790 	{ 18, "W", false },
791 	{ 19, "Y", false },
792 	{ 20, "AA", false },
793 	{ 21, "AB", false },
794 	{ 22, "AC", false },
795 	{ 23, "AD", false },
796 	{ 24, "AE", false },
797 	{ 25, "AF", false },
798 	{ 26, "AG", false },
799 	{ 27, "AH", false },
800 	{ 28, "AJ", false },
801 	{ 29, "AK", false },
802 	{ 30, "AL", false },
803 	{ 31, "ZZ", false }
804 };
805 
806 static const spd_str_map_t spd_ddr4_design_map1[] = {
807 	{ 0, "AM", false },
808 	{ 1, "AN", false },
809 	{ 2, "AP", false },
810 	{ 3, "AR", false },
811 	{ 4, "AT", false },
812 	{ 5, "AU", false },
813 	{ 6, "AV", false },
814 	{ 7, "AW", false },
815 	{ 8, "AY", false },
816 	{ 9, "BA", false },
817 	{ 10, "BB", false },
818 	{ 11, "BC", false },
819 	{ 12, "BD", false },
820 	{ 13, "BE", false },
821 	{ 14, "BF", false },
822 	{ 15, "BG", false },
823 	{ 16, "BH", false },
824 	{ 17, "BJ", false },
825 	{ 18, "BK", false },
826 	{ 19, "BL", false },
827 	{ 20, "BM", false },
828 	{ 21, "BN", false },
829 	{ 22, "BP", false },
830 	{ 23, "BR", false },
831 	{ 24, "BT", false },
832 	{ 25, "BU", false },
833 	{ 26, "BV", false },
834 	{ 27, "BW", false },
835 	{ 28, "BY", false },
836 	{ 29, "CA", false },
837 	{ 30, "CB", false },
838 	{ 31, "ZZ", false }
839 };
840 
841 static void
842 spd_parse_ddr4_design(spd_info_t *si, uint32_t off, uint32_t len,
843     const char *key)
844 {
845 	const uint8_t data = si->si_data[off];
846 	const uint8_t rev = SPD_DDR4_RDIMM_REF_REV(data);
847 	const uint8_t card = SPD_DDR4_RDIMM_REF_CARD(data);
848 
849 	if (SPD_DDR4_RDIMM_REF_EXT(data) != 0) {
850 		spd_insert_str_map(si, SPD_KEY_MOD_REF_DESIGN, card,
851 		    spd_ddr4_design_map1, ARRAY_SIZE(spd_ddr4_design_map1));
852 	} else {
853 		spd_insert_str_map(si, SPD_KEY_MOD_REF_DESIGN, card,
854 		    spd_ddr4_design_map0, ARRAY_SIZE(spd_ddr4_design_map0));
855 	}
856 
857 	/*
858 	 * The DDR4 design rev is split between here and the height field. If we
859 	 * have the value of three, then we must also add in the height's value
860 	 * to this.
861 	 */
862 	if (rev == SPD_DDR4_RDIMM_REV_USE_HEIGHT) {
863 		ASSERT3U(off, >=, SPD_DDR4_RDIMM_HEIGHT);
864 		const uint8_t height = si->si_data[SPD_DDR4_RDIMM_HEIGHT];
865 		const uint8_t hrev = SPD_DDR4_RDIMM_HEIGHT_REV(height);
866 		spd_nvl_insert_u32(si, SPD_KEY_MOD_DESIGN_REV, rev + hrev);
867 	} else {
868 		spd_nvl_insert_u32(si, SPD_KEY_MOD_DESIGN_REV, rev);
869 	}
870 }
871 
872 static void
873 spd_parse_ddr4_edge(spd_info_t *si, uint32_t off, uint32_t len,
874     const char *key)
875 {
876 	const uint8_t data = si->si_data[off];
877 
878 	if (SPD_DDR4_RDIMM_MAP_R1(data) != 0)
879 		spd_nvl_insert_key(si, SPD_KEY_DDR4_MIRROR);
880 }
881 
882 /*
883  * DDR4 UDIMM specific processing.
884  */
885 static const spd_parse_t spd_ddr4_udimm[] = {
886 	{ .sp_off = SPD_DDR4_UDIMM_HEIGHT, .sp_key = SPD_KEY_MOD_HEIGHT,
887 	    .sp_parse = spd_parse_height },
888 	{ .sp_off = SPD_DDR4_UDIMM_THICK, .sp_parse = spd_parse_thickness },
889 	{ .sp_off = SPD_DDR4_UDIMM_REF, .sp_parse = spd_parse_ddr4_design },
890 	{ .sp_off = SPD_DDR4_UDIMM_MAP, .sp_parse = spd_parse_ddr4_edge }
891 };
892 
893 /*
894  * DDR4 RDIMM specific processing.
895  */
896 static const spd_value_map_t spd_ddr4_rcd_type_map[] = {
897 	{ SPD_DDR4_RDIMM_ATTR_TYPE_RCD01, SPD_RCD_T_DDR4RCD01, false },
898 	{ SPD_DDR4_RDIMM_ATTR_TYPE_RCD02, SPD_RCD_T_DDR4RCD02, false },
899 };
900 
901 static void
902 spd_parse_ddr4_rdimm_attr(spd_info_t *si, uint32_t off, uint32_t len,
903     const char *key)
904 {
905 	const uint8_t data = si->si_data[off];
906 	const uint8_t rcd = SPD_DDR4_RDIMM_ATTR_TYPE(data);
907 	const uint8_t nrow = 1 << (SPD_DDR4_RDIMM_ATTR_NROWS(data) - 1);
908 	const uint8_t nreg = 1 << (SPD_DDR4_RDIMM_ATTR_NREGS(data) - 1);
909 
910 	spd_upsert_flag(si, SPD_KEY_DEVS, SPD_DEVICE_RCD);
911 	spd_insert_map(si, SPD_KEY_DEV_RCD_TYPE, rcd,
912 	    spd_ddr4_rcd_type_map, ARRAY_SIZE(spd_ddr4_rcd_type_map));
913 	if (nrow != 0)
914 		spd_nvl_insert_u32(si, SPD_KEY_MOD_NROWS, nrow);
915 	if (nreg != 0)
916 		spd_nvl_insert_u32(si, SPD_KEY_MOD_NREGS, nreg);
917 }
918 
919 static void
920 spd_parse_ddr4_rdimm_therm(spd_info_t *si, uint32_t off, uint32_t len,
921     const char *key)
922 {
923 	const uint8_t data = si->si_data[off];
924 
925 	if (SPD_DDR4_RDIMM_THERM_IMPL(data) != 0)
926 		spd_upsert_flag(si, SPD_KEY_DEVS, SPD_DEVICE_HS);
927 }
928 
929 static void
930 spd_parse_ddr4_rdimm_rcd_mfg(spd_info_t *si, uint32_t off, uint32_t len,
931     const char *key)
932 {
933 	ASSERT3U(len, ==, 2);
934 
935 	spd_parse_jedec_id(si, off, 2, SPD_KEY_DEV_RCD_MFG);
936 	spd_parse_jedec_id_str(si, off, 2, SPD_KEY_DEV_RCD_MFG_NAME);
937 }
938 
939 static const spd_value_map_t spd_ddr4_rdimm_ods_map[] = {
940 	{ SPD_DDR4_RDIMM_ODS0_LIGHT, SPD_DRIVE_LIGHT, false },
941 	{ SPD_DDR4_RDIMM_ODS0_MODERATE, SPD_DRIVE_MODERATE, false },
942 	{ SPD_DDR4_RDIMM_ODS0_STRONG, SPD_DRIVE_STRONG, false },
943 	{ SPD_DDR4_RDIMM_ODS0_VERY_STRONG, SPD_DRIVE_VERY_STRONG, false },
944 };
945 
946 static void
947 spd_parse_ddr4_rdimm_ods(spd_info_t *si, uint32_t off, uint32_t len,
948     const char *key)
949 {
950 	const uint8_t ods0 = si->si_data[off];
951 	const uint8_t ods1 = si->si_data[off + 1];
952 	const uint8_t cs = SPD_DDR4_RDIMM_ODS0_CS(ods0);
953 	const uint8_t ca = SPD_DDR4_RDIMM_ODS0_CA(ods0);
954 	const uint8_t odt = SPD_DDR4_RDIMM_ODS0_ODT(ods0);
955 	const uint8_t cke = SPD_DDR4_RDIMM_ODS0_CKE(ods0);
956 	const uint8_t y1 = SPD_DDR4_RDIMM_ODS1_Y1(ods1);
957 	const uint8_t y0 = SPD_DDR4_RDIMM_ODS1_Y0(ods1);
958 
959 	spd_insert_map(si, SPD_KEY_DDR4_RCD_DS_CKE, cke, spd_ddr4_rdimm_ods_map,
960 	    ARRAY_SIZE(spd_ddr4_rdimm_ods_map));
961 	spd_insert_map(si, SPD_KEY_DDR4_RCD_DS_ODT, odt, spd_ddr4_rdimm_ods_map,
962 	    ARRAY_SIZE(spd_ddr4_rdimm_ods_map));
963 	spd_insert_map(si, SPD_KEY_DDR4_RCD_DS_CA, ca, spd_ddr4_rdimm_ods_map,
964 	    ARRAY_SIZE(spd_ddr4_rdimm_ods_map));
965 	spd_insert_map(si, SPD_KEY_DDR4_RCD_DS_CS, cs, spd_ddr4_rdimm_ods_map,
966 	    ARRAY_SIZE(spd_ddr4_rdimm_ods_map));
967 	spd_insert_map(si, SPD_KEY_DDR4_RCD_DS_Y0, y0, spd_ddr4_rdimm_ods_map,
968 	    ARRAY_SIZE(spd_ddr4_rdimm_ods_map));
969 	spd_insert_map(si, SPD_KEY_DDR4_RCD_DS_Y1, y1, spd_ddr4_rdimm_ods_map,
970 	    ARRAY_SIZE(spd_ddr4_rdimm_ods_map));
971 
972 	if (SPD_DDR4_RDIMM_ODS1_SLEW_SUP(ods1) != 0)
973 		spd_nvl_insert_key(si, SPD_KEY_DDR4_RCD_SLEW);
974 }
975 
976 static const spd_parse_t spd_ddr4_rdimm[] = {
977 	{ .sp_off = SPD_DDR4_RDIMM_HEIGHT, .sp_key = SPD_KEY_MOD_HEIGHT,
978 	    .sp_parse = spd_parse_height },
979 	{ .sp_off = SPD_DDR4_RDIMM_THICK, .sp_parse = spd_parse_thickness },
980 	{ .sp_off = SPD_DDR4_RDIMM_REF, .sp_parse = spd_parse_ddr4_design },
981 	{ .sp_off = SPD_DDR4_RDIMM_ATTR,
982 	    .sp_parse = spd_parse_ddr4_rdimm_attr },
983 	{ .sp_off = SPD_DDR4_RDIMM_THERM,
984 	    .sp_parse = spd_parse_ddr4_rdimm_therm },
985 	{ .sp_off = SPD_DDR4_RDIMM_REG_MFG_ID0, .sp_len = 2,
986 	    .sp_parse = spd_parse_ddr4_rdimm_rcd_mfg },
987 	{ .sp_off = SPD_DDR4_RDIMM_REV, .sp_key = SPD_KEY_DEV_RCD_REV,
988 	    .sp_parse = spd_parse_dram_step },
989 	{ .sp_off = SPD_DDR4_RDIMM_MAP, .sp_parse = spd_parse_ddr4_edge },
990 	{ .sp_off = SPD_DDR4_RDIMM_ODS0, .sp_len = 2,
991 	    .sp_parse = spd_parse_ddr4_rdimm_ods },
992 	{ .sp_off = SPD_DDR4_BLK1_CRC_START, .sp_len = SPD_DDR4_BLK1_CRC_MSB +
993 		1 - SPD_DDR4_BLK1_CRC_START, .sp_key = SPD_KEY_CRC_DDR4_BLK1,
994 	    .sp_parse = spd_parse_crc },
995 };
996 
997 /*
998  * DDR4 LRDIMM specific processing.
999  */
1000 static const spd_value_map_t spd_ddr4_db_type_map[] = {
1001 	{ SPD_DDR4_LRDIMM_ATTR_TYPE_RCD01_DB01, SPD_RCD_T_DDR4RCD01, false },
1002 	{ SPD_DDR4_LRDIMM_ATTR_TYPE_RCD02_DB02, SPD_RCD_T_DDR4RCD02, false },
1003 };
1004 
1005 /*
1006  * We use value maps for these LRDIMM properties because they're a bit
1007  * inconsistent and this gets us out of a lot of if statements. The RDIMM code
1008  * doesn't have this problem because all of the values are valid.
1009  */
1010 static const spd_value_map_t spd_ddr4_lrdimm_nrows_map[] = {
1011 	{ 0, 0, true },
1012 	{ 1, 1, false },
1013 	{ 2, 2, false }
1014 };
1015 
1016 static const spd_value_map_t spd_ddr4_lrdimm_nregs_map[] = {
1017 	{ 0, 0, true },
1018 	{ 1, 1, false }
1019 };
1020 
1021 static void
1022 spd_parse_ddr4_lrdimm_attr(spd_info_t *si, uint32_t off, uint32_t len,
1023     const char *key)
1024 {
1025 	const uint8_t data = si->si_data[off];
1026 	const uint8_t rcd = SPD_DDR4_LRDIMM_ATTR_TYPE(data);
1027 	const uint8_t nrow = SPD_DDR4_LRDIMM_ATTR_NROWS(data);
1028 	const uint8_t nreg = SPD_DDR4_LRDIMM_ATTR_NREGS(data);
1029 
1030 	/*
1031 	 * The type defines both the RCD and the DB. The RCD types overlap with
1032 	 * RDIMMs.
1033 	 */
1034 	spd_upsert_flag(si, SPD_KEY_DEVS, SPD_DEVICE_RCD | SPD_DEVICE_DB);
1035 	spd_insert_map(si, SPD_KEY_DEV_RCD_TYPE, rcd,
1036 	    spd_ddr4_rcd_type_map, ARRAY_SIZE(spd_ddr4_rcd_type_map));
1037 	spd_insert_map(si, SPD_KEY_DEV_DB_TYPE, rcd,
1038 	    spd_ddr4_db_type_map, ARRAY_SIZE(spd_ddr4_db_type_map));
1039 	spd_insert_map(si, SPD_KEY_MOD_NROWS, nrow, spd_ddr4_lrdimm_nrows_map,
1040 	    ARRAY_SIZE(spd_ddr4_lrdimm_nrows_map));
1041 	spd_insert_map(si, SPD_KEY_MOD_NREGS, nreg, spd_ddr4_lrdimm_nregs_map,
1042 	    ARRAY_SIZE(spd_ddr4_lrdimm_nregs_map));
1043 }
1044 
1045 /*
1046  * The LRDIMM manufacturer here covers both the register and the data buffer, so
1047  * we end up setting the same values for both.
1048  */
1049 static void
1050 spd_parse_ddr4_lrdimm_rcd_mfg(spd_info_t *si, uint32_t off, uint32_t len,
1051     const char *key)
1052 {
1053 	ASSERT3U(len, ==, 2);
1054 
1055 	spd_parse_jedec_id(si, off, 2, SPD_KEY_DEV_RCD_MFG);
1056 	spd_parse_jedec_id_str(si, off, 2, SPD_KEY_DEV_RCD_MFG_NAME);
1057 	spd_parse_jedec_id(si, off, 2, SPD_KEY_DEV_DB_MFG);
1058 	spd_parse_jedec_id_str(si, off, 2, SPD_KEY_DEV_DB_MFG_NAME);
1059 }
1060 
1061 static const spd_value_map_t spd_ddr4_lrdimm_ods_map[] = {
1062 	{ SPD_DDR4_LRDIMM_ODS1_MODERATE, SPD_DRIVE_MODERATE, false },
1063 	{ SPD_DDR4_LRDIMM_ODS1_STRONG, SPD_DRIVE_STRONG, false }
1064 };
1065 
1066 static void
1067 spd_parse_ddr4_lrdimm_ods(spd_info_t *si, uint32_t off, uint32_t len,
1068     const char *key)
1069 {
1070 	const uint8_t data = si->si_data[off];
1071 	const uint8_t bck = SPD_DDR4_LRDIMM_ODS1_BCK(data);
1072 	const uint8_t bcom = SPD_DDR4_LRDIMM_ODS1_BCOM(data);
1073 
1074 	spd_insert_map(si, SPD_KEY_DDR4_RCD_DS_BCOM, bcom,
1075 	    spd_ddr4_lrdimm_ods_map, ARRAY_SIZE(spd_ddr4_lrdimm_ods_map));
1076 	spd_insert_map(si, SPD_KEY_DDR4_RCD_DS_BCK, bck,
1077 	    spd_ddr4_lrdimm_ods_map, ARRAY_SIZE(spd_ddr4_lrdimm_ods_map));
1078 }
1079 
1080 /*
1081  * There are two VrefDQ ranges in the DDR4 specs. These all increase at 0.65%
1082  * increments, hence our mult as 65.
1083  */
1084 static const spd_value_range_t spd_ddr4_vrefdq1_range = {
1085 	.svr_base = 6000,
1086 	.svr_mult = 65,
1087 	.svr_max = 9250
1088 };
1089 
1090 static const spd_value_range_t spd_ddr4_vrefdq2_range = {
1091 	.svr_base = 4500,
1092 	.svr_mult = 65,
1093 	.svr_max = 7750
1094 };
1095 
1096 static void
1097 spd_parse_ddr4_vrefdq_common(spd_info_t *si, uint8_t range, uint8_t val,
1098     const char *key)
1099 {
1100 	if (range == SPD_DDR4_LRDIMM_VERFDQ_RNG_1) {
1101 		spd_insert_range(si, key, val, &spd_ddr4_vrefdq1_range);
1102 	} else {
1103 		ASSERT3U(range, ==, SPD_DDR4_LRDIMM_VERFDQ_RNG_2);
1104 		spd_insert_range(si, key, val, &spd_ddr4_vrefdq2_range);
1105 	}
1106 }
1107 
1108 static void
1109 spd_parse_ddr4_lrdimm_vrefdq_r0(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 volt = SPD_DDR4_LRDIMM_VREFDQ_V(data);
1114 	const uint8_t range = si->si_data[off + len];
1115 
1116 	spd_parse_ddr4_vrefdq_common(si, SPD_DDR4_LRDIMM_VREFDQ_RNG_R0(range),
1117 	    volt, key);
1118 }
1119 
1120 static void
1121 spd_parse_ddr4_lrdimm_vrefdq_r1(spd_info_t *si, uint32_t off, uint32_t len,
1122     const char *key)
1123 {
1124 	const uint8_t data = si->si_data[off];
1125 	const uint8_t volt = SPD_DDR4_LRDIMM_VREFDQ_V(data);
1126 	const uint8_t range = si->si_data[off + len];
1127 
1128 	spd_parse_ddr4_vrefdq_common(si, SPD_DDR4_LRDIMM_VREFDQ_RNG_R1(range),
1129 	    volt, key);
1130 }
1131 
1132 static void
1133 spd_parse_ddr4_lrdimm_vrefdq_r2(spd_info_t *si, uint32_t off, uint32_t len,
1134     const char *key)
1135 {
1136 	const uint8_t data = si->si_data[off];
1137 	const uint8_t volt = SPD_DDR4_LRDIMM_VREFDQ_V(data);
1138 	const uint8_t range = si->si_data[off + len];
1139 
1140 	spd_parse_ddr4_vrefdq_common(si, SPD_DDR4_LRDIMM_VREFDQ_RNG_R2(range),
1141 	    volt, key);
1142 }
1143 
1144 static void
1145 spd_parse_ddr4_lrdimm_vrefdq_r3(spd_info_t *si, uint32_t off, uint32_t len,
1146     const char *key)
1147 {
1148 	const uint8_t data = si->si_data[off];
1149 	const uint8_t volt = SPD_DDR4_LRDIMM_VREFDQ_V(data);
1150 	const uint8_t range = si->si_data[off + len];
1151 
1152 	spd_parse_ddr4_vrefdq_common(si, SPD_DDR4_LRDIMM_VREFDQ_RNG_R3(range),
1153 	    volt, key);
1154 }
1155 
1156 static void
1157 spd_parse_ddr4_lrdimm_vrefdq_db(spd_info_t *si, uint32_t off, uint32_t len,
1158     const char *key)
1159 {
1160 	const uint8_t data = si->si_data[off];
1161 	const uint8_t range = si->si_data[off + len];
1162 
1163 	spd_parse_ddr4_vrefdq_common(si, SPD_DDR4_LRDIMM_VREFDQ_RNG_DB(range),
1164 	    data, key);
1165 }
1166 
1167 static const spd_value_map_t spd_ddr4_mdq_ds_map[] = {
1168 	{ SPD_DDR4_LRDIMM_MDQ_DS_40R, 40, false },
1169 	{ SPD_DDR4_LRDIMM_MDQ_DS_34R, 34, false },
1170 	{ SPD_DDR4_LRDIMM_MDQ_DS_48R, 48, false },
1171 	{ SPD_DDR4_LRDIMM_MDQ_DS_60R, 60, false }
1172 };
1173 
1174 static const spd_value_map_t spd_ddr4_rtt_map[] = {
1175 	{ SPD_DDR4_LRDIMM_MDQ_RTT_DIS, SPD_KEY_DDR4_TERM_DISABLED, false },
1176 	{ SPD_DDR4_LRDIMM_MDQ_RTT_60R, 60, false },
1177 	{ SPD_DDR4_LRDIMM_MDQ_RTT_120R, 120, false },
1178 	{ SPD_DDR4_LRDIMM_MDQ_RTT_40R, 40, false },
1179 	{ SPD_DDR4_LRDIMM_MDQ_RTT_240R, 240, false },
1180 	{ SPD_DDR4_LRDIMM_MDQ_RTT_48R, 48, false },
1181 	{ SPD_DDR4_LRDIMM_MDQ_RTT_80R, 80, false },
1182 	{ SPD_DDR4_LRDIMM_MDQ_RTT_34R, 34, false },
1183 };
1184 
1185 static void
1186 spd_parse_ddr4_lrdimm_mdq(spd_info_t *si, uint32_t off, uint32_t len,
1187     const char *key)
1188 {
1189 	const uint8_t d1866 = si->si_data[off];
1190 	const uint8_t d2400 = si->si_data[off + 1];
1191 	const uint8_t d3200 = si->si_data[off + 2];
1192 	const uint8_t rtt[3] = { SPD_DDR4_LRDIMM_MDQ_RTT(d1866),
1193 	    SPD_DDR4_LRDIMM_MDQ_RTT(d2400), SPD_DDR4_LRDIMM_MDQ_RTT(d3200) };
1194 	const uint8_t ds[3] = { SPD_DDR4_LRDIMM_MDQ_DS(d1866),
1195 	    SPD_DDR4_LRDIMM_MDQ_DS(d2400), SPD_DDR4_LRDIMM_MDQ_DS(d3200) };
1196 
1197 	spd_insert_map_array(si, SPD_KEY_DDR4_MDQ_RTT, rtt, ARRAY_SIZE(rtt),
1198 	    spd_ddr4_rtt_map, ARRAY_SIZE(spd_ddr4_rtt_map));
1199 	spd_insert_map_array(si, SPD_KEY_DDR4_MDQ_DS, ds, ARRAY_SIZE(ds),
1200 	    spd_ddr4_mdq_ds_map, ARRAY_SIZE(spd_ddr4_mdq_ds_map));
1201 }
1202 
1203 static const spd_value_map_t spd_ddr4_dram_ds_map[] = {
1204 	{ SPD_DDR4_LRDIMM_DRAM_DS_34R, 34, false },
1205 	{ SPD_DDR4_LRDIMM_DRAM_DS_48R, 48, false }
1206 };
1207 
1208 static void
1209 spd_parse_ddr4_lrdimm_dram(spd_info_t *si, uint32_t off, uint32_t len,
1210     const char *key)
1211 {
1212 	const uint8_t data = si->si_data[off];
1213 	const uint8_t ds[3] = {
1214 		SPD_DDR4_LRDIMM_DRAM_DS_1866(data),
1215 		SPD_DDR4_LRDIMM_DRAM_DS_2400(data),
1216 		SPD_DDR4_LRDIMM_DRAM_DS_3200(data)
1217 	};
1218 
1219 	spd_insert_map_array(si, SPD_KEY_DDR4_DRAM_DS, ds, ARRAY_SIZE(ds),
1220 	    spd_ddr4_dram_ds_map, ARRAY_SIZE(spd_ddr4_dram_ds_map));
1221 }
1222 
1223 static const spd_value_map_t spd_ddr4_rtt_wr_map[] = {
1224 	{ SPD_DDR4_LRDIMM_ODT_WR_DYN_OFF, SPD_KEY_DDR4_TERM_DISABLED, false },
1225 	{ SPD_DDR4_LRDIMM_ODT_WR_120R, 120, false },
1226 	{ SPD_DDR4_LRDIMM_ODT_WR_240R, 240, false },
1227 	{ SPD_DDR4_LRDIMM_ODT_WR_HIZ, SPD_KEY_DDR4_TERM_HIZ, false },
1228 	{ SPD_DDR4_LRDIMM_ODT_WR_80R, 80, false },
1229 };
1230 
1231 static void
1232 spd_parse_ddr4_lrdimm_odt(spd_info_t *si, uint32_t off, uint32_t len,
1233     const char *key)
1234 {
1235 	const uint8_t d1866 = si->si_data[off];
1236 	const uint8_t d2400 = si->si_data[off + 1];
1237 	const uint8_t d3200 = si->si_data[off + 2];
1238 	const uint8_t nom[3] = { SPD_DDR4_LRDIMM_ODT_NOM(d1866),
1239 	    SPD_DDR4_LRDIMM_ODT_NOM(d2400), SPD_DDR4_LRDIMM_ODT_NOM(d3200) };
1240 	const uint8_t wr[3] = { SPD_DDR4_LRDIMM_ODT_WR(d1866),
1241 	    SPD_DDR4_LRDIMM_ODT_WR(d2400), SPD_DDR4_LRDIMM_ODT_WR(d3200) };
1242 
1243 	spd_insert_map_array(si, SPD_KEY_DDR4_RTT_NOM, nom, ARRAY_SIZE(nom),
1244 	    spd_ddr4_rtt_map, ARRAY_SIZE(spd_ddr4_rtt_map));
1245 	spd_insert_map_array(si, SPD_KEY_DDR4_RTT_WR, wr, ARRAY_SIZE(wr),
1246 	    spd_ddr4_rtt_wr_map, ARRAY_SIZE(spd_ddr4_rtt_wr_map));
1247 }
1248 
1249 static void
1250 spd_parse_ddr4_lrdimm_park(spd_info_t *si, uint32_t off, uint32_t len,
1251     const char *key)
1252 {
1253 	const uint8_t d1866 = si->si_data[off];
1254 	const uint8_t d2400 = si->si_data[off + 1];
1255 	const uint8_t d3200 = si->si_data[off + 2];
1256 	const uint8_t r01[3] = { SPD_DDR4_LRDIMM_PARK_R01(d1866),
1257 	    SPD_DDR4_LRDIMM_PARK_R01(d2400), SPD_DDR4_LRDIMM_PARK_R01(d3200) };
1258 	const uint8_t r23[3] = { SPD_DDR4_LRDIMM_PARK_R23(d1866),
1259 	    SPD_DDR4_LRDIMM_PARK_R23(d2400), SPD_DDR4_LRDIMM_PARK_R23(d3200) };
1260 
1261 	spd_insert_map_array(si, SPD_KEY_DDR4_RTT_PARK_R0, r01, ARRAY_SIZE(r01),
1262 	    spd_ddr4_rtt_map, ARRAY_SIZE(spd_ddr4_rtt_map));
1263 	spd_insert_map_array(si, SPD_KEY_DDR4_RTT_PARK_R2, r23, ARRAY_SIZE(r23),
1264 	    spd_ddr4_rtt_map, ARRAY_SIZE(spd_ddr4_rtt_map));
1265 }
1266 
1267 static void
1268 spd_parse_ddr4_lrdimm_dfe(spd_info_t *si, uint32_t off, uint32_t len,
1269     const char *key)
1270 {
1271 	const uint8_t data = si->si_data[off];
1272 
1273 	if (SPD_DDR4_LRDIMM_EQ_DFE_SUP(data) != 0)
1274 		spd_nvl_insert_key(si, SPD_KEY_DDR4_DB_DFE);
1275 	if (SPD_DDR4_LRDIMM_EQ_GA_SUP(data) != 0)
1276 		spd_nvl_insert_key(si, SPD_KEY_DDR4_DB_GAIN);
1277 }
1278 
1279 static const spd_parse_t spd_ddr4_lrdimm[] = {
1280 	{ .sp_off = SPD_DDR4_LRDIMM_HEIGHT, .sp_key = SPD_KEY_MOD_HEIGHT,
1281 	    .sp_parse = spd_parse_height },
1282 	{ .sp_off = SPD_DDR4_LRDIMM_THICK, .sp_parse = spd_parse_thickness },
1283 	{ .sp_off = SPD_DDR4_LRDIMM_REF, .sp_parse = spd_parse_ddr4_design },
1284 	{ .sp_off = SPD_DDR4_LRDIMM_ATTR,
1285 	    .sp_parse = spd_parse_ddr4_lrdimm_attr },
1286 	{ .sp_off = SPD_DDR4_LRDIMM_THERM,
1287 	    .sp_parse = spd_parse_ddr4_rdimm_therm },
1288 	{ .sp_off = SPD_DDR4_LRDIMM_REG_MFG_ID0, .sp_len = 2,
1289 	    .sp_parse = spd_parse_ddr4_lrdimm_rcd_mfg },
1290 	{ .sp_off = SPD_DDR4_LRDIMM_REV, .sp_key = SPD_KEY_DEV_RCD_REV,
1291 	    .sp_parse = spd_parse_dram_step },
1292 	{ .sp_off = SPD_DDR4_LRDIMM_MAP, .sp_parse = spd_parse_ddr4_edge },
1293 	/*
1294 	 * The LRDIMM output drive strength is equivalent to the RDIMM, so we
1295 	 * use that. For ODS1, we fire it a second-time to get just the
1296 	 * LRDIMM-specific fields.
1297 	 */
1298 	{ .sp_off = SPD_DDR4_LRDIMM_ODS0, .sp_len = 2,
1299 	    .sp_parse = spd_parse_ddr4_rdimm_ods },
1300 	{ .sp_off = SPD_DDR4_LRDIMM_ODS1,
1301 	    .sp_parse = spd_parse_ddr4_lrdimm_ods },
1302 	{ .sp_off = SPD_DDR4_LRDIMM_DB_REV,  .sp_key = SPD_KEY_DEV_DB_REV,
1303 	    .sp_parse = spd_parse_dram_step },
1304 	/*
1305 	 * The five VrefDQ values (four ranks and data buffer) require the range
1306 	 * byte to determine which base set of values to use. This is why they
1307 	 * all have the long length to ensure we account for that.
1308 	 */
1309 	{ .sp_off = SPD_DDR4_LRDIMM_VREFDQ0, .sp_key = SPD_KEY_DDR4_VREFDQ_R0,
1310 	    .sp_len = SPD_DDR4_LRDIMM_VREFDQ_RNG - SPD_DDR4_LRDIMM_VREFDQ0 + 1,
1311 	    .sp_parse = spd_parse_ddr4_lrdimm_vrefdq_r0 },
1312 	{ .sp_off = SPD_DDR4_LRDIMM_VREFDQ1, .sp_key = SPD_KEY_DDR4_VREFDQ_R1,
1313 	    .sp_len = SPD_DDR4_LRDIMM_VREFDQ_RNG - SPD_DDR4_LRDIMM_VREFDQ1 + 1,
1314 	    .sp_parse = spd_parse_ddr4_lrdimm_vrefdq_r1 },
1315 
1316 	{ .sp_off = SPD_DDR4_LRDIMM_VREFDQ2, .sp_key = SPD_KEY_DDR4_VREFDQ_R2,
1317 	    .sp_len = SPD_DDR4_LRDIMM_VREFDQ_RNG - SPD_DDR4_LRDIMM_VREFDQ2 + 1,
1318 	    .sp_parse = spd_parse_ddr4_lrdimm_vrefdq_r2 },
1319 
1320 	{ .sp_off = SPD_DDR4_LRDIMM_VREFDQ3, .sp_key = SPD_KEY_DDR4_VREFDQ_R3,
1321 	    .sp_len = SPD_DDR4_LRDIMM_VREFDQ_RNG - SPD_DDR4_LRDIMM_VREFDQ3 + 1,
1322 	    .sp_parse = spd_parse_ddr4_lrdimm_vrefdq_r3 },
1323 
1324 	{ .sp_off = SPD_DDR4_LRDIMM_VREFDQ_DB, .sp_key = SPD_KEY_DDR4_VREFDQ_DB,
1325 	    .sp_len = SPD_DDR4_LRDIMM_VREFDQ_RNG - SPD_DDR4_LRDIMM_VREFDQ_DB +
1326 	    1, .sp_parse = spd_parse_ddr4_lrdimm_vrefdq_db },
1327 	{ .sp_off = SPD_DDR4_LRDIMM_MDQ_1866, .sp_len = 3,
1328 	    .sp_parse = spd_parse_ddr4_lrdimm_mdq },
1329 	{ .sp_off = SPD_DDR4_LRDIMM_DRAM_DS,
1330 	    .sp_parse = spd_parse_ddr4_lrdimm_dram },
1331 	{ .sp_off = SPD_DDR4_LRDIMM_ODT_1866, .sp_len = 3,
1332 	    .sp_parse = spd_parse_ddr4_lrdimm_odt },
1333 	{ .sp_off = SPD_DDR4_LRDIMM_PARK_1866, .sp_len = 3,
1334 	    .sp_parse = spd_parse_ddr4_lrdimm_park },
1335 	{ .sp_off = SPD_DDR4_LRDIMM_EQ, .sp_parse = spd_parse_ddr4_lrdimm_dfe }
1336 };
1337 
1338 static void
1339 spd_parse_ddr4_mod_specific(spd_info_t *si)
1340 {
1341 	uint32_t type;
1342 
1343 	if (nvlist_lookup_uint32(si->si_nvl, SPD_KEY_MOD_TYPE, &type) != 0)
1344 		return;
1345 
1346 	switch (type) {
1347 	case SPD_MOD_TYPE_RDIMM:
1348 	case SPD_MOD_TYPE_MINI_RDIMM:
1349 	case SPD_MOD_TYPE_72b_SO_RDIMM:
1350 		spd_parse(si, spd_ddr4_rdimm, ARRAY_SIZE(spd_ddr4_rdimm));
1351 		break;
1352 	case SPD_MOD_TYPE_LRDIMM:
1353 		spd_parse(si, spd_ddr4_lrdimm, ARRAY_SIZE(spd_ddr4_lrdimm));
1354 		break;
1355 	case SPD_MOD_TYPE_UDIMM:
1356 	case SPD_MOD_TYPE_SODIMM:
1357 	case SPD_MOD_TYPE_MINI_UDIMM:
1358 	case SPD_MOD_TYPE_72b_SO_UDIMM:
1359 	case SPD_MOD_TYPE_16b_SO_DIMM:
1360 	case SPD_MOD_TYPE_32b_SO_DIMM:
1361 		spd_parse(si, spd_ddr4_udimm, ARRAY_SIZE(spd_ddr4_udimm));
1362 		break;
1363 	default:
1364 		break;
1365 	}
1366 }
1367 
1368 /*
1369  * DDR4 processing.
1370  *
1371  *  1. Check that we know the encoding revision of the SPD.
1372  *  2. Capture the SPD module type information as we already have the dram type
1373  *     information.
1374  *  3. Attempt to parse everything. Note that we don't really use the device's
1375  *     notion of how much data should be present and only will attempt to parse
1376  *     regions if we have enough data from the user.
1377  */
1378 void
1379 spd_parse_ddr4(spd_info_t *si)
1380 {
1381 	if (SPD_DDR4_SPD_REV_ENC(si->si_data[SPD_DDR4_SPD_REV]) !=
1382 	    SPD_DDR4_SPD_REV_V1) {
1383 		si->si_error = LIBJEDEC_SPD_UNSUP_REV;
1384 		return;
1385 	}
1386 
1387 	/*
1388 	 * Parse DDR4 common attributes. Some overlay information. Then go
1389 	 * through and do the manufacturing info.
1390 	 */
1391 	spd_parse(si, spd_ddr4_common, ARRAY_SIZE(spd_ddr4_common));
1392 	spd_parse_ddr4_mod_specific(si);
1393 	spd_parse(si, spd_ddr4_mfg, ARRAY_SIZE(spd_ddr4_mfg));
1394 }
1395