summaryrefslogtreecommitdiffstats
path: root/src/import/chips/p9/procedures/hwp/memory
diff options
context:
space:
mode:
authorTsung Yeung <tyeung@us.ibm.com>2018-01-16 18:08:25 -0500
committerDaniel M. Crowell <dcrowell@us.ibm.com>2018-02-24 21:30:45 -0500
commit1d2a738923414693d7c567479c5f85f436b1c416 (patch)
treec4e5906f4502e8a15348a0d2dca1b2f687bc02d2 /src/import/chips/p9/procedures/hwp/memory
parentb5c57afe40a8667b2cfc5c0aae235132812490ed (diff)
downloadtalos-hostboot-1d2a738923414693d7c567479c5f85f436b1c416.tar.gz
talos-hostboot-1d2a738923414693d7c567479c5f85f436b1c416.zip
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 <pfd-jenkins+hostboot@us.ibm.com> Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com> Tested-by: Jenkins OP HW <op-hw-jenkins+hostboot@us.ibm.com> Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com> Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src/import/chips/p9/procedures/hwp/memory')
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/ccs/ccs.C5
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/ccs/ccs.H41
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/nvdimm_utils.C132
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/nvdimm_utils.H41
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/eff_config/timing.H50
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
OpenPOWER on IntegriCloud