diff options
author | Chris Steffen <cwsteffen@us.ibm.com> | 2017-04-24 13:09:57 -0500 |
---|---|---|
committer | Christian R. Geddes <crgeddes@us.ibm.com> | 2017-08-30 13:34:43 -0400 |
commit | 7901cf9e10727a671930cd0d3b2ea1d844471d74 (patch) | |
tree | 5d3de1e047e9a6faa01408412e3b4354015c0ee2 /src/import/chips/p9/procedures/hwp/io | |
parent | e5eae5a0d869c729b5cbd827de2a7b6fb4b85461 (diff) | |
download | talos-hostboot-7901cf9e10727a671930cd0d3b2ea1d844471d74.tar.gz talos-hostboot-7901cf9e10727a671930cd0d3b2ea1d844471d74.zip |
DMI / CEN IO Level 1 Procedures
Change-Id: I9de45364707b10d11860c8305a43327cc2033311
Original-Change-Id: I21cf3398d0a924b17078e3e6232b1fcb2ae83206
Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/39608
Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com>
Tested-by: Hostboot CI <hostboot-ci+hostboot@us.ibm.com>
Reviewed-by: Gary A. Peterson <garyp@us.ibm.com>
Dev-Ready: Gary A. Peterson <garyp@us.ibm.com>
Reviewed-by: Benjamin Gass <bgass@us.ibm.com>
Reviewed-by: Richard J. Knight <rjknight@us.ibm.com>
Reviewed-by: Jennifer A. Stofer <stofer@us.ibm.com>
Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/45323
Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com>
Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com>
Reviewed-by: Christian R. Geddes <crgeddes@us.ibm.com>
Diffstat (limited to 'src/import/chips/p9/procedures/hwp/io')
6 files changed, 1761 insertions, 0 deletions
diff --git a/src/import/chips/p9/procedures/hwp/io/p9_io_dmi_dccal.C b/src/import/chips/p9/procedures/hwp/io/p9_io_dmi_dccal.C new file mode 100644 index 000000000..d21fe24fe --- /dev/null +++ b/src/import/chips/p9/procedures/hwp/io/p9_io_dmi_dccal.C @@ -0,0 +1,792 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/import/chips/p9/procedures/hwp/io/p9_io_dmi_dccal.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +/// +/// @file p9_io_dmi_dccal.C +/// @brief Train the Link. +///----------------------------------------------------------------------------- +/// *HWP HWP Owner : Chris Steffen <cwsteffen@us.ibm.com> +/// *HWP HWP Backup Owner : Gary Peterson <garyp@us.ibm.com> +/// *HWP FW Owner : Jamie Knight <rjknight@us.ibm.com> +/// *HWP Team : IO +/// *HWP Level : 1 +/// *HWP Consumed by : FSP:HB +///----------------------------------------------------------------------------- +/// +/// @verbatim +/// High-level procedure flow: +/// +/// Run Dccal +/// +/// Dccal is completed on all thin/thick PHYs: +/// - DMI(EDIP) +/// +/// Procedure Prereq: +/// - System clocks are running. +/// - Scominit Procedure is completed. +/// +/// @endverbatim +///---------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Includes +//----------------------------------------------------------------------------- +#include <p9_io_dmi_dccal.H> +#include <p9_io_scom.H> +#include <p9_io_regs.H> +#include <p9_io_common.H> + +//----------------------------------------------------------------------------- +// Function Declarations +//----------------------------------------------------------------------------- + + +/** + * @brief Tx Z Impedance Calibration State Machine + * @param[in] i_tgt FAPI2 Target + * @retval ReturnCode + */ +fapi2::ReturnCode tx_zcal_run_bus(const DMI_TGT i_tgt); + +/** + * @brief Tx Z Impedance Calibration + * @param[in] i_tgt FAPI2 Target + * @retval ReturnCode + */ +fapi2::ReturnCode tx_zcal_set_grp(const DMI_TGT i_tgt); + +/** + * @brief Rx Dc Calibration Poll + * @param[in] i_tgt FAPI2 Target + * @retval ReturnCode + */ +fapi2::ReturnCode rx_dccal_poll_grp(const DMI_TGT i_tgt); + +/** + * @brief Rx Dc Calibration Start + * @param[in] i_tgt FAPI2 Target + * @retval ReturnCode + */ +fapi2::ReturnCode rx_dccal_start_grp(const DMI_TGT i_tgt); + +//----------------------------------------------------------------------------- +// Function Definitions +//----------------------------------------------------------------------------- + +/** + * @brief A I/O EDI+ Procedure that runs Rx Dccal and Tx Z Impedance calibration + * on every EDI+ DMI Chiplet. + * @param[in] i_tgt Reference to DMI Target + * @return FAPI2_RC_SUCCESSS on success, error otherwise + */ +fapi2::ReturnCode p9_io_dmi_dccal(const DMI_TGT& i_tgt) +{ + FAPI_IMP("p9_io_dmi_dccal: I/O EDI+ Dmi Entering"); + + char l_tgtStr[fapi2::MAX_ECMD_STRING_LEN]; + fapi2::toString(i_tgt, l_tgtStr, fapi2::MAX_ECMD_STRING_LEN); + FAPI_DBG("I/O EDI+ Dmi Dccal %s", l_tgtStr); + /* + // Runs Tx Zcal on a per bus basis + FAPI_TRY(tx_zcal_run_bus(i_tgt), "I/O Edi+ Dmi Tx Z-Cal Run Bus Failed"); + + // Sets Tx Zcal Group Settings based on the bus results + FAPI_TRY(tx_zcal_set_grp(i_tgt, i_grp), "I/O Edi+ Dmi Tx Z-Cal Set Grp Failed"); + + // Starts Rx Dccal on a per group basis + FAPI_TRY(rx_dccal_start_grp(i_tgt, i_grp), "I/O Edi+ Dmi Rx DC Cal Start Failed"); + + // Checks/polls Rx Dccal on a per group basis + FAPI_TRY(rx_dccal_poll_grp(i_tgt, i_grp), "I/O Edi+ Dmi Rx DC Cal Poll Failed"); + + fapi_try_exit: + */ + FAPI_IMP("p9_io_dmi_dccal: I/O EDI+ Dmi Exiting"); + return fapi2::current_err; +} + +/** + * @brief Convert a 4R decimal value to a 1R thermometer code + * @param[in] i_4r_val 4R Value + * @retval Converted 1R Value + */ +uint32_t convert_4r(const uint32_t i_4r_val) +{ + // 1. Add 2 for averaging since we will truncate the last 2 bits + // 2. Divide by 4 to bring back to a 1r value + // 2. Convert the decimal number to number of bits set by shifting + // a 0x1 over by the amount and subtracting 1 + return ((0x1 << ((i_4r_val + 2) / 4)) - 1 ); +} + +uint32_t convert_4r_with_2r(const uint32_t i_4r_val, const uint8_t i_width) +{ + // Add 1 for rounding, then shift the 4r bit off. We now have a 2r equivalent + uint32_t l_2r_equivalent = (i_4r_val + 1) >> 0x1; + + // If the LSB of the 2r equivalent is on, then we need to set the 2r bit (MSB) + uint32_t l_2r_on = (l_2r_equivalent & 0x1); + + // Shift the 2r equivalent to a 1r value and convert to a thermometer code. + uint32_t l_1r_equivalent ((0x1 << (l_2r_equivalent >> 0x1)) - 1); + + // combine 1r equivalent thermometer code + the 2r MSB value. + return (l_2r_on << (i_width - 1)) | l_1r_equivalent ; +} + +/** + * @brief Tx Z Impedance Calibration Get Results + * @param[in] io_pval Tx Zcal P-value + * @param[in] io_nval Tx Zcal N-value + * @retval ReturnCode + */ +fapi2::ReturnCode tx_zcal_verify_results( + uint32_t& io_pval, + uint32_t& io_nval) +{ + // l_zcal_p and l_zcal_n are 9 bit registers + // These are also 4x of a 1R segment + const uint32_t ZCAL_MIN = 16 * 4; // 16 segments * 4 = 64 (0x40) + const uint32_t ZCAL_MAX = 33 * 4; // 33 segments * 4 = 132(0x84) + FAPI_IMP("tx_zcal_verify_results: I/O EDI+ Dmi Entering"); + + FAPI_DBG("tx_zcal_verify_results: Min/Max Allowed(0x%X,0x%X) Read Pval/Nval(0x%X,0x%X)", + ZCAL_MIN, ZCAL_MAX, + io_pval, io_nval); + + if(io_pval > ZCAL_MAX) + { + io_pval = ZCAL_MAX; + FAPI_ERR("tx_zcal_verify_results: Tx Zcal Pval(0x%X) > Max Allowed(0x%X)", + io_pval, ZCAL_MAX); + } + + if(io_nval > ZCAL_MAX) + { + io_nval = ZCAL_MAX; + FAPI_ERR("tx_zcal_verify_results: Tx Zcal Nval(0x%X) > Max Allowed(0x%X)", + io_nval, ZCAL_MAX); + } + + if(io_pval < ZCAL_MIN) + { + io_pval = ZCAL_MIN; + FAPI_ERR("tx_zcal_verify_results: Tx Zcal Pval(0x%X) < Min Allowed(0x%X)", + io_pval, ZCAL_MIN); + } + + if(io_nval < ZCAL_MIN) + { + io_nval = ZCAL_MIN; + FAPI_ERR("tx_zcal_verify_results: Tx Zcal Nval(0x%X) < Min Allowed(0x%X)", + io_nval, ZCAL_MIN); + } + + FAPI_IMP("tx_zcal_verify_results: I/O EDI+ Dmi Exiting"); + return fapi2::current_err; +} + +/** + * @brief Tx Z Impedance Calibration State Machine + * @param[in] i_tgt FAPI2 Target + * @retval ReturnCode + */ +fapi2::ReturnCode tx_zcal_run_bus(const DMI_TGT i_tgt) +{ + const uint64_t DLY_20MS = 20000000; + const uint64_t DLY_10US = 10000; + const uint64_t DLY_10MIL_CYCLES = 10000000; + const uint64_t DLY_1MIL_CYCLES = 1000000; + const uint32_t TIMEOUT = 200; + const uint8_t GRP0 = 0; + const uint8_t LN0 = 0; + uint32_t l_count = 0; + uint64_t l_data = 0; + uint8_t l_is_sim = 0; + + FAPI_IMP("tx_zcal_run_sm: I/O EDI+ Dmi Entering"); + + /////////////////////////////////////////////////////////////////////////// + /// Simulation Speed Up + /////////////////////////////////////////////////////////////////////////// + FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_IS_SIMULATION, fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), l_is_sim)); + + if(l_is_sim) + { + // To speed up simulation, xbus_unit model + pie driver + // without these settings: 50 million cycles + // with these settings: 13 million cycles + io::set(EDIP_TX_ZCAL_SM_MIN_VAL, 50, l_data); + io::set(EDIP_TX_ZCAL_SM_MAX_VAL, 52, l_data); + FAPI_TRY(io::write(EDIP_TX_IMPCAL_SWO2_PB, i_tgt, GRP0, LN0, l_data)); + } + + // Request to start Tx Impedance Calibration + // The Done bit is read only pulse, must use pie driver or system model in sim + FAPI_TRY(io::rmw(EDIP_TX_ZCAL_REQ, i_tgt, GRP0, LN0, 1), + "tx_zcal_run_sm: RMW Tx Zcal Req Failed"); + + // Delay before we start polling. 20ms was use from past p8 learning + FAPI_TRY(fapi2::delay(DLY_20MS, DLY_10MIL_CYCLES), + "tx_zcal_run_sm: Fapi Delay Failed."); + + // Poll Until Tx Impedance Calibration is done or errors out + FAPI_TRY(io::read(EDIP_TX_IMPCAL_PB, i_tgt, GRP0, LN0, l_data), + "tx_zcal_run_sm: Reading Tx Impcal Pb Failed"); + + while((++l_count < TIMEOUT) && + !(io::get(EDIP_TX_ZCAL_DONE, l_data) || io::get(EDIP_TX_ZCAL_ERROR, l_data))) + { + FAPI_DBG("tx_zcal_run_sm: I/O EDI+ Dmi Tx Zcal Poll, Count(%d/%d).", l_count, TIMEOUT); + + // Delay for 10us between polls for a total of 22ms. + FAPI_TRY(fapi2::delay(DLY_10US, DLY_1MIL_CYCLES), + "tx_zcal_run_sm: Fapi Delay Failed."); + + FAPI_TRY(io::read(EDIP_TX_IMPCAL_PB, i_tgt, GRP0, LN0, l_data), + "tx_zcal_run_sm: Reading Tx Impcal Pb Failed"); + } + + + if(io::get(EDIP_TX_ZCAL_DONE, l_data) == 1) + { + FAPI_DBG("tx_zcal_run_sm: I/O EDI+ Dmi Tx Zcal Poll Completed(%d/%d).", l_count, TIMEOUT); + } + else if(io::get(EDIP_TX_ZCAL_ERROR, l_data) == 1) + { + FAPI_ERR("tx_zcal_run_sm: WARNING: Tx Z Calibration Error"); + } + else + { + FAPI_ERR("tx_zcal_run_sm: WARNING: Tx Z Calibration Timeout: Loops(%d)", l_count); + } + +fapi_try_exit: + FAPI_IMP("tx_zcal_run_sm: I/O EDI+ Dmi Exiting"); + return fapi2::current_err; +} + +/** + * @brief Tx Z Impedance Calibration Apply Segments. The results of the Tx Impedance + * calibrationMargining and FFE Precursor + * @param[in] i_tgt FAPI2 Target + * @param[in] i_pval Tx Zcal P-value + * @param[in] i_nval Tx Zcal N-value + * @retval ReturnCode + */ +fapi2::ReturnCode tx_zcal_apply( + const DMI_TGT i_tgt, + const uint32_t i_pval, + const uint32_t i_nval) +{ + FAPI_IMP("tx_zcal_apply: I/O EDI+ Dmi Entering"); + const uint8_t GRP0 = 0; + const uint8_t LN0 = 0; + const uint8_t PRE_WIDTH = 5; + const uint8_t MAIN_WIDTH = 13; + // 4R Total = (1R * 4) + (2R * 2); + const uint32_t PRE_4R_TOTAL = (4 * 4) + (1 * 2); + const uint32_t MARGIN_4R_TOTAL = (8 * 4) + (0 * 2); + const uint32_t MAIN_4R_TOTAL = (12 * 4) + (1 * 2); + uint8_t l_margin_ratio = 0; + uint8_t l_ffe_pre_coef = 0; + uint32_t p_en_pre = 0; + uint32_t p_en_margin_pu = 0; + uint32_t p_en_margin_pd = 0; + uint32_t p_en_main = 0; + uint32_t p_sel_pre = 0; + uint32_t n_en_pre = 0; + uint32_t n_en_margin_pu = 0; + uint32_t n_en_margin_pd = 0; + uint32_t n_en_main = 0; + uint32_t n_sel_pre = 0; + uint32_t sel_margin_pu = 0; + uint32_t sel_margin_pd = 0; + uint32_t l_4r_pval = i_pval; + uint32_t l_4r_nval = i_nval; + + // Encoding of Margin Ratio and Tx FFE Precursor + // 100.00% = 128(0x80) / 128 + // 75.00% = 96(0x60) / 128 + // 50.00% = 64(0x40) / 128 + // 25.00% = 32(0x20) / 128 + // 4.67% = 6(0x06) / 128 + // 0.00% = 0(0x00) / 128 + + + // TODO Add DMI Attributes + // During normal operation we will not use margining :: min(0, 0%) max(0.5, 50%) + //FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_IO_DMI_TX_MARGIN_RATIO, i_tgt, l_margin_ratio)); + + // -4.8% FFE Precursor Tap Weight :: min(0.0, 0%) max(0.115, 11.5%) + //FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_IO_DMI_TX_FFE_PRECURSOR, i_tgt, l_ffe_pre_coef)); + + /////////////////////////////////////////////////////////////////////////// + // Set P val enables + // All Precursor Segments will always be enabled as the mininum number + // of segments is 16 bits enabled, while there are only 4 1R & 1 2R + // Precursor Segments. + p_en_pre = PRE_4R_TOTAL; + p_en_margin_pu = MARGIN_4R_TOTAL; + p_en_margin_pd = MARGIN_4R_TOTAL; + + l_4r_pval -= p_en_pre; + + // If # of segments is less than margin max, calculate correct margin bits, + // otherwise we will stick with setting the margins to the max. + if(l_4r_pval < (2 * MARGIN_4R_TOTAL)) + { + // If the l_4r_pval(running count of remaining 4r segments to apply), + // has a 2r segment that it needs to apply, we need to apply this to the + // main 2r bit. + if((l_4r_pval % 4) != 0) + { + p_en_main = 2; + l_4r_pval -= p_en_main; + } + + // Apply half of what we need to pd, then apply remaining to the pu. + // The pu will always be equal or +1 segment. + // We will divide the value by 4 to make a 1r segment count. Then we + // will again divide by 2, so we can split up between the pd & pu + // margins. This will also truncate the fraction, so that the extra + // can be applied to the pu. We then multiply by 4 to get it back to + // a 4r equivelant. *Note, the divide must be before the 4R multiplier + // in order to truncate. + p_en_margin_pd = (l_4r_pval / (4 * 2)) * 4; + p_en_margin_pu = l_4r_pval - p_en_margin_pd; + } + + // Apply the remaining segments to the main bank + p_en_main += l_4r_pval - p_en_margin_pu - p_en_margin_pd; + + // We should never have more segments than allowed since we check the results + // before we eneter this function. Although, if we do exceed the max main + // then we will set the main segments to the max. + if(p_en_main > MAIN_4R_TOTAL) + { + p_en_main = MAIN_4R_TOTAL; + } + + // Precursor FFE Select bits will be set as a percentage out of 128 + p_sel_pre = (i_pval * l_ffe_pre_coef) / 128; + + // We can only select as many precursor segments as we have enabled. + if(p_sel_pre > p_en_pre) + { + p_sel_pre = p_en_pre; + } + + /////////////////////////////////////////////////////////////////////////// + // Set N val enables + // All Precursor Segments will always be enabled as the mininum number + // of segments is 16 bits enabled, while there are only 4 1R & 1 2R + // Precursor Segments. + n_en_pre = PRE_4R_TOTAL; + n_en_margin_pu = MARGIN_4R_TOTAL; + n_en_margin_pd = MARGIN_4R_TOTAL; + + l_4r_nval -= n_en_pre; + + // If # of segments is less than margin max, calculate correct margin bits, + // otherwise we will stick with setting the margins to the max. + if(l_4r_nval < (2 * MARGIN_4R_TOTAL)) + { + // If the l_4r_nval(running count of remaining 4r segments to apply), + // has a 2r segment that it needs to apply, we need to apply this to the + // main 2r bit. + if((l_4r_nval % 4) != 0) + { + n_en_main = 2; + l_4r_nval -= n_en_main; + } + + // Apply half of what we need to pd, then apply remaining to the pu. + // The pu will always be equal or +1 segment. + // We will divide the value by 4 to make a 1r segment count. Then we + // will again divide by 2, so we can split up between the pd & pu + // margins. This will also truncate the fraction, so that the extra + // can be applied to the pu. We then multiply by 4 to get it back to + // a 4r equivelant. *Note, the divide must be before the 4R multiplier + // in order to truncate. + n_en_margin_pd = (l_4r_nval / (4 * 2)) * 4; + n_en_margin_pu = l_4r_nval - n_en_margin_pd; + } + + // Apply the remaining segments to the main bank + n_en_main += l_4r_nval - n_en_margin_pu - n_en_margin_pd; + + // We should never have more segments than allowed since we check the results + // before we eneter this function. Although, if we do exceed the max main + // then we will set the main segments to the max. + if(n_en_main > MAIN_4R_TOTAL) + { + n_en_main = MAIN_4R_TOTAL; + } + + // Precursor FFE Select bits will be set as a percentage out of 128 + n_sel_pre = (i_nval * l_ffe_pre_coef) / 128; + + // We can only select as many precursor segments as we have enabled. + if(n_sel_pre > n_en_pre) + { + n_sel_pre = n_en_pre; + } + + + /////////////////////////////////////////////////////////////////////////// + // Set Margin Selects + // l_margin_ratio(0-64) / 128 = (0 - 0.5) + // To calculate the margin selects, + // select = (P/N 4R Value * Margin Ratio(margin_val / 128)) / 2 + // The final divide by 2 is because we have a pu & a pd. + sel_margin_pu = (i_pval * l_margin_ratio) / (128 * 2); + + // We can only select as many margin segments as we have enabled. + if(sel_margin_pu > n_en_margin_pu) + { + sel_margin_pu = n_en_margin_pu; + } + + // We can only select as many margin segments as we have enabled. + if(sel_margin_pu > p_en_margin_pu) + { + sel_margin_pu = p_en_margin_pu; + } + + // l_margin_ratio(0-64) / 128 = (0 - 0.5) + // To calculate the margin selects, + // select = (P/N 4R Value * Margin Ratio(margin_val / 128)) / 2 + // The final divide by 2 is because we have a pu & a pd. + sel_margin_pd = (i_nval * l_margin_ratio) / (128 * 2); + + // We can only select as many margin segments as we have enabled. + if(sel_margin_pd > n_en_margin_pd) + { + sel_margin_pd = n_en_margin_pd; + } + + // We can only select as many margin segments as we have enabled. + if(sel_margin_pd > p_en_margin_pd) + { + sel_margin_pd = p_en_margin_pd; + } + + // Finally Make sure the margin pu / pd are the same. If not, take the + // lower select. + if(sel_margin_pu > sel_margin_pd) + { + sel_margin_pu = sel_margin_pd; + } + else if(sel_margin_pu < sel_margin_pd) + { + sel_margin_pd = sel_margin_pu; + } + + + + // We can write these registers without reading, since we are writing + // the entire register. To convert the 4R values to needed register values, + // we will add the appropriate amount and shift to convert to 1R or + // 1R + a 2R. + FAPI_TRY(io::rmw(EDIP_TX_PSEG_PRE_EN, i_tgt, GRP0, LN0, convert_4r_with_2r(p_en_pre, PRE_WIDTH))); + FAPI_TRY(io::rmw(EDIP_TX_PSEG_PRE_SEL, i_tgt, GRP0, LN0, convert_4r_with_2r(p_sel_pre, PRE_WIDTH))); + FAPI_TRY(io::rmw(EDIP_TX_NSEG_PRE_EN, i_tgt, GRP0, LN0, convert_4r_with_2r(n_en_pre, PRE_WIDTH))); + FAPI_TRY(io::rmw(EDIP_TX_NSEG_PRE_SEL, i_tgt, GRP0, LN0, convert_4r_with_2r(n_sel_pre, PRE_WIDTH))); + FAPI_TRY(io::rmw(EDIP_TX_PSEG_MARGINPD_EN, i_tgt, GRP0, LN0, convert_4r(p_en_margin_pd))); + FAPI_TRY(io::rmw(EDIP_TX_PSEG_MARGINPU_EN, i_tgt, GRP0, LN0, convert_4r(p_en_margin_pu))); + FAPI_TRY(io::rmw(EDIP_TX_NSEG_MARGINPD_EN, i_tgt, GRP0, LN0, convert_4r(n_en_margin_pd))); + FAPI_TRY(io::rmw(EDIP_TX_NSEG_MARGINPU_EN, i_tgt, GRP0, LN0, convert_4r(n_en_margin_pu))); + FAPI_TRY(io::rmw(EDIP_TX_MARGINPD_SEL, i_tgt, GRP0, LN0, convert_4r(sel_margin_pd))); + FAPI_TRY(io::rmw(EDIP_TX_MARGINPU_SEL, i_tgt, GRP0, LN0, convert_4r(sel_margin_pu))); + FAPI_TRY(io::rmw(EDIP_TX_PSEG_MAIN_EN, i_tgt, GRP0, LN0, convert_4r_with_2r(p_en_main, MAIN_WIDTH))); + FAPI_TRY(io::rmw(EDIP_TX_NSEG_MAIN_EN, i_tgt, GRP0, LN0, convert_4r_with_2r(n_en_main, MAIN_WIDTH))); + +fapi_try_exit: + FAPI_IMP("tx_zcal_apply: I/O EDI+ Dmi Exiting"); + return fapi2::current_err; +} + +/** + * @brief Tx Z Impedance Calibration + * @param[in] i_tgt FAPI2 Target + * @retval ReturnCode + */ +fapi2::ReturnCode tx_zcal_set_grp(const DMI_TGT i_tgt) +{ + FAPI_IMP("tx_zcal_set_grp: I/O EDI+ Dmi Entering"); + + const uint8_t GRP0 = 0; + const uint8_t LN0 = 0; + const uint32_t DEFAULT_SEGMENTS = 25 * 4; // Nominal 25 Segments 1R * 4 = 4R + uint32_t l_pval = DEFAULT_SEGMENTS; + uint32_t l_nval = DEFAULT_SEGMENTS; + uint64_t l_data = 0; + + + FAPI_TRY(io::read(EDIP_TX_IMPCAL_PB, i_tgt, GRP0, LN0, l_data), + "tx_zcal_run_sm: Reading Tx Impcal Pb Failed"); + + if(io::get(EDIP_TX_ZCAL_DONE, l_data) == 1) + { + FAPI_DBG("Using zCal Results."); + + FAPI_TRY(io::read(EDIP_TX_ZCAL_P, i_tgt, GRP0, LN0, l_data)); + + // We need to convert the 8R value to a 4R equivalent + l_pval = io::get(EDIP_TX_ZCAL_P, l_data) / 2; + + FAPI_TRY(io::read(EDIP_TX_ZCAL_N, i_tgt, GRP0, LN0, l_data)); + + // We need to convert the 8R value to a 4R equivalent + l_nval = io::get(EDIP_TX_ZCAL_N, l_data) / 2; + + + FAPI_TRY(tx_zcal_verify_results(l_pval, l_nval), "Tx Z Cal Verify Results Failed"); + } + else + { + FAPI_ERR("WARNING: Using Default Tx Zcal Segments."); + } + + // Convert the results of the zCal to actual segments. + FAPI_TRY(tx_zcal_apply(i_tgt, l_pval, l_nval), "Tx Zcal Apply Segments Failed"); + +fapi_try_exit: + FAPI_IMP("tx_zcal_set_grp: I/O EDI+ Dmi Exiting"); + return fapi2::current_err; +} + +/** + * @brief Rx Dc Calibration Set Lanes Invalid + * @param[in] i_tgt FAPI2 Target + * @param[in] i_data Data to Set Lanes Invalid + * @retval ReturnCode + */ +fapi2::ReturnCode set_lanes_invalid(const DMI_TGT i_tgt, const uint8_t i_data) +{ + const uint8_t GRP0 = 0; + const uint8_t DMI_LANES = 24; + + FAPI_IMP("set_lanes_invalid: I/O EDI+ Dmi Entering"); + + for(uint8_t lane = 0; lane < DMI_LANES; ++lane) + { + FAPI_TRY(io::rmw(EDIP_RX_LANE_INVALID, i_tgt, GRP0, lane, i_data)); + } + +fapi_try_exit: + FAPI_IMP("set_lanes_invalid: I/O EDI+ Dmi Exiting"); + return fapi2::current_err; +} + +/** + * @brief Start Cleanup Pll + * @param[in] i_tgt FAPI2 Target + * @retval ReturnCode + */ +fapi2::ReturnCode start_cleanup_pll(const DMI_TGT i_tgt) +{ + FAPI_IMP("start_cleanup_pll: I/O EDI+ Dmi Entering"); + const uint8_t LN0 = 0; + const uint8_t GRP0 = 0; + uint64_t reg_data = 0; + + FAPI_TRY(io::read(EDIP_RX_CTL_CNTL4_E_PG, i_tgt, GRP0, LN0, reg_data), + "read edip_rx_ctl_cntl4_e_pg failed"); + + io::set(EDIP_RX_WT_PLL_REFCLKSEL, 0x1, reg_data); + io::set(EDIP_RX_PLL_REFCLKSEL_SCOM_EN, 0x1, reg_data); + + FAPI_TRY(io::write(EDIP_RX_CTL_CNTL4_E_PG, i_tgt, GRP0, LN0, reg_data), + "write edip_rx_ctl_cntl4_e_pg failed"); + + FAPI_TRY(fapi2::delay(150000, 0), " Fapi Delay Failed."); + + FAPI_TRY(io::rmw(EDIP_RX_WT_CU_PLL_PGOOD, i_tgt, GRP0, LN0, 0x1), + "rmw edip_rx_wt_cu_pll_pgood failed"); + + FAPI_TRY(fapi2::delay(5000, 0), " Fapi Delay Failed."); + + +// The PLL Lock bit is not getting updated. According to AET it is locked. +#if 0 + FAPI_TRY(io::read(EDIP_RX_WT_CU_BYP_PLL_LOCK, i_tgt, i_group, LANE_00, reg_data), + "read edip_rx_wt_cu_byp_pll_lock failed"); + 0 + + FAPI_ASSERT((io::get(EDIP_RX_WT_CU_BYP_PLL_LOCK, reg_data) == 1), + fapi2::IO_XBUS_RX_CLEANUP_PLL_NOT_LOCKED().set_TARGET(i_tgt).set_GROUP(i_group), + "start_cleanup_pll: Cleanup Pll Not Locking"); +#endif + + +fapi_try_exit: + FAPI_IMP("start_cleanup_pll: I/O EDI+ Dmi Exiting"); + return fapi2::current_err; +} + +/** + * @brief Stop Cleanup Pll + * @param[in] i_tgt FAPI2 Target + * @retval ReturnCode + */ +fapi2::ReturnCode stop_cleanup_pll(const DMI_TGT i_tgt) +{ + FAPI_IMP("stop_cleanup_pll: I/O EDI+ Dmi Entering"); + const uint8_t GRP0 = 0; + const uint8_t LN0 = 0; + uint64_t reg_data = 0; + + FAPI_TRY(io::read(EDIP_RX_CTL_CNTL4_E_PG, i_tgt, GRP0, LN0, reg_data)); + + io::set(EDIP_RX_WT_PLL_REFCLKSEL, 0, reg_data); + io::set(EDIP_RX_PLL_REFCLKSEL_SCOM_EN, 0, reg_data); + io::set(EDIP_RX_WT_CU_PLL_PGOOD, 0, reg_data); + + FAPI_TRY(io::write(EDIP_RX_CTL_CNTL4_E_PG, i_tgt, GRP0, LN0, reg_data)); + + FAPI_TRY(fapi2::delay(110500, 0), " Fapi Delay Failed."); + +fapi_try_exit: + FAPI_IMP("stop_cleanup_pll: I/O EDI+ Dmi Exiting"); + return fapi2::current_err; +} + +/** + * @brief Rx Dc Calibration + * @param[in] i_tgt FAPI2 Target + * @retval ReturnCode + */ +fapi2::ReturnCode rx_dccal_start_grp(const DMI_TGT i_tgt) +{ + FAPI_IMP("rx_dccal_start_grp: I/O EDI+ Dmi Entering"); + const uint8_t GRP0 = 0; + const uint8_t LN0 = 0; + + /////////////////////////////////////////////////////////////////////////// + /// Simulation Speed Up + /////////////////////////////////////////////////////////////////////////// + //FAPI_TRY(p9_io_dmi_shorten_timers(i_tgt), "Shorten Timers Failed."); + + //////////////////////////////////////////////////////////////////////////// + /// Start Rx Dccal + //////////////////////////////////////////////////////////////////////////// + + // Must set lane invalid bit to 0 to run rx dccal, this enables us to run + // dccal on the specified lane. These bits are normally set by wiretest + // although we are not running that now. + FAPI_TRY(set_lanes_invalid(i_tgt, 0), "Error Setting Lane Invalid to 0"); + + // We must start the cleanup pll to have a clock that clocks the + // dccal logic. This function locks the rx cleanup pll to the internal + // grid clock reference. + FAPI_TRY(start_cleanup_pll(i_tgt), "rx_dc_cal: Starting Cleanup Pll"); + + // Clear the rx dccal done bit in case rx dccal was previously run. + FAPI_TRY(io::rmw(EDIP_RX_DC_CALIBRATE_DONE, i_tgt, GRP0, LN0, 0)); + + // Start DC Calibrate, this iniates the rx dccal state machine + FAPI_TRY(io::rmw(EDIP_RX_START_DC_CALIBRATE, i_tgt, GRP0, LN0, 1)); + + FAPI_DBG("I/O EDI+ Dmi Rx Dccal Complete"); + + +fapi_try_exit: + FAPI_IMP("rx_dccal_start_grp: I/O EDI+ Dmi Exiting"); + return fapi2::current_err; +} + + + + + +/** + * @brief Rx Dc Calibration + * @param[in] i_tgt FAPI2 Target + * @retval ReturnCode + */ +fapi2::ReturnCode rx_dccal_poll_grp(const DMI_TGT i_tgt) +{ + FAPI_IMP("rx_dccal_poll_grp: I/O EDI+ Dmi Entering"); + const uint8_t TIMEOUT = 200; + const uint64_t DLY_100MS = 100000000; + const uint64_t DLY_10MS = 10000000; + const uint64_t DLY_1MIL_CYCLES = 1000000; + const uint8_t GRP0 = 0; + const uint8_t LN0 = 0; + uint8_t l_poll_count = 0; + uint64_t l_data = 0; + + //////////////////////////////////////////////////////////////////////////// + /// Poll Rx Dccal + //////////////////////////////////////////////////////////////////////////// + // In the pervasive unit model, this takes 750,000,000 sim cycles to finish + // on a group. This equates to 30 loops with 25,000,000 delay each. + + // Delay before we start polling. 100ms was use from past p8 learning + FAPI_TRY(fapi2::delay(DLY_100MS, DLY_1MIL_CYCLES), + "rx_dc_cal_poll: Fapi Delay Failed."); + + do + { + FAPI_DBG("I/O EDI+ Dmi Rx Dccal Polling Count(%d/%d).", l_poll_count, TIMEOUT); + + FAPI_TRY(fapi2::delay(DLY_10MS, DLY_1MIL_CYCLES), "Fapi Delay Failed."); + + FAPI_TRY(io::read(EDIP_RX_DC_CALIBRATE_DONE, i_tgt, GRP0, LN0, l_data)); + } + while((++l_poll_count < TIMEOUT) && !io::get(EDIP_RX_DC_CALIBRATE_DONE, l_data)); + + // TODO Add Dmi Error + //FAPI_ASSERT((io::get(EDIP_RX_DC_CALIBRATE_DONE, l_data) == 1), + // fapi2::IO_DMI_RX_DCCAL_TIMEOUT().set_TARGET(i_tgt), + // "Rx Dccal Timeout: Loops(%d) delay(%d ns, %d cycles)", + // l_poll_count, DLY_10MS, DLY_1MIL_CYCLES); + + FAPI_DBG("I/O EDI+ Dmi Rx Dccal Successful."); + + //////////////////////////////////////////////////////////////////////////// + /// Cleanup Rx Dccal + //////////////////////////////////////////////////////////////////////////// + + // Stop DC Calibrate + FAPI_TRY(io::rmw(EDIP_RX_START_DC_CALIBRATE, i_tgt, GRP0, LN0, 0)); + + // We must stop the cleanup pll to cleanup after ourselves. Wiretest will + // turn this back on. This function will turn off the cleanup pll and + // switch it back to bus clock reference. + FAPI_TRY(stop_cleanup_pll(i_tgt), "rx_dc_cal: Stopping Cleanup Pll"); + + // Restore the invalid bits, Wiretest will modify these as training is run. + FAPI_TRY(set_lanes_invalid(i_tgt, 1), "Error Setting Lane Invalid to 1"); + + FAPI_DBG("I/O EDI+ Dmi Rx Dccal Complete"); + + +fapi_try_exit: + FAPI_IMP("rx_dccal_poll_grp: I/O EDI+ Dmi Exiting"); + return fapi2::current_err; +} + diff --git a/src/import/chips/p9/procedures/hwp/io/p9_io_dmi_dccal.H b/src/import/chips/p9/procedures/hwp/io/p9_io_dmi_dccal.H new file mode 100644 index 000000000..0ff619f18 --- /dev/null +++ b/src/import/chips/p9/procedures/hwp/io/p9_io_dmi_dccal.H @@ -0,0 +1,63 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/import/chips/p9/procedures/hwp/io/p9_io_dmi_dccal.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +/// +/// @file p9_io_dmi_dccal.H +/// @brief Run Dccal on the link. +///----------------------------------------------------------------------------- +/// *HWP HWP Owner : Chris Steffen <cwsteffen@us.ibm.com> +/// *HWP HWP Backup Owner : Gary Peterson <garyp@us.ibm.com> +/// *HWP FW Owner : Jamie Knight <rjknight@us.ibm.com> +/// *HWP Team : IO +/// *HWP Level : 1 +/// *HWP Consumed by : FSP:HB +///----------------------------------------------------------------------------- + +#ifndef _P9_IO_DMI_DCCAL_H +#define _P9_IO_DMI_DCCAL_H + +//----------------------------------------------------------------------------- +// fapi2 Includes +//----------------------------------------------------------------------------- +#include <fapi2.H> + +typedef fapi2::Target<fapi2::TARGET_TYPE_DMI> DMI_TGT; +typedef fapi2::ReturnCode (*p9_io_dmi_dccal_FP_t)(const DMI_TGT); + +extern "C" +{ + + /** + * @brief A I/O EDI+ Procedure that runs Rx Dccal and Tx Z Impedance calibration + * on every EDI+ DMI chiplet. + * + * @param[in] i_tgt Reference to DMI chiplet target + * + * @return FAPI2_RC_SUCCESS on success, error otherwise + */ + fapi2::ReturnCode p9_io_dmi_dccal(const DMI_TGT& i_tgt); + +} // extern "C" + +#endif // _P9_IO_DMI_DCCAL_H diff --git a/src/import/chips/p9/procedures/hwp/io/p9_io_dmi_dccal.mk b/src/import/chips/p9/procedures/hwp/io/p9_io_dmi_dccal.mk new file mode 100644 index 000000000..923174216 --- /dev/null +++ b/src/import/chips/p9/procedures/hwp/io/p9_io_dmi_dccal.mk @@ -0,0 +1,27 @@ +# IBM_PROLOG_BEGIN_TAG +# This is an automatically generated prolog. +# +# $Source: src/import/chips/p9/procedures/hwp/io/p9_io_dmi_dccal.mk $ +# +# OpenPOWER HostBoot Project +# +# Contributors Listed Below - COPYRIGHT 2015,2017 +# [+] International Business Machines Corp. +# +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. See the License for the specific language governing +# permissions and limitations under the License. +# +# IBM_PROLOG_END_TAG +PROCEDURE=p9_io_dmi_dccal +OBJS+=p9_io_common.o +$(call BUILD_PROCEDURE) diff --git a/src/import/chips/p9/procedures/hwp/io/p9_io_dmi_linktrain.C b/src/import/chips/p9/procedures/hwp/io/p9_io_dmi_linktrain.C new file mode 100644 index 000000000..f2a250203 --- /dev/null +++ b/src/import/chips/p9/procedures/hwp/io/p9_io_dmi_linktrain.C @@ -0,0 +1,778 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/import/chips/p9/procedures/hwp/io/p9_io_dmi_linktrain.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +/// +/// @file p9_io_dmi_linktrain.C +/// @brief I/O Link Training on the Dmi Links. +///----------------------------------------------------------------------------- +/// *HWP HWP Owner : Chris Steffen <cwsteffen@us.ibm.com> +/// *HWP HWP Backup Owner : Gary Peterson <garyp@us.ibm.com> +/// *HWP FW Owner : Jamie Knight <rjknight@us.ibm.com> +/// *HWP Team : IO +/// *HWP Level : 2 +/// *HWP Consumed by : FSP:HB +///----------------------------------------------------------------------------- +/// +/// @verbatim +/// High-level procedure flow: +/// +/// Train the link through several steps (WDERF). +/// - (W) Wiretest +/// - (D) Deskew +/// - (E) Eye Optimization +/// - (R) Repair/Recal +/// - (F) Functional +/// +/// Procedure Prereq: +/// - System clocks are running. +/// - Scominit Procedure is completed. +/// - Dccal Procedure is completed. +/// +/// @endverbatim +///---------------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +// Defines +//------------------------------------------------------------------------------ + +//----------------------------------------------------------------------------- +// Includes +//----------------------------------------------------------------------------- +#include <p9_io_dmi_linktrain.H> + +// TODO Create DMI Clear Firs File +//#include <p9_io_dmi_clear_firs.H> + +#include <p9_io_scom.H> +#include <p9_io_regs.H> +#include <p9_io_common.H> + +//----------------------------------------------------------------------------- +// Definitions +//----------------------------------------------------------------------------- + +/** + * @brief I/O EDI+ Training Substeps + */ +enum class State +{ + NONE = 0x00000000, + WIRETEST = 0x00000001, + DESKEW = 0x00000002, + EYEOPT = 0x00000004, + REPAIR = 0x00000008, + FUNCTIONAL = 0x00000010, + WDERF = 0x0000001F +}; +inline State operator& (const State& a, const State& b) +{ + return static_cast<State>(static_cast<uint8_t>(a) & static_cast<uint8_t>(b)); +} + +/** + * @brief Adds I/O FFDC Link data to the Error + * @param[in] i_mtgt Master Target + * @param[in] i_stgt Slave Target + * @param[in] i_grp Clock Group + * @retval fapi2::ReturnCode + */ +fapi2::ReturnCode add_linktrain_ffdc( + const DMI_TGT i_mtgt, + const CN_TGT i_stgt, + const bool i_timeout) +{ + /* + const uint8_t LN0 = 0; + const uint32_t INVALID_FFDC = 0xFFFFFFFF; + uint64_t l_data = 0; + + // Return Codes: + // l_ffdc_rc -- Passed by reference and is used to create the ffdc. This return code + // will be returned at the end of the function + fapi2::ReturnCode l_ffdc_rc = 0; + + // l_rc -- Used during the data collection and will not cause the function to fail, + // only will cause invalid data if the scoms fail. + fapi2::ReturnCode l_rc = 0; + + // Create the FFDC Error + fapi2::IO_DMI_LINKTRAIN_ERROR ffdc(fapi2::FAPI2_ERRL_SEV_UNRECOVERABLE, l_ffdc_rc); + + ffdc.set_M_TARGET(i_mtgt); + ffdc.set_S_TARGET(i_stgt); + ffdc.set_GROUP (i_grp ); + ffdc.set_TIMEOUT (i_timeout); + + /////////////////////////////////////////////////////////////////////////// + // Master Common + /////////////////////////////////////////////////////////////////////////// + l_rc = io::read(EDIP_RX_CTL_CNTL1_E_PG, i_mtgt, i_grp, LN0, l_data); + ffdc.set_M_WDERF_START (io::get(EDIP_RX_START_WDERF_ALIAS, l_data)); + + if(l_rc != fapi2::FAPI2_RC_SUCCESS) + { + ffdc.set_M_WDERF_START (INVALID_FFDC); + l_rc = fapi2::FAPI2_RC_SUCCESS; + } + + l_rc = io::read(EDIP_RX_CTL_STAT1_E_PG, i_mtgt, i_grp, LN0, l_data); + ffdc.set_M_WDERF_DONE (io::get(EDIP_RX_WDERF_DONE_ALIAS, l_data)); + ffdc.set_M_WDERF_FAILED(io::get(EDIP_RX_WDERF_FAILED_ALIAS, l_data)); + + if(l_rc != fapi2::FAPI2_RC_SUCCESS) + { + ffdc.set_M_WDERF_DONE (INVALID_FFDC); + ffdc.set_M_WDERF_FAILED(INVALID_FFDC); + l_rc = fapi2::FAPI2_RC_SUCCESS; + } + + l_rc = io::read(EDIP_RX_CTL_STAT2_E_PG, i_mtgt, i_grp, LN0, l_data); + ffdc.set_M_LANE_BAD_0_15(io::get(EDIP_RX_LANE_BAD_VEC_0_15, l_data)); + + if(l_rc != fapi2::FAPI2_RC_SUCCESS) + { + ffdc.set_M_LANE_BAD_0_15(INVALID_FFDC); + l_rc = fapi2::FAPI2_RC_SUCCESS; + } + + + l_rc = io::read(EDIP_RX_CTL_STAT4_E_PG, i_mtgt, i_grp, LN0, l_data); + ffdc.set_M_LANE_BAD_16_23(io::get(EDIP_RX_LANE_BAD_VEC_16_23, l_data)); + + if(l_rc != fapi2::FAPI2_RC_SUCCESS) + { + ffdc.set_M_LANE_BAD_16_23(INVALID_FFDC); + l_rc = fapi2::FAPI2_RC_SUCCESS; + } + + l_rc = io::read(EDIP_RX_CTL_MODE11_E_PG, i_mtgt, i_grp, LN0, l_data); + ffdc.set_M_LANE_DISABLED_VEC_0_15(io::get(EDIP_RX_LANE_DISABLED_VEC_0_15, l_data)); + + if(l_rc != fapi2::FAPI2_RC_SUCCESS) + { + ffdc.set_M_LANE_DISABLED_VEC_0_15(INVALID_FFDC); + l_rc = fapi2::FAPI2_RC_SUCCESS; + } + + l_rc = io::read(EDIP_RX_CTL_MODE12_E_PG, i_mtgt, i_grp, LN0, l_data); + ffdc.set_M_LANE_DISABLED_VEC_16_23(io::get(EDIP_RX_LANE_DISABLED_VEC_16_23, l_data)); + + if(l_rc != fapi2::FAPI2_RC_SUCCESS) + { + ffdc.set_M_LANE_DISABLED_VEC_16_23(INVALID_FFDC); + l_rc = fapi2::FAPI2_RC_SUCCESS; + } + + l_rc = io::read(EDIP_RX_GLBSM_STAT1_E_PG, i_mtgt, i_grp, LN0, l_data); + ffdc.set_M_MAIN_INIT_STATE(io::get(EDIP_RX_MAIN_INIT_STATE, l_data)); + + if(l_rc != fapi2::FAPI2_RC_SUCCESS) + { + ffdc.set_M_MAIN_INIT_STATE(INVALID_FFDC); + l_rc = fapi2::FAPI2_RC_SUCCESS; + } + + /////////////////////////////////////////////////////////////////////////// + // Master Wiretest + /////////////////////////////////////////////////////////////////////////// + l_rc = io::read(EDIP_RX_GLBSM_STAT1_E_PG, i_mtgt, i_grp, LN0, l_data); + ffdc.set_M_WIRETEST_WTM_STATE(io::get(EDIP_RX_WTM_STATE, l_data)); + ffdc.set_M_WIRETEST_WTR_STATE(io::get(EDIP_RX_WTR_STATE, l_data)); + + if(l_rc != fapi2::FAPI2_RC_SUCCESS) + { + ffdc.set_M_WIRETEST_WTM_STATE(INVALID_FFDC); + ffdc.set_M_WIRETEST_WTR_STATE(INVALID_FFDC); + l_rc = fapi2::FAPI2_RC_SUCCESS; + } + + l_rc = io::read(EDIP_RX_CTL_STAT3_EO_PG, i_mtgt, i_grp, LN0, l_data); + ffdc.set_M_WIRETEST_WTL_SM_STATUS(io::get(EDIP_RX_WTL_SM_STATUS, l_data)); + + if(l_rc != fapi2::FAPI2_RC_SUCCESS) + { + ffdc.set_M_WIRETEST_WTL_SM_STATUS(INVALID_FFDC); + l_rc = fapi2::FAPI2_RC_SUCCESS; + } + + l_rc = io::read(EDIP_RX_GLBSM_STAT2_E_PG, i_mtgt, i_grp, LN0, l_data); + ffdc.set_M_WTR_BAD_LANE_COUNT(io::get(EDIP_RX_WTR_BAD_LANE_COUNT, l_data)); + + if(l_rc != fapi2::FAPI2_RC_SUCCESS) + { + ffdc.set_M_WTR_BAD_LANE_COUNT(INVALID_FFDC); + l_rc = fapi2::FAPI2_RC_SUCCESS; + } + + l_rc = io::read(EDIP_RX_CTL_STAT5_E_PG, i_mtgt, i_grp, LN0, l_data); + ffdc.set_M_CLK_LANE_BAD_CODE (io::get(EDIP_RX_WT_CLK_LANE_BAD_CODE, l_data)); + ffdc.set_M_WT_CLK_LANE_INVERTED(io::get(EDIP_RX_WT_CLK_LANE_INVERTED, l_data)); + + if(l_rc != fapi2::FAPI2_RC_SUCCESS) + { + ffdc.set_M_CLK_LANE_BAD_CODE (INVALID_FFDC); + ffdc.set_M_WT_CLK_LANE_INVERTED(INVALID_FFDC); + l_rc = fapi2::FAPI2_RC_SUCCESS; + } + + /////////////////////////////////////////////////////////////////////////// + // Master Deskew + /////////////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////////////// + // Master Eye Optimization + /////////////////////////////////////////////////////////////////////////// + l_rc = io::read(EDIP_RX_GLBSM_STAT1_EO_PG, i_mtgt, i_grp, LN0, l_data); + ffdc.set_M_EYE_OPT_STATE(io::get(EDIP_RX_EYE_OPT_STATE, l_data)); + + if(l_rc != fapi2::FAPI2_RC_SUCCESS) + { + ffdc.set_M_EYE_OPT_STATE(INVALID_FFDC); + l_rc = fapi2::FAPI2_RC_SUCCESS; + } + + l_rc = io::read(EDIP_RX_CTL_CNTL13_EO_PG, i_mtgt, i_grp, LN0, l_data); + ffdc.set_M_HIST_MIN_EYE_WIDTH( io::get(EDIP_RX_HIST_MIN_EYE_WIDTH, l_data)); + ffdc.set_M_HIST_MIN_EYE_WIDTH_LANE( io::get(EDIP_RX_HIST_MIN_EYE_WIDTH_LANE, l_data)); + ffdc.set_M_HIST_MIN_EYE_WIDTH_VALID(io::get(EDIP_RX_HIST_MIN_EYE_WIDTH_VALID, l_data)); + + if(l_rc != fapi2::FAPI2_RC_SUCCESS) + { + ffdc.set_M_HIST_MIN_EYE_WIDTH (INVALID_FFDC); + ffdc.set_M_HIST_MIN_EYE_WIDTH_LANE (INVALID_FFDC); + ffdc.set_M_HIST_MIN_EYE_WIDTH_VALID(INVALID_FFDC); + l_rc = fapi2::FAPI2_RC_SUCCESS; + } + + /////////////////////////////////////////////////////////////////////////// + // Master Repair + /////////////////////////////////////////////////////////////////////////// + l_rc = io::read(EDIP_RX_GLBSM_STAT4_E_PG, i_mtgt, i_grp, LN0, l_data); + ffdc.set_M_RPR_STATE(io::get(EDIP_RX_RPR_STATE, l_data)); + + if(l_rc != fapi2::FAPI2_RC_SUCCESS) + { + ffdc.set_M_RPR_STATE(INVALID_FFDC); + l_rc = fapi2::FAPI2_RC_SUCCESS; + } + + l_rc = io::read(EDIP_RX_GLBSM_STAT9_E_PG, i_mtgt, i_grp, LN0, l_data); + ffdc.set_M_BAD_LANE1 (io::get(EDIP_RX_BAD_LANE1, l_data)); + ffdc.set_M_BAD_LANE2 (io::get(EDIP_RX_BAD_LANE2, l_data)); + ffdc.set_M_BAD_LANE_CODE(io::get(EDIP_RX_BAD_LANE_CODE, l_data)); + + if(l_rc != fapi2::FAPI2_RC_SUCCESS) + { + ffdc.set_M_BAD_LANE1 (INVALID_FFDC); + ffdc.set_M_BAD_LANE2 (INVALID_FFDC); + ffdc.set_M_BAD_LANE_CODE(INVALID_FFDC); + l_rc = fapi2::FAPI2_RC_SUCCESS; + } + + /////////////////////////////////////////////////////////////////////////// + // Master Functional Mode + /////////////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////////////// + // Slave Common + /////////////////////////////////////////////////////////////////////////// + l_rc = io::read(EDIP_RX_CTL_CNTL1_E_PG, i_stgt, i_grp, LN0, l_data); + ffdc.set_S_WDERF_START (io::get(EDIP_RX_START_WDERF_ALIAS, l_data)); + + if(l_rc != fapi2::FAPI2_RC_SUCCESS) + { + ffdc.set_S_WDERF_START (INVALID_FFDC); + l_rc = fapi2::FAPI2_RC_SUCCESS; + } + + l_rc = io::read(EDIP_RX_CTL_STAT1_E_PG, i_stgt, i_grp, LN0, l_data); + ffdc.set_S_WDERF_DONE (io::get(EDIP_RX_WDERF_DONE_ALIAS, l_data)); + ffdc.set_S_WDERF_FAILED(io::get(EDIP_RX_WDERF_FAILED_ALIAS, l_data)); + + if(l_rc != fapi2::FAPI2_RC_SUCCESS) + { + ffdc.set_S_WDERF_DONE (INVALID_FFDC); + ffdc.set_S_WDERF_FAILED(INVALID_FFDC); + l_rc = fapi2::FAPI2_RC_SUCCESS; + } + + l_rc = io::read(EDIP_RX_CTL_STAT2_E_PG, i_stgt, i_grp, LN0, l_data); + ffdc.set_S_LANE_BAD_0_15(io::get(EDIP_RX_LANE_BAD_VEC_0_15, l_data)); + + if(l_rc != fapi2::FAPI2_RC_SUCCESS) + { + ffdc.set_S_LANE_BAD_0_15(INVALID_FFDC); + l_rc = fapi2::FAPI2_RC_SUCCESS; + } + + + l_rc = io::read(EDIP_RX_CTL_STAT4_E_PG, i_stgt, i_grp, LN0, l_data); + ffdc.set_S_LANE_BAD_16_23(io::get(EDIP_RX_LANE_BAD_VEC_16_23, l_data)); + + if(l_rc != fapi2::FAPI2_RC_SUCCESS) + { + ffdc.set_S_LANE_BAD_16_23(INVALID_FFDC); + l_rc = fapi2::FAPI2_RC_SUCCESS; + } + + l_rc = io::read(EDIP_RX_CTL_MODE11_E_PG, i_stgt, i_grp, LN0, l_data); + ffdc.set_S_LANE_DISABLED_VEC_0_15(io::get(EDIP_RX_LANE_DISABLED_VEC_0_15, l_data)); + + if(l_rc != fapi2::FAPI2_RC_SUCCESS) + { + ffdc.set_S_LANE_DISABLED_VEC_0_15(INVALID_FFDC); + l_rc = fapi2::FAPI2_RC_SUCCESS; + } + + l_rc = io::read(EDIP_RX_CTL_MODE12_E_PG, i_stgt, i_grp, LN0, l_data); + ffdc.set_S_LANE_DISABLED_VEC_16_23(io::get(EDIP_RX_LANE_DISABLED_VEC_16_23, l_data)); + + if(l_rc != fapi2::FAPI2_RC_SUCCESS) + { + ffdc.set_S_LANE_DISABLED_VEC_16_23(INVALID_FFDC); + l_rc = fapi2::FAPI2_RC_SUCCESS; + } + + l_rc = io::read(EDIP_RX_GLBSM_STAT1_E_PG, i_stgt, i_grp, LN0, l_data); + ffdc.set_S_MAIN_INIT_STATE(io::get(EDIP_RX_MAIN_INIT_STATE, l_data)); + + if(l_rc != fapi2::FAPI2_RC_SUCCESS) + { + ffdc.set_S_MAIN_INIT_STATE(INVALID_FFDC); + l_rc = fapi2::FAPI2_RC_SUCCESS; + } + + /////////////////////////////////////////////////////////////////////////// + // Slave Wiretest + /////////////////////////////////////////////////////////////////////////// + l_rc = io::read(EDIP_RX_GLBSM_STAT1_E_PG, i_stgt, i_grp, LN0, l_data); + ffdc.set_S_WIRETEST_WTM_STATE(io::get(EDIP_RX_WTM_STATE, l_data)); + ffdc.set_S_WIRETEST_WTR_STATE(io::get(EDIP_RX_WTR_STATE, l_data)); + + if(l_rc != fapi2::FAPI2_RC_SUCCESS) + { + ffdc.set_S_WIRETEST_WTM_STATE(INVALID_FFDC); + ffdc.set_S_WIRETEST_WTR_STATE(INVALID_FFDC); + l_rc = fapi2::FAPI2_RC_SUCCESS; + } + + l_rc = io::read(EDIP_RX_CTL_STAT3_EO_PG, i_stgt, i_grp, LN0, l_data); + ffdc.set_S_WIRETEST_WTL_SM_STATUS(io::get(EDIP_RX_WTL_SM_STATUS, l_data)); + + if(l_rc != fapi2::FAPI2_RC_SUCCESS) + { + ffdc.set_S_WIRETEST_WTL_SM_STATUS(INVALID_FFDC); + l_rc = fapi2::FAPI2_RC_SUCCESS; + } + + l_rc = io::read(EDIP_RX_GLBSM_STAT2_E_PG, i_stgt, i_grp, LN0, l_data); + ffdc.set_S_WTR_BAD_LANE_COUNT(io::get(EDIP_RX_WTR_BAD_LANE_COUNT, l_data)); + + if(l_rc != fapi2::FAPI2_RC_SUCCESS) + { + ffdc.set_S_WTR_BAD_LANE_COUNT(INVALID_FFDC); + l_rc = fapi2::FAPI2_RC_SUCCESS; + } + + l_rc = io::read(EDIP_RX_CTL_STAT5_E_PG, i_stgt, i_grp, LN0, l_data); + ffdc.set_S_CLK_LANE_BAD_CODE (io::get(EDIP_RX_WT_CLK_LANE_BAD_CODE, l_data)); + ffdc.set_S_WT_CLK_LANE_INVERTED(io::get(EDIP_RX_WT_CLK_LANE_INVERTED, l_data)); + + if(l_rc != fapi2::FAPI2_RC_SUCCESS) + { + ffdc.set_S_CLK_LANE_BAD_CODE (INVALID_FFDC); + ffdc.set_S_WT_CLK_LANE_INVERTED(INVALID_FFDC); + l_rc = fapi2::FAPI2_RC_SUCCESS; + } + + /////////////////////////////////////////////////////////////////////////// + // Slave Deskew + /////////////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////////////// + // Slave Eye Optimization + /////////////////////////////////////////////////////////////////////////// + l_rc = io::read(EDIP_RX_GLBSM_STAT1_EO_PG, i_stgt, i_grp, LN0, l_data); + ffdc.set_S_EYE_OPT_STATE(io::get(EDIP_RX_EYE_OPT_STATE, l_data)); + + if(l_rc != fapi2::FAPI2_RC_SUCCESS) + { + ffdc.set_S_EYE_OPT_STATE(INVALID_FFDC); + l_rc = fapi2::FAPI2_RC_SUCCESS; + } + + l_rc = io::read(EDIP_RX_CTL_CNTL13_EO_PG, i_stgt, i_grp, LN0, l_data); + ffdc.set_S_HIST_MIN_EYE_WIDTH( io::get(EDIP_RX_HIST_MIN_EYE_WIDTH, l_data)); + ffdc.set_S_HIST_MIN_EYE_WIDTH_LANE( io::get(EDIP_RX_HIST_MIN_EYE_WIDTH_LANE, l_data)); + ffdc.set_S_HIST_MIN_EYE_WIDTH_VALID(io::get(EDIP_RX_HIST_MIN_EYE_WIDTH_VALID, l_data)); + + if(l_rc != fapi2::FAPI2_RC_SUCCESS) + { + ffdc.set_S_HIST_MIN_EYE_WIDTH (INVALID_FFDC); + ffdc.set_S_HIST_MIN_EYE_WIDTH_LANE (INVALID_FFDC); + ffdc.set_S_HIST_MIN_EYE_WIDTH_VALID(INVALID_FFDC); + l_rc = fapi2::FAPI2_RC_SUCCESS; + } + + /////////////////////////////////////////////////////////////////////////// + // Slave Repair + /////////////////////////////////////////////////////////////////////////// + l_rc = io::read(EDIP_RX_GLBSM_STAT4_E_PG, i_stgt, i_grp, LN0, l_data); + ffdc.set_S_RPR_STATE(io::get(EDIP_RX_RPR_STATE, l_data)); + + if(l_rc != fapi2::FAPI2_RC_SUCCESS) + { + ffdc.set_S_RPR_STATE(INVALID_FFDC); + l_rc = fapi2::FAPI2_RC_SUCCESS; + } + + l_rc = io::read(EDIP_RX_GLBSM_STAT9_E_PG, i_stgt, i_grp, LN0, l_data); + ffdc.set_S_BAD_LANE1 (io::get(EDIP_RX_BAD_LANE1, l_data)); + ffdc.set_S_BAD_LANE2 (io::get(EDIP_RX_BAD_LANE2, l_data)); + ffdc.set_S_BAD_LANE_CODE(io::get(EDIP_RX_BAD_LANE_CODE, l_data)); + + if(l_rc != fapi2::FAPI2_RC_SUCCESS) + { + ffdc.set_S_BAD_LANE1 (INVALID_FFDC); + ffdc.set_S_BAD_LANE2 (INVALID_FFDC); + ffdc.set_S_BAD_LANE_CODE(INVALID_FFDC); + l_rc = fapi2::FAPI2_RC_SUCCESS; + } + + /////////////////////////////////////////////////////////////////////////// + // Slave Functional Mode + /////////////////////////////////////////////////////////////////////////// + + // Log FFDC + ffdc.execute(); + + return l_ffdc_rc; + */ + return fapi2::FAPI2_RC_SUCCESS; +} + +/** + * @brief Starts I/O Training on Centuar (EDI). The slave target must start + * training before the master. This function also assumes that dccal(tx + * impedance calibration and rx offset calibration) are complete. + * @param[in] i_tgt Fapi2 Target + * @param[in] i_wderf Represents which training substeps are run. + * @retval fapi2::ReturnCode + */ +fapi2::ReturnCode linktrain_start(const CN_TGT i_tgt, const State i_wderf) +{ + const uint8_t GRP0 = 0; + const uint8_t LN0 = 0; + return io::rmw(EDIP_RX_START_WDERF_ALIAS, i_tgt, GRP0, LN0, static_cast<uint64_t>(i_wderf)); +} + + +/** + * @brief Starts I/O Training on DMI (EDI Plus). The slave target must start + * training before the master. This function also assumes that dccal(tx + * impedance calibration and rx offset calibration) are complete. + * @param[in] i_tgt Fapi2 Target + * @param[in] i_wderf Represents which training substeps are run. + * @retval fapi2::ReturnCode + */ +fapi2::ReturnCode linktrain_start(const DMI_TGT i_tgt, const State i_wderf) +{ + const uint8_t GRP0 = 0; + const uint8_t LN0 = 0; + return io::rmw(EDIP_RX_START_WDERF_ALIAS, i_tgt, GRP0, LN0, static_cast<uint64_t>(i_wderf)); +} + +/** + * @brief This function polls the EDI Plus training logic until the training + * is complete. During the case of an error/timeout, the code will log + * FFDC data, which is added to the original error. + * @param[in] i_mtgt Master Target + * @param[in] i_stgt Slave Target + * @param[in] i_started The started EDI/EDI Plus training substeps + * @retval fapi2::ReturnCode + */ +fapi2::ReturnCode linktrain_poll(const DMI_TGT i_mtgt, const CN_TGT i_stgt, const State i_started) +{ + FAPI_IMP("linktrain_poll: P9 I/O EDI+ DMI Entering"); + + const uint8_t MAXLOOPS = 100; + const uint64_t DELAY_1MS = 1000000; + const uint64_t DELAY_SIM_CYCLES = 2000000; // Set lower due to sim speed up + const uint8_t GRP0 = 0; + const uint8_t LN0 = 0; + uint8_t l_loops = 0; + uint64_t l_reg_data = 0; + State l_done_state = State::NONE; + State l_failed_state = State::NONE; + + // In the P9 EDI+ Xbus unit model, polling finishes in + // 17 loops @ 20 million cycles = 340 million cycles + // For hardware timeout, we used what was used in p8, 1ms @ 100 cycles for + // a max of 100ms to complete training. + while(++l_loops < MAXLOOPS) + { + // Get Done/Failed WDERF Status + FAPI_TRY(io::read(EDIP_RX_CTL_STAT1_E_PG, i_mtgt, GRP0, LN0, l_reg_data)); + l_done_state = static_cast<State>(io::get(EDIP_RX_WDERF_DONE_ALIAS, l_reg_data)); + l_failed_state = static_cast<State>(io::get(EDIP_RX_WDERF_FAILED_ALIAS, l_reg_data)); + + // Check if all substeps are complete + if(i_started == (i_started & l_done_state)) + { + break; + } + + // Check if any substeps have failed. + if(l_failed_state != State::NONE) + { + break; + } + + FAPI_TRY(fapi2::delay(DELAY_1MS, DELAY_SIM_CYCLES)); + } + + // Check the error conditions. + if(l_failed_state != State::NONE) + { + FAPI_ERR("I/O EDI+ DMI Link Training Failed."); + FAPI_TRY(add_linktrain_ffdc(i_mtgt, i_stgt, false)); + } + else if(i_started != (i_started & l_done_state)) + { + FAPI_ERR("I/O EDI+ DMI Link Training Timeout."); + FAPI_TRY(add_linktrain_ffdc(i_mtgt, i_stgt, true)); + } + else + { + FAPI_INF("linktrain_poll: P9 I/O EDI+ DMI Training Successful in %d loops.", l_loops); + } + +fapi_try_exit: + FAPI_IMP("linktrain_poll: P9 I/O EDI+ DMI Exiting"); + return fapi2::current_err; +} + + +/** + * @brief Enables the Tx Serializer Sync on DMI (EDI Plus). + * @param[in] i_mtgt Master Fapi2 Target + * @retval fapi2::ReturnCode + */ +fapi2::ReturnCode tx_serializer_sync_power_on(const DMI_TGT i_mtgt) +{ + FAPI_IMP("tx_serializer_sync_power_on: I/O EDI+ DMI Entering"); + const uint8_t DMI_TX_LANES = 17; + const uint8_t GRP0 = 0; + const uint8_t LN0 = 0; + + FAPI_TRY(io::rmw(EDIP_TX_CLK_UNLOAD_CLK_DISABLE, i_mtgt, GRP0, LN0, 0)); + FAPI_TRY(io::rmw(EDIP_TX_CLK_RUN_COUNT , i_mtgt, GRP0, LN0, 0)); + FAPI_TRY(io::rmw(EDIP_TX_CLK_RUN_COUNT , i_mtgt, GRP0, LN0, 1)); + FAPI_TRY(io::rmw(EDIP_TX_CLK_UNLOAD_CLK_DISABLE, i_mtgt, GRP0, LN0, 1)); + + for(uint8_t lane = 0; lane < DMI_TX_LANES; ++lane) + { + FAPI_TRY(io::rmw(EDIP_TX_UNLOAD_CLK_DISABLE, i_mtgt, GRP0, lane, 0x0)); + } + +fapi_try_exit: + FAPI_IMP("tx_serializer_sync_power_on: I/O EDI+ DMI Exiting"); + return fapi2::current_err; +} + +/** + * @brief Disables the Tx Serializer Sync on DMI (EDI Plus). + * @param[in] i_mtgt Master Fapi2 Target + * @retval fapi2::ReturnCode + */ +fapi2::ReturnCode tx_serializer_sync_power_off(const DMI_TGT i_mtgt) +{ + FAPI_IMP("tx_serializer_sync_power_off: I/O EDI+ DMI Entering"); + const uint8_t DMI_TX_LANES = 17; + const uint8_t GRP0 = 0; + + for(uint8_t lane = 0; lane < DMI_TX_LANES; ++lane) + { + FAPI_TRY(io::rmw(EDIP_TX_UNLOAD_CLK_DISABLE, i_mtgt, GRP0, lane, 0x1)); + } + +fapi_try_exit: + FAPI_IMP("tx_serializer_sync_power_off: I/O EDI+ DMI Exiting"); + return fapi2::current_err; +} + +/** + * @brief Reads bad lane vector data from the + * passed target and stores the data in the vector. + * @param[in] i_target Fapi2 Target + * @param[out] o_data Data of bad lane vector data + * @retval ReturnCode + */ +fapi2::ReturnCode get_dmi_bad_lane_data(const DMI_TGT i_tgt, uint32_t& o_data) +{ + FAPI_IMP("P9 I/O EDI+ DMI Entering"); + const uint8_t GRP0 = 0; + const uint8_t LN0 = 0; + uint64_t l_data = 0; + + FAPI_TRY(io::read(EDIP_RX_LANE_BAD_VEC_0_15, i_tgt, GRP0, LN0, l_data)); + o_data = (io::get(EDIP_RX_LANE_BAD_VEC_0_15, l_data) << 8) & 0x00FFFF00; + + FAPI_TRY(io::read(EDIP_RX_LANE_BAD_VEC_16_23, i_tgt, GRP0, LN0, l_data)); + o_data |= (io::get(EDIP_RX_LANE_BAD_VEC_16_23, l_data) & 0x000000FF); + +fapi_try_exit: + FAPI_IMP("P9 I/O EDI+ DMI Exiting"); + return fapi2::current_err; +} + +/** + * @brief Copmares the bad lane vector pre and post training. If the data is + * the same, then we will want to clear the firs, since the firs have already + * been recorded. + * @param[in] i_tgt Fapi2 Target + * @param[out] o_data Data Vector of bad lane vector data + * @retval ReturnCode + */ +fapi2::ReturnCode check_bad_lane_data( + const DMI_TGT i_tgt, + uint32_t i_pre_bad_lane_data, + uint32_t i_post_bad_lane_data) +{ + FAPI_IMP("P9 I/O EDI+ DMI Entering"); + const uint8_t GRP0 = 0; + const uint8_t LN0 = 0; + uint64_t l_data = 0; + + // If the bad lane vector matches pre to post training, then the same bad + // lanes that were previously found, were found again. These bad lanes have + // already been reported. So we will clear the first related to these bad + // lanes + if(i_pre_bad_lane_data == i_post_bad_lane_data) + { + FAPI_DBG("I/O EDI+ DMI Pre/Post Bad Lane Data Match"); + + // If the entire bad lane vector equals 0, then we don't need to clear + // any firs. + if(i_pre_bad_lane_data != 0) + { + FAPI_DBG("I/O EDI+ DMI Clearing Firs"); + + // TODO Create DMI Clear Firs File + //FAPI_TRY(p9_io_dmi_clear_firs(i_tgt, GRP0)); + + // Clear BUS0_SPARE_DEPLOYED (Bit 9). + FAPI_TRY(io::read(EDIP_SCOM_FIR_PB, i_tgt, GRP0, LN0, l_data)); + l_data &= 0xFF7FFFFFFFFFFFFFull; + FAPI_TRY(io::write(EDIP_SCOM_FIR_PB, i_tgt, GRP0, LN0, l_data)); + } + } + +fapi_try_exit: + FAPI_IMP("P9 I/O EDI+ DMI Exiting"); + return fapi2::current_err; +} + + +/** + * @brief A HWP that runs on every link of the DMI(EDI+) + * + * @param[in] i_mtgt Reference to the Master Target + * @param[in] i_stgt Reference to the Slave Target + * + * @return FAPI2_RC_SUCCESS on success, error otherwise + */ +fapi2::ReturnCode p9_io_dmi_linktrain(const DMI_TGT& i_mtgt, const CN_TGT& i_stgt) +{ + FAPI_IMP("p9_io_dmi_linktrain: P9 I/O EDI+ DMI Entering"); + + /* + uint32_t l_m_pre_bad_data = 0; + uint32_t l_m_post_bad_data = 0; + uint32_t l_s_pre_bad_data = 0; + uint32_t l_s_post_bad_data = 0; + + char l_mtgt_str[fapi2::MAX_ECMD_STRING_LEN]; + char l_stgt_str[fapi2::MAX_ECMD_STRING_LEN]; + fapi2::toString(i_mtgt, l_mtgt_str, fapi2::MAX_ECMD_STRING_LEN); + fapi2::toString(i_stgt, l_stgt_str, fapi2::MAX_ECMD_STRING_LEN); + + FAPI_DBG("I/O DMI Targets: Target(%s) Connected(%s)", l_mtgt_str, l_stgt_str); + + // Shorten timers if we are running in simulation + FAPI_TRY(p9_io_dmi_shorten_timers(i_mtgt)); + FAPI_TRY(p9_io_cn_shorten_timers(i_stgt)); + + + // Record the Bad Lane Vectors Prior to link training. + FAPI_TRY(get_bad_lane_data(i_mtgt, l_m_pre_bad_data), + "Pre Training: Get Bad Lane Vector Failed on Master"); + FAPI_TRY(get_bad_lane_data(i_stgt, l_s_pre_bad_data), + "Pre Training: Get Bad Lane Vector Failed on Slave"); + + + // Clock Serializer Init -- isn't strictly necessary but does line up the + // clock serializer counter wit the data slices. + FAPI_TRY(tx_serializer_sync_power_on(i_mtgt), "tx_serializer_sync_power_on Failed."); + + + // Start Slave/Master Target Link Training + FAPI_TRY(linktrain_cn_start(i_stgt, State::WDERF), + "P9 IO DMI Linktrain Start Slave Training Failed"); + FAPI_TRY(linktrain_dmi_start(i_mtgt, tate::WDERF), + "P9 IO Centuar Linktrain Start Master Training Failed."); + + + // Poll for Training to Complete on Master Target + FAPI_TRY(linktrain_poll(i_mtgt, i_stgt, State::WDERF), + "P9 IO DMI Linktrain Polling Failed"); + + + // >> HW390103 -- Leave Tx Unload Clock Disable Off + //// Disable the Tx Serializer Sync + //FAPI_TRY(tx_serializer_sync_power_off(l_mtgt, l_stgt, i_grp), + // "tx_serializer_sync_power_off Failed."); + // << HW390103 -- Leave Tx Unload Clock Disable Off + + // Record the Bad Lane Vectors after link training. + FAPI_TRY(get_bad_lane_data(i_mtgt, l_m_post_bad_data), + "Post Training: Get Bad Lane Vector Failed on Master"); + FAPI_TRY(get_bad_lane_data(i_stgt, l_s_post_bad_data), + "Post Training: Get Bad Lane Vector Failed on Master"); + + + // Check to see if the bad lanes match the bad lanes prior to link training. + // If so, then that error has already been logged and we can clear the firs. + FAPI_TRY(check_bad_lane_data(i_mtgt, l_m_pre_bad_data, l_m_post_bad_data), + "Post Training: Evaluate Firs Failed on Master"); + FAPI_TRY(check_bad_lane_data(i_stgt, l_s_pre_bad_data, l_s_post_bad_data), + "Post Training: Evaluate Firs Failed on Slave"); + + + fapi_try_exit: + */ + FAPI_IMP("p9_io_dmi_linktrain: P9 I/O EDI+ DMI Exiting"); + return fapi2::current_err; +} + diff --git a/src/import/chips/p9/procedures/hwp/io/p9_io_dmi_linktrain.H b/src/import/chips/p9/procedures/hwp/io/p9_io_dmi_linktrain.H new file mode 100644 index 000000000..b2ccd11ca --- /dev/null +++ b/src/import/chips/p9/procedures/hwp/io/p9_io_dmi_linktrain.H @@ -0,0 +1,70 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/import/chips/p9/procedures/hwp/io/p9_io_dmi_linktrain.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +/// +/// @file p9_io_dmi_linktrain.H +/// @brief I/O Link Training on the Dmi Links. +/// +///----------------------------------------------------------------------------- +/// *HWP HWP Owner : Chris Steffen <cwsteffen@us.ibm.com> +/// *HWP HWP Backup Owner : Gary Peterson <garyp@us.ibm.com> +/// *HWP FW Owner : Jamie Knight <rjknight@us.ibm.com> +/// *HWP Team : IO +/// *HWP Level : 1 +/// *HWP Consumed by : FSP:HB +///----------------------------------------------------------------------------- +#ifndef _P9_IO_DMI_TRAIN_H +#define _P9_IO_DMI_TRAIN_H + +//----------------------------------------------------------------------------- +// System Header Include +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// fapi2 Includes +//----------------------------------------------------------------------------- +#include <fapi2.H> + +typedef fapi2::Target<fapi2::TARGET_TYPE_DMI> DMI_TGT; +typedef fapi2::Target<fapi2::TARGET_TYPE_MEMBUF_CHIP> CN_TGT; + +typedef fapi2::ReturnCode (*p9_io_dmi_linktrain_FP_t)(const DMI_TGT&, const CN_TGT&); + +extern "C" +{ + + /** + * @brief A HWP that runs once on every link of the DMI(EDI+). + * The HWP will train both ends of the link. + * + * @param[in] i_mtgt Reference to the Master Target + * @param[in] i_stgt Reference to the Slave Target + * + * @return FAPI2_RC_SUCCESS on success, error otherwise + */ + fapi2::ReturnCode p9_io_dmi_linktrain(const DMI_TGT& i_mtgt, const CN_TGT& i_stgt); + +} // extern "C" + +#endif // _P9_IO_DMI_TRAIN_H diff --git a/src/import/chips/p9/procedures/hwp/io/p9_io_dmi_linktrain.mk b/src/import/chips/p9/procedures/hwp/io/p9_io_dmi_linktrain.mk new file mode 100644 index 000000000..1b688fbb4 --- /dev/null +++ b/src/import/chips/p9/procedures/hwp/io/p9_io_dmi_linktrain.mk @@ -0,0 +1,31 @@ +# IBM_PROLOG_BEGIN_TAG +# This is an automatically generated prolog. +# +# $Source: src/import/chips/p9/procedures/hwp/io/p9_io_dmi_linktrain.mk $ +# +# OpenPOWER HostBoot Project +# +# Contributors Listed Below - COPYRIGHT 2015,2017 +# [+] International Business Machines Corp. +# +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. See the License for the specific language governing +# permissions and limitations under the License. +# +# IBM_PROLOG_END_TAG +PROCEDURE=p9_io_dmi_linktrain +OBJS+=p9_io_common.o + +# TODO Create DMI Clear Firs +# OBJS+=p9_io_dmi_clear_firs.o + +$(call BUILD_PROCEDURE) |