summaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/dimm/eff_dimm.C24
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/eff_config/timing.C165
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/eff_config/timing.H733
-rw-r--r--src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_eff_config.xml45
-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
-rw-r--r--src/import/generic/procedures/xml/error_info/generic_error.xml45
10 files changed, 2529 insertions, 967 deletions
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/eff_dimm.C b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/eff_dimm.C
index baac38c30..74e3182ee 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/eff_dimm.C
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/eff_dimm.C
@@ -366,16 +366,6 @@ enum invalid_freq_function_encoding : uint8_t
F0BC6X = 0x60,
};
-///
-/// @brief encoding for MSS_INVALID_TIMING so we can look up functions based on encoding
-///
-enum invalid_timing_function_encoding : uint8_t
-{
- TRRD_S = 0,
- TRRD_L = 1,
- TFAW = 2,
-};
-
/////////////////////////
// Non-member function implementations
/////////////////////////
@@ -4098,7 +4088,7 @@ fapi2::ReturnCode eff_dimm::dram_trrd_s()
l_trrd_s_in_nck);
}
- FAPI_TRY( trrd_s( iv_dimm, iv_dram_width, l_jedec_trrd) );
+ FAPI_TRY( trrd_s( iv_dimm, iv_dram_width, iv_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)
@@ -4174,7 +4164,7 @@ fapi2::ReturnCode eff_dimm::dram_trrd_l()
l_trrd_l_in_nck);
}
- FAPI_TRY( trrd_l( iv_dimm, iv_dram_width, l_jedec_trrd) );
+ FAPI_TRY( trrd_l( iv_dimm, iv_dram_width, iv_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)
@@ -4273,7 +4263,7 @@ fapi2::ReturnCode eff_dimm::dram_tfaw()
l_tfaw_in_nck);
}
- FAPI_TRY( mss::tfaw(iv_dimm, iv_dram_width, l_jedec_tfaw_in_nck), "Failed tfaw()" );
+ FAPI_TRY( mss::tfaw(iv_dimm, iv_dram_width, iv_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)
@@ -4342,11 +4332,15 @@ fapi2::ReturnCode eff_dimm::dram_tras()
// 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)
- const uint64_t l_tras_in_ps = mss::tras(iv_dimm);
+ uint64_t l_tras_in_ps;
+ uint64_t l_freq = 0;
+ uint8_t l_tras_in_nck = 0;
// Calculate nck
std::vector<uint8_t> l_attrs_dram_tras(PORTS_PER_MCS, 0);
- uint8_t l_tras_in_nck = 0;
+
+ FAPI_TRY( freq(mss::find_target<fapi2::TARGET_TYPE_MCBIST>(iv_dimm), l_freq) );
+ l_tras_in_ps = mss::tras(iv_dimm, l_freq);
// Cast needed for calculations to be done on the same integral type
// as required by template deduction. We have iv_tCK_in_ps as a signed
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/timing.C b/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/timing.C
index ebc203f2e..1f2920c7b 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/timing.C
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/timing.C
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2016,2017 */
+/* Contributors Listed Below - COPYRIGHT 2016,2019 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -37,167 +37,4 @@
namespace mss
{
-enum temp_mode : uint8_t
-{
- NORMAL = 1,
- EXTENDED = 2,
-};
-
-// 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;
-
-// 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},
-};
-
-///
-/// @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
-///
-fapi2::ReturnCode calc_trefi( const refresh_rate i_mode,
- const uint8_t i_refresh_request_rate,
- uint64_t& o_timing )
-{
- 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 );
-
- // FAPI_ASSERT doesn't set current_err as good
- 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
-///
-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)
-{
- 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;
-}
-
}// mss
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/timing.H b/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/timing.H
index 8b8215b96..d748400cb 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/timing.H
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/timing.H
@@ -40,104 +40,13 @@
#include <lib/mss_attribute_accessors.H>
#include <generic/memory/lib/utils/find.H>
#include <generic/memory/lib/utils/shared/mss_generic_consts.H>
+#include <generic/memory/lib/utils/dimm/mss_timing.H>
#include <lib/utils/mss_nimbus_conversions.H>
namespace mss
{
///
-/// @brief Enums for ffdc error callout so we know which function had the error
-///
-enum functions
-{
- 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,
- TDLLK = 11,
-};
-
-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 T the target type from which to get the mt/s
-/// @tparam OT the output type, derrived from the parameters
-/// @param[in] i_target target for the frequency attribute
-/// @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<fapi2::TargetType T, typename OT>
-inline OT ps_to_nck( const fapi2::Target<T>& i_target, const OT& i_timing_in_ps)
-{
- uint64_t l_freq = 0;
- OT l_tck_in_ps = 0;
- OT l_temp_nck = 0;
-
- FAPI_TRY( mss::freq( find_target<fapi2::TARGET_TYPE_MCBIST>(i_target), l_freq) );
-
- // No time if MT/s is 0 (well, infinite really but shut up)
- if (l_freq == 0)
- {
- return 0;
- }
-
- FAPI_TRY( freq_to_ps(l_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 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("Can't get MSS_FREQ, obtained an invalid MSS_FREQ (%d), or overflow occurred - stopping", l_freq);
- fapi2::Assert(false);
-
- // Keeps compiler happy
- return 0;
-}
-
-///
-/// @brief Returns clock cycles from nanoseconds
-/// Uses SPD rounding algorithm for DDR4
-/// @tparam T the target type from which to get the mt/s
-/// @tparam OT the output type, derrived from the parameters
-/// @param[in] timing_in_ps timing parameter in ps
-/// @param[out] o_value_nck the end calculation in nck
-/// @return the clock cycles of timing parameter (provided in ps)F
-/// @note Uses DDR4 SPD Contents Rounding Algorithm
-/// @note Item 2220.46
-///
-template<fapi2::TargetType T, typename OT>
-inline OT ns_to_nck( const fapi2::Target<T>& i_target, const OT& i_timing_in_ns)
-{
- return ps_to_nck(i_target, i_timing_in_ns * CONVERT_PS_IN_A_NS);
-}
-
-}// spd
-
-///
/// @brief Returns application clock period (tCK) based on dimm transfer rate
/// @tparam T the fapi2 target
/// @tparam OT output type
@@ -159,30 +68,6 @@ fapi_try_exit:
}
///
-/// @brief Calculates refresh interval time
-/// @param[in] i_mode fine refresh rate mode
-/// @param[in] i_temp_refresh_range temperature refresh range
-/// @param[out] o_value timing val in ps
-/// @return fapi2::ReturnCode
-///
-fapi2::ReturnCode calc_trefi( const refresh_rate i_mode,
- const uint8_t i_temp_refresh_range,
- uint64_t& o_timing );
-
-///
-/// @brief Calculates Minimum Refresh Recovery Delay Time (different logical rank)
-/// @param[in] i_target a target for attributes
-/// @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
-///
-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 );
-
-///
/// @brief DLL locking time *in clocks*
/// @tparam T the fapi2::TargetType of i_target
/// @tparam OT the type of the output location
@@ -582,602 +467,6 @@ fapi_try_exit:
}
///
-/// @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
-/// @return value in picoseconds
-///
-inline uint64_t tras(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target)
-{
- uint64_t l_freq = 0;
- uint64_t l_tras = 0;
-
- // Frequency is used to determine tRAS
- FAPI_TRY( freq(mss::find_target<fapi2::TARGET_TYPE_MCBIST>(i_target), l_freq) );
-
- switch(l_freq)
- {
- case fapi2::ENUM_ATTR_MSS_FREQ_MT1866:
- l_tras = 34000;
- break;
-
- case fapi2::ENUM_ATTR_MSS_FREQ_MT2133:
- l_tras = 33000;
- break;
-
- case fapi2::ENUM_ATTR_MSS_FREQ_MT2400:
- case fapi2::ENUM_ATTR_MSS_FREQ_MT2666:
- l_tras = 32000;
- break;
-
- default:
- FAPI_ASSERT( false,
- fapi2::MSS_INVALID_FREQ_PASSED_IN()
- .set_FREQ(l_freq)
- .set_FUNCTION(TRAS)
- .set_DIMM_TARGET(i_target),
- "%s Invalid frequency %lu",
- mss::c_str(i_target),
- l_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("Can't get MSS_FREQ or obtained an invalid MSS_FREQ (%d) - stopping", l_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[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,
- 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;
-
- uint64_t l_freq = 0;
- FAPI_TRY( freq(find_target<fapi2::TARGET_TYPE_MCBIST>(i_target), l_freq),
- "Failed to invoke freq accessor" );
-
- // 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(l_freq)
- {
- // static_cast is needed for template deduction of std::max API
- case fapi2::ENUM_ATTR_MSS_FREQ_MT1866:
- o_output = std::max( 16, spd::ns_to_nck(i_target, 17) );
- break;
-
- case fapi2::ENUM_ATTR_MSS_FREQ_MT2133:
- o_output = std::max( 16, spd::ns_to_nck(i_target, 15) );
- break;
-
- case fapi2::ENUM_ATTR_MSS_FREQ_MT2400:
- o_output = std::max( 16, spd::ns_to_nck(i_target, 13) );
- break;
-
- case fapi2::ENUM_ATTR_MSS_FREQ_MT2666:
- o_output = std::max( 16, spd::ns_to_nck(i_target, 12) );
- break;
-
- default:
- FAPI_ASSERT( false,
- fapi2::MSS_INVALID_FREQ_PASSED_IN()
- .set_FREQ(l_freq)
- .set_FUNCTION(TFAW_HALF_KB_PAGE_HELPER)
- .set_DIMM_TARGET(i_target),
- "%s Invalid frequency %lu",
- mss::c_str(i_target),
- l_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[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,
- 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;
-
- uint64_t l_freq = 0;
- FAPI_TRY( freq(find_target<fapi2::TARGET_TYPE_MCBIST>(i_target), l_freq),
- "Failed to invoke freq accessor" );
-
- // 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(l_freq)
- {
- case fapi2::ENUM_ATTR_MSS_FREQ_MT1866:
- o_output = std::max( 20, spd::ns_to_nck(i_target, 23) );
- break;
-
- case fapi2::ENUM_ATTR_MSS_FREQ_MT2133:
- case fapi2::ENUM_ATTR_MSS_FREQ_MT2400:
- case fapi2::ENUM_ATTR_MSS_FREQ_MT2666:
- o_output = std::max( 20, spd::ns_to_nck(i_target, 21) );
- break;
-
- default:
- FAPI_ASSERT( false,
- fapi2::MSS_INVALID_FREQ_PASSED_IN()
- .set_FREQ(l_freq)
- .set_FUNCTION(TFAW_ONE_KB_PAGE_HELPER)
- .set_DIMM_TARGET(i_target),
- "%s Invalid frequency %lu",
- mss::c_str(i_target),
- l_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[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,
- 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.
- uint64_t l_freq = 0;
- FAPI_TRY( freq(find_target<fapi2::TARGET_TYPE_MCBIST>(i_target), l_freq),
- "Failed to invoke freq accessor" );
-
- switch(l_freq)
- {
- case fapi2::ENUM_ATTR_MSS_FREQ_MT1866:
- case fapi2::ENUM_ATTR_MSS_FREQ_MT2133:
- case fapi2::ENUM_ATTR_MSS_FREQ_MT2400:
- case fapi2::ENUM_ATTR_MSS_FREQ_MT2666:
- o_output = std::max( 28, spd::ns_to_nck(i_target, 30) );
- break;
-
- default:
- FAPI_ASSERT( false,
- fapi2::MSS_INVALID_FREQ_PASSED_IN()
- .set_FREQ(l_freq)
- .set_FUNCTION(TFAW_TW_KB_PAGE_HELPER)
- .set_DIMM_TARGET(i_target),
- "%s Invalid frequency %lu",
- mss::c_str(i_target),
- l_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[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,
- 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, o_tFAW) );
- break;
-
- case fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X8:
- FAPI_TRY( tfaw_1kb_page_helper(i_target, o_tFAW) );
- break;
-
- case fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X16:
- FAPI_TRY( tfaw_2kb_page_helper(i_target, 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[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,
- 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;
-
- uint64_t l_freq = 0;
- FAPI_TRY( freq(find_target<fapi2::TARGET_TYPE_MCBIST>(i_target), l_freq),
- "Failed to invoke freq accessor" );
-
- // 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(l_freq)
- {
- case fapi2::ENUM_ATTR_MSS_FREQ_MT1866:
- case fapi2::ENUM_ATTR_MSS_FREQ_MT2133:
- // From the spec: Max(4nCK,5.3ns)
- o_output = std::max( 4, spd::ps_to_nck(i_target, 5300) );
- break;
-
- case fapi2::ENUM_ATTR_MSS_FREQ_MT2666:
- case fapi2::ENUM_ATTR_MSS_FREQ_MT2400:
- // Max(4nCK,4.9ns)
- o_output = std::max( 4, spd::ps_to_nck(i_target, 4900) );
- break;
-
- default:
- FAPI_ASSERT( false,
- fapi2::MSS_INVALID_FREQ_PASSED_IN()
- .set_FREQ(l_freq)
- .set_FUNCTION(TRRD_L_HALF_AND_1KB_PAGE_HELPER)
- .set_DIMM_TARGET(i_target),
- "%s Invalid frequency %lu",
- mss::c_str(i_target),
- l_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[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,
- 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;
-
- uint64_t l_freq = 0;
- FAPI_TRY( freq(find_target<fapi2::TARGET_TYPE_MCBIST>(i_target), l_freq),
- "Failed to invoke freq accessor" );
-
- // 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(l_freq)
- {
- case fapi2::ENUM_ATTR_MSS_FREQ_MT1866:
- case fapi2::ENUM_ATTR_MSS_FREQ_MT2133:
- case fapi2::ENUM_ATTR_MSS_FREQ_MT2400:
- case fapi2::ENUM_ATTR_MSS_FREQ_MT2666:
- o_output = std::max( 4, spd::ps_to_nck(i_target, 6400) );
- break;
-
- default:
- FAPI_TRY(fapi2::FAPI2_RC_INVALID_PARAMETER, "%s Invalid frequency %lu", mss::c_str(i_target), l_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[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,
- 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, 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, 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[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,
- 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;
-
- uint64_t l_freq = 0;
- FAPI_TRY( freq(find_target<fapi2::TARGET_TYPE_MCBIST>(i_target), l_freq),
- "Failed to invoke freq accessor" );
-
- // 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(l_freq)
- {
- case fapi2::ENUM_ATTR_MSS_FREQ_MT1866:
- o_output = std::max( 4, spd::ps_to_nck(i_target, 4200) );
- break;
-
- case fapi2::ENUM_ATTR_MSS_FREQ_MT2133:
- o_output = std::max( 4, spd::ps_to_nck(i_target, 3700) );
- break;
-
- case fapi2::ENUM_ATTR_MSS_FREQ_MT2400:
- o_output = std::max( 4, spd::ps_to_nck(i_target, 3300) );
- break;
-
- case fapi2::ENUM_ATTR_MSS_FREQ_MT2666:
- o_output = std::max( 4, spd::ps_to_nck(i_target, 3000) );
- break;
-
- default:
- FAPI_ASSERT( false,
- fapi2::MSS_INVALID_FREQ_PASSED_IN()
- .set_FREQ(l_freq)
- .set_FUNCTION(TRRD_S_HALF_AND_1KB_PAGE_HELPER)
- .set_DIMM_TARGET(i_target),
- "%s Invalid frequency %lu",
- mss::c_str(i_target),
- l_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[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,
- 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;
-
- uint64_t l_freq = 0;
- FAPI_TRY( freq(find_target<fapi2::TARGET_TYPE_MCBIST>(i_target), l_freq),
- "Failed to invoke freq accessor" );
-
- // 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(l_freq)
- {
- case fapi2::ENUM_ATTR_MSS_FREQ_MT1866:
- case fapi2::ENUM_ATTR_MSS_FREQ_MT2133:
- case fapi2::ENUM_ATTR_MSS_FREQ_MT2400:
- case fapi2::ENUM_ATTR_MSS_FREQ_MT2666:
- o_output = std::max( 4, spd::ps_to_nck(i_target, 5300) );
- break;
-
- default:
- FAPI_ASSERT( false,
- fapi2::MSS_INVALID_FREQ_PASSED_IN()
- .set_FREQ(l_freq)
- .set_FUNCTION(TRRD_S_2KB_PAGE_HELPER)
- .set_DIMM_TARGET(i_target),
- "%s Invalid frequency %lu",
- mss::c_str(i_target),
- l_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[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,
- 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, 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, 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;
-}
-
-///
/// @brief VREF DQ Enter time *in clocks*
/// @tparam T the fapi2::TargetType of i_target
/// @param[in] i_target a target for attributes
@@ -1215,25 +504,5 @@ constexpr uint64_t tccd_s()
return 4;
}
-namespace lrdimm
-{
-
-///
-/// @brief Return the VREF to VREF change time long
-/// @tparam fapi2::TargetType T - type of the target on which to operate
-/// @param[in] i_target the fapi2 target
-/// @return value in clocks
-/// @note VREF time change long is used for changing by more than one VREF tick
-///
-template< fapi2::TargetType T >
-inline uint64_t vref_time_long(const fapi2::Target<T>& i_target)
-{
- // Taken from the LRDIMM spec
- constexpr uint64_t VREF_TIME_LONG_NS = 500;
- return mss::spd::ns_to_nck(i_target, VREF_TIME_LONG_NS);
-}
-
-} // ns lrdimm
-
} // mss
#endif
diff --git a/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_eff_config.xml b/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_eff_config.xml
index 56fb232dc..4bd96d9f7 100644
--- a/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_eff_config.xml
+++ b/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_eff_config.xml
@@ -37,18 +37,6 @@
<hwpErrors>
<hwpError>
- <rc>RC_MSS_INVALID_FINE_REFRESH_MODE</rc>
- <description>
- Invalid fine refresh mode received from the mrw
- </description>
- <ffdc>FINE_REF_MODE</ffdc>
- <callout>
- <procedure>CODE</procedure>
- <priority>HIGH</priority>
- </callout>
- </hwpError>
-
- <hwpError>
<rc>RC_MSS_INVALID_FINE_REFRESH_MODE_WITH_TEMP_REFRESH_MODE_ENABLED</rc>
<description>
Invalid fine refresh mode received due to temperature refresh mode being enabled
@@ -383,19 +371,6 @@
</hwpError>
<hwpError>
- <rc>RC_MSS_INVALID_REFRESH_RATE_REQUEST</rc>
- <description>
- Invalid refresh request rate received.
- Possibly due to bad MRW setting for ATTR_MSS_MRW_REFRESH_RATE_REQUEST.
- </description>
- <ffdc>REFRESH_RATE_REQUEST</ffdc>
- <callout>
- <procedure>CODE</procedure>
- <priority>HIGH</priority>
- </callout>
- </hwpError>
-
- <hwpError>
<rc>RC_MSS_INVALID_FINE_REFRESH</rc>
<description>
Incorrect FINE Refresh Mode received
@@ -408,26 +383,6 @@
</hwpError>
<hwpError>
- <rc>RC_MSS_FAILED_TO_FIND_TRFC</rc>
- <description>
- Unable to find tRFC (ps) from map with SDRAM density key
- </description>
- <ffdc>SDRAM_DENSITY</ffdc>
- <ffdc>REFRESH_MODE</ffdc>
- <callout>
- <target>DIMM_TARGET</target>
- <priority>MEDIUM</priority>
- </callout>
- <deconfigure>
- <target>DIMM_TARGET</target>
- </deconfigure>
- <callout>
- <procedure>CODE</procedure>
- <priority>HIGH</priority>
- </callout>
- </hwpError>
-
- <hwpError>
<rc>RC_MSS_INVALID_PAGE_SIZE</rc>
<description>
Invalid page size
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
diff --git a/src/import/generic/procedures/xml/error_info/generic_error.xml b/src/import/generic/procedures/xml/error_info/generic_error.xml
index a3f26ca8d..eed7aff57 100644
--- a/src/import/generic/procedures/xml/error_info/generic_error.xml
+++ b/src/import/generic/procedures/xml/error_info/generic_error.xml
@@ -89,6 +89,26 @@
</hwpError>
<hwpError>
+ <rc>RC_MSS_FAILED_TO_FIND_TRFC</rc>
+ <description>
+ Unable to find tRFC (ps) from map with SDRAM density key
+ </description>
+ <ffdc>SDRAM_DENSITY</ffdc>
+ <ffdc>REFRESH_MODE</ffdc>
+ <callout>
+ <target>DIMM_TARGET</target>
+ <priority>MEDIUM</priority>
+ </callout>
+ <deconfigure>
+ <target>DIMM_TARGET</target>
+ </deconfigure>
+ <callout>
+ <procedure>CODE</procedure>
+ <priority>HIGH</priority>
+ </callout>
+ </hwpError>
+
+ <hwpError>
<rc>RC_MSS_FREQ_CL_EXCEEDS_TAA_MAX</rc>
<description>
Calculated Cas Latency exceeds JEDEC value for TAA Max
@@ -374,6 +394,18 @@
</hwpError>
<hwpError>
+ <rc>RC_MSS_INVALID_FINE_REFRESH_MODE</rc>
+ <description>
+ Invalid fine refresh mode received from the mrw
+ </description>
+ <ffdc>FINE_REF_MODE</ffdc>
+ <callout>
+ <procedure>CODE</procedure>
+ <priority>HIGH</priority>
+ </callout>
+ </hwpError>
+
+ <hwpError>
<rc>RC_MSS_INVALID_HYBRID_MODULE</rc>
<description>
Received an invalid or unsupported hybrid media (SPD byte 3, bits [6:4])
@@ -425,6 +457,19 @@
</hwpError>
<hwpError>
+ <rc>RC_MSS_INVALID_REFRESH_RATE_REQUEST</rc>
+ <description>
+ Invalid refresh request rate received.
+ Possibly due to bad MRW setting for ATTR_MSS_MRW_REFRESH_RATE_REQUEST.
+ </description>
+ <ffdc>REFRESH_RATE_REQUEST</ffdc>
+ <callout>
+ <procedure>CODE</procedure>
+ <priority>HIGH</priority>
+ </callout>
+ </hwpError>
+
+ <hwpError>
<rc>RC_MSS_INVALID_SPD_PARAMETER_RECEIVED</rc>
<description>
Unable to fall back SPD decoder to the highest decoded
OpenPOWER on IntegriCloud