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 * DDR5-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_ddr5_nbytes_total_map[] = { 26 { SPD_DDR5_NBYTES_TOTAL_UNDEF, 0, true }, 27 { SPD_DDR5_NBYTES_TOTAL_256, 256, false }, 28 { SPD_DDR5_NBYTES_TOTAL_512, 512, false }, 29 { SPD_DDR5_NBYTES_TOTAL_1024, 1024, false }, 30 { SPD_DDR5_NBYTES_TOTAL_2048, 2048, false } 31 }; 32 33 static void 34 spd_parse_ddr5_nbytes(spd_info_t *si, uint32_t off, uint32_t len, 35 const char *key) 36 { 37 const uint8_t data = si->si_data[off]; 38 const uint8_t total = SPD_DDR5_NBYTES_TOTAL(data); 39 uint8_t beta = SPD_DDR5_NBYTES_BETA(data); 40 beta = bitset8(beta, 4, 4, SPD_DDR5_NBYTES_BETAHI(data)); 41 42 spd_nvl_insert_u32(si, SPD_KEY_BETA, beta); 43 spd_insert_map(si, SPD_KEY_NBYTES_TOTAL, total, 44 spd_ddr5_nbytes_total_map, ARRAY_SIZE(spd_ddr5_nbytes_total_map)); 45 } 46 47 static const spd_value_map_t spd_ddr5_mod_type_map[] = { 48 { SPD_DDR5_MOD_TYPE_TYPE_RDIMM, SPD_MOD_TYPE_RDIMM, false }, 49 { SPD_DDR5_MOD_TYPE_TYPE_UDIMM, SPD_MOD_TYPE_UDIMM, false }, 50 { SPD_DDR5_MOD_TYPE_TYPE_SODIMM, SPD_MOD_TYPE_SODIMM, false }, 51 { SPD_DDR5_MOD_TYPE_TYPE_LRDIMM, SPD_MOD_TYPE_LRDIMM, false }, 52 { SPD_DDR5_MOD_TYPE_TYPE_MRDIMM, SPD_MOD_TYPE_MRDIMM, false }, 53 { SPD_DDR5_MOD_TYPE_TYPE_DDIMM, SPD_MOD_TYPE_DDIMM, false }, 54 { SPD_DDR5_MOD_TYPE_TYPE_SOLDER, SPD_MOD_TYPE_SOLDER, false } 55 }; 56 57 static const spd_value_map_t spd_ddr5_mod_is_hybrid_map[] = { 58 { 0, SPD_MOD_NOT_HYBRID, false }, 59 { 1, SPD_MOD_HYBRID_NVDIMMM, false } 60 }; 61 62 static const spd_value_map_t spd_ddr5_mod_hybrid_map[] = { 63 { SPD_DDR5_MOD_TYPE_HYBRID_NVDIMM_N, SPD_MOD_TYPE_NVDIMM_N, false }, 64 { SPD_DDR5_MOD_TYPE_HYBRID_NVDIMM_P, SPD_MOD_TYPE_NVDIMM_P, false } 65 }; 66 67 static void 68 spd_parse_ddr5_mod_type(spd_info_t *si, uint32_t off, uint32_t len, 69 const char *key) 70 { 71 const uint8_t data = si->si_data[off]; 72 const uint8_t type = SPD_DDR5_MOD_TYPE_TYPE(data); 73 const uint8_t is_hyb = SPD_DDR5_MOD_TYPE_ISHYBRID(data); 74 const uint8_t hybrid = SPD_DDR5_MOD_TYPE_HYBRID(data); 75 76 spd_insert_map(si, SPD_KEY_MOD_HYBRID_TYPE, is_hyb, 77 spd_ddr5_mod_is_hybrid_map, ARRAY_SIZE(spd_ddr5_mod_is_hybrid_map)); 78 79 if (is_hyb != 0) { 80 spd_insert_map(si, SPD_KEY_MOD_NVDIMM_TYPE, hybrid, 81 spd_ddr5_mod_hybrid_map, 82 ARRAY_SIZE(spd_ddr5_mod_hybrid_map)); 83 } 84 85 spd_insert_map(si, SPD_KEY_MOD_TYPE, type, spd_ddr5_mod_type_map, 86 ARRAY_SIZE(spd_ddr5_mod_type_map)); 87 } 88 89 static bool 90 spd_parse_ddr5_isassym(spd_info_t *si) 91 { 92 ASSERT3U(si->si_size, >, SPD_DDR5_COM_ORG); 93 const uint8_t data = si->si_data[SPD_DDR5_COM_ORG]; 94 const uint8_t is_asym = SPD_DDR5_COM_ORG_MIX(data); 95 96 return (is_asym == SPD_DDR5_COM_ORG_MIX_ASYM); 97 } 98 99 static const spd_value_map64_t spd_ddr5_density_map[] = { 100 { SPD_DDR5_DENPKG_DPD_4Gb, 4ULL * 1024ULL * 1024ULL * 1024ULL, false }, 101 { SPD_DDR5_DENPKG_DPD_8Gb, 8ULL * 1024ULL * 1024ULL * 1024ULL, false }, 102 { SPD_DDR5_DENPKG_DPD_12Gb, 12ULL * 1024ULL * 1024ULL * 1024ULL, 103 false }, 104 { SPD_DDR5_DENPKG_DPD_16Gb, 16ULL * 1024ULL * 1024ULL * 1024ULL, 105 false }, 106 { SPD_DDR5_DENPKG_DPD_24Gb, 24ULL * 1024ULL * 1024ULL * 1024ULL, 107 false }, 108 { SPD_DDR5_DENPKG_DPD_32Gb, 32ULL * 1024ULL * 1024ULL * 1024ULL, 109 false }, 110 { SPD_DDR5_DENPKG_DPD_48Gb, 48ULL * 1024ULL * 1024ULL * 1024ULL, 111 false }, 112 { SPD_DDR5_DENPKG_DPD_64Gb, 64ULL * 1024ULL * 1024ULL * 1024ULL, 113 false }, 114 }; 115 116 static const spd_value_map_t spd_ddr5_ndies_map[] = { 117 { SPD_DDR5_DENPKG_DPP_MONO, 1, false }, 118 { SPD_DDR5_DENPKG_DPP_DDP, 2, false }, 119 { SPD_DDR5_DENPKG_DPP_2H3DS, 2, false }, 120 { SPD_DDR5_DENPKG_DPP_4H3DS, 4, false }, 121 { SPD_DDR5_DENPKG_DPP_8H3DS, 8, false }, 122 { SPD_DDR5_DENPKG_DPP_16H3DS, 16, false }, 123 }; 124 125 static const spd_value_map_t spd_ddr5_sl_map[] = { 126 { SPD_DDR5_DENPKG_DPP_MONO, SPD_SL_UNSPECIFIED, false }, 127 { SPD_DDR5_DENPKG_DPP_DDP, SPD_SL_UNSPECIFIED, false }, 128 { SPD_DDR5_DENPKG_DPP_2H3DS, SPD_SL_3DS, false }, 129 { SPD_DDR5_DENPKG_DPP_4H3DS, SPD_SL_3DS, false }, 130 { SPD_DDR5_DENPKG_DPP_8H3DS, SPD_SL_3DS, false }, 131 { SPD_DDR5_DENPKG_DPP_16H3DS, SPD_SL_3DS, false }, 132 }; 133 134 static void 135 spd_parse_ddr5_denpkg(spd_info_t *si, uint8_t data, const char *ndie_key, 136 const char *den_key, const char *sl_key) 137 { 138 const uint8_t ndie = SPD_DDR5_DENPKG_DPP(data); 139 const uint8_t dens = SPD_DDR5_DENPKG_DPD(data); 140 141 spd_insert_map(si, ndie_key, ndie, spd_ddr5_ndies_map, 142 ARRAY_SIZE(spd_ddr5_ndies_map)); 143 spd_insert_map(si, sl_key, ndie, spd_ddr5_sl_map, 144 ARRAY_SIZE(spd_ddr5_sl_map)); 145 spd_insert_map64(si, den_key, dens, spd_ddr5_density_map, 146 ARRAY_SIZE(spd_ddr5_density_map)); 147 } 148 149 static void 150 spd_parse_ddr5_denpkg_pri(spd_info_t *si, uint32_t off, uint32_t len, 151 const char *key) 152 { 153 spd_parse_ddr5_denpkg(si, si->si_data[off], SPD_KEY_PKG_NDIE, 154 SPD_KEY_DIE_SIZE, SPD_KEY_PKG_SL); 155 } 156 157 static void 158 spd_parse_ddr5_denpkg_sec(spd_info_t *si, uint32_t off, uint32_t len, 159 const char *key) 160 { 161 if (!spd_parse_ddr5_isassym(si)) 162 return; 163 164 spd_parse_ddr5_denpkg(si, si->si_data[off], SPD_KEY_SEC_PKG_NDIE, 165 SPD_KEY_SEC_DIE_SIZE, SPD_KEY_SEC_PKG_SL); 166 } 167 168 static const spd_value_range_t spd_ddr5_nrow_range = { 169 .svr_max = SPD_DDR5_ADDR_NROWS_MAX, 170 .svr_base = SPD_DDR5_ADDR_NROWS_BASE 171 }; 172 173 static const spd_value_range_t spd_ddr5_ncol_range = { 174 .svr_max = SPD_DDR5_ADDR_NCOLS_MAX, 175 .svr_base = SPD_DDR5_ADDR_NCOLS_BASE 176 }; 177 178 static void 179 spd_parse_ddr5_addr(spd_info_t *si, uint8_t data, const char *row_key, 180 const char *col_key) 181 { 182 const uint8_t ncols = SPD_DDR5_ADDR_NCOLS(data); 183 const uint8_t nrows = SPD_DDR5_ADDR_NROWS(data); 184 185 spd_insert_range(si, col_key, ncols, &spd_ddr5_ncol_range); 186 spd_insert_range(si, row_key, nrows, &spd_ddr5_nrow_range); 187 } 188 189 static void 190 spd_parse_ddr5_addr_pri(spd_info_t *si, uint32_t off, uint32_t len, 191 const char *key) 192 { 193 spd_parse_ddr5_addr(si, si->si_data[off], SPD_KEY_NROW_BITS, 194 SPD_KEY_NCOL_BITS); 195 } 196 197 static void 198 spd_parse_ddr5_addr_sec(spd_info_t *si, uint32_t off, uint32_t len, 199 const char *key) 200 { 201 if (!spd_parse_ddr5_isassym(si)) 202 return; 203 204 spd_parse_ddr5_addr(si, si->si_data[off], SPD_KEY_SEC_NROW_BITS, 205 SPD_KEY_SEC_NCOL_BITS); 206 } 207 208 static const spd_value_map_t spd_ddr5_width_map[] = { 209 { SPD_DDR5_WIDTH_X4, 4, false }, 210 { SPD_DDR5_WIDTH_X8, 8, false }, 211 { SPD_DDR5_WIDTH_X16, 16, false }, 212 { SPD_DDR5_WIDTH_X32, 32, false } 213 }; 214 215 static void 216 spd_parse_ddr5_width(spd_info_t *si, uint8_t data, const char *key) 217 { 218 const uint8_t width = SPD_DDR5_WIDTH_WIDTH(data); 219 220 spd_insert_map(si, key, width, spd_ddr5_width_map, 221 ARRAY_SIZE(spd_ddr5_width_map)); 222 } 223 224 static void 225 spd_parse_ddr5_width_pri(spd_info_t *si, uint32_t off, uint32_t len, 226 const char *key) 227 { 228 spd_parse_ddr5_width(si, si->si_data[off], SPD_KEY_DRAM_WIDTH); 229 } 230 231 static void 232 spd_parse_ddr5_width_sec(spd_info_t *si, uint32_t off, uint32_t len, 233 const char *key) 234 { 235 if (!spd_parse_ddr5_isassym(si)) 236 return; 237 238 spd_parse_ddr5_width(si, si->si_data[off], SPD_KEY_SEC_DRAM_WIDTH); 239 } 240 241 static const spd_value_range_t spd_ddr5_nbg_range = { 242 .svr_max = SPD_DDR5_BANKS_NBG_MAX 243 }; 244 245 static const spd_value_range_t spd_ddr5_nba_range = { 246 .svr_max = SPD_DDR5_BANKS_NBA_MAX 247 }; 248 249 static void 250 spd_parse_ddr5_banks(spd_info_t *si, uint8_t data, const char *bg_key, 251 const char *ba_key) 252 { 253 const uint8_t nbg = 1 << SPD_DDR5_BANKS_NBG(data); 254 const uint8_t nba = 1 << SPD_DDR5_BANKS_NBA(data); 255 256 spd_insert_range(si, bg_key, nbg, &spd_ddr5_nbg_range); 257 spd_insert_range(si, ba_key, nba, &spd_ddr5_nba_range); 258 } 259 260 static void 261 spd_parse_ddr5_banks_pri(spd_info_t *si, uint32_t off, uint32_t len, 262 const char *key) 263 { 264 spd_parse_ddr5_banks(si, si->si_data[off], SPD_KEY_NBGRP_BITS, 265 SPD_KEY_NBANK_BITS); 266 } 267 268 static void 269 spd_parse_ddr5_banks_sec(spd_info_t *si, uint32_t off, uint32_t len, 270 const char *key) 271 { 272 if (!spd_parse_ddr5_isassym(si)) 273 return; 274 275 spd_parse_ddr5_banks(si, si->si_data[off], SPD_KEY_SEC_NBGRP_BITS, 276 SPD_KEY_SEC_NBANK_BITS); 277 } 278 279 static void 280 spd_parse_ddr5_ppr(spd_info_t *si, uint32_t off, uint32_t len, 281 const char *key) 282 { 283 const uint8_t data = si->si_data[off]; 284 spd_ppr_flags_t flags = SPD_PPR_F_HARD_PPR | SPD_PPR_F_SOFT_PPR; 285 286 if (SPD_DDR5_PPR_GRAN(data) == SPD_DDR5_PPR_GRAN_BGRP) { 287 spd_nvl_insert_u32(si, SPD_KEY_PPR_GRAN, 288 SPD_PPR_GRAN_BANK_GROUP); 289 } else { 290 spd_nvl_insert_u32(si, SPD_KEY_PPR_GRAN, 291 SPD_PPR_GRAN_BANK); 292 } 293 294 if (SPD_DDR5_PPR_LOCK_SUP(data) != 0) 295 flags |= SPD_PPR_F_PPR_UNDO; 296 if (SPD_DDR5_PPR_MPPR_SUP(data) != 0) 297 flags |= SPD_PPR_F_MBIST_PPR; 298 spd_nvl_insert_u32(si, SPD_KEY_PPR, flags); 299 300 if (SPD_DDR5_PPR_BL32_SUP(data) != 0) 301 spd_nvl_insert_key(si, SPD_KEY_DDR5_BL32); 302 } 303 304 static const spd_value_map_t spd_ddr5_dca_map[] = { 305 { SPD_DDR5_SPD_DCA_TYPE_UNSUP, SPD_DCA_UNSPPORTED, false }, 306 { SPD_DDR5_SPD_DCA_TYPE_1_2P, SPD_DCA_1_OR_2_PHASE, false }, 307 { SPD_DDR5_SPD_DCA_TYPE_4P, SPD_DCA_4_PHASE, false } 308 }; 309 310 static void 311 spd_parse_ddr5_dca(spd_info_t *si, uint32_t off, uint32_t len, 312 const char *key) 313 { 314 const uint8_t data = si->si_data[off]; 315 const uint8_t dca = SPD_DDR5_SPD_DCA_TYPE(data); 316 317 if (SPD_DDR5_SPD_DCA_PASR(data) != 0) 318 spd_nvl_insert_key(si, SPD_KEY_DDR5_PASR); 319 320 spd_insert_map(si, SPD_KEY_DDR5_DCA, dca, spd_ddr5_dca_map, 321 ARRAY_SIZE(spd_ddr5_dca_map)); 322 } 323 324 static void 325 spd_parse_ddr5_flt(spd_info_t *si, uint32_t off, uint32_t len, 326 const char *key) 327 { 328 const uint8_t data = si->si_data[off]; 329 spd_fault_t flt = 0; 330 331 if (SPD_DDR5_FLT_WIDE_TS(data) != 0) 332 spd_nvl_insert_key(si, SPD_KEY_DDR5_WIDE_TS); 333 334 if (SPD_DDR5_FLT_WBSUPR_SUP(data) != 0) { 335 if (SPD_DDR5_FLT_WBSUPR_SEL(data) == 336 SPD_DDR5_FLT_WBSUPR_SEL_MR15) { 337 flt |= SPD_FLT_WRSUP_MR15; 338 } else { 339 flt |= SPD_FLT_WRSUP_MR9; 340 } 341 } 342 343 if (SPD_DDR5_FLT_BFLT(data)) 344 flt |= SPD_FLT_BOUNDED; 345 spd_nvl_insert_u32(si, SPD_KEY_DDR5_WIDE_TS, flt); 346 } 347 348 /* 349 * Voltages support describing the nominal, operational, and endurant ranges. 350 * Currently we only encode the nominal values. 351 */ 352 static void 353 spd_parse_ddr5_voltage(spd_info_t *si, uint8_t data, const char *key, 354 uint32_t *mv, uint32_t nmv) 355 { 356 const uint8_t nom_idx = SPD_DDR5_DRAM_VOLT_NOM(data); 357 358 if (nom_idx >= nmv) { 359 spd_nvl_err(si, key, SPD_ERROR_NO_XLATE, 360 "encountered unknown value: 0x%x", nom_idx); 361 } else { 362 spd_nvl_insert_u32_array(si, key, &mv[nom_idx], 1); 363 } 364 } 365 366 static void 367 spd_parse_ddr5_vdd(spd_info_t *si, uint32_t off, uint32_t len, 368 const char *key) 369 { 370 uint32_t volts[] = { 1100 }; 371 return (spd_parse_ddr5_voltage(si, si->si_data[off], key, volts, 372 ARRAY_SIZE(volts))); 373 } 374 375 static void 376 spd_parse_ddr5_vddq(spd_info_t *si, uint32_t off, uint32_t len, 377 const char *key) 378 { 379 uint32_t volts[] = { 1100 }; 380 return (spd_parse_ddr5_voltage(si, si->si_data[off], key, volts, 381 ARRAY_SIZE(volts))); 382 } 383 384 static void 385 spd_parse_ddr5_vpp(spd_info_t *si, uint32_t off, uint32_t len, 386 const char *key) 387 { 388 uint32_t volts[] = { 1800 }; 389 return (spd_parse_ddr5_voltage(si, si->si_data[off], key, volts, 390 ARRAY_SIZE(volts))); 391 } 392 393 static void 394 spd_parse_ddr5_time(spd_info_t *si, uint32_t off, uint32_t len, 395 const char *key) 396 { 397 const uint8_t data = si->si_data[off]; 398 399 if (SPD_DDR5_TIME_STD(data) == SPD_DDR5_TIME_STD_NON) 400 spd_nvl_insert_key(si, SPD_KEY_DDR5_NONSTD_TIME); 401 } 402 403 /* 404 * Time in picoseconds. The LSB is at off. The MSB is at off + 1. 405 */ 406 static void 407 spd_parse_ddr5_ps(spd_info_t *si, uint32_t off, uint32_t len, 408 const char *key) 409 { 410 uint64_t ps; 411 412 ASSERT3U(len, ==, 2); 413 ps = (uint64_t)si->si_data[off] << 8; 414 ps |= (uint64_t)si->si_data[off + 1]; 415 416 if (ps == 0) { 417 spd_nvl_err(si, key, SPD_ERROR_NO_XLATE, 418 "encountered unexpected zero time value"); 419 return; 420 } 421 422 spd_nvl_insert_u64(si, key, ps); 423 } 424 425 /* 426 * Time in nanoseconds. The LSB is at off. The MSB is at off + 1. We normalize 427 * all times to ps. 428 */ 429 static void 430 spd_parse_ddr5_ns(spd_info_t *si, uint32_t off, uint32_t len, 431 const char *key) 432 { 433 uint64_t ns, ps; 434 435 ASSERT3U(len, ==, 2); 436 ns = (uint64_t)si->si_data[off] << 8; 437 ns |= (uint64_t)si->si_data[off + 1]; 438 439 if (ns == 0) { 440 spd_nvl_err(si, key, SPD_ERROR_NO_XLATE, 441 "encountered unexpected zero time value"); 442 return; 443 } 444 445 ps = ns * 1000; 446 spd_nvl_insert_u64(si, key, ps); 447 } 448 449 /* 450 * Several DDR5 timing properties are only valid for 3DS type DIMMs. So we 451 * double check the actual DIMM type before we proceed to parse this. 452 */ 453 static void 454 spd_parse_ddr5_3ds_ns(spd_info_t *si, uint32_t off, uint32_t len, 455 const char *key) 456 { 457 ASSERT3U(off, >=, SPD_DDR5_DENPKG1); 458 uint32_t val; 459 460 if (nvlist_lookup_uint32(si->si_nvl, SPD_KEY_PKG_SL, &val) != 0 || 461 val != SPD_SL_3DS) { 462 return; 463 } 464 465 spd_parse_ddr5_ns(si, off, len, key); 466 } 467 468 static void 469 spd_parse_ddr5_nck(spd_info_t *si, uint32_t off, uint32_t len, 470 const char *key) 471 { 472 const uint8_t data = si->si_data[off]; 473 474 if (data == 0) { 475 spd_nvl_err(si, key, SPD_ERROR_NO_XLATE, 476 "encountered unexpected zero clock value"); 477 return; 478 } 479 480 spd_nvl_insert_u32(si, key, data); 481 } 482 483 static void 484 spd_parse_ddr5_cas(spd_info_t *si, uint32_t off, uint32_t len, 485 const char *key) 486 { 487 uint32_t cas[40] = { 0 }; 488 uint_t ncas = 0; 489 uint32_t cas_base = 20; 490 491 ASSERT3U(len, ==, 5); 492 493 for (uint32_t byte = 0; byte < len; byte++) { 494 uint32_t data = si->si_data[off]; 495 496 for (uint32_t i = 0; i < NBBY; i++) { 497 if (bitx8(data, i, i) == 1) { 498 cas[ncas] = cas_base + 2 * (i + NBBY * byte); 499 ncas++; 500 } 501 } 502 } 503 504 spd_nvl_insert_u32_array(si, key, cas, ncas); 505 } 506 507 static const spd_value_range_t spd_ddr5_raammt_norm_range = { 508 .svr_min = SPD_DDR5_RFM0_RAAMMT_NORM_MIN, 509 .svr_max = SPD_DDR5_RFM0_RAAMMT_NORM_MAX, 510 .svr_mult = SPD_DDR5_RFM0_RAAMMT_NORM_MULT 511 }; 512 513 static const spd_value_range_t spd_ddr5_raammt_fgr_range = { 514 .svr_min = SPD_DDR5_RFM0_RAAMMT_FGR_MIN, 515 .svr_max = SPD_DDR5_RFM0_RAAMMT_FGR_MAX, 516 .svr_mult = SPD_DDR5_RFM0_RAAMMT_FGR_MULT 517 }; 518 519 static const spd_value_range_t spd_ddr5_raaimt_norm_range = { 520 .svr_min = SPD_DDR5_RFM0_RAAIMT_NORM_MIN, 521 .svr_max = SPD_DDR5_RFM0_RAAIMT_NORM_MAX, 522 .svr_mult = SPD_DDR5_RFM0_RAAIMT_NORM_MULT 523 }; 524 525 static const spd_value_range_t spd_ddr5_raaimt_fgr_range = { 526 .svr_min = SPD_DDR5_RFM0_RAAIMT_FGR_MIN, 527 .svr_max = SPD_DDR5_RFM0_RAAIMT_FGR_MAX, 528 .svr_mult = SPD_DDR5_RFM0_RAAIMT_FGR_MULT 529 }; 530 531 static const spd_value_range_t spd_ddr5_brc_cfg_range = { 532 .svr_max = SPD_DDR5_RFM1_BRC_CFG_MAX, 533 .svr_base = SPD_DDR5_RFM1_BRC_CFG_BASE 534 }; 535 536 static const spd_value_map_t spd_ddr5_raa_ctr_map[] = { 537 { SPD_DDR5_RFM1_CTR_1X, 1, false }, 538 { SPD_DDR5_RFM1_CTR_2X, 2, false } 539 }; 540 541 static void 542 spd_parse_ddr5_rfm_flags(spd_info_t *si, uint8_t rfm0, uint8_t rfm1, 543 const char *key) 544 { 545 spd_rfm_flags_t flags = 0; 546 547 if (SPD_DDR5_RFM0_RFM_REQ(rfm0) != 0) 548 flags |= SPD_RFM_F_REQUIRED; 549 if (SPD_DDR5_RFM1_DRFM_SUP(rfm1) != 0) 550 flags |= SPD_RFM_F_DRFM_SUP; 551 552 spd_nvl_insert_u32(si, key, flags); 553 } 554 555 static void 556 spd_parse_ddr5_arfm_flags(spd_info_t *si, uint8_t rfm1, const char *key) 557 { 558 spd_rfm_flags_t flags = 0; 559 560 if (SPD_DDR5_RFM1_DRFM_SUP(rfm1) != 0) 561 flags |= SPD_RFM_F_DRFM_SUP; 562 563 spd_nvl_insert_u32(si, key, flags); 564 } 565 566 static void 567 spd_parse_ddr5_rfm_common(spd_info_t *si, uint8_t rfm0, uint8_t rfm1, 568 const char *raaimt_key, const char *raaimt_fgr_key, const char *raammt_key, 569 const char *raammt_fgr_key, const char *brc_cfg_key, 570 const char *brc_sup_key, const char *raa_ctr_key) 571 { 572 const uint8_t raammt = SPD_DDR5_RFM0_RAAMMT_NORM(rfm0); 573 const uint8_t raammt_fgr = SPD_DDR5_RFM0_RAAMMT_FGR(rfm0); 574 const uint8_t raaimt = SPD_DDR5_RFM0_RAAIMT_NORM(rfm0); 575 const uint8_t raaimt_fgr = SPD_DDR5_RFM0_RAAIMT_FGR(rfm0); 576 const uint8_t brc_cfg = SPD_DDR5_RFM1_BRC_CFG(rfm1); 577 const uint8_t brc_sup = SPD_DDR5_RFM1_BRC_SUP(rfm1); 578 const uint8_t raa_ctr = SPD_DDR5_RFM1_CTR(rfm1); 579 spd_brc_flags_t brc_flags = SPD_BRC_F_LVL_2; 580 581 if (brc_sup == SPD_DDR5_RFM1_BRC_SUP_234) 582 brc_flags |= SPD_BRC_F_LVL_3 | SPD_BRC_F_LVL_4; 583 584 spd_insert_range(si, raaimt_key, raaimt, &spd_ddr5_raaimt_norm_range); 585 spd_insert_range(si, raaimt_fgr_key, raaimt_fgr, 586 &spd_ddr5_raaimt_fgr_range); 587 spd_insert_range(si, raammt_key, raammt, &spd_ddr5_raammt_norm_range); 588 spd_insert_range(si, raammt_fgr_key, raammt_fgr, 589 &spd_ddr5_raammt_fgr_range); 590 spd_insert_range(si, brc_cfg_key, brc_cfg, &spd_ddr5_brc_cfg_range); 591 spd_nvl_insert_u32(si, brc_sup_key, brc_flags); 592 593 spd_insert_map(si, raa_ctr_key, raa_ctr, spd_ddr5_raa_ctr_map, 594 ARRAY_SIZE(spd_ddr5_raa_ctr_map)); 595 } 596 597 static void 598 spd_parse_ddr5_rfm_pri(spd_info_t *si, uint32_t off, uint32_t len, 599 const char *key) 600 { 601 ASSERT3U(len, ==, 2); 602 603 spd_parse_ddr5_rfm_flags(si, si->si_data[off], si->si_data[off + 1], 604 SPD_KEY_DDR5_RFM_FLAGS_PRI); 605 spd_parse_ddr5_rfm_common(si, si->si_data[off], si->si_data[off + 1], 606 SPD_KEY_DDR5_RFM_RAAIMT_PRI, SPD_KEY_DDR5_RFM_RAAIMT_FGR_PRI, 607 SPD_KEY_DDR5_RFM_RAAMMT_PRI, SPD_KEY_DDR5_RFM_RAAMMT_FGR_PRI, 608 SPD_KEY_DDR5_RFM_BRC_CFG_PRI, SPD_KEY_DDR5_RFM_BRC_SUP_PRI, 609 SPD_KEY_DDR5_RFM_RAA_DEC_PRI); 610 } 611 612 static void 613 spd_parse_ddr5_rfm_sec(spd_info_t *si, uint32_t off, uint32_t len, 614 const char *key) 615 { 616 if (!spd_parse_ddr5_isassym(si)) 617 return; 618 619 spd_parse_ddr5_rfm_flags(si, si->si_data[off], si->si_data[off + 1], 620 SPD_KEY_DDR5_RFM_FLAGS_SEC); 621 spd_parse_ddr5_rfm_common(si, si->si_data[off], si->si_data[off + 1], 622 SPD_KEY_DDR5_RFM_RAAIMT_SEC, SPD_KEY_DDR5_RFM_RAAIMT_FGR_SEC, 623 SPD_KEY_DDR5_RFM_RAAMMT_SEC, SPD_KEY_DDR5_RFM_RAAMMT_FGR_SEC, 624 SPD_KEY_DDR5_RFM_BRC_CFG_SEC, SPD_KEY_DDR5_RFM_BRC_SUP_SEC, 625 SPD_KEY_DDR5_RFM_RAA_DEC_SEC); 626 } 627 628 static void 629 spd_parse_ddr5_arfma_pri(spd_info_t *si, uint32_t off, uint32_t len, 630 const char *key) 631 { 632 ASSERT3U(len, ==, 2); 633 634 if (SPD_DDR5_ARFM_SUP(si->si_data[off]) == 0) 635 return; 636 637 spd_parse_ddr5_arfm_flags(si, si->si_data[off + 1], 638 SPD_KEY_DDR5_ARFMA_FLAGS_PRI); 639 spd_parse_ddr5_rfm_common(si, si->si_data[off], si->si_data[off + 1], 640 SPD_KEY_DDR5_ARFMA_RAAIMT_PRI, SPD_KEY_DDR5_ARFMA_RAAIMT_FGR_PRI, 641 SPD_KEY_DDR5_ARFMA_RAAMMT_PRI, SPD_KEY_DDR5_ARFMA_RAAMMT_FGR_PRI, 642 SPD_KEY_DDR5_ARFMA_BRC_CFG_PRI, SPD_KEY_DDR5_ARFMA_BRC_SUP_PRI, 643 SPD_KEY_DDR5_ARFMA_RAA_DEC_PRI); 644 } 645 646 static void 647 spd_parse_ddr5_arfma_sec(spd_info_t *si, uint32_t off, uint32_t len, 648 const char *key) 649 { 650 if (!spd_parse_ddr5_isassym(si)) 651 return; 652 653 if (SPD_DDR5_ARFM_SUP(si->si_data[off]) == 0) 654 return; 655 656 spd_parse_ddr5_arfm_flags(si, si->si_data[off + 1], 657 SPD_KEY_DDR5_ARFMA_FLAGS_SEC); 658 spd_parse_ddr5_rfm_common(si, si->si_data[off], si->si_data[off + 1], 659 SPD_KEY_DDR5_ARFMA_RAAIMT_SEC, SPD_KEY_DDR5_ARFMA_RAAIMT_FGR_SEC, 660 SPD_KEY_DDR5_ARFMA_RAAMMT_SEC, SPD_KEY_DDR5_ARFMA_RAAMMT_FGR_SEC, 661 SPD_KEY_DDR5_ARFMA_BRC_CFG_SEC, SPD_KEY_DDR5_ARFMA_BRC_SUP_SEC, 662 SPD_KEY_DDR5_ARFMA_RAA_DEC_SEC); 663 } 664 665 static void 666 spd_parse_ddr5_arfmb_pri(spd_info_t *si, uint32_t off, uint32_t len, 667 const char *key) 668 { 669 ASSERT3U(len, ==, 2); 670 671 if (SPD_DDR5_ARFM_SUP(si->si_data[off]) == 0) 672 return; 673 674 spd_parse_ddr5_arfm_flags(si, si->si_data[off + 1], 675 SPD_KEY_DDR5_ARFMB_FLAGS_PRI); 676 spd_parse_ddr5_rfm_common(si, si->si_data[off], si->si_data[off + 1], 677 SPD_KEY_DDR5_ARFMB_RAAIMT_PRI, SPD_KEY_DDR5_ARFMB_RAAIMT_FGR_PRI, 678 SPD_KEY_DDR5_ARFMB_RAAMMT_PRI, SPD_KEY_DDR5_ARFMB_RAAMMT_FGR_PRI, 679 SPD_KEY_DDR5_ARFMB_BRC_CFG_PRI, SPD_KEY_DDR5_ARFMB_BRC_SUP_PRI, 680 SPD_KEY_DDR5_ARFMB_RAA_DEC_PRI); 681 } 682 683 static void 684 spd_parse_ddr5_arfmb_sec(spd_info_t *si, uint32_t off, uint32_t len, 685 const char *key) 686 { 687 if (!spd_parse_ddr5_isassym(si)) 688 return; 689 690 if (SPD_DDR5_ARFM_SUP(si->si_data[off]) == 0) 691 return; 692 693 spd_parse_ddr5_arfm_flags(si, si->si_data[off + 1], 694 SPD_KEY_DDR5_ARFMB_FLAGS_SEC); 695 spd_parse_ddr5_rfm_common(si, si->si_data[off], si->si_data[off + 1], 696 SPD_KEY_DDR5_ARFMB_RAAIMT_SEC, SPD_KEY_DDR5_ARFMB_RAAIMT_FGR_SEC, 697 SPD_KEY_DDR5_ARFMB_RAAMMT_SEC, SPD_KEY_DDR5_ARFMB_RAAMMT_FGR_SEC, 698 SPD_KEY_DDR5_ARFMB_BRC_CFG_SEC, SPD_KEY_DDR5_ARFMB_BRC_SUP_SEC, 699 SPD_KEY_DDR5_ARFMB_RAA_DEC_SEC); 700 } 701 702 static void 703 spd_parse_ddr5_arfmc_pri(spd_info_t *si, uint32_t off, uint32_t len, 704 const char *key) 705 { 706 ASSERT3U(len, ==, 2); 707 708 if (SPD_DDR5_ARFM_SUP(si->si_data[off]) == 0) 709 return; 710 711 spd_parse_ddr5_arfm_flags(si, si->si_data[off + 1], 712 SPD_KEY_DDR5_ARFMC_FLAGS_PRI); 713 spd_parse_ddr5_rfm_common(si, si->si_data[off], si->si_data[off + 1], 714 SPD_KEY_DDR5_ARFMC_RAAIMT_PRI, SPD_KEY_DDR5_ARFMC_RAAIMT_FGR_PRI, 715 SPD_KEY_DDR5_ARFMC_RAAMMT_PRI, SPD_KEY_DDR5_ARFMC_RAAMMT_FGR_PRI, 716 SPD_KEY_DDR5_ARFMC_BRC_CFG_PRI, SPD_KEY_DDR5_ARFMC_BRC_SUP_PRI, 717 SPD_KEY_DDR5_ARFMC_RAA_DEC_PRI); 718 } 719 720 static void 721 spd_parse_ddr5_arfmc_sec(spd_info_t *si, uint32_t off, uint32_t len, 722 const char *key) 723 { 724 if (!spd_parse_ddr5_isassym(si)) 725 return; 726 727 if (SPD_DDR5_ARFM_SUP(si->si_data[off]) == 0) 728 return; 729 730 spd_parse_ddr5_arfm_flags(si, si->si_data[off + 1], 731 SPD_KEY_DDR5_ARFMC_FLAGS_SEC); 732 spd_parse_ddr5_rfm_common(si, si->si_data[off], si->si_data[off + 1], 733 SPD_KEY_DDR5_ARFMC_RAAIMT_SEC, SPD_KEY_DDR5_ARFMC_RAAIMT_FGR_SEC, 734 SPD_KEY_DDR5_ARFMC_RAAMMT_SEC, SPD_KEY_DDR5_ARFMC_RAAMMT_FGR_SEC, 735 SPD_KEY_DDR5_ARFMC_BRC_CFG_SEC, SPD_KEY_DDR5_ARFMC_BRC_SUP_SEC, 736 SPD_KEY_DDR5_ARFMC_RAA_DEC_SEC); 737 } 738 739 static const spd_parse_t spd_ddr5_base[] = { 740 { .sp_off = SPD_DDR5_NBYTES, .sp_parse = spd_parse_ddr5_nbytes }, 741 { .sp_off = SPD_DDR5_SPD_REV, .sp_parse = spd_parse_rev }, 742 /* 743 * We have previously validated that the DRAM type is something that we 744 * understand. We pass through the raw enum to users here. 745 */ 746 { .sp_off = SPD_DDR5_DRAM_TYPE, .sp_key = SPD_KEY_DRAM_TYPE, 747 .sp_parse = spd_parse_raw_u8 }, 748 { .sp_off = SPD_DDR5_MOD_TYPE, .sp_parse = spd_parse_ddr5_mod_type }, 749 /* 750 * All secondary values must check whether an asymmetrical module is 751 * present in Byte 234. As such, for the secondary versions we set LEN 752 * to include that value. They then move to a common function. 753 */ 754 { .sp_off = SPD_DDR5_DENPKG1, .sp_parse = spd_parse_ddr5_denpkg_pri }, 755 { .sp_off = SPD_DDR5_DENPKG2, .sp_parse = spd_parse_ddr5_denpkg_sec, 756 .sp_len = SPD_DDR5_COM_ORG - SPD_DDR5_DENPKG2 + 1 }, 757 { .sp_off = SPD_DDR5_ADDR1, .sp_parse = spd_parse_ddr5_addr_pri }, 758 { .sp_off = SPD_DDR5_ADDR2, .sp_parse = spd_parse_ddr5_addr_sec, 759 .sp_len = SPD_DDR5_COM_ORG - SPD_DDR5_ADDR2 + 1 }, 760 { .sp_off = SPD_DDR5_WIDTH1, .sp_parse = spd_parse_ddr5_width_pri }, 761 { .sp_off = SPD_DDR5_WIDTH2, .sp_parse = spd_parse_ddr5_width_sec, 762 .sp_len = SPD_DDR5_COM_ORG - SPD_DDR5_WIDTH2 + 1 }, 763 { .sp_off = SPD_DDR5_BANKS1, .sp_parse = spd_parse_ddr5_banks_pri }, 764 { .sp_off = SPD_DDR5_BANKS2, .sp_parse = spd_parse_ddr5_banks_sec, 765 .sp_len = SPD_DDR5_COM_ORG - SPD_DDR5_BANKS2 + 1 }, 766 { .sp_off = SPD_DDR5_PPR, .sp_parse = spd_parse_ddr5_ppr }, 767 { .sp_off = SPD_DDR5_SDA, .sp_parse = spd_parse_ddr5_dca }, 768 { .sp_off = SPD_DDR5_FLT, .sp_parse = spd_parse_ddr5_flt }, 769 { .sp_off = SPD_DDR5_DRAM_VDD, .sp_key = SPD_KEY_NOM_VDD, 770 .sp_parse = spd_parse_ddr5_vdd }, 771 { .sp_off = SPD_DDR5_DRAM_VDDQ, .sp_key = SPD_KEY_NOM_VDDQ, 772 .sp_parse = spd_parse_ddr5_vddq }, 773 { .sp_off = SPD_DDR5_DRAM_VPP, .sp_key = SPD_KEY_NOM_VPP, 774 .sp_parse = spd_parse_ddr5_vpp }, 775 { .sp_off = SPD_DDR5_TIME, .sp_parse = spd_parse_ddr5_time }, 776 { .sp_off = SPD_DDR5_TCKAVG_MIN_LSB, .sp_len = 2, 777 .sp_key = SPD_KEY_TCKAVG_MIN, .sp_parse = spd_parse_ddr5_ps }, 778 { .sp_off = SPD_DDR5_TCKAVG_MAX_LSB, .sp_len = 2, 779 .sp_key = SPD_KEY_TCKAVG_MAX, .sp_parse = spd_parse_ddr5_ps }, 780 { .sp_off = SPD_DDR5_CAS_SUP0, .sp_len = 5, .sp_key = SPD_KEY_CAS, 781 .sp_parse = spd_parse_ddr5_cas }, 782 { .sp_off = SPD_DDR5_TAA_LSB, .sp_len = 2, 783 .sp_key = SPD_KEY_TAA_MIN, .sp_parse = spd_parse_ddr5_ps }, 784 { .sp_off = SPD_DDR5_TRCD_LSB, .sp_len = 2, 785 .sp_key = SPD_KEY_TRCD_MIN, .sp_parse = spd_parse_ddr5_ps }, 786 { .sp_off = SPD_DDR5_TRP_LSB, .sp_len = 2, 787 .sp_key = SPD_KEY_TRP_MIN, .sp_parse = spd_parse_ddr5_ps }, 788 { .sp_off = SPD_DDR5_TRAS_LSB, .sp_len = 2, 789 .sp_key = SPD_KEY_TRAS_MIN, .sp_parse = spd_parse_ddr5_ps }, 790 { .sp_off = SPD_DDR5_TRC_LSB, .sp_len = 2, 791 .sp_key = SPD_KEY_TRC_MIN, .sp_parse = spd_parse_ddr5_ps }, 792 { .sp_off = SPD_DDR5_TWR_LSB, .sp_len = 2, 793 .sp_key = SPD_KEY_TWR_MIN, .sp_parse = spd_parse_ddr5_ps }, 794 { .sp_off = SPD_DDR5_TRFC1_LSB, .sp_len = 2, 795 .sp_key = SPD_KEY_TRFC1_MIN, .sp_parse = spd_parse_ddr5_ns }, 796 { .sp_off = SPD_DDR5_TRFC2_LSB, .sp_len = 2, 797 .sp_key = SPD_KEY_TRFC2_MIN, .sp_parse = spd_parse_ddr5_ns }, 798 { .sp_off = SPD_DDR5_TRFCSB_LSB, .sp_len = 2, 799 .sp_key = SPD_KEY_TRFCSB, .sp_parse = spd_parse_ddr5_ns }, 800 { .sp_off = SPD_DDR5_3DS_TRFC1_LSB, .sp_len = 2, 801 .sp_key = SPD_KEY_TRFC1_DLR, .sp_parse = spd_parse_ddr5_3ds_ns }, 802 { .sp_off = SPD_DDR5_3DS_TRFC2_LSB, .sp_len = 2, 803 .sp_key = SPD_KEY_TRFC2_DLR, .sp_parse = spd_parse_ddr5_3ds_ns }, 804 { .sp_off = SPD_DDR5_3DS_TRFCSB_LSB, .sp_len = 2, 805 .sp_key = SPD_KEY_TRFCSB_DLR, .sp_parse = spd_parse_ddr5_3ds_ns }, 806 { .sp_off = SPD_DDR5_RFM0_SDRAM0, .sp_len = 2, 807 .sp_parse = spd_parse_ddr5_rfm_pri }, 808 { .sp_off = SPD_DDR5_RFM0_SDRAM1, .sp_parse = spd_parse_ddr5_rfm_sec, 809 .sp_len = SPD_DDR5_COM_ORG - SPD_DDR5_RFM0_SDRAM1 + 1 }, 810 { .sp_off = SPD_DDR5_ARFM0_A_SDRAM0, .sp_len = 2, 811 .sp_parse = spd_parse_ddr5_arfma_pri }, 812 { .sp_off = SPD_DDR5_ARFM0_A_SDRAM1, 813 .sp_len = SPD_DDR5_COM_ORG - SPD_DDR5_ARFM0_A_SDRAM1 + 1, 814 .sp_parse = spd_parse_ddr5_arfma_sec }, 815 { .sp_off = SPD_DDR5_ARFM0_B_SDRAM0, .sp_len = 2, 816 .sp_parse = spd_parse_ddr5_arfmb_pri }, 817 { .sp_off = SPD_DDR5_ARFM0_B_SDRAM1, 818 .sp_len = SPD_DDR5_COM_ORG - SPD_DDR5_ARFM0_B_SDRAM1 + 1, 819 .sp_parse = spd_parse_ddr5_arfmb_sec }, 820 { .sp_off = SPD_DDR5_ARFM0_C_SDRAM0, .sp_len = 2, 821 .sp_parse = spd_parse_ddr5_arfmc_pri }, 822 { .sp_off = SPD_DDR5_ARFM0_C_SDRAM1, 823 .sp_len = SPD_DDR5_COM_ORG - SPD_DDR5_ARFM0_C_SDRAM1 + 1, 824 .sp_parse = spd_parse_ddr5_arfmc_sec }, 825 { .sp_off = SPD_DDR5_TRRD_L_LSB, .sp_len = 2, 826 .sp_key = SPD_KEY_TRRD_L_MIN, .sp_parse = spd_parse_ddr5_ps }, 827 { .sp_off = SPD_DDR5_TRRD_L_NCK, .sp_key = SPD_KEY_TRRDL_NCK, 828 .sp_parse = spd_parse_ddr5_nck }, 829 { .sp_off = SPD_DDR5_TCCD_L_LSB, .sp_len = 2, 830 .sp_key = SPD_KEY_TCCD_L_MIN, .sp_parse = spd_parse_ddr5_ps }, 831 { .sp_off = SPD_DDR5_TCCD_L_NCK, .sp_key = SPD_KEY_TCCDL_NCK, 832 .sp_parse = spd_parse_ddr5_nck }, 833 { .sp_off = SPD_DDR5_TCCD_L_WR_LSB, .sp_len = 2, 834 .sp_key = SPD_KEY_TCCDLWR, .sp_parse = spd_parse_ddr5_ps }, 835 { .sp_off = SPD_DDR5_TCCD_L_WR_NCK, .sp_key = SPD_KEY_TCCDLWR_NCK, 836 .sp_parse = spd_parse_ddr5_nck }, 837 { .sp_off = SPD_DDR5_TCCD_L_WR2_LSB, .sp_len = 2, 838 .sp_key = SPD_KEY_TCCDLWR2, .sp_parse = spd_parse_ddr5_ps }, 839 { .sp_off = SPD_DDR5_TCCD_L_WR2_NCK, .sp_key = SPD_KEY_TCCDLWR2_NCK, 840 .sp_parse = spd_parse_ddr5_nck }, 841 { .sp_off = SPD_DDR5_TFAW_LSB, .sp_len = 2, 842 .sp_key = SPD_KEY_TFAW, .sp_parse = spd_parse_ddr5_ps }, 843 { .sp_off = SPD_DDR5_TFAW_NCK, .sp_key = SPD_KEY_TFAW_NCK, 844 .sp_parse = spd_parse_ddr5_nck }, 845 { .sp_off = SPD_DDR5_TCCD_L_WTR_LSB, .sp_len = 2, 846 .sp_key = SPD_KEY_TCCDLWTR, .sp_parse = spd_parse_ddr5_ps }, 847 { .sp_off = SPD_DDR5_TCCD_L_WTR_NCK, .sp_key = SPD_KEY_TCCDLWTR_NCK, 848 .sp_parse = spd_parse_ddr5_nck }, 849 { .sp_off = SPD_DDR5_TCCD_S_WTR_LSB, .sp_len = 2, 850 .sp_key = SPD_KEY_TCCDSWTR, .sp_parse = spd_parse_ddr5_ps }, 851 { .sp_off = SPD_DDR5_TCCD_S_WTR_NCK, .sp_key = SPD_KEY_TCCDSWTR_NCK, 852 .sp_parse = spd_parse_ddr5_nck }, 853 { .sp_off = SPD_DDR5_TRTP_LSB, .sp_len = 2, 854 .sp_key = SPD_KEY_TRTP, .sp_parse = spd_parse_ddr5_ps }, 855 { .sp_off = SPD_DDR5_TRTP_NCK, .sp_key = SPD_KEY_TRTP_NCK, 856 .sp_parse = spd_parse_ddr5_nck } 857 }; 858 859 static void 860 spd_parse_ddr5_mod_rev(spd_info_t *si, uint32_t off, uint32_t len, 861 const char *key) 862 { 863 const uint8_t data = si->si_data[off]; 864 const uint8_t enc = SPD_DDR5_SPD_REV_ENC(data); 865 const uint8_t add = SPD_DDR5_SPD_REV_ENC(data); 866 867 spd_nvl_insert_u32(si, SPD_KEY_MOD_REV_ENC, enc); 868 spd_nvl_insert_u32(si, SPD_KEY_MOD_REV_ADD, add); 869 } 870 871 static const spd_value_map_t spd_ddr5_hash_map[] = { 872 { SPD_DDR5_COM_HASH_NONE, 0, true }, 873 { SPD_DDR5_COM_HASH_ALG1, SPD_HASH_SEQ_ALG_1, false } 874 }; 875 876 static void 877 spd_parse_ddr5_hash_seq(spd_info_t *si, uint32_t off, uint32_t len, 878 const char *key) 879 { 880 const uint8_t data = si->si_data[off]; 881 const uint8_t alg = SPD_DDR5_COM_HASH_HASH(data); 882 883 spd_insert_map(si, key, alg, spd_ddr5_hash_map, 884 ARRAY_SIZE(spd_ddr5_hash_map)); 885 } 886 887 static void 888 spd_parse_ddr5_dev_common(spd_info_t *si, uint32_t off, spd_device_t flags, 889 const char *id_key, const char *id_str_key, const char *rev_key, 890 const char *type_key, const spd_value_map_t *type_map, size_t ntypes) 891 { 892 const uint8_t type = SPD_DDR5_COM_INFO_TYPE(si->si_data[off + 2]); 893 894 spd_parse_jedec_id(si, off, 2, id_key); 895 spd_parse_jedec_id_str(si, off, 2, id_str_key); 896 spd_parse_hex_vers(si, off + 3, 1, rev_key); 897 spd_upsert_flag(si, SPD_KEY_DEVS, flags); 898 spd_insert_map(si, type_key, type, type_map, ntypes); 899 } 900 901 static const spd_value_map_t spd_ddr5_spd_type_map[] = { 902 { SPD_DDR5_COM_INFO_TYPE_SPD5118, SPD_SPD_T_SPD5118, false }, 903 { SPD_DDR5_COM_INFO_TYPE_ESPD5216, SPD_SPD_T_ESPD5216, false } 904 }; 905 906 static void 907 spd_parse_ddr5_spd(spd_info_t *si, uint32_t off, uint32_t len, const char *key) 908 { 909 ASSERT3U(len, ==, 4); 910 const uint8_t type = si->si_data[off + 2]; 911 if (SPD_DDR5_COM_INFO_PRES(type) == 0) 912 return; 913 914 spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_SPD, SPD_KEY_DEV_SPD_MFG, 915 SPD_KEY_DEV_SPD_MFG_NAME, SPD_KEY_DEV_SPD_REV, SPD_KEY_DEV_SPD_TYPE, 916 spd_ddr5_spd_type_map, ARRAY_SIZE(spd_ddr5_spd_type_map)); 917 } 918 919 static const spd_value_map_t spd_ddr5_pmic_type_map[] = { 920 { SPD_DDR5_COM_INFO_TYPE_PMIC5000, SPD_PMIC_T_PMIC5000, false }, 921 { SPD_DDR5_COM_INFO_TYPE_PMIC5010, SPD_PMIC_T_PMIC5010, false }, 922 { SPD_DDR5_COM_INFO_TYPE_PMIC5100, SPD_PMIC_T_PMIC5100, false }, 923 }; 924 925 static void 926 spd_parse_ddr5_pmic0(spd_info_t *si, uint32_t off, uint32_t len, 927 const char *key) 928 { 929 ASSERT3U(len, ==, 4); 930 const uint8_t type = si->si_data[off + 2]; 931 if (SPD_DDR5_COM_INFO_PRES(type) == 0) 932 return; 933 934 spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_PMIC_0, 935 SPD_KEY_DEV_PMIC0_MFG, SPD_KEY_DEV_PMIC0_MFG_NAME, 936 SPD_KEY_DEV_PMIC0_REV, SPD_KEY_DEV_PMIC0_TYPE, 937 spd_ddr5_pmic_type_map, ARRAY_SIZE(spd_ddr5_pmic_type_map)); 938 } 939 940 static void 941 spd_parse_ddr5_pmic1(spd_info_t *si, uint32_t off, uint32_t len, 942 const char *key) 943 { 944 ASSERT3U(len, ==, 4); 945 const uint8_t type = si->si_data[off + 2]; 946 if (SPD_DDR5_COM_INFO_PRES(type) == 0) 947 return; 948 949 spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_PMIC_1, 950 SPD_KEY_DEV_PMIC1_MFG, SPD_KEY_DEV_PMIC1_MFG_NAME, 951 SPD_KEY_DEV_PMIC1_REV, SPD_KEY_DEV_PMIC1_TYPE, 952 spd_ddr5_pmic_type_map, ARRAY_SIZE(spd_ddr5_pmic_type_map)); 953 } 954 955 static void 956 spd_parse_ddr5_pmic2(spd_info_t *si, uint32_t off, uint32_t len, 957 const char *key) 958 { 959 ASSERT3U(len, ==, 4); 960 const uint8_t type = si->si_data[off + 2]; 961 if (SPD_DDR5_COM_INFO_PRES(type) == 0) 962 return; 963 964 spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_PMIC_2, 965 SPD_KEY_DEV_PMIC2_MFG, SPD_KEY_DEV_PMIC2_MFG_NAME, 966 SPD_KEY_DEV_PMIC2_REV, SPD_KEY_DEV_PMIC2_TYPE, 967 spd_ddr5_pmic_type_map, ARRAY_SIZE(spd_ddr5_pmic_type_map)); 968 } 969 970 static const spd_value_map_t spd_ddr5_temp_type_map[] = { 971 { SPD_DDR5_COM_INFO_TYPE_TS5111, SPD_TEMP_T_TS5111, false }, 972 { SPD_DDR5_COM_INFO_TYPE_TS5110, SPD_TEMP_T_TS5110, false } 973 }; 974 975 static void 976 spd_parse_ddr5_ts(spd_info_t *si, uint32_t off, uint32_t len, const char *key) 977 { 978 ASSERT3U(len, ==, 4); 979 const uint8_t type = si->si_data[off + 2]; 980 spd_device_t flags = 0; 981 if (SPD_DDR5_COM_INFO_PRES(type) != 0) 982 flags |= SPD_DEVICE_TEMP_1; 983 if (SPD_DDR5_COM_INFO_TS1_PRES(type) != 0) 984 flags |= SPD_DEVICE_TEMP_2; 985 if (flags == 0) 986 return; 987 988 spd_parse_ddr5_dev_common(si, off, flags, SPD_KEY_DEV_TEMP_MFG, 989 SPD_KEY_DEV_TEMP_MFG_NAME, SPD_KEY_DEV_TEMP_REV, 990 SPD_KEY_DEV_TEMP_TYPE, spd_ddr5_temp_type_map, 991 ARRAY_SIZE(spd_ddr5_temp_type_map)); 992 } 993 994 static const spd_str_map_t spd_ddr5_design_map[] = { 995 { 0, "A", false }, 996 { 1, "B", false }, 997 { 2, "C", false }, 998 { 3, "D", false }, 999 { 4, "E", false }, 1000 { 5, "F", false }, 1001 { 6, "G", false }, 1002 { 7, "H", false }, 1003 { 8, "J", false }, 1004 { 9, "K", false }, 1005 { 10, "L", false }, 1006 { 11, "M", false }, 1007 { 12, "N", false }, 1008 { 13, "P", false }, 1009 { 14, "R", false }, 1010 { 15, "T", false }, 1011 { 16, "U", false }, 1012 { 17, "V", false }, 1013 { 18, "W", false }, 1014 { 19, "Y", false }, 1015 { 20, "AA", false }, 1016 { 21, "AB", false }, 1017 { 22, "AC", false }, 1018 { 23, "AD", false }, 1019 { 24, "AE", false }, 1020 { 25, "AF", false }, 1021 { 26, "AG", false }, 1022 { 27, "AH", false }, 1023 { 28, "AJ", false }, 1024 { 29, "AK", false }, 1025 { 31, "ZZ", false } 1026 }; 1027 1028 static const spd_value_range_t spd_ddr5_design_rev_range = { 1029 .svr_max = SPD_DDR5_COM_REF_REV_MAX 1030 }; 1031 1032 static void 1033 spd_parse_ddr5_design(spd_info_t *si, uint32_t off, uint32_t len, 1034 const char *key) 1035 { 1036 const uint8_t data = si->si_data[off]; 1037 const uint8_t rev = SPD_DDR5_COM_REF_REV(data); 1038 const uint8_t card = SPD_DDR5_COM_REF_REV(data); 1039 1040 spd_insert_str_map(si, SPD_KEY_MOD_REF_DESIGN, card, 1041 spd_ddr5_design_map, ARRAY_SIZE(spd_ddr5_design_map)); 1042 spd_insert_range(si, SPD_KEY_MOD_DESIGN_REV, rev, 1043 &spd_ddr5_design_rev_range); 1044 } 1045 1046 static const spd_value_map_t spd_ddr5_attr_nrows_map[] = { 1047 { SPD_DDR5_COM_ATTR_NROWS_UNDEF, 0, true }, 1048 { SPD_DDR5_COM_ATTR_NROWS_1, 1, false }, 1049 { SPD_DDR5_COM_ATTR_NROWS_2, 2, false } 1050 }; 1051 1052 static const spd_value_map_t spd_ddr5_attr_otr_map[] = { 1053 { SPD_DDR5_COM_ATTR_OTR_A1T, JEDEC_TEMP_CASE_A1T, false }, 1054 { SPD_DDR5_COM_ATTR_OTR_A2T, JEDEC_TEMP_CASE_A2T, false }, 1055 { SPD_DDR5_COM_ATTR_OTR_A3T, JEDEC_TEMP_CASE_A3T, false }, 1056 { SPD_DDR5_COM_ATTR_OTR_IT, JEDEC_TEMP_CASE_IT, false }, 1057 { SPD_DDR5_COM_ATTR_OTR_ST, JEDEC_TEMP_CASE_ST, false }, 1058 { SPD_DDR5_COM_ATTR_OTR_ET, JEDEC_TEMP_CASE_ET, false }, 1059 { SPD_DDR5_COM_ATTR_OTR_RT, JEDEC_TEMP_CASE_RT, false }, 1060 { SPD_DDR5_COM_ATTR_OTR_NT, JEDEC_TEMP_CASE_NT, false }, 1061 { SPD_DDR5_COM_ATTR_OTR_XT, JEDEC_TEMP_CASE_XT, false } 1062 }; 1063 1064 static void 1065 spd_parse_ddr5_attr(spd_info_t *si, uint32_t off, uint32_t len, 1066 const char *key) 1067 { 1068 const uint8_t data = si->si_data[off]; 1069 const uint8_t otr = SPD_DDR5_COM_ATTR_OTR(data); 1070 const uint8_t nrows = SPD_DDR5_COM_ATTR_NROWS(data); 1071 1072 if (SPD_DDR5_COM_ATTR_SPREAD(data) != 0) 1073 spd_upsert_flag(si, SPD_KEY_DEVS, SPD_DEVICE_HS); 1074 spd_insert_map(si, SPD_KEY_MOD_NROWS, nrows, 1075 spd_ddr5_attr_nrows_map, ARRAY_SIZE(spd_ddr5_attr_nrows_map)); 1076 spd_insert_map(si, SPD_KEY_MOD_OPER_TEMP, otr, 1077 spd_ddr5_attr_otr_map, ARRAY_SIZE(spd_ddr5_attr_otr_map)); 1078 } 1079 1080 static const spd_value_range_t spd_ddr5_nrank_range = { 1081 .svr_base = SPD_DDR5_COM_ORG_NRANK_BASE 1082 }; 1083 1084 static void 1085 spd_parse_ddr5_mod_org(spd_info_t *si, uint32_t off, uint32_t len, 1086 const char *key) 1087 { 1088 const uint8_t data = si->si_data[off]; 1089 const uint8_t nranks = SPD_DDR4_MOD_ORG_NPKG_RANK(data); 1090 1091 if (SPD_DDR5_COM_ORG_MIX(data) == SPD_DDR5_COM_ORG_MIX_ASYM) 1092 spd_nvl_insert_key(si, SPD_KEY_RANK_ASYM); 1093 spd_insert_range(si, SPD_KEY_NRANKS, nranks, &spd_ddr5_nrank_range); 1094 } 1095 1096 static const spd_value_map_t spd_ddr5_ext_width[] = { 1097 { SPD_DDR5_COM_BUS_WIDTH_EXT_NONE, 0, false }, 1098 { SPD_DDR5_COM_BUS_WIDTH_EXT_4b, 4, false }, 1099 { SPD_DDR5_COM_BUS_WIDTH_EXT_8b, 8, false } 1100 }; 1101 1102 static const spd_value_map_t spd_ddr5_pri_width[] = { 1103 { SPD_DDR5_COM_BUS_WIDTH_PRI_8b, 8, false }, 1104 { SPD_DDR5_COM_BUS_WIDTH_PRI_16b, 16, false }, 1105 { SPD_DDR5_COM_BUS_WIDTH_PRI_32b, 32, false }, 1106 { SPD_DDR5_COM_BUS_WIDTH_PRI_64b, 64, false }, 1107 }; 1108 1109 static const spd_value_range_t spd_ddr5_nsc_range = { 1110 .svr_max = SPD_DDR5_COM_BUS_WIDTH_NSC_MAX, 1111 .svr_base = SPD_DDR5_COM_BUS_WIDTH_NSC_BASE 1112 }; 1113 1114 static void 1115 spd_parse_ddr5_bus_width(spd_info_t *si, uint32_t off, uint32_t len, 1116 const char *key) 1117 { 1118 const uint8_t data = si->si_data[off]; 1119 const uint8_t nsc = SPD_DDR5_COM_BUS_WIDTH_NSC(data); 1120 const uint8_t ext = SPD_DDR5_COM_BUS_WIDTH_EXT(data); 1121 const uint8_t pri = SPD_DDR5_COM_BUS_WIDTH_PRI(data); 1122 1123 spd_insert_range(si, SPD_KEY_NSUBCHAN, nsc, &spd_ddr5_nsc_range); 1124 spd_insert_map(si, SPD_KEY_ECC_WIDTH, ext, spd_ddr5_ext_width, 1125 ARRAY_SIZE(spd_ddr5_ext_width)); 1126 spd_insert_map(si, SPD_KEY_DATA_WIDTH, pri, spd_ddr5_pri_width, 1127 ARRAY_SIZE(spd_ddr5_pri_width)); 1128 } 1129 1130 static const spd_parse_t spd_ddr5_module[] = { 1131 { .sp_off = SPD_DDR5_COM_REV, .sp_parse = spd_parse_ddr5_mod_rev }, 1132 { .sp_off = SPD_DDR5_COM_HASH, .sp_parse = spd_parse_ddr5_hash_seq, 1133 .sp_key = SPD_KEY_HASH_SEQ }, 1134 { .sp_off = SPD_DDR5_COM_MFG_ID0_SPD, .sp_len = 4, 1135 .sp_parse = spd_parse_ddr5_spd }, 1136 { .sp_off = SPD_DDR5_COM_MFG_ID0_PMIC0, .sp_len = 4, 1137 .sp_parse = spd_parse_ddr5_pmic0 }, 1138 { .sp_off = SPD_DDR5_COM_MFG_ID0_PMIC1, .sp_len = 4, 1139 .sp_parse = spd_parse_ddr5_pmic1 }, 1140 { .sp_off = SPD_DDR5_COM_MFG_ID0_PMIC2, .sp_len = 4, 1141 .sp_parse = spd_parse_ddr5_pmic2 }, 1142 { .sp_off = SPD_DDR5_COM_MFG_ID0_TS, .sp_len = 4, 1143 .sp_parse = spd_parse_ddr5_ts }, 1144 { .sp_off = SPD_DDR5_COM_HEIGHT, .sp_key = SPD_KEY_MOD_HEIGHT, 1145 .sp_parse = spd_parse_height }, 1146 { .sp_off = SPD_DDR5_COM_THICK, .sp_parse = spd_parse_thickness }, 1147 { .sp_off = SPD_DDR5_COM_REF, .sp_parse = spd_parse_ddr5_design }, 1148 { .sp_off = SPD_DDR5_COM_ATTR, .sp_parse = spd_parse_ddr5_attr }, 1149 { .sp_off = SPD_DDR5_COM_ORG, .sp_parse = spd_parse_ddr5_mod_org }, 1150 { .sp_off = SPD_DDR5_COM_BUS_WIDTH, 1151 .sp_parse = spd_parse_ddr5_bus_width }, 1152 /* We include the DDR5 CRC in this group as it's considered common */ 1153 { .sp_len = SPD_DDR5_CRC_MSB + 1, .sp_key = SPD_KEY_CRC_DDR5, 1154 .sp_parse = spd_parse_crc }, 1155 }; 1156 1157 static const spd_parse_t spd_ddr5_mfg[] = { 1158 { .sp_off = SPD_DDR5_MOD_MFG_ID0, .sp_len = 2, 1159 .sp_key = SPD_KEY_MFG_MOD_MFG_ID, .sp_parse = spd_parse_jedec_id }, 1160 { .sp_off = SPD_DDR5_MOD_MFG_ID0, .sp_len = 2, 1161 .sp_key = SPD_KEY_MFG_MOD_MFG_NAME, 1162 .sp_parse = spd_parse_jedec_id_str }, 1163 { .sp_off = SPD_DDR5_DRAM_MFG_ID0, .sp_len = 2, 1164 .sp_key = SPD_KEY_MFG_DRAM_MFG_ID, .sp_parse = spd_parse_jedec_id }, 1165 { .sp_off = SPD_DDR5_DRAM_MFG_ID0, .sp_len = 2, 1166 .sp_key = SPD_KEY_MFG_DRAM_MFG_NAME, 1167 .sp_parse = spd_parse_jedec_id_str }, 1168 { .sp_off = SPD_DDR5_MOD_MFG_LOC, .sp_key = SPD_KEY_MFG_MOD_LOC_ID, 1169 .sp_parse = spd_parse_raw_u8 }, 1170 { .sp_off = SPD_DDR5_MOD_MFG_YEAR, .sp_key = SPD_KEY_MFG_MOD_YEAR, 1171 .sp_parse = spd_parse_hex_string }, 1172 { .sp_off = SPD_DDR5_MOD_MFG_WEEK, .sp_key = SPD_KEY_MFG_MOD_WEEK, 1173 .sp_parse = spd_parse_hex_string }, 1174 { .sp_off = SPD_DDR5_MOD_SN, .sp_len = SPD_DDR5_MOD_SN_LEN, 1175 .sp_key = SPD_KEY_MFG_MOD_SN, .sp_parse = spd_parse_hex_string }, 1176 { .sp_off = SPD_DDR5_MOD_PN, .sp_len = SPD_DDR5_MOD_PN_LEN, 1177 .sp_key = SPD_KEY_MFG_MOD_PN, .sp_parse = spd_parse_string }, 1178 { .sp_off = SPD_DDR5_MOD_REV, .sp_key = SPD_KEY_MFG_MOD_REV, 1179 .sp_parse = spd_parse_dram_step }, 1180 { .sp_off = SPD_DDR5_DRAM_STEP, .sp_key = SPD_KEY_MFG_DRAM_STEP, 1181 .sp_parse = spd_parse_dram_step } 1182 }; 1183 1184 /* 1185 * Annex A.2 UDIMM and SODIMM specific processing. 1186 */ 1187 1188 static const spd_value_map_t spd_ddr5_cd_type_map[] = { 1189 { SPD_DDR5_UDIMM_INFO_TYPE_DDR5CK01, SPD_CD_T_DDR5CK01, false } 1190 }; 1191 1192 static void 1193 spd_parse_ddr5_udimm_cd(spd_info_t *si, uint32_t off, uint32_t len, 1194 const char *key) 1195 { 1196 ASSERT3U(len, ==, 4); 1197 const uint8_t type = si->si_data[off + 2]; 1198 if (SPD_DDR5_COM_INFO_PRES(type) == 0) 1199 return; 1200 1201 spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_CD, 1202 SPD_KEY_DEV_CD_MFG, SPD_KEY_DEV_CD_MFG_NAME, 1203 SPD_KEY_DEV_CD_REV, SPD_KEY_DEV_CD_TYPE, 1204 spd_ddr5_cd_type_map, ARRAY_SIZE(spd_ddr5_cd_type_map)); 1205 } 1206 1207 static const spd_parse_t spd_ddr5_udimm[] = { 1208 { .sp_off = SPD_DDR5_COM_MFG_ID0_TS, .sp_len = 4, 1209 .sp_parse = spd_parse_ddr5_udimm_cd } 1210 }; 1211 1212 /* 1213 * Annex A.3 RDIMM and LRDIMM specific processing. Because certain fields are 1214 * LRDIMM-only, we use two different top-level tables to drive them; however, 1215 * they generally overlap otherwise. Items that are LRDIMM only will contain 1216 * lrdimm in the name. All items named rdimm are shared between both the LRDIMM 1217 * and RDIMM processing. 1218 */ 1219 static const spd_value_map_t spd_ddr5_rcd_type_map[] = { 1220 { SPD_DDR5_RDIMM_INFO_TYPE_RCD01, SPD_RCD_T_DDR5RCD01, false }, 1221 { SPD_DDR5_RDIMM_INFO_TYPE_RCD02, SPD_RCD_T_DDR5RCD02, false }, 1222 { SPD_DDR5_RDIMM_INFO_TYPE_RCD03, SPD_RCD_T_DDR5RCD03, false } 1223 }; 1224 1225 static const spd_value_map_t spd_ddr5_db_type_map[] = { 1226 { SPD_DDR5_RDIMM_INFO_TYPE_DB01, SPD_DB_T_DDR5DB01, false }, 1227 { SPD_DDR5_RDIMM_INFO_TYPE_DB02, SPD_DB_T_DDR5DB02, false } 1228 }; 1229 1230 static void 1231 spd_parse_ddr5_rdimm_rcd(spd_info_t *si, uint32_t off, uint32_t len, 1232 const char *key) 1233 { 1234 ASSERT3U(len, ==, 4); 1235 const uint8_t type = si->si_data[off + 2]; 1236 if (SPD_DDR5_COM_INFO_PRES(type) == 0) 1237 return; 1238 1239 spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_RCD, 1240 SPD_KEY_DEV_RCD_MFG, SPD_KEY_DEV_RCD_MFG_NAME, 1241 SPD_KEY_DEV_RCD_REV, SPD_KEY_DEV_RCD_TYPE, 1242 spd_ddr5_rcd_type_map, ARRAY_SIZE(spd_ddr5_rcd_type_map)); 1243 } 1244 1245 static void 1246 spd_parse_ddr5_lrdimm_db(spd_info_t *si, uint32_t off, uint32_t len, 1247 const char *key) 1248 { 1249 ASSERT3U(len, ==, 4); 1250 const uint8_t type = si->si_data[off + 2]; 1251 if (SPD_DDR5_COM_INFO_PRES(type) == 0) 1252 return; 1253 1254 spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_DB, 1255 SPD_KEY_DEV_DB_MFG, SPD_KEY_DEV_DB_MFG_NAME, 1256 SPD_KEY_DEV_DB_REV, SPD_KEY_DEV_DB_TYPE, 1257 spd_ddr5_db_type_map, ARRAY_SIZE(spd_ddr5_db_type_map)); 1258 } 1259 1260 static void 1261 spd_parse_ddr5_rdimm_clken(spd_info_t *si, uint32_t off, uint32_t len, 1262 const char *key) 1263 { 1264 const uint8_t data = si->si_data[off]; 1265 1266 if (SPD_DDR5_RDIMM_CLKEN_QACK(data) == 0) 1267 spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_QACK_EN); 1268 if (SPD_DDR5_RDIMM_CLKEN_QBCK(data) == 0) 1269 spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_QBCK_EN); 1270 if (SPD_DDR5_RDIMM_CLKEN_QCCK(data) == 0) 1271 spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_QCCK_EN); 1272 if (SPD_DDR5_RDIMM_CLKEN_QDCK(data) == 0) 1273 spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_QDCK_EN); 1274 if (SPD_DDR5_RDIMM_CLKEN_BCK(data) == 0) 1275 spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_BCK_EN); 1276 } 1277 1278 static void 1279 spd_parse_ddr5_rdimm_rwen(spd_info_t *si, uint32_t off, uint32_t len, 1280 const char *key) 1281 { 1282 const uint8_t data = si->si_data[off]; 1283 1284 if (SPD_DDR5_RDIMM_RW09_QBCS(data) == 0) 1285 spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_QBCS_EN); 1286 if (SPD_DDR5_RDIMM_RW09_QACS(data) == 0) 1287 spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_QACS_EN); 1288 if (SPD_DDR5_RDIMM_RW09_QXCA13(data) == 0) 1289 spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_QxCA13_EN); 1290 if (SPD_DDR5_RDIMM_RW09_BCS(data) == 0) 1291 spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_BCS_EN); 1292 if (SPD_DDR5_RDIMM_RW09_DCS(data) == 0) 1293 spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_DCS1_EN); 1294 if (SPD_DDR5_RDIMM_RW09_QBCA(data) == 0) 1295 spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_QBCA_EN); 1296 if (SPD_DDR5_RDIMM_RW09_QACA(data) == 0) 1297 spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_QACA_EN); 1298 } 1299 1300 static const spd_value_map_t spd_ddr5_imp_map[] = { 1301 { SPD_DDR5_RDIMM_DRV_20R, 20, false }, 1302 { SPD_DDR5_RDIMM_DRV_14R, 14, false }, 1303 { SPD_DDR5_RDIMM_DRV_10R, 10, false } 1304 }; 1305 1306 static void 1307 spd_parse_ddr5_rdimm_clkimp(spd_info_t *si, uint32_t off, uint32_t len, 1308 const char *key) 1309 { 1310 const uint8_t data = si->si_data[off]; 1311 const uint8_t qack = SPD_DDR5_RDIMM_QCK_DRV_QACK(data); 1312 const uint8_t qbck = SPD_DDR5_RDIMM_QCK_DRV_QBCK(data); 1313 const uint8_t qcck = SPD_DDR5_RDIMM_QCK_DRV_QCCK(data); 1314 const uint8_t qdck = SPD_DDR5_RDIMM_QCK_DRV_QDCK(data); 1315 1316 spd_insert_map(si, SPD_KEY_DDR5_RCD_QACK_IMP, qack, spd_ddr5_imp_map, 1317 ARRAY_SIZE(spd_ddr5_imp_map)); 1318 spd_insert_map(si, SPD_KEY_DDR5_RCD_QBCK_IMP, qbck, spd_ddr5_imp_map, 1319 ARRAY_SIZE(spd_ddr5_imp_map)); 1320 spd_insert_map(si, SPD_KEY_DDR5_RCD_QCCK_IMP, qcck, spd_ddr5_imp_map, 1321 ARRAY_SIZE(spd_ddr5_imp_map)); 1322 spd_insert_map(si, SPD_KEY_DDR5_RCD_QDCK_IMP, qdck, spd_ddr5_imp_map, 1323 ARRAY_SIZE(spd_ddr5_imp_map)); 1324 } 1325 1326 static void 1327 spd_parse_ddr5_rdimm_casimp(spd_info_t *si, uint32_t off, uint32_t len, 1328 const char *key) 1329 { 1330 const uint8_t data = si->si_data[off]; 1331 const uint8_t cs = SPD_DDR5_RDIMM_QCA_DRV_CS(data); 1332 const uint8_t ca = SPD_DDR5_RDIMM_QCA_DRV_CA(data); 1333 1334 spd_insert_map(si, SPD_KEY_DDR5_RCD_CS_IMP, cs, spd_ddr5_imp_map, 1335 ARRAY_SIZE(spd_ddr5_imp_map)); 1336 spd_insert_map(si, SPD_KEY_DDR5_RCD_CA_IMP, ca, spd_ddr5_imp_map, 1337 ARRAY_SIZE(spd_ddr5_imp_map)); 1338 } 1339 1340 /* 1341 * Unlike the other impedence values the BCOM signal does not allow a 10 Ohm 1342 * value. 1343 */ 1344 static const spd_value_map_t spd_ddr5_bcom_map[] = { 1345 { SPD_DDR5_RDIMM_DRV_20R, 20, false }, 1346 { SPD_DDR5_RDIMM_DRV_14R, 14, false } 1347 }; 1348 1349 static void 1350 spd_parse_ddr5_lrdimm_dbimp(spd_info_t *si, uint32_t off, uint32_t len, 1351 const char *key) 1352 { 1353 const uint8_t data = si->si_data[off]; 1354 const uint8_t bck = SPD_DDR5_LRDIMM_DB_DRV_BCK(data); 1355 const uint8_t bcom = SPD_DDR5_LRDIMM_DB_DRV_BCOM(data); 1356 1357 spd_insert_map(si, SPD_KEY_DDR5_RCD_BCK_IMP, bck, spd_ddr5_imp_map, 1358 ARRAY_SIZE(spd_ddr5_imp_map)); 1359 spd_insert_map(si, SPD_KEY_DDR5_RCD_BCOM_IMP, bcom, spd_ddr5_bcom_map, 1360 ARRAY_SIZE(spd_ddr5_bcom_map)); 1361 } 1362 1363 /* 1364 * Some slew rates only allow moderate and fast, others also allow slow. We use 1365 * different definitions to capture the allowed sets. 1366 */ 1367 static const spd_value_map_t spd_ddr5_mfslew_map[] = { 1368 { SPD_DDR5_RDIMM_SLEW_MODERTE, SPD_SLEW_MODERATE, false }, 1369 { SPD_DDR5_RDIMM_SLEW_FAST, SPD_SLEW_FAST, false } 1370 }; 1371 1372 static const spd_value_map_t spd_ddr5_smfslew_map[] = { 1373 { SPD_DDR5_RDIMM_SLEW_MODERTE, SPD_SLEW_MODERATE, false }, 1374 { SPD_DDR5_RDIMM_SLEW_FAST, SPD_SLEW_FAST, false }, 1375 { SPD_DDR5_RDIMM_SLEW_SLOW, SPD_SLEW_SLOW, false } 1376 }; 1377 1378 static void 1379 spd_parse_ddr5_rdimm_qslew(spd_info_t *si, uint32_t off, uint32_t len, 1380 const char *key) 1381 { 1382 const uint8_t data = si->si_data[off]; 1383 const uint8_t qcs = SPD_DDR5_RDIMM_QXX_SLEW_QCS(data); 1384 const uint8_t qca = SPD_DDR5_RDIMM_QXX_SLEW_QCA(data); 1385 const uint8_t qck = SPD_DDR5_RDIMM_QXX_SLEW_QCK(data); 1386 1387 spd_insert_map(si, SPD_KEY_DDR5_RCD_QCK_SLEW, qck, spd_ddr5_mfslew_map, 1388 ARRAY_SIZE(spd_ddr5_mfslew_map)); 1389 spd_insert_map(si, SPD_KEY_DDR5_RCD_QCA_SLEW, qca, spd_ddr5_smfslew_map, 1390 ARRAY_SIZE(spd_ddr5_smfslew_map)); 1391 spd_insert_map(si, SPD_KEY_DDR5_RCD_QCS_SLEW, qcs, spd_ddr5_smfslew_map, 1392 ARRAY_SIZE(spd_ddr5_smfslew_map)); 1393 } 1394 1395 static void 1396 spd_parse_ddr5_lrdimm_bslew(spd_info_t *si, uint32_t off, uint32_t len, 1397 const char *key) 1398 { 1399 const uint8_t data = si->si_data[off]; 1400 const uint8_t bck = SPD_DDR5_LRDIMM_BXX_SLEW_BCK(data); 1401 const uint8_t bcom = SPD_DDR5_LRDIMM_BXX_SLEW_BCOM(data); 1402 1403 spd_insert_map(si, SPD_KEY_DDR5_RCD_BCK_SLEW, bck, spd_ddr5_mfslew_map, 1404 ARRAY_SIZE(spd_ddr5_mfslew_map)); 1405 spd_insert_map(si, SPD_KEY_DDR5_RCD_BCOM_SLEW, bcom, 1406 spd_ddr5_smfslew_map, ARRAY_SIZE(spd_ddr5_smfslew_map)); 1407 } 1408 1409 static const spd_value_map_t spd_ddr5_rtt_term_map[] = { 1410 { SPD_DDR5_LDRIMM_PARK_OFF, 0, true }, 1411 { SPD_DDR5_LDRIMM_PARK_240R, 240, false }, 1412 { SPD_DDR5_LDRIMM_PARK_120R, 120, false }, 1413 { SPD_DDR5_LDRIMM_PARK_80R, 80, false }, 1414 { SPD_DDR5_LDRIMM_PARK_60R, 60, false }, 1415 { SPD_DDR5_LDRIMM_PARK_48R, 48, false }, 1416 { SPD_DDR5_LDRIMM_PARK_40R, 40, false }, 1417 { SPD_DDR5_LDRIMM_PARK_34R, 34, false } 1418 }; 1419 1420 static void 1421 spd_parse_ddr5_lrdimm_rtt(spd_info_t *si, uint32_t off, uint32_t len, 1422 const char *key) 1423 { 1424 const uint8_t data = si->si_data[off]; 1425 const uint8_t rtt = SPD_DDR5_LRDIMM_PARK_TERM(data); 1426 1427 spd_insert_map(si, SPD_KEY_DDR5_RCD_RTT_TERM, rtt, 1428 spd_ddr5_rtt_term_map, ARRAY_SIZE(spd_ddr5_rtt_term_map)); 1429 } 1430 1431 static const spd_parse_t spd_ddr5_rdimm[] = { 1432 { .sp_off = SPD_DDR5_RDIMM_MFG_ID0_RCD, .sp_len = 4, 1433 .sp_parse = spd_parse_ddr5_rdimm_rcd }, 1434 { .sp_off = SPD_DDR5_RDIMM_CLKEN, 1435 .sp_parse = spd_parse_ddr5_rdimm_clken }, 1436 { .sp_off = SPD_DDR5_RDIMM_RW09, 1437 .sp_parse = spd_parse_ddr5_rdimm_rwen }, 1438 { .sp_off = SPD_DDR5_RDIMM_QCK_DRV, 1439 .sp_parse = spd_parse_ddr5_rdimm_clkimp }, 1440 { .sp_off = SPD_DDR5_RDIMM_QCA_DRV, 1441 .sp_parse = spd_parse_ddr5_rdimm_casimp }, 1442 { .sp_off = SPD_DDR5_RDIMM_QXX_SLEW, 1443 .sp_parse = spd_parse_ddr5_rdimm_qslew } 1444 }; 1445 1446 static const spd_parse_t spd_ddr5_lrdimm[] = { 1447 { .sp_off = SPD_DDR5_RDIMM_MFG_ID0_RCD, .sp_len = 4, 1448 .sp_parse = spd_parse_ddr5_rdimm_rcd }, 1449 { .sp_off = SPD_DDR5_RDIMM_MFG_ID0_DB, .sp_len = 4, 1450 .sp_parse = spd_parse_ddr5_lrdimm_db }, 1451 { .sp_off = SPD_DDR5_RDIMM_CLKEN, 1452 .sp_parse = spd_parse_ddr5_rdimm_clken }, 1453 { .sp_off = SPD_DDR5_RDIMM_RW09, 1454 .sp_parse = spd_parse_ddr5_rdimm_rwen }, 1455 { .sp_off = SPD_DDR5_RDIMM_QCK_DRV, 1456 .sp_parse = spd_parse_ddr5_rdimm_clkimp }, 1457 { .sp_off = SPD_DDR5_RDIMM_QCA_DRV, 1458 .sp_parse = spd_parse_ddr5_rdimm_casimp }, 1459 { .sp_off = SPD_DDR5_LRDIMM_DB_DRV, 1460 .sp_parse = spd_parse_ddr5_lrdimm_dbimp }, 1461 { .sp_off = SPD_DDR5_RDIMM_QXX_SLEW, 1462 .sp_parse = spd_parse_ddr5_rdimm_qslew }, 1463 { .sp_off = SPD_DDR5_LRDIMM_BXX_SLEW, 1464 .sp_parse = spd_parse_ddr5_lrdimm_bslew }, 1465 { .sp_off = SPD_DDR5_LRDIMM_PARK, 1466 .sp_parse = spd_parse_ddr5_lrdimm_rtt }, 1467 }; 1468 1469 /* 1470 * Annex A.4 MRDIMM specific processing. 1471 */ 1472 static const spd_value_map_t spd_ddr5_mrcd_type_map[] = { 1473 { SPD_DDR5_MRDIMM_INFO_TYPE_MRCD01, SPD_MRCD_T_DDR5MRCD01, false } 1474 }; 1475 1476 static const spd_value_map_t spd_ddr5_mdb_type_map[] = { 1477 { SPD_DDR5_MRDIMM_INFO_TYPE_MDB01, SPD_MDB_T_DDR5MDB01, false } 1478 }; 1479 1480 static void 1481 spd_parse_ddr5_mrdimm_mrcd(spd_info_t *si, uint32_t off, uint32_t len, 1482 const char *key) 1483 { 1484 ASSERT3U(len, ==, 4); 1485 const uint8_t type = si->si_data[off + 2]; 1486 if (SPD_DDR5_COM_INFO_PRES(type) == 0) 1487 return; 1488 1489 spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_MRCD, 1490 SPD_KEY_DEV_MRCD_MFG, SPD_KEY_DEV_MRCD_MFG_NAME, 1491 SPD_KEY_DEV_MRCD_REV, SPD_KEY_DEV_MRCD_TYPE, 1492 spd_ddr5_mrcd_type_map, ARRAY_SIZE(spd_ddr5_mrcd_type_map)); 1493 } 1494 1495 static void 1496 spd_parse_ddr5_mrdimm_mdb(spd_info_t *si, uint32_t off, uint32_t len, 1497 const char *key) 1498 { 1499 ASSERT3U(len, ==, 4); 1500 const uint8_t type = si->si_data[off + 2]; 1501 if (SPD_DDR5_COM_INFO_PRES(type) == 0) 1502 return; 1503 1504 spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_MDB, 1505 SPD_KEY_DEV_MDB_MFG, SPD_KEY_DEV_MDB_MFG_NAME, 1506 SPD_KEY_DEV_MDB_REV, SPD_KEY_DEV_MDB_TYPE, 1507 spd_ddr5_mdb_type_map, ARRAY_SIZE(spd_ddr5_mdb_type_map)); 1508 } 1509 1510 static const spd_parse_t spd_ddr5_mrdimm[] = { 1511 { .sp_off = SPD_DDR5_MRDIMM_MFG_ID0_MRCD, .sp_len = 4, 1512 .sp_parse = spd_parse_ddr5_mrdimm_mrcd }, 1513 { .sp_off = SPD_DDR5_MRDIMM_MFG_ID0_MDB, .sp_len = 4, 1514 .sp_parse = spd_parse_ddr5_mrdimm_mdb } 1515 }; 1516 1517 /* 1518 * Annex A.5 Differential Memory Module processing. 1519 */ 1520 static const spd_value_map_t spd_ddr5_dmb_type_map[] = { 1521 { SPD_DDR5_DDIMM_INFO_TYPE_DMB501, SPD_DMB_T_DMB5011, false } 1522 }; 1523 1524 static void 1525 spd_parse_ddr5_ddimm_dmb(spd_info_t *si, uint32_t off, uint32_t len, 1526 const char *key) 1527 { 1528 ASSERT3U(len, ==, 4); 1529 const uint8_t type = si->si_data[off + 2]; 1530 if (SPD_DDR5_COM_INFO_PRES(type) == 0) 1531 return; 1532 1533 spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_DMB, 1534 SPD_KEY_DEV_DMB_MFG, SPD_KEY_DEV_DMB_MFG_NAME, 1535 SPD_KEY_DEV_DMB_REV, SPD_KEY_DEV_DMB_TYPE, 1536 spd_ddr5_dmb_type_map, ARRAY_SIZE(spd_ddr5_dmb_type_map)); 1537 } 1538 1539 static const spd_parse_t spd_ddr5_ddimm[] = { 1540 { .sp_off = SPD_DDR5_DDIMM_MFG_ID0_DMB, .sp_len = 4, 1541 .sp_parse = spd_parse_ddr5_ddimm_dmb }, 1542 }; 1543 1544 static void 1545 spd_parse_ddr5_mod_specific(spd_info_t *si) 1546 { 1547 uint32_t type; 1548 1549 if (nvlist_lookup_uint32(si->si_nvl, SPD_KEY_MOD_TYPE, &type) != 0) 1550 return; 1551 1552 switch (type) { 1553 case SPD_MOD_TYPE_RDIMM: 1554 spd_parse(si, spd_ddr5_rdimm, ARRAY_SIZE(spd_ddr5_rdimm)); 1555 break; 1556 case SPD_MOD_TYPE_LRDIMM: 1557 spd_parse(si, spd_ddr5_lrdimm, ARRAY_SIZE(spd_ddr5_lrdimm)); 1558 break; 1559 case SPD_MOD_TYPE_UDIMM: 1560 case SPD_MOD_TYPE_SODIMM: 1561 spd_parse(si, spd_ddr5_udimm, ARRAY_SIZE(spd_ddr5_udimm)); 1562 break; 1563 case SPD_MOD_TYPE_MRDIMM: 1564 spd_parse(si, spd_ddr5_mrdimm, ARRAY_SIZE(spd_ddr5_mrdimm)); 1565 break; 1566 case SPD_MOD_TYPE_DDIMM: 1567 spd_parse(si, spd_ddr5_ddimm, ARRAY_SIZE(spd_ddr5_ddimm)); 1568 break; 1569 /* 1570 * Soldered DIMMs don't have any data. 1571 */ 1572 case SPD_MOD_TYPE_SOLDER: 1573 default: 1574 break; 1575 } 1576 } 1577 1578 /* 1579 * DDR5 has two different revisions. One that is present in the base region and 1580 * one that is present in the common module region that covers the 1581 * module-related pieces. We check that both are present and go from there. We 1582 * may want to relax this in the future so that it's easier to just decode a 1583 * subset of this, but for the time being, we require both. 1584 */ 1585 void 1586 spd_parse_ddr5(spd_info_t *si) 1587 { 1588 if (SPD_DDR5_SPD_REV_ENC(si->si_data[SPD_DDR5_SPD_REV]) != 1589 SPD_DDR5_SPD_REV_V1) { 1590 si->si_error = LIBJEDEC_SPD_UNSUP_REV; 1591 return; 1592 } 1593 1594 if (si->si_nbytes <= SPD_DDR5_COM_REV) { 1595 si->si_error = LIBJEDEC_SPD_TOOSHORT; 1596 return; 1597 } 1598 1599 if (SPD_DDR5_SPD_REV_ENC(si->si_data[SPD_DDR5_COM_REV]) != 1600 SPD_DDR5_SPD_REV_V1) { 1601 si->si_error = LIBJEDEC_SPD_UNSUP_REV; 1602 return; 1603 } 1604 1605 spd_parse(si, spd_ddr5_base, ARRAY_SIZE(spd_ddr5_base)); 1606 spd_parse(si, spd_ddr5_module, ARRAY_SIZE(spd_ddr5_module)); 1607 spd_parse(si, spd_ddr5_mfg, ARRAY_SIZE(spd_ddr5_mfg)); 1608 spd_parse_ddr5_mod_specific(si); 1609 } 1610