/* IBM_PROLOG_BEGIN_TAG */ /* This is an automatically generated prolog. */ /* */ /* $Source: src/import/chips/p9/procedures/hwp/core/p9_hcd_core_stopclocks.C $ */ /* */ /* OpenPOWER HostBoot Project */ /* */ /* Contributors Listed Below - COPYRIGHT 2016,2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ /* Licensed under the Apache License, Version 2.0 (the "License"); */ /* you may not use this file except in compliance with the License. */ /* You may obtain a copy of the License at */ /* */ /* http://www.apache.org/licenses/LICENSE-2.0 */ /* */ /* Unless required by applicable law or agreed to in writing, software */ /* distributed under the License is distributed on an "AS IS" BASIS, */ /* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ /* implied. See the License for the specific language governing */ /* permissions and limitations under the License. */ /* */ /* IBM_PROLOG_END_TAG */ /// /// @file p9_hcd_core_stopclocks.C /// @brief Core Clock Stop /// /// 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 : HB:PERV // *HWP Level : 2 //------------------------------------------------------------------------------ // Includes //------------------------------------------------------------------------------ #include #include #include #include #include #include #include #include #ifdef __PPE__ #include #else #include #endif #include //------------------------------------------------------------------------------ // Constant Definitions //------------------------------------------------------------------------------ enum P9_HCD_CORE_STOPCLOCKS_CONSTANTS { CORE_PCB_MUX_POLLING_HW_NS_DELAY = 10000, CORE_PCB_MUX_POLLING_SIM_CYCLE_DELAY = 320000, CORE_CLK_SYNC_POLLING_HW_NS_DELAY = 10000, CORE_CLK_SYNC_POLLING_SIM_CYCLE_DELAY = 320000, CORE_CLK_STOP_POLLING_HW_NS_DELAY = 10000, CORE_CLK_STOP_POLLING_SIM_CYCLE_DELAY = 320000 }; //------------------------------------------------------------------------------ // Procedure: Core Clock Stop //------------------------------------------------------------------------------ fapi2::ReturnCode p9_hcd_core_stopclocks( const fapi2::Target& i_target, const bool i_sync_stop_quad_clk) { FAPI_INF(">>p9_hcd_core_stopclocks"); fapi2::ReturnCode l_rc; fapi2::buffer l_ccsr; fapi2::buffer l_data64; fapi2::buffer l_temp64; uint32_t l_loops1ms; uint8_t l_attr_chip_unit_pos; uint8_t l_attr_vdm_enabled; uint8_t l_attr_sdisn_setup; const fapi2::Target l_sys; auto l_quad = i_target.getParent(); auto l_perv = i_target.getParent(); auto l_chip = i_target.getParent(); auto l_ex_vector = l_quad.getChildren (fapi2::TARGET_STATE_FUNCTIONAL); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CHIP_EC_FEATURE_SDISN_SETUP, l_chip, l_attr_sdisn_setup)); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_VDM_ENABLED, l_chip, l_attr_vdm_enabled)); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CHIP_UNIT_POS, l_perv, l_attr_chip_unit_pos)); l_attr_chip_unit_pos = (l_attr_chip_unit_pos - p9hcd::PERV_TO_CORE_POS_OFFSET) % 4; //Check if EQ is powered off; if so, return FAPI_TRY(fapi2::getScom(l_quad, EQ_PPM_PFSNS, l_data64), "Error reading data from EQ_PPM_PFSNS"); if (l_data64.getBit()) { FAPI_DBG("Set core as stopped in STOP history register"); FAPI_TRY(putScom(i_target, C_PPM_SSHSRC, BIT64(0))); return fapi2::current_err; } //Check if core is powered off; if so, return FAPI_TRY(fapi2::getScom(i_target, C_PPM_PFSNS, l_data64), "Error reading data from C_PPM_PFSNS"); if (l_data64.getBit()) { FAPI_DBG("Set core as stopped in STOP history register"); FAPI_TRY(putScom(i_target, C_PPM_SSHSRC, BIT64(0))); return fapi2::current_err; } // ---------------------------- // Prepare to stop core clocks // ---------------------------- FAPI_DBG("Check PM_RESET_STATE_INDICATOR via GPMMR[15]"); FAPI_TRY(getScom(i_target, C_PPM_GPMMR_SCOM, l_data64)); if (!l_data64.getBit<15>()) { FAPI_DBG("Gracefully turn off power management, continue anyways if fail"); /// @todo RTC158181 suspend_pm() } FAPI_DBG("Check core clock controller status"); l_rc = p9_common_clk_ctrl_state(i_target); if (l_rc) { FAPI_INF("Clock controller of this core chiplet is inaccessible, return"); goto fapi_try_exit; } FAPI_DBG("Check cache clock controller status"); l_rc = p9_common_clk_ctrl_state(l_quad); if (l_rc) { FAPI_INF("WARNING: core is enabled while cache is not, continue anyways"); } else { FAPI_DBG("Check PERV clock status for access to CME via CLOCK_STAT[4]"); FAPI_TRY(getScom(l_quad, EQ_CLOCK_STAT_SL, l_data64)); FAPI_DBG("Check PERV fence status for access to CME via CPLT_CTRL1[4]"); FAPI_TRY(getScom(l_quad, EQ_CPLT_CTRL1, l_temp64)); if (l_data64.getBit<4>() == 0 && l_temp64.getBit<4>() == 0) { #ifdef DD2 FAPI_DBG("Halting the PGPE ..."); l_rc = ppe_halt(l_chip, PGPE_BASE_ADDRESS); FAPI_ASSERT_NOEXIT(!l_rc, fapi2::CORE_STOPCLKS_PGPE_HALT_TIMEOUT() .set_CHIP(l_chip), "PSTATE GPE Halt timeout"); FAPI_DBG("Halting the SGPE ..."); l_rc = ppe_halt(l_chip, SGPE_BASE_ADDRESS); FAPI_ASSERT_NOEXIT(!l_rc, fapi2::CORE_STOPCLKS_SGPE_HALT_TIMEOUT() .set_CHIP(l_chip), "STOP GPE Halt timeout"); FAPI_DBG("Clear the atomic lock on EQ %d", l_attr_chip_unit_pos); l_rc = p9_clear_atomic_lock(l_quad); FAPI_ASSERT_NOEXIT(!l_rc, fapi2::CORE_STOPCLKS_ATOMIC_LOCK_FAIL() .set_EQ(l_quad), "EQ Atomic Halt timeout"); for ( auto& ex : l_ex_vector ) { fapi2::ATTR_CHIP_UNIT_POS_Type l_cme_id = 0; FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CHIP_UNIT_POS, ex, l_cme_id)); FAPI_DBG("Halting CME %d", l_cme_id ); uint64_t l_cme_base_address = getCmeBaseAddress (l_cme_id); l_rc = ppe_halt(l_chip, l_cme_base_address); FAPI_ASSERT_NOEXIT(!l_rc, fapi2::CACHE_STOPCLKS_CME_HALT_TIMEOUT() .set_EX(ex), "CME Halt timeout"); } #endif //if a core is only in special wakeup and asserting pm_exit, //then setting 6,7 of SICR will cause pm_exit to drop and //the core will re-enter a power saving state FAPI_DBG("Prevent Core-L2 Quiesce from removing PM_EXIT CME_SCOM_LMCR[22]"); FAPI_TRY(putScom(l_quad, (l_attr_chip_unit_pos < 2) ? EX_0_CME_SCOM_LMCR_OR : EX_1_CME_SCOM_LMCR_OR, (BIT64(22)))); FAPI_DBG("Assert Core-L2/CC Quiesces via CME_SCOM_SICR[6,8]/[7,9]"); FAPI_TRY(putScom(l_quad, (l_attr_chip_unit_pos < 2) ? EX_0_CME_SCOM_SICR_OR : EX_1_CME_SCOM_SICR_OR, (BIT64(6 + (l_attr_chip_unit_pos % 2)) | BIT64(8 + (l_attr_chip_unit_pos % 2))))); } } FAPI_DBG("Assert pm_mux_disable to get PCB Mux from CME via SLAVE_CONFIG[7]"); FAPI_TRY(getScom(i_target, C_SLAVE_CONFIG_REG, l_data64)); FAPI_TRY(putScom(i_target, C_SLAVE_CONFIG_REG, DATA_SET(7))); FAPI_DBG("Override possible PPM write protection to CME via CPPM_CPMMR[1]"); FAPI_TRY(putScom(i_target, C_CPPM_CPMMR_OR, MASK_SET(1))); FAPI_DBG("Assert chiplet fence via NET_CTRL0[18]"); FAPI_TRY(putScom(i_target, C_NET_CTRL0_WOR, MASK_SET(18))); // ------------------------------- // Stop core clocks // ------------------------------- FAPI_DBG("Clear all SCAN_REGION_TYPE bits"); FAPI_TRY(putScom(i_target, C_SCAN_REGION_TYPE, MASK_ZERO)); if(i_sync_stop_quad_clk) { FAPI_DBG("Stop core clocks(all but pll) via CLK_REGION in SLAVE mode"); l_data64 = (p9hcd::CLK_STOP_CMD_SLAVE | p9hcd::CLK_REGION_ALL_BUT_PLL | p9hcd::CLK_THOLD_ALL); FAPI_TRY(putScom(i_target, C_CLK_REGION, l_data64)); } else { FAPI_DBG("Stop core clocks(all but pll) via CLK_REGION"); l_data64 = (p9hcd::CLK_STOP_CMD | p9hcd::CLK_REGION_ALL_BUT_PLL | p9hcd::CLK_THOLD_ALL); FAPI_TRY(putScom(i_target, C_CLK_REGION, l_data64)); FAPI_DBG("Poll for core clocks stopped via CPLT_STAT0[8]"); l_loops1ms = 1E6 / CORE_CLK_STOP_POLLING_HW_NS_DELAY; do { fapi2::delay(CORE_CLK_STOP_POLLING_HW_NS_DELAY, CORE_CLK_STOP_POLLING_SIM_CYCLE_DELAY); FAPI_TRY(getScom(i_target, C_CPLT_STAT0, l_data64)); } while((l_data64.getBit<8>() != 1) && ((--l_loops1ms) != 0)); FAPI_ASSERT((l_loops1ms != 0), fapi2::PMPROC_CORECLKSTOP_TIMEOUT().set_CORECPLTSTAT(l_data64), "Core Clock Stop Timeout"); FAPI_DBG("Check core clocks stopped via CLOCK_STAT_SL[4-13]"); FAPI_TRY(getScom(i_target, C_CLOCK_STAT_SL, l_data64)); FAPI_ASSERT((((~l_data64) & p9hcd::CLK_REGION_ALL_BUT_PLL) == 0), fapi2::PMPROC_CORECLKSTOP_FAILED().set_CORECLKSTAT(l_data64), "Core Clock Stop Failed"); FAPI_DBG("Core clocks stopped now"); } // ------------------------------- // Disable core clock sync // ------------------------------- FAPI_DBG("Drop core clock sync enable via CPPM_CACCR[15]"); FAPI_TRY(putScom(i_target, C_CPPM_CACCR_CLEAR, MASK_SET(15))); FAPI_DBG("Poll for core clock sync done to drop via CPPM_CACSR[13]"); l_loops1ms = 1E6 / CORE_CLK_SYNC_POLLING_HW_NS_DELAY; do { fapi2::delay(CORE_CLK_SYNC_POLLING_HW_NS_DELAY, CORE_CLK_SYNC_POLLING_SIM_CYCLE_DELAY); FAPI_TRY(getScom(i_target, C_CPPM_CACSR, l_data64)); } while((l_data64.getBit<13>() == 1) && ((--l_loops1ms) != 0)); FAPI_ASSERT((l_loops1ms != 0), fapi2::PMPROC_CORECLKSYNCDROP_TIMEOUT().set_COREPPMCACSR(l_data64), "Core Clock Sync Drop Timeout"); FAPI_DBG("Core clock sync done dropped"); // ------------------------------- // Fence up // ------------------------------- FAPI_DBG("Assert skew sense to skew adjust fence via NET_CTRL0[22]"); FAPI_TRY(putScom(i_target, C_NET_CTRL0_WOR, MASK_SET(22))); FAPI_DBG("Drop ABIST_SRAM_MODE_DC to support ABIST Recovery via BIST[1]"); FAPI_TRY(getScom(i_target, C_BIST, l_data64)); FAPI_TRY(putScom(i_target, C_BIST, DATA_UNSET(1))); FAPI_DBG("Assert vital fence via CPLT_CTRL1[3]"); FAPI_TRY(putScom(i_target, C_CPLT_CTRL1_OR, MASK_SET(3))); FAPI_DBG("Assert regional fences via CPLT_CTRL1[4-14]"); FAPI_TRY(putScom(i_target, C_CPLT_CTRL1_OR, p9hcd::CLK_REGION_ALL)); if (l_attr_sdisn_setup) { FAPI_DBG("DD1 Only: Drop sdis_n(flushing LCBES condition) vai CPLT_CONF0[34]"); FAPI_TRY(putScom(i_target, C_CPLT_CONF0_CLEAR, MASK_SET(34))); } // ------------------------------- // Disable VDM // ------------------------------- if (l_attr_vdm_enabled == fapi2::ENUM_ATTR_VDM_ENABLED_TRUE) { FAPI_DBG("Set VDM Disable via CPPM_VDMCR[1]"); FAPI_TRY(putScom(i_target, C_PPM_VDMCR_OR, MASK_SET(1))); FAPI_DBG("Drop VDM Poweron via CPPM_VDMCR[0]"); FAPI_TRY(putScom(i_target, C_PPM_VDMCR_CLEAR, MASK_SET(0))); } // ------------------------------- // Update stop history // ------------------------------- FAPI_DBG("Set core as stopped in STOP history register"); FAPI_TRY(putScom(i_target, C_PPM_SSHSRC, BIT64(0))); // ------------------------------- // Clean up // ------------------------------- FAPI_DBG("Return possible PPM write protection to CME via CPPM_CPMMR[1]"); FAPI_TRY(putScom(i_target, C_CPPM_CPMMR_CLEAR, MASK_SET(1))); FAPI_DBG("Drop pm_mux_disable to release PCB Mux via SLAVE_CONFIG[7]"); FAPI_TRY(getScom(i_target, C_SLAVE_CONFIG_REG, l_data64)); FAPI_TRY(putScom(i_target, C_SLAVE_CONFIG_REG, DATA_UNSET(7))); fapi_try_exit: FAPI_INF("<