summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/ccs/ccs.H7
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/nvdimm_utils.C69
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/nvdimm_utils.H9
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/workarounds/ccs_workarounds.C79
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/workarounds/ccs_workarounds.H12
5 files changed, 173 insertions, 3 deletions
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
index 6de8554b9..0d0434bc1 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/ccs/ccs.H
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/ccs/ccs.H
@@ -521,13 +521,14 @@ inline instruction_t<T> mrs_command( const fapi2::Target<fapi2::TARGET_TYPE_DIMM
/// @brief Create, initialize a JEDEC Device Deselect CCS command
/// @tparam T the target type of the chiplet which executes the CCS instruction
/// @tparam TT the CCS traits of the chiplet which executes the CCS instruction
+/// @param[in] i_idle the idle time to the next command (default to 0)
/// @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()
+inline instruction_t<T> des_command(const uint16_t i_idle = 0)
{
fapi2::buffer<uint64_t> rcd_boilerplate_arr0;
fapi2::buffer<uint64_t> rcd_boilerplate_arr1;
@@ -539,6 +540,9 @@ inline instruction_t<T> des_command()
// 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>(CKE_HIGH);
+ // Insert idle
+ rcd_boilerplate_arr1.template insertFromRight<TT::ARR1_IDLES, TT::ARR1_IDLES_LEN>( i_idle );
+
// ACT is high no-care
// RAS, CAS, WE no-care
@@ -679,6 +683,7 @@ inline instruction_t<T> initial_cal_command(const uint64_t i_rp)
/// @tparam TT the CCS traits of the chiplet which executes the CCS instruction
/// @param[in] i_target the DIMM this instruction is headed for
/// @param[in] i_rank the rank on this dimm
+/// @param[in] i_idle the idle time to the next command (default to 0)
/// @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
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/nvdimm_utils.C b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/nvdimm_utils.C
index d2ddaf136..ed63071d5 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/nvdimm_utils.C
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/nvdimm_utils.C
@@ -651,6 +651,75 @@ fapi_try_exit:
return fapi2::current_err;
}
+///
+/// @brief Preload the CCS with the EPOW sequence
+/// @param[in] i_target the target associated with this subroutine
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+/// @note This is written specifically to support EPOW on NVDIMM and
+/// should only be called after all the draminit.
+///
+fapi2::ReturnCode preload_epow_sequence( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target )
+{
+ typedef ccsTraits<fapi2::TARGET_TYPE_MCBIST> TT;
+ const auto& l_mcbist = mss::find_target<TARGET_TYPE_MCBIST>(i_target);
+ const auto& l_dimms = mss::find_targets<TARGET_TYPE_DIMM>(i_target);
+ constexpr uint64_t CS_N_ACTIVE = 0b00;
+ uint8_t l_trp = 0;
+ uint16_t l_trfc = 0;
+ std::vector<uint64_t> l_ranks;
+ ccs::program<TARGET_TYPE_MCBIST> l_program;
+ ccs::instruction_t<TARGET_TYPE_MCBIST> l_inst;
+
+ // Get tRP and tRFC
+ FAPI_TRY(mss::eff_dram_trp(i_target, l_trp));
+ FAPI_TRY(mss::eff_dram_trfc(i_target, l_trfc));
+
+ l_program.iv_poll.iv_initial_delay = 0;
+ l_program.iv_poll.iv_initial_sim_delay = 0;
+
+ // Start the program with DES and wait for tRFC
+ // All CKE = high, all CSn = high, Reset_n = high, wait tRFC
+ l_inst = ccs::des_command<TARGET_TYPE_MCBIST>(l_trfc);
+ l_inst.arr0.setBit<TT::ARR0_DDR_RESETN>();
+ FAPI_INF("des_command() arr0 = 0x%016lx , arr1 = 0x%016lx", l_inst.arr0, l_inst.arr1);
+ l_program.iv_instructions.push_back(l_inst);
+
+ // Precharge all command
+ // All CKE = high, all CSn = low, Reset_n = high, wait tRP
+ l_inst = ccs::precharge_all_command<TARGET_TYPE_MCBIST>(l_dimms[0], 0, l_trp);
+ l_inst.arr0.insertFromRight<TT::ARR0_DDR_CSN_0_1, TT::ARR0_DDR_CSN_0_1_LEN>(CS_N_ACTIVE);
+ l_inst.arr0.insertFromRight<TT::ARR0_DDR_CSN_2_3, TT::ARR0_DDR_CSN_2_3_LEN>(CS_N_ACTIVE);
+ l_inst.arr0.setBit<TT::ARR0_DDR_RESETN>();
+ FAPI_INF("precharge_all_command() arr0 = 0x%016lx , arr1 = 0x%016lx", l_inst.arr0, l_inst.arr1);
+ l_program.iv_instructions.push_back(l_inst);
+
+ // Self-refresh entry command
+ // All CKE = low, all CSn = low, Reset_n = high, wait tCKSRE
+ l_inst = ccs::self_refresh_entry_command<TARGET_TYPE_MCBIST>(l_dimms[0], 0, mss::tcksre(l_dimms[0]));
+ l_inst.arr0.insertFromRight<TT::ARR0_DDR_CSN_0_1, TT::ARR0_DDR_CSN_0_1_LEN>(CS_N_ACTIVE);
+ l_inst.arr0.insertFromRight<TT::ARR0_DDR_CSN_2_3, TT::ARR0_DDR_CSN_2_3_LEN>(CS_N_ACTIVE);
+ l_inst.arr0.insertFromRight<TT::ARR0_DDR_CKE, TT::ARR0_DDR_CKE_LEN>(mss::CKE_LOW);
+ l_inst.arr0.setBit<TT::ARR0_DDR_RESETN>();
+ FAPI_INF("self_refresh_entry_command() arr0 = 0x%016lx , arr1 = 0x%016lx", l_inst.arr0, l_inst.arr1);
+ l_program.iv_instructions.push_back(l_inst);
+
+ // Push in an empty instruction for RESETn
+ // All CKE = low, all CSn = high (default), Reset_n = low
+ l_inst = ccs::instruction_t<TARGET_TYPE_MCBIST>(l_dimms[0]);
+ FAPI_INF("Assert RESETn arr0 = 0x%016lx , arr1 = 0x%016lx", l_inst.arr0, l_inst.arr1);
+ l_program.iv_instructions.push_back(l_inst);
+
+ // Load the program
+ FAPI_TRY( mss::ccs::workarounds::preload_ccs_for_epow(l_mcbist, l_program),
+ "Failed to preload the ccs for epow %s", mss::c_str(i_target) );
+
+ // The actual execution of this program will be trigger by EPOW. When EPOW occurs,
+ // OCC will change the mux and hit the go button to execute CCS
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
}//ns nvdimm
}//ns mss
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/nvdimm_utils.H b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/nvdimm_utils.H
index fe58fae31..538a650ba 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/nvdimm_utils.H
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/nvdimm_utils.H
@@ -171,6 +171,15 @@ fapi2::ReturnCode post_restore_zqcal( const fapi2::Target<fapi2::TARGET_TYPE_MCA
template< fapi2::TargetType T >
fapi2::ReturnCode post_restore_transition( const fapi2::Target<T>& i_target );
+///
+/// @brief Preload the CCS with the EPOW sequence
+/// @param[in] i_target the target associated with this subroutine
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+/// @note This is written specifically to support EPOW on NVDIMM and
+/// should only be called after all the draminit.
+///
+fapi2::ReturnCode preload_epow_sequence( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target );
+
}//ns nvdimm
}//ns mss
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/ccs_workarounds.C b/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/ccs_workarounds.C
index e7ceb2b0b..42374919c 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/ccs_workarounds.C
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/ccs_workarounds.C
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2017,2018 */
+/* Contributors Listed Below - COPYRIGHT 2017,2019 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -136,6 +136,83 @@ fapi_try_exit:
return fapi2::current_err;
}
+///
+/// @brief Preload the CCS program for epow
+/// @param[in] i_target the target to effect
+/// @param[in] i_program the vector of instructions
+/// @return FAPI2_RC_SUCCSS iff ok
+/// @note This is written specifically to support EPOW on NVDIMM
+/// This function loads the input program to the CCS arrays
+/// without execute as opposed to ccs::execute(). The actual
+/// ccs program execution will be handled by OCC
+///
+fapi2::ReturnCode preload_ccs_for_epow( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target,
+ ccs::program<fapi2::TARGET_TYPE_MCBIST>& i_program)
+{
+ typedef ccsTraits<fapi2::TARGET_TYPE_MCBIST> TT;
+
+ // Subtract one for the idle we insert at the end
+ constexpr size_t CCS_INSTRUCTION_DEPTH = 32 - 1;
+ constexpr uint64_t CCS_ARR0_ZERO = MCBIST_CCS_INST_ARR0_00;
+ constexpr uint64_t CCS_ARR1_ZERO = MCBIST_CCS_INST_ARR1_00;
+
+ FAPI_INF("loading ccs instructions (%d) for epow on %s", i_program.iv_instructions.size(), mss::c_str(i_target));
+
+ auto l_inst_iter = i_program.iv_instructions.begin();
+
+ // Stop the CCS engine just for giggles - it might be running ...
+ FAPI_TRY( start_stop(i_target, mss::states::STOP), "Error in ccs::workarounds::preload_ccs_for_epow" );
+
+ FAPI_ASSERT( mss::poll(i_target, TT::STATQ_REG, poll_parameters(),
+ [](const size_t poll_remaining, const fapi2::buffer<uint64_t>& stat_reg) -> bool
+ {
+ FAPI_INF("ccs statq (stop) 0x%llx, remaining: %d", stat_reg, poll_remaining);
+ return stat_reg.getBit<TT::CCS_IN_PROGRESS>() != 1;
+ }),
+ fapi2::MSS_CCS_HUNG_TRYING_TO_STOP().set_MCBIST_TARGET(i_target) );
+
+ while (l_inst_iter != i_program.iv_instructions.end())
+ {
+ size_t l_inst_count = 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)
+ {
+ // If we are on the last instruction we want to stay there. If we exit
+ // the sequencer could take back the control. This is also the reason
+ // we are not adding up the delays here.
+ if (l_inst_iter + 1 == i_program.iv_instructions.end())
+ {
+ l_inst_iter->arr1.insertFromRight<MCBIST_CCS_INST_ARR1_00_GOTO_CMD,
+ MCBIST_CCS_INST_ARR1_00_GOTO_CMD_LEN>(l_inst_count);
+ }
+ else
+ {
+ 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( mss::putScom(i_target, CCS_ARR0_ZERO + l_inst_count, l_inst_iter->arr0),
+ "Error in ccs::workarounds::preload_ccs_for_epow" );
+ FAPI_TRY( mss::putScom(i_target, CCS_ARR1_ZERO + l_inst_count, l_inst_iter->arr1),
+ "Error in ccs::workarounds::preload_ccs_for_epow" );
+
+ FAPI_INF("css inst %d: 0x%016lX 0x%016lX (0x%lx, 0x%lx)",
+ l_inst_count, l_inst_iter->arr0, l_inst_iter->arr1,
+ CCS_ARR0_ZERO + l_inst_count, CCS_ARR1_ZERO + l_inst_count,
+ mss::c_str(i_target));
+ }
+ }
+
+ // No need to set the ports here. This will be done by OCC before poking the start bit
+
+fapi_try_exit:
+ i_program.iv_instructions.clear();
+ return fapi2::current_err;
+}
+
+
namespace wr_lvl
{
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/ccs_workarounds.H b/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/ccs_workarounds.H
index eb496f383..60c7ef23d 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/ccs_workarounds.H
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/ccs_workarounds.H
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2017,2018 */
+/* Contributors Listed Below - COPYRIGHT 2017,2019 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -147,6 +147,16 @@ inline void hold_cke_high( ccs::program<fapi2::TARGET_TYPE_MCBIST>& io_program )
}
}
+///
+/// @brief Preload the CCS program for epow
+/// @param[in] i_target the target to effect
+/// @param[in] i_program the vector of instructions
+/// @return FAPI2_RC_SUCCSS iff ok
+/// @note This is written specifically to support EPOW on NVDIMM
+///
+fapi2::ReturnCode preload_ccs_for_epow( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target,
+ ccs::program<fapi2::TARGET_TYPE_MCBIST>& i_program);
+
namespace wr_lvl
{
OpenPOWER on IntegriCloud