diff options
author | Brian Silver <bsilver@us.ibm.com> | 2016-06-22 11:14:04 -0500 |
---|---|---|
committer | Daniel M. Crowell <dcrowell@us.ibm.com> | 2016-07-13 14:21:12 -0400 |
commit | f6f43282388298e9e2f6398b40c7fecbc99c62ff (patch) | |
tree | ae626b2ed5b6a6ec806bb515e6d615902a16c7fc /src/import/chips/p9/procedures/hwp/memory | |
parent | 1be7eab90246335fa2293ab5376643d5ec6873ce (diff) | |
download | talos-hostboot-f6f43282388298e9e2f6398b40c7fecbc99c62ff.tar.gz talos-hostboot-f6f43282388298e9e2f6398b40c7fecbc99c62ff.zip |
Add DLL Calibration
Add ADRS32{0,1} register API
Add per-procedure ipl test (phy reset)
Fix blastah, don't return current_err unchanged
Change-Id: I4a76f74f8b7401af15ba1ae0b1823f61ad2ec050
Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/26306
Tested-by: Jenkins Server
Reviewed-by: STEPHEN GLANCY <sglancy@us.ibm.com>
Tested-by: Hostboot CI
Reviewed-by: Louis Stermole <stermole@us.ibm.com>
Reviewed-by: Christian R. Geddes <crgeddes@us.ibm.com>
Reviewed-by: Jennifer A. Stofer <stofer@us.ibm.com>
Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/26307
Tested-by: Jenkins Server <pfd-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')
9 files changed, 679 insertions, 93 deletions
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/phy/adr32s.C b/src/import/chips/p9/procedures/hwp/memory/lib/phy/adr32s.C index f49ad482b..ed7a10b07 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/phy/adr32s.C +++ b/src/import/chips/p9/procedures/hwp/memory/lib/phy/adr32s.C @@ -16,3 +16,29 @@ /* deposited with the U.S. Copyright Office. */ /* */ /* IBM_PROLOG_END_TAG */ + +/// +/// @file adr32s.C +/// @brief Subroutines for the PHY ADR32S 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 <lib/phy/adr32s.H> + +namespace mss +{ + +// Definition of the ADR32S DLL Config registers +const std::vector<uint64_t> adr32sTraits<fapi2::TARGET_TYPE_MCA>::DLL_CNFG_REG = +{ + MCA_DDRPHY_ADR_DLL_CNTL_P0_ADR32S0, + MCA_DDRPHY_ADR_DLL_CNTL_P0_ADR32S1 +}; + +} + diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/phy/adr32s.H b/src/import/chips/p9/procedures/hwp/memory/lib/phy/adr32s.H index e41a5a094..2294db408 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/phy/adr32s.H +++ b/src/import/chips/p9/procedures/hwp/memory/lib/phy/adr32s.H @@ -16,3 +16,149 @@ /* deposited with the U.S. Copyright Office. */ /* */ /* IBM_PROLOG_END_TAG */ + +/// +/// @file adr32s.H +/// @brief Subroutines for the PHY ADR32S 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 + +#ifndef _MSS_ADR32S_H_ +#define _MSS_ADR32S_H_ + +#include <fapi2.H> +#include <p9_mc_scom_addresses.H> +#include <p9_mc_scom_addresses_fld.H> + +#include <lib/shared/mss_const.H> +#include <lib/utils/scom.H> + +namespace mss +{ + +// I have a dream that the PHY code can be shared among controllers. So, I drive the +// engine from a set of traits. This might be folly. Allow me to dream. BRS + +/// +/// @class adr32sTraits +/// @brief a collection of traits associated with the PHY ADR32S interface +/// @tparam T fapi2::TargetType representing the PHY +/// +template< fapi2::TargetType T > +class adr32sTraits; + +/// +/// @class adr32sTraits +/// @brief a collection of traits associated with the Centaur PHY ADR32S interface +/// +template<> +class adr32sTraits<fapi2::TARGET_TYPE_MBA> +{ +}; + +/// +/// @class adr32sTraits +/// @brief a collection of traits associated with the Nimbus PHY ADR32S +/// +template<> +class adr32sTraits<fapi2::TARGET_TYPE_MCA> +{ + public: + + // Number of ADR32S units + static constexpr uint64_t ADR32S_COUNT = 2; + + // MCA ADR32S control registers all come in pairs. + static const std::vector<uint64_t> DLL_CNFG_REG; + + enum + { + DLL_CNTL_INIT_RXDLL_CAL_RESET = MCA_DDRPHY_ADR_DLL_CNTL_P0_ADR32S0_ADR0_INIT_RXDLL_CAL_RESET, + DLL_CNTL_INIT_RXDLL_CAL_UPDATE = MCA_DDRPHY_ADR_DLL_CNTL_P0_ADR32S0_ADR0_INIT_RXDLL_CAL_UPDATE, + DLL_CNTL_REGS_RXDLL_CAL_SKIP = MCA_DDRPHY_ADR_DLL_CNTL_P0_ADR32S0_ADR0_REGS_RXDLL_CAL_SKIP, + DLL_CNTL_REGS_RXDLL_CAL_SKIP_LEN = MCA_DDRPHY_ADR_DLL_CNTL_P0_ADR32S0_ADR0_REGS_RXDLL_CAL_SKIP_LEN, + DLL_CNTL_REGS_RXDLL_COARSE_ADJ_BY2 = MCA_DDRPHY_ADR_DLL_CNTL_P0_ADR32S0_ADR0_REGS_RXDLL_COARSE_ADJ_BY2, + DLL_CNTL_RXREG_FILTER_LENGTH_DC = MCA_DDRPHY_ADR_DLL_CNTL_P0_ADR32S0_ADR0_RXREG_FILTER_LENGTH_DC, + DLL_CNTL_RXREG_FILTER_LENGTH_DC_LEN = MCA_DDRPHY_ADR_DLL_CNTL_P0_ADR32S0_ADR0_RXREG_FILTER_LENGTH_DC_LEN, + DLL_CNTL_RXREG_LEAD_LAG_SEPARATION_DC = MCA_DDRPHY_ADR_DLL_CNTL_P0_ADR32S0_ADR0_RXREG_LEAD_LAG_SEPARATION_DC, + DLL_CNTL_RXREG_LEAD_LAG_SEPARATION_DC_LEN = + MCA_DDRPHY_ADR_DLL_CNTL_P0_ADR32S0_ADR0_RXREG_LEAD_LAG_SEPARATION_DC_LEN, + DLL_CNTL_EN_DRIVER_INVFB_DC = MCA_DDRPHY_ADR_DLL_CNTL_P0_ADR32S0_ADR0_EN_DRIVER_INVFB_DC, + DLL_CNTL_RXREG_FINECAL_2XILSB_DC = MCA_DDRPHY_ADR_DLL_CNTL_P0_ADR32S0_ADR0_RXREG_FINECAL_2XILSB_DC, + DLL_CNTL_CAL_GOOD = MCA_DDRPHY_ADR_DLL_CNTL_P0_ADR32S0_ADR0_CAL_GOOD, + DLL_CNTL_CAL_ERROR = MCA_DDRPHY_ADR_DLL_CNTL_P0_ADR32S0_ADR0_CAL_ERROR, + DLL_CNTL_CAL_ERROR_FINE = MCA_DDRPHY_ADR_DLL_CNTL_P0_ADR32S0_ADR0_CAL_ERROR_FINE, + + }; + +}; + +namespace adr32s +{ + +/// +/// @brief Read DLL_CNTL +/// @tparam I ADR32S instance e.g., 0 or 1 for a 64 bit implementation of the PHY +/// @tparam T fapi2 Target Type - derived +/// @tparam TT traits type defaults to adr32sTraits<T> +/// @param[in] i_target the fapi2 target of the port +/// @param[out] o_data the value of the register +/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok +/// +template< uint64_t I, fapi2::TargetType T, typename TT = adr32sTraits<T> > +inline fapi2::ReturnCode read_dll_cntl( const fapi2::Target<T>& i_target, fapi2::buffer<uint64_t>& o_data ) +{ + static_assert( I < TT::ADR32S_COUNT, "adr32s instance out of range"); + FAPI_TRY( mss::getScom(i_target, TT::DLL_CNFG_REG[I], o_data) ); + FAPI_INF("dll_cntl adrs32%d: 0x%016lx", I, o_data); +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Write DLL_CNTL_ADR32S0 +/// @tparam I ADR32S instance e.g., 0 or 1 for a 64 bit implementation of the PHY +/// @tparam T fapi2 Target Type - derived +/// @tparam TT traits type defaults to adr32sTraits<T> +/// @param[in] i_target the fapi2 target of the port +/// @param[in] i_data the value of the register +/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok +/// +template< uint64_t I, fapi2::TargetType T, typename TT = adr32sTraits<T> > +inline fapi2::ReturnCode write_dll_cntl( const fapi2::Target<T>& i_target, const fapi2::buffer<uint64_t>& i_data ) +{ + static_assert( I < TT::ADR32S_COUNT, "adr32s instance out of range"); + FAPI_INF("dll_cntl adr32s%d: 0x%016lx", I, i_data); + FAPI_TRY( mss::putScom(i_target, TT::DLL_CNFG_REG[I], i_data) ); +fapi_try_exit: + return fapi2::current_err; +} + +// +// Reseting the DLL registers TODO RTC:156518 +// + +/// +/// @brief Set the DLL cal reset (begins DLL cal operations) +/// @tparam T fapi2 Target Type - derived +/// @tparam TT traits type defaults to adr32sTraits<T> +/// @param[in] o_data the value of the register +/// @param[in] i_state mss::LOW or mss::HIGH representing the state of the bit +/// @note Default state is 'low' as writing a 0 forces the cal to begin. +/// +template< fapi2::TargetType T = fapi2::TARGET_TYPE_MCA, typename TT = adr32sTraits<T> > +inline void set_dll_cal_reset( fapi2::buffer<uint64_t>& o_data, const states i_state = mss::LOW ) +{ + FAPI_INF("set_dll_cal_reset %s", (i_state == mss::LOW ? "low" : "high")); + o_data.writeBit<TT::DLL_CNTL_INIT_RXDLL_CAL_RESET>(i_state); +} + +} // close namespace adr + +} // close namespace mss + +#endif 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 62c711f26..f0d5da547 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 @@ -37,8 +37,10 @@ #include <lib/phy/read_cntrl.H> #include <lib/phy/phy_cntrl.H> #include <lib/phy/apb.H> +#include <lib/phy/adr32s.H> #include <lib/utils/bit_count.H> +#include <lib/utils/find.H> #include <lib/utils/dump_regs.H> #include <lib/utils/scom.H> @@ -48,6 +50,7 @@ using fapi2::TARGET_TYPE_SYSTEM; using fapi2::TARGET_TYPE_MCA; using fapi2::TARGET_TYPE_MCS; using fapi2::TARGET_TYPE_DIMM; +using fapi2::FAPI2_RC_SUCCESS; namespace mss { @@ -176,91 +179,15 @@ fapi2::ReturnCode deassert_pll_reset( const fapi2::Target<TARGET_TYPE_MCBIST>& i { fapi2::buffer<uint64_t> l_data; -#ifdef KNOW_ADR_DLL_PROCESS - static const uint64_t dp16_lock_mask = 0x000000000000FFFE; - static const uint64_t ad_lock_mask = fapi2::buffer<uint64_t>().setBit<48>().setBit<49>(); -#endif - // // Write 0x4000 into the PC Resets Registers. This deasserts the PLL_RESET and leaves the SYSCLK_RESET bit active - // (SCOM Addr: 0x8000C00E0301143F, 0x8001C00E0301143F, 0x8000C00E0301183F, 0x8001C00E0301183F) + // + // TODO RTC:156693 Do we need to do this on Nimbus? BRS FAPI_DBG("Write 0x4000 into the PC Resets Regs. This deasserts the PLL_RESET and leaves the SYSCLK_RESET bit active"); l_data.setBit<MCA_DDRPHY_PC_RESETS_P0_SYSCLK_RESET>(); FAPI_TRY( mss::scom_blastah(mss::find_targets<TARGET_TYPE_MCA>(i_target), MCA_DDRPHY_PC_RESETS_P0, l_data) ); - // - // Wait at least 1 millisecond to allow the PLLs to lock. Otherwise, poll the PC DP18 PLL Lock Status - // and the PC AD32S PLL Lock Status to determine if all PLLs have locked. - // PC DP18 PLL Lock Status should be 0xF800: (SCOM Addr: 0x8000C0000301143F, 0x8001C0000301143F, 0x8000C0000301183F, 0x8001C0000301183F) - // PC AD32S PLL Lock Status should be 0xC000: (SCOM Addr: 0x8000C0010301143F, 0x8001C0010301143F, 0x8000C0010301183F, 0x8001C0010301183F) - -#ifdef KNOW_ADR_DLL_PROCESS - // Poll for lock bits - FAPI_DBG("Poll until DP18 and AD32S PLLs have locked"); - - do - { - // Set in the CHECK_PLL macro - done_polling = true; - - fapi2::delay(DELAY_1US, cycles_to_simcycles(us_to_cycles(i_target, 1))); - - // Note: in the latest scomdef this is DP16 BRS - // Note: Not sure what the proper registers here are. I took the following old addresses from Ed's - // version of the code and mapped the addresses to the latests mc_scom_addresses.H. This needs to - // be fixed up when the extended addressing is fixed up. BRS - - // CONST_UINT64_T(DDRPHY_PC_DP18_PLL_LOCK_STATUS_P0_0x8000C0000701143F, ULL(0x8000C0000701143F) ); - CHECK_PLL( l_target_proc, MCA_0_DDRPHY_PC_DP18_PLL_LOCK_STATUS_P0, l_data, dp16_lock_mask ); - - // CONST_UINT64_T(DDRPHY_PC_DP18_PLL_LOCK_STATUS_P1_0x8001C0000701143F, ULL(0x8001C0000701143F) ); - CHECK_PLL( l_target_proc, MCA_1_DDRPHY_PC_DP18_PLL_LOCK_STATUS_P1, l_data, dp16_lock_mask ); - - // CONST_UINT64_T(DDRPHY_PC_DP18_PLL_LOCK_STATUS_P2_0x8000C0000701183F, ULL(0x8000C0000701183F) ); - CHECK_PLL( l_target_proc, MCA_2_DDRPHY_PC_DP18_PLL_LOCK_STATUS_P2, l_data, dp16_lock_mask ); - - // CONST_UINT64_T(DDRPHY_PC_DP18_PLL_LOCK_STATUS_P3_0x8001C0000701183F, ULL(0x8001C0000701183F) ); - CHECK_PLL( l_target_proc, MCA_3_DDRPHY_PC_DP18_PLL_LOCK_STATUS_P3, l_data, dp16_lock_mask ); - - // CONST_UINT64_T( DDRPHY_PC_AD32S_PLL_LOCK_STATUS_P0_0x8000C0010701143F, ULL(0x8000C0010701143F) ); - CHECK_PLL( l_target_proc, MCA_0_DDRPHY_PC_AD32S_PLL_LOCK_STATUS_P0, l_data, ad_lock_mask ); - - // CONST_UINT64_T( DDRPHY_PC_AD32S_PLL_LOCK_STATUS_P1_0x8001C0010701143F, ULL(0x8001C0010701143F) ); - CHECK_PLL( l_target_proc, MCA_1_DDRPHY_PC_AD32S_PLL_LOCK_STATUS_P1, l_data, ad_lock_mask ); - - // CONST_UINT64_T( DDRPHY_PC_AD32S_PLL_LOCK_STATUS_P2_0x8000C0010701183F, ULL(0x8000C0010701183F) ); - CHECK_PLL( l_target_proc, MCA_2_DDRPHY_PC_AD32S_PLL_LOCK_STATUS_P2, l_data, ad_lock_mask ); - - // CONST_UINT64_T( DDRPHY_PC_AD32S_PLL_LOCK_STATUS_P3_0x8001C0010701183F, ULL(0x8001C0010701183F) ); - CHECK_PLL( l_target_proc, MCA_3_DDRPHY_PC_AD32S_PLL_LOCK_STATUS_P3, l_data, ad_lock_mask ); - } - while (!done_polling && --max_poll_loops); - - // If we ran out of iterations, report we have a pll lock failure. - if (max_poll_loops == 0) - { - FAPI_ERR("DDR PHY PLL failed to lock for %s", mss::c_str(i_target)); - FFDC_PLL( l_target_proc, MCA_0_DDRPHY_PC_DP18_PLL_LOCK_STATUS_P0, l_data, dp16_lock_mask, - fapi2::MSS_DP16_PLL_FAILED_TO_LOCK() ); - FFDC_PLL( l_target_proc, MCA_1_DDRPHY_PC_DP18_PLL_LOCK_STATUS_P1, l_data, dp16_lock_mask, - fapi2::MSS_DP16_PLL_FAILED_TO_LOCK() ); - FFDC_PLL( l_target_proc, MCA_2_DDRPHY_PC_DP18_PLL_LOCK_STATUS_P2, l_data, dp16_lock_mask, - fapi2::MSS_DP16_PLL_FAILED_TO_LOCK() ); - FFDC_PLL( l_target_proc, MCA_3_DDRPHY_PC_DP18_PLL_LOCK_STATUS_P3, l_data, dp16_lock_mask, - fapi2::MSS_DP16_PLL_FAILED_TO_LOCK() ); - - FFDC_PLL( l_target_proc, MCA_0_DDRPHY_PC_AD32S_PLL_LOCK_STATUS_P0, l_data, ad_lock_mask, - fapi2::MSS_AD32S_PLL_FAILED_TO_LOCK() ); - FFDC_PLL( l_target_proc, MCA_1_DDRPHY_PC_AD32S_PLL_LOCK_STATUS_P1, l_data, ad_lock_mask, - fapi2::MSS_AD32S_PLL_FAILED_TO_LOCK() ); - FFDC_PLL( l_target_proc, MCA_2_DDRPHY_PC_AD32S_PLL_LOCK_STATUS_P2, l_data, ad_lock_mask, - fapi2::MSS_AD32S_PLL_FAILED_TO_LOCK() ); - FFDC_PLL( l_target_proc, MCA_3_DDRPHY_PC_AD32S_PLL_LOCK_STATUS_P3, l_data, ad_lock_mask, - fapi2::MSS_AD32S_PLL_FAILED_TO_LOCK() ); - } - -#endif fapi_try_exit: return fapi2::current_err; @@ -1107,5 +1034,98 @@ fapi_try_exit: return fapi2::current_err; } +/// +/// @brief Start the DLL calibration, monitor for fails. +/// @param[in] i_target the target associated with this DLL cal +/// @return FAPI2_RC_SUCCESS iff setup was successful +/// +template<> +fapi2::ReturnCode dll_calibration( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target ) +{ + uint8_t is_sim = 0; + fapi2::buffer<uint64_t> l_status; + constexpr uint64_t l_dll_status_reg = pcTraits<TARGET_TYPE_MCA>::PC_DLL_ZCAL_CAL_STATUS_REG; + const auto& l_mca = mss::find_targets<TARGET_TYPE_MCA>(i_target); + + FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_IS_SIMULATION, fapi2::Target<TARGET_TYPE_SYSTEM>(), is_sim) ); + + // Nothing works here in cycle sim ... + if (is_sim) + { + return FAPI2_RC_SUCCESS; + } + + // If we don't have any MCA, we can go + if (l_mca.size() == 0) + { + return FAPI2_RC_SUCCESS; + } + + // 14. Begin DLL calibrations by setting INIT_RXDLL_CAL_RESET=0 in the DDRPHY_DP16_DLL_CNTL{0:1} registers + // and DDRPHY_ADR_DLL_CNTL registers + for (const auto& p : l_mca) + { + // Note: Keep INIT_RXDLL_CAL_UPDATE at 0 to ensure PC CAL_GOOD indicator is accurate. + // Read, modify, write the DLL_RESET in the ADR_DLL registers + { + std::vector<fapi2::buffer<uint64_t>> i_read; + + FAPI_TRY(mss::scom_suckah(p, adr32sTraits<TARGET_TYPE_MCA>::DLL_CNFG_REG, i_read)); + std::for_each( i_read.begin(), i_read.end(), + [](fapi2::buffer<uint64_t>& b) + { + adr32s::set_dll_cal_reset(b); + } ); + FAPI_TRY(mss::scom_blastah(p, adr32sTraits<TARGET_TYPE_MCA>::DLL_CNFG_REG, i_read)); + } + + // Read, modify, write the DLL_RESET in the DP16_DLL registers + { + std::vector< std::pair<fapi2::buffer<uint64_t>, fapi2::buffer<uint64_t> > > i_read; + + FAPI_TRY(mss::scom_suckah(p, dp16Traits<TARGET_TYPE_MCA>::DLL_CNFG_REG, i_read)); + std::for_each( i_read.begin(), i_read.end(), + [](std::pair< fapi2::buffer<uint64_t>, fapi2::buffer<uint64_t> >& b) + { + dp16::set_dll_cal_reset(b.first); + dp16::set_dll_cal_reset(b.second); + } ); + FAPI_TRY(mss::scom_blastah(p, dp16Traits<TARGET_TYPE_MCA>::DLL_CNFG_REG, i_read)); + } + } + + // The [delay value] gives software a reasonable amount of time to wait for an individual + // DLL to calibrate starting from when it is taken out of reset. As some internal state machine transitions + // between steps may not have been counted, software should add some margin. + // 32,772 dphy_nclk cycles from Reset=0 to VREG Calibration to exhaust all values + // 37,382 dphy_nclk cycles for full calibration to start and fail (“worst case”) + // More or less a fake value for sim delay as this isn't executed in sim. + fapi2::delay(mss::cycles_to_ns(i_target, 37382), DELAY_1US); + + // 15. Monitor the DDRPHY_PC_DLL_ZCAL_CAL_STATUS register to determine when calibration is + // complete. One of the 3 bits will be asserted for ADR and DP16. + // To keep things simple, we'll poll for the change in one of the bits. Once that's completed, we'll + // check the others. If any one has failed, or isn't notifying complete, we'll pop out an error + mss::poll(l_mca[0], l_dll_status_reg, poll_parameters(), + [&l_status](const size_t poll_remaining, const fapi2::buffer<uint64_t>& stat_reg) -> bool + { + FAPI_INF("phy control dll/zcal stat 0x%llx, remaining: %d", stat_reg, poll_remaining); + l_status = stat_reg; + return mss::pc::get_dll_cal_status(l_status) == mss::YES; + }); + + for (const auto& p : l_mca) + { + fapi2::buffer<uint64_t> l_read; + FAPI_TRY( mss::getScom(p, l_dll_status_reg, l_read) ); + FAPI_ASSERT(mss::pc::get_dll_cal_status(l_read) == mss::YES, + fapi2::MSS_DLL_FAILED_TO_CALIBRATE().set_MCA_IN_ERROR(p), + "dll fapiled to calibrate: %s", mss::c_str(p)); + } + +fapi_try_exit: + return fapi2::current_err; +} + } diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/phy/ddr_phy.H b/src/import/chips/p9/procedures/hwp/memory/lib/phy/ddr_phy.H index a1256cd6b..6b9010976 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/phy/ddr_phy.H +++ b/src/import/chips/p9/procedures/hwp/memory/lib/phy/ddr_phy.H @@ -223,6 +223,31 @@ template<> fapi2::ReturnCode reset_seq_rd_wr_data( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target ); /// +/// @brief Perform the DLL calibration +/// @tparam T the target type of the MCBIST +/// @param[in] i_target the target associated with this DLL cal +/// @return FAPI2_RC_SUCCESS iff setup was successful +/// +template< fapi2::TargetType T > +fapi2::ReturnCode dll_calibration( const fapi2::Target<T>& i_target ); + +/// +/// @brief Perform the DLL calibration +/// @param[in] i_target the target associated with this DLL cal +/// @return FAPI2_RC_SUCCESS iff setup was successful +/// +template<> +fapi2::ReturnCode dll_calibration( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target ); + +/// +/// @brief Setup seq_rd_wr_data +/// @param[in] i_target the MCA target associated with this cal setup +/// @return FAPI2_RC_SUCCESS iff setup was successful +/// +template<> +fapi2::ReturnCode reset_seq_rd_wr_data( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target ); + +/// /// @brief Setup the PC CONFIG0 register /// @tparam T the fapi2::TargetType /// @param[in] i_target the target (MCA or MBA?) diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/phy/dp16.C b/src/import/chips/p9/procedures/hwp/memory/lib/phy/dp16.C index 180631291..803e9bdea 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/phy/dp16.C +++ b/src/import/chips/p9/procedures/hwp/memory/lib/phy/dp16.C @@ -49,6 +49,20 @@ using fapi2::TARGET_TYPE_SYSTEM; namespace mss { +// Definition of the DP16 DLL Config registers +// DP16 DLL registers all come in pairs - DLL per 8 bits +// 5 DLL per MCA gives us 10 DLL Config Registers. +// All-caps (as opposed to the others) as it's really in the dp16Traits class which is app caps <shrug>) +const std::vector< std::pair<uint64_t, uint64_t> > dp16Traits<TARGET_TYPE_MCA>::DLL_CNFG_REG = +{ + { MCA_DDRPHY_DP16_DLL_CNTL0_P0_0, MCA_DDRPHY_DP16_DLL_CNTL1_P0_0 }, + { MCA_DDRPHY_DP16_DLL_CNTL0_P0_1, MCA_DDRPHY_DP16_DLL_CNTL1_P0_1 }, + { MCA_DDRPHY_DP16_DLL_CNTL0_P0_2, MCA_DDRPHY_DP16_DLL_CNTL1_P0_2 }, + { MCA_DDRPHY_DP16_DLL_CNTL0_P0_3, MCA_DDRPHY_DP16_DLL_CNTL1_P0_3 }, + { MCA_DDRPHY_DP16_DLL_CNTL0_P0_4, MCA_DDRPHY_DP16_DLL_CNTL1_P0_4 }, +}; + + namespace dp16 { @@ -288,7 +302,7 @@ fapi_try_exit: /// fapi2::ReturnCode reset_sysclk( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target ) { - std::vector< std::pair<uint64_t, uint64_t> > l_addrs( + static const std::vector< std::pair<uint64_t, uint64_t> > l_addrs( { {MCA_DDRPHY_DP16_SYSCLK_PR0_P0_0, MCA_DDRPHY_DP16_SYSCLK_PR1_P0_0}, {MCA_DDRPHY_DP16_SYSCLK_PR0_P0_1, MCA_DDRPHY_DP16_SYSCLK_PR1_P0_1}, @@ -393,6 +407,5 @@ fapi_try_exit: return fapi2::current_err; } - } // close namespace dp16 } // close namespace mss diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/phy/dp16.H b/src/import/chips/p9/procedures/hwp/memory/lib/phy/dp16.H index 754e4c16e..04ccb0a38 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/phy/dp16.H +++ b/src/import/chips/p9/procedures/hwp/memory/lib/phy/dp16.H @@ -35,6 +35,7 @@ #include <p9_mc_scom_addresses.H> #include <p9_mc_scom_addresses_fld.H> +#include <lib/utils/scom.H> namespace mss { @@ -106,11 +107,101 @@ class dp16Traits<fapi2::TARGET_TYPE_MBA> template<> class dp16Traits<fapi2::TARGET_TYPE_MCA> { + + public: + // Number of DP instances + static constexpr uint64_t DP_COUNT = 5; + + // Number of instances of the DLL per DP16. Used for checking parameters, the rest of the + // code assumes 2 DLL per DP16. There are no DLL in Centaur so we don't need to worry about + // any of this for some time. + static constexpr uint64_t DLL_PER_DP16 = 2; + + // Vector of the DLL configuration registers. The pair represents the two DLL in per DP16 + static const std::vector< std::pair<uint64_t, uint64_t> > DLL_CNFG_REG; + + enum + { + DLL_CNTL_INIT_RXDLL_CAL_RESET = MCA_DDRPHY_DP16_DLL_CNTL0_P0_0_01_INIT_RXDLL_CAL_RESET, + }; }; namespace dp16 { +/// +/// @brief Read DLL_CNTL +/// @tparam I DP16 instance +/// @tparam D DLL instance in the specified DP16 +/// @tparam T fapi2 Target Type - derived +/// @tparam TT traits type defaults to dp16Traits<T> +/// @param[in] i_target the fapi2 target of the port +/// @param[out] o_data the value of the register +/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok +/// +template< uint64_t I, uint64_t D, fapi2::TargetType T, typename TT = dp16Traits<T> > +inline fapi2::ReturnCode read_dll_cntl( const fapi2::Target<T>& i_target, fapi2::buffer<uint64_t>& o_data ) +{ + static_assert( I < TT::DP_COUNT, "dp16 instance out of range"); + static_assert( D < TT::DLL_PER_DP16, "dll instance out of range"); + + // The pair represents the upper and lower bytes of the DP16 - each has its own DLL regiters + const uint64_t& l_addr = (D == 0) ? TT::DLL_CNFG_REG[I].first : TT::DLL_CNFG_REG[I].second; + + FAPI_TRY( mss::getScom(i_target, l_addr, o_data) ); + FAPI_INF("dll_cntl dp16<%d, %d>: 0x%016lx", I, D, o_data); + +fapi_try_exit: + return fapi2::current_err; + +} + +/// +/// @brief Write DLL_CNTL +/// @tparam I DP16 instance +/// @tparam D DLL instance in the specified DP16 +/// @tparam T fapi2 Target Type - derived +/// @tparam TT traits type defaults to dp16Traits<T> +/// @param[in] i_target the fapi2 target of the port +/// @param[in] i_data the value of the register +/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok +/// +template< uint64_t I, uint64_t D, fapi2::TargetType T, typename TT = dp16Traits<T> > +inline fapi2::ReturnCode write_dll_cntl( const fapi2::Target<T>& i_target, const fapi2::buffer<uint64_t>& i_data ) +{ + static_assert( I < TT::DP_COUNT, "dp16 instance out of range"); + static_assert( D < TT::DLL_PER_DP16, "dll instance out of range"); + + // The pair represents the upper and lower bytes of the DP16 - each has its own DLL regiters + const uint64_t& l_addr = (D == 0) ? TT::DLL_CNFG_REG[I].first : TT::DLL_CNFG_REG[I].second; + + FAPI_INF("dll_cntl dp16<%d,%d>: 0x%016lx", I, D, i_data); + FAPI_TRY( mss::putScom(i_target, l_addr, i_data) ); + +fapi_try_exit: + return fapi2::current_err; + +} + +// +// Reseting the DLL registers TODO RTC:156518 +// + +/// +/// @brief Set the DLL cal reset (begins DLL cal operations) +/// @tparam T fapi2 Target Type - derived +/// @tparam TT traits type defaults to dp16Traits<T> +/// @param[in] o_data the value of the register +/// @param[in] i_state mss::LOW or mss::HIGH representing the state of the bit +/// @note Default state is 'low' as writing a 0 forces the cal to begin. +/// +template< fapi2::TargetType T = fapi2::TARGET_TYPE_MCA, typename TT = dp16Traits<T> > +inline void set_dll_cal_reset( fapi2::buffer<uint64_t>& o_data, const states i_state = mss::LOW ) +{ + FAPI_INF("set_dll_cal_reset %s", (i_state == mss::LOW ? "low" : "high")); + o_data.writeBit<TT::DLL_CNTL_INIT_RXDLL_CAL_RESET>(i_state); +} + /// /// @brief Configure the DP16 sysclk diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/phy/phy_cntrl.H b/src/import/chips/p9/procedures/hwp/memory/lib/phy/phy_cntrl.H index 3c6df4529..978eee23a 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/phy/phy_cntrl.H +++ b/src/import/chips/p9/procedures/hwp/memory/lib/phy/phy_cntrl.H @@ -67,6 +67,7 @@ class pcTraits<fapi2::TARGET_TYPE_MCA> // MCA phy control registers static const uint64_t PC_ERROR_STATUS0_REG = MCA_DDRPHY_PC_ERROR_STATUS0_P0; static const uint64_t PC_INIT_CAL_ERROR_REG = MCA_DDRPHY_PC_INIT_CAL_ERROR_P0; + static const uint64_t PC_DLL_ZCAL_CAL_STATUS_REG = MCA_DDRPHY_PC_DLL_ZCAL_CAL_STATUS_P0; enum { @@ -88,6 +89,15 @@ class pcTraits<fapi2::TARGET_TYPE_MCA> // How many bits are in the field running from INIT_CAL_ERROR_WR_LEVEL to INIT_CAL_ERROR_VREF // Needed to pull the entire field out of the register. CAL_ERROR_FIELD_LEN = 11, + + DLL_CAL_STATUS_DP_GOOD = MCA_DDRPHY_PC_DLL_ZCAL_CAL_STATUS_P0_DP_GOOD, + DLL_CAL_STATUS_DP_ERROR = MCA_DDRPHY_PC_DLL_ZCAL_CAL_STATUS_P0_DP_ERROR, + DLL_CAL_STATUS_DP_ERROR_FINE = MCA_DDRPHY_PC_DLL_ZCAL_CAL_STATUS_P0_DP_ERROR_FINE, + DLL_CAL_STATUS_ADR_GOOD = MCA_DDRPHY_PC_DLL_ZCAL_CAL_STATUS_P0_ADR_GOOD, + DLL_CAL_STATUS_ADR_ERROR = MCA_DDRPHY_PC_DLL_ZCAL_CAL_STATUS_P0_ADR_ERROR, + DLL_CAL_STATUS_ADR_ERROR_FINE = MCA_DDRPHY_PC_DLL_ZCAL_CAL_STATUS_P0_ADR_ERROR_FINE, + ZCAL_CAL_STATUS_DONE = MCA_DDRPHY_PC_DLL_ZCAL_CAL_STATUS_P0_DONE, + }; }; @@ -97,6 +107,65 @@ namespace pc /// +/// @brief read MCA_DDRPHY_PC_DLL_ZCAL_CAL_STATUS +/// @param[in] i_target the fapi2 target of the port +/// @param[out] o_data the value of the register +/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok +/// +template< fapi2::TargetType T, typename TT = pcTraits<T> > +inline fapi2::ReturnCode read_dll_zcal_status( const fapi2::Target<T>& i_target, fapi2::buffer<uint64_t>& o_data ) +{ + FAPI_TRY( mss::getScom(i_target, TT::PC_DLL_ZCAL_CAL_STATUS_REG, o_data) ); + FAPI_INF("pc_dll_zcal_status: 0x%016llx", o_data); +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Get DP DLL Cal Status +/// Combine the processing of Good, Error and Error Fine into one functional interface +/// @param[in] fapi2::buffer representing the status register to interrogate +/// @return mss::states; YES == success, NO == fail, INVALID == still running +/// @note Since the these indicators are a summary of all DLLs, all must be started to make +/// them valid. +/// +template< fapi2::TargetType T = fapi2::TARGET_TYPE_MCA, typename TT = pcTraits<T> > +inline mss::states get_dll_cal_status( fapi2::buffer<uint64_t>& i_data ) +{ + const bool l_dp_good = i_data.getBit<TT::DLL_CAL_STATUS_DP_GOOD>(); + const bool l_dp_error = i_data.getBit<TT::DLL_CAL_STATUS_DP_ERROR>(); + const bool l_dp_error_fine = i_data.getBit<TT::DLL_CAL_STATUS_DP_ERROR_FINE>(); + + FAPI_INF("pc_dll_status: 0x%016llx", i_data); + + // Full calibration is still going on in at least 1 DLL while all 3 signals are 0. + if ((l_dp_good == mss::LOW) && (l_dp_error == mss::LOW) && (l_dp_error_fine == mss::LOW)) + { + return mss::INVALID; + } + + // Full calibration was successful in all DLLs if CAL_GOOD = 1 and both CAL_ERROR and CAL_ERROR_FINE are 0. + if ((l_dp_good == mss::HIGH) && (l_dp_error == mss::LOW) && (l_dp_error_fine == mss::LOW)) + { + return mss::YES; + } + + // Full calibration failed in at least 1 DLL if either CAL_ERROR or CAL_ERROR_FINE are 1. + // Full calibration was successful in all DLLs if CAL_GOOD = 1 and both CAL_ERROR and CAL_ERROR_FINE are 0. + if ((l_dp_error == mss::HIGH) || (l_dp_error_fine == mss::HIGH)) + { + return mss::NO; + } + + // Not reached ... right? + FAPI_ERR("pc_dll_cal_status: 0x%016llx unable to calculate state", i_data); + fapi2::Assert(false); + return mss::NO; +} + +// MCA_DDRPHY_PC_DLL_ZCAL_CAL_STATUS is read-only + +/// /// @brief read PC_ERROR_STATUS0 /// @param[in] i_target the fapi2 target of the port /// @param[out] o_data the value of the register @@ -106,7 +175,7 @@ template< fapi2::TargetType T, typename TT = pcTraits<T> > inline fapi2::ReturnCode read_error_status0( const fapi2::Target<T>& i_target, fapi2::buffer<uint64_t>& o_data ) { FAPI_TRY( mss::getScom(i_target, TT::PC_ERROR_STATUS0_REG, o_data) ); - FAPI_DBG("pc_error_status0: 0x%016llx", o_data); + FAPI_INF("pc_error_status0: 0x%016llx", o_data); fapi_try_exit: return fapi2::current_err; } @@ -121,7 +190,7 @@ template< fapi2::TargetType T, typename TT = pcTraits<T> > inline fapi2::ReturnCode write_error_status0( const fapi2::Target<T>& i_target, const fapi2::buffer<uint64_t>& i_data ) { - FAPI_DBG("pc_error_status0: 0x%016llx", i_data); + FAPI_INF("pc_error_status0: 0x%016llx", i_data); FAPI_TRY( mss::putScom(i_target, TT::PC_ERROR_STATUS0_REG, i_data) ); fapi_try_exit: return fapi2::current_err; @@ -151,7 +220,7 @@ template< fapi2::TargetType T, typename TT = pcTraits<T> > inline fapi2::ReturnCode read_init_cal_error( const fapi2::Target<T>& i_target, fapi2::buffer<uint64_t>& o_data ) { FAPI_TRY( mss::getScom(i_target, TT::PC_INIT_CAL_ERROR_REG, o_data) ); - FAPI_DBG("pc_init_cal_error: 0x%016llx", o_data); + FAPI_INF("pc_init_cal_error: 0x%016llx", o_data); fapi_try_exit: return fapi2::current_err; } @@ -166,7 +235,7 @@ template< fapi2::TargetType T, typename TT = pcTraits<T> > inline fapi2::ReturnCode write_init_cal_error( const fapi2::Target<T>& i_target, const fapi2::buffer<uint64_t>& i_data ) { - FAPI_DBG("pc_init_cal_error: 0x%016llx", i_data); + FAPI_INF("pc_init_cal_error: 0x%016llx", i_data); FAPI_TRY( mss::putScom(i_target, TT::PC_INIT_CAL_ERROR_REG, i_data) ); fapi_try_exit: return fapi2::current_err; diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/utils/scom.H b/src/import/chips/p9/procedures/hwp/memory/lib/utils/scom.H index 109a9a414..324bd9884 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/utils/scom.H +++ b/src/import/chips/p9/procedures/hwp/memory/lib/utils/scom.H @@ -54,7 +54,8 @@ namespace mss /// @note We wrap scom operations in the mss library so that we can hook /// into them in the lab. For IPL firmware, this should compile out. template< fapi2::TargetType K > -inline fapi2::ReturnCode getScom(const fapi2::Target<K>& i_target, const uint64_t i_address, +inline fapi2::ReturnCode getScom(const fapi2::Target<K>& i_target, + const uint64_t i_address, fapi2::buffer<uint64_t>& o_data) { #ifdef PSYSTEMS_MSS_LAB_ONLY @@ -74,7 +75,8 @@ inline fapi2::ReturnCode getScom(const fapi2::Target<K>& i_target, const uint64_ /// @note We wrap scom operations in the mss library so that we can hook /// into them in the lab. For IPL firmware, this should compile out. template< fapi2::TargetType K > -inline fapi2::ReturnCode putScom(const fapi2::Target<K>& i_target, const uint64_t i_address, +inline fapi2::ReturnCode putScom(const fapi2::Target<K>& i_target, + const uint64_t i_address, const fapi2::buffer<uint64_t> i_data) { #ifdef PSYSTEMS_MSS_LAB_ONLY @@ -120,7 +122,8 @@ inline fapi2::ReturnCode putScomUnderMask(const fapi2::Target<K>& i_target, /// and the FAPI_TRY mechanism, this is the simplest. /// template< fapi2::TargetType T > -fapi2::ReturnCode scom_blastah( const fapi2::Target<T>& i_target, const std::vector<uint64_t>& i_addrs, +fapi2::ReturnCode scom_blastah( const fapi2::Target<T>& i_target, + const std::vector<uint64_t>& i_addrs, const fapi2::buffer<uint64_t>& i_data ) { size_t count(0); @@ -131,7 +134,8 @@ fapi2::ReturnCode scom_blastah( const fapi2::Target<T>& i_target, const std::vec ++count; } - return fapi2::current_err; + // Don't return current_err, if there are no registers in the vector we don't set it. + return fapi2::FAPI2_RC_SUCCESS; fapi_try_exit: FAPI_ERR( "scom_blastah failed: %d of %d executed against %s", count, i_addrs.size(), mss::c_str(i_target)); @@ -140,13 +144,14 @@ fapi_try_exit: /// /// @brief Blast one peice of data across a vector of targets -/// @param[in]i_targets the vector of targets for the scom +/// @param[in] i_targets the vector of targets for the scom /// @param[in] i_addr the address /// @param[in] i_data const fapi2::buffer<uint64_t>& the data to blast /// @return FAPI2_RC_SUCCESS iff ok /// template< fapi2::TargetType T > -fapi2::ReturnCode scom_blastah( const std::vector<fapi2::Target<T> >& i_targets, const uint64_t i_addr, +fapi2::ReturnCode scom_blastah( const std::vector<fapi2::Target<T> >& i_targets, + const uint64_t i_addr, const fapi2::buffer<uint64_t>& i_data ) { size_t count(0); @@ -157,7 +162,8 @@ fapi2::ReturnCode scom_blastah( const std::vector<fapi2::Target<T> >& i_targets, ++count; } - return fapi2::current_err; + // Don't return current_err, if there are no targets in the vector we don't set it. + return fapi2::FAPI2_RC_SUCCESS; fapi_try_exit: FAPI_ERR( "scom_blastah failed: %d of %d written to 0x%llx", count, i_targets.size(), i_addr); @@ -166,7 +172,7 @@ fapi_try_exit: /// /// @brief Blast one peice of data across a vector of targets -/// @param[in]i_targets the vector of targets for the scom +/// @param[in] i_targets the vector of targets for the scom /// @param[in] i_addrs the vector of addresses /// @param[in] i_data const fapi2::buffer<uint64_t>& the data to blast /// @return FAPI2_RC_SUCCESS iff ok @@ -184,13 +190,192 @@ fapi2::ReturnCode scom_blastah( const std::vector<fapi2::Target<T> >& i_targets, ++count; } - return fapi2::current_err; + // Don't return current_err, if there are no targets in the vector we don't set it. + return fapi2::FAPI2_RC_SUCCESS; fapi_try_exit: FAPI_ERR( "scom_blastah failed: %d of %dx%d", count, i_targets.size(), i_addrs.size() ); return fapi2::current_err; } +/// +/// @brief Blast parallel vectors of data and addresses to a single target +/// @param[in] i_target the target for the scom +/// @param[in] i_addrs const std::vector<uint64_t>& addresses +/// @param[in] i_data std:vector<fapi2::buffer<uint64_t>>& the data to blast +/// @return FAPI2_RC_SUCCESS iff ok +/// +template< fapi2::TargetType T > +fapi2::ReturnCode scom_blastah( const fapi2::Target<T>& i_targets, + const std::vector<uint64_t>& i_addrs, + const std::vector<fapi2::buffer<uint64_t>>& i_data ) +{ + size_t count(0); + + // Little sanity check + if (i_data.size() != i_addrs.size()) + { + FAPI_ERR("Passed bad vectors in to scom_blastah: %d and %d in size", i_data.size(), i_addrs.size() ); + return fapi2::FAPI2_RC_INVALID_PARAMETER; + } + + auto l_address = i_addrs.begin(); + auto l_data = i_data.begin(); + + for ( ; l_address != i_addrs.end(); ++l_address, ++l_data ) + { + FAPI_TRY( mss::putScom(i_targets, *l_address, *l_data) ); + ++count; + } + + // Don't return current_err, if there are no registers in the vector we don't set it. + return fapi2::FAPI2_RC_SUCCESS; + +fapi_try_exit: + FAPI_ERR( "parallel scom_blastah failed: %d of %d", count, i_addrs.size() ); + return fapi2::current_err; +} + +/// +/// @brief Blast parallel vectors of data and address pairs to a single target +/// @param[in] i_target the target for the scom +/// @param[in] i_addrs const std::vector<uint64_t>& of address pairs +/// @param[in] i_data std::vector< std::pair<uint64_t, uint64_t>> the data to blast +/// @return FAPI2_RC_SUCCESS iff ok +/// +template< fapi2::TargetType T > +fapi2::ReturnCode scom_blastah( const fapi2::Target<T>& i_targets, + const std::vector< std::pair< uint64_t, uint64_t> >& i_addrs, + const std::vector< std::pair<fapi2::buffer<uint64_t>, fapi2::buffer<uint64_t> > >& i_data ) +{ + size_t count(0); + + // Little sanity check + if (i_data.size() != i_addrs.size()) + { + FAPI_ERR("Passed bad vectors of pairs in to scom_blastah: %d and %d in size", i_data.size(), i_addrs.size() ); + return fapi2::FAPI2_RC_INVALID_PARAMETER; + } + + auto l_address = i_addrs.begin(); + auto l_data = i_data.begin(); + + for ( ; l_address != i_addrs.end(); ++l_address, ++l_data ) + { + FAPI_TRY( mss::putScom(i_targets, l_address->first, l_data->first) ); + FAPI_TRY( mss::putScom(i_targets, l_address->second, l_data->second) ); + ++count; + } + + // Don't return current_err, if there are no registers in the vector we don't set it. + return fapi2::FAPI2_RC_SUCCESS; + +fapi_try_exit: + FAPI_ERR( "parallel pairs scom_blastah failed: %d of %d", count, i_addrs.size() ); + return fapi2::current_err; +} + +/// +/// @brief Blast single data data to a vector of address pairs to a single target +/// @param[in] i_target the target for the scom +/// @param[in] i_addrs const std::vector< std::pair<uint64_t, uint64_t> >& of address pairs +/// @param[in] i_data uint64_t the data to blast +/// @return FAPI2_RC_SUCCESS iff ok +/// +template< fapi2::TargetType T > +fapi2::ReturnCode scom_blastah( const fapi2::Target<T>& i_targets, + const std::vector< std::pair< uint64_t, uint64_t> >& i_addr, + const fapi2::buffer<uint64_t>& i_data ) +{ + size_t count(0); + + for (auto a = i_addr.begin(); a != i_addr.end(); ++a) + { + FAPI_TRY( mss::putScom(i_targets, a->first, i_data) ); + FAPI_TRY( mss::putScom(i_targets, a->second, i_data) ); + ++count; + } + + // Don't return current_err, if there are no registers in the vector we don't set it. + return fapi2::FAPI2_RC_SUCCESS; + +fapi_try_exit: + FAPI_ERR( "pairs scom_blastah failed: %d of %d", count, i_addr.size() ); + return fapi2::current_err; +} + +/// +/// @brief Suck one peice of data from a vector of addresses +/// @tparam T the fapi2::TargetType of the target +/// @param[in] i_target the target for the scom +/// @param[in] i_addr the vector of addresses +/// @param[in] o_data std::vector<uint64_t> the resulting data +/// @return FAPI2_RC_SUCCESS iff ok +/// @note Author is originally from Boston (Pahk mah cah in Havahd Yahd) +/// +template< fapi2::TargetType T > +fapi2::ReturnCode scom_suckah( const fapi2::Target<T>& i_target, + const std::vector<uint64_t>& i_addr, + std::vector< fapi2::buffer<uint64_t> >& o_data ) +{ + size_t count(0); + fapi2::buffer<uint64_t> l_read; + + o_data.clear(); + + for (const auto& a : i_addr) + { + FAPI_TRY( mss::getScom(i_target, a, l_read) ); + o_data.push_back(l_read); + ++count; + } + + // Don't return current_err, if there are no registers in the vector we don't set it. + return fapi2::FAPI2_RC_SUCCESS; + +fapi_try_exit: + FAPI_ERR( "scom_suckah failed: %d of %d executed against %s", count, i_addr.size(), mss::c_str(i_target)); + return fapi2::current_err; +} + + +/// +/// @brief Suck one peice of data from a vector of address pairs +/// @tparam T the fapi2::TargetType of the target +/// @tparam B a begin iterator +/// @tparam E an end iterator +/// @param[in] i_target the target for the scom +/// @param[in] i_addr a vector of address pairs +/// @param[in] o_data std::vector< std::pair<uint64_t, uint64_t>> the resulting data +/// @return FAPI2_RC_SUCCESS iff ok +/// @note Author is originally from Boston (Pahk mah cah in Havahd Yahd) +/// +template< fapi2::TargetType T > +fapi2::ReturnCode scom_suckah( const fapi2::Target<T>& i_target, + const std::vector< std::pair< uint64_t, uint64_t> >& i_addr, + std::vector< std::pair<fapi2::buffer<uint64_t>, fapi2::buffer<uint64_t> > >& o_data ) +{ + size_t count(0); + std::pair< fapi2::buffer<uint64_t>, fapi2::buffer<uint64_t> > l_read; + + o_data.clear(); + + for (const auto& a : i_addr) + { + FAPI_TRY( mss::getScom(i_target, a.first, l_read.first) ); + FAPI_TRY( mss::getScom(i_target, a.second, l_read.second) ); + o_data.push_back( l_read ); + ++count; + } + + // Don't return current_err, if there are no registers in the vector we don't set it. + return fapi2::FAPI2_RC_SUCCESS; + +fapi_try_exit: + FAPI_ERR( "scom_suckah failed: %d of %d executed against %s", count, i_addr.size(), mss::c_str(i_target)); + return fapi2::current_err; +} + } #endif diff --git a/src/import/chips/p9/procedures/hwp/memory/p9_mss_ddr_phy_reset.C b/src/import/chips/p9/procedures/hwp/memory/p9_mss_ddr_phy_reset.C index 7d1821b4c..57607a8ea 100644 --- a/src/import/chips/p9/procedures/hwp/memory/p9_mss_ddr_phy_reset.C +++ b/src/import/chips/p9/procedures/hwp/memory/p9_mss_ddr_phy_reset.C @@ -77,6 +77,17 @@ extern "C" FAPI_TRY( mss::deassert_pll_reset(i_target) ); // + // DLL calibration + // + + // 14. Begin DLL calibrations by setting INIT_RXDLL_CAL_RESET=0 in the DDRPHY_DP16_DLL_CNTL{0:1} registers + // and DDRPHY_ADR_DLL_CNTL registers + // 15. Monitor the DDRPHY_PC_DLL_ZCAL_CAL_STATUS register to determine when calibration is + // complete. One of the 3 bits will be asserted for ADR and DP16. + FAPI_INF( "starting DLL calibration %s", mss::c_str(i_target) ); + FAPI_TRY( mss::dll_calibration(i_target) ); + + // // Start bang-bang-lock // |