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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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