diff options
Diffstat (limited to 'src/import/chips/ocmb/explorer/procedures/hwp')
-rw-r--r-- | src/import/chips/ocmb/explorer/procedures/hwp/memory/lib/i2c/exp_i2c.H | 182 | ||||
-rw-r--r-- | src/import/chips/ocmb/explorer/procedures/hwp/memory/lib/shared/exp_consts.H | 34 |
2 files changed, 156 insertions, 60 deletions
diff --git a/src/import/chips/ocmb/explorer/procedures/hwp/memory/lib/i2c/exp_i2c.H b/src/import/chips/ocmb/explorer/procedures/hwp/memory/lib/i2c/exp_i2c.H index 18bc4b808..c4acf2ced 100644 --- a/src/import/chips/ocmb/explorer/procedures/hwp/memory/lib/i2c/exp_i2c.H +++ b/src/import/chips/ocmb/explorer/procedures/hwp/memory/lib/i2c/exp_i2c.H @@ -60,6 +60,7 @@ namespace check /// @param[in] i_cmd_id the command ID /// @param[in] i_data data to check from EXP_FW_STATUS /// @param[out] o_busy true if explorer returns FW_BUSY status, false otherwise +/// @return FAPI2_RC_SUCCESS iff okay /// inline fapi2::ReturnCode status_code( const fapi2::Target<fapi2::TARGET_TYPE_OCMB_CHIP>& i_target, const uint8_t i_cmd_id, @@ -96,33 +97,6 @@ fapi_try_exit: return fapi2::current_err; } -/// -/// @brief Checks the I2c explorer boot stage for FUNTIME_FW -/// @param[in] i_target the OCMB target -/// @param[in] i_data data to check from EXP_FW_STATUS -/// -inline fapi2::ReturnCode runtime_boot_stage( const fapi2::Target<fapi2::TARGET_TYPE_OCMB_CHIP>& i_target, - const std::vector<uint8_t>& i_data ) -{ - constexpr uint8_t EXPECTED_BOOT_STAGE = boot_stages::RUNTIME_FW; - uint8_t l_boot_stage = 0; - FAPI_TRY( status::get_boot_stage(i_target, i_data, l_boot_stage) ); - - // Check that Explorer is in the RUNTIME_FW boot stage - FAPI_ASSERT( (l_boot_stage == EXPECTED_BOOT_STAGE), - fapi2::MSS_EXP_I2C_WRONG_BOOT_STAGE(). - set_TARGET(i_target). - set_BOOT_STAGE(l_boot_stage). - set_EXPECTED_BOOT_STAGE(EXPECTED_BOOT_STAGE), - "FW_STATUS command returned wrong boot stage (0x%01x, expected 0x%01x) for %s", - l_boot_stage, EXPECTED_BOOT_STAGE, mss::c_str(i_target) ); - - return fapi2::FAPI2_RC_SUCCESS; - -fapi_try_exit: - return fapi2::current_err; -} - }// check /// @@ -139,8 +113,19 @@ inline void fw_status_setup(size_t& o_size, } /// +/// @brief EXP_FW_BYPASS_4SEC_TIMEOUT setup helper function +/// @param[out] o_cmd_id the explorer command ID +/// +inline void fw_bypass_download_window_setup(std::vector<uint8_t>& o_cmd_id) +{ + o_cmd_id.clear(); + o_cmd_id.push_back(FW_BYPASS_4SEC_TIMEOUT); +} + +/// /// @brief get EXP_FW_STATUS bytes /// @param[in] i_target the OCMB target +/// @param[out] o_data the return data from FW_STATUS command /// @return FAPI2_RC_SUCCESS iff okay /// inline fapi2::ReturnCode get_fw_status(const fapi2::Target<fapi2::TARGET_TYPE_OCMB_CHIP>& i_target, @@ -160,37 +145,73 @@ fapi_try_exit: } /// +/// @brief Helper function to check FW_STATUS loop termination, for unit testing +/// @param[in] i_target the OCMB target +/// @param[in] i_busy busy flag from check::status_code +/// @param[in] i_boot_stage boot_stage output from status::get_boot_stage +/// @return true if we should break out of the loop, false otherwise +/// +inline bool fw_status_loop_done(const fapi2::Target<fapi2::TARGET_TYPE_OCMB_CHIP>& i_target, + const bool i_busy, + const uint8_t i_boot_stage) +{ + constexpr uint8_t EXPECTED_BOOT_STAGE = boot_stages::RUNTIME_FW; + + if (i_busy) + { + FAPI_DBG( "%s reutrned FW_BUSY status. Retrying...", mss::c_str(i_target) ); + return false; + } + + if (i_boot_stage != EXPECTED_BOOT_STAGE) + { + FAPI_DBG( "%s reutrned non-RUNTIME boot stage (0x%02x). Retrying...", + mss::c_str(i_target), i_boot_stage ); + return false; + } + + return true; +} + +/// /// @brief EXP_FW_STATUS /// @param[in] i_target the OCMB target +/// @param[in] i_delay delay between polls +/// @param[in] i_loops number of polling loops to perform /// @return FAPI2_RC_SUCCESS iff okay /// -inline fapi2::ReturnCode fw_status(const fapi2::Target<fapi2::TARGET_TYPE_OCMB_CHIP>& i_target) +inline fapi2::ReturnCode fw_status(const fapi2::Target<fapi2::TARGET_TYPE_OCMB_CHIP>& i_target, + const uint64_t i_delay, + const uint64_t i_loops) { - constexpr uint64_t NUM_LOOPS = 50; + constexpr uint8_t EXPECTED_BOOT_STAGE = boot_stages::RUNTIME_FW; + // So, why aren't we using the memory team's polling API? // This is a base function that will be utilized by the platform code // As such, we don't want to pull in more libraries than we need to: it would cause extra dependencies // So, we're decomposing the polling library below + fapi2::ReturnCode l_rc = fapi2::FAPI2_RC_SUCCESS; bool l_busy = true; + uint8_t l_boot_stage = 0; uint64_t l_loop = 0; - // Loop until we max our our loop count or get a doorbell response - for(; l_loop < NUM_LOOPS && l_busy; ++l_loop) + // Loop until we max our our loop count or get a non-busy response + for(; l_loop < i_loops; ++l_loop) { std::vector<uint8_t> l_data; FAPI_TRY( get_fw_status(i_target, l_data) ); FAPI_TRY( check::status_code(i_target, FW_STATUS, l_data, l_busy) ); - FAPI_TRY( check::runtime_boot_stage(i_target, l_data) ); + FAPI_TRY( status::get_boot_stage(i_target, l_data, l_boot_stage) ); - if (l_busy) + if (fw_status_loop_done(i_target, l_busy, l_boot_stage)) { - FAPI_INF( "%s reutrned FW_BUSY status. Retrying...", mss::c_str(i_target) ); - FAPI_TRY( fapi2::delay( DELAY_100NS, 200) ); + break; } + + FAPI_TRY( fapi2::delay( i_delay, 200) ); } - FAPI_DBG("%s stopped on loop%u/%u. %s", - mss::c_str(i_target), l_loop, NUM_LOOPS, (l_busy ? "FW_BUSY" : "SUCCESS")); + FAPI_DBG("%s stopped on loop %u/%u", mss::c_str(i_target), l_loop, i_loops); // Check that Explorer is not still in FW_BUSY state FAPI_ASSERT( !l_busy, @@ -199,6 +220,15 @@ inline fapi2::ReturnCode fw_status(const fapi2::Target<fapi2::TARGET_TYPE_OCMB_C "Polling timeout on FW_STATUS command (still FW_BUSY) for %s", mss::c_str(i_target) ); + // Check that Explorer is in RUNTIME_FW boot stage + FAPI_ASSERT( (l_boot_stage == EXPECTED_BOOT_STAGE), + fapi2::MSS_EXP_I2C_WRONG_BOOT_STAGE(). + set_TARGET(i_target). + set_BOOT_STAGE(l_boot_stage). + set_EXPECTED_BOOT_STAGE(EXPECTED_BOOT_STAGE), + "Polling timeout on FW_STATUS command (wrong boot stage: 0x%01x, expected 0x%01x) for %s", + l_boot_stage, EXPECTED_BOOT_STAGE, mss::c_str(i_target) ); + fapi_try_exit: return fapi2::current_err; } @@ -239,9 +269,19 @@ inline fapi2::ReturnCode boot_config(const fapi2::Target<fapi2::TARGET_TYPE_OCMB std::vector<uint8_t> l_configured_data(i_data); boot_config_setup(l_configured_data); - // Get data and check for errors + // Send the command FAPI_TRY(fapi2::putI2c(i_target, l_configured_data)); - FAPI_TRY(fw_status(i_target)); + + // Wait a bit for the command (DLL lock and OMI training) to complete + // Value based on initial Explorer hardware. + // The command takes ~300ms and we poll for around 100ms, so wait 250ms here + FAPI_TRY( fapi2::delay( (mss::DELAY_1MS * 250), 200) ); + + // Poll for status response + // Note: the EXP_FW_BOOT_CONFIG command trains the OMI, which takes a + // significant amount of time. We're waiting 1ms between polls, and poll for 100 loops, + // which totals at least 100ms + FAPI_TRY(fw_status(i_target, DELAY_1MS, 100)); fapi_try_exit: return fapi2::current_err; @@ -260,23 +300,40 @@ inline fapi2::ReturnCode is_ready(const fapi2::Target<fapi2::TARGET_TYPE_OCMB_CH std::vector<uint8_t> l_cmd_id; fw_status_setup(l_size, l_cmd_id); - // We just ignore the data. We'll see FAPI2_RC_SUCCESS if - // the I2C returns an ACK. + // We'll see FAPI2_RC_SUCCESS if the I2C returns an ACK. + // We just ignore the data std::vector<uint8_t> l_data; return fapi2::getI2c(i_target, l_size, l_cmd_id, l_data); } /// +/// @brief EXP_FW_BYPASS_4SEC_TIMEOUT +/// @param[in] i_target the OCMB target +/// @return FAPI2_RC_SUCCESS iff okay +/// +inline fapi2::ReturnCode fw_bypass_download_window(const fapi2::Target<fapi2::TARGET_TYPE_OCMB_CHIP>& i_target) +{ + std::vector<uint8_t> l_cmd_id; + fw_bypass_download_window_setup(l_cmd_id); + + // We'll see FAPI2_RC_SUCCESS if the I2C returns an ACK. + return fapi2::putI2c(i_target, l_cmd_id); +} + +/// /// @brief Helper function for exp_check_for_ready /// @param[in] i_target the controller -/// @param[in] i_poll_count the number of times to run the fw_status command (default = 50) -/// @param[in] i_delay delay in ns between fw_status command attempts (default = 200ns) +/// @param[in] i_poll_count the number of times to run the fw_status command (default = 200) +/// @param[in] i_delay delay in ns between fw_status command attempts (default = 1ms) /// @return FAPI2_RC_SUCCESS iff ok /// inline fapi2::ReturnCode exp_check_for_ready_helper(const fapi2::Target<fapi2::TARGET_TYPE_OCMB_CHIP>& i_target, - const uint64_t i_poll_count = DEFAULT_POLL_LIMIT, - const uint64_t i_delay = 200) + const uint64_t i_poll_count = 200, + const uint64_t i_delay = DELAY_1MS) { + std::vector<uint8_t> l_data; + uint8_t l_boot_stage = 0; + // Using using default parameters from class, with overrides for delay and poll_count mss::poll_parameters l_poll_params(DELAY_10NS, 200, @@ -296,16 +353,37 @@ inline fapi2::ReturnCode exp_check_for_ready_helper(const fapi2::Target<fapi2::T "Failed to see an ACK from I2C -- polling timeout on %s", mss::c_str(i_target) ); - // We send the EXP_FW_STATUS command as a sanity check to see if it returns SUCCESS + // If we're already in RUNTIME_FW stage, due to fuse settings or running procedures manually, + // we can (and should) skip the bypass and polling here + FAPI_TRY( get_fw_status(i_target, l_data) ); + FAPI_TRY( status::get_boot_stage(i_target, l_data, l_boot_stage) ); + + if (l_boot_stage == boot_stages::RUNTIME_FW) + { + return fapi2::FAPI2_RC_SUCCESS; + } + + // MSCC explorer firmware arch spec 4.1.6.5 + // Boot ROM will wait 4 secs and will proceed for normal boot operation. During this time, + // I2C channel will be disabled and Host will see NACK on the bus for subsequent EXP_FW_STATUS + // command. + // Sending FW_BYPASS_4SEC_TIMEOUT command will bypass the 4 secs + // and immediately load the runtime firmware. + FAPI_TRY(fw_bypass_download_window(i_target)); + + // Loop again until we get an ACK from i2c FAPI_ASSERT( mss::poll(i_target, l_poll_params, [i_target]()->bool { - return mss::exp::i2c::fw_status(i_target) == fapi2::FAPI2_RC_SUCCESS; + return mss::exp::i2c::is_ready(i_target) == fapi2::FAPI2_RC_SUCCESS; }), - fapi2::MSS_EXP_STATUS_POLLING_TIMEOUT(). + fapi2::MSS_EXP_I2C_POLLING_TIMEOUT(). set_TARGET(i_target), - "Failed to see a successful return code -- polling timeout on %s", + "Failed to see an ACK from I2C -- polling timeout on %s", mss::c_str(i_target) ); + // Now poll the EXP_FW_STATUS command until it returns SUCCESS and RUNTIME_FW + FAPI_TRY(fw_status(i_target, i_delay, i_poll_count)); + return fapi2::FAPI2_RC_SUCCESS; fapi_try_exit: @@ -352,7 +430,7 @@ inline fapi2::ReturnCode fw_reg_write(const fapi2::Target<fapi2::TARGET_TYPE_OC i_addr, mss::fapi_pos(i_target)); // Check status of operation - FAPI_TRY(fw_status(i_target), + FAPI_TRY(fw_status(i_target, DELAY_1MS, 100), "Invalid Status after FW_REG_WRITE operation to 0x%.8X on OCMB w/ fapiPos = 0x%.8X", i_addr, mss::fapi_pos(i_target)); @@ -398,7 +476,7 @@ inline fapi2::ReturnCode fw_reg_read(const fapi2::Target<fapi2::TARGET_TYPE_OCMB i_addr, mss::fapi_pos(i_target)); // Check i2c status after operation - FAPI_TRY(fw_status(i_target), + FAPI_TRY(fw_status(i_target, DELAY_1MS, 100), "Invalid Status after FW_REG_ADDR_LATCH operation to 0x%.8X on OCMB w/ fapiPos = 0x%.8X", i_addr, mss::fapi_pos(i_target)); @@ -434,7 +512,7 @@ inline fapi2::ReturnCode fw_reg_read(const fapi2::Target<fapi2::TARGET_TYPE_OCMB FW_REG_ADDR_LATCH_SIZE, l_tmp_vector[0] ); // Check i2c status after operation - FAPI_TRY(fw_status(i_target), + FAPI_TRY(fw_status(i_target, DELAY_1MS, 100), "Invalid Status after FW_REG_READ operation to 0x%.8X on OCMB w/ fapiPos = 0x%.8X", i_addr, mss::fapi_pos(i_target)); diff --git a/src/import/chips/ocmb/explorer/procedures/hwp/memory/lib/shared/exp_consts.H b/src/import/chips/ocmb/explorer/procedures/hwp/memory/lib/shared/exp_consts.H index b2b93fedf..41f3ec3f7 100644 --- a/src/import/chips/ocmb/explorer/procedures/hwp/memory/lib/shared/exp_consts.H +++ b/src/import/chips/ocmb/explorer/procedures/hwp/memory/lib/shared/exp_consts.H @@ -182,14 +182,32 @@ namespace i2c /// enum cmd_id : uint8_t { - FW_BOOT_CONFIG = 0x01, - FW_STATUS = 0x02, - FW_REG_ADDR_LATCH = 0x03, - FW_REG_READ = 0x04, - FW_REG_WRITE = 0x05, - FW_DOWNLOAD = 0x06, - FW_CONT_REG_READ = 0x07, - FW_CONT_REG_WRITE = 0x08, + FW_BOOT_CONFIG = 0x01, + FW_STATUS = 0x02, + FW_REG_ADDR_LATCH = 0x03, + FW_REG_READ = 0x04, + FW_REG_WRITE = 0x05, + FW_DOWNLOAD = 0x06, + FW_CONT_REG_READ = 0x07, + FW_CONT_REG_WRITE = 0x08, + FW_BYPASS_4SEC_TIMEOUT = 0x09, + FW_PQM_LANE_SET = 0x0A, + FW_PQM_LANE_GET = 0x0B, + FW_PQM_FREQ_SET = 0x0C, + FW_PQM_FREQ_GET = 0x0D, + FW_PQM_LANE_TRAINING = 0x0E, + FW_PQM_TRAINING_RESET = 0x0F, + FW_PQM_RX_ADAPTATION_OBJ_READ = 0x10, + FW_PQM_RX_CALIBRATION_VALUE_READ = 0x11, + FW_PQM_CSU_CALIBRATION_VALUE_STATUS_READ = 0x12, + FW_PQM_PRBS_PATTERN_MODE_SET = 0x13, + FW_PQM_PRBS_USER_DEFINED_PATTERN_SET = 0x14, + FW_PQM_PRBS_MONITOR_CONTROL = 0x15, + FW_PQM_PRBS_GENERATOR_CONTROL = 0x16, + FW_PQM_PRBS_ERR_COUNT_READ = 0x17, + FW_PQM_HORIZONTAL_BATHTUB_GET = 0x18, + FW_PQM_VERTICAL_BATHTUB_GET = 0x19, + FW_PQM_2D_BATHTUB_GET = 0x1A, }; /// |