From owner-svn-src-vendor@freebsd.org Tue Sep 20 08:56:51 2016 Return-Path: Delivered-To: svn-src-vendor@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id C25A7BE0CBB; Tue, 20 Sep 2016 08:56:51 +0000 (UTC) (envelope-from wma@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 6147FB36; Tue, 20 Sep 2016 08:56:51 +0000 (UTC) (envelope-from wma@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id u8K8uoU2015216; Tue, 20 Sep 2016 08:56:50 GMT (envelope-from wma@FreeBSD.org) Received: (from wma@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id u8K8uosX015215; Tue, 20 Sep 2016 08:56:50 GMT (envelope-from wma@FreeBSD.org) Message-Id: <201609200856.u8K8uosX015215@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: wma set sender to wma@FreeBSD.org using -f From: Wojciech Macek Date: Tue, 20 Sep 2016 08:56:50 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-vendor@freebsd.org Subject: svn commit: r306017 - vendor-sys/alpine-hal/2.7a X-SVN-Group: vendor-sys MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-vendor@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: SVN commit messages for the vendor work area tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 20 Sep 2016 08:56:51 -0000 Author: wma Date: Tue Sep 20 08:56:50 2016 New Revision: 306017 URL: https://svnweb.freebsd.org/changeset/base/306017 Log: Update Annapurna Alpine HAL alpine-hal SerDes file was omitted in the previous commit. Files added here. Added: vendor-sys/alpine-hal/2.7a/al_hal_serdes_hssp.c - copied unchanged from r306016, vendor-sys/alpine-hal/2.7a/al_hal_serdes.c Deleted: vendor-sys/alpine-hal/2.7a/al_hal_serdes.c Copied: vendor-sys/alpine-hal/2.7a/al_hal_serdes_hssp.c (from r306016, vendor-sys/alpine-hal/2.7a/al_hal_serdes.c) ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ vendor-sys/alpine-hal/2.7a/al_hal_serdes_hssp.c Tue Sep 20 08:56:50 2016 (r306017, copy of r306016, vendor-sys/alpine-hal/2.7a/al_hal_serdes.c) @@ -0,0 +1,3164 @@ +/******************************************************************************* +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) { *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***