diff options
Diffstat (limited to 'src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4')
-rw-r--r-- | src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/nvdimm_utils.C | 274 | ||||
-rw-r--r-- | src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/nvdimm_utils.H | 72 |
2 files changed, 346 insertions, 0 deletions
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..306b01362 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,277 @@ /* 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/mc/mc.H> +#include <lib/ccs/ccs.H> +#include <lib/dimm/rank.H> +#include <lib/mss_attribute_accessors.H> +#include <lib/utils/poll.H> +#include <lib/utils/count_dimm.H> +#include <lib/mcbist/address.H> +#include <lib/mcbist/memdiags.H> +#include <lib/mcbist/mcbist.H> +#include <lib/mcbist/settings.H> +#include <lib/utils/conversions.H> + +#include <lib/mc/port.H> +#include <lib/phy/dp16.H> +#include <lib/dimm/rcd_load.H> +#include <lib/dimm/mrs_load.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 Helper for self_refresh_exit(). Uses memdiag to read the port to force +/// CKE back to high. Stolen from mss_lab_memdiags.C +/// Specialization for TARGET_TYPE_MCA +/// @param[in] i_target the target associated with this subroutine +/// @return FAPI2_RC_SUCCESS iff setup was successful +/// +template< > +fapi2::ReturnCode self_refresh_exit_helper( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target ) +{ + + const auto& l_mcbist = mss::find_target<fapi2::TARGET_TYPE_MCBIST>(i_target); + fapi2::buffer<uint64_t> l_status; + + // A small vector of addresses to poll during the polling loop + const std::vector<mss::poll_probe<fapi2::TARGET_TYPE_MCBIST>> l_probes = + { + {l_mcbist, "mcbist current address", MCBIST_MCBMCATQ}, + }; + + // We'll fill in the initial delay below + // Heuristically defined and copied from the f/w version of memdiags + mss::poll_parameters l_poll_parameters(0, 200, 100 * mss::DELAY_1MS, 200, 500); + uint64_t l_memory_size = 0; + + FAPI_TRY( mss::eff_memory_size(l_mcbist, l_memory_size) ); + l_poll_parameters.iv_initial_delay = mss::calculate_initial_delay(l_mcbist, (l_memory_size * mss::BYTES_PER_GB)); + + { + // Force this to run on the targeted port only + const auto& l_port = mss::relative_pos<fapi2::TARGET_TYPE_MCBIST>(i_target); + mss::mcbist::address l_start; + mss::mcbist::end_boundary l_end_boundary = mss::mcbist::end_boundary::STOP_AFTER_SLAVE_RANK; + l_start.set_port(l_port); + mss::mcbist::stop_conditions l_stop_conditions; + + // Read with super fast read + // Set up with mcbist target, stop conditions above + // Using defaults for starting at first valid address and stop at end of slave rank + FAPI_TRY ( mss::memdiags::sf_read(l_mcbist, + l_stop_conditions, + l_start, + l_end_boundary, + l_start) ); + + bool l_poll_results = mss::poll(l_mcbist, MCBIST_MCBISTFIRQ, l_poll_parameters, + [&l_status](const size_t poll_remaining, + const fapi2::buffer<uint64_t>& stat_reg) -> bool + { + FAPI_DBG("mcbist firq 0x%llx, remaining: %d", stat_reg, poll_remaining); + l_status = stat_reg; + return l_status.getBit<MCBIST_MCBISTFIRQ_MCBIST_PROGRAM_COMPLETE>() == true; + }, + l_probes); + + FAPI_DBG("memdiags_read poll result: %d", l_poll_results); + } + + return fapi2::FAPI2_RC_SUCCESS; + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Put target into self-refresh +/// Specialization for TARGET_TYPE_MCA +/// @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_MCA>& i_target ) +{ + fapi2::buffer<uint64_t> l_mbarpc0_data, l_mbastr0_data; + + // Step 1 - In MBARPC0Q, disable power domain control, set domain to MAXALL_MINALL, + // and enable minimum domain reduction + FAPI_TRY(mss::mc::read_mbarpc0(i_target, l_mbarpc0_data)); + mss::mc::set_power_control_min_max_domains_enable( l_mbarpc0_data, mss::states::OFF ); + mss::mc::set_power_control_min_max_domains( l_mbarpc0_data, mss::min_max_domains::MAXALL_MINALL ); + mss::mc::set_power_control_min_domain_reduction_enable( l_mbarpc0_data, mss::states::ON ); + FAPI_TRY(mss::mc::write_mbarpc0(i_target, l_mbarpc0_data)); + + // Step 2 - In MBASTR0Q, enable STR entry + FAPI_TRY(mss::mc::read_mbastr0(i_target, l_mbastr0_data)); + mss::mc::set_self_time_refresh_enable( l_mbastr0_data, mss::states::ON ); + FAPI_TRY(mss::mc::write_mbastr0(i_target, l_mbastr0_data)); + + // Step 3 - In MBARPC0Q, enable power domain control. + mss::mc::set_power_control_min_max_domains_enable( l_mbarpc0_data, mss::states::ON ); + FAPI_TRY(mss::mc::write_mbarpc0(i_target, l_mbarpc0_data)); + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Take the target out of self-refresh and restart refresh +/// Specialization for TARGET_TYPE_MCA +/// @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_MCA>& i_target ) +{ + fapi2::buffer<uint64_t> l_mbarpc0_data, l_mbastr0_data; + + // Step 1 - In MBARPC0Q, disable power domain control + FAPI_TRY(mss::mc::read_mbarpc0(i_target, l_mbarpc0_data)); + mss::mc::set_power_control_min_max_domains_enable( l_mbarpc0_data, mss::states::OFF ); + FAPI_TRY(mss::mc::write_mbarpc0(i_target, l_mbarpc0_data)); + + // Step 2 - In MBASTR0Q, disable STR entry + FAPI_TRY(mss::mc::read_mbastr0(i_target, l_mbastr0_data)); + mss::mc::set_self_time_refresh_enable( l_mbastr0_data, mss::states::OFF ); + FAPI_TRY(mss::mc::write_mbastr0(i_target, l_mbastr0_data)); + + // Step 3 - Run memdiags to read the port to force CKE back to high + FAPI_TRY(self_refresh_exit_helper(i_target)); + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief PDA support for post restore transition +/// Specialization 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 pda_vref_latch( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target ) +{ + std::vector<uint64_t> l_ranks; + const auto& l_mca = mss::find_target<TARGET_TYPE_MCA>(i_target); + fapi2::buffer<uint8_t> l_value, l_range; + fapi2::ReturnCode l_rc(fapi2::FAPI2_RC_SUCCESS); + + // Creates the MRS container class + mss::ddr4::pda::commands<mss::ddr4::mrs06_data> l_container; + + // Get all the ranks in the dimm + mss::rank::ranks(i_target, l_ranks); + + // Get the number of DRAMs + uint8_t l_width = 0; + mss::eff_dram_width(i_target, l_width); + const uint64_t l_num_drams = (l_width == fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X8) ? MAX_DRAMS_X8 : MAX_DRAMS_X4; + + for (const auto& l_rank : l_ranks) + { + + uint64_t l_rp = 0; + uint64_t l_wr_vref_value = 0; + bool l_wr_vref_range = 0; + fapi2::buffer<uint64_t> l_data ; + + mss::rank::get_pair_from_rank(l_mca, l_rank, l_rp); + + // create mrs06 + mss::ddr4::mrs06_data l_mrs(i_target, l_rc); + + // loop through all the dram + for(uint64_t l_dram = 0; l_dram < l_num_drams; l_dram++) + { + mss::dp16::wr_vref::read_wr_vref_register( l_mca, l_rp, l_dram, l_data); + mss::dp16::wr_vref::get_wr_vref_range( l_data, l_dram, l_wr_vref_range); + mss::dp16::wr_vref::get_wr_vref_value( l_data, l_dram, l_wr_vref_value); + + l_mrs.iv_vrefdq_train_value[mss::index(l_rank)] = l_wr_vref_value; + l_mrs.iv_vrefdq_train_range[mss::index(l_rank)] = l_wr_vref_range; + l_container.add_command(i_target, l_rank, l_mrs, l_dram); + } + } + + // Disable refresh + FAPI_TRY( mss::change_refresh_enable(l_mca, states::LOW) ); + + // execute_wr_vref_latch(l_container) + FAPI_TRY( mss::ddr4::pda::execute_wr_vref_latch(l_container) ) + + // Enable refresh + FAPI_TRY( mss::change_refresh_enable(l_mca, states::HIGH) ); + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Post restore transition to support restoring nvdimm to +/// a functional state after the restoring the data from NAND flash +/// to DRAM +/// Specialization for TARGET_TYPE_MCA +/// @param[in] i_target the target associated with this subroutine +/// @return FAPI2_RC_SUCCESS iff setup was successful +/// +template<> +fapi2::ReturnCode post_restore_transition( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target ) +{ + // Subseqent restore on later nvdimms would go wonky if this goes before STR exit... + FAPI_TRY( mss::rcd_load( i_target ) ); + + // Exit STR + FAPI_TRY( self_refresh_exit( i_target ) ); + + // Load the MRS + FAPI_TRY( mss::mrs_load( i_target ) ); + + // Do ZQCAL + { + fapi2::buffer<uint32_t> l_cal_steps_enabled; + l_cal_steps_enabled.setBit<mss::DRAM_ZQCAL>(); + + FAPI_DBG("cal steps enabled: 0x%08x ", l_cal_steps_enabled); + FAPI_TRY( mss::setup_and_execute_zqcal(i_target, l_cal_steps_enabled), "Error in nvdimm setup_and_execute_zqcal()" ); + } + + // Latch the trained PDA vref values for each dimm under the port + for (const auto& l_dimm : mss::find_targets<fapi2::TARGET_TYPE_DIMM>(i_target)) + { + FAPI_TRY( pda_vref_latch( l_dimm ) ); + } + +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..b434abc3b 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,75 @@ /* 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 Helper for self_refresh_exit(). +/// @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 +/// @note Uses memdiag to read the port to force CKE back to high. +/// Stolen from mss_lab_memdiags.C +/// +template< fapi2::TargetType T > +fapi2::ReturnCode self_refresh_exit_helper( const fapi2::Target<T>& i_target ); + +/// +/// @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 ); + +/// +/// @brief Latch write vref at per-dram basis +/// @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 pda_vref_latch( const fapi2::Target<T>& i_target ); + +/// +/// @brief Full post-restore transition for NVDIMM +/// @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 post_restore_transition( const fapi2::Target<T>& i_target ); + +}//ns nvdimm + +}//ns mss |