summaryrefslogtreecommitdiffstats
path: root/src/import/chips/p9/procedures
diff options
context:
space:
mode:
authorAndre Marin <aamarin@us.ibm.com>2017-04-28 17:15:31 -0500
committerChristian R. Geddes <crgeddes@us.ibm.com>2017-05-12 21:13:15 -0400
commit04e2dd7b90abd697b61a956a56d76a5fb7121df6 (patch)
tree48648c2acfe37372f22a936f9a65f9be74503454 /src/import/chips/p9/procedures
parent8ebb4363270fd6bafa4c21413413a68b5778f348 (diff)
downloadtalos-hostboot-04e2dd7b90abd697b61a956a56d76a5fb7121df6.tar.gz
talos-hostboot-04e2dd7b90abd697b61a956a56d76a5fb7121df6.zip
Add DLL workaround and unit tests
Change-Id: I142ecd417abb92f4f8ec7d3748563b30359c486d Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/39673 Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com> Reviewed-by: STEPHEN GLANCY <sglancy@us.ibm.com> Tested-by: PPE CI <ppe-ci+hostboot@us.ibm.com> Dev-Ready: ANDRE A. MARIN <aamarin@us.ibm.com> Tested-by: Hostboot CI <hostboot-ci+hostboot@us.ibm.com> Reviewed-by: Matt K. Light <mklight@us.ibm.com> Reviewed-by: Thi N. Tran <thi@us.ibm.com> Reviewed-by: Louis Stermole <stermole@us.ibm.com> Reviewed-by: Jennifer A. Stofer <stofer@us.ibm.com> Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/39677 Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com> Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com> Reviewed-by: Christian R. Geddes <crgeddes@us.ibm.com>
Diffstat (limited to 'src/import/chips/p9/procedures')
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/mss_attribute_accessors_manual.H22
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/phy/ddr_phy.C57
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/phy/dp16.H17
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/phy/phy_cntrl.H64
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/shared/mss_const.H1
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/workarounds/dll_workarounds.C426
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/workarounds/dll_workarounds.H131
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/p9_mss_ddr_phy_reset.C17
-rw-r--r--src/import/chips/p9/procedures/xml/attribute_info/chip_ec_attributes.xml127
9 files changed, 780 insertions, 82 deletions
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/mss_attribute_accessors_manual.H b/src/import/chips/p9/procedures/hwp/memory/lib/mss_attribute_accessors_manual.H
index 385fdcb40..abdceefb2 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/mss_attribute_accessors_manual.H
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/mss_attribute_accessors_manual.H
@@ -391,6 +391,28 @@ fapi_try_exit:
}
///
+/// @brief ATTR_CHIP_EC_FEATURE_MSS_DLL_WORKAROUND getter
+/// @tparam T the fapi2 target type of the target
+/// @param[in] const ref to the target
+/// @return bool true iff we're on a Nimbus < EC 2.0
+///
+template< fapi2::TargetType T >
+inline bool chip_ec_feature_mss_dll_workaround(const fapi2::Target<T>& i_target)
+{
+ const auto l_chip = mss::find_target<fapi2::TARGET_TYPE_PROC_CHIP>(i_target);
+ uint8_t l_value = 0;
+
+ FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_CHIP_EC_FEATURE_MSS_DLL_WORKAROUND, l_chip, l_value) );
+ return l_value != 0;
+
+fapi_try_exit:
+ FAPI_ERR("failed accessing ATTR_CHIP_EC_FEATURE_MSS_DLL_WORKAROUND: 0x%lx (target: %s)",
+ uint64_t(fapi2::current_err), mss::c_str(i_target));
+ fapi2::Assert(false);
+ return false;
+}
+
+///
/// @brief ATTR_CHIP_EC_FEATURE_MSS_RUN_DQS_LOOP getter
/// @tparam T the fapi2 target type of the target
/// @param[in] const ref to the target
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 7a3d7affc..240b3a259 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
@@ -1514,35 +1514,38 @@ fapi2::ReturnCode dll_calibration( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST
// Note: Keep INIT_RXDLL_CAL_UPDATE at 0 to ensure PC CAL_GOOD indicator is accurate.
// Read, modify, write the DLL_RESET in the ADR_DLL registers
{
- std::vector<fapi2::buffer<uint64_t>> i_read;
+ typedef adr32sTraits<TARGET_TYPE_MCA> TT;
- FAPI_TRY(mss::scom_suckah(p, adr32sTraits<TARGET_TYPE_MCA>::DLL_CNFG_REG, i_read));
- std::for_each( i_read.begin(), i_read.end(),
- [](fapi2::buffer<uint64_t>& b)
+ std::vector<fapi2::buffer<uint64_t>> l_read;
+ FAPI_TRY(mss::scom_suckah(p, TT::DLL_CNFG_REG, l_read));
+
+ std::for_each( l_read.begin(), l_read.end(), [](fapi2::buffer<uint64_t>& b)
{
adr32s::set_dll_cal_reset(b);
} );
- FAPI_TRY(mss::scom_blastah(p, adr32sTraits<TARGET_TYPE_MCA>::DLL_CNFG_REG, i_read));
+
+ FAPI_TRY(mss::scom_blastah(p, TT::DLL_CNFG_REG, l_read));
}
// Read, modify, write the DLL_RESET in the DP16_DLL registers
{
- std::vector< std::pair<fapi2::buffer<uint64_t>, fapi2::buffer<uint64_t> > > i_read;
+ typedef dp16Traits<TARGET_TYPE_MCA> TT;
- FAPI_TRY(mss::scom_suckah(p, dp16Traits<TARGET_TYPE_MCA>::DLL_CNTRL_REG, i_read));
+ std::vector< std::pair<fapi2::buffer<uint64_t>, fapi2::buffer<uint64_t> > > l_read;
+ FAPI_TRY(mss::scom_suckah(p, TT::DLL_CNTRL_REG, l_read));
size_t l_index = 0;
- for (const auto& r : dp16Traits<TARGET_TYPE_MCA>::DLL_CNTRL_REG)
+ for (const auto& r : TT::DLL_CNTRL_REG)
{
mss::states l_state = (r.second == MCA_DDRPHY_DP16_DLL_CNTL1_P0_4) ? mss::HIGH : mss::LOW;
- dp16::set_dll_cal_reset(i_read[l_index].first, mss::LOW);
- dp16::set_dll_cal_reset(i_read[l_index].second, l_state);
+ dp16::set_dll_cal_reset(l_read[l_index].first, mss::LOW);
+ dp16::set_dll_cal_reset(l_read[l_index].second, l_state);
l_index += 1;
}
- FAPI_TRY(mss::scom_blastah(p, dp16Traits<TARGET_TYPE_MCA>::DLL_CNTRL_REG, i_read));
+ FAPI_TRY(mss::scom_blastah(p, TT::DLL_CNTRL_REG, l_read));
}
}
@@ -1552,7 +1555,7 @@ fapi2::ReturnCode dll_calibration( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST
// 32,772 dphy_nclk cycles from Reset=0 to VREG Calibration to exhaust all values
// 37,382 dphy_nclk cycles for full calibration to start and fail (“worst case”)
// More or less a fake value for sim delay as this isn't executed in sim.
- fapi2::delay(mss::cycles_to_ns(i_target, 37382), DELAY_1US);
+ fapi2::delay(mss::cycles_to_ns(i_target, mss::FULL_DLL_CAL_DELAY), DELAY_1US);
// 15. Monitor the DDRPHY_PC_DLL_ZCAL_CAL_STATUS register to determine when calibration is
// complete. One of the 3 bits will be asserted for ADR and DP16.
@@ -1570,10 +1573,32 @@ fapi2::ReturnCode dll_calibration( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST
{
fapi2::buffer<uint64_t> l_read;
FAPI_TRY( mss::getScom(p, l_dll_status_reg, l_read) );
- FAPI_ASSERT(mss::pc::get_dll_cal_status(l_read) == mss::YES,
- fapi2::MSS_DLL_FAILED_TO_CALIBRATE().set_MCA_IN_ERROR(p),
- "dll fapiled to calibrate: %s", mss::c_str(p));
- }
+
+ if( mss::pc::get_dll_cal_status(l_read) != mss::YES )
+ {
+ // For < DD2.0 parts we want to run DLL workaround so
+ // Instead of using FAPI_ASSERT and logging FFDC we will
+ // return a "bad" ReturnCode to trigger a workaround that
+ // will be run after DLL Calibration for all failing DLLs.
+ // FFDC will be collected there if it doesn't pass.
+ if( mss::chip_ec_feature_mss_dll_workaround(p) )
+ {
+ FAPI_INF("%s DLL failed to calibrate", mss::c_str(p));
+ return fapi2::FAPI2_RC_FALSE;
+ }
+
+ // If we are here than we are not running DLL workaround
+ // because this part is not < DD2.0, so we want to fail out here
+ // and log FFDC
+ FAPI_ASSERT( false,
+ fapi2::MSS_DLL_FAILED_TO_CALIBRATE()
+ .set_MCA_IN_ERROR(p),
+ "%s DLL failed to calibrate",
+ mss::c_str(i_target) );
+
+ }// endif
+
+ }// mca
fapi_try_exit:
return fapi2::current_err;
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 0e75b19cf..32cefd760 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
@@ -203,6 +203,8 @@ class dp16Traits<fapi2::TARGET_TYPE_MCA>
enum
{
DLL_CNTL_INIT_RXDLL_CAL_RESET = MCA_DDRPHY_DP16_DLL_CNTL0_P0_0_01_INIT_RXDLL_CAL_RESET,
+ DLL_CNTL_INIT_RXDLL_CAL_SKIP = MCA_DDRPHY_DP16_DLL_CNTL0_P0_1_01_REGS_RXDLL_CAL_SKIP,
+ DLL_CNTL_INIT_RXDLL_CAL_SKIP_LEN = MCA_DDRPHY_DP16_DLL_CNTL0_P0_1_01_REGS_RXDLL_CAL_SKIP_LEN,
FLUSH = MCA_DDRPHY_DP16_DATA_BIT_DIR1_P0_0_01_FLUSH,
INIT_IO = MCA_DDRPHY_DP16_DATA_BIT_DIR1_P0_0_01_INIT_IO,
ADV_PP = MCA_DDRPHY_DP16_DATA_BIT_DIR1_P0_0_01_ADVANCE_PING_PONG,
@@ -697,6 +699,21 @@ inline void set_dll_cal_reset( fapi2::buffer<uint64_t>& o_data, const states i_s
}
///
+/// @brief Set the DLL cal skip reset
+/// @tparam T fapi2 Target Type - defaults to TARGET_TYPE_MCA
+/// @tparam TT traits type defaults to dp16Traits<T>
+/// @param[in,out] io_data the value of the register
+/// @param[in] i_value the value to write
+///
+template< fapi2::TargetType T = fapi2::TARGET_TYPE_MCA, typename TT = dp16Traits<T> >
+inline void set_dll_cal_skip( fapi2::buffer<uint64_t>& io_data, const uint64_t i_value )
+{
+ FAPI_INF("set_dll_cal_skip to %d", i_value);
+ io_data.insertFromRight<TT::DLL_CNTL_INIT_RXDLL_CAL_SKIP,
+ TT::DLL_CNTL_INIT_RXDLL_CAL_SKIP_LEN>(i_value);
+}
+
+///
/// @brief Read DATA_BIT_DIR1
/// @tparam I DP16 instance
/// @tparam T fapi2 Target Type - derived
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/phy/phy_cntrl.H b/src/import/chips/p9/procedures/hwp/memory/lib/phy/phy_cntrl.H
index a2e5b0b87..0fcc81dbb 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/phy/phy_cntrl.H
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/phy/phy_cntrl.H
@@ -391,6 +391,44 @@ fapi_try_exit:
///
/// @brief Get DP DLL Cal Status
+/// @param[in] l_good DLL CAL good status of DP or ADR
+/// @param[in] l_error DLL CAL error status of DP or ADR
+/// @param[in] l_error_fine DLL CAL error fine status of DP or ADR
+/// @return mss::states; YES == success, NO == fail, INVALID == still running
+/// @note Since the these indicators are a summary of all DLLs, all must be started to make
+/// them valid.
+///
+static mss::states dll_cal_status_helper( const bool l_good,
+ const bool l_error,
+ const bool l_error_fine )
+{
+ // Full calibration is still going on in at least 1 DLL while all 3 signals are 0.
+ if ((l_good == mss::LOW) && (l_error == mss::LOW) && (l_error_fine == mss::LOW))
+ {
+ return mss::INVALID;
+ }
+
+ // Full calibration was successful in all DLLs if CAL_GOOD = 1 and both CAL_ERROR and CAL_ERROR_FINE are 0.
+ if ((l_good == mss::HIGH) && (l_error == mss::LOW) && (l_error_fine == mss::LOW))
+ {
+ return mss::YES;
+ }
+
+ // Full calibration failed in at least 1 DLL if either CAL_ERROR or CAL_ERROR_FINE are 1.
+ if ((l_error == mss::HIGH) || (l_error_fine == mss::HIGH))
+ {
+ return mss::NO;
+ }
+
+ // All cases shoud be covered above
+ // we shouldn't reach here so we add
+ // a saftey net.
+ fapi2::Assert(false);
+ return mss::NO;
+}
+
+///
+/// @brief Get DP DLL Cal Status
/// @tparam T fapi2 Target Type - derived
/// @tparam TT traits type defaults to dp16Traits<T>
/// Combine the processing of Good, Error and Error Fine into one functional interface
@@ -402,32 +440,38 @@ fapi_try_exit:
template< fapi2::TargetType T = fapi2::TARGET_TYPE_MCA, typename TT = pcTraits<T> >
inline mss::states get_dll_cal_status( fapi2::buffer<uint64_t>& i_data )
{
+ // Lets check the cal status of the DPs first
const bool l_dp_good = i_data.getBit<TT::DLL_CAL_STATUS_DP_GOOD>();
const bool l_dp_error = i_data.getBit<TT::DLL_CAL_STATUS_DP_ERROR>();
const bool l_dp_error_fine = i_data.getBit<TT::DLL_CAL_STATUS_DP_ERROR_FINE>();
+ const mss::states l_dp_status = dll_cal_status_helper(l_dp_good, l_dp_error, l_dp_error_fine);
+
+ // Lets check the cal status of the ADRs second
+ const bool l_adr_good = i_data.getBit<TT::DLL_CAL_STATUS_ADR_GOOD>();
+ const bool l_adr_error = i_data.getBit<TT::DLL_CAL_STATUS_ADR_ERROR>();
+ const bool l_adr_error_fine = i_data.getBit<TT::DLL_CAL_STATUS_ADR_ERROR_FINE>();
+
+ const mss::states l_adr_status = dll_cal_status_helper(l_adr_good, l_adr_error, l_adr_error_fine);
FAPI_INF("pc_dll_status: 0x%016llx", i_data);
- // Full calibration is still going on in at least 1 DLL while all 3 signals are 0.
- if ((l_dp_good == mss::LOW) && (l_dp_error == mss::LOW) && (l_dp_error_fine == mss::LOW))
+
+ if( l_dp_status == mss::INVALID || l_adr_status == mss::INVALID )
{
return mss::INVALID;
}
- // Full calibration was successful in all DLLs if CAL_GOOD = 1 and both CAL_ERROR and CAL_ERROR_FINE are 0.
- if ((l_dp_good == mss::HIGH) && (l_dp_error == mss::LOW) && (l_dp_error_fine == mss::LOW))
+ if( l_dp_status == mss::NO || l_adr_status == mss::NO )
{
- return mss::YES;
+ return mss::NO;
}
- // Full calibration failed in at least 1 DLL if either CAL_ERROR or CAL_ERROR_FINE are 1.
- // Full calibration was successful in all DLLs if CAL_GOOD = 1 and both CAL_ERROR and CAL_ERROR_FINE are 0.
- if ((l_dp_error == mss::HIGH) || (l_dp_error_fine == mss::HIGH))
+ if( l_dp_status == mss::YES && l_adr_status == mss::YES )
{
- return mss::NO;
+ return mss::YES;
}
- // Not reached ... right?
+ // Shouldn't get here, so we put some belt and suspenders
FAPI_ERR("pc_dll_cal_status: 0x%016llx unable to calculate state", i_data);
fapi2::Assert(false);
return mss::NO;
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 6fb449f8e..fe9ef2680 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
@@ -120,6 +120,7 @@ enum times
BG_SCRUB_IN_HOURS = 12,
CMD_TIMEBASE = 8192, ///< Represents the timebase multiplier for the MCBIST inter cmd gap
+ FULL_DLL_CAL_DELAY = 37382, ///< Full DLL calibration (in ddphy_nck cycles)
};
enum states
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/dll_workarounds.C b/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/dll_workarounds.C
index c44e79560..78b981343 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/dll_workarounds.C
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/dll_workarounds.C
@@ -22,3 +22,429 @@
/* permissions and limitations under the License. */
/* */
/* IBM_PROLOG_END_TAG */
+
+// *HWP HWP Owner: Andre Marin <aamarin@us.ibm.com>
+// *HWP HWP Backup: Stephen Glancy <sglancy@us.ibm.com>
+// *HWP Team: Memory
+// *HWP Level: 2
+// *HWP Consumed by: FSP:HB
+
+#include <map>
+#include <fapi2.H>
+#include <lib/workarounds/dll_workarounds.H>
+#include <generic/memory/lib/utils/find.H>
+#include <generic/memory/lib/utils/scom.H>
+#include <lib/phy/dp16.H>
+#include <lib/shared/mss_const.H>
+#include <lib/utils/conversions.H>
+
+namespace mss
+{
+
+static const std::vector< mss::dll_map > DLL_REGS =
+{
+ // ADR DLL 0
+ {
+ MCA_DDRPHY_ADR_DLL_CNTL_P0_ADR32S0,
+ MCA_DDRPHY_ADR_DLL_VREG_COARSE_P0_ADR32S0,
+ MCA_DDRPHY_DP16_DLL_VREG_COARSE1_P0_2,
+ MCA_DDRPHY_ADR_DLL_DAC_LOWER_P0_ADR32S0,
+ MCA_DDRPHY_ADR_DLL_DAC_UPPER_P0_ADR32S0
+ },
+
+ // DP0 DLL0
+ {
+ MCA_DDRPHY_DP16_DLL_CNTL0_P0_0,
+ MCA_DDRPHY_DP16_DLL_VREG_COARSE0_P0_0,
+ MCA_DDRPHY_DP16_DLL_VREG_COARSE1_P0_0,
+ MCA_DDRPHY_DP16_DLL_DAC_LOWER0_P0_0,
+ MCA_DDRPHY_DP16_DLL_DAC_UPPER0_P0_0,
+ },
+
+ // DP1 DLL0
+ {
+ MCA_DDRPHY_DP16_DLL_CNTL0_P0_1,
+ MCA_DDRPHY_DP16_DLL_VREG_COARSE0_P0_1,
+ MCA_DDRPHY_DP16_DLL_VREG_COARSE1_P0_1,
+ MCA_DDRPHY_DP16_DLL_DAC_LOWER0_P0_1,
+ MCA_DDRPHY_DP16_DLL_DAC_UPPER0_P0_1,
+ },
+
+ // DP2 DLL0
+ {
+ MCA_DDRPHY_DP16_DLL_CNTL0_P0_2,
+ MCA_DDRPHY_DP16_DLL_VREG_COARSE0_P0_2,
+ MCA_DDRPHY_DP16_DLL_VREG_COARSE1_P0_2,
+ MCA_DDRPHY_DP16_DLL_DAC_LOWER0_P0_2,
+ MCA_DDRPHY_DP16_DLL_DAC_UPPER0_P0_2,
+ },
+
+ // DP3 DLL0
+ {
+ MCA_DDRPHY_DP16_DLL_CNTL0_P0_3,
+ MCA_DDRPHY_DP16_DLL_VREG_COARSE0_P0_3,
+ MCA_DDRPHY_DP16_DLL_VREG_COARSE1_P0_3,
+ MCA_DDRPHY_DP16_DLL_DAC_LOWER0_P0_3,
+ MCA_DDRPHY_DP16_DLL_DAC_UPPER0_P0_3,
+ },
+
+ // DP4 DLL0
+ {
+ MCA_DDRPHY_DP16_DLL_CNTL0_P0_4,
+ MCA_DDRPHY_DP16_DLL_VREG_COARSE0_P0_4,
+ MCA_DDRPHY_DP16_DLL_VREG_COARSE0_P0_3,
+ MCA_DDRPHY_DP16_DLL_DAC_LOWER0_P0_4,
+ MCA_DDRPHY_DP16_DLL_DAC_UPPER0_P0_4,
+ },
+
+ // DP0 DLL1
+ {
+ MCA_DDRPHY_DP16_DLL_CNTL1_P0_0,
+ MCA_DDRPHY_DP16_DLL_VREG_COARSE1_P0_0,
+ MCA_DDRPHY_DP16_DLL_VREG_COARSE0_P0_0,
+ MCA_DDRPHY_DP16_DLL_DAC_LOWER1_P0_0,
+ MCA_DDRPHY_DP16_DLL_DAC_UPPER1_P0_0,
+ },
+
+ // DP1 DLL1
+ {
+ MCA_DDRPHY_DP16_DLL_CNTL1_P0_1,
+ MCA_DDRPHY_DP16_DLL_VREG_COARSE1_P0_1,
+ MCA_DDRPHY_DP16_DLL_VREG_COARSE0_P0_1,
+ MCA_DDRPHY_DP16_DLL_DAC_LOWER1_P0_1,
+ MCA_DDRPHY_DP16_DLL_DAC_UPPER1_P0_1,
+ },
+
+ // DP2 DLL1
+ {
+ MCA_DDRPHY_DP16_DLL_CNTL1_P0_2,
+ MCA_DDRPHY_DP16_DLL_VREG_COARSE1_P0_2,
+ MCA_DDRPHY_DP16_DLL_VREG_COARSE0_P0_2,
+ MCA_DDRPHY_DP16_DLL_DAC_LOWER1_P0_2,
+ MCA_DDRPHY_DP16_DLL_DAC_UPPER1_P0_2,
+ },
+
+ // DP3 DLL1
+ {
+ MCA_DDRPHY_DP16_DLL_CNTL1_P0_3,
+ MCA_DDRPHY_DP16_DLL_VREG_COARSE1_P0_3,
+ MCA_DDRPHY_DP16_DLL_VREG_COARSE0_P0_3,
+ MCA_DDRPHY_DP16_DLL_DAC_LOWER1_P0_3,
+ MCA_DDRPHY_DP16_DLL_DAC_UPPER1_P0_3,
+ },
+};
+
+namespace workarounds
+{
+namespace dll
+{
+
+///
+/// @brief Checks if CAL_ERROR and CAL_ERROR_FINE bits are set
+/// @param[in] i_dll_cntrl_data DLL CNTRL data
+/// @return true if DLL cal failed, false otherwiae
+///
+bool did_cal_fail( const fapi2::buffer<uint64_t>& i_dll_cntrl_data )
+{
+ FAPI_DBG("DLL_CNTL data 0x%016llx, CAL_ERROR %d, CAL_ERROR_FINE %d",
+ i_dll_cntrl_data,
+ i_dll_cntrl_data.getBit<mss::dll_map::DLL_CNTL_CAL_ERROR>(),
+ i_dll_cntrl_data.getBit<mss::dll_map::DLL_CNTL_CAL_ERROR_FINE>());
+
+ return i_dll_cntrl_data.getBit<mss::dll_map::DLL_CNTL_CAL_ERROR>() ||
+ i_dll_cntrl_data.getBit<mss::dll_map::DLL_CNTL_CAL_ERROR_FINE>();
+}
+
+///
+/// @brief Logs DLL error mappings from failed DLLs
+/// @param[in] i_target the fapi2 target
+/// @param[in] i_map dll map of DLLs to log errors from
+/// @param[in,out] io_failed_dll_cntrl failed list of DLL CNTRL regs
+/// @param[in,out] io_failed_dll_vreg_coarse map of VREG COARSE from failed DLLs
+/// @param[in,out] io_failed_dll_dac map of DLL DAC from failed DLLs
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+fapi2::ReturnCode log_fails(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const mss::dll_map& i_map,
+ std::vector< uint64_t >& io_failed_dll_cntrl,
+ std::map< fapi2::buffer<uint64_t>, fapi2::buffer<uint64_t> >& io_failed_dll_vreg_coarse,
+ std::map< fapi2::buffer<uint64_t>, fapi2::buffer<uint64_t> >& io_failed_dll_dac)
+{
+ fapi2::buffer<uint64_t> l_dll_cntrl_data;
+ FAPI_TRY( mss::getScom(i_target, i_map.iv_cntrl, l_dll_cntrl_data),
+ "Failed getScom() operation on %s reg 0x%016llx",
+ mss::c_str(i_target), i_map.iv_cntrl);
+
+ FAPI_DBG("%s Read DLL_CNTRL reg 0x%016llx, with data 0x%016llx",
+ mss::c_str(i_target), i_map.iv_cntrl, l_dll_cntrl_data);
+
+ if( did_cal_fail(l_dll_cntrl_data) )
+ {
+ fapi2::buffer<uint64_t> l_dll_dac_data;
+ uint64_t l_neighbor_dac_coarse = 0;
+
+ // Read DAC coarse from neighboring DLL
+ FAPI_TRY( mss::getScom(i_target, i_map.iv_vreg_coarse_neighbor_dll, l_dll_dac_data),
+ "Failed getScom() operation on %s reg 0x%016llx",
+ mss::c_str(i_target), i_map.iv_vreg_coarse_neighbor_dll );
+
+ FAPI_DBG( "%s Read neighboring DLL VREG COARSE reg 0x%016llx with data 0x%016llx",
+ mss::c_str(i_target), i_map.iv_vreg_coarse_neighbor_dll, l_dll_dac_data );
+
+ // Pair VREG coarse from failing DLL w/data from the DAC coarse from the neighboring DLL
+ l_dll_dac_data.extractToRight< dll_map::REGS_RXDLL_DAC_COARSE, dll_map::REGS_RXDLL_DAC_COARSE_LEN >
+ (l_neighbor_dac_coarse);
+
+ FAPI_DBG( "%s Saving failing DLL VREG COARSE reg 0x%016llx, value extracted 0x%llx",
+ mss::c_str(i_target), i_map.iv_vreg_coarse_same_dll, l_neighbor_dac_coarse);
+
+ io_failed_dll_vreg_coarse.emplace( std::make_pair(i_map.iv_vreg_coarse_same_dll, l_neighbor_dac_coarse) );
+
+ // Create a list DAC Lower and Upper pairs for failing DLLs
+ FAPI_DBG( "%s Saving off pair of failling DLL regs for DAC LOWER 0x%016llx, DAC UPPER 0x%016llx",
+ mss::c_str(i_target), i_map.iv_dll_dac_lower, i_map.iv_dll_dac_upper );
+
+ io_failed_dll_dac.emplace( std::make_pair(i_map.iv_dll_dac_lower, i_map.iv_dll_dac_upper) );
+
+ // Store a list of all failing DLL CNTRL registers
+ FAPI_INF( "%s Saving off failed DLL_CNTRL 0x%016llx",
+ mss::c_str(i_target), i_map.iv_cntrl );
+
+ io_failed_dll_cntrl.push_back(i_map.iv_cntrl);
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Checks for DLL error status
+/// @param[in] i_target the fapi2 target
+/// @param[in] i_failed_dll_cntrl vector of failed DLLs
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+fapi2::ReturnCode check_status(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const std::vector< uint64_t >& i_failed_dll_cntrl)
+{
+ for( const auto& reg : i_failed_dll_cntrl )
+ {
+ fapi2::buffer<uint64_t> l_dll_cntrl_data;
+
+ FAPI_TRY( mss::getScom(i_target, reg, l_dll_cntrl_data),
+ "Failed getScom() operation on %s reg 0x%016llx",
+ mss::c_str(i_target), reg );
+
+ FAPI_DBG("Checking status on %s, DLL CNTRL reg 0x%016llx", mss::c_str(i_target), reg);
+
+ FAPI_ASSERT( did_cal_fail(l_dll_cntrl_data) == false,
+ fapi2::MSS_DLL_FAILED_TO_CALIBRATE()
+ .set_MCA_IN_ERROR(i_target),
+ "%s DLL failed to calibrate",
+ mss::c_str(i_target) )
+ }
+
+ return fapi2::FAPI2_RC_SUCCESS;
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Change VREG_COARSE for failed DLLs
+/// @param[in] i_target the fapi2 target
+/// @param[in] i_failed_dll_map failed DLL VREG COARSE map
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+fapi2::ReturnCode change_vreg_coarse(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const std::map< fapi2::buffer<uint64_t>, fapi2::buffer<uint64_t> >& i_failed_dll_map)
+{
+ for( const auto& map : i_failed_dll_map)
+ {
+ // Little renaming to help clarify map fields
+ const auto FAILING_COARSE_REG = map.first;
+ const auto NEIGHBOR_DATA = map.second;
+
+ fapi2::buffer<uint64_t> l_data;
+
+ // Read DAC coarse from failed DLL
+ FAPI_TRY( mss::getScom(i_target, FAILING_COARSE_REG, l_data),
+ "Failed getScom() operation on %s reg 0x%016llx",
+ mss::c_str(i_target), FAILING_COARSE_REG );
+
+
+ FAPI_DBG("%s Read DLL_VREG_COARSE reg 0x%016llx, data 0x%016llx",
+ mss::c_str(i_target), FAILING_COARSE_REG, l_data);
+
+ l_data.insertFromRight< dll_map::REGS_RXDLL_DAC_COARSE,
+ dll_map::REGS_RXDLL_DAC_COARSE_LEN>(NEIGHBOR_DATA);
+
+ FAPI_INF("%s Writing to DLL_VREG_COARSE reg 0x%016llx, data 0x%016llx, value 0x%llx",
+ mss::c_str(i_target), FAILING_COARSE_REG, l_data, NEIGHBOR_DATA);
+
+ // Write DAC coarse from failed DLL with DAC coarse from neighboring DLL
+ FAPI_TRY( mss::putScom(i_target, FAILING_COARSE_REG, l_data),
+ "Failed putScom() operation on %s reg 0x%016llx",
+ mss::c_str(i_target), FAILING_COARSE_REG );
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Helper function to set DAC_COARSE reg
+/// @param[in] i_target the fapi2 target
+/// @param[in] i_failed_dll_dac failed DLL VREG COARSE
+/// @param[in] i_value the value to set
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+static fapi2::ReturnCode dll_dac_helper(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const fapi2::buffer<uint64_t>& i_failed_dll_dac,
+ const uint64_t i_value)
+{
+ constexpr uint64_t SOURCE_START = dll_map::REGS_RXDLL_VREG;
+
+ // Read DAC coarse from failed DLL
+ fapi2::buffer<uint64_t> l_data;
+
+ FAPI_TRY( mss::getScom(i_target, i_failed_dll_dac, l_data),
+ "Failed getScom() operation on %s reg 0x%016llx",
+ mss::c_str(i_target), i_failed_dll_dac );
+
+
+ l_data.insert<dll_map::REGS_RXDLL_VREG,
+ dll_map::REGS_RXDLL_VREG_LEN,
+ SOURCE_START>(i_value);
+
+ FAPI_INF("%s Writing to DAC_REG 0x%016llx, data 0x%016llx, value 0x%llx",
+ mss::c_str(i_target), i_failed_dll_dac, l_data, i_value);
+
+ // Write DAC coarse from failed DLL with DAC coarse from neighboring DLL
+ FAPI_TRY( mss::putScom(i_target, i_failed_dll_dac, l_data),
+ "Failed putScom() operation on %s reg 0x%016llx",
+ mss::c_str(i_target), i_failed_dll_dac );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Change DLL DAC for failled DLLs map
+/// @param[in] i_target the fapi2 target
+/// @param[in] i_failed_dll_dac_map failed DLL DAC map
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+fapi2::ReturnCode change_dac(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const std::map< fapi2::buffer<uint64_t>, fapi2::buffer<uint64_t> >& i_failed_dll_dac_map)
+{
+ // Hard coded default values per Steve Wyatt for this workaround
+ constexpr uint64_t DAC_LOWER_DEFAULT = 0x8000;
+ constexpr uint64_t DAC_UPPER_DEFAULT = 0xFFE0;
+
+ for( const auto& map : i_failed_dll_dac_map)
+ {
+ const auto DAC_LOWER_REG = map.first;
+ const auto DAC_UPPER_REG = map.second;
+
+ FAPI_TRY( dll_dac_helper(i_target, DAC_UPPER_REG, DAC_UPPER_DEFAULT) );
+ FAPI_TRY( dll_dac_helper(i_target, DAC_LOWER_REG, DAC_LOWER_DEFAULT) );
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief DLL Workaround algorithm to fax bad voltage settings
+/// @param[in] i_target the fapi2 target
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+template< >
+fapi2::ReturnCode fix_bad_voltage_settings(const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target)
+{
+ constexpr uint64_t SKIP_VREG = 0b10;
+
+ for( const auto& p : mss::find_targets<fapi2::TARGET_TYPE_MCA>(i_target) )
+ {
+ std::vector<uint64_t> l_failing_dll_cntrl;
+ std::map< fapi2::buffer<uint64_t>, fapi2::buffer<uint64_t> > l_failing_dll_vreg_coarse;
+ std::map< fapi2::buffer<uint64_t>, fapi2::buffer<uint64_t> > l_failing_dll_dac;
+
+ // Find failing DLL
+ for( const auto& map : DLL_REGS )
+ {
+ FAPI_TRY( log_fails(p, map, l_failing_dll_cntrl, l_failing_dll_vreg_coarse, l_failing_dll_dac),
+ "%s Failed log_fails()", mss::c_str(p));
+ }
+
+ // Set DLL reset bit and skip VREG bit on failed DLLs
+ {
+ fapi2::buffer<uint64_t> l_read;
+
+ for( const auto& d : l_failing_dll_cntrl )
+ {
+ FAPI_TRY(mss::getScom(p, d, l_read),
+ "Failed getScom() operation on %s reg 0x%016llx",
+ mss::c_str(i_target), d );
+
+
+ mss::dp16::set_dll_cal_reset(l_read, mss::HIGH);
+ mss::dp16::set_dll_cal_skip(l_read, SKIP_VREG);
+
+ FAPI_TRY(mss::putScom(p, d, l_read),
+ "Failed putScom() operation on %s reg 0x%016llx",
+ mss::c_str(i_target), d );
+
+ }
+
+ }
+
+ // Write the VREG DAC value found in log_fails to the failing DLL VREG DAC
+ FAPI_TRY( change_vreg_coarse(p, l_failing_dll_vreg_coarse),
+ "%s Failed change_vreg_coarse()", mss::c_str(p) );
+
+ // Reset the upper and lower fine calibration bits back to defaults
+ // since the earlier initial full calibration will have disturbed these.
+ FAPI_TRY( change_dac(p, l_failing_dll_dac),
+ "Failed change_dac on %s", mss::c_str(p) );
+
+ // Run DLL Calibration again on failed DLLs
+ {
+ fapi2::buffer<uint64_t> l_read;
+
+ for( const auto& d : l_failing_dll_cntrl )
+ {
+ FAPI_TRY(mss::getScom(p, d, l_read),
+ "Failed getScom() operation on %s reg 0x%016llx",
+ mss::c_str(i_target), d );
+
+ mss::dp16::set_dll_cal_reset(l_read, mss::LOW);
+
+ FAPI_INF("%s DLL_CNTRL_REG 0x%016llx, data 0x%016llx",
+ mss::c_str(p), d, l_read);
+
+ FAPI_TRY(mss::putScom(p, d, l_read),
+ "Failed putScom() operation on %s reg 0x%016llx",
+ mss::c_str(i_target), d );
+ }
+ }
+
+ // The [delay value] gives software a reasonable amount of time to wait for an individual
+ // DLL to calibrate starting from when it is taken out of reset. As some internal state machine transitions
+ // between steps may not have been counted, software should add some margin.
+ // 32,772 dphy_nclk cycles from Reset=0 to VREG Calibration to exhaust all values
+ // 37,382 dphy_nclk cycles for full calibration to start and fail (“worst case”)
+ // More or less a fake value for sim delay as this isn't executed in sim.
+ fapi2::delay(mss::cycles_to_ns(i_target, mss::FULL_DLL_CAL_DELAY), DELAY_1US);
+
+ FAPI_TRY( check_status(p, l_failing_dll_cntrl),
+ "%s check_status() failed", mss::c_str(p));
+ }// mca
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+} // close namespace dll
+} // close namespace workarounds
+} // close namespace mss
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/dll_workarounds.H b/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/dll_workarounds.H
index ab673f919..f7dd7b711 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/dll_workarounds.H
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/dll_workarounds.H
@@ -22,3 +22,134 @@
/* permissions and limitations under the License. */
/* */
/* IBM_PROLOG_END_TAG */
+
+// *HWP HWP Owner: Andre Marin <aamarin@us.ibm.com>
+// *HWP HWP Backup: Stephen Glancy <sglancy@us.ibm.com>
+// *HWP Team: Memory
+// *HWP Level: 2
+// *HWP Consumed by: FSP:HB
+
+#ifndef _MSS_WORKAROUNDS_DLL_H_
+#define _MSS_WORKAROUNDS_DLL_H_
+
+#include <fapi2.H>
+#include <p9_mc_scom_addresses.H>
+#include <p9_mc_scom_addresses_fld.H>
+#include <map>
+
+namespace mss
+{
+
+///
+/// @brief class to keep trace of DLL info for workaround
+///
+struct dll_map
+{
+ // Same values for DP16 and ADR enumerations
+ // Used DP16 enumerations...just because
+ static constexpr uint64_t REGS_RXDLL_DAC_COARSE = MCA_DDRPHY_DP16_DLL_VREG_COARSE0_P0_1_01_REGS_RXDLL_DAC_COARSE;
+ static constexpr uint64_t REGS_RXDLL_DAC_COARSE_LEN =
+ MCA_DDRPHY_DP16_DLL_VREG_COARSE0_P0_1_01_REGS_RXDLL_DAC_COARSE_LEN;
+ static constexpr uint64_t DLL_CNTL_CAL_ERROR = MCA_DDRPHY_DP16_DLL_CNTL0_P0_1_01_CAL_ERROR;
+ static constexpr uint64_t DLL_CNTL_CAL_ERROR_FINE = MCA_DDRPHY_DP16_DLL_CNTL0_P0_1_01_CAL_ERROR_FINE;
+
+ // Value for UPPER and LOWER DAC are the same
+ // Used LOWER DAC enumeration...just because
+ static constexpr uint64_t REGS_RXDLL_VREG = MCA_DDRPHY_DP16_DLL_DAC_LOWER0_P0_0_01_REGS_RXDLL_VREG_LOWER;
+ static constexpr uint64_t REGS_RXDLL_VREG_LEN = MCA_DDRPHY_DP16_DLL_DAC_LOWER0_P0_0_01_REGS_RXDLL_VREG_LOWER_LEN;
+
+ ///
+ /// @brief Checks for DLL error status
+ /// @param[in] i_cntrl_reg
+ /// @param[in] i_vreg_coarse_same_dll
+ /// @param[in] i_vreg_coarse_neighbor_dll
+ /// @param[in] i_dll_dac_upper
+ /// @param[in] i_dll_dac_lower
+ ///
+ constexpr dll_map(const uint64_t i_cntrl_reg,
+ const uint64_t i_vreg_coarse_same_dll,
+ const uint64_t i_vreg_coarse_neighbor_dll,
+ const uint64_t i_dll_dac_lower,
+ const uint64_t i_dll_dac_upper)
+ : iv_cntrl(i_cntrl_reg),
+ iv_vreg_coarse_same_dll(i_vreg_coarse_same_dll),
+ iv_vreg_coarse_neighbor_dll(i_vreg_coarse_neighbor_dll),
+ iv_dll_dac_lower(i_dll_dac_lower),
+ iv_dll_dac_upper(i_dll_dac_upper)
+ {}
+
+ const uint64_t iv_cntrl; // DP16 or ADR CNTRL register
+ const uint64_t iv_vreg_coarse_same_dll; // VREG_COARSE register for same DLL as iv_cntrl_reg
+ const uint64_t iv_vreg_coarse_neighbor_dll; // VREG_COARSE register for DLL neighbor for this workaround
+ const uint64_t iv_dll_dac_lower; // DLL DAC Upper register
+ const uint64_t iv_dll_dac_upper; // DLL DAC Lower register
+};
+
+namespace workarounds
+{
+namespace dll
+{
+
+///
+/// @brief Checks if CAL_ERROR and CAL_ERROR_FINE bits are set
+/// @param[in] i_dll_cntrl_data DLL CNTRL data
+/// @return bool
+///
+bool did_cal_fail( const fapi2::buffer<uint64_t>& i_dll_cntrl_data );
+
+///
+/// @brief Logs DLL error mappings from failed DLLs
+/// @param[in] i_target the fapi2 target
+/// @param[in] i_map dll map of DLLs to log errors from
+/// @param[in,out] io_failed_dll_cntrl failed list of DLL CNTRL regs
+/// @param[in,out] io_failed_dll_vreg_coarse map of VREG COARSE from failed DLLs
+/// @param[in,out] io_failed_dll_dac map of DLL DAC from failed DLLs
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+fapi2::ReturnCode log_fails(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const mss::dll_map& i_map,
+ std::vector< uint64_t >& io_failed_dll_cntrl,
+ std::map< fapi2::buffer<uint64_t>, fapi2::buffer<uint64_t> >& io_failed_dll_vreg_coarse,
+ std::map< fapi2::buffer<uint64_t>, fapi2::buffer<uint64_t> >& io_failed_dll_dac);
+
+///
+/// @brief Checks for DLL error status
+/// @param[in] i_target the fapi2 target
+/// @param[in] i_failed_dll_cntrl vector of failed DLLs
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+fapi2::ReturnCode check_status(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const std::vector< uint64_t >& i_failed_dll_cntrl);
+
+///
+/// @brief Change VREG_COARSE for failed DLLs
+/// @param[in] i_target the fapi2 target
+/// @param[in] i_failed_dll_map failed DLL VREG COARSE map
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+fapi2::ReturnCode change_vreg_coarse(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const std::map< fapi2::buffer<uint64_t>, fapi2::buffer<uint64_t> >& i_failed_dll_map);
+
+///
+/// @brief Change DLL DAC for failled DLLs map
+/// @param[in] i_target the fapi2 target
+/// @param[in] i_failed_dll_dac_map failed DLL DAC map
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+fapi2::ReturnCode change_dac(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const std::map< fapi2::buffer<uint64_t>, fapi2::buffer<uint64_t> >& i_failed_dll_dac_map);
+
+///
+/// @brief DLL Workaround algorithm to fax bad voltage settings
+/// @tparam T fapi2 Target Type - derived
+/// @param[in] i_target the fapi2 target
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+template< fapi2::TargetType T >
+fapi2::ReturnCode fix_bad_voltage_settings(const fapi2::Target<T>& i_target);
+
+} // close namespace dll
+} // close namespace workarounds
+} // close namespace mss
+
+#endif
diff --git a/src/import/chips/p9/procedures/hwp/memory/p9_mss_ddr_phy_reset.C b/src/import/chips/p9/procedures/hwp/memory/p9_mss_ddr_phy_reset.C
index 22ae9b1ba..ab6dc8548 100644
--- a/src/import/chips/p9/procedures/hwp/memory/p9_mss_ddr_phy_reset.C
+++ b/src/import/chips/p9/procedures/hwp/memory/p9_mss_ddr_phy_reset.C
@@ -43,6 +43,7 @@
#include <lib/utils/count_dimm.H>
#include <lib/phy/adr32s.H>
#include <lib/workarounds/dp16_workarounds.H>
+#include <lib/workarounds/dll_workarounds.H>
#include <lib/fir/check.H>
#include <lib/fir/unmask.H>
@@ -109,8 +110,20 @@ extern "C"
// and DDRPHY_ADR_DLL_CNTL registers
// 15. Monitor the DDRPHY_PC_DLL_ZCAL_CAL_STATUS register to determine when calibration is
// complete. One of the 3 bits will be asserted for ADR and DP16.
- FAPI_INF( "starting DLL calibration %s", mss::c_str(i_target) );
- FAPI_TRY( mss::dll_calibration(i_target) );
+ {
+ FAPI_INF( "starting DLL calibration %s", mss::c_str(i_target) );
+ fapi2::ReturnCode l_rc = mss::dll_calibration(i_target);
+
+ // Only run DLL workaround if we fail DLL cal and we are a < DD2.0 part
+ if( l_rc != fapi2::FAPI2_RC_SUCCESS &&
+ mss::chip_ec_feature_mss_dll_workaround(i_target) )
+ {
+ FAPI_INF( "%s Applying DLL workaround", mss::c_str(i_target) );
+ l_rc = mss::workarounds::dll::fix_bad_voltage_settings(i_target);
+ }
+
+ FAPI_TRY( l_rc, "Failed DLL calibration" );
+ }
//
// Start bang-bang-lock
diff --git a/src/import/chips/p9/procedures/xml/attribute_info/chip_ec_attributes.xml b/src/import/chips/p9/procedures/xml/attribute_info/chip_ec_attributes.xml
index 296a301e8..4bdcb1362 100644
--- a/src/import/chips/p9/procedures/xml/attribute_info/chip_ec_attributes.xml
+++ b/src/import/chips/p9/procedures/xml/attribute_info/chip_ec_attributes.xml
@@ -2632,15 +2632,11 @@
</chipEcFeature>
</attribute>
- <!-- ******************************************************************** -->
- <!-- Memory Section -->
- <!-- ******************************************************************** -->
<attribute>
- <id>ATTR_CHIP_EC_FEATURE_MSS_UT_EC_NIMBUS_LESS_THAN_TWO_OH</id>
+ <id>ATTR_CHIP_EC_FEATURE_MSS_HW392781_RDARRAY_CLKGATE</id>
<targetType>TARGET_TYPE_PROC_CHIP</targetType>
<description>
- Attribute used only for memory subsystem unit tests. Tells us whether
- the chip EC we're running on is less than 2.0 and we're on a Nimbus
+ Data integrity issue requires us to disable clockgate in read array for Nimbus DD1.0
</description>
<chipEcFeature>
<chip>
@@ -2654,11 +2650,10 @@
</attribute>
<attribute>
- <id>ATTR_CHIP_EC_FEATURE_MCBIST_END_OF_RANK</id>
+ <id>ATTR_CHIP_EC_FEATURE_HW400075</id>
<targetType>TARGET_TYPE_PROC_CHIP</targetType>
<description>
- MCBIST has a bug where it won't detect the end of a rank properly for
- a 1R DIMM during super-fast read.
+ Addresses issue where MDI bit was getting wrong values with threadmill and transactional data resulting in coherency issues.
</description>
<chipEcFeature>
<chip>
@@ -2672,10 +2667,10 @@
</attribute>
<attribute>
- <id>ATTR_CHIP_EC_FEATURE_MSS_WR_VREF</id>
+ <id>ATTR_CHIP_EC_FEATURE_HW398139</id>
<targetType>TARGET_TYPE_PROC_CHIP</targetType>
<description>
- In DD1 Nimbus in the WR VREF algorithm, certain work-arounds are needed
+ Avoid powerbus early hangs by enabling prefetch drops to break out of fairness issue with prefetch ops
</description>
<chipEcFeature>
<chip>
@@ -2689,10 +2684,10 @@
</attribute>
<attribute>
- <id>ATTR_CHIP_EC_FEATURE_MSS_DQS_POLARITY</id>
+ <id>ATTR_CHIP_EC_FEATURE_HW400932</id>
<targetType>TARGET_TYPE_PROC_CHIP</targetType>
<description>
- For Monza DDR port 2, one pair of DQS P/N is swapped polarity.
+ ATAG info corruption on presp issue requires us to disable clockgate for Nimbus DD1.0
</description>
<chipEcFeature>
<chip>
@@ -2706,10 +2701,10 @@
</attribute>
<attribute>
- <id>ATTR_CHIP_EC_FEATURE_MSS_VREF_DAC</id>
+ <id>ATTR_CHIP_EC_FEATURE_HW401780</id>
<targetType>TARGET_TYPE_PROC_CHIP</targetType>
<description>
- VREF DAC work-around for Nimbus DD1.0
+ Need AMO caching disabled for multiple defects until Nimbus DD2.0
</description>
<chipEcFeature>
<chip>
@@ -2723,10 +2718,10 @@
</attribute>
<attribute>
- <id>ATTR_CHIP_EC_FEATURE_MSS_WAT_DEBUG_ATTN</id>
+ <id>ATTR_CHIP_EC_FEATURE_HW406577</id>
<targetType>TARGET_TYPE_PROC_CHIP</targetType>
<description>
- WAT Debug Attention work-around for Nimbus DD1.0
+ Noise window disabled in DD1 because continually reocurring intermittent UE's can cause us to hang on refreshes.
</description>
<chipEcFeature>
<chip>
@@ -2739,11 +2734,15 @@
</chipEcFeature>
</attribute>
+ <!-- ******************************************************************** -->
+ <!-- Memory Section -->
+ <!-- ******************************************************************** -->
<attribute>
- <id>ATTR_CHIP_EC_FEATURE_MSS_HW392781_RDARRAY_CLKGATE</id>
+ <id>ATTR_CHIP_EC_FEATURE_MCBIST_END_OF_RANK</id>
<targetType>TARGET_TYPE_PROC_CHIP</targetType>
<description>
- Data integrity issue requires us to disable clockgate in read array for Nimbus DD1.0
+ MCBIST has a bug where it won't detect the end of a rank properly for
+ a 1R DIMM during super-fast read.
</description>
<chipEcFeature>
<chip>
@@ -2757,10 +2756,10 @@
</attribute>
<attribute>
- <id>ATTR_CHIP_EC_FEATURE_HW400075</id>
+ <id>ATTR_CHIP_EC_FEATURE_MSS_WAT_DEBUG_ATTN</id>
<targetType>TARGET_TYPE_PROC_CHIP</targetType>
<description>
- Addresses issue where MDI bit was getting wrong values with threadmill and transactional data resulting in coherency issues.
+ WAT Debug Attention work-around for Nimbus DD1.0
</description>
<chipEcFeature>
<chip>
@@ -2774,10 +2773,11 @@
</attribute>
<attribute>
- <id>ATTR_CHIP_EC_FEATURE_HW398139</id>
+ <id>ATTR_CHIP_EC_FEATURE_MSS_UT_EC_NIMBUS_LESS_THAN_TWO_OH</id>
<targetType>TARGET_TYPE_PROC_CHIP</targetType>
<description>
- Avoid powerbus early hangs by enabling prefetch drops to break out of fairness issue with prefetch ops
+ Attribute used only for memory subsystem unit tests. Tells us whether
+ the chip EC we're running on is less than 2.0 and we're on a Nimbus
</description>
<chipEcFeature>
<chip>
@@ -2791,10 +2791,10 @@
</attribute>
<attribute>
- <id>ATTR_CHIP_EC_FEATURE_HW384794</id>
+ <id>ATTR_CHIP_EC_FEATURE_MSS_WR_VREF</id>
<targetType>TARGET_TYPE_PROC_CHIP</targetType>
<description>
- Workaround for defect where clock enables to PHY were incorrectly driven
+ In DD1 Nimbus in the WR VREF algorithm, certain work-arounds are needed
</description>
<chipEcFeature>
<chip>
@@ -2808,10 +2808,10 @@
</attribute>
<attribute>
- <id>ATTR_CHIP_EC_FEATURE_HW375732</id>
+ <id>ATTR_CHIP_EC_FEATURE_MSS_DQS_POLARITY</id>
<targetType>TARGET_TYPE_PROC_CHIP</targetType>
<description>
- Workaround for Data mismatch discovered by Geyzer at certain async frequency ratios
+ For Monza DDR port 2, one pair of DQS P/N is swapped polarity.
</description>
<chipEcFeature>
<chip>
@@ -2825,12 +2825,10 @@
</attribute>
<attribute>
- <id>ATTR_CHIP_EC_FEATURE_MSS_TRAINING_BAD_BITS</id>
+ <id>ATTR_CHIP_EC_FEATURE_MSS_VREF_DAC</id>
<targetType>TARGET_TYPE_PROC_CHIP</targetType>
<description>
- For Nimbus pre DD1.02 we want to pass DDR training if we see 'correctable'
- errors. This isn't the case for post-DD1.02 where we want to pass/fail
- training based on the results from the PHY itself
+ VREF DAC work-around for Nimbus DD1.0
</description>
<chipEcFeature>
<chip>
@@ -2844,10 +2842,12 @@
</attribute>
<attribute>
- <id>ATTR_CHIP_EC_FEATURE_HW400932</id>
+ <id>ATTR_CHIP_EC_FEATURE_MSS_TRAINING_BAD_BITS</id>
<targetType>TARGET_TYPE_PROC_CHIP</targetType>
<description>
- ATAG info corruption on presp issue requires us to disable clockgate for Nimbus DD1.0
+ For Nimbus pre DD1.02 we want to pass DDR training if we see 'correctable'
+ errors. This isn't the case for post-DD1.02 where we want to pass/fail
+ training based on the results from the PHY itself
</description>
<chipEcFeature>
<chip>
@@ -2861,10 +2861,10 @@
</attribute>
<attribute>
- <id>ATTR_CHIP_EC_FEATURE_HW401780</id>
+ <id>ATTR_CHIP_EC_FEATURE_MSS_CHECK_DISABLE_HW_VREF_CAL</id>
<targetType>TARGET_TYPE_PROC_CHIP</targetType>
<description>
- Need AMO caching disabled for multiple defects until Nimbus DD2.0
+ In below DD2 Nimbus, the HW VREF calibration needs to be checked against the chip subversion to see if it can be run.
</description>
<chipEcFeature>
<chip>
@@ -2878,10 +2878,10 @@
</attribute>
<attribute>
- <id>ATTR_CHIP_EC_FEATURE_HW406577</id>
+ <id>ATTR_CHIP_EC_FEATURE_MSS_RUN_RD_CTR_WORKAROUND</id>
<targetType>TARGET_TYPE_PROC_CHIP</targetType>
<description>
- Noise window disabled in DD1 because continually reocurring intermittent UE's can cause us to hang on refreshes.
+ In below DD2 Nimbus, a workaround after read centering might need to be run.
</description>
<chipEcFeature>
<chip>
@@ -2895,10 +2895,12 @@
</attribute>
<attribute>
- <id>ATTR_CHIP_EC_FEATURE_MSS_CHECK_DISABLE_HW_VREF_CAL</id>
+ <id>ATTR_CHIP_EC_FEATURE_MSS_ODT_CONFIG</id>
<targetType>TARGET_TYPE_PROC_CHIP</targetType>
<description>
- In below DD2 Nimbus, the HW VREF calibration needs to be checked against the chip subversion to see if it can be run.
+ For Nimbus pre DD2.** we need to swap ODT2 and ODT3 values in the
+ DDRPHY_SEQ_ODT_RD/WR_CONFIG registers due to a PHY erratum.
+ Post DD2.** will have a hardware enabled fix for this (HW389360).
</description>
<chipEcFeature>
<chip>
@@ -2912,10 +2914,11 @@
</attribute>
<attribute>
- <id>ATTR_CHIP_EC_FEATURE_MSS_RUN_RD_CTR_WORKAROUND</id>
+ <id>ATTR_CHIP_EC_FEATURE_MSS_BLUE_WATERFALL_ADJUST</id>
<targetType>TARGET_TYPE_PROC_CHIP</targetType>
<description>
- In below DD2 Nimbus, a workaround after read centering might need to be run.
+ In DD1.** Nimbus, the blue waterfall can calibrate to an incorrect value. In DD2 Nimbus,
+ This isn't the case as the HW will not allow this calibration value
</description>
<chipEcFeature>
<chip>
@@ -2929,12 +2932,10 @@
</attribute>
<attribute>
- <id>ATTR_CHIP_EC_FEATURE_MSS_ODT_CONFIG</id>
+ <id>ATTR_CHIP_EC_FEATURE_MSS_CHECK_DIABLE_RD_VREF_CAL_VREFSENSE</id>
<targetType>TARGET_TYPE_PROC_CHIP</targetType>
<description>
- For Nimbus pre DD2.** we need to swap ODT2 and ODT3 values in the
- DDRPHY_SEQ_ODT_RD/WR_CONFIG registers due to a PHY erratum.
- Post DD2.** will have a hardware enabled fix for this (HW389360).
+ In below DD2 Nimbus, the RD VREF cal VREF sense needs to be checked against the chip subversion to see if it should be run.
</description>
<chipEcFeature>
<chip>
@@ -2948,11 +2949,10 @@
</attribute>
<attribute>
- <id>ATTR_CHIP_EC_FEATURE_MSS_BLUE_WATERFALL_ADJUST</id>
+ <id>ATTR_CHIP_EC_FEATURE_MSS_DLL_WORKAROUND</id>
<targetType>TARGET_TYPE_PROC_CHIP</targetType>
<description>
- In DD1.** Nimbus, the blue waterfall can calibrate to an incorrect value. In DD2 Nimbus,
- This isn't the case as the HW will not allow this calibration value
+ Run DLL workaround algorithm to fix bad voltage settings pre DD2.0
</description>
<chipEcFeature>
<chip>
@@ -2983,12 +2983,32 @@
</chipEcFeature>
</attribute>
+ <!-- ******************************************************************** -->
+ <!-- End Memory Section -->
+ <!-- ******************************************************************** -->
<attribute>
- <id>ATTR_CHIP_EC_FEATURE_MSS_CHECK_DIABLE_RD_VREF_CAL_VREFSENSE</id>
+ <id>ATTR_CHIP_EC_FEATURE_HW384794</id>
<targetType>TARGET_TYPE_PROC_CHIP</targetType>
<description>
- In below DD2 Nimbus, the RD VREF cal VREF sense needs to be checked against the chip subversion to see if it should be run.
+ Workaround for defect where clock enables to PHY were incorrectly driven
+ </description>
+ <chipEcFeature>
+ <chip>
+ <name>ENUM_ATTR_NAME_NIMBUS</name>
+ <ec>
+ <value>0x20</value>
+ <test>LESS_THAN</test>
+ </ec>
+ </chip>
+ </chipEcFeature>
+ </attribute>
+
+ <attribute>
+ <id>ATTR_CHIP_EC_FEATURE_HW375732</id>
+ <targetType>TARGET_TYPE_PROC_CHIP</targetType>
+ <description>
+ Workaround for Data mismatch discovered by Geyzer at certain async frequency ratios
</description>
<chipEcFeature>
<chip>
@@ -3155,6 +3175,7 @@
</chipEcFeature>
</attribute>
+ <!-- ******************************************************************** -->
<attribute>
<id>ATTR_CHIP_EC_FEATURE_HW399466</id>
<targetType>TARGET_TYPE_PROC_CHIP</targetType>
@@ -3172,6 +3193,7 @@
</chipEcFeature>
</attribute>
+ <!-- ******************************************************************** -->
<attribute>
<id>ATTR_CHIP_EC_FEATURE_HW355538</id>
<targetType>TARGET_TYPE_PROC_CHIP</targetType>
@@ -3189,6 +3211,7 @@
</chipEcFeature>
</attribute>
+ <!-- ******************************************************************** -->
<attribute>
<id>ATTR_CHIP_EC_FEATURE_NEW_MC_DD2_SETTINGS</id>
<targetType>TARGET_TYPE_PROC_CHIP</targetType>
@@ -3206,10 +3229,6 @@
</chipEcFeature>
</attribute>
- <!-- ******************************************************************** -->
- <!-- End Memory Section -->
- <!-- ******************************************************************** -->
-
<!-- ******************************************************************** -->
<attribute>
<id>ATTR_CHIP_EC_FEATURE_DD1_ANALOG</id>
OpenPOWER on IntegriCloud