/* IBM_PROLOG_BEGIN_TAG */ /* This is an automatically generated prolog. */ /* */ /* $Source: src/import/chips/centaur/procedures/hwp/memory/p9c_mss_generic_shmoo.C $ */ /* */ /* OpenPOWER HostBoot Project */ /* */ /* Contributors Listed Below - COPYRIGHT 2016,2018 */ /* [+] 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 p9c_mss_generic_shmoo.C /// @brief MSS Generic Shmoo Implementation /// /// *HWP HWP Owner: Andre Marin /// *HWP HWP Backup: Stephen Glancy /// *HWP Team: Memory /// *HWP Level: 2 /// *HWP Consumed by: HB:CI /// #include #include #include #include #include #include #include #include extern "C" { /// /// @brief Constructor used to initialize variables and do the initial settings /// @param[in] i_addr Port number /// @param[in] shmoo_type_t i_shmoo_mask set what shmoos caller wants to run /// @param[in] shmoo_algorithm SEQ_LIN, PARALLEL etc. /// generic_shmoo::generic_shmoo(uint8_t i_addr, shmoo_type_t i_shmoo_mask, shmoo_algorithm_t shmoo_algorithm) { this->iv_shmoo_mask = i_shmoo_mask; //! Sets what Shmoos the caller wants to run this->iv_algorithm = shmoo_algorithm ; this->iv_shmoo_type = i_shmoo_mask; this->iv_addr = i_addr; iv_MAX_BYTES = 10; iv_DQS_ON = 0; iv_pattern = 0; iv_test_type = 0; iv_dmm_type = 0; iv_shmoo_param = 0; iv_binary_diff = 2; iv_vref_mul = 0; iv_SHMOO_ON = 0; for(uint8_t p = 0; p < MAX_PORT; p++) { for(uint8_t i = 0; i < MAX_RANK; i++) { iv_valid_rank[p][i] = 0; } } iv_MAX_RANKS[0] = 4; iv_MAX_RANKS[1] = 4; if (iv_shmoo_mask & TEST_NONE) { FAPI_INF("mss_generic_shmoo : NONE selected %d", iv_shmoo_mask); } if (iv_shmoo_mask & MCBIST) { FAPI_INF("mss_generic_shmoo : MCBIST selected %d", iv_shmoo_mask); iv_shmoo_type = 1; } if (iv_shmoo_mask & WR_EYE) { FAPI_INF("mss_generic_shmoo : WR_EYE selected %d", iv_shmoo_mask); iv_shmoo_type = 2; } if (iv_shmoo_mask & RD_EYE) { FAPI_INF("mss_generic_shmoo : RD_EYE selected %d", iv_shmoo_mask); iv_shmoo_type = 8; } if (iv_shmoo_mask & WRT_DQS) { FAPI_INF("mss_generic_shmoo : WRT_DQS selected %d", iv_shmoo_mask); iv_shmoo_type = 4; iv_DQS_ON = 1; } if(iv_DQS_ON == 1) { for (uint8_t i = 0; i < MAX_PORT; i++) { for (uint8_t j = 0; j < iv_MAX_RANKS[i]; j++) { init_multi_array(250, SHMOO.MBA.P[i].S[j].K.nom_val); init_multi_array(0, SHMOO.MBA.P[i].S[j].K.lb_regval); init_multi_array(512, SHMOO.MBA.P[i].S[j].K.rb_regval); init_multi_array(0, SHMOO.MBA.P[i].S[j].K.last_pass); init_multi_array(0, SHMOO.MBA.P[i].S[j].K.last_fail); init_multi_array(0, SHMOO.MBA.P[i].S[j].K.curr_val); init_multi_array(250, iv_dqs_rb_regval[i][j]); init_multi_array(250, iv_dqs_lb_regval[i][j]); init_multi_array(250, iv_dqs_nom_val[i][j]); } } } } /// /// @brief Sets up shmoo instance variables /// @param[in] i_target Centaur input mba /// @return FAPI2_RC_SUCCESS iff successful /// fapi2::ReturnCode generic_shmoo::setup(const fapi2::Target& i_target) { uint8_t num_ranks_per_dimm[MAX_PORTS_PER_MBA][MAX_DIMM_PER_PORT] = {0}; uint8_t eff_stack_type[MAX_PORTS_PER_MBA][MAX_DIMM_PER_PORT] = {0}; uint8_t l_attr_eff_dimm_type_u8 = 0; uint8_t rank_table_port0[8] = {0}; uint8_t rank_table_port1[8] = {0}; uint8_t l_dram_gen = 0; uint8_t i_rp = 0; uint8_t l_shmoo_param = 0; FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_STACK_TYPE, i_target, eff_stack_type)); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_DRAM_GEN, i_target, l_dram_gen)); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_NUM_MASTER_RANKS_PER_DIMM, i_target, num_ranks_per_dimm)); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_CUSTOM_DIMM, i_target, l_attr_eff_dimm_type_u8)); iv_MAX_RANKS[0] = num_ranks_per_dimm[0][0] + num_ranks_per_dimm[0][1]; iv_MAX_RANKS[1] = num_ranks_per_dimm[1][0] + num_ranks_per_dimm[1][1]; FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_SCHMOO_MODE, i_target, l_shmoo_param)); iv_shmoo_param = l_shmoo_param; FAPI_INF(" +++++ The iv_shmoo_param = %d ++++ ", iv_shmoo_param); if ( l_attr_eff_dimm_type_u8 == fapi2::ENUM_ATTR_CEN_EFF_CUSTOM_DIMM_YES ) { iv_MAX_BYTES = 10; } else { iv_dmm_type = 1; iv_MAX_BYTES = 9; } for(uint8_t l_rnk = 0; l_rnk < iv_MAX_RANKS[0]; l_rnk++) { // Byte loop FAPI_TRY(mss_getrankpair(i_target, 0, 0, &i_rp, rank_table_port0)); } for(uint8_t l_rnk = 0; l_rnk < iv_MAX_RANKS[0]; l_rnk++) { // Byte loop FAPI_TRY(mss_getrankpair(i_target, 1, 0, &i_rp, rank_table_port1)); } for(uint8_t l_p = 0; l_p < MAX_PORTS_PER_MBA; l_p++) { for(uint8_t l_rnk = 0; l_rnk < MAX_RANKS_PER_PORT; l_rnk++) { // Byte loop if(l_p == 0) { iv_valid_rank[l_p][l_rnk] = rank_table_port0[l_rnk]; } else { iv_valid_rank[l_p][l_rnk] = rank_table_port1[l_rnk]; } if((l_attr_eff_dimm_type_u8 == fapi2::ENUM_ATTR_CEN_EFF_CUSTOM_DIMM_YES) && (eff_stack_type[l_p][0] == fapi2::ENUM_ATTR_CEN_EFF_STACK_TYPE_STACK_3DS) && (l_dram_gen == fapi2::ENUM_ATTR_CEN_EFF_DRAM_GEN_DDR4)) { //3ds 256 GB Dimm //FAPI_INF("3DS - 2H 256GB"); rank_table_port0[0] = 0; rank_table_port0[1] = 4; rank_table_port0[2] = 255; rank_table_port0[3] = 255; rank_table_port1[0] = 0; rank_table_port1[1] = 4; rank_table_port1[2] = 255; rank_table_port1[3] = 255; } } } fapi_try_exit: return fapi2::current_err; } /// /// @brief Delegator function that runs shmoo using other functions /// @param[in] i_target Centaur input mba /// @param[out] o_right_min_margin Minimum hold time /// @param[out] o_left_min_margin Minimum setup time /// @return FAPI2_RC_SUCCESS iff successful /// fapi2::ReturnCode generic_shmoo::run(const fapi2::Target& i_target, uint32_t* o_right_min_margin, uint32_t* o_left_min_margin, uint32_t i_vref_mul) { uint8_t l_attr_schmoo_test_type_u8 = 0; uint8_t l_attr_schmoo_multiple_setup_call_u8 = 0; uint8_t l_mcbist_prnt_off = 0; uint64_t i_content_array[10]; uint8_t l_rankpgrp0[2] = { 0 }; uint8_t l_rankpgrp1[2] = { 0 }; uint8_t l_rankpgrp2[2] = { 0 }; uint8_t l_rankpgrp3[2] = { 0 }; uint8_t l_totrg_0 = 0; uint8_t l_totrg_1 = 0; uint8_t l_pp = 0; uint8_t l_dram_width = 0; iv_vref_mul = i_vref_mul; FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_DRAM_WIDTH, i_target, l_dram_width)); FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_MCBIST_PRINTING_DISABLE, i_target, l_mcbist_prnt_off)); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_SCHMOO_TEST_VALID, i_target, l_attr_schmoo_test_type_u8)); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_SCHMOO_MULTIPLE_SETUP_CALL, i_target, l_attr_schmoo_multiple_setup_call_u8)); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_PRIMARY_RANK_GROUP0, i_target, l_rankpgrp0)); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_PRIMARY_RANK_GROUP1, i_target, l_rankpgrp1)); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_PRIMARY_RANK_GROUP2, i_target, l_rankpgrp2)); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_PRIMARY_RANK_GROUP3, i_target, l_rankpgrp3)); iv_pattern = 0; iv_test_type = 0; FAPI_TRY(setup(i_target), "%s failed generic_shmoo::setup", mss::c_str(i_target)); FAPI_DBG("mss_generic_shmoo : run() for shmoo type %d", iv_shmoo_mask); FAPI_DBG("mss_generic_shmoo : run() l_attr_schmoo_test_type_u8 %d", l_attr_schmoo_test_type_u8); // Check if all bytes/bits are in a pass condition initially .Otherwise quit //Value of l_attr_schmoo_test_type_u8 are 0x01, 0x02, 0x04, 0x08, 0x10 , 0x20 === // "MCBIST","WR_EYE","RD_EYE","WRT_DQS","RD_DQS","BOX" resp. if (l_attr_schmoo_test_type_u8 == 0) { FAPI_INF("%s:This procedure wont change any delay settings", mss::c_str(i_target)); } if (l_attr_schmoo_test_type_u8 == 1) { FAPI_TRY(sanity_check(i_target), "generic_shmoo::run MSS Generic Shmoo failed initial Sanity Check. Memory not in an all pass Condition"); } //runs the box shmoo else if (l_attr_schmoo_test_type_u8 == BOX) { FAPI_TRY(get_all_noms(i_target)); if(l_attr_schmoo_multiple_setup_call_u8 == 0) { FAPI_TRY(schmoo_setup_mcb(i_target)); } FAPI_TRY(do_box_shmoo(i_target)); } else if (l_attr_schmoo_test_type_u8 == 8) { if (l_rankpgrp0[0] != 255) { l_totrg_0++; } if (l_rankpgrp1[0] != 255) { l_totrg_0++; } if (l_rankpgrp2[0] != 255) { l_totrg_0++; } if (l_rankpgrp3[0] != 255) { l_totrg_0++; } if (l_rankpgrp0[1] != 255) { l_totrg_1++; } if (l_rankpgrp1[1] != 255) { l_totrg_1++; } if (l_rankpgrp2[1] != 255) { l_totrg_1++; } if (l_rankpgrp3[1] != 255) { l_totrg_1++; } if ((l_totrg_0 == 1) || (l_totrg_1 == 1)) { FAPI_TRY(shmoo_save_rest(i_target, i_content_array, 0)); l_pp = 1; } if (l_pp == 1) { FAPI_INF("%s:Ping pong is disabled", mss::c_str(i_target)); } else { FAPI_INF("%s:Ping pong is enabled", mss::c_str(i_target)); } if ((l_pp = 1) && ((l_totrg_0 == 1) || (l_totrg_1 == 1))) { FAPI_INF("%s:Rank group is not good with ping pong. Hope you have set W2W gap to 10", mss::c_str(i_target)); } iv_shmoo_type = 4; //for Gate Delays FAPI_TRY(get_all_noms_dqs(i_target)); iv_shmoo_type = 2; // For Access delays FAPI_TRY(get_all_noms(i_target)); FAPI_TRY(schmoo_setup_mcb(i_target)); //Find RIGHT BOUND OR SETUP BOUND FAPI_TRY(find_bound(i_target, RIGHT)); //Find LEFT BOUND OR HOLD BOUND FAPI_TRY(find_bound(i_target, LEFT)); iv_shmoo_type = 4; FAPI_TRY(print_report_dqs(i_target)); FAPI_TRY(get_min_margin_dqs(i_target, o_right_min_margin, o_left_min_margin)); if ((l_totrg_0 == 1) || (l_totrg_1 == 1)) { FAPI_TRY(shmoo_save_rest(i_target, i_content_array, 1)); } FAPI_INF("%s: Least tDQSSmin(ps)=%d ps and Least tDQSSmax=%d ps", mss::c_str(i_target), *o_left_min_margin, *o_right_min_margin); } else { FAPI_INF("************ ++++++++++++++++++ ***************** +++++++++++++ *****************"); FAPI_TRY(get_all_noms(i_target)); if(l_attr_schmoo_multiple_setup_call_u8 == 0) { FAPI_TRY(schmoo_setup_mcb(i_target)); } FAPI_TRY(set_all_binary(i_target, RIGHT)); //Find RIGHT BOUND OR SETUP BOUND FAPI_TRY(find_bound(i_target, RIGHT)); FAPI_TRY(set_all_binary(i_target, LEFT)); //Find LEFT BOUND OR HOLD BOUND FAPI_TRY(find_bound(i_target, LEFT)); //It is used to find the lowest of setup and hold margin if(iv_shmoo_param == 6) { FAPI_TRY(get_min_margin2(i_target, o_right_min_margin, o_left_min_margin)); FAPI_TRY(print_report2(i_target)); FAPI_INF("%s:Minimum hold margin=%d ps and setup margin=%d ps", mss::c_str(i_target), *o_left_min_margin, *o_right_min_margin); } else { FAPI_TRY(get_min_margin2(i_target, o_right_min_margin, o_left_min_margin)); FAPI_TRY(print_report2(i_target)); FAPI_INF("%s:Minimum hold margin=%d ps and setup margin=%d ps", mss::c_str(i_target), *o_left_min_margin, *o_right_min_margin); } } l_mcbist_prnt_off = 0; FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_MCBIST_PRINTING_DISABLE, i_target, l_mcbist_prnt_off)); fapi_try_exit: return fapi2::current_err; } /// /// @brief save and restore registers before and after shmoo /// @param[in] i_target Centaur input MBA /// @param[in] i_content_array register contents to save/restore /// @param[in] i_mode 0 = save; 1 = restore /// @return FAPI2_RC_SUCCESS iff successful /// fapi2::ReturnCode generic_shmoo::shmoo_save_rest(const fapi2::Target& i_target, uint64_t i_content_array[], const uint8_t i_mode) { uint8_t l_index = 0; uint64_t l_value = 0; uint64_t l_val_u64 = 0; fapi2::buffer l_shmoo1ab; uint64_t l_Databitdir[10] = { 0x800000030301143full, 0x800004030301143full, 0x800008030301143full, 0x80000c030301143full, 0x800010030301143full, 0x800100030301143full, 0x800104030301143full, 0x800108030301143full, 0x80010c030301143full, 0x800110030301143full }; if (i_mode == 0) { FAPI_INF("%s: Saving DP18 data bit direction register contents", mss::c_str(i_target)); for (l_index = 0; l_index < MAX_BYTE; l_index++) { l_value = l_Databitdir[l_index]; FAPI_TRY(fapi2::getScom(i_target, l_value, l_shmoo1ab)); l_shmoo1ab.setBit<57>(); FAPI_TRY(fapi2::putScom(i_target, l_value, l_shmoo1ab)); l_shmoo1ab.extract<0, 64>(i_content_array[l_index]); } } else if (i_mode == 1) { FAPI_INF("%s: Restoring DP18 data bit direction register contents", mss::c_str(i_target)); for (l_index = 0; l_index < MAX_BYTE; l_index++) { l_val_u64 = i_content_array[l_index]; l_value = l_Databitdir[l_index]; l_shmoo1ab.insert<0, 64>(l_val_u64); FAPI_TRY(fapi2::putScom(i_target, l_value, l_shmoo1ab)); } } else { FAPI_INF("%s:Invalid value of MODE", mss::c_str(i_target)); } fapi_try_exit: return fapi2::current_err; } /// /// @brief do intial mcbist check in nominal and report spd if any bad bit found /// @param[in] i_target Centaur input mba /// @return FAPI2_RC_SUCCESS iff succesful /// fapi2::ReturnCode generic_shmoo::sanity_check(const fapi2::Target& i_target) { iv_mcbist_mode = QUARTER_SLOW; uint8_t l_mcb_status = 0; struct subtest_info l_sub_info[30]; FAPI_DBG("%s: enter sanity check", mss::c_str(i_target)); FAPI_TRY(schmoo_setup_mcb(i_target), "Sanity Check failed schmoo_setup_mcb"); FAPI_DBG("%s: starting mcbist now", mss::c_str(i_target)); FAPI_TRY(start_mcb(i_target), "Sanity Check failed start_mcb"); FAPI_DBG("%s: polling mcbist now", mss::c_str(i_target)); FAPI_TRY(poll_mcb(i_target, &l_mcb_status, l_sub_info, 1), "generic_shmoo::do_mcbist_test: POLL MCBIST failed !!"); FAPI_DBG("%s: parsing error map ", mss::c_str(i_target)); FAPI_TRY(parse_error_map(i_target), "Failed parse_error_map"); fapi_try_exit: return fapi2::current_err; } /// /// @brief parse the MCBIST error map and report spd if any bad bit found /// @param[in] i_target Centaur input mba /// @return FAPI2_RC_SUCCESS iff succesful /// fapi2::ReturnCode generic_shmoo::parse_error_map( const fapi2::Target& i_target ) { uint8_t l_faulted_rank = 255; uint8_t l_faulted_port = 255; uint8_t l_faulted_dimm = 255; uint8_t l_memory_health = 0; uint8_t l_count = 0; uint8_t l_dram_width = 0; uint8_t l_dqBitmap[DIMM_DQ_RANK_BITMAP_SIZE] = { 0 }; // 10 byte array of bad bits uint8_t l_CDarray0[DIMM_TO_C4_DQ_ENTRIES] = { 0 }; uint8_t l_CDarray1[DIMM_TO_C4_DQ_ENTRIES] = { 0 }; FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_DRAM_WIDTH, i_target, l_dram_width)); FAPI_DBG("%s: checking error map ", mss::c_str(i_target)); FAPI_TRY(mcb_error_map(i_target, iv_mcbist_error_map, l_CDarray0, l_CDarray1, iv_count_bad_dq), "Failed mcb_error_map"); for (uint8_t l_p = 0; l_p < MAX_PORT; l_p++) { for (uint8_t l_rnk = 0; l_rnk < iv_MAX_RANKS[l_p]; l_rnk++) { // Byte loop const uint8_t l_rank = iv_valid_rank[l_p][l_rnk]; const uint8_t l_dimm_rank = l_rank % MAX_RANKS_PER_DIMM; for (uint8_t l_byte = 0; l_byte < DIMM_DQ_RANK_BITMAP_SIZE; l_byte++) { //Nibble loop for (uint8_t l_nibble = 0; l_nibble < MAX_NIBBLES; l_nibble++) { if (iv_mcbist_error_map[l_p][l_rank][l_byte][l_nibble] == 1) { l_memory_health = 1; l_faulted_rank = l_rank; l_faulted_port = l_p; if(l_rank > 3) { l_faulted_dimm = 1; } else { l_faulted_dimm = 0; } // Get the bad DQ Bitmap for l_port, l_dimm, l_rank FAPI_TRY(dimmGetBadDqBitmap(i_target, l_p, l_faulted_dimm, l_dimm_rank, l_dqBitmap), "Error from dimmGetBadDqBitmap on %s.", mss::c_str(i_target)); if (l_dram_width == fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X8) { l_dqBitmap[l_byte] = 0xff; } else if ((l_dram_width == fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X4) && (l_nibble == 0)) { l_dqBitmap[l_byte] = l_dqBitmap[l_byte] | 0xf0; } else { l_dqBitmap[l_byte] = l_dqBitmap[l_byte] | 0x0f; } FAPI_INF("%s Warning dimm_bad bits found ---> Updating Bad Bits: port%d, dimm%d, rank%d, l_dqBitmap[%d] = 0x%02x", mss::c_str(i_target), l_p, l_faulted_dimm, l_rank, l_byte, l_dqBitmap[l_byte]); l_count++; FAPI_TRY(dimmSetBadDqBitmap(i_target, l_p, l_faulted_dimm, l_dimm_rank, l_dqBitmap), "Error from dimmSetBadDqBitmap on %s.", mss::c_str(i_target)); } } // nibble } // byte // Reset error count if there was only one error on this rank if((l_memory_health == 1) && (l_count == 1)) { l_count = 0; } } // rank } // port //////////////// changed the check condition ... The error call out need to gard the dimm=l_faulted_dimm(0 or 1) //// port=l_faulted_port(0 or 1) target=i_target ... #ifdef __HOSTBOOT_MODULE // In firmware, post an error log and callout the last faulted port & DIMM if we found any new bad bits FAPI_ASSERT_NOEXIT((l_memory_health == 0), fapi2::CEN_MSS_GENERIC_SHMOO_MCBIST_FAILED(). set_MBA_TARGET(i_target). set_MBA_PORT_NUMBER(l_faulted_port). set_MBA_DIMM_NUMBER(l_faulted_dimm), "generic_shmoo:sanity_check failed !! MCBIST failed on %s initial run, port=%d rank=%d dimm=%d", mss::c_str(i_target), l_faulted_port, l_faulted_rank, l_faulted_dimm); #else // In Cronus, assert and halt only if we found more than one bad nibble on a given rank FAPI_ASSERT((l_count == 0), fapi2::CEN_MSS_GENERIC_SHMOO_MCBIST_FAILED(). set_MBA_TARGET(i_target). set_MBA_PORT_NUMBER(l_faulted_port). set_MBA_DIMM_NUMBER(l_faulted_dimm), "generic_shmoo:sanity_check failed !! MCBIST failed on %s initial run, port=%d rank=%d dimm=%d", mss::c_str(i_target), l_faulted_port, l_faulted_rank, l_faulted_dimm); #endif fapi_try_exit: return fapi2::current_err; } /// /// @brief do mcbist reset /// @param[in] i_target Centaur input mba /// @return FAPI2_RC_SUCCESS iff successful /// fapi2::ReturnCode generic_shmoo::do_mcbist_reset(const fapi2::Target& i_target) { const auto i_target_centaur = i_target.getParent(); fapi2::buffer l_data_buffer_64; l_data_buffer_64.flush<0>(); //PORT - A FAPI_TRY(fapi2::putScom(i_target_centaur, CEN_MCBISTS01_MCBEMA1Q, l_data_buffer_64)); FAPI_TRY(fapi2::putScom(i_target_centaur, CEN_MCBISTS01_MCBEMA2Q, l_data_buffer_64)); FAPI_TRY(fapi2::putScom(i_target_centaur, CEN_MCBISTS01_MCBEMA3Q, l_data_buffer_64)); //PORT - B FAPI_TRY(fapi2::putScom(i_target_centaur, CEN_MCBISTS01_MCBEMB1Q, l_data_buffer_64)); FAPI_TRY(fapi2::putScom(i_target_centaur, CEN_MCBISTS01_MCBEMB2Q, l_data_buffer_64)); FAPI_TRY(fapi2::putScom(i_target_centaur, CEN_MCBISTS01_MCBEMB3Q, l_data_buffer_64)); // MBS 23 FAPI_TRY(fapi2::putScom(i_target_centaur, 0x0201176a, l_data_buffer_64)); FAPI_TRY(fapi2::putScom(i_target_centaur, 0x0201176b, l_data_buffer_64)); FAPI_TRY(fapi2::putScom(i_target_centaur, 0x0201176c, l_data_buffer_64)); //PORT - B FAPI_TRY(fapi2::putScom(i_target_centaur, 0x0201176d, l_data_buffer_64)); FAPI_TRY(fapi2::putScom(i_target_centaur, 0x0201176e, l_data_buffer_64)); FAPI_TRY(fapi2::putScom(i_target_centaur, 0x0201176f, l_data_buffer_64)); fapi_try_exit: return fapi2::current_err; } /// /// @brief do mcbist check for error on particular nibble /// @param[in] i_target: centaur input mba /// @return FAPI2_RC_SUCCESS iff successful /// fapi2::ReturnCode generic_shmoo::do_mcbist_test(const fapi2::Target& i_target) { uint8_t l_mcb_status = 0; struct subtest_info l_sub_info[30]; FAPI_TRY(start_mcb(i_target), "generic_shmoo::do_mcbist_test: Start MCBIST failed !!"); FAPI_TRY(poll_mcb(i_target, &l_mcb_status, l_sub_info, 1), "generic_shmoo::do_mcbist_test: POLL MCBIST failed !!"); fapi_try_exit: return fapi2::current_err; } /// /// @brief used by do_mcbist_test to check the error map for particular nibble /// @param[in] i_target Centaur input MBA /// @param[in] l_p Centaur input port /// @param[out] pass 1 = error found in mcb_error_map /// @return FAPI2_RC_SUCCESS iff successful /// fapi2::ReturnCode generic_shmoo::check_error_map(const fapi2::Target& i_target, uint8_t l_p, uint8_t& pass) { uint8_t l_byte, l_rnk = 0; uint8_t l_nibble = 0; uint8_t l_byte_is = 0; uint8_t l_nibble_is = 0; uint8_t l_n = 0; pass = 1; input_type l_input_type_e = ISDIMM_DQ; uint8_t i_input_index_u8 = 0; uint8_t l_val = 0; uint8_t rank = 0; uint8_t l_max_byte = 10; uint8_t l_CDarray0[80] = {0}; uint8_t l_CDarray1[80] = {0}; if(iv_dmm_type == 1) { l_max_byte = 9; } FAPI_TRY(mcb_error_map(i_target, iv_mcbist_error_map, l_CDarray0, l_CDarray1, iv_count_bad_dq), "generic_shmoo::do_mcbist_test: mcb_error_map failed!!"); for (l_rnk = 0; l_rnk < iv_MAX_RANKS[l_p]; l_rnk++) { // Byte loop rank = iv_valid_rank[l_p][l_rnk]; l_n = 0; for(l_byte = 0; l_byte < l_max_byte; l_byte++) { //Nibble loop for(l_nibble = 0; l_nibble < MAX_NIBBLES; l_nibble++) { if(iv_dmm_type == 1) { i_input_index_u8 = 8 * l_byte + 4 * l_nibble; FAPI_TRY(rosetta_map(i_target, l_p, l_input_type_e, i_input_index_u8, 0, l_val)); l_byte_is = l_val / 8; l_nibble_is = l_val % 8; if(l_nibble_is > 3) { l_nibble_is = 1; } else { l_nibble_is = 0; } if( iv_mcbist_error_map [l_p][rank][l_byte_is][l_nibble_is] == 1) { iv_shmoo_error_map[l_p][rank][l_n] = 1; pass = 1; } else { iv_shmoo_error_map[l_p][rank][l_n] = 0; pass = 0; } } else { if( iv_mcbist_error_map [l_p][rank][l_byte][l_nibble] == 1) { iv_shmoo_error_map[l_p][rank][l_n] = 1; pass = 1; } else { iv_shmoo_error_map[l_p][rank][l_n] = 0; pass = 0; } } l_n++; }//end of nibble loop }//end byte loop }//end rank loop fapi_try_exit: return fapi2::current_err; } /// /// @brief used by do_mcbist_test to check the error map for particular nibble /// @param[in] i_target Centaur input MBA /// @param[in] l_p Centaur input port /// @param[out] pass 1 = error found in mcb_error_map /// @return FAPI2_RC_SUCCESS iff successful /// fapi2::ReturnCode generic_shmoo::check_error_map2(const fapi2::Target& i_target, uint8_t port, uint8_t& pass) { uint8_t l_byte, l_rnk = 0; uint8_t l_nibble = 0; uint8_t l_byte_is = 0; uint8_t l_nibble_is = 0; uint8_t l_n = 0; pass = 1; uint8_t l_p = 0; input_type l_input_type_e = ISDIMM_DQ; uint8_t i_input_index_u8 = 0; uint8_t l_val = 0; uint8_t rank = 0; uint8_t l_max_byte = 10; uint8_t l_max_nibble = 20; uint8_t l_CDarray0[80] = {0}; uint8_t l_CDarray1[80] = {0}; if(iv_dmm_type == 1) { l_max_byte = 9; l_max_nibble = 18; } FAPI_TRY(mcb_error_map(i_target, iv_mcbist_error_map, l_CDarray0, l_CDarray1, iv_count_bad_dq), "generic_shmoo::do_mcbist_test: mcb_error_map failed!!"); for (l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rnk = 0; l_rnk < iv_MAX_RANKS[l_p]; l_rnk++) { rank = iv_valid_rank[l_p][l_rnk]; l_n = 0; // Byte loop for(l_byte = 0; l_byte < l_max_byte; l_byte++) { //Nibble loop for(l_nibble = 0; l_nibble < MAX_NIBBLES; l_nibble++) { if(iv_dmm_type == 1) { i_input_index_u8 = BITS_PER_BYTE * l_byte + BITS_PER_NIBBLE * l_nibble; FAPI_TRY(rosetta_map(i_target, l_p, l_input_type_e, i_input_index_u8, 0, l_val)); l_byte_is = l_val / BITS_PER_BYTE; l_nibble_is = l_val % BITS_PER_BYTE; if(l_nibble_is > 3) { l_nibble_is = 1; } else { l_nibble_is = 0; } if( iv_mcbist_error_map [l_p][rank][l_byte_is][l_nibble_is] == 1) { //pass=0; iv_shmoo_error_map[l_p][rank][l_n] = 1; } else { iv_shmoo_error_map[l_p][rank][l_n] = 0; } } else { if( iv_mcbist_error_map [l_p][rank][l_byte][l_nibble] == 1) { //pass=0; iv_shmoo_error_map[l_p][rank][l_n] = 1; //FAPI_INF("We are in error and nibble is %d and rank is %d and port is %d \n",l_n,rank,l_p); } else { iv_shmoo_error_map[l_p][rank][l_n] = 0; } } l_n++; } // for nibble } // for byte } // for rank } // for port for (l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rnk = 0; l_rnk < iv_MAX_RANKS[l_p]; l_rnk++) { // Byte loop rank = iv_valid_rank[l_p][l_rnk]; for (l_n = 0; l_n < l_max_nibble; l_n++) { if(iv_shmoo_error_map[l_p][rank][l_n] == 0) { pass = 0; } } } } fapi_try_exit: return fapi2::current_err; } /// /// @brief This function does the initialization of various schmoo parameters /// @param[in] i_init_val initial value to initialize to /// @param[out] io_array address of array /// void generic_shmoo::init_multi_array(const uint16_t i_init_val, uint16_t(&io_array)[MAX_DQ]) { uint8_t l_byte, l_nibble, l_bit = 0; uint8_t l_dq = 0; // Byte loop for (l_byte = 0; l_byte < iv_MAX_BYTES; l_byte++) { //Nibble loop for (l_nibble = 0; l_nibble < MAX_NIBBLES; l_nibble++) { //Bit loop for (l_bit = 0; l_bit < MAX_BITS; l_bit++) { l_dq = 8 * l_byte + 4 * l_nibble + l_bit; io_array[l_dq] = i_init_val; } } } } /// /// @brief set all bits /// @param[in] i_target Centaur input MBA /// @param[in] bound RIGHT/LEFT /// @return FAPI2_RC_SUCCESS iff successful /// fapi2::ReturnCode generic_shmoo::set_all_binary(const fapi2::Target& i_target, const bound_t bound) { uint8_t l_rnk, l_byte, l_nibble, l_bit = 0; uint8_t l_dq = 0; uint8_t l_p = 0; uint32_t l_max = 512; uint32_t l_max_offset = 64; uint8_t rank = 0; //if RD_EYE if(iv_shmoo_type == 8) { l_max = 127; } for (l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rnk = 0; l_rnk < iv_MAX_RANKS[l_p]; l_rnk++) { rank = iv_valid_rank[l_p][l_rnk]; for(l_byte = 0; l_byte < iv_MAX_BYTES; l_byte++) { for(l_nibble = 0; l_nibble < MAX_NIBBLES; l_nibble++) { for(l_bit = 0; l_bit < MAX_BITS; l_bit++) { l_dq = (BITS_PER_BYTE * l_byte) + (BITS_PER_NIBBLE * l_nibble) + l_bit; SHMOO.MBA.P[l_p].S[rank].K.last_pass[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq]; SHMOO.MBA.P[l_p].S[rank].K.curr_val[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq]; if(bound == RIGHT) { if((SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] + l_max_offset) > l_max) { SHMOO.MBA.P[l_p].S[rank].K.last_fail[l_dq] = l_max; } else { SHMOO.MBA.P[l_p].S[rank].K.last_fail[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] + l_max_offset; } } else { if(SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] > 64) { SHMOO.MBA.P[l_p].S[rank].K.last_fail[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] - l_max_offset; } else { SHMOO.MBA.P[l_p].S[rank].K.last_fail[l_dq] = 0; } } } // bit loop } // nibble loop } // byte loop } // rank loop } // port loop return fapi2::FAPI2_RC_SUCCESS; } /// /// @brief This function gets the nominal values for each DQ /// @param[in] i_target Centaur input MBA /// @return FAPI2_RC_SUCCESS iff successful /// fapi2::ReturnCode generic_shmoo::get_all_noms(const fapi2::Target& i_target) { uint8_t l_rnk, l_byte, l_nibble, l_bit = 0; uint8_t i_rnk = 0; uint16_t val = 0; uint8_t l_dq = 0; uint8_t l_p = 0; input_type_t l_input_type_e = WR_DQ; access_type_t l_access_type_e = READ; FAPI_DBG("mss_generic_shmoo : get_all_noms : Reading in all nominal values"); if(iv_shmoo_type == 2) { l_input_type_e = WR_DQ; } else if(iv_shmoo_type == 8) { l_input_type_e = RD_DQ; } else if(iv_shmoo_type == 16) { l_input_type_e = RD_DQS; } for (l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rnk = 0; l_rnk < iv_MAX_RANKS[l_p]; l_rnk++) { // Byte loop i_rnk = iv_valid_rank[l_p][l_rnk]; for(l_byte = 0; l_byte < iv_MAX_BYTES; l_byte++) { //Nibble loop for(l_nibble = 0; l_nibble < MAX_NIBBLES; l_nibble++) { //Bit loop for(l_bit = 0; l_bit < MAX_BITS; l_bit++) { l_dq = 8 * l_byte + 4 * l_nibble + l_bit; FAPI_INF("Before access call"); FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, i_rnk, l_input_type_e, l_dq, 1, val)); SHMOO.MBA.P[l_p].S[i_rnk].K.nom_val[l_dq] = val; SHMOO.MBA.P[l_p].S[i_rnk].K.rb_regval[l_dq] = val; SHMOO.MBA.P[l_p].S[i_rnk].K.lb_regval[l_dq] = val; } } } } } FAPI_INF("get all noms done"); fapi_try_exit: return fapi2::current_err; } /// /// @brief Read in all nominal values /// @param[in] i_target Centaur input MBA /// @return FAPI2_RC_SUCCESS iff successful /// fapi2::ReturnCode generic_shmoo::get_all_noms_dqs(const fapi2::Target& i_target) { uint8_t l_rnk = 0; uint32_t val = 0; uint8_t l_p = 0; uint8_t l_max_nibble = 20; uint8_t rank = 0; uint8_t l_n = 0; FAPI_INF("%s:mss_generic_shmoo : get_all_noms_dqs : Reading in all nominal values and schmoo type=%d \n", mss::c_str(i_target), 1); if(iv_dmm_type == 1) { l_max_nibble = 18; } input_type_t l_input_type_e = WR_DQS; access_type_t l_access_type_e = READ ; FAPI_DBG("mss_generic_shmoo : get_all_noms : Reading in all nominal values"); for (l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rnk = 0; l_rnk < iv_MAX_RANKS[l_p]; l_rnk++) { rank = iv_valid_rank[l_p][l_rnk]; for (l_n = 0; l_n < l_max_nibble; l_n++) { FAPI_TRY(mss_access_delay_reg(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_n, 0, val)); iv_dqs_nom_val[l_p][rank][l_n] = val; } } } fapi_try_exit: return fapi2::current_err; } /// /// @brief This is a key function is used to find right and left bound using new algorithm -- there is an option u can chose not to use it by setting a flag /// @param[in] i_target Centaur input MBA Parameters: Target:MBA,bound:RIGHT/LEFT,scenario:type of schmoo,iv_port:0/1,rank:0-7,byte:0-7,nibble:0/1,bit:0-3,pass, /// @param[in] bound RIGHT/LEFT /// @param[in] scenario type of shmoo /// @param[in] bit 0-3 /// @param[in] pass /// @return FAPI2_RC_SUCCESS iff successful /// fapi2::ReturnCode generic_shmoo::knob_update(const fapi2::Target& i_target, const bound_t bound, const uint8_t scenario, const uint8_t bit, uint8_t pass) { fapi2::buffer data_buffer_64; fapi2::buffer data_buffer_64_1; input_type_t l_input_type_e = WR_DQ; uint8_t l_dq = 0; access_type_t l_access_type_e = WRITE; uint8_t l_n = 0; uint8_t l_i = 0; uint8_t l_p = 0; uint16_t l_delay = 0; uint16_t l_max_limit = 500; uint8_t rank = 0; uint8_t l_rank = 0; uint8_t l_SCHMOO_NIBBLES = 20; uint8_t l_CDarray0[CDIMM_MAX_DQ_80] = {0}; uint8_t l_CDarray1[CDIMM_MAX_DQ_80] = {0}; if(iv_dmm_type == 1) { l_SCHMOO_NIBBLES = 18; } //l_SCHMOO_NIBBLES = 2; //temp preet del this FAPI_TRY(do_mcbist_reset(i_target), "generic_shmoo::find_bound do_mcbist_reset failed"); FAPI_INF("Linear in Progress FW --> %d", scenario); if(iv_shmoo_type == 2) { l_input_type_e = WR_DQ; } else if(iv_shmoo_type == 8) { l_input_type_e = RD_DQ; l_max_limit = 127; } else if(iv_shmoo_type == 4) { l_input_type_e = WR_DQS; } for (l_p = 0; l_p < 2; l_p++) { for(uint8_t i = 0; i < iv_MAX_RANKS[l_p]; i++) { rank = iv_valid_rank[l_p][i]; for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { iv_shmoo_error_map[l_p][rank][l_n] = 0; } } } if(bound == RIGHT) { for (l_delay = 1; ((pass == 0)); l_delay = l_delay + 1) { for (l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rank = 0; l_rank < iv_MAX_RANKS[l_p]; l_rank++) { l_dq = bit; rank = iv_valid_rank[l_p][l_rank]; for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { if(iv_shmoo_error_map[l_p][rank][l_n] == 0) { SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] + l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 1, SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq])); } FAPI_TRY(mcb_error_map(i_target, iv_mcbist_error_map, l_CDarray0, l_CDarray1, iv_count_bad_dq)); if(l_p == 0) { for(l_i = 0; l_i < iv_count_bad_dq[0]; l_i++) { if(l_CDarray0[l_i] == l_dq) { iv_shmoo_error_map[l_p][rank][l_n] = 1; } } } else { for(l_i = 0; l_i < iv_count_bad_dq[1]; l_i++) { if(l_CDarray1[l_i] == l_dq) { iv_shmoo_error_map[l_p][rank][l_n] = 1; } } } if(SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq] > l_max_limit) { iv_shmoo_error_map[l_p][rank][l_n] = 1; } l_dq = l_dq + 4; } //end of nibble } //end of rank } //end of port loop FAPI_TRY(do_mcbist_test(i_target), "generic_shmoo::find_bound do_mcbist_test failed"); FAPI_TRY(check_error_map2(i_target, l_p, pass), "generic_shmoo::find_bound do_mcbist_test failed"); if (l_delay > 35) { break; } } //end of Delay loop; for (l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rank = 0; l_rank < iv_MAX_RANKS[l_p]; l_rank++) { l_dq = bit; rank = iv_valid_rank[l_p][l_rank]; for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 1, SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq])); l_dq = l_dq + 4; } } } } if(bound == LEFT) { for (l_delay = 1; (pass == 0); l_delay += 1) { for (l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rank = 0; l_rank < iv_MAX_RANKS[l_p]; l_rank++) { l_dq = bit; rank = iv_valid_rank[l_p][l_rank]; for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { if(iv_shmoo_error_map[l_p][rank][l_n] == 0) { SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] - l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq])); } FAPI_TRY(mcb_error_map(i_target, iv_mcbist_error_map, l_CDarray0, l_CDarray1, iv_count_bad_dq)); if(l_p == 0) { for(l_i = 0; l_i < iv_count_bad_dq[0]; l_i++) { if(l_CDarray0[l_i] == l_dq) { iv_shmoo_error_map[l_p][rank][l_n] = 1; } } } else { for(l_i = 0; l_i < iv_count_bad_dq[1]; l_i++) { if(l_CDarray1[l_i] == l_dq) { iv_shmoo_error_map[l_p][rank][l_n] = 1; } } } if(SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq] == 0) { iv_shmoo_error_map[l_p][rank][l_n] = 1; } l_dq = l_dq + 4; } } } FAPI_TRY(do_mcbist_test(i_target), "generic_shmoo::find_bound do_mcbist_test failed"); FAPI_TRY(check_error_map2(i_target, l_p, pass), "generic_shmoo::find_bound do_mcbist_test failed"); if (l_delay > 35) { break; } } for (l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rank = 0; l_rank < iv_MAX_RANKS[l_p]; l_rank++) { l_dq = bit; rank = iv_valid_rank[l_p][l_rank]; for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq])); l_dq = l_dq + 4; } } } } fapi_try_exit: return fapi2::current_err; } /// /// @brief used to find right and left bound /// @param[in] i_target Centaur input MBA /// @param[in] bound RIGHT/LEFT /// @param[in] scenario type of shmoo /// @param[in] bit 0-3 /// @param[in] pass /// @return FAPI2_RC_SUCCESS iff successful /// fapi2::ReturnCode generic_shmoo::knob_update_bin(const fapi2::Target& i_target, const bound_t bound, const uint8_t scenario, const uint8_t bit, uint8_t pass) { fapi2::buffer data_buffer_64; fapi2::buffer data_buffer_64_1; input_type_t l_input_type_e = WR_DQ; uint8_t l_dq = 0; access_type_t l_access_type_e = WRITE; uint8_t l_n = 0; uint8_t l_i = 0; uint8_t l_flag_p0 = 0; uint8_t l_flag_p1 = 0; FAPI_INF("Inside - Binary Schmoo FW - %d", scenario); uint8_t l_p = 0; uint8_t rank = 0; uint8_t l_rank = 0; uint8_t l_SCHMOO_NIBBLES = 20; uint8_t l_status = 1; uint8_t l_CDarray0[80] = {0}; uint8_t l_CDarray1[80] = {0}; int count_cycle = 0; if(iv_dmm_type == 1) { l_SCHMOO_NIBBLES = 18; } if(iv_shmoo_type == 2) { l_input_type_e = WR_DQ; } else if(iv_shmoo_type == 8) { l_input_type_e = RD_DQ; } else if(iv_shmoo_type == 4) { l_input_type_e = WR_DQS; } else if(iv_shmoo_type == 16) { l_input_type_e = RD_DQS; } FAPI_TRY(do_mcbist_reset(i_target), "generic_shmoo::find_bound do_mcbist_reset failed"); //Reset iv_shmoo_error_map for(l_p = 0; l_p < MAX_PORT; l_p++) { for(uint8_t i = 0; i < iv_MAX_RANKS[l_p]; i++) { rank = iv_valid_rank[l_p][i]; for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { iv_shmoo_error_map[l_p][rank][l_n] = 0; iv_binary_done_map[l_p][rank][l_n] = 0; } } } if(bound == RIGHT) { for(l_p = 0; l_p < MAX_PORT; l_p++) { do { l_status = 0; FAPI_TRY(mcb_error_map(i_target, iv_mcbist_error_map, l_CDarray0, l_CDarray1, iv_count_bad_dq)); for (l_rank = 0; l_rank < iv_MAX_RANKS[l_p]; l_rank++) { l_dq = bit; rank = iv_valid_rank[l_p][l_rank]; for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { if(iv_binary_done_map[l_p][rank][l_n] == 0) { l_status = 1; } l_flag_p0 = 0; l_flag_p1 = 0; if(l_p == 0) { for(l_i = 0; l_i < iv_count_bad_dq[0]; l_i++) { if(l_CDarray0[l_i] == l_dq) { iv_shmoo_error_map[l_p][rank][l_n] = 1; l_flag_p0 = 1; } } } else { for(l_i = 0; l_i < iv_count_bad_dq[1]; l_i++) { if(l_CDarray1[l_i] == l_dq) { iv_shmoo_error_map[l_p][rank][l_n] = 1; l_flag_p1 = 1; } } } if(iv_shmoo_error_map[l_p][rank][l_n] == 0) { SHMOO.MBA.P[l_p].S[rank].K.last_pass[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.curr_val[l_dq]; SHMOO.MBA.P[l_p].S[rank].K.curr_val[l_dq] = (SHMOO.MBA.P[l_p].S[rank].K.last_pass[l_dq] + SHMOO.MBA.P[l_p].S[rank].K.last_fail[l_dq]) / 2; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.curr_val[l_dq])); auto l_curr_diff = absolute_difference(SHMOO.MBA.P[l_p].S[rank].K.last_pass[l_dq], SHMOO.MBA.P[l_p].S[rank].K.last_fail[l_dq]); if(l_curr_diff <= 1) { iv_binary_done_map[l_p][rank][l_n] = 1; SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.last_fail[l_dq]; } } else { SHMOO.MBA.P[l_p].S[rank].K.last_fail[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.curr_val[l_dq]; SHMOO.MBA.P[l_p].S[rank].K.curr_val[l_dq] = (SHMOO.MBA.P[l_p].S[rank].K.last_pass[l_dq] + SHMOO.MBA.P[l_p].S[rank].K.last_fail[l_dq]) / 2; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.curr_val[l_dq])); uint16_t l_curr_diff = absolute_difference(SHMOO.MBA.P[l_p].S[rank].K.last_pass[l_dq], SHMOO.MBA.P[l_p].S[rank].K.last_fail[l_dq]); if(l_p == 0) { if(l_flag_p0 == 1) { l_curr_diff = 1; } } else { if(l_flag_p1 == 1) { l_curr_diff = 1; } } if(l_curr_diff <= 1) { iv_binary_done_map[l_p][rank][l_n] = 1; SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.last_fail[l_dq]; } } l_dq = l_dq + 4; } } FAPI_TRY(do_mcbist_reset(i_target), "generic_shmoo::find_bound do_mcbist_reset failed"); FAPI_TRY(do_mcbist_test(i_target), "generic_shmoo::find_bound do_mcbist_test failed"); FAPI_TRY(check_error_map(i_target, l_p, pass), "generic_shmoo::find_bound do_mcbist_test failed"); count_cycle++; } while(l_status == 1); } for(l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rank = 0; l_rank < iv_MAX_RANKS[l_p]; l_rank++) { l_dq = bit; ////// rank = iv_valid_rank[l_p][l_rank]; for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq])); l_dq = l_dq + 4; } } } } count_cycle = 0; if(bound == LEFT) { for(l_p = 0; l_p < MAX_PORT; l_p++) { l_status = 1; while(l_status == 1) { l_status = 0; FAPI_TRY(mcb_error_map(i_target, iv_mcbist_error_map, l_CDarray0, l_CDarray1, iv_count_bad_dq)); for (l_rank = 0; l_rank < iv_MAX_RANKS[l_p]; l_rank++) { l_dq = bit; ////// rank = iv_valid_rank[l_p][l_rank]; for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { if(iv_binary_done_map[l_p][rank][l_n] == 0) { l_status = 1; } l_flag_p0 = 0; l_flag_p1 = 0; if(l_p == 0) { for(l_i = 0; l_i < iv_count_bad_dq[0]; l_i++) { if(l_CDarray0[l_i] == l_dq) { iv_shmoo_error_map[l_p][rank][l_n] = 1; l_flag_p0 = 1; } } } else { for(l_i = 0; l_i < iv_count_bad_dq[1]; l_i++) { if(l_CDarray1[l_i] == l_dq) { iv_shmoo_error_map[l_p][rank][l_n] = 1; l_flag_p1 = 1; } } } if(iv_shmoo_error_map[l_p][rank][l_n] == 0) { SHMOO.MBA.P[l_p].S[rank].K.last_pass[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.curr_val[l_dq]; SHMOO.MBA.P[l_p].S[rank].K.curr_val[l_dq] = (SHMOO.MBA.P[l_p].S[rank].K.last_pass[l_dq] + SHMOO.MBA.P[l_p].S[rank].K.last_fail[l_dq]) / 2; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.curr_val[l_dq])); uint16_t l_curr_diff = absolute_difference(SHMOO.MBA.P[l_p].S[rank].K.last_pass[l_dq], SHMOO.MBA.P[l_p].S[rank].K.last_fail[l_dq]); if(l_curr_diff <= 1) { iv_binary_done_map[l_p][rank][l_n] = 1; SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.last_fail[l_dq]; } } else { SHMOO.MBA.P[l_p].S[rank].K.last_fail[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.curr_val[l_dq]; SHMOO.MBA.P[l_p].S[rank].K.curr_val[l_dq] = (SHMOO.MBA.P[l_p].S[rank].K.last_pass[l_dq] + SHMOO.MBA.P[l_p].S[rank].K.last_fail[l_dq]) / 2; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.curr_val[l_dq])); uint16_t l_curr_diff = absolute_difference(SHMOO.MBA.P[l_p].S[rank].K.last_pass[l_dq], SHMOO.MBA.P[l_p].S[rank].K.last_fail[l_dq]); if(l_p == 0) { if(l_flag_p0 == 1) { l_curr_diff = 1; } } else { if(l_flag_p1 == 1) { l_curr_diff = 1; } } if(l_curr_diff <= 1) { iv_binary_done_map[l_p][rank][l_n] = 1; SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.last_fail[l_dq]; } } l_dq = l_dq + 4; } } FAPI_TRY(do_mcbist_reset(i_target), "generic_shmoo::find_bound do_mcbist_reset failed"); FAPI_TRY(do_mcbist_test(i_target), "generic_shmoo::find_bound do_mcbist_test failed"); FAPI_TRY(check_error_map(i_target, l_p, pass), "generic_shmoo::find_bound do_mcbist_test failed"); count_cycle++; } } for(l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rank = 0; l_rank < iv_MAX_RANKS[l_p]; l_rank++) { l_dq = bit; ////// rank = iv_valid_rank[l_p][l_rank]; //printf("Valid rank of %d %d %d %d %d %d %d %d",iv_valid_rank[0],iv_valid_rank[1],iv_valid_rank[2],iv_valid_rank[3],iv_valid_rank[4],iv_valid_rank[5],iv_valid_rank[6],iv_valid_rank[7]); for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq])); l_dq = l_dq + 4; } } } } // End of LEFT fapi_try_exit: return fapi2::current_err; } /// /// @brief used to find right and left bound /// @param[in] i_target Centaur input MBA /// @param[in] bound RIGHT/LEFT /// @param[in] scenario type of shmoo /// @param[in] bit 0-3 /// @param[in] pass /// @return FAPI2_RC_SUCCESS iff successful /// fapi2::ReturnCode generic_shmoo::knob_update_dqs_by4(const fapi2::Target& i_target, const bound_t bound, const uint8_t scenario, const uint8_t bit, uint8_t pass) { fapi2::buffer data_buffer_64; fapi2::buffer data_buffer_64_1; input_type_t l_input_type_e = WR_DQ; input_type_t l_input_type_e_dqs = WR_DQS; uint8_t l_dq = 0; access_type_t l_access_type_e = WRITE; uint8_t l_n = 0; uint8_t l_p = 0; uint8_t l_i = 0; uint16_t l_delay = 0; uint16_t l_max_limit = 500; uint8_t rank = 0; uint8_t l_rank = 0; uint8_t l_SCHMOO_NIBBLES = 20; uint8_t l_CDarray0[80] = {0}; uint8_t l_CDarray1[80] = {0}; FAPI_INF("\nWRT_DQS --- > CDIMM X4 - Scenario = %d", scenario); FAPI_TRY(do_mcbist_test(i_target), "generic_shmoo::find_bound do_mcbist_test failed"); FAPI_TRY(mcb_error_map(i_target, iv_mcbist_error_map, l_CDarray0, l_CDarray1, iv_count_bad_dq), "generic_shmoo::do_mcbist_test: ecb_error_map failed!!"); if(iv_dmm_type == 1) { l_SCHMOO_NIBBLES = 18; } for (l_p = 0; l_p < MAX_PORT; l_p++) { for(uint8_t i = 0; i < iv_MAX_RANKS[l_p]; i++) { rank = iv_valid_rank[l_p][i]; for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { iv_shmoo_error_map[l_p][rank][l_n] = 0; } } } if(bound == RIGHT) { for (l_delay = 1; ((pass == 0)); l_delay++) { for (l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rank = 0; l_rank < iv_MAX_RANKS[l_p]; l_rank++) { l_dq = 0; rank = iv_valid_rank[l_p][l_rank]; for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { l_dq = 4 * l_n; if(l_p == 0) { for(l_i = 0; l_i < iv_count_bad_dq[0]; l_i++) { if(l_CDarray0[l_i] == l_dq) { iv_shmoo_error_map[l_p][rank][l_n] = 1; } } } else { for(l_i = 0; l_i < iv_count_bad_dq[1]; l_i++) { if(l_CDarray1[l_i] == l_dq) { iv_shmoo_error_map[l_p][rank][l_n] = 1; } } } if(iv_shmoo_error_map[l_p][rank][l_n] == 0) { iv_dqs_rb_regval[l_p][rank][l_n] = iv_dqs_nom_val[l_p][rank][l_n] + l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e_dqs, l_n, 0, iv_dqs_rb_regval[l_p][rank][l_n])); SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] + l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq])); l_dq = l_dq + 1; SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] + l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq])); l_dq = l_dq + 1; SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] + l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq])); l_dq = l_dq + 1; SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] + l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq])); } if(iv_dqs_rb_regval[l_p][rank][l_dq] > l_max_limit) { iv_shmoo_error_map[l_p][rank][l_n] = 1; } } // for nibble } // for rank } // for port FAPI_TRY(do_mcbist_test(i_target), "generic_shmoo::find_bound do_mcbist_test failed"); FAPI_TRY(check_error_map2(i_target, l_p, pass), "generic_shmoo::find_bound do_mcbist_test failed"); if (l_delay > 70) { break; } } //end of delay for (l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rank = 0; l_rank < iv_MAX_RANKS[l_p]; l_rank++) { rank = iv_valid_rank[l_p][l_rank]; for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e_dqs, l_n, 0, iv_dqs_nom_val[l_p][rank][l_n])); } } } for(uint8_t l_bit = 0; l_bit < 4; l_bit++) { for (l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rank = 0; l_rank < iv_MAX_RANKS[l_p]; l_rank++) { l_dq = l_bit; rank = iv_valid_rank[l_p][l_rank]; for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq])); l_dq = l_dq + 4; } } } } FAPI_TRY(do_mcbist_test(i_target), "generic_shmoo::find_bound do_mcbist_test failed"); FAPI_TRY(mcb_error_map(i_target, iv_mcbist_error_map, l_CDarray0, l_CDarray1, iv_count_bad_dq), "generic_shmoo::do_mcbist_test: mcb_error_map failed!!"); } // end bound == right if(bound == LEFT) { for (l_delay = 1; (pass == 0); l_delay++) { for (l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rank = 0; l_rank < iv_MAX_RANKS[l_p]; l_rank++) { l_dq = 0; rank = iv_valid_rank[l_p][l_rank]; for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { l_dq = 4 * l_n; if(l_p == 0) { for(l_i = 0; l_i < iv_count_bad_dq[0]; l_i++) { if(l_CDarray0[l_i] == l_dq) { iv_shmoo_error_map[l_p][rank][l_n] = 1; } } } else { for(l_i = 0; l_i < iv_count_bad_dq[1]; l_i++) { if(l_CDarray1[l_i] == l_dq) { iv_shmoo_error_map[l_p][rank][l_n] = 1; } } } if(iv_shmoo_error_map[l_p][rank][l_n] == 0) { iv_dqs_lb_regval[l_p][rank][l_n] = iv_dqs_nom_val[l_p][rank][l_n] - l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e_dqs, l_n, 0, iv_dqs_lb_regval[l_p][rank][l_n])); SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] - l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq])); l_dq = l_dq + 1; SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] - l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq])); l_dq = l_dq + 1; SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] - l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq])); l_dq = l_dq + 1; SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] - l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq])); } if(iv_dqs_lb_regval[l_p][rank][l_n] == 0) { iv_shmoo_error_map[l_p][rank][l_n] = 1; } } } } FAPI_TRY(do_mcbist_test(i_target), "generic_shmoo::find_bound do_mcbist_test failed"); FAPI_TRY(check_error_map2(i_target, l_p, pass), "generic_shmoo::find_bound do_mcbist_test failed"); if (l_delay > 70) { break; } } for (l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rank = 0; l_rank < iv_MAX_RANKS[l_p]; l_rank++) { rank = iv_valid_rank[l_p][l_rank]; for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e_dqs, l_n, 0, iv_dqs_nom_val[l_p][rank][l_n])); } } } for(uint8_t l_bit = 0; l_bit < 4; l_bit++) { for (l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rank = 0; l_rank < iv_MAX_RANKS[l_p]; l_rank++) { l_dq = l_bit; rank = iv_valid_rank[l_p][l_rank]; for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq])); l_dq = l_dq + 4; } } } } FAPI_TRY(do_mcbist_test(i_target), "generic_shmoo::find_bound do_mcbist_test failed"); FAPI_TRY(mcb_error_map(i_target, iv_mcbist_error_map, l_CDarray0, l_CDarray1, iv_count_bad_dq), "generic_shmoo::do_mcbist_test: mcb_error_map failed!!"); } fapi_try_exit: return fapi2::current_err; } /// /// @brief used to find right and left bound /// @param[in] i_target Centaur input MBA /// @param[in] bound RIGHT/LEFT /// @param[in] scenario type of shmoo /// @param[in] bit 0-3 /// @param[in] pass /// @return FAPI2_RC_SUCCESS iff successful /// fapi2::ReturnCode generic_shmoo::knob_update_dqs_by4_isdimm(const fapi2::Target& i_target, const bound_t bound, const uint8_t scenario, const uint8_t bit, uint8_t pass) { fapi2::buffer data_buffer_64; fapi2::buffer data_buffer_64_1; input_type_t l_input_type_e = WR_DQ; input_type_t l_input_type_e_dqs = WR_DQS; uint8_t l_dq = 0; access_type_t l_access_type_e = WRITE; uint8_t l_n = 0; uint8_t l_my_dqs = 0; uint8_t l_CDarray0[80] = {0}; uint8_t l_CDarray1[80] = {0}; uint8_t l_p = 0; uint16_t l_delay = 0; uint16_t l_max_limit = 500; uint8_t rank = 0; uint8_t l_rank = 0; uint8_t l_SCHMOO_NIBBLES = 20; uint8_t l_dqs_arr[18] = {0, 9, 1, 10, 2, 11, 3, 12, 4, 13, 5, 14, 6, 15, 7, 16, 8, 17}; FAPI_TRY(do_mcbist_test(i_target), "generic_shmoo::find_bound do_mcbist_test failed"); FAPI_TRY(mcb_error_map(i_target, iv_mcbist_error_map, l_CDarray0, l_CDarray1, iv_count_bad_dq), "generic_shmoo::do_mcbist_test: mcb_error_map failed!!"); if(iv_dmm_type == 1) { l_SCHMOO_NIBBLES = 18; } for (l_p = 0; l_p < MAX_PORT; l_p++) { for(uint8_t i = 0; i < iv_MAX_RANKS[l_p]; i++) { rank = iv_valid_rank[l_p][i]; for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { iv_shmoo_error_map[l_p][rank][l_n] = 0; } } } if(bound == RIGHT) { for (l_delay = 1; ((pass == 0)); l_delay++) { for (l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rank = 0; l_rank < iv_MAX_RANKS[l_p]; l_rank++) { l_dq = 0; l_my_dqs = 0; rank = iv_valid_rank[l_p][l_rank]; for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { l_dq = 4 * l_n; l_my_dqs = l_dqs_arr[l_n]; if(iv_shmoo_error_map[l_p][rank][l_n] == 0) { iv_dqs_rb_regval[l_p][rank][l_my_dqs] = iv_dqs_nom_val[l_p][rank][l_my_dqs] + l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e_dqs, l_my_dqs, 0, iv_dqs_rb_regval[l_p][rank][l_my_dqs])); SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] + l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq])); l_dq = l_dq + 1; SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] + l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq])); l_dq = l_dq + 1; SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] + l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq])); l_dq = l_dq + 1; SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] + l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq])); } if(iv_dqs_rb_regval[l_p][rank][l_dq] > l_max_limit) { iv_shmoo_error_map[l_p][rank][l_n] = 1; } } //end of nibble loop } //end of rank } //end of port FAPI_TRY(do_mcbist_test(i_target), "generic_shmoo::find_bound do_mcbist_test failed"); FAPI_TRY(check_error_map2(i_target, l_p, pass), "generic_shmoo::find_bound do_mcbist_test failed"); if (l_delay > 70) { break; } } //end of delay loop for (l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rank = 0; l_rank < iv_MAX_RANKS[l_p]; l_rank++) { rank = iv_valid_rank[l_p][l_rank]; for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e_dqs, l_n, 0, iv_dqs_nom_val[l_p][rank][l_n])); } } } for(uint8_t l_bit = 0; l_bit < 4; l_bit++) { for (l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rank = 0; l_rank < iv_MAX_RANKS[l_p]; l_rank++) { l_dq = l_bit; rank = iv_valid_rank[l_p][l_rank]; for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq])); l_dq = l_dq + 4; } } //end of rank } //end of port } //end of bit FAPI_TRY(do_mcbist_test(i_target), "generic_shmoo::find_bound do_mcbist_test failed"); FAPI_TRY(mcb_error_map(i_target, iv_mcbist_error_map, l_CDarray0, l_CDarray1, iv_count_bad_dq), "generic_shmoo::do_mcbist_test: mcb_error_map failed!!"); } if(bound == LEFT) { for (l_delay = 1; (pass == 0); l_delay++) { for (l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rank = 0; l_rank < iv_MAX_RANKS[l_p]; l_rank++) { l_dq = 0; l_my_dqs = 0; rank = iv_valid_rank[l_p][l_rank]; for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { l_dq = 4 * l_n; l_my_dqs = l_dqs_arr[l_n]; if(iv_shmoo_error_map[l_p][rank][l_n] == 0) { iv_dqs_lb_regval[l_p][rank][l_my_dqs] = iv_dqs_nom_val[l_p][rank][l_my_dqs] - l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e_dqs, l_my_dqs, 0, iv_dqs_lb_regval[l_p][rank][l_my_dqs])); SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] - l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq])); l_dq = l_dq + 1; SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] - l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq])); l_dq = l_dq + 1; SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] - l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq])); l_dq = l_dq + 1; SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] - l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq])); } if(iv_dqs_lb_regval[l_p][rank][l_dq] == 0) { iv_shmoo_error_map[l_p][rank][l_n] = 1; } } } } FAPI_TRY(do_mcbist_test(i_target), "generic_shmoo::find_bound do_mcbist_test failed"); FAPI_TRY(check_error_map2(i_target, l_p, pass), "generic_shmoo::find_bound do_mcbist_test failed"); if (l_delay > 70) { break; } } //end of delay loop for (l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rank = 0; l_rank < iv_MAX_RANKS[l_p]; l_rank++) { rank = iv_valid_rank[l_p][l_rank]; for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e_dqs, l_n, 0, iv_dqs_nom_val[l_p][rank][l_n])); } } } for(uint8_t l_bit = 0; l_bit < 4; l_bit++) { for (l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rank = 0; l_rank < iv_MAX_RANKS[l_p]; l_rank++) { l_dq = l_bit; rank = iv_valid_rank[l_p][l_rank]; for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq])); l_dq = l_dq + 4; } //end of nibble } //end of rank } //port loop } //bit loop FAPI_TRY(do_mcbist_test(i_target), "generic_shmoo::find_bound do_mcbist_test failed"); FAPI_TRY(mcb_error_map(i_target, iv_mcbist_error_map, l_CDarray0, l_CDarray1, iv_count_bad_dq), "generic_shmoo::do_mcbist_test: mcb_error_map failed!!"); } //end of Left fapi_try_exit: return fapi2::current_err; } /// /// @brief used to find right and left bound /// @param[in] i_target Centaur input MBA /// @param[in] bound RIGHT/LEFT /// @param[in] scenario type of shmoo /// @param[in] bit 0-3 /// @param[in] pass /// @return FAPI2_RC_SUCCESS iff successful /// fapi2::ReturnCode generic_shmoo::knob_update_dqs_by8(const fapi2::Target& i_target, const bound_t bound, const uint8_t scenario, const uint8_t bit, uint8_t pass) { fapi2::buffer data_buffer_64(64); fapi2::buffer data_buffer_64_1(64); //uint8_t l_rp=0; input_type_t l_input_type_e = WR_DQ; input_type_t l_input_type_e_dqs = WR_DQS; uint8_t l_dq = 0; uint8_t l_dqs = 0; access_type_t l_access_type_e = WRITE; uint8_t l_n = 0; uint8_t l_CDarray0[80] = {0}; uint8_t l_CDarray1[80] = {0}; uint8_t l_p = 0; uint16_t l_delay = 0; uint16_t l_max_limit = 500; uint8_t rank = 0; uint8_t l_rank = 0; uint8_t l_SCHMOO_NIBBLES = 20; FAPI_INF("\nWRT_DQS --- > CDIMM X8 - Scenario = %d", scenario); FAPI_TRY(do_mcbist_test(i_target), "generic_shmoo::find_bound do_mcbist_test failed"); FAPI_TRY(mcb_error_map(i_target, iv_mcbist_error_map, l_CDarray0, l_CDarray1, iv_count_bad_dq), "generic_shmoo::do_mcbist_test: mcb_error_map failed!!"); if(iv_dmm_type == 1) { l_SCHMOO_NIBBLES = 18; } for (l_p = 0; l_p < MAX_PORT; l_p++) { for(uint8_t i = 0; i < iv_MAX_RANKS[l_p]; i++) { rank = iv_valid_rank[l_p][i]; for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { iv_shmoo_error_map[l_p][rank][l_n] = 0; } //end of nib } //end of rank } //end of port loop if(bound == RIGHT) { for (l_delay = 1; ((pass == 0)); l_delay++) { for (l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rank = 0; l_rank < iv_MAX_RANKS[l_p]; l_rank++) { l_dq = 0; l_dqs = 0; rank = iv_valid_rank[l_p][l_rank]; for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { l_dq = 4 * l_n; if((iv_shmoo_error_map[l_p][rank][l_n] == 0) && (iv_shmoo_error_map[l_p][rank][l_n + 1] == 0)) { //Increase delay of DQS iv_dqs_rb_regval[l_p][rank][l_n] = iv_dqs_nom_val[l_p][rank][l_n] + l_delay; //Write it to register DQS delay FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e_dqs, l_n, 0, iv_dqs_rb_regval[l_p][rank][l_n])); //Increase Delay of DQ SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] + l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq])); l_dq = l_dq + 1; SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] + l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq])); l_dq = l_dq + 1; SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] + l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq])); l_dq = l_dq + 1; SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] + l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq])); l_dq = l_dq + 1; SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] + l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq])); l_dq = l_dq + 1; SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] + l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq])); l_dq = l_dq + 1; SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] + l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq])); l_dq = l_dq + 1; SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] + l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq])); } if(SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq] > l_max_limit) { iv_shmoo_error_map[l_p][rank][l_n] = 1; iv_shmoo_error_map[l_p][rank][l_n + 1] = 1; } if((iv_shmoo_error_map[l_p][rank][l_n] == 1) || (iv_shmoo_error_map[l_p][rank][l_n + 1] == 1)) { iv_shmoo_error_map[l_p][rank][l_n] = 1; iv_shmoo_error_map[l_p][rank][l_n + 1] = 1; } l_n = l_n + 1; l_dqs = l_dqs + 1; } //end of nibble loop } //end of rank loop } //end of port loop FAPI_TRY(do_mcbist_test(i_target), "generic_shmoo::find_bound do_mcbist_test failed"); FAPI_TRY(check_error_map2(i_target, l_p, pass), "generic_shmoo::find_bound do_mcbist_test failed"); if (l_delay > 70) { break; } } //end of delay loop for (l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rank = 0; l_rank < iv_MAX_RANKS[l_p]; l_rank++) { rank = iv_valid_rank[l_p][l_rank]; for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e_dqs, l_n, 0, iv_dqs_nom_val[l_p][rank][l_n])); } //end of nib } //end of rank } //end of port loop for(uint8_t l_bit = 0; l_bit < 4; l_bit++) { for (l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rank = 0; l_rank < iv_MAX_RANKS[l_p]; l_rank++) { l_dq = l_bit; rank = iv_valid_rank[l_p][l_rank]; for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq])); l_dq = l_dq + 4; } //end of nib } //end of rank } //end of port loop } //end of bit loop FAPI_TRY(do_mcbist_test(i_target), "generic_shmoo::find_bound do_mcbist_test failed"); FAPI_TRY(mcb_error_map(i_target, iv_mcbist_error_map, l_CDarray0, l_CDarray1, iv_count_bad_dq), "generic_shmoo::do_mcbist_test: mcb_error_map failed!!"); } if(bound == LEFT) { for (l_delay = 1; (pass == 0); l_delay++) { for (l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rank = 0; l_rank < iv_MAX_RANKS[l_p]; l_rank++) { l_dq = 0; l_dqs = 0; rank = iv_valid_rank[l_p][l_rank]; for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { l_dq = 4 * l_n; if((iv_shmoo_error_map[l_p][rank][l_n] == 0) && (iv_shmoo_error_map[l_p][rank][l_n + 1] == 0)) { iv_dqs_lb_regval[l_p][rank][l_n] = iv_dqs_nom_val[l_p][rank][l_n] - l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e_dqs, l_n, 0, iv_dqs_lb_regval[l_p][rank][l_n])); SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] - l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq])); l_dq = l_dq + 1; SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] - l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq])); l_dq = l_dq + 1; SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] - l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq])); l_dq = l_dq + 1; SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] - l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq])); l_dq = l_dq + 1; SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] - l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq])); l_dq = l_dq + 1; SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] - l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq])); l_dq = l_dq + 1; SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] - l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq])); l_dq = l_dq + 1; SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] - l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq])); } if(SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq] == 0) { iv_shmoo_error_map[l_p][rank][l_n] = 1; iv_shmoo_error_map[l_p][rank][l_n + 1] = 1; } if((iv_shmoo_error_map[l_p][rank][l_n] == 1) || (iv_shmoo_error_map[l_p][rank][l_n + 1] == 1)) { iv_shmoo_error_map[l_p][rank][l_n] = 1; iv_shmoo_error_map[l_p][rank][l_n + 1] = 1; } l_n = l_n + 1; l_dqs = l_dq + 1; } //nibble loop } //rank loop } //port loop FAPI_TRY(do_mcbist_test(i_target), "generic_shmoo::find_bound do_mcbist_test failed"); FAPI_TRY(check_error_map2(i_target, l_p, pass), "generic_shmoo::find_bound do_mcbist_test failed"); if (l_delay > 70) { break; } } //end of l delay loop for (l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rank = 0; l_rank < iv_MAX_RANKS[l_p]; l_rank++) { rank = iv_valid_rank[l_p][l_rank]; for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e_dqs, l_n, 0, iv_dqs_nom_val[l_p][rank][l_n])); } } } for(uint8_t l_bit = 0; l_bit < 4; l_bit++) { for (l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rank = 0; l_rank < iv_MAX_RANKS[l_p]; l_rank++) { l_dq = l_bit; rank = iv_valid_rank[l_p][l_rank]; for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq])); l_dq = l_dq + 4; } } } } FAPI_TRY(do_mcbist_test(i_target), "generic_shmoo::find_bound do_mcbist_test failed"); FAPI_TRY(mcb_error_map(i_target, iv_mcbist_error_map, l_CDarray0, l_CDarray1, iv_count_bad_dq), "generic_shmoo::do_mcbist_test: mcb_error_map failed!!"); } //end of bound Left fapi_try_exit: return fapi2::current_err; } /// /// @brief used to find right and left bound /// @param[in] i_target Centaur input MBA /// @param[in] bound RIGHT/LEFT /// @param[in] scenario type of shmoo /// @param[in] bit 0-3 /// @param[in] pass /// @return FAPI2_RC_SUCCESS iff successful /// fapi2::ReturnCode generic_shmoo::knob_update_dqs_by8_isdimm(const fapi2::Target& i_target, const bound_t bound, const uint8_t scenario, const uint8_t bit, uint8_t pass) { fapi2::buffer data_buffer_64; fapi2::buffer data_buffer_64_1; //uint8_t l_rp=0; input_type_t l_input_type_e = WR_DQ; input_type_t l_input_type_e_dqs = WR_DQS; uint8_t l_dq = 0; uint8_t l_dqs = 0; access_type_t l_access_type_e = WRITE; uint8_t l_n = 0; uint8_t l_CDarray0[80] = {0}; uint8_t l_CDarray1[80] = {0}; uint8_t l_p = 0; uint16_t l_delay = 0; uint16_t l_max_limit = 500; uint8_t rank = 0; uint8_t l_rank = 0; uint8_t l_SCHMOO_NIBBLES = 20; //uint8_t i_rp=0; FAPI_TRY(do_mcbist_test(i_target), "generic_shmoo::find_bound do_mcbist_test failed"); FAPI_TRY(mcb_error_map(i_target, iv_mcbist_error_map, l_CDarray0, l_CDarray1, iv_count_bad_dq), "generic_shmoo::do_mcbist_test: mcb_error_map failed!!"); if(iv_dmm_type == 1) { l_SCHMOO_NIBBLES = 18; } for (l_p = 0; l_p < MAX_PORT; l_p++) { for(uint8_t i = 0; i < iv_MAX_RANKS[l_p]; i++) { rank = iv_valid_rank[l_p][i]; for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { iv_shmoo_error_map[l_p][rank][l_n] = 0; } } } if(bound == RIGHT) { for (l_delay = 1; ((pass == 0)); l_delay++) { for (l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rank = 0; l_rank < iv_MAX_RANKS[l_p]; l_rank++) { l_dq = 0; l_dqs = 0; rank = iv_valid_rank[l_p][l_rank]; for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { l_dq = 4 * l_n; l_dqs = l_n / 2; if((iv_shmoo_error_map[l_p][rank][l_n] == 0) && (iv_shmoo_error_map[l_p][rank][l_n + 1] == 0)) { iv_dqs_rb_regval[l_p][rank][l_dqs] = iv_dqs_nom_val[l_p][rank][l_dqs] + l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e_dqs, l_dqs, 0, iv_dqs_rb_regval[l_p][rank][l_dqs])); SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] + l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq])); l_dq = l_dq + 1; SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] + l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq])); l_dq = l_dq + 1; SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] + l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq])); l_dq = l_dq + 1; SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] + l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq])); l_dq = l_dq + 1; SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] + l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq])); l_dq = l_dq + 1; SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] + l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq])); l_dq = l_dq + 1; SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] + l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq])); l_dq = l_dq + 1; SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] + l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq])); } if(iv_dqs_rb_regval[l_p][rank][l_dqs] > l_max_limit) { iv_shmoo_error_map[l_p][rank][l_n] = 1; iv_shmoo_error_map[l_p][rank][l_n + 1] = 1; } if((iv_shmoo_error_map[l_p][rank][l_n] == 1) || (iv_shmoo_error_map[l_p][rank][l_n + 1] == 1)) { iv_shmoo_error_map[l_p][rank][l_n] = 1; iv_shmoo_error_map[l_p][rank][l_n + 1] = 1; } l_n = l_n + 1; } } } FAPI_TRY(do_mcbist_test(i_target), "generic_shmoo::find_bound do_mcbist_test failed"); FAPI_TRY(check_error_map2(i_target, l_p, pass), "generic_shmoo::find_bound do_mcbist_test failed"); if (l_delay > 70) { break; } } for (l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rank = 0; l_rank < iv_MAX_RANKS[l_p]; l_rank++) { rank = iv_valid_rank[l_p][l_rank]; for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e_dqs, l_n, 0, iv_dqs_nom_val[l_p][rank][l_n])); } } } for(uint8_t l_bit = 0; l_bit < 4; l_bit++) { for (l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rank = 0; l_rank < iv_MAX_RANKS[l_p]; l_rank++) { l_dq = l_bit; rank = iv_valid_rank[l_p][l_rank]; for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq])); l_dq = l_dq + 4; } } } } FAPI_TRY(do_mcbist_test(i_target), "generic_shmoo::find_bound do_mcbist_test failed"); FAPI_TRY(mcb_error_map(i_target, iv_mcbist_error_map, l_CDarray0, l_CDarray1, iv_count_bad_dq), "generic_shmoo::do_mcbist_test: mcb_error_map failed!!"); } if(bound == LEFT) { for (l_delay = 1; (pass == 0); l_delay++) { for (l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rank = 0; l_rank < iv_MAX_RANKS[l_p]; l_rank++) { l_dq = 0; l_dqs = 0; rank = iv_valid_rank[l_p][l_rank]; for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { l_dq = 4 * l_n; l_dqs = l_n / 2; if((iv_shmoo_error_map[l_p][rank][l_n] == 0) && (iv_shmoo_error_map[l_p][rank][l_n + 1] == 0)) { iv_dqs_lb_regval[l_p][rank][l_dqs] = iv_dqs_nom_val[l_p][rank][l_dqs] - l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e_dqs, l_dqs, 0, iv_dqs_lb_regval[l_p][rank][l_dqs])); SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] - l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq])); l_dq = l_dq + 1; SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] - l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq])); l_dq = l_dq + 1; SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] - l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq])); l_dq = l_dq + 1; SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] - l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq])); l_dq = l_dq + 1; SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] - l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq])); l_dq = l_dq + 1; SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] - l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq])); l_dq = l_dq + 1; SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] - l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq])); l_dq = l_dq + 1; SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq] = SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq] - l_delay; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq])); } if(iv_dqs_lb_regval[l_p][rank][l_dqs] == 0) { iv_shmoo_error_map[l_p][rank][l_n] = 1; iv_shmoo_error_map[l_p][rank][l_n + 1] = 1; } if((iv_shmoo_error_map[l_p][rank][l_n] == 1) || (iv_shmoo_error_map[l_p][rank][l_n + 1] == 1)) { iv_shmoo_error_map[l_p][rank][l_n] = 1; iv_shmoo_error_map[l_p][rank][l_n + 1] = 1; } l_n = l_n + 1; } //nibble loop } //rank loop } //port loop FAPI_TRY(do_mcbist_test(i_target), "generic_shmoo::find_bound do_mcbist_test failed"); FAPI_TRY(check_error_map2(i_target, l_p, pass), "generic_shmoo::find_bound do_mcbist_test failed"); if (l_delay > 70) { break; } } for (l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rank = 0; l_rank < iv_MAX_RANKS[l_p]; l_rank++) { rank = iv_valid_rank[l_p][l_rank]; for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e_dqs, l_n, 0, iv_dqs_nom_val[l_p][rank][l_n])); } } } for(uint8_t l_bit = 0; l_bit < 4; l_bit++) { for (l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rank = 0; l_rank < iv_MAX_RANKS[l_p]; l_rank++) { l_dq = l_bit; rank = iv_valid_rank[l_p][l_rank]; for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq, 0, SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq])); l_dq = l_dq + 4; } } //rank loop } //port loop } //bit loop FAPI_TRY(do_mcbist_test(i_target), "generic_shmoo::find_bound do_mcbist_test failed"); FAPI_TRY(mcb_error_map(i_target, iv_mcbist_error_map, l_CDarray0, l_CDarray1, iv_count_bad_dq), "generic_shmoo::do_mcbist_test: mcb_error_map failed!!"); } //end of LEFT fapi_try_exit: return fapi2::current_err; } /// /// @brief This function calls the knob_update for each DQ which is used to find bound that is left/right according to schmoo type /// @param[in] i_target Centaur input MBA /// @param[in] bound RIGHT/LEFT /// @return FAPI2_RC_SUCCESS iff successful /// fapi2::ReturnCode generic_shmoo::find_bound(const fapi2::Target& i_target, const bound_t bound) { uint8_t l_bit = 0; uint8_t l_comp = 0; uint8_t pass = 0; uint8_t l_dram_width = 0; FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_DRAM_WIDTH, i_target, l_dram_width)); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_SCHMOO_MODE, i_target, l_comp)); FAPI_INF("%s:\n SCHMOO IS IN PROGRESS ...... \n", mss::c_str(i_target)); //WRT_DQS Portion if(iv_DQS_ON == 1) { FAPI_TRY(do_mcbist_reset(i_target), "generic_shmoo::find_bound do_mcbist_reset failed"); pass = 0; if(l_dram_width == 4) { if(iv_dmm_type == 1) { FAPI_TRY(knob_update_dqs_by4_isdimm(i_target, bound, iv_shmoo_type, l_bit, pass)); } else { FAPI_TRY(knob_update_dqs_by4(i_target, bound, iv_shmoo_type, l_bit, pass)); } } //end of if dram_width 4 else { if(iv_dmm_type == 1) { FAPI_TRY(knob_update_dqs_by8_isdimm(i_target, bound, iv_shmoo_type, l_bit, pass)); } else { FAPI_TRY(knob_update_dqs_by8(i_target, bound, iv_shmoo_type, l_bit, pass)); } } } //end of if iv_DQS_ON 1 or WRT_DQS else if(l_comp == 6) { pass = 0; FAPI_TRY(knob_update_bin_composite(i_target, bound, iv_shmoo_type, l_bit, pass)); } else { //Bit loop for (l_bit = 0; l_bit < MAX_BITS; l_bit++) { // preetham function here pass = 0; //////////////////////////////////////////////////////////////////////////////////// if (l_comp == 4) { FAPI_INF("Calling Binary - %d", iv_shmoo_type); FAPI_TRY(knob_update_bin(i_target, bound, iv_shmoo_type, l_bit, pass)); } else { FAPI_TRY(knob_update(i_target, bound, iv_shmoo_type, l_bit, pass)); } } } fapi_try_exit: return fapi2::current_err; } /// /// @brief This function is used to print the information needed such as freq,voltage etc, and also the right,left and total margin /// @param[in] i_target Centaur input MBA /// @return FAPI2_RC_SUCCESS iff successful /// fapi2::ReturnCode generic_shmoo::print_report(const fapi2::Target& i_target) { uint8_t l_rnk, l_byte, l_nibble, l_bit = 0; uint8_t l_dq = 0; uint8_t l_p = 0; uint8_t i_rank = 0; uint8_t l_mbapos = 0; uint32_t l_attr_mss_freq_u32 = 0; uint32_t l_attr_mss_volt_u32 = 0; uint8_t l_attr_eff_dimm_type_u8 = 0; uint8_t l_attr_eff_num_drops_per_port_u8 = 0; uint8_t l_attr_eff_dram_width_u8 = 0; uint16_t l_right_margin_val[MAX_PORTS_PER_MBA][MAX_RANK][MAX_DQ] = {0}; uint16_t l_left_margin_val[MAX_PORTS_PER_MBA][MAX_RANK][MAX_DQ] = {0}; const auto l_target_centaur = i_target.getParent(); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MSS_FREQ, l_target_centaur, l_attr_mss_freq_u32)); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MSS_VOLT, l_target_centaur, l_attr_mss_volt_u32)); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_CUSTOM_DIMM, i_target, l_attr_eff_dimm_type_u8)); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_NUM_DROPS_PER_PORT, i_target, l_attr_eff_num_drops_per_port_u8)); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_DRAM_WIDTH, i_target, l_attr_eff_dram_width_u8)); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CHIP_UNIT_POS, i_target, l_mbapos)); FAPI_INF("%s:freq = %d on %s.", mss::c_str(i_target), l_attr_mss_freq_u32, mss::c_str(l_target_centaur)); FAPI_INF("%s: volt = %d on %s.", mss::c_str(i_target), l_attr_mss_volt_u32, mss::c_str(l_target_centaur)); FAPI_INF("%s: dimm_type = %d on %s.", mss::c_str(i_target), l_attr_eff_dimm_type_u8, mss::c_str(i_target)); if ( l_attr_eff_dimm_type_u8 == fapi2::ENUM_ATTR_CEN_EFF_CUSTOM_DIMM_YES ) { FAPI_INF("%s: It is a CDIMM", mss::c_str(i_target)); } else { FAPI_INF("%s: It is an ISDIMM", mss::c_str(i_target)); } FAPI_INF("%s: \n Number of ranks on port = 0 is %d ", mss::c_str(i_target), iv_MAX_RANKS[0]); FAPI_INF("%s: \n Number of ranks on port = 1 is %d \n \n", mss::c_str(i_target), iv_MAX_RANKS[1]); FAPI_INF("%s:+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", mss::c_str(i_target)); //// Based on schmoo param the print will change eventually if(iv_shmoo_type == 2) { FAPI_INF("%s:Schmoo POS\tPort\tRank\tByte\tnibble\tbit\tNominal\t\tSetup_Limit\tHold_Limit\tWrD_Setup(ps)\tWrD_Hold(ps)\tEye_Width(ps)\tBitRate\tVref_Multiplier ", mss::c_str(i_target)); } else { FAPI_INF("%s:Schmoo POS\tPort\tRank\tByte\tnibble\tbit\tNominal\t\tSetup_Limit\tHold_Limit\tRdD_Setup(ps)\tRdD_Hold(ps)\tEye_Width(ps)\tBitRate\tVref_Multiplier ", mss::c_str(i_target)); } FAPI_TRY(get_margin2(i_target, l_right_margin_val, l_left_margin_val)); for (l_p = 0; l_p < 2; l_p++) { for (l_rnk = 0; l_rnk < iv_MAX_RANKS[l_p]; l_rnk++) { i_rank = iv_valid_rank[l_p][l_rnk]; for(l_byte = 0; l_byte < 10; l_byte++) { //Nibble loop for(l_nibble = 0; l_nibble < 2; l_nibble++) { for(l_bit = 0; l_bit < 4; l_bit++) { l_dq = 8 * l_byte + 4 * l_nibble + l_bit; uint16_t l_total_margin = l_right_margin_val[l_p][i_rank][l_dq] + l_left_margin_val[l_p][i_rank][l_dq]; if(iv_shmoo_type == 2) { FAPI_INF("%s:WR_EYE %d\t%d\t%d\t%d\t%d\t%d\t%d\t\t%d\t\t%d\t\t%d\t\t%d\t\t%d\t\t%d\t\t%d\n ", mss::c_str(i_target), l_mbapos, l_p, i_rank, l_byte, l_nibble, l_bit, SHMOO.MBA.P[l_p].S[i_rank].K.nom_val[l_dq], SHMOO.MBA.P[l_p].S[i_rank].K.rb_regval[l_dq], SHMOO.MBA.P[l_p].S[i_rank].K.lb_regval[l_dq], l_right_margin_val[l_p][i_rank][l_dq], l_left_margin_val[l_p][i_rank][l_dq], l_total_margin, l_attr_mss_freq_u32, iv_vref_mul); } if(iv_shmoo_type == 8) { FAPI_INF("%s:RD_EYE %d\t%d\t%d\t%d\t%d\t%d\t%d\t\t%d\t\t%d\t\t%d\t\t%d\t\t%d\t\t%d\t\t%d\n ", mss::c_str(i_target), l_mbapos, l_p, i_rank, l_byte, l_nibble, l_bit, SHMOO.MBA.P[l_p].S[i_rank].K.nom_val[l_dq], SHMOO.MBA.P[l_p].S[i_rank].K.lb_regval[l_dq], SHMOO.MBA.P[l_p].S[i_rank].K.rb_regval[l_dq], l_left_margin_val[l_p][i_rank][l_dq], l_right_margin_val[l_p][i_rank][l_dq], l_total_margin, l_attr_mss_freq_u32, iv_vref_mul); } } } } } } fapi_try_exit: return fapi2::current_err; } /// /// @brief This function is used to print the information needed such as freq,voltage etc, and also the right,left and total margin /// @param[in] i_target Centaur input MBA /// @return FAPI2_RC_SUCCESS iff successful /// fapi2::ReturnCode generic_shmoo::print_report_dqs(const fapi2::Target& i_target) { uint8_t l_rnk, l_nibble = 0; uint8_t l_p = 0; uint8_t i_rank = 0; uint8_t l_mbapos = 0; uint16_t l_total_margin = 0; uint32_t l_attr_mss_freq_u32 = 0; uint32_t l_attr_mss_volt_u32 = 0; uint8_t l_attr_eff_dimm_type_u8 = 0; uint8_t l_attr_eff_num_drops_per_port_u8 = 0; uint8_t l_attr_eff_dram_width_u8 = 0; uint8_t l_SCHMOO_NIBBLES = 20; uint8_t l_by8_dqs = 0; char* l_pMike = new char[128]; char* l_str = new char[128]; uint16_t l_right_margin_val[MAX_PORTS_PER_MBA][MAX_RANK][MAX_DQ] = {0}; uint16_t l_left_margin_val[MAX_PORTS_PER_MBA][MAX_RANK][MAX_DQ] = {0}; uint8_t l_i = 0; uint8_t l_dq = 0; uint8_t l_flag = 0; uint8_t l_CDarray0[80] = { 0 }; uint8_t l_CDarray1[80] = { 0 }; const auto l_target_centaur = i_target.getParent(); FAPI_TRY(mcb_error_map(i_target, iv_mcbist_error_map, l_CDarray0, l_CDarray1, iv_count_bad_dq), "generic_shmoo::print report: mcb_error_map failed!!"); if (iv_dmm_type == 1) { l_SCHMOO_NIBBLES = 18; } FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MSS_FREQ, l_target_centaur, l_attr_mss_freq_u32)); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MSS_VOLT, l_target_centaur, l_attr_mss_volt_u32)); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_CUSTOM_DIMM, i_target, l_attr_eff_dimm_type_u8)); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_NUM_DROPS_PER_PORT, i_target, l_attr_eff_num_drops_per_port_u8)); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_DRAM_WIDTH, i_target, l_attr_eff_dram_width_u8)); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CHIP_UNIT_POS, i_target, l_mbapos)); if (l_attr_eff_dram_width_u8 == 8) { l_SCHMOO_NIBBLES = 10; if (iv_dmm_type == 1) { l_SCHMOO_NIBBLES = 9; } } FAPI_INF("%s: freq = %d on %s.", mss::c_str(i_target), l_attr_mss_freq_u32, mss::c_str(l_target_centaur)); FAPI_INF("%s:volt = %d on %s.", mss::c_str(i_target), l_attr_mss_volt_u32, mss::c_str(l_target_centaur)); FAPI_INF("%s:dimm_type = %d on %s.", mss::c_str(i_target), l_attr_eff_dimm_type_u8, mss::c_str(i_target)); FAPI_INF("%s:\n Number of ranks on port=0 is %d ", mss::c_str(i_target), iv_MAX_RANKS[0]); FAPI_INF("%s:\n Number of ranks on port=1 is %d ", mss::c_str(i_target), iv_MAX_RANKS[1]); if (l_attr_eff_dimm_type_u8 == fapi2::ENUM_ATTR_CEN_EFF_CUSTOM_DIMM_YES) { FAPI_INF("%s:It is a CDIMM", mss::c_str(i_target)); } else { FAPI_INF("%s:It is an ISDIMM", mss::c_str(i_target)); } FAPI_INF("%s:\n Number of ranks on port=0 is %d ", mss::c_str(i_target), iv_MAX_RANKS[0]); FAPI_INF("%s:\n Number of ranks on port=1 is %d \n \n", mss::c_str(i_target), iv_MAX_RANKS[1]); FAPI_INF( "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); sprintf(l_pMike, "Schmoo POS\tPort\tRank\tDQS\tNominal\t\ttDQSSmin_PR_limit\ttDQSSmax_PR_limit\ttDQSSmin(ps)\ttDQSSmax(ps)\ttDQSS_Window(ps)\tBitRate "); FAPI_INF("%s", l_pMike); delete[] l_pMike; if (l_attr_eff_dram_width_u8 == 4) { FAPI_TRY(get_margin_dqs_by4(i_target, l_right_margin_val, l_left_margin_val)); } else { FAPI_TRY(get_margin_dqs_by8(i_target, l_right_margin_val, l_left_margin_val)); } for (l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rnk = 0; l_rnk < iv_MAX_RANKS[l_p]; l_rnk++) { //// i_rank = iv_valid_rank[l_p][l_rnk]; // for (l_nibble = 0; l_nibble < l_SCHMOO_NIBBLES; l_nibble++) { l_by8_dqs = l_nibble; if (iv_dmm_type == 0) { if (l_attr_eff_dram_width_u8 == 8) { l_nibble = l_nibble * 2; } } l_dq = 4 * l_nibble; l_flag = 0; if (l_p == 0) { for (l_i = 0; l_i < iv_count_bad_dq[0]; l_i++) { if (l_CDarray0[l_i] == l_dq) { l_flag = 1; } } } else { for (l_i = 0; l_i < iv_count_bad_dq[1]; l_i++) { if (l_CDarray1[l_i] == l_dq) { l_flag = 1; } } } if(l_flag == 1) { continue; } l_total_margin = l_left_margin_val[l_p][i_rank][l_nibble] + l_right_margin_val[l_p][i_rank][l_nibble]; sprintf(l_str, "%d\t%d\t%d\t%d\t%d\t\t%d\t\t%d\t\t%d\t\t%d\t\t%d\t\t%d", l_mbapos, l_p, i_rank, l_nibble, SHMOO.MBA.P[l_p].S[i_rank].K.curr_val[l_nibble], SHMOO.MBA.P[l_p].S[i_rank].K.lb_regval[l_nibble], SHMOO.MBA.P[l_p].S[i_rank].K.rb_regval[l_nibble], l_left_margin_val[l_p][i_rank][l_nibble], l_right_margin_val[l_p][i_rank][l_nibble], l_total_margin, l_attr_mss_freq_u32); FAPI_INF("WR_DQS %s", l_str); if (iv_dmm_type == 0) { if (l_attr_eff_dram_width_u8 == 8) { l_nibble = l_by8_dqs; } } } } } delete[] l_str; fapi_try_exit: return fapi2::current_err; } /// /// @brief This function is used to print the information needed such as freq,voltage etc, and also the right,left and total margin /// @param[in] i_target Centaur input MBA /// @return FAPI2_RC_SUCCESS iff successful /// fapi2::ReturnCode generic_shmoo::print_report_dqs2(const fapi2::Target& i_target) { uint8_t l_rnk, l_nibble = 0; uint8_t l_p = 0; uint8_t i_rank = 0; uint8_t l_mbapos = 0; uint32_t l_attr_mss_freq_u32 = 0; uint32_t l_attr_mss_volt_u32 = 0; uint8_t l_attr_eff_dimm_type_u8 = 0; uint8_t l_attr_eff_num_drops_per_port_u8 = 0; uint8_t l_attr_eff_dram_width_u8 = 0; uint8_t l_SCHMOO_NIBBLES = 20; uint8_t l_by8_dqs = 0; uint16_t l_right_margin_val[MAX_PORTS_PER_MBA][MAX_RANK][MAX_DQ] = {0}; uint16_t l_left_margin_val[MAX_PORTS_PER_MBA][MAX_RANK][MAX_DQ] = {0}; if(iv_dmm_type == 1) { l_SCHMOO_NIBBLES = 18; } const auto l_target_centaur = i_target.getParent(); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MSS_FREQ, l_target_centaur, l_attr_mss_freq_u32)); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MSS_VOLT, l_target_centaur, l_attr_mss_volt_u32)); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_CUSTOM_DIMM, i_target, l_attr_eff_dimm_type_u8)); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_NUM_DROPS_PER_PORT, i_target, l_attr_eff_num_drops_per_port_u8)); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_DRAM_WIDTH, i_target, l_attr_eff_dram_width_u8)); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CHIP_UNIT_POS, i_target, l_mbapos)); if(l_attr_eff_dram_width_u8 == 8) { l_SCHMOO_NIBBLES = 10; if(iv_dmm_type == 1) { l_SCHMOO_NIBBLES = 9; } } FAPI_INF("%s:freq = %d on %s.", mss::c_str(i_target), l_attr_mss_freq_u32, mss::c_str(l_target_centaur)); FAPI_INF("%s:volt = %d on %s.", mss::c_str(i_target), l_attr_mss_volt_u32, mss::c_str(l_target_centaur)); FAPI_INF("%s:dimm_type = %d on %s.", mss::c_str(i_target), l_attr_eff_dimm_type_u8, mss::c_str(i_target)); FAPI_INF("%s:\n Number of ranks on port=0 is %d ", mss::c_str(i_target), iv_MAX_RANKS[0]); FAPI_INF("%s:\n Number of ranks on port=1 is %d ", mss::c_str(i_target), iv_MAX_RANKS[1]); if ( l_attr_eff_dimm_type_u8 == fapi2::ENUM_ATTR_CEN_EFF_CUSTOM_DIMM_YES ) { FAPI_INF("%s:It is a CDIMM", mss::c_str(i_target)); } else { FAPI_INF("%s:It is an ISDIMM", mss::c_str(i_target)); } FAPI_INF("%s:\n Number of ranks on port=0 is %d ", mss::c_str(i_target), iv_MAX_RANKS[0]); FAPI_INF("%s:\n Number of ranks on port=1 is %d \n \n", mss::c_str(i_target), iv_MAX_RANKS[1]); FAPI_INF("%s:+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", mss::c_str(i_target)); FAPI_INF("%s:Schmoo POS\tPort\tRank\tDQS\tNominal\t\ttDQSSmin_PR_limit\ttDQSSmax_PR_limit\ttDQSSmin(ps)\ttDQSSmax(ps)\ttDQSS_Window(ps)\tBitRate ", mss::c_str(i_target)); iv_shmoo_type = 4; if (l_attr_eff_dram_width_u8 == 4) { FAPI_TRY(get_margin_dqs_by4(i_target, l_right_margin_val, l_left_margin_val)); } else { FAPI_TRY(get_margin_dqs_by8(i_target, l_right_margin_val, l_left_margin_val)); } for (l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rnk = 0; l_rnk < iv_MAX_RANKS[l_p]; l_rnk++) { i_rank = iv_valid_rank[l_p][l_rnk]; for(l_nibble = 0; l_nibble < l_SCHMOO_NIBBLES; l_nibble++) { l_by8_dqs = l_nibble; if(iv_dmm_type == 0) { if(l_attr_eff_dram_width_u8 == 8) { l_nibble = l_nibble * 2; } } uint16_t l_total_margin = l_right_margin_val[l_p][i_rank][l_nibble] + l_left_margin_val[l_p][i_rank][l_nibble]; FAPI_INF("%s:WR_DQS %d\t%d\t%d\t%d\t%d\t\t%d\t\t%d\t\t%d\t\t%d\t\t%d\t\t%d\n ", mss::c_str(i_target), l_mbapos, l_p, i_rank, l_nibble, SHMOO.MBA.P[l_p].S[i_rank].K.nom_val[l_nibble], SHMOO.MBA.P[l_p].S[i_rank].K.lb_regval[l_nibble], SHMOO.MBA.P[l_p].S[i_rank].K.rb_regval[l_nibble], l_left_margin_val[l_p][i_rank][l_nibble], l_right_margin_val[l_p][i_rank][l_nibble], l_total_margin, l_attr_mss_freq_u32); if(iv_dmm_type == 0) { if(l_attr_eff_dram_width_u8 == 8) { l_nibble = l_by8_dqs; } } } } } fapi_try_exit: return fapi2::current_err; } /// /// @brief This function is used to get margins for setup and hold in Ps by using frequency /// @param[in] i_target Centaur input MBA /// @param[in,out] io_right_margin_val array reference of hold margins /// @param[in,out] io_left_margin_val array reference of setup margins /// @return FAPI2_RC_SUCCESS iff successful /// fapi2::ReturnCode generic_shmoo::get_margin2(const fapi2::Target& i_target, uint16_t (&io_right_margin_val)[MAX_PORTS_PER_MBA][MAX_RANK][MAX_DQ], uint16_t (&io_left_margin_val)[MAX_PORTS_PER_MBA][MAX_RANK][MAX_DQ]) { uint8_t l_rnk, l_byte, l_nibble, l_bit = 0; uint32_t l_attr_mss_freq_margin_u32 = 0; uint32_t l_freq = 0; uint64_t l_cyc = 1000000000000000ULL; uint8_t l_dq = 0; uint8_t l_p = 0; uint8_t i_rank = 0; uint64_t l_factor = 0; uint64_t l_factor_ps = 1000000000; const auto l_target_centaur = i_target.getParent(); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MSS_FREQ, l_target_centaur, l_attr_mss_freq_margin_u32)); l_freq = l_attr_mss_freq_margin_u32 / 2; l_cyc = l_cyc / l_freq; // converting to zepto to get more accurate data l_factor = l_cyc / 128; //FAPI_INF("Get Margin2 - Preet"); for (l_p = 0; l_p < MAX_PORTS_PER_MBA; l_p++) { for (l_rnk = 0; l_rnk < iv_MAX_RANKS[l_p]; l_rnk++) { i_rank = iv_valid_rank[l_p][l_rnk]; for(l_byte = 0; l_byte < 10; l_byte++) { for(l_nibble = 0; l_nibble < 2; l_nibble++) { for(l_bit = 0; l_bit < 4; l_bit++) { l_dq = 8 * l_byte + 4 * l_nibble + l_bit; if((SHMOO.MBA.P[l_p].S[i_rank].K.lb_regval[l_dq]) <= 0 && (iv_shmoo_type == 8)) { SHMOO.MBA.P[l_p].S[i_rank].K.lb_regval[l_dq] = 0; } if((iv_shmoo_param == 4) || (iv_shmoo_param == 6)) { if(SHMOO.MBA.P[l_p].S[i_rank].K.rb_regval[l_dq] > SHMOO.MBA.P[l_p].S[i_rank].K.nom_val[l_dq]) { SHMOO.MBA.P[l_p].S[i_rank].K.rb_regval[l_dq] = SHMOO.MBA.P[l_p].S[i_rank].K.rb_regval[l_dq] - 1; } if((SHMOO.MBA.P[l_p].S[i_rank].K.lb_regval[l_dq] < SHMOO.MBA.P[l_p].S[i_rank].K.nom_val[l_dq]) && (SHMOO.MBA.P[l_p].S[i_rank].K.lb_regval[l_dq] != 0)) { SHMOO.MBA.P[l_p].S[i_rank].K.lb_regval[l_dq] = SHMOO.MBA.P[l_p].S[i_rank].K.lb_regval[l_dq] + 1; } } else { SHMOO.MBA.P[l_p].S[i_rank].K.rb_regval[l_dq] = SHMOO.MBA.P[l_p].S[i_rank].K.rb_regval[l_dq] - 1; SHMOO.MBA.P[l_p].S[i_rank].K.lb_regval[l_dq] = SHMOO.MBA.P[l_p].S[i_rank].K.lb_regval[l_dq] + 1; } io_right_margin_val[l_p][i_rank][l_dq] = ((SHMOO.MBA.P[l_p].S[i_rank].K.rb_regval[l_dq] - SHMOO.MBA.P[l_p].S[i_rank].K.nom_val[l_dq]) * l_factor) / l_factor_ps; io_left_margin_val[l_p][i_rank][l_dq] = ((SHMOO.MBA.P[l_p].S[i_rank].K.nom_val[l_dq] - SHMOO.MBA.P[l_p].S[i_rank].K.lb_regval[l_dq]) * l_factor) / l_factor_ps; //((1/uint32_t_freq*1000000)/128); } // for bit } // for nibble } //for byte } //for rank } // for port fapi_try_exit: return fapi2::current_err; } /// /// @brief This function is used to print the information needed such as freq,voltage etc, and also the right,left and total margin /// @param[in] i_target Centaur input MBA /// @return FAPI2_RC_SUCCESS iff successful /// fapi2::ReturnCode generic_shmoo::print_report2(const fapi2::Target& i_target) { uint8_t l_rnk, l_byte, l_nibble, l_bit = 0; uint8_t l_p = 0; uint8_t i_rank = 0; uint8_t l_mbapos = 0; uint32_t l_attr_mss_freq_u32 = 0; uint32_t l_attr_mss_volt_u32 = 0; uint8_t l_attr_eff_dimm_type_u8 = 0; uint8_t l_attr_eff_num_drops_per_port_u8 = 0; uint8_t l_attr_eff_dram_width_u8 = 0; uint16_t l_total_margin = 0; uint8_t l_dq = 0; uint8_t vrefdq_train_value[MAX_PORTS_PER_MBA][MAX_DIMM_PER_PORT][MAX_RANKS_PER_DIMM] = {0}; char* l_pMike = new char[160]; char* l_str = new char[128]; uint8_t l_dram_gen = 1; uint8_t l_param_valid = 0; uint32_t base_percent = 60000; uint32_t index_mul_print = 650; uint32_t vref_val_print = 0; uint8_t vrefdq_train_range[MAX_PORTS_PER_MBA][MAX_DIMM_PER_PORT][MAX_RANKS_PER_DIMM] = {0}; uint32_t l_attr_rd_vred_vpd_value[2] = {0}; const auto l_target_centaur = i_target.getParent(); uint16_t l_right_margin_val[MAX_PORTS_PER_MBA][MAX_RANK][MAX_DQ] = {0}; uint16_t l_left_margin_val[MAX_PORTS_PER_MBA][MAX_RANK][MAX_DQ] = {0}; FAPI_TRY(FAPI_ATTR_GET( fapi2::ATTR_CEN_EFF_VREF_DQ_TRAIN_RANGE, i_target, vrefdq_train_range)); FAPI_TRY(FAPI_ATTR_GET( fapi2::ATTR_CEN_EFF_DRAM_GEN, i_target, l_dram_gen)); FAPI_TRY(FAPI_ATTR_GET( fapi2::ATTR_CEN_EFF_VREF_DQ_TRAIN_VALUE, i_target, vrefdq_train_value)); FAPI_TRY(FAPI_ATTR_GET( fapi2::ATTR_CEN_EFF_SCHMOO_PARAM_VALID, i_target, l_param_valid)); if(vrefdq_train_range[0][0][0] == 1) { base_percent = 45000; } if (iv_shmoo_type == 2) { vref_val_print = base_percent + (vrefdq_train_value[0][0][0] * index_mul_print); } else if((iv_shmoo_type == 8) && (l_param_valid != fapi2::ENUM_ATTR_CEN_EFF_SCHMOO_PARAM_VALID_RD_VREF)) { FAPI_TRY(FAPI_ATTR_GET( fapi2::ATTR_CEN_VPD_RD_VREF, i_target, l_attr_rd_vred_vpd_value)); //FAPI_INF("Rd_From VPD = %d",l_attr_rd_vred_vpd_value[0]); vref_val_print = l_attr_rd_vred_vpd_value[0]; } else if((iv_shmoo_type == 8) && (l_param_valid == fapi2::ENUM_ATTR_CEN_EFF_SCHMOO_PARAM_VALID_RD_VREF)) { FAPI_INF("Rd_From iv_vref_mul = %d", iv_vref_mul); vref_val_print = iv_vref_mul; } FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MSS_FREQ, l_target_centaur, l_attr_mss_freq_u32)); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MSS_VOLT, l_target_centaur, l_attr_mss_volt_u32)); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_CUSTOM_DIMM, i_target, l_attr_eff_dimm_type_u8)); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_NUM_DROPS_PER_PORT, i_target, l_attr_eff_num_drops_per_port_u8)); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_DRAM_WIDTH, i_target, l_attr_eff_dram_width_u8)); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CHIP_UNIT_POS, i_target, l_mbapos)); FAPI_INF("%s: freq = %d on %s.", mss::c_str(i_target), l_attr_mss_freq_u32, mss::c_str(l_target_centaur)); FAPI_INF("%s: volt = %d on %s.", mss::c_str(i_target), l_attr_mss_volt_u32, mss::c_str(l_target_centaur)); FAPI_INF("%s: dimm_type = %d on %s.", mss::c_str(i_target), l_attr_eff_dimm_type_u8, mss::c_str(i_target)); //FAPI_INF("%s: +++ Preet1 %d +++ ", mss::c_str(i_target),vref_val_print); if (l_attr_eff_dimm_type_u8 == fapi2::ENUM_ATTR_CEN_EFF_CUSTOM_DIMM_YES) { FAPI_INF("%s: It is a CDIMM", mss::c_str(i_target)); } else { FAPI_INF("%s: It is an ISDIMM", mss::c_str(i_target)); } FAPI_INF("%s: \n Number of ranks on port = 0 is %d ", mss::c_str(i_target), iv_MAX_RANKS[0]); FAPI_INF("%s: \n Number of ranks on port = 1 is %d \n \n", mss::c_str(i_target), iv_MAX_RANKS[1]); FAPI_INF("dram_width = %d \n\n", l_attr_eff_dram_width_u8); FAPI_INF("%s:+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", mss::c_str(i_target)); //// Based on schmoo param the print will change eventually if (iv_shmoo_type == 0) { sprintf(l_pMike, "Schmoo POS\tPort\tRank\tByte\tnibble\t\tNominal\tSetup_Limit\tHold_Limit\tWrD_Setup(ps)\tWrD_Hold(ps)\tEye_Width(ps)\tBitRate\tVref_Multiplier "); } else { sprintf(l_pMike, "Schmoo POS\tPort\tRank\tByte\tnibble\t\tNominal\tSetup_Limit\tHold_Limit\tRdD_Setup(ps)\tRdD_Hold(ps)\tEye_Width(ps)\tBitRate\tVref_Multiplier "); } //FAPI_INF("Schmoo POS\tPort\tRank\tByte\tnibble\tbit\tNominal\t\tSetup_Limit\tHold_Limit \n"); FAPI_INF("%s", l_pMike); delete[] l_pMike; FAPI_TRY(get_margin2(i_target, l_right_margin_val, l_left_margin_val)); for (l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rnk = 0; l_rnk < iv_MAX_RANKS[l_p]; l_rnk++) { i_rank = iv_valid_rank[l_p][l_rnk]; for (l_byte = 0; l_byte < iv_MAX_BYTES; l_byte++) { //Nibble loop for (l_nibble = 0; l_nibble < MAX_NIBBLES; l_nibble++) { for (l_bit = 0; l_bit < MAX_BITS; l_bit++) { l_dq = (BITS_PER_BYTE * l_byte) + (BITS_PER_NIBBLE * l_nibble) + l_bit; l_total_margin = l_left_margin_val[l_p][i_rank][l_dq] + l_right_margin_val[l_p][i_rank][l_dq]; if(l_dram_gen == 2) { sprintf(l_str, "%d\t%d\t%d\t%d\t%d\t%d\t%d\t\t%d\t\t%d\t\t%d\t\t%d\t\t%d\t\t%d\t\t%d", l_mbapos, l_p, i_rank, l_byte, l_nibble, l_bit, SHMOO.MBA.P[l_p].S[i_rank].K.nom_val[l_dq], SHMOO.MBA.P[l_p].S[i_rank].K.lb_regval[l_dq], SHMOO.MBA.P[l_p].S[i_rank].K.rb_regval[l_dq], l_left_margin_val[l_p][i_rank][l_dq], l_right_margin_val[l_p][i_rank][l_dq], l_total_margin, l_attr_mss_freq_u32, vref_val_print); } else { sprintf(l_str, "%d\t%d\t%d\t%d\t%d\t%d\t%d\t\t%d\t\t%d\t\t%d\t\t%d\t\t%d\t\t%d\t\t%d", l_mbapos, l_p, i_rank, l_byte, l_nibble, l_bit, SHMOO.MBA.P[l_p].S[i_rank].K.nom_val[l_dq], SHMOO.MBA.P[l_p].S[i_rank].K.lb_regval[l_dq], SHMOO.MBA.P[l_p].S[i_rank].K.rb_regval[l_dq], l_left_margin_val[l_p][i_rank][l_dq], l_right_margin_val[l_p][i_rank][l_dq], l_total_margin, l_attr_mss_freq_u32, iv_vref_mul); } if (iv_shmoo_type == 2) { FAPI_IMP("WR_EYE %s ", l_str); } if (iv_shmoo_type == 8) { FAPI_IMP("RD_EYE %s ", l_str); } } // end for bit } // end for nibble } // end for byte } // end for rank } // end for port delete[] l_str; fapi_try_exit: return fapi2::current_err; } /// /// @brief This function is used to get DQS margins for setup and hold in Ps by using frequency for x4 DIMM /// @param[in] i_target Centaur input MBA /// @param[in,out] io_right_margin_val array reference of right-side margins /// @param[in,out] io_left_margin_val array reference of left-side margins /// @return FAPI2_RC_SUCCESS iff successful /// fapi2::ReturnCode generic_shmoo::get_margin_dqs_by4(const fapi2::Target& i_target, uint16_t (&io_right_margin_val)[MAX_PORTS_PER_MBA][MAX_RANK][MAX_DQ], uint16_t (&io_left_margin_val)[MAX_PORTS_PER_MBA][MAX_RANK][MAX_DQ]) { uint8_t l_rnk = 0; uint32_t l_attr_mss_freq_margin_u32 = 0; uint32_t l_freq = 0; uint64_t l_cyc = 1000000000000000ULL; uint8_t l_nibble = 0; uint8_t l_p = 0; uint8_t i_rank = 0; uint64_t l_factor = 0; uint64_t l_factor_ps = 1000000000; uint8_t l_SCHMOO_NIBBLES = 20; if(iv_dmm_type == 1) { l_SCHMOO_NIBBLES = 18; } const auto l_target_centaur = i_target.getParent(); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MSS_FREQ, l_target_centaur, l_attr_mss_freq_margin_u32)); l_freq = l_attr_mss_freq_margin_u32 / 2; l_cyc = l_cyc / l_freq; // converting to zepto to get more accurate data l_factor = l_cyc / 128; for (l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rnk = 0; l_rnk < iv_MAX_RANKS[l_p]; l_rnk++) { i_rank = iv_valid_rank[l_p][l_rnk]; //Nibble loop for(l_nibble = 0; l_nibble < l_SCHMOO_NIBBLES; l_nibble++) { SHMOO.MBA.P[l_p].S[i_rank].K.rb_regval[l_nibble] = SHMOO.MBA.P[l_p].S[i_rank].K.rb_regval[l_nibble] - 1; SHMOO.MBA.P[l_p].S[i_rank].K.lb_regval[l_nibble] = SHMOO.MBA.P[l_p].S[i_rank].K.lb_regval[l_nibble] + 1; io_right_margin_val[l_p][i_rank][l_nibble] = ((SHMOO.MBA.P[l_p].S[i_rank].K.rb_regval[l_nibble] - SHMOO.MBA.P[l_p].S[i_rank].K.nom_val[l_nibble]) * l_factor) / l_factor_ps; io_left_margin_val[l_p][i_rank][l_nibble] = ((SHMOO.MBA.P[l_p].S[i_rank].K.nom_val[l_nibble] - SHMOO.MBA.P[l_p].S[i_rank].K.lb_regval[l_nibble]) * l_factor) / l_factor_ps; //((1/uint32_t_freq*1000000)/128); } } } fapi_try_exit: return fapi2::current_err; } /// /// @brief This function is used to get DQS margins for setup and hold in Ps by using frequency for x8 DIMM /// @param[in] i_target Centaur input MBA /// @param[in,out] io_right_margin_val array reference of right-side margins /// @param[in,out] io_left_margin_val array reference of left-side margins /// @return FAPI2_RC_SUCCESS iff successful /// fapi2::ReturnCode generic_shmoo::get_margin_dqs_by8(const fapi2::Target& i_target, uint16_t (&io_right_margin_val)[MAX_PORTS_PER_MBA][MAX_RANK][MAX_DQ], uint16_t (&io_left_margin_val)[MAX_PORTS_PER_MBA][MAX_RANK][MAX_DQ]) { uint8_t l_rnk = 0; uint32_t l_attr_mss_freq_margin_u32 = 0; uint32_t l_freq = 0; uint64_t l_cyc = 1000000000000000ULL; uint8_t l_nibble = 0; uint8_t l_p = 0; uint8_t i_rank = 0; uint64_t l_factor = 0; uint64_t l_factor_ps = 1000000000; uint8_t l_SCHMOO_NIBBLES = 20; if(iv_dmm_type == 1) { l_SCHMOO_NIBBLES = 9; } const auto l_target_centaur = i_target.getParent(); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MSS_FREQ, l_target_centaur, l_attr_mss_freq_margin_u32)); l_freq = l_attr_mss_freq_margin_u32 / 2; l_cyc = l_cyc / l_freq; // converting to zepto to get more accurate data l_factor = l_cyc / 128; for (l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rnk = 0; l_rnk < iv_MAX_RANKS[l_p]; l_rnk++) { i_rank = iv_valid_rank[l_p][l_rnk]; for(l_nibble = 0; l_nibble < l_SCHMOO_NIBBLES; l_nibble++) { if(iv_dmm_type == 0) { if((l_nibble % 2)) { continue ; } } SHMOO.MBA.P[l_p].S[i_rank].K.rb_regval[l_nibble] = SHMOO.MBA.P[l_p].S[i_rank].K.rb_regval[l_nibble] - 1; SHMOO.MBA.P[l_p].S[i_rank].K.lb_regval[l_nibble] = SHMOO.MBA.P[l_p].S[i_rank].K.lb_regval[l_nibble] + 1; io_right_margin_val[l_p][i_rank][l_nibble] = ((SHMOO.MBA.P[l_p].S[i_rank].K.rb_regval[l_nibble] - SHMOO.MBA.P[l_p].S[i_rank].K.nom_val[l_nibble]) * l_factor) / l_factor_ps; io_left_margin_val[l_p][i_rank][l_nibble] = ((SHMOO.MBA.P[l_p].S[i_rank].K.nom_val[l_nibble] - SHMOO.MBA.P[l_p].S[i_rank].K.lb_regval[l_nibble]) * l_factor) / l_factor_ps; //((1/uint32_t_freq*1000000)/128); } } } fapi_try_exit: return fapi2::current_err; } /// /// @brief used to find right and left bound /// @param[in] i_target Centaur input MBA /// @param[in] bound RIGHT/LEFT /// @param[in] scenario type of shmoo /// @param[in] bit 0-3 /// @param[in] pass /// @return FAPI2_RC_SUCCESS iff successful /// fapi2::ReturnCode generic_shmoo::knob_update_bin_composite(const fapi2::Target& i_target, bound_t bound, uint8_t scenario, uint8_t bit, uint8_t pass) { fapi2::buffer data_buffer_64(64); fapi2::buffer data_buffer_64_1(64); input_type_t l_input_type_e = WR_DQ; uint8_t l_n = 0; access_type_t l_access_type_e = WRITE; uint8_t l_dq = 0; uint8_t l_i = 0; uint8_t l_flag_p0 = 0; uint8_t l_flag_p1 = 0; FAPI_INF("SHMOOING VIA COMPOSITE EYE FW !!!!"); uint8_t l_p = 0; uint8_t rank = 0; uint8_t l_rank = 0; uint8_t l_SCHMOO_NIBBLES = 20; uint8_t l_status = 1; uint8_t l_CDarray0[80] = {0}; uint8_t l_CDarray1[80] = {0}; int count_cycle = 0; if(iv_dmm_type == 1) { l_SCHMOO_NIBBLES = 18; } if(iv_shmoo_type == 2) { l_input_type_e = WR_DQ; } else if(iv_shmoo_type == 8) { l_input_type_e = RD_DQ; } else if(iv_shmoo_type == 4) { l_input_type_e = WR_DQS; } else if(iv_shmoo_type == 16) { l_input_type_e = RD_DQS; } FAPI_TRY(do_mcbist_reset(i_target), "generic_shmoo::find_bound do_mcbist_reset failed"); //Reset iv_shmoo_error_map for(l_p = 0; l_p < MAX_PORT; l_p++) { for(uint8_t i = 0; i < iv_MAX_RANKS[l_p]; i++) { rank = iv_valid_rank[l_p][i]; for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { iv_shmoo_error_map[l_p][rank][l_n] = 0; iv_binary_done_map[l_p][rank][l_n] = 0; } } } if(bound == RIGHT) { for(l_p = 0; l_p < MAX_PORT; l_p++) { do { l_status = 0; FAPI_TRY(mcb_error_map(i_target, iv_mcbist_error_map, l_CDarray0, l_CDarray1, iv_count_bad_dq)); for (l_rank = 0; l_rank < iv_MAX_RANKS[l_p]; l_rank++) { rank = iv_valid_rank[l_p][l_rank]; for(l_dq = 0; l_dq < 4; l_dq++) { for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { if(iv_binary_done_map[l_p][rank][l_n] == 0) { l_status = 1; } l_flag_p0 = 0; l_flag_p1 = 0; if(l_p == 0) { for(l_i = 0; l_i < iv_count_bad_dq[0]; l_i++) { if(l_CDarray0[l_i] == l_dq + l_n * 4) { iv_shmoo_error_map[l_p][rank][l_n] = 1; l_flag_p0 = 1; } } } else { for(l_i = 0; l_i < iv_count_bad_dq[1]; l_i++) { if(l_CDarray1[l_i] == l_dq + l_n * 4) { iv_shmoo_error_map[l_p][rank][l_n] = 1; l_flag_p1 = 1; } } } if(iv_shmoo_error_map[l_p][rank][l_n] == 0) { SHMOO.MBA.P[l_p].S[rank].K.last_pass[l_dq + l_n * 4] = SHMOO.MBA.P[l_p].S[rank].K.curr_val[l_dq + l_n * 4]; SHMOO.MBA.P[l_p].S[rank].K.curr_val[l_dq + l_n * 4] = (SHMOO.MBA.P[l_p].S[rank].K.last_pass[l_dq + l_n * 4] + SHMOO.MBA.P[l_p].S[rank].K.last_fail[l_dq + l_n * 4]) / 2; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq + l_n * 4, 0, SHMOO.MBA.P[l_p].S[rank].K.curr_val[l_dq + l_n * 4])); uint16_t l_curr_diff = absolute_difference(SHMOO.MBA.P[l_p].S[rank].K.last_pass[l_dq + l_n * 4], SHMOO.MBA.P[l_p].S[rank].K.last_fail[l_dq + l_n * 4]); if(l_curr_diff <= 1) { iv_binary_done_map[l_p][rank][l_n] = 1; SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq + l_n * 4] = SHMOO.MBA.P[l_p].S[rank].K.last_fail[l_dq + l_n * 4]; // printf("\n the right bound for port=%d rank=%d dq=%d is %d \n",l_p,rank,l_dq+l_n*4,FAPI_INF.MBA.P[l_p].S[rank].K.curr_val[l_dq+l_n*4]); } } else { SHMOO.MBA.P[l_p].S[rank].K.last_fail[l_dq + l_n * 4] = SHMOO.MBA.P[l_p].S[rank].K.curr_val[l_dq + l_n * 4]; SHMOO.MBA.P[l_p].S[rank].K.curr_val[l_dq + l_n * 4] = (SHMOO.MBA.P[l_p].S[rank].K.last_pass[l_dq + l_n * 4] + SHMOO.MBA.P[l_p].S[rank].K.last_fail[l_dq + l_n * 4]) / 2; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq + l_n * 4, 0, SHMOO.MBA.P[l_p].S[rank].K.curr_val[l_dq + l_n * 4])); uint16_t l_curr_diff = absolute_difference(SHMOO.MBA.P[l_p].S[rank].K.last_pass[l_dq + l_n * 4], SHMOO.MBA.P[l_p].S[rank].K.last_fail[l_dq + l_n * 4]); if(l_p == 0) { if(l_flag_p0 == 1) { l_curr_diff = 1; } } else { if(l_flag_p1 == 1) { l_curr_diff = 1; } } if(l_curr_diff <= 1) { iv_binary_done_map[l_p][rank][l_n] = 1; SHMOO.MBA.P[l_p].S[rank].K.rb_regval[l_dq + l_n * 4] = SHMOO.MBA.P[l_p].S[rank].K.last_fail[l_dq + l_n * 4]; } } // end else (iv_shmoo_error_map[l_p][rank][l_n] != 0) } // end for nibble } // end for dq } // end for rank FAPI_TRY(do_mcbist_reset(i_target), "generic_shmoo::find_bound do_mcbist_reset failed"); FAPI_TRY(do_mcbist_test(i_target), "generic_shmoo::find_bound do_mcbist_test failed"); FAPI_TRY(check_error_map(i_target, l_p, pass)); //FAPI_INF("\n the status =%d \n",l_status); count_cycle++; } // end do while(l_status == 1); } // end for port for(l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rank = 0; l_rank < iv_MAX_RANKS[l_p]; l_rank++) { rank = iv_valid_rank[l_p][l_rank]; for(l_dq = 0; l_dq < 4; l_dq++) { for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq + l_n * 4, 0, SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq + l_n * 4])); } } } } } count_cycle = 0; if(bound == LEFT) { for(l_p = 0; l_p < MAX_PORT; l_p++) { l_status = 1; while(l_status == 1) { l_status = 0; FAPI_TRY(mcb_error_map(i_target, iv_mcbist_error_map, l_CDarray0, l_CDarray1, iv_count_bad_dq)); for (l_rank = 0; l_rank < iv_MAX_RANKS[l_p]; l_rank++) { rank = iv_valid_rank[l_p][l_rank]; for(l_dq = 0; l_dq < 4; l_dq++) { for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { if(iv_binary_done_map[l_p][rank][l_n] == 0) { l_status = 1; } l_flag_p0 = 0; l_flag_p1 = 0; if(l_p == 0) { for(l_i = 0; l_i < iv_count_bad_dq[0]; l_i++) { if(l_CDarray0[l_i] == l_dq + l_n * 4) { iv_shmoo_error_map[l_p][rank][l_n] = 1; l_flag_p0 = 1; } } } else { for(l_i = 0; l_i < iv_count_bad_dq[1]; l_i++) { if(l_CDarray1[l_i] == l_dq + l_n * 4) { iv_shmoo_error_map[l_p][rank][l_n] = 1; l_flag_p1 = 1; } } } if(iv_shmoo_error_map[l_p][rank][l_n] == 0) { SHMOO.MBA.P[l_p].S[rank].K.last_pass[l_dq + l_n * 4] = SHMOO.MBA.P[l_p].S[rank].K.curr_val[l_dq + l_n * 4]; SHMOO.MBA.P[l_p].S[rank].K.curr_val[l_dq + l_n * 4] = (SHMOO.MBA.P[l_p].S[rank].K.last_pass[l_dq + l_n * 4] + SHMOO.MBA.P[l_p].S[rank].K.last_fail[l_dq + l_n * 4]) / 2; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq + l_n * 4, 0, SHMOO.MBA.P[l_p].S[rank].K.curr_val[l_dq + l_n * 4])); uint16_t l_curr_diff = absolute_difference(SHMOO.MBA.P[l_p].S[rank].K.last_pass[l_dq + l_n * 4], SHMOO.MBA.P[l_p].S[rank].K.last_fail[l_dq + l_n * 4]); if(l_curr_diff <= 1) { iv_binary_done_map[l_p][rank][l_n] = 1; SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq + l_n * 4] = SHMOO.MBA.P[l_p].S[rank].K.last_fail[l_dq + l_n * 4]; } } else { SHMOO.MBA.P[l_p].S[rank].K.last_fail[l_dq + l_n * 4] = SHMOO.MBA.P[l_p].S[rank].K.curr_val[l_dq + l_n * 4]; SHMOO.MBA.P[l_p].S[rank].K.curr_val[l_dq + l_n * 4] = (SHMOO.MBA.P[l_p].S[rank].K.last_pass[l_dq + l_n * 4] + SHMOO.MBA.P[l_p].S[rank].K.last_fail[l_dq + l_n * 4]) / 2; FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq + l_n * 4, 0, SHMOO.MBA.P[l_p].S[rank].K.curr_val[l_dq + l_n * 4])); uint16_t l_curr_diff = absolute_difference(SHMOO.MBA.P[l_p].S[rank].K.last_pass[l_dq + l_n * 4], SHMOO.MBA.P[l_p].S[rank].K.last_fail[l_dq + l_n * 4]); if(l_p == 0) { if(l_flag_p0 == 1) { l_curr_diff = 1; } } else { if(l_flag_p1 == 1) { l_curr_diff = 1; } } if(l_curr_diff <= 1) { iv_binary_done_map[l_p][rank][l_n] = 1; SHMOO.MBA.P[l_p].S[rank].K.lb_regval[l_dq + l_n * 4] = SHMOO.MBA.P[l_p].S[rank].K.last_fail[l_dq + l_n * 4]; } } } } } FAPI_TRY(do_mcbist_reset(i_target), "generic_shmoo::find_bound do_mcbist_reset failed"); FAPI_TRY(do_mcbist_test(i_target), "generic_shmoo::find_bound do_mcbist_test failed"); FAPI_TRY(check_error_map(i_target, l_p, pass), "generic_shmoo::find_bound do_mcbist_test failed"); count_cycle++; } } for(l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rank = 0; l_rank < iv_MAX_RANKS[l_p]; l_rank++) { rank = iv_valid_rank[l_p][l_rank]; for(l_dq = 0; l_dq < 4; l_dq++) { for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq + l_n * 4, 0, SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq + l_n * 4])); } } } } } // End of LEFT fapi_try_exit: return fapi2::current_err; } /// /// @brief Sets the PDA nibble table with shmoo values /// @param[in] i_target Centaur input MBA /// @param[in] pda_nibble_table Per nibble vref + margins /// @return FAPI2_RC_SUCCESS iff successful /// fapi2::ReturnCode generic_shmoo::get_nibble_pda(const fapi2::Target& i_target, uint32_t (&pda_nibble_table)[MAX_PORTS_PER_MBA][MAX_DIMM_PER_PORT][MAX_RANKS_PER_DIMM][MAX_DRAMS_PER_RANK_X4][2]) { uint16_t l_right_margin_val[MAX_PORTS_PER_MBA][MAX_RANK][MAX_DQ] = {0}; uint16_t l_left_margin_val[MAX_PORTS_PER_MBA][MAX_RANK][MAX_DQ] = {0}; uint8_t l_dimm = 0; uint8_t num_ranks_per_dimm[MAX_PORTS_PER_MBA][MAX_DIMM_PER_PORT] = {0}; FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_NUM_MASTER_RANKS_PER_DIMM, i_target, num_ranks_per_dimm)); FAPI_TRY(get_margin2(i_target, l_right_margin_val, l_left_margin_val)); for(uint8_t l_p = 0; l_p < MAX_PORTS_PER_MBA; l_p++) { for (l_dimm = 0; l_dimm < MAX_DIMM_PER_PORT; l_dimm++) { for(uint8_t l_rnk = 0; l_rnk < num_ranks_per_dimm[l_p][l_dimm]; l_rnk++) { for(uint8_t l_dq = 0; l_dq < 4; l_dq++) { for(uint8_t l_n = 0; l_n < (iv_MAX_BYTES * MAX_NIBBLES_PER_BYTE); l_n++) { pda_nibble_table[l_p][l_dimm][l_rnk][l_n][0] = iv_vref_mul; if(l_dimm == 0) { uint16_t l_total_margin = l_left_margin_val[l_p][l_rnk][l_dq + l_n * 4] + l_right_margin_val[l_p][l_rnk][l_dq + l_n * 4]; pda_nibble_table[l_p][l_dimm][l_rnk][l_n][1] = l_total_margin; } else { uint16_t l_total_margin = l_left_margin_val[l_p][l_rnk + 4][l_dq + l_n * 4] + l_right_margin_val[l_p][l_rnk + 4][l_dq + l_n * 4]; pda_nibble_table[l_p][l_dimm][l_rnk][l_n][1] = l_total_margin; } } } } } } fapi_try_exit: return fapi2::current_err; } /// /// @brief This function is used to get the minimum margin of all the schmoo margins /// @param[in] i_target Centaur input MBA /// @param[out] o_right_min_margin Minimum hold margin /// @param[out] o_left_min_margin Minimum setup margin /// @return FAPI2_RC_SUCCESS iff successful /// fapi2::ReturnCode generic_shmoo::get_min_margin2(const fapi2::Target& i_target, uint32_t* o_right_min_margin, uint32_t* o_left_min_margin) { uint16_t l_right_margin_val[MAX_PORTS_PER_MBA][MAX_RANK][MAX_DQ] = {0}; uint16_t l_left_margin_val[MAX_PORTS_PER_MBA][MAX_RANK][MAX_DQ] = {0}; uint8_t l_rnk, l_byte, l_nibble, l_bit, i_rank = 0; uint16_t l_temp_right = 4800; uint16_t l_temp_left = 4800; uint8_t l_dq = 0; uint8_t l_p = 0; FAPI_INF("In GET_MIN_MARGIN - iv_shmoo_type = %d", iv_shmoo_type); FAPI_TRY(get_margin2(i_target, l_right_margin_val, l_left_margin_val)); for (l_p = 0; l_p < 2; l_p++) { for (l_rnk = 0; l_rnk < iv_MAX_RANKS[l_p]; l_rnk++) { i_rank = iv_valid_rank[l_p][l_rnk]; //// for (l_byte = 0; l_byte < 10; l_byte++) { //Nibble loop for (l_nibble = 0; l_nibble < 2; l_nibble++) { for (l_bit = 0; l_bit < 4; l_bit++) { l_dq = 8 * l_byte + 4 * l_nibble + l_bit; if ((l_right_margin_val[l_p][i_rank][l_dq] < l_temp_right) && (l_right_margin_val[l_p][i_rank][l_dq] != 0 )) { l_temp_right = l_right_margin_val[l_p][i_rank][l_dq]; } if ((l_left_margin_val[l_p][i_rank][l_dq] < l_temp_left) && (l_left_margin_val[l_p][i_rank][l_dq] != 0)) { l_temp_left = l_left_margin_val[l_p][i_rank][l_dq]; } } } } } } if(iv_shmoo_type == 8) { *o_right_min_margin = l_temp_left; *o_left_min_margin = l_temp_right; } else { *o_right_min_margin = l_temp_right; *o_left_min_margin = l_temp_left; } fapi_try_exit: return fapi2::current_err; } /// /// @brief This function is used to get the minimum margin of all the schmoo margins /// @param[in] i_target Centaur input MBA /// @param[out] o_right_min_margin Minimum hold margin /// @param[out] o_left_min_margin Minimum setup margin /// @return FAPI2_RC_SUCCESS iff successful /// fapi2::ReturnCode generic_shmoo::get_min_margin_dqs(const fapi2::Target& i_target, uint32_t* o_right_min_margin, uint32_t* o_left_min_margin) { uint16_t l_right_margin_val[MAX_PORTS_PER_MBA][MAX_RANK][MAX_DQ] = {0}; uint16_t l_left_margin_val[MAX_PORTS_PER_MBA][MAX_RANK][MAX_DQ] = {0}; uint8_t l_rnk, l_nibble, i_rank = 0; uint16_t l_temp_right = 4800; uint16_t l_temp_left = 4800; uint8_t l_p = 0; uint8_t l_attr_eff_dram_width_u8 = 0; uint8_t l_SCHMOO_NIBBLES = 20; uint8_t l_by8_dqs = 0; FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_DRAM_WIDTH, i_target, l_attr_eff_dram_width_u8)); if(iv_dmm_type == 1) { l_SCHMOO_NIBBLES = 18; } if(l_attr_eff_dram_width_u8 == 8) { l_SCHMOO_NIBBLES = 10; if(iv_dmm_type == 1) { l_SCHMOO_NIBBLES = 9; } } iv_shmoo_type = 4; if (l_attr_eff_dram_width_u8 == 4) { FAPI_TRY(get_margin_dqs_by4(i_target, l_right_margin_val, l_left_margin_val)); } else { FAPI_TRY(get_margin_dqs_by8(i_target, l_right_margin_val, l_left_margin_val)); } for (l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rnk = 0; l_rnk < iv_MAX_RANKS[l_p]; l_rnk++) { i_rank = iv_valid_rank[l_p][l_rnk]; for(l_nibble = 0; l_nibble < l_SCHMOO_NIBBLES; l_nibble++) { l_by8_dqs = l_nibble; if(iv_dmm_type == 0) { if(l_attr_eff_dram_width_u8 == 8) { l_nibble = l_nibble * 2; } } if(l_right_margin_val[l_p][i_rank][l_nibble] < l_temp_right) { l_temp_right = l_right_margin_val[l_p][i_rank][l_nibble]; } if(l_left_margin_val[l_p][i_rank][l_nibble] < l_temp_left) { l_temp_left = l_left_margin_val[l_p][i_rank][l_nibble]; } if(iv_dmm_type == 0) { if(l_attr_eff_dram_width_u8 == 8) { l_nibble = l_by8_dqs; } } } // for nibble } // for rank } // for port // hacked for now till schmoo is running if(iv_shmoo_type == 8) { *o_right_min_margin = l_temp_left; *o_left_min_margin = l_temp_right; } else { *o_right_min_margin = l_temp_right; *o_left_min_margin = l_temp_left; } fapi_try_exit: return fapi2::current_err; } /// /// @brief call setup_mcbist /// @param[in] i_target Centaur input MBA /// @return FAPI2_RC_SUCCESS iff successful /// fapi2::ReturnCode generic_shmoo::schmoo_setup_mcb(const fapi2::Target& i_target) { struct subtest_info l_sub_info[30] = {0}; uint32_t l_pattern = 0; uint32_t l_testtype = 0; mcbist_byte_mask i_mcbbytemask1; char l_str_cust_addr[] = "ba0,ba1,mr3,mr2,mr1,mr0,ba2,ba3,cl2,cl3,cl4,cl5,cl6,cl7,cl8,cl9,cl11,cl13,r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,r13,r14,r15,r16,sl2,sl1,sl0"; i_mcbbytemask1 = UNMASK_ALL; l_pattern = iv_pattern; l_testtype = iv_test_type; if (iv_shmoo_type == 16) { FAPI_INF("%s:\n Read DQS is running \n", mss::c_str(i_target)); if (iv_SHMOO_ON == 1) { l_testtype = 3; } if (iv_SHMOO_ON == 2) { l_testtype = 4; } } //send shmoo mode to vary the address range if (iv_shmoo_type == 16) { FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_MCBIST_PATTERN, i_target, l_pattern)); FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_MCBIST_TEST_TYPE, i_target, l_testtype)); } FAPI_TRY(setup_mcbist(i_target, i_mcbbytemask1, 0, 0x0ull , l_sub_info, l_str_cust_addr), "Failed setup_mcbist"); fapi_try_exit: return fapi2::current_err; } /// /// @brief Box shmoo error log helper /// @param[in] i_target the MBA target /// @param[in] i_fail true if MCBIST failed /// @param[in] i_vref the VREF value /// @param[in] i_delay delay offset value /// @param[in] i_offset true if the delay is positive /// fapi2::ReturnCode box_shmoo_error_helper(const fapi2::Target& i_target, const bool i_fail, const uint8_t i_vref, const uint8_t i_delay, const bool i_offset) { const bool l_pass = !i_fail; FAPI_ASSERT(l_pass, fapi2::MSS_BOX_SHMOO_FAIL() .set_TARGET(i_target) .set_VREF(i_vref) .set_DELAY(i_delay) .set_OFFSET(i_offset), "%s FOUND FAILING MCBIST BIT AT %s 0x%02x DELAY and VREF 0x%02x!!!", mss::c_str(i_target), i_offset ? "+" : "-", i_delay, i_vref) // Passing - send out an informational message and return success FAPI_INF("%s FOUND PASSING MCBIST BIT AT %s 0x%02x DELAY and VREF 0x%02x!!!", mss::c_str(i_target), i_offset ? "+" : "-", i_delay, i_vref); return fapi2::FAPI2_RC_SUCCESS; fapi_try_exit: // We're here, so we took a fail - log it as recovered, as we just want it to be informational // Box shmoo is just used to collect data in case we take fails later fapi2::logError(fapi2::current_err, fapi2::FAPI2_ERRL_SEV_RECOVERED); fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; return fapi2::FAPI2_RC_SUCCESS; } /// /// @brief Does the box shmoo /// @param[in] i_target Centaur input MBA /// @return FAPI2_RC_SUCCESS iff successful /// fapi2::ReturnCode generic_shmoo::do_box_shmoo(const fapi2::Target& i_target) { fapi2::buffer data_buffer_64; uint8_t l_p = 0; uint8_t l_rank = 0; uint8_t l_dq = 0; uint8_t l_n = 0; uint8_t rank = 0; uint8_t l_SCHMOO_NIBBLES = 18; input_type_t l_input_type_e = WR_DQ; access_type_t l_access_type_e = WRITE; uint8_t delay_train_step_size = 0; FAPI_TRY(FAPI_ATTR_GET( fapi2::ATTR_CEN_MRW_WR_VREF_CHECK_VREF_STEP_SIZE, fapi2::Target(), delay_train_step_size)); for(l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rank = 0; l_rank < iv_MAX_RANKS[l_p]; l_rank++) { rank = iv_valid_rank[l_p][l_rank]; for(l_dq = 0; l_dq < BITS_PER_NIBBLE; l_dq++) { for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { SHMOO.MBA.P[l_p].S[rank].K.curr_val[l_dq + l_n * BITS_PER_NIBBLE] = (SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq + l_n * 4] + delay_train_step_size); FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq + l_n * BITS_PER_NIBBLE, 0, SHMOO.MBA.P[l_p].S[rank].K.curr_val[l_dq + l_n * BITS_PER_NIBBLE])); } } } } FAPI_TRY(do_mcbist_reset(i_target), "%s generic_shmoo::find_bound do_mcbist_reset failed", mss::c_str(i_target)); FAPI_TRY(do_mcbist_test(i_target), "%s generic_shmoo::find_bound do_mcbist_test failed", mss::c_str(i_target)); FAPI_TRY(getScom(i_target, CEN_MBA_MCB_CNTLSTATQ, data_buffer_64)); // Note: the below function checks if we failed and logs an error if we did // Box shmoo is a margins check, as such we want to just note the fail and move on in the IPL // If we fail, that's ok we might have adequate margins to run, but we'll want to note it and move on // True for increasing delay FAPI_TRY(box_shmoo_error_helper(i_target, data_buffer_64.getBit<2>(), iv_vref_mul, delay_train_step_size, true)); { uint8_t l_CDarray0[DIMM_TO_C4_DQ_ENTRIES] = { 0 }; uint8_t l_CDarray1[DIMM_TO_C4_DQ_ENTRIES] = { 0 }; FAPI_TRY(mcb_error_map(i_target, iv_mcbist_error_map, l_CDarray0, l_CDarray1, iv_count_bad_dq), "Failed mcb_error_map"); } for(l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rank = 0; l_rank < iv_MAX_RANKS[l_p]; l_rank++) { rank = iv_valid_rank[l_p][l_rank]; for(l_dq = 0; l_dq < BITS_PER_NIBBLE; l_dq++) { for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { SHMOO.MBA.P[l_p].S[rank].K.curr_val[l_dq + l_n * BITS_PER_NIBBLE] = (SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq + l_n * 4] - delay_train_step_size); FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq + l_n * BITS_PER_NIBBLE, 0, SHMOO.MBA.P[l_p].S[rank].K.curr_val[l_dq + l_n * BITS_PER_NIBBLE])); } } } } FAPI_TRY(do_mcbist_reset(i_target), "%s generic_shmoo::find_bound do_mcbist_reset failed", mss::c_str(i_target)); FAPI_TRY(do_mcbist_test(i_target), "%s generic_shmoo::find_bound do_mcbist_test failed", mss::c_str(i_target)); FAPI_TRY(getScom(i_target, CEN_MBA_MCB_CNTLSTATQ, data_buffer_64)); // Note: the below function checks if we failed and logs an error if we did // Box shmoo is a margins check, as such we want to just note the fail and move on in the IPL // If we fail, that's ok we might have adequate margins to run, but we'll want to note it and move on // False for decreasing delay FAPI_TRY(box_shmoo_error_helper(i_target, data_buffer_64.getBit<2>(), iv_vref_mul, delay_train_step_size, false)); { uint8_t l_CDarray0[DIMM_TO_C4_DQ_ENTRIES] = { 0 }; uint8_t l_CDarray1[DIMM_TO_C4_DQ_ENTRIES] = { 0 }; FAPI_TRY(mcb_error_map(i_target, iv_mcbist_error_map, l_CDarray0, l_CDarray1, iv_count_bad_dq), "Failed mcb_error_map"); } for(l_p = 0; l_p < MAX_PORT; l_p++) { for (l_rank = 0; l_rank < iv_MAX_RANKS[l_p]; l_rank++) { rank = iv_valid_rank[l_p][l_rank]; for(l_dq = 0; l_dq < BITS_PER_NIBBLE; l_dq++) { for (l_n = 0; l_n < l_SCHMOO_NIBBLES; l_n++) { FAPI_TRY(mss_access_delay_reg_schmoo(i_target, l_access_type_e, l_p, rank, l_input_type_e, l_dq + l_n * BITS_PER_NIBBLE, 0, SHMOO.MBA.P[l_p].S[rank].K.nom_val[l_dq + l_n * BITS_PER_NIBBLE])); } } } } fapi_try_exit: return fapi2::current_err; } /// /// @brief Calculate the absolute value of the difference between two values /// @param[in] i_val1 first value /// @param[in] i_val2 second value /// @return absolute value of the difference between i_val1 and i_val2 /// uint16_t generic_shmoo::absolute_difference(const uint16_t i_val1, const uint16_t i_val2) { return (i_val1 > i_val2) ? (i_val1 - i_val2) : (i_val2 - i_val1); } }//Extern C /// /// @brief helper function for testing ternary search /// @param[in] i_results map of test results that have been found so far /// @param[in,out] io_low_bound lower search boundary's vref value /// @param[in,out] io_high_bound higher search boundary's vref value /// @param[out] o_test_vref next Vref value to test /// @param[out] o_complete true if the search is complete, false otherwise /// @return FAPI2_RC_SUCCESS if no errors encountered /// fapi2::ReturnCode ternary_search_helper(const std::map& i_results, uint8_t& io_low_bound, uint8_t& io_high_bound, uint8_t& o_test_vref, bool& o_complete) { // This value is for termination of the search algorithm. // When the search range gets below this, the answer is the average of the high/low bounds constexpr uint8_t MIN_BOUNDS = 3; while(true) { // First calculate the next step value (how much to move bound on end with lowest margin) const uint32_t l_step = (io_high_bound - io_low_bound) / 3; // See if we've already got results for each test point auto l_low_margin_it = i_results.find(io_low_bound + l_step); auto l_high_margin_it = i_results.find(io_high_bound - l_step); // If we don't have results for the next test points, return the next value to test if (l_low_margin_it == i_results.end()) { o_test_vref = io_low_bound + l_step; o_complete = false; return fapi2::FAPI2_RC_SUCCESS; } if (l_high_margin_it == i_results.end()) { o_test_vref = io_high_bound - l_step; o_complete = false; return fapi2::FAPI2_RC_SUCCESS; } // Next, move in low or high bound, depending on which test point had the lowest margin if (l_low_margin_it->second < l_high_margin_it->second) { io_low_bound += l_step; } else { io_high_bound -= l_step; } // If we're at our minimum search range, return the average of the bounds if ((io_high_bound - io_low_bound) < MIN_BOUNDS) { o_test_vref = (io_high_bound + io_low_bound) / 2; o_complete = true; return fapi2::FAPI2_RC_SUCCESS; } // If not, loop around and continue the search } }