summaryrefslogtreecommitdiffstats
path: root/src/import/generic/memory/lib/data_engine/attr_engine_traits.H
diff options
context:
space:
mode:
Diffstat (limited to 'src/import/generic/memory/lib/data_engine/attr_engine_traits.H')
-rw-r--r--src/import/generic/memory/lib/data_engine/attr_engine_traits.H1550
1 files changed, 1547 insertions, 3 deletions
diff --git a/src/import/generic/memory/lib/data_engine/attr_engine_traits.H b/src/import/generic/memory/lib/data_engine/attr_engine_traits.H
index 44f6674d5..5de4f0da2 100644
--- a/src/import/generic/memory/lib/data_engine/attr_engine_traits.H
+++ b/src/import/generic/memory/lib/data_engine/attr_engine_traits.H
@@ -41,9 +41,12 @@
#include <generic/memory/lib/data_engine/data_engine_utils.H>
#include <generic/memory/lib/mss_generic_attribute_getters.H>
#include <generic/memory/lib/mss_generic_attribute_setters.H>
+#include <generic/memory/lib/mss_generic_system_attribute_getters.H>
#include <generic/memory/lib/spd/ddimm/efd_decoder.H>
#include <generic/memory/lib/spd/spd_facade.H>
#include <generic/memory/lib/utils/buffer_ops.H>
+#include <generic/memory/lib/utils/dimm/mss_timing.H>
+#include <generic/memory/lib/spd/spd_utils.H>
namespace mss
{
@@ -1599,7 +1602,7 @@ struct attrEngineTraits<attr_engine_derived_fields, LOGICAL_RANKS>
// Value of 1 has no meaning and is used for calculation purposes as defined by the SPD spec.
const auto l_multiplier = (l_prim_stack_type == fapi2::ENUM_ATTR_MEM_EFF_PRIM_STACK_TYPE_3DS) ? l_die_count : 1;
o_setting = (l_master_ranks * l_multiplier);
- FAPI_DBG("Num Logical Ranks %d", o_setting);
+ FAPI_DBG("%s Num Logical Ranks %d", spd::c_str(i_target), o_setting);
}
fapi_try_exit:
@@ -1668,8 +1671,8 @@ struct attrEngineTraits<attr_engine_derived_fields, MEM_DIMM_SIZE>
// Total = SDRAM Capacity / 8 * Primary Bus Width / SDRAM Width * Logical Ranks per DIMM
o_setting = (l_dram_density * l_bus_width * l_logical_rank_per_dimm) / (8 * l_dram_width);
- FAPI_DBG("DIMM size = %d => (%d * %d * %d) / (8 * %d)",
- o_setting, l_dram_density, l_bus_width, l_logical_rank_per_dimm, l_dram_width);
+ FAPI_DBG("%s DIMM size = %d => (%d * %d * %d) / (8 * %d)",
+ spd::c_str(i_target), o_setting, l_dram_density, l_bus_width, l_logical_rank_per_dimm, l_dram_width);
fapi_try_exit:
return fapi2::current_err;
@@ -1748,6 +1751,1547 @@ struct attrEngineTraits<attr_engine_derived_fields, HEIGHT_3DS>
}
};
+///
+/// @brief Traits for attrEngineTraits
+/// @class attrEngineTraits
+/// @note attrEngineTraits, DRAM_CWL specialization
+///
+template<>
+struct attrEngineTraits<attr_eff_engine_fields, DRAM_CWL>
+{
+ using attr_type = fapi2::ATTR_MEM_DRAM_CWL_Type;
+ using attr_integral_type = std::remove_all_extents<attr_type>::type;
+ static constexpr fapi2::TargetType TARGET_TYPE = fapi2::ATTR_MEM_DRAM_CWL_TargetType;
+ static constexpr generic_ffdc_codes FFDC_CODE = SET_DRAM_CWL;
+
+ ///
+ /// @brief attribute getter
+ /// @param[in] i_target the attr target
+ /// @param[out] o_setting array to populate
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode get_attr(const fapi2::Target<TARGET_TYPE>& i_target,
+ attr_type& o_setting)
+ {
+ return mss::attr::get_dram_cwl(i_target, o_setting);
+ }
+
+ ///
+ /// @brief attribute setter
+ /// @param[in] i_target the attr target
+ /// @param[in] i_setting array to set
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode set_attr(const fapi2::Target<TARGET_TYPE>& i_target,
+ attr_type& i_setting)
+ {
+ return mss::attr::set_dram_cwl(i_target, i_setting);
+ }
+
+ ///
+ /// @brief Computes setting for attribute
+ /// @param[in] i_spd_data SPD data
+ /// @param[out] o_setting value we want to set attr with
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode get_value_to_set(const spd::facade& i_spd_data,
+ attr_integral_type& o_setting)
+ {
+ // Taken from DDR4 JEDEC spec 1716.78C
+ // Proposed DDR4 Full spec update(79-4A)
+ // Page 26, Table 7
+ static const std::vector<std::pair<uint64_t, uint8_t> > CWL_TABLE_1 =
+ {
+ {1866, 10},
+ {2133, 11},
+ {2400, 12},
+ {2666, 14},
+ {2933, 16},
+ {3200, 16},
+ };
+
+ static const std::vector<std::pair<uint64_t, uint8_t> > CWL_TABLE_2 =
+ {
+ // Note that 2tCK write preamble is not valid for 1866 or 2133 speed grades
+ {2400, 14},
+ {2666, 16},
+ {2933, 18},
+ {3200, 18},
+ };
+
+ const auto& l_dimm = i_spd_data.get_dimm_target();
+ // TK This could change but not sure where to get this from
+ constexpr size_t MAX_RANKS_PER_DIMM = 4;
+ uint64_t l_freq = 0;
+ uint8_t l_preambles[MAX_RANKS_PER_DIMM] = {0};
+ fapi2::buffer<uint8_t> l_preamble;
+
+ FAPI_TRY( mss::attr::get_freq(mss::find_target<fapi2::TARGET_TYPE_MEM_PORT>(l_dimm), l_freq) );
+ FAPI_TRY( mss::attr::get_si_dram_preamble(l_dimm, l_preambles) );
+
+ // TK Using the preamble for rank0 for now
+ l_preamble = l_preambles[0];
+
+ if (!l_preamble.getBit<fapi2::ENUM_ATTR_MEM_SI_DRAM_PREAMBLE_WRITE_PREAMBLE_BIT>())
+ {
+ FAPI_TRY(lookup_table_check(l_dimm, CWL_TABLE_1, FFDC_CODE, l_freq, o_setting));
+ }
+ else
+ {
+ FAPI_TRY(lookup_table_check(l_dimm, CWL_TABLE_2, FFDC_CODE, l_freq, o_setting));
+ }
+
+ FAPI_DBG("%s DRAM CWL %d", spd::c_str(l_dimm), o_setting);
+
+ fapi_try_exit:
+ return fapi2::current_err;
+ }
+};
+
+///
+/// @brief Traits for attrEngineTraits
+/// @class attrEngineTraits
+/// @note attrEngineTraits, DRAM_TREFI specialization
+///
+template<>
+struct attrEngineTraits<attr_eff_engine_fields, DRAM_TREFI>
+{
+ using attr_type = fapi2::ATTR_MEM_EFF_DRAM_TREFI_Type;
+ using attr_integral_type = std::remove_all_extents<attr_type>::type;
+ static constexpr fapi2::TargetType TARGET_TYPE = fapi2::ATTR_MEM_EFF_DRAM_TREFI_TargetType;
+ static constexpr generic_ffdc_codes FFDC_CODE = SET_DRAM_TREFI;
+
+ ///
+ /// @brief attribute getter
+ /// @param[in] i_target the attr target
+ /// @param[out] o_setting array to populate
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode get_attr(const fapi2::Target<TARGET_TYPE>& i_target,
+ attr_type& o_setting)
+ {
+ return mss::attr::get_dram_trefi(i_target, o_setting);
+ }
+
+ ///
+ /// @brief attribute setter
+ /// @param[in] i_target the attr target
+ /// @param[in] i_setting array to set
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode set_attr(const fapi2::Target<TARGET_TYPE>& i_target,
+ attr_type& i_setting)
+ {
+ return mss::attr::set_dram_trefi(i_target, i_setting);
+ }
+
+ ///
+ /// @brief Computes setting for attribute
+ /// @param[in] i_spd_data SPD data
+ /// @param[out] o_setting value we want to set attr with
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode get_value_to_set(const spd::facade& i_spd_data,
+ attr_integral_type& o_setting)
+ {
+ const auto& l_dimm = i_spd_data.get_dimm_target();
+ uint8_t l_refresh_mode = 0;
+ uint8_t l_refresh_rate = 0;
+ uint64_t l_trefi_in_ps = 0;
+ int64_t l_tck_in_ps = 0;
+ uint64_t l_freq = 0;
+
+ FAPI_TRY( attr::get_freq(mss::find_target<fapi2::TARGET_TYPE_MEM_PORT>(l_dimm), l_freq) );
+ FAPI_TRY( freq_to_ps(l_freq, l_tck_in_ps),
+ "%s Failed to calculate clock period (tCK)", spd::c_str(l_dimm) );
+
+ FAPI_TRY( mss::attr::get_mrw_fine_refresh_mode(l_refresh_mode) );
+ FAPI_TRY( mss::attr::get_mrw_refresh_rate_request(l_refresh_rate) );
+
+ switch(l_refresh_mode)
+ {
+ case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_NORMAL:
+
+ FAPI_TRY( calc_trefi( mss::refresh_rate::REF1X,
+ l_refresh_rate,
+ l_trefi_in_ps),
+ "%s Failed to calculate tREF1", spd::c_str(l_dimm) );
+ break;
+
+ case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_FIXED_2X:
+ case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_FLY_2X:
+
+ FAPI_TRY( calc_trefi( mss::refresh_rate::REF2X,
+ l_refresh_rate,
+ l_trefi_in_ps),
+ "%s Failed to calculate tREF2", spd::c_str(l_dimm) );
+ break;
+
+ case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_FIXED_4X:
+ case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_FLY_4X:
+
+ FAPI_TRY( calc_trefi( mss::refresh_rate::REF4X,
+ l_refresh_rate,
+ l_trefi_in_ps),
+ "%s Failed to calculate tREF4", spd::c_str(l_dimm) );
+ break;
+
+ default:
+ // Fine Refresh Mode 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_FINE_REFRESH_MODE().
+ set_FINE_REF_MODE(l_refresh_mode),
+ "%s Incorrect Fine Refresh Mode received: %d ",
+ spd::c_str(l_dimm),
+ l_refresh_mode);
+ break;
+ };
+
+ {
+ // Calculate refresh cycle time in nCK & set attribute
+ constexpr double PERCENT_ADJUST = 0.99;
+
+ // Calculate nck
+ uint64_t l_trefi_in_nck = 0;
+ FAPI_TRY( spd::calc_nck( l_trefi_in_ps,
+ static_cast<uint64_t>(l_tck_in_ps),
+ spd::INVERSE_DDR4_CORRECTION_FACTOR,
+ l_trefi_in_nck),
+ "%s Error in calculating tREFI, with value of l_trefi_in_ps: %d", spd::c_str(l_dimm), l_trefi_in_ps);
+
+ // Lab requested 99% of tREFI calculation to avoid any latency impact and violation of any
+ // refresh specification (across all number of ranks and frequencies) observed
+ // during lab power/thermal tests.
+
+ FAPI_INF("%s adjusting tREFI calculation by 99%, calculated tREFI (nck): %lu, adjusted tREFI (nck): %lu,",
+ spd::c_str(l_dimm), l_trefi_in_nck, l_trefi_in_nck * PERCENT_ADJUST);
+
+ // The compiler does this under the covers but just to be explicit on intent:
+ // Floating point arithmetic and truncation of result saved to an unsigned integer
+ l_trefi_in_nck = static_cast<double>(l_trefi_in_nck * PERCENT_ADJUST);
+
+ FAPI_INF("%s tCK (ps): %d, tREFI (ps): %d, tREFI (nck): %d",
+ spd::c_str(l_dimm), l_tck_in_ps, l_trefi_in_ps, l_trefi_in_nck);
+
+ o_setting = l_trefi_in_nck;
+ FAPI_DBG("%s DRAM TREFI %d", spd::c_str(l_dimm), o_setting);
+ }
+
+ fapi_try_exit:
+ return fapi2::current_err;
+ }
+};
+
+///
+/// @brief Traits for attrEngineTraits
+/// @class attrEngineTraits
+/// @note attrEngineTraits, DRAM_TCCD_L specialization
+///
+template<>
+struct attrEngineTraits<attr_eff_engine_fields, DRAM_TCCD_L>
+{
+ using attr_type = fapi2::ATTR_MEM_EFF_DRAM_TCCD_L_Type;
+ using attr_integral_type = std::remove_all_extents<attr_type>::type;
+ static constexpr fapi2::TargetType TARGET_TYPE = fapi2::ATTR_MEM_EFF_DRAM_TCCD_L_TargetType;
+ static constexpr generic_ffdc_codes FFDC_CODE = SET_DRAM_TCCD_L;
+
+ ///
+ /// @brief attribute getter
+ /// @param[in] i_target the attr target
+ /// @param[out] o_setting array to populate
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode get_attr(const fapi2::Target<TARGET_TYPE>& i_target,
+ attr_type& o_setting)
+ {
+ return mss::attr::get_dram_tccd_l(i_target, o_setting);
+ }
+
+ ///
+ /// @brief attribute setter
+ /// @param[in] i_target the attr target
+ /// @param[in] i_setting array to set
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode set_attr(const fapi2::Target<TARGET_TYPE>& i_target,
+ attr_type& i_setting)
+ {
+ return mss::attr::set_dram_tccd_l(i_target, i_setting);
+ }
+
+ ///
+ /// @brief Computes setting for attribute
+ /// @param[in] i_spd_data SPD data
+ /// @param[out] o_setting value we want to set attr with
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode get_value_to_set(const spd::facade& i_spd_data,
+ attr_integral_type& o_setting)
+ {
+ const auto& l_dimm = i_spd_data.get_dimm_target();
+ int64_t l_tccd_in_ps = 0;
+ int64_t l_tck_in_ps = 0;
+ uint64_t l_freq = 0;
+
+ FAPI_TRY( attr::get_freq(mss::find_target<fapi2::TARGET_TYPE_MEM_PORT>(l_dimm), l_freq) );
+ FAPI_TRY( freq_to_ps(l_freq, l_tck_in_ps),
+ "%s Failed to calculate clock period (tCK)", spd::c_str(l_dimm) );
+
+ // Get the tCCD_L timing values
+ // tCCD_L is speed bin independent and is
+ // the same for all bins at a DRAM frequency.
+ // It is safe to read this from SPD because the correct nck
+ // value will be calulated based on our dimm speed.
+
+ {
+ int64_t l_ftb = 0;
+ int64_t l_mtb = 0;
+ int64_t l_tccd_mtb = 0;
+ int64_t l_tccd_ftb = 0;
+
+ FAPI_TRY( spd::get_timebases(i_spd_data, l_mtb, l_ftb) );
+ FAPI_TRY( i_spd_data.min_tccd_l(l_tccd_mtb),
+ "%s Failed min_tccd_l()", spd::c_str(l_dimm) );
+ FAPI_TRY( i_spd_data.fine_offset_min_tccd_l(l_tccd_ftb),
+ "%s Failed fine_offset_min_tccd_l()", spd::c_str(l_dimm) );
+
+ FAPI_INF("%s medium timebase (ps): %ld, fine timebase (ps): %ld, tCCD_L (MTB): %ld, tCCD_L(FTB): %ld",
+ spd::c_str(l_dimm), l_mtb, l_ftb, l_tccd_mtb, l_tccd_ftb );
+
+ l_tccd_in_ps = spd::calc_timing_from_timebase(l_tccd_mtb, l_mtb, l_tccd_ftb, l_ftb);
+ }
+
+ {
+ // Calculate refresh cycle time in nCK & set attribute
+ uint8_t l_tccd_in_nck = 0;
+
+ // Calculate nck
+ FAPI_TRY( spd::calc_nck(l_tccd_in_ps, l_tck_in_ps, spd::INVERSE_DDR4_CORRECTION_FACTOR, l_tccd_in_nck),
+ "%s Error in calculating tccd, with value of l_tccd_in_ps: %d",
+ spd::c_str(l_dimm), l_tccd_in_ps);
+
+ FAPI_INF("%s tCK (ps): %d, tCCD_L (ps): %d, tCCD_L (nck): %d",
+ spd::c_str(l_dimm), l_tck_in_ps, l_tccd_in_ps, l_tccd_in_nck);
+
+ o_setting = l_tccd_in_nck;
+ FAPI_DBG("%s DRAM TCCD_L %d", spd::c_str(l_dimm), o_setting);
+ }
+
+ fapi_try_exit:
+ return fapi2::current_err;
+ }
+};
+
+///
+/// @brief Traits for attrEngineTraits
+/// @class attrEngineTraits
+/// @note attrEngineTraits, DRAM_TWTR_L specialization
+///
+template<>
+struct attrEngineTraits<attr_eff_engine_fields, DRAM_TWTR_L>
+{
+ using attr_type = fapi2::ATTR_MEM_EFF_DRAM_TWTR_L_Type;
+ using attr_integral_type = std::remove_all_extents<attr_type>::type;
+ static constexpr fapi2::TargetType TARGET_TYPE = fapi2::ATTR_MEM_EFF_DRAM_TWTR_L_TargetType;
+ static constexpr generic_ffdc_codes FFDC_CODE = SET_DRAM_TWTR_L;
+
+ ///
+ /// @brief attribute getter
+ /// @param[in] i_target the attr target
+ /// @param[out] o_setting array to populate
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode get_attr(const fapi2::Target<TARGET_TYPE>& i_target,
+ attr_type& o_setting)
+ {
+ return mss::attr::get_dram_twtr_l(i_target, o_setting);
+ }
+
+ ///
+ /// @brief attribute setter
+ /// @param[in] i_target the attr target
+ /// @param[in] i_setting array to set
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode set_attr(const fapi2::Target<TARGET_TYPE>& i_target,
+ attr_type& i_setting)
+ {
+ return mss::attr::set_dram_twtr_l(i_target, i_setting);
+ }
+
+ ///
+ /// @brief Computes setting for attribute
+ /// @param[in] i_spd_data SPD data
+ /// @param[out] o_setting value we want to set attr with
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode get_value_to_set(const spd::facade& i_spd_data,
+ attr_integral_type& o_setting)
+ {
+ const auto& l_dimm = i_spd_data.get_dimm_target();
+ int64_t l_twtr_l_in_ps = 0;
+ int64_t l_tck_in_ps = 0;
+ uint64_t l_freq = 0;
+
+ FAPI_TRY( attr::get_freq(mss::find_target<fapi2::TARGET_TYPE_MEM_PORT>(l_dimm), l_freq) );
+ FAPI_TRY( freq_to_ps(l_freq, l_tck_in_ps),
+ "%s Failed to calculate clock period (tCK)", spd::c_str(l_dimm) );
+
+ // Calculate twtr_l (in ps)
+ {
+ int64_t l_ftb = 0;
+ int64_t l_mtb = 0;
+ constexpr int64_t l_twtr_l_ftb = 0;
+ int64_t l_twtr_l_mtb = 0;
+
+ FAPI_TRY( spd::get_timebases(i_spd_data, l_mtb, l_ftb) );
+ FAPI_TRY( i_spd_data.min_twtr_l(l_twtr_l_mtb) );
+
+ FAPI_INF("%s medium timebase (ps): %ld, fine timebase (ps): %ld, tWTR_L (MTB): %ld, tWTR_L (FTB): %ld",
+ spd::c_str(l_dimm), l_mtb, l_ftb, l_twtr_l_mtb, l_twtr_l_ftb );
+
+ l_twtr_l_in_ps = spd::calc_timing_from_timebase(l_twtr_l_mtb, l_mtb, l_twtr_l_ftb, l_ftb);
+ }
+
+ {
+ uint8_t l_twtr_l_in_nck = 0;
+
+ // Calculate nck
+ FAPI_TRY( spd::calc_nck(l_twtr_l_in_ps, l_tck_in_ps, spd::INVERSE_DDR4_CORRECTION_FACTOR, l_twtr_l_in_nck),
+ "%s Error in calculating tWTR_L, with value of l_twtr_in_ps: %d",
+ spd::c_str(l_dimm), l_twtr_l_in_ps );
+
+ FAPI_INF( "%s tCK (ps): %d, tWTR_L (ps): %d, tWTR_L (nck): %d",
+ spd::c_str(l_dimm), l_tck_in_ps, l_twtr_l_in_ps, l_twtr_l_in_nck );
+
+ o_setting = l_twtr_l_in_nck;
+ FAPI_DBG("%s DRAM TWTR_L %d", spd::c_str(l_dimm), o_setting);
+ }
+
+ fapi_try_exit:
+ return fapi2::current_err;
+ }
+};
+
+///
+/// @brief Traits for attrEngineTraits
+/// @class attrEngineTraits
+/// @note attrEngineTraits, DRAM_TWTR_S specialization
+///
+template<>
+struct attrEngineTraits<attr_eff_engine_fields, DRAM_TWTR_S>
+{
+ using attr_type = fapi2::ATTR_MEM_EFF_DRAM_TWTR_S_Type;
+ using attr_integral_type = std::remove_all_extents<attr_type>::type;
+ static constexpr fapi2::TargetType TARGET_TYPE = fapi2::ATTR_MEM_EFF_DRAM_TWTR_S_TargetType;
+ static constexpr generic_ffdc_codes FFDC_CODE = SET_DRAM_TWTR_S;
+
+ ///
+ /// @brief attribute getter
+ /// @param[in] i_target the attr target
+ /// @param[out] o_setting array to populate
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode get_attr(const fapi2::Target<TARGET_TYPE>& i_target,
+ attr_type& o_setting)
+ {
+ return mss::attr::get_dram_twtr_s(i_target, o_setting);
+ }
+
+ ///
+ /// @brief attribute setter
+ /// @param[in] i_target the attr target
+ /// @param[in] i_setting array to set
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode set_attr(const fapi2::Target<TARGET_TYPE>& i_target,
+ attr_type& i_setting)
+ {
+ return mss::attr::set_dram_twtr_s(i_target, i_setting);
+ }
+
+ ///
+ /// @brief Computes setting for attribute
+ /// @param[in] i_spd_data SPD data
+ /// @param[out] o_setting value we want to set attr with
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode get_value_to_set(const spd::facade& i_spd_data,
+ attr_integral_type& o_setting)
+ {
+ const auto& l_dimm = i_spd_data.get_dimm_target();
+ int64_t l_twtr_s_in_ps = 0;
+ int64_t l_tck_in_ps = 0;
+ uint64_t l_freq = 0;
+
+ FAPI_TRY( attr::get_freq(mss::find_target<fapi2::TARGET_TYPE_MEM_PORT>(l_dimm), l_freq) );
+ FAPI_TRY( freq_to_ps(l_freq, l_tck_in_ps),
+ "%s Failed to calculate clock period (tCK)", spd::c_str(l_dimm) );
+
+ // Calculate twtr_s (in ps)
+ {
+ int64_t l_ftb = 0;
+ int64_t l_mtb = 0;
+ constexpr int64_t l_twtr_s_ftb = 0;
+ int64_t l_twtr_s_mtb = 0;
+
+ FAPI_TRY( spd::get_timebases(i_spd_data, l_mtb, l_ftb) );
+ FAPI_TRY( i_spd_data.min_twtr_s(l_twtr_s_mtb) );
+
+ FAPI_INF("%s medium timebase (ps): %ld, fine timebase (ps): %ld, tWTR_S (MTB): %ld, tWTR_S (FTB): %ld",
+ spd::c_str(l_dimm), l_mtb, l_ftb, l_twtr_s_mtb, l_twtr_s_ftb );
+
+ l_twtr_s_in_ps = spd::calc_timing_from_timebase(l_twtr_s_mtb, l_mtb, l_twtr_s_ftb, l_ftb);
+ }
+
+ {
+ int8_t l_twtr_s_in_nck = 0;
+
+ // Calculate nck
+ FAPI_TRY( spd::calc_nck(l_twtr_s_in_ps, l_tck_in_ps, spd::INVERSE_DDR4_CORRECTION_FACTOR, l_twtr_s_in_nck),
+ "%s Error in calculating tWTR_S, with value of l_twtr_in_ps: %d",
+ spd::c_str(l_dimm), l_twtr_s_in_ps );
+
+ FAPI_INF( "%s tCK (ps): %d, tWTR_S (ps): %d, tWTR_S (nck): %d",
+ spd::c_str(l_dimm), l_tck_in_ps, l_twtr_s_in_ps, l_twtr_s_in_nck );
+
+ o_setting = l_twtr_s_in_nck;
+ FAPI_DBG("%s DRAM TWTR_S %d", spd::c_str(l_dimm), o_setting);
+ }
+
+ fapi_try_exit:
+ return fapi2::current_err;
+ }
+};
+
+///
+/// @brief Traits for attrEngineTraits
+/// @class attrEngineTraits
+/// @note attrEngineTraits, DRAM_TFAW specialization
+///
+template<>
+struct attrEngineTraits<attr_eff_engine_fields, DRAM_TFAW>
+{
+ using attr_type = fapi2::ATTR_MEM_EFF_DRAM_TFAW_Type;
+ using attr_integral_type = std::remove_all_extents<attr_type>::type;
+ static constexpr fapi2::TargetType TARGET_TYPE = fapi2::ATTR_MEM_EFF_DRAM_TFAW_TargetType;
+ static constexpr generic_ffdc_codes FFDC_CODE = SET_DRAM_TFAW;
+
+ ///
+ /// @brief attribute getter
+ /// @param[in] i_target the attr target
+ /// @param[out] o_setting array to populate
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode get_attr(const fapi2::Target<TARGET_TYPE>& i_target,
+ attr_type& o_setting)
+ {
+ return mss::attr::get_dram_tfaw(i_target, o_setting);
+ }
+
+ ///
+ /// @brief attribute setter
+ /// @param[in] i_target the attr target
+ /// @param[in] i_setting array to set
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode set_attr(const fapi2::Target<TARGET_TYPE>& i_target,
+ attr_type& i_setting)
+ {
+ return mss::attr::set_dram_tfaw(i_target, i_setting);
+ }
+
+ ///
+ /// @brief Computes setting for attribute
+ /// @param[in] i_spd_data SPD data
+ /// @param[out] o_setting value we want to set attr with
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode get_value_to_set(const spd::facade& i_spd_data,
+ attr_integral_type& o_setting)
+ {
+ const auto& l_dimm = i_spd_data.get_dimm_target();
+ uint64_t l_tfaw_in_nck = 0;
+ uint64_t l_jedec_tfaw_in_nck = 0;
+ int64_t l_tfaw_in_ps = 0;
+ int64_t l_tfaw_ftb = 0;
+ int64_t l_tck_in_ps = 0;
+ uint64_t l_freq = 0;
+ uint8_t l_dram_width = 0;
+
+ FAPI_TRY( attr::get_freq(mss::find_target<fapi2::TARGET_TYPE_MEM_PORT>(l_dimm), l_freq) );
+ FAPI_TRY( freq_to_ps(l_freq, l_tck_in_ps),
+ "%s Failed to calculate clock period (tCK)", spd::c_str(l_dimm) );
+
+ // Calculate tFAW
+ {
+ int64_t l_ftb = 0;
+ int64_t l_mtb = 0;
+ int64_t l_tfaw_mtb = 0;
+
+ FAPI_TRY( spd::get_timebases(i_spd_data, l_mtb, l_ftb) );
+ FAPI_TRY( i_spd_data.min_tfaw(l_tfaw_mtb),
+ "%s Failed min_tfaw()", spd::c_str(l_dimm) );
+
+ FAPI_INF("%s medium timebase (ps): %ld, fine timebase (ps): %ld, tfaw (MTB): %ld",
+ spd::c_str(l_dimm), l_mtb, l_ftb, l_tfaw_mtb);
+
+ l_tfaw_in_ps = spd::calc_timing_from_timebase(l_tfaw_mtb, l_mtb, l_tfaw_ftb, l_ftb);
+
+ FAPI_ASSERT( l_tfaw_in_ps >= 0,
+ fapi2::MSS_INVALID_TIMING_VALUE()
+ .set_VALUE(l_tfaw_in_ps)
+ .set_DIMM_TARGET(l_dimm)
+ .set_FUNCTION(TFAW),
+ "%s Error calculating tFAW (%d). Less than or equal to 0",
+ spd::c_str(l_dimm),
+ l_tfaw_in_ps);
+
+ FAPI_DBG("%s TFAW in ps is %d", spd::c_str(l_dimm), l_tfaw_in_ps);
+
+ FAPI_TRY( spd::calc_nck(l_tfaw_in_ps, l_tck_in_ps, spd::INVERSE_DDR4_CORRECTION_FACTOR, l_tfaw_in_nck),
+ "%s Error in calculating l_tFAW, with value of l_tfaw_in_ps: %d",
+ spd::c_str(l_dimm),
+ l_tfaw_in_nck);
+ }
+
+ FAPI_TRY( attr::get_dram_width(l_dimm, l_dram_width) );
+ FAPI_TRY( mss::tfaw(l_dimm, l_dram_width, l_freq, l_jedec_tfaw_in_nck), "Failed tfaw()" );
+
+ // Taking the worst case between the required minimum JEDEC value and the proposed value from SPD
+ if (l_jedec_tfaw_in_nck != l_tfaw_in_nck)
+ {
+ FAPI_INF("%s TFAW from JEDEC (%d) and from SPD (%d) don't match. Choosing worst case. dram width %d, freq %d",
+ spd::c_str(l_dimm),
+ l_jedec_tfaw_in_nck,
+ l_tfaw_in_nck,
+ l_dram_width,
+ l_freq);
+
+ l_tfaw_in_nck = std::max(l_jedec_tfaw_in_nck, l_tfaw_in_nck);
+ }
+
+ FAPI_INF("%s SDRAM width: %d, tFAW (nck): %d",
+ spd::c_str(l_dimm), l_dram_width, l_tfaw_in_nck);
+ o_setting = l_tfaw_in_nck;
+ FAPI_DBG("%s DRAM TFAW %d", spd::c_str(l_dimm), o_setting);
+
+ fapi_try_exit:
+ return fapi2::current_err;
+ }
+};
+
+///
+/// @brief Traits for attrEngineTraits
+/// @class attrEngineTraits
+/// @note attrEngineTraits, DRAM_TRCD specialization
+///
+template<>
+struct attrEngineTraits<attr_eff_engine_fields, DRAM_TRCD>
+{
+ using attr_type = fapi2::ATTR_MEM_EFF_DRAM_TRCD_Type;
+ using attr_integral_type = std::remove_all_extents<attr_type>::type;
+ static constexpr fapi2::TargetType TARGET_TYPE = fapi2::ATTR_MEM_EFF_DRAM_TRCD_TargetType;
+ static constexpr generic_ffdc_codes FFDC_CODE = SET_DRAM_TRCD;
+
+ ///
+ /// @brief attribute getter
+ /// @param[in] i_target the attr target
+ /// @param[out] o_setting array to populate
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode get_attr(const fapi2::Target<TARGET_TYPE>& i_target,
+ attr_type& o_setting)
+ {
+ return mss::attr::get_dram_trcd(i_target, o_setting);
+ }
+
+ ///
+ /// @brief attribute setter
+ /// @param[in] i_target the attr target
+ /// @param[in] i_setting array to set
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode set_attr(const fapi2::Target<TARGET_TYPE>& i_target,
+ attr_type& i_setting)
+ {
+ return mss::attr::set_dram_trcd(i_target, i_setting);
+ }
+
+ ///
+ /// @brief Computes setting for attribute
+ /// @param[in] i_spd_data SPD data
+ /// @param[out] o_setting value we want to set attr with
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode get_value_to_set(const spd::facade& i_spd_data,
+ attr_integral_type& o_setting)
+ {
+ const auto& l_dimm = i_spd_data.get_dimm_target();
+ int64_t l_tck_in_ps = 0;
+ uint64_t l_freq = 0;
+ int64_t l_trcd_in_ps = 0;
+
+ FAPI_TRY( attr::get_freq(mss::find_target<fapi2::TARGET_TYPE_MEM_PORT>(l_dimm), l_freq) );
+ FAPI_TRY( freq_to_ps(l_freq, l_tck_in_ps),
+ "%s Failed to calculate clock period (tCK)", spd::c_str(l_dimm) );
+
+ // Calculate tRCD (in ps)
+ // Get the tRCD timing values
+ // tRCD is speed bin dependent and has a unique
+ // value for each speed bin so it is safe to
+ // read from SPD because the correct nck
+ // value will be calulated based on our dimm speed.
+ {
+ int64_t l_ftb = 0;
+ int64_t l_mtb = 0;
+ int64_t l_trcd_mtb = 0;
+ int64_t l_trcd_ftb = 0;
+
+ FAPI_TRY( spd::get_timebases(i_spd_data, l_mtb, l_ftb) );
+ FAPI_TRY( i_spd_data.min_trcd(l_trcd_mtb),
+ "%s Failed min_trcd()", spd::c_str(l_dimm) );
+ FAPI_TRY( i_spd_data.fine_offset_min_trcd(l_trcd_ftb),
+ "%s Failed fine_offset_min_trcd()", spd::c_str(l_dimm) );
+
+ FAPI_INF("%s medium timebase MTB (ps): %ld, fine timebase FTB (ps): %ld, tRCD (MTB): %ld, tRCD (FTB): %ld",
+ spd::c_str(l_dimm), l_mtb, l_ftb, l_trcd_mtb, l_trcd_ftb);
+
+ l_trcd_in_ps = spd::calc_timing_from_timebase(l_trcd_mtb, l_mtb, l_trcd_ftb, l_ftb);
+ }
+
+ {
+ uint8_t l_trcd_in_nck = 0;
+
+ // Calculate nck
+ FAPI_TRY( spd::calc_nck(l_trcd_in_ps, l_tck_in_ps, spd::INVERSE_DDR4_CORRECTION_FACTOR, l_trcd_in_nck),
+ "%s Error in calculating trcd, with value of l_trcd_in_ps: %d",
+ spd::c_str(l_dimm), l_trcd_in_ps);
+
+ FAPI_INF("%s tCK (ps): %d, tRCD (ps): %d, tRCD (nck): %d",
+ spd::c_str(l_dimm), l_tck_in_ps, l_trcd_in_ps, l_trcd_in_nck);
+
+ o_setting = l_trcd_in_nck;
+ FAPI_DBG("%s DRAM TRCD %d", spd::c_str(l_dimm), o_setting);
+ }
+
+ fapi_try_exit:
+ return fapi2::current_err;
+ }
+};
+
+///
+/// @brief Traits for attrEngineTraits
+/// @class attrEngineTraits
+/// @note attrEngineTraits, DRAM_TRP specialization
+///
+template<>
+struct attrEngineTraits<attr_eff_engine_fields, DRAM_TRP>
+{
+ using attr_type = fapi2::ATTR_MEM_EFF_DRAM_TRP_Type;
+ using attr_integral_type = std::remove_all_extents<attr_type>::type;
+ static constexpr fapi2::TargetType TARGET_TYPE = fapi2::ATTR_MEM_EFF_DRAM_TRP_TargetType;
+ static constexpr generic_ffdc_codes FFDC_CODE = SET_DRAM_TRP;
+
+ ///
+ /// @brief attribute getter
+ /// @param[in] i_target the attr target
+ /// @param[out] o_setting array to populate
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode get_attr(const fapi2::Target<TARGET_TYPE>& i_target,
+ attr_type& o_setting)
+ {
+ return mss::attr::get_dram_trp(i_target, o_setting);
+ }
+
+ ///
+ /// @brief attribute setter
+ /// @param[in] i_target the attr target
+ /// @param[in] i_setting array to set
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode set_attr(const fapi2::Target<TARGET_TYPE>& i_target,
+ attr_type& i_setting)
+ {
+ return mss::attr::set_dram_trp(i_target, i_setting);
+ }
+
+ ///
+ /// @brief Computes setting for attribute
+ /// @param[in] i_spd_data SPD data
+ /// @param[out] o_setting value we want to set attr with
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode get_value_to_set(const spd::facade& i_spd_data,
+ attr_integral_type& o_setting)
+ {
+ const auto& l_dimm = i_spd_data.get_dimm_target();
+ int64_t l_tck_in_ps = 0;
+ uint64_t l_freq = 0;
+ int64_t l_trp_in_ps = 0;
+
+ FAPI_TRY( attr::get_freq(mss::find_target<fapi2::TARGET_TYPE_MEM_PORT>(l_dimm), l_freq) );
+ FAPI_TRY( freq_to_ps(l_freq, l_tck_in_ps),
+ "%s Failed to calculate clock period (tCK)", spd::c_str(l_dimm) );
+
+ // Calculate tRP (in ps)
+ {
+ int64_t l_ftb = 0;
+ int64_t l_mtb = 0;
+ int64_t l_trp_mtb = 0;
+ int64_t l_trp_ftb = 0;
+
+ FAPI_TRY( spd::get_timebases(i_spd_data, l_mtb, l_ftb) );
+ FAPI_TRY( i_spd_data.min_trp(l_trp_mtb),
+ "%s Failed min_trp()", spd::c_str(l_dimm) );
+
+ FAPI_TRY( i_spd_data.fine_offset_min_trp(l_trp_ftb),
+ "%s Failed fine_offset_min_trp()", spd::c_str(l_dimm) );
+
+ FAPI_INF("%s medium timebase (ps): %ld, fine timebase (ps): %ld, tRP (MTB): %ld, tRP(FTB): %ld",
+ spd::c_str(l_dimm), l_mtb, l_ftb, l_trp_mtb, l_trp_ftb);
+
+ l_trp_in_ps = spd::calc_timing_from_timebase(l_trp_mtb, l_mtb, l_trp_ftb, l_ftb);
+ }
+
+ // SPD spec gives us the minimum... compute our worstcase (maximum) from JEDEC
+ {
+ // Declaring as int64_t to fix std::max compile
+ const int64_t l_trp = mss::ps_to_cycles(l_tck_in_ps, mss::trtp());
+ l_trp_in_ps = std::max(l_trp_in_ps, l_trp);
+ }
+
+ {
+ uint8_t l_trp_in_nck = 0;
+
+ // Calculate nck
+ FAPI_TRY( spd::calc_nck(l_trp_in_ps, l_tck_in_ps, spd::INVERSE_DDR4_CORRECTION_FACTOR, l_trp_in_nck),
+ "%s Error in calculating dram_tRP nck, with value of l_trp_in_ps: %d",
+ spd::c_str(l_dimm), l_trp_in_ps);
+
+ FAPI_INF( "%s tCK (ps): %d, tRP (ps): %d, tRP (nck): %d",
+ spd::c_str(l_dimm), l_tck_in_ps, l_trp_in_ps, l_trp_in_nck );
+
+ o_setting = l_trp_in_nck;
+ FAPI_DBG("%s DRAM TRP %d", spd::c_str(l_dimm), o_setting);
+ }
+
+ fapi_try_exit:
+ return fapi2::current_err;
+ }
+};
+
+///
+/// @brief Traits for attrEngineTraits
+/// @class attrEngineTraits
+/// @note attrEngineTraits, DRAM_TRAS specialization
+///
+template<>
+struct attrEngineTraits<attr_eff_engine_fields, DRAM_TRAS>
+{
+ using attr_type = fapi2::ATTR_MEM_EFF_DRAM_TRAS_Type;
+ using attr_integral_type = std::remove_all_extents<attr_type>::type;
+ static constexpr fapi2::TargetType TARGET_TYPE = fapi2::ATTR_MEM_EFF_DRAM_TRAS_TargetType;
+ static constexpr generic_ffdc_codes FFDC_CODE = SET_DRAM_TRAS;
+
+ ///
+ /// @brief attribute getter
+ /// @param[in] i_target the attr target
+ /// @param[out] o_setting array to populate
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode get_attr(const fapi2::Target<TARGET_TYPE>& i_target,
+ attr_type& o_setting)
+ {
+ return mss::attr::get_dram_tras(i_target, o_setting);
+ }
+
+ ///
+ /// @brief attribute setter
+ /// @param[in] i_target the attr target
+ /// @param[in] i_setting array to set
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode set_attr(const fapi2::Target<TARGET_TYPE>& i_target,
+ attr_type& i_setting)
+ {
+ return mss::attr::set_dram_tras(i_target, i_setting);
+ }
+
+ ///
+ /// @brief Computes setting for attribute
+ /// @param[in] i_spd_data SPD data
+ /// @param[out] o_setting value we want to set attr with
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode get_value_to_set(const spd::facade& i_spd_data,
+ attr_integral_type& o_setting)
+ {
+ const auto& l_dimm = i_spd_data.get_dimm_target();
+ int64_t l_tck_in_ps = 0;
+ uint64_t l_freq = 0;
+ uint64_t l_tras_in_ps = 0;
+ uint8_t l_tras_in_nck = 0;
+
+ // tRAS is bin independent so we don't read this from SPD
+ // which will give the best timing value for the dimm
+ // (like 2400 MT/s) which may be different than the system
+ // speed (if we were being limited by VPD or MRW restrictions)
+ FAPI_TRY( attr::get_freq(mss::find_target<fapi2::TARGET_TYPE_MEM_PORT>(l_dimm), l_freq) );
+ l_tras_in_ps = mss::tras(l_dimm, l_freq);
+
+ FAPI_TRY( freq_to_ps(l_freq, l_tck_in_ps),
+ "%s Failed to calculate clock period (tCK)", spd::c_str(l_dimm) );
+
+ // Cast needed for calculations to be done on the same integral type
+ // as required by template deduction. We have l_tck_in_ps as a signed
+ // integer because we have other timing values that calculations do
+ // addition with negative integers.
+ FAPI_TRY( spd::calc_nck(l_tras_in_ps,
+ static_cast<uint64_t>(l_tck_in_ps),
+ spd::INVERSE_DDR4_CORRECTION_FACTOR,
+ l_tras_in_nck),
+ "%s Error in calculating tras_l, with value of l_twtr_in_ps: %d",
+ spd::c_str(l_dimm), l_tras_in_ps);
+
+ FAPI_INF("%s tCK (ps): %d, tRAS (ps): %d, tRAS (nck): %d",
+ spd::c_str(l_dimm), l_tck_in_ps, l_tras_in_ps, l_tras_in_nck);
+
+ o_setting = l_tras_in_nck;
+ FAPI_DBG("%s DRAM TRAS %d", spd::c_str(l_dimm), o_setting);
+
+ fapi_try_exit:
+ return fapi2::current_err;
+ }
+};
+
+///
+/// @brief Traits for attrEngineTraits
+/// @class attrEngineTraits
+/// @note attrEngineTraits, DRAM_TWR specialization
+///
+template<>
+struct attrEngineTraits<attr_eff_engine_fields, DRAM_TWR>
+{
+ using attr_type = fapi2::ATTR_MEM_EFF_DRAM_TWR_Type;
+ using attr_integral_type = std::remove_all_extents<attr_type>::type;
+ static constexpr fapi2::TargetType TARGET_TYPE = fapi2::ATTR_MEM_EFF_DRAM_TWR_TargetType;
+ static constexpr generic_ffdc_codes FFDC_CODE = SET_DRAM_TWR;
+
+ ///
+ /// @brief attribute getter
+ /// @param[in] i_target the attr target
+ /// @param[out] o_setting array to populate
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode get_attr(const fapi2::Target<TARGET_TYPE>& i_target,
+ attr_type& o_setting)
+ {
+ return mss::attr::get_dram_twr(i_target, o_setting);
+ }
+
+ ///
+ /// @brief attribute setter
+ /// @param[in] i_target the attr target
+ /// @param[in] i_setting array to set
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode set_attr(const fapi2::Target<TARGET_TYPE>& i_target,
+ attr_type& i_setting)
+ {
+ return mss::attr::set_dram_twr(i_target, i_setting);
+ }
+
+ ///
+ /// @brief Computes setting for attribute
+ /// @param[in] i_spd_data SPD data
+ /// @param[out] o_setting value we want to set attr with
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode get_value_to_set(const spd::facade& i_spd_data,
+ attr_integral_type& o_setting)
+ {
+ const auto& l_dimm = i_spd_data.get_dimm_target();
+ int64_t l_tck_in_ps = 0;
+ uint64_t l_freq = 0;
+ int64_t l_twr_in_ps = 0;
+
+ FAPI_TRY( attr::get_freq(mss::find_target<fapi2::TARGET_TYPE_MEM_PORT>(l_dimm), l_freq) );
+ FAPI_TRY( freq_to_ps(l_freq, l_tck_in_ps),
+ "%s Failed to calculate clock period (tCK)", spd::c_str(l_dimm) );
+
+ // Get the tWR timing values
+ // tWR is speed bin independent and is
+ // the same for all bins within a speed grade.
+ // It is safe to read this from SPD because the correct nck
+ // value will be calulated based on our dimm speed.
+ {
+ constexpr int64_t l_twr_ftb = 0;
+ int64_t l_twr_mtb = 0;
+ int64_t l_ftb = 0;
+ int64_t l_mtb = 0;
+
+ FAPI_TRY( spd::get_timebases(i_spd_data, l_mtb, l_ftb) );
+
+ FAPI_TRY( i_spd_data.min_twr(l_twr_mtb),
+ "%s Failed min_twr()", spd::c_str(l_dimm) );
+
+ FAPI_INF("%s medium timebase (ps): %ld, fine timebase (ps): %ld, tWR (MTB): %ld, tWR(FTB): %ld",
+ spd::c_str(l_dimm), l_mtb, l_ftb, l_twr_mtb, l_twr_ftb);
+
+ // Calculate twr (in ps)
+ l_twr_in_ps = spd::calc_timing_from_timebase(l_twr_mtb, l_mtb, l_twr_ftb, l_ftb);
+ }
+
+ {
+ uint8_t l_twr_in_nck = 0;
+
+ // Calculate tNCK
+ FAPI_TRY( spd::calc_nck(l_twr_in_ps, l_tck_in_ps, spd::INVERSE_DDR4_CORRECTION_FACTOR, l_twr_in_nck),
+ "%s Error in calculating l_twr_in_nck, with value of l_twr_in_ps: %d", spd::c_str(l_dimm), l_twr_in_ps);
+
+ FAPI_INF( "%s tCK (ps): %d, tWR (ps): %d, tWR (nck): %d",
+ spd::c_str(l_dimm), l_tck_in_ps, l_twr_in_ps, l_twr_in_nck );
+
+ o_setting = l_twr_in_nck;
+ FAPI_DBG("%s DRAM TWR %d", spd::c_str(l_dimm), o_setting);
+ }
+
+ fapi_try_exit:
+ return fapi2::current_err;
+ }
+};
+
+///
+/// @brief Traits for attrEngineTraits
+/// @class attrEngineTraits
+/// @note attrEngineTraits, DRAM_TRTP specialization
+///
+template<>
+struct attrEngineTraits<attr_eff_engine_fields, DRAM_TRTP>
+{
+ using attr_type = fapi2::ATTR_MEM_EFF_DRAM_TRTP_Type;
+ using attr_integral_type = std::remove_all_extents<attr_type>::type;
+ static constexpr fapi2::TargetType TARGET_TYPE = fapi2::ATTR_MEM_EFF_DRAM_TRTP_TargetType;
+ static constexpr generic_ffdc_codes FFDC_CODE = SET_DRAM_TRTP;
+
+ ///
+ /// @brief attribute getter
+ /// @param[in] i_target the attr target
+ /// @param[out] o_setting array to populate
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode get_attr(const fapi2::Target<TARGET_TYPE>& i_target,
+ attr_type& o_setting)
+ {
+ return mss::attr::get_dram_trtp(i_target, o_setting);
+ }
+
+ ///
+ /// @brief attribute setter
+ /// @param[in] i_target the attr target
+ /// @param[in] i_setting array to set
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode set_attr(const fapi2::Target<TARGET_TYPE>& i_target,
+ attr_type& i_setting)
+ {
+ return mss::attr::set_dram_trtp(i_target, i_setting);
+ }
+
+ ///
+ /// @brief Computes setting for attribute
+ /// @param[in] i_spd_data SPD data
+ /// @param[out] o_setting value we want to set attr with
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode get_value_to_set(const spd::facade& i_spd_data,
+ attr_integral_type& o_setting)
+ {
+ const auto& l_dimm = i_spd_data.get_dimm_target();
+ int64_t l_tck_in_ps = 0;
+ uint64_t l_freq = 0;
+
+ // Values from proposed DDR4 Full spec update(79-4A)
+ // Item No. 1716.78C
+ // Page 241 & 246
+ constexpr int64_t l_max_trtp_in_ps = trtp();
+ uint8_t l_calc_trtp_in_nck = 0;
+
+ FAPI_TRY( attr::get_freq(mss::find_target<fapi2::TARGET_TYPE_MEM_PORT>(l_dimm), l_freq) );
+ FAPI_TRY( freq_to_ps(l_freq, l_tck_in_ps),
+ "%s Failed to calculate clock period (tCK)", spd::c_str(l_dimm) );
+
+ // Calculate nck
+ FAPI_TRY( spd::calc_nck(l_max_trtp_in_ps, l_tck_in_ps, spd::INVERSE_DDR4_CORRECTION_FACTOR, l_calc_trtp_in_nck),
+ "%s Error in calculating trtp, with value of l_twtr_in_ps: %d",
+ spd::c_str(l_dimm), l_max_trtp_in_ps);
+
+ FAPI_INF("%s tCK (ps): %d, tRTP (ps): %d, tRTP (nck): %d",
+ spd::c_str(l_dimm), l_tck_in_ps, l_max_trtp_in_ps, l_calc_trtp_in_nck);
+
+ o_setting = l_calc_trtp_in_nck;
+ FAPI_DBG("%s DRAM TRTP %d", spd::c_str(l_dimm), o_setting);
+
+ fapi_try_exit:
+ return fapi2::current_err;
+ }
+};
+
+///
+/// @brief Traits for attrEngineTraits
+/// @class attrEngineTraits
+/// @note attrEngineTraits, DRAM_TRRD_S specialization
+///
+template<>
+struct attrEngineTraits<attr_eff_engine_fields, DRAM_TRRD_S>
+{
+ using attr_type = fapi2::ATTR_MEM_EFF_DRAM_TRRD_S_Type;
+ using attr_integral_type = std::remove_all_extents<attr_type>::type;
+ static constexpr fapi2::TargetType TARGET_TYPE = fapi2::ATTR_MEM_EFF_DRAM_TRRD_S_TargetType;
+ static constexpr generic_ffdc_codes FFDC_CODE = SET_DRAM_TRRD_S;
+
+ ///
+ /// @brief attribute getter
+ /// @param[in] i_target the attr target
+ /// @param[out] o_setting array to populate
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode get_attr(const fapi2::Target<TARGET_TYPE>& i_target,
+ attr_type& o_setting)
+ {
+ return mss::attr::get_dram_trrd_s(i_target, o_setting);
+ }
+
+ ///
+ /// @brief attribute setter
+ /// @param[in] i_target the attr target
+ /// @param[in] i_setting array to set
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode set_attr(const fapi2::Target<TARGET_TYPE>& i_target,
+ attr_type& i_setting)
+ {
+ return mss::attr::set_dram_trrd_s(i_target, i_setting);
+ }
+
+ ///
+ /// @brief Computes setting for attribute
+ /// @param[in] i_spd_data SPD data
+ /// @param[out] o_setting value we want to set attr with
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode get_value_to_set(const spd::facade& i_spd_data,
+ attr_integral_type& o_setting)
+ {
+ const auto& l_dimm = i_spd_data.get_dimm_target();
+ int64_t l_tck_in_ps = 0;
+ uint64_t l_freq = 0;
+ uint64_t l_trrd_s_in_nck = 0;
+ int64_t l_trrd_s_in_ps = 0;
+ uint64_t l_jedec_trrd = 0;
+ uint8_t l_dram_width = 0;
+
+ FAPI_TRY( attr::get_freq(mss::find_target<fapi2::TARGET_TYPE_MEM_PORT>(l_dimm), l_freq) );
+ FAPI_TRY( freq_to_ps(l_freq, l_tck_in_ps),
+ "%s Failed to calculate clock period (tCK)", spd::c_str(l_dimm) );
+
+ // Calculate tRRD_S
+ {
+ int64_t l_trrd_s_mtb = 0;
+ int64_t l_trrd_s_ftb = 0;
+ int64_t l_ftb = 0;
+ int64_t l_mtb = 0;
+
+ FAPI_TRY( spd::get_timebases(i_spd_data, l_mtb, l_ftb) );
+
+ FAPI_TRY( i_spd_data.min_trrd_s(l_trrd_s_mtb),
+ "%s Failed min_trrd_s()", spd::c_str(l_dimm) );
+
+ FAPI_TRY( i_spd_data.fine_offset_min_trrd_s(l_trrd_s_ftb),
+ "%s Failed fine_offset_min_trrd_s()", spd::c_str(l_dimm) );
+
+ FAPI_INF("%s medium timebase (ps): %ld, fine timebase (ps): %ld, trrd_s (MTB): %ld",
+ spd::c_str(l_dimm), l_mtb, l_ftb, l_trrd_s_mtb);
+
+ l_trrd_s_in_ps = spd::calc_timing_from_timebase(l_trrd_s_mtb, l_mtb, l_trrd_s_ftb, l_ftb);
+
+ FAPI_ASSERT( l_trrd_s_in_ps >= 0,
+ fapi2::MSS_INVALID_TIMING_VALUE()
+ .set_VALUE(l_trrd_s_in_ps)
+ .set_DIMM_TARGET(l_dimm)
+ .set_FUNCTION(TRRD_S),
+ "%s Error calculating tRRD_S (%d). Less than or equal to 0",
+ spd::c_str(l_dimm),
+ l_trrd_s_in_ps);
+
+ FAPI_DBG("%s TRRD_S in ps is %d", spd::c_str(l_dimm), l_trrd_s_in_ps);
+
+ FAPI_TRY( spd::calc_nck(l_trrd_s_in_ps, l_tck_in_ps, spd::INVERSE_DDR4_CORRECTION_FACTOR, l_trrd_s_in_nck),
+ "%s Error in calculating l_tRRD_S, with value of l_trrd_s_in_ps: %d",
+ spd::c_str(l_dimm),
+ l_trrd_s_in_nck);
+ }
+
+ FAPI_TRY( attr::get_dram_width(l_dimm, l_dram_width) );
+ FAPI_TRY( trrd_s( l_dimm, l_dram_width, l_freq, l_jedec_trrd) );
+
+ // Taking the worst case between the required minimum JEDEC value and the proposed value from SPD
+ if (l_jedec_trrd != l_trrd_s_in_nck)
+ {
+ FAPI_INF("%s TRRD_S from JEDEC (%d) and from SPD (%d) don't match. Choosing worst case. dram width %d, freq %d",
+ spd::c_str(l_dimm),
+ l_jedec_trrd,
+ l_trrd_s_in_nck,
+ l_dram_width,
+ l_freq);
+
+ l_trrd_s_in_nck = std::max( l_jedec_trrd, l_trrd_s_in_nck);
+ }
+
+ FAPI_INF("%s SDRAM width: %d, tRRD_S (nck): %d",
+ spd::c_str(l_dimm), l_dram_width, l_trrd_s_in_nck);
+
+ o_setting = l_trrd_s_in_nck;
+ FAPI_DBG("%s DRAM TRRD_S %d", spd::c_str(l_dimm), o_setting);
+
+ fapi_try_exit:
+ return fapi2::current_err;
+ }
+};
+
+///
+/// @brief Traits for attrEngineTraits
+/// @class attrEngineTraits
+/// @note attrEngineTraits, DRAM_TRRD_L specialization
+///
+template<>
+struct attrEngineTraits<attr_eff_engine_fields, DRAM_TRRD_L>
+{
+ using attr_type = fapi2::ATTR_MEM_EFF_DRAM_TRRD_L_Type;
+ using attr_integral_type = std::remove_all_extents<attr_type>::type;
+ static constexpr fapi2::TargetType TARGET_TYPE = fapi2::ATTR_MEM_EFF_DRAM_TRRD_L_TargetType;
+ static constexpr generic_ffdc_codes FFDC_CODE = SET_DRAM_TRRD_L;
+
+ ///
+ /// @brief attribute getter
+ /// @param[in] i_target the attr target
+ /// @param[out] o_setting array to populate
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode get_attr(const fapi2::Target<TARGET_TYPE>& i_target,
+ attr_type& o_setting)
+ {
+ return mss::attr::get_dram_trrd_l(i_target, o_setting);
+ }
+
+ ///
+ /// @brief attribute setter
+ /// @param[in] i_target the attr target
+ /// @param[in] i_setting array to set
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode set_attr(const fapi2::Target<TARGET_TYPE>& i_target,
+ attr_type& i_setting)
+ {
+ return mss::attr::set_dram_trrd_l(i_target, i_setting);
+ }
+
+ ///
+ /// @brief Computes setting for attribute
+ /// @param[in] i_spd_data SPD data
+ /// @param[out] o_setting value we want to set attr with
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode get_value_to_set(const spd::facade& i_spd_data,
+ attr_integral_type& o_setting)
+ {
+ const auto& l_dimm = i_spd_data.get_dimm_target();
+ int64_t l_tck_in_ps = 0;
+ uint64_t l_freq = 0;
+ uint64_t l_trrd_l_in_nck = 0;
+ int64_t l_trrd_l_in_ps = 0;
+ uint64_t l_jedec_trrd = 0;
+ uint8_t l_dram_width = 0;
+
+ FAPI_TRY( attr::get_freq(mss::find_target<fapi2::TARGET_TYPE_MEM_PORT>(l_dimm), l_freq) );
+ FAPI_TRY( freq_to_ps(l_freq, l_tck_in_ps),
+ "%s Failed to calculate clock period (tCK)", spd::c_str(l_dimm) );
+
+ // Calculate tRRD_L
+ {
+ int64_t l_trrd_l_mtb = 0;
+ int64_t l_trrd_l_ftb = 0;
+ int64_t l_ftb = 0;
+ int64_t l_mtb = 0;
+
+ FAPI_TRY( spd::get_timebases(i_spd_data, l_mtb, l_ftb) );
+
+ FAPI_TRY( i_spd_data.min_trrd_l(l_trrd_l_mtb),
+ "%s Failed min_trrd_l()", spd::c_str(l_dimm) );
+
+ FAPI_TRY( i_spd_data.fine_offset_min_trrd_l(l_trrd_l_ftb),
+ "%s Failed fine_offset_min_trrd_l()", spd::c_str(l_dimm) );
+
+ FAPI_INF("%s medium timebase (ps): %ld, fine timebase (ps): %ld, trrd_l (MTB): %ld",
+ spd::c_str(l_dimm), l_mtb, l_ftb, l_trrd_l_mtb);
+
+ l_trrd_l_in_ps = spd::calc_timing_from_timebase(l_trrd_l_mtb, l_mtb, l_trrd_l_ftb, l_ftb);
+
+ FAPI_ASSERT( l_trrd_l_in_ps >= 0,
+ fapi2::MSS_INVALID_TIMING_VALUE()
+ .set_VALUE(l_trrd_l_in_ps)
+ .set_DIMM_TARGET(l_dimm)
+ .set_FUNCTION(TRRD_L),
+ "%s Error calculating tRRD_L (%d). Less than or equal to 0",
+ spd::c_str(l_dimm),
+ l_trrd_l_in_ps);
+
+ FAPI_DBG("%s TRRD_L in ps is %d", spd::c_str(l_dimm), l_trrd_l_in_ps);
+
+ FAPI_TRY( spd::calc_nck(l_trrd_l_in_ps, l_tck_in_ps, spd::INVERSE_DDR4_CORRECTION_FACTOR, l_trrd_l_in_nck),
+ "%s Error in calculating l_tRRD_L, with value of l_trrd_l_in_ps: %d",
+ spd::c_str(l_dimm),
+ l_trrd_l_in_nck);
+ }
+
+ FAPI_TRY( attr::get_dram_width(l_dimm, l_dram_width) );
+ FAPI_TRY( trrd_l( l_dimm, l_dram_width, l_freq, l_jedec_trrd) );
+
+ // Taking the worst case between the required minimum JEDEC value and the proposed value from SPD
+ if (l_jedec_trrd != l_trrd_l_in_nck)
+ {
+ FAPI_INF("%s TRRD_L from JEDEC (%d) and from SPD (%d) don't match. Choosing worst case. dram width %d, freq %d",
+ spd::c_str(l_dimm),
+ l_jedec_trrd,
+ l_trrd_l_in_nck,
+ l_dram_width,
+ l_freq);
+
+ l_trrd_l_in_nck = std::max( l_jedec_trrd, l_trrd_l_in_nck);
+ }
+
+ FAPI_INF("%s SDRAM width: %d, tRRD_L (nck): %d",
+ spd::c_str(l_dimm), l_dram_width, l_trrd_l_in_nck);
+
+ o_setting = l_trrd_l_in_nck;
+ FAPI_DBG("%s DRAM TRRD_L %d", spd::c_str(l_dimm), o_setting);
+
+ fapi_try_exit:
+ return fapi2::current_err;
+ }
+};
+
+///
+/// @brief Traits for attrEngineTraits
+/// @class attrEngineTraits
+/// @note attrEngineTraits, DRAM_TRFC specialization
+///
+template<>
+struct attrEngineTraits<attr_eff_engine_fields, DRAM_TRFC>
+{
+ using attr_type = fapi2::ATTR_MEM_EFF_DRAM_TRFC_Type;
+ using attr_integral_type = std::remove_all_extents<attr_type>::type;
+ static constexpr fapi2::TargetType TARGET_TYPE = fapi2::ATTR_MEM_EFF_DRAM_TRFC_TargetType;
+ static constexpr generic_ffdc_codes FFDC_CODE = SET_DRAM_TRFC;
+
+ ///
+ /// @brief attribute getter
+ /// @param[in] i_target the attr target
+ /// @param[out] o_setting array to populate
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode get_attr(const fapi2::Target<TARGET_TYPE>& i_target,
+ attr_type& o_setting)
+ {
+ return mss::attr::get_dram_trfc(i_target, o_setting);
+ }
+
+ ///
+ /// @brief attribute setter
+ /// @param[in] i_target the attr target
+ /// @param[in] i_setting array to set
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode set_attr(const fapi2::Target<TARGET_TYPE>& i_target,
+ attr_type& i_setting)
+ {
+ return mss::attr::set_dram_trfc(i_target, i_setting);
+ }
+
+ ///
+ /// @brief Computes setting for attribute
+ /// @param[in] i_spd_data SPD data
+ /// @param[out] o_setting value we want to set attr with
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode get_value_to_set(const spd::facade& i_spd_data,
+ attr_integral_type& o_setting)
+ {
+ const auto& l_dimm = i_spd_data.get_dimm_target();
+ int64_t l_tck_in_ps = 0;
+ uint64_t l_freq = 0;
+ uint8_t l_refresh_mode = 0;
+ int64_t l_trfc_mtb = 0;
+ int64_t l_trfc_in_ps = 0;
+
+ FAPI_TRY( attr::get_freq(mss::find_target<fapi2::TARGET_TYPE_MEM_PORT>(l_dimm), l_freq) );
+ FAPI_TRY( freq_to_ps(l_freq, l_tck_in_ps),
+ "%s Failed to calculate clock period (tCK)", spd::c_str(l_dimm) );
+
+ FAPI_TRY( mss::attr::get_mrw_fine_refresh_mode(l_refresh_mode) );
+
+ // Selects appropriate tRFC based on fine refresh mode
+ switch(l_refresh_mode)
+ {
+ case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_NORMAL:
+ FAPI_TRY( i_spd_data.min_trfc1(l_trfc_mtb),
+ "%s Failed to decode SPD for tRFC1", spd::c_str(l_dimm) );
+ break;
+
+ case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_FIXED_2X:
+ case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_FLY_2X:
+ FAPI_TRY( i_spd_data.min_trfc2(l_trfc_mtb),
+ "%s Failed to decode SPD for tRFC2", spd::c_str(l_dimm) );
+ break;
+
+ case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_FIXED_4X:
+ case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_FLY_4X:
+ FAPI_TRY( i_spd_data.min_trfc4(l_trfc_mtb),
+ "%s Failed to decode SPD for tRFC4", spd::c_str(l_dimm) );
+ break;
+
+ default:
+ // Fine Refresh Mode 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_FINE_REFRESH_MODE().
+ set_FINE_REF_MODE(l_refresh_mode),
+ "%s Incorrect Fine Refresh Mode received: %d ",
+ spd::c_str(l_dimm),
+ l_refresh_mode);
+ break;
+ }// switch
+
+ // Calculate trfc (in ps)
+ {
+ int64_t l_trfc_ftb = 0;
+ int64_t l_ftb = 0;
+ int64_t l_mtb = 0;
+
+ FAPI_TRY( spd::get_timebases(i_spd_data, l_mtb, l_ftb) );
+
+ FAPI_INF( "%s medium timebase (ps): %ld, fine timebase (ps): %ld, tRFC (MTB): %ld, tRFC(FTB): %ld",
+ spd::c_str(l_dimm), l_mtb, l_ftb, l_trfc_mtb, l_trfc_ftb );
+
+ l_trfc_in_ps = spd::calc_timing_from_timebase(l_trfc_mtb, l_mtb, l_trfc_ftb, l_ftb);
+ }
+
+ {
+ // Calculate refresh cycle time in nCK & set attribute
+
+ uint16_t l_trfc_in_nck = 0;
+
+ // Calculate nck
+ FAPI_TRY( spd::calc_nck(l_trfc_in_ps, l_tck_in_ps, spd::INVERSE_DDR4_CORRECTION_FACTOR, l_trfc_in_nck),
+ "%s Error in calculating l_tRFC, with value of l_trfc_in_ps: %d", spd::c_str(l_dimm), l_trfc_in_ps);
+
+ FAPI_INF("%s tCK (ps): %d, tRFC (ps): %d, tRFC (nck): %d",
+ spd::c_str(l_dimm), l_tck_in_ps, l_trfc_in_ps, l_trfc_in_nck);
+
+ o_setting = l_trfc_in_nck;
+ FAPI_DBG("%s DRAM TRFC %d", spd::c_str(l_dimm), o_setting);
+ }
+
+ fapi_try_exit:
+ return fapi2::current_err;
+ }
+};
+
+///
+/// @brief Traits for attrEngineTraits
+/// @class attrEngineTraits
+/// @note attrEngineTraits, DRAM_TRFC_DLR specialization
+///
+template<>
+struct attrEngineTraits<attr_eff_engine_fields, DRAM_TRFC_DLR>
+{
+ using attr_type = fapi2::ATTR_MEM_EFF_DRAM_TRFC_DLR_Type;
+ using attr_integral_type = std::remove_all_extents<attr_type>::type;
+ static constexpr fapi2::TargetType TARGET_TYPE = fapi2::ATTR_MEM_EFF_DRAM_TRFC_DLR_TargetType;
+ static constexpr generic_ffdc_codes FFDC_CODE = SET_DRAM_TRFC_DLR;
+
+ ///
+ /// @brief attribute getter
+ /// @param[in] i_target the attr target
+ /// @param[out] o_setting array to populate
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode get_attr(const fapi2::Target<TARGET_TYPE>& i_target,
+ attr_type& o_setting)
+ {
+ return mss::attr::get_dram_trfc_dlr(i_target, o_setting);
+ }
+
+ ///
+ /// @brief attribute setter
+ /// @param[in] i_target the attr target
+ /// @param[in] i_setting array to set
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode set_attr(const fapi2::Target<TARGET_TYPE>& i_target,
+ attr_type& i_setting)
+ {
+ return mss::attr::set_dram_trfc_dlr(i_target, i_setting);
+ }
+
+ ///
+ /// @brief Computes setting for attribute
+ /// @param[in] i_spd_data SPD data
+ /// @param[out] o_setting value we want to set attr with
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode get_value_to_set(const spd::facade& i_spd_data,
+ attr_integral_type& o_setting)
+ {
+ const auto& l_dimm = i_spd_data.get_dimm_target();
+ int64_t l_tck_in_ps = 0;
+ uint64_t l_freq = 0;
+ uint8_t l_refresh_mode = 0;
+ uint8_t l_dram_density = 0;
+ uint64_t l_trfc_dlr_in_ps = 0;
+ uint8_t l_trfc_dlr_in_nck = 0;
+
+ FAPI_TRY( attr::get_freq(mss::find_target<fapi2::TARGET_TYPE_MEM_PORT>(l_dimm), l_freq) );
+ FAPI_TRY( freq_to_ps(l_freq, l_tck_in_ps),
+ "%s Failed to calculate clock period (tCK)", spd::c_str(l_dimm) );
+
+ FAPI_TRY( mss::attr::get_mrw_fine_refresh_mode(l_refresh_mode) );
+ FAPI_TRY( mss::attr::get_dram_density(l_dimm, l_dram_density) );
+
+ // Calculate refresh cycle time in ps
+ FAPI_TRY( calc_trfc_dlr(l_dimm, l_refresh_mode, l_dram_density, l_trfc_dlr_in_ps),
+ "%s Failed calc_trfc_dlr()", spd::c_str(l_dimm) );
+
+ // Calculate refresh cycle time in nck
+ FAPI_TRY( spd::calc_nck(l_trfc_dlr_in_ps, static_cast<uint64_t>(l_tck_in_ps), spd::INVERSE_DDR4_CORRECTION_FACTOR,
+ l_trfc_dlr_in_nck));
+
+ FAPI_INF("%s tCK (ps): %d, tRFC_DLR (ps): %d, tRFC_DLR (nck): %d",
+ spd::c_str(l_dimm), l_tck_in_ps, l_trfc_dlr_in_ps, l_trfc_dlr_in_nck);
+
+ o_setting = l_trfc_dlr_in_nck;
+ FAPI_DBG("%s DRAM TRFC_DLR %d", spd::c_str(l_dimm), o_setting);
+
+ fapi_try_exit:
+ return fapi2::current_err;
+ }
+};
+
}//mss
#endif
OpenPOWER on IntegriCloud