diff options
Diffstat (limited to 'src/import/chips/p9')
9 files changed, 5036 insertions, 2853 deletions
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/kind.H b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/kind.H index 6dc0c5c45..4e43b5ca0 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/kind.H +++ b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/kind.H @@ -57,7 +57,7 @@ class kind FAPI_TRY( mss::eff_dram_density(i_target, iv_dram_density) ); FAPI_TRY( mss::eff_dram_width(i_target, iv_dram_width) ); FAPI_TRY( mss::eff_num_master_ranks_per_dimm(i_target, iv_master_ranks) ); - FAPI_TRY( mss::eff_dram_rows(i_target, iv_rows) ); + FAPI_TRY( mss::eff_dram_row_bits(i_target, iv_rows) ); FAPI_TRY( mss::eff_dimm_size(i_target, iv_size) ); // TK: Attribute for slave ranks. diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/eff_config.C b/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/eff_config.C new file mode 100644 index 000000000..ce3e1200c --- /dev/null +++ b/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/eff_config.C @@ -0,0 +1,271 @@ + +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: chips/p9/procedures/hwp/memory/lib/eff_config/eff_config.C $ */ +/* */ +/* IBM CONFIDENTIAL */ +/* */ +/* EKB Project */ +/* */ +/* COPYRIGHT 2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* The source code for this program is not published or otherwise */ +/* divested of its trade secrets, irrespective of what has been */ +/* deposited with the U.S. Copyright Office. */ +/* */ +/* IBM_PROLOG_END_TAG */ +/// +/// @file eff_config.C +/// @brief Determine effective config for mss settings +/// +// *HWP HWP Owner: Andre Marin <aamarin@us.ibm.com> +// *HWP HWP Backup: Brian Silver <bsilver@us.ibm.com> +// *HWP Team: Memory +// *HWP Level: 2 +// *HWP Consumed by: FSP:HB + +#include <fapi2.H> +#include <mss.H> +#include "../spd/spd_decoder.H" +#include "eff_config.H" +#include "timing.H" + +using fapi2::TARGET_TYPE_MCA; +using fapi2::TARGET_TYPE_MCS; +using fapi2::TARGET_TYPE_DIMM; +using fapi2::TARGET_TYPE_MCBIST; + +namespace mss +{ + +/// +/// @brief Determines & sets effective config for DRAM generation from SPD +/// @param[in] i_target FAPI2 target +/// @param[in] i_spd_data SPD blob +/// @param[in] i_pDecoder shared pointer to decoder factory +/// @return fapi2::ReturnCode +/// +fapi2::ReturnCode eff_config::dram_gen(const fapi2::Target<TARGET_TYPE_DIMM>& i_target, + const uint8_t* i_spd_data, + std::shared_ptr<spd::decoder>& i_pDecoder) +{ + uint8_t l_decoder_val = 0; + uint8_t l_mcs_attrs[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + + // Targets + const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target); + const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target); + + // Current index + const auto l_port_num = index(l_target_port); + const auto l_dimm_num = index(i_target); + + // factory selects correct SPD method dependent on rev & dimm type + FAPI_TRY( spd::decoder::factory(i_target, i_spd_data, i_pDecoder) ); + + FAPI_TRY( i_pDecoder->dram_device_type(i_target, i_spd_data, l_decoder_val) ); + + // Get & update MCS attribute + FAPI_TRY( eff_dram_gen(l_target_mcs, &l_mcs_attrs[0][0]) ); + l_mcs_attrs[l_port_num][l_dimm_num] = l_decoder_val; + FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_GEN, l_target_mcs, l_mcs_attrs) ); + +fapi_try_exit: + return fapi2::current_err; +}// dram_gen + + +/// +/// @brief Determines & sets effective config for DIMM type from SPD +/// @param[in] i_target FAPI2 target +/// @param[in] i_spd_data SPD blob +/// @return fapi2::ReturnCode +/// +fapi2::ReturnCode eff_config::dimm_type(const fapi2::Target<TARGET_TYPE_DIMM>& i_target, + const uint8_t* i_spd_data) +{ + uint8_t l_decoder_val = 0; + uint8_t l_mcs_attrs[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + + // Targets + const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target); + const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target); + + // Current index + const auto l_port_num = index(l_target_port); + const auto l_dimm_num = index(i_target); + + FAPI_TRY( spd::decoder::base_module_type(i_target, i_spd_data, l_decoder_val) ); + + // Get & update MCS attribute + FAPI_TRY( eff_dimm_type(l_target_mcs, &l_mcs_attrs[0][0]) ); + l_mcs_attrs[l_port_num][l_dimm_num] = l_decoder_val; + FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DIMM_TYPE, l_target_mcs, l_mcs_attrs) ); + +fapi_try_exit: + return fapi2::current_err; +}// dimm_type + +/// +/// @brief Determines & sets effective config for Hybrid memory type from SPD +/// @param[in] i_target FAPI2 target +/// @param[in] i_spd_data SPD blob +/// @param[in] i_pDecoder shared pointer to decoder factory +/// @return fapi2::ReturnCode +/// +fapi2::ReturnCode eff_config::hybrid_memory_type(const fapi2::Target<TARGET_TYPE_DIMM>& i_target, + const uint8_t* i_spd_data, + std::shared_ptr<spd::decoder>& i_pDecoder) +{ + uint8_t l_decoder_val = 0; + uint8_t l_mcs_attrs[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + + // Targets + const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target); + const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target); + + // Current index + const auto l_port_num = index(l_target_port); + const auto l_dimm_num = index(i_target); + + // Factory selects correct SPD method dependent on rev & dimm type + FAPI_TRY( spd::decoder::factory(i_target, i_spd_data, i_pDecoder) ); + + FAPI_TRY(i_pDecoder->hybrid_media(i_target, i_spd_data, l_decoder_val)); + + // Get & update MCS attribute + FAPI_TRY( eff_hybrid_memory_type(l_target_mcs, &l_mcs_attrs[0][0]) ); + l_mcs_attrs[l_port_num][l_dimm_num] = l_decoder_val; + FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_HYBRID_MEMORY_TYPE, l_target_mcs, l_mcs_attrs) ); + +fapi_try_exit: + return fapi2::current_err; +}// dimm_type + +/// +/// @brief Sets effective config for temperature controlled refresh mode +/// @param[in] i_target FAPI2 target +/// @return fapi2::ReturnCode +/// @note Proposed DDR4 Full spec update(79-4A) +/// @note Committee: JC42.3C +/// @note Committee Item Number: 1716.78C +/// @note 4.8.2 Extended temperature mode (pg. 44) +fapi2::ReturnCode eff_config::temp_ref_range(const fapi2::Target<TARGET_TYPE_DIMM>& i_target) +{ + uint8_t l_mcs_attrs[PORTS_PER_MCS] = {0}; + + // Targets + const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target); + const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target); + + // Current index + const auto l_port_num = index(l_target_port); + + FAPI_TRY( mss::eff_temp_ref_range(l_target_mcs, &l_mcs_attrs[0]) ); + + // TK - I think this will become a platform attribute so this function + // will eventuall get removed - AAM + + // This is defaulted to Extended temperature mode + l_mcs_attrs[l_port_num] = fapi2::ENUM_ATTR_EFF_TEMP_REF_RANGE_EXTEND; + FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_TEMP_REF_RANGE, l_target_mcs, l_mcs_attrs) ); + +fapi_try_exit: + return fapi2::current_err; +}// temp_ref_range + +/// +/// @brief Determines & sets effective config for Refresh Mode +/// @param[in] i_target FAPI2 target +/// @return fapi2::ReturnCode +/// +fapi2::ReturnCode eff_config::fine_refresh_mode(const fapi2::Target<TARGET_TYPE_DIMM>& i_target) +{ + uint8_t l_mcs_attrs[PORTS_PER_MCS] = {0}; + // Targets + const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target); + const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target); + + // Current index + const auto l_port_num = index(l_target_port); + + // Per Warren - should be in Normal mode, might change based on lab test results - AAM + // Get & update MCS attribute + FAPI_TRY( mss::eff_fine_refresh_mode(l_target_mcs, &l_mcs_attrs[0])) ; + l_mcs_attrs[l_port_num] = fapi2::ENUM_ATTR_EFF_FINE_REFRESH_MODE_NORMAL; + FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_FINE_REFRESH_MODE, l_target_mcs, l_mcs_attrs) ); + +fapi_try_exit: + return fapi2::current_err; +}// refresh_mode + + +/// @brief Determines & sets effective config for refresh interval time (tREFI) +/// @param[in] i_target FAPI2 target +/// @return fapi2::ReturnCode +/// +fapi2::ReturnCode eff_config::refresh_interval_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target) +{ + uint8_t l_mcs_attrs_refresh[PORTS_PER_MCS] = {0}; + uint8_t l_refresh_mode = 0; + + uint8_t l_mcs_attrs_trefi[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + uint64_t l_trefi_in_ps = 0; + uint8_t l_trefi_in_nck = 0; + + uint64_t l_mss_freq = 0; + uint64_t l_tCK_in_ps = 0; + + // Targets + const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target); + const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target); + const auto l_target_mcbist = find_target<TARGET_TYPE_MCBIST>(i_target); + + // Current index + const auto l_port_num = index(l_target_port); + const auto l_dimm_num = index(i_target); + + // Retrieve attributes values + FAPI_TRY( mss::freq(l_target_mcbist, l_mss_freq) ); + FAPI_TRY ( mss::eff_fine_refresh_mode(l_target_mcs, &l_mcs_attrs_refresh[0]) ); + + l_refresh_mode = l_mcs_attrs_refresh[l_port_num]; + + switch(l_refresh_mode) + { + case fapi2::ENUM_ATTR_EFF_FINE_REFRESH_MODE_NORMAL: + calc_trefi1(i_target, l_trefi_in_ps); + break; + + case fapi2::ENUM_ATTR_EFF_FINE_REFRESH_MODE_FIXED_2X: + case fapi2::ENUM_ATTR_EFF_FINE_REFRESH_MODE_FLY_2X: + calc_trefi2(i_target, l_trefi_in_ps); + break; + + case fapi2::ENUM_ATTR_EFF_FINE_REFRESH_MODE_FIXED_4X: + case fapi2::ENUM_ATTR_EFF_FINE_REFRESH_MODE_FLY_4X: + calc_trefi4(i_target, l_trefi_in_ps); + break; + } + + // Calculate clock period (tCK) from selected freq from mss_freq + l_tCK_in_ps = freq_to_ps(l_mss_freq); + + // Get & update MCS attribute + FAPI_TRY( eff_dram_trefi(l_target_mcs, &l_mcs_attrs_trefi[0][0]) ); + + l_trefi_in_nck = calc_nck(l_trefi_in_ps, l_tCK_in_ps, uint64_t(INVERSE_DDR4_CORRECTION_FACTOR)); + l_mcs_attrs_trefi[l_port_num][l_dimm_num] = uint8_t(l_trefi_in_nck); + + FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_TREFI, l_target_mcs, l_mcs_attrs_trefi) ); + +fapi_try_exit: + return fapi2::current_err; +}// refresh_interval + + + +}// mss diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/eff_config.H b/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/eff_config.H new file mode 100644 index 000000000..1ddb006bc --- /dev/null +++ b/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/eff_config.H @@ -0,0 +1,112 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: chips/p9/procedures/hwp/memory/lib/eff_config/eff_config.H $ */ +/* */ +/* IBM CONFIDENTIAL */ +/* */ +/* EKB Project */ +/* */ +/* COPYRIGHT 2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* The source code for this program is not published or otherwise */ +/* divested of its trade secrets, irrespective of what has been */ +/* deposited with the U.S. Copyright Office. */ +/* */ +/* IBM_PROLOG_END_TAG */ +/// +/// @file eff_config.H +/// @brief Determine effective config for mss settings +/// +// *HWP HWP Owner: Andre Marin <aamarin@us.ibm.com> +// *HWP FW Owner: Brian Silver <bsilver@us.ibm.com> +// *HWP Team: Memory +// *HWP Level: 2 +// *HWP Consumed by: HB:FSP + +#ifndef _MSS_EFF_CONFIG_H_ +#define _MSS_EFF_CONFIG_H_ + +#include <fapi2.H> +#include <cstdint> +#include "../spd/spd_decoder.H" + +namespace mss +{ + +/// +/// @class eff_config +/// @brief Determine effective config for mss settings +/// +class eff_config +{ + // constructor + eff_config() = default; + + // destructor + ~eff_config() = default; + + public: + //////////////////////// + // Methods + /////////////////////// + + /// + /// @brief Determines & sets effective config for DRAM generation from SPD + /// @param[in] i_target FAPI2 target + /// @param[in] i_spd_data SPD blob + /// @param[in] i_pDecoder shared pointer to decoder factory + /// @return fapi2::ReturnCode + /// + fapi2::ReturnCode dram_gen(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target, + const uint8_t* i_spd_data, + std::shared_ptr<spd::decoder>& i_pDecoder); + + /// + /// @brief Determines & sets effective config for DIMM type + /// @param[in] i_target FAPI2 target + /// @param[in] i_spd_data SPD blob + /// @return fapi2::ReturnCode + /// + fapi2::ReturnCode dimm_type(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target, + const uint8_t* i_spd_data); + /// + /// @brief Determines & sets effective config for Hybrid memory type from SPD + /// @param[in] i_target FAPI2 target + /// @param[in] i_spd_data SPD blob + /// @param[in] i_pDecoder shared pointer to decoder factory + /// @return fapi2::ReturnCode + /// + fapi2::ReturnCode hybrid_memory_type(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target, + const uint8_t* i_spd_data, + std::shared_ptr<spd::decoder>& i_pDecoder); + /// + /// @brief Sets effective config for temperature controlled refresh mode + /// @param[in] i_target FAPI2 target + /// @return fapi2::ReturnCode + /// @note Proposed DDR4 Full spec update(79-4A) + /// @note Committee: JC42.3C + /// @note Committee Item Number: 1716.78C + /// @note 4.8.2 Extended temperature mode (pg. 44) + fapi2::ReturnCode temp_ref_range(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target); + + /// + /// @brief Determines & sets effective config for Refresh Mode + /// @param[in] i_target FAPI2 target + /// @return fapi2::ReturnCode + /// + fapi2::ReturnCode fine_refresh_mode(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target); + + /// @brief Determines & sets effective config for refresh interval time (tREFI) + /// @param[in] i_target FAPI2 target + /// @return fapi2::ReturnCode + /// + fapi2::ReturnCode refresh_interval_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target); + +};// eff_config + +} // mss + +#endif // _MSS_EFF_CONFIG_H_ diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/timing.H b/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/timing.H new file mode 100644 index 000000000..5c921fa5c --- /dev/null +++ b/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/timing.H @@ -0,0 +1,293 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: chips/p9/procedures/hwp/memory/lib/eff_config/timing.H $ */ +/* */ +/* IBM CONFIDENTIAL */ +/* */ +/* EKB Project */ +/* */ +/* COPYRIGHT 2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* The source code for this program is not published or otherwise */ +/* divested of its trade secrets, irrespective of what has been */ +/* deposited with the U.S. Copyright Office. */ +/* */ +/* IBM_PROLOG_END_TAG */ +/// +/// @file timing.H +/// @brief Determine effective config for mss settings +/// +// *HWP HWP Owner: Andre Marin <aamarin@us.ibm.com> +// *HWP FW Owner: Brian Silver <bsilver@us.ibm.com> +// *HWP Team: Memory +// *HWP Level: 2 +// *HWP Consumed by: HB:FSP + +#ifndef _MSS_TIMING_H_ +#define _MSS_TIMING_H_ + +#include <mss.H> +#include <fapi2.H> +#include <cstdint> +#include "../utils/find.H" + +using fapi2::TARGET_TYPE_DIMM; + +namespace mss +{ + +// { density in GBs, tREFI(base) in picoseconds } +static const std::vector<std::pair<uint8_t, uint64_t> > TREFI_BASE = +{ + {2, 7800}, + {4, 7800}, + {8, 7800}, + // 16Gb - TBD +}; + +// { density in GBs, tRFC1(min) in picoseconds } +static const std::vector<std::pair<uint8_t, uint64_t> > TRFC1_MIN = +{ + {2, 160}, + {4, 260}, + {8, 350}, + // 16Gb - TBD +}; + + +// { density in GBs, tRFC2(min) in picoseconds } +static const std::vector<std::pair<uint8_t, uint64_t> > TRFC2_MIN = +{ + {2, 110}, + {4, 160}, + {8, 260}, + // 16Gb - TBD +}; + + +// { density in GBs, tRFC4(min) in picoseconds } +static const std::vector<std::pair<uint8_t, uint64_t> > TRFC4_MIN = +{ + {2, 90}, + {4, 110}, + {8, 160}, + // 16Gb - TBD +}; + +enum GUARD_BAND +{ + // Used for caclulating spd timing values - from JEDEC rounding algorithm + // Correction factor is 1% (for DDR3) or 2.5% (for DDR4) + // when doing integer math, we add-in the inverse correction factor + // Formula used for derivation: + // Guardband = 1000 * (1000* correction_factor) - 1 + INVERSE_DDR3_CORRECTION_FACTOR = 989, + INVERSE_DDR4_CORRECTION_FACTOR = 974, +}; + + +/// +/// @brief Calculates timing value +/// @tparam T input and output type +/// @param[in] i_timing_mtb timing value in MTB units +/// @param[in] i_mtb_multiplier SPD medium timebase +/// @param[in] i_timing_ftb fine offset of timing value +/// @param[in] i_ftb_multiplier SPD fine timebase +/// @return the timing value in picoseconds +/// +template<typename T> +inline T calc_timing_from_timebase(const T i_timing_mtb, + const T i_mtb_multiplier, + const T i_timing_ftb, + const T i_ftb_multiplier) +{ + // JEDEC algorithm + T l_timing_val = i_timing_mtb * i_mtb_multiplier; + T l_fine_offset = i_timing_ftb * i_ftb_multiplier; + + // Needed to do integer math but attribute is uint64 + return l_timing_val + l_fine_offset; +} + + +/// +/// @brief Returns clock cycles +/// @tparam T input and output type +/// @param[in] timing_in_ps timing parameter in ps +/// @param[in] tck_in_ps clock period in ps +/// @param[in] inverse_corr_factor inverse correction factor (defined by JEDEC) +/// @return the clock cycles of timing parameter (provided in ps) +/// @note DDR4 SPD Contents Rounding Algorithm +/// @note Item 2220.46 +/// +template<typename T> +inline T calc_nck(T timing_in_ps, T tck_in_ps, T inverse_corr_factor) +{ + // Preliminary nCK calculation, scaled by 1000 + T temp_nck = timing_in_ps * 1000 / tck_in_ps; + + // Apply inverse of correction factor percentage + temp_nck += inverse_corr_factor; + + return temp_nck / 1000; +} + + +// +// TK - AAM +// These are only used in eff_config, make them non-member non-friend functions in eff_config.C? +// + +/// @brief Calculates refresh interval time 1 (tREFI 1) +/// @param[in] i_target FAPI2 target +/// @param[out] o_value timing val in ps +/// @return fapi2::ReturnCode +/// +inline fapi2::ReturnCode calc_trefi1(const fapi2::Target<TARGET_TYPE_DIMM>& i_target, uint64_t& o_value) +{ + uint8_t l_quotient = 0; + uint8_t l_remainder = 0; + uint64_t l_output = 0; + uint8_t l_temp_ref_range = 0; + uint8_t l_dram_density = 0; + + + FAPI_TRY(mss::eff_dram_density(i_target, l_dram_density)); + + switch(l_temp_ref_range) + { + case fapi2::ENUM_ATTR_EFF_TEMP_REF_RANGE_NORMAL: + mss::find_value_from_key(TREFI_BASE, l_dram_density, o_value); + break; + + case fapi2::ENUM_ATTR_EFF_TEMP_REF_RANGE_EXTEND: + mss::find_value_from_key(TREFI_BASE, l_dram_density, l_output); + l_quotient = l_output / 2; + l_remainder = l_output % 2; + o_value = l_quotient + (l_remainder == 0 ? 0 : 1); + break; + + default: + // l_temp_ref_range will be a platform attribute set by the MRW, + // which they "shouldn't" mess up as long as use "attribute" enums. + // if openpower messes this up we can at least catch it + FAPI_ASSERT(false, + fapi2::MSS_INVALID_TEMP_REF_RANGE(). + set_TEMP_REF_RANGE(l_temp_ref_range), + "%s Incorrect Temperature Ref. Range received: %d ", + mss::c_str(i_target), + l_temp_ref_range); + + break; + } + +fapi_try_exit: + return fapi2::current_err; +} + +/// @brief Calculates refresh interval time 2 (tREFI 2) +/// @param[in] i_target FAPI2 target +/// @param[out] o_value timing val in ps +/// @return fapi2::ReturnCode +/// +inline fapi2::ReturnCode calc_trefi2(const fapi2::Target<TARGET_TYPE_DIMM>& i_target, uint64_t& o_value) +{ + uint8_t l_quotient = 0; + uint8_t l_remainder = 0; + uint64_t l_output = 0; + uint8_t l_temp_ref_range = 0; + uint8_t l_dram_density = 0; + + FAPI_TRY(mss::eff_temp_ref_range(i_target, l_temp_ref_range)); + FAPI_TRY(mss::eff_dram_density(i_target, l_dram_density)); + + switch(l_temp_ref_range) + { + case fapi2::ENUM_ATTR_EFF_TEMP_REF_RANGE_NORMAL: + mss::find_value_from_key(TREFI_BASE, l_dram_density, l_output); + l_quotient = l_output / 2; + l_remainder = l_output % 2; + o_value = l_quotient + (l_remainder == 0 ? 0 : 1); + break; + + case fapi2::ENUM_ATTR_EFF_TEMP_REF_RANGE_EXTEND: + mss::find_value_from_key(TREFI_BASE, l_dram_density, l_output); + l_quotient = l_output / 4; + l_remainder = l_output % 4; + o_value = l_quotient + (l_remainder == 0 ? 0 : 1); + break; + + default: + // l_temp_ref_range will be a platform attribute set by the MRW, + // which they "shouldn't" mess up as long as use "attribute" enums. + // if openpower messes this up we can at least catch it + FAPI_ASSERT(false, + fapi2::MSS_INVALID_TEMP_REF_RANGE(). + set_TEMP_REF_RANGE(l_temp_ref_range), + "%s Incorrect Temperature Ref. Range received: %d ", + mss::c_str(i_target), + l_temp_ref_range); + + break; + } + +fapi_try_exit: + return fapi2::current_err; +} + +/// @brief Calculates refresh interval time 4 (tREFI 4) +/// @param[in] i_target FAPI2 target +/// @param[out] o_value timing val in ps +/// @return fapi2::ReturnCode +/// +inline fapi2::ReturnCode calc_trefi4( const fapi2::Target<TARGET_TYPE_DIMM>& i_target, uint64_t& o_value) +{ + uint8_t l_quotient = 0; + uint8_t l_remainder = 0; + uint64_t l_output = 0; + uint8_t l_temp_ref_range = 0; + uint8_t l_dram_density = 0; + + FAPI_TRY(mss::eff_temp_ref_range(i_target, l_temp_ref_range)); + FAPI_TRY(mss::eff_dram_density(i_target, l_dram_density)); + + switch(l_temp_ref_range) + { + case fapi2::ENUM_ATTR_EFF_TEMP_REF_RANGE_NORMAL: + mss::find_value_from_key(TREFI_BASE, l_dram_density, l_output); + l_quotient = l_output / 4; + l_remainder = l_output % 4; + o_value = l_quotient + (l_remainder == 0 ? 0 : 1); + break; + + case fapi2::ENUM_ATTR_EFF_TEMP_REF_RANGE_EXTEND: + mss::find_value_from_key(TREFI_BASE, l_dram_density, l_output); + l_quotient = l_output / 8; + l_remainder = l_output % 8; + o_value = l_quotient + (l_remainder == 0 ? 0 : 1); + break; + + default: + // l_temp_ref_range will be a platform attribute set by the MRW, + // which they "shouldn't" mess up as long as use "attribute" enums. + // if openpower messes this up we can at least catch it + FAPI_ASSERT(false, + fapi2::MSS_INVALID_TEMP_REF_RANGE(). + set_TEMP_REF_RANGE(l_temp_ref_range), + "%s Incorrect Temperature Ref. Range received: %d ", + mss::c_str(i_target), + l_temp_ref_range); + + break; + } + +fapi_try_exit: + return fapi2::current_err; +} + +} // mss + +#endif 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 <fapi2.H> -#include "../mss.H" +#include <mss.H> #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<std::pair<uint8_t, uint16_t> > 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<std::pair<uint8_t, uint16_t> > 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<std::pair<uint8_t, uint8_t> > 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<std::pair<uint8_t, uint8_t> > 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<std::pair<uint8_t, uint8_t> > 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<std::pair<uint8_t, uint8_t> > 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<std::pair<uint8_t, uint8_t> > 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<std::pair<uint8_t, uint8_t> > 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<std::pair<uint8_t, uint8_t> > 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<std::pair<uint8_t, uint8_t> > 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<std::pair<uint8_t, uint8_t> > 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<std::pair<uint8_t, uint8_t> > 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<std::pair<uint8_t, uint8_t> > 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<std::pair<uint8_t, uint8_t> > 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<std::pair<uint8_t, uint32_t> > 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<std::pair<uint8_t, uint32_t> > 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<std::pair<uint8_t, uint8_t> > 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<std::pair<uint8_t, uint8_t> > 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<std::pair<uint8_t, uint8_t> > SEC_SIGNAL_LOADING_MAP = +{ + // {key byte, signal loading} + {0, UNSPECIFIED}, + {1, MULTI_LOAD_STACK}, + {2, SINGLE_LOAD_STACK} +}; + +static const std::vector<std::pair<uint8_t, uint8_t> > 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<std::pair<uint8_t, uint8_t> > 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<std::pair<uint8_t, uint8_t> > 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<std::pair<uint8_t, uint8_t> > 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<std::pair<uint8_t, uint8_t> > 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<std::pair<uint8_t, uint8_t> > 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<std::pair<uint8_t, uint8_t> > 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<std::pair<uint8_t, uint8_t> > BUS_WIDTH_EXT_MAP = { - // // Units - 0, // bits - 8, // bits + {0, 0}, + {1, 8} // All others reserved }; @@ -384,3165 +383,3733 @@ 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<std::pair<uint8_t, int64_t> > 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<std::pair<uint8_t, int64_t> > 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<TARGET_TYPE_DIMM>& 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<fapi2::TARGET_TYPE_DIMM>& 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<uint8_t> 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<ENCODING_LEVEL_START, ENCODING_LEVEL_LEN>(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<fapi2::TARGET_TYPE_DIMM>& 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<uint8_t> 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<ADDITIONS_LEVEL_START, ADDITIONS_LEVEL_LEN>(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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& i_target_dimm, +fapi2::ReturnCode decoder::base_module_type(const fapi2::Target<TARGET_TYPE_DIMM>& 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<uint8_t> 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<BASE_MODULE_START, BASE_MODULE_LEN>(l_field_bits); - // Buffers used for bit manipulation - fapi2::buffer<uint8_t> 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<BYTES_USED_START, BYTES_USED_LEN>(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<BYTES_TOTAL_START, BYTES_TOTAL_LEN>(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<BYTES_RESERVED_START, BYTES_RESERVED_LEN>(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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::factory(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target, + const uint8_t* i_spd_data, + std::shared_ptr<decoder>& 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; - // Byte variables used for decoding - uint8_t l_revision_num = 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)); - // Verify SPD revision is not undefined. Value is defined by the JEDEC spec - l_revision_num = i_spd_data[BYTE_INDEX]; + // 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<decoder>(); + 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 - 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); + break; + + 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::number_of_used_bytes(const fapi2::Target<TARGET_TYPE_DIMM>& i_target, + const uint8_t* i_spd_data, + uint16_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX = 2; + 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; - // 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) + // Buffers used for bit manipulation + fapi2::buffer<uint8_t> l_spd_buffer(l_raw_byte); - // Targets - const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm); - const auto l_target_port = find_target<TARGET_TYPE_MCA>(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<BYTES_USED_START, BYTES_USED_LEN>(l_field_bits); - // Byte variables used for decoding - uint8_t l_device_type = 0; + FAPI_DBG("Field_Bits value: %d", l_field_bits); - // Attribute variables used to set decoded vals - uint8_t l_device_gen[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + 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") ); - // Check to assure SPD DRAM device type (map) wont be at invalid values - l_device_type = i_spd_data[BYTE_INDEX]; + // Don't update output with garbage data until until all tests pass + o_value = l_map_value; - 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") ); + FAPI_DBG("%s. Bytes Used: %d", + mss::c_str(i_target), + o_value); - // Retrive entire MCS level attribute - FAPI_TRY(eff_dram_gen(l_target_mcs, &l_device_gen[0][0])); +fapi_try_exit: + return fapi2::current_err; +} - // Update attribute to decoded byte values - l_device_gen[PORT_NUM][DIMM_NUM] = dram_gen_map[l_device_type - MAP_OFFSET]; +/// +/// @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 4~6) +/// @note Item JC-45-2220.01x +/// @note Page 14 +/// @note DDR4 SPD Document Release 3 +/// +fapi2::ReturnCode decoder::number_of_total_bytes(const fapi2::Target<TARGET_TYPE_DIMM>& i_target, + const uint8_t* i_spd_data, + uint16_t& o_value) +{ + constexpr size_t BYTE_INDEX = 0; + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 0; - // Update MCS level attribute - FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_GEN, l_target_mcs, l_device_gen)); + // Buffer used for bit manipulation + fapi2::buffer<uint8_t> l_spd_buffer(l_raw_byte); - // Print decoded info - FAPI_INF("%s SPD data at Byte %d: 0x%llX. Device type : %d", - 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_device_gen[PORT_NUM][DIMM_NUM]); + l_raw_byte); + + // Extracting desired bits + l_spd_buffer.extractToRight<BYTES_TOTAL_START, BYTES_TOTAL_LEN>(l_field_bits); + + FAPI_DBG("Field_Bits value: %d", l_field_bits); + + 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") ); + + FAPI_DBG("%s. Total Bytes: %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<TARGET_TYPE_DIMM>& i_target_dimm, -/// uint8_t* i_spd_data -/// @return fapi2::ReturnCode -/// @note Decodes SPD Byte 3 +/// @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::module_type(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::dram_device_type(const fapi2::Target<TARGET_TYPE_DIMM>& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX = 3; - // 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 + constexpr size_t BYTE_INDEX = 2; + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; - // Hybrid Media limit - const size_t MAX_HYBRID_MEDIA_KEY = 1; // All other key values 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 - const size_t MAX_HYBRID_KEY = 1; // Nothing else exits afterwards + 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") ); - // Targets - const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm); - const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm); + // Print decoded info + FAPI_DBG("%s Device type : %d", + c_str(i_target), + o_value); - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); +fapi_try_exit: + return fapi2::current_err; +} - // Byte variables used for decoding - uint8_t l_base_module_type = 0; - uint8_t l_hybrid_media = 0; - uint8_t l_hybrid = 0; +/// +/// @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<TARGET_TYPE_DIMM>& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value) - // Attribute variables used to set decoded vals - uint8_t l_module_type[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; +{ + 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<uint8_t> l_spd_buffer(i_spd_data[BYTE_INDEX]); + fapi2::buffer<uint8_t> l_spd_buffer(l_raw_byte); // 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); + + // Extracting desired bits + l_spd_buffer.extractToRight<HYBRID_MEDIA_START, HYBRID_MEDIA_LEN>(l_field_bits); - // Decoding bits 3~0 - l_spd_buffer.extractToRight<BASE_MODULE_START, BASE_MODULE_LEN>(l_base_module_type); + FAPI_DBG("Field_Bits value: %d", l_field_bits); - // 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( 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") ); - // Decoding bits 6~4 - l_spd_buffer.extractToRight<HYBRID_MEDIA_START, HYBRID_MEDIA_LEN>(l_hybrid_media); + FAPI_DBG("%s. Hybrid Media: %d", + mss::c_str(i_target), + 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") ); +fapi_try_exit: + return fapi2::current_err; +} - // Decoding bit 7 - l_spd_buffer.extractToRight<HYBRID_START, HYBRID_LEN>(l_hybrid); +/// +/// @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 Decodes SPD Byte 3 (bit 7) +/// @note Item JC-45-2220.01x +/// @note Page 17 +/// @note DDR4 SPD Document Release 3 +/// +fapi2::ReturnCode decoder::hybrid(const fapi2::Target<TARGET_TYPE_DIMM>& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value) +{ + 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<uint8_t> 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<HYBRID_START, HYBRID_LEN>(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_MAP, l_field_bits, o_value), + BYTE_INDEX, + l_field_bits, + "Failed check on hybrid field") ); - 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: %d", + mss::c_str(i_target), + o_value); fapi_try_exit: return fapi2::current_err; } /// -/// @brief Decode SDRAM density -/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm, -/// uint8_t* i_spd_data +/// @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 +/// @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<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::sdram_density(const fapi2::Target<TARGET_TYPE_DIMM>& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value) + { - // Immutable constants - const size_t BYTE_INDEX = 4; - // 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 + constexpr size_t BYTE_INDEX = 4; + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 0; - // DRAM banks mapping limits - const size_t BANKS_MAX_VALID_KEY = 1; // The rest are not supported or reserved + // Buffer used for bit manipulation + fapi2::buffer<uint8_t> l_spd_buffer(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); + + // Extracting desired bits + l_spd_buffer.extractToRight<SDRAM_CAPACITY_START, SDRAM_CAPACITY_LEN>(l_field_bits); - // DRAM bank groups mapping limits - const size_t BANK_GRP_MAX_VALID_KEY = 2; // The rest are not supported or reserved + // 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(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); - // Targets - const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm); - const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm); +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 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 4~5) +/// @note Item JC-45-2220.01x +/// @note Page 18 +/// @note DDR4 SPD Document Release 3 +/// +fapi2::ReturnCode decoder::banks(const fapi2::Target<TARGET_TYPE_DIMM>& 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<uint8_t> 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<SDRAM_CAPACITY_START, SDRAM_CAPACITY_LEN>(l_sdram_capacity); + // Extracting desired bits + l_spd_buffer.extractToRight<SDRAM_BANKS_START, SDRAM_BANKS_LEN>(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<SDRAM_BANKS_START, SDRAM_BANKS_LEN>(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<BANK_GROUP_START, BANK_GROUP_LEN>(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(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 addressing -/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& 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 5 +/// @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::sdram_addressing(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::bank_groups(const fapi2::Target<TARGET_TYPE_DIMM>& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value) { - // 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<TARGET_TYPE_MCS>(i_target_dimm); - const auto l_target_port = find_target<TARGET_TYPE_MCA>(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_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<uint8_t> 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<COL_ADDRESS_START, COL_ADDRESS_LEN>(l_column_addr); + // Extracting desired bits + l_spd_buffer.extractToRight<BANK_GROUP_START, BANK_GROUP_LEN>(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<ROW_ADDRESS_START, ROW_ADDRESS_LEN>(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<ADDRESS_RESERVED_START, ADDRESS_RESERVED_LEN>(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_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; } - /// -/// @brief Decode SDRAM Package Type -/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& 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 6 +/// @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::primary_package_type(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::column_address_bits(const fapi2::Target<TARGET_TYPE_DIMM>& 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; + 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<uint8_t> l_spd_buffer(i_spd_data[BYTE_INDEX]); - // Targets - const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm); - const auto l_target_port = find_target<TARGET_TYPE_MCA>(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<COL_ADDRESS_START, COL_ADDRESS_LEN>(l_field_bits); - // 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; + // 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") ); - // 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}; + FAPI_DBG("%s. Number of Column Address Bits: %d", + mss::c_str(i_target), + o_value); + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @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 5 (bits 5~3) +/// @note Item JC-45-2220.01x +/// @note Page 18 +/// @note DDR4 SPD Document Release 3 +/// +fapi2::ReturnCode decoder::row_address_bits(const fapi2::Target<TARGET_TYPE_DIMM>& 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<uint8_t> 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<ROW_ADDRESS_START, ROW_ADDRESS_LEN>(l_field_bits); - // Decoding bits 1~0 (Signal loading) - l_spd_buffer.extractToRight<PRIM_PRIM_SIGNAL_LOAD_START, PRIM_PRIM_SIGNAL_LOAD_LEN>(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<PACKAGE_RESERVE_START, PACKAGE_RESERVE_LEN>(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<PRIM_DIE_COUNT_START, PRIM_DIE_COUNT_LEN>(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<PRIM_PACKAGE_TYPE_START, PRIM_PACKAGE_TYPE_LEN>(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(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; } -//TODO -// Need to complete this function, map need tREF1 calculations /// -/// @brief Decode SDRAM Optional Features -/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& 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 7 +/// @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::sdram_optional_features(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::prim_sdram_signal_loading(const fapi2::Target<TARGET_TYPE_DIMM>& 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; + 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<uint8_t> 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<PRIM_SIGNAL_LOAD_START, PRIM_SIGNAL_LOAD_LEN>(l_field_bits); - // TMAW mappint limits - const size_t TMAW_MAX_VALID_KEY = 2; + 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") ); - // Targets - const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm); - const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm); + FAPI_DBG("%s. Primary SDRAM Signal Loading: %d", + mss::c_str(i_target), + o_value); - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); +fapi_try_exit: + return fapi2::current_err; +} - // 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; +/// +/// @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<TARGET_TYPE_DIMM>& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value) +{ - // 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<uint8_t> l_spd_buffer(i_spd_data[BYTE_INDEX]); + fapi2::buffer<uint8_t> 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); - // Decoding bits 3~0 (MAC) - l_spd_buffer.extractToRight<MAC_START, MAC_LEN>(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<TMAW_START, TMAW_LEN>(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<OPT_FEAT_RESERVED_START, OPT_FEAT_RESERVED_LEN>(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<PRIM_DIE_COUNT_START, PRIM_DIE_COUNT_LEN>(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]); + 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") ); + + FAPI_DBG("%s. Number of Row 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<TARGET_TYPE_DIMM>& 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 8, currently reserved +/// @note SPD Byte 6 (bit 7) +/// @note Item JC-45-2220.01x +/// @note Page 19 +/// @note DDR4 SPD Document Release 3 /// -fapi2::ReturnCode decoder::thermal_and_refresh_options(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::prim_sdram_package_type(const fapi2::Target<TARGET_TYPE_DIMM>& 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<uint8_t> l_spd_buffer(l_raw_byte); - // 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<PRIM_PACKAGE_TYPE_START, PRIM_PACKAGE_TYPE_LEN>(l_field_bits); + + 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") ); + + 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<TARGET_TYPE_DIMM>& 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 9 +/// @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::other_optional_features(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::maximum_activate_count(const fapi2::Target<TARGET_TYPE_DIMM>& i_target, + const uint8_t* i_spd_data, + uint32_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 = 7; + 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 + // Buffer used for bit manipulation + fapi2::buffer<uint8_t> l_spd_buffer(l_raw_byte); - // Targets - const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm); - const auto l_target_port = find_target<TARGET_TYPE_MCA>(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<MAC_START, MAC_LEN>(l_field_bits); - // 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 + 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)") ); - // 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}; + FAPI_DBG("%s. Maximum Active Count (MAC): %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, - i_spd_data[BYTE_INDEX]); +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<TARGET_TYPE_DIMM>& i_target, + const uint8_t* i_spd_data, + uint32_t& o_value) +{ + + constexpr size_t BYTE_INDEX = 7; + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 0; // Buffer used for bit manipulation - fapi2::buffer<uint8_t> l_spd_buffer(i_spd_data[BYTE_INDEX]); + fapi2::buffer<uint8_t> l_spd_buffer(l_raw_byte); - // Decoding bits 4~0 - l_spd_buffer.extractToRight<PPR_RESERVED_START, PPR_RESERVED_LEN>(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); + + // Extracting desired bits + l_spd_buffer.extractToRight<TMAW_START, TMAW_LEN>(l_field_bits); - mss::check::spd::valid_value_warn(i_target_dimm, - (l_reserved == RESERVED), - BYTE_INDEX, - l_reserved, - "Failed check for reserved bits"); + 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)") ); - // Decoding bit 5 - l_spd_buffer.extractToRight<SOFT_PPR_START, SOFT_PPR_LEN>(l_soft_ppr); + FAPI_DBG("%s. Maximum Active Window multiplier: %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_soft_ppr < SOFT_PPR_MAX_VALID_KEY), - BYTE_INDEX, - l_soft_ppr, - "Failed check for SOFT PPR") ); +/// +/// @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 9 (bit 5) +/// @note Item JC-45-2220.01x +/// @note Page 21 +/// @note DDR4 SPD Document Release 3 +/// +fapi2::ReturnCode decoder::soft_post_package_repair(const fapi2::Target<TARGET_TYPE_DIMM>& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value) +{ - // Decoding bits 7~6 - l_spd_buffer.extractToRight<PPR_START, PPR_LEN>(l_ppr); + constexpr size_t BYTE_INDEX = 9; + 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<uint8_t> 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<SOFT_PPR_START, SOFT_PPR_LEN>(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(SOFT_PPR_MAP, l_field_bits, o_value), + BYTE_INDEX, + l_field_bits, + "Failed check for Soft PPR") ); - // 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. Soft Post Package Repair (Soft PPR): %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<TARGET_TYPE_DIMM>& i_target_dimm, -/// uint8_t* i_spd_data +/// @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 10 +/// @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::secondary_package_type(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::post_package_repair(const fapi2::Target<TARGET_TYPE_DIMM>& 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 = 9; + 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<uint8_t> 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<PPR_START, PPR_LEN>(l_field_bits); - // Buffer used for bit manipulation - fapi2::buffer<uint8_t> l_spd_buffer(i_spd_data[BYTE_INDEX]); + 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 1~0 (Signal loading) - l_spd_buffer.extractToRight<SEC_SIGNAL_LOAD_START, SEC_SIGNAL_LOAD_LEN>(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<DENSITY_RATIO_START, DENSITY_RATIO_LEN>(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<SEC_DIE_COUNT_START, SEC_DIE_COUNT_LEN>(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<SEC_PACKAGE_TYPE_START, SEC_PACKAGE_TYPE_LEN>(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. Post Package Repair (PPR): %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<TARGET_TYPE_DIMM>& 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 11 +/// @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_nominal_voltage(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::sec_sdram_signal_loading(const fapi2::Target<TARGET_TYPE_DIMM>& i_target, + const uint8_t* i_spd_data, + uint8_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<TARGET_TYPE_MCS>(i_target_dimm); - const auto l_target_port = find_target<TARGET_TYPE_MCA>(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_operable = 0; - uint8_t l_endurant = 0; - uint8_t l_reserved = 0; + constexpr size_t BYTE_INDEX = 10; + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 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<uint8_t> 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<uint8_t> l_spd_buffer(i_spd_data[BYTE_INDEX]); + // Extracting desired bits + l_spd_buffer.extractToRight<SEC_SIGNAL_LOAD_START, SEC_SIGNAL_LOAD_LEN>(l_field_bits); - // Decoding bits 0 (Operable) - l_spd_buffer.extractToRight<OPERABLE_START, OPERABLE_LEN>(l_operable); + 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") ); - // 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<ENDURANT_START, ENDURANT_LEN>(l_endurant); + FAPI_DBG("%s. Number of Row Address Bits: %d", + mss::c_str(i_target), + o_value); - // 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_try_exit: + return fapi2::current_err; +} - // Decoding bits 7~2 (Reserved) - l_spd_buffer.extractToRight<NOM_VOLT_START, NOM_VOLT_LEN>(l_reserved); +/// +/// @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<TARGET_TYPE_DIMM>& i_target, + const uint8_t* i_spd_data, + uint8_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 = 10; + constexpr size_t UNDEFINED = 3; // JEDEC map doesn't go beyond 3 - // Retrive entire MCS level attribute - FAPI_TRY(spd_module_nominal_voltage(l_target_mcs, &l_operable_attrs[0][0])); + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 0; - // Update attribute to decoded byte values - l_operable_attrs[PORT_NUM][DIMM_NUM] = l_operable; + // Buffer used for bit manipulation + fapi2::buffer<uint8_t> l_spd_buffer(l_raw_byte); - // Update MCS level attribute - FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_SPD_MODULE_NOMINAL_VOLTAGE, l_target_mcs, l_operable_attrs) ); + // 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); - // Printed decoded info - FAPI_INF( "%s Operable: %d, Endurant: %d, Reserved: %d", - c_str(i_target_dimm), - l_operable, - l_endurant, - l_reserved ); + // Extracting desired bits + l_spd_buffer.extractToRight<DENSITY_RATIO_START, DENSITY_RATIO_LEN>(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 Decode Module Organization -/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm, -/// uint8_t* i_spd_data +/// @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 12 +/// @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::module_organization(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::sec_sdram_die_count(const fapi2::Target<TARGET_TYPE_DIMM>& 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 = 5; + 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<uint8_t> 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<TARGET_TYPE_MCS>(i_target_dimm); - const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm); + // Extracting desired bits + l_spd_buffer.extractToRight<SEC_DIE_COUNT_START, SEC_DIE_COUNT_LEN>(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(SEC_DIE_COUNT_MAP, l_field_bits, o_value), + BYTE_INDEX, + l_field_bits, + "Failed check for Secondary Die Count") ); - // 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. Secondary Die Count: %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 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<TARGET_TYPE_DIMM>& 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 = 5; + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 0; // Buffer used for bit manipulation - fapi2::buffer<uint8_t> l_spd_buffer(i_spd_data[BYTE_INDEX]); + fapi2::buffer<uint8_t> l_spd_buffer(l_raw_byte); - // Decoding Bits 2~0 - l_spd_buffer.extractToRight<SDRAM_WIDTH_START, SDRAM_WIDTH_LEN>(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<PACKAGE_RANKS_START, PACKAGE_RANKS_LEN>(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<RANK_MIX_START, RANK_MIX_LEN>(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<MODULE_ORG_RESERVED_START, MODULE_ORG_RESERVED_LEN>(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] ); + // 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<SEC_PACKAGE_TYPE_START, SEC_PACKAGE_TYPE_LEN>(l_field_bits); + + 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; } -//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<TARGET_TYPE_DIMM>& 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 13 +/// @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_memory_bus_width(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::operable_nominal_voltage(const fapi2::Target<TARGET_TYPE_DIMM>& 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 = 11; + 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<uint8_t> l_spd_buffer(l_raw_byte); - // Targets - const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm); - const auto l_target_port = find_target<TARGET_TYPE_MCA>(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<OPERABLE_START, OPERABLE_LEN>(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(OPERABLE_MAP, l_field_bits, o_value), + BYTE_INDEX, + l_field_bits, + "Failed check for Endur") ); - // Attribute variables used to set decoded vals - uint8_t l_module_bus_widths[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + 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), - BYTE_INDEX, - i_spd_data[BYTE_INDEX]); +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<TARGET_TYPE_DIMM>& 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<uint8_t> l_spd_buffer(i_spd_data[BYTE_INDEX]); + fapi2::buffer<uint8_t> l_spd_buffer(l_raw_byte); - // Decoding Bits 2~0 - l_spd_buffer.extractToRight<BUS_WIDTH_START, BUS_WIDTH_LEN>(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<BUS_EXT_WIDTH_START, BUS_EXT_WIDTH_LEN>(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<BUS_WIDTH_RESERVED_START, BUS_WIDTH_RESERVED_LEN>(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] ); + // 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<ENDURANT_START, ENDURANT_LEN>(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 Decode Module Thermal Sensor -/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm, -/// uint8_t* i_spd_data +/// @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 14, no attribute found for this +/// @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::module_thermal_sensor(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::device_width(const fapi2::Target<TARGET_TYPE_DIMM>& 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 = 12; + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 0; - // Attribute variables used to set decoded vals - uint8_t l_therm_sensors[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + // Buffer used for bit manipulation + fapi2::buffer<uint8_t> l_spd_buffer(l_raw_byte); - // Targets - const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm); - const auto l_target_port = find_target<TARGET_TYPE_MCA>(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<SDRAM_WIDTH_START, SDRAM_WIDTH_LEN>(l_field_bits); - // 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, + mss::find_value_from_key(DEVICE_WIDTH_MAP, l_field_bits, o_value), + BYTE_INDEX, + l_field_bits, + "Failed check for Device Width") ); - // Buffer used for bit manipulation - fapi2::buffer<uint8_t> l_spd_buffer(i_spd_data[BYTE_INDEX]); + FAPI_DBG("%s. Device Width: %d", + mss::c_str(i_target), + o_value); - // Decoding Bits 6~0 - l_spd_buffer.extractToRight<THERM_SENSOR_RESERV_START, THERM_SENSOR_RESERV_LEN>(l_reserved); +fapi_try_exit: + return fapi2::current_err; +} - 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<THERM_SENSOR_START, THERM_SENSOR_LEN>(l_thermal_sensor); - // 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") ); +/// +/// @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<TARGET_TYPE_DIMM>& i_target, + const uint8_t* i_spd_data, + uint8_t& o_value) +{ - // Retrive entire MCS level attribute - FAPI_TRY( spd_module_thermal_sensor(l_target_mcs, &l_therm_sensors[0][0]) ); + constexpr size_t BYTE_INDEX = 12; + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 0; - // Update attribute to decoded byte values - l_therm_sensors[PORT_NUM][DIMM_NUM] = l_thermal_sensor; + // Buffer used for bit manipulation + fapi2::buffer<uint8_t> l_spd_buffer(l_raw_byte); - // Update MCS level attribute - FAPI_ATTR_SET(fapi2::ATTR_SPD_MODULE_THERMAL_SENSOR, l_target_mcs, l_therm_sensors); + // 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<PACKAGE_RANKS_START, PACKAGE_RANKS_LEN>(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") ); - // Printed decoded info - FAPI_INF("%s. Thermal sensor: %d, Reserved: %d", - c_str(i_target_dimm), - l_thermal_sensor, - l_reserved ); + 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::rank_mix(const fapi2::Target<TARGET_TYPE_DIMM>& 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<uint8_t> 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); - // Buffer used for bit manipulation - fapi2::buffer<uint8_t> l_spd_buffer(i_spd_data[BYTE_INDEX]); + // Extracting desired bits + l_spd_buffer.extractToRight<RANK_MIX_START, RANK_MIX_LEN>(l_field_bits); - // Decoding Bits 3~0 - l_spd_buffer.extractToRight<EXT_MOD_TYPE_START, EXT_MOD_TYPE_LEN>(l_ext_module_type); + 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") ); - // 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, - BYTE_INDEX, - l_ext_module_type, - "Failed check for extended base module type") ); - // Decoding Bit 7~4 - l_spd_buffer.extractToRight<EXT_MOD_TYPE_RESERV_START, EXT_MOD_TYPE_RESERV_LEN>(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 ); + 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 Decode Timebases -/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm, -/// uint8_t* i_spd_data +/// @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 17 +/// @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::timebases(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::prim_bus_width(const fapi2::Target<TARGET_TYPE_DIMM>& 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; + constexpr size_t BYTE_INDEX = 13; + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 0; - // Medium timebase mapping limits - const int64_t MAX_VALID_MTB_KEY = 1; // All others reserved + // Buffer used for bit manipulation + fapi2::buffer<uint8_t> 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<TARGET_TYPE_MCS>(i_target_dimm); - const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm); + // Extracting desired bits + l_spd_buffer.extractToRight<BUS_WIDTH_START, BUS_WIDTH_LEN>(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(BUS_WIDTH_MAP, l_field_bits, o_value), + BYTE_INDEX, + l_field_bits, + "Failed check for Primary Bus Width") ); - // 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. Primary Bus Width: %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), - BYTE_INDEX, - i_spd_data[BYTE_INDEX]); +/// +/// @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<TARGET_TYPE_DIMM>& 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<uint8_t> l_spd_buffer(i_spd_data[BYTE_INDEX]); - - // TODO - update ENUMS to take account to int64_t - // Decoding Bits 1~0 - l_spd_buffer.extractToRight<FINE_TIMEBASE_START, FINE_TIMEBASE_LEN>(l_fine_timebase); + fapi2::buffer<uint8_t> l_spd_buffer(l_raw_byte); - FAPI_TRY(mss::check::spd::valid_value_fail(i_target_dimm, - l_fine_timebase < MAX_VALID_FTB_KEY, + // 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<MED_TIMEBASE_START, MED_TIMEBASE_LEN>(l_medium_timebase); + l_raw_byte); - FAPI_TRY(mss::check::spd::valid_value_fail(i_target_dimm, - l_medium_timebase < MAX_VALID_MTB_KEY, - BYTE_INDEX, - l_medium_timebase, - "Failed check for medium timebase") ); - // Decoding bits Bits 7~4 - l_spd_buffer.extractToRight<TIMEBASE_RESERV_START, TIMEBASE_RESERV_LEN>(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] ); + // Extracting desired bits + l_spd_buffer.extractToRight<BUS_EXT_WIDTH_START, BUS_EXT_WIDTH_LEN>(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 SDRAM Minimum Cycle Time -/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& 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 18 & Byte 125 -/// This byte depends on the fine & medium timebase values -/// obtained from 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::min_cycle_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::thermal_sensor(const fapi2::Target<TARGET_TYPE_DIMM>& i_target, + const uint8_t* i_spd_data, + uint8_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) - const int64_t MIN_CYCLE_TIME_MTB = 1; // from JEDEC - const int64_t MAX_CYCLE_TIME_MTB = 255; // from JEDEC + 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; - const int64_t MIN_CYCLE_TIME_FTB = -128; // from JEDEC - const int64_t MAX_CYCLE_TIME_FTB = 127; // from JEDEC + // Buffer used for bit manipulation + fapi2::buffer<uint8_t> l_spd_buffer(l_raw_byte); - // Targets - const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm); - const auto l_target_port = find_target<TARGET_TYPE_MCA>(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<THERM_SENSOR_START, THERM_SENSOR_LEN>(l_field_bits); - // Byte variables used for decoding - int64_t l_tCKmin_mtb = 0; - int64_t l_tCKmin_ftb = 0; + 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; - // 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}; + FAPI_DBG("%s. Thermal Sensor: %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_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_try_exit: + return fapi2::current_err; +} - // 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] ); +/// +/// @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<TARGET_TYPE_DIMM>& 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<uint8_t> 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<EXT_MOD_TYPE_START, EXT_MOD_TYPE_LEN>(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 SDRAM Maximum Cycle Time -/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm, -/// uint8_t* i_spd_data +/// @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 19 and 124 +/// @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::max_cycle_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::fine_timebase(const fapi2::Target<TARGET_TYPE_DIMM>& 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) - const int64_t MIN_CYCLE_TIME_MTB = 1; // from JEDEC - const int64_t MAX_CYCLE_TIME_MTB = 255; // from JEDEC + constexpr size_t BYTE_INDEX = 17; + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 0; - const int64_t MIN_CYCLE_TIME_FTB = -128; // from JEDEC - const int64_t MAX_CYCLE_TIME_FTB = 127; // from JEDEC + // Buffer used for bit manipulation + fapi2::buffer<uint8_t> l_spd_buffer(l_raw_byte); - // Targets - const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm); - const auto l_target_port = find_target<TARGET_TYPE_MCA>(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<FINE_TIMEBASE_START, FINE_TIMEBASE_LEN>(l_field_bits); - // Byte variables used for decoding - int64_t l_tCKmax_mtb = 0; - int64_t l_tCKmax_ftb = 0; + 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") ); - // 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. Fine Timebase: %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 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<TARGET_TYPE_DIMM>& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) +{ - 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 size_t BYTE_INDEX = 17; + uint8_t l_raw_byte = i_spd_data[BYTE_INDEX]; + uint8_t l_field_bits = 0; - // 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]) ); + // Buffer used for bit manipulation + fapi2::buffer<uint8_t> l_spd_buffer(l_raw_byte); - // 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_raw_byte); - // 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]); + // Extracting desired bits + l_spd_buffer.extractToRight<MED_TIMEBASE_START, MED_TIMEBASE_LEN>(l_field_bits); - // Update MCS level attribute - FAPI_ATTR_SET( fapi2::ATTR_TIMING_TCKMAX, l_target_mcs, l_max_cycle_times ); + 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") ); - // 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. Medium Timebase: %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<TARGET_TYPE_DIMM>& i_target_dimm, -/// uint8_t* i_spd_data +/// @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 24 & 123 +/// @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_cas_latency_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::min_cycle_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& 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) + constexpr size_t BYTE_INDEX = 18; - 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<TARGET_TYPE_MCS>(i_target_dimm); - const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm); + // 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); - // 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 min cycle time (tckmin) in MTB") ); - // Byte variables used for decoding - int64_t l_tAAmin_mtb = 0; - int64_t l_tAAmin_ftb = 0; + FAPI_DBG("%s. Minimum Cycle Time (tCKmin) in MTB units: %d", + mss::c_str(i_target), + o_value); - // 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}; +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), - 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] ); +/// +/// @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. +/// +fapi2::ReturnCode decoder::max_cycle_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) +{ + constexpr size_t BYTE_INDEX = 19; + + 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_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; } -#if 0 /// /// @brief Decode CAS Latencies Supported -/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm, -/// uint8_t* i_spd_data +/// @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 Byte 20-23 +/// @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<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::supported_cas_latencies(const fapi2::Target<TARGET_TYPE_DIMM>& i_target, + const uint8_t* i_spd_data, + uint64_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; + constexpr size_t FIRST_BYTE = 20; + constexpr size_t SEC_BYTE = 21; + constexpr size_t THIRD_BYTE = 22; + constexpr size_t FOURTH_BYTE = 23; - // Targets - const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm); - const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm); + constexpr size_t OUTPUT_START = 0; + constexpr size_t OUTPUT_LEN = 64; - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); + // Buffers used for bit manipulation + fapi2::buffer<uint64_t> l_buffer; - // Byte variables used for decoding - uint64_t l_supported_cas_lat = 0; + // Trace print in the front assists w/ debug + 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<CAS_BYTE_1_START, CAS_BYTE_1_LEN>(i_spd_data[FIRST_BYTE]). + insertFromRight<CAS_BYTE_2_START, CAS_BYTE_2_LEN>(i_spd_data[SEC_BYTE]). + insertFromRight<CAS_BYTE_3_START, CAS_BYTE_3_LEN>(i_spd_data[THIRD_BYTE]). + insertFromRight<CAS_BYTE_4_START, CAS_BYTE_4_LEN>(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<BIT_START, BIT_LEN>()), + FOURTH_BYTE, + i_spd_data[FOURTH_BYTE], + "Failed check on CAS latencies supported") ); + + // Update output value only if range check passes + l_buffer.extractToRight<OUTPUT_START, OUTPUT_LEN>(o_value); + + FAPI_DBG("%s. CAS latencies supported (bitmap): 0x%llX", + mss::c_str(i_target), + o_value); - // Attribute variables used to set decoded vals - uint64_t l_supported_CLs[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; +fapi_try_exit: + return fapi2::current_err; - // Buffers used for bit manipulation - fapi2::buffer<uint8_t> l_first_byte_buff(i_spd_data[FIRST_BYTE]); - fapi2::buffer<uint8_t> l_second_byte_buff(i_spd_data[SEC_BYTE]); - fapi2::buffer<uint8_t> l_third_byte_buff(i_spd_data[THIRD_BYTE]); - fapi2::buffer<uint8_t> l_forth_byte_buff(i_spd_data[FORTH_BYTE]); +} - // 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]); +/// +/// @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<fapi2::TARGET_TYPE_DIMM>& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) +{ + constexpr size_t BYTE_INDEX = 24; - // TODO - update ENUMS to take account to int64_t + constexpr int64_t TIMING_LOWER_BOUND = 1; // from JEDEC + constexpr int64_t TIMING_UPPER_BOUND = 255; // from JEDEC - // Combine Bytes 20 - 23 to create bitmap - l_first_byte_buff.extractToRight<CAS_BYTE_1_START, CAS_BYTE_1_LEN>(l_supported_cas_lat). - l_second_byte_buff.extractToRight<CAS_BYTE_2_START, CAS_BYTE_2_LEN>(l_supported_cas_lat). - l_third_byte_buff.extractToRight<CAS_BYTE_3_START, CAS_BYTE_3_LEN>(l_supported_cas_lat). - l_forth_byte_buff.extractToRight<CAS_BYTE_4_START, CAS_BYTE_4_LEN>(l_supported_cas_lat); + // Explicit conversion + int64_t l_timing_val = int64_t(i_spd_data[BYTE_INDEX]); - // Retrive entire MCS level attribute - FAPI_TRY( cas_latencies_supported(l_target_mcs, &l_supported_CLs[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_supported_CLs[PORT_NUM][DIMM_NUM] = l_supported_cas_lat; + 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") ); - // 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; -} + // 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 Minimum RAS to CAS Delay Time -/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& 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 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::min_ras_to_cas_delay_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::min_ras_to_cas_delay_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX = 25; - - // Targets - const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm); - const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm); + constexpr size_t BYTE_INDEX = 25; - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); + constexpr int64_t TIMING_LOWER_BOUND = 1; // from JEDEC + constexpr int64_t TIMING_UPPER_BOUND = 255; // from JEDEC - // Attribute variable (rcd = ras to cas delay) - int64_t l_min_rcd_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + // Explicit conversion + 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); + + 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") ); - // Retrive entire MCS level attribute - FAPI_TRY( eff_dram_trcd(l_target_mcs, &l_min_rcd_times[0][0]) ); + // Only update output if it passes check + 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 RAS to CAS Delay Time (tRCDmin) 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<TARGET_TYPE_DIMM>& i_target_dimm, -/// uint8_t* i_spd_data +/// @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<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::min_row_precharge_delay_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX = 26; - - // Targets - const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm); - const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm); + constexpr size_t BYTE_INDEX = 26; - // Current index - const auto PORT_NUM = index(l_target_port); - const auto DIMM_NUM = index(i_target_dimm); + constexpr int64_t TIMING_LOWER_BOUND = 1; // from JEDEC + constexpr int64_t TIMING_UPPER_BOUND = 255; // from JEDEC - // Attribute variable (rp = row to precharge) - int64_t l_min_rp_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + // Explicit conversion + 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_trp(l_target_mcs, &l_min_rp_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), + BYTE_INDEX, + l_timing_val, + "Failed check on the Minimum Row Precharge Delay Time (tRPmin) in MTB") ); - // Update attribute to decoded byte values - l_min_rp_times[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) ); + // Only update output if it passes check + o_value = l_timing_val; - // 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; + 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 Active to Precharge Delay Time (tRASmin) -/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& 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 Byte 27 Bits 3~0 along with Byte 28 Bits 7~0 +/// @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_activate_to_precharge_delay_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::min_active_to_precharge_delay_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX_MSB = 27; // MSN = most significant byte - const size_t BYTE_INDEX_LSB = 28; // LSB = least significant byte + // Lambda expression to retrieve tRASmin's most significant nibble (MSN) + auto tRASmin_MSN = [](const fapi2::Target<TARGET_TYPE_DIMM>& i_target, const uint8_t* i_data) + { + constexpr size_t BYTE_INDEX = 27; + uint8_t l_out = 0; - // Targets - const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm); - const auto l_target_port = find_target<TARGET_TYPE_MCA>(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<uint8_t> l_buffer(i_data[BYTE_INDEX]); - // Byte variables used for decoding (tRAS = Active to Precharge Delay Time) - int64_t l_tRASmin = 0; + // Extracting desired bits + l_buffer.extractToRight<TRASMIN_MSN_START, TRASMIN_MSN_LEN>(l_out); - // Attribute variable - int64_t l_min_ras_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + return l_out; + }; - // Buffers used for bit manipulation - fapi2::buffer<uint8_t> l_buffer_upper_nibble(i_spd_data[BYTE_INDEX_MSB]); - fapi2::buffer<uint8_t> l_buffer_lower_byte(i_spd_data[BYTE_INDEX_LSB]); + // Lambda expression to retrieve tRASmin's least significant byte (LSB) + auto tRASmin_LSB = [](const fapi2::Target<TARGET_TYPE_DIMM>& i_target, const uint8_t* i_data) + { + constexpr size_t BYTE_INDEX = 28; + uint8_t l_out = 0; - // 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]); + // 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<uint8_t> l_buffer(i_data[BYTE_INDEX]); + + // Extracting desired bits + l_buffer.extractToRight<TRASMIN_LSB_START, TRASMIN_LSB_LEN>(l_out); + + return l_out; + }; + + + int64_t l_timing_val = 0; + fapi2::buffer<int64_t> 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<MSN_START, MSN_LEN>( tRASmin_MSN(i_target, i_spd_data) ). + insertFromRight<LSB_START, LSB_LEN>( tRASmin_LSB(i_target, i_spd_data) ); - // TODO - update ENUMS to take account to int64_t + // Extract timing value from the buffer into an integral type + constexpr size_t OUTPUT_START = 0; + constexpr size_t OUTPUT_LEN = 64; - // Combining bits to create timing value - l_buffer_upper_nibble.extractToRight<TRASMIN_MSN_START, TRASMIN_MSN_LEN>(l_tRASmin); - l_buffer_lower_byte.extractToRight<TRASMIN_LSB_START, TRASMIN_LSB_LEN>(l_tRASmin); + l_buffer.extractToRight<OUTPUT_START, OUTPUT_LEN>(l_timing_val); - // Retrive entire MCS level attribute - FAPI_TRY( eff_dram_tras(l_target_mcs, &l_min_ras_times[0][0]) ); + // 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 - // Update attribute to decoded byte values (returning picoseconds) - l_min_ras_times[PORT_NUM][DIMM_NUM] = ns_to_ps(l_tRASmin); + // 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; - // 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(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 Minimum Active to Active/Refresh Delay Time (tRCmin) -/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm, -/// uint8_t* i_spd_data +/// @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 Byte 27 Bits 7~4 along with Byte 29 Bits 7~0 +/// @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_activate_to_activate_refresh_delay_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::min_active_to_active_refresh_delay_time(const fapi2::Target<TARGET_TYPE_DIMM>& 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 + // Lambda expression to retrieve tRCmin's most significant nibble (MSN) + auto tRCmin_MSN = [](const fapi2::Target<TARGET_TYPE_DIMM>& i_target, const uint8_t* i_data) + { + constexpr size_t BYTE_INDEX = 27; + uint8_t l_out = 0; - // Targets - const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm); - const auto l_target_port = find_target<TARGET_TYPE_MCA>(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<uint8_t> l_buffer(i_data[BYTE_INDEX]); - // Byte variables used for decoding (RC = Activate to Activate/Refresh Delay) - uint16_t l_tRCmin = 0; + // Extracting desired bits + l_buffer.extractToRight<TRCMIN_MSN_START, TRCMIN_MSN_LEN>(l_out); - // Attribute variable - uint16_t l_min_rc_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 tRCmin's least significant byte (LSB) + auto tRCmin_LSB = [](const fapi2::Target<TARGET_TYPE_DIMM>& i_target, const uint8_t* i_data) + { + constexpr size_t BYTE_INDEX = 29; + uint8_t l_out = 0; - // Buffers used for bit manipulation - fapi2::buffer<uint8_t> l_buffer_upper_nibble(i_spd_data[BYTE_INDEX_MSN]); - fapi2::buffer<uint8_t> 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<uint8_t> l_buffer(i_data[BYTE_INDEX]); - // Combining bits to create timing value - l_buffer_upper_nibble.extractToRight<TRCMIN_MSN_START, TRCMIN_MSN_LEN>(l_tRCmin); - l_buffer_lower_byte.extractToRight<TRCMIN_LSB_START, TRCMIN_LSB_LEN>(l_tRCmin); + // Extracting desired bits + l_buffer.extractToRight<TRCMIN_LSB_START, TRCMIN_LSB_LEN>(l_out); - // Retrive entire MCS level attribute - FAPI_TRY( eff_dram_trc(l_target_mcs, &l_min_rc_times[0][0]) ); + return l_out; + }; - // Update attribute to decoded byte values (returning picoseconds, currently nanoseconds) - l_min_rc_times[PORT_NUM][DIMM_NUM] = ns_to_ps(l_tRCmin); + int64_t l_timing_val = 0; + fapi2::buffer<int64_t> l_buffer; - // 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; + // 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<MSN_START, MSN_LEN>( tRCmin_MSN(i_target, i_spd_data) ). + insertFromRight<LSB_START, LSB_LEN>( tRCmin_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<OUTPUT_START, OUTPUT_LEN>(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 29 of the JEDEC spec explains how to piece this together - AAM + constexpr size_t ERROR_BYTE_INDEX = 29; + + 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") ); + + // Update output only after check passes + o_value = l_timing_val; + + 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; } + /// -/// @brief Minimum Refresh Recovery Delay Time 1 (tRFC1min) -/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& 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 Byte 30 (LSB) along with Byte 31 (MSB) +/// @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::min_refresh_recovery_delay_time_1(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::min_refresh_recovery_delay_time_1(const fapi2::Target<TARGET_TYPE_DIMM>& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX_MSB = 31; // MSN = most significant nibble - const size_t BYTE_INDEX_LSB = 30; // LSB = least significant byte + // Lambda expression to retrieve tRFC1min's most significant byte (MSB) + auto tRFC1min_MSB = [](const fapi2::Target<TARGET_TYPE_DIMM>& i_target, const uint8_t* i_data) + { + constexpr size_t BYTE_INDEX = 31; + uint8_t l_out = 0; - // Targets - const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm); - const auto l_target_port = find_target<TARGET_TYPE_MCA>(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<uint8_t> l_buffer(i_data[BYTE_INDEX]); - // Byte variables used for decoding (RFC1 = Minimum Refresh Recovery Delay Time) - uint32_t l_tRFC1min = 0; + // Extracting desired bits + l_buffer.extractToRight<TRFC1MIN_MSB_START, TRFC1MIN_MSB_LEN>(l_out); - // Attribute variable - uint32_t l_min_rfc1_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + return l_out; + }; - // Buffers used for bit manipulation - fapi2::buffer<uint8_t> l_buffer_MSB(i_spd_data[BYTE_INDEX_MSB]); - fapi2::buffer<uint8_t> l_buffer_LSB(i_spd_data[BYTE_INDEX_LSB]); + // Lambda expression to retrieve tRFC1min's least significant byte (LSB) + auto tRFC1min_LSB = [](const fapi2::Target<TARGET_TYPE_DIMM>& i_target, const uint8_t* i_data) + { + constexpr size_t BYTE_INDEX = 30; + uint8_t l_out = 0; - // 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]); + // 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<uint8_t> l_buffer(i_data[BYTE_INDEX]); + + // Extracting desired bits + l_buffer.extractToRight<TRFC1MIN_LSB_START, TRFC1MIN_LSB_LEN>(l_out); + + return l_out; + }; + + int64_t l_timing_val = 0; + fapi2::buffer<int64_t> 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<MSB_START, MSB_LEN>( tRFC1min_MSB(i_target, i_spd_data) ). + insertFromRight<LSB_START, LSB_LEN>( tRFC1min_LSB(i_target, i_spd_data) ); - // Combining bits to create timing value - l_buffer_MSB.extractToRight<, >(); - l_buffer_LSB.extractToRight<, >(); + // Extract timing value from the buffer into an integral type + constexpr size_t OUTPUT_START = 0; + constexpr size_t OUTPUT_LEN = 64; - // Retrive entire MCS level attribute - FAPI_TRY( eff_dram_trc(l_target_mcs, &l_min_rfc1_times[0][0]) ); + l_buffer.extractToRight<OUTPUT_START, OUTPUT_LEN>(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); + // 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 - // 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; + // 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; + + 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") ); + + // Update output only after check passes + o_value = l_timing_val; + + FAPI_DBG("%s. Minimum Refresh Recovery Delay Time 1 (tRFC1min) in MTB units: %d", + mss::c_str(i_target), + o_value); + +fapi_try_exit: + return fapi2::current_err; } /// -/// @brief Minimum Refresh Recovery Delay Time 2 (tRFC2min) -/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& 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 Byte 32 (LSB) along with Byte 33 (MSB) +/// @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_refresh_recovery_delay_time_2(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::min_refresh_recovery_delay_time_2(const fapi2::Target<TARGET_TYPE_DIMM>& 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 + // Lambda expression to retrieve tRFC2min's most significant byte (MSB) + auto tRFC2min_MSB = [](const fapi2::Target<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_MCS>(i_target_dimm); - const auto l_target_port = find_target<TARGET_TYPE_MCA>(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<uint8_t> l_buffer(i_data[BYTE_INDEX]); - // Byte variables used for decoding (RFC1 = Minimum Refresh Recovery Delay 2) - uint32_t l_tRFC2min = 0; + // Extracting desired bits + l_buffer.extractToRight<TRFC2MIN_MSB_START, TRFC2MIN_MSB_LEN>(l_out); - // Attribute variable - uint32_t l_min_rfc2_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + return l_out; + }; - // Buffers used for bit manipulation - fapi2::buffer<uint8_t> l_buffer_MSB(i_spd_data[BYTE_INDEX_MSB]); - fapi2::buffer<uint8_t> l_buffer_LSB(i_spd_data[BYTE_INDEX_LSB]); + // Lambda expression to retrieve tRFC2min's least significant byte (LSB) + auto tRFC2min_LSB = [](const fapi2::Target<TARGET_TYPE_DIMM>& i_target, const uint8_t* i_data) + { + constexpr size_t BYTE_INDEX = 32; + uint8_t l_out = 0; - // 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]); + // 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<uint8_t> l_buffer(i_data[BYTE_INDEX]); + + // Extracting desired bits + l_buffer.extractToRight<TRFC2MIN_LSB_START, TRFC2MIN_LSB_LEN>(l_out); + + return l_out; + }; + + int64_t l_timing_val = 0; + fapi2::buffer<int64_t> 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<MSB_START, MSB_LEN>( tRFC2min_MSB(i_target, i_spd_data) ). + insertFromRight<LSB_START, LSB_LEN>( tRFC2min_LSB(i_target, i_spd_data) ); - // Combining bits to create timing value - l_buffer_MSB.extractToRight<, >(); - l_buffer_LSB.extractToRight<, >(); + // Extract timing value from the buffer into an integral type + constexpr size_t OUTPUT_START = 0; + constexpr size_t OUTPUT_LEN = 64; - // Retrive entire MCS level attribute - FAPI_TRY( eff_dram_trc(l_target_mcs, &l_min_rfc2_times[0][0]) ); + l_buffer.extractToRight<OUTPUT_START, OUTPUT_LEN>(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_tRFC2min); + // 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 - // 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; + // 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; + + 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") ); + + // Update output only after check passes + o_value = l_timing_val; + + FAPI_DBG("%s. Minimum Refresh Recovery Delay Time 2 (tRFC2min) in MTB units: %d", + mss::c_str(i_target), + o_value); + +fapi_try_exit: + return fapi2::current_err; } /// -/// @brief Minimum Refresh Recovery Delay Time 4 (tRFC4min) -/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& 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 34 (LSB) along with Byte 5 (MSB) +/// @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_refresh_recovery_delay_time_4(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::min_refresh_recovery_delay_time_4(const fapi2::Target<TARGET_TYPE_DIMM>& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX_MSB = 35; // MSN = most significant nibble - const size_t BYTE_INDEX_LSB = 34; // LSB = least significant byte + // Lambda expression to retrieve tRFC4min's most significant byte (MSB) + auto tRFC4min_MSB = [](const fapi2::Target<TARGET_TYPE_DIMM>& i_target, const uint8_t* i_data) + { + constexpr size_t BYTE_INDEX = 35; + uint8_t l_out = 0; - // Targets - const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm); - const auto l_target_port = find_target<TARGET_TYPE_MCA>(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<uint8_t> l_buffer(i_data[BYTE_INDEX]); - // Byte variables used for decoding (RFC4 = Minimum Refresh Recovery Delay 4) - uint32_t l_tRFC4min = 0; + // Extracting desired bits + l_buffer.extractToRight<TRFC4MIN_MSB_START, TRFC4MIN_MSB_LEN>(l_out); - // Attribute variable - uint32_t l_min_rfc4_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; + return l_out; + }; - // Buffers used for bit manipulation - fapi2::buffer<uint8_t> l_buffer_MSB(i_spd_data[BYTE_INDEX_MSB]); - fapi2::buffer<uint8_t> l_buffer_LSB(i_spd_data[BYTE_INDEX_LSB]); + // Lambda expression to retrieve tRFC4min's least significant byte (LSB) + auto tRFC4min_LSB = [](const fapi2::Target<TARGET_TYPE_DIMM>& i_target, const uint8_t* i_data) + { + constexpr size_t BYTE_INDEX = 34; + uint8_t l_out = 0; - // 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]); + // 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<uint8_t> l_buffer(i_data[BYTE_INDEX]); + + // Extracting desired bits + l_buffer.extractToRight<TRFC4MIN_LSB_START, TRFC4MIN_LSB_LEN>(l_out); + + return l_out; + }; + + int64_t l_timing_val = 0; + fapi2::buffer<int64_t> 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; - // Combining bits to create timing value - l_buffer_MSB.extractToRight<, >(); - l_buffer_LSB.extractToRight<, >(); + l_buffer.insertFromRight<MSB_START, MSB_LEN>( tRFC4min_MSB(i_target, i_spd_data) ). + insertFromRight<LSB_START, LSB_LEN>( tRFC4min_LSB(i_target, i_spd_data) ); - // Retrive entire MCS level attribute - FAPI_TRY( eff_dram_trc(l_target_mcs, &l_min_rfc4_times[0][0]) ); + // Extract timing value from the buffer into an integral type + constexpr size_t OUTPUT_START = 0; + constexpr size_t OUTPUT_LEN = 64; - // Update attribute to decoded byte values (returning picoseconds, currently nanoseconds) - l_min_rfc1_times[PORT_NUM][DIMM_NUM] = ns_to_ps(l_tRFC4min); + l_buffer.extractToRight<OUTPUT_START, OUTPUT_LEN>(l_timing_val); - // 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; + // 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 + + // 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; + + 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") ); + + // Update output only after check passes + o_value = l_timing_val; + + FAPI_DBG("%s. Minimum Refresh Recovery Delay Time 4 (tRFC4min) in MTB units: %d", + mss::c_str(i_target), + o_value); + +fapi_try_exit: + return fapi2::current_err; } /// -/// @brief Minimum Four Activate Window Delay Time (t FAW min) -/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& 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 Byte 36 Bits 3 ~ 0 along with Byte 37 Bits 7 ~ 0 +/// @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_four_activate_window_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::min_tfaw(const fapi2::Target<TARGET_TYPE_DIMM>& 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 + // Lambda expression to retrieve tFAWmin's most significant nibble (MSN) + auto tFAWmin_MSN = [](const fapi2::Target<TARGET_TYPE_DIMM>& i_target, const uint8_t* i_data) + { + constexpr size_t BYTE_INDEX = 36; + uint8_t l_out = 0; - // Targets - const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm); - const auto l_target_port = find_target<TARGET_TYPE_MCA>(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<uint8_t> l_buffer(i_data[BYTE_INDEX]); - // Byte variables used for decoding (FAW = Four Activate Window Delay) - uint16_t l_tFAW = 0; + // Extracting desired bits + l_buffer.extractToRight<TFAWMIN_MSN_START, TFAWMIN_MSN_LEN>(l_out); - // Attribute variable - uint16_t l_min_faw_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 tFAWmin's least significant byte (LSB) + auto tFAWmin_LSB = [](const fapi2::Target<TARGET_TYPE_DIMM>& i_target, const uint8_t* i_data) + { + constexpr size_t BYTE_INDEX = 37; + uint8_t l_out = 0; - // Buffers used for bit manipulation - fapi2::buffer<uint8_t> l_buffer_upper_nibble(i_spd_data[BYTE_INDEX_MSN]); - fapi2::buffer<uint8_t> 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<uint8_t> l_buffer(i_data[BYTE_INDEX]); - // Combining bits to create timing value - l_buffer_upper_nibble.extractToRight<TRCMIN_MSN_START, TRCMIN_MSN_LEN>(l_tFAW); - l_buffer_lower_byte.extractToRight<TRCMIN_LSB_START, TRCMIN_LSB_LEN>(l_tFAW); + // Extracting desired bits + l_buffer.extractToRight<TFAWMIN_LSB_START, TFAWMIN_LSB_LEN>(l_out); - // Retrive entire MCS level attribute - FAPI_TRY( eff_dram_trc(l_target_mcs, &l_min_faw_times[0][0]) ); + return l_out; + }; - // Update attribute to decoded byte values (returning picoseconds, currently nanoseconds) - l_min_faw_times[PORT_NUM][DIMM_NUM] = ns_to_ps(l_tFAW); + int64_t l_timing_val = 0; + fapi2::buffer<int64_t> l_buffer; - // 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; + // 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<MSN_START, MSN_LEN>( tFAWmin_MSN(i_target, i_spd_data) ). + insertFromRight<LSB_START, LSB_LEN>( tFAWmin_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<OUTPUT_START, OUTPUT_LEN>(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 + + // 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; + + 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") ); + + // Update output only after check passes + o_value = l_timing_val; + + FAPI_DBG("%s. Minimum Four Activate Window Delay Time (tFAWmin) 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_Smin) -/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& 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 38 +/// @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_act_to_act_delay_time_diff_bank_group(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::min_trrd_s(const fapi2::Target<TARGET_TYPE_DIMM>& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX = 38; - - // Targets - const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm); - const auto l_target_port = find_target<TARGET_TYPE_MCA>(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 - // 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 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]); - // 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); + + 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_trrd(l_target_mcs, &l_min_tRRD_S[0][0]) ); + // Update output value only if range check passes + o_value = l_timing_val; - // Update attribute to decoded byte values - l_min_tRRD_S[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) ); + 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 - 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_try_exit: + return fapi2::current_err; } /// -/// @brief Minimum Activate to Activate Delay Time (tRRD_Lmin), samebank group -/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& 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 39 +/// @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_same_bank_group(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::min_trrd_l(const fapi2::Target<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_MCS>(i_target_dimm); - const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm); + constexpr size_t BYTE_INDEX = 39; + 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 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]); - // 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_L, l_target_mcs, l_min_tRRD_S ); + 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); - // 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<TARGET_TYPE_DIMM>& 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 40 +/// @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_cas_to_cas_delay_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::min_tccd_l(const fapi2::Target<TARGET_TYPE_DIMM>& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX = 40; - - // Targets - const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm); - const auto l_target_port = find_target<TARGET_TYPE_MCA>(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 (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}; + // 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_tCCD_L[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_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_DRAM_TCCD_L, l_target_mcs, l_min_tCCD_L ); + 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 Write Recovery Time (tWRmin) -/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& 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 41 Bits 3~0, Byte 42 Bits 7~0 +/// @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_write_recovery_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::min_write_recovery_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX_MSN = 41; // MSN = most significant nibble - const size_t BYTE_INDEX_LSB = 42; // LSB = least significant byte + // Lambda expression to retrieve tWRmin's most nibble byte (MSN) + auto tWRmin_MSN = [](const fapi2::Target<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_MCS>(i_target_dimm); - const auto l_target_port = find_target<TARGET_TYPE_MCA>(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<uint8_t> l_buffer(i_data[BYTE_INDEX]); - // Byte variables used for decoding (FAW = Four Activate Window Delay) - uint16_t l_tWRmin = 0; + // Extracting desired bits + l_buffer.extractToRight<TWRMIN_MSN_START, TWRMIN_MSN_LEN>(l_out); - // Attribute variable - int64_t l_min_wr_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 tWRmin's least significant byte (LSB) + auto tWRmin_LSB = [](const fapi2::Target<TARGET_TYPE_DIMM>& i_target, const uint8_t* i_data) + { + constexpr size_t BYTE_INDEX = 42; + uint8_t l_out = 0; - // Buffers used for bit manipulation - fapi2::buffer<uint8_t> l_buffer_upper_nibble(i_spd_data[BYTE_INDEX_MSN]); - fapi2::buffer<uint8_t> 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<uint8_t> l_buffer(i_data[BYTE_INDEX]); - // Combining bits to create timing value - l_buffer_upper_nibble.insert<, >(l_tWRmin); - l_buffer_lower_byte.insert<, >(l_tWRmin); + // Extracting desired bits + l_buffer.extractToRight<TWRMIN_LSB_START, TWRMIN_LSB_LEN>(l_out); - // Retrive entire MCS level attribute - FAPI_TRY( eff_dram_twr(l_target_mcs, &l_min_wr_times[0][0]) ); + return l_out; + }; - // Update attribute to decoded byte values (returning picoseconds, currently nanoseconds) - l_min_wr_times[PORT_NUM][DIMM_NUM] = ns_to_ps(l_tWRmin); + int64_t l_timing_val = 0; + fapi2::buffer<int64_t> l_buffer; - // 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; + // 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<MSN_START, MSN_LEN>( tWRmin_MSN(i_target, i_spd_data) ). + insertFromRight<LSB_START, LSB_LEN>( tWRmin_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<OUTPUT_START, OUTPUT_LEN>(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 42) to for error printout of this decode + constexpr size_t ERROR_BYTE_INDEX = 42; + + 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 output only after check passes + o_value = l_timing_val; + + 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::min_twtr_s(const fapi2::Target<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_MCS>(i_target_dimm); - const auto l_target_port = find_target<TARGET_TYPE_MCA>(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<uint8_t> 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<TWTRMIN_S_MSN_START, TWTRMIN_S_MSN_LEN>(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<TARGET_TYPE_DIMM>& 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<uint8_t> l_buffer_upper_nibble(i_spd_data[BYTE_INDEX_MSN]); - fapi2::buffer<uint8_t> 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<uint8_t> l_buffer(i_data[BYTE_INDEX]); + + // Extracting desired bits + l_buffer.extractToRight<TWTRMIN_S_LSB_START, TWTRMIN_S_LSB_LEN>(l_out); + + return l_out; + }; + + int64_t l_timing_val = 0; + fapi2::buffer<int64_t> 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<MSN_START, MSN_LEN>( tWRT_Smin_MSN(i_target, i_spd_data) ). + insertFromRight<LSB_START, LSB_LEN>( tWRT_Smin_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; - // Combining bits to create timing value - l_buffer_upper_nibble.insert<, >(l_tWRTmin); - l_buffer_lower_byte.insert<, >(l_tWRTmin); + l_buffer.extractToRight<OUTPUT_START, OUTPUT_LEN>(l_timing_val); - // Retrive entire MCS level attribute - FAPI_TRY( eff_dram_twrt(l_target_mcs, &l_min_wrt_times[0][0]) ); - // Update attribute to decoded byte values (returning picoseconds, currently nanoseconds) - l_min_wrt_times[PORT_NUM][DIMM_NUM] = ns_to_ps(l_tWRTmin); + // JEDEC spec limits for this timing value - // 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; + // 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::min_twtr_l(const fapi2::Target<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_MCS>(i_target_dimm); - const auto l_target_port = find_target<TARGET_TYPE_MCA>(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<uint8_t> 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<TWTRMIN_L_MSN_START, TWTRMIN_L_MSN_LEN>(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<TARGET_TYPE_DIMM>& 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<uint8_t> l_buffer_upper_nibble(i_spd_data[BYTE_INDEX_MSN]); - fapi2::buffer<uint8_t> 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<uint8_t> 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<TWTRMIN_L_LSB_START, TWTRMIN_L_LSB_LEN>(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<int64_t> 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<MSN_START, MSN_LEN>( tWRT_Lmin_MSN(i_target, i_spd_data) ). + insertFromRight<LSB_START, LSB_LEN>( 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<OUTPUT_START, OUTPUT_LEN>(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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::fine_offset_min_tccd_l(const fapi2::Target<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_MCS>(i_target_dimm); - const auto l_target_port = find_target<TARGET_TYPE_MCA>(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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::fine_offset_min_trrd_l(const fapi2::Target<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_MCS>(i_target_dimm); - const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm); + constexpr size_t BYTE_INDEX = 118; + 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 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]); + + 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 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 (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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::fine_offset_min_trrd_s(const fapi2::Target<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_MCS>(i_target_dimm); - const auto l_target_port = find_target<TARGET_TYPE_MCA>(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 - // 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 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::fine_offset_min_trc(const fapi2::Target<TARGET_TYPE_DIMM>& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX = 120; - - // Targets - const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm); - const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm); + constexpr size_t BYTE_INDEX = 120; + 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 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::fine_offset_min_trp(const fapi2::Target<TARGET_TYPE_DIMM>& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX = 121; - - // Targets - const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm); - const auto l_target_port = find_target<TARGET_TYPE_MCA>(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 = 121; + 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 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 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 Row Precharge Delay Time (tRPmin)") ); - // 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 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::fine_offset_min_trcd(const fapi2::Target<TARGET_TYPE_DIMM>& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX = 122; + constexpr size_t BYTE_INDEX = 122; + 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<TARGET_TYPE_MCS>(i_target_dimm); - const auto l_target_port = find_target<TARGET_TYPE_MCA>(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 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]); + + 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 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 RAS to CAS Delay Time (tRCDmin) 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 Minimum CAS Latency Time (tAAmin) -/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::fine_offset_min_taa(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX = 123; - - // Targets - const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm); - const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm); + constexpr size_t BYTE_INDEX = 125; + 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 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::fine_offset_max_tck(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& 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<TARGET_TYPE_MCS>(i_target_dimm); - const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm); + constexpr size_t BYTE_INDEX = 124; + 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 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::fine_offset_min_tck(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target, + const uint8_t* i_spd_data, + int64_t& o_value) { - // Immutable constants - const size_t BYTE_INDEX = 125; - - // Targets - const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm); - const auto l_target_port = find_target<TARGET_TYPE_MCA>(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 = 125; + 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 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data) +fapi2::ReturnCode decoder::cyclical_redundancy_code(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_MCS>(i_target_dimm); - const auto l_target_port = find_target<TARGET_TYPE_MCA>(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<uint8_t> 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<CRC_MSB_START, CRC_MSB_LEN>(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<TARGET_TYPE_DIMM>& 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<uint8_t> l_buffer_upper_nibble(i_spd_data[BYTE_INDEX_MSN]); - fapi2::buffer<uint8_t> 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<uint8_t> l_buffer(i_data[BYTE_INDEX]); + + // Extracting desired bits + l_buffer.extractToRight<CRC_LSB_START, CRC_LSB_LEN>(l_out); + + return l_out; + }; + + fapi2::buffer<uint16_t> 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<MSN_START, MSN_LEN>( crc_MSB(i_target, i_spd_data) ). + insertFromRight<LSB_START, LSB_LEN>( 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<OUTPUT_START, OUTPUT_LEN>(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<fapi2::TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data, - const size_t i_read_spd_size); - - virtual fapi2::ReturnCode revision(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data); - - virtual fapi2::ReturnCode dram_device_type(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data); - - virtual fapi2::ReturnCode module_type(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data); - - virtual fapi2::ReturnCode sdram_density(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data); - - virtual fapi2::ReturnCode sdram_addressing(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data); - - virtual fapi2::ReturnCode primary_package_type(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data); - - virtual fapi2::ReturnCode sdram_optional_features(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data); - - virtual fapi2::ReturnCode thermal_and_refresh_options(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data); - - virtual fapi2::ReturnCode other_optional_features(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data); - - virtual fapi2::ReturnCode secondary_package_type(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data); - - virtual fapi2::ReturnCode module_nominal_voltage(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& 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<fapi2::TARGET_TYPE_DIMM>& 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<fapi2::TARGET_TYPE_DIMM>& 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<fapi2::TARGET_TYPE_DIMM>& 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<fapi2::TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data); + TRFC4MIN_MSB_START = 0, + TRFC4MIN_MSB_LEN = 8, - virtual fapi2::ReturnCode timebases(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& 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<fapi2::TARGET_TYPE_DIMM>& 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<fapi2::TARGET_TYPE_DIMM>& 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<fapi2::TARGET_TYPE_DIMM>& 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<fapi2::TARGET_TYPE_DIMM>& 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<fapi2::TARGET_TYPE_DIMM>& 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<fapi2::TARGET_TYPE_DIMM>& 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<fapi2::TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data); - - virtual fapi2::ReturnCode min_activate_to_activate_refresh_delay_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& - i_target_dimm, - const uint8_t* i_spd_data); - - virtual fapi2::ReturnCode min_activate_to_precharge_delay_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& - i_target_dimm, - const uint8_t* i_spd_data); - - virtual fapi2::ReturnCode min_refresh_recovery_delay_time_1(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data); - - virtual fapi2::ReturnCode min_refresh_recovery_delay_time_2(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data); - - virtual fapi2::ReturnCode min_refresh_recovery_delay_time_4(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data); + // Bytes 46 - 59 - reserved - virtual fapi2::ReturnCode min_four_activate_window_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& 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<fapi2::TARGET_TYPE_DIMM>& - 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<fapi2::TARGET_TYPE_DIMM>& - 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<fapi2::TARGET_TYPE_DIMM>& 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<fapi2::TARGET_TYPE_DIMM>& 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<fapi2::TARGET_TYPE_DIMM>& - 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<fapi2::TARGET_TYPE_DIMM>& - 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<fapi2::TARGET_TYPE_DIMM>& 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<fapi2::TARGET_TYPE_DIMM>& - 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<fapi2::TARGET_TYPE_DIMM>& - 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<fapi2::TARGET_TYPE_DIMM>& - 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<fapi2::TARGET_TYPE_DIMM>& - 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<fapi2::TARGET_TYPE_DIMM>& - i_target_dimm, - const uint8_t* i_spd_data); - virtual fapi2::ReturnCode offset_for_min_ras_to_cas_delay_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& - 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<fapi2::TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data); + public: + // Constructor + decoder() = default; - virtual fapi2::ReturnCode offset_for_min_cycle_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data); + // Deconstructor + virtual ~decoder() = default; - virtual fapi2::ReturnCode offset_for_max_cycle_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm, - const uint8_t* i_spd_data); - virtual fapi2::ReturnCode crc_for_base_config_section(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& i_target, + const uint8_t* i_spd_data, + std::shared_ptr<decoder>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<fapi2::TARGET_TYPE_DIMM>& 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<fapi2::TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<fapi2::TARGET_TYPE_DIMM>& 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<fapi2::TARGET_TYPE_DIMM>& 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<fapi2::TARGET_TYPE_DIMM>& 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<fapi2::TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<TARGET_TYPE_DIMM>& 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<fapi2::TARGET_TYPE_DIMM>& 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<fapi2::TARGET_TYPE_DIMM>& 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<fapi2::TARGET_TYPE_DIMM>& 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<fapi2::TARGET_TYPE_DIMM>& i_target, + const uint8_t* i_spd_data, + uint16_t& o_value); +};// decoder }// spd }// mss diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/utils/checker.H b/src/import/chips/p9/procedures/hwp/memory/lib/utils/checker.H index a91715876..f71578e82 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/utils/checker.H +++ b/src/import/chips/p9/procedures/hwp/memory/lib/utils/checker.H @@ -48,7 +48,7 @@ inline fapi2::ReturnCode dram_type(const fapi2::Target<fapi2::TARGET_TYPE_MCS>& uint8_t l_dram_gen[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0}; // Retrieve DDR4 dimm attributes - FAPI_TRY(spd_dram_device_type(i_target_mcs, &(l_dram_gen[0][0]))); + FAPI_TRY(eff_dram_gen(i_target_mcs, &(l_dram_gen[0][0]))); // Make sure all DRAMs are DDR4 or throw an error // Iterate through MCA's/ports @@ -66,7 +66,7 @@ inline fapi2::ReturnCode dram_type(const fapi2::Target<fapi2::TARGET_TYPE_MCS>& l_dram_gen[port_num][dimm_num]); // Nimbus supports only DDR4 - FAPI_ASSERT(l_dram_gen[port_num][dimm_num] == fapi2::ENUM_ATTR_SPD_DRAM_DEVICE_TYPE_DDR4, + FAPI_ASSERT(l_dram_gen[port_num][dimm_num] == fapi2::ENUM_ATTR_EFF_DRAM_GEN_DDR4, fapi2::MSS_UNSUPPORTED_DEV_TYPE(). set_DEV_TYPE(l_dram_gen[port_num][dimm_num]), "%s Incorrect DRAM device generation, DRAM generation is %llx", @@ -82,17 +82,14 @@ fapi_try_exit: /// -/// @brief Check if there is DIMM mixing (and deconfigures unsupported mixing <shrug> ?? - AAM) -/// @param[in] i_target_mcs const fapi2::Target<fapi2::TARGET_TYPE_MCS>& -/// @param[out] o_module_type uint64_t (returns something ?? - AAM ) +/// @brief Check if there is DIMM mixing (and deconfigures unsupported mixing ?? - AAM) /// @return FAPI2_RC_SUCCESS iff ok /// @note Functionality currently unknown /// -inline fapi2::ReturnCode dimm_mixing(const fapi2::Target<fapi2::TARGET_TYPE_MCS>& i_target_mcs, - uint64_t& o_module_type) +inline fapi2::ReturnCode dimm_mixing(void) { - //TODO - //Need to complete - AAM + //FIX p8 ported code + //Need to complete and figure out how to implement for p9 - AAM // Anuwat pushed Warren to say IBM systems will not support DIMM mixing // Now DIMM deconfig rules? - AAM @@ -137,12 +134,13 @@ inline fapi2::ReturnCode dimm_mixing(const fapi2::Target<fapi2::TARGET_TYPE_MCS> }// dimm_mixing /// -/// @brief Checks what type of system is configured (i.e., single drop, dual drop) -/// @note Functionality currently unknown +/// @brief Checks what type of system is configured (i.e., single drop, dual drop) +/// @return FAPI2_RC_SUCCESS iff ok +/// @warning Functionality currently unknown. Used in mss_freq /// inline fapi2::ReturnCode system_drop_type(void) { - //TODO + //Update for P9, how will we check if a system is single/dual drop?? - AAM #if 0 @@ -190,12 +188,12 @@ fapi_try_exit: /// /// @brief Checks nominal voltage is correct for all DIMMs -/// @param[in] i_target_mcsi const fapi2::Target<fapi2::TARGET_TYPE_MCS>&, -/// dimm_state i fapi2::TargetState -/// @return ReturnCode +/// @param[in] i_target_mcs the fapi2 target +/// @param[in] i_dimm_state (i.e. functional or non-functional) +/// @return ReturnCode /// inline fapi2::ReturnCode module_nominal_voltage(const fapi2::Target<fapi2::TARGET_TYPE_MCS>& i_target_mcs, - fapi2::TargetState dimm_state) + fapi2::TargetState i_dimm_state) { uint64_t l_module_nom_voltage[mss::PORTS_PER_MCS][mss::MAX_DIMM_PER_PORT] = {0}; @@ -207,7 +205,7 @@ inline fapi2::ReturnCode module_nominal_voltage(const fapi2::Target<fapi2::TARGE auto port_num = mss::index(p); // Iterate through DIMM targets - for (auto d : p.getChildren<fapi2::TARGET_TYPE_DIMM>(dimm_state)) + for (auto d : p.getChildren<fapi2::TARGET_TYPE_DIMM>(i_dimm_state)) { auto dimm_num = mss::index(d); @@ -231,66 +229,98 @@ fapi_try_exit: namespace spd { + /// /// @brief Checks conditional passes and implements traces & exits if it fails -/// @tparam T spd_data of any size -/// @param[in] i_target const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& , -/// conditional bool, -/// spd_byte_index size_t, -// spd_data T, -/// err_str const char* +/// @tparam T input data of any size +/// @param[in] i_target fapi2 dimm target +/// @param[in] i_conditional conditional that we are testing against +/// @param[in] i_spd_byte_index current SPD byte +/// @param[in] i_spd_data debug data +/// @param[in] i_err_str error string to print out when conditional fails /// @return ReturnCode /// template< typename T > -inline fapi2::ReturnCode valid_value_fail(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target, - bool conditional, - size_t spd_byte_index, - T spd_data, - const char* err_str) +inline fapi2::ReturnCode fail_for_invalid_value(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target, + bool i_conditional, + size_t i_spd_byte_index, + T i_spd_data, + const char* i_err_str) { - FAPI_ASSERT(conditional, - fapi2::MSS_SPD_DECODE_INVALID_VALUE(). - set_VALUE(spd_data). - set_BYTE(spd_byte_index). + FAPI_ASSERT(i_conditional, + fapi2::MSS_BAD_SPD(). + set_VALUE(i_spd_data). + set_BYTE(i_spd_byte_index). set_DIMM_TARGET(i_target), "%s %s Byte %d, Data returned: %d.", c_str(i_target), - err_str, - spd_byte_index, - spd_data); + i_err_str, + i_spd_byte_index, + i_spd_data); fapi_try_exit: return fapi2::current_err; -} // invalid_value_fail() +} // fail_for_invalid_value() /// -/// @brief Checks conditional passes and implements traces if it fails -/// @tparam T spd_data of any size -/// @param[in] i_targeti const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& , -/// conditional bool, -/// spd_byte_index size_t, -// spd_data T, -/// err_str const char* +/// @brief Checks conditional passes and implements traces if it fails. No FFDC collected. +/// @tparam T input data of any size +/// @param[in] i_target fapi2 dimm target +/// @param[in] i_conditional that we are testing against +/// @param[in] i_spd_byte_index +/// @param[in] i_spd_data debug data +/// @param[in] i_err_str string to print out when conditional fails /// @return void /// template< typename T > -inline void valid_value_warn(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target, - bool conditional, - size_t spd_byte_index, - T spd_data, - const char* err_str) +inline void warn_for_invalid_value(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target, + bool i_conditional, + size_t i_spd_byte_index, + T i_spd_data, + const char* i_err_str) { // Don't print warning conditional is true - if(!conditional) + if(!i_conditional) { FAPI_IMP("%s. %s. Byte %d, Data returned: %d.", c_str(i_target), - err_str, - spd_byte_index, - spd_data ); + i_err_str, + i_spd_byte_index, + i_spd_data ); } -}// valid_value_warn +}// warn_for_invalid_value + +/// +/// @brief Checks if valid factory parameters are given +/// @param[in] i_target fapi2 dimm target +/// @param[in] i_dimm_type DIMM type enumeration +/// @param[in] i_encoding_rev SPD encoding level rev number +/// @param[in] i_additions_rev SPD additions level rev number +/// @param[in] i_err_str string to print out when conditional fails +/// @return fapi2::ReturnCode +/// +inline fapi2::ReturnCode invalid_factory_sel(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target, + uint8_t i_dimm_type, + uint8_t i_encoding_rev, + uint8_t i_additions_rev, + const char* i_err_str) +{ + FAPI_ASSERT(false, + fapi2::MSS_INVALID_DIMM_REV_COMBO(). + set_DIMM_TYPE(i_dimm_type). + set_ENCODING_REV(i_encoding_rev). + set_ADDITIONS_REV(i_additions_rev). + set_DIMM_TARGET(i_target), + "%s. %s. Invalid combination for dimm type: %d, rev: %d.%d", + c_str(i_target), + i_err_str, + i_dimm_type, + i_encoding_rev, + i_additions_rev); +fapi_try_exit: + return fapi2::current_err; +}// invalid_factory_sel }// spd }// check diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/utils/conversions.H b/src/import/chips/p9/procedures/hwp/memory/lib/utils/conversions.H index c39ebf057..70c58289d 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/utils/conversions.H +++ b/src/import/chips/p9/procedures/hwp/memory/lib/utils/conversions.H @@ -42,36 +42,40 @@ static const uint64_t SIM_CYCLES_PER_CYCLE = 8; namespace mss { + +/// +/// @brief Return the number of picoseconds +/// @tparam T input and output type +/// @param[in] i_transfer_rate input in MegaTransfers per second (MT/s) +/// @return timing in picoseconds +/// @note clock periods are defined to 1 ps of accuracy, so +/// so 1.0714 ns is defined as 1071 ps as defined by JEDEC's +/// SPD rounding algorithm. This concept is used for this calculation. +/// +template<typename T> +inline T freq_to_ps(const T i_transfer_rate) +{ + // ATTR_MSS_FREQ is in MT/s, and we know microsecond per clock is 1/(freq/2) + // actual dimm_freq is 1/2 of the speed bin + T l_dimm_freq = i_transfer_rate / 2; + + // ps per clock (note value is rounded down) + return CONVERT_PS_IN_A_US / l_dimm_freq; +} + /// -/// @brief Return the number of picoseconds taken by a certain mhz -/// @param[in] i_mhz the mhz of interest -/// @return the picoseconds +/// @brief Return the number in MT/s +/// @tparam T input and output type +/// @param[in] i_time_in_ps time in picoseconds +/// @return speed in MT/s /// -inline uint64_t mhz_to_ps(const uint64_t i_mhz) +template<typename T> +inline T ps_to_freq(const T i_time_in_ps) { - // Just used for indexs into the array below - enum freqs { FREQ_2400 = 0, }; - - // ATTR_MSS_FREQ is in mHZ, and we know us per clock is 1/(freq/2) - // We don't have many frequencies, so lets just make a little table. - static const uint64_t FREQ_TO_PS[MAX_SUPPORTED_FREQUENCIES] = - { - // 2400 is 833 picoseconds per clock - 833 - }; - - switch(i_mhz) - { - case 2400: - return FREQ_TO_PS[FREQ_2400]; - - default: - FAPI_ERR("unsupported frequency %llu", i_mhz); - fapi2::Assert(false); - - // Keeps compiler happy - return 0; - } + // reverse of freq_to_ps function, solving for freq + // since running at DDR, data is transferred on both rising & falling edges + // hence the 2X factor + return (2 * CONVERT_PS_IN_A_US) / i_time_in_ps; } /// @@ -95,7 +99,7 @@ template< fapi2::TargetType T > inline uint64_t ps_to_cycles(const fapi2::Target<T>& i_target, const uint64_t i_ps) { // The frequency in mHZ - uint64_t l_freq; + uint64_t l_freq = 0; uint64_t l_divisor = 0; uint64_t l_quotient = 0; uint64_t l_remainder = 0; @@ -103,7 +107,7 @@ inline uint64_t ps_to_cycles(const fapi2::Target<T>& i_target, const uint64_t i_ FAPI_TRY( mss::freq( find_target<fapi2::TARGET_TYPE_MCBIST>(i_target), l_freq) ); // Hoping the compiler figures out how to do these together. - l_divisor = mhz_to_ps(l_freq); + l_divisor = freq_to_ps(l_freq); l_quotient = i_ps / l_divisor; l_remainder = i_ps % l_divisor; @@ -132,12 +136,12 @@ template< fapi2::TargetType T > inline uint64_t cycles_to_ps(const fapi2::Target<T>& i_target, const uint64_t i_cycles) { // The frequency in mHZ - uint64_t l_freq; + uint64_t l_freq = 0; FAPI_TRY( mss::freq( find_target<fapi2::TARGET_TYPE_MCBIST>(i_target), l_freq) ); - FAPI_DBG("converting %llu cycles to %llups", i_cycles, i_cycles * mhz_to_ps(l_freq)); - return i_cycles * mhz_to_ps(l_freq); + FAPI_DBG("converting %llu cycles to %llups", i_cycles, i_cycles * freq_to_ps(l_freq)); + return i_cycles * freq_to_ps(l_freq); fapi_try_exit: @@ -236,28 +240,33 @@ inline uint64_t twlo_twloe(const fapi2::Target<T>& i_target) } /// -/// @brief Convert nanoseconds to picoseconds -/// @param[in] i_time_in_ns int64_t time in nanoseconds -/// @return int64_t, time in picoseconds +/// @brief Convert nanoseconds to picoseconds +/// @tparam T input and output type +/// @param[in] i_time_in_ns time in nanoseconds +/// @return time in picoseconds /// -inline int64_t ns_to_ps(const int64_t& i_time_in_ns) +template<typename T> +inline T ns_to_ps(const T i_time_in_ns) { return i_time_in_ns * CONVERT_PS_IN_A_NS; } /// -/// @brief Convert nanoseconds to picoseconds -/// @param[in] i_time_in_ps int64_t time in picoseconds -/// @return int64_t, time in nanoseconds +/// @brief Convert nanoseconds to picoseconds +/// @tparam T input and output type +/// @param[in] i_time_in_ps time in picoseconds +/// @return time in nanoseconds /// -inline int64_t ps_to_ns(const int64_t& i_time_in_ps) +template<typename T> +inline T ps_to_ns(const T i_time_in_ps) { - int64_t remainder = i_time_in_ps % CONVERT_PS_IN_A_NS; - int64_t l_time_in_ns = i_time_in_ps / CONVERT_PS_IN_A_NS; + T remainder = i_time_in_ps % CONVERT_PS_IN_A_NS; + T l_time_in_ns = i_time_in_ps / CONVERT_PS_IN_A_NS; // Round up if remainder isn't even return l_time_in_ns + ( remainder == 0 ? 0 : 1 ); } };// mss namespace + #endif diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/utils/find.H b/src/import/chips/p9/procedures/hwp/memory/lib/utils/find.H index a13c1cd62..e15563970 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/utils/find.H +++ b/src/import/chips/p9/procedures/hwp/memory/lib/utils/find.H @@ -43,17 +43,17 @@ namespace mss /// @return a vector of M targets. /// template< fapi2::TargetType M, fapi2::TargetType T > -inline std::vector< fapi2::Target<M> > find_targets( const fapi2::Target<T>& ); +inline std::vector< fapi2::Target<M> > find_targets( const fapi2::Target<T>& i_target); /// /// @brief find an element based on a fapi2 target /// @tparam M the target type to be returned /// @tparam T the fapi2 target type of the argument -/// @param[in] the fapi2 target T +/// @param[in] i_target the fapi2 target T /// @return an M target. /// template< fapi2::TargetType M, fapi2::TargetType T > -inline fapi2::Target<M> find_target( const fapi2::Target<T>& ); +inline fapi2::Target<M> find_target( const fapi2::Target<T>& i_target ); /// /// @brief find the McBIST given a McBIST @@ -182,6 +182,39 @@ inline fapi2::Target<fapi2::TARGET_TYPE_MCA> find_target( const fapi2::Target<fa return i_target.getParent<fapi2::TARGET_TYPE_MCA>(); } +/// +/// @brief find a key value from a vector of STL pairs +/// @tparam T input type +/// @tparam OT the output type to be returned +/// @param[in] i_vector_of_pairs the input vector of pairs +/// @param[in] i_key the "map" key +/// @param[in] o_value the value found from given key +/// @return the value corresponding to the key +/// +template<typename T, typename OT> +bool find_value_from_key(const std::vector<std::pair<T, OT> >& i_vector_of_pairs, const T& i_key, OT& o_value) +{ + // Comparator lambda expression + auto compare = [](const std::pair<T, OT>& i_lhs, const T & i_value) + { + return (i_lhs.first < i_value); + }; + + // Find iterator to matching key (if it exists) + auto l_value_iterator = std::lower_bound(i_vector_of_pairs.begin(), i_vector_of_pairs.end(), i_key, compare); + + // Did you find it? Let me know. + if( (l_value_iterator == i_vector_of_pairs.end()) || (i_key != l_value_iterator->first) ) + { + return false; + } + + o_value = l_value_iterator->second; + return true; + +} + + }// mss #endif |