diff options
Diffstat (limited to 'src')
5 files changed, 265 insertions, 4 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 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<TARGET_TYPE_MCBIST>& 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<TT::ARR0_DDR_CKE, TT::ARR0_DDR_CKE_LEN>(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<P> > 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<uint8_t> 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<T> TT; + + // Pulls out the final command's CKE value and stores it in the associated instance variable + l_last.arr0.template extractToRight<TT::ARR0_DDR_CKE, TT::ARR0_DDR_CKE_LEN>(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<T> self_refresh_entry_command( const fapi2::Target<fapi2::T // From DDR4 Spec table 17: // All other bits from the command truth table are 'V', for valid (1 or 0) + // Sets up the default timing for SRE to be the minimum self time refresh time + l_boilerplate_arr1.insertFromRight<TT::ARR1_IDLES, TT::ARR1_IDLES_LEN>( mss::tckeser(i_target) ); + return instruction_t<T>(i_target, i_rank, l_boilerplate_arr0, l_boilerplate_arr1); } @@ -809,6 +841,9 @@ inline instruction_t<T> self_refresh_exit_command( const fapi2::Target<fapi2::TA // From DDR4 Spec table 17: // All other bits from the command truth table are 'V', for valid (1 or 0) + // Sets up the default timing for SRE to be the minimum self time refresh time + l_boilerplate_arr1.insertFromRight<TT::ARR1_IDLES, TT::ARR1_IDLES_LEN>( mss::txsdll(i_target) ); + return instruction_t<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 <tyeung@us.ibm.com> +// *HWP HWP Backup: Stephen Glancy <sglancy@us.ibm.com> +// *HWP Team: Memory +// *HWP Level: 3 +// *HWP Consumed by: FSP:HB + +#include <fapi2.H> +#include <vector> + +#include <lib/dimm/ddr4/nvdimm_utils.H> +#include <lib/ccs/ccs.H> +#include <lib/mc/port.H> +#include <lib/phy/dp16.H> +#include <lib/dimm/rank.H> +#include <lib/dimm/rcd_load.H> +#include <lib/dimm/mrs_load.H> +#include <lib/mss_attribute_accessors.H> +#include <lib/workarounds/ccs_workarounds.H> +#include <lib/dimm/ddr4/pda.H> +#include <lib/dimm/ddr4/zqcal.H> + +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<fapi2::TARGET_TYPE_DIMM>& i_target ) +{ + std::vector<uint64_t> l_ranks; + const auto& l_mca = mss::find_target<fapi2::TARGET_TYPE_MCA>(i_target); + const auto& l_mcbist = mss::find_target<fapi2::TARGET_TYPE_MCBIST>(i_target); + + mss::ccs::program<TARGET_TYPE_MCBIST> 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<TARGET_TYPE_MCBIST>(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<fapi2::TARGET_TYPE_DIMM>& i_target ) +{ + + std::vector<uint64_t> l_ranks; + const auto& l_mca = mss::find_target<fapi2::TARGET_TYPE_MCA>(i_target); + const auto& l_mcbist = mss::find_target<fapi2::TARGET_TYPE_MCBIST>(i_target); + + mss::ccs::program<TARGET_TYPE_MCBIST> 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<fapi2::TARGET_TYPE_MCBIST>(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 <tyeung@us.ibm.com> +// *HWP HWP Backup: Stephen Glancy <sglancy@us.ibm.com> +// *HWP Team: Memory +// *HWP Level: 3 +// *HWP Consumed by: FSP:HB + +#include <fapi2.H> +#include <generic/memory/lib/utils/find.H> + +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<T>& 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<T>& 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 @@ -332,6 +332,32 @@ fapi_try_exit: } /// +/// @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<T>& 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<T>& 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<T>& i_target ) +{ + return tcke(i_target) + 1; +} + } // mss #endif |