162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * AMD 10Gb Ethernet driver 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * This file is available to you under your choice of the following two 562306a36Sopenharmony_ci * licenses: 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * License 1: GPLv2 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Copyright (c) 2016 Advanced Micro Devices, Inc. 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * This file is free software; you may copy, redistribute and/or modify 1262306a36Sopenharmony_ci * it under the terms of the GNU General Public License as published by 1362306a36Sopenharmony_ci * the Free Software Foundation, either version 2 of the License, or (at 1462306a36Sopenharmony_ci * your option) any later version. 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * This file is distributed in the hope that it will be useful, but 1762306a36Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of 1862306a36Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1962306a36Sopenharmony_ci * General Public License for more details. 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * You should have received a copy of the GNU General Public License 2262306a36Sopenharmony_ci * along with this program. If not, see <http://www.gnu.org/licenses/>. 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * This file incorporates work covered by the following copyright and 2562306a36Sopenharmony_ci * permission notice: 2662306a36Sopenharmony_ci * The Synopsys DWC ETHER XGMAC Software Driver and documentation 2762306a36Sopenharmony_ci * (hereinafter "Software") is an unsupported proprietary work of Synopsys, 2862306a36Sopenharmony_ci * Inc. unless otherwise expressly agreed to in writing between Synopsys 2962306a36Sopenharmony_ci * and you. 3062306a36Sopenharmony_ci * 3162306a36Sopenharmony_ci * The Software IS NOT an item of Licensed Software or Licensed Product 3262306a36Sopenharmony_ci * under any End User Software License Agreement or Agreement for Licensed 3362306a36Sopenharmony_ci * Product with Synopsys or any supplement thereto. Permission is hereby 3462306a36Sopenharmony_ci * granted, free of charge, to any person obtaining a copy of this software 3562306a36Sopenharmony_ci * annotated with this license and the Software, to deal in the Software 3662306a36Sopenharmony_ci * without restriction, including without limitation the rights to use, 3762306a36Sopenharmony_ci * copy, modify, merge, publish, distribute, sublicense, and/or sell copies 3862306a36Sopenharmony_ci * of the Software, and to permit persons to whom the Software is furnished 3962306a36Sopenharmony_ci * to do so, subject to the following conditions: 4062306a36Sopenharmony_ci * 4162306a36Sopenharmony_ci * The above copyright notice and this permission notice shall be included 4262306a36Sopenharmony_ci * in all copies or substantial portions of the Software. 4362306a36Sopenharmony_ci * 4462306a36Sopenharmony_ci * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" 4562306a36Sopenharmony_ci * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 4662306a36Sopenharmony_ci * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 4762306a36Sopenharmony_ci * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 4862306a36Sopenharmony_ci * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 4962306a36Sopenharmony_ci * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 5062306a36Sopenharmony_ci * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 5162306a36Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 5262306a36Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 5362306a36Sopenharmony_ci * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 5462306a36Sopenharmony_ci * THE POSSIBILITY OF SUCH DAMAGE. 5562306a36Sopenharmony_ci * 5662306a36Sopenharmony_ci * 5762306a36Sopenharmony_ci * License 2: Modified BSD 5862306a36Sopenharmony_ci * 5962306a36Sopenharmony_ci * Copyright (c) 2016 Advanced Micro Devices, Inc. 6062306a36Sopenharmony_ci * All rights reserved. 6162306a36Sopenharmony_ci * 6262306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 6362306a36Sopenharmony_ci * modification, are permitted provided that the following conditions are met: 6462306a36Sopenharmony_ci * * Redistributions of source code must retain the above copyright 6562306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 6662306a36Sopenharmony_ci * * Redistributions in binary form must reproduce the above copyright 6762306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer in the 6862306a36Sopenharmony_ci * documentation and/or other materials provided with the distribution. 6962306a36Sopenharmony_ci * * Neither the name of Advanced Micro Devices, Inc. nor the 7062306a36Sopenharmony_ci * names of its contributors may be used to endorse or promote products 7162306a36Sopenharmony_ci * derived from this software without specific prior written permission. 7262306a36Sopenharmony_ci * 7362306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 7462306a36Sopenharmony_ci * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 7562306a36Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 7662306a36Sopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY 7762306a36Sopenharmony_ci * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 7862306a36Sopenharmony_ci * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 7962306a36Sopenharmony_ci * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 8062306a36Sopenharmony_ci * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 8162306a36Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 8262306a36Sopenharmony_ci * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 8362306a36Sopenharmony_ci * 8462306a36Sopenharmony_ci * This file incorporates work covered by the following copyright and 8562306a36Sopenharmony_ci * permission notice: 8662306a36Sopenharmony_ci * The Synopsys DWC ETHER XGMAC Software Driver and documentation 8762306a36Sopenharmony_ci * (hereinafter "Software") is an unsupported proprietary work of Synopsys, 8862306a36Sopenharmony_ci * Inc. unless otherwise expressly agreed to in writing between Synopsys 8962306a36Sopenharmony_ci * and you. 9062306a36Sopenharmony_ci * 9162306a36Sopenharmony_ci * The Software IS NOT an item of Licensed Software or Licensed Product 9262306a36Sopenharmony_ci * under any End User Software License Agreement or Agreement for Licensed 9362306a36Sopenharmony_ci * Product with Synopsys or any supplement thereto. Permission is hereby 9462306a36Sopenharmony_ci * granted, free of charge, to any person obtaining a copy of this software 9562306a36Sopenharmony_ci * annotated with this license and the Software, to deal in the Software 9662306a36Sopenharmony_ci * without restriction, including without limitation the rights to use, 9762306a36Sopenharmony_ci * copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9862306a36Sopenharmony_ci * of the Software, and to permit persons to whom the Software is furnished 9962306a36Sopenharmony_ci * to do so, subject to the following conditions: 10062306a36Sopenharmony_ci * 10162306a36Sopenharmony_ci * The above copyright notice and this permission notice shall be included 10262306a36Sopenharmony_ci * in all copies or substantial portions of the Software. 10362306a36Sopenharmony_ci * 10462306a36Sopenharmony_ci * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" 10562306a36Sopenharmony_ci * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 10662306a36Sopenharmony_ci * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 10762306a36Sopenharmony_ci * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 10862306a36Sopenharmony_ci * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 10962306a36Sopenharmony_ci * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 11062306a36Sopenharmony_ci * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 11162306a36Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 11262306a36Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 11362306a36Sopenharmony_ci * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 11462306a36Sopenharmony_ci * THE POSSIBILITY OF SUCH DAMAGE. 11562306a36Sopenharmony_ci */ 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci#include <linux/module.h> 11862306a36Sopenharmony_ci#include <linux/device.h> 11962306a36Sopenharmony_ci#include <linux/kmod.h> 12062306a36Sopenharmony_ci#include <linux/mdio.h> 12162306a36Sopenharmony_ci#include <linux/phy.h> 12262306a36Sopenharmony_ci#include <linux/ethtool.h> 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci#include "xgbe.h" 12562306a36Sopenharmony_ci#include "xgbe-common.h" 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci#define XGBE_PHY_PORT_SPEED_10 BIT(0) 12862306a36Sopenharmony_ci#define XGBE_PHY_PORT_SPEED_100 BIT(1) 12962306a36Sopenharmony_ci#define XGBE_PHY_PORT_SPEED_1000 BIT(2) 13062306a36Sopenharmony_ci#define XGBE_PHY_PORT_SPEED_2500 BIT(3) 13162306a36Sopenharmony_ci#define XGBE_PHY_PORT_SPEED_10000 BIT(4) 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci#define XGBE_MUTEX_RELEASE 0x80000000 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci#define XGBE_SFP_DIRECT 7 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci/* I2C target addresses */ 13862306a36Sopenharmony_ci#define XGBE_SFP_SERIAL_ID_ADDRESS 0x50 13962306a36Sopenharmony_ci#define XGBE_SFP_DIAG_INFO_ADDRESS 0x51 14062306a36Sopenharmony_ci#define XGBE_SFP_PHY_ADDRESS 0x56 14162306a36Sopenharmony_ci#define XGBE_GPIO_ADDRESS_PCA9555 0x20 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci/* SFP sideband signal indicators */ 14462306a36Sopenharmony_ci#define XGBE_GPIO_NO_TX_FAULT BIT(0) 14562306a36Sopenharmony_ci#define XGBE_GPIO_NO_RATE_SELECT BIT(1) 14662306a36Sopenharmony_ci#define XGBE_GPIO_NO_MOD_ABSENT BIT(2) 14762306a36Sopenharmony_ci#define XGBE_GPIO_NO_RX_LOS BIT(3) 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci/* Rate-change complete wait/retry count */ 15062306a36Sopenharmony_ci#define XGBE_RATECHANGE_COUNT 500 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci/* CDR delay values for KR support (in usec) */ 15362306a36Sopenharmony_ci#define XGBE_CDR_DELAY_INIT 10000 15462306a36Sopenharmony_ci#define XGBE_CDR_DELAY_INC 10000 15562306a36Sopenharmony_ci#define XGBE_CDR_DELAY_MAX 100000 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci/* RRC frequency during link status check */ 15862306a36Sopenharmony_ci#define XGBE_RRC_FREQUENCY 10 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cienum xgbe_port_mode { 16162306a36Sopenharmony_ci XGBE_PORT_MODE_RSVD = 0, 16262306a36Sopenharmony_ci XGBE_PORT_MODE_BACKPLANE, 16362306a36Sopenharmony_ci XGBE_PORT_MODE_BACKPLANE_2500, 16462306a36Sopenharmony_ci XGBE_PORT_MODE_1000BASE_T, 16562306a36Sopenharmony_ci XGBE_PORT_MODE_1000BASE_X, 16662306a36Sopenharmony_ci XGBE_PORT_MODE_NBASE_T, 16762306a36Sopenharmony_ci XGBE_PORT_MODE_10GBASE_T, 16862306a36Sopenharmony_ci XGBE_PORT_MODE_10GBASE_R, 16962306a36Sopenharmony_ci XGBE_PORT_MODE_SFP, 17062306a36Sopenharmony_ci XGBE_PORT_MODE_BACKPLANE_NO_AUTONEG, 17162306a36Sopenharmony_ci XGBE_PORT_MODE_MAX, 17262306a36Sopenharmony_ci}; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cienum xgbe_conn_type { 17562306a36Sopenharmony_ci XGBE_CONN_TYPE_NONE = 0, 17662306a36Sopenharmony_ci XGBE_CONN_TYPE_SFP, 17762306a36Sopenharmony_ci XGBE_CONN_TYPE_MDIO, 17862306a36Sopenharmony_ci XGBE_CONN_TYPE_RSVD1, 17962306a36Sopenharmony_ci XGBE_CONN_TYPE_BACKPLANE, 18062306a36Sopenharmony_ci XGBE_CONN_TYPE_MAX, 18162306a36Sopenharmony_ci}; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci/* SFP/SFP+ related definitions */ 18462306a36Sopenharmony_cienum xgbe_sfp_comm { 18562306a36Sopenharmony_ci XGBE_SFP_COMM_DIRECT = 0, 18662306a36Sopenharmony_ci XGBE_SFP_COMM_PCA9545, 18762306a36Sopenharmony_ci}; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cienum xgbe_sfp_cable { 19062306a36Sopenharmony_ci XGBE_SFP_CABLE_UNKNOWN = 0, 19162306a36Sopenharmony_ci XGBE_SFP_CABLE_ACTIVE, 19262306a36Sopenharmony_ci XGBE_SFP_CABLE_PASSIVE, 19362306a36Sopenharmony_ci XGBE_SFP_CABLE_FIBER, 19462306a36Sopenharmony_ci}; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_cienum xgbe_sfp_base { 19762306a36Sopenharmony_ci XGBE_SFP_BASE_UNKNOWN = 0, 19862306a36Sopenharmony_ci XGBE_SFP_BASE_1000_T, 19962306a36Sopenharmony_ci XGBE_SFP_BASE_1000_SX, 20062306a36Sopenharmony_ci XGBE_SFP_BASE_1000_LX, 20162306a36Sopenharmony_ci XGBE_SFP_BASE_1000_CX, 20262306a36Sopenharmony_ci XGBE_SFP_BASE_10000_SR, 20362306a36Sopenharmony_ci XGBE_SFP_BASE_10000_LR, 20462306a36Sopenharmony_ci XGBE_SFP_BASE_10000_LRM, 20562306a36Sopenharmony_ci XGBE_SFP_BASE_10000_ER, 20662306a36Sopenharmony_ci XGBE_SFP_BASE_10000_CR, 20762306a36Sopenharmony_ci}; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_cienum xgbe_sfp_speed { 21062306a36Sopenharmony_ci XGBE_SFP_SPEED_UNKNOWN = 0, 21162306a36Sopenharmony_ci XGBE_SFP_SPEED_100_1000, 21262306a36Sopenharmony_ci XGBE_SFP_SPEED_1000, 21362306a36Sopenharmony_ci XGBE_SFP_SPEED_10000, 21462306a36Sopenharmony_ci}; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci/* SFP Serial ID Base ID values relative to an offset of 0 */ 21762306a36Sopenharmony_ci#define XGBE_SFP_BASE_ID 0 21862306a36Sopenharmony_ci#define XGBE_SFP_ID_SFP 0x03 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci#define XGBE_SFP_BASE_EXT_ID 1 22162306a36Sopenharmony_ci#define XGBE_SFP_EXT_ID_SFP 0x04 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci#define XGBE_SFP_BASE_10GBE_CC 3 22462306a36Sopenharmony_ci#define XGBE_SFP_BASE_10GBE_CC_SR BIT(4) 22562306a36Sopenharmony_ci#define XGBE_SFP_BASE_10GBE_CC_LR BIT(5) 22662306a36Sopenharmony_ci#define XGBE_SFP_BASE_10GBE_CC_LRM BIT(6) 22762306a36Sopenharmony_ci#define XGBE_SFP_BASE_10GBE_CC_ER BIT(7) 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci#define XGBE_SFP_BASE_1GBE_CC 6 23062306a36Sopenharmony_ci#define XGBE_SFP_BASE_1GBE_CC_SX BIT(0) 23162306a36Sopenharmony_ci#define XGBE_SFP_BASE_1GBE_CC_LX BIT(1) 23262306a36Sopenharmony_ci#define XGBE_SFP_BASE_1GBE_CC_CX BIT(2) 23362306a36Sopenharmony_ci#define XGBE_SFP_BASE_1GBE_CC_T BIT(3) 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci#define XGBE_SFP_BASE_CABLE 8 23662306a36Sopenharmony_ci#define XGBE_SFP_BASE_CABLE_PASSIVE BIT(2) 23762306a36Sopenharmony_ci#define XGBE_SFP_BASE_CABLE_ACTIVE BIT(3) 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci#define XGBE_SFP_BASE_BR 12 24062306a36Sopenharmony_ci#define XGBE_SFP_BASE_BR_1GBE_MIN 0x0a 24162306a36Sopenharmony_ci#define XGBE_SFP_BASE_BR_10GBE_MIN 0x64 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci#define XGBE_SFP_BASE_CU_CABLE_LEN 18 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci#define XGBE_SFP_BASE_VENDOR_NAME 20 24662306a36Sopenharmony_ci#define XGBE_SFP_BASE_VENDOR_NAME_LEN 16 24762306a36Sopenharmony_ci#define XGBE_SFP_BASE_VENDOR_PN 40 24862306a36Sopenharmony_ci#define XGBE_SFP_BASE_VENDOR_PN_LEN 16 24962306a36Sopenharmony_ci#define XGBE_SFP_BASE_VENDOR_REV 56 25062306a36Sopenharmony_ci#define XGBE_SFP_BASE_VENDOR_REV_LEN 4 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci#define XGBE_SFP_BASE_CC 63 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci/* SFP Serial ID Extended ID values relative to an offset of 64 */ 25562306a36Sopenharmony_ci#define XGBE_SFP_BASE_VENDOR_SN 4 25662306a36Sopenharmony_ci#define XGBE_SFP_BASE_VENDOR_SN_LEN 16 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci#define XGBE_SFP_EXTD_OPT1 1 25962306a36Sopenharmony_ci#define XGBE_SFP_EXTD_OPT1_RX_LOS BIT(1) 26062306a36Sopenharmony_ci#define XGBE_SFP_EXTD_OPT1_TX_FAULT BIT(3) 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci#define XGBE_SFP_EXTD_DIAG 28 26362306a36Sopenharmony_ci#define XGBE_SFP_EXTD_DIAG_ADDR_CHANGE BIT(2) 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci#define XGBE_SFP_EXTD_SFF_8472 30 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci#define XGBE_SFP_EXTD_CC 31 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_cistruct xgbe_sfp_eeprom { 27062306a36Sopenharmony_ci u8 base[64]; 27162306a36Sopenharmony_ci u8 extd[32]; 27262306a36Sopenharmony_ci u8 vendor[32]; 27362306a36Sopenharmony_ci}; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci#define XGBE_SFP_DIAGS_SUPPORTED(_x) \ 27662306a36Sopenharmony_ci ((_x)->extd[XGBE_SFP_EXTD_SFF_8472] && \ 27762306a36Sopenharmony_ci !((_x)->extd[XGBE_SFP_EXTD_DIAG] & XGBE_SFP_EXTD_DIAG_ADDR_CHANGE)) 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci#define XGBE_SFP_EEPROM_BASE_LEN 256 28062306a36Sopenharmony_ci#define XGBE_SFP_EEPROM_DIAG_LEN 256 28162306a36Sopenharmony_ci#define XGBE_SFP_EEPROM_MAX (XGBE_SFP_EEPROM_BASE_LEN + \ 28262306a36Sopenharmony_ci XGBE_SFP_EEPROM_DIAG_LEN) 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci#define XGBE_BEL_FUSE_VENDOR "BEL-FUSE " 28562306a36Sopenharmony_ci#define XGBE_BEL_FUSE_PARTNO "1GBT-SFP06 " 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci#define XGBE_MOLEX_VENDOR "Molex Inc. " 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_cistruct xgbe_sfp_ascii { 29062306a36Sopenharmony_ci union { 29162306a36Sopenharmony_ci char vendor[XGBE_SFP_BASE_VENDOR_NAME_LEN + 1]; 29262306a36Sopenharmony_ci char partno[XGBE_SFP_BASE_VENDOR_PN_LEN + 1]; 29362306a36Sopenharmony_ci char rev[XGBE_SFP_BASE_VENDOR_REV_LEN + 1]; 29462306a36Sopenharmony_ci char serno[XGBE_SFP_BASE_VENDOR_SN_LEN + 1]; 29562306a36Sopenharmony_ci } u; 29662306a36Sopenharmony_ci}; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci/* MDIO PHY reset types */ 29962306a36Sopenharmony_cienum xgbe_mdio_reset { 30062306a36Sopenharmony_ci XGBE_MDIO_RESET_NONE = 0, 30162306a36Sopenharmony_ci XGBE_MDIO_RESET_I2C_GPIO, 30262306a36Sopenharmony_ci XGBE_MDIO_RESET_INT_GPIO, 30362306a36Sopenharmony_ci XGBE_MDIO_RESET_MAX, 30462306a36Sopenharmony_ci}; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci/* Re-driver related definitions */ 30762306a36Sopenharmony_cienum xgbe_phy_redrv_if { 30862306a36Sopenharmony_ci XGBE_PHY_REDRV_IF_MDIO = 0, 30962306a36Sopenharmony_ci XGBE_PHY_REDRV_IF_I2C, 31062306a36Sopenharmony_ci XGBE_PHY_REDRV_IF_MAX, 31162306a36Sopenharmony_ci}; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_cienum xgbe_phy_redrv_model { 31462306a36Sopenharmony_ci XGBE_PHY_REDRV_MODEL_4223 = 0, 31562306a36Sopenharmony_ci XGBE_PHY_REDRV_MODEL_4227, 31662306a36Sopenharmony_ci XGBE_PHY_REDRV_MODEL_MAX, 31762306a36Sopenharmony_ci}; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_cienum xgbe_phy_redrv_mode { 32062306a36Sopenharmony_ci XGBE_PHY_REDRV_MODE_CX = 5, 32162306a36Sopenharmony_ci XGBE_PHY_REDRV_MODE_SR = 9, 32262306a36Sopenharmony_ci}; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci#define XGBE_PHY_REDRV_MODE_REG 0x12b0 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci/* PHY related configuration information */ 32762306a36Sopenharmony_cistruct xgbe_phy_data { 32862306a36Sopenharmony_ci enum xgbe_port_mode port_mode; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci unsigned int port_id; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci unsigned int port_speeds; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci enum xgbe_conn_type conn_type; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci enum xgbe_mode cur_mode; 33762306a36Sopenharmony_ci enum xgbe_mode start_mode; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci unsigned int rrc_count; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci unsigned int mdio_addr; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci /* SFP Support */ 34462306a36Sopenharmony_ci enum xgbe_sfp_comm sfp_comm; 34562306a36Sopenharmony_ci unsigned int sfp_mux_address; 34662306a36Sopenharmony_ci unsigned int sfp_mux_channel; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci unsigned int sfp_gpio_address; 34962306a36Sopenharmony_ci unsigned int sfp_gpio_mask; 35062306a36Sopenharmony_ci unsigned int sfp_gpio_inputs; 35162306a36Sopenharmony_ci unsigned int sfp_gpio_rx_los; 35262306a36Sopenharmony_ci unsigned int sfp_gpio_tx_fault; 35362306a36Sopenharmony_ci unsigned int sfp_gpio_mod_absent; 35462306a36Sopenharmony_ci unsigned int sfp_gpio_rate_select; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci unsigned int sfp_rx_los; 35762306a36Sopenharmony_ci unsigned int sfp_tx_fault; 35862306a36Sopenharmony_ci unsigned int sfp_mod_absent; 35962306a36Sopenharmony_ci unsigned int sfp_changed; 36062306a36Sopenharmony_ci unsigned int sfp_phy_avail; 36162306a36Sopenharmony_ci unsigned int sfp_cable_len; 36262306a36Sopenharmony_ci enum xgbe_sfp_base sfp_base; 36362306a36Sopenharmony_ci enum xgbe_sfp_cable sfp_cable; 36462306a36Sopenharmony_ci enum xgbe_sfp_speed sfp_speed; 36562306a36Sopenharmony_ci struct xgbe_sfp_eeprom sfp_eeprom; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci /* External PHY support */ 36862306a36Sopenharmony_ci enum xgbe_mdio_mode phydev_mode; 36962306a36Sopenharmony_ci struct mii_bus *mii; 37062306a36Sopenharmony_ci struct phy_device *phydev; 37162306a36Sopenharmony_ci enum xgbe_mdio_reset mdio_reset; 37262306a36Sopenharmony_ci unsigned int mdio_reset_addr; 37362306a36Sopenharmony_ci unsigned int mdio_reset_gpio; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci /* Re-driver support */ 37662306a36Sopenharmony_ci unsigned int redrv; 37762306a36Sopenharmony_ci unsigned int redrv_if; 37862306a36Sopenharmony_ci unsigned int redrv_addr; 37962306a36Sopenharmony_ci unsigned int redrv_lane; 38062306a36Sopenharmony_ci unsigned int redrv_model; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci /* KR AN support */ 38362306a36Sopenharmony_ci unsigned int phy_cdr_notrack; 38462306a36Sopenharmony_ci unsigned int phy_cdr_delay; 38562306a36Sopenharmony_ci}; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci/* I2C, MDIO and GPIO lines are muxed, so only one device at a time */ 38862306a36Sopenharmony_cistatic DEFINE_MUTEX(xgbe_phy_comm_lock); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_cistatic enum xgbe_an_mode xgbe_phy_an_mode(struct xgbe_prv_data *pdata); 39162306a36Sopenharmony_cistatic void xgbe_phy_rrc(struct xgbe_prv_data *pdata); 39262306a36Sopenharmony_cistatic void xgbe_phy_perform_ratechange(struct xgbe_prv_data *pdata, 39362306a36Sopenharmony_ci enum xgbe_mb_cmd cmd, 39462306a36Sopenharmony_ci enum xgbe_mb_subcmd sub_cmd); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_cistatic int xgbe_phy_i2c_xfer(struct xgbe_prv_data *pdata, 39762306a36Sopenharmony_ci struct xgbe_i2c_op *i2c_op) 39862306a36Sopenharmony_ci{ 39962306a36Sopenharmony_ci return pdata->i2c_if.i2c_xfer(pdata, i2c_op); 40062306a36Sopenharmony_ci} 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_cistatic int xgbe_phy_redrv_write(struct xgbe_prv_data *pdata, unsigned int reg, 40362306a36Sopenharmony_ci unsigned int val) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 40662306a36Sopenharmony_ci struct xgbe_i2c_op i2c_op; 40762306a36Sopenharmony_ci __be16 *redrv_val; 40862306a36Sopenharmony_ci u8 redrv_data[5], csum; 40962306a36Sopenharmony_ci unsigned int i, retry; 41062306a36Sopenharmony_ci int ret; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci /* High byte of register contains read/write indicator */ 41362306a36Sopenharmony_ci redrv_data[0] = ((reg >> 8) & 0xff) << 1; 41462306a36Sopenharmony_ci redrv_data[1] = reg & 0xff; 41562306a36Sopenharmony_ci redrv_val = (__be16 *)&redrv_data[2]; 41662306a36Sopenharmony_ci *redrv_val = cpu_to_be16(val); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci /* Calculate 1 byte checksum */ 41962306a36Sopenharmony_ci csum = 0; 42062306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 42162306a36Sopenharmony_ci csum += redrv_data[i]; 42262306a36Sopenharmony_ci if (redrv_data[i] > csum) 42362306a36Sopenharmony_ci csum++; 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci redrv_data[4] = ~csum; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci retry = 1; 42862306a36Sopenharmony_ciagain1: 42962306a36Sopenharmony_ci i2c_op.cmd = XGBE_I2C_CMD_WRITE; 43062306a36Sopenharmony_ci i2c_op.target = phy_data->redrv_addr; 43162306a36Sopenharmony_ci i2c_op.len = sizeof(redrv_data); 43262306a36Sopenharmony_ci i2c_op.buf = redrv_data; 43362306a36Sopenharmony_ci ret = xgbe_phy_i2c_xfer(pdata, &i2c_op); 43462306a36Sopenharmony_ci if (ret) { 43562306a36Sopenharmony_ci if ((ret == -EAGAIN) && retry--) 43662306a36Sopenharmony_ci goto again1; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci return ret; 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci retry = 1; 44262306a36Sopenharmony_ciagain2: 44362306a36Sopenharmony_ci i2c_op.cmd = XGBE_I2C_CMD_READ; 44462306a36Sopenharmony_ci i2c_op.target = phy_data->redrv_addr; 44562306a36Sopenharmony_ci i2c_op.len = 1; 44662306a36Sopenharmony_ci i2c_op.buf = redrv_data; 44762306a36Sopenharmony_ci ret = xgbe_phy_i2c_xfer(pdata, &i2c_op); 44862306a36Sopenharmony_ci if (ret) { 44962306a36Sopenharmony_ci if ((ret == -EAGAIN) && retry--) 45062306a36Sopenharmony_ci goto again2; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci return ret; 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci if (redrv_data[0] != 0xff) { 45662306a36Sopenharmony_ci netif_dbg(pdata, drv, pdata->netdev, 45762306a36Sopenharmony_ci "Redriver write checksum error\n"); 45862306a36Sopenharmony_ci ret = -EIO; 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci return ret; 46262306a36Sopenharmony_ci} 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_cistatic int xgbe_phy_i2c_write(struct xgbe_prv_data *pdata, unsigned int target, 46562306a36Sopenharmony_ci void *val, unsigned int val_len) 46662306a36Sopenharmony_ci{ 46762306a36Sopenharmony_ci struct xgbe_i2c_op i2c_op; 46862306a36Sopenharmony_ci int retry, ret; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci retry = 1; 47162306a36Sopenharmony_ciagain: 47262306a36Sopenharmony_ci /* Write the specfied register */ 47362306a36Sopenharmony_ci i2c_op.cmd = XGBE_I2C_CMD_WRITE; 47462306a36Sopenharmony_ci i2c_op.target = target; 47562306a36Sopenharmony_ci i2c_op.len = val_len; 47662306a36Sopenharmony_ci i2c_op.buf = val; 47762306a36Sopenharmony_ci ret = xgbe_phy_i2c_xfer(pdata, &i2c_op); 47862306a36Sopenharmony_ci if ((ret == -EAGAIN) && retry--) 47962306a36Sopenharmony_ci goto again; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci return ret; 48262306a36Sopenharmony_ci} 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_cistatic int xgbe_phy_i2c_read(struct xgbe_prv_data *pdata, unsigned int target, 48562306a36Sopenharmony_ci void *reg, unsigned int reg_len, 48662306a36Sopenharmony_ci void *val, unsigned int val_len) 48762306a36Sopenharmony_ci{ 48862306a36Sopenharmony_ci struct xgbe_i2c_op i2c_op; 48962306a36Sopenharmony_ci int retry, ret; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci retry = 1; 49262306a36Sopenharmony_ciagain1: 49362306a36Sopenharmony_ci /* Set the specified register to read */ 49462306a36Sopenharmony_ci i2c_op.cmd = XGBE_I2C_CMD_WRITE; 49562306a36Sopenharmony_ci i2c_op.target = target; 49662306a36Sopenharmony_ci i2c_op.len = reg_len; 49762306a36Sopenharmony_ci i2c_op.buf = reg; 49862306a36Sopenharmony_ci ret = xgbe_phy_i2c_xfer(pdata, &i2c_op); 49962306a36Sopenharmony_ci if (ret) { 50062306a36Sopenharmony_ci if ((ret == -EAGAIN) && retry--) 50162306a36Sopenharmony_ci goto again1; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci return ret; 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci retry = 1; 50762306a36Sopenharmony_ciagain2: 50862306a36Sopenharmony_ci /* Read the specfied register */ 50962306a36Sopenharmony_ci i2c_op.cmd = XGBE_I2C_CMD_READ; 51062306a36Sopenharmony_ci i2c_op.target = target; 51162306a36Sopenharmony_ci i2c_op.len = val_len; 51262306a36Sopenharmony_ci i2c_op.buf = val; 51362306a36Sopenharmony_ci ret = xgbe_phy_i2c_xfer(pdata, &i2c_op); 51462306a36Sopenharmony_ci if ((ret == -EAGAIN) && retry--) 51562306a36Sopenharmony_ci goto again2; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci return ret; 51862306a36Sopenharmony_ci} 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_cistatic int xgbe_phy_sfp_put_mux(struct xgbe_prv_data *pdata) 52162306a36Sopenharmony_ci{ 52262306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 52362306a36Sopenharmony_ci struct xgbe_i2c_op i2c_op; 52462306a36Sopenharmony_ci u8 mux_channel; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci if (phy_data->sfp_comm == XGBE_SFP_COMM_DIRECT) 52762306a36Sopenharmony_ci return 0; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci /* Select no mux channels */ 53062306a36Sopenharmony_ci mux_channel = 0; 53162306a36Sopenharmony_ci i2c_op.cmd = XGBE_I2C_CMD_WRITE; 53262306a36Sopenharmony_ci i2c_op.target = phy_data->sfp_mux_address; 53362306a36Sopenharmony_ci i2c_op.len = sizeof(mux_channel); 53462306a36Sopenharmony_ci i2c_op.buf = &mux_channel; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci return xgbe_phy_i2c_xfer(pdata, &i2c_op); 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_cistatic int xgbe_phy_sfp_get_mux(struct xgbe_prv_data *pdata) 54062306a36Sopenharmony_ci{ 54162306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 54262306a36Sopenharmony_ci struct xgbe_i2c_op i2c_op; 54362306a36Sopenharmony_ci u8 mux_channel; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci if (phy_data->sfp_comm == XGBE_SFP_COMM_DIRECT) 54662306a36Sopenharmony_ci return 0; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci /* Select desired mux channel */ 54962306a36Sopenharmony_ci mux_channel = 1 << phy_data->sfp_mux_channel; 55062306a36Sopenharmony_ci i2c_op.cmd = XGBE_I2C_CMD_WRITE; 55162306a36Sopenharmony_ci i2c_op.target = phy_data->sfp_mux_address; 55262306a36Sopenharmony_ci i2c_op.len = sizeof(mux_channel); 55362306a36Sopenharmony_ci i2c_op.buf = &mux_channel; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci return xgbe_phy_i2c_xfer(pdata, &i2c_op); 55662306a36Sopenharmony_ci} 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_cistatic void xgbe_phy_put_comm_ownership(struct xgbe_prv_data *pdata) 55962306a36Sopenharmony_ci{ 56062306a36Sopenharmony_ci mutex_unlock(&xgbe_phy_comm_lock); 56162306a36Sopenharmony_ci} 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_cistatic int xgbe_phy_get_comm_ownership(struct xgbe_prv_data *pdata) 56462306a36Sopenharmony_ci{ 56562306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 56662306a36Sopenharmony_ci unsigned long timeout; 56762306a36Sopenharmony_ci unsigned int mutex_id; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci /* The I2C and MDIO/GPIO bus is multiplexed between multiple devices, 57062306a36Sopenharmony_ci * the driver needs to take the software mutex and then the hardware 57162306a36Sopenharmony_ci * mutexes before being able to use the busses. 57262306a36Sopenharmony_ci */ 57362306a36Sopenharmony_ci mutex_lock(&xgbe_phy_comm_lock); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci /* Clear the mutexes */ 57662306a36Sopenharmony_ci XP_IOWRITE(pdata, XP_I2C_MUTEX, XGBE_MUTEX_RELEASE); 57762306a36Sopenharmony_ci XP_IOWRITE(pdata, XP_MDIO_MUTEX, XGBE_MUTEX_RELEASE); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci /* Mutex formats are the same for I2C and MDIO/GPIO */ 58062306a36Sopenharmony_ci mutex_id = 0; 58162306a36Sopenharmony_ci XP_SET_BITS(mutex_id, XP_I2C_MUTEX, ID, phy_data->port_id); 58262306a36Sopenharmony_ci XP_SET_BITS(mutex_id, XP_I2C_MUTEX, ACTIVE, 1); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci timeout = jiffies + (5 * HZ); 58562306a36Sopenharmony_ci while (time_before(jiffies, timeout)) { 58662306a36Sopenharmony_ci /* Must be all zeroes in order to obtain the mutex */ 58762306a36Sopenharmony_ci if (XP_IOREAD(pdata, XP_I2C_MUTEX) || 58862306a36Sopenharmony_ci XP_IOREAD(pdata, XP_MDIO_MUTEX)) { 58962306a36Sopenharmony_ci usleep_range(100, 200); 59062306a36Sopenharmony_ci continue; 59162306a36Sopenharmony_ci } 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci /* Obtain the mutex */ 59462306a36Sopenharmony_ci XP_IOWRITE(pdata, XP_I2C_MUTEX, mutex_id); 59562306a36Sopenharmony_ci XP_IOWRITE(pdata, XP_MDIO_MUTEX, mutex_id); 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci return 0; 59862306a36Sopenharmony_ci } 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci mutex_unlock(&xgbe_phy_comm_lock); 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci netdev_err(pdata->netdev, "unable to obtain hardware mutexes\n"); 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci return -ETIMEDOUT; 60562306a36Sopenharmony_ci} 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_cistatic int xgbe_phy_mdio_mii_write_c22(struct xgbe_prv_data *pdata, int addr, 60862306a36Sopenharmony_ci int reg, u16 val) 60962306a36Sopenharmony_ci{ 61062306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci if (phy_data->phydev_mode != XGBE_MDIO_MODE_CL22) 61362306a36Sopenharmony_ci return -EOPNOTSUPP; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci return pdata->hw_if.write_ext_mii_regs_c22(pdata, addr, reg, val); 61662306a36Sopenharmony_ci} 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_cistatic int xgbe_phy_mdio_mii_write_c45(struct xgbe_prv_data *pdata, int addr, 61962306a36Sopenharmony_ci int devad, int reg, u16 val) 62062306a36Sopenharmony_ci{ 62162306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci if (phy_data->phydev_mode != XGBE_MDIO_MODE_CL45) 62462306a36Sopenharmony_ci return -EOPNOTSUPP; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci return pdata->hw_if.write_ext_mii_regs_c45(pdata, addr, devad, 62762306a36Sopenharmony_ci reg, val); 62862306a36Sopenharmony_ci} 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_cistatic int xgbe_phy_i2c_mii_write(struct xgbe_prv_data *pdata, int reg, u16 val) 63162306a36Sopenharmony_ci{ 63262306a36Sopenharmony_ci __be16 *mii_val; 63362306a36Sopenharmony_ci u8 mii_data[3]; 63462306a36Sopenharmony_ci int ret; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci ret = xgbe_phy_sfp_get_mux(pdata); 63762306a36Sopenharmony_ci if (ret) 63862306a36Sopenharmony_ci return ret; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci mii_data[0] = reg & 0xff; 64162306a36Sopenharmony_ci mii_val = (__be16 *)&mii_data[1]; 64262306a36Sopenharmony_ci *mii_val = cpu_to_be16(val); 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci ret = xgbe_phy_i2c_write(pdata, XGBE_SFP_PHY_ADDRESS, 64562306a36Sopenharmony_ci mii_data, sizeof(mii_data)); 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci xgbe_phy_sfp_put_mux(pdata); 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci return ret; 65062306a36Sopenharmony_ci} 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_cistatic int xgbe_phy_mii_write_c22(struct mii_bus *mii, int addr, int reg, 65362306a36Sopenharmony_ci u16 val) 65462306a36Sopenharmony_ci{ 65562306a36Sopenharmony_ci struct xgbe_prv_data *pdata = mii->priv; 65662306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 65762306a36Sopenharmony_ci int ret; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci ret = xgbe_phy_get_comm_ownership(pdata); 66062306a36Sopenharmony_ci if (ret) 66162306a36Sopenharmony_ci return ret; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci if (phy_data->conn_type == XGBE_CONN_TYPE_SFP) 66462306a36Sopenharmony_ci ret = xgbe_phy_i2c_mii_write(pdata, reg, val); 66562306a36Sopenharmony_ci else if (phy_data->conn_type & XGBE_CONN_TYPE_MDIO) 66662306a36Sopenharmony_ci ret = xgbe_phy_mdio_mii_write_c22(pdata, addr, reg, val); 66762306a36Sopenharmony_ci else 66862306a36Sopenharmony_ci ret = -EOPNOTSUPP; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci xgbe_phy_put_comm_ownership(pdata); 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci return ret; 67362306a36Sopenharmony_ci} 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_cistatic int xgbe_phy_mii_write_c45(struct mii_bus *mii, int addr, int devad, 67662306a36Sopenharmony_ci int reg, u16 val) 67762306a36Sopenharmony_ci{ 67862306a36Sopenharmony_ci struct xgbe_prv_data *pdata = mii->priv; 67962306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 68062306a36Sopenharmony_ci int ret; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci ret = xgbe_phy_get_comm_ownership(pdata); 68362306a36Sopenharmony_ci if (ret) 68462306a36Sopenharmony_ci return ret; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci if (phy_data->conn_type == XGBE_CONN_TYPE_SFP) 68762306a36Sopenharmony_ci ret = -EOPNOTSUPP; 68862306a36Sopenharmony_ci else if (phy_data->conn_type & XGBE_CONN_TYPE_MDIO) 68962306a36Sopenharmony_ci ret = xgbe_phy_mdio_mii_write_c45(pdata, addr, devad, reg, val); 69062306a36Sopenharmony_ci else 69162306a36Sopenharmony_ci ret = -EOPNOTSUPP; 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci xgbe_phy_put_comm_ownership(pdata); 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci return ret; 69662306a36Sopenharmony_ci} 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_cistatic int xgbe_phy_mdio_mii_read_c22(struct xgbe_prv_data *pdata, int addr, 69962306a36Sopenharmony_ci int reg) 70062306a36Sopenharmony_ci{ 70162306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci if (phy_data->phydev_mode != XGBE_MDIO_MODE_CL22) 70462306a36Sopenharmony_ci return -EOPNOTSUPP; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci return pdata->hw_if.read_ext_mii_regs_c22(pdata, addr, reg); 70762306a36Sopenharmony_ci} 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_cistatic int xgbe_phy_mdio_mii_read_c45(struct xgbe_prv_data *pdata, int addr, 71062306a36Sopenharmony_ci int devad, int reg) 71162306a36Sopenharmony_ci{ 71262306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci if (phy_data->phydev_mode != XGBE_MDIO_MODE_CL45) 71562306a36Sopenharmony_ci return -EOPNOTSUPP; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci return pdata->hw_if.read_ext_mii_regs_c45(pdata, addr, devad, reg); 71862306a36Sopenharmony_ci} 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_cistatic int xgbe_phy_i2c_mii_read(struct xgbe_prv_data *pdata, int reg) 72162306a36Sopenharmony_ci{ 72262306a36Sopenharmony_ci __be16 mii_val; 72362306a36Sopenharmony_ci u8 mii_reg; 72462306a36Sopenharmony_ci int ret; 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci ret = xgbe_phy_sfp_get_mux(pdata); 72762306a36Sopenharmony_ci if (ret) 72862306a36Sopenharmony_ci return ret; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci mii_reg = reg; 73162306a36Sopenharmony_ci ret = xgbe_phy_i2c_read(pdata, XGBE_SFP_PHY_ADDRESS, 73262306a36Sopenharmony_ci &mii_reg, sizeof(mii_reg), 73362306a36Sopenharmony_ci &mii_val, sizeof(mii_val)); 73462306a36Sopenharmony_ci if (!ret) 73562306a36Sopenharmony_ci ret = be16_to_cpu(mii_val); 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci xgbe_phy_sfp_put_mux(pdata); 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci return ret; 74062306a36Sopenharmony_ci} 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_cistatic int xgbe_phy_mii_read_c22(struct mii_bus *mii, int addr, int reg) 74362306a36Sopenharmony_ci{ 74462306a36Sopenharmony_ci struct xgbe_prv_data *pdata = mii->priv; 74562306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 74662306a36Sopenharmony_ci int ret; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci ret = xgbe_phy_get_comm_ownership(pdata); 74962306a36Sopenharmony_ci if (ret) 75062306a36Sopenharmony_ci return ret; 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci if (phy_data->conn_type == XGBE_CONN_TYPE_SFP) 75362306a36Sopenharmony_ci ret = xgbe_phy_i2c_mii_read(pdata, reg); 75462306a36Sopenharmony_ci else if (phy_data->conn_type & XGBE_CONN_TYPE_MDIO) 75562306a36Sopenharmony_ci ret = xgbe_phy_mdio_mii_read_c22(pdata, addr, reg); 75662306a36Sopenharmony_ci else 75762306a36Sopenharmony_ci ret = -EOPNOTSUPP; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci xgbe_phy_put_comm_ownership(pdata); 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci return ret; 76262306a36Sopenharmony_ci} 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_cistatic int xgbe_phy_mii_read_c45(struct mii_bus *mii, int addr, int devad, 76562306a36Sopenharmony_ci int reg) 76662306a36Sopenharmony_ci{ 76762306a36Sopenharmony_ci struct xgbe_prv_data *pdata = mii->priv; 76862306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 76962306a36Sopenharmony_ci int ret; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci ret = xgbe_phy_get_comm_ownership(pdata); 77262306a36Sopenharmony_ci if (ret) 77362306a36Sopenharmony_ci return ret; 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci if (phy_data->conn_type == XGBE_CONN_TYPE_SFP) 77662306a36Sopenharmony_ci ret = -EOPNOTSUPP; 77762306a36Sopenharmony_ci else if (phy_data->conn_type & XGBE_CONN_TYPE_MDIO) 77862306a36Sopenharmony_ci ret = xgbe_phy_mdio_mii_read_c45(pdata, addr, devad, reg); 77962306a36Sopenharmony_ci else 78062306a36Sopenharmony_ci ret = -ENOTSUPP; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci xgbe_phy_put_comm_ownership(pdata); 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci return ret; 78562306a36Sopenharmony_ci} 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_cistatic void xgbe_phy_sfp_phy_settings(struct xgbe_prv_data *pdata) 78862306a36Sopenharmony_ci{ 78962306a36Sopenharmony_ci struct ethtool_link_ksettings *lks = &pdata->phy.lks; 79062306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci if (!phy_data->sfp_mod_absent && !phy_data->sfp_changed) 79362306a36Sopenharmony_ci return; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci XGBE_ZERO_SUP(lks); 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci if (phy_data->sfp_mod_absent) { 79862306a36Sopenharmony_ci pdata->phy.speed = SPEED_UNKNOWN; 79962306a36Sopenharmony_ci pdata->phy.duplex = DUPLEX_UNKNOWN; 80062306a36Sopenharmony_ci pdata->phy.autoneg = AUTONEG_ENABLE; 80162306a36Sopenharmony_ci pdata->phy.pause_autoneg = AUTONEG_ENABLE; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci XGBE_SET_SUP(lks, Autoneg); 80462306a36Sopenharmony_ci XGBE_SET_SUP(lks, Pause); 80562306a36Sopenharmony_ci XGBE_SET_SUP(lks, Asym_Pause); 80662306a36Sopenharmony_ci XGBE_SET_SUP(lks, TP); 80762306a36Sopenharmony_ci XGBE_SET_SUP(lks, FIBRE); 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci XGBE_LM_COPY(lks, advertising, lks, supported); 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci return; 81262306a36Sopenharmony_ci } 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci switch (phy_data->sfp_base) { 81562306a36Sopenharmony_ci case XGBE_SFP_BASE_1000_T: 81662306a36Sopenharmony_ci case XGBE_SFP_BASE_1000_SX: 81762306a36Sopenharmony_ci case XGBE_SFP_BASE_1000_LX: 81862306a36Sopenharmony_ci case XGBE_SFP_BASE_1000_CX: 81962306a36Sopenharmony_ci pdata->phy.speed = SPEED_UNKNOWN; 82062306a36Sopenharmony_ci pdata->phy.duplex = DUPLEX_UNKNOWN; 82162306a36Sopenharmony_ci pdata->phy.autoneg = AUTONEG_ENABLE; 82262306a36Sopenharmony_ci pdata->phy.pause_autoneg = AUTONEG_ENABLE; 82362306a36Sopenharmony_ci XGBE_SET_SUP(lks, Autoneg); 82462306a36Sopenharmony_ci XGBE_SET_SUP(lks, Pause); 82562306a36Sopenharmony_ci XGBE_SET_SUP(lks, Asym_Pause); 82662306a36Sopenharmony_ci if (phy_data->sfp_base == XGBE_SFP_BASE_1000_T) { 82762306a36Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10) 82862306a36Sopenharmony_ci XGBE_SET_SUP(lks, 10baseT_Full); 82962306a36Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) 83062306a36Sopenharmony_ci XGBE_SET_SUP(lks, 100baseT_Full); 83162306a36Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) 83262306a36Sopenharmony_ci XGBE_SET_SUP(lks, 1000baseT_Full); 83362306a36Sopenharmony_ci } else { 83462306a36Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) 83562306a36Sopenharmony_ci XGBE_SET_SUP(lks, 1000baseX_Full); 83662306a36Sopenharmony_ci } 83762306a36Sopenharmony_ci break; 83862306a36Sopenharmony_ci case XGBE_SFP_BASE_10000_SR: 83962306a36Sopenharmony_ci case XGBE_SFP_BASE_10000_LR: 84062306a36Sopenharmony_ci case XGBE_SFP_BASE_10000_LRM: 84162306a36Sopenharmony_ci case XGBE_SFP_BASE_10000_ER: 84262306a36Sopenharmony_ci case XGBE_SFP_BASE_10000_CR: 84362306a36Sopenharmony_ci pdata->phy.speed = SPEED_10000; 84462306a36Sopenharmony_ci pdata->phy.duplex = DUPLEX_FULL; 84562306a36Sopenharmony_ci pdata->phy.autoneg = AUTONEG_DISABLE; 84662306a36Sopenharmony_ci pdata->phy.pause_autoneg = AUTONEG_DISABLE; 84762306a36Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000) { 84862306a36Sopenharmony_ci switch (phy_data->sfp_base) { 84962306a36Sopenharmony_ci case XGBE_SFP_BASE_10000_SR: 85062306a36Sopenharmony_ci XGBE_SET_SUP(lks, 10000baseSR_Full); 85162306a36Sopenharmony_ci break; 85262306a36Sopenharmony_ci case XGBE_SFP_BASE_10000_LR: 85362306a36Sopenharmony_ci XGBE_SET_SUP(lks, 10000baseLR_Full); 85462306a36Sopenharmony_ci break; 85562306a36Sopenharmony_ci case XGBE_SFP_BASE_10000_LRM: 85662306a36Sopenharmony_ci XGBE_SET_SUP(lks, 10000baseLRM_Full); 85762306a36Sopenharmony_ci break; 85862306a36Sopenharmony_ci case XGBE_SFP_BASE_10000_ER: 85962306a36Sopenharmony_ci XGBE_SET_SUP(lks, 10000baseER_Full); 86062306a36Sopenharmony_ci break; 86162306a36Sopenharmony_ci case XGBE_SFP_BASE_10000_CR: 86262306a36Sopenharmony_ci XGBE_SET_SUP(lks, 10000baseCR_Full); 86362306a36Sopenharmony_ci break; 86462306a36Sopenharmony_ci default: 86562306a36Sopenharmony_ci break; 86662306a36Sopenharmony_ci } 86762306a36Sopenharmony_ci } 86862306a36Sopenharmony_ci break; 86962306a36Sopenharmony_ci default: 87062306a36Sopenharmony_ci pdata->phy.speed = SPEED_UNKNOWN; 87162306a36Sopenharmony_ci pdata->phy.duplex = DUPLEX_UNKNOWN; 87262306a36Sopenharmony_ci pdata->phy.autoneg = AUTONEG_DISABLE; 87362306a36Sopenharmony_ci pdata->phy.pause_autoneg = AUTONEG_DISABLE; 87462306a36Sopenharmony_ci break; 87562306a36Sopenharmony_ci } 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci switch (phy_data->sfp_base) { 87862306a36Sopenharmony_ci case XGBE_SFP_BASE_1000_T: 87962306a36Sopenharmony_ci case XGBE_SFP_BASE_1000_CX: 88062306a36Sopenharmony_ci case XGBE_SFP_BASE_10000_CR: 88162306a36Sopenharmony_ci XGBE_SET_SUP(lks, TP); 88262306a36Sopenharmony_ci break; 88362306a36Sopenharmony_ci default: 88462306a36Sopenharmony_ci XGBE_SET_SUP(lks, FIBRE); 88562306a36Sopenharmony_ci break; 88662306a36Sopenharmony_ci } 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci XGBE_LM_COPY(lks, advertising, lks, supported); 88962306a36Sopenharmony_ci} 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_cistatic bool xgbe_phy_sfp_bit_rate(struct xgbe_sfp_eeprom *sfp_eeprom, 89262306a36Sopenharmony_ci enum xgbe_sfp_speed sfp_speed) 89362306a36Sopenharmony_ci{ 89462306a36Sopenharmony_ci u8 *sfp_base, min; 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci sfp_base = sfp_eeprom->base; 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci switch (sfp_speed) { 89962306a36Sopenharmony_ci case XGBE_SFP_SPEED_1000: 90062306a36Sopenharmony_ci min = XGBE_SFP_BASE_BR_1GBE_MIN; 90162306a36Sopenharmony_ci break; 90262306a36Sopenharmony_ci case XGBE_SFP_SPEED_10000: 90362306a36Sopenharmony_ci min = XGBE_SFP_BASE_BR_10GBE_MIN; 90462306a36Sopenharmony_ci break; 90562306a36Sopenharmony_ci default: 90662306a36Sopenharmony_ci return false; 90762306a36Sopenharmony_ci } 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci return sfp_base[XGBE_SFP_BASE_BR] >= min; 91062306a36Sopenharmony_ci} 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_cistatic void xgbe_phy_free_phy_device(struct xgbe_prv_data *pdata) 91362306a36Sopenharmony_ci{ 91462306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci if (phy_data->phydev) { 91762306a36Sopenharmony_ci phy_detach(phy_data->phydev); 91862306a36Sopenharmony_ci phy_device_remove(phy_data->phydev); 91962306a36Sopenharmony_ci phy_device_free(phy_data->phydev); 92062306a36Sopenharmony_ci phy_data->phydev = NULL; 92162306a36Sopenharmony_ci } 92262306a36Sopenharmony_ci} 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_cistatic bool xgbe_phy_finisar_phy_quirks(struct xgbe_prv_data *pdata) 92562306a36Sopenharmony_ci{ 92662306a36Sopenharmony_ci __ETHTOOL_DECLARE_LINK_MODE_MASK(supported) = { 0, }; 92762306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 92862306a36Sopenharmony_ci unsigned int phy_id = phy_data->phydev->phy_id; 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci if (phy_data->port_mode != XGBE_PORT_MODE_SFP) 93162306a36Sopenharmony_ci return false; 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci if ((phy_id & 0xfffffff0) != 0x01ff0cc0) 93462306a36Sopenharmony_ci return false; 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci /* Enable Base-T AN */ 93762306a36Sopenharmony_ci phy_write(phy_data->phydev, 0x16, 0x0001); 93862306a36Sopenharmony_ci phy_write(phy_data->phydev, 0x00, 0x9140); 93962306a36Sopenharmony_ci phy_write(phy_data->phydev, 0x16, 0x0000); 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci /* Enable SGMII at 100Base-T/1000Base-T Full Duplex */ 94262306a36Sopenharmony_ci phy_write(phy_data->phydev, 0x1b, 0x9084); 94362306a36Sopenharmony_ci phy_write(phy_data->phydev, 0x09, 0x0e00); 94462306a36Sopenharmony_ci phy_write(phy_data->phydev, 0x00, 0x8140); 94562306a36Sopenharmony_ci phy_write(phy_data->phydev, 0x04, 0x0d01); 94662306a36Sopenharmony_ci phy_write(phy_data->phydev, 0x00, 0x9140); 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci linkmode_set_bit_array(phy_10_100_features_array, 94962306a36Sopenharmony_ci ARRAY_SIZE(phy_10_100_features_array), 95062306a36Sopenharmony_ci supported); 95162306a36Sopenharmony_ci linkmode_set_bit_array(phy_gbit_features_array, 95262306a36Sopenharmony_ci ARRAY_SIZE(phy_gbit_features_array), 95362306a36Sopenharmony_ci supported); 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci linkmode_copy(phy_data->phydev->supported, supported); 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci phy_support_asym_pause(phy_data->phydev); 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci netif_dbg(pdata, drv, pdata->netdev, 96062306a36Sopenharmony_ci "Finisar PHY quirk in place\n"); 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci return true; 96362306a36Sopenharmony_ci} 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_cistatic bool xgbe_phy_belfuse_phy_quirks(struct xgbe_prv_data *pdata) 96662306a36Sopenharmony_ci{ 96762306a36Sopenharmony_ci __ETHTOOL_DECLARE_LINK_MODE_MASK(supported) = { 0, }; 96862306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 96962306a36Sopenharmony_ci struct xgbe_sfp_eeprom *sfp_eeprom = &phy_data->sfp_eeprom; 97062306a36Sopenharmony_ci unsigned int phy_id = phy_data->phydev->phy_id; 97162306a36Sopenharmony_ci int reg; 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci if (phy_data->port_mode != XGBE_PORT_MODE_SFP) 97462306a36Sopenharmony_ci return false; 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci if (memcmp(&sfp_eeprom->base[XGBE_SFP_BASE_VENDOR_NAME], 97762306a36Sopenharmony_ci XGBE_BEL_FUSE_VENDOR, XGBE_SFP_BASE_VENDOR_NAME_LEN)) 97862306a36Sopenharmony_ci return false; 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci /* For Bel-Fuse, use the extra AN flag */ 98162306a36Sopenharmony_ci pdata->an_again = 1; 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci if (memcmp(&sfp_eeprom->base[XGBE_SFP_BASE_VENDOR_PN], 98462306a36Sopenharmony_ci XGBE_BEL_FUSE_PARTNO, XGBE_SFP_BASE_VENDOR_PN_LEN)) 98562306a36Sopenharmony_ci return false; 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci if ((phy_id & 0xfffffff0) != 0x03625d10) 98862306a36Sopenharmony_ci return false; 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci /* Reset PHY - wait for self-clearing reset bit to clear */ 99162306a36Sopenharmony_ci genphy_soft_reset(phy_data->phydev); 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci /* Disable RGMII mode */ 99462306a36Sopenharmony_ci phy_write(phy_data->phydev, 0x18, 0x7007); 99562306a36Sopenharmony_ci reg = phy_read(phy_data->phydev, 0x18); 99662306a36Sopenharmony_ci phy_write(phy_data->phydev, 0x18, reg & ~0x0080); 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci /* Enable fiber register bank */ 99962306a36Sopenharmony_ci phy_write(phy_data->phydev, 0x1c, 0x7c00); 100062306a36Sopenharmony_ci reg = phy_read(phy_data->phydev, 0x1c); 100162306a36Sopenharmony_ci reg &= 0x03ff; 100262306a36Sopenharmony_ci reg &= ~0x0001; 100362306a36Sopenharmony_ci phy_write(phy_data->phydev, 0x1c, 0x8000 | 0x7c00 | reg | 0x0001); 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci /* Power down SerDes */ 100662306a36Sopenharmony_ci reg = phy_read(phy_data->phydev, 0x00); 100762306a36Sopenharmony_ci phy_write(phy_data->phydev, 0x00, reg | 0x00800); 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci /* Configure SGMII-to-Copper mode */ 101062306a36Sopenharmony_ci phy_write(phy_data->phydev, 0x1c, 0x7c00); 101162306a36Sopenharmony_ci reg = phy_read(phy_data->phydev, 0x1c); 101262306a36Sopenharmony_ci reg &= 0x03ff; 101362306a36Sopenharmony_ci reg &= ~0x0006; 101462306a36Sopenharmony_ci phy_write(phy_data->phydev, 0x1c, 0x8000 | 0x7c00 | reg | 0x0004); 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci /* Power up SerDes */ 101762306a36Sopenharmony_ci reg = phy_read(phy_data->phydev, 0x00); 101862306a36Sopenharmony_ci phy_write(phy_data->phydev, 0x00, reg & ~0x00800); 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci /* Enable copper register bank */ 102162306a36Sopenharmony_ci phy_write(phy_data->phydev, 0x1c, 0x7c00); 102262306a36Sopenharmony_ci reg = phy_read(phy_data->phydev, 0x1c); 102362306a36Sopenharmony_ci reg &= 0x03ff; 102462306a36Sopenharmony_ci reg &= ~0x0001; 102562306a36Sopenharmony_ci phy_write(phy_data->phydev, 0x1c, 0x8000 | 0x7c00 | reg); 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci /* Power up SerDes */ 102862306a36Sopenharmony_ci reg = phy_read(phy_data->phydev, 0x00); 102962306a36Sopenharmony_ci phy_write(phy_data->phydev, 0x00, reg & ~0x00800); 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci linkmode_set_bit_array(phy_10_100_features_array, 103262306a36Sopenharmony_ci ARRAY_SIZE(phy_10_100_features_array), 103362306a36Sopenharmony_ci supported); 103462306a36Sopenharmony_ci linkmode_set_bit_array(phy_gbit_features_array, 103562306a36Sopenharmony_ci ARRAY_SIZE(phy_gbit_features_array), 103662306a36Sopenharmony_ci supported); 103762306a36Sopenharmony_ci linkmode_copy(phy_data->phydev->supported, supported); 103862306a36Sopenharmony_ci phy_support_asym_pause(phy_data->phydev); 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci netif_dbg(pdata, drv, pdata->netdev, 104162306a36Sopenharmony_ci "BelFuse PHY quirk in place\n"); 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci return true; 104462306a36Sopenharmony_ci} 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_cistatic void xgbe_phy_external_phy_quirks(struct xgbe_prv_data *pdata) 104762306a36Sopenharmony_ci{ 104862306a36Sopenharmony_ci if (xgbe_phy_belfuse_phy_quirks(pdata)) 104962306a36Sopenharmony_ci return; 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci if (xgbe_phy_finisar_phy_quirks(pdata)) 105262306a36Sopenharmony_ci return; 105362306a36Sopenharmony_ci} 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_cistatic int xgbe_phy_find_phy_device(struct xgbe_prv_data *pdata) 105662306a36Sopenharmony_ci{ 105762306a36Sopenharmony_ci struct ethtool_link_ksettings *lks = &pdata->phy.lks; 105862306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 105962306a36Sopenharmony_ci struct phy_device *phydev; 106062306a36Sopenharmony_ci int ret; 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci /* If we already have a PHY, just return */ 106362306a36Sopenharmony_ci if (phy_data->phydev) 106462306a36Sopenharmony_ci return 0; 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci /* Clear the extra AN flag */ 106762306a36Sopenharmony_ci pdata->an_again = 0; 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci /* Check for the use of an external PHY */ 107062306a36Sopenharmony_ci if (phy_data->phydev_mode == XGBE_MDIO_MODE_NONE) 107162306a36Sopenharmony_ci return 0; 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci /* For SFP, only use an external PHY if available */ 107462306a36Sopenharmony_ci if ((phy_data->port_mode == XGBE_PORT_MODE_SFP) && 107562306a36Sopenharmony_ci !phy_data->sfp_phy_avail) 107662306a36Sopenharmony_ci return 0; 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci /* Set the proper MDIO mode for the PHY */ 107962306a36Sopenharmony_ci ret = pdata->hw_if.set_ext_mii_mode(pdata, phy_data->mdio_addr, 108062306a36Sopenharmony_ci phy_data->phydev_mode); 108162306a36Sopenharmony_ci if (ret) { 108262306a36Sopenharmony_ci netdev_err(pdata->netdev, 108362306a36Sopenharmony_ci "mdio port/clause not compatible (%u/%u)\n", 108462306a36Sopenharmony_ci phy_data->mdio_addr, phy_data->phydev_mode); 108562306a36Sopenharmony_ci return ret; 108662306a36Sopenharmony_ci } 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci /* Create and connect to the PHY device */ 108962306a36Sopenharmony_ci phydev = get_phy_device(phy_data->mii, phy_data->mdio_addr, 109062306a36Sopenharmony_ci (phy_data->phydev_mode == XGBE_MDIO_MODE_CL45)); 109162306a36Sopenharmony_ci if (IS_ERR(phydev)) { 109262306a36Sopenharmony_ci netdev_err(pdata->netdev, "get_phy_device failed\n"); 109362306a36Sopenharmony_ci return -ENODEV; 109462306a36Sopenharmony_ci } 109562306a36Sopenharmony_ci netif_dbg(pdata, drv, pdata->netdev, "external PHY id is %#010x\n", 109662306a36Sopenharmony_ci phydev->phy_id); 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci /*TODO: If c45, add request_module based on one of the MMD ids? */ 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci ret = phy_device_register(phydev); 110162306a36Sopenharmony_ci if (ret) { 110262306a36Sopenharmony_ci netdev_err(pdata->netdev, "phy_device_register failed\n"); 110362306a36Sopenharmony_ci phy_device_free(phydev); 110462306a36Sopenharmony_ci return ret; 110562306a36Sopenharmony_ci } 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci ret = phy_attach_direct(pdata->netdev, phydev, phydev->dev_flags, 110862306a36Sopenharmony_ci PHY_INTERFACE_MODE_SGMII); 110962306a36Sopenharmony_ci if (ret) { 111062306a36Sopenharmony_ci netdev_err(pdata->netdev, "phy_attach_direct failed\n"); 111162306a36Sopenharmony_ci phy_device_remove(phydev); 111262306a36Sopenharmony_ci phy_device_free(phydev); 111362306a36Sopenharmony_ci return ret; 111462306a36Sopenharmony_ci } 111562306a36Sopenharmony_ci phy_data->phydev = phydev; 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci xgbe_phy_external_phy_quirks(pdata); 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci linkmode_and(phydev->advertising, phydev->advertising, 112062306a36Sopenharmony_ci lks->link_modes.advertising); 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci phy_start_aneg(phy_data->phydev); 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci return 0; 112562306a36Sopenharmony_ci} 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_cistatic void xgbe_phy_sfp_external_phy(struct xgbe_prv_data *pdata) 112862306a36Sopenharmony_ci{ 112962306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 113062306a36Sopenharmony_ci int ret; 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci if (!phy_data->sfp_changed) 113362306a36Sopenharmony_ci return; 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci phy_data->sfp_phy_avail = 0; 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci if (phy_data->sfp_base != XGBE_SFP_BASE_1000_T) 113862306a36Sopenharmony_ci return; 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci /* Check access to the PHY by reading CTRL1 */ 114162306a36Sopenharmony_ci ret = xgbe_phy_i2c_mii_read(pdata, MII_BMCR); 114262306a36Sopenharmony_ci if (ret < 0) 114362306a36Sopenharmony_ci return; 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci /* Successfully accessed the PHY */ 114662306a36Sopenharmony_ci phy_data->sfp_phy_avail = 1; 114762306a36Sopenharmony_ci} 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_cistatic bool xgbe_phy_check_sfp_rx_los(struct xgbe_phy_data *phy_data) 115062306a36Sopenharmony_ci{ 115162306a36Sopenharmony_ci u8 *sfp_extd = phy_data->sfp_eeprom.extd; 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci if (!(sfp_extd[XGBE_SFP_EXTD_OPT1] & XGBE_SFP_EXTD_OPT1_RX_LOS)) 115462306a36Sopenharmony_ci return false; 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci if (phy_data->sfp_gpio_mask & XGBE_GPIO_NO_RX_LOS) 115762306a36Sopenharmony_ci return false; 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci if (phy_data->sfp_gpio_inputs & (1 << phy_data->sfp_gpio_rx_los)) 116062306a36Sopenharmony_ci return true; 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci return false; 116362306a36Sopenharmony_ci} 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_cistatic bool xgbe_phy_check_sfp_tx_fault(struct xgbe_phy_data *phy_data) 116662306a36Sopenharmony_ci{ 116762306a36Sopenharmony_ci u8 *sfp_extd = phy_data->sfp_eeprom.extd; 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci if (!(sfp_extd[XGBE_SFP_EXTD_OPT1] & XGBE_SFP_EXTD_OPT1_TX_FAULT)) 117062306a36Sopenharmony_ci return false; 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci if (phy_data->sfp_gpio_mask & XGBE_GPIO_NO_TX_FAULT) 117362306a36Sopenharmony_ci return false; 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci if (phy_data->sfp_gpio_inputs & (1 << phy_data->sfp_gpio_tx_fault)) 117662306a36Sopenharmony_ci return true; 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci return false; 117962306a36Sopenharmony_ci} 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_cistatic bool xgbe_phy_check_sfp_mod_absent(struct xgbe_phy_data *phy_data) 118262306a36Sopenharmony_ci{ 118362306a36Sopenharmony_ci if (phy_data->sfp_gpio_mask & XGBE_GPIO_NO_MOD_ABSENT) 118462306a36Sopenharmony_ci return false; 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci if (phy_data->sfp_gpio_inputs & (1 << phy_data->sfp_gpio_mod_absent)) 118762306a36Sopenharmony_ci return true; 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci return false; 119062306a36Sopenharmony_ci} 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_cistatic void xgbe_phy_sfp_parse_eeprom(struct xgbe_prv_data *pdata) 119362306a36Sopenharmony_ci{ 119462306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 119562306a36Sopenharmony_ci struct xgbe_sfp_eeprom *sfp_eeprom = &phy_data->sfp_eeprom; 119662306a36Sopenharmony_ci u8 *sfp_base; 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci sfp_base = sfp_eeprom->base; 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci if (sfp_base[XGBE_SFP_BASE_ID] != XGBE_SFP_ID_SFP) 120162306a36Sopenharmony_ci return; 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci if (sfp_base[XGBE_SFP_BASE_EXT_ID] != XGBE_SFP_EXT_ID_SFP) 120462306a36Sopenharmony_ci return; 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci /* Update transceiver signals (eeprom extd/options) */ 120762306a36Sopenharmony_ci phy_data->sfp_tx_fault = xgbe_phy_check_sfp_tx_fault(phy_data); 120862306a36Sopenharmony_ci phy_data->sfp_rx_los = xgbe_phy_check_sfp_rx_los(phy_data); 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci /* Assume FIBER cable unless told otherwise */ 121162306a36Sopenharmony_ci if (sfp_base[XGBE_SFP_BASE_CABLE] & XGBE_SFP_BASE_CABLE_PASSIVE) { 121262306a36Sopenharmony_ci phy_data->sfp_cable = XGBE_SFP_CABLE_PASSIVE; 121362306a36Sopenharmony_ci phy_data->sfp_cable_len = sfp_base[XGBE_SFP_BASE_CU_CABLE_LEN]; 121462306a36Sopenharmony_ci } else if (sfp_base[XGBE_SFP_BASE_CABLE] & XGBE_SFP_BASE_CABLE_ACTIVE) { 121562306a36Sopenharmony_ci phy_data->sfp_cable = XGBE_SFP_CABLE_ACTIVE; 121662306a36Sopenharmony_ci } else { 121762306a36Sopenharmony_ci phy_data->sfp_cable = XGBE_SFP_CABLE_FIBER; 121862306a36Sopenharmony_ci } 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci /* Determine the type of SFP */ 122162306a36Sopenharmony_ci if (phy_data->sfp_cable != XGBE_SFP_CABLE_FIBER && 122262306a36Sopenharmony_ci xgbe_phy_sfp_bit_rate(sfp_eeprom, XGBE_SFP_SPEED_10000)) 122362306a36Sopenharmony_ci phy_data->sfp_base = XGBE_SFP_BASE_10000_CR; 122462306a36Sopenharmony_ci else if (sfp_base[XGBE_SFP_BASE_10GBE_CC] & XGBE_SFP_BASE_10GBE_CC_SR) 122562306a36Sopenharmony_ci phy_data->sfp_base = XGBE_SFP_BASE_10000_SR; 122662306a36Sopenharmony_ci else if (sfp_base[XGBE_SFP_BASE_10GBE_CC] & XGBE_SFP_BASE_10GBE_CC_LR) 122762306a36Sopenharmony_ci phy_data->sfp_base = XGBE_SFP_BASE_10000_LR; 122862306a36Sopenharmony_ci else if (sfp_base[XGBE_SFP_BASE_10GBE_CC] & XGBE_SFP_BASE_10GBE_CC_LRM) 122962306a36Sopenharmony_ci phy_data->sfp_base = XGBE_SFP_BASE_10000_LRM; 123062306a36Sopenharmony_ci else if (sfp_base[XGBE_SFP_BASE_10GBE_CC] & XGBE_SFP_BASE_10GBE_CC_ER) 123162306a36Sopenharmony_ci phy_data->sfp_base = XGBE_SFP_BASE_10000_ER; 123262306a36Sopenharmony_ci else if (sfp_base[XGBE_SFP_BASE_1GBE_CC] & XGBE_SFP_BASE_1GBE_CC_SX) 123362306a36Sopenharmony_ci phy_data->sfp_base = XGBE_SFP_BASE_1000_SX; 123462306a36Sopenharmony_ci else if (sfp_base[XGBE_SFP_BASE_1GBE_CC] & XGBE_SFP_BASE_1GBE_CC_LX) 123562306a36Sopenharmony_ci phy_data->sfp_base = XGBE_SFP_BASE_1000_LX; 123662306a36Sopenharmony_ci else if (sfp_base[XGBE_SFP_BASE_1GBE_CC] & XGBE_SFP_BASE_1GBE_CC_CX) 123762306a36Sopenharmony_ci phy_data->sfp_base = XGBE_SFP_BASE_1000_CX; 123862306a36Sopenharmony_ci else if (sfp_base[XGBE_SFP_BASE_1GBE_CC] & XGBE_SFP_BASE_1GBE_CC_T) 123962306a36Sopenharmony_ci phy_data->sfp_base = XGBE_SFP_BASE_1000_T; 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci switch (phy_data->sfp_base) { 124262306a36Sopenharmony_ci case XGBE_SFP_BASE_1000_T: 124362306a36Sopenharmony_ci phy_data->sfp_speed = XGBE_SFP_SPEED_100_1000; 124462306a36Sopenharmony_ci break; 124562306a36Sopenharmony_ci case XGBE_SFP_BASE_1000_SX: 124662306a36Sopenharmony_ci case XGBE_SFP_BASE_1000_LX: 124762306a36Sopenharmony_ci case XGBE_SFP_BASE_1000_CX: 124862306a36Sopenharmony_ci phy_data->sfp_speed = XGBE_SFP_SPEED_1000; 124962306a36Sopenharmony_ci break; 125062306a36Sopenharmony_ci case XGBE_SFP_BASE_10000_SR: 125162306a36Sopenharmony_ci case XGBE_SFP_BASE_10000_LR: 125262306a36Sopenharmony_ci case XGBE_SFP_BASE_10000_LRM: 125362306a36Sopenharmony_ci case XGBE_SFP_BASE_10000_ER: 125462306a36Sopenharmony_ci case XGBE_SFP_BASE_10000_CR: 125562306a36Sopenharmony_ci phy_data->sfp_speed = XGBE_SFP_SPEED_10000; 125662306a36Sopenharmony_ci break; 125762306a36Sopenharmony_ci default: 125862306a36Sopenharmony_ci break; 125962306a36Sopenharmony_ci } 126062306a36Sopenharmony_ci} 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_cistatic void xgbe_phy_sfp_eeprom_info(struct xgbe_prv_data *pdata, 126362306a36Sopenharmony_ci struct xgbe_sfp_eeprom *sfp_eeprom) 126462306a36Sopenharmony_ci{ 126562306a36Sopenharmony_ci struct xgbe_sfp_ascii sfp_ascii; 126662306a36Sopenharmony_ci char *sfp_data = (char *)&sfp_ascii; 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_ci netif_dbg(pdata, drv, pdata->netdev, "SFP detected:\n"); 126962306a36Sopenharmony_ci memcpy(sfp_data, &sfp_eeprom->base[XGBE_SFP_BASE_VENDOR_NAME], 127062306a36Sopenharmony_ci XGBE_SFP_BASE_VENDOR_NAME_LEN); 127162306a36Sopenharmony_ci sfp_data[XGBE_SFP_BASE_VENDOR_NAME_LEN] = '\0'; 127262306a36Sopenharmony_ci netif_dbg(pdata, drv, pdata->netdev, " vendor: %s\n", 127362306a36Sopenharmony_ci sfp_data); 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci memcpy(sfp_data, &sfp_eeprom->base[XGBE_SFP_BASE_VENDOR_PN], 127662306a36Sopenharmony_ci XGBE_SFP_BASE_VENDOR_PN_LEN); 127762306a36Sopenharmony_ci sfp_data[XGBE_SFP_BASE_VENDOR_PN_LEN] = '\0'; 127862306a36Sopenharmony_ci netif_dbg(pdata, drv, pdata->netdev, " part number: %s\n", 127962306a36Sopenharmony_ci sfp_data); 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci memcpy(sfp_data, &sfp_eeprom->base[XGBE_SFP_BASE_VENDOR_REV], 128262306a36Sopenharmony_ci XGBE_SFP_BASE_VENDOR_REV_LEN); 128362306a36Sopenharmony_ci sfp_data[XGBE_SFP_BASE_VENDOR_REV_LEN] = '\0'; 128462306a36Sopenharmony_ci netif_dbg(pdata, drv, pdata->netdev, " revision level: %s\n", 128562306a36Sopenharmony_ci sfp_data); 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci memcpy(sfp_data, &sfp_eeprom->extd[XGBE_SFP_BASE_VENDOR_SN], 128862306a36Sopenharmony_ci XGBE_SFP_BASE_VENDOR_SN_LEN); 128962306a36Sopenharmony_ci sfp_data[XGBE_SFP_BASE_VENDOR_SN_LEN] = '\0'; 129062306a36Sopenharmony_ci netif_dbg(pdata, drv, pdata->netdev, " serial number: %s\n", 129162306a36Sopenharmony_ci sfp_data); 129262306a36Sopenharmony_ci} 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_cistatic bool xgbe_phy_sfp_verify_eeprom(u8 cc_in, u8 *buf, unsigned int len) 129562306a36Sopenharmony_ci{ 129662306a36Sopenharmony_ci u8 cc; 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci for (cc = 0; len; buf++, len--) 129962306a36Sopenharmony_ci cc += *buf; 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci return cc == cc_in; 130262306a36Sopenharmony_ci} 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_cistatic int xgbe_phy_sfp_read_eeprom(struct xgbe_prv_data *pdata) 130562306a36Sopenharmony_ci{ 130662306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 130762306a36Sopenharmony_ci struct xgbe_sfp_eeprom sfp_eeprom; 130862306a36Sopenharmony_ci u8 eeprom_addr; 130962306a36Sopenharmony_ci int ret; 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci ret = xgbe_phy_sfp_get_mux(pdata); 131262306a36Sopenharmony_ci if (ret) { 131362306a36Sopenharmony_ci dev_err_once(pdata->dev, "%s: I2C error setting SFP MUX\n", 131462306a36Sopenharmony_ci netdev_name(pdata->netdev)); 131562306a36Sopenharmony_ci return ret; 131662306a36Sopenharmony_ci } 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci /* Read the SFP serial ID eeprom */ 131962306a36Sopenharmony_ci eeprom_addr = 0; 132062306a36Sopenharmony_ci ret = xgbe_phy_i2c_read(pdata, XGBE_SFP_SERIAL_ID_ADDRESS, 132162306a36Sopenharmony_ci &eeprom_addr, sizeof(eeprom_addr), 132262306a36Sopenharmony_ci &sfp_eeprom, sizeof(sfp_eeprom)); 132362306a36Sopenharmony_ci if (ret) { 132462306a36Sopenharmony_ci dev_err_once(pdata->dev, "%s: I2C error reading SFP EEPROM\n", 132562306a36Sopenharmony_ci netdev_name(pdata->netdev)); 132662306a36Sopenharmony_ci goto put; 132762306a36Sopenharmony_ci } 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci /* Validate the contents read */ 133062306a36Sopenharmony_ci if (!xgbe_phy_sfp_verify_eeprom(sfp_eeprom.base[XGBE_SFP_BASE_CC], 133162306a36Sopenharmony_ci sfp_eeprom.base, 133262306a36Sopenharmony_ci sizeof(sfp_eeprom.base) - 1)) { 133362306a36Sopenharmony_ci ret = -EINVAL; 133462306a36Sopenharmony_ci goto put; 133562306a36Sopenharmony_ci } 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci if (!xgbe_phy_sfp_verify_eeprom(sfp_eeprom.extd[XGBE_SFP_EXTD_CC], 133862306a36Sopenharmony_ci sfp_eeprom.extd, 133962306a36Sopenharmony_ci sizeof(sfp_eeprom.extd) - 1)) { 134062306a36Sopenharmony_ci ret = -EINVAL; 134162306a36Sopenharmony_ci goto put; 134262306a36Sopenharmony_ci } 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_ci /* Check for an added or changed SFP */ 134562306a36Sopenharmony_ci if (memcmp(&phy_data->sfp_eeprom, &sfp_eeprom, sizeof(sfp_eeprom))) { 134662306a36Sopenharmony_ci phy_data->sfp_changed = 1; 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci if (netif_msg_drv(pdata)) 134962306a36Sopenharmony_ci xgbe_phy_sfp_eeprom_info(pdata, &sfp_eeprom); 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci memcpy(&phy_data->sfp_eeprom, &sfp_eeprom, sizeof(sfp_eeprom)); 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ci xgbe_phy_free_phy_device(pdata); 135462306a36Sopenharmony_ci } else { 135562306a36Sopenharmony_ci phy_data->sfp_changed = 0; 135662306a36Sopenharmony_ci } 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ciput: 135962306a36Sopenharmony_ci xgbe_phy_sfp_put_mux(pdata); 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_ci return ret; 136262306a36Sopenharmony_ci} 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_cistatic void xgbe_phy_sfp_signals(struct xgbe_prv_data *pdata) 136562306a36Sopenharmony_ci{ 136662306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 136762306a36Sopenharmony_ci u8 gpio_reg, gpio_ports[2]; 136862306a36Sopenharmony_ci int ret; 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci /* Read the input port registers */ 137162306a36Sopenharmony_ci gpio_reg = 0; 137262306a36Sopenharmony_ci ret = xgbe_phy_i2c_read(pdata, phy_data->sfp_gpio_address, 137362306a36Sopenharmony_ci &gpio_reg, sizeof(gpio_reg), 137462306a36Sopenharmony_ci gpio_ports, sizeof(gpio_ports)); 137562306a36Sopenharmony_ci if (ret) { 137662306a36Sopenharmony_ci dev_err_once(pdata->dev, "%s: I2C error reading SFP GPIOs\n", 137762306a36Sopenharmony_ci netdev_name(pdata->netdev)); 137862306a36Sopenharmony_ci return; 137962306a36Sopenharmony_ci } 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci phy_data->sfp_gpio_inputs = (gpio_ports[1] << 8) | gpio_ports[0]; 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci phy_data->sfp_mod_absent = xgbe_phy_check_sfp_mod_absent(phy_data); 138462306a36Sopenharmony_ci} 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_cistatic void xgbe_phy_sfp_mod_absent(struct xgbe_prv_data *pdata) 138762306a36Sopenharmony_ci{ 138862306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci xgbe_phy_free_phy_device(pdata); 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci phy_data->sfp_mod_absent = 1; 139362306a36Sopenharmony_ci phy_data->sfp_phy_avail = 0; 139462306a36Sopenharmony_ci memset(&phy_data->sfp_eeprom, 0, sizeof(phy_data->sfp_eeprom)); 139562306a36Sopenharmony_ci} 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_cistatic void xgbe_phy_sfp_reset(struct xgbe_phy_data *phy_data) 139862306a36Sopenharmony_ci{ 139962306a36Sopenharmony_ci phy_data->sfp_rx_los = 0; 140062306a36Sopenharmony_ci phy_data->sfp_tx_fault = 0; 140162306a36Sopenharmony_ci phy_data->sfp_mod_absent = 1; 140262306a36Sopenharmony_ci phy_data->sfp_base = XGBE_SFP_BASE_UNKNOWN; 140362306a36Sopenharmony_ci phy_data->sfp_cable = XGBE_SFP_CABLE_UNKNOWN; 140462306a36Sopenharmony_ci phy_data->sfp_speed = XGBE_SFP_SPEED_UNKNOWN; 140562306a36Sopenharmony_ci} 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_cistatic void xgbe_phy_sfp_detect(struct xgbe_prv_data *pdata) 140862306a36Sopenharmony_ci{ 140962306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 141062306a36Sopenharmony_ci int ret; 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci /* Reset the SFP signals and info */ 141362306a36Sopenharmony_ci xgbe_phy_sfp_reset(phy_data); 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci ret = xgbe_phy_get_comm_ownership(pdata); 141662306a36Sopenharmony_ci if (ret) 141762306a36Sopenharmony_ci return; 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci /* Read the SFP signals and check for module presence */ 142062306a36Sopenharmony_ci xgbe_phy_sfp_signals(pdata); 142162306a36Sopenharmony_ci if (phy_data->sfp_mod_absent) { 142262306a36Sopenharmony_ci xgbe_phy_sfp_mod_absent(pdata); 142362306a36Sopenharmony_ci goto put; 142462306a36Sopenharmony_ci } 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci ret = xgbe_phy_sfp_read_eeprom(pdata); 142762306a36Sopenharmony_ci if (ret) { 142862306a36Sopenharmony_ci /* Treat any error as if there isn't an SFP plugged in */ 142962306a36Sopenharmony_ci xgbe_phy_sfp_reset(phy_data); 143062306a36Sopenharmony_ci xgbe_phy_sfp_mod_absent(pdata); 143162306a36Sopenharmony_ci goto put; 143262306a36Sopenharmony_ci } 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci xgbe_phy_sfp_parse_eeprom(pdata); 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_ci xgbe_phy_sfp_external_phy(pdata); 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_ciput: 143962306a36Sopenharmony_ci xgbe_phy_sfp_phy_settings(pdata); 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_ci xgbe_phy_put_comm_ownership(pdata); 144262306a36Sopenharmony_ci} 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_cistatic int xgbe_phy_module_eeprom(struct xgbe_prv_data *pdata, 144562306a36Sopenharmony_ci struct ethtool_eeprom *eeprom, u8 *data) 144662306a36Sopenharmony_ci{ 144762306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 144862306a36Sopenharmony_ci u8 eeprom_addr, eeprom_data[XGBE_SFP_EEPROM_MAX]; 144962306a36Sopenharmony_ci struct xgbe_sfp_eeprom *sfp_eeprom; 145062306a36Sopenharmony_ci unsigned int i, j, rem; 145162306a36Sopenharmony_ci int ret; 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci rem = eeprom->len; 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci if (!eeprom->len) { 145662306a36Sopenharmony_ci ret = -EINVAL; 145762306a36Sopenharmony_ci goto done; 145862306a36Sopenharmony_ci } 145962306a36Sopenharmony_ci 146062306a36Sopenharmony_ci if ((eeprom->offset + eeprom->len) > XGBE_SFP_EEPROM_MAX) { 146162306a36Sopenharmony_ci ret = -EINVAL; 146262306a36Sopenharmony_ci goto done; 146362306a36Sopenharmony_ci } 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci if (phy_data->port_mode != XGBE_PORT_MODE_SFP) { 146662306a36Sopenharmony_ci ret = -ENXIO; 146762306a36Sopenharmony_ci goto done; 146862306a36Sopenharmony_ci } 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci if (!netif_running(pdata->netdev)) { 147162306a36Sopenharmony_ci ret = -EIO; 147262306a36Sopenharmony_ci goto done; 147362306a36Sopenharmony_ci } 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_ci if (phy_data->sfp_mod_absent) { 147662306a36Sopenharmony_ci ret = -EIO; 147762306a36Sopenharmony_ci goto done; 147862306a36Sopenharmony_ci } 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci ret = xgbe_phy_get_comm_ownership(pdata); 148162306a36Sopenharmony_ci if (ret) { 148262306a36Sopenharmony_ci ret = -EIO; 148362306a36Sopenharmony_ci goto done; 148462306a36Sopenharmony_ci } 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci ret = xgbe_phy_sfp_get_mux(pdata); 148762306a36Sopenharmony_ci if (ret) { 148862306a36Sopenharmony_ci netdev_err(pdata->netdev, "I2C error setting SFP MUX\n"); 148962306a36Sopenharmony_ci ret = -EIO; 149062306a36Sopenharmony_ci goto put_own; 149162306a36Sopenharmony_ci } 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci /* Read the SFP serial ID eeprom */ 149462306a36Sopenharmony_ci eeprom_addr = 0; 149562306a36Sopenharmony_ci ret = xgbe_phy_i2c_read(pdata, XGBE_SFP_SERIAL_ID_ADDRESS, 149662306a36Sopenharmony_ci &eeprom_addr, sizeof(eeprom_addr), 149762306a36Sopenharmony_ci eeprom_data, XGBE_SFP_EEPROM_BASE_LEN); 149862306a36Sopenharmony_ci if (ret) { 149962306a36Sopenharmony_ci netdev_err(pdata->netdev, 150062306a36Sopenharmony_ci "I2C error reading SFP EEPROM\n"); 150162306a36Sopenharmony_ci ret = -EIO; 150262306a36Sopenharmony_ci goto put_mux; 150362306a36Sopenharmony_ci } 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_ci sfp_eeprom = (struct xgbe_sfp_eeprom *)eeprom_data; 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci if (XGBE_SFP_DIAGS_SUPPORTED(sfp_eeprom)) { 150862306a36Sopenharmony_ci /* Read the SFP diagnostic eeprom */ 150962306a36Sopenharmony_ci eeprom_addr = 0; 151062306a36Sopenharmony_ci ret = xgbe_phy_i2c_read(pdata, XGBE_SFP_DIAG_INFO_ADDRESS, 151162306a36Sopenharmony_ci &eeprom_addr, sizeof(eeprom_addr), 151262306a36Sopenharmony_ci eeprom_data + XGBE_SFP_EEPROM_BASE_LEN, 151362306a36Sopenharmony_ci XGBE_SFP_EEPROM_DIAG_LEN); 151462306a36Sopenharmony_ci if (ret) { 151562306a36Sopenharmony_ci netdev_err(pdata->netdev, 151662306a36Sopenharmony_ci "I2C error reading SFP DIAGS\n"); 151762306a36Sopenharmony_ci ret = -EIO; 151862306a36Sopenharmony_ci goto put_mux; 151962306a36Sopenharmony_ci } 152062306a36Sopenharmony_ci } 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_ci for (i = 0, j = eeprom->offset; i < eeprom->len; i++, j++) { 152362306a36Sopenharmony_ci if ((j >= XGBE_SFP_EEPROM_BASE_LEN) && 152462306a36Sopenharmony_ci !XGBE_SFP_DIAGS_SUPPORTED(sfp_eeprom)) 152562306a36Sopenharmony_ci break; 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_ci data[i] = eeprom_data[j]; 152862306a36Sopenharmony_ci rem--; 152962306a36Sopenharmony_ci } 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ciput_mux: 153262306a36Sopenharmony_ci xgbe_phy_sfp_put_mux(pdata); 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ciput_own: 153562306a36Sopenharmony_ci xgbe_phy_put_comm_ownership(pdata); 153662306a36Sopenharmony_ci 153762306a36Sopenharmony_cidone: 153862306a36Sopenharmony_ci eeprom->len -= rem; 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci return ret; 154162306a36Sopenharmony_ci} 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_cistatic int xgbe_phy_module_info(struct xgbe_prv_data *pdata, 154462306a36Sopenharmony_ci struct ethtool_modinfo *modinfo) 154562306a36Sopenharmony_ci{ 154662306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 154762306a36Sopenharmony_ci 154862306a36Sopenharmony_ci if (phy_data->port_mode != XGBE_PORT_MODE_SFP) 154962306a36Sopenharmony_ci return -ENXIO; 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci if (!netif_running(pdata->netdev)) 155262306a36Sopenharmony_ci return -EIO; 155362306a36Sopenharmony_ci 155462306a36Sopenharmony_ci if (phy_data->sfp_mod_absent) 155562306a36Sopenharmony_ci return -EIO; 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_ci if (XGBE_SFP_DIAGS_SUPPORTED(&phy_data->sfp_eeprom)) { 155862306a36Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8472; 155962306a36Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; 156062306a36Sopenharmony_ci } else { 156162306a36Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8079; 156262306a36Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN; 156362306a36Sopenharmony_ci } 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_ci return 0; 156662306a36Sopenharmony_ci} 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_cistatic void xgbe_phy_phydev_flowctrl(struct xgbe_prv_data *pdata) 156962306a36Sopenharmony_ci{ 157062306a36Sopenharmony_ci struct ethtool_link_ksettings *lks = &pdata->phy.lks; 157162306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 157262306a36Sopenharmony_ci u16 lcl_adv = 0, rmt_adv = 0; 157362306a36Sopenharmony_ci u8 fc; 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_ci pdata->phy.tx_pause = 0; 157662306a36Sopenharmony_ci pdata->phy.rx_pause = 0; 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_ci if (!phy_data->phydev) 157962306a36Sopenharmony_ci return; 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_ci lcl_adv = linkmode_adv_to_lcl_adv_t(phy_data->phydev->advertising); 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_ci if (phy_data->phydev->pause) { 158462306a36Sopenharmony_ci XGBE_SET_LP_ADV(lks, Pause); 158562306a36Sopenharmony_ci rmt_adv |= LPA_PAUSE_CAP; 158662306a36Sopenharmony_ci } 158762306a36Sopenharmony_ci if (phy_data->phydev->asym_pause) { 158862306a36Sopenharmony_ci XGBE_SET_LP_ADV(lks, Asym_Pause); 158962306a36Sopenharmony_ci rmt_adv |= LPA_PAUSE_ASYM; 159062306a36Sopenharmony_ci } 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_ci fc = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv); 159362306a36Sopenharmony_ci if (fc & FLOW_CTRL_TX) 159462306a36Sopenharmony_ci pdata->phy.tx_pause = 1; 159562306a36Sopenharmony_ci if (fc & FLOW_CTRL_RX) 159662306a36Sopenharmony_ci pdata->phy.rx_pause = 1; 159762306a36Sopenharmony_ci} 159862306a36Sopenharmony_ci 159962306a36Sopenharmony_cistatic enum xgbe_mode xgbe_phy_an37_sgmii_outcome(struct xgbe_prv_data *pdata) 160062306a36Sopenharmony_ci{ 160162306a36Sopenharmony_ci struct ethtool_link_ksettings *lks = &pdata->phy.lks; 160262306a36Sopenharmony_ci enum xgbe_mode mode; 160362306a36Sopenharmony_ci 160462306a36Sopenharmony_ci XGBE_SET_LP_ADV(lks, Autoneg); 160562306a36Sopenharmony_ci XGBE_SET_LP_ADV(lks, TP); 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_ci /* Use external PHY to determine flow control */ 160862306a36Sopenharmony_ci if (pdata->phy.pause_autoneg) 160962306a36Sopenharmony_ci xgbe_phy_phydev_flowctrl(pdata); 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_ci switch (pdata->an_status & XGBE_SGMII_AN_LINK_SPEED) { 161262306a36Sopenharmony_ci case XGBE_SGMII_AN_LINK_SPEED_10: 161362306a36Sopenharmony_ci if (pdata->an_status & XGBE_SGMII_AN_LINK_DUPLEX) { 161462306a36Sopenharmony_ci XGBE_SET_LP_ADV(lks, 10baseT_Full); 161562306a36Sopenharmony_ci mode = XGBE_MODE_SGMII_10; 161662306a36Sopenharmony_ci } else { 161762306a36Sopenharmony_ci /* Half-duplex not supported */ 161862306a36Sopenharmony_ci XGBE_SET_LP_ADV(lks, 10baseT_Half); 161962306a36Sopenharmony_ci mode = XGBE_MODE_UNKNOWN; 162062306a36Sopenharmony_ci } 162162306a36Sopenharmony_ci break; 162262306a36Sopenharmony_ci case XGBE_SGMII_AN_LINK_SPEED_100: 162362306a36Sopenharmony_ci if (pdata->an_status & XGBE_SGMII_AN_LINK_DUPLEX) { 162462306a36Sopenharmony_ci XGBE_SET_LP_ADV(lks, 100baseT_Full); 162562306a36Sopenharmony_ci mode = XGBE_MODE_SGMII_100; 162662306a36Sopenharmony_ci } else { 162762306a36Sopenharmony_ci /* Half-duplex not supported */ 162862306a36Sopenharmony_ci XGBE_SET_LP_ADV(lks, 100baseT_Half); 162962306a36Sopenharmony_ci mode = XGBE_MODE_UNKNOWN; 163062306a36Sopenharmony_ci } 163162306a36Sopenharmony_ci break; 163262306a36Sopenharmony_ci case XGBE_SGMII_AN_LINK_SPEED_1000: 163362306a36Sopenharmony_ci if (pdata->an_status & XGBE_SGMII_AN_LINK_DUPLEX) { 163462306a36Sopenharmony_ci XGBE_SET_LP_ADV(lks, 1000baseT_Full); 163562306a36Sopenharmony_ci mode = XGBE_MODE_SGMII_1000; 163662306a36Sopenharmony_ci } else { 163762306a36Sopenharmony_ci /* Half-duplex not supported */ 163862306a36Sopenharmony_ci XGBE_SET_LP_ADV(lks, 1000baseT_Half); 163962306a36Sopenharmony_ci mode = XGBE_MODE_UNKNOWN; 164062306a36Sopenharmony_ci } 164162306a36Sopenharmony_ci break; 164262306a36Sopenharmony_ci default: 164362306a36Sopenharmony_ci mode = XGBE_MODE_UNKNOWN; 164462306a36Sopenharmony_ci } 164562306a36Sopenharmony_ci 164662306a36Sopenharmony_ci return mode; 164762306a36Sopenharmony_ci} 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_cistatic enum xgbe_mode xgbe_phy_an37_outcome(struct xgbe_prv_data *pdata) 165062306a36Sopenharmony_ci{ 165162306a36Sopenharmony_ci struct ethtool_link_ksettings *lks = &pdata->phy.lks; 165262306a36Sopenharmony_ci enum xgbe_mode mode; 165362306a36Sopenharmony_ci unsigned int ad_reg, lp_reg; 165462306a36Sopenharmony_ci 165562306a36Sopenharmony_ci XGBE_SET_LP_ADV(lks, Autoneg); 165662306a36Sopenharmony_ci XGBE_SET_LP_ADV(lks, FIBRE); 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci /* Compare Advertisement and Link Partner register */ 165962306a36Sopenharmony_ci ad_reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_ADVERTISE); 166062306a36Sopenharmony_ci lp_reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_LP_ABILITY); 166162306a36Sopenharmony_ci if (lp_reg & 0x100) 166262306a36Sopenharmony_ci XGBE_SET_LP_ADV(lks, Pause); 166362306a36Sopenharmony_ci if (lp_reg & 0x80) 166462306a36Sopenharmony_ci XGBE_SET_LP_ADV(lks, Asym_Pause); 166562306a36Sopenharmony_ci 166662306a36Sopenharmony_ci if (pdata->phy.pause_autoneg) { 166762306a36Sopenharmony_ci /* Set flow control based on auto-negotiation result */ 166862306a36Sopenharmony_ci pdata->phy.tx_pause = 0; 166962306a36Sopenharmony_ci pdata->phy.rx_pause = 0; 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_ci if (ad_reg & lp_reg & 0x100) { 167262306a36Sopenharmony_ci pdata->phy.tx_pause = 1; 167362306a36Sopenharmony_ci pdata->phy.rx_pause = 1; 167462306a36Sopenharmony_ci } else if (ad_reg & lp_reg & 0x80) { 167562306a36Sopenharmony_ci if (ad_reg & 0x100) 167662306a36Sopenharmony_ci pdata->phy.rx_pause = 1; 167762306a36Sopenharmony_ci else if (lp_reg & 0x100) 167862306a36Sopenharmony_ci pdata->phy.tx_pause = 1; 167962306a36Sopenharmony_ci } 168062306a36Sopenharmony_ci } 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci if (lp_reg & 0x20) 168362306a36Sopenharmony_ci XGBE_SET_LP_ADV(lks, 1000baseX_Full); 168462306a36Sopenharmony_ci 168562306a36Sopenharmony_ci /* Half duplex is not supported */ 168662306a36Sopenharmony_ci ad_reg &= lp_reg; 168762306a36Sopenharmony_ci mode = (ad_reg & 0x20) ? XGBE_MODE_X : XGBE_MODE_UNKNOWN; 168862306a36Sopenharmony_ci 168962306a36Sopenharmony_ci return mode; 169062306a36Sopenharmony_ci} 169162306a36Sopenharmony_ci 169262306a36Sopenharmony_cistatic enum xgbe_mode xgbe_phy_an73_redrv_outcome(struct xgbe_prv_data *pdata) 169362306a36Sopenharmony_ci{ 169462306a36Sopenharmony_ci struct ethtool_link_ksettings *lks = &pdata->phy.lks; 169562306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 169662306a36Sopenharmony_ci enum xgbe_mode mode; 169762306a36Sopenharmony_ci unsigned int ad_reg, lp_reg; 169862306a36Sopenharmony_ci 169962306a36Sopenharmony_ci XGBE_SET_LP_ADV(lks, Autoneg); 170062306a36Sopenharmony_ci XGBE_SET_LP_ADV(lks, Backplane); 170162306a36Sopenharmony_ci 170262306a36Sopenharmony_ci /* Use external PHY to determine flow control */ 170362306a36Sopenharmony_ci if (pdata->phy.pause_autoneg) 170462306a36Sopenharmony_ci xgbe_phy_phydev_flowctrl(pdata); 170562306a36Sopenharmony_ci 170662306a36Sopenharmony_ci /* Compare Advertisement and Link Partner register 2 */ 170762306a36Sopenharmony_ci ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1); 170862306a36Sopenharmony_ci lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1); 170962306a36Sopenharmony_ci if (lp_reg & 0x80) 171062306a36Sopenharmony_ci XGBE_SET_LP_ADV(lks, 10000baseKR_Full); 171162306a36Sopenharmony_ci if (lp_reg & 0x20) 171262306a36Sopenharmony_ci XGBE_SET_LP_ADV(lks, 1000baseKX_Full); 171362306a36Sopenharmony_ci 171462306a36Sopenharmony_ci ad_reg &= lp_reg; 171562306a36Sopenharmony_ci if (ad_reg & 0x80) { 171662306a36Sopenharmony_ci switch (phy_data->port_mode) { 171762306a36Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE: 171862306a36Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE_NO_AUTONEG: 171962306a36Sopenharmony_ci mode = XGBE_MODE_KR; 172062306a36Sopenharmony_ci break; 172162306a36Sopenharmony_ci default: 172262306a36Sopenharmony_ci mode = XGBE_MODE_SFI; 172362306a36Sopenharmony_ci break; 172462306a36Sopenharmony_ci } 172562306a36Sopenharmony_ci } else if (ad_reg & 0x20) { 172662306a36Sopenharmony_ci switch (phy_data->port_mode) { 172762306a36Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE: 172862306a36Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE_NO_AUTONEG: 172962306a36Sopenharmony_ci mode = XGBE_MODE_KX_1000; 173062306a36Sopenharmony_ci break; 173162306a36Sopenharmony_ci case XGBE_PORT_MODE_1000BASE_X: 173262306a36Sopenharmony_ci mode = XGBE_MODE_X; 173362306a36Sopenharmony_ci break; 173462306a36Sopenharmony_ci case XGBE_PORT_MODE_SFP: 173562306a36Sopenharmony_ci switch (phy_data->sfp_base) { 173662306a36Sopenharmony_ci case XGBE_SFP_BASE_1000_T: 173762306a36Sopenharmony_ci if (phy_data->phydev && 173862306a36Sopenharmony_ci (phy_data->phydev->speed == SPEED_10)) 173962306a36Sopenharmony_ci mode = XGBE_MODE_SGMII_10; 174062306a36Sopenharmony_ci else if (phy_data->phydev && 174162306a36Sopenharmony_ci (phy_data->phydev->speed == SPEED_100)) 174262306a36Sopenharmony_ci mode = XGBE_MODE_SGMII_100; 174362306a36Sopenharmony_ci else 174462306a36Sopenharmony_ci mode = XGBE_MODE_SGMII_1000; 174562306a36Sopenharmony_ci break; 174662306a36Sopenharmony_ci case XGBE_SFP_BASE_1000_SX: 174762306a36Sopenharmony_ci case XGBE_SFP_BASE_1000_LX: 174862306a36Sopenharmony_ci case XGBE_SFP_BASE_1000_CX: 174962306a36Sopenharmony_ci default: 175062306a36Sopenharmony_ci mode = XGBE_MODE_X; 175162306a36Sopenharmony_ci break; 175262306a36Sopenharmony_ci } 175362306a36Sopenharmony_ci break; 175462306a36Sopenharmony_ci default: 175562306a36Sopenharmony_ci if (phy_data->phydev && 175662306a36Sopenharmony_ci (phy_data->phydev->speed == SPEED_10)) 175762306a36Sopenharmony_ci mode = XGBE_MODE_SGMII_10; 175862306a36Sopenharmony_ci else if (phy_data->phydev && 175962306a36Sopenharmony_ci (phy_data->phydev->speed == SPEED_100)) 176062306a36Sopenharmony_ci mode = XGBE_MODE_SGMII_100; 176162306a36Sopenharmony_ci else 176262306a36Sopenharmony_ci mode = XGBE_MODE_SGMII_1000; 176362306a36Sopenharmony_ci break; 176462306a36Sopenharmony_ci } 176562306a36Sopenharmony_ci } else { 176662306a36Sopenharmony_ci mode = XGBE_MODE_UNKNOWN; 176762306a36Sopenharmony_ci } 176862306a36Sopenharmony_ci 176962306a36Sopenharmony_ci /* Compare Advertisement and Link Partner register 3 */ 177062306a36Sopenharmony_ci ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); 177162306a36Sopenharmony_ci lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2); 177262306a36Sopenharmony_ci if (lp_reg & 0xc000) 177362306a36Sopenharmony_ci XGBE_SET_LP_ADV(lks, 10000baseR_FEC); 177462306a36Sopenharmony_ci 177562306a36Sopenharmony_ci return mode; 177662306a36Sopenharmony_ci} 177762306a36Sopenharmony_ci 177862306a36Sopenharmony_cistatic enum xgbe_mode xgbe_phy_an73_outcome(struct xgbe_prv_data *pdata) 177962306a36Sopenharmony_ci{ 178062306a36Sopenharmony_ci struct ethtool_link_ksettings *lks = &pdata->phy.lks; 178162306a36Sopenharmony_ci enum xgbe_mode mode; 178262306a36Sopenharmony_ci unsigned int ad_reg, lp_reg; 178362306a36Sopenharmony_ci 178462306a36Sopenharmony_ci XGBE_SET_LP_ADV(lks, Autoneg); 178562306a36Sopenharmony_ci XGBE_SET_LP_ADV(lks, Backplane); 178662306a36Sopenharmony_ci 178762306a36Sopenharmony_ci /* Compare Advertisement and Link Partner register 1 */ 178862306a36Sopenharmony_ci ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE); 178962306a36Sopenharmony_ci lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA); 179062306a36Sopenharmony_ci if (lp_reg & 0x400) 179162306a36Sopenharmony_ci XGBE_SET_LP_ADV(lks, Pause); 179262306a36Sopenharmony_ci if (lp_reg & 0x800) 179362306a36Sopenharmony_ci XGBE_SET_LP_ADV(lks, Asym_Pause); 179462306a36Sopenharmony_ci 179562306a36Sopenharmony_ci if (pdata->phy.pause_autoneg) { 179662306a36Sopenharmony_ci /* Set flow control based on auto-negotiation result */ 179762306a36Sopenharmony_ci pdata->phy.tx_pause = 0; 179862306a36Sopenharmony_ci pdata->phy.rx_pause = 0; 179962306a36Sopenharmony_ci 180062306a36Sopenharmony_ci if (ad_reg & lp_reg & 0x400) { 180162306a36Sopenharmony_ci pdata->phy.tx_pause = 1; 180262306a36Sopenharmony_ci pdata->phy.rx_pause = 1; 180362306a36Sopenharmony_ci } else if (ad_reg & lp_reg & 0x800) { 180462306a36Sopenharmony_ci if (ad_reg & 0x400) 180562306a36Sopenharmony_ci pdata->phy.rx_pause = 1; 180662306a36Sopenharmony_ci else if (lp_reg & 0x400) 180762306a36Sopenharmony_ci pdata->phy.tx_pause = 1; 180862306a36Sopenharmony_ci } 180962306a36Sopenharmony_ci } 181062306a36Sopenharmony_ci 181162306a36Sopenharmony_ci /* Compare Advertisement and Link Partner register 2 */ 181262306a36Sopenharmony_ci ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1); 181362306a36Sopenharmony_ci lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1); 181462306a36Sopenharmony_ci if (lp_reg & 0x80) 181562306a36Sopenharmony_ci XGBE_SET_LP_ADV(lks, 10000baseKR_Full); 181662306a36Sopenharmony_ci if (lp_reg & 0x20) 181762306a36Sopenharmony_ci XGBE_SET_LP_ADV(lks, 1000baseKX_Full); 181862306a36Sopenharmony_ci 181962306a36Sopenharmony_ci ad_reg &= lp_reg; 182062306a36Sopenharmony_ci if (ad_reg & 0x80) 182162306a36Sopenharmony_ci mode = XGBE_MODE_KR; 182262306a36Sopenharmony_ci else if (ad_reg & 0x20) 182362306a36Sopenharmony_ci mode = XGBE_MODE_KX_1000; 182462306a36Sopenharmony_ci else 182562306a36Sopenharmony_ci mode = XGBE_MODE_UNKNOWN; 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_ci /* Compare Advertisement and Link Partner register 3 */ 182862306a36Sopenharmony_ci ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); 182962306a36Sopenharmony_ci lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2); 183062306a36Sopenharmony_ci if (lp_reg & 0xc000) 183162306a36Sopenharmony_ci XGBE_SET_LP_ADV(lks, 10000baseR_FEC); 183262306a36Sopenharmony_ci 183362306a36Sopenharmony_ci return mode; 183462306a36Sopenharmony_ci} 183562306a36Sopenharmony_ci 183662306a36Sopenharmony_cistatic enum xgbe_mode xgbe_phy_an_outcome(struct xgbe_prv_data *pdata) 183762306a36Sopenharmony_ci{ 183862306a36Sopenharmony_ci switch (pdata->an_mode) { 183962306a36Sopenharmony_ci case XGBE_AN_MODE_CL73: 184062306a36Sopenharmony_ci return xgbe_phy_an73_outcome(pdata); 184162306a36Sopenharmony_ci case XGBE_AN_MODE_CL73_REDRV: 184262306a36Sopenharmony_ci return xgbe_phy_an73_redrv_outcome(pdata); 184362306a36Sopenharmony_ci case XGBE_AN_MODE_CL37: 184462306a36Sopenharmony_ci return xgbe_phy_an37_outcome(pdata); 184562306a36Sopenharmony_ci case XGBE_AN_MODE_CL37_SGMII: 184662306a36Sopenharmony_ci return xgbe_phy_an37_sgmii_outcome(pdata); 184762306a36Sopenharmony_ci default: 184862306a36Sopenharmony_ci return XGBE_MODE_UNKNOWN; 184962306a36Sopenharmony_ci } 185062306a36Sopenharmony_ci} 185162306a36Sopenharmony_ci 185262306a36Sopenharmony_cistatic void xgbe_phy_an_advertising(struct xgbe_prv_data *pdata, 185362306a36Sopenharmony_ci struct ethtool_link_ksettings *dlks) 185462306a36Sopenharmony_ci{ 185562306a36Sopenharmony_ci struct ethtool_link_ksettings *slks = &pdata->phy.lks; 185662306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 185762306a36Sopenharmony_ci 185862306a36Sopenharmony_ci XGBE_LM_COPY(dlks, advertising, slks, advertising); 185962306a36Sopenharmony_ci 186062306a36Sopenharmony_ci /* Without a re-driver, just return current advertising */ 186162306a36Sopenharmony_ci if (!phy_data->redrv) 186262306a36Sopenharmony_ci return; 186362306a36Sopenharmony_ci 186462306a36Sopenharmony_ci /* With the KR re-driver we need to advertise a single speed */ 186562306a36Sopenharmony_ci XGBE_CLR_ADV(dlks, 1000baseKX_Full); 186662306a36Sopenharmony_ci XGBE_CLR_ADV(dlks, 10000baseKR_Full); 186762306a36Sopenharmony_ci 186862306a36Sopenharmony_ci /* Advertise FEC support is present */ 186962306a36Sopenharmony_ci if (pdata->fec_ability & MDIO_PMA_10GBR_FECABLE_ABLE) 187062306a36Sopenharmony_ci XGBE_SET_ADV(dlks, 10000baseR_FEC); 187162306a36Sopenharmony_ci 187262306a36Sopenharmony_ci switch (phy_data->port_mode) { 187362306a36Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE: 187462306a36Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE_NO_AUTONEG: 187562306a36Sopenharmony_ci XGBE_SET_ADV(dlks, 10000baseKR_Full); 187662306a36Sopenharmony_ci break; 187762306a36Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE_2500: 187862306a36Sopenharmony_ci XGBE_SET_ADV(dlks, 1000baseKX_Full); 187962306a36Sopenharmony_ci break; 188062306a36Sopenharmony_ci case XGBE_PORT_MODE_1000BASE_T: 188162306a36Sopenharmony_ci case XGBE_PORT_MODE_1000BASE_X: 188262306a36Sopenharmony_ci case XGBE_PORT_MODE_NBASE_T: 188362306a36Sopenharmony_ci XGBE_SET_ADV(dlks, 1000baseKX_Full); 188462306a36Sopenharmony_ci break; 188562306a36Sopenharmony_ci case XGBE_PORT_MODE_10GBASE_T: 188662306a36Sopenharmony_ci if (phy_data->phydev && 188762306a36Sopenharmony_ci (phy_data->phydev->speed == SPEED_10000)) 188862306a36Sopenharmony_ci XGBE_SET_ADV(dlks, 10000baseKR_Full); 188962306a36Sopenharmony_ci else if (phy_data->phydev && 189062306a36Sopenharmony_ci (phy_data->phydev->speed == SPEED_2500)) 189162306a36Sopenharmony_ci XGBE_SET_ADV(dlks, 2500baseX_Full); 189262306a36Sopenharmony_ci else 189362306a36Sopenharmony_ci XGBE_SET_ADV(dlks, 1000baseKX_Full); 189462306a36Sopenharmony_ci break; 189562306a36Sopenharmony_ci case XGBE_PORT_MODE_10GBASE_R: 189662306a36Sopenharmony_ci XGBE_SET_ADV(dlks, 10000baseKR_Full); 189762306a36Sopenharmony_ci break; 189862306a36Sopenharmony_ci case XGBE_PORT_MODE_SFP: 189962306a36Sopenharmony_ci switch (phy_data->sfp_base) { 190062306a36Sopenharmony_ci case XGBE_SFP_BASE_1000_T: 190162306a36Sopenharmony_ci case XGBE_SFP_BASE_1000_SX: 190262306a36Sopenharmony_ci case XGBE_SFP_BASE_1000_LX: 190362306a36Sopenharmony_ci case XGBE_SFP_BASE_1000_CX: 190462306a36Sopenharmony_ci XGBE_SET_ADV(dlks, 1000baseKX_Full); 190562306a36Sopenharmony_ci break; 190662306a36Sopenharmony_ci default: 190762306a36Sopenharmony_ci XGBE_SET_ADV(dlks, 10000baseKR_Full); 190862306a36Sopenharmony_ci break; 190962306a36Sopenharmony_ci } 191062306a36Sopenharmony_ci break; 191162306a36Sopenharmony_ci default: 191262306a36Sopenharmony_ci XGBE_SET_ADV(dlks, 10000baseKR_Full); 191362306a36Sopenharmony_ci break; 191462306a36Sopenharmony_ci } 191562306a36Sopenharmony_ci} 191662306a36Sopenharmony_ci 191762306a36Sopenharmony_cistatic int xgbe_phy_an_config(struct xgbe_prv_data *pdata) 191862306a36Sopenharmony_ci{ 191962306a36Sopenharmony_ci struct ethtool_link_ksettings *lks = &pdata->phy.lks; 192062306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 192162306a36Sopenharmony_ci int ret; 192262306a36Sopenharmony_ci 192362306a36Sopenharmony_ci ret = xgbe_phy_find_phy_device(pdata); 192462306a36Sopenharmony_ci if (ret) 192562306a36Sopenharmony_ci return ret; 192662306a36Sopenharmony_ci 192762306a36Sopenharmony_ci if (!phy_data->phydev) 192862306a36Sopenharmony_ci return 0; 192962306a36Sopenharmony_ci 193062306a36Sopenharmony_ci phy_data->phydev->autoneg = pdata->phy.autoneg; 193162306a36Sopenharmony_ci linkmode_and(phy_data->phydev->advertising, 193262306a36Sopenharmony_ci phy_data->phydev->supported, 193362306a36Sopenharmony_ci lks->link_modes.advertising); 193462306a36Sopenharmony_ci 193562306a36Sopenharmony_ci if (pdata->phy.autoneg != AUTONEG_ENABLE) { 193662306a36Sopenharmony_ci phy_data->phydev->speed = pdata->phy.speed; 193762306a36Sopenharmony_ci phy_data->phydev->duplex = pdata->phy.duplex; 193862306a36Sopenharmony_ci } 193962306a36Sopenharmony_ci 194062306a36Sopenharmony_ci ret = phy_start_aneg(phy_data->phydev); 194162306a36Sopenharmony_ci 194262306a36Sopenharmony_ci return ret; 194362306a36Sopenharmony_ci} 194462306a36Sopenharmony_ci 194562306a36Sopenharmony_cistatic enum xgbe_an_mode xgbe_phy_an_sfp_mode(struct xgbe_phy_data *phy_data) 194662306a36Sopenharmony_ci{ 194762306a36Sopenharmony_ci switch (phy_data->sfp_base) { 194862306a36Sopenharmony_ci case XGBE_SFP_BASE_1000_T: 194962306a36Sopenharmony_ci return XGBE_AN_MODE_CL37_SGMII; 195062306a36Sopenharmony_ci case XGBE_SFP_BASE_1000_SX: 195162306a36Sopenharmony_ci case XGBE_SFP_BASE_1000_LX: 195262306a36Sopenharmony_ci case XGBE_SFP_BASE_1000_CX: 195362306a36Sopenharmony_ci return XGBE_AN_MODE_CL37; 195462306a36Sopenharmony_ci default: 195562306a36Sopenharmony_ci return XGBE_AN_MODE_NONE; 195662306a36Sopenharmony_ci } 195762306a36Sopenharmony_ci} 195862306a36Sopenharmony_ci 195962306a36Sopenharmony_cistatic enum xgbe_an_mode xgbe_phy_an_mode(struct xgbe_prv_data *pdata) 196062306a36Sopenharmony_ci{ 196162306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 196262306a36Sopenharmony_ci 196362306a36Sopenharmony_ci /* A KR re-driver will always require CL73 AN */ 196462306a36Sopenharmony_ci if (phy_data->redrv) 196562306a36Sopenharmony_ci return XGBE_AN_MODE_CL73_REDRV; 196662306a36Sopenharmony_ci 196762306a36Sopenharmony_ci switch (phy_data->port_mode) { 196862306a36Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE: 196962306a36Sopenharmony_ci return XGBE_AN_MODE_CL73; 197062306a36Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE_NO_AUTONEG: 197162306a36Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE_2500: 197262306a36Sopenharmony_ci return XGBE_AN_MODE_NONE; 197362306a36Sopenharmony_ci case XGBE_PORT_MODE_1000BASE_T: 197462306a36Sopenharmony_ci return XGBE_AN_MODE_CL37_SGMII; 197562306a36Sopenharmony_ci case XGBE_PORT_MODE_1000BASE_X: 197662306a36Sopenharmony_ci return XGBE_AN_MODE_CL37; 197762306a36Sopenharmony_ci case XGBE_PORT_MODE_NBASE_T: 197862306a36Sopenharmony_ci return XGBE_AN_MODE_CL37_SGMII; 197962306a36Sopenharmony_ci case XGBE_PORT_MODE_10GBASE_T: 198062306a36Sopenharmony_ci return XGBE_AN_MODE_CL73; 198162306a36Sopenharmony_ci case XGBE_PORT_MODE_10GBASE_R: 198262306a36Sopenharmony_ci return XGBE_AN_MODE_NONE; 198362306a36Sopenharmony_ci case XGBE_PORT_MODE_SFP: 198462306a36Sopenharmony_ci return xgbe_phy_an_sfp_mode(phy_data); 198562306a36Sopenharmony_ci default: 198662306a36Sopenharmony_ci return XGBE_AN_MODE_NONE; 198762306a36Sopenharmony_ci } 198862306a36Sopenharmony_ci} 198962306a36Sopenharmony_ci 199062306a36Sopenharmony_cistatic int xgbe_phy_set_redrv_mode_mdio(struct xgbe_prv_data *pdata, 199162306a36Sopenharmony_ci enum xgbe_phy_redrv_mode mode) 199262306a36Sopenharmony_ci{ 199362306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 199462306a36Sopenharmony_ci u16 redrv_reg, redrv_val; 199562306a36Sopenharmony_ci 199662306a36Sopenharmony_ci redrv_reg = XGBE_PHY_REDRV_MODE_REG + (phy_data->redrv_lane * 0x1000); 199762306a36Sopenharmony_ci redrv_val = (u16)mode; 199862306a36Sopenharmony_ci 199962306a36Sopenharmony_ci return pdata->hw_if.write_ext_mii_regs_c22(pdata, phy_data->redrv_addr, 200062306a36Sopenharmony_ci redrv_reg, redrv_val); 200162306a36Sopenharmony_ci} 200262306a36Sopenharmony_ci 200362306a36Sopenharmony_cistatic int xgbe_phy_set_redrv_mode_i2c(struct xgbe_prv_data *pdata, 200462306a36Sopenharmony_ci enum xgbe_phy_redrv_mode mode) 200562306a36Sopenharmony_ci{ 200662306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 200762306a36Sopenharmony_ci unsigned int redrv_reg; 200862306a36Sopenharmony_ci int ret; 200962306a36Sopenharmony_ci 201062306a36Sopenharmony_ci /* Calculate the register to write */ 201162306a36Sopenharmony_ci redrv_reg = XGBE_PHY_REDRV_MODE_REG + (phy_data->redrv_lane * 0x1000); 201262306a36Sopenharmony_ci 201362306a36Sopenharmony_ci ret = xgbe_phy_redrv_write(pdata, redrv_reg, mode); 201462306a36Sopenharmony_ci 201562306a36Sopenharmony_ci return ret; 201662306a36Sopenharmony_ci} 201762306a36Sopenharmony_ci 201862306a36Sopenharmony_cistatic void xgbe_phy_set_redrv_mode(struct xgbe_prv_data *pdata) 201962306a36Sopenharmony_ci{ 202062306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 202162306a36Sopenharmony_ci enum xgbe_phy_redrv_mode mode; 202262306a36Sopenharmony_ci int ret; 202362306a36Sopenharmony_ci 202462306a36Sopenharmony_ci if (!phy_data->redrv) 202562306a36Sopenharmony_ci return; 202662306a36Sopenharmony_ci 202762306a36Sopenharmony_ci mode = XGBE_PHY_REDRV_MODE_CX; 202862306a36Sopenharmony_ci if ((phy_data->port_mode == XGBE_PORT_MODE_SFP) && 202962306a36Sopenharmony_ci (phy_data->sfp_base != XGBE_SFP_BASE_1000_CX) && 203062306a36Sopenharmony_ci (phy_data->sfp_base != XGBE_SFP_BASE_10000_CR)) 203162306a36Sopenharmony_ci mode = XGBE_PHY_REDRV_MODE_SR; 203262306a36Sopenharmony_ci 203362306a36Sopenharmony_ci ret = xgbe_phy_get_comm_ownership(pdata); 203462306a36Sopenharmony_ci if (ret) 203562306a36Sopenharmony_ci return; 203662306a36Sopenharmony_ci 203762306a36Sopenharmony_ci if (phy_data->redrv_if) 203862306a36Sopenharmony_ci xgbe_phy_set_redrv_mode_i2c(pdata, mode); 203962306a36Sopenharmony_ci else 204062306a36Sopenharmony_ci xgbe_phy_set_redrv_mode_mdio(pdata, mode); 204162306a36Sopenharmony_ci 204262306a36Sopenharmony_ci xgbe_phy_put_comm_ownership(pdata); 204362306a36Sopenharmony_ci} 204462306a36Sopenharmony_ci 204562306a36Sopenharmony_ci#define MAX_RX_ADAPT_RETRIES 1 204662306a36Sopenharmony_ci#define XGBE_PMA_RX_VAL_SIG_MASK (XGBE_PMA_RX_SIG_DET_0_MASK | \ 204762306a36Sopenharmony_ci XGBE_PMA_RX_VALID_0_MASK) 204862306a36Sopenharmony_ci 204962306a36Sopenharmony_cistatic void xgbe_set_rx_adap_mode(struct xgbe_prv_data *pdata, 205062306a36Sopenharmony_ci enum xgbe_mode mode) 205162306a36Sopenharmony_ci{ 205262306a36Sopenharmony_ci if (pdata->rx_adapt_retries++ >= MAX_RX_ADAPT_RETRIES) { 205362306a36Sopenharmony_ci pdata->rx_adapt_retries = 0; 205462306a36Sopenharmony_ci return; 205562306a36Sopenharmony_ci } 205662306a36Sopenharmony_ci 205762306a36Sopenharmony_ci xgbe_phy_perform_ratechange(pdata, 205862306a36Sopenharmony_ci mode == XGBE_MODE_KR ? 205962306a36Sopenharmony_ci XGBE_MB_CMD_SET_10G_KR : 206062306a36Sopenharmony_ci XGBE_MB_CMD_SET_10G_SFI, 206162306a36Sopenharmony_ci XGBE_MB_SUBCMD_RX_ADAP); 206262306a36Sopenharmony_ci} 206362306a36Sopenharmony_ci 206462306a36Sopenharmony_cistatic void xgbe_rx_adaptation(struct xgbe_prv_data *pdata) 206562306a36Sopenharmony_ci{ 206662306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 206762306a36Sopenharmony_ci unsigned int reg; 206862306a36Sopenharmony_ci 206962306a36Sopenharmony_ci /* step 2: force PCS to send RX_ADAPT Req to PHY */ 207062306a36Sopenharmony_ci XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_RX_EQ_CTRL4, 207162306a36Sopenharmony_ci XGBE_PMA_RX_AD_REQ_MASK, XGBE_PMA_RX_AD_REQ_ENABLE); 207262306a36Sopenharmony_ci 207362306a36Sopenharmony_ci /* Step 3: Wait for RX_ADAPT ACK from the PHY */ 207462306a36Sopenharmony_ci msleep(200); 207562306a36Sopenharmony_ci 207662306a36Sopenharmony_ci /* Software polls for coefficient update command (given by local PHY) */ 207762306a36Sopenharmony_ci reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_PHY_RX_EQ_CEU); 207862306a36Sopenharmony_ci 207962306a36Sopenharmony_ci /* Clear the RX_AD_REQ bit */ 208062306a36Sopenharmony_ci XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_RX_EQ_CTRL4, 208162306a36Sopenharmony_ci XGBE_PMA_RX_AD_REQ_MASK, XGBE_PMA_RX_AD_REQ_DISABLE); 208262306a36Sopenharmony_ci 208362306a36Sopenharmony_ci /* Check if coefficient update command is set */ 208462306a36Sopenharmony_ci if ((reg & XGBE_PMA_CFF_UPDT_MASK) != XGBE_PMA_CFF_UPDT_MASK) 208562306a36Sopenharmony_ci goto set_mode; 208662306a36Sopenharmony_ci 208762306a36Sopenharmony_ci /* Step 4: Check for Block lock */ 208862306a36Sopenharmony_ci 208962306a36Sopenharmony_ci /* Link status is latched low, so read once to clear 209062306a36Sopenharmony_ci * and then read again to get current state 209162306a36Sopenharmony_ci */ 209262306a36Sopenharmony_ci reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1); 209362306a36Sopenharmony_ci reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1); 209462306a36Sopenharmony_ci if (reg & MDIO_STAT1_LSTATUS) { 209562306a36Sopenharmony_ci /* If the block lock is found, update the helpers 209662306a36Sopenharmony_ci * and declare the link up 209762306a36Sopenharmony_ci */ 209862306a36Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, "Block_lock done"); 209962306a36Sopenharmony_ci pdata->rx_adapt_done = true; 210062306a36Sopenharmony_ci pdata->mode_set = false; 210162306a36Sopenharmony_ci return; 210262306a36Sopenharmony_ci } 210362306a36Sopenharmony_ci 210462306a36Sopenharmony_ciset_mode: 210562306a36Sopenharmony_ci xgbe_set_rx_adap_mode(pdata, phy_data->cur_mode); 210662306a36Sopenharmony_ci} 210762306a36Sopenharmony_ci 210862306a36Sopenharmony_cistatic void xgbe_phy_rx_adaptation(struct xgbe_prv_data *pdata) 210962306a36Sopenharmony_ci{ 211062306a36Sopenharmony_ci unsigned int reg; 211162306a36Sopenharmony_ci 211262306a36Sopenharmony_cirx_adapt_reinit: 211362306a36Sopenharmony_ci reg = XMDIO_READ_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_RX_LSTS, 211462306a36Sopenharmony_ci XGBE_PMA_RX_VAL_SIG_MASK); 211562306a36Sopenharmony_ci 211662306a36Sopenharmony_ci /* step 1: Check for RX_VALID && LF_SIGDET */ 211762306a36Sopenharmony_ci if ((reg & XGBE_PMA_RX_VAL_SIG_MASK) != XGBE_PMA_RX_VAL_SIG_MASK) { 211862306a36Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, 211962306a36Sopenharmony_ci "RX_VALID or LF_SIGDET is unset, issue rrc"); 212062306a36Sopenharmony_ci xgbe_phy_rrc(pdata); 212162306a36Sopenharmony_ci if (pdata->rx_adapt_retries++ >= MAX_RX_ADAPT_RETRIES) { 212262306a36Sopenharmony_ci pdata->rx_adapt_retries = 0; 212362306a36Sopenharmony_ci return; 212462306a36Sopenharmony_ci } 212562306a36Sopenharmony_ci goto rx_adapt_reinit; 212662306a36Sopenharmony_ci } 212762306a36Sopenharmony_ci 212862306a36Sopenharmony_ci /* perform rx adaptation */ 212962306a36Sopenharmony_ci xgbe_rx_adaptation(pdata); 213062306a36Sopenharmony_ci} 213162306a36Sopenharmony_ci 213262306a36Sopenharmony_cistatic void xgbe_phy_rx_reset(struct xgbe_prv_data *pdata) 213362306a36Sopenharmony_ci{ 213462306a36Sopenharmony_ci int reg; 213562306a36Sopenharmony_ci 213662306a36Sopenharmony_ci reg = XMDIO_READ_BITS(pdata, MDIO_MMD_PCS, MDIO_PCS_DIGITAL_STAT, 213762306a36Sopenharmony_ci XGBE_PCS_PSEQ_STATE_MASK); 213862306a36Sopenharmony_ci if (reg == XGBE_PCS_PSEQ_STATE_POWER_GOOD) { 213962306a36Sopenharmony_ci /* Mailbox command timed out, reset of RX block is required. 214062306a36Sopenharmony_ci * This can be done by asseting the reset bit and wait for 214162306a36Sopenharmony_ci * its compeletion. 214262306a36Sopenharmony_ci */ 214362306a36Sopenharmony_ci XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_RX_CTRL1, 214462306a36Sopenharmony_ci XGBE_PMA_RX_RST_0_MASK, XGBE_PMA_RX_RST_0_RESET_ON); 214562306a36Sopenharmony_ci ndelay(20); 214662306a36Sopenharmony_ci XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_RX_CTRL1, 214762306a36Sopenharmony_ci XGBE_PMA_RX_RST_0_MASK, XGBE_PMA_RX_RST_0_RESET_OFF); 214862306a36Sopenharmony_ci usleep_range(40, 50); 214962306a36Sopenharmony_ci netif_err(pdata, link, pdata->netdev, "firmware mailbox reset performed\n"); 215062306a36Sopenharmony_ci } 215162306a36Sopenharmony_ci} 215262306a36Sopenharmony_ci 215362306a36Sopenharmony_cistatic void xgbe_phy_pll_ctrl(struct xgbe_prv_data *pdata, bool enable) 215462306a36Sopenharmony_ci{ 215562306a36Sopenharmony_ci /* PLL_CTRL feature needs to be enabled for fixed PHY modes (Non-Autoneg) only */ 215662306a36Sopenharmony_ci if (pdata->phy.autoneg != AUTONEG_DISABLE) 215762306a36Sopenharmony_ci return; 215862306a36Sopenharmony_ci 215962306a36Sopenharmony_ci XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_VEND2_PMA_MISC_CTRL0, 216062306a36Sopenharmony_ci XGBE_PMA_PLL_CTRL_MASK, 216162306a36Sopenharmony_ci enable ? XGBE_PMA_PLL_CTRL_ENABLE 216262306a36Sopenharmony_ci : XGBE_PMA_PLL_CTRL_DISABLE); 216362306a36Sopenharmony_ci 216462306a36Sopenharmony_ci /* Wait for command to complete */ 216562306a36Sopenharmony_ci usleep_range(100, 200); 216662306a36Sopenharmony_ci} 216762306a36Sopenharmony_ci 216862306a36Sopenharmony_cistatic void xgbe_phy_perform_ratechange(struct xgbe_prv_data *pdata, 216962306a36Sopenharmony_ci enum xgbe_mb_cmd cmd, enum xgbe_mb_subcmd sub_cmd) 217062306a36Sopenharmony_ci{ 217162306a36Sopenharmony_ci unsigned int s0 = 0; 217262306a36Sopenharmony_ci unsigned int wait; 217362306a36Sopenharmony_ci 217462306a36Sopenharmony_ci /* Disable PLL re-initialization during FW command processing */ 217562306a36Sopenharmony_ci xgbe_phy_pll_ctrl(pdata, false); 217662306a36Sopenharmony_ci 217762306a36Sopenharmony_ci /* Log if a previous command did not complete */ 217862306a36Sopenharmony_ci if (XP_IOREAD_BITS(pdata, XP_DRIVER_INT_RO, STATUS)) { 217962306a36Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, 218062306a36Sopenharmony_ci "firmware mailbox not ready for command\n"); 218162306a36Sopenharmony_ci xgbe_phy_rx_reset(pdata); 218262306a36Sopenharmony_ci } 218362306a36Sopenharmony_ci 218462306a36Sopenharmony_ci /* Construct the command */ 218562306a36Sopenharmony_ci XP_SET_BITS(s0, XP_DRIVER_SCRATCH_0, COMMAND, cmd); 218662306a36Sopenharmony_ci XP_SET_BITS(s0, XP_DRIVER_SCRATCH_0, SUB_COMMAND, sub_cmd); 218762306a36Sopenharmony_ci 218862306a36Sopenharmony_ci /* Issue the command */ 218962306a36Sopenharmony_ci XP_IOWRITE(pdata, XP_DRIVER_SCRATCH_0, s0); 219062306a36Sopenharmony_ci XP_IOWRITE(pdata, XP_DRIVER_SCRATCH_1, 0); 219162306a36Sopenharmony_ci XP_IOWRITE_BITS(pdata, XP_DRIVER_INT_REQ, REQUEST, 1); 219262306a36Sopenharmony_ci 219362306a36Sopenharmony_ci /* Wait for command to complete */ 219462306a36Sopenharmony_ci wait = XGBE_RATECHANGE_COUNT; 219562306a36Sopenharmony_ci while (wait--) { 219662306a36Sopenharmony_ci if (!XP_IOREAD_BITS(pdata, XP_DRIVER_INT_RO, STATUS)) 219762306a36Sopenharmony_ci goto do_rx_adaptation; 219862306a36Sopenharmony_ci 219962306a36Sopenharmony_ci usleep_range(1000, 2000); 220062306a36Sopenharmony_ci } 220162306a36Sopenharmony_ci 220262306a36Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, 220362306a36Sopenharmony_ci "firmware mailbox command did not complete\n"); 220462306a36Sopenharmony_ci 220562306a36Sopenharmony_ci /* Reset on error */ 220662306a36Sopenharmony_ci xgbe_phy_rx_reset(pdata); 220762306a36Sopenharmony_ci goto reenable_pll; 220862306a36Sopenharmony_ci 220962306a36Sopenharmony_cido_rx_adaptation: 221062306a36Sopenharmony_ci if (pdata->en_rx_adap && sub_cmd == XGBE_MB_SUBCMD_RX_ADAP && 221162306a36Sopenharmony_ci (cmd == XGBE_MB_CMD_SET_10G_KR || cmd == XGBE_MB_CMD_SET_10G_SFI)) { 221262306a36Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, 221362306a36Sopenharmony_ci "Enabling RX adaptation\n"); 221462306a36Sopenharmony_ci pdata->mode_set = true; 221562306a36Sopenharmony_ci xgbe_phy_rx_adaptation(pdata); 221662306a36Sopenharmony_ci /* return from here to avoid enabling PLL ctrl 221762306a36Sopenharmony_ci * during adaptation phase 221862306a36Sopenharmony_ci */ 221962306a36Sopenharmony_ci return; 222062306a36Sopenharmony_ci } 222162306a36Sopenharmony_ci 222262306a36Sopenharmony_cireenable_pll: 222362306a36Sopenharmony_ci /* Enable PLL re-initialization, not needed for PHY Power Off and RRC cmds */ 222462306a36Sopenharmony_ci if (cmd != XGBE_MB_CMD_POWER_OFF && 222562306a36Sopenharmony_ci cmd != XGBE_MB_CMD_RRC) 222662306a36Sopenharmony_ci xgbe_phy_pll_ctrl(pdata, true); 222762306a36Sopenharmony_ci} 222862306a36Sopenharmony_ci 222962306a36Sopenharmony_cistatic void xgbe_phy_rrc(struct xgbe_prv_data *pdata) 223062306a36Sopenharmony_ci{ 223162306a36Sopenharmony_ci /* Receiver Reset Cycle */ 223262306a36Sopenharmony_ci xgbe_phy_perform_ratechange(pdata, XGBE_MB_CMD_RRC, XGBE_MB_SUBCMD_NONE); 223362306a36Sopenharmony_ci 223462306a36Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, "receiver reset complete\n"); 223562306a36Sopenharmony_ci} 223662306a36Sopenharmony_ci 223762306a36Sopenharmony_cistatic void xgbe_phy_power_off(struct xgbe_prv_data *pdata) 223862306a36Sopenharmony_ci{ 223962306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 224062306a36Sopenharmony_ci 224162306a36Sopenharmony_ci /* Power off */ 224262306a36Sopenharmony_ci xgbe_phy_perform_ratechange(pdata, XGBE_MB_CMD_POWER_OFF, XGBE_MB_SUBCMD_NONE); 224362306a36Sopenharmony_ci 224462306a36Sopenharmony_ci phy_data->cur_mode = XGBE_MODE_UNKNOWN; 224562306a36Sopenharmony_ci 224662306a36Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, "phy powered off\n"); 224762306a36Sopenharmony_ci} 224862306a36Sopenharmony_ci 224962306a36Sopenharmony_cistatic bool enable_rx_adap(struct xgbe_prv_data *pdata, enum xgbe_mode mode) 225062306a36Sopenharmony_ci{ 225162306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 225262306a36Sopenharmony_ci unsigned int ver; 225362306a36Sopenharmony_ci 225462306a36Sopenharmony_ci /* Rx-Adaptation is not supported on older platforms(< 0x30H) */ 225562306a36Sopenharmony_ci ver = XGMAC_GET_BITS(pdata->hw_feat.version, MAC_VR, SNPSVER); 225662306a36Sopenharmony_ci if (ver < 0x30) 225762306a36Sopenharmony_ci return false; 225862306a36Sopenharmony_ci 225962306a36Sopenharmony_ci /* Re-driver models 4223 && 4227 do not support Rx-Adaptation */ 226062306a36Sopenharmony_ci if (phy_data->redrv && 226162306a36Sopenharmony_ci (phy_data->redrv_model == XGBE_PHY_REDRV_MODEL_4223 || 226262306a36Sopenharmony_ci phy_data->redrv_model == XGBE_PHY_REDRV_MODEL_4227)) 226362306a36Sopenharmony_ci return false; 226462306a36Sopenharmony_ci 226562306a36Sopenharmony_ci /* 10G KR mode with AN does not support Rx-Adaptation */ 226662306a36Sopenharmony_ci if (mode == XGBE_MODE_KR && 226762306a36Sopenharmony_ci phy_data->port_mode != XGBE_PORT_MODE_BACKPLANE_NO_AUTONEG) 226862306a36Sopenharmony_ci return false; 226962306a36Sopenharmony_ci 227062306a36Sopenharmony_ci pdata->en_rx_adap = 1; 227162306a36Sopenharmony_ci return true; 227262306a36Sopenharmony_ci} 227362306a36Sopenharmony_ci 227462306a36Sopenharmony_cistatic void xgbe_phy_sfi_mode(struct xgbe_prv_data *pdata) 227562306a36Sopenharmony_ci{ 227662306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 227762306a36Sopenharmony_ci 227862306a36Sopenharmony_ci xgbe_phy_set_redrv_mode(pdata); 227962306a36Sopenharmony_ci 228062306a36Sopenharmony_ci /* 10G/SFI */ 228162306a36Sopenharmony_ci if (phy_data->sfp_cable != XGBE_SFP_CABLE_PASSIVE) { 228262306a36Sopenharmony_ci pdata->en_rx_adap = 0; 228362306a36Sopenharmony_ci xgbe_phy_perform_ratechange(pdata, XGBE_MB_CMD_SET_10G_SFI, XGBE_MB_SUBCMD_ACTIVE); 228462306a36Sopenharmony_ci } else if ((phy_data->sfp_cable == XGBE_SFP_CABLE_PASSIVE) && 228562306a36Sopenharmony_ci (enable_rx_adap(pdata, XGBE_MODE_SFI))) { 228662306a36Sopenharmony_ci xgbe_phy_perform_ratechange(pdata, XGBE_MB_CMD_SET_10G_SFI, 228762306a36Sopenharmony_ci XGBE_MB_SUBCMD_RX_ADAP); 228862306a36Sopenharmony_ci } else { 228962306a36Sopenharmony_ci if (phy_data->sfp_cable_len <= 1) 229062306a36Sopenharmony_ci xgbe_phy_perform_ratechange(pdata, XGBE_MB_CMD_SET_10G_SFI, 229162306a36Sopenharmony_ci XGBE_MB_SUBCMD_PASSIVE_1M); 229262306a36Sopenharmony_ci else if (phy_data->sfp_cable_len <= 3) 229362306a36Sopenharmony_ci xgbe_phy_perform_ratechange(pdata, XGBE_MB_CMD_SET_10G_SFI, 229462306a36Sopenharmony_ci XGBE_MB_SUBCMD_PASSIVE_3M); 229562306a36Sopenharmony_ci else 229662306a36Sopenharmony_ci xgbe_phy_perform_ratechange(pdata, XGBE_MB_CMD_SET_10G_SFI, 229762306a36Sopenharmony_ci XGBE_MB_SUBCMD_PASSIVE_OTHER); 229862306a36Sopenharmony_ci } 229962306a36Sopenharmony_ci 230062306a36Sopenharmony_ci phy_data->cur_mode = XGBE_MODE_SFI; 230162306a36Sopenharmony_ci 230262306a36Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, "10GbE SFI mode set\n"); 230362306a36Sopenharmony_ci} 230462306a36Sopenharmony_ci 230562306a36Sopenharmony_cistatic void xgbe_phy_x_mode(struct xgbe_prv_data *pdata) 230662306a36Sopenharmony_ci{ 230762306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 230862306a36Sopenharmony_ci 230962306a36Sopenharmony_ci xgbe_phy_set_redrv_mode(pdata); 231062306a36Sopenharmony_ci 231162306a36Sopenharmony_ci /* 1G/X */ 231262306a36Sopenharmony_ci xgbe_phy_perform_ratechange(pdata, XGBE_MB_CMD_SET_1G, XGBE_MB_SUBCMD_1G_KX); 231362306a36Sopenharmony_ci 231462306a36Sopenharmony_ci phy_data->cur_mode = XGBE_MODE_X; 231562306a36Sopenharmony_ci 231662306a36Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, "1GbE X mode set\n"); 231762306a36Sopenharmony_ci} 231862306a36Sopenharmony_ci 231962306a36Sopenharmony_cistatic void xgbe_phy_sgmii_1000_mode(struct xgbe_prv_data *pdata) 232062306a36Sopenharmony_ci{ 232162306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 232262306a36Sopenharmony_ci 232362306a36Sopenharmony_ci xgbe_phy_set_redrv_mode(pdata); 232462306a36Sopenharmony_ci 232562306a36Sopenharmony_ci /* 1G/SGMII */ 232662306a36Sopenharmony_ci xgbe_phy_perform_ratechange(pdata, XGBE_MB_CMD_SET_1G, XGBE_MB_SUBCMD_1G_SGMII); 232762306a36Sopenharmony_ci 232862306a36Sopenharmony_ci phy_data->cur_mode = XGBE_MODE_SGMII_1000; 232962306a36Sopenharmony_ci 233062306a36Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, "1GbE SGMII mode set\n"); 233162306a36Sopenharmony_ci} 233262306a36Sopenharmony_ci 233362306a36Sopenharmony_cistatic void xgbe_phy_sgmii_100_mode(struct xgbe_prv_data *pdata) 233462306a36Sopenharmony_ci{ 233562306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 233662306a36Sopenharmony_ci 233762306a36Sopenharmony_ci xgbe_phy_set_redrv_mode(pdata); 233862306a36Sopenharmony_ci 233962306a36Sopenharmony_ci /* 100M/SGMII */ 234062306a36Sopenharmony_ci xgbe_phy_perform_ratechange(pdata, XGBE_MB_CMD_SET_1G, XGBE_MB_SUBCMD_100MBITS); 234162306a36Sopenharmony_ci 234262306a36Sopenharmony_ci phy_data->cur_mode = XGBE_MODE_SGMII_100; 234362306a36Sopenharmony_ci 234462306a36Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, "100MbE SGMII mode set\n"); 234562306a36Sopenharmony_ci} 234662306a36Sopenharmony_ci 234762306a36Sopenharmony_cistatic void xgbe_phy_sgmii_10_mode(struct xgbe_prv_data *pdata) 234862306a36Sopenharmony_ci{ 234962306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 235062306a36Sopenharmony_ci 235162306a36Sopenharmony_ci xgbe_phy_set_redrv_mode(pdata); 235262306a36Sopenharmony_ci 235362306a36Sopenharmony_ci /* 10M/SGMII */ 235462306a36Sopenharmony_ci xgbe_phy_perform_ratechange(pdata, XGBE_MB_CMD_SET_1G, XGBE_MB_SUBCMD_10MBITS); 235562306a36Sopenharmony_ci 235662306a36Sopenharmony_ci phy_data->cur_mode = XGBE_MODE_SGMII_10; 235762306a36Sopenharmony_ci 235862306a36Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, "10MbE SGMII mode set\n"); 235962306a36Sopenharmony_ci} 236062306a36Sopenharmony_ci 236162306a36Sopenharmony_cistatic void xgbe_phy_kr_mode(struct xgbe_prv_data *pdata) 236262306a36Sopenharmony_ci{ 236362306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 236462306a36Sopenharmony_ci 236562306a36Sopenharmony_ci xgbe_phy_set_redrv_mode(pdata); 236662306a36Sopenharmony_ci 236762306a36Sopenharmony_ci /* 10G/KR */ 236862306a36Sopenharmony_ci if (enable_rx_adap(pdata, XGBE_MODE_KR)) 236962306a36Sopenharmony_ci xgbe_phy_perform_ratechange(pdata, XGBE_MB_CMD_SET_10G_KR, 237062306a36Sopenharmony_ci XGBE_MB_SUBCMD_RX_ADAP); 237162306a36Sopenharmony_ci else 237262306a36Sopenharmony_ci xgbe_phy_perform_ratechange(pdata, XGBE_MB_CMD_SET_10G_KR, 237362306a36Sopenharmony_ci XGBE_MB_SUBCMD_NONE); 237462306a36Sopenharmony_ci 237562306a36Sopenharmony_ci phy_data->cur_mode = XGBE_MODE_KR; 237662306a36Sopenharmony_ci 237762306a36Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, "10GbE KR mode set\n"); 237862306a36Sopenharmony_ci} 237962306a36Sopenharmony_ci 238062306a36Sopenharmony_cistatic void xgbe_phy_kx_2500_mode(struct xgbe_prv_data *pdata) 238162306a36Sopenharmony_ci{ 238262306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 238362306a36Sopenharmony_ci 238462306a36Sopenharmony_ci xgbe_phy_set_redrv_mode(pdata); 238562306a36Sopenharmony_ci 238662306a36Sopenharmony_ci /* 2.5G/KX */ 238762306a36Sopenharmony_ci xgbe_phy_perform_ratechange(pdata, XGBE_MB_CMD_SET_2_5G, XGBE_MB_SUBCMD_NONE); 238862306a36Sopenharmony_ci 238962306a36Sopenharmony_ci phy_data->cur_mode = XGBE_MODE_KX_2500; 239062306a36Sopenharmony_ci 239162306a36Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, "2.5GbE KX mode set\n"); 239262306a36Sopenharmony_ci} 239362306a36Sopenharmony_ci 239462306a36Sopenharmony_cistatic void xgbe_phy_kx_1000_mode(struct xgbe_prv_data *pdata) 239562306a36Sopenharmony_ci{ 239662306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 239762306a36Sopenharmony_ci 239862306a36Sopenharmony_ci xgbe_phy_set_redrv_mode(pdata); 239962306a36Sopenharmony_ci 240062306a36Sopenharmony_ci /* 1G/KX */ 240162306a36Sopenharmony_ci xgbe_phy_perform_ratechange(pdata, XGBE_MB_CMD_SET_1G, XGBE_MB_SUBCMD_1G_KX); 240262306a36Sopenharmony_ci 240362306a36Sopenharmony_ci phy_data->cur_mode = XGBE_MODE_KX_1000; 240462306a36Sopenharmony_ci 240562306a36Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, "1GbE KX mode set\n"); 240662306a36Sopenharmony_ci} 240762306a36Sopenharmony_ci 240862306a36Sopenharmony_cistatic enum xgbe_mode xgbe_phy_cur_mode(struct xgbe_prv_data *pdata) 240962306a36Sopenharmony_ci{ 241062306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 241162306a36Sopenharmony_ci 241262306a36Sopenharmony_ci return phy_data->cur_mode; 241362306a36Sopenharmony_ci} 241462306a36Sopenharmony_ci 241562306a36Sopenharmony_cistatic enum xgbe_mode xgbe_phy_switch_baset_mode(struct xgbe_prv_data *pdata) 241662306a36Sopenharmony_ci{ 241762306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 241862306a36Sopenharmony_ci 241962306a36Sopenharmony_ci /* No switching if not 10GBase-T */ 242062306a36Sopenharmony_ci if (phy_data->port_mode != XGBE_PORT_MODE_10GBASE_T) 242162306a36Sopenharmony_ci return xgbe_phy_cur_mode(pdata); 242262306a36Sopenharmony_ci 242362306a36Sopenharmony_ci switch (xgbe_phy_cur_mode(pdata)) { 242462306a36Sopenharmony_ci case XGBE_MODE_SGMII_10: 242562306a36Sopenharmony_ci case XGBE_MODE_SGMII_100: 242662306a36Sopenharmony_ci case XGBE_MODE_SGMII_1000: 242762306a36Sopenharmony_ci return XGBE_MODE_KR; 242862306a36Sopenharmony_ci case XGBE_MODE_KX_2500: 242962306a36Sopenharmony_ci return XGBE_MODE_SGMII_1000; 243062306a36Sopenharmony_ci case XGBE_MODE_KR: 243162306a36Sopenharmony_ci default: 243262306a36Sopenharmony_ci return XGBE_MODE_KX_2500; 243362306a36Sopenharmony_ci } 243462306a36Sopenharmony_ci} 243562306a36Sopenharmony_ci 243662306a36Sopenharmony_cistatic enum xgbe_mode xgbe_phy_switch_bp_2500_mode(struct xgbe_prv_data *pdata) 243762306a36Sopenharmony_ci{ 243862306a36Sopenharmony_ci return XGBE_MODE_KX_2500; 243962306a36Sopenharmony_ci} 244062306a36Sopenharmony_ci 244162306a36Sopenharmony_cistatic enum xgbe_mode xgbe_phy_switch_bp_mode(struct xgbe_prv_data *pdata) 244262306a36Sopenharmony_ci{ 244362306a36Sopenharmony_ci /* If we are in KR switch to KX, and vice-versa */ 244462306a36Sopenharmony_ci switch (xgbe_phy_cur_mode(pdata)) { 244562306a36Sopenharmony_ci case XGBE_MODE_KX_1000: 244662306a36Sopenharmony_ci return XGBE_MODE_KR; 244762306a36Sopenharmony_ci case XGBE_MODE_KR: 244862306a36Sopenharmony_ci default: 244962306a36Sopenharmony_ci return XGBE_MODE_KX_1000; 245062306a36Sopenharmony_ci } 245162306a36Sopenharmony_ci} 245262306a36Sopenharmony_ci 245362306a36Sopenharmony_cistatic enum xgbe_mode xgbe_phy_switch_mode(struct xgbe_prv_data *pdata) 245462306a36Sopenharmony_ci{ 245562306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 245662306a36Sopenharmony_ci 245762306a36Sopenharmony_ci switch (phy_data->port_mode) { 245862306a36Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE: 245962306a36Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE_NO_AUTONEG: 246062306a36Sopenharmony_ci return xgbe_phy_switch_bp_mode(pdata); 246162306a36Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE_2500: 246262306a36Sopenharmony_ci return xgbe_phy_switch_bp_2500_mode(pdata); 246362306a36Sopenharmony_ci case XGBE_PORT_MODE_1000BASE_T: 246462306a36Sopenharmony_ci case XGBE_PORT_MODE_NBASE_T: 246562306a36Sopenharmony_ci case XGBE_PORT_MODE_10GBASE_T: 246662306a36Sopenharmony_ci return xgbe_phy_switch_baset_mode(pdata); 246762306a36Sopenharmony_ci case XGBE_PORT_MODE_1000BASE_X: 246862306a36Sopenharmony_ci case XGBE_PORT_MODE_10GBASE_R: 246962306a36Sopenharmony_ci case XGBE_PORT_MODE_SFP: 247062306a36Sopenharmony_ci /* No switching, so just return current mode */ 247162306a36Sopenharmony_ci return xgbe_phy_cur_mode(pdata); 247262306a36Sopenharmony_ci default: 247362306a36Sopenharmony_ci return XGBE_MODE_UNKNOWN; 247462306a36Sopenharmony_ci } 247562306a36Sopenharmony_ci} 247662306a36Sopenharmony_ci 247762306a36Sopenharmony_cistatic enum xgbe_mode xgbe_phy_get_basex_mode(struct xgbe_phy_data *phy_data, 247862306a36Sopenharmony_ci int speed) 247962306a36Sopenharmony_ci{ 248062306a36Sopenharmony_ci switch (speed) { 248162306a36Sopenharmony_ci case SPEED_1000: 248262306a36Sopenharmony_ci return XGBE_MODE_X; 248362306a36Sopenharmony_ci case SPEED_10000: 248462306a36Sopenharmony_ci return XGBE_MODE_KR; 248562306a36Sopenharmony_ci default: 248662306a36Sopenharmony_ci return XGBE_MODE_UNKNOWN; 248762306a36Sopenharmony_ci } 248862306a36Sopenharmony_ci} 248962306a36Sopenharmony_ci 249062306a36Sopenharmony_cistatic enum xgbe_mode xgbe_phy_get_baset_mode(struct xgbe_phy_data *phy_data, 249162306a36Sopenharmony_ci int speed) 249262306a36Sopenharmony_ci{ 249362306a36Sopenharmony_ci switch (speed) { 249462306a36Sopenharmony_ci case SPEED_10: 249562306a36Sopenharmony_ci return XGBE_MODE_SGMII_10; 249662306a36Sopenharmony_ci case SPEED_100: 249762306a36Sopenharmony_ci return XGBE_MODE_SGMII_100; 249862306a36Sopenharmony_ci case SPEED_1000: 249962306a36Sopenharmony_ci return XGBE_MODE_SGMII_1000; 250062306a36Sopenharmony_ci case SPEED_2500: 250162306a36Sopenharmony_ci return XGBE_MODE_KX_2500; 250262306a36Sopenharmony_ci case SPEED_10000: 250362306a36Sopenharmony_ci return XGBE_MODE_KR; 250462306a36Sopenharmony_ci default: 250562306a36Sopenharmony_ci return XGBE_MODE_UNKNOWN; 250662306a36Sopenharmony_ci } 250762306a36Sopenharmony_ci} 250862306a36Sopenharmony_ci 250962306a36Sopenharmony_cistatic enum xgbe_mode xgbe_phy_get_sfp_mode(struct xgbe_phy_data *phy_data, 251062306a36Sopenharmony_ci int speed) 251162306a36Sopenharmony_ci{ 251262306a36Sopenharmony_ci switch (speed) { 251362306a36Sopenharmony_ci case SPEED_10: 251462306a36Sopenharmony_ci return XGBE_MODE_SGMII_10; 251562306a36Sopenharmony_ci case SPEED_100: 251662306a36Sopenharmony_ci return XGBE_MODE_SGMII_100; 251762306a36Sopenharmony_ci case SPEED_1000: 251862306a36Sopenharmony_ci if (phy_data->sfp_base == XGBE_SFP_BASE_1000_T) 251962306a36Sopenharmony_ci return XGBE_MODE_SGMII_1000; 252062306a36Sopenharmony_ci else 252162306a36Sopenharmony_ci return XGBE_MODE_X; 252262306a36Sopenharmony_ci case SPEED_10000: 252362306a36Sopenharmony_ci case SPEED_UNKNOWN: 252462306a36Sopenharmony_ci return XGBE_MODE_SFI; 252562306a36Sopenharmony_ci default: 252662306a36Sopenharmony_ci return XGBE_MODE_UNKNOWN; 252762306a36Sopenharmony_ci } 252862306a36Sopenharmony_ci} 252962306a36Sopenharmony_ci 253062306a36Sopenharmony_cistatic enum xgbe_mode xgbe_phy_get_bp_2500_mode(int speed) 253162306a36Sopenharmony_ci{ 253262306a36Sopenharmony_ci switch (speed) { 253362306a36Sopenharmony_ci case SPEED_2500: 253462306a36Sopenharmony_ci return XGBE_MODE_KX_2500; 253562306a36Sopenharmony_ci default: 253662306a36Sopenharmony_ci return XGBE_MODE_UNKNOWN; 253762306a36Sopenharmony_ci } 253862306a36Sopenharmony_ci} 253962306a36Sopenharmony_ci 254062306a36Sopenharmony_cistatic enum xgbe_mode xgbe_phy_get_bp_mode(int speed) 254162306a36Sopenharmony_ci{ 254262306a36Sopenharmony_ci switch (speed) { 254362306a36Sopenharmony_ci case SPEED_1000: 254462306a36Sopenharmony_ci return XGBE_MODE_KX_1000; 254562306a36Sopenharmony_ci case SPEED_10000: 254662306a36Sopenharmony_ci return XGBE_MODE_KR; 254762306a36Sopenharmony_ci default: 254862306a36Sopenharmony_ci return XGBE_MODE_UNKNOWN; 254962306a36Sopenharmony_ci } 255062306a36Sopenharmony_ci} 255162306a36Sopenharmony_ci 255262306a36Sopenharmony_cistatic enum xgbe_mode xgbe_phy_get_mode(struct xgbe_prv_data *pdata, 255362306a36Sopenharmony_ci int speed) 255462306a36Sopenharmony_ci{ 255562306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 255662306a36Sopenharmony_ci 255762306a36Sopenharmony_ci switch (phy_data->port_mode) { 255862306a36Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE: 255962306a36Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE_NO_AUTONEG: 256062306a36Sopenharmony_ci return xgbe_phy_get_bp_mode(speed); 256162306a36Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE_2500: 256262306a36Sopenharmony_ci return xgbe_phy_get_bp_2500_mode(speed); 256362306a36Sopenharmony_ci case XGBE_PORT_MODE_1000BASE_T: 256462306a36Sopenharmony_ci case XGBE_PORT_MODE_NBASE_T: 256562306a36Sopenharmony_ci case XGBE_PORT_MODE_10GBASE_T: 256662306a36Sopenharmony_ci return xgbe_phy_get_baset_mode(phy_data, speed); 256762306a36Sopenharmony_ci case XGBE_PORT_MODE_1000BASE_X: 256862306a36Sopenharmony_ci case XGBE_PORT_MODE_10GBASE_R: 256962306a36Sopenharmony_ci return xgbe_phy_get_basex_mode(phy_data, speed); 257062306a36Sopenharmony_ci case XGBE_PORT_MODE_SFP: 257162306a36Sopenharmony_ci return xgbe_phy_get_sfp_mode(phy_data, speed); 257262306a36Sopenharmony_ci default: 257362306a36Sopenharmony_ci return XGBE_MODE_UNKNOWN; 257462306a36Sopenharmony_ci } 257562306a36Sopenharmony_ci} 257662306a36Sopenharmony_ci 257762306a36Sopenharmony_cistatic void xgbe_phy_set_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode) 257862306a36Sopenharmony_ci{ 257962306a36Sopenharmony_ci switch (mode) { 258062306a36Sopenharmony_ci case XGBE_MODE_KX_1000: 258162306a36Sopenharmony_ci xgbe_phy_kx_1000_mode(pdata); 258262306a36Sopenharmony_ci break; 258362306a36Sopenharmony_ci case XGBE_MODE_KX_2500: 258462306a36Sopenharmony_ci xgbe_phy_kx_2500_mode(pdata); 258562306a36Sopenharmony_ci break; 258662306a36Sopenharmony_ci case XGBE_MODE_KR: 258762306a36Sopenharmony_ci xgbe_phy_kr_mode(pdata); 258862306a36Sopenharmony_ci break; 258962306a36Sopenharmony_ci case XGBE_MODE_SGMII_10: 259062306a36Sopenharmony_ci xgbe_phy_sgmii_10_mode(pdata); 259162306a36Sopenharmony_ci break; 259262306a36Sopenharmony_ci case XGBE_MODE_SGMII_100: 259362306a36Sopenharmony_ci xgbe_phy_sgmii_100_mode(pdata); 259462306a36Sopenharmony_ci break; 259562306a36Sopenharmony_ci case XGBE_MODE_SGMII_1000: 259662306a36Sopenharmony_ci xgbe_phy_sgmii_1000_mode(pdata); 259762306a36Sopenharmony_ci break; 259862306a36Sopenharmony_ci case XGBE_MODE_X: 259962306a36Sopenharmony_ci xgbe_phy_x_mode(pdata); 260062306a36Sopenharmony_ci break; 260162306a36Sopenharmony_ci case XGBE_MODE_SFI: 260262306a36Sopenharmony_ci xgbe_phy_sfi_mode(pdata); 260362306a36Sopenharmony_ci break; 260462306a36Sopenharmony_ci default: 260562306a36Sopenharmony_ci break; 260662306a36Sopenharmony_ci } 260762306a36Sopenharmony_ci} 260862306a36Sopenharmony_ci 260962306a36Sopenharmony_cistatic bool xgbe_phy_check_mode(struct xgbe_prv_data *pdata, 261062306a36Sopenharmony_ci enum xgbe_mode mode, bool advert) 261162306a36Sopenharmony_ci{ 261262306a36Sopenharmony_ci if (pdata->phy.autoneg == AUTONEG_ENABLE) { 261362306a36Sopenharmony_ci return advert; 261462306a36Sopenharmony_ci } else { 261562306a36Sopenharmony_ci enum xgbe_mode cur_mode; 261662306a36Sopenharmony_ci 261762306a36Sopenharmony_ci cur_mode = xgbe_phy_get_mode(pdata, pdata->phy.speed); 261862306a36Sopenharmony_ci if (cur_mode == mode) 261962306a36Sopenharmony_ci return true; 262062306a36Sopenharmony_ci } 262162306a36Sopenharmony_ci 262262306a36Sopenharmony_ci return false; 262362306a36Sopenharmony_ci} 262462306a36Sopenharmony_ci 262562306a36Sopenharmony_cistatic bool xgbe_phy_use_basex_mode(struct xgbe_prv_data *pdata, 262662306a36Sopenharmony_ci enum xgbe_mode mode) 262762306a36Sopenharmony_ci{ 262862306a36Sopenharmony_ci struct ethtool_link_ksettings *lks = &pdata->phy.lks; 262962306a36Sopenharmony_ci 263062306a36Sopenharmony_ci switch (mode) { 263162306a36Sopenharmony_ci case XGBE_MODE_X: 263262306a36Sopenharmony_ci return xgbe_phy_check_mode(pdata, mode, 263362306a36Sopenharmony_ci XGBE_ADV(lks, 1000baseX_Full)); 263462306a36Sopenharmony_ci case XGBE_MODE_KR: 263562306a36Sopenharmony_ci return xgbe_phy_check_mode(pdata, mode, 263662306a36Sopenharmony_ci XGBE_ADV(lks, 10000baseKR_Full)); 263762306a36Sopenharmony_ci default: 263862306a36Sopenharmony_ci return false; 263962306a36Sopenharmony_ci } 264062306a36Sopenharmony_ci} 264162306a36Sopenharmony_ci 264262306a36Sopenharmony_cistatic bool xgbe_phy_use_baset_mode(struct xgbe_prv_data *pdata, 264362306a36Sopenharmony_ci enum xgbe_mode mode) 264462306a36Sopenharmony_ci{ 264562306a36Sopenharmony_ci struct ethtool_link_ksettings *lks = &pdata->phy.lks; 264662306a36Sopenharmony_ci 264762306a36Sopenharmony_ci switch (mode) { 264862306a36Sopenharmony_ci case XGBE_MODE_SGMII_10: 264962306a36Sopenharmony_ci return xgbe_phy_check_mode(pdata, mode, 265062306a36Sopenharmony_ci XGBE_ADV(lks, 10baseT_Full)); 265162306a36Sopenharmony_ci case XGBE_MODE_SGMII_100: 265262306a36Sopenharmony_ci return xgbe_phy_check_mode(pdata, mode, 265362306a36Sopenharmony_ci XGBE_ADV(lks, 100baseT_Full)); 265462306a36Sopenharmony_ci case XGBE_MODE_SGMII_1000: 265562306a36Sopenharmony_ci return xgbe_phy_check_mode(pdata, mode, 265662306a36Sopenharmony_ci XGBE_ADV(lks, 1000baseT_Full)); 265762306a36Sopenharmony_ci case XGBE_MODE_KX_2500: 265862306a36Sopenharmony_ci return xgbe_phy_check_mode(pdata, mode, 265962306a36Sopenharmony_ci XGBE_ADV(lks, 2500baseT_Full)); 266062306a36Sopenharmony_ci case XGBE_MODE_KR: 266162306a36Sopenharmony_ci return xgbe_phy_check_mode(pdata, mode, 266262306a36Sopenharmony_ci XGBE_ADV(lks, 10000baseT_Full)); 266362306a36Sopenharmony_ci default: 266462306a36Sopenharmony_ci return false; 266562306a36Sopenharmony_ci } 266662306a36Sopenharmony_ci} 266762306a36Sopenharmony_ci 266862306a36Sopenharmony_cistatic bool xgbe_phy_use_sfp_mode(struct xgbe_prv_data *pdata, 266962306a36Sopenharmony_ci enum xgbe_mode mode) 267062306a36Sopenharmony_ci{ 267162306a36Sopenharmony_ci struct ethtool_link_ksettings *lks = &pdata->phy.lks; 267262306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 267362306a36Sopenharmony_ci 267462306a36Sopenharmony_ci switch (mode) { 267562306a36Sopenharmony_ci case XGBE_MODE_X: 267662306a36Sopenharmony_ci if (phy_data->sfp_base == XGBE_SFP_BASE_1000_T) 267762306a36Sopenharmony_ci return false; 267862306a36Sopenharmony_ci return xgbe_phy_check_mode(pdata, mode, 267962306a36Sopenharmony_ci XGBE_ADV(lks, 1000baseX_Full)); 268062306a36Sopenharmony_ci case XGBE_MODE_SGMII_10: 268162306a36Sopenharmony_ci if (phy_data->sfp_base != XGBE_SFP_BASE_1000_T) 268262306a36Sopenharmony_ci return false; 268362306a36Sopenharmony_ci return xgbe_phy_check_mode(pdata, mode, 268462306a36Sopenharmony_ci XGBE_ADV(lks, 10baseT_Full)); 268562306a36Sopenharmony_ci case XGBE_MODE_SGMII_100: 268662306a36Sopenharmony_ci if (phy_data->sfp_base != XGBE_SFP_BASE_1000_T) 268762306a36Sopenharmony_ci return false; 268862306a36Sopenharmony_ci return xgbe_phy_check_mode(pdata, mode, 268962306a36Sopenharmony_ci XGBE_ADV(lks, 100baseT_Full)); 269062306a36Sopenharmony_ci case XGBE_MODE_SGMII_1000: 269162306a36Sopenharmony_ci if (phy_data->sfp_base != XGBE_SFP_BASE_1000_T) 269262306a36Sopenharmony_ci return false; 269362306a36Sopenharmony_ci return xgbe_phy_check_mode(pdata, mode, 269462306a36Sopenharmony_ci XGBE_ADV(lks, 1000baseT_Full)); 269562306a36Sopenharmony_ci case XGBE_MODE_SFI: 269662306a36Sopenharmony_ci if (phy_data->sfp_mod_absent) 269762306a36Sopenharmony_ci return true; 269862306a36Sopenharmony_ci return xgbe_phy_check_mode(pdata, mode, 269962306a36Sopenharmony_ci XGBE_ADV(lks, 10000baseSR_Full) || 270062306a36Sopenharmony_ci XGBE_ADV(lks, 10000baseLR_Full) || 270162306a36Sopenharmony_ci XGBE_ADV(lks, 10000baseLRM_Full) || 270262306a36Sopenharmony_ci XGBE_ADV(lks, 10000baseER_Full) || 270362306a36Sopenharmony_ci XGBE_ADV(lks, 10000baseCR_Full)); 270462306a36Sopenharmony_ci default: 270562306a36Sopenharmony_ci return false; 270662306a36Sopenharmony_ci } 270762306a36Sopenharmony_ci} 270862306a36Sopenharmony_ci 270962306a36Sopenharmony_cistatic bool xgbe_phy_use_bp_2500_mode(struct xgbe_prv_data *pdata, 271062306a36Sopenharmony_ci enum xgbe_mode mode) 271162306a36Sopenharmony_ci{ 271262306a36Sopenharmony_ci struct ethtool_link_ksettings *lks = &pdata->phy.lks; 271362306a36Sopenharmony_ci 271462306a36Sopenharmony_ci switch (mode) { 271562306a36Sopenharmony_ci case XGBE_MODE_KX_2500: 271662306a36Sopenharmony_ci return xgbe_phy_check_mode(pdata, mode, 271762306a36Sopenharmony_ci XGBE_ADV(lks, 2500baseX_Full)); 271862306a36Sopenharmony_ci default: 271962306a36Sopenharmony_ci return false; 272062306a36Sopenharmony_ci } 272162306a36Sopenharmony_ci} 272262306a36Sopenharmony_ci 272362306a36Sopenharmony_cistatic bool xgbe_phy_use_bp_mode(struct xgbe_prv_data *pdata, 272462306a36Sopenharmony_ci enum xgbe_mode mode) 272562306a36Sopenharmony_ci{ 272662306a36Sopenharmony_ci struct ethtool_link_ksettings *lks = &pdata->phy.lks; 272762306a36Sopenharmony_ci 272862306a36Sopenharmony_ci switch (mode) { 272962306a36Sopenharmony_ci case XGBE_MODE_KX_1000: 273062306a36Sopenharmony_ci return xgbe_phy_check_mode(pdata, mode, 273162306a36Sopenharmony_ci XGBE_ADV(lks, 1000baseKX_Full)); 273262306a36Sopenharmony_ci case XGBE_MODE_KR: 273362306a36Sopenharmony_ci return xgbe_phy_check_mode(pdata, mode, 273462306a36Sopenharmony_ci XGBE_ADV(lks, 10000baseKR_Full)); 273562306a36Sopenharmony_ci default: 273662306a36Sopenharmony_ci return false; 273762306a36Sopenharmony_ci } 273862306a36Sopenharmony_ci} 273962306a36Sopenharmony_ci 274062306a36Sopenharmony_cistatic bool xgbe_phy_use_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode) 274162306a36Sopenharmony_ci{ 274262306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 274362306a36Sopenharmony_ci 274462306a36Sopenharmony_ci switch (phy_data->port_mode) { 274562306a36Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE: 274662306a36Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE_NO_AUTONEG: 274762306a36Sopenharmony_ci return xgbe_phy_use_bp_mode(pdata, mode); 274862306a36Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE_2500: 274962306a36Sopenharmony_ci return xgbe_phy_use_bp_2500_mode(pdata, mode); 275062306a36Sopenharmony_ci case XGBE_PORT_MODE_1000BASE_T: 275162306a36Sopenharmony_ci case XGBE_PORT_MODE_NBASE_T: 275262306a36Sopenharmony_ci case XGBE_PORT_MODE_10GBASE_T: 275362306a36Sopenharmony_ci return xgbe_phy_use_baset_mode(pdata, mode); 275462306a36Sopenharmony_ci case XGBE_PORT_MODE_1000BASE_X: 275562306a36Sopenharmony_ci case XGBE_PORT_MODE_10GBASE_R: 275662306a36Sopenharmony_ci return xgbe_phy_use_basex_mode(pdata, mode); 275762306a36Sopenharmony_ci case XGBE_PORT_MODE_SFP: 275862306a36Sopenharmony_ci return xgbe_phy_use_sfp_mode(pdata, mode); 275962306a36Sopenharmony_ci default: 276062306a36Sopenharmony_ci return false; 276162306a36Sopenharmony_ci } 276262306a36Sopenharmony_ci} 276362306a36Sopenharmony_ci 276462306a36Sopenharmony_cistatic bool xgbe_phy_valid_speed_basex_mode(struct xgbe_phy_data *phy_data, 276562306a36Sopenharmony_ci int speed) 276662306a36Sopenharmony_ci{ 276762306a36Sopenharmony_ci switch (speed) { 276862306a36Sopenharmony_ci case SPEED_1000: 276962306a36Sopenharmony_ci return (phy_data->port_mode == XGBE_PORT_MODE_1000BASE_X); 277062306a36Sopenharmony_ci case SPEED_10000: 277162306a36Sopenharmony_ci return (phy_data->port_mode == XGBE_PORT_MODE_10GBASE_R); 277262306a36Sopenharmony_ci default: 277362306a36Sopenharmony_ci return false; 277462306a36Sopenharmony_ci } 277562306a36Sopenharmony_ci} 277662306a36Sopenharmony_ci 277762306a36Sopenharmony_cistatic bool xgbe_phy_valid_speed_baset_mode(struct xgbe_prv_data *pdata, 277862306a36Sopenharmony_ci int speed) 277962306a36Sopenharmony_ci{ 278062306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 278162306a36Sopenharmony_ci unsigned int ver; 278262306a36Sopenharmony_ci 278362306a36Sopenharmony_ci switch (speed) { 278462306a36Sopenharmony_ci case SPEED_10: 278562306a36Sopenharmony_ci /* Supported in ver 21H and ver >= 30H */ 278662306a36Sopenharmony_ci ver = XGMAC_GET_BITS(pdata->hw_feat.version, MAC_VR, SNPSVER); 278762306a36Sopenharmony_ci return (ver == 0x21 || ver >= 0x30); 278862306a36Sopenharmony_ci case SPEED_100: 278962306a36Sopenharmony_ci case SPEED_1000: 279062306a36Sopenharmony_ci return true; 279162306a36Sopenharmony_ci case SPEED_2500: 279262306a36Sopenharmony_ci return ((phy_data->port_mode == XGBE_PORT_MODE_10GBASE_T) || 279362306a36Sopenharmony_ci (phy_data->port_mode == XGBE_PORT_MODE_NBASE_T)); 279462306a36Sopenharmony_ci case SPEED_10000: 279562306a36Sopenharmony_ci return (phy_data->port_mode == XGBE_PORT_MODE_10GBASE_T); 279662306a36Sopenharmony_ci default: 279762306a36Sopenharmony_ci return false; 279862306a36Sopenharmony_ci } 279962306a36Sopenharmony_ci} 280062306a36Sopenharmony_ci 280162306a36Sopenharmony_cistatic bool xgbe_phy_valid_speed_sfp_mode(struct xgbe_prv_data *pdata, 280262306a36Sopenharmony_ci int speed) 280362306a36Sopenharmony_ci{ 280462306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 280562306a36Sopenharmony_ci unsigned int ver; 280662306a36Sopenharmony_ci 280762306a36Sopenharmony_ci switch (speed) { 280862306a36Sopenharmony_ci case SPEED_10: 280962306a36Sopenharmony_ci /* Supported in ver 21H and ver >= 30H */ 281062306a36Sopenharmony_ci ver = XGMAC_GET_BITS(pdata->hw_feat.version, MAC_VR, SNPSVER); 281162306a36Sopenharmony_ci return ((ver == 0x21 || ver >= 0x30) && 281262306a36Sopenharmony_ci (phy_data->sfp_speed == XGBE_SFP_SPEED_100_1000)); 281362306a36Sopenharmony_ci case SPEED_100: 281462306a36Sopenharmony_ci return (phy_data->sfp_speed == XGBE_SFP_SPEED_100_1000); 281562306a36Sopenharmony_ci case SPEED_1000: 281662306a36Sopenharmony_ci return ((phy_data->sfp_speed == XGBE_SFP_SPEED_100_1000) || 281762306a36Sopenharmony_ci (phy_data->sfp_speed == XGBE_SFP_SPEED_1000)); 281862306a36Sopenharmony_ci case SPEED_10000: 281962306a36Sopenharmony_ci return (phy_data->sfp_speed == XGBE_SFP_SPEED_10000); 282062306a36Sopenharmony_ci default: 282162306a36Sopenharmony_ci return false; 282262306a36Sopenharmony_ci } 282362306a36Sopenharmony_ci} 282462306a36Sopenharmony_ci 282562306a36Sopenharmony_cistatic bool xgbe_phy_valid_speed_bp_2500_mode(int speed) 282662306a36Sopenharmony_ci{ 282762306a36Sopenharmony_ci switch (speed) { 282862306a36Sopenharmony_ci case SPEED_2500: 282962306a36Sopenharmony_ci return true; 283062306a36Sopenharmony_ci default: 283162306a36Sopenharmony_ci return false; 283262306a36Sopenharmony_ci } 283362306a36Sopenharmony_ci} 283462306a36Sopenharmony_ci 283562306a36Sopenharmony_cistatic bool xgbe_phy_valid_speed_bp_mode(int speed) 283662306a36Sopenharmony_ci{ 283762306a36Sopenharmony_ci switch (speed) { 283862306a36Sopenharmony_ci case SPEED_1000: 283962306a36Sopenharmony_ci case SPEED_10000: 284062306a36Sopenharmony_ci return true; 284162306a36Sopenharmony_ci default: 284262306a36Sopenharmony_ci return false; 284362306a36Sopenharmony_ci } 284462306a36Sopenharmony_ci} 284562306a36Sopenharmony_ci 284662306a36Sopenharmony_cistatic bool xgbe_phy_valid_speed(struct xgbe_prv_data *pdata, int speed) 284762306a36Sopenharmony_ci{ 284862306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 284962306a36Sopenharmony_ci 285062306a36Sopenharmony_ci switch (phy_data->port_mode) { 285162306a36Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE: 285262306a36Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE_NO_AUTONEG: 285362306a36Sopenharmony_ci return xgbe_phy_valid_speed_bp_mode(speed); 285462306a36Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE_2500: 285562306a36Sopenharmony_ci return xgbe_phy_valid_speed_bp_2500_mode(speed); 285662306a36Sopenharmony_ci case XGBE_PORT_MODE_1000BASE_T: 285762306a36Sopenharmony_ci case XGBE_PORT_MODE_NBASE_T: 285862306a36Sopenharmony_ci case XGBE_PORT_MODE_10GBASE_T: 285962306a36Sopenharmony_ci return xgbe_phy_valid_speed_baset_mode(pdata, speed); 286062306a36Sopenharmony_ci case XGBE_PORT_MODE_1000BASE_X: 286162306a36Sopenharmony_ci case XGBE_PORT_MODE_10GBASE_R: 286262306a36Sopenharmony_ci return xgbe_phy_valid_speed_basex_mode(phy_data, speed); 286362306a36Sopenharmony_ci case XGBE_PORT_MODE_SFP: 286462306a36Sopenharmony_ci return xgbe_phy_valid_speed_sfp_mode(pdata, speed); 286562306a36Sopenharmony_ci default: 286662306a36Sopenharmony_ci return false; 286762306a36Sopenharmony_ci } 286862306a36Sopenharmony_ci} 286962306a36Sopenharmony_ci 287062306a36Sopenharmony_cistatic int xgbe_phy_link_status(struct xgbe_prv_data *pdata, int *an_restart) 287162306a36Sopenharmony_ci{ 287262306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 287362306a36Sopenharmony_ci unsigned int reg; 287462306a36Sopenharmony_ci int ret; 287562306a36Sopenharmony_ci 287662306a36Sopenharmony_ci *an_restart = 0; 287762306a36Sopenharmony_ci 287862306a36Sopenharmony_ci if (phy_data->port_mode == XGBE_PORT_MODE_SFP) { 287962306a36Sopenharmony_ci /* Check SFP signals */ 288062306a36Sopenharmony_ci xgbe_phy_sfp_detect(pdata); 288162306a36Sopenharmony_ci 288262306a36Sopenharmony_ci if (phy_data->sfp_changed) { 288362306a36Sopenharmony_ci *an_restart = 1; 288462306a36Sopenharmony_ci return 0; 288562306a36Sopenharmony_ci } 288662306a36Sopenharmony_ci 288762306a36Sopenharmony_ci if (phy_data->sfp_mod_absent || phy_data->sfp_rx_los) { 288862306a36Sopenharmony_ci if (pdata->en_rx_adap) 288962306a36Sopenharmony_ci pdata->rx_adapt_done = false; 289062306a36Sopenharmony_ci return 0; 289162306a36Sopenharmony_ci } 289262306a36Sopenharmony_ci } 289362306a36Sopenharmony_ci 289462306a36Sopenharmony_ci if (phy_data->phydev) { 289562306a36Sopenharmony_ci /* Check external PHY */ 289662306a36Sopenharmony_ci ret = phy_read_status(phy_data->phydev); 289762306a36Sopenharmony_ci if (ret < 0) 289862306a36Sopenharmony_ci return 0; 289962306a36Sopenharmony_ci 290062306a36Sopenharmony_ci if ((pdata->phy.autoneg == AUTONEG_ENABLE) && 290162306a36Sopenharmony_ci !phy_aneg_done(phy_data->phydev)) 290262306a36Sopenharmony_ci return 0; 290362306a36Sopenharmony_ci 290462306a36Sopenharmony_ci if (!phy_data->phydev->link) 290562306a36Sopenharmony_ci return 0; 290662306a36Sopenharmony_ci } 290762306a36Sopenharmony_ci 290862306a36Sopenharmony_ci /* Link status is latched low, so read once to clear 290962306a36Sopenharmony_ci * and then read again to get current state 291062306a36Sopenharmony_ci */ 291162306a36Sopenharmony_ci reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1); 291262306a36Sopenharmony_ci reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1); 291362306a36Sopenharmony_ci 291462306a36Sopenharmony_ci if (pdata->en_rx_adap) { 291562306a36Sopenharmony_ci /* if the link is available and adaptation is done, 291662306a36Sopenharmony_ci * declare link up 291762306a36Sopenharmony_ci */ 291862306a36Sopenharmony_ci if ((reg & MDIO_STAT1_LSTATUS) && pdata->rx_adapt_done) 291962306a36Sopenharmony_ci return 1; 292062306a36Sopenharmony_ci /* If either link is not available or adaptation is not done, 292162306a36Sopenharmony_ci * retrigger the adaptation logic. (if the mode is not set, 292262306a36Sopenharmony_ci * then issue mailbox command first) 292362306a36Sopenharmony_ci */ 292462306a36Sopenharmony_ci if (pdata->mode_set) { 292562306a36Sopenharmony_ci xgbe_phy_rx_adaptation(pdata); 292662306a36Sopenharmony_ci } else { 292762306a36Sopenharmony_ci pdata->rx_adapt_done = false; 292862306a36Sopenharmony_ci xgbe_phy_set_mode(pdata, phy_data->cur_mode); 292962306a36Sopenharmony_ci } 293062306a36Sopenharmony_ci 293162306a36Sopenharmony_ci /* check again for the link and adaptation status */ 293262306a36Sopenharmony_ci reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1); 293362306a36Sopenharmony_ci if ((reg & MDIO_STAT1_LSTATUS) && pdata->rx_adapt_done) 293462306a36Sopenharmony_ci return 1; 293562306a36Sopenharmony_ci } else if (reg & MDIO_STAT1_LSTATUS) 293662306a36Sopenharmony_ci return 1; 293762306a36Sopenharmony_ci 293862306a36Sopenharmony_ci if (pdata->phy.autoneg == AUTONEG_ENABLE && 293962306a36Sopenharmony_ci phy_data->port_mode == XGBE_PORT_MODE_BACKPLANE) { 294062306a36Sopenharmony_ci if (!test_bit(XGBE_LINK_INIT, &pdata->dev_state)) { 294162306a36Sopenharmony_ci netif_carrier_off(pdata->netdev); 294262306a36Sopenharmony_ci *an_restart = 1; 294362306a36Sopenharmony_ci } 294462306a36Sopenharmony_ci } 294562306a36Sopenharmony_ci 294662306a36Sopenharmony_ci /* No link, attempt a receiver reset cycle */ 294762306a36Sopenharmony_ci if (pdata->vdata->enable_rrc && phy_data->rrc_count++ > XGBE_RRC_FREQUENCY) { 294862306a36Sopenharmony_ci phy_data->rrc_count = 0; 294962306a36Sopenharmony_ci xgbe_phy_rrc(pdata); 295062306a36Sopenharmony_ci } 295162306a36Sopenharmony_ci 295262306a36Sopenharmony_ci return 0; 295362306a36Sopenharmony_ci} 295462306a36Sopenharmony_ci 295562306a36Sopenharmony_cistatic void xgbe_phy_sfp_gpio_setup(struct xgbe_prv_data *pdata) 295662306a36Sopenharmony_ci{ 295762306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 295862306a36Sopenharmony_ci 295962306a36Sopenharmony_ci phy_data->sfp_gpio_address = XGBE_GPIO_ADDRESS_PCA9555 + 296062306a36Sopenharmony_ci XP_GET_BITS(pdata->pp3, XP_PROP_3, 296162306a36Sopenharmony_ci GPIO_ADDR); 296262306a36Sopenharmony_ci 296362306a36Sopenharmony_ci phy_data->sfp_gpio_mask = XP_GET_BITS(pdata->pp3, XP_PROP_3, 296462306a36Sopenharmony_ci GPIO_MASK); 296562306a36Sopenharmony_ci 296662306a36Sopenharmony_ci phy_data->sfp_gpio_rx_los = XP_GET_BITS(pdata->pp3, XP_PROP_3, 296762306a36Sopenharmony_ci GPIO_RX_LOS); 296862306a36Sopenharmony_ci phy_data->sfp_gpio_tx_fault = XP_GET_BITS(pdata->pp3, XP_PROP_3, 296962306a36Sopenharmony_ci GPIO_TX_FAULT); 297062306a36Sopenharmony_ci phy_data->sfp_gpio_mod_absent = XP_GET_BITS(pdata->pp3, XP_PROP_3, 297162306a36Sopenharmony_ci GPIO_MOD_ABS); 297262306a36Sopenharmony_ci phy_data->sfp_gpio_rate_select = XP_GET_BITS(pdata->pp3, XP_PROP_3, 297362306a36Sopenharmony_ci GPIO_RATE_SELECT); 297462306a36Sopenharmony_ci 297562306a36Sopenharmony_ci if (netif_msg_probe(pdata)) { 297662306a36Sopenharmony_ci dev_dbg(pdata->dev, "SFP: gpio_address=%#x\n", 297762306a36Sopenharmony_ci phy_data->sfp_gpio_address); 297862306a36Sopenharmony_ci dev_dbg(pdata->dev, "SFP: gpio_mask=%#x\n", 297962306a36Sopenharmony_ci phy_data->sfp_gpio_mask); 298062306a36Sopenharmony_ci dev_dbg(pdata->dev, "SFP: gpio_rx_los=%u\n", 298162306a36Sopenharmony_ci phy_data->sfp_gpio_rx_los); 298262306a36Sopenharmony_ci dev_dbg(pdata->dev, "SFP: gpio_tx_fault=%u\n", 298362306a36Sopenharmony_ci phy_data->sfp_gpio_tx_fault); 298462306a36Sopenharmony_ci dev_dbg(pdata->dev, "SFP: gpio_mod_absent=%u\n", 298562306a36Sopenharmony_ci phy_data->sfp_gpio_mod_absent); 298662306a36Sopenharmony_ci dev_dbg(pdata->dev, "SFP: gpio_rate_select=%u\n", 298762306a36Sopenharmony_ci phy_data->sfp_gpio_rate_select); 298862306a36Sopenharmony_ci } 298962306a36Sopenharmony_ci} 299062306a36Sopenharmony_ci 299162306a36Sopenharmony_cistatic void xgbe_phy_sfp_comm_setup(struct xgbe_prv_data *pdata) 299262306a36Sopenharmony_ci{ 299362306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 299462306a36Sopenharmony_ci unsigned int mux_addr_hi, mux_addr_lo; 299562306a36Sopenharmony_ci 299662306a36Sopenharmony_ci mux_addr_hi = XP_GET_BITS(pdata->pp4, XP_PROP_4, MUX_ADDR_HI); 299762306a36Sopenharmony_ci mux_addr_lo = XP_GET_BITS(pdata->pp4, XP_PROP_4, MUX_ADDR_LO); 299862306a36Sopenharmony_ci if (mux_addr_lo == XGBE_SFP_DIRECT) 299962306a36Sopenharmony_ci return; 300062306a36Sopenharmony_ci 300162306a36Sopenharmony_ci phy_data->sfp_comm = XGBE_SFP_COMM_PCA9545; 300262306a36Sopenharmony_ci phy_data->sfp_mux_address = (mux_addr_hi << 2) + mux_addr_lo; 300362306a36Sopenharmony_ci phy_data->sfp_mux_channel = XP_GET_BITS(pdata->pp4, XP_PROP_4, 300462306a36Sopenharmony_ci MUX_CHAN); 300562306a36Sopenharmony_ci 300662306a36Sopenharmony_ci if (netif_msg_probe(pdata)) { 300762306a36Sopenharmony_ci dev_dbg(pdata->dev, "SFP: mux_address=%#x\n", 300862306a36Sopenharmony_ci phy_data->sfp_mux_address); 300962306a36Sopenharmony_ci dev_dbg(pdata->dev, "SFP: mux_channel=%u\n", 301062306a36Sopenharmony_ci phy_data->sfp_mux_channel); 301162306a36Sopenharmony_ci } 301262306a36Sopenharmony_ci} 301362306a36Sopenharmony_ci 301462306a36Sopenharmony_cistatic void xgbe_phy_sfp_setup(struct xgbe_prv_data *pdata) 301562306a36Sopenharmony_ci{ 301662306a36Sopenharmony_ci xgbe_phy_sfp_comm_setup(pdata); 301762306a36Sopenharmony_ci xgbe_phy_sfp_gpio_setup(pdata); 301862306a36Sopenharmony_ci} 301962306a36Sopenharmony_ci 302062306a36Sopenharmony_cistatic int xgbe_phy_int_mdio_reset(struct xgbe_prv_data *pdata) 302162306a36Sopenharmony_ci{ 302262306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 302362306a36Sopenharmony_ci unsigned int ret; 302462306a36Sopenharmony_ci 302562306a36Sopenharmony_ci ret = pdata->hw_if.set_gpio(pdata, phy_data->mdio_reset_gpio); 302662306a36Sopenharmony_ci if (ret) 302762306a36Sopenharmony_ci return ret; 302862306a36Sopenharmony_ci 302962306a36Sopenharmony_ci ret = pdata->hw_if.clr_gpio(pdata, phy_data->mdio_reset_gpio); 303062306a36Sopenharmony_ci 303162306a36Sopenharmony_ci return ret; 303262306a36Sopenharmony_ci} 303362306a36Sopenharmony_ci 303462306a36Sopenharmony_cistatic int xgbe_phy_i2c_mdio_reset(struct xgbe_prv_data *pdata) 303562306a36Sopenharmony_ci{ 303662306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 303762306a36Sopenharmony_ci u8 gpio_reg, gpio_ports[2], gpio_data[3]; 303862306a36Sopenharmony_ci int ret; 303962306a36Sopenharmony_ci 304062306a36Sopenharmony_ci /* Read the output port registers */ 304162306a36Sopenharmony_ci gpio_reg = 2; 304262306a36Sopenharmony_ci ret = xgbe_phy_i2c_read(pdata, phy_data->mdio_reset_addr, 304362306a36Sopenharmony_ci &gpio_reg, sizeof(gpio_reg), 304462306a36Sopenharmony_ci gpio_ports, sizeof(gpio_ports)); 304562306a36Sopenharmony_ci if (ret) 304662306a36Sopenharmony_ci return ret; 304762306a36Sopenharmony_ci 304862306a36Sopenharmony_ci /* Prepare to write the GPIO data */ 304962306a36Sopenharmony_ci gpio_data[0] = 2; 305062306a36Sopenharmony_ci gpio_data[1] = gpio_ports[0]; 305162306a36Sopenharmony_ci gpio_data[2] = gpio_ports[1]; 305262306a36Sopenharmony_ci 305362306a36Sopenharmony_ci /* Set the GPIO pin */ 305462306a36Sopenharmony_ci if (phy_data->mdio_reset_gpio < 8) 305562306a36Sopenharmony_ci gpio_data[1] |= (1 << (phy_data->mdio_reset_gpio % 8)); 305662306a36Sopenharmony_ci else 305762306a36Sopenharmony_ci gpio_data[2] |= (1 << (phy_data->mdio_reset_gpio % 8)); 305862306a36Sopenharmony_ci 305962306a36Sopenharmony_ci /* Write the output port registers */ 306062306a36Sopenharmony_ci ret = xgbe_phy_i2c_write(pdata, phy_data->mdio_reset_addr, 306162306a36Sopenharmony_ci gpio_data, sizeof(gpio_data)); 306262306a36Sopenharmony_ci if (ret) 306362306a36Sopenharmony_ci return ret; 306462306a36Sopenharmony_ci 306562306a36Sopenharmony_ci /* Clear the GPIO pin */ 306662306a36Sopenharmony_ci if (phy_data->mdio_reset_gpio < 8) 306762306a36Sopenharmony_ci gpio_data[1] &= ~(1 << (phy_data->mdio_reset_gpio % 8)); 306862306a36Sopenharmony_ci else 306962306a36Sopenharmony_ci gpio_data[2] &= ~(1 << (phy_data->mdio_reset_gpio % 8)); 307062306a36Sopenharmony_ci 307162306a36Sopenharmony_ci /* Write the output port registers */ 307262306a36Sopenharmony_ci ret = xgbe_phy_i2c_write(pdata, phy_data->mdio_reset_addr, 307362306a36Sopenharmony_ci gpio_data, sizeof(gpio_data)); 307462306a36Sopenharmony_ci 307562306a36Sopenharmony_ci return ret; 307662306a36Sopenharmony_ci} 307762306a36Sopenharmony_ci 307862306a36Sopenharmony_cistatic int xgbe_phy_mdio_reset(struct xgbe_prv_data *pdata) 307962306a36Sopenharmony_ci{ 308062306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 308162306a36Sopenharmony_ci int ret; 308262306a36Sopenharmony_ci 308362306a36Sopenharmony_ci if (phy_data->conn_type != XGBE_CONN_TYPE_MDIO) 308462306a36Sopenharmony_ci return 0; 308562306a36Sopenharmony_ci 308662306a36Sopenharmony_ci ret = xgbe_phy_get_comm_ownership(pdata); 308762306a36Sopenharmony_ci if (ret) 308862306a36Sopenharmony_ci return ret; 308962306a36Sopenharmony_ci 309062306a36Sopenharmony_ci if (phy_data->mdio_reset == XGBE_MDIO_RESET_I2C_GPIO) 309162306a36Sopenharmony_ci ret = xgbe_phy_i2c_mdio_reset(pdata); 309262306a36Sopenharmony_ci else if (phy_data->mdio_reset == XGBE_MDIO_RESET_INT_GPIO) 309362306a36Sopenharmony_ci ret = xgbe_phy_int_mdio_reset(pdata); 309462306a36Sopenharmony_ci 309562306a36Sopenharmony_ci xgbe_phy_put_comm_ownership(pdata); 309662306a36Sopenharmony_ci 309762306a36Sopenharmony_ci return ret; 309862306a36Sopenharmony_ci} 309962306a36Sopenharmony_ci 310062306a36Sopenharmony_cistatic bool xgbe_phy_redrv_error(struct xgbe_phy_data *phy_data) 310162306a36Sopenharmony_ci{ 310262306a36Sopenharmony_ci if (!phy_data->redrv) 310362306a36Sopenharmony_ci return false; 310462306a36Sopenharmony_ci 310562306a36Sopenharmony_ci if (phy_data->redrv_if >= XGBE_PHY_REDRV_IF_MAX) 310662306a36Sopenharmony_ci return true; 310762306a36Sopenharmony_ci 310862306a36Sopenharmony_ci switch (phy_data->redrv_model) { 310962306a36Sopenharmony_ci case XGBE_PHY_REDRV_MODEL_4223: 311062306a36Sopenharmony_ci if (phy_data->redrv_lane > 3) 311162306a36Sopenharmony_ci return true; 311262306a36Sopenharmony_ci break; 311362306a36Sopenharmony_ci case XGBE_PHY_REDRV_MODEL_4227: 311462306a36Sopenharmony_ci if (phy_data->redrv_lane > 1) 311562306a36Sopenharmony_ci return true; 311662306a36Sopenharmony_ci break; 311762306a36Sopenharmony_ci default: 311862306a36Sopenharmony_ci return true; 311962306a36Sopenharmony_ci } 312062306a36Sopenharmony_ci 312162306a36Sopenharmony_ci return false; 312262306a36Sopenharmony_ci} 312362306a36Sopenharmony_ci 312462306a36Sopenharmony_cistatic int xgbe_phy_mdio_reset_setup(struct xgbe_prv_data *pdata) 312562306a36Sopenharmony_ci{ 312662306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 312762306a36Sopenharmony_ci 312862306a36Sopenharmony_ci if (phy_data->conn_type != XGBE_CONN_TYPE_MDIO) 312962306a36Sopenharmony_ci return 0; 313062306a36Sopenharmony_ci 313162306a36Sopenharmony_ci phy_data->mdio_reset = XP_GET_BITS(pdata->pp3, XP_PROP_3, MDIO_RESET); 313262306a36Sopenharmony_ci switch (phy_data->mdio_reset) { 313362306a36Sopenharmony_ci case XGBE_MDIO_RESET_NONE: 313462306a36Sopenharmony_ci case XGBE_MDIO_RESET_I2C_GPIO: 313562306a36Sopenharmony_ci case XGBE_MDIO_RESET_INT_GPIO: 313662306a36Sopenharmony_ci break; 313762306a36Sopenharmony_ci default: 313862306a36Sopenharmony_ci dev_err(pdata->dev, "unsupported MDIO reset (%#x)\n", 313962306a36Sopenharmony_ci phy_data->mdio_reset); 314062306a36Sopenharmony_ci return -EINVAL; 314162306a36Sopenharmony_ci } 314262306a36Sopenharmony_ci 314362306a36Sopenharmony_ci if (phy_data->mdio_reset == XGBE_MDIO_RESET_I2C_GPIO) { 314462306a36Sopenharmony_ci phy_data->mdio_reset_addr = XGBE_GPIO_ADDRESS_PCA9555 + 314562306a36Sopenharmony_ci XP_GET_BITS(pdata->pp3, XP_PROP_3, 314662306a36Sopenharmony_ci MDIO_RESET_I2C_ADDR); 314762306a36Sopenharmony_ci phy_data->mdio_reset_gpio = XP_GET_BITS(pdata->pp3, XP_PROP_3, 314862306a36Sopenharmony_ci MDIO_RESET_I2C_GPIO); 314962306a36Sopenharmony_ci } else if (phy_data->mdio_reset == XGBE_MDIO_RESET_INT_GPIO) { 315062306a36Sopenharmony_ci phy_data->mdio_reset_gpio = XP_GET_BITS(pdata->pp3, XP_PROP_3, 315162306a36Sopenharmony_ci MDIO_RESET_INT_GPIO); 315262306a36Sopenharmony_ci } 315362306a36Sopenharmony_ci 315462306a36Sopenharmony_ci return 0; 315562306a36Sopenharmony_ci} 315662306a36Sopenharmony_ci 315762306a36Sopenharmony_cistatic bool xgbe_phy_port_mode_mismatch(struct xgbe_prv_data *pdata) 315862306a36Sopenharmony_ci{ 315962306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 316062306a36Sopenharmony_ci unsigned int ver; 316162306a36Sopenharmony_ci 316262306a36Sopenharmony_ci /* 10 Mbps speed is supported in ver 21H and ver >= 30H */ 316362306a36Sopenharmony_ci ver = XGMAC_GET_BITS(pdata->hw_feat.version, MAC_VR, SNPSVER); 316462306a36Sopenharmony_ci if ((ver < 0x30 && ver != 0x21) && (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10)) 316562306a36Sopenharmony_ci return true; 316662306a36Sopenharmony_ci 316762306a36Sopenharmony_ci switch (phy_data->port_mode) { 316862306a36Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE: 316962306a36Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE_NO_AUTONEG: 317062306a36Sopenharmony_ci if ((phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) || 317162306a36Sopenharmony_ci (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000)) 317262306a36Sopenharmony_ci return false; 317362306a36Sopenharmony_ci break; 317462306a36Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE_2500: 317562306a36Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_2500) 317662306a36Sopenharmony_ci return false; 317762306a36Sopenharmony_ci break; 317862306a36Sopenharmony_ci case XGBE_PORT_MODE_1000BASE_T: 317962306a36Sopenharmony_ci if ((phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10) || 318062306a36Sopenharmony_ci (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) || 318162306a36Sopenharmony_ci (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000)) 318262306a36Sopenharmony_ci return false; 318362306a36Sopenharmony_ci break; 318462306a36Sopenharmony_ci case XGBE_PORT_MODE_1000BASE_X: 318562306a36Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) 318662306a36Sopenharmony_ci return false; 318762306a36Sopenharmony_ci break; 318862306a36Sopenharmony_ci case XGBE_PORT_MODE_NBASE_T: 318962306a36Sopenharmony_ci if ((phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10) || 319062306a36Sopenharmony_ci (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) || 319162306a36Sopenharmony_ci (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) || 319262306a36Sopenharmony_ci (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_2500)) 319362306a36Sopenharmony_ci return false; 319462306a36Sopenharmony_ci break; 319562306a36Sopenharmony_ci case XGBE_PORT_MODE_10GBASE_T: 319662306a36Sopenharmony_ci if ((phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10) || 319762306a36Sopenharmony_ci (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) || 319862306a36Sopenharmony_ci (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) || 319962306a36Sopenharmony_ci (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_2500) || 320062306a36Sopenharmony_ci (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000)) 320162306a36Sopenharmony_ci return false; 320262306a36Sopenharmony_ci break; 320362306a36Sopenharmony_ci case XGBE_PORT_MODE_10GBASE_R: 320462306a36Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000) 320562306a36Sopenharmony_ci return false; 320662306a36Sopenharmony_ci break; 320762306a36Sopenharmony_ci case XGBE_PORT_MODE_SFP: 320862306a36Sopenharmony_ci if ((phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10) || 320962306a36Sopenharmony_ci (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) || 321062306a36Sopenharmony_ci (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) || 321162306a36Sopenharmony_ci (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000)) 321262306a36Sopenharmony_ci return false; 321362306a36Sopenharmony_ci break; 321462306a36Sopenharmony_ci default: 321562306a36Sopenharmony_ci break; 321662306a36Sopenharmony_ci } 321762306a36Sopenharmony_ci 321862306a36Sopenharmony_ci return true; 321962306a36Sopenharmony_ci} 322062306a36Sopenharmony_ci 322162306a36Sopenharmony_cistatic bool xgbe_phy_conn_type_mismatch(struct xgbe_prv_data *pdata) 322262306a36Sopenharmony_ci{ 322362306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 322462306a36Sopenharmony_ci 322562306a36Sopenharmony_ci switch (phy_data->port_mode) { 322662306a36Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE: 322762306a36Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE_NO_AUTONEG: 322862306a36Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE_2500: 322962306a36Sopenharmony_ci if (phy_data->conn_type == XGBE_CONN_TYPE_BACKPLANE) 323062306a36Sopenharmony_ci return false; 323162306a36Sopenharmony_ci break; 323262306a36Sopenharmony_ci case XGBE_PORT_MODE_1000BASE_T: 323362306a36Sopenharmony_ci case XGBE_PORT_MODE_1000BASE_X: 323462306a36Sopenharmony_ci case XGBE_PORT_MODE_NBASE_T: 323562306a36Sopenharmony_ci case XGBE_PORT_MODE_10GBASE_T: 323662306a36Sopenharmony_ci case XGBE_PORT_MODE_10GBASE_R: 323762306a36Sopenharmony_ci if (phy_data->conn_type == XGBE_CONN_TYPE_MDIO) 323862306a36Sopenharmony_ci return false; 323962306a36Sopenharmony_ci break; 324062306a36Sopenharmony_ci case XGBE_PORT_MODE_SFP: 324162306a36Sopenharmony_ci if (phy_data->conn_type == XGBE_CONN_TYPE_SFP) 324262306a36Sopenharmony_ci return false; 324362306a36Sopenharmony_ci break; 324462306a36Sopenharmony_ci default: 324562306a36Sopenharmony_ci break; 324662306a36Sopenharmony_ci } 324762306a36Sopenharmony_ci 324862306a36Sopenharmony_ci return true; 324962306a36Sopenharmony_ci} 325062306a36Sopenharmony_ci 325162306a36Sopenharmony_cistatic bool xgbe_phy_port_enabled(struct xgbe_prv_data *pdata) 325262306a36Sopenharmony_ci{ 325362306a36Sopenharmony_ci if (!XP_GET_BITS(pdata->pp0, XP_PROP_0, PORT_SPEEDS)) 325462306a36Sopenharmony_ci return false; 325562306a36Sopenharmony_ci if (!XP_GET_BITS(pdata->pp0, XP_PROP_0, CONN_TYPE)) 325662306a36Sopenharmony_ci return false; 325762306a36Sopenharmony_ci 325862306a36Sopenharmony_ci return true; 325962306a36Sopenharmony_ci} 326062306a36Sopenharmony_ci 326162306a36Sopenharmony_cistatic void xgbe_phy_cdr_track(struct xgbe_prv_data *pdata) 326262306a36Sopenharmony_ci{ 326362306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 326462306a36Sopenharmony_ci 326562306a36Sopenharmony_ci if (!pdata->debugfs_an_cdr_workaround) 326662306a36Sopenharmony_ci return; 326762306a36Sopenharmony_ci 326862306a36Sopenharmony_ci if (!phy_data->phy_cdr_notrack) 326962306a36Sopenharmony_ci return; 327062306a36Sopenharmony_ci 327162306a36Sopenharmony_ci usleep_range(phy_data->phy_cdr_delay, 327262306a36Sopenharmony_ci phy_data->phy_cdr_delay + 500); 327362306a36Sopenharmony_ci 327462306a36Sopenharmony_ci XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_VEND2_PMA_CDR_CONTROL, 327562306a36Sopenharmony_ci XGBE_PMA_CDR_TRACK_EN_MASK, 327662306a36Sopenharmony_ci XGBE_PMA_CDR_TRACK_EN_ON); 327762306a36Sopenharmony_ci 327862306a36Sopenharmony_ci phy_data->phy_cdr_notrack = 0; 327962306a36Sopenharmony_ci} 328062306a36Sopenharmony_ci 328162306a36Sopenharmony_cistatic void xgbe_phy_cdr_notrack(struct xgbe_prv_data *pdata) 328262306a36Sopenharmony_ci{ 328362306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 328462306a36Sopenharmony_ci 328562306a36Sopenharmony_ci if (!pdata->debugfs_an_cdr_workaround) 328662306a36Sopenharmony_ci return; 328762306a36Sopenharmony_ci 328862306a36Sopenharmony_ci if (phy_data->phy_cdr_notrack) 328962306a36Sopenharmony_ci return; 329062306a36Sopenharmony_ci 329162306a36Sopenharmony_ci XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_VEND2_PMA_CDR_CONTROL, 329262306a36Sopenharmony_ci XGBE_PMA_CDR_TRACK_EN_MASK, 329362306a36Sopenharmony_ci XGBE_PMA_CDR_TRACK_EN_OFF); 329462306a36Sopenharmony_ci 329562306a36Sopenharmony_ci xgbe_phy_rrc(pdata); 329662306a36Sopenharmony_ci 329762306a36Sopenharmony_ci phy_data->phy_cdr_notrack = 1; 329862306a36Sopenharmony_ci} 329962306a36Sopenharmony_ci 330062306a36Sopenharmony_cistatic void xgbe_phy_kr_training_post(struct xgbe_prv_data *pdata) 330162306a36Sopenharmony_ci{ 330262306a36Sopenharmony_ci if (!pdata->debugfs_an_cdr_track_early) 330362306a36Sopenharmony_ci xgbe_phy_cdr_track(pdata); 330462306a36Sopenharmony_ci} 330562306a36Sopenharmony_ci 330662306a36Sopenharmony_cistatic void xgbe_phy_kr_training_pre(struct xgbe_prv_data *pdata) 330762306a36Sopenharmony_ci{ 330862306a36Sopenharmony_ci if (pdata->debugfs_an_cdr_track_early) 330962306a36Sopenharmony_ci xgbe_phy_cdr_track(pdata); 331062306a36Sopenharmony_ci} 331162306a36Sopenharmony_ci 331262306a36Sopenharmony_cistatic void xgbe_phy_an_post(struct xgbe_prv_data *pdata) 331362306a36Sopenharmony_ci{ 331462306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 331562306a36Sopenharmony_ci 331662306a36Sopenharmony_ci switch (pdata->an_mode) { 331762306a36Sopenharmony_ci case XGBE_AN_MODE_CL73: 331862306a36Sopenharmony_ci case XGBE_AN_MODE_CL73_REDRV: 331962306a36Sopenharmony_ci if (phy_data->cur_mode != XGBE_MODE_KR) 332062306a36Sopenharmony_ci break; 332162306a36Sopenharmony_ci 332262306a36Sopenharmony_ci xgbe_phy_cdr_track(pdata); 332362306a36Sopenharmony_ci 332462306a36Sopenharmony_ci switch (pdata->an_result) { 332562306a36Sopenharmony_ci case XGBE_AN_READY: 332662306a36Sopenharmony_ci case XGBE_AN_COMPLETE: 332762306a36Sopenharmony_ci break; 332862306a36Sopenharmony_ci default: 332962306a36Sopenharmony_ci if (phy_data->phy_cdr_delay < XGBE_CDR_DELAY_MAX) 333062306a36Sopenharmony_ci phy_data->phy_cdr_delay += XGBE_CDR_DELAY_INC; 333162306a36Sopenharmony_ci else 333262306a36Sopenharmony_ci phy_data->phy_cdr_delay = XGBE_CDR_DELAY_INIT; 333362306a36Sopenharmony_ci break; 333462306a36Sopenharmony_ci } 333562306a36Sopenharmony_ci break; 333662306a36Sopenharmony_ci default: 333762306a36Sopenharmony_ci break; 333862306a36Sopenharmony_ci } 333962306a36Sopenharmony_ci} 334062306a36Sopenharmony_ci 334162306a36Sopenharmony_cistatic void xgbe_phy_an_pre(struct xgbe_prv_data *pdata) 334262306a36Sopenharmony_ci{ 334362306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 334462306a36Sopenharmony_ci 334562306a36Sopenharmony_ci switch (pdata->an_mode) { 334662306a36Sopenharmony_ci case XGBE_AN_MODE_CL73: 334762306a36Sopenharmony_ci case XGBE_AN_MODE_CL73_REDRV: 334862306a36Sopenharmony_ci if (phy_data->cur_mode != XGBE_MODE_KR) 334962306a36Sopenharmony_ci break; 335062306a36Sopenharmony_ci 335162306a36Sopenharmony_ci xgbe_phy_cdr_notrack(pdata); 335262306a36Sopenharmony_ci break; 335362306a36Sopenharmony_ci default: 335462306a36Sopenharmony_ci break; 335562306a36Sopenharmony_ci } 335662306a36Sopenharmony_ci} 335762306a36Sopenharmony_ci 335862306a36Sopenharmony_cistatic void xgbe_phy_stop(struct xgbe_prv_data *pdata) 335962306a36Sopenharmony_ci{ 336062306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 336162306a36Sopenharmony_ci 336262306a36Sopenharmony_ci /* If we have an external PHY, free it */ 336362306a36Sopenharmony_ci xgbe_phy_free_phy_device(pdata); 336462306a36Sopenharmony_ci 336562306a36Sopenharmony_ci /* Reset SFP data */ 336662306a36Sopenharmony_ci xgbe_phy_sfp_reset(phy_data); 336762306a36Sopenharmony_ci xgbe_phy_sfp_mod_absent(pdata); 336862306a36Sopenharmony_ci 336962306a36Sopenharmony_ci /* Reset CDR support */ 337062306a36Sopenharmony_ci xgbe_phy_cdr_track(pdata); 337162306a36Sopenharmony_ci 337262306a36Sopenharmony_ci /* Power off the PHY */ 337362306a36Sopenharmony_ci xgbe_phy_power_off(pdata); 337462306a36Sopenharmony_ci 337562306a36Sopenharmony_ci /* Stop the I2C controller */ 337662306a36Sopenharmony_ci pdata->i2c_if.i2c_stop(pdata); 337762306a36Sopenharmony_ci} 337862306a36Sopenharmony_ci 337962306a36Sopenharmony_cistatic int xgbe_phy_start(struct xgbe_prv_data *pdata) 338062306a36Sopenharmony_ci{ 338162306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 338262306a36Sopenharmony_ci int ret; 338362306a36Sopenharmony_ci 338462306a36Sopenharmony_ci /* Start the I2C controller */ 338562306a36Sopenharmony_ci ret = pdata->i2c_if.i2c_start(pdata); 338662306a36Sopenharmony_ci if (ret) 338762306a36Sopenharmony_ci return ret; 338862306a36Sopenharmony_ci 338962306a36Sopenharmony_ci /* Set the proper MDIO mode for the re-driver */ 339062306a36Sopenharmony_ci if (phy_data->redrv && !phy_data->redrv_if) { 339162306a36Sopenharmony_ci ret = pdata->hw_if.set_ext_mii_mode(pdata, phy_data->redrv_addr, 339262306a36Sopenharmony_ci XGBE_MDIO_MODE_CL22); 339362306a36Sopenharmony_ci if (ret) { 339462306a36Sopenharmony_ci netdev_err(pdata->netdev, 339562306a36Sopenharmony_ci "redriver mdio port not compatible (%u)\n", 339662306a36Sopenharmony_ci phy_data->redrv_addr); 339762306a36Sopenharmony_ci return ret; 339862306a36Sopenharmony_ci } 339962306a36Sopenharmony_ci } 340062306a36Sopenharmony_ci 340162306a36Sopenharmony_ci /* Start in highest supported mode */ 340262306a36Sopenharmony_ci xgbe_phy_set_mode(pdata, phy_data->start_mode); 340362306a36Sopenharmony_ci 340462306a36Sopenharmony_ci /* Reset CDR support */ 340562306a36Sopenharmony_ci xgbe_phy_cdr_track(pdata); 340662306a36Sopenharmony_ci 340762306a36Sopenharmony_ci /* After starting the I2C controller, we can check for an SFP */ 340862306a36Sopenharmony_ci switch (phy_data->port_mode) { 340962306a36Sopenharmony_ci case XGBE_PORT_MODE_SFP: 341062306a36Sopenharmony_ci xgbe_phy_sfp_detect(pdata); 341162306a36Sopenharmony_ci break; 341262306a36Sopenharmony_ci default: 341362306a36Sopenharmony_ci break; 341462306a36Sopenharmony_ci } 341562306a36Sopenharmony_ci 341662306a36Sopenharmony_ci /* If we have an external PHY, start it */ 341762306a36Sopenharmony_ci ret = xgbe_phy_find_phy_device(pdata); 341862306a36Sopenharmony_ci if (ret) 341962306a36Sopenharmony_ci goto err_i2c; 342062306a36Sopenharmony_ci 342162306a36Sopenharmony_ci return 0; 342262306a36Sopenharmony_ci 342362306a36Sopenharmony_cierr_i2c: 342462306a36Sopenharmony_ci pdata->i2c_if.i2c_stop(pdata); 342562306a36Sopenharmony_ci 342662306a36Sopenharmony_ci return ret; 342762306a36Sopenharmony_ci} 342862306a36Sopenharmony_ci 342962306a36Sopenharmony_cistatic int xgbe_phy_reset(struct xgbe_prv_data *pdata) 343062306a36Sopenharmony_ci{ 343162306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 343262306a36Sopenharmony_ci enum xgbe_mode cur_mode; 343362306a36Sopenharmony_ci int ret; 343462306a36Sopenharmony_ci 343562306a36Sopenharmony_ci /* Reset by power cycling the PHY */ 343662306a36Sopenharmony_ci cur_mode = phy_data->cur_mode; 343762306a36Sopenharmony_ci xgbe_phy_power_off(pdata); 343862306a36Sopenharmony_ci xgbe_phy_set_mode(pdata, cur_mode); 343962306a36Sopenharmony_ci 344062306a36Sopenharmony_ci if (!phy_data->phydev) 344162306a36Sopenharmony_ci return 0; 344262306a36Sopenharmony_ci 344362306a36Sopenharmony_ci /* Reset the external PHY */ 344462306a36Sopenharmony_ci ret = xgbe_phy_mdio_reset(pdata); 344562306a36Sopenharmony_ci if (ret) 344662306a36Sopenharmony_ci return ret; 344762306a36Sopenharmony_ci 344862306a36Sopenharmony_ci return phy_init_hw(phy_data->phydev); 344962306a36Sopenharmony_ci} 345062306a36Sopenharmony_ci 345162306a36Sopenharmony_cistatic void xgbe_phy_exit(struct xgbe_prv_data *pdata) 345262306a36Sopenharmony_ci{ 345362306a36Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 345462306a36Sopenharmony_ci 345562306a36Sopenharmony_ci /* Unregister for driving external PHYs */ 345662306a36Sopenharmony_ci mdiobus_unregister(phy_data->mii); 345762306a36Sopenharmony_ci} 345862306a36Sopenharmony_ci 345962306a36Sopenharmony_cistatic int xgbe_phy_init(struct xgbe_prv_data *pdata) 346062306a36Sopenharmony_ci{ 346162306a36Sopenharmony_ci struct ethtool_link_ksettings *lks = &pdata->phy.lks; 346262306a36Sopenharmony_ci struct xgbe_phy_data *phy_data; 346362306a36Sopenharmony_ci struct mii_bus *mii; 346462306a36Sopenharmony_ci int ret; 346562306a36Sopenharmony_ci 346662306a36Sopenharmony_ci /* Check if enabled */ 346762306a36Sopenharmony_ci if (!xgbe_phy_port_enabled(pdata)) { 346862306a36Sopenharmony_ci dev_info(pdata->dev, "device is not enabled\n"); 346962306a36Sopenharmony_ci return -ENODEV; 347062306a36Sopenharmony_ci } 347162306a36Sopenharmony_ci 347262306a36Sopenharmony_ci /* Initialize the I2C controller */ 347362306a36Sopenharmony_ci ret = pdata->i2c_if.i2c_init(pdata); 347462306a36Sopenharmony_ci if (ret) 347562306a36Sopenharmony_ci return ret; 347662306a36Sopenharmony_ci 347762306a36Sopenharmony_ci phy_data = devm_kzalloc(pdata->dev, sizeof(*phy_data), GFP_KERNEL); 347862306a36Sopenharmony_ci if (!phy_data) 347962306a36Sopenharmony_ci return -ENOMEM; 348062306a36Sopenharmony_ci pdata->phy_data = phy_data; 348162306a36Sopenharmony_ci 348262306a36Sopenharmony_ci phy_data->port_mode = XP_GET_BITS(pdata->pp0, XP_PROP_0, PORT_MODE); 348362306a36Sopenharmony_ci phy_data->port_id = XP_GET_BITS(pdata->pp0, XP_PROP_0, PORT_ID); 348462306a36Sopenharmony_ci phy_data->port_speeds = XP_GET_BITS(pdata->pp0, XP_PROP_0, PORT_SPEEDS); 348562306a36Sopenharmony_ci phy_data->conn_type = XP_GET_BITS(pdata->pp0, XP_PROP_0, CONN_TYPE); 348662306a36Sopenharmony_ci phy_data->mdio_addr = XP_GET_BITS(pdata->pp0, XP_PROP_0, MDIO_ADDR); 348762306a36Sopenharmony_ci if (netif_msg_probe(pdata)) { 348862306a36Sopenharmony_ci dev_dbg(pdata->dev, "port mode=%u\n", phy_data->port_mode); 348962306a36Sopenharmony_ci dev_dbg(pdata->dev, "port id=%u\n", phy_data->port_id); 349062306a36Sopenharmony_ci dev_dbg(pdata->dev, "port speeds=%#x\n", phy_data->port_speeds); 349162306a36Sopenharmony_ci dev_dbg(pdata->dev, "conn type=%u\n", phy_data->conn_type); 349262306a36Sopenharmony_ci dev_dbg(pdata->dev, "mdio addr=%u\n", phy_data->mdio_addr); 349362306a36Sopenharmony_ci } 349462306a36Sopenharmony_ci 349562306a36Sopenharmony_ci phy_data->redrv = XP_GET_BITS(pdata->pp4, XP_PROP_4, REDRV_PRESENT); 349662306a36Sopenharmony_ci phy_data->redrv_if = XP_GET_BITS(pdata->pp4, XP_PROP_4, REDRV_IF); 349762306a36Sopenharmony_ci phy_data->redrv_addr = XP_GET_BITS(pdata->pp4, XP_PROP_4, REDRV_ADDR); 349862306a36Sopenharmony_ci phy_data->redrv_lane = XP_GET_BITS(pdata->pp4, XP_PROP_4, REDRV_LANE); 349962306a36Sopenharmony_ci phy_data->redrv_model = XP_GET_BITS(pdata->pp4, XP_PROP_4, REDRV_MODEL); 350062306a36Sopenharmony_ci if (phy_data->redrv && netif_msg_probe(pdata)) { 350162306a36Sopenharmony_ci dev_dbg(pdata->dev, "redrv present\n"); 350262306a36Sopenharmony_ci dev_dbg(pdata->dev, "redrv i/f=%u\n", phy_data->redrv_if); 350362306a36Sopenharmony_ci dev_dbg(pdata->dev, "redrv addr=%#x\n", phy_data->redrv_addr); 350462306a36Sopenharmony_ci dev_dbg(pdata->dev, "redrv lane=%u\n", phy_data->redrv_lane); 350562306a36Sopenharmony_ci dev_dbg(pdata->dev, "redrv model=%u\n", phy_data->redrv_model); 350662306a36Sopenharmony_ci } 350762306a36Sopenharmony_ci 350862306a36Sopenharmony_ci /* Validate the connection requested */ 350962306a36Sopenharmony_ci if (xgbe_phy_conn_type_mismatch(pdata)) { 351062306a36Sopenharmony_ci dev_err(pdata->dev, "phy mode/connection mismatch (%#x/%#x)\n", 351162306a36Sopenharmony_ci phy_data->port_mode, phy_data->conn_type); 351262306a36Sopenharmony_ci return -EINVAL; 351362306a36Sopenharmony_ci } 351462306a36Sopenharmony_ci 351562306a36Sopenharmony_ci /* Validate the mode requested */ 351662306a36Sopenharmony_ci if (xgbe_phy_port_mode_mismatch(pdata)) { 351762306a36Sopenharmony_ci dev_err(pdata->dev, "phy mode/speed mismatch (%#x/%#x)\n", 351862306a36Sopenharmony_ci phy_data->port_mode, phy_data->port_speeds); 351962306a36Sopenharmony_ci return -EINVAL; 352062306a36Sopenharmony_ci } 352162306a36Sopenharmony_ci 352262306a36Sopenharmony_ci /* Check for and validate MDIO reset support */ 352362306a36Sopenharmony_ci ret = xgbe_phy_mdio_reset_setup(pdata); 352462306a36Sopenharmony_ci if (ret) 352562306a36Sopenharmony_ci return ret; 352662306a36Sopenharmony_ci 352762306a36Sopenharmony_ci /* Validate the re-driver information */ 352862306a36Sopenharmony_ci if (xgbe_phy_redrv_error(phy_data)) { 352962306a36Sopenharmony_ci dev_err(pdata->dev, "phy re-driver settings error\n"); 353062306a36Sopenharmony_ci return -EINVAL; 353162306a36Sopenharmony_ci } 353262306a36Sopenharmony_ci pdata->kr_redrv = phy_data->redrv; 353362306a36Sopenharmony_ci 353462306a36Sopenharmony_ci /* Indicate current mode is unknown */ 353562306a36Sopenharmony_ci phy_data->cur_mode = XGBE_MODE_UNKNOWN; 353662306a36Sopenharmony_ci 353762306a36Sopenharmony_ci /* Initialize supported features */ 353862306a36Sopenharmony_ci XGBE_ZERO_SUP(lks); 353962306a36Sopenharmony_ci 354062306a36Sopenharmony_ci switch (phy_data->port_mode) { 354162306a36Sopenharmony_ci /* Backplane support */ 354262306a36Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE: 354362306a36Sopenharmony_ci XGBE_SET_SUP(lks, Autoneg); 354462306a36Sopenharmony_ci fallthrough; 354562306a36Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE_NO_AUTONEG: 354662306a36Sopenharmony_ci XGBE_SET_SUP(lks, Pause); 354762306a36Sopenharmony_ci XGBE_SET_SUP(lks, Asym_Pause); 354862306a36Sopenharmony_ci XGBE_SET_SUP(lks, Backplane); 354962306a36Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) { 355062306a36Sopenharmony_ci XGBE_SET_SUP(lks, 1000baseKX_Full); 355162306a36Sopenharmony_ci phy_data->start_mode = XGBE_MODE_KX_1000; 355262306a36Sopenharmony_ci } 355362306a36Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000) { 355462306a36Sopenharmony_ci XGBE_SET_SUP(lks, 10000baseKR_Full); 355562306a36Sopenharmony_ci if (pdata->fec_ability & MDIO_PMA_10GBR_FECABLE_ABLE) 355662306a36Sopenharmony_ci XGBE_SET_SUP(lks, 10000baseR_FEC); 355762306a36Sopenharmony_ci phy_data->start_mode = XGBE_MODE_KR; 355862306a36Sopenharmony_ci } 355962306a36Sopenharmony_ci 356062306a36Sopenharmony_ci phy_data->phydev_mode = XGBE_MDIO_MODE_NONE; 356162306a36Sopenharmony_ci break; 356262306a36Sopenharmony_ci case XGBE_PORT_MODE_BACKPLANE_2500: 356362306a36Sopenharmony_ci XGBE_SET_SUP(lks, Pause); 356462306a36Sopenharmony_ci XGBE_SET_SUP(lks, Asym_Pause); 356562306a36Sopenharmony_ci XGBE_SET_SUP(lks, Backplane); 356662306a36Sopenharmony_ci XGBE_SET_SUP(lks, 2500baseX_Full); 356762306a36Sopenharmony_ci phy_data->start_mode = XGBE_MODE_KX_2500; 356862306a36Sopenharmony_ci 356962306a36Sopenharmony_ci phy_data->phydev_mode = XGBE_MDIO_MODE_NONE; 357062306a36Sopenharmony_ci break; 357162306a36Sopenharmony_ci 357262306a36Sopenharmony_ci /* MDIO 1GBase-T support */ 357362306a36Sopenharmony_ci case XGBE_PORT_MODE_1000BASE_T: 357462306a36Sopenharmony_ci XGBE_SET_SUP(lks, Autoneg); 357562306a36Sopenharmony_ci XGBE_SET_SUP(lks, Pause); 357662306a36Sopenharmony_ci XGBE_SET_SUP(lks, Asym_Pause); 357762306a36Sopenharmony_ci XGBE_SET_SUP(lks, TP); 357862306a36Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10) { 357962306a36Sopenharmony_ci XGBE_SET_SUP(lks, 10baseT_Full); 358062306a36Sopenharmony_ci phy_data->start_mode = XGBE_MODE_SGMII_10; 358162306a36Sopenharmony_ci } 358262306a36Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) { 358362306a36Sopenharmony_ci XGBE_SET_SUP(lks, 100baseT_Full); 358462306a36Sopenharmony_ci phy_data->start_mode = XGBE_MODE_SGMII_100; 358562306a36Sopenharmony_ci } 358662306a36Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) { 358762306a36Sopenharmony_ci XGBE_SET_SUP(lks, 1000baseT_Full); 358862306a36Sopenharmony_ci phy_data->start_mode = XGBE_MODE_SGMII_1000; 358962306a36Sopenharmony_ci } 359062306a36Sopenharmony_ci 359162306a36Sopenharmony_ci phy_data->phydev_mode = XGBE_MDIO_MODE_CL22; 359262306a36Sopenharmony_ci break; 359362306a36Sopenharmony_ci 359462306a36Sopenharmony_ci /* MDIO Base-X support */ 359562306a36Sopenharmony_ci case XGBE_PORT_MODE_1000BASE_X: 359662306a36Sopenharmony_ci XGBE_SET_SUP(lks, Autoneg); 359762306a36Sopenharmony_ci XGBE_SET_SUP(lks, Pause); 359862306a36Sopenharmony_ci XGBE_SET_SUP(lks, Asym_Pause); 359962306a36Sopenharmony_ci XGBE_SET_SUP(lks, FIBRE); 360062306a36Sopenharmony_ci XGBE_SET_SUP(lks, 1000baseX_Full); 360162306a36Sopenharmony_ci phy_data->start_mode = XGBE_MODE_X; 360262306a36Sopenharmony_ci 360362306a36Sopenharmony_ci phy_data->phydev_mode = XGBE_MDIO_MODE_CL22; 360462306a36Sopenharmony_ci break; 360562306a36Sopenharmony_ci 360662306a36Sopenharmony_ci /* MDIO NBase-T support */ 360762306a36Sopenharmony_ci case XGBE_PORT_MODE_NBASE_T: 360862306a36Sopenharmony_ci XGBE_SET_SUP(lks, Autoneg); 360962306a36Sopenharmony_ci XGBE_SET_SUP(lks, Pause); 361062306a36Sopenharmony_ci XGBE_SET_SUP(lks, Asym_Pause); 361162306a36Sopenharmony_ci XGBE_SET_SUP(lks, TP); 361262306a36Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10) { 361362306a36Sopenharmony_ci XGBE_SET_SUP(lks, 10baseT_Full); 361462306a36Sopenharmony_ci phy_data->start_mode = XGBE_MODE_SGMII_10; 361562306a36Sopenharmony_ci } 361662306a36Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) { 361762306a36Sopenharmony_ci XGBE_SET_SUP(lks, 100baseT_Full); 361862306a36Sopenharmony_ci phy_data->start_mode = XGBE_MODE_SGMII_100; 361962306a36Sopenharmony_ci } 362062306a36Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) { 362162306a36Sopenharmony_ci XGBE_SET_SUP(lks, 1000baseT_Full); 362262306a36Sopenharmony_ci phy_data->start_mode = XGBE_MODE_SGMII_1000; 362362306a36Sopenharmony_ci } 362462306a36Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_2500) { 362562306a36Sopenharmony_ci XGBE_SET_SUP(lks, 2500baseT_Full); 362662306a36Sopenharmony_ci phy_data->start_mode = XGBE_MODE_KX_2500; 362762306a36Sopenharmony_ci } 362862306a36Sopenharmony_ci 362962306a36Sopenharmony_ci phy_data->phydev_mode = XGBE_MDIO_MODE_CL45; 363062306a36Sopenharmony_ci break; 363162306a36Sopenharmony_ci 363262306a36Sopenharmony_ci /* 10GBase-T support */ 363362306a36Sopenharmony_ci case XGBE_PORT_MODE_10GBASE_T: 363462306a36Sopenharmony_ci XGBE_SET_SUP(lks, Autoneg); 363562306a36Sopenharmony_ci XGBE_SET_SUP(lks, Pause); 363662306a36Sopenharmony_ci XGBE_SET_SUP(lks, Asym_Pause); 363762306a36Sopenharmony_ci XGBE_SET_SUP(lks, TP); 363862306a36Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10) { 363962306a36Sopenharmony_ci XGBE_SET_SUP(lks, 10baseT_Full); 364062306a36Sopenharmony_ci phy_data->start_mode = XGBE_MODE_SGMII_10; 364162306a36Sopenharmony_ci } 364262306a36Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) { 364362306a36Sopenharmony_ci XGBE_SET_SUP(lks, 100baseT_Full); 364462306a36Sopenharmony_ci phy_data->start_mode = XGBE_MODE_SGMII_100; 364562306a36Sopenharmony_ci } 364662306a36Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) { 364762306a36Sopenharmony_ci XGBE_SET_SUP(lks, 1000baseT_Full); 364862306a36Sopenharmony_ci phy_data->start_mode = XGBE_MODE_SGMII_1000; 364962306a36Sopenharmony_ci } 365062306a36Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_2500) { 365162306a36Sopenharmony_ci XGBE_SET_SUP(lks, 2500baseT_Full); 365262306a36Sopenharmony_ci phy_data->start_mode = XGBE_MODE_KX_2500; 365362306a36Sopenharmony_ci } 365462306a36Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000) { 365562306a36Sopenharmony_ci XGBE_SET_SUP(lks, 10000baseT_Full); 365662306a36Sopenharmony_ci phy_data->start_mode = XGBE_MODE_KR; 365762306a36Sopenharmony_ci } 365862306a36Sopenharmony_ci 365962306a36Sopenharmony_ci phy_data->phydev_mode = XGBE_MDIO_MODE_CL45; 366062306a36Sopenharmony_ci break; 366162306a36Sopenharmony_ci 366262306a36Sopenharmony_ci /* 10GBase-R support */ 366362306a36Sopenharmony_ci case XGBE_PORT_MODE_10GBASE_R: 366462306a36Sopenharmony_ci XGBE_SET_SUP(lks, Autoneg); 366562306a36Sopenharmony_ci XGBE_SET_SUP(lks, Pause); 366662306a36Sopenharmony_ci XGBE_SET_SUP(lks, Asym_Pause); 366762306a36Sopenharmony_ci XGBE_SET_SUP(lks, FIBRE); 366862306a36Sopenharmony_ci XGBE_SET_SUP(lks, 10000baseSR_Full); 366962306a36Sopenharmony_ci XGBE_SET_SUP(lks, 10000baseLR_Full); 367062306a36Sopenharmony_ci XGBE_SET_SUP(lks, 10000baseLRM_Full); 367162306a36Sopenharmony_ci XGBE_SET_SUP(lks, 10000baseER_Full); 367262306a36Sopenharmony_ci if (pdata->fec_ability & MDIO_PMA_10GBR_FECABLE_ABLE) 367362306a36Sopenharmony_ci XGBE_SET_SUP(lks, 10000baseR_FEC); 367462306a36Sopenharmony_ci phy_data->start_mode = XGBE_MODE_SFI; 367562306a36Sopenharmony_ci 367662306a36Sopenharmony_ci phy_data->phydev_mode = XGBE_MDIO_MODE_NONE; 367762306a36Sopenharmony_ci break; 367862306a36Sopenharmony_ci 367962306a36Sopenharmony_ci /* SFP support */ 368062306a36Sopenharmony_ci case XGBE_PORT_MODE_SFP: 368162306a36Sopenharmony_ci XGBE_SET_SUP(lks, Autoneg); 368262306a36Sopenharmony_ci XGBE_SET_SUP(lks, Pause); 368362306a36Sopenharmony_ci XGBE_SET_SUP(lks, Asym_Pause); 368462306a36Sopenharmony_ci XGBE_SET_SUP(lks, TP); 368562306a36Sopenharmony_ci XGBE_SET_SUP(lks, FIBRE); 368662306a36Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10) 368762306a36Sopenharmony_ci phy_data->start_mode = XGBE_MODE_SGMII_10; 368862306a36Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) 368962306a36Sopenharmony_ci phy_data->start_mode = XGBE_MODE_SGMII_100; 369062306a36Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) 369162306a36Sopenharmony_ci phy_data->start_mode = XGBE_MODE_SGMII_1000; 369262306a36Sopenharmony_ci if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000) 369362306a36Sopenharmony_ci phy_data->start_mode = XGBE_MODE_SFI; 369462306a36Sopenharmony_ci 369562306a36Sopenharmony_ci phy_data->phydev_mode = XGBE_MDIO_MODE_CL22; 369662306a36Sopenharmony_ci 369762306a36Sopenharmony_ci xgbe_phy_sfp_setup(pdata); 369862306a36Sopenharmony_ci break; 369962306a36Sopenharmony_ci default: 370062306a36Sopenharmony_ci return -EINVAL; 370162306a36Sopenharmony_ci } 370262306a36Sopenharmony_ci 370362306a36Sopenharmony_ci if (netif_msg_probe(pdata)) 370462306a36Sopenharmony_ci dev_dbg(pdata->dev, "phy supported=0x%*pb\n", 370562306a36Sopenharmony_ci __ETHTOOL_LINK_MODE_MASK_NBITS, 370662306a36Sopenharmony_ci lks->link_modes.supported); 370762306a36Sopenharmony_ci 370862306a36Sopenharmony_ci if ((phy_data->conn_type & XGBE_CONN_TYPE_MDIO) && 370962306a36Sopenharmony_ci (phy_data->phydev_mode != XGBE_MDIO_MODE_NONE)) { 371062306a36Sopenharmony_ci ret = pdata->hw_if.set_ext_mii_mode(pdata, phy_data->mdio_addr, 371162306a36Sopenharmony_ci phy_data->phydev_mode); 371262306a36Sopenharmony_ci if (ret) { 371362306a36Sopenharmony_ci dev_err(pdata->dev, 371462306a36Sopenharmony_ci "mdio port/clause not compatible (%d/%u)\n", 371562306a36Sopenharmony_ci phy_data->mdio_addr, phy_data->phydev_mode); 371662306a36Sopenharmony_ci return -EINVAL; 371762306a36Sopenharmony_ci } 371862306a36Sopenharmony_ci } 371962306a36Sopenharmony_ci 372062306a36Sopenharmony_ci if (phy_data->redrv && !phy_data->redrv_if) { 372162306a36Sopenharmony_ci ret = pdata->hw_if.set_ext_mii_mode(pdata, phy_data->redrv_addr, 372262306a36Sopenharmony_ci XGBE_MDIO_MODE_CL22); 372362306a36Sopenharmony_ci if (ret) { 372462306a36Sopenharmony_ci dev_err(pdata->dev, 372562306a36Sopenharmony_ci "redriver mdio port not compatible (%u)\n", 372662306a36Sopenharmony_ci phy_data->redrv_addr); 372762306a36Sopenharmony_ci return -EINVAL; 372862306a36Sopenharmony_ci } 372962306a36Sopenharmony_ci } 373062306a36Sopenharmony_ci 373162306a36Sopenharmony_ci phy_data->phy_cdr_delay = XGBE_CDR_DELAY_INIT; 373262306a36Sopenharmony_ci 373362306a36Sopenharmony_ci /* Register for driving external PHYs */ 373462306a36Sopenharmony_ci mii = devm_mdiobus_alloc(pdata->dev); 373562306a36Sopenharmony_ci if (!mii) { 373662306a36Sopenharmony_ci dev_err(pdata->dev, "mdiobus_alloc failed\n"); 373762306a36Sopenharmony_ci return -ENOMEM; 373862306a36Sopenharmony_ci } 373962306a36Sopenharmony_ci 374062306a36Sopenharmony_ci mii->priv = pdata; 374162306a36Sopenharmony_ci mii->name = "amd-xgbe-mii"; 374262306a36Sopenharmony_ci mii->read = xgbe_phy_mii_read_c22; 374362306a36Sopenharmony_ci mii->write = xgbe_phy_mii_write_c22; 374462306a36Sopenharmony_ci mii->read_c45 = xgbe_phy_mii_read_c45; 374562306a36Sopenharmony_ci mii->write_c45 = xgbe_phy_mii_write_c45; 374662306a36Sopenharmony_ci mii->parent = pdata->dev; 374762306a36Sopenharmony_ci mii->phy_mask = ~0; 374862306a36Sopenharmony_ci snprintf(mii->id, sizeof(mii->id), "%s", dev_name(pdata->dev)); 374962306a36Sopenharmony_ci ret = mdiobus_register(mii); 375062306a36Sopenharmony_ci if (ret) { 375162306a36Sopenharmony_ci dev_err(pdata->dev, "mdiobus_register failed\n"); 375262306a36Sopenharmony_ci return ret; 375362306a36Sopenharmony_ci } 375462306a36Sopenharmony_ci phy_data->mii = mii; 375562306a36Sopenharmony_ci 375662306a36Sopenharmony_ci return 0; 375762306a36Sopenharmony_ci} 375862306a36Sopenharmony_ci 375962306a36Sopenharmony_civoid xgbe_init_function_ptrs_phy_v2(struct xgbe_phy_if *phy_if) 376062306a36Sopenharmony_ci{ 376162306a36Sopenharmony_ci struct xgbe_phy_impl_if *phy_impl = &phy_if->phy_impl; 376262306a36Sopenharmony_ci 376362306a36Sopenharmony_ci phy_impl->init = xgbe_phy_init; 376462306a36Sopenharmony_ci phy_impl->exit = xgbe_phy_exit; 376562306a36Sopenharmony_ci 376662306a36Sopenharmony_ci phy_impl->reset = xgbe_phy_reset; 376762306a36Sopenharmony_ci phy_impl->start = xgbe_phy_start; 376862306a36Sopenharmony_ci phy_impl->stop = xgbe_phy_stop; 376962306a36Sopenharmony_ci 377062306a36Sopenharmony_ci phy_impl->link_status = xgbe_phy_link_status; 377162306a36Sopenharmony_ci 377262306a36Sopenharmony_ci phy_impl->valid_speed = xgbe_phy_valid_speed; 377362306a36Sopenharmony_ci 377462306a36Sopenharmony_ci phy_impl->use_mode = xgbe_phy_use_mode; 377562306a36Sopenharmony_ci phy_impl->set_mode = xgbe_phy_set_mode; 377662306a36Sopenharmony_ci phy_impl->get_mode = xgbe_phy_get_mode; 377762306a36Sopenharmony_ci phy_impl->switch_mode = xgbe_phy_switch_mode; 377862306a36Sopenharmony_ci phy_impl->cur_mode = xgbe_phy_cur_mode; 377962306a36Sopenharmony_ci 378062306a36Sopenharmony_ci phy_impl->an_mode = xgbe_phy_an_mode; 378162306a36Sopenharmony_ci 378262306a36Sopenharmony_ci phy_impl->an_config = xgbe_phy_an_config; 378362306a36Sopenharmony_ci 378462306a36Sopenharmony_ci phy_impl->an_advertising = xgbe_phy_an_advertising; 378562306a36Sopenharmony_ci 378662306a36Sopenharmony_ci phy_impl->an_outcome = xgbe_phy_an_outcome; 378762306a36Sopenharmony_ci 378862306a36Sopenharmony_ci phy_impl->an_pre = xgbe_phy_an_pre; 378962306a36Sopenharmony_ci phy_impl->an_post = xgbe_phy_an_post; 379062306a36Sopenharmony_ci 379162306a36Sopenharmony_ci phy_impl->kr_training_pre = xgbe_phy_kr_training_pre; 379262306a36Sopenharmony_ci phy_impl->kr_training_post = xgbe_phy_kr_training_post; 379362306a36Sopenharmony_ci 379462306a36Sopenharmony_ci phy_impl->module_info = xgbe_phy_module_info; 379562306a36Sopenharmony_ci phy_impl->module_eeprom = xgbe_phy_module_eeprom; 379662306a36Sopenharmony_ci} 3797