summaryrefslogtreecommitdiffstats
path: root/src/import/chips/p9/procedures/hwp/memory/lib/termination/slew_cal.C
diff options
context:
space:
mode:
Diffstat (limited to 'src/import/chips/p9/procedures/hwp/memory/lib/termination/slew_cal.C')
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/termination/slew_cal.C497
1 files changed, 497 insertions, 0 deletions
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/termination/slew_cal.C b/src/import/chips/p9/procedures/hwp/memory/lib/termination/slew_cal.C
new file mode 100644
index 000000000..906e8ced6
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/termination/slew_cal.C
@@ -0,0 +1,497 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/termination/slew_cal.C $ */
+/* */
+/* IBM CONFIDENTIAL */
+/* */
+/* EKB Project */
+/* */
+/* COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* The source code for this program is not published or otherwise */
+/* divested of its trade secrets, irrespective of what has been */
+/* deposited with the U.S. Copyright Office. */
+/* */
+/* IBM_PROLOG_END_TAG */
+///
+/// @file slew_cal.C
+/// @brief * This function runs the slew calibration engine to configure MSS_SLEW_DATA/ADR
+/// attributes and calls config_slew_rate to set the slew rate in the registers.
+///
+// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
+// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
+// *HWP Team: Memory
+// *HWP Level: 2
+// *HWP Consumed by: FSP:HB
+
+#include <fapi2.H>
+
+#include "../mss.H"
+#include "slew_cal.H"
+
+using fapi2::TARGET_TYPE_MCBIST;
+using fapi2::TARGET_TYPE_MCA;
+using fapi2::TARGET_TYPE_MCS;
+using fapi2::TARGET_TYPE_SYSTEM;
+
+using fapi2::TARGET_STATE_FUNCTIONAL;
+
+using fapi2::FAPI2_RC_SUCCESS;
+
+// slew calibration control register
+
+static const uint64_t slew_cal_cntl[] =
+{
+ MCA_0_DDRPHY_ADR_SLEW_CAL_CNTL_P0_ADR32S0,
+ MCA_1_DDRPHY_ADR_SLEW_CAL_CNTL_P1_ADR32S0,
+ MCA_2_DDRPHY_ADR_SLEW_CAL_CNTL_P2_ADR32S0,
+ MCA_3_DDRPHY_ADR_SLEW_CAL_CNTL_P3_ADR32S0,
+};
+// slew calibration status registers
+static const uint64_t ENABLE_BIT = 48;
+static const uint64_t slew_cal_stat[] =
+{
+ MCA_0_DDRPHY_ADR_SYSCLK_CNTL_PR_P0_ADR32S0,
+ MCA_1_DDRPHY_ADR_SYSCLK_CNTL_PR_P1_ADR32S0,
+ MCA_2_DDRPHY_ADR_SYSCLK_CNTL_PR_P2_ADR32S0,
+ MCA_3_DDRPHY_ADR_SYSCLK_CNTL_PR_P3_ADR32S0,
+};
+
+// big bang lock bit register
+static const uint64_t bb_lock_stat[] =
+{
+ MCA_0_DDRPHY_ADR_SYSCLK_PR_VALUE_RO_P0_ADR32S0,
+ MCA_1_DDRPHY_ADR_SYSCLK_PR_VALUE_RO_P1_ADR32S0,
+ MCA_2_DDRPHY_ADR_SYSCLK_PR_VALUE_RO_P2_ADR32S0,
+ MCA_3_DDRPHY_ADR_SYSCLK_PR_VALUE_RO_P3_ADR32S0,
+};
+
+namespace mss
+{
+
+///
+/// @brief perform the slew calibration, store the result.
+/// @tparam T, the type of the slew table
+/// @param[in] MCA (port) target
+/// @param[in] a vector of the steps which came before me
+/// @param[in] the slew table to be operated on
+/// @param[out] the array holding the results
+/// @return FAPI2_RC_SUCCESS, iff ok
+///
+template<typename T>
+fapi2::ReturnCode perform_slew_cal(
+ const fapi2::Target<TARGET_TYPE_MCA>& i_target,
+ std::vector<tags_t>& i_where_am_i, T& l_table,
+ uint8_t (&o_cal_slew)[2][PORTS_PER_MCS][MAX_NUM_IMP][MAX_NUM_CAL_SLEW_RATES])
+{
+ i_where_am_i.push_back(l_table.first);
+
+ for (auto e : l_table.second)
+ {
+ FAPI_TRY( perform_slew_cal(i_target, i_where_am_i, e, o_cal_slew) );
+ }
+
+ i_where_am_i.pop_back();
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief perform the slew calibration, store the result.
+/// @param[in] MCA (port) target
+/// @param[in] a vector of the steps which came before me
+/// @param[in] a slew_table_t
+/// @param[out] the array holding the results
+/// @bote Prunes recursion based on frequency.
+/// @return FAPI2_RC_SUCCESS, iff ok
+///
+template<>
+fapi2::ReturnCode perform_slew_cal(
+ const fapi2::Target<TARGET_TYPE_MCA>& i_target,
+ std::vector<tags_t>& i_where_am_i,
+ std::pair<tags_t, slew_per_imp_t>& l_table,
+ uint8_t (&o_cal_slew)[2][PORTS_PER_MCS][MAX_NUM_IMP][MAX_NUM_CAL_SLEW_RATES])
+{
+ uint64_t ddr_freq = 0;
+ const char* l_type = i_where_am_i[0] == TAG_ADR ? "adr" : "data";
+
+ // Check our speed. If this isn't our speed, we can get out of here.
+ FAPI_TRY( mss::freq(i_target.getParent<TARGET_TYPE_MCBIST>(), ddr_freq),
+ "Unable to get ddr freq for %s", mss::c_str(i_target) );
+
+ if (ddr_freq != l_table.first)
+ {
+ FAPI_DBG("Skipping slew %s for %s: invalid speed %d(%d)",
+ l_type, mss::c_str(i_target), l_table.first, ddr_freq);
+ return FAPI2_RC_SUCCESS;
+ }
+
+ i_where_am_i.push_back(l_table.first);
+
+ for (auto e : l_table.second)
+ {
+ FAPI_TRY( perform_slew_cal(i_target, i_where_am_i, e, o_cal_slew) );
+ }
+
+ i_where_am_i.pop_back();
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief perform the slew calibration, store the result.
+/// @param[in] MCA (port) target
+/// @param[in] a vector of the steps which came before me
+/// @param[in] the slew rate to be calculated
+/// @param[out] the array holding the results
+/// @return FAPI2_RC_SUCCESS, iff ok
+///
+template<>
+fapi2::ReturnCode perform_slew_cal<slew_rate_t>(
+ const fapi2::Target<TARGET_TYPE_MCA>& i_target,
+ std::vector<tags_t>& i_where_am_i,
+ slew_rate_t& l_slew_rate,
+ uint8_t (&o_cal_slew)[2][PORTS_PER_MCS][MAX_NUM_IMP][MAX_NUM_CAL_SLEW_RATES])
+{
+ i_where_am_i.push_back(l_slew_rate.first);
+
+ fapi2::buffer<uint64_t> l_data;
+
+ // Some short-hand for this calibration
+ const char* l_type = i_where_am_i[0] == TAG_ADR ? "adr" : "data";
+ const uint64_t& l_speed = i_where_am_i[1];
+ const uint64_t& l_ohm = i_where_am_i[2];
+ const uint64_t& l_vns = i_where_am_i[3];
+
+ uint64_t cal_status = 0;
+ fapi2::buffer<uint64_t> status_register;
+ uint64_t calculated_slew = 0;
+
+ FAPI_INF("Processing slew %s, %dmhz %dohm %dV/ns: %d", l_type, l_speed, l_ohm, l_vns, l_slew_rate.second);
+
+#ifdef NOT_TESTING_WITH_SUET
+ // Get out of here if we're in the simulator. Calibration fails in sim since bb_lock not possible in cycle
+ // simulator, putting initial to be cal'd value in output table
+ uint8_t is_sim = 0;
+ FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_IS_SIMULATION, fapi2::Target<TARGET_TYPE_SYSTEM>(), is_sim) );
+
+ if (is_sim)
+ {
+ FAPI_INF("In SIM setting input slew value in array");
+ calculated_slew = l_slew_rate.second;
+ goto perform_slew_cal_exit;
+ }
+
+#endif
+
+ // This doesn't look right. There are 5 bits, but some of our values (134) are 8 bits. So, the
+ // left-most bits are truncated. Note this is the same in P8, it seems - this needs to be looked at BRS
+ l_data.insertFromRight<MCA_DDRPHY_ADR_SLEW_CAL_CNTL_P0_ADR32S0_ADR0_TARGET_PR_OFFSET,
+ MCA_DDRPHY_ADR_SLEW_CAL_CNTL_P0_ADR32S0_ADR0_TARGET_PR_OFFSET_LEN>(l_slew_rate.second);
+ l_data.setBit<MCA_DDRPHY_ADR_SLEW_CAL_CNTL_P0_ADR32S0_ADR0_START>();
+
+ FAPI_TRY( fapi2::putScom(i_target, MCA_DDRPHY_ADR_SLEW_CAL_CNTL_P0_ADR32S0, l_data) );
+
+ mss::poll( i_target, MCA_DDRPHY_ADR_SYSCLK_PR_VALUE_RO_P0_ADR32S0, mss::poll_parameters(DELAY_100NS),
+ [&](const size_t poll_remaining, const fapi2::buffer<uint64_t>& stat_reg) -> bool
+ {
+ // Save off our claibration status
+ status_register = stat_reg;
+ stat_reg.extractToRight<MCA_DDRPHY_ADR_SYSCLK_PR_VALUE_RO_P0_ADR32S0_ADR0_SLEW_DONE_STATUS,
+ MCA_DDRPHY_ADR_SYSCLK_PR_VALUE_RO_P0_ADR32S0_ADR0_SLEW_DONE_STATUS_LEN>(cal_status);
+ FAPI_DBG("slew calibration status 0x%llx, remaining: %d", cal_status, poll_remaining);
+ return cal_status != SLEW_CAL_NOT_DONE;
+ });
+
+ // This will kick us out if there's no further processing we can do.
+ FAPI_TRY( slew_cal_status(i_target, i_where_am_i, l_slew_rate.second, cal_status, status_register) );
+
+ // Get our calculated slew rate and process.
+ FAPI_TRY( fapi2::getScom(i_target, MCA_DDRPHY_ADR_SLEW_CAL_CNTL_P0_ADR32S0, l_data) );
+ l_data.extractToRight<MCA_DDRPHY_ADR_SLEW_CAL_CNTL_P0_ADR32S0_ADR0_TARGET_PR_OFFSET,
+ MCA_DDRPHY_ADR_SLEW_CAL_CNTL_P0_ADR32S0_ADR0_TARGET_PR_OFFSET_LEN>(calculated_slew);
+
+#ifdef NOT_TESTING_WITH_SUET
+perform_slew_cal_exit:
+#endif
+ FAPI_DBG("MSS_SLEW_RATE %s port %d %dohm slew 0x%lx(0x%lx)",
+ l_type, mss::pos(i_target), l_ohm, calculated_slew, uint64_t(status_register));
+
+ o_cal_slew[i_where_am_i[0]] // adr/data
+ [mss::index(i_target)] // port
+ [mss::index(i_where_am_i[0], i_where_am_i[2])] // imp
+ [mss::index(i_where_am_i[0], i_where_am_i[3])] = calculated_slew;
+
+ i_where_am_i.pop_back();
+
+ return FAPI2_RC_SUCCESS;
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+
+///
+/// @brief Run the slew calibration engine
+/// @param[in] i_target, the MCBIST
+/// @return FAPI2_RC_SUCCESS iff OK
+///
+fapi2::ReturnCode slew_cal(const fapi2::Target<TARGET_TYPE_MCBIST>& i_target)
+{
+ // freq index into lookup table. Fixed at 3 right now as we don't support
+ // dimm slower than 1866 - without more work below.
+ static const uint8_t freq_idx = 3;
+
+ // current ddr freq
+ uint64_t ddr_freq = 0;
+
+ // ddr type index into lookup table
+ // We only have one entry in the table right now, so this is fixed.
+ static const uint8_t ddr_idx = 0;
+
+ // ATTR_EFF_DRAM_GEN{0=invalid, 1=ddr3, 2=ddr4}
+ // p9n only supprts ddr4 right now. So, fixed
+ static const uint8_t ddr_type = 2;
+
+ fapi2::buffer<uint64_t> ctl_reg;
+ fapi2::buffer<uint64_t> stat_reg;
+
+ // DD level 1.0-1.1, Version 1.0
+ // [ddr3/4][dq/adr][speed][impedance][slew_rate]
+ // note: Assumes standard voltage for DDR3(1.35V), DDR4(1.2V),
+ // little endian, if >=128, lab only debug.
+ //
+ // ddr_type(1), ddr4=0
+ // data/adr(2)data(dq/dqs)=0, adr(cmd/cntl)=1
+ // speed(4)1066=0, 1333=1, 1600=2, 1866=3
+ // imped(4)24ohms=0, 30ohms=1, 34ohms=2, 40ohms=3 for DQ/DQS
+ // imped(4)15ohms=0, 20ohms=1, 30ohms=2, 40ohms=3 for ADR driver
+ // slew(3)3V/ns=0, 4V/ns=1, 5V/ns=2, 6V/ns=3
+
+ // Too many in here for real-world. But this allows us to test out the
+ // logic to make sure we're in good shape as we add to this table. We
+ // can redice this table before flight BRS.
+ std::vector< std::pair< tags_t, slew_table_t> > slew_table =
+ {
+ {
+ TAG_ADR, {
+ {
+ TAG_1066MHZ,
+ {
+ { TAG_15OHM, {{TAG_3VNS, 142}, {TAG_4VNS, 139}, {TAG_5VNS, 136}, {TAG_6VNS, 134}} },
+ { TAG_20OHM, {{TAG_3VNS, 140}, {TAG_4VNS, 136}, {TAG_5VNS, 134}, {TAG_6VNS, 133}} },
+ { TAG_30OHM, {{TAG_3VNS, 138}, {TAG_4VNS, 134}, {TAG_5VNS, 131}, {TAG_6VNS, 131}} },
+ { TAG_40OHM, {{TAG_3VNS, 133}, {TAG_4VNS, 131}, {TAG_5VNS, 131}, {TAG_6VNS, 131}} },
+ }
+ },
+
+
+ {
+ TAG_1333MHZ,
+ {
+ { TAG_15OHM, {{TAG_3VNS, 145}, {TAG_4VNS, 142}, {TAG_5VNS, 139}, {TAG_6VNS, 136}} },
+ { TAG_20OHM, {{TAG_3VNS, 143}, {TAG_4VNS, 138}, {TAG_5VNS, 135}, {TAG_6VNS, 134}} },
+ { TAG_30OHM, {{TAG_3VNS, 140}, {TAG_4VNS, 135}, {TAG_5VNS, 132}, {TAG_6VNS, 132}} },
+ { TAG_40OHM, {{TAG_3VNS, 134}, {TAG_4VNS, 132}, {TAG_5VNS, 132}, {TAG_6VNS, 132}} },
+ }
+ },
+
+
+ {
+ TAG_1600MHZ,
+ {
+ { TAG_15OHM, {{TAG_3VNS, 21}, {TAG_4VNS, 16}, {TAG_5VNS, 13}, {TAG_6VNS, 10}} },
+ { TAG_20OHM, {{TAG_3VNS, 18}, {TAG_4VNS, 12}, {TAG_5VNS, 9}, {TAG_6VNS, 135}} },
+ { TAG_30OHM, {{TAG_3VNS, 15}, {TAG_4VNS, 8}, {TAG_5VNS, 133}, {TAG_6VNS, 133}} },
+ { TAG_40OHM, {{TAG_3VNS, 7}, {TAG_4VNS, 133}, {TAG_5VNS, 133}, {TAG_6VNS, 133}} },
+ }
+ },
+
+
+ {
+ TAG_1866MHZ,
+ {
+ { TAG_15OHM, {{TAG_3VNS, 24}, {TAG_4VNS, 19}, {TAG_5VNS, 15}, {TAG_6VNS, 11}} },
+ { TAG_20OHM, {{TAG_3VNS, 21}, {TAG_4VNS, 14}, {TAG_5VNS, 10}, {TAG_6VNS, 136}} },
+ { TAG_30OHM, {{TAG_3VNS, 17}, {TAG_4VNS, 10}, {TAG_5VNS, 134}, {TAG_6VNS, 134}} },
+ { TAG_40OHM, {{TAG_3VNS, 9}, {TAG_4VNS, 134}, {TAG_5VNS, 134}, {TAG_6VNS, 134}} },
+ }
+ },
+
+ {
+ TAG_2400MHZ,
+ {
+ { TAG_15OHM, {{TAG_3VNS, 24}, {TAG_4VNS, 19}, {TAG_5VNS, 15}, {TAG_6VNS, 11}} },
+ { TAG_20OHM, {{TAG_3VNS, 21}, {TAG_4VNS, 14}, {TAG_5VNS, 10}, {TAG_6VNS, 136}} },
+ { TAG_30OHM, {{TAG_3VNS, 17}, {TAG_4VNS, 10}, {TAG_5VNS, 134}, {TAG_6VNS, 134}} },
+ { TAG_40OHM, {{TAG_3VNS, 9}, {TAG_4VNS, 134}, {TAG_5VNS, 134}, {TAG_6VNS, 134}} },
+ }
+ },
+
+ },
+ },
+
+ {
+ TAG_DATA, {
+ {
+ TAG_1066MHZ,
+ {
+ { TAG_24OHM, {{TAG_3VNS, 138}, {TAG_4VNS, 135}, {TAG_5VNS, 134}, {TAG_6VNS, 133}} },
+ { TAG_30OHM, {{TAG_3VNS, 139}, {TAG_4VNS, 136}, {TAG_5VNS, 134}, {TAG_6VNS, 132}} },
+ { TAG_34OHM, {{TAG_3VNS, 140}, {TAG_4VNS, 136}, {TAG_5VNS, 135}, {TAG_6VNS, 133}} },
+ { TAG_40OHM, {{TAG_3VNS, 140}, {TAG_4VNS, 136}, {TAG_5VNS, 132}, {TAG_6VNS, 132}} },
+ }
+ },
+
+ {
+ TAG_1333MHZ,
+ {
+ { TAG_24OHM, {{TAG_3VNS, 139}, {TAG_4VNS, 137}, {TAG_5VNS, 135}, {TAG_6VNS, 134}} },
+ { TAG_30OHM, {{TAG_3VNS, 142}, {TAG_4VNS, 138}, {TAG_5VNS, 135}, {TAG_6VNS, 133}} },
+ { TAG_34OHM, {{TAG_3VNS, 143}, {TAG_4VNS, 138}, {TAG_5VNS, 135}, {TAG_6VNS, 133}} },
+ { TAG_40OHM, {{TAG_3VNS, 143}, {TAG_4VNS, 138}, {TAG_5VNS, 133}, {TAG_6VNS, 132}} },
+ }
+ },
+
+ {
+ TAG_1600MHZ,
+ {
+ { TAG_24OHM, {{TAG_3VNS, 15}, {TAG_4VNS, 11}, {TAG_5VNS, 9}, {TAG_6VNS, 135}} },
+ { TAG_30OHM, {{TAG_3VNS, 17}, {TAG_4VNS, 11}, {TAG_5VNS, 9}, {TAG_6VNS, 135}} },
+ { TAG_34OHM, {{TAG_3VNS, 18}, {TAG_4VNS, 13}, {TAG_5VNS, 9}, {TAG_6VNS, 134}} },
+ { TAG_40OHM, {{TAG_3VNS, 18}, {TAG_4VNS, 11}, {TAG_5VNS, 6}, {TAG_6VNS, 133}} },
+ }
+ },
+
+
+ {
+ TAG_1866MHZ,
+ {
+ { TAG_24OHM, {{TAG_3VNS, 18}, {TAG_4VNS, 13}, {TAG_5VNS, 10}, {TAG_6VNS, 137}} },
+ { TAG_30OHM, {{TAG_3VNS, 19}, {TAG_4VNS, 13}, {TAG_5VNS, 10}, {TAG_6VNS, 136}} },
+ { TAG_34OHM, {{TAG_3VNS, 21}, {TAG_4VNS, 15}, {TAG_5VNS, 10}, {TAG_6VNS, 135}} },
+ { TAG_40OHM, {{TAG_3VNS, 21}, {TAG_4VNS, 13}, {TAG_5VNS, 8}, {TAG_6VNS, 134}} },
+ }
+ },
+
+ {
+ TAG_2400MHZ,
+ {
+ { TAG_24OHM, {{TAG_3VNS, 18}, {TAG_4VNS, 13}, {TAG_5VNS, 10}, {TAG_6VNS, 137}} },
+ { TAG_30OHM, {{TAG_3VNS, 19}, {TAG_4VNS, 13}, {TAG_5VNS, 10}, {TAG_6VNS, 136}} },
+ { TAG_34OHM, {{TAG_3VNS, 21}, {TAG_4VNS, 15}, {TAG_5VNS, 10}, {TAG_6VNS, 135}} },
+ { TAG_40OHM, {{TAG_3VNS, 21}, {TAG_4VNS, 13}, {TAG_5VNS, 8}, {TAG_6VNS, 134}} },
+ }
+ },
+
+ }
+ }
+ };
+
+ // Get the vector of ports. Note that we presently think there's a bit in the CCS_MODE
+ // register which needs to be twiddled during slew cal. That means our caller can't
+ // put each port's slew cal on a thread and do them in parallel. So, we interleave.
+ // If that requirement for that MCBIST register goes away, then these functions can turn
+ // in to per-port functions and the caller can decide to loop or thread as appropriate.
+ // Or maybe per MCS given the attribute work we need to do at the end ...
+ auto l_ports = i_target.getChildren<TARGET_TYPE_MCA>(TARGET_STATE_FUNCTIONAL);
+
+ // Cache the name of our target. We can't just keep the pointer from c_str as
+ // it points to thread-local space and anything we call might change the string.
+ char l_name[fapi2::MAX_ECMD_STRING_LEN];
+ strncpy(l_name, mss::c_str(i_target), fapi2::MAX_ECMD_STRING_LEN);
+
+ // p9n is ddr4 only for now, so skip checking the dimm generation (effective config
+ // should have raised a rukus if this isn't a DDR4 dimm ...
+
+ FAPI_TRY( mss::freq(i_target, ddr_freq),
+ "Unable to get ddr freq for %s", l_name );
+
+ // Note: this catches two cases. One where ddr_freq is 0 and the other
+ // where we put something slow in we don't (yet?) support
+ FAPI_ASSERT( ddr_freq > 1732,
+ fapi2::MSS_SLEW_CAL_INVALID_FREQ(),
+ "Invalid ATTR_MSS_FREQ (%d) on %s", ddr_freq, l_name );
+
+ // Get a list of functional ports.
+ // Note: If we need to use the functional vector to figure this out,
+ // change this to an mss call, and bury the attribute manipluation
+ // in that function so it can be shared and tests. BRS
+
+ //
+ // This doesn't match teh Centaur workbook algorithm, but it matches the P8 code so
+ // I'm leaving it this way. The algorithm according to the Centaur book would be to
+ // configure ADR/MCLK detect and then wait for BB_LOCK. Then, enable the cal engine and
+ // wait 2K clocks. So to "fix" you'd move the polling for BB_LOCK above the putScom. BRS
+ //
+
+ // Sanity check the DRAM generation
+ for (auto c : i_target.getChildren<TARGET_TYPE_MCS>())
+ {
+ FAPI_TRY( check::dram_type(c) );
+ }
+
+ // Step A: Configure ADR registers and MCLK detect (done in ddr_phy_reset)
+ {
+ for (auto p : l_ports)
+ {
+ FAPI_INF("Enabling slew calibration engine on port %i: DDR%i(%u) %u(%u) in %s",
+ mss::pos(p), (ddr_type + 2), ddr_idx, ddr_freq, freq_idx, l_name);
+
+ // Note: This is wrong. Cant' find the SLEW_CAL enable bit in n10_e9024, so leaving this here for now BRS
+ FAPI_TRY( fapi2::putScom(p, MCA_DDRPHY_ADR_SLEW_CAL_CNTL_P0_ADR32S0,
+ fapi2::buffer<uint64_t>().setBit<ENABLE_BIT>()),
+ "Error enabling slew calibration engine in DDRPHY_ADR_SLEW_CAL_CNTL register.");
+ }
+ }
+
+ // Note: must be 2000 nclks+ after setting enable bit
+ // normally 2000, but since cal doesn't work in SIM, setting to 1
+ FAPI_TRY( fapi2::delay(cycles_to_ns(i_target, 2000), cycles_to_simcycles(1)) );
+
+ // Create calibrated slew settings, per MCS. We do this as the attributes are written per MCS,
+ // and this makes it easier to keep track of what's going where, etc.
+ for (auto c : i_target.getChildren<TARGET_TYPE_MCS>())
+ {
+ // [adr or data][port on mcs][imp][slew]
+ uint8_t calibrated_slew[2][PORTS_PER_MCS][MAX_NUM_IMP][MAX_NUM_CAL_SLEW_RATES] = {0};
+
+ auto l_mcs_ports = c.getChildren<TARGET_TYPE_MCA>();
+
+ for (auto p : l_mcs_ports)
+ {
+ for (auto e : slew_table)
+ {
+ FAPI_INF("Starting %s, port %d slew calibration", (e.first == TAG_ADR ? "adr" : "data"), mss::pos(p));
+
+ for (auto this_table : e.second)
+ {
+ std::vector<tags_t> l_where_am_i;
+ l_where_am_i.push_back(e.first);
+ FAPI_TRY( perform_slew_cal(p, l_where_am_i, this_table, calibrated_slew) );
+ }
+ }
+ }
+
+ // We have the calibrated slew settings, disable the calibration engine and do the
+ // attribute dance.
+ for (auto p : l_mcs_ports)
+ {
+ // Note: This is wrong. Cant' find the SLEW_CAL enable bit in n10_e9024, so leaving this here for now BRS
+ FAPI_TRY( fapi2::putScom(p, MCA_DDRPHY_ADR_SLEW_CAL_CNTL_P0_ADR32S0,
+ fapi2::buffer<uint64_t>().clearBit<ENABLE_BIT>()),
+ "Error disabling slew calibration engine in DDRPHY_ADR_SLEW_CAL_CNTL register.");
+ }
+
+// FAPI_TRY( slew_cal_attributes() );
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+} // namespace
OpenPOWER on IntegriCloud