summaryrefslogtreecommitdiffstats
path: root/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/wr_vref_workarounds.C
diff options
context:
space:
mode:
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.C92
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
OpenPOWER on IntegriCloud