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) 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) 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/module.h> 1188c2ecf20Sopenharmony_ci#include <linux/device.h> 1198c2ecf20Sopenharmony_ci#include <linux/kmod.h> 1208c2ecf20Sopenharmony_ci#include <linux/mdio.h> 1218c2ecf20Sopenharmony_ci#include <linux/phy.h> 1228c2ecf20Sopenharmony_ci#include <linux/ethtool.h> 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci#include "xgbe.h" 1258c2ecf20Sopenharmony_ci#include "xgbe-common.h" 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci#define XGBE_PHY_PORT_SPEED_100 BIT(0) 1288c2ecf20Sopenharmony_ci#define XGBE_PHY_PORT_SPEED_1000 BIT(1) 1298c2ecf20Sopenharmony_ci#define XGBE_PHY_PORT_SPEED_2500 BIT(2) 1308c2ecf20Sopenharmony_ci#define XGBE_PHY_PORT_SPEED_10000 BIT(3) 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci#define XGBE_MUTEX_RELEASE 0x80000000 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci#define XGBE_SFP_DIRECT 7 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci/* I2C target addresses */ 1378c2ecf20Sopenharmony_ci#define XGBE_SFP_SERIAL_ID_ADDRESS 0x50 1388c2ecf20Sopenharmony_ci#define XGBE_SFP_DIAG_INFO_ADDRESS 0x51 1398c2ecf20Sopenharmony_ci#define XGBE_SFP_PHY_ADDRESS 0x56 1408c2ecf20Sopenharmony_ci#define XGBE_GPIO_ADDRESS_PCA9555 0x20 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci/* SFP sideband signal indicators */ 1438c2ecf20Sopenharmony_ci#define XGBE_GPIO_NO_TX_FAULT BIT(0) 1448c2ecf20Sopenharmony_ci#define XGBE_GPIO_NO_RATE_SELECT BIT(1) 1458c2ecf20Sopenharmony_ci#define XGBE_GPIO_NO_MOD_ABSENT BIT(2) 1468c2ecf20Sopenharmony_ci#define XGBE_GPIO_NO_RX_LOS BIT(3) 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci/* Rate-change complete wait/retry count */ 1498c2ecf20Sopenharmony_ci#define XGBE_RATECHANGE_COUNT 500 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci/* CDR delay values for KR support (in usec) */ 1528c2ecf20Sopenharmony_ci#define XGBE_CDR_DELAY_INIT 10000 1538c2ecf20Sopenharmony_ci#define XGBE_CDR_DELAY_INC 10000 1548c2ecf20Sopenharmony_ci#define XGBE_CDR_DELAY_MAX 100000 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci/* RRC frequency during link status check */ 1578c2ecf20Sopenharmony_ci#define XGBE_RRC_FREQUENCY 10 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_cienum xgbe_port_mode { 1608c2ecf20Sopenharmony_ci XGBE_PORT_MODE_RSVD = 0, 1618c2ecf20Sopenharmony_ci XGBE_PORT_MODE_BACKPLANE, 1628c2ecf20Sopenharmony_ci XGBE_PORT_MODE_BACKPLANE_2500, 1638c2ecf20Sopenharmony_ci XGBE_PORT_MODE_1000BASE_T, 1648c2ecf20Sopenharmony_ci XGBE_PORT_MODE_1000BASE_X, 1658c2ecf20Sopenharmony_ci XGBE_PORT_MODE_NBASE_T, 1668c2ecf20Sopenharmony_ci XGBE_PORT_MODE_10GBASE_T, 1678c2ecf20Sopenharmony_ci XGBE_PORT_MODE_10GBASE_R, 1688c2ecf20Sopenharmony_ci XGBE_PORT_MODE_SFP, 1698c2ecf20Sopenharmony_ci XGBE_PORT_MODE_BACKPLANE_NO_AUTONEG, 1708c2ecf20Sopenharmony_ci XGBE_PORT_MODE_MAX, 1718c2ecf20Sopenharmony_ci}; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cienum xgbe_conn_type { 1748c2ecf20Sopenharmony_ci XGBE_CONN_TYPE_NONE = 0, 1758c2ecf20Sopenharmony_ci XGBE_CONN_TYPE_SFP, 1768c2ecf20Sopenharmony_ci XGBE_CONN_TYPE_MDIO, 1778c2ecf20Sopenharmony_ci XGBE_CONN_TYPE_RSVD1, 1788c2ecf20Sopenharmony_ci XGBE_CONN_TYPE_BACKPLANE, 1798c2ecf20Sopenharmony_ci XGBE_CONN_TYPE_MAX, 1808c2ecf20Sopenharmony_ci}; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci/* SFP/SFP+ related definitions */ 1838c2ecf20Sopenharmony_cienum xgbe_sfp_comm { 1848c2ecf20Sopenharmony_ci XGBE_SFP_COMM_DIRECT = 0, 1858c2ecf20Sopenharmony_ci XGBE_SFP_COMM_PCA9545, 1868c2ecf20Sopenharmony_ci}; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cienum xgbe_sfp_cable { 1898c2ecf20Sopenharmony_ci XGBE_SFP_CABLE_UNKNOWN = 0, 1908c2ecf20Sopenharmony_ci XGBE_SFP_CABLE_ACTIVE, 1918c2ecf20Sopenharmony_ci XGBE_SFP_CABLE_PASSIVE, 1928c2ecf20Sopenharmony_ci XGBE_SFP_CABLE_FIBER, 1938c2ecf20Sopenharmony_ci}; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cienum xgbe_sfp_base { 1968c2ecf20Sopenharmony_ci XGBE_SFP_BASE_UNKNOWN = 0, 1978c2ecf20Sopenharmony_ci XGBE_SFP_BASE_1000_T, 1988c2ecf20Sopenharmony_ci XGBE_SFP_BASE_1000_SX, 1998c2ecf20Sopenharmony_ci XGBE_SFP_BASE_1000_LX, 2008c2ecf20Sopenharmony_ci XGBE_SFP_BASE_1000_CX, 2018c2ecf20Sopenharmony_ci XGBE_SFP_BASE_10000_SR, 2028c2ecf20Sopenharmony_ci XGBE_SFP_BASE_10000_LR, 2038c2ecf20Sopenharmony_ci XGBE_SFP_BASE_10000_LRM, 2048c2ecf20Sopenharmony_ci XGBE_SFP_BASE_10000_ER, 2058c2ecf20Sopenharmony_ci XGBE_SFP_BASE_10000_CR, 2068c2ecf20Sopenharmony_ci}; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cienum xgbe_sfp_speed { 2098c2ecf20Sopenharmony_ci XGBE_SFP_SPEED_UNKNOWN = 0, 2108c2ecf20Sopenharmony_ci XGBE_SFP_SPEED_100_1000, 2118c2ecf20Sopenharmony_ci XGBE_SFP_SPEED_1000, 2128c2ecf20Sopenharmony_ci XGBE_SFP_SPEED_10000, 2138c2ecf20Sopenharmony_ci}; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci/* SFP Serial ID Base ID values relative to an offset of 0 */ 2168c2ecf20Sopenharmony_ci#define XGBE_SFP_BASE_ID 0 2178c2ecf20Sopenharmony_ci#define XGBE_SFP_ID_SFP 0x03 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci#define XGBE_SFP_BASE_EXT_ID 1 2208c2ecf20Sopenharmony_ci#define XGBE_SFP_EXT_ID_SFP 0x04 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci#define XGBE_SFP_BASE_10GBE_CC 3 2238c2ecf20Sopenharmony_ci#define XGBE_SFP_BASE_10GBE_CC_SR BIT(4) 2248c2ecf20Sopenharmony_ci#define XGBE_SFP_BASE_10GBE_CC_LR BIT(5) 2258c2ecf20Sopenharmony_ci#define XGBE_SFP_BASE_10GBE_CC_LRM BIT(6) 2268c2ecf20Sopenharmony_ci#define XGBE_SFP_BASE_10GBE_CC_ER BIT(7) 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci#define XGBE_SFP_BASE_1GBE_CC 6 2298c2ecf20Sopenharmony_ci#define XGBE_SFP_BASE_1GBE_CC_SX BIT(0) 2308c2ecf20Sopenharmony_ci#define XGBE_SFP_BASE_1GBE_CC_LX BIT(1) 2318c2ecf20Sopenharmony_ci#define XGBE_SFP_BASE_1GBE_CC_CX BIT(2) 2328c2ecf20Sopenharmony_ci#define XGBE_SFP_BASE_1GBE_CC_T BIT(3) 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci#define XGBE_SFP_BASE_CABLE 8 2358c2ecf20Sopenharmony_ci#define XGBE_SFP_BASE_CABLE_PASSIVE BIT(2) 2368c2ecf20Sopenharmony_ci#define XGBE_SFP_BASE_CABLE_ACTIVE BIT(3) 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci#define XGBE_SFP_BASE_BR 12 2398c2ecf20Sopenharmony_ci#define XGBE_SFP_BASE_BR_1GBE_MIN 0x0a 2408c2ecf20Sopenharmony_ci#define XGBE_SFP_BASE_BR_10GBE_MIN 0x64 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci#define XGBE_SFP_BASE_CU_CABLE_LEN 18 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci#define XGBE_SFP_BASE_VENDOR_NAME 20 2458c2ecf20Sopenharmony_ci#define XGBE_SFP_BASE_VENDOR_NAME_LEN 16 2468c2ecf20Sopenharmony_ci#define XGBE_SFP_BASE_VENDOR_PN 40 2478c2ecf20Sopenharmony_ci#define XGBE_SFP_BASE_VENDOR_PN_LEN 16 2488c2ecf20Sopenharmony_ci#define XGBE_SFP_BASE_VENDOR_REV 56 2498c2ecf20Sopenharmony_ci#define XGBE_SFP_BASE_VENDOR_REV_LEN 4 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci#define XGBE_SFP_BASE_CC 63 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci/* SFP Serial ID Extended ID values relative to an offset of 64 */ 2548c2ecf20Sopenharmony_ci#define XGBE_SFP_BASE_VENDOR_SN 4 2558c2ecf20Sopenharmony_ci#define XGBE_SFP_BASE_VENDOR_SN_LEN 16 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci#define XGBE_SFP_EXTD_OPT1 1 2588c2ecf20Sopenharmony_ci#define XGBE_SFP_EXTD_OPT1_RX_LOS BIT(1) 2598c2ecf20Sopenharmony_ci#define XGBE_SFP_EXTD_OPT1_TX_FAULT BIT(3) 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci#define XGBE_SFP_EXTD_DIAG 28 2628c2ecf20Sopenharmony_ci#define XGBE_SFP_EXTD_DIAG_ADDR_CHANGE BIT(2) 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci#define XGBE_SFP_EXTD_SFF_8472 30 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci#define XGBE_SFP_EXTD_CC 31 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_cistruct xgbe_sfp_eeprom { 2698c2ecf20Sopenharmony_ci u8 base[64]; 2708c2ecf20Sopenharmony_ci u8 extd[32]; 2718c2ecf20Sopenharmony_ci u8 vendor[32]; 2728c2ecf20Sopenharmony_ci}; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci#define XGBE_SFP_DIAGS_SUPPORTED(_x) \ 2758c2ecf20Sopenharmony_ci ((_x)->extd[XGBE_SFP_EXTD_SFF_8472] && \ 2768c2ecf20Sopenharmony_ci !((_x)->extd[XGBE_SFP_EXTD_DIAG] & XGBE_SFP_EXTD_DIAG_ADDR_CHANGE)) 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci#define XGBE_SFP_EEPROM_BASE_LEN 256 2798c2ecf20Sopenharmony_ci#define XGBE_SFP_EEPROM_DIAG_LEN 256 2808c2ecf20Sopenharmony_ci#define XGBE_SFP_EEPROM_MAX (XGBE_SFP_EEPROM_BASE_LEN + \ 2818c2ecf20Sopenharmony_ci XGBE_SFP_EEPROM_DIAG_LEN) 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci#define XGBE_BEL_FUSE_VENDOR "BEL-FUSE " 2848c2ecf20Sopenharmony_ci#define XGBE_BEL_FUSE_PARTNO "1GBT-SFP06 " 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci#define XGBE_MOLEX_VENDOR "Molex Inc. " 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_cistruct xgbe_sfp_ascii { 2898c2ecf20Sopenharmony_ci union { 2908c2ecf20Sopenharmony_ci char vendor[XGBE_SFP_BASE_VENDOR_NAME_LEN + 1]; 2918c2ecf20Sopenharmony_ci char partno[XGBE_SFP_BASE_VENDOR_PN_LEN + 1]; 2928c2ecf20Sopenharmony_ci char rev[XGBE_SFP_BASE_VENDOR_REV_LEN + 1]; 2938c2ecf20Sopenharmony_ci char serno[XGBE_SFP_BASE_VENDOR_SN_LEN + 1]; 2948c2ecf20Sopenharmony_ci } u; 2958c2ecf20Sopenharmony_ci}; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci/* MDIO PHY reset types */ 2988c2ecf20Sopenharmony_cienum xgbe_mdio_reset { 2998c2ecf20Sopenharmony_ci XGBE_MDIO_RESET_NONE = 0, 3008c2ecf20Sopenharmony_ci XGBE_MDIO_RESET_I2C_GPIO, 3018c2ecf20Sopenharmony_ci XGBE_MDIO_RESET_INT_GPIO, 3028c2ecf20Sopenharmony_ci XGBE_MDIO_RESET_MAX, 3038c2ecf20Sopenharmony_ci}; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci/* Re-driver related definitions */ 3068c2ecf20Sopenharmony_cienum xgbe_phy_redrv_if { 3078c2ecf20Sopenharmony_ci XGBE_PHY_REDRV_IF_MDIO = 0, 3088c2ecf20Sopenharmony_ci XGBE_PHY_REDRV_IF_I2C, 3098c2ecf20Sopenharmony_ci XGBE_PHY_REDRV_IF_MAX, 3108c2ecf20Sopenharmony_ci}; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_cienum xgbe_phy_redrv_model { 3138c2ecf20Sopenharmony_ci XGBE_PHY_REDRV_MODEL_4223 = 0, 3148c2ecf20Sopenharmony_ci XGBE_PHY_REDRV_MODEL_4227, 3158c2ecf20Sopenharmony_ci XGBE_PHY_REDRV_MODEL_MAX, 3168c2ecf20Sopenharmony_ci}; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_cienum xgbe_phy_redrv_mode { 3198c2ecf20Sopenharmony_ci XGBE_PHY_REDRV_MODE_CX = 5, 3208c2ecf20Sopenharmony_ci XGBE_PHY_REDRV_MODE_SR = 9, 3218c2ecf20Sopenharmony_ci}; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci#define XGBE_PHY_REDRV_MODE_REG 0x12b0 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci/* PHY related configuration information */ 3268c2ecf20Sopenharmony_cistruct xgbe_phy_data { 3278c2ecf20Sopenharmony_ci enum xgbe_port_mode port_mode; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci unsigned int port_id; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci unsigned int port_speeds; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci enum xgbe_conn_type conn_type; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci enum xgbe_mode cur_mode; 3368c2ecf20Sopenharmony_ci enum xgbe_mode start_mode; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci unsigned int rrc_count; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci unsigned int mdio_addr; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci /* SFP Support */ 3438c2ecf20Sopenharmony_ci enum xgbe_sfp_comm sfp_comm; 3448c2ecf20Sopenharmony_ci unsigned int sfp_mux_address; 3458c2ecf20Sopenharmony_ci unsigned int sfp_mux_channel; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci unsigned int sfp_gpio_address; 3488c2ecf20Sopenharmony_ci unsigned int sfp_gpio_mask; 3498c2ecf20Sopenharmony_ci unsigned int sfp_gpio_inputs; 3508c2ecf20Sopenharmony_ci unsigned int sfp_gpio_rx_los; 3518c2ecf20Sopenharmony_ci unsigned int sfp_gpio_tx_fault; 3528c2ecf20Sopenharmony_ci unsigned int sfp_gpio_mod_absent; 3538c2ecf20Sopenharmony_ci unsigned int sfp_gpio_rate_select; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci unsigned int sfp_rx_los; 3568c2ecf20Sopenharmony_ci unsigned int sfp_tx_fault; 3578c2ecf20Sopenharmony_ci unsigned int sfp_mod_absent; 3588c2ecf20Sopenharmony_ci unsigned int sfp_changed; 3598c2ecf20Sopenharmony_ci unsigned int sfp_phy_avail; 3608c2ecf20Sopenharmony_ci unsigned int sfp_cable_len; 3618c2ecf20Sopenharmony_ci enum xgbe_sfp_base sfp_base; 3628c2ecf20Sopenharmony_ci enum xgbe_sfp_cable sfp_cable; 3638c2ecf20Sopenharmony_ci enum xgbe_sfp_speed sfp_speed; 3648c2ecf20Sopenharmony_ci struct xgbe_sfp_eeprom sfp_eeprom; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci /* External PHY support */ 3678c2ecf20Sopenharmony_ci enum xgbe_mdio_mode phydev_mode; 3688c2ecf20Sopenharmony_ci struct mii_bus *mii; 3698c2ecf20Sopenharmony_ci struct phy_device *phydev; 3708c2ecf20Sopenharmony_ci enum xgbe_mdio_reset mdio_reset; 3718c2ecf20Sopenharmony_ci unsigned int mdio_reset_addr; 3728c2ecf20Sopenharmony_ci unsigned int mdio_reset_gpio; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci /* Re-driver support */ 3758c2ecf20Sopenharmony_ci unsigned int redrv; 3768c2ecf20Sopenharmony_ci unsigned int redrv_if; 3778c2ecf20Sopenharmony_ci unsigned int redrv_addr; 3788c2ecf20Sopenharmony_ci unsigned int redrv_lane; 3798c2ecf20Sopenharmony_ci unsigned int redrv_model; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci /* KR AN support */ 3828c2ecf20Sopenharmony_ci unsigned int phy_cdr_notrack; 3838c2ecf20Sopenharmony_ci unsigned int phy_cdr_delay; 3848c2ecf20Sopenharmony_ci}; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci/* I2C, MDIO and GPIO lines are muxed, so only one device at a time */ 3878c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(xgbe_phy_comm_lock); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_cistatic enum xgbe_an_mode xgbe_phy_an_mode(struct xgbe_prv_data *pdata); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_cistatic int xgbe_phy_i2c_xfer(struct xgbe_prv_data *pdata, 3928c2ecf20Sopenharmony_ci struct xgbe_i2c_op *i2c_op) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci return pdata->i2c_if.i2c_xfer(pdata, i2c_op); 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_cistatic int xgbe_phy_redrv_write(struct xgbe_prv_data *pdata, unsigned int reg, 3988c2ecf20Sopenharmony_ci unsigned int val) 3998c2ecf20Sopenharmony_ci{ 4008c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 4018c2ecf20Sopenharmony_ci struct xgbe_i2c_op i2c_op; 4028c2ecf20Sopenharmony_ci __be16 *redrv_val; 4038c2ecf20Sopenharmony_ci u8 redrv_data[5], csum; 4048c2ecf20Sopenharmony_ci unsigned int i, retry; 4058c2ecf20Sopenharmony_ci int ret; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci /* High byte of register contains read/write indicator */ 4088c2ecf20Sopenharmony_ci redrv_data[0] = ((reg >> 8) & 0xff) << 1; 4098c2ecf20Sopenharmony_ci redrv_data[1] = reg & 0xff; 4108c2ecf20Sopenharmony_ci redrv_val = (__be16 *)&redrv_data[2]; 4118c2ecf20Sopenharmony_ci *redrv_val = cpu_to_be16(val); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci /* Calculate 1 byte checksum */ 4148c2ecf20Sopenharmony_ci csum = 0; 4158c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 4168c2ecf20Sopenharmony_ci csum += redrv_data[i]; 4178c2ecf20Sopenharmony_ci if (redrv_data[i] > csum) 4188c2ecf20Sopenharmony_ci csum++; 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci redrv_data[4] = ~csum; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci retry = 1; 4238c2ecf20Sopenharmony_ciagain1: 4248c2ecf20Sopenharmony_ci i2c_op.cmd = XGBE_I2C_CMD_WRITE; 4258c2ecf20Sopenharmony_ci i2c_op.target = phy_data->redrv_addr; 4268c2ecf20Sopenharmony_ci i2c_op.len = sizeof(redrv_data); 4278c2ecf20Sopenharmony_ci i2c_op.buf = redrv_data; 4288c2ecf20Sopenharmony_ci ret = xgbe_phy_i2c_xfer(pdata, &i2c_op); 4298c2ecf20Sopenharmony_ci if (ret) { 4308c2ecf20Sopenharmony_ci if ((ret == -EAGAIN) && retry--) 4318c2ecf20Sopenharmony_ci goto again1; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci return ret; 4348c2ecf20Sopenharmony_ci } 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci retry = 1; 4378c2ecf20Sopenharmony_ciagain2: 4388c2ecf20Sopenharmony_ci i2c_op.cmd = XGBE_I2C_CMD_READ; 4398c2ecf20Sopenharmony_ci i2c_op.target = phy_data->redrv_addr; 4408c2ecf20Sopenharmony_ci i2c_op.len = 1; 4418c2ecf20Sopenharmony_ci i2c_op.buf = redrv_data; 4428c2ecf20Sopenharmony_ci ret = xgbe_phy_i2c_xfer(pdata, &i2c_op); 4438c2ecf20Sopenharmony_ci if (ret) { 4448c2ecf20Sopenharmony_ci if ((ret == -EAGAIN) && retry--) 4458c2ecf20Sopenharmony_ci goto again2; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci return ret; 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci if (redrv_data[0] != 0xff) { 4518c2ecf20Sopenharmony_ci netif_dbg(pdata, drv, pdata->netdev, 4528c2ecf20Sopenharmony_ci "Redriver write checksum error\n"); 4538c2ecf20Sopenharmony_ci ret = -EIO; 4548c2ecf20Sopenharmony_ci } 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci return ret; 4578c2ecf20Sopenharmony_ci} 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_cistatic int xgbe_phy_i2c_write(struct xgbe_prv_data *pdata, unsigned int target, 4608c2ecf20Sopenharmony_ci void *val, unsigned int val_len) 4618c2ecf20Sopenharmony_ci{ 4628c2ecf20Sopenharmony_ci struct xgbe_i2c_op i2c_op; 4638c2ecf20Sopenharmony_ci int retry, ret; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci retry = 1; 4668c2ecf20Sopenharmony_ciagain: 4678c2ecf20Sopenharmony_ci /* Write the specfied register */ 4688c2ecf20Sopenharmony_ci i2c_op.cmd = XGBE_I2C_CMD_WRITE; 4698c2ecf20Sopenharmony_ci i2c_op.target = target; 4708c2ecf20Sopenharmony_ci i2c_op.len = val_len; 4718c2ecf20Sopenharmony_ci i2c_op.buf = val; 4728c2ecf20Sopenharmony_ci ret = xgbe_phy_i2c_xfer(pdata, &i2c_op); 4738c2ecf20Sopenharmony_ci if ((ret == -EAGAIN) && retry--) 4748c2ecf20Sopenharmony_ci goto again; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci return ret; 4778c2ecf20Sopenharmony_ci} 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_cistatic int xgbe_phy_i2c_read(struct xgbe_prv_data *pdata, unsigned int target, 4808c2ecf20Sopenharmony_ci void *reg, unsigned int reg_len, 4818c2ecf20Sopenharmony_ci void *val, unsigned int val_len) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci struct xgbe_i2c_op i2c_op; 4848c2ecf20Sopenharmony_ci int retry, ret; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci retry = 1; 4878c2ecf20Sopenharmony_ciagain1: 4888c2ecf20Sopenharmony_ci /* Set the specified register to read */ 4898c2ecf20Sopenharmony_ci i2c_op.cmd = XGBE_I2C_CMD_WRITE; 4908c2ecf20Sopenharmony_ci i2c_op.target = target; 4918c2ecf20Sopenharmony_ci i2c_op.len = reg_len; 4928c2ecf20Sopenharmony_ci i2c_op.buf = reg; 4938c2ecf20Sopenharmony_ci ret = xgbe_phy_i2c_xfer(pdata, &i2c_op); 4948c2ecf20Sopenharmony_ci if (ret) { 4958c2ecf20Sopenharmony_ci if ((ret == -EAGAIN) && retry--) 4968c2ecf20Sopenharmony_ci goto again1; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci return ret; 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci retry = 1; 5028c2ecf20Sopenharmony_ciagain2: 5038c2ecf20Sopenharmony_ci /* Read the specfied register */ 5048c2ecf20Sopenharmony_ci i2c_op.cmd = XGBE_I2C_CMD_READ; 5058c2ecf20Sopenharmony_ci i2c_op.target = target; 5068c2ecf20Sopenharmony_ci i2c_op.len = val_len; 5078c2ecf20Sopenharmony_ci i2c_op.buf = val; 5088c2ecf20Sopenharmony_ci ret = xgbe_phy_i2c_xfer(pdata, &i2c_op); 5098c2ecf20Sopenharmony_ci if ((ret == -EAGAIN) && retry--) 5108c2ecf20Sopenharmony_ci goto again2; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci return ret; 5138c2ecf20Sopenharmony_ci} 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_cistatic int xgbe_phy_sfp_put_mux(struct xgbe_prv_data *pdata) 5168c2ecf20Sopenharmony_ci{ 5178c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 5188c2ecf20Sopenharmony_ci struct xgbe_i2c_op i2c_op; 5198c2ecf20Sopenharmony_ci u8 mux_channel; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci if (phy_data->sfp_comm == XGBE_SFP_COMM_DIRECT) 5228c2ecf20Sopenharmony_ci return 0; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci /* Select no mux channels */ 5258c2ecf20Sopenharmony_ci mux_channel = 0; 5268c2ecf20Sopenharmony_ci i2c_op.cmd = XGBE_I2C_CMD_WRITE; 5278c2ecf20Sopenharmony_ci i2c_op.target = phy_data->sfp_mux_address; 5288c2ecf20Sopenharmony_ci i2c_op.len = sizeof(mux_channel); 5298c2ecf20Sopenharmony_ci i2c_op.buf = &mux_channel; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci return xgbe_phy_i2c_xfer(pdata, &i2c_op); 5328c2ecf20Sopenharmony_ci} 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_cistatic int xgbe_phy_sfp_get_mux(struct xgbe_prv_data *pdata) 5358c2ecf20Sopenharmony_ci{ 5368c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 5378c2ecf20Sopenharmony_ci struct xgbe_i2c_op i2c_op; 5388c2ecf20Sopenharmony_ci u8 mux_channel; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci if (phy_data->sfp_comm == XGBE_SFP_COMM_DIRECT) 5418c2ecf20Sopenharmony_ci return 0; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci /* Select desired mux channel */ 5448c2ecf20Sopenharmony_ci mux_channel = 1 << phy_data->sfp_mux_channel; 5458c2ecf20Sopenharmony_ci i2c_op.cmd = XGBE_I2C_CMD_WRITE; 5468c2ecf20Sopenharmony_ci i2c_op.target = phy_data->sfp_mux_address; 5478c2ecf20Sopenharmony_ci i2c_op.len = sizeof(mux_channel); 5488c2ecf20Sopenharmony_ci i2c_op.buf = &mux_channel; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci return xgbe_phy_i2c_xfer(pdata, &i2c_op); 5518c2ecf20Sopenharmony_ci} 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_cistatic void xgbe_phy_put_comm_ownership(struct xgbe_prv_data *pdata) 5548c2ecf20Sopenharmony_ci{ 5558c2ecf20Sopenharmony_ci mutex_unlock(&xgbe_phy_comm_lock); 5568c2ecf20Sopenharmony_ci} 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_cistatic int xgbe_phy_get_comm_ownership(struct xgbe_prv_data *pdata) 5598c2ecf20Sopenharmony_ci{ 5608c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 5618c2ecf20Sopenharmony_ci unsigned long timeout; 5628c2ecf20Sopenharmony_ci unsigned int mutex_id; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci /* The I2C and MDIO/GPIO bus is multiplexed between multiple devices, 5658c2ecf20Sopenharmony_ci * the driver needs to take the software mutex and then the hardware 5668c2ecf20Sopenharmony_ci * mutexes before being able to use the busses. 5678c2ecf20Sopenharmony_ci */ 5688c2ecf20Sopenharmony_ci mutex_lock(&xgbe_phy_comm_lock); 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci /* Clear the mutexes */ 5718c2ecf20Sopenharmony_ci XP_IOWRITE(pdata, XP_I2C_MUTEX, XGBE_MUTEX_RELEASE); 5728c2ecf20Sopenharmony_ci XP_IOWRITE(pdata, XP_MDIO_MUTEX, XGBE_MUTEX_RELEASE); 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci /* Mutex formats are the same for I2C and MDIO/GPIO */ 5758c2ecf20Sopenharmony_ci mutex_id = 0; 5768c2ecf20Sopenharmony_ci XP_SET_BITS(mutex_id, XP_I2C_MUTEX, ID, phy_data->port_id); 5778c2ecf20Sopenharmony_ci XP_SET_BITS(mutex_id, XP_I2C_MUTEX, ACTIVE, 1); 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci timeout = jiffies + (5 * HZ); 5808c2ecf20Sopenharmony_ci while (time_before(jiffies, timeout)) { 5818c2ecf20Sopenharmony_ci /* Must be all zeroes in order to obtain the mutex */ 5828c2ecf20Sopenharmony_ci if (XP_IOREAD(pdata, XP_I2C_MUTEX) || 5838c2ecf20Sopenharmony_ci XP_IOREAD(pdata, XP_MDIO_MUTEX)) { 5848c2ecf20Sopenharmony_ci usleep_range(100, 200); 5858c2ecf20Sopenharmony_ci continue; 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci /* Obtain the mutex */ 5898c2ecf20Sopenharmony_ci XP_IOWRITE(pdata, XP_I2C_MUTEX, mutex_id); 5908c2ecf20Sopenharmony_ci XP_IOWRITE(pdata, XP_MDIO_MUTEX, mutex_id); 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci return 0; 5938c2ecf20Sopenharmony_ci } 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci mutex_unlock(&xgbe_phy_comm_lock); 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci netdev_err(pdata->netdev, "unable to obtain hardware mutexes\n"); 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci return -ETIMEDOUT; 6008c2ecf20Sopenharmony_ci} 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_cistatic int xgbe_phy_mdio_mii_write(struct xgbe_prv_data *pdata, int addr, 6038c2ecf20Sopenharmony_ci int reg, u16 val) 6048c2ecf20Sopenharmony_ci{ 6058c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci if (reg & MII_ADDR_C45) { 6088c2ecf20Sopenharmony_ci if (phy_data->phydev_mode != XGBE_MDIO_MODE_CL45) 6098c2ecf20Sopenharmony_ci return -ENOTSUPP; 6108c2ecf20Sopenharmony_ci } else { 6118c2ecf20Sopenharmony_ci if (phy_data->phydev_mode != XGBE_MDIO_MODE_CL22) 6128c2ecf20Sopenharmony_ci return -ENOTSUPP; 6138c2ecf20Sopenharmony_ci } 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci return pdata->hw_if.write_ext_mii_regs(pdata, addr, reg, val); 6168c2ecf20Sopenharmony_ci} 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_cistatic int xgbe_phy_i2c_mii_write(struct xgbe_prv_data *pdata, int reg, u16 val) 6198c2ecf20Sopenharmony_ci{ 6208c2ecf20Sopenharmony_ci __be16 *mii_val; 6218c2ecf20Sopenharmony_ci u8 mii_data[3]; 6228c2ecf20Sopenharmony_ci int ret; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci ret = xgbe_phy_sfp_get_mux(pdata); 6258c2ecf20Sopenharmony_ci if (ret) 6268c2ecf20Sopenharmony_ci return ret; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci mii_data[0] = reg & 0xff; 6298c2ecf20Sopenharmony_ci mii_val = (__be16 *)&mii_data[1]; 6308c2ecf20Sopenharmony_ci *mii_val = cpu_to_be16(val); 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci ret = xgbe_phy_i2c_write(pdata, XGBE_SFP_PHY_ADDRESS, 6338c2ecf20Sopenharmony_ci mii_data, sizeof(mii_data)); 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci xgbe_phy_sfp_put_mux(pdata); 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci return ret; 6388c2ecf20Sopenharmony_ci} 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_cistatic int xgbe_phy_mii_write(struct mii_bus *mii, int addr, int reg, u16 val) 6418c2ecf20Sopenharmony_ci{ 6428c2ecf20Sopenharmony_ci struct xgbe_prv_data *pdata = mii->priv; 6438c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 6448c2ecf20Sopenharmony_ci int ret; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci ret = xgbe_phy_get_comm_ownership(pdata); 6478c2ecf20Sopenharmony_ci if (ret) 6488c2ecf20Sopenharmony_ci return ret; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci if (phy_data->conn_type == XGBE_CONN_TYPE_SFP) 6518c2ecf20Sopenharmony_ci ret = xgbe_phy_i2c_mii_write(pdata, reg, val); 6528c2ecf20Sopenharmony_ci else if (phy_data->conn_type & XGBE_CONN_TYPE_MDIO) 6538c2ecf20Sopenharmony_ci ret = xgbe_phy_mdio_mii_write(pdata, addr, reg, val); 6548c2ecf20Sopenharmony_ci else 6558c2ecf20Sopenharmony_ci ret = -ENOTSUPP; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci xgbe_phy_put_comm_ownership(pdata); 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci return ret; 6608c2ecf20Sopenharmony_ci} 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_cistatic int xgbe_phy_mdio_mii_read(struct xgbe_prv_data *pdata, int addr, 6638c2ecf20Sopenharmony_ci int reg) 6648c2ecf20Sopenharmony_ci{ 6658c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci if (reg & MII_ADDR_C45) { 6688c2ecf20Sopenharmony_ci if (phy_data->phydev_mode != XGBE_MDIO_MODE_CL45) 6698c2ecf20Sopenharmony_ci return -ENOTSUPP; 6708c2ecf20Sopenharmony_ci } else { 6718c2ecf20Sopenharmony_ci if (phy_data->phydev_mode != XGBE_MDIO_MODE_CL22) 6728c2ecf20Sopenharmony_ci return -ENOTSUPP; 6738c2ecf20Sopenharmony_ci } 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci return pdata->hw_if.read_ext_mii_regs(pdata, addr, reg); 6768c2ecf20Sopenharmony_ci} 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_cistatic int xgbe_phy_i2c_mii_read(struct xgbe_prv_data *pdata, int reg) 6798c2ecf20Sopenharmony_ci{ 6808c2ecf20Sopenharmony_ci __be16 mii_val; 6818c2ecf20Sopenharmony_ci u8 mii_reg; 6828c2ecf20Sopenharmony_ci int ret; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci ret = xgbe_phy_sfp_get_mux(pdata); 6858c2ecf20Sopenharmony_ci if (ret) 6868c2ecf20Sopenharmony_ci return ret; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci mii_reg = reg; 6898c2ecf20Sopenharmony_ci ret = xgbe_phy_i2c_read(pdata, XGBE_SFP_PHY_ADDRESS, 6908c2ecf20Sopenharmony_ci &mii_reg, sizeof(mii_reg), 6918c2ecf20Sopenharmony_ci &mii_val, sizeof(mii_val)); 6928c2ecf20Sopenharmony_ci if (!ret) 6938c2ecf20Sopenharmony_ci ret = be16_to_cpu(mii_val); 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci xgbe_phy_sfp_put_mux(pdata); 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci return ret; 6988c2ecf20Sopenharmony_ci} 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_cistatic int xgbe_phy_mii_read(struct mii_bus *mii, int addr, int reg) 7018c2ecf20Sopenharmony_ci{ 7028c2ecf20Sopenharmony_ci struct xgbe_prv_data *pdata = mii->priv; 7038c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 7048c2ecf20Sopenharmony_ci int ret; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci ret = xgbe_phy_get_comm_ownership(pdata); 7078c2ecf20Sopenharmony_ci if (ret) 7088c2ecf20Sopenharmony_ci return ret; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci if (phy_data->conn_type == XGBE_CONN_TYPE_SFP) 7118c2ecf20Sopenharmony_ci ret = xgbe_phy_i2c_mii_read(pdata, reg); 7128c2ecf20Sopenharmony_ci else if (phy_data->conn_type & XGBE_CONN_TYPE_MDIO) 7138c2ecf20Sopenharmony_ci ret = xgbe_phy_mdio_mii_read(pdata, addr, reg); 7148c2ecf20Sopenharmony_ci else 7158c2ecf20Sopenharmony_ci ret = -ENOTSUPP; 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci xgbe_phy_put_comm_ownership(pdata); 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci return ret; 7208c2ecf20Sopenharmony_ci} 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_cistatic void xgbe_phy_sfp_phy_settings(struct xgbe_prv_data *pdata) 7238c2ecf20Sopenharmony_ci{ 7248c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *lks = &pdata->phy.lks; 7258c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci if (!phy_data->sfp_mod_absent && !phy_data->sfp_changed) 7288c2ecf20Sopenharmony_ci return; 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci XGBE_ZERO_SUP(lks); 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci if (phy_data->sfp_mod_absent) { 7338c2ecf20Sopenharmony_ci pdata->phy.speed = SPEED_UNKNOWN; 7348c2ecf20Sopenharmony_ci pdata->phy.duplex = DUPLEX_UNKNOWN; 7358c2ecf20Sopenharmony_ci pdata->phy.autoneg = AUTONEG_ENABLE; 7368c2ecf20Sopenharmony_ci pdata->phy.pause_autoneg = AUTONEG_ENABLE; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, Autoneg); 7398c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, Pause); 7408c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, Asym_Pause); 7418c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, TP); 7428c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, FIBRE); 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci XGBE_LM_COPY(lks, advertising, lks, supported); 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci return; 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci switch (phy_data->sfp_base) { 7508c2ecf20Sopenharmony_ci case XGBE_SFP_BASE_1000_T: 7518c2ecf20Sopenharmony_ci case XGBE_SFP_BASE_1000_SX: 7528c2ecf20Sopenharmony_ci case XGBE_SFP_BASE_1000_LX: 7538c2ecf20Sopenharmony_ci case XGBE_SFP_BASE_1000_CX: 7548c2ecf20Sopenharmony_ci pdata->phy.speed = SPEED_UNKNOWN; 7558c2ecf20Sopenharmony_ci pdata->phy.duplex = DUPLEX_UNKNOWN; 7568c2ecf20Sopenharmony_ci pdata->phy.autoneg = AUTONEG_ENABLE; 7578c2ecf20Sopenharmony_ci pdata->phy.pause_autoneg = AUTONEG_ENABLE; 7588c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, Autoneg); 7598c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, Pause); 7608c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, Asym_Pause); 7618c2ecf20Sopenharmony_ci if (phy_data->sfp_base == XGBE_SFP_BASE_1000_T) { 7628c2ecf20Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) 7638c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, 100baseT_Full); 7648c2ecf20Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) 7658c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, 1000baseT_Full); 7668c2ecf20Sopenharmony_ci } else { 7678c2ecf20Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) 7688c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, 1000baseX_Full); 7698c2ecf20Sopenharmony_ci } 7708c2ecf20Sopenharmony_ci break; 7718c2ecf20Sopenharmony_ci case XGBE_SFP_BASE_10000_SR: 7728c2ecf20Sopenharmony_ci case XGBE_SFP_BASE_10000_LR: 7738c2ecf20Sopenharmony_ci case XGBE_SFP_BASE_10000_LRM: 7748c2ecf20Sopenharmony_ci case XGBE_SFP_BASE_10000_ER: 7758c2ecf20Sopenharmony_ci case XGBE_SFP_BASE_10000_CR: 7768c2ecf20Sopenharmony_ci pdata->phy.speed = SPEED_10000; 7778c2ecf20Sopenharmony_ci pdata->phy.duplex = DUPLEX_FULL; 7788c2ecf20Sopenharmony_ci pdata->phy.autoneg = AUTONEG_DISABLE; 7798c2ecf20Sopenharmony_ci pdata->phy.pause_autoneg = AUTONEG_DISABLE; 7808c2ecf20Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000) { 7818c2ecf20Sopenharmony_ci switch (phy_data->sfp_base) { 7828c2ecf20Sopenharmony_ci case XGBE_SFP_BASE_10000_SR: 7838c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, 10000baseSR_Full); 7848c2ecf20Sopenharmony_ci break; 7858c2ecf20Sopenharmony_ci case XGBE_SFP_BASE_10000_LR: 7868c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, 10000baseLR_Full); 7878c2ecf20Sopenharmony_ci break; 7888c2ecf20Sopenharmony_ci case XGBE_SFP_BASE_10000_LRM: 7898c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, 10000baseLRM_Full); 7908c2ecf20Sopenharmony_ci break; 7918c2ecf20Sopenharmony_ci case XGBE_SFP_BASE_10000_ER: 7928c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, 10000baseER_Full); 7938c2ecf20Sopenharmony_ci break; 7948c2ecf20Sopenharmony_ci case XGBE_SFP_BASE_10000_CR: 7958c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, 10000baseCR_Full); 7968c2ecf20Sopenharmony_ci break; 7978c2ecf20Sopenharmony_ci default: 7988c2ecf20Sopenharmony_ci break; 7998c2ecf20Sopenharmony_ci } 8008c2ecf20Sopenharmony_ci } 8018c2ecf20Sopenharmony_ci break; 8028c2ecf20Sopenharmony_ci default: 8038c2ecf20Sopenharmony_ci pdata->phy.speed = SPEED_UNKNOWN; 8048c2ecf20Sopenharmony_ci pdata->phy.duplex = DUPLEX_UNKNOWN; 8058c2ecf20Sopenharmony_ci pdata->phy.autoneg = AUTONEG_DISABLE; 8068c2ecf20Sopenharmony_ci pdata->phy.pause_autoneg = AUTONEG_DISABLE; 8078c2ecf20Sopenharmony_ci break; 8088c2ecf20Sopenharmony_ci } 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci switch (phy_data->sfp_base) { 8118c2ecf20Sopenharmony_ci case XGBE_SFP_BASE_1000_T: 8128c2ecf20Sopenharmony_ci case XGBE_SFP_BASE_1000_CX: 8138c2ecf20Sopenharmony_ci case XGBE_SFP_BASE_10000_CR: 8148c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, TP); 8158c2ecf20Sopenharmony_ci break; 8168c2ecf20Sopenharmony_ci default: 8178c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, FIBRE); 8188c2ecf20Sopenharmony_ci break; 8198c2ecf20Sopenharmony_ci } 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci XGBE_LM_COPY(lks, advertising, lks, supported); 8228c2ecf20Sopenharmony_ci} 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_cistatic bool xgbe_phy_sfp_bit_rate(struct xgbe_sfp_eeprom *sfp_eeprom, 8258c2ecf20Sopenharmony_ci enum xgbe_sfp_speed sfp_speed) 8268c2ecf20Sopenharmony_ci{ 8278c2ecf20Sopenharmony_ci u8 *sfp_base, min; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci sfp_base = sfp_eeprom->base; 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci switch (sfp_speed) { 8328c2ecf20Sopenharmony_ci case XGBE_SFP_SPEED_1000: 8338c2ecf20Sopenharmony_ci min = XGBE_SFP_BASE_BR_1GBE_MIN; 8348c2ecf20Sopenharmony_ci break; 8358c2ecf20Sopenharmony_ci case XGBE_SFP_SPEED_10000: 8368c2ecf20Sopenharmony_ci min = XGBE_SFP_BASE_BR_10GBE_MIN; 8378c2ecf20Sopenharmony_ci break; 8388c2ecf20Sopenharmony_ci default: 8398c2ecf20Sopenharmony_ci return false; 8408c2ecf20Sopenharmony_ci } 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci return sfp_base[XGBE_SFP_BASE_BR] >= min; 8438c2ecf20Sopenharmony_ci} 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_cistatic void xgbe_phy_free_phy_device(struct xgbe_prv_data *pdata) 8468c2ecf20Sopenharmony_ci{ 8478c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci if (phy_data->phydev) { 8508c2ecf20Sopenharmony_ci phy_detach(phy_data->phydev); 8518c2ecf20Sopenharmony_ci phy_device_remove(phy_data->phydev); 8528c2ecf20Sopenharmony_ci phy_device_free(phy_data->phydev); 8538c2ecf20Sopenharmony_ci phy_data->phydev = NULL; 8548c2ecf20Sopenharmony_ci } 8558c2ecf20Sopenharmony_ci} 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_cistatic bool xgbe_phy_finisar_phy_quirks(struct xgbe_prv_data *pdata) 8588c2ecf20Sopenharmony_ci{ 8598c2ecf20Sopenharmony_ci __ETHTOOL_DECLARE_LINK_MODE_MASK(supported) = { 0, }; 8608c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 8618c2ecf20Sopenharmony_ci unsigned int phy_id = phy_data->phydev->phy_id; 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci if (phy_data->port_mode != XGBE_PORT_MODE_SFP) 8648c2ecf20Sopenharmony_ci return false; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci if ((phy_id & 0xfffffff0) != 0x01ff0cc0) 8678c2ecf20Sopenharmony_ci return false; 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci /* Enable Base-T AN */ 8708c2ecf20Sopenharmony_ci phy_write(phy_data->phydev, 0x16, 0x0001); 8718c2ecf20Sopenharmony_ci phy_write(phy_data->phydev, 0x00, 0x9140); 8728c2ecf20Sopenharmony_ci phy_write(phy_data->phydev, 0x16, 0x0000); 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci /* Enable SGMII at 100Base-T/1000Base-T Full Duplex */ 8758c2ecf20Sopenharmony_ci phy_write(phy_data->phydev, 0x1b, 0x9084); 8768c2ecf20Sopenharmony_ci phy_write(phy_data->phydev, 0x09, 0x0e00); 8778c2ecf20Sopenharmony_ci phy_write(phy_data->phydev, 0x00, 0x8140); 8788c2ecf20Sopenharmony_ci phy_write(phy_data->phydev, 0x04, 0x0d01); 8798c2ecf20Sopenharmony_ci phy_write(phy_data->phydev, 0x00, 0x9140); 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci linkmode_set_bit_array(phy_10_100_features_array, 8828c2ecf20Sopenharmony_ci ARRAY_SIZE(phy_10_100_features_array), 8838c2ecf20Sopenharmony_ci supported); 8848c2ecf20Sopenharmony_ci linkmode_set_bit_array(phy_gbit_features_array, 8858c2ecf20Sopenharmony_ci ARRAY_SIZE(phy_gbit_features_array), 8868c2ecf20Sopenharmony_ci supported); 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci linkmode_copy(phy_data->phydev->supported, supported); 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci phy_support_asym_pause(phy_data->phydev); 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci netif_dbg(pdata, drv, pdata->netdev, 8938c2ecf20Sopenharmony_ci "Finisar PHY quirk in place\n"); 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci return true; 8968c2ecf20Sopenharmony_ci} 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_cistatic bool xgbe_phy_belfuse_phy_quirks(struct xgbe_prv_data *pdata) 8998c2ecf20Sopenharmony_ci{ 9008c2ecf20Sopenharmony_ci __ETHTOOL_DECLARE_LINK_MODE_MASK(supported) = { 0, }; 9018c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 9028c2ecf20Sopenharmony_ci struct xgbe_sfp_eeprom *sfp_eeprom = &phy_data->sfp_eeprom; 9038c2ecf20Sopenharmony_ci unsigned int phy_id = phy_data->phydev->phy_id; 9048c2ecf20Sopenharmony_ci int reg; 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci if (phy_data->port_mode != XGBE_PORT_MODE_SFP) 9078c2ecf20Sopenharmony_ci return false; 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci if (memcmp(&sfp_eeprom->base[XGBE_SFP_BASE_VENDOR_NAME], 9108c2ecf20Sopenharmony_ci XGBE_BEL_FUSE_VENDOR, XGBE_SFP_BASE_VENDOR_NAME_LEN)) 9118c2ecf20Sopenharmony_ci return false; 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci /* For Bel-Fuse, use the extra AN flag */ 9148c2ecf20Sopenharmony_ci pdata->an_again = 1; 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci if (memcmp(&sfp_eeprom->base[XGBE_SFP_BASE_VENDOR_PN], 9178c2ecf20Sopenharmony_ci XGBE_BEL_FUSE_PARTNO, XGBE_SFP_BASE_VENDOR_PN_LEN)) 9188c2ecf20Sopenharmony_ci return false; 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci if ((phy_id & 0xfffffff0) != 0x03625d10) 9218c2ecf20Sopenharmony_ci return false; 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci /* Reset PHY - wait for self-clearing reset bit to clear */ 9248c2ecf20Sopenharmony_ci genphy_soft_reset(phy_data->phydev); 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci /* Disable RGMII mode */ 9278c2ecf20Sopenharmony_ci phy_write(phy_data->phydev, 0x18, 0x7007); 9288c2ecf20Sopenharmony_ci reg = phy_read(phy_data->phydev, 0x18); 9298c2ecf20Sopenharmony_ci phy_write(phy_data->phydev, 0x18, reg & ~0x0080); 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci /* Enable fiber register bank */ 9328c2ecf20Sopenharmony_ci phy_write(phy_data->phydev, 0x1c, 0x7c00); 9338c2ecf20Sopenharmony_ci reg = phy_read(phy_data->phydev, 0x1c); 9348c2ecf20Sopenharmony_ci reg &= 0x03ff; 9358c2ecf20Sopenharmony_ci reg &= ~0x0001; 9368c2ecf20Sopenharmony_ci phy_write(phy_data->phydev, 0x1c, 0x8000 | 0x7c00 | reg | 0x0001); 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci /* Power down SerDes */ 9398c2ecf20Sopenharmony_ci reg = phy_read(phy_data->phydev, 0x00); 9408c2ecf20Sopenharmony_ci phy_write(phy_data->phydev, 0x00, reg | 0x00800); 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci /* Configure SGMII-to-Copper mode */ 9438c2ecf20Sopenharmony_ci phy_write(phy_data->phydev, 0x1c, 0x7c00); 9448c2ecf20Sopenharmony_ci reg = phy_read(phy_data->phydev, 0x1c); 9458c2ecf20Sopenharmony_ci reg &= 0x03ff; 9468c2ecf20Sopenharmony_ci reg &= ~0x0006; 9478c2ecf20Sopenharmony_ci phy_write(phy_data->phydev, 0x1c, 0x8000 | 0x7c00 | reg | 0x0004); 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci /* Power up SerDes */ 9508c2ecf20Sopenharmony_ci reg = phy_read(phy_data->phydev, 0x00); 9518c2ecf20Sopenharmony_ci phy_write(phy_data->phydev, 0x00, reg & ~0x00800); 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci /* Enable copper register bank */ 9548c2ecf20Sopenharmony_ci phy_write(phy_data->phydev, 0x1c, 0x7c00); 9558c2ecf20Sopenharmony_ci reg = phy_read(phy_data->phydev, 0x1c); 9568c2ecf20Sopenharmony_ci reg &= 0x03ff; 9578c2ecf20Sopenharmony_ci reg &= ~0x0001; 9588c2ecf20Sopenharmony_ci phy_write(phy_data->phydev, 0x1c, 0x8000 | 0x7c00 | reg); 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci /* Power up SerDes */ 9618c2ecf20Sopenharmony_ci reg = phy_read(phy_data->phydev, 0x00); 9628c2ecf20Sopenharmony_ci phy_write(phy_data->phydev, 0x00, reg & ~0x00800); 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci linkmode_set_bit_array(phy_10_100_features_array, 9658c2ecf20Sopenharmony_ci ARRAY_SIZE(phy_10_100_features_array), 9668c2ecf20Sopenharmony_ci supported); 9678c2ecf20Sopenharmony_ci linkmode_set_bit_array(phy_gbit_features_array, 9688c2ecf20Sopenharmony_ci ARRAY_SIZE(phy_gbit_features_array), 9698c2ecf20Sopenharmony_ci supported); 9708c2ecf20Sopenharmony_ci linkmode_copy(phy_data->phydev->supported, supported); 9718c2ecf20Sopenharmony_ci phy_support_asym_pause(phy_data->phydev); 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci netif_dbg(pdata, drv, pdata->netdev, 9748c2ecf20Sopenharmony_ci "BelFuse PHY quirk in place\n"); 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci return true; 9778c2ecf20Sopenharmony_ci} 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_cistatic void xgbe_phy_external_phy_quirks(struct xgbe_prv_data *pdata) 9808c2ecf20Sopenharmony_ci{ 9818c2ecf20Sopenharmony_ci if (xgbe_phy_belfuse_phy_quirks(pdata)) 9828c2ecf20Sopenharmony_ci return; 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci if (xgbe_phy_finisar_phy_quirks(pdata)) 9858c2ecf20Sopenharmony_ci return; 9868c2ecf20Sopenharmony_ci} 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_cistatic int xgbe_phy_find_phy_device(struct xgbe_prv_data *pdata) 9898c2ecf20Sopenharmony_ci{ 9908c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *lks = &pdata->phy.lks; 9918c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 9928c2ecf20Sopenharmony_ci struct phy_device *phydev; 9938c2ecf20Sopenharmony_ci int ret; 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci /* If we already have a PHY, just return */ 9968c2ecf20Sopenharmony_ci if (phy_data->phydev) 9978c2ecf20Sopenharmony_ci return 0; 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci /* Clear the extra AN flag */ 10008c2ecf20Sopenharmony_ci pdata->an_again = 0; 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci /* Check for the use of an external PHY */ 10038c2ecf20Sopenharmony_ci if (phy_data->phydev_mode == XGBE_MDIO_MODE_NONE) 10048c2ecf20Sopenharmony_ci return 0; 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci /* For SFP, only use an external PHY if available */ 10078c2ecf20Sopenharmony_ci if ((phy_data->port_mode == XGBE_PORT_MODE_SFP) && 10088c2ecf20Sopenharmony_ci !phy_data->sfp_phy_avail) 10098c2ecf20Sopenharmony_ci return 0; 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci /* Set the proper MDIO mode for the PHY */ 10128c2ecf20Sopenharmony_ci ret = pdata->hw_if.set_ext_mii_mode(pdata, phy_data->mdio_addr, 10138c2ecf20Sopenharmony_ci phy_data->phydev_mode); 10148c2ecf20Sopenharmony_ci if (ret) { 10158c2ecf20Sopenharmony_ci netdev_err(pdata->netdev, 10168c2ecf20Sopenharmony_ci "mdio port/clause not compatible (%u/%u)\n", 10178c2ecf20Sopenharmony_ci phy_data->mdio_addr, phy_data->phydev_mode); 10188c2ecf20Sopenharmony_ci return ret; 10198c2ecf20Sopenharmony_ci } 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci /* Create and connect to the PHY device */ 10228c2ecf20Sopenharmony_ci phydev = get_phy_device(phy_data->mii, phy_data->mdio_addr, 10238c2ecf20Sopenharmony_ci (phy_data->phydev_mode == XGBE_MDIO_MODE_CL45)); 10248c2ecf20Sopenharmony_ci if (IS_ERR(phydev)) { 10258c2ecf20Sopenharmony_ci netdev_err(pdata->netdev, "get_phy_device failed\n"); 10268c2ecf20Sopenharmony_ci return -ENODEV; 10278c2ecf20Sopenharmony_ci } 10288c2ecf20Sopenharmony_ci netif_dbg(pdata, drv, pdata->netdev, "external PHY id is %#010x\n", 10298c2ecf20Sopenharmony_ci phydev->phy_id); 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci /*TODO: If c45, add request_module based on one of the MMD ids? */ 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci ret = phy_device_register(phydev); 10348c2ecf20Sopenharmony_ci if (ret) { 10358c2ecf20Sopenharmony_ci netdev_err(pdata->netdev, "phy_device_register failed\n"); 10368c2ecf20Sopenharmony_ci phy_device_free(phydev); 10378c2ecf20Sopenharmony_ci return ret; 10388c2ecf20Sopenharmony_ci } 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci ret = phy_attach_direct(pdata->netdev, phydev, phydev->dev_flags, 10418c2ecf20Sopenharmony_ci PHY_INTERFACE_MODE_SGMII); 10428c2ecf20Sopenharmony_ci if (ret) { 10438c2ecf20Sopenharmony_ci netdev_err(pdata->netdev, "phy_attach_direct failed\n"); 10448c2ecf20Sopenharmony_ci phy_device_remove(phydev); 10458c2ecf20Sopenharmony_ci phy_device_free(phydev); 10468c2ecf20Sopenharmony_ci return ret; 10478c2ecf20Sopenharmony_ci } 10488c2ecf20Sopenharmony_ci phy_data->phydev = phydev; 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci xgbe_phy_external_phy_quirks(pdata); 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci linkmode_and(phydev->advertising, phydev->advertising, 10538c2ecf20Sopenharmony_ci lks->link_modes.advertising); 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci phy_start_aneg(phy_data->phydev); 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci return 0; 10588c2ecf20Sopenharmony_ci} 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_cistatic void xgbe_phy_sfp_external_phy(struct xgbe_prv_data *pdata) 10618c2ecf20Sopenharmony_ci{ 10628c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 10638c2ecf20Sopenharmony_ci int ret; 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci if (!phy_data->sfp_changed) 10668c2ecf20Sopenharmony_ci return; 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci phy_data->sfp_phy_avail = 0; 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci if (phy_data->sfp_base != XGBE_SFP_BASE_1000_T) 10718c2ecf20Sopenharmony_ci return; 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci /* Check access to the PHY by reading CTRL1 */ 10748c2ecf20Sopenharmony_ci ret = xgbe_phy_i2c_mii_read(pdata, MII_BMCR); 10758c2ecf20Sopenharmony_ci if (ret < 0) 10768c2ecf20Sopenharmony_ci return; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci /* Successfully accessed the PHY */ 10798c2ecf20Sopenharmony_ci phy_data->sfp_phy_avail = 1; 10808c2ecf20Sopenharmony_ci} 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_cistatic bool xgbe_phy_check_sfp_rx_los(struct xgbe_phy_data *phy_data) 10838c2ecf20Sopenharmony_ci{ 10848c2ecf20Sopenharmony_ci u8 *sfp_extd = phy_data->sfp_eeprom.extd; 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci if (!(sfp_extd[XGBE_SFP_EXTD_OPT1] & XGBE_SFP_EXTD_OPT1_RX_LOS)) 10878c2ecf20Sopenharmony_ci return false; 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci if (phy_data->sfp_gpio_mask & XGBE_GPIO_NO_RX_LOS) 10908c2ecf20Sopenharmony_ci return false; 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci if (phy_data->sfp_gpio_inputs & (1 << phy_data->sfp_gpio_rx_los)) 10938c2ecf20Sopenharmony_ci return true; 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci return false; 10968c2ecf20Sopenharmony_ci} 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_cistatic bool xgbe_phy_check_sfp_tx_fault(struct xgbe_phy_data *phy_data) 10998c2ecf20Sopenharmony_ci{ 11008c2ecf20Sopenharmony_ci u8 *sfp_extd = phy_data->sfp_eeprom.extd; 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci if (!(sfp_extd[XGBE_SFP_EXTD_OPT1] & XGBE_SFP_EXTD_OPT1_TX_FAULT)) 11038c2ecf20Sopenharmony_ci return false; 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci if (phy_data->sfp_gpio_mask & XGBE_GPIO_NO_TX_FAULT) 11068c2ecf20Sopenharmony_ci return false; 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci if (phy_data->sfp_gpio_inputs & (1 << phy_data->sfp_gpio_tx_fault)) 11098c2ecf20Sopenharmony_ci return true; 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci return false; 11128c2ecf20Sopenharmony_ci} 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_cistatic bool xgbe_phy_check_sfp_mod_absent(struct xgbe_phy_data *phy_data) 11158c2ecf20Sopenharmony_ci{ 11168c2ecf20Sopenharmony_ci if (phy_data->sfp_gpio_mask & XGBE_GPIO_NO_MOD_ABSENT) 11178c2ecf20Sopenharmony_ci return false; 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci if (phy_data->sfp_gpio_inputs & (1 << phy_data->sfp_gpio_mod_absent)) 11208c2ecf20Sopenharmony_ci return true; 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci return false; 11238c2ecf20Sopenharmony_ci} 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_cistatic void xgbe_phy_sfp_parse_eeprom(struct xgbe_prv_data *pdata) 11268c2ecf20Sopenharmony_ci{ 11278c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 11288c2ecf20Sopenharmony_ci struct xgbe_sfp_eeprom *sfp_eeprom = &phy_data->sfp_eeprom; 11298c2ecf20Sopenharmony_ci u8 *sfp_base; 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci sfp_base = sfp_eeprom->base; 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci if (sfp_base[XGBE_SFP_BASE_ID] != XGBE_SFP_ID_SFP) 11348c2ecf20Sopenharmony_ci return; 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci if (sfp_base[XGBE_SFP_BASE_EXT_ID] != XGBE_SFP_EXT_ID_SFP) 11378c2ecf20Sopenharmony_ci return; 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci /* Update transceiver signals (eeprom extd/options) */ 11408c2ecf20Sopenharmony_ci phy_data->sfp_tx_fault = xgbe_phy_check_sfp_tx_fault(phy_data); 11418c2ecf20Sopenharmony_ci phy_data->sfp_rx_los = xgbe_phy_check_sfp_rx_los(phy_data); 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci /* Assume FIBER cable unless told otherwise */ 11448c2ecf20Sopenharmony_ci if (sfp_base[XGBE_SFP_BASE_CABLE] & XGBE_SFP_BASE_CABLE_PASSIVE) { 11458c2ecf20Sopenharmony_ci phy_data->sfp_cable = XGBE_SFP_CABLE_PASSIVE; 11468c2ecf20Sopenharmony_ci phy_data->sfp_cable_len = sfp_base[XGBE_SFP_BASE_CU_CABLE_LEN]; 11478c2ecf20Sopenharmony_ci } else if (sfp_base[XGBE_SFP_BASE_CABLE] & XGBE_SFP_BASE_CABLE_ACTIVE) { 11488c2ecf20Sopenharmony_ci phy_data->sfp_cable = XGBE_SFP_CABLE_ACTIVE; 11498c2ecf20Sopenharmony_ci } else { 11508c2ecf20Sopenharmony_ci phy_data->sfp_cable = XGBE_SFP_CABLE_FIBER; 11518c2ecf20Sopenharmony_ci } 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci /* Determine the type of SFP */ 11548c2ecf20Sopenharmony_ci if (phy_data->sfp_cable != XGBE_SFP_CABLE_FIBER && 11558c2ecf20Sopenharmony_ci xgbe_phy_sfp_bit_rate(sfp_eeprom, XGBE_SFP_SPEED_10000)) 11568c2ecf20Sopenharmony_ci phy_data->sfp_base = XGBE_SFP_BASE_10000_CR; 11578c2ecf20Sopenharmony_ci else if (sfp_base[XGBE_SFP_BASE_10GBE_CC] & XGBE_SFP_BASE_10GBE_CC_SR) 11588c2ecf20Sopenharmony_ci phy_data->sfp_base = XGBE_SFP_BASE_10000_SR; 11598c2ecf20Sopenharmony_ci else if (sfp_base[XGBE_SFP_BASE_10GBE_CC] & XGBE_SFP_BASE_10GBE_CC_LR) 11608c2ecf20Sopenharmony_ci phy_data->sfp_base = XGBE_SFP_BASE_10000_LR; 11618c2ecf20Sopenharmony_ci else if (sfp_base[XGBE_SFP_BASE_10GBE_CC] & XGBE_SFP_BASE_10GBE_CC_LRM) 11628c2ecf20Sopenharmony_ci phy_data->sfp_base = XGBE_SFP_BASE_10000_LRM; 11638c2ecf20Sopenharmony_ci else if (sfp_base[XGBE_SFP_BASE_10GBE_CC] & XGBE_SFP_BASE_10GBE_CC_ER) 11648c2ecf20Sopenharmony_ci phy_data->sfp_base = XGBE_SFP_BASE_10000_ER; 11658c2ecf20Sopenharmony_ci else if (sfp_base[XGBE_SFP_BASE_1GBE_CC] & XGBE_SFP_BASE_1GBE_CC_SX) 11668c2ecf20Sopenharmony_ci phy_data->sfp_base = XGBE_SFP_BASE_1000_SX; 11678c2ecf20Sopenharmony_ci else if (sfp_base[XGBE_SFP_BASE_1GBE_CC] & XGBE_SFP_BASE_1GBE_CC_LX) 11688c2ecf20Sopenharmony_ci phy_data->sfp_base = XGBE_SFP_BASE_1000_LX; 11698c2ecf20Sopenharmony_ci else if (sfp_base[XGBE_SFP_BASE_1GBE_CC] & XGBE_SFP_BASE_1GBE_CC_CX) 11708c2ecf20Sopenharmony_ci phy_data->sfp_base = XGBE_SFP_BASE_1000_CX; 11718c2ecf20Sopenharmony_ci else if (sfp_base[XGBE_SFP_BASE_1GBE_CC] & XGBE_SFP_BASE_1GBE_CC_T) 11728c2ecf20Sopenharmony_ci phy_data->sfp_base = XGBE_SFP_BASE_1000_T; 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci switch (phy_data->sfp_base) { 11758c2ecf20Sopenharmony_ci case XGBE_SFP_BASE_1000_T: 11768c2ecf20Sopenharmony_ci phy_data->sfp_speed = XGBE_SFP_SPEED_100_1000; 11778c2ecf20Sopenharmony_ci break; 11788c2ecf20Sopenharmony_ci case XGBE_SFP_BASE_1000_SX: 11798c2ecf20Sopenharmony_ci case XGBE_SFP_BASE_1000_LX: 11808c2ecf20Sopenharmony_ci case XGBE_SFP_BASE_1000_CX: 11818c2ecf20Sopenharmony_ci phy_data->sfp_speed = XGBE_SFP_SPEED_1000; 11828c2ecf20Sopenharmony_ci break; 11838c2ecf20Sopenharmony_ci case XGBE_SFP_BASE_10000_SR: 11848c2ecf20Sopenharmony_ci case XGBE_SFP_BASE_10000_LR: 11858c2ecf20Sopenharmony_ci case XGBE_SFP_BASE_10000_LRM: 11868c2ecf20Sopenharmony_ci case XGBE_SFP_BASE_10000_ER: 11878c2ecf20Sopenharmony_ci case XGBE_SFP_BASE_10000_CR: 11888c2ecf20Sopenharmony_ci phy_data->sfp_speed = XGBE_SFP_SPEED_10000; 11898c2ecf20Sopenharmony_ci break; 11908c2ecf20Sopenharmony_ci default: 11918c2ecf20Sopenharmony_ci break; 11928c2ecf20Sopenharmony_ci } 11938c2ecf20Sopenharmony_ci} 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_cistatic void xgbe_phy_sfp_eeprom_info(struct xgbe_prv_data *pdata, 11968c2ecf20Sopenharmony_ci struct xgbe_sfp_eeprom *sfp_eeprom) 11978c2ecf20Sopenharmony_ci{ 11988c2ecf20Sopenharmony_ci struct xgbe_sfp_ascii sfp_ascii; 11998c2ecf20Sopenharmony_ci char *sfp_data = (char *)&sfp_ascii; 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci netif_dbg(pdata, drv, pdata->netdev, "SFP detected:\n"); 12028c2ecf20Sopenharmony_ci memcpy(sfp_data, &sfp_eeprom->base[XGBE_SFP_BASE_VENDOR_NAME], 12038c2ecf20Sopenharmony_ci XGBE_SFP_BASE_VENDOR_NAME_LEN); 12048c2ecf20Sopenharmony_ci sfp_data[XGBE_SFP_BASE_VENDOR_NAME_LEN] = '\0'; 12058c2ecf20Sopenharmony_ci netif_dbg(pdata, drv, pdata->netdev, " vendor: %s\n", 12068c2ecf20Sopenharmony_ci sfp_data); 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci memcpy(sfp_data, &sfp_eeprom->base[XGBE_SFP_BASE_VENDOR_PN], 12098c2ecf20Sopenharmony_ci XGBE_SFP_BASE_VENDOR_PN_LEN); 12108c2ecf20Sopenharmony_ci sfp_data[XGBE_SFP_BASE_VENDOR_PN_LEN] = '\0'; 12118c2ecf20Sopenharmony_ci netif_dbg(pdata, drv, pdata->netdev, " part number: %s\n", 12128c2ecf20Sopenharmony_ci sfp_data); 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci memcpy(sfp_data, &sfp_eeprom->base[XGBE_SFP_BASE_VENDOR_REV], 12158c2ecf20Sopenharmony_ci XGBE_SFP_BASE_VENDOR_REV_LEN); 12168c2ecf20Sopenharmony_ci sfp_data[XGBE_SFP_BASE_VENDOR_REV_LEN] = '\0'; 12178c2ecf20Sopenharmony_ci netif_dbg(pdata, drv, pdata->netdev, " revision level: %s\n", 12188c2ecf20Sopenharmony_ci sfp_data); 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci memcpy(sfp_data, &sfp_eeprom->extd[XGBE_SFP_BASE_VENDOR_SN], 12218c2ecf20Sopenharmony_ci XGBE_SFP_BASE_VENDOR_SN_LEN); 12228c2ecf20Sopenharmony_ci sfp_data[XGBE_SFP_BASE_VENDOR_SN_LEN] = '\0'; 12238c2ecf20Sopenharmony_ci netif_dbg(pdata, drv, pdata->netdev, " serial number: %s\n", 12248c2ecf20Sopenharmony_ci sfp_data); 12258c2ecf20Sopenharmony_ci} 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_cistatic bool xgbe_phy_sfp_verify_eeprom(u8 cc_in, u8 *buf, unsigned int len) 12288c2ecf20Sopenharmony_ci{ 12298c2ecf20Sopenharmony_ci u8 cc; 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci for (cc = 0; len; buf++, len--) 12328c2ecf20Sopenharmony_ci cc += *buf; 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci return cc == cc_in; 12358c2ecf20Sopenharmony_ci} 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_cistatic int xgbe_phy_sfp_read_eeprom(struct xgbe_prv_data *pdata) 12388c2ecf20Sopenharmony_ci{ 12398c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 12408c2ecf20Sopenharmony_ci struct xgbe_sfp_eeprom sfp_eeprom; 12418c2ecf20Sopenharmony_ci u8 eeprom_addr; 12428c2ecf20Sopenharmony_ci int ret; 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci ret = xgbe_phy_sfp_get_mux(pdata); 12458c2ecf20Sopenharmony_ci if (ret) { 12468c2ecf20Sopenharmony_ci dev_err_once(pdata->dev, "%s: I2C error setting SFP MUX\n", 12478c2ecf20Sopenharmony_ci netdev_name(pdata->netdev)); 12488c2ecf20Sopenharmony_ci return ret; 12498c2ecf20Sopenharmony_ci } 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci /* Read the SFP serial ID eeprom */ 12528c2ecf20Sopenharmony_ci eeprom_addr = 0; 12538c2ecf20Sopenharmony_ci ret = xgbe_phy_i2c_read(pdata, XGBE_SFP_SERIAL_ID_ADDRESS, 12548c2ecf20Sopenharmony_ci &eeprom_addr, sizeof(eeprom_addr), 12558c2ecf20Sopenharmony_ci &sfp_eeprom, sizeof(sfp_eeprom)); 12568c2ecf20Sopenharmony_ci if (ret) { 12578c2ecf20Sopenharmony_ci dev_err_once(pdata->dev, "%s: I2C error reading SFP EEPROM\n", 12588c2ecf20Sopenharmony_ci netdev_name(pdata->netdev)); 12598c2ecf20Sopenharmony_ci goto put; 12608c2ecf20Sopenharmony_ci } 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ci /* Validate the contents read */ 12638c2ecf20Sopenharmony_ci if (!xgbe_phy_sfp_verify_eeprom(sfp_eeprom.base[XGBE_SFP_BASE_CC], 12648c2ecf20Sopenharmony_ci sfp_eeprom.base, 12658c2ecf20Sopenharmony_ci sizeof(sfp_eeprom.base) - 1)) { 12668c2ecf20Sopenharmony_ci ret = -EINVAL; 12678c2ecf20Sopenharmony_ci goto put; 12688c2ecf20Sopenharmony_ci } 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci if (!xgbe_phy_sfp_verify_eeprom(sfp_eeprom.extd[XGBE_SFP_EXTD_CC], 12718c2ecf20Sopenharmony_ci sfp_eeprom.extd, 12728c2ecf20Sopenharmony_ci sizeof(sfp_eeprom.extd) - 1)) { 12738c2ecf20Sopenharmony_ci ret = -EINVAL; 12748c2ecf20Sopenharmony_ci goto put; 12758c2ecf20Sopenharmony_ci } 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci /* Check for an added or changed SFP */ 12788c2ecf20Sopenharmony_ci if (memcmp(&phy_data->sfp_eeprom, &sfp_eeprom, sizeof(sfp_eeprom))) { 12798c2ecf20Sopenharmony_ci phy_data->sfp_changed = 1; 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci if (netif_msg_drv(pdata)) 12828c2ecf20Sopenharmony_ci xgbe_phy_sfp_eeprom_info(pdata, &sfp_eeprom); 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci memcpy(&phy_data->sfp_eeprom, &sfp_eeprom, sizeof(sfp_eeprom)); 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci xgbe_phy_free_phy_device(pdata); 12878c2ecf20Sopenharmony_ci } else { 12888c2ecf20Sopenharmony_ci phy_data->sfp_changed = 0; 12898c2ecf20Sopenharmony_ci } 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ciput: 12928c2ecf20Sopenharmony_ci xgbe_phy_sfp_put_mux(pdata); 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci return ret; 12958c2ecf20Sopenharmony_ci} 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_cistatic void xgbe_phy_sfp_signals(struct xgbe_prv_data *pdata) 12988c2ecf20Sopenharmony_ci{ 12998c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 13008c2ecf20Sopenharmony_ci u8 gpio_reg, gpio_ports[2]; 13018c2ecf20Sopenharmony_ci int ret; 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci /* Read the input port registers */ 13048c2ecf20Sopenharmony_ci gpio_reg = 0; 13058c2ecf20Sopenharmony_ci ret = xgbe_phy_i2c_read(pdata, phy_data->sfp_gpio_address, 13068c2ecf20Sopenharmony_ci &gpio_reg, sizeof(gpio_reg), 13078c2ecf20Sopenharmony_ci gpio_ports, sizeof(gpio_ports)); 13088c2ecf20Sopenharmony_ci if (ret) { 13098c2ecf20Sopenharmony_ci dev_err_once(pdata->dev, "%s: I2C error reading SFP GPIOs\n", 13108c2ecf20Sopenharmony_ci netdev_name(pdata->netdev)); 13118c2ecf20Sopenharmony_ci return; 13128c2ecf20Sopenharmony_ci } 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci phy_data->sfp_gpio_inputs = (gpio_ports[1] << 8) | gpio_ports[0]; 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci phy_data->sfp_mod_absent = xgbe_phy_check_sfp_mod_absent(phy_data); 13178c2ecf20Sopenharmony_ci} 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_cistatic void xgbe_phy_sfp_mod_absent(struct xgbe_prv_data *pdata) 13208c2ecf20Sopenharmony_ci{ 13218c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci xgbe_phy_free_phy_device(pdata); 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci phy_data->sfp_mod_absent = 1; 13268c2ecf20Sopenharmony_ci phy_data->sfp_phy_avail = 0; 13278c2ecf20Sopenharmony_ci memset(&phy_data->sfp_eeprom, 0, sizeof(phy_data->sfp_eeprom)); 13288c2ecf20Sopenharmony_ci} 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_cistatic void xgbe_phy_sfp_reset(struct xgbe_phy_data *phy_data) 13318c2ecf20Sopenharmony_ci{ 13328c2ecf20Sopenharmony_ci phy_data->sfp_rx_los = 0; 13338c2ecf20Sopenharmony_ci phy_data->sfp_tx_fault = 0; 13348c2ecf20Sopenharmony_ci phy_data->sfp_mod_absent = 1; 13358c2ecf20Sopenharmony_ci phy_data->sfp_base = XGBE_SFP_BASE_UNKNOWN; 13368c2ecf20Sopenharmony_ci phy_data->sfp_cable = XGBE_SFP_CABLE_UNKNOWN; 13378c2ecf20Sopenharmony_ci phy_data->sfp_speed = XGBE_SFP_SPEED_UNKNOWN; 13388c2ecf20Sopenharmony_ci} 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_cistatic void xgbe_phy_sfp_detect(struct xgbe_prv_data *pdata) 13418c2ecf20Sopenharmony_ci{ 13428c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 13438c2ecf20Sopenharmony_ci int ret; 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci /* Reset the SFP signals and info */ 13468c2ecf20Sopenharmony_ci xgbe_phy_sfp_reset(phy_data); 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci ret = xgbe_phy_get_comm_ownership(pdata); 13498c2ecf20Sopenharmony_ci if (ret) 13508c2ecf20Sopenharmony_ci return; 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci /* Read the SFP signals and check for module presence */ 13538c2ecf20Sopenharmony_ci xgbe_phy_sfp_signals(pdata); 13548c2ecf20Sopenharmony_ci if (phy_data->sfp_mod_absent) { 13558c2ecf20Sopenharmony_ci xgbe_phy_sfp_mod_absent(pdata); 13568c2ecf20Sopenharmony_ci goto put; 13578c2ecf20Sopenharmony_ci } 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci ret = xgbe_phy_sfp_read_eeprom(pdata); 13608c2ecf20Sopenharmony_ci if (ret) { 13618c2ecf20Sopenharmony_ci /* Treat any error as if there isn't an SFP plugged in */ 13628c2ecf20Sopenharmony_ci xgbe_phy_sfp_reset(phy_data); 13638c2ecf20Sopenharmony_ci xgbe_phy_sfp_mod_absent(pdata); 13648c2ecf20Sopenharmony_ci goto put; 13658c2ecf20Sopenharmony_ci } 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci xgbe_phy_sfp_parse_eeprom(pdata); 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci xgbe_phy_sfp_external_phy(pdata); 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ciput: 13728c2ecf20Sopenharmony_ci xgbe_phy_sfp_phy_settings(pdata); 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci xgbe_phy_put_comm_ownership(pdata); 13758c2ecf20Sopenharmony_ci} 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_cistatic int xgbe_phy_module_eeprom(struct xgbe_prv_data *pdata, 13788c2ecf20Sopenharmony_ci struct ethtool_eeprom *eeprom, u8 *data) 13798c2ecf20Sopenharmony_ci{ 13808c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 13818c2ecf20Sopenharmony_ci u8 eeprom_addr, eeprom_data[XGBE_SFP_EEPROM_MAX]; 13828c2ecf20Sopenharmony_ci struct xgbe_sfp_eeprom *sfp_eeprom; 13838c2ecf20Sopenharmony_ci unsigned int i, j, rem; 13848c2ecf20Sopenharmony_ci int ret; 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci rem = eeprom->len; 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci if (!eeprom->len) { 13898c2ecf20Sopenharmony_ci ret = -EINVAL; 13908c2ecf20Sopenharmony_ci goto done; 13918c2ecf20Sopenharmony_ci } 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci if ((eeprom->offset + eeprom->len) > XGBE_SFP_EEPROM_MAX) { 13948c2ecf20Sopenharmony_ci ret = -EINVAL; 13958c2ecf20Sopenharmony_ci goto done; 13968c2ecf20Sopenharmony_ci } 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci if (phy_data->port_mode != XGBE_PORT_MODE_SFP) { 13998c2ecf20Sopenharmony_ci ret = -ENXIO; 14008c2ecf20Sopenharmony_ci goto done; 14018c2ecf20Sopenharmony_ci } 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_ci if (!netif_running(pdata->netdev)) { 14048c2ecf20Sopenharmony_ci ret = -EIO; 14058c2ecf20Sopenharmony_ci goto done; 14068c2ecf20Sopenharmony_ci } 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci if (phy_data->sfp_mod_absent) { 14098c2ecf20Sopenharmony_ci ret = -EIO; 14108c2ecf20Sopenharmony_ci goto done; 14118c2ecf20Sopenharmony_ci } 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci ret = xgbe_phy_get_comm_ownership(pdata); 14148c2ecf20Sopenharmony_ci if (ret) { 14158c2ecf20Sopenharmony_ci ret = -EIO; 14168c2ecf20Sopenharmony_ci goto done; 14178c2ecf20Sopenharmony_ci } 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci ret = xgbe_phy_sfp_get_mux(pdata); 14208c2ecf20Sopenharmony_ci if (ret) { 14218c2ecf20Sopenharmony_ci netdev_err(pdata->netdev, "I2C error setting SFP MUX\n"); 14228c2ecf20Sopenharmony_ci ret = -EIO; 14238c2ecf20Sopenharmony_ci goto put_own; 14248c2ecf20Sopenharmony_ci } 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci /* Read the SFP serial ID eeprom */ 14278c2ecf20Sopenharmony_ci eeprom_addr = 0; 14288c2ecf20Sopenharmony_ci ret = xgbe_phy_i2c_read(pdata, XGBE_SFP_SERIAL_ID_ADDRESS, 14298c2ecf20Sopenharmony_ci &eeprom_addr, sizeof(eeprom_addr), 14308c2ecf20Sopenharmony_ci eeprom_data, XGBE_SFP_EEPROM_BASE_LEN); 14318c2ecf20Sopenharmony_ci if (ret) { 14328c2ecf20Sopenharmony_ci netdev_err(pdata->netdev, 14338c2ecf20Sopenharmony_ci "I2C error reading SFP EEPROM\n"); 14348c2ecf20Sopenharmony_ci ret = -EIO; 14358c2ecf20Sopenharmony_ci goto put_mux; 14368c2ecf20Sopenharmony_ci } 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_ci sfp_eeprom = (struct xgbe_sfp_eeprom *)eeprom_data; 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci if (XGBE_SFP_DIAGS_SUPPORTED(sfp_eeprom)) { 14418c2ecf20Sopenharmony_ci /* Read the SFP diagnostic eeprom */ 14428c2ecf20Sopenharmony_ci eeprom_addr = 0; 14438c2ecf20Sopenharmony_ci ret = xgbe_phy_i2c_read(pdata, XGBE_SFP_DIAG_INFO_ADDRESS, 14448c2ecf20Sopenharmony_ci &eeprom_addr, sizeof(eeprom_addr), 14458c2ecf20Sopenharmony_ci eeprom_data + XGBE_SFP_EEPROM_BASE_LEN, 14468c2ecf20Sopenharmony_ci XGBE_SFP_EEPROM_DIAG_LEN); 14478c2ecf20Sopenharmony_ci if (ret) { 14488c2ecf20Sopenharmony_ci netdev_err(pdata->netdev, 14498c2ecf20Sopenharmony_ci "I2C error reading SFP DIAGS\n"); 14508c2ecf20Sopenharmony_ci ret = -EIO; 14518c2ecf20Sopenharmony_ci goto put_mux; 14528c2ecf20Sopenharmony_ci } 14538c2ecf20Sopenharmony_ci } 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci for (i = 0, j = eeprom->offset; i < eeprom->len; i++, j++) { 14568c2ecf20Sopenharmony_ci if ((j >= XGBE_SFP_EEPROM_BASE_LEN) && 14578c2ecf20Sopenharmony_ci !XGBE_SFP_DIAGS_SUPPORTED(sfp_eeprom)) 14588c2ecf20Sopenharmony_ci break; 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci data[i] = eeprom_data[j]; 14618c2ecf20Sopenharmony_ci rem--; 14628c2ecf20Sopenharmony_ci } 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ciput_mux: 14658c2ecf20Sopenharmony_ci xgbe_phy_sfp_put_mux(pdata); 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ciput_own: 14688c2ecf20Sopenharmony_ci xgbe_phy_put_comm_ownership(pdata); 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_cidone: 14718c2ecf20Sopenharmony_ci eeprom->len -= rem; 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci return ret; 14748c2ecf20Sopenharmony_ci} 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_cistatic int xgbe_phy_module_info(struct xgbe_prv_data *pdata, 14778c2ecf20Sopenharmony_ci struct ethtool_modinfo *modinfo) 14788c2ecf20Sopenharmony_ci{ 14798c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci if (phy_data->port_mode != XGBE_PORT_MODE_SFP) 14828c2ecf20Sopenharmony_ci return -ENXIO; 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci if (!netif_running(pdata->netdev)) 14858c2ecf20Sopenharmony_ci return -EIO; 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci if (phy_data->sfp_mod_absent) 14888c2ecf20Sopenharmony_ci return -EIO; 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci if (XGBE_SFP_DIAGS_SUPPORTED(&phy_data->sfp_eeprom)) { 14918c2ecf20Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8472; 14928c2ecf20Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; 14938c2ecf20Sopenharmony_ci } else { 14948c2ecf20Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8079; 14958c2ecf20Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN; 14968c2ecf20Sopenharmony_ci } 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci return 0; 14998c2ecf20Sopenharmony_ci} 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_cistatic void xgbe_phy_phydev_flowctrl(struct xgbe_prv_data *pdata) 15028c2ecf20Sopenharmony_ci{ 15038c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *lks = &pdata->phy.lks; 15048c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 15058c2ecf20Sopenharmony_ci u16 lcl_adv = 0, rmt_adv = 0; 15068c2ecf20Sopenharmony_ci u8 fc; 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci pdata->phy.tx_pause = 0; 15098c2ecf20Sopenharmony_ci pdata->phy.rx_pause = 0; 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci if (!phy_data->phydev) 15128c2ecf20Sopenharmony_ci return; 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_ci lcl_adv = linkmode_adv_to_lcl_adv_t(phy_data->phydev->advertising); 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci if (phy_data->phydev->pause) { 15178c2ecf20Sopenharmony_ci XGBE_SET_LP_ADV(lks, Pause); 15188c2ecf20Sopenharmony_ci rmt_adv |= LPA_PAUSE_CAP; 15198c2ecf20Sopenharmony_ci } 15208c2ecf20Sopenharmony_ci if (phy_data->phydev->asym_pause) { 15218c2ecf20Sopenharmony_ci XGBE_SET_LP_ADV(lks, Asym_Pause); 15228c2ecf20Sopenharmony_ci rmt_adv |= LPA_PAUSE_ASYM; 15238c2ecf20Sopenharmony_ci } 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci fc = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv); 15268c2ecf20Sopenharmony_ci if (fc & FLOW_CTRL_TX) 15278c2ecf20Sopenharmony_ci pdata->phy.tx_pause = 1; 15288c2ecf20Sopenharmony_ci if (fc & FLOW_CTRL_RX) 15298c2ecf20Sopenharmony_ci pdata->phy.rx_pause = 1; 15308c2ecf20Sopenharmony_ci} 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_cistatic enum xgbe_mode xgbe_phy_an37_sgmii_outcome(struct xgbe_prv_data *pdata) 15338c2ecf20Sopenharmony_ci{ 15348c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *lks = &pdata->phy.lks; 15358c2ecf20Sopenharmony_ci enum xgbe_mode mode; 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci XGBE_SET_LP_ADV(lks, Autoneg); 15388c2ecf20Sopenharmony_ci XGBE_SET_LP_ADV(lks, TP); 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ci /* Use external PHY to determine flow control */ 15418c2ecf20Sopenharmony_ci if (pdata->phy.pause_autoneg) 15428c2ecf20Sopenharmony_ci xgbe_phy_phydev_flowctrl(pdata); 15438c2ecf20Sopenharmony_ci 15448c2ecf20Sopenharmony_ci switch (pdata->an_status & XGBE_SGMII_AN_LINK_SPEED) { 15458c2ecf20Sopenharmony_ci case XGBE_SGMII_AN_LINK_SPEED_100: 15468c2ecf20Sopenharmony_ci if (pdata->an_status & XGBE_SGMII_AN_LINK_DUPLEX) { 15478c2ecf20Sopenharmony_ci XGBE_SET_LP_ADV(lks, 100baseT_Full); 15488c2ecf20Sopenharmony_ci mode = XGBE_MODE_SGMII_100; 15498c2ecf20Sopenharmony_ci } else { 15508c2ecf20Sopenharmony_ci /* Half-duplex not supported */ 15518c2ecf20Sopenharmony_ci XGBE_SET_LP_ADV(lks, 100baseT_Half); 15528c2ecf20Sopenharmony_ci mode = XGBE_MODE_UNKNOWN; 15538c2ecf20Sopenharmony_ci } 15548c2ecf20Sopenharmony_ci break; 15558c2ecf20Sopenharmony_ci case XGBE_SGMII_AN_LINK_SPEED_1000: 15568c2ecf20Sopenharmony_ci if (pdata->an_status & XGBE_SGMII_AN_LINK_DUPLEX) { 15578c2ecf20Sopenharmony_ci XGBE_SET_LP_ADV(lks, 1000baseT_Full); 15588c2ecf20Sopenharmony_ci mode = XGBE_MODE_SGMII_1000; 15598c2ecf20Sopenharmony_ci } else { 15608c2ecf20Sopenharmony_ci /* Half-duplex not supported */ 15618c2ecf20Sopenharmony_ci XGBE_SET_LP_ADV(lks, 1000baseT_Half); 15628c2ecf20Sopenharmony_ci mode = XGBE_MODE_UNKNOWN; 15638c2ecf20Sopenharmony_ci } 15648c2ecf20Sopenharmony_ci break; 15658c2ecf20Sopenharmony_ci default: 15668c2ecf20Sopenharmony_ci mode = XGBE_MODE_UNKNOWN; 15678c2ecf20Sopenharmony_ci } 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci return mode; 15708c2ecf20Sopenharmony_ci} 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_cistatic enum xgbe_mode xgbe_phy_an37_outcome(struct xgbe_prv_data *pdata) 15738c2ecf20Sopenharmony_ci{ 15748c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *lks = &pdata->phy.lks; 15758c2ecf20Sopenharmony_ci enum xgbe_mode mode; 15768c2ecf20Sopenharmony_ci unsigned int ad_reg, lp_reg; 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci XGBE_SET_LP_ADV(lks, Autoneg); 15798c2ecf20Sopenharmony_ci XGBE_SET_LP_ADV(lks, FIBRE); 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_ci /* Compare Advertisement and Link Partner register */ 15828c2ecf20Sopenharmony_ci ad_reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_ADVERTISE); 15838c2ecf20Sopenharmony_ci lp_reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_LP_ABILITY); 15848c2ecf20Sopenharmony_ci if (lp_reg & 0x100) 15858c2ecf20Sopenharmony_ci XGBE_SET_LP_ADV(lks, Pause); 15868c2ecf20Sopenharmony_ci if (lp_reg & 0x80) 15878c2ecf20Sopenharmony_ci XGBE_SET_LP_ADV(lks, Asym_Pause); 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci if (pdata->phy.pause_autoneg) { 15908c2ecf20Sopenharmony_ci /* Set flow control based on auto-negotiation result */ 15918c2ecf20Sopenharmony_ci pdata->phy.tx_pause = 0; 15928c2ecf20Sopenharmony_ci pdata->phy.rx_pause = 0; 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_ci if (ad_reg & lp_reg & 0x100) { 15958c2ecf20Sopenharmony_ci pdata->phy.tx_pause = 1; 15968c2ecf20Sopenharmony_ci pdata->phy.rx_pause = 1; 15978c2ecf20Sopenharmony_ci } else if (ad_reg & lp_reg & 0x80) { 15988c2ecf20Sopenharmony_ci if (ad_reg & 0x100) 15998c2ecf20Sopenharmony_ci pdata->phy.rx_pause = 1; 16008c2ecf20Sopenharmony_ci else if (lp_reg & 0x100) 16018c2ecf20Sopenharmony_ci pdata->phy.tx_pause = 1; 16028c2ecf20Sopenharmony_ci } 16038c2ecf20Sopenharmony_ci } 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci if (lp_reg & 0x20) 16068c2ecf20Sopenharmony_ci XGBE_SET_LP_ADV(lks, 1000baseX_Full); 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_ci /* Half duplex is not supported */ 16098c2ecf20Sopenharmony_ci ad_reg &= lp_reg; 16108c2ecf20Sopenharmony_ci mode = (ad_reg & 0x20) ? XGBE_MODE_X : XGBE_MODE_UNKNOWN; 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci return mode; 16138c2ecf20Sopenharmony_ci} 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_cistatic enum xgbe_mode xgbe_phy_an73_redrv_outcome(struct xgbe_prv_data *pdata) 16168c2ecf20Sopenharmony_ci{ 16178c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *lks = &pdata->phy.lks; 16188c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 16198c2ecf20Sopenharmony_ci enum xgbe_mode mode; 16208c2ecf20Sopenharmony_ci unsigned int ad_reg, lp_reg; 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_ci XGBE_SET_LP_ADV(lks, Autoneg); 16238c2ecf20Sopenharmony_ci XGBE_SET_LP_ADV(lks, Backplane); 16248c2ecf20Sopenharmony_ci 16258c2ecf20Sopenharmony_ci /* Use external PHY to determine flow control */ 16268c2ecf20Sopenharmony_ci if (pdata->phy.pause_autoneg) 16278c2ecf20Sopenharmony_ci xgbe_phy_phydev_flowctrl(pdata); 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_ci /* Compare Advertisement and Link Partner register 2 */ 16308c2ecf20Sopenharmony_ci ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1); 16318c2ecf20Sopenharmony_ci lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1); 16328c2ecf20Sopenharmony_ci if (lp_reg & 0x80) 16338c2ecf20Sopenharmony_ci XGBE_SET_LP_ADV(lks, 10000baseKR_Full); 16348c2ecf20Sopenharmony_ci if (lp_reg & 0x20) 16358c2ecf20Sopenharmony_ci XGBE_SET_LP_ADV(lks, 1000baseKX_Full); 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_ci ad_reg &= lp_reg; 16388c2ecf20Sopenharmony_ci if (ad_reg & 0x80) { 16398c2ecf20Sopenharmony_ci switch (phy_data->port_mode) { 16408c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE: 16418c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE_NO_AUTONEG: 16428c2ecf20Sopenharmony_ci mode = XGBE_MODE_KR; 16438c2ecf20Sopenharmony_ci break; 16448c2ecf20Sopenharmony_ci default: 16458c2ecf20Sopenharmony_ci mode = XGBE_MODE_SFI; 16468c2ecf20Sopenharmony_ci break; 16478c2ecf20Sopenharmony_ci } 16488c2ecf20Sopenharmony_ci } else if (ad_reg & 0x20) { 16498c2ecf20Sopenharmony_ci switch (phy_data->port_mode) { 16508c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE: 16518c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE_NO_AUTONEG: 16528c2ecf20Sopenharmony_ci mode = XGBE_MODE_KX_1000; 16538c2ecf20Sopenharmony_ci break; 16548c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_1000BASE_X: 16558c2ecf20Sopenharmony_ci mode = XGBE_MODE_X; 16568c2ecf20Sopenharmony_ci break; 16578c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_SFP: 16588c2ecf20Sopenharmony_ci switch (phy_data->sfp_base) { 16598c2ecf20Sopenharmony_ci case XGBE_SFP_BASE_1000_T: 16608c2ecf20Sopenharmony_ci if (phy_data->phydev && 16618c2ecf20Sopenharmony_ci (phy_data->phydev->speed == SPEED_100)) 16628c2ecf20Sopenharmony_ci mode = XGBE_MODE_SGMII_100; 16638c2ecf20Sopenharmony_ci else 16648c2ecf20Sopenharmony_ci mode = XGBE_MODE_SGMII_1000; 16658c2ecf20Sopenharmony_ci break; 16668c2ecf20Sopenharmony_ci case XGBE_SFP_BASE_1000_SX: 16678c2ecf20Sopenharmony_ci case XGBE_SFP_BASE_1000_LX: 16688c2ecf20Sopenharmony_ci case XGBE_SFP_BASE_1000_CX: 16698c2ecf20Sopenharmony_ci default: 16708c2ecf20Sopenharmony_ci mode = XGBE_MODE_X; 16718c2ecf20Sopenharmony_ci break; 16728c2ecf20Sopenharmony_ci } 16738c2ecf20Sopenharmony_ci break; 16748c2ecf20Sopenharmony_ci default: 16758c2ecf20Sopenharmony_ci if (phy_data->phydev && 16768c2ecf20Sopenharmony_ci (phy_data->phydev->speed == SPEED_100)) 16778c2ecf20Sopenharmony_ci mode = XGBE_MODE_SGMII_100; 16788c2ecf20Sopenharmony_ci else 16798c2ecf20Sopenharmony_ci mode = XGBE_MODE_SGMII_1000; 16808c2ecf20Sopenharmony_ci break; 16818c2ecf20Sopenharmony_ci } 16828c2ecf20Sopenharmony_ci } else { 16838c2ecf20Sopenharmony_ci mode = XGBE_MODE_UNKNOWN; 16848c2ecf20Sopenharmony_ci } 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_ci /* Compare Advertisement and Link Partner register 3 */ 16878c2ecf20Sopenharmony_ci ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); 16888c2ecf20Sopenharmony_ci lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2); 16898c2ecf20Sopenharmony_ci if (lp_reg & 0xc000) 16908c2ecf20Sopenharmony_ci XGBE_SET_LP_ADV(lks, 10000baseR_FEC); 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci return mode; 16938c2ecf20Sopenharmony_ci} 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_cistatic enum xgbe_mode xgbe_phy_an73_outcome(struct xgbe_prv_data *pdata) 16968c2ecf20Sopenharmony_ci{ 16978c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *lks = &pdata->phy.lks; 16988c2ecf20Sopenharmony_ci enum xgbe_mode mode; 16998c2ecf20Sopenharmony_ci unsigned int ad_reg, lp_reg; 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_ci XGBE_SET_LP_ADV(lks, Autoneg); 17028c2ecf20Sopenharmony_ci XGBE_SET_LP_ADV(lks, Backplane); 17038c2ecf20Sopenharmony_ci 17048c2ecf20Sopenharmony_ci /* Compare Advertisement and Link Partner register 1 */ 17058c2ecf20Sopenharmony_ci ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE); 17068c2ecf20Sopenharmony_ci lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA); 17078c2ecf20Sopenharmony_ci if (lp_reg & 0x400) 17088c2ecf20Sopenharmony_ci XGBE_SET_LP_ADV(lks, Pause); 17098c2ecf20Sopenharmony_ci if (lp_reg & 0x800) 17108c2ecf20Sopenharmony_ci XGBE_SET_LP_ADV(lks, Asym_Pause); 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_ci if (pdata->phy.pause_autoneg) { 17138c2ecf20Sopenharmony_ci /* Set flow control based on auto-negotiation result */ 17148c2ecf20Sopenharmony_ci pdata->phy.tx_pause = 0; 17158c2ecf20Sopenharmony_ci pdata->phy.rx_pause = 0; 17168c2ecf20Sopenharmony_ci 17178c2ecf20Sopenharmony_ci if (ad_reg & lp_reg & 0x400) { 17188c2ecf20Sopenharmony_ci pdata->phy.tx_pause = 1; 17198c2ecf20Sopenharmony_ci pdata->phy.rx_pause = 1; 17208c2ecf20Sopenharmony_ci } else if (ad_reg & lp_reg & 0x800) { 17218c2ecf20Sopenharmony_ci if (ad_reg & 0x400) 17228c2ecf20Sopenharmony_ci pdata->phy.rx_pause = 1; 17238c2ecf20Sopenharmony_ci else if (lp_reg & 0x400) 17248c2ecf20Sopenharmony_ci pdata->phy.tx_pause = 1; 17258c2ecf20Sopenharmony_ci } 17268c2ecf20Sopenharmony_ci } 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_ci /* Compare Advertisement and Link Partner register 2 */ 17298c2ecf20Sopenharmony_ci ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1); 17308c2ecf20Sopenharmony_ci lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1); 17318c2ecf20Sopenharmony_ci if (lp_reg & 0x80) 17328c2ecf20Sopenharmony_ci XGBE_SET_LP_ADV(lks, 10000baseKR_Full); 17338c2ecf20Sopenharmony_ci if (lp_reg & 0x20) 17348c2ecf20Sopenharmony_ci XGBE_SET_LP_ADV(lks, 1000baseKX_Full); 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_ci ad_reg &= lp_reg; 17378c2ecf20Sopenharmony_ci if (ad_reg & 0x80) 17388c2ecf20Sopenharmony_ci mode = XGBE_MODE_KR; 17398c2ecf20Sopenharmony_ci else if (ad_reg & 0x20) 17408c2ecf20Sopenharmony_ci mode = XGBE_MODE_KX_1000; 17418c2ecf20Sopenharmony_ci else 17428c2ecf20Sopenharmony_ci mode = XGBE_MODE_UNKNOWN; 17438c2ecf20Sopenharmony_ci 17448c2ecf20Sopenharmony_ci /* Compare Advertisement and Link Partner register 3 */ 17458c2ecf20Sopenharmony_ci ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); 17468c2ecf20Sopenharmony_ci lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2); 17478c2ecf20Sopenharmony_ci if (lp_reg & 0xc000) 17488c2ecf20Sopenharmony_ci XGBE_SET_LP_ADV(lks, 10000baseR_FEC); 17498c2ecf20Sopenharmony_ci 17508c2ecf20Sopenharmony_ci return mode; 17518c2ecf20Sopenharmony_ci} 17528c2ecf20Sopenharmony_ci 17538c2ecf20Sopenharmony_cistatic enum xgbe_mode xgbe_phy_an_outcome(struct xgbe_prv_data *pdata) 17548c2ecf20Sopenharmony_ci{ 17558c2ecf20Sopenharmony_ci switch (pdata->an_mode) { 17568c2ecf20Sopenharmony_ci case XGBE_AN_MODE_CL73: 17578c2ecf20Sopenharmony_ci return xgbe_phy_an73_outcome(pdata); 17588c2ecf20Sopenharmony_ci case XGBE_AN_MODE_CL73_REDRV: 17598c2ecf20Sopenharmony_ci return xgbe_phy_an73_redrv_outcome(pdata); 17608c2ecf20Sopenharmony_ci case XGBE_AN_MODE_CL37: 17618c2ecf20Sopenharmony_ci return xgbe_phy_an37_outcome(pdata); 17628c2ecf20Sopenharmony_ci case XGBE_AN_MODE_CL37_SGMII: 17638c2ecf20Sopenharmony_ci return xgbe_phy_an37_sgmii_outcome(pdata); 17648c2ecf20Sopenharmony_ci default: 17658c2ecf20Sopenharmony_ci return XGBE_MODE_UNKNOWN; 17668c2ecf20Sopenharmony_ci } 17678c2ecf20Sopenharmony_ci} 17688c2ecf20Sopenharmony_ci 17698c2ecf20Sopenharmony_cistatic void xgbe_phy_an_advertising(struct xgbe_prv_data *pdata, 17708c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *dlks) 17718c2ecf20Sopenharmony_ci{ 17728c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *slks = &pdata->phy.lks; 17738c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_ci XGBE_LM_COPY(dlks, advertising, slks, advertising); 17768c2ecf20Sopenharmony_ci 17778c2ecf20Sopenharmony_ci /* Without a re-driver, just return current advertising */ 17788c2ecf20Sopenharmony_ci if (!phy_data->redrv) 17798c2ecf20Sopenharmony_ci return; 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_ci /* With the KR re-driver we need to advertise a single speed */ 17828c2ecf20Sopenharmony_ci XGBE_CLR_ADV(dlks, 1000baseKX_Full); 17838c2ecf20Sopenharmony_ci XGBE_CLR_ADV(dlks, 10000baseKR_Full); 17848c2ecf20Sopenharmony_ci 17858c2ecf20Sopenharmony_ci /* Advertise FEC support is present */ 17868c2ecf20Sopenharmony_ci if (pdata->fec_ability & MDIO_PMA_10GBR_FECABLE_ABLE) 17878c2ecf20Sopenharmony_ci XGBE_SET_ADV(dlks, 10000baseR_FEC); 17888c2ecf20Sopenharmony_ci 17898c2ecf20Sopenharmony_ci switch (phy_data->port_mode) { 17908c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE: 17918c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE_NO_AUTONEG: 17928c2ecf20Sopenharmony_ci XGBE_SET_ADV(dlks, 10000baseKR_Full); 17938c2ecf20Sopenharmony_ci break; 17948c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE_2500: 17958c2ecf20Sopenharmony_ci XGBE_SET_ADV(dlks, 1000baseKX_Full); 17968c2ecf20Sopenharmony_ci break; 17978c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_1000BASE_T: 17988c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_1000BASE_X: 17998c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_NBASE_T: 18008c2ecf20Sopenharmony_ci XGBE_SET_ADV(dlks, 1000baseKX_Full); 18018c2ecf20Sopenharmony_ci break; 18028c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_10GBASE_T: 18038c2ecf20Sopenharmony_ci if (phy_data->phydev && 18048c2ecf20Sopenharmony_ci (phy_data->phydev->speed == SPEED_10000)) 18058c2ecf20Sopenharmony_ci XGBE_SET_ADV(dlks, 10000baseKR_Full); 18068c2ecf20Sopenharmony_ci else 18078c2ecf20Sopenharmony_ci XGBE_SET_ADV(dlks, 1000baseKX_Full); 18088c2ecf20Sopenharmony_ci break; 18098c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_10GBASE_R: 18108c2ecf20Sopenharmony_ci XGBE_SET_ADV(dlks, 10000baseKR_Full); 18118c2ecf20Sopenharmony_ci break; 18128c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_SFP: 18138c2ecf20Sopenharmony_ci switch (phy_data->sfp_base) { 18148c2ecf20Sopenharmony_ci case XGBE_SFP_BASE_1000_T: 18158c2ecf20Sopenharmony_ci case XGBE_SFP_BASE_1000_SX: 18168c2ecf20Sopenharmony_ci case XGBE_SFP_BASE_1000_LX: 18178c2ecf20Sopenharmony_ci case XGBE_SFP_BASE_1000_CX: 18188c2ecf20Sopenharmony_ci XGBE_SET_ADV(dlks, 1000baseKX_Full); 18198c2ecf20Sopenharmony_ci break; 18208c2ecf20Sopenharmony_ci default: 18218c2ecf20Sopenharmony_ci XGBE_SET_ADV(dlks, 10000baseKR_Full); 18228c2ecf20Sopenharmony_ci break; 18238c2ecf20Sopenharmony_ci } 18248c2ecf20Sopenharmony_ci break; 18258c2ecf20Sopenharmony_ci default: 18268c2ecf20Sopenharmony_ci XGBE_SET_ADV(dlks, 10000baseKR_Full); 18278c2ecf20Sopenharmony_ci break; 18288c2ecf20Sopenharmony_ci } 18298c2ecf20Sopenharmony_ci} 18308c2ecf20Sopenharmony_ci 18318c2ecf20Sopenharmony_cistatic int xgbe_phy_an_config(struct xgbe_prv_data *pdata) 18328c2ecf20Sopenharmony_ci{ 18338c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *lks = &pdata->phy.lks; 18348c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 18358c2ecf20Sopenharmony_ci int ret; 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_ci ret = xgbe_phy_find_phy_device(pdata); 18388c2ecf20Sopenharmony_ci if (ret) 18398c2ecf20Sopenharmony_ci return ret; 18408c2ecf20Sopenharmony_ci 18418c2ecf20Sopenharmony_ci if (!phy_data->phydev) 18428c2ecf20Sopenharmony_ci return 0; 18438c2ecf20Sopenharmony_ci 18448c2ecf20Sopenharmony_ci phy_data->phydev->autoneg = pdata->phy.autoneg; 18458c2ecf20Sopenharmony_ci linkmode_and(phy_data->phydev->advertising, 18468c2ecf20Sopenharmony_ci phy_data->phydev->supported, 18478c2ecf20Sopenharmony_ci lks->link_modes.advertising); 18488c2ecf20Sopenharmony_ci 18498c2ecf20Sopenharmony_ci if (pdata->phy.autoneg != AUTONEG_ENABLE) { 18508c2ecf20Sopenharmony_ci phy_data->phydev->speed = pdata->phy.speed; 18518c2ecf20Sopenharmony_ci phy_data->phydev->duplex = pdata->phy.duplex; 18528c2ecf20Sopenharmony_ci } 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_ci ret = phy_start_aneg(phy_data->phydev); 18558c2ecf20Sopenharmony_ci 18568c2ecf20Sopenharmony_ci return ret; 18578c2ecf20Sopenharmony_ci} 18588c2ecf20Sopenharmony_ci 18598c2ecf20Sopenharmony_cistatic enum xgbe_an_mode xgbe_phy_an_sfp_mode(struct xgbe_phy_data *phy_data) 18608c2ecf20Sopenharmony_ci{ 18618c2ecf20Sopenharmony_ci switch (phy_data->sfp_base) { 18628c2ecf20Sopenharmony_ci case XGBE_SFP_BASE_1000_T: 18638c2ecf20Sopenharmony_ci return XGBE_AN_MODE_CL37_SGMII; 18648c2ecf20Sopenharmony_ci case XGBE_SFP_BASE_1000_SX: 18658c2ecf20Sopenharmony_ci case XGBE_SFP_BASE_1000_LX: 18668c2ecf20Sopenharmony_ci case XGBE_SFP_BASE_1000_CX: 18678c2ecf20Sopenharmony_ci return XGBE_AN_MODE_CL37; 18688c2ecf20Sopenharmony_ci default: 18698c2ecf20Sopenharmony_ci return XGBE_AN_MODE_NONE; 18708c2ecf20Sopenharmony_ci } 18718c2ecf20Sopenharmony_ci} 18728c2ecf20Sopenharmony_ci 18738c2ecf20Sopenharmony_cistatic enum xgbe_an_mode xgbe_phy_an_mode(struct xgbe_prv_data *pdata) 18748c2ecf20Sopenharmony_ci{ 18758c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 18768c2ecf20Sopenharmony_ci 18778c2ecf20Sopenharmony_ci /* A KR re-driver will always require CL73 AN */ 18788c2ecf20Sopenharmony_ci if (phy_data->redrv) 18798c2ecf20Sopenharmony_ci return XGBE_AN_MODE_CL73_REDRV; 18808c2ecf20Sopenharmony_ci 18818c2ecf20Sopenharmony_ci switch (phy_data->port_mode) { 18828c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE: 18838c2ecf20Sopenharmony_ci return XGBE_AN_MODE_CL73; 18848c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE_NO_AUTONEG: 18858c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE_2500: 18868c2ecf20Sopenharmony_ci return XGBE_AN_MODE_NONE; 18878c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_1000BASE_T: 18888c2ecf20Sopenharmony_ci return XGBE_AN_MODE_CL37_SGMII; 18898c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_1000BASE_X: 18908c2ecf20Sopenharmony_ci return XGBE_AN_MODE_CL37; 18918c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_NBASE_T: 18928c2ecf20Sopenharmony_ci return XGBE_AN_MODE_CL37_SGMII; 18938c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_10GBASE_T: 18948c2ecf20Sopenharmony_ci return XGBE_AN_MODE_CL73; 18958c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_10GBASE_R: 18968c2ecf20Sopenharmony_ci return XGBE_AN_MODE_NONE; 18978c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_SFP: 18988c2ecf20Sopenharmony_ci return xgbe_phy_an_sfp_mode(phy_data); 18998c2ecf20Sopenharmony_ci default: 19008c2ecf20Sopenharmony_ci return XGBE_AN_MODE_NONE; 19018c2ecf20Sopenharmony_ci } 19028c2ecf20Sopenharmony_ci} 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_cistatic int xgbe_phy_set_redrv_mode_mdio(struct xgbe_prv_data *pdata, 19058c2ecf20Sopenharmony_ci enum xgbe_phy_redrv_mode mode) 19068c2ecf20Sopenharmony_ci{ 19078c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 19088c2ecf20Sopenharmony_ci u16 redrv_reg, redrv_val; 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_ci redrv_reg = XGBE_PHY_REDRV_MODE_REG + (phy_data->redrv_lane * 0x1000); 19118c2ecf20Sopenharmony_ci redrv_val = (u16)mode; 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_ci return pdata->hw_if.write_ext_mii_regs(pdata, phy_data->redrv_addr, 19148c2ecf20Sopenharmony_ci redrv_reg, redrv_val); 19158c2ecf20Sopenharmony_ci} 19168c2ecf20Sopenharmony_ci 19178c2ecf20Sopenharmony_cistatic int xgbe_phy_set_redrv_mode_i2c(struct xgbe_prv_data *pdata, 19188c2ecf20Sopenharmony_ci enum xgbe_phy_redrv_mode mode) 19198c2ecf20Sopenharmony_ci{ 19208c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 19218c2ecf20Sopenharmony_ci unsigned int redrv_reg; 19228c2ecf20Sopenharmony_ci int ret; 19238c2ecf20Sopenharmony_ci 19248c2ecf20Sopenharmony_ci /* Calculate the register to write */ 19258c2ecf20Sopenharmony_ci redrv_reg = XGBE_PHY_REDRV_MODE_REG + (phy_data->redrv_lane * 0x1000); 19268c2ecf20Sopenharmony_ci 19278c2ecf20Sopenharmony_ci ret = xgbe_phy_redrv_write(pdata, redrv_reg, mode); 19288c2ecf20Sopenharmony_ci 19298c2ecf20Sopenharmony_ci return ret; 19308c2ecf20Sopenharmony_ci} 19318c2ecf20Sopenharmony_ci 19328c2ecf20Sopenharmony_cistatic void xgbe_phy_set_redrv_mode(struct xgbe_prv_data *pdata) 19338c2ecf20Sopenharmony_ci{ 19348c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 19358c2ecf20Sopenharmony_ci enum xgbe_phy_redrv_mode mode; 19368c2ecf20Sopenharmony_ci int ret; 19378c2ecf20Sopenharmony_ci 19388c2ecf20Sopenharmony_ci if (!phy_data->redrv) 19398c2ecf20Sopenharmony_ci return; 19408c2ecf20Sopenharmony_ci 19418c2ecf20Sopenharmony_ci mode = XGBE_PHY_REDRV_MODE_CX; 19428c2ecf20Sopenharmony_ci if ((phy_data->port_mode == XGBE_PORT_MODE_SFP) && 19438c2ecf20Sopenharmony_ci (phy_data->sfp_base != XGBE_SFP_BASE_1000_CX) && 19448c2ecf20Sopenharmony_ci (phy_data->sfp_base != XGBE_SFP_BASE_10000_CR)) 19458c2ecf20Sopenharmony_ci mode = XGBE_PHY_REDRV_MODE_SR; 19468c2ecf20Sopenharmony_ci 19478c2ecf20Sopenharmony_ci ret = xgbe_phy_get_comm_ownership(pdata); 19488c2ecf20Sopenharmony_ci if (ret) 19498c2ecf20Sopenharmony_ci return; 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_ci if (phy_data->redrv_if) 19528c2ecf20Sopenharmony_ci xgbe_phy_set_redrv_mode_i2c(pdata, mode); 19538c2ecf20Sopenharmony_ci else 19548c2ecf20Sopenharmony_ci xgbe_phy_set_redrv_mode_mdio(pdata, mode); 19558c2ecf20Sopenharmony_ci 19568c2ecf20Sopenharmony_ci xgbe_phy_put_comm_ownership(pdata); 19578c2ecf20Sopenharmony_ci} 19588c2ecf20Sopenharmony_ci 19598c2ecf20Sopenharmony_cistatic void xgbe_phy_rx_reset(struct xgbe_prv_data *pdata) 19608c2ecf20Sopenharmony_ci{ 19618c2ecf20Sopenharmony_ci int reg; 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci reg = XMDIO_READ_BITS(pdata, MDIO_MMD_PCS, MDIO_PCS_DIGITAL_STAT, 19648c2ecf20Sopenharmony_ci XGBE_PCS_PSEQ_STATE_MASK); 19658c2ecf20Sopenharmony_ci if (reg == XGBE_PCS_PSEQ_STATE_POWER_GOOD) { 19668c2ecf20Sopenharmony_ci /* Mailbox command timed out, reset of RX block is required. 19678c2ecf20Sopenharmony_ci * This can be done by asseting the reset bit and wait for 19688c2ecf20Sopenharmony_ci * its compeletion. 19698c2ecf20Sopenharmony_ci */ 19708c2ecf20Sopenharmony_ci XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_RX_CTRL1, 19718c2ecf20Sopenharmony_ci XGBE_PMA_RX_RST_0_MASK, XGBE_PMA_RX_RST_0_RESET_ON); 19728c2ecf20Sopenharmony_ci ndelay(20); 19738c2ecf20Sopenharmony_ci XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_RX_CTRL1, 19748c2ecf20Sopenharmony_ci XGBE_PMA_RX_RST_0_MASK, XGBE_PMA_RX_RST_0_RESET_OFF); 19758c2ecf20Sopenharmony_ci usleep_range(40, 50); 19768c2ecf20Sopenharmony_ci netif_err(pdata, link, pdata->netdev, "firmware mailbox reset performed\n"); 19778c2ecf20Sopenharmony_ci } 19788c2ecf20Sopenharmony_ci} 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_cistatic void xgbe_phy_pll_ctrl(struct xgbe_prv_data *pdata, bool enable) 19818c2ecf20Sopenharmony_ci{ 19828c2ecf20Sopenharmony_ci XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_VEND2_PMA_MISC_CTRL0, 19838c2ecf20Sopenharmony_ci XGBE_PMA_PLL_CTRL_MASK, 19848c2ecf20Sopenharmony_ci enable ? XGBE_PMA_PLL_CTRL_ENABLE 19858c2ecf20Sopenharmony_ci : XGBE_PMA_PLL_CTRL_DISABLE); 19868c2ecf20Sopenharmony_ci 19878c2ecf20Sopenharmony_ci /* Wait for command to complete */ 19888c2ecf20Sopenharmony_ci usleep_range(100, 200); 19898c2ecf20Sopenharmony_ci} 19908c2ecf20Sopenharmony_ci 19918c2ecf20Sopenharmony_cistatic void xgbe_phy_perform_ratechange(struct xgbe_prv_data *pdata, 19928c2ecf20Sopenharmony_ci unsigned int cmd, unsigned int sub_cmd) 19938c2ecf20Sopenharmony_ci{ 19948c2ecf20Sopenharmony_ci unsigned int s0 = 0; 19958c2ecf20Sopenharmony_ci unsigned int wait; 19968c2ecf20Sopenharmony_ci 19978c2ecf20Sopenharmony_ci /* Disable PLL re-initialization during FW command processing */ 19988c2ecf20Sopenharmony_ci xgbe_phy_pll_ctrl(pdata, false); 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_ci /* Log if a previous command did not complete */ 20018c2ecf20Sopenharmony_ci if (XP_IOREAD_BITS(pdata, XP_DRIVER_INT_RO, STATUS)) { 20028c2ecf20Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, 20038c2ecf20Sopenharmony_ci "firmware mailbox not ready for command\n"); 20048c2ecf20Sopenharmony_ci xgbe_phy_rx_reset(pdata); 20058c2ecf20Sopenharmony_ci } 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_ci /* Construct the command */ 20088c2ecf20Sopenharmony_ci XP_SET_BITS(s0, XP_DRIVER_SCRATCH_0, COMMAND, cmd); 20098c2ecf20Sopenharmony_ci XP_SET_BITS(s0, XP_DRIVER_SCRATCH_0, SUB_COMMAND, sub_cmd); 20108c2ecf20Sopenharmony_ci 20118c2ecf20Sopenharmony_ci /* Issue the command */ 20128c2ecf20Sopenharmony_ci XP_IOWRITE(pdata, XP_DRIVER_SCRATCH_0, s0); 20138c2ecf20Sopenharmony_ci XP_IOWRITE(pdata, XP_DRIVER_SCRATCH_1, 0); 20148c2ecf20Sopenharmony_ci XP_IOWRITE_BITS(pdata, XP_DRIVER_INT_REQ, REQUEST, 1); 20158c2ecf20Sopenharmony_ci 20168c2ecf20Sopenharmony_ci /* Wait for command to complete */ 20178c2ecf20Sopenharmony_ci wait = XGBE_RATECHANGE_COUNT; 20188c2ecf20Sopenharmony_ci while (wait--) { 20198c2ecf20Sopenharmony_ci if (!XP_IOREAD_BITS(pdata, XP_DRIVER_INT_RO, STATUS)) 20208c2ecf20Sopenharmony_ci goto reenable_pll; 20218c2ecf20Sopenharmony_ci 20228c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 20238c2ecf20Sopenharmony_ci } 20248c2ecf20Sopenharmony_ci 20258c2ecf20Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, 20268c2ecf20Sopenharmony_ci "firmware mailbox command did not complete\n"); 20278c2ecf20Sopenharmony_ci 20288c2ecf20Sopenharmony_ci /* Reset on error */ 20298c2ecf20Sopenharmony_ci xgbe_phy_rx_reset(pdata); 20308c2ecf20Sopenharmony_ci 20318c2ecf20Sopenharmony_cireenable_pll: 20328c2ecf20Sopenharmony_ci /* Enable PLL re-initialization */ 20338c2ecf20Sopenharmony_ci xgbe_phy_pll_ctrl(pdata, true); 20348c2ecf20Sopenharmony_ci} 20358c2ecf20Sopenharmony_ci 20368c2ecf20Sopenharmony_cistatic void xgbe_phy_rrc(struct xgbe_prv_data *pdata) 20378c2ecf20Sopenharmony_ci{ 20388c2ecf20Sopenharmony_ci /* Receiver Reset Cycle */ 20398c2ecf20Sopenharmony_ci xgbe_phy_perform_ratechange(pdata, 5, 0); 20408c2ecf20Sopenharmony_ci 20418c2ecf20Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, "receiver reset complete\n"); 20428c2ecf20Sopenharmony_ci} 20438c2ecf20Sopenharmony_ci 20448c2ecf20Sopenharmony_cistatic void xgbe_phy_power_off(struct xgbe_prv_data *pdata) 20458c2ecf20Sopenharmony_ci{ 20468c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 20478c2ecf20Sopenharmony_ci 20488c2ecf20Sopenharmony_ci /* Power off */ 20498c2ecf20Sopenharmony_ci xgbe_phy_perform_ratechange(pdata, 0, 0); 20508c2ecf20Sopenharmony_ci 20518c2ecf20Sopenharmony_ci phy_data->cur_mode = XGBE_MODE_UNKNOWN; 20528c2ecf20Sopenharmony_ci 20538c2ecf20Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, "phy powered off\n"); 20548c2ecf20Sopenharmony_ci} 20558c2ecf20Sopenharmony_ci 20568c2ecf20Sopenharmony_cistatic void xgbe_phy_sfi_mode(struct xgbe_prv_data *pdata) 20578c2ecf20Sopenharmony_ci{ 20588c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_ci xgbe_phy_set_redrv_mode(pdata); 20618c2ecf20Sopenharmony_ci 20628c2ecf20Sopenharmony_ci /* 10G/SFI */ 20638c2ecf20Sopenharmony_ci if (phy_data->sfp_cable != XGBE_SFP_CABLE_PASSIVE) { 20648c2ecf20Sopenharmony_ci xgbe_phy_perform_ratechange(pdata, 3, 0); 20658c2ecf20Sopenharmony_ci } else { 20668c2ecf20Sopenharmony_ci if (phy_data->sfp_cable_len <= 1) 20678c2ecf20Sopenharmony_ci xgbe_phy_perform_ratechange(pdata, 3, 1); 20688c2ecf20Sopenharmony_ci else if (phy_data->sfp_cable_len <= 3) 20698c2ecf20Sopenharmony_ci xgbe_phy_perform_ratechange(pdata, 3, 2); 20708c2ecf20Sopenharmony_ci else 20718c2ecf20Sopenharmony_ci xgbe_phy_perform_ratechange(pdata, 3, 3); 20728c2ecf20Sopenharmony_ci } 20738c2ecf20Sopenharmony_ci 20748c2ecf20Sopenharmony_ci phy_data->cur_mode = XGBE_MODE_SFI; 20758c2ecf20Sopenharmony_ci 20768c2ecf20Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, "10GbE SFI mode set\n"); 20778c2ecf20Sopenharmony_ci} 20788c2ecf20Sopenharmony_ci 20798c2ecf20Sopenharmony_cistatic void xgbe_phy_x_mode(struct xgbe_prv_data *pdata) 20808c2ecf20Sopenharmony_ci{ 20818c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 20828c2ecf20Sopenharmony_ci 20838c2ecf20Sopenharmony_ci xgbe_phy_set_redrv_mode(pdata); 20848c2ecf20Sopenharmony_ci 20858c2ecf20Sopenharmony_ci /* 1G/X */ 20868c2ecf20Sopenharmony_ci xgbe_phy_perform_ratechange(pdata, 1, 3); 20878c2ecf20Sopenharmony_ci 20888c2ecf20Sopenharmony_ci phy_data->cur_mode = XGBE_MODE_X; 20898c2ecf20Sopenharmony_ci 20908c2ecf20Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, "1GbE X mode set\n"); 20918c2ecf20Sopenharmony_ci} 20928c2ecf20Sopenharmony_ci 20938c2ecf20Sopenharmony_cistatic void xgbe_phy_sgmii_1000_mode(struct xgbe_prv_data *pdata) 20948c2ecf20Sopenharmony_ci{ 20958c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 20968c2ecf20Sopenharmony_ci 20978c2ecf20Sopenharmony_ci xgbe_phy_set_redrv_mode(pdata); 20988c2ecf20Sopenharmony_ci 20998c2ecf20Sopenharmony_ci /* 1G/SGMII */ 21008c2ecf20Sopenharmony_ci xgbe_phy_perform_ratechange(pdata, 1, 2); 21018c2ecf20Sopenharmony_ci 21028c2ecf20Sopenharmony_ci phy_data->cur_mode = XGBE_MODE_SGMII_1000; 21038c2ecf20Sopenharmony_ci 21048c2ecf20Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, "1GbE SGMII mode set\n"); 21058c2ecf20Sopenharmony_ci} 21068c2ecf20Sopenharmony_ci 21078c2ecf20Sopenharmony_cistatic void xgbe_phy_sgmii_100_mode(struct xgbe_prv_data *pdata) 21088c2ecf20Sopenharmony_ci{ 21098c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_ci xgbe_phy_set_redrv_mode(pdata); 21128c2ecf20Sopenharmony_ci 21138c2ecf20Sopenharmony_ci /* 100M/SGMII */ 21148c2ecf20Sopenharmony_ci xgbe_phy_perform_ratechange(pdata, 1, 1); 21158c2ecf20Sopenharmony_ci 21168c2ecf20Sopenharmony_ci phy_data->cur_mode = XGBE_MODE_SGMII_100; 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, "100MbE SGMII mode set\n"); 21198c2ecf20Sopenharmony_ci} 21208c2ecf20Sopenharmony_ci 21218c2ecf20Sopenharmony_cistatic void xgbe_phy_kr_mode(struct xgbe_prv_data *pdata) 21228c2ecf20Sopenharmony_ci{ 21238c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 21248c2ecf20Sopenharmony_ci 21258c2ecf20Sopenharmony_ci xgbe_phy_set_redrv_mode(pdata); 21268c2ecf20Sopenharmony_ci 21278c2ecf20Sopenharmony_ci /* 10G/KR */ 21288c2ecf20Sopenharmony_ci xgbe_phy_perform_ratechange(pdata, 4, 0); 21298c2ecf20Sopenharmony_ci 21308c2ecf20Sopenharmony_ci phy_data->cur_mode = XGBE_MODE_KR; 21318c2ecf20Sopenharmony_ci 21328c2ecf20Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, "10GbE KR mode set\n"); 21338c2ecf20Sopenharmony_ci} 21348c2ecf20Sopenharmony_ci 21358c2ecf20Sopenharmony_cistatic void xgbe_phy_kx_2500_mode(struct xgbe_prv_data *pdata) 21368c2ecf20Sopenharmony_ci{ 21378c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 21388c2ecf20Sopenharmony_ci 21398c2ecf20Sopenharmony_ci xgbe_phy_set_redrv_mode(pdata); 21408c2ecf20Sopenharmony_ci 21418c2ecf20Sopenharmony_ci /* 2.5G/KX */ 21428c2ecf20Sopenharmony_ci xgbe_phy_perform_ratechange(pdata, 2, 0); 21438c2ecf20Sopenharmony_ci 21448c2ecf20Sopenharmony_ci phy_data->cur_mode = XGBE_MODE_KX_2500; 21458c2ecf20Sopenharmony_ci 21468c2ecf20Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, "2.5GbE KX mode set\n"); 21478c2ecf20Sopenharmony_ci} 21488c2ecf20Sopenharmony_ci 21498c2ecf20Sopenharmony_cistatic void xgbe_phy_kx_1000_mode(struct xgbe_prv_data *pdata) 21508c2ecf20Sopenharmony_ci{ 21518c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 21528c2ecf20Sopenharmony_ci 21538c2ecf20Sopenharmony_ci xgbe_phy_set_redrv_mode(pdata); 21548c2ecf20Sopenharmony_ci 21558c2ecf20Sopenharmony_ci /* 1G/KX */ 21568c2ecf20Sopenharmony_ci xgbe_phy_perform_ratechange(pdata, 1, 3); 21578c2ecf20Sopenharmony_ci 21588c2ecf20Sopenharmony_ci phy_data->cur_mode = XGBE_MODE_KX_1000; 21598c2ecf20Sopenharmony_ci 21608c2ecf20Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, "1GbE KX mode set\n"); 21618c2ecf20Sopenharmony_ci} 21628c2ecf20Sopenharmony_ci 21638c2ecf20Sopenharmony_cistatic enum xgbe_mode xgbe_phy_cur_mode(struct xgbe_prv_data *pdata) 21648c2ecf20Sopenharmony_ci{ 21658c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 21668c2ecf20Sopenharmony_ci 21678c2ecf20Sopenharmony_ci return phy_data->cur_mode; 21688c2ecf20Sopenharmony_ci} 21698c2ecf20Sopenharmony_ci 21708c2ecf20Sopenharmony_cistatic enum xgbe_mode xgbe_phy_switch_baset_mode(struct xgbe_prv_data *pdata) 21718c2ecf20Sopenharmony_ci{ 21728c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 21738c2ecf20Sopenharmony_ci 21748c2ecf20Sopenharmony_ci /* No switching if not 10GBase-T */ 21758c2ecf20Sopenharmony_ci if (phy_data->port_mode != XGBE_PORT_MODE_10GBASE_T) 21768c2ecf20Sopenharmony_ci return xgbe_phy_cur_mode(pdata); 21778c2ecf20Sopenharmony_ci 21788c2ecf20Sopenharmony_ci switch (xgbe_phy_cur_mode(pdata)) { 21798c2ecf20Sopenharmony_ci case XGBE_MODE_SGMII_100: 21808c2ecf20Sopenharmony_ci case XGBE_MODE_SGMII_1000: 21818c2ecf20Sopenharmony_ci return XGBE_MODE_KR; 21828c2ecf20Sopenharmony_ci case XGBE_MODE_KR: 21838c2ecf20Sopenharmony_ci default: 21848c2ecf20Sopenharmony_ci return XGBE_MODE_SGMII_1000; 21858c2ecf20Sopenharmony_ci } 21868c2ecf20Sopenharmony_ci} 21878c2ecf20Sopenharmony_ci 21888c2ecf20Sopenharmony_cistatic enum xgbe_mode xgbe_phy_switch_bp_2500_mode(struct xgbe_prv_data *pdata) 21898c2ecf20Sopenharmony_ci{ 21908c2ecf20Sopenharmony_ci return XGBE_MODE_KX_2500; 21918c2ecf20Sopenharmony_ci} 21928c2ecf20Sopenharmony_ci 21938c2ecf20Sopenharmony_cistatic enum xgbe_mode xgbe_phy_switch_bp_mode(struct xgbe_prv_data *pdata) 21948c2ecf20Sopenharmony_ci{ 21958c2ecf20Sopenharmony_ci /* If we are in KR switch to KX, and vice-versa */ 21968c2ecf20Sopenharmony_ci switch (xgbe_phy_cur_mode(pdata)) { 21978c2ecf20Sopenharmony_ci case XGBE_MODE_KX_1000: 21988c2ecf20Sopenharmony_ci return XGBE_MODE_KR; 21998c2ecf20Sopenharmony_ci case XGBE_MODE_KR: 22008c2ecf20Sopenharmony_ci default: 22018c2ecf20Sopenharmony_ci return XGBE_MODE_KX_1000; 22028c2ecf20Sopenharmony_ci } 22038c2ecf20Sopenharmony_ci} 22048c2ecf20Sopenharmony_ci 22058c2ecf20Sopenharmony_cistatic enum xgbe_mode xgbe_phy_switch_mode(struct xgbe_prv_data *pdata) 22068c2ecf20Sopenharmony_ci{ 22078c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 22088c2ecf20Sopenharmony_ci 22098c2ecf20Sopenharmony_ci switch (phy_data->port_mode) { 22108c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE: 22118c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE_NO_AUTONEG: 22128c2ecf20Sopenharmony_ci return xgbe_phy_switch_bp_mode(pdata); 22138c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE_2500: 22148c2ecf20Sopenharmony_ci return xgbe_phy_switch_bp_2500_mode(pdata); 22158c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_1000BASE_T: 22168c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_NBASE_T: 22178c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_10GBASE_T: 22188c2ecf20Sopenharmony_ci return xgbe_phy_switch_baset_mode(pdata); 22198c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_1000BASE_X: 22208c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_10GBASE_R: 22218c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_SFP: 22228c2ecf20Sopenharmony_ci /* No switching, so just return current mode */ 22238c2ecf20Sopenharmony_ci return xgbe_phy_cur_mode(pdata); 22248c2ecf20Sopenharmony_ci default: 22258c2ecf20Sopenharmony_ci return XGBE_MODE_UNKNOWN; 22268c2ecf20Sopenharmony_ci } 22278c2ecf20Sopenharmony_ci} 22288c2ecf20Sopenharmony_ci 22298c2ecf20Sopenharmony_cistatic enum xgbe_mode xgbe_phy_get_basex_mode(struct xgbe_phy_data *phy_data, 22308c2ecf20Sopenharmony_ci int speed) 22318c2ecf20Sopenharmony_ci{ 22328c2ecf20Sopenharmony_ci switch (speed) { 22338c2ecf20Sopenharmony_ci case SPEED_1000: 22348c2ecf20Sopenharmony_ci return XGBE_MODE_X; 22358c2ecf20Sopenharmony_ci case SPEED_10000: 22368c2ecf20Sopenharmony_ci return XGBE_MODE_KR; 22378c2ecf20Sopenharmony_ci default: 22388c2ecf20Sopenharmony_ci return XGBE_MODE_UNKNOWN; 22398c2ecf20Sopenharmony_ci } 22408c2ecf20Sopenharmony_ci} 22418c2ecf20Sopenharmony_ci 22428c2ecf20Sopenharmony_cistatic enum xgbe_mode xgbe_phy_get_baset_mode(struct xgbe_phy_data *phy_data, 22438c2ecf20Sopenharmony_ci int speed) 22448c2ecf20Sopenharmony_ci{ 22458c2ecf20Sopenharmony_ci switch (speed) { 22468c2ecf20Sopenharmony_ci case SPEED_100: 22478c2ecf20Sopenharmony_ci return XGBE_MODE_SGMII_100; 22488c2ecf20Sopenharmony_ci case SPEED_1000: 22498c2ecf20Sopenharmony_ci return XGBE_MODE_SGMII_1000; 22508c2ecf20Sopenharmony_ci case SPEED_2500: 22518c2ecf20Sopenharmony_ci return XGBE_MODE_KX_2500; 22528c2ecf20Sopenharmony_ci case SPEED_10000: 22538c2ecf20Sopenharmony_ci return XGBE_MODE_KR; 22548c2ecf20Sopenharmony_ci default: 22558c2ecf20Sopenharmony_ci return XGBE_MODE_UNKNOWN; 22568c2ecf20Sopenharmony_ci } 22578c2ecf20Sopenharmony_ci} 22588c2ecf20Sopenharmony_ci 22598c2ecf20Sopenharmony_cistatic enum xgbe_mode xgbe_phy_get_sfp_mode(struct xgbe_phy_data *phy_data, 22608c2ecf20Sopenharmony_ci int speed) 22618c2ecf20Sopenharmony_ci{ 22628c2ecf20Sopenharmony_ci switch (speed) { 22638c2ecf20Sopenharmony_ci case SPEED_100: 22648c2ecf20Sopenharmony_ci return XGBE_MODE_SGMII_100; 22658c2ecf20Sopenharmony_ci case SPEED_1000: 22668c2ecf20Sopenharmony_ci if (phy_data->sfp_base == XGBE_SFP_BASE_1000_T) 22678c2ecf20Sopenharmony_ci return XGBE_MODE_SGMII_1000; 22688c2ecf20Sopenharmony_ci else 22698c2ecf20Sopenharmony_ci return XGBE_MODE_X; 22708c2ecf20Sopenharmony_ci case SPEED_10000: 22718c2ecf20Sopenharmony_ci case SPEED_UNKNOWN: 22728c2ecf20Sopenharmony_ci return XGBE_MODE_SFI; 22738c2ecf20Sopenharmony_ci default: 22748c2ecf20Sopenharmony_ci return XGBE_MODE_UNKNOWN; 22758c2ecf20Sopenharmony_ci } 22768c2ecf20Sopenharmony_ci} 22778c2ecf20Sopenharmony_ci 22788c2ecf20Sopenharmony_cistatic enum xgbe_mode xgbe_phy_get_bp_2500_mode(int speed) 22798c2ecf20Sopenharmony_ci{ 22808c2ecf20Sopenharmony_ci switch (speed) { 22818c2ecf20Sopenharmony_ci case SPEED_2500: 22828c2ecf20Sopenharmony_ci return XGBE_MODE_KX_2500; 22838c2ecf20Sopenharmony_ci default: 22848c2ecf20Sopenharmony_ci return XGBE_MODE_UNKNOWN; 22858c2ecf20Sopenharmony_ci } 22868c2ecf20Sopenharmony_ci} 22878c2ecf20Sopenharmony_ci 22888c2ecf20Sopenharmony_cistatic enum xgbe_mode xgbe_phy_get_bp_mode(int speed) 22898c2ecf20Sopenharmony_ci{ 22908c2ecf20Sopenharmony_ci switch (speed) { 22918c2ecf20Sopenharmony_ci case SPEED_1000: 22928c2ecf20Sopenharmony_ci return XGBE_MODE_KX_1000; 22938c2ecf20Sopenharmony_ci case SPEED_10000: 22948c2ecf20Sopenharmony_ci return XGBE_MODE_KR; 22958c2ecf20Sopenharmony_ci default: 22968c2ecf20Sopenharmony_ci return XGBE_MODE_UNKNOWN; 22978c2ecf20Sopenharmony_ci } 22988c2ecf20Sopenharmony_ci} 22998c2ecf20Sopenharmony_ci 23008c2ecf20Sopenharmony_cistatic enum xgbe_mode xgbe_phy_get_mode(struct xgbe_prv_data *pdata, 23018c2ecf20Sopenharmony_ci int speed) 23028c2ecf20Sopenharmony_ci{ 23038c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 23048c2ecf20Sopenharmony_ci 23058c2ecf20Sopenharmony_ci switch (phy_data->port_mode) { 23068c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE: 23078c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE_NO_AUTONEG: 23088c2ecf20Sopenharmony_ci return xgbe_phy_get_bp_mode(speed); 23098c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE_2500: 23108c2ecf20Sopenharmony_ci return xgbe_phy_get_bp_2500_mode(speed); 23118c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_1000BASE_T: 23128c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_NBASE_T: 23138c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_10GBASE_T: 23148c2ecf20Sopenharmony_ci return xgbe_phy_get_baset_mode(phy_data, speed); 23158c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_1000BASE_X: 23168c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_10GBASE_R: 23178c2ecf20Sopenharmony_ci return xgbe_phy_get_basex_mode(phy_data, speed); 23188c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_SFP: 23198c2ecf20Sopenharmony_ci return xgbe_phy_get_sfp_mode(phy_data, speed); 23208c2ecf20Sopenharmony_ci default: 23218c2ecf20Sopenharmony_ci return XGBE_MODE_UNKNOWN; 23228c2ecf20Sopenharmony_ci } 23238c2ecf20Sopenharmony_ci} 23248c2ecf20Sopenharmony_ci 23258c2ecf20Sopenharmony_cistatic void xgbe_phy_set_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode) 23268c2ecf20Sopenharmony_ci{ 23278c2ecf20Sopenharmony_ci switch (mode) { 23288c2ecf20Sopenharmony_ci case XGBE_MODE_KX_1000: 23298c2ecf20Sopenharmony_ci xgbe_phy_kx_1000_mode(pdata); 23308c2ecf20Sopenharmony_ci break; 23318c2ecf20Sopenharmony_ci case XGBE_MODE_KX_2500: 23328c2ecf20Sopenharmony_ci xgbe_phy_kx_2500_mode(pdata); 23338c2ecf20Sopenharmony_ci break; 23348c2ecf20Sopenharmony_ci case XGBE_MODE_KR: 23358c2ecf20Sopenharmony_ci xgbe_phy_kr_mode(pdata); 23368c2ecf20Sopenharmony_ci break; 23378c2ecf20Sopenharmony_ci case XGBE_MODE_SGMII_100: 23388c2ecf20Sopenharmony_ci xgbe_phy_sgmii_100_mode(pdata); 23398c2ecf20Sopenharmony_ci break; 23408c2ecf20Sopenharmony_ci case XGBE_MODE_SGMII_1000: 23418c2ecf20Sopenharmony_ci xgbe_phy_sgmii_1000_mode(pdata); 23428c2ecf20Sopenharmony_ci break; 23438c2ecf20Sopenharmony_ci case XGBE_MODE_X: 23448c2ecf20Sopenharmony_ci xgbe_phy_x_mode(pdata); 23458c2ecf20Sopenharmony_ci break; 23468c2ecf20Sopenharmony_ci case XGBE_MODE_SFI: 23478c2ecf20Sopenharmony_ci xgbe_phy_sfi_mode(pdata); 23488c2ecf20Sopenharmony_ci break; 23498c2ecf20Sopenharmony_ci default: 23508c2ecf20Sopenharmony_ci break; 23518c2ecf20Sopenharmony_ci } 23528c2ecf20Sopenharmony_ci} 23538c2ecf20Sopenharmony_ci 23548c2ecf20Sopenharmony_cistatic bool xgbe_phy_check_mode(struct xgbe_prv_data *pdata, 23558c2ecf20Sopenharmony_ci enum xgbe_mode mode, bool advert) 23568c2ecf20Sopenharmony_ci{ 23578c2ecf20Sopenharmony_ci if (pdata->phy.autoneg == AUTONEG_ENABLE) { 23588c2ecf20Sopenharmony_ci return advert; 23598c2ecf20Sopenharmony_ci } else { 23608c2ecf20Sopenharmony_ci enum xgbe_mode cur_mode; 23618c2ecf20Sopenharmony_ci 23628c2ecf20Sopenharmony_ci cur_mode = xgbe_phy_get_mode(pdata, pdata->phy.speed); 23638c2ecf20Sopenharmony_ci if (cur_mode == mode) 23648c2ecf20Sopenharmony_ci return true; 23658c2ecf20Sopenharmony_ci } 23668c2ecf20Sopenharmony_ci 23678c2ecf20Sopenharmony_ci return false; 23688c2ecf20Sopenharmony_ci} 23698c2ecf20Sopenharmony_ci 23708c2ecf20Sopenharmony_cistatic bool xgbe_phy_use_basex_mode(struct xgbe_prv_data *pdata, 23718c2ecf20Sopenharmony_ci enum xgbe_mode mode) 23728c2ecf20Sopenharmony_ci{ 23738c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *lks = &pdata->phy.lks; 23748c2ecf20Sopenharmony_ci 23758c2ecf20Sopenharmony_ci switch (mode) { 23768c2ecf20Sopenharmony_ci case XGBE_MODE_X: 23778c2ecf20Sopenharmony_ci return xgbe_phy_check_mode(pdata, mode, 23788c2ecf20Sopenharmony_ci XGBE_ADV(lks, 1000baseX_Full)); 23798c2ecf20Sopenharmony_ci case XGBE_MODE_KR: 23808c2ecf20Sopenharmony_ci return xgbe_phy_check_mode(pdata, mode, 23818c2ecf20Sopenharmony_ci XGBE_ADV(lks, 10000baseKR_Full)); 23828c2ecf20Sopenharmony_ci default: 23838c2ecf20Sopenharmony_ci return false; 23848c2ecf20Sopenharmony_ci } 23858c2ecf20Sopenharmony_ci} 23868c2ecf20Sopenharmony_ci 23878c2ecf20Sopenharmony_cistatic bool xgbe_phy_use_baset_mode(struct xgbe_prv_data *pdata, 23888c2ecf20Sopenharmony_ci enum xgbe_mode mode) 23898c2ecf20Sopenharmony_ci{ 23908c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *lks = &pdata->phy.lks; 23918c2ecf20Sopenharmony_ci 23928c2ecf20Sopenharmony_ci switch (mode) { 23938c2ecf20Sopenharmony_ci case XGBE_MODE_SGMII_100: 23948c2ecf20Sopenharmony_ci return xgbe_phy_check_mode(pdata, mode, 23958c2ecf20Sopenharmony_ci XGBE_ADV(lks, 100baseT_Full)); 23968c2ecf20Sopenharmony_ci case XGBE_MODE_SGMII_1000: 23978c2ecf20Sopenharmony_ci return xgbe_phy_check_mode(pdata, mode, 23988c2ecf20Sopenharmony_ci XGBE_ADV(lks, 1000baseT_Full)); 23998c2ecf20Sopenharmony_ci case XGBE_MODE_KX_2500: 24008c2ecf20Sopenharmony_ci return xgbe_phy_check_mode(pdata, mode, 24018c2ecf20Sopenharmony_ci XGBE_ADV(lks, 2500baseT_Full)); 24028c2ecf20Sopenharmony_ci case XGBE_MODE_KR: 24038c2ecf20Sopenharmony_ci return xgbe_phy_check_mode(pdata, mode, 24048c2ecf20Sopenharmony_ci XGBE_ADV(lks, 10000baseT_Full)); 24058c2ecf20Sopenharmony_ci default: 24068c2ecf20Sopenharmony_ci return false; 24078c2ecf20Sopenharmony_ci } 24088c2ecf20Sopenharmony_ci} 24098c2ecf20Sopenharmony_ci 24108c2ecf20Sopenharmony_cistatic bool xgbe_phy_use_sfp_mode(struct xgbe_prv_data *pdata, 24118c2ecf20Sopenharmony_ci enum xgbe_mode mode) 24128c2ecf20Sopenharmony_ci{ 24138c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *lks = &pdata->phy.lks; 24148c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 24158c2ecf20Sopenharmony_ci 24168c2ecf20Sopenharmony_ci switch (mode) { 24178c2ecf20Sopenharmony_ci case XGBE_MODE_X: 24188c2ecf20Sopenharmony_ci if (phy_data->sfp_base == XGBE_SFP_BASE_1000_T) 24198c2ecf20Sopenharmony_ci return false; 24208c2ecf20Sopenharmony_ci return xgbe_phy_check_mode(pdata, mode, 24218c2ecf20Sopenharmony_ci XGBE_ADV(lks, 1000baseX_Full)); 24228c2ecf20Sopenharmony_ci case XGBE_MODE_SGMII_100: 24238c2ecf20Sopenharmony_ci if (phy_data->sfp_base != XGBE_SFP_BASE_1000_T) 24248c2ecf20Sopenharmony_ci return false; 24258c2ecf20Sopenharmony_ci return xgbe_phy_check_mode(pdata, mode, 24268c2ecf20Sopenharmony_ci XGBE_ADV(lks, 100baseT_Full)); 24278c2ecf20Sopenharmony_ci case XGBE_MODE_SGMII_1000: 24288c2ecf20Sopenharmony_ci if (phy_data->sfp_base != XGBE_SFP_BASE_1000_T) 24298c2ecf20Sopenharmony_ci return false; 24308c2ecf20Sopenharmony_ci return xgbe_phy_check_mode(pdata, mode, 24318c2ecf20Sopenharmony_ci XGBE_ADV(lks, 1000baseT_Full)); 24328c2ecf20Sopenharmony_ci case XGBE_MODE_SFI: 24338c2ecf20Sopenharmony_ci if (phy_data->sfp_mod_absent) 24348c2ecf20Sopenharmony_ci return true; 24358c2ecf20Sopenharmony_ci return xgbe_phy_check_mode(pdata, mode, 24368c2ecf20Sopenharmony_ci XGBE_ADV(lks, 10000baseSR_Full) || 24378c2ecf20Sopenharmony_ci XGBE_ADV(lks, 10000baseLR_Full) || 24388c2ecf20Sopenharmony_ci XGBE_ADV(lks, 10000baseLRM_Full) || 24398c2ecf20Sopenharmony_ci XGBE_ADV(lks, 10000baseER_Full) || 24408c2ecf20Sopenharmony_ci XGBE_ADV(lks, 10000baseCR_Full)); 24418c2ecf20Sopenharmony_ci default: 24428c2ecf20Sopenharmony_ci return false; 24438c2ecf20Sopenharmony_ci } 24448c2ecf20Sopenharmony_ci} 24458c2ecf20Sopenharmony_ci 24468c2ecf20Sopenharmony_cistatic bool xgbe_phy_use_bp_2500_mode(struct xgbe_prv_data *pdata, 24478c2ecf20Sopenharmony_ci enum xgbe_mode mode) 24488c2ecf20Sopenharmony_ci{ 24498c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *lks = &pdata->phy.lks; 24508c2ecf20Sopenharmony_ci 24518c2ecf20Sopenharmony_ci switch (mode) { 24528c2ecf20Sopenharmony_ci case XGBE_MODE_KX_2500: 24538c2ecf20Sopenharmony_ci return xgbe_phy_check_mode(pdata, mode, 24548c2ecf20Sopenharmony_ci XGBE_ADV(lks, 2500baseX_Full)); 24558c2ecf20Sopenharmony_ci default: 24568c2ecf20Sopenharmony_ci return false; 24578c2ecf20Sopenharmony_ci } 24588c2ecf20Sopenharmony_ci} 24598c2ecf20Sopenharmony_ci 24608c2ecf20Sopenharmony_cistatic bool xgbe_phy_use_bp_mode(struct xgbe_prv_data *pdata, 24618c2ecf20Sopenharmony_ci enum xgbe_mode mode) 24628c2ecf20Sopenharmony_ci{ 24638c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *lks = &pdata->phy.lks; 24648c2ecf20Sopenharmony_ci 24658c2ecf20Sopenharmony_ci switch (mode) { 24668c2ecf20Sopenharmony_ci case XGBE_MODE_KX_1000: 24678c2ecf20Sopenharmony_ci return xgbe_phy_check_mode(pdata, mode, 24688c2ecf20Sopenharmony_ci XGBE_ADV(lks, 1000baseKX_Full)); 24698c2ecf20Sopenharmony_ci case XGBE_MODE_KR: 24708c2ecf20Sopenharmony_ci return xgbe_phy_check_mode(pdata, mode, 24718c2ecf20Sopenharmony_ci XGBE_ADV(lks, 10000baseKR_Full)); 24728c2ecf20Sopenharmony_ci default: 24738c2ecf20Sopenharmony_ci return false; 24748c2ecf20Sopenharmony_ci } 24758c2ecf20Sopenharmony_ci} 24768c2ecf20Sopenharmony_ci 24778c2ecf20Sopenharmony_cistatic bool xgbe_phy_use_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode) 24788c2ecf20Sopenharmony_ci{ 24798c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 24808c2ecf20Sopenharmony_ci 24818c2ecf20Sopenharmony_ci switch (phy_data->port_mode) { 24828c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE: 24838c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE_NO_AUTONEG: 24848c2ecf20Sopenharmony_ci return xgbe_phy_use_bp_mode(pdata, mode); 24858c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE_2500: 24868c2ecf20Sopenharmony_ci return xgbe_phy_use_bp_2500_mode(pdata, mode); 24878c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_1000BASE_T: 24888c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_NBASE_T: 24898c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_10GBASE_T: 24908c2ecf20Sopenharmony_ci return xgbe_phy_use_baset_mode(pdata, mode); 24918c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_1000BASE_X: 24928c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_10GBASE_R: 24938c2ecf20Sopenharmony_ci return xgbe_phy_use_basex_mode(pdata, mode); 24948c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_SFP: 24958c2ecf20Sopenharmony_ci return xgbe_phy_use_sfp_mode(pdata, mode); 24968c2ecf20Sopenharmony_ci default: 24978c2ecf20Sopenharmony_ci return false; 24988c2ecf20Sopenharmony_ci } 24998c2ecf20Sopenharmony_ci} 25008c2ecf20Sopenharmony_ci 25018c2ecf20Sopenharmony_cistatic bool xgbe_phy_valid_speed_basex_mode(struct xgbe_phy_data *phy_data, 25028c2ecf20Sopenharmony_ci int speed) 25038c2ecf20Sopenharmony_ci{ 25048c2ecf20Sopenharmony_ci switch (speed) { 25058c2ecf20Sopenharmony_ci case SPEED_1000: 25068c2ecf20Sopenharmony_ci return (phy_data->port_mode == XGBE_PORT_MODE_1000BASE_X); 25078c2ecf20Sopenharmony_ci case SPEED_10000: 25088c2ecf20Sopenharmony_ci return (phy_data->port_mode == XGBE_PORT_MODE_10GBASE_R); 25098c2ecf20Sopenharmony_ci default: 25108c2ecf20Sopenharmony_ci return false; 25118c2ecf20Sopenharmony_ci } 25128c2ecf20Sopenharmony_ci} 25138c2ecf20Sopenharmony_ci 25148c2ecf20Sopenharmony_cistatic bool xgbe_phy_valid_speed_baset_mode(struct xgbe_phy_data *phy_data, 25158c2ecf20Sopenharmony_ci int speed) 25168c2ecf20Sopenharmony_ci{ 25178c2ecf20Sopenharmony_ci switch (speed) { 25188c2ecf20Sopenharmony_ci case SPEED_100: 25198c2ecf20Sopenharmony_ci case SPEED_1000: 25208c2ecf20Sopenharmony_ci return true; 25218c2ecf20Sopenharmony_ci case SPEED_2500: 25228c2ecf20Sopenharmony_ci return (phy_data->port_mode == XGBE_PORT_MODE_NBASE_T); 25238c2ecf20Sopenharmony_ci case SPEED_10000: 25248c2ecf20Sopenharmony_ci return (phy_data->port_mode == XGBE_PORT_MODE_10GBASE_T); 25258c2ecf20Sopenharmony_ci default: 25268c2ecf20Sopenharmony_ci return false; 25278c2ecf20Sopenharmony_ci } 25288c2ecf20Sopenharmony_ci} 25298c2ecf20Sopenharmony_ci 25308c2ecf20Sopenharmony_cistatic bool xgbe_phy_valid_speed_sfp_mode(struct xgbe_phy_data *phy_data, 25318c2ecf20Sopenharmony_ci int speed) 25328c2ecf20Sopenharmony_ci{ 25338c2ecf20Sopenharmony_ci switch (speed) { 25348c2ecf20Sopenharmony_ci case SPEED_100: 25358c2ecf20Sopenharmony_ci return (phy_data->sfp_speed == XGBE_SFP_SPEED_100_1000); 25368c2ecf20Sopenharmony_ci case SPEED_1000: 25378c2ecf20Sopenharmony_ci return ((phy_data->sfp_speed == XGBE_SFP_SPEED_100_1000) || 25388c2ecf20Sopenharmony_ci (phy_data->sfp_speed == XGBE_SFP_SPEED_1000)); 25398c2ecf20Sopenharmony_ci case SPEED_10000: 25408c2ecf20Sopenharmony_ci return (phy_data->sfp_speed == XGBE_SFP_SPEED_10000); 25418c2ecf20Sopenharmony_ci default: 25428c2ecf20Sopenharmony_ci return false; 25438c2ecf20Sopenharmony_ci } 25448c2ecf20Sopenharmony_ci} 25458c2ecf20Sopenharmony_ci 25468c2ecf20Sopenharmony_cistatic bool xgbe_phy_valid_speed_bp_2500_mode(int speed) 25478c2ecf20Sopenharmony_ci{ 25488c2ecf20Sopenharmony_ci switch (speed) { 25498c2ecf20Sopenharmony_ci case SPEED_2500: 25508c2ecf20Sopenharmony_ci return true; 25518c2ecf20Sopenharmony_ci default: 25528c2ecf20Sopenharmony_ci return false; 25538c2ecf20Sopenharmony_ci } 25548c2ecf20Sopenharmony_ci} 25558c2ecf20Sopenharmony_ci 25568c2ecf20Sopenharmony_cistatic bool xgbe_phy_valid_speed_bp_mode(int speed) 25578c2ecf20Sopenharmony_ci{ 25588c2ecf20Sopenharmony_ci switch (speed) { 25598c2ecf20Sopenharmony_ci case SPEED_1000: 25608c2ecf20Sopenharmony_ci case SPEED_10000: 25618c2ecf20Sopenharmony_ci return true; 25628c2ecf20Sopenharmony_ci default: 25638c2ecf20Sopenharmony_ci return false; 25648c2ecf20Sopenharmony_ci } 25658c2ecf20Sopenharmony_ci} 25668c2ecf20Sopenharmony_ci 25678c2ecf20Sopenharmony_cistatic bool xgbe_phy_valid_speed(struct xgbe_prv_data *pdata, int speed) 25688c2ecf20Sopenharmony_ci{ 25698c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 25708c2ecf20Sopenharmony_ci 25718c2ecf20Sopenharmony_ci switch (phy_data->port_mode) { 25728c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE: 25738c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE_NO_AUTONEG: 25748c2ecf20Sopenharmony_ci return xgbe_phy_valid_speed_bp_mode(speed); 25758c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE_2500: 25768c2ecf20Sopenharmony_ci return xgbe_phy_valid_speed_bp_2500_mode(speed); 25778c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_1000BASE_T: 25788c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_NBASE_T: 25798c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_10GBASE_T: 25808c2ecf20Sopenharmony_ci return xgbe_phy_valid_speed_baset_mode(phy_data, speed); 25818c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_1000BASE_X: 25828c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_10GBASE_R: 25838c2ecf20Sopenharmony_ci return xgbe_phy_valid_speed_basex_mode(phy_data, speed); 25848c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_SFP: 25858c2ecf20Sopenharmony_ci return xgbe_phy_valid_speed_sfp_mode(phy_data, speed); 25868c2ecf20Sopenharmony_ci default: 25878c2ecf20Sopenharmony_ci return false; 25888c2ecf20Sopenharmony_ci } 25898c2ecf20Sopenharmony_ci} 25908c2ecf20Sopenharmony_ci 25918c2ecf20Sopenharmony_cistatic int xgbe_phy_link_status(struct xgbe_prv_data *pdata, int *an_restart) 25928c2ecf20Sopenharmony_ci{ 25938c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 25948c2ecf20Sopenharmony_ci unsigned int reg; 25958c2ecf20Sopenharmony_ci int ret; 25968c2ecf20Sopenharmony_ci 25978c2ecf20Sopenharmony_ci *an_restart = 0; 25988c2ecf20Sopenharmony_ci 25998c2ecf20Sopenharmony_ci if (phy_data->port_mode == XGBE_PORT_MODE_SFP) { 26008c2ecf20Sopenharmony_ci /* Check SFP signals */ 26018c2ecf20Sopenharmony_ci xgbe_phy_sfp_detect(pdata); 26028c2ecf20Sopenharmony_ci 26038c2ecf20Sopenharmony_ci if (phy_data->sfp_changed) { 26048c2ecf20Sopenharmony_ci *an_restart = 1; 26058c2ecf20Sopenharmony_ci return 0; 26068c2ecf20Sopenharmony_ci } 26078c2ecf20Sopenharmony_ci 26088c2ecf20Sopenharmony_ci if (phy_data->sfp_mod_absent || phy_data->sfp_rx_los) 26098c2ecf20Sopenharmony_ci return 0; 26108c2ecf20Sopenharmony_ci } 26118c2ecf20Sopenharmony_ci 26128c2ecf20Sopenharmony_ci if (phy_data->phydev) { 26138c2ecf20Sopenharmony_ci /* Check external PHY */ 26148c2ecf20Sopenharmony_ci ret = phy_read_status(phy_data->phydev); 26158c2ecf20Sopenharmony_ci if (ret < 0) 26168c2ecf20Sopenharmony_ci return 0; 26178c2ecf20Sopenharmony_ci 26188c2ecf20Sopenharmony_ci if ((pdata->phy.autoneg == AUTONEG_ENABLE) && 26198c2ecf20Sopenharmony_ci !phy_aneg_done(phy_data->phydev)) 26208c2ecf20Sopenharmony_ci return 0; 26218c2ecf20Sopenharmony_ci 26228c2ecf20Sopenharmony_ci if (!phy_data->phydev->link) 26238c2ecf20Sopenharmony_ci return 0; 26248c2ecf20Sopenharmony_ci } 26258c2ecf20Sopenharmony_ci 26268c2ecf20Sopenharmony_ci /* Link status is latched low, so read once to clear 26278c2ecf20Sopenharmony_ci * and then read again to get current state 26288c2ecf20Sopenharmony_ci */ 26298c2ecf20Sopenharmony_ci reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1); 26308c2ecf20Sopenharmony_ci reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1); 26318c2ecf20Sopenharmony_ci if (reg & MDIO_STAT1_LSTATUS) 26328c2ecf20Sopenharmony_ci return 1; 26338c2ecf20Sopenharmony_ci 26348c2ecf20Sopenharmony_ci if (pdata->phy.autoneg == AUTONEG_ENABLE && 26358c2ecf20Sopenharmony_ci phy_data->port_mode == XGBE_PORT_MODE_BACKPLANE) { 26368c2ecf20Sopenharmony_ci if (!test_bit(XGBE_LINK_INIT, &pdata->dev_state)) { 26378c2ecf20Sopenharmony_ci netif_carrier_off(pdata->netdev); 26388c2ecf20Sopenharmony_ci *an_restart = 1; 26398c2ecf20Sopenharmony_ci } 26408c2ecf20Sopenharmony_ci } 26418c2ecf20Sopenharmony_ci 26428c2ecf20Sopenharmony_ci /* No link, attempt a receiver reset cycle */ 26438c2ecf20Sopenharmony_ci if (phy_data->rrc_count++ > XGBE_RRC_FREQUENCY) { 26448c2ecf20Sopenharmony_ci phy_data->rrc_count = 0; 26458c2ecf20Sopenharmony_ci xgbe_phy_rrc(pdata); 26468c2ecf20Sopenharmony_ci } 26478c2ecf20Sopenharmony_ci 26488c2ecf20Sopenharmony_ci return 0; 26498c2ecf20Sopenharmony_ci} 26508c2ecf20Sopenharmony_ci 26518c2ecf20Sopenharmony_cistatic void xgbe_phy_sfp_gpio_setup(struct xgbe_prv_data *pdata) 26528c2ecf20Sopenharmony_ci{ 26538c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 26548c2ecf20Sopenharmony_ci 26558c2ecf20Sopenharmony_ci phy_data->sfp_gpio_address = XGBE_GPIO_ADDRESS_PCA9555 + 26568c2ecf20Sopenharmony_ci XP_GET_BITS(pdata->pp3, XP_PROP_3, 26578c2ecf20Sopenharmony_ci GPIO_ADDR); 26588c2ecf20Sopenharmony_ci 26598c2ecf20Sopenharmony_ci phy_data->sfp_gpio_mask = XP_GET_BITS(pdata->pp3, XP_PROP_3, 26608c2ecf20Sopenharmony_ci GPIO_MASK); 26618c2ecf20Sopenharmony_ci 26628c2ecf20Sopenharmony_ci phy_data->sfp_gpio_rx_los = XP_GET_BITS(pdata->pp3, XP_PROP_3, 26638c2ecf20Sopenharmony_ci GPIO_RX_LOS); 26648c2ecf20Sopenharmony_ci phy_data->sfp_gpio_tx_fault = XP_GET_BITS(pdata->pp3, XP_PROP_3, 26658c2ecf20Sopenharmony_ci GPIO_TX_FAULT); 26668c2ecf20Sopenharmony_ci phy_data->sfp_gpio_mod_absent = XP_GET_BITS(pdata->pp3, XP_PROP_3, 26678c2ecf20Sopenharmony_ci GPIO_MOD_ABS); 26688c2ecf20Sopenharmony_ci phy_data->sfp_gpio_rate_select = XP_GET_BITS(pdata->pp3, XP_PROP_3, 26698c2ecf20Sopenharmony_ci GPIO_RATE_SELECT); 26708c2ecf20Sopenharmony_ci 26718c2ecf20Sopenharmony_ci if (netif_msg_probe(pdata)) { 26728c2ecf20Sopenharmony_ci dev_dbg(pdata->dev, "SFP: gpio_address=%#x\n", 26738c2ecf20Sopenharmony_ci phy_data->sfp_gpio_address); 26748c2ecf20Sopenharmony_ci dev_dbg(pdata->dev, "SFP: gpio_mask=%#x\n", 26758c2ecf20Sopenharmony_ci phy_data->sfp_gpio_mask); 26768c2ecf20Sopenharmony_ci dev_dbg(pdata->dev, "SFP: gpio_rx_los=%u\n", 26778c2ecf20Sopenharmony_ci phy_data->sfp_gpio_rx_los); 26788c2ecf20Sopenharmony_ci dev_dbg(pdata->dev, "SFP: gpio_tx_fault=%u\n", 26798c2ecf20Sopenharmony_ci phy_data->sfp_gpio_tx_fault); 26808c2ecf20Sopenharmony_ci dev_dbg(pdata->dev, "SFP: gpio_mod_absent=%u\n", 26818c2ecf20Sopenharmony_ci phy_data->sfp_gpio_mod_absent); 26828c2ecf20Sopenharmony_ci dev_dbg(pdata->dev, "SFP: gpio_rate_select=%u\n", 26838c2ecf20Sopenharmony_ci phy_data->sfp_gpio_rate_select); 26848c2ecf20Sopenharmony_ci } 26858c2ecf20Sopenharmony_ci} 26868c2ecf20Sopenharmony_ci 26878c2ecf20Sopenharmony_cistatic void xgbe_phy_sfp_comm_setup(struct xgbe_prv_data *pdata) 26888c2ecf20Sopenharmony_ci{ 26898c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 26908c2ecf20Sopenharmony_ci unsigned int mux_addr_hi, mux_addr_lo; 26918c2ecf20Sopenharmony_ci 26928c2ecf20Sopenharmony_ci mux_addr_hi = XP_GET_BITS(pdata->pp4, XP_PROP_4, MUX_ADDR_HI); 26938c2ecf20Sopenharmony_ci mux_addr_lo = XP_GET_BITS(pdata->pp4, XP_PROP_4, MUX_ADDR_LO); 26948c2ecf20Sopenharmony_ci if (mux_addr_lo == XGBE_SFP_DIRECT) 26958c2ecf20Sopenharmony_ci return; 26968c2ecf20Sopenharmony_ci 26978c2ecf20Sopenharmony_ci phy_data->sfp_comm = XGBE_SFP_COMM_PCA9545; 26988c2ecf20Sopenharmony_ci phy_data->sfp_mux_address = (mux_addr_hi << 2) + mux_addr_lo; 26998c2ecf20Sopenharmony_ci phy_data->sfp_mux_channel = XP_GET_BITS(pdata->pp4, XP_PROP_4, 27008c2ecf20Sopenharmony_ci MUX_CHAN); 27018c2ecf20Sopenharmony_ci 27028c2ecf20Sopenharmony_ci if (netif_msg_probe(pdata)) { 27038c2ecf20Sopenharmony_ci dev_dbg(pdata->dev, "SFP: mux_address=%#x\n", 27048c2ecf20Sopenharmony_ci phy_data->sfp_mux_address); 27058c2ecf20Sopenharmony_ci dev_dbg(pdata->dev, "SFP: mux_channel=%u\n", 27068c2ecf20Sopenharmony_ci phy_data->sfp_mux_channel); 27078c2ecf20Sopenharmony_ci } 27088c2ecf20Sopenharmony_ci} 27098c2ecf20Sopenharmony_ci 27108c2ecf20Sopenharmony_cistatic void xgbe_phy_sfp_setup(struct xgbe_prv_data *pdata) 27118c2ecf20Sopenharmony_ci{ 27128c2ecf20Sopenharmony_ci xgbe_phy_sfp_comm_setup(pdata); 27138c2ecf20Sopenharmony_ci xgbe_phy_sfp_gpio_setup(pdata); 27148c2ecf20Sopenharmony_ci} 27158c2ecf20Sopenharmony_ci 27168c2ecf20Sopenharmony_cistatic int xgbe_phy_int_mdio_reset(struct xgbe_prv_data *pdata) 27178c2ecf20Sopenharmony_ci{ 27188c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 27198c2ecf20Sopenharmony_ci unsigned int ret; 27208c2ecf20Sopenharmony_ci 27218c2ecf20Sopenharmony_ci ret = pdata->hw_if.set_gpio(pdata, phy_data->mdio_reset_gpio); 27228c2ecf20Sopenharmony_ci if (ret) 27238c2ecf20Sopenharmony_ci return ret; 27248c2ecf20Sopenharmony_ci 27258c2ecf20Sopenharmony_ci ret = pdata->hw_if.clr_gpio(pdata, phy_data->mdio_reset_gpio); 27268c2ecf20Sopenharmony_ci 27278c2ecf20Sopenharmony_ci return ret; 27288c2ecf20Sopenharmony_ci} 27298c2ecf20Sopenharmony_ci 27308c2ecf20Sopenharmony_cistatic int xgbe_phy_i2c_mdio_reset(struct xgbe_prv_data *pdata) 27318c2ecf20Sopenharmony_ci{ 27328c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 27338c2ecf20Sopenharmony_ci u8 gpio_reg, gpio_ports[2], gpio_data[3]; 27348c2ecf20Sopenharmony_ci int ret; 27358c2ecf20Sopenharmony_ci 27368c2ecf20Sopenharmony_ci /* Read the output port registers */ 27378c2ecf20Sopenharmony_ci gpio_reg = 2; 27388c2ecf20Sopenharmony_ci ret = xgbe_phy_i2c_read(pdata, phy_data->mdio_reset_addr, 27398c2ecf20Sopenharmony_ci &gpio_reg, sizeof(gpio_reg), 27408c2ecf20Sopenharmony_ci gpio_ports, sizeof(gpio_ports)); 27418c2ecf20Sopenharmony_ci if (ret) 27428c2ecf20Sopenharmony_ci return ret; 27438c2ecf20Sopenharmony_ci 27448c2ecf20Sopenharmony_ci /* Prepare to write the GPIO data */ 27458c2ecf20Sopenharmony_ci gpio_data[0] = 2; 27468c2ecf20Sopenharmony_ci gpio_data[1] = gpio_ports[0]; 27478c2ecf20Sopenharmony_ci gpio_data[2] = gpio_ports[1]; 27488c2ecf20Sopenharmony_ci 27498c2ecf20Sopenharmony_ci /* Set the GPIO pin */ 27508c2ecf20Sopenharmony_ci if (phy_data->mdio_reset_gpio < 8) 27518c2ecf20Sopenharmony_ci gpio_data[1] |= (1 << (phy_data->mdio_reset_gpio % 8)); 27528c2ecf20Sopenharmony_ci else 27538c2ecf20Sopenharmony_ci gpio_data[2] |= (1 << (phy_data->mdio_reset_gpio % 8)); 27548c2ecf20Sopenharmony_ci 27558c2ecf20Sopenharmony_ci /* Write the output port registers */ 27568c2ecf20Sopenharmony_ci ret = xgbe_phy_i2c_write(pdata, phy_data->mdio_reset_addr, 27578c2ecf20Sopenharmony_ci gpio_data, sizeof(gpio_data)); 27588c2ecf20Sopenharmony_ci if (ret) 27598c2ecf20Sopenharmony_ci return ret; 27608c2ecf20Sopenharmony_ci 27618c2ecf20Sopenharmony_ci /* Clear the GPIO pin */ 27628c2ecf20Sopenharmony_ci if (phy_data->mdio_reset_gpio < 8) 27638c2ecf20Sopenharmony_ci gpio_data[1] &= ~(1 << (phy_data->mdio_reset_gpio % 8)); 27648c2ecf20Sopenharmony_ci else 27658c2ecf20Sopenharmony_ci gpio_data[2] &= ~(1 << (phy_data->mdio_reset_gpio % 8)); 27668c2ecf20Sopenharmony_ci 27678c2ecf20Sopenharmony_ci /* Write the output port registers */ 27688c2ecf20Sopenharmony_ci ret = xgbe_phy_i2c_write(pdata, phy_data->mdio_reset_addr, 27698c2ecf20Sopenharmony_ci gpio_data, sizeof(gpio_data)); 27708c2ecf20Sopenharmony_ci 27718c2ecf20Sopenharmony_ci return ret; 27728c2ecf20Sopenharmony_ci} 27738c2ecf20Sopenharmony_ci 27748c2ecf20Sopenharmony_cistatic int xgbe_phy_mdio_reset(struct xgbe_prv_data *pdata) 27758c2ecf20Sopenharmony_ci{ 27768c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 27778c2ecf20Sopenharmony_ci int ret; 27788c2ecf20Sopenharmony_ci 27798c2ecf20Sopenharmony_ci if (phy_data->conn_type != XGBE_CONN_TYPE_MDIO) 27808c2ecf20Sopenharmony_ci return 0; 27818c2ecf20Sopenharmony_ci 27828c2ecf20Sopenharmony_ci ret = xgbe_phy_get_comm_ownership(pdata); 27838c2ecf20Sopenharmony_ci if (ret) 27848c2ecf20Sopenharmony_ci return ret; 27858c2ecf20Sopenharmony_ci 27868c2ecf20Sopenharmony_ci if (phy_data->mdio_reset == XGBE_MDIO_RESET_I2C_GPIO) 27878c2ecf20Sopenharmony_ci ret = xgbe_phy_i2c_mdio_reset(pdata); 27888c2ecf20Sopenharmony_ci else if (phy_data->mdio_reset == XGBE_MDIO_RESET_INT_GPIO) 27898c2ecf20Sopenharmony_ci ret = xgbe_phy_int_mdio_reset(pdata); 27908c2ecf20Sopenharmony_ci 27918c2ecf20Sopenharmony_ci xgbe_phy_put_comm_ownership(pdata); 27928c2ecf20Sopenharmony_ci 27938c2ecf20Sopenharmony_ci return ret; 27948c2ecf20Sopenharmony_ci} 27958c2ecf20Sopenharmony_ci 27968c2ecf20Sopenharmony_cistatic bool xgbe_phy_redrv_error(struct xgbe_phy_data *phy_data) 27978c2ecf20Sopenharmony_ci{ 27988c2ecf20Sopenharmony_ci if (!phy_data->redrv) 27998c2ecf20Sopenharmony_ci return false; 28008c2ecf20Sopenharmony_ci 28018c2ecf20Sopenharmony_ci if (phy_data->redrv_if >= XGBE_PHY_REDRV_IF_MAX) 28028c2ecf20Sopenharmony_ci return true; 28038c2ecf20Sopenharmony_ci 28048c2ecf20Sopenharmony_ci switch (phy_data->redrv_model) { 28058c2ecf20Sopenharmony_ci case XGBE_PHY_REDRV_MODEL_4223: 28068c2ecf20Sopenharmony_ci if (phy_data->redrv_lane > 3) 28078c2ecf20Sopenharmony_ci return true; 28088c2ecf20Sopenharmony_ci break; 28098c2ecf20Sopenharmony_ci case XGBE_PHY_REDRV_MODEL_4227: 28108c2ecf20Sopenharmony_ci if (phy_data->redrv_lane > 1) 28118c2ecf20Sopenharmony_ci return true; 28128c2ecf20Sopenharmony_ci break; 28138c2ecf20Sopenharmony_ci default: 28148c2ecf20Sopenharmony_ci return true; 28158c2ecf20Sopenharmony_ci } 28168c2ecf20Sopenharmony_ci 28178c2ecf20Sopenharmony_ci return false; 28188c2ecf20Sopenharmony_ci} 28198c2ecf20Sopenharmony_ci 28208c2ecf20Sopenharmony_cistatic int xgbe_phy_mdio_reset_setup(struct xgbe_prv_data *pdata) 28218c2ecf20Sopenharmony_ci{ 28228c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 28238c2ecf20Sopenharmony_ci 28248c2ecf20Sopenharmony_ci if (phy_data->conn_type != XGBE_CONN_TYPE_MDIO) 28258c2ecf20Sopenharmony_ci return 0; 28268c2ecf20Sopenharmony_ci 28278c2ecf20Sopenharmony_ci phy_data->mdio_reset = XP_GET_BITS(pdata->pp3, XP_PROP_3, MDIO_RESET); 28288c2ecf20Sopenharmony_ci switch (phy_data->mdio_reset) { 28298c2ecf20Sopenharmony_ci case XGBE_MDIO_RESET_NONE: 28308c2ecf20Sopenharmony_ci case XGBE_MDIO_RESET_I2C_GPIO: 28318c2ecf20Sopenharmony_ci case XGBE_MDIO_RESET_INT_GPIO: 28328c2ecf20Sopenharmony_ci break; 28338c2ecf20Sopenharmony_ci default: 28348c2ecf20Sopenharmony_ci dev_err(pdata->dev, "unsupported MDIO reset (%#x)\n", 28358c2ecf20Sopenharmony_ci phy_data->mdio_reset); 28368c2ecf20Sopenharmony_ci return -EINVAL; 28378c2ecf20Sopenharmony_ci } 28388c2ecf20Sopenharmony_ci 28398c2ecf20Sopenharmony_ci if (phy_data->mdio_reset == XGBE_MDIO_RESET_I2C_GPIO) { 28408c2ecf20Sopenharmony_ci phy_data->mdio_reset_addr = XGBE_GPIO_ADDRESS_PCA9555 + 28418c2ecf20Sopenharmony_ci XP_GET_BITS(pdata->pp3, XP_PROP_3, 28428c2ecf20Sopenharmony_ci MDIO_RESET_I2C_ADDR); 28438c2ecf20Sopenharmony_ci phy_data->mdio_reset_gpio = XP_GET_BITS(pdata->pp3, XP_PROP_3, 28448c2ecf20Sopenharmony_ci MDIO_RESET_I2C_GPIO); 28458c2ecf20Sopenharmony_ci } else if (phy_data->mdio_reset == XGBE_MDIO_RESET_INT_GPIO) { 28468c2ecf20Sopenharmony_ci phy_data->mdio_reset_gpio = XP_GET_BITS(pdata->pp3, XP_PROP_3, 28478c2ecf20Sopenharmony_ci MDIO_RESET_INT_GPIO); 28488c2ecf20Sopenharmony_ci } 28498c2ecf20Sopenharmony_ci 28508c2ecf20Sopenharmony_ci return 0; 28518c2ecf20Sopenharmony_ci} 28528c2ecf20Sopenharmony_ci 28538c2ecf20Sopenharmony_cistatic bool xgbe_phy_port_mode_mismatch(struct xgbe_prv_data *pdata) 28548c2ecf20Sopenharmony_ci{ 28558c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 28568c2ecf20Sopenharmony_ci 28578c2ecf20Sopenharmony_ci switch (phy_data->port_mode) { 28588c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE: 28598c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE_NO_AUTONEG: 28608c2ecf20Sopenharmony_ci if ((phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) || 28618c2ecf20Sopenharmony_ci (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000)) 28628c2ecf20Sopenharmony_ci return false; 28638c2ecf20Sopenharmony_ci break; 28648c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE_2500: 28658c2ecf20Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_2500) 28668c2ecf20Sopenharmony_ci return false; 28678c2ecf20Sopenharmony_ci break; 28688c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_1000BASE_T: 28698c2ecf20Sopenharmony_ci if ((phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) || 28708c2ecf20Sopenharmony_ci (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000)) 28718c2ecf20Sopenharmony_ci return false; 28728c2ecf20Sopenharmony_ci break; 28738c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_1000BASE_X: 28748c2ecf20Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) 28758c2ecf20Sopenharmony_ci return false; 28768c2ecf20Sopenharmony_ci break; 28778c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_NBASE_T: 28788c2ecf20Sopenharmony_ci if ((phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) || 28798c2ecf20Sopenharmony_ci (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) || 28808c2ecf20Sopenharmony_ci (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_2500)) 28818c2ecf20Sopenharmony_ci return false; 28828c2ecf20Sopenharmony_ci break; 28838c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_10GBASE_T: 28848c2ecf20Sopenharmony_ci if ((phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) || 28858c2ecf20Sopenharmony_ci (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) || 28868c2ecf20Sopenharmony_ci (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000)) 28878c2ecf20Sopenharmony_ci return false; 28888c2ecf20Sopenharmony_ci break; 28898c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_10GBASE_R: 28908c2ecf20Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000) 28918c2ecf20Sopenharmony_ci return false; 28928c2ecf20Sopenharmony_ci break; 28938c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_SFP: 28948c2ecf20Sopenharmony_ci if ((phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) || 28958c2ecf20Sopenharmony_ci (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) || 28968c2ecf20Sopenharmony_ci (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000)) 28978c2ecf20Sopenharmony_ci return false; 28988c2ecf20Sopenharmony_ci break; 28998c2ecf20Sopenharmony_ci default: 29008c2ecf20Sopenharmony_ci break; 29018c2ecf20Sopenharmony_ci } 29028c2ecf20Sopenharmony_ci 29038c2ecf20Sopenharmony_ci return true; 29048c2ecf20Sopenharmony_ci} 29058c2ecf20Sopenharmony_ci 29068c2ecf20Sopenharmony_cistatic bool xgbe_phy_conn_type_mismatch(struct xgbe_prv_data *pdata) 29078c2ecf20Sopenharmony_ci{ 29088c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 29098c2ecf20Sopenharmony_ci 29108c2ecf20Sopenharmony_ci switch (phy_data->port_mode) { 29118c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE: 29128c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE_NO_AUTONEG: 29138c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE_2500: 29148c2ecf20Sopenharmony_ci if (phy_data->conn_type == XGBE_CONN_TYPE_BACKPLANE) 29158c2ecf20Sopenharmony_ci return false; 29168c2ecf20Sopenharmony_ci break; 29178c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_1000BASE_T: 29188c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_1000BASE_X: 29198c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_NBASE_T: 29208c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_10GBASE_T: 29218c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_10GBASE_R: 29228c2ecf20Sopenharmony_ci if (phy_data->conn_type == XGBE_CONN_TYPE_MDIO) 29238c2ecf20Sopenharmony_ci return false; 29248c2ecf20Sopenharmony_ci break; 29258c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_SFP: 29268c2ecf20Sopenharmony_ci if (phy_data->conn_type == XGBE_CONN_TYPE_SFP) 29278c2ecf20Sopenharmony_ci return false; 29288c2ecf20Sopenharmony_ci break; 29298c2ecf20Sopenharmony_ci default: 29308c2ecf20Sopenharmony_ci break; 29318c2ecf20Sopenharmony_ci } 29328c2ecf20Sopenharmony_ci 29338c2ecf20Sopenharmony_ci return true; 29348c2ecf20Sopenharmony_ci} 29358c2ecf20Sopenharmony_ci 29368c2ecf20Sopenharmony_cistatic bool xgbe_phy_port_enabled(struct xgbe_prv_data *pdata) 29378c2ecf20Sopenharmony_ci{ 29388c2ecf20Sopenharmony_ci if (!XP_GET_BITS(pdata->pp0, XP_PROP_0, PORT_SPEEDS)) 29398c2ecf20Sopenharmony_ci return false; 29408c2ecf20Sopenharmony_ci if (!XP_GET_BITS(pdata->pp0, XP_PROP_0, CONN_TYPE)) 29418c2ecf20Sopenharmony_ci return false; 29428c2ecf20Sopenharmony_ci 29438c2ecf20Sopenharmony_ci return true; 29448c2ecf20Sopenharmony_ci} 29458c2ecf20Sopenharmony_ci 29468c2ecf20Sopenharmony_cistatic void xgbe_phy_cdr_track(struct xgbe_prv_data *pdata) 29478c2ecf20Sopenharmony_ci{ 29488c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 29498c2ecf20Sopenharmony_ci 29508c2ecf20Sopenharmony_ci if (!pdata->debugfs_an_cdr_workaround) 29518c2ecf20Sopenharmony_ci return; 29528c2ecf20Sopenharmony_ci 29538c2ecf20Sopenharmony_ci if (!phy_data->phy_cdr_notrack) 29548c2ecf20Sopenharmony_ci return; 29558c2ecf20Sopenharmony_ci 29568c2ecf20Sopenharmony_ci usleep_range(phy_data->phy_cdr_delay, 29578c2ecf20Sopenharmony_ci phy_data->phy_cdr_delay + 500); 29588c2ecf20Sopenharmony_ci 29598c2ecf20Sopenharmony_ci XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_VEND2_PMA_CDR_CONTROL, 29608c2ecf20Sopenharmony_ci XGBE_PMA_CDR_TRACK_EN_MASK, 29618c2ecf20Sopenharmony_ci XGBE_PMA_CDR_TRACK_EN_ON); 29628c2ecf20Sopenharmony_ci 29638c2ecf20Sopenharmony_ci phy_data->phy_cdr_notrack = 0; 29648c2ecf20Sopenharmony_ci} 29658c2ecf20Sopenharmony_ci 29668c2ecf20Sopenharmony_cistatic void xgbe_phy_cdr_notrack(struct xgbe_prv_data *pdata) 29678c2ecf20Sopenharmony_ci{ 29688c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 29698c2ecf20Sopenharmony_ci 29708c2ecf20Sopenharmony_ci if (!pdata->debugfs_an_cdr_workaround) 29718c2ecf20Sopenharmony_ci return; 29728c2ecf20Sopenharmony_ci 29738c2ecf20Sopenharmony_ci if (phy_data->phy_cdr_notrack) 29748c2ecf20Sopenharmony_ci return; 29758c2ecf20Sopenharmony_ci 29768c2ecf20Sopenharmony_ci XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_VEND2_PMA_CDR_CONTROL, 29778c2ecf20Sopenharmony_ci XGBE_PMA_CDR_TRACK_EN_MASK, 29788c2ecf20Sopenharmony_ci XGBE_PMA_CDR_TRACK_EN_OFF); 29798c2ecf20Sopenharmony_ci 29808c2ecf20Sopenharmony_ci xgbe_phy_rrc(pdata); 29818c2ecf20Sopenharmony_ci 29828c2ecf20Sopenharmony_ci phy_data->phy_cdr_notrack = 1; 29838c2ecf20Sopenharmony_ci} 29848c2ecf20Sopenharmony_ci 29858c2ecf20Sopenharmony_cistatic void xgbe_phy_kr_training_post(struct xgbe_prv_data *pdata) 29868c2ecf20Sopenharmony_ci{ 29878c2ecf20Sopenharmony_ci if (!pdata->debugfs_an_cdr_track_early) 29888c2ecf20Sopenharmony_ci xgbe_phy_cdr_track(pdata); 29898c2ecf20Sopenharmony_ci} 29908c2ecf20Sopenharmony_ci 29918c2ecf20Sopenharmony_cistatic void xgbe_phy_kr_training_pre(struct xgbe_prv_data *pdata) 29928c2ecf20Sopenharmony_ci{ 29938c2ecf20Sopenharmony_ci if (pdata->debugfs_an_cdr_track_early) 29948c2ecf20Sopenharmony_ci xgbe_phy_cdr_track(pdata); 29958c2ecf20Sopenharmony_ci} 29968c2ecf20Sopenharmony_ci 29978c2ecf20Sopenharmony_cistatic void xgbe_phy_an_post(struct xgbe_prv_data *pdata) 29988c2ecf20Sopenharmony_ci{ 29998c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 30008c2ecf20Sopenharmony_ci 30018c2ecf20Sopenharmony_ci switch (pdata->an_mode) { 30028c2ecf20Sopenharmony_ci case XGBE_AN_MODE_CL73: 30038c2ecf20Sopenharmony_ci case XGBE_AN_MODE_CL73_REDRV: 30048c2ecf20Sopenharmony_ci if (phy_data->cur_mode != XGBE_MODE_KR) 30058c2ecf20Sopenharmony_ci break; 30068c2ecf20Sopenharmony_ci 30078c2ecf20Sopenharmony_ci xgbe_phy_cdr_track(pdata); 30088c2ecf20Sopenharmony_ci 30098c2ecf20Sopenharmony_ci switch (pdata->an_result) { 30108c2ecf20Sopenharmony_ci case XGBE_AN_READY: 30118c2ecf20Sopenharmony_ci case XGBE_AN_COMPLETE: 30128c2ecf20Sopenharmony_ci break; 30138c2ecf20Sopenharmony_ci default: 30148c2ecf20Sopenharmony_ci if (phy_data->phy_cdr_delay < XGBE_CDR_DELAY_MAX) 30158c2ecf20Sopenharmony_ci phy_data->phy_cdr_delay += XGBE_CDR_DELAY_INC; 30168c2ecf20Sopenharmony_ci else 30178c2ecf20Sopenharmony_ci phy_data->phy_cdr_delay = XGBE_CDR_DELAY_INIT; 30188c2ecf20Sopenharmony_ci break; 30198c2ecf20Sopenharmony_ci } 30208c2ecf20Sopenharmony_ci break; 30218c2ecf20Sopenharmony_ci default: 30228c2ecf20Sopenharmony_ci break; 30238c2ecf20Sopenharmony_ci } 30248c2ecf20Sopenharmony_ci} 30258c2ecf20Sopenharmony_ci 30268c2ecf20Sopenharmony_cistatic void xgbe_phy_an_pre(struct xgbe_prv_data *pdata) 30278c2ecf20Sopenharmony_ci{ 30288c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 30298c2ecf20Sopenharmony_ci 30308c2ecf20Sopenharmony_ci switch (pdata->an_mode) { 30318c2ecf20Sopenharmony_ci case XGBE_AN_MODE_CL73: 30328c2ecf20Sopenharmony_ci case XGBE_AN_MODE_CL73_REDRV: 30338c2ecf20Sopenharmony_ci if (phy_data->cur_mode != XGBE_MODE_KR) 30348c2ecf20Sopenharmony_ci break; 30358c2ecf20Sopenharmony_ci 30368c2ecf20Sopenharmony_ci xgbe_phy_cdr_notrack(pdata); 30378c2ecf20Sopenharmony_ci break; 30388c2ecf20Sopenharmony_ci default: 30398c2ecf20Sopenharmony_ci break; 30408c2ecf20Sopenharmony_ci } 30418c2ecf20Sopenharmony_ci} 30428c2ecf20Sopenharmony_ci 30438c2ecf20Sopenharmony_cistatic void xgbe_phy_stop(struct xgbe_prv_data *pdata) 30448c2ecf20Sopenharmony_ci{ 30458c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 30468c2ecf20Sopenharmony_ci 30478c2ecf20Sopenharmony_ci /* If we have an external PHY, free it */ 30488c2ecf20Sopenharmony_ci xgbe_phy_free_phy_device(pdata); 30498c2ecf20Sopenharmony_ci 30508c2ecf20Sopenharmony_ci /* Reset SFP data */ 30518c2ecf20Sopenharmony_ci xgbe_phy_sfp_reset(phy_data); 30528c2ecf20Sopenharmony_ci xgbe_phy_sfp_mod_absent(pdata); 30538c2ecf20Sopenharmony_ci 30548c2ecf20Sopenharmony_ci /* Reset CDR support */ 30558c2ecf20Sopenharmony_ci xgbe_phy_cdr_track(pdata); 30568c2ecf20Sopenharmony_ci 30578c2ecf20Sopenharmony_ci /* Power off the PHY */ 30588c2ecf20Sopenharmony_ci xgbe_phy_power_off(pdata); 30598c2ecf20Sopenharmony_ci 30608c2ecf20Sopenharmony_ci /* Stop the I2C controller */ 30618c2ecf20Sopenharmony_ci pdata->i2c_if.i2c_stop(pdata); 30628c2ecf20Sopenharmony_ci} 30638c2ecf20Sopenharmony_ci 30648c2ecf20Sopenharmony_cistatic int xgbe_phy_start(struct xgbe_prv_data *pdata) 30658c2ecf20Sopenharmony_ci{ 30668c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 30678c2ecf20Sopenharmony_ci int ret; 30688c2ecf20Sopenharmony_ci 30698c2ecf20Sopenharmony_ci /* Start the I2C controller */ 30708c2ecf20Sopenharmony_ci ret = pdata->i2c_if.i2c_start(pdata); 30718c2ecf20Sopenharmony_ci if (ret) 30728c2ecf20Sopenharmony_ci return ret; 30738c2ecf20Sopenharmony_ci 30748c2ecf20Sopenharmony_ci /* Set the proper MDIO mode for the re-driver */ 30758c2ecf20Sopenharmony_ci if (phy_data->redrv && !phy_data->redrv_if) { 30768c2ecf20Sopenharmony_ci ret = pdata->hw_if.set_ext_mii_mode(pdata, phy_data->redrv_addr, 30778c2ecf20Sopenharmony_ci XGBE_MDIO_MODE_CL22); 30788c2ecf20Sopenharmony_ci if (ret) { 30798c2ecf20Sopenharmony_ci netdev_err(pdata->netdev, 30808c2ecf20Sopenharmony_ci "redriver mdio port not compatible (%u)\n", 30818c2ecf20Sopenharmony_ci phy_data->redrv_addr); 30828c2ecf20Sopenharmony_ci return ret; 30838c2ecf20Sopenharmony_ci } 30848c2ecf20Sopenharmony_ci } 30858c2ecf20Sopenharmony_ci 30868c2ecf20Sopenharmony_ci /* Start in highest supported mode */ 30878c2ecf20Sopenharmony_ci xgbe_phy_set_mode(pdata, phy_data->start_mode); 30888c2ecf20Sopenharmony_ci 30898c2ecf20Sopenharmony_ci /* Reset CDR support */ 30908c2ecf20Sopenharmony_ci xgbe_phy_cdr_track(pdata); 30918c2ecf20Sopenharmony_ci 30928c2ecf20Sopenharmony_ci /* After starting the I2C controller, we can check for an SFP */ 30938c2ecf20Sopenharmony_ci switch (phy_data->port_mode) { 30948c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_SFP: 30958c2ecf20Sopenharmony_ci xgbe_phy_sfp_detect(pdata); 30968c2ecf20Sopenharmony_ci break; 30978c2ecf20Sopenharmony_ci default: 30988c2ecf20Sopenharmony_ci break; 30998c2ecf20Sopenharmony_ci } 31008c2ecf20Sopenharmony_ci 31018c2ecf20Sopenharmony_ci /* If we have an external PHY, start it */ 31028c2ecf20Sopenharmony_ci ret = xgbe_phy_find_phy_device(pdata); 31038c2ecf20Sopenharmony_ci if (ret) 31048c2ecf20Sopenharmony_ci goto err_i2c; 31058c2ecf20Sopenharmony_ci 31068c2ecf20Sopenharmony_ci return 0; 31078c2ecf20Sopenharmony_ci 31088c2ecf20Sopenharmony_cierr_i2c: 31098c2ecf20Sopenharmony_ci pdata->i2c_if.i2c_stop(pdata); 31108c2ecf20Sopenharmony_ci 31118c2ecf20Sopenharmony_ci return ret; 31128c2ecf20Sopenharmony_ci} 31138c2ecf20Sopenharmony_ci 31148c2ecf20Sopenharmony_cistatic int xgbe_phy_reset(struct xgbe_prv_data *pdata) 31158c2ecf20Sopenharmony_ci{ 31168c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 31178c2ecf20Sopenharmony_ci enum xgbe_mode cur_mode; 31188c2ecf20Sopenharmony_ci int ret; 31198c2ecf20Sopenharmony_ci 31208c2ecf20Sopenharmony_ci /* Reset by power cycling the PHY */ 31218c2ecf20Sopenharmony_ci cur_mode = phy_data->cur_mode; 31228c2ecf20Sopenharmony_ci xgbe_phy_power_off(pdata); 31238c2ecf20Sopenharmony_ci xgbe_phy_set_mode(pdata, cur_mode); 31248c2ecf20Sopenharmony_ci 31258c2ecf20Sopenharmony_ci if (!phy_data->phydev) 31268c2ecf20Sopenharmony_ci return 0; 31278c2ecf20Sopenharmony_ci 31288c2ecf20Sopenharmony_ci /* Reset the external PHY */ 31298c2ecf20Sopenharmony_ci ret = xgbe_phy_mdio_reset(pdata); 31308c2ecf20Sopenharmony_ci if (ret) 31318c2ecf20Sopenharmony_ci return ret; 31328c2ecf20Sopenharmony_ci 31338c2ecf20Sopenharmony_ci return phy_init_hw(phy_data->phydev); 31348c2ecf20Sopenharmony_ci} 31358c2ecf20Sopenharmony_ci 31368c2ecf20Sopenharmony_cistatic void xgbe_phy_exit(struct xgbe_prv_data *pdata) 31378c2ecf20Sopenharmony_ci{ 31388c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 31398c2ecf20Sopenharmony_ci 31408c2ecf20Sopenharmony_ci /* Unregister for driving external PHYs */ 31418c2ecf20Sopenharmony_ci mdiobus_unregister(phy_data->mii); 31428c2ecf20Sopenharmony_ci} 31438c2ecf20Sopenharmony_ci 31448c2ecf20Sopenharmony_cistatic int xgbe_phy_init(struct xgbe_prv_data *pdata) 31458c2ecf20Sopenharmony_ci{ 31468c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *lks = &pdata->phy.lks; 31478c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data; 31488c2ecf20Sopenharmony_ci struct mii_bus *mii; 31498c2ecf20Sopenharmony_ci int ret; 31508c2ecf20Sopenharmony_ci 31518c2ecf20Sopenharmony_ci /* Check if enabled */ 31528c2ecf20Sopenharmony_ci if (!xgbe_phy_port_enabled(pdata)) { 31538c2ecf20Sopenharmony_ci dev_info(pdata->dev, "device is not enabled\n"); 31548c2ecf20Sopenharmony_ci return -ENODEV; 31558c2ecf20Sopenharmony_ci } 31568c2ecf20Sopenharmony_ci 31578c2ecf20Sopenharmony_ci /* Initialize the I2C controller */ 31588c2ecf20Sopenharmony_ci ret = pdata->i2c_if.i2c_init(pdata); 31598c2ecf20Sopenharmony_ci if (ret) 31608c2ecf20Sopenharmony_ci return ret; 31618c2ecf20Sopenharmony_ci 31628c2ecf20Sopenharmony_ci phy_data = devm_kzalloc(pdata->dev, sizeof(*phy_data), GFP_KERNEL); 31638c2ecf20Sopenharmony_ci if (!phy_data) 31648c2ecf20Sopenharmony_ci return -ENOMEM; 31658c2ecf20Sopenharmony_ci pdata->phy_data = phy_data; 31668c2ecf20Sopenharmony_ci 31678c2ecf20Sopenharmony_ci phy_data->port_mode = XP_GET_BITS(pdata->pp0, XP_PROP_0, PORT_MODE); 31688c2ecf20Sopenharmony_ci phy_data->port_id = XP_GET_BITS(pdata->pp0, XP_PROP_0, PORT_ID); 31698c2ecf20Sopenharmony_ci phy_data->port_speeds = XP_GET_BITS(pdata->pp0, XP_PROP_0, PORT_SPEEDS); 31708c2ecf20Sopenharmony_ci phy_data->conn_type = XP_GET_BITS(pdata->pp0, XP_PROP_0, CONN_TYPE); 31718c2ecf20Sopenharmony_ci phy_data->mdio_addr = XP_GET_BITS(pdata->pp0, XP_PROP_0, MDIO_ADDR); 31728c2ecf20Sopenharmony_ci if (netif_msg_probe(pdata)) { 31738c2ecf20Sopenharmony_ci dev_dbg(pdata->dev, "port mode=%u\n", phy_data->port_mode); 31748c2ecf20Sopenharmony_ci dev_dbg(pdata->dev, "port id=%u\n", phy_data->port_id); 31758c2ecf20Sopenharmony_ci dev_dbg(pdata->dev, "port speeds=%#x\n", phy_data->port_speeds); 31768c2ecf20Sopenharmony_ci dev_dbg(pdata->dev, "conn type=%u\n", phy_data->conn_type); 31778c2ecf20Sopenharmony_ci dev_dbg(pdata->dev, "mdio addr=%u\n", phy_data->mdio_addr); 31788c2ecf20Sopenharmony_ci } 31798c2ecf20Sopenharmony_ci 31808c2ecf20Sopenharmony_ci phy_data->redrv = XP_GET_BITS(pdata->pp4, XP_PROP_4, REDRV_PRESENT); 31818c2ecf20Sopenharmony_ci phy_data->redrv_if = XP_GET_BITS(pdata->pp4, XP_PROP_4, REDRV_IF); 31828c2ecf20Sopenharmony_ci phy_data->redrv_addr = XP_GET_BITS(pdata->pp4, XP_PROP_4, REDRV_ADDR); 31838c2ecf20Sopenharmony_ci phy_data->redrv_lane = XP_GET_BITS(pdata->pp4, XP_PROP_4, REDRV_LANE); 31848c2ecf20Sopenharmony_ci phy_data->redrv_model = XP_GET_BITS(pdata->pp4, XP_PROP_4, REDRV_MODEL); 31858c2ecf20Sopenharmony_ci if (phy_data->redrv && netif_msg_probe(pdata)) { 31868c2ecf20Sopenharmony_ci dev_dbg(pdata->dev, "redrv present\n"); 31878c2ecf20Sopenharmony_ci dev_dbg(pdata->dev, "redrv i/f=%u\n", phy_data->redrv_if); 31888c2ecf20Sopenharmony_ci dev_dbg(pdata->dev, "redrv addr=%#x\n", phy_data->redrv_addr); 31898c2ecf20Sopenharmony_ci dev_dbg(pdata->dev, "redrv lane=%u\n", phy_data->redrv_lane); 31908c2ecf20Sopenharmony_ci dev_dbg(pdata->dev, "redrv model=%u\n", phy_data->redrv_model); 31918c2ecf20Sopenharmony_ci } 31928c2ecf20Sopenharmony_ci 31938c2ecf20Sopenharmony_ci /* Validate the connection requested */ 31948c2ecf20Sopenharmony_ci if (xgbe_phy_conn_type_mismatch(pdata)) { 31958c2ecf20Sopenharmony_ci dev_err(pdata->dev, "phy mode/connection mismatch (%#x/%#x)\n", 31968c2ecf20Sopenharmony_ci phy_data->port_mode, phy_data->conn_type); 31978c2ecf20Sopenharmony_ci return -EINVAL; 31988c2ecf20Sopenharmony_ci } 31998c2ecf20Sopenharmony_ci 32008c2ecf20Sopenharmony_ci /* Validate the mode requested */ 32018c2ecf20Sopenharmony_ci if (xgbe_phy_port_mode_mismatch(pdata)) { 32028c2ecf20Sopenharmony_ci dev_err(pdata->dev, "phy mode/speed mismatch (%#x/%#x)\n", 32038c2ecf20Sopenharmony_ci phy_data->port_mode, phy_data->port_speeds); 32048c2ecf20Sopenharmony_ci return -EINVAL; 32058c2ecf20Sopenharmony_ci } 32068c2ecf20Sopenharmony_ci 32078c2ecf20Sopenharmony_ci /* Check for and validate MDIO reset support */ 32088c2ecf20Sopenharmony_ci ret = xgbe_phy_mdio_reset_setup(pdata); 32098c2ecf20Sopenharmony_ci if (ret) 32108c2ecf20Sopenharmony_ci return ret; 32118c2ecf20Sopenharmony_ci 32128c2ecf20Sopenharmony_ci /* Validate the re-driver information */ 32138c2ecf20Sopenharmony_ci if (xgbe_phy_redrv_error(phy_data)) { 32148c2ecf20Sopenharmony_ci dev_err(pdata->dev, "phy re-driver settings error\n"); 32158c2ecf20Sopenharmony_ci return -EINVAL; 32168c2ecf20Sopenharmony_ci } 32178c2ecf20Sopenharmony_ci pdata->kr_redrv = phy_data->redrv; 32188c2ecf20Sopenharmony_ci 32198c2ecf20Sopenharmony_ci /* Indicate current mode is unknown */ 32208c2ecf20Sopenharmony_ci phy_data->cur_mode = XGBE_MODE_UNKNOWN; 32218c2ecf20Sopenharmony_ci 32228c2ecf20Sopenharmony_ci /* Initialize supported features */ 32238c2ecf20Sopenharmony_ci XGBE_ZERO_SUP(lks); 32248c2ecf20Sopenharmony_ci 32258c2ecf20Sopenharmony_ci switch (phy_data->port_mode) { 32268c2ecf20Sopenharmony_ci /* Backplane support */ 32278c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE: 32288c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, Autoneg); 32298c2ecf20Sopenharmony_ci fallthrough; 32308c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE_NO_AUTONEG: 32318c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, Pause); 32328c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, Asym_Pause); 32338c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, Backplane); 32348c2ecf20Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) { 32358c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, 1000baseKX_Full); 32368c2ecf20Sopenharmony_ci phy_data->start_mode = XGBE_MODE_KX_1000; 32378c2ecf20Sopenharmony_ci } 32388c2ecf20Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000) { 32398c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, 10000baseKR_Full); 32408c2ecf20Sopenharmony_ci if (pdata->fec_ability & MDIO_PMA_10GBR_FECABLE_ABLE) 32418c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, 10000baseR_FEC); 32428c2ecf20Sopenharmony_ci phy_data->start_mode = XGBE_MODE_KR; 32438c2ecf20Sopenharmony_ci } 32448c2ecf20Sopenharmony_ci 32458c2ecf20Sopenharmony_ci phy_data->phydev_mode = XGBE_MDIO_MODE_NONE; 32468c2ecf20Sopenharmony_ci break; 32478c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE_2500: 32488c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, Pause); 32498c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, Asym_Pause); 32508c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, Backplane); 32518c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, 2500baseX_Full); 32528c2ecf20Sopenharmony_ci phy_data->start_mode = XGBE_MODE_KX_2500; 32538c2ecf20Sopenharmony_ci 32548c2ecf20Sopenharmony_ci phy_data->phydev_mode = XGBE_MDIO_MODE_NONE; 32558c2ecf20Sopenharmony_ci break; 32568c2ecf20Sopenharmony_ci 32578c2ecf20Sopenharmony_ci /* MDIO 1GBase-T support */ 32588c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_1000BASE_T: 32598c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, Autoneg); 32608c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, Pause); 32618c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, Asym_Pause); 32628c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, TP); 32638c2ecf20Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) { 32648c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, 100baseT_Full); 32658c2ecf20Sopenharmony_ci phy_data->start_mode = XGBE_MODE_SGMII_100; 32668c2ecf20Sopenharmony_ci } 32678c2ecf20Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) { 32688c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, 1000baseT_Full); 32698c2ecf20Sopenharmony_ci phy_data->start_mode = XGBE_MODE_SGMII_1000; 32708c2ecf20Sopenharmony_ci } 32718c2ecf20Sopenharmony_ci 32728c2ecf20Sopenharmony_ci phy_data->phydev_mode = XGBE_MDIO_MODE_CL22; 32738c2ecf20Sopenharmony_ci break; 32748c2ecf20Sopenharmony_ci 32758c2ecf20Sopenharmony_ci /* MDIO Base-X support */ 32768c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_1000BASE_X: 32778c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, Autoneg); 32788c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, Pause); 32798c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, Asym_Pause); 32808c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, FIBRE); 32818c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, 1000baseX_Full); 32828c2ecf20Sopenharmony_ci phy_data->start_mode = XGBE_MODE_X; 32838c2ecf20Sopenharmony_ci 32848c2ecf20Sopenharmony_ci phy_data->phydev_mode = XGBE_MDIO_MODE_CL22; 32858c2ecf20Sopenharmony_ci break; 32868c2ecf20Sopenharmony_ci 32878c2ecf20Sopenharmony_ci /* MDIO NBase-T support */ 32888c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_NBASE_T: 32898c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, Autoneg); 32908c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, Pause); 32918c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, Asym_Pause); 32928c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, TP); 32938c2ecf20Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) { 32948c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, 100baseT_Full); 32958c2ecf20Sopenharmony_ci phy_data->start_mode = XGBE_MODE_SGMII_100; 32968c2ecf20Sopenharmony_ci } 32978c2ecf20Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) { 32988c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, 1000baseT_Full); 32998c2ecf20Sopenharmony_ci phy_data->start_mode = XGBE_MODE_SGMII_1000; 33008c2ecf20Sopenharmony_ci } 33018c2ecf20Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_2500) { 33028c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, 2500baseT_Full); 33038c2ecf20Sopenharmony_ci phy_data->start_mode = XGBE_MODE_KX_2500; 33048c2ecf20Sopenharmony_ci } 33058c2ecf20Sopenharmony_ci 33068c2ecf20Sopenharmony_ci phy_data->phydev_mode = XGBE_MDIO_MODE_CL45; 33078c2ecf20Sopenharmony_ci break; 33088c2ecf20Sopenharmony_ci 33098c2ecf20Sopenharmony_ci /* 10GBase-T support */ 33108c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_10GBASE_T: 33118c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, Autoneg); 33128c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, Pause); 33138c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, Asym_Pause); 33148c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, TP); 33158c2ecf20Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) { 33168c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, 100baseT_Full); 33178c2ecf20Sopenharmony_ci phy_data->start_mode = XGBE_MODE_SGMII_100; 33188c2ecf20Sopenharmony_ci } 33198c2ecf20Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) { 33208c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, 1000baseT_Full); 33218c2ecf20Sopenharmony_ci phy_data->start_mode = XGBE_MODE_SGMII_1000; 33228c2ecf20Sopenharmony_ci } 33238c2ecf20Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000) { 33248c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, 10000baseT_Full); 33258c2ecf20Sopenharmony_ci phy_data->start_mode = XGBE_MODE_KR; 33268c2ecf20Sopenharmony_ci } 33278c2ecf20Sopenharmony_ci 33288c2ecf20Sopenharmony_ci phy_data->phydev_mode = XGBE_MDIO_MODE_CL45; 33298c2ecf20Sopenharmony_ci break; 33308c2ecf20Sopenharmony_ci 33318c2ecf20Sopenharmony_ci /* 10GBase-R support */ 33328c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_10GBASE_R: 33338c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, Autoneg); 33348c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, Pause); 33358c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, Asym_Pause); 33368c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, FIBRE); 33378c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, 10000baseSR_Full); 33388c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, 10000baseLR_Full); 33398c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, 10000baseLRM_Full); 33408c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, 10000baseER_Full); 33418c2ecf20Sopenharmony_ci if (pdata->fec_ability & MDIO_PMA_10GBR_FECABLE_ABLE) 33428c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, 10000baseR_FEC); 33438c2ecf20Sopenharmony_ci phy_data->start_mode = XGBE_MODE_SFI; 33448c2ecf20Sopenharmony_ci 33458c2ecf20Sopenharmony_ci phy_data->phydev_mode = XGBE_MDIO_MODE_NONE; 33468c2ecf20Sopenharmony_ci break; 33478c2ecf20Sopenharmony_ci 33488c2ecf20Sopenharmony_ci /* SFP support */ 33498c2ecf20Sopenharmony_ci case XGBE_PORT_MODE_SFP: 33508c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, Autoneg); 33518c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, Pause); 33528c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, Asym_Pause); 33538c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, TP); 33548c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, FIBRE); 33558c2ecf20Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) 33568c2ecf20Sopenharmony_ci phy_data->start_mode = XGBE_MODE_SGMII_100; 33578c2ecf20Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) 33588c2ecf20Sopenharmony_ci phy_data->start_mode = XGBE_MODE_SGMII_1000; 33598c2ecf20Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000) 33608c2ecf20Sopenharmony_ci phy_data->start_mode = XGBE_MODE_SFI; 33618c2ecf20Sopenharmony_ci 33628c2ecf20Sopenharmony_ci phy_data->phydev_mode = XGBE_MDIO_MODE_CL22; 33638c2ecf20Sopenharmony_ci 33648c2ecf20Sopenharmony_ci xgbe_phy_sfp_setup(pdata); 33658c2ecf20Sopenharmony_ci break; 33668c2ecf20Sopenharmony_ci default: 33678c2ecf20Sopenharmony_ci return -EINVAL; 33688c2ecf20Sopenharmony_ci } 33698c2ecf20Sopenharmony_ci 33708c2ecf20Sopenharmony_ci if (netif_msg_probe(pdata)) 33718c2ecf20Sopenharmony_ci dev_dbg(pdata->dev, "phy supported=0x%*pb\n", 33728c2ecf20Sopenharmony_ci __ETHTOOL_LINK_MODE_MASK_NBITS, 33738c2ecf20Sopenharmony_ci lks->link_modes.supported); 33748c2ecf20Sopenharmony_ci 33758c2ecf20Sopenharmony_ci if ((phy_data->conn_type & XGBE_CONN_TYPE_MDIO) && 33768c2ecf20Sopenharmony_ci (phy_data->phydev_mode != XGBE_MDIO_MODE_NONE)) { 33778c2ecf20Sopenharmony_ci ret = pdata->hw_if.set_ext_mii_mode(pdata, phy_data->mdio_addr, 33788c2ecf20Sopenharmony_ci phy_data->phydev_mode); 33798c2ecf20Sopenharmony_ci if (ret) { 33808c2ecf20Sopenharmony_ci dev_err(pdata->dev, 33818c2ecf20Sopenharmony_ci "mdio port/clause not compatible (%d/%u)\n", 33828c2ecf20Sopenharmony_ci phy_data->mdio_addr, phy_data->phydev_mode); 33838c2ecf20Sopenharmony_ci return -EINVAL; 33848c2ecf20Sopenharmony_ci } 33858c2ecf20Sopenharmony_ci } 33868c2ecf20Sopenharmony_ci 33878c2ecf20Sopenharmony_ci if (phy_data->redrv && !phy_data->redrv_if) { 33888c2ecf20Sopenharmony_ci ret = pdata->hw_if.set_ext_mii_mode(pdata, phy_data->redrv_addr, 33898c2ecf20Sopenharmony_ci XGBE_MDIO_MODE_CL22); 33908c2ecf20Sopenharmony_ci if (ret) { 33918c2ecf20Sopenharmony_ci dev_err(pdata->dev, 33928c2ecf20Sopenharmony_ci "redriver mdio port not compatible (%u)\n", 33938c2ecf20Sopenharmony_ci phy_data->redrv_addr); 33948c2ecf20Sopenharmony_ci return -EINVAL; 33958c2ecf20Sopenharmony_ci } 33968c2ecf20Sopenharmony_ci } 33978c2ecf20Sopenharmony_ci 33988c2ecf20Sopenharmony_ci phy_data->phy_cdr_delay = XGBE_CDR_DELAY_INIT; 33998c2ecf20Sopenharmony_ci 34008c2ecf20Sopenharmony_ci /* Register for driving external PHYs */ 34018c2ecf20Sopenharmony_ci mii = devm_mdiobus_alloc(pdata->dev); 34028c2ecf20Sopenharmony_ci if (!mii) { 34038c2ecf20Sopenharmony_ci dev_err(pdata->dev, "mdiobus_alloc failed\n"); 34048c2ecf20Sopenharmony_ci return -ENOMEM; 34058c2ecf20Sopenharmony_ci } 34068c2ecf20Sopenharmony_ci 34078c2ecf20Sopenharmony_ci mii->priv = pdata; 34088c2ecf20Sopenharmony_ci mii->name = "amd-xgbe-mii"; 34098c2ecf20Sopenharmony_ci mii->read = xgbe_phy_mii_read; 34108c2ecf20Sopenharmony_ci mii->write = xgbe_phy_mii_write; 34118c2ecf20Sopenharmony_ci mii->parent = pdata->dev; 34128c2ecf20Sopenharmony_ci mii->phy_mask = ~0; 34138c2ecf20Sopenharmony_ci snprintf(mii->id, sizeof(mii->id), "%s", dev_name(pdata->dev)); 34148c2ecf20Sopenharmony_ci ret = mdiobus_register(mii); 34158c2ecf20Sopenharmony_ci if (ret) { 34168c2ecf20Sopenharmony_ci dev_err(pdata->dev, "mdiobus_register failed\n"); 34178c2ecf20Sopenharmony_ci return ret; 34188c2ecf20Sopenharmony_ci } 34198c2ecf20Sopenharmony_ci phy_data->mii = mii; 34208c2ecf20Sopenharmony_ci 34218c2ecf20Sopenharmony_ci return 0; 34228c2ecf20Sopenharmony_ci} 34238c2ecf20Sopenharmony_ci 34248c2ecf20Sopenharmony_civoid xgbe_init_function_ptrs_phy_v2(struct xgbe_phy_if *phy_if) 34258c2ecf20Sopenharmony_ci{ 34268c2ecf20Sopenharmony_ci struct xgbe_phy_impl_if *phy_impl = &phy_if->phy_impl; 34278c2ecf20Sopenharmony_ci 34288c2ecf20Sopenharmony_ci phy_impl->init = xgbe_phy_init; 34298c2ecf20Sopenharmony_ci phy_impl->exit = xgbe_phy_exit; 34308c2ecf20Sopenharmony_ci 34318c2ecf20Sopenharmony_ci phy_impl->reset = xgbe_phy_reset; 34328c2ecf20Sopenharmony_ci phy_impl->start = xgbe_phy_start; 34338c2ecf20Sopenharmony_ci phy_impl->stop = xgbe_phy_stop; 34348c2ecf20Sopenharmony_ci 34358c2ecf20Sopenharmony_ci phy_impl->link_status = xgbe_phy_link_status; 34368c2ecf20Sopenharmony_ci 34378c2ecf20Sopenharmony_ci phy_impl->valid_speed = xgbe_phy_valid_speed; 34388c2ecf20Sopenharmony_ci 34398c2ecf20Sopenharmony_ci phy_impl->use_mode = xgbe_phy_use_mode; 34408c2ecf20Sopenharmony_ci phy_impl->set_mode = xgbe_phy_set_mode; 34418c2ecf20Sopenharmony_ci phy_impl->get_mode = xgbe_phy_get_mode; 34428c2ecf20Sopenharmony_ci phy_impl->switch_mode = xgbe_phy_switch_mode; 34438c2ecf20Sopenharmony_ci phy_impl->cur_mode = xgbe_phy_cur_mode; 34448c2ecf20Sopenharmony_ci 34458c2ecf20Sopenharmony_ci phy_impl->an_mode = xgbe_phy_an_mode; 34468c2ecf20Sopenharmony_ci 34478c2ecf20Sopenharmony_ci phy_impl->an_config = xgbe_phy_an_config; 34488c2ecf20Sopenharmony_ci 34498c2ecf20Sopenharmony_ci phy_impl->an_advertising = xgbe_phy_an_advertising; 34508c2ecf20Sopenharmony_ci 34518c2ecf20Sopenharmony_ci phy_impl->an_outcome = xgbe_phy_an_outcome; 34528c2ecf20Sopenharmony_ci 34538c2ecf20Sopenharmony_ci phy_impl->an_pre = xgbe_phy_an_pre; 34548c2ecf20Sopenharmony_ci phy_impl->an_post = xgbe_phy_an_post; 34558c2ecf20Sopenharmony_ci 34568c2ecf20Sopenharmony_ci phy_impl->kr_training_pre = xgbe_phy_kr_training_pre; 34578c2ecf20Sopenharmony_ci phy_impl->kr_training_post = xgbe_phy_kr_training_post; 34588c2ecf20Sopenharmony_ci 34598c2ecf20Sopenharmony_ci phy_impl->module_info = xgbe_phy_module_info; 34608c2ecf20Sopenharmony_ci phy_impl->module_eeprom = xgbe_phy_module_eeprom; 34618c2ecf20Sopenharmony_ci} 3462