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 * 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_CUDIMM, SPD_MOD_TYPE_CUDIMM, false }, 53 { SPD_DDR5_MOD_TYPE_TYPE_CSODIMM, SPD_MOD_TYPE_CSODIMM, false }, 54 { SPD_DDR5_MOD_TYPE_TYPE_MRDIMM, SPD_MOD_TYPE_MRDIMM, false }, 55 { SPD_DDR5_MOD_TYPE_TYPE_CAMM2, SPD_MOD_TYPE_CAMM2, false }, 56 { SPD_DDR5_MOD_TYPE_TYPE_DDIMM, SPD_MOD_TYPE_DDIMM, false }, 57 { SPD_DDR5_MOD_TYPE_TYPE_SOLDER, SPD_MOD_TYPE_SOLDER, false } 58 }; 59 60 static const spd_value_map_t spd_ddr5_mod_is_hybrid_map[] = { 61 { 0, SPD_MOD_NOT_HYBRID, false }, 62 { 1, SPD_MOD_HYBRID_NVDIMMM, false } 63 }; 64 65 static const spd_value_map_t spd_ddr5_mod_hybrid_map[] = { 66 { SPD_DDR5_MOD_TYPE_HYBRID_NVDIMM_N, SPD_MOD_TYPE_NVDIMM_N, false }, 67 { SPD_DDR5_MOD_TYPE_HYBRID_NVDIMM_P, SPD_MOD_TYPE_NVDIMM_P, false } 68 }; 69 70 /* 71 * This is shared between DDR5 and LPDDR5 as they end up using the same 72 * definitions for module types. 73 */ 74 void 75 spd_parse_ddr5_mod_type(spd_info_t *si, uint32_t off, uint32_t len, 76 const char *key) 77 { 78 const uint8_t data = si->si_data[off]; 79 const uint8_t type = SPD_DDR5_MOD_TYPE_TYPE(data); 80 const uint8_t is_hyb = SPD_DDR5_MOD_TYPE_ISHYBRID(data); 81 const uint8_t hybrid = SPD_DDR5_MOD_TYPE_HYBRID(data); 82 83 spd_insert_map(si, SPD_KEY_MOD_HYBRID_TYPE, is_hyb, 84 spd_ddr5_mod_is_hybrid_map, ARRAY_SIZE(spd_ddr5_mod_is_hybrid_map)); 85 86 if (is_hyb != 0) { 87 spd_insert_map(si, SPD_KEY_MOD_NVDIMM_TYPE, hybrid, 88 spd_ddr5_mod_hybrid_map, 89 ARRAY_SIZE(spd_ddr5_mod_hybrid_map)); 90 } 91 92 spd_insert_map(si, SPD_KEY_MOD_TYPE, type, spd_ddr5_mod_type_map, 93 ARRAY_SIZE(spd_ddr5_mod_type_map)); 94 } 95 96 static bool 97 spd_parse_ddr5_isassym(spd_info_t *si) 98 { 99 ASSERT3U(si->si_size, >, SPD_DDR5_COM_ORG); 100 const uint8_t data = si->si_data[SPD_DDR5_COM_ORG]; 101 const uint8_t is_asym = SPD_DDR5_COM_ORG_MIX(data); 102 103 return (is_asym == SPD_DDR5_COM_ORG_MIX_ASYM); 104 } 105 106 static const spd_value_map64_t spd_ddr5_density_map[] = { 107 { SPD_DDR5_DENPKG_DPD_4Gb, 4ULL * 1024ULL * 1024ULL * 1024ULL, false }, 108 { SPD_DDR5_DENPKG_DPD_8Gb, 8ULL * 1024ULL * 1024ULL * 1024ULL, false }, 109 { SPD_DDR5_DENPKG_DPD_12Gb, 12ULL * 1024ULL * 1024ULL * 1024ULL, 110 false }, 111 { SPD_DDR5_DENPKG_DPD_16Gb, 16ULL * 1024ULL * 1024ULL * 1024ULL, 112 false }, 113 { SPD_DDR5_DENPKG_DPD_24Gb, 24ULL * 1024ULL * 1024ULL * 1024ULL, 114 false }, 115 { SPD_DDR5_DENPKG_DPD_32Gb, 32ULL * 1024ULL * 1024ULL * 1024ULL, 116 false }, 117 { SPD_DDR5_DENPKG_DPD_48Gb, 48ULL * 1024ULL * 1024ULL * 1024ULL, 118 false }, 119 { SPD_DDR5_DENPKG_DPD_64Gb, 64ULL * 1024ULL * 1024ULL * 1024ULL, 120 false }, 121 }; 122 123 static const spd_value_map_t spd_ddr5_ndies_map[] = { 124 { SPD_DDR5_DENPKG_DPP_MONO, 1, false }, 125 { SPD_DDR5_DENPKG_DPP_DDP, 2, false }, 126 { SPD_DDR5_DENPKG_DPP_2H3DS, 2, false }, 127 { SPD_DDR5_DENPKG_DPP_4H3DS, 4, false }, 128 { SPD_DDR5_DENPKG_DPP_8H3DS, 8, false }, 129 { SPD_DDR5_DENPKG_DPP_16H3DS, 16, false }, 130 }; 131 132 static const spd_value_map_t spd_ddr5_sl_map[] = { 133 { SPD_DDR5_DENPKG_DPP_MONO, SPD_SL_UNSPECIFIED, false }, 134 { SPD_DDR5_DENPKG_DPP_DDP, SPD_SL_UNSPECIFIED, false }, 135 { SPD_DDR5_DENPKG_DPP_2H3DS, SPD_SL_3DS, false }, 136 { SPD_DDR5_DENPKG_DPP_4H3DS, SPD_SL_3DS, false }, 137 { SPD_DDR5_DENPKG_DPP_8H3DS, SPD_SL_3DS, false }, 138 { SPD_DDR5_DENPKG_DPP_16H3DS, SPD_SL_3DS, false }, 139 }; 140 141 static void 142 spd_parse_ddr5_denpkg(spd_info_t *si, uint8_t data, const char *ndie_key, 143 const char *den_key, const char *sl_key) 144 { 145 const uint8_t ndie = SPD_DDR5_DENPKG_DPP(data); 146 const uint8_t dens = SPD_DDR5_DENPKG_DPD(data); 147 148 spd_insert_map(si, ndie_key, ndie, spd_ddr5_ndies_map, 149 ARRAY_SIZE(spd_ddr5_ndies_map)); 150 spd_insert_map(si, sl_key, ndie, spd_ddr5_sl_map, 151 ARRAY_SIZE(spd_ddr5_sl_map)); 152 spd_insert_map64(si, den_key, dens, spd_ddr5_density_map, 153 ARRAY_SIZE(spd_ddr5_density_map)); 154 } 155 156 static void 157 spd_parse_ddr5_denpkg_pri(spd_info_t *si, uint32_t off, uint32_t len, 158 const char *key) 159 { 160 spd_parse_ddr5_denpkg(si, si->si_data[off], SPD_KEY_PKG_NDIE, 161 SPD_KEY_DIE_SIZE, SPD_KEY_PKG_SL); 162 } 163 164 static void 165 spd_parse_ddr5_denpkg_sec(spd_info_t *si, uint32_t off, uint32_t len, 166 const char *key) 167 { 168 if (!spd_parse_ddr5_isassym(si)) 169 return; 170 171 spd_parse_ddr5_denpkg(si, si->si_data[off], SPD_KEY_SEC_PKG_NDIE, 172 SPD_KEY_SEC_DIE_SIZE, SPD_KEY_SEC_PKG_SL); 173 } 174 175 static const spd_value_range_t spd_ddr5_nrow_range = { 176 .svr_max = SPD_DDR5_ADDR_NROWS_MAX, 177 .svr_base = SPD_DDR5_ADDR_NROWS_BASE 178 }; 179 180 static const spd_value_range_t spd_ddr5_ncol_range = { 181 .svr_max = SPD_DDR5_ADDR_NCOLS_MAX, 182 .svr_base = SPD_DDR5_ADDR_NCOLS_BASE 183 }; 184 185 static void 186 spd_parse_ddr5_addr(spd_info_t *si, uint8_t data, const char *row_key, 187 const char *col_key) 188 { 189 const uint8_t ncols = SPD_DDR5_ADDR_NCOLS(data); 190 const uint8_t nrows = SPD_DDR5_ADDR_NROWS(data); 191 192 spd_insert_range(si, col_key, ncols, &spd_ddr5_ncol_range); 193 spd_insert_range(si, row_key, nrows, &spd_ddr5_nrow_range); 194 } 195 196 static void 197 spd_parse_ddr5_addr_pri(spd_info_t *si, uint32_t off, uint32_t len, 198 const char *key) 199 { 200 spd_parse_ddr5_addr(si, si->si_data[off], SPD_KEY_NROW_BITS, 201 SPD_KEY_NCOL_BITS); 202 } 203 204 static void 205 spd_parse_ddr5_addr_sec(spd_info_t *si, uint32_t off, uint32_t len, 206 const char *key) 207 { 208 if (!spd_parse_ddr5_isassym(si)) 209 return; 210 211 spd_parse_ddr5_addr(si, si->si_data[off], SPD_KEY_SEC_NROW_BITS, 212 SPD_KEY_SEC_NCOL_BITS); 213 } 214 215 static const spd_value_map_t spd_ddr5_width_map[] = { 216 { SPD_DDR5_WIDTH_X4, 4, false }, 217 { SPD_DDR5_WIDTH_X8, 8, false }, 218 { SPD_DDR5_WIDTH_X16, 16, false }, 219 { SPD_DDR5_WIDTH_X32, 32, false } 220 }; 221 222 static void 223 spd_parse_ddr5_width(spd_info_t *si, uint8_t data, const char *key) 224 { 225 const uint8_t width = SPD_DDR5_WIDTH_WIDTH(data); 226 227 spd_insert_map(si, key, width, spd_ddr5_width_map, 228 ARRAY_SIZE(spd_ddr5_width_map)); 229 } 230 231 static void 232 spd_parse_ddr5_width_pri(spd_info_t *si, uint32_t off, uint32_t len, 233 const char *key) 234 { 235 spd_parse_ddr5_width(si, si->si_data[off], SPD_KEY_DRAM_WIDTH); 236 } 237 238 static void 239 spd_parse_ddr5_width_sec(spd_info_t *si, uint32_t off, uint32_t len, 240 const char *key) 241 { 242 if (!spd_parse_ddr5_isassym(si)) 243 return; 244 245 spd_parse_ddr5_width(si, si->si_data[off], SPD_KEY_SEC_DRAM_WIDTH); 246 } 247 248 static const spd_value_range_t spd_ddr5_nbg_range = { 249 .svr_max = SPD_DDR5_BANKS_NBG_BITS_MAX 250 }; 251 252 static const spd_value_range_t spd_ddr5_nba_range = { 253 .svr_max = SPD_DDR5_BANKS_NBA_BITS_MAX 254 }; 255 256 static void 257 spd_parse_ddr5_banks(spd_info_t *si, uint8_t data, const char *bg_key, 258 const char *ba_key) 259 { 260 const uint8_t nbg = SPD_DDR5_BANKS_NBG_BITS(data); 261 const uint8_t nba = SPD_DDR5_BANKS_NBA_BITS(data); 262 263 spd_insert_range(si, bg_key, nbg, &spd_ddr5_nbg_range); 264 spd_insert_range(si, ba_key, nba, &spd_ddr5_nba_range); 265 } 266 267 static void 268 spd_parse_ddr5_banks_pri(spd_info_t *si, uint32_t off, uint32_t len, 269 const char *key) 270 { 271 spd_parse_ddr5_banks(si, si->si_data[off], SPD_KEY_NBGRP_BITS, 272 SPD_KEY_NBANK_BITS); 273 } 274 275 static void 276 spd_parse_ddr5_banks_sec(spd_info_t *si, uint32_t off, uint32_t len, 277 const char *key) 278 { 279 if (!spd_parse_ddr5_isassym(si)) 280 return; 281 282 spd_parse_ddr5_banks(si, si->si_data[off], SPD_KEY_SEC_NBGRP_BITS, 283 SPD_KEY_SEC_NBANK_BITS); 284 } 285 286 static void 287 spd_parse_ddr5_ppr(spd_info_t *si, uint32_t off, uint32_t len, 288 const char *key) 289 { 290 const uint8_t data = si->si_data[off]; 291 spd_ppr_flags_t flags = SPD_PPR_F_HARD_PPR | SPD_PPR_F_SOFT_PPR; 292 293 if (SPD_DDR5_PPR_GRAN(data) == SPD_DDR5_PPR_GRAN_BGRP) { 294 spd_nvl_insert_u32(si, SPD_KEY_PPR_GRAN, 295 SPD_PPR_GRAN_BANK_GROUP); 296 } else { 297 spd_nvl_insert_u32(si, SPD_KEY_PPR_GRAN, 298 SPD_PPR_GRAN_BANK); 299 } 300 301 if (SPD_DDR5_PPR_LOCK_SUP(data) != 0) 302 flags |= SPD_PPR_F_PPR_UNDO; 303 if (SPD_DDR5_PPR_MPPR_SUP(data) != 0) 304 flags |= SPD_PPR_F_MBIST_PPR; 305 spd_nvl_insert_u32(si, SPD_KEY_PPR, flags); 306 307 if (SPD_DDR5_PPR_BL32_SUP(data) != 0) 308 spd_nvl_insert_key(si, SPD_KEY_DDR5_BL32); 309 } 310 311 static const spd_value_map_t spd_ddr5_dca_map[] = { 312 { SPD_DDR5_SPD_DCA_TYPE_UNSUP, SPD_DCA_UNSPPORTED, false }, 313 { SPD_DDR5_SPD_DCA_TYPE_1_2P, SPD_DCA_1_OR_2_PHASE, false }, 314 { SPD_DDR5_SPD_DCA_TYPE_4P, SPD_DCA_4_PHASE, false } 315 }; 316 317 static void 318 spd_parse_ddr5_dca(spd_info_t *si, uint32_t off, uint32_t len, 319 const char *key) 320 { 321 const uint8_t data = si->si_data[off]; 322 const uint8_t dca = SPD_DDR5_SPD_DCA_TYPE(data); 323 324 if (SPD_DDR5_SPD_DCA_PASR(data) != 0) 325 spd_nvl_insert_key(si, SPD_KEY_DDR_PASR); 326 327 spd_insert_map(si, SPD_KEY_DDR5_DCA, dca, spd_ddr5_dca_map, 328 ARRAY_SIZE(spd_ddr5_dca_map)); 329 } 330 331 static void 332 spd_parse_ddr5_flt(spd_info_t *si, uint32_t off, uint32_t len, 333 const char *key) 334 { 335 const uint8_t data = si->si_data[off]; 336 spd_fault_t flt = 0; 337 338 if (SPD_DDR5_FLT_WIDE_TS(data) != 0) 339 spd_nvl_insert_key(si, SPD_KEY_DDR5_WIDE_TS); 340 341 if (SPD_DDR5_FLT_WBSUPR_SUP(data) != 0) { 342 if (SPD_DDR5_FLT_WBSUPR_SEL(data) == 343 SPD_DDR5_FLT_WBSUPR_SEL_MR15) { 344 flt |= SPD_FLT_WRSUP_MR15; 345 } else { 346 flt |= SPD_FLT_WRSUP_MR9; 347 } 348 } 349 350 if (SPD_DDR5_FLT_BFLT(data)) 351 flt |= SPD_FLT_BOUNDED; 352 if (flt != 0) 353 spd_nvl_insert_u32(si, SPD_KEY_DDR5_FLT, flt); 354 } 355 356 /* 357 * Voltages support describing the nominal, operational, and endurant ranges. 358 * Currently we only encode the nominal values. 359 */ 360 static void 361 spd_parse_ddr5_voltage(spd_info_t *si, uint8_t data, const char *key, 362 uint32_t *mv, uint32_t nmv) 363 { 364 const uint8_t nom_idx = SPD_DDR5_DRAM_VOLT_NOM(data); 365 366 if (nom_idx >= nmv) { 367 spd_nvl_err(si, key, SPD_ERROR_NO_XLATE, 368 "encountered unknown value: 0x%x", nom_idx); 369 } else { 370 spd_nvl_insert_u32_array(si, key, &mv[nom_idx], 1); 371 } 372 } 373 374 static void 375 spd_parse_ddr5_vdd(spd_info_t *si, uint32_t off, uint32_t len, 376 const char *key) 377 { 378 uint32_t volts[] = { 1100 }; 379 return (spd_parse_ddr5_voltage(si, si->si_data[off], key, volts, 380 ARRAY_SIZE(volts))); 381 } 382 383 static void 384 spd_parse_ddr5_vddq(spd_info_t *si, uint32_t off, uint32_t len, 385 const char *key) 386 { 387 uint32_t volts[] = { 1100 }; 388 return (spd_parse_ddr5_voltage(si, si->si_data[off], key, volts, 389 ARRAY_SIZE(volts))); 390 } 391 392 static void 393 spd_parse_ddr5_vpp(spd_info_t *si, uint32_t off, uint32_t len, 394 const char *key) 395 { 396 uint32_t volts[] = { 1800 }; 397 return (spd_parse_ddr5_voltage(si, si->si_data[off], key, volts, 398 ARRAY_SIZE(volts))); 399 } 400 401 static void 402 spd_parse_ddr5_time(spd_info_t *si, uint32_t off, uint32_t len, 403 const char *key) 404 { 405 const uint8_t data = si->si_data[off]; 406 407 if (SPD_DDR5_TIME_STD(data) == SPD_DDR5_TIME_STD_NON) 408 spd_nvl_insert_key(si, SPD_KEY_DDR5_NONSTD_TIME); 409 } 410 411 /* 412 * Time in picoseconds. The LSB is at off. The MSB is at off + 1. 413 */ 414 static void 415 spd_parse_ddr5_ps(spd_info_t *si, uint32_t off, uint32_t len, 416 const char *key) 417 { 418 uint64_t ps; 419 420 ASSERT3U(len, ==, 2); 421 ps = (uint64_t)si->si_data[off]; 422 ps |= (uint64_t)si->si_data[off + 1] << 8; 423 424 if (ps == 0) { 425 spd_nvl_err(si, key, SPD_ERROR_NO_XLATE, 426 "encountered unexpected zero time value"); 427 return; 428 } 429 430 spd_nvl_insert_u64(si, key, ps); 431 } 432 433 /* 434 * Time in nanoseconds. The LSB is at off. The MSB is at off + 1. We normalize 435 * all times to ps. 436 */ 437 static void 438 spd_parse_ddr5_ns(spd_info_t *si, uint32_t off, uint32_t len, 439 const char *key) 440 { 441 uint64_t ns, ps; 442 443 ASSERT3U(len, ==, 2); 444 ns = (uint64_t)si->si_data[off]; 445 ns |= (uint64_t)si->si_data[off + 1] << 8; 446 447 if (ns == 0) { 448 spd_nvl_err(si, key, SPD_ERROR_NO_XLATE, 449 "encountered unexpected zero time value"); 450 return; 451 } 452 453 ps = ns * 1000; 454 spd_nvl_insert_u64(si, key, ps); 455 } 456 457 /* 458 * Several DDR5 timing properties are only valid for 3DS type DIMMs. So we 459 * double check the actual DIMM type before we proceed to parse this. 460 */ 461 static void 462 spd_parse_ddr5_3ds_ns(spd_info_t *si, uint32_t off, uint32_t len, 463 const char *key) 464 { 465 ASSERT3U(off, >=, SPD_DDR5_DENPKG1); 466 uint32_t val; 467 468 if (nvlist_lookup_uint32(si->si_nvl, SPD_KEY_PKG_SL, &val) != 0 || 469 val != SPD_SL_3DS) { 470 return; 471 } 472 473 spd_parse_ddr5_ns(si, off, len, key); 474 } 475 476 static void 477 spd_parse_ddr5_nck(spd_info_t *si, uint32_t off, uint32_t len, 478 const char *key) 479 { 480 const uint8_t data = si->si_data[off]; 481 482 if (data == 0) { 483 spd_nvl_err(si, key, SPD_ERROR_NO_XLATE, 484 "encountered unexpected zero clock value"); 485 return; 486 } 487 488 spd_nvl_insert_u32(si, key, data); 489 } 490 491 static void 492 spd_parse_ddr5_cas(spd_info_t *si, uint32_t off, uint32_t len, 493 const char *key) 494 { 495 uint32_t cas[40] = { 0 }; 496 uint_t ncas = 0; 497 uint32_t cas_base = 20; 498 499 ASSERT3U(len, ==, 5); 500 501 for (uint32_t byte = 0; byte < len; byte++) { 502 uint32_t data = si->si_data[off + byte]; 503 504 for (uint32_t i = 0; i < NBBY; i++) { 505 if (bitx8(data, i, i) == 1) { 506 cas[ncas] = cas_base + 2 * (i + NBBY * byte); 507 ncas++; 508 } 509 } 510 } 511 512 spd_nvl_insert_u32_array(si, key, cas, ncas); 513 } 514 515 static const spd_value_range_t spd_ddr5_raammt_norm_range = { 516 .svr_min = SPD_DDR5_RFM0_RAAMMT_NORM_MIN, 517 .svr_max = SPD_DDR5_RFM0_RAAMMT_NORM_MAX, 518 .svr_mult = SPD_DDR5_RFM0_RAAMMT_NORM_MULT 519 }; 520 521 static const spd_value_range_t spd_ddr5_raammt_fgr_range = { 522 .svr_min = SPD_DDR5_RFM0_RAAMMT_FGR_MIN, 523 .svr_max = SPD_DDR5_RFM0_RAAMMT_FGR_MAX, 524 .svr_mult = SPD_DDR5_RFM0_RAAMMT_FGR_MULT 525 }; 526 527 static const spd_value_range_t spd_ddr5_raaimt_norm_range = { 528 .svr_min = SPD_DDR5_RFM0_RAAIMT_NORM_MIN, 529 .svr_max = SPD_DDR5_RFM0_RAAIMT_NORM_MAX, 530 .svr_mult = SPD_DDR5_RFM0_RAAIMT_NORM_MULT 531 }; 532 533 static const spd_value_range_t spd_ddr5_raaimt_fgr_range = { 534 .svr_min = SPD_DDR5_RFM0_RAAIMT_FGR_MIN, 535 .svr_max = SPD_DDR5_RFM0_RAAIMT_FGR_MAX, 536 .svr_mult = SPD_DDR5_RFM0_RAAIMT_FGR_MULT 537 }; 538 539 static const spd_value_range_t spd_ddr5_brc_cfg_range = { 540 .svr_max = SPD_DDR5_RFM1_BRC_CFG_MAX, 541 .svr_base = SPD_DDR5_RFM1_BRC_CFG_BASE 542 }; 543 544 static const spd_value_map_t spd_ddr5_raa_ctr_map[] = { 545 { SPD_DDR5_RFM1_CTR_1X, 1, false }, 546 { SPD_DDR5_RFM1_CTR_2X, 2, false } 547 }; 548 549 static void 550 spd_parse_ddr5_rfm_flags(spd_info_t *si, uint8_t rfm0, uint8_t rfm1, 551 const char *key) 552 { 553 spd_rfm_flags_t flags = 0; 554 555 if (SPD_DDR5_RFM0_RFM_REQ(rfm0) != 0) 556 flags |= SPD_RFM_F_REQUIRED; 557 if (SPD_DDR5_RFM1_DRFM_SUP(rfm1) != 0) 558 flags |= SPD_RFM_F_DRFM_SUP; 559 560 spd_nvl_insert_u32(si, key, flags); 561 } 562 563 static void 564 spd_parse_ddr5_arfm_flags(spd_info_t *si, uint8_t rfm1, const char *key) 565 { 566 spd_rfm_flags_t flags = 0; 567 568 if (SPD_DDR5_RFM1_DRFM_SUP(rfm1) != 0) 569 flags |= SPD_RFM_F_DRFM_SUP; 570 571 spd_nvl_insert_u32(si, key, flags); 572 } 573 574 static void 575 spd_parse_ddr5_rfm_common(spd_info_t *si, uint8_t rfm0, uint8_t rfm1, 576 const char *raaimt_key, const char *raaimt_fgr_key, const char *raammt_key, 577 const char *raammt_fgr_key, const char *brc_cfg_key, 578 const char *brc_sup_key, const char *raa_ctr_key) 579 { 580 const uint8_t raammt = SPD_DDR5_RFM0_RAAMMT_NORM(rfm0); 581 const uint8_t raammt_fgr = SPD_DDR5_RFM0_RAAMMT_FGR(rfm0); 582 const uint8_t raaimt = SPD_DDR5_RFM0_RAAIMT_NORM(rfm0); 583 const uint8_t raaimt_fgr = SPD_DDR5_RFM0_RAAIMT_FGR(rfm0); 584 const uint8_t brc_cfg = SPD_DDR5_RFM1_BRC_CFG(rfm1); 585 const uint8_t brc_sup = SPD_DDR5_RFM1_BRC_SUP(rfm1); 586 const uint8_t raa_ctr = SPD_DDR5_RFM1_CTR(rfm1); 587 spd_brc_flags_t brc_flags = SPD_BRC_F_LVL_2; 588 589 if (brc_sup == SPD_DDR5_RFM1_BRC_SUP_234) 590 brc_flags |= SPD_BRC_F_LVL_3 | SPD_BRC_F_LVL_4; 591 592 if (SPD_DDR5_RFM0_RFM_REQ(rfm0) != 0) { 593 spd_insert_range(si, raaimt_key, raaimt, 594 &spd_ddr5_raaimt_norm_range); 595 spd_insert_range(si, raaimt_fgr_key, raaimt_fgr, 596 &spd_ddr5_raaimt_fgr_range); 597 spd_insert_range(si, raammt_key, raammt, 598 &spd_ddr5_raammt_norm_range); 599 spd_insert_range(si, raammt_fgr_key, raammt_fgr, 600 &spd_ddr5_raammt_fgr_range); 601 spd_insert_map(si, raa_ctr_key, raa_ctr, spd_ddr5_raa_ctr_map, 602 ARRAY_SIZE(spd_ddr5_raa_ctr_map)); 603 } 604 605 if (SPD_DDR5_RFM1_DRFM_SUP(rfm1) != 0) { 606 spd_insert_range(si, brc_cfg_key, brc_cfg, 607 &spd_ddr5_brc_cfg_range); 608 spd_nvl_insert_u32(si, brc_sup_key, brc_flags); 609 } 610 } 611 612 static void 613 spd_parse_ddr5_rfm_pri(spd_info_t *si, uint32_t off, uint32_t len, 614 const char *key) 615 { 616 ASSERT3U(len, ==, 2); 617 618 spd_parse_ddr5_rfm_flags(si, si->si_data[off], si->si_data[off + 1], 619 SPD_KEY_DDR5_RFM_FLAGS_PRI); 620 spd_parse_ddr5_rfm_common(si, si->si_data[off], si->si_data[off + 1], 621 SPD_KEY_DDR5_RFM_RAAIMT_PRI, SPD_KEY_DDR5_RFM_RAAIMT_FGR_PRI, 622 SPD_KEY_DDR5_RFM_RAAMMT_PRI, SPD_KEY_DDR5_RFM_RAAMMT_FGR_PRI, 623 SPD_KEY_DDR5_RFM_BRC_CFG_PRI, SPD_KEY_DDR5_RFM_BRC_SUP_PRI, 624 SPD_KEY_DDR5_RFM_RAA_DEC_PRI); 625 } 626 627 static void 628 spd_parse_ddr5_rfm_sec(spd_info_t *si, uint32_t off, uint32_t len, 629 const char *key) 630 { 631 if (!spd_parse_ddr5_isassym(si)) 632 return; 633 634 spd_parse_ddr5_rfm_flags(si, si->si_data[off], si->si_data[off + 1], 635 SPD_KEY_DDR5_RFM_FLAGS_SEC); 636 spd_parse_ddr5_rfm_common(si, si->si_data[off], si->si_data[off + 1], 637 SPD_KEY_DDR5_RFM_RAAIMT_SEC, SPD_KEY_DDR5_RFM_RAAIMT_FGR_SEC, 638 SPD_KEY_DDR5_RFM_RAAMMT_SEC, SPD_KEY_DDR5_RFM_RAAMMT_FGR_SEC, 639 SPD_KEY_DDR5_RFM_BRC_CFG_SEC, SPD_KEY_DDR5_RFM_BRC_SUP_SEC, 640 SPD_KEY_DDR5_RFM_RAA_DEC_SEC); 641 } 642 643 static void 644 spd_parse_ddr5_arfma_pri(spd_info_t *si, uint32_t off, uint32_t len, 645 const char *key) 646 { 647 ASSERT3U(len, ==, 2); 648 649 if (SPD_DDR5_ARFM_SUP(si->si_data[off]) == 0) 650 return; 651 652 spd_parse_ddr5_arfm_flags(si, si->si_data[off + 1], 653 SPD_KEY_DDR5_ARFMA_FLAGS_PRI); 654 spd_parse_ddr5_rfm_common(si, si->si_data[off], si->si_data[off + 1], 655 SPD_KEY_DDR5_ARFMA_RAAIMT_PRI, SPD_KEY_DDR5_ARFMA_RAAIMT_FGR_PRI, 656 SPD_KEY_DDR5_ARFMA_RAAMMT_PRI, SPD_KEY_DDR5_ARFMA_RAAMMT_FGR_PRI, 657 SPD_KEY_DDR5_ARFMA_BRC_CFG_PRI, SPD_KEY_DDR5_ARFMA_BRC_SUP_PRI, 658 SPD_KEY_DDR5_ARFMA_RAA_DEC_PRI); 659 } 660 661 static void 662 spd_parse_ddr5_arfma_sec(spd_info_t *si, uint32_t off, uint32_t len, 663 const char *key) 664 { 665 if (!spd_parse_ddr5_isassym(si)) 666 return; 667 668 if (SPD_DDR5_ARFM_SUP(si->si_data[off]) == 0) 669 return; 670 671 spd_parse_ddr5_arfm_flags(si, si->si_data[off + 1], 672 SPD_KEY_DDR5_ARFMA_FLAGS_SEC); 673 spd_parse_ddr5_rfm_common(si, si->si_data[off], si->si_data[off + 1], 674 SPD_KEY_DDR5_ARFMA_RAAIMT_SEC, SPD_KEY_DDR5_ARFMA_RAAIMT_FGR_SEC, 675 SPD_KEY_DDR5_ARFMA_RAAMMT_SEC, SPD_KEY_DDR5_ARFMA_RAAMMT_FGR_SEC, 676 SPD_KEY_DDR5_ARFMA_BRC_CFG_SEC, SPD_KEY_DDR5_ARFMA_BRC_SUP_SEC, 677 SPD_KEY_DDR5_ARFMA_RAA_DEC_SEC); 678 } 679 680 static void 681 spd_parse_ddr5_arfmb_pri(spd_info_t *si, uint32_t off, uint32_t len, 682 const char *key) 683 { 684 ASSERT3U(len, ==, 2); 685 686 if (SPD_DDR5_ARFM_SUP(si->si_data[off]) == 0) 687 return; 688 689 spd_parse_ddr5_arfm_flags(si, si->si_data[off + 1], 690 SPD_KEY_DDR5_ARFMB_FLAGS_PRI); 691 spd_parse_ddr5_rfm_common(si, si->si_data[off], si->si_data[off + 1], 692 SPD_KEY_DDR5_ARFMB_RAAIMT_PRI, SPD_KEY_DDR5_ARFMB_RAAIMT_FGR_PRI, 693 SPD_KEY_DDR5_ARFMB_RAAMMT_PRI, SPD_KEY_DDR5_ARFMB_RAAMMT_FGR_PRI, 694 SPD_KEY_DDR5_ARFMB_BRC_CFG_PRI, SPD_KEY_DDR5_ARFMB_BRC_SUP_PRI, 695 SPD_KEY_DDR5_ARFMB_RAA_DEC_PRI); 696 } 697 698 static void 699 spd_parse_ddr5_arfmb_sec(spd_info_t *si, uint32_t off, uint32_t len, 700 const char *key) 701 { 702 if (!spd_parse_ddr5_isassym(si)) 703 return; 704 705 if (SPD_DDR5_ARFM_SUP(si->si_data[off]) == 0) 706 return; 707 708 spd_parse_ddr5_arfm_flags(si, si->si_data[off + 1], 709 SPD_KEY_DDR5_ARFMB_FLAGS_SEC); 710 spd_parse_ddr5_rfm_common(si, si->si_data[off], si->si_data[off + 1], 711 SPD_KEY_DDR5_ARFMB_RAAIMT_SEC, SPD_KEY_DDR5_ARFMB_RAAIMT_FGR_SEC, 712 SPD_KEY_DDR5_ARFMB_RAAMMT_SEC, SPD_KEY_DDR5_ARFMB_RAAMMT_FGR_SEC, 713 SPD_KEY_DDR5_ARFMB_BRC_CFG_SEC, SPD_KEY_DDR5_ARFMB_BRC_SUP_SEC, 714 SPD_KEY_DDR5_ARFMB_RAA_DEC_SEC); 715 } 716 717 static void 718 spd_parse_ddr5_arfmc_pri(spd_info_t *si, uint32_t off, uint32_t len, 719 const char *key) 720 { 721 ASSERT3U(len, ==, 2); 722 723 if (SPD_DDR5_ARFM_SUP(si->si_data[off]) == 0) 724 return; 725 726 spd_parse_ddr5_arfm_flags(si, si->si_data[off + 1], 727 SPD_KEY_DDR5_ARFMC_FLAGS_PRI); 728 spd_parse_ddr5_rfm_common(si, si->si_data[off], si->si_data[off + 1], 729 SPD_KEY_DDR5_ARFMC_RAAIMT_PRI, SPD_KEY_DDR5_ARFMC_RAAIMT_FGR_PRI, 730 SPD_KEY_DDR5_ARFMC_RAAMMT_PRI, SPD_KEY_DDR5_ARFMC_RAAMMT_FGR_PRI, 731 SPD_KEY_DDR5_ARFMC_BRC_CFG_PRI, SPD_KEY_DDR5_ARFMC_BRC_SUP_PRI, 732 SPD_KEY_DDR5_ARFMC_RAA_DEC_PRI); 733 } 734 735 static void 736 spd_parse_ddr5_arfmc_sec(spd_info_t *si, uint32_t off, uint32_t len, 737 const char *key) 738 { 739 if (!spd_parse_ddr5_isassym(si)) 740 return; 741 742 if (SPD_DDR5_ARFM_SUP(si->si_data[off]) == 0) 743 return; 744 745 spd_parse_ddr5_arfm_flags(si, si->si_data[off + 1], 746 SPD_KEY_DDR5_ARFMC_FLAGS_SEC); 747 spd_parse_ddr5_rfm_common(si, si->si_data[off], si->si_data[off + 1], 748 SPD_KEY_DDR5_ARFMC_RAAIMT_SEC, SPD_KEY_DDR5_ARFMC_RAAIMT_FGR_SEC, 749 SPD_KEY_DDR5_ARFMC_RAAMMT_SEC, SPD_KEY_DDR5_ARFMC_RAAMMT_FGR_SEC, 750 SPD_KEY_DDR5_ARFMC_BRC_CFG_SEC, SPD_KEY_DDR5_ARFMC_BRC_SUP_SEC, 751 SPD_KEY_DDR5_ARFMC_RAA_DEC_SEC); 752 } 753 754 static const spd_parse_t spd_ddr5_base[] = { 755 { .sp_off = SPD_DDR5_NBYTES, .sp_parse = spd_parse_ddr5_nbytes }, 756 { .sp_off = SPD_DDR5_SPD_REV, .sp_parse = spd_parse_rev }, 757 /* 758 * We have previously validated that the DRAM type is something that we 759 * understand. We pass through the raw enum to users here. 760 */ 761 { .sp_off = SPD_DDR5_DRAM_TYPE, .sp_key = SPD_KEY_DRAM_TYPE, 762 .sp_parse = spd_parse_raw_u8 }, 763 { .sp_off = SPD_DDR5_MOD_TYPE, .sp_parse = spd_parse_ddr5_mod_type }, 764 /* 765 * All secondary values must check whether an asymmetrical module is 766 * present in Byte 234. As such, for the secondary versions we set LEN 767 * to include that value. They then move to a common function. 768 */ 769 { .sp_off = SPD_DDR5_DENPKG1, .sp_parse = spd_parse_ddr5_denpkg_pri }, 770 { .sp_off = SPD_DDR5_DENPKG2, .sp_parse = spd_parse_ddr5_denpkg_sec, 771 .sp_len = SPD_DDR5_COM_ORG - SPD_DDR5_DENPKG2 + 1 }, 772 { .sp_off = SPD_DDR5_ADDR1, .sp_parse = spd_parse_ddr5_addr_pri }, 773 { .sp_off = SPD_DDR5_ADDR2, .sp_parse = spd_parse_ddr5_addr_sec, 774 .sp_len = SPD_DDR5_COM_ORG - SPD_DDR5_ADDR2 + 1 }, 775 { .sp_off = SPD_DDR5_WIDTH1, .sp_parse = spd_parse_ddr5_width_pri }, 776 { .sp_off = SPD_DDR5_WIDTH2, .sp_parse = spd_parse_ddr5_width_sec, 777 .sp_len = SPD_DDR5_COM_ORG - SPD_DDR5_WIDTH2 + 1 }, 778 { .sp_off = SPD_DDR5_BANKS1, .sp_parse = spd_parse_ddr5_banks_pri }, 779 { .sp_off = SPD_DDR5_BANKS2, .sp_parse = spd_parse_ddr5_banks_sec, 780 .sp_len = SPD_DDR5_COM_ORG - SPD_DDR5_BANKS2 + 1 }, 781 { .sp_off = SPD_DDR5_PPR, .sp_parse = spd_parse_ddr5_ppr }, 782 { .sp_off = SPD_DDR5_SDA, .sp_parse = spd_parse_ddr5_dca }, 783 { .sp_off = SPD_DDR5_FLT, .sp_parse = spd_parse_ddr5_flt }, 784 { .sp_off = SPD_DDR5_DRAM_VDD, .sp_key = SPD_KEY_NOM_VDD, 785 .sp_parse = spd_parse_ddr5_vdd }, 786 { .sp_off = SPD_DDR5_DRAM_VDDQ, .sp_key = SPD_KEY_NOM_VDDQ, 787 .sp_parse = spd_parse_ddr5_vddq }, 788 { .sp_off = SPD_DDR5_DRAM_VPP, .sp_key = SPD_KEY_NOM_VPP, 789 .sp_parse = spd_parse_ddr5_vpp }, 790 { .sp_off = SPD_DDR5_TIME, .sp_parse = spd_parse_ddr5_time }, 791 { .sp_off = SPD_DDR5_TCKAVG_MIN_LSB, .sp_len = 2, 792 .sp_key = SPD_KEY_TCKAVG_MIN, .sp_parse = spd_parse_ddr5_ps }, 793 { .sp_off = SPD_DDR5_TCKAVG_MAX_LSB, .sp_len = 2, 794 .sp_key = SPD_KEY_TCKAVG_MAX, .sp_parse = spd_parse_ddr5_ps }, 795 { .sp_off = SPD_DDR5_CAS_SUP0, .sp_len = 5, .sp_key = SPD_KEY_CAS, 796 .sp_parse = spd_parse_ddr5_cas }, 797 { .sp_off = SPD_DDR5_TAA_LSB, .sp_len = 2, 798 .sp_key = SPD_KEY_TAA_MIN, .sp_parse = spd_parse_ddr5_ps }, 799 { .sp_off = SPD_DDR5_TRCD_LSB, .sp_len = 2, 800 .sp_key = SPD_KEY_TRCD_MIN, .sp_parse = spd_parse_ddr5_ps }, 801 { .sp_off = SPD_DDR5_TRP_LSB, .sp_len = 2, 802 .sp_key = SPD_KEY_TRP_MIN, .sp_parse = spd_parse_ddr5_ps }, 803 { .sp_off = SPD_DDR5_TRAS_LSB, .sp_len = 2, 804 .sp_key = SPD_KEY_TRAS_MIN, .sp_parse = spd_parse_ddr5_ps }, 805 { .sp_off = SPD_DDR5_TRC_LSB, .sp_len = 2, 806 .sp_key = SPD_KEY_TRC_MIN, .sp_parse = spd_parse_ddr5_ps }, 807 { .sp_off = SPD_DDR5_TWR_LSB, .sp_len = 2, 808 .sp_key = SPD_KEY_TWR_MIN, .sp_parse = spd_parse_ddr5_ps }, 809 { .sp_off = SPD_DDR5_TRFC1_LSB, .sp_len = 2, 810 .sp_key = SPD_KEY_TRFC1_MIN, .sp_parse = spd_parse_ddr5_ns }, 811 { .sp_off = SPD_DDR5_TRFC2_LSB, .sp_len = 2, 812 .sp_key = SPD_KEY_TRFC2_MIN, .sp_parse = spd_parse_ddr5_ns }, 813 { .sp_off = SPD_DDR5_TRFCSB_LSB, .sp_len = 2, 814 .sp_key = SPD_KEY_TRFCSB, .sp_parse = spd_parse_ddr5_ns }, 815 { .sp_off = SPD_DDR5_3DS_TRFC1_LSB, .sp_len = 2, 816 .sp_key = SPD_KEY_TRFC1_DLR, .sp_parse = spd_parse_ddr5_3ds_ns }, 817 { .sp_off = SPD_DDR5_3DS_TRFC2_LSB, .sp_len = 2, 818 .sp_key = SPD_KEY_TRFC2_DLR, .sp_parse = spd_parse_ddr5_3ds_ns }, 819 { .sp_off = SPD_DDR5_3DS_TRFCSB_LSB, .sp_len = 2, 820 .sp_key = SPD_KEY_TRFCSB_DLR, .sp_parse = spd_parse_ddr5_3ds_ns }, 821 { .sp_off = SPD_DDR5_RFM0_SDRAM0, .sp_len = 2, 822 .sp_parse = spd_parse_ddr5_rfm_pri }, 823 { .sp_off = SPD_DDR5_RFM0_SDRAM1, .sp_parse = spd_parse_ddr5_rfm_sec, 824 .sp_len = SPD_DDR5_COM_ORG - SPD_DDR5_RFM0_SDRAM1 + 1 }, 825 { .sp_off = SPD_DDR5_ARFM0_A_SDRAM0, .sp_len = 2, 826 .sp_parse = spd_parse_ddr5_arfma_pri }, 827 { .sp_off = SPD_DDR5_ARFM0_A_SDRAM1, 828 .sp_len = SPD_DDR5_COM_ORG - SPD_DDR5_ARFM0_A_SDRAM1 + 1, 829 .sp_parse = spd_parse_ddr5_arfma_sec }, 830 { .sp_off = SPD_DDR5_ARFM0_B_SDRAM0, .sp_len = 2, 831 .sp_parse = spd_parse_ddr5_arfmb_pri }, 832 { .sp_off = SPD_DDR5_ARFM0_B_SDRAM1, 833 .sp_len = SPD_DDR5_COM_ORG - SPD_DDR5_ARFM0_B_SDRAM1 + 1, 834 .sp_parse = spd_parse_ddr5_arfmb_sec }, 835 { .sp_off = SPD_DDR5_ARFM0_C_SDRAM0, .sp_len = 2, 836 .sp_parse = spd_parse_ddr5_arfmc_pri }, 837 { .sp_off = SPD_DDR5_ARFM0_C_SDRAM1, 838 .sp_len = SPD_DDR5_COM_ORG - SPD_DDR5_ARFM0_C_SDRAM1 + 1, 839 .sp_parse = spd_parse_ddr5_arfmc_sec }, 840 { .sp_off = SPD_DDR5_TRRD_L_LSB, .sp_len = 2, 841 .sp_key = SPD_KEY_TRRD_L_MIN, .sp_parse = spd_parse_ddr5_ps }, 842 { .sp_off = SPD_DDR5_TRRD_L_NCK, .sp_key = SPD_KEY_TRRD_L_NCK, 843 .sp_parse = spd_parse_ddr5_nck }, 844 { .sp_off = SPD_DDR5_TCCD_L_LSB, .sp_len = 2, 845 .sp_key = SPD_KEY_TCCD_L_MIN, .sp_parse = spd_parse_ddr5_ps }, 846 { .sp_off = SPD_DDR5_TCCD_L_NCK, .sp_key = SPD_KEY_TCCD_L_NCK, 847 .sp_parse = spd_parse_ddr5_nck }, 848 { .sp_off = SPD_DDR5_TCCD_L_WR_LSB, .sp_len = 2, 849 .sp_key = SPD_KEY_TCCDLWR, .sp_parse = spd_parse_ddr5_ps }, 850 { .sp_off = SPD_DDR5_TCCD_L_WR_NCK, .sp_key = SPD_KEY_TCCDLWR_NCK, 851 .sp_parse = spd_parse_ddr5_nck }, 852 { .sp_off = SPD_DDR5_TCCD_L_WR2_LSB, .sp_len = 2, 853 .sp_key = SPD_KEY_TCCDLWR2, .sp_parse = spd_parse_ddr5_ps }, 854 { .sp_off = SPD_DDR5_TCCD_L_WR2_NCK, .sp_key = SPD_KEY_TCCDLWR2_NCK, 855 .sp_parse = spd_parse_ddr5_nck }, 856 { .sp_off = SPD_DDR5_TFAW_LSB, .sp_len = 2, 857 .sp_key = SPD_KEY_TFAW, .sp_parse = spd_parse_ddr5_ps }, 858 { .sp_off = SPD_DDR5_TFAW_NCK, .sp_key = SPD_KEY_TFAW_NCK, 859 .sp_parse = spd_parse_ddr5_nck }, 860 { .sp_off = SPD_DDR5_TCCD_L_WTR_LSB, .sp_len = 2, 861 .sp_key = SPD_KEY_TCCDLWTR, .sp_parse = spd_parse_ddr5_ps }, 862 { .sp_off = SPD_DDR5_TCCD_L_WTR_NCK, .sp_key = SPD_KEY_TCCDLWTR_NCK, 863 .sp_parse = spd_parse_ddr5_nck }, 864 { .sp_off = SPD_DDR5_TCCD_S_WTR_LSB, .sp_len = 2, 865 .sp_key = SPD_KEY_TCCDSWTR, .sp_parse = spd_parse_ddr5_ps }, 866 { .sp_off = SPD_DDR5_TCCD_S_WTR_NCK, .sp_key = SPD_KEY_TCCDSWTR_NCK, 867 .sp_parse = spd_parse_ddr5_nck }, 868 { .sp_off = SPD_DDR5_TRTP_LSB, .sp_len = 2, 869 .sp_key = SPD_KEY_TRTP, .sp_parse = spd_parse_ddr5_ps }, 870 { .sp_off = SPD_DDR5_TRTP_NCK, .sp_key = SPD_KEY_TRTP_NCK, 871 .sp_parse = spd_parse_ddr5_nck } 872 }; 873 874 /* 875 * These are additional fields that were added in v1.2 of the SPD data. 876 */ 877 static const spd_parse_t spd_ddr5_base_1v2[] = { 878 { .sp_off = SPD_DDR5_TCCD_M_LSB, .sp_len = 2, 879 .sp_key = SPD_KEY_TCCDM, .sp_parse = spd_parse_ddr5_ps }, 880 { .sp_off = SPD_DDR5_TCCD_M_NCK, .sp_key = SPD_KEY_TCCDM_NCK, 881 .sp_parse = spd_parse_ddr5_nck }, 882 { .sp_off = SPD_DDR5_TCCD_M_WR_LSB, .sp_len = 2, 883 .sp_key = SPD_KEY_TCCDMWR, .sp_parse = spd_parse_ddr5_ps }, 884 { .sp_off = SPD_DDR5_TCCD_M_WR_NCK, .sp_key = SPD_KEY_TCCDMWR_NCK, 885 .sp_parse = spd_parse_ddr5_nck }, 886 { .sp_off = SPD_DDR5_TCCD_M_WTR_LSB, .sp_len = 2, 887 .sp_key = SPD_KEY_TCCDMWTR, .sp_parse = spd_parse_ddr5_ps }, 888 { .sp_off = SPD_DDR5_TCCD_M_WTR_NCK, .sp_key = SPD_KEY_TCCDMWTR_NCK, 889 .sp_parse = spd_parse_ddr5_nck } 890 891 }; 892 893 static void 894 spd_parse_ddr5_mod_rev(spd_info_t *si, uint32_t off, uint32_t len, 895 const char *key) 896 { 897 const uint8_t data = si->si_data[off]; 898 const uint8_t enc = SPD_DDR5_SPD_REV_ENC(data); 899 const uint8_t add = SPD_DDR5_SPD_REV_ADD(data); 900 901 spd_nvl_insert_u32(si, SPD_KEY_MOD_REV_ENC, enc); 902 spd_nvl_insert_u32(si, SPD_KEY_MOD_REV_ADD, add); 903 } 904 905 static const spd_value_map_t spd_ddr5_hash_map[] = { 906 { SPD_DDR5_COM_HASH_NONE, 0, true }, 907 { SPD_DDR5_COM_HASH_ALG1, SPD_HASH_SEQ_ALG_1, false } 908 }; 909 910 static void 911 spd_parse_ddr5_hash_seq(spd_info_t *si, uint32_t off, uint32_t len, 912 const char *key) 913 { 914 const uint8_t data = si->si_data[off]; 915 const uint8_t alg = SPD_DDR5_COM_HASH_HASH(data); 916 917 spd_insert_map(si, key, alg, spd_ddr5_hash_map, 918 ARRAY_SIZE(spd_ddr5_hash_map)); 919 } 920 921 static void 922 spd_parse_ddr5_dev_common(spd_info_t *si, uint32_t off, spd_device_t flags, 923 const char *id_key, const char *id_str_key, const char *rev_key, 924 const char *type_key, const spd_value_map_t *type_map, size_t ntypes) 925 { 926 const uint8_t type = SPD_DDR5_COM_INFO_TYPE(si->si_data[off + 2]); 927 928 spd_parse_jedec_id(si, off, 2, id_key); 929 spd_parse_jedec_id_str(si, off, 2, id_str_key); 930 spd_parse_hex_vers(si, off + 3, 1, rev_key); 931 spd_upsert_flag(si, SPD_KEY_DEVS, flags); 932 spd_insert_map(si, type_key, type, type_map, ntypes); 933 } 934 935 static const spd_value_map_t spd_ddr5_spd_type_map[] = { 936 { SPD_DDR5_COM_INFO_TYPE_SPD5118, SPD_SPD_T_SPD5118, false }, 937 { SPD_DDR5_COM_INFO_TYPE_ESPD5216, SPD_SPD_T_ESPD5216, false } 938 }; 939 940 static void 941 spd_parse_ddr5_spd(spd_info_t *si, uint32_t off, uint32_t len, const char *key) 942 { 943 ASSERT3U(len, ==, 4); 944 const uint8_t type = si->si_data[off + 2]; 945 if (SPD_DDR5_COM_INFO_PRES(type) == 0) 946 return; 947 948 spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_SPD, SPD_KEY_DEV_SPD_MFG, 949 SPD_KEY_DEV_SPD_MFG_NAME, SPD_KEY_DEV_SPD_REV, SPD_KEY_DEV_SPD_TYPE, 950 spd_ddr5_spd_type_map, ARRAY_SIZE(spd_ddr5_spd_type_map)); 951 } 952 953 static const spd_value_map_t spd_ddr5_pmic_type_map[] = { 954 { SPD_DDR5_COM_INFO_TYPE_PMIC5000, SPD_PMIC_T_PMIC5000, false }, 955 { SPD_DDR5_COM_INFO_TYPE_PMIC5010, SPD_PMIC_T_PMIC5010, false }, 956 { SPD_DDR5_COM_INFO_TYPE_PMIC5100, SPD_PMIC_T_PMIC5100, false }, 957 { SPD_DDR5_COM_INFO_TYPE_PMIC5020, SPD_PMIC_T_PMIC5020, false }, 958 { SPD_DDR5_COM_INFO_TYPE_PMIC5120, SPD_PMIC_T_PMIC5120, false }, 959 { SPD_DDR5_COM_INFO_TYPE_PMIC5200, SPD_PMIC_T_PMIC5200, false }, 960 { SPD_DDR5_COM_INFO_TYPE_PMIC5030, SPD_PMIC_T_PMIC5030, false }, 961 }; 962 963 static void 964 spd_parse_ddr5_pmic0(spd_info_t *si, uint32_t off, uint32_t len, 965 const char *key) 966 { 967 ASSERT3U(len, ==, 4); 968 const uint8_t type = si->si_data[off + 2]; 969 if (SPD_DDR5_COM_INFO_PRES(type) == 0) 970 return; 971 972 spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_PMIC_0, 973 SPD_KEY_DEV_PMIC0_MFG, SPD_KEY_DEV_PMIC0_MFG_NAME, 974 SPD_KEY_DEV_PMIC0_REV, SPD_KEY_DEV_PMIC0_TYPE, 975 spd_ddr5_pmic_type_map, ARRAY_SIZE(spd_ddr5_pmic_type_map)); 976 } 977 978 static void 979 spd_parse_ddr5_pmic1(spd_info_t *si, uint32_t off, uint32_t len, 980 const char *key) 981 { 982 ASSERT3U(len, ==, 4); 983 const uint8_t type = si->si_data[off + 2]; 984 if (SPD_DDR5_COM_INFO_PRES(type) == 0) 985 return; 986 987 spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_PMIC_1, 988 SPD_KEY_DEV_PMIC1_MFG, SPD_KEY_DEV_PMIC1_MFG_NAME, 989 SPD_KEY_DEV_PMIC1_REV, SPD_KEY_DEV_PMIC1_TYPE, 990 spd_ddr5_pmic_type_map, ARRAY_SIZE(spd_ddr5_pmic_type_map)); 991 } 992 993 static void 994 spd_parse_ddr5_pmic2(spd_info_t *si, uint32_t off, uint32_t len, 995 const char *key) 996 { 997 ASSERT3U(len, ==, 4); 998 const uint8_t type = si->si_data[off + 2]; 999 if (SPD_DDR5_COM_INFO_PRES(type) == 0) 1000 return; 1001 1002 spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_PMIC_2, 1003 SPD_KEY_DEV_PMIC2_MFG, SPD_KEY_DEV_PMIC2_MFG_NAME, 1004 SPD_KEY_DEV_PMIC2_REV, SPD_KEY_DEV_PMIC2_TYPE, 1005 spd_ddr5_pmic_type_map, ARRAY_SIZE(spd_ddr5_pmic_type_map)); 1006 } 1007 1008 static const spd_value_map_t spd_ddr5_temp_type_map[] = { 1009 { SPD_DDR5_COM_INFO_TYPE_TS5111, SPD_TEMP_T_TS5111, false }, 1010 { SPD_DDR5_COM_INFO_TYPE_TS5110, SPD_TEMP_T_TS5110, false }, 1011 { SPD_DDR5_COM_INFO_TYPE_TS5211, SPD_TEMP_T_TS5211, false }, 1012 { SPD_DDR5_COM_INFO_TYPE_TS5210, SPD_TEMP_T_TS5210, false } 1013 }; 1014 1015 static void 1016 spd_parse_ddr5_ts(spd_info_t *si, uint32_t off, uint32_t len, const char *key) 1017 { 1018 ASSERT3U(len, ==, 4); 1019 const uint8_t type = si->si_data[off + 2]; 1020 spd_device_t flags = 0; 1021 if (SPD_DDR5_COM_INFO_PRES(type) != 0) 1022 flags |= SPD_DEVICE_TEMP_1; 1023 if (SPD_DDR5_COM_INFO_TS1_PRES(type) != 0) 1024 flags |= SPD_DEVICE_TEMP_2; 1025 if (flags == 0) 1026 return; 1027 1028 spd_parse_ddr5_dev_common(si, off, flags, SPD_KEY_DEV_TEMP_MFG, 1029 SPD_KEY_DEV_TEMP_MFG_NAME, SPD_KEY_DEV_TEMP_REV, 1030 SPD_KEY_DEV_TEMP_TYPE, spd_ddr5_temp_type_map, 1031 ARRAY_SIZE(spd_ddr5_temp_type_map)); 1032 } 1033 1034 /* 1035 * While DDR5 uses similar constants as earlier DDR standards, less values have 1036 * been officially defined yet so we use a different table from the others. 1037 */ 1038 static const spd_str_map_t spd_ddr5_design_map[] = { 1039 { 0, "A", false }, 1040 { 1, "B", false }, 1041 { 2, "C", false }, 1042 { 3, "D", false }, 1043 { 4, "E", false }, 1044 { 5, "F", false }, 1045 { 6, "G", false }, 1046 { 7, "H", false }, 1047 { 8, "J", false }, 1048 { 9, "K", false }, 1049 { 10, "L", false }, 1050 { 11, "M", false }, 1051 { 12, "N", false }, 1052 { 13, "P", false }, 1053 { 14, "R", false }, 1054 { 15, "T", false }, 1055 { 16, "U", false }, 1056 { 17, "V", false }, 1057 { 18, "W", false }, 1058 { 19, "Y", false }, 1059 { 20, "AA", false }, 1060 { 21, "AB", false }, 1061 { 22, "AC", false }, 1062 { 23, "AD", false }, 1063 { 24, "AE", false }, 1064 { 25, "AF", false }, 1065 { 26, "AG", false }, 1066 { 27, "AH", false }, 1067 { 28, "AJ", false }, 1068 { 29, "AK", false }, 1069 { 31, "ZZ", false } 1070 }; 1071 1072 static const spd_value_range_t spd_ddr5_design_rev_range = { 1073 .svr_max = SPD_DDR5_COM_REF_REV_MAX 1074 }; 1075 1076 static void 1077 spd_parse_ddr5_design(spd_info_t *si, uint32_t off, uint32_t len, 1078 const char *key) 1079 { 1080 const uint8_t data = si->si_data[off]; 1081 const uint8_t rev = SPD_DDR5_COM_REF_REV(data); 1082 const uint8_t card = SPD_DDR5_COM_REF_CARD(data); 1083 1084 spd_insert_str_map(si, SPD_KEY_MOD_REF_DESIGN, card, 1085 spd_ddr5_design_map, ARRAY_SIZE(spd_ddr5_design_map)); 1086 spd_insert_range(si, SPD_KEY_MOD_DESIGN_REV, rev, 1087 &spd_ddr5_design_rev_range); 1088 } 1089 1090 static const spd_value_map_t spd_ddr5_attr_nrows_map[] = { 1091 { SPD_DDR5_COM_ATTR_NROWS_UNDEF, 0, true }, 1092 { SPD_DDR5_COM_ATTR_NROWS_1, 1, false }, 1093 { SPD_DDR5_COM_ATTR_NROWS_2, 2, false } 1094 }; 1095 1096 static const spd_value_map_t spd_ddr5_attr_otr_map[] = { 1097 { SPD_DDR5_COM_ATTR_OTR_A1T, JEDEC_TEMP_CASE_A1T, false }, 1098 { SPD_DDR5_COM_ATTR_OTR_A2T, JEDEC_TEMP_CASE_A2T, false }, 1099 { SPD_DDR5_COM_ATTR_OTR_A3T, JEDEC_TEMP_CASE_A3T, false }, 1100 { SPD_DDR5_COM_ATTR_OTR_IT, JEDEC_TEMP_CASE_IT, false }, 1101 { SPD_DDR5_COM_ATTR_OTR_ST, JEDEC_TEMP_CASE_ST, false }, 1102 { SPD_DDR5_COM_ATTR_OTR_ET, JEDEC_TEMP_CASE_ET, false }, 1103 { SPD_DDR5_COM_ATTR_OTR_RT, JEDEC_TEMP_CASE_RT, false }, 1104 { SPD_DDR5_COM_ATTR_OTR_NT, JEDEC_TEMP_CASE_NT, false }, 1105 { SPD_DDR5_COM_ATTR_OTR_XT, JEDEC_TEMP_CASE_XT, false } 1106 }; 1107 1108 static void 1109 spd_parse_ddr5_attr(spd_info_t *si, uint32_t off, uint32_t len, 1110 const char *key) 1111 { 1112 const uint8_t data = si->si_data[off]; 1113 const uint8_t otr = SPD_DDR5_COM_ATTR_OTR(data); 1114 const uint8_t nrows = SPD_DDR5_COM_ATTR_NROWS(data); 1115 1116 if (SPD_DDR5_COM_ATTR_SPREAD(data) != 0) 1117 spd_upsert_flag(si, SPD_KEY_DEVS, SPD_DEVICE_HS); 1118 spd_insert_map(si, SPD_KEY_MOD_NROWS, nrows, 1119 spd_ddr5_attr_nrows_map, ARRAY_SIZE(spd_ddr5_attr_nrows_map)); 1120 spd_insert_map(si, SPD_KEY_MOD_OPER_TEMP, otr, 1121 spd_ddr5_attr_otr_map, ARRAY_SIZE(spd_ddr5_attr_otr_map)); 1122 } 1123 1124 static const spd_value_range_t spd_ddr5_nrank_range = { 1125 .svr_base = SPD_DDR5_COM_ORG_NRANK_BASE 1126 }; 1127 1128 static void 1129 spd_parse_ddr5_mod_org(spd_info_t *si, uint32_t off, uint32_t len, 1130 const char *key) 1131 { 1132 const uint8_t data = si->si_data[off]; 1133 const uint8_t nranks = SPD_DDR4_MOD_ORG_NPKG_RANK(data); 1134 1135 if (SPD_DDR5_COM_ORG_MIX(data) == SPD_DDR5_COM_ORG_MIX_ASYM) 1136 spd_nvl_insert_key(si, SPD_KEY_RANK_ASYM); 1137 spd_insert_range(si, SPD_KEY_NRANKS, nranks, &spd_ddr5_nrank_range); 1138 } 1139 1140 static const spd_value_map_t spd_ddr5_ext_width[] = { 1141 { SPD_DDR5_COM_BUS_WIDTH_EXT_NONE, 0, false }, 1142 { SPD_DDR5_COM_BUS_WIDTH_EXT_4b, 4, false }, 1143 { SPD_DDR5_COM_BUS_WIDTH_EXT_8b, 8, false } 1144 }; 1145 1146 static const spd_value_map_t spd_ddr5_pri_width[] = { 1147 { SPD_DDR5_COM_BUS_WIDTH_PRI_8b, 8, false }, 1148 { SPD_DDR5_COM_BUS_WIDTH_PRI_16b, 16, false }, 1149 { SPD_DDR5_COM_BUS_WIDTH_PRI_32b, 32, false }, 1150 { SPD_DDR5_COM_BUS_WIDTH_PRI_64b, 64, false }, 1151 }; 1152 1153 static const spd_value_range_t spd_ddr5_nsc_range = { 1154 .svr_max = SPD_DDR5_COM_BUS_WIDTH_NSC_MAX, 1155 .svr_exp = true 1156 }; 1157 1158 static void 1159 spd_parse_ddr5_bus_width(spd_info_t *si, uint32_t off, uint32_t len, 1160 const char *key) 1161 { 1162 const uint8_t data = si->si_data[off]; 1163 const uint8_t nsc = SPD_DDR5_COM_BUS_WIDTH_NSC(data); 1164 const uint8_t ext = SPD_DDR5_COM_BUS_WIDTH_EXT(data); 1165 const uint8_t pri = SPD_DDR5_COM_BUS_WIDTH_PRI(data); 1166 1167 spd_insert_range(si, SPD_KEY_NSUBCHAN, nsc, &spd_ddr5_nsc_range); 1168 spd_nvl_insert_u32(si, SPD_KEY_DRAM_NCHAN, 1); 1169 spd_insert_map(si, SPD_KEY_ECC_WIDTH, ext, spd_ddr5_ext_width, 1170 ARRAY_SIZE(spd_ddr5_ext_width)); 1171 spd_insert_map(si, SPD_KEY_DATA_WIDTH, pri, spd_ddr5_pri_width, 1172 ARRAY_SIZE(spd_ddr5_pri_width)); 1173 } 1174 1175 static const spd_parse_t spd_ddr5_module[] = { 1176 { .sp_off = SPD_DDR5_COM_REV, .sp_parse = spd_parse_ddr5_mod_rev }, 1177 { .sp_off = SPD_DDR5_COM_HASH, .sp_parse = spd_parse_ddr5_hash_seq, 1178 .sp_key = SPD_KEY_HASH_SEQ }, 1179 { .sp_off = SPD_DDR5_COM_MFG_ID0_SPD, .sp_len = 4, 1180 .sp_parse = spd_parse_ddr5_spd }, 1181 { .sp_off = SPD_DDR5_COM_MFG_ID0_PMIC0, .sp_len = 4, 1182 .sp_parse = spd_parse_ddr5_pmic0 }, 1183 { .sp_off = SPD_DDR5_COM_MFG_ID0_PMIC1, .sp_len = 4, 1184 .sp_parse = spd_parse_ddr5_pmic1 }, 1185 { .sp_off = SPD_DDR5_COM_MFG_ID0_PMIC2, .sp_len = 4, 1186 .sp_parse = spd_parse_ddr5_pmic2 }, 1187 { .sp_off = SPD_DDR5_COM_MFG_ID0_TS, .sp_len = 4, 1188 .sp_parse = spd_parse_ddr5_ts }, 1189 { .sp_off = SPD_DDR5_COM_HEIGHT, .sp_key = SPD_KEY_MOD_HEIGHT, 1190 .sp_parse = spd_parse_height }, 1191 { .sp_off = SPD_DDR5_COM_THICK, .sp_parse = spd_parse_thickness }, 1192 { .sp_off = SPD_DDR5_COM_REF, .sp_parse = spd_parse_ddr5_design }, 1193 { .sp_off = SPD_DDR5_COM_ATTR, .sp_parse = spd_parse_ddr5_attr }, 1194 { .sp_off = SPD_DDR5_COM_ORG, .sp_parse = spd_parse_ddr5_mod_org }, 1195 { .sp_off = SPD_DDR5_COM_BUS_WIDTH, 1196 .sp_parse = spd_parse_ddr5_bus_width }, 1197 /* We include the DDR5 CRC in this group as it's considered common */ 1198 { .sp_len = SPD_DDR5_CRC_MSB + 1, .sp_key = SPD_KEY_CRC_DDR5, 1199 .sp_parse = spd_parse_crc }, 1200 }; 1201 1202 static const spd_parse_t spd_ddr5_mfg[] = { 1203 { .sp_off = SPD_DDR5_MOD_MFG_ID0, .sp_len = 2, 1204 .sp_key = SPD_KEY_MFG_MOD_MFG_ID, .sp_parse = spd_parse_jedec_id }, 1205 { .sp_off = SPD_DDR5_MOD_MFG_ID0, .sp_len = 2, 1206 .sp_key = SPD_KEY_MFG_MOD_MFG_NAME, 1207 .sp_parse = spd_parse_jedec_id_str }, 1208 { .sp_off = SPD_DDR5_DRAM_MFG_ID0, .sp_len = 2, 1209 .sp_key = SPD_KEY_MFG_DRAM_MFG_ID, .sp_parse = spd_parse_jedec_id }, 1210 { .sp_off = SPD_DDR5_DRAM_MFG_ID0, .sp_len = 2, 1211 .sp_key = SPD_KEY_MFG_DRAM_MFG_NAME, 1212 .sp_parse = spd_parse_jedec_id_str }, 1213 { .sp_off = SPD_DDR5_MOD_MFG_LOC, .sp_key = SPD_KEY_MFG_MOD_LOC_ID, 1214 .sp_parse = spd_parse_raw_u8 }, 1215 { .sp_off = SPD_DDR5_MOD_MFG_YEAR, .sp_key = SPD_KEY_MFG_MOD_YEAR, 1216 .sp_parse = spd_parse_hex_string }, 1217 { .sp_off = SPD_DDR5_MOD_MFG_WEEK, .sp_key = SPD_KEY_MFG_MOD_WEEK, 1218 .sp_parse = spd_parse_hex_string }, 1219 { .sp_off = SPD_DDR5_MOD_SN, .sp_len = SPD_DDR5_MOD_SN_LEN, 1220 .sp_key = SPD_KEY_MFG_MOD_SN, .sp_parse = spd_parse_hex_string }, 1221 { .sp_off = SPD_DDR5_MOD_PN, .sp_len = SPD_DDR5_MOD_PN_LEN, 1222 .sp_key = SPD_KEY_MFG_MOD_PN, .sp_parse = spd_parse_string }, 1223 { .sp_off = SPD_DDR5_MOD_REV, .sp_key = SPD_KEY_MFG_MOD_REV, 1224 .sp_parse = spd_parse_dram_step }, 1225 { .sp_off = SPD_DDR5_DRAM_STEP, .sp_key = SPD_KEY_MFG_DRAM_STEP, 1226 .sp_parse = spd_parse_dram_step } 1227 }; 1228 1229 /* 1230 * Annex A.2 UDIMM and SODIMM specific processing. 1231 */ 1232 1233 static const spd_value_map_t spd_ddr5_cd_type_map[] = { 1234 { SPD_DDR5_UDIMM_INFO_TYPE_DDR5CK01, SPD_CD_T_DDR5CK01, false } 1235 }; 1236 1237 static void 1238 spd_parse_ddr5_udimm_cd(spd_info_t *si, uint32_t off, uint32_t len, 1239 const char *key) 1240 { 1241 ASSERT3U(len, ==, 4); 1242 const uint8_t type = si->si_data[off + 2]; 1243 if (SPD_DDR5_COM_INFO_PRES(type) == 0) 1244 return; 1245 1246 spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_CD_0, 1247 SPD_KEY_DEV_CD0_MFG, SPD_KEY_DEV_CD0_MFG_NAME, 1248 SPD_KEY_DEV_CD0_REV, SPD_KEY_DEV_CD0_TYPE, 1249 spd_ddr5_cd_type_map, ARRAY_SIZE(spd_ddr5_cd_type_map)); 1250 } 1251 1252 static void 1253 spd_parse_ddr5_udimm_ckd_cfg(spd_info_t *si, uint32_t off, uint32_t len, 1254 const char *key) 1255 { 1256 const uint8_t data = si->si_data[off]; 1257 1258 if (SPD_DDR5_UDIMM_CKD_CFG_CHAQCK0(data) == 0) 1259 spd_nvl_insert_key(si, SPD_KEY_DDR5_CKD_CHAQCK0_EN); 1260 if (SPD_DDR5_UDIMM_CKD_CFG_CHAQCK1(data) == 0) 1261 spd_nvl_insert_key(si, SPD_KEY_DDR5_CKD_CHAQCK1_EN); 1262 if (SPD_DDR5_UDIMM_CKD_CFG_CHBQCK0(data) == 0) 1263 spd_nvl_insert_key(si, SPD_KEY_DDR5_CKD_CHBQCK0_EN); 1264 if (SPD_DDR5_UDIMM_CKD_CFG_CHBQCK1(data) == 0) 1265 spd_nvl_insert_key(si, SPD_KEY_DDR5_CKD_CHBQCK1_EN); 1266 } 1267 1268 static const spd_value_map_t spd_ddr5_ckd_ds_map[] = { 1269 { SPD_DDR5_UDIMM_CKD_DRV_LIGHT, SPD_DRIVE_LIGHT, false }, 1270 { SPD_DDR5_UDIMM_CKD_DRV_MODERATE, SPD_DRIVE_MODERATE, false }, 1271 { SPD_DDR5_UDIMM_CKD_DRV_STRONG, SPD_DRIVE_STRONG, false }, 1272 { SPD_DDR5_UDIMM_CKD_DRV_WEAK, SPD_DRIVE_WEAK, false } 1273 }; 1274 1275 static void 1276 spd_parse_ddr5_udimm_ckd_drv(spd_info_t *si, uint32_t off, uint32_t len, 1277 const char *key) 1278 { 1279 const uint8_t data = si->si_data[off]; 1280 const uint8_t qck0a = SPD_DDR5_UDIMM_CKD_DRV_CHAQCK0_DRIVE(data); 1281 const uint8_t qck1a = SPD_DDR5_UDIMM_CKD_DRV_CHAQCK1_DRIVE(data); 1282 const uint8_t qck0b = SPD_DDR5_UDIMM_CKD_DRV_CHBQCK0_DRIVE(data); 1283 const uint8_t qck1b = SPD_DDR5_UDIMM_CKD_DRV_CHBQCK1_DRIVE(data); 1284 1285 1286 spd_insert_map(si, SPD_KEY_DDR5_CKD_CHAQCK0_DS, qck0a, 1287 spd_ddr5_ckd_ds_map, ARRAY_SIZE(spd_ddr5_ckd_ds_map)); 1288 spd_insert_map(si, SPD_KEY_DDR5_CKD_CHAQCK1_DS, qck1a, 1289 spd_ddr5_ckd_ds_map, ARRAY_SIZE(spd_ddr5_ckd_ds_map)); 1290 spd_insert_map(si, SPD_KEY_DDR5_CKD_CHBQCK0_DS, qck0b, 1291 spd_ddr5_ckd_ds_map, ARRAY_SIZE(spd_ddr5_ckd_ds_map)); 1292 spd_insert_map(si, SPD_KEY_DDR5_CKD_CHBQCK1_DS, qck1b, 1293 spd_ddr5_ckd_ds_map, ARRAY_SIZE(spd_ddr5_ckd_ds_map)); 1294 } 1295 1296 static const spd_value_map_t spd_ddr5_ckd_slew_map[] = { 1297 { SPD_DDR5_UDIMM_CKD_SLEW_SLEW_MODERATE, SPD_SLEW_MODERATE, false }, 1298 { SPD_DDR5_UDIMM_CKD_SLEW_SLEW_FAST, SPD_SLEW_FAST, false } 1299 }; 1300 1301 static void 1302 spd_parse_ddr5_udimm_ckd_slew(spd_info_t *si, uint32_t off, uint32_t len, 1303 const char *key) 1304 { 1305 const uint8_t data = si->si_data[off]; 1306 const uint8_t qcka = SPD_DDR5_UDIMM_CKD_SLEW_CHAQCK_SLEW(data); 1307 const uint8_t qckb = SPD_DDR5_UDIMM_CKD_SLEW_CHBQCK_SLEW(data); 1308 1309 spd_insert_map(si, SPD_KEY_DDR5_CKD_CHAQCK_SLEW, qcka, 1310 spd_ddr5_ckd_slew_map, ARRAY_SIZE(spd_ddr5_ckd_slew_map)); 1311 spd_insert_map(si, SPD_KEY_DDR5_CKD_CHBQCK_SLEW, qckb, 1312 spd_ddr5_ckd_slew_map, ARRAY_SIZE(spd_ddr5_ckd_slew_map)); 1313 } 1314 1315 static const spd_parse_t spd_ddr5_udimm[] = { 1316 { .sp_off = SPD_DDR5_COM_MFG_ID0_TS, .sp_len = 4, 1317 .sp_parse = spd_parse_ddr5_udimm_cd } 1318 }; 1319 1320 static const spd_parse_t spd_ddr5_udimm_1v1[] = { 1321 { .sp_off = SPD_DDR5_UDIMM_CKD_CFG, 1322 .sp_parse = spd_parse_ddr5_udimm_ckd_cfg }, 1323 { .sp_off = SPD_DDR5_UDIMM_CKD_DRV, 1324 .sp_parse = spd_parse_ddr5_udimm_ckd_drv }, 1325 { .sp_off = SPD_DDR5_UDIMM_CKD_SLEW, 1326 .sp_parse = spd_parse_ddr5_udimm_ckd_slew } 1327 }; 1328 1329 /* 1330 * Annex A.3 RDIMM and LRDIMM specific processing. Because certain fields are 1331 * LRDIMM-only, we use two different top-level tables to drive them; however, 1332 * they generally overlap otherwise. Items that are LRDIMM only will contain 1333 * lrdimm in the name. All items named rdimm are shared between both the LRDIMM 1334 * and RDIMM processing. 1335 */ 1336 static const spd_value_map_t spd_ddr5_rcd_type_map[] = { 1337 { SPD_DDR5_RDIMM_INFO_TYPE_RCD01, SPD_RCD_T_DDR5RCD01, false }, 1338 { SPD_DDR5_RDIMM_INFO_TYPE_RCD02, SPD_RCD_T_DDR5RCD02, false }, 1339 { SPD_DDR5_RDIMM_INFO_TYPE_RCD03, SPD_RCD_T_DDR5RCD03, false }, 1340 { SPD_DDR5_RDIMM_INFO_TYPE_RCD04, SPD_RCD_T_DDR5RCD04, false }, 1341 { SPD_DDR5_RDIMM_INFO_TYPE_RCD05, SPD_RCD_T_DDR5RCD05, false } 1342 }; 1343 1344 static const spd_value_map_t spd_ddr5_db_type_map[] = { 1345 { SPD_DDR5_RDIMM_INFO_TYPE_DB01, SPD_DB_T_DDR5DB01, false }, 1346 { SPD_DDR5_RDIMM_INFO_TYPE_DB02, SPD_DB_T_DDR5DB02, false } 1347 }; 1348 1349 static void 1350 spd_parse_ddr5_rdimm_rcd(spd_info_t *si, uint32_t off, uint32_t len, 1351 const char *key) 1352 { 1353 ASSERT3U(len, ==, 4); 1354 const uint8_t type = si->si_data[off + 2]; 1355 if (SPD_DDR5_COM_INFO_PRES(type) == 0) 1356 return; 1357 1358 spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_RCD, 1359 SPD_KEY_DEV_RCD_MFG, SPD_KEY_DEV_RCD_MFG_NAME, 1360 SPD_KEY_DEV_RCD_REV, SPD_KEY_DEV_RCD_TYPE, 1361 spd_ddr5_rcd_type_map, ARRAY_SIZE(spd_ddr5_rcd_type_map)); 1362 } 1363 1364 static void 1365 spd_parse_ddr5_lrdimm_db(spd_info_t *si, uint32_t off, uint32_t len, 1366 const char *key) 1367 { 1368 ASSERT3U(len, ==, 4); 1369 const uint8_t type = si->si_data[off + 2]; 1370 if (SPD_DDR5_COM_INFO_PRES(type) == 0) 1371 return; 1372 1373 spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_DB, 1374 SPD_KEY_DEV_DB_MFG, SPD_KEY_DEV_DB_MFG_NAME, 1375 SPD_KEY_DEV_DB_REV, SPD_KEY_DEV_DB_TYPE, 1376 spd_ddr5_db_type_map, ARRAY_SIZE(spd_ddr5_db_type_map)); 1377 } 1378 1379 static void 1380 spd_parse_ddr5_rdimm_clken(spd_info_t *si, uint32_t off, uint32_t len, 1381 const char *key) 1382 { 1383 const uint8_t data = si->si_data[off]; 1384 1385 if (SPD_DDR5_RDIMM_CLKEN_QACK(data) == 0) 1386 spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_QACK_EN); 1387 if (SPD_DDR5_RDIMM_CLKEN_QBCK(data) == 0) 1388 spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_QBCK_EN); 1389 if (SPD_DDR5_RDIMM_CLKEN_QCCK(data) == 0) 1390 spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_QCCK_EN); 1391 if (SPD_DDR5_RDIMM_CLKEN_QDCK(data) == 0) 1392 spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_QDCK_EN); 1393 if (SPD_DDR5_RDIMM_CLKEN_BCK(data) == 0) 1394 spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_BCK_EN); 1395 } 1396 1397 static void 1398 spd_parse_ddr5_rdimm_rwen(spd_info_t *si, uint32_t off, uint32_t len, 1399 const char *key) 1400 { 1401 const uint8_t data = si->si_data[off]; 1402 1403 if (SPD_DDR5_RDIMM_RW09_QBCS(data) == 0) 1404 spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_QBCS_EN); 1405 if (SPD_DDR5_RDIMM_RW09_QACS(data) == 0) 1406 spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_QACS_EN); 1407 if (SPD_DDR5_RDIMM_RW09_QXCA13(data) == 0) 1408 spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_QxCA13_EN); 1409 if (SPD_DDR5_RDIMM_RW09_BCS(data) == 0) 1410 spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_BCS_EN); 1411 if (SPD_DDR5_RDIMM_RW09_DCS(data) == 0) 1412 spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_QxCS_EN); 1413 if (SPD_DDR5_RDIMM_RW09_QBCA(data) == 0) 1414 spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_QBCA_EN); 1415 if (SPD_DDR5_RDIMM_RW09_QACA(data) == 0) 1416 spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_QACA_EN); 1417 } 1418 1419 static const spd_value_map_t spd_ddr5_ds_map[] = { 1420 { SPD_DDR5_RDIMM_DRV_LIGHT, SPD_DRIVE_LIGHT, false }, 1421 { SPD_DDR5_RDIMM_DRV_MODERATE, SPD_DRIVE_MODERATE, false }, 1422 { SPD_DDR5_RDIMM_DRV_STRONG, SPD_DRIVE_STRONG, false } 1423 }; 1424 1425 static void 1426 spd_parse_ddr5_rdimm_clkimp(spd_info_t *si, uint32_t off, uint32_t len, 1427 const char *key) 1428 { 1429 const uint8_t data = si->si_data[off]; 1430 const uint8_t qack = SPD_DDR5_RDIMM_QCK_DRV_QACK(data); 1431 const uint8_t qbck = SPD_DDR5_RDIMM_QCK_DRV_QBCK(data); 1432 const uint8_t qcck = SPD_DDR5_RDIMM_QCK_DRV_QCCK(data); 1433 const uint8_t qdck = SPD_DDR5_RDIMM_QCK_DRV_QDCK(data); 1434 1435 spd_insert_map(si, SPD_KEY_DDR5_RCD_QACK_DS, qack, spd_ddr5_ds_map, 1436 ARRAY_SIZE(spd_ddr5_ds_map)); 1437 spd_insert_map(si, SPD_KEY_DDR5_RCD_QBCK_DS, qbck, spd_ddr5_ds_map, 1438 ARRAY_SIZE(spd_ddr5_ds_map)); 1439 spd_insert_map(si, SPD_KEY_DDR5_RCD_QCCK_DS, qcck, spd_ddr5_ds_map, 1440 ARRAY_SIZE(spd_ddr5_ds_map)); 1441 spd_insert_map(si, SPD_KEY_DDR5_RCD_QDCK_DS, qdck, spd_ddr5_ds_map, 1442 ARRAY_SIZE(spd_ddr5_ds_map)); 1443 } 1444 1445 static void 1446 spd_parse_ddr5_rdimm_casimp(spd_info_t *si, uint32_t off, uint32_t len, 1447 const char *key) 1448 { 1449 const uint8_t data = si->si_data[off]; 1450 const uint8_t cs = SPD_DDR5_RDIMM_QCA_DRV_CS(data); 1451 const uint8_t ca = SPD_DDR5_RDIMM_QCA_DRV_CA(data); 1452 1453 spd_insert_map(si, SPD_KEY_DDR5_RCD_QxCS_DS, cs, spd_ddr5_ds_map, 1454 ARRAY_SIZE(spd_ddr5_ds_map)); 1455 spd_insert_map(si, SPD_KEY_DDR5_RCD_CA_DS, ca, spd_ddr5_ds_map, 1456 ARRAY_SIZE(spd_ddr5_ds_map)); 1457 } 1458 1459 static void 1460 spd_parse_ddr5_lrdimm_dbimp(spd_info_t *si, uint32_t off, uint32_t len, 1461 const char *key) 1462 { 1463 const uint8_t data = si->si_data[off]; 1464 const uint8_t bck = SPD_DDR5_LRDIMM_DB_DRV_BCK(data); 1465 const uint8_t bcom = SPD_DDR5_LRDIMM_DB_DRV_BCOM(data); 1466 1467 spd_insert_map(si, SPD_KEY_DDR5_RCD_BCK_DS, bck, spd_ddr5_ds_map, 1468 ARRAY_SIZE(spd_ddr5_ds_map)); 1469 spd_insert_map(si, SPD_KEY_DDR5_RCD_BCOM_DS, bcom, spd_ddr5_ds_map, 1470 ARRAY_SIZE(spd_ddr5_ds_map)); 1471 } 1472 1473 static const spd_value_map_t spd_ddr5_rcd_slew_map[] = { 1474 { SPD_DDR5_RDIMM_SLEW_MODERTE, SPD_SLEW_MODERATE, false }, 1475 { SPD_DDR5_RDIMM_SLEW_FAST, SPD_SLEW_FAST, false }, 1476 { SPD_DDR5_RDIMM_SLEW_SLOW, SPD_SLEW_SLOW, false } 1477 }; 1478 1479 static void 1480 spd_parse_ddr5_rdimm_qslew(spd_info_t *si, uint32_t off, uint32_t len, 1481 const char *key) 1482 { 1483 const uint8_t data = si->si_data[off]; 1484 const uint8_t qcs = SPD_DDR5_RDIMM_QXX_SLEW_QCS(data); 1485 const uint8_t qca = SPD_DDR5_RDIMM_QXX_SLEW_QCA(data); 1486 const uint8_t qck = SPD_DDR5_RDIMM_QXX_SLEW_QCK(data); 1487 1488 spd_insert_map(si, SPD_KEY_DDR5_RCD_QCK_SLEW, qck, 1489 spd_ddr5_rcd_slew_map, ARRAY_SIZE(spd_ddr5_rcd_slew_map)); 1490 spd_insert_map(si, SPD_KEY_DDR5_RCD_QCA_SLEW, qca, 1491 spd_ddr5_rcd_slew_map, ARRAY_SIZE(spd_ddr5_rcd_slew_map)); 1492 spd_insert_map(si, SPD_KEY_DDR5_RCD_QCS_SLEW, qcs, 1493 spd_ddr5_rcd_slew_map, ARRAY_SIZE(spd_ddr5_rcd_slew_map)); 1494 } 1495 1496 static void 1497 spd_parse_ddr5_lrdimm_bslew(spd_info_t *si, uint32_t off, uint32_t len, 1498 const char *key) 1499 { 1500 const uint8_t data = si->si_data[off]; 1501 const uint8_t bck = SPD_DDR5_LRDIMM_BXX_SLEW_BCK(data); 1502 const uint8_t bcom = SPD_DDR5_LRDIMM_BXX_SLEW_BCOM(data); 1503 1504 spd_insert_map(si, SPD_KEY_DDR5_RCD_BCK_SLEW, bck, 1505 spd_ddr5_rcd_slew_map, ARRAY_SIZE(spd_ddr5_rcd_slew_map)); 1506 spd_insert_map(si, SPD_KEY_DDR5_RCD_BCOM_SLEW, bcom, 1507 spd_ddr5_rcd_slew_map, ARRAY_SIZE(spd_ddr5_rcd_slew_map)); 1508 } 1509 1510 static const spd_value_map_t spd_ddr5_rtt_term_map[] = { 1511 { SPD_DDR5_LDRIMM_PARK_OFF, 0, true }, 1512 { SPD_DDR5_LDRIMM_PARK_240R, 240, false }, 1513 { SPD_DDR5_LDRIMM_PARK_120R, 120, false }, 1514 { SPD_DDR5_LDRIMM_PARK_80R, 80, false }, 1515 { SPD_DDR5_LDRIMM_PARK_60R, 60, false }, 1516 { SPD_DDR5_LDRIMM_PARK_48R, 48, false }, 1517 { SPD_DDR5_LDRIMM_PARK_40R, 40, false }, 1518 { SPD_DDR5_LDRIMM_PARK_34R, 34, false } 1519 }; 1520 1521 static void 1522 spd_parse_ddr5_lrdimm_rtt(spd_info_t *si, uint32_t off, uint32_t len, 1523 const char *key) 1524 { 1525 const uint8_t data = si->si_data[off]; 1526 const uint8_t rtt = SPD_DDR5_LRDIMM_PARK_TERM(data); 1527 1528 spd_insert_map(si, SPD_KEY_DDR5_RCD_RTT_TERM, rtt, 1529 spd_ddr5_rtt_term_map, ARRAY_SIZE(spd_ddr5_rtt_term_map)); 1530 } 1531 1532 static const spd_parse_t spd_ddr5_rdimm[] = { 1533 { .sp_off = SPD_DDR5_RDIMM_MFG_ID0_RCD, .sp_len = 4, 1534 .sp_parse = spd_parse_ddr5_rdimm_rcd }, 1535 { .sp_off = SPD_DDR5_RDIMM_CLKEN, 1536 .sp_parse = spd_parse_ddr5_rdimm_clken }, 1537 { .sp_off = SPD_DDR5_RDIMM_RW09, 1538 .sp_parse = spd_parse_ddr5_rdimm_rwen }, 1539 { .sp_off = SPD_DDR5_RDIMM_QCK_DRV, 1540 .sp_parse = spd_parse_ddr5_rdimm_clkimp }, 1541 { .sp_off = SPD_DDR5_RDIMM_QCA_DRV, 1542 .sp_parse = spd_parse_ddr5_rdimm_casimp }, 1543 { .sp_off = SPD_DDR5_RDIMM_QXX_SLEW, 1544 .sp_parse = spd_parse_ddr5_rdimm_qslew } 1545 }; 1546 1547 static const spd_parse_t spd_ddr5_lrdimm[] = { 1548 { .sp_off = SPD_DDR5_RDIMM_MFG_ID0_RCD, .sp_len = 4, 1549 .sp_parse = spd_parse_ddr5_rdimm_rcd }, 1550 { .sp_off = SPD_DDR5_RDIMM_MFG_ID0_DB, .sp_len = 4, 1551 .sp_parse = spd_parse_ddr5_lrdimm_db }, 1552 { .sp_off = SPD_DDR5_RDIMM_CLKEN, 1553 .sp_parse = spd_parse_ddr5_rdimm_clken }, 1554 { .sp_off = SPD_DDR5_RDIMM_RW09, 1555 .sp_parse = spd_parse_ddr5_rdimm_rwen }, 1556 { .sp_off = SPD_DDR5_RDIMM_QCK_DRV, 1557 .sp_parse = spd_parse_ddr5_rdimm_clkimp }, 1558 { .sp_off = SPD_DDR5_RDIMM_QCA_DRV, 1559 .sp_parse = spd_parse_ddr5_rdimm_casimp }, 1560 { .sp_off = SPD_DDR5_LRDIMM_DB_DRV, 1561 .sp_parse = spd_parse_ddr5_lrdimm_dbimp }, 1562 { .sp_off = SPD_DDR5_RDIMM_QXX_SLEW, 1563 .sp_parse = spd_parse_ddr5_rdimm_qslew }, 1564 { .sp_off = SPD_DDR5_LRDIMM_BXX_SLEW, 1565 .sp_parse = spd_parse_ddr5_lrdimm_bslew }, 1566 { .sp_off = SPD_DDR5_LRDIMM_PARK, 1567 .sp_parse = spd_parse_ddr5_lrdimm_rtt }, 1568 }; 1569 1570 /* 1571 * Annex A.4 MRDIMM specific processing. 1572 */ 1573 static const spd_value_map_t spd_ddr5_mrcd_type_map[] = { 1574 { SPD_DDR5_MRDIMM_INFO_TYPE_MRCD01, SPD_MRCD_T_DDR5MRCD01, false }, 1575 { SPD_DDR5_MRDIMM_INFO_TYPE_MRCD02, SPD_MRCD_T_DDR5MRCD02, false } 1576 }; 1577 1578 static const spd_value_map_t spd_ddr5_mdb_type_map[] = { 1579 { SPD_DDR5_MRDIMM_INFO_TYPE_MDB01, SPD_MDB_T_DDR5MDB01, false }, 1580 { SPD_DDR5_MRDIMM_INFO_TYPE_MDB02, SPD_MDB_T_DDR5MDB02, false } 1581 }; 1582 1583 static void 1584 spd_parse_ddr5_mrdimm_mrcd(spd_info_t *si, uint32_t off, uint32_t len, 1585 const char *key) 1586 { 1587 ASSERT3U(len, ==, 4); 1588 const uint8_t type = si->si_data[off + 2]; 1589 if (SPD_DDR5_COM_INFO_PRES(type) == 0) 1590 return; 1591 1592 spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_MRCD, 1593 SPD_KEY_DEV_MRCD_MFG, SPD_KEY_DEV_MRCD_MFG_NAME, 1594 SPD_KEY_DEV_MRCD_REV, SPD_KEY_DEV_MRCD_TYPE, 1595 spd_ddr5_mrcd_type_map, ARRAY_SIZE(spd_ddr5_mrcd_type_map)); 1596 } 1597 1598 static void 1599 spd_parse_ddr5_mrdimm_mdb(spd_info_t *si, uint32_t off, uint32_t len, 1600 const char *key) 1601 { 1602 ASSERT3U(len, ==, 4); 1603 const uint8_t type = si->si_data[off + 2]; 1604 if (SPD_DDR5_COM_INFO_PRES(type) == 0) 1605 return; 1606 1607 spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_MDB, 1608 SPD_KEY_DEV_MDB_MFG, SPD_KEY_DEV_MDB_MFG_NAME, 1609 SPD_KEY_DEV_MDB_REV, SPD_KEY_DEV_MDB_TYPE, 1610 spd_ddr5_mdb_type_map, ARRAY_SIZE(spd_ddr5_mdb_type_map)); 1611 } 1612 1613 static const spd_parse_t spd_ddr5_mrdimm[] = { 1614 { .sp_off = SPD_DDR5_MRDIMM_MFG_ID0_MRCD, .sp_len = 4, 1615 .sp_parse = spd_parse_ddr5_mrdimm_mrcd }, 1616 { .sp_off = SPD_DDR5_MRDIMM_MFG_ID0_MDB, .sp_len = 4, 1617 .sp_parse = spd_parse_ddr5_mrdimm_mdb } 1618 }; 1619 1620 static void 1621 spd_parse_ddr5_mrdimm_cden(spd_info_t *si, uint32_t off, uint32_t len, 1622 const char *key) 1623 { 1624 const uint8_t data = si->si_data[off]; 1625 1626 if (SPD_DDR5_MRDIMM_CDEN_QACK(data) == 0) 1627 spd_nvl_insert_key(si, SPD_KEY_DDR5_MRCD_QACK_EN); 1628 if (SPD_DDR5_MRDIMM_CDEN_QBCK(data) == 0) 1629 spd_nvl_insert_key(si, SPD_KEY_DDR5_MRCD_QBCK_EN); 1630 if (SPD_DDR5_MRDIMM_CDEN_QCCK(data) == 0) 1631 spd_nvl_insert_key(si, SPD_KEY_DDR5_MRCD_QCCK_EN); 1632 if (SPD_DDR5_MRDIMM_CDEN_QDCK(data) == 0) 1633 spd_nvl_insert_key(si, SPD_KEY_DDR5_MRCD_QDCK_EN); 1634 if (SPD_DDR5_MRDIMM_CDEN_BCK(data) == 0) 1635 spd_nvl_insert_key(si, SPD_KEY_DDR5_MRCD_BCK_EN); 1636 } 1637 1638 static void 1639 spd_parse_ddr5_mrdimm_oacen(spd_info_t *si, uint32_t off, uint32_t len, 1640 const char *key) 1641 { 1642 const uint8_t data = si->si_data[off]; 1643 1644 if (SPD_DDR5_MRDIMM_CDEN_QACA(data) == 0) 1645 spd_nvl_insert_key(si, SPD_KEY_DDR5_MRCD_QACA_EN); 1646 if (SPD_DDR5_MRDIMM_CDEN_QBCA(data) == 0) 1647 spd_nvl_insert_key(si, SPD_KEY_DDR5_MRCD_QBCA_EN); 1648 if (SPD_DDR5_MRDIMM_CDEN_QxCS1(data) == 0) 1649 spd_nvl_insert_key(si, SPD_KEY_DDR5_MRCD_QxCS_EN); 1650 if (SPD_DDR5_MRDIMM_CDEN_BCS(data) == 0) 1651 spd_nvl_insert_key(si, SPD_KEY_DDR5_MRCD_BCS_EN); 1652 if (SPD_DDR5_MRDIMM_CDEN_QCA13(data) == 0) 1653 spd_nvl_insert_key(si, SPD_KEY_DDR5_MRCD_QxCA13_EN); 1654 if (SPD_DDR5_MRDIMM_CDEN_QACS(data) == 0) 1655 spd_nvl_insert_key(si, SPD_KEY_DDR5_MRCD_QACS_EN); 1656 if (SPD_DDR5_MRDIMM_CDEN_QBCS(data) == 0) 1657 spd_nvl_insert_key(si, SPD_KEY_DDR5_MRCD_QBCS_EN); 1658 if (SPD_DDR5_MRDIMM_CDEN_DCS1(data) == 0) 1659 spd_nvl_insert_key(si, SPD_KEY_DDR5_MRCD_DCS1_EN); 1660 } 1661 1662 static const spd_value_map_t spd_ddr5_mrcd_ds_map[] = { 1663 { SPD_DDR5_MRDIMM_DRV_LIGHT, SPD_DRIVE_LIGHT, false }, 1664 { SPD_DDR5_MRDIMM_DRV_MODERATE, SPD_DRIVE_MODERATE, false }, 1665 { SPD_DDR5_MRDIMM_DRV_STRONG, SPD_DRIVE_STRONG, false } 1666 }; 1667 1668 static void 1669 spd_parse_ddr5_mrdimm_qck_drv(spd_info_t *si, uint32_t off, uint32_t len, 1670 const char *key) 1671 { 1672 const uint8_t data = si->si_data[off]; 1673 const uint8_t qack = SPD_DDR5_MRDIMM_QCK_DRV_QACK(data); 1674 const uint8_t qbck = SPD_DDR5_MRDIMM_QCK_DRV_QBCK(data); 1675 const uint8_t qcck = SPD_DDR5_MRDIMM_QCK_DRV_QCCK(data); 1676 const uint8_t qdck = SPD_DDR5_MRDIMM_QCK_DRV_QDCK(data); 1677 1678 spd_insert_map(si, SPD_KEY_DDR5_RCD_QACK_DS, qack, spd_ddr5_mrcd_ds_map, 1679 ARRAY_SIZE(spd_ddr5_mrcd_ds_map)); 1680 spd_insert_map(si, SPD_KEY_DDR5_RCD_QBCK_DS, qbck, spd_ddr5_mrcd_ds_map, 1681 ARRAY_SIZE(spd_ddr5_mrcd_ds_map)); 1682 spd_insert_map(si, SPD_KEY_DDR5_RCD_QCCK_DS, qcck, spd_ddr5_mrcd_ds_map, 1683 ARRAY_SIZE(spd_ddr5_mrcd_ds_map)); 1684 spd_insert_map(si, SPD_KEY_DDR5_RCD_QDCK_DS, qdck, spd_ddr5_mrcd_ds_map, 1685 ARRAY_SIZE(spd_ddr5_mrcd_ds_map)); 1686 1687 } 1688 1689 static const spd_value_map_t spd_ddr5_mrcd_out[] = { 1690 { SPD_DDR5_MRDIMM_QCA_DRV_QCS1_OUT_NORM, SPD_MRCD_OUT_NORMAL, false }, 1691 { SPD_DDR5_MRDIMM_QCA_DRV_QCS1_OUT_DIS, SPD_MRCD_OUT_DISABLED, false }, 1692 { SPD_DDR5_MRDIMM_QCA_DRV_QCS1_OUT_LOW, SPD_MRCD_OUT_LOW, false } 1693 }; 1694 1695 static void 1696 spd_parse_ddr5_mrdimm_qca_drv(spd_info_t *si, uint32_t off, uint32_t len, 1697 const char *key) 1698 { 1699 const uint8_t data = si->si_data[off]; 1700 const uint8_t cs = SPD_DDR5_MRDIMM_QCA_DRV_CS(data); 1701 const uint8_t ca = SPD_DDR5_MRDIMM_QCA_DRV_CA(data); 1702 const uint8_t out = SPD_DDR5_MRDIMM_QCA_DRV_QCS1_OUT(data); 1703 1704 spd_insert_map(si, SPD_KEY_DDR5_MRCD_QxCS_DS, cs, spd_ddr5_mrcd_ds_map, 1705 ARRAY_SIZE(spd_ddr5_mrcd_ds_map)); 1706 spd_insert_map(si, SPD_KEY_DDR5_MRCD_CA_DS, ca, spd_ddr5_mrcd_ds_map, 1707 ARRAY_SIZE(spd_ddr5_mrcd_ds_map)); 1708 spd_insert_map(si, SPD_KEY_DDR5_MRCD_QxCS_OUT, out, spd_ddr5_mrcd_out, 1709 ARRAY_SIZE(spd_ddr5_mrcd_out)); 1710 } 1711 1712 static void 1713 spd_parse_ddr5_mrdimm_db_drv(spd_info_t *si, uint32_t off, uint32_t len, 1714 const char *key) 1715 { 1716 const uint8_t data = si->si_data[off]; 1717 const uint8_t bck = SPD_DDR5_MRDIMM_DB_DRV_BCK(data); 1718 const uint8_t bcom = SPD_DDR5_MRDIMM_DB_DRV_BCOM(data); 1719 1720 spd_insert_map(si, SPD_KEY_DDR5_MRCD_BCK_DS, bck, spd_ddr5_mrcd_ds_map, 1721 ARRAY_SIZE(spd_ddr5_mrcd_ds_map)); 1722 spd_insert_map(si, SPD_KEY_DDR5_MRCD_BCOM_DS, bcom, 1723 spd_ddr5_mrcd_ds_map, ARRAY_SIZE(spd_ddr5_mrcd_ds_map)); 1724 } 1725 1726 static const spd_value_map_t spd_ddr5_mrcd_slew_map[] = { 1727 { SPD_DDR5_MRDIMM_SLEW_MODERTE, SPD_SLEW_MODERATE, false }, 1728 { SPD_DDR5_MRDIMM_SLEW_FAST, SPD_SLEW_FAST, false }, 1729 { SPD_DDR5_MRDIMM_SLEW_SLOW, SPD_SLEW_SLOW, false } 1730 }; 1731 1732 static void 1733 spd_parse_ddr5_mrdimm_qxx_slew(spd_info_t *si, uint32_t off, uint32_t len, 1734 const char *key) 1735 { 1736 const uint8_t data = si->si_data[off]; 1737 const uint8_t qcs = SPD_DDR5_MRDIMM_QXX_SLEW_QCS(data); 1738 const uint8_t qca = SPD_DDR5_MRDIMM_QXX_SLEW_QCA(data); 1739 const uint8_t qck = SPD_DDR5_MRDIMM_QXX_SLEW_QCK(data); 1740 1741 spd_insert_map(si, SPD_KEY_DDR5_MRCD_QCK_SLEW, qck, 1742 spd_ddr5_mrcd_slew_map, ARRAY_SIZE(spd_ddr5_mrcd_slew_map)); 1743 spd_insert_map(si, SPD_KEY_DDR5_MRCD_QCA_SLEW, qca, 1744 spd_ddr5_mrcd_slew_map, ARRAY_SIZE(spd_ddr5_mrcd_slew_map)); 1745 spd_insert_map(si, SPD_KEY_DDR5_MRCD_QCS_SLEW, qcs, 1746 spd_ddr5_mrcd_slew_map, ARRAY_SIZE(spd_ddr5_mrcd_slew_map)); 1747 } 1748 1749 static void 1750 spd_parse_ddr5_mrdimm_bxx_slew(spd_info_t *si, uint32_t off, uint32_t len, 1751 const char *key) 1752 { 1753 const uint8_t data = si->si_data[off]; 1754 const uint8_t bck = SPD_DDR5_MRDIMM_BXX_SLEW_BCK(data); 1755 const uint8_t bcom = SPD_DDR5_MRDIMM_BXX_SLEW_BCOM(data); 1756 1757 spd_insert_map(si, SPD_KEY_DDR5_MRCD_BCK_SLEW, bck, 1758 spd_ddr5_mrcd_slew_map, ARRAY_SIZE(spd_ddr5_mrcd_slew_map)); 1759 spd_insert_map(si, SPD_KEY_DDR5_MRCD_BCOM_SLEW, bcom, 1760 spd_ddr5_mrcd_slew_map, ARRAY_SIZE(spd_ddr5_mrcd_slew_map)); 1761 1762 } 1763 1764 static const spd_value_map_t spd_ddr5_mrcd_dca_map[] = { 1765 { 0, SPD_MRCD_DCA_CFG_0, false }, 1766 { 1, SPD_MRCD_DCA_CFG_1, false } 1767 }; 1768 1769 static void 1770 spd_parse_ddr5_mrdimm_dca_cfg(spd_info_t *si, uint32_t off, uint32_t len, 1771 const char *key) 1772 { 1773 const uint8_t data = si->si_data[off]; 1774 const uint8_t cfg = SPD_DDR5_MRDIMM_DCA_CFG_CFG(data); 1775 1776 spd_insert_map(si, SPD_KEY_DDR5_MRCD_DCA_CFG, cfg, 1777 spd_ddr5_mrcd_dca_map, ARRAY_SIZE(spd_ddr5_mrcd_dca_map)); 1778 } 1779 1780 static const spd_value_map_t spd_ddr5_mrdimm_irxt_map[] = { 1781 { SPD_DDR5_MRDIMM_IRXTYPE_TYPE_UNMATCHED, SPD_MRDIMM_IRXT_UNMATCHED, 1782 false }, 1783 { SPD_DDR5_MRDIMM_IRXTYPE_TYPE_MATCHED, SPD_MRDIMM_IRXT_MATCHED, 1784 false } 1785 }; 1786 1787 static void 1788 spd_parse_ddr5_mrdimm_irxtype(spd_info_t *si, uint32_t off, uint32_t len, 1789 const char *key) 1790 { 1791 const uint8_t data = si->si_data[off]; 1792 const uint8_t irxt = SPD_DDR5_MRDIMM_IRXTYPE_TYPE(data); 1793 1794 spd_insert_map(si, SPD_KEY_DDR5_MRDIMM_IRXT, irxt, 1795 spd_ddr5_mrdimm_irxt_map, ARRAY_SIZE(spd_ddr5_mrdimm_irxt_map)); 1796 } 1797 1798 static const spd_parse_t spd_ddr5_mrdimm_1v1[] = { 1799 { .sp_off = SPD_DDR5_MRDIMM_CDEN, 1800 .sp_parse = spd_parse_ddr5_mrdimm_cden }, 1801 { .sp_off = SPD_DDR5_MRDIMM_OACEN, 1802 .sp_parse = spd_parse_ddr5_mrdimm_oacen }, 1803 { .sp_off = SPD_DDR5_MRDIMM_QCK_DRV, 1804 .sp_parse = spd_parse_ddr5_mrdimm_qck_drv }, 1805 { .sp_off = SPD_DDR5_MRDIMM_QCA_DRV, 1806 .sp_parse = spd_parse_ddr5_mrdimm_qca_drv }, 1807 { .sp_off = SPD_DDR5_MRDIMM_DB_DRV, 1808 .sp_parse = spd_parse_ddr5_mrdimm_db_drv }, 1809 { .sp_off = SPD_DDR5_MRDIMM_QXX_SLEW, 1810 .sp_parse = spd_parse_ddr5_mrdimm_qxx_slew }, 1811 { .sp_off = SPD_DDR5_MRDIMM_BXX_SLEW, 1812 .sp_parse = spd_parse_ddr5_mrdimm_bxx_slew }, 1813 { .sp_off = SPD_DDR5_MRDIMM_DCA_CFG, 1814 .sp_parse = spd_parse_ddr5_mrdimm_dca_cfg }, 1815 { .sp_off = SPD_DDR5_MRDIMM_IRXTYPE, 1816 .sp_parse = spd_parse_ddr5_mrdimm_irxtype } 1817 }; 1818 1819 /* 1820 * Annex A.5 DDIMM specific processing. 1821 */ 1822 static const spd_value_map_t spd_ddr5_dmb_type_map[] = { 1823 { SPD_DDR5_DDIMM_INFO_TYPE_DMB501, SPD_DMB_T_DMB5011, false } 1824 }; 1825 1826 static void 1827 spd_parse_ddr5_ddimm_dmb(spd_info_t *si, uint32_t off, uint32_t len, 1828 const char *key) 1829 { 1830 ASSERT3U(len, ==, 4); 1831 const uint8_t type = si->si_data[off + 2]; 1832 if (SPD_DDR5_COM_INFO_PRES(type) == 0) 1833 return; 1834 1835 spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_DMB, 1836 SPD_KEY_DEV_DMB_MFG, SPD_KEY_DEV_DMB_MFG_NAME, 1837 SPD_KEY_DEV_DMB_REV, SPD_KEY_DEV_DMB_TYPE, 1838 spd_ddr5_dmb_type_map, ARRAY_SIZE(spd_ddr5_dmb_type_map)); 1839 } 1840 1841 static const spd_parse_t spd_ddr5_ddimm[] = { 1842 { .sp_off = SPD_DDR5_DDIMM_MFG_ID0_DMB, .sp_len = 4, 1843 .sp_parse = spd_parse_ddr5_ddimm_dmb }, 1844 }; 1845 1846 /* 1847 * Annex A.8 CAMM2 specific processing. 1848 */ 1849 static void 1850 spd_parse_ddr5_camm2_ckd0(spd_info_t *si, uint32_t off, uint32_t len, 1851 const char *key) 1852 { 1853 ASSERT3U(len, ==, 4); 1854 const uint8_t type = si->si_data[off + 2]; 1855 if (SPD_DDR5_COM_INFO_PRES(type) == 0) 1856 return; 1857 1858 spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_CD_0, 1859 SPD_KEY_DEV_CD0_MFG, SPD_KEY_DEV_CD0_MFG_NAME, 1860 SPD_KEY_DEV_CD0_REV, SPD_KEY_DEV_CD0_TYPE, 1861 spd_ddr5_cd_type_map, ARRAY_SIZE(spd_ddr5_cd_type_map)); 1862 } 1863 1864 static void 1865 spd_parse_ddr5_camm2_ckd1(spd_info_t *si, uint32_t off, uint32_t len, 1866 const char *key) 1867 { 1868 ASSERT3U(len, ==, 4); 1869 const uint8_t type = si->si_data[off + 2]; 1870 if (SPD_DDR5_COM_INFO_PRES(type) == 0) 1871 return; 1872 1873 spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_CD_1, 1874 SPD_KEY_DEV_CD1_MFG, SPD_KEY_DEV_CD1_MFG_NAME, 1875 SPD_KEY_DEV_CD1_REV, SPD_KEY_DEV_CD1_TYPE, 1876 spd_ddr5_cd_type_map, ARRAY_SIZE(spd_ddr5_cd_type_map)); 1877 } 1878 1879 static const spd_parse_t spd_ddr5_camm2[] = { 1880 { .sp_off = SPD_DDR5_CAMM2_MFG_ID0_CKD0, .sp_len = 4, 1881 .sp_parse = spd_parse_ddr5_camm2_ckd0 }, 1882 { .sp_off = SPD_DDR5_CAMM2_MFG_ID0_CKD1, .sp_len = 4, 1883 .sp_parse = spd_parse_ddr5_camm2_ckd1 }, 1884 }; 1885 1886 static void 1887 spd_parse_ddr5_mod_specific(spd_info_t *si) 1888 { 1889 uint32_t type; 1890 1891 if (nvlist_lookup_uint32(si->si_nvl, SPD_KEY_MOD_TYPE, &type) != 0) 1892 return; 1893 1894 switch (type) { 1895 case SPD_MOD_TYPE_RDIMM: 1896 spd_parse(si, spd_ddr5_rdimm, ARRAY_SIZE(spd_ddr5_rdimm)); 1897 break; 1898 case SPD_MOD_TYPE_LRDIMM: 1899 spd_parse(si, spd_ddr5_lrdimm, ARRAY_SIZE(spd_ddr5_lrdimm)); 1900 break; 1901 case SPD_MOD_TYPE_UDIMM: 1902 case SPD_MOD_TYPE_SODIMM: 1903 case SPD_MOD_TYPE_CUDIMM: 1904 case SPD_MOD_TYPE_CSODIMM: 1905 spd_parse(si, spd_ddr5_udimm, ARRAY_SIZE(spd_ddr5_udimm)); 1906 if (SPD_DDR5_SPD_REV_ADD(si->si_data[SPD_DDR5_COM_REV]) >= 1) { 1907 spd_parse(si, spd_ddr5_udimm_1v1, 1908 ARRAY_SIZE(spd_ddr5_udimm_1v1)); 1909 } 1910 break; 1911 case SPD_MOD_TYPE_MRDIMM: 1912 spd_parse(si, spd_ddr5_mrdimm, ARRAY_SIZE(spd_ddr5_mrdimm)); 1913 if (SPD_DDR5_SPD_REV_ADD(si->si_data[SPD_DDR5_COM_REV]) >= 1) { 1914 spd_parse(si, spd_ddr5_mrdimm_1v1, 1915 ARRAY_SIZE(spd_ddr5_mrdimm_1v1)); 1916 } 1917 break; 1918 case SPD_MOD_TYPE_DDIMM: 1919 spd_parse(si, spd_ddr5_ddimm, ARRAY_SIZE(spd_ddr5_ddimm)); 1920 break; 1921 case SPD_MOD_TYPE_CAMM2: 1922 spd_parse(si, spd_ddr5_camm2, ARRAY_SIZE(spd_ddr5_camm2)); 1923 break; 1924 /* 1925 * Soldered DIMMs don't have any data. 1926 */ 1927 case SPD_MOD_TYPE_SOLDER: 1928 default: 1929 break; 1930 } 1931 } 1932 1933 /* 1934 * This is a common entry point for all of the common pieces of DDR5 and LPDDR5. 1935 * They use the same offsets and meanings and therefore this is called by both. 1936 * While strictly speaking LPDDR5 doesn't support all of the different types of 1937 * module types that DDR5 does, we will parse whatever is claimed. 1938 */ 1939 void 1940 spd_parse_ddr5_common(spd_info_t *si) 1941 { 1942 spd_parse(si, spd_ddr5_module, ARRAY_SIZE(spd_ddr5_module)); 1943 spd_parse(si, spd_ddr5_mfg, ARRAY_SIZE(spd_ddr5_mfg)); 1944 spd_parse_ddr5_mod_specific(si); 1945 } 1946 1947 /* 1948 * DDR5 has two different revisions. One that is present in the base region and 1949 * one that is present in the common module region that covers the 1950 * module-related pieces. We check that both are present and go from there. We 1951 * may want to relax this in the future so that it's easier to just decode a 1952 * subset of this, but for the time being, we require both. 1953 */ 1954 void 1955 spd_parse_ddr5(spd_info_t *si) 1956 { 1957 if (SPD_DDR5_SPD_REV_ENC(si->si_data[SPD_DDR5_SPD_REV]) != 1958 SPD_DDR5_SPD_REV_V1) { 1959 si->si_error = LIBJEDEC_SPD_UNSUP_REV; 1960 return; 1961 } 1962 1963 if (si->si_nbytes <= SPD_DDR5_COM_REV) { 1964 si->si_error = LIBJEDEC_SPD_TOOSHORT; 1965 return; 1966 } 1967 1968 if (SPD_DDR5_SPD_REV_ENC(si->si_data[SPD_DDR5_COM_REV]) != 1969 SPD_DDR5_SPD_REV_V1) { 1970 si->si_error = LIBJEDEC_SPD_UNSUP_REV; 1971 return; 1972 } 1973 1974 spd_parse(si, spd_ddr5_base, ARRAY_SIZE(spd_ddr5_base)); 1975 if (SPD_DDR5_SPD_REV_ADD(si->si_data[SPD_DDR5_COM_REV]) >= 2) 1976 spd_parse(si, spd_ddr5_base_1v2, ARRAY_SIZE(spd_ddr5_base_1v2)); 1977 spd_parse_ddr5_common(si); 1978 } 1979