diff options
Diffstat (limited to 'src')
9 files changed, 278 insertions, 568 deletions
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/mrs_load_ddr4.C b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/mrs_load_ddr4.C index b4ce1a6b7..540ae5b8c 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/mrs_load_ddr4.C +++ b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/mrs_load_ddr4.C @@ -37,6 +37,7 @@ #include <mss.H> #include <lib/dimm/ddr4/mrs_load_ddr4.H> +#include <lib/eff_config/timing.H> using fapi2::TARGET_TYPE_MCBIST; using fapi2::TARGET_TYPE_DIMM; @@ -60,31 +61,26 @@ fapi2::ReturnCode mrs_load( const fapi2::Target<TARGET_TYPE_DIMM>& i_target, { FAPI_INF("ddr4::mrs_load %s", mss::c_str(i_target)); - // Per DDR4 Full spec update (79-4A) - timing requirements - constexpr uint64_t tMRD = 8; - constexpr uint64_t tZQinit = 1024; - uint64_t l_freq = 0; - uint64_t tDLLK = 0; fapi2::buffer<uint16_t> l_cal_steps; + uint64_t tDLLK = 0; static std::vector< mrs_data<TARGET_TYPE_MCBIST> > l_mrs_data = { // JEDEC ordering of MRS per DDR4 power on sequence - { 3, mrs03, mrs03_decode, tMRD }, - { 6, mrs06, mrs06_decode, tMRD }, - { 5, mrs05, mrs05_decode, tMRD }, - { 4, mrs04, mrs04_decode, tMRD }, - { 2, mrs02, mrs02_decode, tMRD }, - { 1, mrs01, mrs01_decode, tMRD }, - { 0, mrs00, mrs00_decode, tMRD }, + { 3, mrs03, mrs03_decode, mss::tmrd() }, + { 6, mrs06, mrs06_decode, mss::tmrd() }, + { 5, mrs05, mrs05_decode, mss::tmrd() }, + { 4, mrs04, mrs04_decode, mss::tmrd() }, + { 2, mrs02, mrs02_decode, mss::tmrd() }, + { 1, mrs01, mrs01_decode, mss::tmrd() }, + + // We need to wait either tmod or tmrd before zqcl. + { 0, mrs00, mrs00_decode, std::max(mss::tmrd(), mss::tmod(i_target)) }, }; std::vector< uint64_t > l_ranks; FAPI_TRY( mss::ranks(i_target, l_ranks) ); - - // Calculate tDLLK from our frequency. Magic numbers (in clocks) from the DDR4 spec - FAPI_TRY( mss::freq(mss::find_target<TARGET_TYPE_MCBIST>(i_target), l_freq) ); - tDLLK = (l_freq < fapi2::ENUM_ATTR_MSS_FREQ_MT2133) ? 597 : 768; + FAPI_TRY( mss::tdllk(i_target, tDLLK) ); // Load MRS for (const auto& d : l_mrs_data) @@ -141,9 +137,9 @@ fapi2::ReturnCode mrs_load( const fapi2::Target<TARGET_TYPE_DIMM>& i_target, l_inst_b_side = mss::address_invert(l_inst_a_side); l_inst_a_side.arr1.insertFromRight<MCBIST_CCS_INST_ARR1_00_IDLES, - MCBIST_CCS_INST_ARR1_00_IDLES_LEN>(tDLLK + tZQinit); + MCBIST_CCS_INST_ARR1_00_IDLES_LEN>(tDLLK + mss::tzqinit()); l_inst_b_side.arr1.insertFromRight<MCBIST_CCS_INST_ARR1_00_IDLES, - MCBIST_CCS_INST_ARR1_00_IDLES_LEN>(tDLLK + tZQinit); + MCBIST_CCS_INST_ARR1_00_IDLES_LEN>(tDLLK + mss::tzqinit()); // There's nothing to decode here. FAPI_INF("ZQCL 0x%016llx:0x%016llx %s:rank %d a-side", diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rcd_load_ddr4.C b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rcd_load_ddr4.C index ef7f77392..a1f57e489 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rcd_load_ddr4.C +++ b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rcd_load_ddr4.C @@ -59,28 +59,29 @@ fapi2::ReturnCode rcd_load_ddr4( const fapi2::Target<TARGET_TYPE_DIMM>& i_target { FAPI_INF("rcd_load_ddr4 %s", mss::c_str(i_target)); - // Per DDR4RCD02 table 104 - timing requirements - static const uint64_t tMRD = 8; - static const uint64_t tMRD_L = 16; - - // Per DDR4RCD02, tSTAB is 5us. We want this in cycles for the CCS. - const uint64_t tSTAB = mss::us_to_cycles(i_target, 5); + // Per DDR4RCD02, tSTAB is us. We want this in cycles for the CCS. + const uint64_t tSTAB = mss::us_to_cycles(i_target, mss::tstab()); static std::vector< rcd_data > l_rcd_4bit_data = { - { 0, eff_dimm_ddr4_rc00, tMRD }, { 1, eff_dimm_ddr4_rc01, tMRD }, { 2, eff_dimm_ddr4_rc02, tSTAB }, - { 3, eff_dimm_ddr4_rc03, tMRD_L}, { 4, eff_dimm_ddr4_rc04, tMRD_L}, { 5, eff_dimm_ddr4_rc05, tMRD_L}, - { 6, eff_dimm_ddr4_rc06_07, tMRD }, { 8, eff_dimm_ddr4_rc08, tMRD }, { 9, eff_dimm_ddr4_rc09, tMRD }, - { 10, eff_dimm_ddr4_rc10, tSTAB }, { 11, eff_dimm_ddr4_rc11, tMRD }, { 12, eff_dimm_ddr4_rc12, tMRD }, - { 13, eff_dimm_ddr4_rc13, tMRD }, { 14, eff_dimm_ddr4_rc14, tMRD }, { 15, eff_dimm_ddr4_rc15, tMRD }, + { 0, eff_dimm_ddr4_rc00, mss::tmrd() }, { 1, eff_dimm_ddr4_rc01, mss::tmrd() }, + { 2, eff_dimm_ddr4_rc02, tSTAB }, { 3, eff_dimm_ddr4_rc03, mss::tmrd_l() }, + { 4, eff_dimm_ddr4_rc04, mss::tmrd_l() }, { 5, eff_dimm_ddr4_rc05, mss::tmrd_l() }, + { 6, eff_dimm_ddr4_rc06_07, mss::tmrd() }, { 8, eff_dimm_ddr4_rc08, mss::tmrd() }, + { 9, eff_dimm_ddr4_rc09, mss::tmrd() }, { 10, eff_dimm_ddr4_rc10, tSTAB }, + { 11, eff_dimm_ddr4_rc11, mss::tmrd() }, { 12, eff_dimm_ddr4_rc12, mss::tmrd() }, + { 13, eff_dimm_ddr4_rc13, mss::tmrd() }, { 14, eff_dimm_ddr4_rc14, mss::tmrd() }, + { 15, eff_dimm_ddr4_rc15, mss::tmrd() }, }; static std::vector< rcd_data > l_rcd_8bit_data = { - { 1, eff_dimm_ddr4_rc_1x, tMRD }, { 2, eff_dimm_ddr4_rc_2x, tMRD }, { 3, eff_dimm_ddr4_rc_3x, tSTAB }, - { 4, eff_dimm_ddr4_rc_4x, tMRD }, { 5, eff_dimm_ddr4_rc_5x, tMRD }, { 6, eff_dimm_ddr4_rc_6x, tMRD }, - { 7, eff_dimm_ddr4_rc_7x, tMRD }, { 8, eff_dimm_ddr4_rc_8x, tMRD }, { 9, eff_dimm_ddr4_rc_9x, tMRD }, - { 10, eff_dimm_ddr4_rc_ax, tMRD }, { 11, eff_dimm_ddr4_rc_bx, tMRD_L} + { 1, eff_dimm_ddr4_rc_1x, mss::tmrd() }, { 2, eff_dimm_ddr4_rc_2x, mss::tmrd() }, + { 3, eff_dimm_ddr4_rc_3x, tSTAB }, { 4, eff_dimm_ddr4_rc_4x, mss::tmrd() }, + { 5, eff_dimm_ddr4_rc_5x, mss::tmrd() }, { 6, eff_dimm_ddr4_rc_6x, mss::tmrd() }, + { 7, eff_dimm_ddr4_rc_7x, mss::tmrd() }, { 8, eff_dimm_ddr4_rc_8x, mss::tmrd() }, + { 9, eff_dimm_ddr4_rc_9x, mss::tmrd() }, { 10, eff_dimm_ddr4_rc_ax, mss::tmrd() }, + { 11, eff_dimm_ddr4_rc_bx, mss::tmrd_l() } }; fapi2::buffer<uint8_t> l_value; 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 894205480..88024e7a0 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 @@ -145,6 +145,7 @@ fapi_try_exit: return fapi2::current_err; } +/// /// @brief Calculates refresh interval time /// @param[in] i_mode fine refresh rate mode /// @param[in] i_temp_refresh_range temperature refresh range @@ -155,6 +156,7 @@ fapi2::ReturnCode calc_trefi( const refresh_rate i_mode, const uint8_t i_temp_refresh_range, int64_t& o_timing ); +/// /// @brief Calculates Minimum Refresh Recovery Delay Time (different logical rank) /// @param[in] i_mode fine refresh rate mode /// @param[in] i_density SDRAM density @@ -165,5 +167,204 @@ fapi2::ReturnCode calc_trfc_dlr( const uint8_t i_refresh_mode, const uint8_t i_density, uint64_t& o_trfc_in_ps ); +/// +/// @brief DLL locking time +/// @tparam T the fapi2::TargetType of i_target +/// @tparam OT the type of the output location +/// @param[in] i_target a target for attributes +/// @param[out] o_value reference to space into which to store the output +/// @return fapi2::FAPI2_RC_SUCCESS iff okay +/// +template< fapi2::TargetType T, typename OT = uint64_t > +inline fapi2::ReturnCode tdllk( const fapi2::Target<T>& i_target, OT& o_value ) +{ + uint64_t l_freq = 0; + + // Calculate tDLLK from our MT/s. Magic numbers (in clocks) from the DDR4 spec + FAPI_TRY( mss::freq(mss::find_target<fapi2::TARGET_TYPE_MCBIST>(i_target), l_freq) ); + o_value = (l_freq < fapi2::ENUM_ATTR_MSS_FREQ_MT2133) ? 597 : 768; + return fapi2::FAPI2_RC_SUCCESS; + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Mode Register Set Command Cycle Time +/// @return constexpr value of 8 clocks +/// +constexpr uint64_t tmrd() +{ + // Per DDR4 Full spec update (79-4A) - timing requirements + return 8; +} + +/// +/// @brief Control word to control word delay +/// @return constexpr value of 16 clocks +/// +constexpr uint64_t tmrd_l() +{ + // Per DDR4RCD02 Spec Rev 0.85 + return 16; +} + +/// +/// @brief Stabilization time +/// @return constexpr value of 5 us +/// +constexpr uint64_t tstab() +{ + // Per DDR4RCD02 Spec Rev 0.85 CK_t stable + return 5; +} + +/// +/// @brief Power-up and RESET calibration time +/// @return constexpr value of 1024 clocks +/// +constexpr uint64_t tzqinit() +{ + // Per DDR4 Full spec update (79-4A) - timing requirements + return 1024; +} + +/// +/// @brief Normal operation Full calibration time +/// @return constexpr value of 512 clocks +/// +constexpr uint64_t tzqoper() +{ + // Per DDR4 Full spec update (79-4A) - timing requirements + return 512; +} + +/// +/// @brief Normal operation Short calibration time +/// @return constexpr value of 128 clocks +/// +constexpr uint64_t tzqcs() +{ + // Per DDR4 Full spec update (79-4A) - timing requirements + return 128; +} + +/// +/// @brief DQS_t/DQS_n delay after write leveling mode is programmed +/// @return constexpr value of 25 clocks +/// +constexpr uint64_t twldqsen() +{ + // Per DDR4 Full spec update (79-4A) - timing requirements + return 25; +} + +/// +/// @brief First DQS_t/DQS_n rising edge after write leveling mode is programmed +/// @return constexpr value of 40 clocks +/// +constexpr uint64_t twlmrd() +{ + // Per DDR4 Full spec update (79-4A) - timing requirements + return 40; +} + +/// +/// @brief Calculate TWLO_TWLOE +/// @tparam T fapi2::TargetType of the target used to calculate cycles from ns +/// @param[in] i_target the target used to get DIMM clocks +/// @return uint64_t, TWLO_TWLOE in cycles +/// +template< fapi2::TargetType T > +inline uint64_t twlo_twloe(const fapi2::Target<T>& i_target) +{ + return 12 + mss::ns_to_cycles(i_target, tWLO - tWLOE); +} + +/// +/// @brief Mode Register Set command update delay +/// @tparam T fapi2::TargetType of the target used to calculate cycles from ns +/// @param[in] i_target the target used to get clocks +/// @return max(24nCK,15ns) in clocks +/// +template< fapi2::TargetType T > +inline uint64_t tmod( const fapi2::Target<T>& i_target ) +{ + // Per DDR4 Full spec update (79-4A) - timing requirements + return mss::max_ck_ns( i_target, 24, 15 ); +} + +/// +/// @brief Refresh cycle time +/// @param[in] i_target the DIMM target used to get clocks (needed to know the stack type) +/// @param[out] o_trfc the trfc *in clocks* +/// @return FAPI2_RC_SUCCESS iff ok +/// +inline fapi2::ReturnCode trfc( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target, uint16_t& o_trfc ) +{ + // Pull down the 3DS attribute. If we have a stack we need to use + // tRFC_DLR if not we pull down TRFC and use that. + uint8_t l_stack = 0; + + FAPI_TRY( mss::eff_prim_stack_type(i_target, l_stack) ); + + if (l_stack == fapi2::ENUM_ATTR_EFF_PRIM_STACK_TYPE_3DS) + { + uint8_t l_value = 0; + FAPI_TRY( mss::eff_dram_trfc_dlr(i_target, l_value) ); + o_trfc = l_value; + } + else + { + FAPI_TRY( mss::eff_dram_trfc(i_target, o_trfc) ); + } + + return fapi2::FAPI2_RC_SUCCESS; + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Direct ODT turn on Latency +/// @param[in] i_target the DIMM target used to get attributes +/// @param[out] o_dodt *in clocks* +/// @return FAPI2_RC_SUCCESS iff ok +/// +inline fapi2::ReturnCode dodt_on( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target, uint8_t& o_dodt ) +{ + // CWL + AL + PL - 2.0 per DDR4 Full spec update(79-4B) + + uint8_t l_ca_parity_latency = 0; + uint8_t l_al = 0; + uint8_t l_cwl = 0; + + FAPI_TRY( mss::eff_ca_parity_latency(i_target, l_ca_parity_latency) ); + FAPI_TRY( mss::eff_dram_al(i_target, l_al) ); + FAPI_TRY( mss::eff_dram_cwl(i_target, l_cwl) ); + + o_dodt = l_cwl + l_al + l_ca_parity_latency - 2; + return fapi2::FAPI2_RC_SUCCESS; + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Direct ODT turn off Latency +/// @param[in] i_target the DIMM target used to get attributes +/// @param[out] o_dodt *in clocks* +/// @return FAPI2_RC_SUCCESS iff ok +/// +inline fapi2::ReturnCode dodt_off( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target, uint8_t& o_dodt ) +{ + // Same for all frequencies of DDR4; DDR4 Full spec update(79-4B) + return dodt_on(i_target, o_dodt); +} + +// TK RODTon - The use would be for the ODT in the PHY, but the max RODT is equal to or less than +// the max DODTon/off so it would really never be used anyway there anyway. We can implement it if +// we find another need for it. + } // mss #endif diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/phy/cal_timers.H b/src/import/chips/p9/procedures/hwp/memory/lib/phy/cal_timers.H index e2b2e316a..898154c93 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/phy/cal_timers.H +++ b/src/import/chips/p9/procedures/hwp/memory/lib/phy/cal_timers.H @@ -38,7 +38,7 @@ #include <fapi2.H> #include <lib/shared/mss_const.H> -#include <lib/utils/conversions.H> +#include <lib/eff_config/timing.H> #include <lib/utils/poll.H> namespace mss diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/phy/ddr_phy.C b/src/import/chips/p9/procedures/hwp/memory/lib/phy/ddr_phy.C index 0333ed464..78dbc776e 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/phy/ddr_phy.C +++ b/src/import/chips/p9/procedures/hwp/memory/lib/phy/ddr_phy.C @@ -188,15 +188,14 @@ fapi_try_exit: fapi2::ReturnCode setup_phase_rotator_control_registers( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target, const states i_state ) { - uint8_t is_sim = 0; + // From the DDR PHY workbook + constexpr uint64_t CONTINUOUS_UPDATE = 0x8004; + constexpr uint64_t SIM_OVERRIDE = 0x8080; + constexpr uint64_t PHASE_CNTL_EN = 0x8020; - // Per Bialas, we don't want to do true alignment in the cycle sim as we have - // a chance of being off one-tick (which is detrimental.) Per his recomendations, - // we write 0's to the control registers and then configure them with 0x8080. We'll - // over write l_update's values with a getScom to the correct h/w initiialized values - // if we're not in sim + uint8_t is_sim = 0; - fapi2::buffer<uint64_t> l_update( i_state == mss::ON ? 0x0 : 0x8080 ); + fapi2::buffer<uint64_t> l_update( i_state == mss::ON ? CONTINUOUS_UPDATE : PHASE_CNTL_EN ); const auto l_mca = find_targets<TARGET_TYPE_MCA>(i_target); std::vector<uint64_t> addrs( @@ -212,15 +211,17 @@ fapi2::ReturnCode setup_phase_rotator_control_registers( const fapi2::Target<TAR FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_IS_SIMULATION, fapi2::Target<TARGET_TYPE_SYSTEM>(), is_sim) ); - if (! is_sim) + if (is_sim) { - // All the MCA (and both registers) will be in the same state, so we can get the first and use it to create the - // values for the others. - FAPI_TRY( mss::getScom(l_mca[0], MCA_DDRPHY_ADR_SYSCLK_CNTL_PR_P0_ADR32S0, l_update) ); - l_update.setBit<MCA_DDRPHY_ADR_SYSCLK_CNTL_PR_P0_ADR32S0_ADR0_PHASE_EN>(); - l_update.writeBit<MCA_DDRPHY_ADR_SYSCLK_CNTL_PR_P0_ADR32S0_ADR0_CONTINUOUS_UPDATE>(i_state); + // Per Bialas, we don't want to do true alignment in the cycle sim as we have + // a chance of being off one-tick (which is detrimental.) Per his recomendations, + // we write 0's to the control registers and then configure them with 0x8080. + l_update = (i_state == mss::ON) ? 0x0 : SIM_OVERRIDE; } + // All the MCA (and both registers) will be in the same state, so we can get the first and use it to create the + // values for the others. + FAPI_INF("Write 0x%lx into the ADR SysClk Phase Rotator Control Regs", l_update); // WRCLK Phase rotators are taken care of in the phy initfile. BRS 6/16. @@ -734,6 +735,7 @@ fapi2::ReturnCode setup_cal_config( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& { fapi2::buffer<uint64_t> l_cal_config; fapi2::buffer<uint64_t> l_vref_config; + uint8_t is_sim = 0; // This is the buffer which will be written to CAL_CONFIG0. It starts // life assuming no cal sequences, no rank pairs - but we set the abort-on-error @@ -747,6 +749,8 @@ fapi2::ReturnCode setup_cal_config( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_cal_steps_enabled.clearBit<WRITE_CTR>(); } + FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_IS_SIMULATION, fapi2::Target<TARGET_TYPE_SYSTEM>(), is_sim) ); + // Sadly, the bits in the register don't align directly with the bits in the attribute. // So, arrange the bits accordingly and write the config register. { @@ -766,6 +770,12 @@ fapi2::ReturnCode setup_cal_config( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_cal_steps_enabled.getBit<COARSE_WR>()); l_cal_config.writeBit<MCA_DDRPHY_PC_INIT_CAL_CONFIG0_P0_ENA_COARSE_RD>( i_cal_steps_enabled.getBit<COARSE_RD>()); + + // Always turn on initial pattern write in h/w, never for sim (makes the DIMM behavioral lose it's mind) + if (!is_sim) + { + l_cal_config.setBit<MCA_DDRPHY_PC_INIT_CAL_CONFIG0_P0_ENA_INITIAL_PAT_WR>(); + } } // Blast the VREF config with the proper setting for these cal bits. diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/phy/read_cntrl.H b/src/import/chips/p9/procedures/hwp/memory/lib/phy/read_cntrl.H index cadca6a20..58e638ae7 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/phy/read_cntrl.H +++ b/src/import/chips/p9/procedures/hwp/memory/lib/phy/read_cntrl.H @@ -390,12 +390,10 @@ template< fapi2::TargetType T, typename TT = rcTraits<T> > inline fapi2::ReturnCode reset_config3( const fapi2::Target<T>& i_target ) { fapi2::buffer<uint64_t> l_data; - uint8_t is_sim = 0; - FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_IS_SIMULATION, fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), is_sim) ); - // 51:54, 0b1010, (def_is_sim); # COARSE_CAL_STEP_SIZE» # old=4=5/128 (5/18) - // 51:54, 0b0000, any; # COARSE_CAL_STEP_SIZE = 1/128 - l_data.insertFromRight<TT::COARSE_CAL_STEP_SIZE, TT::COARSE_CAL_STEP_SIZE_LEN>(is_sim ? 0b1010 : 0b0000); + // Per S. Wyatt 8/16: COARSE_CAL_STEP_SIZE='1010'b [Centaur sim value] is reserved. + // Change to COARSE_CAL_STEP_SIZE='0100' + l_data.insertFromRight<TT::COARSE_CAL_STEP_SIZE, TT::COARSE_CAL_STEP_SIZE_LEN>(0b0100); FAPI_TRY( write_config3(i_target, l_data) ); diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/phy/write_cntrl.H b/src/import/chips/p9/procedures/hwp/memory/lib/phy/write_cntrl.H index 2b1a9084e..26cc5e564 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/phy/write_cntrl.H +++ b/src/import/chips/p9/procedures/hwp/memory/lib/phy/write_cntrl.H @@ -39,7 +39,7 @@ #include <fapi2.H> #include <p9_mc_scom_addresses.H> #include <lib/utils/scom.H> -#include <lib/utils/conversions.H> +#include <lib/eff_config/timing.H> namespace mss { diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/termination/slew_cal.C b/src/import/chips/p9/procedures/hwp/memory/lib/termination/slew_cal.C deleted file mode 100644 index f62f8b920..000000000 --- a/src/import/chips/p9/procedures/hwp/memory/lib/termination/slew_cal.C +++ /dev/null @@ -1,503 +0,0 @@ -/* IBM_PROLOG_BEGIN_TAG */ -/* This is an automatically generated prolog. */ -/* */ -/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/termination/slew_cal.C $ */ -/* */ -/* OpenPOWER HostBoot Project */ -/* */ -/* Contributors Listed Below - COPYRIGHT 2015,2016 */ -/* [+] International Business Machines Corp. */ -/* */ -/* */ -/* Licensed under the Apache License, Version 2.0 (the "License"); */ -/* you may not use this file except in compliance with the License. */ -/* You may obtain a copy of the License at */ -/* */ -/* http://www.apache.org/licenses/LICENSE-2.0 */ -/* */ -/* Unless required by applicable law or agreed to in writing, software */ -/* distributed under the License is distributed on an "AS IS" BASIS, */ -/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ -/* implied. See the License for the specific language governing */ -/* permissions and limitations under the License. */ -/* */ -/* IBM_PROLOG_END_TAG */ -/// -/// @file slew_cal.C -/// @brief * This function runs the slew calibration engine to configure MSS_SLEW_DATA/ADR -/// attributes and calls config_slew_rate to set the slew rate in the registers. -/// -// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com> -// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com> -// *HWP Team: Memory -// *HWP Level: 2 -// *HWP Consumed by: FSP:HB - -#include <fapi2.H> - -#include <mss.H> -#include <lib/termination/slew_cal.H> - -using fapi2::TARGET_TYPE_MCBIST; -using fapi2::TARGET_TYPE_MCA; -using fapi2::TARGET_TYPE_MCS; -using fapi2::TARGET_TYPE_SYSTEM; - -using fapi2::TARGET_STATE_FUNCTIONAL; - -using fapi2::FAPI2_RC_SUCCESS; - -// slew calibration control register - -static const uint64_t slew_cal_cntl[] = -{ - MCA_0_DDRPHY_ADR_SLEW_CAL_CNTL_P0_ADR32S0, - MCA_1_DDRPHY_ADR_SLEW_CAL_CNTL_P1_ADR32S0, - MCA_2_DDRPHY_ADR_SLEW_CAL_CNTL_P2_ADR32S0, - MCA_3_DDRPHY_ADR_SLEW_CAL_CNTL_P3_ADR32S0, -}; -// slew calibration status registers -static const uint64_t ENABLE_BIT = 48; -static const uint64_t slew_cal_stat[] = -{ - MCA_0_DDRPHY_ADR_SYSCLK_CNTL_PR_P0_ADR32S0, - MCA_1_DDRPHY_ADR_SYSCLK_CNTL_PR_P1_ADR32S0, - MCA_2_DDRPHY_ADR_SYSCLK_CNTL_PR_P2_ADR32S0, - MCA_3_DDRPHY_ADR_SYSCLK_CNTL_PR_P3_ADR32S0, -}; - -// big bang lock bit register -static const uint64_t bb_lock_stat[] = -{ - MCA_0_DDRPHY_ADR_SYSCLK_PR_VALUE_RO_P0_ADR32S0, - MCA_1_DDRPHY_ADR_SYSCLK_PR_VALUE_RO_P1_ADR32S0, - MCA_2_DDRPHY_ADR_SYSCLK_PR_VALUE_RO_P2_ADR32S0, - MCA_3_DDRPHY_ADR_SYSCLK_PR_VALUE_RO_P3_ADR32S0, -}; - -namespace mss -{ - -/// -/// @brief perform the slew calibration, store the result. -/// @tparam T the type of the slew table -/// @param[in] i_target MCA (port) target -/// @param[in] l_table a vector of the steps which came before me -/// @param[in] o_cal_slew the slew table to be operated on -/// @param[out] the array holding the results -/// @return FAPI2_RC_SUCCESS, iff ok -/// -template<typename T> -fapi2::ReturnCode perform_slew_cal( - const fapi2::Target<TARGET_TYPE_MCA>& i_target, - std::vector<tags_t>& i_where_am_i, T& l_table, - uint8_t (&o_cal_slew)[2][PORTS_PER_MCS][MAX_NUM_IMP][MAX_NUM_CAL_SLEW_RATES]) -{ - i_where_am_i.push_back(l_table.first); - - for (auto e : l_table.second) - { - FAPI_TRY( perform_slew_cal(i_target, i_where_am_i, e, o_cal_slew) ); - } - - i_where_am_i.pop_back(); - -fapi_try_exit: - return fapi2::current_err; -} - -/// -/// @brief perform the slew calibration, store the result. -/// @param[in] i_target MCA (port) target -/// @param[in] i_where_am_i a vector of the steps which came before me -/// @param[in] a slew_table_t -/// @param[out] the array holding the results -/// @bote Prunes recursion based on frequency. -/// @return FAPI2_RC_SUCCESS, iff ok -/// -template<> -fapi2::ReturnCode perform_slew_cal( - const fapi2::Target<TARGET_TYPE_MCA>& i_target, - std::vector<tags_t>& i_where_am_i, - std::pair<tags_t, slew_per_imp_t>& l_table, - uint8_t (&o_cal_slew)[2][PORTS_PER_MCS][MAX_NUM_IMP][MAX_NUM_CAL_SLEW_RATES]) -{ - uint64_t ddr_freq = 0; - const char* l_type = i_where_am_i[0] == TAG_ADR ? "adr" : "data"; - - // Check our speed. If this isn't our speed, we can get out of here. - FAPI_TRY( mss::freq(i_target.getParent<TARGET_TYPE_MCBIST>(), ddr_freq), - "Unable to get ddr freq for %s", mss::c_str(i_target) ); - - if (ddr_freq != l_table.first) - { - FAPI_DBG("Skipping slew %s for %s: invalid speed %d(%d)", - l_type, mss::c_str(i_target), l_table.first, ddr_freq); - return FAPI2_RC_SUCCESS; - } - - i_where_am_i.push_back(l_table.first); - - for (auto e : l_table.second) - { - FAPI_TRY( perform_slew_cal(i_target, i_where_am_i, e, o_cal_slew) ); - } - - i_where_am_i.pop_back(); - -fapi_try_exit: - return fapi2::current_err; -} - -/// -/// @brief perform the slew calibration, store the result. -/// @param[in] i_target MCA (port) target -/// @param[in] i_where_am_i a vector of the steps which came before me -/// @param[in] l_slew_rate the slew rate to be calculated -/// @param[out] the array holding the results -/// @return FAPI2_RC_SUCCESS, iff ok -/// -template<> -fapi2::ReturnCode perform_slew_cal<slew_rate_t>( - const fapi2::Target<TARGET_TYPE_MCA>& i_target, - std::vector<tags_t>& i_where_am_i, - slew_rate_t& l_slew_rate, - uint8_t (&o_cal_slew)[2][PORTS_PER_MCS][MAX_NUM_IMP][MAX_NUM_CAL_SLEW_RATES]) -{ - i_where_am_i.push_back(l_slew_rate.first); - - fapi2::buffer<uint64_t> l_data; - - // Some short-hand for this calibration - const char* l_type = i_where_am_i[0] == TAG_ADR ? "adr" : "data"; - const uint64_t& l_speed = i_where_am_i[1]; - const uint64_t& l_ohm = i_where_am_i[2]; - const uint64_t& l_vns = i_where_am_i[3]; - - uint64_t cal_status = 0; - fapi2::buffer<uint64_t> status_register; - uint64_t calculated_slew = 0; - - FAPI_INF("Processing slew %s, %dmhz %dohm %dV/ns: %d", l_type, l_speed, l_ohm, l_vns, l_slew_rate.second); - -#ifdef NOT_TESTING_WITH_SUET - // Get out of here if we're in the simulator. Calibration fails in sim since bb_lock not possible in cycle - // simulator, putting initial to be cal'd value in output table - uint8_t is_sim = 0; - FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_IS_SIMULATION, fapi2::Target<TARGET_TYPE_SYSTEM>(), is_sim) ); - - if (is_sim) - { - FAPI_INF("In SIM setting input slew value in array"); - calculated_slew = l_slew_rate.second; - goto perform_slew_cal_exit; - } - -#endif - - // This doesn't look right. There are 5 bits, but some of our values (134) are 8 bits. So, the - // left-most bits are truncated. Note this is the same in P8, it seems - this needs to be looked at BRS - l_data.insertFromRight<MCA_DDRPHY_ADR_SLEW_CAL_CNTL_P0_ADR32S0_ADR0_TARGET_PR_OFFSET, - MCA_DDRPHY_ADR_SLEW_CAL_CNTL_P0_ADR32S0_ADR0_TARGET_PR_OFFSET_LEN>(l_slew_rate.second); - l_data.setBit<MCA_DDRPHY_ADR_SLEW_CAL_CNTL_P0_ADR32S0_ADR0_START>(); - - FAPI_TRY( mss::putScom(i_target, MCA_DDRPHY_ADR_SLEW_CAL_CNTL_P0_ADR32S0, l_data) ); - - mss::poll( i_target, MCA_DDRPHY_ADR_SYSCLK_PR_VALUE_RO_P0_ADR32S0, mss::poll_parameters(DELAY_100NS), - [&](const size_t poll_remaining, const fapi2::buffer<uint64_t>& stat_reg) -> bool - { - // Save off our claibration status - status_register = stat_reg; - stat_reg.extractToRight<MCA_DDRPHY_ADR_SYSCLK_PR_VALUE_RO_P0_ADR32S0_ADR0_SLEW_DONE_STATUS, - MCA_DDRPHY_ADR_SYSCLK_PR_VALUE_RO_P0_ADR32S0_ADR0_SLEW_DONE_STATUS_LEN>(cal_status); - FAPI_DBG("slew calibration status 0x%llx, remaining: %d", cal_status, poll_remaining); - return cal_status != SLEW_CAL_NOT_DONE; - }); - - // This will kick us out if there's no further processing we can do. - FAPI_TRY( slew_cal_status(i_target, i_where_am_i, l_slew_rate.second, cal_status, status_register) ); - - // Get our calculated slew rate and process. - FAPI_TRY( mss::getScom(i_target, MCA_DDRPHY_ADR_SLEW_CAL_CNTL_P0_ADR32S0, l_data) ); - l_data.extractToRight<MCA_DDRPHY_ADR_SLEW_CAL_CNTL_P0_ADR32S0_ADR0_TARGET_PR_OFFSET, - MCA_DDRPHY_ADR_SLEW_CAL_CNTL_P0_ADR32S0_ADR0_TARGET_PR_OFFSET_LEN>(calculated_slew); - -#ifdef NOT_TESTING_WITH_SUET -perform_slew_cal_exit: -#endif - FAPI_DBG("MSS_SLEW_RATE %s port %d %dohm slew 0x%lx(0x%lx)", - l_type, mss::pos(i_target), l_ohm, calculated_slew, uint64_t(status_register)); - - o_cal_slew[i_where_am_i[0]] // adr/data - [mss::index(i_target)] // port - [mss::index(i_where_am_i[0], i_where_am_i[2])] // imp - [mss::index(i_where_am_i[0], i_where_am_i[3])] = calculated_slew; - - i_where_am_i.pop_back(); - - return FAPI2_RC_SUCCESS; - -fapi_try_exit: - return fapi2::current_err; -} - - -/// -/// @brief Run the slew calibration engine -/// @param[in] i_target the MCBIST -/// @return FAPI2_RC_SUCCESS iff OK -/// -fapi2::ReturnCode slew_cal(const fapi2::Target<TARGET_TYPE_MCBIST>& i_target) -{ - // freq index into lookup table. Fixed at 3 right now as we don't support - // dimm slower than 1866 - without more work below. - static const uint8_t freq_idx = 3; - - // current ddr freq - uint64_t ddr_freq = 0; - - // ddr type index into lookup table - // We only have one entry in the table right now, so this is fixed. - static const uint8_t ddr_idx = 0; - - // ATTR_EFF_DRAM_GEN{0=invalid, 1=ddr3, 2=ddr4} - // p9n only supprts ddr4 right now. So, fixed - static const uint8_t ddr_type = 2; - - fapi2::buffer<uint64_t> ctl_reg; - fapi2::buffer<uint64_t> stat_reg; - - // DD level 1.0-1.1, Version 1.0 - // [ddr3/4][dq/adr][speed][impedance][slew_rate] - // note: Assumes standard voltage for DDR3(1.35V), DDR4(1.2V), - // little endian, if >=128, lab only debug. - // - // ddr_type(1), ddr4=0 - // data/adr(2)data(dq/dqs)=0, adr(cmd/cntl)=1 - // speed(4)1066=0, 1333=1, 1600=2, 1866=3 - // imped(4)24ohms=0, 30ohms=1, 34ohms=2, 40ohms=3 for DQ/DQS - // imped(4)15ohms=0, 20ohms=1, 30ohms=2, 40ohms=3 for ADR driver - // slew(3)3V/ns=0, 4V/ns=1, 5V/ns=2, 6V/ns=3 - - // Too many in here for real-world. But this allows us to test out the - // logic to make sure we're in good shape as we add to this table. We - // can redice this table before flight BRS. - std::vector< std::pair< tags_t, slew_table_t> > slew_table = - { - { - TAG_ADR, { - { - TAG_1066MHZ, - { - { TAG_15OHM, {{TAG_3VNS, 142}, {TAG_4VNS, 139}, {TAG_5VNS, 136}, {TAG_6VNS, 134}} }, - { TAG_20OHM, {{TAG_3VNS, 140}, {TAG_4VNS, 136}, {TAG_5VNS, 134}, {TAG_6VNS, 133}} }, - { TAG_30OHM, {{TAG_3VNS, 138}, {TAG_4VNS, 134}, {TAG_5VNS, 131}, {TAG_6VNS, 131}} }, - { TAG_40OHM, {{TAG_3VNS, 133}, {TAG_4VNS, 131}, {TAG_5VNS, 131}, {TAG_6VNS, 131}} }, - } - }, - - - { - TAG_1333MHZ, - { - { TAG_15OHM, {{TAG_3VNS, 145}, {TAG_4VNS, 142}, {TAG_5VNS, 139}, {TAG_6VNS, 136}} }, - { TAG_20OHM, {{TAG_3VNS, 143}, {TAG_4VNS, 138}, {TAG_5VNS, 135}, {TAG_6VNS, 134}} }, - { TAG_30OHM, {{TAG_3VNS, 140}, {TAG_4VNS, 135}, {TAG_5VNS, 132}, {TAG_6VNS, 132}} }, - { TAG_40OHM, {{TAG_3VNS, 134}, {TAG_4VNS, 132}, {TAG_5VNS, 132}, {TAG_6VNS, 132}} }, - } - }, - - - { - TAG_1600MHZ, - { - { TAG_15OHM, {{TAG_3VNS, 21}, {TAG_4VNS, 16}, {TAG_5VNS, 13}, {TAG_6VNS, 10}} }, - { TAG_20OHM, {{TAG_3VNS, 18}, {TAG_4VNS, 12}, {TAG_5VNS, 9}, {TAG_6VNS, 135}} }, - { TAG_30OHM, {{TAG_3VNS, 15}, {TAG_4VNS, 8}, {TAG_5VNS, 133}, {TAG_6VNS, 133}} }, - { TAG_40OHM, {{TAG_3VNS, 7}, {TAG_4VNS, 133}, {TAG_5VNS, 133}, {TAG_6VNS, 133}} }, - } - }, - - - { - TAG_1866MHZ, - { - { TAG_15OHM, {{TAG_3VNS, 24}, {TAG_4VNS, 19}, {TAG_5VNS, 15}, {TAG_6VNS, 11}} }, - { TAG_20OHM, {{TAG_3VNS, 21}, {TAG_4VNS, 14}, {TAG_5VNS, 10}, {TAG_6VNS, 136}} }, - { TAG_30OHM, {{TAG_3VNS, 17}, {TAG_4VNS, 10}, {TAG_5VNS, 134}, {TAG_6VNS, 134}} }, - { TAG_40OHM, {{TAG_3VNS, 9}, {TAG_4VNS, 134}, {TAG_5VNS, 134}, {TAG_6VNS, 134}} }, - } - }, - - { - TAG_2400MHZ, - { - { TAG_15OHM, {{TAG_3VNS, 24}, {TAG_4VNS, 19}, {TAG_5VNS, 15}, {TAG_6VNS, 11}} }, - { TAG_20OHM, {{TAG_3VNS, 21}, {TAG_4VNS, 14}, {TAG_5VNS, 10}, {TAG_6VNS, 136}} }, - { TAG_30OHM, {{TAG_3VNS, 17}, {TAG_4VNS, 10}, {TAG_5VNS, 134}, {TAG_6VNS, 134}} }, - { TAG_40OHM, {{TAG_3VNS, 9}, {TAG_4VNS, 134}, {TAG_5VNS, 134}, {TAG_6VNS, 134}} }, - } - }, - - }, - }, - - { - TAG_DATA, { - { - TAG_1066MHZ, - { - { TAG_24OHM, {{TAG_3VNS, 138}, {TAG_4VNS, 135}, {TAG_5VNS, 134}, {TAG_6VNS, 133}} }, - { TAG_30OHM, {{TAG_3VNS, 139}, {TAG_4VNS, 136}, {TAG_5VNS, 134}, {TAG_6VNS, 132}} }, - { TAG_34OHM, {{TAG_3VNS, 140}, {TAG_4VNS, 136}, {TAG_5VNS, 135}, {TAG_6VNS, 133}} }, - { TAG_40OHM, {{TAG_3VNS, 140}, {TAG_4VNS, 136}, {TAG_5VNS, 132}, {TAG_6VNS, 132}} }, - } - }, - - { - TAG_1333MHZ, - { - { TAG_24OHM, {{TAG_3VNS, 139}, {TAG_4VNS, 137}, {TAG_5VNS, 135}, {TAG_6VNS, 134}} }, - { TAG_30OHM, {{TAG_3VNS, 142}, {TAG_4VNS, 138}, {TAG_5VNS, 135}, {TAG_6VNS, 133}} }, - { TAG_34OHM, {{TAG_3VNS, 143}, {TAG_4VNS, 138}, {TAG_5VNS, 135}, {TAG_6VNS, 133}} }, - { TAG_40OHM, {{TAG_3VNS, 143}, {TAG_4VNS, 138}, {TAG_5VNS, 133}, {TAG_6VNS, 132}} }, - } - }, - - { - TAG_1600MHZ, - { - { TAG_24OHM, {{TAG_3VNS, 15}, {TAG_4VNS, 11}, {TAG_5VNS, 9}, {TAG_6VNS, 135}} }, - { TAG_30OHM, {{TAG_3VNS, 17}, {TAG_4VNS, 11}, {TAG_5VNS, 9}, {TAG_6VNS, 135}} }, - { TAG_34OHM, {{TAG_3VNS, 18}, {TAG_4VNS, 13}, {TAG_5VNS, 9}, {TAG_6VNS, 134}} }, - { TAG_40OHM, {{TAG_3VNS, 18}, {TAG_4VNS, 11}, {TAG_5VNS, 6}, {TAG_6VNS, 133}} }, - } - }, - - - { - TAG_1866MHZ, - { - { TAG_24OHM, {{TAG_3VNS, 18}, {TAG_4VNS, 13}, {TAG_5VNS, 10}, {TAG_6VNS, 137}} }, - { TAG_30OHM, {{TAG_3VNS, 19}, {TAG_4VNS, 13}, {TAG_5VNS, 10}, {TAG_6VNS, 136}} }, - { TAG_34OHM, {{TAG_3VNS, 21}, {TAG_4VNS, 15}, {TAG_5VNS, 10}, {TAG_6VNS, 135}} }, - { TAG_40OHM, {{TAG_3VNS, 21}, {TAG_4VNS, 13}, {TAG_5VNS, 8}, {TAG_6VNS, 134}} }, - } - }, - - { - TAG_2400MHZ, - { - { TAG_24OHM, {{TAG_3VNS, 18}, {TAG_4VNS, 13}, {TAG_5VNS, 10}, {TAG_6VNS, 137}} }, - { TAG_30OHM, {{TAG_3VNS, 19}, {TAG_4VNS, 13}, {TAG_5VNS, 10}, {TAG_6VNS, 136}} }, - { TAG_34OHM, {{TAG_3VNS, 21}, {TAG_4VNS, 15}, {TAG_5VNS, 10}, {TAG_6VNS, 135}} }, - { TAG_40OHM, {{TAG_3VNS, 21}, {TAG_4VNS, 13}, {TAG_5VNS, 8}, {TAG_6VNS, 134}} }, - } - }, - - } - } - }; - - // Get the vector of ports. Note that we presently think there's a bit in the CCS_MODE - // register which needs to be twiddled during slew cal. That means our caller can't - // put each port's slew cal on a thread and do them in parallel. So, we interleave. - // If that requirement for that MCBIST register goes away, then these functions can turn - // in to per-port functions and the caller can decide to loop or thread as appropriate. - // Or maybe per MCS given the attribute work we need to do at the end ... - auto l_ports = i_target.getChildren<TARGET_TYPE_MCA>(TARGET_STATE_FUNCTIONAL); - - // Cache the name of our target. We can't just keep the pointer from c_str as - // it points to thread-local space and anything we call might change the string. - char l_name[fapi2::MAX_ECMD_STRING_LEN]; - strncpy(l_name, mss::c_str(i_target), fapi2::MAX_ECMD_STRING_LEN); - - // p9n is ddr4 only for now, so skip checking the dimm generation (effective config - // should have raised a rukus if this isn't a DDR4 dimm ... - - FAPI_TRY( mss::freq(i_target, ddr_freq), - "Unable to get ddr freq for %s", l_name ); - - // Note: this catches two cases. One where ddr_freq is 0 and the other - // where we put something slow in we don't (yet?) support - FAPI_ASSERT( ddr_freq > 1732, - fapi2::MSS_SLEW_CAL_INVALID_FREQ(), - "Invalid ATTR_MSS_FREQ (%d) on %s", ddr_freq, l_name ); - - // Get a list of functional ports. - // Note: If we need to use the functional vector to figure this out, - // change this to an mss call, and bury the attribute manipluation - // in that function so it can be shared and tests. BRS - - // - // This doesn't match teh Centaur workbook algorithm, but it matches the P8 code so - // I'm leaving it this way. The algorithm according to the Centaur book would be to - // configure ADR/MCLK detect and then wait for BB_LOCK. Then, enable the cal engine and - // wait 2K clocks. So to "fix" you'd move the polling for BB_LOCK above the putScom. BRS - // - - // Sanity check the DRAM generation - for (auto c : i_target.getChildren<TARGET_TYPE_MCS>()) - { - FAPI_TRY( check::dram_type(c) ); - } - - // Step A: Configure ADR registers and MCLK detect (done in ddr_phy_reset) - { - for (auto p : l_ports) - { - FAPI_INF("Enabling slew calibration engine on port %i: DDR%i(%u) %u(%u) in %s", - mss::pos(p), (ddr_type + 2), ddr_idx, ddr_freq, freq_idx, l_name); - - // Note: This is wrong. Cant' find the SLEW_CAL enable bit in n10_e9024, so leaving this here for now BRS - FAPI_TRY( mss::putScom(p, MCA_DDRPHY_ADR_SLEW_CAL_CNTL_P0_ADR32S0, - fapi2::buffer<uint64_t>().setBit<ENABLE_BIT>()), - "Error enabling slew calibration engine in DDRPHY_ADR_SLEW_CAL_CNTL register."); - } - } - - // Note: must be 2000 nclks+ after setting enable bit - // normally 2000, but since cal doesn't work in SIM, setting to 1 - FAPI_TRY( fapi2::delay(cycles_to_ns(i_target, 2000), cycles_to_simcycles(1)) ); - - // Create calibrated slew settings, per MCS. We do this as the attributes are written per MCS, - // and this makes it easier to keep track of what's going where, etc. - for (auto c : i_target.getChildren<TARGET_TYPE_MCS>()) - { - // [adr or data][port on mcs][imp][slew] - uint8_t calibrated_slew[2][PORTS_PER_MCS][MAX_NUM_IMP][MAX_NUM_CAL_SLEW_RATES] = {0}; - - auto l_mcs_ports = c.getChildren<TARGET_TYPE_MCA>(); - - for (auto p : l_mcs_ports) - { - for (auto e : slew_table) - { - FAPI_INF("Starting %s, port %d slew calibration", (e.first == TAG_ADR ? "adr" : "data"), mss::pos(p)); - - for (auto this_table : e.second) - { - std::vector<tags_t> l_where_am_i; - l_where_am_i.push_back(e.first); - FAPI_TRY( perform_slew_cal(p, l_where_am_i, this_table, calibrated_slew) ); - } - } - } - - // We have the calibrated slew settings, disable the calibration engine and do the - // attribute dance. - for (auto p : l_mcs_ports) - { - // Note: This is wrong. Cant' find the SLEW_CAL enable bit in n10_e9024, so leaving this here for now BRS - FAPI_TRY( mss::putScom(p, MCA_DDRPHY_ADR_SLEW_CAL_CNTL_P0_ADR32S0, - fapi2::buffer<uint64_t>().clearBit<ENABLE_BIT>()), - "Error disabling slew calibration engine in DDRPHY_ADR_SLEW_CAL_CNTL register."); - } - -// FAPI_TRY( slew_cal_attributes() ); - } - -fapi_try_exit: - return fapi2::current_err; -} -} // namespace diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/utils/conversions.H b/src/import/chips/p9/procedures/hwp/memory/lib/utils/conversions.H index 9076f97ee..c7a3589b7 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/utils/conversions.H +++ b/src/import/chips/p9/procedures/hwp/memory/lib/utils/conversions.H @@ -186,6 +186,12 @@ inline uint64_t ps_to_cycles(const fapi2::Target<T>& i_target, const uint64_t i_ FAPI_TRY( mss::freq( find_target<fapi2::TARGET_TYPE_MCBIST>(i_target), l_freq) ); + // No time if MT/s is 0 (well, infinite really but shut up) + if (l_freq == 0) + { + return 0; + } + // Hoping the compiler figures out how to do these together. FAPI_TRY( freq_to_ps(l_freq, l_divisor) ); l_quotient = i_ps / ((l_divisor == 0) ? 1 : l_divisor); @@ -312,18 +318,6 @@ inline uint64_t cycles_to_us(const fapi2::Target<T>& i_target, const uint64_t i_ } /// -/// @brief Calculate TWLO_TWLOE - this needs to go in to eff_config and be an attribute -/// @tparam T fapi2::TargetType of the target used to calculate cycles from ns -/// @param[in] i_target the target used to get DIMM clocks -/// @return uint64_t, TWLO_TWLOE in cycles -/// -template< fapi2::TargetType T > -inline uint64_t twlo_twloe(const fapi2::Target<T>& i_target) -{ - return 12 + mss::ns_to_cycles(i_target, tWLO - tWLOE); -} - -/// /// @brief Convert nanoseconds to picoseconds /// @tparam T input and output type /// @param[in] i_time_in_ns time in nanoseconds @@ -352,6 +346,19 @@ inline T ps_to_ns(const T i_time_in_ps) return l_time_in_ns + ( remainder == 0 ? 0 : 1 ); } +/// +/// @brief Return the maximum of two values *in clocks*, the first in clocks the second in ns +/// @tparam T the fapi2::TargetType of a type from which we can get MT/s +/// @param[in] i_clocks a value in clocks +/// @param[in] i_time a value in nanoseconds +/// @return max( iclocks nCK, i_time ) in clocks +/// +template< fapi2::TargetType T > +inline uint64_t max_ck_ns(const fapi2::Target<T>& i_target, const uint64_t i_clocks, const uint64_t i_time) +{ + return std::max( i_clocks, ns_to_cycles(i_target, i_time) ); +} + };// mss namespace |