summaryrefslogtreecommitdiffstats
path: root/src/import
diff options
context:
space:
mode:
authorBrian Silver <bsilver@us.ibm.com>2016-08-22 08:44:42 -0500
committerDaniel M. Crowell <dcrowell@us.ibm.com>2016-08-24 23:45:46 -0400
commite6059f6594051106f13391d2967ef7f37aa4ec29 (patch)
treec4c66edfb8803d7598bfe3b671fb588114131156 /src/import
parent04b10dfde23c8c88e8036ac7f70bab8c308000fd (diff)
downloadtalos-hostboot-e6059f6594051106f13391d2967ef7f37aa4ec29.tar.gz
talos-hostboot-e6059f6594051106f13391d2967ef7f37aa4ec29.zip
Add f/w implementation of PHY duty cycle distortion cal
Change-Id: Ie15b5e674ed4285e8d76ca1583b9b1feaf120c3d Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/28605 Reviewed-by: ANDRE A. MARIN <aamarin@us.ibm.com> Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com> Tested-by: Hostboot CI <hostboot-ci+hostboot@us.ibm.com> Reviewed-by: JACOB L. HARVEY <jlharvey@us.ibm.com> Reviewed-by: Jennifer A. Stofer <stofer@us.ibm.com> Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/28606 Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com> Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src/import')
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/phy/adr32s.C203
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/phy/adr32s.H106
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/p9_mss_ddr_phy_reset.C7
-rw-r--r--src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_ddr_phy_reset.xml18
4 files changed, 332 insertions, 2 deletions
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/phy/adr32s.C b/src/import/chips/p9/procedures/hwp/memory/lib/phy/adr32s.C
index 672c9d371..c43c981e4 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/phy/adr32s.C
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/phy/adr32s.C
@@ -35,6 +35,11 @@
#include <fapi2.H>
#include <lib/phy/adr32s.H>
+#include <lib/utils/find.H>
+
+using fapi2::TARGET_TYPE_MCA;
+using fapi2::TARGET_TYPE_SYSTEM;
+using fapi2::FAPI2_RC_SUCCESS;
namespace mss
{
@@ -53,5 +58,203 @@ const std::vector<uint64_t> adr32sTraits<fapi2::TARGET_TYPE_MCA>::OUTPUT_DRIVER_
MCA_DDRPHY_ADR_OUTPUT_DRIVER_FORCE_VALUE0_P0_ADR32S1
};
+// Definition of the ADR32S duty cycle distortion registers
+const std::vector<uint64_t> adr32sTraits<fapi2::TARGET_TYPE_MCA>::DUTY_CYCLE_DISTORTION_REG =
+{
+ MCA_DDRPHY_ADR_DCD_CONTROL_P0_ADR32S0,
+ MCA_DDRPHY_ADR_DCD_CONTROL_P0_ADR32S1
+};
+
+namespace adr32s
+{
+
+///
+/// @brief Helper to iterate over ADR32S 'sides' when performing DCD cal
+/// @param[in] i_target the MCA to iterate for
+/// @param[in] i_reg the register (ADR0 or ADR1's register)
+/// @param[in] i_seed the seed value for the adjuster
+/// @param[in] i_side bool; true if this is side a, false for side b
+/// @param[out] o_value the value of the adjuster when the compare bit changes state
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+fapi2::ReturnCode dcd_cal_helper( const fapi2::Target<TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_reg,
+ const uint64_t i_seed,
+ const bool i_side,
+ uint64_t& o_value )
+{
+ typedef adr32sTraits<TARGET_TYPE_MCA> TT;
+
+ constexpr uint64_t l_dcd_adjust_overflow = 0b1111111;
+ constexpr uint64_t l_dcd_adjust_underflow = 0b0000000;
+
+ // If compare out is 0, we tick up ...
+ // Signed value which helps us increment or decrement the adjustment
+ int64_t l_tick = 1;
+ // ... and we expect a transition to 1
+ bool l_expected = 1;
+ // ... and we don't expect to overflow
+ uint64_t l_overrun = l_dcd_adjust_overflow;
+
+ fapi2::buffer<uint64_t> l_read;
+ uint64_t l_current_adjust = i_seed;
+ size_t l_iter = 0;
+
+ // More or less mirror's Bialas's logic for DD2 so we can kind of try out the algorithm on DD1.
+
+ FAPI_INF("enter dcd_cal_helper %s 0x%016lx seed: 0x%016lx side: %d",
+ mss::c_str(i_target), i_reg, i_seed, i_side );
+
+ // Prime the system with the starting values. We don't need to read/modify/write here as we're resetting
+ // the world and saving a scom here is likely benificial. Clear the compare out bit as writing it set
+ // will cause the PHY to throw a parity error
+ l_read.insertFromRight<TT::DCD_CONTROL_DLL_ADJUST, TT::DCD_CONTROL_DLL_ADJUST_LEN>(l_current_adjust);
+ l_read.writeBit<TT::DCD_CONTROL_DLL_ITER_A>(i_side);
+ l_read.clearBit<TT::DCD_CONTROL_DLL_COMPARE_OUT>();
+ FAPI_TRY( mss::putScom(i_target, i_reg, l_read) );
+
+ // Algorithm waits 128ck (~100ns) between steps. However, scom takes so long (and rippling up thru
+ // the platforms takes time too) that there's no need to actually delay - plenty of time has elapsed.
+
+ // Read. Note the register is volatile in that l_read which we just wrote isn't what we'll read
+ // as the distortion logic will take the seeded adjustment value and give us information on the next
+ // read (so don't get cute and remove this getScom.)
+ FAPI_TRY( mss::getScom(i_target, i_reg, l_read) );
+
+ // Based on the 'direction' we're going, we have some values to setup. We setup the bit == 0 case
+ // when we initialized these variables above.
+ if (l_read.getBit<TT::DCD_CONTROL_DLL_COMPARE_OUT>() != 0)
+ {
+ // If compare out is 1, we tick down ...
+ l_tick = -1;
+
+ // ... and we expect a transition to 0
+ l_expected = 0;
+
+ // ... and we don't expect to underflow
+ l_overrun = l_dcd_adjust_underflow;
+ }
+
+ do
+ {
+ l_iter += 1;
+ bool l_current_compare = l_read.getBit<TT::DCD_CONTROL_DLL_COMPARE_OUT>();
+
+ FAPI_INF("dcd_cal_helper: iter %d tick: %d expected: %d overrun: 0x%x out: %d adj: 0x%x",
+ l_iter, l_tick, l_expected, l_overrun, l_current_compare, l_current_adjust);
+
+ if (l_current_compare == l_expected)
+ {
+ break;
+ }
+
+ // If we're here we're not done, so just adjust and try again. Clear the compare out bit, it must
+ // always be 0 or the PHY will parity error
+ l_read.insertFromRight<TT::DCD_CONTROL_DLL_ADJUST, TT::DCD_CONTROL_DLL_ADJUST_LEN>(l_current_adjust + l_tick);
+ l_read.clearBit<TT::DCD_CONTROL_DLL_COMPARE_OUT>();
+ FAPI_TRY( mss::putScom(i_target, i_reg, l_read) );
+
+ // Wait 128ck (~100ns) ...
+
+ FAPI_TRY( mss::getScom(i_target, i_reg, l_read) );
+
+ l_read.extractToRight<TT::DCD_CONTROL_DLL_ADJUST, TT::DCD_CONTROL_DLL_ADJUST_LEN>(l_current_adjust);
+
+ }
+ while (l_current_adjust != l_overrun);
+
+ FAPI_ASSERT( l_current_adjust != l_overrun,
+ fapi2::MSS_DUTY_CLOCK_DISTORTION_CAL_FAILED()
+ .set_CURRENT_ADJUST(l_current_adjust)
+ .set_SIDE(i_side)
+ .set_REGISTER(i_reg)
+ .set_REGISTER_VALUE(l_read),
+ "Failed ADR DCD for %s 0x%016lx", mss::c_str(i_target), i_reg );
+
+ // If we're here, we were done and there were no errors. So we can return back the current adjust value
+ // as the output/result of our operation
+ o_value = l_current_adjust;
+ FAPI_INF("side: %d final adjust value: 0x%x (0x%x)", i_side, o_value, l_current_adjust);
+
+ return FAPI2_RC_SUCCESS;
+
+fapi_try_exit:
+ return fapi2::current_err;
}
+
+///
+/// @brief Perform ADR DCD calibration - Nimbus Only
+/// @param[in] i_target the MCBIST (controler) to perform calibration on
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+fapi2::ReturnCode duty_cycle_distortion_calibration( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target )
+{
+ typedef adr32sTraits<TARGET_TYPE_MCA> TT;
+
+ const auto l_mca = mss::find_targets<TARGET_TYPE_MCA>(i_target);
+ fapi2::buffer<uint64_t> l_read;
+ uint8_t is_sim = 0;
+
+ FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_IS_SIMULATION, fapi2::Target<TARGET_TYPE_SYSTEM>(), is_sim) );
+
+ // Nothing works here in cycle sim ...
+ if (is_sim)
+ {
+ return FAPI2_RC_SUCCESS;
+ }
+
+ if (l_mca.size() == 0)
+ {
+ FAPI_INF("No MCA, skipping duty cycle distortion calibration");
+ return FAPI2_RC_SUCCESS;
+ }
+
+ // Do a quick check to make sure this chip doesn't have the DCD logic built in (e.g., DD1 Nimbus)
+ // TODO RTC:159687 For DD2 all we need to do is kick off the h/w cal and wait. We can check any ADR_DCD
+ // register, they all should reflect the inclusion of the DCD logic.
+
+ FAPI_TRY( mss::getScom(l_mca[0], TT::DUTY_CYCLE_DISTORTION_REG[0], l_read) );
+
+ if (l_read.getBit<TT::DCD_CONTROL_DLL_CORRECT_EN>() == 1)
+ {
+ FAPI_ERR("seeing ADR DCD algorithm is in the logic but we didn't code it?");
+ fapi2::Assert(false);
+ }
+
+ // We must calibrate each of our ports. Each has 2 ADR units and each unit needs it's A-side and B-side calibrated.
+ for (const auto& p : mss::find_targets<TARGET_TYPE_MCA>(i_target))
+ {
+ uint64_t l_seed = TT::DCD_ADJUST_DEFAULT;
+
+ for (const auto& r : TT::DUTY_CYCLE_DISTORTION_REG)
+ {
+ uint64_t l_a_side_value = 0;
+ uint64_t l_b_side_value = 0;
+
+ FAPI_TRY( dcd_cal_helper(p, r, l_seed, true, l_a_side_value) );
+
+ // We want to seed the other side (and each subsequent port) with the
+ // value found in the pervious iteration as that will likely reduce the number
+ // of iterations to find the transition. We back up one so that if we're on
+ // a transition, we don't 'bounce' from a 1 to a 0. This will give us a good
+ // transition if the a-side value is really to be the b-side value too.
+ FAPI_TRY( dcd_cal_helper(p, r, l_a_side_value - 1, false, l_b_side_value) );
+
+ // The final value is the average of the a-side and b-side values.
+ l_seed = (l_a_side_value + l_b_side_value) / 2;
+
+ FAPI_INF("average for both sides 0x%02x", l_seed);
+
+ // Note this writes all the other values to 0's which is OK for DD1
+ FAPI_TRY( mss::putScom(p, r, l_seed) );
+ }
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+} // close namespace adrs32
+
+} // close namespace mss
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/phy/adr32s.H b/src/import/chips/p9/procedures/hwp/memory/lib/phy/adr32s.H
index 360c508f1..ae650302f 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/phy/adr32s.H
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/phy/adr32s.H
@@ -81,6 +81,11 @@ class adr32sTraits<fapi2::TARGET_TYPE_MCA>
// MCA ADR32S control registers all come in pairs.
static const std::vector<uint64_t> DLL_CNFG_REG;
static const std::vector<uint64_t> OUTPUT_DRIVER_REG;
+ static const std::vector<uint64_t> DUTY_CYCLE_DISTORTION_REG;
+
+ // This fellow is needed for the reset_dcd template, so he's more like a real trait.
+ // Default starting place for duty cycle distortion algorithm
+ static constexpr uint64_t DCD_ADJUST_DEFAULT = 0b1000000;
enum
{
@@ -103,6 +108,11 @@ class adr32sTraits<fapi2::TARGET_TYPE_MCA>
FLUSH = MCA_DDRPHY_ADR_OUTPUT_FORCE_ATEST_CNTL_P0_ADR32S0_ADR0_FLUSH,
INIT_IO = MCA_DDRPHY_ADR_OUTPUT_FORCE_ATEST_CNTL_P0_ADR32S0_ADR0_INIT_IO,
+ DCD_CONTROL_DLL_ADJUST = MCA_DDRPHY_ADR_DCD_CONTROL_P0_ADR32S0_ADR0_DLL_ADJUST,
+ DCD_CONTROL_DLL_ADJUST_LEN = MCA_DDRPHY_ADR_DCD_CONTROL_P0_ADR32S0_ADR0_DLL_ADJUST_LEN,
+ DCD_CONTROL_DLL_CORRECT_EN = MCA_DDRPHY_ADR_DCD_CONTROL_P0_ADR32S0_ADR0_DLL_CORRECT_EN,
+ DCD_CONTROL_DLL_ITER_A = MCA_DDRPHY_ADR_DCD_CONTROL_P0_ADR32S0_ADR0_DLL_ITER_A,
+ DCD_CONTROL_DLL_COMPARE_OUT = MCA_DDRPHY_ADR_DCD_CONTROL_P0_ADR32S0_ADR0_DLL_COMPARE_OUT,
};
};
@@ -153,6 +163,80 @@ fapi_try_exit:
//
///
+/// @brief Read DCD_CNTL
+/// @tparam I ADR32S instance e.g., 0 or 1 for a 64 bit implementation of the PHY
+/// @tparam T fapi2 Target Type - derived
+/// @tparam TT traits type defaults to adr32sTraits<T>
+/// @param[in] i_target the fapi2 target of the port
+/// @param[out] o_data the value of the register
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
+///
+template< uint64_t I, fapi2::TargetType T, typename TT = adr32sTraits<T> >
+inline fapi2::ReturnCode read_dcd_cntl( const fapi2::Target<T>& i_target, fapi2::buffer<uint64_t>& o_data )
+{
+ static_assert( I < TT::ADR32S_COUNT, "adr32s instance out of range");
+ FAPI_TRY( mss::getScom(i_target, TT::DUTY_CYCLE_DISTORTION_REG[I], o_data) );
+ FAPI_INF("dcd_cntl adrs32%d: 0x%016lx", I, o_data);
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Write DCD_CNTL
+/// @tparam I ADR32S instance e.g., 0 or 1 for a 64 bit implementation of the PHY
+/// @tparam T fapi2 Target Type - derived
+/// @tparam TT traits type defaults to adr32sTraits<T>
+/// @param[in] i_target the fapi2 target of the port
+/// @param[in] i_data the value of the register
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
+///
+template< uint64_t I, fapi2::TargetType T, typename TT = adr32sTraits<T> >
+inline fapi2::ReturnCode write_dcd_cntl( const fapi2::Target<T>& i_target, const fapi2::buffer<uint64_t>& i_data )
+{
+ static_assert( I < TT::ADR32S_COUNT, "adr32s instance out of range");
+
+ // Per datasheet, bit 15 must always be written 0 or we'll get a parity error
+ if (i_data.getBit<TT::DCD_CONTROL_DLL_COMPARE_OUT>() != 0)
+ {
+ FAPI_ERR("DCD DLL Compare out is set - will cause a parity error 0x%016lx (0x%016lx)",
+ TT::DUTY_CYCLE_DISTORTION_REG[I], i_data);
+ fapi2::Assert(false);
+ }
+
+ FAPI_INF("dcd_cntl adr32s%d: 0x%016lx", I, i_data);
+ FAPI_TRY( mss::putScom(i_target, TT::DUTY_CYCLE_DISTORTION_REG[I], i_data) );
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Reset DCD_CNTL
+/// @tparam T fapi2 Target Type - derived
+/// @tparam TT traits type defaults to adr32sTraits<T>
+/// @param[in] i_target the fapi2 target of the port
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
+///
+template< fapi2::TargetType T, typename TT = adr32sTraits<T> >
+inline fapi2::ReturnCode reset_dcd_cntl( const fapi2::Target<T>& i_target )
+{
+ fapi2::buffer<uint64_t> l_data;
+
+ // All we need to write is the adjustment default, all the other bits are 0 (and
+ // the adujtment default accounts for this)
+ l_data.insertFromRight<TT::DCD_CONTROL_DLL_ADJUST, TT::DCD_CONTROL_DLL_ADJUST_LEN>(TT::DCD_ADJUST_DEFAULT);
+
+ for (const auto r : TT::DUTY_CYCLE_DISTORTION_REG)
+ {
+ FAPI_INF("reset dcd_cntl 0x%016lx: 0x%016lx", r, l_data);
+ FAPI_TRY( mss::putScom(i_target, r, l_data) );
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+
+///
/// @brief Set the DLL cal reset (begins DLL cal operations)
/// @tparam T fapi2 Target Type - defaults to TARGET_TYPE_MCA
/// @tparam TT traits type defaults to adr32sTraits<T>
@@ -235,6 +319,28 @@ inline void set_init_io( fapi2::buffer<uint64_t>& o_data, const states i_state )
o_data.writeBit<TT::INIT_IO>(i_state);
}
+///
+/// @brief Helper to iterate over ADR32S 'sides' when performing DCD cal
+/// @param[in] i_target the MCA to iterate for
+/// @param[in] i_reg the register (ADR0 or ADR1's register)
+/// @param[in] i_seed the seed value for the adjuster
+/// @param[in] i_side bool; true if this is side a, false for side b
+/// @param[out] o_value the value of the adjuster when the compare bit changes state
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+fapi2::ReturnCode dcd_cal_helper( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_reg,
+ const uint64_t i_seed,
+ const bool i_side,
+ uint64_t& o_value );
+
+///
+/// @brief Perform ADR DCD calibration - Nimbus Only
+/// @param[in] i_target the MCBIST (controler) to perform calibration on
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+fapi2::ReturnCode duty_cycle_distortion_calibration( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target );
+
} // close namespace adr
} // close namespace mss
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 d54ac8084..e6b9fbeda 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
@@ -41,6 +41,7 @@
#include <p9_mss_ddr_phy_reset.H>
#include <lib/utils/count_dimm.H>
+#include <lib/phy/adr32s.H>
using fapi2::TARGET_TYPE_MCBIST;
@@ -64,13 +65,15 @@ extern "C"
return fapi2::FAPI2_RC_SUCCESS;
}
- // Initialize via scoms. Could be put in to p9_mss_scominit.C if that ever exists BRS.
+ // Initialize via scoms. Could be put in to p9_mss_scominit.C
FAPI_TRY( mss::phy_scominit(i_target) );
FAPI_TRY(mss::change_force_mclk_low(i_target, mss::HIGH),
"force_mclk_low (set high) Failed rc = 0x%08X", uint64_t(fapi2::current_err) );
- //
+ // New for Nimbus - perform duty cycle clock distortion calibration
+ FAPI_TRY( mss::adr32s::duty_cycle_distortion_calibration(i_target) );
+
// 1. Drive all control signals to the PHY to their inactive state, idle state, or inactive value.
FAPI_TRY( mss::dp16::reset_sysclk(i_target) );
diff --git a/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_ddr_phy_reset.xml b/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_ddr_phy_reset.xml
index e62924b6a..3a2489c60 100644
--- a/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_ddr_phy_reset.xml
+++ b/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_ddr_phy_reset.xml
@@ -465,4 +465,22 @@
</deconfigure>
</hwpError>
+<hwpError>
+ <rc>RC_MSS_DUTY_CLOCK_DISTORTION_CAL_FAILED</rc>
+ <description>
+ The ADR duty clock distortion calibration algorithm failed
+ </description>
+ <ffdc>CURRENT_ADJUST</ffdc>
+ <ffdc>SIDE</ffdc>
+ <ffdc>REGISTER</ffdc>
+ <ffdc>REGISTER_VALUE</ffdc>
+ <callout>
+ <target>TARGET</target>
+ <priority>HIGH</priority>
+ </callout>
+ <deconfigure>
+ <target>TARGET</target>
+ </deconfigure>
+</hwpError>
+
</hwpErrors>
OpenPOWER on IntegriCloud