summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/dimm/rank.C76
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/dimm/rank.H324
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/mc/port.C19
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/mc/port.H32
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/phy/ddr_phy.C180
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/phy/ddr_phy.H37
6 files changed, 533 insertions, 135 deletions
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rank.C b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rank.C
index 13642122e..011f801b5 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rank.C
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rank.C
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2015,2016 */
+/* Contributors Listed Below - COPYRIGHT 2015,2017 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -82,7 +82,7 @@ namespace rank
{
//
-// Static table of rank pair assignments. Some of thoem won't be valid depending on
+// Static table of rank pair assignments. Some of them won't be valid depending on
// the plug rules (which may be OpenPOWER, IBM, etc.) Some also won't make sense
// -- 3 rank DIMM? -- but it doesn't take up much space and lord knows stranger things
// have happened ... Won't hurt to have this defined JustInCase(tm).
@@ -92,11 +92,11 @@ namespace rank
// TODO RTC 160869: Review hard coded values, possibly make into traits?
static const std::vector< std::vector< std::pair< uint64_t, uint64_t > > > rank_pair_assignments =
{
- { {0x0000, 0x0000}, {0x1000, 0x0000}, {0x1030, 0x0000}, {0x1030, 0x5000}, {0x1030, 0x5070} },
- { {0x9000, 0x0000}, {0x1090, 0x0000}, {0x1090, 0x3000}, {0x1090, 0x3050}, {0x1090, 0x5730} },
- { {0x90B0, 0x0000}, {0x1090, 0xB000}, {0x1090, 0x30B0}, {0x1390, 0x50B0}, {0x1390, 0x57B0} },
- { {0x90B0, 0xD000}, {0x1090, 0xB0D0}, {0x109B, 0x30D0}, {0x139B, 0x50D0}, {0x139B, 0x57D0} },
- { {0x90B0, 0xD0F0}, {0x1090, 0xB0DF}, {0x109B, 0x30DF}, {0x139B, 0x50DF}, {0x139B, 0x57DF} },
+ { {0x0000, 0x0000}, {0x1000, 0x0000}, {0x1030, 0x0000}, {0x1530, 0x0000}, {0x1537, 0x0000} },
+ { {0x0000, 0x9000}, {0x1000, 0x9000}, {0x1030, 0x9000}, {0x1530, 0x9000}, {0x1537, 0x9000} },
+ { {0x0000, 0x90B0}, {0x1000, 0x90B0}, {0x1030, 0x90B0}, {0x1530, 0x90B0}, {0x1537, 0x90B0} },
+ { {0x0000, 0x9DB0}, {0x1000, 0x9DB0}, {0x1030, 0x9DB0}, {0x1530, 0x9DB0}, {0x1537, 0x9DB0} },
+ { {0x0000, 0x9DBF}, {0x1000, 0x9DBF}, {0x1030, 0x9DBF}, {0x1530, 0x9DBF}, {0x1537, 0x9DBF} },
};
//
@@ -106,11 +106,11 @@ static const std::vector< std::vector< std::pair< uint64_t, uint64_t > > > rank_
//
static const std::vector< std::vector< std::vector< uint64_t > > > primary_rank_pairs =
{
- { {}, {0}, {0, 1}, {0, 1, 2}, {0, 1, 2, 3} },
- { {4}, {0, 4}, {0, 4, 1}, {0, 4, 2, 1}, {0, 4, 2, 1} },
- { {4, 5}, {0, 4, 5}, {0, 4, 1, 5}, {0, 4, 2, 5}, {0, 4, 2, 5} },
- { {4, 5}, {0, 4, 5}, {0, 4, 1, 5}, {0, 4, 2, 5}, {0, 4, 2, 5} },
- { {4, 5, 6, 7}, {0, 4, 5, 6}, {0, 4, 1, 6}, {0, 4, 2, 6}, {0, 4, 2, 6} },
+ { {}, {0}, {0, 1}, {0, 1}, {0, 1} },
+ { {NO_RANK, NO_RANK, 4}, {0, NO_RANK, 4}, {0, 1, 4}, {0, 1, 4}, {0, 1, 4} },
+ { {NO_RANK, NO_RANK, 4, 5}, {0, NO_RANK, 4, 5}, {0, 1, 4, 5}, {0, 1, 4, 5}, {0, 1, 4, 5} },
+ { {NO_RANK, NO_RANK, 4, 5}, {0, NO_RANK, 4, 5}, {0, 1, 4, 5}, {0, 1, 4, 5}, {0, 1, 4, 5} },
+ { {NO_RANK, NO_RANK, 4, 5}, {0, NO_RANK, 4, 5}, {0, 1, 4, 5}, {0, 1, 4, 5}, {0, 1, 4, 5} },
};
//
@@ -123,17 +123,6 @@ static const std::vector< std::vector< std::vector< uint64_t > > > single_dimm_r
{ {}, {4}, {4, 5}, {4, 5, 6}, {4, 5, 6, 7} },
};
-// These fields represent the rank fields and valid bits from rank_pair_assignments
-constexpr uint64_t EVEN_PRIMARY_RANK = 48;
-constexpr uint64_t EVEN_SECONDARY_RANK = 52;
-constexpr uint64_t ODD_PRIMARY_RANK = 56;
-constexpr uint64_t ODD_SECONDARY_RANK = 60;
-constexpr uint64_t RANK_LEN = 3;
-constexpr uint64_t EVEN_PRIMARY_VALID = 51;
-constexpr uint64_t EVEN_SECONDARY_VALID = 55;
-constexpr uint64_t ODD_PRIMARY_VALID = 59;
-constexpr uint64_t ODD_SECONDARY_VALID = 63;
-
///
/// @brief Return true iff this rank is on thie DIMM
/// @param[in] i_target representing the DIMM
@@ -186,7 +175,7 @@ size_t get_dimm_from_rank(const uint64_t i_rank)
}
///
-/// @brief Return a vector of rank numbers which represent the primary rank pairs for this dimm
+/// @brief Return a vector of rank numbers which represent the primary rank pairs for this port
/// @tparam T the target type
/// @param[in] i_target TARGET_TYPE_MCA
/// @param[out] o_rps a vector of rank_pairs
@@ -200,13 +189,23 @@ fapi2::ReturnCode primary_ranks( const fapi2::Target<TARGET_TYPE_MCA>& i_target,
// Get the count of rank pairs for both DIMM on the port
std::vector<uint8_t> l_rank_count(MAX_DIMM_PER_PORT, 0);
- for (auto d : i_target.getChildren<TARGET_TYPE_DIMM>())
+ for (const auto d : mss::find_targets<fapi2::TARGET_TYPE_DIMM>(i_target))
{
FAPI_TRY( mss::eff_num_master_ranks_per_dimm(d, l_rank_count[mss::index(d)]) );
}
FAPI_DBG("ranks: %d, %d", l_rank_count[0], l_rank_count[1]);
- o_rps = primary_rank_pairs[l_rank_count[1]][l_rank_count[0]];
+
+ // Walk through rank pair table and skip empty pairs
+ o_rps.clear();
+
+ for (const auto l_rank : primary_rank_pairs[l_rank_count[1]][l_rank_count[0]])
+ {
+ if (l_rank != NO_RANK)
+ {
+ o_rps.push_back(l_rank);
+ }
+ }
fapi_try_exit:
return fapi2::current_err;
@@ -229,7 +228,7 @@ fapi2::ReturnCode primary_ranks( const fapi2::Target<TARGET_TYPE_DIMM>& i_target
o_rps.clear();
- for (auto r : l_prs)
+ for (const auto r : l_prs)
{
if (is_rank_on_dimm(i_target, r))
{
@@ -272,7 +271,7 @@ fapi2::ReturnCode ranks( const fapi2::Target<TARGET_TYPE_MCA>& i_target, std::ve
std::vector< uint64_t > l_ranks;
o_ranks.clear();
- for (auto d : i_target.getChildren<TARGET_TYPE_DIMM>())
+ for (const auto d : mss::find_targets<fapi2::TARGET_TYPE_DIMM>(i_target))
{
FAPI_TRY( ranks(d, l_ranks) );
o_ranks.insert(o_ranks.end(), l_ranks.begin(), l_ranks.end());
@@ -300,7 +299,7 @@ fapi2::ReturnCode get_rank_pair_assignments(const fapi2::Target<TARGET_TYPE_MCA>
// Get the count of rank pairs for all DIMM on the port
std::vector<uint8_t> l_rank_count(MAX_DIMM_PER_PORT, 0);
- for (auto d : i_target.getChildren<TARGET_TYPE_DIMM>())
+ for (const auto d : mss::find_targets<fapi2::TARGET_TYPE_DIMM>(i_target))
{
FAPI_TRY( mss::eff_num_master_ranks_per_dimm(d, l_rank_count[mss::index(d)]) );
}
@@ -423,18 +422,29 @@ fapi_try_exit:
template<>
fapi2::ReturnCode get_rank_pairs(const fapi2::Target<TARGET_TYPE_MCA>& i_target, std::vector<uint64_t>& o_pairs)
{
- std::vector< uint64_t > l_prs;
uint64_t l_index = 0;
+ std::vector<uint64_t> l_prs;
- FAPI_TRY( primary_ranks(i_target, l_prs) );
+ // Get the count of rank pairs for both DIMM on the port
+ std::vector<uint8_t> l_rank_count(MAX_DIMM_PER_PORT, 0);
+ for (const auto d : mss::find_targets<fapi2::TARGET_TYPE_DIMM>(i_target))
+ {
+ FAPI_TRY( mss::eff_num_master_ranks_per_dimm(d, l_rank_count[mss::index(d)]) );
+ }
+
+ // Walk through rank pair table and skip empty pairs
o_pairs.clear();
+ l_prs = primary_rank_pairs[l_rank_count[1]][l_rank_count[0]];
// Can't use for (auto rp : l_prs) as rp is unused. BRS
for (auto rp_iter = l_prs.begin(); rp_iter != l_prs.end(); ++rp_iter)
{
- o_pairs.push_back(l_index);
- l_index += 1;
+ if (*rp_iter != NO_RANK)
+ {
+ o_pairs.push_back(l_index);
+ l_index += 1;
+ }
}
fapi_try_exit:
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rank.H b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rank.H
index 74cfbe566..9ae319a16 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rank.H
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rank.H
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2015,2016 */
+/* Contributors Listed Below - COPYRIGHT 2015,2017 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -42,6 +42,7 @@
#include <p9_mc_scom_addresses_fld.H>
#include <lib/utils/scom.H>
#include <lib/utils/num.H>
+#include <lib/utils/count_dimm.H>
namespace mss
{
@@ -53,6 +54,18 @@ enum
TERTIARY = 2,
QUATERNARY = 3,
NO_RANK = 999,
+
+ // These enums represent the rank fields and valid bits from rank_pair_assignments
+ EVEN_PRIMARY_RANK = 48,
+ EVEN_SECONDARY_RANK = 52,
+ ODD_PRIMARY_RANK = 56,
+ ODD_SECONDARY_RANK = 60,
+ RANK_LEN = 3,
+ EVEN_PRIMARY_VALID = 51,
+ EVEN_SECONDARY_VALID = 55,
+ ODD_PRIMARY_VALID = 59,
+ ODD_SECONDARY_VALID = 63,
+
};
///
@@ -290,6 +303,284 @@ namespace rank
{
///
+/// @brief Maps a rank's canonical number to the proper ordinal number for the PHY
+/// @param[in] i_count the number of DIMM to be considered
+/// @param[in] i_rank the rank number to be mapped
+/// @return the mapped value
+// i_rank passed by value to save a local variable in the caller
+///
+template <fapi2::TargetType T>
+inline uint64_t map_rank_ordinal_to_phy( const size_t i_count, const uint64_t i_rank );
+
+///
+/// @brief Maps a rank's canonical number to the proper ordinal number for the PHY
+/// @param[in] i_count the number of DIMM to be considered
+/// @param[in] i_rank the rank number to be mapped
+/// @return the mapped value
+// i_rank passed by value to save a local
+///
+template <>
+inline uint64_t map_rank_ordinal_to_phy<fapi2::TARGET_TYPE_MCA>( const size_t i_count, const uint64_t i_rank )
+{
+ if (i_count == 0)
+ {
+ FAPI_ERR("seeing 0 DIMM?");
+ fapi2::Assert(false);
+ }
+
+ if ((i_count == MAX_DIMM_PER_PORT) && (i_rank >= RANK_MID_POINT))
+ {
+ return i_rank - MAX_RANKS_DIMM1;
+ }
+
+ // Nothing to do in the single drop case. Nothing to do for {0,1} on a dual drop either
+ return i_rank;
+}
+
+///
+/// @brief Maps a rank's canonical number to the proper ordinal number for the PHY
+/// @param[in] i_target the fapi2 target of the MCA
+/// @param[in] i_rank the rank number to be mapped
+/// @return the mapped value
+// i_rank passed by value to save a local
+///
+inline uint64_t map_rank_ordinal_to_phy( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target, const uint64_t i_rank )
+{
+ return map_rank_ordinal_to_phy<fapi2::TARGET_TYPE_MCA>(count_dimm(i_target), i_rank);
+}
+
+///
+/// @brief Maps a ranks canonical number to the proper ordinal number
+/// for the PHY
+/// @param[in] i_target the fapi2 target of the MBA
+/// @param[in] i_rank the rank number to be mapped
+/// @return the mapped value
+// i_rank passed by value to save a local
+///
+inline uint64_t map_rank_ordinal_to_phy( const fapi2::Target<fapi2::TARGET_TYPE_MBA>& i_target, const uint64_t i_rank )
+{
+ // NOOP for Centaur
+ return i_rank;
+}
+
+///
+/// @brief Maps a rank's canonical number from the proper ordinal number for the PHY
+/// @param[in] i_count the number of DIMM to be considered
+/// @param[in] i_rank the rank number to be mapped
+/// @return the mapped value
+// i_rank passed by value to save a local
+///
+template <fapi2::TargetType T>
+inline uint64_t map_rank_ordinal_from_phy( const size_t i_count, const uint64_t i_rank );
+
+///
+/// @brief Maps a rank's canonical number from the proper ordinal number for the PHY
+/// @param[in] i_count the number of DIMM to be considered
+/// @param[in] i_rank the rank number to be mapped
+/// @return the mapped value
+// i_rank passed by value to save a local
+///
+template <>
+inline uint64_t map_rank_ordinal_from_phy<fapi2::TARGET_TYPE_MCA>( const size_t i_count, const uint64_t i_rank )
+{
+ if (i_count == 0)
+ {
+ FAPI_ERR("seeing 0 DIMM?");
+ fapi2::Assert(false);
+ }
+
+ if ((i_count == MAX_DIMM_PER_PORT) && ((i_rank + MAX_RANKS_DIMM1) >= RANK_MID_POINT))
+ {
+ return i_rank + MAX_RANKS_DIMM1;
+ }
+
+ // Nothing to do in the single drop case. Nothing to do for {0,1} on a dual drop either
+ return i_rank;
+}
+
+///
+/// @brief Maps a rank's canonical number from the proper ordinal number for the PHY
+/// @param[in] i_target the fapi2 target of the MCA
+/// @param[in] i_rank the rank number to be mapped
+/// @return the mapped value
+// i_rank passed by value to save a local
+///
+inline uint64_t map_rank_ordinal_from_phy( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_rank )
+{
+ return map_rank_ordinal_from_phy<fapi2::TARGET_TYPE_MCA>(count_dimm(i_target), i_rank);
+}
+
+///
+/// @brief Maps a ranks canonical number to the proper ordinal number
+/// for the PHY
+/// @param[in] i_target the fapi2 target of the MBA
+/// @param[in] i_rank the rank number to be mapped
+/// @return the mapped value
+// i_rank passed by value to save a local
+///
+inline uint64_t map_rank_ordinal_from_phy( const fapi2::Target<fapi2::TARGET_TYPE_MBA>& i_target,
+ const uint64_t i_rank )
+{
+ // NOOP for Centaur
+ return i_rank;
+}
+
+///
+/// @brief Convert rank indexes in a rank_pair reg value from MC perspective to PHY perspective
+/// @tparam T fapi2 Target Type the type of the MC target
+/// @param[in] i_count the number of DIMM to be considered
+/// @param[in] i_rp_reg value of RANK_PAIR register
+/// @param[in, out] io_data the register value with mapped rank indexes
+///
+template< fapi2::TargetType T >
+inline void map_rank_pair_to_phy( const size_t i_count,
+ const fapi2::buffer<uint64_t>& i_rp_reg_value,
+ fapi2::buffer<uint64_t>& io_data );
+
+///
+/// @brief Convert rank indexes in a rank_pair reg value from MC perspective to PHY perspective
+/// Specialization for TARGET_TYPE_MCA
+/// @param[in] i_count the number of DIMM to be considered
+/// @param[in] i_rp_reg value of RANK_PAIR register
+/// @param[in, out] io_data the register value with mapped rank indexes
+///
+template<>
+inline void map_rank_pair_to_phy<fapi2::TARGET_TYPE_MCA>( const size_t i_count,
+ const fapi2::buffer<uint64_t>& i_rp_reg_value,
+ fapi2::buffer<uint64_t>& io_data )
+{
+ uint64_t l_rank = 0;
+
+ // copy over so we get the valid bits
+ io_data = i_rp_reg_value;
+
+ // No mapping necessary if single drop
+ if (i_count != 1)
+ {
+ i_rp_reg_value.extractToRight<EVEN_PRIMARY_RANK, RANK_LEN>(l_rank);
+ l_rank = map_rank_ordinal_to_phy<fapi2::TARGET_TYPE_MCA>(i_count, l_rank);
+ io_data.insertFromRight<EVEN_PRIMARY_RANK, RANK_LEN>(l_rank);
+
+ i_rp_reg_value.extractToRight<EVEN_SECONDARY_RANK, RANK_LEN>(l_rank);
+ l_rank = map_rank_ordinal_to_phy<fapi2::TARGET_TYPE_MCA>(i_count, l_rank);
+ io_data.insertFromRight<EVEN_SECONDARY_RANK, RANK_LEN>(l_rank);
+
+ i_rp_reg_value.extractToRight<ODD_PRIMARY_RANK, RANK_LEN>(l_rank);
+ l_rank = map_rank_ordinal_to_phy<fapi2::TARGET_TYPE_MCA>(i_count, l_rank);
+ io_data.insertFromRight<ODD_PRIMARY_RANK, RANK_LEN>(l_rank);
+
+ i_rp_reg_value.extractToRight<ODD_SECONDARY_RANK, RANK_LEN>(l_rank);
+ l_rank = map_rank_ordinal_to_phy<fapi2::TARGET_TYPE_MCA>(i_count, l_rank);
+ io_data.insertFromRight<ODD_SECONDARY_RANK, RANK_LEN>(l_rank);
+ }
+}
+
+///
+/// @brief Convert rank indexes in a rank_pair reg value from MC perspective to PHY perspective
+/// @param[in] i_target the fapi2 target of the MCA
+/// @param[in] i_rp_reg value of RANK_PAIR register
+/// @param[in, out] io_data the register value with mapped rank indexes
+///
+inline void map_rank_pair_to_phy( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const fapi2::buffer<uint64_t>& i_rp_reg_value,
+ fapi2::buffer<uint64_t>& io_data )
+{
+ map_rank_pair_to_phy<fapi2::TARGET_TYPE_MCA>(count_dimm(i_target), i_rp_reg_value, io_data);
+}
+
+///
+/// @brief Convert rank indexes in a rank_pair reg value from MC perspective to PHY perspective
+/// @param[in] i_target the fapi2 target of the MCA
+/// @param[in] i_rp_reg value of RANK_PAIR register
+/// @param[in, out] io_data the register value with mapped rank indexes
+///
+inline void map_rank_pair_to_phy( const fapi2::Target<fapi2::TARGET_TYPE_MBA>& i_target,
+ const fapi2::buffer<uint64_t>& i_rp_reg_value,
+ fapi2::buffer<uint64_t>& io_data )
+{
+ // NOOP for Centaur
+ io_data = i_rp_reg_value;
+}
+
+///
+/// @brief Convert rank indexes in a rank_pair reg value from PHY perspective to MC perspective
+/// @tparam T fapi2 Target Type the type of the MC target
+/// @param[in] i_count the number of DIMM to be considered
+/// @param[in] i_rp_reg value of RANK_PAIR register
+/// @param[in, out] io_data the register value with mapped rank indexes
+///
+template< fapi2::TargetType T >
+inline void map_rank_pair_from_phy( const size_t i_count,
+ const fapi2::buffer<uint64_t>& i_rp_reg_value,
+ fapi2::buffer<uint64_t>& io_data );
+
+///
+/// @brief Convert rank indexes in a rank_pair reg value from PHY perspective to MC perspective
+/// Specialization for TARGET_TYPE_MCA
+/// @param[in] i_count the number of DIMM to be considered
+/// @param[in] i_rp_reg value of RANK_PAIR register
+/// @param[in, out] io_data the register value with mapped rank indexes
+///
+template<>
+inline void map_rank_pair_from_phy<fapi2::TARGET_TYPE_MCA>( const size_t i_count,
+ const fapi2::buffer<uint64_t>& i_rp_reg_value,
+ fapi2::buffer<uint64_t>& io_data )
+{
+ uint64_t l_rank = 0;
+
+ // copy over so we get the valid bits
+ io_data = i_rp_reg_value;
+
+ // No mapping necessary if single drop
+ if (i_count != 1)
+ {
+ i_rp_reg_value.extractToRight<EVEN_PRIMARY_RANK, RANK_LEN>(l_rank);
+ l_rank = map_rank_ordinal_from_phy<fapi2::TARGET_TYPE_MCA>(i_count, l_rank);
+ io_data.insertFromRight<EVEN_PRIMARY_RANK, RANK_LEN>(l_rank);
+
+ i_rp_reg_value.extractToRight<EVEN_SECONDARY_RANK, RANK_LEN>(l_rank);
+ l_rank = map_rank_ordinal_from_phy<fapi2::TARGET_TYPE_MCA>(i_count, l_rank);
+ io_data.insertFromRight<EVEN_SECONDARY_RANK, RANK_LEN>(l_rank);
+
+ i_rp_reg_value.extractToRight<ODD_PRIMARY_RANK, RANK_LEN>(l_rank);
+ l_rank = map_rank_ordinal_from_phy<fapi2::TARGET_TYPE_MCA>(i_count, l_rank);
+ io_data.insertFromRight<ODD_PRIMARY_RANK, RANK_LEN>(l_rank);
+
+ i_rp_reg_value.extractToRight<ODD_SECONDARY_RANK, RANK_LEN>(l_rank);
+ l_rank = map_rank_ordinal_from_phy<fapi2::TARGET_TYPE_MCA>(i_count, l_rank);
+ io_data.insertFromRight<ODD_SECONDARY_RANK, RANK_LEN>(l_rank);
+ }
+}
+
+///
+/// @brief Convert rank indexes in a rank_pair reg value from PHY perspective to MC perspective
+/// @param[in] i_target the fapi2 target of the MCA
+/// @param[in] i_rp_reg value of RANK_PAIR register
+/// @param[in, out] io_data the register value with mapped rank indexes
+///
+inline void map_rank_pair_from_phy( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const fapi2::buffer<uint64_t>& i_rp_reg_value,
+ fapi2::buffer<uint64_t>& io_data )
+{
+ map_rank_pair_from_phy<fapi2::TARGET_TYPE_MCA>(count_dimm(i_target), i_rp_reg_value, io_data);
+}
+
+///
+/// @brief Convert rank indexes in a rank_pair reg value from PHY perspective to MC perspective
+/// @param[in] i_target the fapi2 target of the MCA
+/// @param[in] i_rp_reg value of RANK_PAIR register
+/// @param[in, out] io_data the register value with mapped rank indexes
+///
+inline void map_rank_pair_from_phy( const fapi2::Target<fapi2::TARGET_TYPE_MBA>& i_target,
+ const fapi2::buffer<uint64_t>& i_rp_reg_value,
+ fapi2::buffer<uint64_t>& io_data )
+{
+ // NOOP for Centaur
+ io_data = i_rp_reg_value;
+}
+
+///
/// @brief Return a vector of rank numbers which represent the ranks for this dimm
/// @tparam T the target type you'd like the associated ranks for
/// @param[in] i_target
@@ -379,9 +670,11 @@ fapi2::ReturnCode get_pair_from_rank(const fapi2::Target<T>& i_target, const uin
template< uint64_t RP, uint64_t N, fapi2::TargetType T, typename TT = rankPairTraits<T, RP> >
inline fapi2::ReturnCode read_rank_pair_reg( const fapi2::Target<T>& i_target, fapi2::buffer<uint64_t>& o_data )
{
+ fapi2::buffer<uint64_t> l_buf;
static_assert((N < TT::NUM_RANK_PAIR_REGS), "Rank pair register index failed range check");
- FAPI_TRY( mss::getScom(i_target, TT::RANK_PAIR_REGS[N], o_data) );
- FAPI_INF("read_rank_pair_reg: 0x%016lx", o_data);
+ FAPI_TRY( mss::getScom(i_target, TT::RANK_PAIR_REGS[N], l_buf) );
+ FAPI_INF("read_rank_pair_reg: 0x%016lx", l_buf);
+ map_rank_pair_from_phy(i_target, l_buf, o_data);
fapi_try_exit:
return fapi2::current_err;
}
@@ -399,9 +692,11 @@ fapi_try_exit:
template< uint64_t RP, uint64_t N, fapi2::TargetType T, typename TT = rankPairTraits<T, RP> >
inline fapi2::ReturnCode write_rank_pair_reg( const fapi2::Target<T>& i_target, const fapi2::buffer<uint64_t>& i_data )
{
+ fapi2::buffer<uint64_t> l_buf;
static_assert((N < TT::NUM_RANK_PAIR_REGS), "Rank pair register index failed range check");
- FAPI_TRY( mss::putScom(i_target, TT::RANK_PAIR_REGS[N], i_data) );
- FAPI_INF("write_rank_pair_reg: 0x%016lx", i_data);
+ map_rank_pair_to_phy(i_target, i_data, l_buf);
+ FAPI_TRY( mss::putScom(i_target, TT::RANK_PAIR_REGS[N], l_buf) );
+ FAPI_INF("write_rank_pair_reg: 0x%016lx", l_buf);
fapi_try_exit:
return fapi2::current_err;
}
@@ -730,10 +1025,15 @@ fapi2::ReturnCode set_ranks_in_pair( const fapi2::Target<T>& i_target,
}
// Read the rank pair register(s)
+ fapi2::buffer<uint64_t> l_reg;
std::vector<fapi2::buffer<uint64_t>> l_data;
uint64_t l_ordinal = 0;
- FAPI_TRY( scom_suckah(i_target, TT::RANK_PAIR_REGS, l_data) );
+ // Use the reg API here so we get the PHY to MC rank conversion
+ FAPI_TRY( (mss::rank::read_rank_pair_reg< RP, 0 >(i_target, l_reg)) );
+ l_data.push_back(l_reg);
+ FAPI_TRY( (mss::rank::read_rank_pair_reg< RP, 1 >(i_target, l_reg)) );
+ l_data.push_back(l_reg);
// Modify
for (const auto l_rank : i_ranks)
@@ -750,8 +1050,9 @@ fapi2::ReturnCode set_ranks_in_pair( const fapi2::Target<T>& i_target,
++l_ordinal;
}
- // Write
- FAPI_TRY( scom_blastah(i_target, TT::RANK_PAIR_REGS, l_data) );
+ // Use the reg API here so we get the MC to PHY rank conversion
+ FAPI_TRY( (mss::rank::write_rank_pair_reg< RP, 0 >(i_target, l_data[0])) );
+ FAPI_TRY( (mss::rank::write_rank_pair_reg< RP, 1 >(i_target, l_data[1])) );
return fapi2::FAPI2_RC_SUCCESS;
@@ -776,9 +1077,14 @@ fapi2::ReturnCode get_ranks_in_pair( const fapi2::Target<T>& i_target,
o_ranks.clear();
// Read the rank pair register(s)
+ fapi2::buffer<uint64_t> l_reg;
std::vector<fapi2::buffer<uint64_t>> l_data;
- FAPI_TRY( scom_suckah(i_target, TT::RANK_PAIR_REGS, l_data) );
+ // Use the reg API here so we get the PHY to MC rank conversion
+ FAPI_TRY( (mss::rank::read_rank_pair_reg< RP, 0 >(i_target, l_reg)) );
+ l_data.push_back(l_reg);
+ FAPI_TRY( (mss::rank::read_rank_pair_reg< RP, 1 >(i_target, l_reg)) );
+ l_data.push_back(l_reg);
// Get data
for (uint64_t l_ordinal = 0; l_ordinal < TT::NUM_RANKS_IN_PAIR; ++l_ordinal)
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/mc/port.C b/src/import/chips/p9/procedures/hwp/memory/lib/mc/port.C
index 942e2c8a5..979ca5eb8 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/mc/port.C
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/mc/port.C
@@ -35,7 +35,6 @@
#include <fapi2.H>
#include <lib/mc/port.H>
-#include <lib/dimm/rank.H>
#include <lib/shared/mss_const.H>
#include <lib/utils/scom.H>
@@ -80,14 +79,13 @@ fapi2::ReturnCode enable_periodic_cal( const fapi2::Target<fapi2::TARGET_TYPE_MC
fapi2::buffer<uint16_t> l_per_zqcal_mode_options = 0;
fapi2::buffer<uint64_t> l_periodic_cal_config;
- fapi2::buffer<uint64_t> l_phy_zqcal_config;
std::vector<uint64_t> l_pairs;
FAPI_INF("Enable periodic cal");
uint8_t is_sim = 0;
- FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_IS_SIMULATION, fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), is_sim) );
+ FAPI_TRY( mss::is_simulation(is_sim) );
// Even if we're in sim, do these so that we do the attribute work (even though the values aren't used.)
FAPI_TRY( mss::eff_memcal_interval(i_target, l_memcal_interval) );
@@ -128,8 +126,6 @@ fapi2::ReturnCode enable_periodic_cal( const fapi2::Target<fapi2::TARGET_TYPE_MC
// ZQCAL
if (l_per_zqcal_mode_options != 0)
{
- std::vector<uint64_t> l_ranks;
-
//
// Configure the controller
//
@@ -162,20 +158,11 @@ fapi2::ReturnCode enable_periodic_cal( const fapi2::Target<fapi2::TARGET_TYPE_MC
//
// Setup PER_ZCAL_CONFIG based on the number of ranks on the DIMM in either slot.
- FAPI_TRY( mss::rank::ranks(i_target, l_ranks) );
-
- for (auto r : l_ranks)
- {
- l_phy_zqcal_config.setBit(TT::PER_ZCAL_ENA_RANK + r);
- }
+ FAPI_TRY( reset_zqcal_config(i_target) );
// No ZQCAL in sim
l_periodic_cal_config.writeBit<TT::PER_ENA_ZCAL>(is_sim ? 0 : 1);
- // Write the ZQCAL periodic config
- FAPI_INF("zcal periodic config: 0x%016lx", l_phy_zqcal_config);
- FAPI_TRY( mss::putScom(i_target, TT::PHY_ZQCAL_REG, l_phy_zqcal_config) );
-
// Write the ZQCAL timer reload register
// # DPHY01_DDRPHY_PC_ZCAL_TIMER_RELOAD_VALUE_P0 0x00A 0x8000c0090301143f
// # PHYW.PHYX.SYNTHX.D3SIDEA.PCX.REG09_L2
@@ -210,7 +197,7 @@ fapi2::ReturnCode enable_periodic_cal( const fapi2::Target<fapi2::TARGET_TYPE_MC
FAPI_TRY( mss::rank::get_rank_pairs(i_target, l_pairs) );
- for (auto pair : l_pairs)
+ for (const auto pair : l_pairs)
{
l_rank_config.setBit(pair);
}
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/mc/port.H b/src/import/chips/p9/procedures/hwp/memory/lib/mc/port.H
index 21a62fa2a..0e8c21f11 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/mc/port.H
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/mc/port.H
@@ -45,6 +45,7 @@
#include <lib/shared/mss_const.H>
#include <lib/utils/scom.H>
#include <lib/utils/c_str.H>
+#include <lib/dimm/rank.H>
namespace mss
{
@@ -77,7 +78,10 @@ class portTraits<fapi2::TARGET_TYPE_MCA>
static constexpr uint64_t CAL3Q_REG = MCA_MBA_CAL3Q;
static constexpr uint64_t DSM0Q_REG = MCA_MBA_DSM0Q;
+ // Danger Will Robinson <wave robot arms> MCA_DDRPHY_PC_PER_ZCAL_CONFIG_P0 uses PHY rank ordinal numbers
+ // which are different between PHYs. So if you're playing with this register, be sure to map rank numbers.
static constexpr uint64_t PHY_ZQCAL_REG = MCA_DDRPHY_PC_PER_ZCAL_CONFIG_P0;
+
static constexpr uint64_t PHY_PERIODIC_CAL_CONFIG_REG = MCA_DDRPHY_PC_PER_CAL_CONFIG_P0;
static constexpr uint64_t PHY_PERIODIC_CAL_RELOAD_REG = MCA_DDRPHY_PC_RELOAD_VALUE0_P0;
static constexpr uint64_t PHY_CAL_TIMER_RELOAD_REG = MCA_DDRPHY_PC_CAL_TIMER_RELOAD_VALUE_P0;
@@ -602,6 +606,34 @@ fapi_try_exit:
return fapi2::current_err;
}
+///
+/// @brief Reset the ZCAL config register.
+/// @warning This maps PHY rank numbers per target
+/// @tparam T, the fapi2 target type of the target
+/// @param[in] i_target A target representing a port
+/// @return FAPI2_RC_SUCCESS if and only if ok
+///
+template< fapi2::TargetType T, typename TT = portTraits<T> >
+fapi2::ReturnCode reset_zqcal_config( const fapi2::Target<T>& i_target )
+{
+ fapi2::buffer<uint64_t> l_phy_zqcal_config;
+ std::vector<uint64_t> l_ranks;
+
+ FAPI_TRY( mss::rank::ranks(i_target, l_ranks) );
+
+ for (const auto r : l_ranks)
+ {
+ l_phy_zqcal_config.setBit(TT::PER_ZCAL_ENA_RANK + rank::map_rank_ordinal_to_phy(i_target, r));
+ }
+
+ // Write the ZQCAL periodic config
+ FAPI_INF("zcal periodic config: 0x%016lx", l_phy_zqcal_config);
+ FAPI_TRY( mss::putScom(i_target, TT::PHY_ZQCAL_REG, l_phy_zqcal_config) );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
}// 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 e58ab08ef..f2ee912bf 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
@@ -960,17 +960,26 @@ fapi2::ReturnCode setup_cal_config( const fapi2::Target<fapi2::TARGET_TYPE_MCA>&
///
/// @brief Setup odt_wr/rd_config
-/// @param[in] i_target the MCA target associated with this cal setup
+/// @param[in] i_target the MCA target
+/// @param[in] i_dimm_count the number of DIMM presently on the target
+/// @param[in] i_odt_rd the RD ODT values from VPD
+/// @param[in] i_odt_wr the WR ODT values from VPD
/// @return FAPI2_RC_SUCCESS iff setup was successful
///
template<>
-fapi2::ReturnCode reset_odt_config( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target )
+fapi2::ReturnCode reset_odt_config_helper<fapi2::TARGET_TYPE_MCA, MAX_DIMM_PER_PORT, MAX_RANK_PER_DIMM>(
+ const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_dimm_count,
+ const uint8_t i_odt_rd[MAX_DIMM_PER_PORT][MAX_RANK_PER_DIMM],
+ const uint8_t i_odt_wr[MAX_DIMM_PER_PORT][MAX_RANK_PER_DIMM])
{
- uint8_t l_odt_rd[MAX_DIMM_PER_PORT][MAX_RANK_PER_DIMM];
- uint8_t l_odt_wr[MAX_DIMM_PER_PORT][MAX_RANK_PER_DIMM];
+ // The fields in the ODT VPD are 8 bits wide, but we only use the left-most 2 bits
+ // of each nibble. The encoding for each rank in the VPD is
+ // [Dimm0 ODT0][Dimm0 ODT1][N/A][N/A][Dimm1 ODT0][Dimm1 ODT1][N/A][N/A]
- FAPI_TRY( mss::vpd_mt_odt_rd(i_target, &(l_odt_rd[0][0])) );
- FAPI_TRY( mss::vpd_mt_odt_wr(i_target, &(l_odt_wr[0][0])) );
+ constexpr uint64_t BIT_FIELD0_START = 0;
+ constexpr uint64_t BIT_FIELD1_START = 4;
+ constexpr uint64_t BIT_FIELD_LENGTH = 2;
// Nimbus PHY is more or less hard-wired for 2 DIMM/port 4R/DIMM
// So there's not much point in looping over DIMM or ranks.
@@ -983,56 +992,57 @@ fapi2::ReturnCode reset_odt_config( const fapi2::Target<fapi2::TARGET_TYPE_MCA>&
// 48:55, ATTR_VPD_ODT_RD[0][0][0]; # when Read of Rank0
// 56:63, ATTR_VPD_ODT_RD[0][0][1]; # when Read of Rank1
fapi2::buffer<uint64_t> l_data;
+ uint8_t l_vpd_0 = 0;
+ uint8_t l_vpd_1 = 0;
- l_data.insertFromRight<MCA_DDRPHY_SEQ_ODT_RD_CONFIG0_P0_VALUES0,
- MCA_DDRPHY_SEQ_ODT_RD_CONFIG0_P0_VALUES0_LEN>(l_odt_rd[0][0]);
- l_data.insertFromRight<MCA_DDRPHY_SEQ_ODT_RD_CONFIG0_P0_VALUES1,
- MCA_DDRPHY_SEQ_ODT_RD_CONFIG0_P0_VALUES1_LEN>(l_odt_rd[0][1]);
+ // Extract the 2 DIMM0 bits we need from the VPD.
+ fapi2::buffer<uint8_t>(i_odt_rd[0][0]).extract<BIT_FIELD0_START, BIT_FIELD_LENGTH>(l_vpd_0);
+ fapi2::buffer<uint8_t>(i_odt_rd[0][1]).extract<BIT_FIELD0_START, BIT_FIELD_LENGTH>(l_vpd_1);
+ // Extract the 2 DIMM1 bits we need from the VPD.
+ fapi2::buffer<uint8_t>(i_odt_rd[0][0]).extract<BIT_FIELD1_START, BIT_FIELD_LENGTH, BIT_FIELD_LENGTH>(l_vpd_0);
+ fapi2::buffer<uint8_t>(i_odt_rd[0][1]).extract<BIT_FIELD1_START, BIT_FIELD_LENGTH, BIT_FIELD_LENGTH>(l_vpd_1);
+
+ FAPI_DBG("vpd: 0x%02x extract: 0x%02x", i_odt_rd[0][0], l_vpd_0);
+ FAPI_DBG("vpd: 0x%02x extract: 0x%02x", i_odt_rd[0][1], l_vpd_1);
+
+ l_data.insert<MCA_DDRPHY_SEQ_ODT_RD_CONFIG0_P0_VALUES0, BITS_PER_NIBBLE>(l_vpd_0);
+ l_data.insert<MCA_DDRPHY_SEQ_ODT_RD_CONFIG0_P0_VALUES1, BITS_PER_NIBBLE>(l_vpd_1);
FAPI_INF("odt_rd_config0: 0x%016llx", uint64_t(l_data));
FAPI_TRY( mss::putScom(i_target, MCA_DDRPHY_SEQ_ODT_RD_CONFIG0_P0, l_data) );
}
+ // Remember Centaur-canonical rank numbering is different from Nimbus numbering. Here,
+ // we need to lay the canonically defined VPD into the proper subfield based on DIMM config.
{
- // DPHY01_DDRPHY_SEQ_ODT_RD_CONFIG1_P0
- // 48:55, ATTR_VPD_ODT_RD[0][0][2]; # when Read of Rank2
- // 56:63, ATTR_VPD_ODT_RD[0][0][3]; # when Read of Rank3
- fapi2::buffer<uint64_t> l_data;
+ // "dual drop" which means what is in the VPD as ranks 4/5 go in to 2/3
+ fapi2::buffer<uint8_t> l_values2 = (i_dimm_count == MAX_DIMM_PER_PORT) ? i_odt_rd[1][0] : i_odt_rd[0][2];
+ fapi2::buffer<uint8_t> l_values3 = (i_dimm_count == MAX_DIMM_PER_PORT) ? i_odt_rd[1][1] : i_odt_rd[0][3];
- l_data.insertFromRight<MCA_DDRPHY_SEQ_ODT_RD_CONFIG1_P0_VALUES2,
- MCA_DDRPHY_SEQ_ODT_RD_CONFIG1_P0_VALUES2_LEN>(l_odt_rd[0][2]);
- l_data.insertFromRight<MCA_DDRPHY_SEQ_ODT_RD_CONFIG1_P0_VALUES3,
- MCA_DDRPHY_SEQ_ODT_RD_CONFIG1_P0_VALUES3_LEN>(l_odt_rd[0][3]);
- FAPI_INF("odt_rd_config1: 0x%016llx", uint64_t(l_data));
- FAPI_TRY( mss::putScom(i_target, MCA_DDRPHY_SEQ_ODT_RD_CONFIG1_P0, l_data) );
- }
+ uint8_t l_vpd_2 = 0;
+ uint8_t l_vpd_3 = 0;
+
+ // Extract the 2 DIMM0 bits we need from the VPD.
+ l_values2.extract<BIT_FIELD0_START, BIT_FIELD_LENGTH>(l_vpd_2);
+ l_values3.extract<BIT_FIELD0_START, BIT_FIELD_LENGTH>(l_vpd_3);
+ // Extract the 2 DIMM1 bits we need from the VPD.
+ l_values2.extract<BIT_FIELD1_START, BIT_FIELD_LENGTH, BIT_FIELD_LENGTH>(l_vpd_2);
+ l_values3.extract<BIT_FIELD1_START, BIT_FIELD_LENGTH, BIT_FIELD_LENGTH>(l_vpd_3);
+
+ FAPI_DBG("vpd: 0x%02x extract: 0x%02x", l_values2, l_vpd_2);
+ FAPI_DBG("vpd: 0x%02x extract: 0x%02x", l_values3, l_vpd_3);
- {
// DPHY01_DDRPHY_SEQ_ODT_RD_CONFIG2_P0
// 48:55, ATTR_VPD_ODT_RD[0][1][0]; # when Read of Rank4
// 56:63, ATTR_VPD_ODT_RD[0][1][1]; # when Read of Rank5
fapi2::buffer<uint64_t> l_data;
- l_data.insertFromRight<MCA_DDRPHY_SEQ_ODT_RD_CONFIG2_P0_VALUES4,
- MCA_DDRPHY_SEQ_ODT_RD_CONFIG2_P0_VALUES4_LEN>(l_odt_rd[1][0]);
- l_data.insertFromRight<MCA_DDRPHY_SEQ_ODT_RD_CONFIG2_P0_VALUES5,
- MCA_DDRPHY_SEQ_ODT_RD_CONFIG2_P0_VALUES5_LEN>(l_odt_rd[1][1]);
- FAPI_INF("odt_rd_config2: 0x%016llx", uint64_t(l_data));
- FAPI_TRY( mss::putScom(i_target, MCA_DDRPHY_SEQ_ODT_RD_CONFIG2_P0, l_data) );
+ l_data.insert<MCA_DDRPHY_SEQ_ODT_RD_CONFIG1_P0_VALUES2, BITS_PER_NIBBLE>(l_vpd_2);
+ l_data.insert<MCA_DDRPHY_SEQ_ODT_RD_CONFIG1_P0_VALUES3, BITS_PER_NIBBLE>(l_vpd_3);
+ FAPI_INF("odt_rd_config1: 0x%016llx", uint64_t(l_data));
+ FAPI_TRY( mss::putScom(i_target, MCA_DDRPHY_SEQ_ODT_RD_CONFIG1_P0, l_data) );
}
- {
- // DPHY01_DDRPHY_SEQ_ODT_RD_CONFIG3_P0
- // 48:55, ATTR_VPD_ODT_RD[0][1][2]; # when Read of Rank6
- // 56:63, ATTR_VPD_ODT_RD[0][1][3]; # when Read of Rank7
- fapi2::buffer<uint64_t> l_data;
-
- l_data.insertFromRight<MCA_DDRPHY_SEQ_ODT_RD_CONFIG3_P0_VALUES6,
- MCA_DDRPHY_SEQ_ODT_RD_CONFIG3_P0_VALUES6_LEN>(l_odt_rd[1][2]);
- l_data.insertFromRight<MCA_DDRPHY_SEQ_ODT_RD_CONFIG3_P0_VALUES7,
- MCA_DDRPHY_SEQ_ODT_RD_CONFIG3_P0_VALUES7_LEN>(l_odt_rd[1][3]);
- FAPI_INF("odt_rd_config3: 0x%016llx", uint64_t(l_data));
- FAPI_TRY( mss::putScom(i_target, MCA_DDRPHY_SEQ_ODT_RD_CONFIG3_P0, l_data) );
- }
+ // TODO RTC:167929 Can ODT VPD processing be shared between RD and WR?
//
// ODT Write
@@ -1042,56 +1052,76 @@ fapi2::ReturnCode reset_odt_config( const fapi2::Target<fapi2::TARGET_TYPE_MCA>&
// 48:55, ATTR_VPD_ODT_WR[0][0][0]; # when Read of Rank0
// 56:63, ATTR_VPD_ODT_WR[0][0][1]; # when Read of Rank1
fapi2::buffer<uint64_t> l_data;
+ uint8_t l_vpd_0 = 0;
+ uint8_t l_vpd_1 = 0;
+
+ // Extract the 2 DIMM0 bits we need from the VPD.
+ fapi2::buffer<uint8_t>(i_odt_wr[0][0]).extract<BIT_FIELD0_START, BIT_FIELD_LENGTH>(l_vpd_0);
+ fapi2::buffer<uint8_t>(i_odt_wr[0][1]).extract<BIT_FIELD0_START, BIT_FIELD_LENGTH>(l_vpd_1);
+ // Extract the 2 DIMM1 bits we need from the VPD.
+ fapi2::buffer<uint8_t>(i_odt_wr[0][0]).extract<BIT_FIELD1_START, BIT_FIELD_LENGTH, BIT_FIELD_LENGTH>(l_vpd_0);
+ fapi2::buffer<uint8_t>(i_odt_wr[0][1]).extract<BIT_FIELD1_START, BIT_FIELD_LENGTH, BIT_FIELD_LENGTH>(l_vpd_1);
+
+ FAPI_DBG("vpd: 0x%02x extract: 0x%02x", i_odt_wr[0][0], l_vpd_0);
+ FAPI_DBG("vpd: 0x%02x extract: 0x%02x", i_odt_wr[0][1], l_vpd_1);
- l_data.insertFromRight<MCA_DDRPHY_SEQ_ODT_WR_CONFIG0_P0_VALUES0,
- MCA_DDRPHY_SEQ_ODT_WR_CONFIG0_P0_VALUES0_LEN>(l_odt_wr[0][0]);
- l_data.insertFromRight<MCA_DDRPHY_SEQ_ODT_WR_CONFIG0_P0_VALUES1,
- MCA_DDRPHY_SEQ_ODT_WR_CONFIG0_P0_VALUES1_LEN>(l_odt_wr[0][1]);
+ l_data.insert<MCA_DDRPHY_SEQ_ODT_WR_CONFIG0_P0_VALUES0, BITS_PER_NIBBLE>(l_vpd_0);
+ l_data.insert<MCA_DDRPHY_SEQ_ODT_WR_CONFIG0_P0_VALUES1, BITS_PER_NIBBLE>(l_vpd_1);
FAPI_INF("odt_wr_config0: 0x%016llx", uint64_t(l_data));
FAPI_TRY( mss::putScom(i_target, MCA_DDRPHY_SEQ_ODT_WR_CONFIG0_P0, l_data) );
}
{
- // DPHY01_DDRPHY_SEQ_ODT_WR_CONFIG1_P0
- // 48:55, ATTR_VPD_ODT_WR[0][0][2]; # when Read of Rank2
- // 56:63, ATTR_VPD_ODT_WR[0][0][3]; # when Read of Rank3
- fapi2::buffer<uint64_t> l_data;
+ // "dual drop" which means what is in the VPD as ranks 4/5 go in to 2/3
+ fapi2::buffer<uint8_t> l_values2 = (i_dimm_count == MAX_DIMM_PER_PORT) ? i_odt_wr[1][0] : i_odt_wr[0][2];
+ fapi2::buffer<uint8_t> l_values3 = (i_dimm_count == MAX_DIMM_PER_PORT) ? i_odt_wr[1][1] : i_odt_wr[0][3];
- l_data.insertFromRight<MCA_DDRPHY_SEQ_ODT_WR_CONFIG1_P0_VALUES2,
- MCA_DDRPHY_SEQ_ODT_WR_CONFIG1_P0_VALUES2_LEN>(l_odt_wr[0][2]);
- l_data.insertFromRight<MCA_DDRPHY_SEQ_ODT_WR_CONFIG1_P0_VALUES3,
- MCA_DDRPHY_SEQ_ODT_WR_CONFIG1_P0_VALUES3_LEN>(l_odt_wr[0][3]);
- FAPI_INF("odt_wr_config1: 0x%016llx", uint64_t(l_data));
- FAPI_TRY( mss::putScom(i_target, MCA_DDRPHY_SEQ_ODT_WR_CONFIG1_P0, l_data) );
- }
+ uint8_t l_vpd_2 = 0;
+ uint8_t l_vpd_3 = 0;
+
+ // Extract the 2 DIMM0 bits we need from the VPD.
+ l_values2.extract<BIT_FIELD0_START, BIT_FIELD_LENGTH>(l_vpd_2);
+ l_values3.extract<BIT_FIELD0_START, BIT_FIELD_LENGTH>(l_vpd_3);
+ // Extract the 2 DIMM1 bits we need from the VPD.
+ l_values2.extract<BIT_FIELD1_START, BIT_FIELD_LENGTH, BIT_FIELD_LENGTH>(l_vpd_2);
+ l_values3.extract<BIT_FIELD1_START, BIT_FIELD_LENGTH, BIT_FIELD_LENGTH>(l_vpd_3);
+
+ FAPI_DBG("vpd: 0x%02x extract: 0x%02x", l_values2, l_vpd_2);
+ FAPI_DBG("vpd: 0x%02x extract: 0x%02x", l_values3, l_vpd_3);
- {
// DPHY01_DDRPHY_SEQ_ODT_WR_CONFIG2_P0
// 48:55, ATTR_VPD_ODT_WR[0][1][0]; # when Read of Rank4
// 56:63, ATTR_VPD_ODT_WR[0][1][1]; # when Read of Rank5
fapi2::buffer<uint64_t> l_data;
- l_data.insertFromRight<MCA_DDRPHY_SEQ_ODT_WR_CONFIG2_P0_VALUES4,
- MCA_DDRPHY_SEQ_ODT_WR_CONFIG2_P0_VALUES4_LEN>(l_odt_wr[1][0]);
- l_data.insertFromRight<MCA_DDRPHY_SEQ_ODT_WR_CONFIG2_P0_VALUES5,
- MCA_DDRPHY_SEQ_ODT_WR_CONFIG2_P0_VALUES5_LEN>(l_odt_wr[1][1]);
- FAPI_INF("odt_wr_config2: 0x%016llx", uint64_t(l_data));
- FAPI_TRY( mss::putScom(i_target, MCA_DDRPHY_SEQ_ODT_WR_CONFIG2_P0, l_data) );
+ l_data.insert<MCA_DDRPHY_SEQ_ODT_WR_CONFIG1_P0_VALUES2, BITS_PER_NIBBLE>(l_vpd_2);
+ l_data.insert<MCA_DDRPHY_SEQ_ODT_WR_CONFIG1_P0_VALUES3, BITS_PER_NIBBLE>(l_vpd_3);
+ FAPI_INF("odt_wr_config1: 0x%016llx", uint64_t(l_data));
+ FAPI_TRY( mss::putScom(i_target, MCA_DDRPHY_SEQ_ODT_WR_CONFIG1_P0, l_data) );
}
- {
- // DPHY01_DDRPHY_SEQ_ODT_WR_CONFIG3_P0
- // 48:55, ATTR_VPD_ODT_WR[0][1][2]; # when Read of Rank6
- // 56:63, ATTR_VPD_ODT_WR[0][1][3]; # when Read of Rank7
- fapi2::buffer<uint64_t> l_data;
+fapi_try_exit:
+ return fapi2::current_err;
+}
- l_data.insertFromRight<MCA_DDRPHY_SEQ_ODT_WR_CONFIG3_P0_VALUES6,
- MCA_DDRPHY_SEQ_ODT_WR_CONFIG3_P0_VALUES6_LEN>(l_odt_wr[1][2]);
- l_data.insertFromRight<MCA_DDRPHY_SEQ_ODT_WR_CONFIG3_P0_VALUES7,
- MCA_DDRPHY_SEQ_ODT_WR_CONFIG3_P0_VALUES7_LEN>(l_odt_wr[1][3]);
- FAPI_INF("odt_wr_config3: 0x%016llx", uint64_t(l_data));
- FAPI_TRY( mss::putScom(i_target, MCA_DDRPHY_SEQ_ODT_WR_CONFIG3_P0, l_data) );
- }
+///
+/// @brief Setup odt_wr/rd_config, reads attributes
+/// @param[in] i_target the MCA target associated with this cal setup
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+///
+template<>
+fapi2::ReturnCode reset_odt_config( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target )
+{
+ uint8_t l_odt_rd[MAX_DIMM_PER_PORT][MAX_RANK_PER_DIMM];
+ uint8_t l_odt_wr[MAX_DIMM_PER_PORT][MAX_RANK_PER_DIMM];
+
+ uint64_t l_dimm_count = count_dimm(i_target);
+
+ FAPI_TRY( mss::vpd_mt_odt_rd(i_target, &(l_odt_rd[0][0])) );
+ FAPI_TRY( mss::vpd_mt_odt_wr(i_target, &(l_odt_wr[0][0])) );
+
+ return reset_odt_config_helper<fapi2::TARGET_TYPE_MCA, MAX_DIMM_PER_PORT, MAX_RANK_PER_DIMM>(
+ i_target, l_dimm_count, l_odt_rd, l_odt_wr);
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 075db9781..7f0d9042f 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
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2015,2016 */
+/* Contributors Listed Below - COPYRIGHT 2015,2017 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -149,9 +149,42 @@ fapi2::ReturnCode setup_cal_config( const fapi2::Target<fapi2::TARGET_TYPE_MCA>&
const uint64_t i_rank,
const fapi2::buffer<uint16_t> i_cal_steps_enabled);
+// TODO RTC: 157753 tparams P and R can be pulled from an MCA trait once we have it
///
/// @brief Setup odt_wr/rd_config
/// @tparam T the target type of the MCA/MBA
+/// @tparam P the maximum DIMM per T
+/// @tparam R the maximum rank per DIMM on T
+/// @param[in] i_target the target
+/// @param[in] i_dimm_count the number of DIMM presently on the target
+/// @param[in] i_odt_rd the RD ODT values from VPD
+/// @param[in] i_odt_wr the WR ODT values from VPD
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+///
+template< fapi2::TargetType T, uint64_t P, uint64_t R >
+fapi2::ReturnCode reset_odt_config_helper( const fapi2::Target<T>& i_target,
+ const uint64_t i_dimm_count,
+ const uint8_t i_odt_rd[P][R],
+ const uint8_t i_odt_wr[P][R] );
+
+///
+/// @brief Setup odt_wr/rd_config
+/// @param[in] i_target the MCA target
+/// @param[in] i_dimm_count the number of DIMM presently on the target
+/// @param[in] i_odt_rd the RD ODT values from VPD
+/// @param[in] i_odt_wr the WR ODT values from VPD
+/// @return FAPI2_RC_SUCCESS iff setup was successful
+///
+template<>
+fapi2::ReturnCode reset_odt_config_helper<fapi2::TARGET_TYPE_MCA, MAX_DIMM_PER_PORT, MAX_RANK_PER_DIMM>(
+ const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_dimm_count,
+ const uint8_t i_odt_rd[MAX_DIMM_PER_PORT][MAX_RANK_PER_DIMM],
+ const uint8_t i_odt_wr[MAX_DIMM_PER_PORT][MAX_RANK_PER_DIMM]);
+
+///
+/// @brief Setup odt_wr/rd_config, reads attributes
+/// @tparam T the target type of the MCA/MBA
/// @param[in] i_target the target associated with this cal setup
/// @return FAPI2_RC_SUCCESS iff setup was successful
///
@@ -159,7 +192,7 @@ template< fapi2::TargetType T >
fapi2::ReturnCode reset_odt_config( const fapi2::Target<T>& i_target );
///
-/// @brief Setup odt_wr/rd_config
+/// @brief Setup odt_wr/rd_config, reads attributes
/// @param[in] i_target the MCA target associated with this cal setup
/// @return FAPI2_RC_SUCCESS iff setup was successful
///
OpenPOWER on IntegriCloud