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