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