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