summaryrefslogtreecommitdiffstats
path: root/src/import/chips/p9/procedures/hwp/memory/lib
diff options
context:
space:
mode:
authorLouis Stermole <stermole@us.ibm.com>2017-02-28 13:02:04 -0600
committerDaniel M. Crowell <dcrowell@us.ibm.com>2017-03-15 20:03:30 -0400
commit21ec8864c33a21ab6fedb220e92318c3e9f2c940 (patch)
treef424dc1c29a86ad03c0881d16e31b6f5019cd391 /src/import/chips/p9/procedures/hwp/memory/lib
parente8b8f27d39f6633ff89f2dc541db77c802988685 (diff)
downloadtalos-hostboot-21ec8864c33a21ab6fedb220e92318c3e9f2c940.tar.gz
talos-hostboot-21ec8864c33a21ab6fedb220e92318c3e9f2c940.zip
Disable RTT_WR during WR_LEVEL cal step, and set equivalent terminations
Change-Id: Ie813c26588d803371e35790ab9b233630c5041b4 Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/37203 Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com> Tested-by: Hostboot CI <hostboot-ci+hostboot@us.ibm.com> Reviewed-by: Brian R. Silver <bsilver@us.ibm.com> Reviewed-by: JACOB L. HARVEY <jlharvey@us.ibm.com> Dev-Ready: Louis Stermole <stermole@us.ibm.com> Reviewed-by: Matt K. Light <mklight@us.ibm.com> Reviewed-by: Christian R. Geddes <crgeddes@us.ibm.com> Reviewed-by: Jennifer A. Stofer <stofer@us.ibm.com> Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/37702 Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com> Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src/import/chips/p9/procedures/hwp/memory/lib')
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/mrs_load_ddr4.C176
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/mrs_load_ddr4.H218
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/mss_attribute_accessors.H90
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/phy/ddr_phy.C356
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/phy/ddr_phy.H171
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/phy/seq.H3
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/shared/mss_const.H1
7 files changed, 982 insertions, 33 deletions
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/mrs_load_ddr4.C b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/mrs_load_ddr4.C
index 7f42d97d6..850244d4a 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/mrs_load_ddr4.C
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/mrs_load_ddr4.C
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2016 */
+/* Contributors Listed Below - COPYRIGHT 2016,2017 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -42,6 +42,7 @@
#include <lib/eff_config/timing.H>
using fapi2::TARGET_TYPE_MCBIST;
+using fapi2::TARGET_TYPE_MCA;
using fapi2::TARGET_TYPE_DIMM;
using fapi2::FAPI2_RC_SUCCESS;
@@ -158,5 +159,178 @@ fapi_try_exit:
return fapi2::current_err;
}
+///
+/// @brief Maps RTT_WR setting to equivalent RTT_NOM setting
+/// Specialization for TARGET_TYPE_DIMM
+/// @param[in] i_target a DIMM target
+/// @param[in] i_rtt_wr an RTT_WR setting
+/// @param[out] o_rtt_nom equivalent RTT_NOM setting
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+template<>
+fapi2::ReturnCode rtt_wr_to_rtt_nom_helper(const fapi2::Target<TARGET_TYPE_DIMM>& i_target,
+ const uint8_t i_rtt_wr,
+ uint8_t& o_rtt_nom)
+{
+ switch(i_rtt_wr)
+ {
+ case RTT_WR_DYNAMIC_ODT_OFF:
+ case RTT_WR_HIZ:
+ o_rtt_nom = RTT_NOM_DISABLE;
+ break;
+
+ case RTT_WR_RZQ_OVER_3:
+ o_rtt_nom = RTT_NOM_RZQ_OVER_3;
+ break;
+
+ case RTT_WR_RZQ_OVER_2:
+ o_rtt_nom = RTT_NOM_RZQ_OVER_2;
+ break;
+
+ case RTT_WR_RZQ_OVER_1:
+ o_rtt_nom = RTT_NOM_RZQ_OVER_1;
+ break;
+
+ default:
+ FAPI_ASSERT( false,
+ fapi2::MSS_INVALID_RTT_WR_ENCODING().
+ set_RTT_WR(i_rtt_wr).
+ set_TARGET(i_target),
+ "Received invalid RTT_WR value: 0x%02x for %s.",
+ i_rtt_wr, mss::c_str(i_target) );
+ break;
+ }
+
+ return fapi2::FAPI2_RC_SUCCESS;
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Executes CCS instructions to set RTT_WR value into RTT_NOM
+/// Specialization for TARGET_TYPE_DIMM
+/// @param[in] i_target a DIMM target
+/// @param[in] i_rank selected rank
+/// @param[in,out] io_inst a vector of CCS instructions we should add to
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+template<>
+fapi2::ReturnCode rtt_nom_override(const fapi2::Target<TARGET_TYPE_DIMM>& i_target,
+ const uint64_t i_rank,
+ std::vector< ccs::instruction_t<TARGET_TYPE_MCBIST> >& io_inst)
+{
+ uint8_t l_rtt_nom_override_disable = 0;
+ uint8_t l_rtt_wr_value[MAX_RANK_PER_DIMM] = {0};
+ uint8_t l_rtt_nom_value[MAX_RANK_PER_DIMM] = {0};
+
+ // eff_dram* attributes use a per-DIMM rank index, so get that
+ const auto l_rank_idx = mss::index(i_rank);
+
+ FAPI_TRY( mss::rtt_nom_override_disable(i_target, l_rtt_nom_override_disable) );
+
+ if ( fapi2::ENUM_ATTR_MSS_RTT_NOM_OVERRIDE_DISABLE_YES == l_rtt_nom_override_disable )
+ {
+ return fapi2::FAPI2_RC_SUCCESS;
+ }
+
+ // Map RTT_WR settings to RTT_NOM
+ FAPI_TRY( mss::eff_dram_rtt_wr(i_target, &(l_rtt_wr_value[0])) );
+ FAPI_TRY( rtt_wr_to_rtt_nom_helper(i_target, l_rtt_wr_value[l_rank_idx], l_rtt_nom_value[l_rank_idx]) );
+
+ // Write the override values to RTT_NOM
+ FAPI_DBG("Overriding RTT_NOM value to 0x%01x to match original RTT_WR value 0x%01x on rank %d",
+ l_rtt_nom_value[l_rank_idx], l_rtt_wr_value[l_rank_idx], i_rank);
+ FAPI_TRY( rtt_nom_load(i_target, l_rtt_nom_value, i_rank, io_inst) );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Executes CCS instructions to disable RTT_WR
+/// Specialization for TARGET_TYPE_DIMM
+/// @param[in] i_target a DIMM target
+/// @param[in] i_rank selected rank
+/// @param[in,out] io_inst a vector of CCS instructions we should add to
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+template<>
+fapi2::ReturnCode rtt_wr_disable(const fapi2::Target<TARGET_TYPE_DIMM>& i_target,
+ const uint64_t i_rank,
+ std::vector< ccs::instruction_t<TARGET_TYPE_MCBIST> >& io_inst)
+{
+ uint8_t l_rtt_wr_value[MAX_RANK_PER_DIMM] = {0};
+
+ // eff_dram* attributes use a per-DIMM rank index, so get that
+ const auto l_rank_idx = mss::index(i_rank);
+
+ // Write RTT_WR setting for the given rank to RTT_WR_DYNAMIC_ODT_OFF
+ FAPI_TRY( mss::eff_dram_rtt_wr(i_target, &(l_rtt_wr_value[0])) );
+ l_rtt_wr_value[l_rank_idx] = RTT_WR_DYNAMIC_ODT_OFF;
+
+ FAPI_TRY( rtt_wr_load(i_target, l_rtt_wr_value, i_rank, io_inst) );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Executes CCS instructions to restore original value of RTT_NOM
+/// Specialization for TARGET_TYPE_DIMM
+/// @param[in] i_target a DIMM target
+/// @param[in] i_rank selected rank
+/// @param[in,out] io_inst a vector of CCS instructions we should add to
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+template<>
+fapi2::ReturnCode rtt_nom_restore(const fapi2::Target<TARGET_TYPE_DIMM>& i_target,
+ const uint64_t i_rank,
+ std::vector< ccs::instruction_t<TARGET_TYPE_MCBIST> >& io_inst)
+{
+ uint8_t l_rtt_nom_override_disable = 0;
+ uint8_t l_rtt_nom_value[MAX_RANK_PER_DIMM] = {0};
+
+ FAPI_TRY( mss::rtt_nom_override_disable(i_target, l_rtt_nom_override_disable) );
+
+ if ( fapi2::ENUM_ATTR_MSS_RTT_NOM_OVERRIDE_DISABLE_YES == l_rtt_nom_override_disable )
+ {
+ return fapi2::FAPI2_RC_SUCCESS;
+ }
+
+ // Get original RTT_NOM value
+ FAPI_TRY( mss::eff_dram_rtt_nom(i_target, &(l_rtt_nom_value[0])) );
+
+ // Write the value to RTT_NOM
+ FAPI_TRY( rtt_nom_load(i_target, l_rtt_nom_value, i_rank, io_inst) );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Executes CCS instructions to restore original value of RTT_WR
+/// Specialization for TARGET_TYPE_DIMM
+/// @param[in] i_target a DIMM target
+/// @param[in] i_rank selected rank
+/// @param[in,out] io_inst a vector of CCS instructions we should add to
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+template<>
+fapi2::ReturnCode rtt_wr_restore(const fapi2::Target<TARGET_TYPE_DIMM>& i_target,
+ const uint64_t i_rank,
+ std::vector< ccs::instruction_t<TARGET_TYPE_MCBIST> >& io_inst)
+{
+ // Get original RTT_WR value
+ uint8_t l_rtt_wr_value[MAX_RANK_PER_DIMM] = {0};
+ FAPI_TRY( mss::eff_dram_rtt_wr(i_target, &(l_rtt_wr_value[0])) );
+
+ // Write the value to RTT_WR
+ FAPI_TRY( rtt_wr_load(i_target, l_rtt_wr_value, i_rank, io_inst) );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
} // ns ddr4
} // ns mss
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 652f2d388..20e3aff35 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
@@ -74,6 +74,29 @@ enum address_bits
BG1 = 15,
};
+// RTT_WR settings in MR2 from JEDEC DDR4 spec
+enum rtt_wr_settings
+{
+ RTT_WR_DYNAMIC_ODT_OFF = 0b000,
+ RTT_WR_RZQ_OVER_2 = 0b001,
+ RTT_WR_RZQ_OVER_1 = 0b010,
+ RTT_WR_HIZ = 0b011,
+ RTT_WR_RZQ_OVER_3 = 0b100,
+};
+
+// RTT_NOM settings in MR1 from JEDEC DDR4 spec
+enum rtt_nom_settings
+{
+ RTT_NOM_DISABLE = 0b000,
+ RTT_NOM_RZQ_OVER_4 = 0b001,
+ RTT_NOM_RZQ_OVER_2 = 0b010,
+ RTT_NOM_RZQ_OVER_6 = 0b011,
+ RTT_NOM_RZQ_OVER_1 = 0b100,
+ RTT_NOM_RZQ_OVER_5 = 0b101,
+ RTT_NOM_RZQ_OVER_3 = 0b110,
+ RTT_NOM_RZQ_OVER_7 = 0b111,
+};
+
///
/// @brief Mirror (front to back) the ADR bits of a CCS instruction - implementation
/// @tparam T typename of the ccs::instruction_t
@@ -1001,7 +1024,7 @@ fapi2::ReturnCode mrs_load( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_targ
std::vector< ccs::instruction_t<fapi2::TARGET_TYPE_MCBIST> >& io_inst);
///
-/// @brief Set MPR Mode
+/// @brief Set MPR Mode
/// @param[in] i_target a DIMM target
/// @param[in] i_mode setting for MPR mode
/// @param[in,out] io_data data we are modifying MPR mode to
@@ -1026,6 +1049,62 @@ inline fapi2::ReturnCode set_dram_mpr_mode(const fapi2::Target<fapi2::TARGET_TYP
}
///
+/// @brief Set RTT_NOM values in an mrs01_data object
+/// @param[in] i_target a DIMM target
+/// @param[in] i_value settings for RTT_NOM
+/// @param[in,out] io_data data we are modifying RTT_NOM to
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+inline fapi2::ReturnCode set_dram_rtt_nom(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ const uint8_t i_value[MAX_RANK_PER_DIMM],
+ mrs01_data& io_data)
+{
+ constexpr uint64_t MAX_RTT_NOM = RTT_NOM_RZQ_OVER_7;
+
+ for (size_t l_rank = 0; l_rank < MAX_RANK_PER_DIMM; ++l_rank)
+ {
+ if(i_value[l_rank] > MAX_RTT_NOM)
+ {
+ FAPI_ERR("Invalid RTT_NOM value recieved: %d. Max encoding allowed: %d.", i_value[l_rank], MAX_RTT_NOM);
+ return fapi2::FAPI2_RC_INVALID_PARAMETER;
+ }
+
+ // Update field if input check passes
+ io_data.iv_rtt_nom[l_rank] = i_value[l_rank];
+ }
+
+ return fapi2::FAPI2_RC_SUCCESS;
+}
+
+///
+/// @brief Set RTT_WR values in an mrs02_data object
+/// @param[in] i_target a DIMM target
+/// @param[in] i_value settings for RTT_WR
+/// @param[in,out] io_data data we are modifying RTT_WR to
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+inline fapi2::ReturnCode set_dram_rtt_wr(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ const uint8_t i_value[MAX_RANK_PER_DIMM],
+ mrs02_data& io_data)
+{
+ constexpr uint64_t MAX_RTT_WR = RTT_WR_RZQ_OVER_3;
+
+ for (size_t l_rank = 0; l_rank < MAX_RANK_PER_DIMM; ++l_rank)
+ {
+ if(i_value[l_rank] > MAX_RTT_WR)
+ {
+ FAPI_ERR("Invalid RTT_WR value recieved: %d. Max encoding allowed: %d.", i_value[l_rank], MAX_RTT_WR);
+ return fapi2::FAPI2_RC_INVALID_PARAMETER;
+ }
+
+ // Update field if input check passes
+ io_data.iv_dram_rtt_wr[l_rank] = i_value[l_rank];
+ }
+
+ return fapi2::FAPI2_RC_SUCCESS;
+}
+
+///
/// @brief Set MPR Read
/// @param[in] i_target a DIMM target
/// @param[in] i_format setting for MPR read format
@@ -1152,6 +1231,74 @@ fapi_try_exit:
}
///
+/// @brief Makes CCS instruction to set RTT_NOM value
+/// @tparam T TargetType of the CCS instruction
+/// @param[in] i_target a DIMM target
+/// @param[in] i_value values to set to RTT_NOM
+/// @param[in] i_rank DIMM rank
+/// @param[in,out] io_inst a vector of CCS instructions we should add to
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+template< fapi2::TargetType T >
+fapi2::ReturnCode rtt_nom_load(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ const uint8_t i_value[MAX_RANK_PER_DIMM],
+ const uint64_t i_rank,
+ std::vector< ccs::instruction_t<T> >& io_inst )
+{
+ // tMRD (clock cycles) must be satisfied after an MRS command
+ constexpr uint64_t l_delay = mss::tmrd();
+
+ mrs01_data l_data(i_target, fapi2::current_err);
+ FAPI_TRY(fapi2::current_err, "%s. Failed to initialize mrs01_data for rtt_nom_load", mss::c_str(i_target) );
+
+ FAPI_TRY( set_dram_rtt_nom(i_target, i_value, l_data),
+ "%s. Failed set_dram_rtt_nom()",
+ mss::c_str(i_target));
+
+ // Make MRS CCS inst
+ FAPI_TRY( mrs_engine(i_target, l_data, i_rank, l_delay, io_inst),
+ "Failed to send MRS01 on %s, rank: %d",
+ mss::c_str(i_target), i_rank);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Makes CCS instruction to set RTT_WR value
+/// @tparam T TargetType of the CCS instruction
+/// @param[in] i_target a DIMM target
+/// @param[in] i_value values to set to RTT_WR
+/// @param[in] i_rank DIMM rank
+/// @param[in,out] io_inst a vector of CCS instructions we should add to
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+template< fapi2::TargetType T >
+fapi2::ReturnCode rtt_wr_load(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ const uint8_t i_value[MAX_RANK_PER_DIMM],
+ const uint64_t i_rank,
+ std::vector< ccs::instruction_t<T> >& io_inst )
+{
+ // tMRD (clock cycles) must be satisfied after an MRS command
+ constexpr uint64_t l_delay = mss::tmrd();
+
+ mrs02_data l_data(i_target, fapi2::current_err);
+ FAPI_TRY(fapi2::current_err, "%s. Failed to initialize mrs02_data for rtt_wr_load", mss::c_str(i_target) );
+
+ FAPI_TRY( set_dram_rtt_wr(i_target, i_value, l_data),
+ "%s. Failed set_dram_rtt_wr()",
+ mss::c_str(i_target));
+
+ // Make MRS CCS inst
+ FAPI_TRY( mrs_engine(i_target, l_data, i_rank, l_delay, io_inst),
+ "Failed to send MRS02 on %s, rank: %d",
+ mss::c_str(i_target), i_rank);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
/// @brief Makes CCS instruction for an MPR read
/// @tparam T TargetType of the CCS instruction
/// @param[in] i_target a DIMM target
@@ -1234,6 +1381,75 @@ fapi_try_exit:
return fapi2::current_err;
}
+///
+/// @brief Maps RTT_WR setting to equivalent RTT_NOM setting
+/// @tparam T TargetType of the DIMM
+/// @param[in] i_target a DIMM target
+/// @param[in] i_rtt_wr an RTT_WR setting
+/// @param[out] o_rtt_nom equivalent RTT_NOM setting
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+template< fapi2::TargetType T >
+fapi2::ReturnCode rtt_wr_to_rtt_nom_helper(const fapi2::Target<T>& i_target,
+ const uint8_t i_rtt_wr,
+ uint8_t& o_rtt_nom);
+
+///
+/// @brief Executes CCS instructions to set RTT_WR value into RTT_NOM
+/// @tparam T TargetType of the DIMM
+/// @tparam CT TargetType of the CCS instruction
+/// @param[in] i_target a DIMM target
+/// @param[in] i_rank selected rank
+/// @param[in,out] io_inst a vector of CCS instructions we should add to
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+template< fapi2::TargetType T, fapi2::TargetType CT >
+fapi2::ReturnCode rtt_nom_override(const fapi2::Target<T>& i_target,
+ const uint64_t i_rank,
+ std::vector< ccs::instruction_t<CT> >& io_inst);
+
+///
+/// @brief Executes CCS instructions to disable RTT_WR
+/// @tparam T TargetType of the DIMM
+/// @tparam CT TargetType of the CCS instruction
+/// @param[in] i_target a DIMM target
+/// @param[in] i_rank selected rank
+/// @param[in,out] io_inst a vector of CCS instructions we should add to
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+template< fapi2::TargetType T, fapi2::TargetType CT >
+fapi2::ReturnCode rtt_wr_disable(const fapi2::Target<T>& i_target,
+ const uint64_t i_rank,
+ std::vector< ccs::instruction_t<CT> >& io_inst);
+
+///
+/// @brief Executes CCS instructions to restore original value to RTT_NOM
+/// @tparam T TargetType of the DIMM
+/// @tparam CT TargetType of the CCS instruction
+/// @param[in] i_target a DIMM target
+/// @param[in] i_rank selected rank
+/// @param[in,out] io_inst a vector of CCS instructions we should add to
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+template< fapi2::TargetType T, fapi2::TargetType CT >
+fapi2::ReturnCode rtt_nom_restore(const fapi2::Target<T>& i_target,
+ const uint64_t i_rank,
+ std::vector< ccs::instruction_t<CT> >& io_inst);
+
+///
+/// @brief Executes CCS instructions to restore original value to RTT_WR
+/// @tparam T TargetType of the DIMM
+/// @tparam CT TargetType of the CCS instruction
+/// @param[in] i_target a DIMM target
+/// @param[in] i_rank selected rank
+/// @param[in,out] io_inst a vector of CCS instructions we should add to
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+template< fapi2::TargetType T, fapi2::TargetType CT >
+fapi2::ReturnCode rtt_wr_restore(const fapi2::Target<T>& i_target,
+ const uint64_t i_rank,
+ std::vector< ccs::instruction_t<CT> >& io_inst);
+
} // ddr4
} // mss
#endif
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 5d76833db..002df9591 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
@@ -16989,6 +16989,96 @@ fapi_try_exit:
return fapi2::current_err;
}
+///
+/// @brief ATTR_MSS_RTT_NOM_OVERRIDE_DISABLE getter
+/// @param[in] const ref to the fapi2::Target<fapi2::TARGET_TYPE_DIMM>
+/// @param[out] ref to the value uint8_t
+/// @note Generated by gen_accessors.pl generateParameters (F)
+/// @return fapi2::ReturnCode - FAPI2_RC_SUCCESS iff get is OK
+/// @note Set equal to 1 to disable setting of RTT_NOM to use RTT_WR values during
+/// WR_LEVEL
+/// calibration.
+///
+inline fapi2::ReturnCode rtt_nom_override_disable(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ uint8_t& o_value)
+{
+ uint8_t l_value[2][2];
+ auto l_mca = i_target.getParent<fapi2::TARGET_TYPE_MCA>();
+ auto l_mcs = l_mca.getParent<fapi2::TARGET_TYPE_MCS>();
+
+ FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_MSS_RTT_NOM_OVERRIDE_DISABLE, l_mcs, l_value) );
+ o_value = l_value[mss::index(l_mca)][mss::index(i_target)];
+ return fapi2::current_err;
+
+fapi_try_exit:
+ FAPI_ERR("failed accessing ATTR_MSS_RTT_NOM_OVERRIDE_DISABLE: 0x%lx (target: %s)",
+ uint64_t(fapi2::current_err), mss::c_str(i_target));
+ return fapi2::current_err;
+}
+
+///
+/// @brief ATTR_MSS_RTT_NOM_OVERRIDE_DISABLE getter
+/// @param[in] const ref to the fapi2::Target<fapi2::TARGET_TYPE_MCA>
+/// @param[out] uint8_t* memory to store the value
+/// @note Generated by gen_accessors.pl generateParameters (G)
+/// @return fapi2::ReturnCode - FAPI2_RC_SUCCESS iff get is OK
+/// @note Set equal to 1 to disable setting of RTT_NOM to use RTT_WR values during
+/// WR_LEVEL
+/// calibration.
+///
+inline fapi2::ReturnCode rtt_nom_override_disable(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ uint8_t* o_array)
+{
+ if (o_array == nullptr)
+ {
+ FAPI_ERR("nullptr passed to attribute accessor %s", __func__);
+ return fapi2::FAPI2_RC_INVALID_PARAMETER;
+ }
+
+ uint8_t l_value[2][2];
+ auto l_mcs = i_target.getParent<fapi2::TARGET_TYPE_MCS>();
+
+ FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_MSS_RTT_NOM_OVERRIDE_DISABLE, l_mcs, l_value) );
+ memcpy(o_array, &(l_value[mss::index(i_target)][0]), 2);
+ return fapi2::current_err;
+
+fapi_try_exit:
+ FAPI_ERR("failed accessing ATTR_MSS_RTT_NOM_OVERRIDE_DISABLE: 0x%lx (target: %s)",
+ uint64_t(fapi2::current_err), mss::c_str(i_target));
+ return fapi2::current_err;
+}
+
+///
+/// @brief ATTR_MSS_RTT_NOM_OVERRIDE_DISABLE getter
+/// @param[in] const ref to the fapi2::Target<fapi2::TARGET_TYPE_MCS>
+/// @param[out] uint8_t* memory to store the value
+/// @note Generated by gen_accessors.pl generateParameters (H)
+/// @return fapi2::ReturnCode - FAPI2_RC_SUCCESS iff get is OK
+/// @note Set equal to 1 to disable setting of RTT_NOM to use RTT_WR values during
+/// WR_LEVEL
+/// calibration.
+///
+inline fapi2::ReturnCode rtt_nom_override_disable(const fapi2::Target<fapi2::TARGET_TYPE_MCS>& i_target,
+ uint8_t* o_array)
+{
+ if (o_array == nullptr)
+ {
+ FAPI_ERR("nullptr passed to attribute accessor %s", __func__);
+ return fapi2::FAPI2_RC_INVALID_PARAMETER;
+ }
+
+ uint8_t l_value[2][2];
+
+ FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_MSS_RTT_NOM_OVERRIDE_DISABLE, i_target, l_value) );
+ memcpy(o_array, &l_value, 4);
+ return fapi2::current_err;
+
+fapi_try_exit:
+ FAPI_ERR("failed accessing ATTR_MSS_RTT_NOM_OVERRIDE_DISABLE: 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/ddr_phy.C b/src/import/chips/p9/procedures/hwp/memory/lib/phy/ddr_phy.C
index 029b7a61e..69ceaf8ed 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/phy/ddr_phy.C
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/phy/ddr_phy.C
@@ -875,10 +875,10 @@ fapi2::ReturnCode setup_cal_config( const fapi2::Target<fapi2::TARGET_TYPE_MCA>&
FAPI_TRY(mss::scom_blastah(i_target, mss::dp16Traits<fapi2::TARGET_TYPE_MCA>::WR_VREF_CONFIG0_REG, l_vref_config));
}
- // Latches in the WR VREF values
// loops through all RP's running workarounds and latching the VREF's as need be
for(const auto& l_rp : i_rank_pairs)
{
+ // Latches in the WR VREF values
// Overrides will be set by mss::workarounds::wr_vref::execute.
// If the execute code is skipped, then it will read from the attributes
uint8_t l_vrefdq_train_range_override = mss::ddr4::USE_DEFAULT_WR_VREF_SETTINGS;
@@ -934,19 +934,155 @@ fapi2::ReturnCode setup_cal_config( const fapi2::Target<fapi2::TARGET_TYPE_MCA>&
}
///
-/// @brief Setup odt_wr/rd_config
+/// @brief Execute a set of PHY cal steps
+/// Specializaton for TARGET_TYPE_MCA
+/// @param[in] i_target the target associated with this cal
+/// @param[in] i_rp one of the currently configured rank pairs
+/// @param[in] i_cal_steps_enabled fapi2::buffer<uint16_t> representing the cal steps to enable
+/// @param[in] i_abort_on_error CAL_ABORT_ON_ERROR override
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+/// @note This is a helper function. Library users are required to call setup_and_execute_cal
+///
+template<>
+fapi2::ReturnCode execute_cal_steps_helper( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_rp,
+ const fapi2::buffer<uint16_t> i_cal_steps_enabled,
+ const uint8_t i_abort_on_error)
+{
+ const auto& l_mcbist = mss::find_target<TARGET_TYPE_MCBIST>(i_target);
+ auto l_cal_inst = mss::ccs::initial_cal_command<TARGET_TYPE_MCBIST>(i_rp);
+
+ mss::ccs::program<TARGET_TYPE_MCBIST, TARGET_TYPE_MCA> l_program;
+
+ // Sanity check due to WR_LEVEL termination requirement
+ if ((i_cal_steps_enabled.getBit<mss::cal_steps::WR_LEVEL>()) &&
+ (mss::bit_count(static_cast<uint64_t>(i_cal_steps_enabled)) != 1))
+ {
+ FAPI_ERR("WR_LEVEL cal step requires special terminations, so must be run separately from other cal steps");
+ fapi2::Assert(false);
+ }
+
+ FAPI_DBG("executing training CCS instruction: 0x%llx, 0x%llx", l_cal_inst.arr0, l_cal_inst.arr1);
+
+ // Delays in the CCS instruction ARR1 for training are supposed to be 0xFFFF,
+ // and we're supposed to poll for the done or timeout bit. But we don't want
+ // to wait 0xFFFF cycles before we start polling - that's too long. So we put
+ // in a best-guess of how long to wait. This, in a perfect world, would be the
+ // time it takes one rank to train one training algorithm times the number of
+ // ranks we're going to train. We fail-safe as worst-case we simply poll the
+ // register too much - so we can tune this as we learn more.
+ l_program.iv_poll.iv_initial_sim_delay = 200;
+ l_program.iv_poll.iv_poll_count = 0xFFFF;
+ l_program.iv_instructions.push_back(l_cal_inst);
+
+ // We need to figure out how long to wait before we start polling. Each cal step has an expected
+ // duration, so for each cal step which was enabled, we update the CCS program.
+ FAPI_TRY( mss::cal_timer_setup(i_target, l_program.iv_poll, i_cal_steps_enabled) );
+ FAPI_TRY( mss::setup_cal_config(i_target, i_rp, i_cal_steps_enabled) );
+
+ // In the event of an init cal hang, CCS_STATQ(2) will assert and CCS_STATQ(3:5) = “001” to indicate a
+ // timeout. Otherwise, if calibration completes, FW should inspect DDRPHY_FIR_REG bits (50) and (58)
+ // for signs of a calibration error. If either bit is on, then the DDRPHY_PC_INIT_CAL_ERROR register
+ // should be polled to determine which calibration step failed.
+
+ // If we got a cal timeout, or another CCS error just leave now. If we got success, check the error
+ // bits for a cal failure. We'll return the proper ReturnCode so all we need to do is FAPI_TRY.
+ FAPI_TRY( mss::ccs::execute(l_mcbist, l_program, i_target) );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Perform necessary termination setup and execute a set of PHY cal steps
+/// Specializaton for TARGET_TYPE_MCA
+/// @param[in] i_target the target associated with this cal
+/// @param[in] i_rp one of the currently configured rank pairs
+/// @param[in] i_cal_steps_enabled fapi2::buffer<uint16_t> representing the cal steps to enable
+/// @param[in] i_abort_on_error CAL_ABORT_ON_ERROR override
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+///
+template<>
+fapi2::ReturnCode setup_and_execute_cal( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_rp,
+ const fapi2::buffer<uint16_t> i_cal_steps_enabled,
+ const uint8_t i_abort_on_error)
+{
+ const auto& l_mcbist = mss::find_target<TARGET_TYPE_MCBIST>(i_target);
+
+ // We run the cal steps in three chunks: pre-write-leveling, write-leveling, post-wirte-leveling.
+ // This is because write-leveling requires a special set of termination values.
+
+ // Run cal steps before WR_LEVEL if selected
+ if (i_cal_steps_enabled.getBit<mss::cal_steps::EXT_ZQCAL>())
+ {
+ FAPI_DBG("%s Running EXT_ZQCAL step on RP%d", mss::c_str(i_target), i_rp);
+ fapi2::buffer<uint16_t> l_steps_to_execute;
+ l_steps_to_execute.setBit<mss::cal_steps::EXT_ZQCAL>();
+ FAPI_TRY( execute_cal_steps_helper(i_target, i_rp, l_steps_to_execute, i_abort_on_error) );
+ }
+
+ // Run WR_LEVEL step (with overridden termination values) if selected
+ if (i_cal_steps_enabled.getBit<mss::cal_steps::WR_LEVEL>())
+ {
+ mss::ccs::program<TARGET_TYPE_MCBIST, TARGET_TYPE_MCA> l_program;
+ std::vector< ccs::instruction_t<TARGET_TYPE_MCBIST> > l_rtt_inst;
+
+ FAPI_DBG("%s Running WR_LEVEL step on RP%d", mss::c_str(i_target), i_rp);
+ fapi2::buffer<uint16_t> l_steps_to_execute;
+ l_steps_to_execute.setBit<mss::cal_steps::WR_LEVEL>();
+
+ // Setup WR_LEVEL specific terminations
+ // JEDEC spec requires disabling RTT_WR during WR_LEVEL, and enabling equivalent terminations
+ FAPI_TRY( setup_wr_level_terminations(i_target, i_rp, l_rtt_inst) );
+
+ if (!l_rtt_inst.empty())
+ {
+ l_program.iv_instructions.insert(l_program.iv_instructions.end(), l_rtt_inst.begin(), l_rtt_inst.end() );
+ FAPI_TRY( mss::ccs::execute(l_mcbist, l_program, i_target) );
+ l_program.iv_instructions.clear();
+ }
+
+ // Execute WR_LEVEL
+ FAPI_TRY( execute_cal_steps_helper(i_target, i_rp, l_steps_to_execute, i_abort_on_error) );
+
+ // Restore normal terminations
+ l_rtt_inst.clear();
+ FAPI_TRY( restore_mainline_terminations(i_target, i_rp, l_rtt_inst) );
+
+ if (!l_rtt_inst.empty())
+ {
+ l_program.iv_instructions.insert(l_program.iv_instructions.end(), l_rtt_inst.begin(), l_rtt_inst.end() );
+ FAPI_TRY( mss::ccs::execute(l_mcbist, l_program, i_target) );
+ }
+ }
+
+ // Run cal steps after WR_LEVEL if any are selected
+ if (i_cal_steps_enabled.getBit<mss::cal_steps::DQS_ALIGN, mss::cal_steps::STEPS_AFTER_WR_LEVEL>())
+ {
+ FAPI_DBG("%s Running remaining cal steps on RP%d", mss::c_str(i_target), i_rp);
+ fapi2::buffer<uint16_t> l_steps_to_execute = i_cal_steps_enabled;
+ l_steps_to_execute.clearBit<mss::cal_steps::EXT_ZQCAL>().clearBit<mss::cal_steps::WR_LEVEL>();
+ FAPI_TRY( execute_cal_steps_helper(i_target, i_rp, l_steps_to_execute, i_abort_on_error) );
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+// TODO RTC:167929 Can ODT VPD processing be shared between RD and WR?
+///
+/// @brief Setup odt_rd_config
/// @param[in] i_target the MCA target
/// @param[in] i_dimm_count the number of DIMM presently on the target
/// @param[in] i_odt_rd the RD ODT values from VPD
-/// @param[in] i_odt_wr the WR ODT values from VPD
/// @return FAPI2_RC_SUCCESS iff setup was successful
///
template<>
-fapi2::ReturnCode reset_odt_config_helper<fapi2::TARGET_TYPE_MCA, MAX_DIMM_PER_PORT, MAX_RANK_PER_DIMM>(
+fapi2::ReturnCode reset_odt_rd_config_helper<fapi2::TARGET_TYPE_MCA, MAX_DIMM_PER_PORT, MAX_RANK_PER_DIMM>(
const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
const uint64_t i_dimm_count,
- const uint8_t i_odt_rd[MAX_DIMM_PER_PORT][MAX_RANK_PER_DIMM],
- const uint8_t i_odt_wr[MAX_DIMM_PER_PORT][MAX_RANK_PER_DIMM])
+ const uint8_t i_odt_rd[MAX_DIMM_PER_PORT][MAX_RANK_PER_DIMM])
{
// The fields in the ODT VPD are 8 bits wide, but we only use the left-most 2 bits
// of each nibble. The encoding for each rank in the VPD is
@@ -959,9 +1095,6 @@ fapi2::ReturnCode reset_odt_config_helper<fapi2::TARGET_TYPE_MCA, MAX_DIMM_PER_P
// Nimbus PHY is more or less hard-wired for 2 DIMM/port 4R/DIMM
// So there's not much point in looping over DIMM or ranks.
- //
- // ODT Read
- //
{
// DPHY01_DDRPHY_SEQ_ODT_RD_CONFIG0_P0
// 48:55, ATTR_VPD_ODT_RD[0][0][0]; # when Read of Rank0
@@ -1017,11 +1150,34 @@ fapi2::ReturnCode reset_odt_config_helper<fapi2::TARGET_TYPE_MCA, MAX_DIMM_PER_P
FAPI_TRY( mss::putScom(i_target, MCA_DDRPHY_SEQ_ODT_RD_CONFIG1_P0, l_data) );
}
- // TODO RTC:167929 Can ODT VPD processing be shared between RD and WR?
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Setup odt_wr_config
+/// @param[in] i_target the MCA target
+/// @param[in] i_dimm_count the number of DIMM presently on the target
+/// @param[in] i_odt_wr the WR ODT values from VPD
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+///
+template<>
+fapi2::ReturnCode reset_odt_wr_config_helper<fapi2::TARGET_TYPE_MCA, MAX_DIMM_PER_PORT, MAX_RANK_PER_DIMM>(
+ const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_dimm_count,
+ const uint8_t i_odt_wr[MAX_DIMM_PER_PORT][MAX_RANK_PER_DIMM])
+{
+ // The fields in the ODT VPD are 8 bits wide, but we only use the left-most 2 bits
+ // of each nibble. The encoding for each rank in the VPD is
+ // [Dimm0 ODT0][Dimm0 ODT1][N/A][N/A][Dimm1 ODT0][Dimm1 ODT1][N/A][N/A]
+
+ constexpr uint64_t BIT_FIELD0_START = 0;
+ constexpr uint64_t BIT_FIELD1_START = 4;
+ constexpr uint64_t BIT_FIELD_LENGTH = 2;
+
+ // Nimbus PHY is more or less hard-wired for 2 DIMM/port 4R/DIMM
+ // So there's not much point in looping over DIMM or ranks.
- //
- // ODT Write
- //
{
// DPHY01_DDRPHY_SEQ_ODT_WR_CONFIG0_P0
// 48:55, ATTR_VPD_ODT_WR[0][0][0]; # when Read of Rank0
@@ -1080,23 +1236,185 @@ fapi_try_exit:
}
///
-/// @brief Setup odt_wr/rd_config, reads attributes
+/// @brief Setup odt_rd_config, reads attributes
/// @param[in] i_target the MCA target associated with this cal setup
/// @return FAPI2_RC_SUCCESS iff setup was successful
///
template<>
-fapi2::ReturnCode reset_odt_config( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target )
+fapi2::ReturnCode reset_odt_rd_config( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target )
{
uint8_t l_odt_rd[MAX_DIMM_PER_PORT][MAX_RANK_PER_DIMM];
- uint8_t l_odt_wr[MAX_DIMM_PER_PORT][MAX_RANK_PER_DIMM];
- uint64_t l_dimm_count = count_dimm(i_target);
+ const uint64_t l_dimm_count = count_dimm(i_target);
FAPI_TRY( mss::vpd_mt_odt_rd(i_target, &(l_odt_rd[0][0])) );
+
+ return reset_odt_rd_config_helper<fapi2::TARGET_TYPE_MCA, MAX_DIMM_PER_PORT, MAX_RANK_PER_DIMM>(
+ i_target, l_dimm_count, l_odt_rd);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Setup odt_wr_config, reads attributes
+/// @param[in] i_target the MCA target associated with this cal setup
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+///
+template<>
+fapi2::ReturnCode reset_odt_wr_config( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target )
+{
+ uint8_t l_odt_wr[MAX_DIMM_PER_PORT][MAX_RANK_PER_DIMM];
+
+ const uint64_t l_dimm_count = count_dimm(i_target);
+
+ FAPI_TRY( mss::vpd_mt_odt_wr(i_target, &(l_odt_wr[0][0])) );
+
+ return reset_odt_wr_config_helper<fapi2::TARGET_TYPE_MCA, MAX_DIMM_PER_PORT, MAX_RANK_PER_DIMM>(
+ i_target, l_dimm_count, l_odt_wr);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Override odt_wr_config to enabled for a given rank
+/// @param[in] i_target the MCA target associated with this cal setup
+/// @param[in] i_rank the rank to override
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+///
+template<>
+fapi2::ReturnCode override_odt_wr_config( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t& i_rank)
+{
+ uint8_t l_odt_wr[MAX_DIMM_PER_PORT][MAX_RANK_PER_DIMM] = {0};
+ fapi2::buffer<uint8_t> l_odt_wr_buf;
+
+ const uint64_t l_dimm_count = count_dimm(i_target);
+
+ // read the attributes
FAPI_TRY( mss::vpd_mt_odt_wr(i_target, &(l_odt_wr[0][0])) );
- return reset_odt_config_helper<fapi2::TARGET_TYPE_MCA, MAX_DIMM_PER_PORT, MAX_RANK_PER_DIMM>(
- i_target, l_dimm_count, l_odt_rd, l_odt_wr);
+ // set the ODTs for the rank selected
+ // The ODT encoding is (for mranks only)
+ // [R0 ODT][R1 ODT][N/A][N/A][R4 ODT][R5 ODT][N/A][N/A]
+ // For WR_LEVEL we only want to set the ODT bit for the selected mrank
+ l_odt_wr_buf = l_odt_wr[mss::rank::get_dimm_from_rank(i_rank)][mss::index(i_rank)];
+ FAPI_TRY( l_odt_wr_buf.setBit(i_rank) );
+ l_odt_wr[mss::rank::get_dimm_from_rank(i_rank)][mss::index(i_rank)] = l_odt_wr_buf;
+
+ return reset_odt_wr_config_helper<fapi2::TARGET_TYPE_MCA, MAX_DIMM_PER_PORT, MAX_RANK_PER_DIMM>(
+ i_target, l_dimm_count, l_odt_wr);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Setup terminations for WR_LEVEL cal for a given RP
+/// @param[in] i_target the MCA target associated with this cal setup
+/// @param[in] i_rp selected rank pair
+/// @param[in,out] io_inst a vector of CCS instructions we should add to
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+///
+template<>
+fapi2::ReturnCode setup_wr_level_terminations( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_rp,
+ std::vector< ccs::instruction_t<TARGET_TYPE_MCBIST> >& io_inst)
+{
+ // Danger: Make sure this DIMM target doesn't get used/accessed until it is populated
+ // by get_dimm_target_from_rank below!
+ fapi2::Target<TARGET_TYPE_DIMM> l_dimm;
+ std::vector<uint64_t> l_ranks;
+ uint8_t l_rtt_wr_value[MAX_RANK_PER_DIMM] = {0};
+
+ // mrank will be l_ranks[0] from get_ranks_in_pair
+ FAPI_TRY( mss::rank::get_ranks_in_pair(i_target, i_rp, l_ranks) );
+ FAPI_ASSERT( !l_ranks.empty(),
+ fapi2::MSS_NO_RANKS_IN_RANK_PAIR()
+ .set_TARGET(i_target)
+ .set_RANK_PAIR(i_rp),
+ "No ranks configured in MCA %s, rank pair %d", mss::c_str(i_target), i_rp );
+
+ FAPI_INF("%s Setting up terminations for WR_LEVEL, MRANK %d", mss::c_str(i_target), l_ranks[0]);
+
+ // Get DIMM target
+ FAPI_TRY( mss::rank::get_dimm_target_from_rank(i_target, l_ranks[0], l_dimm) );
+
+ // Get RTT_WR value
+ FAPI_TRY( mss::eff_dram_rtt_wr(l_dimm, &(l_rtt_wr_value[0])) );
+
+ // If RTT_WR is not enabled for pair's mrank, we're done
+ if (l_rtt_wr_value[mss::index(l_ranks[0])] == RTT_WR_DYNAMIC_ODT_OFF)
+ {
+ FAPI_INF("%s RTT_WR not set for MRANK %d, no termination adjustment necessary", mss::c_str(i_target), l_ranks[0]);
+ return fapi2::FAPI2_RC_SUCCESS;
+ }
+
+ // Disable RTT_WR for the pair's mrank
+ FAPI_TRY( mss::ddr4::rtt_wr_disable(l_dimm, l_ranks[0], io_inst) );
+
+ // Write the RTT_WR value into RTT_NOM
+ FAPI_TRY( mss::ddr4::rtt_nom_override(l_dimm, l_ranks[0], io_inst) );
+
+ // Set ODT so we get RTT_NOM for writes
+ FAPI_TRY( override_odt_wr_config(i_target, l_ranks[0]) );
+ FAPI_TRY( mss::workarounds::seq::odt_config(i_target) );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Restore normal terminations after WR_LEVEL cal for a given RP
+/// @param[in] i_target the MCA target associated with this cal setup
+/// @param[in] i_rp selected rank pair
+/// @param[in,out] io_inst a vector of CCS instructions we should add to
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+///
+template<>
+fapi2::ReturnCode restore_mainline_terminations( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_rp,
+ std::vector< ccs::instruction_t<TARGET_TYPE_MCBIST> >& io_inst)
+{
+ // Danger: Make sure this DIMM target doesn't get used/accessed until it is populated
+ // by get_dimm_target_from_rank below!
+ fapi2::Target<TARGET_TYPE_DIMM> l_dimm;
+ std::vector<uint64_t> l_ranks;
+ uint8_t l_rtt_wr_value[MAX_RANK_PER_DIMM] = {0};
+
+ // mrank will be l_ranks[0] from get_ranks_in_pair
+ FAPI_TRY( mss::rank::get_ranks_in_pair(i_target, i_rp, l_ranks) );
+ FAPI_ASSERT( !l_ranks.empty(),
+ fapi2::MSS_NO_RANKS_IN_RANK_PAIR()
+ .set_TARGET(i_target)
+ .set_RANK_PAIR(i_rp),
+ "No ranks configured in MCA %s, rank pair %d", mss::c_str(i_target), i_rp );
+
+ FAPI_INF("%s Restoring terminations after WR_LEVEL, MRANK %d", mss::c_str(i_target), l_ranks[0]);
+
+ // Get DIMM target
+ FAPI_TRY( mss::rank::get_dimm_target_from_rank(i_target, l_ranks[0], l_dimm) );
+
+ // Get RTT_WR value
+ FAPI_TRY( mss::eff_dram_rtt_wr(l_dimm, &(l_rtt_wr_value[0])) );
+
+ // If RTT_WR is not enabled for pair's mrank, we're done
+ if (l_rtt_wr_value[mss::index(l_ranks[0])] == RTT_WR_DYNAMIC_ODT_OFF)
+ {
+ FAPI_INF("%s RTT_WR not set for MRANK %d, no termination adjustment necessary", mss::c_str(i_target), l_ranks[0]);
+ return fapi2::FAPI2_RC_SUCCESS;
+ }
+
+ // Restore RTT_WR for the pair's mrank
+ FAPI_TRY( mss::ddr4::rtt_wr_restore(l_dimm, l_ranks[0], io_inst) );
+
+ // Restore RTT_NOM
+ FAPI_TRY( mss::ddr4::rtt_nom_restore(l_dimm, l_ranks[0], io_inst) );
+
+ // Restore ODT
+ FAPI_TRY( reset_odt_wr_config(i_target) );
+ FAPI_TRY( mss::workarounds::seq::odt_config(i_target) );
fapi_try_exit:
return fapi2::current_err;
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/phy/ddr_phy.H b/src/import/chips/p9/procedures/hwp/memory/lib/phy/ddr_phy.H
index 7f0d9042f..f3a4cd89d 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/phy/ddr_phy.H
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/phy/ddr_phy.H
@@ -38,6 +38,7 @@
#include <fapi2.H>
#include <lib/mss_attribute_accessors.H>
+#include <lib/ccs/ccs.H>
namespace mss
{
@@ -149,55 +150,203 @@ fapi2::ReturnCode setup_cal_config( const fapi2::Target<fapi2::TARGET_TYPE_MCA>&
const uint64_t i_rank,
const fapi2::buffer<uint16_t> i_cal_steps_enabled);
-// TODO RTC: 157753 tparams P and R can be pulled from an MCA trait once we have it
///
-/// @brief Setup odt_wr/rd_config
+/// @brief Execute a set of PHY cal steps
+/// @tparam T, the target type of the MCA/MBA
+/// @param[in] i_target the target associated with this cal
+/// @param[in] i_rp one of the currently configured rank pairs
+/// @param[in] i_cal_steps_enabled fapi2::buffer<uint16_t> representing the cal steps to enable
+/// @param[in] i_abort_on_error CAL_ABORT_ON_ERROR override
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+/// @note This is a helper function. Library users are required to call setup_and_execute_cal
+///
+template< fapi2::TargetType T >
+fapi2::ReturnCode execute_cal_steps_helper( const fapi2::Target<T>& i_target,
+ const uint64_t i_rp,
+ const fapi2::buffer<uint16_t> i_cal_steps_enabled,
+ const uint8_t i_abort_on_error);
+
+///
+/// @brief Perform necessary termination setup and execute a set of PHY cal steps
+/// @tparam T, the target type of the MCA/MBA
+/// @param[in] i_target the target associated with this cal
+/// @param[in] i_rp one of the currently configured rank pairs
+/// @param[in] i_cal_steps_enabled fapi2::buffer<uint16_t> representing the cal steps to enable
+/// @param[in] i_abort_on_error CAL_ABORT_ON_ERROR override
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+///
+template< fapi2::TargetType T >
+fapi2::ReturnCode setup_and_execute_cal( const fapi2::Target<T>& i_target,
+ const uint64_t i_rp,
+ const fapi2::buffer<uint16_t> i_cal_steps_enabled,
+ const uint8_t i_abort_on_error);
+
+// TODO RTC:167929 Can ODT VPD processing be shared between RD and WR?
+// TODO RTC:157753 tparams P and R can be pulled from an MCA trait once we have it
+///
+/// @brief Setup odt_rd_config
/// @tparam T the target type of the MCA/MBA
/// @tparam P the maximum DIMM per T
/// @tparam R the maximum rank per DIMM on T
/// @param[in] i_target the target
/// @param[in] i_dimm_count the number of DIMM presently on the target
/// @param[in] i_odt_rd the RD ODT values from VPD
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+///
+template< fapi2::TargetType T, uint64_t P, uint64_t R >
+fapi2::ReturnCode reset_odt_rd_config_helper( const fapi2::Target<T>& i_target,
+ const uint64_t i_dimm_count,
+ const uint8_t i_odt_rd[P][R] );
+
+// TODO RTC:167929 Can ODT VPD processing be shared between RD and WR?
+// TODO RTC:157753 tparams P and R can be pulled from an MCA trait once we have it
+///
+/// @brief Setup odt_wr_config
+/// @tparam T the target type of the MCA/MBA
+/// @tparam P the maximum DIMM per T
+/// @tparam R the maximum rank per DIMM on T
+/// @param[in] i_target the target
+/// @param[in] i_dimm_count the number of DIMM presently on the target
/// @param[in] i_odt_wr the WR ODT values from VPD
/// @return FAPI2_RC_SUCCESS iff setup was successful
///
template< fapi2::TargetType T, uint64_t P, uint64_t R >
-fapi2::ReturnCode reset_odt_config_helper( const fapi2::Target<T>& i_target,
+fapi2::ReturnCode reset_odt_wr_config_helper( const fapi2::Target<T>& i_target,
const uint64_t i_dimm_count,
- const uint8_t i_odt_rd[P][R],
const uint8_t i_odt_wr[P][R] );
///
-/// @brief Setup odt_wr/rd_config
+/// @brief Setup odt_rd_config
/// @param[in] i_target the MCA target
/// @param[in] i_dimm_count the number of DIMM presently on the target
/// @param[in] i_odt_rd the RD ODT values from VPD
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+///
+template<>
+fapi2::ReturnCode reset_odt_rd_config_helper<fapi2::TARGET_TYPE_MCA, MAX_DIMM_PER_PORT, MAX_RANK_PER_DIMM>(
+ const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_dimm_count,
+ const uint8_t i_odt_rd[MAX_DIMM_PER_PORT][MAX_RANK_PER_DIMM]);
+
+///
+/// @brief Setup odt_wr_config
+/// @param[in] i_target the MCA target
+/// @param[in] i_dimm_count the number of DIMM presently on the target
/// @param[in] i_odt_wr the WR ODT values from VPD
/// @return FAPI2_RC_SUCCESS iff setup was successful
///
template<>
-fapi2::ReturnCode reset_odt_config_helper<fapi2::TARGET_TYPE_MCA, MAX_DIMM_PER_PORT, MAX_RANK_PER_DIMM>(
+fapi2::ReturnCode reset_odt_wr_config_helper<fapi2::TARGET_TYPE_MCA, MAX_DIMM_PER_PORT, MAX_RANK_PER_DIMM>(
const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
const uint64_t i_dimm_count,
- const uint8_t i_odt_rd[MAX_DIMM_PER_PORT][MAX_RANK_PER_DIMM],
const uint8_t i_odt_wr[MAX_DIMM_PER_PORT][MAX_RANK_PER_DIMM]);
///
-/// @brief Setup odt_wr/rd_config, reads attributes
+/// @brief Setup odt_rd_config, reads attributes
+/// @tparam T the target type of the MCA/MBA
+/// @param[in] i_target the target associated with this cal setup
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+///
+template< fapi2::TargetType T >
+fapi2::ReturnCode reset_odt_rd_config( const fapi2::Target<T>& i_target );
+
+///
+/// @brief Setup odt_rd_config, reads attributes
+/// @param[in] i_target the MCA target associated with this cal setup
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+///
+template<>
+fapi2::ReturnCode reset_odt_rd_config( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target );
+
+///
+/// @brief Setup odt_wr_config, reads attributes
/// @tparam T the target type of the MCA/MBA
/// @param[in] i_target the target associated with this cal setup
/// @return FAPI2_RC_SUCCESS iff setup was successful
///
template< fapi2::TargetType T >
-fapi2::ReturnCode reset_odt_config( const fapi2::Target<T>& i_target );
+fapi2::ReturnCode reset_odt_wr_config( const fapi2::Target<T>& i_target );
+
+///
+/// @brief Setup odt_wr_config, reads attributes
+/// @param[in] i_target the MCA target associated with this cal setup
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+///
+template<>
+fapi2::ReturnCode reset_odt_wr_config( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target );
+
+///
+/// @brief Override odt_wr_config to enabled for a given rank
+/// @tparam T the target type of the MCA/MBA
+/// @param[in] i_target the target associated with this cal setup
+/// @param[in] i_rank the rank to override
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+///
+template< fapi2::TargetType T >
+fapi2::ReturnCode override_odt_wr_config( const fapi2::Target<T>& i_target,
+ const uint64_t& i_rank);
+
+///
+/// @brief Override odt_wr_config to enabled for a given rank
+/// @param[in] i_target the MCA target associated with this cal setup
+/// @param[in] i_rank the rank to override
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+///
+template<>
+fapi2::ReturnCode override_odt_wr_config( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t& i_rank);
+
+///
+/// @brief Setup terminations for WR_LEVEL cal for a given RP
+/// @tparam T the target type of the MCA/MBA
+/// @tparam CT TargetType of the CCS instruction
+/// @param[in] i_target the target associated with this cal setup
+/// @param[in] i_rp selected rank pair
+/// @param[in,out] io_inst a vector of CCS instructions we should add to
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+///
+template< fapi2::TargetType T, fapi2::TargetType CT >
+fapi2::ReturnCode setup_wr_level_terminations( const fapi2::Target<T>& i_target,
+ const uint64_t i_rp,
+ std::vector< ccs::instruction_t<CT> >& io_inst);
+
+///
+/// @brief Setup terminations for WR_LEVEL cal for a given RP
+/// @param[in] i_target the MCA target associated with this cal setup
+/// @param[in] i_rp selected rank pair
+/// @param[in,out] io_inst a vector of CCS instructions we should add to
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+///
+template<>
+fapi2::ReturnCode setup_wr_level_terminations( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_rp,
+ std::vector< ccs::instruction_t<fapi2::TARGET_TYPE_MCBIST> >& io_inst);
+
+///
+/// @brief Restore terminations after WR_LEVEL cal for a given RP
+/// @tparam T the target type of the MCA/MBA
+/// @tparam CT TargetType of the CCS instruction
+/// @param[in] i_target the target associated with this cal setup
+/// @param[in] i_rp selected rank pair
+/// @param[in,out] io_inst a vector of CCS instructions we should add to
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+///
+template< fapi2::TargetType T, fapi2::TargetType CT >
+fapi2::ReturnCode restore_mainline_terminations( const fapi2::Target<T>& i_target,
+ const uint64_t i_rp,
+ std::vector< ccs::instruction_t<CT> >& io_inst);
///
-/// @brief Setup odt_wr/rd_config, reads attributes
+/// @brief Restore terminations after WR_LEVEL cal for a given RP
/// @param[in] i_target the MCA target associated with this cal setup
+/// @param[in] i_rp selected rank pair
+/// @param[in,out] io_inst a vector of CCS instructions we should add to
/// @return FAPI2_RC_SUCCESS iff setup was successful
///
template<>
-fapi2::ReturnCode reset_odt_config( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target );
+fapi2::ReturnCode restore_mainline_terminations( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_rp,
+ std::vector< ccs::instruction_t<fapi2::TARGET_TYPE_MCBIST> >& io_inst);
///
/// @brief Perform the DLL calibration
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/phy/seq.H b/src/import/chips/p9/procedures/hwp/memory/lib/phy/seq.H
index 6896b19cb..989e672d9 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/phy/seq.H
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/phy/seq.H
@@ -396,7 +396,8 @@ inline fapi2::ReturnCode reset( const fapi2::Target<T>& i_target )
FAPI_TRY( reset_timing1(i_target) );
FAPI_TRY( reset_timing2(i_target) );
FAPI_TRY( reset_rd_wr_data(i_target) );
- FAPI_TRY( reset_odt_config(i_target) );
+ FAPI_TRY( reset_odt_rd_config(i_target) );
+ FAPI_TRY( reset_odt_wr_config(i_target) );
fapi_try_exit:
return fapi2::current_err;
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 5eee66a56..4cb69e317 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
@@ -153,6 +153,7 @@ enum cal_steps
WRITE_CTR_2D_VREF = 7,
COARSE_WR = 8,
COARSE_RD = 9,
+ STEPS_AFTER_WR_LEVEL = 8, // represents the number of bits in cal_step_enable after the WR_LEVEL bit
};
// Static consts for DDR4 voltages used in p9_mss_volt
OpenPOWER on IntegriCloud