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
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 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
spd_parse_ddr4_sec_pkg(spd_info_t * si,uint32_t off,uint32_t len,const char * key)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
spd_parse_ddr4_feat(spd_info_t * si,uint32_t off,uint32_t len,const char * key)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
spd_parse_ddr4_feat2(spd_info_t * si,uint32_t off,uint32_t len,const char * key)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
spd_parse_ddr4_volt(spd_info_t * si,uint32_t off,uint32_t len,const char * key)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
spd_parse_ddr4_mod_org(spd_info_t * si,uint32_t off,uint32_t len,const char * key)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
spd_parse_ddr4_bus_width(spd_info_t * si,uint32_t off,uint32_t len,const char * key)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
spd_parse_ddr4_therm(spd_info_t * si,uint32_t off,uint32_t len,const char * key)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
spd_parse_ddr4_ts(spd_info_t * si,uint32_t off,uint32_t len,const char * key)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
spd_parse_ddr4_time(spd_info_t * si,const char * key,uint8_t up_nib,uint8_t mtb,uint8_t ftb)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
spd_parse_ddr4_mtb_ftb(spd_info_t * si,uint32_t off,uint32_t len,const char * key)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
spd_parse_ddr4_mtb_pair(spd_info_t * si,uint32_t off,uint32_t len,const char * key)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
spd_parse_ddr4_tras(spd_info_t * si,uint32_t off,uint32_t len,const char * key)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
spd_parse_ddr4_trc(spd_info_t * si,uint32_t off,uint32_t len,const char * key)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
spd_parse_ddr4_tfaw(spd_info_t * si,uint32_t off,uint32_t len,const char * key)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
spd_parse_ddr4_twr(spd_info_t * si,uint32_t off,uint32_t len,const char * key)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
spd_parse_ddr4_twtrs(spd_info_t * si,uint32_t off,uint32_t len,const char * key)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
spd_parse_ddr4_twtrl(spd_info_t * si,uint32_t off,uint32_t len,const char * key)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
spd_parse_ddr4_cas(spd_info_t * si,uint32_t off,uint32_t len,const char * key)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
spd_parse_ddr4_nib_map(spd_info_t * si,uint32_t off,uint32_t len,const char * key)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
spd_parse_ddr4_design(spd_info_t * si,uint32_t off,uint32_t len,const char * key)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
spd_parse_ddr4_edge(spd_info_t * si,uint32_t off,uint32_t len,const char * key)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
spd_parse_ddr4_rdimm_attr(spd_info_t * si,uint32_t off,uint32_t len,const char * key)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
spd_parse_ddr4_rdimm_therm(spd_info_t * si,uint32_t off,uint32_t len,const char * key)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
spd_parse_ddr4_rdimm_rcd_mfg(spd_info_t * si,uint32_t off,uint32_t len,const char * key)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
spd_parse_ddr4_rdimm_ods(spd_info_t * si,uint32_t off,uint32_t len,const char * key)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
spd_parse_ddr4_lrdimm_attr(spd_info_t * si,uint32_t off,uint32_t len,const char * key)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
spd_parse_ddr4_lrdimm_rcd_mfg(spd_info_t * si,uint32_t off,uint32_t len,const char * key)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
spd_parse_ddr4_lrdimm_ods(spd_info_t * si,uint32_t off,uint32_t len,const char * key)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
spd_parse_ddr4_vrefdq_common(spd_info_t * si,uint8_t range,uint8_t val,const char * key)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
spd_parse_ddr4_lrdimm_vrefdq_r0(spd_info_t * si,uint32_t off,uint32_t len,const char * key)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
spd_parse_ddr4_lrdimm_vrefdq_r1(spd_info_t * si,uint32_t off,uint32_t len,const char * key)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
spd_parse_ddr4_lrdimm_vrefdq_r2(spd_info_t * si,uint32_t off,uint32_t len,const char * key)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
spd_parse_ddr4_lrdimm_vrefdq_r3(spd_info_t * si,uint32_t off,uint32_t len,const char * key)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
spd_parse_ddr4_lrdimm_vrefdq_db(spd_info_t * si,uint32_t off,uint32_t len,const char * key)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
spd_parse_ddr4_lrdimm_mdq(spd_info_t * si,uint32_t off,uint32_t len,const char * key)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
spd_parse_ddr4_lrdimm_dram(spd_info_t * si,uint32_t off,uint32_t len,const char * key)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
spd_parse_ddr4_lrdimm_odt(spd_info_t * si,uint32_t off,uint32_t len,const char * key)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
spd_parse_ddr4_lrdimm_park(spd_info_t * si,uint32_t off,uint32_t len,const char * key)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
spd_parse_ddr4_lrdimm_dfe(spd_info_t * si,uint32_t off,uint32_t len,const char * key)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
spd_parse_ddr4_mod_specific(spd_info_t * si)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
spd_parse_ddr4(spd_info_t * si)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