fapi::ReturnCode mss_volt(std::vector<fapi::Target> & i_targets_memb) { fapi::ReturnCode l_rc; uint8_t l_dimm_functionality=0; uint8_t l_spd_dramtype=0; uint8_t l_spd_volts=0; uint8_t l_spd_volts_all_dimms=0x06; //start assuming all voltages supported uint8_t l_dram_ddr3_found_flag=0; uint8_t l_dram_ddr4_found_flag=0; uint8_t l_volt_override = 0x00; uint8_t l_volt_override_domain = 0x00; uint32_t l_selected_dram_voltage=0; //this gets written into all centaurs when done. uint32_t l_selected_dram_voltage_vpp=0; uint32_t l_tolerated_dram_voltage = MAX_TOLERATED_VOLT; //initially set to the max tolerated voltage do { // Iterate through the list of centaurs for (uint32_t i=0; i < i_targets_memb.size(); i++) { std::vector<fapi::Target> l_mbaChiplets; // Get associated MBA's on this centaur l_rc=fapiGetChildChiplets(i_targets_memb[i], fapi::TARGET_TYPE_MBA_CHIPLET, l_mbaChiplets); if (l_rc) break; l_rc = FAPI_ATTR_GET(ATTR_MSS_VOLT_OVERRIDE, &i_targets_memb[i], l_volt_override); if (l_rc) break; // Note if there is an overrride being applied on the domain if ( (l_volt_override != fapi::ENUM_ATTR_MSS_VOLT_OVERRIDE_NONE) && (l_volt_override_domain == fapi::ENUM_ATTR_MSS_VOLT_OVERRIDE_NONE) ) { l_volt_override_domain = l_volt_override; } // Error if our overides are not the same across the domain if (l_volt_override_domain != l_volt_override) { // this just needs to callout the mismatching memb. const uint8_t &OVERRIDE_TYPE = l_volt_override; const uint8_t &OVERRIDE_DOMAIN_TYPE = l_volt_override_domain; const fapi::Target &MEMB_TARGET = i_targets_memb[i]; FAPI_ERR("Mismatch volt override request. Domain: 0x%x Current Target Requests: 0x%x", l_volt_override_domain, l_volt_override); FAPI_SET_HWP_ERROR(l_rc, RC_MSS_VOLT_OVERIDE_MIXING); fapiLogError(l_rc); } // Loop through the 2 MBA's for (uint32_t j=0; j < l_mbaChiplets.size(); j++) { std::vector<fapi::Target> l_dimm_targets; // Get a vector of DIMM targets l_rc = fapiGetAssociatedDimms(l_mbaChiplets[j], l_dimm_targets, fapi::TARGET_STATE_PRESENT); if (l_rc) break; for (uint32_t k=0; k < l_dimm_targets.size(); k++) { l_rc = FAPI_ATTR_GET(ATTR_SPD_DRAM_DEVICE_TYPE, &l_dimm_targets[k], l_spd_dramtype); if (l_rc) break; l_rc = FAPI_ATTR_GET(ATTR_SPD_MODULE_NOMINAL_VOLTAGE, &l_dimm_targets[k], l_spd_volts); if (l_rc) break; l_rc = FAPI_ATTR_GET(ATTR_FUNCTIONAL, &l_dimm_targets[k], l_dimm_functionality); if (l_rc) break; // spd_volts: bit0= NOT 1.5V bit1=1.35V bit2=1.25V, assume a 1.20V in future for DDR4 // check for supported voltage/dram type combo DDR3=12, DDR4=13 if (l_spd_dramtype == fapi::ENUM_ATTR_SPD_DRAM_DEVICE_TYPE_DDR3) { l_dram_ddr3_found_flag=1; } else if (l_spd_dramtype == fapi::ENUM_ATTR_SPD_DRAM_DEVICE_TYPE_DDR4) { l_dram_ddr4_found_flag=1; } else { // this just needs to be deconfiged at the dimm level const uint8_t &DEVICE_TYPE = l_spd_dramtype; const fapi::Target &DIMM_TARGET = l_dimm_targets[k]; FAPI_ERR("Unknown DRAM Device Type 0x%x", l_spd_dramtype); FAPI_SET_HWP_ERROR(l_rc, RC_MSS_VOLT_UNRECOGNIZED_DRAM_DEVICE_TYPE); fapiLogError(l_rc); } if(l_dimm_functionality == fapi::ENUM_ATTR_FUNCTIONAL_FUNCTIONAL) { //AND dimm voltage capabilities together to find aggregate voltage support on all dimms l_spd_volts_all_dimms = l_spd_volts_all_dimms & l_spd_volts; } }//end of dimms loop if (l_rc) { break; } }//end of mba loop if (l_rc) { break; } }//end of centaur (memb) loop if (l_rc) { // Break out of do...while(0) break; } // now we figure out if we have a supported ddr type and voltage // note: only support DDR3=1.35V and DDR4=1.2xV // Mixed Dimms, Deconfig the DDR4. if (l_dram_ddr3_found_flag && l_dram_ddr4_found_flag) { std::vector<fapi::Target> l_dimm_targets_deconfig; // Iterate through the list of centaurs for (uint32_t i=0; i < i_targets_memb.size(); i++) { std::vector<fapi::Target> l_mbaChiplets; // Get associated MBA's on this centaur l_rc=fapiGetChildChiplets(i_targets_memb[i], fapi::TARGET_TYPE_MBA_CHIPLET, l_mbaChiplets); if (l_rc) break; // Loop through the 2 MBA's for (uint32_t j=0; j < l_mbaChiplets.size(); j++) { std::vector<fapi::Target> l_dimm_targets; // Get a vector of DIMM targets l_rc = fapiGetAssociatedDimms(l_mbaChiplets[j], l_dimm_targets, fapi::TARGET_STATE_PRESENT); if (l_rc) break; for (uint32_t k=0; k < l_dimm_targets.size(); k++) { l_rc = FAPI_ATTR_GET(ATTR_SPD_DRAM_DEVICE_TYPE, &l_dimm_targets[k], l_spd_dramtype); if (l_rc) break; if (l_spd_dramtype == fapi::ENUM_ATTR_SPD_DRAM_DEVICE_TYPE_DDR4) { const fapi::Target &DIMM_DDR4_TARGET = l_dimm_targets[k]; const uint8_t &DEVICE_TYPE = l_spd_dramtype; FAPI_ERR("mss_volt: DDR3 and DDR4 mixing not allowed"); FAPI_SET_HWP_ERROR(l_rc, RC_MSS_VOLT_DDR_TYPE_MIXING_UNSUPPORTED); fapiLogError(l_rc); } }//end of dimms loop if (l_rc) { break; } }//end of mba loop if (l_rc) { break; } }//end of centaur (memb) loop } if (l_rc) { // Break out of do...while(0) break; } if (l_volt_override != fapi::ENUM_ATTR_MSS_VOLT_OVERRIDE_NONE) { if (l_volt_override == fapi::ENUM_ATTR_MSS_VOLT_OVERRIDE_VOLT_135) { l_tolerated_dram_voltage = 1350; FAPI_INF( "mss_volt_overide being applied. MSS_VOLT_OVERRIDE: 1.35V"); FAPI_INF( "NOTE: Still checking for violations of tolerated voltage. If DIMMs cannot tolerate, the override will not be applied."); } if (l_volt_override == fapi::ENUM_ATTR_MSS_VOLT_OVERRIDE_VOLT_120) { l_tolerated_dram_voltage = 1200; FAPI_INF( "mss_volt_overide being applied. MSS_VOLT_OVERRIDE: 1.20V"); FAPI_INF( "NOTE: Still checking for violations of tolerated voltage. If DIMMs cannot tolerate, the override will not be applied."); } else { const uint8_t &OVERRIDE_TYPE = l_volt_override; FAPI_ERR("Unknown volt override request. Override Request: 0x%x", l_volt_override); FAPI_SET_HWP_ERROR(l_rc, RC_MSS_VOLT_OVERIDE_UKNOWN); fapiLogError(l_rc); } } else if (l_dram_ddr3_found_flag && ((l_spd_volts_all_dimms & fapi::ENUM_ATTR_SPD_MODULE_NOMINAL_VOLTAGE_OP1_35) == fapi::ENUM_ATTR_SPD_MODULE_NOMINAL_VOLTAGE_OP1_35)) { l_selected_dram_voltage=1350; l_selected_dram_voltage_vpp = DDR3_VPP_VOLT; } else if (l_dram_ddr4_found_flag && ((l_spd_volts_all_dimms & fapi::ENUM_ATTR_SPD_MODULE_NOMINAL_VOLTAGE_OP1_2X) == fapi::ENUM_ATTR_SPD_MODULE_NOMINAL_VOLTAGE_OP1_2X)) { l_selected_dram_voltage=1200; l_selected_dram_voltage_vpp = DDR4_VPP_VOLT; } else if ((l_spd_volts_all_dimms & fapi::ENUM_ATTR_SPD_MODULE_NOMINAL_VOLTAGE_NOTOP1_5) != fapi::ENUM_ATTR_SPD_MODULE_NOMINAL_VOLTAGE_NOTOP1_5) { l_selected_dram_voltage=1500; l_selected_dram_voltage_vpp = DDR3_VPP_VOLT; } else { std::vector<fapi::Target> l_dimm_targets_deconfig; // Iterate through the list of centaurs for (uint32_t i=0; i < i_targets_memb.size(); i++) { std::vector<fapi::Target> l_mbaChiplets; // Get associated MBA's on this centaur l_rc=fapiGetChildChiplets(i_targets_memb[i], fapi::TARGET_TYPE_MBA_CHIPLET, l_mbaChiplets); if (l_rc) break; // Loop through the 2 MBA's for (uint32_t j=0; j < l_mbaChiplets.size(); j++) { std::vector<fapi::Target> l_dimm_targets; // Get a vector of DIMM targets l_rc = fapiGetAssociatedDimms(l_mbaChiplets[j], l_dimm_targets, fapi::TARGET_STATE_PRESENT); if (l_rc) break; for (uint32_t k=0; k < l_dimm_targets.size(); k++) { l_rc = FAPI_ATTR_GET(ATTR_SPD_MODULE_NOMINAL_VOLTAGE, &l_dimm_targets[k], l_spd_volts); if (l_rc) break; if((l_spd_volts & fapi::ENUM_ATTR_SPD_MODULE_NOMINAL_VOLTAGE_NOTOP1_5) == fapi::ENUM_ATTR_SPD_MODULE_NOMINAL_VOLTAGE_NOTOP1_5) { const fapi::Target &DIMM_UV_TARGET = l_dimm_targets[k]; const uint8_t &DIMM_VOLTAGE = l_spd_volts; FAPI_ERR("One or more DIMMs do not support required voltage for DIMM type"); FAPI_SET_HWP_ERROR(l_rc, RC_MSS_VOLT_DDR_TYPE_REQUIRED_VOLTAGE); fapiLogError(l_rc); } }//end of dimms loop if (l_rc) { break; } }//end of mba loop if (l_rc) { break; } }//end of centaur (memb) loop } if (l_rc) { // Break out of do...while(0) break; } // Must check to see if we violate Tolerent voltages of Non-functional Dimms // If so we must error/deconfigure on the dimm level primarily then centaur level. // Iterate through the list of centaurs for (uint32_t i=0; i < i_targets_memb.size(); i++) { std::vector<fapi::Target> l_dimm_targets_deconfig; l_tolerated_dram_voltage = MAX_TOLERATED_VOLT; // using 1.5 as this is the largest supported voltage std::vector<fapi::Target> l_mbaChiplets; // Get associated MBA's on this centaur l_rc=fapiGetChildChiplets(i_targets_memb[i], fapi::TARGET_TYPE_MBA_CHIPLET, l_mbaChiplets); if (l_rc) break; for (uint32_t j=0; j < l_mbaChiplets.size(); j++) { std::vector<fapi::Target> l_dimm_targets; // Get a vector of DIMM targets l_rc = fapiGetAssociatedDimms(l_mbaChiplets[j], l_dimm_targets, fapi::TARGET_STATE_PRESENT); if (l_rc) break; for (uint32_t k=0; k < l_dimm_targets.size(); k++) { l_rc = FAPI_ATTR_GET(ATTR_FUNCTIONAL, &l_dimm_targets[k], l_dimm_functionality); if (l_rc) break; if(l_dimm_functionality == fapi::ENUM_ATTR_FUNCTIONAL_NON_FUNCTIONAL) { if (l_spd_dramtype == fapi::ENUM_ATTR_SPD_DRAM_DEVICE_TYPE_DDR3) { if (l_tolerated_dram_voltage > MAX_TOLERATED_DDR3_VOLT) { l_tolerated_dram_voltage = MAX_TOLERATED_DDR3_VOLT; } if (MAX_TOLERATED_DDR3_VOLT < l_selected_dram_voltage) { FAPI_ERR("One or more DIMMs classified non-functional has a" " tolerated voltage below selected voltage."); const fapi::Target & CHIP_TARGET = l_dimm_targets[k]; const uint8_t &DIMM_VOLTAGE = l_selected_dram_voltage; FAPI_SET_HWP_ERROR(l_rc, RC_MSS_VOLT_TOLERATED_VOLTAGE_VIOLATION); fapiLogError(l_rc); } } if (l_spd_dramtype == fapi::ENUM_ATTR_SPD_DRAM_DEVICE_TYPE_DDR4) { if (l_tolerated_dram_voltage > MAX_TOLERATED_DDR4_VOLT) { l_tolerated_dram_voltage = MAX_TOLERATED_DDR4_VOLT; } if (MAX_TOLERATED_DDR4_VOLT < l_selected_dram_voltage) { FAPI_ERR("One or more DIMMs classified non-functional has a" " tolerated voltage below selected voltage."); const fapi::Target & CHIP_TARGET = l_dimm_targets[k]; const uint8_t &DIMM_VOLTAGE = l_selected_dram_voltage; FAPI_SET_HWP_ERROR(l_rc, RC_MSS_VOLT_TOLERATED_VOLTAGE_VIOLATION); fapiLogError(l_rc); } } }//End of functional check }//End of Dimm loop if (l_rc) { break; } }// End of MBA loop if (l_rc) { break; } if ( l_tolerated_dram_voltage < l_selected_dram_voltage ) { FAPI_ERR("Deconfiguring the associated Centaur."); const fapi::Target & CHIP_TARGET = i_targets_memb[i]; const uint8_t &DIMM_VOLTAGE = l_selected_dram_voltage; FAPI_SET_HWP_ERROR(l_rc, RC_MSS_VOLT_TOLERATED_VOLTAGE_VIOLATION); break; } }//End of Centaur (MEMB) loop if (l_rc) { // Break out of do...while(0) break; } // Iterate through the list of centaurs again, to update ATTR for (uint32_t i=0; i < i_targets_memb.size(); i++) { l_rc = FAPI_ATTR_SET(ATTR_MSS_VOLT, &i_targets_memb[i], l_selected_dram_voltage); FAPI_INF( "mss_volt calculation complete. MSS_VOLT: %d", l_selected_dram_voltage); if (l_rc) break; l_rc = FAPI_ATTR_SET(ATTR_MSS_VOLT_VPP, &i_targets_memb[i], l_selected_dram_voltage_vpp); FAPI_INF( "mss_volt calculation complete. MSS_VOLT_VPP: %d", l_selected_dram_voltage_vpp); if (l_rc) break; } }while(0); return l_rc; }
// parameters: // 'i_target' is chip target // // returns: // FAPI_RC_SUCCESS (success, EX chiplets entered fast winkle) // // getscom/putscom/getattribute fapi errors // fapi error assigned from eCMD function failure // //------------------------------------------------------------------------------ fapi::ReturnCode proc_mpipl_ex_cleanup(const fapi::Target & i_target) { const char *procedureName = "proc_mpipl_ex_cleanup"; fapi::ReturnCode rc; //fapi return code uint32_t rc_ecmd = 0; //ecmd return code value ecmdDataBufferBase fsi_data(64); //64-bit data buffer uint8_t attr_chip_unit_pos; //EX chiplet's unit offset within chip with respect to similar EX units const uint64_t EX_OFFSET_MULT = 0x01000000; //Multiplier used to calculate offset for respective EX chiplet uint64_t address; // Varible for computed addresses uint64_t offset; char reg_name[32]; // Character array for register names // Relevant PMGP0 bits // const uint32_t PM_DISABLE = 0; const uint32_t BLOCK_REG_WKUP_SOURCE = 53; // Relevant PMGP1 bits const uint32_t WINKLE_POWER_OFF_SEL = 5; std::vector<fapi::Target> v_ex_chiplets; //Vector of EX chiplets do { //Entering fapi function FAPI_INF("Entering %s", procedureName); //Get vector of EX chiplets rc = fapiGetChildChiplets( i_target, fapi::TARGET_TYPE_EX_CHIPLET, v_ex_chiplets, fapi::TARGET_STATE_FUNCTIONAL); if (rc) { FAPI_ERR("%s: fapiGetChildChiplets error", procedureName); break; } FAPI_INF("Processing target %s", i_target.toEcmdString()); //Parse thru EX chiplets and prepare fast-winkled cores for deep operations //Loop thru EX chiplets in vector for (uint32_t counter = 0; counter < v_ex_chiplets.size(); counter++) { // Get EX chiplet number rc = FAPI_ATTR_GET( ATTR_CHIP_UNIT_POS, &(v_ex_chiplets[counter]), attr_chip_unit_pos); if (rc) { FAPI_ERR("%s: fapiGetAttribute error (ATTR_CHIP_UNIT_POS)", procedureName); break; } FAPI_INF("EX chiplet pos = 0x%02X", attr_chip_unit_pos); // Calculate the address offset based on chiplet number offset = EX_OFFSET_MULT * attr_chip_unit_pos; // ----------------------------------------------------------------- FAPI_DBG("\tOriginal register contents"); address = EX_GP3_0x100F0012 + offset; strcpy(reg_name, "GP3"); rc = fapiGetScom( i_target, address, fsi_data ); if (rc) { FAPI_ERR("fapiGetScom error (addr: 0x%08llX)", address); break; } FAPI_DBG("\t%s (addr: 0x%08llX), val=0x%016llX", reg_name, address, fsi_data.getDoubleWord(0)); address = EX_PMGP0_0x100F0100 + offset; strcpy(reg_name, "PMGP0"); rc = fapiGetScom( i_target, address, fsi_data ); if (rc) { FAPI_ERR("fapiGetScom error (addr: 0x%08llX)", address); break; } FAPI_DBG("\t%s (addr: 0x%08llX), val=0x%016llX", reg_name, address, fsi_data.getDoubleWord(0)); address = EX_PMGP1_0x100F0103 + offset; strcpy(reg_name, "PMGP1"); rc = fapiGetScom( i_target, address, fsi_data ); if (rc) { FAPI_ERR("fapiGetScom error (addr: 0x%08llX)", address); break; } FAPI_DBG("\t%s (addr: 0x%08llX), val=0x%016llX", reg_name, address, fsi_data.getDoubleWord(0)); // ----------------------------------------------------------------- // Clean up configuration remnants of the fast-winkle configuration // that was used to flush the chiplets after checkstop. EX chiplets // will have been through SBE EX Init with certain step skippled due // to MPIPL. FAPI_INF("Re-establish Deep Winkle mode default"); address = EX_PMGP1_OR_0x100F0105 + offset; strcpy(reg_name, "PMGP1 OR"); rc_ecmd |= fsi_data.flushTo0(); rc_ecmd |= fsi_data.setBit(WINKLE_POWER_OFF_SEL); if(rc_ecmd) { FAPI_ERR("ecmdDatatBuffer error preparing %s reg (addr: 0x%08llX) with rc %x", reg_name, address, rc_ecmd); rc.setEcmdError(rc_ecmd); break; } rc = fapiPutScom(i_target, address, fsi_data); if (rc) { FAPI_ERR("fapiPutScom error (addr: 0x%08llX)", address); break; } FAPI_INF("Clear block wakeup sources to PM logic. PM is NOT re-enabled"); // (eg clear Block Interrrupt Sources) address = EX_PMGP0_AND_0x100F0101 + offset; strcpy(reg_name, "PMGP0 AND"); rc_ecmd |= fsi_data.flushTo1(); // rc_ecmd |= fsi_data.clearBit(PM_DISABLE); rc_ecmd |= fsi_data.clearBit(BLOCK_REG_WKUP_SOURCE); if(rc_ecmd) { FAPI_ERR("ecmdDatatBuffer error preparing %s reg (addr: 0x%08llX)", reg_name, address); rc.setEcmdError(rc_ecmd); break; } rc = fapiPutScom(i_target, address, fsi_data); if (rc) { FAPI_ERR("fapiPutScom error (addr: 0x%08llX)", address); break; } // ----------------------------------------------------------------- FAPI_DBG("\tUpdated register contents"); address = EX_GP3_0x100F0012 + offset; strcpy(reg_name, "GP3"); rc = fapiGetScom( i_target, address, fsi_data ); if (rc) { FAPI_ERR("fapiGetScom error (addr: 0x%08llX)", address); break; } FAPI_DBG("\t%s (addr: 0x%08llX), val=0x%016llX", reg_name, address, fsi_data.getDoubleWord(0)); address = EX_PMGP0_0x100F0100 + offset; strcpy(reg_name, "PMGP0"); rc = fapiGetScom( i_target, address, fsi_data ); if (rc) { FAPI_ERR("fapiGetScom error (addr: 0x%08llX)", address); break; } FAPI_DBG("\t%s (addr: 0x%08llX), val=0x%016llX", reg_name, address, fsi_data.getDoubleWord(0)); address = EX_PMGP1_0x100F0103 + offset; strcpy(reg_name, "PMGP1"); rc = fapiGetScom( i_target, address, fsi_data ); if (rc) { FAPI_ERR("fapiGetScom error (addr: 0x%08llX)", address); break; } FAPI_DBG("\t%s (addr: 0x%08llX), val=0x%016llX", reg_name, address, fsi_data.getDoubleWord(0)); // ----------------------------------------------------------------- } // chiplet loop // Error exit from above loop // Not really needed as outer while(0) is next but here for consistent structure if (!rc.ok()) { break; } } while (0); //Exiting fapi function FAPI_INF("Exiting %s", procedureName); return rc; }
// HWP entry point, comments in header fapi::ReturnCode proc_chiplet_scominit(const fapi::Target & i_target) { fapi::ReturnCode rc; uint32_t rc_ecmd = 0; fapi::TargetType target_type; std::vector<fapi::Target> initfile_targets; std::vector<fapi::Target> ex_targets; std::vector<fapi::Target> mcs_targets; uint8_t nx_enabled; uint8_t mcs_pos; uint8_t ex_pos; uint8_t num_ex_targets; uint8_t master_mcs_pos = 0xFF; fapi::Target master_mcs; uint8_t enable_xbus_resonant_clocking = 0x0; uint8_t i2c_slave_address = 0x0; uint8_t dual_capp_present = 0x0; ecmdDataBufferBase data(64); ecmdDataBufferBase cfam_data(32); ecmdDataBufferBase mask(64); bool is_master = false; // mark HWP entry FAPI_INF("proc_chiplet_scominit: Start"); do { rc = proc_check_master_sbe_seeprom(i_target, is_master); if (!rc.ok()) { FAPI_ERR("proc_cen_ref_clk_enable: Error from proc_check_master_sbe_seeprom"); break; } // obtain target type to determine which initfile(s) to execute target_type = i_target.getType(); // chip level target if (target_type == fapi::TARGET_TYPE_PROC_CHIP) { // execute FBC SCOM initfile initfile_targets.push_back(i_target); FAPI_INF("proc_chiplet_scominit: Executing %s on %s", PROC_CHIPLET_SCOMINIT_FBC_IF, i_target.toEcmdString()); FAPI_EXEC_HWP( rc, fapiHwpExecInitFile, initfile_targets, PROC_CHIPLET_SCOMINIT_FBC_IF); if (!rc.ok()) { FAPI_ERR("proc_chiplet_scominit: Error from fapiHwpExecInitfile executing %s on %s", PROC_CHIPLET_SCOMINIT_FBC_IF, i_target.toEcmdString()); break; } // execute PSI SCOM initfile FAPI_INF("proc_chiplet_scominit: Executing %s on %s", PROC_CHIPLET_SCOMINIT_PSI_IF, i_target.toEcmdString()); FAPI_EXEC_HWP( rc, fapiHwpExecInitFile, initfile_targets, PROC_CHIPLET_SCOMINIT_PSI_IF); if (!rc.ok()) { FAPI_ERR("proc_chiplet_scominit: Error from fapiHwpExecInitfile executing %s on %s", PROC_CHIPLET_SCOMINIT_PSI_IF, i_target.toEcmdString()); break; } // execute TP bridge SCOM initfile FAPI_INF("proc_chiplet_scominit: Executing %s on %s", PROC_CHIPLET_SCOMINIT_TPBRIDGE_IF, i_target.toEcmdString()); FAPI_EXEC_HWP( rc, fapiHwpExecInitFile, initfile_targets, PROC_CHIPLET_SCOMINIT_TPBRIDGE_IF); if (!rc.ok()) { FAPI_ERR("proc_chiplet_scominit: Error from fapiHwpExecInitfile executing %s on %s", PROC_CHIPLET_SCOMINIT_TPBRIDGE_IF, i_target.toEcmdString()); break; } // query NX partial good attribute rc = FAPI_ATTR_GET(ATTR_PROC_NX_ENABLE, &i_target, nx_enabled); if (!rc.ok()) { FAPI_ERR("proc_chiplet_scominit: Error querying ATTR_PROC_NX_ENABLE"); break; } // apply NX/AS SCOM initfiles only if partial good attribute is set if (nx_enabled == fapi::ENUM_ATTR_PROC_NX_ENABLE_ENABLE) { // execute NX SCOM initfile FAPI_INF("proc_chiplet_scominit: Executing %s on %s", PROC_CHIPLET_SCOMINIT_NX_IF, i_target.toEcmdString()); FAPI_EXEC_HWP( rc, fapiHwpExecInitFile, initfile_targets, PROC_CHIPLET_SCOMINIT_NX_IF); if (!rc.ok()) { FAPI_ERR("proc_chiplet_scominit: Error from fapiHwpExecInitfile executing %s on %s", PROC_CHIPLET_SCOMINIT_NX_IF, i_target.toEcmdString()); break; } // execute CXA SCOM initfile FAPI_INF("proc_chiplet_scominit: Executing %s on %s", PROC_CHIPLET_SCOMINIT_CXA_IF, i_target.toEcmdString()); FAPI_EXEC_HWP( rc, fapiHwpExecInitFile, initfile_targets, PROC_CHIPLET_SCOMINIT_CXA_IF); if (!rc.ok()) { FAPI_ERR("proc_chiplet_scominit: Error from fapiHwpExecInitfile executing %s on %s", PROC_CHIPLET_SCOMINIT_CXA_IF, i_target.toEcmdString()); break; } // configure CXA APC master LCO settings rc = fapiGetChildChiplets(i_target, fapi::TARGET_TYPE_EX_CHIPLET, ex_targets, fapi::TARGET_STATE_FUNCTIONAL); if (!rc.ok()) { FAPI_ERR("proc_chiplet_scominit: Error from fapiGetChildChiplets (EX) on %s", i_target.toEcmdString()); break; } // form valid LCO target list for (std::vector<fapi::Target>::iterator i = ex_targets.begin(); i != ex_targets.end(); i++) { // determine EX chiplet number rc = FAPI_ATTR_GET(ATTR_CHIP_UNIT_POS, &(*i), ex_pos); if (!rc.ok()) { FAPI_ERR("proc_chiplet_scominit: Error from FAPI_ATTR_GET (ATTR_CHIP_UNIT_POS) on %s", i->toEcmdString()); break; } rc_ecmd |= data.setBit(ex_pos-((ex_pos < 8)?(1):(3))); } if (!rc.ok()) { break; } num_ex_targets = ex_targets.size(); rc_ecmd |= data.insertFromRight( num_ex_targets, CAPP_APC_MASTER_LCO_TARGET_MIN_START_BIT, (CAPP_APC_MASTER_LCO_TARGET_MIN_END_BIT- CAPP_APC_MASTER_LCO_TARGET_MIN_START_BIT+1)); if (rc_ecmd) { FAPI_ERR("proc_chiplet_scominit: Error 0x%x setting APC Master LCO Target register data buffer", rc_ecmd); rc.setEcmdError(rc_ecmd); break; } rc = fapiPutScom(i_target, CAPP_APC_MASTER_LCO_TARGET_0x02013021, data); if (!rc.ok()) { FAPI_ERR("proc_chiplet_scominit: fapiPutScom error (CAPP_APC_MASTER_LCO_TARGET_0x02013021) on %s", i_target.toEcmdString()); break; } // get dual CAPP presence attribute FAPI_DBG("proc_chiplet_scominit: Querying dual CAPP feature attribute"); rc = FAPI_ATTR_GET(ATTR_CHIP_EC_FEATURE_DUAL_CAPP_PRESENT, &i_target, dual_capp_present); if (!rc.ok()) { FAPI_ERR("proc_chiplet_scominit: Error querying ATTR_CHIP_EC_FEATURE_DUAL_CAPP_PRESENT"); break; } if (dual_capp_present != 0) { rc = fapiPutScom(i_target, CAPP1_APC_MASTER_LCO_TARGET_0x020131A1, data); if (!rc.ok()) { FAPI_ERR("proc_chiplet_scominit: fapiPutScom error (CAPP1_APC_MASTER_LCO_TARGET_0x020131A1) on %s", i_target.toEcmdString()); break; } } // execute AS SCOM initfile FAPI_INF("proc_chiplet_scominit: Executing %s on %s", PROC_CHIPLET_SCOMINIT_AS_IF, i_target.toEcmdString()); FAPI_EXEC_HWP( rc, fapiHwpExecInitFile, initfile_targets, PROC_CHIPLET_SCOMINIT_AS_IF); if (!rc.ok()) { FAPI_ERR("proc_chiplet_scominit: Error from fapiHwpExecInitfile executing %s on %s", PROC_CHIPLET_SCOMINIT_AS_IF, i_target.toEcmdString()); break; } } else { FAPI_DBG("proc_chiplet_scominit: Skipping execution of %s/%s/%s (partial good)", PROC_CHIPLET_SCOMINIT_NX_IF, PROC_CHIPLET_SCOMINIT_CXA_IF, PROC_CHIPLET_SCOMINIT_AS_IF); } // conditionally enable I2C Slave rc = FAPI_ATTR_GET(ATTR_I2C_SLAVE_ADDRESS, &i_target, i2c_slave_address); if (!rc.ok()) { FAPI_ERR("proc_chiplet_scominit: Error querying ATTR_I2C_SLAVE_ADDRESS on %s", i_target.toEcmdString()); break; } rc = fapiGetScom(i_target, I2C_SLAVE_CONFIG_REG_0x000D0000, data); if (!rc.ok()) { FAPI_ERR("proc_chiplet_scominit: fapiGetScom error (I2C_SLAVE_CONFIG_REG_0x000D0000) on %s", i_target.toEcmdString()); break; } if (i2c_slave_address) { FAPI_DBG("proc_chiplet_scominit: I2C Slave enabled (%s) address = %d", i_target.toEcmdString(),i2c_slave_address); //set I2C address rc_ecmd |= data.insert(i2c_slave_address,0,7); // disable error state. when this is enabled and there // is an error from I2CS it locks up the I2CS and no // more operations are allowed unless cleared // through FSI. Not good for a FSPless system. rc_ecmd |= data.clearBit(23); // enable I2C interface rc_ecmd |= data.setBit(21); } else { FAPI_DBG("proc_chiplet_scominit: I2C Slave disabled (%s)", i_target.toEcmdString()); // disable I2C interface when attribute = 0x0 rc_ecmd |= data.clearBit(21); } if (rc_ecmd) { FAPI_ERR("proc_chiplet_scominit: Error 0x%x setting I2C Slave register data buffer", rc_ecmd); rc.setEcmdError(rc_ecmd); break; } rc = fapiPutScom(i_target, I2C_SLAVE_CONFIG_REG_0x000D0000, data); if (!rc.ok()) { FAPI_ERR("proc_chiplet_scominit: fapiPutScom error (I2C_SLAVE_CONFIG_REG_0x000D0000) on %s", i_target.toEcmdString()); break; } // conditionally enable resonant clocking for XBUS rc = FAPI_ATTR_GET(ATTR_CHIP_EC_FEATURE_XBUS_RESONANT_CLK_VALID, &i_target, enable_xbus_resonant_clocking); if (!rc.ok()) { FAPI_ERR("proc_chiplet_scominit: Error querying ATTR_CHIP_EC_FEATURE_XBUS_RESONANT_CLK_VALID on %s", i_target.toEcmdString()); break; } if (enable_xbus_resonant_clocking) { FAPI_DBG("proc_chiplet_scominit: Enabling XBUS resonant clocking"); rc = fapiGetScom(i_target, MBOX_FSIGP6_0x00050015, data); if (!rc.ok()) { FAPI_ERR("proc_chiplet_scominit: fapiGetScom error (MBOX_FSIGP6_0x00050015) on %s", i_target.toEcmdString()); break; } rc_ecmd |= data.insertFromRight( XBUS_RESONANT_CLOCK_CONFIG, MBOX_FSIGP6_XBUS_RESONANT_CLOCK_CONFIG_START_BIT, (MBOX_FSIGP6_XBUS_RESONANT_CLOCK_CONFIG_END_BIT- MBOX_FSIGP6_XBUS_RESONANT_CLOCK_CONFIG_START_BIT+1)); if (rc_ecmd) { FAPI_ERR("proc_chiplet_scominit: Error 0x%x setting FSI GP6 register data buffer", rc_ecmd); rc.setEcmdError(rc_ecmd); break; } if (is_master) { rc = fapiPutScom(i_target, MBOX_FSIGP6_0x00050015, data); if (!rc.ok()) { FAPI_ERR("proc_chiplet_scominit: fapiPutScom error (MBOX_FSIGP6_0x00050015) on %s", i_target.toEcmdString()); break; } } else { cfam_data.insert(data, 0, 32, 0); rc = fapiPutCfamRegister(i_target, CFAM_FSI_GP6_0x00002815, cfam_data); if (rc) { FAPI_ERR("proc_cen_ref_clk_enable: fapiPutCfamRegister error (CFAM_FSI_GP8_0x00001017)"); break; } } } // execute A/X/PCI/DMI FIR init SCOM initfile FAPI_INF("proc_chiplet_scominit: Executing %s on %s", PROC_CHIPLET_SCOMINIT_A_X_PCI_DMI_IF, i_target.toEcmdString()); FAPI_EXEC_HWP( rc, fapiHwpExecInitFile, initfile_targets, PROC_CHIPLET_SCOMINIT_A_X_PCI_DMI_IF); if (!rc.ok()) { FAPI_ERR("proc_chiplet_scominit: Error from fapiHwpExecInitfile executing %s on %s", PROC_CHIPLET_SCOMINIT_A_X_PCI_DMI_IF, i_target.toEcmdString()); break; } // execute NV scominit file uint8_t exist_NV = 0x00; rc = FAPI_ATTR_GET(ATTR_CHIP_EC_FEATURE_NV_PRESENT, &i_target, exist_NV); if (!rc.ok()) { FAPI_ERR("proc_chiplet_scominit: Error getting attribute value ATTR_CHIP_EC_FEATURE_NV_PRESENT"); break; } if (exist_NV) { FAPI_INF("proc_chiplet_scominit: Executing %s on %s", PROC_CHIPLET_SCOMINIT_NPU_IF, i_target.toEcmdString()); FAPI_EXEC_HWP( rc, fapiHwpExecInitFile, initfile_targets, PROC_CHIPLET_SCOMINIT_NPU_IF); if (!rc.ok()) { FAPI_ERR("proc_chiplet_scominit: Error from fapiHwpExecInitfile executing %s on %s", PROC_CHIPLET_SCOMINIT_NPU_IF, i_target.toEcmdString()); break; } // cleanup FIR bit (NPU FIR bit 27) caused by NDL/NTL parity error rc_ecmd = data.flushTo1(); rc_ecmd = data.clearBit(NPU_FIR_NTL_DL2TL_PARITY_ERR_BIT); if (rc_ecmd) { FAPI_ERR("proc_chiplet_scominit: Error 0x%Xforming NPU FIR cleanup data buffer", rc_ecmd); rc.setEcmdError(rc_ecmd); break; } rc = fapiPutScom(i_target, NPU_FIR_AND_0x08013D81, data); if (!rc.ok()) { FAPI_ERR("proc_chiplet_scominit: fapiPutScom error (NPU_FIR_AND_0x08013D81) on %s", i_target.toEcmdString()); break; } rc = fapiPutScom(i_target, NPU_FIR_MASK_AND_0x08013D84, data); if (!rc.ok()) { FAPI_ERR("proc_chiplet_scominit: fapiPutScom error (NPU_FIR_MASK_AND_0x08013D84) on %s", i_target.toEcmdString()); break; } } else { FAPI_INF("proc_chiplet_scominit: NV link logic not present, scom initfile processing skipped"); } // determine set of functional MCS chiplets rc = fapiGetChildChiplets(i_target, fapi::TARGET_TYPE_MCS_CHIPLET, mcs_targets, fapi::TARGET_STATE_FUNCTIONAL); if (!rc.ok()) { FAPI_ERR("proc_chiplet_scominit: Error from fapiGetChildChiplets (MCS) on %s", i_target.toEcmdString()); break; } // apply MCS SCOM initfile only for functional chiplets for (std::vector<fapi::Target>::iterator i = mcs_targets.begin(); (i != mcs_targets.end()) && rc.ok(); i++) { // execute MCS SCOM initfile initfile_targets.clear(); initfile_targets.push_back(*i); initfile_targets.push_back(i_target); FAPI_INF("proc_chiplet_scominit: Executing %s on %s", PROC_CHIPLET_SCOMINIT_MCS_IF, i->toEcmdString()); FAPI_EXEC_HWP( rc, fapiHwpExecInitFile, initfile_targets, PROC_CHIPLET_SCOMINIT_MCS_IF); if (!rc.ok()) { FAPI_ERR("proc_chiplet_scominit: Error from fapiHwpExecInitfile executing %s on %s", PROC_CHIPLET_SCOMINIT_MCS_IF, i->toEcmdString()); break; } // determine MCS position rc = FAPI_ATTR_GET(ATTR_CHIP_UNIT_POS, &(*i), mcs_pos); if (!rc.ok()) { FAPI_ERR("proc_chiplet_scominit: Error from FAPI_ATTR_GET (ATTR_CHIP_UNIT_POS) on %s", i->toEcmdString()); break; } if (mcs_pos < master_mcs_pos) { fapi::Target cen_target_unused; rc = fapiGetOtherSideOfMemChannel(*i, cen_target_unused, fapi::TARGET_STATE_FUNCTIONAL); // use return code only to indicate presence of connected Centaur, // do not propogate/emit error if not connected if (rc.ok()) { FAPI_DBG("Updating master_mcs_pos to %d", mcs_pos); FAPI_DBG(" Target: %s", cen_target_unused.toEcmdString()); master_mcs = *i; master_mcs_pos = mcs_pos; } else { rc = fapi::FAPI_RC_SUCCESS; } } } if (!rc.ok()) { break; } if (master_mcs.getType() == fapi::TARGET_TYPE_MCS_CHIPLET) { // set MCMODE0Q_ENABLE_CENTAUR_SYNC on first target only // (this bit is required to be set on at most one MCS/chip) rc_ecmd |= data.flushTo0(); rc_ecmd |= data.setBit(MCSMODE0_EN_CENTAUR_SYNC_BIT); rc_ecmd |= mask.setBit(MCSMODE0_EN_CENTAUR_SYNC_BIT); // check buffer manipulation return codes if (rc_ecmd) { FAPI_ERR("proc_chiplet_scominit: Error 0x%X setting up MCSMODE0 data buffer", rc_ecmd); rc.setEcmdError(rc_ecmd); break; } // write register with updated content rc = fapiPutScomUnderMask(master_mcs, MCS_MCSMODE0_0x02011807, data, mask); if (!rc.ok()) { FAPI_ERR("proc_chiplet_scominit: fapiPutScomUnderMask error (MCS_MCSMODE0_0x02011807) on %s", master_mcs.toEcmdString()); break; } } } // unsupported target type else { FAPI_ERR("proc_chiplet_scominit: Unsupported target type"); const fapi::Target & TARGET = i_target; FAPI_SET_HWP_ERROR(rc, RC_PROC_CHIPLET_SCOMINIT_INVALID_TARGET); break; } } while(0); // mark HWP exit FAPI_INF("proc_chiplet_scominit: End"); return rc; }