18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * AMD 10Gb Ethernet driver 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This file is available to you under your choice of the following two 58c2ecf20Sopenharmony_ci * licenses: 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * License 1: GPLv2 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Copyright (c) 2014-2016 Advanced Micro Devices, Inc. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * This file is free software; you may copy, redistribute and/or modify 128c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License as published by 138c2ecf20Sopenharmony_ci * the Free Software Foundation, either version 2 of the License, or (at 148c2ecf20Sopenharmony_ci * your option) any later version. 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * This file is distributed in the hope that it will be useful, but 178c2ecf20Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of 188c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 198c2ecf20Sopenharmony_ci * General Public License for more details. 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * You should have received a copy of the GNU General Public License 228c2ecf20Sopenharmony_ci * along with this program. If not, see <http://www.gnu.org/licenses/>. 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * This file incorporates work covered by the following copyright and 258c2ecf20Sopenharmony_ci * permission notice: 268c2ecf20Sopenharmony_ci * The Synopsys DWC ETHER XGMAC Software Driver and documentation 278c2ecf20Sopenharmony_ci * (hereinafter "Software") is an unsupported proprietary work of Synopsys, 288c2ecf20Sopenharmony_ci * Inc. unless otherwise expressly agreed to in writing between Synopsys 298c2ecf20Sopenharmony_ci * and you. 308c2ecf20Sopenharmony_ci * 318c2ecf20Sopenharmony_ci * The Software IS NOT an item of Licensed Software or Licensed Product 328c2ecf20Sopenharmony_ci * under any End User Software License Agreement or Agreement for Licensed 338c2ecf20Sopenharmony_ci * Product with Synopsys or any supplement thereto. Permission is hereby 348c2ecf20Sopenharmony_ci * granted, free of charge, to any person obtaining a copy of this software 358c2ecf20Sopenharmony_ci * annotated with this license and the Software, to deal in the Software 368c2ecf20Sopenharmony_ci * without restriction, including without limitation the rights to use, 378c2ecf20Sopenharmony_ci * copy, modify, merge, publish, distribute, sublicense, and/or sell copies 388c2ecf20Sopenharmony_ci * of the Software, and to permit persons to whom the Software is furnished 398c2ecf20Sopenharmony_ci * to do so, subject to the following conditions: 408c2ecf20Sopenharmony_ci * 418c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice shall be included 428c2ecf20Sopenharmony_ci * in all copies or substantial portions of the Software. 438c2ecf20Sopenharmony_ci * 448c2ecf20Sopenharmony_ci * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" 458c2ecf20Sopenharmony_ci * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 468c2ecf20Sopenharmony_ci * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 478c2ecf20Sopenharmony_ci * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 488c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 498c2ecf20Sopenharmony_ci * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 508c2ecf20Sopenharmony_ci * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 518c2ecf20Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 528c2ecf20Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 538c2ecf20Sopenharmony_ci * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 548c2ecf20Sopenharmony_ci * THE POSSIBILITY OF SUCH DAMAGE. 558c2ecf20Sopenharmony_ci * 568c2ecf20Sopenharmony_ci * 578c2ecf20Sopenharmony_ci * License 2: Modified BSD 588c2ecf20Sopenharmony_ci * 598c2ecf20Sopenharmony_ci * Copyright (c) 2014-2016 Advanced Micro Devices, Inc. 608c2ecf20Sopenharmony_ci * All rights reserved. 618c2ecf20Sopenharmony_ci * 628c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 638c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions are met: 648c2ecf20Sopenharmony_ci * * Redistributions of source code must retain the above copyright 658c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 668c2ecf20Sopenharmony_ci * * Redistributions in binary form must reproduce the above copyright 678c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer in the 688c2ecf20Sopenharmony_ci * documentation and/or other materials provided with the distribution. 698c2ecf20Sopenharmony_ci * * Neither the name of Advanced Micro Devices, Inc. nor the 708c2ecf20Sopenharmony_ci * names of its contributors may be used to endorse or promote products 718c2ecf20Sopenharmony_ci * derived from this software without specific prior written permission. 728c2ecf20Sopenharmony_ci * 738c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 748c2ecf20Sopenharmony_ci * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 758c2ecf20Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 768c2ecf20Sopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY 778c2ecf20Sopenharmony_ci * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 788c2ecf20Sopenharmony_ci * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 798c2ecf20Sopenharmony_ci * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 808c2ecf20Sopenharmony_ci * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 818c2ecf20Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 828c2ecf20Sopenharmony_ci * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 838c2ecf20Sopenharmony_ci * 848c2ecf20Sopenharmony_ci * This file incorporates work covered by the following copyright and 858c2ecf20Sopenharmony_ci * permission notice: 868c2ecf20Sopenharmony_ci * The Synopsys DWC ETHER XGMAC Software Driver and documentation 878c2ecf20Sopenharmony_ci * (hereinafter "Software") is an unsupported proprietary work of Synopsys, 888c2ecf20Sopenharmony_ci * Inc. unless otherwise expressly agreed to in writing between Synopsys 898c2ecf20Sopenharmony_ci * and you. 908c2ecf20Sopenharmony_ci * 918c2ecf20Sopenharmony_ci * The Software IS NOT an item of Licensed Software or Licensed Product 928c2ecf20Sopenharmony_ci * under any End User Software License Agreement or Agreement for Licensed 938c2ecf20Sopenharmony_ci * Product with Synopsys or any supplement thereto. Permission is hereby 948c2ecf20Sopenharmony_ci * granted, free of charge, to any person obtaining a copy of this software 958c2ecf20Sopenharmony_ci * annotated with this license and the Software, to deal in the Software 968c2ecf20Sopenharmony_ci * without restriction, including without limitation the rights to use, 978c2ecf20Sopenharmony_ci * copy, modify, merge, publish, distribute, sublicense, and/or sell copies 988c2ecf20Sopenharmony_ci * of the Software, and to permit persons to whom the Software is furnished 998c2ecf20Sopenharmony_ci * to do so, subject to the following conditions: 1008c2ecf20Sopenharmony_ci * 1018c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice shall be included 1028c2ecf20Sopenharmony_ci * in all copies or substantial portions of the Software. 1038c2ecf20Sopenharmony_ci * 1048c2ecf20Sopenharmony_ci * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" 1058c2ecf20Sopenharmony_ci * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 1068c2ecf20Sopenharmony_ci * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 1078c2ecf20Sopenharmony_ci * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 1088c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 1098c2ecf20Sopenharmony_ci * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 1108c2ecf20Sopenharmony_ci * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 1118c2ecf20Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 1128c2ecf20Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 1138c2ecf20Sopenharmony_ci * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 1148c2ecf20Sopenharmony_ci * THE POSSIBILITY OF SUCH DAMAGE. 1158c2ecf20Sopenharmony_ci */ 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 1188c2ecf20Sopenharmony_ci#include <linux/module.h> 1198c2ecf20Sopenharmony_ci#include <linux/kmod.h> 1208c2ecf20Sopenharmony_ci#include <linux/mdio.h> 1218c2ecf20Sopenharmony_ci#include <linux/phy.h> 1228c2ecf20Sopenharmony_ci#include <linux/of.h> 1238c2ecf20Sopenharmony_ci#include <linux/bitops.h> 1248c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci#include "xgbe.h" 1278c2ecf20Sopenharmony_ci#include "xgbe-common.h" 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic int xgbe_phy_module_eeprom(struct xgbe_prv_data *pdata, 1308c2ecf20Sopenharmony_ci struct ethtool_eeprom *eeprom, u8 *data) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci if (!pdata->phy_if.phy_impl.module_eeprom) 1338c2ecf20Sopenharmony_ci return -ENXIO; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci return pdata->phy_if.phy_impl.module_eeprom(pdata, eeprom, data); 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic int xgbe_phy_module_info(struct xgbe_prv_data *pdata, 1398c2ecf20Sopenharmony_ci struct ethtool_modinfo *modinfo) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci if (!pdata->phy_if.phy_impl.module_info) 1428c2ecf20Sopenharmony_ci return -ENXIO; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci return pdata->phy_if.phy_impl.module_info(pdata, modinfo); 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic void xgbe_an37_clear_interrupts(struct xgbe_prv_data *pdata) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci int reg; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT); 1528c2ecf20Sopenharmony_ci reg &= ~XGBE_AN_CL37_INT_MASK; 1538c2ecf20Sopenharmony_ci XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT, reg); 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic void xgbe_an37_disable_interrupts(struct xgbe_prv_data *pdata) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci int reg; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL); 1618c2ecf20Sopenharmony_ci reg &= ~XGBE_AN_CL37_INT_MASK; 1628c2ecf20Sopenharmony_ci XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL, reg); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL); 1658c2ecf20Sopenharmony_ci reg &= ~XGBE_PCS_CL37_BP; 1668c2ecf20Sopenharmony_ci XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL, reg); 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic void xgbe_an37_enable_interrupts(struct xgbe_prv_data *pdata) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci int reg; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL); 1748c2ecf20Sopenharmony_ci reg |= XGBE_PCS_CL37_BP; 1758c2ecf20Sopenharmony_ci XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL, reg); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL); 1788c2ecf20Sopenharmony_ci reg |= XGBE_AN_CL37_INT_MASK; 1798c2ecf20Sopenharmony_ci XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL, reg); 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_cistatic void xgbe_an73_clear_interrupts(struct xgbe_prv_data *pdata) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0); 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cistatic void xgbe_an73_disable_interrupts(struct xgbe_prv_data *pdata) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, 0); 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistatic void xgbe_an73_enable_interrupts(struct xgbe_prv_data *pdata) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, XGBE_AN_CL73_INT_MASK); 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistatic void xgbe_an_enable_interrupts(struct xgbe_prv_data *pdata) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci switch (pdata->an_mode) { 2008c2ecf20Sopenharmony_ci case XGBE_AN_MODE_CL73: 2018c2ecf20Sopenharmony_ci case XGBE_AN_MODE_CL73_REDRV: 2028c2ecf20Sopenharmony_ci xgbe_an73_enable_interrupts(pdata); 2038c2ecf20Sopenharmony_ci break; 2048c2ecf20Sopenharmony_ci case XGBE_AN_MODE_CL37: 2058c2ecf20Sopenharmony_ci case XGBE_AN_MODE_CL37_SGMII: 2068c2ecf20Sopenharmony_ci xgbe_an37_enable_interrupts(pdata); 2078c2ecf20Sopenharmony_ci break; 2088c2ecf20Sopenharmony_ci default: 2098c2ecf20Sopenharmony_ci break; 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_cistatic void xgbe_an_clear_interrupts_all(struct xgbe_prv_data *pdata) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci xgbe_an73_clear_interrupts(pdata); 2168c2ecf20Sopenharmony_ci xgbe_an37_clear_interrupts(pdata); 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_cistatic void xgbe_kr_mode(struct xgbe_prv_data *pdata) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci /* Set MAC to 10G speed */ 2228c2ecf20Sopenharmony_ci pdata->hw_if.set_speed(pdata, SPEED_10000); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci /* Call PHY implementation support to complete rate change */ 2258c2ecf20Sopenharmony_ci pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_KR); 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistatic void xgbe_kx_2500_mode(struct xgbe_prv_data *pdata) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci /* Set MAC to 2.5G speed */ 2318c2ecf20Sopenharmony_ci pdata->hw_if.set_speed(pdata, SPEED_2500); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci /* Call PHY implementation support to complete rate change */ 2348c2ecf20Sopenharmony_ci pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_KX_2500); 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cistatic void xgbe_kx_1000_mode(struct xgbe_prv_data *pdata) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci /* Set MAC to 1G speed */ 2408c2ecf20Sopenharmony_ci pdata->hw_if.set_speed(pdata, SPEED_1000); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci /* Call PHY implementation support to complete rate change */ 2438c2ecf20Sopenharmony_ci pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_KX_1000); 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistatic void xgbe_sfi_mode(struct xgbe_prv_data *pdata) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci /* If a KR re-driver is present, change to KR mode instead */ 2498c2ecf20Sopenharmony_ci if (pdata->kr_redrv) 2508c2ecf20Sopenharmony_ci return xgbe_kr_mode(pdata); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci /* Set MAC to 10G speed */ 2538c2ecf20Sopenharmony_ci pdata->hw_if.set_speed(pdata, SPEED_10000); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci /* Call PHY implementation support to complete rate change */ 2568c2ecf20Sopenharmony_ci pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_SFI); 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic void xgbe_x_mode(struct xgbe_prv_data *pdata) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci /* Set MAC to 1G speed */ 2628c2ecf20Sopenharmony_ci pdata->hw_if.set_speed(pdata, SPEED_1000); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci /* Call PHY implementation support to complete rate change */ 2658c2ecf20Sopenharmony_ci pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_X); 2668c2ecf20Sopenharmony_ci} 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_cistatic void xgbe_sgmii_1000_mode(struct xgbe_prv_data *pdata) 2698c2ecf20Sopenharmony_ci{ 2708c2ecf20Sopenharmony_ci /* Set MAC to 1G speed */ 2718c2ecf20Sopenharmony_ci pdata->hw_if.set_speed(pdata, SPEED_1000); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci /* Call PHY implementation support to complete rate change */ 2748c2ecf20Sopenharmony_ci pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_SGMII_1000); 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cistatic void xgbe_sgmii_100_mode(struct xgbe_prv_data *pdata) 2788c2ecf20Sopenharmony_ci{ 2798c2ecf20Sopenharmony_ci /* Set MAC to 1G speed */ 2808c2ecf20Sopenharmony_ci pdata->hw_if.set_speed(pdata, SPEED_1000); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci /* Call PHY implementation support to complete rate change */ 2838c2ecf20Sopenharmony_ci pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_SGMII_100); 2848c2ecf20Sopenharmony_ci} 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_cistatic enum xgbe_mode xgbe_cur_mode(struct xgbe_prv_data *pdata) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci return pdata->phy_if.phy_impl.cur_mode(pdata); 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistatic bool xgbe_in_kr_mode(struct xgbe_prv_data *pdata) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci return (xgbe_cur_mode(pdata) == XGBE_MODE_KR); 2948c2ecf20Sopenharmony_ci} 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_cistatic void xgbe_change_mode(struct xgbe_prv_data *pdata, 2978c2ecf20Sopenharmony_ci enum xgbe_mode mode) 2988c2ecf20Sopenharmony_ci{ 2998c2ecf20Sopenharmony_ci switch (mode) { 3008c2ecf20Sopenharmony_ci case XGBE_MODE_KX_1000: 3018c2ecf20Sopenharmony_ci xgbe_kx_1000_mode(pdata); 3028c2ecf20Sopenharmony_ci break; 3038c2ecf20Sopenharmony_ci case XGBE_MODE_KX_2500: 3048c2ecf20Sopenharmony_ci xgbe_kx_2500_mode(pdata); 3058c2ecf20Sopenharmony_ci break; 3068c2ecf20Sopenharmony_ci case XGBE_MODE_KR: 3078c2ecf20Sopenharmony_ci xgbe_kr_mode(pdata); 3088c2ecf20Sopenharmony_ci break; 3098c2ecf20Sopenharmony_ci case XGBE_MODE_SGMII_100: 3108c2ecf20Sopenharmony_ci xgbe_sgmii_100_mode(pdata); 3118c2ecf20Sopenharmony_ci break; 3128c2ecf20Sopenharmony_ci case XGBE_MODE_SGMII_1000: 3138c2ecf20Sopenharmony_ci xgbe_sgmii_1000_mode(pdata); 3148c2ecf20Sopenharmony_ci break; 3158c2ecf20Sopenharmony_ci case XGBE_MODE_X: 3168c2ecf20Sopenharmony_ci xgbe_x_mode(pdata); 3178c2ecf20Sopenharmony_ci break; 3188c2ecf20Sopenharmony_ci case XGBE_MODE_SFI: 3198c2ecf20Sopenharmony_ci xgbe_sfi_mode(pdata); 3208c2ecf20Sopenharmony_ci break; 3218c2ecf20Sopenharmony_ci case XGBE_MODE_UNKNOWN: 3228c2ecf20Sopenharmony_ci break; 3238c2ecf20Sopenharmony_ci default: 3248c2ecf20Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, 3258c2ecf20Sopenharmony_ci "invalid operation mode requested (%u)\n", mode); 3268c2ecf20Sopenharmony_ci } 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cistatic void xgbe_switch_mode(struct xgbe_prv_data *pdata) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci xgbe_change_mode(pdata, pdata->phy_if.phy_impl.switch_mode(pdata)); 3328c2ecf20Sopenharmony_ci} 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_cistatic bool xgbe_set_mode(struct xgbe_prv_data *pdata, 3358c2ecf20Sopenharmony_ci enum xgbe_mode mode) 3368c2ecf20Sopenharmony_ci{ 3378c2ecf20Sopenharmony_ci if (mode == xgbe_cur_mode(pdata)) 3388c2ecf20Sopenharmony_ci return false; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci xgbe_change_mode(pdata, mode); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci return true; 3438c2ecf20Sopenharmony_ci} 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_cistatic bool xgbe_use_mode(struct xgbe_prv_data *pdata, 3468c2ecf20Sopenharmony_ci enum xgbe_mode mode) 3478c2ecf20Sopenharmony_ci{ 3488c2ecf20Sopenharmony_ci return pdata->phy_if.phy_impl.use_mode(pdata, mode); 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_cistatic void xgbe_an37_set(struct xgbe_prv_data *pdata, bool enable, 3528c2ecf20Sopenharmony_ci bool restart) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci unsigned int reg; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_CTRL1); 3578c2ecf20Sopenharmony_ci reg &= ~MDIO_VEND2_CTRL1_AN_ENABLE; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci if (enable) 3608c2ecf20Sopenharmony_ci reg |= MDIO_VEND2_CTRL1_AN_ENABLE; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci if (restart) 3638c2ecf20Sopenharmony_ci reg |= MDIO_VEND2_CTRL1_AN_RESTART; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_CTRL1, reg); 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_cistatic void xgbe_an37_restart(struct xgbe_prv_data *pdata) 3698c2ecf20Sopenharmony_ci{ 3708c2ecf20Sopenharmony_ci xgbe_an37_enable_interrupts(pdata); 3718c2ecf20Sopenharmony_ci xgbe_an37_set(pdata, true, true); 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, "CL37 AN enabled/restarted\n"); 3748c2ecf20Sopenharmony_ci} 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_cistatic void xgbe_an37_disable(struct xgbe_prv_data *pdata) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci xgbe_an37_set(pdata, false, false); 3798c2ecf20Sopenharmony_ci xgbe_an37_disable_interrupts(pdata); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, "CL37 AN disabled\n"); 3828c2ecf20Sopenharmony_ci} 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_cistatic void xgbe_an73_set(struct xgbe_prv_data *pdata, bool enable, 3858c2ecf20Sopenharmony_ci bool restart) 3868c2ecf20Sopenharmony_ci{ 3878c2ecf20Sopenharmony_ci unsigned int reg; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci /* Disable KR training for now */ 3908c2ecf20Sopenharmony_ci reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL); 3918c2ecf20Sopenharmony_ci reg &= ~XGBE_KR_TRAINING_ENABLE; 3928c2ecf20Sopenharmony_ci XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, reg); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci /* Update AN settings */ 3958c2ecf20Sopenharmony_ci reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_CTRL1); 3968c2ecf20Sopenharmony_ci reg &= ~MDIO_AN_CTRL1_ENABLE; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci if (enable) 3998c2ecf20Sopenharmony_ci reg |= MDIO_AN_CTRL1_ENABLE; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci if (restart) 4028c2ecf20Sopenharmony_ci reg |= MDIO_AN_CTRL1_RESTART; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_CTRL1, reg); 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_cistatic void xgbe_an73_restart(struct xgbe_prv_data *pdata) 4088c2ecf20Sopenharmony_ci{ 4098c2ecf20Sopenharmony_ci xgbe_an73_enable_interrupts(pdata); 4108c2ecf20Sopenharmony_ci xgbe_an73_set(pdata, true, true); 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, "CL73 AN enabled/restarted\n"); 4138c2ecf20Sopenharmony_ci} 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_cistatic void xgbe_an73_disable(struct xgbe_prv_data *pdata) 4168c2ecf20Sopenharmony_ci{ 4178c2ecf20Sopenharmony_ci xgbe_an73_set(pdata, false, false); 4188c2ecf20Sopenharmony_ci xgbe_an73_disable_interrupts(pdata); 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci pdata->an_start = 0; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, "CL73 AN disabled\n"); 4238c2ecf20Sopenharmony_ci} 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_cistatic void xgbe_an_restart(struct xgbe_prv_data *pdata) 4268c2ecf20Sopenharmony_ci{ 4278c2ecf20Sopenharmony_ci if (pdata->phy_if.phy_impl.an_pre) 4288c2ecf20Sopenharmony_ci pdata->phy_if.phy_impl.an_pre(pdata); 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci switch (pdata->an_mode) { 4318c2ecf20Sopenharmony_ci case XGBE_AN_MODE_CL73: 4328c2ecf20Sopenharmony_ci case XGBE_AN_MODE_CL73_REDRV: 4338c2ecf20Sopenharmony_ci xgbe_an73_restart(pdata); 4348c2ecf20Sopenharmony_ci break; 4358c2ecf20Sopenharmony_ci case XGBE_AN_MODE_CL37: 4368c2ecf20Sopenharmony_ci case XGBE_AN_MODE_CL37_SGMII: 4378c2ecf20Sopenharmony_ci xgbe_an37_restart(pdata); 4388c2ecf20Sopenharmony_ci break; 4398c2ecf20Sopenharmony_ci default: 4408c2ecf20Sopenharmony_ci break; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci} 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_cistatic void xgbe_an_disable(struct xgbe_prv_data *pdata) 4458c2ecf20Sopenharmony_ci{ 4468c2ecf20Sopenharmony_ci if (pdata->phy_if.phy_impl.an_post) 4478c2ecf20Sopenharmony_ci pdata->phy_if.phy_impl.an_post(pdata); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci switch (pdata->an_mode) { 4508c2ecf20Sopenharmony_ci case XGBE_AN_MODE_CL73: 4518c2ecf20Sopenharmony_ci case XGBE_AN_MODE_CL73_REDRV: 4528c2ecf20Sopenharmony_ci xgbe_an73_disable(pdata); 4538c2ecf20Sopenharmony_ci break; 4548c2ecf20Sopenharmony_ci case XGBE_AN_MODE_CL37: 4558c2ecf20Sopenharmony_ci case XGBE_AN_MODE_CL37_SGMII: 4568c2ecf20Sopenharmony_ci xgbe_an37_disable(pdata); 4578c2ecf20Sopenharmony_ci break; 4588c2ecf20Sopenharmony_ci default: 4598c2ecf20Sopenharmony_ci break; 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci} 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_cistatic void xgbe_an_disable_all(struct xgbe_prv_data *pdata) 4648c2ecf20Sopenharmony_ci{ 4658c2ecf20Sopenharmony_ci xgbe_an73_disable(pdata); 4668c2ecf20Sopenharmony_ci xgbe_an37_disable(pdata); 4678c2ecf20Sopenharmony_ci} 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_cistatic enum xgbe_an xgbe_an73_tx_training(struct xgbe_prv_data *pdata, 4708c2ecf20Sopenharmony_ci enum xgbe_rx *state) 4718c2ecf20Sopenharmony_ci{ 4728c2ecf20Sopenharmony_ci unsigned int ad_reg, lp_reg, reg; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci *state = XGBE_RX_COMPLETE; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci /* If we're not in KR mode then we're done */ 4778c2ecf20Sopenharmony_ci if (!xgbe_in_kr_mode(pdata)) 4788c2ecf20Sopenharmony_ci return XGBE_AN_PAGE_RECEIVED; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci /* Enable/Disable FEC */ 4818c2ecf20Sopenharmony_ci ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); 4828c2ecf20Sopenharmony_ci lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FECCTRL); 4858c2ecf20Sopenharmony_ci reg &= ~(MDIO_PMA_10GBR_FECABLE_ABLE | MDIO_PMA_10GBR_FECABLE_ERRABLE); 4868c2ecf20Sopenharmony_ci if ((ad_reg & 0xc000) && (lp_reg & 0xc000)) 4878c2ecf20Sopenharmony_ci reg |= pdata->fec_ability; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FECCTRL, reg); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci /* Start KR training */ 4928c2ecf20Sopenharmony_ci if (pdata->phy_if.phy_impl.kr_training_pre) 4938c2ecf20Sopenharmony_ci pdata->phy_if.phy_impl.kr_training_pre(pdata); 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL); 4968c2ecf20Sopenharmony_ci reg |= XGBE_KR_TRAINING_ENABLE; 4978c2ecf20Sopenharmony_ci reg |= XGBE_KR_TRAINING_START; 4988c2ecf20Sopenharmony_ci XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, reg); 4998c2ecf20Sopenharmony_ci pdata->kr_start_time = jiffies; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, 5028c2ecf20Sopenharmony_ci "KR training initiated\n"); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci if (pdata->phy_if.phy_impl.kr_training_post) 5058c2ecf20Sopenharmony_ci pdata->phy_if.phy_impl.kr_training_post(pdata); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci return XGBE_AN_PAGE_RECEIVED; 5088c2ecf20Sopenharmony_ci} 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_cistatic enum xgbe_an xgbe_an73_tx_xnp(struct xgbe_prv_data *pdata, 5118c2ecf20Sopenharmony_ci enum xgbe_rx *state) 5128c2ecf20Sopenharmony_ci{ 5138c2ecf20Sopenharmony_ci u16 msg; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci *state = XGBE_RX_XNP; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci msg = XGBE_XNP_MCF_NULL_MESSAGE; 5188c2ecf20Sopenharmony_ci msg |= XGBE_XNP_MP_FORMATTED; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_XNP + 2, 0); 5218c2ecf20Sopenharmony_ci XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_XNP + 1, 0); 5228c2ecf20Sopenharmony_ci XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_XNP, msg); 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci return XGBE_AN_PAGE_RECEIVED; 5258c2ecf20Sopenharmony_ci} 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_cistatic enum xgbe_an xgbe_an73_rx_bpa(struct xgbe_prv_data *pdata, 5288c2ecf20Sopenharmony_ci enum xgbe_rx *state) 5298c2ecf20Sopenharmony_ci{ 5308c2ecf20Sopenharmony_ci unsigned int link_support; 5318c2ecf20Sopenharmony_ci unsigned int reg, ad_reg, lp_reg; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci /* Read Base Ability register 2 first */ 5348c2ecf20Sopenharmony_ci reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1); 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci /* Check for a supported mode, otherwise restart in a different one */ 5378c2ecf20Sopenharmony_ci link_support = xgbe_in_kr_mode(pdata) ? 0x80 : 0x20; 5388c2ecf20Sopenharmony_ci if (!(reg & link_support)) 5398c2ecf20Sopenharmony_ci return XGBE_AN_INCOMPAT_LINK; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci /* Check Extended Next Page support */ 5428c2ecf20Sopenharmony_ci ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE); 5438c2ecf20Sopenharmony_ci lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci return ((ad_reg & XGBE_XNP_NP_EXCHANGE) || 5468c2ecf20Sopenharmony_ci (lp_reg & XGBE_XNP_NP_EXCHANGE)) 5478c2ecf20Sopenharmony_ci ? xgbe_an73_tx_xnp(pdata, state) 5488c2ecf20Sopenharmony_ci : xgbe_an73_tx_training(pdata, state); 5498c2ecf20Sopenharmony_ci} 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_cistatic enum xgbe_an xgbe_an73_rx_xnp(struct xgbe_prv_data *pdata, 5528c2ecf20Sopenharmony_ci enum xgbe_rx *state) 5538c2ecf20Sopenharmony_ci{ 5548c2ecf20Sopenharmony_ci unsigned int ad_reg, lp_reg; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci /* Check Extended Next Page support */ 5578c2ecf20Sopenharmony_ci ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_XNP); 5588c2ecf20Sopenharmony_ci lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPX); 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci return ((ad_reg & XGBE_XNP_NP_EXCHANGE) || 5618c2ecf20Sopenharmony_ci (lp_reg & XGBE_XNP_NP_EXCHANGE)) 5628c2ecf20Sopenharmony_ci ? xgbe_an73_tx_xnp(pdata, state) 5638c2ecf20Sopenharmony_ci : xgbe_an73_tx_training(pdata, state); 5648c2ecf20Sopenharmony_ci} 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_cistatic enum xgbe_an xgbe_an73_page_received(struct xgbe_prv_data *pdata) 5678c2ecf20Sopenharmony_ci{ 5688c2ecf20Sopenharmony_ci enum xgbe_rx *state; 5698c2ecf20Sopenharmony_ci unsigned long an_timeout; 5708c2ecf20Sopenharmony_ci enum xgbe_an ret; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci if (!pdata->an_start) { 5738c2ecf20Sopenharmony_ci pdata->an_start = jiffies; 5748c2ecf20Sopenharmony_ci } else { 5758c2ecf20Sopenharmony_ci an_timeout = pdata->an_start + 5768c2ecf20Sopenharmony_ci msecs_to_jiffies(XGBE_AN_MS_TIMEOUT); 5778c2ecf20Sopenharmony_ci if (time_after(jiffies, an_timeout)) { 5788c2ecf20Sopenharmony_ci /* Auto-negotiation timed out, reset state */ 5798c2ecf20Sopenharmony_ci pdata->kr_state = XGBE_RX_BPA; 5808c2ecf20Sopenharmony_ci pdata->kx_state = XGBE_RX_BPA; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci pdata->an_start = jiffies; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, 5858c2ecf20Sopenharmony_ci "CL73 AN timed out, resetting state\n"); 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci } 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci state = xgbe_in_kr_mode(pdata) ? &pdata->kr_state 5908c2ecf20Sopenharmony_ci : &pdata->kx_state; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci switch (*state) { 5938c2ecf20Sopenharmony_ci case XGBE_RX_BPA: 5948c2ecf20Sopenharmony_ci ret = xgbe_an73_rx_bpa(pdata, state); 5958c2ecf20Sopenharmony_ci break; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci case XGBE_RX_XNP: 5988c2ecf20Sopenharmony_ci ret = xgbe_an73_rx_xnp(pdata, state); 5998c2ecf20Sopenharmony_ci break; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci default: 6028c2ecf20Sopenharmony_ci ret = XGBE_AN_ERROR; 6038c2ecf20Sopenharmony_ci } 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci return ret; 6068c2ecf20Sopenharmony_ci} 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_cistatic enum xgbe_an xgbe_an73_incompat_link(struct xgbe_prv_data *pdata) 6098c2ecf20Sopenharmony_ci{ 6108c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *lks = &pdata->phy.lks; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci /* Be sure we aren't looping trying to negotiate */ 6138c2ecf20Sopenharmony_ci if (xgbe_in_kr_mode(pdata)) { 6148c2ecf20Sopenharmony_ci pdata->kr_state = XGBE_RX_ERROR; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci if (!XGBE_ADV(lks, 1000baseKX_Full) && 6178c2ecf20Sopenharmony_ci !XGBE_ADV(lks, 2500baseX_Full)) 6188c2ecf20Sopenharmony_ci return XGBE_AN_NO_LINK; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci if (pdata->kx_state != XGBE_RX_BPA) 6218c2ecf20Sopenharmony_ci return XGBE_AN_NO_LINK; 6228c2ecf20Sopenharmony_ci } else { 6238c2ecf20Sopenharmony_ci pdata->kx_state = XGBE_RX_ERROR; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci if (!XGBE_ADV(lks, 10000baseKR_Full)) 6268c2ecf20Sopenharmony_ci return XGBE_AN_NO_LINK; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci if (pdata->kr_state != XGBE_RX_BPA) 6298c2ecf20Sopenharmony_ci return XGBE_AN_NO_LINK; 6308c2ecf20Sopenharmony_ci } 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci xgbe_an_disable(pdata); 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci xgbe_switch_mode(pdata); 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci pdata->an_result = XGBE_AN_READY; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci xgbe_an_restart(pdata); 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci return XGBE_AN_INCOMPAT_LINK; 6418c2ecf20Sopenharmony_ci} 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_cistatic void xgbe_an37_isr(struct xgbe_prv_data *pdata) 6448c2ecf20Sopenharmony_ci{ 6458c2ecf20Sopenharmony_ci unsigned int reg; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci /* Disable AN interrupts */ 6488c2ecf20Sopenharmony_ci xgbe_an37_disable_interrupts(pdata); 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci /* Save the interrupt(s) that fired */ 6518c2ecf20Sopenharmony_ci reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT); 6528c2ecf20Sopenharmony_ci pdata->an_int = reg & XGBE_AN_CL37_INT_MASK; 6538c2ecf20Sopenharmony_ci pdata->an_status = reg & ~XGBE_AN_CL37_INT_MASK; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci if (pdata->an_int) { 6568c2ecf20Sopenharmony_ci /* Clear the interrupt(s) that fired and process them */ 6578c2ecf20Sopenharmony_ci reg &= ~XGBE_AN_CL37_INT_MASK; 6588c2ecf20Sopenharmony_ci XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT, reg); 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci queue_work(pdata->an_workqueue, &pdata->an_irq_work); 6618c2ecf20Sopenharmony_ci } else { 6628c2ecf20Sopenharmony_ci /* Enable AN interrupts */ 6638c2ecf20Sopenharmony_ci xgbe_an37_enable_interrupts(pdata); 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci /* Reissue interrupt if status is not clear */ 6668c2ecf20Sopenharmony_ci if (pdata->vdata->irq_reissue_support) 6678c2ecf20Sopenharmony_ci XP_IOWRITE(pdata, XP_INT_REISSUE_EN, 1 << 3); 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci} 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_cistatic void xgbe_an73_isr(struct xgbe_prv_data *pdata) 6728c2ecf20Sopenharmony_ci{ 6738c2ecf20Sopenharmony_ci /* Disable AN interrupts */ 6748c2ecf20Sopenharmony_ci xgbe_an73_disable_interrupts(pdata); 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci /* Save the interrupt(s) that fired */ 6778c2ecf20Sopenharmony_ci pdata->an_int = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_INT); 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci if (pdata->an_int) { 6808c2ecf20Sopenharmony_ci /* Clear the interrupt(s) that fired and process them */ 6818c2ecf20Sopenharmony_ci XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, ~pdata->an_int); 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci queue_work(pdata->an_workqueue, &pdata->an_irq_work); 6848c2ecf20Sopenharmony_ci } else { 6858c2ecf20Sopenharmony_ci /* Enable AN interrupts */ 6868c2ecf20Sopenharmony_ci xgbe_an73_enable_interrupts(pdata); 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci /* Reissue interrupt if status is not clear */ 6898c2ecf20Sopenharmony_ci if (pdata->vdata->irq_reissue_support) 6908c2ecf20Sopenharmony_ci XP_IOWRITE(pdata, XP_INT_REISSUE_EN, 1 << 3); 6918c2ecf20Sopenharmony_ci } 6928c2ecf20Sopenharmony_ci} 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_cistatic void xgbe_an_isr_task(struct tasklet_struct *t) 6958c2ecf20Sopenharmony_ci{ 6968c2ecf20Sopenharmony_ci struct xgbe_prv_data *pdata = from_tasklet(pdata, t, tasklet_an); 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci netif_dbg(pdata, intr, pdata->netdev, "AN interrupt received\n"); 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci switch (pdata->an_mode) { 7018c2ecf20Sopenharmony_ci case XGBE_AN_MODE_CL73: 7028c2ecf20Sopenharmony_ci case XGBE_AN_MODE_CL73_REDRV: 7038c2ecf20Sopenharmony_ci xgbe_an73_isr(pdata); 7048c2ecf20Sopenharmony_ci break; 7058c2ecf20Sopenharmony_ci case XGBE_AN_MODE_CL37: 7068c2ecf20Sopenharmony_ci case XGBE_AN_MODE_CL37_SGMII: 7078c2ecf20Sopenharmony_ci xgbe_an37_isr(pdata); 7088c2ecf20Sopenharmony_ci break; 7098c2ecf20Sopenharmony_ci default: 7108c2ecf20Sopenharmony_ci break; 7118c2ecf20Sopenharmony_ci } 7128c2ecf20Sopenharmony_ci} 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_cistatic irqreturn_t xgbe_an_isr(int irq, void *data) 7158c2ecf20Sopenharmony_ci{ 7168c2ecf20Sopenharmony_ci struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)data; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci if (pdata->isr_as_tasklet) 7198c2ecf20Sopenharmony_ci tasklet_schedule(&pdata->tasklet_an); 7208c2ecf20Sopenharmony_ci else 7218c2ecf20Sopenharmony_ci xgbe_an_isr_task(&pdata->tasklet_an); 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci return IRQ_HANDLED; 7248c2ecf20Sopenharmony_ci} 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_cistatic irqreturn_t xgbe_an_combined_isr(struct xgbe_prv_data *pdata) 7278c2ecf20Sopenharmony_ci{ 7288c2ecf20Sopenharmony_ci xgbe_an_isr_task(&pdata->tasklet_an); 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci return IRQ_HANDLED; 7318c2ecf20Sopenharmony_ci} 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_cistatic void xgbe_an_irq_work(struct work_struct *work) 7348c2ecf20Sopenharmony_ci{ 7358c2ecf20Sopenharmony_ci struct xgbe_prv_data *pdata = container_of(work, 7368c2ecf20Sopenharmony_ci struct xgbe_prv_data, 7378c2ecf20Sopenharmony_ci an_irq_work); 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci /* Avoid a race between enabling the IRQ and exiting the work by 7408c2ecf20Sopenharmony_ci * waiting for the work to finish and then queueing it 7418c2ecf20Sopenharmony_ci */ 7428c2ecf20Sopenharmony_ci flush_work(&pdata->an_work); 7438c2ecf20Sopenharmony_ci queue_work(pdata->an_workqueue, &pdata->an_work); 7448c2ecf20Sopenharmony_ci} 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_cistatic const char *xgbe_state_as_string(enum xgbe_an state) 7478c2ecf20Sopenharmony_ci{ 7488c2ecf20Sopenharmony_ci switch (state) { 7498c2ecf20Sopenharmony_ci case XGBE_AN_READY: 7508c2ecf20Sopenharmony_ci return "Ready"; 7518c2ecf20Sopenharmony_ci case XGBE_AN_PAGE_RECEIVED: 7528c2ecf20Sopenharmony_ci return "Page-Received"; 7538c2ecf20Sopenharmony_ci case XGBE_AN_INCOMPAT_LINK: 7548c2ecf20Sopenharmony_ci return "Incompatible-Link"; 7558c2ecf20Sopenharmony_ci case XGBE_AN_COMPLETE: 7568c2ecf20Sopenharmony_ci return "Complete"; 7578c2ecf20Sopenharmony_ci case XGBE_AN_NO_LINK: 7588c2ecf20Sopenharmony_ci return "No-Link"; 7598c2ecf20Sopenharmony_ci case XGBE_AN_ERROR: 7608c2ecf20Sopenharmony_ci return "Error"; 7618c2ecf20Sopenharmony_ci default: 7628c2ecf20Sopenharmony_ci return "Undefined"; 7638c2ecf20Sopenharmony_ci } 7648c2ecf20Sopenharmony_ci} 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_cistatic void xgbe_an37_state_machine(struct xgbe_prv_data *pdata) 7678c2ecf20Sopenharmony_ci{ 7688c2ecf20Sopenharmony_ci enum xgbe_an cur_state = pdata->an_state; 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci if (!pdata->an_int) 7718c2ecf20Sopenharmony_ci return; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci if (pdata->an_int & XGBE_AN_CL37_INT_CMPLT) { 7748c2ecf20Sopenharmony_ci pdata->an_state = XGBE_AN_COMPLETE; 7758c2ecf20Sopenharmony_ci pdata->an_int &= ~XGBE_AN_CL37_INT_CMPLT; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci /* If SGMII is enabled, check the link status */ 7788c2ecf20Sopenharmony_ci if ((pdata->an_mode == XGBE_AN_MODE_CL37_SGMII) && 7798c2ecf20Sopenharmony_ci !(pdata->an_status & XGBE_SGMII_AN_LINK_STATUS)) 7808c2ecf20Sopenharmony_ci pdata->an_state = XGBE_AN_NO_LINK; 7818c2ecf20Sopenharmony_ci } 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, "CL37 AN %s\n", 7848c2ecf20Sopenharmony_ci xgbe_state_as_string(pdata->an_state)); 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci cur_state = pdata->an_state; 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci switch (pdata->an_state) { 7898c2ecf20Sopenharmony_ci case XGBE_AN_READY: 7908c2ecf20Sopenharmony_ci break; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci case XGBE_AN_COMPLETE: 7938c2ecf20Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, 7948c2ecf20Sopenharmony_ci "Auto negotiation successful\n"); 7958c2ecf20Sopenharmony_ci break; 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci case XGBE_AN_NO_LINK: 7988c2ecf20Sopenharmony_ci break; 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci default: 8018c2ecf20Sopenharmony_ci pdata->an_state = XGBE_AN_ERROR; 8028c2ecf20Sopenharmony_ci } 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci if (pdata->an_state == XGBE_AN_ERROR) { 8058c2ecf20Sopenharmony_ci netdev_err(pdata->netdev, 8068c2ecf20Sopenharmony_ci "error during auto-negotiation, state=%u\n", 8078c2ecf20Sopenharmony_ci cur_state); 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci pdata->an_int = 0; 8108c2ecf20Sopenharmony_ci xgbe_an37_clear_interrupts(pdata); 8118c2ecf20Sopenharmony_ci } 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci if (pdata->an_state >= XGBE_AN_COMPLETE) { 8148c2ecf20Sopenharmony_ci pdata->an_result = pdata->an_state; 8158c2ecf20Sopenharmony_ci pdata->an_state = XGBE_AN_READY; 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci if (pdata->phy_if.phy_impl.an_post) 8188c2ecf20Sopenharmony_ci pdata->phy_if.phy_impl.an_post(pdata); 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, "CL37 AN result: %s\n", 8218c2ecf20Sopenharmony_ci xgbe_state_as_string(pdata->an_result)); 8228c2ecf20Sopenharmony_ci } 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci xgbe_an37_enable_interrupts(pdata); 8258c2ecf20Sopenharmony_ci} 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_cistatic void xgbe_an73_state_machine(struct xgbe_prv_data *pdata) 8288c2ecf20Sopenharmony_ci{ 8298c2ecf20Sopenharmony_ci enum xgbe_an cur_state = pdata->an_state; 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci if (!pdata->an_int) 8328c2ecf20Sopenharmony_ci return; 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_cinext_int: 8358c2ecf20Sopenharmony_ci if (pdata->an_int & XGBE_AN_CL73_PG_RCV) { 8368c2ecf20Sopenharmony_ci pdata->an_state = XGBE_AN_PAGE_RECEIVED; 8378c2ecf20Sopenharmony_ci pdata->an_int &= ~XGBE_AN_CL73_PG_RCV; 8388c2ecf20Sopenharmony_ci } else if (pdata->an_int & XGBE_AN_CL73_INC_LINK) { 8398c2ecf20Sopenharmony_ci pdata->an_state = XGBE_AN_INCOMPAT_LINK; 8408c2ecf20Sopenharmony_ci pdata->an_int &= ~XGBE_AN_CL73_INC_LINK; 8418c2ecf20Sopenharmony_ci } else if (pdata->an_int & XGBE_AN_CL73_INT_CMPLT) { 8428c2ecf20Sopenharmony_ci pdata->an_state = XGBE_AN_COMPLETE; 8438c2ecf20Sopenharmony_ci pdata->an_int &= ~XGBE_AN_CL73_INT_CMPLT; 8448c2ecf20Sopenharmony_ci } else { 8458c2ecf20Sopenharmony_ci pdata->an_state = XGBE_AN_ERROR; 8468c2ecf20Sopenharmony_ci } 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ciagain: 8498c2ecf20Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, "CL73 AN %s\n", 8508c2ecf20Sopenharmony_ci xgbe_state_as_string(pdata->an_state)); 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci cur_state = pdata->an_state; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci switch (pdata->an_state) { 8558c2ecf20Sopenharmony_ci case XGBE_AN_READY: 8568c2ecf20Sopenharmony_ci pdata->an_supported = 0; 8578c2ecf20Sopenharmony_ci break; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci case XGBE_AN_PAGE_RECEIVED: 8608c2ecf20Sopenharmony_ci pdata->an_state = xgbe_an73_page_received(pdata); 8618c2ecf20Sopenharmony_ci pdata->an_supported++; 8628c2ecf20Sopenharmony_ci break; 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci case XGBE_AN_INCOMPAT_LINK: 8658c2ecf20Sopenharmony_ci pdata->an_supported = 0; 8668c2ecf20Sopenharmony_ci pdata->parallel_detect = 0; 8678c2ecf20Sopenharmony_ci pdata->an_state = xgbe_an73_incompat_link(pdata); 8688c2ecf20Sopenharmony_ci break; 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci case XGBE_AN_COMPLETE: 8718c2ecf20Sopenharmony_ci pdata->parallel_detect = pdata->an_supported ? 0 : 1; 8728c2ecf20Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, "%s successful\n", 8738c2ecf20Sopenharmony_ci pdata->an_supported ? "Auto negotiation" 8748c2ecf20Sopenharmony_ci : "Parallel detection"); 8758c2ecf20Sopenharmony_ci break; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci case XGBE_AN_NO_LINK: 8788c2ecf20Sopenharmony_ci break; 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci default: 8818c2ecf20Sopenharmony_ci pdata->an_state = XGBE_AN_ERROR; 8828c2ecf20Sopenharmony_ci } 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci if (pdata->an_state == XGBE_AN_NO_LINK) { 8858c2ecf20Sopenharmony_ci pdata->an_int = 0; 8868c2ecf20Sopenharmony_ci xgbe_an73_clear_interrupts(pdata); 8878c2ecf20Sopenharmony_ci } else if (pdata->an_state == XGBE_AN_ERROR) { 8888c2ecf20Sopenharmony_ci netdev_err(pdata->netdev, 8898c2ecf20Sopenharmony_ci "error during auto-negotiation, state=%u\n", 8908c2ecf20Sopenharmony_ci cur_state); 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci pdata->an_int = 0; 8938c2ecf20Sopenharmony_ci xgbe_an73_clear_interrupts(pdata); 8948c2ecf20Sopenharmony_ci } 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci if (pdata->an_state >= XGBE_AN_COMPLETE) { 8978c2ecf20Sopenharmony_ci pdata->an_result = pdata->an_state; 8988c2ecf20Sopenharmony_ci pdata->an_state = XGBE_AN_READY; 8998c2ecf20Sopenharmony_ci pdata->kr_state = XGBE_RX_BPA; 9008c2ecf20Sopenharmony_ci pdata->kx_state = XGBE_RX_BPA; 9018c2ecf20Sopenharmony_ci pdata->an_start = 0; 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci if (pdata->phy_if.phy_impl.an_post) 9048c2ecf20Sopenharmony_ci pdata->phy_if.phy_impl.an_post(pdata); 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, "CL73 AN result: %s\n", 9078c2ecf20Sopenharmony_ci xgbe_state_as_string(pdata->an_result)); 9088c2ecf20Sopenharmony_ci } 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci if (cur_state != pdata->an_state) 9118c2ecf20Sopenharmony_ci goto again; 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci if (pdata->an_int) 9148c2ecf20Sopenharmony_ci goto next_int; 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci xgbe_an73_enable_interrupts(pdata); 9178c2ecf20Sopenharmony_ci} 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_cistatic void xgbe_an_state_machine(struct work_struct *work) 9208c2ecf20Sopenharmony_ci{ 9218c2ecf20Sopenharmony_ci struct xgbe_prv_data *pdata = container_of(work, 9228c2ecf20Sopenharmony_ci struct xgbe_prv_data, 9238c2ecf20Sopenharmony_ci an_work); 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci mutex_lock(&pdata->an_mutex); 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci switch (pdata->an_mode) { 9288c2ecf20Sopenharmony_ci case XGBE_AN_MODE_CL73: 9298c2ecf20Sopenharmony_ci case XGBE_AN_MODE_CL73_REDRV: 9308c2ecf20Sopenharmony_ci xgbe_an73_state_machine(pdata); 9318c2ecf20Sopenharmony_ci break; 9328c2ecf20Sopenharmony_ci case XGBE_AN_MODE_CL37: 9338c2ecf20Sopenharmony_ci case XGBE_AN_MODE_CL37_SGMII: 9348c2ecf20Sopenharmony_ci xgbe_an37_state_machine(pdata); 9358c2ecf20Sopenharmony_ci break; 9368c2ecf20Sopenharmony_ci default: 9378c2ecf20Sopenharmony_ci break; 9388c2ecf20Sopenharmony_ci } 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci /* Reissue interrupt if status is not clear */ 9418c2ecf20Sopenharmony_ci if (pdata->vdata->irq_reissue_support) 9428c2ecf20Sopenharmony_ci XP_IOWRITE(pdata, XP_INT_REISSUE_EN, 1 << 3); 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci mutex_unlock(&pdata->an_mutex); 9458c2ecf20Sopenharmony_ci} 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_cistatic void xgbe_an37_init(struct xgbe_prv_data *pdata) 9488c2ecf20Sopenharmony_ci{ 9498c2ecf20Sopenharmony_ci struct ethtool_link_ksettings lks; 9508c2ecf20Sopenharmony_ci unsigned int reg; 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci pdata->phy_if.phy_impl.an_advertising(pdata, &lks); 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci /* Set up Advertisement register */ 9558c2ecf20Sopenharmony_ci reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_ADVERTISE); 9568c2ecf20Sopenharmony_ci if (XGBE_ADV(&lks, Pause)) 9578c2ecf20Sopenharmony_ci reg |= 0x100; 9588c2ecf20Sopenharmony_ci else 9598c2ecf20Sopenharmony_ci reg &= ~0x100; 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci if (XGBE_ADV(&lks, Asym_Pause)) 9628c2ecf20Sopenharmony_ci reg |= 0x80; 9638c2ecf20Sopenharmony_ci else 9648c2ecf20Sopenharmony_ci reg &= ~0x80; 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci /* Full duplex, but not half */ 9678c2ecf20Sopenharmony_ci reg |= XGBE_AN_CL37_FD_MASK; 9688c2ecf20Sopenharmony_ci reg &= ~XGBE_AN_CL37_HD_MASK; 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_ADVERTISE, reg); 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci /* Set up the Control register */ 9738c2ecf20Sopenharmony_ci reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL); 9748c2ecf20Sopenharmony_ci reg &= ~XGBE_AN_CL37_TX_CONFIG_MASK; 9758c2ecf20Sopenharmony_ci reg &= ~XGBE_AN_CL37_PCS_MODE_MASK; 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci switch (pdata->an_mode) { 9788c2ecf20Sopenharmony_ci case XGBE_AN_MODE_CL37: 9798c2ecf20Sopenharmony_ci reg |= XGBE_AN_CL37_PCS_MODE_BASEX; 9808c2ecf20Sopenharmony_ci break; 9818c2ecf20Sopenharmony_ci case XGBE_AN_MODE_CL37_SGMII: 9828c2ecf20Sopenharmony_ci reg |= XGBE_AN_CL37_PCS_MODE_SGMII; 9838c2ecf20Sopenharmony_ci break; 9848c2ecf20Sopenharmony_ci default: 9858c2ecf20Sopenharmony_ci break; 9868c2ecf20Sopenharmony_ci } 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci reg |= XGBE_AN_CL37_MII_CTRL_8BIT; 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL, reg); 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, "CL37 AN (%s) initialized\n", 9938c2ecf20Sopenharmony_ci (pdata->an_mode == XGBE_AN_MODE_CL37) ? "BaseX" : "SGMII"); 9948c2ecf20Sopenharmony_ci} 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_cistatic void xgbe_an73_init(struct xgbe_prv_data *pdata) 9978c2ecf20Sopenharmony_ci{ 9988c2ecf20Sopenharmony_ci struct ethtool_link_ksettings lks; 9998c2ecf20Sopenharmony_ci unsigned int reg; 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci pdata->phy_if.phy_impl.an_advertising(pdata, &lks); 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci /* Set up Advertisement register 3 first */ 10048c2ecf20Sopenharmony_ci reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); 10058c2ecf20Sopenharmony_ci if (XGBE_ADV(&lks, 10000baseR_FEC)) 10068c2ecf20Sopenharmony_ci reg |= 0xc000; 10078c2ecf20Sopenharmony_ci else 10088c2ecf20Sopenharmony_ci reg &= ~0xc000; 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2, reg); 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci /* Set up Advertisement register 2 next */ 10138c2ecf20Sopenharmony_ci reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1); 10148c2ecf20Sopenharmony_ci if (XGBE_ADV(&lks, 10000baseKR_Full)) 10158c2ecf20Sopenharmony_ci reg |= 0x80; 10168c2ecf20Sopenharmony_ci else 10178c2ecf20Sopenharmony_ci reg &= ~0x80; 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci if (XGBE_ADV(&lks, 1000baseKX_Full) || 10208c2ecf20Sopenharmony_ci XGBE_ADV(&lks, 2500baseX_Full)) 10218c2ecf20Sopenharmony_ci reg |= 0x20; 10228c2ecf20Sopenharmony_ci else 10238c2ecf20Sopenharmony_ci reg &= ~0x20; 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1, reg); 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci /* Set up Advertisement register 1 last */ 10288c2ecf20Sopenharmony_ci reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE); 10298c2ecf20Sopenharmony_ci if (XGBE_ADV(&lks, Pause)) 10308c2ecf20Sopenharmony_ci reg |= 0x400; 10318c2ecf20Sopenharmony_ci else 10328c2ecf20Sopenharmony_ci reg &= ~0x400; 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci if (XGBE_ADV(&lks, Asym_Pause)) 10358c2ecf20Sopenharmony_ci reg |= 0x800; 10368c2ecf20Sopenharmony_ci else 10378c2ecf20Sopenharmony_ci reg &= ~0x800; 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci /* We don't intend to perform XNP */ 10408c2ecf20Sopenharmony_ci reg &= ~XGBE_XNP_NP_EXCHANGE; 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg); 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, "CL73 AN initialized\n"); 10458c2ecf20Sopenharmony_ci} 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_cistatic void xgbe_an_init(struct xgbe_prv_data *pdata) 10488c2ecf20Sopenharmony_ci{ 10498c2ecf20Sopenharmony_ci /* Set up advertisement registers based on current settings */ 10508c2ecf20Sopenharmony_ci pdata->an_mode = pdata->phy_if.phy_impl.an_mode(pdata); 10518c2ecf20Sopenharmony_ci switch (pdata->an_mode) { 10528c2ecf20Sopenharmony_ci case XGBE_AN_MODE_CL73: 10538c2ecf20Sopenharmony_ci case XGBE_AN_MODE_CL73_REDRV: 10548c2ecf20Sopenharmony_ci xgbe_an73_init(pdata); 10558c2ecf20Sopenharmony_ci break; 10568c2ecf20Sopenharmony_ci case XGBE_AN_MODE_CL37: 10578c2ecf20Sopenharmony_ci case XGBE_AN_MODE_CL37_SGMII: 10588c2ecf20Sopenharmony_ci xgbe_an37_init(pdata); 10598c2ecf20Sopenharmony_ci break; 10608c2ecf20Sopenharmony_ci default: 10618c2ecf20Sopenharmony_ci break; 10628c2ecf20Sopenharmony_ci } 10638c2ecf20Sopenharmony_ci} 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_cistatic const char *xgbe_phy_fc_string(struct xgbe_prv_data *pdata) 10668c2ecf20Sopenharmony_ci{ 10678c2ecf20Sopenharmony_ci if (pdata->tx_pause && pdata->rx_pause) 10688c2ecf20Sopenharmony_ci return "rx/tx"; 10698c2ecf20Sopenharmony_ci else if (pdata->rx_pause) 10708c2ecf20Sopenharmony_ci return "rx"; 10718c2ecf20Sopenharmony_ci else if (pdata->tx_pause) 10728c2ecf20Sopenharmony_ci return "tx"; 10738c2ecf20Sopenharmony_ci else 10748c2ecf20Sopenharmony_ci return "off"; 10758c2ecf20Sopenharmony_ci} 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_cistatic const char *xgbe_phy_speed_string(int speed) 10788c2ecf20Sopenharmony_ci{ 10798c2ecf20Sopenharmony_ci switch (speed) { 10808c2ecf20Sopenharmony_ci case SPEED_100: 10818c2ecf20Sopenharmony_ci return "100Mbps"; 10828c2ecf20Sopenharmony_ci case SPEED_1000: 10838c2ecf20Sopenharmony_ci return "1Gbps"; 10848c2ecf20Sopenharmony_ci case SPEED_2500: 10858c2ecf20Sopenharmony_ci return "2.5Gbps"; 10868c2ecf20Sopenharmony_ci case SPEED_10000: 10878c2ecf20Sopenharmony_ci return "10Gbps"; 10888c2ecf20Sopenharmony_ci case SPEED_UNKNOWN: 10898c2ecf20Sopenharmony_ci return "Unknown"; 10908c2ecf20Sopenharmony_ci default: 10918c2ecf20Sopenharmony_ci return "Unsupported"; 10928c2ecf20Sopenharmony_ci } 10938c2ecf20Sopenharmony_ci} 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_cistatic void xgbe_phy_print_status(struct xgbe_prv_data *pdata) 10968c2ecf20Sopenharmony_ci{ 10978c2ecf20Sopenharmony_ci if (pdata->phy.link) 10988c2ecf20Sopenharmony_ci netdev_info(pdata->netdev, 10998c2ecf20Sopenharmony_ci "Link is Up - %s/%s - flow control %s\n", 11008c2ecf20Sopenharmony_ci xgbe_phy_speed_string(pdata->phy.speed), 11018c2ecf20Sopenharmony_ci pdata->phy.duplex == DUPLEX_FULL ? "Full" : "Half", 11028c2ecf20Sopenharmony_ci xgbe_phy_fc_string(pdata)); 11038c2ecf20Sopenharmony_ci else 11048c2ecf20Sopenharmony_ci netdev_info(pdata->netdev, "Link is Down\n"); 11058c2ecf20Sopenharmony_ci} 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_cistatic void xgbe_phy_adjust_link(struct xgbe_prv_data *pdata) 11088c2ecf20Sopenharmony_ci{ 11098c2ecf20Sopenharmony_ci int new_state = 0; 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci if (pdata->phy.link) { 11128c2ecf20Sopenharmony_ci /* Flow control support */ 11138c2ecf20Sopenharmony_ci pdata->pause_autoneg = pdata->phy.pause_autoneg; 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci if (pdata->tx_pause != pdata->phy.tx_pause) { 11168c2ecf20Sopenharmony_ci new_state = 1; 11178c2ecf20Sopenharmony_ci pdata->tx_pause = pdata->phy.tx_pause; 11188c2ecf20Sopenharmony_ci pdata->hw_if.config_tx_flow_control(pdata); 11198c2ecf20Sopenharmony_ci } 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci if (pdata->rx_pause != pdata->phy.rx_pause) { 11228c2ecf20Sopenharmony_ci new_state = 1; 11238c2ecf20Sopenharmony_ci pdata->rx_pause = pdata->phy.rx_pause; 11248c2ecf20Sopenharmony_ci pdata->hw_if.config_rx_flow_control(pdata); 11258c2ecf20Sopenharmony_ci } 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci /* Speed support */ 11288c2ecf20Sopenharmony_ci if (pdata->phy_speed != pdata->phy.speed) { 11298c2ecf20Sopenharmony_ci new_state = 1; 11308c2ecf20Sopenharmony_ci pdata->phy_speed = pdata->phy.speed; 11318c2ecf20Sopenharmony_ci } 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci if (pdata->phy_link != pdata->phy.link) { 11348c2ecf20Sopenharmony_ci new_state = 1; 11358c2ecf20Sopenharmony_ci pdata->phy_link = pdata->phy.link; 11368c2ecf20Sopenharmony_ci } 11378c2ecf20Sopenharmony_ci } else if (pdata->phy_link) { 11388c2ecf20Sopenharmony_ci new_state = 1; 11398c2ecf20Sopenharmony_ci pdata->phy_link = 0; 11408c2ecf20Sopenharmony_ci pdata->phy_speed = SPEED_UNKNOWN; 11418c2ecf20Sopenharmony_ci } 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci if (new_state && netif_msg_link(pdata)) 11448c2ecf20Sopenharmony_ci xgbe_phy_print_status(pdata); 11458c2ecf20Sopenharmony_ci} 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_cistatic bool xgbe_phy_valid_speed(struct xgbe_prv_data *pdata, int speed) 11488c2ecf20Sopenharmony_ci{ 11498c2ecf20Sopenharmony_ci return pdata->phy_if.phy_impl.valid_speed(pdata, speed); 11508c2ecf20Sopenharmony_ci} 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_cistatic int xgbe_phy_config_fixed(struct xgbe_prv_data *pdata) 11538c2ecf20Sopenharmony_ci{ 11548c2ecf20Sopenharmony_ci enum xgbe_mode mode; 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, "fixed PHY configuration\n"); 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci /* Disable auto-negotiation */ 11598c2ecf20Sopenharmony_ci xgbe_an_disable(pdata); 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci /* Set specified mode for specified speed */ 11628c2ecf20Sopenharmony_ci mode = pdata->phy_if.phy_impl.get_mode(pdata, pdata->phy.speed); 11638c2ecf20Sopenharmony_ci switch (mode) { 11648c2ecf20Sopenharmony_ci case XGBE_MODE_KX_1000: 11658c2ecf20Sopenharmony_ci case XGBE_MODE_KX_2500: 11668c2ecf20Sopenharmony_ci case XGBE_MODE_KR: 11678c2ecf20Sopenharmony_ci case XGBE_MODE_SGMII_100: 11688c2ecf20Sopenharmony_ci case XGBE_MODE_SGMII_1000: 11698c2ecf20Sopenharmony_ci case XGBE_MODE_X: 11708c2ecf20Sopenharmony_ci case XGBE_MODE_SFI: 11718c2ecf20Sopenharmony_ci break; 11728c2ecf20Sopenharmony_ci case XGBE_MODE_UNKNOWN: 11738c2ecf20Sopenharmony_ci default: 11748c2ecf20Sopenharmony_ci return -EINVAL; 11758c2ecf20Sopenharmony_ci } 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci /* Validate duplex mode */ 11788c2ecf20Sopenharmony_ci if (pdata->phy.duplex != DUPLEX_FULL) 11798c2ecf20Sopenharmony_ci return -EINVAL; 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci /* Force the mode change for SFI in Fixed PHY config. 11828c2ecf20Sopenharmony_ci * Fixed PHY configs needs PLL to be enabled while doing mode set. 11838c2ecf20Sopenharmony_ci * When the SFP module isn't connected during boot, driver assumes 11848c2ecf20Sopenharmony_ci * AN is ON and attempts autonegotiation. However, if the connected 11858c2ecf20Sopenharmony_ci * SFP comes up in Fixed PHY config, the link will not come up as 11868c2ecf20Sopenharmony_ci * PLL isn't enabled while the initial mode set command is issued. 11878c2ecf20Sopenharmony_ci * So, force the mode change for SFI in Fixed PHY configuration to 11888c2ecf20Sopenharmony_ci * fix link issues. 11898c2ecf20Sopenharmony_ci */ 11908c2ecf20Sopenharmony_ci if (mode == XGBE_MODE_SFI) 11918c2ecf20Sopenharmony_ci xgbe_change_mode(pdata, mode); 11928c2ecf20Sopenharmony_ci else 11938c2ecf20Sopenharmony_ci xgbe_set_mode(pdata, mode); 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci return 0; 11968c2ecf20Sopenharmony_ci} 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_cistatic int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata, bool set_mode) 11998c2ecf20Sopenharmony_ci{ 12008c2ecf20Sopenharmony_ci int ret; 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci mutex_lock(&pdata->an_mutex); 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci set_bit(XGBE_LINK_INIT, &pdata->dev_state); 12058c2ecf20Sopenharmony_ci pdata->link_check = jiffies; 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci ret = pdata->phy_if.phy_impl.an_config(pdata); 12088c2ecf20Sopenharmony_ci if (ret) 12098c2ecf20Sopenharmony_ci goto out; 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci if (pdata->phy.autoneg != AUTONEG_ENABLE) { 12128c2ecf20Sopenharmony_ci ret = xgbe_phy_config_fixed(pdata); 12138c2ecf20Sopenharmony_ci if (ret || !pdata->kr_redrv) 12148c2ecf20Sopenharmony_ci goto out; 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, "AN redriver support\n"); 12178c2ecf20Sopenharmony_ci } else { 12188c2ecf20Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, "AN PHY configuration\n"); 12198c2ecf20Sopenharmony_ci } 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci /* Disable auto-negotiation interrupt */ 12228c2ecf20Sopenharmony_ci disable_irq(pdata->an_irq); 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci if (set_mode) { 12258c2ecf20Sopenharmony_ci /* Start auto-negotiation in a supported mode */ 12268c2ecf20Sopenharmony_ci if (xgbe_use_mode(pdata, XGBE_MODE_KR)) { 12278c2ecf20Sopenharmony_ci xgbe_set_mode(pdata, XGBE_MODE_KR); 12288c2ecf20Sopenharmony_ci } else if (xgbe_use_mode(pdata, XGBE_MODE_KX_2500)) { 12298c2ecf20Sopenharmony_ci xgbe_set_mode(pdata, XGBE_MODE_KX_2500); 12308c2ecf20Sopenharmony_ci } else if (xgbe_use_mode(pdata, XGBE_MODE_KX_1000)) { 12318c2ecf20Sopenharmony_ci xgbe_set_mode(pdata, XGBE_MODE_KX_1000); 12328c2ecf20Sopenharmony_ci } else if (xgbe_use_mode(pdata, XGBE_MODE_SFI)) { 12338c2ecf20Sopenharmony_ci xgbe_set_mode(pdata, XGBE_MODE_SFI); 12348c2ecf20Sopenharmony_ci } else if (xgbe_use_mode(pdata, XGBE_MODE_X)) { 12358c2ecf20Sopenharmony_ci xgbe_set_mode(pdata, XGBE_MODE_X); 12368c2ecf20Sopenharmony_ci } else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_1000)) { 12378c2ecf20Sopenharmony_ci xgbe_set_mode(pdata, XGBE_MODE_SGMII_1000); 12388c2ecf20Sopenharmony_ci } else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_100)) { 12398c2ecf20Sopenharmony_ci xgbe_set_mode(pdata, XGBE_MODE_SGMII_100); 12408c2ecf20Sopenharmony_ci } else { 12418c2ecf20Sopenharmony_ci enable_irq(pdata->an_irq); 12428c2ecf20Sopenharmony_ci ret = -EINVAL; 12438c2ecf20Sopenharmony_ci goto out; 12448c2ecf20Sopenharmony_ci } 12458c2ecf20Sopenharmony_ci } 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci /* Disable and stop any in progress auto-negotiation */ 12488c2ecf20Sopenharmony_ci xgbe_an_disable_all(pdata); 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci /* Clear any auto-negotitation interrupts */ 12518c2ecf20Sopenharmony_ci xgbe_an_clear_interrupts_all(pdata); 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci pdata->an_result = XGBE_AN_READY; 12548c2ecf20Sopenharmony_ci pdata->an_state = XGBE_AN_READY; 12558c2ecf20Sopenharmony_ci pdata->kr_state = XGBE_RX_BPA; 12568c2ecf20Sopenharmony_ci pdata->kx_state = XGBE_RX_BPA; 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci /* Re-enable auto-negotiation interrupt */ 12598c2ecf20Sopenharmony_ci enable_irq(pdata->an_irq); 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci xgbe_an_init(pdata); 12628c2ecf20Sopenharmony_ci xgbe_an_restart(pdata); 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ciout: 12658c2ecf20Sopenharmony_ci if (ret) 12668c2ecf20Sopenharmony_ci set_bit(XGBE_LINK_ERR, &pdata->dev_state); 12678c2ecf20Sopenharmony_ci else 12688c2ecf20Sopenharmony_ci clear_bit(XGBE_LINK_ERR, &pdata->dev_state); 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci mutex_unlock(&pdata->an_mutex); 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci return ret; 12738c2ecf20Sopenharmony_ci} 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_cistatic int xgbe_phy_config_aneg(struct xgbe_prv_data *pdata) 12768c2ecf20Sopenharmony_ci{ 12778c2ecf20Sopenharmony_ci return __xgbe_phy_config_aneg(pdata, true); 12788c2ecf20Sopenharmony_ci} 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_cistatic int xgbe_phy_reconfig_aneg(struct xgbe_prv_data *pdata) 12818c2ecf20Sopenharmony_ci{ 12828c2ecf20Sopenharmony_ci return __xgbe_phy_config_aneg(pdata, false); 12838c2ecf20Sopenharmony_ci} 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_cistatic bool xgbe_phy_aneg_done(struct xgbe_prv_data *pdata) 12868c2ecf20Sopenharmony_ci{ 12878c2ecf20Sopenharmony_ci return (pdata->an_result == XGBE_AN_COMPLETE); 12888c2ecf20Sopenharmony_ci} 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_cistatic void xgbe_check_link_timeout(struct xgbe_prv_data *pdata) 12918c2ecf20Sopenharmony_ci{ 12928c2ecf20Sopenharmony_ci unsigned long link_timeout; 12938c2ecf20Sopenharmony_ci unsigned long kr_time; 12948c2ecf20Sopenharmony_ci int wait; 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci link_timeout = pdata->link_check + (XGBE_LINK_TIMEOUT * HZ); 12978c2ecf20Sopenharmony_ci if (time_after(jiffies, link_timeout)) { 12988c2ecf20Sopenharmony_ci if ((xgbe_cur_mode(pdata) == XGBE_MODE_KR) && 12998c2ecf20Sopenharmony_ci pdata->phy.autoneg == AUTONEG_ENABLE) { 13008c2ecf20Sopenharmony_ci /* AN restart should not happen while KR training is in progress. 13018c2ecf20Sopenharmony_ci * The while loop ensures no AN restart during KR training, 13028c2ecf20Sopenharmony_ci * waits up to 500ms and AN restart is triggered only if KR 13038c2ecf20Sopenharmony_ci * training is failed. 13048c2ecf20Sopenharmony_ci */ 13058c2ecf20Sopenharmony_ci wait = XGBE_KR_TRAINING_WAIT_ITER; 13068c2ecf20Sopenharmony_ci while (wait--) { 13078c2ecf20Sopenharmony_ci kr_time = pdata->kr_start_time + 13088c2ecf20Sopenharmony_ci msecs_to_jiffies(XGBE_AN_MS_TIMEOUT); 13098c2ecf20Sopenharmony_ci if (time_after(jiffies, kr_time)) 13108c2ecf20Sopenharmony_ci break; 13118c2ecf20Sopenharmony_ci /* AN restart is not required, if AN result is COMPLETE */ 13128c2ecf20Sopenharmony_ci if (pdata->an_result == XGBE_AN_COMPLETE) 13138c2ecf20Sopenharmony_ci return; 13148c2ecf20Sopenharmony_ci usleep_range(10000, 11000); 13158c2ecf20Sopenharmony_ci } 13168c2ecf20Sopenharmony_ci } 13178c2ecf20Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, "AN link timeout\n"); 13188c2ecf20Sopenharmony_ci xgbe_phy_config_aneg(pdata); 13198c2ecf20Sopenharmony_ci } 13208c2ecf20Sopenharmony_ci} 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_cistatic enum xgbe_mode xgbe_phy_status_aneg(struct xgbe_prv_data *pdata) 13238c2ecf20Sopenharmony_ci{ 13248c2ecf20Sopenharmony_ci return pdata->phy_if.phy_impl.an_outcome(pdata); 13258c2ecf20Sopenharmony_ci} 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_cistatic bool xgbe_phy_status_result(struct xgbe_prv_data *pdata) 13288c2ecf20Sopenharmony_ci{ 13298c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *lks = &pdata->phy.lks; 13308c2ecf20Sopenharmony_ci enum xgbe_mode mode; 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci XGBE_ZERO_LP_ADV(lks); 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci if ((pdata->phy.autoneg != AUTONEG_ENABLE) || pdata->parallel_detect) 13358c2ecf20Sopenharmony_ci mode = xgbe_cur_mode(pdata); 13368c2ecf20Sopenharmony_ci else 13378c2ecf20Sopenharmony_ci mode = xgbe_phy_status_aneg(pdata); 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_ci switch (mode) { 13408c2ecf20Sopenharmony_ci case XGBE_MODE_SGMII_100: 13418c2ecf20Sopenharmony_ci pdata->phy.speed = SPEED_100; 13428c2ecf20Sopenharmony_ci break; 13438c2ecf20Sopenharmony_ci case XGBE_MODE_X: 13448c2ecf20Sopenharmony_ci case XGBE_MODE_KX_1000: 13458c2ecf20Sopenharmony_ci case XGBE_MODE_SGMII_1000: 13468c2ecf20Sopenharmony_ci pdata->phy.speed = SPEED_1000; 13478c2ecf20Sopenharmony_ci break; 13488c2ecf20Sopenharmony_ci case XGBE_MODE_KX_2500: 13498c2ecf20Sopenharmony_ci pdata->phy.speed = SPEED_2500; 13508c2ecf20Sopenharmony_ci break; 13518c2ecf20Sopenharmony_ci case XGBE_MODE_KR: 13528c2ecf20Sopenharmony_ci case XGBE_MODE_SFI: 13538c2ecf20Sopenharmony_ci pdata->phy.speed = SPEED_10000; 13548c2ecf20Sopenharmony_ci break; 13558c2ecf20Sopenharmony_ci case XGBE_MODE_UNKNOWN: 13568c2ecf20Sopenharmony_ci default: 13578c2ecf20Sopenharmony_ci pdata->phy.speed = SPEED_UNKNOWN; 13588c2ecf20Sopenharmony_ci } 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci pdata->phy.duplex = DUPLEX_FULL; 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci if (!xgbe_set_mode(pdata, mode)) 13638c2ecf20Sopenharmony_ci return false; 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci if (pdata->an_again) 13668c2ecf20Sopenharmony_ci xgbe_phy_reconfig_aneg(pdata); 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci return true; 13698c2ecf20Sopenharmony_ci} 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_cistatic void xgbe_phy_status(struct xgbe_prv_data *pdata) 13728c2ecf20Sopenharmony_ci{ 13738c2ecf20Sopenharmony_ci unsigned int link_aneg; 13748c2ecf20Sopenharmony_ci int an_restart; 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci if (test_bit(XGBE_LINK_ERR, &pdata->dev_state)) { 13778c2ecf20Sopenharmony_ci netif_carrier_off(pdata->netdev); 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci pdata->phy.link = 0; 13808c2ecf20Sopenharmony_ci goto adjust_link; 13818c2ecf20Sopenharmony_ci } 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci link_aneg = (pdata->phy.autoneg == AUTONEG_ENABLE); 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci pdata->phy.link = pdata->phy_if.phy_impl.link_status(pdata, 13868c2ecf20Sopenharmony_ci &an_restart); 13878c2ecf20Sopenharmony_ci if (an_restart) { 13888c2ecf20Sopenharmony_ci xgbe_phy_config_aneg(pdata); 13898c2ecf20Sopenharmony_ci goto adjust_link; 13908c2ecf20Sopenharmony_ci } 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ci if (pdata->phy.link) { 13938c2ecf20Sopenharmony_ci if (link_aneg && !xgbe_phy_aneg_done(pdata)) { 13948c2ecf20Sopenharmony_ci xgbe_check_link_timeout(pdata); 13958c2ecf20Sopenharmony_ci return; 13968c2ecf20Sopenharmony_ci } 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci if (xgbe_phy_status_result(pdata)) 13998c2ecf20Sopenharmony_ci return; 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci if (test_bit(XGBE_LINK_INIT, &pdata->dev_state)) 14028c2ecf20Sopenharmony_ci clear_bit(XGBE_LINK_INIT, &pdata->dev_state); 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci netif_carrier_on(pdata->netdev); 14058c2ecf20Sopenharmony_ci } else { 14068c2ecf20Sopenharmony_ci if (test_bit(XGBE_LINK_INIT, &pdata->dev_state)) { 14078c2ecf20Sopenharmony_ci xgbe_check_link_timeout(pdata); 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci if (link_aneg) 14108c2ecf20Sopenharmony_ci return; 14118c2ecf20Sopenharmony_ci } 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci xgbe_phy_status_result(pdata); 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci netif_carrier_off(pdata->netdev); 14168c2ecf20Sopenharmony_ci } 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ciadjust_link: 14198c2ecf20Sopenharmony_ci xgbe_phy_adjust_link(pdata); 14208c2ecf20Sopenharmony_ci} 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_cistatic void xgbe_phy_stop(struct xgbe_prv_data *pdata) 14238c2ecf20Sopenharmony_ci{ 14248c2ecf20Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, "stopping PHY\n"); 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci if (!pdata->phy_started) 14278c2ecf20Sopenharmony_ci return; 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci /* Indicate the PHY is down */ 14308c2ecf20Sopenharmony_ci pdata->phy_started = 0; 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci /* Disable auto-negotiation */ 14338c2ecf20Sopenharmony_ci xgbe_an_disable_all(pdata); 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci if (pdata->dev_irq != pdata->an_irq) { 14368c2ecf20Sopenharmony_ci devm_free_irq(pdata->dev, pdata->an_irq, pdata); 14378c2ecf20Sopenharmony_ci tasklet_kill(&pdata->tasklet_an); 14388c2ecf20Sopenharmony_ci } 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci pdata->phy_if.phy_impl.stop(pdata); 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_ci pdata->phy.link = 0; 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci xgbe_phy_adjust_link(pdata); 14458c2ecf20Sopenharmony_ci} 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_cistatic int xgbe_phy_start(struct xgbe_prv_data *pdata) 14488c2ecf20Sopenharmony_ci{ 14498c2ecf20Sopenharmony_ci struct net_device *netdev = pdata->netdev; 14508c2ecf20Sopenharmony_ci int ret; 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, "starting PHY\n"); 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci ret = pdata->phy_if.phy_impl.start(pdata); 14558c2ecf20Sopenharmony_ci if (ret) 14568c2ecf20Sopenharmony_ci return ret; 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_ci /* If we have a separate AN irq, enable it */ 14598c2ecf20Sopenharmony_ci if (pdata->dev_irq != pdata->an_irq) { 14608c2ecf20Sopenharmony_ci tasklet_setup(&pdata->tasklet_an, xgbe_an_isr_task); 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci ret = devm_request_irq(pdata->dev, pdata->an_irq, 14638c2ecf20Sopenharmony_ci xgbe_an_isr, 0, pdata->an_name, 14648c2ecf20Sopenharmony_ci pdata); 14658c2ecf20Sopenharmony_ci if (ret) { 14668c2ecf20Sopenharmony_ci netdev_err(netdev, "phy irq request failed\n"); 14678c2ecf20Sopenharmony_ci goto err_stop; 14688c2ecf20Sopenharmony_ci } 14698c2ecf20Sopenharmony_ci } 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci /* Set initial mode - call the mode setting routines 14728c2ecf20Sopenharmony_ci * directly to insure we are properly configured 14738c2ecf20Sopenharmony_ci */ 14748c2ecf20Sopenharmony_ci if (xgbe_use_mode(pdata, XGBE_MODE_KR)) { 14758c2ecf20Sopenharmony_ci xgbe_kr_mode(pdata); 14768c2ecf20Sopenharmony_ci } else if (xgbe_use_mode(pdata, XGBE_MODE_KX_2500)) { 14778c2ecf20Sopenharmony_ci xgbe_kx_2500_mode(pdata); 14788c2ecf20Sopenharmony_ci } else if (xgbe_use_mode(pdata, XGBE_MODE_KX_1000)) { 14798c2ecf20Sopenharmony_ci xgbe_kx_1000_mode(pdata); 14808c2ecf20Sopenharmony_ci } else if (xgbe_use_mode(pdata, XGBE_MODE_SFI)) { 14818c2ecf20Sopenharmony_ci xgbe_sfi_mode(pdata); 14828c2ecf20Sopenharmony_ci } else if (xgbe_use_mode(pdata, XGBE_MODE_X)) { 14838c2ecf20Sopenharmony_ci xgbe_x_mode(pdata); 14848c2ecf20Sopenharmony_ci } else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_1000)) { 14858c2ecf20Sopenharmony_ci xgbe_sgmii_1000_mode(pdata); 14868c2ecf20Sopenharmony_ci } else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_100)) { 14878c2ecf20Sopenharmony_ci xgbe_sgmii_100_mode(pdata); 14888c2ecf20Sopenharmony_ci } else { 14898c2ecf20Sopenharmony_ci ret = -EINVAL; 14908c2ecf20Sopenharmony_ci goto err_irq; 14918c2ecf20Sopenharmony_ci } 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci /* Indicate the PHY is up and running */ 14948c2ecf20Sopenharmony_ci pdata->phy_started = 1; 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci xgbe_an_init(pdata); 14978c2ecf20Sopenharmony_ci xgbe_an_enable_interrupts(pdata); 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci return xgbe_phy_config_aneg(pdata); 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_cierr_irq: 15028c2ecf20Sopenharmony_ci if (pdata->dev_irq != pdata->an_irq) 15038c2ecf20Sopenharmony_ci devm_free_irq(pdata->dev, pdata->an_irq, pdata); 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_cierr_stop: 15068c2ecf20Sopenharmony_ci pdata->phy_if.phy_impl.stop(pdata); 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci return ret; 15098c2ecf20Sopenharmony_ci} 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_cistatic int xgbe_phy_reset(struct xgbe_prv_data *pdata) 15128c2ecf20Sopenharmony_ci{ 15138c2ecf20Sopenharmony_ci int ret; 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci ret = pdata->phy_if.phy_impl.reset(pdata); 15168c2ecf20Sopenharmony_ci if (ret) 15178c2ecf20Sopenharmony_ci return ret; 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci /* Disable auto-negotiation for now */ 15208c2ecf20Sopenharmony_ci xgbe_an_disable_all(pdata); 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci /* Clear auto-negotiation interrupts */ 15238c2ecf20Sopenharmony_ci xgbe_an_clear_interrupts_all(pdata); 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci return 0; 15268c2ecf20Sopenharmony_ci} 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_cistatic void xgbe_dump_phy_registers(struct xgbe_prv_data *pdata) 15298c2ecf20Sopenharmony_ci{ 15308c2ecf20Sopenharmony_ci struct device *dev = pdata->dev; 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci dev_dbg(dev, "\n************* PHY Reg dump **********************\n"); 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci dev_dbg(dev, "PCS Control Reg (%#06x) = %#06x\n", MDIO_CTRL1, 15358c2ecf20Sopenharmony_ci XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1)); 15368c2ecf20Sopenharmony_ci dev_dbg(dev, "PCS Status Reg (%#06x) = %#06x\n", MDIO_STAT1, 15378c2ecf20Sopenharmony_ci XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1)); 15388c2ecf20Sopenharmony_ci dev_dbg(dev, "Phy Id (PHYS ID 1 %#06x)= %#06x\n", MDIO_DEVID1, 15398c2ecf20Sopenharmony_ci XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_DEVID1)); 15408c2ecf20Sopenharmony_ci dev_dbg(dev, "Phy Id (PHYS ID 2 %#06x)= %#06x\n", MDIO_DEVID2, 15418c2ecf20Sopenharmony_ci XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_DEVID2)); 15428c2ecf20Sopenharmony_ci dev_dbg(dev, "Devices in Package (%#06x)= %#06x\n", MDIO_DEVS1, 15438c2ecf20Sopenharmony_ci XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_DEVS1)); 15448c2ecf20Sopenharmony_ci dev_dbg(dev, "Devices in Package (%#06x)= %#06x\n", MDIO_DEVS2, 15458c2ecf20Sopenharmony_ci XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_DEVS2)); 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci dev_dbg(dev, "Auto-Neg Control Reg (%#06x) = %#06x\n", MDIO_CTRL1, 15488c2ecf20Sopenharmony_ci XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_CTRL1)); 15498c2ecf20Sopenharmony_ci dev_dbg(dev, "Auto-Neg Status Reg (%#06x) = %#06x\n", MDIO_STAT1, 15508c2ecf20Sopenharmony_ci XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_STAT1)); 15518c2ecf20Sopenharmony_ci dev_dbg(dev, "Auto-Neg Ad Reg 1 (%#06x) = %#06x\n", 15528c2ecf20Sopenharmony_ci MDIO_AN_ADVERTISE, 15538c2ecf20Sopenharmony_ci XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE)); 15548c2ecf20Sopenharmony_ci dev_dbg(dev, "Auto-Neg Ad Reg 2 (%#06x) = %#06x\n", 15558c2ecf20Sopenharmony_ci MDIO_AN_ADVERTISE + 1, 15568c2ecf20Sopenharmony_ci XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1)); 15578c2ecf20Sopenharmony_ci dev_dbg(dev, "Auto-Neg Ad Reg 3 (%#06x) = %#06x\n", 15588c2ecf20Sopenharmony_ci MDIO_AN_ADVERTISE + 2, 15598c2ecf20Sopenharmony_ci XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2)); 15608c2ecf20Sopenharmony_ci dev_dbg(dev, "Auto-Neg Completion Reg (%#06x) = %#06x\n", 15618c2ecf20Sopenharmony_ci MDIO_AN_COMP_STAT, 15628c2ecf20Sopenharmony_ci XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_COMP_STAT)); 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_ci dev_dbg(dev, "\n*************************************************\n"); 15658c2ecf20Sopenharmony_ci} 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_cistatic int xgbe_phy_best_advertised_speed(struct xgbe_prv_data *pdata) 15688c2ecf20Sopenharmony_ci{ 15698c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *lks = &pdata->phy.lks; 15708c2ecf20Sopenharmony_ci 15718c2ecf20Sopenharmony_ci if (XGBE_ADV(lks, 10000baseKR_Full)) 15728c2ecf20Sopenharmony_ci return SPEED_10000; 15738c2ecf20Sopenharmony_ci else if (XGBE_ADV(lks, 10000baseT_Full)) 15748c2ecf20Sopenharmony_ci return SPEED_10000; 15758c2ecf20Sopenharmony_ci else if (XGBE_ADV(lks, 2500baseX_Full)) 15768c2ecf20Sopenharmony_ci return SPEED_2500; 15778c2ecf20Sopenharmony_ci else if (XGBE_ADV(lks, 2500baseT_Full)) 15788c2ecf20Sopenharmony_ci return SPEED_2500; 15798c2ecf20Sopenharmony_ci else if (XGBE_ADV(lks, 1000baseKX_Full)) 15808c2ecf20Sopenharmony_ci return SPEED_1000; 15818c2ecf20Sopenharmony_ci else if (XGBE_ADV(lks, 1000baseT_Full)) 15828c2ecf20Sopenharmony_ci return SPEED_1000; 15838c2ecf20Sopenharmony_ci else if (XGBE_ADV(lks, 100baseT_Full)) 15848c2ecf20Sopenharmony_ci return SPEED_100; 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci return SPEED_UNKNOWN; 15878c2ecf20Sopenharmony_ci} 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_cistatic void xgbe_phy_exit(struct xgbe_prv_data *pdata) 15908c2ecf20Sopenharmony_ci{ 15918c2ecf20Sopenharmony_ci pdata->phy_if.phy_impl.exit(pdata); 15928c2ecf20Sopenharmony_ci} 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_cistatic int xgbe_phy_init(struct xgbe_prv_data *pdata) 15958c2ecf20Sopenharmony_ci{ 15968c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *lks = &pdata->phy.lks; 15978c2ecf20Sopenharmony_ci int ret; 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci mutex_init(&pdata->an_mutex); 16008c2ecf20Sopenharmony_ci INIT_WORK(&pdata->an_irq_work, xgbe_an_irq_work); 16018c2ecf20Sopenharmony_ci INIT_WORK(&pdata->an_work, xgbe_an_state_machine); 16028c2ecf20Sopenharmony_ci pdata->mdio_mmd = MDIO_MMD_PCS; 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_ci /* Check for FEC support */ 16058c2ecf20Sopenharmony_ci pdata->fec_ability = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, 16068c2ecf20Sopenharmony_ci MDIO_PMA_10GBR_FECABLE); 16078c2ecf20Sopenharmony_ci pdata->fec_ability &= (MDIO_PMA_10GBR_FECABLE_ABLE | 16088c2ecf20Sopenharmony_ci MDIO_PMA_10GBR_FECABLE_ERRABLE); 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci /* Setup the phy (including supported features) */ 16118c2ecf20Sopenharmony_ci ret = pdata->phy_if.phy_impl.init(pdata); 16128c2ecf20Sopenharmony_ci if (ret) 16138c2ecf20Sopenharmony_ci return ret; 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ci /* Copy supported link modes to advertising link modes */ 16168c2ecf20Sopenharmony_ci XGBE_LM_COPY(lks, advertising, lks, supported); 16178c2ecf20Sopenharmony_ci 16188c2ecf20Sopenharmony_ci pdata->phy.address = 0; 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci if (XGBE_ADV(lks, Autoneg)) { 16218c2ecf20Sopenharmony_ci pdata->phy.autoneg = AUTONEG_ENABLE; 16228c2ecf20Sopenharmony_ci pdata->phy.speed = SPEED_UNKNOWN; 16238c2ecf20Sopenharmony_ci pdata->phy.duplex = DUPLEX_UNKNOWN; 16248c2ecf20Sopenharmony_ci } else { 16258c2ecf20Sopenharmony_ci pdata->phy.autoneg = AUTONEG_DISABLE; 16268c2ecf20Sopenharmony_ci pdata->phy.speed = xgbe_phy_best_advertised_speed(pdata); 16278c2ecf20Sopenharmony_ci pdata->phy.duplex = DUPLEX_FULL; 16288c2ecf20Sopenharmony_ci } 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ci pdata->phy.link = 0; 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci pdata->phy.pause_autoneg = pdata->pause_autoneg; 16338c2ecf20Sopenharmony_ci pdata->phy.tx_pause = pdata->tx_pause; 16348c2ecf20Sopenharmony_ci pdata->phy.rx_pause = pdata->rx_pause; 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_ci /* Fix up Flow Control advertising */ 16378c2ecf20Sopenharmony_ci XGBE_CLR_ADV(lks, Pause); 16388c2ecf20Sopenharmony_ci XGBE_CLR_ADV(lks, Asym_Pause); 16398c2ecf20Sopenharmony_ci 16408c2ecf20Sopenharmony_ci if (pdata->rx_pause) { 16418c2ecf20Sopenharmony_ci XGBE_SET_ADV(lks, Pause); 16428c2ecf20Sopenharmony_ci XGBE_SET_ADV(lks, Asym_Pause); 16438c2ecf20Sopenharmony_ci } 16448c2ecf20Sopenharmony_ci 16458c2ecf20Sopenharmony_ci if (pdata->tx_pause) { 16468c2ecf20Sopenharmony_ci /* Equivalent to XOR of Asym_Pause */ 16478c2ecf20Sopenharmony_ci if (XGBE_ADV(lks, Asym_Pause)) 16488c2ecf20Sopenharmony_ci XGBE_CLR_ADV(lks, Asym_Pause); 16498c2ecf20Sopenharmony_ci else 16508c2ecf20Sopenharmony_ci XGBE_SET_ADV(lks, Asym_Pause); 16518c2ecf20Sopenharmony_ci } 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci if (netif_msg_drv(pdata)) 16548c2ecf20Sopenharmony_ci xgbe_dump_phy_registers(pdata); 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci return 0; 16578c2ecf20Sopenharmony_ci} 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_civoid xgbe_init_function_ptrs_phy(struct xgbe_phy_if *phy_if) 16608c2ecf20Sopenharmony_ci{ 16618c2ecf20Sopenharmony_ci phy_if->phy_init = xgbe_phy_init; 16628c2ecf20Sopenharmony_ci phy_if->phy_exit = xgbe_phy_exit; 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_ci phy_if->phy_reset = xgbe_phy_reset; 16658c2ecf20Sopenharmony_ci phy_if->phy_start = xgbe_phy_start; 16668c2ecf20Sopenharmony_ci phy_if->phy_stop = xgbe_phy_stop; 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ci phy_if->phy_status = xgbe_phy_status; 16698c2ecf20Sopenharmony_ci phy_if->phy_config_aneg = xgbe_phy_config_aneg; 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci phy_if->phy_valid_speed = xgbe_phy_valid_speed; 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_ci phy_if->an_isr = xgbe_an_combined_isr; 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_ci phy_if->module_info = xgbe_phy_module_info; 16768c2ecf20Sopenharmony_ci phy_if->module_eeprom = xgbe_phy_module_eeprom; 16778c2ecf20Sopenharmony_ci} 1678