summaryrefslogtreecommitdiffstats
path: root/src/import/generic/memory
diff options
context:
space:
mode:
authorLouis Stermole <stermole@us.ibm.com>2019-06-07 15:44:22 -0400
committerChristian R. Geddes <crgeddes@us.ibm.com>2019-07-09 10:18:24 -0500
commitd9bbcfabbc2f041ba85095ac70dc27c37cb87755 (patch)
tree7d1270c8dc0939956034a7ab1f6cddb45a33ac72 /src/import/generic/memory
parent491995a6a3ed6062169c2818c89db7a85da9e448 (diff)
downloadtalos-hostboot-d9bbcfabbc2f041ba85095ac70dc27c37cb87755.tar.gz
talos-hostboot-d9bbcfabbc2f041ba85095ac70dc27c37cb87755.zip
Add missing timing attrs to p9a_eff_config
Change-Id: I0270bec76fa1146c3c74cc125f838f5602b8a5b8 Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/78564 Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com> Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com> Tested-by: Hostboot CI <hostboot-ci+hostboot@us.ibm.com> Tested-by: HWSV CI <hwsv-ci+hostboot@us.ibm.com> Reviewed-by: STEPHEN GLANCY <sglancy@us.ibm.com> Reviewed-by: Mark Pizzutillo <mark.pizzutillo@ibm.com> Reviewed-by: Jennifer A Stofer <stofer@us.ibm.com> Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/78576 Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com> Tested-by: Jenkins OP HW <op-hw-jenkins+hostboot@us.ibm.com> Reviewed-by: Christian R. Geddes <crgeddes@us.ibm.com>
Diffstat (limited to 'src/import/generic/memory')
-rw-r--r--src/import/generic/memory/lib/data_engine/attr_engine_traits.H1550
-rw-r--r--src/import/generic/memory/lib/data_engine/data_engine_traits_def.H29
-rw-r--r--src/import/generic/memory/lib/utils/conversions.H2
-rw-r--r--src/import/generic/memory/lib/utils/dimm/mss_timing.H888
-rw-r--r--src/import/generic/memory/lib/utils/shared/mss_generic_consts.H15
5 files changed, 2473 insertions, 11 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
diff --git a/src/import/generic/memory/lib/data_engine/data_engine_traits_def.H b/src/import/generic/memory/lib/data_engine/data_engine_traits_def.H
index 911821b5f..702e0db9a 100644
--- a/src/import/generic/memory/lib/data_engine/data_engine_traits_def.H
+++ b/src/import/generic/memory/lib/data_engine/data_engine_traits_def.H
@@ -93,13 +93,28 @@ enum attr_eff_engine_fields
ATTR_EFF_BASE_CASE = 0,
// Attrs to set
- DRAM_WIDTH = 1,
- PRIM_BUS_WIDTH = 2,
- DRAM_DENSITY = 3,
- PRIMARY_DIE_COUNT = 4,
- PRIM_STACK_TYPE = 5,
- COLUMN_ADDR_BITS = 6,
- ROW_ADDR_BITS = 7,
+ DRAM_CWL = 1,
+ DRAM_TREFI = 2,
+ DRAM_TCCD_L = 3,
+ DRAM_TWTR_L = 4,
+ DRAM_TWTR_S = 5,
+ DRAM_TFAW = 6,
+ DRAM_TRCD = 7,
+ DRAM_TRP = 8,
+ DRAM_TRAS = 9,
+ DRAM_TWR = 10,
+ DRAM_TRTP = 11,
+ DRAM_TRRD_S = 12,
+ DRAM_TRRD_L = 13,
+ DRAM_TRFC = 14,
+ DRAM_TRFC_DLR = 15,
+ DRAM_WIDTH = 16,
+ PRIM_BUS_WIDTH = 17,
+ DRAM_DENSITY = 18,
+ PRIMARY_DIE_COUNT = 19,
+ PRIM_STACK_TYPE = 20,
+ COLUMN_ADDR_BITS = 21,
+ ROW_ADDR_BITS = 22,
// Dispatcher set to last enum value
ATTR_EFF_DISPATCHER = ROW_ADDR_BITS,
diff --git a/src/import/generic/memory/lib/utils/conversions.H b/src/import/generic/memory/lib/utils/conversions.H
index 5981fe7b5..dc4290ea5 100644
--- a/src/import/generic/memory/lib/utils/conversions.H
+++ b/src/import/generic/memory/lib/utils/conversions.H
@@ -101,7 +101,7 @@ static const std::vector<std::pair<uint64_t, uint64_t>> FREQ_TO_CLOCK_PERIOD =
{DIMM_SPEED_4400, 454}, // DDR5
{DIMM_SPEED_4800, 416}, // DDR5
};
-}
+} // ns dram_freq
///
/// @brief Return the number of picoseconds
diff --git a/src/import/generic/memory/lib/utils/dimm/mss_timing.H b/src/import/generic/memory/lib/utils/dimm/mss_timing.H
index 54fac6474..aa1915e3d 100644
--- a/src/import/generic/memory/lib/utils/dimm/mss_timing.H
+++ b/src/import/generic/memory/lib/utils/dimm/mss_timing.H
@@ -22,3 +22,891 @@
/* permissions and limitations under the License. */
/* */
/* IBM_PROLOG_END_TAG */
+
+///
+/// @file mss_timing.H
+/// @brief Determine effective config for mss settings
+///
+// *HWP HWP Owner: Louis Stermole <stermole@us.ibm.com>
+// *HWP FW Owner: Stephen Glancy <sglancy@us.ibm.com>
+// *HWP Team: Memory
+// *HWP Level: 3
+// *HWP Consumed by: HB:FSP
+
+#ifndef _MSS_GEN_TIMING_H_
+#define _MSS_GEN_TIMING_H_
+
+#include <cstdint>
+#include <fapi2.H>
+#include <generic/memory/lib/mss_generic_attribute_getters.H>
+#include <generic/memory/lib/utils/find.H>
+#include <generic/memory/lib/utils/shared/mss_generic_consts.H>
+#include <generic/memory/lib/utils/conversions.H>
+#include <generic/memory/lib/spd/spd_utils.H>
+
+namespace mss
+{
+
+///
+/// @brief Enums for ffdc error callout so we know which function had the error
+///
+enum timing_ffdc_codes
+{
+ TRAS = 0,
+ TFAW_HALF_KB_PAGE_HELPER = 1,
+ TFAW_ONE_KB_PAGE_HELPER = 2,
+ TFAW_TW_KB_PAGE_HELPER = 3,
+ TFAW_SLR_X4_HELPER = 4,
+ TFAW_SLR_X8_HELPER = 5,
+ TRRD_S_SLR = 6,
+ TRRD_L_SLR = 7,
+ TRRD_L_HALF_AND_1KB_PAGE_HELPER = 8,
+ TRRD_S_HALF_AND_1KB_PAGE_HELPER = 9,
+ TRRD_S_2KB_PAGE_HELPER = 10,
+ TRRD_S = 11,
+ TRRD_L = 12,
+ TFAW = 13,
+ TDLLK = 14,
+};
+
+enum refresh_rate : uint8_t
+{
+ REF1X = 1, ///< Refresh rate 1X
+ REF2X = 2, ///< Refresh rate 2X
+ REF4X = 4, ///< Refresh rate 4X
+};
+
+namespace spd
+{
+
+///
+/// @brief Returns clock cycles form picoseconds based on speed bin
+/// Uses SPD rounding algorithm for DDR4
+/// @tparam OT the output type, derrived from the parameters
+/// @param[in] i_freq frequency of the DIMM
+/// @param[in] timing_in_ps timing parameter in ps
+/// @return the clock cycles of timing parameter (provided in ps)
+/// @note Uses DDR4 SPD Contents Rounding Algorithm
+/// @note Item 2220.46
+///
+template<typename OT>
+inline OT ps_to_nck( const uint64_t i_freq, const OT& i_timing_in_ps)
+{
+ OT l_tck_in_ps = 0;
+ OT l_temp_nck = 0;
+
+ // No time if MT/s is 0 (well, infinite really but shut up)
+ if (i_freq == 0)
+ {
+ return 0;
+ }
+
+ FAPI_TRY( freq_to_ps(i_freq, l_tck_in_ps),
+ "Failed freq() accessor" );
+ FAPI_TRY( calc_nck(i_timing_in_ps, l_tck_in_ps, spd::INVERSE_DDR4_CORRECTION_FACTOR, l_temp_nck),
+ "Failed calc_nck()" );
+
+ return l_temp_nck;
+
+fapi_try_exit:
+ // We simply can't work if we get an unsupported value that can't be converted to a valid tCK (clock period)
+ // ...so this should be ok
+ FAPI_ERR("Obtained an invalid MSS_FREQ (%d), or overflow occurred - stopping", i_freq);
+ fapi2::Assert(false);
+
+ // Keeps compiler happy
+ return 0;
+}
+
+///
+/// @brief Returns clock cycles from nanoseconds
+/// Uses SPD rounding algorithm for DDR4
+/// @tparam OT the output type, derrived from the parameters
+/// @param[in] i_freq frequency of the DIMM
+/// @param[out] o_value_nck the end calculation in nck
+/// @return the clock cycles of timing parameter (provided in ps)
+/// @note Uses DDR4 SPD Contents Rounding Algorithm
+/// @note Item 2220.46
+///
+template<typename OT>
+inline OT ns_to_nck( const uint64_t i_freq, const OT& i_timing_in_ns)
+{
+ return ps_to_nck(i_freq, i_timing_in_ns * CONVERT_PS_IN_A_NS);
+}
+
+}// spd
+
+///
+/// @brief Calculates refresh interval time
+/// @param[in] i_mode fine refresh rate mode
+/// @param[in] i_refresh_request_rate refresh rate
+/// @param[out] o_value timing val in ps
+/// @return fapi2::ReturnCode
+///
+inline fapi2::ReturnCode calc_trefi( const refresh_rate i_mode,
+ const uint8_t i_refresh_request_rate,
+ uint64_t& o_timing )
+{
+ // Proposed DDR4 Full spec update(79-4B)
+ // Item No. 1716.78C
+ // pg.46
+ // Table 24 - tREFI and tRFC parameters (in ps)
+ constexpr uint64_t TREFI_BASE = 7800000;
+
+ uint64_t l_refresh_request = 0;
+ constexpr double TEN_PERCENT_FASTER = 0.90;
+
+ switch(i_refresh_request_rate)
+ {
+ case fapi2::ENUM_ATTR_MSS_MRW_REFRESH_RATE_REQUEST_SINGLE:
+ l_refresh_request = TREFI_BASE;
+ break;
+
+ case fapi2::ENUM_ATTR_MSS_MRW_REFRESH_RATE_REQUEST_DOUBLE:
+ // We are truncating but there is no remainder with TREFI_BASE, so we are okay
+ l_refresh_request = TREFI_BASE / 2;
+ break;
+
+ case fapi2::ENUM_ATTR_MSS_MRW_REFRESH_RATE_REQUEST_SINGLE_10_PERCENT_FASTER:
+ // We are truncating but there is no remainder with TREFI_BASE, so we are okay
+ // 10% faster so 100% - 10% = 90%
+ l_refresh_request = TREFI_BASE * TEN_PERCENT_FASTER;
+ break;
+
+ case fapi2::ENUM_ATTR_MSS_MRW_REFRESH_RATE_REQUEST_DOUBLE_10_PERCENT_FASTER:
+ // We are truncating but there is no remainder with TREFI_BASE, so we are okay
+ // 10% faster so 100% - 10% = 90%
+ l_refresh_request = (TREFI_BASE / 2) * TEN_PERCENT_FASTER;
+ break;
+
+ default:
+ // Will catch incorrect MRW value set
+ FAPI_ASSERT(false,
+ fapi2::MSS_INVALID_REFRESH_RATE_REQUEST().set_REFRESH_RATE_REQUEST(i_refresh_request_rate),
+ "Incorrect refresh request rate received: %d ", i_refresh_request_rate);
+ break;
+ }
+
+ o_timing = (l_refresh_request / i_mode);
+
+ FAPI_INF( "tREFI (ps): %d, refresh request (ps): %d, tREFI_base (ps): %d, REF%dX",
+ o_timing, l_refresh_request, TREFI_BASE, i_mode );
+
+ return fapi2::FAPI2_RC_SUCCESS;
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+/// @brief Calculates Minimum Refresh Recovery Delay Time (different logical rank)
+/// @param[in] i_mode fine refresh rate mode
+/// @param[in] i_density SDRAM density
+/// @param[out] o_trfc_in_ps timing val in ps
+/// @return fapi2::FAPI2_RC_SUCCESS iff okay
+///
+inline fapi2::ReturnCode calc_trfc_dlr(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ const uint8_t i_refresh_mode,
+ const uint8_t i_density,
+ uint64_t& o_trfc_in_ps)
+{
+ // Proposed DDR4 3DS Addendum
+ // Item No. 1727.58A
+ // pg. 69 - 71
+ // Table 42 - Refresh parameters by logical rank density
+ static const std::vector<std::pair<uint8_t, uint64_t> > TRFC_DLR1 =
+ {
+ // { density in GBs, tRFC4(min) in picoseconds }
+ {4, 90000},
+ {8, 120000},
+ {16, 185000},
+ };
+
+ // Proposed DDR4 3DS Addendum
+ // Item No. 1727.58A
+ // pg. 69 - 71
+ // Table 42 - Refresh parameters by logical rank density
+ static const std::vector<std::pair<uint8_t, uint64_t> > TRFC_DLR2 =
+ {
+ // { density in GBs, tRFC4(min) in picoseconds }
+ {4, 55000},
+ {8, 90000},
+ {16, 120000},
+ };
+
+ // Proposed DDR4 3DS Addendum
+ // Item No. 1727.58A
+ // pg. 69 - 71
+ // Table 42 - Refresh parameters by logical rank density
+ static const std::vector<std::pair<uint8_t, uint64_t> > TRFC_DLR4 =
+ {
+ // { density in GBs, tRFC4(min) in picoseconds }
+ {4, 40000},
+ {8, 55000},
+ {16, 90000},
+ };
+
+ bool l_is_val_found = 0;
+
+ // Selects appropriate tRFC based on fine refresh mode
+ switch(i_refresh_mode)
+ {
+ case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_NORMAL:
+ l_is_val_found = find_value_from_key(TRFC_DLR1, i_density, o_trfc_in_ps);
+ break;
+
+ case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_FIXED_2X:
+ case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_FLY_2X:
+ l_is_val_found = find_value_from_key(TRFC_DLR2, i_density, o_trfc_in_ps);
+ break;
+
+ case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_FIXED_4X:
+ case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_FLY_4X:
+ l_is_val_found = find_value_from_key(TRFC_DLR4, i_density, o_trfc_in_ps);
+ 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()
+ .set_REFRESH_MODE(i_refresh_mode),
+ "Incorrect Fine Refresh Mode received: %d ",
+ i_refresh_mode);
+ break;
+ }// switch
+
+ FAPI_ASSERT( l_is_val_found,
+ fapi2::MSS_FAILED_TO_FIND_TRFC()
+ .set_SDRAM_DENSITY(i_density)
+ .set_REFRESH_MODE(i_refresh_mode)
+ .set_DIMM_TARGET(i_target),
+ "%s: Unable to find tRFC (ps) from map with SDRAM density key %d with %d refresh mode",
+ mss::c_str(i_target),
+ i_density,
+ i_refresh_mode);
+
+ // Again, FAPI_ASSERT doesn't set current_err to good, only to bad
+ return fapi2::FAPI2_RC_SUCCESS;
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief tRTP *in ps*
+/// @return constexpr value of RTP = 7500 ps
+///
+constexpr uint64_t trtp()
+{
+ // Per JEDEC spec, defaults to 7500 ps for all frequencies.
+ // (technically max of 7.5 ns or 4 nclk, which is always 7.5ns for DDR4)
+ return 7500;
+}
+
+///
+/// @brief Return the minimum allowable tRAS in picoseconds
+/// @param[in] i_target the fapi2 target
+/// @param[in] i_freq freq for the DIMM
+/// @return value in picoseconds
+///
+inline uint64_t tras(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ const uint64_t i_freq)
+{
+ uint64_t l_tras = 0;
+
+ switch(i_freq)
+ {
+ case 1866:
+ l_tras = 34000;
+ break;
+
+ case 2133:
+ l_tras = 33000;
+ break;
+
+ case 2400:
+ case 2666:
+ case 2933:
+ case 3200:
+ l_tras = 32000;
+ break;
+
+ default:
+ FAPI_ASSERT( false,
+ fapi2::MSS_INVALID_FREQ_PASSED_IN()
+ .set_FREQ(i_freq)
+ .set_FUNCTION(TRAS)
+ .set_DIMM_TARGET(i_target),
+ "%s Invalid frequency %lu",
+ mss::c_str(i_target),
+ i_freq);
+ }
+
+ return l_tras;
+
+fapi_try_exit:
+
+ // We simply can't work if we can't get the frequency or
+ // if we get an unsupported value that can't be converted to a valid tCK (clock period)
+ // ...so this should be ok
+ FAPI_ERR("Obtained an invalid MSS_FREQ (%d) - stopping", i_freq);
+ fapi2::Assert(false);
+
+ // Keeps compiler happy
+ return 0;
+}
+
+///
+/// @brief Helper function to find tFAW based speed (MT/s) for 1/2 KB page
+/// @tparam T the fapi2::TargetType of a type from which we can get MT/s
+/// @param[in] i_target the fapi2 target
+/// @param[in] i_freq the DRAM frequency
+/// @param[out] o_output timing in clocks (nck)
+/// @return FAPI2_RC_SUCCESS iff okay
+/// @note this is only for non-3DS DIMM
+///
+template< fapi2::TargetType T >
+static fapi2::ReturnCode tfaw_half_kb_page_helper(const fapi2::Target<T>& i_target,
+ const uint64_t i_freq,
+ uint64_t& o_output)
+{
+ // Values derived from DDR4 Spec (79-4A)
+ // 13.3 Timing Parameters by Speed Grade
+ // Table 132. Pg 240
+ fapi2::current_err = fapi2::FAPI2_RC_SUCCESS;
+
+ // It could have been more "efficient" to hand-calculate the answer and
+ // use compile time constants to return the answer. To avoid magic
+ // numbers and to align (more closely) with the DDR4 JEDEC spec,
+ // we let the std library do the work for us for maintainability.
+ // Could have used compile-time constants to denote the numbers below
+ // but they are "random" and vary.
+ switch(i_freq)
+ {
+ // static_cast is needed for template deduction of std::max API
+ case 1866:
+ o_output = std::max( 16, spd::ps_to_nck(i_freq, 17000) );
+ break;
+
+ case 2133:
+ o_output = std::max( 16, spd::ps_to_nck(i_freq, 15000) );
+ break;
+
+ case 2400:
+ o_output = std::max( 16, spd::ps_to_nck(i_freq, 13000) );
+ break;
+
+ case 2666:
+ o_output = std::max( 16, spd::ps_to_nck(i_freq, 12000) );
+ break;
+
+ case 2933:
+ o_output = std::max( 16, spd::ps_to_nck(i_freq, 10875) );
+ break;
+
+ case 3200:
+ o_output = std::max( 16, spd::ps_to_nck(i_freq, 10000) );
+ break;
+
+ default:
+ FAPI_ASSERT( false,
+ fapi2::MSS_INVALID_FREQ_PASSED_IN()
+ .set_FREQ(i_freq)
+ .set_FUNCTION(TFAW_HALF_KB_PAGE_HELPER)
+ .set_DIMM_TARGET(i_target),
+ "%s Invalid frequency %lu",
+ mss::c_str(i_target),
+ i_freq);
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Helper function to find tFAW based speed (MT/s) for 1KB page
+/// @tparam T the fapi2::TargetType of a type from which we can get MT/s
+/// @param[in] i_target the fapi2 target
+/// @param[in] i_freq the DRAM frequency
+/// @param[out] o_output timing in clocks (nck)
+/// @return FAPI2_RC_SUCCESS iff okay
+/// @note this is only for non-3DS DIMM
+///
+template< fapi2::TargetType T >
+static fapi2::ReturnCode tfaw_1kb_page_helper(const fapi2::Target<T>& i_target,
+ const uint64_t i_freq,
+ uint64_t& o_output)
+{
+ // Values derived from DDR4 Spec (79-4A)
+ // 13.3 Timing Parameters by Speed Grade
+ // Table 132. Pg 240
+ fapi2::current_err = fapi2::FAPI2_RC_SUCCESS;
+
+ // It could have been more "efficient" to hand-calculate the answer and
+ // use compile time constants to return the answer. To avoid magic
+ // numbers and to align (more closely) with the DDR4 JEDEC spec,
+ // we let the std library do the work for us for maintainability (and ease of debug?).
+ // Could have used compile-time constants to denote the numbers below
+ // but they are "random" and vary.
+ switch(i_freq)
+ {
+ case 1866:
+ o_output = std::max( 20, spd::ns_to_nck(i_freq, 23) );
+ break;
+
+ case 2133:
+ case 2400:
+ case 2666:
+ case 2933:
+ case 3200:
+ o_output = std::max( 20, spd::ns_to_nck(i_freq, 21) );
+ break;
+
+ default:
+ FAPI_ASSERT( false,
+ fapi2::MSS_INVALID_FREQ_PASSED_IN()
+ .set_FREQ(i_freq)
+ .set_FUNCTION(TFAW_ONE_KB_PAGE_HELPER)
+ .set_DIMM_TARGET(i_target),
+ "%s Invalid frequency %lu",
+ mss::c_str(i_target),
+ i_freq);
+ break;
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Helper function to find tFAW based speed (MT/s) for 2KB page
+/// @tparam T the fapi2::TargetType of a type from which we can get MT/s
+/// @param[in] i_target the fapi2 target
+/// @param[in] i_freq the DRAM frequency
+/// @param[out] o_output timing in clocks (nck)
+/// @return FAPI2_RC_SUCCESS iff okay
+/// @note this is only for non-3DS DIMM
+///
+template< fapi2::TargetType T >
+static fapi2::ReturnCode tfaw_2kb_page_helper(const fapi2::Target<T>& i_target,
+ const uint64_t i_freq,
+ uint64_t& o_output)
+{
+
+ // Values derived from DDR4 Spec (79-4A)
+ // 13.3 Timing Parameters by Speed Grade
+ // Table 132. Pg 240
+ fapi2::current_err = fapi2::FAPI2_RC_SUCCESS;
+
+ // It could have been more "efficient" to hand-calculate the answer and
+ // use compile time constants to return the answer. To avoid magic
+ // numbers and to align (more closely) with the DDR4 JEDEC spec,
+ // we let the std library do the work for us for maintainability.
+ // Could have used compile-time constants to denote the numbers below
+ // but they are "random" and vary.
+ switch(i_freq)
+ {
+ case 1866:
+ case 2133:
+ case 2400:
+ case 2666:
+ case 2933:
+ case 3200:
+ o_output = std::max( 28, spd::ns_to_nck(i_freq, 30) );
+ break;
+
+ default:
+ FAPI_ASSERT( false,
+ fapi2::MSS_INVALID_FREQ_PASSED_IN()
+ .set_FREQ(i_freq)
+ .set_FUNCTION(TFAW_TW_KB_PAGE_HELPER)
+ .set_DIMM_TARGET(i_target),
+ "%s Invalid frequency %lu",
+ mss::c_str(i_target),
+ i_freq);
+ break;
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Return the minimum allowable tFAW in nck
+/// @tparam T the fapi2::TargetType of a type from which we can get MT/s
+/// @param[in] i_target the fapi2 target
+/// @param[in] i_dram_width the page size
+/// @param[in] i_freq the DRAM frequency
+/// @param[out] o_tFAW timing in clocks (nck)
+/// @return FAPI2_RC_SUCCESS iff okay
+//
+template< fapi2::TargetType T >
+fapi2::ReturnCode tfaw( const fapi2::Target<T>& i_target,
+ const uint8_t i_dram_width,
+ const uint64_t i_freq,
+ uint64_t& o_tFAW )
+{
+ switch(i_dram_width)
+ {
+ case fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X4:
+ FAPI_TRY( tfaw_half_kb_page_helper(i_target, i_freq, o_tFAW) );
+ break;
+
+ case fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X8:
+ FAPI_TRY( tfaw_1kb_page_helper(i_target, i_freq, o_tFAW) );
+ break;
+
+ case fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X16:
+ FAPI_TRY( tfaw_2kb_page_helper(i_target, i_freq, o_tFAW) );
+ break;
+
+ default:
+ FAPI_ASSERT( false,
+ fapi2::MSS_INVALID_DRAM_WIDTH()
+ .set_DRAM_WIDTH(i_dram_width)
+ .set_DIMM_TARGET(i_target),
+ "Invalid DRAM width with %d for target %s",
+ i_dram_width,
+ mss::c_str(i_target));
+ break;
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief tFAW_dlr *in nck*
+/// @return 16nck
+/// @note From DDR4 3DS Spec
+/// 12.2 Timing Parameters by Speed Grade
+///
+constexpr uint64_t tfaw_dlr()
+{
+ return 16;
+}
+
+///
+/// @brief tRRD_dlr *in nck*
+/// @return 4nck
+/// @note From DDR4 3DS Spec
+/// 12.2 Timing Parameters by Speed Grade
+///
+constexpr uint64_t trrd_dlr()
+{
+ return 4;
+}
+
+///
+/// @brief Helper function to find tRRD_L based speed (MT/s) for 1KB page
+/// @tparam T the fapi2::TargetType of a type from which we can get MT/s
+/// @param[in] i_target the fapi2 target
+/// @param[in] i_freq the DRAM frequency
+/// @param[out] o_output timing in clocks (nck)
+/// @return FAPI2_RC_SUCCESS iff okay
+/// @note this is only for non-3DS DIMM
+///
+template< fapi2::TargetType T >
+static fapi2::ReturnCode trrd_l_half_and_1kb_page_helper(const fapi2::Target<T>& i_target,
+ const uint64_t i_freq,
+ uint64_t& o_output)
+{
+ // Values derived from DDR4 Spec (79-4A)
+ // 13.3 Timing Parameters by Speed Grade
+ // Table 132. Pg 240
+ fapi2::current_err = fapi2::FAPI2_RC_SUCCESS;
+
+ // It could have been more "efficient" to hand-calculate the answer and
+ // use compile time constants to return the answer. To avoid magic
+ // numbers and to align (more closely) with the DDR4 JEDEC spec,
+ // we let the std library do the work for us for maintainability (and ease of debug?).
+ // Could have used compile-time constants to denote the numbers below
+ // but they are "random" and vary.
+ switch(i_freq)
+ {
+ case 1866:
+ case 2133:
+ // From the spec: Max(4nCK,5.3ns)
+ o_output = std::max( 4, spd::ps_to_nck(i_freq, 5300) );
+ break;
+
+ case 2400:
+ case 2666:
+ case 2933:
+ case 3200:
+ // Max(4nCK,4.9ns)
+ o_output = std::max( 4, spd::ps_to_nck(i_freq, 4900) );
+ break;
+
+ default:
+ FAPI_ASSERT( false,
+ fapi2::MSS_INVALID_FREQ_PASSED_IN()
+ .set_FREQ(i_freq)
+ .set_FUNCTION(TRRD_L_HALF_AND_1KB_PAGE_HELPER)
+ .set_DIMM_TARGET(i_target),
+ "%s Invalid frequency %lu",
+ mss::c_str(i_target),
+ i_freq);
+ }
+
+ return fapi2::FAPI2_RC_SUCCESS;
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Helper function to find tRRD_L based speed (MT/s) for 2KB page
+/// @tparam T the fapi2::TargetType of a type from which we can get MT/s
+/// @param[in] i_target the fapi2 target
+/// @param[in] i_freq the DRAM frequency
+/// @param[out] o_output timing in clocks (nck)
+/// @return FAPI2_RC_SUCCESS iff okay
+/// @note this is only for non-3DS DIMM
+///
+template< fapi2::TargetType T >
+static fapi2::ReturnCode trrd_l_2kb_page_helper(const fapi2::Target<T>& i_target,
+ const uint64_t i_freq,
+ uint64_t& o_output)
+{
+
+ // Values derived from DDR4 Spec (79-4A)
+ // 13.3 Timing Parameters by Speed Grade
+ // Table 132. Pg 240
+ fapi2::current_err = fapi2::FAPI2_RC_SUCCESS;
+
+ // It could have been more "efficient" to hand-calculate the answer and
+ // use compile time constants to return the answer. To avoid magic
+ // numbers and to align (more closely) with the DDR4 JEDEC spec,
+ // we let the std library do the work for us for maintainability (and ease of debug?).
+ // Could have used compile-time constants to denote the numbers below
+ // but they are "random" and vary.
+ switch(i_freq)
+ {
+ case 1866:
+ case 2133:
+ case 2400:
+ case 2666:
+ case 2933:
+ case 3200:
+ o_output = std::max( 4, spd::ps_to_nck(i_freq, 6400) );
+ break;
+
+ default:
+ FAPI_TRY(fapi2::FAPI2_RC_INVALID_PARAMETER, "%s Invalid frequency %lu", mss::c_str(i_target), i_freq);
+ break;
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Return the minimum allowable tRRD_L in nck
+/// @tparam T the fapi2::TargetType of a type from which we can get MT/s
+/// @param[in] i_target the fapi2 target
+/// @param[in] i_dram_width the page size
+/// @param[in] i_freq the DRAM frequency
+/// @param[out] o_output timing in clocks (nck)
+/// @return FAPI2_RC_SUCCESS iff okay
+/// @note this is only for non-3DS DIMM
+///
+template< fapi2::TargetType T >
+fapi2::ReturnCode trrd_l( const fapi2::Target<T>& i_target,
+ const uint8_t i_dram_width,
+ const uint64_t i_freq,
+ uint64_t& o_tRRD_L )
+{
+ switch(i_dram_width)
+ {
+ case fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X4:
+ case fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X8:
+ FAPI_TRY( trrd_l_half_and_1kb_page_helper(i_target, i_freq, o_tRRD_L),
+ "Error calculating trrd l for half and 1kb page" );
+ break;
+
+ case fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X16:
+ FAPI_TRY( trrd_l_2kb_page_helper(i_target, i_freq, o_tRRD_L) );
+ break;
+
+ default:
+ FAPI_ASSERT( false,
+ fapi2::MSS_INVALID_PAGE_SIZE()
+ .set_DRAM_WIDTH(i_dram_width)
+ .set_DIMM_TARGET(i_target),
+ "%s Recieved an invalid page size: %lu",
+ mss::c_str(i_target),
+ i_dram_width);
+ break;
+ }
+
+ return fapi2::FAPI2_RC_SUCCESS;
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Helper function to find tRRD_S based speed (MT/s) for 1KB page
+/// @tparam T the fapi2::TargetType of a type from which we can get MT/s
+/// @param[in] i_target the fapi2 target
+/// @param[in] i_freq the DRAM frequency
+/// @param[out] o_output timing in clocks (nck)
+/// @return FAPI2_RC_SUCCESS iff okay
+/// @note this is only for non-3DS DIMM
+///
+template< fapi2::TargetType T >
+static fapi2::ReturnCode trrd_s_half_and_1kb_page_helper(const fapi2::Target<T>& i_target,
+ const uint64_t i_freq,
+ uint64_t& o_output)
+{
+ // Values derived from DDR4 Spec (79-4A)
+ // 13.3 Timing Parameters by Speed Grade
+ // Table 132. Pg 240
+ fapi2::current_err = fapi2::FAPI2_RC_SUCCESS;
+
+ // It could have been more "efficient" to hand-calculate the answer and
+ // use compile time constants to return the answer. To avoid magic
+ // numbers and to align (more closely) with the DDR4 JEDEC spec,
+ // we let the std library do the work for us for maintainability (and ease of debug?).
+ // Could have used compile-time constants to denote the numbers below
+ // but they are "random" and vary.
+ switch(i_freq)
+ {
+ case 1866:
+ o_output = std::max( 4, spd::ps_to_nck(i_freq, 4200) );
+ break;
+
+ case 2133:
+ o_output = std::max( 4, spd::ps_to_nck(i_freq, 3700) );
+ break;
+
+ case 2400:
+ o_output = std::max( 4, spd::ps_to_nck(i_freq, 3300) );
+ break;
+
+ case 2666:
+ o_output = std::max( 4, spd::ps_to_nck(i_freq, 3000) );
+ break;
+
+ case 2933:
+ o_output = std::max( 4, spd::ps_to_nck(i_freq, 2700) );
+ break;
+
+ case 3200:
+ o_output = std::max( 4, spd::ps_to_nck(i_freq, 2500) );
+ break;
+
+ default:
+ FAPI_ASSERT( false,
+ fapi2::MSS_INVALID_FREQ_PASSED_IN()
+ .set_FREQ(i_freq)
+ .set_FUNCTION(TRRD_S_HALF_AND_1KB_PAGE_HELPER)
+ .set_DIMM_TARGET(i_target),
+ "%s Invalid frequency %lu",
+ mss::c_str(i_target),
+ i_freq);
+ }
+
+ return fapi2::FAPI2_RC_SUCCESS;
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Helper function to find tRRD_S based speed (MT/s) for 2KB page
+/// @tparam T the fapi2::TargetType of a type from which we can get MT/s
+/// @param[in] i_target the fapi2 target
+/// @param[in] i_freq the DRAM frequency
+/// @param[out] o_output timing in clocks (nck)
+/// @return FAPI2_RC_SUCCESS iff okay
+/// @note this is only for non-3DS DIMM
+///
+template< fapi2::TargetType T >
+static fapi2::ReturnCode trrd_s_2kb_page_helper(const fapi2::Target<T>& i_target,
+ const uint64_t i_freq,
+ uint64_t& o_output)
+{
+ // Values derived from DDR4 Spec (79-4A)
+ // 13.3 Timing Parameters by Speed Grade
+ // Table 132. Pg 240
+ fapi2::current_err = fapi2::FAPI2_RC_SUCCESS;
+
+ // It could have been more "efficient" to hand-calculate the answer and
+ // use compile time constants to return the answer. To avoid magic
+ // numbers and to align (more closely) with the DDR4 JEDEC spec,
+ // we let the std library do the work for us for maintainability (and ease of debug?).
+ // Could have used compile-time constants to denote the numbers below
+ // but they are "random" and vary.
+ switch(i_freq)
+ {
+ case 1866:
+ case 2133:
+ case 2400:
+ case 2666:
+ case 2933:
+ case 3200:
+ o_output = std::max( 4, spd::ps_to_nck(i_freq, 5300) );
+ break;
+
+ default:
+ FAPI_ASSERT( false,
+ fapi2::MSS_INVALID_FREQ_PASSED_IN()
+ .set_FREQ(i_freq)
+ .set_FUNCTION(TRRD_S_2KB_PAGE_HELPER)
+ .set_DIMM_TARGET(i_target),
+ "%s Invalid frequency %lu",
+ mss::c_str(i_target),
+ i_freq);
+ break;
+ }
+
+ return fapi2::FAPI2_RC_SUCCESS;
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Return the minimum allowable tRRD_S in nck
+/// @tparam T the fapi2::TargetType of a type from which we can get MT/s
+/// @param[in] i_target the fapi2 target
+/// @param[in] i_dram_width the page size
+/// @param[in] i_freq the DRAM frequency
+/// @param[out] o_tRRD_S timing in clocks (nck)
+/// @return FAPI2_RC_SUCCESS iff okay
+/// @note this is only for non-3DS DIMM
+///
+template< fapi2::TargetType T >
+fapi2::ReturnCode trrd_s( const fapi2::Target<T>& i_target,
+ const uint8_t i_dram_width,
+ const uint64_t i_freq,
+ uint64_t& o_tRRD_S )
+{
+ switch(i_dram_width)
+ {
+ case fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X4:
+ case fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X8:
+ FAPI_TRY( trrd_s_half_and_1kb_page_helper(i_target, i_freq, o_tRRD_S),
+ "Error calculating trrd_s for half and 1kb page" );
+ break;
+
+ case fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X16:
+ FAPI_TRY( trrd_s_2kb_page_helper(i_target, i_freq, o_tRRD_S) );
+ break;
+
+ default:
+ FAPI_ASSERT( false,
+ fapi2::MSS_INVALID_PAGE_SIZE()
+ .set_DRAM_WIDTH(i_dram_width)
+ .set_DIMM_TARGET(i_target),
+ "%s Recieved an invalid page size: %lu",
+ mss::c_str(i_target),
+ i_dram_width);
+ break;
+ }
+
+ return fapi2::FAPI2_RC_SUCCESS;
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+} // mss
+#endif
diff --git a/src/import/generic/memory/lib/utils/shared/mss_generic_consts.H b/src/import/generic/memory/lib/utils/shared/mss_generic_consts.H
index 09182bb70..37901f21b 100644
--- a/src/import/generic/memory/lib/utils/shared/mss_generic_consts.H
+++ b/src/import/generic/memory/lib/utils/shared/mss_generic_consts.H
@@ -223,6 +223,21 @@ enum generic_ffdc_codes
SET_COL_ADDR_BITS = 0x1082,
SET_ROW_ADDR_BITS = 0x1083,
SET_3DS_HEIGHT = 0x1084,
+ SET_DRAM_CWL = 0x1085,
+ SET_DRAM_TREFI = 0x1086,
+ SET_DRAM_TCCD_L = 0x1087,
+ SET_DRAM_TWTR_L = 0x1088,
+ SET_DRAM_TWTR_S = 0x1089,
+ SET_DRAM_TFAW = 0x108A,
+ SET_DRAM_TRCD = 0x108B,
+ SET_DRAM_TRP = 0x108C,
+ SET_DRAM_TRAS = 0x108D,
+ SET_DRAM_TWR = 0x108E,
+ SET_DRAM_TRTP = 0x108F,
+ SET_DRAM_TRRD_S = 0x1090,
+ SET_DRAM_TRRD_L = 0x1091,
+ SET_DRAM_TRFC = 0x1092,
+ SET_DRAM_TRFC_DLR = 0x1093,
// Power thermal functions
OpenPOWER on IntegriCloud