From 1d2a738923414693d7c567479c5f85f436b1c416 Mon Sep 17 00:00:00 2001 From: Tsung Yeung Date: Tue, 16 Jan 2018 18:08:25 -0500 Subject: Adds self time refresh entry and exit helper functions For NVDIMM, self time refresh entry and exit are needed for the NVDIMM data restore functionality. This commit adds in helper functions for SRE/SRX for NVDIMM Change-Id: I3fb522f0baf6cc6a6cafb41c220be50ce1875ba3 Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/54261 Tested-by: Jenkins Server Tested-by: Jenkins OP Build CI Tested-by: Jenkins OP HW Tested-by: FSP CI Jenkins Reviewed-by: Daniel M. Crowell --- .../chips/p9/procedures/hwp/memory/lib/ccs/ccs.C | 5 +- .../chips/p9/procedures/hwp/memory/lib/ccs/ccs.H | 41 ++++++- .../hwp/memory/lib/dimm/ddr4/nvdimm_utils.C | 132 +++++++++++++++++++++ .../hwp/memory/lib/dimm/ddr4/nvdimm_utils.H | 41 +++++++ .../procedures/hwp/memory/lib/eff_config/timing.H | 50 ++++++++ 5 files changed, 265 insertions(+), 4 deletions(-) (limited to 'src/import/chips/p9/procedures/hwp/memory') 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 index 669048513..aa5de6be6 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/ccs/ccs.C +++ b/src/import/chips/p9/procedures/hwp/memory/lib/ccs/ccs.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* Contributors Listed Below - COPYRIGHT 2015,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -249,6 +249,9 @@ fapi2::ReturnCode execute( const fapi2::Target& i_target, FAPI_INF("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)); + // Sets up the CKE values to be latched for the final CCS command + l_des.arr0.insertFromRight(i_program.iv_final_cke_value); + // 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.) 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 579c0a317..b0ca43165 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 @@ -183,7 +183,7 @@ static constexpr uint64_t CKE_ARY_SRE[] = // 0, 1, 2, 3, 0b0111, 0b1011, 0, 0, // 4, 5, 6, 7 - 0b0111, 0b1011, 0, 0 + 0b1101, 0b1110, 0, 0 }; // For self_refresh_exit_command() @@ -192,7 +192,7 @@ static constexpr uint64_t CKE_ARY_SRX[] = // 0, 1, 2, 3, 0b1000, 0b0100, 0, 0, // 4, 5, 6, 7 - 0b1000, 0b0100, 0, 0 + 0b0010, 0b0001, 0, 0 }; namespace ccs @@ -346,7 +346,7 @@ 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) + program(): iv_poll(0, 0), iv_final_cke_value(CKE_HIGH) {} // Vector of instructions @@ -355,6 +355,35 @@ class program // Vector of polling probes std::vector< poll_probe

> iv_probes; + + // Certain commands require different CKE values at the end of CCS + // These commands need a way to plop in those CKE values to be used with the final NOP + // The following variable allows for a custom CKE value to be passed in + fapi2::buffer iv_final_cke_value; + + /// + /// @brief Sets up the final CKE value to be latched by the final command in the instructions vector + /// + inline void set_last_cke_value() + { + // If we don't have any instructions, then just bail out + if(iv_instructions.empty()) + { + FAPI_INF("An empty instruction was passed in. Last CKE value will be held the same: 0x%02x", iv_final_cke_value); + return; + } + + // Get the last valid instruction + const auto& l_last = iv_instructions.back(); + + // Beautifying traits declaration + typedef ccsTraits TT; + + // Pulls out the final command's CKE value and stores it in the associated instance variable + l_last.arr0.template extractToRight(iv_final_cke_value); + + FAPI_DBG("new final CKE value for CCS instructions is 0x%02x", iv_final_cke_value); + } }; /// @@ -775,6 +804,9 @@ inline instruction_t self_refresh_entry_command( const fapi2::Target( mss::tckeser(i_target) ); + return instruction_t(i_target, i_rank, l_boilerplate_arr0, l_boilerplate_arr1); } @@ -809,6 +841,9 @@ inline instruction_t self_refresh_exit_command( const fapi2::Target( mss::txsdll(i_target) ); + return instruction_t(i_target, i_rank, l_boilerplate_arr0, l_boilerplate_arr1); } 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 37d0d8d8a..807274e35 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 @@ -22,3 +22,135 @@ /* permissions and limitations under the License. */ /* */ /* IBM_PROLOG_END_TAG */ + +/// +/// @file nvdimm_utils.C +/// @brief Subroutines to support nvdimm backup/restore process +/// +// *HWP HWP Owner: Tsung Yeung +// *HWP HWP Backup: Stephen Glancy +// *HWP Team: Memory +// *HWP Level: 3 +// *HWP Consumed by: FSP:HB + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using fapi2::TARGET_TYPE_MCBIST; +using fapi2::TARGET_TYPE_MCA; +using fapi2::TARGET_TYPE_DIMM; + +namespace mss +{ + +namespace nvdimm +{ + +/// +/// @brief Put target into self-refresh +/// Specializaton for TARGET_TYPE_DIMM +/// @param[in] i_target the target associated with this subroutine +/// @return FAPI2_RC_SUCCESS iff setup was successful +/// +template<> +fapi2::ReturnCode self_refresh_entry( const fapi2::Target& i_target ) +{ + std::vector l_ranks; + const auto& l_mca = mss::find_target(i_target); + const auto& l_mcbist = mss::find_target(i_target); + + mss::ccs::program l_program; + // Timings on these guys should be pretty short + l_program.iv_poll.iv_initial_delay = DELAY_100NS; + l_program.iv_poll.iv_initial_sim_delay = DELAY_100NS; + + // Get all the ranks in the dimm + FAPI_TRY( mss::rank::ranks(i_target, l_ranks) ); + + // Prep the instructions to put each rank into self refresh + for ( const auto& l_rank : l_ranks ) + { + l_program.iv_instructions.push_back( mss::ccs::self_refresh_entry_command(i_target, l_rank) ); + } + + // Hacks to hold low order ranks CKE low in higher order rank instruction + mss::ccs::workarounds::hold_cke_low(l_program); + + // Setup the CKE to latch for the final command with the CKE from our final true command + l_program.set_last_cke_value(); + + // Sets the CCS address mux register to latch in the CKE state that was on the bus last + // This is needed to keep the DIMM in self-time refresh mode + FAPI_TRY(mss::change_addr_mux_sel(l_mca, mss::states::HIGH)); + + // Disable refresh + FAPI_TRY( mss::change_refresh_enable(l_mca, states::LOW) ); + + // Execute CCS + FAPI_TRY( mss::ccs::execute( l_mcbist, l_program, l_mca ) ); + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Take the target out of self-refresh and restart refresh +/// @tparam T the target type associated with this subroutine +/// @param[in] i_target the target associated with this subroutine +/// @return FAPI2_RC_SUCCESS iff setup was successful +/// +template< > +fapi2::ReturnCode self_refresh_exit( const fapi2::Target& i_target ) +{ + + std::vector l_ranks; + const auto& l_mca = mss::find_target(i_target); + const auto& l_mcbist = mss::find_target(i_target); + + mss::ccs::program l_program; + l_program.iv_poll.iv_initial_delay = DELAY_100NS; + l_program.iv_poll.iv_initial_sim_delay = DELAY_100NS; + + // Get all the ranks in the dimm + mss::rank::ranks(i_target, l_ranks); + + // Prep the instructions to take each rank out of self refresh + for ( const auto& l_rank : l_ranks ) + { + l_program.iv_instructions.push_back( mss::ccs::self_refresh_exit_command(i_target, l_rank) ); + } + + // Hacks to hold CKE high, so we don't put any ranks accidentally into power down mode + mss::ccs::workarounds::hold_cke_high(l_program); + + // Setup the CKE to latch for the final command with the CKE from our final true command + l_program.set_last_cke_value(); + + // Restores the CCS address mux select to its mainline setting + FAPI_TRY(mss::change_addr_mux_sel(l_mca, mss::states::LOW)); + + // Execute CCS + FAPI_TRY( mss::ccs::execute( l_mcbist, l_program, l_mca ) ); + + // Enable refresh + FAPI_TRY( mss::change_refresh_enable(l_mca, states::HIGH) ); + +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 03c1af7a0..aec77f3f8 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 @@ -22,3 +22,44 @@ /* permissions and limitations under the License. */ /* */ /* IBM_PROLOG_END_TAG */ + +/// +/// @file nvdimm_utils.H +/// @brief Subroutines to support nvdimm backup/restore process +/// +// *HWP HWP Owner: Tsung Yeung +// *HWP HWP Backup: Stephen Glancy +// *HWP Team: Memory +// *HWP Level: 3 +// *HWP Consumed by: FSP:HB + +#include +#include + +namespace mss +{ + +namespace nvdimm +{ + +/// +/// @brief Disable refresh and put target into self-refresh +/// @tparam T the target type associated with this subroutine +/// @param[in] i_target the target associated with this subroutine +/// @return FAPI2_RC_SUCCESS iff setup was successful +/// +template< fapi2::TargetType T > +fapi2::ReturnCode self_refresh_entry( const fapi2::Target& i_target ); + +/// +/// @brief Take the target out of self-refresh and restart refresh +/// @tparam T the target type associated with this subroutine +/// @param[in] i_target the target associated with this subroutine +/// @return FAPI2_RC_SUCCESS iff setup was successful +/// +template< fapi2::TargetType T > +fapi2::ReturnCode self_refresh_exit( const fapi2::Target& i_target ); + +}//ns nvdimm + +}//ns mss diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/timing.H b/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/timing.H index cb500c798..bcad7b92b 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/timing.H +++ b/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/timing.H @@ -331,6 +331,32 @@ fapi_try_exit: return fapi2::current_err; } +/// +/// @brief DLL locking time *in clocks* +/// @tparam T the fapi2::TargetType of i_target +/// @param[in] i_target a target for attributes +/// @return txsdll +/// +// TK is there some way to handle this better? we want to use the below in CCS command creation +template< fapi2::TargetType T > +inline uint64_t txsdll( const fapi2::Target& i_target ) +{ + uint64_t l_tdllk = 0; + + FAPI_TRY(tdllk(i_target, l_tdllk)); + return l_tdllk; + +fapi_try_exit: + // We simply can't work if we can't get the frequency or + // if we get an unsupported value that can't be converted to a valid tCK (clock period) + // ...so this should be ok + FAPI_ERR("Failed accessing tDLLK, exiting..."); + fapi2::Assert(false); + + // Keeps compiler happy + return 0; +} + /// /// @brief Mode Register Set Command Cycle Time /// @return constexpr value of 8 clocks @@ -1278,5 +1304,29 @@ constexpr uint64_t tccd_s() return 4; } +/// +/// @brief Return the minimum allowable CKE pulse time +/// @tparam T the fapi2::TargetType of a type from which we can get MT/s +/// @param[in] i_target the fapi2 target +/// @return tCKE timing in clocks (nck) +/// +template< fapi2::TargetType T > +uint64_t tcke( const fapi2::Target& i_target ) +{ + return std::max( 3, spd::ns_to_nck(i_target, 5) ); +} + +/// +/// @brief Return the minimum allowable CKE pulse time +/// @tparam T the fapi2::TargetType of a type from which we can get MT/s +/// @param[in] i_target the fapi2 target +/// @return tCKE timing in clocks (nck) +/// +template< fapi2::TargetType T > +uint64_t tckeser( const fapi2::Target& i_target ) +{ + return tcke(i_target) + 1; +} + } // mss #endif -- cgit v1.2.1