summaryrefslogtreecommitdiffstats
path: root/src/import/chips/p9
diff options
context:
space:
mode:
authorStephen Glancy <sglancy@us.ibm.com>2017-01-23 10:25:55 -0600
committerDaniel M. Crowell <dcrowell@us.ibm.com>2017-01-30 11:40:56 -0500
commitef02e47839d9c312606cd7b51be614ec695d76ba (patch)
treeeeb83dd18200717156386a29e3fbee07767476ef /src/import/chips/p9
parent3933a5cbfc15fc4184b4c1045e558da232a83e5b (diff)
downloadtalos-hostboot-ef02e47839d9c312606cd7b51be614ec695d76ba.tar.gz
talos-hostboot-ef02e47839d9c312606cd7b51be614ec695d76ba.zip
Added periodic cal fix - fixes bad delays
Change-Id: I8c55c2947dd85cc9ada45aaa9225ce641633f259 Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/35239 Reviewed-by: Brian R. Silver <bsilver@us.ibm.com> Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com> Tested-by: PPE CI <ppe-ci+hostboot@us.ibm.com> Reviewed-by: JACOB L. HARVEY <jlharvey@us.ibm.com> Dev-Ready: STEPHEN GLANCY <sglancy@us.ibm.com> Tested-by: Hostboot CI <hostboot-ci+hostboot@us.ibm.com> Reviewed-by: Matt K. Light <mklight@us.ibm.com> Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com> Reviewed-by: Jennifer A. Stofer <stofer@us.ibm.com> Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/35335 Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com> Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com>
Diffstat (limited to 'src/import/chips/p9')
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/mss_attribute_accessors_manual.H27
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/phy/dp16.C4
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/phy/dp16.H93
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/workarounds/dp16_workarounds.C122
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/workarounds/dp16_workarounds.H67
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/p9_mss_draminit_training.C4
-rw-r--r--src/import/chips/p9/procedures/hwp/perv/p9_getecid.C1
-rw-r--r--src/import/chips/p9/procedures/xml/attribute_info/chip_ec_attributes.xml18
-rw-r--r--src/import/chips/p9/procedures/xml/attribute_info/memory_workarounds_attributes.xml14
9 files changed, 348 insertions, 2 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 ee9205500..87e3e52c9 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
@@ -31,7 +31,7 @@
/// a work-around they'd be burdened with updating this file.
///
// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
-// *HWP HWP Backup: Steven Glancy <sglancy@usi.ibm.com>
+// *HWP HWP Backup: Stephen Glancy <sglancy@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 3
// *HWP Consumed by: Memory
@@ -253,6 +253,31 @@ fapi_try_exit:
return false;
}
+///
+/// @brief ATTR_CHIP_EC_FEATURE_MSS_BLUE_WATERFALL_ADJUST 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_blue_waterfall_adjust(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;
+ uint8_t l_do_value = 0;
+
+ FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_CHIP_EC_FEATURE_MSS_BLUE_WATERFALL_ADJUST, l_chip, l_value) );
+ FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_DO_BLUE_WATERFALL_ADJUST, l_chip, l_do_value) );
+
+ return (l_value != 0) && (l_do_value == fapi2::ENUM_ATTR_DO_BLUE_WATERFALL_ADJUST_YES);
+
+fapi_try_exit:
+ FAPI_ERR("failed accessing ATTR_CHIP_EC_FEATURE_MSS_WR_VREF or ATTR_DO_MSS_WR_VREF: 0x%lx (target: %s)",
+ uint64_t(fapi2::current_err), mss::c_str(i_target));
+ fapi2::Assert(false);
+ return false;
+}
+
} // close mss namespace
#endif
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/phy/dp16.C b/src/import/chips/p9/procedures/hwp/memory/lib/phy/dp16.C
index fab3712cd..968944ddc 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/phy/dp16.C
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/phy/dp16.C
@@ -468,6 +468,10 @@ const std::vector< std::vector<std::pair<uint64_t, uint64_t>> > dp16Traits<TARGE
},
};
+// we need these declarations here in order for the linker to see the definitions
+constexpr const uint64_t dp16Traits<fapi2::TARGET_TYPE_MCA>::GATE_DELAY_BIT_POS[];
+constexpr const uint64_t dp16Traits<fapi2::TARGET_TYPE_MCA>::BLUE_WATERFALL_BIT_POS[];
+
///
/// @brief Given a RD_VREF value, create a PHY 'standard' bit field for that percentage.
/// @tparam T fapi2 Target Type - derived
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 9fb1b1ae3..597d5047e 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
@@ -123,6 +123,9 @@ class dp16Traits<fapi2::TARGET_TYPE_MCA>
// Maximum number of DRAM's per DP
static constexpr uint64_t MAX_DRAM_PER_DP = 4;
+ // Number of quads per DP16
+ static constexpr uint64_t NUM_QUAD_PER_DP16 = 4;
+
// Number of instances of the DLL per DP16. Used for checking parameters, the rest of the
// code assumes 2 DLL per DP16. There are no DLL in Centaur so we don't need to worry about
// any of this for some time.
@@ -164,7 +167,7 @@ class dp16Traits<fapi2::TARGET_TYPE_MCA>
static const std::vector<std::vector<std::pair<uint64_t, uint64_t>>> BIT_DISABLE_REG;
- //WR VREF registers
+ // WR VREF registers
static const std::vector< uint64_t > WR_VREF_CONFIG0_REG;
static const std::vector< uint64_t > WR_VREF_CONFIG1_REG;
static const std::vector< uint64_t > WR_VREF_STATUS0_REG;
@@ -176,6 +179,22 @@ class dp16Traits<fapi2::TARGET_TYPE_MCA>
static const std::vector< std::pair<uint64_t, uint64_t> > WR_VREF_VALUE_RP2_REG;
static const std::vector< std::pair<uint64_t, uint64_t> > WR_VREF_VALUE_RP3_REG;
+ // Definitions of the gate delay and waterfall bits' locations
+ constexpr static const uint64_t GATE_DELAY_BIT_POS[NUM_QUAD_PER_DP16] =
+ {
+ MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP0_P0_0_01_N0,
+ MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP0_P0_0_01_N1,
+ MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP0_P0_0_01_N2,
+ MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP0_P0_0_01_N3,
+ };
+ constexpr static const uint64_t BLUE_WATERFALL_BIT_POS[NUM_QUAD_PER_DP16] =
+ {
+ MCA_DDRPHY_DP16_DQS_RD_PHASE_SELECT_RANK_PAIR0_P0_0_01_RDCLK_SELECT0,
+ MCA_DDRPHY_DP16_DQS_RD_PHASE_SELECT_RANK_PAIR0_P0_0_01_RDCLK_SELECT1,
+ MCA_DDRPHY_DP16_DQS_RD_PHASE_SELECT_RANK_PAIR0_P0_0_01_RDCLK_SELECT2,
+ MCA_DDRPHY_DP16_DQS_RD_PHASE_SELECT_RANK_PAIR0_P0_0_01_RDCLK_SELECT3,
+ };
+
enum
{
DLL_CNTL_INIT_RXDLL_CAL_RESET = MCA_DDRPHY_DP16_DLL_CNTL0_P0_0_01_INIT_RXDLL_CAL_RESET,
@@ -224,6 +243,10 @@ class dp16Traits<fapi2::TARGET_TYPE_MCA>
IO_TX_PFET_TERM_EN_P_WR = MCA_DDRPHY_DP16_IO_TX_PFET_TERM_P0_0_01_EN_P_WR,
IO_TX_PFET_TERM_EN_P_WR_LEN = MCA_DDRPHY_DP16_IO_TX_PFET_TERM_P0_0_01_EN_P_WR_LEN,
+ GATE_DELAY_LEN = MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP0_P0_0_01_N0_LEN,
+ // Both blue and red waterfalls are the same number of bits
+ WATERFALL_LEN = MCA_DDRPHY_DP16_DQS_RD_PHASE_SELECT_RANK_PAIR0_P0_0_01_RDCLK_SELECT0_LEN,
+
////////////////////////////////////////
// WR VREF register field information //
////////////////////////////////////////
@@ -1773,6 +1796,74 @@ template< fapi2::TargetType T, typename TT = dp16Traits<T> >
fapi2::ReturnCode write_force_fifo_capture( const fapi2::Target<T>& i_target,
const mss::states i_state);
+///
+/// @brief Get the blue waterfall for the given quad
+/// @tparam uint64_t QUAD - which quad to access
+/// @tparam T fapi2 Target Type - defaults to TARGET_TYPE_MCA
+/// @tparam TT traits type defaults to dp16Traits<T>
+/// @param[in] i_data the value of the register
+/// @return value of the blue waterfall
+///
+template< uint64_t QUAD, fapi2::TargetType T = fapi2::TARGET_TYPE_MCA, typename TT = dp16Traits<T> >
+inline uint64_t get_blue_waterfall( const fapi2::buffer<uint64_t>& i_data )
+{
+
+ static_assert(QUAD < TT::NUM_QUAD_PER_DP16, "Inserted quad value is not less than the maximum value");
+ uint64_t l_waterfall = 0;
+ i_data.extractToRight<TT::BLUE_WATERFALL_BIT_POS[QUAD], TT::WATERFALL_LEN>(l_waterfall);
+ return l_waterfall;
+}
+
+///
+/// @brief Get the gate delay for the given quad
+/// @tparam uint64_t QUAD - which quad to access
+/// @tparam T fapi2 Target Type - defaults to TARGET_TYPE_MCA
+/// @tparam TT traits type defaults to dp16Traits<T>
+/// @param[in] i_data the value of the register
+/// @return value of the gate delay
+///
+template< uint64_t QUAD, fapi2::TargetType T = fapi2::TARGET_TYPE_MCA, typename TT = dp16Traits<T> >
+inline uint64_t get_gate_delay( const fapi2::buffer<uint64_t>& i_data )
+{
+
+ static_assert(QUAD < TT::NUM_QUAD_PER_DP16, "Inserted quad value is not less than the maximum value");
+ uint64_t l_gate_delay = 0;
+ i_data.extractToRight<TT::GATE_DELAY_BIT_POS[QUAD], TT::GATE_DELAY_LEN>(l_gate_delay);
+ return l_gate_delay;
+}
+
+///
+/// @brief Set the blue waterfall for the given quad
+/// @tparam uint64_t QUAD - which quad to access
+/// @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] value of the blue waterfall
+///
+template< uint64_t QUAD, fapi2::TargetType T = fapi2::TARGET_TYPE_MCA, typename TT = dp16Traits<T> >
+inline void set_blue_waterfall( fapi2::buffer<uint64_t>& io_data, const uint64_t i_waterfall )
+{
+
+ static_assert(QUAD < TT::NUM_QUAD_PER_DP16, "QUAD value is not less than the maximum value");
+ io_data.insertFromRight<TT::BLUE_WATERFALL_BIT_POS[QUAD], TT::WATERFALL_LEN>(i_waterfall);
+}
+
+///
+/// @brief Set the gate delay for the given quad
+/// @tparam uint64_t QUAD - which quad to access
+/// @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] value of the gate delay
+///
+template< uint64_t QUAD, fapi2::TargetType T = fapi2::TARGET_TYPE_MCA, typename TT = dp16Traits<T> >
+inline void set_gate_delay( fapi2::buffer<uint64_t>& io_data, const uint64_t i_gate_delay )
+{
+
+ static_assert(QUAD < TT::NUM_QUAD_PER_DP16, "QUAD value is not less than the maximum value");
+ io_data.insertFromRight<TT::GATE_DELAY_BIT_POS[QUAD], TT::GATE_DELAY_LEN>(i_gate_delay);
+}
+
} // close namespace dp16
} // close namespace mss
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 67a152547..78ca353a7 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
@@ -192,6 +192,128 @@ fapi_try_exit:
return fapi2::current_err;
}
+///
+/// @brief Fixes blue waterfall values in a port
+/// @param[in] i_target - the target to operate on
+/// @param[in] i_always_run - ignores the attribute and always run - default = false
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
+///
+fapi2::ReturnCode fix_blue_waterfall_gate( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const bool i_always_run )
+{
+ // Checks if the workaround needs to be run
+ const bool l_attr_value = mss::chip_ec_feature_blue_waterfall_adjust(i_target);
+
+ if(!l_attr_value && !i_always_run)
+ {
+ FAPI_DBG("Skipping running fix_blue_waterfall_gate i_always_run %s attr %s", i_always_run ? "true" : "false",
+ l_attr_value ? "true" : "false" );
+ return fapi2::FAPI2_RC_SUCCESS;
+ }
+
+ // Loops through the first 4 DP's as the last DP is a DP08 so we only need to do 2 quads
+ // TK update to hit all rank pairs
+ const std::vector<std::vector<std::pair<uint64_t, uint64_t>>> l_dp16_registers =
+ {
+ {
+ {MCA_DDRPHY_DP16_DQS_RD_PHASE_SELECT_RANK_PAIR0_P0_0, MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP0_P0_0},
+ {MCA_DDRPHY_DP16_DQS_RD_PHASE_SELECT_RANK_PAIR0_P0_1, MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP0_P0_1},
+ {MCA_DDRPHY_DP16_DQS_RD_PHASE_SELECT_RANK_PAIR0_P0_2, MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP0_P0_2},
+ {MCA_DDRPHY_DP16_DQS_RD_PHASE_SELECT_RANK_PAIR0_P0_3, MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP0_P0_3},
+ },
+ {
+ {MCA_DDRPHY_DP16_DQS_RD_PHASE_SELECT_RANK_PAIR1_P0_0, MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP1_P0_0},
+ {MCA_DDRPHY_DP16_DQS_RD_PHASE_SELECT_RANK_PAIR1_P0_1, MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP1_P0_1},
+ {MCA_DDRPHY_DP16_DQS_RD_PHASE_SELECT_RANK_PAIR1_P0_2, MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP1_P0_2},
+ {MCA_DDRPHY_DP16_DQS_RD_PHASE_SELECT_RANK_PAIR1_P0_3, MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP1_P0_3},
+ },
+ {
+ {MCA_DDRPHY_DP16_DQS_RD_PHASE_SELECT_RANK_PAIR2_P0_0, MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP2_P0_0},
+ {MCA_DDRPHY_DP16_DQS_RD_PHASE_SELECT_RANK_PAIR2_P0_1, MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP2_P0_1},
+ {MCA_DDRPHY_DP16_DQS_RD_PHASE_SELECT_RANK_PAIR2_P0_2, MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP2_P0_2},
+ {MCA_DDRPHY_DP16_DQS_RD_PHASE_SELECT_RANK_PAIR2_P0_3, MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP2_P0_3},
+ },
+ {
+ {MCA_DDRPHY_DP16_DQS_RD_PHASE_SELECT_RANK_PAIR3_P0_0, MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP3_P0_0},
+ {MCA_DDRPHY_DP16_DQS_RD_PHASE_SELECT_RANK_PAIR3_P0_1, MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP3_P0_1},
+ {MCA_DDRPHY_DP16_DQS_RD_PHASE_SELECT_RANK_PAIR3_P0_2, MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP3_P0_2},
+ {MCA_DDRPHY_DP16_DQS_RD_PHASE_SELECT_RANK_PAIR3_P0_3, MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP3_P0_3},
+ },
+ };
+ const std::vector<std::pair<uint64_t, uint64_t>> l_dp08_registers =
+ {
+ {MCA_DDRPHY_DP16_DQS_RD_PHASE_SELECT_RANK_PAIR0_P0_4, MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP0_P0_4},
+ {MCA_DDRPHY_DP16_DQS_RD_PHASE_SELECT_RANK_PAIR1_P0_4, MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP1_P0_4},
+ {MCA_DDRPHY_DP16_DQS_RD_PHASE_SELECT_RANK_PAIR2_P0_4, MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP2_P0_4},
+ {MCA_DDRPHY_DP16_DQS_RD_PHASE_SELECT_RANK_PAIR3_P0_4, MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP3_P0_4},
+ };
+
+ // Gets the number of primary ranks to loop through
+ std::vector<uint64_t> l_primary_ranks;
+ FAPI_TRY(mss::rank::primary_ranks(i_target, l_primary_ranks));
+
+ // Loops through all configured rank pairs
+ for(uint64_t l_rp = 0; l_rp < l_primary_ranks.size(); ++l_rp)
+ {
+ // Loops through all DP16s
+ for(const auto& l_reg : l_dp16_registers[l_rp])
+ {
+ fapi2::buffer<uint64_t> l_waterfall;
+ fapi2::buffer<uint64_t> l_gate_delay;
+
+ // Getscoms
+ FAPI_TRY(mss::getScom(i_target, l_reg.first, l_waterfall), "Failed to getScom from 0x%016lx", l_reg.first);
+ FAPI_TRY(mss::getScom(i_target, l_reg.second, l_gate_delay), "Failed to getScom from 0x%016lx", l_reg.second);
+
+ // Updates the data for all quads
+ update_blue_waterfall_gate_delay_for_quad<0>(l_waterfall, l_gate_delay);
+ update_blue_waterfall_gate_delay_for_quad<1>(l_waterfall, l_gate_delay);
+ update_blue_waterfall_gate_delay_for_quad<2>(l_waterfall, l_gate_delay);
+ update_blue_waterfall_gate_delay_for_quad<3>(l_waterfall, l_gate_delay);
+
+ // Putscoms
+ FAPI_TRY(mss::putScom(i_target, l_reg.first, l_waterfall), "Failed to putScom to 0x%016lx", l_reg.first);
+ FAPI_TRY(mss::putScom(i_target, l_reg.second, l_gate_delay), "Failed to putScom to 0x%016lx", l_reg.second);
+ }
+
+ // Now for the odd man out - the DP08, as it only has two quads.
+ // Note: We are not modifying the non-existant quads, as changing values in the non-existant DP08 has caused FIRs
+ {
+ fapi2::buffer<uint64_t> l_waterfall;
+ fapi2::buffer<uint64_t> l_gate_delay;
+
+ // Getscoms
+ FAPI_TRY(mss::getScom(i_target, l_dp08_registers[l_rp].first, l_waterfall), "Failed to getScom from 0x%016lx",
+ l_dp08_registers[l_rp].first);
+ FAPI_TRY(mss::getScom(i_target, l_dp08_registers[l_rp].second, l_gate_delay), "Failed to getScom from 0x%016lx",
+ l_dp08_registers[l_rp].second);
+
+ // Updates the data for all quads
+ update_blue_waterfall_gate_delay_for_quad<0>(l_waterfall, l_gate_delay);
+ update_blue_waterfall_gate_delay_for_quad<1>(l_waterfall, l_gate_delay);
+
+ // Putscoms
+ FAPI_TRY(mss::putScom(i_target, l_dp08_registers[l_rp].first, l_waterfall), "Failed to putScom to 0x%016lx",
+ l_dp08_registers[l_rp].first);
+ FAPI_TRY(mss::putScom(i_target, l_dp08_registers[l_rp].second, l_gate_delay), "Failed to putScom to 0x%016lx",
+ l_dp08_registers[l_rp].second);
+ }
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Modifies HW calibration results based upon workarounds
+/// @param[in] i_target - the target to operate on
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
+///
+fapi2::ReturnCode modify_calibration_results( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target )
+{
+ return fix_blue_waterfall_gate( i_target );
+}
+
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 c7fc99d96..25e6efc97 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
@@ -42,6 +42,7 @@
#include <p9_mc_scom_addresses.H>
#include <p9_mc_scom_addresses_fld.H>
#include <mss_attribute_accessors.H>
+#include <lib/phy/dp16.H>
namespace mss
{
@@ -185,6 +186,72 @@ fapi_try_exit:
///
fapi2::ReturnCode after_phy_reset( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target );
+///
+/// @brief Updates gate delay and blue waterfall (aka RDCLK phase select) values based upon blue waterfall values
+/// @param[in,out] io_blue_waterfall - the blue waterfall value
+/// @param[in,out] io_gate_delay - the gate delay value
+///
+inline void update_blue_waterfall_gate_delay(uint64_t& io_blue_waterfall, uint64_t& io_gate_delay)
+{
+ // The PHY should never have a blue waterfall value of a 0 - if so, change it to a 3, and decrease one off the gate delay
+ // The blue waterfall is a quarter clock cycle delay - the current thinking is that a value of a 0 is a value of a 4
+ // In this case the delay was large enough, so that a value of a 3 rolled over to another clock cycle.
+ // The value of a 0 is considered to be incorrect but can be passable, as the gate delay calibrates in an extra cycle of delay
+ // So, if there is a 0 value in the blue waterfall, change it to the max, a 3, and subtract one off the gate delay to have correct timing
+ constexpr uint64_t BW_INCORRECT = 0;
+ constexpr uint64_t BW_MAX = 3;
+
+ // Check if a correction is needed
+ if(io_blue_waterfall == BW_INCORRECT)
+ {
+ io_blue_waterfall = BW_MAX;
+ // Does a check to make sure the value doesn't underflow
+ io_gate_delay = ((io_gate_delay == 0) ? 0 : (io_gate_delay - 1));
+ }
+}
+
+///
+/// @brief Gets the blue waterfall and gate delay values for a given DP quad
+/// @tparam uint64_t QUAD - which quad to access
+/// @param[in,out] io_waterfall_reg - waterfall register data
+/// @param[in,out] io_gate_reg - gate delay register information
+///
+template< uint64_t QUAD>
+void update_blue_waterfall_gate_delay_for_quad(fapi2::buffer<uint64_t>& io_waterfall_reg,
+ fapi2::buffer<uint64_t>& io_gate_reg)
+{
+ constexpr uint64_t NUM_QUAD = 4;
+ // Valid quad values are from 0-3, exit if the requested value is greater
+ static_assert(QUAD < NUM_QUAD, "Inserted quad value is greater than or equal to 4");
+
+ // Gets the data for this Quad
+ auto l_blue_waterfall = mss::dp16::get_blue_waterfall<QUAD>(io_waterfall_reg);
+ auto l_gate_delay = mss::dp16::get_gate_delay<QUAD>(io_gate_reg);
+
+ // Updates the waterfall and gate delay
+ update_blue_waterfall_gate_delay(l_blue_waterfall, l_gate_delay);
+
+ // Sets the data back into the register
+ mss::dp16::set_blue_waterfall<QUAD>(io_waterfall_reg, l_blue_waterfall);
+ mss::dp16::set_gate_delay<QUAD>(io_gate_reg, l_gate_delay);
+}
+
+///
+/// @brief Fixes blue waterfall values in a port
+/// @param[in] i_target - the target to operate on
+/// @param[in] i_always_run - ignores the attribute and always run - default = false - this is used in lab code to force the workaround to be run
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
+///
+fapi2::ReturnCode fix_blue_waterfall_gate( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const bool i_always_run = false );
+
+///
+/// @brief Modifies HW calibration results based upon workarounds
+/// @param[in] i_target - the target to operate on
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
+///
+fapi2::ReturnCode modify_calibration_results( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target );
+
namespace wr_vref
{
diff --git a/src/import/chips/p9/procedures/hwp/memory/p9_mss_draminit_training.C b/src/import/chips/p9/procedures/hwp/memory/p9_mss_draminit_training.C
index b8cdf227a..635ccc0cd 100644
--- a/src/import/chips/p9/procedures/hwp/memory/p9_mss_draminit_training.C
+++ b/src/import/chips/p9/procedures/hwp/memory/p9_mss_draminit_training.C
@@ -38,6 +38,7 @@
#include <p9_mss_draminit_training.H>
#include <lib/utils/count_dimm.H>
+#include <lib/workarounds/dp16_workarounds.H>
#include <lib/fir/unmask.H>
using fapi2::TARGET_TYPE_MCBIST;
@@ -191,6 +192,9 @@ extern "C"
// 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(i_target, l_program, p) );
+ // Modifies the training steps, based upon workarounds - adding this here so it always gets run
+ FAPI_TRY( mss::workarounds::dp16::modify_calibration_results( p ) );
+
// If we're aborting on error we can just FAPI_TRY. If we're not, we don't want to exit if there's
// an error but we want to log the error and keep on keeping on.
if ((fapi2::current_err = mss::process_initial_cal_errors(p)) != fapi2::FAPI2_RC_SUCCESS)
diff --git a/src/import/chips/p9/procedures/hwp/perv/p9_getecid.C b/src/import/chips/p9/procedures/hwp/perv/p9_getecid.C
index df69deb21..753d323d6 100644
--- a/src/import/chips/p9/procedures/hwp/perv/p9_getecid.C
+++ b/src/import/chips/p9/procedures/hwp/perv/p9_getecid.C
@@ -123,6 +123,7 @@ static fapi2::ReturnCode setup_memory_work_around_attributes(
// All these attributes have 1 as their 'YES' enum value
uint8_t l_value = 1;
FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_DO_MSS_TRAINING_BAD_BITS, i_target, l_value) );
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_DO_BLUE_WATERFALL_ADJUST, i_target, l_value) );
}
return fapi2::FAPI2_RC_SUCCESS;
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 163fa1c2d..c1a351a8a 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
@@ -2061,6 +2061,24 @@
</chipEcFeature>
</attribute>
+ <attribute>
+ <id>ATTR_CHIP_EC_FEATURE_MSS_BLUE_WATERFALL_ADJUST</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
+ </description>
+ <chipEcFeature>
+ <chip>
+ <name>ENUM_ATTR_NAME_NIMBUS</name>
+ <ec>
+ <value>0x20</value>
+ <test>LESS_THAN</test>
+ </ec>
+ </chip>
+ </chipEcFeature>
+ </attribute>
+
<!-- ******************************************************************** -->
<!-- End Memory Section -->
<!-- ******************************************************************** -->
diff --git a/src/import/chips/p9/procedures/xml/attribute_info/memory_workarounds_attributes.xml b/src/import/chips/p9/procedures/xml/attribute_info/memory_workarounds_attributes.xml
index 1d40c3ced..02b9915c5 100644
--- a/src/import/chips/p9/procedures/xml/attribute_info/memory_workarounds_attributes.xml
+++ b/src/import/chips/p9/procedures/xml/attribute_info/memory_workarounds_attributes.xml
@@ -69,4 +69,18 @@
<writeable/>
</attribute>
+ <attribute>
+ <id>ATTR_DO_BLUE_WATERFALL_ADJUST</id>
+ <targetType>TARGET_TYPE_PROC_CHIP</targetType>
+ <description>
+ For Nimbus pre DD1.** we want to adjust the blue waterfall values
+ and their associated gate delays if the blue waterfalls are 0.
+ Post DD1.** will have a hardware enabled fix for this.
+ </description>
+ <initToZero></initToZero>
+ <valueType>uint8</valueType>
+ <enum>NO = 0, YES = 1</enum>
+ <writeable/>
+ </attribute>
+
</attributes>
OpenPOWER on IntegriCloud