xref: /illumos-gate/usr/src/lib/libjedec/common/libjedec_spd_ddr4.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  * 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
spd_parse_ddr4_nbytes(spd_info_t * si,uint32_t off,uint32_t len,const char * key)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
spd_parse_ddr4_mod_type(spd_info_t * si,uint32_t off,uint32_t len,const char * key)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
spd_parse_ddr4_density(spd_info_t * si,uint32_t off,uint32_t len,const char * key)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
spd_parse_ddr4_addr(spd_info_t * si,uint32_t off,uint32_t len,const char * key)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
spd_parse_ddr4_pkg_common(spd_info_t * si,uint8_t data,const char * die_key,const char * sl_key)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
spd_parse_ddr4_pri_pkg(spd_info_t * si,uint32_t off,uint32_t len,const char * key)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 
205 	if (SPD_DDR4_PKG_TYPE(data) == SPD_DDR4_PKG_TYPE_NOT) {
206 		spd_nvl_insert_key(si, SPD_KEY_PKG_NOT_MONO);
207 	}
208 
209 	return (spd_parse_ddr4_pkg_common(si, si->si_data[off],
210 	    SPD_KEY_PKG_NDIE, SPD_KEY_PKG_SL));
211 }
212 
213 static void
spd_parse_ddr4_sec_pkg(spd_info_t * si,uint32_t off,uint32_t len,const char * key)214 spd_parse_ddr4_sec_pkg(spd_info_t *si, uint32_t off, uint32_t len,
215     const char *key)
216 {
217 	ASSERT3U(off, >=, SPD_DDR4_PRI_PKG);
218 
219 	if (SPD_DDR4_PKG_TYPE(si->si_data[SPD_DDR4_PRI_PKG]) ==
220 	    SPD_DDR4_PKG_TYPE_MONO) {
221 		return;
222 	}
223 
224 	return (spd_parse_ddr4_pkg_common(si, si->si_data[off],
225 	    SPD_KEY_SEC_PKG_NDIE, SPD_KEY_SEC_PKG_SL));
226 }
227 
228 static const spd_value_map_t spd_ddr4_maw_map[] = {
229 	{ SPD_DDR4_OPT_FEAT_MAW_8192X, 8192, false },
230 	{ SPD_DDR4_OPT_FEAT_MAW_4096X, 4096, false },
231 	{ SPD_DDR4_OPT_FEAT_MAW_2048X, 2048, false }
232 };
233 
234 static const spd_value_map_t spd_ddr4_mac_map[] = {
235 	{ SPD_DDR4_OPT_FEAT_MAC_UNTESTED, 0, true},
236 	{ SPD_DDR4_OPT_FEAT_MAC_700K, 700000, false },
237 	{ SPD_DDR4_OPT_FEAT_MAC_600K, 600000, false },
238 	{ SPD_DDR4_OPT_FEAT_MAC_500K, 500000, false },
239 	{ SPD_DDR4_OPT_FEAT_MAC_400K, 400000, false },
240 	{ SPD_DDR4_OPT_FEAT_MAC_300K, 300000, false },
241 	{ SPD_DDR4_OPT_FEAT_MAC_200K, 200000, false },
242 	{ SPD_DDR4_OPT_FEAT_MAC_UNLIMITED, SPD_KEY_MAC_UNLIMITED, false }
243 };
244 
245 static void
spd_parse_ddr4_feat(spd_info_t * si,uint32_t off,uint32_t len,const char * key)246 spd_parse_ddr4_feat(spd_info_t *si, uint32_t off, uint32_t len, const char *key)
247 {
248 	const uint8_t data = si->si_data[off];
249 	const uint8_t maw = SPD_DDR4_OPT_FEAT_MAW(data);
250 	const uint8_t mac = SPD_DDR4_OPT_FEAT_MAC(data);
251 
252 	spd_insert_map(si, SPD_KEY_MAW, maw, spd_ddr4_maw_map,
253 	    ARRAY_SIZE(spd_ddr4_maw_map));
254 	spd_insert_map(si, SPD_KEY_MAC, mac, spd_ddr4_mac_map,
255 	    ARRAY_SIZE(spd_ddr4_mac_map));
256 }
257 
258 static void
spd_parse_ddr4_feat2(spd_info_t * si,uint32_t off,uint32_t len,const char * key)259 spd_parse_ddr4_feat2(spd_info_t *si, uint32_t off, uint32_t len,
260     const char *key)
261 {
262 	const uint8_t data = si->si_data[off];
263 	const uint8_t ppr_sup = SPD_DDR4_OPT_FEAT2_PPR(data);
264 	spd_ppr_flags_t flags = 0;
265 
266 	switch (ppr_sup) {
267 	case SPD_DDR4_OPT_FEAT2_PPR_1RPBG:
268 		spd_nvl_insert_u32(si, SPD_KEY_PPR_GRAN,
269 		    SPD_PPR_GRAN_BANK_GROUP);
270 		flags |= SPD_PPR_F_HARD_PPR;
271 		break;
272 	case SPD_DDR4_OPT_FEAT2_PPR_NOTSUP:
273 		/*
274 		 * No PPR, nothing to do.
275 		 */
276 		return;
277 	default:
278 		/*
279 		 * Unknown PPR value.
280 		 */
281 		spd_nvl_err(si, SPD_KEY_PPR, SPD_ERROR_NO_XLATE,
282 		    "encountered unknown value: 0x%x", ppr_sup);
283 		return;
284 	}
285 
286 	if (SPD_DDR4_OPT_FEAT2_SOFT_PPR(data))
287 		flags |= SPD_PPR_F_SOFT_PPR;
288 	if (SPD_DDR4_OPT_FEAT2_MBIST_PPR(data))
289 		flags |= SPD_PPR_F_MBIST_PPR;
290 	spd_nvl_insert_u32(si, SPD_KEY_PPR, flags);
291 }
292 
293 static void
spd_parse_ddr4_volt(spd_info_t * si,uint32_t off,uint32_t len,const char * key)294 spd_parse_ddr4_volt(spd_info_t *si, uint32_t off, uint32_t len, const char *key)
295 {
296 	const uint8_t data = si->si_data[off];
297 	uint32_t volts[] = { 1200 };
298 
299 	if (SPD_DDR4_VOLT_V1P2_OPER(data) == 0)
300 		return;
301 	spd_nvl_insert_u32_array(si, key, volts, ARRAY_SIZE(volts));
302 }
303 
304 static const spd_value_map_t spd_ddr4_dram_width[] = {
305 	{ SPD_DDR4_MOD_ORG_WIDTH_4b, 4, false },
306 	{ SPD_DDR4_MOD_ORG_WIDTH_8b, 8, false },
307 	{ SPD_DDR4_MOD_ORG_WIDTH_16b, 16, false },
308 	{ SPD_DDR4_MOD_ORG_WIDTH_32b, 32, false }
309 };
310 
311 static const spd_value_range_t spd_ddr4_nrank_range = {
312 	.svr_base = SPD_DDR4_MOD_ORG_NPKG_RANK_BASE
313 };
314 
315 static void
spd_parse_ddr4_mod_org(spd_info_t * si,uint32_t off,uint32_t len,const char * key)316 spd_parse_ddr4_mod_org(spd_info_t *si, uint32_t off, uint32_t len,
317     const char *key)
318 {
319 	const uint8_t data = si->si_data[off];
320 	const uint8_t mix = SPD_DDR4_MOD_ORG_RANK_MIX(data);
321 	const uint8_t nranks = SPD_DDR4_MOD_ORG_NPKG_RANK(data);
322 	const uint8_t width = SPD_DDR4_MOD_ORG_WIDTH(data);
323 
324 	if (mix == SPD_DDR4_MOD_ORG_RANK_MIX_ASYM)
325 		spd_nvl_insert_key(si, SPD_KEY_RANK_ASYM);
326 	spd_insert_range(si, SPD_KEY_NRANKS, nranks, &spd_ddr4_nrank_range);
327 	spd_insert_map(si, SPD_KEY_DRAM_WIDTH, width, spd_ddr4_dram_width,
328 	    ARRAY_SIZE(spd_ddr4_dram_width));
329 }
330 
331 static const spd_value_map_t spd_ddr4_ext_width[] = {
332 	{ SPD_DDR4_MOD_BUS_WIDTH_EXT_NONE, 0, false },
333 	{ SPD_DDR4_MOD_BUS_WIDTH_EXT_8b, 8, false }
334 };
335 
336 static const spd_value_map_t spd_ddr4_pri_width[] = {
337 	{ SPD_DDR4_MOD_BUS_WIDTH_PRI_8b, 8, false },
338 	{ SPD_DDR4_MOD_BUS_WIDTH_PRI_16b, 16, false },
339 	{ SPD_DDR4_MOD_BUS_WIDTH_PRI_32b, 32, false },
340 	{ SPD_DDR4_MOD_BUS_WIDTH_PRI_64b, 64, false },
341 };
342 
343 static void
spd_parse_ddr4_bus_width(spd_info_t * si,uint32_t off,uint32_t len,const char * key)344 spd_parse_ddr4_bus_width(spd_info_t *si, uint32_t off, uint32_t len,
345     const char *key)
346 {
347 	const uint8_t data = si->si_data[off];
348 	const uint8_t ext = SPD_DDR4_MOD_BUS_WIDTH_EXT(data);
349 	const uint8_t pri = SPD_DDR4_MOD_BUS_WIDTH_PRI(data);
350 
351 	/*
352 	 * DDR4 is simpler than LPDDRx and DDR5. It only has a single channel
353 	 * and each DRAM is only connected to one channel.
354 	 */
355 	spd_nvl_insert_u32(si, SPD_KEY_NSUBCHAN, 1);
356 	spd_nvl_insert_u32(si, SPD_KEY_DRAM_NCHAN, 1);
357 	spd_insert_map(si, SPD_KEY_DATA_WIDTH, pri, spd_ddr4_pri_width,
358 	    ARRAY_SIZE(spd_ddr4_pri_width));
359 	spd_insert_map(si, SPD_KEY_ECC_WIDTH, ext, spd_ddr4_ext_width,
360 	    ARRAY_SIZE(spd_ddr4_ext_width));
361 }
362 
363 static void
spd_parse_ddr4_therm(spd_info_t * si,uint32_t off,uint32_t len,const char * key)364 spd_parse_ddr4_therm(spd_info_t *si, uint32_t off, uint32_t len,
365     const char *key)
366 {
367 	const uint8_t data = si->si_data[off];
368 
369 	/*
370 	 * In DDR4, there is only a single standard temperature device. It is
371 	 * often integrated into the EEPROM, but from a JEDEC perspective these
372 	 * each have their own device type.
373 	 */
374 	if (SPD_DDR4_MOD_THERM_PRES(data) != 0) {
375 		spd_upsert_flag(si, key, SPD_DEVICE_TEMP_1);
376 		spd_nvl_insert_u32(si, SPD_KEY_DEV_TEMP_TYPE,
377 		    SPD_TEMP_T_TSE2004av);
378 	}
379 }
380 
381 static const spd_value_map_t spd_ddr4_ts_mtb[] = {
382 	{ SPD_DDR4_TIMEBASE_MTB_125ps, SPD_DDR4_MTB_PS, false }
383 };
384 
385 static const spd_value_map_t spd_ddr4_ts_ftb[] = {
386 	{ SPD_DDR4_TIMEBASE_FTB_1ps, SPD_DDR4_FTB_PS, false }
387 };
388 
389 static void
spd_parse_ddr4_ts(spd_info_t * si,uint32_t off,uint32_t len,const char * key)390 spd_parse_ddr4_ts(spd_info_t *si, uint32_t off, uint32_t len,
391     const char *key)
392 {
393 	const uint8_t data = si->si_data[off];
394 	const uint8_t mtb = SPD_DDR4_TIMEBASE_MTB(data);
395 	const uint8_t ftb = SPD_DDR4_TIMEBASE_FTB(data);
396 
397 
398 	spd_insert_map(si, SPD_KEY_MTB, mtb, spd_ddr4_ts_mtb,
399 	    ARRAY_SIZE(spd_ddr4_ts_mtb));
400 	spd_insert_map(si, SPD_KEY_FTB, ftb, spd_ddr4_ts_ftb,
401 	    ARRAY_SIZE(spd_ddr4_ts_ftb));
402 }
403 
404 /*
405  * t~RAS~ consists of the upper nibble at off and the MTB at off + 1.
406  */
407 static void
spd_parse_ddr4_tras(spd_info_t * si,uint32_t off,uint32_t len,const char * key)408 spd_parse_ddr4_tras(spd_info_t *si, uint32_t off, uint32_t len,
409     const char *key)
410 {
411 	const uint8_t ras_nib = SPD_DDR4_RAS_RC_UPPER_RAS(si->si_data[off]);
412 	ASSERT3U(len, ==, 2);
413 
414 	return (spd_parse_ddr_time(si, key, ras_nib, si->si_data[off + 1], 0));
415 }
416 
417 /*
418  * t~RC~ consists of an upper 4-bit nibble at off. Its MTB is at off + 2. The
419  * FTB is at off + len - 1.
420  */
421 static void
spd_parse_ddr4_trc(spd_info_t * si,uint32_t off,uint32_t len,const char * key)422 spd_parse_ddr4_trc(spd_info_t *si, uint32_t off, uint32_t len,
423     const char *key)
424 {
425 	const uint8_t rc_nib = SPD_DDR4_RAS_RC_UPPER_RC(si->si_data[off]);
426 
427 	return (spd_parse_ddr_time(si, key, rc_nib, si->si_data[off + 2],
428 	    si->si_data[off + len - 1]));
429 }
430 
431 /*
432  * Upper nibble in off, MTB in off + 1, no FTB.
433  */
434 static void
spd_parse_ddr4_tfaw(spd_info_t * si,uint32_t off,uint32_t len,const char * key)435 spd_parse_ddr4_tfaw(spd_info_t *si, uint32_t off, uint32_t len,
436     const char *key)
437 {
438 	const uint8_t faw_nib = SPD_DDR4_TFAW_UPPER_FAW(si->si_data[off]);
439 	return (spd_parse_ddr_time(si, key, faw_nib, si->si_data[off + 1], 0));
440 }
441 
442 static void
spd_parse_ddr4_twr(spd_info_t * si,uint32_t off,uint32_t len,const char * key)443 spd_parse_ddr4_twr(spd_info_t *si, uint32_t off, uint32_t len,
444     const char *key)
445 {
446 	const uint8_t twr_nib = SPD_DDR4_TWR_MIN_UPPER_TWR(si->si_data[off]);
447 	return (spd_parse_ddr_time(si, key, twr_nib, si->si_data[off + 1], 0));
448 }
449 
450 static void
spd_parse_ddr4_twtrs(spd_info_t * si,uint32_t off,uint32_t len,const char * key)451 spd_parse_ddr4_twtrs(spd_info_t *si, uint32_t off, uint32_t len,
452     const char *key)
453 {
454 	const uint8_t twtrs_nib = SPD_DDR4_TWRT_UPPER_TWRS(si->si_data[off]);
455 	return (spd_parse_ddr_time(si, key, twtrs_nib, si->si_data[off + 1],
456 	    0));
457 }
458 
459 static void
spd_parse_ddr4_twtrl(spd_info_t * si,uint32_t off,uint32_t len,const char * key)460 spd_parse_ddr4_twtrl(spd_info_t *si, uint32_t off, uint32_t len,
461     const char *key)
462 {
463 	const uint8_t twtrl_nib = SPD_DDR4_TWRT_UPPER_TWRL(si->si_data[off]);
464 	return (spd_parse_ddr_time(si, key, twtrl_nib, si->si_data[off + 2],
465 	    0));
466 }
467 
468 static void
spd_parse_ddr4_cas(spd_info_t * si,uint32_t off,uint32_t len,const char * key)469 spd_parse_ddr4_cas(spd_info_t *si, uint32_t off, uint32_t len,
470     const char *key)
471 {
472 	uint32_t cas[32] = { 0 };
473 	uint_t ncas = 0;
474 	uint32_t cas_base;
475 
476 	ASSERT3U(len, ==, 4);
477 	if (SPD_DDR4_CAS_SUP3_RANGE(si->si_data[off + 3]) ==
478 	    SPD_DDR4_CAS_SUP3_RANGE_7) {
479 		cas_base = 7;
480 	} else {
481 		cas_base = 23;
482 	}
483 
484 	for (uint32_t byte = 0; byte < len; byte++) {
485 		uint32_t data = si->si_data[off + byte];
486 		uint32_t nbits = NBBY;
487 
488 		/*
489 		 * The last byte reserves the last two bits.
490 		 */
491 		if (byte == len - 1)
492 			nbits -= 2;
493 
494 		for (uint32_t i = 0; i < nbits; i++) {
495 			if (bitx8(data, i, i) == 1) {
496 				cas[ncas] = cas_base + i + NBBY * byte;
497 				ncas++;
498 			}
499 		}
500 	}
501 
502 	spd_nvl_insert_u32_array(si, key, cas, ncas);
503 }
504 
505 static const uint32_t spd_ddr4_nib_map[0x18][0x4] = {
506 	{ 0, 1, 2, 3 },
507 	{ 0, 1, 3, 2 },
508 	{ 0, 2, 1, 3 },
509 	{ 0, 2, 3, 1 },
510 	{ 0, 3, 1, 2 },
511 	{ 0, 3, 2, 1 },
512 	{ 1, 0, 2, 3 },
513 	{ 1, 0, 3, 2 },
514 	{ 1, 2, 0, 3 },
515 	{ 1, 2, 3, 0 },
516 	{ 1, 3, 0, 2 },
517 	{ 1, 3, 2, 0 },
518 	{ 2, 0, 1, 3 },
519 	{ 2, 0, 3, 1 },
520 	{ 2, 1, 0, 3 },
521 	{ 2, 1, 3, 0 },
522 	{ 2, 3, 0, 1 },
523 	{ 2, 3, 1, 0 },
524 	{ 3, 0, 1, 2 },
525 	{ 3, 0, 2, 1 },
526 	{ 3, 1, 0, 2 },
527 	{ 3, 1, 2, 0 },
528 	{ 3, 2, 0, 1 },
529 	{ 3, 2, 1, 0 }
530 };
531 
532 /*
533  * This function is shared between LPDDR3/4 and DDR4. They have the same values.
534  */
535 void
spd_parse_ddr4_nib_map(spd_info_t * si,uint32_t off,uint32_t len,const char * key)536 spd_parse_ddr4_nib_map(spd_info_t *si, uint32_t off, uint32_t len,
537     const char *key)
538 {
539 	const uint8_t data = si->si_data[off];
540 	const uint8_t pkg = SPD_DDR4_MAP_PKG(data);
541 	const uint8_t nib = SPD_DDR4_MAP_NIBBLE(data);
542 	uint8_t idx = SPD_DDR4_MAP_IDX(data);
543 	uint32_t bits[4];
544 
545 	/*
546 	 * Because there is only a single legal value we don't make a specific
547 	 * nvlist key for it; however, if it is incorrect we will complain about
548 	 * it!
549 	 */
550 	if (pkg != SPD_DDR4_MAP_PKG_FLIP) {
551 		spd_nvl_err(si, key, SPD_ERROR_NO_XLATE,
552 		    "encountered bad package value: 0x%x", pkg);
553 	}
554 
555 	if (idx == SPD_DDR4_MAP_IDX_UNSPEC)
556 		return;
557 	idx--;
558 
559 	if (idx >= ARRAY_SIZE(spd_ddr4_nib_map)) {
560 		spd_nvl_err(si, key, SPD_ERROR_NO_XLATE,
561 		    "encountered bad nibble mapping value: 0x%x", idx);
562 		return;
563 	}
564 
565 	if (nib == 1) {
566 		bits[0] = spd_ddr4_nib_map[idx][0] + 4;
567 		bits[1] = spd_ddr4_nib_map[idx][1] + 4;
568 		bits[2] = spd_ddr4_nib_map[idx][2] + 4;
569 		bits[3] = spd_ddr4_nib_map[idx][3] + 4;
570 	} else {
571 		bits[0] = spd_ddr4_nib_map[idx][0];
572 		bits[1] = spd_ddr4_nib_map[idx][1];
573 		bits[2] = spd_ddr4_nib_map[idx][2];
574 		bits[3] = spd_ddr4_nib_map[idx][3];
575 	};
576 
577 	spd_nvl_insert_u32_array(si, key, bits, ARRAY_SIZE(bits));
578 }
579 
580 static const spd_parse_t spd_ddr4_common[] = {
581 	{ .sp_off = SPD_DDR4_NBYTES, .sp_parse = spd_parse_ddr4_nbytes },
582 	{ .sp_off = SPD_DDR4_SPD_REV, .sp_parse = spd_parse_rev },
583 	/*
584 	 * We have previously validated that the DRAM type is something that we
585 	 * understand. We pass through the raw enum to users here.
586 	 */
587 	{ .sp_off = SPD_DDR4_DRAM_TYPE, .sp_key = SPD_KEY_DRAM_TYPE,
588 	    .sp_parse = spd_parse_raw_u8 },
589 	{ .sp_off = SPD_DDR4_MOD_TYPE, .sp_parse = spd_parse_ddr4_mod_type },
590 	{ .sp_off = SPD_DDR4_DENSITY, .sp_parse = spd_parse_ddr4_density },
591 	{ .sp_off = SPD_DDR4_ADDR, .sp_parse = spd_parse_ddr4_addr },
592 	{ .sp_off = SPD_DDR4_PRI_PKG, .sp_parse = spd_parse_ddr4_pri_pkg },
593 	{ .sp_off = SPD_DDR4_SEC_PKG, .sp_parse = spd_parse_ddr4_sec_pkg },
594 	{ .sp_off = SPD_DDR4_OPT_FEAT, .sp_parse = spd_parse_ddr4_feat },
595 	{ .sp_off = SPD_DDR4_OPT_FEAT2, .sp_parse = spd_parse_ddr4_feat2 },
596 	{ .sp_off = SPD_DDR4_VOLT, .sp_key = SPD_KEY_NOM_VDD,
597 	    .sp_parse = spd_parse_ddr4_volt },
598 	{ .sp_off = SPD_DDR4_MOD_ORG, .sp_parse = spd_parse_ddr4_mod_org },
599 	{ .sp_off = SPD_DDR4_MOD_BUS_WIDTH,
600 	    .sp_parse = spd_parse_ddr4_bus_width },
601 	{ .sp_off = SPD_DDR4_MOD_THERM, .sp_key = SPD_KEY_DEVS,
602 	    .sp_parse = spd_parse_ddr4_therm },
603 	/*
604 	 * Because there is only one set of valid time bases, we assume that
605 	 * as part of the rest of the time construction.
606 	 */
607 	{ .sp_off = SPD_DDR4_TIMEBASE, .sp_parse = spd_parse_ddr4_ts },
608 	{ .sp_off = SPD_DDR4_TCKAVG_MIN, .sp_key = SPD_KEY_TCKAVG_MIN,
609 	    .sp_len = SPD_DDR4_TCKAVG_MIN_FINE - SPD_DDR4_TCKAVG_MIN + 1,
610 	    .sp_parse = spd_parse_mtb_ftb_time_pair },
611 	{ .sp_off = SPD_DDR4_TCKAVG_MAX, .sp_key = SPD_KEY_TCKAVG_MAX,
612 	    .sp_len = SPD_DDR4_TCKAVG_MAX_FINE - SPD_DDR4_TCKAVG_MAX + 1,
613 	    .sp_parse = spd_parse_mtb_ftb_time_pair },
614 	{ .sp_off = SPD_DDR4_CAS_SUP0, .sp_key = SPD_KEY_CAS,
615 	    .sp_len = SPD_DDR4_CAS_SUP3 - SPD_DDR4_CAS_SUP0 + 1,
616 	    .sp_parse = spd_parse_ddr4_cas },
617 	{ .sp_off = SPD_DDR4_TAA_MIN, .sp_key = SPD_KEY_TAA_MIN,
618 	    .sp_len = SPD_DDR4_TAA_MIN_FINE - SPD_DDR4_TAA_MIN + 1,
619 	    .sp_parse = spd_parse_mtb_ftb_time_pair },
620 	{ .sp_off = SPD_DDR4_TRCD_MIN, .sp_key = SPD_KEY_TRCD_MIN,
621 	    .sp_len = SPD_DDR4_TRCD_MIN_FINE - SPD_DDR4_TRCD_MIN + 1,
622 	    .sp_parse = spd_parse_mtb_ftb_time_pair },
623 	{ .sp_off = SPD_DDR4_TRP_MIN, .sp_key = SPD_KEY_TRP_MIN,
624 	    .sp_len = SPD_DDR4_TRP_MIN_FINE - SPD_DDR4_TRP_MIN + 1,
625 	    .sp_parse = spd_parse_mtb_ftb_time_pair },
626 	{ .sp_off = SPD_DDR4_RAS_RC_UPPER, .sp_len = 2,
627 	    .sp_key = SPD_KEY_TRAS_MIN, .sp_parse = spd_parse_ddr4_tras },
628 	{ .sp_off = SPD_DDR4_RAS_RC_UPPER, .sp_key = SPD_KEY_TRC_MIN,
629 	    .sp_len = SPD_DDR4_TRC_MIN_FINE - SPD_DDR4_RAS_RC_UPPER + 1,
630 	    .sp_parse = spd_parse_ddr4_trc },
631 	{ .sp_off = SPD_DDR4_TRFC1_MIN_LSB, .sp_len = 2,
632 	    .sp_key = SPD_KEY_TRFC1_MIN, .sp_parse = spd_parse_mtb_pair },
633 	{ .sp_off = SPD_DDR4_TRFC2_MIN_LSB, .sp_len = 2,
634 	    .sp_key = SPD_KEY_TRFC2_MIN, .sp_parse = spd_parse_mtb_pair },
635 	{ .sp_off = SPD_DDR4_TRFC4_MIN_LSB, .sp_len = 2,
636 	    .sp_key = SPD_KEY_TRFC4_MIN, .sp_parse = spd_parse_mtb_pair },
637 	{ .sp_off = SPD_DDR4_TFAW_UPPER, .sp_len = 2, .sp_key = SPD_KEY_TFAW,
638 	    .sp_parse = spd_parse_ddr4_tfaw },
639 	{ .sp_off = SPD_DDR4_TRRDS_MIN, .sp_key = SPD_KEY_TRRD_S_MIN,
640 	    .sp_len = SPD_DDR4_TRRDS_MIN_FINE - SPD_DDR4_TRRDS_MIN + 1,
641 	    .sp_parse = spd_parse_mtb_ftb_time_pair },
642 	{ .sp_off = SPD_DDR4_TRRDL_MIN, .sp_key = SPD_KEY_TRRD_L_MIN,
643 	    .sp_len = SPD_DDR4_TRRDL_MIN_FINE - SPD_DDR4_TRRDL_MIN + 1,
644 	    .sp_parse = spd_parse_mtb_ftb_time_pair },
645 	{ .sp_off = SPD_DDR4_TCCDL_MIN, .sp_key = SPD_KEY_TCCD_L_MIN,
646 	    .sp_len = SPD_DDR4_TCCDL_MIN_FINE - SPD_DDR4_TCCDL_MIN + 1,
647 	    .sp_parse = spd_parse_mtb_ftb_time_pair },
648 	{ .sp_off = SPD_DDR4_TWR_MIN_UPPER, .sp_len = 2,
649 	    .sp_key = SPD_KEY_TWR_MIN, .sp_parse = spd_parse_ddr4_twr },
650 	{ .sp_off = SPD_DDR4_TWRT_UPPER, .sp_len = 2,
651 	    .sp_key = SPD_KEY_TWTRS_MIN, .sp_parse = spd_parse_ddr4_twtrs },
652 	{ .sp_off = SPD_DDR4_TWRT_UPPER, .sp_len = 3,
653 	    .sp_key = SPD_KEY_TWTRL_MIN, .sp_parse = spd_parse_ddr4_twtrl },
654 	{ .sp_off = SPD_DDR4_MAP_DQ0, .sp_key = SPD_KEY_DDR4_MAP_DQ0,
655 	    .sp_parse = spd_parse_ddr4_nib_map },
656 	{ .sp_off = SPD_DDR4_MAP_DQ4, .sp_key = SPD_KEY_DDR4_MAP_DQ4,
657 	    .sp_parse = spd_parse_ddr4_nib_map },
658 	{ .sp_off = SPD_DDR4_MAP_DQ8, .sp_key = SPD_KEY_DDR4_MAP_DQ8,
659 	    .sp_parse = spd_parse_ddr4_nib_map },
660 	{ .sp_off = SPD_DDR4_MAP_DQ12, .sp_key = SPD_KEY_DDR4_MAP_DQ12,
661 	    .sp_parse = spd_parse_ddr4_nib_map },
662 	{ .sp_off = SPD_DDR4_MAP_DQ16, .sp_key = SPD_KEY_DDR4_MAP_DQ16,
663 	    .sp_parse = spd_parse_ddr4_nib_map },
664 	{ .sp_off = SPD_DDR4_MAP_DQ20, .sp_key = SPD_KEY_DDR4_MAP_DQ20,
665 	    .sp_parse = spd_parse_ddr4_nib_map },
666 	{ .sp_off = SPD_DDR4_MAP_DQ24, .sp_key = SPD_KEY_DDR4_MAP_DQ24,
667 	    .sp_parse = spd_parse_ddr4_nib_map },
668 	{ .sp_off = SPD_DDR4_MAP_DQ28, .sp_key = SPD_KEY_DDR4_MAP_DQ28,
669 	    .sp_parse = spd_parse_ddr4_nib_map },
670 	{ .sp_off = SPD_DDR4_MAP_CB0, .sp_key = SPD_KEY_DDR4_MAP_CB0,
671 	    .sp_parse = spd_parse_ddr4_nib_map },
672 	{ .sp_off = SPD_DDR4_MAP_CB4, .sp_key = SPD_KEY_DDR4_MAP_CB4,
673 	    .sp_parse = spd_parse_ddr4_nib_map },
674 	{ .sp_off = SPD_DDR4_MAP_DQ32, .sp_key = SPD_KEY_DDR4_MAP_DQ32,
675 	    .sp_parse = spd_parse_ddr4_nib_map },
676 	{ .sp_off = SPD_DDR4_MAP_DQ36, .sp_key = SPD_KEY_DDR4_MAP_DQ36,
677 	    .sp_parse = spd_parse_ddr4_nib_map },
678 	{ .sp_off = SPD_DDR4_MAP_DQ40, .sp_key = SPD_KEY_DDR4_MAP_DQ40,
679 	    .sp_parse = spd_parse_ddr4_nib_map },
680 	{ .sp_off = SPD_DDR4_MAP_DQ44, .sp_key = SPD_KEY_DDR4_MAP_DQ44,
681 	    .sp_parse = spd_parse_ddr4_nib_map },
682 	{ .sp_off = SPD_DDR4_MAP_DQ48, .sp_key = SPD_KEY_DDR4_MAP_DQ48,
683 	    .sp_parse = spd_parse_ddr4_nib_map },
684 	{ .sp_off = SPD_DDR4_MAP_DQ52, .sp_key = SPD_KEY_DDR4_MAP_DQ52,
685 	    .sp_parse = spd_parse_ddr4_nib_map },
686 	{ .sp_off = SPD_DDR4_MAP_DQ56, .sp_key = SPD_KEY_DDR4_MAP_DQ56,
687 	    .sp_parse = spd_parse_ddr4_nib_map },
688 	{ .sp_off = SPD_DDR4_MAP_DQ60, .sp_key = SPD_KEY_DDR4_MAP_DQ60,
689 	    .sp_parse = spd_parse_ddr4_nib_map },
690 	{ .sp_len = SPD_DDR4_CRC_MSB + 1, .sp_key = SPD_KEY_CRC_DDR4_BASE,
691 	    .sp_parse = spd_parse_crc },
692 };
693 
694 static const spd_parse_t spd_ddr4_mfg[] = {
695 	{ .sp_off = SPD_DDR4_MOD_MFG_ID0, .sp_len = 2,
696 	    .sp_key = SPD_KEY_MFG_MOD_MFG_ID,
697 	    .sp_parse = spd_parse_jedec_id },
698 	{ .sp_off = SPD_DDR4_MOD_MFG_ID0, .sp_len = 2,
699 	    .sp_key = SPD_KEY_MFG_MOD_MFG_NAME,
700 	    .sp_parse = spd_parse_jedec_id_str },
701 	{ .sp_off = SPD_DDR4_DRAM_MFG_ID0, .sp_len = 2,
702 	    .sp_key = SPD_KEY_MFG_DRAM_MFG_ID,
703 	    .sp_parse = spd_parse_jedec_id },
704 	{ .sp_off = SPD_DDR4_DRAM_MFG_ID0, .sp_len = 2,
705 	    .sp_key = SPD_KEY_MFG_DRAM_MFG_NAME,
706 	    .sp_parse = spd_parse_jedec_id_str },
707 	{ .sp_off = SPD_DDR4_MOD_MFG_LOC, .sp_key = SPD_KEY_MFG_MOD_LOC_ID,
708 	    .sp_parse = spd_parse_raw_u8 },
709 	{ .sp_off = SPD_DDR4_MOD_MFG_YEAR, .sp_key = SPD_KEY_MFG_MOD_YEAR,
710 	    .sp_parse = spd_parse_hex_string },
711 	{ .sp_off = SPD_DDR4_MOD_MFG_WEEK, .sp_key = SPD_KEY_MFG_MOD_WEEK,
712 	    .sp_parse = spd_parse_hex_string },
713 	{ .sp_off = SPD_DDR4_MOD_SN, .sp_len = SPD_DDR4_MOD_SN_LEN,
714 	    .sp_key = SPD_KEY_MFG_MOD_SN, .sp_parse = spd_parse_hex_string },
715 	{ .sp_off = SPD_DDR4_MOD_PN, .sp_len = SPD_DDR4_MOD_PN_LEN,
716 	    .sp_key = SPD_KEY_MFG_MOD_PN, .sp_parse = spd_parse_string },
717 	{ .sp_off = SPD_DDR4_MOD_REV, .sp_key = SPD_KEY_MFG_MOD_REV,
718 	    .sp_parse = spd_parse_dram_step },
719 	{ .sp_off = SPD_DDR4_DRAM_STEP, .sp_key = SPD_KEY_MFG_DRAM_STEP,
720 	    .sp_parse = spd_parse_dram_step },
721 };
722 
723 /*
724  * The offsets and values for design information are identical across DDR4 and
725  * the LPDDR3/4/4X SPD data.
726  */
727 void
spd_parse_ddr4_design(spd_info_t * si,uint32_t off,uint32_t len,const char * key)728 spd_parse_ddr4_design(spd_info_t *si, uint32_t off, uint32_t len,
729     const char *key)
730 {
731 	ASSERT3U(off, >=, SPD_DDR4_RDIMM_HEIGHT);
732 	return (spd_parse_design(si, off, SPD_DDR4_RDIMM_HEIGHT));
733 }
734 
735 static void
spd_parse_ddr4_edge(spd_info_t * si,uint32_t off,uint32_t len,const char * key)736 spd_parse_ddr4_edge(spd_info_t *si, uint32_t off, uint32_t len,
737     const char *key)
738 {
739 	const uint8_t data = si->si_data[off];
740 
741 	if (SPD_DDR4_RDIMM_MAP_R1(data) != 0)
742 		spd_nvl_insert_key(si, SPD_KEY_MOD_EDGE_MIRROR);
743 }
744 
745 /*
746  * DDR4 UDIMM specific processing.
747  */
748 static const spd_parse_t spd_ddr4_udimm[] = {
749 	{ .sp_off = SPD_DDR4_UDIMM_HEIGHT, .sp_key = SPD_KEY_MOD_HEIGHT,
750 	    .sp_parse = spd_parse_height },
751 	{ .sp_off = SPD_DDR4_UDIMM_THICK, .sp_parse = spd_parse_thickness },
752 	{ .sp_off = SPD_DDR4_UDIMM_REF, .sp_parse = spd_parse_ddr4_design },
753 	{ .sp_off = SPD_DDR4_UDIMM_MAP, .sp_parse = spd_parse_ddr4_edge },
754 	{ .sp_off = SPD_DDR4_BLK1_CRC_START, .sp_len = SPD_DDR4_BLK1_CRC_MSB +
755 	    1 - SPD_DDR4_BLK1_CRC_START, .sp_key = SPD_KEY_CRC_DDR4_BLK1,
756 	    .sp_parse = spd_parse_crc }
757 };
758 
759 /*
760  * DDR4 RDIMM specific processing.
761  */
762 static const spd_value_map_t spd_ddr4_rcd_type_map[] = {
763 	{ SPD_DDR4_RDIMM_ATTR_TYPE_RCD01, SPD_RCD_T_DDR4RCD01, false },
764 	{ SPD_DDR4_RDIMM_ATTR_TYPE_RCD02, SPD_RCD_T_DDR4RCD02, false },
765 };
766 
767 static void
spd_parse_ddr4_rdimm_attr(spd_info_t * si,uint32_t off,uint32_t len,const char * key)768 spd_parse_ddr4_rdimm_attr(spd_info_t *si, uint32_t off, uint32_t len,
769     const char *key)
770 {
771 	const uint8_t data = si->si_data[off];
772 	const uint8_t rcd = SPD_DDR4_RDIMM_ATTR_TYPE(data);
773 	const uint8_t nrow = 1 << (SPD_DDR4_RDIMM_ATTR_NROWS(data) - 1);
774 	const uint8_t nreg = 1 << (SPD_DDR4_RDIMM_ATTR_NREGS(data) - 1);
775 
776 	spd_upsert_flag(si, SPD_KEY_DEVS, SPD_DEVICE_RCD);
777 	spd_insert_map(si, SPD_KEY_DEV_RCD_TYPE, rcd,
778 	    spd_ddr4_rcd_type_map, ARRAY_SIZE(spd_ddr4_rcd_type_map));
779 	if (nrow != 0)
780 		spd_nvl_insert_u32(si, SPD_KEY_MOD_NROWS, nrow);
781 	if (nreg != 0)
782 		spd_nvl_insert_u32(si, SPD_KEY_MOD_NREGS, nreg);
783 }
784 
785 static void
spd_parse_ddr4_rdimm_therm(spd_info_t * si,uint32_t off,uint32_t len,const char * key)786 spd_parse_ddr4_rdimm_therm(spd_info_t *si, uint32_t off, uint32_t len,
787     const char *key)
788 {
789 	const uint8_t data = si->si_data[off];
790 
791 	if (SPD_DDR4_RDIMM_THERM_IMPL(data) != 0)
792 		spd_upsert_flag(si, SPD_KEY_DEVS, SPD_DEVICE_HS);
793 }
794 
795 static void
spd_parse_ddr4_rdimm_rcd_mfg(spd_info_t * si,uint32_t off,uint32_t len,const char * key)796 spd_parse_ddr4_rdimm_rcd_mfg(spd_info_t *si, uint32_t off, uint32_t len,
797     const char *key)
798 {
799 	ASSERT3U(len, ==, 2);
800 
801 	spd_parse_jedec_id(si, off, 2, SPD_KEY_DEV_RCD_MFG);
802 	spd_parse_jedec_id_str(si, off, 2, SPD_KEY_DEV_RCD_MFG_NAME);
803 }
804 
805 static const spd_value_map_t spd_ddr4_rdimm_ods_map[] = {
806 	{ SPD_DDR4_RDIMM_ODS0_LIGHT, SPD_DRIVE_LIGHT, false },
807 	{ SPD_DDR4_RDIMM_ODS0_MODERATE, SPD_DRIVE_MODERATE, false },
808 	{ SPD_DDR4_RDIMM_ODS0_STRONG, SPD_DRIVE_STRONG, false },
809 	{ SPD_DDR4_RDIMM_ODS0_VERY_STRONG, SPD_DRIVE_VERY_STRONG, false },
810 };
811 
812 static void
spd_parse_ddr4_rdimm_ods(spd_info_t * si,uint32_t off,uint32_t len,const char * key)813 spd_parse_ddr4_rdimm_ods(spd_info_t *si, uint32_t off, uint32_t len,
814     const char *key)
815 {
816 	const uint8_t ods0 = si->si_data[off];
817 	const uint8_t ods1 = si->si_data[off + 1];
818 	const uint8_t cs = SPD_DDR4_RDIMM_ODS0_CS(ods0);
819 	const uint8_t ca = SPD_DDR4_RDIMM_ODS0_CA(ods0);
820 	const uint8_t odt = SPD_DDR4_RDIMM_ODS0_ODT(ods0);
821 	const uint8_t cke = SPD_DDR4_RDIMM_ODS0_CKE(ods0);
822 	const uint8_t y1 = SPD_DDR4_RDIMM_ODS1_Y1(ods1);
823 	const uint8_t y0 = SPD_DDR4_RDIMM_ODS1_Y0(ods1);
824 
825 	spd_insert_map(si, SPD_KEY_DDR4_RCD_DS_CKE, cke, spd_ddr4_rdimm_ods_map,
826 	    ARRAY_SIZE(spd_ddr4_rdimm_ods_map));
827 	spd_insert_map(si, SPD_KEY_DDR4_RCD_DS_ODT, odt, spd_ddr4_rdimm_ods_map,
828 	    ARRAY_SIZE(spd_ddr4_rdimm_ods_map));
829 	spd_insert_map(si, SPD_KEY_DDR4_RCD_DS_CA, ca, spd_ddr4_rdimm_ods_map,
830 	    ARRAY_SIZE(spd_ddr4_rdimm_ods_map));
831 	spd_insert_map(si, SPD_KEY_DDR4_RCD_DS_CS, cs, spd_ddr4_rdimm_ods_map,
832 	    ARRAY_SIZE(spd_ddr4_rdimm_ods_map));
833 	spd_insert_map(si, SPD_KEY_DDR4_RCD_DS_Y0, y0, spd_ddr4_rdimm_ods_map,
834 	    ARRAY_SIZE(spd_ddr4_rdimm_ods_map));
835 	spd_insert_map(si, SPD_KEY_DDR4_RCD_DS_Y1, y1, spd_ddr4_rdimm_ods_map,
836 	    ARRAY_SIZE(spd_ddr4_rdimm_ods_map));
837 
838 	if (SPD_DDR4_RDIMM_ODS1_SLEW_SUP(ods1) != 0)
839 		spd_nvl_insert_key(si, SPD_KEY_DDR4_RCD_SLEW);
840 }
841 
842 static const spd_parse_t spd_ddr4_rdimm[] = {
843 	{ .sp_off = SPD_DDR4_RDIMM_HEIGHT, .sp_key = SPD_KEY_MOD_HEIGHT,
844 	    .sp_parse = spd_parse_height },
845 	{ .sp_off = SPD_DDR4_RDIMM_THICK, .sp_parse = spd_parse_thickness },
846 	{ .sp_off = SPD_DDR4_RDIMM_REF, .sp_parse = spd_parse_ddr4_design },
847 	{ .sp_off = SPD_DDR4_RDIMM_ATTR,
848 	    .sp_parse = spd_parse_ddr4_rdimm_attr },
849 	{ .sp_off = SPD_DDR4_RDIMM_THERM,
850 	    .sp_parse = spd_parse_ddr4_rdimm_therm },
851 	{ .sp_off = SPD_DDR4_RDIMM_REG_MFG_ID0, .sp_len = 2,
852 	    .sp_parse = spd_parse_ddr4_rdimm_rcd_mfg },
853 	{ .sp_off = SPD_DDR4_RDIMM_REV, .sp_key = SPD_KEY_DEV_RCD_REV,
854 	    .sp_parse = spd_parse_dram_step },
855 	{ .sp_off = SPD_DDR4_RDIMM_MAP, .sp_parse = spd_parse_ddr4_edge },
856 	{ .sp_off = SPD_DDR4_RDIMM_ODS0, .sp_len = 2,
857 	    .sp_parse = spd_parse_ddr4_rdimm_ods },
858 	{ .sp_off = SPD_DDR4_BLK1_CRC_START, .sp_len = SPD_DDR4_BLK1_CRC_MSB +
859 	    1 - SPD_DDR4_BLK1_CRC_START, .sp_key = SPD_KEY_CRC_DDR4_BLK1,
860 	    .sp_parse = spd_parse_crc }
861 };
862 
863 /*
864  * DDR4 LRDIMM specific processing.
865  */
866 static const spd_value_map_t spd_ddr4_db_type_map[] = {
867 	{ SPD_DDR4_LRDIMM_ATTR_TYPE_RCD01_DB01, SPD_RCD_T_DDR4RCD01, false },
868 	{ SPD_DDR4_LRDIMM_ATTR_TYPE_RCD02_DB02, SPD_RCD_T_DDR4RCD02, false },
869 };
870 
871 /*
872  * We use value maps for these LRDIMM properties because they're a bit
873  * inconsistent and this gets us out of a lot of if statements. The RDIMM code
874  * doesn't have this problem because all of the values are valid.
875  */
876 static const spd_value_map_t spd_ddr4_lrdimm_nrows_map[] = {
877 	{ 0, 0, true },
878 	{ 1, 1, false },
879 	{ 2, 2, false }
880 };
881 
882 static const spd_value_map_t spd_ddr4_lrdimm_nregs_map[] = {
883 	{ 0, 0, true },
884 	{ 1, 1, false }
885 };
886 
887 static void
spd_parse_ddr4_lrdimm_attr(spd_info_t * si,uint32_t off,uint32_t len,const char * key)888 spd_parse_ddr4_lrdimm_attr(spd_info_t *si, uint32_t off, uint32_t len,
889     const char *key)
890 {
891 	const uint8_t data = si->si_data[off];
892 	const uint8_t rcd = SPD_DDR4_LRDIMM_ATTR_TYPE(data);
893 	const uint8_t nrow = SPD_DDR4_LRDIMM_ATTR_NROWS(data);
894 	const uint8_t nreg = SPD_DDR4_LRDIMM_ATTR_NREGS(data);
895 
896 	/*
897 	 * The type defines both the RCD and the DB. The RCD types overlap with
898 	 * RDIMMs.
899 	 */
900 	spd_upsert_flag(si, SPD_KEY_DEVS, SPD_DEVICE_RCD | SPD_DEVICE_DB);
901 	spd_insert_map(si, SPD_KEY_DEV_RCD_TYPE, rcd,
902 	    spd_ddr4_rcd_type_map, ARRAY_SIZE(spd_ddr4_rcd_type_map));
903 	spd_insert_map(si, SPD_KEY_DEV_DB_TYPE, rcd,
904 	    spd_ddr4_db_type_map, ARRAY_SIZE(spd_ddr4_db_type_map));
905 	spd_insert_map(si, SPD_KEY_MOD_NROWS, nrow, spd_ddr4_lrdimm_nrows_map,
906 	    ARRAY_SIZE(spd_ddr4_lrdimm_nrows_map));
907 	spd_insert_map(si, SPD_KEY_MOD_NREGS, nreg, spd_ddr4_lrdimm_nregs_map,
908 	    ARRAY_SIZE(spd_ddr4_lrdimm_nregs_map));
909 }
910 
911 /*
912  * The LRDIMM manufacturer here covers both the register and the data buffer, so
913  * we end up setting the same values for both.
914  */
915 static void
spd_parse_ddr4_lrdimm_rcd_mfg(spd_info_t * si,uint32_t off,uint32_t len,const char * key)916 spd_parse_ddr4_lrdimm_rcd_mfg(spd_info_t *si, uint32_t off, uint32_t len,
917     const char *key)
918 {
919 	ASSERT3U(len, ==, 2);
920 
921 	spd_parse_jedec_id(si, off, 2, SPD_KEY_DEV_RCD_MFG);
922 	spd_parse_jedec_id_str(si, off, 2, SPD_KEY_DEV_RCD_MFG_NAME);
923 	spd_parse_jedec_id(si, off, 2, SPD_KEY_DEV_DB_MFG);
924 	spd_parse_jedec_id_str(si, off, 2, SPD_KEY_DEV_DB_MFG_NAME);
925 }
926 
927 static const spd_value_map_t spd_ddr4_lrdimm_ods_map[] = {
928 	{ SPD_DDR4_LRDIMM_ODS1_MODERATE, SPD_DRIVE_MODERATE, false },
929 	{ SPD_DDR4_LRDIMM_ODS1_STRONG, SPD_DRIVE_STRONG, false }
930 };
931 
932 static void
spd_parse_ddr4_lrdimm_ods(spd_info_t * si,uint32_t off,uint32_t len,const char * key)933 spd_parse_ddr4_lrdimm_ods(spd_info_t *si, uint32_t off, uint32_t len,
934     const char *key)
935 {
936 	const uint8_t data = si->si_data[off];
937 	const uint8_t bck = SPD_DDR4_LRDIMM_ODS1_BCK(data);
938 	const uint8_t bcom = SPD_DDR4_LRDIMM_ODS1_BCOM(data);
939 
940 	spd_insert_map(si, SPD_KEY_DDR4_RCD_DS_BCOM, bcom,
941 	    spd_ddr4_lrdimm_ods_map, ARRAY_SIZE(spd_ddr4_lrdimm_ods_map));
942 	spd_insert_map(si, SPD_KEY_DDR4_RCD_DS_BCK, bck,
943 	    spd_ddr4_lrdimm_ods_map, ARRAY_SIZE(spd_ddr4_lrdimm_ods_map));
944 }
945 
946 /*
947  * There are two VrefDQ ranges in the DDR4 specs. These all increase at 0.65%
948  * increments, hence our mult as 65.
949  */
950 static const spd_value_range_t spd_ddr4_vrefdq1_range = {
951 	.svr_base = 6000,
952 	.svr_mult = 65,
953 	.svr_max = 9250
954 };
955 
956 static const spd_value_range_t spd_ddr4_vrefdq2_range = {
957 	.svr_base = 4500,
958 	.svr_mult = 65,
959 	.svr_max = 7750
960 };
961 
962 static void
spd_parse_ddr4_vrefdq_common(spd_info_t * si,uint8_t range,uint8_t val,const char * key)963 spd_parse_ddr4_vrefdq_common(spd_info_t *si, uint8_t range, uint8_t val,
964     const char *key)
965 {
966 	if (range == SPD_DDR4_LRDIMM_VERFDQ_RNG_1) {
967 		spd_insert_range(si, key, val, &spd_ddr4_vrefdq1_range);
968 	} else {
969 		ASSERT3U(range, ==, SPD_DDR4_LRDIMM_VERFDQ_RNG_2);
970 		spd_insert_range(si, key, val, &spd_ddr4_vrefdq2_range);
971 	}
972 }
973 
974 static void
spd_parse_ddr4_lrdimm_vrefdq_r0(spd_info_t * si,uint32_t off,uint32_t len,const char * key)975 spd_parse_ddr4_lrdimm_vrefdq_r0(spd_info_t *si, uint32_t off, uint32_t len,
976     const char *key)
977 {
978 	const uint8_t data = si->si_data[off];
979 	const uint8_t volt = SPD_DDR4_LRDIMM_VREFDQ_V(data);
980 	const uint8_t range = si->si_data[off + len - 1];
981 
982 	spd_parse_ddr4_vrefdq_common(si, SPD_DDR4_LRDIMM_VREFDQ_RNG_R0(range),
983 	    volt, key);
984 }
985 
986 static void
spd_parse_ddr4_lrdimm_vrefdq_r1(spd_info_t * si,uint32_t off,uint32_t len,const char * key)987 spd_parse_ddr4_lrdimm_vrefdq_r1(spd_info_t *si, uint32_t off, uint32_t len,
988     const char *key)
989 {
990 	const uint8_t data = si->si_data[off];
991 	const uint8_t volt = SPD_DDR4_LRDIMM_VREFDQ_V(data);
992 	const uint8_t range = si->si_data[off + len];
993 
994 	spd_parse_ddr4_vrefdq_common(si, SPD_DDR4_LRDIMM_VREFDQ_RNG_R1(range),
995 	    volt, key);
996 }
997 
998 static void
spd_parse_ddr4_lrdimm_vrefdq_r2(spd_info_t * si,uint32_t off,uint32_t len,const char * key)999 spd_parse_ddr4_lrdimm_vrefdq_r2(spd_info_t *si, uint32_t off, uint32_t len,
1000     const char *key)
1001 {
1002 	const uint8_t data = si->si_data[off];
1003 	const uint8_t volt = SPD_DDR4_LRDIMM_VREFDQ_V(data);
1004 	const uint8_t range = si->si_data[off + len];
1005 
1006 	spd_parse_ddr4_vrefdq_common(si, SPD_DDR4_LRDIMM_VREFDQ_RNG_R2(range),
1007 	    volt, key);
1008 }
1009 
1010 static void
spd_parse_ddr4_lrdimm_vrefdq_r3(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1011 spd_parse_ddr4_lrdimm_vrefdq_r3(spd_info_t *si, uint32_t off, uint32_t len,
1012     const char *key)
1013 {
1014 	const uint8_t data = si->si_data[off];
1015 	const uint8_t volt = SPD_DDR4_LRDIMM_VREFDQ_V(data);
1016 	const uint8_t range = si->si_data[off + len];
1017 
1018 	spd_parse_ddr4_vrefdq_common(si, SPD_DDR4_LRDIMM_VREFDQ_RNG_R3(range),
1019 	    volt, key);
1020 }
1021 
1022 static void
spd_parse_ddr4_lrdimm_vrefdq_db(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1023 spd_parse_ddr4_lrdimm_vrefdq_db(spd_info_t *si, uint32_t off, uint32_t len,
1024     const char *key)
1025 {
1026 	const uint8_t data = si->si_data[off];
1027 	const uint8_t range = si->si_data[off + len];
1028 
1029 	spd_parse_ddr4_vrefdq_common(si, SPD_DDR4_LRDIMM_VREFDQ_RNG_DB(range),
1030 	    data, key);
1031 }
1032 
1033 static const spd_value_map_t spd_ddr4_mdq_ds_map[] = {
1034 	{ SPD_DDR4_LRDIMM_MDQ_DS_40R, 40, false },
1035 	{ SPD_DDR4_LRDIMM_MDQ_DS_34R, 34, false },
1036 	{ SPD_DDR4_LRDIMM_MDQ_DS_48R, 48, false },
1037 	{ SPD_DDR4_LRDIMM_MDQ_DS_60R, 60, false }
1038 };
1039 
1040 static const spd_value_map_t spd_ddr4_rtt_map[] = {
1041 	{ SPD_DDR4_LRDIMM_MDQ_RTT_DIS, SPD_TERM_DISABLED, false },
1042 	{ SPD_DDR4_LRDIMM_MDQ_RTT_60R, 60, false },
1043 	{ SPD_DDR4_LRDIMM_MDQ_RTT_120R, 120, false },
1044 	{ SPD_DDR4_LRDIMM_MDQ_RTT_40R, 40, false },
1045 	{ SPD_DDR4_LRDIMM_MDQ_RTT_240R, 240, false },
1046 	{ SPD_DDR4_LRDIMM_MDQ_RTT_48R, 48, false },
1047 	{ SPD_DDR4_LRDIMM_MDQ_RTT_80R, 80, false },
1048 	{ SPD_DDR4_LRDIMM_MDQ_RTT_34R, 34, false },
1049 };
1050 
1051 static void
spd_parse_ddr4_lrdimm_mdq(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1052 spd_parse_ddr4_lrdimm_mdq(spd_info_t *si, uint32_t off, uint32_t len,
1053     const char *key)
1054 {
1055 	const uint8_t d1866 = si->si_data[off];
1056 	const uint8_t d2400 = si->si_data[off + 1];
1057 	const uint8_t d3200 = si->si_data[off + 2];
1058 	const uint8_t rtt[3] = { SPD_DDR4_LRDIMM_MDQ_RTT(d1866),
1059 	    SPD_DDR4_LRDIMM_MDQ_RTT(d2400), SPD_DDR4_LRDIMM_MDQ_RTT(d3200) };
1060 	const uint8_t ds[3] = { SPD_DDR4_LRDIMM_MDQ_DS(d1866),
1061 	    SPD_DDR4_LRDIMM_MDQ_DS(d2400), SPD_DDR4_LRDIMM_MDQ_DS(d3200) };
1062 
1063 	spd_insert_map_array(si, SPD_KEY_DDR4_MDQ_RTT, rtt, ARRAY_SIZE(rtt),
1064 	    spd_ddr4_rtt_map, ARRAY_SIZE(spd_ddr4_rtt_map));
1065 	spd_insert_map_array(si, SPD_KEY_DDR4_MDQ_DS, ds, ARRAY_SIZE(ds),
1066 	    spd_ddr4_mdq_ds_map, ARRAY_SIZE(spd_ddr4_mdq_ds_map));
1067 }
1068 
1069 static const spd_value_map_t spd_ddr4_dram_ds_map[] = {
1070 	{ SPD_DDR4_LRDIMM_DRAM_DS_34R, 34, false },
1071 	{ SPD_DDR4_LRDIMM_DRAM_DS_48R, 48, false }
1072 };
1073 
1074 static void
spd_parse_ddr4_lrdimm_dram(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1075 spd_parse_ddr4_lrdimm_dram(spd_info_t *si, uint32_t off, uint32_t len,
1076     const char *key)
1077 {
1078 	const uint8_t data = si->si_data[off];
1079 	const uint8_t ds[3] = {
1080 		SPD_DDR4_LRDIMM_DRAM_DS_1866(data),
1081 		SPD_DDR4_LRDIMM_DRAM_DS_2400(data),
1082 		SPD_DDR4_LRDIMM_DRAM_DS_3200(data)
1083 	};
1084 
1085 	spd_insert_map_array(si, SPD_KEY_DDR4_DRAM_DS, ds, ARRAY_SIZE(ds),
1086 	    spd_ddr4_dram_ds_map, ARRAY_SIZE(spd_ddr4_dram_ds_map));
1087 }
1088 
1089 static const spd_value_map_t spd_ddr4_rtt_wr_map[] = {
1090 	{ SPD_DDR4_LRDIMM_ODT_WR_DYN_OFF, SPD_TERM_DISABLED, false },
1091 	{ SPD_DDR4_LRDIMM_ODT_WR_120R, 120, false },
1092 	{ SPD_DDR4_LRDIMM_ODT_WR_240R, 240, false },
1093 	{ SPD_DDR4_LRDIMM_ODT_WR_HIZ, SPD_TERM_HIZ, false },
1094 	{ SPD_DDR4_LRDIMM_ODT_WR_80R, 80, false },
1095 };
1096 
1097 static void
spd_parse_ddr4_lrdimm_odt(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1098 spd_parse_ddr4_lrdimm_odt(spd_info_t *si, uint32_t off, uint32_t len,
1099     const char *key)
1100 {
1101 	const uint8_t d1866 = si->si_data[off];
1102 	const uint8_t d2400 = si->si_data[off + 1];
1103 	const uint8_t d3200 = si->si_data[off + 2];
1104 	const uint8_t nom[3] = { SPD_DDR4_LRDIMM_ODT_NOM(d1866),
1105 	    SPD_DDR4_LRDIMM_ODT_NOM(d2400), SPD_DDR4_LRDIMM_ODT_NOM(d3200) };
1106 	const uint8_t wr[3] = { SPD_DDR4_LRDIMM_ODT_WR(d1866),
1107 	    SPD_DDR4_LRDIMM_ODT_WR(d2400), SPD_DDR4_LRDIMM_ODT_WR(d3200) };
1108 
1109 	spd_insert_map_array(si, SPD_KEY_DDR4_RTT_NOM, nom, ARRAY_SIZE(nom),
1110 	    spd_ddr4_rtt_map, ARRAY_SIZE(spd_ddr4_rtt_map));
1111 	spd_insert_map_array(si, SPD_KEY_DDR4_RTT_WR, wr, ARRAY_SIZE(wr),
1112 	    spd_ddr4_rtt_wr_map, ARRAY_SIZE(spd_ddr4_rtt_wr_map));
1113 }
1114 
1115 static void
spd_parse_ddr4_lrdimm_park(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1116 spd_parse_ddr4_lrdimm_park(spd_info_t *si, uint32_t off, uint32_t len,
1117     const char *key)
1118 {
1119 	const uint8_t d1866 = si->si_data[off];
1120 	const uint8_t d2400 = si->si_data[off + 1];
1121 	const uint8_t d3200 = si->si_data[off + 2];
1122 	const uint8_t r01[3] = { SPD_DDR4_LRDIMM_PARK_R01(d1866),
1123 	    SPD_DDR4_LRDIMM_PARK_R01(d2400), SPD_DDR4_LRDIMM_PARK_R01(d3200) };
1124 	const uint8_t r23[3] = { SPD_DDR4_LRDIMM_PARK_R23(d1866),
1125 	    SPD_DDR4_LRDIMM_PARK_R23(d2400), SPD_DDR4_LRDIMM_PARK_R23(d3200) };
1126 
1127 	spd_insert_map_array(si, SPD_KEY_DDR4_RTT_PARK_R0, r01, ARRAY_SIZE(r01),
1128 	    spd_ddr4_rtt_map, ARRAY_SIZE(spd_ddr4_rtt_map));
1129 	spd_insert_map_array(si, SPD_KEY_DDR4_RTT_PARK_R2, r23, ARRAY_SIZE(r23),
1130 	    spd_ddr4_rtt_map, ARRAY_SIZE(spd_ddr4_rtt_map));
1131 }
1132 
1133 static void
spd_parse_ddr4_lrdimm_dfe(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1134 spd_parse_ddr4_lrdimm_dfe(spd_info_t *si, uint32_t off, uint32_t len,
1135     const char *key)
1136 {
1137 	const uint8_t data = si->si_data[off];
1138 
1139 	if (SPD_DDR4_LRDIMM_EQ_DFE_SUP(data) != 0)
1140 		spd_nvl_insert_key(si, SPD_KEY_DDR4_DB_DFE);
1141 	if (SPD_DDR4_LRDIMM_EQ_GA_SUP(data) != 0)
1142 		spd_nvl_insert_key(si, SPD_KEY_DDR4_DB_GAIN);
1143 }
1144 
1145 static const spd_parse_t spd_ddr4_lrdimm[] = {
1146 	{ .sp_off = SPD_DDR4_LRDIMM_HEIGHT, .sp_key = SPD_KEY_MOD_HEIGHT,
1147 	    .sp_parse = spd_parse_height },
1148 	{ .sp_off = SPD_DDR4_LRDIMM_THICK, .sp_parse = spd_parse_thickness },
1149 	{ .sp_off = SPD_DDR4_LRDIMM_REF, .sp_parse = spd_parse_ddr4_design },
1150 	{ .sp_off = SPD_DDR4_LRDIMM_ATTR,
1151 	    .sp_parse = spd_parse_ddr4_lrdimm_attr },
1152 	{ .sp_off = SPD_DDR4_LRDIMM_THERM,
1153 	    .sp_parse = spd_parse_ddr4_rdimm_therm },
1154 	{ .sp_off = SPD_DDR4_LRDIMM_REG_MFG_ID0, .sp_len = 2,
1155 	    .sp_parse = spd_parse_ddr4_lrdimm_rcd_mfg },
1156 	{ .sp_off = SPD_DDR4_LRDIMM_REV, .sp_key = SPD_KEY_DEV_RCD_REV,
1157 	    .sp_parse = spd_parse_dram_step },
1158 	{ .sp_off = SPD_DDR4_LRDIMM_MAP, .sp_parse = spd_parse_ddr4_edge },
1159 	/*
1160 	 * The LRDIMM output drive strength is equivalent to the RDIMM, so we
1161 	 * use that. For ODS1, we fire it a second-time to get just the
1162 	 * LRDIMM-specific fields.
1163 	 */
1164 	{ .sp_off = SPD_DDR4_LRDIMM_ODS0, .sp_len = 2,
1165 	    .sp_parse = spd_parse_ddr4_rdimm_ods },
1166 	{ .sp_off = SPD_DDR4_LRDIMM_ODS1,
1167 	    .sp_parse = spd_parse_ddr4_lrdimm_ods },
1168 	{ .sp_off = SPD_DDR4_LRDIMM_DB_REV,  .sp_key = SPD_KEY_DEV_DB_REV,
1169 	    .sp_parse = spd_parse_dram_step },
1170 	/*
1171 	 * The five VrefDQ values (four ranks and data buffer) require the range
1172 	 * byte to determine which base set of values to use. This is why they
1173 	 * all have the long length to ensure we account for that.
1174 	 */
1175 	{ .sp_off = SPD_DDR4_LRDIMM_VREFDQ0, .sp_key = SPD_KEY_DDR4_VREFDQ_R0,
1176 	    .sp_len = SPD_DDR4_LRDIMM_VREFDQ_RNG - SPD_DDR4_LRDIMM_VREFDQ0 + 1,
1177 	    .sp_parse = spd_parse_ddr4_lrdimm_vrefdq_r0 },
1178 	{ .sp_off = SPD_DDR4_LRDIMM_VREFDQ1, .sp_key = SPD_KEY_DDR4_VREFDQ_R1,
1179 	    .sp_len = SPD_DDR4_LRDIMM_VREFDQ_RNG - SPD_DDR4_LRDIMM_VREFDQ1 + 1,
1180 	    .sp_parse = spd_parse_ddr4_lrdimm_vrefdq_r1 },
1181 
1182 	{ .sp_off = SPD_DDR4_LRDIMM_VREFDQ2, .sp_key = SPD_KEY_DDR4_VREFDQ_R2,
1183 	    .sp_len = SPD_DDR4_LRDIMM_VREFDQ_RNG - SPD_DDR4_LRDIMM_VREFDQ2 + 1,
1184 	    .sp_parse = spd_parse_ddr4_lrdimm_vrefdq_r2 },
1185 
1186 	{ .sp_off = SPD_DDR4_LRDIMM_VREFDQ3, .sp_key = SPD_KEY_DDR4_VREFDQ_R3,
1187 	    .sp_len = SPD_DDR4_LRDIMM_VREFDQ_RNG - SPD_DDR4_LRDIMM_VREFDQ3 + 1,
1188 	    .sp_parse = spd_parse_ddr4_lrdimm_vrefdq_r3 },
1189 
1190 	{ .sp_off = SPD_DDR4_LRDIMM_VREFDQ_DB, .sp_key = SPD_KEY_DDR4_VREFDQ_DB,
1191 	    .sp_len = SPD_DDR4_LRDIMM_VREFDQ_RNG - SPD_DDR4_LRDIMM_VREFDQ_DB +
1192 	    1, .sp_parse = spd_parse_ddr4_lrdimm_vrefdq_db },
1193 	{ .sp_off = SPD_DDR4_LRDIMM_MDQ_1866, .sp_len = 3,
1194 	    .sp_parse = spd_parse_ddr4_lrdimm_mdq },
1195 	{ .sp_off = SPD_DDR4_LRDIMM_DRAM_DS,
1196 	    .sp_parse = spd_parse_ddr4_lrdimm_dram },
1197 	{ .sp_off = SPD_DDR4_LRDIMM_ODT_1866, .sp_len = 3,
1198 	    .sp_parse = spd_parse_ddr4_lrdimm_odt },
1199 	{ .sp_off = SPD_DDR4_LRDIMM_PARK_1866, .sp_len = 3,
1200 	    .sp_parse = spd_parse_ddr4_lrdimm_park },
1201 	{ .sp_off = SPD_DDR4_LRDIMM_EQ, .sp_parse = spd_parse_ddr4_lrdimm_dfe },
1202 	{ .sp_off = SPD_DDR4_BLK1_CRC_START, .sp_len = SPD_DDR4_BLK1_CRC_MSB +
1203 	    1 - SPD_DDR4_BLK1_CRC_START, .sp_key = SPD_KEY_CRC_DDR4_BLK1,
1204 	    .sp_parse = spd_parse_crc }
1205 };
1206 
1207 static void
spd_parse_ddr4_mod_specific(spd_info_t * si)1208 spd_parse_ddr4_mod_specific(spd_info_t *si)
1209 {
1210 	uint32_t type;
1211 
1212 	if (nvlist_lookup_uint32(si->si_nvl, SPD_KEY_MOD_TYPE, &type) != 0)
1213 		return;
1214 
1215 	switch (type) {
1216 	case SPD_MOD_TYPE_RDIMM:
1217 	case SPD_MOD_TYPE_MINI_RDIMM:
1218 	case SPD_MOD_TYPE_72b_SO_RDIMM:
1219 		spd_parse(si, spd_ddr4_rdimm, ARRAY_SIZE(spd_ddr4_rdimm));
1220 		break;
1221 	case SPD_MOD_TYPE_LRDIMM:
1222 		spd_parse(si, spd_ddr4_lrdimm, ARRAY_SIZE(spd_ddr4_lrdimm));
1223 		break;
1224 	case SPD_MOD_TYPE_UDIMM:
1225 	case SPD_MOD_TYPE_SODIMM:
1226 	case SPD_MOD_TYPE_MINI_UDIMM:
1227 	case SPD_MOD_TYPE_72b_SO_UDIMM:
1228 	case SPD_MOD_TYPE_16b_SO_DIMM:
1229 	case SPD_MOD_TYPE_32b_SO_DIMM:
1230 		spd_parse(si, spd_ddr4_udimm, ARRAY_SIZE(spd_ddr4_udimm));
1231 		break;
1232 	default:
1233 		break;
1234 	}
1235 }
1236 
1237 void
spd_parse_ddr4_mfg(spd_info_t * si)1238 spd_parse_ddr4_mfg(spd_info_t *si)
1239 {
1240 	spd_parse(si, spd_ddr4_mfg, ARRAY_SIZE(spd_ddr4_mfg));
1241 }
1242 
1243 /*
1244  * DDR4 processing.
1245  *
1246  *  1. Check that we know the encoding revision of the SPD.
1247  *  2. Capture the SPD module type information as we already have the dram type
1248  *     information.
1249  *  3. Attempt to parse everything. Note that we don't really use the device's
1250  *     notion of how much data should be present and only will attempt to parse
1251  *     regions if we have enough data from the user.
1252  */
1253 void
spd_parse_ddr4(spd_info_t * si)1254 spd_parse_ddr4(spd_info_t *si)
1255 {
1256 	if (SPD_DDR4_SPD_REV_ENC(si->si_data[SPD_DDR4_SPD_REV]) !=
1257 	    SPD_DDR4_SPD_REV_V1) {
1258 		si->si_error = LIBJEDEC_SPD_UNSUP_REV;
1259 		return;
1260 	}
1261 
1262 	/*
1263 	 * Parse DDR4 common attributes. Some overlay information. Then go
1264 	 * through and do the manufacturing info.
1265 	 */
1266 	spd_parse(si, spd_ddr4_common, ARRAY_SIZE(spd_ddr4_common));
1267 	spd_parse_ddr4_mod_specific(si);
1268 	spd_parse_ddr4_mfg(si);
1269 }
1270