Skip to content

Commit

Permalink
Check PMIC error and enable statuses after pmic_enable
Browse files Browse the repository at this point in the history
Change-Id: I26bc700a3b368c9bd110ee62b1037a6c6d14491e
Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/83886
Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com>
Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com>
Tested-by: Hostboot CI <hostboot-ci+hostboot@us.ibm.com>
Reviewed-by: Louis Stermole <stermole@us.ibm.com>
Reviewed-by: STEPHEN GLANCY <sglancy@us.ibm.com>
Reviewed-by: Jennifer A Stofer <stofer@us.ibm.com>
Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/83904
Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com>
Reviewed-by: Daniel M Crowell <dcrowell@us.ibm.com>
  • Loading branch information
markypizz authored and dcrowell77 committed Oct 8, 2019
1 parent 23d883c commit c349ba9
Show file tree
Hide file tree
Showing 7 changed files with 519 additions and 53 deletions.
25 changes: 25 additions & 0 deletions src/import/chips/ocmb/common/include/pmic_regs_fld.H
Expand Up @@ -69,6 +69,31 @@ struct pmicFields<mss::pmic::product::JEDEC_COMPLIANT>
static constexpr uint8_t SEQUENCE_SWC_ENABLE = 0x04;
static constexpr uint8_t SEQUENCE_SWD_ENABLE = 0x03;

// R04
static constexpr uint8_t R04_GLOBAL_ERROR_COUNT = 0x07;
static constexpr uint8_t R04_GLOBAL_ERROR_LOG_BUCK_OV_OR_UV = 0x06;
static constexpr uint8_t R04_GLOBAL_ERROR_LOG_VIN_BULK_OVER_VOLTAGE = 0x05;
static constexpr uint8_t R04_GLOBAL_ERROR_LOG_CRITICAL_TEMPERATURE = 0x04;

// R05
static constexpr uint8_t R05_SWA_POWER_GOOD = 0x06;
static constexpr uint8_t R05_SWB_POWER_GOOD = 0x05;
static constexpr uint8_t R05_SWC_POWER_GOOD = 0x04;
static constexpr uint8_t R05_SWD_POWER_GOOD = 0x03;
static constexpr uint8_t R05_PMIC_ERROR_LOG = 0x02; // TK ARRAY

// R06
static constexpr uint8_t R06_SWA_UNDER_VOLTAGE_LOCKOUT = 0x07;
static constexpr uint8_t R06_SWB_UNDER_VOLTAGE_LOCKOUT = 0x06;
static constexpr uint8_t R06_SWC_UNDER_VOLTAGE_LOCKOUT = 0x05;
static constexpr uint8_t R06_SWD_UNDER_VOLTAGE_LOCKOUT = 0x04;
static constexpr uint8_t R06_SWA_OVER_VOLTAGE = 0x03;
static constexpr uint8_t R06_SWB_OVER_VOLTAGE = 0x02;
static constexpr uint8_t R06_SWC_OVER_VOLTAGE = 0x01;
static constexpr uint8_t R06_SWD_OVER_VOLTAGE = 0x00;

// R07 all reserved

// R08
static constexpr uint8_t R08_VIN_BULK_INPUT_PWR_GOOD_STATUS = 0x07;
static constexpr uint8_t R08_CRITICAL_TEMP_SHUTDOWN_STATUS = 0x06;
Expand Down
Expand Up @@ -145,5 +145,202 @@ fapi_try_exit:
return ((i_rc == fapi2::FAPI2_RC_SUCCESS) ? fapi2::current_err : i_rc);
}

///
/// @brief Check if PMIC is IDT vendor
///
/// @param[in] i_pmic_target PMIC target
/// @param[out] o_is_idt true/false
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS iff success, else error code
/// @note Can't unit test this properly as R3D is hardcoded in simics
///
fapi2::ReturnCode pmic_is_idt(const fapi2::Target<fapi2::TARGET_TYPE_PMIC>& i_pmic_target, bool& o_is_idt)
{
o_is_idt = false;
using REGS = pmicRegs<mss::pmic::product::JEDEC_COMPLIANT>;
fapi2::buffer<uint8_t> l_reg_contents;

FAPI_TRY(mss::pmic::i2c::reg_read(i_pmic_target, REGS::R3D_VENDOR_ID_BYTE_1, l_reg_contents));

o_is_idt = (l_reg_contents == mss::pmic::vendor::IDT_SHORT);

fapi_try_exit:
return fapi2::current_err;
}

namespace status
{

///
/// @brief Checks that the PMIC is enabled via VR Enable bit
///
/// @param[in] i_ocmb_target OCMB target
/// @param[in] i_pmic_target PMIC target
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS iff success, else error code
///
fapi2::ReturnCode check_for_vr_enable(
const fapi2::Target<fapi2::TARGET_TYPE_OCMB_CHIP>& i_ocmb_target,
const fapi2::Target<fapi2::TargetType::TARGET_TYPE_PMIC>& i_pmic_target)
{
fapi2::buffer<uint8_t> l_vr_enable_buffer;

FAPI_TRY(mss::pmic::i2c::reg_read_reverse_buffer(i_pmic_target, REGS::R32, l_vr_enable_buffer),
"start_vr_enable: Could not read address 0x%02hhX of %s to check for VR Enable",
REGS::R32,
mss::c_str(i_pmic_target));

// Make sure we are enabled
FAPI_ASSERT(l_vr_enable_buffer.getBit<FIELDS::R32_VR_ENABLE>(),
fapi2::PMIC_NOT_ENABLED()
.set_PMIC_TARGET(i_pmic_target)
.set_OCMB_TARGET(i_ocmb_target),
"PMIC %s was not identified as enabled by checking VR Enable bit",
mss::c_str(i_pmic_target));

return fapi2::FAPI2_RC_SUCCESS;

fapi_try_exit:
return fapi2::current_err;
}

///
/// @brief Check the statuses of all PMICs present on the given OCMB chip
///
/// @param[in] i_ocmb_target OCMB target
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if success, else error code
/// @note the returned target is only valid if o_errors returns as true. Else, the target is an uninitialized blank target!
///
fapi2::ReturnCode check_all_pmics(const fapi2::Target<fapi2::TARGET_TYPE_OCMB_CHIP>& i_ocmb_target)
{
const char* l_ocmb_c_str = mss::c_str(i_ocmb_target);

// Initialize returnable PMIC with a blank target. This blank target won't be used if there's no error.
// If there is an error, this will be overwritten with a valid erroneous PMIC
bool l_pmic_error = false;

fapi2::current_err = fapi2::FAPI2_RC_SUCCESS;

// Start success so we can't log and return the same error in loop logic
fapi2::ReturnCode l_rc = fapi2::FAPI2_RC_SUCCESS;

// Check that the PMICs are enabled and without errors
for (const auto& l_pmic : mss::find_targets<fapi2::TARGET_TYPE_PMIC>(i_ocmb_target))
{
FAPI_TRY(check_for_vr_enable(i_ocmb_target, l_pmic),
"PMIC %s did not return enabled status", mss::c_str(l_pmic));

FAPI_TRY(mss::pmic::status::check_pmic(l_pmic, l_pmic_error));

FAPI_ASSERT_NOEXIT(!l_pmic_error,
fapi2::PMIC_STATUS_ERRORS()
.set_OCMB_TARGET(i_ocmb_target)
.set_PMIC_TARGET(l_pmic),
"PMIC on OCMB %s had one or more status bits set after running pmic_enable(). "
"One of possibly several bad PMICs: %s",
l_ocmb_c_str, mss::c_str(l_pmic));

if (l_rc != fapi2::FAPI2_RC_SUCCESS)
{
fapi2::logError(fapi2::current_err, fapi2::FAPI2_ERRL_SEV_UNRECOVERABLE);
}

// Reset for next loop
l_rc = fapi2::current_err;
l_pmic_error = false;
fapi2::current_err = fapi2::FAPI2_RC_SUCCESS;
}

// Else, exit on whatever RC we had
FAPI_TRY(l_rc);

fapi_try_exit:
return fapi2::current_err;
}

///
/// @brief Check the PMIC's status codes and report back if an error occurred
///
/// @param[in] i_pmic_target PMIC target
/// @param[out] o_error true/false
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS iff success, else error
///
fapi2::ReturnCode check_pmic(
const fapi2::Target<fapi2::TARGET_TYPE_PMIC>& i_pmic_target,
bool& o_error)
{
o_error = false;
bool l_pmic_is_idt = false;

FAPI_TRY(pmic_is_idt(i_pmic_target, l_pmic_is_idt));

if (l_pmic_is_idt)
{
// These registers reflect the previous power down cycle of the PMIC. Therefore, they may
// not necessarily cause issues on this life. So, we do not need to worry about keeping track if
// these failed with l_status_error, but the check_fields() function will still print them out.
bool l_status_error = false;

// if we exit from this try, there were i2c errors
FAPI_TRY(mss::pmic::status::check_fields(i_pmic_target, mss::pmic::status::IDT_SPECIFIC_STATUS_FIELDS, l_status_error));
}

{
bool l_status_error = false;

// if we exit from this try, there were i2c errors
FAPI_TRY(mss::pmic::status::check_fields(i_pmic_target, mss::pmic::status::STATUS_FIELDS, l_status_error));
o_error = l_status_error;
}

fapi_try_exit:
return fapi2::current_err;
}

///
/// @brief Check an individual set of PMIC status codes
///
/// @param[in] i_pmic_target PMIC target
/// @param[in] i_statuses STATUS object to check
/// @param[out] o_error At least one error bit was found to be set
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS iff success, else error in case of an I2C read error
///
fapi2::ReturnCode check_fields(
const fapi2::Target<fapi2::TARGET_TYPE_PMIC>& i_pmic_target,
const std::vector<std::pair<uint8_t, std::vector<status_field>>>& i_statuses,
bool& o_error)
{
o_error = false;

for (const auto& l_reg_bit_pair : i_statuses)
{
fapi2::buffer<uint8_t> l_reg_contents;
FAPI_TRY(mss::pmic::i2c::reg_read_reverse_buffer(i_pmic_target, l_reg_bit_pair.first, l_reg_contents));

for (const auto& l_status : l_reg_bit_pair.second)
{
if (l_reg_contents.getBit(l_status.l_reg_field))
{
// Print it out
FAPI_ERR("%s :: REG 0x%02x bit %u was set on %s",
l_status.l_error_description,
l_reg_bit_pair.first,
l_status.l_reg_field,
mss::c_str(i_pmic_target));
// We don't want to exit out here, errors can be independent of each other and we should check them all.
// Since there's no easy way to FFDC each individual error, we will report them here and then worry about
// return codes in the caller of this function
o_error = true;
}
}

l_reg_contents.flush<0>();
}

return fapi2::FAPI2_RC_SUCCESS;

fapi_try_exit:
return fapi2::current_err;
}

} // status
} // pmic
} // mss
Expand Up @@ -159,6 +159,161 @@ fapi2::ReturnCode unlock_vendor_region(const fapi2::Target<fapi2::TargetType::TA
fapi2::ReturnCode lock_vendor_region(const fapi2::Target<fapi2::TargetType::TARGET_TYPE_PMIC>& i_pmic_target,
const fapi2::ReturnCode i_rc = fapi2::FAPI2_RC_SUCCESS);

///
/// @brief Check if PMIC is IDT vendor
///
/// @param[in] i_pmic_target PMIC target
/// @param[out] o_is_idt true/false
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS iff success, else error code
///
fapi2::ReturnCode pmic_is_idt(const fapi2::Target<fapi2::TARGET_TYPE_PMIC>& i_pmic_target, bool& o_is_idt);

namespace status
{

///
/// @brief Information for each field that we can iterate through
///
struct status_field
{
uint8_t l_reg_field;
const char* l_error_description;
};

static const std::vector<std::pair<uint8_t, std::vector<status_field>>> IDT_SPECIFIC_STATUS_FIELDS =
{
{
REGS::R04,
{ {FIELDS::R04_GLOBAL_ERROR_COUNT, "GLOBAL_ERROR_COUNT: >1 error count since last erase operation"},
{FIELDS::R04_GLOBAL_ERROR_LOG_BUCK_OV_OR_UV, "GLOBAL_ERROR_LOG: BUCK OV/UV: Error occurred"},
{FIELDS::R04_GLOBAL_ERROR_LOG_VIN_BULK_OVER_VOLTAGE, "GLOBAL_ERROR_LOG: VIN_BULK_OVER_VOLTAGE"},
{FIELDS::R04_GLOBAL_ERROR_LOG_CRITICAL_TEMPERATURE, "GLOBAL_ERROR_LOG: CRITICAL_TEMPERATURE"}
}
},

{
REGS::R05,
{ {FIELDS::R05_SWA_POWER_GOOD, "PMIC POWER ON: SWA_PWR_NOT_GOOD"},
{FIELDS::R05_SWB_POWER_GOOD, "PMIC POWER ON: SWB_PWR_NOT_GOOD"},
{FIELDS::R05_SWC_POWER_GOOD, "PMIC POWER ON: SWC_PWR_NOT_GOOD"},
{FIELDS::R05_SWD_POWER_GOOD, "PMIC POWER ON: SWD_PWR_NOT_GOOD"}
}
},

{
REGS::R06,
{ {FIELDS::R06_SWA_UNDER_VOLTAGE_LOCKOUT, "SWA_UNDER_VOLTAGE_LOCKOUT"},
{FIELDS::R06_SWB_UNDER_VOLTAGE_LOCKOUT, "SWB_UNDER_VOLTAGE_LOCKOUT"},
{FIELDS::R06_SWC_UNDER_VOLTAGE_LOCKOUT, "SWC_UNDER_VOLTAGE_LOCKOUT"},
{FIELDS::R06_SWD_UNDER_VOLTAGE_LOCKOUT, "SWD_UNDER_VOLTAGE_LOCKOUT"},
{FIELDS::R06_SWA_OVER_VOLTAGE, "SWA_OVER_VOLTAGE"},
{FIELDS::R06_SWB_OVER_VOLTAGE, "SWB_OVER_VOLTAGE"},
{FIELDS::R06_SWC_OVER_VOLTAGE, "SWC_OVER_VOLTAGE"},
{FIELDS::R06_SWD_OVER_VOLTAGE, "SWD_OVER_VOLTAGE"}
}
}
};

///
/// @brief const vector of statuses to check
///
static const std::vector<std::pair<uint8_t, std::vector<status_field>>> STATUS_FIELDS =
{
{
REGS::R08,
{ {FIELDS::R08_VIN_BULK_INPUT_PWR_GOOD_STATUS, "VIN_BULK_INPUT_PWR_NOT_GOOD"},
{FIELDS::R08_CRITICAL_TEMP_SHUTDOWN_STATUS, "CRITICAL_TEMP_SHUTDOWN"},
{FIELDS::R08_SWA_PWR_GOOD_STATUS, "SWA_PWR_NOT_GOOD"},
{FIELDS::R08_SWB_PWR_GOOD_STATUS, "SWB_PWR_NOT_GOOD"},
{FIELDS::R08_SWC_PWR_GOOD_STATUS, "SWC_PWR_NOT_GOOD"},
{FIELDS::R08_SWD_PWR_GOOD_STATUS, "SWD_PWR_NOT_GOOD"},
{FIELDS::R08_VIN_MGMT_INPUT_OVER_VOLTAGE, "VIN_MGMT_INPUT_OVER_VOLTAGE"},
{FIELDS::R08_VIN_BULK_INPUT_OVER_VOLTAGE, "VIN_BULK_INPUT_OVER_VOLTAGE"}
}
},

{
REGS::R09,
{ {FIELDS::R09_PMIC_HIGH_TEMP_WARNING_STATUS, "PMIC Temperature exceeded warning threshold"},
{FIELDS::R09_VBIAS_PWR_GOOD_STATUS, "VBIAS_PWR_NOT_GOOD"},
{FIELDS::R09_VOUT_1_8_V_PWR_GOOD_STATUS, "VOUT_1.8V_PWR_NOT_GOOD"},
{FIELDS::R09_VIN_MGMT_TO_VIN_BULK_SWITCHOVER_STATUS, "VIN_MGMT is removed (using VIN_Bulk)"},
{FIELDS::R09_SWA_HIGH_OUTPUT_CURRENT_CONSUMPTION_WARNING_STATUS, "SWA_HIGH_OUTPUT_CURRENT_CONSUMPTION_WARNING"},
{FIELDS::R09_SWB_HIGH_OUTPUT_CURRENT_CONSUMPTION_WARNING_STATUS, "SWB_HIGH_OUTPUT_CURRENT_CONSUMPTION_WARNING"},
{FIELDS::R09_SWC_HIGH_OUTPUT_CURRENT_CONSUMPTION_WARNING_STATUS, "SWC_HIGH_OUTPUT_CURRENT_CONSUMPTION_WARNING"},
{FIELDS::R09_SWD_HIGH_OUTPUT_CURRENT_CONSUMPTION_WARNING_STATUS, "SWD_HIGH_OUTPUT_CURRENT_CONSUMPTION_WARNING"}
}
},

{
REGS::R0A,
{ {FIELDS::R0A_SWA_OUTPUT_OVER_VOLTAGE_STATUS, "SWA_OUTPUT_OVER_VOLTAGE"},
{FIELDS::R0A_SWB_OUTPUT_OVER_VOLTAGE_STATUS, "SWB_OUTPUT_OVER_VOLTAGE"},
{FIELDS::R0A_SWC_OUTPUT_OVER_VOLTAGE_STATUS, "SWC_OUTPUT_OVER_VOLTAGE"},
{FIELDS::R0A_SWD_OUTPUT_OVER_VOLTAGE_STATUS, "SWD_OUTPUT_OVER_VOLTAGE"},
{FIELDS::R0A_PEC_ERROR_STATUS, "PEC_ERROR"},
{FIELDS::R0A_PARITY_ERROR_STATUS, "PARITY_ERROR"},
{FIELDS::R0A_IBI_STATUS, "PENDING_IBI"}
}
},

{
REGS::R0B,
{ {FIELDS::R0B_SWA_OUTPUT_CURRENT_LIMITER_WARNING_STATUS, "SWA_OUTPUT_CURRENT_LIMITER_EVENT"},
{FIELDS::R0B_SWB_OUTPUT_CURRENT_LIMITER_WARNING_STATUS, "SWB_OUTPUT_CURRENT_LIMITER_EVENT"},
{FIELDS::R0B_SWC_OUTPUT_CURRENT_LIMITER_WARNING_STATUS, "SWC_OUTPUT_CURRENT_LIMITER_EVENT"},
{FIELDS::R0B_SWD_OUTPUT_CURRENT_LIMITER_WARNING_STATUS, "SWD_OUTPUT_CURRENT_LIMITER_EVENT"},
{FIELDS::R0B_SWA_OUTPUT_UNDER_VOLTAGE_LOCKOUT_STATUS , "SWA_OUTPUT_UNDER_VOLTAGE_LOCKOUT"},
{FIELDS::R0B_SWB_OUTPUT_UNDER_VOLTAGE_LOCKOUT_STATUS , "SWB_OUTPUT_UNDER_VOLTAGE_LOCKOUT"},
{FIELDS::R0B_SWC_OUTPUT_UNDER_VOLTAGE_LOCKOUT_STATUS , "SWC_OUTPUT_UNDER_VOLTAGE_LOCKOUT"},
{FIELDS::R0B_SWD_OUTPUT_UNDER_VOLTAGE_LOCKOUT_STATUS , "SWD_OUTPUT_UNDER_VOLTAGE_LOCKOUT"}
}
}
};

///
/// @brief Checks that the PMIC is enabled via VR Enable bit
///
/// @param[in] i_ocmb_target OCMB target
/// @param[in] i_pmic_target PMIC target
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS iff success, else error code
///
fapi2::ReturnCode check_for_vr_enable(
const fapi2::Target<fapi2::TARGET_TYPE_OCMB_CHIP>& i_ocmb_target,
const fapi2::Target<fapi2::TargetType::TARGET_TYPE_PMIC>& i_pmic_target);

///
/// @brief Check the statuses of all PMICs present on the given OCMB chip
///
/// @param[in] i_ocmb_target OCMB target
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if success, else error code
/// @note the returned target is only valid if o_errors returns as true. Else, the target is an uninitialized blank target!
///
fapi2::ReturnCode check_all_pmics(const fapi2::Target<fapi2::TARGET_TYPE_OCMB_CHIP>& i_ocmb_target);

///
/// @brief Check the PMIC's status codes and report back if an error occurred
///
/// @param[in] i_pmic_target PMIC target
/// @param[out] o_error true/false
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS iff success, else error
///
fapi2::ReturnCode check_pmic(const fapi2::Target<fapi2::TARGET_TYPE_PMIC>& i_pmic_target, bool& o_error);

///
/// @brief Check the IDT specific status codes
///
/// @param[in] i_pmic_target PMIC target
/// @param[in] i_statuses STATUS object to check
/// @param[out] o_error At least one error bit was found to be set
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS iff success, else error in case of an I2C read error
///
fapi2::ReturnCode check_fields(
const fapi2::Target<fapi2::TARGET_TYPE_PMIC>& i_pmic_target,
const std::vector<std::pair<uint8_t, std::vector<status_field>>>& i_statuses,
bool& o_error);

} // status
} // pmic
} // mss

Expand Down

0 comments on commit c349ba9

Please sign in to comment.