From 27d51dd4709eab460d8bffe0099da545b00cd84a Mon Sep 17 00:00:00 2001 From: Andre Marin Date: Tue, 9 Feb 2016 13:16:51 -0600 Subject: Modify spd_decoder, eff_config, unit tests. Modify dependent files Change-Id: I8280ac1f6c66f822725ae6a4446ce7a23453aec6 Original-Change-Id: Ifa4fbf9d452a3e77075bee9ab72b2bde2afe90a5 Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/20861 Tested-by: Jenkins Server Tested-by: Auto Mirror Reviewed-by: Brian R. Silver Tested-by: Hostboot CI Reviewed-by: CRAIG C. HAMILTON Reviewed-by: Jennifer A. Stofer Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/22776 Tested-by: FSP CI Jenkins Reviewed-by: Daniel M. Crowell --- .../p9/procedures/hwp/memory/lib/spd/spd_decoder.C | 5799 +++++++++++--------- .../p9/procedures/hwp/memory/lib/spd/spd_decoder.H | 1230 ++++- 2 files changed, 4232 insertions(+), 2797 deletions(-) (limited to 'src/import/chips/p9/procedures/hwp/memory/lib/spd') diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/spd/spd_decoder.C b/src/import/chips/p9/procedures/hwp/memory/lib/spd/spd_decoder.C index d215773a0..00c4c6419 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/spd/spd_decoder.C +++ b/src/import/chips/p9/procedures/hwp/memory/lib/spd/spd_decoder.C @@ -7,7 +7,7 @@ /* */ /* EKB Project */ /* */ -/* COPYRIGHT 2015 */ +/* COPYRIGHT 2015,2016 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -17,6 +17,7 @@ /* */ /* IBM_PROLOG_END_TAG */ + /// /// @file spd_decoder.C /// @brief SPD decoder definitions @@ -28,8 +29,9 @@ // *HWP Consumed by: HB:FSP #include -#include "../mss.H" +#include #include "../utils/conversions.H" +#include "../utils/find.H" #include "spd_decoder.H" using fapi2::TARGET_TYPE_MCBIST; @@ -43,7 +45,7 @@ namespace mss namespace spd { -// Note: IBM's implementation of std::maps are not thread safe +// Note: IBM's implementation of std::map is not thread safe // ========================================================= // Byte 0 maps @@ -51,31 +53,22 @@ namespace spd // Page 14 // DDR4 SPD Document Release 3 // Byte 0 (0x000): Number of Bytes Used / Number of Bytes in SPD Device - -static const uint16_t bytes_used_map[] = +// ========================================================= +static const std::vector > BYTES_USED_MAP = { - // Shifting index by 1 first since first key value is undefined - // Key values < 1 and > 3 aren't supported or reserved - - // Undefined - 128, - 256, - 384, - 512, - //... - // All other bits reserved + //{key byte, number of used bytes} + {1, 128}, + {2, 256}, + {3, 384}, + {4, 512} }; -static const uint16_t bytes_total_map[] = -{ - // Shifting index by 1 first since first key value is undefined - // Key values < 1 and > 2 aren't supported or reserved - // Undefined - 256, - 512, - //... - // All other bits reserved +static const std::vector > BYTES_TOTAL_MAP = +{ + //{key byte, number of total bytes} + {1, 256}, + {2, 512} }; // ========================================================= @@ -84,28 +77,13 @@ static const uint16_t bytes_total_map[] = // Page 16 // DDR4 SPD Document Release 3 // Byte 2 (0x002): Key Byte / DRAM Device Type - -static const uint8_t dram_gen_map[] = -{ - // Initial and ending index values are not supported or reserved - // Shifting index by 11 since initial dram gen types aren't supported (by IBM) - // Key values < 12 and > 13 are not supported or reserved - - // Reserved - // Fast page mode is not supported - // EDO is not supported - // Pipelined Nibbleis not supported - // SDRAM - // ROM is not supported - // DDR SGRAM is not supported - // DDR SDRAM is not supported - // DDR2 SDRAM is not supported - // DDR2 SDRAM FB-DIMM is not supported - // DDR2 SDRAM FB-DIMM PROBE is not supported - fapi2::ENUM_ATTR_EFF_DRAM_GEN_DDR3, - fapi2::ENUM_ATTR_EFF_DRAM_GEN_DDR4, - //... - // All other bits reserved +// ========================================================= +static const std::vector > DRAM_GEN_MAP = +{ + //{key value, dram gen} + {0x0B, fapi2::ENUM_ATTR_EFF_DRAM_GEN_DDR3}, + {0x0C, fapi2::ENUM_ATTR_EFF_DRAM_GEN_DDR4} + // Other key bytes reserved or not supported }; // ========================================================= @@ -114,30 +92,27 @@ static const uint8_t dram_gen_map[] = // Page 17 // DDR4 SPD Document Release 3 // Byte 3 (0x003): Key Byte / Module Type +// ========================================================= +static const std::vector > BASE_MODULE_TYPE_MAP = +{ + //{key byte, dimm type} + {1, fapi2::ENUM_ATTR_EFF_DIMM_TYPE_RDIMM}, + {2, fapi2::ENUM_ATTR_EFF_DIMM_TYPE_UDIMM}, + {4, fapi2::ENUM_ATTR_EFF_DIMM_TYPE_LRDIMM} +}; -static const uint8_t base_module_type_map[] = -{ - - // Initial and ending index values are not supported or reserved - // Index shifted by 1 since first module type isn't supported (by IBM) - // Key values < 1 and > 4 are not supported or reserved - - // Extending DIMM not supported - fapi2::ENUM_ATTR_SPD_MODULE_TYPE_RDIMM, - fapi2::ENUM_ATTR_SPD_MODULE_TYPE_UDIMM, - fapi2::ENUM_ATTR_SPD_MODULE_TYPE_SO_DIMM, - fapi2::ENUM_ATTR_SPD_MODULE_TYPE_LRDIMM, - // Mini-RDIMM not supported - // Mini-UDIMM not supported - // Reserved - // 72b-SO-RDIMM not supported - // 72b-SO-UDIMM not supported - // Reserved - // Reserved - // 16b-SO-DIMM - // 32b-SO-DIMM - // Reserved - // Reserved +static const std::vector > HYBRID_MEDIA_MAP = +{ + //{key, value} + {0, fapi2::ENUM_ATTR_EFF_HYBRID_MEMORY_TYPE_NONE}, + {1, fapi2::ENUM_ATTR_EFF_HYBRID_MEMORY_TYPE_NVDIMM} +}; + +static const std::vector > HYBRID_MAP = +{ + //{key byte, value} + {0, fapi2::ENUM_ATTR_EFF_HYBRID_NOT_HYBRID}, + {1, fapi2::ENUM_ATTR_EFF_HYBRID_IS_HYBRID} }; // ========================================================= @@ -146,74 +121,62 @@ static const uint8_t base_module_type_map[] = // Page 18 // DDR4 SPD Document Release 3 // Byte 4 (0x004): SDRAM Density and Banks - -static const uint8_t sdram_capacity_map[] = -{ - // Initial and ending index values are not supported or reserved - // Index shifted by 2 since first module type isn't supported (by IBM) - // Key values < 2 and > 9 are not supported or reserved - - // 256 Mbs is not supported - // 512 Mbs is not supported - // // Units (Gigabits) - 1, // Gb - 2, // Gb - 4, // Gb - 8, // Gb - 16, // Gb - 32, // Gb - 12, // Gb - 24, // Gb - //... - //All others reserved +// ========================================================= +static const std::vector > SDRAM_DENSITY_MAP = +{ + // {key byte, capacity in GBs} + {2, 1}, + {3, 2}, + {4, 4}, + {5, 8}, + {6, 16}, + {7, 32}, + {8, 12}, + {12, 24} }; -static const uint8_t sdram_banks_map[] = +static const std::vector > BANK_ADDR_BITS_MAP = { - // Key values > 1 are not supported or reserved - - 4, // banks address bits (2 address bits) - 8, // banks address bits (3 address bits) - //... - // All others Reserved + // {key byte, number of bank address bits} + {0, 2}, + {1, 3} }; -static const uint8_t sdram_bankgroups_map[] = +static const std::vector > BANK_GROUP_BITS_MAP = { - // Key values > 2 are not supported or reserved - - 0, // No bank groups (0 bank group bits) - 2, // 2 bank groups (1 bank group bit) - 4, // 4 bank groups (2 bank group bits) - //Reserved + // {key byte, number of bank groups bits} + {0, 0}, + {1, 1}, + {2, 2} }; + // ========================================================= // Byte 5 maps // Item JC-45-2220.01x // Page 18 // DDR4 SPD Document Release 3 // Byte 5 (0x005): SDRAM Addressing - -static const uint8_t column_address_map[] = +// ========================================================= +static const std::vector > COLUMN_ADDRESS_BITS_MAP = { - 9, // Column address bits 000 - 10, // Column address bits 001 - 11, // Column address bits 010 - 12, // Column address bits 011 - // All others reserved + //{key byte,col address bits} + {0, 9}, + {1, 10}, + {2, 11}, + {3, 12} }; -static const uint8_t row_address_map[] = +static const std::vector > ROW_ADDRESS_BITS_MAP = { - 12, // Row address bits 000 - 13, // Row address bits 001 - 14, // Row address bits 010 - 15, // Row address bits 011 - 16, // Row address bits 100 - 17, // Row address bits 101 - 18, // Row address bits 110 - // All others reserved + //{key byte,row address bits} + {0, 12}, + {1, 13}, + {2, 14}, + {3, 15}, + {4, 16}, + {5, 17}, + {6, 18} }; // ========================================================= @@ -222,28 +185,34 @@ static const uint8_t row_address_map[] = // Page 19 // DDR4 SPD Document Release 3 // Byte 6 (0x006): Primary SDRAM Package Type +// ========================================================= +static const std::vector > PRIM_SIGNAL_LOADING_MAP = +{ + // {key byte, signal loading} + {0, UNSPECIFIED}, + {1, MULTI_LOAD_STACK}, + {2, SINGLE_LOAD_STACK} +}; -static const uint8_t die_count_map[] = +static const std::vector > PRIM_DIE_COUNT_MAP = { - 1, // 000 = Single die - 2, // 001 = 2 die - 3, // 010 = 3 die - 4, // 011 = 4 die - 5, // 100 = 5 die - 6, // 101 = 6 die - 7, // 110 = 7 die - 8, // 111 = 8 die + // {key byte, number of die} + {0, 1}, + {1, 2}, + {2, 3}, + {3, 4}, + {4, 5}, + {5, 6}, + {6, 7}, + {7, 8} + }; -static const uint8_t package_type_map[] = +static const std::vector > PRIM_PACKAGE_TYPE_MAP = { - fapi2::ENUM_ATTR_EFF_STACK_TYPE_SDP, - uint8_t(~0), - uint8_t(~0), - uint8_t(~0), - uint8_t(~0), - fapi2::ENUM_ATTR_EFF_STACK_TYPE_DDP_QDP, - fapi2::ENUM_ATTR_EFF_STACK_TYPE_3DS, + // {key byte, value} + {0, MONOLITHIC}, + {1, NON_MONOLITHIC} }; // ========================================================= @@ -252,26 +221,27 @@ static const uint8_t package_type_map[] = // Page 20 // DDR4 SPD Document Release 3 // Byte 7 (0x007): SDRAM Optional Features - -uint16_t static const MAC_map[] = -{ - fapi2::ENUM_ATTR_EFF_DRAM_MAC_UNTESTED, // Untested MAC - fapi2::ENUM_ATTR_EFF_DRAM_MAC_700K, // 700K - fapi2::ENUM_ATTR_EFF_DRAM_MAC_600K, // 600K - fapi2::ENUM_ATTR_EFF_DRAM_MAC_500K, // 500K - fapi2::ENUM_ATTR_EFF_DRAM_MAC_400K, // 400K - fapi2::ENUM_ATTR_EFF_DRAM_MAC_300K, // 300K - fapi2::ENUM_ATTR_EFF_DRAM_MAC_200K, // 200K - uint16_t(~0), // Reserved - fapi2::ENUM_ATTR_EFF_DRAM_MAC_UNLIMITED,// Unlimited MAC - // All others reserved +// ========================================================= +static const std::vector > MAC_MAP = +{ + // {key byte, maximum activate count} + {0, fapi2::ENUM_ATTR_EFF_DRAM_MAC_UNTESTED}, + {1, fapi2::ENUM_ATTR_EFF_DRAM_MAC_700K}, + {2, fapi2::ENUM_ATTR_EFF_DRAM_MAC_600K}, + {3, fapi2::ENUM_ATTR_EFF_DRAM_MAC_500K}, + {4, fapi2::ENUM_ATTR_EFF_DRAM_MAC_400K}, + {5, fapi2::ENUM_ATTR_EFF_DRAM_MAC_300K}, + {6, fapi2::ENUM_ATTR_EFF_DRAM_MAC_200K}, + {8, fapi2::ENUM_ATTR_EFF_DRAM_MAC_UNLIMITED} }; -uint16_t static const tMAW_map[] = +// Multiplier with tREFI is not taken into account here +static const std::vector > TMAW_MAP = { - 8192, - 4096, - 2048, + // {key byte, tMAW multiplier} + {0, 8192}, + {1, 4096}, + {2, 2048} }; // ========================================================= @@ -280,48 +250,77 @@ uint16_t static const tMAW_map[] = // Page 21 // DDR4 SPD Document Release 3 // Byte 9 (0x009): Other SDRAM Optional Features -static const uint8_t ppr_map[] +// ========================================================= +static const std::vector > SOFT_PPR_MAP = { - fapi2::ENUM_ATTR_EFF_DRAM_PPR_NOT_SUPPORTED, - fapi2::ENUM_ATTR_EFF_DRAM_PPR_SUPPORTED, - //... - // Reserved + // {key byte, value } + {0, fapi2::ENUM_ATTR_EFF_DRAM_SOFT_PPR_NOT_SUPPORTED}, + {1, fapi2::ENUM_ATTR_EFF_DRAM_SOFT_PPR_SUPPORTED} }; -static const uint8_t soft_ppr_map[] +static const std::vector > PPR_MAP = { - fapi2::ENUM_ATTR_EFF_DRAM_SOFT_PPR_NOT_SUPPORTED, - fapi2::ENUM_ATTR_EFF_DRAM_SOFT_PPR_SUPPORTED, + // {key byte, value } + {0, fapi2::ENUM_ATTR_EFF_DRAM_PPR_NOT_SUPPORTED}, + {1, fapi2::ENUM_ATTR_EFF_DRAM_PPR_SUPPORTED} }; // ========================================================= -// Byte 6 maps +// Byte 10 maps // Item JC-45-2220.01x -// Page 19 +// Page 21-22 // DDR4 SPD Document Release 3 -// Byte 6 (0x006): Primary SDRAM Package Type +// Byte 10 (0x00A): Secondary SDRAM Package Type +// ========================================================= +static const std::vector > SEC_SIGNAL_LOADING_MAP = +{ + // {key byte, signal loading} + {0, UNSPECIFIED}, + {1, MULTI_LOAD_STACK}, + {2, SINGLE_LOAD_STACK} +}; + +static const std::vector > SEC_DIE_COUNT_MAP = +{ + // {key byte, number of die} + {0, 1}, + {1, 2}, + {2, 3}, + {3, 4}, + {4, 5}, + {5, 6}, + {6, 7}, + {7, 8} + +}; + +static const std::vector > SEC_PACKAGE_TYPE_MAP = +{ + // {key byte, value } + {0, MONOLITHIC}, + {1, NON_MONOLITHIC} +}; -static const uint8_t sec_die_count_map[] = + +// ========================================================= +// Byte 11 maps +// Item JC-45-2220.01x +// Page 22-23 +// DDR4 SPD Document Release 3 +// Byte 11 (0x00B): Modle Nominal Voltage +// ========================================================= +static const std::vector > ENDURANT_MAP = { - 1, // 000 = Single die - 2, // 001 = 2 die - 3, // 010 = 3 die - 4, // 011 = 4 die - 5, // 100 = 5 die - 6, // 101 = 6 die - 7, // 110 = 7 die - 8, // 111 = 8 die + // {key byte, value } + {0, NOT_ENDURANT}, + {1, ENDURANT} }; -static const uint8_t sec_package_type_map[] = +static const std::vector > OPERABLE_MAP = { - fapi2::ENUM_ATTR_EFF_STACK_TYPE_SDP, - uint8_t(~0), - uint8_t(~0), - uint8_t(~0), - uint8_t(~0), - fapi2::ENUM_ATTR_EFF_STACK_TYPE_DDP_QDP, - fapi2::ENUM_ATTR_EFF_STACK_TYPE_3DS, + // {key byte, value } + {0, NOT_OPERABLE }, + {1, OPERABLE} }; // ========================================================= @@ -330,51 +329,51 @@ static const uint8_t sec_package_type_map[] = // Page 23 // DDR4 SPD Document Release 3 // Byte 12 (0x00C): Module Organization -static const uint8_t device_type_map[] = +// ========================================================= +static const std::vector > DEVICE_WIDTH_MAP = { - // // Units - 4, // bits - 8, // bits - 16, // bits - 32, // bits + // {key byte, device width (bits)} + {0, 4}, + {1, 8}, + {2, 16}, + {3, 32}, // All others reserved }; -static const uint8_t num_pkgs_ranks_per_dimm_map[] = -{ - // // Units - 1, // package rank - 2, // package ranks - 3, // package ranks - 4, // package ranks - 5, // package ranks - 6, // package ranks - 7, // package ranks - 8 // package ranks - // All others reserved +static const std::vector > NUM_PACKAGE_RANKS_MAP = +{ + // {key byte, num of package ranks per DIMM (package ranks)} + {0, 1}, + {1, 2}, + {2, 3}, + {3, 4}, + {4, 5}, + {5, 6}, + {6, 7}, + {7, 8} }; // ========================================================= -// Byte 12 maps +// Byte 13 maps // Item JC-45-2220.01x -// Page 23 +// Page 27 // DDR4 SPD Document Release 3 // Byte 13 (0x00D): Module Memory Bus Width -static const uint8_t prim_bus_width_map[] = +// ========================================================= +static const std::vector > BUS_WIDTH_MAP = { - // // Units - 8, // bits - 16, // bits - 32, // bits - 64, // bits + // {key byte, bus width (in bits) + {0, 8}, + {1, 16}, + {2, 32}, + {3, 64} // All others reserved }; -static const uint8_t bus_width_ext_map[] = +static const std::vector > BUS_WIDTH_EXT_MAP = { - // // Units - 0, // bits - 8, // bits + {0, 0}, + {1, 8} // All others reserved }; @@ -384,1313 +383,1259 @@ static const uint8_t bus_width_ext_map[] = // Page 29 // DDR4 SPD Document Release 3 // Byte 17 (0x011): Timebases - +// ========================================================= // Created a maps of a single value in case mapping expands to more values -static const uint8_t medium_timebase_map[] = +static const std::vector > MEDIUM_TIMEBASE_MAP = { - // // Units - 125, // ps + // {key byte, medium timebase (in picoseconds) + {0, 125} // All others reserved }; -static const uint8_t fine_timebase_map[] = +static const std::vector > FINE_TIMEBASE_MAP = { - // // Units - 1, // ps + // {key byte, fine timebase (in picoseconds) + {0, 1} // All others reserved }; -// ========================================================= -// Function implementations -// ========================================================= -namespace check -{ +///////////////////////// +// Static member functions implementation +///////////////////////// + /// -/// @brief Checks that stack type conforms to JEDEC table -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data -/// @return fapi2::ReturnCode -/// @note Consumed in (Byte 7) sdram_package_type(...) -/// Item JC-45-2220.01x -/// Page 20 (Terminology table) -/// DDR4 SPD Document Release 3 -bool stack_type(const uint8_t i_stack_type, const uint8_t i_die_count) +/// @brief Decodes SPD Revision encoding level +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value revision number +/// @return fapi2::ReturnCode +/// @note Decodes SPD Byte 1 (3~0). +/// @note Item JC-45-2220.01x +/// @note Page 14-15 +/// @note DDR4 SPD Document Release 3 +/// +fapi2::ReturnCode decoder::rev_encoding_level(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value) { - const size_t STACK_SDP = 0; - const size_t STACK_DDP_QDP = 5; - const size_t STACK_3DS = 6; + constexpr size_t BYTE_INDEX = 1; + constexpr size_t UNDEFINED = 0xF; // per JEDEC spec this value is undefined + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_bit_fields = 0; - const size_t SINGLE_DIE_PACKAGE = 1; - const size_t DUAL_DIE_PACKAGE = 2; - const size_t QUAD_DIE_PACKAGE = 4; + // Buffer used for bit manipulation + fapi2::buffer l_buffer(l_raw_byte); - const size_t TWO_SDRAM_DIE = 2; - const size_t EIGHT_SDRAM_DIE = 8; + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), + BYTE_INDEX, + l_raw_byte); - // Use const or enums - switch(i_stack_type) - { - case STACK_SDP: - //SDP has single die - return i_die_count == SINGLE_DIE_PACKAGE; - break; + // Extracting desired bits + l_buffer.extractToRight(l_bit_fields); - case STACK_DDP_QDP: - //DDP has 2 die, QDP has 4 die - return (i_die_count == DUAL_DIE_PACKAGE) || (i_die_count == QUAD_DIE_PACKAGE); - break; + FAPI_TRY( mss::check::spd:: + fail_for_invalid_value(i_target, + (l_bit_fields != UNDEFINED), + BYTE_INDEX, + l_raw_byte, + "Failed check on SPD rev encoding level") ); - case STACK_3DS: - //3DS has 2 - 8 dies - return (i_die_count >= TWO_SDRAM_DIE) && (i_die_count <= EIGHT_SDRAM_DIE); - break; + // Update output only after check passes + o_value = l_bit_fields; - default: - return false; // Doesn't meet JEDEC spec - } -}// stack_type() + // Print decoded info + FAPI_DBG("%s. Rev - Encoding Level : %d", + c_str(i_target), + o_value); -} // check namespace +fapi_try_exit: + return fapi2::current_err; +} /// -/// @brief Calculates timing value -/// @param[in] const int64_t& i_spd_timing_mtb, -/// const int64_t& i_spd_timing_ftb, -/// const int64_t& multiplier_mtb, -/// const int64_t& multiplier_ftb -/// @return int64_t, (timing value) -inline int64_t calc_timing(const int64_t& i_spd_timing_mtb, - const int64_t& i_spd_timing_ftb, - const int64_t& multiplier_mtb, - const int64_t& multiplier_ftb) +/// @brief Decodes SPD Revision additions level +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value revision number +/// @return fapi2::ReturnCode +/// @note Decodes SPD Byte 1 (bits 7~4). +/// @note Item JC-45-2220.01x +/// @note Page 14-15 +/// @note DDR4 SPD Document Release 3 +/// +fapi2::ReturnCode decoder::rev_additions_level(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value) { - int64_t timing_val = i_spd_timing_mtb * multiplier_mtb; - int64_t offset = (i_spd_timing_ftb * multiplier_ftb); - int64_t remainder_val = timing_val % multiplier_mtb; + constexpr size_t BYTE_INDEX = 1; + constexpr size_t UNDEFINED = 0xF; // per JEDEC spec this value is undefined + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_bit_fields = 0; - if( remainder_val == 0) - { - // If the timing value can be expressed as an integer number - // of MTB units, return that - return timing_val; - } - else - { - // Else round up and incorporate correction factor - return (++timing_val) + offset; - } + // Buffer used for bit manipulation + fapi2::buffer l_buffer(l_raw_byte); + + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), + BYTE_INDEX, + l_raw_byte); + + // Extracting desired bits + l_buffer.extractToRight(l_bit_fields); + + FAPI_TRY( mss::check::spd:: + fail_for_invalid_value(i_target, + (l_bit_fields != UNDEFINED), + BYTE_INDEX, + l_raw_byte, + "Failed check on SPD rev encoding level") ); + + // Update output only after check passes + o_value = l_bit_fields; + + // Print decoded info + FAPI_DBG("%s. Rev - Additions Level : %d", + c_str(i_target), + o_value); + +fapi_try_exit: + return fapi2::current_err; } /// -/// @brief Decodes SPD number of bytes -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data -/// size_t i_read_spd_size +/// @brief Decodes base module type (DIMM type) from SPD +/// @param[in] i_target +/// @param[in] i_spd_data PD blob +/// @param[out] o_value /// @return fapi2::ReturnCode -/// @note Decodes SPD Byte 0 +/// @note Decodes SPD Byte 3 (bits 0~3) +/// @note Item JC-45-2220.01x +/// @note Page 17 +/// @note DDR4 SPD Document Release 3 /// -fapi2::ReturnCode decoder::number_of_bytes(const fapi2::Target& i_target_dimm, +fapi2::ReturnCode decoder::base_module_type(const fapi2::Target& i_target, const uint8_t* i_spd_data, - const size_t i_read_spd_size) + uint8_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX = 0; + constexpr size_t BYTE_INDEX = 3; + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 0; - // SPD Bytes used mapping limits - const size_t BYTES_USED_MAP_OFFSET = 1; - const size_t BYTES_USED_MIN_VALID_KEY = 1; // All previous keys are not supported or reserved - const size_t BYTES_USED_MAX_VALID_KEY = 4; // The rest are not supported or reserved + // Buffer used for bit manipulation + fapi2::buffer l_spd_buffer(l_raw_byte); - // Total SPD bytes mapping limits - const size_t BYTES_TOTAL_MAP_OFFSET = 1; - const size_t BYTES_TOTAL_MIN_VALID_KEY = 1; // All previous keys are not supported or reserved - const size_t BYTES_TOTAL_MAX_VALID_KEY = 2; // The rest are not supported or reserved + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX", + c_str(i_target), + BYTE_INDEX, + l_raw_byte); - // Byte variables used for decoding - uint8_t l_spd_bytes_used = 0; - uint8_t l_spd_bytes_total = 0; - uint8_t l_reserved = 0; - uint16_t l_total_bytes_map_val = 0; - uint16_t l_used_bytes_map_val = 0; + // Extracting desired bits + l_spd_buffer.extractToRight(l_field_bits); - // Buffers used for bit manipulation - fapi2::buffer l_spd_buffer(i_spd_data[BYTE_INDEX]); + FAPI_DBG("Field_Bits value: %d", l_field_bits); - // Trace in the front assists w/ debug - FAPI_INF("%s SPD data at Byte 0: 0x%llX.", - mss::c_str(i_target_dimm), - i_spd_data[BYTE_INDEX]); + FAPI_TRY( mss::check::spd:: + fail_for_invalid_value(i_target, + mss::find_value_from_key(BASE_MODULE_TYPE_MAP, l_field_bits, o_value), + BYTE_INDEX, + l_field_bits, + "Failed check on Base Module Type") ); - // Decoding 1st nibble, bits 3~0 (SPD Bytes Used) - l_spd_buffer.extractToRight(l_spd_bytes_used); - - // Check to assure SPD Bytes Used (map) wont be at invalid values - FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm, - (l_spd_bytes_used >= BYTES_USED_MIN_VALID_KEY) && - (l_spd_bytes_used <= BYTES_USED_MAX_VALID_KEY), - BYTE_INDEX, - l_spd_bytes_used, - "Failed check on Used SPD bytes") ); - - // Decoding bits 6~4 (SPD Bytes Total) - l_spd_buffer.extractToRight(l_spd_bytes_total); - - // Check to assure SPD Bytes Total (map) wont be at invalid values - FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm, - (l_spd_bytes_total >= BYTES_TOTAL_MIN_VALID_KEY) && - (l_spd_bytes_total <= BYTES_TOTAL_MAX_VALID_KEY), - BYTE_INDEX, - l_spd_bytes_total, - "Failed check on total SPD bytes" ) ); - - // Decoding bit 7 (Reserved bit) - l_spd_buffer.extractToRight(l_reserved); - - // Hold map values in temp variables - l_used_bytes_map_val = bytes_used_map[l_spd_bytes_used - BYTES_USED_MAP_OFFSET]; - l_total_bytes_map_val = bytes_total_map[l_spd_bytes_total - BYTES_TOTAL_MAP_OFFSET]; - - // Size of input SPD read should match size it claims to be based on the SPD spec - // "Used SPD bytes" wasn't used since manufacturers may not use all available bytes - FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm, - l_total_bytes_map_val == i_read_spd_size, - BYTE_INDEX, - l_total_bytes_map_val, - "Failed SPD size check") ); - - FAPI_INF("%s. Bytes Used: %d, Total Bytes: %d, Reserved : %d", - mss::c_str(i_target_dimm), - l_used_bytes_map_val, - l_total_bytes_map_val, - l_reserved); + FAPI_DBG("%s. Base Module Type: %d", + mss::c_str(i_target), + o_value); fapi_try_exit: return fapi2::current_err; } /// -/// @brief Decodes SPD Revision -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data -/// @param[in, out] uint8_t io_revision_num -/// @return fapi2::ReturnCode -/// @note Decodes SPD Byte 1 +/// @brief Object factory to select correct decoder based on SPD revision & dimm type +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value shared pointer to the factory object +/// @return fapi2::ReturnCode /// -fapi2::ReturnCode decoder::revision(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::factory(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + std::shared_ptr& o_value) { - // Immutable constants - const size_t BYTE_INDEX = 1; - const size_t UNDEFINED = 0xFF; // per JEDEC spec + uint8_t l_dimm_type = 0; + uint8_t l_encoding_rev = 0; + uint8_t l_additions_rev = 0; + + // Get dimm type & revision levels + FAPI_TRY(base_module_type(i_target, i_spd_data, l_dimm_type)); + FAPI_TRY(rev_encoding_level(i_target, i_spd_data, l_encoding_rev)); + FAPI_TRY(rev_additions_level(i_target, i_spd_data, l_additions_rev)); - // Byte variables used for decoding - uint8_t l_revision_num = 0; + // Get decoder object needed for current dimm type and spd rev + switch(l_dimm_type) + { + // Each dimm type rev is independent + case fapi2::ENUM_ATTR_EFF_DIMM_TYPE_RDIMM: + + // SPD Revision format #.# + // 1st # = encoding level + // 2nd # = additions level + switch(l_encoding_rev) + { + case 1: + switch(l_additions_rev) + { + case 0: + case 1: + o_value = std::make_shared(); + break; + + default: + FAPI_TRY( mss::check::spd:: + invalid_factory_sel(i_target, + l_dimm_type, + l_encoding_rev, + l_additions_rev, + "Additions Level Unsupported!") ); + break; + }//end additions + + break; + + default: + FAPI_TRY( mss::check::spd:: + invalid_factory_sel(i_target, + l_dimm_type, + l_encoding_rev, + l_additions_rev, + "Encoding Level Unsupported!") ); + break; + }// end encodings - // Verify SPD revision is not undefined. Value is defined by the JEDEC spec - l_revision_num = i_spd_data[BYTE_INDEX]; + break; - FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm, - (l_revision_num != UNDEFINED), - BYTE_INDEX, - l_revision_num, - "Failed check on SPD revision") ); - // Print decoded info - FAPI_INF("%s. SPD data at Byte %d: 0x%llX, Revision number : %d", - c_str(i_target_dimm), - BYTE_INDEX, - i_spd_data[BYTE_INDEX], - l_revision_num); + default: + FAPI_TRY( mss::check::spd:: + invalid_factory_sel(i_target, + l_dimm_type, + l_encoding_rev, + l_additions_rev, + "DIMM Type Unsupported!") ); + break; + + } // end dimm type fapi_try_exit: return fapi2::current_err; + } + +///////////////////////// +// Member Method implementation +///////////////////////// + /// -/// @brief Decodes DRAM Device Type -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data +/// @brief Decodes number of used SPD bytes +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value number of SPD bytes used /// @return fapi2::ReturnCode -/// @note Decodes SPD Byte 2 +/// @note Decodes SPD Byte 0 bits(0~3) +/// @note Item JC-45-2220.01x +/// @note Page 14 +/// @note DDR4 SPD Document Release 3 /// -fapi2::ReturnCode decoder::dram_device_type(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::number_of_used_bytes(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint16_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX = 2; - - // dram generation mapping limits - const size_t MIN_VALID_KEY = 12; // All previous keys are not supported or reserved - const size_t MAX_VALID_KEY = 13; // The rest are not supported or reserved - const size_t MAP_OFFSET = 11; // SPD DRAM device type map has an index offset of 11 (simplifies array) - // //since initial map values are not supported or reserved (ignored for now) + constexpr size_t BYTE_INDEX = 0; + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 0; + uint16_t l_map_value = 0; - // Targets - const auto l_target_mcs = find_target(i_target_dimm); - const auto l_target_port = find_target(i_target_dimm); - - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); - - // Byte variables used for decoding - uint8_t l_device_type = 0; - - // Attribute variables used to set decoded vals - uint8_t l_device_gen[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + // Buffers used for bit manipulation + fapi2::buffer l_spd_buffer(l_raw_byte); - // Check to assure SPD DRAM device type (map) wont be at invalid values - l_device_type = i_spd_data[BYTE_INDEX]; + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), + BYTE_INDEX, + l_raw_byte); - FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm, - (l_device_type >= MIN_VALID_KEY) && - (l_device_type <= MAX_VALID_KEY), - BYTE_INDEX, - l_device_type, - "Unsupported/reserved key value retried from SPD") ); + // Extracting desired bits + l_spd_buffer.extractToRight(l_field_bits); - // Retrive entire MCS level attribute - FAPI_TRY(eff_dram_gen(l_target_mcs, &l_device_gen[0][0])); + FAPI_DBG("Field_Bits value: %d", l_field_bits); - // Update attribute to decoded byte values - l_device_gen[PORT_NUM][DIMM_NUM] = dram_gen_map[l_device_type - MAP_OFFSET]; + FAPI_TRY( mss::check::spd:: + fail_for_invalid_value(i_target, + mss::find_value_from_key(BYTES_USED_MAP, l_field_bits, l_map_value), + BYTE_INDEX, + l_map_value, + "Failed check on SPD total bytes") ); - // Update MCS level attribute - FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_GEN, l_target_mcs, l_device_gen)); + // Don't update output with garbage data until until all tests pass + o_value = l_map_value; - // Print decoded info - FAPI_INF("%s SPD data at Byte %d: 0x%llX. Device type : %d", - c_str(i_target_dimm), - BYTE_INDEX, - i_spd_data[BYTE_INDEX], - l_device_gen[PORT_NUM][DIMM_NUM]); + FAPI_DBG("%s. Bytes Used: %d", + mss::c_str(i_target), + o_value); fapi_try_exit: return fapi2::current_err; - } /// -/// @brief Decodes SPD module type -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data +/// @brief Decodes total number of SPD bytes +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value number of total SPD bytes /// @return fapi2::ReturnCode -/// @note Decodes SPD Byte 3 +/// @note Decodes SPD Byte 0 (bits 4~6) +/// @note Item JC-45-2220.01x +/// @note Page 14 +/// @note DDR4 SPD Document Release 3 /// -fapi2::ReturnCode decoder::module_type(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::number_of_total_bytes(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint16_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX = 3; + constexpr size_t BYTE_INDEX = 0; + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 0; + + // Buffer used for bit manipulation + fapi2::buffer l_spd_buffer(l_raw_byte); - // Base module mapping limits // since first index is not supported - const size_t BASE_MODULE_MAP_OFFSET = 1; // base_module_type_map has an index offset of 1 - const size_t MIN_VALID_KEY = 1; // All previous keys are not supported or reserved - const size_t MAX_VALID_KEY = 4; // The rest are not supported or reserved + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), + BYTE_INDEX, + l_raw_byte); - // Hybrid Media limit - const size_t MAX_HYBRID_MEDIA_KEY = 1; // All other key values reserved + // Extracting desired bits + l_spd_buffer.extractToRight(l_field_bits); - // Hybrid - const size_t MAX_HYBRID_KEY = 1; // Nothing else exits afterwards + FAPI_DBG("Field_Bits value: %d", l_field_bits); - // Targets - const auto l_target_mcs = find_target(i_target_dimm); - const auto l_target_port = find_target(i_target_dimm); + FAPI_TRY( mss::check::spd:: + fail_for_invalid_value(i_target, + mss::find_value_from_key(BYTES_TOTAL_MAP, l_field_bits, o_value), + BYTE_INDEX, + l_field_bits, + "Failed check on SPD total bytes") ); - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); + FAPI_DBG("%s. Total Bytes: %d", + mss::c_str(i_target), + o_value); - // Byte variables used for decoding - uint8_t l_base_module_type = 0; - uint8_t l_hybrid_media = 0; - uint8_t l_hybrid = 0; +fapi_try_exit: + return fapi2::current_err; +} - // Attribute variables used to set decoded vals - uint8_t l_module_type[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; +/// +/// @brief Decodes DRAM Device Type +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value dram device type enumeration +/// @return fapi2::ReturnCode +/// @note Decodes SPD Byte 2 +/// @note Item JC-45-2220.01x +/// @note Page 16 +/// @note DDR4 SPD Document Release 3 +/// +fapi2::ReturnCode decoder::dram_device_type(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value) +{ - // Buffer used for bit manipulation - fapi2::buffer l_spd_buffer(i_spd_data[BYTE_INDEX]); + constexpr size_t BYTE_INDEX = 2; + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; // Trace in the front assists w/ debug - // Trace print in the front assists w/ debug - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), BYTE_INDEX, - i_spd_data[BYTE_INDEX]); + l_raw_byte); + + FAPI_TRY( mss::check::spd:: + fail_for_invalid_value(i_target, + mss::find_value_from_key(DRAM_GEN_MAP, l_raw_byte, o_value), + BYTE_INDEX, + l_raw_byte, + "Failed check on SPD dram device type") ); - // Decoding bits 3~0 - l_spd_buffer.extractToRight(l_base_module_type); + // Print decoded info + FAPI_DBG("%s Device type : %d", + c_str(i_target), + o_value); - // Check to assure SPD DRAM base module type (map) wont be at invalid values - FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm, - (l_base_module_type >= MIN_VALID_KEY) && - (l_base_module_type <= MAX_VALID_KEY), - BYTE_INDEX, - l_base_module_type, - "Failed check for SPD DRAM base module type") ); +fapi_try_exit: + return fapi2::current_err; +} - // Decoding bits 6~4 - l_spd_buffer.extractToRight(l_hybrid_media); +/// +/// @brief Decodes hybrid media field from SPD +/// @param[in] i_target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value enum representing hybrid memory type +/// @return fapi2::ReturnCode +/// @note Decodes SPD Byte 3 (bits 4~6) +/// @note Item JC-45-2220.01x +/// @note Page 17 +/// @note DDR4 SPD Document Release 3 +/// +fapi2::ReturnCode decoder::hybrid_media(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value) - // Check to assure SPD DRAM hybrid media is valid - FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm, - l_hybrid_media <= MAX_HYBRID_MEDIA_KEY, - BYTE_INDEX, - l_hybrid_media, - "Failed check for SPD DRAM hybrid media") ); +{ + constexpr size_t BYTE_INDEX = 3; + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 0; - // Decoding bit 7 - l_spd_buffer.extractToRight(l_hybrid); + // Buffer used for bit manipulation + fapi2::buffer l_spd_buffer(l_raw_byte); + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), + BYTE_INDEX, + l_raw_byte); - // Check to assure SPD DRAM hybrid media is valid - FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm, - l_hybrid_media <= MAX_HYBRID_KEY, - BYTE_INDEX, - l_hybrid, - "Failed check for SPD DRAM hybrid media") ); - // Retrive entire MCS level attribute - FAPI_TRY(spd_module_type(l_target_mcs, &l_module_type[0][0])); + // Extracting desired bits + l_spd_buffer.extractToRight(l_field_bits); - // Update attribute to decoded byte values - l_module_type[PORT_NUM][DIMM_NUM] = base_module_type_map[l_base_module_type - BASE_MODULE_MAP_OFFSET]; + FAPI_DBG("Field_Bits value: %d", l_field_bits); - // Update MCS level attribute - FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_SPD_MODULE_TYPE, l_target_mcs, l_module_type)); + FAPI_TRY( mss::check::spd:: + fail_for_invalid_value(i_target, + mss::find_value_from_key(HYBRID_MEDIA_MAP, l_field_bits, o_value), + BYTE_INDEX, + l_field_bits, + "Failed check on Hybrid Media type") ); - FAPI_INF("%s. Base Module Type: %d, Hybrid Media: %d, Hybrid: %d", - c_str(i_target_dimm), - l_module_type[PORT_NUM][DIMM_NUM], - l_hybrid_media, - l_hybrid); + FAPI_DBG("%s. Hybrid Media: %d", + mss::c_str(i_target), + o_value); fapi_try_exit: return fapi2::current_err; } /// -/// @brief Decode SDRAM density -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data +/// @brief Decodes hybrid field from SPD +/// @param[in] i_target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value enum representing if module is hybrid /// @return fapi2::ReturnCode -/// @note SPD Byte 4 +/// @note Decodes SPD Byte 3 (bit 7) +/// @note Item JC-45-2220.01x +/// @note Page 17 +/// @note DDR4 SPD Document Release 3 /// -fapi2::ReturnCode decoder::sdram_density(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::hybrid(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX = 4; + constexpr size_t BYTE_INDEX = 3; + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 0; + + // Buffer used for bit manipulation + fapi2::buffer l_spd_buffer(l_raw_byte); + + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), + BYTE_INDEX, + l_raw_byte); - // DRAM capacity mapping limits - const size_t CAPACITY_MAP_OFFSET = 1; // base_module_type_map has an index offset of 1 - const size_t CAPACITY_MIN_VALID_KEY = 2; // All previous keys are not supported or reserved - const size_t CAPACITY_MAX_VALID_KEY = 9; // The rest are not supported or reserved + // Extracting desired bits + l_spd_buffer.extractToRight(l_field_bits); - // DRAM banks mapping limits - const size_t BANKS_MAX_VALID_KEY = 1; // The rest are not supported or reserved + FAPI_DBG("Field_Bits value: %d", l_field_bits); - // DRAM bank groups mapping limits - const size_t BANK_GRP_MAX_VALID_KEY = 2; // The rest are not supported or reserved + FAPI_TRY( mss::check::spd:: + fail_for_invalid_value(i_target, + mss::find_value_from_key(HYBRID_MAP, l_field_bits, o_value), + BYTE_INDEX, + l_field_bits, + "Failed check on hybrid field") ); - // Targets - const auto l_target_mcs = find_target(i_target_dimm); - const auto l_target_port = find_target(i_target_dimm); + FAPI_DBG("%s. Hybrid: %d", + mss::c_str(i_target), + o_value); + +fapi_try_exit: + return fapi2::current_err; +} - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); +/// +/// @brief Decodes SDRAM density from SPD +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value SDRAM density in GBs +/// @return fapi2::ReturnCode +/// @note SPD Byte 4 (bits 0~3) +/// @note Item JC-45-2220.01x +/// @note Page 18 +/// @note DDR4 SPD Document Release 3 +/// +fapi2::ReturnCode decoder::sdram_density(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value) - // Byte variables used for decoding - uint8_t l_sdram_capacity = 0; - uint8_t l_sdram_banks = 0; - uint8_t l_sdram_bank_group = 0; +{ - // Attribute variables used to set decoded vals - uint8_t l_capacities[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; - uint8_t l_banks[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; - uint8_t l_bank_groups[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + constexpr size_t BYTE_INDEX = 4; + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 0; // Buffer used for bit manipulation fapi2::buffer l_spd_buffer(i_spd_data[BYTE_INDEX]); // Trace in the front assists w/ debug - // Trace print in the front assists w/ debug - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), BYTE_INDEX, - i_spd_data[BYTE_INDEX]); + l_raw_byte); - // Decoding bits 3~0 - l_spd_buffer.extractToRight(l_sdram_capacity); + // Extracting desired bits + l_spd_buffer.extractToRight(l_field_bits); // Check to assure SPD DRAM capacity (map) wont be at invalid values - FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm, - (l_sdram_capacity >= CAPACITY_MIN_VALID_KEY) && - (l_sdram_capacity <= CAPACITY_MAX_VALID_KEY), - BYTE_INDEX, - l_sdram_capacity, - "Failed check for SPD DRAM capacity") ); - // Decoding bits 5~4 - l_spd_buffer.extractToRight(l_sdram_banks); - - // Check to assure SPD DRAM banks (map) wont be at invalid values - FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm, - (l_sdram_banks <= BANKS_MAX_VALID_KEY), - BYTE_INDEX, - l_sdram_banks, - "Failed check for SPD DRAM banks") ); - - // Decoding bits 7~6 - l_spd_buffer.extractToRight(l_sdram_bank_group); - - // Check to assure SPD DRAM banks groups (map) wont be at invalid values - FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm, - (l_sdram_bank_group <= BANK_GRP_MAX_VALID_KEY), - BYTE_INDEX, - l_sdram_bank_group, - "Failed check for SPD DRAM bank groups") ); - - // Retrive entire MCS level attribute - FAPI_TRY( eff_dram_density(l_target_mcs, &l_capacities[0][0]) ); - FAPI_TRY( eff_dram_banks(l_target_mcs, &l_banks[0][0]) ); - FAPI_TRY( eff_dram_bank_groups(l_target_mcs, &l_bank_groups[0][0]) ); - - // Update attribute to decoded byte values - l_capacities[PORT_NUM][DIMM_NUM] = sdram_capacity_map[l_sdram_capacity - CAPACITY_MAP_OFFSET]; - l_banks[PORT_NUM][DIMM_NUM] = sdram_banks_map[l_sdram_banks]; - l_bank_groups[PORT_NUM][DIMM_NUM] = sdram_bankgroups_map[l_sdram_bank_group]; - - // Update MCS level attribute - FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_DENSITY, l_target_mcs, l_capacities)); - FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_BANKS, l_target_mcs, l_banks)); - FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_BANK_GROUPS, l_target_mcs, l_bank_groups)); - - FAPI_INF("%s. SDRAM capacity: %d, banks: %d, bank groups: %d", - c_str(i_target_dimm), - sdram_capacity_map[l_sdram_capacity], - sdram_banks_map[l_sdram_banks], - sdram_bankgroups_map[l_sdram_bank_group]); + FAPI_TRY( mss::check::spd:: + fail_for_invalid_value(i_target, + mss::find_value_from_key(SDRAM_DENSITY_MAP, l_field_bits, o_value), + BYTE_INDEX, + l_field_bits, + "Failed check for SPD DRAM capacity") ); + + FAPI_DBG("%s. SDRAM density: %d", + mss::c_str(i_target), + o_value); fapi_try_exit: return fapi2::current_err; } /// -/// @brief Decode SDRAM addressing -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data +/// @brief Decodes number of SDRAM banks from SPD +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value Number of SDRAM banks /// @return fapi2::ReturnCode -/// @note SPD Byte 5 +/// @note SPD Byte 4 (bits 4~5) +/// @note Item JC-45-2220.01x +/// @note Page 18 +/// @note DDR4 SPD Document Release 3 /// -fapi2::ReturnCode decoder::sdram_addressing(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) -{ - // Immutable constants - const size_t BYTE_INDEX = 5; - // DRAM column address mapping limits - const size_t COLUMN_MAX_VALID_KEY = 3; // The rest are not supported or reserved - // DRAM row address mapping limits - const size_t ROW_MAX_VALID_KEY = 6; // The rest are not supported or reserved - - // Targets - const auto l_target_mcs = find_target(i_target_dimm); - const auto l_target_port = find_target(i_target_dimm); +fapi2::ReturnCode decoder::banks(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value) - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); - - // Byte variables used for decoding - uint8_t l_column_addr = 0; - uint8_t l_row_addr = 0; - uint8_t l_reserved = 0; +{ - // Attribute variables used to set decoded vals - uint8_t l_columns[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; - uint8_t l_rows[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + constexpr size_t BYTE_INDEX = 4; + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 0; // Buffer used for bit manipulation fapi2::buffer l_spd_buffer(i_spd_data[BYTE_INDEX]); // Trace in the front assists w/ debug - // Trace print in the front assists w/ debug - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), BYTE_INDEX, - i_spd_data[BYTE_INDEX]); + l_raw_byte); - // Decoding bits 2~0 (Column Address bits) - l_spd_buffer.extractToRight(l_column_addr); + // Extracting desired bits + l_spd_buffer.extractToRight(l_field_bits); - // Check to assure SPD DRAM Column Address bits (map) wont be indexed at invalid values - FAPI_TRY(mss::check::spd::valid_value_fail(i_target_dimm, - (l_column_addr <= COLUMN_MAX_VALID_KEY), - BYTE_INDEX, - l_column_addr, - "Failed check for SPD DRAM bank groups") ); - - // Decoding bits 3~0 (Row address bits) - l_spd_buffer.extractToRight(l_row_addr); - - // Check to assure SPD DRAM Row address bits (map) wont be at invalid values - FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm, - (l_row_addr <= ROW_MAX_VALID_KEY), - BYTE_INDEX, - l_row_addr, - "Failed check for SPD DRAM bank groups") ); - - // Decoding bits 7~6 - l_spd_buffer.extractToRight(l_reserved); - - // Check to assure SPD reserved bits are 0 as defined in JEDEC SPD spec - FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm, - (l_reserved == 0), - BYTE_INDEX, - l_reserved, - "Failed check for SPD DRAM bank groups") ); - - // Retrive entire MCS level attribute - FAPI_TRY( eff_dram_cols(l_target_mcs, &l_columns[0][0]) ); - FAPI_TRY( eff_dram_rows(l_target_mcs, &l_rows[0][0]) ); - - // Update attribute to decoded byte values - l_columns[PORT_NUM][DIMM_NUM] = column_address_map[l_column_addr]; - l_rows[PORT_NUM][DIMM_NUM] = row_address_map[l_row_addr]; - - // Update MCS level attribute - FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_COLS, l_target_mcs, l_columns)); - FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_ROWS, l_target_mcs, l_rows)); - - FAPI_INF("%s. Columns: %d, Rows: %d", - c_str(i_target_dimm), - l_columns[PORT_NUM][DIMM_NUM], - l_rows[PORT_NUM][DIMM_NUM]); + // Check to assure SPD DRAM capacity (map) wont be at invalid values + FAPI_TRY( mss::check::spd:: + fail_for_invalid_value(i_target, + mss::find_value_from_key(BANK_ADDR_BITS_MAP, l_field_bits, o_value), + BYTE_INDEX, + l_field_bits, + "Failed check for SPD DRAM banks") ); + + FAPI_DBG("%s. Banks: %d", + mss::c_str(i_target), + o_value); fapi_try_exit: return fapi2::current_err; } - /// -/// @brief Decode SDRAM Package Type -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data +/// @brief Decodes number of SDRAM bank groups from SPD +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value Number of SDRAM bank groups /// @return fapi2::ReturnCode -/// @note SPD Byte 6 +/// @note SPD Byte 4 (bits 6~7) +/// @note Item JC-45-2220.01x +/// @note Page 18 +/// @note DDR4 SPD Document Release 3 /// -fapi2::ReturnCode decoder::primary_package_type(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::bank_groups(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX = 6; - const size_t INVALID_VALUE = 0x11; //per JEDEC spec - const size_t RESERVED = 0; - - // DRAM die count mapping limits - const size_t DIE_COUNT_MAX_VALID_KEY = 7; // Nothing greater doesn't exist - const size_t INVALID_PACKAGE_TYPE = ~0; - - // Targets - const auto l_target_mcs = find_target(i_target_dimm); - const auto l_target_port = find_target(i_target_dimm); - - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); - - // Byte variables used for decoding - uint8_t l_prim_signal_loading = 0; - uint8_t l_reserved = 0; - uint8_t l_prim_die_count = 0; - uint8_t l_prim_package_type = 0; - // Attribute variables used to set decoded vals - uint8_t l_stack_type = 0; - uint8_t l_sdram_package_type[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; - uint8_t l_sdram_die_count[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + constexpr size_t BYTE_INDEX = 4; + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 0; // Buffer used for bit manipulation fapi2::buffer l_spd_buffer(i_spd_data[BYTE_INDEX]); - // Trace print in the front assists w/ debug - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), BYTE_INDEX, - i_spd_data[BYTE_INDEX]); + l_raw_byte); + + // Extracting desired bits + l_spd_buffer.extractToRight(l_field_bits); - // Decoding bits 1~0 (Signal loading) - l_spd_buffer.extractToRight(l_prim_signal_loading); - - // Check to assure SPD DRAM signal loading conforms to JEDEC SPEC - FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm, - (l_prim_signal_loading != INVALID_VALUE), - BYTE_INDEX, - l_prim_signal_loading, - "Failed check for SPD DRAM signal loading") ); - // Decoding bits 3~2 (Reserved) - l_spd_buffer.extractToRight(l_reserved); - - // Check to assure SPD reserved bits are 0 as defined in JEDEC SPD spec - mss::check::spd::valid_value_warn(i_target_dimm, - (l_reserved == RESERVED), - BYTE_INDEX, - l_reserved, - "Failed check for SPD DRAM reserved bits"); - - // Decoding bits 6~4 (Die Count) - l_spd_buffer.extractToRight(l_prim_die_count); - - FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm, - (l_prim_die_count <= DIE_COUNT_MAX_VALID_KEY), - BYTE_INDEX, - l_prim_die_count, - "Failed check for SPD DRAM die count") ); - // Decoding bit 7 - l_spd_buffer.extractToRight(l_prim_package_type); - - // Manipulating and combining l_prim_package_type and l_prim_signal_loading to produce the following - // table for indexing the package_type_map[]. - // 0000 0000 = SDP (monolithic device) - // 0000 0101 = DDP/QDP (non-monolithic device) - // 0000 0110 = 3DS (non-monolithic device) - // What this essentially does is remove reserved bits. - // This was done to avoid having large gaps (of 0's) in the package_type_map (sparsed array) - // since we can't use std::map due to thread saftey issues - l_stack_type = (l_prim_package_type >> 5) | l_prim_signal_loading; - - FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm, - check::stack_type(l_stack_type, die_count_map[l_prim_die_count]) && - (package_type_map[l_stack_type] != INVALID_PACKAGE_TYPE), - BYTE_INDEX, - package_type_map[l_stack_type], - "Failed check for SPD DRAM stack type") ); - - // Retrive entire MCS level attribute - FAPI_TRY( eff_stack_type(l_target_mcs, &l_sdram_package_type[0][0]) ); - FAPI_TRY( eff_prim_die_count(l_target_mcs, &l_sdram_die_count[0][0]) ); - - // Update attribute to decoded byte values - l_sdram_die_count[PORT_NUM][DIMM_NUM] = die_count_map[l_prim_die_count]; - l_sdram_package_type[PORT_NUM][DIMM_NUM] = package_type_map[l_stack_type]; - - // Update MCS level attribute - FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_STACK_TYPE, l_target_mcs, l_sdram_package_type)); - FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_PRIM_DIE_COUNT, l_target_mcs, l_sdram_die_count)); - - FAPI_INF("%s. Signal loading: %d, Die count: %d, Stack type: %d", - c_str(i_target_dimm), - l_prim_signal_loading, - die_count_map[l_prim_die_count], - l_sdram_package_type[PORT_NUM][DIMM_NUM]); + // Check to assure SPD DRAM capacity (map) wont be at invalid values + FAPI_TRY( mss::check::spd:: + fail_for_invalid_value(i_target, + mss::find_value_from_key(BANK_GROUP_BITS_MAP, l_field_bits, o_value), + BYTE_INDEX, + l_field_bits, + "Failed check for SPD DRAM bank groups") ); + + FAPI_DBG("%s. Bank Groups: %d", + mss::c_str(i_target), + o_value); fapi_try_exit: return fapi2::current_err; } -//TODO -// Need to complete this function, map need tREF1 calculations - /// -/// @brief Decode SDRAM Optional Features -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data +/// @brief Decodes number of SDRAM column address bits +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value number of column address bits /// @return fapi2::ReturnCode -/// @note SPD Byte 7 +/// @note SPD Byte 5 (bits 2~0) +/// @note Item JC-45-2220.01x +/// @note Page 18 +/// @note DDR4 SPD Document Release 3 /// -fapi2::ReturnCode decoder::sdram_optional_features(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::column_address_bits(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX = 7; - const size_t RESERVED = 0; - // MAC mapping limits - const size_t MAC_RESERVED = 7; //per JEDEC spec - const size_t MAC_MAX_VALID_KEY = 8; - - // TMAW mappint limits - const size_t TMAW_MAX_VALID_KEY = 2; - - // Targets - const auto l_target_mcs = find_target(i_target_dimm); - const auto l_target_port = find_target(i_target_dimm); - - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); - - // Byte variables used for decoding - uint16_t l_MAC = 0; // Maximum Active Count - uint16_t l_tMAW = 0; // Maximum Active Window - uint8_t l_reserved = 0; - - // Attribute variables used to set decoded vals - uint16_t l_mac[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; - uint16_t l_tmaw[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + constexpr size_t BYTE_INDEX = 5; + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 0; // Buffer used for bit manipulation fapi2::buffer l_spd_buffer(i_spd_data[BYTE_INDEX]); - // Trace print in the front assists w/ debug - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), BYTE_INDEX, - i_spd_data[BYTE_INDEX]); + l_raw_byte); - // Decoding bits 3~0 (MAC) - l_spd_buffer.extractToRight(l_MAC); - // Check to assure SPD DRAM signal loading conforms to JEDEC SPEC - FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm, - (l_MAC <= MAC_MAX_VALID_KEY) && - l_MAC != MAC_RESERVED, - BYTE_INDEX, - l_MAC, - "Failed check for Maximum Active Count (MAC)") ); - - // Decoding bits 5~4 (tMAW) - l_spd_buffer.extractToRight(l_tMAW); - - // Check to assure SPD DRAM signal loading conforms to JEDEC SPEC - FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm, - (l_tMAW <= TMAW_MAX_VALID_KEY), - BYTE_INDEX, - l_tMAW, - "Failed check for Maximum Active Window (tMAW)") ); - - // Decoding bits 7~6 (Reserved) - l_spd_buffer.extractToRight(l_reserved); - - mss::check::spd::valid_value_warn(i_target_dimm, - (l_reserved == RESERVED), - BYTE_INDEX, - l_reserved, - "Failed check for Reserved bits") ; - - // Retrive entire MCS level attribute - FAPI_TRY(eff_dram_mac(l_target_mcs, &l_mac[0][0])); - FAPI_TRY(eff_dram_tmaw(l_target_mcs, &l_tmaw[0][0])); - - // Update attribute to decoded byte values - l_mac[PORT_NUM][DIMM_NUM] = MAC_map[l_MAC]; - l_tmaw[PORT_NUM][DIMM_NUM] = tMAW_map[l_tMAW]; - - // Update MCS level attribute - FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_MAC, l_target_mcs, l_mac)); - FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_TMAW, l_target_mcs, l_tmaw)); + // Extracting desired bits + l_spd_buffer.extractToRight(l_field_bits); - // Print decoded info - FAPI_INF("%s. MAC: %d, tMAW: %d", - c_str(i_target_dimm), - l_tmaw[PORT_NUM][DIMM_NUM], - l_mac[PORT_NUM][DIMM_NUM]); + // Check to assure SPD DRAM capacity (map) wont be at invalid values + FAPI_TRY( mss::check::spd:: + fail_for_invalid_value(i_target, + mss::find_value_from_key(COLUMN_ADDRESS_BITS_MAP, l_field_bits, o_value), + BYTE_INDEX, + l_field_bits, + "Failed check for SDRAM Column Address Bits") ); + + FAPI_DBG("%s. Number of Column Address Bits: %d", + mss::c_str(i_target), + o_value); fapi_try_exit: return fapi2::current_err; -}// decode_sdram_optional_features() +} /// -/// @brief Decode SDRAM Thermal and Refresh Options -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data +/// @brief Decodes number of SDRAM row address bits +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value number of row address bits /// @return fapi2::ReturnCode -/// @note SPD Byte 8, currently reserved +/// @note SPD Byte 5 (bits 5~3) +/// @note Item JC-45-2220.01x +/// @note Page 18 +/// @note DDR4 SPD Document Release 3 /// -fapi2::ReturnCode decoder::thermal_and_refresh_options(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::row_address_bits(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX = 8; - const size_t RESERVED_BYTE = 0; // per JEDEC spec - // Byte variable - uint8_t l_reserved = i_spd_data[BYTE_INDEX]; + constexpr size_t BYTE_INDEX = 5; + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 0; - // Check to assure SPD reserved byte is 0 per JEDEC spec - FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm, - (l_reserved == RESERVED_BYTE), - BYTE_INDEX, - l_reserved, - "Failed check for SPD DRAM reserved byte") ); + // Buffer used for bit manipulation + fapi2::buffer l_spd_buffer(i_spd_data[BYTE_INDEX]); - // Print decoded info - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), BYTE_INDEX, - i_spd_data[BYTE_INDEX]); + l_raw_byte); + + // Extracting desired bits + l_spd_buffer.extractToRight(l_field_bits); + + // Check to assure SPD DRAM capacity (map) wont be at invalid values + FAPI_TRY( mss::check::spd:: + fail_for_invalid_value(i_target, + mss::find_value_from_key(ROW_ADDRESS_BITS_MAP, l_field_bits, o_value), + BYTE_INDEX, + l_field_bits, + "Failed check for SDRAM Row Address Bits") ); + + FAPI_DBG("%s. Number of Row Address Bits: %d", + mss::c_str(i_target), + o_value); fapi_try_exit: return fapi2::current_err; -}// decode_thermal_and_refresh_options() +} /// -/// @brief Decode Other SDRAM Optional Features -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data +/// @brief Decodes Primary SDRAM signal loading +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value enum representing signal loading type /// @return fapi2::ReturnCode -/// @note SPD Byte 9 +/// @note SPD Byte 6 (bits 1~0) +/// @note Item JC-45-2220.01x +/// @note Page 19 +/// @note DDR4 SPD Document Release 3 /// -fapi2::ReturnCode decoder::other_optional_features(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::prim_sdram_signal_loading(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX = 9; - const size_t RESERVED = 0; - // Soft PPR mapping limits - const size_t SOFT_PPR_MAX_VALID_KEY = 2; // Nothing greater doesn't exist + constexpr size_t BYTE_INDEX = 5; + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 0; - // PPR mapping limits - const size_t PPR_MAX_VALID_KEY = 2; // Nothing greater doesn't exist - - // Targets - const auto l_target_mcs = find_target(i_target_dimm); - const auto l_target_port = find_target(i_target_dimm); - - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); - - // Byte variables used for decoding - uint8_t l_reserved = 0; - uint8_t l_soft_ppr = 0;// Soft Post Package Repair - uint8_t l_ppr = 0; // Post Package Repair - - // Attribute variables used to set decoded vals - uint8_t l_soft_PPRs[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; - uint8_t l_PPRs[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + // Buffer used for bit manipulation + fapi2::buffer l_spd_buffer(l_raw_byte); - // Trace print in the front assists w/ debug - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), BYTE_INDEX, - i_spd_data[BYTE_INDEX]); + l_raw_byte); - // Buffer used for bit manipulation - fapi2::buffer l_spd_buffer(i_spd_data[BYTE_INDEX]); + // Extracting desired bits + l_spd_buffer.extractToRight(l_field_bits); - // Decoding bits 4~0 - l_spd_buffer.extractToRight(l_reserved); + FAPI_TRY( mss::check::spd:: + fail_for_invalid_value(i_target, + mss::find_value_from_key(PRIM_SIGNAL_LOADING_MAP, l_field_bits, o_value), + BYTE_INDEX, + l_field_bits, + "Failed check for Primary SDRAM Signal Loading") ); - mss::check::spd::valid_value_warn(i_target_dimm, - (l_reserved == RESERVED), - BYTE_INDEX, - l_reserved, - "Failed check for reserved bits"); + FAPI_DBG("%s. Primary SDRAM Signal Loading: %d", + mss::c_str(i_target), + o_value); - // Decoding bit 5 - l_spd_buffer.extractToRight(l_soft_ppr); +fapi_try_exit: + return fapi2::current_err; +} - FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm, - (l_soft_ppr < SOFT_PPR_MAX_VALID_KEY), - BYTE_INDEX, - l_soft_ppr, - "Failed check for SOFT PPR") ); +/// +/// @brief Decodes Primary SDRAM die count +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value die count +/// @return fapi2::ReturnCode +/// @note SPD Byte 6 (bits 6~4) +/// @note Item JC-45-2220.01x +/// @note Page 19 +/// @note DDR4 SPD Document Release 3 +/// +fapi2::ReturnCode decoder::prim_sdram_die_count(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value) +{ - // Decoding bits 7~6 - l_spd_buffer.extractToRight(l_ppr); + constexpr size_t BYTE_INDEX = 5; + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 0; - FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm, - (l_ppr < PPR_MAX_VALID_KEY), - BYTE_INDEX, - l_ppr, - "Failed check for PPR") ); + // Buffer used for bit manipulation + fapi2::buffer l_spd_buffer(l_raw_byte); - // Retrive entire MCS level attribute - FAPI_TRY(eff_dram_soft_ppr(l_target_mcs, &l_soft_PPRs[0][0])); - FAPI_TRY(eff_dram_ppr(l_target_mcs, &l_PPRs[0][0])); + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), + BYTE_INDEX, + l_raw_byte); - // Update attribute to decoded byte values - l_soft_PPRs[PORT_NUM][DIMM_NUM] = soft_ppr_map[l_soft_ppr]; - l_PPRs[PORT_NUM][DIMM_NUM] = ppr_map[l_ppr]; + // Extracting desired bits + l_spd_buffer.extractToRight(l_field_bits); - // Update MCS level attribute - FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_SOFT_PPR, l_target_mcs, l_soft_PPRs)); - FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_PPR, l_target_mcs, l_PPRs)); + FAPI_TRY( mss::check::spd:: + fail_for_invalid_value(i_target, + mss::find_value_from_key(PRIM_DIE_COUNT_MAP, l_field_bits, o_value), + BYTE_INDEX, + l_field_bits, + "Failed check for SDRAM Row Address Bits") ); - // Printed decoded info - FAPI_INF("%s. Soft PPR: %d, PPR: %d, Reserved: %d", - c_str(i_target_dimm), - l_soft_PPRs[PORT_NUM][DIMM_NUM], - l_PPRs[PORT_NUM][DIMM_NUM], - l_reserved); + FAPI_DBG("%s. Number of Row Address Bits: %d", + mss::c_str(i_target), + o_value); fapi_try_exit: return fapi2::current_err; } /// -/// @brief Decode Secondary SDRAM Package Type -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data +/// @brief Decodes Primary SDRAM package type +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value enum representing package type /// @return fapi2::ReturnCode -/// @note SPD Byte 10 +/// @note SPD Byte 6 (bit 7) +/// @note Item JC-45-2220.01x +/// @note Page 19 +/// @note DDR4 SPD Document Release 3 /// -fapi2::ReturnCode decoder::secondary_package_type(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::prim_sdram_package_type(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX = 10; - const size_t SUPPORTED_VALUE = 0; - // Byte variables used for decoding - uint8_t l_sec_signal_loading = 0; - uint8_t l_density_ratio = 0; - uint8_t l_sec_die_count = 0; - uint8_t l_sec_package_type = 0; + constexpr size_t BYTE_INDEX = 5; + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 0; - // Trace print in the front assists w/ debug - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), + // Buffer used for bit manipulation + fapi2::buffer l_spd_buffer(l_raw_byte); + + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), BYTE_INDEX, - i_spd_data[BYTE_INDEX]); + l_raw_byte); - // Currently we do not support asymmetrical assembly of multiple SDRAM package types - // According to the JEDEC spec, for modules with symmetrical assembly (which we do support), - // this byte must be coded as 0x00. Additional checks were added to isolate any corrupt data failure + // Extracting desired bits + l_spd_buffer.extractToRight(l_field_bits); - // Buffer used for bit manipulation - fapi2::buffer l_spd_buffer(i_spd_data[BYTE_INDEX]); + FAPI_TRY( mss::check::spd:: + fail_for_invalid_value(i_target, + mss::find_value_from_key(PRIM_PACKAGE_TYPE_MAP, l_field_bits, o_value), + BYTE_INDEX, + l_field_bits, + "Failed check for SDRAM Row Address Bits") ); - // Decoding bits 1~0 (Signal loading) - l_spd_buffer.extractToRight(l_sec_signal_loading); - - // Check to assure SPD DRAM signal loading conforms to JEDEC SPEC - FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm, - (l_sec_signal_loading == SUPPORTED_VALUE), - BYTE_INDEX, - l_sec_signal_loading, - "Failed check for SPD DRAM signal loading") ); - - // Decoding bits 3~2 (Density Ratio) - l_spd_buffer.extractToRight(l_density_ratio); - - // Check to assure SPD density ratio bits are 0 to assure symmetical package - FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm, - (l_density_ratio == SUPPORTED_VALUE), - BYTE_INDEX, - l_density_ratio, - "Failed check for SPD DRAM density ratio") ); - - // Decoding bits 6~4 (Die Count) - l_spd_buffer.extractToRight(l_sec_die_count); - - FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm, - (l_sec_die_count == SUPPORTED_VALUE), - BYTE_INDEX, - l_sec_die_count, - "Failed check for SPD DRAM secondary die count") ); - - // Decoding bit 7 - l_spd_buffer.extractToRight(l_sec_package_type); - - FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm, - (l_sec_package_type == SUPPORTED_VALUE), - BYTE_INDEX, - l_sec_package_type, - "Failed check for SPD DRAM secondary package type") ); - - // Printed decoded info - FAPI_INF("Signal Loading: %d, DRAM Density Ratio: %d, Die Count: %d, SDRAM Package Type: %d", - l_sec_signal_loading, - l_density_ratio, - l_sec_die_count, - l_sec_package_type); + FAPI_DBG("%s. Number of Row Address Bits: %d", + mss::c_str(i_target), + o_value); fapi_try_exit: return fapi2::current_err; } + /// -/// @brief Decode Module Nominal Voltage, VDD -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data +/// @brief Decode SDRAM Maximum activate count +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value enum representing max activate count /// @return fapi2::ReturnCode -/// @note SPD Byte 11 +/// @note SPD Byte 7 (bits 3~0) +/// @note Item JC-45-2220.01x +/// @note Page 20 +/// @note DDR4 SPD Document Release 3 /// -fapi2::ReturnCode decoder::module_nominal_voltage(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::maximum_activate_count(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint32_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX = 11; - const size_t RESERVED = 0; // per JEDEC sepc - const size_t SUPPORTED = 1; // per JEDEC sepc - // Targets - const auto l_target_mcs = find_target(i_target_dimm); - const auto l_target_port = find_target(i_target_dimm); - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); + constexpr size_t BYTE_INDEX = 7; + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 0; - // Byte variables used for decoding - uint8_t l_operable = 0; - uint8_t l_endurant = 0; - uint8_t l_reserved = 0; - - // Attribute variables used to set decoded vals - uint64_t l_operable_attrs[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + // Buffer used for bit manipulation + fapi2::buffer l_spd_buffer(l_raw_byte); - // Trace print in the front assists w/ debug - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), BYTE_INDEX, - i_spd_data[BYTE_INDEX]); - - // Buffer used for bit manipulation - fapi2::buffer l_spd_buffer(i_spd_data[BYTE_INDEX]); + l_raw_byte); - // Decoding bits 0 (Operable) - l_spd_buffer.extractToRight(l_operable); + // Extracting desired bits + l_spd_buffer.extractToRight(l_field_bits); - // DDR4 only supports 1.2 V, if not OPERABLE at this voltage than fail IPL - FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm, - l_operable == SUPPORTED, - BYTE_INDEX, - l_operable, - "Failed check for OPERABLE module nominal voltage") ); - // Decoding bits 1 (Endurant) - l_spd_buffer.extractToRight(l_endurant); + FAPI_TRY( mss::check::spd:: + fail_for_invalid_value(i_target, + mss::find_value_from_key(MAC_MAP, l_field_bits, o_value), + BYTE_INDEX, + l_field_bits, + "Failed check for SDRAM Maximum Active Count (MAC)") ); - // OPERABLE at 1.2V implies ENDURANT at 1.2V - FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm, - l_endurant == SUPPORTED, - BYTE_INDEX, - l_endurant, - "Failed check for ENDURABLE module nominal voltage") ); + FAPI_DBG("%s. Maximum Active Count (MAC): %d", + mss::c_str(i_target), + o_value); - // Decoding bits 7~2 (Reserved) - l_spd_buffer.extractToRight(l_reserved); +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Decode SDRAM Maximum activate window (multiplier), tREFI uknown at this point +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value max activate window multiplier +/// @return fapi2::ReturnCode +/// @note SPD Byte 7 (bits 3~0) +/// @note Item JC-45-2220.01x +/// @note Page 20 +/// @note DDR4 SPD Document Release 3 +/// +fapi2::ReturnCode decoder::maximum_activate_window_multiplier(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint32_t& o_value) +{ - mss::check::spd::valid_value_warn(i_target_dimm, - l_reserved == RESERVED, - BYTE_INDEX, - l_reserved, - "Failed check for module nominal voltage RESERVED bits"); + constexpr size_t BYTE_INDEX = 7; + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 0; - // Retrive entire MCS level attribute - FAPI_TRY(spd_module_nominal_voltage(l_target_mcs, &l_operable_attrs[0][0])); + // Buffer used for bit manipulation + fapi2::buffer l_spd_buffer(l_raw_byte); - // Update attribute to decoded byte values - l_operable_attrs[PORT_NUM][DIMM_NUM] = l_operable; + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), + BYTE_INDEX, + l_raw_byte); - // Update MCS level attribute - FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_SPD_MODULE_NOMINAL_VOLTAGE, l_target_mcs, l_operable_attrs) ); + // Extracting desired bits + l_spd_buffer.extractToRight(l_field_bits); - // Printed decoded info - FAPI_INF( "%s Operable: %d, Endurant: %d, Reserved: %d", - c_str(i_target_dimm), - l_operable, - l_endurant, - l_reserved ); + FAPI_TRY( mss::check::spd:: + fail_for_invalid_value(i_target, + mss::find_value_from_key(TMAW_MAP, l_field_bits, o_value), + BYTE_INDEX, + l_field_bits, + "Failed check for Maximum Active Window (tMAW)") ); + FAPI_DBG("%s. Maximum Active Window multiplier: %d", + mss::c_str(i_target), + o_value); fapi_try_exit: return fapi2::current_err; } /// -/// @brief Decode Module Organization -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data +/// @brief Decode Soft post package repair (soft PPR) +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value enum representing if soft PPR is supported /// @return fapi2::ReturnCode -/// @note SPD Byte 12 +/// @note SPD Byte 9 (bit 5) +/// @note Item JC-45-2220.01x +/// @note Page 21 +/// @note DDR4 SPD Document Release 3 /// -fapi2::ReturnCode decoder::module_organization(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::soft_post_package_repair(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX = 12; - const size_t RESERVED = 0; - // SDRAM device width mapping limits - const size_t MAX_DEV_WIDTH_VALID_KEY = 3; // All others reserved + constexpr size_t BYTE_INDEX = 9; + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 0; - // Number of package ranks per DIMM mapping limits - const size_t MAX_PKG_RANKS_VALID_KEY = 7; // max supported packages + // Buffer used for bit manipulation + fapi2::buffer l_spd_buffer(l_raw_byte); - // Rank mix limits - const size_t SYMMETRICAL = 0; // asymmetical not supported + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), + BYTE_INDEX, + l_raw_byte); - // Targets - const auto l_target_mcs = find_target(i_target_dimm); - const auto l_target_port = find_target(i_target_dimm); + // Extracting desired bits + l_spd_buffer.extractToRight(l_field_bits); - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); + FAPI_TRY( mss::check::spd:: + fail_for_invalid_value(i_target, + mss::find_value_from_key(SOFT_PPR_MAP, l_field_bits, o_value), + BYTE_INDEX, + l_field_bits, + "Failed check for Soft PPR") ); - // Byte variables used for decoding - uint8_t l_device_width = 0; - uint8_t l_num_pkgs_ranks = 0; - uint8_t l_rank_mix = 0; - uint8_t l_reserved = 0; + FAPI_DBG("%s. Soft Post Package Repair (Soft PPR): %d", + mss::c_str(i_target), + o_value); - // Attribute variables used to set decoded vals - uint8_t l_sdram_device_widths[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; - uint8_t l_num_pkg_ranks_per_dimm[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; - uint8_t l_rank_mixes[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; +fapi_try_exit: + return fapi2::current_err; +} +/// +/// @brief Decode Post package repair (PPR) +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value enum representing if (hard) PPR is supported +/// @return fapi2::ReturnCode +/// @note SPD Byte 9 (bits 7~6) +/// @note Item JC-45-2220.01x +/// @note Page 21 +/// @note DDR4 SPD Document Release 3 +/// +fapi2::ReturnCode decoder::post_package_repair(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value) +{ - // Trace print in the front assists w/ debug - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), - BYTE_INDEX, - i_spd_data[BYTE_INDEX]); + constexpr size_t BYTE_INDEX = 9; + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 0; // Buffer used for bit manipulation - fapi2::buffer l_spd_buffer(i_spd_data[BYTE_INDEX]); + fapi2::buffer l_spd_buffer(l_raw_byte); + + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), + BYTE_INDEX, + l_raw_byte); + + // Extracting desired bits + l_spd_buffer.extractToRight(l_field_bits); + + FAPI_TRY( mss::check::spd:: + fail_for_invalid_value(i_target, + mss::find_value_from_key(PPR_MAP, l_field_bits, o_value), + BYTE_INDEX, + l_field_bits, + "Failed check for PPR") ); - // Decoding Bits 2~0 - l_spd_buffer.extractToRight(l_device_width); - - FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm, - l_device_width <= MAX_DEV_WIDTH_VALID_KEY, - BYTE_INDEX, - l_device_width, - "Failed check for SDRAM device width") ); - // Decoding Bits 5~3 - l_spd_buffer.extractToRight(l_num_pkgs_ranks); - - FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm, - l_num_pkgs_ranks <= MAX_PKG_RANKS_VALID_KEY, - BYTE_INDEX, - l_num_pkgs_ranks, - "Failed check for number of packages per DIMM") ); - // Decoding Bit 6 - l_spd_buffer.extractToRight(l_rank_mix); - - // We only support symmetrical rank mix - FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm, - l_rank_mix == SYMMETRICAL, - BYTE_INDEX, - l_rank_mix, - "Failed check for number of packages per DIMM") ); - // Decoding Bit 7 - l_spd_buffer.extractToRight(l_reserved); - - mss::check::spd::valid_value_warn(i_target_dimm, - l_reserved == RESERVED, - BYTE_INDEX, - l_reserved, - "Failed check for number of packages per DIMM"); - - // Retrive entire MCS level attribute - FAPI_TRY(eff_dram_width(l_target_mcs, &l_sdram_device_widths[0][0])); - FAPI_TRY(eff_num_packages_per_rank(l_target_mcs, &l_num_pkg_ranks_per_dimm[0][0])); - FAPI_TRY(eff_dram_rank_mix(l_target_mcs, &l_rank_mixes[0][0])); - - // Update attribute to decoded byte values - l_sdram_device_widths[PORT_NUM][DIMM_NUM] = device_type_map[l_device_width]; - l_num_pkg_ranks_per_dimm[PORT_NUM][DIMM_NUM] = num_pkgs_ranks_per_dimm_map[l_num_pkgs_ranks]; - l_rank_mixes[PORT_NUM][DIMM_NUM] = l_rank_mix; - - // Update MCS level attribute - FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_WIDTH, l_target_mcs, l_sdram_device_widths) ); - FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_NUM_PACKAGES_PER_RANK, l_target_mcs, l_num_pkg_ranks_per_dimm) ); - FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_RANK_MIX, l_target_mcs, l_rank_mixes) ); - - // Printed decoded info - FAPI_INF( "%s. Device Width: %d, Number of rank packages per DIMM: %d, Rank Mix: %d", - c_str(i_target_dimm), - l_sdram_device_widths[PORT_NUM][DIMM_NUM], - l_num_pkg_ranks_per_dimm[PORT_NUM][DIMM_NUM], - l_rank_mixes[PORT_NUM][DIMM_NUM] ); + FAPI_DBG("%s. Post Package Repair (PPR): %d", + mss::c_str(i_target), + o_value); fapi_try_exit: return fapi2::current_err; } -//TODO -// Returning correct stuff (bits) ?? Or am I supposed to calc "Module DRAM Capacity" pg 27 /// -/// @brief Decode Module Memory Bus Width -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data +/// @brief Decodes Secondary SDRAM signal loading +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value enum representing signal loading type /// @return fapi2::ReturnCode -/// @note SPD Byte 13 +/// @note SPD Byte 10 (bits 1~0) +/// @note Item JC-45-2220.01x +/// @note Page 22 +/// @note DDR4 SPD Document Release 3 /// -fapi2::ReturnCode decoder::module_memory_bus_width(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::sec_sdram_signal_loading(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX = 13; - const size_t RESERVED = 0; - // Primary bus width mapping limits - const size_t MAX_PRIM_BUS_WIDTH_KEY = 3; // All others reserved + constexpr size_t BYTE_INDEX = 10; + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 0; - // Bus width extention mapping limits - const size_t MAX_VALID_BUS_WIDTH_EXT_KEY = 1; // All others reserved + // Buffer used for bit manipulation + fapi2::buffer l_spd_buffer(l_raw_byte); - // Targets - const auto l_target_mcs = find_target(i_target_dimm); - const auto l_target_port = find_target(i_target_dimm); + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), + BYTE_INDEX, + l_raw_byte); - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); + // Extracting desired bits + l_spd_buffer.extractToRight(l_field_bits); - // Byte variables used for decoding - uint8_t l_bus_width = 0; - uint8_t l_bus_width_ext = 0; - uint8_t l_reserved = 0; + FAPI_TRY( mss::check::spd:: + fail_for_invalid_value(i_target, + mss::find_value_from_key(SEC_SIGNAL_LOADING_MAP, l_field_bits, o_value), + BYTE_INDEX, + l_field_bits, + "Failed check for SDRAM Row Address Bits") ); - // Attribute variables used to set decoded vals - uint8_t l_module_bus_widths[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + FAPI_DBG("%s. Number of Row Address Bits: %d", + mss::c_str(i_target), + o_value); - // Trace print in the front assists w/ debug - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Decodes Secondary DRAM Density Ratio +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value raw bits from SPD +/// @return fapi2::ReturnCode +/// @note SPD Byte 10 (bits 3~2) +/// @note Item JC-45-2220.01x +/// @note Page 22 +/// @note DDR4 SPD Document Release 3 +/// +fapi2::ReturnCode decoder::sec_dram_density_ratio(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value) +{ + + constexpr size_t BYTE_INDEX = 10; + constexpr size_t UNDEFINED = 3; // JEDEC map doesn't go beyond 3 + + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 0; + + // Buffer used for bit manipulation + fapi2::buffer l_spd_buffer(l_raw_byte); + + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), BYTE_INDEX, - i_spd_data[BYTE_INDEX]); + l_raw_byte); + + // Extracting desired bits + l_spd_buffer.extractToRight(l_field_bits); + + FAPI_TRY( mss::check::spd:: + fail_for_invalid_value(i_target, + l_field_bits != UNDEFINED, + BYTE_INDEX, + l_field_bits, + "Failed check for DRAM Density Ratio") ); + + FAPI_DBG("%s. DRAM Density Ratio: %d", + mss::c_str(i_target), + o_value); + +fapi_try_exit: + return fapi2::current_err; + +} + +/// +/// @brief Decodes Secondary SDRAM die count +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value die count +/// @return fapi2::ReturnCode +/// @note SPD Byte 10 (bits 6~4) +/// @note Item JC-45-2220.01x +/// @note Page 22 +/// @note DDR4 SPD Document Release 3 +/// +fapi2::ReturnCode decoder::sec_sdram_die_count(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value) +{ + + constexpr size_t BYTE_INDEX = 5; + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 0; // Buffer used for bit manipulation - fapi2::buffer l_spd_buffer(i_spd_data[BYTE_INDEX]); + fapi2::buffer l_spd_buffer(l_raw_byte); + + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), + BYTE_INDEX, + l_raw_byte); + + // Extracting desired bits + l_spd_buffer.extractToRight(l_field_bits); + + FAPI_TRY( mss::check::spd:: + fail_for_invalid_value(i_target, + mss::find_value_from_key(SEC_DIE_COUNT_MAP, l_field_bits, o_value), + BYTE_INDEX, + l_field_bits, + "Failed check for Secondary Die Count") ); + + FAPI_DBG("%s. Secondary Die Count: %d", + mss::c_str(i_target), + o_value); + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Decodes Secondary SDRAM package type +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value enum representing package type +/// @return fapi2::ReturnCode +/// @note SPD Byte 10 (bit 7) +/// @note Item JC-45-2220.01x +/// @note Page 22 +/// @note DDR4 SPD Document Release 3 +/// +fapi2::ReturnCode decoder::sec_sdram_package_type(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value) +{ + + constexpr size_t BYTE_INDEX = 5; + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 0; + + // Buffer used for bit manipulation + fapi2::buffer l_spd_buffer(l_raw_byte); + + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), + BYTE_INDEX, + l_raw_byte); + + // Extracting desired bits + l_spd_buffer.extractToRight(l_field_bits); - // Decoding Bits 2~0 - l_spd_buffer.extractToRight(l_bus_width); - - FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm, - l_bus_width <= MAX_PRIM_BUS_WIDTH_KEY, - BYTE_INDEX, - l_bus_width, - "Failed check on primary bus width") ); - // Decoding Bits 4~3 - l_spd_buffer.extractToRight(l_bus_width_ext); - - FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm, - l_bus_width_ext <= MAX_VALID_BUS_WIDTH_EXT_KEY, - BYTE_INDEX, - l_bus_width_ext, - "Failed check for bus width extension") ); - // Decoding bits Bits 7~5 - l_spd_buffer.extractToRight(l_reserved); - - mss::check::spd::valid_value_warn(i_target_dimm, - l_reserved == RESERVED, - BYTE_INDEX, - l_reserved, - "Failed check for bus width reserved bits"); - - // Retrive entire MCS level attribute - FAPI_TRY( eff_dram_module_bus_width(l_target_mcs, &l_module_bus_widths[0][0]) ); - - // Update attribute to decoded byte values - l_module_bus_widths[PORT_NUM][DIMM_NUM] = prim_bus_width_map[l_bus_width] + bus_width_ext_map[l_bus_width_ext]; - - // Update MCS level attribute - FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_MODULE_BUS_WIDTH, l_target_mcs, l_module_bus_widths); - - // Printed decoded info - FAPI_INF( "%s Module Memory Bus Width (in bits): %d, Primary bus width: %d, Bus width extension: %d", - c_str(i_target_dimm), - l_module_bus_widths[PORT_NUM][DIMM_NUM], - prim_bus_width_map[l_bus_width], - bus_width_ext_map[l_bus_width_ext] ); + FAPI_TRY( mss::check::spd:: + fail_for_invalid_value(i_target, + mss::find_value_from_key(SEC_PACKAGE_TYPE_MAP, l_field_bits, o_value), + BYTE_INDEX, + l_field_bits, + "Failed check for Secondary Package Type") ); + + FAPI_DBG("%s. Secondary Package Type: %d", + mss::c_str(i_target), + o_value); fapi_try_exit: return fapi2::current_err; @@ -1698,1851 +1643,2473 @@ fapi_try_exit: /// -/// @brief Decode Module Thermal Sensor -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data +/// @brief Decode Module Nominal Voltage, VDD +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value enum representing if 1.2V is operable /// @return fapi2::ReturnCode -/// @note SPD Byte 14, no attribute found for this +/// @note SPD Byte 11 (bit 0) +/// @note Item JC-45-2220.01x +/// @note Page 23 +/// @note DDR4 SPD Document Release 3 /// -fapi2::ReturnCode decoder::module_thermal_sensor(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::operable_nominal_voltage(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX = 14; - const size_t VALID_VALUE = 1; - const size_t RESERVED = 0; - // Byte variables used for decoding - uint8_t l_reserved = 0; - uint8_t l_thermal_sensor = 0; + constexpr size_t BYTE_INDEX = 11; + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 0; + + // Buffer used for bit manipulation + fapi2::buffer l_spd_buffer(l_raw_byte); + + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), + BYTE_INDEX, + l_raw_byte); - // Attribute variables used to set decoded vals - uint8_t l_therm_sensors[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + // Extracting desired bits + l_spd_buffer.extractToRight(l_field_bits); - // Targets - const auto l_target_mcs = find_target(i_target_dimm); - const auto l_target_port = find_target(i_target_dimm); + FAPI_TRY( mss::check::spd:: + fail_for_invalid_value(i_target, + mss::find_value_from_key(OPERABLE_MAP, l_field_bits, o_value), + BYTE_INDEX, + l_field_bits, + "Failed check for Endur") ); - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); + FAPI_DBG("%s. Operable: %d", + mss::c_str(i_target), + o_value); - // Trace print in the front assists w/ debug - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Decode Module Nominal Voltage, VDD +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value enum representing if 1.2V is endurant +/// @return fapi2::ReturnCode +/// @note SPD Byte 11 (bit 1) +/// @note Item JC-45-2220.01x +/// @note Page 23 +/// @note DDR4 SPD Document Release 3 +/// +fapi2::ReturnCode decoder::endurant_nominal_voltage(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value) +{ + + constexpr size_t BYTE_INDEX = 11; + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 0; + + // Buffer used for bit manipulation + fapi2::buffer l_spd_buffer(l_raw_byte); + + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), BYTE_INDEX, - i_spd_data[BYTE_INDEX]); + l_raw_byte); + + // Extracting desired bits + l_spd_buffer.extractToRight(l_field_bits); + + FAPI_TRY( mss::check::spd:: + fail_for_invalid_value(i_target, + mss::find_value_from_key(ENDURANT_MAP, l_field_bits, o_value), + BYTE_INDEX, + l_field_bits, + "Failed check for Endurant") ); + + FAPI_DBG("%s. Endurant: %d", + mss::c_str(i_target), + o_value); + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Decodes SDRAM device width +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value device width in bits +/// @return fapi2::ReturnCode +/// @note SPD Byte 12 (bits 2~0) +/// @note Item JC-45-2220.01x +/// @note Page 23 +/// @note DDR4 SPD Document Release 3 +/// +fapi2::ReturnCode decoder::device_width(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value) +{ + + constexpr size_t BYTE_INDEX = 12; + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 0; // Buffer used for bit manipulation - fapi2::buffer l_spd_buffer(i_spd_data[BYTE_INDEX]); + fapi2::buffer l_spd_buffer(l_raw_byte); - // Decoding Bits 6~0 - l_spd_buffer.extractToRight(l_reserved); + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), + BYTE_INDEX, + l_raw_byte); - mss::check::spd::valid_value_warn(i_target_dimm, - l_reserved == RESERVED, - BYTE_INDEX, - l_reserved, - "Failed check for thermal sensor reserved bits"); - // Decoding bits Bit 7 - l_spd_buffer.extractToRight(l_thermal_sensor); + // Extracting desired bits + l_spd_buffer.extractToRight(l_field_bits); - // Length is a single bit (0 or 1), anything larger means corrupt data - FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm, - l_thermal_sensor <= VALID_VALUE, - BYTE_INDEX, - l_thermal_sensor, - "Failed check for thermal sensor") ); + FAPI_TRY( mss::check::spd:: + fail_for_invalid_value(i_target, + mss::find_value_from_key(DEVICE_WIDTH_MAP, l_field_bits, o_value), + BYTE_INDEX, + l_field_bits, + "Failed check for Device Width") ); - // Retrive entire MCS level attribute - FAPI_TRY( spd_module_thermal_sensor(l_target_mcs, &l_therm_sensors[0][0]) ); + FAPI_DBG("%s. Device Width: %d", + mss::c_str(i_target), + o_value); - // Update attribute to decoded byte values - l_therm_sensors[PORT_NUM][DIMM_NUM] = l_thermal_sensor; +fapi_try_exit: + return fapi2::current_err; +} - // Update MCS level attribute - FAPI_ATTR_SET(fapi2::ATTR_SPD_MODULE_THERMAL_SENSOR, l_target_mcs, l_therm_sensors); - // Printed decoded info - FAPI_INF("%s. Thermal sensor: %d, Reserved: %d", - c_str(i_target_dimm), - l_thermal_sensor, - l_reserved ); +/// +/// @brief Decodes number of package ranks per DIMM +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value number of package ranks per DIMM +/// @return fapi2::ReturnCode +/// @note SPD Byte 12 (bits 5~3) +/// @note Item JC-45-2220.01x +/// @note Page 23 +/// @note DDR4 SPD Document Release 3 +/// +fapi2::ReturnCode decoder::num_package_ranks_per_dimm(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value) +{ + + constexpr size_t BYTE_INDEX = 12; + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 0; + + // Buffer used for bit manipulation + fapi2::buffer l_spd_buffer(l_raw_byte); + + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), + BYTE_INDEX, + l_raw_byte); + + // Extracting desired bits + l_spd_buffer.extractToRight(l_field_bits); + + FAPI_TRY( mss::check::spd:: + fail_for_invalid_value(i_target, + mss::find_value_from_key(NUM_PACKAGE_RANKS_MAP, l_field_bits, o_value), + BYTE_INDEX, + l_field_bits, + "Failed check for Num Package Ranks Per DIMM") ); + + FAPI_DBG("%s. Num Package Ranks per DIMM: %d", + mss::c_str(i_target), + o_value); fapi_try_exit: return fapi2::current_err; } /// -/// @brief Decode Extended Module Type -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data +/// @brief Decodes Rank Mix +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value rank mix value from SPD /// @return fapi2::ReturnCode -/// @note SPD Byte 15, no attribute for this byte +/// @note SPD Byte 12 (bit 6) +/// @note Item JC-45-2220.01x +/// @note Page 23 +/// @note DDR4 SPD Document Release 3 /// -fapi2::ReturnCode decoder::extended_module_type(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::rank_mix(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX = 15; - const size_t RESERVED = 0; - // Byte variables used for decoding - uint8_t l_ext_module_type = 0; - uint8_t l_reserved = 0; + constexpr size_t BYTE_INDEX = 12; + constexpr size_t INVALID_VALUE = 2; + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 0; - // Trace print in the front assists w/ debug - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), + // Buffer used for bit manipulation + fapi2::buffer l_spd_buffer(l_raw_byte); + + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), BYTE_INDEX, - i_spd_data[BYTE_INDEX]); + l_raw_byte); + + // Extracting desired bits + l_spd_buffer.extractToRight(l_field_bits); + + FAPI_TRY( mss::check::spd:: + fail_for_invalid_value(i_target, + (l_field_bits < INVALID_VALUE), + BYTE_INDEX, + l_field_bits, + "Failed check for Rank Mix") ); + + o_value = l_field_bits; + + FAPI_DBG("%s. Rank Mix: %d", + mss::c_str(i_target), + o_value); + +fapi_try_exit: + return fapi2::current_err; +} + + +/// +/// @brief Decodes primary bus width +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value primary bus width in bits +/// @return fapi2::ReturnCode +/// @note SPD Byte 13 (bits 2~0) +/// @note Item JC-45-2220.01x +/// @note Page 27 +/// @note DDR4 SPD Document Release 3 +/// +fapi2::ReturnCode decoder::prim_bus_width(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value) +{ + constexpr size_t BYTE_INDEX = 13; + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 0; // Buffer used for bit manipulation - fapi2::buffer l_spd_buffer(i_spd_data[BYTE_INDEX]); + fapi2::buffer l_spd_buffer(l_raw_byte); + + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), + BYTE_INDEX, + l_raw_byte); + + // Extracting desired bits + l_spd_buffer.extractToRight(l_field_bits); + + FAPI_TRY( mss::check::spd:: + fail_for_invalid_value(i_target, + mss::find_value_from_key(BUS_WIDTH_MAP, l_field_bits, o_value), + BYTE_INDEX, + l_field_bits, + "Failed check for Primary Bus Width") ); + + FAPI_DBG("%s. Primary Bus Width: %d", + mss::c_str(i_target), + o_value); + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Decodes bus width extension +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value bus width extension in bits +/// @return fapi2::ReturnCode +/// @note SPD Byte 13 (bits 2~0) +/// @note Item JC-45-2220.01x +/// @note Page 28 +/// @note DDR4 SPD Document Release 3 +/// +fapi2::ReturnCode decoder::bus_width_extension(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value) +{ + constexpr size_t BYTE_INDEX = 13; + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 0; - // Decoding Bits 3~0 - l_spd_buffer.extractToRight(l_ext_module_type); + // Buffer used for bit manipulation + fapi2::buffer l_spd_buffer(l_raw_byte); - // According to JEDEC spec this value should be coded as 0000 which is the value as the reserved bits - FAPI_TRY(mss::check::spd::valid_value_fail(i_target_dimm, - l_ext_module_type == RESERVED, + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), BYTE_INDEX, - l_ext_module_type, - "Failed check for extended base module type") ); - // Decoding Bit 7~4 - l_spd_buffer.extractToRight(l_reserved); - - mss::check::spd::valid_value_warn(i_target_dimm, - l_reserved == RESERVED, - BYTE_INDEX, - l_reserved, - "Failed check for extended module type reserved bits"); - - // Printed decoded info - FAPI_INF("%s. Extended Base Module Type: %d, Reserved: %d", - c_str(i_target_dimm), - l_ext_module_type, - l_reserved ); + l_raw_byte); + + // Extracting desired bits + l_spd_buffer.extractToRight(l_field_bits); + + FAPI_TRY( mss::check::spd:: + fail_for_invalid_value(i_target, + mss::find_value_from_key(BUS_WIDTH_EXT_MAP, l_field_bits, o_value), + BYTE_INDEX, + l_field_bits, + "Failed check for Bus Width Extension") ); + + FAPI_DBG("%s. Bus Width Extension (bits): %d", + mss::c_str(i_target), + o_value); fapi_try_exit: return fapi2::current_err; } + /// -/// @brief Decode Timebases -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data +/// @brief Decode Module Thermal Sensor +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value thermal sensor value from SPD /// @return fapi2::ReturnCode -/// @note SPD Byte 17 +/// @note SPD Byte 14 (bit 7) +/// @note Item JC-45-2220.01x +/// @note Page 28 +/// @note DDR4 SPD Document Release 3 /// -fapi2::ReturnCode decoder::timebases(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::thermal_sensor(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX = 17; - const size_t RESERVED = 0; - // Medium timebase mapping limits - const int64_t MAX_VALID_MTB_KEY = 1; // All others reserved + constexpr size_t BYTE_INDEX = 14; + constexpr size_t INVALID_VALUE = 2; // single bit value 0 or 1 + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 0; + + // Buffer used for bit manipulation + fapi2::buffer l_spd_buffer(l_raw_byte); - // Fine timebase mapping limits - const int64_t MAX_VALID_FTB_KEY = 1; // All others reserved + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), + BYTE_INDEX, + l_raw_byte); - // Targets - const auto l_target_mcs = find_target(i_target_dimm); - const auto l_target_port = find_target(i_target_dimm); + // Extracting desired bits + l_spd_buffer.extractToRight(l_field_bits); - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); + FAPI_TRY( mss::check::spd:: + fail_for_invalid_value(i_target, + l_field_bits < INVALID_VALUE, + BYTE_INDEX, + l_field_bits, + "Failed check for Thermal Sensor") ); + o_value = l_field_bits; - // Byte variables used for decoding - int64_t l_fine_timebase = 0; - int64_t l_medium_timebase = 0; - int64_t l_reserved = 0; + FAPI_DBG("%s. Thermal Sensor: %d", + mss::c_str(i_target), + o_value); - // Attribute variables used to set decoded vals - int64_t l_FTBs[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; - int64_t l_MTBs[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; +fapi_try_exit: + return fapi2::current_err; +} - // Trace print in the front assists w/ debug - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), +/// +/// @brief Decode Extended Base Module Type +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value raw data from SPD +/// @return fapi2::ReturnCode +/// @note SPD Byte 15 (bits 3~0) +/// @note Item JC-45-2220.01x +/// @note Page 28 +/// @note DDR4 SPD Document Release 3 +/// +fapi2::ReturnCode decoder::extended_base_module_type(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value) +{ + + constexpr size_t BYTE_INDEX = 15; + constexpr size_t RESERVED = 0; + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 0; + + // Buffer used for bit manipulation + fapi2::buffer l_spd_buffer(l_raw_byte); + + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), BYTE_INDEX, - i_spd_data[BYTE_INDEX]); + l_raw_byte); + + // Extracting desired bits + l_spd_buffer.extractToRight(l_field_bits); + + // Currently reserved to 0b000 + FAPI_TRY( mss::check::spd:: + fail_for_invalid_value(i_target, + l_field_bits == RESERVED, + BYTE_INDEX, + l_field_bits, + "Failed check for Extended Base Module Type") ); + o_value = l_field_bits; + + FAPI_DBG("%s. Extended Base Module Type: %d", + mss::c_str(i_target), + o_value); + +fapi_try_exit: + return fapi2::current_err; +} + + +/// +/// @brief Decode Fine Timebase +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value fine_timebase from SPD in picoseconds +/// @return fapi2::ReturnCode +/// @note SPD Byte 17 (bits 1~0) +/// @note Item JC-45-2220.01x +/// @note Page 29 +/// @note DDR4 SPD Document Release 3 +/// +fapi2::ReturnCode decoder::fine_timebase(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) +{ + + constexpr size_t BYTE_INDEX = 17; + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 0; // Buffer used for bit manipulation - fapi2::buffer l_spd_buffer(i_spd_data[BYTE_INDEX]); + fapi2::buffer l_spd_buffer(l_raw_byte); - // TODO - update ENUMS to take account to int64_t - // Decoding Bits 1~0 - l_spd_buffer.extractToRight(l_fine_timebase); + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), + BYTE_INDEX, + l_raw_byte); + + // Extracting desired bits + l_spd_buffer.extractToRight(l_field_bits); + + FAPI_TRY( mss::check::spd:: + fail_for_invalid_value(i_target, + mss::find_value_from_key(FINE_TIMEBASE_MAP, l_field_bits, o_value), + BYTE_INDEX, + l_field_bits, + "Failed check for Fine Timebase") ); + + FAPI_DBG("%s. Fine Timebase: %d", + mss::c_str(i_target), + o_value); + +fapi_try_exit: + return fapi2::current_err; +} - FAPI_TRY(mss::check::spd::valid_value_fail(i_target_dimm, - l_fine_timebase < MAX_VALID_FTB_KEY, +/// +/// @brief Decode Medium Timebase +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value medium timebase from SPD in picoseconds +/// @return fapi2::ReturnCode +/// @note SPD Byte 17 (bits 3~2) +/// @note Item JC-45-2220.01x +/// @note Page 29 +/// @note DDR4 SPD Document Release 3 +/// +fapi2::ReturnCode decoder::medium_timebase(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) +{ + + constexpr size_t BYTE_INDEX = 17; + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 0; + + // Buffer used for bit manipulation + fapi2::buffer l_spd_buffer(l_raw_byte); + + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), BYTE_INDEX, - l_fine_timebase, - "Failed check for fine timebase") ); - // Decoding Bits 3~2 - l_spd_buffer.extractToRight(l_medium_timebase); + l_raw_byte); + + // Extracting desired bits + l_spd_buffer.extractToRight(l_field_bits); + + FAPI_TRY( mss::check::spd:: + fail_for_invalid_value(i_target, + mss::find_value_from_key(MEDIUM_TIMEBASE_MAP, l_field_bits, o_value), + BYTE_INDEX, + l_field_bits, + "Failed check for Medium Timebase") ); + + FAPI_DBG("%s. Medium Timebase: %d", + mss::c_str(i_target), + o_value); + +fapi_try_exit: + return fapi2::current_err; +} + + +/// +/// @brief Decodes SDRAM Minimum Cycle Time in MTB +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value tCKmin in MTB units +/// @return fapi2::ReturnCode +/// @note SPD Byte 18 +/// @note Item JC-45-2220.01x +/// @note Page 31-32 +/// @note DDR4 SPD Document Release 3 +/// @warning If tCKmin cannot be divided evenly by the MTB, +/// this byte must be rounded up to the next larger +/// integer and the Fine Offset for tCKmin (SPD byte 125) +/// used for correction to get the actual value. +/// +fapi2::ReturnCode decoder::min_cycle_time(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) +{ + constexpr size_t BYTE_INDEX = 18; - FAPI_TRY(mss::check::spd::valid_value_fail(i_target_dimm, - l_medium_timebase < MAX_VALID_MTB_KEY, + constexpr int64_t TIMING_LOWER_BOUND = 1; // from JEDEC + constexpr int64_t TIMING_UPPER_BOUND = 255; // from JEDEC + + // Explicit conversion + int64_t l_timing_val = int64_t(i_spd_data[BYTE_INDEX]); + + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: %d.", + mss::c_str(i_target), BYTE_INDEX, - l_medium_timebase, - "Failed check for medium timebase") ); - // Decoding bits Bits 7~4 - l_spd_buffer.extractToRight(l_reserved); - - mss::check::spd::valid_value_warn(i_target_dimm, - l_reserved == RESERVED, - BYTE_INDEX, - l_reserved, - "Failed check for timebases reserved bits"); - - // Retrive entire MCS level attribute - FAPI_TRY( spd_fine_timebase(l_target_mcs, &l_FTBs[0][0]) ); - FAPI_TRY( spd_medium_timebase(l_target_mcs, &l_MTBs[0][0]) ); - - // Update attribute to decoded byte values - l_FTBs[PORT_NUM][DIMM_NUM] = fine_timebase_map[l_fine_timebase]; - l_MTBs[PORT_NUM][DIMM_NUM] = medium_timebase_map[l_medium_timebase]; - - // Update MCS level attribute - FAPI_ATTR_SET( fapi2::ATTR_SPD_FINE_TIMEBASE, l_target_mcs, l_FTBs ); - FAPI_ATTR_SET( fapi2::ATTR_SPD_MEDIUM_TIMEBASE, l_target_mcs, l_MTBs ); - - // Printed decoded info - FAPI_INF( "%s. Fine Timebase: %d, Medium Timebase: %d", - c_str(i_target_dimm), - l_FTBs[PORT_NUM][DIMM_NUM], - l_MTBs[PORT_NUM][DIMM_NUM] ); + l_timing_val); + + FAPI_TRY(mss::check::spd:: + fail_for_invalid_value(i_target, + (l_timing_val <= TIMING_UPPER_BOUND) && + (l_timing_val >= TIMING_LOWER_BOUND), + BYTE_INDEX, + l_timing_val, + "Failed check on the min cycle time (tckmin) in MTB") ); + + FAPI_DBG("%s. Minimum Cycle Time (tCKmin) in MTB units: %d", + mss::c_str(i_target), + o_value); fapi_try_exit: return fapi2::current_err; } /// -/// @brief Decode SDRAM Minimum Cycle Time -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data +/// @brief Decodes SDRAM Maximum Cycle Time in MTB +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value tCKmax in MTB units /// @return fapi2::ReturnCode -/// @note SPD Byte 18 & Byte 125 -/// This byte depends on the fine & medium timebase values -/// obtained from Byte 17 +/// @note SPD Byte 19 +/// @note Item JC-45-2220.01x +/// @note Page 32 +/// @note DDR4 SPD Document Release 3 +/// @warning If tCKmax cannot be divided evenly by the MTB, +/// this byte must be rounded up to the next larger +/// integer and the Fine Offset for tCKmax (SPD byte 124) +/// used for correction to get the actual value. /// -fapi2::ReturnCode decoder::min_cycle_time(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::max_cycle_time(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX_MTB = 18; // min cycle medium timebase (mtb) - const size_t BYTE_INDEX_FTB = 125; // min cycle fine timebase (ftb) + constexpr size_t BYTE_INDEX = 19; - const int64_t MIN_CYCLE_TIME_MTB = 1; // from JEDEC - const int64_t MAX_CYCLE_TIME_MTB = 255; // from JEDEC + constexpr int64_t TIMING_LOWER_BOUND = 1; // from JEDEC + constexpr int64_t TIMING_UPPER_BOUND = 255; // from JEDEC - const int64_t MIN_CYCLE_TIME_FTB = -128; // from JEDEC - const int64_t MAX_CYCLE_TIME_FTB = 127; // from JEDEC + // Explicit conversion + int64_t l_timing_val = int64_t(i_spd_data[BYTE_INDEX]); + + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: %d.", + mss::c_str(i_target), + BYTE_INDEX, + l_timing_val); + + FAPI_TRY(mss::check::spd:: + fail_for_invalid_value(i_target, + (l_timing_val <= TIMING_UPPER_BOUND) && + (l_timing_val >= TIMING_LOWER_BOUND), + BYTE_INDEX, + l_timing_val, + "Failed check on the max cycle time (tckmax) in MTB") ); + + FAPI_DBG("%s. Maximum Cycle Time (tCKmax) in MTB units: %d", + mss::c_str(i_target), + o_value); + +fapi_try_exit: + return fapi2::current_err; +} - // Targets - const auto l_target_mcs = find_target(i_target_dimm); - const auto l_target_port = find_target(i_target_dimm); - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); +/// +/// @brief Decode CAS Latencies Supported +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value bitmap of supported CAS latencies +/// @return fapi2::ReturnCode +/// @note SPD Bytes 20-23 +/// @note Item JC-45-2220.01x +/// @note Page 33-34 +/// @note DDR4 SPD Document Release 3 +/// +fapi2::ReturnCode decoder::supported_cas_latencies(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint64_t& o_value) +{ + constexpr size_t FIRST_BYTE = 20; + constexpr size_t SEC_BYTE = 21; + constexpr size_t THIRD_BYTE = 22; + constexpr size_t FOURTH_BYTE = 23; - // Byte variables used for decoding - int64_t l_tCKmin_mtb = 0; - int64_t l_tCKmin_ftb = 0; + constexpr size_t OUTPUT_START = 0; + constexpr size_t OUTPUT_LEN = 64; - // Attribute variables - int64_t l_min_cycle_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; - int64_t l_MTBs[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; - int64_t l_FTBs[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + // Buffers used for bit manipulation + fapi2::buffer l_buffer; // Trace print in the front assists w/ debug - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), - BYTE_INDEX_MTB, - i_spd_data[BYTE_INDEX_MTB]); - - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), - BYTE_INDEX_FTB, - i_spd_data[BYTE_INDEX_FTB]); - - // Retrieve SDRAM Maximum Cycle Time - l_tCKmin_mtb = i_spd_data[BYTE_INDEX_MTB]; - - FAPI_TRY(mss::check::spd::valid_value_fail(i_target_dimm, - (l_tCKmin_mtb <= MAX_CYCLE_TIME_MTB) && - (l_tCKmin_mtb >= MIN_CYCLE_TIME_MTB), - BYTE_INDEX_MTB, - l_tCKmin_mtb, - "Failed check for tCKmin (min cycle time) in MTB units") ); + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + c_str(i_target), + FIRST_BYTE, + i_spd_data[FIRST_BYTE]); + + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + c_str(i_target), + SEC_BYTE, + i_spd_data[SEC_BYTE]); + + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + c_str(i_target), + THIRD_BYTE, + i_spd_data[THIRD_BYTE]) + + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + c_str(i_target), + FOURTH_BYTE, + i_spd_data[FOURTH_BYTE]); + + // Combine Bytes to create bitmap - right aligned + l_buffer.insertFromRight(i_spd_data[FIRST_BYTE]). + insertFromRight(i_spd_data[SEC_BYTE]). + insertFromRight(i_spd_data[THIRD_BYTE]). + insertFromRight(i_spd_data[FOURTH_BYTE]); + + // According to the JEDEC spec: + // Byte 23 bit 6 is reserved and must be coded as 0. + // Warn instead of fail because in last revision this was a reserved byte coded as 0x00 + constexpr size_t BIT_START = 33; // relative position of bit 6 in byte 23 relative to uint64_t + constexpr size_t BIT_LEN = 1; + + FAPI_TRY( mss::check::spd:: + fail_for_invalid_value(i_target, + !(l_buffer.getBit()), + FOURTH_BYTE, + i_spd_data[FOURTH_BYTE], + "Failed check on CAS latencies supported") ); + + // Update output value only if range check passes + l_buffer.extractToRight(o_value); + + FAPI_DBG("%s. CAS latencies supported (bitmap): 0x%llX", + mss::c_str(i_target), + o_value); - // Retrieve Fine Offset for SDRAM Minimum Cycle Time - // casted int8_t undoes 2's complement on the uint8_t spd data - l_tCKmin_ftb = int8_t(i_spd_data[BYTE_INDEX_FTB]); - - FAPI_TRY(mss::check::spd::valid_value_fail(i_target_dimm, - (l_tCKmin_ftb <= MAX_CYCLE_TIME_FTB) && - (l_tCKmin_ftb >= MIN_CYCLE_TIME_FTB), - BYTE_INDEX_FTB, - l_tCKmin_ftb, - "Failed check for tCKmin (min cycle time) in FTB units") ); - - - // Retrieving medium timebase (MTB) multiplier used for timing calculation - FAPI_TRY( spd_medium_timebase(l_target_mcs, &l_MTBs[0][0]) ); - FAPI_TRY( spd_fine_timebase(l_target_mcs, &l_FTBs[0][0]) ); - - // Retrive entire MCS level attribute - FAPI_TRY( spd_timing_tckmin(l_target_mcs, &l_min_cycle_times[0][0]) ); - - // Update attribute to decoded byte values - // Calculating minimum cycle time in picosconds - l_min_cycle_times[PORT_NUM][DIMM_NUM] = calc_timing(l_tCKmin_mtb, - l_tCKmin_ftb, - l_MTBs[PORT_NUM][DIMM_NUM], - l_FTBs[PORT_NUM][DIMM_NUM]); - // Update MCS level attribute - FAPI_ATTR_SET( fapi2::ATTR_TIMING_TCKMIN, l_target_mcs, l_min_cycle_times ); - - // Printed decoded info - FAPI_INF("%s. tCKmin (min cycle time): %d (ps)", - c_str(i_target_dimm), - l_min_cycle_times[PORT_NUM][DIMM_NUM] ); +fapi_try_exit: + return fapi2::current_err; + +} + +/// +/// @brief Decodes SDRAM Minimum CAS Latency Time in MTB +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value tAAmin in MTB units +/// @return fapi2::ReturnCode +/// @note SPD Byte 24 +/// @note Item JC-45-2220.01x +/// @note Page 34 +/// @note DDR4 SPD Document Release 3 +/// @warning If tAAmin cannot be divided evenly by the MTB, +/// this byte must be rounded up to the next larger +/// integer and the Fine Offset for tAAmin (SPD byte 123) +/// used for correction to get the actual value. +/// +fapi2::ReturnCode decoder::min_cas_latency_time(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) +{ + constexpr size_t BYTE_INDEX = 24; + + constexpr int64_t TIMING_LOWER_BOUND = 1; // from JEDEC + constexpr int64_t TIMING_UPPER_BOUND = 255; // from JEDEC + + // Explicit conversion + int64_t l_timing_val = int64_t(i_spd_data[BYTE_INDEX]); + + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), + BYTE_INDEX, + l_timing_val); + + FAPI_TRY(mss::check::spd:: + fail_for_invalid_value(i_target, + (l_timing_val <= TIMING_UPPER_BOUND) && + (l_timing_val >= TIMING_LOWER_BOUND), + BYTE_INDEX, + l_timing_val, + "Failed check on the Minimum CAS Latency Time (tAAmin) in MTB") ); + + // Only update output if it passes check + o_value = l_timing_val; + + FAPI_DBG("%s. Minimum CAS Latency Time (tAAmin) in MTB units: %d", + mss::c_str(i_target), + o_value); fapi_try_exit: return fapi2::current_err; } /// -/// @brief Decode SDRAM Maximum Cycle Time -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data +/// @brief Decodes SDRAM Minimum RAS to CAS Delay Time in MTB +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value tRCDmin in MTB units /// @return fapi2::ReturnCode -/// @note SPD Byte 19 and 124 +/// @note SPD Byte 25 +/// @note Item JC-45-2220.01x +/// @note Page 35 +/// @note DDR4 SPD Document Release 3 +/// @warning If tRCDmin cannot be divided evenly by the MTB, +/// this byte must be rounded up to the next larger +/// integer and the Fine Offset for tRCDmin (SPD byte 122) +/// used for correction to get the actual value /// -fapi2::ReturnCode decoder::max_cycle_time(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::min_ras_to_cas_delay_time(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX_MTB = 19; // min cycle medium timebase (mtb) - const size_t BYTE_INDEX_FTB = 124; // min cycle fine timebase (ftb) + constexpr size_t BYTE_INDEX = 25; - const int64_t MIN_CYCLE_TIME_MTB = 1; // from JEDEC - const int64_t MAX_CYCLE_TIME_MTB = 255; // from JEDEC + constexpr int64_t TIMING_LOWER_BOUND = 1; // from JEDEC + constexpr int64_t TIMING_UPPER_BOUND = 255; // from JEDEC - const int64_t MIN_CYCLE_TIME_FTB = -128; // from JEDEC - const int64_t MAX_CYCLE_TIME_FTB = 127; // from JEDEC + // Explicit conversion + int64_t l_timing_val = int64_t(i_spd_data[BYTE_INDEX]); - // Targets - const auto l_target_mcs = find_target(i_target_dimm); - const auto l_target_port = find_target(i_target_dimm); + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), + BYTE_INDEX, + l_timing_val); - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); + FAPI_TRY(mss::check::spd:: + fail_for_invalid_value(i_target, + (l_timing_val <= TIMING_UPPER_BOUND) && + (l_timing_val >= TIMING_LOWER_BOUND), + BYTE_INDEX, + l_timing_val, + "Failed check on the Minimum RAS to CAS Delay Time (tRCDmin) in MTB") ); - // Byte variables used for decoding - int64_t l_tCKmax_mtb = 0; - int64_t l_tCKmax_ftb = 0; + // Only update output if it passes check + o_value = l_timing_val; - // Attribute variable - int64_t l_max_cycle_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; - int64_t l_MTBs[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; - int64_t l_FTBs[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + FAPI_DBG("%s. Minimum RAS to CAS Delay Time (tRCDmin) in MTB units: %d", + mss::c_str(i_target), + o_value); - // Trace print in the front assists w/ debug - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), - BYTE_INDEX_MTB, - i_spd_data[BYTE_INDEX_MTB]); - - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), - BYTE_INDEX_FTB, - i_spd_data[BYTE_INDEX_FTB]); - - // Retrieve SDRAM Maximum Cycle Time - l_tCKmax_mtb = i_spd_data[BYTE_INDEX_MTB]; - - FAPI_TRY(mss::check::spd::valid_value_fail(i_target_dimm, - (l_tCKmax_mtb <= MAX_CYCLE_TIME_MTB) && - (l_tCKmax_mtb >= MIN_CYCLE_TIME_MTB), - BYTE_INDEX_MTB, - l_tCKmax_mtb, - "Failed check for tCKmin (min cycle time) in MTB units") ); +fapi_try_exit: + return fapi2::current_err; +} - // Retrieve Fine Offset for SDRAM Maximum Cycle Time - // casted int8_t undoes 2's complement on the uint8_t spd data - l_tCKmax_ftb = int8_t(i_spd_data[BYTE_INDEX_FTB]); +/// +/// @brief Decodes SDRAM Minimum Row Precharge Delay Time in MTB +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value tRPmin in MTB units +/// @return fapi2::ReturnCode +/// @note SPD Byte 26 +/// @note Item JC-45-2220.01x +/// @note Page 36-37 +/// @note DDR4 SPD Document Release 3 +/// @warning If tRPmin cannot be divided evenly by the MTB, +// this byte must be rounded up to the next larger +/// integer and the Fine Offset for tRPmin (SPD byte 121) +/// used for correction to get the actual value +/// +fapi2::ReturnCode decoder::min_row_precharge_delay_time(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) +{ + constexpr size_t BYTE_INDEX = 26; - FAPI_TRY(mss::check::spd::valid_value_fail(i_target_dimm, - (l_tCKmax_ftb <= MAX_CYCLE_TIME_FTB) && - (l_tCKmax_ftb >= MIN_CYCLE_TIME_FTB), - BYTE_INDEX_FTB, - l_tCKmax_ftb, - "Failed check for tCKmin (min cycle time) in FTB units") ); + constexpr int64_t TIMING_LOWER_BOUND = 1; // from JEDEC + constexpr int64_t TIMING_UPPER_BOUND = 255; // from JEDEC - // Retrieving medium timebase (MTB) multiplier used for timing calculation - FAPI_TRY( spd_medium_timebase(l_target_mcs, &l_MTBs[0][0]) ); - FAPI_TRY( spd_fine_timebase(l_target_mcs, &l_FTBs[0][0]) ); + // Explicit conversion + int64_t l_timing_val = int64_t(i_spd_data[BYTE_INDEX]); - // Retrive entire MCS level attribute - FAPI_TRY(spd_timing_tckmax(l_target_mcs, &l_max_cycle_times[0][0])) + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), + BYTE_INDEX, + l_timing_val); - // Update attribute to decoded byte values - l_max_cycle_times[PORT_NUM][DIMM_NUM] = calc_timing(l_tCKmax_mtb, - l_tCKmax_ftb, - l_MTBs[PORT_NUM][DIMM_NUM], - l_FTBs[PORT_NUM][DIMM_NUM]); + FAPI_TRY(mss::check::spd:: + fail_for_invalid_value(i_target, + (l_timing_val <= TIMING_UPPER_BOUND) && + (l_timing_val >= TIMING_LOWER_BOUND), + BYTE_INDEX, + l_timing_val, + "Failed check on the Minimum Row Precharge Delay Time (tRPmin) in MTB") ); - // Update MCS level attribute - FAPI_ATTR_SET( fapi2::ATTR_TIMING_TCKMAX, l_target_mcs, l_max_cycle_times ); + // Only update output if it passes check + o_value = l_timing_val; - // Printed decoded info - FAPI_INF("%s. tCKmax (max cycle time): %d (ps)", - c_str(i_target_dimm), - l_max_cycle_times[PORT_NUM][DIMM_NUM] ); + FAPI_DBG("%s. Minimum Row Precharge Delay Time (tRPmin) in MTB units: %d", + mss::c_str(i_target), + o_value); fapi_try_exit: return fapi2::current_err; } + /// -/// @brief Decode Minimum CAS Latency Time -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data +/// @brief Decodes SDRAM Minimum Active to Precharge Delay Time in MTB +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value tRASmin in MTB units /// @return fapi2::ReturnCode -/// @note SPD Byte 24 & 123 +/// @note SPD Byte 27 (bits 3~0) & Byte 28 (bits 7~0) +/// @note Item JC-45-2220.01x +/// @note Page 38 +/// @note DDR4 SPD Document Release 3 /// -fapi2::ReturnCode decoder::min_cas_latency_time(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::min_active_to_precharge_delay_time(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX_MTB = 24; // min cycle medium timebase (mtb) - const size_t BYTE_INDEX_FTB = 123; // min cycle fine timebase (ftb) + // Lambda expression to retrieve tRASmin's most significant nibble (MSN) + auto tRASmin_MSN = [](const fapi2::Target& i_target, const uint8_t* i_data) + { + constexpr size_t BYTE_INDEX = 27; + uint8_t l_out = 0; + + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), + BYTE_INDEX, + i_data[BYTE_INDEX]); + + fapi2::buffer l_buffer(i_data[BYTE_INDEX]); + + // Extracting desired bits + l_buffer.extractToRight(l_out); + + return l_out; + }; + + // Lambda expression to retrieve tRASmin's least significant byte (LSB) + auto tRASmin_LSB = [](const fapi2::Target& i_target, const uint8_t* i_data) + { + constexpr size_t BYTE_INDEX = 28; + uint8_t l_out = 0; + + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), + BYTE_INDEX, + i_data[BYTE_INDEX]); + + fapi2::buffer l_buffer(i_data[BYTE_INDEX]); + + // Extracting desired bits + l_buffer.extractToRight(l_out); + + return l_out; + }; + + + int64_t l_timing_val = 0; + fapi2::buffer l_buffer; + + // Combining bits to create timing value (in a buffer) + constexpr size_t MSN_START = 52; + constexpr size_t MSN_LEN = 4; + constexpr size_t LSB_START = 56; + constexpr size_t LSB_LEN = 8; + + l_buffer.insertFromRight( tRASmin_MSN(i_target, i_spd_data) ). + insertFromRight( tRASmin_LSB(i_target, i_spd_data) ); + + // Extract timing value from the buffer into an integral type + constexpr size_t OUTPUT_START = 0; + constexpr size_t OUTPUT_LEN = 64; + + l_buffer.extractToRight(l_timing_val); + + // JEDEC spec limits for this timing value + constexpr int64_t TIMING_LOWER_BOUND = 1; // from JEDEC + constexpr int64_t TIMING_UPPER_BOUND = 4095; // from JEDEC + + // best we can do? + // I had to combine parts from two different bytes. + // But byte 28 of the JEDEC spec explains how to piece this together - AAM + constexpr size_t ERROR_BYTE_INDEX = 28; + + FAPI_TRY(mss::check::spd:: + fail_for_invalid_value(i_target, + (l_timing_val <= TIMING_UPPER_BOUND) && + (l_timing_val >= TIMING_LOWER_BOUND), + ERROR_BYTE_INDEX, + l_timing_val, + "Failed check on the Minimum Active to Precharge Delay Time (tRASmin) in MTB") ); + + // Update output only after check passes + o_value = l_timing_val; + + FAPI_DBG("%s. Minimum Active to Precharge Delay Time (tRASmin) in MTB units: %d", + mss::c_str(i_target), + o_value); + +fapi_try_exit: + return fapi2::current_err; +} + + +/// +/// @brief Decodes SDRAM Minimum Active to Active/Refresh Delay Time in MTB +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value tRCmin in MTB units +/// @return fapi2::ReturnCode +/// @note SPD Byte 27 (bits 7~4) & SPD Byte 29 (bits 7~0) +/// @note Item JC-45-2220.01x +/// @note Page 38 +/// @note DDR4 SPD Document Release 3 +/// @warning If tRCmin cannot be divided evenly by the MTB, +/// this byte must be rounded up to the next larger +/// integer and the Fine Offset for tRCmin (SPD byte 120) +/// used for correction to get the actual value. +/// +fapi2::ReturnCode decoder::min_active_to_active_refresh_delay_time(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) +{ + // Lambda expression to retrieve tRCmin's most significant nibble (MSN) + auto tRCmin_MSN = [](const fapi2::Target& i_target, const uint8_t* i_data) + { + constexpr size_t BYTE_INDEX = 27; + uint8_t l_out = 0; + + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), + BYTE_INDEX, + i_data[BYTE_INDEX]); + + fapi2::buffer l_buffer(i_data[BYTE_INDEX]); + + // Extracting desired bits + l_buffer.extractToRight(l_out); + + return l_out; + }; + + // Lambda expression to retrieve tRCmin's least significant byte (LSB) + auto tRCmin_LSB = [](const fapi2::Target& i_target, const uint8_t* i_data) + { + constexpr size_t BYTE_INDEX = 29; + uint8_t l_out = 0; + + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), + BYTE_INDEX, + i_data[BYTE_INDEX]); + + fapi2::buffer l_buffer(i_data[BYTE_INDEX]); + + // Extracting desired bits + l_buffer.extractToRight(l_out); + + return l_out; + }; + + int64_t l_timing_val = 0; + fapi2::buffer l_buffer; + + // Combining bits to create timing value (in a buffer) + constexpr size_t MSN_START = 52; + constexpr size_t MSN_LEN = 4; + constexpr size_t LSB_START = 56; + constexpr size_t LSB_LEN = 8; + + l_buffer.insertFromRight( tRCmin_MSN(i_target, i_spd_data) ). + insertFromRight( tRCmin_LSB(i_target, i_spd_data) ); - const int64_t MIN_CYCLE_TIME_MTB = 1; // from JEDEC - const int64_t MAX_CYCLE_TIME_MTB = 255; // from JEDEC + // Extract timing value from the buffer into an integral type + constexpr size_t OUTPUT_START = 0; + constexpr size_t OUTPUT_LEN = 64; - const int64_t MIN_CYCLE_TIME_FTB = -128; // from JEDEC - const int64_t MAX_CYCLE_TIME_FTB = 127; // from JEDEC + l_buffer.extractToRight(l_timing_val); - // Targets - const auto l_target_mcs = find_target(i_target_dimm); - const auto l_target_port = find_target(i_target_dimm); + // JEDEC spec limits for this timing value + constexpr int64_t TIMING_LOWER_BOUND = 1; // from JEDEC + constexpr int64_t TIMING_UPPER_BOUND = 4095; // from JEDEC - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); + // best we can do? + // I had to combine parts from two different bytes. + // But byte 29 of the JEDEC spec explains how to piece this together - AAM + constexpr size_t ERROR_BYTE_INDEX = 29; - // Byte variables used for decoding - int64_t l_tAAmin_mtb = 0; - int64_t l_tAAmin_ftb = 0; + FAPI_TRY(mss::check::spd:: + fail_for_invalid_value(i_target, + (l_timing_val <= TIMING_UPPER_BOUND) && + (l_timing_val >= TIMING_LOWER_BOUND), + ERROR_BYTE_INDEX, + l_timing_val, + "Failed check on the Minimum Active to Active/Refresh Delay Time (tRCmin) in MTB") ); - // Attribute variable - int64_t l_min_cas_latency_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; - int64_t l_MTBs[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; - int64_t l_FTBs[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + // Update output only after check passes + o_value = l_timing_val; - // Trace print in the front assists w/ debug - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), - BYTE_INDEX_MTB, - i_spd_data[BYTE_INDEX_MTB]); - - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), - BYTE_INDEX_FTB, - i_spd_data[BYTE_INDEX_FTB]); - - // Retrieve SDRAM Minimum CAS Latency Time - l_tAAmin_mtb = i_spd_data[BYTE_INDEX_MTB]; - - FAPI_TRY(mss::check::spd::valid_value_fail(i_target_dimm, - (l_tAAmin_mtb <= MAX_CYCLE_TIME_MTB) && - (l_tAAmin_mtb >= MIN_CYCLE_TIME_MTB), - BYTE_INDEX_MTB, - l_tAAmin_mtb, - "Failed check for min CAS latency time (tAAmin) in MTB units") ); - - // Retrieve Fine Offset for Minimum CAS Latency Time - // casted int8_t undoes 2's complement on the uint8_t spd data - l_tAAmin_ftb = int8_t(i_spd_data[BYTE_INDEX_FTB]); - - FAPI_TRY(mss::check::spd::valid_value_fail(i_target_dimm, - (l_tAAmin_ftb <= MAX_CYCLE_TIME_FTB) && - (l_tAAmin_ftb >= MIN_CYCLE_TIME_FTB), - BYTE_INDEX_FTB, - l_tAAmin_ftb, - "Failed check for min CAS latency time (tAAmin) in FTB units") ); - - // Retrieving medium timebase (MTB) multiplier used for timing calculation - FAPI_TRY( spd_medium_timebase(l_target_mcs, &l_MTBs[0][0]) ); - FAPI_TRY( spd_fine_timebase(l_target_mcs, &l_FTBs[0][0]) ); - - // Retrive entire MCS level attribute - FAPI_TRY(spd_timing_taamin(l_target_mcs, &l_min_cas_latency_times[0][0])) - - // Update attribute to decoded byte values - l_min_cas_latency_times[PORT_NUM][DIMM_NUM] = calc_timing(l_tAAmin_mtb, - l_tAAmin_ftb, - l_MTBs[PORT_NUM][DIMM_NUM], - l_FTBs[PORT_NUM][DIMM_NUM]); - - // Update MCS level attribute - FAPI_ATTR_SET( fapi2::ATTR_TIMING_TAAMIN, l_target_mcs, l_min_cas_latency_times ); - - // Printed decoded info - FAPI_INF("%s. tAAmin (min cycle time): %d (ps)", - c_str(i_target_dimm), - l_min_cas_latency_times[PORT_NUM][DIMM_NUM] ); + FAPI_DBG("%s. Minimum Active to Active/Refresh Delay Time (tRCmin) in MTB units: %d", + mss::c_str(i_target), + o_value); fapi_try_exit: return fapi2::current_err; } -#if 0 /// -/// @brief Decode CAS Latencies Supported -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data +/// @brief Decodes SDRAM Minimum Refresh Recovery Delay Time 1 +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value tRFC1min in MTB units /// @return fapi2::ReturnCode -/// @note SPD Byte 20-23 +/// @note SPD Byte 30 & Byte 31 +/// @note Item JC-45-2220.01x +/// @note Page 39-40 +/// @note DDR4 SPD Document Release 3 /// -fapi2::ReturnCode decoder::supported_cas_latencies(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::min_refresh_recovery_delay_time_1(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) { - // Immutable constants - const size_t FIRST_BYTE = 20; - const size_t SEC_BYTE = 21; - const size_t THIRD_BYTE = 22; - const size_t FORTH_BYTE = 23; - - // Targets - const auto l_target_mcs = find_target(i_target_dimm); - const auto l_target_port = find_target(i_target_dimm); + // Lambda expression to retrieve tRFC1min's most significant byte (MSB) + auto tRFC1min_MSB = [](const fapi2::Target& i_target, const uint8_t* i_data) + { + constexpr size_t BYTE_INDEX = 31; + uint8_t l_out = 0; - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), + BYTE_INDEX, + i_data[BYTE_INDEX]); - // Byte variables used for decoding - uint64_t l_supported_cas_lat = 0; + fapi2::buffer l_buffer(i_data[BYTE_INDEX]); - // Attribute variables used to set decoded vals - uint64_t l_supported_CLs[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + // Extracting desired bits + l_buffer.extractToRight(l_out); - // Buffers used for bit manipulation - fapi2::buffer l_first_byte_buff(i_spd_data[FIRST_BYTE]); - fapi2::buffer l_second_byte_buff(i_spd_data[SEC_BYTE]); - fapi2::buffer l_third_byte_buff(i_spd_data[THIRD_BYTE]); - fapi2::buffer l_forth_byte_buff(i_spd_data[FORTH_BYTE]); + return l_out; + }; - // Trace print in the front assists w/ debug - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), - BYTE_INDEX, - i_spd_data[BYTE_INDEX]); + // Lambda expression to retrieve tRFC1min's least significant byte (LSB) + auto tRFC1min_LSB = [](const fapi2::Target& i_target, const uint8_t* i_data) + { + constexpr size_t BYTE_INDEX = 30; + uint8_t l_out = 0; - // TODO - update ENUMS to take account to int64_t + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), + BYTE_INDEX, + i_data[BYTE_INDEX]); - // Combine Bytes 20 - 23 to create bitmap - l_first_byte_buff.extractToRight(l_supported_cas_lat). - l_second_byte_buff.extractToRight(l_supported_cas_lat). - l_third_byte_buff.extractToRight(l_supported_cas_lat). - l_forth_byte_buff.extractToRight(l_supported_cas_lat); + fapi2::buffer l_buffer(i_data[BYTE_INDEX]); - // Retrive entire MCS level attribute - FAPI_TRY( cas_latencies_supported(l_target_mcs, &l_supported_CLs[0][0]) ); + // Extracting desired bits + l_buffer.extractToRight(l_out); - // Update attribute to decoded byte values - l_supported_CLs[PORT_NUM][DIMM_NUM] = l_supported_cas_lat; + return l_out; + }; - // Update MCS level attribute - FAPI_ATTR_SET( fapi2::ATTR_SPD_CAS_LATENCIES_SUPPORTED, l_target_mcs, l_supported_CLs ); - // Printed decoded info - FAPI_INF("%s", - c_str(i_target_dimm); - fapi_try_exit: - return fapi2::current_err; -} + int64_t l_timing_val = 0; + fapi2::buffer l_buffer; + // Combining bits to create timing value (in a buffer) + constexpr size_t MSB_START = 48; + constexpr size_t MSB_LEN = 8; + constexpr size_t LSB_START = 56; + constexpr size_t LSB_LEN = 8; + l_buffer.insertFromRight( tRFC1min_MSB(i_target, i_spd_data) ). + insertFromRight( tRFC1min_LSB(i_target, i_spd_data) ); -/// -/// @brief Decode Minimum RAS to CAS Delay Time -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data -/// @return fapi2::ReturnCode -/// @note SPD Byte 25 -/// -fapi2::ReturnCode decoder::min_ras_to_cas_delay_time(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) -{ - // Immutable constants - const size_t BYTE_INDEX = 25; + // Extract timing value from the buffer into an integral type + constexpr size_t OUTPUT_START = 0; + constexpr size_t OUTPUT_LEN = 64; - // Targets - const auto l_target_mcs = find_target(i_target_dimm); - const auto l_target_port = find_target(i_target_dimm); + l_buffer.extractToRight(l_timing_val); - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); + // JEDEC spec limits for this timing value + constexpr int64_t TIMING_LOWER_BOUND = 1; // from JEDEC + constexpr int64_t TIMING_UPPER_BOUND = 65535; // from JEDEC - // Attribute variable (rcd = ras to cas delay) - int64_t l_min_rcd_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + // best we can do? + // I had to combine parts from two different bytes. + // Chose one of them (byte 30) to for error printout of this decode + constexpr size_t ERROR_BYTE_INDEX = 30; - // Trace print in the front assists w/ debug - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), - BYTE_INDEX, - i_spd_data[BYTE_INDEX]); + FAPI_TRY(mss::check::spd:: + fail_for_invalid_value(i_target, + (l_timing_val <= TIMING_UPPER_BOUND) && + (l_timing_val >= TIMING_LOWER_BOUND), + ERROR_BYTE_INDEX, + l_timing_val, + "Failed check on the Minimum Refresh Recovery Delay Time 1 (tRFC1min) in MTB") ); - // Retrive entire MCS level attribute - FAPI_TRY( eff_dram_trcd(l_target_mcs, &l_min_rcd_times[0][0]) ); + // Update output only after check passes + o_value = l_timing_val; - // Update attribute to decoded byte values - l_min_rcd_times[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) ); + FAPI_DBG("%s. Minimum Refresh Recovery Delay Time 1 (tRFC1min) in MTB units: %d", + mss::c_str(i_target), + o_value); - // Update MCS level attribute - FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TRCD, l_target_mcs, l_min_rcd_times ); - // Printed decoded info - FAPI_INF("%s", - c_str(i_target_dimm); - fapi_try_exit: - return fapi2::current_err; +fapi_try_exit: + return fapi2::current_err; } /// -/// @brief Decode Minimum Row Precharge Delay Time -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data +/// @brief Decodes SDRAM Minimum Refresh Recovery Delay Time 2 +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value tRFC2min in MTB units /// @return fapi2::ReturnCode -/// @note SPD Byte 26 +/// @note SPD Byte 32 & Byte 33 +/// @note Item JC-45-2220.01x +/// @note Page 40 +/// @note DDR4 SPD Document Release 3 /// -fapi2::ReturnCode decoder::min_row_precharge_delay_time(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::min_refresh_recovery_delay_time_2(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX = 26; + // Lambda expression to retrieve tRFC2min's most significant byte (MSB) + auto tRFC2min_MSB = [](const fapi2::Target& i_target, const uint8_t* i_data) + { + constexpr size_t BYTE_INDEX = 33; + uint8_t l_out = 0; - // Targets - const auto l_target_mcs = find_target(i_target_dimm); - const auto l_target_port = find_target(i_target_dimm); + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), + BYTE_INDEX, + i_data[BYTE_INDEX]); - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); + fapi2::buffer l_buffer(i_data[BYTE_INDEX]); - // Attribute variable (rp = row to precharge) - int64_t l_min_rp_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + // Extracting desired bits + l_buffer.extractToRight(l_out); - // Trace print in the front assists w/ debug - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), - BYTE_INDEX, - i_spd_data[BYTE_INDEX]); + return l_out; + }; - // Retrive entire MCS level attribute - FAPI_TRY( eff_dram_trp(l_target_mcs, &l_min_rp_times[0][0]) ); + // Lambda expression to retrieve tRFC2min's least significant byte (LSB) + auto tRFC2min_LSB = [](const fapi2::Target& i_target, const uint8_t* i_data) + { + constexpr size_t BYTE_INDEX = 32; + uint8_t l_out = 0; - // Update attribute to decoded byte values - l_min_rp_times[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) ); + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), + BYTE_INDEX, + i_data[BYTE_INDEX]); - // Update MCS level attribute - FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TRP, l_target_mcs, l_min_rp_times ); - // Printed decoded info - FAPI_INF("%s", - c_str(i_target_dimm); - fapi_try_exit: - return fapi2::current_err; -} + fapi2::buffer l_buffer(i_data[BYTE_INDEX]); -/// -/// @brief Decode Minimum Active to Precharge Delay Time (tRASmin) -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data -/// @return fapi2::ReturnCode -/// @note Byte 27 Bits 3~0 along with Byte 28 Bits 7~0 -/// -fapi2::ReturnCode decoder::min_activate_to_precharge_delay_time(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) -{ - // Immutable constants - const size_t BYTE_INDEX_MSB = 27; // MSN = most significant byte - const size_t BYTE_INDEX_LSB = 28; // LSB = least significant byte + // Extracting desired bits + l_buffer.extractToRight(l_out); - // Targets - const auto l_target_mcs = find_target(i_target_dimm); - const auto l_target_port = find_target(i_target_dimm); + return l_out; + }; - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); + int64_t l_timing_val = 0; + fapi2::buffer l_buffer; - // Byte variables used for decoding (tRAS = Active to Precharge Delay Time) - int64_t l_tRASmin = 0; + // Combining bits to create timing value (in a buffer) + constexpr size_t MSB_START = 48; + constexpr size_t MSB_LEN = 8; + constexpr size_t LSB_START = 56; + constexpr size_t LSB_LEN = 8; - // Attribute variable - int64_t l_min_ras_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + l_buffer.insertFromRight( tRFC2min_MSB(i_target, i_spd_data) ). + insertFromRight( tRFC2min_LSB(i_target, i_spd_data) ); - // Buffers used for bit manipulation - fapi2::buffer l_buffer_upper_nibble(i_spd_data[BYTE_INDEX_MSB]); - fapi2::buffer l_buffer_lower_byte(i_spd_data[BYTE_INDEX_LSB]); + // Extract timing value from the buffer into an integral type + constexpr size_t OUTPUT_START = 0; + constexpr size_t OUTPUT_LEN = 64; - // Trace print in the front assists w/ debug - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), - BYTE_INDEX, - i_spd_data[BYTE_INDEX]); + l_buffer.extractToRight(l_timing_val); + + // JEDEC spec limits for this timing value + constexpr int64_t TIMING_LOWER_BOUND = 1; // from JEDEC + constexpr int64_t TIMING_UPPER_BOUND = 65535; // from JEDEC - // TODO - update ENUMS to take account to int64_t + // best we can do? + // I had to combine parts from two different bytes. + // Chose one of them (byte 33) to for error printout of this decode + constexpr size_t ERROR_BYTE_INDEX = 33; - // Combining bits to create timing value - l_buffer_upper_nibble.extractToRight(l_tRASmin); - l_buffer_lower_byte.extractToRight(l_tRASmin); + FAPI_TRY(mss::check::spd:: + fail_for_invalid_value(i_target, + (l_timing_val <= TIMING_UPPER_BOUND) && + (l_timing_val >= TIMING_LOWER_BOUND), + ERROR_BYTE_INDEX, + l_timing_val, + "Failed check on the Minimum Refresh Recovery Delay Time 2 (tRFC2min) in MTB") ); - // Retrive entire MCS level attribute - FAPI_TRY( eff_dram_tras(l_target_mcs, &l_min_ras_times[0][0]) ); + // Update output only after check passes + o_value = l_timing_val; - // Update attribute to decoded byte values (returning picoseconds) - l_min_ras_times[PORT_NUM][DIMM_NUM] = ns_to_ps(l_tRASmin); + FAPI_DBG("%s. Minimum Refresh Recovery Delay Time 2 (tRFC2min) in MTB units: %d", + mss::c_str(i_target), + o_value); - // Update MCS level attribute - FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TRAS, l_target_mcs, l_min_ras_times ); - // Printed decoded info - FAPI_INF("%s", - c_str(i_target_dimm); - fapi_try_exit: - return fapi2::current_err; +fapi_try_exit: + return fapi2::current_err; } /// -/// @brief Minimum Active to Active/Refresh Delay Time (tRCmin) -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data +/// @brief Decodes SDRAM Minimum Refresh Recovery Delay Time 4 +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value tRFC4min in MTB units /// @return fapi2::ReturnCode -/// @note SPD Byte Byte 27 Bits 7~4 along with Byte 29 Bits 7~0 +/// @note SPD Byte 34 & Byte 35 +/// @note Item JC-45-2220.01x +/// @note Page 40 +/// @note DDR4 SPD Document Release 3 /// -fapi2::ReturnCode -decoder::min_activate_to_activate_refresh_delay_time(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::min_refresh_recovery_delay_time_4(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX_MSN = 27; // MSN = most significant nibble - const size_t BYTE_INDEX_LSB = 28; // LSB = least significant byte - - // Targets - const auto l_target_mcs = find_target(i_target_dimm); - const auto l_target_port = find_target(i_target_dimm); - - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); + // Lambda expression to retrieve tRFC4min's most significant byte (MSB) + auto tRFC4min_MSB = [](const fapi2::Target& i_target, const uint8_t* i_data) + { + constexpr size_t BYTE_INDEX = 35; + uint8_t l_out = 0; - // Byte variables used for decoding (RC = Activate to Activate/Refresh Delay) - uint16_t l_tRCmin = 0; + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), + BYTE_INDEX, + i_data[BYTE_INDEX]); - // Attribute variable - uint16_t l_min_rc_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + fapi2::buffer l_buffer(i_data[BYTE_INDEX]); - // TODO - update ENUMS to take account to int64_t + // Extracting desired bits + l_buffer.extractToRight(l_out); - // Buffers used for bit manipulation - fapi2::buffer l_buffer_upper_nibble(i_spd_data[BYTE_INDEX_MSN]); - fapi2::buffer l_buffer_lower_byte(i_spd_data[BYTE_INDEX_LSB]); + return l_out; + }; - // Trace print in the front assists w/ debug - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), - BYTE_INDEX, - i_spd_data[BYTE_INDEX]); + // Lambda expression to retrieve tRFC4min's least significant byte (LSB) + auto tRFC4min_LSB = [](const fapi2::Target& i_target, const uint8_t* i_data) + { + constexpr size_t BYTE_INDEX = 34; + uint8_t l_out = 0; - // Combining bits to create timing value - l_buffer_upper_nibble.extractToRight(l_tRCmin); - l_buffer_lower_byte.extractToRight(l_tRCmin); + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), + BYTE_INDEX, + i_data[BYTE_INDEX]); - // Retrive entire MCS level attribute - FAPI_TRY( eff_dram_trc(l_target_mcs, &l_min_rc_times[0][0]) ); + fapi2::buffer l_buffer(i_data[BYTE_INDEX]); - // Update attribute to decoded byte values (returning picoseconds, currently nanoseconds) - l_min_rc_times[PORT_NUM][DIMM_NUM] = ns_to_ps(l_tRCmin); + // Extracting desired bits + l_buffer.extractToRight(l_out); - // Update MCS level attribute (returning picoseconds, currently nanoseconds) - FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TRC, l_target_mcs, l_min_rc_times ); - // Printed decoded info - FAPI_INF("%s", - c_str(i_target_dimm); - fapi_try_exit: - return fapi2::current_err; -} + return l_out; + }; -/// -/// @brief Minimum Refresh Recovery Delay Time 1 (tRFC1min) -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data -/// @return fapi2::ReturnCode -/// @note SPD Byte Byte 30 (LSB) along with Byte 31 (MSB) -/// -fapi2::ReturnCode decoder::min_refresh_recovery_delay_time_1(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) -{ - // Immutable constants - const size_t BYTE_INDEX_MSB = 31; // MSN = most significant nibble - const size_t BYTE_INDEX_LSB = 30; // LSB = least significant byte + int64_t l_timing_val = 0; + fapi2::buffer l_buffer; - // Targets - const auto l_target_mcs = find_target(i_target_dimm); - const auto l_target_port = find_target(i_target_dimm); + // Combining bits to create timing value (in a buffer) + constexpr size_t MSB_START = 48; + constexpr size_t MSB_LEN = 8; + constexpr size_t LSB_START = 56; + constexpr size_t LSB_LEN = 8; - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); + l_buffer.insertFromRight( tRFC4min_MSB(i_target, i_spd_data) ). + insertFromRight( tRFC4min_LSB(i_target, i_spd_data) ); - // Byte variables used for decoding (RFC1 = Minimum Refresh Recovery Delay Time) - uint32_t l_tRFC1min = 0; + // Extract timing value from the buffer into an integral type + constexpr size_t OUTPUT_START = 0; + constexpr size_t OUTPUT_LEN = 64; - // Attribute variable - uint32_t l_min_rfc1_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + l_buffer.extractToRight(l_timing_val); - // Buffers used for bit manipulation - fapi2::buffer l_buffer_MSB(i_spd_data[BYTE_INDEX_MSB]); - fapi2::buffer l_buffer_LSB(i_spd_data[BYTE_INDEX_LSB]); + // JEDEC spec limits for this timing value + constexpr int64_t TIMING_LOWER_BOUND = 1; // from JEDEC + constexpr int64_t TIMING_UPPER_BOUND = 65535; // from JEDEC - // Trace print in the front assists w/ debug - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), - BYTE_INDEX, - i_spd_data[BYTE_INDEX]); + // best we can do? + // I had to combine parts from two different bytes. + // Chose one of them (byte 34) for error printout of this decode + constexpr size_t ERROR_BYTE_INDEX = 34; - // Combining bits to create timing value - l_buffer_MSB.extractToRight<, >(); - l_buffer_LSB.extractToRight<, >(); + FAPI_TRY(mss::check::spd:: + fail_for_invalid_value(i_target, + (l_timing_val <= TIMING_UPPER_BOUND) && + (l_timing_val >= TIMING_LOWER_BOUND), + ERROR_BYTE_INDEX, + l_timing_val, + "Failed check on the Minimum Refresh Recovery Delay Time 4 (tRFC4min) in MTB") ); - // Retrive entire MCS level attribute - FAPI_TRY( eff_dram_trc(l_target_mcs, &l_min_rfc1_times[0][0]) ); + // Update output only after check passes + o_value = l_timing_val; - // Update attribute to decoded byte values (returning picoseconds, currently nanoseconds) - l_min_rfc1_times[PORT_NUM][DIMM_NUM] = ns_to_ps(l_tRFC1min); + FAPI_DBG("%s. Minimum Refresh Recovery Delay Time 4 (tRFC4min) in MTB units: %d", + mss::c_str(i_target), + o_value); - // Update MCS level attribute (returning picoseconds, currently nanoseconds) - FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TRFC1, l_target_mcs, l_min_rfc1_times ); - // Printed decoded info - FAPI_INF("%s", - c_str(i_target_dimm); - fapi_try_exit: - return fapi2::current_err; +fapi_try_exit: + return fapi2::current_err; } /// -/// @brief Minimum Refresh Recovery Delay Time 2 (tRFC2min) -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data +/// @brief Decodes SDRAM Minimum Four Activate Window Delay Time +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value tFAWmin in MTB units /// @return fapi2::ReturnCode -/// @note SPD Byte Byte 32 (LSB) along with Byte 33 (MSB) +/// @note SPD Byte 36 (bits 3~0) & Byte 37 (bits 7~0) +/// @note Item JC-45-2220.01x +/// @note Page 42 +/// @note DDR4 SPD Document Release 3 /// -fapi2::ReturnCode decoder::min_refresh_recovery_delay_time_2(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::min_tfaw(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX_MSB = 33; // MSN = most significant nibble - const size_t BYTE_INDEX_LSB = 32; // LSB = least significant byte - - // Targets - const auto l_target_mcs = find_target(i_target_dimm); - const auto l_target_port = find_target(i_target_dimm); + // Lambda expression to retrieve tFAWmin's most significant nibble (MSN) + auto tFAWmin_MSN = [](const fapi2::Target& i_target, const uint8_t* i_data) + { + constexpr size_t BYTE_INDEX = 36; + uint8_t l_out = 0; - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), + BYTE_INDEX, + i_data[BYTE_INDEX]); - // Byte variables used for decoding (RFC1 = Minimum Refresh Recovery Delay 2) - uint32_t l_tRFC2min = 0; + fapi2::buffer l_buffer(i_data[BYTE_INDEX]); - // Attribute variable - uint32_t l_min_rfc2_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + // Extracting desired bits + l_buffer.extractToRight(l_out); - // Buffers used for bit manipulation - fapi2::buffer l_buffer_MSB(i_spd_data[BYTE_INDEX_MSB]); - fapi2::buffer l_buffer_LSB(i_spd_data[BYTE_INDEX_LSB]); + return l_out; + }; - // Trace print in the front assists w/ debug - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), - BYTE_INDEX, - i_spd_data[BYTE_INDEX]); + // Lambda expression to retrieve tFAWmin's least significant byte (LSB) + auto tFAWmin_LSB = [](const fapi2::Target& i_target, const uint8_t* i_data) + { + constexpr size_t BYTE_INDEX = 37; + uint8_t l_out = 0; - // Combining bits to create timing value - l_buffer_MSB.extractToRight<, >(); - l_buffer_LSB.extractToRight<, >(); + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), + BYTE_INDEX, + i_data[BYTE_INDEX]); - // Retrive entire MCS level attribute - FAPI_TRY( eff_dram_trc(l_target_mcs, &l_min_rfc2_times[0][0]) ); + fapi2::buffer l_buffer(i_data[BYTE_INDEX]); - // Update attribute to decoded byte values (returning picoseconds, currently nanoseconds) - l_min_rfc1_times[PORT_NUM][DIMM_NUM] = ns_to_ps(l_tRFC2min); + // Extracting desired bits + l_buffer.extractToRight(l_out); - // Update MCS level attribute (returning picoseconds, currently nanoseconds) - FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TRFC2, l_target_mcs, l_min_rfc2_times ); - // Printed decoded info - FAPI_INF("%s", - c_str(i_target_dimm); - fapi_try_exit: - return fapi2::current_err; -} + return l_out; + }; -/// -/// @brief Minimum Refresh Recovery Delay Time 4 (tRFC4min) -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data -/// @return fapi2::ReturnCode -/// @note SPD Byte Byte 34 (LSB) along with Byte 5 (MSB) -/// -fapi2::ReturnCode decoder::min_refresh_recovery_delay_time_4(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) -{ - // Immutable constants - const size_t BYTE_INDEX_MSB = 35; // MSN = most significant nibble - const size_t BYTE_INDEX_LSB = 34; // LSB = least significant byte + int64_t l_timing_val = 0; + fapi2::buffer l_buffer; - // Targets - const auto l_target_mcs = find_target(i_target_dimm); - const auto l_target_port = find_target(i_target_dimm); + // Combining bits to create timing value (in a buffer) + constexpr size_t MSN_START = 52; + constexpr size_t MSN_LEN = 4; + constexpr size_t LSB_START = 56; + constexpr size_t LSB_LEN = 8; - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); + l_buffer.insertFromRight( tFAWmin_MSN(i_target, i_spd_data) ). + insertFromRight( tFAWmin_LSB(i_target, i_spd_data) ); - // Byte variables used for decoding (RFC4 = Minimum Refresh Recovery Delay 4) - uint32_t l_tRFC4min = 0; + // Extract timing value from the buffer into an integral type + constexpr size_t OUTPUT_START = 0; + constexpr size_t OUTPUT_LEN = 64; - // Attribute variable - uint32_t l_min_rfc4_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + l_buffer.extractToRight(l_timing_val); - // Buffers used for bit manipulation - fapi2::buffer l_buffer_MSB(i_spd_data[BYTE_INDEX_MSB]); - fapi2::buffer l_buffer_LSB(i_spd_data[BYTE_INDEX_LSB]); + // JEDEC spec limits for this timing value + constexpr int64_t TIMING_LOWER_BOUND = 1; // from JEDEC + constexpr int64_t TIMING_UPPER_BOUND = 65535; // from JEDEC - // Trace print in the front assists w/ debug - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), - BYTE_INDEX, - i_spd_data[BYTE_INDEX]); + // best we can do? + // I had to combine parts from two different bytes. + // Chose one of them (byte 37) to for error printout of this decode + constexpr size_t ERROR_BYTE_INDEX = 37; - // Combining bits to create timing value - l_buffer_MSB.extractToRight<, >(); - l_buffer_LSB.extractToRight<, >(); + FAPI_TRY(mss::check::spd:: + fail_for_invalid_value(i_target, + (l_timing_val <= TIMING_UPPER_BOUND) && + (l_timing_val >= TIMING_LOWER_BOUND), + ERROR_BYTE_INDEX, + l_timing_val, + "Failed check on the Minimum Four Activate Window Delay Time (tFAWmin) in MTB") ); - // Retrive entire MCS level attribute - FAPI_TRY( eff_dram_trc(l_target_mcs, &l_min_rfc4_times[0][0]) ); + // Update output only after check passes + o_value = l_timing_val; - // Update attribute to decoded byte values (returning picoseconds, currently nanoseconds) - l_min_rfc1_times[PORT_NUM][DIMM_NUM] = ns_to_ps(l_tRFC4min); + FAPI_DBG("%s. Minimum Four Activate Window Delay Time (tFAWmin) in MTB units: %d", + mss::c_str(i_target), + o_value); - // Update MCS level attribute (returning picoseconds, currently nanoseconds) - FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TRFC2, l_target_mcs, l_min_rfc4_times ); - // Printed decoded info - FAPI_INF("%s", - c_str(i_target_dimm); - fapi_try_exit: - return fapi2::current_err; +fapi_try_exit: + return fapi2::current_err; } /// -/// @brief Minimum Four Activate Window Delay Time (t FAW min) -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data +/// @brief Decodes Minimum Activate to Activate Delay Time - Different Bank Group +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value tRRD_Smin MTB units /// @return fapi2::ReturnCode -/// @note Byte 36 Bits 3 ~ 0 along with Byte 37 Bits 7 ~ 0 +/// @note SPD Byte 38 +/// @note Item JC-45-2220.01x +/// @note Page 43 +/// @note DDR4 SPD Document Release 3 +/// @warning If tRRD_Smin cannot be divided evenly by the MTB, +/// this byte must be rounded up to the next larger +/// integer and the Fine Offset for tRRD_Smin (SPD byte 119) +/// used for correction to get the actual value. /// -fapi2::ReturnCode decoder::min_four_activate_window_time(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::min_trrd_s(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX_MSN = 36; // MSN = most significant nibble - const size_t BYTE_INDEX_LSB = 37; // LSB = least significant byte - - // Targets - const auto l_target_mcs = find_target(i_target_dimm); - const auto l_target_port = find_target(i_target_dimm); - - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); + constexpr size_t BYTE_INDEX = 38; + constexpr int64_t TIMING_LOWER_BOUND = 1; // from JEDEC + constexpr int64_t TIMING_UPPER_BOUND = 255; // from JEDEC - // Byte variables used for decoding (FAW = Four Activate Window Delay) - uint16_t l_tFAW = 0; - // Attribute variable - uint16_t l_min_faw_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + // Retrieve Minimum Activate to Activate Delay Time - Different Bank Group + // explicit conversion to int64_t + int64_t l_timing_val = int64_t(i_spd_data[BYTE_INDEX]); - // TODO - update ENUMS to take account to int64_t - - // Buffers used for bit manipulation - fapi2::buffer l_buffer_upper_nibble(i_spd_data[BYTE_INDEX_MSN]); - fapi2::buffer l_buffer_lower_byte(i_spd_data[BYTE_INDEX_LSB]); - - // Trace print in the front assists w/ debug - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), BYTE_INDEX, - i_spd_data[BYTE_INDEX]); + l_timing_val); - // Combining bits to create timing value - l_buffer_upper_nibble.extractToRight(l_tFAW); - l_buffer_lower_byte.extractToRight(l_tFAW); + FAPI_TRY(mss::check::spd:: + fail_for_invalid_value(i_target, + (l_timing_val <= TIMING_UPPER_BOUND) && + (l_timing_val >= TIMING_LOWER_BOUND), + BYTE_INDEX, + l_timing_val, + "Failed check on Minimum Activate to Activate Delay Time - Different Bank Group (tRRD_Smin) in MTB") ); - // Retrive entire MCS level attribute - FAPI_TRY( eff_dram_trc(l_target_mcs, &l_min_faw_times[0][0]) ); + // Update output value only if range check passes + o_value = l_timing_val; - // Update attribute to decoded byte values (returning picoseconds, currently nanoseconds) - l_min_faw_times[PORT_NUM][DIMM_NUM] = ns_to_ps(l_tFAW); + FAPI_DBG("%s. Minimum Activate to Activate Delay Time - Different Bank Group (tRRD_Smin) in MTB units: %d", + mss::c_str(i_target), + o_value); - // Update MCS level attribute (returning picoseconds, currently nanoseconds) - FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TRC, l_target_mcs, l_min_faw_times ); - // Printed decoded info - FAPI_INF("%s", - c_str(i_target_dimm); - fapi_try_exit: - return fapi2::current_err; +fapi_try_exit: + return fapi2::current_err; } /// -/// @brief Minimum Activate to Activate Delay Time (tRRD_Smin) -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data +/// @brief Decodes Minimum Activate to Activate Delay Time - Same Bank Group +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value tRRD_Lmin MTB units /// @return fapi2::ReturnCode -/// @note Byte 38 +/// @note SPD Byte 39 +/// @note Item JC-45-2220.01x +/// @note Page 43-44 +/// @note DDR4 SPD Document Release 3 +/// @warning If tRRD_Lmin cannot be divided evenly by the MTB, +/// this byte must be rounded up to the next larger +/// integer and the Fine Offset for tRRD_Lmin (SPD byte 118) +/// used for correction to get the actual value. /// -fapi2::ReturnCode -decoder::min_act_to_act_delay_time_diff_bank_group(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::min_trrd_l(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX = 38; + constexpr size_t BYTE_INDEX = 39; + constexpr int64_t TIMING_LOWER_BOUND = 1; // from JEDEC + constexpr int64_t TIMING_UPPER_BOUND = 255; // from JEDEC - // Targets - const auto l_target_mcs = find_target(i_target_dimm); - const auto l_target_port = find_target(i_target_dimm); - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); + // Retrieve Minimum Activate to Activate Delay Time - Same Bank Group + // explicit conversion to int64_t + int64_t l_timing_val = int64_t(i_spd_data[BYTE_INDEX]); - // Attribute variable (rrd_s = Activate to Activate Delay) - int64_t l_min_tRRD_S[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; - - // Trace print in the front assists w/ debug - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), BYTE_INDEX, - i_spd_data[BYTE_INDEX]); + l_timing_val); - // Retrive entire MCS level attribute - FAPI_TRY( eff_dram_trrd(l_target_mcs, &l_min_tRRD_S[0][0]) ); + FAPI_TRY(mss::check::spd:: + fail_for_invalid_value(i_target, + (l_timing_val <= TIMING_UPPER_BOUND) && + (l_timing_val >= TIMING_LOWER_BOUND), + BYTE_INDEX, + l_timing_val, + "Failed check on Minimum Activate to Activate Delay Time - Same Bank Group (tRRD_Lmin) in MTB") ); - // Update attribute to decoded byte values - l_min_tRRD_S[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) ); + // Update output value only if range check passes + o_value = l_timing_val; - // Update MCS level attribute - FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TRRD_S, l_target_mcs, l_min_tRRD_S ); - // Printed decoded info - FAPI_INF("%s", - c_str(i_target_dimm); - fapi_try_exit: - return fapi2::current_err; + FAPI_DBG("%s. Minimum Activate to Activate Delay Time - Same Bank Group (tRRD_Lmin) in MTB units: %d", + mss::c_str(i_target), + o_value); + +fapi_try_exit: + return fapi2::current_err; } /// -/// @brief Minimum Activate to Activate Delay Time (tRRD_Lmin), samebank group -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data +/// @brief Decodes Minimum CAS to CAS Delay Time - Same Bank Group +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value tCCD_Lmin MTB units /// @return fapi2::ReturnCode -/// @note Byte 39 +/// @note SPD Byte 40 +/// @note Item JC-45-2220.01x +/// @note Page 44-45 +/// @note DDR4 SPD Document Release 3 +/// @warning If tCCD_Lmin cannot be divided evenly by the MTB, +/// this byte must be rounded up to the next larger +/// integer and the Fine Offset for tCCD_Lmin (SPD byte 117) +/// used for correction to get the actual value. /// -fapi2::ReturnCode -decoder::min_act_to_act_delay_time_same_bank_group(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::min_tccd_l(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX = 39; - - // Targets - const auto l_target_mcs = find_target(i_target_dimm); - const auto l_target_port = find_target(i_target_dimm); + constexpr size_t BYTE_INDEX = 40; + constexpr int64_t TIMING_LOWER_BOUND = 1; // from JEDEC + constexpr int64_t TIMING_UPPER_BOUND = 255; // from JEDEC - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); - // Attribute variable (rrd_s = Activate to Activate Delay) - int64_t l_min_tRRD_S[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + // Retrieve Minimum CAS to CAS Delay Time - Same Bank Group + // explicit conversion to int64_t + int64_t l_timing_val = int64_t(i_spd_data[BYTE_INDEX]); - // Trace print in the front assists w/ debug - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), BYTE_INDEX, - i_spd_data[BYTE_INDEX]); + l_timing_val); - // Retrive entire MCS level attribute - FAPI_TRY( eff_dram_trrd(l_target_mcs, &l_min_tRRD_S[0][0]) ); + FAPI_TRY(mss::check::spd:: + fail_for_invalid_value(i_target, + (l_timing_val <= TIMING_UPPER_BOUND) && + (l_timing_val >= TIMING_LOWER_BOUND), + BYTE_INDEX, + l_timing_val, + "Failed check on Minimum CAS to CAS Delay Time - Same Bank Group (tCCD_Lmin) in MTB") ); - // Update attribute to decoded byte values - l_min_tRRD_S[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) ); + // Update output value only if range check passes + o_value = l_timing_val; - // Update MCS level attribute - FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TRRD_L, l_target_mcs, l_min_tRRD_S ); + FAPI_DBG("%s. Minimum CAS to CAS Delay Time - Same Bank Group (tCCD_Lmin) in MTB units: %d", + mss::c_str(i_target), + o_value); - // Printed decoded info - FAPI_INF("%s", - c_str(i_target_dimm); - fapi_try_exit: - return fapi2::current_err; +fapi_try_exit: + return fapi2::current_err; } /// -/// @brief Minimum CAS to CAS Delay Time (tCCD_Lmin), same bank group -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data +/// @brief Decodes Minimum Write Recovery Time +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value tWRmin in MTB units /// @return fapi2::ReturnCode -/// @note Byte 40 +/// @note SPD Byte 41 (bits 3~0) & Byte 42 (bits 7~0) +/// @note Item JC-45-2220.01x +/// @note Page 40 +/// @note DDR4 SPD Document Release 3 /// -fapi2::ReturnCode decoder::min_cas_to_cas_delay_time(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::min_write_recovery_time(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX = 40; + // Lambda expression to retrieve tWRmin's most nibble byte (MSN) + auto tWRmin_MSN = [](const fapi2::Target& i_target, const uint8_t* i_data) + { + constexpr size_t BYTE_INDEX = 41; + uint8_t l_out = 0; - // Targets - const auto l_target_mcs = find_target(i_target_dimm); - const auto l_target_port = find_target(i_target_dimm); + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), + BYTE_INDEX, + i_data[BYTE_INDEX]); - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); + fapi2::buffer l_buffer(i_data[BYTE_INDEX]); - // Attribute variable (CCD_L = Minimum CAS to CAS Delay Time, same bank group) - int64_t l_min_tCCD_L[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + // Extracting desired bits + l_buffer.extractToRight(l_out); - // Trace print in the front assists w/ debug - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), - BYTE_INDEX, - i_spd_data[BYTE_INDEX]); + return l_out; + }; - // Retrive entire MCS level attribute - FAPI_TRY( eff_dram_trrd(l_target_mcs, &l_min_tCCD_L[0][0]) ); + // Lambda expression to retrieve tWRmin's least significant byte (LSB) + auto tWRmin_LSB = [](const fapi2::Target& i_target, const uint8_t* i_data) + { + constexpr size_t BYTE_INDEX = 42; + uint8_t l_out = 0; - // Update attribute to decoded byte values - l_min_tCCD_L[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) ); + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), + BYTE_INDEX, + i_data[BYTE_INDEX]); - // Update MCS level attribute - FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TCCD_L, l_target_mcs, l_min_tCCD_L ); + fapi2::buffer l_buffer(i_data[BYTE_INDEX]); - // Printed decoded info - FAPI_INF("%s", - c_str(i_target_dimm); - fapi_try_exit: - return fapi2::current_err; -} + // Extracting desired bits + l_buffer.extractToRight(l_out); -/// -/// @brief Minimum Write Recovery Time (tWRmin) -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data -/// @return fapi2::ReturnCode -/// @note Byte 41 Bits 3~0, Byte 42 Bits 7~0 -/// -fapi2::ReturnCode decoder::min_write_recovery_time(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) -{ - // Immutable constants - const size_t BYTE_INDEX_MSN = 41; // MSN = most significant nibble - const size_t BYTE_INDEX_LSB = 42; // LSB = least significant byte + return l_out; + }; - // Targets - const auto l_target_mcs = find_target(i_target_dimm); - const auto l_target_port = find_target(i_target_dimm); + int64_t l_timing_val = 0; + fapi2::buffer l_buffer; - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); + // Combining bits to create timing value (in a buffer) + constexpr size_t MSN_START = 52; + constexpr size_t MSN_LEN = 4; + constexpr size_t LSB_START = 56; + constexpr size_t LSB_LEN = 8; - // Byte variables used for decoding (FAW = Four Activate Window Delay) - uint16_t l_tWRmin = 0; + l_buffer.insertFromRight( tWRmin_MSN(i_target, i_spd_data) ). + insertFromRight( tWRmin_LSB(i_target, i_spd_data) ); - // Attribute variable - int64_t l_min_wr_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + // Extract timing value from the buffer into an integral type + constexpr size_t OUTPUT_START = 0; + constexpr size_t OUTPUT_LEN = 64; - // TODO - update ENUMS to take account to int64_t + l_buffer.extractToRight(l_timing_val); - // Buffers used for bit manipulation - fapi2::buffer l_buffer_upper_nibble(i_spd_data[BYTE_INDEX_MSN]); - fapi2::buffer l_buffer_lower_byte(i_spd_data[BYTE_INDEX_LSB]); + // JEDEC spec limits for this timing value + // This value used to be reserved to 0 - before spec update + // constexpr int64_t TIMING_LOWER_BOUND = 1; // from JEDEC - // Trace print in the front assists w/ debug - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), - BYTE_INDEX, - i_spd_data[BYTE_INDEX]); + constexpr int64_t TIMING_LOWER_BOUND = 0; + constexpr int64_t TIMING_UPPER_BOUND = 4095; // from JEDEC - // Combining bits to create timing value - l_buffer_upper_nibble.insert<, >(l_tWRmin); - l_buffer_lower_byte.insert<, >(l_tWRmin); + // best we can do? + // I had to combine parts from two different bytes. + // Chose one of them (byte 42) to for error printout of this decode + constexpr size_t ERROR_BYTE_INDEX = 42; - // Retrive entire MCS level attribute - FAPI_TRY( eff_dram_twr(l_target_mcs, &l_min_wr_times[0][0]) ); + FAPI_TRY(mss::check::spd:: + fail_for_invalid_value(i_target, + (l_timing_val <= TIMING_UPPER_BOUND) && + (l_timing_val >= TIMING_LOWER_BOUND), + ERROR_BYTE_INDEX, + l_timing_val, + "Failed check on the Minimum Write Recovery Time (tWRmin) in MTB") ); - // Update attribute to decoded byte values (returning picoseconds, currently nanoseconds) - l_min_wr_times[PORT_NUM][DIMM_NUM] = ns_to_ps(l_tWRmin); + // Update output only after check passes + o_value = l_timing_val; - // Update MCS level attribute (returning picoseconds, currently nanoseconds) - FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TWR, l_target_mcs, l_min_wr_times ); - // Printed decoded info - FAPI_INF("%s", - c_str(i_target_dimm); - fapi_try_exit: - return fapi2::current_err; + FAPI_DBG("%s. Minimum Write Recovery Time (tWRmin) in MTB units: %d", + mss::c_str(i_target), + o_value); + +fapi_try_exit: + return fapi2::current_err; } + /// -/// @brief Minimum Write to Read Time (tWTR_Smin), different bank group -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data +/// @brief Decodes Minimum Write to Read Time - Different Bank Group +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value tWRT_Smin in MTB units /// @return fapi2::ReturnCode -/// @note Byte 43 Bits 3~0, Byte 44 Bits 7~0 +/// @note SPD Byte 43 (bits 3~0) & Byte 44 (bits 7~0) +/// @note Item JC-45-2220.01x +/// @note Page 40 +/// @note DDR4 SPD Document Release 3 /// -fapi2::ReturnCode decoder::min_write_to_read_time_diff_bank_group(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::min_twtr_s(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX_MSN = 43; // MSN = most significant nibble - const size_t BYTE_INDEX_LSB = 44; // LSB = least significant byte + // Lambda expression to retrieve tWRT_Smin's most nibble byte (MSN) + auto tWRT_Smin_MSN = [](const fapi2::Target& i_target, const uint8_t* i_data) + { + constexpr size_t BYTE_INDEX = 43; + uint8_t l_out = 0; - // Targets - const auto l_target_mcs = find_target(i_target_dimm); - const auto l_target_port = find_target(i_target_dimm); + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), + BYTE_INDEX, + i_data[BYTE_INDEX]); - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); + fapi2::buffer l_buffer(i_data[BYTE_INDEX]); - // Byte variables used for decoding (WRT = Write to Read Time) - int64_t l_tWRTmin = 0; + // Extracting desired bits + l_buffer.extractToRight(l_out); - // Attribute variable - int64_t l_min_wrt_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + return l_out; + }; - // TODO - update ENUMS to take account to int64_t + // Lambda expression to retrieve tWRT_Smin's least significant byte (LSB) + auto tWRT_Smin_LSB = [](const fapi2::Target& i_target, const uint8_t* i_data) + { + constexpr size_t BYTE_INDEX = 44; + uint8_t l_out = 0; - // Buffers used for bit manipulation - fapi2::buffer l_buffer_upper_nibble(i_spd_data[BYTE_INDEX_MSN]); - fapi2::buffer l_buffer_lower_byte(i_spd_data[BYTE_INDEX_LSB]); + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), + BYTE_INDEX, + i_data[BYTE_INDEX]); - // Trace print in the front assists w/ debug - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), - BYTE_INDEX, - i_spd_data[BYTE_INDEX]); + fapi2::buffer l_buffer(i_data[BYTE_INDEX]); + + // Extracting desired bits + l_buffer.extractToRight(l_out); + + return l_out; + }; - // Combining bits to create timing value - l_buffer_upper_nibble.insert<, >(l_tWRTmin); - l_buffer_lower_byte.insert<, >(l_tWRTmin); + int64_t l_timing_val = 0; + fapi2::buffer l_buffer; - // Retrive entire MCS level attribute - FAPI_TRY( eff_dram_twrt(l_target_mcs, &l_min_wrt_times[0][0]) ); + // Combining bits to create timing value (in a buffer) + constexpr size_t MSN_START = 52; + constexpr size_t MSN_LEN = 4; + constexpr size_t LSB_START = 56; + constexpr size_t LSB_LEN = 8; - // Update attribute to decoded byte values (returning picoseconds, currently nanoseconds) - l_min_wrt_times[PORT_NUM][DIMM_NUM] = ns_to_ps(l_tWRTmin); + l_buffer.insertFromRight( tWRT_Smin_MSN(i_target, i_spd_data) ). + insertFromRight( tWRT_Smin_LSB(i_target, i_spd_data) ); - // Update MCS level attribute (returning picoseconds, currently nanoseconds) - FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TWRT, l_target_mcs, l_min_wrt_times ); - // Printed decoded info - FAPI_INF("%s", - c_str(i_target_dimm); - fapi_try_exit: - return fapi2::current_err; + // Extract timing value from the buffer into an integral type + constexpr size_t OUTPUT_START = 0; + constexpr size_t OUTPUT_LEN = 64; + + l_buffer.extractToRight(l_timing_val); + + + // JEDEC spec limits for this timing value + + // This value used to be reserved to 0 - before spec update - AAM + // constexpr int64_t TIMING_LOWER_BOUND = 1; // from JEDEC + constexpr int64_t TIMING_LOWER_BOUND = 0; + constexpr int64_t TIMING_UPPER_BOUND = 4095; // from JEDEC + + // best we can do? + // I had to combine parts from two different bytes. + // Chose one of them (byte 44) to for error printout of this decode + constexpr size_t ERROR_BYTE_INDEX = 44; + + FAPI_TRY(mss::check::spd:: + fail_for_invalid_value(i_target, + (l_timing_val <= TIMING_UPPER_BOUND) && + (l_timing_val >= TIMING_LOWER_BOUND), + ERROR_BYTE_INDEX, + l_timing_val, + "Failed check on the Minimum Write to Read Time - Different Bank Group (tWRT_Smin) in MTB") ); + + // Update output only after check passes + o_value = l_timing_val; + + FAPI_DBG("%s. Minimum Write to Read Time - Different Bank Group (tWRT_Smin) in MTB units: %d", + mss::c_str(i_target), + o_value); + +fapi_try_exit: + return fapi2::current_err; } /// -/// @brief Minimum Write to Read Time (tWTR_Lmin), same bank group -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data +/// @brief Decodes Minimum Write to Read Time - Same Bank Group +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value tWRT_Lmin in MTB units /// @return fapi2::ReturnCode -/// @note Byte 43 Bits 7~4, Byte 45 Bits 7~0 +/// @note SPD Byte 43 (bits 7~4) & Byte 45 (bits 7~0) +/// @note Item JC-45-2220.01x +/// @note Page 46 +/// @note DDR4 SPD Document Release 3 /// -fapi2::ReturnCode -decoder::min_write_to_read_time_same_bank_group(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::min_twtr_l(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX_MSN = 43; // MSN = most significant nibble - const size_t BYTE_INDEX_LSB = 45; // LSB = least significant byte + // Lambda expression to retrieve tWRT_Lmin's most nibble byte (MSN) + auto tWRT_Lmin_MSN = [](const fapi2::Target& i_target, const uint8_t* i_data) + { + constexpr size_t BYTE_INDEX = 43; + uint8_t l_out = 0; - // Targets - const auto l_target_mcs = find_target(i_target_dimm); - const auto l_target_port = find_target(i_target_dimm); + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), + BYTE_INDEX, + i_data[BYTE_INDEX]); - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); + fapi2::buffer l_buffer(i_data[BYTE_INDEX]); - // Byte variables used for decoding (WRT = Write to Read Time) - int64_t l_tWRTmin = 0; + // Extracting desired bits + l_buffer.extractToRight(l_out); - // Attribute variable - int64_t l_min_wrt_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + return l_out; + }; - // TODO - update ENUMS to take account to int64_t + // Lambda expression to retrieve tWRT_Lmin's least significant byte (LSB) + auto tWRT_Lmin_LSB = [](const fapi2::Target& i_target, const uint8_t* i_data) + { + constexpr size_t BYTE_INDEX = 45; + uint8_t l_out = 0; - // Buffers used for bit manipulation - fapi2::buffer l_buffer_upper_nibble(i_spd_data[BYTE_INDEX_MSN]); - fapi2::buffer l_buffer_lower_byte(i_spd_data[BYTE_INDEX_LSB]); + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), + BYTE_INDEX, + i_data[BYTE_INDEX]); - // Trace print in the front assists w/ debug - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), - BYTE_INDEX, - i_spd_data[BYTE_INDEX]); + fapi2::buffer l_buffer(i_data[BYTE_INDEX]); - // Combining bits to create timing value - l_buffer_upper_nibble.insert<, >(l_tWRTmin); - l_buffer_lower_byte.insert<, >(l_tWRTmin); + // Extracting desired bits + l_buffer.extractToRight(l_out); - // Retrive entire MCS level attribute - FAPI_TRY( eff_dram_twrt(l_target_mcs, &l_min_wrt_times[0][0]) ); + return l_out; + }; - // Update attribute to decoded byte values (returning picoseconds, currently nanoseconds) - l_min_wrt_times[PORT_NUM][DIMM_NUM] = ns_to_ps(l_tWRTmin); + int64_t l_timing_val = 0; + fapi2::buffer l_buffer; - // Update MCS level attribute (returning picoseconds, currently nanoseconds) - FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TWRT, l_target_mcs, l_min_wrt_times ); - // Printed decoded info - FAPI_INF("%s", - c_str(i_target_dimm); - fapi_try_exit: - return fapi2::current_err; -} + // Combining bits to create timing value (in a buffer) + constexpr size_t MSN_START = 52; + constexpr size_t MSN_LEN = 4; + constexpr size_t LSB_START = 56; + constexpr size_t LSB_LEN = 8; -/// -/// @brief Connector to SDRAM Bit Mapping -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data -/// @return fapi2::ReturnCode -/// @note Bytes 60~77 -/// -fapi2::ReturnCode decoder::connector_to_sdram_bit_mapping(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) -{ -// Retrive entire MCS level attribute -// Update attribute to decoded byte values -// Update MCS level attribute - // Printed decoded info - FAPI_INF("%s", - c_str(i_target_dimm); - fapi_try_exit: - return fapi2::current_err; + l_buffer.insertFromRight( tWRT_Lmin_MSN(i_target, i_spd_data) ). + insertFromRight( tWRT_Lmin_LSB(i_target, i_spd_data) ); + + // Extract timing value from the buffer into an integral type + constexpr size_t OUTPUT_START = 0; + constexpr size_t OUTPUT_LEN = 64; + + l_buffer.extractToRight(l_timing_val); + + // JEDEC spec limits for this timing value + // This value used to be reserved to 0 - before spec update + //constexpr int64_t TIMING_LOWER_BOUND = 1 // from JEDEC + constexpr int64_t TIMING_LOWER_BOUND = 0; + constexpr int64_t TIMING_UPPER_BOUND = 4095; // from JEDEC + + // best we can do? + // I had to combine parts from two different bytes. + // Chose one of them (byte 45) to for error printout of this decode + constexpr size_t ERROR_BYTE_INDEX = 45; + + FAPI_TRY(mss::check::spd:: + fail_for_invalid_value(i_target, + (l_timing_val <= TIMING_UPPER_BOUND) && + (l_timing_val >= TIMING_LOWER_BOUND), + ERROR_BYTE_INDEX, + l_timing_val, + "Failed check on the Minimum Write to Read Time - Same Bank Group (tWRT_Lmin) in MTB") ); + + // Update output only after check passes + o_value = l_timing_val; + + FAPI_DBG("%s. Minimum Write to Read Time - Same Bank Group (tWRT_Lmin) in MTB units: %d", + mss::c_str(i_target), + o_value); + +fapi_try_exit: + return fapi2::current_err; } /// -/// @brief Fine Offset for Minimum CAS to CAS Delay Time (tCCD_Lmin), same bank group -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data +/// @brief Decodes Fine Offset for Minimum CAS to CAS Delay Time - Same Bank Group +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value tCCD_Lmin offset in FTB units /// @return fapi2::ReturnCode -/// @note Byte 117 +/// @note SPD Byte 117 +/// @note Item JC-45-2220.01x +/// @note Page 52 +/// @note DDR4 SPD Document Release 3 /// -fapi2::ReturnCode decoder::offset_for_min_cas_to_cas_delay_time(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::fine_offset_min_tccd_l(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX = 117; - - // Targets - const auto l_target_mcs = find_target(i_target_dimm); - const auto l_target_port = find_target(i_target_dimm); - - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); - - // Attribute variable (CCD_L = Minimum CAS to CAS Delay Time, same bank group) - int64_t l_min_offset_tCCD_L[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + constexpr size_t BYTE_INDEX = 117; + constexpr int64_t TIMING_LOWER_BOUND = -128; // from JEDEC + constexpr int64_t TIMING_UPPER_BOUND = 127; // from JEDEC - // Trace print in the front assists w/ debug - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), BYTE_INDEX, i_spd_data[BYTE_INDEX]); - // Retrive entire MCS level attribute - FAPI_TRY( eff_dram_trrd(l_target_mcs, &l_min_offset_tCCD_L[0][0]) ); + // Retrieve Fine Offset for Minimum CAS to CAS Delay Time + // int8_t conversion - allows me to get a negative offset + // then implicit conversion to int64_t + int64_t l_timing_val = int8_t(i_spd_data[BYTE_INDEX]); - // Update attribute to decoded byte values - l_min_offset_tCCD_L[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) ); + FAPI_TRY(mss::check::spd:: + fail_for_invalid_value(i_target, + (l_timing_val <= TIMING_UPPER_BOUND) && + (l_timing_val >= TIMING_LOWER_BOUND), + BYTE_INDEX, + l_timing_val, + "Failed check on the fine offset for min RAS to CAS Delay Time (tCCD_Lmin)") ); - // Update MCS level attribute - FAPI_ATTR_SET( fapi2::ATTR_EFF_OFFSET_DRAM_TCCD_L, l_target_mcs, l_min_offset_tCCD_L ); - // Printed decoded info - FAPI_INF("%s", - c_str(i_target_dimm); - fapi_try_exit: - return fapi2::current_err; -} + // Update output value only if range check passes + o_value = l_timing_val; -// Retrive entire MCS level attribute -// Update attribute to decoded byte values -// Update MCS level attribute + FAPI_DBG("%s. Fine offset for Minimum RAS to CAS Delay Time (tCCD_Lmin) in FTB units: %d", + mss::c_str(i_target), + o_value); fapi_try_exit: -return fapi2::current_err; + return fapi2::current_err; } /// -/// @brief Fine Offset for Minimum Activate to Activate Delay Time(tRRD_Lmin), same bank group -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data +/// @brief Decodes Fine Offset for Minimum Activate to Activate Delay Time - Same Bank Group +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value tRRD_Lmin offset in FTB units /// @return fapi2::ReturnCode -/// @note Byte 118 +/// @note SPD Byte 118 +/// @note Item JC-45-2220.01x +/// @note Page 52 +/// @note DDR4 SPD Document Release 3 /// -fapi2::ReturnCode -decoder::offset_min_act_to_act_delay_time_diff_bank_gp(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::fine_offset_min_trrd_l(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX = 118; - - // Targets - const auto l_target_mcs = find_target(i_target_dimm); - const auto l_target_port = find_target(i_target_dimm); - - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); - - // Attribute variable (CCD_L = Minimum CAS to CAS Delay Time, same bank group) - int64_t l_min_offset_tCCD_L[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + constexpr size_t BYTE_INDEX = 118; + constexpr int64_t TIMING_LOWER_BOUND = -128; // from JEDEC + constexpr int64_t TIMING_UPPER_BOUND = 127; // from JEDEC - // Trace print in the front assists w/ debug - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), BYTE_INDEX, i_spd_data[BYTE_INDEX]); - // Retrive entire MCS level attribute - FAPI_TRY( eff_dram_trrd(l_target_mcs, &l_min_offset_tCCD_L[0][0]) ); + // Retrieve Fine Offset for Minimum Activate to Activate Delay Time + // int8_t conversion - allows me to get a negative offset + // then implicit conversion to int64_t + int64_t l_timing_val = int8_t(i_spd_data[BYTE_INDEX]); - // Update attribute to decoded byte values - l_min_offset_tCCD_L[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) ); + FAPI_TRY(mss::check::spd:: + fail_for_invalid_value(i_target, + (l_timing_val <= TIMING_UPPER_BOUND) && + (l_timing_val >= TIMING_LOWER_BOUND), + BYTE_INDEX, + l_timing_val, + "Failed check on the fine offset for Minimum Activate to Activate Delay Time (tRRD_Lmin)") ); - // Update MCS level attribute - FAPI_ATTR_SET( fapi2::ATTR_EFF_OFFSET_DRAM_TCCD_L, l_target_mcs, l_min_offset_tCCD_L ); - // Printed decoded info - FAPI_INF("%s", - c_str(i_target_dimm); - fapi_try_exit: - return fapi2::current_err; + // Update output value only if range check passes + o_value = l_timing_val; + FAPI_DBG("%s. Fine offset for Minimum Activate to Activate Delay Time (tRRD_Lmin) in FTB units: %d", + mss::c_str(i_target), + o_value); + +fapi_try_exit: + return fapi2::current_err; } /// -/// @brief Fine Offset for Minimum Activate to Activate Delay Time (tRRD_Smin), different bank group -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data +/// @brief Decodes Fine Offset for Minimum Activate to Activate Delay Time - Different Bank Group +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value tRRD_Smin offset in FTB units /// @return fapi2::ReturnCode -/// @note Byte 119 +/// @note SPD Byte 119 +/// @note Item JC-45-2220.01x +/// @note Page 52 +/// @note DDR4 SPD Document Release 3 /// -fapi2::ReturnCode -decoder::offset_min_act_to_act_delay_time_same_bank_gp(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::fine_offset_min_trrd_s(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX = 119; - - // Targets - const auto l_target_mcs = find_target(i_target_dimm); - const auto l_target_port = find_target(i_target_dimm); - - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); + constexpr size_t BYTE_INDEX = 119; + constexpr int64_t TIMING_LOWER_BOUND = -128; // from JEDEC + constexpr int64_t TIMING_UPPER_BOUND = 127; // from JEDEC - // Attribute variable (CCD_L = Minimum CAS to CAS Delay Time, same bank group) - int64_t l_min_offset_tCCD_L[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; - - // Trace print in the front assists w/ debug - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), BYTE_INDEX, i_spd_data[BYTE_INDEX]); - // Retrive entire MCS level attribute - FAPI_TRY( eff_dram_trrd(l_target_mcs, &l_min_offset_tCCD_L[0][0]) ); + // Retrieve Fine Offset for Minimum Activate to Activate Delay Time - Different Bank Group + // int8_t conversion - allows me to get a negative offset + // then implicit conversion to int64_t + int64_t l_timing_val = int8_t(i_spd_data[BYTE_INDEX]); + + FAPI_TRY(mss::check::spd:: + fail_for_invalid_value(i_target, + (l_timing_val <= TIMING_UPPER_BOUND) && + (l_timing_val >= TIMING_LOWER_BOUND), + BYTE_INDEX, + l_timing_val, + "Failed check on the fine offset for Minimum Activate to Activate Delay Time - Different Bank Group (tRRD_Smin)") ); - // Update attribute to decoded byte values - l_min_offset_tCCD_L[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) ); + // Update output value only if range check passes + o_value = l_timing_val; - // Update MCS level attribute - FAPI_ATTR_SET( fapi2::ATTR_EFF_OFFSET_DRAM_TCCD_L, l_target_mcs, l_min_offset_tCCD_L ); - // Printed decoded info - FAPI_INF("%s", - c_str(i_target_dimm); - fapi_try_exit: - return fapi2::current_err; + FAPI_DBG("%s. Fine offset for Minimum Activate to Activate Delay Time - Different Bank Group (tRRD_Smin) in FTB units: %d", + mss::c_str(i_target), + o_value); + +fapi_try_exit: + return fapi2::current_err; } /// -/// @brief Fine Offset for Minimum Active to Active/Refresh Delay Time (tRCmin) -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data +/// @brief Decodes Fine Offset for Minimum Active to Active/Refresh Delay Time +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value tRCmin offset in FTB units /// @return fapi2::ReturnCode -/// @note Byte 120 +/// @note SPD Byte 120 +/// @note Item JC-45-2220.01x +/// @note Page 52 +/// @note DDR4 SPD Document Release 3 /// -fapi2::ReturnCode -decoder::offset_for_min_act_to_act_refresh_delay_time(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::fine_offset_min_trc(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX = 120; + constexpr size_t BYTE_INDEX = 120; + constexpr int64_t TIMING_LOWER_BOUND = -128; // from JEDEC + constexpr int64_t TIMING_UPPER_BOUND = 127; // from JEDEC - // Targets - const auto l_target_mcs = find_target(i_target_dimm); - const auto l_target_port = find_target(i_target_dimm); - - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); - - // Attribute variable (CCD_L = Minimum CAS to CAS Delay Time, same bank group) - int64_t l_min_offset_tCCD_L[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; - - // Trace print in the front assists w/ debug - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), BYTE_INDEX, i_spd_data[BYTE_INDEX]); - // Retrive entire MCS level attribute - FAPI_TRY( eff_dram_trrd(l_target_mcs, &l_min_offset_tCCD_L[0][0]) ); + // Retrieve Fine Offset for Minimum Active to Active/Refresh Delay Time + // int8_t conversion - allows me to get a negative offset + // then implicit conversion to int64_t + int64_t l_timing_val = int8_t(i_spd_data[BYTE_INDEX]); - // Update attribute to decoded byte values - l_min_offset_tCCD_L[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) ); + FAPI_TRY(mss::check::spd:: + fail_for_invalid_value(i_target, + (l_timing_val <= TIMING_UPPER_BOUND) && + (l_timing_val >= TIMING_LOWER_BOUND), + BYTE_INDEX, + l_timing_val, + "Failed check on the fine offset for Minimum Active to Active/Refresh Delay Time (tRCmin)") ); - // Update MCS level attribute - FAPI_ATTR_SET( fapi2::ATTR_EFF_OFFSET_DRAM_TCCD_L, l_target_mcs, l_min_offset_tCCD_L ); - // Printed decoded info - FAPI_INF("%s", - c_str(i_target_dimm); - fapi_try_exit: - return fapi2::current_err; + // Update output value only if range check passes + o_value = l_timing_val; -// Retrive entire MCS level attribute -// Update attribute to decoded byte values -// Update MCS level attribute + FAPI_DBG("%s. Fine offset for Minimum Active to Active/Refresh Delay Time (tRCmin) in FTB units: %d", + mss::c_str(i_target), + o_value); - fapi_try_exit: - return fapi2::current_err; +fapi_try_exit: + return fapi2::current_err; } /// -/// @brief Fine Offset for Minimum Row Precharge Delay Time (tRPmin) -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data +/// @brief Decodes Fine Offset for Minimum Row Precharge Delay Time +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value tRPmin offset in FTB units /// @return fapi2::ReturnCode -/// @note Byte 121 +/// @note SPD Byte 121 +/// @note Item JC-45-2220.01x +/// @note Page 52 +/// @note DDR4 SPD Document Release 3 /// -fapi2::ReturnCode -decoder::offset_for_min_row_precharge_delay_time(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::fine_offset_min_trp(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX = 121; + constexpr size_t BYTE_INDEX = 121; + constexpr int64_t TIMING_LOWER_BOUND = -128; // from JEDEC + constexpr int64_t TIMING_UPPER_BOUND = 127; // from JEDEC - // Targets - const auto l_target_mcs = find_target(i_target_dimm); - const auto l_target_port = find_target(i_target_dimm); - - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); - - // Attribute variable (CCD_L = Minimum CAS to CAS Delay Time, same bank group) - int64_t l_min_offset_tCCD_L[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; - - // Trace print in the front assists w/ debug - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), BYTE_INDEX, i_spd_data[BYTE_INDEX]); - // Retrive entire MCS level attribute - FAPI_TRY( eff_dram_trrd(l_target_mcs, &l_min_offset_tCCD_L[0][0]) ); - - // Update attribute to decoded byte values - l_min_offset_tCCD_L[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) ); + // Retrieve Fine Offset for Minimum Row Precharge Delay Time + // int8_t conversion - allows me to get a negative offset + // then implicit conversion to int64_t + int64_t l_timing_val = int8_t(i_spd_data[BYTE_INDEX]); - // Update MCS level attribute - FAPI_ATTR_SET( fapi2::ATTR_EFF_OFFSET_DRAM_TCCD_L, l_target_mcs, l_min_offset_tCCD_L ); + FAPI_TRY(mss::check::spd:: + fail_for_invalid_value(i_target, + (l_timing_val <= TIMING_UPPER_BOUND) && + (l_timing_val >= TIMING_LOWER_BOUND), + BYTE_INDEX, + l_timing_val, + "Failed check on the fine offset for Minimum Row Precharge Delay Time (tRPmin)") ); - // Printed decoded info - FAPI_INF("%s", - c_str(i_target_dimm); - fapi_try_exit: - return fapi2::current_err; -} + // Update output value only if range check passes + o_value = l_timing_val; + FAPI_DBG("%s. Fine offset for Minimum Row Precharge Delay Time (tRPmin) in FTB units: %d", + mss::c_str(i_target), + o_value); +fapi_try_exit: + return fapi2::current_err; +} /// -/// @brief Fine Offset for Minimum RAS to CAS Delay Time (tRCDmin) -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data +/// @brief Decodes Fine Offset for SDRAM Minimum RAS to CAS Delay Time +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value tRCDmin offset in FTB units /// @return fapi2::ReturnCode -/// @note Byte 122 +/// @note SPD Byte 122 +/// @note Item JC-45-2220.01x +/// @note Page 52 +/// @note DDR4 SPD Document Release 3 /// -fapi2::ReturnCode decoder::offset_for_min_ras_to_cas_delay_time(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::fine_offset_min_trcd(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX = 122; - - // Targets - const auto l_target_mcs = find_target(i_target_dimm); - const auto l_target_port = find_target(i_target_dimm); + constexpr size_t BYTE_INDEX = 122; + constexpr int64_t TIMING_LOWER_BOUND = -128; // from JEDEC + constexpr int64_t TIMING_UPPER_BOUND = 127; // from JEDEC - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); - - // Attribute variable (CCD_L = Minimum CAS to CAS Delay Time, same bank group) - int64_t l_min_offset_tCCD_L[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; - - // Trace print in the front assists w/ debug - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), BYTE_INDEX, i_spd_data[BYTE_INDEX]); - // Retrive entire MCS level attribute - FAPI_TRY( eff_dram_trrd(l_target_mcs, &l_min_offset_tCCD_L[0][0]) ); + // Retrieve Fine Offset for SDRAM Minimum RAS to CAS Delay Time + // int8_t conversion - allows me to get a negative offset + // then implicit conversion to int64_t + int64_t l_timing_val = int8_t(i_spd_data[BYTE_INDEX]); - // Update attribute to decoded byte values - l_min_offset_tCCD_L[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) ); + FAPI_TRY(mss::check::spd:: + fail_for_invalid_value(i_target, + (l_timing_val <= TIMING_UPPER_BOUND) && + (l_timing_val >= TIMING_LOWER_BOUND), + BYTE_INDEX, + l_timing_val, + "Failed check on the fine offset for min RAS to CAS Delay Time (tRCDmin)") ); - // Update MCS level attribute - FAPI_ATTR_SET( fapi2::ATTR_EFF_OFFSET_DRAM_TCCD_L, l_target_mcs, l_min_offset_tCCD_L ); + // Update output value only if range check passes + o_value = l_timing_val; - // Printed decoded info - FAPI_INF("%s", - c_str(i_target_dimm); - fapi_try_exit: - return fapi2::current_err; + FAPI_DBG("%s. Fine offset for Minimum RAS to CAS Delay Time (tRCDmin) in FTB units: %d", + mss::c_str(i_target), + o_value); + +fapi_try_exit: + return fapi2::current_err; } /// -/// @brief Fine Offset for Minimum CAS Latency Time (tAAmin) -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data +/// @brief Decodes Fine Offset for SDRAM Minimum CAS Latency Time +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value tAAmin offset in FTB units /// @return fapi2::ReturnCode -/// @note Byte 123 +/// @note SPD Byte 123 +/// @note Item JC-45-2220.01x +/// @note Page 52 +/// @note DDR4 SPD Document Release 3 /// -fapi2::ReturnCode decoder::offset_for_min_cas_latency_time(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::fine_offset_min_taa(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX = 123; + constexpr size_t BYTE_INDEX = 125; + constexpr int64_t TIMING_LOWER_BOUND = -128; // from JEDEC + constexpr int64_t TIMING_UPPER_BOUND = 127; // from JEDEC - // Targets - const auto l_target_mcs = find_target(i_target_dimm); - const auto l_target_port = find_target(i_target_dimm); - - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); - - // Attribute variable (CCD_L = Minimum CAS to CAS Delay Time, same bank group) - int64_t l_min_offset_tCCD_L[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; - - // Trace print in the front assists w/ debug - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), BYTE_INDEX, i_spd_data[BYTE_INDEX]); - // Retrive entire MCS level attribute - FAPI_TRY( eff_dram_trrd(l_target_mcs, &l_min_offset_tCCD_L[0][0]) ); + // Retrieve Fine Offset for SDRAM Minimum CAS Latency Time + // int8_t conversion - allows me to get a negative offset + // then implicit conversion to int64_t + int64_t l_timing_val = int8_t(i_spd_data[BYTE_INDEX]); + + FAPI_TRY(mss::check::spd:: + fail_for_invalid_value(i_target, + (l_timing_val <= TIMING_UPPER_BOUND) && + (l_timing_val >= TIMING_LOWER_BOUND), + BYTE_INDEX, + l_timing_val, + "Failed check on the Fine offset for Minimum CAS Latency Time (tAAmin)") ); - // Update attribute to decoded byte values - l_min_offset_tCCD_L[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) ); + // Update output value only if range check passes + o_value = l_timing_val; - // Update MCS level attribute - FAPI_ATTR_SET( fapi2::ATTR_EFF_OFFSET_DRAM_TCCD_L, l_target_mcs, l_min_offset_tCCD_L ); + FAPI_DBG("%s. Fine offset for Minimum CAS Latency Time (tAAmin) in FTB units: %d", + mss::c_str(i_target), + o_value); - // Printed decoded info - FAPI_INF("%s", - c_str(i_target_dimm); - fapi_try_exit: - return fapi2::current_err; +fapi_try_exit: + return fapi2::current_err; } /// -/// @brief Fine Offset for SDRAM Maximum Cycle Time (tCKAVGmax) -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data +/// @brief Decodes Fine Offset for SDRAM Maximum Cycle Time +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value tCKmax offset in FTB units /// @return fapi2::ReturnCode -/// @note Byte 124 +/// @note SPD Byte 124 +/// @note Item JC-45-2220.01x +/// @note Page 52 +/// @note DDR4 SPD Document Release 3 /// -fapi2::ReturnCode decoder::offset_for_max_cycle_time(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::fine_offset_max_tck(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX = 124; - - // Targets - const auto l_target_mcs = find_target(i_target_dimm); - const auto l_target_port = find_target(i_target_dimm); - - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); - - // Attribute variable (CCD_L = Minimum CAS to CAS Delay Time, same bank group) - int64_t l_min_offset_tCCD_L[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + constexpr size_t BYTE_INDEX = 124; + constexpr int64_t TIMING_LOWER_BOUND = -128; // from JEDEC + constexpr int64_t TIMING_UPPER_BOUND = 127; // from JEDEC - // Trace print in the front assists w/ debug - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), BYTE_INDEX, i_spd_data[BYTE_INDEX]); - // Retrive entire MCS level attribute - FAPI_TRY( eff_dram_trrd(l_target_mcs, &l_min_offset_tCCD_L[0][0]) ); + // Retrieve Fine Offset for SDRAM Maximum Cycle Time + // int8_t conversion - allows me to get a negative offset + // then implicit conversion to int64_t + int64_t l_timing_val = int8_t(i_spd_data[BYTE_INDEX]); + + FAPI_TRY(mss::check::spd:: + fail_for_invalid_value(i_target, + (l_timing_val <= TIMING_UPPER_BOUND) && + (l_timing_val >= TIMING_LOWER_BOUND), + BYTE_INDEX, + l_timing_val, + "Failed check on the fine offset for max cycle time (tckmax)") ); - // Update attribute to decoded byte values - l_min_offset_tCCD_L[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) ); + // Update output value only if range check passes + o_value = l_timing_val; - // Update MCS level attribute - FAPI_ATTR_SET( fapi2::ATTR_EFF_OFFSET_DRAM_TCCD_L, l_target_mcs, l_min_offset_tCCD_L ); + FAPI_DBG("%s. Fine offset for Maximum Cycle Time (tCKmax) in FTB units: %d", + mss::c_str(i_target), + o_value); - // Printed decoded info - FAPI_INF("%s", - c_str(i_target_dimm); - fapi_try_exit: - return fapi2::current_err; +fapi_try_exit: + return fapi2::current_err; } + /// -/// @brief Fine Offset for SDRAM Minimum Cycle Time (tCKAVGmin) -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data +/// @brief Decodes Fine Offset for SDRAM Minimum Cycle Time +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value tCKmin offset in FTB units /// @return fapi2::ReturnCode -/// @note Byte 125 +/// @note SPD Byte 125 +/// @note Item JC-45-2220.01x +/// @note Page 52 +/// @note DDR4 SPD Document Release 3 /// -fapi2::ReturnCode decoder::offset_for_min_cycle_time(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::fine_offset_min_tck(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX = 125; + constexpr size_t BYTE_INDEX = 125; + constexpr int64_t TIMING_LOWER_BOUND = -128; // from JEDEC + constexpr int64_t TIMING_UPPER_BOUND = 127; // from JEDEC - // Targets - const auto l_target_mcs = find_target(i_target_dimm); - const auto l_target_port = find_target(i_target_dimm); - - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); - - // Attribute variable (CCD_L = Minimum CAS to CAS Delay Time, same bank group) - int64_t l_min_offset_tCCD_L[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; - - // Trace print in the front assists w/ debug - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), BYTE_INDEX, i_spd_data[BYTE_INDEX]); - // Retrive entire MCS level attribute - FAPI_TRY( eff_dram_trrd(l_target_mcs, &l_min_offset_tCCD_L[0][0]) ); + // Retrieve Fine Offset for SDRAM Minimum Cycle Time + // int8_t conversion - allows me to get a negative offset + // then implicit conversion to int64_t + int64_t l_timing_val = int8_t(i_spd_data[BYTE_INDEX]); + + FAPI_TRY(mss::check::spd:: + fail_for_invalid_value(i_target, + (l_timing_val <= TIMING_UPPER_BOUND) && + (l_timing_val >= TIMING_LOWER_BOUND), + BYTE_INDEX, + l_timing_val, + "Failed check on the Fine offset for Minimum Cycle Time (tCKmin)") ); - // Update attribute to decoded byte values - l_min_offset_tCCD_L[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) ); + // Update output value only if range check passes + o_value = l_timing_val; - // Update MCS level attribute - FAPI_ATTR_SET( fapi2::ATTR_EFF_OFFSET_DRAM_TCCD_L, l_target_mcs, l_min_offset_tCCD_L ); - // Printed decoded info - FAPI_INF("%s", - c_str(i_target_dimm); + FAPI_DBG("%s. Fine offset for Minimum Cycle Time (tCKmin) in FTB units: %d", + mss::c_str(i_target), + o_value); - fapi_try_exit: - return fapi2::current_err; +fapi_try_exit: + return fapi2::current_err; } + /// -/// @brief Cyclical Redundancy Code (CRC) for Base Configuration Section -/// @param[in] const fapi2::Target& i_target_dimm, -/// uint8_t* i_spd_data +/// @brief Decodes Cyclical Redundancy Code (CRC) for Base Configuration Section +/// @param[in] i_target FAPI2 DIMM target +/// @param[in] i_spd_data SPD blob +/// @param[out] o_value crc value from SPD /// @return fapi2::ReturnCode -/// @note Byte 126 (LSB) along with Byte 127 (MSB) +/// @note SPD Byte 127 & Byte 126 +/// @note Item JC-45-2220.01x +/// @note Page 53 +/// @note DDR4 SPD Document Release 3 /// -fapi2::ReturnCode decoder::crc_for_base_config_section(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::cyclical_redundancy_code(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint16_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX_MSB = 127; // MSN = most significant nibble - const size_t BYTE_INDEX_LSB = 126; // LSB = least significant byte + // Lambda expression to retrieve crc's most significant byte (MSB) + auto crc_MSB = [](const fapi2::Target& i_target, const uint8_t* i_data) + { + constexpr size_t BYTE_INDEX = 127; + uint8_t l_out = 0; - // Targets - const auto l_target_mcs = find_target(i_target_dimm); - const auto l_target_port = find_target(i_target_dimm); + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), + BYTE_INDEX, + i_data[BYTE_INDEX]); - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); + fapi2::buffer l_buffer(i_data[BYTE_INDEX]); - // Byte variables used for decoding (WRT = Write to Read Time) - int64_t l_tWRTmin = 0; + // Extracting desired bits + l_buffer.extractToRight(l_out); - // Attribute variable - int64_t l_min_wrt_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + return l_out; + }; - // TODO - update ENUMS to take account to int64_t + // Lambda expression to retrieve crc's least significant byte (LSB) + auto crc_LSB = [](const fapi2::Target& i_target, const uint8_t* i_data) + { + constexpr size_t BYTE_INDEX = 126; + uint8_t l_out = 0; - // Buffers used for bit manipulation - fapi2::buffer l_buffer_upper_nibble(i_spd_data[BYTE_INDEX_MSN]); - fapi2::buffer l_buffer_lower_byte(i_spd_data[BYTE_INDEX_LSB]); + // Trace in the front assists w/ debug + FAPI_DBG("%s SPD data at Byte %d: 0x%llX.", + mss::c_str(i_target), + BYTE_INDEX, + i_data[BYTE_INDEX]); - // Trace print in the front assists w/ debug - FAPI_INF("%s SPD data at Byte %d: 0x%llX", - c_str(i_target_dimm), - BYTE_INDEX, - i_spd_data[BYTE_INDEX]); + fapi2::buffer l_buffer(i_data[BYTE_INDEX]); + + // Extracting desired bits + l_buffer.extractToRight(l_out); + + return l_out; + }; + + fapi2::buffer l_buffer; + // Combining bits to create timing value (in a buffer) + constexpr size_t MSN_START = 0; + constexpr size_t MSN_LEN = 8; + constexpr size_t LSB_START = 8; + constexpr size_t LSB_LEN = 8; - // Combining bits to create timing value - l_buffer_upper_nibble.insert<, >(l_tWRTmin); - l_buffer_lower_byte.insert<, >(l_tWRTmin); + l_buffer.insertFromRight( crc_MSB(i_target, i_spd_data) ). + insertFromRight( crc_LSB(i_target, i_spd_data) ); - // Retrive entire MCS level attribute - FAPI_TRY( eff_dram_twrt(l_target_mcs, &l_min_wrt_times[0][0]) ); + // Extract timing value from the buffer into an integral type + constexpr size_t OUTPUT_START = 0; + constexpr size_t OUTPUT_LEN = 16; - // Update attribute to decoded byte values (returning picoseconds, currently nanoseconds) - l_min_wrt_times[PORT_NUM][DIMM_NUM] = ns_to_ps(l_tWRTmin); + // This value isn't bounded in the SPD document + l_buffer.extractToRight(o_value); - // Update MCS level attribute (returning picoseconds, currently nanoseconds) - FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TWRT, l_target_mcs, l_min_wrt_times ); + FAPI_DBG("%s. Cyclical Redundancy Code (CRC): %d", + mss::c_str(i_target), + o_value); - // Printed decoded info - FAPI_INF("%s", - c_str(i_target_dimm); - fapi_try_exit: - return fapi2::current_err; + // Returns "happy" until we can figure out a way to test this - AAM + return fapi2::FAPI2_RC_SUCCESS; } -#endif }//spd namespace }// mss namespace diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/spd/spd_decoder.H b/src/import/chips/p9/procedures/hwp/memory/lib/spd/spd_decoder.H index c86dc8816..390850032 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/spd/spd_decoder.H +++ b/src/import/chips/p9/procedures/hwp/memory/lib/spd/spd_decoder.H @@ -7,7 +7,7 @@ /* */ /* EKB Project */ /* */ -/* COPYRIGHT 2015 */ +/* COPYRIGHT 2015,2016 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -38,8 +38,9 @@ namespace mss namespace spd { +using fapi2::TARGET_TYPE_DIMM; -enum constants : uint64_t +enum BYTE_EXTRACT : uint64_t { // Byte 0 BYTES_USED_START = 4, @@ -51,7 +52,14 @@ enum constants : uint64_t BYTES_RESERVED_START = 0, BYTES_RESERVED_LEN = 1, - // Byte 1 & 2 not used now + // Byte 1 + ENCODING_LEVEL_START = 0, + ENCODING_LEVEL_LEN = 4, + + ADDITIONS_LEVEL_START = 4, + ADDITIONS_LEVEL_LEN = 4, + + // Byte 2 - Entire byte used // Byte 3 BASE_MODULE_START = 4, @@ -84,8 +92,8 @@ enum constants : uint64_t ADDRESS_RESERVED_LEN = 2, // Byte 6 - PRIM_PRIM_SIGNAL_LOAD_START = 5, - PRIM_PRIM_SIGNAL_LOAD_LEN = 2, + PRIM_SIGNAL_LOAD_START = 5, + PRIM_SIGNAL_LOAD_LEN = 2, PACKAGE_RESERVE_START = 4, PACKAGE_RESERVE_LEN = 2, @@ -155,8 +163,8 @@ enum constants : uint64_t MODULE_ORG_RESERVED_LEN = 1, // Byte 13 - BUS_WIDTH_START = 6, - BUS_WIDTH_LEN = 2, + BUS_WIDTH_START = 5, + BUS_WIDTH_LEN = 3, BUS_EXT_WIDTH_START = 3, BUS_EXT_WIDTH_LEN = 2, @@ -190,233 +198,1093 @@ enum constants : uint64_t TIMEBASE_RESERV_START = 0, TIMEBASE_RESERV_LEN = 4, - // Byte 18 - bits not decoded - // Byte 19 - bits not decoded + // Byte 18 - Entire byte used + // Byte 19 - Entire byte used // Byte 20-23 - CAS_BYTE_1_START = 55, + CAS_BYTE_1_START = 56, CAS_BYTE_1_LEN = 8, - CAS_BYTE_2_START = 47, + CAS_BYTE_2_START = 48, CAS_BYTE_2_LEN = 8, - CAS_BYTE_3_START = 39, + CAS_BYTE_3_START = 40, CAS_BYTE_3_LEN = 8, - CAS_BYTE_4_START = 31, + CAS_BYTE_4_START = 32, CAS_BYTE_4_LEN = 8, - // Byte 24 - bits not decoded - // Byte 25 - bits not decoded - // Byte 26 - bits not decoded + // Byte 24 - Entire byte used + // Byte 25 - Entire byte used + // Byte 26 - Entire byte used // Byte 27 - TRCMIN_MSN_START = 0, // MSN = most significant nibble - TRCMIN_MSN_LEN = 4, - TRASMIN_MSN_START = 4, // MSN = most significant nibble TRASMIN_MSN_LEN = 4, + TRCMIN_MSN_START = 0, // MSN = most significant nibble + TRCMIN_MSN_LEN = 4, + // Byte 28 - TRASMIN_LSB_START = 4, // LSB = least significant byte + TRASMIN_LSB_START = 0, // LSB = least significant byte TRASMIN_LSB_LEN = 8, // Byte 29 - TRCMIN_LSB_START = 4, // LSB = least significant byte + TRCMIN_LSB_START = 0, // LSB = least significant byte TRCMIN_LSB_LEN = 8, // Byte 30 - // TRFC1MIN_LSB_START - // TRFC1MIN_LSB_LEN + TRFC1MIN_LSB_START = 0, + TRFC1MIN_LSB_LEN = 8, // Byte 31 -// TRFC1MIN_MSB_START -// TRFC1MIN_MSB_LEN - - // Bytes 46 - 59 - reserved - - // Bytes 60 - 77 - Connector to SDRAM Bit Mapping ?? - - // Bytes 78 - 116 - reserved - - // Bytes 117 - 125 : bits not decoded - - // Bytes 128 ~ 191 Module-Specific Section ?? - - // Bytes 192 ~ 255 Hybrid Memory Architecture Specific Parameters ?? - - // Bytes 256 ~ 319 Extended Function Parameter Block ?? - - // Bytes 320 ~ 383 Module Supplier’s Data ?? -}; - - -class decoder -{ - - public: - // Constructor - decoder() = default; - // Deconstructor - virtual ~decoder() = default; - - // Methods - virtual fapi2::ReturnCode number_of_bytes(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data, - const size_t i_read_spd_size); - - virtual fapi2::ReturnCode revision(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data); - - virtual fapi2::ReturnCode dram_device_type(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data); - - virtual fapi2::ReturnCode module_type(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data); - - virtual fapi2::ReturnCode sdram_density(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data); - - virtual fapi2::ReturnCode sdram_addressing(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data); - - virtual fapi2::ReturnCode primary_package_type(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data); - - virtual fapi2::ReturnCode sdram_optional_features(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data); - - virtual fapi2::ReturnCode thermal_and_refresh_options(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data); - - virtual fapi2::ReturnCode other_optional_features(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data); - - virtual fapi2::ReturnCode secondary_package_type(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data); - - virtual fapi2::ReturnCode module_nominal_voltage(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data); + TRFC1MIN_MSB_START = 0, + TRFC1MIN_MSB_LEN = 8, - virtual fapi2::ReturnCode module_organization(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data); + // Byte 32 + TRFC2MIN_LSB_START = 0, + TRFC2MIN_LSB_LEN = 8, - virtual fapi2::ReturnCode module_memory_bus_width(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data); + // Byte 33 + TRFC2MIN_MSB_START = 0, + TRFC2MIN_MSB_LEN = 8, - virtual fapi2::ReturnCode module_thermal_sensor(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data); + // Byte 34 & Byte 35 + TRFC4MIN_LSB_START = 0, + TRFC4MIN_LSB_LEN = 8, - virtual fapi2::ReturnCode extended_module_type(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data); + TRFC4MIN_MSB_START = 0, + TRFC4MIN_MSB_LEN = 8, - virtual fapi2::ReturnCode timebases(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data); + // Byte 36 + TFAWMIN_MSN_START = 4, + TFAWMIN_MSN_LEN = 4, - virtual fapi2::ReturnCode min_cycle_time(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data); + // Byte 37 + TFAWMIN_LSB_START = 0, + TFAWMIN_LSB_LEN = 8, - virtual fapi2::ReturnCode max_cycle_time(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data); + // Byte 38 - Entire byte used + // Byte 39 - Entire byte used + // Byte 40 - Entire byte used - virtual fapi2::ReturnCode min_cas_latency_time(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data); + // Byte 41 + TWRMIN_MSN_START = 4, // MSN = most significant nibble + TWRMIN_MSN_LEN = 4, - // Note: Yet to be implemented methods -#if 0 + // Byte 42 + TWRMIN_LSB_START = 0, // LSB = least significant nibble + TWRMIN_LSB_LEN = 8, - virtual fapi2::ReturnCode supported_cas_latencies(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data); + // Byte 43 + TWTRMIN_L_MSN_START = 0, // MSN = most significant nibble + TWTRMIN_L_MSN_LEN = 4, + TWTRMIN_S_MSN_START = 4, // MSN = most significant nibble + TWTRMIN_S_MSN_LEN = 4, - virtual fapi2::ReturnCode min_ras_to_cas_delay_time(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data); + // Byte 44 + TWTRMIN_S_LSB_START = 0, // LSB = least significant byte + TWTRMIN_S_LSB_LEN = 8, - virtual fapi2::ReturnCode min_row_precharge_delay_time(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data); + // Byte 45 + TWTRMIN_L_LSB_START = 0, + TWTRMIN_L_LSB_LEN = 8, - virtual fapi2::ReturnCode upper_nibble_tRAS_tRC(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data); - - virtual fapi2::ReturnCode min_activate_to_activate_refresh_delay_time(const fapi2::Target& - i_target_dimm, - const uint8_t* i_spd_data); - - virtual fapi2::ReturnCode min_activate_to_precharge_delay_time(const fapi2::Target& - i_target_dimm, - const uint8_t* i_spd_data); - - virtual fapi2::ReturnCode min_refresh_recovery_delay_time_1(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data); - - virtual fapi2::ReturnCode min_refresh_recovery_delay_time_2(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data); - - virtual fapi2::ReturnCode min_refresh_recovery_delay_time_4(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data); + // Bytes 46 - 59 - reserved - virtual fapi2::ReturnCode min_four_activate_window_time(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data); + // Bytes 60 - 77 - Connector to SDRAM Bit Mapping ?? - virtual fapi2::ReturnCode min_act_to_act_delay_time_diff_bank_group(const fapi2::Target& - i_target_dimm, - const uint8_t* i_spd_data); + // Bytes 78 - 116 - reserved - virtual fapi2::ReturnCode min_act_to_act_delay_time_same_bank_group(const fapi2::Target& - i_target_dimm, - const uint8_t* i_spd_data); + // Bytes 117 - 125 : Entire byte used - virtual fapi2::ReturnCode min_cas_to_cas_delay_time(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data); + // Byte 126 + CRC_MSB_START = 0, + CRC_MSB_LEN = 8, - virtual fapi2::ReturnCode min_write_recovery_time(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data); + // Byte 127 + CRC_LSB_START = 0, + CRC_LSB_LEN = 8, - virtual fapi2::ReturnCode min_write_to_read_time_diff_bank_group(const fapi2::Target& - i_target_dimm, - const uint8_t* i_spd_data); + // Bytes 128 ~ 191 Module-Specific Section ?? - virtual fapi2::ReturnCode min_write_recovery_time_same_bank_group(const fapi2::Target& - i_target_dimm, - const uint8_t* i_spd_data); + // Bytes 192 ~ 255 Hybrid Memory Architecture Specific Parameters ?? - virtual fapi2::ReturnCode connector_to_sdram_bit_mapping(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data); + // Bytes 256 ~ 319 Extended Function Parameter Block ?? - virtual fapi2::ReturnCode offset_for_min_cas_to_cas_delay_time(const fapi2::Target& - i_target_dimm, - const uint8_t* i_spd_data); + // Bytes 320 ~ 383 Module Supplier’s Data ?? +}; - virtual fapi2::ReturnCode offset_min_act_to_act_delay_time_diff_bank_gp(const fapi2::Target& - i_target_dimm, - const uint8_t* i_spd_data); +enum SDRAM_PACKAGE_TYPE : uint64_t +{ + // Signal loading + MONOLITHIC = 0, + NON_MONOLITHIC = 1, + + // Package Type + UNSPECIFIED = 0, + MULTI_LOAD_STACK = 1, + SINGLE_LOAD_STACK = 2, +}; - virtual fapi2::ReturnCode offset_min_act_to_act_delay_time_same_bank_gp(const fapi2::Target& - i_target_dimm, - const uint8_t* i_spd_data); +enum NOMINAL_VOLTAGE : uint64_t +{ + NOT_OPERABLE = 0, + OPERABLE = 1, - virtual fapi2::ReturnCode offset_for_min_act_to_act_refresh_delay_time(const fapi2::Target& - i_target_dimm, - const uint8_t* i_spd_data); + NOT_ENDURANT = 0, + ENDURANT = 1 +}; - virtual fapi2::ReturnCode offset_for_min_row_precharge_delay_time(const fapi2::Target& - i_target_dimm, - const uint8_t* i_spd_data); - virtual fapi2::ReturnCode offset_for_min_ras_to_cas_delay_time(const fapi2::Target& - i_target_dimm, - const uint8_t* i_spd_data); +/// +/// @class decoder +/// @brief Base SPD DRAM decoder +/// +class decoder +{ - virtual fapi2::ReturnCode offset_for_min_cas_latency_time(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data); + public: + // Constructor + decoder() = default; - virtual fapi2::ReturnCode offset_for_min_cycle_time(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data); + // Deconstructor + virtual ~decoder() = default; - virtual fapi2::ReturnCode offset_for_max_cycle_time(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data); - virtual fapi2::ReturnCode crc_for_base_config_section(const fapi2::Target& i_target_dimm, - const uint8_t* i_spd_data); -#endif -}; + ///////////////////////// + // Static members functions + ///////////////////////// + + /// + /// @brief Decodes SPD Revision encoding level + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value revision number + /// @return fapi2::ReturnCode + /// @note Decodes SPD Byte 1 (3~0). + /// @note Item JC-45-2220.01x + /// @note Page 14-15 + /// @note DDR4 SPD Document Release 3 + /// + static fapi2::ReturnCode rev_encoding_level(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value); + /// + /// @brief Decodes SPD Revision additions level + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value revision number + /// @return fapi2::ReturnCode + /// @note Decodes SPD Byte 1 (bits 7~4). + /// @note Item JC-45-2220.01x + /// @note Page 14-15 + /// @note DDR4 SPD Document Release 3 + /// + static fapi2::ReturnCode rev_additions_level(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value); + + /// + /// @brief Decodes base module type (DIMM type) from SPD + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value + /// @return fapi2::ReturnCode + /// @note Decodes SPD Byte 3 (bits 3~0) + /// @note Item JC-45-2220.01x + /// @note Page 17 + /// @note DDR4 SPD Document Release 3 + /// + static fapi2::ReturnCode base_module_type(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value); + + /// + /// @brief Object factory to select correct decoder based on SPD revision & dimm type + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value shared pointer to the factory object + /// @return fapi2::ReturnCode + /// + static fapi2::ReturnCode factory(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + std::shared_ptr& o_value); + + ///////////////////////// + // Member Methods + ///////////////////////// + + /// + /// @brief Decodes number of used SPD bytes + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value number of SPD bytes used + /// @return fapi2::ReturnCode + /// @note Decodes SPD Byte 0 (3~0) + /// @note Item JC-45-2220.01x + /// @note Page 14 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode number_of_used_bytes(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint16_t& o_value); + + /// + /// @brief Decodes total number of SPD bytes + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value number of total SPD bytes + /// @return fapi2::ReturnCode + /// @note Decodes SPD Byte 0 (bits 6~4) + /// @note Item JC-45-2220.01x + /// @note Page 14 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode number_of_total_bytes(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint16_t& o_value); + + /// + /// @brief Decodes DRAM Device Type + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value dram device type enumeration + /// @return fapi2::ReturnCode + /// @note Decodes SPD Byte 2 + /// @note Item JC-45-2220.01x + /// @note Page 16 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode dram_device_type(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value); + + /// + /// @brief Decodes hybrid media field from SPD + /// @param[in] i_target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value + /// @return fapi2::ReturnCode + /// @note Decodes SPD Byte 3 (bits 6~4) + /// @note Item JC-45-2220.01x + /// @note Page 17 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode hybrid_media(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value); + /// + /// @brief Decodes hybrid field from SPD + /// @param[in] i_target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value + /// @return fapi2::ReturnCode + /// @note Decodes SPD Byte 3 (bit 7) + /// @note Item JC-45-2220.01x + /// @note Page 17 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode hybrid(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value); + /// + /// @brief Decodes SDRAM density from SPD + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value SDRAM density in GBs + /// @return fapi2::ReturnCode + /// @note SPD Byte 4 (bits 3~0) + /// @note Item JC-45-2220.01x + /// @note Page 18 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode sdram_density(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value); + /// + /// @brief Decodes number of SDRAM banks from SPD + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value Number of SDRAM banks + /// @return fapi2::ReturnCode + /// @note SPD Byte 4 (bits 5~4) + /// @note Item JC-45-2220.01x + /// @note Page 18 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode banks(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value); + + /// + /// @brief Decodes number of SDRAM bank groups from SPD + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value Number of SDRAM bank groups + /// @return fapi2::ReturnCode + /// @note SPD Byte 4 (bits 7~6) + /// @note Item JC-45-2220.01x + /// @note Page 18 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode bank_groups(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value); + /// + /// @brief Decodes number of SDRAM column address bits + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @return fapi2::ReturnCode + /// @note SPD Byte 5 (bits 2~0) + /// @note Item JC-45-2220.01x + /// @note Page 18 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode column_address_bits(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value); + /// + /// @brief Decodes number of SDRAM row address bits + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @return fapi2::ReturnCode + /// @note SPD Byte 5 (bits 5~3) + /// @note Item JC-45-2220.01x + /// @note Page 18 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode row_address_bits(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value); + /// + /// @brief Decodes Primary SDRAM signal loading + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @return fapi2::ReturnCode + /// @note SPD Byte 6 (bits 1~0) + /// @note Item JC-45-2220.01x + /// @note Page 19 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode prim_sdram_signal_loading(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value); + /// + /// @brief Decodes Primary SDRAM die count + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @return fapi2::ReturnCode + /// @note SPD Byte 6 (bits 6~4) + /// @note Item JC-45-2220.01x + /// @note Page 19 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode prim_sdram_die_count(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value); + /// + /// @brief Decodes Primary SDRAM package type + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @return fapi2::ReturnCode + /// @note SPD Byte 6 (bit 7) + /// @note Item JC-45-2220.01x + /// @note Page 19 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode prim_sdram_package_type(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value); + /// + /// @brief Decode SDRAM Maximum activate count + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @return fapi2::ReturnCode + /// @note SPD Byte 7 (bits 3~0) + /// @note Item JC-45-2220.01x + /// @note Page 20 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode maximum_activate_count(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint32_t& o_value); + /// + /// @brief Decode SDRAM Maximum activate window (multiplier), tREFI uknown at this point + /// @param[in] i_target + /// @param[in] i_spd_data + /// @return fapi2::ReturnCode + /// @note SPD Byte 7 (bits 3~0) + /// @note Item JC-45-2220.01x + /// @note Page 20 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode maximum_activate_window_multiplier(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint32_t& o_value); + /// + /// @brief Decode Soft post package repair (soft PPR) + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @return fapi2::ReturnCode + /// @note SPD Byte 9 (bit 5) + /// @note Item JC-45-2220.01x + /// @note Page 21 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode soft_post_package_repair(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value); + /// + /// @brief Decode Post package repair (PPR) + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @return fapi2::ReturnCode + /// @note SPD Byte 9 (bits 7~6) + /// @note Item JC-45-2220.01x + /// @note Page 21 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode post_package_repair(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value); + /// + /// @brief Decodes Secondary SDRAM signal loading + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @return fapi2::ReturnCode + /// @note SPD Byte 10 (bits 1~0) + /// @note Item JC-45-2220.01x + /// @note Page 22 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode sec_sdram_signal_loading(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value); + /// + /// @brief Decodes Secondary DRAM Density Ratio + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @return fapi2::ReturnCode + /// @note SPD Byte 10 (bits 3~2) + /// @note Item JC-45-2220.01x + /// @note Page 22 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode sec_dram_density_ratio(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value); + /// + /// @brief Decodes Secondary SDRAM die count + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @return fapi2::ReturnCode + /// @note SPD Byte 10 (bits 6~4) + /// @note Item JC-45-2220.01x + /// @note Page 22 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode sec_sdram_die_count(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value); + /// + /// @brief Decodes Secondary SDRAM package type + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @return fapi2::ReturnCode + /// @note SPD Byte 10 (bit 7) + /// @note Item JC-45-2220.01x + /// @note Page 22 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode sec_sdram_package_type(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value); + /// + /// @brief Decode Module Nominal Voltage, VDD + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value enum representing if 1.2V is operable + /// @return fapi2::ReturnCode + /// @note SPD Byte 11 (bit 0) + /// @note Item JC-45-2220.01x + /// @note Page 23 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode operable_nominal_voltage(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value); + /// + /// @brief Decode Module Nominal Voltage, VDD + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value enum representing if 1.2V is endurant + /// @return fapi2::ReturnCode + /// @note SPD Byte 11 (bit 1) + /// @note Item JC-45-2220.01x + /// @note Page 23 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode endurant_nominal_voltage(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value); + /// + /// @brief Decodes SDRAM device width + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value device width in bits + /// @return fapi2::ReturnCode + /// @note SPD Byte 12 (bits 2~0) + /// @note Item JC-45-2220.01x + /// @note Page 23 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode device_width(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value); + /// + /// @brief Decodes number of package ranks per DIMM + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value number of package ranks per DIMM + /// @return fapi2::ReturnCode + /// @note SPD Byte 12 (bits 5~3) + /// @note Item JC-45-2220.01x + /// @note Page 23 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode num_package_ranks_per_dimm(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value); + /// + /// @brief Decodes Rank Mix + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value rank mix value from SPD + /// @return fapi2::ReturnCode + /// @note SPD Byte 12 (bit 6) + /// @note Item JC-45-2220.01x + /// @note Page 23 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode rank_mix(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value); + /// + /// @brief Decodes primary bus width + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value primary bus width in bits + /// @return fapi2::ReturnCode + /// @note SPD Byte 13 (bits 2~0) + /// @note Item JC-45-2220.01x + /// @note Page 27 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode prim_bus_width(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value); + /// + /// @brief Decodes bus width extension + /// @param[in] i_target FAPI2 DIMM targetn + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value bus width extension in bits + /// @return fapi2::ReturnCode + /// @note SPD Byte 13 (bits 4~3) + /// @note Item JC-45-2220.01x + /// @note Page 27 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode bus_width_extension(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value); + /// + /// @brief Decode Module Thermal Sensor + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value thermal sensor value from SPD + /// @return fapi2::ReturnCode + /// @note SPD Byte 14 (bit 7) + /// @note Item JC-45-2220.01x + /// @note Page 28 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode thermal_sensor(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value); + /// + /// @brief Decode Extended Base Module Type + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value extended base module type value from SPD + /// @return fapi2::ReturnCode + /// @note SPD Byte 15 (bits 3~0) + /// @note Item JC-45-2220.01x + /// @note Page 28 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode extended_base_module_type(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value); + /// + /// @brief Decode Fine Timebase + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value fine_timebase from SPD in picoseconds + /// @return fapi2::ReturnCode + /// @note SPD Byte 17 (bits 1~0) + /// @note Item JC-45-2220.01x + /// @note Page 29 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode fine_timebase(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value); + /// + /// @brief Decode Medium Timebase + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value fine_timebase from SPD in picoseconds + /// @return fapi2::ReturnCode + /// @note SPD Byte 17 (bits 3~2) + /// @note Item JC-45-2220.01x + /// @note Page 29 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode medium_timebase(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value); + /// + /// + /// @brief Decodes SDRAM Minimum Cycle Time in MTB + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value tCKmin in MTB units + /// @return fapi2::ReturnCode + /// @note SPD Byte 18 + /// @note Item JC-45-2220.01x + /// @note Page 31-32 + /// @note DDR4 SPD Document Release 3 + /// @warning If tCKmin cannot be divided evenly by the MTB, + /// this byte must be rounded up to the next larger + /// integer and the Fine Offset for tCKmin (SPD byte 125) + /// used for correction to get the actual value. + /// + virtual fapi2::ReturnCode min_cycle_time(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value); + + /// + /// @brief Decodes SDRAM Maximum Cycle Time in MTB + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value tCKmax in MTB units + /// @return fapi2::ReturnCode + /// @note SPD Byte 19 + /// @note Item JC-45-2220.01x + /// @note Page 32 + /// @note DDR4 SPD Document Release 3 + /// @warning If tCKmax cannot be divided evenly by the MTB, + /// this byte must be rounded up to the next larger + /// integer and the Fine Offset for tCKmax (SPD byte 124) + /// used for correction to get the actual value. + /// + virtual fapi2::ReturnCode max_cycle_time(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value); + /// + /// @brief Decode CAS Latencies Supported + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value bitmap of supported CAS latencies + /// @return fapi2::ReturnCode + /// @note SPD Bytes 20-23 + /// @note Item JC-45-2220.01x + /// @note Page 33-34 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode supported_cas_latencies(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint64_t& o_value); + /// + /// @brief Decodes SDRAM Minimum CAS Latency Time in MTB + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value tAAmin in MTB units + /// @return fapi2::ReturnCode + /// @note SPD Byte 24 + /// @note Item JC-45-2220.01x + /// @note Page 34 + /// @note DDR4 SPD Document Release 3 + /// @warning If tAAmin cannot be divided evenly by the MTB, + /// this byte must be rounded up to the next larger + /// integer and the Fine Offset for tAAmin (SPD byte 123) + /// used for correction to get the actual value. + /// + virtual fapi2::ReturnCode min_cas_latency_time(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value); + /// + /// @brief Decodes SDRAM Minimum RAS to CAS Delay Time in MTB + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value tRCDmin in MTB units + /// @return fapi2::ReturnCode + /// @note SPD Byte 25 + /// @note Item JC-45-2220.01x + /// @note Page 35 + /// @note DDR4 SPD Document Release 3 + /// @warning If tRCDmin cannot be divided evenly by the MTB, + // this byte must be rounded up to the next larger + /// integer and the Fine Offset for tRCDmin (SPD byte 122) + /// used for correction to get the actual value + /// + virtual fapi2::ReturnCode min_ras_to_cas_delay_time(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value); + /// + /// @brief Decodes SDRAM Minimum Row Precharge Delay Time in MTB + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value tRPmin in MTB units + /// @return fapi2::ReturnCode + /// @note SPD Byte 26 + /// @note Item JC-45-2220.01x + /// @note Page 36-37 + /// @note DDR4 SPD Document Release 3 + /// @warning If tRPmin cannot be divided evenly by the MTB, + // this byte must be rounded up to the next larger + /// integer and the Fine Offset for tRPmin (SPD byte 121) + /// used for correction to get the actual value + /// + virtual fapi2::ReturnCode min_row_precharge_delay_time(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value); + /// + /// @brief Decodes SDRAM Minimum Active to Precharge Delay Time in MTB + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value tRASmin in MTB units + /// @return fapi2::ReturnCode + /// @note SPD Byte 28 (bits 7~4) & SPD Byte 27 (bits 3~0) + /// @note Item JC-45-2220.01x + /// @note Page 38 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode min_active_to_precharge_delay_time(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value); + /// + /// @brief Decodes SDRAM Minimum Active to Active/Refresh Delay Time in MTB + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value tRCmin in MTB units + /// @return fapi2::ReturnCode + /// @note SPD Byte 27 (bits 7~4) & SPD Byte 29 (bits 7~0) + /// @note Item JC-45-2220.01x + /// @note Page 38 + /// @note DDR4 SPD Document Release 3 + /// @warning If tRCmin cannot be divided evenly by the MTB, + /// this byte must be rounded up to the next larger + /// integer and the Fine Offset for tRCmin (SPD byte 120) + /// used for correction to get the actual value. + /// + virtual fapi2::ReturnCode min_active_to_active_refresh_delay_time(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value); + /// + /// @brief Decodes SDRAM Minimum Refresh Recovery Delay Time 1 + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value tRFC1min in MTB units + /// @return fapi2::ReturnCode + /// @note SPD Byte 30 & Byte 31 + /// @note Item JC-45-2220.01x + /// @note Page 39-40 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode min_refresh_recovery_delay_time_1(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value); + /// + /// @brief Decodes SDRAM Minimum Refresh Recovery Delay Time 2 + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value tRFC2min in MTB units + /// @return fapi2::ReturnCode + /// @note SPD Byte 32 & Byte 33 + /// @note Item JC-45-2220.01x + /// @note Page 40 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode min_refresh_recovery_delay_time_2(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value); + /// + /// @brief Decodes SDRAM Minimum Refresh Recovery Delay Time 4 + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value tRFC4min in MTB units + /// @return fapi2::ReturnCode + /// @note SPD Byte 34 & Byte 35 + /// @note Item JC-45-2220.01x + /// @note Page 40 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode min_refresh_recovery_delay_time_4(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value); + /// + /// @brief Decodes SDRAM Minimum Four Activate Window Delay Time + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value tFAWmin in MTB units + /// @return fapi2::ReturnCode + /// @note SPD Byte 36 (bits 3~0) & Byte 37 (bits 7~0) + /// @note Item JC-45-2220.01x + /// @note Page 42 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode min_tfaw(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value); + /// + /// @brief Decodes Minimum Activate to Activate Delay Time - Different Bank Group + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value tRRD_Smin MTB units + /// @return fapi2::ReturnCode + /// @note SPD Byte 38 + /// @note Item JC-45-2220.01x + /// @note Page 43 + /// @note DDR4 SPD Document Release 3 + /// @warning If tRRD_Smin cannot be divided evenly by the MTB, + /// this byte must be rounded up to the next larger + /// integer and the Fine Offset for tRRD_Smin (SPD byte 119) + /// used for correction to get the actual value. + /// + virtual fapi2::ReturnCode min_trrd_s(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value); + /// + /// @brief Decodes Minimum Activate to Activate Delay Time - Same Bank Group + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value tRRD_Lmin MTB units + /// @return fapi2::ReturnCode + /// @note SPD Byte 39 + /// @note Item JC-45-2220.01x + /// @note Page 43-44 + /// @note DDR4 SPD Document Release 3 + /// @warning If tRRD_Lmin cannot be divided evenly by the MTB, + /// this byte must be rounded up to the next larger + /// integer and the Fine Offset for tRRD_Lmin (SPD byte 118) + /// used for correction to get the actual value. + /// + virtual fapi2::ReturnCode min_trrd_l(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value); + /// + /// @brief Decodes Minimum CAS to CAS Delay Time - Same Bank Group + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value tCCD_Lmin MTB units + /// @return fapi2::ReturnCode + /// @note SPD Byte 40 + /// @note Item JC-45-2220.01x + /// @note Page 44-45 + /// @note DDR4 SPD Document Release 3 + /// @warning If tCCD_Lmin cannot be divided evenly by the MTB, + /// this byte must be rounded up to the next larger + /// integer and the Fine Offset for tCCD_Lmin (SPD byte 117) + /// used for correction to get the actual value. + /// + virtual fapi2::ReturnCode min_tccd_l(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value); + /// + /// @brief Decodes Minimum Write Recovery Time + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value tWRmin in MTB units + /// @return fapi2::ReturnCode + /// @note SPD Byte 41 (bits 3~0) & Byte 42 (bits 7~0) + /// @note Item JC-45-2220.01x + /// @note Page 40 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode min_write_recovery_time(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value); + /// + /// @brief Decodes Minimum Write to Read Time - Different Bank Group + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value tWRT_Smin in MTB units + /// @return fapi2::ReturnCode + /// @note SPD Byte 43 (bits 3~0) & Byte 44 (bits 7~0) + /// @note Item JC-45-2220.01x + /// @note Page 40 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode min_twtr_s(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value); + + /// + /// @brief Decodes Minimum Write to Read Time - Same Bank Group + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value tWRT_Lmin in MTB units + /// @return fapi2::ReturnCode + /// @note SPD Byte 43 (bits 7~4) & Byte 45 (bits 7~0) + /// @note Item JC-45-2220.01x + /// @note Page 46 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode min_twtr_l(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value); + /// + /// @brief Decodes Fine Offset for Minimum CAS to CAS Delay Time - Same Bank Group + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value tCCD_Lmin offset in FTB units + /// @return fapi2::ReturnCode + /// @note SPD Byte 117 + /// @note Item JC-45-2220.01x + /// @note Page 52 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode fine_offset_min_tccd_l(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value); + /// + /// @brief Decodes Fine Offset for Minimum Activate to Activate Delay Time - Same Bank Group + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value tRRD_Lmin offset in FTB units + /// @return fapi2::ReturnCode + /// @note SPD Byte 118 + /// @note Item JC-45-2220.01x + /// @note Page 52 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode fine_offset_min_trrd_l(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value); + /// + /// @brief Decodes Fine Offset for Minimum Activate to Activate Delay Time - Different Bank Group + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value tRRD_Smin offset in FTB units + /// @return fapi2::ReturnCode + /// @note SPD Byte 119 + /// @note Item JC-45-2220.01x + /// @note Page 52 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode fine_offset_min_trrd_s(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value); + /// + /// @brief Decodes Fine Offset for Minimum Active to Active/Refresh Delay Time + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value tRCmin offset in FTB units + /// @return fapi2::ReturnCode + /// @note SPD Byte 120 + /// @note Item JC-45-2220.01x + /// @note Page 52 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode fine_offset_min_trc(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value); + /// + /// @brief Decodes Fine Offset for Minimum Row Precharge Delay Time + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value tRPmin offset in FTB units + /// @return fapi2::ReturnCode + /// @note SPD Byte 121 + /// @note Item JC-45-2220.01x + /// @note Page 52 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode fine_offset_min_trp(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value); + /// + /// @brief Decodes Fine Offset for SDRAM Minimum RAS to CAS Delay Time + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value tRCDmin offset in FTB units + /// @return fapi2::ReturnCode + /// @note SPD Byte 122 + /// @note Item JC-45-2220.01x + /// @note Page 52 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode fine_offset_min_trcd(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value); + /// + /// @brief Decodes Fine Offset for SDRAM Minimum CAS Latency Time + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value tAAmin offset in FTB units + /// @return fapi2::ReturnCode + /// @note SPD Byte 123 + /// @note Item JC-45-2220.01x + /// @note Page 52 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode fine_offset_min_taa(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value); + /// + /// @brief Decodes Fine Offset for SDRAM Maximum Cycle Time + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value tCKmax offset in FTB units + /// @return fapi2::ReturnCode + /// @note SPD Byte 124 + /// @note Item JC-45-2220.01x + /// @note Page 52 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode fine_offset_max_tck(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value); + /// + /// @brief Decodes Fine Offset for SDRAM Minimum Cycle Time + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value tCKmin offset in FTB units + /// @return fapi2::ReturnCode + /// @note SPD Byte 125 + /// @note Item JC-45-2220.01x + /// @note Page 52 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode fine_offset_min_tck(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + int64_t& o_value); + + /// + /// @brief Decodes Cyclical Redundancy Code (CRC) for Base Configuration Section + /// @param[in] i_target FAPI2 DIMM target + /// @param[in] i_spd_data SPD blob + /// @param[out] o_value crc value from SPD + /// @return fapi2::ReturnCode + /// @note SPD Byte 127 & Byte 126 + /// @note Item JC-45-2220.01x + /// @note Page 53 + /// @note DDR4 SPD Document Release 3 + /// + virtual fapi2::ReturnCode cyclical_redundancy_code(const fapi2::Target& i_target, + const uint8_t* i_spd_data, + uint16_t& o_value); +};// decoder }// spd }// mss -- cgit v1.2.1