Skip to content

Commit 35f0f22

Browse files
snehakadam85dcrowell77
authored andcommitted
Implemented new PMIC power-down sequence
ZEN:MST-811 CQ:SW530990 Change-Id: Ia72e13d4342964b8ef128967f3ffd62698600a07 Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/120723 Tested-by: Jenkins Server <[email protected]> Tested-by: HWSV CI <[email protected]> Tested-by: PPE CI <[email protected]> Tested-by: FSP CI Jenkins <[email protected]> Tested-by: Hostboot CI <[email protected]> Reviewed-by: Michael D Pardeik <[email protected]> Reviewed-by: STEPHEN GLANCY <[email protected]> Reviewed-by: Louis Stermole <[email protected]> Dev-Ready: Sneha Kadam <[email protected]> Reviewed-by: Edgar R Cordero <[email protected]> Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/121632 Tested-by: Jenkins OP Build CI <[email protected]> Tested-by: Jenkins OP HW <[email protected]> Tested-by: Jenkins Combined Simics CI <[email protected]> Reviewed-by: Daniel M Crowell <[email protected]>
1 parent f3c9410 commit 35f0f22

File tree

3 files changed

+316
-36
lines changed

3 files changed

+316
-36
lines changed

src/import/chips/ocmb/common/procedures/hwp/pmic/lib/utils/pmic_consts.H

+2-1
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ struct consts<mss::pmic::product::JEDEC_COMPLIANT>
280280
static constexpr uint8_t R30_SAMPLE_VIN_BULK_ENABLE_ADC = 0xA8;
281281

282282
// R31
283-
static constexpr uint8_t R31_VIN_BULK_EFUSE_OFF_HIGH = 0x04;
283+
static constexpr uint8_t R31_VIN_BULK_EFUSE_OFF_HIGH = 0x08;
284284
static constexpr uint8_t R31_VIN_BULK_EFUSE_ON_HIGH = 0xBF;
285285
static constexpr uint8_t R31_VIN_BULK_EFUSE_ON_LOW = 0x9D;
286286

@@ -459,6 +459,7 @@ enum fields
459459
GPIO_CFG_CH0_DIGITAL_GP0 = 0x01,
460460
PIN_CFG_CH0_GPIO = 0x01,
461461
GENERAL_CFG_EN_DIGITAL_WINDOW_COMPARATOR_AND_STATS = 0x30,
462+
GENERAL_CFG_CLEAR_STATS_EN = 0x10,
462463
SEQUENCE_CFG_CHANNEL_SEQUENCING = 0x11,
463464
SEQUENCE_CFG_AUTO_SEQUENCE = 0x01,
464465
AUTO_SEQ_CH_SEL_ALL_AUTO_SEQUENCING = 0xFF,

src/import/chips/ocmb/common/procedures/hwp/pmic/lib/utils/pmic_enable_utils.C

+283-35
Original file line numberDiff line numberDiff line change
@@ -881,6 +881,247 @@ fapi_try_exit:
881881
return fapi2::current_err;
882882
}
883883

884+
///
885+
/// @brief PMIC power down sequence for 1U/2U parts
886+
///
887+
/// @param[in] i_target OCMB target
888+
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS iff success, else error code
889+
///
890+
fapi2::ReturnCode power_down_sequence_1u_2u(const fapi2::Target<fapi2::TARGET_TYPE_OCMB_CHIP>& i_target)
891+
{
892+
using REGS = pmicRegs<mss::pmic::product::JEDEC_COMPLIANT>;
893+
using FIELDS = pmicFields<mss::pmic::product::JEDEC_COMPLIANT>;
894+
895+
fapi2::ReturnCode l_rc = fapi2::FAPI2_RC_SUCCESS;
896+
897+
auto l_pmics = mss::find_targets_sorted_by_pos<fapi2::TARGET_TYPE_PMIC>(i_target);
898+
899+
// Next, sort them by the sequence attributes
900+
FAPI_TRY(mss::pmic::order_pmics_by_sequence(i_target, l_pmics));
901+
902+
// Reverse loop, so we disable in the opposite order as the enable
903+
for (int16_t l_i = (l_pmics.size() - 1); l_i >= 0; --l_i)
904+
{
905+
const auto& PMIC = l_pmics[l_i];
906+
fapi2::buffer<uint8_t> l_reg_contents;
907+
908+
// Redundant clearBit, but just so it's clear what we're doing
909+
FAPI_TRY(mss::pmic::i2c::reg_read_reverse_buffer(PMIC, REGS::R32, l_reg_contents));
910+
l_reg_contents.clearBit<FIELDS::R32_VR_ENABLE>();
911+
912+
// Due to long soft stop time in 4U (~8ms), let's delay for 10ms to be safe
913+
fapi2::delay(10 * mss::common_timings::DELAY_1MS, mss::common_timings::DELAY_1MS);
914+
915+
// We are opting here to log RC's here as recovered. If this register write fails,
916+
// the ones later in the procedure will fail as well.
917+
l_rc = mss::pmic::i2c::reg_write_reverse_buffer(PMIC, REGS::R32, l_reg_contents);
918+
919+
if (l_rc != fapi2::FAPI2_RC_SUCCESS)
920+
{
921+
fapi2::logError(l_rc, fapi2::FAPI2_ERRL_SEV_RECOVERED);
922+
fapi2::current_err = fapi2::FAPI2_RC_SUCCESS;
923+
}
924+
925+
}
926+
927+
fapi_try_exit:
928+
return fapi2::current_err;
929+
}
930+
931+
///
932+
/// @brief PMIC power down sequence for 4U parts for pmic
933+
///
934+
/// @param[in,out] io_target_info Target info struct
935+
/// @return fapi2::ReturnCode
936+
///
937+
fapi2::ReturnCode pmic_clear_vr_swa_swc_en(target_info_redundancy& io_target_info)
938+
{
939+
using REGS = pmicRegs<mss::pmic::product::JEDEC_COMPLIANT>;
940+
using FIELDS = pmicFields<mss::pmic::product::JEDEC_COMPLIANT>;
941+
942+
// Regardless of the N-Mode states, we want to try to do a full disable of all parts
943+
// so if we do hit a failure on a PMIC write, we will just continue. enable_with_redundancy
944+
// on the next run of pmic_enable should catch read/write failures and handle them correctly
945+
// with the correct N-Mode declaration logic
946+
947+
// These PMIC writes have the potential to fail in N-Mode configs. We will not do any
948+
// N-mode declarations here as the runtime detection or next enable will catch all of these.
949+
FAPI_TRY_NO_TRACE(run_if_present(io_target_info.iv_pmic_map, mss::pmic::id::PMIC3, []
950+
(const fapi2::Target<fapi2::TARGET_TYPE_PMIC>& i_pmic) -> fapi2::ReturnCode
951+
{
952+
fapi2::buffer<uint8_t> l_reg_contents;
953+
954+
// VR Disable PMIC3
955+
mss::pmic::i2c::reg_read_reverse_buffer(i_pmic, REGS::R32, l_reg_contents);
956+
l_reg_contents.clearBit<FIELDS::R32_VR_ENABLE>();
957+
958+
mss::pmic::i2c::reg_write_reverse_buffer(i_pmic, REGS::R32, l_reg_contents);
959+
960+
return fapi2::FAPI2_RC_SUCCESS;
961+
}));
962+
963+
FAPI_TRY_NO_TRACE(run_if_present(io_target_info.iv_pmic_map, mss::pmic::id::PMIC1, []
964+
(const fapi2::Target<fapi2::TARGET_TYPE_PMIC>& i_pmic) -> fapi2::ReturnCode
965+
{
966+
fapi2::buffer<uint8_t> l_reg_contents;
967+
968+
// VR Disable PMIC1
969+
mss::pmic::i2c::reg_read_reverse_buffer(i_pmic, REGS::R32, l_reg_contents);
970+
l_reg_contents.clearBit<FIELDS::R32_VR_ENABLE>();
971+
972+
mss::pmic::i2c::reg_write_reverse_buffer(i_pmic, REGS::R32, l_reg_contents);
973+
974+
return fapi2::FAPI2_RC_SUCCESS;
975+
}));
976+
977+
FAPI_TRY_NO_TRACE(run_if_present(io_target_info.iv_pmic_map, mss::pmic::id::PMIC2, []
978+
(const fapi2::Target<fapi2::TARGET_TYPE_PMIC>& i_pmic) -> fapi2::ReturnCode
979+
{
980+
fapi2::buffer<uint8_t> l_reg_contents;
981+
982+
// Disable SWA and SWC of PMIC2
983+
mss::pmic::i2c::reg_read_reverse_buffer(i_pmic, REGS::R2F, l_reg_contents);
984+
985+
l_reg_contents.clearBit<FIELDS::R2F_SWA_REGULATOR_CONTROL>();
986+
l_reg_contents.clearBit<FIELDS::R2F_SWC_REGULATOR_CONTROL>();
987+
988+
mss::pmic::i2c::reg_write_reverse_buffer(i_pmic, REGS::R2F, l_reg_contents);
989+
990+
return fapi2::FAPI2_RC_SUCCESS;
991+
}));
992+
993+
FAPI_TRY_NO_TRACE(run_if_present(io_target_info.iv_pmic_map, mss::pmic::id::PMIC0, []
994+
(const fapi2::Target<fapi2::TARGET_TYPE_PMIC>& i_pmic) -> fapi2::ReturnCode
995+
{
996+
fapi2::buffer<uint8_t> l_reg_contents;
997+
998+
// Disable SWA and SWC of PMIC0
999+
mss::pmic::i2c::reg_read_reverse_buffer(i_pmic, REGS::R2F, l_reg_contents);
1000+
1001+
l_reg_contents.clearBit<FIELDS::R2F_SWA_REGULATOR_CONTROL>();
1002+
l_reg_contents.clearBit<FIELDS::R2F_SWC_REGULATOR_CONTROL>();
1003+
1004+
mss::pmic::i2c::reg_write_reverse_buffer(i_pmic, REGS::R2F, l_reg_contents);
1005+
1006+
return fapi2::FAPI2_RC_SUCCESS;
1007+
}));
1008+
1009+
// Delay 700ms to allow more time for VDDR to ramp down before VPP ramps down.
1010+
fapi2::delay(700 * mss::common_timings::DELAY_1MS, mss::common_timings::DELAY_1MS);
1011+
1012+
FAPI_TRY_NO_TRACE(run_if_present(io_target_info.iv_pmic_map, mss::pmic::id::PMIC0, []
1013+
(const fapi2::Target<fapi2::TARGET_TYPE_PMIC>& i_pmic) -> fapi2::ReturnCode
1014+
{
1015+
fapi2::buffer<uint8_t> l_reg_contents;
1016+
1017+
// VR Disable
1018+
mss::pmic::i2c::reg_read_reverse_buffer(i_pmic, REGS::R32, l_reg_contents);
1019+
l_reg_contents.clearBit<FIELDS::R32_VR_ENABLE>();
1020+
1021+
mss::pmic::i2c::reg_write_reverse_buffer(i_pmic, REGS::R32, l_reg_contents);
1022+
1023+
return fapi2::FAPI2_RC_SUCCESS;
1024+
}));
1025+
1026+
FAPI_TRY_NO_TRACE(run_if_present(io_target_info.iv_pmic_map, mss::pmic::id::PMIC2, []
1027+
(const fapi2::Target<fapi2::TARGET_TYPE_PMIC>& i_pmic) -> fapi2::ReturnCode
1028+
{
1029+
fapi2::buffer<uint8_t> l_reg_contents;
1030+
1031+
// VR Disable
1032+
mss::pmic::i2c::reg_read_reverse_buffer(i_pmic, REGS::R32, l_reg_contents);
1033+
l_reg_contents.clearBit<FIELDS::R32_VR_ENABLE>();
1034+
1035+
mss::pmic::i2c::reg_write_reverse_buffer(i_pmic, REGS::R32, l_reg_contents);
1036+
1037+
return fapi2::FAPI2_RC_SUCCESS;
1038+
}));
1039+
1040+
fapi2::current_err = fapi2::FAPI2_RC_SUCCESS;
1041+
1042+
fapi_try_exit:
1043+
return fapi2::current_err;
1044+
}
1045+
1046+
///
1047+
/// @brief PMIC power down sequence for 4U parts
1048+
///
1049+
/// @param[in] i_target OCMB target
1050+
/// @return fapi2::ReturnCode
1051+
///
1052+
fapi2::ReturnCode power_down_sequence_4u(const fapi2::Target<fapi2::TARGET_TYPE_OCMB_CHIP>& i_target)
1053+
{
1054+
fapi2::ReturnCode l_rc = fapi2::FAPI2_RC_SUCCESS;
1055+
1056+
const auto I2C_DEVICES =
1057+
mss::find_targets_sorted_by_pos<fapi2::TARGET_TYPE_GENERICI2CSLAVE>(i_target);
1058+
1059+
// Grab the targets as a struct, if they exist
1060+
target_info_redundancy l_target_info(i_target, l_rc);
1061+
// If platform did not provide a usable set of targets (4 GENERICI2CSLAVE, at least 2 PMICs),
1062+
// Then we can't properly disable, the part is as good as dead, since re-enable would fail
1063+
FAPI_TRY(l_rc, "Unusable PMIC/GENERICI2CSLAVE child target configuration found from %s",
1064+
mss::c_str(i_target));
1065+
1066+
// ADC or GPIO fails are hard fails.
1067+
// ADCs and GPIOs are guaranted to exist as asserted by l_rc above
1068+
FAPI_TRY(mss::pmic::i2c::reg_write(l_target_info.iv_adc1, mss::adc::regs::GENERAL_CFG,
1069+
mss::adc::fields::GENERAL_CFG_CLEAR_STATS_EN));
1070+
FAPI_TRY(mss::pmic::i2c::reg_write(l_target_info.iv_adc1, mss::adc::regs::SEQUENCE_CFG,
1071+
mss::adc::fields::SEQUENCE_CFG_AUTO_SEQUENCE));
1072+
1073+
FAPI_TRY(mss::pmic::i2c::reg_write(l_target_info.iv_adc2, mss::adc::regs::GENERAL_CFG,
1074+
mss::adc::fields::GENERAL_CFG_CLEAR_STATS_EN));
1075+
FAPI_TRY(mss::pmic::i2c::reg_write(l_target_info.iv_adc2, mss::adc::regs::SEQUENCE_CFG,
1076+
mss::adc::fields::SEQUENCE_CFG_AUTO_SEQUENCE));
1077+
1078+
FAPI_TRY(pmic_clear_vr_swa_swc_en(l_target_info));
1079+
1080+
// Finally, disable the GPIOs, and delay
1081+
FAPI_TRY(mss::pmic::i2c::reg_write(I2C_DEVICES[mss::GPIO1], mss::gpio::regs::EFUSE_OUTPUT,
1082+
mss::gpio::fields::EFUSE_OUTPUT_OFF));
1083+
FAPI_TRY(mss::pmic::i2c::reg_write(I2C_DEVICES[mss::GPIO2], mss::gpio::regs::EFUSE_OUTPUT,
1084+
mss::gpio::fields::EFUSE_OUTPUT_OFF));
1085+
1086+
// Delay 2 seconds. FW and cronus run pmic_enable in parallel. So the overall delay will only be 2 secs
1087+
// across all the targets during IPL
1088+
fapi2::delay(2000 * mss::common_timings::DELAY_1MS, mss::common_timings::DELAY_1MS);
1089+
1090+
fapi2::current_err = fapi2::FAPI2_RC_SUCCESS;
1091+
1092+
fapi_try_exit:
1093+
return fapi2::current_err;
1094+
}
1095+
1096+
///
1097+
/// @brief Power down function for 4U pmics
1098+
/// @param[in] i_target ocmb target
1099+
/// @return FAPI2_RC_SUCCESS iff ok
1100+
///
1101+
fapi2::ReturnCode pmic_power_down(const fapi2::Target<fapi2::TARGET_TYPE_OCMB_CHIP>& i_target)
1102+
{
1103+
uint8_t l_module_height = 0;
1104+
fapi2::ReturnCode l_rc = fapi2::FAPI2_RC_SUCCESS;
1105+
1106+
FAPI_TRY(mss::attr::get_dram_module_height(i_target, l_module_height));
1107+
1108+
// For non 4U configs, let's just VR disable down the line
1109+
if (l_module_height == fapi2::ENUM_ATTR_MEM_EFF_DRAM_MODULE_HEIGHT_4U)
1110+
{
1111+
// For 4U, do our defined disable sequence
1112+
FAPI_TRY(mss::pmic::power_down_sequence_4u(i_target));
1113+
}
1114+
else
1115+
{
1116+
FAPI_TRY(mss::pmic::power_down_sequence_1u_2u(i_target));
1117+
}
1118+
1119+
return fapi2::FAPI2_RC_SUCCESS;
1120+
1121+
fapi_try_exit:
1122+
return fapi2::current_err;
1123+
}
1124+
8841125
///
8851126
/// @brief Disable PMICs and clear status bits in preparation for enable
8861127
///
@@ -928,45 +1169,22 @@ fapi2::ReturnCode disable_and_reset_pmics(const fapi2::Target<fapi2::TARGET_TYPE
9281169
}
9291170
}
9301171

1172+
// Call the new PMIC power down sequence
1173+
FAPI_TRY(pmic_power_down(i_ocmb_target));
1174+
9311175
// Reverse loop
9321176
for (int16_t l_i = (l_pmics.size() - 1); l_i >= 0; --l_i)
9331177
{
9341178
const auto& PMIC = l_pmics[l_i];
9351179

936-
// First, disable
937-
{
938-
fapi2::buffer<uint8_t> l_reg_contents;
939-
940-
// Redundant clearBit, but just so it's clear what we're doing
941-
FAPI_TRY(mss::pmic::i2c::reg_read_reverse_buffer(PMIC, REGS::R32, l_reg_contents));
942-
l_reg_contents.clearBit<FIELDS::R32_VR_ENABLE>();
943-
944-
// Due to long soft stop time in 4U (~8ms), let's delay for 10ms to be safe
945-
fapi2::delay(10 * mss::common_timings::DELAY_1MS, mss::common_timings::DELAY_1MS);
946-
947-
// We are opting here to log RC's here as recovered. If this register write fails,
948-
// the ones later in the procedure will fail as well. The action to perform in
949-
// such a case is dependent on whether we do or do not have redundancy, which we
950-
// will know later in the procedure. As a result, we will not worry about failures here.
951-
l_rc = mss::pmic::i2c::reg_write_reverse_buffer(PMIC, REGS::R32, l_reg_contents);
952-
953-
if (l_rc != fapi2::FAPI2_RC_SUCCESS)
954-
{
955-
fapi2::logError(l_rc, fapi2::FAPI2_ERRL_SEV_RECOVERED);
956-
fapi2::current_err = fapi2::FAPI2_RC_SUCCESS;
957-
}
958-
}
959-
9601180
// Now that it's disabled, let's clear the status bits so errors don't hang over into the next enable
961-
{
962-
// Similarly, we will log bad ReturnCodes here as recoverable for the reasons mentioned above
963-
l_rc = mss::pmic::status::clear(PMIC);
1181+
// Similarly, we will log bad ReturnCodes here as recoverable for the reasons mentioned above
1182+
l_rc = mss::pmic::status::clear(PMIC);
9641183

965-
if (l_rc != fapi2::FAPI2_RC_SUCCESS)
966-
{
967-
fapi2::logError(l_rc, fapi2::FAPI2_ERRL_SEV_RECOVERED);
968-
fapi2::current_err = fapi2::FAPI2_RC_SUCCESS;
969-
}
1184+
if (l_rc != fapi2::FAPI2_RC_SUCCESS)
1185+
{
1186+
fapi2::logError(l_rc, fapi2::FAPI2_ERRL_SEV_RECOVERED);
1187+
fapi2::current_err = fapi2::FAPI2_RC_SUCCESS;
9701188
}
9711189
}
9721190

@@ -1256,9 +1474,39 @@ fapi2::ReturnCode validate_efuse_off(const fapi2::Target<fapi2::TARGET_TYPE_PMIC
12561474
// Prior to turning on the efuse via the GPIO expander, we expect to see VIN below the
12571475
// EFUSE_OFF_HIGH threshold, as power will not be applied.
12581476
// Otherwise the efuse must be blown, and we should declare N-mode.
1259-
if (l_reg_contents > CONSTS::R31_VIN_BULK_EFUSE_OFF_HIGH)
1477+
// Will poll for 2.5 seconds for the VIN to go below 560mV. If not then will declare N-mode.
1478+
// 25ms * 100 = 2.5 Seconds
1479+
constexpr uint8_t POLL_2_5_SECS = 100;
1480+
constexpr uint8_t THRESHOLD_HIGH = CONSTS::R31_VIN_BULK_EFUSE_OFF_HIGH;
1481+
auto l_vin_below_efuse_off_high = false;
1482+
1483+
for (auto count = 0; count < POLL_2_5_SECS; count++)
1484+
{
1485+
if (l_reg_contents > THRESHOLD_HIGH)
1486+
{
1487+
// Delay 25ms and read R31 for VIN value again
1488+
fapi2::delay(25 * mss::common_timings::DELAY_1MS, mss::common_timings::DELAY_1MS);
1489+
fapi2::current_err = mss::pmic::i2c::reg_read(i_pmic_target, REGS::R31, l_reg_contents);
1490+
1491+
// Check the error on the reg_read
1492+
if (fapi2::current_err != fapi2::FAPI2_RC_SUCCESS)
1493+
{
1494+
return mss::pmic::declare_n_mode(
1495+
mss::find_target<fapi2::TARGET_TYPE_OCMB_CHIP>(i_pmic_target),
1496+
mss::index(i_pmic_target));
1497+
}
1498+
1499+
FAPI_DBG("%s EFUSE OFF VIN_BULK Reading: 0x%02X", mss::c_str(i_pmic_target), l_reg_contents);
1500+
}
1501+
else
1502+
{
1503+
l_vin_below_efuse_off_high = true;
1504+
break;
1505+
}
1506+
}
1507+
1508+
if (!l_vin_below_efuse_off_high)
12601509
{
1261-
constexpr uint8_t THRESHOLD_HIGH = CONSTS::R31_VIN_BULK_EFUSE_OFF_HIGH;
12621510
FAPI_ASSERT_NOEXIT(false,
12631511
fapi2::PMIC_EFUSE_BLOWN(fapi2::FAPI2_ERRL_SEV_RECOVERED)
12641512
.set_PMIC_TARGET(i_pmic_target)
@@ -1423,7 +1671,7 @@ fapi2::ReturnCode setup_pmic_pair_and_gpio(
14231671
if (!l_already_enabled)
14241672
{
14251673
// Now, sampling VIN_BULK, which is protected by a fuse, we check that VIN_BULK does not read
1426-
// more than 0.28V. If it does, then the fuse must be bad/blown, and we will declare N-mode.
1674+
// more than 0.56V. If it does, then the fuse must be bad/blown, and we will declare N-mode.
14271675

14281676
// Validate the EFUSE readings for both PMICs
14291677
FAPI_TRY(run_if_present(i_pmic_map, i_pmic_id_0, [&i_pmic_map, i_pmic_id_0]

0 commit comments

Comments
 (0)