/* IBM_PROLOG_BEGIN_TAG */ /* This is an automatically generated prolog. */ /* */ /* $Source: import/chips/p9/procedures/ppe_closed/sgpe/stop_gpe/p9_hcd_cache_l2_startclocks.c $ */ /* */ /* OpenPOWER HCODE Project */ /* */ /* COPYRIGHT 2015,2017 */ /* [+] 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 */ #include "p9_sgpe_stop_exit_marks.h" extern SgpeStopRecord G_sgpe_stop_record; inline __attribute__((always_inline)) void p9_hcd_cache_l2_startclocks(uint32_t quad, uint32_t ex) { uint64_t scom_data = 0; PK_TRACE("Drop L2 Regional Fences via CPLT_CTRL1[8/9]"); GPE_PUTSCOM(GPE_SCOM_ADDR_QUAD(EQ_CPLT_CTRL1_CLEAR, quad), ((uint64_t)ex << SHIFT64(9))); PK_TRACE("Raise clock sync enable before switch to dpll"); GPE_PUTSCOM(GPE_SCOM_ADDR_QUAD(EQ_QPPM_EXCGCR_OR, quad), ((uint64_t)ex << SHIFT64(37))); PK_TRACE("Poll for clock sync done to raise"); do { GPE_GETSCOM(GPE_SCOM_ADDR_QUAD(QPPM_QACSR, quad), scom_data); } while((~scom_data) & ((uint64_t)ex << SHIFT64(37))); MARK_TRAP(SX_L2_STARTCLOCKS_ALIGN) // align_chiplets() PK_TRACE("Assert flushmode_inhibit via CPLT_CTRL0[2]"); GPE_PUTSCOM(GPE_SCOM_ADDR_QUAD(EQ_CPLT_CTRL0_OR, quad), BIT64(2)); PK_TRACE("Assert force_align via CPLT_CTRL0[3]"); GPE_PUTSCOM(GPE_SCOM_ADDR_QUAD(EQ_CPLT_CTRL0_OR, quad), BIT64(3)); PK_TRACE("Set then unset clear_chiplet_is_aligned via SYNC_CONFIG[7]"); GPE_GETSCOM(GPE_SCOM_ADDR_QUAD(EQ_SYNC_CONFIG, quad), scom_data); scom_data = scom_data | BIT64(7); GPE_PUTSCOM(GPE_SCOM_ADDR_QUAD(EQ_SYNC_CONFIG, quad), scom_data); scom_data = scom_data & ~BIT64(7); GPE_PUTSCOM(GPE_SCOM_ADDR_QUAD(EQ_SYNC_CONFIG, quad), scom_data); // 255 cache cycles PPE_WAIT_CORE_CYCLES(510); PK_TRACE("Check chiplet_is_aligned"); do { GPE_GETSCOM(GPE_SCOM_ADDR_QUAD(EQ_CPLT_STAT0, quad), scom_data); } while((~scom_data) & BIT64(9)); MARK_TRAP(SX_L2_STARTCLOCKS_REGION) PK_TRACE("Drop force_align via CPLT_CTRL0[3]"); GPE_PUTSCOM(GPE_SCOM_ADDR_QUAD(EQ_CPLT_CTRL0_CLEAR, quad), BIT64(3)); // ------------------------------- // Start L2 Clock // ------------------------------- PK_TRACE("Clear all bits prior clock start via SCAN_REGION_TYPE"); GPE_PUTSCOM(GPE_SCOM_ADDR_QUAD(EQ_SCAN_REGION_TYPE, quad), 0); PK_TRACE("Start clock via CLK_REGION"); scom_data = (CLK_START_CMD | CLK_THOLD_ALL | ((uint64_t)ex << SHIFT64(9))); GPE_PUTSCOM(GPE_SCOM_ADDR_QUAD(EQ_CLK_REGION, quad), scom_data); PK_TRACE("Polling for clocks starting via CPLT_STAT0[8]"); do { GPE_GETSCOM(GPE_SCOM_ADDR_QUAD(EQ_CPLT_STAT0, quad), scom_data); } while((~scom_data) & BIT64(8)); PK_TRACE("Check L2 clock running via CLOCK_STAT_SL[8:9]"); GPE_GETSCOM(GPE_SCOM_ADDR_QUAD(EQ_CLOCK_STAT_SL, quad), scom_data); if (scom_data & ((uint64_t)ex << SHIFT64(9))) { PK_TRACE_ERR("ERROR: L2 Clock Start Failed. HALT SGPE!"); SGPE_STOP_QUAD_ERROR_HANDLER(quad, SGPE_STOP_EXIT_L2_STARTCLK_FAILED); return; } PK_TRACE("L2 clock is now running"); // ------------------------------- // Cleaning up // ------------------------------- /// @todo RTC166917 Check the Global Checkstop FIR #if NIMBUS_DD_LEVEL != 10 PK_TRACE("Drop flushmode_inhibit via CPLT_CTRL0[2]"); GPE_PUTSCOM(GPE_SCOM_ADDR_QUAD(EQ_CPLT_CTRL0_CLEAR, quad), BIT64(2)); #endif PK_TRACE("Set parital bad l2/l3 and stopped l2 pscom mask"); scom_data = 0; if ((~G_sgpe_stop_record.group.expg[quad]) & FST_EX_IN_QUAD) { scom_data |= (PSCOM_MASK_EX0_L2 | PSCOM_MASK_EX0_L3); } else if (((~ex) & FST_EX_IN_QUAD) && (G_sgpe_stop_record.state[quad].act_state_x0 >= LEVEL_EX_BASE)) { scom_data |= PSCOM_MASK_EX0_L2; } if ((~G_sgpe_stop_record.group.expg[quad]) & SND_EX_IN_QUAD) { scom_data |= (PSCOM_MASK_EX1_L2 | PSCOM_MASK_EX1_L3); } else if (((~ex) & SND_EX_IN_QUAD) && (G_sgpe_stop_record.state[quad].act_state_x1 >= LEVEL_EX_BASE)) { scom_data |= PSCOM_MASK_EX1_L2; } GPE_PUTSCOM(GPE_SCOM_ADDR_QUAD(EQ_RING_FENCE_MASK_LATCH, quad), scom_data); }