summaryrefslogtreecommitdiffstats
path: root/src/import/chips/p9/procedures/hwp/memory
diff options
context:
space:
mode:
authorStephen Glancy <sglancy@us.ibm.com>2017-11-27 14:47:16 -0600
committerDaniel M. Crowell <dcrowell@us.ibm.com>2018-01-13 14:13:50 -0500
commit01c730dd41576de25c422070d89e5117ed6975dc (patch)
tree39c2b7e3ac0660c53f0ad10463c30af2c59d0d9e /src/import/chips/p9/procedures/hwp/memory
parent02e505b4c437fbf21b39f29c005c934137ad0c6a (diff)
downloadtalos-hostboot-01c730dd41576de25c422070d89e5117ed6975dc.tar.gz
talos-hostboot-01c730dd41576de25c422070d89e5117ed6975dc.zip
Updates WR VREF for characterization results
Change-Id: I9803ee77afa2ebc32e12d9d528ac4ae6a6c947f8 CQ:SW411492 Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/50709 Dev-Ready: STEPHEN GLANCY <sglancy@us.ibm.com> Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com> Reviewed-by: Louis Stermole <stermole@us.ibm.com> Reviewed-by: ANDRE A. MARIN <aamarin@us.ibm.com> Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com> Tested-by: HWSV CI <hwsv-ci+hostboot@us.ibm.com> Tested-by: Hostboot CI <hostboot-ci+hostboot@us.ibm.com> Reviewed-by: Jennifer A. Stofer <stofer@us.ibm.com> Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/50713 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: Daniel M. Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src/import/chips/p9/procedures/hwp/memory')
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/mrs_load_ddr4.H93
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/pda.H72
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/dimm/eff_dimm.C97
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/dimm/eff_dimm.H25
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/dimm/rank.H4
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/fir/check.C4
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/mss_attribute_accessors.H23
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/phy/dp16.C461
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/phy/dp16.H48
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/phy/mss_training.C237
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/phy/mss_training.H42
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/shared/mss_const.H23
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/workarounds/dp16_workarounds.C662
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/workarounds/dp16_workarounds.H236
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/p9_mss_eff_config.C8
15 files changed, 1920 insertions, 115 deletions
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/mrs_load_ddr4.H b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/mrs_load_ddr4.H
index 746b1621e..89f9539ae 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/mrs_load_ddr4.H
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/mrs_load_ddr4.H
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2016,2017 */
+/* Contributors Listed Below - COPYRIGHT 2016,2018 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -830,6 +830,9 @@ struct mrs00_data
///
mrs00_data( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target, fapi2::ReturnCode& o_rc );
+ // Delete MRS00 default constructor
+ mrs00_data() = delete;
+
///
/// @brief Less than operator
/// @param[in] i_rhs right hand comparison operator
@@ -873,6 +876,16 @@ struct mrs00_data
return iv_burst_length < i_rhs.iv_burst_length;
}
+ ///
+ /// @brief Equal to operator
+ /// @param[in] i_rhs right hand comparison operator
+ /// @bool true if this object is equal to i_rhs
+ ///
+ bool operator==(const mss::ddr4::mrs00_data& i_rhs) const
+ {
+ return !((*this < i_rhs) || (i_rhs < *this));
+ }
+
uint8_t iv_burst_length;
uint8_t iv_read_burst_type;
uint8_t iv_dll_reset;
@@ -905,6 +918,9 @@ struct mrs01_data
///
mrs01_data( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target, fapi2::ReturnCode& o_rc );
+ // Delete MRS01 default constructor
+ mrs01_data() = delete;
+
///
/// @brief Less than operator
/// @param[in] i_rhs right hand comparison operator
@@ -958,6 +974,16 @@ struct mrs01_data
return iv_dll_enable < i_rhs.iv_dll_enable;
}
+ ///
+ /// @brief Equal to operator
+ /// @param[in] i_rhs right hand comparison operator
+ /// @bool true if this object is equal to i_rhs
+ ///
+ bool operator==(const mss::ddr4::mrs01_data& i_rhs) const
+ {
+ return !((*this < i_rhs) || (i_rhs < *this));
+ }
+
uint8_t iv_dll_enable;
uint8_t iv_odic[MAX_RANK_PER_DIMM];
uint8_t iv_additive_latency;
@@ -991,6 +1017,9 @@ struct mrs02_data
///
mrs02_data( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target, fapi2::ReturnCode& o_rc );
+ // Delete MRS02 default constructor
+ mrs02_data() = delete;
+
///
/// @brief Less than operator
/// @param[in] i_rhs right hand comparison operator
@@ -1024,6 +1053,16 @@ struct mrs02_data
return iv_cwl < i_rhs.iv_cwl;
}
+ ///
+ /// @brief Equal to operator
+ /// @param[in] i_rhs right hand comparison operator
+ /// @bool true if this object is equal to i_rhs
+ ///
+ bool operator==(const mss::ddr4::mrs02_data& i_rhs) const
+ {
+ return !((*this < i_rhs) || (i_rhs < *this));
+ }
+
uint8_t iv_lpasr;
uint8_t iv_cwl;
uint8_t iv_write_crc;
@@ -1055,6 +1094,9 @@ struct mrs03_data
///
mrs03_data( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target, fapi2::ReturnCode& o_rc );
+ // Delete MRS03 default constructor
+ mrs03_data() = delete;
+
///
/// @brief Less than operator
/// @param[in] i_rhs right hand comparison operator
@@ -1110,6 +1152,16 @@ struct mrs03_data
return iv_mpr_page < i_rhs.iv_mpr_page;
}
+ ///
+ /// @brief Equal to operator
+ /// @param[in] i_rhs right hand comparison operator
+ /// @bool true if this object is equal to i_rhs
+ ///
+ bool operator==(const mss::ddr4::mrs03_data& i_rhs) const
+ {
+ return !((*this < i_rhs) || (i_rhs < *this));
+ }
+
uint8_t iv_mpr_mode;
uint8_t iv_mpr_page;
uint8_t iv_geardown;
@@ -1144,6 +1196,9 @@ struct mrs04_data
///
mrs04_data( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target, fapi2::ReturnCode& o_rc );
+ // Delete MRS04 default constructor
+ mrs04_data() = delete;
+
///
/// @brief Less than operator
/// @param[in] i_rhs right hand comparison operator
@@ -1217,6 +1272,16 @@ struct mrs04_data
return iv_max_pd_mode < i_rhs.iv_max_pd_mode;
}
+ ///
+ /// @brief Equal to operator
+ /// @param[in] i_rhs right hand comparison operator
+ /// @bool true if this object is equal to i_rhs
+ ///
+ bool operator==(const mss::ddr4::mrs04_data& i_rhs) const
+ {
+ return !((*this < i_rhs) || (i_rhs < *this));
+ }
+
uint8_t iv_max_pd_mode;
uint8_t iv_temp_refresh_range;
uint8_t iv_temp_ref_mode;
@@ -1254,6 +1319,9 @@ struct mrs05_data
///
mrs05_data( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target, fapi2::ReturnCode& o_rc );
+ // Delete MRS05 default constructor
+ mrs05_data() = delete;
+
///
/// @brief Less than operator
/// @param[in] i_rhs right hand comparison operator
@@ -1317,6 +1385,16 @@ struct mrs05_data
return iv_ca_parity_latency < i_rhs.iv_ca_parity_latency;
}
+ ///
+ /// @brief Equal to operator
+ /// @param[in] i_rhs right hand comparison operator
+ /// @bool true if this object is equal to i_rhs
+ ///
+ bool operator==(const mss::ddr4::mrs05_data& i_rhs) const
+ {
+ return !((*this < i_rhs) || (i_rhs < *this));
+ }
+
uint8_t iv_ca_parity_latency;
uint8_t iv_crc_error_clear;
uint8_t iv_ca_parity_error_status;
@@ -1352,6 +1430,9 @@ struct mrs06_data
///
mrs06_data( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target, fapi2::ReturnCode& o_rc );
+ // Delete MRS06 default constructor
+ mrs06_data() = delete;
+
///
/// @brief Less than operator
/// @param[in] i_rhs right hand comparison operator
@@ -1388,6 +1469,16 @@ struct mrs06_data
return memcmp(iv_vrefdq_train_value, i_rhs.iv_vrefdq_train_value, sizeof(i_rhs.iv_vrefdq_train_value)) < MEMCMP_EQUAL;
}
+ ///
+ /// @brief Equal to operator
+ /// @param[in] i_rhs right hand comparison operator
+ /// @bool true if this object is equal to i_rhs
+ ///
+ bool operator==(const mss::ddr4::mrs06_data& i_rhs) const
+ {
+ return !((*this < i_rhs) || (i_rhs < *this));
+ }
+
uint8_t iv_vrefdq_train_value[MAX_RANK_PER_DIMM];
uint8_t iv_vrefdq_train_range[MAX_RANK_PER_DIMM];
uint8_t iv_vrefdq_train_enable[MAX_RANK_PER_DIMM];
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/pda.H b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/pda.H
index 271e90368..748907d44 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/pda.H
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/pda.H
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2017 */
+/* Contributors Listed Below - COPYRIGHT 2017,2018 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -208,7 +208,8 @@ class commands
public:
// Typdefs to make the code more readable
typedef std::pair<fapi2::Target<fapi2::TARGET_TYPE_DIMM>, uint64_t> rank_target;
- typedef std::map<D, std::vector<uint64_t> > mrs_drams;
+ typedef std::pair<D, std::vector<uint64_t> > mrs_dram;
+ typedef std::vector<mrs_dram> mrs_drams_vect;
///
/// @brief Base constructor
@@ -267,7 +268,57 @@ class commands
set_FUNCTION(mss::ffdc_function_codes::PDA_ADD_COMMAND),
"%s does not have rank %lu", mss::c_str(i_target), i_rank);
- iv_commands[ {i_target, i_rank}][i_mrs].push_back(i_dram);
+ // Does the compression
+ {
+ // If the rank/target pair does not exist simply insert a new pair
+ const rank_target RANK_TARGET = {i_target, i_rank};
+ // Note: technically this should be const auto to keep the iterator at the found position
+ // However, HB asumes that the const in front of the auto makes this a const_iterator
+ // Note: Find value from key prints an error if the key could not be found. We don't want that
+ // Rolling our own below
+ // TODO:RTC184689 Create find_iterator_from_value and find_iterator_from_key
+ auto l_it = std::find_if(iv_commands.begin(),
+ iv_commands.end(), [&RANK_TARGET](const std::pair<rank_target, mrs_drams_vect>& i_rhs)
+ {
+ return RANK_TARGET == i_rhs.first;
+ });
+
+ if( l_it == iv_commands.end() )
+ {
+ FAPI_INF("%s rank%lu NEW target rank info DRAM%lu", mss::c_str(i_target), i_rank, i_dram);
+ mrs_drams_vect l_mrs_dram = {{ i_mrs, { i_dram } }};
+ iv_commands.push_back( { RANK_TARGET, l_mrs_dram } );
+ }
+ // The rank/target exist
+ else
+ {
+ // Does the MRS exist?
+ auto& l_mrs_vect = l_it->second;
+ // Note: technically this should be const auto to keep the iterator at the found position
+ // However, HB asumes that the const in front of the auto makes this a const_iterator
+ // Note: Find value from key prints an error if the key could not be found. We don't want that
+ // Rolling our own below
+ // TODO:RTC184689 Create find_iterator_from_value and find_iterator_from_key
+ auto l_mrs_it = std::find_if(l_mrs_vect.begin(), l_mrs_vect.end(), [&i_mrs](const mrs_dram & i_rhs)
+ {
+ return i_mrs == i_rhs.first;
+ });
+
+ // No, add a new DRAM mapping
+ if( l_mrs_it == l_mrs_vect.end() )
+ {
+ FAPI_INF("%s rank%lu inserting new DRAM + MRS info DRAM%lu", mss::c_str(i_target), i_rank, i_dram);
+ const mrs_dram MRS_DRAM = { i_mrs, { i_dram } };
+ l_mrs_vect.push_back( MRS_DRAM );
+ }
+ // Yes, add a DRAM onto the vector
+ else
+ {
+ l_mrs_it->second.push_back( i_dram );
+ FAPI_INF("%s rank%lu pushing back DRAM%lu size %lu", mss::c_str(i_target), i_rank, i_dram, l_mrs_it->second.size());
+ }
+ }
+ }
fapi_try_exit:
return fapi2::current_err;
@@ -294,23 +345,24 @@ class commands
/// @brief Returns the command information
/// @return iv_commands
///
- inline const typename std::map<rank_target, mrs_drams>& get() const
+ inline const typename std::vector<std::pair<rank_target, mrs_drams_vect>>& get() const
{
return iv_commands;
}
private:
- // The following is a map of targets/DIMM as the key to a map of
+ // The following is a vector of target/DIMM pairs as the key to a vector of
// the MRS command as the key to the DRAM's to toggle. An explanation as to the data structure is included below
+ // Note: due to HB compile, a vector is used instead of a map
// PDA compression is a little complex, but is organized to allow us to minimize the number of commands run
- // Each individual map is designed to further minimize the number of commands run
- // The compressed commands consist of a map within a map
- // The outside map, maps the DIMM/rank to the MRS command and DRAM's that need to be run
+ // Each individual vector is designed to further minimize the number of commands run
+ // The compressed commands consist of a vector of pairs within a vector of pairs
+ // The outside vector, maps the DIMM/rank to the MRS command and DRAM's that need to be run
// Basically, it's a list of a specific rank target with all the commands that need to be run
// The rank-specific target information allows us to just issue the enter/exit commands for PDA for each rank once
// The MRS commands to the DRAM are then looped over in the inside loop
- // The inside map has a key of the MRS and a value of a vector of DRAM's to issue the MRS to
+ // The inside vector has a key of the MRS and a value of a vector of DRAM's to issue the MRS to
// CCS does not allow the user to toggle the DQ during an MRS command
// The DQ information is stored in separate registers in the PHY
// What this means for issuing the commands is that we have to issue an invocation of CCS for each different MRS command we issue
@@ -318,7 +370,7 @@ class commands
// Each invocation of CCS creates a noticable increase in time, as the registers need to be configured, CCS needs to be started, and we need to poll for done
// By only entering into PDA on a DIMM-rank once and by issuing the PDA MRS's to multiple DRAM's at a time, we can save a lot of runtime
// Note: in shmoo, adding the compression reduced runtime from about 13 minutes down to 3 minutes
- typename std::map<rank_target, mrs_drams> iv_commands;
+ typename std::vector<std::pair<rank_target, mrs_drams_vect>> iv_commands;
};
///
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 6e9c4398e..f6e77862b 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
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2016,2017 */
+/* Contributors Listed Below - COPYRIGHT 2016,2018 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -49,6 +49,8 @@
#include <lib/dimm/mrs_load.H>
#include <lib/shared/mss_kind.H>
#include <generic/memory/lib/spd/common/dimm_module_decoder.H>
+#include <lib/phy/dp16.H>
+#include <lib/mss_attribute_accessors_manual.H>
namespace mss
{
@@ -223,6 +225,35 @@ enum invalid_timing_function_encoding
/////////////////////////
///
+/// @brief Gets the JEDEC train and range values from the encoded VPD value
+/// @param[in] i_target - the DIMM target on which to operate
+/// @param[out] o_range - the JEDEC VREFDQ range
+/// @param[out] o_value - the JEDEC VREFDQ value
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
+///
+fapi2::ReturnCode get_vpd_wr_vref_range_and_value( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ uint8_t& o_range,
+ uint8_t& o_value )
+{
+ fapi2::buffer<uint8_t> l_vpd_value;
+ constexpr uint64_t VPD_TRAIN_RANGE_START = 1;
+ constexpr uint64_t VPD_TRAIN_VALUE_START = 2;
+ constexpr uint64_t VPD_TRAIN_VALUE_LEN = 6;
+
+ FAPI_TRY(mss::vpd_mt_vref_dram_wr(i_target, l_vpd_value));
+
+ o_range = l_vpd_value.getBit<VPD_TRAIN_RANGE_START>() ?
+ fapi2::ENUM_ATTR_EFF_VREF_DQ_TRAIN_RANGE_RANGE2 :
+ fapi2::ENUM_ATTR_EFF_VREF_DQ_TRAIN_RANGE_RANGE1;
+ l_vpd_value.extractToRight<VPD_TRAIN_VALUE_START, VPD_TRAIN_VALUE_LEN>(o_value);
+
+ FAPI_INF("%s JEDEC range 0x%02x JEDEC value 0x%02x", mss::c_str(i_target), o_range, o_value);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
/// @brief IBT helper - maps from VPD definition of IBT to the RCD control word bit fields
/// @param[in] i_ibt the IBT from VPD (e.g., 10, 15, ...), stored as 10% of original val (10 in VPD == 100 Ohms)
/// @return the IBT bit field e.g., 00, 01 ... (right aligned)
@@ -2449,25 +2480,24 @@ fapi_try_exit:
}
///
-/// @brief Determines & sets effective config for Vref DQ Train Value
+/// @brief Determines & sets effective config for Vref DQ Train Value and Range
/// @return fapi2::FAPI2_RC_SUCCESS if okay
+/// @note The value and range attributes are combined as offsetting the WR VREF percentage can cause both the value and range to shift
+/// The calculations would have to be done twice if the calculations were done separately. As such, they are combined below
///
-fapi2::ReturnCode eff_dimm::vref_dq_train_value()
+fapi2::ReturnCode eff_dimm::vref_dq_train_value_and_range()
{
+ // Taken from DDR4 (this attribute is DDR4 only) spec MRS6 section VrefDQ training: values table
+ constexpr uint8_t JEDEC_MAX_TRAIN_VALUE = 0b00110010;
uint8_t l_attrs_vref_dq_train_val[PORTS_PER_MCS][MAX_DIMM_PER_PORT][MAX_RANK_PER_DIMM] = {};
+ uint8_t l_attrs_vref_dq_train_range[PORTS_PER_MCS][MAX_DIMM_PER_PORT][MAX_RANK_PER_DIMM] = {};
std::vector< uint64_t > l_ranks;
- // value to set.
- fapi2::buffer<uint8_t> l_vpd_value;
+ // Gets the JEDEC VREFDQ range and value
fapi2::buffer<uint8_t> l_train_value;
- constexpr uint64_t VPD_TRAIN_VALUE_START = 2;
- constexpr uint64_t VPD_TRAIN_VALUE_LEN = 6;
- // Taken from DDR4 (this attribute is DDR4 only) spec MRS6 section VrefDQ training: values table
- constexpr uint8_t JEDEC_MAX_TRAIN_VALUE = 0b00110010;
-
- FAPI_TRY(mss::vpd_mt_vref_dram_wr(iv_dimm, l_vpd_value));
- l_vpd_value.extractToRight<VPD_TRAIN_VALUE_START, VPD_TRAIN_VALUE_LEN>(l_train_value);
+ fapi2::buffer<uint8_t> l_train_range;
+ FAPI_TRY(mss::get_vpd_wr_vref_range_and_value(iv_dimm, l_train_range, l_train_value));
FAPI_ASSERT(l_train_value <= JEDEC_MAX_TRAIN_VALUE,
fapi2::MSS_INVALID_VPD_VREF_DRAM_WR_RANGE()
@@ -2477,6 +2507,11 @@ fapi2::ReturnCode eff_dimm::vref_dq_train_value()
"%s VPD DRAM VREF value out of range max 0x%02x value 0x%02x", mss::c_str(iv_dimm),
JEDEC_MAX_TRAIN_VALUE, l_train_value );
+ // Updates the training values and ranges
+ FAPI_TRY(mss::dp16::wr_vref::offset_values(iv_mca, l_train_range, l_train_value),
+ "Failed to offset VPD WR VREF values %s", mss::c_str(iv_mca));
+
+
// Attribute to set num dimm ranks is a pre-requisite
FAPI_TRY( eff_vref_dq_train_value(iv_mcs, &l_attrs_vref_dq_train_val[0][0][0]) );
FAPI_TRY( mss::rank::ranks(iv_dimm, l_ranks) );
@@ -2484,11 +2519,15 @@ fapi2::ReturnCode eff_dimm::vref_dq_train_value()
for(const auto& l_rank : l_ranks)
{
l_attrs_vref_dq_train_val[iv_port_index][iv_dimm_index][index(l_rank)] = l_train_value;
+ l_attrs_vref_dq_train_range[iv_port_index][iv_dimm_index][index(l_rank)] = l_train_range;
}
FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_VREF_DQ_TRAIN_VALUE, iv_mcs, l_attrs_vref_dq_train_val),
"Failed setting attribute for ATTR_EFF_VREF_DQ_TRAIN_VALUE");
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_VREF_DQ_TRAIN_RANGE, iv_mcs, l_attrs_vref_dq_train_range),
+ "Failed setting attribute for ATTR_EFF_VREF_DQ_TRAIN_RANGE");
+
fapi_try_exit:
return fapi2::current_err;
}
@@ -2521,40 +2560,6 @@ fapi_try_exit:
}
///
-/// @brief Determines & sets effective config for Vref DQ Train Range
-/// @return fapi2::FAPI2_RC_SUCCESS if okay
-///
-fapi2::ReturnCode eff_dimm::vref_dq_train_range()
-{
-
- // Attribute to set num dimm ranks is a pre-requisite
- uint8_t l_attrs_vref_dq_train_range[PORTS_PER_MCS][MAX_DIMM_PER_PORT][MAX_RANK_PER_DIMM] = {};
- std::vector< uint64_t > l_ranks;
-
- // value to set.
- fapi2::buffer<uint8_t> l_vpd_value;
- fapi2::buffer<uint8_t> l_train_range;
- constexpr uint64_t VPD_TRAIN_RANGE_START = 1;
- FAPI_TRY(mss::vpd_mt_vref_dram_wr(iv_dimm, l_vpd_value));
- l_train_range = l_vpd_value.getBit<VPD_TRAIN_RANGE_START>();
-
- // gets the current value of train_range
- FAPI_TRY( eff_vref_dq_train_range(iv_mcs, &l_attrs_vref_dq_train_range[0][0][0]) );
- FAPI_TRY( mss::rank::ranks(iv_dimm, l_ranks) );
-
- for(const auto& l_rank : l_ranks)
- {
- l_attrs_vref_dq_train_range[iv_port_index][iv_dimm_index][index(l_rank)] = l_train_range;
- }
-
- FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_VREF_DQ_TRAIN_RANGE, iv_mcs, l_attrs_vref_dq_train_range),
- "Failed setting attribute for ATTR_EFF_VREF_DQ_TRAIN_RANGE");
-
-fapi_try_exit:
- return fapi2::current_err;
-}
-
-///
/// @brief Determines & sets effective config for CA Parity Latency
/// @return fapi2::FAPI2_RC_SUCCESS if okay
///
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/eff_dimm.H b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/eff_dimm.H
index b0de045ed..9b8b1780d 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/eff_dimm.H
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/eff_dimm.H
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2016,2017 */
+/* Contributors Listed Below - COPYRIGHT 2016,2018 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -40,6 +40,17 @@ namespace mss
{
///
+/// @brief Gets the JEDEC train and range values from the encoded VPD value
+/// @param[in] i_target - the DIMM target on which to operate
+/// @param[out] o_range - the JEDEC VREFDQ range
+/// @param[out] o_value - the JEDEC VREFDQ value
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
+///
+fapi2::ReturnCode get_vpd_wr_vref_range_and_value( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ uint8_t& o_range,
+ uint8_t& o_value );
+
+///
/// @class mss::dimm::eff_dimm
/// @brief A class made to perform eff_config functions based on the different dimm kinds (gen, type, buffer type)
/// @note this is a base class
@@ -484,15 +495,17 @@ class eff_dimm
///
/// @brief Determines & sets effective config for Output Buffer
/// @return fapi2::FAPI2_RC_SUCCESS if okay
+ /// @note The value and range attributes are combined as offsetting the WR VREF percentage can cause both the value and range to shift
+ /// The calculations would have to be done twice if the calculations were done separately. As such, they are combined below
///
fapi2::ReturnCode output_buffer();
///
- /// @brief Determines & sets effective config for Vref DQ Train Value
+ /// @brief Determines & sets effective config for Vref DQ Train Value and Range
/// @return fapi2::FAPI2_RC_SUCCESS if okay
///
- fapi2::ReturnCode vref_dq_train_value();
+ fapi2::ReturnCode vref_dq_train_value_and_range();
///
/// @brief Determines & sets effective config for Vref DQ Train Enable
@@ -501,12 +514,6 @@ class eff_dimm
fapi2::ReturnCode vref_dq_train_enable();
///
- /// @brief Determines & sets effective config for Vref DQ Train Range
- /// @return fapi2::FAPI2_RC_SUCCESS if okay
- ///
- fapi2::ReturnCode vref_dq_train_range();
-
- ///
/// @brief Determines & sets effective config for CA Parity Latency
/// @return fapi2::FAPI2_RC_SUCCESS if okay
///
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rank.H b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rank.H
index e5b3b9041..7cc82c5e5 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rank.H
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rank.H
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2015,2017 */
+/* Contributors Listed Below - COPYRIGHT 2015,2018 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -708,7 +708,7 @@ fapi2::ReturnCode get_dimm_target_from_rank(const fapi2::Target<T>& i_target,
/// @brief Given a target, get the rank pair assignments, based on DIMMs
/// @tparam T the fapi2::TargetType
/// @param[in] i_target the target (MCA or MBA?)
-/// @param[out] o_registers the regiter settings for the appropriate rank pairs
+/// @param[out] o_registers the register settings for the appropriate rank pairs
/// @return FAPI2_RC_SUCCESS if and only if ok
///
template< fapi2::TargetType T>
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/fir/check.C b/src/import/chips/p9/procedures/hwp/memory/lib/fir/check.C
index 7a329aaed..aef337cde 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/fir/check.C
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/fir/check.C
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2016,2017 */
+/* Contributors Listed Below - COPYRIGHT 2016,2018 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -225,7 +225,7 @@ fapi2::ReturnCode during_draminit_training( const fapi2::Target<fapi2::TARGET_TY
.set_PHY_FIR(l_phyfir_masked)
.set_DIMM_TARGET(i_target)
.set_MCA_TARGET(l_mca),
- "Initial CAL failed: Reporting FIR bits set for %s ( phy: 0x%016lx",
+ "Initial CAL failed: Reporting FIR bits set for %s ( phy: 0x%016lx )",
mss::c_str(i_target), l_phyfir_masked);
fapi_try_exit:
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/mss_attribute_accessors.H b/src/import/chips/p9/procedures/hwp/memory/lib/mss_attribute_accessors.H
index 0898e2903..fa1683bd2 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/mss_attribute_accessors.H
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/mss_attribute_accessors.H
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2016,2017 */
+/* Contributors Listed Below - COPYRIGHT 2016,2018 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -17556,6 +17556,27 @@ fapi_try_exit:
return fapi2::current_err;
}
+///
+/// @brief ATTR_MSS_WR_VREF_OFFSET getter
+/// @param[in] const ref to the TARGET_TYPE_MCBIST
+/// @param[out] int8_t& reference to store the value
+/// @note Generated by gen_accessors.pl generateParameters (NODIM A)
+/// @return fapi2::ReturnCode - FAPI2_RC_SUCCESS iff get is OK
+/// @note Offsets the WR VREF value from the VPD when creating the eff config WR VREF
+/// attributes.
+///
+inline fapi2::ReturnCode wr_vref_offset(const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target, int8_t& o_value)
+{
+
+ FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_MSS_WR_VREF_OFFSET, i_target, o_value) );
+ return fapi2::current_err;
+
+fapi_try_exit:
+ FAPI_ERR("failed accessing ATTR_MSS_WR_VREF_OFFSET: 0x%lx (target: %s)",
+ uint64_t(fapi2::current_err), mss::c_str(i_target));
+ return fapi2::current_err;
+}
+
///
/// @brief ATTR_EFF_DRAM_GEN getter
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/phy/dp16.C b/src/import/chips/p9/procedures/hwp/memory/lib/phy/dp16.C
index 3fabd4b4e..5522ec472 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/phy/dp16.C
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/phy/dp16.C
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2015,2017 */
+/* Contributors Listed Below - COPYRIGHT 2015,2018 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -1072,6 +1072,349 @@ const std::vector< std::vector<uint64_t> > dp16Traits<TARGET_TYPE_MCA>::RDCLK_RE
},
};
+const std::vector< std::vector<uint64_t> > dp16Traits<TARGET_TYPE_MCA>::WR_DQ_DELAY_REG =
+{
+ // RP0
+ {
+ // DP0
+ MCA_DP16_WR_DELAY_VALUE_0_RP0_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_1_RP0_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_2_RP0_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_3_RP0_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_4_RP0_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_5_RP0_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_6_RP0_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_7_RP0_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_8_RP0_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_9_RP0_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_10_RP0_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_11_RP0_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_12_RP0_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_13_RP0_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_14_RP0_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_15_RP0_REG_P0_0,
+
+ // DP1
+ MCA_DP16_WR_DELAY_VALUE_0_RP0_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_1_RP0_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_2_RP0_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_3_RP0_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_4_RP0_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_5_RP0_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_6_RP0_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_7_RP0_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_8_RP0_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_9_RP0_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_10_RP0_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_11_RP0_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_12_RP0_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_13_RP0_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_14_RP0_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_15_RP0_REG_P0_1,
+
+ // DP2
+ MCA_DP16_WR_DELAY_VALUE_0_RP0_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_1_RP0_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_2_RP0_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_3_RP0_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_4_RP0_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_5_RP0_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_6_RP0_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_7_RP0_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_8_RP0_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_9_RP0_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_10_RP0_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_11_RP0_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_12_RP0_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_13_RP0_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_14_RP0_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_15_RP0_REG_P0_2,
+
+ // DP3
+ MCA_DP16_WR_DELAY_VALUE_0_RP0_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_1_RP0_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_2_RP0_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_3_RP0_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_4_RP0_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_5_RP0_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_6_RP0_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_7_RP0_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_8_RP0_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_9_RP0_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_10_RP0_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_11_RP0_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_12_RP0_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_13_RP0_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_14_RP0_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_15_RP0_REG_P0_3,
+
+ // DP4
+ MCA_DP16_WR_DELAY_VALUE_0_RP0_REG_P0_4,
+ MCA_DP16_WR_DELAY_VALUE_1_RP0_REG_P0_4,
+ MCA_DP16_WR_DELAY_VALUE_2_RP0_REG_P0_4,
+ MCA_DP16_WR_DELAY_VALUE_3_RP0_REG_P0_4,
+ MCA_DP16_WR_DELAY_VALUE_4_RP0_REG_P0_4,
+ MCA_DP16_WR_DELAY_VALUE_5_RP0_REG_P0_4,
+ MCA_DP16_WR_DELAY_VALUE_6_RP0_REG_P0_4,
+ MCA_DP16_WR_DELAY_VALUE_7_RP0_REG_P0_4,
+ },
+
+ // RP1
+ {
+ // DP0
+ MCA_DP16_WR_DELAY_VALUE_0_RP1_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_1_RP1_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_2_RP1_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_3_RP1_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_4_RP1_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_5_RP1_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_6_RP1_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_7_RP1_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_8_RP1_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_9_RP1_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_10_RP1_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_11_RP1_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_12_RP1_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_13_RP1_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_14_RP1_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_15_RP1_REG_P0_0,
+
+ // DP1
+ MCA_DP16_WR_DELAY_VALUE_0_RP1_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_1_RP1_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_2_RP1_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_3_RP1_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_4_RP1_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_5_RP1_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_6_RP1_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_7_RP1_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_8_RP1_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_9_RP1_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_10_RP1_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_11_RP1_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_12_RP1_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_13_RP1_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_14_RP1_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_15_RP1_REG_P0_1,
+
+ // DP2
+ MCA_DP16_WR_DELAY_VALUE_0_RP1_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_1_RP1_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_2_RP1_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_3_RP1_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_4_RP1_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_5_RP1_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_6_RP1_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_7_RP1_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_8_RP1_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_9_RP1_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_10_RP1_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_11_RP1_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_12_RP1_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_13_RP1_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_14_RP1_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_15_RP1_REG_P0_2,
+
+ // DP3
+ MCA_DP16_WR_DELAY_VALUE_0_RP1_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_1_RP1_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_2_RP1_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_3_RP1_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_4_RP1_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_5_RP1_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_6_RP1_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_7_RP1_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_8_RP1_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_9_RP1_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_10_RP1_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_11_RP1_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_12_RP1_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_13_RP1_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_14_RP1_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_15_RP1_REG_P0_3,
+
+ // DP4
+ MCA_DP16_WR_DELAY_VALUE_0_RP1_REG_P0_4,
+ MCA_DP16_WR_DELAY_VALUE_1_RP1_REG_P0_4,
+ MCA_DP16_WR_DELAY_VALUE_2_RP1_REG_P0_4,
+ MCA_DP16_WR_DELAY_VALUE_3_RP1_REG_P0_4,
+ MCA_DP16_WR_DELAY_VALUE_4_RP1_REG_P0_4,
+ MCA_DP16_WR_DELAY_VALUE_5_RP1_REG_P0_4,
+ MCA_DP16_WR_DELAY_VALUE_6_RP1_REG_P0_4,
+ MCA_DP16_WR_DELAY_VALUE_7_RP1_REG_P0_4,
+ },
+
+ // RP2
+ {
+ // DP0
+ MCA_DP16_WR_DELAY_VALUE_0_RP2_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_1_RP2_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_2_RP2_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_3_RP2_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_4_RP2_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_5_RP2_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_6_RP2_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_7_RP2_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_8_RP2_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_9_RP2_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_10_RP2_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_11_RP2_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_12_RP2_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_13_RP2_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_14_RP2_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_15_RP2_REG_P0_0,
+
+ // DP1
+ MCA_DP16_WR_DELAY_VALUE_0_RP2_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_1_RP2_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_2_RP2_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_3_RP2_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_4_RP2_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_5_RP2_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_6_RP2_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_7_RP2_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_8_RP2_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_9_RP2_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_10_RP2_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_11_RP2_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_12_RP2_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_13_RP2_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_14_RP2_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_15_RP2_REG_P0_1,
+
+ // DP2
+ MCA_DP16_WR_DELAY_VALUE_0_RP2_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_1_RP2_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_2_RP2_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_3_RP2_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_4_RP2_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_5_RP2_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_6_RP2_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_7_RP2_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_8_RP2_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_9_RP2_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_10_RP2_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_11_RP2_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_12_RP2_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_13_RP2_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_14_RP2_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_15_RP2_REG_P0_2,
+
+ // DP3
+ MCA_DP16_WR_DELAY_VALUE_0_RP2_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_1_RP2_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_2_RP2_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_3_RP2_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_4_RP2_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_5_RP2_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_6_RP2_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_7_RP2_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_8_RP2_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_9_RP2_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_10_RP2_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_11_RP2_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_12_RP2_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_13_RP2_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_14_RP2_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_15_RP2_REG_P0_3,
+
+ // DP4
+ MCA_DP16_WR_DELAY_VALUE_0_RP2_REG_P0_4,
+ MCA_DP16_WR_DELAY_VALUE_1_RP2_REG_P0_4,
+ MCA_DP16_WR_DELAY_VALUE_2_RP2_REG_P0_4,
+ MCA_DP16_WR_DELAY_VALUE_3_RP2_REG_P0_4,
+ MCA_DP16_WR_DELAY_VALUE_4_RP2_REG_P0_4,
+ MCA_DP16_WR_DELAY_VALUE_5_RP2_REG_P0_4,
+ MCA_DP16_WR_DELAY_VALUE_6_RP2_REG_P0_4,
+ MCA_DP16_WR_DELAY_VALUE_7_RP2_REG_P0_4,
+ },
+
+ // RP3
+ {
+ // DP0
+ MCA_DP16_WR_DELAY_VALUE_0_RP3_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_1_RP3_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_2_RP3_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_3_RP3_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_4_RP3_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_5_RP3_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_6_RP3_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_7_RP3_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_8_RP3_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_9_RP3_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_10_RP3_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_11_RP3_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_12_RP3_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_13_RP3_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_14_RP3_REG_P0_0,
+ MCA_DP16_WR_DELAY_VALUE_15_RP3_REG_P0_0,
+
+ // DP1
+ MCA_DP16_WR_DELAY_VALUE_0_RP3_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_1_RP3_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_2_RP3_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_3_RP3_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_4_RP3_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_5_RP3_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_6_RP3_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_7_RP3_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_8_RP3_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_9_RP3_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_10_RP3_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_11_RP3_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_12_RP3_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_13_RP3_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_14_RP3_REG_P0_1,
+ MCA_DP16_WR_DELAY_VALUE_15_RP3_REG_P0_1,
+
+ // DP2
+ MCA_DP16_WR_DELAY_VALUE_0_RP3_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_1_RP3_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_2_RP3_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_3_RP3_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_4_RP3_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_5_RP3_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_6_RP3_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_7_RP3_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_8_RP3_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_9_RP3_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_10_RP3_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_11_RP3_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_12_RP3_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_13_RP3_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_14_RP3_REG_P0_2,
+ MCA_DP16_WR_DELAY_VALUE_15_RP3_REG_P0_2,
+
+ // DP3
+ MCA_DP16_WR_DELAY_VALUE_0_RP3_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_1_RP3_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_2_RP3_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_3_RP3_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_4_RP3_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_5_RP3_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_6_RP3_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_7_RP3_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_8_RP3_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_9_RP3_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_10_RP3_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_11_RP3_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_12_RP3_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_13_RP3_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_14_RP3_REG_P0_3,
+ MCA_DP16_WR_DELAY_VALUE_15_RP3_REG_P0_3,
+
+ // DP4
+ MCA_DP16_WR_DELAY_VALUE_0_RP3_REG_P0_4,
+ MCA_DP16_WR_DELAY_VALUE_1_RP3_REG_P0_4,
+ MCA_DP16_WR_DELAY_VALUE_2_RP3_REG_P0_4,
+ MCA_DP16_WR_DELAY_VALUE_3_RP3_REG_P0_4,
+ MCA_DP16_WR_DELAY_VALUE_4_RP3_REG_P0_4,
+ MCA_DP16_WR_DELAY_VALUE_5_RP3_REG_P0_4,
+ MCA_DP16_WR_DELAY_VALUE_6_RP3_REG_P0_4,
+ MCA_DP16_WR_DELAY_VALUE_7_RP3_REG_P0_4,
+ },
+};
+
///
/// @brief Given a RD_VREF value, create a PHY 'standard' bit field for that percentage.
/// @tparam T fapi2 Target Type - derived
@@ -2539,33 +2882,32 @@ fapi2::ReturnCode reset_wr_vref_config0( const fapi2::Target<TARGET_TYPE_MCA>& i
// traits definition
typedef dp16Traits<TARGET_TYPE_MCA> TT;
- // builds up the base register value
+ // Builds up the base register value by field for clarity, using characterized values that lead to the best results
fapi2::buffer<uint64_t> l_config0_data;
- l_config0_data.clearBit<TT::WR_VREF_CONFIG0_FULL_1D>()
- // TK putting hardcoded defaults here - revisit how to handle this (values should be obtained through characterization)
- // smallest available step size - algorithm adds 1 so this is a 1 not a 0
+ l_config0_data.setBit<TT::WR_VREF_CONFIG0_FULL_1D>()
+ // Smallest available step size - algorithm adds 1 so this is a 1 not a 0
.insertFromRight<TT::WR_VREF_CONFIG0_2D_SMALL_STEP_VAL, TT::WR_VREF_CONFIG0_2D_SMALL_STEP_VAL_LEN>(0b000)
- // step size of 4 - algorithm adds 1 so this is a 4, not a 3
- .insertFromRight<TT::WR_VREF_CONFIG0_2D_BIG_STEP_VAL, TT::WR_VREF_CONFIG0_2D_BIG_STEP_VAL_LEN>(0b0011)
- // for intermediary bits, skip all 7, aka only run one bit on each DRAM for intermediary bits
- .insertFromRight<TT::WR_VREF_CONFIG0_NUM_BITS_TO_SKIP, TT::WR_VREF_CONFIG0_NUM_BITS_TO_SKIP_LEN>(0b111)
- // run for two VREFs looking for an increase - this is register value + 1 to the algorithm, so it's a 1, not a 0
- .insertFromRight<TT::WR_VREF_CONFIG0_NUM_NO_INC_COMP, TT::WR_VREF_CONFIG0_NUM_NO_INC_COMP_LEN>(0b001);
+ // Big step size of 2 - algorithm adds 1 so the register setting is a 1
+ .insertFromRight<TT::WR_VREF_CONFIG0_2D_BIG_STEP_VAL, TT::WR_VREF_CONFIG0_2D_BIG_STEP_VAL_LEN>(0b0001)
+ // For intermediary bits, skip all 7, aka only run one bit on each DRAM for intermediary bits
+ .insertFromRight<TT::WR_VREF_CONFIG0_NUM_BITS_TO_SKIP, TT::WR_VREF_CONFIG0_NUM_BITS_TO_SKIP_LEN>(0b000)
+ // Run for the maximum number of VREFs looking for an increase
+ .insertFromRight<TT::WR_VREF_CONFIG0_NUM_NO_INC_COMP, TT::WR_VREF_CONFIG0_NUM_NO_INC_COMP_LEN>(0b111);
// Whether the 2D VREF is enabled or not varies by the calibration attribute
fapi2::buffer<uint32_t> l_cal_steps_enabled;
FAPI_TRY( mss::cal_step_enable(i_target, l_cal_steps_enabled) );
- // adds the information to the buffer
+ // Adds the information to the buffer
l_config0_data.writeBit<TT::WR_VREF_CONFIG0_1D_ONLY_SWITCH>(!l_cal_steps_enabled.getBit<WRITE_CTR_2D_VREF>());
- //blast out the scoms
+ // Blast out the scoms
FAPI_TRY( mss::scom_blastah(i_target, TT::WR_VREF_CONFIG0_REG, l_config0_data) );
- // return success
+ // Return success
return fapi2::FAPI2_RC_SUCCESS;
- // handle errors
+ // Handle errors
fapi_try_exit:
return fapi2::current_err;
}
@@ -3679,6 +4021,95 @@ fapi_try_exit:
return fapi2::current_err;
}
+namespace wr_vref
+{
+
+///
+/// @brief Gets the WR VREF range based upon the composite range
+/// @param[in] i_value the composite range value
+/// @return l_range the JEDEC WR VREF range
+///
+uint8_t get_range(const uint64_t i_value)
+{
+ // According to JEDEC range 1 uses a 0 and range 2 uses a 1
+ constexpr uint64_t RANGE1 = 0x00;
+ constexpr uint64_t RANGE2 = 0x01;
+ const uint8_t l_range = ((i_value >= WR_VREF_CROSSOVER_RANGE) ? RANGE1 : RANGE2);
+ return l_range;
+}
+
+///
+/// @brief Gets the WR VREF value based upon the composite range
+/// @param[in] i_value the composite range value
+/// @return l_range the JEDEC WR VREF value
+///
+uint8_t get_value(const uint64_t i_value)
+{
+ // Subtract out the crossover range if need be
+ // Remember, the JEDEC range overlaps for a number of VREFs
+ // The crossover range is used to offset the start of the JEDEC range that is higher than the other
+ const uint8_t l_value = ((i_value >= WR_VREF_CROSSOVER_RANGE) ?
+ (i_value - WR_VREF_CROSSOVER_RANGE) : (i_value));
+ return l_value;
+}
+
+///
+/// @brief Gets the WR VREF value based upon the inputted values
+/// @param[in] i_range the JEDEC range to use
+/// @param[in] i_value the JEDED value to use
+/// @return l_range the JEDEC WR VREF value
+///
+uint64_t compute_composite_value(const uint64_t i_range, const uint64_t i_value)
+{
+ // Add in the crossover range if need be
+ // Remember, the JEDEC range overlaps for a number of VREFs
+ // The crossover range is used to offset the start of the JEDEC range that is higher than the other
+ constexpr uint64_t USE_CROSSOVER_RANGE = 0;
+ return i_value + ((i_range == USE_CROSSOVER_RANGE) ? WR_VREF_CROSSOVER_RANGE : 0);
+}
+
+///
+/// @brief Offsets the WR VREF train and range values based upon the offset attribute
+/// @param[in] i_target the fapi2 target of the port
+/// @param[in,out] io_train_range - train range value to update
+/// @param[in,out] io_train_value - train range value to update
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
+///
+fapi2::ReturnCode offset_values( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ uint8_t& io_train_range,
+ uint8_t& io_train_value )
+{
+ const auto& l_mcs = mss::find_target<fapi2::TARGET_TYPE_MCS>(i_target);
+ // Computing the composite range simplifies the logic for offsetting a WR VREF range and value
+ int64_t l_composite = compute_composite_value(io_train_range, io_train_value);
+
+ int8_t l_offset = 0;
+ FAPI_TRY( mss::wr_vref_offset(mss::find_target<fapi2::TARGET_TYPE_MCBIST>(i_target), l_offset) );
+ l_composite += l_offset;
+
+ // Check that the value is in range
+ FAPI_ASSERT( (l_composite >= 0) && (l_composite <= WR_VREF_MAX_COMPOSITE_RANGE),
+ fapi2::MSS_OFFSET_WR_VREF_OUT_OF_RANGE()
+ .set_TARGET(i_target)
+ .set_MCS_TARGET(l_mcs)
+ .set_MAX(WR_VREF_MAX_COMPOSITE_RANGE)
+ .set_OFFSET(l_offset)
+ .set_COMPOSITE(l_composite),
+ "%s Offset composite range is out of bounds (%d - %d): %d offset is: %d",
+ mss::c_str(i_target),
+ 0,
+ WR_VREF_MAX_COMPOSITE_RANGE,
+ l_composite,
+ l_offset );
+
+ io_train_range = get_range(l_composite);
+ io_train_value = get_value(l_composite);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+} // close namespace wr_vref
} // close namespace dp16
} // close namespace mss
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/phy/dp16.H b/src/import/chips/p9/procedures/hwp/memory/lib/phy/dp16.H
index 238eaa3dc..e36b5969a 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/phy/dp16.H
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/phy/dp16.H
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2015,2017 */
+/* Contributors Listed Below - COPYRIGHT 2015,2018 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -196,6 +196,9 @@ class dp16Traits<fapi2::TARGET_TYPE_MCA>
static const std::vector< std::pair<uint64_t, uint64_t> > WR_VREF_VALUE_RP2_REG;
static const std::vector< std::pair<uint64_t, uint64_t> > WR_VREF_VALUE_RP3_REG;
+ // WR DQ delay registers - in terms of rank pair, then bit
+ static const std::vector< std::vector<uint64_t> > WR_DQ_DELAY_REG;
+
static const std::vector< uint64_t > RD_DIA_CONFIG5_REG;
static const std::vector< uint64_t > DATA_BIT_ENABLE0_REG;
static const std::vector< uint64_t > DATA_BIT_ENABLE1_REG;
@@ -379,6 +382,13 @@ class dp16Traits<fapi2::TARGET_TYPE_MCA>
WR_VREF_VALUE_VALUE_DRAM_ODD = MCA_DDRPHY_DP16_WR_VREF_VALUE0_RANK_PAIR0_P0_0_01_VALUE_DRAM1 ,
WR_VREF_VALUE_VALUE_DRAM_ODD_LEN = MCA_DDRPHY_DP16_WR_VREF_VALUE0_RANK_PAIR0_P0_0_01_VALUE_DRAM1_LEN ,
+ // Write delay fields
+ WR_DELAY = MCA_DP16_WR_DELAY_VALUE_0_RP0_REG_P0_0_01_DELAYG,
+ WR_DELAY_LEN = MCA_DP16_WR_DELAY_VALUE_0_RP0_REG_P0_0_01_DELAYG_LEN,
+
+ // Bit disable field start
+ BIT_DISABLE = MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP0_P0_0_01_DISABLE_15,
+
// Read Delay fields.
READ_OFFSET_LOWER = MCA_DDRPHY_DP16_READ_DELAY_OFFSET0_RANK_PAIR0_P0_0_01,
READ_OFFSET_LOWER_LEN = MCA_DDRPHY_DP16_READ_DELAY_OFFSET0_RANK_PAIR0_P0_0_01_LEN,
@@ -2316,6 +2326,42 @@ fapi_try_exit:
return fapi2::current_err;
}
+namespace wr_vref
+{
+
+///
+/// @brief Gets the WR VREF range based upon the composite range
+/// @param[in] i_value the composite range value
+/// @return l_range the JEDEC WR VREF range
+///
+uint8_t get_range(const uint64_t i_value);
+
+///
+/// @brief Gets the WR VREF value based upon the composite range
+/// @param[in] i_value the composite range value
+/// @return l_range the JEDEC WR VREF value
+///
+uint8_t get_value(const uint64_t i_value);
+
+///
+/// @brief Gets the WR VREF value based upon the inputted values
+/// @param[in] i_range the JEDEC range to use
+/// @param[in] i_value the JEDED value to use
+/// @return l_range the JEDEC WR VREF value
+///
+uint64_t compute_composite_value(const uint64_t i_range, const uint64_t i_value);
+
+///
+/// @brief Offsets the WR VREF train and range values based upon the offset attribute
+/// @param[in] i_target the fapi2 target of the port
+/// @param[in,out] io_train_range - train range value to update
+/// @param[in,out] io_train_value - train range value to update
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
+///
+fapi2::ReturnCode offset_values( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ uint8_t& io_train_range,
+ uint8_t& io_train_value );
+} // close namespace wr_vref
} // close namespace dp16
} // close namespace mss
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/phy/mss_training.C b/src/import/chips/p9/procedures/hwp/memory/lib/phy/mss_training.C
index c7438b096..06131bd61 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/phy/mss_training.C
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/phy/mss_training.C
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2017 */
+/* Contributors Listed Below - COPYRIGHT 2017,2018 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -53,6 +53,7 @@
#include <lib/utils/count_dimm.H>
#include <lib/dimm/rank.H>
#include <lib/shared/mss_const.H>
+#include <lib/dimm/ddr4/pda.H>
namespace mss
{
@@ -468,17 +469,18 @@ uint64_t read_ctr::calculate_cycles( const fapi2::Target<fapi2::TARGET_TYPE_MCA>
return l_read_ctr_cycles + rc::vref_guess_time(i_target);
}
-
///
-/// @brief Sets up and runs the calibration step
+/// @brief Sets up and runs the calibration step according to an external 1D vs 2D input
/// @param[in] i_target - the MCA target on which to operate
/// @param[in] i_rp - the rank pair
/// @param[in] i_abort_on_error - whether or not we are aborting on cal error
+/// @param[in] i_wr_vref - true IFF write VREF calibration needs to be run
/// @return fapi2::ReturnCode fapi2::FAPI2_RC_SUCCESS iff ok
///
fapi2::ReturnCode write_ctr::run( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
const uint64_t i_rp,
- const uint8_t i_abort_on_error ) const
+ const uint8_t i_abort_on_error,
+ const bool i_wr_vref ) const
{
typedef mss::dp16Traits<fapi2::TARGET_TYPE_MCA> TT;
std::vector<fapi2::buffer<uint64_t>> l_wr_vref_config;
@@ -489,7 +491,7 @@ fapi2::ReturnCode write_ctr::run( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i
{
// 0: Run only the VREF (2D) write centering algorithm
// 1: Run only the 1D
- l_data.writeBit<TT::WR_VREF_CONFIG0_1D_ONLY_SWITCH>(!iv_wr_vref);
+ l_data.writeBit<TT::WR_VREF_CONFIG0_1D_ONLY_SWITCH>(!i_wr_vref);
}
FAPI_TRY(mss::scom_blastah(i_target, TT::WR_VREF_CONFIG0_REG, l_wr_vref_config));
@@ -501,6 +503,231 @@ fapi_try_exit:
}
///
+/// @brief Sets up and runs the calibration step
+/// @param[in] i_target - the MCA target on which to operate
+/// @param[in] i_rp - the rank pair
+/// @param[in] i_abort_on_error - whether or not we are aborting on cal error
+/// @return fapi2::ReturnCode fapi2::FAPI2_RC_SUCCESS iff ok
+///
+fapi2::ReturnCode write_ctr::run( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_rp,
+ const uint8_t i_abort_on_error ) const
+{
+ return run(i_target, i_rp, i_abort_on_error, iv_wr_vref);
+}
+
+///
+/// @brief Executes the pre-cal step workaround
+/// @param[in] i_target - the MCA target on which to operate
+/// @param[in] i_rp - the rank pair
+/// @param[in] i_abort_on_error - whether or not we are aborting on cal error
+/// @return fapi2::ReturnCode fapi2::FAPI2_RC_SUCCESS iff ok
+///
+fapi2::ReturnCode write_ctr::pre_workaround( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_rp,
+ const uint8_t i_abort_on_error ) const
+{
+ iv_dram_to_check.clear();
+
+ // Only add DRAMs to check if:
+ // 1) WR VREF is enabled
+ // 2) the part is a DD2 or above
+ if(iv_wr_vref && (!mss::chip_ec_nimbus_lt_2_0(i_target)))
+ {
+ FAPI_INF("%s checking for clear DRAMs", mss::c_str(i_target));
+ uint64_t l_num_dram = 0;
+
+ uint8_t l_width[MAX_DIMM_PER_PORT] = {};
+ FAPI_TRY( mss::eff_dram_width(i_target, l_width) );
+ l_num_dram = (l_width[0] == fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X8) ? MAX_DRAMS_X8 : MAX_DRAMS_X4;
+
+ // Loops through all the DRAM and adds them to be checked if they are clean of any bad bits
+ // We only want to run the workaround on an entirely clean DRAM that goes bad
+ // If we have a DRAM that already has bad bit(s), there could be something else going on and the workaround will not help or could make matters worse
+ for(uint64_t l_dram = 0; l_dram < l_num_dram; l_dram++)
+ {
+ bool l_has_disables = false;
+
+ FAPI_TRY(mss::workarounds::dp16::wr_vref::dram_has_disables(i_target, i_rp, l_dram, l_has_disables));
+
+ FAPI_INF("%s RP%lu DRAM%lu Disables? %s", mss::c_str(i_target), i_rp, l_dram, l_has_disables ? "yes" : "no");
+
+ // If there are no disables, then we need to check the DRAM
+ if(!l_has_disables)
+ {
+ // Gets the starting WR DQ delay for the DRAM
+ uint64_t l_value = 0;
+
+ FAPI_TRY(mss::workarounds::dp16::wr_vref::get_starting_wr_dq_delay(i_target, i_rp, l_dram, l_value));
+
+ iv_dram_to_check.push_back({l_dram, l_value});
+ }
+ }
+ }
+ else
+ {
+ FAPI_INF("%s workaround is not being run. WR VREF: %s chip version: %s", mss::c_str(i_target),
+ iv_wr_vref ? "enabled" : "disabled", mss::chip_ec_nimbus_lt_2_0(i_target) ? "DD1" : "DD2");
+ }
+
+ return fapi2::FAPI2_RC_SUCCESS;
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Executes the post-cal step workaround
+/// @param[in] i_target - the MCA target on which to operate
+/// @param[in] i_rp - the rank pair
+/// @param[in] i_abort_on_error - whether or not we are aborting on cal error
+/// @return fapi2::ReturnCode fapi2::FAPI2_RC_SUCCESS iff ok
+///
+fapi2::ReturnCode write_ctr::post_workaround( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_rp,
+ const uint8_t i_abort_on_error ) const
+{
+ // Loops through the DRAMs to check and creates a vector of bad DRAMs and their associated starting delays
+ std::vector<std::pair<uint64_t, uint64_t>> l_bad_drams;
+
+ // Checking all of the DRAMs that had been good before WR VREF
+ // If any of them have gone bad, then note it and run the workaround
+ for(const auto l_pair : iv_dram_to_check)
+ {
+ const auto l_dram = l_pair.first;
+ const auto l_delay = l_pair.second;
+ bool l_is_bad = false;
+ FAPI_TRY(mss::workarounds::dp16::wr_vref::is_dram_disabled(i_target, i_rp, l_dram, l_is_bad));
+
+ // If we have a bad DRAM, note it and add it to the DRAM to test
+ if(l_is_bad)
+ {
+ FAPI_INF("%s RP%lu DRAM%lu is bad! Workaround will be run on it", mss::c_str(i_target), i_rp, l_dram);
+ l_bad_drams.push_back({l_dram, l_delay});
+ }
+ }
+
+ iv_dram_to_check.clear();
+
+ // Only run the rest of the workaround if we have any bad DRAMs
+ if(l_bad_drams.size() > 0)
+ {
+ fapi2::Target<fapi2::TARGET_TYPE_DIMM> l_dimm;
+ std::vector<uint64_t> l_ranks;
+
+ // Gets the ranks on which to latch the VREF's
+ FAPI_TRY(mss::rank::get_ranks_in_pair( i_target, i_rp, l_ranks));
+
+ // If the rank vector is empty log an error
+ FAPI_ASSERT(!l_ranks.empty(),
+ fapi2::MSS_INVALID_RANK().
+ set_MCA_TARGET(i_target).
+ set_RANK(i_rp).
+ set_FUNCTION(mss::ffdc_function_codes::WR_VREF_TRAINING_WORKAROUND),
+ "%s rank pair is empty! %lu", mss::c_str(i_target), i_rp);
+
+ FAPI_ASSERT(l_ranks[0] != NO_RANK,
+ fapi2::MSS_INVALID_RANK().
+ set_MCA_TARGET(i_target).
+ set_RANK(NO_RANK).
+ set_FUNCTION(mss::ffdc_function_codes::WR_VREF_TRAINING_WORKAROUND),
+ "%s rank pair has no ranks %lu", mss::c_str(i_target), i_rp);
+
+ // Ensures we get a valid DIMM target / rank combo
+ FAPI_TRY( mss::rank::get_dimm_target_from_rank(i_target, l_ranks[0], l_dimm),
+ "%s Failed get_dimm_target_from_rank in write_ctr::post_workaround",
+ mss::c_str(i_target));
+
+ // Assembles the PDA container and fixes the disables
+ {
+ mss::ddr4::pda::commands<mss::ddr4::mrs06_data> l_container;
+
+ // Loops through and sets up all the data needed the workaround
+ for(const auto& l_pair : l_bad_drams )
+ {
+ const auto l_dram = l_pair.first;
+ const auto l_delay = l_pair.second;
+
+ // Adds in the PDA necessary for the latching commands
+ fapi2::ReturnCode l_rc(fapi2::FAPI2_RC_SUCCESS);
+ mss::ddr4::mrs06_data l_mrs(l_dimm, l_rc);
+ FAPI_TRY(l_rc, "%s failed to create MRS06 data class", mss::c_str(l_dimm));
+
+ // Updates the MRS06 settings to have the proper VREF settings
+ FAPI_TRY(mss::workarounds::dp16::wr_vref::modify_mrs_vref_to_vpd( l_dimm, l_mrs));
+
+ FAPI_TRY(l_container.add_command(l_dimm, l_ranks[0], l_mrs, l_dram));
+
+ // Updates the WR VREF value in the DP
+ FAPI_TRY(mss::workarounds::dp16::wr_vref::configure_wr_vref_to_nominal( l_dimm, i_rp, l_dram));
+
+ // Restores the known good values for WR DQ delays
+ FAPI_TRY(mss::workarounds::dp16::wr_vref::reset_wr_dq_delay( i_target, i_rp, l_dram, l_delay ));
+
+ // Clears the disable bits for PDA latching
+ FAPI_TRY(mss::workarounds::dp16::wr_vref::clear_dram_disable_bits( i_target, i_rp, l_dram ));
+ }
+
+ // Latches the failing DRAM's originally good values out to the DRAMs with PDA
+ FAPI_TRY(mss::ddr4::pda::execute_wr_vref_latch(l_container));
+
+ // Disabling bits prior to PDA could cause issues with DRAM latching in the VREF values
+ // As such, we're setting disable bits after latching PDA
+ for(const auto& l_pair : l_bad_drams )
+ {
+ const auto l_dram = l_pair.first;
+ FAPI_TRY(mss::workarounds::dp16::wr_vref::disable_bits( i_target, i_rp, l_dram));
+ }
+ }
+
+ FAPI_TRY(mss::workarounds::dp16::wr_vref::configure_skip_bits( i_target ));
+
+ // Re-runs WR VREF calibration
+ FAPI_TRY(run( i_target,
+ i_rp,
+ i_abort_on_error,
+ true ));
+
+ // Clears the training FIR's
+ FAPI_TRY(mss::workarounds::dp16::wr_vref::clear_training_firs( i_target ));
+
+ // If the DRAM's are still bad, exit
+ for(const auto& l_pair : l_bad_drams )
+ {
+ bool l_is_bad = false;
+ const auto l_dram = l_pair.first;
+
+ FAPI_TRY(mss::workarounds::dp16::wr_vref::is_dram_disabled(i_target, i_rp, l_dram, l_is_bad));
+
+ if(l_is_bad)
+ {
+ FAPI_INF("%s RP%lu found DRAM%lu as bad after the second run of WR VREF! Exiting and letting ECC clean this up",
+ mss::c_str(i_target), i_rp, l_dram);
+ }
+ else
+ {
+ FAPI_INF("%s RP%lu found DRAM%lu as recovered after the second run of WR VREF! Restoring disable bits and running WR CTR 1D calibration",
+ mss::c_str(i_target), i_rp, l_dram);
+ FAPI_TRY(mss::workarounds::dp16::wr_vref::clear_dram_disable_bits( i_target, i_rp, l_dram ));
+ }
+
+ // Logs the results for this DRAM
+ // Note: always logged as recovered, as we want this to be informational
+ FAPI_TRY(mss::workarounds::dp16::wr_vref::log_dram_results(i_target, i_rp, l_dram, l_is_bad));
+ }
+
+ // Re-runs WR VREF
+ FAPI_TRY(run( i_target,
+ i_rp,
+ i_abort_on_error,
+ false ));
+ }
+
+ return fapi2::FAPI2_RC_SUCCESS;
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
/// @brief Calculates the number of cycles a given calibration step will take
/// @param[in] i_target - the MCA target on which to operate
/// @return l_cycles - the number of cycles a given calibration step wil take
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/phy/mss_training.H b/src/import/chips/p9/procedures/hwp/memory/lib/phy/mss_training.H
index 37f756098..69372ef85 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/phy/mss_training.H
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/phy/mss_training.H
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2017 */
+/* Contributors Listed Below - COPYRIGHT 2017,2018 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -580,6 +580,28 @@ class write_ctr : public phy_step
const uint8_t i_abort_on_error ) const override;
///
+ /// @brief Executes the pre-cal step workaround
+ /// @param[in] i_target - the MCA target on which to operate
+ /// @param[in] i_rp - the rank pair
+ /// @param[in] i_abort_on_error - whether or not we are aborting on cal error
+ /// @return fapi2::ReturnCode fapi2::FAPI2_RC_SUCCESS iff ok
+ ///
+ fapi2::ReturnCode pre_workaround( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_rp,
+ const uint8_t i_abort_on_error ) const override;
+
+ ///
+ /// @brief Executes the post-cal step workaround
+ /// @param[in] i_target - the MCA target on which to operate
+ /// @param[in] i_rp - the rank pair
+ /// @param[in] i_abort_on_error - whether or not we are aborting on cal error
+ /// @return fapi2::ReturnCode fapi2::FAPI2_RC_SUCCESS iff ok
+ ///
+ fapi2::ReturnCode post_workaround( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_rp,
+ const uint8_t i_abort_on_error ) const override;
+
+ ///
/// @brief Calculates the number of cycles a given calibration step will take
/// @param[in] i_target - the MCA target on which to operate
/// @return l_cycles - the number of cycles a given calibration step wil take
@@ -597,6 +619,24 @@ class write_ctr : public phy_step
private:
bool iv_wr_vref;
+ // Contains all information related to any DRAMs that were disabled due to the WR VREF algorithm
+ // The pair contains the following information:
+ // first -> the DRAM's number to test
+ // second -> the DRAM's starting write delay value
+ mutable std::vector<std::pair<uint64_t, uint64_t>> iv_dram_to_check;
+
+ ///
+ /// @brief Sets up and runs the calibration step according to an external 1D vs 2D input
+ /// @param[in] i_target - the MCA target on which to operate
+ /// @param[in] i_rp - the rank pair
+ /// @param[in] i_abort_on_error - whether or not we are aborting on cal error
+ /// @param[in] i_wr_vref - true IFF write VREF calibration needs to be run
+ /// @return fapi2::ReturnCode fapi2::FAPI2_RC_SUCCESS iff ok
+ ///
+ fapi2::ReturnCode run( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_rp,
+ const uint8_t i_abort_on_error,
+ const bool i_wr_vref ) const;
};
///
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/shared/mss_const.H b/src/import/chips/p9/procedures/hwp/memory/lib/shared/mss_const.H
index eabb67fb9..4aa8db4cf 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/shared/mss_const.H
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/shared/mss_const.H
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2015,2017 */
+/* Contributors Listed Below - COPYRIGHT 2015,2018 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -51,11 +51,12 @@ enum sizes
MCBIST_PER_MC = 1,
MAX_DIMM_PER_PORT = 2,
MAX_RANK_PER_DIMM = 4,
- BYTES_PER_DP = 2,
- NIBBLES_PER_DP = 4,
NIBBLES_PER_BYTE = 2,
BITS_PER_NIBBLE = 4,
BITS_PER_BYTE = 8,
+ BITS_PER_DP = 16,
+ NIBBLES_PER_DP = BITS_PER_DP / BITS_PER_NIBBLE,
+ BYTES_PER_DP = BITS_PER_DP / BITS_PER_BYTE,
BITS_PER_DQS = 2, ///< Differential clock pair
MAX_RANKS_DIMM1 = 2, ///< DIMM1 (inner DIMM) can't be a 4R DIMM
MAX_PRIMARY_RANKS_PER_PORT = 4,
@@ -87,6 +88,14 @@ enum sizes
WR_LVL_PRE_DLY = 0b101010,
WR_LVL_NUM_VALID_SAMPLES = 0x5,
+ // WR VREF JEDEC values - we're using em in multiple places, so let's define them in one
+ // Single range max is the maximum range for a single WR VREF range in JEDEC - 0b110010
+ WR_VREF_SINGLE_RANGE_MAX = 0b110010,
+ // Crossover range is where the top of Range 2 (the lower range) equals the bottom of Range 1 (the upper range)
+ WR_VREF_CROSSOVER_RANGE = 0b011000,
+ // Max range is computed from single range max (50) + the crossover range (24)
+ WR_VREF_MAX_COMPOSITE_RANGE = WR_VREF_SINGLE_RANGE_MAX + WR_VREF_CROSSOVER_RANGE,
+
// Attribute? BRS
COARSE_CAL_STEP_SIZE = 0x4,
CONSEQ_PASS = 0x8,
@@ -166,6 +175,14 @@ enum ffdc_function_codes
PDA_WR_VREF_LATCH_CONTAINER = 80,
PDA_WR_VREF_LATCH_VECTOR = 81,
PDA_ADD_COMMAND = 82,
+
+ // WR VREF workaround functions
+ WR_VREF_TRAINING_WORKAROUND = 90,
+ CONFIGURE_WR_VREF_TO_NOMINAL = 91,
+ RESET_WR_DQ_DELAY = 92,
+ READ_RD_VREF_VALUES_FOR_DRAM = 93,
+ GET_DRAM_DISABLE_REG_AND_POS = 94,
+ GET_STARTING_WR_DQ_DELAY_VALUE = 95,
};
enum states
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/dp16_workarounds.C b/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/dp16_workarounds.C
index 1ed664574..e67b4dc0f 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/dp16_workarounds.C
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/dp16_workarounds.C
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2016,2017 */
+/* Contributors Listed Below - COPYRIGHT 2016,2018 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -49,6 +49,8 @@
#include <lib/dimm/rank.H>
#include <lib/utils/bit_count.H>
#include <lib/fir/check.H>
+#include <lib/dimm/ddr4/mrs_load_ddr4.H>
+#include <lib/dimm/eff_dimm.H>
namespace mss
{
@@ -1077,7 +1079,6 @@ fapi2::ReturnCode get_delay_data(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_
MCA_DDRPHY_DP16_READ_DELAY3_RANK_PAIR3_P0_4,
},
};
-
// Bombs out if the rank pair is out of range
FAPI_ASSERT( i_rank_pair < MAX_RANK_PAIRS,
@@ -1115,6 +1116,7 @@ fapi2::ReturnCode get_delay_data(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_
fapi_try_exit:
return fapi2::current_err;
}
+
///
/// @brief Finds the median and sorts the vector
/// @param[in,out] io_reg_data register data
@@ -1127,21 +1129,17 @@ fapi2::ReturnCode find_median_and_sort(std::vector<delay_data>& io_reg_data, uin
// The fapi_try is in an if statement, this ensures we have a good value
fapi2::current_err = fapi2::FAPI2_RC_SUCCESS;
- // Bomb out if the vector is empty to avoid accessing a non-existant element
- FAPI_ASSERT(!io_reg_data.empty(),
- fapi2::MSS_RD_CTR_WORKAROUND_EMPTY_VECTOR(),
- "Empty vector passed in to find_median_and_sort"
- );
+ // Note: the null constructor is deleted
+ // We need to return the data value, so we're creating a temporary variable with 0's for it's values to get the median positon
+ // Below, we'll get the data and return it to o_median
+ delay_data l_temp(0, 0, 0);
// Sorts first
std::sort(io_reg_data.begin(), io_reg_data.end());
- // TODO:RTC172759 Add generic median function - that can replace the below code
- // Finding the median is simply a matter of finding the midway point and getting the data there
- {
- const auto l_median_it = io_reg_data.begin() + io_reg_data.size() / 2;
- o_median = l_median_it->iv_data;
- }
+ // Returns the median value
+ FAPI_TRY(find_median(io_reg_data, l_temp));
+ o_median = l_temp.iv_data;
fapi_try_exit:
return fapi2::current_err;
@@ -1558,6 +1556,644 @@ fapi_try_exit:
return fapi2::current_err;
}
+///
+/// @brief Checks that the rank pair and DRAM are in bounds
+/// @param[in] i_target - the MCA target on which to operate
+/// @param[in] i_rp - the rank pair on which to operate
+/// @param[in] i_dram - the DRAM that needs to have the workaround applied to it
+/// @param[in] i_function - the calling function to callout in FFDC
+///
+fapi2::ReturnCode check_rp_and_dram( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_rp,
+ const uint64_t i_dram,
+ const ffdc_function_codes i_function )
+{
+ fapi2::current_err = fapi2::FAPI2_RC_SUCCESS;
+
+ // Checks inputs
+ uint8_t l_width[MAX_DIMM_PER_PORT] = {};
+ FAPI_TRY( mss::eff_dram_width(i_target, l_width) );
+
+ // Checks for DRAM in bounds
+ {
+ const uint64_t MAX_NUM_DRAM = l_width[0] == fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X8 ? MAX_DRAMS_X8 : MAX_DRAMS_X4;
+ FAPI_ASSERT(i_dram < MAX_NUM_DRAM,
+ fapi2::MSS_INVALID_INDEX_PASSED()
+ .set_INDEX(i_dram)
+ .set_FUNCTION(i_function),
+ "%s Invalid DRAM index passed to check_for_dram_disabled (%d)",
+ mss::c_str(i_target),
+ i_dram);
+ }
+
+ // Checks for i_rp in bounds
+ FAPI_ASSERT(i_rp < MAX_RANK_PAIRS,
+ fapi2::MSS_INVALID_RANK().
+ set_MCA_TARGET(i_target).
+ set_RANK(i_rp).
+ set_FUNCTION(i_function),
+ "%s rank pair is out of bounds %lu", mss::c_str(i_target), i_rp);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Gets the disable register and bit position for the DRAM
+/// @param[in] i_target the fapi2 target type MCA of the port
+/// @param[in] i_rp - rank pair to check and modify
+/// @param[in] i_dram - the DRAM to be checked
+/// @param[out] o_reg - the register to access from
+/// @param[out] o_bit_pos - the bit position in the register to access from
+/// @param[out] o_bit_len - the bit length to access
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
+///
+fapi2::ReturnCode get_disable_reg_and_pos_for_dram( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_rp,
+ const uint64_t i_dram,
+ uint64_t& o_reg,
+ uint64_t& o_bit_pos,
+ uint64_t& o_bit_len)
+{
+ // Gets the DRAM width
+ uint8_t l_width[MAX_DIMM_PER_PORT] = {};
+ FAPI_TRY( mss::eff_dram_width(i_target, l_width) );
+
+ // Checks inputs
+ FAPI_TRY(check_rp_and_dram(i_target,
+ i_rp,
+ i_dram,
+ ffdc_function_codes::GET_DRAM_DISABLE_REG_AND_POS));
+
+ // Get the register and bit positions
+ {
+ typedef dp16Traits<fapi2::TARGET_TYPE_MCA> TT;
+
+ // Gets the DP associated with the DRAM and the DRAM's position in the DP
+ const auto l_dram_per_dp = (l_width[0] == fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X8) ? BYTES_PER_DP : NIBBLES_PER_DP;
+ const auto l_dp = i_dram / l_dram_per_dp;
+ const auto l_dram_pos = i_dram % l_dram_per_dp;
+
+ // Bit position and length
+ o_bit_pos = TT::BIT_DISABLE + (l_dram_pos * l_width[0]);
+ o_bit_len = l_width[0];
+
+ // Gets the register address to read
+ o_reg = TT::BIT_DISABLE_REG[i_rp][l_dp].first;
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Gets the disables for a specific DRAM
+/// @param[in] i_target the fapi2 target type MCA of the port
+/// @param[in] i_rp - rank pair to check and modify
+/// @param[in] i_dram - the DRAM to be checked
+/// @param[out] o_disables - true if the whole DRAM is disabled
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
+///
+fapi2::ReturnCode get_disables_for_dram( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_rp,
+ const uint64_t i_dram,
+ uint64_t& o_disables)
+{
+ uint64_t l_reg = 0;
+ uint64_t l_bit_pos = 0;
+ uint64_t l_len = 0;
+ fapi2::buffer<uint64_t> l_data;
+ FAPI_TRY(get_disable_reg_and_pos_for_dram(i_target, i_rp, i_dram, l_reg, l_bit_pos, l_len));
+
+ // Reads
+ FAPI_TRY( mss::getScom(i_target, l_reg, l_data) );
+
+ // Gets the DRAM's data
+ FAPI_TRY(l_data.extractToRight(o_disables, l_bit_pos, l_len));
+
+ FAPI_INF("%s RP%lu DRAM%lu reg:0x%016lx reg_value:0x%016lx DRAM disables: 0x%lx", mss::c_str(i_target), i_rp, i_dram,
+ l_reg, l_data, o_disables);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Identifies if an inputted DRAM is wholely disabled
+/// @param[in] i_target the fapi2 target type MCA of the port
+/// @param[in] i_rp - rank pair to check and modify
+/// @param[in] i_dram - the DRAM to be checked
+/// @param[out] o_disabled - true if the whole DRAM is disabled
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
+///
+fapi2::ReturnCode is_dram_disabled( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_rp,
+ const uint64_t i_dram,
+ bool& o_disabled)
+{
+ // Checks inputs
+ uint8_t l_width[MAX_DIMM_PER_PORT] = {};
+ uint64_t l_disables = 0;
+ FAPI_TRY( mss::eff_dram_width(i_target, l_width) );
+
+ // Gets the disables for this DRAM
+ FAPI_TRY(get_disables_for_dram(i_target, i_rp, i_dram, l_disables));
+
+ // A DRAM is disabled if all of it's bits are disabled
+ {
+ const uint64_t l_disabled_value = (l_width[0] == fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X8) ? 0xff : 0xf;
+ o_disabled = (l_disables == l_disabled_value);
+ FAPI_INF("%s RP%lu DRAM%lu DRAM disables: 0x%lx check value: 0x%lx %s disabled", mss::c_str(i_target), i_rp, i_dram,
+ l_disables, l_disabled_value, o_disabled ? "is" : "isn't");
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Identifies if an inputted DRAM has any disables
+/// @param[in] i_target the fapi2 target type MCA of the port
+/// @param[in] i_rp - rank pair to check and modify
+/// @param[in] i_dram - the DRAM to be checked
+/// @param[out] o_has_disables - true if the whole DRAM has any disables
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
+///
+fapi2::ReturnCode dram_has_disables( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_rp,
+ const uint64_t i_dram,
+ bool& o_has_disables)
+{
+ // Checks inputs
+ uint64_t l_disables = 0;
+
+ // Gets the disables for this DRAM
+ FAPI_TRY(get_disables_for_dram(i_target, i_rp, i_dram, l_disables));
+
+ // A DRAM is disabled if all of it's bits are disabled
+ {
+ constexpr uint64_t CLEAR = 0;
+ o_has_disables = (CLEAR != l_disables);
+ FAPI_INF("%s RP%lu DRAM%lu DRAM disables: 0x%lx clear value: 0x%lx %s disables", mss::c_str(i_target), i_rp, i_dram,
+ l_disables, CLEAR, o_has_disables ? "has" : "has no");
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Disables bits based upon RD VREF values that differ from the median significantly
+/// @param[in] i_target - the MCA target on which to operate
+/// @param[in] i_rp - the rank pair on which to operate
+/// @param[in] i_dram - the DRAM that needs to have the workaround applied to it
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
+/// @note The differing values can cause WR VREF fail, so the bit(s) that differ are disabled temporarily
+///
+fapi2::ReturnCode disable_bits( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_rp,
+ const uint64_t i_dram )
+{
+ // Gets the register for the disable bits
+ uint64_t l_reg = 0;
+ uint64_t l_dram_start_pos = 0;
+ uint64_t l_len = 0;
+ FAPI_TRY(get_disable_reg_and_pos_for_dram(i_target, i_rp, i_dram, l_reg, l_dram_start_pos, l_len));
+
+ // Sets up this DRAM's disable bits
+ {
+ // Gets the bit to test
+ uint64_t l_bit = 0;
+ fapi2::buffer<uint64_t> l_data;
+ std::vector<uint64_t> l_rd_vref_values;
+ FAPI_TRY(read_rd_vref_for_dram( i_target, i_rp, i_dram, l_rd_vref_values ));
+ FAPI_TRY(identify_first_good_rd_vref( i_target, i_rp, i_dram, l_rd_vref_values, l_bit ));
+
+ // Read...
+ FAPI_TRY(mss::getScom(i_target, l_reg, l_data));
+
+ // Modify...
+ // First of all, disable all bits - for the workaround, we only want to run one bit in the DRAM
+ FAPI_TRY(l_data.setBit(l_dram_start_pos, l_len));
+ // Next, clear the bit (set it as good)
+ FAPI_TRY(l_data.clearBit(l_dram_start_pos + l_bit));
+
+ // Write...
+ FAPI_TRY(mss::putScom(i_target, l_reg, l_data));
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Clears all disable bits for a recovered DRAM
+/// @param[in] i_target - the MCA target on which to operate
+/// @param[in] i_rp - the rank pair on which to operate
+/// @param[in] i_dram - the DRAM that needs to have the workaround applied to it
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
+///
+fapi2::ReturnCode clear_dram_disable_bits( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_rp,
+ const uint64_t i_dram )
+{
+ // Gets the register for the disable bits
+ uint64_t l_reg = 0;
+ uint64_t l_bit_pos = 0;
+ uint64_t l_len = 0;
+ FAPI_TRY(get_disable_reg_and_pos_for_dram(i_target, i_rp, i_dram, l_reg, l_bit_pos, l_len));
+
+ // Restores the disabled bits
+ {
+ // Read...
+ fapi2::buffer<uint64_t> l_data;
+ FAPI_TRY(mss::getScom(i_target, l_reg, l_data));
+
+ // Modify...
+ FAPI_TRY(l_data.clearBit(l_bit_pos, l_len));
+
+ // Write...
+ FAPI_TRY(mss::putScom(i_target, l_reg, l_data));
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Configures the WR VREF value of a DRAM to be the nominal values
+/// @param[in] i_target the fapi2 target type DIMM
+/// @param[in] i_rp - rank pair to check and modify
+/// @param[in] i_dram - the DRAM
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
+///
+fapi2::ReturnCode configure_wr_vref_to_nominal( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ const uint64_t i_rp,
+ const uint64_t i_dram)
+{
+ typedef dp16Traits<fapi2::TARGET_TYPE_MCA> TT;
+ const std::vector<std::vector< std::pair<uint64_t, uint64_t> >> REGS =
+ {
+ TT::WR_VREF_VALUE_RP0_REG,
+ TT::WR_VREF_VALUE_RP1_REG,
+ TT::WR_VREF_VALUE_RP2_REG,
+ TT::WR_VREF_VALUE_RP3_REG,
+ };
+
+ const auto& l_mca = mss::find_target<fapi2::TARGET_TYPE_MCA>(i_target);
+
+ uint8_t l_width = 0;
+ FAPI_TRY( mss::eff_dram_width(i_target, l_width) );
+ FAPI_TRY(check_rp_and_dram(l_mca, i_rp, i_dram, ffdc_function_codes::CONFIGURE_WR_VREF_TO_NOMINAL));
+
+ // First gets the address
+ {
+ constexpr uint64_t NUM_DRAM_PER_REG = 2;
+ const auto l_dram_per_dp = (l_width == fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X8) ? BYTES_PER_DP : NIBBLES_PER_DP;
+ const auto l_dp = i_dram / l_dram_per_dp;
+ const auto l_reg_num = (i_dram % l_dram_per_dp) / NUM_DRAM_PER_REG;
+ const auto l_dram_pos = i_dram % NUM_DRAM_PER_REG;
+ const auto l_range_pos = (l_dram_pos == 0) ? TT::WR_VREF_VALUE_RANGE_DRAM_EVEN : TT::WR_VREF_VALUE_RANGE_DRAM_ODD;
+ const auto l_value_pos = (l_dram_pos == 0) ? TT::WR_VREF_VALUE_VALUE_DRAM_EVEN : TT::WR_VREF_VALUE_VALUE_DRAM_ODD;
+
+ const auto l_reg = (l_reg_num == 0) ? REGS[i_rp][l_dp].first : REGS[i_rp][l_dp].second;
+
+ // Now for read modify write
+ fapi2::buffer<uint64_t> l_data;
+
+ // Gets the VPD JEDEC WR VREF information
+ fapi2::buffer<uint8_t> l_train_value;
+ fapi2::buffer<uint8_t> l_train_range;
+ FAPI_TRY(mss::get_vpd_wr_vref_range_and_value(i_target, l_train_range, l_train_value));
+
+ FAPI_TRY(mss::getScom(l_mca, l_reg, l_data));
+
+ // Sends the data
+ FAPI_TRY(l_data.writeBit(l_train_range, l_range_pos));
+ FAPI_TRY(l_data.insertFromRight(l_train_value, l_value_pos, TT::WR_VREF_VALUE_VALUE_DRAM_EVEN_LEN));
+
+ FAPI_TRY(mss::putScom(l_mca, l_reg, l_data));
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Configures the skip bits to be 0x7 for an entire port for the workaround
+/// @param[in] i_target the fapi2 target type DIMM
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
+///
+fapi2::ReturnCode configure_skip_bits( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target )
+{
+ typedef dp16Traits<fapi2::TARGET_TYPE_MCA> TT;
+ constexpr uint64_t SKIP_ALL = 0x7;
+
+ std::vector<fapi2::buffer<uint64_t>> l_wr_vref_config;
+ FAPI_TRY( mss::scom_suckah(i_target, TT::WR_VREF_CONFIG0_REG, l_wr_vref_config) );
+
+ // Loops and sets or clears the 2D VREF bit on all DPs
+ for(auto& l_data : l_wr_vref_config)
+ {
+ // Updates the skip bits to be skip all
+ l_data.insertFromRight<TT::WR_VREF_CONFIG0_NUM_BITS_TO_SKIP, TT::WR_VREF_CONFIG0_NUM_BITS_TO_SKIP_LEN>(SKIP_ALL);
+ }
+
+ FAPI_TRY(mss::scom_blastah(i_target, TT::WR_VREF_CONFIG0_REG, l_wr_vref_config));
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Modifies the WR VREF value in an MRS06 to have the VPD, not eff_config attribute values
+/// @param[in] i_target - the DIMM target on which to operate
+/// @param[in,out] io_mrs06 - the MRS data class to modify
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
+/// @note The differing values can cause WR VREF fail, so the bit(s) that differ are disabled temporarily
+///
+fapi2::ReturnCode modify_mrs_vref_to_vpd( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ mss::ddr4::mrs06_data& io_mrs06 )
+{
+ // Gets the VPD JEDEC WR VREF information
+ uint8_t l_train_value = 0;
+ uint8_t l_train_range = 0;
+ FAPI_TRY(mss::get_vpd_wr_vref_range_and_value(i_target, l_train_range, l_train_value));
+
+ FAPI_INF("%s setting MRS06 to have the correct VPD value from 0x%02lx to range: %lu value 0x%02lx from 0x%02x",
+ mss::c_str(i_target), io_mrs06.iv_vrefdq_train_range[0], l_train_range, io_mrs06.iv_vrefdq_train_value[0],
+ l_train_value);
+
+ for(uint64_t l_rank = 0; l_rank < MAX_RANK_PER_DIMM; ++l_rank)
+ {
+ io_mrs06.iv_vrefdq_train_value[l_rank] = l_train_value;
+ io_mrs06.iv_vrefdq_train_range[l_rank] = l_train_range;
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Resets the WR DQ delays for a given DRAM to be a quarter clock before the DQS
+/// @param[in] i_target - the MCA target on which to operate
+/// @param[in] i_rp - the rank pair on which to operate
+/// @param[in] i_dram - the DRAM that needs to have the workaround applied to it
+/// @param[in] i_delay - the write DQ delay value
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
+/// @note The differing values can cause WR VREF fail, so the bit(s) that differ are disabled temporarily
+///
+fapi2::ReturnCode reset_wr_dq_delay( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_rp,
+ const uint64_t i_dram,
+ const uint64_t i_delay )
+{
+ typedef dp16Traits<fapi2::TARGET_TYPE_MCA> TT;
+
+ // Gets the DRAM width
+ uint8_t l_width[MAX_DIMM_PER_PORT] = {};
+ FAPI_TRY( mss::eff_dram_width(i_target, l_width) );
+
+ // Checks inputs
+ FAPI_TRY(check_rp_and_dram(i_target, i_rp, i_dram, ffdc_function_codes::RESET_WR_DQ_DELAY));
+
+ // Restores the inputted delay values
+ {
+ const uint64_t l_start_bit = i_dram * l_width[0];
+ const uint64_t l_end_bit = l_start_bit + l_width[0];
+
+ // And restore the good DQ values
+ for(uint64_t l_bit = l_start_bit; l_bit < l_end_bit; ++l_bit)
+ {
+ const auto l_dq_reg = TT::WR_DQ_DELAY_REG[i_rp][l_bit];
+ fapi2::buffer<uint64_t> l_data;
+ l_data.insertFromRight<TT::WR_DELAY, TT::WR_DELAY_LEN>(i_delay);
+
+ FAPI_INF("%s RP%lu DRAM %lu DQ reg 0x%016lx DQ val 0x%lx reg val 0x%016lx",
+ mss::c_str(i_target), i_rp, i_dram, l_dq_reg, i_delay, l_data);
+ FAPI_TRY(mss::putScom(i_target, l_dq_reg, l_data));
+ }
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Reads out the RD VREF values for a given DRAM
+/// @param[in] i_target - the MCA target on which to operate
+/// @param[in] i_rp - the rank pair on which to operate
+/// @param[in] i_dram - the DRAM that needs to have the workaround applied to it
+/// @param[out] o_rd_vref_values - the RD VREF values for a given DRAM
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
+/// @note The differing values can cause WR VREF fail, so the bit(s) that differ are disabled temporarily
+///
+fapi2::ReturnCode read_rd_vref_for_dram( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_rp,
+ const uint64_t i_dram,
+ std::vector<uint64_t>& o_rd_vref_values )
+{
+ typedef dp16Traits<fapi2::TARGET_TYPE_MCA> TT;
+
+ // Clears the output, just in case
+ o_rd_vref_values.clear();
+
+ // Gets the DRAM width
+ uint8_t l_width[MAX_DIMM_PER_PORT] = {};
+ FAPI_TRY( mss::eff_dram_width(i_target, l_width) );
+
+ // Checks inputs
+ FAPI_TRY(check_rp_and_dram(i_target, i_rp, i_dram, ffdc_function_codes::READ_RD_VREF_VALUES_FOR_DRAM));
+
+ // Gets the RD VREF values
+ {
+ // There are two RD VREF values stored per register
+ // One RD VREF value corresponds to one bit
+ // For a x4 DRAM, there are 4 bits per DRAM, meaning two registers need to be read
+ // For a x8 DRAM, there are 8 bits per DRAM, meaning four registers need to be read
+ constexpr uint64_t NUM_REGS_X4 = 2;
+ constexpr uint64_t NUM_REGS_X8 = 4;
+ const auto NUM_REGS = (l_width[0] == fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X8) ? NUM_REGS_X8 : NUM_REGS_X4;
+
+ // Computes the starting register's position
+ const uint64_t START_REG = i_dram * NUM_REGS;
+
+ // Loops through all of the registers
+ for(uint64_t l_reg = 0; l_reg < NUM_REGS; ++l_reg)
+ {
+ const auto l_reg_pos = l_reg + START_REG;
+ uint64_t l_value = 0;
+ fapi2::buffer<uint64_t> l_buff;
+
+ FAPI_TRY(mss::getScom(i_target, TT::DD2_RD_VREF_CNTRL_REG[l_reg_pos], l_buff));
+ l_buff.extractToRight<TT::RD_VREF_BYTE0_NIB0, TT::RD_VREF_BYTE0_NIB0_LEN>(l_value);
+ FAPI_INF("%s RP%lu DRAM%lu has RD VREF value of 0x%02lx", mss::c_str(i_target), i_rp, i_dram, l_value);
+ o_rd_vref_values.push_back(l_value);
+ l_buff.extractToRight<TT::RD_VREF_BYTE0_NIB1, TT::RD_VREF_BYTE0_NIB1_LEN>(l_value);
+ FAPI_INF("%s RP%lu DRAM%lu has RD VREF value of 0x%02lx", mss::c_str(i_target), i_rp, i_dram, l_value);
+ o_rd_vref_values.push_back(l_value);
+ }
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Identifies the first good RD VREF bit
+/// @param[in] i_target - the MCA target on which to operate
+/// @param[in] i_rp - the rank pair on which to operate
+/// @param[in] i_dram - the DRAM that needs to have the workaround applied to it
+/// @param[in] i_rd_vref_values - the RD VREF values for a given DRAM
+/// @param[out] o_bit - the bit for the first good RD VREF
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
+/// @note The differing values can cause WR VREF fail, so the bit(s) that differ are disabled temporarily
+///
+fapi2::ReturnCode identify_first_good_rd_vref( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_rp,
+ const uint64_t i_dram,
+ const std::vector<uint64_t>& i_rd_vref_values,
+ uint64_t& o_bit )
+{
+ constexpr uint64_t THRESHOLD = 3;
+ // Loop through all RD VREF values
+ uint64_t l_bit = 0;
+
+ // Gets the median value
+ uint64_t l_median = 0;
+ FAPI_TRY(rd_dq::find_median(i_rd_vref_values, l_median));
+
+ for(const auto l_value : i_rd_vref_values)
+ {
+ // Error case, continue on...
+ if((l_median > (l_value + THRESHOLD)) || (l_value > (l_median + THRESHOLD)))
+ {
+ FAPI_INF("%s RP%lu DRAM%lu bit: %lu with value of %lu is out of the median (%lu) +/- threshold range (%lu). Testing the next bit",
+ mss::c_str(i_target), i_rp, i_dram, l_bit, l_value, l_median, THRESHOLD);
+ }
+ // The first bit inside the threshold is good, note it and exit out successfully
+ else
+ {
+ FAPI_INF("%s RP%lu DRAM%lu bit: %lu with value of %lu is inside of the median (%lu) +/- threshold range (%lu). Returning this as the bit to test",
+ mss::c_str(i_target), i_rp, i_dram, l_bit, l_value, l_median, THRESHOLD);
+ o_bit = l_bit;
+ break;
+ }
+
+ ++l_bit;
+ }
+
+ return fapi2::FAPI2_RC_SUCCESS;
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Reads out the WR DQ delay value for a given DRAM
+/// @param[in] i_target - the MCA target on which to operate
+/// @param[in] i_rp - the rank pair on which to operate
+/// @param[in] i_dram - the DRAM that needs to have the workaround applied to it
+/// @param[out] o_wr_dq_delay - the WR DQ delay value for a given DRAM
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
+/// @note At this point, WR CTR hasn't been run, so all WR DQ delays should be the same on the DRAM
+///
+fapi2::ReturnCode get_starting_wr_dq_delay( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_rp,
+ const uint64_t i_dram,
+ uint64_t& o_wr_dq_delay )
+{
+ typedef dp16Traits<fapi2::TARGET_TYPE_MCA> TT;
+
+ // Gets the DRAM width
+ uint8_t l_width[MAX_DIMM_PER_PORT] = {};
+ FAPI_TRY( mss::eff_dram_width(i_target, l_width) );
+
+ // Checks inputs
+ FAPI_TRY(check_rp_and_dram(i_target, i_rp, i_dram, ffdc_function_codes::GET_STARTING_WR_DQ_DELAY_VALUE));
+
+ // Gets the data
+ {
+ // Gets the register - we only want bit 0 of the DRAM
+ const auto l_first_bit = i_dram * l_width[0];
+ const auto l_reg = TT::WR_DQ_DELAY_REG[i_rp][l_first_bit];
+
+ // Gets the register
+ fapi2::buffer<uint64_t> l_data;
+ FAPI_TRY(mss::getScom(i_target, l_reg, l_data));
+
+ // Returns the data
+ o_wr_dq_delay = 0;
+ l_data.extractToRight<TT::WR_DELAY, TT::WR_DELAY_LEN>(o_wr_dq_delay);
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Logs an informational callout detailing if we were able to recover
+/// @param[in] i_target - the MCA target under calibration
+/// @param[in] i_rp - the rank pair under calibration
+/// @param[in] i_dram - the DRAM in question
+/// @param[in] i_bad - true iff the DRAM failed to recover
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
+///
+fapi2::ReturnCode log_dram_results( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_rp,
+ const uint64_t i_dram,
+ const bool i_bad )
+{
+ // Log this information for cronus, as the logs are normally supressed
+#ifndef __HOSTBOOT_MODULE
+ FAPI_ERR("%s WR VREF workaround recovery %s on RP%lu DRAM%lu",
+ mss::c_str(i_target), i_bad ? "failed" : "succeeded", i_rp, i_dram);
+#endif
+
+ // If we call this function, we have a fail
+ FAPI_ASSERT( true,
+ fapi2::MSS_WR_VREF_DRAM_RECOVERY()
+ .set_TARGET(i_target)
+ .set_RP(i_rp)
+ .set_DRAM(i_dram)
+ .set_IS_BAD(i_bad),
+ "%s WR VREF workaround recovery %s on RP%lu DRAM%lu",
+ mss::c_str(i_target),
+ i_bad ? "failed" : "succeeded",
+ i_rp,
+ i_dram
+ );
+
+ return fapi2::FAPI2_RC_SUCCESS;
+fapi_try_exit:
+
+ // Log the error as recovered - we want this error to be informational
+ fapi2::logError(fapi2::current_err, fapi2::FAPI2_ERRL_SEV_RECOVERED);
+ fapi2::current_err = fapi2::FAPI2_RC_SUCCESS;
+ return fapi2::current_err;
+}
+
+///
+/// @brief Clears the PHY training FIRs for a given port
+/// @param[in] i_target - the MCA target under calibration
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
+///
+fapi2::ReturnCode clear_training_firs( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target )
+{
+
+ fapi2::buffer<uint64_t> l_phyfir_mask;
+ l_phyfir_mask.setBit<MCA_IOM_PHY0_DDRPHY_FIR_REG_ERROR_2>();
+
+ // Clear the PHY FIR ERROR 2 bit so we don't keep failing training and training advance on this port
+ FAPI_TRY( mss::putScom(i_target, MCA_IOM_PHY0_DDRPHY_FIR_REG_AND, l_phyfir_mask.invert()) );
+
+ FAPI_TRY( mss::getScom(i_target, MCA_IOM_PHY0_DDRPHY_FIR_REG, l_phyfir_mask));
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+
} // close namespace wr_vref
} // close namespace dp16
} // close namespace workarounds
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/dp16_workarounds.H b/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/dp16_workarounds.H
index fd5cdb7e6..ac5a73f48 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/dp16_workarounds.H
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/dp16_workarounds.H
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2016,2017 */
+/* Contributors Listed Below - COPYRIGHT 2016,2018 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -44,6 +44,7 @@
#include <p9_mc_scom_addresses_fld.H>
#include <mss_attribute_accessors.H>
#include <lib/phy/dp16.H>
+#include <lib/dimm/ddr4/mrs_load_ddr4.H>
namespace mss
{
@@ -497,6 +498,42 @@ fapi2::ReturnCode get_delay_data(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_
///
/// @brief Finds the median and sorts the vector
+/// @tparam T the type of data to sort
+/// @param[in] i_data the data to find a median for
+/// @param[out] o_median the median value
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
+///
+template < typename T >
+fapi2::ReturnCode find_median(const std::vector<T>& i_data, T& o_median)
+{
+
+ // The fapi_try is in an if statement, this ensures we have a good value
+ fapi2::current_err = fapi2::FAPI2_RC_SUCCESS;
+
+ // Bomb out if the vector is empty to avoid accessing a non-existant element
+ FAPI_ASSERT(!i_data.empty(),
+ fapi2::MSS_RD_CTR_WORKAROUND_EMPTY_VECTOR(),
+ "Empty vector passed in to find_median_and_sort"
+ );
+ {
+ // Copies the data to make finding the median easier
+ auto l_data = i_data;
+
+ // Sorts first
+ std::sort(l_data.begin(), l_data.end());
+
+ // The only way to find the median, is to sort and find the mid point
+ const auto l_median_it = l_data.begin() + (l_data.size() / 2);
+ o_median = *l_median_it;
+ }
+
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Finds the median and sorts the vector
/// @param[in,out] io_reg_data register data
/// @param[out] o_median the median value
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
@@ -603,6 +640,203 @@ fapi2::ReturnCode setup_values( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_t
uint8_t& o_train_range,
uint8_t& o_train_value);
+///
+/// @brief Gets the disable register and bit position for the DRAM
+/// @param[in] i_target the fapi2 target type MCA of the port
+/// @param[in] i_rp - rank pair to check and modify
+/// @param[in] i_dram - the DRAM to be checked
+/// @param[out] o_reg - the register to access from
+/// @param[out] o_bit_pos - the bit position in the register to access from
+/// @param[out] o_bit_len - the bit length to access
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
+///
+fapi2::ReturnCode get_disable_reg_and_pos_for_dram( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_rp,
+ const uint64_t i_dram,
+ uint64_t& o_reg,
+ uint64_t& o_bit_pos,
+ uint64_t& o_bit_len);
+
+///
+/// @brief Gets the disables for a specific DRAM
+/// @param[in] i_target the fapi2 target type MCA of the port
+/// @param[in] i_rp - rank pair to check and modify
+/// @param[in] i_dram - the DRAM to be checked
+/// @param[out] o_disables - true if the whole DRAM is disabled
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
+///
+fapi2::ReturnCode get_disables_for_dram( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_rp,
+ const uint64_t i_dram,
+ uint64_t& o_disables);
+
+///
+/// @brief Identifies if an inputted DRAM is wholely disabled
+/// @param[in] i_target the fapi2 target type MCA of the port
+/// @param[in] i_rp - rank pair to check and modify
+/// @param[in] i_dram - the DRAM to be checked
+/// @param[out] o_disabled - true if the whole DRAM is disabled
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
+///
+fapi2::ReturnCode is_dram_disabled( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_rp,
+ const uint64_t i_dram,
+ bool& o_disabled);
+
+///
+/// @brief Identifies if an inputted DRAM has any disables
+/// @param[in] i_target the fapi2 target type MCA of the port
+/// @param[in] i_rp - rank pair to check and modify
+/// @param[in] i_dram - the DRAM to be checked
+/// @param[out] o_has_disables - true if the whole DRAM has any disables
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
+///
+fapi2::ReturnCode dram_has_disables( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_rp,
+ const uint64_t i_dram,
+ bool& o_has_disables);
+
+///
+/// @brief Disables bits based upon RD VREF values that differ from the median significantly
+/// @param[in] i_target - the MCA target on which to operate
+/// @param[in] i_rp - the rank pair on which to operate
+/// @param[in] i_dram - the DRAM that needs to have the workaround applied to it
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
+/// @note The differing values can cause WR VREF fail, so the bit(s) that differ are disabled temporarily
+///
+fapi2::ReturnCode disable_bits( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_rp,
+ const uint64_t i_dram );
+
+///
+/// @brief Clears all disable bits for a recovered DRAM
+/// @param[in] i_target - the MCA target on which to operate
+/// @param[in] i_rp - the rank pair on which to operate
+/// @param[in] i_dram - the DRAM that needs to have the workaround applied to it
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
+///
+fapi2::ReturnCode clear_dram_disable_bits( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_rp,
+ const uint64_t i_dram );
+
+///
+/// @brief Checks that the rank pair and DRAM are in bounds
+/// @param[in] i_target - the MCA target on which to operate
+/// @param[in] i_rp - the rank pair on which to operate
+/// @param[in] i_dram - the DRAM that needs to have the workaround applied to it
+/// @param[in] i_function - the calling function to callout in FFDC
+///
+fapi2::ReturnCode check_rp_and_dram( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_rp,
+ const uint64_t i_dram,
+ const ffdc_function_codes i_function );
+
+///
+/// @brief Configures the WR VREF value of a DRAM to be the nominal values
+/// @param[in] i_target the fapi2 target type DIMM
+/// @param[in] i_rp - rank pair to check and modify
+/// @param[in] i_dram - the DRAM
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
+///
+fapi2::ReturnCode configure_wr_vref_to_nominal( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ const uint64_t i_rp,
+ const uint64_t i_dram);
+
+///
+/// @brief Configures the skip bits to be 0x7 for an entire port for the workaround
+/// @param[in] i_target the fapi2 target type DIMM
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
+///
+fapi2::ReturnCode configure_skip_bits( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target);
+
+///
+/// @brief Modifies the WR VREF value in an MRS06 to have the VPD, not eff_config attribute values
+/// @param[in] i_target - the DIMM target on which to operate
+/// @param[in,out] io_mrs06 - the MRS data class to modify
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
+/// @note The differing values can cause WR VREF fail, so the bit(s) that differ are disabled temporarily
+///
+fapi2::ReturnCode modify_mrs_vref_to_vpd( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ mss::ddr4::mrs06_data& io_mrs06 );
+
+///
+/// @brief Resets the WR DQ delays for a given DRAM to be a quarter clock before the DQS
+/// @param[in] i_target - the MCA target on which to operate
+/// @param[in] i_rp - the rank pair on which to operate
+/// @param[in] i_dram - the DRAM that needs to have the workaround applied to it
+/// @param[in] i_delay - the write DQ delay value
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
+/// @note The differing values can cause WR VREF fail, so the bit(s) that differ are disabled temporarily
+///
+fapi2::ReturnCode reset_wr_dq_delay( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_rp,
+ const uint64_t i_dram,
+ const uint64_t i_delay );
+
+///
+/// @brief Reads out the RD VREF values for a given DRAM
+/// @param[in] i_target - the MCA target on which to operate
+/// @param[in] i_rp - the rank pair on which to operate
+/// @param[in] i_dram - the DRAM that needs to have the workaround applied to it
+/// @param[out] o_rd_vref_values - the RD VREF values for a given DRAM
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
+/// @note The differing values can cause WR VREF fail, so the bit(s) that differ are disabled temporarily
+///
+fapi2::ReturnCode read_rd_vref_for_dram( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_rp,
+ const uint64_t i_dram,
+ std::vector<uint64_t>& o_rd_vref_values );
+
+///
+/// @brief Identifies the first good RD VREF bit
+/// @param[in] i_target - the MCA target on which to operate
+/// @param[in] i_rp - the rank pair on which to operate
+/// @param[in] i_dram - the DRAM that needs to have the workaround applied to it
+/// @param[in] i_rd_vref_values - the RD VREF values for a given DRAM
+/// @param[out] o_bit - the bit for the first good RD VREF
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
+/// @note The differing values can cause WR VREF fail, so the bit(s) that differ are disabled temporarily
+///
+fapi2::ReturnCode identify_first_good_rd_vref( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_rp,
+ const uint64_t i_dram,
+ const std::vector<uint64_t>& i_rd_vref_values,
+ uint64_t& o_bit );
+
+///
+/// @brief Reads out the WR DQ delay value for a given DRAM
+/// @param[in] i_target - the MCA target on which to operate
+/// @param[in] i_rp - the rank pair on which to operate
+/// @param[in] i_dram - the DRAM that needs to have the workaround applied to it
+/// @param[out] o_wr_dq_delay - the WR DQ delay value for a given DRAM
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
+/// @note At this point, WR CTR hasn't been run, so all WR DQ delays should be the same on the DRAM
+///
+fapi2::ReturnCode get_starting_wr_dq_delay( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_rp,
+ const uint64_t i_dram,
+ uint64_t& o_wr_dq_delay );
+
+///
+/// @brief Logs an informational callout detailing if we were able to recover
+/// @param[in] i_target - the MCA target under calibration
+/// @param[in] i_rp - the rank pair under calibration
+/// @param[in] i_dram - the DRAM in question
+/// @param[in] i_bad - true iff the DRAM failed to recover
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
+///
+fapi2::ReturnCode log_dram_results( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_rp,
+ const uint64_t i_dram,
+ const bool i_bad );
+
+///
+/// @brief Clears the PHY training FIRs for a given port
+/// @param[in] i_target - the MCA target under calibration
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
+///
+fapi2::ReturnCode clear_training_firs( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target );
+
} // close namespace wr_vref
} // close namespace dp16
} // close namespace workarounds
diff --git a/src/import/chips/p9/procedures/hwp/memory/p9_mss_eff_config.C b/src/import/chips/p9/procedures/hwp/memory/p9_mss_eff_config.C
index b6068bcc7..4b508ede7 100644
--- a/src/import/chips/p9/procedures/hwp/memory/p9_mss_eff_config.C
+++ b/src/import/chips/p9/procedures/hwp/memory/p9_mss_eff_config.C
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2015,2017 */
+/* Contributors Listed Below - COPYRIGHT 2015,2018 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -209,10 +209,8 @@ fapi2::ReturnCode p9_mss_eff_config( const fapi2::Target<fapi2::TARGET_TYPE_MCS>
"Failed write_level_enable for %s", mss::c_str(l_dimm) );
FAPI_TRY( l_eff_dimm->output_buffer(),
"Failed output_buffer for %s", mss::c_str(l_dimm) );
- FAPI_TRY( l_eff_dimm->vref_dq_train_value(),
- "Failed vref_dq_train_value for %s", mss::c_str(l_dimm) );
- FAPI_TRY( l_eff_dimm->vref_dq_train_range(),
- "Failed vref_dq_train_range for %s", mss::c_str(l_dimm) );
+ FAPI_TRY( l_eff_dimm->vref_dq_train_value_and_range(),
+ "Failed vref_dq_train_value_and_range for %s", mss::c_str(l_dimm) );
FAPI_TRY( l_eff_dimm->vref_dq_train_enable(),
"Failed vref_dq_train_enable for %s", mss::c_str(l_dimm) );
FAPI_TRY( l_eff_dimm->ca_parity_latency(),
OpenPOWER on IntegriCloud