diff options
Diffstat (limited to 'src/import/chips')
8 files changed, 478 insertions, 6 deletions
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rank.H b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rank.H index 4a3700f54..bdd0a7a3d 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rank.H +++ b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rank.H @@ -81,6 +81,7 @@ enum rank_functions GET_RANK_FIELD = 4, GET_PAIR_VALID = 5, SET_RANK_FIELD = 6, + RD_CTR_WORKAROUND_READ_DATA = 7, }; /// /// @class rankPairTraits 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 cccb0d57e..069b24625 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 @@ -337,6 +337,29 @@ fapi_try_exit: } /// +/// @brief ATTR_CHIP_EC_FEATURE_MSS_RUN_RD_CTR_WOKRAROUND getter +/// @tparam T the fapi2 target type of the target +/// @param[in] const ref to the target +/// @return bool true iff feature is enabled +/// +template< fapi2::TargetType T > +inline bool chip_ec_feature_mss_run_rd_ctr_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_RUN_RD_CTR_WOKRAROUND, l_chip, l_value) ); + + return l_value != 0; + +fapi_try_exit: + FAPI_ERR("failed accessing ATTR_CHIP_EC_FEATURE_MSS_RUN_RD_CTR_WOKRAROUND: 0x%lx (target: %s)", + uint64_t(fapi2::current_err), mss::c_str(i_target)); + fapi2::Assert(false); + return false; +} + +/// /// @brief ATTR_SKIP_RD_VREF_VREFSENSE_OVERRIDE 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 6f9bc77c0..c3d3151f5 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 @@ -423,7 +423,7 @@ fapi2::ReturnCode rank_pair_primary_to_dimm( const fapi2::Target<TARGET_TYPE_MCA // Sanity check the rank pair FAPI_INF("%s rank pair: %d", mss::c_str(i_target), i_rp); - FAPI_ASSERT( i_rp < MAX_RANK_PER_DIMM, + FAPI_ASSERT( i_rp < MAX_RANK_PAIRS, fapi2::MSS_INVALID_RANK_PAIR() .set_RANK_PAIR(i_rp) .set_MCA_TARGET(i_target) @@ -1067,12 +1067,42 @@ fapi2::ReturnCode setup_and_execute_cal( const fapi2::Target<fapi2::TARGET_TYPE_ } } - // 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>()) + // Run cal steps between WR_LEVEL and RD_CTR if any are selected - note DQS_ALIGN takes place after WR_LEVEL + if (i_cal_steps_enabled.getBit + < mss::cal_steps::DQS_ALIGN, mss::cal_steps::STEPS_FROM_DQS_ALIGN_TO_AFTER_RD_CTR_LEN > ()) { - FAPI_DBG("%s Running remaining cal steps on RP%d", mss::c_str(i_target), i_rp); + // Sets up the cal steps in the buffer 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>(); + l_steps_to_execute.clearBit<mss::cal_steps::EXT_ZQCAL>() + .clearBit<mss::cal_steps::WR_LEVEL>() + .clearBit<mss::cal_steps::WRITE_CTR, mss::cal_steps::STEPS_FROM_WR_CTR_TO_COARSE_RD_LEN>(); + + FAPI_INF("%s Running cal steps through read centering on RP%d 0x%04x", mss::c_str(i_target), i_rp, + uint16_t(l_steps_to_execute)); + + // Undertake the calibration steps + FAPI_TRY( execute_cal_steps_helper(i_target, i_rp, l_steps_to_execute, i_abort_on_error) ); + + // Now run the read centering workaround + if(l_steps_to_execute.getBit<READ_CTR>()) + { + FAPI_TRY(mss::workarounds::dp16::rd_dq::fix_delay_values(i_target, i_rp), + "%s Failed to run read centering workaround on rp %d", mss::c_str(i_target), i_rp); + } + } + + // Run cal steps after RD_CTR if any are selected - note: WRITE_CTR takes place after RD_CTR + if (i_cal_steps_enabled.getBit<mss::cal_steps::WRITE_CTR, mss::cal_steps::STEPS_FROM_WR_CTR_TO_COARSE_RD_LEN>()) + { + fapi2::buffer<uint16_t> l_steps_to_execute = i_cal_steps_enabled; + + // Clear until we hit write centering + l_steps_to_execute.clearBit<mss::cal_steps::EXT_ZQCAL, mss::cal_steps::WRITE_CTR>(); + + FAPI_INF("%s Running remaining cal steps after read centering on RP%d 0x%04x", mss::c_str(i_target), i_rp, + uint16_t(l_steps_to_execute)); + + // Undertake the calibration steps FAPI_TRY( execute_cal_steps_helper(i_target, i_rp, l_steps_to_execute, i_abort_on_error) ); } 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 4cb69e317..0c9d0194b 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 @@ -57,6 +57,7 @@ enum sizes BITS_PER_DQS = 2, ///< Differential clock pair MAX_RANKS_DIMM1 = 2, ///< DIMM1 (inner DIMM) can't be a 4R DIMM MAX_PRIMARY_RANKS_PER_PORT = 4, + MAX_RANK_PAIRS = 4, MAX_MRANK_PER_PORT = MAX_DIMM_PER_PORT * MAX_RANK_PER_DIMM, RANK_MID_POINT = 4, ///< Which rank number indicates the switch to the other DIMM DEFAULT_POLL_LIMIT = 50, ///< the number of poll attempts in the event we can't calculate another @@ -153,7 +154,11 @@ 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 + // We can do math here, so this pretties up the code + // Note: a function was investigated but abandoned due to unresolvable compile issues + // Note: for STEPS_FROM_DQS_ALIGN_TO_AFTER_RD_CTR_LEN - READ_CTR/READ_CTR_2D_VREF are run together pick the larger of the steps + STEPS_FROM_DQS_ALIGN_TO_AFTER_RD_CTR_LEN = (READ_CTR_2D_VREF - DQS_ALIGN) + 1, + STEPS_FROM_WR_CTR_TO_COARSE_RD_LEN = (COARSE_RD - WRITE_CTR) + 1, }; // Static consts for DDR4 voltages used in p9_mss_volt diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/dp16_workarounds.C b/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/dp16_workarounds.C index 16d56cf69..ed85cd1d6 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/dp16_workarounds.C +++ b/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/dp16_workarounds.C @@ -416,6 +416,315 @@ fapi2::ReturnCode modify_calibration_results( const fapi2::Target<fapi2::TARGET_ return fix_blue_waterfall_gate( i_target ); } +namespace rd_dq +{ + +/// +/// @brief Reads out the read dq registers and stores the values in a vector +/// @param[in] i_target the fapi2 target of the port +/// @param[in] i_rank_pair the rank pair to operate on +/// @param[out] o_reg_data register conglomerate +/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok +/// +fapi2::ReturnCode get_delay_data(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target, + const uint64_t i_rank_pair, + std::vector<delay_data>& o_reg_data) +{ + static const std::vector<std::vector<uint64_t>> REGISTER = + { + // RANK_PAIR0 + { + MCA_DDRPHY_DP16_READ_DELAY0_RANK_PAIR0_P0_0, + MCA_DDRPHY_DP16_READ_DELAY1_RANK_PAIR0_P0_0, + MCA_DDRPHY_DP16_READ_DELAY2_RANK_PAIR0_P0_0, + MCA_DDRPHY_DP16_READ_DELAY3_RANK_PAIR0_P0_0, + MCA_DDRPHY_DP16_READ_DELAY4_RANK_PAIR0_P0_0, + MCA_DDRPHY_DP16_READ_DELAY5_RANK_PAIR0_P0_0, + MCA_DDRPHY_DP16_READ_DELAY6_RANK_PAIR0_P0_0, + MCA_DDRPHY_DP16_READ_DELAY7_RANK_PAIR0_P0_0, + MCA_DDRPHY_DP16_READ_DELAY0_RANK_PAIR0_P0_1, + MCA_DDRPHY_DP16_READ_DELAY1_RANK_PAIR0_P0_1, + MCA_DDRPHY_DP16_READ_DELAY2_RANK_PAIR0_P0_1, + MCA_DDRPHY_DP16_READ_DELAY3_RANK_PAIR0_P0_1, + MCA_DDRPHY_DP16_READ_DELAY4_RANK_PAIR0_P0_1, + MCA_DDRPHY_DP16_READ_DELAY5_RANK_PAIR0_P0_1, + MCA_DDRPHY_DP16_READ_DELAY6_RANK_PAIR0_P0_1, + MCA_DDRPHY_DP16_READ_DELAY7_RANK_PAIR0_P0_1, + MCA_DDRPHY_DP16_READ_DELAY0_RANK_PAIR0_P0_2, + MCA_DDRPHY_DP16_READ_DELAY1_RANK_PAIR0_P0_2, + MCA_DDRPHY_DP16_READ_DELAY2_RANK_PAIR0_P0_2, + MCA_DDRPHY_DP16_READ_DELAY3_RANK_PAIR0_P0_2, + MCA_DDRPHY_DP16_READ_DELAY4_RANK_PAIR0_P0_2, + MCA_DDRPHY_DP16_READ_DELAY5_RANK_PAIR0_P0_2, + MCA_DDRPHY_DP16_READ_DELAY6_RANK_PAIR0_P0_2, + MCA_DDRPHY_DP16_READ_DELAY7_RANK_PAIR0_P0_2, + MCA_DDRPHY_DP16_READ_DELAY0_RANK_PAIR0_P0_3, + MCA_DDRPHY_DP16_READ_DELAY1_RANK_PAIR0_P0_3, + MCA_DDRPHY_DP16_READ_DELAY2_RANK_PAIR0_P0_3, + MCA_DDRPHY_DP16_READ_DELAY3_RANK_PAIR0_P0_3, + MCA_DDRPHY_DP16_READ_DELAY4_RANK_PAIR0_P0_3, + MCA_DDRPHY_DP16_READ_DELAY5_RANK_PAIR0_P0_3, + MCA_DDRPHY_DP16_READ_DELAY6_RANK_PAIR0_P0_3, + MCA_DDRPHY_DP16_READ_DELAY7_RANK_PAIR0_P0_3, + MCA_DDRPHY_DP16_READ_DELAY0_RANK_PAIR0_P0_4, + MCA_DDRPHY_DP16_READ_DELAY1_RANK_PAIR0_P0_4, + MCA_DDRPHY_DP16_READ_DELAY2_RANK_PAIR0_P0_4, + MCA_DDRPHY_DP16_READ_DELAY3_RANK_PAIR0_P0_4, + }, + // RANK_PAIR1 + { + MCA_DDRPHY_DP16_READ_DELAY0_RANK_PAIR1_P0_0, + MCA_DDRPHY_DP16_READ_DELAY1_RANK_PAIR1_P0_0, + MCA_DDRPHY_DP16_READ_DELAY2_RANK_PAIR1_P0_0, + MCA_DDRPHY_DP16_READ_DELAY3_RANK_PAIR1_P0_0, + MCA_DDRPHY_DP16_READ_DELAY4_RANK_PAIR1_P0_0, + MCA_DDRPHY_DP16_READ_DELAY5_RANK_PAIR1_P0_0, + MCA_DDRPHY_DP16_READ_DELAY6_RANK_PAIR1_P0_0, + MCA_DDRPHY_DP16_READ_DELAY7_RANK_PAIR1_P0_0, + MCA_DDRPHY_DP16_READ_DELAY0_RANK_PAIR1_P0_1, + MCA_DDRPHY_DP16_READ_DELAY1_RANK_PAIR1_P0_1, + MCA_DDRPHY_DP16_READ_DELAY2_RANK_PAIR1_P0_1, + MCA_DDRPHY_DP16_READ_DELAY3_RANK_PAIR1_P0_1, + MCA_DDRPHY_DP16_READ_DELAY4_RANK_PAIR1_P0_1, + MCA_DDRPHY_DP16_READ_DELAY5_RANK_PAIR1_P0_1, + MCA_DDRPHY_DP16_READ_DELAY6_RANK_PAIR1_P0_1, + MCA_DDRPHY_DP16_READ_DELAY7_RANK_PAIR1_P0_1, + MCA_DDRPHY_DP16_READ_DELAY0_RANK_PAIR1_P0_2, + MCA_DDRPHY_DP16_READ_DELAY1_RANK_PAIR1_P0_2, + MCA_DDRPHY_DP16_READ_DELAY2_RANK_PAIR1_P0_2, + MCA_DDRPHY_DP16_READ_DELAY3_RANK_PAIR1_P0_2, + MCA_DDRPHY_DP16_READ_DELAY4_RANK_PAIR1_P0_2, + MCA_DDRPHY_DP16_READ_DELAY5_RANK_PAIR1_P0_2, + MCA_DDRPHY_DP16_READ_DELAY6_RANK_PAIR1_P0_2, + MCA_DDRPHY_DP16_READ_DELAY7_RANK_PAIR1_P0_2, + MCA_DDRPHY_DP16_READ_DELAY0_RANK_PAIR1_P0_3, + MCA_DDRPHY_DP16_READ_DELAY1_RANK_PAIR1_P0_3, + MCA_DDRPHY_DP16_READ_DELAY2_RANK_PAIR1_P0_3, + MCA_DDRPHY_DP16_READ_DELAY3_RANK_PAIR1_P0_3, + MCA_DDRPHY_DP16_READ_DELAY4_RANK_PAIR1_P0_3, + MCA_DDRPHY_DP16_READ_DELAY5_RANK_PAIR1_P0_3, + MCA_DDRPHY_DP16_READ_DELAY6_RANK_PAIR1_P0_3, + MCA_DDRPHY_DP16_READ_DELAY7_RANK_PAIR1_P0_3, + MCA_DDRPHY_DP16_READ_DELAY0_RANK_PAIR1_P0_4, + MCA_DDRPHY_DP16_READ_DELAY1_RANK_PAIR1_P0_4, + MCA_DDRPHY_DP16_READ_DELAY2_RANK_PAIR1_P0_4, + MCA_DDRPHY_DP16_READ_DELAY3_RANK_PAIR1_P0_4, + }, + // RANK_PAIR2 + { + MCA_DDRPHY_DP16_READ_DELAY0_RANK_PAIR2_P0_0, + MCA_DDRPHY_DP16_READ_DELAY1_RANK_PAIR2_P0_0, + MCA_DDRPHY_DP16_READ_DELAY2_RANK_PAIR2_P0_0, + MCA_DDRPHY_DP16_READ_DELAY3_RANK_PAIR2_P0_0, + MCA_DDRPHY_DP16_READ_DELAY4_RANK_PAIR2_P0_0, + MCA_DDRPHY_DP16_READ_DELAY5_RANK_PAIR2_P0_0, + MCA_DDRPHY_DP16_READ_DELAY6_RANK_PAIR2_P0_0, + MCA_DDRPHY_DP16_READ_DELAY7_RANK_PAIR2_P0_0, + MCA_DDRPHY_DP16_READ_DELAY0_RANK_PAIR2_P0_1, + MCA_DDRPHY_DP16_READ_DELAY1_RANK_PAIR2_P0_1, + MCA_DDRPHY_DP16_READ_DELAY2_RANK_PAIR2_P0_1, + MCA_DDRPHY_DP16_READ_DELAY3_RANK_PAIR2_P0_1, + MCA_DDRPHY_DP16_READ_DELAY4_RANK_PAIR2_P0_1, + MCA_DDRPHY_DP16_READ_DELAY5_RANK_PAIR2_P0_1, + MCA_DDRPHY_DP16_READ_DELAY6_RANK_PAIR2_P0_1, + MCA_DDRPHY_DP16_READ_DELAY7_RANK_PAIR2_P0_1, + MCA_DDRPHY_DP16_READ_DELAY0_RANK_PAIR2_P0_2, + MCA_DDRPHY_DP16_READ_DELAY1_RANK_PAIR2_P0_2, + MCA_DDRPHY_DP16_READ_DELAY2_RANK_PAIR2_P0_2, + MCA_DDRPHY_DP16_READ_DELAY3_RANK_PAIR2_P0_2, + MCA_DDRPHY_DP16_READ_DELAY4_RANK_PAIR2_P0_2, + MCA_DDRPHY_DP16_READ_DELAY5_RANK_PAIR2_P0_2, + MCA_DDRPHY_DP16_READ_DELAY6_RANK_PAIR2_P0_2, + MCA_DDRPHY_DP16_READ_DELAY7_RANK_PAIR2_P0_2, + MCA_DDRPHY_DP16_READ_DELAY0_RANK_PAIR2_P0_3, + MCA_DDRPHY_DP16_READ_DELAY1_RANK_PAIR2_P0_3, + MCA_DDRPHY_DP16_READ_DELAY2_RANK_PAIR2_P0_3, + MCA_DDRPHY_DP16_READ_DELAY3_RANK_PAIR2_P0_3, + MCA_DDRPHY_DP16_READ_DELAY4_RANK_PAIR2_P0_3, + MCA_DDRPHY_DP16_READ_DELAY5_RANK_PAIR2_P0_3, + MCA_DDRPHY_DP16_READ_DELAY6_RANK_PAIR2_P0_3, + MCA_DDRPHY_DP16_READ_DELAY7_RANK_PAIR2_P0_3, + MCA_DDRPHY_DP16_READ_DELAY0_RANK_PAIR2_P0_4, + MCA_DDRPHY_DP16_READ_DELAY1_RANK_PAIR2_P0_4, + MCA_DDRPHY_DP16_READ_DELAY2_RANK_PAIR2_P0_4, + MCA_DDRPHY_DP16_READ_DELAY3_RANK_PAIR2_P0_4, + }, + // RANK_PAIR3 + { + MCA_DDRPHY_DP16_READ_DELAY0_RANK_PAIR3_P0_0, + MCA_DDRPHY_DP16_READ_DELAY1_RANK_PAIR3_P0_0, + MCA_DDRPHY_DP16_READ_DELAY2_RANK_PAIR3_P0_0, + MCA_DDRPHY_DP16_READ_DELAY3_RANK_PAIR3_P0_0, + MCA_DDRPHY_DP16_READ_DELAY4_RANK_PAIR3_P0_0, + MCA_DDRPHY_DP16_READ_DELAY5_RANK_PAIR3_P0_0, + MCA_DDRPHY_DP16_READ_DELAY6_RANK_PAIR3_P0_0, + MCA_DDRPHY_DP16_READ_DELAY7_RANK_PAIR3_P0_0, + MCA_DDRPHY_DP16_READ_DELAY0_RANK_PAIR3_P0_1, + MCA_DDRPHY_DP16_READ_DELAY1_RANK_PAIR3_P0_1, + MCA_DDRPHY_DP16_READ_DELAY2_RANK_PAIR3_P0_1, + MCA_DDRPHY_DP16_READ_DELAY3_RANK_PAIR3_P0_1, + MCA_DDRPHY_DP16_READ_DELAY4_RANK_PAIR3_P0_1, + MCA_DDRPHY_DP16_READ_DELAY5_RANK_PAIR3_P0_1, + MCA_DDRPHY_DP16_READ_DELAY6_RANK_PAIR3_P0_1, + MCA_DDRPHY_DP16_READ_DELAY7_RANK_PAIR3_P0_1, + MCA_DDRPHY_DP16_READ_DELAY0_RANK_PAIR3_P0_2, + MCA_DDRPHY_DP16_READ_DELAY1_RANK_PAIR3_P0_2, + MCA_DDRPHY_DP16_READ_DELAY2_RANK_PAIR3_P0_2, + MCA_DDRPHY_DP16_READ_DELAY3_RANK_PAIR3_P0_2, + MCA_DDRPHY_DP16_READ_DELAY4_RANK_PAIR3_P0_2, + MCA_DDRPHY_DP16_READ_DELAY5_RANK_PAIR3_P0_2, + MCA_DDRPHY_DP16_READ_DELAY6_RANK_PAIR3_P0_2, + MCA_DDRPHY_DP16_READ_DELAY7_RANK_PAIR3_P0_2, + MCA_DDRPHY_DP16_READ_DELAY0_RANK_PAIR3_P0_3, + MCA_DDRPHY_DP16_READ_DELAY1_RANK_PAIR3_P0_3, + MCA_DDRPHY_DP16_READ_DELAY2_RANK_PAIR3_P0_3, + MCA_DDRPHY_DP16_READ_DELAY3_RANK_PAIR3_P0_3, + MCA_DDRPHY_DP16_READ_DELAY4_RANK_PAIR3_P0_3, + MCA_DDRPHY_DP16_READ_DELAY5_RANK_PAIR3_P0_3, + MCA_DDRPHY_DP16_READ_DELAY6_RANK_PAIR3_P0_3, + MCA_DDRPHY_DP16_READ_DELAY7_RANK_PAIR3_P0_3, + MCA_DDRPHY_DP16_READ_DELAY0_RANK_PAIR3_P0_4, + MCA_DDRPHY_DP16_READ_DELAY1_RANK_PAIR3_P0_4, + MCA_DDRPHY_DP16_READ_DELAY2_RANK_PAIR3_P0_4, + MCA_DDRPHY_DP16_READ_DELAY3_RANK_PAIR3_P0_4, + }, + }; + + // Bombs out if the rank pair is out of range + + FAPI_ASSERT( i_rank_pair < MAX_RANK_PAIRS, + fapi2::MSS_INVALID_RANK_PAIR() + .set_RANK_PAIR(i_rank_pair) + .set_MCA_TARGET(i_target) + .set_FUNCTION(RD_CTR_WORKAROUND_READ_DATA), + "%s Invalid rank pair (%d) in get_ranks_in_pair", + mss::c_str(i_target), + i_rank_pair); + + // loops and gets the registers + o_reg_data.clear(); + + for(const auto l_reg : REGISTER[i_rank_pair]) + { + constexpr uint64_t EVEN_START = MCA_DDRPHY_DP16_READ_DELAY0_RANK_PAIR0_P0_0_01_RD; + constexpr uint64_t ODD_START = MCA_DDRPHY_DP16_READ_DELAY0_RANK_PAIR0_P0_0_01_RD_DELAY1; + fapi2::buffer<uint64_t> l_buff; + uint64_t l_data = 0; + + // Reads the register information + FAPI_TRY(mss::getScom(i_target, l_reg, l_buff), "%s failed getscom to register 0x%016lx", mss::c_str(i_target), l_reg); + + // Gets out the specific information and stores it + // Even delay + l_buff.extractToRight<EVEN_START, delay_data::LEN>(l_data); + o_reg_data.push_back({l_reg, EVEN_START, l_data}); + + // Odd delay + l_buff.extractToRight<ODD_START, delay_data::LEN>(l_data); + o_reg_data.push_back({l_reg, ODD_START, l_data}); + } + +fapi_try_exit: + return fapi2::current_err; +} +/// +/// @brief Finds the median and sorts the vector +/// @param[in,out] io_reg_data register data +/// @param[out] o_median the median value +/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok +/// +fapi2::ReturnCode find_median_and_sort(std::vector<delay_data>& io_reg_data, uint64_t& o_median) +{ + + // The fapi_try is in an if statement, this ensures we have a good value + fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; + + // Bomb out if the vector is empty to avoid accessing a non-existant element + FAPI_ASSERT(!io_reg_data.empty(), + fapi2::MSS_RD_CTR_WORKAROUND_EMPTY_VECTOR(), + "Empty vector passed in to find_median_and_sort" + ); + + // Sorts first + std::sort(io_reg_data.begin(), io_reg_data.end()); + + // TODO:RTC172759 Add generic median function - that can replace the below code + // Finding the median is simply a matter of finding the midway point and getting the data there + { + const auto l_median_it = io_reg_data.begin() + io_reg_data.size() / 2; + o_median = l_median_it->iv_data; + } + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Overrides any bad (out of range) read delay values with the median value +/// @param[in] i_target the fapi2 target of the port +/// @param[in] i_rank_pair the rank pair to operate on +/// @param[in] i_percent the percentage below the median outside of which to override values to be the median - OPTIONAL - defaults to 66 +/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok +/// +fapi2::ReturnCode fix_delay_values(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target, + const uint64_t i_rank_pair, + const uint64_t i_percent) +{ + if(!mss::chip_ec_feature_mss_run_rd_ctr_workaround(i_target)) + { + FAPI_INF("%s skipping the rd centering workaround!", mss::c_str(i_target)); + return fapi2::FAPI2_RC_SUCCESS; + } + + std::vector<delay_data> l_reg_data; + uint64_t l_median = 0; + + FAPI_TRY(get_delay_data(i_target, i_rank_pair, l_reg_data), "%s i_rank_pair %d failed to get the delay data", + mss::c_str(i_target), i_rank_pair); + + FAPI_TRY(find_median_and_sort(l_reg_data, l_median), "%s i_rank_pair %d failed to find median value and sort", + mss::c_str(i_target), i_rank_pair); + + FAPI_INF("%s i_rank_pair %d found a median of 0x%02x any value below %d %% of the median will be modified", + mss::c_str(i_target), i_rank_pair, l_median, i_percent); + + // Overrides the bad delay values - the ones that are i_percent below the median + { + // Finds the iterator corresponding to the first location where we are within i_percent of the median + const auto l_last = std::find_if(l_reg_data.begin(), l_reg_data.end(), [ i_percent, + l_median]( const delay_data & i_rhs) -> bool + { + // Does this funky compare to avoid underflow + const auto l_comp_value = (i_percent * l_median) / 100; + return l_comp_value < i_rhs.iv_data; + }); + + // Loops and does the overrides + // Note: does a simple RMW, we can speed this up by doing a more complex algorithm to sort registers together. + // Keeping it simple for now + for( auto l_it = l_reg_data.begin(); l_it < l_last; ++l_it) + { + fapi2::buffer<uint64_t> l_buff; + FAPI_INF("%s i_rank_pair %d modifying delay position %d on register 0x%016lx from 0x%02x to be 0x%02x", + mss::c_str(i_target), i_rank_pair, l_it->iv_bit, l_it->iv_register, l_it->iv_data, l_median); + + // Read + FAPI_TRY(mss::getScom(i_target, l_it->iv_register, l_buff)); + + // Modify + FAPI_TRY(l_buff.insertFromRight(l_median, l_it->iv_bit, delay_data::LEN)); + + // Write + FAPI_TRY(mss::putScom(i_target, l_it->iv_register, l_buff)); + } + } + +fapi_try_exit: + return fapi2::current_err; +} + +} // close namespace rd_dq + namespace wr_vref { diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/dp16_workarounds.H b/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/dp16_workarounds.H index 03ecb9b2e..2db02bf34 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/dp16_workarounds.H +++ b/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/dp16_workarounds.H @@ -279,6 +279,82 @@ fapi2::ReturnCode rd_vref_vref_sense_setup( const fapi2::Target<fapi2::TARGET_TY fapi2::ReturnCode post_training_workarounds( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target, const fapi2::buffer<uint16_t>& i_cal_steps_enabled ); +namespace rd_dq +{ + +/// +/// @brief Declares a struct to simplify the rd_dq workaround +/// +struct delay_data +{ + // Deletes base constructor + delay_data() = delete; + + /// + /// @brief Constructor + /// @param[in] i_register - register info + /// @param[in] i_bit - bit position info + /// @param[in] i_data - data stored in the register + /// + delay_data(const uint64_t i_register, const uint64_t i_bit, const uint64_t& i_data) : + iv_register(i_register), + iv_bit(i_bit), + iv_data(i_data) + {} + + /// + /// @brief Default destructor + /// + ~delay_data() = default; + + /// + /// @brief Comparison operator + /// @param[in] i_rhs - delay_info to compare against + /// @return bool - true if the right hand side is greater + bool operator<(const delay_data& i_rhs) const + { + // For this class, we only care about the delay value + return iv_data < i_rhs.iv_data; + } + + static constexpr uint64_t LEN = MCA_DDRPHY_DP16_READ_DELAY0_RANK_PAIR0_P0_0_01_RD_LEN; + uint64_t iv_register; + uint64_t iv_bit; + uint64_t iv_data; +}; + +/// +/// @brief Reads out the read dq registers and stores the values in a vector +/// @param[in] i_target the fapi2 target of the port +/// @param[in] i_rank_pair the rank pair to operate on +/// @param[out] o_reg_data register conglomerate +/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok +/// +fapi2::ReturnCode get_delay_data(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target, + const uint64_t i_rank_pair, + std::vector<delay_data>& o_reg_data); + +/// +/// @brief Finds the median and sorts the vector +/// @param[in,out] io_reg_data register data +/// @param[out] o_median the median value +/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok +/// +fapi2::ReturnCode find_median_and_sort(std::vector<delay_data>& io_reg_data, uint64_t& o_median); + +/// +/// @brief Overrides any bad (out of range) read delay values with the median value +/// @param[in] i_target the fapi2 target of the port +/// @param[in] i_rank_pair the rank pair to operate on +/// @param[in] i_percent the percentage below the median outside of which to override values to be the median - OPTIONAL - defaults to 66 +/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok +/// +fapi2::ReturnCode fix_delay_values(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target, + const uint64_t i_rank_pair, + const uint64_t i_percent = 66); + +} // close namespace rd_dq + namespace wr_vref { 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 78e5443a1..a950b489a 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 @@ -2676,6 +2676,23 @@ </attribute> <attribute> + <id>ATTR_CHIP_EC_FEATURE_MSS_RUN_RD_CTR_WOKRAROUND</id> + <targetType>TARGET_TYPE_PROC_CHIP</targetType> + <description> + In below DD2 Nimbus, a workaround after read centering might need to be run. + </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_MSS_ODT_CONFIG</id> <targetType>TARGET_TYPE_PROC_CHIP</targetType> <description> diff --git a/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_draminit_training.xml b/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_draminit_training.xml index 8a1342744..a10c43e20 100644 --- a/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_draminit_training.xml +++ b/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_draminit_training.xml @@ -642,4 +642,15 @@ </gard> </hwpError> +<hwpError> + <rc>RC_MSS_RD_CTR_WORKAROUND_EMPTY_VECTOR</rc> + <description> + An empty vector was passed into the find_median_and_sort function + </description> + <callout> + <procedure>CODE</procedure> + <priority>HIGH</priority> + </callout> +</hwpError> + </hwpErrors> |