From 9ab1bc28a6d2b703cab2d36985e17601d85b0c20 Mon Sep 17 00:00:00 2001 From: Tsung Yeung Date: Fri, 22 Mar 2019 09:43:38 -0400 Subject: Preload CCS program to support EPOW on NVDIMM This is written specifically for NVDIMM on P9 Nimbus. The current recipe relies on the MC sequencer to enter STR in the event of EPOW and could be delayed depending on the status of the bus. CCS will ensure the immediate entry of the STR and the order of execution (STR -> assert RESETn) Change-Id: Ic117b489582aaf92810e905f43fe2e4e0408eeeb CQ:SW458983 Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/74969 Tested-by: FSP CI Jenkins Tested-by: Jenkins Server Tested-by: HWSV CI Tested-by: Hostboot CI Reviewed-by: Louis Stermole Reviewed-by: STEPHEN GLANCY Reviewed-by: Jennifer A. Stofer Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/75019 Reviewed-by: Christian R. Geddes --- .../chips/p9/procedures/hwp/memory/lib/ccs/ccs.H | 7 +- .../hwp/memory/lib/dimm/ddr4/nvdimm_utils.C | 69 +++++++++++++++++++ .../hwp/memory/lib/dimm/ddr4/nvdimm_utils.H | 9 +++ .../hwp/memory/lib/workarounds/ccs_workarounds.C | 79 +++++++++++++++++++++- .../hwp/memory/lib/workarounds/ccs_workarounds.H | 12 +++- 5 files changed, 173 insertions(+), 3 deletions(-) (limited to 'src/import/chips') 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 mrs_command( const fapi2::Target > -inline instruction_t des_command() +inline instruction_t des_command(const uint16_t i_idle = 0) { fapi2::buffer rcd_boilerplate_arr0; fapi2::buffer rcd_boilerplate_arr1; @@ -539,6 +540,9 @@ inline instruction_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(CKE_HIGH); + // Insert idle + rcd_boilerplate_arr1.template insertFromRight( i_idle ); + // ACT is high no-care // RAS, CAS, WE no-care @@ -679,6 +683,7 @@ inline instruction_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& i_target ) +{ + typedef ccsTraits TT; + const auto& l_mcbist = mss::find_target(i_target); + const auto& l_dimms = mss::find_targets(i_target); + constexpr uint64_t CS_N_ACTIVE = 0b00; + uint8_t l_trp = 0; + uint16_t l_trfc = 0; + std::vector l_ranks; + ccs::program l_program; + ccs::instruction_t 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(l_trfc); + l_inst.arr0.setBit(); + 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(l_dimms[0], 0, l_trp); + l_inst.arr0.insertFromRight(CS_N_ACTIVE); + l_inst.arr0.insertFromRight(CS_N_ACTIVE); + l_inst.arr0.setBit(); + 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(l_dimms[0], 0, mss::tcksre(l_dimms[0])); + l_inst.arr0.insertFromRight(CS_N_ACTIVE); + l_inst.arr0.insertFromRight(CS_N_ACTIVE); + l_inst.arr0.insertFromRight(mss::CKE_LOW); + l_inst.arr0.setBit(); + 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(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::ReturnCode post_restore_transition( const fapi2::Target& 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& 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& i_target, + ccs::program& i_program) +{ + typedef ccsTraits 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& stat_reg) -> bool + { + FAPI_INF("ccs statq (stop) 0x%llx, remaining: %d", stat_reg, poll_remaining); + return stat_reg.getBit() != 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(l_inst_count); + } + else + { + l_inst_iter->arr1.insertFromRight(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& 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& i_target, + ccs::program& i_program); + namespace wr_lvl { -- cgit v1.2.1