summaryrefslogtreecommitdiffstats
path: root/src/import/chips/ocmb/common/procedures/hwp/pmic/lib/utils/pmic_enable_utils.H
diff options
context:
space:
mode:
Diffstat (limited to 'src/import/chips/ocmb/common/procedures/hwp/pmic/lib/utils/pmic_enable_utils.H')
-rw-r--r--src/import/chips/ocmb/common/procedures/hwp/pmic/lib/utils/pmic_enable_utils.H784
1 files changed, 781 insertions, 3 deletions
diff --git a/src/import/chips/ocmb/common/procedures/hwp/pmic/lib/utils/pmic_enable_utils.H b/src/import/chips/ocmb/common/procedures/hwp/pmic/lib/utils/pmic_enable_utils.H
index d673a0073..ba93774bb 100644
--- a/src/import/chips/ocmb/common/procedures/hwp/pmic/lib/utils/pmic_enable_utils.H
+++ b/src/import/chips/ocmb/common/procedures/hwp/pmic/lib/utils/pmic_enable_utils.H
@@ -30,13 +30,22 @@
// *HWP HWP Owner: Mark Pizzutillo <mark.pizzutillo@ibm.com>
// *HWP HWP Backup: Louis Stermole <stermole@us.ibm.com>
// *HWP Team: Memory
-// *HWP Level: 1
+// *HWP Level: 2
// *HWP Consumed by: FSP:HB
#ifndef __PMIC_ENABLE_UTILS_H__
#define __PMIC_ENABLE_UTILS_H__
#include <fapi2.H>
+#include <pmic_regs.H>
+#include <pmic_regs_fld.H>
+#include <lib/i2c/i2c_pmic.H>
+#include <lib/utils/pmic_common_utils.H>
+#include <lib/utils/pmic_consts.H>
+#include <generic/memory/lib/utils/c_str.H>
+#include <generic/memory/lib/utils/index.H>
+#include <mss_pmic_attribute_getters.H>
+#include <mss_pmic_attribute_setters.H>
namespace mss
{
@@ -52,7 +61,776 @@ enum enable_mode
MANUAL = 1, // Use voltage settings currently in the vendor region. (Changed via pmic_update, or factory defaults)
};
-}// pmic
-}// mss
+/// @brief pointer to PMIC attribute getters for DIMM target
+typedef fapi2::ReturnCode (*pmic_attr_ptr)(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target, uint8_t& o_value);
+
+// Pointers below allow for run-time attribute getter selection by PMIC ID (0,1)
+
+// Voltage Setting
+static constexpr pmic_attr_ptr get_swa_voltage_setting[] =
+{
+ mss::attr::get_pmic0_swa_voltage_setting,
+ mss::attr::get_pmic1_swa_voltage_setting
+};
+static constexpr pmic_attr_ptr get_swb_voltage_setting[] =
+{
+ mss::attr::get_pmic0_swb_voltage_setting,
+ mss::attr::get_pmic1_swb_voltage_setting
+};
+static constexpr pmic_attr_ptr get_swc_voltage_setting[] =
+{
+ mss::attr::get_pmic0_swc_voltage_setting,
+ mss::attr::get_pmic1_swc_voltage_setting
+};
+static constexpr pmic_attr_ptr get_swd_voltage_setting[] =
+{
+ mss::attr::get_pmic0_swd_voltage_setting,
+ mss::attr::get_pmic1_swd_voltage_setting
+};
+
+// Voltage Range Select
+static constexpr pmic_attr_ptr get_swa_voltage_range_select[] =
+{
+ mss::attr::get_pmic0_swa_voltage_range_select,
+ mss::attr::get_pmic1_swa_voltage_range_select
+};
+static constexpr pmic_attr_ptr get_swb_voltage_range_select[] =
+{
+ mss::attr::get_pmic0_swb_voltage_range_select,
+ mss::attr::get_pmic1_swb_voltage_range_select
+};
+static constexpr pmic_attr_ptr get_swc_voltage_range_select[] =
+{
+ mss::attr::get_pmic0_swc_voltage_range_select,
+ mss::attr::get_pmic1_swc_voltage_range_select
+};
+static constexpr pmic_attr_ptr get_swd_voltage_range_select[] =
+{
+ mss::attr::get_pmic0_swd_voltage_range_select,
+ mss::attr::get_pmic1_swd_voltage_range_select
+};
+
+// Voltage Offset
+static constexpr pmic_attr_ptr get_swa_voltage_offset[] =
+{
+ mss::attr::get_pmic0_swa_voltage_offset,
+ mss::attr::get_pmic1_swa_voltage_offset
+};
+static constexpr pmic_attr_ptr get_swb_voltage_offset[] =
+{
+ mss::attr::get_pmic0_swb_voltage_offset,
+ mss::attr::get_pmic1_swb_voltage_offset
+};
+static constexpr pmic_attr_ptr get_swc_voltage_offset[] =
+{
+ mss::attr::get_pmic0_swc_voltage_offset,
+ mss::attr::get_pmic1_swc_voltage_offset
+};
+static constexpr pmic_attr_ptr get_swd_voltage_offset[] =
+{
+ mss::attr::get_pmic0_swd_voltage_offset,
+ mss::attr::get_pmic1_swd_voltage_offset
+};
+
+// Voltage Offset Direction
+static constexpr pmic_attr_ptr get_swa_voltage_offset_direction[] =
+{
+ mss::attr::get_pmic0_swa_voltage_offset_direction,
+ mss::attr::get_pmic1_swa_voltage_offset_direction
+};
+static constexpr pmic_attr_ptr get_swb_voltage_offset_direction[] =
+{
+ mss::attr::get_pmic0_swb_voltage_offset_direction,
+ mss::attr::get_pmic1_swb_voltage_offset_direction
+};
+static constexpr pmic_attr_ptr get_swc_voltage_offset_direction[] =
+{
+ mss::attr::get_pmic0_swc_voltage_offset_direction,
+ mss::attr::get_pmic1_swc_voltage_offset_direction
+};
+static constexpr pmic_attr_ptr get_swd_voltage_offset_direction[] =
+{
+ mss::attr::get_pmic0_swd_voltage_offset_direction,
+ mss::attr::get_pmic1_swd_voltage_offset_direction
+};
+
+// Sequence Delay
+static constexpr pmic_attr_ptr get_swa_sequence_delay[] =
+{
+ mss::attr::get_pmic0_swa_sequence_delay,
+ mss::attr::get_pmic1_swa_sequence_delay
+};
+static constexpr pmic_attr_ptr get_swb_sequence_delay[] =
+{
+ mss::attr::get_pmic0_swb_sequence_delay,
+ mss::attr::get_pmic1_swb_sequence_delay
+};
+static constexpr pmic_attr_ptr get_swc_sequence_delay[] =
+{
+ mss::attr::get_pmic0_swc_sequence_delay,
+ mss::attr::get_pmic1_swc_sequence_delay
+};
+static constexpr pmic_attr_ptr get_swd_sequence_delay[] =
+{
+ mss::attr::get_pmic0_swd_sequence_delay,
+ mss::attr::get_pmic1_swd_sequence_delay
+};
+
+// Sequence Order
+static constexpr pmic_attr_ptr get_swa_sequence_order[] =
+{
+ mss::attr::get_pmic0_swa_sequence_order,
+ mss::attr::get_pmic1_swa_sequence_order
+};
+static constexpr pmic_attr_ptr get_swb_sequence_order[] =
+{
+ mss::attr::get_pmic0_swb_sequence_order,
+ mss::attr::get_pmic1_swb_sequence_order
+};
+static constexpr pmic_attr_ptr get_swc_sequence_order[] =
+{
+ mss::attr::get_pmic0_swc_sequence_order,
+ mss::attr::get_pmic1_swc_sequence_order
+};
+static constexpr pmic_attr_ptr get_swd_sequence_order[] =
+{
+ mss::attr::get_pmic0_swd_sequence_order,
+ mss::attr::get_pmic1_swd_sequence_order
+};
+
+// Phase Combination
+static constexpr pmic_attr_ptr get_phase_comb[] =
+{
+ mss::attr::get_pmic0_phase_comb,
+ mss::attr::get_pmic1_phase_comb
+};
+
+// These arrays allow us to dynamically choose the right attribute getter at runtime based on the rail and mss::pmic::id
+static const pmic_attr_ptr* l_get_volt_setting[] =
+{
+ mss::pmic::get_swa_voltage_setting,
+ mss::pmic::get_swb_voltage_setting,
+ mss::pmic::get_swc_voltage_setting,
+ mss::pmic::get_swd_voltage_setting
+};
+
+static const pmic_attr_ptr* l_get_volt_range_select[] =
+{
+ mss::pmic::get_swa_voltage_range_select,
+ mss::pmic::get_swb_voltage_range_select,
+ mss::pmic::get_swc_voltage_range_select,
+ mss::pmic::get_swd_voltage_range_select
+};
+
+static const pmic_attr_ptr* l_get_volt_offset[] =
+{
+ mss::pmic::get_swa_voltage_offset,
+ mss::pmic::get_swb_voltage_offset,
+ mss::pmic::get_swc_voltage_offset,
+ mss::pmic::get_swd_voltage_offset
+};
+
+static const pmic_attr_ptr* l_get_volt_offset_direction[] =
+{
+ mss::pmic::get_swa_voltage_offset_direction,
+ mss::pmic::get_swb_voltage_offset_direction,
+ mss::pmic::get_swc_voltage_offset_direction,
+ mss::pmic::get_swd_voltage_offset_direction
+};
+
+// For output traces
+static const std::vector<const char*> PMIC_RAIL_NAMES = {"SWA", "SWB", "SWC", "SWD"};
+
+// Attribute setter FP type
+typedef fapi2::ReturnCode (*pmic_attr_setter_ptr)(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ uint8_t i_value);
+
+// Voltage Setting
+static constexpr pmic_attr_setter_ptr set_swa_voltage_setting[] =
+{
+ mss::attr::set_pmic0_swa_voltage_setting,
+ mss::attr::set_pmic1_swa_voltage_setting
+};
+static constexpr pmic_attr_setter_ptr set_swb_voltage_setting[] =
+{
+ mss::attr::set_pmic0_swb_voltage_setting,
+ mss::attr::set_pmic1_swb_voltage_setting
+};
+static constexpr pmic_attr_setter_ptr set_swc_voltage_setting[] =
+{
+ mss::attr::set_pmic0_swc_voltage_setting,
+ mss::attr::set_pmic1_swc_voltage_setting
+};
+static constexpr pmic_attr_setter_ptr set_swd_voltage_setting[] =
+{
+ mss::attr::set_pmic0_swd_voltage_setting,
+ mss::attr::set_pmic1_swd_voltage_setting
+};
+
+// Voltage Range Select
+static constexpr pmic_attr_setter_ptr set_swa_voltage_range_select[] =
+{
+ mss::attr::set_pmic0_swa_voltage_range_select,
+ mss::attr::set_pmic1_swa_voltage_range_select
+};
+static constexpr pmic_attr_setter_ptr set_swb_voltage_range_select[] =
+{
+ mss::attr::set_pmic0_swb_voltage_range_select,
+ mss::attr::set_pmic1_swb_voltage_range_select
+};
+static constexpr pmic_attr_setter_ptr set_swc_voltage_range_select[] =
+{
+ mss::attr::set_pmic0_swc_voltage_range_select,
+ mss::attr::set_pmic1_swc_voltage_range_select
+};
+static constexpr pmic_attr_setter_ptr set_swd_voltage_range_select[] =
+{
+ mss::attr::set_pmic0_swd_voltage_range_select,
+ mss::attr::set_pmic1_swd_voltage_range_select
+};
+
+// Voltage Offset
+static constexpr pmic_attr_setter_ptr set_swa_voltage_offset[] =
+{
+ mss::attr::set_pmic0_swa_voltage_offset,
+ mss::attr::set_pmic1_swa_voltage_offset
+};
+static constexpr pmic_attr_setter_ptr set_swb_voltage_offset[] =
+{
+ mss::attr::set_pmic0_swb_voltage_offset,
+ mss::attr::set_pmic1_swb_voltage_offset
+};
+static constexpr pmic_attr_setter_ptr set_swc_voltage_offset[] =
+{
+ mss::attr::set_pmic0_swc_voltage_offset,
+ mss::attr::set_pmic1_swc_voltage_offset
+};
+static constexpr pmic_attr_setter_ptr set_swd_voltage_offset[] =
+{
+ mss::attr::set_pmic0_swd_voltage_offset,
+ mss::attr::set_pmic1_swd_voltage_offset
+};
+
+// Voltage Offset Direction
+static constexpr pmic_attr_setter_ptr set_swa_voltage_offset_direction[] =
+{
+ mss::attr::set_pmic0_swa_voltage_offset_direction,
+ mss::attr::set_pmic1_swa_voltage_offset_direction
+};
+static constexpr pmic_attr_setter_ptr set_swb_voltage_offset_direction[] =
+{
+ mss::attr::set_pmic0_swb_voltage_offset_direction,
+ mss::attr::set_pmic1_swb_voltage_offset_direction
+};
+static constexpr pmic_attr_setter_ptr set_swc_voltage_offset_direction[] =
+{
+ mss::attr::set_pmic0_swc_voltage_offset_direction,
+ mss::attr::set_pmic1_swc_voltage_offset_direction
+};
+static constexpr pmic_attr_setter_ptr set_swd_voltage_offset_direction[] =
+{
+ mss::attr::set_pmic0_swd_voltage_offset_direction,
+ mss::attr::set_pmic1_swd_voltage_offset_direction
+};
+
+// Sequence Delay
+static constexpr pmic_attr_setter_ptr set_swa_sequence_delay[] =
+{
+ mss::attr::set_pmic0_swa_sequence_delay,
+ mss::attr::set_pmic1_swa_sequence_delay
+};
+static constexpr pmic_attr_setter_ptr set_swb_sequence_delay[] =
+{
+ mss::attr::set_pmic0_swb_sequence_delay,
+ mss::attr::set_pmic1_swb_sequence_delay
+};
+static constexpr pmic_attr_setter_ptr set_swc_sequence_delay[] =
+{
+ mss::attr::set_pmic0_swc_sequence_delay,
+ mss::attr::set_pmic1_swc_sequence_delay
+};
+static constexpr pmic_attr_setter_ptr set_swd_sequence_delay[] =
+{
+ mss::attr::set_pmic0_swd_sequence_delay,
+ mss::attr::set_pmic1_swd_sequence_delay
+};
+
+// Sequence Order
+static constexpr pmic_attr_setter_ptr set_swa_sequence_order[] =
+{
+ mss::attr::set_pmic0_swa_sequence_order,
+ mss::attr::set_pmic1_swa_sequence_order
+};
+static constexpr pmic_attr_setter_ptr set_swb_sequence_order[] =
+{
+ mss::attr::set_pmic0_swb_sequence_order,
+ mss::attr::set_pmic1_swb_sequence_order
+};
+static constexpr pmic_attr_setter_ptr set_swc_sequence_order[] =
+{
+ mss::attr::set_pmic0_swc_sequence_order,
+ mss::attr::set_pmic1_swc_sequence_order
+};
+static constexpr pmic_attr_setter_ptr set_swd_sequence_order[] =
+{
+ mss::attr::set_pmic0_swd_sequence_order,
+ mss::attr::set_pmic1_swd_sequence_order
+};
+
+// Phase Combination
+static constexpr pmic_attr_setter_ptr set_phase_comb[] =
+{
+ mss::attr::set_pmic0_phase_comb,
+ mss::attr::set_pmic1_phase_comb
+};
+
+// TK - these will be needed in the next commit (pmic_bias).
+
+// These arrays allow us to dynamically choose the right attribute setter at runtime based on the rail and mss::pmic::id
+// static const pmic_attr_setter_ptr* l_set_volt_setting[] =
+// {
+// mss::pmic::set_swa_voltage_setting,
+// mss::pmic::set_swb_voltage_setting,
+// mss::pmic::set_swc_voltage_setting,
+// mss::pmic::set_swd_voltage_setting
+// };
+
+// static const pmic_attr_setter_ptr* l_set_volt_range_select[] =
+// {
+// mss::pmic::set_swa_voltage_range_select,
+// mss::pmic::set_swb_voltage_range_select,
+// mss::pmic::set_swc_voltage_range_select,
+// mss::pmic::set_swd_voltage_range_select
+// };
+
+// static const pmic_attr_setter_ptr* l_set_volt_offset[] =
+// {
+// mss::pmic::set_swa_voltage_offset,
+// mss::pmic::set_swb_voltage_offset,
+// mss::pmic::set_swc_voltage_offset,
+// mss::pmic::set_swd_voltage_offset
+// };
+
+// static const pmic_attr_setter_ptr* l_set_volt_offset_direction[] =
+// {
+// mss::pmic::set_swa_voltage_offset_direction,
+// mss::pmic::set_swb_voltage_offset_direction,
+// mss::pmic::set_swc_voltage_offset_direction,
+// mss::pmic::set_swd_voltage_offset_direction
+// };
+
+//-----------------------------------
+// SPD Biasing functions
+//-----------------------------------
+
+///
+/// @breif set VR enable bit for system startup via R32 (not broadcast)
+///
+/// @param[in] i_pmic_target PMIC target
+/// @return fapi2::FAPI2_RC_SUCCESS iff success
+///
+fapi2::ReturnCode start_vr_enable(
+ const fapi2::Target<fapi2::TargetType::TARGET_TYPE_PMIC>& i_pmic_target);
+
+///
+/// @brief bias PMIC0 with spd settings for phase combination (SWA, SWB or SWA+SWB)
+///
+/// @param[in] i_pmic_target PMIC target
+/// @param[in] i_port - port target of PMIC
+/// @param[in] i_dimm_index - DIMM index for PMIC (0,1)
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS iff no error
+///
+fapi2::ReturnCode bias_with_spd_phase_comb(
+ const fapi2::Target<fapi2::TargetType::TARGET_TYPE_PMIC>& i_pmic_target,
+ const fapi2::Target<fapi2::TargetType::TARGET_TYPE_DIMM>& i_dimm,
+ const mss::pmic::id i_id);
+
+///
+/// @brief bias with SPD settings for voltage ranges
+///
+/// @param[in] i_pmic_target PMIC target
+/// @param[in] i_port port target of PMIC
+/// @param[in] i_dimm_index DIMM index for PMIC (0,1)
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS iff no error
+///
+fapi2::ReturnCode bias_with_spd_volt_ranges(
+ const fapi2::Target<fapi2::TargetType::TARGET_TYPE_PMIC>& i_pmic_target,
+ const fapi2::Target<fapi2::TargetType::TARGET_TYPE_DIMM>& i_dimm,
+ const mss::pmic::id i_id);
+
+///
+/// @brief bias with SPD settings for startup sequence
+///
+/// @param[in] i_pmic_target PMIC target
+/// @param[in] i_port port target of PMIC
+/// @param[in] i_dimm_index DIMM index for PMIC (0,1)
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS iff no error
+///
+fapi2::ReturnCode bias_with_spd_startup_seq(
+ const fapi2::Target<fapi2::TargetType::TARGET_TYPE_PMIC>& i_pmic_target,
+ const fapi2::Target<fapi2::TargetType::TARGET_TYPE_DIMM>& i_dimm,
+ const mss::pmic::id i_id);
+
+///
+/// @brief Set the startup seq register with the given parameters
+///
+/// @param[in] i_pmic_target PMIC target
+/// @param[in] i_rail rail to
+/// @param[in] i_round sequence round 1-4
+/// @param[in] i_delay delay after round
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS iff no error
+///
+fapi2::ReturnCode set_startup_seq_register(
+ const fapi2::Target<fapi2::TargetType::TARGET_TYPE_PMIC>& i_pmic_target,
+ const uint8_t i_rail,
+ const uint8_t i_round,
+ const uint8_t i_delay);
+
+//-----------------------------------
+// Templated SPD Biasing functions
+//-----------------------------------
+
+///
+/// @brief bias with spd settings for voltages
+///
+/// @tparam V mss::pmic::vendor (TI/IDT)
+/// @param[in] i_pmic_target PMIC target
+/// @param[in] i_dimm_target DIMM target of PMIC
+/// @param[in] i_dimm_index - DIMM index for PMIC (0,1)
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS iff no error
+///
+template <mss::pmic::vendor V>
+fapi2::ReturnCode bias_with_spd_voltages(
+ const fapi2::Target<fapi2::TargetType::TARGET_TYPE_PMIC>& i_pmic_target,
+ const fapi2::Target<fapi2::TargetType::TARGET_TYPE_DIMM>& i_dimm_target,
+ const mss::pmic::id i_id);
+
+///
+/// @brief Calcuate target voltage for PMIC
+///
+/// @param[in] i_dimm_target DIMM target of PMIC (holds the attributes)
+/// @param[in] i_id ID of pmic (0,1)
+/// @param[in] i_rail RAIL to calculate voltage for
+/// @param[out] o_volt_buffer output buffer
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS iff success
+///
+inline fapi2::ReturnCode calculate_voltage_write_buffer(
+ const fapi2::Target<fapi2::TargetType::TARGET_TYPE_DIMM>& i_dimm_target,
+ const mss::pmic::id i_id,
+ const uint8_t i_rail,
+ fapi2::buffer<uint8_t>& o_volt_buffer)
+{
+ uint8_t l_volt = 0;
+ uint8_t l_volt_offset = 0;
+ uint8_t l_volt_offset_direction = 0;
+
+ // Get the attributes corresponding to the rail and PMIC indices
+ FAPI_TRY(l_get_volt_setting[i_rail][i_id](i_dimm_target, l_volt));
+ FAPI_TRY(l_get_volt_offset[i_rail][i_id](i_dimm_target, l_volt_offset));
+ FAPI_TRY(l_get_volt_offset_direction[i_rail][i_id](i_dimm_target, l_volt_offset_direction));
+
+ o_volt_buffer = (l_volt_offset_direction == CONSTS::OFFSET_PLUS) ?
+ l_volt + l_volt_offset : l_volt - l_volt_offset;
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Bias with spd voltages for IDT pmic
+///
+/// @param[in] i_pmic_target PMIC target
+/// @param[in] i_dimm_target DIMM target
+/// @param[in] i_id relative ID of PMIC (0/1)
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS iff success
+///
+template <>
+inline fapi2::ReturnCode bias_with_spd_voltages<mss::pmic::vendor::IDT>(
+ const fapi2::Target<fapi2::TargetType::TARGET_TYPE_PMIC>& i_pmic_target,
+ const fapi2::Target<fapi2::TargetType::TARGET_TYPE_DIMM>& i_dimm_target,
+ const mss::pmic::id i_id)
+{
+ using CONSTS = mss::pmic::consts<mss::pmic::product::JEDEC_COMPLIANT>;
+
+ for (uint8_t l_rail_index = mss::pmic::rail::SWA; l_rail_index <= mss::pmic::rail::SWD; ++l_rail_index)
+ {
+ fapi2::buffer<uint8_t> l_volt_buffer;
+ FAPI_TRY(calculate_voltage_write_buffer(i_dimm_target, i_id, l_rail_index, l_volt_buffer));
+
+ // Since we have unsigned integers, this should check both underflow and overflow
+ FAPI_ASSERT(l_volt_buffer <= CONSTS::MAX_VOLT_BITMAP,
+ fapi2::PMIC_VOLTAGE_OUT_OF_RANGE()
+ .set_TARGET(i_pmic_target)
+ .set_VOLTAGE_BITMAP(l_volt_buffer)
+ .set_RAIL(mss::pmic::VOLT_SETTING_REGS[l_rail_index]),
+ "Voltage out of range as determined by SPD voltage +/- offset for %s of %s",
+ PMIC_RAIL_NAMES[l_rail_index], mss::c_str(i_pmic_target) );
+
+ l_volt_buffer = l_volt_buffer << CONSTS::SHIFT_VOLTAGE_FOR_REG;
+ FAPI_TRY(mss::pmic::i2c::reg_write(i_pmic_target, mss::pmic::VOLT_SETTING_REGS[l_rail_index], l_volt_buffer),
+ "Error writing address 0x%02hhX of PMIC %s", mss::pmic::VOLT_SETTING_REGS[l_rail_index], mss::c_str(i_pmic_target));
+
+ }
+
+ return fapi2::FAPI2_RC_SUCCESS;
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Bias with spd voltages for TI pmic
+///
+/// @param[in] i_pmic_target PMIC target
+/// @param[in] i_dimm_target DIMM target
+/// @param[in] i_id relative ID of PMIC (0/1)
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS iff success
+///
+template <>
+inline fapi2::ReturnCode bias_with_spd_voltages<mss::pmic::vendor::TI>(
+ const fapi2::Target<fapi2::TargetType::TARGET_TYPE_PMIC>& i_pmic_target,
+ const fapi2::Target<fapi2::TargetType::TARGET_TYPE_DIMM>& i_dimm_target,
+ const mss::pmic::id i_id)
+{
+ using REGS = pmicRegs<mss::pmic::product::JEDEC_COMPLIANT>;
+ using CONSTS = mss::pmic::consts<mss::pmic::product::JEDEC_COMPLIANT>;
+
+ for (uint8_t l_rail_index = mss::pmic::rail::SWA; l_rail_index <= mss::pmic::rail::SWD; ++l_rail_index)
+ {
+ fapi2::buffer<uint8_t> l_volt_buffer;
+ FAPI_TRY(calculate_voltage_write_buffer(i_dimm_target, i_id, l_rail_index, l_volt_buffer));
+
+ bool l_overflow = false;
+
+ uint8_t l_volt_range_select = 0;
+ FAPI_TRY(l_get_volt_range_select[l_rail_index][i_id](i_dimm_target, l_volt_range_select));
+
+ // SWD supports a RANGE 1, but NOT SWA-C
+ if (l_rail_index == mss::pmic::rail::SWD)
+ {
+ // Can set range and voltage directly
+ fapi2::buffer<uint8_t> l_volt_range_buffer;
+
+ // Read in what the register has, as to not overwrite any default values
+ FAPI_TRY(mss::pmic::i2c::reg_read_reverse_buffer(i_pmic_target, REGS::R2B, l_volt_range_buffer));
+
+ l_volt_range_buffer.writeBit<FIELDS::SWD_VOLTAGE_RANGE>(l_volt_range_select);
+
+ // Write to PMIC
+ FAPI_TRY(mss::pmic::i2c::reg_write_reverse_buffer(i_pmic_target, REGS::R2B, l_volt_range_buffer));
+ }
+ else
+ {
+ // Check if the range is range 1, in which case we will need to convert to range 0 (thanks TI)
+ if (l_volt_range_select == CONSTS::RANGE_1)
+ {
+ // Convert from RANGE1 -> RANGE0
+
+ // Since both ranges are 5mV (at least they're supposed to be)
+ // we can just subtract the difference between range 1 and 0
+ // which is 600mV -> 800mV
+ // 200mV / 5 = 40
+ uint8_t l_old_voltage = uint8_t(l_volt_buffer);
+ l_volt_buffer = l_volt_buffer - CONSTS::CONVERT_RANGE1_TO_RANGE0;
+
+ // Check for overflow (the old voltage should be larger unless we rolled over)
+ if (l_old_voltage < l_volt_buffer)
+ {
+ // Not using an extra xml error for this as overflow implies PMIC_VOLTAGE_OUT_OF_RANGE anyway.
+ FAPI_ERR("Overflow ocurred when converting SPD Range 1 voltage to TI Range 0");
+ l_overflow = true;
+ }
+ }
+ }
+
+ // Check for overflow due to range conversion (SWA-C), but also due to overflow due to offset attributes
+ FAPI_ASSERT( (!l_overflow) && (l_volt_buffer <= CONSTS::MAX_VOLT_BITMAP),
+ fapi2::PMIC_VOLTAGE_OUT_OF_RANGE()
+ .set_TARGET(i_pmic_target)
+ .set_VOLTAGE_BITMAP(l_volt_buffer)
+ .set_RAIL(mss::pmic::VOLT_SETTING_REGS[l_rail_index]),
+ "Voltage out of range as determined by SPD voltage +/- offset for %s of %s",
+ PMIC_RAIL_NAMES[l_rail_index], mss::c_str(i_pmic_target) );
+
+ l_volt_buffer = l_volt_buffer << CONSTS::SHIFT_VOLTAGE_FOR_REG;
+ FAPI_TRY(mss::pmic::i2c::reg_write(i_pmic_target, mss::pmic::VOLT_SETTING_REGS[l_rail_index], l_volt_buffer),
+ "Error writing address 0x%02hhX of PMIC %s", mss::pmic::VOLT_SETTING_REGS[l_rail_index], mss::c_str(i_pmic_target));
+
+ }
+
+ return fapi2::FAPI2_RC_SUCCESS;
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Bias PMIC from SPD settings per vendor
+///
+/// @tparam V mss::pmic::vendor (IDT/TI)
+/// @param[in] i_pmic_target PMIC target
+/// @param[in] i_dimm_target DIMM target associated with PMIC
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS iff success
+///
+template <mss::pmic::vendor V>
+fapi2::ReturnCode bias_with_spd_settings(
+ const fapi2::Target<fapi2::TargetType::TARGET_TYPE_PMIC>& i_pmic_target,
+ const fapi2::Target<fapi2::TargetType::TARGET_TYPE_DIMM>& i_dimm_target);
+
+///
+/// @brief Bias IDT PMIC from SPD settings
+///
+/// @param[in] i_pmic_target PMIC target
+/// @param[in] i_dimm_target DIMM target
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS iff success
+///
+template<>
+inline fapi2::ReturnCode bias_with_spd_settings<mss::pmic::vendor::IDT>(
+ const fapi2::Target<fapi2::TargetType::TARGET_TYPE_PMIC>& i_pmic_target,
+ const fapi2::Target<fapi2::TargetType::TARGET_TYPE_DIMM>& i_dimm_target)
+{
+ using CONSTS = mss::pmic::consts<mss::pmic::product::JEDEC_COMPLIANT>;
+ // Unlock Vendor Region
+ FAPI_TRY(mss::pmic::unlock_vendor_region(i_pmic_target),
+ "Error unlocking vendor region on PMIC %s", mss::c_str(i_pmic_target));
+
+ {
+ // PMIC position/ID of the OCMB target. There could be 4 total, but we care about whether its PMIC0(2) or PMIC1(3)
+ const mss::pmic::id l_relative_pmic_id = static_cast<mss::pmic::id>(
+ mss::index(i_pmic_target) % CONSTS::NUM_UNIQUE_PMICS);
+
+ // Phase combination
+ FAPI_TRY(mss::pmic::bias_with_spd_phase_comb(i_pmic_target, i_dimm_target, l_relative_pmic_id));
+
+ // Voltage ranges
+ FAPI_TRY(mss::pmic::bias_with_spd_volt_ranges(i_pmic_target, i_dimm_target, l_relative_pmic_id));
+
+ // Voltages
+ FAPI_TRY(mss::pmic::bias_with_spd_voltages<mss::pmic::IDT>(i_pmic_target, i_dimm_target, l_relative_pmic_id));
+
+ // Startup sequence
+ FAPI_TRY(mss::pmic::bias_with_spd_startup_seq(i_pmic_target, i_dimm_target, l_relative_pmic_id));
+ }
+
+fapi_try_exit:
+ // Try to lock vendor region even in the case of an error in this function
+ return mss::pmic::lock_vendor_region(i_pmic_target, fapi2::current_err);
+}
+
+///
+/// @brief Bias TI PMIC from SPD settings
+///
+/// @param[in] i_pmic_target PMIC target
+/// @param[in] i_dimm_target DIMM target
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS iff success
+///
+template<>
+inline fapi2::ReturnCode bias_with_spd_settings<mss::pmic::vendor::TI>(
+ const fapi2::Target<fapi2::TargetType::TARGET_TYPE_PMIC>& i_pmic_target,
+ const fapi2::Target<fapi2::TargetType::TARGET_TYPE_DIMM>& i_dimm_target)
+{
+ using CONSTS = mss::pmic::consts<mss::pmic::product::JEDEC_COMPLIANT>;
+ // Unlock Vendor Region
+ FAPI_TRY(mss::pmic::unlock_vendor_region(i_pmic_target),
+ "Error unlocking vendor region on PMIC %s", mss::c_str(i_pmic_target));
+
+ {
+ // PMIC position/ID of the OCMB target. There could be 4 total, but we care about whether its PMIC0(2) or PMIC1(3)
+ const mss::pmic::id l_relative_pmic_id = static_cast<mss::pmic::id>(
+ mss::index(i_pmic_target) % CONSTS::NUM_UNIQUE_PMICS);
+ // Phase combination
+ FAPI_TRY(mss::pmic::bias_with_spd_phase_comb(i_pmic_target, i_dimm_target, l_relative_pmic_id));
+
+ // Voltages
+ // TI pmic only has range 0 for SWA-C. We need to convert anything SPD that says range 1 --> range 0
+ FAPI_TRY(mss::pmic::bias_with_spd_voltages<mss::pmic::TI>(i_pmic_target, i_dimm_target, l_relative_pmic_id));
+
+ // Startup sequence
+ FAPI_TRY(mss::pmic::bias_with_spd_startup_seq(i_pmic_target, i_dimm_target, l_relative_pmic_id));
+ }
+
+fapi_try_exit:
+ // Try to lock vendor region even in the case of an error in this function
+ return mss::pmic::lock_vendor_region(i_pmic_target, fapi2::current_err);
+}
+
+//------------------- ENABLE FUNCTIONS-----------------//
+
+///
+/// @brief template function for the chip-specific enable functions
+///
+/// @tparam H module_height
+/// @param[in] i_pmic_target - the pmic target
+/// @param[in] i_dimm_target - the dimm target that the PMIC resides on
+/// @param[in] i_vendor_id - the vendor ID of the PMIC to bias
+/// @param[in] i_mode enable mode operation
+/// @return fapi2::ReturnCode - FAPI2_RC_SUCCESS if successful
+///
+template <mss::pmic::module_height H>
+fapi2::ReturnCode enable_chip(const fapi2::Target<fapi2::TargetType::TARGET_TYPE_PMIC>& i_pmic_target,
+ const fapi2::Target<fapi2::TargetType::TARGET_TYPE_DIMM>& i_dimm_target,
+ const uint16_t i_vendor_id,
+ const mss::pmic::enable_mode i_mode);
+
+///
+/// @brief enable procedure for IDT PMIC and 1U or 2U DIMM
+///
+/// @param[in] i_pmic_target - the pmic_target
+/// @param[in] i_dimm_target - the dimm target that the PMIC resides on
+/// @param[in] i_vendor_id - the vendor ID of the PMIC to bias
+/// @param[in] i_mode enable mode operation
+/// @return fapi2::ReturnCode - FAPI2_RC_SUCCESS if successful
+///
+template <>
+inline fapi2::ReturnCode enable_chip<mss::pmic::module_height::HEIGHT_1U>(
+ const fapi2::Target<fapi2::TARGET_TYPE_PMIC>& i_pmic_target,
+ const fapi2::Target<fapi2::TargetType::TARGET_TYPE_DIMM>& i_dimm_target,
+ const uint16_t i_vendor_id,
+ const mss::pmic::enable_mode i_mode)
+{
+ if (i_mode == mss::pmic::enable_mode::SPD)
+ {
+ FAPI_INF("Setting PMIC settings from SPD");
+
+ // Make sure it is TI or IDT
+ FAPI_ASSERT((i_vendor_id == mss::pmic::vendor::IDT ||
+ i_vendor_id == mss::pmic::vendor::TI),
+ fapi2::PMIC_CHIP_NOT_RECOGNIZED()
+ .set_TARGET(i_pmic_target)
+ .set_VENDOR_ID(i_vendor_id),
+ "Unknown PMIC: %s with vendor ID 0x%04hhX",
+ mss::c_str(i_pmic_target),
+ uint8_t(i_vendor_id) );
+
+ if (i_vendor_id == mss::pmic::vendor::IDT)
+ {
+ FAPI_TRY(mss::pmic::bias_with_spd_settings<mss::pmic::vendor::IDT>(i_pmic_target, i_dimm_target),
+ "enable_chip<IDT, 1U/2U>: Error biasing PMIC %s with SPD settings",
+ mss::c_str(i_pmic_target));
+ }
+ else // assert done in pmic_enable.C that vendor is IDT or TI
+ {
+ FAPI_TRY(mss::pmic::bias_with_spd_settings<mss::pmic::vendor::TI>(i_pmic_target, i_dimm_target),
+ "enable_chip<TI, 1U/2U>: Error biasing PMIC %s with SPD settings",
+ mss::c_str(i_pmic_target));
+ }
+ }
+ else // manual mode
+ {
+ FAPI_INF("Using built-in PMIC settings (defaults or from pmic_update)");
+ }
+
+ // Execute VR Enable command
+ FAPI_TRY((mss::pmic::start_vr_enable(i_pmic_target)),
+ "enable_chip: Failed to start VR Enable for %s", mss::c_str(i_pmic_target));
+
+ return fapi2::FAPI2_RC_SUCCESS;
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+}
+} // mss
#endif
OpenPOWER on IntegriCloud