summaryrefslogtreecommitdiffstats
path: root/src/import/chips/p9
diff options
context:
space:
mode:
Diffstat (limited to 'src/import/chips/p9')
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/ccs/ccs.C254
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/ccs/ccs.H648
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/dimm/mrs_load.C166
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/dimm/mrs_load.H184
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/dimm/mrs_load_ddr4.C844
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/dimm/mrs_load_ddr4.H157
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/dimm/rank.C320
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/dimm/rank.H94
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/dimm/rcd_load.C165
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/dimm/rcd_load.H174
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/dimm/rcd_load_ddr4.C138
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/dimm/rcd_load_ddr4.H48
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/mcbist/mcbist.C41
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/mcbist/mcbist.H255
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/mss.H63
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/mss.mk43
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/mss_utils.H36
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/phy/cal_timers.H245
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/phy/ddr_phy.C881
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/phy/ddr_phy.H832
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/phy/dp16.C330
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/phy/dp16.H165
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/port/port.H265
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/shared/mss_const.H141
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/shared/mss_kind.H116
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/spd/spd_decoder.C3548
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/spd/spd_decoder.H424
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/termination/slew_cal.C497
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/termination/slew_cal.H144
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/termination/slew_cal_status.C110
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/utils/bit_count.H83
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/utils/c_str.C122
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/utils/c_str.H154
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/utils/checker.H298
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/utils/conversions.H263
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/utils/fake_spd.C95
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/utils/fake_spd.H51
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/utils/find.H187
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/utils/index.H71
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/utils/poll.H134
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/utils/pos.H133
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/utils/swizzle.H123
42 files changed, 13042 insertions, 0 deletions
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/ccs/ccs.C b/src/import/chips/p9/procedures/hwp/memory/lib/ccs/ccs.C
new file mode 100644
index 000000000..5753fd577
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/ccs/ccs.C
@@ -0,0 +1,254 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/ccs/ccs.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 ccs.C
+/// @brief Run and manage the CCS engine
+///
+// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
+// *HWP HWP Backup: Craig Hamilton <cchamilt@us.ibm.com>
+// *HWP Team: Memory
+// *HWP Level: 2
+// *HWP Consumed by: FSP:HB
+
+#include <fapi2.H>
+
+#include "../mss.H"
+#include "ccs.H"
+
+using fapi2::TARGET_TYPE_MCBIST;
+using fapi2::TARGET_TYPE_MCA;
+
+using fapi2::FAPI2_RC_SUCCESS;
+
+namespace mss
+{
+namespace ccs
+{
+
+///
+/// @brief Start or stop the CCS engine
+/// @param[in] i_target The MCBIST containing the CCS engine
+/// @param[in] i_start_stop bool MSS_CCS_START for starting, MSS_CCS_STOP otherwise
+/// @return FAPI2_RC_SUCCESS iff success
+///
+template<>
+fapi2::ReturnCode start_stop( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target, bool i_start_stop )
+{
+ typedef ccsTraits<TARGET_TYPE_MCBIST> TT;
+
+ fapi2::buffer<uint64_t> l_buf;
+
+ // Do we need to read this? We are setting the only bit defined in the scomdef? BRS
+ FAPI_TRY(fapi2::getScom(i_target, TT::CNTLQ_REG, l_buf));
+
+ FAPI_TRY( fapi2::putScom(i_target, TT::CNTLQ_REG,
+ i_start_stop ? l_buf.setBit<TT::CCS_START>() : l_buf.setBit<TT::CCS_STOP>()) );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Determine the CCS failure type
+/// @tparam T the fapi2 target type of the target for this error
+/// @param[in] the failure type
+/// @return ReturnCode associated with the fail.
+/// @note FFDC is handled here, caller doesn't need to do it
+///
+template< fapi2::TargetType T >
+fapi2::ReturnCode fail_type( const fapi2::Target<T>& i_target, const uint64_t& i_type )
+{
+ FAPI_ASSERT(STAT_READ_MISCOMPARE != i_type,
+ fapi2::MSS_CCS_READ_MISCOMPARE().set_TARGET_IN_ERROR(i_target),
+ "CCS FAIL Read Miscompare");
+
+ FAPI_ASSERT(STAT_UE_SUE != i_type,
+ fapi2::MSS_CCS_UE_SUE().set_TARGET_IN_ERROR(i_target),
+ "CCS FAIL UE or SUE Error");
+
+ FAPI_ASSERT(STAT_CAL_TIMEOUT != i_type,
+ fapi2::MSS_CCS_CAL_TIMEOUT().set_TARGET_IN_ERROR(i_target),
+ "CCS FAIL Calibration Operation Time Out");
+
+ FAPI_ASSERT(STAT_HUNG != i_type,
+ fapi2::MSS_CCS_HUNG().set_TARGET_IN_ERROR(i_target),
+ "CCS appears hung");
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Execute the contents of the CCS array
+/// @param[in] i_target The MCBIST containing the array
+/// @param[in] the MCBIST ccs program - to get the polling parameters
+/// @return FAPI2_RC_SUCCESS iff success
+///
+template<>
+fapi2::ReturnCode execute_inst_array(const fapi2::Target<TARGET_TYPE_MCBIST>& i_target,
+ ccs::program<TARGET_TYPE_MCBIST>& i_program)
+{
+ typedef ccsTraits<TARGET_TYPE_MCBIST> TT;
+
+ fapi2::buffer<uint64_t> status;
+
+ FAPI_TRY(start_stop(i_target, mss::START));
+
+ mss::poll(i_target, TT::STATQ_REG, i_program.iv_poll,
+ [&status](const size_t poll_remaining, const fapi2::buffer<uint64_t>& stat_reg) -> bool
+ {
+ FAPI_DBG("ccs statq 0x%llx, remaining: %d", stat_reg, poll_remaining);
+ status = stat_reg;
+ return status.getBit<TT::CCS_IN_PROGRESS>() != 1;
+ });
+
+ // Check for done and success. DONE being the only bit set.
+ if (status == STAT_QUERY_SUCCESS)
+ {
+ FAPI_DBG("CCS Executed Successfully.");
+ goto fapi_try_exit;
+ }
+
+ // So we failed or we're still in progress. Mask off the fail bits
+ // and run this through the FFDC generator.
+ FAPI_TRY( fail_type(i_target, status & 0x1C00000000000000) );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Execute a set of CCS instructions
+/// @tparam T, the fapi2::TargetType - derived
+/// @tparam TT, the ccsTraits associated with T - derived
+/// @param[in] the target to effect
+/// @param[in] the vector of instructions
+/// @param[in] the vector of ports
+/// @return FAPI2_RC_SUCCSS iff ok
+/// @note assumes the CCS engine has been configured.
+///
+template<>
+fapi2::ReturnCode execute( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target,
+ ccs::program<TARGET_TYPE_MCBIST>& i_program,
+ const std::vector< fapi2::Target<TARGET_TYPE_MCA> >& i_ports)
+{
+ // Subtract one for the idle we insert at the end
+ static const size_t CCS_INSTRUCTION_DEPTH = 32 - 1;
+ static const uint64_t CCS_ARR0_ZERO = MCBIST_CCS_INST_ARR0_00;
+ static const uint64_t CCS_ARR1_ZERO = MCBIST_CCS_INST_ARR1_00;
+
+ ccs::instruction_t<TARGET_TYPE_MCBIST> l_des = ccs::des_command<TARGET_TYPE_MCBIST>();
+
+ FAPI_DBG("loading ccs instructions (%d) for %s", i_program.iv_instructions.size(), mss::c_str(i_target));
+
+ auto l_inst_iter = i_program.iv_instructions.begin();
+
+ while (l_inst_iter != i_program.iv_instructions.end())
+ {
+ size_t l_inst_count = 0;
+
+ uint64_t l_total_delay = 0;
+ uint64_t l_delay = 0;
+ uint64_t l_repeat = 0;
+
+ // Shove the instructions into the CCS engine, in 32 instruction chunks, and execute them
+ for (; l_inst_iter != i_program.iv_instructions.end()
+ && l_inst_count < CCS_INSTRUCTION_DEPTH; ++l_inst_count, ++l_inst_iter)
+ {
+ // Make sure this instruction leads to the next. Notice this limits this mechanism to pretty
+ // simple (straight line) CCS programs. Anything with a loop or such will need another mechanism.
+ l_inst_iter->arr1.insertFromRight<MCBIST_CCS_INST_ARR1_00_GOTO_CMD,
+ MCBIST_CCS_INST_ARR1_00_GOTO_CMD_LEN>(l_inst_count + 1);
+ FAPI_TRY( fapi2::putScom(i_target, CCS_ARR0_ZERO + l_inst_count, l_inst_iter->arr0) );
+ FAPI_TRY( fapi2::putScom(i_target, CCS_ARR1_ZERO + l_inst_count, l_inst_iter->arr1) );
+
+ // arr1 contains a specification of the delay and repeat after this instruction, as well
+ // as a repeat. Total up the delays as we go so we know how long to wait before polling
+ // the CCS engine for completion
+ l_inst_iter->arr1.extractToRight<MCBIST_CCS_INST_ARR1_00_IDLES, MCBIST_CCS_INST_ARR1_00_IDLES_LEN>(l_delay);
+ l_inst_iter->arr1.extractToRight<MCBIST_CCS_INST_ARR1_00_REPEAT_CMD_CNT,
+ MCBIST_CCS_INST_ARR1_00_REPEAT_CMD_CNT>(l_repeat);
+
+ l_total_delay += l_delay * (l_repeat + 1);
+
+ FAPI_DBG("css inst %d: 0x%016lX 0x%016lX (0x%lx, 0x%lx) delay: 0x%x (0x%x) %s",
+ l_inst_count, l_inst_iter->arr0, l_inst_iter->arr1,
+ CCS_ARR0_ZERO + l_inst_count, CCS_ARR1_ZERO + l_inst_count,
+ l_delay, l_total_delay, mss::c_str(i_target));
+ }
+
+ // Check our program for any delays. If there isn't a iv_initial_delay configured, then
+ // we use the delay we just summed from the instructions.
+ if (i_program.iv_poll.iv_initial_delay == 0)
+ {
+ i_program.iv_poll.iv_initial_delay = cycles_to_ns(i_target, l_total_delay);
+ }
+
+ if (i_program.iv_poll.iv_initial_sim_delay == 0)
+ {
+ i_program.iv_poll.iv_initial_sim_delay = cycles_to_simcycles(l_total_delay);
+ }
+
+ FAPI_DBG("executing ccs instructions (%d:%d, %d) for %s",
+ i_program.iv_instructions.size(), l_inst_count, i_program.iv_poll.iv_initial_delay, mss::c_str(i_target));
+
+ // Insert a DES as our last instruction. DES is idle state anyway and having this
+ // here as an instruction forces the CCS engine to wait the delay specified in
+ // the last instruction in this array (which it otherwise doesn't do.)
+ l_des.arr1.setBit<MCBIST_CCS_INST_ARR1_00_END>();
+ FAPI_TRY( fapi2::putScom(i_target, CCS_ARR0_ZERO + l_inst_count, l_des.arr0) );
+ FAPI_TRY( fapi2::putScom(i_target, CCS_ARR1_ZERO + l_inst_count, l_des.arr1) );
+
+ FAPI_DBG("css inst %d fixup: 0x%016lX 0x%016lX (0x%lx, 0x%lx) %s",
+ l_inst_count, l_des.arr0, l_des.arr1,
+ CCS_ARR0_ZERO + l_inst_count, CCS_ARR1_ZERO + l_inst_count, mss::c_str(i_target));
+
+ // Kick off the CCS engine - per port. No broadcast mode for CCS (per Shelton 9/23/15)
+ for (auto p : i_ports)
+ {
+ FAPI_DBG("executing CCS array for port %d (%s)", mss::pos(p), mss::c_str(p));
+ FAPI_TRY( select_ports( i_target, mss::pos(p)) );
+ FAPI_TRY( execute_inst_array(i_target, i_program) );
+ }
+ }
+
+fapi_try_exit:
+ i_program.iv_instructions.clear();
+ return fapi2::current_err;
+}
+
+///
+/// @brief Nimbus specialization for modeq_copy_cke_to_spare_cke
+/// @tparam T, the fapi2::TargetType - derived
+/// @tparam TT, the ccsTraits associated with T - derived
+/// @param[in] the target to effect
+/// @param[in] the buffer representing the mode register
+/// @param[in] bool, true iff Copy CKE signals to CKE Spare on both ports
+/// @return void
+/// @note no-op for p9n
+///
+template<>
+void copy_cke_to_spare_cke<TARGET_TYPE_MCBIST>( const fapi2::Target<TARGET_TYPE_MCBIST>&, fapi2::buffer<uint64_t>&,
+ bool )
+{
+ return;
+}
+
+} // namespace
+} // namespace
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/ccs/ccs.H b/src/import/chips/p9/procedures/hwp/memory/lib/ccs/ccs.H
new file mode 100644
index 000000000..d5008f660
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/ccs/ccs.H
@@ -0,0 +1,648 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/ccs/ccs.H $ */
+/* */
+/* 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 ccs.H
+/// @brief Run and manage the CCS engine
+///
+// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
+// *HWP HWP Backup: Craig Hamilton <cchamilt@us.ibm.com>
+// *HWP Team: Memory
+// *HWP Level: 1
+// *HWP Consumed by: HB:FSP
+
+#ifndef _MSS_CCS_H_
+#define _MSS_CCS_H_
+
+#include <fapi2.H>
+
+#include <p9_mc_scom_addresses.H>
+
+#include "../utils/poll.H"
+#include "../port/port.H"
+#include "../shared/mss_const.H"
+
+// I have a dream that the CCS engine code can be shared among controllers. So, I drive the
+// engine from a set of traits. This might be folly. Allow me to dream. BRS
+
+template< fapi2::TargetType T >
+class ccsTraits;
+
+// Centaur CCS Engine traits
+template<>
+class ccsTraits<fapi2::TARGET_TYPE_MEMBUF_CHIP>
+{
+ public:
+};
+
+// Nimbus CCS Engine traits
+template<>
+class ccsTraits<fapi2::TARGET_TYPE_MCBIST>
+{
+ public:
+ static const uint64_t MODEQ_REG = MCBIST_CCS_MODEQ;
+ static const uint64_t MCB_CNTL_REG = MCBIST_MCB_CNTLQ;
+ static const uint64_t CNTLQ_REG = MCBIST_CCS_CNTLQ;
+ static const uint64_t STATQ_REG = MCBIST_CCS_STATQ;
+
+ enum
+ {
+ // CCS MODEQ
+ STOP_ON_ERR = MCBIST_CCS_MODEQ_STOP_ON_ERR,
+ UE_DISABLE = MCBIST_CCS_MODEQ_UE_DISABLE,
+ DATA_COMPARE_BURST_SEL = MCBIST_CCS_MODEQ_DATA_COMPARE_BURST_SEL,
+ DATA_COMPARE_BURST_SEL_LEN = MCBIST_CCS_MODEQ_DATA_COMPARE_BURST_SEL_LEN,
+ DDR_CAL_TIMEOUT_CNT = MCBIST_CCS_MODEQ_DDR_CAL_TIMEOUT_CNT,
+ DDR_CAL_TIMEOUT_CNT_LEN = MCBIST_CCS_MODEQ_DDR_CAL_TIMEOUT_CNT_LEN,
+ CFG_PARITY_AFTER_CMD = MCBIST_CCS_MODEQ_CFG_PARITY_AFTER_CMD,
+ COPY_CKE_TO_SPARE_CKE = MCBIST_CCS_MODEQ_COPY_CKE_TO_SPARE_CKE,
+ DISABLE_ECC_ARRAY_CHK = MCBIST_CCS_MODEQ_DISABLE_ECC_ARRAY_CHK,
+ DISABLE_ECC_ARRAY_CORRECTION = MCBIST_CCS_MODEQ_DISABLE_ECC_ARRAY_CORRECTION,
+ CFG_DGEN_FIXED_MODE = MCBIST_CCS_MODEQ_CFG_DGEN_FIXED_MODE,
+ DDR_CAL_TIMEOUT_CNT_MULT = MCBIST_CCS_MODEQ_DDR_CAL_TIMEOUT_CNT_MULT,
+ DDR_CAL_TIMEOUT_CNT_MULT_LEN = MCBIST_CCS_MODEQ_DDR_CAL_TIMEOUT_CNT_MULT_LEN,
+ IDLE_PAT_ADDRESS_0_13 = MCBIST_CCS_MODEQ_IDLE_PAT_ADDRESS_0_13,
+ IDLE_PAT_ADDRESS_0_13_LEN = MCBIST_CCS_MODEQ_IDLE_PAT_ADDRESS_0_13_LEN,
+ IDLE_PAT_ADDRESS_17 = MCBIST_CCS_MODEQ_IDLE_PAT_ADDRESS_17,
+ IDLE_PAT_BANK_GROUP_1 = MCBIST_CCS_MODEQ_IDLE_PAT_BANK_GROUP_1,
+ IDLE_PAT_BANK_0_1 = MCBIST_CCS_MODEQ_IDLE_PAT_BANK_0_1,
+ IDLE_PAT_BANK_0_1_LEN = MCBIST_CCS_MODEQ_IDLE_PAT_BANK_0_1_LEN,
+ IDLE_PAT_BANK_GROUP_0 = MCBIST_CCS_MODEQ_IDLE_PAT_BANK_GROUP_0,
+ IDLE_PAT_ACTN = MCBIST_CCS_MODEQ_IDLE_PAT_ACTN,
+ IDLE_PAT_ADDRESS_16 = MCBIST_CCS_MODEQ_IDLE_PAT_ADDRESS_16,
+ IDLE_PAT_ADDRESS_15 = MCBIST_CCS_MODEQ_IDLE_PAT_ADDRESS_15,
+ IDLE_PAT_ADDRESS_14 = MCBIST_CCS_MODEQ_IDLE_PAT_ADDRESS_14,
+ NTTM_MODE = MCBIST_CCS_MODEQ_NTTM_MODE,
+ NTTM_RW_DATA_DLY = MCBIST_CCS_MODEQ_NTTM_RW_DATA_DLY,
+ NTTM_RW_DATA_DLY_LEN = MCBIST_CCS_MODEQ_NTTM_RW_DATA_DLY_LEN,
+ IDLE_PAT_BANK_2 = MCBIST_CCS_MODEQ_IDLE_PAT_BANK_2,
+ DDR_PARITY_ENABLE = MCBIST_CCS_MODEQ_DDR_PARITY_ENABLE,
+ IDLE_PAT_PARITY = MCBIST_CCS_MODEQ_IDLE_PAT_PARITY,
+
+ // MCB_CNTRL
+ MCB_CNTL_PORT_SEL = MCBIST_MCB_CNTLQ_MCBCNTL_PORT_SEL,
+ MCB_CNTL_PORT_SEL_LEN = MCBIST_MCB_CNTLQ_MCBCNTL_PORT_SEL_LEN,
+
+ // CCS CNTL
+ CCS_START = MCBIST_CCS_CNTLQ_START,
+ CCS_STOP = MCBIST_CCS_CNTLQ_STOP,
+
+ // CCS STATQ
+ CCS_IN_PROGRESS = MCBIST_CCS_STATQ_IP,
+
+ // ARR0
+ ARR0_DDR_ADDRESS_0_13 = MCBIST_CCS_INST_ARR0_00_DDR_ADDRESS_0_13,
+ ARR0_DDR_ADDRESS_0_13_LEN = MCBIST_CCS_INST_ARR0_00_DDR_ADDRESS_0_13_LEN,
+ ARR0_DDR_ADDRESS_17 = MCBIST_CCS_INST_ARR0_00_DDR_ADDRESS_17,
+ ARR0_DDR_BANK_GROUP_1 = MCBIST_CCS_INST_ARR0_00_DDR_BANK_GROUP_1,
+ ARR0_DDR_RESETN = MCBIST_CCS_INST_ARR0_00_DDR_RESETN,
+ ARR0_DDR_BANK_0_1 = MCBIST_CCS_INST_ARR0_00_DDR_BANK_0_1,
+ ARR0_DDR_BANK_0_1_LEN = MCBIST_CCS_INST_ARR0_00_DDR_BANK_0_1_LEN,
+ ARR0_DDR_BANK_GROUP_0 = MCBIST_CCS_INST_ARR0_00_DDR_BANK_GROUP_0,
+ ARR0_DDR_ACTN = MCBIST_CCS_INST_ARR0_00_DDR_ACTN,
+ ARR0_DDR_ADDRESS_16 = MCBIST_CCS_INST_ARR0_00_DDR_ADDRESS_16,
+ ARR0_DDR_ADDRESS_15 = MCBIST_CCS_INST_ARR0_00_DDR_ADDRESS_15,
+ ARR0_DDR_ADDRESS_14 = MCBIST_CCS_INST_ARR0_00_DDR_ADDRESS_14,
+ ARR0_DDR_CKE = MCBIST_CCS_INST_ARR0_00_DDR_CKE,
+ ARR0_DDR_CKE_LEN = MCBIST_CCS_INST_ARR0_00_DDR_CKE_LEN,
+ ARR0_DDR_CSN_0_1 = MCBIST_CCS_INST_ARR0_00_DDR_CSN_0_1,
+ ARR0_DDR_CSN_0_1_LEN = MCBIST_CCS_INST_ARR0_00_DDR_CSN_0_1_LEN,
+ ARR0_DDR_CID_0_1 = MCBIST_CCS_INST_ARR0_00_DDR_CID_0_1,
+ ARR0_DDR_CID_0_1_LEN = MCBIST_CCS_INST_ARR0_00_DDR_CID_0_1_LEN,
+ ARR0_DDR_CSN_2_3 = MCBIST_CCS_INST_ARR0_00_DDR_CSN_2_3,
+ ARR0_DDR_CSN_2_3_LEN = MCBIST_CCS_INST_ARR0_00_DDR_CSN_2_3_LEN,
+ ARR0_DDR_CID_2 = MCBIST_CCS_INST_ARR0_00_DDR_CID_2,
+ ARR0_DDR_ODT = MCBIST_CCS_INST_ARR0_00_DDR_ODT,
+ ARR0_DDR_ODT_LEN = MCBIST_CCS_INST_ARR0_00_DDR_ODT_LEN,
+ ARR0_DDR_CAL_TYPE = MCBIST_CCS_INST_ARR0_00_DDR_CAL_TYPE,
+ ARR0_DDR_CAL_TYPE_LEN = MCBIST_CCS_INST_ARR0_00_DDR_CAL_TYPE_LEN,
+ ARR0_DDR_PARITY = MCBIST_CCS_INST_ARR0_00_DDR_PARITY,
+ ARR0_DDR_BANK_2 = MCBIST_CCS_INST_ARR0_00_DDR_BANK_2,
+ ARR0_LOOP_BREAK_MODE = MCBIST_CCS_INST_ARR0_00_LOOP_BREAK_MODE,
+ ARR0_LOOP_BREAK_MODE_LEN = MCBIST_CCS_INST_ARR0_00_LOOP_BREAK_MODE_LEN,
+
+ // ARR1
+ ARR1_IDLES = MCBIST_CCS_INST_ARR1_00_IDLES,
+ ARR1_IDLES_LEN = MCBIST_CCS_INST_ARR1_00_IDLES_LEN,
+ ARR1_REPEAT_CMD_CNT = MCBIST_CCS_INST_ARR1_00_REPEAT_CMD_CNT,
+ ARR1_REPEAT_CMD_CNT_LEN = MCBIST_CCS_INST_ARR1_00_REPEAT_CMD_CNT_LEN,
+ ARR1_READ_OR_WRITE_DATA = MCBIST_CCS_INST_ARR1_00_READ_OR_WRITE_DATA,
+ ARR1_READ_OR_WRITE_DATA_LEN = MCBIST_CCS_INST_ARR1_00_READ_OR_WRITE_DATA_LEN,
+ ARR1_READ_COMPARE_REQUIRED = MCBIST_CCS_INST_ARR1_00_READ_COMPARE_REQUIRED,
+ ARR1_DDR_CAL_RANK = MCBIST_CCS_INST_ARR1_00_DDR_CAL_RANK,
+ ARR1_DDR_CAL_RANK_LEN = MCBIST_CCS_INST_ARR1_00_DDR_CAL_RANK_LEN,
+ ARR1_DDR_CALIBRATION_ENABLE = MCBIST_CCS_INST_ARR1_00_DDR_CALIBRATION_ENABLE,
+ ARR1_END = MCBIST_CCS_INST_ARR1_00_END,
+ ARR1_GOTO_CMD = MCBIST_CCS_INST_ARR1_00_GOTO_CMD,
+ ARR1_GOTO_CMD_LEN = MCBIST_CCS_INST_ARR1_00_GOTO_CMD_LEN,
+
+ };
+};
+
+namespace mss
+{
+namespace ccs
+{
+
+enum
+{
+ // Success is defined as done-bit set, no others.
+ STAT_QUERY_SUCCESS = 0x4000000000000000,
+
+ // Bit positions 3:5
+ STAT_READ_MISCOMPARE = 0x1000000000000000,
+ STAT_UE_SUE = 0x0800000000000000,
+ STAT_CAL_TIMEOUT = 0x0400000000000000,
+
+ // If the fail type isn't one of these, we're hung
+ STAT_HUNG = 0x0ull,
+};
+
+// A ccs instruction is data (array 0) and some control information (array 1)
+template< fapi2::TargetType T, typename TT = ccsTraits<T> >
+class instruction_t
+{
+ public:
+ fapi2::buffer<uint64_t> arr0;
+ fapi2::buffer<uint64_t> arr1;
+
+ ///
+ /// @brief intstruction_t ctor
+ /// @param[in] the DIMM this instruction is headed for
+ /// @param[in] the rank this instruction is headed for
+ /// @param[in] the initial value for arr0, defaults to 0
+ /// @param[in] the initial value for arr1, defaults to 0
+ ///
+ instruction_t( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target = fapi2::Target<fapi2::TARGET_TYPE_DIMM>(),
+ uint64_t i_rank = 0xFF,
+ const fapi2::buffer<uint64_t> i_arr0 = 0,
+ const fapi2::buffer<uint64_t> i_arr1 = 0):
+ arr0(i_arr0),
+ arr1(i_arr1)
+ {
+
+ static const uint64_t CS_N[mss::MAX_RANK_PER_DIMM] =
+ {
+ // DCS0 L DCS1 H => Rank 0
+ 0b01,
+ // DCS0 H DCS1 L => Rank 1
+ 0b10,
+ };
+
+ // Start be deselcting everything and we'll clear the bits we want.
+ arr0.insertFromRight<TT::ARR0_DDR_CSN_0_1, TT::ARR0_DDR_CSN_0_1_LEN>(0b11);
+ arr0.insertFromRight<TT::ARR0_DDR_CSN_2_3, TT::ARR0_DDR_CSN_2_3_LEN>(0b11);
+
+ // If the rank indicates nothing selected (active low) then we're done.
+ if (i_rank == 0xFF)
+ {
+ return;
+ }
+
+ //
+ // Note: This needs to be able to handle all DIMM, stacked, encoded CS_n, etc. This
+ // ain't gonna cut it. Turn this in to a dispatched funtion like c_str() and rcd_load() BRS
+ //
+
+ // Direct CS mode - just clear the CS_N you're interested in.
+ // Setup the chip select based on which dimm in the slot and the rank
+ if (mss::index(i_target) == 0)
+ {
+ arr0.insertFromRight<TT::ARR0_DDR_CSN_0_1,
+ TT::ARR0_DDR_CSN_0_1_LEN>(CS_N[i_rank]);
+ }
+ else
+ {
+ arr0.insertFromRight<TT::ARR0_DDR_CSN_2_3,
+ TT::ARR0_DDR_CSN_2_3_LEN>(CS_N[i_rank]);
+ }
+
+#ifdef QUAD_ENCODED_CS
+ // Implement the Encoded QuadCS Mode DCS, DC mapping and stuff the resulting
+ // bits in to the proper location for the CCS instruction (perhaps we need
+ // to be a template - p9n CCS is different from Centaur ... make initializing
+ // the instruction a policy of the ccsTraits ... BRS)
+
+ // Lookup table for CS_N and CID indexed by rank for Quad encoded CS modee
+ // First bits 0:1 is DCS1_n:DCS2_n. Second bits 0:1 are CID 0:1 bit 2 is CID 2
+ static const std::pair< uint8_t, uint8_t > CS_CID[mss::MAX_RANK_PER_DIMM] =
+ {
+ // DCS0 L DCS1 H CID L:L => Rank 0
+ { 0b01000000, 0b00000000 },
+ // DCS0 L DCS1 H CID H:H => Rank 1
+ { 0b01000000, 0b11000000 },
+ // DCS0 H DCS1 L CID L:L => Rank 2
+ { 0b10000000, 0b00000000 },
+ // DCS0 H DCS1 L CID H:H => Rank 3
+ { 0b10000000, 0b11000000 },
+ };
+
+ // Setup the chip select based on which dimm in the slot and the rank
+ if (mss::index(i_target) == 0)
+ {
+ arr0.insert<TT::ARR0_DDR_CSN_0_1,
+ TT::ARR0_DDR_CSN_0_1_LEN>(CS_CID[i_rank].first);
+ }
+ else
+ {
+ arr0.insert<TT::ARR0_DDR_CSN_2_3,
+ TT::ARR0_DDR_CSN_2_3_LEN>(CS_CID[i_rank].first);
+ }
+
+ arr0.insert<TT::ARR0_DDR_CID_0_1,
+ TT::ARR0_DDR_CID_0_1_LEN>(CS_CID[i_rank].second);
+ arr0.writeBit<TT::ARR0_DDR_CID_2>(
+ fapi2::buffer<uint8_t>(CS_CID[i_rank].second).getBit<2>());
+#endif
+ }
+};
+
+///
+/// @brief A class representing a series of CCS instructions, and the
+/// CCS engine parameters associated with running the instructions
+/// @tparam fapi2::TargetType T representing the fapi2 target which
+/// contains the CCS engine (e.g., fapi2::TARGET_TYPE_MCBIST)
+template< fapi2::TargetType T >
+class program
+{
+ public:
+ // Setup our poll parameters so the CCS executer can see
+ // whether to use the delays in the instruction stream or not
+ program(): iv_poll(0, 0)
+ {}
+
+ // Vector of instructions
+ std::vector< instruction_t<T> > iv_instructions;
+ poll_parameters iv_poll;
+};
+
+///
+/// @brief Common setup for all MRS/RCD instructions
+/// @param[in,out] fapi2::buffer<uint64_t> representing the ARR0 of the instruction
+/// @return void
+///
+template< fapi2::TargetType T, typename TT = ccsTraits<T> >
+static void mrs_rcd_helper( fapi2::buffer<uint64_t>& i_arr0 )
+{
+ //
+ // Generic DDR4 MRS setup (RCD is an MRS)
+ //
+ // CKE is high Note: P8 set all 4 of these high - not sure if that's correct. BRS
+ i_arr0.insertFromRight<TT::ARR0_DDR_CKE, TT::ARR0_DDR_CKE_LEN>(0b1111);
+
+ // ACT is high
+ i_arr0.setBit<TT::ARR0_DDR_ACTN>();
+
+ // RAS, CAS, WE low
+ i_arr0.clearBit<TT::ARR0_DDR_ADDRESS_16>();
+ i_arr0.clearBit<TT::ARR0_DDR_ADDRESS_15>();
+ i_arr0.clearBit<TT::ARR0_DDR_ADDRESS_14>();
+}
+
+///
+/// @brief Create, initialize an RCD (RCW - JEDEC) CCS command
+/// @tparam T, the fapi2 type of the unit which contains the CCS engine
+/// @param[in] the DIMM this instruction is headed for
+/// @return the RCD CCS instruction
+/// @note THIS IS DDR4 ONLY RIGHT NOW. We can (and possibly should) specialize this
+/// for the controller (Nimbus v Centaur) and then correct for DRAM generation (not included
+/// in this template definition)
+///
+template< fapi2::TargetType T, typename TT = ccsTraits<T> >
+inline instruction_t<T> rcd_command( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target )
+{
+ fapi2::buffer<uint64_t> rcd_boilerplate_arr0;
+ fapi2::buffer<uint64_t> rcd_boilerplate_arr1;
+
+ //
+ // Generic DDR4 MRS setup (RCD is an MRS)
+ //
+ mrs_rcd_helper<fapi2::TARGET_TYPE_MCBIST>(rcd_boilerplate_arr0);
+
+ //
+ // RCD setup
+ //
+ // DDR4: Set BG1 to 0. BG0, BA1:BA0 to 0b111
+ rcd_boilerplate_arr0.clearBit<TT::ARR0_DDR_BANK_GROUP_1>();
+ rcd_boilerplate_arr0.insertFromRight<TT::ARR0_DDR_BANK_0_1, TT::ARR0_DDR_BANK_0_1_LEN>(0b11);
+ rcd_boilerplate_arr0.setBit<TT::ARR0_DDR_BANK_GROUP_0>();
+
+ // RCD always goes to rank 0. All we need to know is which DIMM we are on the port
+ return instruction_t<T>(i_target, 0, rcd_boilerplate_arr0, rcd_boilerplate_arr1);
+}
+
+///
+/// @brief Create, initialize an MRS CCS command
+/// @tparam T, the fapi2 type of the unit which contains the CCS engine
+/// @param[in] the DIMM this instruction is headed for
+/// @param[in] the rank on this dimm
+/// @param[in] the specific MRS
+/// @return the MRS CCS instruction
+/// @note THIS IS DDR4 ONLY RIGHT NOW. We can (and possibly should) specialize this
+/// for the controller (Nimbus v Centaur) and then correct for DRAM generation (not included
+/// in this template definition)
+///
+template< fapi2::TargetType T, typename TT = ccsTraits<T> >
+inline instruction_t<T> mrs_command( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target, const uint64_t i_rank,
+ const uint64_t i_mrs )
+{
+ fapi2::buffer<uint64_t> rcd_boilerplate_arr0;
+ fapi2::buffer<uint64_t> rcd_boilerplate_arr1;
+ fapi2::buffer<uint8_t> mrs(i_mrs);
+
+ //
+ // Generic DDR4 MRS setup (RCD is an MRS)
+ //
+ mrs_rcd_helper<fapi2::TARGET_TYPE_MCBIST>(rcd_boilerplate_arr0);
+
+ //
+ // MRS setup
+ //
+ // DDR4: Set BG1 to 0. BG0, BA1:BA0 to i_mrs
+ rcd_boilerplate_arr0.clearBit<TT::ARR0_DDR_BANK_GROUP_1>();
+ mss::swizzle<TT::ARR0_DDR_BANK_0_1, 3, 7>(mrs, rcd_boilerplate_arr0);
+ FAPI_DBG("mrs rcd boiler 0x%llx 0x%llx", uint8_t(mrs), uint64_t(rcd_boilerplate_arr0));
+ return instruction_t<T>(i_target, i_rank, rcd_boilerplate_arr0, rcd_boilerplate_arr1);
+}
+
+///
+/// @brief Create, initialize a JEDEC Device Deselect CCS command
+/// @tparam T, the fapi2 type of the unit containing the CCS engine
+/// @return the Device Deselect CCS instruction
+/// @note THIS IS DDR4 ONLY RIGHT NOW. We can (and possibly should) specialize this
+/// for the controller (Nimbus v Centaur) and then correct for DRAM generation (not included
+/// in this template definition)
+///
+template< fapi2::TargetType T, typename TT = ccsTraits<T> >
+inline instruction_t<T> des_command()
+{
+ fapi2::buffer<uint64_t> rcd_boilerplate_arr0;
+ fapi2::buffer<uint64_t> rcd_boilerplate_arr1;
+
+ // ACT is high. It's a no-care in the spec but it seems to raise questions when
+ // people look at the trace, so lets set it high.
+ rcd_boilerplate_arr0.setBit<TT::ARR0_DDR_ACTN>();
+
+ // CKE is high Note: P8 set all 4 of these high - not sure if that's correct. BRS
+ rcd_boilerplate_arr0.insertFromRight<TT::ARR0_DDR_CKE, TT::ARR0_DDR_CKE_LEN>(0b1111);
+
+ // ACT is high no-care
+ // RAS, CAS, WE no-care
+
+ // Device Deslect wants CS_n always high (select nothing using rank 0xFF)
+ return instruction_t<T>(fapi2::Target<fapi2::TARGET_TYPE_DIMM>(), 0xFF, rcd_boilerplate_arr0, rcd_boilerplate_arr1);
+}
+
+///
+/// @brief Create, initialize an instruction which indicates an initial cal
+/// @param[in] the rank-pair (rank) to cal
+/// @return the initial cal instruction
+///
+template< fapi2::TargetType T, typename TT = ccsTraits<T> >
+inline instruction_t<T> initial_cal_command(const uint64_t i_rp)
+{
+ // An initial cal arr0 looks just like a DES, but we set the initial cal bits
+ instruction_t<T> l_inst = des_command<T>();
+
+ // ACT is low - per Centaur spec (Shelton to confirm for Nimbus) BRS
+ l_inst.arr0.template clearBit<TT::ARR0_DDR_ACTN>();
+
+ l_inst.arr0.template insertFromRight<TT::ARR0_DDR_CAL_TYPE, TT::ARR0_DDR_CAL_TYPE_LEN>(0b1100);
+ l_inst.arr1.template setBit<TT::ARR1_DDR_CALIBRATION_ENABLE>();
+
+#ifdef USE_LOTS_OF_IDLES
+ // Idles is 0xFFFF - per Centaur spec (Shelton to confirm for Nimbus) BRS
+ l_inst.arr1.template insertFromRight<TT::ARR1_IDLES, TT::ARR1_IDLES_LEN>(0xFFFF);
+#else
+ l_inst.arr1.template insertFromRight<TT::ARR1_IDLES, TT::ARR1_IDLES_LEN>(0x0);
+#endif
+
+ // The rank we're calibrating is enacoded - it's an int. So rank 3 is 0011 not 0001
+ l_inst.arr1.template insertFromRight<TT::ARR1_DDR_CAL_RANK, TT::ARR1_DDR_CAL_RANK_LEN>(i_rp);
+
+ return l_inst;
+}
+
+//
+// These functions are a little sugar to keep callers from doing the traits-dance to get the
+// appropriate bit field
+//
+
+///
+/// @brief Select the port(s) to be used by the CCS
+/// @tparam T, the fapi2::TargetType - derived
+/// @tparam TT, the ccsTraits associated with T - derived
+/// @param[in] the target to effect
+/// @param[in] the buffer representing the ports
+/// @return void
+///
+template< fapi2::TargetType T, typename TT = ccsTraits<T> >
+inline fapi2::ReturnCode select_ports( const fapi2::Target<T>& i_target, uint64_t i_ports)
+{
+ fapi2::buffer<uint64_t> l_data;
+ fapi2::buffer<uint64_t> l_ports;
+
+ // Not handling multiple ports here, can't do that for CCS. BRS
+ FAPI_TRY( l_ports.setBit(i_ports) );
+
+ FAPI_TRY( fapi2::getScom(i_target, TT::MCB_CNTL_REG, l_data) );
+ l_data.insert<TT::MCB_CNTL_PORT_SEL, TT::MCB_CNTL_PORT_SEL_LEN>(l_ports);
+ FAPI_TRY( fapi2::putScom(i_target, TT::MCB_CNTL_REG, l_data) );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief User sets to a '1'b to tell the Hdw to stop CCS whenever failure occurs. When a
+/// '0'b, Hdw will continue CCS even if a failure occurs.
+/// @tparam T, the fapi2::TargetType - derived
+/// @tparam TT, the ccsTraits associated with T - derived
+/// @param[in] the target to effect
+/// @param[in] the buffer representing the mode register
+/// @param[in] i_value, true iff stop whenever failure occurs.
+/// @return void
+///
+template< fapi2::TargetType T, typename TT = ccsTraits<T> >
+inline void stop_on_err( const fapi2::Target<T>&, fapi2::buffer<uint64_t>& i_buffer, bool i_value)
+{
+ i_buffer.writeBit<TT::STOP_ON_ERR>(i_value);
+}
+
+///
+/// @brief Disable ECC checking on the CCS arrays
+/// @tparam T, the fapi2::TargetType - derived
+/// @tparam TT, the ccsTraits associated with T - derived
+/// @param[in] the target to effect
+/// @param[in] the buffer representing the mode register
+/// @return void
+///
+template< fapi2::TargetType T, typename TT = ccsTraits<T> >
+inline void disable_ecc( const fapi2::Target<T>&, fapi2::buffer<uint64_t>& i_buffer)
+{
+ i_buffer.setBit<TT::DISABLE_ECC_ARRAY_CHK>();
+ i_buffer.setBit<TT::DISABLE_ECC_ARRAY_CORRECTION>();
+}
+
+///
+/// @brief User sets to a '1'b to force the Hdw to ignore any array ue or sue errors
+/// during CCS command fetching.
+/// @tparam T, the fapi2::TargetType - derived
+/// @tparam TT, the ccsTraits associated with T - derived
+/// @param[in] the target to effect
+/// @param[in] the buffer representing the mode register
+/// @param[in] i_value, true iff ignore any array ue or sue errors.
+/// @return void
+///
+template< fapi2::TargetType T, typename TT = ccsTraits<T> >
+inline void ue_disable( const fapi2::Target<T>&, fapi2::buffer<uint64_t>& i_buffer, bool i_value)
+{
+ i_buffer.writeBit<TT::UE_DISABLE>(i_value);
+}
+
+///
+/// @brief DDr calibration counter
+/// @tparam T, the fapi2::TargetType - derived
+/// @tparam TT, the ccsTraits associated with T - derived
+/// @param[in] the target to effect
+/// @param[in] the buffer representing the mode register
+/// @param[in] i_count, the count to wait for DDR cal to complete.
+/// @param[in] i_mult, the DDR calibration time multiplaction factor
+/// @return void
+///
+template< fapi2::TargetType T, typename TT = ccsTraits<T> >
+inline void cal_count( const fapi2::Target<T>&, fapi2::buffer<uint64_t>& i_buffer,
+ const uint64_t i_count, const uint64_t i_mult)
+{
+ i_buffer.insertFromRight<TT::DDR_CAL_TIMEOUT_CNT, TT::DDR_CAL_TIMEOUT_CNT_LEN>(i_count);
+ i_buffer.insertFromRight<TT::DDR_CAL_TIMEOUT_CNT_MULT, TT::DDR_CAL_TIMEOUT_CNT_MULT_LEN>(i_mult);
+}
+
+///
+/// @brief Copy CKE signals to CKE Spare on both ports NOTE: DOESN'T APPLY FOR NIMBUS. NO
+/// SPARE CHIPS TO COPY TO. 0 - Spare CKEs not copied with values from CKE(0:1) and
+/// CKE(4:5) 1 - Port A CKE(0:1) copied to Port A CKE(2:3), Port A CKE(4:5) copied
+/// to Port A CKE(6:7), Port B CKE(0:1) copied to Port B CKE(2:3) and Port B CKE(4:5)
+/// copied to Port B CKE(6:7)
+/// @tparam T, the fapi2::TargetType - derived
+/// @tparam TT, the ccsTraits associated with T - derived
+/// @param[in] the target to effect
+/// @param[in] the buffer representing the mode register
+/// @param[in] bool, true iff Copy CKE signals to CKE Spare on both ports
+/// @note no-op for p9n
+/// @return void
+///
+template< fapi2::TargetType T, typename TT = ccsTraits<T> >
+void copy_cke_to_spare_cke( const fapi2::Target<T>&, fapi2::buffer<uint64_t>& i_buffer, bool i_value);
+
+///
+/// @brief Read the modeq register appropriate for this target
+/// @tparam T, the fapi2::TargetType - derived
+/// @tparam TT, the ccsTraits associated with T - derived
+/// @param[in] the target to effect
+/// @param[in] the buffer representing the mode register
+/// @erturn FAPI2_RC_SUCCSS iff ok
+///
+template< fapi2::TargetType T, typename TT = ccsTraits<T> >
+inline fapi2::ReturnCode read_mode( const fapi2::Target<T>& i_target, fapi2::buffer<uint64_t>& i_buffer)
+{
+ FAPI_DBG("read mode 0x%llx", TT::MODEQ_REG);
+ return fapi2::getScom(i_target, TT::MODEQ_REG, i_buffer);
+}
+
+///
+/// @brief Write the modeq register appropriate for this target
+/// @tparam T, the fapi2::TargetType - derived
+/// @tparam TT, the ccsTraits associated with T - derived
+/// @param[in] the target to effect
+/// @param[in] the buffer representing the mode register
+/// @erturn FAPI2_RC_SUCCSS iff ok
+///
+template< fapi2::TargetType T, typename TT = ccsTraits<T> >
+inline fapi2::ReturnCode write_mode( const fapi2::Target<T>& i_target, const fapi2::buffer<uint64_t>& i_buffer)
+{
+ return fapi2::putScom(i_target, TT::MODEQ_REG, i_buffer);
+}
+
+///
+/// @brief Execute a set of CCS instructions - multiple ports
+/// @tparam T, the fapi2::TargetType - derived
+/// @tparam TT, the ccsTraits associated with T - derived
+/// @param[in] the target to effect
+/// @param[in] the vector of instructions
+/// @param[in] the vector of ports
+/// @erturn FAPI2_RC_SUCCSS iff ok
+///
+template< fapi2::TargetType T, fapi2::TargetType P, typename TT = ccsTraits<T> >
+fapi2::ReturnCode execute( const fapi2::Target<T>& i_target,
+ ccs::program<T>& i_program,
+ const std::vector< fapi2::Target<P> >& i_ports );
+
+///
+/// @brief Execute a set of CCS instructions - single port
+/// @tparam T, the fapi2::TargetType - derived
+/// @tparam TT, the ccsTraits associated with T - derived
+/// @param[in] the target to effect
+/// @param[in] the vector of instructions
+/// @param[in] the port
+/// @erturn FAPI2_RC_SUCCSS iff ok
+///
+template< fapi2::TargetType T, fapi2::TargetType P, typename TT = ccsTraits<T> >
+fapi2::ReturnCode execute( const fapi2::Target<T>& i_target,
+ ccs::program<T>& i_program,
+ const fapi2::Target<P>& i_port )
+{
+ // Mmm. Might want to find a better way to do this - seems expensive. BRS
+ std::vector< fapi2::Target<P> > l_ports{ i_port };
+ return execute(i_target, i_program, l_ports);
+}
+
+///
+/// @brief Execute a CCS array already loaded in to the engine
+/// @tparam T, the fapi2::TargetType - derived
+/// @tparam TT, the ccsTraits associated with T - derived
+/// @param[in] the target to effect
+/// @param[in] the MCBIST ccs program - to get the polling parameters
+/// @erturn FAPI2_RC_SUCCSS iff ok
+///
+template< fapi2::TargetType T, typename TT = ccsTraits<T> >
+fapi2::ReturnCode execute_inst_array(const fapi2::Target<T>& i_target, ccs::program<T>& i_program);
+///
+/// @brief Start or stop the CCS engine
+/// @param[in] i_target The MCBIST containing the CCS engine
+/// @param[in] i_start_stop bool MSS_CCS_START for starting,
+/// MSS_CCS_STOP otherwise
+/// @return FAPI2_RC_SUCCESS iff success
+///
+template< fapi2::TargetType T, typename TT = ccsTraits<T> >
+fapi2::ReturnCode start_stop( const fapi2::Target<T>& i_target, bool i_start_stop );
+
+///
+/// @brief Query the status of the CCS engine
+/// @param[in] i_target The MCBIST containing the CCS engine
+/// @param[out] The query result, first being the result, second the type
+/// @return FAPI2_RC_SUCCESS iff success
+///
+template< fapi2::TargetType T, typename TT = ccsTraits<T> >
+fapi2::ReturnCode status_query( const fapi2::Target<T>& i_target, std::pair<uint64_t, uint64_t>& io_status );
+
+} // ends namespace ccs
+}
+
+#endif
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/mrs_load.C b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/mrs_load.C
new file mode 100644
index 000000000..7b93ab7ac
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/mrs_load.C
@@ -0,0 +1,166 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/dimm/mrs_load.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 mrs_load.C
+/// @brief Run and manage the MRS_LOAD engine
+///
+// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
+// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
+// *HWP FW Owner: Bill Hoffa <wghoffa@us.ibm.com>
+// *HWP Team: Memory
+// *HWP Level: 1
+// *HWP Consumed by: FSP:HB
+
+#include <fapi2.H>
+
+#include "../mss.H"
+#include "mrs_load.H"
+#include "mrs_load_ddr4.H"
+
+using fapi2::TARGET_TYPE_MCBIST;
+using fapi2::TARGET_TYPE_DIMM;
+using fapi2::TARGET_TYPE_MCA;
+using fapi2::TARGET_TYPE_MCS;
+
+using fapi2::FAPI2_RC_SUCCESS;
+
+namespace mss
+{
+///
+/// @brief Perform the mrs_load operations - TARGET_TYPE_MCBIST specialization
+/// @param[in] i_target, a fapi2::Target<TARGET_TYPE_MCBIST>
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+template<>
+fapi2::ReturnCode mrs_load<TARGET_TYPE_MCBIST>( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target )
+{
+ // A vector of CCS instructions. We'll ask the targets to fill it, and then we'll execute it
+ ccs::program<TARGET_TYPE_MCBIST> l_program;
+
+ for (auto c : i_target.getChildren<TARGET_TYPE_MCS>())
+ {
+ for (auto p : c.getChildren<TARGET_TYPE_MCA>())
+ {
+ for (auto d : p.getChildren<TARGET_TYPE_DIMM>())
+ {
+ FAPI_DBG("mrs load for %s", mss::c_str(d));
+ FAPI_TRY( perform_mrs_load(d, l_program.iv_instructions) );
+ }
+
+ // We have to configure the CCS engine to let it know which port these instructions are
+ // going out (or whether it's broadcast ...) so lets execute the instructions we presently
+ // have so that we kind of do this by port
+ FAPI_TRY( ccs::execute(i_target, l_program, p) );
+ }
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Perform the mrs_load operations - unknown DIMM case
+/// @param[in] i_target, a fapi2::Target<TARGET_TYPE_DIMM>
+/// @param[in] a vector of CCS instructions we should add to (unused)
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+template<>
+fapi2::ReturnCode perform_mrs_load<DEFAULT_KIND>( const fapi2::Target<TARGET_TYPE_DIMM>& i_target,
+ std::vector< ccs::instruction_t<TARGET_TYPE_MCBIST> >& i_inst)
+{
+ uint8_t l_type = 0;
+ uint8_t l_gen = 0;
+
+ FAPI_TRY( mss::eff_dimm_type(i_target, l_type) );
+ FAPI_TRY( mss::eff_dram_gen(i_target, l_gen) );
+
+ // If we're here, we have a problem. The DIMM kind (type and/or generation) wasn't know
+ // to our dispatcher. We have a DIMM plugged in we don't know how to deal with.
+ FAPI_ASSERT(false,
+ fapi2::MSS_UNKNOWN_DIMM()
+ .set_DIMM_TYPE(l_type)
+ .set_DRAM_GEN(l_gen)
+ .set_DIMM_IN_ERROR(i_target),
+ "Unable to perform mrs load on %s: unknown type (%d) or generation (%d)",
+ mss::c_str(i_target), l_type, l_gen);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Perform the mrs_load operations - RDIMM DDR4
+/// @param[in] i_target, a fapi2::Target<TARGET_TYPE_DIMM>
+/// @param[in] a vector of CCS instructions we should add to
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+template<>
+fapi2::ReturnCode perform_mrs_load<KIND_RDIMM_DDR4>( const fapi2::Target<TARGET_TYPE_DIMM>& i_target,
+ std::vector< ccs::instruction_t<TARGET_TYPE_MCBIST> >& i_inst)
+{
+ FAPI_DBG("perform mrs_load for %s [expecting rdimm (ddr4)]", mss::c_str(i_target));
+ FAPI_TRY( mrs_load_ddr4(i_target, i_inst) );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Perform the mrs_load operations - LRDIMM DDR4
+/// @param[in] i_target, a fapi2::Target<TARGET_TYPE_DIMM>
+/// @param[in] a vector of CCS instructions we should add to
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+template<>
+fapi2::ReturnCode perform_mrs_load<KIND_LRDIMM_DDR4>( const fapi2::Target<TARGET_TYPE_DIMM>& i_target,
+ std::vector< ccs::instruction_t<TARGET_TYPE_MCBIST> >& i_inst)
+{
+ FAPI_DBG("perform mrs_load for %s [expecting lrdimm (ddr4)]", mss::c_str(i_target));
+ FAPI_TRY( mrs_load_ddr4(i_target, i_inst) );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+
+///
+/// @brief Perform the mrs_load operations - start the dispatcher
+/// @param[in] i_target, a fapi2::Target<TARGET_TYPE_DIMM>
+/// @param[in] a vector of CCS instructions we should add to
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+template<>
+fapi2::ReturnCode perform_mrs_load<FORCE_DISPATCH>( const fapi2::Target<TARGET_TYPE_DIMM>& i_target,
+ std::vector< ccs::instruction_t<TARGET_TYPE_MCBIST> >& i_inst)
+{
+ uint8_t l_type = 0;
+ uint8_t l_gen = 0;
+
+ FAPI_TRY( mss::eff_dimm_type(i_target, l_type) );
+ FAPI_TRY( mss::eff_dram_gen(i_target, l_gen) );
+
+ return perform_mrs_load_dispatch<FORCE_DISPATCH>(dimm_kind( l_type, l_gen ), i_target, i_inst);
+
+fapi_try_exit:
+ FAPI_ERR("couldn't get dimm type, dram gen: %s", mss::c_str(i_target));
+ return fapi2::current_err;
+}
+
+} // namespace
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/mrs_load.H b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/mrs_load.H
new file mode 100644
index 000000000..2f2f176d3
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/mrs_load.H
@@ -0,0 +1,184 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/dimm/mrs_load.H $ */
+/* */
+/* 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 mrs_load.H
+/// @brief Code to support mrs_loads
+///
+// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
+// *HWP HWP Backup: Craig Hamilton <cchamilt@us.ibm.com>
+// *HWP Team: Memory
+// *HWP Level: 2
+// *HWP Consumed by: HB:FSP
+
+#ifndef _MSS_MRS_LOAD_H_
+#define _MSS_MRS_LOAD_H_
+
+#include <fapi2.H>
+#include "../utils/c_str.H"
+#include <p9_mc_scom_addresses.H>
+
+#include "../shared/mss_kind.H"
+
+namespace mss
+{
+
+///
+/// @brief A structure to represent an MRS operation
+/// @tparam T, the target type of the CCS engine chiplet
+///
+template< fapi2::TargetType T >
+struct mrs_data
+{
+ // Which MRS# this is
+ fapi2::buffer<uint8_t> iv_mrs;
+
+ // The attribute getter. For MRS we pass in the ARR0 of the CCS instruction
+ // as that allows us to encapsulate the attribute processing and the bit
+ // manipulation in one function.
+ fapi2::ReturnCode (*iv_func)(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>&, ccs::instruction_t<T>&, const uint64_t);
+ fapi2::ReturnCode (*iv_dumper)(const ccs::instruction_t<T>&, const uint64_t);
+
+ // The delay needed after this MRS word is written
+ uint64_t iv_delay;
+
+ mrs_data( uint64_t i_mrs,
+ fapi2::ReturnCode (*i_func)(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>&, ccs::instruction_t<T>&, const uint64_t),
+ fapi2::ReturnCode (*i_dumper)(const ccs::instruction_t<T>&, const uint64_t),
+ uint64_t i_delay ):
+ iv_mrs(i_mrs),
+ iv_func(i_func),
+ iv_dumper(i_dumper),
+ iv_delay(i_delay)
+ {}
+};
+
+///
+/// @brief Perform the mrs_load operations
+/// @tparam T, the fapi2::TargetType of i_target
+/// @param[in] i_target, a fapi2::Target
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+template< fapi2::TargetType T >
+fapi2::ReturnCode mrs_load( const fapi2::Target<T>& i_target );
+
+
+//
+// Implement the polymorphism for mrs_load
+//
+
+// -# Register the API.
+/// -# Define the template parameters for the overloaded function
+/// @note the first argument is the api name, and the rest are the api's template parameters.
+/// @note this creates __api_name##_overload
+
+template< mss::kind_t K >
+struct perform_mrs_load_overload
+{
+ static const bool available = false;
+};
+
+/// -# Register the specific overloads. The first parameter is the name
+/// of the api, the second is the kind of the element which is being
+/// overloaded - an RDIMM, an LRDIMM, etc. The remaining parameters
+/// indicate the specialization of the api itself.
+/// @note You need to define the "DEFAULT_KIND" here as an overload. This
+/// allows the mechanism to find the "base" implementation for things which
+/// have no specific overload.
+template<>
+struct perform_mrs_load_overload< DEFAULT_KIND >
+{
+ static const bool available = true;
+};
+
+template<>
+struct perform_mrs_load_overload< KIND_RDIMM_DDR4 >
+{
+ static const bool available = true;
+};
+
+template<>
+struct perform_mrs_load_overload< KIND_LRDIMM_DDR4 >
+{
+ static const bool available = true;
+};
+
+///
+/// -# Define the default case for overloaded calls. enable_if states that
+/// if there is a DEFAULT_KIND overload for this TargetType, then this
+/// entry point will be defined. Note the general case below is enabled if
+/// there is no overload defined for this TargetType
+///
+
+///
+/// @brief Perform the mrs_load operations
+/// @tparam K, the kind of DIMM we're operating on (derived)
+/// @param[in] i_target, a fapi2::Target<fapi2::TARGET_TYPE_DIMM>
+/// @param[in] a vector of CCS instructions we should add to
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+template< mss::kind_t K = FORCE_DISPATCH >
+typename std::enable_if< perform_mrs_load_overload<DEFAULT_KIND>::available, fapi2::ReturnCode>::type
+perform_mrs_load( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ std::vector< ccs::instruction_t<fapi2::TARGET_TYPE_MCBIST> >& i_inst);
+
+//
+// We know we registered overloads for perform_mrs_load, so we need the entry point to
+// the dispatcher. Add a set of these for all TargetTypes which get overloads
+// for this API
+//
+template<>
+fapi2::ReturnCode perform_mrs_load<FORCE_DISPATCH>( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ std::vector< ccs::instruction_t<fapi2::TARGET_TYPE_MCBIST> >& i_inst);
+
+template<>
+fapi2::ReturnCode perform_mrs_load<DEFAULT_KIND>( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ std::vector< ccs::instruction_t<fapi2::TARGET_TYPE_MCBIST> >& i_inst);
+
+//
+// Boilerplate dispatcher
+//
+template< kind_t K, bool B = perform_mrs_load_overload<K>::available >
+inline fapi2::ReturnCode perform_mrs_load_dispatch( const kind_t& i_kind,
+ const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ std::vector< ccs::instruction_t<fapi2::TARGET_TYPE_MCBIST> >& i_inst)
+{
+ // We dispatch to another kind if:
+ // We don't have an overload defined (B == false)
+ // Or, if we do have an overload (B == true) and this is not out kind.
+ if ((B == false) || ((B == true) && (K != i_kind)))
+ {
+ return perform_mrs_load_dispatch < (kind_t)(K - 1) > (i_kind, i_target, i_inst);
+ }
+
+ // Otherwise, we call the overload.
+ return perform_mrs_load<K>(i_target, i_inst);
+}
+
+// DEFAULT_KIND is 0 so this is the end of the recursion
+template<>
+inline fapi2::ReturnCode perform_mrs_load_dispatch<DEFAULT_KIND>(const kind_t&,
+ const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ std::vector< ccs::instruction_t<fapi2::TARGET_TYPE_MCBIST> >& i_inst)
+{
+ return perform_mrs_load<DEFAULT_KIND>(i_target, i_inst);
+}
+
+}
+#endif
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/mrs_load_ddr4.C b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/mrs_load_ddr4.C
new file mode 100644
index 000000000..94d14cb96
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/mrs_load_ddr4.C
@@ -0,0 +1,844 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/dimm/mrs_load_ddr4.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 mrs_load_ddr4.C
+/// @brief Run and manage the DDR4 mrs loading
+///
+// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
+// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
+// *HWP FW Owner: Bill Hoffa <wghoffa@us.ibm.com>
+// *HWP Team: Memory
+// *HWP Level: 1
+// *HWP Consumed by: FSP:HB
+
+#include <fapi2.H>
+
+#include "../mss.H"
+#include "mrs_load_ddr4.H"
+
+using fapi2::TARGET_TYPE_MCBIST;
+using fapi2::TARGET_TYPE_DIMM;
+
+using fapi2::FAPI2_RC_SUCCESS;
+
+namespace mss
+{
+
+//
+// Each MRS has it's attributes encapsulated in it's little setter function.
+//
+
+///
+/// @brief Configure the ARR0 of the CCS isntruction for mrs00
+/// @param[in] i_target, a fapi2::Target<TARGET_TYPE_DIMM>
+/// @param[in,out] the instruction to fixup
+/// @param[in] ths rank in question
+/// @return FAPI2_RC_SUCCESS iff OK
+///
+static fapi2::ReturnCode ddr4_mrs00(const fapi2::Target<TARGET_TYPE_DIMM>& i_target,
+ ccs::instruction_t<TARGET_TYPE_MCBIST>& io_inst,
+ const uint64_t i_rank)
+{
+ // Map from Write Recovery attribute value to bits in the MRS.
+ // Bit 4 is A13, bits 5:7 are A11:A9
+ static const uint8_t wr_map[27] =
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0b0000, 0, 0b0001, 0, 0b0001, 0, 0b0011,
+ 0, 0b0100, 0, 0b0101, 0, 0b0111, 0, 0b0110, 0, 0b1000
+ };
+
+ // Map from the CAS Latency attribute to the bits in the MRS
+ static const uint8_t cl_map[34] =
+ {
+ // 0 1 2 3 4 5 6 7 8
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ // 9 10 11 12 13 14 15 16
+ 0b00000, 0b00001, 0b00010, 0b00011, 0b00100, 0b00101, 0b00110, 0b00111,
+ // 17, 18 19 20 21 22 23 24
+ 0b01101, 0b01000, 0b01110, 0b01001, 0b01111, 0b01010, 0b01100, 0b01011,
+ // 25 26 27 28 29 30 31 32 33
+ 0b10000, 0b10001, 0b10010, 0b10011, 0b10100, 0b10101, 0b10110, 0b10111, 0b11000
+ };
+
+ uint8_t l_burst_length = 0;
+ uint8_t l_read_burst_type = 0;
+ uint8_t l_dll_reset = 0;
+ uint8_t l_test_mode = 0;
+ uint8_t l_write_recovery = 0;
+ uint64_t l_cas_latency = 0;
+
+ fapi2::buffer<uint8_t> l_cl;
+ fapi2::buffer<uint8_t> l_wr;
+
+ FAPI_TRY( mss::eff_dram_burst_length(i_target, l_burst_length) );
+ FAPI_TRY( mss::eff_dram_read_burst_type(i_target, l_read_burst_type) );
+ FAPI_TRY( mss::eff_dram_cas_latency(i_target, l_cas_latency) );
+ FAPI_TRY( mss::eff_dram_dll_reset(i_target, l_dll_reset) );
+ FAPI_TRY( mss::eff_dram_tm(i_target, l_test_mode) );
+ FAPI_TRY( mss::eff_dram_write_recovery(i_target, l_write_recovery) );
+
+ FAPI_DBG("MR0 Attributes: BL: 0x%x, RBT: 0x%x, CL: 0x%x(0x%x), TM: 0x%x, DLL_RESET: 0x%x, WR: 0x%x(0x%x)",
+ l_burst_length, l_read_burst_type, l_cas_latency, cl_map[l_cas_latency],
+ l_test_mode, l_dll_reset, l_write_recovery, wr_map[l_write_recovery]);
+
+ io_inst.arr0.insertFromRight<A0, 2>(l_burst_length);
+ io_inst.arr0.writeBit<A3>(l_read_burst_type);
+ io_inst.arr0.writeBit<A7>(l_test_mode);
+ io_inst.arr0.writeBit<A8>(l_dll_reset);
+
+ // CAS Latency takes a little effort - the bits aren't contiguous
+ l_cl = cl_map[l_cas_latency];
+ io_inst.arr0.writeBit<A12>(l_cl.getBit<3>());
+ io_inst.arr0.writeBit<A6>(l_cl.getBit<4>());
+ io_inst.arr0.writeBit<A5>(l_cl.getBit<5>());
+ io_inst.arr0.writeBit<A4>(l_cl.getBit<6>());
+ io_inst.arr0.writeBit<A2>(l_cl.getBit<7>());
+
+ // Write Recovery/Read to Precharge is not contiguous either.
+ l_wr = wr_map[l_write_recovery];
+ io_inst.arr0.writeBit<A13>(l_wr.getBit<4>());
+ io_inst.arr0.writeBit<A11>(l_wr.getBit<5>());
+ io_inst.arr0.writeBit<A10>(l_wr.getBit<6>());
+ io_inst.arr0.writeBit<A9>(l_wr.getBit<7>());
+
+ FAPI_DBG("MR0: 0x%016llx", uint64_t(io_inst.arr0));
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Given a CCS instruction which contains address bits with an encoded MRS0,
+/// decode and trace the contents
+/// @param[in] i_inst, the CCS instruction
+/// @param[in] ths rank in question
+/// @return void
+///
+static fapi2::ReturnCode ddr4_mrs00_decode(const ccs::instruction_t<TARGET_TYPE_MCBIST>& i_inst,
+ const uint64_t i_rank)
+{
+ static const uint8_t wr_map[9] = { 10, 12, 14, 16, 18, 20, 24, 22, 26 };
+
+ uint8_t l_burst_length = 0;
+ uint8_t l_read_burst_type = 0;
+ uint8_t l_dll_reset = 0;
+ uint8_t l_test_mode = 0;
+
+ fapi2::buffer<uint8_t> l_wr_index;
+ fapi2::buffer<uint8_t> l_cas_latency;
+
+ i_inst.arr0.extractToRight<A0, 2>(l_burst_length);
+ l_read_burst_type = i_inst.arr0.getBit<A3>();
+ l_test_mode = i_inst.arr0.getBit<A7>();
+ l_dll_reset = i_inst.arr0.getBit<A8>();
+
+ // CAS Latency takes a little effort - the bits aren't contiguous
+ l_cas_latency.writeBit<3>(i_inst.arr0.getBit<A12>());
+ l_cas_latency.writeBit<4>(i_inst.arr0.getBit<A6>());
+ l_cas_latency.writeBit<5>(i_inst.arr0.getBit<A5>());
+ l_cas_latency.writeBit<6>(i_inst.arr0.getBit<A4>());
+ l_cas_latency.writeBit<7>(i_inst.arr0.getBit<A2>());
+
+ // Write Recovery/Read to Precharge is not contiguous either.
+ l_wr_index.writeBit<4>(i_inst.arr0.getBit<A13>());
+ l_wr_index.writeBit<5>(i_inst.arr0.getBit<A11>());
+ l_wr_index.writeBit<6>(i_inst.arr0.getBit<A10>());
+ l_wr_index.writeBit<7>(i_inst.arr0.getBit<A9>());
+
+ FAPI_DBG("MR0 Decode BL: 0x%x, RBT: 0x%x, CL: 0x%x, TM: 0x%x, DLL_RESET: 0x%x, WR: (0x%x)0x%x",
+ l_burst_length, l_read_burst_type, uint8_t(l_cas_latency), l_test_mode, l_dll_reset,
+ wr_map[uint8_t(l_wr_index)], uint8_t(l_wr_index));
+
+ return FAPI2_RC_SUCCESS;
+}
+
+///
+/// @brief Configure the ARR0 of the CCS isntruction for mrs01
+/// @param[in] i_target, a fapi2::Target<TARGET_TYPE_DIMM>
+/// @param[in,out] the instruction to fixup
+/// @param[in] ths rank in question
+/// @return FAPI2_RC_SUCCESS iff OK
+///
+static fapi2::ReturnCode ddr4_mrs01(const fapi2::Target<TARGET_TYPE_DIMM>& i_target,
+ ccs::instruction_t<TARGET_TYPE_MCBIST>& io_inst,
+ const uint64_t i_rank)
+{
+ // Little table to map Output Driver Imepdance Control. 34Ohm is index 0,
+ // 48Ohm is index 1 and we expect eff_config to make sure there's nothing
+ // else used here.
+ // Left bit is A2, right bit is A1
+ static const uint8_t odic_map[2] = { 0b00, 0b01 };
+
+ // Indexed by denominator. So, if RQZ is 240, and you have OHM240, then you're looking
+ // for index 1. So this doesn't correspond directly with the table in the JEDEC spec,
+ // as that's not in "denominator order."
+ // 0 RQZ/1 RQZ/2 RQZ/3 RQZ/4 RQZ/5 RQZ/6 RQZ/7
+ static const uint8_t rtt_nom_map[8] = { 0, 0b100, 0b010, 0b110, 0b001, 0b101, 0b011, 0b111 };
+
+ uint8_t l_dll_enable = 0;
+ uint8_t l_odic = 0;
+ uint8_t l_wl_enable = 0;
+ uint8_t l_tdqs = 0;
+ uint8_t l_qoff = 0;
+ uint8_t l_rtt_nom[MAX_RANK_PER_DIMM] = {0};
+
+ size_t l_rtt_nom_index = 0;
+
+ fapi2::buffer<uint8_t> l_additive_latency;
+ fapi2::buffer<uint8_t> l_odic_buffer;
+ fapi2::buffer<uint8_t> l_rtt_nom_buffer;
+
+ FAPI_TRY( mss::eff_dram_dll_enable(i_target, l_dll_enable) );
+ FAPI_TRY( mss::eff_dram_ron(i_target, l_odic) );
+ FAPI_TRY( mss::eff_dram_al(i_target, l_additive_latency) );
+ FAPI_TRY( mss::eff_dram_wr_lvl_enable(i_target, l_wl_enable) );
+ FAPI_TRY( mss::eff_dram_rtt_nom(i_target, &(l_rtt_nom[0])) );
+ FAPI_TRY( mss::eff_dram_tdqs(i_target, l_tdqs) );
+ FAPI_TRY( mss::eff_dram_output_buffer(i_target, l_qoff) );
+
+ // Map from impedance to bits in MRS1
+ l_odic_buffer = (l_odic == fapi2::ENUM_ATTR_EFF_DRAM_RON_OHM34) ? odic_map[0] : odic_map[1];
+
+ // We have to be careful about 0
+ l_rtt_nom_index = (l_rtt_nom[mss::index(i_rank)] == 0) ?
+ 0 : fapi2::ENUM_ATTR_EFF_DRAM_RTT_NOM_OHM240 / l_rtt_nom[mss::index(i_rank)];
+
+ // Map from RTT_NOM array to the value in the map
+ l_rtt_nom_buffer = rtt_nom_map[l_rtt_nom_index];
+
+ FAPI_INF("MR1 rank %d attributes: DLL_ENABLE: 0x%x, ODIC: 0x%x(0x%x), AL: 0x%x, WLE: 0x%x, "
+ "RTT_NOM: 0x%x(0x%x), TDQS: 0x%x, QOFF: 0x%x", i_rank,
+ l_dll_enable, l_odic, uint8_t(l_odic_buffer), uint8_t(l_additive_latency), l_wl_enable,
+ l_rtt_nom[mss::index(i_rank)], uint8_t(l_rtt_nom_buffer), l_tdqs, l_qoff);
+
+ io_inst.arr0.writeBit<A0>(l_dll_enable);
+ mss::swizzle<A1, 2, 7>(l_odic_buffer, io_inst.arr0);
+ mss::swizzle<A3, 2, 7>(l_additive_latency, io_inst.arr0);
+ io_inst.arr0.writeBit<A7>(l_wl_enable);
+ mss::swizzle<A8, 3, 7>(l_rtt_nom_buffer, io_inst.arr0);
+ io_inst.arr0.writeBit<A11>(l_tdqs);
+ io_inst.arr0.writeBit<A12>(l_qoff);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Given a CCS instruction which contains address bits with an encoded MRS1,
+/// decode and trace the contents
+/// @param[in] i_inst, the CCS instruction
+/// @param[in] ths rank in question
+/// @return void
+///
+static fapi2::ReturnCode ddr4_mrs01_decode(const ccs::instruction_t<TARGET_TYPE_MCBIST>& i_inst,
+ const uint64_t i_rank)
+{
+ fapi2::buffer<uint8_t> l_odic;
+ fapi2::buffer<uint8_t> l_additive_latency;
+ fapi2::buffer<uint8_t> l_rtt_nom;
+
+ uint8_t l_dll_enable = i_inst.arr0.getBit<A0>();
+ uint8_t l_wrl_enable = i_inst.arr0.getBit<A7>();
+ uint8_t l_tdqs = i_inst.arr0.getBit<A11>();
+ uint8_t l_qoff = i_inst.arr0.getBit<A12>();
+
+ mss::swizzle<6, 2, A2>(i_inst.arr0, l_odic);
+ mss::swizzle<6, 2, A4>(i_inst.arr0, l_additive_latency);
+ mss::swizzle<5, 3, A10>(i_inst.arr0, l_rtt_nom);
+
+ FAPI_INF("MR1 rank %d decode: DLL_ENABLE: 0x%x, ODIC: 0x%x, AL: 0x%x, WLE: 0x%x, "
+ "RTT_NOM: 0x%x, TDQS: 0x%x, QOFF: 0x%x", i_rank,
+ l_dll_enable, uint8_t(l_odic), uint8_t(l_additive_latency), l_wrl_enable, uint8_t(l_rtt_nom),
+ l_tdqs, l_qoff);
+
+ return FAPI2_RC_SUCCESS;
+}
+
+///
+/// @brief Given a uint32_t, which contains address bits with an encoded MRS1,
+/// decode and trace the contents
+/// @param[in] i_value, ADR 17:0
+/// @return void
+///
+fapi2::ReturnCode ddr4_mrs01_decode(const uint32_t i_value)
+{
+ fapi2::buffer<uint32_t> l_data(i_value);
+ // Flip l_data so bit 0 is bit 0, bit 17 is bit 17 ...
+ reverse(l_data);
+
+ fapi2::buffer<uint8_t> l_odic;
+ fapi2::buffer<uint8_t> l_additive_latency;
+ fapi2::buffer<uint8_t> l_rtt_nom;
+
+ uint8_t l_dll_enable = l_data.getBit<A0>();
+ uint8_t l_wrl_enable = l_data.getBit<A7>();
+ uint8_t l_tdqs = l_data.getBit<A11>();
+ uint8_t l_qoff = l_data.getBit<A12>();
+
+ mss::swizzle<6, 2, A2>(l_data, l_odic);
+ mss::swizzle<6, 2, A4>(l_data, l_additive_latency);
+ mss::swizzle<5, 3, A10>(l_data, l_rtt_nom);
+
+ FAPI_INF("MR1 buffer decode: DLL_ENABLE: 0x%x, ODIC: 0x%x, AL: 0x%x, WLE: 0x%x, "
+ "RTT_NOM: 0x%x, TDQS: 0x%x, QOFF: 0x%x",
+ l_dll_enable, uint8_t(l_odic), uint8_t(l_additive_latency), l_wrl_enable, uint8_t(l_rtt_nom),
+ l_tdqs, l_qoff);
+
+ return FAPI2_RC_SUCCESS;
+}
+
+///
+/// @brief Configure the ARR0 of the CCS isntruction for mrs02
+/// @param[in] i_target, a fapi2::Target<TARGET_TYPE_DIMM>
+/// @param[in,out] the instruction to fixup
+/// @param[in] ths rank in question
+/// @return FAPI2_RC_SUCCESS iff OK
+///
+static fapi2::ReturnCode ddr4_mrs02(const fapi2::Target<TARGET_TYPE_DIMM>& i_target,
+ ccs::instruction_t<TARGET_TYPE_MCBIST>& io_inst,
+ const uint64_t i_rank)
+{
+ // Index this by subtracting 9 from the CWL attribute value.
+ static const uint64_t LOWEST_CWL = 9;
+ // 9 10 11 12 14 16 18 20
+ static const uint8_t cwl_map[12] = { 0b000, 0b001, 0b010, 0b011, 0, 0b100, 0, 0b101, 0, 0b110, 0, 0b111 };
+
+ fapi2::buffer<uint8_t> l_lpasr;
+ uint8_t l_cwl = 0;
+ uint8_t l_dram_rtt_wr[MAX_RANK_PER_DIMM] = {0};
+ uint8_t l_write_crc = 0;
+
+ fapi2::buffer<uint8_t> l_cwl_buffer;
+ fapi2::buffer<uint8_t> l_rtt_wr_buffer;
+
+ FAPI_TRY( mss::eff_dram_lpasr(i_target, l_lpasr) );
+ FAPI_TRY( mss::eff_dram_cwl(i_target, l_cwl) );
+ FAPI_TRY( mss::eff_dram_rtt_wr(i_target, &(l_dram_rtt_wr[0])) );
+ FAPI_TRY( mss::eff_write_crc(i_target, l_write_crc) );
+
+ l_cwl_buffer = cwl_map[l_cwl - LOWEST_CWL];
+
+ // Arg. Change this. BRS
+ switch (l_dram_rtt_wr[i_rank])
+ {
+ case fapi2::ENUM_ATTR_EFF_DRAM_RTT_WR_DISABLE:
+ l_rtt_wr_buffer = 0b000;
+ break;
+
+ case fapi2::ENUM_ATTR_EFF_DRAM_RTT_WR_HIGHZ:
+ l_rtt_wr_buffer = 0b011;
+ break;
+
+ case fapi2::ENUM_ATTR_EFF_DRAM_RTT_WR_OHM240:
+ l_rtt_wr_buffer = 0b010;
+ break;
+
+ case fapi2::ENUM_ATTR_EFF_DRAM_RTT_WR_OHM120:
+ l_rtt_wr_buffer = 0b001;
+ break;
+
+ case fapi2::ENUM_ATTR_EFF_DRAM_RTT_WR_OHM60:
+ l_rtt_wr_buffer = 0b100;
+ break;
+
+ default:
+ FAPI_ERR("unknown RTT_WR 0x%x (%s rank %d), dynamic odt off",
+ l_dram_rtt_wr[i_rank], mss::c_str(i_target), i_rank);
+ l_rtt_wr_buffer = 0b000;
+ break;
+ };
+
+ FAPI_INF("MR2 rank %d attributes: LPASR: 0x%x, CWL: 0x%x(0x%x), RTT_WR: 0x%x(0x%x), WRITE_CRC: 0x%x", i_rank,
+ uint8_t(l_lpasr), l_cwl, uint8_t(l_cwl_buffer),
+ l_dram_rtt_wr[i_rank], uint8_t(l_rtt_wr_buffer), l_write_crc);
+
+ mss::swizzle<A3, 3, 7>(l_cwl_buffer, io_inst.arr0);
+
+ mss::swizzle<A6, 2, 7>(l_lpasr, io_inst.arr0);
+
+ mss::swizzle<A9, 3, 7>(l_rtt_wr_buffer, io_inst.arr0);
+
+ io_inst.arr0.writeBit<A12>(l_write_crc);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Given a CCS instruction which contains address bits with an encoded MRS2,
+/// decode and trace the contents
+/// @param[in] i_inst, the CCS instruction
+/// @param[in] ths rank in question
+/// @return void
+///
+static fapi2::ReturnCode ddr4_mrs02_decode(const ccs::instruction_t<TARGET_TYPE_MCBIST>& i_inst,
+ const uint64_t i_rank)
+{
+ fapi2::buffer<uint8_t> l_lpasr;
+ fapi2::buffer<uint8_t> l_cwl;
+ fapi2::buffer<uint8_t> l_rtt_wr;
+
+ uint8_t l_write_crc = i_inst.arr0.getBit<A12>();
+ mss::swizzle<5, 3, A5>(i_inst.arr0, l_cwl);
+ mss::swizzle<6, 2, A7>(i_inst.arr0, l_lpasr);
+ mss::swizzle<5, 3, A11>(i_inst.arr0, l_rtt_wr);
+
+ FAPI_INF("MR2 rank %d deocode: LPASR: 0x%x, CWL: 0x%x, RTT_WR: 0x%x, WRITE_CRC: 0x%x", i_rank,
+ uint8_t(l_lpasr), uint8_t(l_cwl), uint8_t(l_rtt_wr), l_write_crc);
+
+ return FAPI2_RC_SUCCESS;
+}
+
+///
+/// @brief Configure the ARR0 of the CCS isntruction for mrs03
+/// @param[in] i_target, a fapi2::Target<TARGET_TYPE_DIMM>
+/// @param[in,out] the instruction to fixup
+/// @param[in] ths rank in question
+/// @return FAPI2_RC_SUCCESS iff OK
+///
+static fapi2::ReturnCode ddr4_mrs03(const fapi2::Target<TARGET_TYPE_DIMM>& i_target,
+ ccs::instruction_t<TARGET_TYPE_MCBIST>& io_inst,
+ const uint64_t i_rank)
+{
+ // 4 5 6 R
+ static const uint8_t crc_wr_latency_map[8] = { 0, 0, 0, 0, 0, 1, 2, 3 };
+
+ uint8_t l_mpr_page = 0;
+ uint8_t l_geardown = 0;
+ uint8_t l_pda = 0;
+ uint8_t l_crc_wr_latency = 0;
+ uint8_t l_temp_readout = 0;
+
+ fapi2::buffer<uint8_t> l_mpr_mode;
+ fapi2::buffer<uint8_t> l_fine_refresh;
+ fapi2::buffer<uint8_t> l_crc_wr_latency_buffer;
+ fapi2::buffer<uint8_t> l_read_format;
+
+ FAPI_TRY( mss::eff_mpr_mode(i_target, l_mpr_mode) );
+ FAPI_TRY( mss::eff_mpr_page(i_target, l_mpr_page) );
+ FAPI_TRY( mss::eff_geardown_mode(i_target, l_geardown) );
+ FAPI_TRY( mss::eff_per_dram_access(i_target, l_pda) );
+ FAPI_TRY( mss::eff_temp_readout(i_target, l_temp_readout) );
+ FAPI_TRY( mss::eff_fine_refresh_mode(i_target, l_fine_refresh) );
+ FAPI_TRY( mss::eff_crc_wr_latency(i_target, l_crc_wr_latency) );
+ FAPI_TRY( mss::eff_mpr_rd_format(i_target, l_read_format) );
+
+ l_crc_wr_latency_buffer = crc_wr_latency_map[l_crc_wr_latency];
+
+ FAPI_INF("MR3 rank %d attributes: MPR_MODE: 0x%x, MPR_PAGE: 0x%x, GD: 0x%x, PDA: 0x%x, "
+ "TEMP: 0x%x FR: 0x%x, CRC_WL: 0x%x(0x%x), RF: 0x%x", i_rank,
+ uint8_t(l_mpr_mode), l_mpr_page, l_geardown, l_pda, l_temp_readout,
+ uint8_t(l_fine_refresh), l_crc_wr_latency, uint8_t(l_crc_wr_latency_buffer),
+ uint8_t(l_read_format));
+
+ mss::swizzle<A0, 2, 7>(l_mpr_mode, io_inst.arr0);
+ io_inst.arr0.writeBit<A2>(l_mpr_page);
+ io_inst.arr0.writeBit<A3>(l_geardown);
+ io_inst.arr0.writeBit<A4>(l_pda);
+ io_inst.arr0.writeBit<A5>(l_temp_readout);
+
+ mss::swizzle<A6 , 3, 7>(l_fine_refresh, io_inst.arr0);
+ mss::swizzle<A9 , 2, 7>(l_crc_wr_latency_buffer, io_inst.arr0);
+ mss::swizzle<A11, 2, 7>(l_read_format, io_inst.arr0);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Given a CCS instruction which contains address bits with an encoded MRS3,
+/// decode and trace the contents
+/// @param[in] i_inst, the CCS instruction
+/// @param[in] ths rank in question
+/// @return void
+///
+static fapi2::ReturnCode ddr4_mrs03_decode(const ccs::instruction_t<TARGET_TYPE_MCBIST>& i_inst,
+ const uint64_t i_rank)
+{
+ fapi2::buffer<uint8_t> l_mpr_mode;
+
+ fapi2::buffer<uint8_t> l_fine_refresh;
+ fapi2::buffer<uint8_t> l_crc_wr_latency_buffer;
+ fapi2::buffer<uint8_t> l_read_format;
+
+ uint8_t l_mpr_page = i_inst.arr0.getBit<A2>();
+ uint8_t l_geardown = i_inst.arr0.getBit<A3>();
+ uint8_t l_pda = i_inst.arr0.getBit<A4>();
+ uint8_t l_temp_readout = i_inst.arr0.getBit<A5>();
+
+ mss::swizzle<6, 2, A1>(i_inst.arr0, l_mpr_mode);
+ mss::swizzle<5, 3, A7>(i_inst.arr0, l_fine_refresh);
+ mss::swizzle<6, 2, A10>(i_inst.arr0, l_crc_wr_latency_buffer);
+ mss::swizzle<6, 2, A12>(i_inst.arr0, l_read_format);
+
+ FAPI_INF("MR3 rank %d decode: MPR_MODE: 0x%x, MPR_PAGE: 0x%x, GD: 0x%x, PDA: 0x%x, "
+ "TEMP: 0x%x FR: 0x%x, CRC_WL: 0x%x, RF: 0x%x", i_rank,
+ uint8_t(l_mpr_mode), l_mpr_page, l_geardown, l_pda, uint8_t(l_temp_readout),
+ uint8_t(l_fine_refresh), uint8_t(l_crc_wr_latency_buffer), uint8_t(l_read_format));
+
+ return FAPI2_RC_SUCCESS;
+}
+
+///
+/// @brief Configure the ARR0 of the CCS isntruction for mrs04
+/// @param[in] i_target, a fapi2::Target<TARGET_TYPE_DIMM>
+/// @param[in,out] the instruction to fixup
+/// @param[in] ths rank in question
+/// @return FAPI2_RC_SUCCESS iff OK
+///
+static fapi2::ReturnCode ddr4_mrs04(const fapi2::Target<TARGET_TYPE_DIMM>& i_target,
+ ccs::instruction_t<TARGET_TYPE_MCBIST>& io_inst,
+ const uint64_t i_rank)
+{
+ // 0 3 4 5 6 8
+ static const uint8_t cs_cmd_latency_map[9] = { 0b000, 0, 0, 0b001, 0b010, 0b011, 0b100, 0, 0b101 };
+
+ uint8_t l_max_pd_mode = 0;
+ uint8_t l_temp_ref_range = 0;
+ uint8_t l_temp_ref_mode = 0;
+ uint8_t l_vref_mon = 0;
+ uint8_t l_cs_cmd_latency = 0;
+ uint8_t l_ref_abort = 0;
+ uint8_t l_rd_pre_train_mode = 0;
+ uint8_t l_rd_preamble = 0;
+ uint8_t l_wr_preamble = 0;
+ uint8_t l_ppr = 0;
+
+ fapi2::buffer<uint8_t> l_cs_cmd_latency_buffer;
+
+ FAPI_TRY( mss::eff_max_powerdown_mode(i_target, l_max_pd_mode) );
+ FAPI_TRY( mss::eff_temp_ref_range(i_target, l_temp_ref_range) );
+ FAPI_TRY( mss::eff_temp_ref_mode(i_target, l_temp_ref_mode) );
+ FAPI_TRY( mss::eff_int_vref_mon(i_target, l_vref_mon) );
+ FAPI_TRY( mss::eff_cs_cmd_latency(i_target, l_cs_cmd_latency) );
+ FAPI_TRY( mss::eff_self_ref_abort(i_target, l_ref_abort) );
+ FAPI_TRY( mss::eff_rd_preamble_train(i_target, l_rd_pre_train_mode) );
+ FAPI_TRY( mss::eff_rd_preamble(i_target, l_rd_preamble) );
+ FAPI_TRY( mss::eff_wr_preamble(i_target, l_wr_preamble) );
+ FAPI_TRY( mss::eff_dram_ppr(i_target, l_ppr) );
+
+ l_cs_cmd_latency_buffer = cs_cmd_latency_map[l_cs_cmd_latency];
+
+ FAPI_INF("MR4 rank %d attributes: MAX_PD: 0x%x, TEMP_REF_RANGE: 0x%x, TEMP_REF_MODE: 0x%x "
+ "VREF_MON: 0x%x, CSL: 0x%x(0x%x), REF_ABORT: 0x%x, RD_PTM: 0x%x, RD_PRE: 0x%x, "
+ "WR_PRE: 0x%x, PPR: 0x%x", i_rank,
+ l_max_pd_mode, l_temp_ref_range, l_temp_ref_mode, l_vref_mon,
+ l_cs_cmd_latency, uint8_t(l_cs_cmd_latency_buffer), l_ref_abort,
+ l_rd_pre_train_mode, l_rd_preamble, l_wr_preamble, l_ppr);
+
+ io_inst.arr0.writeBit<A1>(l_max_pd_mode);
+ io_inst.arr0.writeBit<A2>(l_temp_ref_range);
+ io_inst.arr0.writeBit<A3>(l_temp_ref_mode);
+ io_inst.arr0.writeBit<A4>(l_vref_mon);
+
+ mss::swizzle<A6, 3, 7>(l_cs_cmd_latency_buffer, io_inst.arr0);
+ io_inst.arr0.writeBit<A9>(l_ref_abort);
+ io_inst.arr0.writeBit<A10>(l_rd_pre_train_mode);
+ io_inst.arr0.writeBit<A11>(l_rd_preamble);
+ io_inst.arr0.writeBit<A12>(l_wr_preamble);
+ io_inst.arr0.writeBit<A13>(l_ppr);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Given a CCS instruction which contains address bits with an encoded MRS4,
+/// decode and trace the contents
+/// @param[in] i_inst, the CCS instruction
+/// @param[in] ths rank in question
+/// @return void
+///
+static fapi2::ReturnCode ddr4_mrs04_decode(const ccs::instruction_t<TARGET_TYPE_MCBIST>& i_inst,
+ const uint64_t i_rank)
+{
+ uint8_t l_max_pd_mode = i_inst.arr0.getBit<A1>();
+ uint8_t l_temp_ref_range = i_inst.arr0.getBit<A2>();
+ uint8_t l_temp_ref_mode = i_inst.arr0.getBit<A3>();
+ uint8_t l_vref_mon = i_inst.arr0.getBit<A4>();
+
+ fapi2::buffer<uint8_t> l_cs_cmd_latency_buffer;
+ mss::swizzle<5, 3, A8>(i_inst.arr0, l_cs_cmd_latency_buffer);
+
+ uint8_t l_ref_abort = i_inst.arr0.getBit<A9>();
+ uint8_t l_rd_pre_train_mode = i_inst.arr0.getBit<A10>();
+ uint8_t l_rd_preamble = i_inst.arr0.getBit<A11>();
+ uint8_t l_wr_preamble = i_inst.arr0.getBit<A12>();
+ uint8_t l_ppr = i_inst.arr0.getBit<A13>();
+
+ FAPI_INF("MR4 rank %d decode: MAX_PD: 0x%x, TEMP_REF_RANGE: 0x%x, TEMP_REF_MODE: 0x%x "
+ "VREF_MON: 0x%x, CSL: 0x%x, REF_ABORT: 0x%x, RD_PTM: 0x%x, RD_PRE: 0x%x, "
+ "WR_PRE: 0x%x, PPR: 0x%x", i_rank,
+ l_max_pd_mode, l_temp_ref_range, l_temp_ref_mode, l_vref_mon,
+ uint8_t(l_cs_cmd_latency_buffer), l_ref_abort,
+ l_rd_pre_train_mode, l_rd_preamble, l_wr_preamble, l_ppr);
+
+ return FAPI2_RC_SUCCESS;
+}
+
+///
+/// @brief Configure the ARR0 of the CCS isntruction for mrs05
+/// @param[in] i_target, a fapi2::Target<TARGET_TYPE_DIMM>
+/// @param[in,out] the instruction to fixup
+/// @param[in] ths rank in question
+/// @return FAPI2_RC_SUCCESS iff OK
+///
+static fapi2::ReturnCode ddr4_mrs05(const fapi2::Target<TARGET_TYPE_DIMM>& i_target,
+ ccs::instruction_t<TARGET_TYPE_MCBIST>& io_inst,
+ const uint64_t i_rank)
+{
+ // 0 4 5 6 8
+ static const uint8_t ca_parity_latency_map[9] = { 0b000, 0, 0, 0, 0b001, 0b010, 0b011, 0, 0b100 };
+
+ // Indexed by denominator. So, if RQZ is 240, and you have OHM240, then you're looking
+ // for index 1. So this doesn't correspond directly with the table in the JEDEC spec,
+ // as that's not in "denominator order."
+ // 0 RQZ/1 RQZ/2 RQZ/3 RQZ/4 RQZ/5 RQZ/6 RQZ/7
+ static const uint8_t rtt_park_map[8] = { 0, 0b100, 0b010, 0b110, 0b001, 0b101, 0b011, 0b111 };
+
+ uint8_t l_ca_parity_latency = 0;
+ uint8_t l_crc_error_clear = 0;
+ uint8_t l_ca_parity_error_status = 0;
+ uint8_t l_odt_input_buffer = 0;
+ uint8_t l_rtt_park[MAX_RANK_PER_DIMM] = {0};
+ uint8_t l_ca_parity = 0;
+ uint8_t l_data_mask = 0;
+ uint8_t l_write_dbi = 0;
+ uint8_t l_read_dbi = 0;
+
+ uint8_t l_rtt_park_index = 0;
+
+ fapi2::buffer<uint8_t> l_ca_parity_latency_buffer;
+ fapi2::buffer<uint8_t> l_rtt_park_buffer;
+
+ FAPI_TRY( mss::eff_ca_parity_latency(i_target, l_ca_parity_latency) );
+ FAPI_TRY( mss::eff_crc_error_clear(i_target, l_crc_error_clear) );
+ FAPI_TRY( mss::eff_ca_parity_error_status(i_target, l_ca_parity_error_status) );
+ FAPI_TRY( mss::eff_odt_input_buff(i_target, l_odt_input_buffer) );
+
+ FAPI_TRY( mss::eff_rtt_park(i_target, &(l_rtt_park[0])) );
+
+ FAPI_TRY( mss::eff_ca_parity(i_target, l_ca_parity) );
+ FAPI_TRY( mss::eff_data_mask(i_target, l_data_mask) );
+ FAPI_TRY( mss::eff_write_dbi(i_target, l_write_dbi) );
+ FAPI_TRY( mss::eff_read_dbi(i_target, l_read_dbi) );
+
+ l_ca_parity_latency_buffer = ca_parity_latency_map[l_ca_parity_latency];
+
+ // We have to be careful about 0
+ l_rtt_park_index = (l_rtt_park[mss::index(i_rank)] == 0) ?
+ 0 : fapi2::ENUM_ATTR_EFF_RTT_PARK_240OHM / l_rtt_park[mss::index(i_rank)];
+
+ // Map from RTT_NOM array to the value in the map
+ l_rtt_park_buffer = rtt_park_map[l_rtt_park_index];
+
+ FAPI_INF("MR5 rank %d attributes: CAPL: 0x%x(0x%x), CRC_EC: 0x%x, CA_PES: 0x%x, ODT_IB: 0x%x "
+ "RTT_PARK: 0x%x(0x%x), CAP: 0x%x, DM: 0x%x, WDBI: 0x%x, RDBI: 0x%x", i_rank,
+ l_ca_parity_latency, uint8_t(l_ca_parity_latency_buffer), l_crc_error_clear,
+ l_ca_parity_error_status, l_odt_input_buffer,
+ l_rtt_park[mss::index(i_rank)], uint8_t(l_rtt_park_buffer), l_ca_parity,
+ l_data_mask, l_write_dbi, l_read_dbi);
+
+ mss::swizzle<A0, 3, 7>(l_ca_parity_latency_buffer, io_inst.arr0);
+ io_inst.arr0.writeBit<A3>(l_crc_error_clear);
+ io_inst.arr0.writeBit<A4>(l_ca_parity_error_status);
+ io_inst.arr0.writeBit<A5>(l_odt_input_buffer);
+ mss::swizzle<A6, 3, 7>(l_rtt_park_buffer, io_inst.arr0);
+ io_inst.arr0.writeBit<A9>(l_ca_parity);
+ io_inst.arr0.writeBit<A10>(l_data_mask);
+ io_inst.arr0.writeBit<A11>(l_write_dbi);
+ io_inst.arr0.writeBit<A12>(l_read_dbi);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Given a CCS instruction which contains address bits with an encoded MRS5,
+/// decode and trace the contents
+/// @param[in] i_inst, the CCS instruction
+/// @param[in] ths rank in question
+/// @return void
+///
+static fapi2::ReturnCode ddr4_mrs05_decode(const ccs::instruction_t<TARGET_TYPE_MCBIST>& i_inst,
+ const uint64_t i_rank)
+{
+ fapi2::buffer<uint8_t> l_ca_parity_latency_buffer;
+ fapi2::buffer<uint8_t> l_rtt_park_buffer;
+
+ mss::swizzle<5, 3, A2>(i_inst.arr0, l_ca_parity_latency_buffer);
+ mss::swizzle<5, 3, A8>(i_inst.arr0, l_rtt_park_buffer);
+
+ uint8_t l_crc_error_clear = i_inst.arr0.getBit<A3>();
+ uint8_t l_ca_parity_error_status = i_inst.arr0.getBit<A4>();
+ uint8_t l_odt_input_buffer = i_inst.arr0.getBit<A5>();
+
+ uint8_t l_ca_parity = i_inst.arr0.getBit<A9>();
+ uint8_t l_data_mask = i_inst.arr0.getBit<A10>();
+ uint8_t l_write_dbi = i_inst.arr0.getBit<A11>();
+ uint8_t l_read_dbi = i_inst.arr0.getBit<A12>();
+
+ FAPI_INF("MR5 rank %d decode: CAPL: 0x%x, CRC_EC: 0x%x, CA_PES: 0x%x, ODT_IB: 0x%x "
+ "RTT_PARK: 0x%x, CAP: 0x%x, DM: 0x%x, WDBI: 0x%x, RDBI: 0x%x", i_rank,
+ uint8_t(l_ca_parity_latency_buffer), l_crc_error_clear, l_ca_parity_error_status,
+ l_odt_input_buffer, uint8_t(l_rtt_park_buffer), l_ca_parity, l_data_mask,
+ l_write_dbi, l_read_dbi);
+
+ return FAPI2_RC_SUCCESS;
+}
+
+///
+/// @brief Configure the ARR0 of the CCS isntruction for mrs06
+/// @param[in] i_target, a fapi2::Target<TARGET_TYPE_DIMM>
+/// @param[in,out] the instruction to fixup
+/// @param[in] ths rank in question
+/// @return FAPI2_RC_SUCCESS iff OK
+///
+static fapi2::ReturnCode ddr4_mrs06(const fapi2::Target<TARGET_TYPE_DIMM>& i_target,
+ ccs::instruction_t<TARGET_TYPE_MCBIST>& io_inst,
+ const uint64_t i_rank)
+{
+ // 4 5 6 7 8
+ static const uint8_t tccd_l_map[9] = { 0, 0, 0, 0, 0b000, 0b001, 0b010, 0b011, 0b100 };
+
+ uint8_t l_vrefdq_train_value[MAX_RANK_PER_DIMM] = {0};
+ uint8_t l_vrefdq_train_range[MAX_RANK_PER_DIMM] = {0};
+ uint8_t l_vrefdq_train_enable[MAX_RANK_PER_DIMM] = {0};
+ uint8_t l_tccd_l = 0;
+
+ fapi2::buffer<uint8_t> l_tccd_l_buffer;
+ fapi2::buffer<uint8_t> l_vrefdq_train_value_buffer;
+
+ FAPI_TRY( mss::vref_dq_train_value(i_target, l_vrefdq_train_value) );
+ FAPI_TRY( mss::vref_dq_train_range(i_target, l_vrefdq_train_range) );
+ FAPI_TRY( mss::vref_dq_train_enable(i_target, l_vrefdq_train_enable) );
+ FAPI_TRY( mss::tccd_l(i_target, l_tccd_l) );
+
+ l_tccd_l_buffer = tccd_l_map[l_tccd_l];
+ l_vrefdq_train_value_buffer = l_vrefdq_train_value[mss::index(i_rank)];
+
+ FAPI_INF("MR6 rank %d attributes: TRAIN_V: 0x%x(0x%x), TRAIN_R: 0x%x, TRAIN_E: 0x%x, TCCD_L: 0x%x(0x%x)", i_rank,
+ l_vrefdq_train_value[mss::index(i_rank)], uint8_t(l_vrefdq_train_value_buffer),
+ l_vrefdq_train_range[mss::index(i_rank)],
+ l_vrefdq_train_enable[mss::index(i_rank)], l_tccd_l, uint8_t(l_tccd_l_buffer));
+
+ mss::swizzle<A0, 6, 7>(l_vrefdq_train_value_buffer, io_inst.arr0);
+ io_inst.arr0.writeBit<A6>(l_vrefdq_train_range[mss::index(i_rank)]);
+ io_inst.arr0.writeBit<A7>(l_vrefdq_train_enable[mss::index(i_rank)]);
+ mss::swizzle<A10, 3, 7>(l_tccd_l_buffer, io_inst.arr0);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Given a CCS instruction which contains address bits with an encoded MRS6,
+/// decode and trace the contents
+/// @param[in] i_inst, the CCS instruction
+/// @param[in] ths rank in question
+/// @return void
+///
+static fapi2::ReturnCode ddr4_mrs06_decode(const ccs::instruction_t<TARGET_TYPE_MCBIST>& i_inst,
+ const uint64_t i_rank)
+{
+ fapi2::buffer<uint8_t> l_tccd_l_buffer;
+ fapi2::buffer<uint8_t> l_vrefdq_train_value_buffer;
+
+ mss::swizzle<2, 6, A5>(i_inst.arr0, l_vrefdq_train_value_buffer);
+ uint8_t l_vrefdq_train_range = i_inst.arr0.getBit<A6>();
+ uint8_t l_vrefdq_train_enable = i_inst.arr0.getBit<A7>();
+ mss::swizzle<5, 3, A12>(i_inst.arr0, l_tccd_l_buffer);
+
+ FAPI_INF("MR6 rank %d decode: TRAIN_V: 0x%x, TRAIN_R: 0x%x, TRAIN_E: 0x%x, TCCD_L: 0x%x", i_rank,
+ uint8_t(l_vrefdq_train_value_buffer), l_vrefdq_train_range,
+ l_vrefdq_train_enable, uint8_t(l_tccd_l_buffer));
+
+ return FAPI2_RC_SUCCESS;
+}
+
+///
+/// @brief Perform the mrs_load_ddr4 operations - TARGET_TYPE_DIMM specialization
+/// @param[in] i_target, a fapi2::Target<TARGET_TYPE_DIMM>
+/// @param[in] a vector of CCS instructions we should add to
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+fapi2::ReturnCode mrs_load_ddr4( const fapi2::Target<TARGET_TYPE_DIMM>& i_target,
+ std::vector< ccs::instruction_t<TARGET_TYPE_MCBIST> >& i_inst)
+{
+ FAPI_INF("mrs_load_ddr4 %s", mss::c_str(i_target));
+
+ // Per DDR4MRS02 table 104 - timing requirements
+ static const uint64_t tMRD = 8;
+
+ static std::vector< mrs_data<TARGET_TYPE_MCBIST> > l_mrs_data =
+ {
+ { 0, ddr4_mrs00, ddr4_mrs00_decode, tMRD }, { 1, ddr4_mrs01, ddr4_mrs01_decode, tMRD },
+ { 2, ddr4_mrs02, ddr4_mrs02_decode, tMRD }, { 3, ddr4_mrs03, ddr4_mrs03_decode, tMRD },
+ { 4, ddr4_mrs04, ddr4_mrs04_decode, tMRD }, { 5, ddr4_mrs05, ddr4_mrs05_decode, tMRD },
+ { 6, ddr4_mrs06, ddr4_mrs06_decode, tMRD },
+ };
+
+ std::vector< uint64_t > l_ranks;
+ FAPI_TRY( mss::ranks(i_target, l_ranks) );
+
+ for (auto d : l_mrs_data)
+ {
+ for (auto r : l_ranks)
+ {
+ // Note: this isn't general - assumes Nimbus via MCBIST instruction here BRS
+ ccs::instruction_t<TARGET_TYPE_MCBIST> l_inst_a_side = ccs::mrs_command<TARGET_TYPE_MCBIST>(i_target, r, d.iv_mrs);
+ ccs::instruction_t<TARGET_TYPE_MCBIST> l_inst_b_side;
+
+ // Thou shalt send 2 MRS, one for the a-side and the other inverted for the b-side.
+ // If we're on an odd-rank then we need to mirror
+ // So configure the A-side, mirror if necessary and invert for the B-side
+ FAPI_TRY( d.iv_func(i_target, l_inst_a_side, r) );
+
+ FAPI_TRY( mss::address_mirror(i_target, r, l_inst_a_side) );
+ l_inst_b_side = mss::address_invert(l_inst_a_side);
+
+ // Not sure if we can get tricky here and only delay after the b-side MR. The question is whether the delay
+ // is needed/assumed by the register or is purely a DRAM mandated delay. We know we can't go wrong having
+ // both delays but if we can ever confirm that we only need one we can fix this. BRS
+ l_inst_a_side.arr1.insertFromRight<MCBIST_CCS_INST_ARR1_00_IDLES, MCBIST_CCS_INST_ARR1_00_IDLES_LEN>(d.iv_delay);
+ l_inst_b_side.arr1.insertFromRight<MCBIST_CCS_INST_ARR1_00_IDLES, MCBIST_CCS_INST_ARR1_00_IDLES_LEN>(d.iv_delay);
+
+ // Dump out the 'decoded' MRS and trace the CCS instructions.
+ if (d.iv_dumper != NULL)
+ {
+ FAPI_TRY( d.iv_dumper(l_inst_a_side, r) );
+ }
+
+ FAPI_INF("MRS%02d (%d) 0x%016llx:0x%016llx %s:rank %d a-side", uint8_t(d.iv_mrs), d.iv_delay,
+ l_inst_a_side.arr0, l_inst_a_side.arr1, mss::c_str(i_target), r);
+ FAPI_INF("MRS%02d (%d) 0x%016llx:0x%016llx %s:rank %d b-side", uint8_t(d.iv_mrs), d.iv_delay,
+ l_inst_b_side.arr0, l_inst_b_side.arr1, mss::c_str(i_target), r);
+
+ // Add both to the CCS program
+ i_inst.push_back(l_inst_a_side);
+ i_inst.push_back(l_inst_b_side);
+ }
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+} // namespace
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/mrs_load_ddr4.H b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/mrs_load_ddr4.H
new file mode 100644
index 000000000..ea11517f6
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/mrs_load_ddr4.H
@@ -0,0 +1,157 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/dimm/mrs_load_ddr4.H $ */
+/* */
+/* 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 mrs_load_ddr4.H
+/// @brief Code to support mrs_load_ddr4
+///
+// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
+// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
+// *HWP FW Owner: Bill Hoffa <wghoffa@us.ibm.com>
+// *HWP Team: Memory
+// *HWP Level: 1
+// *HWP Consumed by: HB:FSP
+
+#ifndef _MSS_MRS_LOAD_DDR4_H_
+#define _MSS_MRS_LOAD_DDR4_H_
+
+#include <fapi2.H>
+#include "../mss.H"
+
+namespace mss
+{
+
+// Map bits in the ARR0 register(s) to MRS address bits. Should be traits related to ARR0. BRS
+enum address_bits
+{
+ A0 = 0,
+ A1 = 1,
+ A2 = 2,
+ A3 = 3,
+ A4 = 4,
+ A5 = 5,
+ A6 = 6,
+ A7 = 7,
+ A8 = 8,
+ A9 = 9,
+ A10 = 10,
+ A11 = 11,
+ A12 = 12,
+ A13 = 13,
+ A14 = MCBIST_CCS_INST_ARR0_00_DDR_ADDRESS_14,
+ A15 = MCBIST_CCS_INST_ARR0_00_DDR_ADDRESS_15,
+ A16 = MCBIST_CCS_INST_ARR0_00_DDR_ADDRESS_16,
+ A17 = MCBIST_CCS_INST_ARR0_00_DDR_ADDRESS_17,
+
+ // Only kind of address bits ... <shrug>
+ BA0 = 17,
+ BA1 = 18,
+ BG0 = 19,
+ BG1 = 15,
+};
+
+///
+/// @brief Perform the mrs_load_ddr4 operations - TARGET_TYPE_DIMM specialization
+/// @param[in] i_target, a fapi2::Target<TARGET_TYPE_DIMM>
+/// @param[in] a vector of CCS instructions we should add to
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+fapi2::ReturnCode mrs_load_ddr4( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ std::vector< ccs::instruction_t<fapi2::TARGET_TYPE_MCBIST> >& i_inst);
+
+///
+/// @brief Mirror (front to back) the ADR bits of a CCS instruction - implementation
+/// @tparam T, typename of the ccs::instruction_t
+/// @param[in, out] io_inst, reference to a CCS instruction to be mirrored
+/// @return FAPI2_RC_SUCESS iff ok
+/// @note written this way so this is easier to test
+///
+template<fapi2::TargetType T>
+void address_mirror_impl(ccs::instruction_t<T>& io_inst)
+{
+ // Nothing fancy here, just mirror the bits we're told to mirror in Table 14 — Address Mirroring and Inversion
+ mss::template swap<A3, A4>(io_inst.arr0);
+ mss::template swap<A5, A6>(io_inst.arr0);
+ mss::template swap<A7, A8>(io_inst.arr0);
+ mss::template swap<A11, A13>(io_inst.arr0);
+ mss::template swap<BA0, BA1>(io_inst.arr0);
+ mss::template swap<BG0, BG1>(io_inst.arr0);
+}
+
+///
+/// @brief Mirror (front to back) the ADR bits of a CCS instruction
+/// @tparam T, typename of the ccs::instruction_t
+/// @param[in] i_target, target to use to get mirroring attribute
+/// @param[in] i_rank, the rank in question
+/// @param[in, out] io_inst, reference to a CCS instruction to be mirrored
+/// @return FAPI2_RC_SUCESS iff ok
+/// @note assumes the input is from an even number rank
+///
+template<fapi2::TargetType T>
+fapi2::ReturnCode address_mirror(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ const uint64_t i_rank, ccs::instruction_t<T>& io_inst)
+{
+ // We only mirror if the mirroring attribute is set.
+ uint8_t l_mirror = 0;
+ FAPI_TRY( eff_dimm_rcd_mirror_mode(i_target, l_mirror) );
+
+ // We only mirror odd ranks.
+ if ((l_mirror == fapi2::ENUM_ATTR_EFF_DIMM_RCD_MIRROR_MODE_ON) && (i_rank & 0x1))
+ {
+ address_mirror_impl(io_inst);
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Invert (side to side) the ADR bits of a CCS instruction
+/// @param[in] i_inst, const reference to a CCS instruction.
+/// @return[out] ccs instruction with the ADR bits inverted (side-to-side)
+///
+template<fapi2::TargetType T>
+ccs::instruction_t<T> address_invert(const ccs::instruction_t<T>& i_inst)
+{
+ // Copy the input as the output doesn't all change.
+ ccs::instruction_t<T> i_out(i_inst);
+
+ // Nothing fancy here, just negate the bits we're told to negate in Table 14 — Address Mirroring and Inversion
+ mss::template negate<A3>(i_out.arr0);
+ mss::template negate<A4>(i_out.arr0);
+ mss::template negate<A5>(i_out.arr0);
+ mss::template negate<A6>(i_out.arr0);
+ mss::template negate<A7>(i_out.arr0);
+ mss::template negate<A8>(i_out.arr0);
+ mss::template negate<A9>(i_out.arr0);
+
+ mss::template negate<A11>(i_out.arr0);
+ mss::template negate<A13>(i_out.arr0);
+ mss::template negate<A17>(i_out.arr0);
+
+ mss::template negate<BA0>(i_out.arr0);
+ mss::template negate<BA1>(i_out.arr0);
+ mss::template negate<BG0>(i_out.arr0);
+ mss::template negate<BG1>(i_out.arr0);
+
+ return i_out;
+}
+
+} // namespace
+#endif
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rank.C b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rank.C
new file mode 100644
index 000000000..8a618b813
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rank.C
@@ -0,0 +1,320 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/dimm/rank.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 rank.C
+/// @brief Manage dIMM ranks
+///
+// *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"
+
+using fapi2::TARGET_TYPE_MCA;
+using fapi2::TARGET_TYPE_DIMM;
+
+namespace mss
+{
+
+//
+// Static table of rank pair assignments. Some of thoem won't be valid depending on
+// the plug rules (which may be OpenPOWER, IBM, etc.) Some also won't make sense
+// -- 3 rank DIMM? -- but it doesn't take up much space and lord knows stranger things
+// have happened ... Won't hurt to have this defined JustInCase(tm).
+// Index by [DIMM1 rank count][DIMM0 rank count] and first is the RANK_PAIR0 register,
+// second is RANK_PAIR1.
+//
+static const std::vector< std::vector< std::pair< uint64_t, uint64_t > > > rank_pair_assignments =
+{
+ { {0x0000, 0x0000}, {0x1000, 0x0000}, {0x1030, 0x0000}, {0x1030, 0x5000}, {0x1030, 0x5070} },
+ { {0x9000, 0x0000}, {0x1090, 0x0000}, {0x1090, 0x3000}, {0x1090, 0x3050}, {0x1090, 0x5730} },
+ { {0x90B0, 0x0000}, {0x1090, 0xB000}, {0x1090, 0x30B0}, {0x1390, 0x50B0}, {0x1390, 0x57B0} },
+ { {0x90B0, 0xD000}, {0x1090, 0xB0D0}, {0x109B, 0x30D0}, {0x139B, 0x50D0}, {0x139B, 0x57D0} },
+ { {0x90B0, 0xD0F0}, {0x1090, 0xB0DF}, {0x109B, 0x30DF}, {0x139B, 0x50DF}, {0x139B, 0x57DF} },
+};
+
+//
+// Static table of vectors representing the master ranks, depending on the rank pair
+// config. This table maps 1-1 to the table above, and allows us to skip the bit manipulation
+// to figure out the master ranks. Note, no ranks means an empty vector ...
+//
+static const std::vector< std::vector< std::vector< uint64_t > > > primary_rank_pairs =
+{
+ { {}, {0}, {0, 1}, {0, 1, 2}, {0, 1, 2, 3} },
+ { {4}, {0, 4}, {0, 4, 1}, {0, 4, 2, 1}, {0, 4, 2, 1} },
+ { {4, 5}, {0, 4, 5}, {0, 4, 1, 5}, {0, 4, 2, 5}, {0, 4, 2, 5} },
+ { {4, 5}, {0, 4, 5}, {0, 4, 1, 5}, {0, 4, 2, 5}, {0, 4, 2, 5} },
+ { {4, 5, 6, 7}, {0, 4, 5, 6}, {0, 4, 1, 6}, {0, 4, 2, 6}, {0, 4, 2, 6} },
+};
+
+//
+// Static table of vectors representing ranks on a single DIMM
+// Note: std::vector< uint64_t > v = single_dimm_ranks[mss::index(dimm)][ranks on dimm];
+//
+static const std::vector< std::vector< std::vector< uint64_t > > > single_dimm_ranks =
+{
+ { {}, {0}, {0, 1}, {0, 1, 2}, {0, 1, 2, 3} },
+ { {}, {4}, {4, 5}, {4, 5, 6}, {4, 5, 6, 7} },
+};
+
+///
+/// @brief Return true iff this rank is on thie DIMM
+/// @param[in] i_target representing the DIMM
+/// @param[in] i_rank, the rank number.
+/// @return true iff i_rank is a rank on i_target
+///
+bool is_rank_on_dimm(const fapi2::Target<TARGET_TYPE_DIMM>& i_target, const uint64_t i_rank)
+{
+ // DIMM[0] has ranks 0:3, DIMM[1] has ranks 4:7 - if there are not 4 ranks
+ // on a DIMM, there are holes. That is, the first rank on DIMM[1] is always
+ // rank #4.
+
+ if (i_rank > 7)
+ {
+ FAPI_ERR("seeing rank %d? %s", i_rank, mss::c_str(i_target));
+ return false;
+ }
+
+ if ((i_rank < RANK_MID_POINT) && (mss::index(i_target) == 0))
+ {
+ return true;
+ }
+
+ if ((i_rank >= RANK_MID_POINT) && (mss::index(i_target) == 1))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+///
+/// @brief Return the *port relative position* of the DIMM which posesses this rank
+/// @param[in] i_rank, the rank number.
+/// @return the relative position of the DIMM which contains this rank.
+///
+size_t get_dimm_from_rank(const uint64_t i_rank)
+{
+ // DIMM[0] has ranks 0:3, DIMM[1] has ranks 4:7 - if there are not 4 ranks
+ // on a DIMM, there are holes. That is, the first rank on DIMM[1] is always
+ // rank #4.
+
+ if (i_rank > 7)
+ {
+ FAPI_ERR("seeing rank %d?", i_rank);
+ fapi2::Assert(false);
+ }
+
+ return (i_rank < RANK_MID_POINT) ? 0 : 1;
+}
+
+///
+/// @brief Return a vector of rank numbers which represent the primary rank pairs for this dimm
+/// @tparam T, the target type
+/// @param[in] TARGET_TYPE_MCA
+/// @param[out] a vector of rank_pairs
+/// @return FAPI2_RC_SUCCESS iff all is ok
+///
+template<>
+fapi2::ReturnCode primary_ranks( const fapi2::Target<TARGET_TYPE_MCA>& i_target, std::vector< uint64_t >& o_rps )
+{
+ FAPI_INF("get the primary ranks for %s", mss::c_str(i_target));
+
+ // Get the count of rank pairs for both DIMM on the port
+ std::vector<uint8_t> l_rank_count(MAX_DIMM_PER_PORT, 0);
+
+ for (auto d : i_target.getChildren<TARGET_TYPE_DIMM>())
+ {
+ FAPI_TRY( mss::eff_num_ranks_per_dimm(d, l_rank_count[mss::index(d)]) );
+ }
+
+ o_rps = primary_rank_pairs[l_rank_count[1]][l_rank_count[0]];
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Return a vector of rank numbers which represent the primary rank pairs for this dimm
+/// @tparam T, the target type
+/// @param[in] TARGET_TYPE_DIMM
+/// @param[out] a vector of rank_pairs
+/// @return FAPI2_RC_SUCCESS iff all is ok
+///
+template<>
+fapi2::ReturnCode primary_ranks( const fapi2::Target<TARGET_TYPE_DIMM>& i_target, std::vector< uint64_t >& o_rps )
+{
+ FAPI_INF("get the primary ranks for %s", mss::c_str(i_target));
+
+ std::vector< uint64_t > l_prs;
+ FAPI_TRY( primary_ranks(i_target.getParent<TARGET_TYPE_MCA>(), l_prs) );
+
+ o_rps.clear();
+
+ for (auto r : l_prs)
+ {
+ if (is_rank_on_dimm(i_target, r))
+ {
+ o_rps.push_back(r);
+ }
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Return a vector of rank numbers which represent the ranks for this dimm
+/// @param[in] i_target, TARGET_TYPE_DIMM
+/// @param[out] o_ranks, a vector of ranks (numbers)
+/// @return FAPI2_RC_SUCCESS iff all is ok
+///
+template<>
+fapi2::ReturnCode ranks( const fapi2::Target<TARGET_TYPE_DIMM>& i_target, std::vector< uint64_t >& o_ranks )
+{
+ uint8_t l_ranks;
+ FAPI_TRY( eff_num_ranks_per_dimm(i_target, l_ranks) );
+
+ o_ranks = single_dimm_ranks[mss::index(i_target)][l_ranks];
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Return a vector of rank numbers which represent the ranks for this dimm
+/// @param[in] i_target, TARGET_TYPE_MCA
+/// @param[out] o_ranks, a vector of ranks (numbers)
+/// @return FAPI2_RC_SUCCESS iff all is ok
+///
+template<>
+fapi2::ReturnCode ranks( const fapi2::Target<TARGET_TYPE_MCA>& i_target, std::vector< uint64_t >& o_ranks )
+{
+ // Note: Isn't there a better way to do this?
+ std::vector< uint64_t > l_ranks;
+ o_ranks.clear();
+
+ for (auto d : i_target.getChildren<TARGET_TYPE_DIMM>())
+ {
+ FAPI_TRY( ranks(d, l_ranks) );
+ o_ranks.insert(o_ranks.end(), l_ranks.begin(), l_ranks.end());
+ }
+
+ // Lets make sure the ranks are in order - we don't know if the child vector is in position
+ // order, but its easy to get the ranks in order by sorting them.
+ std::sort(o_ranks.begin(), o_ranks.end());
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Setup the rank information in the port
+/// @tparam T the fapi2::TargetType
+/// @param[in] the target (MCA or MBA?)
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+template<>
+fapi2::ReturnCode set_rank_pairs(const fapi2::Target<TARGET_TYPE_MCA>& i_target)
+{
+ // If a memory system consists of four or less ranks, each Rank Pair must contain one rank. Each rank has
+ // unique configuration registers, calibration registers, and registers to store delay values. When a system
+ // contains four or less ranks, each rank number used by the system must be loaded into one of the Primary
+ // Rank fields.
+
+ // Set the CSID to all 'unused' and we'll reset them as we configure rank pairs.
+ // Note: Centaur configured this as 0xff00 all the time - it's unclear if we need
+ // to set only the bits for the rank pairs configured, or whether 0xff00 will suffice. BRS
+ fapi2::buffer<uint64_t> l_csid_data(0xFF00);
+
+ fapi2::buffer<uint64_t> l_rp0_register;
+ fapi2::buffer<uint64_t> l_rp1_register;
+
+ // Get the count of rank pairs for all DIMM on the port
+ std::vector<uint8_t> l_rank_count(MAX_DIMM_PER_PORT, 0);
+
+ for (auto d : i_target.getChildren<TARGET_TYPE_DIMM>())
+ {
+ FAPI_TRY( mss::eff_num_ranks_per_dimm(d, l_rank_count[mss::index(d)]) );
+ }
+
+ l_rp0_register = rank_pair_assignments[l_rank_count[1]][l_rank_count[0]].first;
+ l_rp1_register = rank_pair_assignments[l_rank_count[1]][l_rank_count[0]].second;
+
+ FAPI_DBG("setting rank pairs for %s. [%d,%d] (0x%08llx, 0x%08llx) csid: 0x%016llx",
+ mss::c_str(i_target), l_rank_count[1], l_rank_count[0], l_rp0_register, l_rp1_register, l_csid_data);
+
+ FAPI_TRY( fapi2::putScom(i_target, MCA_DDRPHY_PC_RANK_PAIR0_P0, l_rp0_register) );
+ FAPI_TRY( fapi2::putScom(i_target, MCA_DDRPHY_PC_RANK_PAIR1_P0, l_rp1_register) );
+ FAPI_TRY( fapi2::putScom(i_target, MCA_DDRPHY_PC_CSID_CFG_P0, l_csid_data) );
+
+ // HACK HACK HACK: put this in the code properly!! BRS
+ {
+ fapi2::buffer<uint64_t> l_fix_me;
+ l_fix_me.setBit<MCA_DDRPHY_PC_RANK_GROUP_P0_ADDR_MIRROR_RP1_PRI>();
+
+ l_fix_me.setBit<MCA_DDRPHY_PC_RANK_GROUP_P0_ADDR_MIRROR_A3_A4>();
+ l_fix_me.setBit<MCA_DDRPHY_PC_RANK_GROUP_P0_ADDR_MIRROR_A5_A6>();
+ l_fix_me.setBit<MCA_DDRPHY_PC_RANK_GROUP_P0_ADDR_MIRROR_A7_A8>();
+ l_fix_me.setBit<MCA_DDRPHY_PC_RANK_GROUP_P0_ADDR_MIRROR_A11_A13>();
+ l_fix_me.setBit<MCA_DDRPHY_PC_RANK_GROUP_P0_ADDR_MIRROR_BA0_BA1>();
+ l_fix_me.setBit<MCA_DDRPHY_PC_RANK_GROUP_P0_ADDR_MIRROR_BG0_BG1>();
+ FAPI_DBG("pc_rank_group: 0x%016llx", uint64_t(l_fix_me));
+ FAPI_TRY( fapi2::putScom(i_target, MCA_DDRPHY_PC_RANK_GROUP_P0, l_fix_me) );
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Get a vector of configured rank pairs.
+/// Returns a vector of ordinal values of the configured rank pairs. e.g., for a 2R DIMM, {0, 1}
+/// @tparam T the fapi2::TargetType
+/// @param[in] the target (MCA or MBA?)
+/// @param[out] std::vector of rank pairs configured
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+template<>
+fapi2::ReturnCode get_rank_pairs(const fapi2::Target<TARGET_TYPE_MCA>& i_target, std::vector<uint64_t>& o_pairs)
+{
+ std::vector< uint64_t > l_prs;
+ uint64_t l_index = 0;
+
+ FAPI_TRY( primary_ranks(i_target, l_prs) );
+
+ o_pairs.clear();
+
+ // Can't use for (auto rp : l_prs) as rp is unused. BRS
+ for (auto rp_iter = l_prs.begin(); rp_iter != l_prs.end(); ++rp_iter)
+ {
+ o_pairs.push_back(l_index);
+ l_index += 1;
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+} // namespace
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
new file mode 100644
index 000000000..66bcd6b5f
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rank.H
@@ -0,0 +1,94 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/dimm/rank.H $ */
+/* */
+/* 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 rank.H
+/// @brief Do things with or for ranks
+///
+// *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: HB:FSP
+
+#ifndef _MSS_RANK_H_
+#define _MSS_RANK_H_
+
+#include <fapi2.H>
+#include <mss_attribute_accessors.H>
+
+namespace mss
+{
+
+///
+/// @brief Return a vector of rank numbers which represent the ranks for this dimm
+/// @tparam T, the target type you'd like the associated ranks for
+/// @param[in] i_target
+/// @param[out] o_ranks, a vector of ranks (numbers)
+/// @return FAPI2_RC_SUCCESS iff all is ok
+///
+template< fapi2::TargetType T >
+fapi2::ReturnCode ranks( const fapi2::Target<T>& i_target, std::vector< uint64_t >& o_ranks );
+
+///
+/// @brief Return a vector of rank numbers which represent the primary rank pairs for this port or dimm
+/// @tparam T, the target type
+/// @param[in] TARGET_TYPE_MCA or TARGET_TYPEDIMM
+/// @param[out] a vector of rank_pairs
+/// @return FAPI@_RC_SUCCESS iff all is ok
+///
+template< fapi2::TargetType T >
+fapi2::ReturnCode primary_ranks( const fapi2::Target<T>& i_target, std::vector< uint64_t >& o_rps );
+
+///
+/// @brief Return true iff this rank is on thie DIMM
+/// @param[in] i_target representing the DIMM
+/// @param[in] i_rank, the rank number.
+/// @return true iff i_rank is a rank on i_target
+///
+bool is_rank_on_dimm(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target, const uint64_t i_rank);
+
+///
+/// @brief Return the *port relative position* of the DIMM which posesses this rank
+/// @param[in] i_rank, the rank number.
+/// @return the relative position of the DIMM which contains this rank.
+///
+size_t get_dimm_from_rank(const uint64_t i_rank);
+
+///
+/// @brief Setup the rank information in the port
+/// @tparam T the fapi2::TargetType
+/// @param[in] the target (MCA or MBA?)
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+template< fapi2::TargetType T>
+fapi2::ReturnCode set_rank_pairs(const fapi2::Target<T>& i_target);
+
+///
+/// @brief get the rank information related to the port
+/// @tparam T the fapi2::TargetType
+/// @param[in] the target (MCA or MBA?)
+/// @param[out] std::vector of rank pairs configured
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+template< fapi2::TargetType T>
+fapi2::ReturnCode get_rank_pairs(const fapi2::Target<T>& i_target, std::vector<uint64_t>& o_pairs);
+
+}
+#endif
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rcd_load.C b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rcd_load.C
new file mode 100644
index 000000000..7598d4f27
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rcd_load.C
@@ -0,0 +1,165 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/dimm/rcd_load.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 rcd_load.C
+/// @brief Run and manage the RCD_LOAD engine
+///
+// *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 "rcd_load.H"
+#include "rcd_load_ddr4.H"
+
+using fapi2::TARGET_TYPE_MCBIST;
+using fapi2::TARGET_TYPE_MCA;
+using fapi2::TARGET_TYPE_MCS;
+using fapi2::TARGET_TYPE_DIMM;
+
+using fapi2::FAPI2_RC_SUCCESS;
+
+namespace mss
+{
+///
+/// @brief Perform the rcd_load operations - TARGET_TYPE_MCBIST specialization
+/// @param[in] i_target, a fapi2::Target<TARGET_TYPE_MCBIST>
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+template<>
+fapi2::ReturnCode rcd_load<TARGET_TYPE_MCBIST>( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target )
+{
+ // A vector of CCS instructions. We'll ask the targets to fill it, and then we'll execute it
+ ccs::program<TARGET_TYPE_MCBIST> l_program;
+
+ for (auto c : i_target.getChildren<TARGET_TYPE_MCS>())
+ {
+ for (auto p : c.getChildren<TARGET_TYPE_MCA>())
+ {
+ for (auto d : p.getChildren<TARGET_TYPE_DIMM>())
+ {
+ FAPI_DBG("rcd load for %s", mss::c_str(d));
+ FAPI_TRY( perform_rcd_load(d, l_program.iv_instructions) );
+ }
+
+ // We have to configure the CCS engine to let it know which port these instructions are
+ // going out (or whether it's broadcast ...) so lets execute the instructions we presently
+ // have so that we kind of do this by port
+ FAPI_TRY( ccs::execute(i_target, l_program, p) );
+ }
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Perform the rcd_load operations - unknown DIMM case
+/// @param[in] i_target, a fapi2::Target<TARGET_TYPE_DIMM>
+/// @param[in] a vector of CCS instructions we should add to (unused)
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+template<>
+fapi2::ReturnCode perform_rcd_load<DEFAULT_KIND>( const fapi2::Target<TARGET_TYPE_DIMM>& i_target,
+ std::vector< ccs::instruction_t<TARGET_TYPE_MCBIST> >& i_inst)
+{
+ uint8_t l_type = 0;
+ uint8_t l_gen = 0;
+
+ FAPI_TRY( mss::eff_dimm_type(i_target, l_type) );
+ FAPI_TRY( mss::eff_dram_gen(i_target, l_gen) );
+
+ // If we're here, we have a problem. The DIMM kind (type and/or generation) wasn't know
+ // to our dispatcher. We have a DIMM plugged in we don't know how to deal with.
+ FAPI_ASSERT(false,
+ fapi2::MSS_UNKNOWN_DIMM()
+ .set_DIMM_TYPE(l_type)
+ .set_DRAM_GEN(l_gen)
+ .set_DIMM_IN_ERROR(i_target),
+ "Unable to perform rcd load on %s: unknown type (%d) or generation (%d)",
+ mss::c_str(i_target), l_type, l_gen);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Perform the rcd_load operations - RDIMM DDR4
+/// @param[in] i_target, a fapi2::Target<TARGET_TYPE_DIMM>
+/// @param[in] a vector of CCS instructions we should add to
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+template<>
+fapi2::ReturnCode perform_rcd_load<KIND_RDIMM_DDR4>( const fapi2::Target<TARGET_TYPE_DIMM>& i_target,
+ std::vector< ccs::instruction_t<TARGET_TYPE_MCBIST> >& i_inst)
+{
+ FAPI_DBG("perform rcd_load for %s [expecting rdimm (ddr4)]", mss::c_str(i_target));
+ FAPI_TRY( rcd_load_ddr4(i_target, i_inst) );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Perform the rcd_load operations - LRDIMM DDR4
+/// @param[in] i_target, a fapi2::Target<TARGET_TYPE_DIMM>
+/// @param[in] a vector of CCS instructions we should add to
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+template<>
+fapi2::ReturnCode perform_rcd_load<KIND_LRDIMM_DDR4>( const fapi2::Target<TARGET_TYPE_DIMM>& i_target,
+ std::vector< ccs::instruction_t<TARGET_TYPE_MCBIST> >& i_inst)
+{
+ FAPI_DBG("perform rcd_load for %s [expecting lrdimm (ddr4)]", mss::c_str(i_target));
+ FAPI_TRY( rcd_load_ddr4(i_target, i_inst) );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+
+///
+/// @brief Perform the rcd_load operations - start the dispatcher
+/// @param[in] i_target, a fapi2::Target<TARGET_TYPE_DIMM>
+/// @param[in] a vector of CCS instructions we should add to
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+template<>
+fapi2::ReturnCode perform_rcd_load<FORCE_DISPATCH>( const fapi2::Target<TARGET_TYPE_DIMM>& i_target,
+ std::vector< ccs::instruction_t<TARGET_TYPE_MCBIST> >& i_inst)
+{
+ uint8_t l_type = 0;
+ uint8_t l_gen = 0;
+
+ FAPI_TRY( mss::eff_dimm_type(i_target, l_type) );
+ FAPI_TRY( mss::eff_dram_gen(i_target, l_gen) );
+
+ return perform_rcd_load_dispatch<FORCE_DISPATCH>(dimm_kind( l_type, l_gen ), i_target, i_inst);
+
+fapi_try_exit:
+ FAPI_ERR("couldn't get dimm type, dram gen: %s", mss::c_str(i_target));
+ return fapi2::current_err;
+}
+
+} // namespace
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rcd_load.H b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rcd_load.H
new file mode 100644
index 000000000..bc66ccd46
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rcd_load.H
@@ -0,0 +1,174 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/dimm/rcd_load.H $ */
+/* */
+/* 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 rcd_load.H
+/// @brief Code to support rcd_loads
+///
+// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
+// *HWP HWP Backup: Craig Hamilton <cchamilt@us.ibm.com>
+// *HWP Team: Memory
+// *HWP Level: 2
+// *HWP Consumed by: HB:FSP
+
+#ifndef _MSS_RCD_LOAD_H_
+#define _MSS_RCD_LOAD_H_
+
+#include <fapi2.H>
+#include "../utils/c_str.H"
+#include <p9_mc_scom_addresses.H>
+
+#include "../shared/mss_kind.H"
+
+namespace mss
+{
+
+struct rcd_data
+{
+ // Which RC# this is
+ fapi2::buffer<uint8_t> iv_rcd;
+
+ // The attribute getter
+ fapi2::ReturnCode (*iv_func)(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>&, uint8_t&);
+
+ // The delay needed after this RCD word is written
+ uint64_t iv_delay;
+
+ rcd_data( uint64_t i_rcd,
+ fapi2::ReturnCode (*i_func)(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>&, uint8_t&),
+ uint64_t i_delay ):
+ iv_rcd(i_rcd),
+ iv_func(i_func),
+ iv_delay(i_delay)
+ {}
+};
+
+///
+/// @brief Perform the rcd_load operations
+/// @tparam T, the fapi2::TargetType of i_target
+/// @param[in] i_target, a fapi2::Target
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+template< fapi2::TargetType T >
+fapi2::ReturnCode rcd_load( const fapi2::Target<T>& i_target );
+
+
+//
+// Implement the polymorphism for rcd_load
+//
+
+// -# Register the API.
+/// -# Define the template parameters for the overloaded function
+/// @note the first argument is the api name, and the rest are the api's template parameters.
+/// @note this creates __api_name##_overload
+
+template< mss::kind_t K >
+struct perform_rcd_load_overload
+{
+ static const bool available = false;
+};
+
+/// -# Register the specific overloads. The first parameter is the name
+/// of the api, the second is the kind of the element which is being
+/// overloaded - an RDIMM, an LRDIMM, etc. The remaining parameters
+/// indicate the specialization of the api itself.
+/// @note You need to define the "DEFAULT_KIND" here as an overload. This
+/// allows the mechanism to find the "base" implementation for things which
+/// have no specific overload.
+template<>
+struct perform_rcd_load_overload< DEFAULT_KIND >
+{
+ static const bool available = true;
+};
+
+template<>
+struct perform_rcd_load_overload< KIND_RDIMM_DDR4 >
+{
+ static const bool available = true;
+};
+
+template<>
+struct perform_rcd_load_overload< KIND_LRDIMM_DDR4 >
+{
+ static const bool available = true;
+};
+
+///
+/// -# Define the default case for overloaded calls. enable_if states that
+/// if there is a DEFAULT_KIND overload for this TargetType, then this
+/// entry point will be defined. Note the general case below is enabled if
+/// there is no overload defined for this TargetType
+///
+
+///
+/// @brief Perform the rcd_load operations
+/// @tparam K, the kind of DIMM we're operating on (derived)
+/// @param[in] i_target, a fapi2::Target<fapi2::TARGET_TYPE_DIMM>
+/// @param[in] a vector of CCS instructions we should add to
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+template< mss::kind_t K = FORCE_DISPATCH >
+typename std::enable_if< perform_rcd_load_overload<DEFAULT_KIND>::available, fapi2::ReturnCode>::type
+perform_rcd_load( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ std::vector< ccs::instruction_t<fapi2::TARGET_TYPE_MCBIST> >& i_inst);
+
+//
+// We know we registered overloads for perform_rcd_load, so we need the entry point to
+// the dispatcher. Add a set of these for all TargetTypes which get overloads
+// for this API
+//
+template<>
+fapi2::ReturnCode perform_rcd_load<FORCE_DISPATCH>( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ std::vector< ccs::instruction_t<fapi2::TARGET_TYPE_MCBIST> >& i_inst);
+
+template<>
+fapi2::ReturnCode perform_rcd_load<DEFAULT_KIND>( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ std::vector< ccs::instruction_t<fapi2::TARGET_TYPE_MCBIST> >& i_inst);
+
+//
+// Boilerplate dispatcher
+//
+template< kind_t K, bool B = perform_rcd_load_overload<K>::available >
+inline fapi2::ReturnCode perform_rcd_load_dispatch( const kind_t& i_kind,
+ const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ std::vector< ccs::instruction_t<fapi2::TARGET_TYPE_MCBIST> >& i_inst)
+{
+ // We dispatch to another kind if:
+ // We don't have an overload defined (B == false)
+ // Or, if we do have an overload (B == true) and this is not out kind.
+ if ((B == false) || ((B == true) && (K != i_kind)))
+ {
+ return perform_rcd_load_dispatch < (kind_t)(K - 1) > (i_kind, i_target, i_inst);
+ }
+
+ // Otherwise, we call the overload.
+ return perform_rcd_load<K>(i_target, i_inst);
+}
+
+// DEFAULT_KIND is 0 so this is the end of the recursion
+template<>
+inline fapi2::ReturnCode perform_rcd_load_dispatch<DEFAULT_KIND>(const kind_t&,
+ const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ std::vector< ccs::instruction_t<fapi2::TARGET_TYPE_MCBIST> >& i_inst)
+{
+ return perform_rcd_load<DEFAULT_KIND>(i_target, i_inst);
+}
+
+}
+#endif
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rcd_load_ddr4.C b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rcd_load_ddr4.C
new file mode 100644
index 000000000..cbf370047
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rcd_load_ddr4.C
@@ -0,0 +1,138 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/dimm/rcd_load_ddr4.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 rcd_load_ddr4.C
+/// @brief Run and manage the DDR4 rcd loading
+///
+// *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 "rcd_load_ddr4.H"
+
+using fapi2::TARGET_TYPE_MCBIST;
+using fapi2::TARGET_TYPE_MCA;
+using fapi2::TARGET_TYPE_MCS;
+using fapi2::TARGET_TYPE_DIMM;
+
+using fapi2::FAPI2_RC_SUCCESS;
+
+namespace mss
+{
+
+///
+/// @brief Perform the rcd_load_ddr4 operations - TARGET_TYPE_DIMM specialization
+/// @param[in] i_target, a fapi2::Target<TARGET_TYPE_DIMM>
+/// @param[in] a vector of CCS instructions we should add to
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+fapi2::ReturnCode rcd_load_ddr4( const fapi2::Target<TARGET_TYPE_DIMM>& i_target,
+ std::vector< ccs::instruction_t<TARGET_TYPE_MCBIST> >& i_inst)
+{
+ FAPI_INF("rcd_load_ddr4 %s", mss::c_str(i_target));
+
+ // Per DDR4RCD02 table 104 - timing requirements
+ static const uint64_t tMRD = 8;
+ static const uint64_t tMRD_L = 16;
+
+ // Per DDR4RCD02, tSTAB is 5us. We want this in cycles for the CCS.
+ const uint64_t tSTAB = mss::us_to_cycles(i_target, 5);
+
+ static std::vector< rcd_data > l_rcd_4bit_data =
+ {
+ { 0, eff_dimm_ddr4_rc00, tMRD }, { 1, eff_dimm_ddr4_rc01, tMRD }, { 2, eff_dimm_ddr4_rc02, tSTAB },
+ { 3, eff_dimm_ddr4_rc03, tMRD_L}, { 4, eff_dimm_ddr4_rc04, tMRD_L}, { 5, eff_dimm_ddr4_rc05, tMRD_L},
+ { 6, eff_dimm_ddr4_rc67, tMRD }, { 8, eff_dimm_ddr4_rc08, tMRD }, { 9, eff_dimm_ddr4_rc09, tMRD },
+ { 10, eff_dimm_ddr4_rc10, tSTAB }, { 11, eff_dimm_ddr4_rc11, tMRD }, { 12, eff_dimm_ddr4_rc12, tMRD },
+ { 13, eff_dimm_ddr4_rc13, tMRD }, { 14, eff_dimm_ddr4_rc14, tMRD }, { 15, eff_dimm_ddr4_rc15, tMRD },
+ };
+
+ static std::vector< rcd_data > l_rcd_8bit_data =
+ {
+ { 1, eff_dimm_ddr4_rc1x, tMRD }, { 2, eff_dimm_ddr4_rc2x, tMRD }, { 3, eff_dimm_ddr4_rc3x, tSTAB },
+ { 4, eff_dimm_ddr4_rc4x, tMRD }, { 5, eff_dimm_ddr4_rc5x, tMRD }, { 6, eff_dimm_ddr4_rc6x, tMRD },
+ { 7, eff_dimm_ddr4_rc7x, tMRD }, { 8, eff_dimm_ddr4_rc8x, tMRD }, { 9, eff_dimm_ddr4_rc9x, tMRD },
+ { 10, eff_dimm_ddr4_rcax, tMRD }, { 11, eff_dimm_ddr4_rcbx, tMRD_L}
+ };
+
+ fapi2::buffer<uint8_t> l_value;
+
+ // A little 4bit RCD love ...
+ for (auto d : l_rcd_4bit_data)
+ {
+ // Note: this isn't general - assumes Nimbus via MCBIST instruction here BRS
+ ccs::instruction_t<TARGET_TYPE_MCBIST> l_inst = ccs::rcd_command<TARGET_TYPE_MCBIST>(i_target);
+ FAPI_TRY( d.iv_func(i_target, l_value) );
+
+ // If this control word would be set to 0, skip it - we can rely on the DIMM default
+ if (l_value != 0)
+ {
+ // Data to be written into the 4-bit configuration registers need to be presented on DA0 .. DA3
+ mss::swizzle<MCBIST_CCS_INST_ARR0_00_DDR_ADDRESS_0_13, 4, 7>(l_value, l_inst.arr0);
+
+ // Selection of each word of 4-bit control bits is presented on inputs DA4 through DA12
+ mss::swizzle < MCBIST_CCS_INST_ARR0_00_DDR_ADDRESS_0_13 + 4, 4, 7 > (d.iv_rcd, l_inst.arr0);
+
+ // For changes to the control word setting [...] the controller needs to wait tMRD[tSTAB] after
+ // the last control word access, before further access to the DRAM can take place.
+ l_inst.arr1.insertFromRight<MCBIST_CCS_INST_ARR1_00_IDLES, MCBIST_CCS_INST_ARR1_00_IDLES_LEN>(d.iv_delay);
+
+ FAPI_INF("RCD%02d value 0x%x (%d) 0x%016llx:0x%016llx %s", uint8_t(d.iv_rcd), l_value, d.iv_delay,
+ l_inst.arr0, l_inst.arr1, mss::c_str(i_target));
+ i_inst.push_back(l_inst);
+ }
+ }
+
+ // 8bit's turn
+ for (auto d : l_rcd_8bit_data)
+ {
+ // Note: this isn't general - assumes Nimbus via MCBIST instruction here BRS
+ ccs::instruction_t<TARGET_TYPE_MCBIST> l_inst = ccs::rcd_command<TARGET_TYPE_MCBIST>(i_target);
+ FAPI_TRY( d.iv_func(i_target, l_value) );
+
+ // If this control word would be set to 0, skip it - we can rely on the DIMM default
+ if (l_value != 0)
+ {
+ // Data to be written into the 8-bit configuration registers need to be presented on DA0 .. DA7
+ mss::swizzle<MCBIST_CCS_INST_ARR0_00_DDR_ADDRESS_0_13, 8, 7>(l_value, l_inst.arr0);
+
+ // Selection of each word of 8-bit control bits is presented on inputs DA8 through DA12.
+ mss::swizzle < MCBIST_CCS_INST_ARR0_00_DDR_ADDRESS_0_13 + 8, 5, 7 > (d.iv_rcd, l_inst.arr0);
+
+ // For changes to the control word setting [...] the controller needs to wait tMRD[tSTAB] after
+ // the last control word access, before further access to the DRAM can take place.
+ l_inst.arr1.insertFromRight<MCBIST_CCS_INST_ARR1_00_IDLES, MCBIST_CCS_INST_ARR1_00_IDLES_LEN>(d.iv_delay);
+
+ FAPI_INF("RCD%XX value 0x%x (%d) 0x%016llx:0x%016llx %s", uint8_t(d.iv_rcd), l_value, d.iv_delay,
+ l_inst.arr0, l_inst.arr1, mss::c_str(i_target));
+ i_inst.push_back(l_inst);
+ }
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+} // namespace
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rcd_load_ddr4.H b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rcd_load_ddr4.H
new file mode 100644
index 000000000..640f43d89
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rcd_load_ddr4.H
@@ -0,0 +1,48 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/dimm/rcd_load_ddr4.H $ */
+/* */
+/* 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 rcd_load_ddr4.H
+/// @brief Code to support rcd_load_ddr4
+///
+// *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: HB:FSP
+
+#ifndef _MSS_RCD_LOAD_DDR4_H_
+#define _MSS_RCD_LOAD_DDR4_H_
+
+#include <fapi2.H>
+#include "../utils/c_str.H"
+#include <p9_mc_scom_addresses.H>
+
+namespace mss
+{
+///
+/// @brief Perform the rcd_load_ddr4 operations - TARGET_TYPE_DIMM specialization
+/// @param[in] i_target, a fapi2::Target<TARGET_TYPE_DIMM>
+/// @param[in] a vector of CCS instructions we should add to
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+fapi2::ReturnCode rcd_load_ddr4( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ std::vector< ccs::instruction_t<fapi2::TARGET_TYPE_MCBIST> >& i_inst);
+}
+#endif
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/mcbist.C b/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/mcbist.C
new file mode 100644
index 000000000..f2184f89b
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/mcbist.C
@@ -0,0 +1,41 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/mcbist/mcbist.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 mcbist.C
+/// @brief Run and manage the MCBIST engine
+///
+// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
+// *HWP HWP Backup: Craig Hamilton <cchamilt@us.ibm.com>
+// *HWP Team: Memory
+// *HWP Level: 2
+// *HWP Consumed by: FSP:HB
+
+#include <fapi2.H>
+#include "mcbist.H"
+
+using fapi2::TARGET_TYPE_MCBIST;
+
+namespace mss
+{
+namespace mcbist
+{
+
+} // namespace
+} // namespace
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/mcbist.H b/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/mcbist.H
new file mode 100644
index 000000000..1a6660c3c
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/mcbist.H
@@ -0,0 +1,255 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/mcbist/mcbist.H $ */
+/* */
+/* 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 mcbist.H
+/// @brief Run and manage the MCBIST engine
+///
+// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
+// *HWP HWP Backup: Craig Hamilton <cchamilt@us.ibm.com>
+// *HWP Team: Memory
+// *HWP Level: 2
+// *HWP Consumed by: HB:FSP
+
+#ifndef _MSS_MCBIST_H_
+#define _MSS_MCBIST_H_
+
+#include <fapi2.H>
+
+#include <p9_mc_scom_addresses.H>
+#include <p9_mc_scom_addresses_fld.H>
+
+#include "../utils/poll.H"
+#include "../shared/mss_const.H"
+
+namespace mss
+{
+namespace mcbist
+{
+
+// I have a dream that the MCBIST engine code can be shared among controllers. So, I drive the
+// engine from a set of traits. This might be folly. Allow me to dream. BRS
+
+///
+/// @class mcbistTraits
+/// @brief a collection of traits associated with the MCBIST engine or hardware
+///
+template< fapi2::TargetType T >
+class mcbistTraits;
+
+///
+/// @class mcbistTraits<fapi2::TARGET_TYPE_MEMBUF_CHIP>
+/// @brief a collection of traits associated with the Centaur MCBIST engine or hardware
+///
+template<>
+class mcbistTraits<fapi2::TARGET_TYPE_MEMBUF_CHIP>
+{
+};
+
+///
+/// @class mcbistTraits<fapi2::TARGET_TYPE_MCBIST>
+/// @brief a collection of traits associated with the Nimbus MCBIST engine or hardware
+///
+template<>
+class mcbistTraits<fapi2::TARGET_TYPE_MCBIST>
+{
+ public:
+ /// MCBIST "memory registers" - config for subtests.
+ static const uint64_t MCBMR0_REG = MCBIST_MCBMR0Q;
+
+ enum
+ {
+ // Subtest control bits. These are the same in all '16 bit subtest' field
+ COMPL_1ST_CMD = MCBIST_MCBMR0Q_MCBIST_CFG_TEST00_COMPL_1ST_CMD,
+ COMPL_2ND_CMD = MCBIST_MCBMR0Q_MCBIST_CFG_TEST00_COMPL_2ND_CMD,
+ COMPL_3RD_CMD = MCBIST_MCBMR0Q_MCBIST_CFG_TEST00_COMPL_3RD_CMD,
+ ADDR_REV_MODE = MCBIST_MCBMR0Q_MCBIST_CFG_TEST00_ADDR_REV_MODE,
+ ADDR_RAND_MODE = MCBIST_MCBMR0Q_MCBIST_CFG_TEST00_ADDR_RAND_MODE,
+ ECC_MODE = MCBIST_MCBMR0Q_MCBIST_CFG_TEST00_ECC_MODE,
+ DATA_MODE = MCBIST_MCBMR0Q_MCBIST_CFG_TEST00_DATA_MODE,
+ DATA_MODE_LEN = MCBIST_MCBMR0Q_MCBIST_CFG_TEST00_DATA_MODE_LEN,
+ ADDR_SEL = MCBIST_MCBMR0Q_MCBIST_CFG_TEST00_ADDR_SEL,
+ ADDR_SEL_LEN = MCBIST_MCBMR0Q_MCBIST_CFG_TEST00_ADDR_SEL_LEN,
+ };
+
+};
+
+///
+/// @class subtest_t
+/// @brief encapsulation of an MCBIST subtest.
+///
+template< fapi2::TargetType T, typename TT = mcbistTraits<T> >
+class subtest_t
+{
+ public:
+ /// The mcbist 'memory register' for this subtest.
+ // Note that it is only 16 bits.
+ // Each 64b memory register contains multiple 16 bit subtest definitions.
+ // As we create a vector of subtests, we'll drop them in to their appropriate
+ // MCBMR register before executing.
+ fapi2::buffer<uint16_t> iv_mcbmr;
+};
+
+///
+/// @brief A class representing a series of MCBIST subtests, and the
+/// MCBIST engine parameters associated with running the subtests
+/// @tparam fapi2::TargetType T representing the fapi2 target which
+/// contains the MCBIST engine (e.g., fapi2::TARGET_TYPE_MCBIST)
+///
+template< fapi2::TargetType T >
+class program
+{
+ public:
+ // Setup our poll parameters so the CCS executer can see
+ // whether to use the delays in the instruction stream or not
+ program(): iv_poll(0, 0)
+ {}
+
+ // Vector of subtests
+ std::vector< subtest_t<T> > iv_subtests;
+ poll_parameters iv_poll;
+};
+
+///
+/// @brief Complement the data for the first subcommand
+/// @tparam T, fapi2::TargetType of the MCBIST engine
+/// @tparam TT, the mssTraits associtated with T
+/// @param[in,out] io_subtest, a subtest
+/// @param[in] i_state, the desired state of the function
+/// @return void
+///
+template< fapi2::TargetType T, typename TT = mcbistTraits<T> >
+void change_compliment_1st_cmd( subtest_t<T>& io_subtest, const mss::states i_state )
+{
+ io_subtest.iv_mcbmr.template writeBit<TT::COMPL_1ST_CMD>(i_state);
+ return;
+}
+
+///
+/// @brief Complement the data for the second subcommand
+/// @tparam T, fapi2::TargetType of the MCBIST engine
+/// @tparam TT, the mssTraits associtated with T
+/// @param[in,out] io_subtest, a subtest
+/// @param[in] i_state, the desired state of the function
+/// @return void
+///
+template< fapi2::TargetType T, typename TT = mcbistTraits<T> >
+void change_compliment_2nd_cmd( subtest_t<T>& io_subtest, const mss::states i_state )
+{
+ io_subtest.iv_mcbmr.template writeBit<TT::COMPL_2ND_CMD>(i_state);
+ return;
+}
+
+///
+/// @brief Complement the data for the third subcommand
+/// @tparam T, fapi2::TargetType of the MCBIST engine
+/// @tparam TT, the mssTraits associtated with T
+/// @param[in,out] io_subtest, a subtest
+/// @param[in] i_state, the desired state of the function
+/// @return void
+///
+template< fapi2::TargetType T, typename TT = mcbistTraits<T> >
+void change_compliment_3rd_cmd( subtest_t<T>& io_subtest, const mss::states i_state )
+{
+ io_subtest.iv_mcbmr.template writeBit<TT::COMPL_3RD_CMD>(i_state);
+ return;
+}
+
+///
+/// @brief Generate addresses in reverse order
+/// @tparam T, fapi2::TargetType of the MCBIST engine
+/// @tparam TT, the mssTraits associtated with T
+/// @param[in,out] io_subtest, a subtest
+/// @param[in] i_state, the desired state of the function
+/// @return void
+///
+template< fapi2::TargetType T, typename TT = mcbistTraits<T> >
+void change_addr_rev_mode( subtest_t<T>& io_subtest, const mss::states i_state )
+{
+ io_subtest.iv_mcbmr.template writeBit<TT::ADDR_REV_MODE>(i_state);
+ return;
+}
+
+///
+/// @brief Generate addresses in random order
+/// @tparam T, fapi2::TargetType of the MCBIST engine
+/// @tparam TT, the mssTraits associtated with T
+/// @param[in,out] io_subtest, a subtest
+/// @param[in] i_state, the desired state of the function
+/// @return void
+///
+template< fapi2::TargetType T, typename TT = mcbistTraits<T> >
+void change_addr_rand_mode( subtest_t<T>& io_subtest, const mss::states i_state )
+{
+ io_subtest.iv_mcbmr.template writeBit<TT::ADDR_RAND_MODE>(i_state);
+ return;
+}
+
+///
+/// @brief Generate and check data with ECC
+/// @tparam T, fapi2::TargetType of the MCBIST engine
+/// @tparam TT, the mssTraits associtated with T
+/// @param[in,out] io_subtest, a subtest
+/// @param[in] i_state, the desired state of the function
+/// @return void
+///
+template< fapi2::TargetType T, typename TT = mcbistTraits<T> >
+void change_ecc_mode( subtest_t<T>& io_subtest, const mss::states i_state )
+{
+ io_subtest.iv_mcbmr.template writeBit<TT::ECC_MODE>(i_state);
+ return;
+}
+
+///
+/// @brief Set the data mode for this subtest
+/// @tparam T, fapi2::TargetType of the MCBIST engine
+/// @tparam TT, the mssTraits associtated with T
+/// @param[in,out] io_subtest, a subtest
+/// @param[in] i_mode, the desired mcbist::data_mode
+/// @return void
+///
+template< fapi2::TargetType T, typename TT = mcbistTraits<T> >
+void change_data_mode( subtest_t<T>& io_subtest, const data_mode i_mode )
+{
+ io_subtest.iv_mcbmr.template insertFromRight<TT::DATA_MODE, TT::DATA_MODE_LEN>(i_mode);
+ return;
+}
+
+///
+/// @brief Configure which address registers to use for this subtest
+/// @tparam T, fapi2::TargetType of the MCBIST engine
+/// @tparam TT, the mssTraits associtated with T
+/// @param[in,out] io_subtest, a subtest
+/// @param[in] i_index, 0 = MCBSA0Q, 1 = MCBSA1Q, ...
+/// @note wraps to 0-3 no matter what value you pass in.
+/// @return void
+///
+template< fapi2::TargetType T, typename TT = mcbistTraits<T> >
+void change_addr_sel( subtest_t<T>& io_subtest, const uint16_t i_index )
+{
+ // Roll the index around - tidy support for an index which is out of range.
+ static const uint16_t MAX_ADDRESS_START_END_REGISTERS = 3 + 1;
+ io_subtest.iv_mcbmr.template insertFromRight<TT::ADDR_SEL, TT::ADDR_SEL_LEN>(i_index % MAX_ADDRESS_START_END_REGISTERS);
+ return;
+}
+
+} // namespace
+} // namespace
+
+#endif
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/mss.H b/src/import/chips/p9/procedures/hwp/memory/lib/mss.H
new file mode 100644
index 000000000..5ec6f752e
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/mss.H
@@ -0,0 +1,63 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/mss.H $ */
+/* */
+/* 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 mss.H
+/// @brief Main include file for the Memory Subsystem
+///
+// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
+// *HWP HWP Backup: Craig Hamilton <cchamilt@us.ibm.com>
+// *HWP Team: Memory
+// *HWP Level: 2
+// *HWP Consumed by: HB:FSP
+
+#ifndef _MSS_H_
+#define _MSS_H_
+
+#include <fapi2.H>
+#include <p9_mc_scom_addresses.H>
+#include <p9_mc_scom_addresses_fld.H>
+
+#include "shared/mss_const.H"
+#include "shared/mss_kind.H"
+
+#include "utils/index.H"
+#include "utils/c_str.H"
+
+#include "utils/pos.H"
+#include "utils/swizzle.H"
+#include "utils/conversions.H"
+#include "utils/find.H"
+#include "utils/poll.H"
+#include "utils/checker.H"
+
+#include "ccs/ccs.H"
+
+#include "port/port.H"
+
+
+#include "dimm/rcd_load.H"
+#include "dimm/mrs_load.H"
+#include "dimm/rank.H"
+
+#include "phy/ddr_phy.H"
+#include "phy/dp16.H"
+#include "phy/cal_timers.H"
+
+#endif
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/mss.mk b/src/import/chips/p9/procedures/hwp/memory/lib/mss.mk
new file mode 100644
index 000000000..3f4e6c60f
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/mss.mk
@@ -0,0 +1,43 @@
+# IBM_PROLOG_BEGIN_TAG
+# This is an automatically generated prolog.
+#
+# $Source: chips/p9/procedures/hwp/memory/lib/mss.mk $
+#
+# 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
+
+#
+# Makefile to build the MSS libraries.
+#
+
+# Add common and generated parts to object list.
+
+MSS_PATH := $(ROOTPATH)/chips/p9/procedures/hwp/memory/lib
+
+MSS_SOURCE := $(shell find $(MSS_PATH) -name '*.C' -exec basename {} \;)
+MSS_MODULE_OBJS += $(patsubst %.C,%.o,$(MSS_SOURCE))
+
+MSS_SOURCE_DIRS := $(shell find $(MSS_PATH) -type d)
+
+# Define common source and include paths.
+define MSS_MODULE_INCLUDES
+$(foreach dir, $(MSS_SOURCE_DIRS), $(call ADD_MODULE_SRCDIR,$(1),$(dir)))
+$(call ADD_MODULE_INCDIR,$(1),$(GENPATH))
+$(call ADD_MODULE_INCDIR,$(1),$(FAPI2_PLAT_INCLUDE))
+endef
+
+MODULE = mss
+OBJS += $(MSS_MODULE_OBJS)
+$(eval $(call MSS_MODULE_INCLUDES,$(MODULE)))
+$(call BUILD_MODULE)
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/mss_utils.H b/src/import/chips/p9/procedures/hwp/memory/lib/mss_utils.H
new file mode 100644
index 000000000..a20562e15
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/mss_utils.H
@@ -0,0 +1,36 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/mss_utils.H $ */
+/* */
+/* 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 mss_utils.h.H
+/// @brief Main include file for the Memory Subsystem
+///
+// *HWP HWP Owner: Craig Hamilton <cchamilt@us.ibm.com>
+// *HWP HWP Backup: Brian Silver <bsilver@us.ibm.com>
+// *HWP Team: Memory
+// *HWP Level: 2
+// *HWP Consumed by: HB:FSP
+
+#ifndef _MSS_P9_ATTR_UTILS_H_
+#define _MSS_P9_ATTR_UTILS_H_
+
+#include "utils/index.H"
+#include "utils/c_str.H"
+
+#endif // _MSS_P9_ATTR_UTILS_H_
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/phy/cal_timers.H b/src/import/chips/p9/procedures/hwp/memory/lib/phy/cal_timers.H
new file mode 100644
index 000000000..4045ada50
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/phy/cal_timers.H
@@ -0,0 +1,245 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/phy/cal_timers.H $ */
+/* */
+/* 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 cal_timers.H
+/// @brief Subroutines to calculate the duration of training operations
+///
+// *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
+
+#ifndef _MSS_CAL_TIMERS_H_
+#define _MSS_CAL_TIMERS_H_
+
+#include <fapi2.H>
+#include "../shared/mss_const.H"
+#include "../utils/conversions.H"
+#include "../utils/poll.H"
+
+namespace mss
+{
+
+///
+/// @brief Return the cycles taken for write leveling on a single rank
+/// @tparam T, the target type used to get attributes
+/// @param[in] i_target, used to get attributes
+/// @return uint64_t, the cycles taken for write leveling on a single rank
+///
+template<fapi2::TargetType T>
+uint64_t wr_lvl_cycles(const fapi2::Target<T>& i_target )
+{
+ const uint64_t TWLO_TWLOE = mss::twlo_twloe(i_target);
+
+ // This step runs for approximately (80 + TWLO_TWLOE) x NUM_VALID_SAMPLES x (384/(BIG_STEP + 1) +
+ // (2 x (BIG_STEP + 1))/(SMALL_STEP + 1)) + 20 memory clock cycles per rank.
+
+ const uint64_t l_wr_lvl_cycles = (80 + TWLO_TWLOE) * WR_LVL_NUM_VALID_SAMPLES * (384 / (WR_LVL_BIG_STEP + 1) +
+ (2 * (WR_LVL_BIG_STEP + 1)) / (WR_LVL_SMALL_STEP + 1)) + 20;
+ FAPI_DBG("wr_lvl_cycles: %d(%dns) (%d, %d, %d, %d)", l_wr_lvl_cycles, mss::cycles_to_ns(i_target, l_wr_lvl_cycles),
+ TWLO_TWLOE, WR_LVL_NUM_VALID_SAMPLES, WR_LVL_BIG_STEP, WR_LVL_SMALL_STEP);
+
+ return l_wr_lvl_cycles;
+}
+
+///
+/// @brief Return the cycles taken for DQS align on a single rank
+/// @tparam T, the target type used to get attributes
+/// @param[in] i_target, used to get attributes
+/// @return uint64_t, the cycles taken for DQS align on a single rank
+///
+template<fapi2::TargetType T>
+uint64_t dqs_align_cycles(const fapi2::Target<T>& i_target )
+{
+ // This step runs for approximately 6 x 600 x 4 DRAM clocks per rank pair.
+ const uint64_t l_dqs_align_cycles = 6 * 600 * 4;
+
+ FAPI_DBG("dqs_align_cycles: %d(%dns)", l_dqs_align_cycles, mss::cycles_to_ns(i_target, l_dqs_align_cycles));
+ return l_dqs_align_cycles;
+}
+
+///
+/// @brief Return the cycles taken for RD clock align on a single rank
+/// @tparam T, the target type used to get attributes
+/// @param[in] i_target, used to get attributes
+/// @return uint64_t, the cycles taken for RD clock align on a single rank
+///
+template<fapi2::TargetType T>
+uint64_t rdclk_align_cycles(const fapi2::Target<T>& i_target )
+{
+ // This step runs for approximately 24 x ((1024/COARSE_CAL_STEP_SIZE + 4 x COARSE_CAL_STEP_SIZE) x 4 + 32) DRAM
+ // clocks per rank pair
+ const uint64_t l_rdclk_align_cycles = 24 * ((1024 / COARSE_CAL_STEP_SIZE + 4 * COARSE_CAL_STEP_SIZE) * 4 + 32);
+ FAPI_DBG("rdclk_align_cycles: %d(%dns) (%d)", l_rdclk_align_cycles,
+ mss::cycles_to_ns(i_target, l_rdclk_align_cycles), COARSE_CAL_STEP_SIZE);
+ return l_rdclk_align_cycles;
+}
+
+///
+/// @brief Return the cycles taken for read centering on a single rank
+/// @tparam T, the target type used to get attributes
+/// @param[in] i_target, used to get attributes
+/// @return uint64_t, the cycles taken for read centering on a single rank
+///
+template<fapi2::TargetType T>
+uint64_t read_ctr_cycles(const fapi2::Target<T>& i_target )
+{
+ // This step runs for approximately 6 x (512/COARSE_CAL_STEP_SIZE + 4 x (COARSE_CAL_STEP_SIZE +
+ // 4 x CONSEQ_PASS)) x 24 DRAM clocks per rank pair.
+
+ const uint64_t l_read_ctr_cycles = 6 * (512 / COARSE_CAL_STEP_SIZE + 4 * (COARSE_CAL_STEP_SIZE + 4 * CONSEQ_PASS)) * 24;
+ FAPI_DBG("read_ctr_cycles %d(%dns) (%d, %d)", l_read_ctr_cycles, mss::cycles_to_ns(i_target, l_read_ctr_cycles),
+ COARSE_CAL_STEP_SIZE, CONSEQ_PASS);
+ return l_read_ctr_cycles;
+}
+
+///
+/// @brief Return the cycles taken for write centering on a single rank
+/// @tparam T, the target type used to get attributes
+/// @param[in] i_target, used to get attributes
+/// @return uint64_t, the cycles taken for write centering on a single rank
+///
+template<fapi2::TargetType T>
+uint64_t write_ctr_cycles(const fapi2::Target<T>& i_target )
+{
+ // 1000 + (NUM_VALID_SAMPLES * (FW_WR_RD + FW_RD_WR + 16) *
+ // (1024/(SMALL_STEP +1) + 128/(BIG_STEP +1)) + 2 * (BIG_STEP+1)/(SMALL_STEP+1)) x 24 DRAM
+ // clocks per rank pair.
+ const uint64_t l_write_ctr_cycles = 1000 + (WR_LVL_NUM_VALID_SAMPLES * (WR_CNTR_FW_WR_RD + WR_CNTR_FW_RD_WR + 16) *
+ (1024 / (WR_LVL_SMALL_STEP + 1) + 128 / (WR_LVL_BIG_STEP + 1)) + 2 *
+ (WR_LVL_BIG_STEP + 1) / (WR_LVL_SMALL_STEP + 1)) * 24;
+
+ FAPI_DBG("write_ctr_cycles: %d(%dns) (%d, %d, %d, %d, %d)",
+ l_write_ctr_cycles, mss::cycles_to_ns(i_target, l_write_ctr_cycles),
+ WR_LVL_NUM_VALID_SAMPLES, WR_CNTR_FW_WR_RD, WR_CNTR_FW_RD_WR, WR_LVL_BIG_STEP, WR_LVL_SMALL_STEP);
+
+ return l_write_ctr_cycles;
+}
+
+///
+/// @brief Return the cycles taken for coarse write on a single rank
+/// @tparam T, the target type used to get attributes
+/// @param[in] i_target, used to get attributes
+/// @return uint64_t, the cycles taken for coarse write on a single rank
+///
+template<fapi2::TargetType T>
+uint64_t coarse_wr_cycles(const fapi2::Target<T>& i_target )
+{
+ // The run length given here is the maximum run length for this calibration algorithm.
+ // This step runs for approximately 40 DRAM clocks per rank pair.
+ static const uint64_t l_coarse_wr_cycles = 40;
+ FAPI_DBG("coarse_wr_cycles: %d(%dns)", l_coarse_wr_cycles, mss::cycles_to_ns(i_target, l_coarse_wr_cycles));
+ return l_coarse_wr_cycles;
+}
+
+///
+/// @brief Return the cycles taken for coarse read on a single rank
+/// @tparam T, the target type used to get attributes
+/// @param[in] i_target, used to get attributes
+/// @return uint64_t, the cycles taken for coarse rd on a single rank
+///
+template<fapi2::TargetType T>
+uint64_t coarse_rd_cycles(const fapi2::Target<T>& i_target )
+{
+ // The run length given here is the maximum run length for this calibration algorithm.
+ // This step runs for approximately 32 DRAM clocks per rank pair.
+ static const uint64_t l_coarse_rd_cycles = 32;
+ FAPI_DBG("coarse_rd_cycles: %d(%dns)", l_coarse_rd_cycles, mss::cycles_to_ns(i_target, l_coarse_rd_cycles));
+ return l_coarse_rd_cycles;
+}
+
+///
+/// @brief Configure the polling intervals with the proper timeings based on the cal steps enabled
+/// @tparam T, the fapi2::TargetType of the port
+/// @param[in] i_target, the port target
+/// @param[in] the poll_parameters to update
+/// @param[in] a fapi2::buffer<uint8_t> representing the cal steps enabled
+/// @return FAPI2_RC_SUCCESS iff everything is OK
+///
+template<fapi2::TargetType T>
+inline fapi2::ReturnCode cal_timer_setup(const fapi2::Target<T>& i_target,
+ poll_parameters& i_poll,
+ const fapi2::buffer<uint16_t>& i_cal_steps_enabled)
+{
+ // First, calculate the total number of cycles this cal should take if everything
+ // runs to completion
+ uint64_t l_total_cycles = i_cal_steps_enabled.getBit<WR_LEVEL>() ? wr_lvl_cycles(i_target) : 0;
+ l_total_cycles += i_cal_steps_enabled.getBit<DQS_ALIGN>() ? dqs_align_cycles(i_target) : 0;
+ l_total_cycles += i_cal_steps_enabled.getBit<RDCLK_ALIGN>() ? rdclk_align_cycles(i_target) : 0;
+ l_total_cycles += i_cal_steps_enabled.getBit<READ_CTR>() ? read_ctr_cycles(i_target) : 0;
+ l_total_cycles += i_cal_steps_enabled.getBit<WRITE_CTR>() ? write_ctr_cycles(i_target) : 0;
+ l_total_cycles += i_cal_steps_enabled.getBit<COARSE_WR>() ? coarse_wr_cycles(i_target) : 0;
+ l_total_cycles += i_cal_steps_enabled.getBit<COARSE_RD>() ? coarse_rd_cycles(i_target) : 0;
+
+ // Now we have to decide if we're going to abort on an error or keep going. If we keep going,
+ // then we want our initial delay to be the expected time to completion - we don't have much
+ // of a choice. If we abort on error then we want to have a small initial delay, and poll more
+ // times with longer durations between the polling.
+
+#define THRASH_CCS_IP_IN_SIM 1
+#ifdef THRASH_CCS_IP_IN_SIM
+
+ i_poll.iv_initial_delay = mss::cycles_to_ns(i_target, 1);
+ i_poll.iv_initial_sim_delay = mss::cycles_to_simcycles(1);
+
+ i_poll.iv_delay = DELAY_1US;
+ i_poll.iv_sim_delay = mss::cycles_to_simcycles(mss::ns_to_cycles(i_target, DELAY_1US));
+
+ i_poll.iv_poll_count = (mss::cycles_to_ns(i_target, l_total_cycles) - i_poll.iv_initial_delay) / i_poll.iv_delay;
+
+ // Don't let the poll count be 0 - that just makes for a bad day.
+ i_poll.iv_poll_count = (i_poll.iv_poll_count == 0) ? 1 : i_poll.iv_poll_count;
+
+#else
+
+ if (CAL_ABORT_ON_ERROR)
+ {
+ // We don't want to wait too long for the initial check, just some hueristics here
+ i_poll.iv_initial_delay = mss::cycles_to_ns(i_target, l_total_cycles / 8);
+ i_poll.iv_initial_sim_delay = mss::cycles_to_simcycles(l_total_cycles / 8);
+
+ // Delay 1us between polls, and setup the poll count so
+ // iv_initial_delay + (iv_delay * iv_poll_count) == l_total_cycles;
+ i_poll.iv_delay = DELAY_1US;
+ i_poll.iv_sim_delay = mss::cycles_to_simcycles(mss::ns_to_cycles(i_target, DELAY_1US));
+
+ i_poll.iv_poll_count = (mss::cycles_to_ns(i_target, l_total_cycles) - i_poll.iv_initial_delay) / i_poll.iv_delay;
+
+ // Don't let the poll count be 0 - that just makes for a bad day.
+ i_poll.iv_poll_count = (i_poll.iv_poll_count == 0) ? 1 : i_poll.iv_poll_count;
+ }
+ else
+ {
+ i_poll.iv_initial_delay = mss::cycles_to_ns(i_target, l_total_cycles);
+ i_poll.iv_initial_sim_delay = mss::cycles_to_simcycles(l_total_cycles);
+ }
+
+#endif
+
+ FAPI_DBG("cal abort on error? %s. tc: %dc, id: %dns(%dsc), d: %d(%dsc), pc: %d",
+ (CAL_ABORT_ON_ERROR ? "yup" : "nope"), l_total_cycles, i_poll.iv_initial_delay,
+ i_poll.iv_initial_sim_delay, i_poll.iv_delay, i_poll.iv_sim_delay, i_poll.iv_poll_count);
+
+ return fapi2::FAPI2_RC_SUCCESS;
+}
+
+}
+#endif
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
new file mode 100644
index 000000000..cccb0b3e1
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/phy/ddr_phy.C
@@ -0,0 +1,881 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/phy/ddr_phy.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 ddr_phy.C
+/// @brief Subroutines to manipulate the phy, or used during phy procedures
+///
+// *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 <vector>
+#include <initializer_list>
+
+#include <fapi2.H>
+#include "../mss.H"
+
+#include "ddr_phy.H"
+#include "../utils/bit_count.H"
+
+using fapi2::TARGET_TYPE_MCBIST;
+using fapi2::TARGET_TYPE_PROC_CHIP;
+using fapi2::TARGET_TYPE_SYSTEM;
+using fapi2::TARGET_TYPE_MCA;
+using fapi2::TARGET_TYPE_MCS;
+using fapi2::TARGET_TYPE_DIMM;
+
+using fapi2::FAPI2_RC_SUCCESS;
+
+namespace mss
+{
+
+///
+/// @brief Blast one peice of data across a vector of addresses
+/// @param[in] i_target, the target for the scom
+/// @param[in] const std::vector<uint64_t>&, addresses
+/// @param[in] const fapi2::buffer<uint64_t>&, the data to blast
+/// @return FAPI2_RC_SUCCESS iff ok
+/// @note Author is originally from Boston (Pahk mah cah in Havahd Yahd)
+
+/// @note std::transform might have been tidier, but because of the ReturnCode
+/// and the FAPI_TRY mechanism, this is the simplest.
+///
+template< fapi2::TargetType T >
+fapi2::ReturnCode scom_blastah( const fapi2::Target<T>& i_target, const std::vector<uint64_t>& i_addrs,
+ const fapi2::buffer<uint64_t>& i_data )
+{
+ size_t count(0);
+
+ for (auto a : i_addrs)
+ {
+ FAPI_TRY( fapi2::putScom(i_target, a, i_data) );
+ ++count;
+ }
+
+ return fapi2::current_err;
+
+fapi_try_exit:
+ FAPI_ERR( "scom_blastah failed: %d of %d executed against %s", count, i_addrs.size(), mss::c_str(i_target));
+ return fapi2::current_err;
+}
+
+///
+/// @brief Blast one peice of data across a vector of targets
+/// @param[in] the vector of targets for the scom
+/// @param[in] the address
+/// @param[in] const fapi2::buffer<uint64_t>&, the data to blast
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+template< fapi2::TargetType T >
+fapi2::ReturnCode scom_blastah( const std::vector<fapi2::Target<T> >& i_targets, const uint64_t i_addr,
+ const fapi2::buffer<uint64_t>& i_data )
+{
+ size_t count(0);
+
+ for (auto t : i_targets)
+ {
+ FAPI_TRY( fapi2::putScom(t, i_addr, i_data) );
+ ++count;
+ }
+
+ return fapi2::current_err;
+
+fapi_try_exit:
+ FAPI_ERR( "scom_blastah failed: %d of %d written to 0x%llx", count, i_targets.size(), i_addr);
+ return fapi2::current_err;
+}
+
+///
+/// @brief Blast one peice of data across a vector of targets
+/// @param[in] the vector of targets for the scom
+/// @param[in] the vector of addresses
+/// @param[in] const fapi2::buffer<uint64_t>&, the data to blast
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+template< fapi2::TargetType T >
+fapi2::ReturnCode scom_blastah( const std::vector<fapi2::Target<T> >& i_targets,
+ const std::vector<uint64_t>& i_addrs,
+ const fapi2::buffer<uint64_t>& i_data )
+{
+ size_t count(0);
+
+ for (auto t : i_targets)
+ {
+ FAPI_TRY( mss::scom_blastah(t, i_addrs, i_data) );
+ ++count;
+ }
+
+ return fapi2::current_err;
+
+fapi_try_exit:
+ FAPI_ERR( "scom_blastah failed: %d of %dx%d", count, i_targets.size(), i_addrs.size() );
+ return fapi2::current_err;
+}
+
+///
+/// @brief change resetn to the given state
+/// @param[in] i_target, the mcbist
+/// @param[in] the desired state
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+fapi2::ReturnCode change_resetn( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target, states i_state )
+{
+ fapi2::buffer<uint64_t> l_data;
+
+ for (auto p : i_target.getChildren<TARGET_TYPE_MCA>())
+ {
+ FAPI_DBG("Change reset to %s PHY: %s", (i_state == HIGH ? "high" : "low"), mss::c_str(p));
+
+ FAPI_TRY( fapi2::getScom(p, MCA_MBA_CAL0Q, l_data) );
+ i_state == HIGH ? l_data.setBit<MCA_MBA_CAL0Q_RESET_RECOVER>() : l_data.clearBit<MCA_MBA_CAL0Q_RESET_RECOVER>();
+ FAPI_TRY( fapi2::putScom(p, MCA_MBA_CAL0Q, l_data) );
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief perform the zctl toggle process
+/// @param[in] i_target, the mcbist for the reset recover
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+fapi2::ReturnCode toggle_zctl( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target )
+{
+ fapi2::buffer<uint64_t> l_data;
+
+ auto l_ports = i_target.getChildren<TARGET_TYPE_MCA>();
+ //
+ // 4. Write 0x0010 to PC IO PVT N/P FET driver control registers to assert ZCTL reset and enable the internal impedance controller.
+ // (SCOM Addr: 0x8000C0140301143F, 0x8000C0140301183F, 0x8001C0140301143F, 0x8001C0140301183F)
+ FAPI_DBG("Write 0x0010 to PC IO PVT N/P FET driver control registers to assert ZCTL reset");
+ l_data.setBit<59>();
+ FAPI_TRY( mss::scom_blastah(l_ports, MCA_DDRPHY_PC_IO_PVT_FET_CONTROL_P0, l_data) );
+
+ //
+ // 5. Write 0x0018 to PC IO PVT N/P FET driver control registers to deassert ZCTL reset while impedance controller is still enabled.
+ // (SCOM Addr: 0x8000C0140301143F, 0x8000C0140301183F, 0x8001C0140301143F, 0x8001C0140301183F)
+ FAPI_DBG("Write 0x0018 to PC IO PVT N/P FET driver control registers to deassert ZCTL reset.");
+ l_data.setBit<59>().setBit<60>();
+ FAPI_TRY( mss::scom_blastah(l_ports, MCA_DDRPHY_PC_IO_PVT_FET_CONTROL_P0, l_data) );
+
+ //
+ // 6. Write 0x0008 to PC IO PVT N/P FET driver control registers to deassert the impedance controller.
+ // (SCOM Addr: 0x8000C0140301143F, 0x8000C0140301183F, 0x8001C0140301143F, 0x8001C0140301183F)
+
+ FAPI_DBG("Write 0x0008 to PC IO PVT N/P FET driver control registers to deassert the impedance controller");
+ l_data.clearBit<59>().setBit<60>();
+ FAPI_TRY( mss::scom_blastah(l_ports, MCA_DDRPHY_PC_IO_PVT_FET_CONTROL_P0, l_data) );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+/// @brief Change mclk low
+/// @param[in] mcbist target
+/// @param[in] mss::HIGH or mss::LOW - desired state.
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+fapi2::ReturnCode change_force_mclk_low (const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target,
+ const mss::states i_state)
+{
+
+ // Working with Goldade, we learned this:
+ // From John Bailas: 9:49:46 AM: you need to use that force_mclk_low signal, it needs to be asserted which
+ // forces RESETN on, and CK/CKN to 0, and all other address/cmd to Z. Then the MC has to establish valid
+ // values for all signals after PHY reset before force_mclk_low gets de-asserted
+ // And to celar up the ambiguity of "on" <grin>
+ // John S. Bialas Jr: Hi Brian, force_mclk_low should force RESETN, CK, and CK# to 0, and all
+ // other address/command signals to Z
+ // So, this should be enough to get us going. BRS
+
+ // Additionally: from John Bailas
+ // The PHY should be reset and initialized such that it can synchronously control the RESETN, CK, and CKN
+ // to the DIMM, then force_mclk_low can be de-asserted and the control of those signals will be synchronously
+ // maintained. Beyond that the remainder of the DIMM init sequence can be performed, ie. start CK/CKN,
+ // de-assert RESETN, etc
+
+ fapi2::buffer<uint64_t> l_data;
+
+ FAPI_DBG("force mclk %s for all ports", (i_state == mss::LOW ? "low" : "high") );
+
+ // Might as well do this for all the ports while we're here.
+ for (auto p : i_target.getChildren<TARGET_TYPE_MCA>())
+ {
+ FAPI_TRY(fapi2::getScom( p, MCA_MBA_FARB5Q, l_data));
+
+ if (i_state == mss::HIGH)
+ {
+ l_data.setBit<MCA_MBA_FARB5Q_CFG_FORCE_MCLK_LOW_N>();
+ }
+ else
+ {
+ l_data.clearBit<MCA_MBA_FARB5Q_CFG_FORCE_MCLK_LOW_N>();
+ }
+
+ FAPI_TRY(fapi2::putScom( p, MCA_MBA_FARB5Q, l_data));
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+
+///
+/// @brief Unset the PLL and check to see that the PLL's have started
+/// @param[in] the mcbist target
+/// @return FAPI2_RC_SUCCES iff ok
+///
+fapi2::ReturnCode deassert_pll_reset( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target )
+{
+ fapi2::buffer<uint64_t> l_data;
+
+#ifdef KNOW_ADR_DLL_PROCESS
+ static const uint64_t dp16_lock_mask = 0x000000000000FFFE;
+ static const uint64_t ad_lock_mask = fapi2::buffer<uint64_t>().setBit<48>().setBit<49>();
+#endif
+
+ //
+ // Write 0x4000 into the PC Resets Registers. This deasserts the PLL_RESET and leaves the SYSCLK_RESET bit active
+ // (SCOM Addr: 0x8000C00E0301143F, 0x8001C00E0301143F, 0x8000C00E0301183F, 0x8001C00E0301183F)
+ FAPI_DBG("Write 0x4000 into the PC Resets Regs. This deasserts the PLL_RESET and leaves the SYSCLK_RESET bit active");
+
+ l_data.setBit<MCA_DDRPHY_PC_RESETS_P0_SYSCLK_RESET>();
+ FAPI_TRY( mss::scom_blastah(i_target.getChildren<TARGET_TYPE_MCA>(), MCA_DDRPHY_PC_RESETS_P0, l_data) );
+
+ //
+ // Wait at least 1 millisecond to allow the PLLs to lock. Otherwise, poll the PC DP18 PLL Lock Status
+ // and the PC AD32S PLL Lock Status to determine if all PLLs have locked.
+ // PC DP18 PLL Lock Status should be 0xF800: (SCOM Addr: 0x8000C0000301143F, 0x8001C0000301143F, 0x8000C0000301183F, 0x8001C0000301183F)
+ // PC AD32S PLL Lock Status should be 0xC000: (SCOM Addr: 0x8000C0010301143F, 0x8001C0010301143F, 0x8000C0010301183F, 0x8001C0010301183F)
+
+#ifdef KNOW_ADR_DLL_PROCESS
+ // Poll for lock bits
+ FAPI_DBG("Poll until DP18 and AD32S PLLs have locked");
+
+ do
+ {
+ // Set in the CHECK_PLL macro
+ done_polling = true;
+
+ fapi2::delay(DELAY_1US, cycles_to_simcycles(us_to_cycles(i_target, 1)));
+
+ // Note: in the latest scomdef this is DP16 BRS
+ // Note: Not sure what the proper registers here are. I took the following old addresses from Ed's
+ // version of the code and mapped the addresses to the latests mc_scom_addresses.H. This needs to
+ // be fixed up when the extended addressing is fixed up. BRS
+
+ // CONST_UINT64_T(DDRPHY_PC_DP18_PLL_LOCK_STATUS_P0_0x8000C0000701143F, ULL(0x8000C0000701143F) );
+ CHECK_PLL( l_target_proc, MCA_0_DDRPHY_PC_DP18_PLL_LOCK_STATUS_P0, l_data, dp16_lock_mask );
+
+ // CONST_UINT64_T(DDRPHY_PC_DP18_PLL_LOCK_STATUS_P1_0x8001C0000701143F, ULL(0x8001C0000701143F) );
+ CHECK_PLL( l_target_proc, MCA_1_DDRPHY_PC_DP18_PLL_LOCK_STATUS_P1, l_data, dp16_lock_mask );
+
+ // CONST_UINT64_T(DDRPHY_PC_DP18_PLL_LOCK_STATUS_P2_0x8000C0000701183F, ULL(0x8000C0000701183F) );
+ CHECK_PLL( l_target_proc, MCA_2_DDRPHY_PC_DP18_PLL_LOCK_STATUS_P2, l_data, dp16_lock_mask );
+
+ // CONST_UINT64_T(DDRPHY_PC_DP18_PLL_LOCK_STATUS_P3_0x8001C0000701183F, ULL(0x8001C0000701183F) );
+ CHECK_PLL( l_target_proc, MCA_3_DDRPHY_PC_DP18_PLL_LOCK_STATUS_P3, l_data, dp16_lock_mask );
+
+ // CONST_UINT64_T( DDRPHY_PC_AD32S_PLL_LOCK_STATUS_P0_0x8000C0010701143F, ULL(0x8000C0010701143F) );
+ CHECK_PLL( l_target_proc, MCA_0_DDRPHY_PC_AD32S_PLL_LOCK_STATUS_P0, l_data, ad_lock_mask );
+
+ // CONST_UINT64_T( DDRPHY_PC_AD32S_PLL_LOCK_STATUS_P1_0x8001C0010701143F, ULL(0x8001C0010701143F) );
+ CHECK_PLL( l_target_proc, MCA_1_DDRPHY_PC_AD32S_PLL_LOCK_STATUS_P1, l_data, ad_lock_mask );
+
+ // CONST_UINT64_T( DDRPHY_PC_AD32S_PLL_LOCK_STATUS_P2_0x8000C0010701183F, ULL(0x8000C0010701183F) );
+ CHECK_PLL( l_target_proc, MCA_2_DDRPHY_PC_AD32S_PLL_LOCK_STATUS_P2, l_data, ad_lock_mask );
+
+ // CONST_UINT64_T( DDRPHY_PC_AD32S_PLL_LOCK_STATUS_P3_0x8001C0010701183F, ULL(0x8001C0010701183F) );
+ CHECK_PLL( l_target_proc, MCA_3_DDRPHY_PC_AD32S_PLL_LOCK_STATUS_P3, l_data, ad_lock_mask );
+ }
+ while (!done_polling && --max_poll_loops);
+
+ // If we ran out of iterations, report we have a pll lock failure.
+ if (max_poll_loops == 0)
+ {
+ FAPI_ERR("DDR PHY PLL failed to lock for %s", mss::c_str(i_target));
+ FFDC_PLL( l_target_proc, MCA_0_DDRPHY_PC_DP18_PLL_LOCK_STATUS_P0, l_data, dp16_lock_mask,
+ fapi2::MSS_DP16_PLL_FAILED_TO_LOCK() );
+ FFDC_PLL( l_target_proc, MCA_1_DDRPHY_PC_DP18_PLL_LOCK_STATUS_P1, l_data, dp16_lock_mask,
+ fapi2::MSS_DP16_PLL_FAILED_TO_LOCK() );
+ FFDC_PLL( l_target_proc, MCA_2_DDRPHY_PC_DP18_PLL_LOCK_STATUS_P2, l_data, dp16_lock_mask,
+ fapi2::MSS_DP16_PLL_FAILED_TO_LOCK() );
+ FFDC_PLL( l_target_proc, MCA_3_DDRPHY_PC_DP18_PLL_LOCK_STATUS_P3, l_data, dp16_lock_mask,
+ fapi2::MSS_DP16_PLL_FAILED_TO_LOCK() );
+
+ FFDC_PLL( l_target_proc, MCA_0_DDRPHY_PC_AD32S_PLL_LOCK_STATUS_P0, l_data, ad_lock_mask,
+ fapi2::MSS_AD32S_PLL_FAILED_TO_LOCK() );
+ FFDC_PLL( l_target_proc, MCA_1_DDRPHY_PC_AD32S_PLL_LOCK_STATUS_P1, l_data, ad_lock_mask,
+ fapi2::MSS_AD32S_PLL_FAILED_TO_LOCK() );
+ FFDC_PLL( l_target_proc, MCA_2_DDRPHY_PC_AD32S_PLL_LOCK_STATUS_P2, l_data, ad_lock_mask,
+ fapi2::MSS_AD32S_PLL_FAILED_TO_LOCK() );
+ FFDC_PLL( l_target_proc, MCA_3_DDRPHY_PC_AD32S_PLL_LOCK_STATUS_P3, l_data, ad_lock_mask,
+ fapi2::MSS_AD32S_PLL_FAILED_TO_LOCK() );
+ }
+
+#endif
+fapi_try_exit:
+ return fapi2::current_err;
+
+}
+
+///
+/// @brief Setup the phase rotator control registers
+/// @param[in] the mcbist target
+/// @param[in] the value for the registers
+/// @return FAPI2_RC_SUCCES iff ok
+///
+fapi2::ReturnCode setup_phase_rotator_control_registers( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target,
+ const fapi2::buffer<uint64_t>& i_data )
+{
+ FAPI_DBG("Write 0x%lx into the ADR SysClk Phase Rotator Control Regs and the DP18 SysClk Phase Rotator Control Regs",
+ i_data);
+
+ std::vector<uint64_t> addrs(
+ {
+ MCA_DDRPHY_ADR_SYSCLK_CNTL_PR_P0_ADR32S0, MCA_DDRPHY_ADR_SYSCLK_CNTL_PR_P0_ADR32S1,
+ MCA_DDRPHY_DP16_WRCLK_PR_P0_0, MCA_DDRPHY_DP16_WRCLK_PR_P0_1,
+ MCA_DDRPHY_DP16_WRCLK_PR_P0_2, MCA_DDRPHY_DP16_WRCLK_PR_P0_3, MCA_DDRPHY_DP16_WRCLK_PR_P0_4,
+ } );
+
+ FAPI_TRY( mss::scom_blastah(i_target.getChildren<TARGET_TYPE_MCA>(), addrs, i_data) );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Deassetr the sys clk reset
+/// @param[in] the mcbist target
+/// @return FAPI2_RC_SUCCES iff ok
+///
+fapi2::ReturnCode deassert_sysclk_reset( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target )
+{
+ FAPI_DBG("Write 0x0000 into the PC Resets Register. This deasserts the SysClk Reset.");
+ FAPI_TRY( mss::scom_blastah(i_target.getChildren<TARGET_TYPE_MCA>(), MCA_DDRPHY_PC_RESETS_P0, 0) );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Flush the DDR PHY
+/// @param[in] the mcbist target
+/// @return FAPI2_RC_SUCCES iff ok
+///
+fapi2::ReturnCode ddr_phy_flush( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target )
+{
+ fapi2::buffer<uint64_t> l_data;
+ fapi2::buffer<uint64_t> l_mask;
+
+ FAPI_INF( "Performing mss_ddr_phy_flush routine" );
+
+ FAPI_INF("ADR/DP18 FLUSH: 1) set PC_POWERDOWN_1 register, powerdown enable(48), flush bit(58)");
+ // set MASTER_PD_CNTL bit set WR_FIFO_STAB bit
+ l_data.setBit<48>().setBit<58>();
+ l_mask.setBit<48>().setBit<58>();
+
+ auto l_ports = i_target.getChildren<TARGET_TYPE_MCA>();
+
+ for (auto p : l_ports)
+ {
+ FAPI_TRY(fapi2::putScomUnderMask(p, MCA_DDRPHY_PC_POWERDOWN_1_P0, l_data, l_mask) );
+ }
+
+ fapi2::delay(DELAY_100NS, cycles_to_simcycles(ns_to_cycles(i_target, 100)));
+
+ FAPI_INF("ADR/DP18 FLUSH: 2) clear PC_POWERDOWN_1 register, powerdown enable(48), flush bit(58)");
+
+ for (auto p : l_ports)
+ {
+ FAPI_TRY(fapi2::putScomUnderMask(p, MCA_DDRPHY_PC_POWERDOWN_1_P0, 0, l_mask) );
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Send a scom to all instances of a block on the phy.
+/// @param[in] the MCA target
+/// @param[in] the address
+/// @param[in] the value
+/// @note this iterates creating addresses - needs to change to use the
+/// braodcast bits in the phy when we can scom it directly.
+///
+static inline fapi2::ReturnCode phy_block_broadcast( const fapi2::Target<TARGET_TYPE_MCA>& i_target,
+ const uint64_t l_addr,
+ const fapi2::buffer<uint64_t> i_data)
+{
+#ifndef BROADSIDE_SCOM_ONLY
+ static const size_t PHY_INSTANCE_COUNT = 5;
+
+ // We have to use a dull knife since broadisde scom has to have the address in
+ // the scomdef. When we get a full system model (or the PIE driver supports scomming
+ // the PHY) we can use the broadcast bits and iterate over the DIMM ranks.
+ for (size_t i = 0; i < PHY_INSTANCE_COUNT; ++i)
+ {
+ FAPI_TRY( fapi2::putScom(i_target, l_addr | fapi2::buffer<uint64_t>().insertFromRight<18, 4>(i), i_data) );
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+#endif
+}
+
+///
+/// @brief Lock dphy_gckn and sysclk
+/// @param[in] a port target
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+fapi2::ReturnCode bang_bang_lock( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target )
+{
+ fapi2::buffer<uint64_t> l_start_update(0x8024);
+ fapi2::buffer<uint64_t> l_stop_update(0x8020);
+
+ // Per Bialas, we don't want to do true alignment in the cycle sim as we have
+ // a chnace of being off one-tick (which is detremental.) Per his recomendations,
+ // we write 0's to the control registers and then configure them with x8080.
+ uint8_t is_sim = 0;
+ FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_IS_SIMULATION, fapi2::Target<TARGET_TYPE_SYSTEM>(), is_sim) );
+
+ if (is_sim)
+ {
+ l_start_update = 0x0;
+ l_stop_update = 0x8080;
+ }
+
+ // 9.
+ FAPI_TRY( mss::setup_phase_rotator_control_registers(i_target, l_start_update),
+ "set up of phase rotator controls failed (in to cont update) %s", mss::c_str(i_target) );
+
+ //
+ // 10.Wait at least 5932 memory clock cycles to allow the clock alignment circuit to perform initial alignment.
+ // wait 2000 simcycles per Ed Maj,
+ FAPI_DBG("Wait at least 5932 memory clock cycles to allow the clock alignment circuit to perform initial alignment");
+ FAPI_TRY( fapi2::delay(mss::cycles_to_ns(i_target, 5932), 2000) );
+
+ //
+ // 11.Write 0x0000 into the PC Resets Register. This deasserts the SysClk Reset
+ // (SCOM Addr: 0x8000C00E0301143F, 0x8001C00E0301143F, 0x8000C00E0301183F, 0x8001C00E0301183F)
+ FAPI_TRY( mss::deassert_sysclk_reset(i_target), "deassert_sysclk_reset failed for %s", mss::c_str(i_target) );
+
+ // 12.
+ FAPI_TRY( mss::setup_phase_rotator_control_registers(i_target, l_stop_update),
+ "set up of phase rotator controls failed (out of cont update) %s", mss::c_str(i_target) );
+
+ // 13.
+ FAPI_DBG("Wait at least 32 memory clock cycles");
+ FAPI_TRY( fapi2::delay(mss::cycles_to_ns(i_target, 32), mss::cycles_to_simcycles(32)) );
+
+ // Don't bother in cycle sim, we don't do the actual aligment
+ if (!is_sim)
+ {
+ // Check for BB lock.
+ for (auto p : i_target.getChildren<TARGET_TYPE_MCA>())
+ {
+ FAPI_DBG("Wait for BB lock in status register, bit %u",
+ MCA_DDRPHY_ADR_SYSCLK_PR_VALUE_RO_P0_ADR32S0_ADR0_BB_LOCK);
+
+ FAPI_ASSERT( mss::poll(p, 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
+ {
+ FAPI_DBG("stat_reg 0x%llx, remaining: %d", stat_reg, poll_remaining);
+ return stat_reg.getBit<MCA_DDRPHY_ADR_SYSCLK_PR_VALUE_RO_P0_ADR32S0_ADR0_BB_LOCK>();
+ }),
+ fapi2::MSS_BANG_BANG_FAILED_TO_LOCK().set_MCA_IN_ERROR(p),
+ "MCA %s failed bang-bang alignment", mss::c_str(p) );
+ }
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Return the DIMM target for the primary rank in the specificed rank pair
+/// @param[in] the MCA target
+/// @param[in] the rank pair
+/// @param[out] fapi2::Target<TARGET_TYPE_DIMM>
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+template<>
+fapi2::ReturnCode rank_pair_primary_to_dimm(
+ const fapi2::Target<TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_rp,
+ fapi2::Target<TARGET_TYPE_DIMM>& o_dimm)
+{
+ fapi2::buffer<uint64_t> l_data;
+ fapi2::buffer<uint64_t> l_rank;
+ uint64_t l_rank_on_dimm;
+ auto l_dimms = i_target.getChildren<TARGET_TYPE_DIMM>();
+
+ // Sanity check the rank pair
+ FAPI_INF("%s rank pair: %d", mss::c_str(i_target), i_rp);
+
+ fapi2::Assert(i_rp < MAX_RANK_PER_DIMM);
+
+ // We need to get the register containing the specification for this rank pair,
+ // and fish out the primary rank for this rank pair
+ switch(i_rp)
+ {
+ case 0:
+ FAPI_TRY( fapi2::getScom(i_target, MCA_DDRPHY_PC_RANK_PAIR0_P0, l_data) );
+ l_data.extractToRight<MCA_DDRPHY_PC_RANK_PAIR0_P0_PRI,
+ MCA_DDRPHY_PC_RANK_PAIR0_P0_PRI_LEN>(l_rank);
+ break;
+
+ case 1:
+ FAPI_TRY( fapi2::getScom(i_target, MCA_DDRPHY_PC_RANK_PAIR0_P0, l_data) );
+ l_data.extractToRight<MCA_DDRPHY_PC_RANK_PAIR0_P0_PAIR1_PRI,
+ MCA_DDRPHY_PC_RANK_PAIR0_P0_PAIR1_PRI_LEN>(l_rank);
+ break;
+
+ case 2:
+ FAPI_TRY( fapi2::getScom(i_target, MCA_DDRPHY_PC_RANK_PAIR1_P0, l_data) );
+ l_data.extractToRight<MCA_DDRPHY_PC_RANK_PAIR1_P0_PAIR2_PRI,
+ MCA_DDRPHY_PC_RANK_PAIR1_P0_PAIR2_PRI_LEN>(l_rank);
+ break;
+
+ case 3:
+ FAPI_TRY( fapi2::getScom(i_target, MCA_DDRPHY_PC_RANK_PAIR1_P0, l_data) );
+ l_data.extractToRight<MCA_DDRPHY_PC_RANK_PAIR1_P0_PAIR3_PRI,
+ MCA_DDRPHY_PC_RANK_PAIR1_P0_PAIR3_PRI_LEN>(l_rank);
+ break;
+ };
+
+ // Now we need to figure out which DIMM this rank is on. It's either on DIMM0 or DIMM1, and DIMM0
+ // has ranks 0-3 and DIMM1 has ranks 4-7. Return the DIMM associated.
+ l_rank_on_dimm = get_dimm_from_rank(l_rank);
+
+ // Sanity check the DIMM list
+ FAPI_INF("%s rank is on dimm: %d, number of dimms: %d", mss::c_str(i_target), l_rank_on_dimm, l_dimms.size());
+
+ fapi2::Assert(l_rank_on_dimm < l_dimms.size());
+
+ o_dimm = l_dimms[l_rank_on_dimm];
+
+ return FAPI2_RC_SUCCESS;
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief check and process initial cal errors
+/// @param[in] the port in question
+/// @return fapi2::ReturnCode, FAPI2_RC_SUCCESS iff no error
+///
+template<>
+fapi2::ReturnCode process_initial_cal_errors( const fapi2::Target<TARGET_TYPE_MCA>& i_target )
+{
+ static const uint64_t init_cal_err_mask = 0x7FF;
+
+ uint64_t l_errors = 0;
+ uint64_t l_rank_pairs = 0;
+
+ fapi2::buffer<uint64_t> l_fir_data;
+ fapi2::buffer<uint64_t> l_err_data;
+
+ fapi2::Target<TARGET_TYPE_DIMM> l_failed_dimm;
+
+ FAPI_TRY( fapi2::getScom(i_target, MCA_DDRPHY_APB_FIR_ERR1_P0, l_fir_data) );
+
+ FAPI_DBG("initial cal FIR: 0x%016llx", uint64_t(l_fir_data));
+
+ if ((init_cal_err_mask & l_fir_data) == 0)
+ {
+ return FAPI2_RC_SUCCESS;
+ }
+
+ // We have bits to check ...
+ FAPI_TRY( fapi2::getScom(i_target, MCA_DDRPHY_PC_INIT_CAL_ERROR_P0, l_err_data) );
+
+ l_err_data.extractToRight<MCA_DDRPHY_PC_INIT_CAL_ERROR_P0_WR_LEVEL, 11>(l_errors);
+ l_err_data.extractToRight<MCA_DDRPHY_PC_INIT_CAL_ERROR_P0_RANK_PAIR,
+ MCA_DDRPHY_PC_INIT_CAL_ERROR_P0_RANK_PAIR_LEN>(l_rank_pairs);
+ FAPI_DBG("initial cal err: 0x%016llx, rp: 0x%016llx (0x%016llx)", l_errors, l_rank_pairs, uint64_t(l_err_data));
+
+ if ((l_rank_pairs == 0) || (l_errors == 0))
+ {
+ FAPI_INF("Initial CAL FIR is 0x%016llx but missing info in the error register: 0x%016llx",
+ l_fir_data, l_err_data);
+ return FAPI2_RC_SUCCESS;
+ }
+
+ // Get the DIMM which failed. We should only have one rank pair as we calibrate the
+ // rank pairs individually (we do this so we can see which DIMM failed if more than one
+ // fails ...) Note first_bit_set gives a bit position (0 being left most.) So, the rank
+ // in question is the bit postion minus the position of the 0th rank in the register.
+ // (the rank bits are bits 60:63, for example, so rank 0 is in position 60)
+ FAPI_TRY( mss::rank_pair_primary_to_dimm(i_target,
+ mss::first_bit_set(l_rank_pairs) - MCA_DDRPHY_PC_INIT_CAL_ERROR_P0_RANK_PAIR,
+ l_failed_dimm) );
+ FAPI_ERR("initial cal failed for %s", mss::c_str(l_failed_dimm));
+
+ // So we can do a few things here. If we're aborting on the first calibration error,
+ // we only expect to have one error bit set. If we ran all the calibrations, we can
+ // either have one bit set or more than one bit set. If we have more than one bit set
+ // the result is the same - a broken DIMM which will be deconfigured. So put enough
+ // information in the FFDC for the lab but we don't need one error for every cal fail.
+ FAPI_ASSERT(mss::bit_count(l_errors) == 1,
+ fapi2::MSS_DRAMINIT_TRAINING_MULTIPLE_ERRORS()
+ .set_FAILED_STEPS(uint64_t(l_err_data))
+ .set_PORT_POSITION(mss::pos(i_target))
+ .set_RANKGROUP_POSITION(l_rank_pairs)
+ .set_TARGET_IN_ERROR(l_failed_dimm),
+ "Initial CAL failed multiple training steps. dimm: %s, cal err: 0x%016llx",
+ mss::c_str(l_failed_dimm), uint64_t(l_err_data)
+ );
+
+ FAPI_ASSERT( ! l_err_data.getBit<MCA_DDRPHY_PC_INIT_CAL_ERROR_P0_WR_LEVEL>(),
+ fapi2::MSS_DRAMINIT_TRAINING_WR_LVL_ERROR()
+ .set_PORT_POSITION(mss::pos(i_target))
+ .set_RANKGROUP_POSITION(l_rank_pairs)
+ .set_TARGET_IN_ERROR(l_failed_dimm),
+ "Initial CAL failed write leveling. dimm: %s, cal err: 0x%016llx",
+ mss::c_str(l_failed_dimm), uint64_t(l_err_data)
+ );
+
+ FAPI_ASSERT( ! l_err_data.getBit<MCA_DDRPHY_PC_INIT_CAL_ERROR_P0_INITIAL_PAT_WRITE>(),
+ fapi2::MSS_DRAMINIT_TRAINING_INITIAL_PAT_WRITE_ERROR()
+ .set_PORT_POSITION(mss::pos(i_target))
+ .set_RANKGROUP_POSITION(l_rank_pairs)
+ .set_TARGET_IN_ERROR(l_failed_dimm),
+ "Initial CAL failed initial pattern write. dimm: %s, cal err: 0x%016llx",
+ mss::c_str(l_failed_dimm), uint64_t(l_err_data)
+ );
+
+ FAPI_ASSERT( ! l_err_data.getBit<MCA_DDRPHY_PC_INIT_CAL_ERROR_P0_DQS_ALIGN>(),
+ fapi2::MSS_DRAMINIT_TRAINING_DQS_ALIGNMENT_ERROR()
+ .set_PORT_POSITION(mss::pos(i_target))
+ .set_RANKGROUP_POSITION(l_rank_pairs)
+ .set_TARGET_IN_ERROR(l_failed_dimm),
+ "Initial CAL failed DQS alignenment. dimm: %s, cal err: 0x%016llx",
+ mss::c_str(l_failed_dimm), uint64_t(l_err_data)
+ );
+
+ FAPI_ASSERT( ! l_err_data.getBit<MCA_DDRPHY_PC_INIT_CAL_ERROR_P0_RDCLK_ALIGN>(),
+ fapi2::MSS_DRAMINIT_TRAINING_RD_CLK_SYS_CLK_ALIGNMENT_ERROR()
+ .set_PORT_POSITION(mss::pos(i_target))
+ .set_RANKGROUP_POSITION(l_rank_pairs)
+ .set_TARGET_IN_ERROR(l_failed_dimm),
+ "Initial CAL failed read clk alignenment. dimm: %s, cal err: 0x%016llx",
+ mss::c_str(l_failed_dimm), uint64_t(l_err_data)
+ );
+
+ FAPI_ASSERT( ! l_err_data.getBit<MCA_DDRPHY_PC_INIT_CAL_ERROR_P0_READ_CTR>(),
+ fapi2::MSS_DRAMINIT_TRAINING_RD_CENTERING_ERROR()
+ .set_PORT_POSITION(mss::pos(i_target))
+ .set_RANKGROUP_POSITION(l_rank_pairs)
+ .set_TARGET_IN_ERROR(l_failed_dimm),
+ "Initial CAL failed read centering. dimm: %s, cal err: 0x%016llx",
+ mss::c_str(l_failed_dimm), uint64_t(l_err_data)
+ );
+
+ FAPI_ASSERT( ! l_err_data.getBit<MCA_DDRPHY_PC_INIT_CAL_ERROR_P0_WRITE_CTR>(),
+ fapi2::MSS_DRAMINIT_TRAINING_WR_CENTERING_ERROR()
+ .set_PORT_POSITION(mss::pos(i_target))
+ .set_RANKGROUP_POSITION(l_rank_pairs)
+ .set_TARGET_IN_ERROR(l_failed_dimm),
+ "Initial CAL failed write centering. dimm: %s, cal err: 0x%016llx",
+ mss::c_str(l_failed_dimm), uint64_t(l_err_data)
+ );
+
+ FAPI_ASSERT( ! l_err_data.getBit<MCA_DDRPHY_PC_INIT_CAL_ERROR_P0_INITIAL_COARSE_WR>(),
+ fapi2::MSS_DRAMINIT_TRAINING_INITIAL_COARSE_WR_ERROR()
+ .set_PORT_POSITION(mss::pos(i_target))
+ .set_RANKGROUP_POSITION(l_rank_pairs)
+ .set_TARGET_IN_ERROR(l_failed_dimm),
+ "Initial CAL failed initial coarse write. dimm: %s, cal err: 0x%016llx",
+ mss::c_str(l_failed_dimm), uint64_t(l_err_data)
+ );
+
+ FAPI_ASSERT( ! l_err_data.getBit<MCA_DDRPHY_PC_INIT_CAL_ERROR_P0_COARSE_RD>(),
+ fapi2::MSS_DRAMINIT_TRAINING_COARSE_RD_ERROR()
+ .set_PORT_POSITION(mss::pos(i_target))
+ .set_RANKGROUP_POSITION(l_rank_pairs)
+ .set_TARGET_IN_ERROR(l_failed_dimm),
+ "Initial CAL failed coarse read. dimm: %s, cal err: 0x%016llx",
+ mss::c_str(l_failed_dimm), uint64_t(l_err_data)
+ );
+
+ FAPI_ASSERT( ! l_err_data.getBit<MCA_DDRPHY_PC_INIT_CAL_ERROR_P0_CUSTOM_RD>(),
+ fapi2::MSS_DRAMINIT_TRAINING_CUSTOM_PATTERN_RD_ERROR()
+ .set_PORT_POSITION(mss::pos(i_target))
+ .set_RANKGROUP_POSITION(l_rank_pairs)
+ .set_TARGET_IN_ERROR(l_failed_dimm),
+ "Initial CAL failed custom read. dimm: %s, cal err: 0x%016llx",
+ mss::c_str(l_failed_dimm), uint64_t(l_err_data)
+ );
+
+ FAPI_ASSERT( ! l_err_data.getBit<MCA_DDRPHY_PC_INIT_CAL_ERROR_P0_CUSTOM_WR>(),
+ fapi2::MSS_DRAMINIT_TRAINING_CUSTOM_PATTERN_WR_ERROR()
+ .set_PORT_POSITION(mss::pos(i_target))
+ .set_RANKGROUP_POSITION(l_rank_pairs)
+ .set_TARGET_IN_ERROR(l_failed_dimm),
+ "Initial CAL failed custom write. dimm: %s, cal err: 0x%016llx",
+ mss::c_str(l_failed_dimm), uint64_t(l_err_data)
+ );
+
+ FAPI_ASSERT( ! l_err_data.getBit<MCA_DDRPHY_PC_INIT_CAL_ERROR_P0_DIGITAL_EYE>(),
+ fapi2::MSS_DRAMINIT_TRAINING_DIGITAL_EYE_ERROR()
+ .set_PORT_POSITION(mss::pos(i_target))
+ .set_RANKGROUP_POSITION(l_rank_pairs)
+ .set_TARGET_IN_ERROR(l_failed_dimm),
+ "Initial CAL failed digital eye. dimm: %s, cal err: 0x%016llx",
+ mss::c_str(l_failed_dimm), uint64_t(l_err_data)
+ );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Setup the PC CONFIG0 register
+/// @tparam T the fapi2::TargetType
+/// @param[in] the target (MCA or MBA?)
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+template<>
+fapi2::ReturnCode set_pc_config0(const fapi2::Target<TARGET_TYPE_MCA>& i_target)
+{
+ fapi2::buffer<uint64_t> l_data;
+ FAPI_TRY( fapi2::getScom(i_target, MCA_DDRPHY_PC_CONFIG0_P0, l_data) );
+
+ // Note: This needs to get the DRAM gen from an attribute. - 0x1 is DDR4 Note for Nimbus PHY
+ // this is ignored and hard-wired to DDR4, per John Bialas 10/15 BRS
+ l_data.insertFromRight<MCA_DDRPHY_PC_CONFIG0_P0_PROTOCOL, MCA_DDRPHY_PC_CONFIG0_P0_PROTOCOL_LEN>(0x1);
+
+ l_data.setBit<MCA_DDRPHY_PC_CONFIG0_P0_DDR4_CMD_SIG_REDUCTION>();
+ l_data.setBit<MCA_DDRPHY_PC_CONFIG0_P0_DDR4_VLEVEL_BANK_GROUP>();
+
+ FAPI_DBG("phy pc_config0 0x%0llx", l_data);
+ FAPI_TRY( fapi2::putScom(i_target, MCA_DDRPHY_PC_CONFIG0_P0, l_data) );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Setup the PC CONFIG1 register
+/// @tparam T the fapi2::TargetType
+/// @param[in] the target (MCA or MBA?)
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+template<>
+fapi2::ReturnCode set_pc_config1(const fapi2::Target<TARGET_TYPE_MCA>& i_target)
+{
+ // Static table of PHY config values for MEMORY_TYPE.
+ // [EMPTY, RDIMM, CDIMM, or LRDIMM][EMPTY, DDR3 or DDR4]
+ static const uint64_t memory_type[4][3] =
+ {
+ { 0, 0, 0 }, // Empty, never really used.
+ { 0, 0b001, 0b101 }, // RDIMM
+ { 0, 0b000, 0b000 }, // CDIMM
+ { 0, 0b011, 0b111 }, // LRDIMM
+ };
+
+ fapi2::buffer<uint64_t> l_data;
+
+ uint8_t l_rlo = 0;
+ uint8_t l_wlo = 0;
+ uint8_t l_dram_gen[MAX_DIMM_PER_PORT] = {0};
+ uint8_t l_dimm_type[MAX_DIMM_PER_PORT] = {0};
+ uint8_t l_custom_dimm[MAX_DIMM_PER_PORT] = {0};
+ uint8_t l_type_index = 0;
+ uint8_t l_gen_index = 0;
+
+ FAPI_TRY( mss::vpd_rlo(i_target, l_rlo) );
+ FAPI_TRY( mss::vpd_wlo(i_target, l_wlo) );
+ FAPI_TRY( mss::eff_dram_gen(i_target, &(l_dram_gen[0])) );
+ FAPI_TRY( mss::eff_dimm_type(i_target, &(l_dimm_type[0])) );
+ FAPI_TRY( mss::eff_custom_dimm(i_target, &(l_custom_dimm[0])) );
+
+ // There's no way to configure the PHY for more than one value. However, we don't know if there's
+ // a DIMM in one slot, the other or double drop. So we do a little gyration here to make sure
+ // we have one of the two values (and assume effective config caught a bad config.)
+ l_type_index = (l_custom_dimm[0] | l_custom_dimm[1]) == fapi2::ENUM_ATTR_EFF_CUSTOM_DIMM_YES ?
+ 2 : l_dimm_type[0] | l_dimm_type[1];
+ l_gen_index = l_dram_gen[0] | l_dram_gen[1];
+
+ // FOR NIMBUS PHY (as the protocol choice above is) BRS
+ FAPI_TRY( fapi2::getScom(i_target, MCA_DDRPHY_PC_CONFIG1_P0, l_data) );
+
+ l_data.insertFromRight<MCA_DDRPHY_PC_CONFIG1_P0_MEMORY_TYPE,
+ MCA_DDRPHY_PC_CONFIG1_P0_MEMORY_TYPE_LEN>(memory_type[l_type_index][l_gen_index]);
+ l_data.insertFromRight<MCA_DDRPHY_PC_CONFIG1_P0_READ_LATENCY_OFFSET,
+ MCA_DDRPHY_PC_CONFIG1_P0_READ_LATENCY_OFFSET_LEN>(l_rlo);
+ l_data.insertFromRight<MCA_DDRPHY_PC_CONFIG1_P0_WRITE_LATENCY_OFFSET,
+ MCA_DDRPHY_PC_CONFIG1_P0_WRITE_LATENCY_OFFSET_LEN>(l_wlo);
+
+ l_data.setBit<MCA_DDRPHY_PC_CONFIG1_P0_DDR4_LATENCY_SW>();
+
+ FAPI_DBG("phy pc_config1 0x%0llx", l_data);
+ FAPI_TRY( fapi2::putScom(i_target, MCA_DDRPHY_PC_CONFIG1_P0, l_data) );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Perform initializations for the PHY
+/// @param[in] i_target, the MCBIST which has the PHYs to initialize
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+fapi2::ReturnCode phy_scominit(const fapi2::Target<TARGET_TYPE_MCBIST>& i_target)
+{
+ // Returned from set_rank_pairs, it tells us how many rank pairs we configured on this port.
+ std::vector<uint64_t> l_pairs;
+
+ for( auto p : i_target.getChildren<TARGET_TYPE_MCA>())
+ {
+ // The following registers must be configured to the correct operating environment:
+
+ // Undocumented, noted by Bialas
+ FAPI_TRY( mss::set_pc_config0(p) );
+ FAPI_TRY( mss::set_pc_config1(p) );
+
+ // Section 5.2.1.3 PC Rank Pair 0 on page 177
+ // Section 5.2.1.4 PC Rank Pair 1 on page 179
+ FAPI_TRY( mss::set_rank_pairs(p) );
+
+ // Section 5.2.4.1 DP16 Data Bit Enable 0 on page 284
+ // Section 5.2.4.2 DP16 Data Bit Enable 1 on page 285
+ // Section 5.2.4.3 DP16 Data Bit Disable 0 on page 288
+ // Section 5.2.4.4 DP16 Data Bit Disable 1 on page 289
+ FAPI_TRY( mss::dp16::write_data_bit_enable(p) );
+ FAPI_TRY( mss::dp16::set_bad_bits(p) );
+
+ FAPI_TRY( mss::get_rank_pairs(p, l_pairs) );
+
+ // Section 5.2.4.8 DP16 Write Clock Enable & Clock Selection on page 301
+ FAPI_TRY( mss::dp16::write_clock_enable(p, l_pairs) );
+ FAPI_TRY( mss::dp16::read_clock_enable(p, l_pairs) );
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+}
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/phy/ddr_phy.H b/src/import/chips/p9/procedures/hwp/memory/lib/phy/ddr_phy.H
new file mode 100644
index 000000000..dd7ee3fa4
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/phy/ddr_phy.H
@@ -0,0 +1,832 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/phy/ddr_phy.H $ */
+/* */
+/* 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 ddr_phy.H
+/// @brief Subroutines to manipulate the phy, or used during phy procedures
+///
+// *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
+
+#ifndef _MSS_DDR_PHY_H_
+#define _MSS_DDR_PHY_H_
+
+#include <fapi2.H>
+#include <mss_attribute_accessors.H>
+
+// Helper macro to condense the checking for PLL lock
+#define CHECK_PLL( __target, __register, __buffer, __mask ) \
+ FAPI_TRY(fapi2::getScom( __target, __register, __buffer)); \
+ if ((__buffer & __mask) != __mask) \
+ { \
+ FAPI_INF("PLL 0x%lx failed to lock 0x%lx", __register, __buffer); \
+ done_polling = false; \
+ continue; \
+ }
+
+// Helper macro to condense the checking for PLL lock
+#define FFDC_PLL( __target, __register, __buffer, __mask, __ffdc_object ) \
+ FAPI_ASSERT( ((__buffer & __mask) == __mask), \
+ __ffdc_object.set_EXPECTED_STATUS(__mask) \
+ .set_ACTUAL_STATUS(__buffer) \
+ .set_REGISTER(__register) \
+ .set_MCBIST_IN_ERROR(__target), \
+ "PLL 0x%llx failed to lock 0x%llx", __register, __buffer);
+
+namespace mss
+{
+
+///
+/// @brief Perform initializations for the PHY
+/// @param[in] i_target, the MCBIST which has the PHYs to initialize
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+fapi2::ReturnCode phy_scominit(const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target);
+
+///
+/// @brief change resetn to the given state
+/// @param[in] i_target, the mcbist
+/// @param[in] the desired state
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+fapi2::ReturnCode change_resetn( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target, states i_state );
+
+///
+/// @brief perform the zctl toggle process
+/// @param[in] i_target, the mcbist for the reset recover
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+fapi2::ReturnCode toggle_zctl( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target );
+
+/// @brief Change mclk low
+/// @param[in] mcbist target
+/// @param[in] mss::HIGH or mss::LOW - desired state.
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+fapi2::ReturnCode change_force_mclk_low (const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target,
+ const mss::states i_state);
+///
+/// @brief Unset the PLL and check to see that the PLL's have started
+/// @param[in] the mcbist target
+/// @return FAPI2_RC_SUCCES iff ok
+///
+fapi2::ReturnCode deassert_pll_reset( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target );
+
+///
+/// @brief Setup the phase rotator control registers
+/// @param[in] the mcbist target
+/// @param[in] the value for the registers
+/// @return FAPI2_RC_SUCCES iff ok
+///
+fapi2::ReturnCode setup_phase_rotator_control_registers( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target,
+ const fapi2::buffer<uint64_t>& i_data );
+
+///
+/// @brief Deassetr the sys clk reset
+/// @param[in] the mcbist target
+/// @return FAPI2_RC_SUCCES iff ok
+///
+fapi2::ReturnCode deassert_sysclk_reset( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target );
+
+///
+/// @brief Flush the DDR PHY
+/// @param[in] the mcbist target
+/// @return FAPI2_RC_SUCCES iff ok
+///
+fapi2::ReturnCode ddr_phy_flush( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target );
+
+///
+/// @brief Reset the training delay configureation
+/// @param[in] the mcbist target
+/// @return FAPI2_RC_SUCCES iff ok
+///
+fapi2::ReturnCode reset_delay_values( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target );
+
+///
+/// @brief Lock dphy_gckn and sysclk
+/// @param[in] a MCBIST target
+/// @return FAPI2_RC_SUCCESs iff ok
+///
+fapi2::ReturnCode bang_bang_lock( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target );
+
+///
+/// @brief Configure the DP16 sysclk
+/// @param[in] a MCBIST target
+/// @return FAPI2_RC_SUCCESs iff ok
+///
+fapi2::ReturnCode setup_dp16_sysclk( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target );
+
+///
+/// @brief check and process initial cal errors
+/// @tparam T, the type of the target in question
+/// @param[in] the port in question
+/// @return fapi2::ReturnCode, FAPI2_RC_SUCCESS iff no error
+///
+template< fapi2::TargetType T >
+fapi2::ReturnCode process_initial_cal_errors( const fapi2::Target<T>& i_target );
+
+///
+/// @brief Dump all the cal config registers
+/// @tparam T, the target type of the MCA/MBA
+/// @param[in] the target associated with this cal setup
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+///
+template< fapi2::TargetType T >
+inline fapi2::ReturnCode dump_cal_registers( const fapi2::Target<T>& i_target );
+
+///
+/// @brief Dump all the cal config registers
+/// @param[in] the MCA target associated with this cal setup
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+///
+template<>
+inline fapi2::ReturnCode dump_cal_registers( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target )
+{
+ // Note: Can we wrap this in an ifdef DEBUG or something? BRS
+ static const std::vector< std::pair<uint64_t, char const*> > l_registers =
+ {
+ { MCA_DDRPHY_PC_INIT_CAL_STATUS_P0, "PC_INIT_CAL_STATUS" },
+ { MCA_DDRPHY_PC_INIT_CAL_ERROR_P0, "PC_INIT_CAL_ERROR" },
+ { MCA_DDRPHY_PC_INIT_CAL_CONFIG0_P0, "PC_INIT_CAL_CONFIG0" },
+ { MCA_DDRPHY_PC_INIT_CAL_CONFIG1_P0, "PC_INIT_CAL_CONFIG1" },
+ { MCA_DDRPHY_PC_RANK_PAIR0_P0, "PC_RANK_PAIR0" },
+ { MCA_DDRPHY_PC_RANK_PAIR1_P0, "PC_RANK_PAIR1" },
+ { MCA_DDRPHY_PC_RANK_PAIR2_P0, "PC_RANK_PAIR2" },
+ { MCA_DDRPHY_PC_RANK_PAIR3_P0, "PC_RANK_PAIR3" },
+
+ { MCA_DDRPHY_PC_CSID_CFG_P0, "PC_CSID_CFG" },
+
+ { MCA_DDRPHY_WC_CONFIG0_P0, "WC_CONFIG0" },
+ { MCA_DDRPHY_WC_CONFIG1_P0, "WC_CONFIG1" },
+ { MCA_DDRPHY_WC_CONFIG2_P0, "WC_CONFIG2" },
+ { MCA_DDRPHY_WC_CONFIG3_P0, "WC_CONFIG3" },
+
+ { MCA_DDRPHY_DP16_DATA_BIT_ENABLE0_P0_0, "DP16_DATA_BIT_ENABLE0_0"},
+ { MCA_DDRPHY_DP16_DATA_BIT_ENABLE0_P0_1, "DP16_DATA_BIT_ENABLE0_1"},
+ { MCA_DDRPHY_DP16_DATA_BIT_ENABLE0_P0_2, "DP16_DATA_BIT_ENABLE0_2"},
+ { MCA_DDRPHY_DP16_DATA_BIT_ENABLE0_P0_3, "DP16_DATA_BIT_ENABLE0_3"},
+ { MCA_DDRPHY_DP16_DATA_BIT_ENABLE0_P0_4, "DP16_DATA_BIT_ENABLE0_4"},
+ { MCA_DDRPHY_DP16_DATA_BIT_ENABLE1_P0_0, "DP16_DATA_BIT_ENABLE1_0"},
+ { MCA_DDRPHY_DP16_DATA_BIT_ENABLE1_P0_1, "DP16_DATA_BIT_ENABLE1_1"},
+ { MCA_DDRPHY_DP16_DATA_BIT_ENABLE1_P0_2, "DP16_DATA_BIT_ENABLE1_2"},
+ { MCA_DDRPHY_DP16_DATA_BIT_ENABLE1_P0_3, "DP16_DATA_BIT_ENABLE1_3"},
+ { MCA_DDRPHY_DP16_DATA_BIT_ENABLE1_P0_4, "DP16_DATA_BIT_ENABLE1_4"},
+
+
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP0_P0_0, "DP16_DATA_BIT_DISABLE0_RP0_0"},
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP0_P0_1, "DP16_DATA_BIT_DISABLE0_RP0_1"},
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP0_P0_2, "DP16_DATA_BIT_DISABLE0_RP0_2"},
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP0_P0_3, "DP16_DATA_BIT_DISABLE0_RP0_3"},
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP0_P0_4, "DP16_DATA_BIT_DISABLE0_RP0_4"},
+
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP1_P0_0, "DP16_DATA_BIT_DISABLE0_RP1_0"},
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP1_P0_1, "DP16_DATA_BIT_DISABLE0_RP1_1"},
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP1_P0_2, "DP16_DATA_BIT_DISABLE0_RP1_2"},
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP1_P0_3, "DP16_DATA_BIT_DISABLE0_RP1_3"},
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP1_P0_4, "DP16_DATA_BIT_DISABLE0_RP1_4"},
+
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP2_P0_0, "DP16_DATA_BIT_DISABLE0_RP2_0"},
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP2_P0_1, "DP16_DATA_BIT_DISABLE0_RP2_1"},
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP2_P0_2, "DP16_DATA_BIT_DISABLE0_RP2_2"},
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP2_P0_3, "DP16_DATA_BIT_DISABLE0_RP2_3"},
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP2_P0_4, "DP16_DATA_BIT_DISABLE0_RP2_4"},
+
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP3_P0_0, "DP16_DATA_BIT_DISABLE0_RP3_0"},
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP3_P0_1, "DP16_DATA_BIT_DISABLE0_RP3_1"},
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP3_P0_2, "DP16_DATA_BIT_DISABLE0_RP3_2"},
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP3_P0_3, "DP16_DATA_BIT_DISABLE0_RP3_3"},
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP3_P0_4, "DP16_DATA_BIT_DISABLE0_RP3_4"},
+
+
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP0_P0_0, "DP16_DATA_BIT_DISABLE1_RP0_0"},
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP0_P0_1, "DP16_DATA_BIT_DISABLE1_RP0_1"},
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP0_P0_2, "DP16_DATA_BIT_DISABLE1_RP0_2"},
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP0_P0_3, "DP16_DATA_BIT_DISABLE1_RP0_3"},
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP0_P0_4, "DP16_DATA_BIT_DISABLE1_RP0_4"},
+
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP1_P0_0, "DP16_DATA_BIT_DISABLE1_RP1_0"},
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP1_P0_1, "DP16_DATA_BIT_DISABLE1_RP1_1"},
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP1_P0_2, "DP16_DATA_BIT_DISABLE1_RP1_2"},
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP1_P0_3, "DP16_DATA_BIT_DISABLE1_RP1_3"},
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP1_P0_4, "DP16_DATA_BIT_DISABLE1_RP1_4"},
+
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP2_P0_0, "DP16_DATA_BIT_DISABLE1_RP2_0"},
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP2_P0_1, "DP16_DATA_BIT_DISABLE1_RP2_1"},
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP2_P0_2, "DP16_DATA_BIT_DISABLE1_RP2_2"},
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP2_P0_3, "DP16_DATA_BIT_DISABLE1_RP2_3"},
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP2_P0_4, "DP16_DATA_BIT_DISABLE1_RP2_4"},
+
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP3_P0_0, "DP16_DATA_BIT_DISABLE1_RP3_0"},
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP3_P0_1, "DP16_DATA_BIT_DISABLE1_RP3_1"},
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP3_P0_2, "DP16_DATA_BIT_DISABLE1_RP3_2"},
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP3_P0_3, "DP16_DATA_BIT_DISABLE1_RP3_3"},
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP3_P0_4, "DP16_DATA_BIT_DISABLE1_RP3_4"},
+
+
+
+ { MCA_DDRPHY_DP16_WRCLK_EN_RP0_P0_0, "DP16_WRCLK_EN_RP0_0" },
+ { MCA_DDRPHY_DP16_WRCLK_EN_RP0_P0_1, "DP16_WRCLK_EN_RP0_1" },
+ { MCA_DDRPHY_DP16_WRCLK_EN_RP0_P0_2, "DP16_WRCLK_EN_RP0_2" },
+ { MCA_DDRPHY_DP16_WRCLK_EN_RP0_P0_3, "DP16_WRCLK_EN_RP0_3" },
+ { MCA_DDRPHY_DP16_WRCLK_EN_RP0_P0_4, "DP16_WRCLK_EN_RP0_4" },
+
+ { MCA_DDRPHY_DP16_WRCLK_EN_RP1_P0_0, "DP16_WRCLK_EN_RP1_0" },
+ { MCA_DDRPHY_DP16_WRCLK_EN_RP1_P0_1, "DP16_WRCLK_EN_RP1_1" },
+ { MCA_DDRPHY_DP16_WRCLK_EN_RP1_P0_2, "DP16_WRCLK_EN_RP1_2" },
+ { MCA_DDRPHY_DP16_WRCLK_EN_RP1_P0_3, "DP16_WRCLK_EN_RP1_3" },
+ { MCA_DDRPHY_DP16_WRCLK_EN_RP1_P0_4, "DP16_WRCLK_EN_RP1_4" },
+
+ { MCA_DDRPHY_DP16_WRCLK_EN_RP2_P0_0, "DP16_WRCLK_EN_RP2_0" },
+ { MCA_DDRPHY_DP16_WRCLK_EN_RP2_P0_1, "DP16_WRCLK_EN_RP2_1" },
+ { MCA_DDRPHY_DP16_WRCLK_EN_RP2_P0_2, "DP16_WRCLK_EN_RP2_2" },
+ { MCA_DDRPHY_DP16_WRCLK_EN_RP2_P0_3, "DP16_WRCLK_EN_RP2_3" },
+ { MCA_DDRPHY_DP16_WRCLK_EN_RP2_P0_4, "DP16_WRCLK_EN_RP2_4" },
+
+ { MCA_DDRPHY_DP16_WRCLK_EN_RP3_P0_0, "DP16_WRCLK_EN_RP3_0" },
+ { MCA_DDRPHY_DP16_WRCLK_EN_RP3_P0_1, "DP16_WRCLK_EN_RP3_1" },
+ { MCA_DDRPHY_DP16_WRCLK_EN_RP3_P0_2, "DP16_WRCLK_EN_RP3_2" },
+ { MCA_DDRPHY_DP16_WRCLK_EN_RP3_P0_3, "DP16_WRCLK_EN_RP3_3" },
+ { MCA_DDRPHY_DP16_WRCLK_EN_RP3_P0_4, "DP16_WRCLK_EN_RP3_4" },
+
+
+ { MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP0_P0_0, "DP16_DQS_GATE_DELAY_RP0_0" },
+ { MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP0_P0_1, "DP16_DQS_GATE_DELAY_RP0_1" },
+ { MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP0_P0_2, "DP16_DQS_GATE_DELAY_RP0_2" },
+ { MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP0_P0_3, "DP16_DQS_GATE_DELAY_RP0_3" },
+ { MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP0_P0_4, "DP16_DQS_GATE_DELAY_RP0_4" },
+
+ { MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP1_P0_0, "DP16_DQS_GATE_DELAY_RP1_0" },
+ { MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP1_P0_1, "DP16_DQS_GATE_DELAY_RP1_1" },
+ { MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP1_P0_2, "DP16_DQS_GATE_DELAY_RP1_2" },
+ { MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP1_P0_3, "DP16_DQS_GATE_DELAY_RP1_3" },
+ { MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP1_P0_4, "DP16_DQS_GATE_DELAY_RP1_4" },
+
+ { MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP2_P0_0, "DP16_DQS_GATE_DELAY_RP2_0" },
+ { MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP2_P0_1, "DP16_DQS_GATE_DELAY_RP2_1" },
+ { MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP2_P0_2, "DP16_DQS_GATE_DELAY_RP2_2" },
+ { MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP2_P0_3, "DP16_DQS_GATE_DELAY_RP2_3" },
+ { MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP2_P0_4, "DP16_DQS_GATE_DELAY_RP2_4" },
+
+ { MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP3_P0_0, "DP16_DQS_GATE_DELAY_RP3_0" },
+ { MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP3_P0_1, "DP16_DQS_GATE_DELAY_RP3_1" },
+ { MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP3_P0_2, "DP16_DQS_GATE_DELAY_RP3_2" },
+ { MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP3_P0_3, "DP16_DQS_GATE_DELAY_RP3_3" },
+ { MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP3_P0_4, "DP16_DQS_GATE_DELAY_RP3_4" },
+
+
+
+
+ { MCA_DDRPHY_DP16_SYSCLK_PR0_P0_0, "DP16_SYSCLK_PR0_P0_0" },
+ { MCA_DDRPHY_DP16_SYSCLK_PR0_P0_1, "DP16_SYSCLK_PR0_P0_1" },
+ { MCA_DDRPHY_DP16_SYSCLK_PR0_P0_2, "DP16_SYSCLK_PR0_P0_2" },
+ { MCA_DDRPHY_DP16_SYSCLK_PR0_P0_3, "DP16_SYSCLK_PR0_P0_3" },
+ { MCA_DDRPHY_DP16_SYSCLK_PR0_P0_4, "DP16_SYSCLK_PR0_P0_4" },
+
+
+ { MCA_DDRPHY_DP16_READ_CLOCK_RANK_PAIR0_P0_0, "DP16_READ_CLOCK_RANK_PAIR0_0" },
+ { MCA_DDRPHY_DP16_READ_CLOCK_RANK_PAIR0_P0_1, "DP16_READ_CLOCK_RANK_PAIR0_1" },
+ { MCA_DDRPHY_DP16_READ_CLOCK_RANK_PAIR0_P0_2, "DP16_READ_CLOCK_RANK_PAIR0_2" },
+ { MCA_DDRPHY_DP16_READ_CLOCK_RANK_PAIR0_P0_3, "DP16_READ_CLOCK_RANK_PAIR0_3" },
+ { MCA_DDRPHY_DP16_READ_CLOCK_RANK_PAIR0_P0_4, "DP16_READ_CLOCK_RANK_PAIR0_4" },
+
+ { MCA_DDRPHY_DP16_READ_CLOCK_RANK_PAIR1_P0_0, "DP16_READ_CLOCK_RANK_PAIR1_0" },
+ { MCA_DDRPHY_DP16_READ_CLOCK_RANK_PAIR1_P0_1, "DP16_READ_CLOCK_RANK_PAIR1_1" },
+ { MCA_DDRPHY_DP16_READ_CLOCK_RANK_PAIR1_P0_2, "DP16_READ_CLOCK_RANK_PAIR1_2" },
+ { MCA_DDRPHY_DP16_READ_CLOCK_RANK_PAIR1_P0_3, "DP16_READ_CLOCK_RANK_PAIR1_3" },
+ { MCA_DDRPHY_DP16_READ_CLOCK_RANK_PAIR1_P0_4, "DP16_READ_CLOCK_RANK_PAIR1_4" },
+
+ { MCA_DDRPHY_DP16_READ_CLOCK_RANK_PAIR2_P0_0, "DP16_READ_CLOCK_RANK_PAIR2_0" },
+ { MCA_DDRPHY_DP16_READ_CLOCK_RANK_PAIR2_P0_1, "DP16_READ_CLOCK_RANK_PAIR2_1" },
+ { MCA_DDRPHY_DP16_READ_CLOCK_RANK_PAIR2_P0_2, "DP16_READ_CLOCK_RANK_PAIR2_2" },
+ { MCA_DDRPHY_DP16_READ_CLOCK_RANK_PAIR2_P0_3, "DP16_READ_CLOCK_RANK_PAIR2_3" },
+ { MCA_DDRPHY_DP16_READ_CLOCK_RANK_PAIR2_P0_4, "DP16_READ_CLOCK_RANK_PAIR2_4" },
+
+ { MCA_DDRPHY_DP16_READ_CLOCK_RANK_PAIR3_P0_0, "DP16_READ_CLOCK_RANK_PAIR3_0" },
+ { MCA_DDRPHY_DP16_READ_CLOCK_RANK_PAIR3_P0_1, "DP16_READ_CLOCK_RANK_PAIR3_1" },
+ { MCA_DDRPHY_DP16_READ_CLOCK_RANK_PAIR3_P0_2, "DP16_READ_CLOCK_RANK_PAIR3_2" },
+ { MCA_DDRPHY_DP16_READ_CLOCK_RANK_PAIR3_P0_3, "DP16_READ_CLOCK_RANK_PAIR3_3" },
+ { MCA_DDRPHY_DP16_READ_CLOCK_RANK_PAIR3_P0_4, "DP16_READ_CLOCK_RANK_PAIR3_4" },
+
+ };
+
+ for (auto r : l_registers)
+ {
+ fapi2::buffer<uint64_t> l_data;
+ FAPI_TRY( fapi2::getScom(i_target, r.first, l_data) );
+ FAPI_DBG("dump %s: 0x%llx 0x%llx", r.second, r.first, l_data);
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Setup all the cal config register
+/// @tparam T, the target type of the MCA/MBA
+/// @param[in] the target associated with this cal setup
+/// @param[in] the vector of currently configured rank pairs
+/// @param[in] fapi2::buffer<uint8_t> representing the cal steps to enable
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+///
+template< fapi2::TargetType T >
+inline fapi2::ReturnCode setup_cal_config( const fapi2::Target<T>& i_target,
+ const std::vector<uint64_t> i_rank_pairs,
+ const fapi2::buffer<uint16_t> i_cal_steps_enabled);
+
+///
+/// @brief Setup all the cal config register
+/// @param[in] the MCA target associated with this cal setup
+/// @param[in] the vector of currently configured rank pairs
+/// @param[in] fapi2::buffer<uint8_t> representing the cal steps to enable
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+///
+template<>
+inline fapi2::ReturnCode setup_cal_config( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const std::vector<uint64_t> i_rank_pairs,
+ const fapi2::buffer<uint16_t> i_cal_steps_enabled)
+{
+ fapi2::buffer<uint64_t> l_cal_config;
+
+ // This is the buffer which will be written to CAL_CONFIG0. It starts
+ // life assuming no cal sequences, no rank pairs - but we set the abort-on-error
+ // bit ahead of time.
+ l_cal_config.writeBit<MCA_DDRPHY_PC_INIT_CAL_CONFIG0_P0_ABORT_ON_ERROR>(CAL_ABORT_ON_ERROR);
+
+ // Sadly, the bits in the register don't align directly with the bits in the attribute.
+ // So, arrange the bits accordingly and write the config register.
+ {
+ // Skip EXT_ZQCAL as it's not in the config register - we do it outside.
+ // Loop (unrolled because static) over the remaining bits.
+ l_cal_config.writeBit<MCA_DDRPHY_PC_INIT_CAL_CONFIG0_P0_ENA_WR_LEVEL>(
+ i_cal_steps_enabled.getBit<WR_LEVEL>());
+ l_cal_config.writeBit<MCA_DDRPHY_PC_INIT_CAL_CONFIG0_P0_ENA_DQS_ALIGN>(
+ i_cal_steps_enabled.getBit<DQS_ALIGN>());
+ l_cal_config.writeBit<MCA_DDRPHY_PC_INIT_CAL_CONFIG0_P0_ENA_RDCLK_ALIGN>(
+ i_cal_steps_enabled.getBit<RDCLK_ALIGN>());
+ l_cal_config.writeBit<MCA_DDRPHY_PC_INIT_CAL_CONFIG0_P0_ENA_READ_CTR>(
+ i_cal_steps_enabled.getBit<READ_CTR>());
+ l_cal_config.writeBit<MCA_DDRPHY_PC_INIT_CAL_CONFIG0_P0_ENA_WRITE_CTR>(
+ i_cal_steps_enabled.getBit<WRITE_CTR>());
+ l_cal_config.writeBit<MCA_DDRPHY_PC_INIT_CAL_CONFIG0_P0_ENA_INITIAL_COARSE_WR>(
+ i_cal_steps_enabled.getBit<COARSE_WR>());
+ l_cal_config.writeBit<MCA_DDRPHY_PC_INIT_CAL_CONFIG0_P0_ENA_COARSE_RD>(
+ i_cal_steps_enabled.getBit<COARSE_RD>());
+ }
+
+ // Note: This rank encoding isn't used if the cal is initiated from the CCS engine
+ // as they use the recal inteface.
+ // Configure the rank pairs
+ for (auto rp : i_rank_pairs)
+ {
+ l_cal_config.setBit(MCA_DDRPHY_PC_INIT_CAL_CONFIG0_P0_ENA_RANK_PAIR + rp);
+ }
+
+ FAPI_INF("cal_config for %s: 0x%llx", mss::c_str(i_target), l_cal_config);
+ FAPI_TRY( fapi2::putScom(i_target, MCA_DDRPHY_PC_INIT_CAL_CONFIG0_P0, l_cal_config) );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Setup all the cal config register
+/// @param[in] the target associated with this cal setup
+/// @param[in] i_rank, one currently configured rank pairs
+/// @param[in] fapi2::buffer<uint8_t> representing the cal steps to enable
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+///
+inline fapi2::ReturnCode setup_cal_config( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_rank,
+ const fapi2::buffer<uint16_t> i_cal_steps_enabled)
+{
+ std::vector< uint64_t > l_ranks({i_rank});
+ return setup_cal_config(i_target, l_ranks, i_cal_steps_enabled);
+}
+
+///
+/// @brief Setup wc_config0
+/// @tparam T, the target type of the MCA/MBA
+/// @param[in] the target associated with this cal setup
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+///
+template< fapi2::TargetType T >
+inline fapi2::ReturnCode reset_wc_config0( const fapi2::Target<T>& i_target );
+
+///
+/// @brief Setup wc_config0
+/// @param[in] the MCA target associated with this cal setup
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+///
+template<>
+inline fapi2::ReturnCode reset_wc_config0( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target )
+{
+ fapi2::buffer<uint64_t> l_data;
+ uint8_t l_is_sim = 0;
+ FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_IS_SIMULATION, fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), l_is_sim) );
+
+ // This is a simplification - in sim we don't have DQS wire delays so we don't acccount for them BRS
+ l_data.insertFromRight<MCA_DDRPHY_WC_CONFIG0_P0_TWLO_TWLOE,
+ MCA_DDRPHY_WC_CONFIG0_P0_TWLO_TWLOE_LEN>(mss::twlo_twloe(i_target));
+
+ // WL_ONE_DQS_PULSE = enable (one pulse)
+ l_data.setBit<MCA_DDRPHY_WC_CONFIG0_P0_WL_ONE_DQS_PULSE>();
+
+ // FW_WR_RD [same formula as RD_WR? max(tWTR+11,AL+tRTP+3), ATTR_EFF_DRAM_AL(0,1,2)]
+ // 57:62, 0b000000, (def_is_sim); # is this max?
+ // 57:62, 0b100000, any; # dd0 = 17 clocks, now 32 from SWyatt
+ {
+ const uint64_t FW_WR_RD = l_is_sim ? 0b000000 : 0b100000;
+ l_data.insertFromRight<MCA_DDRPHY_WC_CONFIG0_P0_FW_WR_RD,
+ MCA_DDRPHY_WC_CONFIG0_P0_FW_WR_RD_LEN>(FW_WR_RD);
+ }
+
+ // 63, 0b0, any; # CUSTOM_INIT_WRITE
+ l_data.clearBit<MCA_DDRPHY_WC_CONFIG0_P0_CUSTOM_INIT_WRITE>();
+
+ FAPI_DBG("wc_config0 0x%llx (tWLO_tWLOE: %d)", l_data, mss::twlo_twloe(i_target));
+ FAPI_TRY( fapi2::putScom(i_target, MCA_DDRPHY_WC_CONFIG0_P0, l_data) );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+
+
+
+
+///
+/// @brief Setup wc_config1
+/// @tparam T, the target type of the MCA/MBA
+/// @param[in] the target associated with this cal setup
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+///
+template< fapi2::TargetType T >
+inline fapi2::ReturnCode reset_wc_config1( const fapi2::Target<T>& i_target );
+
+///
+/// @brief Setup wc_config1
+/// @param[in] the MCA target associated with this cal setup
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+///
+template<>
+inline fapi2::ReturnCode reset_wc_config1( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target )
+{
+ // Reset WC_CONFIG1 with the values directly from the PHY databook
+ fapi2::buffer<uint64_t> l_data;
+
+ l_data.insertFromRight<MCA_DDRPHY_WC_CONFIG1_P0_BIG_STEP, MCA_DDRPHY_WC_CONFIG1_P0_BIG_STEP_LEN>(WR_LVL_BIG_STEP);
+ l_data.insertFromRight<MCA_DDRPHY_WC_CONFIG1_P0_SMALL_STEP, MCA_DDRPHY_WC_CONFIG1_P0_SMALL_STEP_LEN>(WR_LVL_SMALL_STEP);
+ l_data.insertFromRight<MCA_DDRPHY_WC_CONFIG1_P0_WR_PRE_DLY,
+ MCA_DDRPHY_WC_CONFIG1_P0_WR_PRE_DLY_LEN>(WR_LVL_PRE_DLY);
+ FAPI_TRY( fapi2::putScom(i_target, MCA_DDRPHY_WC_CONFIG1_P0, l_data) );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+
+
+///
+/// @brief Setup wc_config2
+/// @tparam T, the target type of the MCA/MBA
+/// @param[in] the target associated with this cal setup
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+///
+template< fapi2::TargetType T >
+inline fapi2::ReturnCode reset_wc_config2( const fapi2::Target<T>& i_target );
+
+///
+/// @brief Setup wc_config2
+/// @param[in] the MCA target associated with this cal setup
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+///
+template<>
+inline fapi2::ReturnCode reset_wc_config2( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target )
+{
+ fapi2::buffer<uint64_t> l_data;
+
+ l_data.insertFromRight<MCA_DDRPHY_WC_CONFIG2_P0_NUM_VALID_SAMPLES,
+ MCA_DDRPHY_WC_CONFIG2_P0_NUM_VALID_SAMPLES_LEN>(WR_LVL_NUM_VALID_SAMPLES);
+
+ l_data.insertFromRight<MCA_DDRPHY_WC_CONFIG2_P0_FW_RD_WR, MCA_DDRPHY_WC_CONFIG2_P0_FW_RD_WR_LEN>(WR_CNTR_FW_RD_WR);
+
+ FAPI_TRY( fapi2::putScom(i_target, MCA_DDRPHY_WC_CONFIG2_P0, l_data) );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+
+
+
+///
+/// @brief Setup wc_config3
+/// @tparam T, the target type of the MCA/MBA
+/// @param[in] the target associated with this cal setup
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+///
+template< fapi2::TargetType T >
+inline fapi2::ReturnCode reset_wc_config3( const fapi2::Target<T>& i_target );
+
+///
+/// @brief Setup wc_config3
+/// @param[in] the MCA target associated with this cal setup
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+///
+template<>
+inline fapi2::ReturnCode reset_wc_config3( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target )
+{
+ fapi2::buffer<uint64_t> l_data;
+ uint8_t l_is_sim = 0;
+ FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_IS_SIMULATION, fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), l_is_sim) );
+
+ // MCA_DDRPHY_WC_CONFIG3_P0_MRS_CMD_DQ_ON is 0's
+
+ // 55:60, 0b000000, (def_is_sim); # MRS_CMD_DQ_OFF !!
+ // 55:60, 0b111111, any ; # MRS_CMD_DQ_OFF !!
+ {
+ const uint64_t CMD_DQ_OFF = l_is_sim ? 0b000000 : 0b111111;
+ l_data.insertFromRight<MCA_DDRPHY_WC_CONFIG3_P0_MRS_CMD_DQ_OFF,
+ MCA_DDRPHY_WC_CONFIG3_P0_MRS_CMD_DQ_OFF_LEN>(CMD_DQ_OFF);
+ }
+
+ FAPI_TRY( fapi2::putScom(i_target, MCA_DDRPHY_WC_CONFIG3_P0, l_data) );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+
+
+
+///
+/// @brief Setup seq_config0
+/// @tparam T, the target type of the MCA/MBA
+/// @param[in] the target associated with this cal setup
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+///
+template< fapi2::TargetType T >
+inline fapi2::ReturnCode reset_seq_config0( const fapi2::Target<T>& i_target );
+
+///
+/// @brief Setup seq_config0
+/// @param[in] the MCA target associated with this cal setup
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+///
+template<>
+inline fapi2::ReturnCode reset_seq_config0( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target )
+{
+ fapi2::buffer<uint64_t> l_data;
+
+ // ATTR_VPD_DRAM_2N_MODE_ENABLED 49, 0b1, (def_2N_mode); # enable 2 cycle addr mode BRS
+
+ FAPI_DBG("seq_config0 0x%llx", l_data);
+ FAPI_TRY( fapi2::putScom(i_target, MCA_DDRPHY_SEQ_CONFIG0_P0, l_data) );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+
+
+
+///
+/// @brief Setup odt_wr/rd_config
+/// @tparam T, the target type of the MCA/MBA
+/// @param[in] the target associated with this cal setup
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+///
+template< fapi2::TargetType T >
+inline fapi2::ReturnCode reset_odt_config( const fapi2::Target<T>& i_target );
+
+///
+/// @brief Setup odt_wr/rd_config
+/// @param[in] the MCA target associated with this cal setup
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+///
+template<>
+inline fapi2::ReturnCode reset_odt_config( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target )
+{
+ uint8_t l_odt_rd[MAX_DIMM_PER_PORT][MAX_RANK_PER_DIMM];
+ uint8_t l_odt_wr[MAX_DIMM_PER_PORT][MAX_RANK_PER_DIMM];
+
+ FAPI_TRY( mss::eff_odt_rd(i_target, &(l_odt_rd[0][0])) );
+ FAPI_TRY( mss::eff_odt_wr(i_target, &(l_odt_rd[0][0])) );
+
+ // Nimbus PHY is more or less hard-wired for 2 DIMM/port 4R/DIMM
+ // So there's not much point in looping over DIMM or ranks.
+
+ //
+ // ODT Read
+ //
+ {
+ // DPHY01_DDRPHY_SEQ_ODT_RD_CONFIG0_P0
+ // 48:55, ATTR_VPD_ODT_RD[0][0][0]; # when Read of Rank0
+ // 56:63, ATTR_VPD_ODT_RD[0][0][1]; # when Read of Rank1
+ fapi2::buffer<uint64_t> l_data;
+
+ l_data.insertFromRight<MCA_DDRPHY_SEQ_ODT_RD_CONFIG0_P0_VALUES0,
+ MCA_DDRPHY_SEQ_ODT_RD_CONFIG0_P0_VALUES0_LEN>(l_odt_rd[0][0]);
+ l_data.insertFromRight<MCA_DDRPHY_SEQ_ODT_RD_CONFIG0_P0_VALUES1,
+ MCA_DDRPHY_SEQ_ODT_RD_CONFIG0_P0_VALUES1_LEN>(l_odt_rd[0][1]);
+ FAPI_DBG("odt_rd_config0: 0x%016llx", uint64_t(l_data));
+ FAPI_TRY( fapi2::putScom(i_target, MCA_DDRPHY_SEQ_ODT_RD_CONFIG0_P0, l_data) );
+ }
+
+ {
+ // DPHY01_DDRPHY_SEQ_ODT_RD_CONFIG1_P0
+ // 48:55, ATTR_VPD_ODT_RD[0][0][2]; # when Read of Rank2
+ // 56:63, ATTR_VPD_ODT_RD[0][0][3]; # when Read of Rank3
+ fapi2::buffer<uint64_t> l_data;
+
+ l_data.insertFromRight<MCA_DDRPHY_SEQ_ODT_RD_CONFIG1_P0_VALUES2,
+ MCA_DDRPHY_SEQ_ODT_RD_CONFIG1_P0_VALUES2_LEN>(l_odt_rd[0][2]);
+ l_data.insertFromRight<MCA_DDRPHY_SEQ_ODT_RD_CONFIG1_P0_VALUES3,
+ MCA_DDRPHY_SEQ_ODT_RD_CONFIG1_P0_VALUES3_LEN>(l_odt_rd[0][3]);
+ FAPI_DBG("odt_rd_config1: 0x%016llx", uint64_t(l_data));
+ FAPI_TRY( fapi2::putScom(i_target, MCA_DDRPHY_SEQ_ODT_RD_CONFIG1_P0, l_data) );
+ }
+
+ {
+ // DPHY01_DDRPHY_SEQ_ODT_RD_CONFIG2_P0
+ // 48:55, ATTR_VPD_ODT_RD[0][1][0]; # when Read of Rank4
+ // 56:63, ATTR_VPD_ODT_RD[0][1][1]; # when Read of Rank5
+ fapi2::buffer<uint64_t> l_data;
+
+ l_data.insertFromRight<MCA_DDRPHY_SEQ_ODT_RD_CONFIG2_P0_VALUES4,
+ MCA_DDRPHY_SEQ_ODT_RD_CONFIG2_P0_VALUES4_LEN>(l_odt_rd[1][0]);
+ l_data.insertFromRight<MCA_DDRPHY_SEQ_ODT_RD_CONFIG2_P0_VALUES5,
+ MCA_DDRPHY_SEQ_ODT_RD_CONFIG2_P0_VALUES5_LEN>(l_odt_rd[1][1]);
+ FAPI_DBG("odt_rd_config2: 0x%016llx", uint64_t(l_data));
+ FAPI_TRY( fapi2::putScom(i_target, MCA_DDRPHY_SEQ_ODT_RD_CONFIG2_P0, l_data) );
+ }
+
+ {
+ // DPHY01_DDRPHY_SEQ_ODT_RD_CONFIG3_P0
+ // 48:55, ATTR_VPD_ODT_RD[0][1][2]; # when Read of Rank6
+ // 56:63, ATTR_VPD_ODT_RD[0][1][3]; # when Read of Rank7
+ fapi2::buffer<uint64_t> l_data;
+
+ l_data.insertFromRight<MCA_DDRPHY_SEQ_ODT_RD_CONFIG3_P0_VALUES6,
+ MCA_DDRPHY_SEQ_ODT_RD_CONFIG3_P0_VALUES6_LEN>(l_odt_rd[1][2]);
+ l_data.insertFromRight<MCA_DDRPHY_SEQ_ODT_RD_CONFIG3_P0_VALUES7,
+ MCA_DDRPHY_SEQ_ODT_RD_CONFIG3_P0_VALUES7_LEN>(l_odt_rd[1][3]);
+ FAPI_DBG("odt_rd_config3: 0x%016llx", uint64_t(l_data));
+ FAPI_TRY( fapi2::putScom(i_target, MCA_DDRPHY_SEQ_ODT_RD_CONFIG3_P0, l_data) );
+ }
+
+ //
+ // ODT Write
+ //
+ {
+ // DPHY01_DDRPHY_SEQ_ODT_WR_CONFIG0_P0
+ // 48:55, ATTR_VPD_ODT_WR[0][0][0]; # when Read of Rank0
+ // 56:63, ATTR_VPD_ODT_WR[0][0][1]; # when Read of Rank1
+ fapi2::buffer<uint64_t> l_data;
+
+ l_data.insertFromRight<MCA_DDRPHY_SEQ_ODT_WR_CONFIG0_P0_VALUES0,
+ MCA_DDRPHY_SEQ_ODT_WR_CONFIG0_P0_VALUES0_LEN>(l_odt_wr[0][0]);
+ l_data.insertFromRight<MCA_DDRPHY_SEQ_ODT_WR_CONFIG0_P0_VALUES1,
+ MCA_DDRPHY_SEQ_ODT_WR_CONFIG0_P0_VALUES1_LEN>(l_odt_wr[0][1]);
+ FAPI_DBG("odt_wr_config0: 0x%016llx", uint64_t(l_data));
+ FAPI_TRY( fapi2::putScom(i_target, MCA_DDRPHY_SEQ_ODT_WR_CONFIG0_P0, l_data) );
+ }
+
+ {
+ // DPHY01_DDRPHY_SEQ_ODT_WR_CONFIG1_P0
+ // 48:55, ATTR_VPD_ODT_WR[0][0][2]; # when Read of Rank2
+ // 56:63, ATTR_VPD_ODT_WR[0][0][3]; # when Read of Rank3
+ fapi2::buffer<uint64_t> l_data;
+
+ l_data.insertFromRight<MCA_DDRPHY_SEQ_ODT_WR_CONFIG1_P0_VALUES2,
+ MCA_DDRPHY_SEQ_ODT_WR_CONFIG1_P0_VALUES2_LEN>(l_odt_wr[0][2]);
+ l_data.insertFromRight<MCA_DDRPHY_SEQ_ODT_WR_CONFIG1_P0_VALUES3,
+ MCA_DDRPHY_SEQ_ODT_WR_CONFIG1_P0_VALUES3_LEN>(l_odt_wr[0][3]);
+ FAPI_DBG("odt_wr_config1: 0x%016llx", uint64_t(l_data));
+ FAPI_TRY( fapi2::putScom(i_target, MCA_DDRPHY_SEQ_ODT_WR_CONFIG1_P0, l_data) );
+ }
+
+ {
+ // DPHY01_DDRPHY_SEQ_ODT_WR_CONFIG2_P0
+ // 48:55, ATTR_VPD_ODT_WR[0][1][0]; # when Read of Rank4
+ // 56:63, ATTR_VPD_ODT_WR[0][1][1]; # when Read of Rank5
+ fapi2::buffer<uint64_t> l_data;
+
+ l_data.insertFromRight<MCA_DDRPHY_SEQ_ODT_WR_CONFIG2_P0_VALUES4,
+ MCA_DDRPHY_SEQ_ODT_WR_CONFIG2_P0_VALUES4_LEN>(l_odt_wr[1][0]);
+ l_data.insertFromRight<MCA_DDRPHY_SEQ_ODT_WR_CONFIG2_P0_VALUES5,
+ MCA_DDRPHY_SEQ_ODT_WR_CONFIG2_P0_VALUES5_LEN>(l_odt_wr[1][1]);
+ FAPI_DBG("odt_wr_config2: 0x%016llx", uint64_t(l_data));
+ FAPI_TRY( fapi2::putScom(i_target, MCA_DDRPHY_SEQ_ODT_WR_CONFIG2_P0, l_data) );
+ }
+
+ {
+ // DPHY01_DDRPHY_SEQ_ODT_WR_CONFIG3_P0
+ // 48:55, ATTR_VPD_ODT_WR[0][1][2]; # when Read of Rank6
+ // 56:63, ATTR_VPD_ODT_WR[0][1][3]; # when Read of Rank7
+ fapi2::buffer<uint64_t> l_data;
+
+ l_data.insertFromRight<MCA_DDRPHY_SEQ_ODT_WR_CONFIG3_P0_VALUES6,
+ MCA_DDRPHY_SEQ_ODT_WR_CONFIG3_P0_VALUES6_LEN>(l_odt_wr[1][2]);
+ l_data.insertFromRight<MCA_DDRPHY_SEQ_ODT_WR_CONFIG3_P0_VALUES7,
+ MCA_DDRPHY_SEQ_ODT_WR_CONFIG3_P0_VALUES7_LEN>(l_odt_wr[1][3]);
+ FAPI_DBG("odt_wr_config3: 0x%016llx", uint64_t(l_data));
+ FAPI_TRY( fapi2::putScom(i_target, MCA_DDRPHY_SEQ_ODT_WR_CONFIG3_P0, l_data) );
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+
+
+
+
+///
+/// @brief Setup seq_rd_wr_data
+/// @tparam T, the target type of the MCA/MBA
+/// @param[in] the target associated with this cal setup
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+///
+template< fapi2::TargetType T >
+inline fapi2::ReturnCode reset_seq_rd_wr_data( const fapi2::Target<T>& i_target );
+
+///
+/// @brief Setup seq_rd_wr_data
+/// @param[in] the MCA target associated with this cal setup
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+///
+template<>
+inline fapi2::ReturnCode reset_seq_rd_wr_data( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target )
+{
+ // MPR_PATTERN_BIT of 0F0F0F0F pattern
+ static const uint64_t MPR_PATTERN = 0x5555;
+ fapi2::buffer<uint64_t> l_data;
+
+ l_data.insertFromRight<MCA_DDRPHY_SEQ_RD_WR_DATA0_P0_DATA_REG0,
+ MCA_DDRPHY_SEQ_RD_WR_DATA0_P0_DATA_REG0_LEN>(MPR_PATTERN);
+
+ FAPI_DBG("seq_rd_wr 0x%llx", l_data);
+ FAPI_TRY( fapi2::putScom(i_target, MCA_DDRPHY_SEQ_RD_WR_DATA0_P0, l_data) );
+ FAPI_TRY( fapi2::putScom(i_target, MCA_DDRPHY_SEQ_RD_WR_DATA1_P0, l_data) );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+
+
+
+
+
+///
+/// @brief Setup the PC CONFIG0 register
+/// @tparam T the fapi2::TargetType
+/// @param[in] the target (MCA or MBA?)
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+template< fapi2::TargetType T>
+fapi2::ReturnCode set_pc_config0(const fapi2::Target<T>& i_target);
+
+///
+/// @brief Setup the PC CONFIG1 register
+/// @tparam T the fapi2::TargetType
+/// @param[in] the target (MCA or MBA?)
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+template< fapi2::TargetType T>
+fapi2::ReturnCode set_pc_config1(const fapi2::Target<T>& i_target);
+
+///
+/// @brief Return the DIMM target for the primary rank in the specificed rank pair
+/// @tparam T, fapi2::TargetType of the port target
+/// @param[in] the arget
+/// @param[in] the rank pair
+/// @param[out] fapi2::Target<fapi2::TARGET_TYPE_DIMM>
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+template<fapi2::TargetType T>
+fapi2::ReturnCode rank_pair_primary_to_dimm(const fapi2::Target<T>& i_target, const uint64_t i_rp,
+ fapi2::Target<fapi2::TARGET_TYPE_DIMM>& o_dimm);
+
+}
+#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
new file mode 100644
index 000000000..81e50fc8c
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/phy/dp16.C
@@ -0,0 +1,330 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/phy/dp16.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 dp16.C
+/// @brief Static data and subroutines to control the DP16 logic blocks
+///
+// *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 <utility>
+#include <vector>
+
+#include "dp16.H"
+
+#include <p9_mc_scom_addresses.H>
+#include <p9_mc_scom_addresses_fld.H>
+
+#include "../utils/pos.H"
+#include "../utils/c_str.H"
+
+using fapi2::TARGET_TYPE_MCA;
+using fapi2::TARGET_TYPE_MCBIST;
+using fapi2::TARGET_TYPE_SYSTEM;
+
+namespace mss
+{
+namespace dp16
+{
+
+typedef std::pair< uint64_t, uint64_t > register_data_pair;
+typedef std::vector< register_data_pair > register_data_vector;
+
+// Why the tables you ask? Because these bits need to be controlled
+// depending on phy, packaging, board swizzling and it's just eaiser
+// to see the bits like this than in a more compact algorithmic arrangement.
+
+// Systems without Spare Bytes (or with deconfigured spares)
+static std::vector< register_data_vector > data_bit_enable_no_spare =
+{
+ // DHPY01
+ {
+ {MCA_DDRPHY_DP16_DATA_BIT_ENABLE0_P0_0, 0xFFFF},
+ {MCA_DDRPHY_DP16_DATA_BIT_ENABLE0_P0_1, 0xFFFF},
+ {MCA_DDRPHY_DP16_DATA_BIT_ENABLE0_P0_2, 0xFFFF},
+ {MCA_DDRPHY_DP16_DATA_BIT_ENABLE0_P0_3, 0xFFFF},
+ {MCA_DDRPHY_DP16_DATA_BIT_ENABLE0_P0_4, 0xFF00},
+
+ {MCA_DDRPHY_DP16_DATA_BIT_ENABLE1_P0_0, 0x0},
+ {MCA_DDRPHY_DP16_DATA_BIT_ENABLE1_P0_1, 0x0},
+ {MCA_DDRPHY_DP16_DATA_BIT_ENABLE1_P0_2, 0x0},
+ {MCA_DDRPHY_DP16_DATA_BIT_ENABLE1_P0_3, 0x0},
+ {MCA_DDRPHY_DP16_DATA_BIT_ENABLE1_P0_4, 0x0},
+ },
+};
+
+// Rank Pair will be added to the register address before writing
+static std::vector< register_data_vector > wrclk_enable_no_spare_x4 =
+{
+ {
+ {MCA_DDRPHY_DP16_WRCLK_EN_RP0_P0_0, 0x8640},
+ {MCA_DDRPHY_DP16_WRCLK_EN_RP0_P0_1, 0x8640},
+ {MCA_DDRPHY_DP16_WRCLK_EN_RP0_P0_2, 0x8640},
+ {MCA_DDRPHY_DP16_WRCLK_EN_RP0_P0_3, 0x8640},
+ {MCA_DDRPHY_DP16_WRCLK_EN_RP0_P0_4, 0x8400},
+ },
+};
+
+// Rank Pair will be added to the register address before writing
+static std::vector< register_data_vector > rdclk_enable_no_spare_x4 =
+{
+ {
+ {MCA_DDRPHY_DP16_READ_CLOCK_RANK_PAIR0_P0_0, 0x8640},
+ {MCA_DDRPHY_DP16_READ_CLOCK_RANK_PAIR0_P0_1, 0x8640},
+ {MCA_DDRPHY_DP16_READ_CLOCK_RANK_PAIR0_P0_2, 0x8640},
+ {MCA_DDRPHY_DP16_READ_CLOCK_RANK_PAIR0_P0_3, 0x8640},
+ {MCA_DDRPHY_DP16_READ_CLOCK_RANK_PAIR0_P0_4, 0x8400},
+ },
+};
+
+// Systems With Spare Bytes Enabled
+static std::vector< register_data_vector > data_bit_enable_spare =
+{
+ // DHPY01
+ {
+ {MCA_DDRPHY_DP16_DATA_BIT_ENABLE0_P0_0, 0xFFFF},
+ {MCA_DDRPHY_DP16_DATA_BIT_ENABLE0_P0_1, 0xFFFF},
+ {MCA_DDRPHY_DP16_DATA_BIT_ENABLE0_P0_2, 0xFFFF},
+ {MCA_DDRPHY_DP16_DATA_BIT_ENABLE0_P0_3, 0xFFFF},
+ {MCA_DDRPHY_DP16_DATA_BIT_ENABLE0_P0_4, 0xFFFF},
+
+ {MCA_DDRPHY_DP16_DATA_BIT_ENABLE1_P0_0, 0x0},
+ {MCA_DDRPHY_DP16_DATA_BIT_ENABLE1_P0_1, 0x0},
+ {MCA_DDRPHY_DP16_DATA_BIT_ENABLE1_P0_2, 0x0},
+ {MCA_DDRPHY_DP16_DATA_BIT_ENABLE1_P0_3, 0x0},
+ {MCA_DDRPHY_DP16_DATA_BIT_ENABLE1_P0_4, 0x0},
+ },
+};
+
+static std::vector< register_data_vector > wrclk_enable_spare_x4 =
+{
+ {
+ {MCA_DDRPHY_DP16_WRCLK_EN_RP0_P0_0, 0x8640},
+ {MCA_DDRPHY_DP16_WRCLK_EN_RP0_P0_1, 0x8640},
+ {MCA_DDRPHY_DP16_WRCLK_EN_RP0_P0_2, 0x8640},
+ {MCA_DDRPHY_DP16_WRCLK_EN_RP0_P0_3, 0x8640},
+ {MCA_DDRPHY_DP16_WRCLK_EN_RP0_P0_4, 0x8640},
+ },
+};
+
+static std::vector< register_data_vector > rdclk_enable_spare_x4 =
+{
+ {
+ {MCA_DDRPHY_DP16_READ_CLOCK_RANK_PAIR0_P0_0, 0x8640},
+ {MCA_DDRPHY_DP16_READ_CLOCK_RANK_PAIR0_P0_1, 0x8640},
+ {MCA_DDRPHY_DP16_READ_CLOCK_RANK_PAIR0_P0_2, 0x8640},
+ {MCA_DDRPHY_DP16_READ_CLOCK_RANK_PAIR0_P0_3, 0x8640},
+ {MCA_DDRPHY_DP16_READ_CLOCK_RANK_PAIR0_P0_4, 0x8640},
+ },
+};
+
+///
+/// @brief Write the data bit enable registers
+/// @param[in] a port target
+/// @param[in] vector of rank pairs
+/// @return FAPI2_RC_SUCCES iff ok
+///
+template<>
+fapi2::ReturnCode write_data_bit_enable( const fapi2::Target<TARGET_TYPE_MCA>& i_target )
+{
+ // Determine if we're running with spares or not. Once we know that, we can find the right vector to iterate over.
+ // Note: Is this ATTR_EFF_DIMM_SPARE? Because that's per DIMM, but this is a port-level statement, right? BRS
+ // Assume Nimbus for now - no spares ever. BRS
+ bool l_using_spares = false;
+
+ // Since this code is the MCA specialization, we know we never deal with DPHY23 - Nimbus PHY are
+ // 4 copies of the same PHY. So we can use the DPHY01 data for all position.
+ auto l_reg_data = l_using_spares ? data_bit_enable_spare[0] : data_bit_enable_no_spare[0];
+
+ FAPI_DBG("reg/data vector %d", l_reg_data.size());
+
+ for (auto rdp : l_reg_data)
+ {
+ // This is probably important enough to be seen all the time, not just debug
+ FAPI_INF( "Setting up DATA_BIT_ENABLE 0x%llx (0x%llx) %s", rdp.first, rdp.second, mss::c_str(i_target) );
+ FAPI_TRY( fapi2::putScom(i_target, rdp.first, rdp.second) );
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Write the clock enable registers
+/// @param[in] a port target
+/// @param[in] vector of rank pairs
+/// @return FAPI2_RC_SUCCES iff ok
+///
+template<>
+fapi2::ReturnCode read_clock_enable( const fapi2::Target<TARGET_TYPE_MCA>& i_target,
+ const std::vector< uint64_t >& l_rank_pairs )
+{
+ // Just slam something in here for now - we know the 'RIT DIMM' is x4, lets assume no cross-coupling for now
+ bool l_using_spares = false;
+ auto l_reg_data = l_using_spares ? rdclk_enable_spare_x4[0] : rdclk_enable_no_spare_x4[0];
+
+ for (auto rp : l_rank_pairs)
+ {
+ for (auto rdp : l_reg_data)
+ {
+ // Grab the register and add the rank pair in
+ fapi2::buffer<uint64_t> l_address(rdp.first);
+ l_address.insertFromRight<22, 2>(rp);
+
+ fapi2::buffer<uint64_t> l_data;
+ l_data.insertFromRight<MCA_DDRPHY_DP16_READ_CLOCK_RANK_PAIR0_P0_0_01_QUAD0_CLK16, 16>(rdp.second);
+
+ FAPI_INF( "Setting up RDCLK RP%d 0x%llx (0x%llx) %s", rp, l_address, l_data, mss::c_str(i_target) );
+ FAPI_TRY( fapi2::putScom(i_target, l_address, l_data) );
+ }
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Write the read clock enable registers
+/// @param[in] a port target
+/// @param[in] vector of rank pairs
+/// @return FAPI2_RC_SUCCESs iff ok
+///
+template<>
+fapi2::ReturnCode write_clock_enable( const fapi2::Target<TARGET_TYPE_MCA>& i_target,
+ const std::vector< uint64_t >& l_rank_pairs )
+{
+ // Just slam something in here for now - we know the 'RIT DIMM' is x4, lets assume no cross-coupling for now
+ bool l_using_spares = false;
+ auto l_reg_data = l_using_spares ? wrclk_enable_spare_x4[0] : wrclk_enable_no_spare_x4[0];
+
+ for (auto rp : l_rank_pairs)
+ {
+ for (auto rdp : l_reg_data)
+ {
+ // Grab the register and add the rank pair in
+ fapi2::buffer<uint64_t> l_address(rdp.first);
+ l_address.insertFromRight<22, 2>(rp);
+
+ fapi2::buffer<uint64_t> l_data;
+ l_data.insertFromRight<MCA_DDRPHY_DP16_WRCLK_EN_RP0_P0_0_01_QUAD0_CLK16, 16>(rdp.second);
+
+ FAPI_INF( "Setting up WRCLK RP%d 0x%llx (0x%llx) %s", rp, l_address, l_data, mss::c_str(i_target) );
+ FAPI_TRY( fapi2::putScom(i_target, l_address, l_data) );
+ }
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Reset the training delay configureation
+/// @param[in] the port target
+/// @param[in] vector of rank pairs
+/// @return FAPI2_RC_SUCCES iff ok
+///
+template<>
+fapi2::ReturnCode reset_delay_values( const fapi2::Target<TARGET_TYPE_MCA>& i_target,
+ const std::vector< uint64_t >& l_rank_pairs )
+{
+ std::vector<uint64_t> l_addrs(
+ {
+ MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP0_P0_0,
+ MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP0_P0_1,
+ MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP0_P0_2,
+ MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP0_P0_3,
+ MCA_DDRPHY_DP16_DQS_GATE_DELAY_RP0_P0_4,
+ } );
+
+ fapi2::buffer<uint64_t> l_data;
+
+ // Reset the write level values
+ FAPI_INF( "Resetting write level values %s", mss::c_str(i_target) );
+ FAPI_TRY( fapi2::getScom(i_target, MCA_DDRPHY_WC_CONFIG2_P0, l_data) );
+ l_data.setBit<MCA_DDRPHY_WC_CONFIG2_P0_EN_RESET_WR_DELAY_WL>();
+ FAPI_TRY( fapi2::putScom(i_target, MCA_DDRPHY_WC_CONFIG2_P0, l_data) );
+
+ for (auto rp : l_rank_pairs)
+ {
+ for (auto a : l_addrs)
+ {
+ // Add the rank pair into the register to get the actual address
+ fapi2::buffer<uint64_t> l_address(a);
+ l_address.insertFromRight<22, 2>(rp);
+
+ FAPI_DBG( "Resetting DP16 gate delay 0x%llx %s", l_address, mss::c_str(i_target) );
+ FAPI_TRY( fapi2::putScom(i_target, l_address, 0) );
+ }
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Configure the DP16 sysclk
+/// @param[in] a MCBIST target
+/// @return FAPI2_RC_SUCCESs iff ok
+///
+template<>
+fapi2::ReturnCode setup_sysclk( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target )
+{
+ std::vector< std::pair<uint64_t, uint64_t> > l_addrs(
+ {
+ {MCA_DDRPHY_DP16_SYSCLK_PR0_P0_0, MCA_DDRPHY_DP16_SYSCLK_PR1_P0_0},
+ {MCA_DDRPHY_DP16_SYSCLK_PR0_P0_1, MCA_DDRPHY_DP16_SYSCLK_PR1_P0_1},
+ {MCA_DDRPHY_DP16_SYSCLK_PR0_P0_2, MCA_DDRPHY_DP16_SYSCLK_PR1_P0_2},
+ {MCA_DDRPHY_DP16_SYSCLK_PR0_P0_3, MCA_DDRPHY_DP16_SYSCLK_PR1_P0_3},
+ {MCA_DDRPHY_DP16_SYSCLK_PR0_P0_4, MCA_DDRPHY_DP16_SYSCLK_PR1_P0_4},
+ } );
+
+ fapi2::buffer<uint64_t> l_data;
+ uint8_t is_sim = 0;
+ FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_IS_SIMULATION, fapi2::Target<TARGET_TYPE_SYSTEM>(), is_sim) );
+
+ l_data.setBit<MCA_DDRPHY_DP16_SYSCLK_PR0_P0_0_01_ENABLE>();
+
+ if (is_sim)
+ {
+ l_data.setBit<MCA_DDRPHY_DP16_SYSCLK_PR0_P0_0_01_ROT_OVERRIDE_EN>();
+ }
+
+ for (auto p : i_target.getChildren<TARGET_TYPE_MCA>())
+ {
+ FAPI_DBG("set dp16_sysclk for %s", mss::c_str(p));
+
+ for (auto a : l_addrs)
+ {
+ FAPI_TRY( fapi2::putScom(p, a.first, l_data) );
+ FAPI_TRY( fapi2::putScom(p, a.second, l_data) );
+ }
+ }
+
+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
new file mode 100644
index 000000000..f5f962516
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/phy/dp16.H
@@ -0,0 +1,165 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/phy/dp16.H $ */
+/* */
+/* 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 dp16.H
+/// @brief Subroutines to control the DP16 logic blocks
+///
+// *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
+
+#ifndef _MSS_DP16_H_
+#define _MSS_DP16_H_
+
+#include <fapi2.H>
+#include <vector>
+
+namespace mss
+{
+namespace dp16
+{
+
+///
+/// @brief Configure the DP16 sysclk
+/// @tparam T, the fapi2 target type
+/// @param[in] a target
+/// @return FAPI2_RC_SUCCESs iff ok
+///
+template< fapi2::TargetType T >
+fapi2::ReturnCode setup_sysclk( const fapi2::Target<T>& i_target );
+
+///
+/// @brief Configure the DP16 sysclk
+/// @param[in] a MCBIST target
+/// @return FAPI2_RC_SUCCESs iff ok
+///
+template<>
+fapi2::ReturnCode setup_sysclk( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target );
+
+///
+/// @brief Reset the training delay configureation
+/// @tparam T, the type of the port
+/// @param[in] the port target
+/// @param[in] vector of rank pairs
+/// @return FAPI2_RC_SUCCES iff ok
+///
+template< fapi2::TargetType T>
+fapi2::ReturnCode reset_delay_values( const fapi2::Target<T>& i_target,
+ const std::vector< uint64_t >& l_rank_pairs );
+
+///
+/// @brief Reset the training delay configureation
+/// @param[in] the port target
+/// @param[in] vector of rank pairs
+/// @return FAPI2_RC_SUCCES iff ok
+///
+template<>
+fapi2::ReturnCode reset_delay_values( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const std::vector< uint64_t >& l_rank_pairs );
+
+///
+/// @brief Write the read clock enable registers
+/// @tparam T, the type of the port
+/// @param[in] a port target
+/// @param[in] vector of rank pairs
+/// @return FAPI2_RC_SUCCES iff ok
+///
+template< fapi2::TargetType T>
+fapi2::ReturnCode read_clock_enable( const fapi2::Target<T>& i_target,
+ const std::vector< uint64_t >& l_rank_pairs );
+
+///
+/// @brief Write the clock enable registers
+/// @param[in] a port target
+/// @param[in] vector of rank pairs
+/// @return FAPI2_RC_SUCCES iff ok
+///
+template<>
+fapi2::ReturnCode read_clock_enable( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const std::vector< uint64_t >& l_rank_pairs );
+
+///
+/// @brief Write the clock enable registers
+/// @tparam T, the type of the port
+/// @param[in] a port target
+/// @param[in] vector of rank pairs
+/// @return FAPI2_RC_SUCCES iff ok
+///
+template< fapi2::TargetType T>
+fapi2::ReturnCode write_clock_enable( const fapi2::Target<T>& i_target,
+ const std::vector< uint64_t >& l_rank_pairs );
+
+///
+/// @brief Write the clock enable registers
+/// @param[in] a port target
+/// @param[in] vector of rank pairs
+/// @return FAPI2_RC_SUCCES iff ok
+///
+template<>
+fapi2::ReturnCode write_clock_enable( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const std::vector< uint64_t >& l_rank_pairs );
+
+///
+/// @brief Write the data bit enable registers
+/// @tparam T, the type of the port
+/// @param[in] a port target
+/// @param[in] vector of port pairs
+/// @return FAPI2_RC_SUCCESs iff ok
+///
+template< fapi2::TargetType T>
+fapi2::ReturnCode write_data_bit_enable( const fapi2::Target<T>& i_target );
+
+///
+/// @brief Write the data bit enable registers
+/// @param[in] a port target
+/// @param[in] vector of port pairs
+/// @return FAPI2_RC_SUCCESs iff ok
+///
+template<>
+fapi2::ReturnCode write_data_bit_enable( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target );
+
+///
+/// @brief Setup the bad-bits masks for a port
+/// @tparam T the fapi2::TargetType
+/// @param[in] the target (MCA or MBA?)
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+template< fapi2::TargetType T>
+inline fapi2::ReturnCode set_bad_bits(const fapi2::Target<T>& i_target);
+
+///
+/// @brief Setup the bad-bits masks for a port
+/// @tparam T the fapi2::TargetType
+/// @param[in] the target (MCA or MBA?)
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+template<>
+inline fapi2::ReturnCode set_bad_bits(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target)
+{
+ // Note: We need to do this ... BRS
+ return fapi2::FAPI2_RC_SUCCESS;
+}
+
+}
+}
+
+#endif
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/port/port.H b/src/import/chips/p9/procedures/hwp/memory/lib/port/port.H
new file mode 100644
index 000000000..4b3f6637b
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/port/port.H
@@ -0,0 +1,265 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/port/port.H $ */
+/* */
+/* 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 port.H
+/// @brief Code to support ports
+///
+// *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: HB:FSP
+
+#ifndef _MSS_PORT_H_
+#define _MSS_PORT_H_
+
+#include <fapi2.H>
+
+#include <p9_mc_scom_addresses.H>
+
+// I have a dream that port code can be shared among controllers. So, I drive the
+// engine from a set of traits. This might be folly. Allow me to dream. BRS
+
+template< fapi2::TargetType T >
+class portTraits;
+
+// Centaur port traits
+template<>
+class portTraits<fapi2::TARGET_TYPE_MBA>
+{
+ public:
+};
+
+// Nimbus port traits
+template<>
+class portTraits<fapi2::TARGET_TYPE_MCA>
+{
+ public:
+ static const uint64_t FARB5Q_REG = MCA_MBA_FARB5Q;
+ static const uint64_t REFRESH_REG = MCA_MBAREF0Q;
+ static const uint64_t ECC_REG = MCA_RECR;
+
+ enum
+ {
+ CFG_DDR_DPHY_NCLK = MCA_MBA_FARB5Q_CFG_DDR_DPHY_NCLK,
+ CFG_DDR_DPHY_NCLK_LEN = MCA_MBA_FARB5Q_CFG_DDR_DPHY_NCLK_LEN,
+ CFG_DDR_DPHY_PCLK = MCA_MBA_FARB5Q_CFG_DDR_DPHY_PCLK,
+ CFG_DDR_DPHY_PCLK_LEN = MCA_MBA_FARB5Q_CFG_DDR_DPHY_PCLK_LEN,
+ CFG_CCS_INST_RESET_ENABLE = MCA_MBA_FARB5Q_CFG_CCS_INST_RESET_ENABLE,
+ CFG_DDR_RESETN = MCA_MBA_FARB5Q_CFG_DDR_RESETN,
+ CFG_CCS_ADDR_MUX_SEL = MCA_MBA_FARB5Q_CFG_CCS_ADDR_MUX_SEL,
+
+ REFRESH_ENABLE = MCA_MBAREF0Q_CFG_REFRESH_ENABLE,
+
+ ECC_CHECK_DISABLE = MCA_RECR_MBSECCQ_DISABLE_MEMORY_ECC_CHECK_CORRECT,
+ ECC_CORRECT_DISABLE = MCA_RECR_MBSECCQ_DISABLE_MEMORY_ECC_CORRECT,
+ };
+};
+
+
+namespace mss
+{
+///
+/// @brief Given a DIMM, return it's port number.
+/// @param[in] the DIMM in question
+/// @return the port number it's attached to
+///
+// Note: Make this a template and dispatch at runtime to determine if the parent of
+// the DIMM is an MBA or an MCA BRS
+//
+inline uint64_t port( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target )
+{
+ // Our port is the position of our MCA
+ return mss::pos( i_target.getParent<fapi2::TARGET_TYPE_MCA>() );
+}
+
+///
+/// @brief Change the state of the addr_mux_sel bit
+/// @param[in] the target
+/// @param[in] the state
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+template< fapi2::TargetType T, typename TT = portTraits<T> >
+fapi2::ReturnCode change_addr_mux_sel( const fapi2::Target<T>& i_target, states i_state )
+{
+ fapi2::buffer<uint64_t> l_data;
+
+ FAPI_DBG("Change addr_mux_sel to %s %s", (i_state == HIGH ? "high" : "low"), mss::c_str(i_target));
+ FAPI_TRY( fapi2::getScom(i_target, TT::FARB5Q_REG, l_data) );
+ l_data.writeBit<TT::CFG_CCS_ADDR_MUX_SEL>(i_state);
+ FAPI_TRY( fapi2::putScom(i_target, TT::FARB5Q_REG, l_data) );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Change the state of the MC Refresh enable bit
+/// @param[in] the target
+/// @param[in] the state
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+template< fapi2::TargetType T, typename TT = portTraits<T> >
+fapi2::ReturnCode change_refresh_enable( const fapi2::Target<T>& i_target, states i_state )
+{
+ fapi2::buffer<uint64_t> l_data;
+
+ FAPI_DBG("Change refresh enable to %s %s", (i_state == HIGH ? "high" : "low"), mss::c_str(i_target));
+ FAPI_TRY( fapi2::getScom(i_target, TT::REFRESH_REG, l_data) );
+ l_data.writeBit<TT::REFRESH_ENABLE>(i_state);
+ FAPI_TRY( fapi2::putScom(i_target, TT::REFRESH_REG, l_data) );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Enable the MC Periodic calibration functionality
+/// @param[in] the target
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+template< fapi2::TargetType T, typename TT = portTraits<T> >
+fapi2::ReturnCode enable_periodic_cal( const fapi2::Target<T>& i_target )
+{
+ FAPI_INF("Enable periodic cal NOOP");
+ return fapi2::FAPI2_RC_SUCCESS;
+}
+
+///
+/// @brief Enable Read ECC checking
+/// @param[in] the target
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+template< fapi2::TargetType T, typename TT = portTraits<T> >
+fapi2::ReturnCode enable_read_ecc( const fapi2::Target<T>& i_target )
+{
+ fapi2::buffer<uint64_t> l_data;
+
+ FAPI_DBG("Enable Read ECC %s", mss::c_str(i_target));
+
+ FAPI_TRY( fapi2::getScom(i_target, TT::ECC_REG, l_data) );
+ l_data.clearBit<TT::ECC_CHECK_DISABLE>();
+ l_data.clearBit<TT::ECC_CORRECT_DISABLE>();
+
+ // The preferred operating mode is 11 (INVERT_DATA_TOGGLE_CHECKS) which stores data complemented
+ // (because most bits are '0', and the dram bus pulls up, so transmitting 1s is least power) but
+ // still flips the inversion of check bits to aid RAS. Per Brad Michael 12/15
+ l_data.insertFromRight<MCA_RECR_MBSECCQ_DATA_INVERSION, MCA_RECR_MBSECCQ_DATA_INVERSION_LEN>(0b11);
+
+ // bits: 60 MBSTRQ_CFG_MAINT_RCE_WITH_CE
+ // cfg_maint_rce_with_ce - not implemented. Need to investigate if needed for nimbus.
+
+ FAPI_TRY( fapi2::putScom(i_target, TT::ECC_REG, l_data) );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+//
+// We expect to come in to draminit with the following setup:
+// 1. ENABLE_RESET_N (FARB5Q(6)) 0
+// 2. RESET_N (FARB5Q(4)) 1 - out of reset (done in draminit as a separate step)
+// 3. CCS_ADDR_MUX_SEL (FARB5Q(5)) - 1
+// 4. CKE out of high impedence
+// Note: Ignore resetn as it's taken care of as a separate step
+//
+///
+/// @brief Secure the entry criteria for draminit
+/// @param[in] A target representing a port
+/// @return FAPI2_RC_SUCCESS if and only if ok
+// This is in this header as it's hoped to be able to be shared. Seems to make more
+// Might make more sense in p9_mss_draminit.C ... BRS
+///
+template< fapi2::TargetType T, typename TT = portTraits<T> >
+inline fapi2::ReturnCode draminit_entry_invariant( const fapi2::Target<T>& i_target )
+{
+ fapi2::buffer<uint64_t> l_data;
+ FAPI_TRY( fapi2::getScom(i_target, TT::FARB5Q_REG, l_data) );
+
+ if ((l_data.getBit<TT::CFG_CCS_ADDR_MUX_SEL>() != HIGH) || (l_data.getBit<TT::CFG_CCS_INST_RESET_ENABLE>() != LOW))
+ {
+ // We have some bits not set correctly. Lets try to reset the register.
+ FAPI_INF("FARB5Q: 0x%llx, setting MUX_SEL, clearing RESET_ENABLE", uint64_t(l_data));
+ l_data.setBit<TT::CFG_CCS_ADDR_MUX_SEL>();
+ l_data.clearBit<TT::CFG_CCS_INST_RESET_ENABLE>();
+ FAPI_TRY( fapi2::putScom(i_target, TT::FARB5Q_REG, l_data) );
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Drive memory clocks
+/// @param[in] A target representing a port
+/// @param[in] phy p clock - right most 2 bits
+/// @param[in] phy n clock - right most 2 bits
+/// @return FAPI2_RC_SUCCESS if and only if ok
+/// @note this might need a port id added for Centaur/MBA controllers
+///
+template< fapi2::TargetType T, typename TT = portTraits<T> >
+fapi2::ReturnCode drive_mem_clks( const fapi2::Target<T>& i_target, uint64_t i_pclk, uint64_t i_nclk )
+{
+ fapi2::buffer<uint64_t> l_data;
+
+ FAPI_DBG("Drive mem clocks");
+ FAPI_TRY( fapi2::getScom(i_target, TT::FARB5Q_REG, l_data) );
+
+ l_data.insertFromRight<TT::CFG_DDR_DPHY_NCLK, TT::CFG_DDR_DPHY_NCLK_LEN>(i_nclk);
+ l_data.insertFromRight<TT::CFG_DDR_DPHY_PCLK, TT::CFG_DDR_DPHY_PCLK_LEN>(i_pclk);
+
+ FAPI_TRY( fapi2::putScom(i_target, TT::FARB5Q_REG, l_data) );
+
+ return fapi2::FAPI2_RC_SUCCESS;
+
+fapi_try_exit:
+ FAPI_ERR("Unable to drive mem clocks: %s", mss::c_str(i_target));
+ return fapi2::current_err;
+}
+
+///
+/// @brief Set DDR resetn
+/// @param[in] A target representing a port
+/// @param[in] high or low
+/// @return FAPI2_RC_SUCCESS if and only if ok
+/// @note this might need a port id added for Centaur/MBA controllers
+///
+template< fapi2::TargetType T, typename TT = portTraits<T> >
+fapi2::ReturnCode ddr_resetn( const fapi2::Target<T>& i_target, bool i_state )
+{
+ fapi2::buffer<uint64_t> l_data;
+ FAPI_TRY( fapi2::getScom(i_target, TT::FARB5Q_REG, l_data) );
+
+ if (l_data.getBit<TT::CFG_DDR_RESETN>() != i_state)
+ {
+ l_data.writeBit<TT::CFG_DDR_RESETN>(i_state);
+ FAPI_DBG("ddr_resetn transitioning to %d (0x%llx)", i_state, l_data);
+ FAPI_TRY( fapi2::putScom(i_target, TT::FARB5Q_REG, l_data) );
+ }
+
+ return fapi2::FAPI2_RC_SUCCESS;
+
+fapi_try_exit:
+ FAPI_ERR("Unable to change resetn: %s (%d)", mss::c_str(i_target), i_state);
+ return fapi2::current_err;
+}
+
+}
+#endif
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
new file mode 100644
index 000000000..b6b8c25aa
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/shared/mss_const.H
@@ -0,0 +1,141 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/shared/mss_const.H $ */
+/* */
+/* 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 */
+
+///
+/// @mss_const.H
+/// @This file contains constants for the memory team.
+///
+// *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: HB:FSP
+
+#ifndef _MSS_CONST_H_
+#define _MSS_CONST_H_
+
+
+namespace mss
+{
+
+enum sizes
+{
+ PORTS_PER_MCS = 2,
+ PORTS_PER_MCBIST = 4,
+ MAX_DIMM_PER_PORT = 2,
+ MAX_RANK_PER_DIMM = 4,
+ RANK_MID_POINT = 4, ///< Which rank number indicates the switch to the other DIMM
+ DEFAULT_POLL_LIMIT = 10, ///< the number of poll attempts in the event we can't calculate another
+ MAX_NUM_IMP = 4, ///< number of impedances valid per slew type
+ MAX_NUM_CAL_SLEW_RATES = 4, ///< 3V/ns, 4V/ns, 5V/ns, 6V/n
+ MAX_SLEW_VALUE = 15, ///< 4 bit value
+ MAX_SUPPORTED_FREQUENCIES = 1, ///< Number of supported frequencies. Right now it's only 2400
+
+ // All need to be attributes - BRS
+ // 48:51, 0b1100, (def_is_sim); # BIG_STEP = 12 (changed from default for SIM)
+ // 48:51, 0b0000, any; # BIG_STEP = 0 SWyatt
+ // #48:51, 0b0010, any; # BIG_STEP = 2 (default)
+ // 52:54, 0b000, any; # SMALL_STEP = 0 (default) SWyatt
+ //#52:54, 0b001, any; # SMALL_STEP = 1 (!! recommend setting to 0)
+ // 55:60, 0b101010, any; # WR_PRE_DLY = 42
+ WR_LVL_BIG_STEP = 0b1100,
+ WR_LVL_SMALL_STEP = 0b000,
+ WR_LVL_PRE_DLY = 0b101010,
+ WR_LVL_NUM_VALID_SAMPLES = 0x5,
+
+ // THIS IS LIKELY INCORRECT - Should be defined in the DDR4 write centering protocol BRS
+ // This field must be set to the larger of the two values in number of memory clock cycles.
+ // FW_RD_WR = max(tWTR + 11, AL + tRTP + 3)
+ WR_CNTR_FW_RD_WR = 0x11 + 4,
+ WR_CNTR_FW_WR_RD = 0x0,
+
+ // Attribute? BRS
+ COARSE_CAL_STEP_SIZE = 0x4,
+ CONSEQ_PASS = 0x8,
+};
+
+enum times
+{
+ CONVERT_PS_IN_A_NS = 1000, ///< 1000 pico in an nano
+ CONVERT_PS_IN_A_US = 1000000, ///< 1000000 picos in a micro
+
+ DELAY_1NS = 1,
+ DELAY_10NS = 10 , ///< general purpose 10 ns delay for HW mode
+ DELAY_100NS = 100, ///< general purpose 100 ns delay for HW mode
+ DELAY_1US = 1000, ///< general purpose 1 usec delay for HW mode
+ DELAY_100US = 100000, ///< general purpose 100 usec delay for HW mode
+
+ // From the DDR4spec 2400 speed - need to be changed to read attributes. BRS
+ tWLO = 10,
+ tWLOE = 2,
+};
+
+enum states
+{
+ LOW = 0,
+ HIGH = 1,
+ START = 1,
+ STOP = 0,
+ START_N = 0,
+ STOP_N = 1,
+ ON = 1,
+ OFF = 0,
+ ON_N = 0,
+ OFF_N = 1,
+ INVALID = 0xFF,
+
+ // This needs to be an attribute I think - BRS. Used as a boolean.
+ CAL_ABORT_ON_ERROR = 1,
+};
+
+// Static consts describing the bits used in the cal_step_enable attribute
+// These are bit positions. 0 is the left most bit.
+enum cal_steps
+{
+ EXT_ZQCAL = 0,
+ WR_LEVEL = 1,
+ DQS_ALIGN = 2,
+ RDCLK_ALIGN = 3,
+ READ_CTR = 4,
+ READ_CTR_2D_VREF = 5,
+ WRITE_CTR = 6,
+ WRITE_CTR_2D_VREF = 7,
+ COARSE_WR = 8,
+ COARSE_RD = 9,
+};
+
+namespace mcbist
+{
+enum data_mode
+{
+ // MCBIST test data modes
+ FIXED_DATA_MODE = 0b000,
+ RAND_FWD_MODE = 0b001,
+ RAND_REV_MODE = 0b010,
+ RAND_FWD_MAINT = 0b011,
+ RAND_REV_MAINT = 0b100,
+ DATA_EQ_ADDR = 0b101,
+ ROTATE_LEFT_MODE = 0b110,
+ ROTATE_RIGHT_MODE = 0b111,
+};
+} // namespace mcbist
+
+
+}
+#endif
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/shared/mss_kind.H b/src/import/chips/p9/procedures/hwp/memory/lib/shared/mss_kind.H
new file mode 100644
index 000000000..b89fc304c
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/shared/mss_kind.H
@@ -0,0 +1,116 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/shared/mss_kind.H $ */
+/* */
+/* 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 mss_kind.H
+/// @brief Implementation of mss specific types
+///
+// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
+// *HWP HWP Backup: Craig Hamilton <cchamilt@us.ibm.com>
+// *HWP Team: Memory
+// *HWP Level: 2
+// *HWP Consumed by: HB:FSP
+
+#ifndef _MSS_KIND_H_
+#define _MSS_KIND_H_
+
+#include <fapi2.H>
+
+///
+/// @brief Class to compile-time inspect whether an API has an overload
+/// @note contains a static bool which defaults to false. Any overload
+/// will specialize this template and replace the value with true.
+///
+#define REGISTER_API( __api_name, ... ) \
+ template< mss::kind_t K, __VA_ARGS__ > \
+ struct __api_name##_overload \
+ { static const bool available = false; };
+
+//
+// Overload definitions for the specializations
+//
+#define REGISTER_OVERLOAD( __api_name, __kind, ... ) \
+ template<> \
+ struct __api_name##_overload< __kind, __VA_ARGS__> \
+ { static const bool available = true; };
+
+namespace mss
+{
+
+// These must be contiguous and unique
+enum kind_t
+{
+ // The default, base, etc. kind. Used to define the function
+ // which would be in a base class. Also used to stop the
+ // metaprogramming recursion of the dispatcher functions.
+ DEFAULT_KIND = 0,
+
+ // DIMM type and DRAM Generation representation
+ KIND_RDIMM_EMPTY = 1,
+ KIND_RDIMM_DDR4 = 2,
+ KIND_LRDIMM_EMPTY = 3,
+ KIND_LRDIMM_DDR4 = 4,
+
+ // Used to force dispatching looking for overloads
+ // This moust always be one more than that largest
+ // kind_t.
+ FORCE_DISPATCH = 4 + 1,
+};
+
+inline mss::kind_t dimm_kind( const uint64_t l_type, const uint64_t l_gen )
+{
+ // This is the conditional needed to differentiate dimm type/generation
+ switch (l_type)
+ {
+ case fapi2::ENUM_ATTR_EFF_DIMM_TYPE_RDIMM:
+ if (l_gen == fapi2::ENUM_ATTR_EFF_DRAM_GEN_EMPTY)
+ {
+ return KIND_RDIMM_EMPTY;
+ }
+
+ if (l_gen == fapi2::ENUM_ATTR_EFF_DRAM_GEN_DDR4)
+ {
+ return KIND_RDIMM_DDR4;
+ }
+
+ return DEFAULT_KIND;
+ break;
+
+ case fapi2::ENUM_ATTR_EFF_DIMM_TYPE_LRDIMM:
+ if (l_gen == fapi2::ENUM_ATTR_EFF_DRAM_GEN_EMPTY)
+ {
+ return KIND_LRDIMM_EMPTY;
+ }
+
+ if (l_gen == fapi2::ENUM_ATTR_EFF_DRAM_GEN_DDR4)
+ {
+ return KIND_LRDIMM_DDR4;
+ }
+
+ return DEFAULT_KIND;
+ break;
+
+ default:
+ return DEFAULT_KIND;
+ break;
+ };
+}
+
+}
+#endif
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/spd/spd_decoder.C b/src/import/chips/p9/procedures/hwp/memory/lib/spd/spd_decoder.C
new file mode 100644
index 000000000..d215773a0
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/spd/spd_decoder.C
@@ -0,0 +1,3548 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/spd/spd_decoder.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 spd_decoder.C
+/// @brief SPD decoder definitions
+///
+// *HWP HWP Owner: Andre Marin <aamarin@us.ibm.com>
+// *HWP HWP Backup: Brian Silver <bsilver@us.ibm.com>
+// *HWP Team: Memory
+// *HWP Level: 2
+// *HWP Consumed by: HB:FSP
+
+#include <fapi2.H>
+#include "../mss.H"
+#include "../utils/conversions.H"
+#include "spd_decoder.H"
+
+using fapi2::TARGET_TYPE_MCBIST;
+using fapi2::TARGET_TYPE_MCA;
+using fapi2::TARGET_TYPE_MCS;
+using fapi2::TARGET_TYPE_DIMM;
+
+
+namespace mss
+{
+namespace spd
+{
+
+// Note: IBM's implementation of std::maps are not thread safe
+
+// =========================================================
+// Byte 0 maps
+// Item JC-45-2220.01x
+// Page 14
+// DDR4 SPD Document Release 3
+// Byte 0 (0x000): Number of Bytes Used / Number of Bytes in SPD Device
+
+static const uint16_t bytes_used_map[] =
+{
+ // Shifting index by 1 first since first key value is undefined
+ // Key values < 1 and > 3 aren't supported or reserved
+
+ // Undefined
+ 128,
+ 256,
+ 384,
+ 512,
+ //...
+ // All other bits reserved
+};
+
+static const uint16_t bytes_total_map[] =
+{
+ // Shifting index by 1 first since first key value is undefined
+ // Key values < 1 and > 2 aren't supported or reserved
+
+ // Undefined
+ 256,
+ 512,
+ //...
+ // All other bits reserved
+};
+
+// =========================================================
+// Byte 2 maps
+// Item JC-45-2220.01x
+// Page 16
+// DDR4 SPD Document Release 3
+// Byte 2 (0x002): Key Byte / DRAM Device Type
+
+static const uint8_t dram_gen_map[] =
+{
+ // Initial and ending index values are not supported or reserved
+ // Shifting index by 11 since initial dram gen types aren't supported (by IBM)
+ // Key values < 12 and > 13 are not supported or reserved
+
+ // Reserved
+ // Fast page mode is not supported
+ // EDO is not supported
+ // Pipelined Nibbleis not supported
+ // SDRAM
+ // ROM is not supported
+ // DDR SGRAM is not supported
+ // DDR SDRAM is not supported
+ // DDR2 SDRAM is not supported
+ // DDR2 SDRAM FB-DIMM is not supported
+ // DDR2 SDRAM FB-DIMM PROBE is not supported
+ fapi2::ENUM_ATTR_EFF_DRAM_GEN_DDR3,
+ fapi2::ENUM_ATTR_EFF_DRAM_GEN_DDR4,
+ //...
+ // All other bits reserved
+};
+
+// =========================================================
+// Byte 3 maps
+// Item JC-45-2220.01x
+// Page 17
+// DDR4 SPD Document Release 3
+// Byte 3 (0x003): Key Byte / Module Type
+
+static const uint8_t base_module_type_map[] =
+{
+
+ // Initial and ending index values are not supported or reserved
+ // Index shifted by 1 since first module type isn't supported (by IBM)
+ // Key values < 1 and > 4 are not supported or reserved
+
+ // Extending DIMM not supported
+ fapi2::ENUM_ATTR_SPD_MODULE_TYPE_RDIMM,
+ fapi2::ENUM_ATTR_SPD_MODULE_TYPE_UDIMM,
+ fapi2::ENUM_ATTR_SPD_MODULE_TYPE_SO_DIMM,
+ fapi2::ENUM_ATTR_SPD_MODULE_TYPE_LRDIMM,
+ // Mini-RDIMM not supported
+ // Mini-UDIMM not supported
+ // Reserved
+ // 72b-SO-RDIMM not supported
+ // 72b-SO-UDIMM not supported
+ // Reserved
+ // Reserved
+ // 16b-SO-DIMM
+ // 32b-SO-DIMM
+ // Reserved
+ // Reserved
+};
+
+// =========================================================
+// Byte 4 maps
+// Item JC-45-2220.01x
+// Page 18
+// DDR4 SPD Document Release 3
+// Byte 4 (0x004): SDRAM Density and Banks
+
+static const uint8_t sdram_capacity_map[] =
+{
+ // Initial and ending index values are not supported or reserved
+ // Index shifted by 2 since first module type isn't supported (by IBM)
+ // Key values < 2 and > 9 are not supported or reserved
+
+ // 256 Mbs is not supported
+ // 512 Mbs is not supported
+ // // Units (Gigabits)
+ 1, // Gb
+ 2, // Gb
+ 4, // Gb
+ 8, // Gb
+ 16, // Gb
+ 32, // Gb
+ 12, // Gb
+ 24, // Gb
+ //...
+ //All others reserved
+};
+
+static const uint8_t sdram_banks_map[] =
+{
+ // Key values > 1 are not supported or reserved
+
+ 4, // banks address bits (2 address bits)
+ 8, // banks address bits (3 address bits)
+ //...
+ // All others Reserved
+};
+
+static const uint8_t sdram_bankgroups_map[] =
+{
+ // Key values > 2 are not supported or reserved
+
+ 0, // No bank groups (0 bank group bits)
+ 2, // 2 bank groups (1 bank group bit)
+ 4, // 4 bank groups (2 bank group bits)
+ //Reserved
+};
+
+// =========================================================
+// Byte 5 maps
+// Item JC-45-2220.01x
+// Page 18
+// DDR4 SPD Document Release 3
+// Byte 5 (0x005): SDRAM Addressing
+
+static const uint8_t column_address_map[] =
+{
+ 9, // Column address bits 000
+ 10, // Column address bits 001
+ 11, // Column address bits 010
+ 12, // Column address bits 011
+ // All others reserved
+};
+
+static const uint8_t row_address_map[] =
+{
+ 12, // Row address bits 000
+ 13, // Row address bits 001
+ 14, // Row address bits 010
+ 15, // Row address bits 011
+ 16, // Row address bits 100
+ 17, // Row address bits 101
+ 18, // Row address bits 110
+ // All others reserved
+};
+
+// =========================================================
+// Byte 6 maps
+// Item JC-45-2220.01x
+// Page 19
+// DDR4 SPD Document Release 3
+// Byte 6 (0x006): Primary SDRAM Package Type
+
+static const uint8_t die_count_map[] =
+{
+ 1, // 000 = Single die
+ 2, // 001 = 2 die
+ 3, // 010 = 3 die
+ 4, // 011 = 4 die
+ 5, // 100 = 5 die
+ 6, // 101 = 6 die
+ 7, // 110 = 7 die
+ 8, // 111 = 8 die
+};
+
+static const uint8_t package_type_map[] =
+{
+ fapi2::ENUM_ATTR_EFF_STACK_TYPE_SDP,
+ uint8_t(~0),
+ uint8_t(~0),
+ uint8_t(~0),
+ uint8_t(~0),
+ fapi2::ENUM_ATTR_EFF_STACK_TYPE_DDP_QDP,
+ fapi2::ENUM_ATTR_EFF_STACK_TYPE_3DS,
+};
+
+// =========================================================
+// Byte 7 maps
+// Item JC-45-2220.01x
+// Page 20
+// DDR4 SPD Document Release 3
+// Byte 7 (0x007): SDRAM Optional Features
+
+uint16_t static const MAC_map[] =
+{
+ fapi2::ENUM_ATTR_EFF_DRAM_MAC_UNTESTED, // Untested MAC
+ fapi2::ENUM_ATTR_EFF_DRAM_MAC_700K, // 700K
+ fapi2::ENUM_ATTR_EFF_DRAM_MAC_600K, // 600K
+ fapi2::ENUM_ATTR_EFF_DRAM_MAC_500K, // 500K
+ fapi2::ENUM_ATTR_EFF_DRAM_MAC_400K, // 400K
+ fapi2::ENUM_ATTR_EFF_DRAM_MAC_300K, // 300K
+ fapi2::ENUM_ATTR_EFF_DRAM_MAC_200K, // 200K
+ uint16_t(~0), // Reserved
+ fapi2::ENUM_ATTR_EFF_DRAM_MAC_UNLIMITED,// Unlimited MAC
+ // All others reserved
+};
+
+uint16_t static const tMAW_map[] =
+{
+ 8192,
+ 4096,
+ 2048,
+};
+
+// =========================================================
+// Byte 9 maps
+// Item JC-45-2220.01x
+// Page 21
+// DDR4 SPD Document Release 3
+// Byte 9 (0x009): Other SDRAM Optional Features
+static const uint8_t ppr_map[]
+{
+ fapi2::ENUM_ATTR_EFF_DRAM_PPR_NOT_SUPPORTED,
+ fapi2::ENUM_ATTR_EFF_DRAM_PPR_SUPPORTED,
+ //...
+ // Reserved
+};
+
+static const uint8_t soft_ppr_map[]
+{
+ fapi2::ENUM_ATTR_EFF_DRAM_SOFT_PPR_NOT_SUPPORTED,
+ fapi2::ENUM_ATTR_EFF_DRAM_SOFT_PPR_SUPPORTED,
+};
+
+// =========================================================
+// Byte 6 maps
+// Item JC-45-2220.01x
+// Page 19
+// DDR4 SPD Document Release 3
+// Byte 6 (0x006): Primary SDRAM Package Type
+
+static const uint8_t sec_die_count_map[] =
+{
+ 1, // 000 = Single die
+ 2, // 001 = 2 die
+ 3, // 010 = 3 die
+ 4, // 011 = 4 die
+ 5, // 100 = 5 die
+ 6, // 101 = 6 die
+ 7, // 110 = 7 die
+ 8, // 111 = 8 die
+};
+
+static const uint8_t sec_package_type_map[] =
+{
+ fapi2::ENUM_ATTR_EFF_STACK_TYPE_SDP,
+ uint8_t(~0),
+ uint8_t(~0),
+ uint8_t(~0),
+ uint8_t(~0),
+ fapi2::ENUM_ATTR_EFF_STACK_TYPE_DDP_QDP,
+ fapi2::ENUM_ATTR_EFF_STACK_TYPE_3DS,
+};
+
+// =========================================================
+// Byte 12 maps
+// Item JC-45-2220.01x
+// Page 23
+// DDR4 SPD Document Release 3
+// Byte 12 (0x00C): Module Organization
+static const uint8_t device_type_map[] =
+{
+ // // Units
+ 4, // bits
+ 8, // bits
+ 16, // bits
+ 32, // bits
+ // All others reserved
+};
+
+static const uint8_t num_pkgs_ranks_per_dimm_map[] =
+{
+ // // Units
+ 1, // package rank
+ 2, // package ranks
+ 3, // package ranks
+ 4, // package ranks
+ 5, // package ranks
+ 6, // package ranks
+ 7, // package ranks
+ 8 // package ranks
+ // All others reserved
+};
+
+// =========================================================
+// Byte 12 maps
+// Item JC-45-2220.01x
+// Page 23
+// DDR4 SPD Document Release 3
+// Byte 13 (0x00D): Module Memory Bus Width
+static const uint8_t prim_bus_width_map[] =
+{
+ // // Units
+ 8, // bits
+ 16, // bits
+ 32, // bits
+ 64, // bits
+ // All others reserved
+};
+
+static const uint8_t bus_width_ext_map[] =
+{
+ // // Units
+ 0, // bits
+ 8, // bits
+ // All others reserved
+};
+
+// =========================================================
+// Byte 17 maps
+// Item JC-45-2220.01x
+// Page 29
+// DDR4 SPD Document Release 3
+// Byte 17 (0x011): Timebases
+
+// Created a maps of a single value in case mapping expands to more values
+static const uint8_t medium_timebase_map[] =
+{
+ // // Units
+ 125, // ps
+ // All others reserved
+};
+
+static const uint8_t fine_timebase_map[] =
+{
+ // // Units
+ 1, // ps
+ // All others reserved
+};
+
+
+// =========================================================
+// Function implementations
+// =========================================================
+namespace check
+{
+///
+/// @brief Checks that stack type conforms to JEDEC table
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Consumed in (Byte 7) sdram_package_type(...)
+/// Item JC-45-2220.01x
+/// Page 20 (Terminology table)
+/// DDR4 SPD Document Release 3
+bool stack_type(const uint8_t i_stack_type, const uint8_t i_die_count)
+{
+ const size_t STACK_SDP = 0;
+ const size_t STACK_DDP_QDP = 5;
+ const size_t STACK_3DS = 6;
+
+ const size_t SINGLE_DIE_PACKAGE = 1;
+ const size_t DUAL_DIE_PACKAGE = 2;
+ const size_t QUAD_DIE_PACKAGE = 4;
+
+ const size_t TWO_SDRAM_DIE = 2;
+ const size_t EIGHT_SDRAM_DIE = 8;
+
+ // Use const or enums
+ switch(i_stack_type)
+ {
+ case STACK_SDP:
+ //SDP has single die
+ return i_die_count == SINGLE_DIE_PACKAGE;
+ break;
+
+ case STACK_DDP_QDP:
+ //DDP has 2 die, QDP has 4 die
+ return (i_die_count == DUAL_DIE_PACKAGE) || (i_die_count == QUAD_DIE_PACKAGE);
+ break;
+
+ case STACK_3DS:
+ //3DS has 2 - 8 dies
+ return (i_die_count >= TWO_SDRAM_DIE) && (i_die_count <= EIGHT_SDRAM_DIE);
+ break;
+
+ default:
+ return false; // Doesn't meet JEDEC spec
+ }
+}// stack_type()
+
+} // check namespace
+
+///
+/// @brief Calculates timing value
+/// @param[in] const int64_t& i_spd_timing_mtb,
+/// const int64_t& i_spd_timing_ftb,
+/// const int64_t& multiplier_mtb,
+/// const int64_t& multiplier_ftb
+/// @return int64_t, (timing value)
+inline int64_t calc_timing(const int64_t& i_spd_timing_mtb,
+ const int64_t& i_spd_timing_ftb,
+ const int64_t& multiplier_mtb,
+ const int64_t& multiplier_ftb)
+{
+ int64_t timing_val = i_spd_timing_mtb * multiplier_mtb;
+ int64_t offset = (i_spd_timing_ftb * multiplier_ftb);
+ int64_t remainder_val = timing_val % multiplier_mtb;
+
+ if( remainder_val == 0)
+ {
+ // If the timing value can be expressed as an integer number
+ // of MTB units, return that
+ return timing_val;
+ }
+ else
+ {
+ // Else round up and incorporate correction factor
+ return (++timing_val) + offset;
+ }
+}
+
+///
+/// @brief Decodes SPD number of bytes
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// size_t i_read_spd_size
+/// @return fapi2::ReturnCode
+/// @note Decodes SPD Byte 0
+///
+fapi2::ReturnCode decoder::number_of_bytes(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data,
+ const size_t i_read_spd_size)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 0;
+
+ // SPD Bytes used mapping limits
+ const size_t BYTES_USED_MAP_OFFSET = 1;
+ const size_t BYTES_USED_MIN_VALID_KEY = 1; // All previous keys are not supported or reserved
+ const size_t BYTES_USED_MAX_VALID_KEY = 4; // The rest are not supported or reserved
+
+ // Total SPD bytes mapping limits
+ const size_t BYTES_TOTAL_MAP_OFFSET = 1;
+ const size_t BYTES_TOTAL_MIN_VALID_KEY = 1; // All previous keys are not supported or reserved
+ const size_t BYTES_TOTAL_MAX_VALID_KEY = 2; // The rest are not supported or reserved
+
+ // Byte variables used for decoding
+ uint8_t l_spd_bytes_used = 0;
+ uint8_t l_spd_bytes_total = 0;
+ uint8_t l_reserved = 0;
+ uint16_t l_total_bytes_map_val = 0;
+ uint16_t l_used_bytes_map_val = 0;
+
+ // Buffers used for bit manipulation
+ fapi2::buffer<uint8_t> l_spd_buffer(i_spd_data[BYTE_INDEX]);
+
+ // Trace in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte 0: 0x%llX.",
+ mss::c_str(i_target_dimm),
+ i_spd_data[BYTE_INDEX]);
+
+ // Decoding 1st nibble, bits 3~0 (SPD Bytes Used)
+ l_spd_buffer.extractToRight<BYTES_USED_START, BYTES_USED_LEN>(l_spd_bytes_used);
+
+ // Check to assure SPD Bytes Used (map) wont be at invalid values
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_spd_bytes_used >= BYTES_USED_MIN_VALID_KEY) &&
+ (l_spd_bytes_used <= BYTES_USED_MAX_VALID_KEY),
+ BYTE_INDEX,
+ l_spd_bytes_used,
+ "Failed check on Used SPD bytes") );
+
+ // Decoding bits 6~4 (SPD Bytes Total)
+ l_spd_buffer.extractToRight<BYTES_TOTAL_START, BYTES_TOTAL_LEN>(l_spd_bytes_total);
+
+ // Check to assure SPD Bytes Total (map) wont be at invalid values
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_spd_bytes_total >= BYTES_TOTAL_MIN_VALID_KEY) &&
+ (l_spd_bytes_total <= BYTES_TOTAL_MAX_VALID_KEY),
+ BYTE_INDEX,
+ l_spd_bytes_total,
+ "Failed check on total SPD bytes" ) );
+
+ // Decoding bit 7 (Reserved bit)
+ l_spd_buffer.extractToRight<BYTES_RESERVED_START, BYTES_RESERVED_LEN>(l_reserved);
+
+ // Hold map values in temp variables
+ l_used_bytes_map_val = bytes_used_map[l_spd_bytes_used - BYTES_USED_MAP_OFFSET];
+ l_total_bytes_map_val = bytes_total_map[l_spd_bytes_total - BYTES_TOTAL_MAP_OFFSET];
+
+ // Size of input SPD read should match size it claims to be based on the SPD spec
+ // "Used SPD bytes" wasn't used since manufacturers may not use all available bytes
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ l_total_bytes_map_val == i_read_spd_size,
+ BYTE_INDEX,
+ l_total_bytes_map_val,
+ "Failed SPD size check") );
+
+ FAPI_INF("%s. Bytes Used: %d, Total Bytes: %d, Reserved : %d",
+ mss::c_str(i_target_dimm),
+ l_used_bytes_map_val,
+ l_total_bytes_map_val,
+ l_reserved);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Decodes SPD Revision
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @param[in, out] uint8_t io_revision_num
+/// @return fapi2::ReturnCode
+/// @note Decodes SPD Byte 1
+///
+fapi2::ReturnCode decoder::revision(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 1;
+ const size_t UNDEFINED = 0xFF; // per JEDEC spec
+
+ // Byte variables used for decoding
+ uint8_t l_revision_num = 0;
+
+ // Verify SPD revision is not undefined. Value is defined by the JEDEC spec
+ l_revision_num = i_spd_data[BYTE_INDEX];
+
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_revision_num != UNDEFINED),
+ BYTE_INDEX,
+ l_revision_num,
+ "Failed check on SPD revision") );
+ // Print decoded info
+ FAPI_INF("%s. SPD data at Byte %d: 0x%llX, Revision number : %d",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX],
+ l_revision_num);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Decodes DRAM Device Type
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Decodes SPD Byte 2
+///
+fapi2::ReturnCode decoder::dram_device_type(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 2;
+
+ // dram generation mapping limits
+ const size_t MIN_VALID_KEY = 12; // All previous keys are not supported or reserved
+ const size_t MAX_VALID_KEY = 13; // The rest are not supported or reserved
+ const size_t MAP_OFFSET = 11; // SPD DRAM device type map has an index offset of 11 (simplifies array)
+ // //since initial map values are not supported or reserved (ignored for now)
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding
+ uint8_t l_device_type = 0;
+
+ // Attribute variables used to set decoded vals
+ uint8_t l_device_gen[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Check to assure SPD DRAM device type (map) wont be at invalid values
+ l_device_type = i_spd_data[BYTE_INDEX];
+
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_device_type >= MIN_VALID_KEY) &&
+ (l_device_type <= MAX_VALID_KEY),
+ BYTE_INDEX,
+ l_device_type,
+ "Unsupported/reserved key value retried from SPD") );
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY(eff_dram_gen(l_target_mcs, &l_device_gen[0][0]));
+
+ // Update attribute to decoded byte values
+ l_device_gen[PORT_NUM][DIMM_NUM] = dram_gen_map[l_device_type - MAP_OFFSET];
+
+ // Update MCS level attribute
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_GEN, l_target_mcs, l_device_gen));
+
+ // Print decoded info
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX. Device type : %d",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX],
+ l_device_gen[PORT_NUM][DIMM_NUM]);
+
+fapi_try_exit:
+ return fapi2::current_err;
+
+}
+
+///
+/// @brief Decodes SPD module type
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Decodes SPD Byte 3
+///
+fapi2::ReturnCode decoder::module_type(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 3;
+
+ // Base module mapping limits // since first index is not supported
+ const size_t BASE_MODULE_MAP_OFFSET = 1; // base_module_type_map has an index offset of 1
+ const size_t MIN_VALID_KEY = 1; // All previous keys are not supported or reserved
+ const size_t MAX_VALID_KEY = 4; // The rest are not supported or reserved
+
+ // Hybrid Media limit
+ const size_t MAX_HYBRID_MEDIA_KEY = 1; // All other key values reserved
+
+ // Hybrid
+ const size_t MAX_HYBRID_KEY = 1; // Nothing else exits afterwards
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding
+ uint8_t l_base_module_type = 0;
+ uint8_t l_hybrid_media = 0;
+ uint8_t l_hybrid = 0;
+
+ // Attribute variables used to set decoded vals
+ uint8_t l_module_type[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Buffer used for bit manipulation
+ fapi2::buffer<uint8_t> l_spd_buffer(i_spd_data[BYTE_INDEX]);
+
+ // Trace in the front assists w/ debug
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Decoding bits 3~0
+ l_spd_buffer.extractToRight<BASE_MODULE_START, BASE_MODULE_LEN>(l_base_module_type);
+
+ // Check to assure SPD DRAM base module type (map) wont be at invalid values
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_base_module_type >= MIN_VALID_KEY) &&
+ (l_base_module_type <= MAX_VALID_KEY),
+ BYTE_INDEX,
+ l_base_module_type,
+ "Failed check for SPD DRAM base module type") );
+
+ // Decoding bits 6~4
+ l_spd_buffer.extractToRight<HYBRID_MEDIA_START, HYBRID_MEDIA_LEN>(l_hybrid_media);
+
+ // Check to assure SPD DRAM hybrid media is valid
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ l_hybrid_media <= MAX_HYBRID_MEDIA_KEY,
+ BYTE_INDEX,
+ l_hybrid_media,
+ "Failed check for SPD DRAM hybrid media") );
+
+ // Decoding bit 7
+ l_spd_buffer.extractToRight<HYBRID_START, HYBRID_LEN>(l_hybrid);
+
+
+ // Check to assure SPD DRAM hybrid media is valid
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ l_hybrid_media <= MAX_HYBRID_KEY,
+ BYTE_INDEX,
+ l_hybrid,
+ "Failed check for SPD DRAM hybrid media") );
+ // Retrive entire MCS level attribute
+ FAPI_TRY(spd_module_type(l_target_mcs, &l_module_type[0][0]));
+
+ // Update attribute to decoded byte values
+ l_module_type[PORT_NUM][DIMM_NUM] = base_module_type_map[l_base_module_type - BASE_MODULE_MAP_OFFSET];
+
+ // Update MCS level attribute
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_SPD_MODULE_TYPE, l_target_mcs, l_module_type));
+
+ FAPI_INF("%s. Base Module Type: %d, Hybrid Media: %d, Hybrid: %d",
+ c_str(i_target_dimm),
+ l_module_type[PORT_NUM][DIMM_NUM],
+ l_hybrid_media,
+ l_hybrid);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Decode SDRAM density
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte 4
+///
+fapi2::ReturnCode decoder::sdram_density(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 4;
+
+ // DRAM capacity mapping limits
+ const size_t CAPACITY_MAP_OFFSET = 1; // base_module_type_map has an index offset of 1
+ const size_t CAPACITY_MIN_VALID_KEY = 2; // All previous keys are not supported or reserved
+ const size_t CAPACITY_MAX_VALID_KEY = 9; // The rest are not supported or reserved
+
+ // DRAM banks mapping limits
+ const size_t BANKS_MAX_VALID_KEY = 1; // The rest are not supported or reserved
+
+ // DRAM bank groups mapping limits
+ const size_t BANK_GRP_MAX_VALID_KEY = 2; // The rest are not supported or reserved
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding
+ uint8_t l_sdram_capacity = 0;
+ uint8_t l_sdram_banks = 0;
+ uint8_t l_sdram_bank_group = 0;
+
+ // Attribute variables used to set decoded vals
+ uint8_t l_capacities[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+ uint8_t l_banks[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+ uint8_t l_bank_groups[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Buffer used for bit manipulation
+ fapi2::buffer<uint8_t> l_spd_buffer(i_spd_data[BYTE_INDEX]);
+
+ // Trace in the front assists w/ debug
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Decoding bits 3~0
+ l_spd_buffer.extractToRight<SDRAM_CAPACITY_START, SDRAM_CAPACITY_LEN>(l_sdram_capacity);
+
+ // Check to assure SPD DRAM capacity (map) wont be at invalid values
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_sdram_capacity >= CAPACITY_MIN_VALID_KEY) &&
+ (l_sdram_capacity <= CAPACITY_MAX_VALID_KEY),
+ BYTE_INDEX,
+ l_sdram_capacity,
+ "Failed check for SPD DRAM capacity") );
+ // Decoding bits 5~4
+ l_spd_buffer.extractToRight<SDRAM_BANKS_START, SDRAM_BANKS_LEN>(l_sdram_banks);
+
+ // Check to assure SPD DRAM banks (map) wont be at invalid values
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_sdram_banks <= BANKS_MAX_VALID_KEY),
+ BYTE_INDEX,
+ l_sdram_banks,
+ "Failed check for SPD DRAM banks") );
+
+ // Decoding bits 7~6
+ l_spd_buffer.extractToRight<BANK_GROUP_START, BANK_GROUP_LEN>(l_sdram_bank_group);
+
+ // Check to assure SPD DRAM banks groups (map) wont be at invalid values
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_sdram_bank_group <= BANK_GRP_MAX_VALID_KEY),
+ BYTE_INDEX,
+ l_sdram_bank_group,
+ "Failed check for SPD DRAM bank groups") );
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_density(l_target_mcs, &l_capacities[0][0]) );
+ FAPI_TRY( eff_dram_banks(l_target_mcs, &l_banks[0][0]) );
+ FAPI_TRY( eff_dram_bank_groups(l_target_mcs, &l_bank_groups[0][0]) );
+
+ // Update attribute to decoded byte values
+ l_capacities[PORT_NUM][DIMM_NUM] = sdram_capacity_map[l_sdram_capacity - CAPACITY_MAP_OFFSET];
+ l_banks[PORT_NUM][DIMM_NUM] = sdram_banks_map[l_sdram_banks];
+ l_bank_groups[PORT_NUM][DIMM_NUM] = sdram_bankgroups_map[l_sdram_bank_group];
+
+ // Update MCS level attribute
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_DENSITY, l_target_mcs, l_capacities));
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_BANKS, l_target_mcs, l_banks));
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_BANK_GROUPS, l_target_mcs, l_bank_groups));
+
+ FAPI_INF("%s. SDRAM capacity: %d, banks: %d, bank groups: %d",
+ c_str(i_target_dimm),
+ sdram_capacity_map[l_sdram_capacity],
+ sdram_banks_map[l_sdram_banks],
+ sdram_bankgroups_map[l_sdram_bank_group]);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Decode SDRAM addressing
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte 5
+///
+fapi2::ReturnCode decoder::sdram_addressing(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 5;
+ // DRAM column address mapping limits
+ const size_t COLUMN_MAX_VALID_KEY = 3; // The rest are not supported or reserved
+ // DRAM row address mapping limits
+ const size_t ROW_MAX_VALID_KEY = 6; // The rest are not supported or reserved
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding
+ uint8_t l_column_addr = 0;
+ uint8_t l_row_addr = 0;
+ uint8_t l_reserved = 0;
+
+ // Attribute variables used to set decoded vals
+ uint8_t l_columns[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+ uint8_t l_rows[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Buffer used for bit manipulation
+ fapi2::buffer<uint8_t> l_spd_buffer(i_spd_data[BYTE_INDEX]);
+
+ // Trace in the front assists w/ debug
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Decoding bits 2~0 (Column Address bits)
+ l_spd_buffer.extractToRight<COL_ADDRESS_START, COL_ADDRESS_LEN>(l_column_addr);
+
+ // Check to assure SPD DRAM Column Address bits (map) wont be indexed at invalid values
+ FAPI_TRY(mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_column_addr <= COLUMN_MAX_VALID_KEY),
+ BYTE_INDEX,
+ l_column_addr,
+ "Failed check for SPD DRAM bank groups") );
+
+ // Decoding bits 3~0 (Row address bits)
+ l_spd_buffer.extractToRight<ROW_ADDRESS_START, ROW_ADDRESS_LEN>(l_row_addr);
+
+ // Check to assure SPD DRAM Row address bits (map) wont be at invalid values
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_row_addr <= ROW_MAX_VALID_KEY),
+ BYTE_INDEX,
+ l_row_addr,
+ "Failed check for SPD DRAM bank groups") );
+
+ // Decoding bits 7~6
+ l_spd_buffer.extractToRight<ADDRESS_RESERVED_START, ADDRESS_RESERVED_LEN>(l_reserved);
+
+ // Check to assure SPD reserved bits are 0 as defined in JEDEC SPD spec
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_reserved == 0),
+ BYTE_INDEX,
+ l_reserved,
+ "Failed check for SPD DRAM bank groups") );
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_cols(l_target_mcs, &l_columns[0][0]) );
+ FAPI_TRY( eff_dram_rows(l_target_mcs, &l_rows[0][0]) );
+
+ // Update attribute to decoded byte values
+ l_columns[PORT_NUM][DIMM_NUM] = column_address_map[l_column_addr];
+ l_rows[PORT_NUM][DIMM_NUM] = row_address_map[l_row_addr];
+
+ // Update MCS level attribute
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_COLS, l_target_mcs, l_columns));
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_ROWS, l_target_mcs, l_rows));
+
+ FAPI_INF("%s. Columns: %d, Rows: %d",
+ c_str(i_target_dimm),
+ l_columns[PORT_NUM][DIMM_NUM],
+ l_rows[PORT_NUM][DIMM_NUM]);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+
+///
+/// @brief Decode SDRAM Package Type
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte 6
+///
+fapi2::ReturnCode decoder::primary_package_type(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 6;
+ const size_t INVALID_VALUE = 0x11; //per JEDEC spec
+ const size_t RESERVED = 0;
+
+ // DRAM die count mapping limits
+ const size_t DIE_COUNT_MAX_VALID_KEY = 7; // Nothing greater doesn't exist
+ const size_t INVALID_PACKAGE_TYPE = ~0;
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding
+ uint8_t l_prim_signal_loading = 0;
+ uint8_t l_reserved = 0;
+ uint8_t l_prim_die_count = 0;
+ uint8_t l_prim_package_type = 0;
+
+ // Attribute variables used to set decoded vals
+ uint8_t l_stack_type = 0;
+ uint8_t l_sdram_package_type[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+ uint8_t l_sdram_die_count[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Buffer used for bit manipulation
+ fapi2::buffer<uint8_t> l_spd_buffer(i_spd_data[BYTE_INDEX]);
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Decoding bits 1~0 (Signal loading)
+ l_spd_buffer.extractToRight<PRIM_PRIM_SIGNAL_LOAD_START, PRIM_PRIM_SIGNAL_LOAD_LEN>(l_prim_signal_loading);
+
+ // Check to assure SPD DRAM signal loading conforms to JEDEC SPEC
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_prim_signal_loading != INVALID_VALUE),
+ BYTE_INDEX,
+ l_prim_signal_loading,
+ "Failed check for SPD DRAM signal loading") );
+ // Decoding bits 3~2 (Reserved)
+ l_spd_buffer.extractToRight<PACKAGE_RESERVE_START, PACKAGE_RESERVE_LEN>(l_reserved);
+
+ // Check to assure SPD reserved bits are 0 as defined in JEDEC SPD spec
+ mss::check::spd::valid_value_warn(i_target_dimm,
+ (l_reserved == RESERVED),
+ BYTE_INDEX,
+ l_reserved,
+ "Failed check for SPD DRAM reserved bits");
+
+ // Decoding bits 6~4 (Die Count)
+ l_spd_buffer.extractToRight<PRIM_DIE_COUNT_START, PRIM_DIE_COUNT_LEN>(l_prim_die_count);
+
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_prim_die_count <= DIE_COUNT_MAX_VALID_KEY),
+ BYTE_INDEX,
+ l_prim_die_count,
+ "Failed check for SPD DRAM die count") );
+ // Decoding bit 7
+ l_spd_buffer.extractToRight<PRIM_PACKAGE_TYPE_START, PRIM_PACKAGE_TYPE_LEN>(l_prim_package_type);
+
+ // Manipulating and combining l_prim_package_type and l_prim_signal_loading to produce the following
+ // table for indexing the package_type_map[].
+ // 0000 0000 = SDP (monolithic device)
+ // 0000 0101 = DDP/QDP (non-monolithic device)
+ // 0000 0110 = 3DS (non-monolithic device)
+ // What this essentially does is remove reserved bits.
+ // This was done to avoid having large gaps (of 0's) in the package_type_map (sparsed array)
+ // since we can't use std::map due to thread saftey issues
+ l_stack_type = (l_prim_package_type >> 5) | l_prim_signal_loading;
+
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ check::stack_type(l_stack_type, die_count_map[l_prim_die_count]) &&
+ (package_type_map[l_stack_type] != INVALID_PACKAGE_TYPE),
+ BYTE_INDEX,
+ package_type_map[l_stack_type],
+ "Failed check for SPD DRAM stack type") );
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_stack_type(l_target_mcs, &l_sdram_package_type[0][0]) );
+ FAPI_TRY( eff_prim_die_count(l_target_mcs, &l_sdram_die_count[0][0]) );
+
+ // Update attribute to decoded byte values
+ l_sdram_die_count[PORT_NUM][DIMM_NUM] = die_count_map[l_prim_die_count];
+ l_sdram_package_type[PORT_NUM][DIMM_NUM] = package_type_map[l_stack_type];
+
+ // Update MCS level attribute
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_STACK_TYPE, l_target_mcs, l_sdram_package_type));
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_PRIM_DIE_COUNT, l_target_mcs, l_sdram_die_count));
+
+ FAPI_INF("%s. Signal loading: %d, Die count: %d, Stack type: %d",
+ c_str(i_target_dimm),
+ l_prim_signal_loading,
+ die_count_map[l_prim_die_count],
+ l_sdram_package_type[PORT_NUM][DIMM_NUM]);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+//TODO
+// Need to complete this function, map need tREF1 calculations
+
+///
+/// @brief Decode SDRAM Optional Features
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte 7
+///
+fapi2::ReturnCode decoder::sdram_optional_features(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 7;
+ const size_t RESERVED = 0;
+
+ // MAC mapping limits
+ const size_t MAC_RESERVED = 7; //per JEDEC spec
+ const size_t MAC_MAX_VALID_KEY = 8;
+
+ // TMAW mappint limits
+ const size_t TMAW_MAX_VALID_KEY = 2;
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding
+ uint16_t l_MAC = 0; // Maximum Active Count
+ uint16_t l_tMAW = 0; // Maximum Active Window
+ uint8_t l_reserved = 0;
+
+ // Attribute variables used to set decoded vals
+ uint16_t l_mac[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+ uint16_t l_tmaw[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Buffer used for bit manipulation
+ fapi2::buffer<uint8_t> l_spd_buffer(i_spd_data[BYTE_INDEX]);
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Decoding bits 3~0 (MAC)
+ l_spd_buffer.extractToRight<MAC_START, MAC_LEN>(l_MAC);
+ // Check to assure SPD DRAM signal loading conforms to JEDEC SPEC
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_MAC <= MAC_MAX_VALID_KEY) &&
+ l_MAC != MAC_RESERVED,
+ BYTE_INDEX,
+ l_MAC,
+ "Failed check for Maximum Active Count (MAC)") );
+
+ // Decoding bits 5~4 (tMAW)
+ l_spd_buffer.extractToRight<TMAW_START, TMAW_LEN>(l_tMAW);
+
+ // Check to assure SPD DRAM signal loading conforms to JEDEC SPEC
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_tMAW <= TMAW_MAX_VALID_KEY),
+ BYTE_INDEX,
+ l_tMAW,
+ "Failed check for Maximum Active Window (tMAW)") );
+
+ // Decoding bits 7~6 (Reserved)
+ l_spd_buffer.extractToRight<OPT_FEAT_RESERVED_START, OPT_FEAT_RESERVED_LEN>(l_reserved);
+
+ mss::check::spd::valid_value_warn(i_target_dimm,
+ (l_reserved == RESERVED),
+ BYTE_INDEX,
+ l_reserved,
+ "Failed check for Reserved bits") ;
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY(eff_dram_mac(l_target_mcs, &l_mac[0][0]));
+ FAPI_TRY(eff_dram_tmaw(l_target_mcs, &l_tmaw[0][0]));
+
+ // Update attribute to decoded byte values
+ l_mac[PORT_NUM][DIMM_NUM] = MAC_map[l_MAC];
+ l_tmaw[PORT_NUM][DIMM_NUM] = tMAW_map[l_tMAW];
+
+ // Update MCS level attribute
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_MAC, l_target_mcs, l_mac));
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_TMAW, l_target_mcs, l_tmaw));
+
+ // Print decoded info
+ FAPI_INF("%s. MAC: %d, tMAW: %d",
+ c_str(i_target_dimm),
+ l_tmaw[PORT_NUM][DIMM_NUM],
+ l_mac[PORT_NUM][DIMM_NUM]);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}// decode_sdram_optional_features()
+
+///
+/// @brief Decode SDRAM Thermal and Refresh Options
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte 8, currently reserved
+///
+fapi2::ReturnCode decoder::thermal_and_refresh_options(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 8;
+ const size_t RESERVED_BYTE = 0; // per JEDEC spec
+
+ // Byte variable
+ uint8_t l_reserved = i_spd_data[BYTE_INDEX];
+
+ // Check to assure SPD reserved byte is 0 per JEDEC spec
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_reserved == RESERVED_BYTE),
+ BYTE_INDEX,
+ l_reserved,
+ "Failed check for SPD DRAM reserved byte") );
+
+ // Print decoded info
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}// decode_thermal_and_refresh_options()
+
+
+///
+/// @brief Decode Other SDRAM Optional Features
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte 9
+///
+fapi2::ReturnCode decoder::other_optional_features(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 9;
+ const size_t RESERVED = 0;
+
+ // Soft PPR mapping limits
+ const size_t SOFT_PPR_MAX_VALID_KEY = 2; // Nothing greater doesn't exist
+
+ // PPR mapping limits
+ const size_t PPR_MAX_VALID_KEY = 2; // Nothing greater doesn't exist
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding
+ uint8_t l_reserved = 0;
+ uint8_t l_soft_ppr = 0;// Soft Post Package Repair
+ uint8_t l_ppr = 0; // Post Package Repair
+
+ // Attribute variables used to set decoded vals
+ uint8_t l_soft_PPRs[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+ uint8_t l_PPRs[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Buffer used for bit manipulation
+ fapi2::buffer<uint8_t> l_spd_buffer(i_spd_data[BYTE_INDEX]);
+
+ // Decoding bits 4~0
+ l_spd_buffer.extractToRight<PPR_RESERVED_START, PPR_RESERVED_LEN>(l_reserved);
+
+ mss::check::spd::valid_value_warn(i_target_dimm,
+ (l_reserved == RESERVED),
+ BYTE_INDEX,
+ l_reserved,
+ "Failed check for reserved bits");
+
+ // Decoding bit 5
+ l_spd_buffer.extractToRight<SOFT_PPR_START, SOFT_PPR_LEN>(l_soft_ppr);
+
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_soft_ppr < SOFT_PPR_MAX_VALID_KEY),
+ BYTE_INDEX,
+ l_soft_ppr,
+ "Failed check for SOFT PPR") );
+
+ // Decoding bits 7~6
+ l_spd_buffer.extractToRight<PPR_START, PPR_LEN>(l_ppr);
+
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_ppr < PPR_MAX_VALID_KEY),
+ BYTE_INDEX,
+ l_ppr,
+ "Failed check for PPR") );
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY(eff_dram_soft_ppr(l_target_mcs, &l_soft_PPRs[0][0]));
+ FAPI_TRY(eff_dram_ppr(l_target_mcs, &l_PPRs[0][0]));
+
+ // Update attribute to decoded byte values
+ l_soft_PPRs[PORT_NUM][DIMM_NUM] = soft_ppr_map[l_soft_ppr];
+ l_PPRs[PORT_NUM][DIMM_NUM] = ppr_map[l_ppr];
+
+ // Update MCS level attribute
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_SOFT_PPR, l_target_mcs, l_soft_PPRs));
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_PPR, l_target_mcs, l_PPRs));
+
+ // Printed decoded info
+ FAPI_INF("%s. Soft PPR: %d, PPR: %d, Reserved: %d",
+ c_str(i_target_dimm),
+ l_soft_PPRs[PORT_NUM][DIMM_NUM],
+ l_PPRs[PORT_NUM][DIMM_NUM],
+ l_reserved);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Decode Secondary SDRAM Package Type
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte 10
+///
+fapi2::ReturnCode decoder::secondary_package_type(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 10;
+ const size_t SUPPORTED_VALUE = 0;
+
+ // Byte variables used for decoding
+ uint8_t l_sec_signal_loading = 0;
+ uint8_t l_density_ratio = 0;
+ uint8_t l_sec_die_count = 0;
+ uint8_t l_sec_package_type = 0;
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Currently we do not support asymmetrical assembly of multiple SDRAM package types
+ // According to the JEDEC spec, for modules with symmetrical assembly (which we do support),
+ // this byte must be coded as 0x00. Additional checks were added to isolate any corrupt data failure
+
+ // Buffer used for bit manipulation
+ fapi2::buffer<uint8_t> l_spd_buffer(i_spd_data[BYTE_INDEX]);
+
+ // Decoding bits 1~0 (Signal loading)
+ l_spd_buffer.extractToRight<SEC_SIGNAL_LOAD_START, SEC_SIGNAL_LOAD_LEN>(l_sec_signal_loading);
+
+ // Check to assure SPD DRAM signal loading conforms to JEDEC SPEC
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_sec_signal_loading == SUPPORTED_VALUE),
+ BYTE_INDEX,
+ l_sec_signal_loading,
+ "Failed check for SPD DRAM signal loading") );
+
+ // Decoding bits 3~2 (Density Ratio)
+ l_spd_buffer.extractToRight<DENSITY_RATIO_START, DENSITY_RATIO_LEN>(l_density_ratio);
+
+ // Check to assure SPD density ratio bits are 0 to assure symmetical package
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_density_ratio == SUPPORTED_VALUE),
+ BYTE_INDEX,
+ l_density_ratio,
+ "Failed check for SPD DRAM density ratio") );
+
+ // Decoding bits 6~4 (Die Count)
+ l_spd_buffer.extractToRight<SEC_DIE_COUNT_START, SEC_DIE_COUNT_LEN>(l_sec_die_count);
+
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_sec_die_count == SUPPORTED_VALUE),
+ BYTE_INDEX,
+ l_sec_die_count,
+ "Failed check for SPD DRAM secondary die count") );
+
+ // Decoding bit 7
+ l_spd_buffer.extractToRight<SEC_PACKAGE_TYPE_START, SEC_PACKAGE_TYPE_LEN>(l_sec_package_type);
+
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_sec_package_type == SUPPORTED_VALUE),
+ BYTE_INDEX,
+ l_sec_package_type,
+ "Failed check for SPD DRAM secondary package type") );
+
+ // Printed decoded info
+ FAPI_INF("Signal Loading: %d, DRAM Density Ratio: %d, Die Count: %d, SDRAM Package Type: %d",
+ l_sec_signal_loading,
+ l_density_ratio,
+ l_sec_die_count,
+ l_sec_package_type);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Decode Module Nominal Voltage, VDD
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte 11
+///
+fapi2::ReturnCode decoder::module_nominal_voltage(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 11;
+ const size_t RESERVED = 0; // per JEDEC sepc
+ const size_t SUPPORTED = 1; // per JEDEC sepc
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding
+ uint8_t l_operable = 0;
+ uint8_t l_endurant = 0;
+ uint8_t l_reserved = 0;
+
+ // Attribute variables used to set decoded vals
+ uint64_t l_operable_attrs[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Buffer used for bit manipulation
+ fapi2::buffer<uint8_t> l_spd_buffer(i_spd_data[BYTE_INDEX]);
+
+ // Decoding bits 0 (Operable)
+ l_spd_buffer.extractToRight<OPERABLE_START, OPERABLE_LEN>(l_operable);
+
+ // DDR4 only supports 1.2 V, if not OPERABLE at this voltage than fail IPL
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ l_operable == SUPPORTED,
+ BYTE_INDEX,
+ l_operable,
+ "Failed check for OPERABLE module nominal voltage") );
+ // Decoding bits 1 (Endurant)
+ l_spd_buffer.extractToRight<ENDURANT_START, ENDURANT_LEN>(l_endurant);
+
+ // OPERABLE at 1.2V implies ENDURANT at 1.2V
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ l_endurant == SUPPORTED,
+ BYTE_INDEX,
+ l_endurant,
+ "Failed check for ENDURABLE module nominal voltage") );
+
+ // Decoding bits 7~2 (Reserved)
+ l_spd_buffer.extractToRight<NOM_VOLT_START, NOM_VOLT_LEN>(l_reserved);
+
+ mss::check::spd::valid_value_warn(i_target_dimm,
+ l_reserved == RESERVED,
+ BYTE_INDEX,
+ l_reserved,
+ "Failed check for module nominal voltage RESERVED bits");
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY(spd_module_nominal_voltage(l_target_mcs, &l_operable_attrs[0][0]));
+
+ // Update attribute to decoded byte values
+ l_operable_attrs[PORT_NUM][DIMM_NUM] = l_operable;
+
+ // Update MCS level attribute
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_SPD_MODULE_NOMINAL_VOLTAGE, l_target_mcs, l_operable_attrs) );
+
+ // Printed decoded info
+ FAPI_INF( "%s Operable: %d, Endurant: %d, Reserved: %d",
+ c_str(i_target_dimm),
+ l_operable,
+ l_endurant,
+ l_reserved );
+
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Decode Module Organization
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte 12
+///
+fapi2::ReturnCode decoder::module_organization(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 12;
+ const size_t RESERVED = 0;
+
+ // SDRAM device width mapping limits
+ const size_t MAX_DEV_WIDTH_VALID_KEY = 3; // All others reserved
+
+ // Number of package ranks per DIMM mapping limits
+ const size_t MAX_PKG_RANKS_VALID_KEY = 7; // max supported packages
+
+ // Rank mix limits
+ const size_t SYMMETRICAL = 0; // asymmetical not supported
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding
+ uint8_t l_device_width = 0;
+ uint8_t l_num_pkgs_ranks = 0;
+ uint8_t l_rank_mix = 0;
+ uint8_t l_reserved = 0;
+
+ // Attribute variables used to set decoded vals
+ uint8_t l_sdram_device_widths[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+ uint8_t l_num_pkg_ranks_per_dimm[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+ uint8_t l_rank_mixes[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Buffer used for bit manipulation
+ fapi2::buffer<uint8_t> l_spd_buffer(i_spd_data[BYTE_INDEX]);
+
+ // Decoding Bits 2~0
+ l_spd_buffer.extractToRight<SDRAM_WIDTH_START, SDRAM_WIDTH_LEN>(l_device_width);
+
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ l_device_width <= MAX_DEV_WIDTH_VALID_KEY,
+ BYTE_INDEX,
+ l_device_width,
+ "Failed check for SDRAM device width") );
+ // Decoding Bits 5~3
+ l_spd_buffer.extractToRight<PACKAGE_RANKS_START, PACKAGE_RANKS_LEN>(l_num_pkgs_ranks);
+
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ l_num_pkgs_ranks <= MAX_PKG_RANKS_VALID_KEY,
+ BYTE_INDEX,
+ l_num_pkgs_ranks,
+ "Failed check for number of packages per DIMM") );
+ // Decoding Bit 6
+ l_spd_buffer.extractToRight<RANK_MIX_START, RANK_MIX_LEN>(l_rank_mix);
+
+ // We only support symmetrical rank mix
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ l_rank_mix == SYMMETRICAL,
+ BYTE_INDEX,
+ l_rank_mix,
+ "Failed check for number of packages per DIMM") );
+ // Decoding Bit 7
+ l_spd_buffer.extractToRight<MODULE_ORG_RESERVED_START, MODULE_ORG_RESERVED_LEN>(l_reserved);
+
+ mss::check::spd::valid_value_warn(i_target_dimm,
+ l_reserved == RESERVED,
+ BYTE_INDEX,
+ l_reserved,
+ "Failed check for number of packages per DIMM");
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY(eff_dram_width(l_target_mcs, &l_sdram_device_widths[0][0]));
+ FAPI_TRY(eff_num_packages_per_rank(l_target_mcs, &l_num_pkg_ranks_per_dimm[0][0]));
+ FAPI_TRY(eff_dram_rank_mix(l_target_mcs, &l_rank_mixes[0][0]));
+
+ // Update attribute to decoded byte values
+ l_sdram_device_widths[PORT_NUM][DIMM_NUM] = device_type_map[l_device_width];
+ l_num_pkg_ranks_per_dimm[PORT_NUM][DIMM_NUM] = num_pkgs_ranks_per_dimm_map[l_num_pkgs_ranks];
+ l_rank_mixes[PORT_NUM][DIMM_NUM] = l_rank_mix;
+
+ // Update MCS level attribute
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_WIDTH, l_target_mcs, l_sdram_device_widths) );
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_NUM_PACKAGES_PER_RANK, l_target_mcs, l_num_pkg_ranks_per_dimm) );
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_RANK_MIX, l_target_mcs, l_rank_mixes) );
+
+ // Printed decoded info
+ FAPI_INF( "%s. Device Width: %d, Number of rank packages per DIMM: %d, Rank Mix: %d",
+ c_str(i_target_dimm),
+ l_sdram_device_widths[PORT_NUM][DIMM_NUM],
+ l_num_pkg_ranks_per_dimm[PORT_NUM][DIMM_NUM],
+ l_rank_mixes[PORT_NUM][DIMM_NUM] );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+//TODO
+// Returning correct stuff (bits) ?? Or am I supposed to calc "Module DRAM Capacity" pg 27
+
+///
+/// @brief Decode Module Memory Bus Width
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte 13
+///
+fapi2::ReturnCode decoder::module_memory_bus_width(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 13;
+ const size_t RESERVED = 0;
+
+ // Primary bus width mapping limits
+ const size_t MAX_PRIM_BUS_WIDTH_KEY = 3; // All others reserved
+
+ // Bus width extention mapping limits
+ const size_t MAX_VALID_BUS_WIDTH_EXT_KEY = 1; // All others reserved
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding
+ uint8_t l_bus_width = 0;
+ uint8_t l_bus_width_ext = 0;
+ uint8_t l_reserved = 0;
+
+ // Attribute variables used to set decoded vals
+ uint8_t l_module_bus_widths[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Buffer used for bit manipulation
+ fapi2::buffer<uint8_t> l_spd_buffer(i_spd_data[BYTE_INDEX]);
+
+ // Decoding Bits 2~0
+ l_spd_buffer.extractToRight<BUS_WIDTH_START, BUS_WIDTH_LEN>(l_bus_width);
+
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ l_bus_width <= MAX_PRIM_BUS_WIDTH_KEY,
+ BYTE_INDEX,
+ l_bus_width,
+ "Failed check on primary bus width") );
+ // Decoding Bits 4~3
+ l_spd_buffer.extractToRight<BUS_EXT_WIDTH_START, BUS_EXT_WIDTH_LEN>(l_bus_width_ext);
+
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ l_bus_width_ext <= MAX_VALID_BUS_WIDTH_EXT_KEY,
+ BYTE_INDEX,
+ l_bus_width_ext,
+ "Failed check for bus width extension") );
+ // Decoding bits Bits 7~5
+ l_spd_buffer.extractToRight<BUS_WIDTH_RESERVED_START, BUS_WIDTH_RESERVED_LEN>(l_reserved);
+
+ mss::check::spd::valid_value_warn(i_target_dimm,
+ l_reserved == RESERVED,
+ BYTE_INDEX,
+ l_reserved,
+ "Failed check for bus width reserved bits");
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_module_bus_width(l_target_mcs, &l_module_bus_widths[0][0]) );
+
+ // Update attribute to decoded byte values
+ l_module_bus_widths[PORT_NUM][DIMM_NUM] = prim_bus_width_map[l_bus_width] + bus_width_ext_map[l_bus_width_ext];
+
+ // Update MCS level attribute
+ FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_MODULE_BUS_WIDTH, l_target_mcs, l_module_bus_widths);
+
+ // Printed decoded info
+ FAPI_INF( "%s Module Memory Bus Width (in bits): %d, Primary bus width: %d, Bus width extension: %d",
+ c_str(i_target_dimm),
+ l_module_bus_widths[PORT_NUM][DIMM_NUM],
+ prim_bus_width_map[l_bus_width],
+ bus_width_ext_map[l_bus_width_ext] );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+
+///
+/// @brief Decode Module Thermal Sensor
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte 14, no attribute found for this
+///
+fapi2::ReturnCode decoder::module_thermal_sensor(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 14;
+ const size_t VALID_VALUE = 1;
+ const size_t RESERVED = 0;
+
+ // Byte variables used for decoding
+ uint8_t l_reserved = 0;
+ uint8_t l_thermal_sensor = 0;
+
+ // Attribute variables used to set decoded vals
+ uint8_t l_therm_sensors[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Buffer used for bit manipulation
+ fapi2::buffer<uint8_t> l_spd_buffer(i_spd_data[BYTE_INDEX]);
+
+ // Decoding Bits 6~0
+ l_spd_buffer.extractToRight<THERM_SENSOR_RESERV_START, THERM_SENSOR_RESERV_LEN>(l_reserved);
+
+ mss::check::spd::valid_value_warn(i_target_dimm,
+ l_reserved == RESERVED,
+ BYTE_INDEX,
+ l_reserved,
+ "Failed check for thermal sensor reserved bits");
+ // Decoding bits Bit 7
+ l_spd_buffer.extractToRight<THERM_SENSOR_START, THERM_SENSOR_LEN>(l_thermal_sensor);
+
+ // Length is a single bit (0 or 1), anything larger means corrupt data
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ l_thermal_sensor <= VALID_VALUE,
+ BYTE_INDEX,
+ l_thermal_sensor,
+ "Failed check for thermal sensor") );
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( spd_module_thermal_sensor(l_target_mcs, &l_therm_sensors[0][0]) );
+
+ // Update attribute to decoded byte values
+ l_therm_sensors[PORT_NUM][DIMM_NUM] = l_thermal_sensor;
+
+ // Update MCS level attribute
+ FAPI_ATTR_SET(fapi2::ATTR_SPD_MODULE_THERMAL_SENSOR, l_target_mcs, l_therm_sensors);
+
+ // Printed decoded info
+ FAPI_INF("%s. Thermal sensor: %d, Reserved: %d",
+ c_str(i_target_dimm),
+ l_thermal_sensor,
+ l_reserved );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Decode Extended Module Type
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte 15, no attribute for this byte
+///
+fapi2::ReturnCode decoder::extended_module_type(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 15;
+ const size_t RESERVED = 0;
+
+ // Byte variables used for decoding
+ uint8_t l_ext_module_type = 0;
+ uint8_t l_reserved = 0;
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Buffer used for bit manipulation
+ fapi2::buffer<uint8_t> l_spd_buffer(i_spd_data[BYTE_INDEX]);
+
+ // Decoding Bits 3~0
+ l_spd_buffer.extractToRight<EXT_MOD_TYPE_START, EXT_MOD_TYPE_LEN>(l_ext_module_type);
+
+ // According to JEDEC spec this value should be coded as 0000 which is the value as the reserved bits
+ FAPI_TRY(mss::check::spd::valid_value_fail(i_target_dimm,
+ l_ext_module_type == RESERVED,
+ BYTE_INDEX,
+ l_ext_module_type,
+ "Failed check for extended base module type") );
+ // Decoding Bit 7~4
+ l_spd_buffer.extractToRight<EXT_MOD_TYPE_RESERV_START, EXT_MOD_TYPE_RESERV_LEN>(l_reserved);
+
+ mss::check::spd::valid_value_warn(i_target_dimm,
+ l_reserved == RESERVED,
+ BYTE_INDEX,
+ l_reserved,
+ "Failed check for extended module type reserved bits");
+
+ // Printed decoded info
+ FAPI_INF("%s. Extended Base Module Type: %d, Reserved: %d",
+ c_str(i_target_dimm),
+ l_ext_module_type,
+ l_reserved );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Decode Timebases
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte 17
+///
+fapi2::ReturnCode decoder::timebases(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 17;
+ const size_t RESERVED = 0;
+
+ // Medium timebase mapping limits
+ const int64_t MAX_VALID_MTB_KEY = 1; // All others reserved
+
+ // Fine timebase mapping limits
+ const int64_t MAX_VALID_FTB_KEY = 1; // All others reserved
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding
+ int64_t l_fine_timebase = 0;
+ int64_t l_medium_timebase = 0;
+ int64_t l_reserved = 0;
+
+ // Attribute variables used to set decoded vals
+ int64_t l_FTBs[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+ int64_t l_MTBs[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Buffer used for bit manipulation
+ fapi2::buffer<uint8_t> l_spd_buffer(i_spd_data[BYTE_INDEX]);
+
+ // TODO - update ENUMS to take account to int64_t
+ // Decoding Bits 1~0
+ l_spd_buffer.extractToRight<FINE_TIMEBASE_START, FINE_TIMEBASE_LEN>(l_fine_timebase);
+
+ FAPI_TRY(mss::check::spd::valid_value_fail(i_target_dimm,
+ l_fine_timebase < MAX_VALID_FTB_KEY,
+ BYTE_INDEX,
+ l_fine_timebase,
+ "Failed check for fine timebase") );
+ // Decoding Bits 3~2
+ l_spd_buffer.extractToRight<MED_TIMEBASE_START, MED_TIMEBASE_LEN>(l_medium_timebase);
+
+ FAPI_TRY(mss::check::spd::valid_value_fail(i_target_dimm,
+ l_medium_timebase < MAX_VALID_MTB_KEY,
+ BYTE_INDEX,
+ l_medium_timebase,
+ "Failed check for medium timebase") );
+ // Decoding bits Bits 7~4
+ l_spd_buffer.extractToRight<TIMEBASE_RESERV_START, TIMEBASE_RESERV_LEN>(l_reserved);
+
+ mss::check::spd::valid_value_warn(i_target_dimm,
+ l_reserved == RESERVED,
+ BYTE_INDEX,
+ l_reserved,
+ "Failed check for timebases reserved bits");
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( spd_fine_timebase(l_target_mcs, &l_FTBs[0][0]) );
+ FAPI_TRY( spd_medium_timebase(l_target_mcs, &l_MTBs[0][0]) );
+
+ // Update attribute to decoded byte values
+ l_FTBs[PORT_NUM][DIMM_NUM] = fine_timebase_map[l_fine_timebase];
+ l_MTBs[PORT_NUM][DIMM_NUM] = medium_timebase_map[l_medium_timebase];
+
+ // Update MCS level attribute
+ FAPI_ATTR_SET( fapi2::ATTR_SPD_FINE_TIMEBASE, l_target_mcs, l_FTBs );
+ FAPI_ATTR_SET( fapi2::ATTR_SPD_MEDIUM_TIMEBASE, l_target_mcs, l_MTBs );
+
+ // Printed decoded info
+ FAPI_INF( "%s. Fine Timebase: %d, Medium Timebase: %d",
+ c_str(i_target_dimm),
+ l_FTBs[PORT_NUM][DIMM_NUM],
+ l_MTBs[PORT_NUM][DIMM_NUM] );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Decode SDRAM Minimum Cycle Time
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte 18 & Byte 125
+/// This byte depends on the fine & medium timebase values
+/// obtained from Byte 17
+///
+fapi2::ReturnCode decoder::min_cycle_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX_MTB = 18; // min cycle medium timebase (mtb)
+ const size_t BYTE_INDEX_FTB = 125; // min cycle fine timebase (ftb)
+
+ const int64_t MIN_CYCLE_TIME_MTB = 1; // from JEDEC
+ const int64_t MAX_CYCLE_TIME_MTB = 255; // from JEDEC
+
+ const int64_t MIN_CYCLE_TIME_FTB = -128; // from JEDEC
+ const int64_t MAX_CYCLE_TIME_FTB = 127; // from JEDEC
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding
+ int64_t l_tCKmin_mtb = 0;
+ int64_t l_tCKmin_ftb = 0;
+
+ // Attribute variables
+ int64_t l_min_cycle_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+ int64_t l_MTBs[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+ int64_t l_FTBs[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX_MTB,
+ i_spd_data[BYTE_INDEX_MTB]);
+
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX_FTB,
+ i_spd_data[BYTE_INDEX_FTB]);
+
+ // Retrieve SDRAM Maximum Cycle Time
+ l_tCKmin_mtb = i_spd_data[BYTE_INDEX_MTB];
+
+ FAPI_TRY(mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_tCKmin_mtb <= MAX_CYCLE_TIME_MTB) &&
+ (l_tCKmin_mtb >= MIN_CYCLE_TIME_MTB),
+ BYTE_INDEX_MTB,
+ l_tCKmin_mtb,
+ "Failed check for tCKmin (min cycle time) in MTB units") );
+
+ // Retrieve Fine Offset for SDRAM Minimum Cycle Time
+ // casted int8_t undoes 2's complement on the uint8_t spd data
+ l_tCKmin_ftb = int8_t(i_spd_data[BYTE_INDEX_FTB]);
+
+ FAPI_TRY(mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_tCKmin_ftb <= MAX_CYCLE_TIME_FTB) &&
+ (l_tCKmin_ftb >= MIN_CYCLE_TIME_FTB),
+ BYTE_INDEX_FTB,
+ l_tCKmin_ftb,
+ "Failed check for tCKmin (min cycle time) in FTB units") );
+
+
+ // Retrieving medium timebase (MTB) multiplier used for timing calculation
+ FAPI_TRY( spd_medium_timebase(l_target_mcs, &l_MTBs[0][0]) );
+ FAPI_TRY( spd_fine_timebase(l_target_mcs, &l_FTBs[0][0]) );
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( spd_timing_tckmin(l_target_mcs, &l_min_cycle_times[0][0]) );
+
+ // Update attribute to decoded byte values
+ // Calculating minimum cycle time in picosconds
+ l_min_cycle_times[PORT_NUM][DIMM_NUM] = calc_timing(l_tCKmin_mtb,
+ l_tCKmin_ftb,
+ l_MTBs[PORT_NUM][DIMM_NUM],
+ l_FTBs[PORT_NUM][DIMM_NUM]);
+ // Update MCS level attribute
+ FAPI_ATTR_SET( fapi2::ATTR_TIMING_TCKMIN, l_target_mcs, l_min_cycle_times );
+
+ // Printed decoded info
+ FAPI_INF("%s. tCKmin (min cycle time): %d (ps)",
+ c_str(i_target_dimm),
+ l_min_cycle_times[PORT_NUM][DIMM_NUM] );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Decode SDRAM Maximum Cycle Time
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte 19 and 124
+///
+fapi2::ReturnCode decoder::max_cycle_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX_MTB = 19; // min cycle medium timebase (mtb)
+ const size_t BYTE_INDEX_FTB = 124; // min cycle fine timebase (ftb)
+
+ const int64_t MIN_CYCLE_TIME_MTB = 1; // from JEDEC
+ const int64_t MAX_CYCLE_TIME_MTB = 255; // from JEDEC
+
+ const int64_t MIN_CYCLE_TIME_FTB = -128; // from JEDEC
+ const int64_t MAX_CYCLE_TIME_FTB = 127; // from JEDEC
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding
+ int64_t l_tCKmax_mtb = 0;
+ int64_t l_tCKmax_ftb = 0;
+
+ // Attribute variable
+ int64_t l_max_cycle_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+ int64_t l_MTBs[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+ int64_t l_FTBs[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX_MTB,
+ i_spd_data[BYTE_INDEX_MTB]);
+
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX_FTB,
+ i_spd_data[BYTE_INDEX_FTB]);
+
+ // Retrieve SDRAM Maximum Cycle Time
+ l_tCKmax_mtb = i_spd_data[BYTE_INDEX_MTB];
+
+ FAPI_TRY(mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_tCKmax_mtb <= MAX_CYCLE_TIME_MTB) &&
+ (l_tCKmax_mtb >= MIN_CYCLE_TIME_MTB),
+ BYTE_INDEX_MTB,
+ l_tCKmax_mtb,
+ "Failed check for tCKmin (min cycle time) in MTB units") );
+
+ // Retrieve Fine Offset for SDRAM Maximum Cycle Time
+ // casted int8_t undoes 2's complement on the uint8_t spd data
+ l_tCKmax_ftb = int8_t(i_spd_data[BYTE_INDEX_FTB]);
+
+ FAPI_TRY(mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_tCKmax_ftb <= MAX_CYCLE_TIME_FTB) &&
+ (l_tCKmax_ftb >= MIN_CYCLE_TIME_FTB),
+ BYTE_INDEX_FTB,
+ l_tCKmax_ftb,
+ "Failed check for tCKmin (min cycle time) in FTB units") );
+
+ // Retrieving medium timebase (MTB) multiplier used for timing calculation
+ FAPI_TRY( spd_medium_timebase(l_target_mcs, &l_MTBs[0][0]) );
+ FAPI_TRY( spd_fine_timebase(l_target_mcs, &l_FTBs[0][0]) );
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY(spd_timing_tckmax(l_target_mcs, &l_max_cycle_times[0][0]))
+
+ // Update attribute to decoded byte values
+ l_max_cycle_times[PORT_NUM][DIMM_NUM] = calc_timing(l_tCKmax_mtb,
+ l_tCKmax_ftb,
+ l_MTBs[PORT_NUM][DIMM_NUM],
+ l_FTBs[PORT_NUM][DIMM_NUM]);
+
+ // Update MCS level attribute
+ FAPI_ATTR_SET( fapi2::ATTR_TIMING_TCKMAX, l_target_mcs, l_max_cycle_times );
+
+ // Printed decoded info
+ FAPI_INF("%s. tCKmax (max cycle time): %d (ps)",
+ c_str(i_target_dimm),
+ l_max_cycle_times[PORT_NUM][DIMM_NUM] );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Decode Minimum CAS Latency Time
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte 24 & 123
+///
+fapi2::ReturnCode decoder::min_cas_latency_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX_MTB = 24; // min cycle medium timebase (mtb)
+ const size_t BYTE_INDEX_FTB = 123; // min cycle fine timebase (ftb)
+
+ const int64_t MIN_CYCLE_TIME_MTB = 1; // from JEDEC
+ const int64_t MAX_CYCLE_TIME_MTB = 255; // from JEDEC
+
+ const int64_t MIN_CYCLE_TIME_FTB = -128; // from JEDEC
+ const int64_t MAX_CYCLE_TIME_FTB = 127; // from JEDEC
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding
+ int64_t l_tAAmin_mtb = 0;
+ int64_t l_tAAmin_ftb = 0;
+
+ // Attribute variable
+ int64_t l_min_cas_latency_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+ int64_t l_MTBs[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+ int64_t l_FTBs[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX_MTB,
+ i_spd_data[BYTE_INDEX_MTB]);
+
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX_FTB,
+ i_spd_data[BYTE_INDEX_FTB]);
+
+ // Retrieve SDRAM Minimum CAS Latency Time
+ l_tAAmin_mtb = i_spd_data[BYTE_INDEX_MTB];
+
+ FAPI_TRY(mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_tAAmin_mtb <= MAX_CYCLE_TIME_MTB) &&
+ (l_tAAmin_mtb >= MIN_CYCLE_TIME_MTB),
+ BYTE_INDEX_MTB,
+ l_tAAmin_mtb,
+ "Failed check for min CAS latency time (tAAmin) in MTB units") );
+
+ // Retrieve Fine Offset for Minimum CAS Latency Time
+ // casted int8_t undoes 2's complement on the uint8_t spd data
+ l_tAAmin_ftb = int8_t(i_spd_data[BYTE_INDEX_FTB]);
+
+ FAPI_TRY(mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_tAAmin_ftb <= MAX_CYCLE_TIME_FTB) &&
+ (l_tAAmin_ftb >= MIN_CYCLE_TIME_FTB),
+ BYTE_INDEX_FTB,
+ l_tAAmin_ftb,
+ "Failed check for min CAS latency time (tAAmin) in FTB units") );
+
+ // Retrieving medium timebase (MTB) multiplier used for timing calculation
+ FAPI_TRY( spd_medium_timebase(l_target_mcs, &l_MTBs[0][0]) );
+ FAPI_TRY( spd_fine_timebase(l_target_mcs, &l_FTBs[0][0]) );
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY(spd_timing_taamin(l_target_mcs, &l_min_cas_latency_times[0][0]))
+
+ // Update attribute to decoded byte values
+ l_min_cas_latency_times[PORT_NUM][DIMM_NUM] = calc_timing(l_tAAmin_mtb,
+ l_tAAmin_ftb,
+ l_MTBs[PORT_NUM][DIMM_NUM],
+ l_FTBs[PORT_NUM][DIMM_NUM]);
+
+ // Update MCS level attribute
+ FAPI_ATTR_SET( fapi2::ATTR_TIMING_TAAMIN, l_target_mcs, l_min_cas_latency_times );
+
+ // Printed decoded info
+ FAPI_INF("%s. tAAmin (min cycle time): %d (ps)",
+ c_str(i_target_dimm),
+ l_min_cas_latency_times[PORT_NUM][DIMM_NUM] );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+#if 0
+
+///
+/// @brief Decode CAS Latencies Supported
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte 20-23
+///
+fapi2::ReturnCode decoder::supported_cas_latencies(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t FIRST_BYTE = 20;
+ const size_t SEC_BYTE = 21;
+ const size_t THIRD_BYTE = 22;
+ const size_t FORTH_BYTE = 23;
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding
+ uint64_t l_supported_cas_lat = 0;
+
+ // Attribute variables used to set decoded vals
+ uint64_t l_supported_CLs[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Buffers used for bit manipulation
+ fapi2::buffer<uint8_t> l_first_byte_buff(i_spd_data[FIRST_BYTE]);
+ fapi2::buffer<uint8_t> l_second_byte_buff(i_spd_data[SEC_BYTE]);
+ fapi2::buffer<uint8_t> l_third_byte_buff(i_spd_data[THIRD_BYTE]);
+ fapi2::buffer<uint8_t> l_forth_byte_buff(i_spd_data[FORTH_BYTE]);
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // TODO - update ENUMS to take account to int64_t
+
+ // Combine Bytes 20 - 23 to create bitmap
+ l_first_byte_buff.extractToRight<CAS_BYTE_1_START, CAS_BYTE_1_LEN>(l_supported_cas_lat).
+ l_second_byte_buff.extractToRight<CAS_BYTE_2_START, CAS_BYTE_2_LEN>(l_supported_cas_lat).
+ l_third_byte_buff.extractToRight<CAS_BYTE_3_START, CAS_BYTE_3_LEN>(l_supported_cas_lat).
+ l_forth_byte_buff.extractToRight<CAS_BYTE_4_START, CAS_BYTE_4_LEN>(l_supported_cas_lat);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( cas_latencies_supported(l_target_mcs, &l_supported_CLs[0][0]) );
+
+ // Update attribute to decoded byte values
+ l_supported_CLs[PORT_NUM][DIMM_NUM] = l_supported_cas_lat;
+
+ // Update MCS level attribute
+ FAPI_ATTR_SET( fapi2::ATTR_SPD_CAS_LATENCIES_SUPPORTED, l_target_mcs, l_supported_CLs );
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+
+
+///
+/// @brief Decode Minimum RAS to CAS Delay Time
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte 25
+///
+fapi2::ReturnCode decoder::min_ras_to_cas_delay_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 25;
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Attribute variable (rcd = ras to cas delay)
+ int64_t l_min_rcd_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_trcd(l_target_mcs, &l_min_rcd_times[0][0]) );
+
+ // Update attribute to decoded byte values
+ l_min_rcd_times[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) );
+
+ // Update MCS level attribute
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TRCD, l_target_mcs, l_min_rcd_times );
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Decode Minimum Row Precharge Delay Time
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte 26
+///
+fapi2::ReturnCode decoder::min_row_precharge_delay_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 26;
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Attribute variable (rp = row to precharge)
+ int64_t l_min_rp_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_trp(l_target_mcs, &l_min_rp_times[0][0]) );
+
+ // Update attribute to decoded byte values
+ l_min_rp_times[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) );
+
+ // Update MCS level attribute
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TRP, l_target_mcs, l_min_rp_times );
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Decode Minimum Active to Precharge Delay Time (tRASmin)
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Byte 27 Bits 3~0 along with Byte 28 Bits 7~0
+///
+fapi2::ReturnCode decoder::min_activate_to_precharge_delay_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX_MSB = 27; // MSN = most significant byte
+ const size_t BYTE_INDEX_LSB = 28; // LSB = least significant byte
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding (tRAS = Active to Precharge Delay Time)
+ int64_t l_tRASmin = 0;
+
+ // Attribute variable
+ int64_t l_min_ras_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Buffers used for bit manipulation
+ fapi2::buffer<uint8_t> l_buffer_upper_nibble(i_spd_data[BYTE_INDEX_MSB]);
+ fapi2::buffer<uint8_t> l_buffer_lower_byte(i_spd_data[BYTE_INDEX_LSB]);
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // TODO - update ENUMS to take account to int64_t
+
+ // Combining bits to create timing value
+ l_buffer_upper_nibble.extractToRight<TRASMIN_MSN_START, TRASMIN_MSN_LEN>(l_tRASmin);
+ l_buffer_lower_byte.extractToRight<TRASMIN_LSB_START, TRASMIN_LSB_LEN>(l_tRASmin);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_tras(l_target_mcs, &l_min_ras_times[0][0]) );
+
+ // Update attribute to decoded byte values (returning picoseconds)
+ l_min_ras_times[PORT_NUM][DIMM_NUM] = ns_to_ps(l_tRASmin);
+
+ // Update MCS level attribute
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TRAS, l_target_mcs, l_min_ras_times );
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Minimum Active to Active/Refresh Delay Time (tRCmin)
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte Byte 27 Bits 7~4 along with Byte 29 Bits 7~0
+///
+fapi2::ReturnCode
+decoder::min_activate_to_activate_refresh_delay_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX_MSN = 27; // MSN = most significant nibble
+ const size_t BYTE_INDEX_LSB = 28; // LSB = least significant byte
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding (RC = Activate to Activate/Refresh Delay)
+ uint16_t l_tRCmin = 0;
+
+ // Attribute variable
+ uint16_t l_min_rc_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // TODO - update ENUMS to take account to int64_t
+
+ // Buffers used for bit manipulation
+ fapi2::buffer<uint8_t> l_buffer_upper_nibble(i_spd_data[BYTE_INDEX_MSN]);
+ fapi2::buffer<uint8_t> l_buffer_lower_byte(i_spd_data[BYTE_INDEX_LSB]);
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Combining bits to create timing value
+ l_buffer_upper_nibble.extractToRight<TRCMIN_MSN_START, TRCMIN_MSN_LEN>(l_tRCmin);
+ l_buffer_lower_byte.extractToRight<TRCMIN_LSB_START, TRCMIN_LSB_LEN>(l_tRCmin);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_trc(l_target_mcs, &l_min_rc_times[0][0]) );
+
+ // Update attribute to decoded byte values (returning picoseconds, currently nanoseconds)
+ l_min_rc_times[PORT_NUM][DIMM_NUM] = ns_to_ps(l_tRCmin);
+
+ // Update MCS level attribute (returning picoseconds, currently nanoseconds)
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TRC, l_target_mcs, l_min_rc_times );
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Minimum Refresh Recovery Delay Time 1 (tRFC1min)
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte Byte 30 (LSB) along with Byte 31 (MSB)
+///
+fapi2::ReturnCode decoder::min_refresh_recovery_delay_time_1(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX_MSB = 31; // MSN = most significant nibble
+ const size_t BYTE_INDEX_LSB = 30; // LSB = least significant byte
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding (RFC1 = Minimum Refresh Recovery Delay Time)
+ uint32_t l_tRFC1min = 0;
+
+ // Attribute variable
+ uint32_t l_min_rfc1_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Buffers used for bit manipulation
+ fapi2::buffer<uint8_t> l_buffer_MSB(i_spd_data[BYTE_INDEX_MSB]);
+ fapi2::buffer<uint8_t> l_buffer_LSB(i_spd_data[BYTE_INDEX_LSB]);
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Combining bits to create timing value
+ l_buffer_MSB.extractToRight<, >();
+ l_buffer_LSB.extractToRight<, >();
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_trc(l_target_mcs, &l_min_rfc1_times[0][0]) );
+
+ // Update attribute to decoded byte values (returning picoseconds, currently nanoseconds)
+ l_min_rfc1_times[PORT_NUM][DIMM_NUM] = ns_to_ps(l_tRFC1min);
+
+ // Update MCS level attribute (returning picoseconds, currently nanoseconds)
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TRFC1, l_target_mcs, l_min_rfc1_times );
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Minimum Refresh Recovery Delay Time 2 (tRFC2min)
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte Byte 32 (LSB) along with Byte 33 (MSB)
+///
+fapi2::ReturnCode decoder::min_refresh_recovery_delay_time_2(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX_MSB = 33; // MSN = most significant nibble
+ const size_t BYTE_INDEX_LSB = 32; // LSB = least significant byte
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding (RFC1 = Minimum Refresh Recovery Delay 2)
+ uint32_t l_tRFC2min = 0;
+
+ // Attribute variable
+ uint32_t l_min_rfc2_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Buffers used for bit manipulation
+ fapi2::buffer<uint8_t> l_buffer_MSB(i_spd_data[BYTE_INDEX_MSB]);
+ fapi2::buffer<uint8_t> l_buffer_LSB(i_spd_data[BYTE_INDEX_LSB]);
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Combining bits to create timing value
+ l_buffer_MSB.extractToRight<, >();
+ l_buffer_LSB.extractToRight<, >();
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_trc(l_target_mcs, &l_min_rfc2_times[0][0]) );
+
+ // Update attribute to decoded byte values (returning picoseconds, currently nanoseconds)
+ l_min_rfc1_times[PORT_NUM][DIMM_NUM] = ns_to_ps(l_tRFC2min);
+
+ // Update MCS level attribute (returning picoseconds, currently nanoseconds)
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TRFC2, l_target_mcs, l_min_rfc2_times );
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Minimum Refresh Recovery Delay Time 4 (tRFC4min)
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte Byte 34 (LSB) along with Byte 5 (MSB)
+///
+fapi2::ReturnCode decoder::min_refresh_recovery_delay_time_4(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX_MSB = 35; // MSN = most significant nibble
+ const size_t BYTE_INDEX_LSB = 34; // LSB = least significant byte
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding (RFC4 = Minimum Refresh Recovery Delay 4)
+ uint32_t l_tRFC4min = 0;
+
+ // Attribute variable
+ uint32_t l_min_rfc4_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Buffers used for bit manipulation
+ fapi2::buffer<uint8_t> l_buffer_MSB(i_spd_data[BYTE_INDEX_MSB]);
+ fapi2::buffer<uint8_t> l_buffer_LSB(i_spd_data[BYTE_INDEX_LSB]);
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Combining bits to create timing value
+ l_buffer_MSB.extractToRight<, >();
+ l_buffer_LSB.extractToRight<, >();
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_trc(l_target_mcs, &l_min_rfc4_times[0][0]) );
+
+ // Update attribute to decoded byte values (returning picoseconds, currently nanoseconds)
+ l_min_rfc1_times[PORT_NUM][DIMM_NUM] = ns_to_ps(l_tRFC4min);
+
+ // Update MCS level attribute (returning picoseconds, currently nanoseconds)
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TRFC2, l_target_mcs, l_min_rfc4_times );
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Minimum Four Activate Window Delay Time (t FAW min)
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Byte 36 Bits 3 ~ 0 along with Byte 37 Bits 7 ~ 0
+///
+fapi2::ReturnCode decoder::min_four_activate_window_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX_MSN = 36; // MSN = most significant nibble
+ const size_t BYTE_INDEX_LSB = 37; // LSB = least significant byte
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding (FAW = Four Activate Window Delay)
+ uint16_t l_tFAW = 0;
+
+ // Attribute variable
+ uint16_t l_min_faw_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // TODO - update ENUMS to take account to int64_t
+
+ // Buffers used for bit manipulation
+ fapi2::buffer<uint8_t> l_buffer_upper_nibble(i_spd_data[BYTE_INDEX_MSN]);
+ fapi2::buffer<uint8_t> l_buffer_lower_byte(i_spd_data[BYTE_INDEX_LSB]);
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Combining bits to create timing value
+ l_buffer_upper_nibble.extractToRight<TRCMIN_MSN_START, TRCMIN_MSN_LEN>(l_tFAW);
+ l_buffer_lower_byte.extractToRight<TRCMIN_LSB_START, TRCMIN_LSB_LEN>(l_tFAW);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_trc(l_target_mcs, &l_min_faw_times[0][0]) );
+
+ // Update attribute to decoded byte values (returning picoseconds, currently nanoseconds)
+ l_min_faw_times[PORT_NUM][DIMM_NUM] = ns_to_ps(l_tFAW);
+
+ // Update MCS level attribute (returning picoseconds, currently nanoseconds)
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TRC, l_target_mcs, l_min_faw_times );
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Minimum Activate to Activate Delay Time (tRRD_Smin)
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Byte 38
+///
+fapi2::ReturnCode
+decoder::min_act_to_act_delay_time_diff_bank_group(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 38;
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Attribute variable (rrd_s = Activate to Activate Delay)
+ int64_t l_min_tRRD_S[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_trrd(l_target_mcs, &l_min_tRRD_S[0][0]) );
+
+ // Update attribute to decoded byte values
+ l_min_tRRD_S[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) );
+
+ // Update MCS level attribute
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TRRD_S, l_target_mcs, l_min_tRRD_S );
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Minimum Activate to Activate Delay Time (tRRD_Lmin), samebank group
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Byte 39
+///
+fapi2::ReturnCode
+decoder::min_act_to_act_delay_time_same_bank_group(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 39;
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Attribute variable (rrd_s = Activate to Activate Delay)
+ int64_t l_min_tRRD_S[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_trrd(l_target_mcs, &l_min_tRRD_S[0][0]) );
+
+ // Update attribute to decoded byte values
+ l_min_tRRD_S[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) );
+
+ // Update MCS level attribute
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TRRD_L, l_target_mcs, l_min_tRRD_S );
+
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Minimum CAS to CAS Delay Time (tCCD_Lmin), same bank group
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Byte 40
+///
+fapi2::ReturnCode decoder::min_cas_to_cas_delay_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 40;
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Attribute variable (CCD_L = Minimum CAS to CAS Delay Time, same bank group)
+ int64_t l_min_tCCD_L[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_trrd(l_target_mcs, &l_min_tCCD_L[0][0]) );
+
+ // Update attribute to decoded byte values
+ l_min_tCCD_L[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) );
+
+ // Update MCS level attribute
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TCCD_L, l_target_mcs, l_min_tCCD_L );
+
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Minimum Write Recovery Time (tWRmin)
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Byte 41 Bits 3~0, Byte 42 Bits 7~0
+///
+fapi2::ReturnCode decoder::min_write_recovery_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX_MSN = 41; // MSN = most significant nibble
+ const size_t BYTE_INDEX_LSB = 42; // LSB = least significant byte
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding (FAW = Four Activate Window Delay)
+ uint16_t l_tWRmin = 0;
+
+ // Attribute variable
+ int64_t l_min_wr_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // TODO - update ENUMS to take account to int64_t
+
+ // Buffers used for bit manipulation
+ fapi2::buffer<uint8_t> l_buffer_upper_nibble(i_spd_data[BYTE_INDEX_MSN]);
+ fapi2::buffer<uint8_t> l_buffer_lower_byte(i_spd_data[BYTE_INDEX_LSB]);
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Combining bits to create timing value
+ l_buffer_upper_nibble.insert<, >(l_tWRmin);
+ l_buffer_lower_byte.insert<, >(l_tWRmin);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_twr(l_target_mcs, &l_min_wr_times[0][0]) );
+
+ // Update attribute to decoded byte values (returning picoseconds, currently nanoseconds)
+ l_min_wr_times[PORT_NUM][DIMM_NUM] = ns_to_ps(l_tWRmin);
+
+ // Update MCS level attribute (returning picoseconds, currently nanoseconds)
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TWR, l_target_mcs, l_min_wr_times );
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Minimum Write to Read Time (tWTR_Smin), different bank group
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Byte 43 Bits 3~0, Byte 44 Bits 7~0
+///
+fapi2::ReturnCode decoder::min_write_to_read_time_diff_bank_group(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX_MSN = 43; // MSN = most significant nibble
+ const size_t BYTE_INDEX_LSB = 44; // LSB = least significant byte
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding (WRT = Write to Read Time)
+ int64_t l_tWRTmin = 0;
+
+ // Attribute variable
+ int64_t l_min_wrt_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // TODO - update ENUMS to take account to int64_t
+
+ // Buffers used for bit manipulation
+ fapi2::buffer<uint8_t> l_buffer_upper_nibble(i_spd_data[BYTE_INDEX_MSN]);
+ fapi2::buffer<uint8_t> l_buffer_lower_byte(i_spd_data[BYTE_INDEX_LSB]);
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Combining bits to create timing value
+ l_buffer_upper_nibble.insert<, >(l_tWRTmin);
+ l_buffer_lower_byte.insert<, >(l_tWRTmin);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_twrt(l_target_mcs, &l_min_wrt_times[0][0]) );
+
+ // Update attribute to decoded byte values (returning picoseconds, currently nanoseconds)
+ l_min_wrt_times[PORT_NUM][DIMM_NUM] = ns_to_ps(l_tWRTmin);
+
+ // Update MCS level attribute (returning picoseconds, currently nanoseconds)
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TWRT, l_target_mcs, l_min_wrt_times );
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Minimum Write to Read Time (tWTR_Lmin), same bank group
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Byte 43 Bits 7~4, Byte 45 Bits 7~0
+///
+fapi2::ReturnCode
+decoder::min_write_to_read_time_same_bank_group(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX_MSN = 43; // MSN = most significant nibble
+ const size_t BYTE_INDEX_LSB = 45; // LSB = least significant byte
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding (WRT = Write to Read Time)
+ int64_t l_tWRTmin = 0;
+
+ // Attribute variable
+ int64_t l_min_wrt_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // TODO - update ENUMS to take account to int64_t
+
+ // Buffers used for bit manipulation
+ fapi2::buffer<uint8_t> l_buffer_upper_nibble(i_spd_data[BYTE_INDEX_MSN]);
+ fapi2::buffer<uint8_t> l_buffer_lower_byte(i_spd_data[BYTE_INDEX_LSB]);
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Combining bits to create timing value
+ l_buffer_upper_nibble.insert<, >(l_tWRTmin);
+ l_buffer_lower_byte.insert<, >(l_tWRTmin);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_twrt(l_target_mcs, &l_min_wrt_times[0][0]) );
+
+ // Update attribute to decoded byte values (returning picoseconds, currently nanoseconds)
+ l_min_wrt_times[PORT_NUM][DIMM_NUM] = ns_to_ps(l_tWRTmin);
+
+ // Update MCS level attribute (returning picoseconds, currently nanoseconds)
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TWRT, l_target_mcs, l_min_wrt_times );
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Connector to SDRAM Bit Mapping
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Bytes 60~77
+///
+fapi2::ReturnCode decoder::connector_to_sdram_bit_mapping(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+// Retrive entire MCS level attribute
+// Update attribute to decoded byte values
+// Update MCS level attribute
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Fine Offset for Minimum CAS to CAS Delay Time (tCCD_Lmin), same bank group
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Byte 117
+///
+fapi2::ReturnCode decoder::offset_for_min_cas_to_cas_delay_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 117;
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Attribute variable (CCD_L = Minimum CAS to CAS Delay Time, same bank group)
+ int64_t l_min_offset_tCCD_L[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_trrd(l_target_mcs, &l_min_offset_tCCD_L[0][0]) );
+
+ // Update attribute to decoded byte values
+ l_min_offset_tCCD_L[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) );
+
+ // Update MCS level attribute
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_OFFSET_DRAM_TCCD_L, l_target_mcs, l_min_offset_tCCD_L );
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+// Retrive entire MCS level attribute
+// Update attribute to decoded byte values
+// Update MCS level attribute
+
+fapi_try_exit:
+return fapi2::current_err;
+}
+
+///
+/// @brief Fine Offset for Minimum Activate to Activate Delay Time(tRRD_Lmin), same bank group
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Byte 118
+///
+fapi2::ReturnCode
+decoder::offset_min_act_to_act_delay_time_diff_bank_gp(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 118;
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Attribute variable (CCD_L = Minimum CAS to CAS Delay Time, same bank group)
+ int64_t l_min_offset_tCCD_L[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_trrd(l_target_mcs, &l_min_offset_tCCD_L[0][0]) );
+
+ // Update attribute to decoded byte values
+ l_min_offset_tCCD_L[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) );
+
+ // Update MCS level attribute
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_OFFSET_DRAM_TCCD_L, l_target_mcs, l_min_offset_tCCD_L );
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+
+}
+
+///
+/// @brief Fine Offset for Minimum Activate to Activate Delay Time (tRRD_Smin), different bank group
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Byte 119
+///
+fapi2::ReturnCode
+decoder::offset_min_act_to_act_delay_time_same_bank_gp(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 119;
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Attribute variable (CCD_L = Minimum CAS to CAS Delay Time, same bank group)
+ int64_t l_min_offset_tCCD_L[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_trrd(l_target_mcs, &l_min_offset_tCCD_L[0][0]) );
+
+ // Update attribute to decoded byte values
+ l_min_offset_tCCD_L[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) );
+
+ // Update MCS level attribute
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_OFFSET_DRAM_TCCD_L, l_target_mcs, l_min_offset_tCCD_L );
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Fine Offset for Minimum Active to Active/Refresh Delay Time (tRCmin)
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Byte 120
+///
+fapi2::ReturnCode
+decoder::offset_for_min_act_to_act_refresh_delay_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 120;
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Attribute variable (CCD_L = Minimum CAS to CAS Delay Time, same bank group)
+ int64_t l_min_offset_tCCD_L[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_trrd(l_target_mcs, &l_min_offset_tCCD_L[0][0]) );
+
+ // Update attribute to decoded byte values
+ l_min_offset_tCCD_L[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) );
+
+ // Update MCS level attribute
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_OFFSET_DRAM_TCCD_L, l_target_mcs, l_min_offset_tCCD_L );
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+
+// Retrive entire MCS level attribute
+// Update attribute to decoded byte values
+// Update MCS level attribute
+
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Fine Offset for Minimum Row Precharge Delay Time (tRPmin)
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Byte 121
+///
+fapi2::ReturnCode
+decoder::offset_for_min_row_precharge_delay_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 121;
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Attribute variable (CCD_L = Minimum CAS to CAS Delay Time, same bank group)
+ int64_t l_min_offset_tCCD_L[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_trrd(l_target_mcs, &l_min_offset_tCCD_L[0][0]) );
+
+ // Update attribute to decoded byte values
+ l_min_offset_tCCD_L[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) );
+
+ // Update MCS level attribute
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_OFFSET_DRAM_TCCD_L, l_target_mcs, l_min_offset_tCCD_L );
+
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+
+///
+/// @brief Fine Offset for Minimum RAS to CAS Delay Time (tRCDmin)
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Byte 122
+///
+fapi2::ReturnCode decoder::offset_for_min_ras_to_cas_delay_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 122;
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Attribute variable (CCD_L = Minimum CAS to CAS Delay Time, same bank group)
+ int64_t l_min_offset_tCCD_L[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_trrd(l_target_mcs, &l_min_offset_tCCD_L[0][0]) );
+
+ // Update attribute to decoded byte values
+ l_min_offset_tCCD_L[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) );
+
+ // Update MCS level attribute
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_OFFSET_DRAM_TCCD_L, l_target_mcs, l_min_offset_tCCD_L );
+
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Fine Offset for Minimum CAS Latency Time (tAAmin)
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Byte 123
+///
+fapi2::ReturnCode decoder::offset_for_min_cas_latency_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 123;
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Attribute variable (CCD_L = Minimum CAS to CAS Delay Time, same bank group)
+ int64_t l_min_offset_tCCD_L[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_trrd(l_target_mcs, &l_min_offset_tCCD_L[0][0]) );
+
+ // Update attribute to decoded byte values
+ l_min_offset_tCCD_L[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) );
+
+ // Update MCS level attribute
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_OFFSET_DRAM_TCCD_L, l_target_mcs, l_min_offset_tCCD_L );
+
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Fine Offset for SDRAM Maximum Cycle Time (tCKAVGmax)
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Byte 124
+///
+fapi2::ReturnCode decoder::offset_for_max_cycle_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 124;
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Attribute variable (CCD_L = Minimum CAS to CAS Delay Time, same bank group)
+ int64_t l_min_offset_tCCD_L[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_trrd(l_target_mcs, &l_min_offset_tCCD_L[0][0]) );
+
+ // Update attribute to decoded byte values
+ l_min_offset_tCCD_L[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) );
+
+ // Update MCS level attribute
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_OFFSET_DRAM_TCCD_L, l_target_mcs, l_min_offset_tCCD_L );
+
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Fine Offset for SDRAM Minimum Cycle Time (tCKAVGmin)
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Byte 125
+///
+fapi2::ReturnCode decoder::offset_for_min_cycle_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 125;
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Attribute variable (CCD_L = Minimum CAS to CAS Delay Time, same bank group)
+ int64_t l_min_offset_tCCD_L[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_trrd(l_target_mcs, &l_min_offset_tCCD_L[0][0]) );
+
+ // Update attribute to decoded byte values
+ l_min_offset_tCCD_L[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) );
+
+ // Update MCS level attribute
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_OFFSET_DRAM_TCCD_L, l_target_mcs, l_min_offset_tCCD_L );
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Cyclical Redundancy Code (CRC) for Base Configuration Section
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Byte 126 (LSB) along with Byte 127 (MSB)
+///
+fapi2::ReturnCode decoder::crc_for_base_config_section(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX_MSB = 127; // MSN = most significant nibble
+ const size_t BYTE_INDEX_LSB = 126; // LSB = least significant byte
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding (WRT = Write to Read Time)
+ int64_t l_tWRTmin = 0;
+
+ // Attribute variable
+ int64_t l_min_wrt_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // TODO - update ENUMS to take account to int64_t
+
+ // Buffers used for bit manipulation
+ fapi2::buffer<uint8_t> l_buffer_upper_nibble(i_spd_data[BYTE_INDEX_MSN]);
+ fapi2::buffer<uint8_t> l_buffer_lower_byte(i_spd_data[BYTE_INDEX_LSB]);
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Combining bits to create timing value
+ l_buffer_upper_nibble.insert<, >(l_tWRTmin);
+ l_buffer_lower_byte.insert<, >(l_tWRTmin);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_twrt(l_target_mcs, &l_min_wrt_times[0][0]) );
+
+ // Update attribute to decoded byte values (returning picoseconds, currently nanoseconds)
+ l_min_wrt_times[PORT_NUM][DIMM_NUM] = ns_to_ps(l_tWRTmin);
+
+ // Update MCS level attribute (returning picoseconds, currently nanoseconds)
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TWRT, l_target_mcs, l_min_wrt_times );
+
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+#endif
+
+}//spd namespace
+}// mss namespace
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/spd/spd_decoder.H b/src/import/chips/p9/procedures/hwp/memory/lib/spd/spd_decoder.H
new file mode 100644
index 000000000..c86dc8816
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/spd/spd_decoder.H
@@ -0,0 +1,424 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/spd/spd_decoder.H $ */
+/* */
+/* 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 spd_decoder.H
+/// @brief SPD decoder declarations
+///
+// *HWP HWP Owner: Andre Marin <aamarin@us.ibm.com>
+// *HWP HWP Backup: Brian Silver <bsilver@us.ibm.com>
+// *HWP Team: Memory
+// *HWP Level: 2
+// *HWP Consumed by: HB:FSP
+
+#ifndef _MSS_SPD_DECODER_H_
+#define _MSS_SPD_DECODER_H_
+
+#include <fapi2.H>
+#include <cstdint>
+
+namespace mss
+{
+namespace spd
+{
+
+
+enum constants : uint64_t
+{
+ // Byte 0
+ BYTES_USED_START = 4,
+ BYTES_USED_LEN = 4,
+
+ BYTES_TOTAL_START = 1,
+ BYTES_TOTAL_LEN = 3,
+
+ BYTES_RESERVED_START = 0,
+ BYTES_RESERVED_LEN = 1,
+
+ // Byte 1 & 2 not used now
+
+ // Byte 3
+ BASE_MODULE_START = 4,
+ BASE_MODULE_LEN = 4,
+
+ HYBRID_MEDIA_START = 1,
+ HYBRID_MEDIA_LEN = 3,
+
+ HYBRID_START = 0,
+ HYBRID_LEN = 1,
+
+ // Byte 4
+ SDRAM_CAPACITY_START = 4,
+ SDRAM_CAPACITY_LEN = 4,
+
+ SDRAM_BANKS_START = 2,
+ SDRAM_BANKS_LEN = 2,
+
+ BANK_GROUP_START = 0,
+ BANK_GROUP_LEN = 2,
+
+ // Byte 5
+ COL_ADDRESS_START = 5,
+ COL_ADDRESS_LEN = 3,
+
+ ROW_ADDRESS_START = 2,
+ ROW_ADDRESS_LEN = 3,
+
+ ADDRESS_RESERVED_START = 0,
+ ADDRESS_RESERVED_LEN = 2,
+
+ // Byte 6
+ PRIM_PRIM_SIGNAL_LOAD_START = 5,
+ PRIM_PRIM_SIGNAL_LOAD_LEN = 2,
+
+ PACKAGE_RESERVE_START = 4,
+ PACKAGE_RESERVE_LEN = 2,
+
+ PRIM_DIE_COUNT_START = 1,
+ PRIM_DIE_COUNT_LEN = 3,
+
+ PRIM_PACKAGE_TYPE_START = 0,
+ PRIM_PACKAGE_TYPE_LEN = 1,
+
+ // Byte 7
+ MAC_START = 4,
+ MAC_LEN = 4,
+
+ TMAW_START = 2,
+ TMAW_LEN = 2,
+
+ OPT_FEAT_RESERVED_START = 0,
+ OPT_FEAT_RESERVED_LEN = 2,
+
+ // Byte 8 reserved
+
+ // Byte 9
+ PPR_RESERVED_START = 3,
+ PPR_RESERVED_LEN = 5,
+
+ SOFT_PPR_START = 2,
+ SOFT_PPR_LEN = 1,
+
+ PPR_START = 0,
+ PPR_LEN = 2,
+
+ // Byte 10
+ SEC_SIGNAL_LOAD_START = 5,
+ SEC_SIGNAL_LOAD_LEN = 2,
+
+ DENSITY_RATIO_START = 4,
+ DENSITY_RATIO_LEN = 2,
+
+ SEC_DIE_COUNT_START = 1,
+ SEC_DIE_COUNT_LEN = 3,
+
+ SEC_PACKAGE_TYPE_START = 0,
+ SEC_PACKAGE_TYPE_LEN = 1,
+
+ // Byte 11
+ OPERABLE_START = 7,
+ OPERABLE_LEN = 1,
+
+ ENDURANT_START = 6,
+ ENDURANT_LEN = 1,
+
+ NOM_VOLT_START = 0,
+ NOM_VOLT_LEN = 6,
+
+ // Byte 12
+ SDRAM_WIDTH_START = 5,
+ SDRAM_WIDTH_LEN = 3,
+
+ PACKAGE_RANKS_START = 2,
+ PACKAGE_RANKS_LEN = 3,
+
+ RANK_MIX_START = 1,
+ RANK_MIX_LEN = 1,
+
+ MODULE_ORG_RESERVED_START = 0,
+ MODULE_ORG_RESERVED_LEN = 1,
+
+ // Byte 13
+ BUS_WIDTH_START = 6,
+ BUS_WIDTH_LEN = 2,
+
+ BUS_EXT_WIDTH_START = 3,
+ BUS_EXT_WIDTH_LEN = 2,
+
+ BUS_WIDTH_RESERVED_START = 0,
+ BUS_WIDTH_RESERVED_LEN = 3,
+
+ // Byte 14
+ THERM_SENSOR_RESERV_START = 1,
+ THERM_SENSOR_RESERV_LEN = 7,
+
+ THERM_SENSOR_START = 0,
+ THERM_SENSOR_LEN = 1,
+
+ // Byte 15
+ EXT_MOD_TYPE_START = 5,
+ EXT_MOD_TYPE_LEN = 3,
+
+ EXT_MOD_TYPE_RESERV_START = 0,
+ EXT_MOD_TYPE_RESERV_LEN = 4,
+
+ // Byte 16 - reserved
+
+ // Byte 17
+ FINE_TIMEBASE_START = 6,
+ FINE_TIMEBASE_LEN = 2,
+
+ MED_TIMEBASE_START = 4,
+ MED_TIMEBASE_LEN = 2,
+
+ TIMEBASE_RESERV_START = 0,
+ TIMEBASE_RESERV_LEN = 4,
+
+ // Byte 18 - bits not decoded
+ // Byte 19 - bits not decoded
+
+ // Byte 20-23
+ CAS_BYTE_1_START = 55,
+ CAS_BYTE_1_LEN = 8,
+ CAS_BYTE_2_START = 47,
+ CAS_BYTE_2_LEN = 8,
+ CAS_BYTE_3_START = 39,
+ CAS_BYTE_3_LEN = 8,
+ CAS_BYTE_4_START = 31,
+ CAS_BYTE_4_LEN = 8,
+
+ // Byte 24 - bits not decoded
+ // Byte 25 - bits not decoded
+ // Byte 26 - bits not decoded
+
+ // Byte 27
+ TRCMIN_MSN_START = 0, // MSN = most significant nibble
+ TRCMIN_MSN_LEN = 4,
+
+ TRASMIN_MSN_START = 4, // MSN = most significant nibble
+ TRASMIN_MSN_LEN = 4,
+
+ // Byte 28
+ TRASMIN_LSB_START = 4, // LSB = least significant byte
+ TRASMIN_LSB_LEN = 8,
+
+ // Byte 29
+ TRCMIN_LSB_START = 4, // LSB = least significant byte
+ TRCMIN_LSB_LEN = 8,
+
+ // Byte 30
+ // TRFC1MIN_LSB_START
+ // TRFC1MIN_LSB_LEN
+
+ // Byte 31
+// TRFC1MIN_MSB_START
+// TRFC1MIN_MSB_LEN
+
+ // Bytes 46 - 59 - reserved
+
+ // Bytes 60 - 77 - Connector to SDRAM Bit Mapping ??
+
+ // Bytes 78 - 116 - reserved
+
+ // Bytes 117 - 125 : bits not decoded
+
+ // Bytes 128 ~ 191 Module-Specific Section ??
+
+ // Bytes 192 ~ 255 Hybrid Memory Architecture Specific Parameters ??
+
+ // Bytes 256 ~ 319 Extended Function Parameter Block ??
+
+ // Bytes 320 ~ 383 Module Supplier’s Data ??
+};
+
+
+class decoder
+{
+
+ public:
+ // Constructor
+ decoder() = default;
+ // Deconstructor
+ virtual ~decoder() = default;
+
+ // Methods
+ virtual fapi2::ReturnCode number_of_bytes(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data,
+ const size_t i_read_spd_size);
+
+ virtual fapi2::ReturnCode revision(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode dram_device_type(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode module_type(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode sdram_density(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode sdram_addressing(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode primary_package_type(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode sdram_optional_features(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode thermal_and_refresh_options(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode other_optional_features(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode secondary_package_type(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode module_nominal_voltage(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode module_organization(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode module_memory_bus_width(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode module_thermal_sensor(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode extended_module_type(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode timebases(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode min_cycle_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode max_cycle_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode min_cas_latency_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ // Note: Yet to be implemented methods
+#if 0
+
+ virtual fapi2::ReturnCode supported_cas_latencies(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+
+ virtual fapi2::ReturnCode min_ras_to_cas_delay_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode min_row_precharge_delay_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode upper_nibble_tRAS_tRC(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode min_activate_to_activate_refresh_delay_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>&
+ i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode min_activate_to_precharge_delay_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>&
+ i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode min_refresh_recovery_delay_time_1(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode min_refresh_recovery_delay_time_2(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode min_refresh_recovery_delay_time_4(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode min_four_activate_window_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode min_act_to_act_delay_time_diff_bank_group(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>&
+ i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode min_act_to_act_delay_time_same_bank_group(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>&
+ i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode min_cas_to_cas_delay_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode min_write_recovery_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode min_write_to_read_time_diff_bank_group(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>&
+ i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode min_write_recovery_time_same_bank_group(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>&
+ i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode connector_to_sdram_bit_mapping(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode offset_for_min_cas_to_cas_delay_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>&
+ i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode offset_min_act_to_act_delay_time_diff_bank_gp(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>&
+ i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode offset_min_act_to_act_delay_time_same_bank_gp(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>&
+ i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode offset_for_min_act_to_act_refresh_delay_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>&
+ i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode offset_for_min_row_precharge_delay_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>&
+ i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode offset_for_min_ras_to_cas_delay_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>&
+ i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode offset_for_min_cas_latency_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode offset_for_min_cycle_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode offset_for_max_cycle_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode crc_for_base_config_section(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+#endif
+};
+
+}// spd
+}// mss
+
+#endif //_MSS_SPD_DECODER_H_
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
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/termination/slew_cal.H b/src/import/chips/p9/procedures/hwp/memory/lib/termination/slew_cal.H
new file mode 100644
index 000000000..e74bb9ad3
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/termination/slew_cal.H
@@ -0,0 +1,144 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/termination/slew_cal.H $ */
+/* */
+/* 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.H
+/// @brief Runs the slew calibration engine
+///
+// *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: HB:FSP
+
+#ifndef _MSS_SLEW_CAL_H_
+#define _MSS_SLEW_CAL_H_
+
+#include <fapi2.H>
+
+namespace mss
+{
+
+// bits: 58:59 DDRPHY_ADR_SYSCLK_PR_VALUE_RO_P0_ADR0_SLEW_DONE_STATUS(0:1)
+enum slew_done_status
+{
+ SLEW_CAL_NOT_DONE = 0b00, ///< Not complete
+ SLEW_CAL_ERRORS = 0b01, ///< Complete, but with errors - didn't reach alignment
+ SLEW_CAL_WARNING = 0b10, ///< Complete, but with warnings - slew cntl is 0b0000
+ SLEW_CAL_SUCCESS = 0b11, ///< OK
+};
+
+// Used for tagging slew rate information in the table. We use enums for tags rather than
+// strings for a few reasons, not the least of which it simplifies putting the tags into error logs.
+enum tags_t
+{
+ TAG_DATA = 0,
+ TAG_ADR = 1,
+
+ TAG_3VNS = 3,
+ TAG_4VNS = 4,
+ TAG_5VNS = 5,
+ TAG_6VNS = 6,
+ TAG_MAXVNS = 7,
+
+ TAG_15OHM = 15,
+ TAG_20OHM = 20,
+ TAG_24OHM = 24,
+ TAG_30OHM = 30,
+ TAG_34OHM = 34,
+ TAG_40OHM = 40,
+
+ TAG_1066MHZ = 1066,
+ TAG_1333MHZ = 1333,
+ TAG_1600MHZ = 1600,
+ TAG_1866MHZ = 1866,
+ TAG_2400MHZ = 2400,
+};
+
+///
+/// @brief find the attribute array index of a tag
+/// @parm[in] i_type, whether this is an adr or dq lookup
+/// @parm[in] tags_t, the tag to find the index of
+/// @return size_t, the attribute array index
+///
+inline size_t index(const tags_t& i_type, const tags_t& i_tag)
+{
+ // Static table to map some tags to indexes.
+ // First are the indexes for DATA, second are the indexes for ADR
+ static const size_t map[2][41] =
+ {
+ // DATA
+ // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
+ {
+ 0, 1, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ // 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 3
+ },
+
+ // ADR
+ // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
+ {
+ 0, 1, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ // 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3
+ }
+ };
+
+ fapi2::Assert((i_type == TAG_ADR) || (i_type == TAG_DATA));
+ fapi2::Assert(i_tag <= TAG_40OHM);
+ return map[i_type][i_tag];
+}
+
+
+typedef std::pair<tags_t, uint64_t> slew_rate_t;
+
+// Some types to help us keep track of the slew information
+///< slew(3)3V/ns=0, 4V/ns=1, 5V/ns=2, 6V/ns=3
+typedef std::vector< slew_rate_t > slew_rates_t;
+
+///< 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
+typedef std::vector< std::pair<tags_t, slew_rates_t> > slew_per_imp_t;
+
+///< speed(4)1066=0, 1333=1, 1600=2, 1866=3
+typedef std::vector< std::pair<tags_t, slew_per_imp_t> > slew_table_t;
+
+///
+/// @brief Run the sle calibration engine
+/// @param[in] i_target, the MCBIST
+/// @return FAPI2_RC_SUCCESS iff OK
+///
+fapi2::ReturnCode slew_cal(const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target);
+
+///
+/// @brief Process FFDC for slew calibration
+/// @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[in] the calibration status
+/// @param[in] the register value
+/// @return A fapi2::ReturnCode, appropriate for the calibration status
+///
+fapi2::ReturnCode slew_cal_status(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ std::vector<tags_t>& i_where_am_i,
+ const uint64_t l_slew_rate,
+ const uint64_t i_status,
+ const fapi2::buffer<uint64_t>& i_reg);
+}
+#endif
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/termination/slew_cal_status.C b/src/import/chips/p9/procedures/hwp/memory/lib/termination/slew_cal_status.C
new file mode 100644
index 000000000..4f62b626d
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/termination/slew_cal_status.C
@@ -0,0 +1,110 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/termination/slew_cal_status.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_status.C
+/// @brief Process the status from slew calibration. This is it's own function
+/// and file as it gets messey considering there are FFDC object per port ...
+///
+// *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_SYSTEM;
+
+using fapi2::TARGET_STATE_FUNCTIONAL;
+
+using fapi2::FAPI2_RC_SUCCESS;
+
+namespace mss
+{
+
+///
+/// @brief Process FFDC for slew calibration
+/// @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[in] the calibration status
+/// @param[in] the register value
+/// @return A fapi2::ReturnCode, appropriate for the calibration status
+///
+fapi2::ReturnCode slew_cal_status(const fapi2::Target<TARGET_TYPE_MCA>& i_target,
+ std::vector<tags_t>& i_where_am_i,
+ const uint64_t l_slew_rate,
+ const uint64_t i_status,
+ const fapi2::buffer<uint64_t>& i_reg)
+{
+ // Some short-hand for this subroutine
+ 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];
+
+ // Write up the message/error string once.
+ FAPI_INF("Slew calibration: %s slew %s, %lumhz %luohm %luV/ns: %d",
+ mss::c_str(i_target), l_type, l_speed, l_ohm, l_vns, l_slew_rate);
+
+ switch (i_status)
+ {
+ case SLEW_CAL_SUCCESS:
+ FAPI_DBG("Slew calibration success");
+ break;
+
+ case SLEW_CAL_WARNING:
+ FAPI_ERR("Slew calibration warning");
+ break;
+
+ case SLEW_CAL_NOT_DONE:
+ FAPI_ASSERT(false, fapi2::MSS_SLEW_CAL_TIMEOUT()
+ .set_PORT(mss::pos(i_target))
+ .set_DATA_ADR(i_where_am_i[0])
+ .set_IMP(l_ohm)
+ .set_SLEW(l_slew_rate)
+ .set_STAT_REG(i_reg)
+ .set_TARGET_IN_ERROR(i_target),
+ "Slew calibration timeout");
+ break;
+
+ case SLEW_CAL_ERRORS:
+ FAPI_ASSERT(false, fapi2::MSS_SLEW_CAL_ERROR()
+ .set_PORT(mss::pos(i_target))
+ .set_DATA_ADR(i_where_am_i[0])
+ .set_IMP(l_ohm)
+ .set_SLEW(l_slew_rate)
+ .set_STAT_REG(i_reg)
+ .set_TARGET_IN_ERROR(i_target),
+ "Slew calibration error");
+ break;
+ };
+
+ return fapi2::FAPI2_RC_SUCCESS;
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+}
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/utils/bit_count.H b/src/import/chips/p9/procedures/hwp/memory/lib/utils/bit_count.H
new file mode 100644
index 000000000..6292100d0
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/utils/bit_count.H
@@ -0,0 +1,83 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/utils/bit_count.H $ */
+/* */
+/* 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 bit_count.H
+/// @brief count bits
+///
+// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
+// *HWP HWP Backup: Craig Hamilton <cchamilt@us.ibm.com>
+// *HWP Team: Memory
+// *HWP Level: 2
+// *HWP Consumed by: HB:FSP
+
+#ifndef _MSS_BIT_COUNT_H_
+#define _MSS_BIT_COUNT_H_
+
+#include <fapi2.H>
+
+namespace mss
+{
+
+///
+/// @brief Count the bits in a T which are set (1)
+/// @tparam T, an integral type. e.g., uint64_t, uint8_t
+/// @param[in] the value to check, count
+/// @return uint64_t the number of bits set in the input
+///
+template< typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
+inline uint64_t bit_count(const T& i_value)
+{
+ if (i_value == 0)
+ {
+ return 0;
+ }
+ else
+ {
+ return bit_count(i_value >> 1) + (i_value & 0x01);
+ }
+}
+
+///
+/// @brief Return the bit position of the first bit set, from the left
+/// @tparam T, an integral type. e.g., uint64_t, uint8_t
+/// @param[in] the value to check
+/// @return uint64_t the bit position of the first set bit
+/// @bote assumes you checked to make sure there were bits set because it will return 0
+///
+template< typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
+inline uint64_t first_bit_set(const T& i_value, const uint64_t i_pos = 0)
+{
+ if (i_value == 0)
+ {
+ return 0;
+ }
+
+ if (fapi2::buffer<T>(i_value).template getBit<0>())
+ {
+ return i_pos;
+ }
+ else
+ {
+ return first_bit_set(i_value << 1, i_pos + 1);
+ }
+}
+
+}
+#endif
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/utils/c_str.C b/src/import/chips/p9/procedures/hwp/memory/lib/utils/c_str.C
new file mode 100644
index 000000000..657481c74
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/utils/c_str.C
@@ -0,0 +1,122 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/utils/c_str.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 c_str.C
+/// @brief Storage for the C-string name of a thing
+///
+// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
+// *HWP HWP Backup: Craig Hamilton <cchamilt@us.ibm.com>
+// *HWP Team: Memory
+// *HWP Level: 2
+// *HWP Consumed by: HB:FSP
+
+#include <mss_attribute_accessors.H>
+#include <fapi2.H>
+#include "c_str.H"
+
+using fapi2::TARGET_TYPE_MCBIST;
+using fapi2::TARGET_TYPE_MCA;
+using fapi2::TARGET_TYPE_MCS;
+using fapi2::TARGET_TYPE_DIMM;
+
+using fapi2::FAPI2_RC_SUCCESS;
+
+namespace mss
+{
+
+// Thread local storage for the string we're going to create.
+thread_local char c_str_storage[fapi2::MAX_ECMD_STRING_LEN];
+
+template< fapi2::TargetType T >
+char const* make_c_str_helper( char const* s, const fapi2::Target<T>& i_target);
+
+template<>
+char const* c_str<DEFAULT_KIND, TARGET_TYPE_DIMM>( const fapi2::Target<TARGET_TYPE_DIMM>& i_target )
+{
+ return make_c_str_helper(" unknown dimm", i_target);
+}
+
+template<>
+char const* c_str<KIND_RDIMM_DDR4, TARGET_TYPE_DIMM>( const fapi2::Target<TARGET_TYPE_DIMM>& i_target )
+{
+ return make_c_str_helper(" rdimm (ddr4)", i_target);
+}
+
+template<>
+char const* c_str<KIND_RDIMM_EMPTY, TARGET_TYPE_DIMM>( const fapi2::Target<TARGET_TYPE_DIMM>& i_target )
+{
+ return make_c_str_helper(" rdimm (empty)", i_target);
+}
+
+template<>
+char const* c_str<KIND_LRDIMM_DDR4, TARGET_TYPE_DIMM>( const fapi2::Target<TARGET_TYPE_DIMM>& i_target )
+{
+ return make_c_str_helper(" lrdimm (ddr4)", i_target);
+}
+
+template<>
+char const* c_str<KIND_LRDIMM_EMPTY, TARGET_TYPE_DIMM>( const fapi2::Target<TARGET_TYPE_DIMM>& i_target )
+{
+ return make_c_str_helper(" lrdimm (empty)", i_target);
+}
+
+template<>
+char const* c_str<FORCE_DISPATCH, TARGET_TYPE_DIMM>( const fapi2::Target<TARGET_TYPE_DIMM>& i_target )
+{
+ uint8_t l_type = 0;
+ uint8_t l_gen = 0;
+
+ uint8_t l_value[2][2];
+ auto l_mca = i_target.getParent<TARGET_TYPE_MCA>();
+ auto l_mcs = l_mca.getParent<TARGET_TYPE_MCS>();
+
+ // Had to unroll FAPI_TRY so that fapi2::current_err doesn't get overwritten, causes errors
+ // when calling c_str inside of a function that returns fapi2::ReturnCode
+ if (FAPI_ATTR_GET(fapi2::ATTR_EFF_DIMM_TYPE, l_mcs, l_value) != FAPI2_RC_SUCCESS)
+ {
+ goto fapi_try_exit;
+ }
+
+ l_type = l_value[mss::index(l_mca)][mss::index(i_target)];
+
+ // Had to unroll FAPI_TRY so that fapi2::current_err doesn't get overwritten, causes errors
+ // when calling c_str inside of a function that returns fapi2::ReturnCode
+ if (FAPI_ATTR_GET(fapi2::ATTR_EFF_DRAM_GEN, l_mcs, l_value) != FAPI2_RC_SUCCESS)
+ {
+ goto fapi_try_exit;
+ }
+
+ l_gen = l_value[mss::index(l_mca)][mss::index(i_target)];
+
+ return c_str_dispatch<FORCE_DISPATCH, TARGET_TYPE_DIMM>(dimm_kind( l_type, l_gen ), i_target);
+
+fapi_try_exit:
+ // Probably the best we're going to do ...
+ return "couldn't get dimm type, dram gen";
+}
+
+template< fapi2::TargetType T >
+char const* make_c_str_helper( char const* s, const fapi2::Target<T>& i_target)
+{
+ fapi2::toString( i_target, c_str_storage, fapi2::MAX_ECMD_STRING_LEN );
+ return strncat( c_str_storage, s, fapi2::MAX_ECMD_STRING_LEN - strlen(c_str_storage) );
+}
+
+}
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/utils/c_str.H b/src/import/chips/p9/procedures/hwp/memory/lib/utils/c_str.H
new file mode 100644
index 000000000..7a8855b04
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/utils/c_str.H
@@ -0,0 +1,154 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/utils/c_str.H $ */
+/* */
+/* 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 c_str.H
+/// @brief Function to return the C-string name of a thing
+///
+// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
+// *HWP HWP Backup: Craig Hamilton <cchamilt@us.ibm.com>
+// *HWP Team: Memory
+// *HWP Level: 2
+// *HWP Consumed by: HB:FSP
+
+#ifndef _MSS_C_STR_H_
+#define _MSS_C_STR_H_
+
+#include <fapi2.H>
+
+///
+/// @remark To create an overloaded function a few things need to be defined.
+/// Sorry.
+///
+
+/// -# Document the function and define its signature *as a comment* Why as a comment?
+/// We're going to use SFINAE to expose this signature if there has been no overload
+/// defined for any of the template arguments. So, we don't know if this signature will
+/// be the correct one until we instantiate the template. So this is here simply for
+/// documentation. We do need a simple way for our callers to know how to call this
+/// non-traditionally defined function - so we do that here.
+
+///
+/// @brief return the c-string name of the input, including any extension to the name defined by its type
+/// @tparam T, the fapi2::TargetType of the input - derived.
+/// @param[in] i_target, the fapi2::Target of interest
+/// @return char const* a thread-safe c-string containing the element's name
+/// @note to call: char* s = c_str(i_target);
+///
+//template< fapi2::TargetType T>
+//const char* c_str( const fapi2::Target<T>& i_target);
+
+///
+/// -# Include the header which defines all the macros which will
+/// expand into our overload templates. Note that the pre-processor
+/// is single-pass so all of the pre-requisites for the larger macros
+/// need to be defined prior to including them.
+///
+#include "../shared/mss_kind.H"
+
+namespace mss
+{
+
+// Thread local storage for the string we're going to create.
+extern thread_local char c_str_storage[fapi2::MAX_ECMD_STRING_LEN];
+
+/// -# Register the API.
+/// -# Define the template parameters for the overloaded function
+/// @note the first argument is the api name, and the rest are the api's template parameters.
+/// @note this creates __api_name##_overload - so in this case it defines
+/// c_str_overload which is used below to mame decisions.
+REGISTER_API( c_str, fapi2::TargetType T );
+
+/// -# Register the specific overloads. The first parameter is the name
+/// of the api, the second is the kind of the element which is being
+/// overloaded - an RDIMM, an LRDIMM, etc. The remaining parameters
+/// indicate the specialization of the api itself.
+/// @note You need to define the "DEFAULT_KIND" here as an overload. This
+/// allows the mechanism to find the "base" implementation for things which
+/// have no specific overload.
+REGISTER_OVERLOAD( c_str, DEFAULT_KIND, fapi2::TARGET_TYPE_DIMM );
+REGISTER_OVERLOAD( c_str, KIND_RDIMM_DDR4, fapi2::TARGET_TYPE_DIMM );
+REGISTER_OVERLOAD( c_str, KIND_RDIMM_EMPTY, fapi2::TARGET_TYPE_DIMM );
+REGISTER_OVERLOAD( c_str, KIND_LRDIMM_DDR4, fapi2::TARGET_TYPE_DIMM );
+REGISTER_OVERLOAD( c_str, KIND_LRDIMM_EMPTY, fapi2::TARGET_TYPE_DIMM );
+
+///
+/// -# Define the default case for overloaded calls. enable_if states that
+/// if there is a DEFAULT_KIND overload for this TargetType, then this
+/// entry point will be defined. Note the general case below is enabled if
+/// there is no overload defined for this TargetType
+///
+
+template< mss::kind_t K = FORCE_DISPATCH, fapi2::TargetType T >
+typename std::enable_if< c_str_overload<DEFAULT_KIND, T>::available, const char*>::type
+c_str( const fapi2::template Target<T>& i_target );
+
+///
+/// -# Register the handler for the API, not the overloads. This is the
+/// code which implements the general case of the template. Because it
+/// is not a full specialization of the template, it must be defiend in
+/// this header.
+///
+template< fapi2::TargetType T >
+typename std::enable_if < ! c_str_overload<DEFAULT_KIND, T>::available, const char* >::type
+c_str( const fapi2::template Target<T>& i_target )
+{
+ fapi2::toString( i_target, c_str_storage, fapi2::MAX_ECMD_STRING_LEN );
+ return c_str_storage;
+}
+
+//
+// We know we registered overloads for c_str, so we need the entry point to
+// the dispatcher. Add a set of these for all TargetTypes which get overloads
+// for this API
+//
+template<>
+char const* c_str<FORCE_DISPATCH, fapi2::TARGET_TYPE_DIMM>( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target );
+
+template<>
+char const* c_str<DEFAULT_KIND, fapi2::TARGET_TYPE_DIMM>( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target );
+
+//
+// Boilerplate dispatcher
+//
+template< kind_t K, fapi2::TargetType T, bool B = c_str_overload<K, T>::available >
+inline char const * c_str_dispatch( const kind_t& i_kind, const fapi2::Target<T>& i_target )
+{
+ // We dispatch to another kind if:
+ // We don't have an overload defined (B == false)
+ // Or, if we do have an overload (B == true) and this is not out kind.
+ if ((B == false) || ((B == true) && (K != i_kind)))
+ {
+ return c_str_dispatch < (kind_t)(K - 1), T > (i_kind, i_target);
+ }
+
+ // Otherwise, we call the overload.
+ return c_str<K, T>(i_target);
+}
+
+// DEFAULT_KIND is 0 so this is the end of the recursion
+template<>
+inline char const* c_str_dispatch<DEFAULT_KIND, fapi2::TARGET_TYPE_DIMM>(const kind_t&,
+ const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target)
+{
+ return c_str<DEFAULT_KIND, fapi2::TARGET_TYPE_DIMM>(i_target);
+}
+
+}
+#endif
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/utils/checker.H b/src/import/chips/p9/procedures/hwp/memory/lib/utils/checker.H
new file mode 100644
index 000000000..ff2a493f3
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/utils/checker.H
@@ -0,0 +1,298 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/utils/checker.H $ */
+/* */
+/* 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 checker.H
+/// @brief Contains common functions that perform checks
+///
+// *HWP HWP Owner: Andre Marin <aamarin@us.ibm.com>
+// *HWP FW Owner: Brian Silver <bsilver@us.ibm.com>
+// *HWP Team: Memory
+// *HWP Level: 2
+// *HWP Consumed by: FSP:HB
+
+#ifndef _CHECKER_H_
+#define _CHECKER_H_
+
+#include <fapi2.H>
+#include "../shared/mss_const.H"
+#include <mss_attribute_accessors.H>
+
+namespace mss
+{
+namespace check
+{
+///
+/// @brief Checks homogenous DDR4 dimm configuration (e.g. DDR4)
+/// @param[in] const fapi2::Target<fapi2::TARGET_TYPE_MCS>& i_target_mcs
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+inline fapi2::ReturnCode dram_type(const fapi2::Target<fapi2::TARGET_TYPE_MCS>& i_target_mcs)
+{
+ uint8_t l_dram_gen[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Retrieve DDR4 dimm attributes
+ FAPI_TRY(spd_dram_device_type(i_target_mcs, &(l_dram_gen[0][0])));
+
+ // Make sure all DRAMs are DDR4 or throw an error
+ // Iterate through MCA's/ports
+ for (auto p : i_target_mcs.getChildren<fapi2::TARGET_TYPE_MCA>())
+ {
+ auto port_num = mss::index(p);
+
+ // Iterate through DIMM targets
+ for (auto d : p.getChildren<fapi2::TARGET_TYPE_DIMM>())
+ {
+ auto dimm_num = mss::index(d);
+
+ FAPI_INF("%s DRAM device type is %llX",
+ mss::c_str(d),
+ l_dram_gen[port_num][dimm_num]);
+
+ // Nimbus supports only DDR4
+ FAPI_ASSERT(l_dram_gen[port_num][dimm_num] == fapi2::ENUM_ATTR_SPD_DRAM_DEVICE_TYPE_DDR4,
+ fapi2::MSS_UNSUPPORTED_DEV_TYPE().
+ set_DEV_TYPE(l_dram_gen[port_num][dimm_num]),
+ "%s Incorrect DRAM device generation, DRAM generation is %llx",
+ mss::c_str(d),
+ l_dram_gen[port_num][dimm_num]);
+ }
+
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}// dram_type
+
+
+///
+/// @brief Check if there is DIMM mixing (and deconfigures unsupported mixing <shrug> ?? - AAM)
+/// @param[in] const fapi2::Target<fapi2::TARGET_TYPE_MCS>& i_target_mcs
+/// @param[out] uint64_t& o_module_type (returns something ?? - AAM )
+/// @return FAPI2_RC_SUCCESS iff ok
+/// @note Functionality currently unknown
+///
+inline fapi2::ReturnCode dimm_mixing(const fapi2::Target<fapi2::TARGET_TYPE_MCS>& i_target_mcs,
+ uint64_t& o_module_type)
+{
+ //TODO
+ //Need to complete - AAM
+
+ // Anuwat pushed Warren to say IBM systems will not support DIMM mixing
+ // Now DIMM deconfig rules? - AAM
+#if 0
+
+ std::vector<uint8_t> l_module_type_vector;
+ uint8_t l_module_type[mss::PORTS_PER_MCS][mss::MAX_DIMM_PER_PORT] = {0};
+ uint8_t lr_dimm_count;
+ uint8_t r_dimm_count;
+ uint8_t u_dimm_count;
+
+ FAPI_TRY(mss::spd_module_type(i_target_mcs, &l_module_type[0][0]),
+ "Unable to read the SPD module type.");
+
+ for(size_t l_port = 0; l_port < mss::PORTS_PER_MCS; l_port++)
+ {
+ for (size_t l_dimm = 0; l_dimm < mss::MAX_DIMM_PER_PORT; l_dimm++)
+ {
+ l_module_type_vector.push_back(l_module_type[l_port][l_dimm]);
+ }
+ }
+
+ lr_dimm_count = std::count(l_module_type_vector.begin(),
+ l_module_type_vector.end(),
+ fapi2::ENUM_ATTR_SPD_MODULE_TYPE_LRDIMM);
+ r_dimm_count = std::count(l_module_type_vector.begin(),
+ l_module_type_vector.end(),
+ fapi2::ENUM_ATTR_SPD_MODULE_TYPE_RDIMM);
+ u_dimm_count = std::count(l_module_type_vector.begin(),
+ l_module_type_vector.end(),
+ fapi2::ENUM_ATTR_SPD_MODULE_TYPE_UDIMM); // Not supported? - AAM
+
+ count(l_module_type_vector.begin(), l_module_type_vector.end(), fapi2::SO_DIMM); // Not supported? - AAM
+
+ uint8_t temp = std::max({lr_dimm_count, r_dimm_count, u_dimm_count});
+
+ return (temp == r_dimm_count) ? fapi2::RDIMM : fapi2::LRDIMM
+
+#endif
+
+ return fapi2::FAPI2_RC_SUCCESS;
+}// dimm_mixing
+
+///
+/// @brief Checks what type of system is configured (i.e., single drop, dual drop)
+/// @param[in] Unknown
+/// @param[out] Unknown
+/// @return FAPI2_RC_SUCCESS iff ok
+/// @note Functionality currently unknown
+///
+inline fapi2::ReturnCode system_drop_type(void)
+{
+ //TODO
+ //Update for P9, how will we check if a system is single/dual drop?? - AAM
+
+#if 0
+ //Determining the cnfg for imposing any cnfg speed limitations
+ if ( (cur_dimm_spd_valid_u8array[0][0][0] == MSS_FREQ_VALID)
+ && (cur_dimm_spd_valid_u8array[0][0][1] == MSS_FREQ_EMPTY) )
+ {
+ plug_config = MSS_FREQ_SINGLE_DROP;
+ num_ranks_total = num_ranks[0][0][0] + 1;
+ }
+ else if (((cur_dimm_spd_valid_u8array[1][0][0] == MSS_FREQ_VALID)
+ && (cur_dimm_spd_valid_u8array[1][0][1] == MSS_FREQ_EMPTY)) ||
+ ((cur_dimm_spd_valid_u8array[1][0][1] == MSS_FREQ_VALID) && (cur_dimm_spd_valid_u8array[1][0][0] == MSS_FREQ_EMPTY)))
+ {
+ plug_config = MSS_FREQ_SINGLE_DROP;
+ num_ranks_total = num_ranks[1][0][0] + 1;
+ }
+ else if ((cur_dimm_spd_valid_u8array[0][0][0] == MSS_FREQ_VALID)
+ && (cur_dimm_spd_valid_u8array[0][0][1] == MSS_FREQ_VALID))
+ {
+ plug_config = MSS_FREQ_DUAL_DROP;
+ num_ranks_total = (num_ranks[0][0][0] + 1) + (num_ranks[0][0][1] + 1);
+ }
+ else if ((cur_dimm_spd_valid_u8array[1][0][0] == MSS_FREQ_VALID)
+ && (cur_dimm_spd_valid_u8array[1][0][1] == MSS_FREQ_VALID))
+ {
+ plug_config = MSS_FREQ_DUAL_DROP;
+ num_ranks_total = (num_ranks[1][0][0] + 1) + (num_ranks[1][0][1] + 1);
+ }
+ else
+ {
+ plug_config = MSS_FREQ_EMPTY;
+ }
+
+
+ FAPI_INF( "PLUG CONFIG(from SPD): %d, Type of Dimm(from SPD): 0x%02X, Num Ranks(from SPD): %d",
+ plug_config, module_type, num_ranks_total);
+fapi_try_exit:
+ return fapi2::current_err;
+
+#endif
+
+ return fapi2::FAPI2_RC_SUCCESS;
+}// system_drop_type
+
+///
+/// @brief Checks nominal voltage is correct for all DIMMs
+/// @param[in] const fapi2::Target<fapi2::TARGET_TYPE_MCS>& i_target_mcs,
+/// fapi2::TargetState dimm_state
+/// @return ReturnCode
+///
+inline fapi2::ReturnCode module_nominal_voltage(const fapi2::Target<fapi2::TARGET_TYPE_MCS>& i_target_mcs,
+ fapi2::TargetState dimm_state)
+{
+
+ uint64_t l_module_nom_voltage[mss::PORTS_PER_MCS][mss::MAX_DIMM_PER_PORT] = {0};
+
+ FAPI_TRY(mss::spd_module_nominal_voltage(i_target_mcs, &l_module_nom_voltage[0][0]));
+
+ for (auto p : i_target_mcs.getChildren<fapi2::TARGET_TYPE_MCA>())
+ {
+ auto port_num = mss::index(p);
+
+ // Iterate through DIMM targets
+ for (auto d : p.getChildren<fapi2::TARGET_TYPE_DIMM>(dimm_state))
+ {
+ auto dimm_num = mss::index(d);
+
+ FAPI_INF("%s DRAM nominal voltage (in milliseconds) is %d",
+ mss::c_str(d),
+ l_module_nom_voltage[port_num][dimm_num]);
+
+ // All DIMMs have to be operable at 1.2 V, else don't IPL (according to Warren)
+ FAPI_ASSERT( l_module_nom_voltage[port_num][dimm_num] == fapi2::ENUM_ATTR_SPD_MODULE_NOMINAL_VOLTAGE_OPERABLE,
+ fapi2::MSS_VOLT_DDR_TYPE_REQUIRED_VOLTAGE().
+ set_DIMM_VOLTAGE(l_module_nom_voltage[port_num][dimm_num]),
+ "%s.Failed conditional, data returned:o %d.",
+ mss::c_str(d),
+ l_module_nom_voltage[port_num][dimm_num] );
+ }
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}// module_nominal_voltage
+
+namespace spd
+{
+///
+/// @brief Checks conditional passes and implements traces & exits if it fails
+/// @tparam T spd_data, of any size
+/// @param[in] const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+/// bool conditional
+/// size_t spd_byte_inded
+/// char* err_str
+/// @return ReturnCode
+///
+template< typename T >
+inline fapi2::ReturnCode valid_value_fail(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ bool conditional,
+ size_t spd_byte_index,
+ T spd_data,
+ const char* err_str)
+{
+ FAPI_ASSERT(conditional,
+ fapi2::MSS_VALID_VALUE().
+ set_VALUE(spd_data).
+ set_BYTE(spd_byte_index),
+ "%s %s Byte %d, Data returned: %d.",
+ c_str(i_target_dimm),
+ err_str,
+ spd_byte_index,
+ spd_data);
+
+fapi_try_exit:
+ return fapi2::current_err;
+
+} // invalid_value_fail()
+
+///
+/// @brief Checks conditional passes and implements traces if it fails
+/// @tparam T spd_data, of any size
+/// @param[in] const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+/// bool conditional
+/// size_t spd_byte_inded
+/// char* err_str
+/// @return void
+///
+template< typename T >
+inline void valid_value_warn(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ bool conditional,
+ size_t spd_byte_index,
+ T spd_data,
+ const char* err_str)
+{
+ if(!conditional)
+ {
+ FAPI_IMP("%s. %s. Byte %d, Data returned: %d.",
+ c_str(i_target_dimm),
+ err_str,
+ spd_byte_index,
+ spd_data );
+ }
+}// valid_value_warn
+
+}// spd
+}// check
+}// mss
+
+#endif
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/utils/conversions.H b/src/import/chips/p9/procedures/hwp/memory/lib/utils/conversions.H
new file mode 100644
index 000000000..3989c172b
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/utils/conversions.H
@@ -0,0 +1,263 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/utils/conversions.H $ */
+/* */
+/* 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 conversions.H
+/// @brief Functions to convert units
+///
+// *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: HB:FSP
+
+#ifndef _MSS_CONVERSIONS_H_
+#define _MSS_CONVERSIONS_H_
+
+#include <fapi2.H>
+#include <mss_attribute_accessors.H>
+#include "../shared/mss_const.H"
+#include "find.H"
+
+// Mutiplication factor to go from clocks to simcycles.
+// Is this just 2400 speed or does this hold for all? BRS
+static const uint64_t SIM_CYCLES_PER_CYCLE = 8;
+
+namespace mss
+{
+
+///
+/// @brief Return the number of picoseconds taken by a certain mhz
+/// @param[in] i_mhz - the mhz of interest
+/// @return the picoseconds
+///
+inline uint64_t mhz_to_ps(const uint64_t i_mhz)
+{
+ // Just used for indexs into the array below
+ enum freqs { FREQ_2400 = 0, };
+
+ // ATTR_MSS_FREQ is in mHZ, and we know us per clock is 1/(freq/2)
+ // We don't have many frequencies, so lets just make a little table.
+ static const uint64_t FREQ_TO_PS[MAX_SUPPORTED_FREQUENCIES] =
+ {
+ // 2400 is 833 picoseconds per clock
+ 833
+ };
+
+ switch(i_mhz)
+ {
+ case 2400:
+ return FREQ_TO_PS[FREQ_2400];
+
+ default:
+ FAPI_ERR("unsupported frequency %d", i_mhz);
+ fapi2::Assert(false);
+
+ // Keeps compiler happy
+ return 0;
+ }
+}
+
+///
+/// @brief Translate from cycles to sim cycles
+/// @param[in] i_cycles, the cycles to translate
+/// @return uint64_t, the number of sim cycles.
+///
+inline uint64_t cycles_to_simcycles( const uint64_t i_cycles )
+{
+ // Is this always the case or do we need the freq to really figure this out?
+ return i_cycles * SIM_CYCLES_PER_CYCLE;
+}
+
+///
+/// @brief Return the number of cycles contained in a count of picoseconds
+/// @param[in] i_target, target for the frequency attribute
+/// @param[in] i_ps, the number of picoseconds to convert
+/// @return uint64_t, the number of cycles
+///
+template< fapi2::TargetType T >
+inline uint64_t ps_to_cycles(const fapi2::Target<T>& i_target, const uint64_t i_ps)
+{
+ // The frequency in mHZ
+ uint64_t l_freq;
+ uint64_t l_divisor = 0;
+ uint64_t l_quotient = 0;
+ uint64_t l_remainder = 0;
+
+ FAPI_TRY( mss::freq( find_target<fapi2::TARGET_TYPE_MCBIST>(i_target), l_freq) );
+
+ // Hoping the compiler figures out how to do these together.
+ l_divisor = mhz_to_ps(l_freq);
+ l_quotient = i_ps / l_divisor;
+ l_remainder = i_ps % l_divisor;
+
+ // Make sure we add a cycle if there wasn't an even number of cycles in the input
+ FAPI_DBG("converting %dps to %d cycles", i_ps, l_quotient + (l_remainder == 0 ? 0 : 1));
+
+ return l_quotient + (l_remainder == 0 ? 0 : 1);
+
+fapi_try_exit:
+
+ // We simply can't work if we can't get the frequency - so this should be ok
+ FAPI_ERR("Can't get MSS_FREQ - stopping");
+ fapi2::Assert(false);
+
+ // Keeps compiler happy
+ return 0;
+}
+
+///
+/// @brief Return the number of ps contained in a count of cycles
+/// @param[in] i_target, target for the frequency attribute
+/// @param[in] i_ps, the number of cycles to convert
+/// @return uint64_t, the number of picoseconds
+///
+template< fapi2::TargetType T >
+inline uint64_t cycles_to_ps(const fapi2::Target<T>& i_target, const uint64_t i_cycles)
+{
+ // The frequency in mHZ
+ uint64_t l_freq;
+
+ FAPI_TRY( mss::freq( find_target<fapi2::TARGET_TYPE_MCBIST>(i_target), l_freq) );
+
+ FAPI_DBG("converting %d cycles to %dps", i_cycles, i_cycles * mhz_to_ps(l_freq));
+ return i_cycles * mhz_to_ps(l_freq);
+
+fapi_try_exit:
+
+ // We simply can't work if we can't get the frequency - so this should be ok
+ FAPI_ERR("Can't get MSS_FREQ - stopping");
+ fapi2::Assert(false);
+
+ // Keeps compiler happy
+ return 0;
+}
+
+///
+/// @brief Return the number of cycles contained in a count of microseconds
+/// @param[in] i_target, target for the frequency attribute
+/// @param[in] i_ps, the number of microseconds to convert
+/// @return uint64_t, the number of cycles
+///
+template< fapi2::TargetType T >
+inline uint64_t us_to_cycles(const fapi2::Target<T>& i_target, const uint64_t i_us)
+{
+ return ps_to_cycles(i_target, i_us * CONVERT_PS_IN_A_US);
+}
+
+///
+/// @brief Return the number of cycles contained in a count of nanoseconds
+/// @param[in] i_target, target for the frequency attribute
+/// @param[in] i_ps, the number of nanoseconds to convert
+/// @return uint64_t, the number of cycles
+///
+template< fapi2::TargetType T >
+inline uint64_t ns_to_cycles(const fapi2::Target<T>& i_target, const uint64_t i_ns)
+{
+ return ps_to_cycles(i_target, i_ns * CONVERT_PS_IN_A_NS);
+}
+
+///
+/// @brief Return the number of microseconds contained in a count of cycles
+/// @tparam T, the target type
+/// @tparam D, the time conversion (NS_IN_PS, etc)
+/// @param[in] i_target, target for the frequency attribute
+/// @param[in] i_ps, the number of cycles to convert
+/// @return uint64_t, the number of microseconds
+///
+template< fapi2::TargetType T, uint64_t D >
+inline uint64_t cycles_to_time(const fapi2::Target<T>& i_target, const uint64_t i_cycles)
+{
+ // Hoping the compiler figures out how to do these together.
+ uint64_t l_dividend = cycles_to_ps(i_target, i_cycles);
+ uint64_t l_quotient = l_dividend / D;
+ uint64_t l_remainder = l_dividend % D;
+
+ // Make sure we add time if there wasn't an even number of cycles
+ return l_quotient + (l_remainder == 0 ? 0 : 1);
+}
+
+///
+/// @brief Return the number of nanoseconds contained in a count of cycles
+/// @param[in] i_target, target for the frequency attribute
+/// @param[in] i_cycles, the number of cycles to convert
+/// @return uint64_t, the number of nanoseconds
+///
+template< fapi2::TargetType T >
+inline uint64_t cycles_to_ns(const fapi2::Target<T>& i_target, const uint64_t i_cycles)
+{
+ uint64_t l_ns = cycles_to_time<T, CONVERT_PS_IN_A_NS>(i_target, i_cycles);
+ FAPI_DBG("converting %d cycles to %dns", i_cycles, l_ns);
+
+ return l_ns;
+}
+
+///
+/// @brief Return the number of microseconds contained in a count of cycles
+/// @param[in] i_target, target for the frequency attribute
+/// @param[in] i_cycles, the number of cycles to convert
+/// @return uint64_t, the number of microseconds
+///
+template< fapi2::TargetType T >
+inline uint64_t cycles_to_us(const fapi2::Target<T>& i_target, const uint64_t i_cycles)
+{
+ uint64_t l_us = cycles_to_time<T, CONVERT_PS_IN_A_US>(i_target, i_cycles);
+ FAPI_DBG("converting %d cycles to %dus", i_cycles, l_us);
+
+ return l_us;
+}
+
+///
+/// @brief Calculate TWLO_TWLOE - this needs to go in to eff_config and be an attribute
+/// @tparam fapi2::TargetType T of the target used to calculate cycles from ns
+/// @param[in] i_target, the target used to get DIMM clocks
+/// @return uint64_t, TWLO_TWLOE in cycles
+///
+template< fapi2::TargetType T >
+inline uint64_t twlo_twloe(const fapi2::Target<T>& i_target)
+{
+ return 12 + mss::ns_to_cycles(i_target, tWLO - tWLOE);
+}
+
+///
+/// @brief Convert nanoseconds to picoseconds
+/// @param[in] int64_t i_time_in_ns, time in nanoseconds
+/// @return int64_t, time in picoseconds
+///
+inline int64_t ns_to_ps(const int64_t& i_time_in_ns)
+{
+ return i_time_in_ns * CONVERT_PS_IN_A_NS;
+}
+
+///
+/// @brief Convert nanoseconds to picoseconds
+/// @param[in] int64_t i_time_in_ps, time in picoseconds
+/// @return int64_t, time in nanoseconds
+///
+inline int64_t ps_to_ns(const int64_t& i_time_in_ps)
+{
+ int64_t remainder = i_time_in_ps % CONVERT_PS_IN_A_NS;
+ int64_t l_time_in_ns = i_time_in_ps / CONVERT_PS_IN_A_NS;
+
+ // Round up if remainder isn't even
+ return l_time_in_ns + ( remainder == 0 ? 0 : 1 );
+}
+
+};// mss namespace
+#endif
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/utils/fake_spd.C b/src/import/chips/p9/procedures/hwp/memory/lib/utils/fake_spd.C
new file mode 100644
index 000000000..1fd1d1401
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/utils/fake_spd.C
@@ -0,0 +1,95 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/utils/fake_spd.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 fake_spd.H
+/// @brief A tool to return fake (fixed) DIMM SPD for testing, development
+///
+// *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: HB:FSP
+
+#include "fake_spd.H"
+
+/// DIMM data was taken from /afs/awd.austin.ibm.com/projects/eclipz/lab/p8/gsiexe/
+/// 78P0AAM_DDR4_8G1RX8_mu/MICRON_SPD_8G_1Rx8_DDR4_2400_RDIMM.hex on 7/31/2015.
+
+static const uint8_t raw_spd[] =
+{
+ 0x23, 0x10, 0x0C, 0x01, 0x85, 0x21, 0x00, 0x08, 0x00, 0x60, 0x00, 0x03, 0x01, 0x0B, 0x80, 0x00,
+ 0x00, 0x00, 0x07, 0x0D, 0xF8, 0x7F, 0x00, 0x00, 0x6E, 0x6E, 0x6E, 0x11, 0x00, 0x6E, 0xF0, 0x0A,
+ 0x20, 0x08, 0x00, 0x05, 0x00, 0xA8, 0x1B, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x03, 0x15, 0x2C,
+ 0x24, 0x03, 0x15, 0x2C, 0x24, 0x03, 0x24, 0x03, 0x15, 0x2C, 0x24, 0x03, 0x15, 0x2C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9C, 0xB5, 0x00, 0x00, 0x00, 0x00, 0xE7, 0xD6, 0xCA, 0x91,
+ 0x11, 0x11, 0x23, 0x05, 0x00, 0x80, 0xB3, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x41, 0x53, 0x46, 0x31, 0x47, 0x37,
+ 0x32, 0x50, 0x5A, 0x2D, 0x32, 0x47, 0x33, 0x41, 0x31, 0x20, 0x20, 0x20, 0x20, 0x31, 0x80, 0x2C,
+ 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+///
+/// @brief Return a blob of SPD data from a DIMM
+/// @param[in] i_target, a DIMM target representing the DIMM in question
+/// @param[out] o_blob, the blob of data from the DIMM - raw
+/// @param[out] o_size, o_size, the size of the blob
+/// @return FAPI2_RC_SUCCESS if there's no problem
+/// @note passing nullptr for o_blob will return the size of the blob
+/// size_t s;
+/// FAPI_TRY(getSPD( dimm, nullptr, s ));
+/// char blob[s];
+/// FAPI_TRY(getSPD( dimm, blob, s ));
+/// blob now contains the SPD for the dimm.
+///
+fapi2::ReturnCode getSPD(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target, uint8_t* o_blob, size_t& o_size)
+{
+ o_size = sizeof( raw_spd );
+
+ if( o_blob != nullptr )
+ {
+ memcpy(o_blob, raw_spd, o_size);
+ }
+
+ return fapi2::FAPI2_RC_SUCCESS;
+}
+
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/utils/fake_spd.H b/src/import/chips/p9/procedures/hwp/memory/lib/utils/fake_spd.H
new file mode 100644
index 000000000..30161339e
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/utils/fake_spd.H
@@ -0,0 +1,51 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/utils/fake_spd.H $ */
+/* */
+/* 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 fake_spd.H
+/// @brief A tool to return fake (fixed) DIMM SPD for testing, development
+///
+// *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: HB:FSP
+
+#ifndef _MSS_FAKE_SPD_H_
+#define _MSS_FAKE_SPD_H_
+
+#include <fapi2.H>
+
+///
+/// @brief Return a blob of SPD data from a DIMM
+/// @param[in] i_target, a DIMM target representing the DIMM in question
+/// @param[out] o_blob, the blob of data from the DIMM - raw
+/// @param[out] o_size, o_size, the size of the blob
+/// @return FAPI2_RC_SUCCESS if there's no problem
+/// @note passing nullptr for o_blob will return the size of the blob
+/// size_t s;
+/// FAPI_TRY( getSPD(d->target(), nullptr, s) );
+/// {
+/// uint8_t blob[s];
+/// FAPI_TRY( getSPD(d->target(), blob, s) );
+/// }
+///
+fapi2::ReturnCode getSPD(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target, uint8_t* o_blob, size_t& s);
+
+#endif
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/utils/find.H b/src/import/chips/p9/procedures/hwp/memory/lib/utils/find.H
new file mode 100644
index 000000000..15c559d38
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/utils/find.H
@@ -0,0 +1,187 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/utils/find.H $ */
+/* */
+/* 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 find.H
+/// @brief Templates for finding things
+///
+// *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: HB:FSP
+
+#ifndef _MSS_FIND_H
+#define _MSS_FIND_H
+
+#include <fapi2.H>
+
+namespace mss
+{
+
+///
+/// @brief find a set of elements based on a fapi2 target
+/// @tparam M the target type to be returned
+/// @tparam T the fapi2 target type of the argument
+/// @param[in] the fapi2 target, T
+/// @return a vector of M targets.
+///
+template< fapi2::TargetType M, fapi2::TargetType T >
+inline std::vector< fapi2::Target<M> > find_targets( const fapi2::Target<T>& );
+
+///
+/// @brief find an element based on a fapi2 target
+/// @tparam M the target type to be returned
+/// @tparam T the fapi2 target type of the argument
+/// @param[in] the fapi2 target, T
+/// @return an M target.
+///
+template< fapi2::TargetType M, fapi2::TargetType T >
+inline fapi2::Target<M> find_target( const fapi2::Target<T>& );
+
+///
+/// @brief find the McBIST given a McBIST
+/// @param[in] the fapi2 target, mcBIST
+/// @return a McBIST target.
+///
+template<>
+inline fapi2::Target<fapi2::TARGET_TYPE_MCBIST> find_target( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_self)
+{
+ return i_self;
+}
+
+///
+/// @brief find the McBIST given a DIMM
+/// @param[in] the fapi2 target, DIMM
+/// @return a McBIST target.
+///
+template<>
+inline fapi2::Target<fapi2::TARGET_TYPE_MCBIST> find_target( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target)
+{
+ return i_target.getParent<fapi2::TARGET_TYPE_MCA>().getParent<fapi2::TARGET_TYPE_MCBIST>();
+}
+
+///
+/// @brief find the McBIST given a MCA
+/// @param[in] the fapi2 target, MCA
+/// @return a McBIST target.
+///
+template<>
+inline fapi2::Target<fapi2::TARGET_TYPE_MCBIST> find_target( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target)
+{
+ return i_target.getParent<fapi2::TARGET_TYPE_MCBIST>();
+}
+
+
+///
+/// @brief find all the dimm connected to an MCS
+/// @param[in] a fapi2::Target MCS
+/// @return a vector of fapi2::TARGET_TYPE_DIMM
+///
+template<>
+inline std::vector< fapi2::Target<fapi2::TARGET_TYPE_DIMM> > find_targets( const fapi2::Target<fapi2::TARGET_TYPE_MCS>&
+ i_target )
+{
+ std::vector< fapi2::Target<fapi2::TARGET_TYPE_DIMM> > l_dimms;
+
+ // At this time, fapi2 (cronus?) doesn't seem to recognize a DIMM is the child of an MCS.
+ for (auto p : i_target.getChildren<fapi2::TARGET_TYPE_MCA>())
+ {
+ auto l_these_dimms( p.getChildren<fapi2::TARGET_TYPE_DIMM>() );
+ l_dimms.insert(l_dimms.end(), l_these_dimms.begin(), l_these_dimms.end());
+ }
+
+ return l_dimms;
+}
+
+///
+/// @brief find all the dimm connected to an MCBIST
+/// @param[in] a fapi2::Target MCBIST
+/// @return a vector of fapi2::TARGET_TYPE_DIMM
+///
+template<>
+inline std::vector< fapi2::Target<fapi2::TARGET_TYPE_DIMM> > find_targets( const
+ fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target )
+{
+ std::vector< fapi2::Target<fapi2::TARGET_TYPE_DIMM> > l_dimms;
+
+ for (auto p : i_target.getChildren<fapi2::TARGET_TYPE_MCA>())
+ {
+ auto l_these_dimms( p.getChildren<fapi2::TARGET_TYPE_DIMM>() );
+ l_dimms.insert(l_dimms.end(), l_these_dimms.begin(), l_these_dimms.end());
+ }
+
+ return l_dimms;
+}
+
+///
+/// @brief find all the MCS connected to an MCBIST
+/// @param[in] a fapi2::Target MCBIST
+/// @return a vector of fapi2::TARGET_TYPE_MCS
+/// @note Cronus should support MCS children of an MCBIST - so this might be temporary
+///
+template<>
+inline std::vector< fapi2::Target<fapi2::TARGET_TYPE_MCS> > find_targets( const
+ fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target )
+{
+ std::vector< fapi2::Target<fapi2::TARGET_TYPE_MCS> > l_mcses;
+
+ // At this time, fapi2 (cronus?) doesn't seem to recognize a MCS is the child of an MCBIST
+ for (auto p : i_target.getChildren<fapi2::TARGET_TYPE_MCA>())
+ {
+ fapi2::Target<fapi2::TARGET_TYPE_MCS> l_mcs = p.getParent<fapi2::TARGET_TYPE_MCS>();
+
+ if ( l_mcses.end() == std::find_if( l_mcses.begin(), l_mcses.end(),
+ [l_mcs](const fapi2::Target<fapi2::TARGET_TYPE_MCS>& c)
+ {
+ return l_mcs == c;
+ }) )
+ {
+ l_mcses.push_back(l_mcs);
+ }
+ }
+
+ return l_mcses;
+}
+
+///
+/// @brief find the MCS given a DIMM
+/// @param[in] the fapi2 target, DIMM
+/// @return a MCS target.
+///
+template<>
+inline fapi2::Target<fapi2::TARGET_TYPE_MCS> find_target( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target)
+{
+ return i_target.getParent<fapi2::TARGET_TYPE_MCA>().getParent<fapi2::TARGET_TYPE_MCS>();
+}
+
+///
+/// @brief find the MCA given a DIMM
+/// @param[in] the fapi2 target, DIMM
+/// @return a MCA target.
+///
+template<>
+inline fapi2::Target<fapi2::TARGET_TYPE_MCA> find_target( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target)
+{
+ return i_target.getParent<fapi2::TARGET_TYPE_MCA>();
+}
+
+}// mss
+
+#endif
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/utils/index.H b/src/import/chips/p9/procedures/hwp/memory/lib/utils/index.H
new file mode 100644
index 000000000..aa9474895
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/utils/index.H
@@ -0,0 +1,71 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/utils/index.H $ */
+/* */
+/* 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 index.H
+/// @brief Tools to return attribute array index from a fapi2 target
+///
+// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
+// *HWP HWP Backup: Craig Hamilton <cchamilt@us.ibm.com>
+// *HWP Team: Memory
+// *HWP Level: 2
+// *HWP Consumed by: HB:FSP
+
+#ifndef _MSS_INDEX_H_
+#define _MSS_INDEX_H_
+
+#include <fapi2.H>
+#include "pos.H"
+#include "../shared/mss_const.H"
+
+namespace mss
+{
+///
+/// @brief Return an attribute array index from a fapi2 target
+/// @tparam T, the fapi2::TargetType
+/// @param[in] i_target, a DIMM target representing the DIMM in question
+/// @return size_t, the attribute array index.
+///
+template< fapi2::TargetType T >
+inline size_t index(const fapi2::Target<T>& i_target);
+
+template<>
+inline size_t index(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target)
+{
+ return mss::pos(i_target) % MAX_DIMM_PER_PORT;
+}
+
+template<>
+inline size_t index(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target)
+{
+ return mss::pos(i_target) % PORTS_PER_MCS;
+}
+
+///
+/// @brief Return an attribute array index from a rank number
+/// @param[in] uint64_t, a rank number DIMM0 {0, 1, 2, 3} DIMM1 {0, 1, 2, 3}
+/// @return size_t, the attribute array index.
+///
+inline size_t index(const uint64_t i_rank)
+{
+ return i_rank % RANK_MID_POINT;
+}
+
+}
+#endif
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/utils/poll.H b/src/import/chips/p9/procedures/hwp/memory/lib/utils/poll.H
new file mode 100644
index 000000000..4fc9dab60
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/utils/poll.H
@@ -0,0 +1,134 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/utils/poll.H $ */
+/* */
+/* 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 poll.H
+/// @brief Poll a scom
+///
+// *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: HB:FSP
+
+#ifndef _MSS_POLL_H_
+#define _MSS_POLL_H_
+
+#include <fapi2.H>
+#include "../shared/mss_const.H"
+#include "conversions.H"
+
+namespace mss
+{
+
+///
+/// @brief Poll paramter data structure.
+/// Represents the parameters used to poll a register.
+/// _delays are in ns, _sim_delays are in sim_cycles
+/// See conversions.H for conversions.
+struct poll_parameters
+{
+ // We need to decide how long to wait before pounding the compeletion SCOM.
+ // IN NS
+ uint64_t iv_initial_delay;
+
+ // Same as the initial delay, but used when we're running in a simulator
+ // IN SIM_CYCLES
+ uint64_t iv_initial_sim_delay;
+
+ // How many ns to wait in between poll attempts
+ // IN NS
+ uint64_t iv_delay;
+
+ // Same as the interpoll delay, but used when we're running in a simulator
+ // IN SIM_CYCLES
+ uint64_t iv_sim_delay;
+
+ // The count of polls to make
+ uint64_t iv_poll_count;
+
+ poll_parameters( const uint64_t i_initial_delay = DELAY_10NS,
+ const uint64_t i_initial_sim_delay = 200,
+ const uint64_t i_delay = DELAY_10NS,
+ const uint64_t i_sim_delay = 200,
+ const uint64_t i_poll_count = DEFAULT_POLL_LIMIT):
+ iv_initial_delay(i_initial_delay),
+ iv_initial_sim_delay(i_initial_sim_delay),
+ iv_delay(i_delay),
+ iv_sim_delay(i_sim_delay),
+ iv_poll_count(i_poll_count)
+ {}
+};
+
+///
+/// @brief Poll a scom, return whether the poll croteria were met or not
+/// @tparam T, the fapi2::TargetType
+/// @tparam L, a lambda representing the completion criteria - returns true
+/// iff the poll criteria have been met (and the polling can stop)
+/// @param[in] i_target, target for the getScom
+/// @param[in] i_addr, the address for the scom
+/// @param[in] i_params, a poll_parameters structure
+/// @param[in] i_fn, the function to call to check the poll criteria
+/// [](const size_t poll_remaining, const fapi2::buffer<uint64_t>& stat_reg) -> bool
+/// {
+/// return true;
+/// }
+/// @return bool, true iff poll criteria was met before the number of iterations
+/// ran out.
+/// @warning If you want to handle a failure as an error, you need to wrap
+/// the call to poll() in a FAPI_ASSERT. FAPI_TRY is *not* the right mechanism
+/// as poll() does not return a fapi2::ReturnCode
+///
+template< fapi2::TargetType T, typename L >
+inline bool poll(const fapi2::Target<T>& i_target, const uint64_t i_addr,
+ const poll_parameters i_params, L i_fn)
+{
+ fapi2::buffer<uint64_t> l_reg;
+
+ FAPI_DBG("polling 0x%llx: initial delay %dns(%dsc) poll %dns(%dsc) %d iters",
+ i_addr, i_params.iv_initial_delay, i_params.iv_initial_sim_delay,
+ i_params.iv_delay, i_params.iv_sim_delay, i_params.iv_poll_count);
+
+ // We know to wait this long before polling
+ FAPI_TRY( fapi2::delay(i_params.iv_initial_delay, i_params.iv_initial_sim_delay) );
+
+ for ( size_t l_poll_limit = i_params.iv_poll_count; l_poll_limit > 0; --l_poll_limit )
+ {
+ FAPI_TRY( fapi2::getScom(i_target, i_addr, l_reg) );
+
+ if (i_fn(l_poll_limit, l_reg) == true)
+ {
+ FAPI_DBG("polling finished. %d iterations remaining", l_poll_limit);
+ return true;
+ }
+
+ FAPI_TRY( fapi2::delay(i_params.iv_delay, i_params.iv_sim_delay) );
+ }
+
+ // If we're here, we ran out of poll iterations
+ FAPI_INF("WARNING: Timeout on polling");
+ return false;
+
+fapi_try_exit:
+ FAPI_ERR("mss::poll() hit an error in fapi2::delay or fapi2::getScom");
+ return false;
+}
+
+}
+#endif
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/utils/pos.H b/src/import/chips/p9/procedures/hwp/memory/lib/utils/pos.H
new file mode 100644
index 000000000..18dadf701
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/utils/pos.H
@@ -0,0 +1,133 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/utils/pos.H $ */
+/* */
+/* 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 pos.H
+/// @brief Tools to return target's position from a fapi2 target
+///
+// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
+// *HWP HWP Backup: Craig Hamilton <cchailt@us.ibm.com>
+// *HWP Team: Memory
+// *HWP Level: 2
+// *HWP Consumed by: HB:FSP
+
+#ifndef _MSS_POS_H_
+#define _MSS_POS_H_
+
+#include <fapi2.H>
+
+namespace mss
+{
+
+///
+/// @brief Trait classes for the mss::pos functions
+///
+template<fapi2::TargetType T>
+class posTraits
+{
+ public:
+ // Needed as some targets have chip_unit_pos attributes,
+ // uint8_t and some attr_pos, uint32_t. We don't really care
+ // but the type checking in the macros sure does ...
+ typedef uint8_t pos_type;
+};
+
+template<>
+class posTraits<fapi2::TARGET_TYPE_DIMM>
+{
+ public:
+ typedef uint32_t pos_type;
+};
+
+template<>
+class posTraits<fapi2::TARGET_TYPE_PROC_CHIP>
+{
+ public:
+ typedef uint32_t pos_type;
+};
+
+///
+/// @brief Return a target's position from a fapi2 target
+/// @tparam T, the fapi2::TargetType
+/// @param[in] i_target, a DIMM target representing the DIMM in question
+/// @return The position
+///
+template< fapi2::TargetType T, typename TT = posTraits<T> >
+inline typename TT::pos_type pos(const fapi2::Target<T>& i_target)
+{
+ typename TT::pos_type i_pos = 0;
+
+ // Don't use FAPI_TRY as you'll mess up fapi2::current_err which
+ // lmits where this can be used.
+ if (FAPI_ATTR_GET(fapi2::ATTR_CHIP_UNIT_POS, i_target, i_pos) != fapi2::FAPI2_RC_SUCCESS)
+ {
+ goto fapi_try_exit;
+ }
+
+ return i_pos;
+
+fapi_try_exit:
+ // If we can't get our unit position, we're in other trouble
+ FAPI_ERR("can't get our chip unit position");
+ fapi2::Assert(false);
+ return 0;
+}
+
+template<>
+inline posTraits<fapi2::TARGET_TYPE_DIMM>::pos_type pos(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target)
+{
+ posTraits<fapi2::TARGET_TYPE_DIMM>::pos_type i_pos = 0;
+
+ if (FAPI_ATTR_GET(fapi2::ATTR_POS, i_target, i_pos) != fapi2::FAPI2_RC_SUCCESS)
+ {
+ goto fapi_try_exit;
+ }
+
+ return i_pos;
+
+fapi_try_exit:
+ // If we can't get our position, we're in other trouble
+ FAPI_ERR("can't get our position");
+ fapi2::Assert(false);
+ return 0;
+
+}
+
+template<>
+inline posTraits<fapi2::TARGET_TYPE_PROC_CHIP>::pos_type pos(const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>&
+ i_target)
+{
+ posTraits<fapi2::TARGET_TYPE_PROC_CHIP>::pos_type i_pos = 0;
+
+ if (FAPI_ATTR_GET(fapi2::ATTR_POS, i_target, i_pos) != fapi2::FAPI2_RC_SUCCESS)
+ {
+ goto fapi_try_exit;
+ }
+
+ return i_pos;
+
+fapi_try_exit:
+ // If we can't get our position, we're in other trouble
+ FAPI_ERR("can't get our position");
+ fapi2::Assert(false);
+ return 0;
+
+}
+}
+#endif
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/utils/swizzle.H b/src/import/chips/p9/procedures/hwp/memory/lib/utils/swizzle.H
new file mode 100644
index 000000000..57814b265
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/utils/swizzle.H
@@ -0,0 +1,123 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/utils/swizzle.H $ */
+/* */
+/* 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 swizzle.H
+/// @brief Swizzle bits
+///
+// *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: HB:FSP
+
+#ifndef _MSS_SWIZZLE_H_
+#define _MSS_SWIZZLE_H_
+
+#include <fapi2.H>
+
+namespace mss
+{
+
+///
+/// @brief Swap two bits in a buffer
+/// @tparam TB, the bit in the buffer to move to SB
+/// @tparam SB, the bit in the buffer to move to TB
+/// @tparam T, integral type of the buffer
+/// @param[in,out] io_data, reference to the buffer
+/// @return reference to the input buffer (for chaining)
+///
+template< uint64_t TB, uint64_t SB, typename T >
+inline fapi2::buffer<T>& swap( fapi2::buffer<T>& i_data )
+{
+ bool l_tb = i_data.template getBit<TB>();
+ i_data.template writeBit<TB>(i_data.template getBit<SB>());
+ i_data.template writeBit<SB>(l_tb);
+
+ return i_data;
+}
+
+///
+/// @brief Invert (negate) one bit in a buffer
+/// @tparam TB, the bit in the buffer to negate
+/// @tparam T, integral type of the buffer
+/// @param[in,out] io_data, reference to the buffer
+/// @return reference to the input buffer (for chaining)
+///
+template< uint64_t TB, typename T >
+inline fapi2::buffer<T>& negate( fapi2::buffer<T>& i_data )
+{
+ // Use care when writeBit'ing a getBit as getBit returns a bool and writeBit
+ // checks if the input != 0. Negating it (~ getBit) was causing havok. So
+ // we do this - note the negation of the conditional to get the reverse.
+ i_data.template writeBit<TB>(i_data.template getBit<TB>() == true ? 0 : 1);
+ return i_data;
+}
+
+///
+/// @brief Reverse the buffer
+/// @param[in,out] io_buffer the buffer which to reverse
+//
+// @note from
+// http://stackoverflow.com/questions/746171/best-algorithm-for-bit-reversal-from-msb-lsb-to-lsb-msb-in-c
+///
+template< typename T >
+static inline void reverse( T& io_buffer )
+{
+ T l_result = io_buffer;
+ size_t l_s = sizeof(T) * 8 - 1;
+
+ for( io_buffer >>= 1; io_buffer; io_buffer >>= 1)
+ {
+ l_result <<= 1;
+ l_result |= io_buffer & 1;
+ l_s--;
+ }
+
+ l_result <<= l_s;
+
+ io_buffer = l_result;
+}
+
+///
+/// @brief Swizzle bits between two fapi2 buffers, and insert from source to destination
+/// @tparam DS, the start bit in the destination buffer - swizzle will count up from here
+/// @tparam L, how many bits to swizzle
+/// @tparam SS, the start bit in the source buffer - swizzle will count down from here
+/// @param[in] source buffer - these bits will be decremented
+/// @param[in] destination buffer - these bits will be incremented
+/// @return reference to the destination
+///
+template<uint64_t DS, uint64_t L, uint64_t SS, typename SB, typename DB>
+inline fapi2::buffer<DB>& swizzle( fapi2::buffer<SB> i_source, fapi2::buffer<DB>& o_destination )
+{
+ // Reverse the destination, and then mangle the start bits to get things to line up
+ fapi2::buffer<SB> l_tmp(i_source);
+ reverse(i_source);
+
+#ifdef SWIZZLE_TRACE
+ FAPI_DBG("swizzle o: 0x%0X s: 0x%X d: 0x%llX ds: %d l: %d ss: %d",
+ l_tmp, i_source, o_destination, DS, L, (sizeof(SB) * 8) - (SS + 1));
+#endif
+
+ return o_destination.template insert < DS, L, (sizeof(SB) * 8) - (SS + 1) > (SB(i_source));
+}
+
+}
+#endif
OpenPOWER on IntegriCloud