summaryrefslogtreecommitdiffstats
path: root/src/import/chips/p9/procedures/hwp/memory
diff options
context:
space:
mode:
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