144b781cfSAndrew Turner /* 244b781cfSAndrew Turner * AMD 10Gb Ethernet driver 344b781cfSAndrew Turner * 47113afc8SEmmanuel Vadot * Copyright (c) 2014-2016,2020 Advanced Micro Devices, Inc. 57113afc8SEmmanuel Vadot * 644b781cfSAndrew Turner * This file is available to you under your choice of the following two 744b781cfSAndrew Turner * licenses: 844b781cfSAndrew Turner * 944b781cfSAndrew Turner * License 1: GPLv2 1044b781cfSAndrew Turner * 1144b781cfSAndrew Turner * This file is free software; you may copy, redistribute and/or modify 1244b781cfSAndrew Turner * it under the terms of the GNU General Public License as published by 1344b781cfSAndrew Turner * the Free Software Foundation, either version 2 of the License, or (at 1444b781cfSAndrew Turner * your option) any later version. 1544b781cfSAndrew Turner * 1644b781cfSAndrew Turner * This file is distributed in the hope that it will be useful, but 1744b781cfSAndrew Turner * WITHOUT ANY WARRANTY; without even the implied warranty of 1844b781cfSAndrew Turner * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1944b781cfSAndrew Turner * General Public License for more details. 2044b781cfSAndrew Turner * 2144b781cfSAndrew Turner * You should have received a copy of the GNU General Public License 2244b781cfSAndrew Turner * along with this program. If not, see <http://www.gnu.org/licenses/>. 2344b781cfSAndrew Turner * 2444b781cfSAndrew Turner * This file incorporates work covered by the following copyright and 2544b781cfSAndrew Turner * permission notice: 2644b781cfSAndrew Turner * The Synopsys DWC ETHER XGMAC Software Driver and documentation 2744b781cfSAndrew Turner * (hereinafter "Software") is an unsupported proprietary work of Synopsys, 2844b781cfSAndrew Turner * Inc. unless otherwise expressly agreed to in writing between Synopsys 2944b781cfSAndrew Turner * and you. 3044b781cfSAndrew Turner * 3144b781cfSAndrew Turner * The Software IS NOT an item of Licensed Software or Licensed Product 3244b781cfSAndrew Turner * under any End User Software License Agreement or Agreement for Licensed 3344b781cfSAndrew Turner * Product with Synopsys or any supplement thereto. Permission is hereby 3444b781cfSAndrew Turner * granted, free of charge, to any person obtaining a copy of this software 3544b781cfSAndrew Turner * annotated with this license and the Software, to deal in the Software 3644b781cfSAndrew Turner * without restriction, including without limitation the rights to use, 3744b781cfSAndrew Turner * copy, modify, merge, publish, distribute, sublicense, and/or sell copies 3844b781cfSAndrew Turner * of the Software, and to permit persons to whom the Software is furnished 3944b781cfSAndrew Turner * to do so, subject to the following conditions: 4044b781cfSAndrew Turner * 4144b781cfSAndrew Turner * The above copyright notice and this permission notice shall be included 4244b781cfSAndrew Turner * in all copies or substantial portions of the Software. 4344b781cfSAndrew Turner * 4444b781cfSAndrew Turner * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" 4544b781cfSAndrew Turner * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 4644b781cfSAndrew Turner * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 4744b781cfSAndrew Turner * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 4844b781cfSAndrew Turner * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 4944b781cfSAndrew Turner * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 5044b781cfSAndrew Turner * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 5144b781cfSAndrew Turner * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 5244b781cfSAndrew Turner * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 5344b781cfSAndrew Turner * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 5444b781cfSAndrew Turner * THE POSSIBILITY OF SUCH DAMAGE. 5544b781cfSAndrew Turner * 5644b781cfSAndrew Turner * 5744b781cfSAndrew Turner * License 2: Modified BSD 5844b781cfSAndrew Turner * 5944b781cfSAndrew Turner * Redistribution and use in source and binary forms, with or without 6044b781cfSAndrew Turner * modification, are permitted provided that the following conditions are met: 6144b781cfSAndrew Turner * * Redistributions of source code must retain the above copyright 6244b781cfSAndrew Turner * notice, this list of conditions and the following disclaimer. 6344b781cfSAndrew Turner * * Redistributions in binary form must reproduce the above copyright 6444b781cfSAndrew Turner * notice, this list of conditions and the following disclaimer in the 6544b781cfSAndrew Turner * documentation and/or other materials provided with the distribution. 6644b781cfSAndrew Turner * * Neither the name of Advanced Micro Devices, Inc. nor the 6744b781cfSAndrew Turner * names of its contributors may be used to endorse or promote products 6844b781cfSAndrew Turner * derived from this software without specific prior written permission. 6944b781cfSAndrew Turner * 7044b781cfSAndrew Turner * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 7144b781cfSAndrew Turner * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 7244b781cfSAndrew Turner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 7344b781cfSAndrew Turner * ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY 7444b781cfSAndrew Turner * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 7544b781cfSAndrew Turner * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 7644b781cfSAndrew Turner * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 7744b781cfSAndrew Turner * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 7844b781cfSAndrew Turner * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 7944b781cfSAndrew Turner * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 8044b781cfSAndrew Turner * 8144b781cfSAndrew Turner * This file incorporates work covered by the following copyright and 8244b781cfSAndrew Turner * permission notice: 8344b781cfSAndrew Turner * The Synopsys DWC ETHER XGMAC Software Driver and documentation 8444b781cfSAndrew Turner * (hereinafter "Software") is an unsupported proprietary work of Synopsys, 8544b781cfSAndrew Turner * Inc. unless otherwise expressly agreed to in writing between Synopsys 8644b781cfSAndrew Turner * and you. 8744b781cfSAndrew Turner * 8844b781cfSAndrew Turner * The Software IS NOT an item of Licensed Software or Licensed Product 8944b781cfSAndrew Turner * under any End User Software License Agreement or Agreement for Licensed 9044b781cfSAndrew Turner * Product with Synopsys or any supplement thereto. Permission is hereby 9144b781cfSAndrew Turner * granted, free of charge, to any person obtaining a copy of this software 9244b781cfSAndrew Turner * annotated with this license and the Software, to deal in the Software 9344b781cfSAndrew Turner * without restriction, including without limitation the rights to use, 9444b781cfSAndrew Turner * copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9544b781cfSAndrew Turner * of the Software, and to permit persons to whom the Software is furnished 9644b781cfSAndrew Turner * to do so, subject to the following conditions: 9744b781cfSAndrew Turner * 9844b781cfSAndrew Turner * The above copyright notice and this permission notice shall be included 9944b781cfSAndrew Turner * in all copies or substantial portions of the Software. 10044b781cfSAndrew Turner * 10144b781cfSAndrew Turner * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" 10244b781cfSAndrew Turner * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 10344b781cfSAndrew Turner * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 10444b781cfSAndrew Turner * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 10544b781cfSAndrew Turner * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 10644b781cfSAndrew Turner * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 10744b781cfSAndrew Turner * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 10844b781cfSAndrew Turner * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 10944b781cfSAndrew Turner * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 11044b781cfSAndrew Turner * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 11144b781cfSAndrew Turner * THE POSSIBILITY OF SUCH DAMAGE. 11244b781cfSAndrew Turner */ 11344b781cfSAndrew Turner 1149c6d6488SAndrew Turner #include <sys/cdefs.h> 1159c6d6488SAndrew Turner __FBSDID("$FreeBSD$"); 1169c6d6488SAndrew Turner 11744b781cfSAndrew Turner #include "xgbe.h" 11844b781cfSAndrew Turner #include "xgbe-common.h" 11944b781cfSAndrew Turner 1209c6d6488SAndrew Turner static void xgbe_an_state_machine(struct xgbe_prv_data *pdata); 1219c6d6488SAndrew Turner 1227113afc8SEmmanuel Vadot static void 1237113afc8SEmmanuel Vadot xgbe_an37_clear_interrupts(struct xgbe_prv_data *pdata) 12444b781cfSAndrew Turner { 1257113afc8SEmmanuel Vadot int reg; 12644b781cfSAndrew Turner 1277113afc8SEmmanuel Vadot reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT); 1287113afc8SEmmanuel Vadot reg &= ~XGBE_AN_CL37_INT_MASK; 1297113afc8SEmmanuel Vadot XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT, reg); 13044b781cfSAndrew Turner } 13144b781cfSAndrew Turner 1327113afc8SEmmanuel Vadot static void 1337113afc8SEmmanuel Vadot xgbe_an37_disable_interrupts(struct xgbe_prv_data *pdata) 13444b781cfSAndrew Turner { 1357113afc8SEmmanuel Vadot int reg; 13644b781cfSAndrew Turner 1377113afc8SEmmanuel Vadot reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL); 1387113afc8SEmmanuel Vadot reg &= ~XGBE_AN_CL37_INT_MASK; 1397113afc8SEmmanuel Vadot XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL, reg); 14044b781cfSAndrew Turner 1417113afc8SEmmanuel Vadot reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL); 1427113afc8SEmmanuel Vadot reg &= ~XGBE_PCS_CL37_BP; 1437113afc8SEmmanuel Vadot XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL, reg); 14444b781cfSAndrew Turner } 14544b781cfSAndrew Turner 1467113afc8SEmmanuel Vadot static void 1477113afc8SEmmanuel Vadot xgbe_an37_enable_interrupts(struct xgbe_prv_data *pdata) 14844b781cfSAndrew Turner { 1497113afc8SEmmanuel Vadot int reg; 15044b781cfSAndrew Turner 1517113afc8SEmmanuel Vadot reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL); 1527113afc8SEmmanuel Vadot reg |= XGBE_PCS_CL37_BP; 1537113afc8SEmmanuel Vadot XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL, reg); 15444b781cfSAndrew Turner 1557113afc8SEmmanuel Vadot reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL); 1567113afc8SEmmanuel Vadot reg |= XGBE_AN_CL37_INT_MASK; 1577113afc8SEmmanuel Vadot XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL, reg); 15844b781cfSAndrew Turner } 15944b781cfSAndrew Turner 1607113afc8SEmmanuel Vadot static void 1617113afc8SEmmanuel Vadot xgbe_an73_clear_interrupts(struct xgbe_prv_data *pdata) 16244b781cfSAndrew Turner { 1637113afc8SEmmanuel Vadot XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0); 16444b781cfSAndrew Turner } 16544b781cfSAndrew Turner 1667113afc8SEmmanuel Vadot static void 1677113afc8SEmmanuel Vadot xgbe_an73_disable_interrupts(struct xgbe_prv_data *pdata) 16844b781cfSAndrew Turner { 1697113afc8SEmmanuel Vadot XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, 0); 17044b781cfSAndrew Turner } 17144b781cfSAndrew Turner 1727113afc8SEmmanuel Vadot static void 1737113afc8SEmmanuel Vadot xgbe_an73_enable_interrupts(struct xgbe_prv_data *pdata) 1747113afc8SEmmanuel Vadot { 1757113afc8SEmmanuel Vadot XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, XGBE_AN_CL73_INT_MASK); 17644b781cfSAndrew Turner } 17744b781cfSAndrew Turner 1787113afc8SEmmanuel Vadot static void 1797113afc8SEmmanuel Vadot xgbe_an_enable_interrupts(struct xgbe_prv_data *pdata) 18044b781cfSAndrew Turner { 1817113afc8SEmmanuel Vadot switch (pdata->an_mode) { 1827113afc8SEmmanuel Vadot case XGBE_AN_MODE_CL73: 1837113afc8SEmmanuel Vadot case XGBE_AN_MODE_CL73_REDRV: 1847113afc8SEmmanuel Vadot xgbe_an73_enable_interrupts(pdata); 1857113afc8SEmmanuel Vadot break; 1867113afc8SEmmanuel Vadot case XGBE_AN_MODE_CL37: 1877113afc8SEmmanuel Vadot case XGBE_AN_MODE_CL37_SGMII: 1887113afc8SEmmanuel Vadot xgbe_an37_enable_interrupts(pdata); 1897113afc8SEmmanuel Vadot break; 1907113afc8SEmmanuel Vadot default: 1917113afc8SEmmanuel Vadot break; 1927113afc8SEmmanuel Vadot } 1937113afc8SEmmanuel Vadot } 19444b781cfSAndrew Turner 1957113afc8SEmmanuel Vadot static void 1967113afc8SEmmanuel Vadot xgbe_an_clear_interrupts_all(struct xgbe_prv_data *pdata) 1977113afc8SEmmanuel Vadot { 1987113afc8SEmmanuel Vadot xgbe_an73_clear_interrupts(pdata); 1997113afc8SEmmanuel Vadot xgbe_an37_clear_interrupts(pdata); 2007113afc8SEmmanuel Vadot } 2017113afc8SEmmanuel Vadot 2027113afc8SEmmanuel Vadot static void 2037113afc8SEmmanuel Vadot xgbe_kr_mode(struct xgbe_prv_data *pdata) 2047113afc8SEmmanuel Vadot { 2057113afc8SEmmanuel Vadot /* Set MAC to 10G speed */ 2067113afc8SEmmanuel Vadot pdata->hw_if.set_speed(pdata, SPEED_10000); 2077113afc8SEmmanuel Vadot 2087113afc8SEmmanuel Vadot /* Call PHY implementation support to complete rate change */ 2097113afc8SEmmanuel Vadot pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_KR); 2107113afc8SEmmanuel Vadot } 2117113afc8SEmmanuel Vadot 2127113afc8SEmmanuel Vadot static void 2137113afc8SEmmanuel Vadot xgbe_kx_2500_mode(struct xgbe_prv_data *pdata) 2147113afc8SEmmanuel Vadot { 2157113afc8SEmmanuel Vadot /* Set MAC to 2.5G speed */ 2167113afc8SEmmanuel Vadot pdata->hw_if.set_speed(pdata, SPEED_2500); 2177113afc8SEmmanuel Vadot 2187113afc8SEmmanuel Vadot /* Call PHY implementation support to complete rate change */ 2197113afc8SEmmanuel Vadot pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_KX_2500); 2207113afc8SEmmanuel Vadot } 2217113afc8SEmmanuel Vadot 2227113afc8SEmmanuel Vadot static void 2237113afc8SEmmanuel Vadot xgbe_kx_1000_mode(struct xgbe_prv_data *pdata) 2247113afc8SEmmanuel Vadot { 2257113afc8SEmmanuel Vadot /* Set MAC to 1G speed */ 2267113afc8SEmmanuel Vadot pdata->hw_if.set_speed(pdata, SPEED_1000); 2277113afc8SEmmanuel Vadot 2287113afc8SEmmanuel Vadot /* Call PHY implementation support to complete rate change */ 2297113afc8SEmmanuel Vadot pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_KX_1000); 2307113afc8SEmmanuel Vadot } 2317113afc8SEmmanuel Vadot 2327113afc8SEmmanuel Vadot static void 2337113afc8SEmmanuel Vadot xgbe_sfi_mode(struct xgbe_prv_data *pdata) 2347113afc8SEmmanuel Vadot { 2357113afc8SEmmanuel Vadot /* If a KR re-driver is present, change to KR mode instead */ 2367113afc8SEmmanuel Vadot if (pdata->kr_redrv) 2377113afc8SEmmanuel Vadot return (xgbe_kr_mode(pdata)); 23844b781cfSAndrew Turner 23944b781cfSAndrew Turner /* Set MAC to 10G speed */ 2407113afc8SEmmanuel Vadot pdata->hw_if.set_speed(pdata, SPEED_10000); 24144b781cfSAndrew Turner 2427113afc8SEmmanuel Vadot /* Call PHY implementation support to complete rate change */ 2437113afc8SEmmanuel Vadot pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_SFI); 24444b781cfSAndrew Turner } 24544b781cfSAndrew Turner 2467113afc8SEmmanuel Vadot static void 2477113afc8SEmmanuel Vadot xgbe_x_mode(struct xgbe_prv_data *pdata) 24844b781cfSAndrew Turner { 24944b781cfSAndrew Turner /* Set MAC to 1G speed */ 2507113afc8SEmmanuel Vadot pdata->hw_if.set_speed(pdata, SPEED_1000); 25144b781cfSAndrew Turner 2527113afc8SEmmanuel Vadot /* Call PHY implementation support to complete rate change */ 2537113afc8SEmmanuel Vadot pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_X); 25444b781cfSAndrew Turner } 25544b781cfSAndrew Turner 2567113afc8SEmmanuel Vadot static void 2577113afc8SEmmanuel Vadot xgbe_sgmii_1000_mode(struct xgbe_prv_data *pdata) 2587113afc8SEmmanuel Vadot { 2597113afc8SEmmanuel Vadot /* Set MAC to 1G speed */ 2607113afc8SEmmanuel Vadot pdata->hw_if.set_speed(pdata, SPEED_1000); 2617113afc8SEmmanuel Vadot 2627113afc8SEmmanuel Vadot /* Call PHY implementation support to complete rate change */ 2637113afc8SEmmanuel Vadot pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_SGMII_1000); 2647113afc8SEmmanuel Vadot } 2657113afc8SEmmanuel Vadot 2667113afc8SEmmanuel Vadot static void 2677113afc8SEmmanuel Vadot xgbe_sgmii_100_mode(struct xgbe_prv_data *pdata) 2687113afc8SEmmanuel Vadot { 2697113afc8SEmmanuel Vadot /* Set MAC to 1G speed */ 2707113afc8SEmmanuel Vadot pdata->hw_if.set_speed(pdata, SPEED_1000); 2717113afc8SEmmanuel Vadot 2727113afc8SEmmanuel Vadot /* Call PHY implementation support to complete rate change */ 2737113afc8SEmmanuel Vadot pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_SGMII_100); 2747113afc8SEmmanuel Vadot } 2757113afc8SEmmanuel Vadot 2767113afc8SEmmanuel Vadot static enum xgbe_mode 2777113afc8SEmmanuel Vadot xgbe_cur_mode(struct xgbe_prv_data *pdata) 2787113afc8SEmmanuel Vadot { 2797113afc8SEmmanuel Vadot return (pdata->phy_if.phy_impl.cur_mode(pdata)); 2807113afc8SEmmanuel Vadot } 2817113afc8SEmmanuel Vadot 2827113afc8SEmmanuel Vadot static bool 2837113afc8SEmmanuel Vadot xgbe_in_kr_mode(struct xgbe_prv_data *pdata) 2847113afc8SEmmanuel Vadot { 2857113afc8SEmmanuel Vadot return (xgbe_cur_mode(pdata) == XGBE_MODE_KR); 2867113afc8SEmmanuel Vadot } 2877113afc8SEmmanuel Vadot 2887113afc8SEmmanuel Vadot static void 2897113afc8SEmmanuel Vadot xgbe_change_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode) 2907113afc8SEmmanuel Vadot { 2917113afc8SEmmanuel Vadot switch (mode) { 2927113afc8SEmmanuel Vadot case XGBE_MODE_KX_1000: 2937113afc8SEmmanuel Vadot xgbe_kx_1000_mode(pdata); 2947113afc8SEmmanuel Vadot break; 2957113afc8SEmmanuel Vadot case XGBE_MODE_KX_2500: 2967113afc8SEmmanuel Vadot xgbe_kx_2500_mode(pdata); 2977113afc8SEmmanuel Vadot break; 2987113afc8SEmmanuel Vadot case XGBE_MODE_KR: 2997113afc8SEmmanuel Vadot xgbe_kr_mode(pdata); 3007113afc8SEmmanuel Vadot break; 3017113afc8SEmmanuel Vadot case XGBE_MODE_SGMII_100: 3027113afc8SEmmanuel Vadot xgbe_sgmii_100_mode(pdata); 3037113afc8SEmmanuel Vadot break; 3047113afc8SEmmanuel Vadot case XGBE_MODE_SGMII_1000: 3057113afc8SEmmanuel Vadot xgbe_sgmii_1000_mode(pdata); 3067113afc8SEmmanuel Vadot break; 3077113afc8SEmmanuel Vadot case XGBE_MODE_X: 3087113afc8SEmmanuel Vadot xgbe_x_mode(pdata); 3097113afc8SEmmanuel Vadot break; 3107113afc8SEmmanuel Vadot case XGBE_MODE_SFI: 3117113afc8SEmmanuel Vadot xgbe_sfi_mode(pdata); 3127113afc8SEmmanuel Vadot break; 3137113afc8SEmmanuel Vadot case XGBE_MODE_UNKNOWN: 3147113afc8SEmmanuel Vadot break; 3157113afc8SEmmanuel Vadot default: 3167113afc8SEmmanuel Vadot axgbe_error("invalid operation mode requested (%u)\n", mode); 3177113afc8SEmmanuel Vadot } 3187113afc8SEmmanuel Vadot } 3197113afc8SEmmanuel Vadot 3207113afc8SEmmanuel Vadot static void 3217113afc8SEmmanuel Vadot xgbe_switch_mode(struct xgbe_prv_data *pdata) 3227113afc8SEmmanuel Vadot { 3237113afc8SEmmanuel Vadot xgbe_change_mode(pdata, pdata->phy_if.phy_impl.switch_mode(pdata)); 3247113afc8SEmmanuel Vadot } 3257113afc8SEmmanuel Vadot 3267113afc8SEmmanuel Vadot static bool 3277113afc8SEmmanuel Vadot xgbe_set_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode) 3287113afc8SEmmanuel Vadot { 3297113afc8SEmmanuel Vadot if (mode == xgbe_cur_mode(pdata)) 3307113afc8SEmmanuel Vadot return (false); 3317113afc8SEmmanuel Vadot 3327113afc8SEmmanuel Vadot xgbe_change_mode(pdata, mode); 3337113afc8SEmmanuel Vadot 3347113afc8SEmmanuel Vadot return (true); 3357113afc8SEmmanuel Vadot } 3367113afc8SEmmanuel Vadot 3377113afc8SEmmanuel Vadot static bool 3387113afc8SEmmanuel Vadot xgbe_use_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode) 3397113afc8SEmmanuel Vadot { 3407113afc8SEmmanuel Vadot return (pdata->phy_if.phy_impl.use_mode(pdata, mode)); 3417113afc8SEmmanuel Vadot } 3427113afc8SEmmanuel Vadot 3437113afc8SEmmanuel Vadot static void 3447113afc8SEmmanuel Vadot xgbe_an37_set(struct xgbe_prv_data *pdata, bool enable, bool restart) 34544b781cfSAndrew Turner { 34644b781cfSAndrew Turner unsigned int reg; 34744b781cfSAndrew Turner 3487113afc8SEmmanuel Vadot reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_CTRL1); 3497113afc8SEmmanuel Vadot reg &= ~MDIO_VEND2_CTRL1_AN_ENABLE; 3507113afc8SEmmanuel Vadot 3517113afc8SEmmanuel Vadot if (enable) 3527113afc8SEmmanuel Vadot reg |= MDIO_VEND2_CTRL1_AN_ENABLE; 3537113afc8SEmmanuel Vadot 3547113afc8SEmmanuel Vadot if (restart) 3557113afc8SEmmanuel Vadot reg |= MDIO_VEND2_CTRL1_AN_RESTART; 3567113afc8SEmmanuel Vadot 3577113afc8SEmmanuel Vadot XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_CTRL1, reg); 35844b781cfSAndrew Turner } 35944b781cfSAndrew Turner 3607113afc8SEmmanuel Vadot static void 3617113afc8SEmmanuel Vadot xgbe_an37_restart(struct xgbe_prv_data *pdata) 36244b781cfSAndrew Turner { 3637113afc8SEmmanuel Vadot xgbe_an37_enable_interrupts(pdata); 3647113afc8SEmmanuel Vadot xgbe_an37_set(pdata, true, true); 36544b781cfSAndrew Turner } 36644b781cfSAndrew Turner 3677113afc8SEmmanuel Vadot static void 3687113afc8SEmmanuel Vadot xgbe_an37_disable(struct xgbe_prv_data *pdata) 36944b781cfSAndrew Turner { 3707113afc8SEmmanuel Vadot xgbe_an37_set(pdata, false, false); 3717113afc8SEmmanuel Vadot xgbe_an37_disable_interrupts(pdata); 37244b781cfSAndrew Turner } 37344b781cfSAndrew Turner 3747113afc8SEmmanuel Vadot static void 3757113afc8SEmmanuel Vadot xgbe_an73_set(struct xgbe_prv_data *pdata, bool enable, bool restart) 37644b781cfSAndrew Turner { 37744b781cfSAndrew Turner unsigned int reg; 37844b781cfSAndrew Turner 3797113afc8SEmmanuel Vadot /* Disable KR training for now */ 3807113afc8SEmmanuel Vadot reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL); 3817113afc8SEmmanuel Vadot reg &= ~XGBE_KR_TRAINING_ENABLE; 3827113afc8SEmmanuel Vadot XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, reg); 3837113afc8SEmmanuel Vadot 3847113afc8SEmmanuel Vadot /* Update AN settings */ 38544b781cfSAndrew Turner reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_CTRL1); 38644b781cfSAndrew Turner reg &= ~MDIO_AN_CTRL1_ENABLE; 38744b781cfSAndrew Turner 38844b781cfSAndrew Turner if (enable) 38944b781cfSAndrew Turner reg |= MDIO_AN_CTRL1_ENABLE; 39044b781cfSAndrew Turner 39144b781cfSAndrew Turner if (restart) 39244b781cfSAndrew Turner reg |= MDIO_AN_CTRL1_RESTART; 39344b781cfSAndrew Turner 39444b781cfSAndrew Turner XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_CTRL1, reg); 39544b781cfSAndrew Turner } 39644b781cfSAndrew Turner 3977113afc8SEmmanuel Vadot static void 3987113afc8SEmmanuel Vadot xgbe_an73_restart(struct xgbe_prv_data *pdata) 39944b781cfSAndrew Turner { 4007113afc8SEmmanuel Vadot xgbe_an73_enable_interrupts(pdata); 4017113afc8SEmmanuel Vadot xgbe_an73_set(pdata, true, true); 40244b781cfSAndrew Turner } 40344b781cfSAndrew Turner 4047113afc8SEmmanuel Vadot static void 4057113afc8SEmmanuel Vadot xgbe_an73_disable(struct xgbe_prv_data *pdata) 40644b781cfSAndrew Turner { 4077113afc8SEmmanuel Vadot xgbe_an73_set(pdata, false, false); 4087113afc8SEmmanuel Vadot xgbe_an73_disable_interrupts(pdata); 4097113afc8SEmmanuel Vadot 4107113afc8SEmmanuel Vadot pdata->an_start = 0; 41144b781cfSAndrew Turner } 41244b781cfSAndrew Turner 4137113afc8SEmmanuel Vadot static void 4147113afc8SEmmanuel Vadot xgbe_an_restart(struct xgbe_prv_data *pdata) 4157113afc8SEmmanuel Vadot { 4167113afc8SEmmanuel Vadot if (pdata->phy_if.phy_impl.an_pre) 4177113afc8SEmmanuel Vadot pdata->phy_if.phy_impl.an_pre(pdata); 4187113afc8SEmmanuel Vadot 4197113afc8SEmmanuel Vadot switch (pdata->an_mode) { 4207113afc8SEmmanuel Vadot case XGBE_AN_MODE_CL73: 4217113afc8SEmmanuel Vadot case XGBE_AN_MODE_CL73_REDRV: 4227113afc8SEmmanuel Vadot xgbe_an73_restart(pdata); 4237113afc8SEmmanuel Vadot break; 4247113afc8SEmmanuel Vadot case XGBE_AN_MODE_CL37: 4257113afc8SEmmanuel Vadot case XGBE_AN_MODE_CL37_SGMII: 4267113afc8SEmmanuel Vadot xgbe_an37_restart(pdata); 4277113afc8SEmmanuel Vadot break; 4287113afc8SEmmanuel Vadot default: 4297113afc8SEmmanuel Vadot break; 4307113afc8SEmmanuel Vadot } 4317113afc8SEmmanuel Vadot } 4327113afc8SEmmanuel Vadot 4337113afc8SEmmanuel Vadot static void 4347113afc8SEmmanuel Vadot xgbe_an_disable(struct xgbe_prv_data *pdata) 4357113afc8SEmmanuel Vadot { 4367113afc8SEmmanuel Vadot if (pdata->phy_if.phy_impl.an_post) 4377113afc8SEmmanuel Vadot pdata->phy_if.phy_impl.an_post(pdata); 4387113afc8SEmmanuel Vadot 4397113afc8SEmmanuel Vadot switch (pdata->an_mode) { 4407113afc8SEmmanuel Vadot case XGBE_AN_MODE_CL73: 4417113afc8SEmmanuel Vadot case XGBE_AN_MODE_CL73_REDRV: 4427113afc8SEmmanuel Vadot xgbe_an73_disable(pdata); 4437113afc8SEmmanuel Vadot break; 4447113afc8SEmmanuel Vadot case XGBE_AN_MODE_CL37: 4457113afc8SEmmanuel Vadot case XGBE_AN_MODE_CL37_SGMII: 4467113afc8SEmmanuel Vadot xgbe_an37_disable(pdata); 4477113afc8SEmmanuel Vadot break; 4487113afc8SEmmanuel Vadot default: 4497113afc8SEmmanuel Vadot break; 4507113afc8SEmmanuel Vadot } 4517113afc8SEmmanuel Vadot } 4527113afc8SEmmanuel Vadot 4537113afc8SEmmanuel Vadot static void 4547113afc8SEmmanuel Vadot xgbe_an_disable_all(struct xgbe_prv_data *pdata) 4557113afc8SEmmanuel Vadot { 4567113afc8SEmmanuel Vadot xgbe_an73_disable(pdata); 4577113afc8SEmmanuel Vadot xgbe_an37_disable(pdata); 4587113afc8SEmmanuel Vadot } 4597113afc8SEmmanuel Vadot 4607113afc8SEmmanuel Vadot static enum xgbe_an 4617113afc8SEmmanuel Vadot xgbe_an73_tx_training(struct xgbe_prv_data *pdata, enum xgbe_rx *state) 46244b781cfSAndrew Turner { 46344b781cfSAndrew Turner unsigned int ad_reg, lp_reg, reg; 46444b781cfSAndrew Turner 46544b781cfSAndrew Turner *state = XGBE_RX_COMPLETE; 46644b781cfSAndrew Turner 46744b781cfSAndrew Turner /* If we're not in KR mode then we're done */ 46844b781cfSAndrew Turner if (!xgbe_in_kr_mode(pdata)) 4697113afc8SEmmanuel Vadot return (XGBE_AN_PAGE_RECEIVED); 47044b781cfSAndrew Turner 47144b781cfSAndrew Turner /* Enable/Disable FEC */ 47244b781cfSAndrew Turner ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); 47344b781cfSAndrew Turner lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2); 47444b781cfSAndrew Turner 47544b781cfSAndrew Turner reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FECCTRL); 47644b781cfSAndrew Turner reg &= ~(MDIO_PMA_10GBR_FECABLE_ABLE | MDIO_PMA_10GBR_FECABLE_ERRABLE); 47744b781cfSAndrew Turner if ((ad_reg & 0xc000) && (lp_reg & 0xc000)) 47844b781cfSAndrew Turner reg |= pdata->fec_ability; 47944b781cfSAndrew Turner 48044b781cfSAndrew Turner XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FECCTRL, reg); 48144b781cfSAndrew Turner 48244b781cfSAndrew Turner /* Start KR training */ 4837113afc8SEmmanuel Vadot if (pdata->phy_if.phy_impl.kr_training_pre) 4847113afc8SEmmanuel Vadot pdata->phy_if.phy_impl.kr_training_pre(pdata); 4857113afc8SEmmanuel Vadot 4867113afc8SEmmanuel Vadot /* Start KR training */ 48744b781cfSAndrew Turner reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL); 4887113afc8SEmmanuel Vadot reg |= XGBE_KR_TRAINING_ENABLE; 48944b781cfSAndrew Turner reg |= XGBE_KR_TRAINING_START; 4907113afc8SEmmanuel Vadot XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, reg); 49144b781cfSAndrew Turner 4927113afc8SEmmanuel Vadot if (pdata->phy_if.phy_impl.kr_training_post) 4937113afc8SEmmanuel Vadot pdata->phy_if.phy_impl.kr_training_post(pdata); 4947113afc8SEmmanuel Vadot 4957113afc8SEmmanuel Vadot return (XGBE_AN_PAGE_RECEIVED); 49644b781cfSAndrew Turner } 49744b781cfSAndrew Turner 4987113afc8SEmmanuel Vadot static enum xgbe_an 4997113afc8SEmmanuel Vadot xgbe_an73_tx_xnp(struct xgbe_prv_data *pdata, enum xgbe_rx *state) 50044b781cfSAndrew Turner { 5017113afc8SEmmanuel Vadot uint16_t msg; 50244b781cfSAndrew Turner 50344b781cfSAndrew Turner *state = XGBE_RX_XNP; 50444b781cfSAndrew Turner 50544b781cfSAndrew Turner msg = XGBE_XNP_MCF_NULL_MESSAGE; 50644b781cfSAndrew Turner msg |= XGBE_XNP_MP_FORMATTED; 50744b781cfSAndrew Turner 50844b781cfSAndrew Turner XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_XNP + 2, 0); 50944b781cfSAndrew Turner XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_XNP + 1, 0); 51044b781cfSAndrew Turner XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_XNP, msg); 51144b781cfSAndrew Turner 5127113afc8SEmmanuel Vadot return (XGBE_AN_PAGE_RECEIVED); 51344b781cfSAndrew Turner } 51444b781cfSAndrew Turner 5157113afc8SEmmanuel Vadot static enum xgbe_an 5167113afc8SEmmanuel Vadot xgbe_an73_rx_bpa(struct xgbe_prv_data *pdata, enum xgbe_rx *state) 51744b781cfSAndrew Turner { 51844b781cfSAndrew Turner unsigned int link_support; 51944b781cfSAndrew Turner unsigned int reg, ad_reg, lp_reg; 52044b781cfSAndrew Turner 52144b781cfSAndrew Turner /* Read Base Ability register 2 first */ 52244b781cfSAndrew Turner reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1); 52344b781cfSAndrew Turner 52444b781cfSAndrew Turner /* Check for a supported mode, otherwise restart in a different one */ 52544b781cfSAndrew Turner link_support = xgbe_in_kr_mode(pdata) ? 0x80 : 0x20; 52644b781cfSAndrew Turner if (!(reg & link_support)) 5277113afc8SEmmanuel Vadot return (XGBE_AN_INCOMPAT_LINK); 52844b781cfSAndrew Turner 52944b781cfSAndrew Turner /* Check Extended Next Page support */ 53044b781cfSAndrew Turner ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE); 53144b781cfSAndrew Turner lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA); 53244b781cfSAndrew Turner 5337113afc8SEmmanuel Vadot return (((ad_reg & XGBE_XNP_NP_EXCHANGE) || 53444b781cfSAndrew Turner (lp_reg & XGBE_XNP_NP_EXCHANGE)) 5357113afc8SEmmanuel Vadot ? xgbe_an73_tx_xnp(pdata, state) 5367113afc8SEmmanuel Vadot : xgbe_an73_tx_training(pdata, state)); 53744b781cfSAndrew Turner } 53844b781cfSAndrew Turner 5397113afc8SEmmanuel Vadot static enum xgbe_an 5407113afc8SEmmanuel Vadot xgbe_an73_rx_xnp(struct xgbe_prv_data *pdata, enum xgbe_rx *state) 54144b781cfSAndrew Turner { 54244b781cfSAndrew Turner unsigned int ad_reg, lp_reg; 54344b781cfSAndrew Turner 54444b781cfSAndrew Turner /* Check Extended Next Page support */ 54544b781cfSAndrew Turner ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_XNP); 54644b781cfSAndrew Turner lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPX); 54744b781cfSAndrew Turner 5487113afc8SEmmanuel Vadot return (((ad_reg & XGBE_XNP_NP_EXCHANGE) || 54944b781cfSAndrew Turner (lp_reg & XGBE_XNP_NP_EXCHANGE)) 5507113afc8SEmmanuel Vadot ? xgbe_an73_tx_xnp(pdata, state) 5517113afc8SEmmanuel Vadot : xgbe_an73_tx_training(pdata, state)); 55244b781cfSAndrew Turner } 55344b781cfSAndrew Turner 5547113afc8SEmmanuel Vadot static enum xgbe_an 5557113afc8SEmmanuel Vadot xgbe_an73_page_received(struct xgbe_prv_data *pdata) 55644b781cfSAndrew Turner { 55744b781cfSAndrew Turner enum xgbe_rx *state; 55844b781cfSAndrew Turner unsigned long an_timeout; 55944b781cfSAndrew Turner enum xgbe_an ret; 56044b781cfSAndrew Turner 56144b781cfSAndrew Turner if (!pdata->an_start) { 5629c6d6488SAndrew Turner pdata->an_start = ticks; 56344b781cfSAndrew Turner } else { 56444b781cfSAndrew Turner an_timeout = pdata->an_start + 5659c6d6488SAndrew Turner ((uint64_t)XGBE_AN_MS_TIMEOUT * (uint64_t)hz) / 1000ull; 5669c6d6488SAndrew Turner if ((int)(ticks - an_timeout) > 0) { 56744b781cfSAndrew Turner /* Auto-negotiation timed out, reset state */ 56844b781cfSAndrew Turner pdata->kr_state = XGBE_RX_BPA; 56944b781cfSAndrew Turner pdata->kx_state = XGBE_RX_BPA; 57044b781cfSAndrew Turner 5719c6d6488SAndrew Turner pdata->an_start = ticks; 5727113afc8SEmmanuel Vadot 5737113afc8SEmmanuel Vadot axgbe_printf(2, "CL73 AN timed out, resetting state\n"); 57444b781cfSAndrew Turner } 57544b781cfSAndrew Turner } 57644b781cfSAndrew Turner 5777113afc8SEmmanuel Vadot state = xgbe_in_kr_mode(pdata) ? &pdata->kr_state : &pdata->kx_state; 57844b781cfSAndrew Turner 57944b781cfSAndrew Turner switch (*state) { 58044b781cfSAndrew Turner case XGBE_RX_BPA: 5817113afc8SEmmanuel Vadot ret = xgbe_an73_rx_bpa(pdata, state); 58244b781cfSAndrew Turner break; 58344b781cfSAndrew Turner 58444b781cfSAndrew Turner case XGBE_RX_XNP: 5857113afc8SEmmanuel Vadot ret = xgbe_an73_rx_xnp(pdata, state); 58644b781cfSAndrew Turner break; 58744b781cfSAndrew Turner 58844b781cfSAndrew Turner default: 58944b781cfSAndrew Turner ret = XGBE_AN_ERROR; 59044b781cfSAndrew Turner } 59144b781cfSAndrew Turner 5927113afc8SEmmanuel Vadot return (ret); 59344b781cfSAndrew Turner } 59444b781cfSAndrew Turner 5957113afc8SEmmanuel Vadot static enum xgbe_an 5967113afc8SEmmanuel Vadot xgbe_an73_incompat_link(struct xgbe_prv_data *pdata) 59744b781cfSAndrew Turner { 59844b781cfSAndrew Turner /* Be sure we aren't looping trying to negotiate */ 59944b781cfSAndrew Turner if (xgbe_in_kr_mode(pdata)) { 60044b781cfSAndrew Turner pdata->kr_state = XGBE_RX_ERROR; 60144b781cfSAndrew Turner 6027113afc8SEmmanuel Vadot if (!(XGBE_ADV(&pdata->phy, 1000baseKX_Full)) && 6037113afc8SEmmanuel Vadot !(XGBE_ADV(&pdata->phy, 2500baseX_Full))) 6047113afc8SEmmanuel Vadot return (XGBE_AN_NO_LINK); 60544b781cfSAndrew Turner 60644b781cfSAndrew Turner if (pdata->kx_state != XGBE_RX_BPA) 6077113afc8SEmmanuel Vadot return (XGBE_AN_NO_LINK); 60844b781cfSAndrew Turner } else { 60944b781cfSAndrew Turner pdata->kx_state = XGBE_RX_ERROR; 61044b781cfSAndrew Turner 6117113afc8SEmmanuel Vadot if (!(XGBE_ADV(&pdata->phy, 10000baseKR_Full))) 6127113afc8SEmmanuel Vadot return (XGBE_AN_NO_LINK); 61344b781cfSAndrew Turner 61444b781cfSAndrew Turner if (pdata->kr_state != XGBE_RX_BPA) 6157113afc8SEmmanuel Vadot return (XGBE_AN_NO_LINK); 61644b781cfSAndrew Turner } 61744b781cfSAndrew Turner 6187113afc8SEmmanuel Vadot xgbe_an_disable(pdata); 61944b781cfSAndrew Turner 62044b781cfSAndrew Turner xgbe_switch_mode(pdata); 62144b781cfSAndrew Turner 6227113afc8SEmmanuel Vadot xgbe_an_restart(pdata); 62344b781cfSAndrew Turner 6247113afc8SEmmanuel Vadot return (XGBE_AN_INCOMPAT_LINK); 62544b781cfSAndrew Turner } 62644b781cfSAndrew Turner 6277113afc8SEmmanuel Vadot static void 6287113afc8SEmmanuel Vadot xgbe_an37_isr(struct xgbe_prv_data *pdata) 62944b781cfSAndrew Turner { 6307113afc8SEmmanuel Vadot unsigned int reg; 63144b781cfSAndrew Turner 63244b781cfSAndrew Turner /* Disable AN interrupts */ 6337113afc8SEmmanuel Vadot xgbe_an37_disable_interrupts(pdata); 6347113afc8SEmmanuel Vadot 6357113afc8SEmmanuel Vadot /* Save the interrupt(s) that fired */ 6367113afc8SEmmanuel Vadot reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT); 6377113afc8SEmmanuel Vadot pdata->an_int = reg & XGBE_AN_CL37_INT_MASK; 6387113afc8SEmmanuel Vadot pdata->an_status = reg & ~XGBE_AN_CL37_INT_MASK; 6397113afc8SEmmanuel Vadot 6407113afc8SEmmanuel Vadot if (pdata->an_int) { 6417113afc8SEmmanuel Vadot /* Clear the interrupt(s) that fired and process them */ 6427113afc8SEmmanuel Vadot reg &= ~XGBE_AN_CL37_INT_MASK; 6437113afc8SEmmanuel Vadot XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT, reg); 6447113afc8SEmmanuel Vadot 6457113afc8SEmmanuel Vadot xgbe_an_state_machine(pdata); 6467113afc8SEmmanuel Vadot } else { 6477113afc8SEmmanuel Vadot /* Enable AN interrupts */ 6487113afc8SEmmanuel Vadot xgbe_an37_enable_interrupts(pdata); 6497113afc8SEmmanuel Vadot 6507113afc8SEmmanuel Vadot /* Reissue interrupt if status is not clear */ 6517113afc8SEmmanuel Vadot if (pdata->vdata->irq_reissue_support) 6527113afc8SEmmanuel Vadot XP_IOWRITE(pdata, XP_INT_REISSUE_EN, 1 << 3); 6537113afc8SEmmanuel Vadot } 6547113afc8SEmmanuel Vadot } 6557113afc8SEmmanuel Vadot 6567113afc8SEmmanuel Vadot static void 6577113afc8SEmmanuel Vadot xgbe_an73_isr(struct xgbe_prv_data *pdata) 6587113afc8SEmmanuel Vadot { 6597113afc8SEmmanuel Vadot /* Disable AN interrupts */ 6607113afc8SEmmanuel Vadot xgbe_an73_disable_interrupts(pdata); 66144b781cfSAndrew Turner 66244b781cfSAndrew Turner /* Save the interrupt(s) that fired */ 66344b781cfSAndrew Turner pdata->an_int = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_INT); 66444b781cfSAndrew Turner 66544b781cfSAndrew Turner if (pdata->an_int) { 66644b781cfSAndrew Turner /* Clear the interrupt(s) that fired and process them */ 66744b781cfSAndrew Turner XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, ~pdata->an_int); 66844b781cfSAndrew Turner 6699c6d6488SAndrew Turner xgbe_an_state_machine(pdata); 67044b781cfSAndrew Turner } else { 67144b781cfSAndrew Turner /* Enable AN interrupts */ 6727113afc8SEmmanuel Vadot xgbe_an73_enable_interrupts(pdata); 6737113afc8SEmmanuel Vadot 6747113afc8SEmmanuel Vadot /* Reissue interrupt if status is not clear */ 6757113afc8SEmmanuel Vadot if (pdata->vdata->irq_reissue_support) 6767113afc8SEmmanuel Vadot XP_IOWRITE(pdata, XP_INT_REISSUE_EN, 1 << 3); 67744b781cfSAndrew Turner } 67844b781cfSAndrew Turner } 67944b781cfSAndrew Turner 6807113afc8SEmmanuel Vadot static void 6817113afc8SEmmanuel Vadot xgbe_an_isr_task(unsigned long data) 6827113afc8SEmmanuel Vadot { 6837113afc8SEmmanuel Vadot struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)data; 6847113afc8SEmmanuel Vadot 6857113afc8SEmmanuel Vadot axgbe_printf(2, "AN interrupt received\n"); 6867113afc8SEmmanuel Vadot 6877113afc8SEmmanuel Vadot switch (pdata->an_mode) { 6887113afc8SEmmanuel Vadot case XGBE_AN_MODE_CL73: 6897113afc8SEmmanuel Vadot case XGBE_AN_MODE_CL73_REDRV: 6907113afc8SEmmanuel Vadot xgbe_an73_isr(pdata); 6917113afc8SEmmanuel Vadot break; 6927113afc8SEmmanuel Vadot case XGBE_AN_MODE_CL37: 6937113afc8SEmmanuel Vadot case XGBE_AN_MODE_CL37_SGMII: 6947113afc8SEmmanuel Vadot xgbe_an37_isr(pdata); 6957113afc8SEmmanuel Vadot break; 6967113afc8SEmmanuel Vadot default: 6977113afc8SEmmanuel Vadot break; 6987113afc8SEmmanuel Vadot } 6997113afc8SEmmanuel Vadot } 7007113afc8SEmmanuel Vadot 7017113afc8SEmmanuel Vadot static void 7027113afc8SEmmanuel Vadot xgbe_an_combined_isr(struct xgbe_prv_data *pdata) 7037113afc8SEmmanuel Vadot { 7047113afc8SEmmanuel Vadot xgbe_an_isr_task((unsigned long)pdata); 7057113afc8SEmmanuel Vadot } 7067113afc8SEmmanuel Vadot 7077113afc8SEmmanuel Vadot static const char * 7087113afc8SEmmanuel Vadot xgbe_state_as_string(enum xgbe_an state) 7097113afc8SEmmanuel Vadot { 7107113afc8SEmmanuel Vadot switch (state) { 7117113afc8SEmmanuel Vadot case XGBE_AN_READY: 7127113afc8SEmmanuel Vadot return ("Ready"); 7137113afc8SEmmanuel Vadot case XGBE_AN_PAGE_RECEIVED: 7147113afc8SEmmanuel Vadot return ("Page-Received"); 7157113afc8SEmmanuel Vadot case XGBE_AN_INCOMPAT_LINK: 7167113afc8SEmmanuel Vadot return ("Incompatible-Link"); 7177113afc8SEmmanuel Vadot case XGBE_AN_COMPLETE: 7187113afc8SEmmanuel Vadot return ("Complete"); 7197113afc8SEmmanuel Vadot case XGBE_AN_NO_LINK: 7207113afc8SEmmanuel Vadot return ("No-Link"); 7217113afc8SEmmanuel Vadot case XGBE_AN_ERROR: 7227113afc8SEmmanuel Vadot return ("Error"); 7237113afc8SEmmanuel Vadot default: 7247113afc8SEmmanuel Vadot return ("Undefined"); 7257113afc8SEmmanuel Vadot } 7267113afc8SEmmanuel Vadot } 7277113afc8SEmmanuel Vadot 7287113afc8SEmmanuel Vadot static void 7297113afc8SEmmanuel Vadot xgbe_an37_state_machine(struct xgbe_prv_data *pdata) 73044b781cfSAndrew Turner { 73144b781cfSAndrew Turner enum xgbe_an cur_state = pdata->an_state; 73244b781cfSAndrew Turner 7337113afc8SEmmanuel Vadot if (!pdata->an_int) 7347113afc8SEmmanuel Vadot return; 7357113afc8SEmmanuel Vadot 7367113afc8SEmmanuel Vadot if (pdata->an_int & XGBE_AN_CL37_INT_CMPLT) { 7377113afc8SEmmanuel Vadot pdata->an_state = XGBE_AN_COMPLETE; 7387113afc8SEmmanuel Vadot pdata->an_int &= ~XGBE_AN_CL37_INT_CMPLT; 7397113afc8SEmmanuel Vadot 7407113afc8SEmmanuel Vadot /* If SGMII is enabled, check the link status */ 7417113afc8SEmmanuel Vadot if ((pdata->an_mode == XGBE_AN_MODE_CL37_SGMII) && 7427113afc8SEmmanuel Vadot !(pdata->an_status & XGBE_SGMII_AN_LINK_STATUS)) 7437113afc8SEmmanuel Vadot pdata->an_state = XGBE_AN_NO_LINK; 7447113afc8SEmmanuel Vadot } 7457113afc8SEmmanuel Vadot 7467113afc8SEmmanuel Vadot axgbe_printf(2, "%s: CL37 AN %s\n", __func__, 7477113afc8SEmmanuel Vadot xgbe_state_as_string(pdata->an_state)); 7487113afc8SEmmanuel Vadot 7497113afc8SEmmanuel Vadot cur_state = pdata->an_state; 7507113afc8SEmmanuel Vadot 7517113afc8SEmmanuel Vadot switch (pdata->an_state) { 7527113afc8SEmmanuel Vadot case XGBE_AN_READY: 7537113afc8SEmmanuel Vadot break; 7547113afc8SEmmanuel Vadot 7557113afc8SEmmanuel Vadot case XGBE_AN_COMPLETE: 7567113afc8SEmmanuel Vadot axgbe_printf(2, "Auto negotiation successful\n"); 7577113afc8SEmmanuel Vadot break; 7587113afc8SEmmanuel Vadot 7597113afc8SEmmanuel Vadot case XGBE_AN_NO_LINK: 7607113afc8SEmmanuel Vadot break; 7617113afc8SEmmanuel Vadot 7627113afc8SEmmanuel Vadot default: 7637113afc8SEmmanuel Vadot pdata->an_state = XGBE_AN_ERROR; 7647113afc8SEmmanuel Vadot } 7657113afc8SEmmanuel Vadot 7667113afc8SEmmanuel Vadot if (pdata->an_state == XGBE_AN_ERROR) { 7677113afc8SEmmanuel Vadot axgbe_printf(2, "error during auto-negotiation, state=%u\n", 7687113afc8SEmmanuel Vadot cur_state); 7697113afc8SEmmanuel Vadot 7707113afc8SEmmanuel Vadot pdata->an_int = 0; 7717113afc8SEmmanuel Vadot xgbe_an37_clear_interrupts(pdata); 7727113afc8SEmmanuel Vadot } 7737113afc8SEmmanuel Vadot 7747113afc8SEmmanuel Vadot if (pdata->an_state >= XGBE_AN_COMPLETE) { 7757113afc8SEmmanuel Vadot pdata->an_result = pdata->an_state; 7767113afc8SEmmanuel Vadot pdata->an_state = XGBE_AN_READY; 7777113afc8SEmmanuel Vadot 7787113afc8SEmmanuel Vadot if (pdata->phy_if.phy_impl.an_post) 7797113afc8SEmmanuel Vadot pdata->phy_if.phy_impl.an_post(pdata); 7807113afc8SEmmanuel Vadot 7817113afc8SEmmanuel Vadot axgbe_printf(2, "CL37 AN result: %s\n", 7827113afc8SEmmanuel Vadot xgbe_state_as_string(pdata->an_result)); 7837113afc8SEmmanuel Vadot } 7847113afc8SEmmanuel Vadot 7857113afc8SEmmanuel Vadot axgbe_printf(2, "%s: an_state %d an_int %d an_mode %d an_status %d\n", 7867113afc8SEmmanuel Vadot __func__, pdata->an_state, pdata->an_int, pdata->an_mode, 7877113afc8SEmmanuel Vadot pdata->an_status); 7887113afc8SEmmanuel Vadot 7897113afc8SEmmanuel Vadot xgbe_an37_enable_interrupts(pdata); 7907113afc8SEmmanuel Vadot } 7917113afc8SEmmanuel Vadot 7927113afc8SEmmanuel Vadot static void 7937113afc8SEmmanuel Vadot xgbe_an73_state_machine(struct xgbe_prv_data *pdata) 7947113afc8SEmmanuel Vadot { 7957113afc8SEmmanuel Vadot enum xgbe_an cur_state = pdata->an_state; 79644b781cfSAndrew Turner 79744b781cfSAndrew Turner if (!pdata->an_int) 79844b781cfSAndrew Turner goto out; 79944b781cfSAndrew Turner 80044b781cfSAndrew Turner next_int: 8017113afc8SEmmanuel Vadot if (pdata->an_int & XGBE_AN_CL73_PG_RCV) { 80244b781cfSAndrew Turner pdata->an_state = XGBE_AN_PAGE_RECEIVED; 8037113afc8SEmmanuel Vadot pdata->an_int &= ~XGBE_AN_CL73_PG_RCV; 8047113afc8SEmmanuel Vadot } else if (pdata->an_int & XGBE_AN_CL73_INC_LINK) { 80544b781cfSAndrew Turner pdata->an_state = XGBE_AN_INCOMPAT_LINK; 8067113afc8SEmmanuel Vadot pdata->an_int &= ~XGBE_AN_CL73_INC_LINK; 8077113afc8SEmmanuel Vadot } else if (pdata->an_int & XGBE_AN_CL73_INT_CMPLT) { 80844b781cfSAndrew Turner pdata->an_state = XGBE_AN_COMPLETE; 8097113afc8SEmmanuel Vadot pdata->an_int &= ~XGBE_AN_CL73_INT_CMPLT; 81044b781cfSAndrew Turner } else { 81144b781cfSAndrew Turner pdata->an_state = XGBE_AN_ERROR; 81244b781cfSAndrew Turner } 81344b781cfSAndrew Turner 81444b781cfSAndrew Turner again: 8157113afc8SEmmanuel Vadot axgbe_printf(2, "CL73 AN %s\n", 8167113afc8SEmmanuel Vadot xgbe_state_as_string(pdata->an_state)); 8177113afc8SEmmanuel Vadot 81844b781cfSAndrew Turner cur_state = pdata->an_state; 81944b781cfSAndrew Turner 82044b781cfSAndrew Turner switch (pdata->an_state) { 82144b781cfSAndrew Turner case XGBE_AN_READY: 82244b781cfSAndrew Turner pdata->an_supported = 0; 82344b781cfSAndrew Turner break; 82444b781cfSAndrew Turner 82544b781cfSAndrew Turner case XGBE_AN_PAGE_RECEIVED: 8267113afc8SEmmanuel Vadot pdata->an_state = xgbe_an73_page_received(pdata); 82744b781cfSAndrew Turner pdata->an_supported++; 82844b781cfSAndrew Turner break; 82944b781cfSAndrew Turner 83044b781cfSAndrew Turner case XGBE_AN_INCOMPAT_LINK: 83144b781cfSAndrew Turner pdata->an_supported = 0; 83244b781cfSAndrew Turner pdata->parallel_detect = 0; 8337113afc8SEmmanuel Vadot pdata->an_state = xgbe_an73_incompat_link(pdata); 83444b781cfSAndrew Turner break; 83544b781cfSAndrew Turner 83644b781cfSAndrew Turner case XGBE_AN_COMPLETE: 83744b781cfSAndrew Turner pdata->parallel_detect = pdata->an_supported ? 0 : 1; 8387113afc8SEmmanuel Vadot axgbe_printf(2, "%s successful\n", 8397113afc8SEmmanuel Vadot pdata->an_supported ? "Auto negotiation" 8407113afc8SEmmanuel Vadot : "Parallel detection"); 84144b781cfSAndrew Turner break; 84244b781cfSAndrew Turner 84344b781cfSAndrew Turner case XGBE_AN_NO_LINK: 84444b781cfSAndrew Turner break; 84544b781cfSAndrew Turner 84644b781cfSAndrew Turner default: 84744b781cfSAndrew Turner pdata->an_state = XGBE_AN_ERROR; 84844b781cfSAndrew Turner } 84944b781cfSAndrew Turner 85044b781cfSAndrew Turner if (pdata->an_state == XGBE_AN_NO_LINK) { 85144b781cfSAndrew Turner pdata->an_int = 0; 8527113afc8SEmmanuel Vadot xgbe_an73_clear_interrupts(pdata); 85344b781cfSAndrew Turner } else if (pdata->an_state == XGBE_AN_ERROR) { 8547113afc8SEmmanuel Vadot axgbe_printf(2, 8557113afc8SEmmanuel Vadot "error during auto-negotiation, state=%u\n", 8567113afc8SEmmanuel Vadot cur_state); 8577113afc8SEmmanuel Vadot 85844b781cfSAndrew Turner pdata->an_int = 0; 8597113afc8SEmmanuel Vadot xgbe_an73_clear_interrupts(pdata); 86044b781cfSAndrew Turner } 86144b781cfSAndrew Turner 86244b781cfSAndrew Turner if (pdata->an_state >= XGBE_AN_COMPLETE) { 86344b781cfSAndrew Turner pdata->an_result = pdata->an_state; 86444b781cfSAndrew Turner pdata->an_state = XGBE_AN_READY; 86544b781cfSAndrew Turner pdata->kr_state = XGBE_RX_BPA; 86644b781cfSAndrew Turner pdata->kx_state = XGBE_RX_BPA; 86744b781cfSAndrew Turner pdata->an_start = 0; 8687113afc8SEmmanuel Vadot 8697113afc8SEmmanuel Vadot if (pdata->phy_if.phy_impl.an_post) 8707113afc8SEmmanuel Vadot pdata->phy_if.phy_impl.an_post(pdata); 8717113afc8SEmmanuel Vadot 8727113afc8SEmmanuel Vadot axgbe_printf(2, "CL73 AN result: %s\n", 8737113afc8SEmmanuel Vadot xgbe_state_as_string(pdata->an_result)); 87444b781cfSAndrew Turner } 87544b781cfSAndrew Turner 87644b781cfSAndrew Turner if (cur_state != pdata->an_state) 87744b781cfSAndrew Turner goto again; 87844b781cfSAndrew Turner 87944b781cfSAndrew Turner if (pdata->an_int) 88044b781cfSAndrew Turner goto next_int; 88144b781cfSAndrew Turner 88244b781cfSAndrew Turner out: 88344b781cfSAndrew Turner /* Enable AN interrupts on the way out */ 8847113afc8SEmmanuel Vadot xgbe_an73_enable_interrupts(pdata); 8857113afc8SEmmanuel Vadot } 8867113afc8SEmmanuel Vadot 8877113afc8SEmmanuel Vadot static void 8887113afc8SEmmanuel Vadot xgbe_an_state_machine(struct xgbe_prv_data *pdata) 8897113afc8SEmmanuel Vadot { 8907113afc8SEmmanuel Vadot sx_xlock(&pdata->an_mutex); 8917113afc8SEmmanuel Vadot 8927113afc8SEmmanuel Vadot switch (pdata->an_mode) { 8937113afc8SEmmanuel Vadot case XGBE_AN_MODE_CL73: 8947113afc8SEmmanuel Vadot case XGBE_AN_MODE_CL73_REDRV: 8957113afc8SEmmanuel Vadot xgbe_an73_state_machine(pdata); 8967113afc8SEmmanuel Vadot break; 8977113afc8SEmmanuel Vadot case XGBE_AN_MODE_CL37: 8987113afc8SEmmanuel Vadot case XGBE_AN_MODE_CL37_SGMII: 8997113afc8SEmmanuel Vadot xgbe_an37_state_machine(pdata); 9007113afc8SEmmanuel Vadot break; 9017113afc8SEmmanuel Vadot default: 9027113afc8SEmmanuel Vadot break; 9037113afc8SEmmanuel Vadot } 9047113afc8SEmmanuel Vadot 9057113afc8SEmmanuel Vadot /* Reissue interrupt if status is not clear */ 9067113afc8SEmmanuel Vadot if (pdata->vdata->irq_reissue_support) 9077113afc8SEmmanuel Vadot XP_IOWRITE(pdata, XP_INT_REISSUE_EN, 1 << 3); 90844b781cfSAndrew Turner 9099c6d6488SAndrew Turner sx_xunlock(&pdata->an_mutex); 91044b781cfSAndrew Turner } 91144b781cfSAndrew Turner 9127113afc8SEmmanuel Vadot static void 9137113afc8SEmmanuel Vadot xgbe_an37_init(struct xgbe_prv_data *pdata) 91444b781cfSAndrew Turner { 9157113afc8SEmmanuel Vadot struct xgbe_phy local_phy; 91644b781cfSAndrew Turner unsigned int reg; 91744b781cfSAndrew Turner 9187113afc8SEmmanuel Vadot pdata->phy_if.phy_impl.an_advertising(pdata, &local_phy); 9197113afc8SEmmanuel Vadot 9207113afc8SEmmanuel Vadot axgbe_printf(2, "%s: advertising 0x%x\n", __func__, local_phy.advertising); 9217113afc8SEmmanuel Vadot 9227113afc8SEmmanuel Vadot /* Set up Advertisement register */ 9237113afc8SEmmanuel Vadot reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_ADVERTISE); 9247113afc8SEmmanuel Vadot if (XGBE_ADV(&local_phy, Pause)) 9257113afc8SEmmanuel Vadot reg |= 0x100; 9267113afc8SEmmanuel Vadot else 9277113afc8SEmmanuel Vadot reg &= ~0x100; 9287113afc8SEmmanuel Vadot 9297113afc8SEmmanuel Vadot if (XGBE_ADV(&local_phy, Asym_Pause)) 9307113afc8SEmmanuel Vadot reg |= 0x80; 9317113afc8SEmmanuel Vadot else 9327113afc8SEmmanuel Vadot reg &= ~0x80; 9337113afc8SEmmanuel Vadot 9347113afc8SEmmanuel Vadot /* Full duplex, but not half */ 9357113afc8SEmmanuel Vadot reg |= XGBE_AN_CL37_FD_MASK; 9367113afc8SEmmanuel Vadot reg &= ~XGBE_AN_CL37_HD_MASK; 9377113afc8SEmmanuel Vadot 9387113afc8SEmmanuel Vadot axgbe_printf(2, "%s: Writing reg: 0x%x\n", __func__, reg); 9397113afc8SEmmanuel Vadot XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_ADVERTISE, reg); 9407113afc8SEmmanuel Vadot 9417113afc8SEmmanuel Vadot /* Set up the Control register */ 9427113afc8SEmmanuel Vadot reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL); 9437113afc8SEmmanuel Vadot axgbe_printf(2, "%s: AN_ADVERTISE reg 0x%x an_mode %d\n", __func__, 9447113afc8SEmmanuel Vadot reg, pdata->an_mode); 9457113afc8SEmmanuel Vadot reg &= ~XGBE_AN_CL37_TX_CONFIG_MASK; 9467113afc8SEmmanuel Vadot reg &= ~XGBE_AN_CL37_PCS_MODE_MASK; 9477113afc8SEmmanuel Vadot 9487113afc8SEmmanuel Vadot switch (pdata->an_mode) { 9497113afc8SEmmanuel Vadot case XGBE_AN_MODE_CL37: 9507113afc8SEmmanuel Vadot reg |= XGBE_AN_CL37_PCS_MODE_BASEX; 9517113afc8SEmmanuel Vadot break; 9527113afc8SEmmanuel Vadot case XGBE_AN_MODE_CL37_SGMII: 9537113afc8SEmmanuel Vadot reg |= XGBE_AN_CL37_PCS_MODE_SGMII; 9547113afc8SEmmanuel Vadot break; 9557113afc8SEmmanuel Vadot default: 9567113afc8SEmmanuel Vadot break; 9577113afc8SEmmanuel Vadot } 9587113afc8SEmmanuel Vadot 9597113afc8SEmmanuel Vadot reg |= XGBE_AN_CL37_MII_CTRL_8BIT; 9607113afc8SEmmanuel Vadot axgbe_printf(2, "%s: Writing reg: 0x%x\n", __func__, reg); 9617113afc8SEmmanuel Vadot XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL, reg); 9627113afc8SEmmanuel Vadot 9637113afc8SEmmanuel Vadot axgbe_printf(2, "CL37 AN (%s) initialized\n", 9647113afc8SEmmanuel Vadot (pdata->an_mode == XGBE_AN_MODE_CL37) ? "BaseX" : "SGMII"); 9657113afc8SEmmanuel Vadot } 9667113afc8SEmmanuel Vadot 9677113afc8SEmmanuel Vadot static void 9687113afc8SEmmanuel Vadot xgbe_an73_init(struct xgbe_prv_data *pdata) 9697113afc8SEmmanuel Vadot { 9707113afc8SEmmanuel Vadot /* 9717113afc8SEmmanuel Vadot * This local_phy is needed because phy-v2 alters the 9727113afc8SEmmanuel Vadot * advertising flag variable. so phy-v1 an_advertising is just copying 9737113afc8SEmmanuel Vadot */ 9747113afc8SEmmanuel Vadot struct xgbe_phy local_phy; 9757113afc8SEmmanuel Vadot unsigned int reg; 9767113afc8SEmmanuel Vadot 9777113afc8SEmmanuel Vadot pdata->phy_if.phy_impl.an_advertising(pdata, &local_phy); 9787113afc8SEmmanuel Vadot 97944b781cfSAndrew Turner /* Set up Advertisement register 3 first */ 98044b781cfSAndrew Turner reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); 9817113afc8SEmmanuel Vadot if (XGBE_ADV(&local_phy, 10000baseR_FEC)) 9827113afc8SEmmanuel Vadot reg |= 0xc000; 9837113afc8SEmmanuel Vadot else 98444b781cfSAndrew Turner reg &= ~0xc000; 98544b781cfSAndrew Turner 98644b781cfSAndrew Turner XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2, reg); 98744b781cfSAndrew Turner 98844b781cfSAndrew Turner /* Set up Advertisement register 2 next */ 98944b781cfSAndrew Turner reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1); 9907113afc8SEmmanuel Vadot if (XGBE_ADV(&local_phy, 10000baseKR_Full)) 99144b781cfSAndrew Turner reg |= 0x80; 99244b781cfSAndrew Turner else 99344b781cfSAndrew Turner reg &= ~0x80; 99444b781cfSAndrew Turner 9957113afc8SEmmanuel Vadot if (XGBE_ADV(&local_phy, 1000baseKX_Full) || 9967113afc8SEmmanuel Vadot XGBE_ADV(&local_phy, 2500baseX_Full)) 99744b781cfSAndrew Turner reg |= 0x20; 99844b781cfSAndrew Turner else 99944b781cfSAndrew Turner reg &= ~0x20; 100044b781cfSAndrew Turner 100144b781cfSAndrew Turner XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1, reg); 100244b781cfSAndrew Turner 100344b781cfSAndrew Turner /* Set up Advertisement register 1 last */ 100444b781cfSAndrew Turner reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE); 10057113afc8SEmmanuel Vadot if (XGBE_ADV(&local_phy, Pause)) 100644b781cfSAndrew Turner reg |= 0x400; 100744b781cfSAndrew Turner else 100844b781cfSAndrew Turner reg &= ~0x400; 100944b781cfSAndrew Turner 10107113afc8SEmmanuel Vadot if (XGBE_ADV(&local_phy, Asym_Pause)) 101144b781cfSAndrew Turner reg |= 0x800; 101244b781cfSAndrew Turner else 101344b781cfSAndrew Turner reg &= ~0x800; 101444b781cfSAndrew Turner 101544b781cfSAndrew Turner /* We don't intend to perform XNP */ 101644b781cfSAndrew Turner reg &= ~XGBE_XNP_NP_EXCHANGE; 101744b781cfSAndrew Turner 101844b781cfSAndrew Turner XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg); 10197113afc8SEmmanuel Vadot 10207113afc8SEmmanuel Vadot axgbe_printf(2, "CL73 AN initialized\n"); 102144b781cfSAndrew Turner } 102244b781cfSAndrew Turner 10237113afc8SEmmanuel Vadot static void 10247113afc8SEmmanuel Vadot xgbe_an_init(struct xgbe_prv_data *pdata) 102544b781cfSAndrew Turner { 10267113afc8SEmmanuel Vadot /* Set up advertisement registers based on current settings */ 10277113afc8SEmmanuel Vadot pdata->an_mode = pdata->phy_if.phy_impl.an_mode(pdata); 10287113afc8SEmmanuel Vadot axgbe_printf(2, "%s: setting up an_mode %d\n", __func__, pdata->an_mode); 10297113afc8SEmmanuel Vadot 10307113afc8SEmmanuel Vadot switch (pdata->an_mode) { 10317113afc8SEmmanuel Vadot case XGBE_AN_MODE_CL73: 10327113afc8SEmmanuel Vadot case XGBE_AN_MODE_CL73_REDRV: 10337113afc8SEmmanuel Vadot xgbe_an73_init(pdata); 10347113afc8SEmmanuel Vadot break; 10357113afc8SEmmanuel Vadot case XGBE_AN_MODE_CL37: 10367113afc8SEmmanuel Vadot case XGBE_AN_MODE_CL37_SGMII: 10377113afc8SEmmanuel Vadot xgbe_an37_init(pdata); 10387113afc8SEmmanuel Vadot break; 10397113afc8SEmmanuel Vadot default: 10407113afc8SEmmanuel Vadot break; 10417113afc8SEmmanuel Vadot } 10427113afc8SEmmanuel Vadot } 10437113afc8SEmmanuel Vadot 10447113afc8SEmmanuel Vadot static const char * 10457113afc8SEmmanuel Vadot xgbe_phy_fc_string(struct xgbe_prv_data *pdata) 10467113afc8SEmmanuel Vadot { 10477113afc8SEmmanuel Vadot if (pdata->tx_pause && pdata->rx_pause) 10487113afc8SEmmanuel Vadot return ("rx/tx"); 10497113afc8SEmmanuel Vadot else if (pdata->rx_pause) 10507113afc8SEmmanuel Vadot return ("rx"); 10517113afc8SEmmanuel Vadot else if (pdata->tx_pause) 10527113afc8SEmmanuel Vadot return ("tx"); 10537113afc8SEmmanuel Vadot else 10547113afc8SEmmanuel Vadot return ("off"); 10557113afc8SEmmanuel Vadot } 10567113afc8SEmmanuel Vadot 10577113afc8SEmmanuel Vadot static const char * 10587113afc8SEmmanuel Vadot xgbe_phy_speed_string(int speed) 10597113afc8SEmmanuel Vadot { 10607113afc8SEmmanuel Vadot switch (speed) { 10617113afc8SEmmanuel Vadot case SPEED_100: 10627113afc8SEmmanuel Vadot return ("100Mbps"); 10637113afc8SEmmanuel Vadot case SPEED_1000: 10647113afc8SEmmanuel Vadot return ("1Gbps"); 10657113afc8SEmmanuel Vadot case SPEED_2500: 10667113afc8SEmmanuel Vadot return ("2.5Gbps"); 10677113afc8SEmmanuel Vadot case SPEED_10000: 10687113afc8SEmmanuel Vadot return ("10Gbps"); 10697113afc8SEmmanuel Vadot case SPEED_UNKNOWN: 10707113afc8SEmmanuel Vadot return ("Unknown"); 10717113afc8SEmmanuel Vadot default: 10727113afc8SEmmanuel Vadot return ("Unsupported"); 10737113afc8SEmmanuel Vadot } 10747113afc8SEmmanuel Vadot } 10757113afc8SEmmanuel Vadot 10767113afc8SEmmanuel Vadot static void 10777113afc8SEmmanuel Vadot xgbe_phy_print_status(struct xgbe_prv_data *pdata) 10787113afc8SEmmanuel Vadot { 10797113afc8SEmmanuel Vadot if (pdata->phy.link) 10807113afc8SEmmanuel Vadot axgbe_printf(0, 10817113afc8SEmmanuel Vadot "Link is UP - %s/%s - flow control %s\n", 10827113afc8SEmmanuel Vadot xgbe_phy_speed_string(pdata->phy.speed), 10837113afc8SEmmanuel Vadot pdata->phy.duplex == DUPLEX_FULL ? "Full" : "Half", 10847113afc8SEmmanuel Vadot xgbe_phy_fc_string(pdata)); 10857113afc8SEmmanuel Vadot else 10867113afc8SEmmanuel Vadot axgbe_printf(0, "Link is DOWN\n"); 10877113afc8SEmmanuel Vadot } 10887113afc8SEmmanuel Vadot 10897113afc8SEmmanuel Vadot static void 10907113afc8SEmmanuel Vadot xgbe_phy_adjust_link(struct xgbe_prv_data *pdata) 10917113afc8SEmmanuel Vadot { 10927113afc8SEmmanuel Vadot int new_state = 0; 10937113afc8SEmmanuel Vadot 10947113afc8SEmmanuel Vadot axgbe_printf(1, "link %d/%d tx %d/%d rx %d/%d speed %d/%d autoneg %d/%d\n", 10957113afc8SEmmanuel Vadot pdata->phy_link, pdata->phy.link, 10967113afc8SEmmanuel Vadot pdata->tx_pause, pdata->phy.tx_pause, 10977113afc8SEmmanuel Vadot pdata->rx_pause, pdata->phy.rx_pause, 10987113afc8SEmmanuel Vadot pdata->phy_speed, pdata->phy.speed, 10997113afc8SEmmanuel Vadot pdata->pause_autoneg, pdata->phy.pause_autoneg); 110044b781cfSAndrew Turner 110144b781cfSAndrew Turner if (pdata->phy.link) { 110244b781cfSAndrew Turner /* Flow control support */ 110344b781cfSAndrew Turner pdata->pause_autoneg = pdata->phy.pause_autoneg; 110444b781cfSAndrew Turner 110544b781cfSAndrew Turner if (pdata->tx_pause != pdata->phy.tx_pause) { 11067113afc8SEmmanuel Vadot new_state = 1; 11077113afc8SEmmanuel Vadot axgbe_printf(2, "tx pause %d/%d\n", pdata->tx_pause, 11087113afc8SEmmanuel Vadot pdata->phy.tx_pause); 110944b781cfSAndrew Turner pdata->tx_pause = pdata->phy.tx_pause; 11107113afc8SEmmanuel Vadot pdata->hw_if.config_tx_flow_control(pdata); 111144b781cfSAndrew Turner } 111244b781cfSAndrew Turner 111344b781cfSAndrew Turner if (pdata->rx_pause != pdata->phy.rx_pause) { 11147113afc8SEmmanuel Vadot new_state = 1; 11157113afc8SEmmanuel Vadot axgbe_printf(2, "rx pause %d/%d\n", pdata->rx_pause, 11167113afc8SEmmanuel Vadot pdata->phy.rx_pause); 111744b781cfSAndrew Turner pdata->rx_pause = pdata->phy.rx_pause; 11187113afc8SEmmanuel Vadot pdata->hw_if.config_rx_flow_control(pdata); 111944b781cfSAndrew Turner } 112044b781cfSAndrew Turner 112144b781cfSAndrew Turner /* Speed support */ 112244b781cfSAndrew Turner if (pdata->phy_speed != pdata->phy.speed) { 11237113afc8SEmmanuel Vadot new_state = 1; 112444b781cfSAndrew Turner pdata->phy_speed = pdata->phy.speed; 112544b781cfSAndrew Turner } 112644b781cfSAndrew Turner 112744b781cfSAndrew Turner if (pdata->phy_link != pdata->phy.link) { 11287113afc8SEmmanuel Vadot new_state = 1; 112944b781cfSAndrew Turner pdata->phy_link = pdata->phy.link; 113044b781cfSAndrew Turner } 113144b781cfSAndrew Turner } else if (pdata->phy_link) { 11327113afc8SEmmanuel Vadot new_state = 1; 113344b781cfSAndrew Turner pdata->phy_link = 0; 113444b781cfSAndrew Turner pdata->phy_speed = SPEED_UNKNOWN; 113544b781cfSAndrew Turner } 11367113afc8SEmmanuel Vadot 11377113afc8SEmmanuel Vadot axgbe_printf(2, "phy_link %d Link %d new_state %d\n", pdata->phy_link, 11387113afc8SEmmanuel Vadot pdata->phy.link, new_state); 11397113afc8SEmmanuel Vadot 11407113afc8SEmmanuel Vadot if (new_state) 11417113afc8SEmmanuel Vadot xgbe_phy_print_status(pdata); 114244b781cfSAndrew Turner } 114344b781cfSAndrew Turner 11447113afc8SEmmanuel Vadot static bool 11457113afc8SEmmanuel Vadot xgbe_phy_valid_speed(struct xgbe_prv_data *pdata, int speed) 114644b781cfSAndrew Turner { 11477113afc8SEmmanuel Vadot return (pdata->phy_if.phy_impl.valid_speed(pdata, speed)); 11487113afc8SEmmanuel Vadot } 11497113afc8SEmmanuel Vadot 11507113afc8SEmmanuel Vadot static int 11517113afc8SEmmanuel Vadot xgbe_phy_config_fixed(struct xgbe_prv_data *pdata) 11527113afc8SEmmanuel Vadot { 11537113afc8SEmmanuel Vadot enum xgbe_mode mode; 11547113afc8SEmmanuel Vadot 11557113afc8SEmmanuel Vadot axgbe_printf(2, "fixed PHY configuration\n"); 115644b781cfSAndrew Turner 115744b781cfSAndrew Turner /* Disable auto-negotiation */ 11587113afc8SEmmanuel Vadot xgbe_an_disable(pdata); 115944b781cfSAndrew Turner 11607113afc8SEmmanuel Vadot /* Set specified mode for specified speed */ 11617113afc8SEmmanuel Vadot mode = pdata->phy_if.phy_impl.get_mode(pdata, pdata->phy.speed); 11627113afc8SEmmanuel Vadot switch (mode) { 11637113afc8SEmmanuel Vadot case XGBE_MODE_KX_1000: 11647113afc8SEmmanuel Vadot case XGBE_MODE_KX_2500: 11657113afc8SEmmanuel Vadot case XGBE_MODE_KR: 11667113afc8SEmmanuel Vadot case XGBE_MODE_SGMII_100: 11677113afc8SEmmanuel Vadot case XGBE_MODE_SGMII_1000: 11687113afc8SEmmanuel Vadot case XGBE_MODE_X: 11697113afc8SEmmanuel Vadot case XGBE_MODE_SFI: 117044b781cfSAndrew Turner break; 11717113afc8SEmmanuel Vadot case XGBE_MODE_UNKNOWN: 117244b781cfSAndrew Turner default: 11737113afc8SEmmanuel Vadot return (-EINVAL); 117444b781cfSAndrew Turner } 117544b781cfSAndrew Turner 117644b781cfSAndrew Turner /* Validate duplex mode */ 117744b781cfSAndrew Turner if (pdata->phy.duplex != DUPLEX_FULL) 11787113afc8SEmmanuel Vadot return (-EINVAL); 117944b781cfSAndrew Turner 11807113afc8SEmmanuel Vadot xgbe_set_mode(pdata, mode); 11817113afc8SEmmanuel Vadot 11827113afc8SEmmanuel Vadot return (0); 118344b781cfSAndrew Turner } 118444b781cfSAndrew Turner 11857113afc8SEmmanuel Vadot static int 11867113afc8SEmmanuel Vadot __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata, bool set_mode) 118744b781cfSAndrew Turner { 11887113afc8SEmmanuel Vadot int ret; 1189*94e3e7d2SAdrian Chadd unsigned int reg = 0; 11907113afc8SEmmanuel Vadot 11917113afc8SEmmanuel Vadot sx_xlock(&pdata->an_mutex); 11927113afc8SEmmanuel Vadot 119344b781cfSAndrew Turner set_bit(XGBE_LINK_INIT, &pdata->dev_state); 11949c6d6488SAndrew Turner pdata->link_check = ticks; 119544b781cfSAndrew Turner 11967113afc8SEmmanuel Vadot ret = pdata->phy_if.phy_impl.an_config(pdata); 11977113afc8SEmmanuel Vadot if (ret) { 11987113afc8SEmmanuel Vadot axgbe_error("%s: an_config fail %d\n", __func__, ret); 11997113afc8SEmmanuel Vadot goto out; 12007113afc8SEmmanuel Vadot } 12017113afc8SEmmanuel Vadot 12027113afc8SEmmanuel Vadot if (pdata->phy.autoneg != AUTONEG_ENABLE) { 12037113afc8SEmmanuel Vadot ret = xgbe_phy_config_fixed(pdata); 12047113afc8SEmmanuel Vadot if (ret || !pdata->kr_redrv) { 12057113afc8SEmmanuel Vadot if (ret) 12067113afc8SEmmanuel Vadot axgbe_error("%s: fix conf fail %d\n", __func__, ret); 12077113afc8SEmmanuel Vadot goto out; 12087113afc8SEmmanuel Vadot } 12097113afc8SEmmanuel Vadot 12107113afc8SEmmanuel Vadot axgbe_printf(2, "AN redriver support\n"); 12117113afc8SEmmanuel Vadot } else 12127113afc8SEmmanuel Vadot axgbe_printf(2, "AN PHY configuration\n"); 121344b781cfSAndrew Turner 121444b781cfSAndrew Turner /* Disable auto-negotiation interrupt */ 12159c6d6488SAndrew Turner XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, 0); 12167113afc8SEmmanuel Vadot reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK); 12177113afc8SEmmanuel Vadot axgbe_printf(2, "%s: set_mode %d AN int reg value 0x%x\n", __func__, 12187113afc8SEmmanuel Vadot set_mode, reg); 12199c6d6488SAndrew Turner 12209c6d6488SAndrew Turner /* Clear any auto-negotitation interrupts */ 12219c6d6488SAndrew Turner XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0); 122244b781cfSAndrew Turner 122344b781cfSAndrew Turner /* Start auto-negotiation in a supported mode */ 12247113afc8SEmmanuel Vadot if (set_mode) { 12257113afc8SEmmanuel Vadot /* Start auto-negotiation in a supported mode */ 12267113afc8SEmmanuel Vadot if (xgbe_use_mode(pdata, XGBE_MODE_KR)) { 122744b781cfSAndrew Turner xgbe_set_mode(pdata, XGBE_MODE_KR); 12287113afc8SEmmanuel Vadot } else if (xgbe_use_mode(pdata, XGBE_MODE_KX_2500)) { 12297113afc8SEmmanuel Vadot xgbe_set_mode(pdata, XGBE_MODE_KX_2500); 12307113afc8SEmmanuel Vadot } else if (xgbe_use_mode(pdata, XGBE_MODE_KX_1000)) { 12317113afc8SEmmanuel Vadot xgbe_set_mode(pdata, XGBE_MODE_KX_1000); 12327113afc8SEmmanuel Vadot } else if (xgbe_use_mode(pdata, XGBE_MODE_SFI)) { 12337113afc8SEmmanuel Vadot xgbe_set_mode(pdata, XGBE_MODE_SFI); 12347113afc8SEmmanuel Vadot } else if (xgbe_use_mode(pdata, XGBE_MODE_X)) { 12357113afc8SEmmanuel Vadot xgbe_set_mode(pdata, XGBE_MODE_X); 12367113afc8SEmmanuel Vadot } else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_1000)) { 12377113afc8SEmmanuel Vadot xgbe_set_mode(pdata, XGBE_MODE_SGMII_1000); 12387113afc8SEmmanuel Vadot } else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_100)) { 12397113afc8SEmmanuel Vadot xgbe_set_mode(pdata, XGBE_MODE_SGMII_100); 124044b781cfSAndrew Turner } else { 12419c6d6488SAndrew Turner XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, 0x07); 12427113afc8SEmmanuel Vadot ret = -EINVAL; 12437113afc8SEmmanuel Vadot goto out; 12447113afc8SEmmanuel Vadot } 124544b781cfSAndrew Turner } 124644b781cfSAndrew Turner 124744b781cfSAndrew Turner /* Disable and stop any in progress auto-negotiation */ 12487113afc8SEmmanuel Vadot xgbe_an_disable_all(pdata); 124944b781cfSAndrew Turner 125044b781cfSAndrew Turner /* Clear any auto-negotitation interrupts */ 12517113afc8SEmmanuel Vadot xgbe_an_clear_interrupts_all(pdata); 125244b781cfSAndrew Turner 125344b781cfSAndrew Turner pdata->an_result = XGBE_AN_READY; 125444b781cfSAndrew Turner pdata->an_state = XGBE_AN_READY; 125544b781cfSAndrew Turner pdata->kr_state = XGBE_RX_BPA; 125644b781cfSAndrew Turner pdata->kx_state = XGBE_RX_BPA; 125744b781cfSAndrew Turner 125844b781cfSAndrew Turner /* Re-enable auto-negotiation interrupt */ 12599c6d6488SAndrew Turner XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, 0x07); 12607113afc8SEmmanuel Vadot reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK); 126144b781cfSAndrew Turner 126244b781cfSAndrew Turner /* Set up advertisement registers based on current settings */ 126344b781cfSAndrew Turner xgbe_an_init(pdata); 126444b781cfSAndrew Turner 126544b781cfSAndrew Turner /* Enable and start auto-negotiation */ 12667113afc8SEmmanuel Vadot xgbe_an_restart(pdata); 126744b781cfSAndrew Turner 12687113afc8SEmmanuel Vadot out: 12697113afc8SEmmanuel Vadot if (ret) { 12707113afc8SEmmanuel Vadot axgbe_printf(0, "%s: set_mode %d AN int reg value 0x%x ret value %d\n", 12717113afc8SEmmanuel Vadot __func__, set_mode, reg, ret); 127244b781cfSAndrew Turner set_bit(XGBE_LINK_ERR, &pdata->dev_state); 12737113afc8SEmmanuel Vadot } else 127444b781cfSAndrew Turner clear_bit(XGBE_LINK_ERR, &pdata->dev_state); 127544b781cfSAndrew Turner 12769c6d6488SAndrew Turner sx_unlock(&pdata->an_mutex); 127744b781cfSAndrew Turner 12787113afc8SEmmanuel Vadot return (ret); 127944b781cfSAndrew Turner } 128044b781cfSAndrew Turner 12817113afc8SEmmanuel Vadot static int 12827113afc8SEmmanuel Vadot xgbe_phy_config_aneg(struct xgbe_prv_data *pdata) 12837113afc8SEmmanuel Vadot { 12847113afc8SEmmanuel Vadot return (__xgbe_phy_config_aneg(pdata, true)); 12857113afc8SEmmanuel Vadot } 12867113afc8SEmmanuel Vadot 12877113afc8SEmmanuel Vadot static int 12887113afc8SEmmanuel Vadot xgbe_phy_reconfig_aneg(struct xgbe_prv_data *pdata) 12897113afc8SEmmanuel Vadot { 12907113afc8SEmmanuel Vadot return (__xgbe_phy_config_aneg(pdata, false)); 12917113afc8SEmmanuel Vadot } 12927113afc8SEmmanuel Vadot 12937113afc8SEmmanuel Vadot static bool 12947113afc8SEmmanuel Vadot xgbe_phy_aneg_done(struct xgbe_prv_data *pdata) 129544b781cfSAndrew Turner { 129644b781cfSAndrew Turner return (pdata->an_result == XGBE_AN_COMPLETE); 129744b781cfSAndrew Turner } 129844b781cfSAndrew Turner 12997113afc8SEmmanuel Vadot static void 13007113afc8SEmmanuel Vadot xgbe_check_link_timeout(struct xgbe_prv_data *pdata) 130144b781cfSAndrew Turner { 130244b781cfSAndrew Turner unsigned long link_timeout; 130344b781cfSAndrew Turner 13049c6d6488SAndrew Turner link_timeout = pdata->link_check + (XGBE_LINK_TIMEOUT * hz); 13057113afc8SEmmanuel Vadot if ((int)(ticks - link_timeout) > 0) { 13067113afc8SEmmanuel Vadot axgbe_printf(2, "AN link timeout\n"); 130744b781cfSAndrew Turner xgbe_phy_config_aneg(pdata); 130844b781cfSAndrew Turner } 130944b781cfSAndrew Turner } 131044b781cfSAndrew Turner 13117113afc8SEmmanuel Vadot static enum xgbe_mode 13127113afc8SEmmanuel Vadot xgbe_phy_status_aneg(struct xgbe_prv_data *pdata) 131344b781cfSAndrew Turner { 13147113afc8SEmmanuel Vadot return (pdata->phy_if.phy_impl.an_outcome(pdata)); 131544b781cfSAndrew Turner } 131644b781cfSAndrew Turner 13177113afc8SEmmanuel Vadot static void 13187113afc8SEmmanuel Vadot xgbe_phy_status_result(struct xgbe_prv_data *pdata) 131944b781cfSAndrew Turner { 13207113afc8SEmmanuel Vadot enum xgbe_mode mode; 132144b781cfSAndrew Turner 13227113afc8SEmmanuel Vadot XGBE_ZERO_LP_ADV(&pdata->phy); 132344b781cfSAndrew Turner 132444b781cfSAndrew Turner if ((pdata->phy.autoneg != AUTONEG_ENABLE) || pdata->parallel_detect) 13257113afc8SEmmanuel Vadot mode = xgbe_cur_mode(pdata); 13267113afc8SEmmanuel Vadot else 13277113afc8SEmmanuel Vadot mode = xgbe_phy_status_aneg(pdata); 132844b781cfSAndrew Turner 13297113afc8SEmmanuel Vadot axgbe_printf(3, "%s: xgbe mode %d\n", __func__, mode); 13307113afc8SEmmanuel Vadot switch (mode) { 13317113afc8SEmmanuel Vadot case XGBE_MODE_SGMII_100: 13327113afc8SEmmanuel Vadot pdata->phy.speed = SPEED_100; 133344b781cfSAndrew Turner break; 13347113afc8SEmmanuel Vadot case XGBE_MODE_X: 13357113afc8SEmmanuel Vadot case XGBE_MODE_KX_1000: 13367113afc8SEmmanuel Vadot case XGBE_MODE_SGMII_1000: 133744b781cfSAndrew Turner pdata->phy.speed = SPEED_1000; 133844b781cfSAndrew Turner break; 13397113afc8SEmmanuel Vadot case XGBE_MODE_KX_2500: 134044b781cfSAndrew Turner pdata->phy.speed = SPEED_2500; 134144b781cfSAndrew Turner break; 13427113afc8SEmmanuel Vadot case XGBE_MODE_KR: 13437113afc8SEmmanuel Vadot case XGBE_MODE_SFI: 13447113afc8SEmmanuel Vadot pdata->phy.speed = SPEED_10000; 13457113afc8SEmmanuel Vadot break; 13467113afc8SEmmanuel Vadot case XGBE_MODE_UNKNOWN: 13477113afc8SEmmanuel Vadot default: 13487113afc8SEmmanuel Vadot axgbe_printf(1, "%s: unknown mode\n", __func__); 134944b781cfSAndrew Turner pdata->phy.speed = SPEED_UNKNOWN; 135044b781cfSAndrew Turner } 135144b781cfSAndrew Turner 13527113afc8SEmmanuel Vadot pdata->phy.duplex = DUPLEX_FULL; 13537113afc8SEmmanuel Vadot axgbe_printf(2, "%s: speed %d duplex %d\n", __func__, pdata->phy.speed, 13547113afc8SEmmanuel Vadot pdata->phy.duplex); 13557113afc8SEmmanuel Vadot 13567113afc8SEmmanuel Vadot if (xgbe_set_mode(pdata, mode) && pdata->an_again) 13577113afc8SEmmanuel Vadot xgbe_phy_reconfig_aneg(pdata); 135844b781cfSAndrew Turner } 135944b781cfSAndrew Turner 13607113afc8SEmmanuel Vadot static void 13617113afc8SEmmanuel Vadot xgbe_phy_status(struct xgbe_prv_data *pdata) 136244b781cfSAndrew Turner { 13637113afc8SEmmanuel Vadot bool link_aneg; 13647113afc8SEmmanuel Vadot int an_restart; 136544b781cfSAndrew Turner 136644b781cfSAndrew Turner if (test_bit(XGBE_LINK_ERR, &pdata->dev_state)) { 13677113afc8SEmmanuel Vadot axgbe_error("%s: LINK_ERR\n", __func__); 136844b781cfSAndrew Turner pdata->phy.link = 0; 136944b781cfSAndrew Turner goto adjust_link; 137044b781cfSAndrew Turner } 137144b781cfSAndrew Turner 137244b781cfSAndrew Turner link_aneg = (pdata->phy.autoneg == AUTONEG_ENABLE); 13737113afc8SEmmanuel Vadot axgbe_printf(3, "link_aneg - %d\n", link_aneg); 137444b781cfSAndrew Turner 137544b781cfSAndrew Turner /* Get the link status. Link status is latched low, so read 137644b781cfSAndrew Turner * once to clear and then read again to get current state 137744b781cfSAndrew Turner */ 13787113afc8SEmmanuel Vadot pdata->phy.link = pdata->phy_if.phy_impl.link_status(pdata, 13797113afc8SEmmanuel Vadot &an_restart); 13807113afc8SEmmanuel Vadot 13817113afc8SEmmanuel Vadot axgbe_printf(1, "link_status returned Link:%d an_restart:%d aneg:%d\n", 13827113afc8SEmmanuel Vadot pdata->phy.link, an_restart, link_aneg); 13837113afc8SEmmanuel Vadot 13847113afc8SEmmanuel Vadot if (an_restart) { 13857113afc8SEmmanuel Vadot xgbe_phy_config_aneg(pdata); 13867113afc8SEmmanuel Vadot return; 13877113afc8SEmmanuel Vadot } 138844b781cfSAndrew Turner 138944b781cfSAndrew Turner if (pdata->phy.link) { 13907113afc8SEmmanuel Vadot axgbe_printf(2, "Link Active\n"); 139144b781cfSAndrew Turner if (link_aneg && !xgbe_phy_aneg_done(pdata)) { 13927113afc8SEmmanuel Vadot axgbe_printf(1, "phy_link set check timeout\n"); 139344b781cfSAndrew Turner xgbe_check_link_timeout(pdata); 139444b781cfSAndrew Turner return; 139544b781cfSAndrew Turner } 139644b781cfSAndrew Turner 13977113afc8SEmmanuel Vadot axgbe_printf(2, "%s: Link write phy_status result\n", __func__); 13987113afc8SEmmanuel Vadot xgbe_phy_status_result(pdata); 139944b781cfSAndrew Turner 140044b781cfSAndrew Turner if (test_bit(XGBE_LINK_INIT, &pdata->dev_state)) 140144b781cfSAndrew Turner clear_bit(XGBE_LINK_INIT, &pdata->dev_state); 14027113afc8SEmmanuel Vadot 140344b781cfSAndrew Turner } else { 14047113afc8SEmmanuel Vadot axgbe_printf(2, "Link Deactive\n"); 140544b781cfSAndrew Turner if (test_bit(XGBE_LINK_INIT, &pdata->dev_state)) { 14067113afc8SEmmanuel Vadot axgbe_printf(1, "phy_link not set check timeout\n"); 140744b781cfSAndrew Turner xgbe_check_link_timeout(pdata); 140844b781cfSAndrew Turner 14097113afc8SEmmanuel Vadot if (link_aneg) { 14107113afc8SEmmanuel Vadot axgbe_printf(2, "link_aneg case\n"); 141144b781cfSAndrew Turner return; 141244b781cfSAndrew Turner } 14137113afc8SEmmanuel Vadot } 141444b781cfSAndrew Turner 14157113afc8SEmmanuel Vadot xgbe_phy_status_result(pdata); 14167113afc8SEmmanuel Vadot 141744b781cfSAndrew Turner } 141844b781cfSAndrew Turner 141944b781cfSAndrew Turner adjust_link: 14207113afc8SEmmanuel Vadot axgbe_printf(2, "%s: Link %d\n", __func__, pdata->phy.link); 142144b781cfSAndrew Turner xgbe_phy_adjust_link(pdata); 142244b781cfSAndrew Turner } 142344b781cfSAndrew Turner 14247113afc8SEmmanuel Vadot static void 14257113afc8SEmmanuel Vadot xgbe_phy_stop(struct xgbe_prv_data *pdata) 142644b781cfSAndrew Turner { 14277113afc8SEmmanuel Vadot axgbe_printf(2, "stopping PHY\n"); 14287113afc8SEmmanuel Vadot 14297113afc8SEmmanuel Vadot if (!pdata->phy_started) 14307113afc8SEmmanuel Vadot return; 14317113afc8SEmmanuel Vadot 14327113afc8SEmmanuel Vadot /* Indicate the PHY is down */ 14337113afc8SEmmanuel Vadot pdata->phy_started = 0; 143444b781cfSAndrew Turner 143544b781cfSAndrew Turner /* Disable auto-negotiation */ 14367113afc8SEmmanuel Vadot xgbe_an_disable_all(pdata); 143744b781cfSAndrew Turner 14387113afc8SEmmanuel Vadot pdata->phy_if.phy_impl.stop(pdata); 143944b781cfSAndrew Turner 144044b781cfSAndrew Turner pdata->phy.link = 0; 144144b781cfSAndrew Turner 144244b781cfSAndrew Turner xgbe_phy_adjust_link(pdata); 144344b781cfSAndrew Turner } 144444b781cfSAndrew Turner 14457113afc8SEmmanuel Vadot static int 14467113afc8SEmmanuel Vadot xgbe_phy_start(struct xgbe_prv_data *pdata) 144744b781cfSAndrew Turner { 144844b781cfSAndrew Turner int ret; 144944b781cfSAndrew Turner 14507113afc8SEmmanuel Vadot DBGPR("-->xgbe_phy_start\n"); 14517113afc8SEmmanuel Vadot 14527113afc8SEmmanuel Vadot ret = pdata->phy_if.phy_impl.start(pdata); 145344b781cfSAndrew Turner if (ret) { 14547113afc8SEmmanuel Vadot axgbe_error("%s: impl start ret %d\n", __func__, ret); 14557113afc8SEmmanuel Vadot return (ret); 145644b781cfSAndrew Turner } 145744b781cfSAndrew Turner 145844b781cfSAndrew Turner /* Set initial mode - call the mode setting routines 145944b781cfSAndrew Turner * directly to insure we are properly configured 146044b781cfSAndrew Turner */ 14617113afc8SEmmanuel Vadot if (xgbe_use_mode(pdata, XGBE_MODE_KR)) { 14627113afc8SEmmanuel Vadot axgbe_printf(2, "%s: KR\n", __func__); 14637113afc8SEmmanuel Vadot xgbe_kr_mode(pdata); 14647113afc8SEmmanuel Vadot } else if (xgbe_use_mode(pdata, XGBE_MODE_KX_2500)) { 14657113afc8SEmmanuel Vadot axgbe_printf(2, "%s: KX 2500\n", __func__); 14667113afc8SEmmanuel Vadot xgbe_kx_2500_mode(pdata); 14677113afc8SEmmanuel Vadot } else if (xgbe_use_mode(pdata, XGBE_MODE_KX_1000)) { 14687113afc8SEmmanuel Vadot axgbe_printf(2, "%s: KX 1000\n", __func__); 14697113afc8SEmmanuel Vadot xgbe_kx_1000_mode(pdata); 14707113afc8SEmmanuel Vadot } else if (xgbe_use_mode(pdata, XGBE_MODE_SFI)) { 14717113afc8SEmmanuel Vadot axgbe_printf(2, "%s: SFI\n", __func__); 14727113afc8SEmmanuel Vadot xgbe_sfi_mode(pdata); 14737113afc8SEmmanuel Vadot } else if (xgbe_use_mode(pdata, XGBE_MODE_X)) { 14747113afc8SEmmanuel Vadot axgbe_printf(2, "%s: X\n", __func__); 14757113afc8SEmmanuel Vadot xgbe_x_mode(pdata); 14767113afc8SEmmanuel Vadot } else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_1000)) { 14777113afc8SEmmanuel Vadot axgbe_printf(2, "%s: SGMII 1000\n", __func__); 14787113afc8SEmmanuel Vadot xgbe_sgmii_1000_mode(pdata); 14797113afc8SEmmanuel Vadot } else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_100)) { 14807113afc8SEmmanuel Vadot axgbe_printf(2, "%s: SGMII 100\n", __func__); 14817113afc8SEmmanuel Vadot xgbe_sgmii_100_mode(pdata); 148244b781cfSAndrew Turner } else { 14837113afc8SEmmanuel Vadot axgbe_error("%s: invalid mode\n", __func__); 148444b781cfSAndrew Turner ret = -EINVAL; 14857113afc8SEmmanuel Vadot goto err_stop; 148644b781cfSAndrew Turner } 148744b781cfSAndrew Turner 14887113afc8SEmmanuel Vadot /* Indicate the PHY is up and running */ 14897113afc8SEmmanuel Vadot pdata->phy_started = 1; 14907113afc8SEmmanuel Vadot 149144b781cfSAndrew Turner /* Set up advertisement registers based on current settings */ 149244b781cfSAndrew Turner xgbe_an_init(pdata); 149344b781cfSAndrew Turner 149444b781cfSAndrew Turner /* Enable auto-negotiation interrupts */ 14957113afc8SEmmanuel Vadot xgbe_an_enable_interrupts(pdata); 149644b781cfSAndrew Turner 14977113afc8SEmmanuel Vadot ret = xgbe_phy_config_aneg(pdata); 14987113afc8SEmmanuel Vadot if (ret) 14997113afc8SEmmanuel Vadot axgbe_error("%s: phy_config_aneg %d\n", __func__, ret); 150044b781cfSAndrew Turner 15017113afc8SEmmanuel Vadot return (ret); 150244b781cfSAndrew Turner 15037113afc8SEmmanuel Vadot err_stop: 15047113afc8SEmmanuel Vadot pdata->phy_if.phy_impl.stop(pdata); 15057113afc8SEmmanuel Vadot 15067113afc8SEmmanuel Vadot return (ret); 150744b781cfSAndrew Turner } 150844b781cfSAndrew Turner 15097113afc8SEmmanuel Vadot static int 15107113afc8SEmmanuel Vadot xgbe_phy_reset(struct xgbe_prv_data *pdata) 151144b781cfSAndrew Turner { 15127113afc8SEmmanuel Vadot int ret; 151344b781cfSAndrew Turner 15147113afc8SEmmanuel Vadot ret = pdata->phy_if.phy_impl.reset(pdata); 15157113afc8SEmmanuel Vadot if (ret) { 15167113afc8SEmmanuel Vadot axgbe_error("%s: impl phy reset %d\n", __func__, ret); 15177113afc8SEmmanuel Vadot return (ret); 15187113afc8SEmmanuel Vadot } 151944b781cfSAndrew Turner 152044b781cfSAndrew Turner /* Disable auto-negotiation for now */ 15217113afc8SEmmanuel Vadot xgbe_an_disable_all(pdata); 152244b781cfSAndrew Turner 152344b781cfSAndrew Turner /* Clear auto-negotiation interrupts */ 15247113afc8SEmmanuel Vadot xgbe_an_clear_interrupts_all(pdata); 152544b781cfSAndrew Turner 15267113afc8SEmmanuel Vadot return (0); 152744b781cfSAndrew Turner } 152844b781cfSAndrew Turner 15297113afc8SEmmanuel Vadot static int 15307113afc8SEmmanuel Vadot xgbe_phy_best_advertised_speed(struct xgbe_prv_data *pdata) 153144b781cfSAndrew Turner { 15327113afc8SEmmanuel Vadot 15337113afc8SEmmanuel Vadot if (XGBE_ADV(&pdata->phy, 10000baseKR_Full)) 15347113afc8SEmmanuel Vadot return (SPEED_10000); 15357113afc8SEmmanuel Vadot else if (XGBE_ADV(&pdata->phy, 10000baseT_Full)) 15367113afc8SEmmanuel Vadot return (SPEED_10000); 15377113afc8SEmmanuel Vadot else if (XGBE_ADV(&pdata->phy, 2500baseX_Full)) 15387113afc8SEmmanuel Vadot return (SPEED_2500); 15397113afc8SEmmanuel Vadot else if (XGBE_ADV(&pdata->phy, 2500baseT_Full)) 15407113afc8SEmmanuel Vadot return (SPEED_2500); 15417113afc8SEmmanuel Vadot else if (XGBE_ADV(&pdata->phy, 1000baseKX_Full)) 15427113afc8SEmmanuel Vadot return (SPEED_1000); 15437113afc8SEmmanuel Vadot else if (XGBE_ADV(&pdata->phy, 1000baseT_Full)) 15447113afc8SEmmanuel Vadot return (SPEED_1000); 15457113afc8SEmmanuel Vadot else if (XGBE_ADV(&pdata->phy, 100baseT_Full)) 15467113afc8SEmmanuel Vadot return (SPEED_100); 15477113afc8SEmmanuel Vadot 15487113afc8SEmmanuel Vadot return (SPEED_UNKNOWN); 15497113afc8SEmmanuel Vadot } 15507113afc8SEmmanuel Vadot 15517113afc8SEmmanuel Vadot static void 15527113afc8SEmmanuel Vadot xgbe_phy_exit(struct xgbe_prv_data *pdata) 15537113afc8SEmmanuel Vadot { 15547113afc8SEmmanuel Vadot pdata->phy_if.phy_impl.exit(pdata); 15557113afc8SEmmanuel Vadot } 15567113afc8SEmmanuel Vadot 15577113afc8SEmmanuel Vadot static int 15587113afc8SEmmanuel Vadot xgbe_phy_init(struct xgbe_prv_data *pdata) 15597113afc8SEmmanuel Vadot { 15607113afc8SEmmanuel Vadot int ret = 0; 15617113afc8SEmmanuel Vadot 15627113afc8SEmmanuel Vadot DBGPR("-->xgbe_phy_init\n"); 15637113afc8SEmmanuel Vadot 15649c6d6488SAndrew Turner sx_init(&pdata->an_mutex, "axgbe AN lock"); 156544b781cfSAndrew Turner pdata->mdio_mmd = MDIO_MMD_PCS; 156644b781cfSAndrew Turner 156744b781cfSAndrew Turner /* Initialize supported features */ 156844b781cfSAndrew Turner pdata->fec_ability = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, 156944b781cfSAndrew Turner MDIO_PMA_10GBR_FECABLE); 157044b781cfSAndrew Turner pdata->fec_ability &= (MDIO_PMA_10GBR_FECABLE_ABLE | 157144b781cfSAndrew Turner MDIO_PMA_10GBR_FECABLE_ERRABLE); 157244b781cfSAndrew Turner 15737113afc8SEmmanuel Vadot /* Setup the phy (including supported features) */ 15747113afc8SEmmanuel Vadot ret = pdata->phy_if.phy_impl.init(pdata); 15757113afc8SEmmanuel Vadot if (ret) 15767113afc8SEmmanuel Vadot return (ret); 15777113afc8SEmmanuel Vadot 15787113afc8SEmmanuel Vadot /* Copy supported link modes to advertising link modes */ 15797113afc8SEmmanuel Vadot XGBE_LM_COPY(&pdata->phy, advertising, &pdata->phy, supported); 158044b781cfSAndrew Turner 158144b781cfSAndrew Turner pdata->phy.address = 0; 158244b781cfSAndrew Turner 15837113afc8SEmmanuel Vadot if (XGBE_ADV(&pdata->phy, Autoneg)) { 158444b781cfSAndrew Turner pdata->phy.autoneg = AUTONEG_ENABLE; 158544b781cfSAndrew Turner pdata->phy.speed = SPEED_UNKNOWN; 158644b781cfSAndrew Turner pdata->phy.duplex = DUPLEX_UNKNOWN; 15877113afc8SEmmanuel Vadot } else { 15887113afc8SEmmanuel Vadot pdata->phy.autoneg = AUTONEG_DISABLE; 15897113afc8SEmmanuel Vadot pdata->phy.speed = xgbe_phy_best_advertised_speed(pdata); 15907113afc8SEmmanuel Vadot pdata->phy.duplex = DUPLEX_FULL; 15917113afc8SEmmanuel Vadot } 159244b781cfSAndrew Turner 159344b781cfSAndrew Turner pdata->phy.link = 0; 159444b781cfSAndrew Turner 159544b781cfSAndrew Turner pdata->phy.pause_autoneg = pdata->pause_autoneg; 159644b781cfSAndrew Turner pdata->phy.tx_pause = pdata->tx_pause; 159744b781cfSAndrew Turner pdata->phy.rx_pause = pdata->rx_pause; 159844b781cfSAndrew Turner 159944b781cfSAndrew Turner /* Fix up Flow Control advertising */ 16007113afc8SEmmanuel Vadot XGBE_CLR_ADV(&pdata->phy, Pause); 16017113afc8SEmmanuel Vadot XGBE_CLR_ADV(&pdata->phy, Asym_Pause); 160244b781cfSAndrew Turner 160344b781cfSAndrew Turner if (pdata->rx_pause) { 16047113afc8SEmmanuel Vadot XGBE_SET_ADV(&pdata->phy, Pause); 16057113afc8SEmmanuel Vadot XGBE_SET_ADV(&pdata->phy, Asym_Pause); 160644b781cfSAndrew Turner } 160744b781cfSAndrew Turner 16087113afc8SEmmanuel Vadot if (pdata->tx_pause) { 16097113afc8SEmmanuel Vadot if (XGBE_ADV(&pdata->phy, Asym_Pause)) 16107113afc8SEmmanuel Vadot XGBE_CLR_ADV(&pdata->phy, Asym_Pause); 16117113afc8SEmmanuel Vadot else 16127113afc8SEmmanuel Vadot XGBE_SET_ADV(&pdata->phy, Asym_Pause); 161344b781cfSAndrew Turner } 161444b781cfSAndrew Turner 16157113afc8SEmmanuel Vadot return (0); 16167113afc8SEmmanuel Vadot } 16177113afc8SEmmanuel Vadot 16187113afc8SEmmanuel Vadot void 16197113afc8SEmmanuel Vadot xgbe_init_function_ptrs_phy(struct xgbe_phy_if *phy_if) 162044b781cfSAndrew Turner { 162144b781cfSAndrew Turner phy_if->phy_init = xgbe_phy_init; 16227113afc8SEmmanuel Vadot phy_if->phy_exit = xgbe_phy_exit; 162344b781cfSAndrew Turner 162444b781cfSAndrew Turner phy_if->phy_reset = xgbe_phy_reset; 162544b781cfSAndrew Turner phy_if->phy_start = xgbe_phy_start; 162644b781cfSAndrew Turner phy_if->phy_stop = xgbe_phy_stop; 162744b781cfSAndrew Turner 162844b781cfSAndrew Turner phy_if->phy_status = xgbe_phy_status; 162944b781cfSAndrew Turner phy_if->phy_config_aneg = xgbe_phy_config_aneg; 16307113afc8SEmmanuel Vadot 16317113afc8SEmmanuel Vadot phy_if->phy_valid_speed = xgbe_phy_valid_speed; 16327113afc8SEmmanuel Vadot 16337113afc8SEmmanuel Vadot phy_if->an_isr = xgbe_an_combined_isr; 163444b781cfSAndrew Turner } 1635