diff options
Diffstat (limited to 'src/import/chips/p9/procedures/hwp/memory/lib/workarounds/wr_vref_workarounds.C')
-rw-r--r-- | src/import/chips/p9/procedures/hwp/memory/lib/workarounds/wr_vref_workarounds.C | 92 |
1 files changed, 91 insertions, 1 deletions
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/wr_vref_workarounds.C b/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/wr_vref_workarounds.C index b9426fe94..3fbc51f9a 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/wr_vref_workarounds.C +++ b/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/wr_vref_workarounds.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* Contributors Listed Below - COPYRIGHT 2016,2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -38,6 +38,10 @@ #include <fapi2.H> #include <lib/workarounds/dp16_workarounds.H> #include <lib/workarounds/wr_vref_workarounds.H> +#include <lib/phy/dp16.H> +#include <lib/dimm/ddr4/latch_wr_vref.H> +#include <lib/dimm/ddr4/nvdimm_utils.H> +#include <generic/memory/lib/utils/scom.H> namespace mss { @@ -79,6 +83,92 @@ fapi_try_exit: return fapi2::current_err; } +/// +/// @brief Executes the nvdimm workaround +/// @param[in] i_target - the MCA target on which to operate +/// @param[in] i_rp - the rank pair +/// @param[in] i_abort_on_error - whether or not we are aborting on cal error +/// @return fapi2::ReturnCode fapi2::FAPI2_RC_SUCCESS iff ok +/// +fapi2::ReturnCode nvdimm_workaround( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target, + const uint64_t i_rp, + const uint8_t i_abort_on_error ) +{ + FAPI_INF("nvdimm_workaround() on %s RP%lu ", mss::c_str(i_target), i_rp); + + // traits definition + typedef dp16Traits<fapi2::TARGET_TYPE_MCA> TT; + constexpr uint64_t DRAMS_PER_RP = 18; + std::vector<std::pair<uint64_t, uint64_t>> l_wr_vref_regs; + std::vector<std::pair<fapi2::buffer<uint64_t>, fapi2::buffer<uint64_t>>> l_wr_vref_regs_values; + std::vector<uint64_t> l_composite_values; + + // Get the wr_vref regs by rp and then suck out all the data + FAPI_TRY(mss::dp16::wr_vref::get_wr_vref_regs_by_rp(i_rp, l_wr_vref_regs)); + FAPI_TRY(mss::scom_suckah(i_target, l_wr_vref_regs, l_wr_vref_regs_values)); + + for (const auto l_wr_vref_pair : l_wr_vref_regs_values) + { + // Get the composite values from the first reg. We don't really care which value belongs to which + // dram here since we only need the median value + mss::nvdimm::wr_vref::get_wr_vref_composite_value_helper(l_wr_vref_pair.first, l_composite_values); + + // Abort if we have enough... + // This excludes the non-existent on DP4 + if (l_composite_values.size() == DRAMS_PER_RP) + { + break; + } + + // Repeat for the second reg + mss::nvdimm::wr_vref::get_wr_vref_composite_value_helper(l_wr_vref_pair.second, l_composite_values); + } + + // Get the median + { + // Sort by the "first" of each pair + std::sort(l_composite_values.begin(), l_composite_values.end()); + + // I'm assuming we always have even number of DRAMs here... + const uint64_t MID_POINT = DRAMS_PER_RP / 2; + + // Average the two mid-point values + const uint64_t l_wr_vref_med_avg = ( l_composite_values[MID_POINT] + + l_composite_values[MID_POINT - 1] ) / 2; + + FAPI_INF("nvdimm_workaround() - l_wr_vref_med_avg: 0x%016lx", l_wr_vref_med_avg); + + // Convert to JEDEC language + const uint8_t l_jedec_med_value = mss::dp16::wr_vref::get_value(l_wr_vref_med_avg); + const uint8_t l_jedec_med_range = mss::dp16::wr_vref::get_range(l_wr_vref_med_avg); + fapi2::buffer<uint64_t> l_wr_vref_med_data; + + FAPI_INF("nvdimm_workaround() - median jedec: value = 0x%02x, range = 0x%02x", l_jedec_med_value, l_jedec_med_range); + + // Set up the reg with the median value + l_wr_vref_med_data.insertFromRight<TT::WR_VREF_VALUE_VALUE_DRAM_EVEN, TT::WR_VREF_VALUE_VALUE_DRAM_EVEN_LEN> + (l_jedec_med_value); + l_wr_vref_med_data.insertFromRight<TT::WR_VREF_VALUE_VALUE_DRAM_ODD, TT::WR_VREF_VALUE_VALUE_DRAM_ODD_LEN> + (l_jedec_med_value); + + l_wr_vref_med_data.writeBit<TT::WR_VREF_VALUE_RANGE_DRAM_EVEN>(l_jedec_med_range); + l_wr_vref_med_data.writeBit<TT::WR_VREF_VALUE_RANGE_DRAM_ODD>(l_jedec_med_range); + + // Set the phy with the median value + FAPI_TRY(mss::scom_blastah(i_target, l_wr_vref_regs, l_wr_vref_med_data)); + + // Latches the median wr_vref + FAPI_TRY( mss::ddr4::latch_wr_vref_commands_by_rank_pair(i_target, + i_rp, + l_jedec_med_range, + l_jedec_med_value) ); + } + + return fapi2::FAPI2_RC_SUCCESS; +fapi_try_exit: + return fapi2::current_err; +} + } // close namespace wr_vref } // close namespace workarounds } // close namespace mss |