/******************************************************************************* Copyright (C) 2015 Annapurna Labs Ltd. This file may be licensed under the terms of the Annapurna Labs Commercial License Agreement. Alternatively, this file can be distributed under the terms of the GNU General Public License V2 as published by the Free Software Foundation and can be found at http://www.gnu.org/licenses/gpl-2.0.html Alternatively, redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *******************************************************************************/ #include "al_hal_serdes_hssp.h" #include "al_hal_serdes_hssp_regs.h" #include "al_hal_serdes_hssp_internal_regs.h" #define SRDS_CORE_REG_ADDR(page, type, offset)\ (((page) << 13) | ((type) << 12) | (offset)) /* Link Training configuration */ #define AL_SERDES_TX_DEEMPH_SUM_MAX 0x1b /* c configurations */ #define AL_SERDES_TX_DEEMPH_C_ZERO_MAX_VAL 0x1b #define AL_SERDES_TX_DEEMPH_C_ZERO_MIN_VAL 0 #define AL_SERDES_TX_DEEMPH_C_ZERO_PRESET AL_SERDES_TX_DEEMPH_C_ZERO_MAX_VAL /* c(+1) configurations */ #define AL_SERDES_TX_DEEMPH_C_PLUS_MAX_VAL 0x9 #define AL_SERDES_TX_DEEMPH_C_PLUS_MIN_VAL 0 #define AL_SERDES_TX_DEEMPH_C_PLUS_PRESET AL_SERDES_TX_DEEMPH_C_PLUS_MIN_VAL /* c(-1) configurations */ #define AL_SERDES_TX_DEEMPH_C_MINUS_MAX_VAL 0x6 #define AL_SERDES_TX_DEEMPH_C_MINUS_MIN_VAL 0 #define AL_SERDES_TX_DEEMPH_C_MINUS_PRESET AL_SERDES_TX_DEEMPH_C_MINUS_MIN_VAL /* Rx equal total delay = MDELAY * TRIES */ #define AL_SERDES_RX_EQUAL_MDELAY 10 #define AL_SERDES_RX_EQUAL_TRIES 50 /* Rx eye calculation delay = MDELAY * TRIES */ #define AL_SERDES_RX_EYE_CAL_MDELAY 50 #define AL_SERDES_RX_EYE_CAL_TRIES 70 #if (!defined(AL_SERDES_BASIC_SERVICES_ONLY)) || (AL_SERDES_BASIC_SERVICES_ONLY == 0) #define AL_SRDS_ADV_SRVC(func) func #else static void al_serdes_hssp_stub_func(void) { al_err("%s: not implemented service called!\n", __func__); } #define AL_SRDS_ADV_SRVC(func) ((typeof(func) *)al_serdes_hssp_stub_func) #endif /** * SERDES core reg read */ static inline uint8_t al_serdes_grp_reg_read( struct al_serdes_grp_obj *obj, enum al_serdes_reg_page page, enum al_serdes_reg_type type, uint16_t offset); /** * SERDES core reg write */ static inline void al_serdes_grp_reg_write( struct al_serdes_grp_obj *obj, enum al_serdes_reg_page page, enum al_serdes_reg_type type, uint16_t offset, uint8_t data); /** * SERDES core masked reg write */ static inline void al_serdes_grp_reg_masked_write( struct al_serdes_grp_obj *obj, enum al_serdes_reg_page page, enum al_serdes_reg_type type, uint16_t offset, uint8_t mask, uint8_t data); /** * Lane Rx rate change software flow disable */ static void _al_serdes_lane_rx_rate_change_sw_flow_dis( struct al_serdes_grp_obj *obj, enum al_serdes_lane lane); /** * Group Rx rate change software flow enable if all conditions met */ static void al_serdes_group_rx_rate_change_sw_flow_dis( struct al_serdes_grp_obj *obj); /** * Lane Rx rate change software flow enable if all conditions met */ static void _al_serdes_lane_rx_rate_change_sw_flow_en_cond( struct al_serdes_grp_obj *obj, enum al_serdes_lane lane); /** * Group Rx rate change software flow enable if all conditions met */ static void al_serdes_group_rx_rate_change_sw_flow_en_cond( struct al_serdes_grp_obj *obj); /******************************************************************************/ /******************************************************************************/ static enum al_serdes_type al_serdes_hssp_type_get(void) { return AL_SRDS_TYPE_HSSP; } /******************************************************************************/ /******************************************************************************/ static int al_serdes_reg_read( struct al_serdes_grp_obj *obj, enum al_serdes_reg_page page, enum al_serdes_reg_type type, uint16_t offset, uint8_t *data) { int status = 0; al_dbg( "%s(%p, %d, %d, %u)\n", __func__, obj, page, type, offset); al_assert(obj); al_assert(data); al_assert(((int)page) >= AL_SRDS_REG_PAGE_0_LANE_0); al_assert(((int)page) <= AL_SRDS_REG_PAGE_4_COMMON); al_assert(((int)type) >= AL_SRDS_REG_TYPE_PMA); al_assert(((int)type) <= AL_SRDS_REG_TYPE_PCS); *data = al_serdes_grp_reg_read( obj, page, type, offset); al_dbg( "%s: return(%u)\n", __func__, *data); return status; } /******************************************************************************/ /******************************************************************************/ static int al_serdes_reg_write( struct al_serdes_grp_obj *obj, enum al_serdes_reg_page page, enum al_serdes_reg_type type, uint16_t offset, uint8_t data) { int status = 0; al_dbg( "%s(%p, %d, %d, %u, %u)\n", __func__, obj, page, type, offset, data); al_assert(obj); al_assert(((int)page) >= AL_SRDS_REG_PAGE_0_LANE_0); al_assert(((int)page) <= AL_SRDS_REG_PAGE_0123_LANES_0123); al_assert(((int)type) >= AL_SRDS_REG_TYPE_PMA); al_assert(((int)type) <= AL_SRDS_REG_TYPE_PCS); al_serdes_grp_reg_write( obj, page, type, offset, data); return status; } /******************************************************************************/ /******************************************************************************/ #if (SERDES_IREG_FLD_PCSRX_DATAWIDTH_REG_NUM != SERDES_IREG_FLD_PCSTX_DATAWIDTH_REG_NUM) #error "Wrong assumption!" #endif #if (SERDES_IREG_FLD_PCSRX_DIVRATE_REG_NUM != SERDES_IREG_FLD_PCSTX_DIVRATE_REG_NUM) #error "Wrong assumption!" #endif #if (SERDES_IREG_FLD_CMNPCIEGEN3_LOCWREN_REG_NUM != SERDES_IREG_FLD_CMNPCS_LOCWREN_REG_NUM) #error "Wrong assumption!" #endif #if (SERDES_IREG_FLD_CMNPCIEGEN3_LOCWREN_REG_NUM != SERDES_IREG_FLD_CMNPCSBIST_LOCWREN_REG_NUM) #error "Wrong assumption!" #endif #if (SERDES_IREG_FLD_CMNPCIEGEN3_LOCWREN_REG_NUM != SERDES_IREG_FLD_CMNPCSPSTATE_LOCWREN_REG_NUM) #error "Wrong assumption!" #endif #if (SERDES_IREG_FLD_LANEPCSPSTATE_LOCWREN_REG_NUM != SERDES_IREG_FLD_LB_LOCWREN_REG_NUM) #error "Wrong assumption!" #endif #if (SERDES_IREG_FLD_LANEPCSPSTATE_LOCWREN_REG_NUM != SERDES_IREG_FLD_PCSRX_LOCWREN_REG_NUM) #error "Wrong assumption!" #endif #if (SERDES_IREG_FLD_LANEPCSPSTATE_LOCWREN_REG_NUM != SERDES_IREG_FLD_PCSRXBIST_LOCWREN_REG_NUM) #error "Wrong assumption!" #endif #if (SERDES_IREG_FLD_LANEPCSPSTATE_LOCWREN_REG_NUM != SERDES_IREG_FLD_PCSRXEQ_LOCWREN_REG_NUM) #error "Wrong assumption!" #endif #if (SERDES_IREG_FLD_LANEPCSPSTATE_LOCWREN_REG_NUM != SERDES_IREG_FLD_PCSTX_LOCWREN_REG_NUM) #error "Wrong assumption!" #endif static void al_serdes_bist_overrides_enable( struct al_serdes_grp_obj *obj, enum al_serdes_rate rate) { int i; uint8_t rx_rate_val; uint8_t tx_rate_val; switch (rate) { case AL_SRDS_RATE_1_8: rx_rate_val = SERDES_IREG_FLD_PCSRX_DIVRATE_VAL_1_8; tx_rate_val = SERDES_IREG_FLD_PCSTX_DIVRATE_VAL_1_8; break; case AL_SRDS_RATE_1_4: rx_rate_val = SERDES_IREG_FLD_PCSRX_DIVRATE_VAL_1_4; tx_rate_val = SERDES_IREG_FLD_PCSTX_DIVRATE_VAL_1_4; break; case AL_SRDS_RATE_1_2: rx_rate_val = SERDES_IREG_FLD_PCSRX_DIVRATE_VAL_1_2; tx_rate_val = SERDES_IREG_FLD_PCSTX_DIVRATE_VAL_1_2; break; case AL_SRDS_RATE_FULL: rx_rate_val = SERDES_IREG_FLD_PCSRX_DIVRATE_VAL_1_1; tx_rate_val = SERDES_IREG_FLD_PCSTX_DIVRATE_VAL_1_1; break; default: al_err("%s: invalid rate (%d)\n", __func__, rate); al_assert(0); rx_rate_val = SERDES_IREG_FLD_PCSRX_DIVRATE_VAL_1_1; tx_rate_val = SERDES_IREG_FLD_PCSTX_DIVRATE_VAL_1_1; } for (i = 0; i < AL_SRDS_NUM_LANES; i++) { al_serdes_grp_reg_masked_write( obj, (enum al_serdes_reg_page)i, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_PCSRX_DATAWIDTH_REG_NUM, SERDES_IREG_FLD_PCSRX_DATAWIDTH_MASK | SERDES_IREG_FLD_PCSTX_DATAWIDTH_MASK, SERDES_IREG_FLD_PCSRX_DATAWIDTH_VAL_20 | SERDES_IREG_FLD_PCSTX_DATAWIDTH_VAL_20); al_serdes_grp_reg_masked_write( obj, (enum al_serdes_reg_page)i, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_PCSRX_DIVRATE_REG_NUM, SERDES_IREG_FLD_PCSRX_DIVRATE_MASK | SERDES_IREG_FLD_PCSTX_DIVRATE_MASK, rx_rate_val | tx_rate_val); } al_serdes_grp_reg_masked_write( obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_CMNPCIEGEN3_LOCWREN_REG_NUM, SERDES_IREG_FLD_CMNPCIEGEN3_LOCWREN | SERDES_IREG_FLD_CMNPCS_LOCWREN | SERDES_IREG_FLD_CMNPCSBIST_LOCWREN | SERDES_IREG_FLD_CMNPCSPSTATE_LOCWREN, 0); al_serdes_grp_reg_masked_write( obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_CMNPCIEGEN3_LOCWREN_REG_NUM, SERDES_IREG_FLD_CMNPCIEGEN3_LOCWREN | SERDES_IREG_FLD_CMNPCS_LOCWREN | SERDES_IREG_FLD_CMNPCSBIST_LOCWREN | SERDES_IREG_FLD_CMNPCSPSTATE_LOCWREN, 0); al_serdes_grp_reg_masked_write( obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_PCS_LOCWREN_REG_NUM, SERDES_IREG_FLD_PCS_LOCWREN, 0); al_serdes_grp_reg_masked_write( obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_CMNPCS_TXENABLE_REG_NUM, SERDES_IREG_FLD_CMNPCS_TXENABLE, SERDES_IREG_FLD_CMNPCS_TXENABLE); for (i = 0; i < AL_SRDS_NUM_LANES; i++) { al_serdes_grp_reg_masked_write( obj, (enum al_serdes_reg_page)i, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_LANEPCSPSTATE_LOCWREN_REG_NUM, SERDES_IREG_FLD_LANEPCSPSTATE_LOCWREN | SERDES_IREG_FLD_LB_LOCWREN | SERDES_IREG_FLD_PCSRX_LOCWREN | SERDES_IREG_FLD_PCSRXBIST_LOCWREN | SERDES_IREG_FLD_PCSRXEQ_LOCWREN | SERDES_IREG_FLD_PCSTX_LOCWREN, 0); al_serdes_grp_reg_masked_write( obj, (enum al_serdes_reg_page)i, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_PCSTXBIST_LOCWREN_REG_NUM, SERDES_IREG_FLD_PCSTXBIST_LOCWREN, 0); al_serdes_grp_reg_masked_write( obj, (enum al_serdes_reg_page)i, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_TX_DRV_OVERRIDE_EN_REG_NUM, SERDES_IREG_FLD_TX_DRV_OVERRIDE_EN, 0); al_serdes_grp_reg_masked_write( obj, (enum al_serdes_reg_page)i, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXLOCK2REF_OVREN_REG_NUM, SERDES_IREG_FLD_RXLOCK2REF_OVREN, SERDES_IREG_FLD_RXLOCK2REF_OVREN); } } /******************************************************************************/ /******************************************************************************/ static void al_serdes_bist_overrides_disable( struct al_serdes_grp_obj *obj) { int i; al_serdes_grp_reg_masked_write( obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_CMNPCIEGEN3_LOCWREN_REG_NUM, SERDES_IREG_FLD_CMNPCSBIST_LOCWREN, SERDES_IREG_FLD_CMNPCSBIST_LOCWREN); for (i = 0; i < AL_SRDS_NUM_LANES; i++) { al_serdes_grp_reg_masked_write( obj, (enum al_serdes_reg_page)i, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_LANEPCSPSTATE_LOCWREN_REG_NUM, SERDES_IREG_FLD_LB_LOCWREN | SERDES_IREG_FLD_PCSRXBIST_LOCWREN, SERDES_IREG_FLD_LB_LOCWREN | SERDES_IREG_FLD_PCSRXBIST_LOCWREN); al_serdes_grp_reg_masked_write( obj, (enum al_serdes_reg_page)i, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_PCSTXBIST_LOCWREN_REG_NUM, SERDES_IREG_FLD_PCSTXBIST_LOCWREN, SERDES_IREG_FLD_PCSTXBIST_LOCWREN); } } /******************************************************************************/ /******************************************************************************/ static void al_serdes_rx_rate_change( struct al_serdes_grp_obj *obj, enum al_serdes_rate rate) { int i; uint8_t rx_rate_val; switch (rate) { case AL_SRDS_RATE_1_8: rx_rate_val = SERDES_IREG_FLD_PCSRX_DIVRATE_VAL_1_8; break; case AL_SRDS_RATE_1_4: rx_rate_val = SERDES_IREG_FLD_PCSRX_DIVRATE_VAL_1_4; break; case AL_SRDS_RATE_1_2: rx_rate_val = SERDES_IREG_FLD_PCSRX_DIVRATE_VAL_1_2; break; case AL_SRDS_RATE_FULL: rx_rate_val = SERDES_IREG_FLD_PCSRX_DIVRATE_VAL_1_1; break; default: al_err("%s: invalid rate (%d)\n", __func__, rate); rx_rate_val = SERDES_IREG_FLD_PCSRX_DIVRATE_VAL_1_1; break; } for (i = 0; i < AL_SRDS_NUM_LANES; i++) { al_serdes_grp_reg_masked_write( obj, (enum al_serdes_reg_page)i, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_PCSRX_DIVRATE_REG_NUM, SERDES_IREG_FLD_PCSRX_DIVRATE_MASK, rx_rate_val); } } /******************************************************************************/ /******************************************************************************/ static void al_serdes_group_pm_set( struct al_serdes_grp_obj *obj, enum al_serdes_pm pm) { uint8_t pm_val; switch (pm) { case AL_SRDS_PM_PD: pm_val = SERDES_IREG_FLD_CMNPCSPSTATE_SYNTH_VAL_PD; break; case AL_SRDS_PM_P2: pm_val = SERDES_IREG_FLD_CMNPCSPSTATE_SYNTH_VAL_P2; break; case AL_SRDS_PM_P1: pm_val = SERDES_IREG_FLD_CMNPCSPSTATE_SYNTH_VAL_P1; break; case AL_SRDS_PM_P0S: pm_val = SERDES_IREG_FLD_CMNPCSPSTATE_SYNTH_VAL_P0S; break; case AL_SRDS_PM_P0: pm_val = SERDES_IREG_FLD_CMNPCSPSTATE_SYNTH_VAL_P0; break; default: al_err("%s: invalid power mode (%d)\n", __func__, pm); al_assert(0); pm_val = SERDES_IREG_FLD_CMNPCSPSTATE_SYNTH_VAL_P0; } if (pm == AL_SRDS_PM_PD) al_serdes_group_rx_rate_change_sw_flow_dis(obj); al_serdes_grp_reg_masked_write( obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_CMNPCSPSTATE_SYNTH_REG_NUM, SERDES_IREG_FLD_CMNPCSPSTATE_SYNTH_MASK, pm_val); if (pm != AL_SRDS_PM_PD) al_serdes_group_rx_rate_change_sw_flow_en_cond(obj); } /******************************************************************************/ /******************************************************************************/ static void al_serdes_lane_rx_rate_change_sw_flow_en( struct al_serdes_grp_obj *obj, enum al_serdes_lane lane) { al_serdes_reg_write(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, 201, 0xfc); al_serdes_reg_write(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, 202, 0xff); al_serdes_reg_write(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, 203, 0xff); al_serdes_reg_write(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, 204, 0xff); al_serdes_reg_write(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, 205, 0x7f); al_serdes_reg_write(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, 205, 0xff); } /******************************************************************************/ /******************************************************************************/ static void al_serdes_lane_rx_rate_change_sw_flow_dis( struct al_serdes_grp_obj *obj, enum al_serdes_lane lane) { al_serdes_reg_write(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, 205, 0x7f); } /******************************************************************************/ /******************************************************************************/ static void al_serdes_lane_pcie_rate_override_enable_set( struct al_serdes_grp_obj *obj, enum al_serdes_lane lane, al_bool en) { al_serdes_grp_reg_masked_write( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PCS, SERDES_IREG_FLD_PCS_VPCSIF_OVR_RATE_ENA_REG_NUM, SERDES_IREG_FLD_PCS_VPCSIF_OVR_RATE_ENA, en ? SERDES_IREG_FLD_PCS_VPCSIF_OVR_RATE_ENA : 0); } /******************************************************************************/ /******************************************************************************/ static al_bool al_serdes_lane_pcie_rate_override_is_enabled( struct al_serdes_grp_obj *obj, enum al_serdes_lane lane) { return (al_serdes_grp_reg_read( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PCS, SERDES_IREG_FLD_PCS_VPCSIF_OVR_RATE_ENA_REG_NUM) & SERDES_IREG_FLD_PCS_VPCSIF_OVR_RATE_ENA) ? AL_TRUE : AL_FALSE; } /******************************************************************************/ /******************************************************************************/ static enum al_serdes_pcie_rate al_serdes_lane_pcie_rate_get( struct al_serdes_grp_obj *obj, enum al_serdes_lane lane) { return (al_serdes_grp_reg_read( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PCS, SERDES_IREG_FLD_PCS_VPCSIF_OVR_RATE_REG_NUM) & SERDES_IREG_FLD_PCS_VPCSIF_OVR_RATE_MASK) >> SERDES_IREG_FLD_PCS_VPCSIF_OVR_RATE_SHIFT; } /******************************************************************************/ /******************************************************************************/ static void al_serdes_lane_pcie_rate_set( struct al_serdes_grp_obj *obj, enum al_serdes_lane lane, enum al_serdes_pcie_rate rate) { al_serdes_grp_reg_masked_write( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PCS, SERDES_IREG_FLD_PCS_VPCSIF_OVR_RATE_REG_NUM, SERDES_IREG_FLD_PCS_VPCSIF_OVR_RATE_MASK, rate << SERDES_IREG_FLD_PCS_VPCSIF_OVR_RATE_SHIFT); } /******************************************************************************/ /******************************************************************************/ static void al_serdes_lane_pm_set( struct al_serdes_grp_obj *obj, enum al_serdes_lane lane, enum al_serdes_pm rx_pm, enum al_serdes_pm tx_pm) { uint8_t rx_pm_val; uint8_t tx_pm_val; switch (rx_pm) { case AL_SRDS_PM_PD: rx_pm_val = SERDES_IREG_FLD_LANEPCSPSTATE_RX_VAL_PD; break; case AL_SRDS_PM_P2: rx_pm_val = SERDES_IREG_FLD_LANEPCSPSTATE_RX_VAL_P2; break; case AL_SRDS_PM_P1: rx_pm_val = SERDES_IREG_FLD_LANEPCSPSTATE_RX_VAL_P1; break; case AL_SRDS_PM_P0S: rx_pm_val = SERDES_IREG_FLD_LANEPCSPSTATE_RX_VAL_P0S; break; case AL_SRDS_PM_P0: rx_pm_val = SERDES_IREG_FLD_LANEPCSPSTATE_RX_VAL_P0; break; default: al_err("%s: invalid rx power mode (%d)\n", __func__, rx_pm); al_assert(0); rx_pm_val = SERDES_IREG_FLD_LANEPCSPSTATE_RX_VAL_P0; } switch (tx_pm) { case AL_SRDS_PM_PD: tx_pm_val = SERDES_IREG_FLD_LANEPCSPSTATE_TX_VAL_PD; break; case AL_SRDS_PM_P2: tx_pm_val = SERDES_IREG_FLD_LANEPCSPSTATE_TX_VAL_P2; break; case AL_SRDS_PM_P1: tx_pm_val = SERDES_IREG_FLD_LANEPCSPSTATE_TX_VAL_P1; break; case AL_SRDS_PM_P0S: tx_pm_val = SERDES_IREG_FLD_LANEPCSPSTATE_TX_VAL_P0S; break; case AL_SRDS_PM_P0: tx_pm_val = SERDES_IREG_FLD_LANEPCSPSTATE_TX_VAL_P0; break; default: al_err("%s: invalid tx power mode (%d)\n", __func__, tx_pm); al_assert(0); tx_pm_val = SERDES_IREG_FLD_LANEPCSPSTATE_TX_VAL_P0; } if (rx_pm == AL_SRDS_PM_PD) _al_serdes_lane_rx_rate_change_sw_flow_dis(obj, lane); al_serdes_grp_reg_masked_write( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_LANEPCSPSTATE_RX_REG_NUM, SERDES_IREG_FLD_LANEPCSPSTATE_RX_MASK, rx_pm_val); al_serdes_grp_reg_masked_write( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_LANEPCSPSTATE_TX_REG_NUM, SERDES_IREG_FLD_LANEPCSPSTATE_TX_MASK, tx_pm_val); if (rx_pm != AL_SRDS_PM_PD) _al_serdes_lane_rx_rate_change_sw_flow_en_cond(obj, lane); } /******************************************************************************/ /******************************************************************************/ static void al_serdes_pma_hard_reset_group( struct al_serdes_grp_obj *obj, al_bool enable) { if (enable) al_serdes_group_rx_rate_change_sw_flow_dis(obj); /* Enable Hard Reset Override */ al_serdes_grp_reg_masked_write( obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_CMNCTLPOR_HARDRSTBYPASSEN_SYNTH_REG_NUM, SERDES_IREG_FLD_CMNCTLPOR_HARDRSTBYPASSEN_SYNTH_MASK, SERDES_IREG_FLD_CMNCTLPOR_HARDRSTBYPASSEN_SYNTH_VAL_REGS); /* Assert/Deassert Hard Reset Override */ al_serdes_grp_reg_masked_write( obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_CMNCTLPOR_HARDRSTBYPASS_SYNTH_REG_NUM, SERDES_IREG_FLD_CMNCTLPOR_HARDRSTBYPASS_SYNTH_MASK, enable ? SERDES_IREG_FLD_CMNCTLPOR_HARDRSTBYPASS_SYNTH_VAL_ASSERT : SERDES_IREG_FLD_CMNCTLPOR_HARDRSTBYPASS_SYNTH_VAL_DEASSERT); if (!enable) al_serdes_group_rx_rate_change_sw_flow_en_cond(obj); } /******************************************************************************/ /******************************************************************************/ static void al_serdes_pma_hard_reset_lane( struct al_serdes_grp_obj *obj, enum al_serdes_lane lane, al_bool enable) { if (enable) _al_serdes_lane_rx_rate_change_sw_flow_dis(obj, lane); /* Enable Hard Reset Override */ al_serdes_grp_reg_masked_write( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_CMNCTLPOR_HARDRSTBYPASSEN_REG_NUM, SERDES_IREG_FLD_CMNCTLPOR_HARDRSTBYPASSEN_MASK, SERDES_IREG_FLD_CMNCTLPOR_HARDRSTBYPASSEN_VAL_REGS); /* Assert/Deassert Hard Reset Override */ al_serdes_grp_reg_masked_write( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_CMNCTLPOR_HARDRSTBYPASS_REG_NUM, SERDES_IREG_FLD_CMNCTLPOR_HARDRSTBYPASS_MASK, enable ? SERDES_IREG_FLD_CMNCTLPOR_HARDRSTBYPASS_VAL_ASSERT : SERDES_IREG_FLD_CMNCTLPOR_HARDRSTBYPASS_VAL_DEASSERT); if (!enable) _al_serdes_lane_rx_rate_change_sw_flow_en_cond(obj, lane); } /******************************************************************************/ /******************************************************************************/ #if (SERDES_IREG_FLD_LB_RX2TXUNTIMEDEN_REG_NUM !=\ SERDES_IREG_FLD_LB_TX2RXBUFTIMEDEN_REG_NUM) ||\ (SERDES_IREG_FLD_LB_TX2RXBUFTIMEDEN_REG_NUM !=\ SERDES_IREG_FLD_LB_TX2RXIOTIMEDEN_REG_NUM) ||\ (SERDES_IREG_FLD_LB_TX2RXIOTIMEDEN_REG_NUM !=\ SERDES_IREG_FLD_LB_PARRX2TXTIMEDEN_REG_NUM) ||\ (SERDES_IREG_FLD_LB_PARRX2TXTIMEDEN_REG_NUM !=\ SERDES_IREG_FLD_LB_CDRCLK2TXEN_REG_NUM) #error Wrong assumption #endif static void al_serdes_loopback_control( struct al_serdes_grp_obj *obj, enum al_serdes_lane lane, enum al_serdes_lb_mode mode) { uint8_t val = 0; switch (mode) { case AL_SRDS_LB_MODE_OFF: break; case AL_SRDS_LB_MODE_PMA_IO_UN_TIMED_RX_TO_TX: val = SERDES_IREG_FLD_LB_RX2TXUNTIMEDEN; break; case AL_SRDS_LB_MODE_PMA_INTERNALLY_BUFFERED_SERIAL_TX_TO_RX: val = SERDES_IREG_FLD_LB_TX2RXBUFTIMEDEN; break; case AL_SRDS_LB_MODE_PMA_SERIAL_TX_IO_TO_RX_IO: val = SERDES_IREG_FLD_LB_TX2RXIOTIMEDEN; break; case AL_SRDS_LB_MODE_PMA_PARALLEL_RX_TO_TX: val = SERDES_IREG_FLD_LB_PARRX2TXTIMEDEN | SERDES_IREG_FLD_LB_CDRCLK2TXEN; break; default: al_err("%s: invalid mode (%d)\n", __func__, mode); al_assert(0); } al_serdes_grp_reg_masked_write( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_LB_RX2TXUNTIMEDEN_REG_NUM, SERDES_IREG_FLD_LB_RX2TXUNTIMEDEN | SERDES_IREG_FLD_LB_TX2RXBUFTIMEDEN | SERDES_IREG_FLD_LB_TX2RXIOTIMEDEN | SERDES_IREG_FLD_LB_PARRX2TXTIMEDEN | SERDES_IREG_FLD_LB_CDRCLK2TXEN, val); } /******************************************************************************/ /******************************************************************************/ static void al_serdes_bist_pattern_select( struct al_serdes_grp_obj *obj, enum al_serdes_bist_pattern pattern, uint8_t *user_data) { uint8_t val = 0; switch (pattern) { case AL_SRDS_BIST_PATTERN_USER: al_assert(user_data); val = SERDES_IREG_FLD_CMNPCSBIST_MODESEL_VAL_USER; break; case AL_SRDS_BIST_PATTERN_PRBS7: val = SERDES_IREG_FLD_CMNPCSBIST_MODESEL_VAL_PRBS7; break; case AL_SRDS_BIST_PATTERN_PRBS23: val = SERDES_IREG_FLD_CMNPCSBIST_MODESEL_VAL_PRBS23; break; case AL_SRDS_BIST_PATTERN_PRBS31: val = SERDES_IREG_FLD_CMNPCSBIST_MODESEL_VAL_PRBS31; break; case AL_SRDS_BIST_PATTERN_CLK1010: val = SERDES_IREG_FLD_CMNPCSBIST_MODESEL_VAL_CLK1010; break; default: al_err("%s: invalid pattern (%d)\n", __func__, pattern); al_assert(0); } if (pattern == AL_SRDS_BIST_PATTERN_USER) { int i; for (i = 0; i < SERDES_IREG_FLD_TX_BIST_PAT_NUM_BYTES; i++) al_serdes_grp_reg_write( obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_TX_BIST_PAT_REG_NUM(i), user_data[i]); } al_serdes_grp_reg_masked_write( obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_CMNPCSBIST_MODESEL_REG_NUM, SERDES_IREG_FLD_CMNPCSBIST_MODESEL_MASK, val); } /******************************************************************************/ /******************************************************************************/ static void al_serdes_bist_tx_enable( struct al_serdes_grp_obj *obj, enum al_serdes_lane lane, al_bool enable) { al_serdes_grp_reg_masked_write( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_PCSTXBIST_EN_REG_NUM, SERDES_IREG_FLD_PCSTXBIST_EN, enable ? SERDES_IREG_FLD_PCSTXBIST_EN : 0); } /******************************************************************************/ /******************************************************************************/ static void al_serdes_bist_tx_err_inject( struct al_serdes_grp_obj *obj) { al_serdes_grp_reg_masked_write( obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_TXBIST_BITERROR_EN_REG_NUM, SERDES_IREG_FLD_TXBIST_BITERROR_EN, SERDES_IREG_FLD_TXBIST_BITERROR_EN); al_serdes_grp_reg_masked_write( obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_TXBIST_BITERROR_EN_REG_NUM, SERDES_IREG_FLD_TXBIST_BITERROR_EN, 0); } /******************************************************************************/ /******************************************************************************/ static void al_serdes_bist_rx_enable( struct al_serdes_grp_obj *obj, enum al_serdes_lane lane, al_bool enable) { al_serdes_grp_reg_masked_write( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_PCSRXBIST_EN_REG_NUM, SERDES_IREG_FLD_PCSRXBIST_EN, enable ? SERDES_IREG_FLD_PCSRXBIST_EN : 0); } /******************************************************************************/ /******************************************************************************/ #if (SERDES_IREG_FLD_RXBIST_ERRCOUNT_OVERFLOW_REG_NUM !=\ SERDES_IREG_FLD_RXBIST_RXLOCKED_REG_NUM) #error Wrong assumption #endif static void al_serdes_bist_rx_status( struct al_serdes_grp_obj *obj, enum al_serdes_lane lane, al_bool *is_locked, al_bool *err_cnt_overflow, uint32_t *err_cnt) { uint8_t status_reg_val; uint16_t err_cnt_msb_reg_val; uint16_t err_cnt_lsb_reg_val; status_reg_val = al_serdes_grp_reg_read( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXBIST_RXLOCKED_REG_NUM); err_cnt_msb_reg_val = al_serdes_grp_reg_read( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXBIST_ERRCOUNT_MSB_REG_NUM); err_cnt_lsb_reg_val = al_serdes_grp_reg_read( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXBIST_ERRCOUNT_LSB_REG_NUM); *is_locked = (status_reg_val & SERDES_IREG_FLD_RXBIST_RXLOCKED) ? AL_TRUE : AL_FALSE; *err_cnt_overflow = (status_reg_val & SERDES_IREG_FLD_RXBIST_ERRCOUNT_OVERFLOW) ? AL_TRUE : AL_FALSE; *err_cnt = (err_cnt_msb_reg_val << 8) + err_cnt_lsb_reg_val; } /******************************************************************************/ /******************************************************************************/ static inline uint8_t al_serdes_grp_reg_read( struct al_serdes_grp_obj *obj, enum al_serdes_reg_page page, enum al_serdes_reg_type type, uint16_t offset) { struct al_serdes_regs __iomem *regs_base = obj->regs_base; al_reg_write32( ®s_base->gen.reg_addr, SRDS_CORE_REG_ADDR(page, type, offset)); return al_reg_read32(®s_base->gen.reg_data); } /******************************************************************************/ /******************************************************************************/ static inline void al_serdes_grp_reg_write( struct al_serdes_grp_obj *obj, enum al_serdes_reg_page page, enum al_serdes_reg_type type, uint16_t offset, uint8_t data) { struct al_serdes_regs __iomem *regs_base = obj->regs_base; al_reg_write32( ®s_base->gen.reg_addr, SRDS_CORE_REG_ADDR(page, type, offset)); al_reg_write32(®s_base->gen.reg_data, data); } /******************************************************************************/ /******************************************************************************/ static inline void al_serdes_ns_delay(int cnt) { al_udelay((cnt + 999) / 1000); } /******************************************************************************/ /******************************************************************************/ static inline void al_serdes_grp_reg_masked_write( struct al_serdes_grp_obj *obj, enum al_serdes_reg_page page, enum al_serdes_reg_type type, uint16_t offset, uint8_t mask, uint8_t data) { uint8_t val; enum al_serdes_reg_page start_page = page; enum al_serdes_reg_page end_page = page; enum al_serdes_reg_page iter_page; if (page == AL_SRDS_REG_PAGE_0123_LANES_0123) { start_page = AL_SRDS_REG_PAGE_0_LANE_0; end_page = AL_SRDS_REG_PAGE_3_LANE_3; } for (iter_page = start_page; iter_page <= end_page; ++iter_page) { val = al_serdes_grp_reg_read(obj, iter_page, type, offset); val &= ~mask; val |= data; al_serdes_grp_reg_write(obj, iter_page, type, offset, val); } } /******************************************************************************/ /******************************************************************************/ static void _al_serdes_lane_rx_rate_change_sw_flow_dis( struct al_serdes_grp_obj *obj, enum al_serdes_lane lane) { al_bool lane_sw_flow_enabled; al_assert(lane != AL_SRDS_LANES_0123); lane_sw_flow_enabled = (al_serdes_grp_reg_read(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, 201) == 0xfc) && (al_serdes_grp_reg_read(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, 202) == 0xff) && (al_serdes_grp_reg_read(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, 203) == 0xff) && (al_serdes_grp_reg_read(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, 204) == 0xff) && (al_serdes_grp_reg_read(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, 205) == 0xff); /** * Disable the Rx rate change software flow by clearing bit 7 of lane PMA register 205 * (RSTPDOVR_RX_OVREN) */ if (lane_sw_flow_enabled) { al_dbg("%s(%d): actually disabling\n", __func__, lane); al_serdes_grp_reg_masked_write(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, 205, 0x80, 0x00); } } /******************************************************************************/ /******************************************************************************/ static void al_serdes_group_rx_rate_change_sw_flow_dis( struct al_serdes_grp_obj *obj) { int lane; for (lane = AL_SRDS_LANE_0; lane < AL_SRDS_NUM_LANES; lane++) _al_serdes_lane_rx_rate_change_sw_flow_dis(obj, lane); } /******************************************************************************/ /******************************************************************************/ static void _al_serdes_lane_rx_rate_change_sw_flow_en_cond( struct al_serdes_grp_obj *obj, enum al_serdes_lane lane) { al_bool lane_sw_flow_almost_enabled; al_bool group_reset_enabled; al_bool lane_reset_enabled; al_bool group_pd_enabled; al_bool lane_pd_enabled; al_assert(lane != AL_SRDS_LANES_0123); lane_sw_flow_almost_enabled = (al_serdes_grp_reg_read(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, 201) == 0xfc) && (al_serdes_grp_reg_read(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, 202) == 0xff) && (al_serdes_grp_reg_read(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, 203) == 0xff) && (al_serdes_grp_reg_read(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, 204) == 0xff) && (al_serdes_grp_reg_read(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, 205) == 0x7f); group_reset_enabled = ((al_serdes_grp_reg_read( obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_CMNCTLPOR_HARDRSTBYPASSEN_SYNTH_REG_NUM) & SERDES_IREG_FLD_CMNCTLPOR_HARDRSTBYPASSEN_SYNTH_MASK) == SERDES_IREG_FLD_CMNCTLPOR_HARDRSTBYPASSEN_SYNTH_VAL_REGS) && ((al_serdes_grp_reg_read( obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_CMNCTLPOR_HARDRSTBYPASS_SYNTH_REG_NUM) & SERDES_IREG_FLD_CMNCTLPOR_HARDRSTBYPASS_SYNTH_MASK) == SERDES_IREG_FLD_CMNCTLPOR_HARDRSTBYPASS_SYNTH_VAL_ASSERT); lane_reset_enabled = ((al_serdes_grp_reg_read( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_CMNCTLPOR_HARDRSTBYPASSEN_REG_NUM) & SERDES_IREG_FLD_CMNCTLPOR_HARDRSTBYPASSEN_MASK) == SERDES_IREG_FLD_CMNCTLPOR_HARDRSTBYPASSEN_VAL_REGS) && ((al_serdes_grp_reg_read( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_CMNCTLPOR_HARDRSTBYPASS_REG_NUM) & SERDES_IREG_FLD_CMNCTLPOR_HARDRSTBYPASS_MASK) == SERDES_IREG_FLD_CMNCTLPOR_HARDRSTBYPASS_VAL_ASSERT); group_pd_enabled = (al_serdes_grp_reg_read( obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_CMNPCSPSTATE_SYNTH_REG_NUM) & SERDES_IREG_FLD_CMNPCSPSTATE_SYNTH_MASK) == SERDES_IREG_FLD_CMNPCSPSTATE_SYNTH_VAL_PD; lane_pd_enabled = (al_serdes_grp_reg_read( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_LANEPCSPSTATE_RX_REG_NUM) & SERDES_IREG_FLD_LANEPCSPSTATE_RX_MASK) == SERDES_IREG_FLD_LANEPCSPSTATE_RX_VAL_PD; /** * Enable the Rx rate change software flow by setting bit 7 of lane PMA register 205 * (RSTPDOVR_RX_OVREN) */ if (lane_sw_flow_almost_enabled && !group_reset_enabled && !lane_reset_enabled && !group_pd_enabled && !lane_pd_enabled) { al_dbg("%s(%d): actually enabling\n", __func__, lane); al_serdes_ns_delay(500); al_serdes_grp_reg_masked_write(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, 205, 0x80, 0x80); } } /******************************************************************************/ /******************************************************************************/ static void al_serdes_group_rx_rate_change_sw_flow_en_cond( struct al_serdes_grp_obj *obj) { int lane; for (lane = AL_SRDS_LANE_0; lane < AL_SRDS_NUM_LANES; lane++) _al_serdes_lane_rx_rate_change_sw_flow_en_cond(obj, lane); } /******************************************************************************/ /******************************************************************************/ static int al_serdes_eye_measure_run( struct al_serdes_grp_obj *obj, enum al_serdes_lane lane, uint32_t timeout, unsigned int *value) { struct al_serdes_grp_obj *grp_obj = obj; struct al_serdes_regs __iomem *regs_base = grp_obj->regs_base; uint32_t reg = 0; uint32_t i; struct serdes_lane *lane_regs; lane_regs = ®s_base->lane[lane]; al_reg_write32(&lane_regs->ictl_multi_rxeq, SERDES_LANE_ICTL_MULTI_RXEQ_START_L_A); for (i = 0; i < timeout; i++) { reg = al_reg_read32(&lane_regs->octl_multi); if (reg & SERDES_LANE_OCTL_MULTI_RXEQ_DONE_L_A) break; al_msleep(10); } if (i == timeout) { al_err("%s: measure eye failed on timeout\n", __func__); return -ETIMEDOUT; } *value = al_reg_read32(&lane_regs->odat_multi_rxeq); al_reg_write32(&lane_regs->ictl_multi_rxeq, 0); return 0; } /******************************************************************************/ /******************************************************************************/ static int al_serdes_eye_diag_sample( struct al_serdes_grp_obj *obj, enum al_serdes_lane lane, unsigned int x, int y, unsigned int timeout, unsigned int *value) { enum al_serdes_reg_page page = (enum al_serdes_reg_page)lane; uint32_t i; uint8_t sample_count_orig_msb; uint8_t sample_count_orig_lsb; al_assert(obj); al_assert(((int)page) >= AL_SRDS_REG_PAGE_0_LANE_0); al_assert(((int)page) <= AL_SRDS_REG_PAGE_0123_LANES_0123); /* Obtain sample count by reading RXCALROAMEYEMEAS_COUNT */ sample_count_orig_msb = al_serdes_grp_reg_read(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_EYE_DIAG_SAMPLE_CNT_MSB_REG_NUM); sample_count_orig_lsb = al_serdes_grp_reg_read(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_EYE_DIAG_SAMPLE_CNT_LSB_REG_NUM); /* Set sample count to ~100000 samples */ al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_EYE_DIAG_SAMPLE_CNT_MSB_REG_NUM, 0x13); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_EYE_DIAG_SAMPLE_CNT_LSB_REG_NUM, 0x88); /* BER Contour Overwrite */ al_serdes_grp_reg_masked_write(obj, page, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALROAMEYEMEASIN_LOCWREN_REG_NUM, SERDES_IREG_FLD_RXCALROAMEYEMEASIN_LOCWREN, 0); al_serdes_grp_reg_masked_write(obj, page, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALROAMXADJUST_LOCWREN_REG_NUM, SERDES_IREG_FLD_RXCALROAMXADJUST_LOCWREN, 0); al_serdes_grp_reg_masked_write(obj, page, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALROAMYADJUST_LOCWREN_REG_NUM, SERDES_IREG_FLD_RXCALROAMYADJUST_LOCWREN, 0); /* RXROAM_XORBITSEL = 0x1 or 0x0 */ al_serdes_grp_reg_masked_write(obj, page, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXROAM_XORBITSEL_REG_NUM, SERDES_IREG_FLD_RXROAM_XORBITSEL, SERDES_IREG_FLD_RXROAM_XORBITSEL_2ND); /* Set X */ al_serdes_grp_reg_write(obj, page, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALROAMXADJUST_REG_NUM, x); /* Set Y */ al_serdes_grp_reg_write(obj, page, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALROAMYADJUST_REG_NUM, y < 32 ? 31 - y : y + 1); /* Start Measurement by setting RXCALROAMEYEMEASIN_CYCLEEN = 0x1 */ al_serdes_grp_reg_masked_write(obj, page, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALROAMEYEMEASIN_CYCLEEN_REG_NUM, SERDES_IREG_FLD_RXCALROAMEYEMEASIN_CYCLEEN_START, SERDES_IREG_FLD_RXCALROAMEYEMEASIN_CYCLEEN_START); /* Check RXCALROAMEYEMEASDONE Signal (Polling Until 0x1) */ for (i = 0; i < timeout; i++) { if (al_serdes_grp_reg_read(obj, page, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALROAMEYEMEASDONE_REG_NUM) & SERDES_IREG_FLD_RXCALROAMEYEMEASDONE) break; al_udelay(1); } if (i == timeout) { al_err("%s: eye diagram sampling timed out!\n", __func__); return -ETIMEDOUT; } /* Stop Measurement by setting RXCALROAMEYEMEASIN_CYCLEEN = 0x0 */ al_serdes_grp_reg_masked_write(obj, page, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALROAMEYEMEASIN_CYCLEEN_REG_NUM, SERDES_IREG_FLD_RXCALROAMEYEMEASIN_CYCLEEN_START, 0); /* Obtain Error Counts by reading RXCALROAMEYEMEAS_ACC */ *value = ((unsigned int)al_serdes_grp_reg_read(obj, page, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALROAMEYEMEAS_ACC_MSB_REG_NUM)) << 8 | al_serdes_grp_reg_read(obj, page, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALROAMEYEMEAS_ACC_LSB_REG_NUM); /* BER Contour Overwrite */ al_serdes_grp_reg_masked_write(obj, page, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALROAMEYEMEASIN_LOCWREN_REG_NUM, SERDES_IREG_FLD_RXCALROAMEYEMEASIN_LOCWREN, SERDES_IREG_FLD_RXCALROAMEYEMEASIN_LOCWREN); al_serdes_grp_reg_masked_write(obj, page, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALROAMXADJUST_LOCWREN_REG_NUM, SERDES_IREG_FLD_RXCALROAMXADJUST_LOCWREN, SERDES_IREG_FLD_RXCALROAMXADJUST_LOCWREN); al_serdes_grp_reg_masked_write(obj, page, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALROAMYADJUST_LOCWREN_REG_NUM, SERDES_IREG_FLD_RXCALROAMYADJUST_LOCWREN, SERDES_IREG_FLD_RXCALROAMYADJUST_LOCWREN); /* Restore sample count */ al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_EYE_DIAG_SAMPLE_CNT_MSB_REG_NUM, sample_count_orig_msb); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_EYE_DIAG_SAMPLE_CNT_LSB_REG_NUM, sample_count_orig_lsb); return 0; } /******************************************************************************/ /******************************************************************************/ static void al_serdes_tx_deemph_set( struct al_serdes_grp_obj *obj, enum al_serdes_lane lane, uint32_t c_zero, uint32_t c_plus_1, uint32_t c_minus_1) { al_serdes_grp_reg_masked_write( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_TX_DRV_1_REG_NUM, SERDES_IREG_TX_DRV_1_LEVN_MASK, ((c_zero + c_plus_1 + c_minus_1) << SERDES_IREG_TX_DRV_1_LEVN_SHIFT)); al_serdes_grp_reg_masked_write( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_TX_DRV_2_REG_NUM, SERDES_IREG_TX_DRV_2_LEVNM1_MASK, (c_plus_1 << SERDES_IREG_TX_DRV_2_LEVNM1_SHIFT)); al_serdes_grp_reg_masked_write( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_TX_DRV_3_REG_NUM, SERDES_IREG_TX_DRV_3_LEVNP1_MASK, (c_minus_1 << SERDES_IREG_TX_DRV_3_LEVNP1_SHIFT)); } static void al_serdes_tx_deemph_get( struct al_serdes_grp_obj *obj, enum al_serdes_lane lane, uint32_t *c_zero, uint32_t *c_plus_1, uint32_t *c_minus_1) { uint32_t reg = 0; reg = al_serdes_grp_reg_read( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_TX_DRV_2_REG_NUM); *c_plus_1 = ((reg & SERDES_IREG_TX_DRV_2_LEVNM1_MASK) >> SERDES_IREG_TX_DRV_2_LEVNM1_SHIFT); reg = al_serdes_grp_reg_read( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_TX_DRV_3_REG_NUM); *c_minus_1 = ((reg & SERDES_IREG_TX_DRV_3_LEVNP1_MASK) >> SERDES_IREG_TX_DRV_3_LEVNP1_SHIFT); reg = al_serdes_grp_reg_read( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_TX_DRV_1_REG_NUM); *c_zero = (((reg & SERDES_IREG_TX_DRV_1_LEVN_MASK) >> SERDES_IREG_TX_DRV_1_LEVN_SHIFT) - *c_plus_1 - *c_minus_1); } static al_bool al_serdes_tx_deemph_inc( struct al_serdes_grp_obj *obj, enum al_serdes_lane lane, enum al_serdes_tx_deemph_param param) { al_bool ret = AL_TRUE; uint32_t c0; uint32_t c1; uint32_t c_1; al_serdes_tx_deemph_get(obj, lane, &c0, &c1, &c_1); al_dbg("%s: current txdeemph: c0 = 0x%x c1 = 0x%x c-1 = 0x%x\n", __func__, c0, c1, c_1); switch (param) { case AL_SERDES_TX_DEEMP_C_ZERO: if (c0 == AL_SERDES_TX_DEEMPH_C_ZERO_MAX_VAL) return AL_FALSE; c0++; break; case AL_SERDES_TX_DEEMP_C_PLUS: if (c1 == AL_SERDES_TX_DEEMPH_C_PLUS_MAX_VAL) return AL_FALSE; c1++; break; case AL_SERDES_TX_DEEMP_C_MINUS: if (c_1 == AL_SERDES_TX_DEEMPH_C_MINUS_MAX_VAL) return AL_FALSE; c_1++; break; } if ((c0 + c1 + c_1) > AL_SERDES_TX_DEEMPH_SUM_MAX) { al_dbg("%s: sum of all tx de-emphasis over the max limit\n", __func__); return AL_FALSE; } al_dbg("%s: new txdeemph: c0 = 0x%x c1 = 0x%x c-1 = 0x%x\n", __func__, c0, c1, c_1); al_serdes_tx_deemph_set(obj, lane, c0, c1, c_1); return ret; } static al_bool al_serdes_tx_deemph_dec( struct al_serdes_grp_obj *obj, enum al_serdes_lane lane, enum al_serdes_tx_deemph_param param) { al_bool ret = AL_TRUE; uint32_t c0; uint32_t c1; uint32_t c_1; al_serdes_tx_deemph_get(obj, lane, &c0, &c1, &c_1); al_dbg("%s: current txdeemph: c0 = 0x%x c1 = 0x%x c-1 = 0x%x\n", __func__, c0, c1, c_1); switch (param) { case AL_SERDES_TX_DEEMP_C_ZERO: if (c0 == AL_SERDES_TX_DEEMPH_C_ZERO_MIN_VAL) return AL_FALSE; c0--; break; case AL_SERDES_TX_DEEMP_C_PLUS: if (c1 == AL_SERDES_TX_DEEMPH_C_PLUS_MIN_VAL) return AL_FALSE; c1--; break; case AL_SERDES_TX_DEEMP_C_MINUS: if (c_1 == AL_SERDES_TX_DEEMPH_C_MINUS_MIN_VAL) return AL_FALSE; c_1--; break; } al_dbg("%s: new txdeemph: c0 = 0x%x c1 = 0x%x c-1 = 0x%x\n", __func__, c0, c1, c_1); al_serdes_tx_deemph_set(obj, lane, c0, c1, c_1); return ret; } static void al_serdes_tx_deemph_preset( struct al_serdes_grp_obj *obj, enum al_serdes_lane lane) { uint32_t c0; uint32_t c1; uint32_t c_1; c0 = AL_SERDES_TX_DEEMPH_C_ZERO_PRESET; c1 = AL_SERDES_TX_DEEMPH_C_PLUS_PRESET; c_1 = AL_SERDES_TX_DEEMPH_C_MINUS_PRESET; al_dbg("preset: new txdeemph: c0 = 0x%x c1 = 0x%x c-1 = 0x%x\n", c0, c1, c_1); al_serdes_tx_deemph_set(obj, lane, c0, c1, c_1); } static al_bool al_serdes_signal_is_detected( struct al_serdes_grp_obj *obj, enum al_serdes_lane lane) { uint32_t reg = 0; reg = al_serdes_grp_reg_read( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXRANDET_REG_NUM); return ((reg & SERDES_IREG_FLD_RXRANDET_STAT) ? AL_TRUE : AL_FALSE); } static void al_serdes_tx_advanced_params_set(struct al_serdes_grp_obj *obj, enum al_serdes_lane lane, void *tx_params) { uint8_t reg = 0; struct al_serdes_adv_tx_params *params = tx_params; if (!params->override) { al_serdes_grp_reg_masked_write(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_TX_DRV_OVERRIDE_EN_REG_NUM, SERDES_IREG_FLD_TX_DRV_OVERRIDE_EN, SERDES_IREG_FLD_TX_DRV_OVERRIDE_EN); return; } al_serdes_grp_reg_masked_write(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_TX_DRV_OVERRIDE_EN_REG_NUM, SERDES_IREG_FLD_TX_DRV_OVERRIDE_EN, 0); AL_REG_FIELD_SET(reg, SERDES_IREG_TX_DRV_1_HLEV_MASK, SERDES_IREG_TX_DRV_1_HLEV_SHIFT, params->amp); AL_REG_FIELD_SET(reg, SERDES_IREG_TX_DRV_1_LEVN_MASK, SERDES_IREG_TX_DRV_1_LEVN_SHIFT, params->total_driver_units); al_serdes_grp_reg_write(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_TX_DRV_1_REG_NUM, reg); reg = 0; AL_REG_FIELD_SET(reg, SERDES_IREG_TX_DRV_2_LEVNM1_MASK, SERDES_IREG_TX_DRV_2_LEVNM1_SHIFT, params->c_plus_1); AL_REG_FIELD_SET(reg, SERDES_IREG_TX_DRV_2_LEVNM2_MASK, SERDES_IREG_TX_DRV_2_LEVNM2_SHIFT, params->c_plus_2); al_serdes_grp_reg_write(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_TX_DRV_2_REG_NUM, reg); reg = 0; AL_REG_FIELD_SET(reg, SERDES_IREG_TX_DRV_3_LEVNP1_MASK, SERDES_IREG_TX_DRV_3_LEVNP1_SHIFT, params->c_minus_1); AL_REG_FIELD_SET(reg, SERDES_IREG_TX_DRV_3_SLEW_MASK, SERDES_IREG_TX_DRV_3_SLEW_SHIFT, params->slew_rate); al_serdes_grp_reg_write(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_TX_DRV_3_REG_NUM, reg); } static void al_serdes_tx_advanced_params_get(struct al_serdes_grp_obj *obj, enum al_serdes_lane lane, void *tx_params) { struct al_serdes_adv_tx_params *params = tx_params; uint8_t reg_val = 0; al_serdes_reg_read(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_TX_DRV_1_REG_NUM, ®_val); params->amp = (reg_val & SERDES_IREG_TX_DRV_1_HLEV_MASK) >> SERDES_IREG_TX_DRV_1_HLEV_SHIFT; params->total_driver_units = (reg_val & SERDES_IREG_TX_DRV_1_LEVN_MASK) >> SERDES_IREG_TX_DRV_1_LEVN_SHIFT; al_serdes_reg_read(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_TX_DRV_2_REG_NUM, ®_val); params->c_plus_1 = (reg_val & SERDES_IREG_TX_DRV_2_LEVNM1_MASK) >> SERDES_IREG_TX_DRV_2_LEVNM1_SHIFT; params->c_plus_2 = (reg_val & SERDES_IREG_TX_DRV_2_LEVNM2_MASK) >> SERDES_IREG_TX_DRV_2_LEVNM2_SHIFT; al_serdes_reg_read(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_TX_DRV_3_REG_NUM, ®_val); params->c_minus_1 = (reg_val & SERDES_IREG_TX_DRV_3_LEVNP1_MASK) >> SERDES_IREG_TX_DRV_3_LEVNP1_SHIFT; params->slew_rate = (reg_val & SERDES_IREG_TX_DRV_3_SLEW_MASK) >> SERDES_IREG_TX_DRV_3_SLEW_SHIFT; al_serdes_reg_read(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_TX_DRV_OVERRIDE_EN_REG_NUM, ®_val); params->override = ((reg_val & SERDES_IREG_FLD_TX_DRV_OVERRIDE_EN) == 0); } static void al_serdes_rx_advanced_params_set(struct al_serdes_grp_obj *obj, enum al_serdes_lane lane, void *rx_params) { struct al_serdes_adv_rx_params *params = rx_params; uint8_t reg = 0; if (!params->override) { al_serdes_grp_reg_masked_write(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RX_DRV_OVERRIDE_EN_REG_NUM, SERDES_IREG_FLD_RX_DRV_OVERRIDE_EN, SERDES_IREG_FLD_RX_DRV_OVERRIDE_EN); return; } al_serdes_grp_reg_masked_write(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RX_DRV_OVERRIDE_EN_REG_NUM, SERDES_IREG_FLD_RX_DRV_OVERRIDE_EN, 0); AL_REG_FIELD_SET(reg, SERDES_IREG_RX_CALEQ_1_DCGAIN_MASK, SERDES_IREG_RX_CALEQ_1_DCGAIN_SHIFT, params->dcgain); AL_REG_FIELD_SET(reg, SERDES_IREG_RX_CALEQ_1_DFEPSTAP3DB_MASK, SERDES_IREG_RX_CALEQ_1_DFEPSTAP3DB_SHIFT, params->dfe_3db_freq); al_serdes_grp_reg_write(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_RX_CALEQ_1_REG_NUM, reg); reg = 0; AL_REG_FIELD_SET(reg, SERDES_IREG_RX_CALEQ_2_DFEPSTAPGAIN_MASK, SERDES_IREG_RX_CALEQ_2_DFEPSTAPGAIN_SHIFT, params->dfe_gain); AL_REG_FIELD_SET(reg, SERDES_IREG_RX_CALEQ_2_DFETAP1GAIN_MASK, SERDES_IREG_RX_CALEQ_2_DFETAP1GAIN_SHIFT, params->dfe_first_tap_ctrl); al_serdes_grp_reg_write(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_RX_CALEQ_2_REG_NUM, reg); reg = 0; AL_REG_FIELD_SET(reg, SERDES_IREG_RX_CALEQ_3_DFETAP2GAIN_MASK, SERDES_IREG_RX_CALEQ_3_DFETAP2GAIN_SHIFT, params->dfe_secound_tap_ctrl); AL_REG_FIELD_SET(reg, SERDES_IREG_RX_CALEQ_3_DFETAP3GAIN_MASK, SERDES_IREG_RX_CALEQ_3_DFETAP3GAIN_SHIFT, params->dfe_third_tap_ctrl); al_serdes_grp_reg_write(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_RX_CALEQ_3_REG_NUM, reg); reg = 0; AL_REG_FIELD_SET(reg, SERDES_IREG_RX_CALEQ_4_DFETAP4GAIN_MASK, SERDES_IREG_RX_CALEQ_4_DFETAP4GAIN_SHIFT, params->dfe_fourth_tap_ctrl); AL_REG_FIELD_SET(reg, SERDES_IREG_RX_CALEQ_4_LOFREQAGCGAIN_MASK, SERDES_IREG_RX_CALEQ_4_LOFREQAGCGAIN_SHIFT, params->low_freq_agc_gain); al_serdes_grp_reg_write(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_RX_CALEQ_4_REG_NUM, reg); reg = 0; AL_REG_FIELD_SET(reg, SERDES_IREG_RX_CALEQ_5_PRECAL_CODE_SEL_MASK, SERDES_IREG_RX_CALEQ_5_PRECAL_CODE_SEL_SHIFT, params->precal_code_sel); AL_REG_FIELD_SET(reg, SERDES_IREG_RX_CALEQ_5_HIFREQAGCCAP_MASK, SERDES_IREG_RX_CALEQ_5_HIFREQAGCCAP_SHIFT, params->high_freq_agc_boost); al_serdes_grp_reg_write(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_RX_CALEQ_5_REG_NUM, reg); } static inline void al_serdes_common_cfg_eth(struct al_serdes_grp_obj *obj) { al_serdes_grp_reg_masked_write( obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXEQ_LOOKUP_CODE_EN_REG_NUM, SERDES_IREG_FLD_RXEQ_LOOKUP_CODE_EN_MASK, (0x1 << SERDES_IREG_FLD_RXEQ_LOOKUP_CODE_EN_SHIFT)); al_serdes_grp_reg_masked_write( obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXEQ_LOOKUP_LASTCODE_REG_NUM, SERDES_IREG_FLD_RXEQ_LOOKUP_LASTCODE_MASK, (0 << SERDES_IREG_FLD_RXEQ_LOOKUP_LASTCODE_SHIFT)); al_serdes_grp_reg_masked_write( obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXEQ_COARSE_RUN1_MASK_REG_NUM, SERDES_IREG_FLD_RXEQ_COARSE_RUN1_MASK_MASK, (0x2 << SERDES_IREG_FLD_RXEQ_COARSE_RUN1_MASK_SHIFT)); al_serdes_grp_reg_masked_write( obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXEQ_COARSE_RUN2_MASK_REG_NUM, SERDES_IREG_FLD_RXEQ_COARSE_RUN2_MASK_MASK, (0 << SERDES_IREG_FLD_RXEQ_COARSE_RUN2_MASK_SHIFT)); al_serdes_grp_reg_masked_write( obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXEQ_COARSE_STEP_REG_NUM, SERDES_IREG_FLD_RXEQ_COARSE_STEP_MASK, (0x1 << SERDES_IREG_FLD_RXEQ_COARSE_STEP_SHIFT)); al_serdes_grp_reg_masked_write( obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXEQ_COARSE_ITER_NUM_REG_NUM, SERDES_IREG_FLD_RXEQ_COARSE_ITER_NUM_MASK, (0x1 << SERDES_IREG_FLD_RXEQ_COARSE_ITER_NUM_SHIFT)); al_serdes_grp_reg_masked_write( obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXEQ_FINE_RUN1_MASK_REG_NUM, SERDES_IREG_FLD_RXEQ_FINE_RUN1_MASK_MASK, (0xf0 << SERDES_IREG_FLD_RXEQ_FINE_RUN1_MASK_SHIFT)); al_serdes_grp_reg_masked_write( obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXEQ_FINE_RUN2_MASK_REG_NUM, SERDES_IREG_FLD_RXEQ_FINE_RUN2_MASK_MASK, (0 << SERDES_IREG_FLD_RXEQ_FINE_RUN2_MASK_SHIFT)); al_serdes_grp_reg_masked_write( obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXEQ_FINE_STEP_REG_NUM, SERDES_IREG_FLD_RXEQ_FINE_STEP_MASK, (1 << SERDES_IREG_FLD_RXEQ_FINE_STEP_SHIFT)); al_serdes_grp_reg_masked_write( obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXEQ_FINE_ITER_NUM_REG_NUM, SERDES_IREG_FLD_RXEQ_FINE_ITER_NUM_MASK, (0x8 << SERDES_IREG_FLD_RXEQ_FINE_ITER_NUM_SHIFT)); al_serdes_grp_reg_masked_write( obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALEYEDIAGFSM_BERTHRESHOLD1_REG_NUM, SERDES_IREG_FLD_RXCALEYEDIAGFSM_BERTHRESHOLD1_MASK, (0 << SERDES_IREG_FLD_RXCALEYEDIAGFSM_BERTHRESHOLD1_SHIFT)); al_serdes_grp_reg_masked_write( obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALEYEDIAGFSM_BERTHRESHOLD2_REG_NUM, SERDES_IREG_FLD_RXCALEYEDIAGFSM_BERTHRESHOLD2_MASK, (0x64 << SERDES_IREG_FLD_RXCALEYEDIAGFSM_BERTHRESHOLD2_SHIFT)); al_serdes_grp_reg_masked_write( obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALEYEDIAGFSM_XVALCOARSE_REG_NUM, SERDES_IREG_FLD_RXCALEYEDIAGFSM_XVALCOARSE_MASK, (0x3 << SERDES_IREG_FLD_RXCALEYEDIAGFSM_XVALCOARSE_SHIFT)); al_serdes_grp_reg_masked_write( obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALEYEDIAGFSM_XVALFINE_REG_NUM, SERDES_IREG_FLD_RXCALEYEDIAGFSM_XVALFINE_MASK, (0x1 << SERDES_IREG_FLD_RXCALEYEDIAGFSM_XVALFINE_SHIFT)); al_serdes_grp_reg_masked_write( obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALEYEDIAGFSM_YVALCOARSE_REG_NUM, SERDES_IREG_FLD_RXCALEYEDIAGFSM_YVALCOARSE_MASK, (3 << SERDES_IREG_FLD_RXCALEYEDIAGFSM_YVALCOARSE_SHIFT)); al_serdes_grp_reg_masked_write( obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALEYEDIAGFSM_YVALFINE_REG_NUM, SERDES_IREG_FLD_RXCALEYEDIAGFSM_YVALFINE_MASK, (1 << SERDES_IREG_FLD_RXCALEYEDIAGFSM_YVALFINE_SHIFT)); al_serdes_grp_reg_masked_write( obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_EYE_DIAG_SAMPLE_CNT_MSB_REG_NUM, SERDES_IREG_FLD_EYE_DIAG_SAMPLE_CNT_MSB_MASK, (0xc << SERDES_IREG_FLD_EYE_DIAG_SAMPLE_CNT_MSB_SHIFT)); al_serdes_grp_reg_masked_write( obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_EYE_DIAG_SAMPLE_CNT_LSB_REG_NUM, SERDES_IREG_FLD_EYE_DIAG_SAMPLE_CNT_LSB_MASK, (0xcc << SERDES_IREG_FLD_EYE_DIAG_SAMPLE_CNT_LSB_SHIFT)); } struct al_serdes_mode_rx_tx_inv_state { al_bool restore; uint32_t pipe_rst; uint32_t ipd_multi[AL_SRDS_NUM_LANES]; uint8_t inv_value[AL_SRDS_NUM_LANES]; }; static void al_serdes_mode_rx_tx_inv_state_save( struct al_serdes_grp_obj *obj, struct al_serdes_mode_rx_tx_inv_state *state) { struct al_serdes_regs __iomem *regs_base = obj->regs_base; if (al_reg_read32(®s_base->gen.irst) & SERDES_GEN_IRST_POR_B_A) { int i; state->restore = AL_TRUE; state->pipe_rst = al_reg_read32(®s_base->gen.irst); for (i = 0; i < AL_SRDS_NUM_LANES; i++) { state->inv_value[i] = al_serdes_grp_reg_read( obj, i, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_POLARITY_RX_REG_NUM); state->ipd_multi[i] = al_reg_read32(®s_base->lane[i].ipd_multi); } } else { state->restore = AL_FALSE; } } static void al_serdes_mode_rx_tx_inv_state_restore( struct al_serdes_grp_obj *obj, struct al_serdes_mode_rx_tx_inv_state *state) { struct al_serdes_regs __iomem *regs_base = obj->regs_base; if (state->restore) { int i; for (i = 0; i < AL_SRDS_NUM_LANES; i++) { al_serdes_grp_reg_write( obj, i, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_POLARITY_RX_REG_NUM, state->inv_value[i]); al_reg_write32( ®s_base->lane[i].ipd_multi, state->ipd_multi[i]); al_reg_write32_masked( ®s_base->gen.irst, (SERDES_GEN_IRST_PIPE_RST_L0_B_A_SEL >> i) | (SERDES_GEN_IRST_PIPE_RST_L0_B_A >> i), state->pipe_rst); } } } static void al_serdes_mode_set_sgmii( struct al_serdes_grp_obj *obj) { struct al_serdes_grp_obj *grp_obj = obj; struct al_serdes_regs __iomem *regs_base = grp_obj->regs_base; struct al_serdes_mode_rx_tx_inv_state rx_tx_inv_state; al_assert(obj); al_serdes_mode_rx_tx_inv_state_save(grp_obj, &rx_tx_inv_state); al_reg_write32(®s_base->gen.irst, 0x000000); al_reg_write32(®s_base->lane[0].ictl_multi, 0x10110010); al_reg_write32(®s_base->lane[1].ictl_multi, 0x10110010); al_reg_write32(®s_base->lane[2].ictl_multi, 0x10110010); al_reg_write32(®s_base->lane[3].ictl_multi, 0x10110010); al_reg_write32(®s_base->gen.ipd_multi_synth , 0x0001); al_reg_write32(®s_base->lane[0].ipd_multi, 0x0003); al_reg_write32(®s_base->lane[1].ipd_multi, 0x0003); al_reg_write32(®s_base->lane[2].ipd_multi, 0x0003); al_reg_write32(®s_base->lane[3].ipd_multi, 0x0003); al_reg_write32(®s_base->gen.ictl_pcs , 0); al_reg_write32(®s_base->gen.irst, 0x001000); al_serdes_ns_delay(800); al_reg_write32(®s_base->gen.irst, 0x000000); al_serdes_ns_delay(500); al_reg_write32(®s_base->gen.irst, 0x001000); al_serdes_ns_delay(500); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_0123_LANES_0123, AL_SRDS_REG_TYPE_PMA, 101, 183); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_0123_LANES_0123, AL_SRDS_REG_TYPE_PMA, 102, 183); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_0123_LANES_0123, AL_SRDS_REG_TYPE_PMA, 103, 12); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_0123_LANES_0123, AL_SRDS_REG_TYPE_PMA, 104, 12); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_0123_LANES_0123, AL_SRDS_REG_TYPE_PMA, 105, 26); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_0123_LANES_0123, AL_SRDS_REG_TYPE_PMA, 106, 26); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_0123_LANES_0123, AL_SRDS_REG_TYPE_PMA, 107, 2); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_0123_LANES_0123, AL_SRDS_REG_TYPE_PMA, 108, 2); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_0123_LANES_0123, AL_SRDS_REG_TYPE_PMA, 109, 17); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_0123_LANES_0123, AL_SRDS_REG_TYPE_PMA, 110, 13); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 101, 153); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 102, 0); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 103, 108); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 104, 183); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 105, 183); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 106, 12); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 107, 12); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 108, 26); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 109, 26); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 110, 7); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 111, 12); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 112, 8); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 113, 0); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 114, 8); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 115, 0); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 116, 255); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 117, 179); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 118, 246); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 119, 208); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 120, 239); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 121, 251); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 122, 255); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 123, 255); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 124, 255); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 125, 255); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 126, 255); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 127, 211); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 128, 211); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 129, 226); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 130, 239); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 131, 251); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 132, 251); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 133, 255); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 134, 239); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 135, 255); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 136, 255); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 137, 211); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 138, 211); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 139, 226); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 140, 239); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 141, 251); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 142, 251); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 143, 255); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 144, 239); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 145, 255); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 146, 255); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 147, 251); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 148, 255); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 149, 63); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 150, 0); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 151, 100); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 152, 0); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 153, 4); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 154, 2); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 155, 5); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 156, 5); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 157, 4); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 158, 0); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 159, 0); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 160, 8); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 161, 4); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 162, 0); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 163, 0); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 164, 4); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_0_LANE_0, AL_SRDS_REG_TYPE_PMA, 7, 0); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_1_LANE_1, AL_SRDS_REG_TYPE_PMA, 7, 0); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_2_LANE_2, AL_SRDS_REG_TYPE_PMA, 7, 0); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_3_LANE_3, AL_SRDS_REG_TYPE_PMA, 7, 0); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 13, 16); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 48, 0); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 49, 0); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 54, 0); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 55, 180); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 93, 2); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 165, 3); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_0123_LANES_0123, AL_SRDS_REG_TYPE_PMA, 41, 6); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 354, 3); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 355, 58); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 356, 9); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 357, 3); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 358, 62); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 359, 12); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_0123_LANES_0123, AL_SRDS_REG_TYPE_PMA, 701, 0); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_0123_LANES_0123, AL_SRDS_REG_TYPE_PMA, 87, 0x1f); al_serdes_common_cfg_eth(obj); al_serdes_mode_rx_tx_inv_state_restore(grp_obj, &rx_tx_inv_state); al_reg_write32(®s_base->gen.irst, 0x0011F0); al_serdes_ns_delay(500); } static void al_serdes_mode_set_kr( struct al_serdes_grp_obj *obj) { struct al_serdes_grp_obj *grp_obj = obj; struct al_serdes_regs __iomem *regs_base = grp_obj->regs_base; struct al_serdes_mode_rx_tx_inv_state rx_tx_inv_state; al_assert(obj); al_serdes_mode_rx_tx_inv_state_save(grp_obj, &rx_tx_inv_state); al_reg_write32(®s_base->gen.irst, 0x000000); al_reg_write32(®s_base->lane[0].ictl_multi, 0x30330030); al_reg_write32(®s_base->lane[1].ictl_multi, 0x30330030); al_reg_write32(®s_base->lane[2].ictl_multi, 0x30330030); al_reg_write32(®s_base->lane[3].ictl_multi, 0x30330030); al_reg_write32(®s_base->gen.ipd_multi_synth , 0x0001); al_reg_write32(®s_base->lane[0].ipd_multi, 0x0003); al_reg_write32(®s_base->lane[1].ipd_multi, 0x0003); al_reg_write32(®s_base->lane[2].ipd_multi, 0x0003); al_reg_write32(®s_base->lane[3].ipd_multi, 0x0003); al_reg_write32(®s_base->gen.ictl_pcs , 0); al_reg_write32(®s_base->gen.irst, 0x001000); al_serdes_ns_delay(800); al_reg_write32(®s_base->gen.irst, 0x000000); al_serdes_ns_delay(500); al_reg_write32(®s_base->gen.irst, 0x001000); al_serdes_ns_delay(500); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_0123_LANES_0123, AL_SRDS_REG_TYPE_PMA, 101, 189); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_0123_LANES_0123, AL_SRDS_REG_TYPE_PMA, 102, 189); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_0123_LANES_0123, AL_SRDS_REG_TYPE_PMA, 103, 6); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_0123_LANES_0123, AL_SRDS_REG_TYPE_PMA, 104, 6); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_0123_LANES_0123, AL_SRDS_REG_TYPE_PMA, 105, 27); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_0123_LANES_0123, AL_SRDS_REG_TYPE_PMA, 106, 27); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_0123_LANES_0123, AL_SRDS_REG_TYPE_PMA, 107, 1); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_0123_LANES_0123, AL_SRDS_REG_TYPE_PMA, 108, 1); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_0123_LANES_0123, AL_SRDS_REG_TYPE_PMA, 109, 119); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_0123_LANES_0123, AL_SRDS_REG_TYPE_PMA, 110, 5); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 101, 170); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 102, 0); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 103, 108); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 104, 189); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 105, 189); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 106, 6); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 107, 6); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 108, 27); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 109, 27); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 110, 7); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 111, 12); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 112, 16); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 113, 0); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 114, 16); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 115, 0); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 116, 255); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 117, 179); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 118, 246); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 119, 208); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 120, 239); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 121, 251); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 122, 255); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 123, 255); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 124, 255); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 125, 255); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 126, 255); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 127, 211); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 128, 211); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 129, 226); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 130, 239); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 131, 251); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 132, 251); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 133, 255); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 134, 239); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 135, 255); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 136, 255); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 137, 211); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 138, 211); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 139, 226); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 140, 239); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 141, 251); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 142, 251); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 143, 255); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 144, 239); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 145, 255); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 146, 255); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 147, 251); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 148, 255); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 149, 63); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 150, 0); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 151, 50); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 152, 17); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 153, 2); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 154, 1); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 155, 0); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 156, 0); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 157, 4); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 158, 0); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 159, 0); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 160, 8); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 161, 4); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 162, 0); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 163, 0); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 164, 4); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_0_LANE_0, AL_SRDS_REG_TYPE_PMA, 7, 0); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_1_LANE_1, AL_SRDS_REG_TYPE_PMA, 7, 0); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_2_LANE_2, AL_SRDS_REG_TYPE_PMA, 7, 0); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_3_LANE_3, AL_SRDS_REG_TYPE_PMA, 7, 0); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 13, 16); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 48, 0); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 49, 0); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 54, 0); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 55, 149); /*Was 182*/ al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 93, 2); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 165, 3); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_0123_LANES_0123, AL_SRDS_REG_TYPE_PMA, 41, 6); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 354, 3); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 355, 58); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 356, 9); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 357, 3); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 358, 62); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, 359, 12); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_0123_LANES_0123, AL_SRDS_REG_TYPE_PMA, 701, 0); al_serdes_grp_reg_write(obj, AL_SRDS_REG_PAGE_0123_LANES_0123, AL_SRDS_REG_TYPE_PMA, 87, 0x1f); al_serdes_common_cfg_eth(obj); al_serdes_mode_rx_tx_inv_state_restore(grp_obj, &rx_tx_inv_state); al_reg_write32(®s_base->gen.irst, 0x0011F0); al_serdes_ns_delay(500); } static void al_serdes_rx_advanced_params_get(struct al_serdes_grp_obj *obj, enum al_serdes_lane lane, void *rx_params) { struct al_serdes_adv_rx_params *params = rx_params; uint8_t temp_val; al_serdes_reg_read( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_RX_CALEQ_1_REG_NUM, &temp_val); params->dcgain = (temp_val & SERDES_IREG_RX_CALEQ_1_DCGAIN_MASK) >> SERDES_IREG_RX_CALEQ_1_DCGAIN_SHIFT; params->dfe_3db_freq = (temp_val & SERDES_IREG_RX_CALEQ_1_DFEPSTAP3DB_MASK) >> SERDES_IREG_RX_CALEQ_1_DFEPSTAP3DB_SHIFT; al_serdes_reg_read( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_RX_CALEQ_2_REG_NUM, &temp_val); params->dfe_gain = (temp_val & SERDES_IREG_RX_CALEQ_2_DFEPSTAPGAIN_MASK) >> SERDES_IREG_RX_CALEQ_2_DFEPSTAPGAIN_SHIFT; params->dfe_first_tap_ctrl = (temp_val & SERDES_IREG_RX_CALEQ_2_DFETAP1GAIN_MASK) >> SERDES_IREG_RX_CALEQ_2_DFETAP1GAIN_SHIFT; al_serdes_reg_read( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_RX_CALEQ_3_REG_NUM, &temp_val); params->dfe_secound_tap_ctrl = (temp_val & SERDES_IREG_RX_CALEQ_3_DFETAP2GAIN_MASK) >> SERDES_IREG_RX_CALEQ_3_DFETAP2GAIN_SHIFT; params->dfe_third_tap_ctrl = (temp_val & SERDES_IREG_RX_CALEQ_3_DFETAP3GAIN_MASK) >> SERDES_IREG_RX_CALEQ_3_DFETAP3GAIN_SHIFT; al_serdes_reg_read( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_RX_CALEQ_4_REG_NUM, &temp_val); params->dfe_fourth_tap_ctrl = (temp_val & SERDES_IREG_RX_CALEQ_4_DFETAP4GAIN_MASK) >> SERDES_IREG_RX_CALEQ_4_DFETAP4GAIN_SHIFT; params->low_freq_agc_gain = (temp_val & SERDES_IREG_RX_CALEQ_4_LOFREQAGCGAIN_MASK) >> SERDES_IREG_RX_CALEQ_4_LOFREQAGCGAIN_SHIFT; al_serdes_reg_read( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_RX_CALEQ_5_REG_NUM, &temp_val); params->precal_code_sel = (temp_val & SERDES_IREG_RX_CALEQ_5_PRECAL_CODE_SEL_MASK) >> SERDES_IREG_RX_CALEQ_5_PRECAL_CODE_SEL_SHIFT; params->high_freq_agc_boost = (temp_val & SERDES_IREG_RX_CALEQ_5_HIFREQAGCCAP_MASK) >> SERDES_IREG_RX_CALEQ_5_HIFREQAGCCAP_SHIFT; al_serdes_reg_read(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RX_DRV_OVERRIDE_EN_REG_NUM, &temp_val); params->override = ((temp_val & SERDES_IREG_FLD_RX_DRV_OVERRIDE_EN) == 0); } #if (SERDES_IREG_FLD_RXCALEYEDIAGFSMIN_LOCWREN_REG_NUM != \ SERDES_IREG_FLD_RXCALROAMEYEMEASIN_LOCWREN_REG_NUM || \ SERDES_IREG_FLD_RXCALEYEDIAGFSMIN_LOCWREN_REG_NUM != \ SERDES_IREG_FLD_RXCALROAMXADJUST_LOCWREN_REG_NUM) #error Wrong assumption #endif static int al_serdes_rx_equalization( struct al_serdes_grp_obj *obj, enum al_serdes_lane lane) { uint8_t serdes_ireg_fld_rxcalroamyadjust_locwren_val; uint8_t serdes_ireg_fld_rxroam_xorbitsel_val; uint8_t serdes_ireg_fld_pcsrxeq_locwren_val; uint8_t serdes_ireg_fld_rxcal_locwren_val; uint8_t temp_val; uint8_t done; int test_score; int i; /* * Make sure Roam Eye mechanism is not overridden * Lane SERDES_IREG_FLD_RXCALEYEDIAGFSMIN_LOCWREN = 1, * so Rx 4-Point Eye process is not overridden * Lane SERDES_IREG_FLD_RXCALROAMEYEMEASIN_LOCWREN = 1, * so Eye Roam latch is not overridden * Lane SERDES_IREG_FLD_RXCALROAMXADJUST_LOCWREN = 1, * so Eye Roam latch 'X adjust' is not overridden * Lane SERDES_IREG_FLD_RXCALROAMYADJUST_LOCWREN = 1, * so Eye Roam latch 'Y adjust' is not overridden * Lane SERDES_IREG_FLD_RXROAM_XORBITSEL = 0/1, * so Eye Roamlatch works on the right Eye position (XORBITSEL) * For most cases 0 is needed, but sometimes 1 is needed. * I couldn't sort out why is this so the code uses a global * XORBITSELmode variable, set by the user (GUI). Default is 0. * control must be internal. At the end we restore original setting */ /* save current values for restoring them later in the end */ al_serdes_reg_read( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCAL_LOCWREN_REG_NUM, &serdes_ireg_fld_rxcal_locwren_val); al_serdes_reg_read( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALROAMYADJUST_LOCWREN_REG_NUM, &serdes_ireg_fld_rxcalroamyadjust_locwren_val); al_serdes_reg_read( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXROAM_XORBITSEL_REG_NUM, &serdes_ireg_fld_rxroam_xorbitsel_val); al_serdes_reg_read( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_PCSRXEQ_LOCWREN_REG_NUM, &serdes_ireg_fld_pcsrxeq_locwren_val); /* * Set Bits: * SERDES_IREG_FLD_RXCALEYEDIAGFSMIN_LOCWREN * SERDES_IREG_FLD_RXCALROAMEYEMEASIN_LOCWREN * SERDES_IREG_FLD_RXCALROAMXADJUST_LOCWREN * to return 4pt-RxEye and EyeRoam Latch to internal logic * * clear bit SERDES_IREG_FLD_RX_DRV_OVERRIDE_EN * AGC/DFE controlled via PMA registers */ temp_val = serdes_ireg_fld_rxcal_locwren_val; temp_val |= SERDES_IREG_FLD_RXCALEYEDIAGFSMIN_LOCWREN; temp_val |= SERDES_IREG_FLD_RXCALROAMEYEMEASIN_LOCWREN; temp_val |= SERDES_IREG_FLD_RXCALROAMXADJUST_LOCWREN; temp_val |= SERDES_IREG_FLD_RX_DRV_OVERRIDE_EN; al_serdes_reg_write( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCAL_LOCWREN_REG_NUM, temp_val); /* * Set bit SERDES_IREG_FLD_RXCALROAMYADJUST_LOCWREN * to return EyeRoam Latch Y to internal logic */ temp_val = serdes_ireg_fld_rxcalroamyadjust_locwren_val | SERDES_IREG_FLD_RXCALROAMYADJUST_LOCWREN; al_serdes_reg_write( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALROAMYADJUST_LOCWREN_REG_NUM, temp_val); /* * Clear Bit: SERDES_IREG_FLD_RXROAM_XORBITSEL * so XORBITSEL=0, needed for the Eye mapping. */ temp_val = serdes_ireg_fld_rxroam_xorbitsel_val & ~SERDES_IREG_FLD_RXROAM_XORBITSEL; al_serdes_reg_write( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXROAM_XORBITSEL_REG_NUM, temp_val); /* * Take Control from int.pin over RxEQ process. * Clear Bit SERDES_IREG_FLD_PCSRXEQ_LOCWREN * to override RxEQ via PMA */ temp_val = serdes_ireg_fld_pcsrxeq_locwren_val & ~SERDES_IREG_FLD_PCSRXEQ_LOCWREN; al_serdes_reg_write( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_PCSRXEQ_LOCWREN_REG_NUM, temp_val); /* * Start/Stop RxEQ Cal is via PCSRXEQ_START: 1=START. 0=STOP. * Clear Bit SERDES_IREG_FLD_PCSRXEQ_START * to start fresh from Stop */ al_serdes_reg_read( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_PCSRXEQ_START_REG_NUM, &temp_val); temp_val &= ~SERDES_IREG_FLD_PCSRXEQ_START; al_serdes_reg_write( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_PCSRXEQ_START_REG_NUM, temp_val); /* Set Bit SERDES_IREG_FLD_PCSRXEQ_START * to begin Rx Eq Cal */ temp_val |= SERDES_IREG_FLD_PCSRXEQ_START; al_serdes_reg_write( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_PCSRXEQ_START_REG_NUM, temp_val); /* Poll on RxEq Cal completion. SERDES_IREG_FLD_RXEQ_DONE. 1=Done. */ for (i = 0; i < AL_SERDES_RX_EQUAL_TRIES; ++i) { al_serdes_reg_read( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALROAMEYEMEASDONE_REG_NUM, &done); done &= SERDES_IREG_FLD_RXEQ_DONE; /* Check if RxEQ Cal is done */ if (done) break; al_msleep(AL_SERDES_RX_EQUAL_MDELAY); } if (!done) { al_err("%s: Timeout!\n", __func__); return -1; } /* Stop the RxEQ process. */ temp_val &= ~SERDES_IREG_FLD_PCSRXEQ_START; al_serdes_reg_write( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_PCSRXEQ_START_REG_NUM, temp_val); /* Get score */ al_serdes_reg_read( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_RXEQ_BEST_EYE_MSB_VAL_REG_NUM, &temp_val); test_score = (int)((temp_val & 0xFF) << 6); al_serdes_reg_read( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_RXEQ_BEST_EYE_LSB_VAL_REG_NUM, &temp_val); test_score += (int)(temp_val & SERDES_IREG_RXEQ_BEST_EYE_LSB_VAL_MASK); /* Restore start values */ al_serdes_reg_write( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCAL_LOCWREN_REG_NUM, serdes_ireg_fld_rxcal_locwren_val); al_serdes_reg_write( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALROAMYADJUST_LOCWREN_REG_NUM, serdes_ireg_fld_rxcalroamyadjust_locwren_val); al_serdes_reg_write( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXROAM_XORBITSEL_REG_NUM, serdes_ireg_fld_rxroam_xorbitsel_val); al_serdes_reg_write( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_PCSRXEQ_LOCWREN_REG_NUM, serdes_ireg_fld_pcsrxeq_locwren_val); return test_score; } #if (SERDES_IREG_FLD_RXCAL_LOCWREN_REG_NUM != \ SERDES_IREG_FLD_RXCALROAMEYEMEASIN_LOCWREN_REG_NUM || \ SERDES_IREG_FLD_RXCAL_LOCWREN_REG_NUM != \ SERDES_IREG_FLD_RXCALROAMXADJUST_LOCWREN_REG_NUM || \ SERDES_IREG_FLD_RXCAL_LOCWREN_REG_NUM != \ SERDES_IREG_FLD_RXCALEYEDIAGFSMIN_LOCWREN_REG_NUM) #error Wrong assumption #endif static int al_serdes_calc_eye_size( struct al_serdes_grp_obj *obj, enum al_serdes_lane lane, int *width, int *height) { uint8_t rxcaleyediagfsm_x_y_valweight_val; uint8_t rxcaleyediagfsm_xvalcoarse_val; uint8_t rxcaleyediagfsm_xvalfine_val; uint8_t rxcaleyediagfsm_yvalcoarse_val; uint8_t rxcaleyediagfsm_yvalfine_val; uint8_t rxlock2ref_locwren_val; uint8_t rxcal_locwren_val; uint8_t rxcalroamyadjust_locwren_val; uint8_t rxlock2ref_ovren_val; int i; uint8_t status; uint8_t reg_value; /* Save Registers */ al_serdes_reg_read(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXLOCK2REF_LOCWREN_REG_NUM, &rxlock2ref_locwren_val); al_serdes_reg_read(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCAL_LOCWREN_REG_NUM, &rxcal_locwren_val); al_serdes_reg_read(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALROAMYADJUST_LOCWREN_REG_NUM, &rxcalroamyadjust_locwren_val); al_serdes_reg_read(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXLOCK2REF_OVREN_REG_NUM, &rxlock2ref_ovren_val); al_serdes_reg_read(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALEYEDIAGFSM_X_Y_VALWEIGHT_REG_NUM, &rxcaleyediagfsm_x_y_valweight_val); al_serdes_reg_read(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALEYEDIAGFSM_XVALCOARSE_REG_NUM, &rxcaleyediagfsm_xvalcoarse_val); al_serdes_reg_read(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALEYEDIAGFSM_XVALFINE_REG_NUM, &rxcaleyediagfsm_xvalfine_val); al_serdes_reg_read(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALEYEDIAGFSM_YVALCOARSE_REG_NUM, &rxcaleyediagfsm_yvalcoarse_val); al_serdes_reg_read(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALEYEDIAGFSM_YVALFINE_REG_NUM, &rxcaleyediagfsm_yvalfine_val); /* * Clear Bit: * SERDES_IREG_FLD_RXCALEYEDIAGFSMIN_LOCWREN * to override RxEQ via PMA * Set Bits: * SERDES_IREG_FLD_RXCALROAMEYEMEASIN_LOCWREN, * SERDES_IREG_FLD_RXCALROAMXADJUST_LOCWREN * to keep Eye Diag Roam controlled internally */ al_serdes_grp_reg_masked_write(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCAL_LOCWREN_REG_NUM, SERDES_IREG_FLD_RXCALEYEDIAGFSMIN_LOCWREN | SERDES_IREG_FLD_RXCALROAMEYEMEASIN_LOCWREN | SERDES_IREG_FLD_RXCALROAMXADJUST_LOCWREN, SERDES_IREG_FLD_RXCALROAMEYEMEASIN_LOCWREN | SERDES_IREG_FLD_RXCALROAMXADJUST_LOCWREN); /* * Set Bit: * SERDES_IREG_FLD_RXCALROAMYADJUST_LOCWREN * to keep Eye Diag Roam controlled internally */ al_serdes_grp_reg_masked_write(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALROAMYADJUST_LOCWREN_REG_NUM, SERDES_IREG_FLD_RXCALROAMYADJUST_LOCWREN, SERDES_IREG_FLD_RXCALROAMYADJUST_LOCWREN); /* * Clear Bit: * SERDES_IREG_FLD_RXROAM_XORBITSEL, * so XORBITSEL=0, needed for the Eye mapping * Set Bit: * SERDES_IREG_FLD_RXLOCK2REF_OVREN, * so RXLOCK2REF_OVREN=1, keeping lock to data, preventing data hit */ al_serdes_grp_reg_masked_write(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXROAM_XORBITSEL_REG_NUM, SERDES_IREG_FLD_RXLOCK2REF_OVREN | SERDES_IREG_FLD_RXROAM_XORBITSEL, SERDES_IREG_FLD_RXLOCK2REF_OVREN); /* * Clear Bit: * SERDES_IREG_FLD_RXLOCK2REF_LOCWREN, * so RXLOCK2REF_LOCWREN=0, to override control */ al_serdes_grp_reg_masked_write(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXLOCK2REF_LOCWREN_REG_NUM, SERDES_IREG_FLD_RXLOCK2REF_LOCWREN, 0); /* Width Calculation */ /* Return Value = 0*Y + 1*X */ al_serdes_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALEYEDIAGFSM_X_Y_VALWEIGHT_REG_NUM, 0x01); /* X coarse scan step = 3 */ al_serdes_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALEYEDIAGFSM_XVALCOARSE_REG_NUM, 0x03); /* X fine scan step = 1 */ al_serdes_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALEYEDIAGFSM_XVALFINE_REG_NUM, 0x01); /* Y coarse scan step = 0 */ al_serdes_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALEYEDIAGFSM_YVALCOARSE_REG_NUM, 0x00); /* Y fine scan step = 0 */ al_serdes_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALEYEDIAGFSM_YVALFINE_REG_NUM, 0x00); /* * Set Bit: * SERDES_IREG_FLD_RXCALEYEDIAGFSMIN_START, * to start Eye measurement */ al_serdes_grp_reg_masked_write(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALEYEDIAGFSMIN_START_REG_NUM, SERDES_IREG_FLD_RXCALEYEDIAGFSMIN_START, SERDES_IREG_FLD_RXCALEYEDIAGFSMIN_START); for(i = 0; i < AL_SERDES_RX_EYE_CAL_TRIES; ++i) { /* Check if RxEQ Cal is done */ al_serdes_reg_read( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALEYEDIAGFSM_DONE_REG_NUM, &status); if (status & SERDES_IREG_FLD_RXCALEYEDIAGFSM_DONE) break; al_msleep(AL_SERDES_RX_EYE_CAL_MDELAY); } if (status & SERDES_IREG_FLD_RXCALEYEDIAGFSM_ERR) { al_err("%s: eye measure error!\n", __func__); return -1; } if (!(status & SERDES_IREG_FLD_RXCALEYEDIAGFSM_DONE)) { al_err("%s: eye measure timeout!\n", __func__); return -1; } /* Read Eye Opening Metrics, Bits: * SERDES_IREG_FLD_RXCALEYEDIAGFSM_EYESUM_LSB, * SERDES_IREG_FLD_RXCALEYEDIAGFSM_EYESUM_LSB */ al_serdes_reg_read( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALEYEDIAGFSM_EYESUM_MSB_REG_NUM, ®_value); *width = reg_value << 6; al_serdes_reg_read( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALEYEDIAGFSM_EYESUM_LSB_REG_NUM, ®_value); *width =+ reg_value & SERDES_IREG_FLD_RXCALEYEDIAGFSM_EYESUM_LSB_MAKE; /* * Clear Bit: * SERDES_IREG_FLD_RXCALEYEDIAGFSMIN_START, * to stop Eye measurement */ al_serdes_grp_reg_masked_write(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALEYEDIAGFSMIN_START_REG_NUM, SERDES_IREG_FLD_RXCALEYEDIAGFSMIN_START, 0); /* Height Calculation */ /* Return Value = 1*Y + 0*X */ al_serdes_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALEYEDIAGFSM_X_Y_VALWEIGHT_REG_NUM, 0x10); /* X coarse scan step = 0 */ al_serdes_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALEYEDIAGFSM_XVALCOARSE_REG_NUM, 0x00); /* X fine scan step = 0 */ al_serdes_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALEYEDIAGFSM_XVALFINE_REG_NUM, 0x00); /* Y coarse scan step = 3 */ al_serdes_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALEYEDIAGFSM_YVALCOARSE_REG_NUM, 0x03); /* Y fine scan step = 1 */ al_serdes_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALEYEDIAGFSM_YVALFINE_REG_NUM, 0x01); /* * Set Bit: * SERDES_IREG_FLD_RXCALEYEDIAGFSMIN_START, * to start Eye measurement */ al_serdes_grp_reg_masked_write(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALEYEDIAGFSMIN_START_REG_NUM, SERDES_IREG_FLD_RXCALEYEDIAGFSMIN_START, SERDES_IREG_FLD_RXCALEYEDIAGFSMIN_START); for( i = 0; i < AL_SERDES_RX_EYE_CAL_TRIES; ++i ) { /* Check if RxEQ Cal is done */ al_serdes_reg_read( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALEYEDIAGFSM_DONE_REG_NUM, &status ); if (status & SERDES_IREG_FLD_RXCALEYEDIAGFSM_DONE) break; al_msleep(AL_SERDES_RX_EYE_CAL_MDELAY); } if (status & SERDES_IREG_FLD_RXCALEYEDIAGFSM_ERR) { al_err("%s: eye measure error!\n", __func__); return -1; } if (!(status & SERDES_IREG_FLD_RXCALEYEDIAGFSM_DONE)) { al_err("%s: eye measure timeout!\n", __func__); return -1; } /* Read Eye Opening Metrics, Bits: * SERDES_IREG_FLD_RXCALEYEDIAGFSM_EYESUM_LSB, * SERDES_IREG_FLD_RXCALEYEDIAGFSM_EYESUM_LSB */ al_serdes_reg_read( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALEYEDIAGFSM_EYESUM_MSB_REG_NUM, ®_value ); *height = reg_value << 6; al_serdes_reg_read( obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALEYEDIAGFSM_EYESUM_LSB_REG_NUM, ®_value ); *height =+ reg_value & SERDES_IREG_FLD_RXCALEYEDIAGFSM_EYESUM_LSB_MAKE; /* * Clear Bit: * SERDES_IREG_FLD_RXCALEYEDIAGFSMIN_START, * to stop Eye measurement */ al_serdes_grp_reg_masked_write(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALEYEDIAGFSMIN_START_REG_NUM, SERDES_IREG_FLD_RXCALEYEDIAGFSMIN_START, 0); /* Restore Registers */ al_serdes_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALEYEDIAGFSM_X_Y_VALWEIGHT_REG_NUM, rxcaleyediagfsm_x_y_valweight_val); al_serdes_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALEYEDIAGFSM_XVALCOARSE_REG_NUM, rxcaleyediagfsm_xvalcoarse_val); al_serdes_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALEYEDIAGFSM_XVALFINE_REG_NUM, rxcaleyediagfsm_xvalfine_val); al_serdes_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALEYEDIAGFSM_YVALCOARSE_REG_NUM, rxcaleyediagfsm_yvalcoarse_val); al_serdes_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALEYEDIAGFSM_YVALFINE_REG_NUM, rxcaleyediagfsm_yvalfine_val); al_serdes_reg_write(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXLOCK2REF_LOCWREN_REG_NUM, rxlock2ref_locwren_val); al_serdes_reg_write(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCAL_LOCWREN_REG_NUM, rxcal_locwren_val); al_serdes_reg_write(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXCALROAMYADJUST_LOCWREN_REG_NUM, rxcalroamyadjust_locwren_val); al_serdes_reg_write(obj, (enum al_serdes_reg_page)lane, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXLOCK2REF_OVREN_REG_NUM, rxlock2ref_ovren_val); return 0; } static void al_serdes_sris_config( struct al_serdes_grp_obj *obj, void *sris_params) { struct al_serdes_sris_params *params = sris_params; al_serdes_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_PPMDRIFTCOUNT1_REG_NUM, (params->ppm_drift_count & AL_FIELD_MASK(7, 0)) >> 0); al_serdes_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_PPMDRIFTCOUNT2_REG_NUM, (params->ppm_drift_count & AL_FIELD_MASK(15, 8)) >> 8); al_serdes_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_PPMDRIFTMAX1_REG_NUM, (params->ppm_drift_max & AL_FIELD_MASK(7, 0)) >> 0); al_serdes_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_PPMDRIFTMAX2_REG_NUM, (params->ppm_drift_max & AL_FIELD_MASK(15, 8)) >> 8); al_serdes_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_SYNTHPPMDRIFTMAX1_REG_NUM, (params->synth_ppm_drift_max & AL_FIELD_MASK(7, 0)) >> 0); al_serdes_reg_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_SYNTHPPMDRIFTMAX2_REG_NUM, (params->synth_ppm_drift_max & AL_FIELD_MASK(15, 8)) >> 8); al_serdes_grp_reg_masked_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PCS, SERDES_IREG_FLD_PCS_EBUF_FULL_D2R1_REG_NUM, SERDES_IREG_FLD_PCS_EBUF_FULL_D2R1_REG_MASK, (params->full_d2r1) << SERDES_IREG_FLD_PCS_EBUF_FULL_D2R1_REG_SHIFT); al_serdes_grp_reg_masked_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PCS, SERDES_IREG_FLD_PCS_EBUF_FULL_PCIE_G3_REG_NUM, SERDES_IREG_FLD_PCS_EBUF_FULL_PCIE_G3_REG_MASK, (params->full_pcie_g3) << SERDES_IREG_FLD_PCS_EBUF_FULL_PCIE_G3_REG_SHIFT); al_serdes_grp_reg_masked_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PCS, SERDES_IREG_FLD_PCS_EBUF_RD_THRESHOLD_D2R1_REG_NUM, SERDES_IREG_FLD_PCS_EBUF_RD_THRESHOLD_D2R1_REG_MASK, (params->rd_threshold_d2r1) << SERDES_IREG_FLD_PCS_EBUF_RD_THRESHOLD_D2R1_REG_SHIFT); al_serdes_grp_reg_masked_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PCS, SERDES_IREG_FLD_PCS_EBUF_RD_THRESHOLD_PCIE_G3_REG_NUM, SERDES_IREG_FLD_PCS_EBUF_RD_THRESHOLD_PCIE_G3_REG_MASK, (params->rd_threshold_pcie_g3) << SERDES_IREG_FLD_PCS_EBUF_RD_THRESHOLD_PCIE_G3_REG_SHIFT); } /******************************************************************************/ /******************************************************************************/ static void al_serdes_dcgain_set( struct al_serdes_grp_obj *obj, uint8_t dcgain) { al_serdes_grp_reg_masked_write(obj, AL_SRDS_REG_PAGE_4_COMMON, AL_SRDS_REG_TYPE_PMA, SERDES_IREG_FLD_RXEQ_DCGAIN_LUP0_REG_NUM, SERDES_IREG_FLD_RXEQ_DCGAIN_LUP0_MASK, (dcgain << SERDES_IREG_FLD_RXEQ_DCGAIN_LUP0_SHIFT)); } /******************************************************************************/ /******************************************************************************/ int al_serdes_hssp_handle_init( void __iomem *serdes_regs_base, struct al_serdes_grp_obj *obj) { al_dbg( "%s(%p, %p)\n", __func__, serdes_regs_base, obj); al_memset(obj, 0, sizeof(struct al_serdes_grp_obj)); obj->regs_base = (struct al_serdes_regs *)serdes_regs_base; obj->type_get = al_serdes_hssp_type_get; obj->reg_read = al_serdes_reg_read; obj->reg_write = al_serdes_reg_write; obj->bist_overrides_enable = AL_SRDS_ADV_SRVC(al_serdes_bist_overrides_enable); obj->bist_overrides_disable = AL_SRDS_ADV_SRVC(al_serdes_bist_overrides_disable); obj->rx_rate_change = AL_SRDS_ADV_SRVC(al_serdes_rx_rate_change); obj->rx_rate_change_sw_flow_en = AL_SRDS_ADV_SRVC(al_serdes_lane_rx_rate_change_sw_flow_en); obj->rx_rate_change_sw_flow_dis = AL_SRDS_ADV_SRVC(al_serdes_lane_rx_rate_change_sw_flow_dis); obj->pcie_rate_override_is_enabled = AL_SRDS_ADV_SRVC(al_serdes_lane_pcie_rate_override_is_enabled); obj->pcie_rate_override_enable_set = AL_SRDS_ADV_SRVC(al_serdes_lane_pcie_rate_override_enable_set); obj->pcie_rate_get = AL_SRDS_ADV_SRVC(al_serdes_lane_pcie_rate_get); obj->pcie_rate_set = AL_SRDS_ADV_SRVC(al_serdes_lane_pcie_rate_set); obj->group_pm_set = AL_SRDS_ADV_SRVC(al_serdes_group_pm_set); obj->lane_pm_set = AL_SRDS_ADV_SRVC(al_serdes_lane_pm_set); obj->pma_hard_reset_group = AL_SRDS_ADV_SRVC(al_serdes_pma_hard_reset_group); obj->pma_hard_reset_lane = AL_SRDS_ADV_SRVC(al_serdes_pma_hard_reset_lane); obj->loopback_control = AL_SRDS_ADV_SRVC(al_serdes_loopback_control); obj->bist_pattern_select = AL_SRDS_ADV_SRVC(al_serdes_bist_pattern_select); obj->bist_tx_enable = AL_SRDS_ADV_SRVC(al_serdes_bist_tx_enable); obj->bist_tx_err_inject = AL_SRDS_ADV_SRVC(al_serdes_bist_tx_err_inject); obj->bist_rx_enable = AL_SRDS_ADV_SRVC(al_serdes_bist_rx_enable); obj->bist_rx_status = AL_SRDS_ADV_SRVC(al_serdes_bist_rx_status); obj->tx_deemph_preset = AL_SRDS_ADV_SRVC(al_serdes_tx_deemph_preset); obj->tx_deemph_inc = AL_SRDS_ADV_SRVC(al_serdes_tx_deemph_inc); obj->tx_deemph_dec = AL_SRDS_ADV_SRVC(al_serdes_tx_deemph_dec); obj->eye_measure_run = AL_SRDS_ADV_SRVC(al_serdes_eye_measure_run); obj->eye_diag_sample = AL_SRDS_ADV_SRVC(al_serdes_eye_diag_sample); obj->signal_is_detected = AL_SRDS_ADV_SRVC(al_serdes_signal_is_detected); obj->tx_advanced_params_set = AL_SRDS_ADV_SRVC(al_serdes_tx_advanced_params_set); obj->tx_advanced_params_get = AL_SRDS_ADV_SRVC(al_serdes_tx_advanced_params_get); obj->rx_advanced_params_set = AL_SRDS_ADV_SRVC(al_serdes_rx_advanced_params_set); obj->rx_advanced_params_get = AL_SRDS_ADV_SRVC(al_serdes_rx_advanced_params_get); obj->mode_set_sgmii = AL_SRDS_ADV_SRVC(al_serdes_mode_set_sgmii); obj->mode_set_kr = AL_SRDS_ADV_SRVC(al_serdes_mode_set_kr); obj->rx_equalization = AL_SRDS_ADV_SRVC(al_serdes_rx_equalization); obj->calc_eye_size = AL_SRDS_ADV_SRVC(al_serdes_calc_eye_size); obj->sris_config = AL_SRDS_ADV_SRVC(al_serdes_sris_config); obj->dcgain_set = AL_SRDS_ADV_SRVC(al_serdes_dcgain_set); return 0; }