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