/* IBM_PROLOG_BEGIN_TAG */ /* This is an automatically generated prolog. */ /* */ /* $Source: chips/p9/procedures/hwp/lib/p9_common_poweronoff.C $ */ /* */ /* IBM CONFIDENTIAL */ /* */ /* EKB Project */ /* */ /* COPYRIGHT 2015,2016 */ /* [+] International Business Machines Corp. */ /* */ /* */ /* The source code for this program is not published or otherwise */ /* divested of its trade secrets, irrespective of what has been */ /* deposited with the U.S. Copyright Office. */ /* */ /* IBM_PROLOG_END_TAG */ /// /// @file p9_common_poweronoff.C /// @brief common procedure for power on/off /// /// Procedure Summary: /// // *HWP HWP Owner : David Du // *HWP Backup HWP Owner : Greg Still // *HWP FW Owner : Sangeetha T S // *HWP Team : PM // *HWP Consumed by : SBE:SGPE:CME // *HWP Level : 2 //------------------------------------------------------------------------------ // Includes //------------------------------------------------------------------------------ #include "p9_common_poweronoff.H" #include "p9_quad_scom_addresses.H" //------------------------------------------------------------------------------ // Constant Definitions: //------------------------------------------------------------------------------ // Define only address offset to be compatible with both core and cache domain const uint64_t PPM_PFCS[2] = { C_PPM_PFCS_SCOM, EQ_PPM_PFCS_SCOM }; const uint64_t PPM_PFCS_CLR[2] = { C_PPM_PFCS_SCOM1, EQ_PPM_PFCS_SCOM1 }; const uint64_t PPM_PFCS_OR[2] = { C_PPM_PFCS_SCOM2, EQ_PPM_PFCS_SCOM2 }; const uint64_t PPM_PFDLY[2] = { C_PPM_PFDLY, EQ_PPM_PFDLY }; const uint64_t PPM_PFSNS[2] = { C_PPM_PFSNS, EQ_PPM_PFSNS }; enum { CYCLES_PER_MS = 500000, INST_PER_LOOP = 8, PFET_STATE_LENGTH = 2, VXX_PG_SEL_LEN = 4 }; enum pfetRegField { PFET_NOP = 0, PFET_FORCE_VOFF = 1, PFET_NOP_RESERVERD = 2, PFET_FORCE_VON = 3 }; enum pgStateOffset { PG_STATE_IDLE_OFFSET = 0, PG_STATE_INC_OFFSET = 1, PG_STATE_DEC_OFFSET = 2, PG_STATE_WAIT_OFFSET = 3 }; enum PFCS_Bits { VDD_PFET_FORCE_STATE_BIT = 0, VCS_PFET_FORCE_STATE_BIT = 2, VDD_PFET_VAL_OVERRIDE_BIT = 4, VDD_PFET_SEL_OVERRIDE_BIT = 5, VCS_PFET_VAL_OVERRIDE_BIT = 6, VCS_PFET_SEL_OVERRIDE_BIT = 7, VDD_PFET_REGULATION_FINGER_EN_BIT = 8, VDD_PFET_REGULATION_FINGER_VALUE_BIT = 9, RESERVED1_BIT = 10, VDD_PFET_ENABLE_VALUE_BIT = 12, VDD_PFET_SEL_VALUE_BIT = 20, VCS_PFET_ENABLE_VALUE_BIT = 24, VCS_PFET_SEL_VALUE_BIT = 32, RESERVED2_BIT = 36, VDD_PG_STATE_BIT = 42, VDD_PG_SEL_BIT = 46, VCS_PG_STATE_BIT = 50, VCS_PG_SEL_BIT = 54, RESERVED3_BIT = 58 }; enum { VDD_PFETS_ENABLED_SENSE_BIT = 0, VDD_PFETS_DISABLED_SENSE_BIT = 1, VCS_PFETS_ENABLED_SENSE_BIT = 2, VCS_PFETS_DISABLED_SENSE_BIT = 3 }; enum { POWDN_DLY_BIT = 0, POWUP_DLY_BIT = 4, TP_VDD_PFET_ENABLE_ACTUAL_BIT = 16, TP_VCS_PFET_ENABLE_ACTUAL_BIT = 24 }; enum { POWDN_DLY_LENGTH = 4, POWUP_DLY_LENGTH = 4, TP_VDD_PFET_ENABLE_ACTUAL_LENGTH = 8, TP_VCS_PFET_ENABLE_ACTUAL_LENGTH = 8 }; // i_operation defines //------------------------------------------------------------------------------ // Procedure: //------------------------------------------------------------------------------ template fapi2::ReturnCode p9_common_poweronoff( const fapi2::Target& i_target, const p9power::powerOperation_t i_operation) { uint32_t l_loopsPerMs; FAPI_INF(">>p9_common_poweronoff: %d", i_operation); uint32_t l_type = 0; // Assumes core if((i_target.getType() & fapi2::TARGET_TYPE_EQ)) { l_type = 1; } fapi2::buffer l_data; fapi2::buffer l_temp; // extractToRight seems the require space to write into. /////////////////////////////////////////////////////////////////////////// // lambda functions for poweronoff procedure /////////////////////////////////////////////////////////////////////////// auto pollVddFSMIdle = [&] () { // Poll for PFETCNTLSTAT_REG[VDD_PG_STATE] for 0b1000 (FSM idle) // – Timeout value = 1ms FAPI_DBG("Polling for power gate sequencer state: FSM idle"); l_loopsPerMs = CYCLES_PER_MS / INST_PER_LOOP; // Note that the Lamda assumes that l_data already contains the do { FAPI_TRY(fapi2::getScom(i_target, PPM_PFCS[l_type], l_data), "getScom failed for address PPM_PFCS"); // poll } while ((l_data.getBit < VDD_PG_STATE_BIT + PG_STATE_IDLE_OFFSET > () == 0 ) && (--l_loopsPerMs != 0)); /* do { FAPI_TRY(fapi2::getScom(i_target, PPM_PFSNS[l_type], l_data), "getScom failed for address PPM_PFSNS"); // poll } while ((l_data.getBit<0>() == 0 ) && (--l_loopsPerMs != 0)); */ FAPI_ASSERT((l_loopsPerMs != 0), fapi2::PMPROC_PFETLIB_TIMEOUT() .set_ADDRESS(PPM_PFCS[l_type]), "VDD FSM idle timeout"); /// (Optional) Check PFETCNTLSTAT_REG[VDD_PG_SEL]being 0x8 // (Off encode point) #if 0 // this field does not get set yet l_data.extractToRight(l_temp); FAPI_ASSERT((l_temp == 8), fapi2::PROCPM_PFET_CODE_BAD_MODE(), "VDD_PG_SEL != 8: l_temp %0x", l_temp); #endif fapi_try_exit: return fapi2::current_err; }; auto pollVcsFSMIdle = [&] () { // Poll for PFETCNTLSTAT_REG[VDD_PG_STATE] for 0b1000 (FSM idle) // – Timeout value = 1ms FAPI_DBG("Polling for power gate sequencer state: FSM idle"); l_loopsPerMs = CYCLES_PER_MS / INST_PER_LOOP; do { FAPI_TRY(fapi2::getScom(i_target, PPM_PFCS[l_type], l_data), "getScom failed for address PPM_PFCS"); // poll FAPI_DBG("timeout l_loopsPerMs. %x", l_loopsPerMs); } while ((l_data.getBit < VCS_PG_STATE_BIT + PG_STATE_IDLE_OFFSET > () == 0 ) && (--l_loopsPerMs != 0)); /* do { FAPI_TRY(fapi2::getScom(i_target, PPM_PFSNS[l_type], l_data), "getScom failed for address PPM_PFSNS"); // poll } while ((l_data.getBit<2>() == 0 ) && (--l_loopsPerMs != 0)); */ FAPI_ASSERT((l_loopsPerMs != 0), fapi2::PMPROC_PFETLIB_TIMEOUT() .set_ADDRESS(PPM_PFCS[l_type]), "VCS FSM idle timeout"); // (Optional) Check PFETCNTLSTAT_REG[VDD_PG_SEL] // being 0x8 (Off encode point) #if 0 // this field does not get set yet l_data.extractToRight(l_temp); FAPI_ASSERT((l_temp == 8), fapi2::PROCPM_PFET_CODE_BAD_MODE(), "VCS_PG_SEL != 8: l_temp %0x", l_temp); #endif fapi_try_exit: return fapi2::current_err; }; auto powerOnVdd = [&] () { // Command the cache PFET controller to power-on // Write PFETCNTLSTAT_REG: // vdd_pfet_force_state = 11 (Force Von) // vdd_pfet_val_override = 0 (Override disabled) // vdd_pfet_sel_override = 0 (Override disabled) // vdd_pfet_enable_regulation_finger = 0 // (Regulation finger controlled by FSM) FAPI_DBG("Clear VDD PFET stage select and value override bits"); l_data.flush<0>(). setBit(). setBit(). setBit(); FAPI_TRY(fapi2::putScom(i_target, PPM_PFCS_CLR[l_type], l_data), "putScom failed for address PPM_PFCS"); FAPI_DBG("Force VDD on"); l_data.flush<0>().insertFromRight (PFET_FORCE_VON); FAPI_TRY(fapi2::putScom(i_target, PPM_PFCS_OR[l_type], l_data), "putScom failed for address PPM_PFCS_OR"); // Check for valid power on completion // Polled Timeout: 100us FAPI_TRY(pollVddFSMIdle()); // Write PFETCNTLSTAT_REG_WCLEAR // vdd_pfet_force_state = 00 (No Operation); // all fields set to 1 for WAND // Use PPM_PFCS_CLR, // vdd_pfet_force_state = 0b11 FAPI_DBG("vdd_pfet_force_state = 00, or Idle"); l_data.flush<0>().insertFromRight (~PFET_NOP); FAPI_TRY(fapi2::putScom(i_target, PPM_PFCS_CLR[l_type], l_data), "putScom failed for address PPM_PFCS_CLR"); fapi_try_exit: return fapi2::current_err; }; auto powerOnVcs = [&] () { // Command the PFET controller to power-on // Write PFETCNTLSTAT_REG_OR with values defined below // vcs_pfet_force_state = 11 (Force Von) // Write to PFETCNTLSTAT_REG_CLR // vcs_pfet_val_override = 0 (Override disabled) // vcs_pfet_sel_override = 0 (Override disabled) // Note there is no vcs_pfet_enable_regulation_finger FAPI_DBG("Clear VSS PFET stage select and value override bits"); l_data.flush<0>(). setBit(). setBit(); FAPI_TRY(fapi2::putScom(i_target, PPM_PFCS_CLR[l_type], l_data), "putScom failed for address PPM_PFCS_CLR"); FAPI_DBG("Force VSS on"); l_data.flush<0>().insertFromRight (PFET_FORCE_VON); FAPI_TRY(fapi2::putScom(i_target, PPM_PFCS_OR[l_type], l_data), "putScom failed for address PPM_PFCS_OR"); // Check for valid power on completion // Polled Timeout: 100us FAPI_TRY(pollVcsFSMIdle()); // Write PFETCNTLSTAT_REG_WCLEAR // vcs_pfet_force_state = 00 (No Operation); // all fields set to 1 for WAND // Use PPM_PFCS_CLR, vdd_pfet_force_state = ~(0b00) FAPI_DBG("vss_pfet_force_state = 00, or Idle"); l_data.flush<0>().insertFromRight (~PFET_NOP); FAPI_TRY(fapi2::putScom(i_target, PPM_PFCS_CLR[l_type], l_data), "putScom failed for address PPM_PFCS_CLR"); fapi_try_exit: return fapi2::current_err; }; auto powerOffVdd = [&] () { // Command the PFET controller to power-off // Write PFETCNTLSTAT_REG: // vdd_pfet_force_state = 01 (Force Voff) // vdd_pfet_val_override = 0 (Override disabled) // vdd_pfet_sel_override = 0 (Override disabled) // vdd_pfet_enable_regulation_finger = 0 // (Regulation finger controlled by FSM) FAPI_DBG("Clear VDD PFET stage select and value override bits"); l_data.flush<0>(). setBit(). setBit(). setBit(); FAPI_TRY(fapi2::putScom(i_target, PPM_PFCS_CLR[l_type], l_data), "putScom failed for address PPM_PFCS"); FAPI_DBG("Force VDD off"); l_data.flush<0>().insertFromRight (PFET_FORCE_VOFF); FAPI_TRY(fapi2::putScom(i_target, PPM_PFCS_OR[l_type], l_data), "putScom failed for address PPM_PFCS"); // Check for valid power off completion // Polled Timeout: 100us FAPI_TRY(pollVddFSMIdle()); // Write PFETCNTLSTAT_REG_WCLEAR // vdd_pfet_force_state = 00 (No Operation); // all fields set to 1 for WAND // Use PPM_PFCS_CLR, vdd_pfet_force_state = 0b11 FAPI_DBG("vdd_pfet_force_state = 00, or Idle"); l_data.flush<0>().insertFromRight (~PFET_NOP); FAPI_TRY(fapi2::putScom(i_target, PPM_PFCS_CLR[l_type], l_data), "putScom failed for address PPM_PFCS_CLR"); fapi_try_exit: return fapi2::current_err; }; auto powerOffVcs = [&] () { // Command the PFET controller to power-off // Write PFETCNTLSTAT_REG_OR with values defined below // vcs_pfet_force_state = 11 (Force Voff) // DOC BUG: ?? Write to PFETCNTLSTAT_REG_CLR // vcs_pfet_val_override = 0 (Override disabled) // vcs_pfet_sel_override = 0 (Override disabled) // Note there is no vcs_pfet_enable_regulation_finger FAPI_DBG("Clear VSS PFET stage select and value override bits"); l_data.flush<0>(). setBit(). setBit(); FAPI_TRY(fapi2::putScom(i_target, PPM_PFCS_CLR[l_type], l_data), "putScom failed for address PPM_PFCS_CLR"); FAPI_DBG("Force VSS off"); l_data.flush<0>(). insertFromRight (PFET_FORCE_VOFF); FAPI_TRY(fapi2::putScom(i_target, PPM_PFCS_OR[l_type], l_data), "putScom failed for address PPM_PFCS_OR"); // Check for valid power off completion // Polled Timeout: 100us FAPI_TRY(pollVcsFSMIdle()); // Write PFETCNTLSTAT_REG_WCLEAR // vcs_pfet_force_state = 00 (No Operation); // all fields set to 1 for WAND // Use PPM_PFCS_CLR, vcs_pfet_force_state = ~(0b00) FAPI_DBG("vcs_pfet_force_state = 00, or Idle"); l_data.flush<0>().insertFromRight (~PFET_NOP); FAPI_TRY(fapi2::putScom(i_target, PPM_PFCS_CLR[l_type], l_data), "putScom failed for address PPM_PFCS_CLR"); fapi_try_exit: return fapi2::current_err; }; /////////////////////////////////////////////////////////////////////////// // Initialization code /////////////////////////////////////////////////////////////////////////// #if 0 // unneeded for AWAN operation. Also, fails if delay field is > 8 l_data.flush<0>().insertFromRight(0x8). insertFromRight(0x8); FAPI_TRY(fapi2::putScom(i_target, PPM_PFDLY, l_data), "putScom failed for address PPM_PFDLY"); #endif /////////////////////////////////////////////////////////////////////////// // Procedure code /////////////////////////////////////////////////////////////////////////// switch(i_operation) { case p9power::POWER_ON: case p9power::POWER_ON_VDD: { // 4.3.8.1 Power-on via Hardware FSM // VDD first, VCS second // 1) Read PFETCNTLSTAT_REG: check for bits 0:3 being 0b0000 l_data.flush<0>(). setBit(). setBit(); FAPI_TRY(fapi2::putScom(i_target, PPM_PFCS_CLR[l_type], l_data), "putScom failed for address PPM_PFCS_CLR"); FAPI_DBG("Make sure that we are not forcing PFET for VCS or VDD off"); FAPI_TRY(fapi2::getScom(i_target, PPM_PFCS[l_type], l_data), "getScom failed for address PPM_PFCS"); l_data.extractToRight (l_temp); FAPI_ASSERT((l_temp == 0), fapi2::PMPROC_PFETLIB_BAD_SCOM() .set_ADDRESS(PPM_PFCS[l_type]), "PFET_FORCE_STATE not 0"); // 2) Set bits to program HW to enable VDD PFET, and // 3) Poll state bit until Pfet sequence is complete FAPI_TRY(powerOnVdd()); // 4) Set bits to program HW to enable VCS PFET, and // 5) Poll state bit until Pfet sequence is complete // Note: if (i_target.getType() & fapi2::TARGET_TYPE_EQ) doesn't work. // Created a POWER_*_VDD label to delineate Vcs and Vdd if (i_operation == p9power::POWER_ON) { FAPI_TRY(powerOnVcs()); } } break; case p9power::POWER_OFF: case p9power::POWER_OFF_VDD: { // 4.3.8.2 Power-off via Hardware FSM // 1) Read PFETCNTLSTAT_REG: check for bits 0:3 being 0b0000 FAPI_DBG("Make sure that we are not forcing PFET for VCS or VDD off"); FAPI_TRY(fapi2::getScom(i_target, PPM_PFCS[l_type], l_data), "getScom failed for address PPM_PFCS"); l_data.extractToRight (l_temp); FAPI_ASSERT((l_temp == 0), fapi2::PMPROC_PFETLIB_BAD_SCOM() .set_ADDRESS(PPM_PFCS[l_type]), "PFET_FORCE_STATE not 0"); // 2) Set bits to program HW to turn off VDD PFET, and // 3) Poll state bit until Pfet sequence is complete FAPI_TRY(powerOffVdd()); // 4) Set bits to program HW to turn off VCS PFET, and // 5) Poll state bit until Pfet sequence is complete // Note: if (i_target.getType() & fapi2::TARGET_TYPE_EQ) doesn't work. // Created a POWER_*_VDD label to delineate Vcs and Vdd if (i_operation == p9power::POWER_OFF) { FAPI_TRY(powerOffVcs()); } } break; } FAPI_INF("<