xref: /freebsd/sys/dev/axgbe/xgbe-phy-v2.c (revision 2b8df536)
17113afc8SEmmanuel Vadot /*
27113afc8SEmmanuel Vadot  * AMD 10Gb Ethernet driver
37113afc8SEmmanuel Vadot  *
47113afc8SEmmanuel Vadot  * Copyright (c) 2020 Advanced Micro Devices, Inc.
57113afc8SEmmanuel Vadot  *
67113afc8SEmmanuel Vadot  * This file is available to you under your choice of the following two
77113afc8SEmmanuel Vadot  * licenses:
87113afc8SEmmanuel Vadot  *
97113afc8SEmmanuel Vadot  * License 1: GPLv2
107113afc8SEmmanuel Vadot  *
117113afc8SEmmanuel Vadot  * This file is free software; you may copy, redistribute and/or modify
127113afc8SEmmanuel Vadot  * it under the terms of the GNU General Public License as published by
137113afc8SEmmanuel Vadot  * the Free Software Foundation, either version 2 of the License, or (at
147113afc8SEmmanuel Vadot  * your option) any later version.
157113afc8SEmmanuel Vadot  *
167113afc8SEmmanuel Vadot  * This file is distributed in the hope that it will be useful, but
177113afc8SEmmanuel Vadot  * WITHOUT ANY WARRANTY; without even the implied warranty of
187113afc8SEmmanuel Vadot  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
197113afc8SEmmanuel Vadot  * General Public License for more details.
207113afc8SEmmanuel Vadot  *
217113afc8SEmmanuel Vadot  * You should have received a copy of the GNU General Public License
227113afc8SEmmanuel Vadot  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
237113afc8SEmmanuel Vadot  *
247113afc8SEmmanuel Vadot  * This file incorporates work covered by the following copyright and
257113afc8SEmmanuel Vadot  * permission notice:
267113afc8SEmmanuel Vadot  *     The Synopsys DWC ETHER XGMAC Software Driver and documentation
277113afc8SEmmanuel Vadot  *     (hereinafter "Software") is an unsupported proprietary work of Synopsys,
287113afc8SEmmanuel Vadot  *     Inc. unless otherwise expressly agreed to in writing between Synopsys
297113afc8SEmmanuel Vadot  *     and you.
307113afc8SEmmanuel Vadot  *
317113afc8SEmmanuel Vadot  *     The Software IS NOT an item of Licensed Software or Licensed Product
327113afc8SEmmanuel Vadot  *     under any End User Software License Agreement or Agreement for Licensed
337113afc8SEmmanuel Vadot  *     Product with Synopsys or any supplement thereto.  Permission is hereby
347113afc8SEmmanuel Vadot  *     granted, free of charge, to any person obtaining a copy of this software
357113afc8SEmmanuel Vadot  *     annotated with this license and the Software, to deal in the Software
367113afc8SEmmanuel Vadot  *     without restriction, including without limitation the rights to use,
377113afc8SEmmanuel Vadot  *     copy, modify, merge, publish, distribute, sublicense, and/or sell copies
387113afc8SEmmanuel Vadot  *     of the Software, and to permit persons to whom the Software is furnished
397113afc8SEmmanuel Vadot  *     to do so, subject to the following conditions:
407113afc8SEmmanuel Vadot  *
417113afc8SEmmanuel Vadot  *     The above copyright notice and this permission notice shall be included
427113afc8SEmmanuel Vadot  *     in all copies or substantial portions of the Software.
437113afc8SEmmanuel Vadot  *
447113afc8SEmmanuel Vadot  *     THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
457113afc8SEmmanuel Vadot  *     BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
467113afc8SEmmanuel Vadot  *     TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
477113afc8SEmmanuel Vadot  *     PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS
487113afc8SEmmanuel Vadot  *     BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
497113afc8SEmmanuel Vadot  *     CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
507113afc8SEmmanuel Vadot  *     SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
517113afc8SEmmanuel Vadot  *     INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
527113afc8SEmmanuel Vadot  *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
537113afc8SEmmanuel Vadot  *     ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
547113afc8SEmmanuel Vadot  *     THE POSSIBILITY OF SUCH DAMAGE.
557113afc8SEmmanuel Vadot  *
567113afc8SEmmanuel Vadot  *
577113afc8SEmmanuel Vadot  * License 2: Modified BSD
587113afc8SEmmanuel Vadot  *
597113afc8SEmmanuel Vadot  * Redistribution and use in source and binary forms, with or without
607113afc8SEmmanuel Vadot  * modification, are permitted provided that the following conditions are met:
617113afc8SEmmanuel Vadot  *     * Redistributions of source code must retain the above copyright
627113afc8SEmmanuel Vadot  *       notice, this list of conditions and the following disclaimer.
637113afc8SEmmanuel Vadot  *     * Redistributions in binary form must reproduce the above copyright
647113afc8SEmmanuel Vadot  *       notice, this list of conditions and the following disclaimer in the
657113afc8SEmmanuel Vadot  *       documentation and/or other materials provided with the distribution.
667113afc8SEmmanuel Vadot  *     * Neither the name of Advanced Micro Devices, Inc. nor the
677113afc8SEmmanuel Vadot  *       names of its contributors may be used to endorse or promote products
687113afc8SEmmanuel Vadot  *       derived from this software without specific prior written permission.
697113afc8SEmmanuel Vadot  *
707113afc8SEmmanuel Vadot  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
717113afc8SEmmanuel Vadot  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
727113afc8SEmmanuel Vadot  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
737113afc8SEmmanuel Vadot  * ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
747113afc8SEmmanuel Vadot  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
757113afc8SEmmanuel Vadot  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
767113afc8SEmmanuel Vadot  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
777113afc8SEmmanuel Vadot  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
787113afc8SEmmanuel Vadot  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
797113afc8SEmmanuel Vadot  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
807113afc8SEmmanuel Vadot  *
817113afc8SEmmanuel Vadot  * This file incorporates work covered by the following copyright and
827113afc8SEmmanuel Vadot  * permission notice:
837113afc8SEmmanuel Vadot  *     The Synopsys DWC ETHER XGMAC Software Driver and documentation
847113afc8SEmmanuel Vadot  *     (hereinafter "Software") is an unsupported proprietary work of Synopsys,
857113afc8SEmmanuel Vadot  *     Inc. unless otherwise expressly agreed to in writing between Synopsys
867113afc8SEmmanuel Vadot  *     and you.
877113afc8SEmmanuel Vadot  *
887113afc8SEmmanuel Vadot  *     The Software IS NOT an item of Licensed Software or Licensed Product
897113afc8SEmmanuel Vadot  *     under any End User Software License Agreement or Agreement for Licensed
907113afc8SEmmanuel Vadot  *     Product with Synopsys or any supplement thereto.  Permission is hereby
917113afc8SEmmanuel Vadot  *     granted, free of charge, to any person obtaining a copy of this software
927113afc8SEmmanuel Vadot  *     annotated with this license and the Software, to deal in the Software
937113afc8SEmmanuel Vadot  *     without restriction, including without limitation the rights to use,
947113afc8SEmmanuel Vadot  *     copy, modify, merge, publish, distribute, sublicense, and/or sell copies
957113afc8SEmmanuel Vadot  *     of the Software, and to permit persons to whom the Software is furnished
967113afc8SEmmanuel Vadot  *     to do so, subject to the following conditions:
977113afc8SEmmanuel Vadot  *
987113afc8SEmmanuel Vadot  *     The above copyright notice and this permission notice shall be included
997113afc8SEmmanuel Vadot  *     in all copies or substantial portions of the Software.
1007113afc8SEmmanuel Vadot  *
1017113afc8SEmmanuel Vadot  *     THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
1027113afc8SEmmanuel Vadot  *     BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
1037113afc8SEmmanuel Vadot  *     TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
1047113afc8SEmmanuel Vadot  *     PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS
1057113afc8SEmmanuel Vadot  *     BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
1067113afc8SEmmanuel Vadot  *     CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
1077113afc8SEmmanuel Vadot  *     SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
1087113afc8SEmmanuel Vadot  *     INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
1097113afc8SEmmanuel Vadot  *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
1107113afc8SEmmanuel Vadot  *     ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
1117113afc8SEmmanuel Vadot  *     THE POSSIBILITY OF SUCH DAMAGE.
1127113afc8SEmmanuel Vadot  */
1137113afc8SEmmanuel Vadot 
1147113afc8SEmmanuel Vadot #include <sys/cdefs.h>
1157113afc8SEmmanuel Vadot #include "xgbe.h"
1167113afc8SEmmanuel Vadot #include "xgbe-common.h"
1177113afc8SEmmanuel Vadot 
1187113afc8SEmmanuel Vadot struct mtx xgbe_phy_comm_lock;
1197113afc8SEmmanuel Vadot 
1207113afc8SEmmanuel Vadot #define XGBE_PHY_PORT_SPEED_100		BIT(0)
1217113afc8SEmmanuel Vadot #define XGBE_PHY_PORT_SPEED_1000	BIT(1)
1227113afc8SEmmanuel Vadot #define XGBE_PHY_PORT_SPEED_2500	BIT(2)
1237113afc8SEmmanuel Vadot #define XGBE_PHY_PORT_SPEED_10000	BIT(3)
1247113afc8SEmmanuel Vadot 
1257113afc8SEmmanuel Vadot #define XGBE_MUTEX_RELEASE		0x80000000
1267113afc8SEmmanuel Vadot 
1277113afc8SEmmanuel Vadot #define XGBE_SFP_DIRECT			7
1287113afc8SEmmanuel Vadot #define GPIO_MASK_WIDTH			4
1297113afc8SEmmanuel Vadot 
1307113afc8SEmmanuel Vadot /* I2C target addresses */
1317113afc8SEmmanuel Vadot #define XGBE_SFP_SERIAL_ID_ADDRESS	0x50
1327113afc8SEmmanuel Vadot #define XGBE_SFP_DIAG_INFO_ADDRESS	0x51
1337113afc8SEmmanuel Vadot #define XGBE_SFP_PHY_ADDRESS		0x56
1347113afc8SEmmanuel Vadot #define XGBE_GPIO_ADDRESS_PCA9555	0x20
1357113afc8SEmmanuel Vadot 
1367113afc8SEmmanuel Vadot /* SFP sideband signal indicators */
1377113afc8SEmmanuel Vadot #define XGBE_GPIO_NO_TX_FAULT		BIT(0)
1387113afc8SEmmanuel Vadot #define XGBE_GPIO_NO_RATE_SELECT	BIT(1)
1397113afc8SEmmanuel Vadot #define XGBE_GPIO_NO_MOD_ABSENT		BIT(2)
1407113afc8SEmmanuel Vadot #define XGBE_GPIO_NO_RX_LOS		BIT(3)
1417113afc8SEmmanuel Vadot 
1427113afc8SEmmanuel Vadot /* Rate-change complete wait/retry count */
1437113afc8SEmmanuel Vadot #define XGBE_RATECHANGE_COUNT		500
1447113afc8SEmmanuel Vadot 
1457113afc8SEmmanuel Vadot /* CDR delay values for KR support (in usec) */
1467113afc8SEmmanuel Vadot #define XGBE_CDR_DELAY_INIT		10000
1477113afc8SEmmanuel Vadot #define XGBE_CDR_DELAY_INC		10000
1487113afc8SEmmanuel Vadot #define XGBE_CDR_DELAY_MAX		100000
1497113afc8SEmmanuel Vadot 
1507113afc8SEmmanuel Vadot /* RRC frequency during link status check */
1517113afc8SEmmanuel Vadot #define XGBE_RRC_FREQUENCY		10
1527113afc8SEmmanuel Vadot 
153445bed5cSStephan de Wit /* SFP port max PHY probe retries */
154445bed5cSStephan de Wit #define XGBE_SFP_PHY_RETRY_MAX		5
155445bed5cSStephan de Wit 
1567113afc8SEmmanuel Vadot enum xgbe_port_mode {
1577113afc8SEmmanuel Vadot 	XGBE_PORT_MODE_RSVD = 0,
1587113afc8SEmmanuel Vadot 	XGBE_PORT_MODE_BACKPLANE,
1597113afc8SEmmanuel Vadot 	XGBE_PORT_MODE_BACKPLANE_2500,
1607113afc8SEmmanuel Vadot 	XGBE_PORT_MODE_1000BASE_T,
1617113afc8SEmmanuel Vadot 	XGBE_PORT_MODE_1000BASE_X,
1627113afc8SEmmanuel Vadot 	XGBE_PORT_MODE_NBASE_T,
1637113afc8SEmmanuel Vadot 	XGBE_PORT_MODE_10GBASE_T,
1647113afc8SEmmanuel Vadot 	XGBE_PORT_MODE_10GBASE_R,
1657113afc8SEmmanuel Vadot 	XGBE_PORT_MODE_SFP,
1667113afc8SEmmanuel Vadot 	XGBE_PORT_MODE_MAX,
1677113afc8SEmmanuel Vadot };
1687113afc8SEmmanuel Vadot 
1697113afc8SEmmanuel Vadot enum xgbe_conn_type {
1707113afc8SEmmanuel Vadot 	XGBE_CONN_TYPE_NONE = 0,
1717113afc8SEmmanuel Vadot 	XGBE_CONN_TYPE_SFP,
1727113afc8SEmmanuel Vadot 	XGBE_CONN_TYPE_MDIO,
1737113afc8SEmmanuel Vadot 	XGBE_CONN_TYPE_RSVD1,
1747113afc8SEmmanuel Vadot 	XGBE_CONN_TYPE_BACKPLANE,
1757113afc8SEmmanuel Vadot 	XGBE_CONN_TYPE_MAX,
1767113afc8SEmmanuel Vadot };
1777113afc8SEmmanuel Vadot 
1787113afc8SEmmanuel Vadot /* SFP/SFP+ related definitions */
1797113afc8SEmmanuel Vadot enum xgbe_sfp_comm {
1807113afc8SEmmanuel Vadot 	XGBE_SFP_COMM_DIRECT = 0,
1817113afc8SEmmanuel Vadot 	XGBE_SFP_COMM_PCA9545,
1827113afc8SEmmanuel Vadot };
1837113afc8SEmmanuel Vadot 
1847113afc8SEmmanuel Vadot enum xgbe_sfp_cable {
1857113afc8SEmmanuel Vadot 	XGBE_SFP_CABLE_UNKNOWN = 0,
1867113afc8SEmmanuel Vadot 	XGBE_SFP_CABLE_ACTIVE,
1877113afc8SEmmanuel Vadot 	XGBE_SFP_CABLE_PASSIVE,
1887113afc8SEmmanuel Vadot };
1897113afc8SEmmanuel Vadot 
1907113afc8SEmmanuel Vadot enum xgbe_sfp_base {
1917113afc8SEmmanuel Vadot 	XGBE_SFP_BASE_UNKNOWN = 0,
192445bed5cSStephan de Wit 	XGBE_SFP_BASE_PX,
193445bed5cSStephan de Wit 	XGBE_SFP_BASE_BX10,
194445bed5cSStephan de Wit 	XGBE_SFP_BASE_100_FX,
195445bed5cSStephan de Wit 	XGBE_SFP_BASE_100_LX10,
196445bed5cSStephan de Wit 	XGBE_SFP_BASE_100_BX,
1977113afc8SEmmanuel Vadot 	XGBE_SFP_BASE_1000_T,
1987113afc8SEmmanuel Vadot 	XGBE_SFP_BASE_1000_SX,
1997113afc8SEmmanuel Vadot 	XGBE_SFP_BASE_1000_LX,
2007113afc8SEmmanuel Vadot 	XGBE_SFP_BASE_1000_CX,
201445bed5cSStephan de Wit 	XGBE_SFP_BASE_1000_BX,
2027113afc8SEmmanuel Vadot 	XGBE_SFP_BASE_10000_SR,
2037113afc8SEmmanuel Vadot 	XGBE_SFP_BASE_10000_LR,
2047113afc8SEmmanuel Vadot 	XGBE_SFP_BASE_10000_LRM,
2057113afc8SEmmanuel Vadot 	XGBE_SFP_BASE_10000_ER,
2067113afc8SEmmanuel Vadot 	XGBE_SFP_BASE_10000_CR,
2077113afc8SEmmanuel Vadot };
2087113afc8SEmmanuel Vadot 
2097113afc8SEmmanuel Vadot enum xgbe_sfp_speed {
2107113afc8SEmmanuel Vadot 	XGBE_SFP_SPEED_UNKNOWN = 0,
211445bed5cSStephan de Wit 	XGBE_SFP_SPEED_100,
2127113afc8SEmmanuel Vadot 	XGBE_SFP_SPEED_100_1000,
2137113afc8SEmmanuel Vadot 	XGBE_SFP_SPEED_1000,
2147113afc8SEmmanuel Vadot 	XGBE_SFP_SPEED_10000,
215445bed5cSStephan de Wit 	XGBE_SFP_SPEED_25000,
2167113afc8SEmmanuel Vadot };
2177113afc8SEmmanuel Vadot 
2187113afc8SEmmanuel Vadot /* SFP Serial ID Base ID values relative to an offset of 0 */
2197113afc8SEmmanuel Vadot #define XGBE_SFP_BASE_ID			0
2207113afc8SEmmanuel Vadot #define XGBE_SFP_ID_SFP				0x03
2217113afc8SEmmanuel Vadot 
2227113afc8SEmmanuel Vadot #define XGBE_SFP_BASE_EXT_ID			1
2237113afc8SEmmanuel Vadot #define XGBE_SFP_EXT_ID_SFP			0x04
2247113afc8SEmmanuel Vadot 
225bfd75d45SVincenzo Maffione #define XGBE_SFP_BASE_CV			2
226bfd75d45SVincenzo Maffione #define XGBE_SFP_BASE_CV_CP			0x21
227bfd75d45SVincenzo Maffione 
2287113afc8SEmmanuel Vadot #define XGBE_SFP_BASE_10GBE_CC			3
2297113afc8SEmmanuel Vadot #define XGBE_SFP_BASE_10GBE_CC_SR		BIT(4)
2307113afc8SEmmanuel Vadot #define XGBE_SFP_BASE_10GBE_CC_LR		BIT(5)
2317113afc8SEmmanuel Vadot #define XGBE_SFP_BASE_10GBE_CC_LRM		BIT(6)
2327113afc8SEmmanuel Vadot #define XGBE_SFP_BASE_10GBE_CC_ER		BIT(7)
2337113afc8SEmmanuel Vadot 
2347113afc8SEmmanuel Vadot #define XGBE_SFP_BASE_1GBE_CC			6
2357113afc8SEmmanuel Vadot #define XGBE_SFP_BASE_1GBE_CC_SX		BIT(0)
2367113afc8SEmmanuel Vadot #define XGBE_SFP_BASE_1GBE_CC_LX		BIT(1)
2377113afc8SEmmanuel Vadot #define XGBE_SFP_BASE_1GBE_CC_CX		BIT(2)
2387113afc8SEmmanuel Vadot #define XGBE_SFP_BASE_1GBE_CC_T			BIT(3)
239445bed5cSStephan de Wit #define XGBE_SFP_BASE_100M_CC_LX10		BIT(4)
240445bed5cSStephan de Wit #define XGBE_SFP_BASE_100M_CC_FX		BIT(5)
241445bed5cSStephan de Wit #define XGBE_SFP_BASE_CC_BX10			BIT(6)
242445bed5cSStephan de Wit #define XGBE_SFP_BASE_CC_PX			BIT(7)
2437113afc8SEmmanuel Vadot 
2447113afc8SEmmanuel Vadot #define XGBE_SFP_BASE_CABLE			8
2457113afc8SEmmanuel Vadot #define XGBE_SFP_BASE_CABLE_PASSIVE		BIT(2)
2467113afc8SEmmanuel Vadot #define XGBE_SFP_BASE_CABLE_ACTIVE		BIT(3)
2477113afc8SEmmanuel Vadot 
2487113afc8SEmmanuel Vadot #define XGBE_SFP_BASE_BR			12
249445bed5cSStephan de Wit #define XGBE_SFP_BASE_BR_100M_MIN		0x1
250445bed5cSStephan de Wit #define XGBE_SFP_BASE_BR_100M_MAX		0x2
2517113afc8SEmmanuel Vadot #define XGBE_SFP_BASE_BR_1GBE_MIN		0x0a
2527113afc8SEmmanuel Vadot #define XGBE_SFP_BASE_BR_1GBE_MAX		0x0d
2537113afc8SEmmanuel Vadot #define XGBE_SFP_BASE_BR_10GBE_MIN		0x64
2547113afc8SEmmanuel Vadot #define XGBE_SFP_BASE_BR_10GBE_MAX		0x68
255445bed5cSStephan de Wit #define XGBE_SFP_BASE_BR_25GBE			0xFF
256445bed5cSStephan de Wit 
257445bed5cSStephan de Wit /* Single mode, length of fiber in units of km */
258445bed5cSStephan de Wit #define XGBE_SFP_BASE_SM_LEN_KM			14
259445bed5cSStephan de Wit #define XGBE_SFP_BASE_SM_LEN_KM_MIN		0x0A
260445bed5cSStephan de Wit 
261445bed5cSStephan de Wit /* Single mode, length of fiber in units of 100m */
262445bed5cSStephan de Wit #define XGBE_SFP_BASE_SM_LEN_100M		15
263445bed5cSStephan de Wit #define XGBE_SFP_BASE_SM_LEN_100M_MIN		0x64
2647113afc8SEmmanuel Vadot 
2657113afc8SEmmanuel Vadot #define XGBE_SFP_BASE_CU_CABLE_LEN		18
2667113afc8SEmmanuel Vadot 
2677113afc8SEmmanuel Vadot #define XGBE_SFP_BASE_VENDOR_NAME		20
2687113afc8SEmmanuel Vadot #define XGBE_SFP_BASE_VENDOR_NAME_LEN		16
2697113afc8SEmmanuel Vadot #define XGBE_SFP_BASE_VENDOR_PN			40
2707113afc8SEmmanuel Vadot #define XGBE_SFP_BASE_VENDOR_PN_LEN		16
2717113afc8SEmmanuel Vadot #define XGBE_SFP_BASE_VENDOR_REV		56
2727113afc8SEmmanuel Vadot #define XGBE_SFP_BASE_VENDOR_REV_LEN		4
2737113afc8SEmmanuel Vadot 
274445bed5cSStephan de Wit /*
275445bed5cSStephan de Wit  * Optical specification compliance - denotes wavelength
276445bed5cSStephan de Wit  * for optical tranceivers
277445bed5cSStephan de Wit  */
278445bed5cSStephan de Wit #define XGBE_SFP_BASE_OSC			60
279445bed5cSStephan de Wit #define XGBE_SFP_BASE_OSC_LEN			2
280445bed5cSStephan de Wit #define XGBE_SFP_BASE_OSC_1310			0x051E
281445bed5cSStephan de Wit 
2827113afc8SEmmanuel Vadot #define XGBE_SFP_BASE_CC			63
2837113afc8SEmmanuel Vadot 
2847113afc8SEmmanuel Vadot /* SFP Serial ID Extended ID values relative to an offset of 64 */
2857113afc8SEmmanuel Vadot #define XGBE_SFP_BASE_VENDOR_SN			4
2867113afc8SEmmanuel Vadot #define XGBE_SFP_BASE_VENDOR_SN_LEN		16
2877113afc8SEmmanuel Vadot 
2887113afc8SEmmanuel Vadot #define XGBE_SFP_EXTD_OPT1			1
2897113afc8SEmmanuel Vadot #define XGBE_SFP_EXTD_OPT1_RX_LOS		BIT(1)
2907113afc8SEmmanuel Vadot #define XGBE_SFP_EXTD_OPT1_TX_FAULT		BIT(3)
2917113afc8SEmmanuel Vadot 
2927113afc8SEmmanuel Vadot #define XGBE_SFP_EXTD_DIAG			28
2937113afc8SEmmanuel Vadot #define XGBE_SFP_EXTD_DIAG_ADDR_CHANGE		BIT(2)
2947113afc8SEmmanuel Vadot 
2957113afc8SEmmanuel Vadot #define XGBE_SFP_EXTD_SFF_8472			30
2967113afc8SEmmanuel Vadot 
2977113afc8SEmmanuel Vadot #define XGBE_SFP_EXTD_CC			31
2987113afc8SEmmanuel Vadot 
2997113afc8SEmmanuel Vadot struct xgbe_sfp_eeprom {
3007113afc8SEmmanuel Vadot 	uint8_t base[64];
3017113afc8SEmmanuel Vadot 	uint8_t extd[32];
3027113afc8SEmmanuel Vadot 	uint8_t vendor[32];
3037113afc8SEmmanuel Vadot };
3047113afc8SEmmanuel Vadot 
3057113afc8SEmmanuel Vadot #define XGBE_SFP_DIAGS_SUPPORTED(_x)			\
3067113afc8SEmmanuel Vadot 	((_x)->extd[XGBE_SFP_EXTD_SFF_8472] &&		\
3077113afc8SEmmanuel Vadot 	 !((_x)->extd[XGBE_SFP_EXTD_DIAG] & XGBE_SFP_EXTD_DIAG_ADDR_CHANGE))
3087113afc8SEmmanuel Vadot 
3097113afc8SEmmanuel Vadot #define XGBE_SFP_EEPROM_BASE_LEN		256
3107113afc8SEmmanuel Vadot #define XGBE_SFP_EEPROM_DIAG_LEN		256
3117113afc8SEmmanuel Vadot #define XGBE_SFP_EEPROM_MAX			(XGBE_SFP_EEPROM_BASE_LEN +	\
3127113afc8SEmmanuel Vadot 					 	XGBE_SFP_EEPROM_DIAG_LEN)
3137113afc8SEmmanuel Vadot 
3147113afc8SEmmanuel Vadot #define XGBE_BEL_FUSE_VENDOR			"BEL-FUSE        "
3157113afc8SEmmanuel Vadot #define XGBE_BEL_FUSE_PARTNO			"1GBT-SFP06      "
3167113afc8SEmmanuel Vadot 
3177113afc8SEmmanuel Vadot struct xgbe_sfp_ascii {
3187113afc8SEmmanuel Vadot 	union {
3197113afc8SEmmanuel Vadot 		char vendor[XGBE_SFP_BASE_VENDOR_NAME_LEN + 1];
3207113afc8SEmmanuel Vadot 		char partno[XGBE_SFP_BASE_VENDOR_PN_LEN + 1];
3217113afc8SEmmanuel Vadot 		char rev[XGBE_SFP_BASE_VENDOR_REV_LEN + 1];
3227113afc8SEmmanuel Vadot 		char serno[XGBE_SFP_BASE_VENDOR_SN_LEN + 1];
3237113afc8SEmmanuel Vadot 	} u;
3247113afc8SEmmanuel Vadot };
3257113afc8SEmmanuel Vadot 
3267113afc8SEmmanuel Vadot /* MDIO PHY reset types */
3277113afc8SEmmanuel Vadot enum xgbe_mdio_reset {
3287113afc8SEmmanuel Vadot 	XGBE_MDIO_RESET_NONE = 0,
3297113afc8SEmmanuel Vadot 	XGBE_MDIO_RESET_I2C_GPIO,
3307113afc8SEmmanuel Vadot 	XGBE_MDIO_RESET_INT_GPIO,
3317113afc8SEmmanuel Vadot 	XGBE_MDIO_RESET_MAX,
3327113afc8SEmmanuel Vadot };
3337113afc8SEmmanuel Vadot 
3347113afc8SEmmanuel Vadot /* Re-driver related definitions */
3357113afc8SEmmanuel Vadot enum xgbe_phy_redrv_if {
3367113afc8SEmmanuel Vadot 	XGBE_PHY_REDRV_IF_MDIO = 0,
3377113afc8SEmmanuel Vadot 	XGBE_PHY_REDRV_IF_I2C,
3387113afc8SEmmanuel Vadot 	XGBE_PHY_REDRV_IF_MAX,
3397113afc8SEmmanuel Vadot };
3407113afc8SEmmanuel Vadot 
3417113afc8SEmmanuel Vadot enum xgbe_phy_redrv_model {
3427113afc8SEmmanuel Vadot 	XGBE_PHY_REDRV_MODEL_4223 = 0,
3437113afc8SEmmanuel Vadot 	XGBE_PHY_REDRV_MODEL_4227,
3447113afc8SEmmanuel Vadot 	XGBE_PHY_REDRV_MODEL_MAX,
3457113afc8SEmmanuel Vadot };
3467113afc8SEmmanuel Vadot 
3477113afc8SEmmanuel Vadot enum xgbe_phy_redrv_mode {
3487113afc8SEmmanuel Vadot 	XGBE_PHY_REDRV_MODE_CX = 5,
3497113afc8SEmmanuel Vadot 	XGBE_PHY_REDRV_MODE_SR = 9,
3507113afc8SEmmanuel Vadot };
3517113afc8SEmmanuel Vadot 
3527113afc8SEmmanuel Vadot #define XGBE_PHY_REDRV_MODE_REG	0x12b0
3537113afc8SEmmanuel Vadot 
3547113afc8SEmmanuel Vadot /* PHY related configuration information */
3557113afc8SEmmanuel Vadot struct xgbe_phy_data {
3567113afc8SEmmanuel Vadot 	enum xgbe_port_mode port_mode;
3577113afc8SEmmanuel Vadot 
3587113afc8SEmmanuel Vadot 	unsigned int port_id;
3597113afc8SEmmanuel Vadot 
3607113afc8SEmmanuel Vadot 	unsigned int port_speeds;
3617113afc8SEmmanuel Vadot 
3627113afc8SEmmanuel Vadot 	enum xgbe_conn_type conn_type;
3637113afc8SEmmanuel Vadot 
3647113afc8SEmmanuel Vadot 	enum xgbe_mode cur_mode;
3657113afc8SEmmanuel Vadot 	enum xgbe_mode start_mode;
3667113afc8SEmmanuel Vadot 
3677113afc8SEmmanuel Vadot 	unsigned int rrc_count;
3687113afc8SEmmanuel Vadot 
3697113afc8SEmmanuel Vadot 	unsigned int mdio_addr;
3707113afc8SEmmanuel Vadot 
3717113afc8SEmmanuel Vadot 	/* SFP Support */
3727113afc8SEmmanuel Vadot 	enum xgbe_sfp_comm sfp_comm;
3737113afc8SEmmanuel Vadot 	unsigned int sfp_mux_address;
3747113afc8SEmmanuel Vadot 	unsigned int sfp_mux_channel;
3757113afc8SEmmanuel Vadot 
3767113afc8SEmmanuel Vadot 	unsigned int sfp_gpio_address;
3777113afc8SEmmanuel Vadot 	unsigned int sfp_gpio_mask;
3787113afc8SEmmanuel Vadot 	unsigned int sfp_gpio_inputs;
3792b8df536SStephan de Wit 	unsigned int sfp_gpio_outputs;
3802b8df536SStephan de Wit 	unsigned int sfp_gpio_polarity;
3812b8df536SStephan de Wit 	unsigned int sfp_gpio_configuration;
3827113afc8SEmmanuel Vadot 	unsigned int sfp_gpio_rx_los;
3837113afc8SEmmanuel Vadot 	unsigned int sfp_gpio_tx_fault;
3847113afc8SEmmanuel Vadot 	unsigned int sfp_gpio_mod_absent;
3857113afc8SEmmanuel Vadot 	unsigned int sfp_gpio_rate_select;
3867113afc8SEmmanuel Vadot 
3877113afc8SEmmanuel Vadot 	unsigned int sfp_rx_los;
3887113afc8SEmmanuel Vadot 	unsigned int sfp_tx_fault;
3897113afc8SEmmanuel Vadot 	unsigned int sfp_mod_absent;
3907113afc8SEmmanuel Vadot 	unsigned int sfp_changed;
3917113afc8SEmmanuel Vadot 	unsigned int sfp_phy_avail;
3927113afc8SEmmanuel Vadot 	unsigned int sfp_cable_len;
3937113afc8SEmmanuel Vadot 	enum xgbe_sfp_base sfp_base;
3947113afc8SEmmanuel Vadot 	enum xgbe_sfp_cable sfp_cable;
3957113afc8SEmmanuel Vadot 	enum xgbe_sfp_speed sfp_speed;
3967113afc8SEmmanuel Vadot 	struct xgbe_sfp_eeprom sfp_eeprom;
3977113afc8SEmmanuel Vadot 
3987113afc8SEmmanuel Vadot 	/* External PHY support */
3997113afc8SEmmanuel Vadot 	enum xgbe_mdio_mode phydev_mode;
4007113afc8SEmmanuel Vadot 	uint32_t phy_id;
4017113afc8SEmmanuel Vadot 	int phydev;
4027113afc8SEmmanuel Vadot 	enum xgbe_mdio_reset mdio_reset;
4037113afc8SEmmanuel Vadot 	unsigned int mdio_reset_addr;
4047113afc8SEmmanuel Vadot 	unsigned int mdio_reset_gpio;
405445bed5cSStephan de Wit 	int sfp_phy_retries;
4067113afc8SEmmanuel Vadot 
4077113afc8SEmmanuel Vadot 	/* Re-driver support */
4087113afc8SEmmanuel Vadot 	unsigned int redrv;
4097113afc8SEmmanuel Vadot 	unsigned int redrv_if;
4107113afc8SEmmanuel Vadot 	unsigned int redrv_addr;
4117113afc8SEmmanuel Vadot 	unsigned int redrv_lane;
4127113afc8SEmmanuel Vadot 	unsigned int redrv_model;
4137113afc8SEmmanuel Vadot 
4147113afc8SEmmanuel Vadot 	/* KR AN support */
4157113afc8SEmmanuel Vadot 	unsigned int phy_cdr_notrack;
4167113afc8SEmmanuel Vadot 	unsigned int phy_cdr_delay;
4177113afc8SEmmanuel Vadot 
4187113afc8SEmmanuel Vadot 	uint8_t port_sfp_inputs;
4197113afc8SEmmanuel Vadot };
4207113afc8SEmmanuel Vadot 
4217113afc8SEmmanuel Vadot static enum xgbe_an_mode xgbe_phy_an_mode(struct xgbe_prv_data *pdata);
422bfd75d45SVincenzo Maffione static int xgbe_phy_reset(struct xgbe_prv_data *pdata);
423445bed5cSStephan de Wit static int axgbe_ifmedia_upd(struct ifnet *ifp);
424445bed5cSStephan de Wit static void axgbe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr);
4257113afc8SEmmanuel Vadot 
4267113afc8SEmmanuel Vadot static int
xgbe_phy_i2c_xfer(struct xgbe_prv_data * pdata,struct xgbe_i2c_op * i2c_op)4277113afc8SEmmanuel Vadot xgbe_phy_i2c_xfer(struct xgbe_prv_data *pdata, struct xgbe_i2c_op *i2c_op)
4287113afc8SEmmanuel Vadot {
4297113afc8SEmmanuel Vadot 	return (pdata->i2c_if.i2c_xfer(pdata, i2c_op));
4307113afc8SEmmanuel Vadot }
4317113afc8SEmmanuel Vadot 
4327113afc8SEmmanuel Vadot static int
xgbe_phy_redrv_write(struct xgbe_prv_data * pdata,unsigned int reg,unsigned int val)4337113afc8SEmmanuel Vadot xgbe_phy_redrv_write(struct xgbe_prv_data *pdata, unsigned int reg,
4347113afc8SEmmanuel Vadot     unsigned int val)
4357113afc8SEmmanuel Vadot {
4367113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
4377113afc8SEmmanuel Vadot 	struct xgbe_i2c_op i2c_op;
4387113afc8SEmmanuel Vadot 	__be16 *redrv_val;
4397113afc8SEmmanuel Vadot 	uint8_t redrv_data[5], csum;
4407113afc8SEmmanuel Vadot 	unsigned int i, retry;
4417113afc8SEmmanuel Vadot 	int ret;
4427113afc8SEmmanuel Vadot 
4437113afc8SEmmanuel Vadot 	/* High byte of register contains read/write indicator */
4447113afc8SEmmanuel Vadot 	redrv_data[0] = ((reg >> 8) & 0xff) << 1;
4457113afc8SEmmanuel Vadot 	redrv_data[1] = reg & 0xff;
4467113afc8SEmmanuel Vadot 	redrv_val = (__be16 *)&redrv_data[2];
4477113afc8SEmmanuel Vadot 	*redrv_val = cpu_to_be16(val);
4487113afc8SEmmanuel Vadot 
4497113afc8SEmmanuel Vadot 	/* Calculate 1 byte checksum */
4507113afc8SEmmanuel Vadot 	csum = 0;
4517113afc8SEmmanuel Vadot 	for (i = 0; i < 4; i++) {
4527113afc8SEmmanuel Vadot 		csum += redrv_data[i];
4537113afc8SEmmanuel Vadot 		if (redrv_data[i] > csum)
4547113afc8SEmmanuel Vadot 			csum++;
4557113afc8SEmmanuel Vadot 	}
4567113afc8SEmmanuel Vadot 	redrv_data[4] = ~csum;
4577113afc8SEmmanuel Vadot 
4587113afc8SEmmanuel Vadot 	retry = 1;
4597113afc8SEmmanuel Vadot again1:
4607113afc8SEmmanuel Vadot 	i2c_op.cmd = XGBE_I2C_CMD_WRITE;
4617113afc8SEmmanuel Vadot 	i2c_op.target = phy_data->redrv_addr;
4627113afc8SEmmanuel Vadot 	i2c_op.len = sizeof(redrv_data);
4637113afc8SEmmanuel Vadot 	i2c_op.buf = redrv_data;
4647113afc8SEmmanuel Vadot 	ret = xgbe_phy_i2c_xfer(pdata, &i2c_op);
4657113afc8SEmmanuel Vadot 	if (ret) {
4667113afc8SEmmanuel Vadot 		if ((ret == -EAGAIN) && retry--)
4677113afc8SEmmanuel Vadot 			goto again1;
4687113afc8SEmmanuel Vadot 
4697113afc8SEmmanuel Vadot 		return (ret);
4707113afc8SEmmanuel Vadot 	}
4717113afc8SEmmanuel Vadot 
4727113afc8SEmmanuel Vadot 	retry = 1;
4737113afc8SEmmanuel Vadot again2:
4747113afc8SEmmanuel Vadot 	i2c_op.cmd = XGBE_I2C_CMD_READ;
4757113afc8SEmmanuel Vadot 	i2c_op.target = phy_data->redrv_addr;
4767113afc8SEmmanuel Vadot 	i2c_op.len = 1;
4777113afc8SEmmanuel Vadot 	i2c_op.buf = redrv_data;
4787113afc8SEmmanuel Vadot 	ret = xgbe_phy_i2c_xfer(pdata, &i2c_op);
4797113afc8SEmmanuel Vadot 	if (ret) {
4807113afc8SEmmanuel Vadot 		if ((ret == -EAGAIN) && retry--)
4817113afc8SEmmanuel Vadot 			goto again2;
4827113afc8SEmmanuel Vadot 
4837113afc8SEmmanuel Vadot 		return (ret);
4847113afc8SEmmanuel Vadot 	}
4857113afc8SEmmanuel Vadot 
4867113afc8SEmmanuel Vadot 	if (redrv_data[0] != 0xff) {
4877113afc8SEmmanuel Vadot 		axgbe_error("Redriver write checksum error\n");
4887113afc8SEmmanuel Vadot 		ret = -EIO;
4897113afc8SEmmanuel Vadot 	}
4907113afc8SEmmanuel Vadot 
4917113afc8SEmmanuel Vadot 	return (ret);
4927113afc8SEmmanuel Vadot }
4937113afc8SEmmanuel Vadot 
4947113afc8SEmmanuel Vadot static int
xgbe_phy_i2c_write(struct xgbe_prv_data * pdata,unsigned int target,void * val,unsigned int val_len)4957113afc8SEmmanuel Vadot xgbe_phy_i2c_write(struct xgbe_prv_data *pdata, unsigned int target, void *val,
4967113afc8SEmmanuel Vadot     unsigned int val_len)
4977113afc8SEmmanuel Vadot {
4987113afc8SEmmanuel Vadot 	struct xgbe_i2c_op i2c_op;
4997113afc8SEmmanuel Vadot 	int retry, ret;
5007113afc8SEmmanuel Vadot 
5017113afc8SEmmanuel Vadot 	retry = 1;
5027113afc8SEmmanuel Vadot again:
5037113afc8SEmmanuel Vadot 	/* Write the specfied register */
5047113afc8SEmmanuel Vadot 	i2c_op.cmd = XGBE_I2C_CMD_WRITE;
5057113afc8SEmmanuel Vadot 	i2c_op.target = target;
5067113afc8SEmmanuel Vadot 	i2c_op.len = val_len;
5077113afc8SEmmanuel Vadot 	i2c_op.buf = val;
5087113afc8SEmmanuel Vadot 	ret = xgbe_phy_i2c_xfer(pdata, &i2c_op);
5097113afc8SEmmanuel Vadot 	if ((ret == -EAGAIN) && retry--)
5107113afc8SEmmanuel Vadot 		goto again;
5117113afc8SEmmanuel Vadot 
5127113afc8SEmmanuel Vadot 	return (ret);
5137113afc8SEmmanuel Vadot }
5147113afc8SEmmanuel Vadot 
5157113afc8SEmmanuel Vadot static int
xgbe_phy_i2c_read(struct xgbe_prv_data * pdata,unsigned int target,void * reg,unsigned int reg_len,void * val,unsigned int val_len)5167113afc8SEmmanuel Vadot xgbe_phy_i2c_read(struct xgbe_prv_data *pdata, unsigned int target, void *reg,
5177113afc8SEmmanuel Vadot     unsigned int reg_len, void *val, unsigned int val_len)
5187113afc8SEmmanuel Vadot {
5197113afc8SEmmanuel Vadot 	struct xgbe_i2c_op i2c_op;
5207113afc8SEmmanuel Vadot 	int retry, ret;
5217113afc8SEmmanuel Vadot 
5227113afc8SEmmanuel Vadot 	axgbe_printf(3, "%s: target 0x%x reg_len %d val_len %d\n", __func__,
5237113afc8SEmmanuel Vadot 	    target, reg_len, val_len);
5247113afc8SEmmanuel Vadot 	retry = 1;
5257113afc8SEmmanuel Vadot again1:
5267113afc8SEmmanuel Vadot 	/* Set the specified register to read */
5277113afc8SEmmanuel Vadot 	i2c_op.cmd = XGBE_I2C_CMD_WRITE;
5287113afc8SEmmanuel Vadot 	i2c_op.target = target;
5297113afc8SEmmanuel Vadot 	i2c_op.len = reg_len;
5307113afc8SEmmanuel Vadot 	i2c_op.buf = reg;
5317113afc8SEmmanuel Vadot 	ret = xgbe_phy_i2c_xfer(pdata, &i2c_op);
5327113afc8SEmmanuel Vadot 	axgbe_printf(3, "%s: ret1 %d retry %d\n", __func__, ret, retry);
5337113afc8SEmmanuel Vadot 	if (ret) {
5347113afc8SEmmanuel Vadot 		if ((ret == -EAGAIN) && retry--)
5357113afc8SEmmanuel Vadot 			goto again1;
5367113afc8SEmmanuel Vadot 
5377113afc8SEmmanuel Vadot 		return (ret);
5387113afc8SEmmanuel Vadot 	}
5397113afc8SEmmanuel Vadot 
5407113afc8SEmmanuel Vadot 	retry = 1;
5417113afc8SEmmanuel Vadot again2:
5427113afc8SEmmanuel Vadot 	/* Read the specfied register */
5437113afc8SEmmanuel Vadot 	i2c_op.cmd = XGBE_I2C_CMD_READ;
5447113afc8SEmmanuel Vadot 	i2c_op.target = target;
5457113afc8SEmmanuel Vadot 	i2c_op.len = val_len;
5467113afc8SEmmanuel Vadot 	i2c_op.buf = val;
5477113afc8SEmmanuel Vadot 	ret = xgbe_phy_i2c_xfer(pdata, &i2c_op);
5487113afc8SEmmanuel Vadot 	axgbe_printf(3, "%s: ret2 %d retry %d\n", __func__, ret, retry);
5497113afc8SEmmanuel Vadot 	if ((ret == -EAGAIN) && retry--)
5507113afc8SEmmanuel Vadot 		goto again2;
5517113afc8SEmmanuel Vadot 
5527113afc8SEmmanuel Vadot 	return (ret);
5537113afc8SEmmanuel Vadot }
5547113afc8SEmmanuel Vadot 
5557113afc8SEmmanuel Vadot static int
xgbe_phy_sfp_put_mux(struct xgbe_prv_data * pdata)5567113afc8SEmmanuel Vadot xgbe_phy_sfp_put_mux(struct xgbe_prv_data *pdata)
5577113afc8SEmmanuel Vadot {
5587113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
5597113afc8SEmmanuel Vadot 	struct xgbe_i2c_op i2c_op;
5607113afc8SEmmanuel Vadot 	uint8_t mux_channel;
5617113afc8SEmmanuel Vadot 
5627113afc8SEmmanuel Vadot 	if (phy_data->sfp_comm == XGBE_SFP_COMM_DIRECT)
5637113afc8SEmmanuel Vadot 		return (0);
5647113afc8SEmmanuel Vadot 
5657113afc8SEmmanuel Vadot 	/* Select no mux channels */
5667113afc8SEmmanuel Vadot 	mux_channel = 0;
5677113afc8SEmmanuel Vadot 	i2c_op.cmd = XGBE_I2C_CMD_WRITE;
5687113afc8SEmmanuel Vadot 	i2c_op.target = phy_data->sfp_mux_address;
5697113afc8SEmmanuel Vadot 	i2c_op.len = sizeof(mux_channel);
5707113afc8SEmmanuel Vadot 	i2c_op.buf = &mux_channel;
5717113afc8SEmmanuel Vadot 
5727113afc8SEmmanuel Vadot 	return (xgbe_phy_i2c_xfer(pdata, &i2c_op));
5737113afc8SEmmanuel Vadot }
5747113afc8SEmmanuel Vadot 
5757113afc8SEmmanuel Vadot static int
xgbe_phy_sfp_get_mux(struct xgbe_prv_data * pdata)5767113afc8SEmmanuel Vadot xgbe_phy_sfp_get_mux(struct xgbe_prv_data *pdata)
5777113afc8SEmmanuel Vadot {
5787113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
5797113afc8SEmmanuel Vadot 	struct xgbe_i2c_op i2c_op;
5807113afc8SEmmanuel Vadot 	uint8_t mux_channel;
5817113afc8SEmmanuel Vadot 
5827113afc8SEmmanuel Vadot 	if (phy_data->sfp_comm == XGBE_SFP_COMM_DIRECT)
5837113afc8SEmmanuel Vadot 		return (0);
5847113afc8SEmmanuel Vadot 
5857113afc8SEmmanuel Vadot 	/* Select desired mux channel */
5867113afc8SEmmanuel Vadot 	mux_channel = 1 << phy_data->sfp_mux_channel;
5877113afc8SEmmanuel Vadot 	i2c_op.cmd = XGBE_I2C_CMD_WRITE;
5887113afc8SEmmanuel Vadot 	i2c_op.target = phy_data->sfp_mux_address;
5897113afc8SEmmanuel Vadot 	i2c_op.len = sizeof(mux_channel);
5907113afc8SEmmanuel Vadot 	i2c_op.buf = &mux_channel;
5917113afc8SEmmanuel Vadot 
5927113afc8SEmmanuel Vadot 	return (xgbe_phy_i2c_xfer(pdata, &i2c_op));
5937113afc8SEmmanuel Vadot }
5947113afc8SEmmanuel Vadot 
5957113afc8SEmmanuel Vadot static void
xgbe_phy_put_comm_ownership(struct xgbe_prv_data * pdata)5967113afc8SEmmanuel Vadot xgbe_phy_put_comm_ownership(struct xgbe_prv_data *pdata)
5977113afc8SEmmanuel Vadot {
5987113afc8SEmmanuel Vadot 	mtx_unlock(&xgbe_phy_comm_lock);
5997113afc8SEmmanuel Vadot }
6007113afc8SEmmanuel Vadot 
6017113afc8SEmmanuel Vadot static int
xgbe_phy_get_comm_ownership(struct xgbe_prv_data * pdata)6027113afc8SEmmanuel Vadot xgbe_phy_get_comm_ownership(struct xgbe_prv_data *pdata)
6037113afc8SEmmanuel Vadot {
6047113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
6057113afc8SEmmanuel Vadot 	unsigned long timeout;
6067113afc8SEmmanuel Vadot 	unsigned int mutex_id;
6077113afc8SEmmanuel Vadot 
6087113afc8SEmmanuel Vadot 	/* The I2C and MDIO/GPIO bus is multiplexed between multiple devices,
6097113afc8SEmmanuel Vadot 	 * the driver needs to take the software mutex and then the hardware
6107113afc8SEmmanuel Vadot 	 * mutexes before being able to use the busses.
6117113afc8SEmmanuel Vadot 	 */
6127113afc8SEmmanuel Vadot 	mtx_lock(&xgbe_phy_comm_lock);
6137113afc8SEmmanuel Vadot 
6147113afc8SEmmanuel Vadot 	/* Clear the mutexes */
6157113afc8SEmmanuel Vadot 	XP_IOWRITE(pdata, XP_I2C_MUTEX, XGBE_MUTEX_RELEASE);
6167113afc8SEmmanuel Vadot 	XP_IOWRITE(pdata, XP_MDIO_MUTEX, XGBE_MUTEX_RELEASE);
6177113afc8SEmmanuel Vadot 
6187113afc8SEmmanuel Vadot 	/* Mutex formats are the same for I2C and MDIO/GPIO */
6197113afc8SEmmanuel Vadot 	mutex_id = 0;
6207113afc8SEmmanuel Vadot 	XP_SET_BITS(mutex_id, XP_I2C_MUTEX, ID, phy_data->port_id);
6217113afc8SEmmanuel Vadot 	XP_SET_BITS(mutex_id, XP_I2C_MUTEX, ACTIVE, 1);
6227113afc8SEmmanuel Vadot 
6237113afc8SEmmanuel Vadot 	timeout = ticks + (5 * hz);
6247113afc8SEmmanuel Vadot 	while (ticks < timeout) {
6257113afc8SEmmanuel Vadot 		/* Must be all zeroes in order to obtain the mutex */
6267113afc8SEmmanuel Vadot 		if (XP_IOREAD(pdata, XP_I2C_MUTEX) ||
6277113afc8SEmmanuel Vadot 		    XP_IOREAD(pdata, XP_MDIO_MUTEX)) {
6287113afc8SEmmanuel Vadot 			DELAY(200);
6297113afc8SEmmanuel Vadot 			continue;
6307113afc8SEmmanuel Vadot 		}
6317113afc8SEmmanuel Vadot 
6327113afc8SEmmanuel Vadot 		/* Obtain the mutex */
6337113afc8SEmmanuel Vadot 		XP_IOWRITE(pdata, XP_I2C_MUTEX, mutex_id);
6347113afc8SEmmanuel Vadot 		XP_IOWRITE(pdata, XP_MDIO_MUTEX, mutex_id);
6357113afc8SEmmanuel Vadot 
6367113afc8SEmmanuel Vadot 		return (0);
6377113afc8SEmmanuel Vadot 	}
6387113afc8SEmmanuel Vadot 
6397113afc8SEmmanuel Vadot 	mtx_unlock(&xgbe_phy_comm_lock);
6407113afc8SEmmanuel Vadot 
6417113afc8SEmmanuel Vadot 	axgbe_error("unable to obtain hardware mutexes\n");
6427113afc8SEmmanuel Vadot 
6437113afc8SEmmanuel Vadot 	return (-ETIMEDOUT);
6447113afc8SEmmanuel Vadot }
6457113afc8SEmmanuel Vadot 
6467113afc8SEmmanuel Vadot static int
xgbe_phy_mdio_mii_write(struct xgbe_prv_data * pdata,int addr,int reg,uint16_t val)6477113afc8SEmmanuel Vadot xgbe_phy_mdio_mii_write(struct xgbe_prv_data *pdata, int addr, int reg,
6487113afc8SEmmanuel Vadot     uint16_t val)
6497113afc8SEmmanuel Vadot {
6507113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
6517113afc8SEmmanuel Vadot 
6527113afc8SEmmanuel Vadot 	if (reg & MII_ADDR_C45) {
6537113afc8SEmmanuel Vadot 		if (phy_data->phydev_mode != XGBE_MDIO_MODE_CL45)
6547113afc8SEmmanuel Vadot 			return (-ENOTSUP);
6557113afc8SEmmanuel Vadot 	} else {
6567113afc8SEmmanuel Vadot 		if (phy_data->phydev_mode != XGBE_MDIO_MODE_CL22)
6577113afc8SEmmanuel Vadot 			return (-ENOTSUP);
6587113afc8SEmmanuel Vadot 	}
6597113afc8SEmmanuel Vadot 
6607113afc8SEmmanuel Vadot 	return (pdata->hw_if.write_ext_mii_regs(pdata, addr, reg, val));
6617113afc8SEmmanuel Vadot }
6627113afc8SEmmanuel Vadot 
6637113afc8SEmmanuel Vadot static int
xgbe_phy_i2c_mii_write(struct xgbe_prv_data * pdata,int reg,uint16_t val)6647113afc8SEmmanuel Vadot xgbe_phy_i2c_mii_write(struct xgbe_prv_data *pdata, int reg, uint16_t val)
6657113afc8SEmmanuel Vadot {
6667113afc8SEmmanuel Vadot 	__be16 *mii_val;
6677113afc8SEmmanuel Vadot 	uint8_t mii_data[3];
6687113afc8SEmmanuel Vadot 	int ret;
6697113afc8SEmmanuel Vadot 
6707113afc8SEmmanuel Vadot 	ret = xgbe_phy_sfp_get_mux(pdata);
6717113afc8SEmmanuel Vadot 	if (ret)
6727113afc8SEmmanuel Vadot 		return (ret);
6737113afc8SEmmanuel Vadot 
6747113afc8SEmmanuel Vadot 	mii_data[0] = reg & 0xff;
6757113afc8SEmmanuel Vadot 	mii_val = (__be16 *)&mii_data[1];
6767113afc8SEmmanuel Vadot 	*mii_val = cpu_to_be16(val);
6777113afc8SEmmanuel Vadot 
6787113afc8SEmmanuel Vadot 	ret = xgbe_phy_i2c_write(pdata, XGBE_SFP_PHY_ADDRESS,
6797113afc8SEmmanuel Vadot 				 mii_data, sizeof(mii_data));
6807113afc8SEmmanuel Vadot 
6817113afc8SEmmanuel Vadot 	xgbe_phy_sfp_put_mux(pdata);
6827113afc8SEmmanuel Vadot 
6837113afc8SEmmanuel Vadot 	return (ret);
6847113afc8SEmmanuel Vadot }
6857113afc8SEmmanuel Vadot 
6867113afc8SEmmanuel Vadot int
xgbe_phy_mii_write(struct xgbe_prv_data * pdata,int addr,int reg,uint16_t val)6877113afc8SEmmanuel Vadot xgbe_phy_mii_write(struct xgbe_prv_data *pdata, int addr, int reg, uint16_t val)
6887113afc8SEmmanuel Vadot {
6897113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
6907113afc8SEmmanuel Vadot 	int ret;
6917113afc8SEmmanuel Vadot 
6927113afc8SEmmanuel Vadot 	axgbe_printf(3, "%s: addr %d reg %d val %#x\n", __func__, addr, reg, val);
6937113afc8SEmmanuel Vadot 	ret = xgbe_phy_get_comm_ownership(pdata);
6947113afc8SEmmanuel Vadot 	if (ret)
6957113afc8SEmmanuel Vadot 		return (ret);
6967113afc8SEmmanuel Vadot 
6977113afc8SEmmanuel Vadot 	if (phy_data->conn_type == XGBE_CONN_TYPE_SFP)
6987113afc8SEmmanuel Vadot 		ret = xgbe_phy_i2c_mii_write(pdata, reg, val);
6997113afc8SEmmanuel Vadot 	else if (phy_data->conn_type & XGBE_CONN_TYPE_MDIO)
7007113afc8SEmmanuel Vadot 		ret = xgbe_phy_mdio_mii_write(pdata, addr, reg, val);
7017113afc8SEmmanuel Vadot 	else
7027113afc8SEmmanuel Vadot 		ret = -ENOTSUP;
7037113afc8SEmmanuel Vadot 
7047113afc8SEmmanuel Vadot 	xgbe_phy_put_comm_ownership(pdata);
7057113afc8SEmmanuel Vadot 
7067113afc8SEmmanuel Vadot 	return (ret);
7077113afc8SEmmanuel Vadot }
7087113afc8SEmmanuel Vadot 
7097113afc8SEmmanuel Vadot static int
xgbe_phy_mdio_mii_read(struct xgbe_prv_data * pdata,int addr,int reg)7107113afc8SEmmanuel Vadot xgbe_phy_mdio_mii_read(struct xgbe_prv_data *pdata, int addr, int reg)
7117113afc8SEmmanuel Vadot {
7127113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
7137113afc8SEmmanuel Vadot 
7147113afc8SEmmanuel Vadot 	if (reg & MII_ADDR_C45) {
7157113afc8SEmmanuel Vadot 		if (phy_data->phydev_mode != XGBE_MDIO_MODE_CL45)
7167113afc8SEmmanuel Vadot 			return (-ENOTSUP);
7177113afc8SEmmanuel Vadot 	} else {
7187113afc8SEmmanuel Vadot 		if (phy_data->phydev_mode != XGBE_MDIO_MODE_CL22)
7197113afc8SEmmanuel Vadot 			return (-ENOTSUP);
7207113afc8SEmmanuel Vadot 	}
7217113afc8SEmmanuel Vadot 
7227113afc8SEmmanuel Vadot 	return (pdata->hw_if.read_ext_mii_regs(pdata, addr, reg));
7237113afc8SEmmanuel Vadot }
7247113afc8SEmmanuel Vadot 
7257113afc8SEmmanuel Vadot static int
xgbe_phy_i2c_mii_read(struct xgbe_prv_data * pdata,int reg)7267113afc8SEmmanuel Vadot xgbe_phy_i2c_mii_read(struct xgbe_prv_data *pdata, int reg)
7277113afc8SEmmanuel Vadot {
7287113afc8SEmmanuel Vadot 	__be16 mii_val;
7297113afc8SEmmanuel Vadot 	uint8_t mii_reg;
7307113afc8SEmmanuel Vadot 	int ret;
7317113afc8SEmmanuel Vadot 
7327113afc8SEmmanuel Vadot 	ret = xgbe_phy_sfp_get_mux(pdata);
7337113afc8SEmmanuel Vadot 	if (ret)
7347113afc8SEmmanuel Vadot 		return (ret);
7357113afc8SEmmanuel Vadot 
7367113afc8SEmmanuel Vadot 	mii_reg = reg;
7377113afc8SEmmanuel Vadot 	ret = xgbe_phy_i2c_read(pdata, XGBE_SFP_PHY_ADDRESS,
7387113afc8SEmmanuel Vadot 				&mii_reg, sizeof(mii_reg),
7397113afc8SEmmanuel Vadot 				&mii_val, sizeof(mii_val));
7407113afc8SEmmanuel Vadot 	if (!ret)
7417113afc8SEmmanuel Vadot 		ret = be16_to_cpu(mii_val);
7427113afc8SEmmanuel Vadot 
7437113afc8SEmmanuel Vadot 	xgbe_phy_sfp_put_mux(pdata);
7447113afc8SEmmanuel Vadot 
7457113afc8SEmmanuel Vadot 	return (ret);
7467113afc8SEmmanuel Vadot }
7477113afc8SEmmanuel Vadot 
7487113afc8SEmmanuel Vadot int
xgbe_phy_mii_read(struct xgbe_prv_data * pdata,int addr,int reg)7497113afc8SEmmanuel Vadot xgbe_phy_mii_read(struct xgbe_prv_data *pdata, int addr, int reg)
7507113afc8SEmmanuel Vadot {
7517113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
7527113afc8SEmmanuel Vadot 	int ret;
7537113afc8SEmmanuel Vadot 
7547113afc8SEmmanuel Vadot 	axgbe_printf(3, "%s: addr %d reg %d\n", __func__, addr, reg);
7557113afc8SEmmanuel Vadot 	ret = xgbe_phy_get_comm_ownership(pdata);
7567113afc8SEmmanuel Vadot 	if (ret)
7577113afc8SEmmanuel Vadot 		return (ret);
7587113afc8SEmmanuel Vadot 
7597113afc8SEmmanuel Vadot 	if (phy_data->conn_type == XGBE_CONN_TYPE_SFP)
7607113afc8SEmmanuel Vadot 		ret = xgbe_phy_i2c_mii_read(pdata, reg);
7617113afc8SEmmanuel Vadot 	else if (phy_data->conn_type & XGBE_CONN_TYPE_MDIO)
7627113afc8SEmmanuel Vadot 		ret = xgbe_phy_mdio_mii_read(pdata, addr, reg);
7637113afc8SEmmanuel Vadot 	else
7647113afc8SEmmanuel Vadot 		ret = -ENOTSUP;
7657113afc8SEmmanuel Vadot 
7667113afc8SEmmanuel Vadot 	xgbe_phy_put_comm_ownership(pdata);
7677113afc8SEmmanuel Vadot 
7687113afc8SEmmanuel Vadot 	return (ret);
7697113afc8SEmmanuel Vadot }
7707113afc8SEmmanuel Vadot 
7717113afc8SEmmanuel Vadot static void
xgbe_phy_sfp_phy_settings(struct xgbe_prv_data * pdata)7727113afc8SEmmanuel Vadot xgbe_phy_sfp_phy_settings(struct xgbe_prv_data *pdata)
7737113afc8SEmmanuel Vadot {
7747113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
7757113afc8SEmmanuel Vadot 
7767113afc8SEmmanuel Vadot 	if (!phy_data->sfp_mod_absent && !phy_data->sfp_changed)
7777113afc8SEmmanuel Vadot 		return;
7787113afc8SEmmanuel Vadot 
7797113afc8SEmmanuel Vadot 	XGBE_ZERO_SUP(&pdata->phy);
7807113afc8SEmmanuel Vadot 
7817113afc8SEmmanuel Vadot 	if (phy_data->sfp_mod_absent) {
7827113afc8SEmmanuel Vadot 		pdata->phy.speed = SPEED_UNKNOWN;
7837113afc8SEmmanuel Vadot 		pdata->phy.duplex = DUPLEX_UNKNOWN;
7847113afc8SEmmanuel Vadot 		pdata->phy.autoneg = AUTONEG_ENABLE;
7857113afc8SEmmanuel Vadot 		pdata->phy.pause_autoneg = AUTONEG_ENABLE;
7867113afc8SEmmanuel Vadot 
7877113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, Autoneg);
7887113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, Pause);
7897113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, Asym_Pause);
7907113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, TP);
7917113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, FIBRE);
7927113afc8SEmmanuel Vadot 
7937113afc8SEmmanuel Vadot 		XGBE_LM_COPY(&pdata->phy, advertising, &pdata->phy, supported);
7947113afc8SEmmanuel Vadot 
7957113afc8SEmmanuel Vadot 		return;
7967113afc8SEmmanuel Vadot 	}
7977113afc8SEmmanuel Vadot 
7987113afc8SEmmanuel Vadot 	switch (phy_data->sfp_base) {
799445bed5cSStephan de Wit 	case XGBE_SFP_BASE_100_FX:
800445bed5cSStephan de Wit 	case XGBE_SFP_BASE_100_LX10:
801445bed5cSStephan de Wit 	case XGBE_SFP_BASE_100_BX:
802445bed5cSStephan de Wit 		pdata->phy.speed = SPEED_100;
803445bed5cSStephan de Wit 		pdata->phy.duplex = DUPLEX_FULL;
804445bed5cSStephan de Wit 		pdata->phy.autoneg = AUTONEG_DISABLE;
805445bed5cSStephan de Wit 		pdata->phy.pause_autoneg = AUTONEG_DISABLE;
806445bed5cSStephan de Wit 		break;
8077113afc8SEmmanuel Vadot 	case XGBE_SFP_BASE_1000_T:
8087113afc8SEmmanuel Vadot 	case XGBE_SFP_BASE_1000_SX:
8097113afc8SEmmanuel Vadot 	case XGBE_SFP_BASE_1000_LX:
8107113afc8SEmmanuel Vadot 	case XGBE_SFP_BASE_1000_CX:
8117113afc8SEmmanuel Vadot 		pdata->phy.speed = SPEED_UNKNOWN;
8127113afc8SEmmanuel Vadot 		pdata->phy.duplex = DUPLEX_UNKNOWN;
8137113afc8SEmmanuel Vadot 		pdata->phy.autoneg = AUTONEG_ENABLE;
8147113afc8SEmmanuel Vadot 		pdata->phy.pause_autoneg = AUTONEG_ENABLE;
8157113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, Autoneg);
8167113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, Pause);
8177113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, Asym_Pause);
8187113afc8SEmmanuel Vadot 		if (phy_data->sfp_base == XGBE_SFP_BASE_1000_T) {
8197113afc8SEmmanuel Vadot 			if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100)
8207113afc8SEmmanuel Vadot 				XGBE_SET_SUP(&pdata->phy, 100baseT_Full);
8217113afc8SEmmanuel Vadot 			if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000)
8227113afc8SEmmanuel Vadot 				XGBE_SET_SUP(&pdata->phy, 1000baseT_Full);
8237113afc8SEmmanuel Vadot 		} else {
8247113afc8SEmmanuel Vadot 			if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000)
8257113afc8SEmmanuel Vadot 				XGBE_SET_SUP(&pdata->phy, 1000baseX_Full);
8267113afc8SEmmanuel Vadot 		}
8277113afc8SEmmanuel Vadot 		break;
828445bed5cSStephan de Wit 	case XGBE_SFP_BASE_1000_BX:
829445bed5cSStephan de Wit 	case XGBE_SFP_BASE_PX:
830445bed5cSStephan de Wit 		pdata->phy.speed = SPEED_1000;
831445bed5cSStephan de Wit 		pdata->phy.duplex = DUPLEX_FULL;
832445bed5cSStephan de Wit 		pdata->phy.autoneg = AUTONEG_DISABLE;
833445bed5cSStephan de Wit 		pdata->phy.pause_autoneg = AUTONEG_DISABLE;
834445bed5cSStephan de Wit 		break;
8357113afc8SEmmanuel Vadot 	case XGBE_SFP_BASE_10000_SR:
8367113afc8SEmmanuel Vadot 	case XGBE_SFP_BASE_10000_LR:
8377113afc8SEmmanuel Vadot 	case XGBE_SFP_BASE_10000_LRM:
8387113afc8SEmmanuel Vadot 	case XGBE_SFP_BASE_10000_ER:
8397113afc8SEmmanuel Vadot 	case XGBE_SFP_BASE_10000_CR:
8407113afc8SEmmanuel Vadot 		pdata->phy.speed = SPEED_10000;
8417113afc8SEmmanuel Vadot 		pdata->phy.duplex = DUPLEX_FULL;
8427113afc8SEmmanuel Vadot 		pdata->phy.autoneg = AUTONEG_DISABLE;
8437113afc8SEmmanuel Vadot 		pdata->phy.pause_autoneg = AUTONEG_DISABLE;
8447113afc8SEmmanuel Vadot 		if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000) {
8457113afc8SEmmanuel Vadot 			switch (phy_data->sfp_base) {
8467113afc8SEmmanuel Vadot 			case XGBE_SFP_BASE_10000_SR:
8477113afc8SEmmanuel Vadot 				XGBE_SET_SUP(&pdata->phy, 10000baseSR_Full);
8487113afc8SEmmanuel Vadot 				break;
8497113afc8SEmmanuel Vadot 			case XGBE_SFP_BASE_10000_LR:
8507113afc8SEmmanuel Vadot 				XGBE_SET_SUP(&pdata->phy, 10000baseLR_Full);
8517113afc8SEmmanuel Vadot 				break;
8527113afc8SEmmanuel Vadot 			case XGBE_SFP_BASE_10000_LRM:
8537113afc8SEmmanuel Vadot 				XGBE_SET_SUP(&pdata->phy, 10000baseLRM_Full);
8547113afc8SEmmanuel Vadot 				break;
8557113afc8SEmmanuel Vadot 			case XGBE_SFP_BASE_10000_ER:
8567113afc8SEmmanuel Vadot 				XGBE_SET_SUP(&pdata->phy, 10000baseER_Full);
8577113afc8SEmmanuel Vadot 				break;
8587113afc8SEmmanuel Vadot 			case XGBE_SFP_BASE_10000_CR:
8597113afc8SEmmanuel Vadot 				XGBE_SET_SUP(&pdata->phy, 10000baseCR_Full);
8607113afc8SEmmanuel Vadot 				break;
8617113afc8SEmmanuel Vadot 			default:
8627113afc8SEmmanuel Vadot 				break;
8637113afc8SEmmanuel Vadot 			}
8647113afc8SEmmanuel Vadot 		}
8657113afc8SEmmanuel Vadot 		break;
8667113afc8SEmmanuel Vadot 	default:
8677113afc8SEmmanuel Vadot 		pdata->phy.speed = SPEED_UNKNOWN;
8687113afc8SEmmanuel Vadot 		pdata->phy.duplex = DUPLEX_UNKNOWN;
8697113afc8SEmmanuel Vadot 		pdata->phy.autoneg = AUTONEG_DISABLE;
8707113afc8SEmmanuel Vadot 		pdata->phy.pause_autoneg = AUTONEG_DISABLE;
8717113afc8SEmmanuel Vadot 		break;
8727113afc8SEmmanuel Vadot 	}
8737113afc8SEmmanuel Vadot 
8747113afc8SEmmanuel Vadot 	switch (phy_data->sfp_base) {
8757113afc8SEmmanuel Vadot 	case XGBE_SFP_BASE_1000_T:
8767113afc8SEmmanuel Vadot 	case XGBE_SFP_BASE_1000_CX:
8777113afc8SEmmanuel Vadot 	case XGBE_SFP_BASE_10000_CR:
8787113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, TP);
8797113afc8SEmmanuel Vadot 		break;
8807113afc8SEmmanuel Vadot 	default:
8817113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, FIBRE);
8827113afc8SEmmanuel Vadot 		break;
8837113afc8SEmmanuel Vadot 	}
8847113afc8SEmmanuel Vadot 
8857113afc8SEmmanuel Vadot 	XGBE_LM_COPY(&pdata->phy, advertising, &pdata->phy, supported);
8867113afc8SEmmanuel Vadot 
8877113afc8SEmmanuel Vadot 	axgbe_printf(1, "%s: link speed %d spf_base 0x%x pause_autoneg %d "
8887113afc8SEmmanuel Vadot 	    "advert 0x%x support 0x%x\n", __func__, pdata->phy.speed,
8897113afc8SEmmanuel Vadot 	    phy_data->sfp_base, pdata->phy.pause_autoneg,
8907113afc8SEmmanuel Vadot 	    pdata->phy.advertising, pdata->phy.supported);
8917113afc8SEmmanuel Vadot }
8927113afc8SEmmanuel Vadot 
8937113afc8SEmmanuel Vadot static bool
xgbe_phy_sfp_bit_rate(struct xgbe_sfp_eeprom * sfp_eeprom,enum xgbe_sfp_speed sfp_speed)8947113afc8SEmmanuel Vadot xgbe_phy_sfp_bit_rate(struct xgbe_sfp_eeprom *sfp_eeprom,
8957113afc8SEmmanuel Vadot     enum xgbe_sfp_speed sfp_speed)
8967113afc8SEmmanuel Vadot {
8977113afc8SEmmanuel Vadot 	uint8_t *sfp_base, min, max;
8987113afc8SEmmanuel Vadot 
8997113afc8SEmmanuel Vadot 	sfp_base = sfp_eeprom->base;
9007113afc8SEmmanuel Vadot 
9017113afc8SEmmanuel Vadot 	switch (sfp_speed) {
902445bed5cSStephan de Wit 	case XGBE_SFP_SPEED_100:
903445bed5cSStephan de Wit 		min = XGBE_SFP_BASE_BR_100M_MIN;
904445bed5cSStephan de Wit 		max = XGBE_SFP_BASE_BR_100M_MAX;
905445bed5cSStephan de Wit 		break;
9067113afc8SEmmanuel Vadot 	case XGBE_SFP_SPEED_1000:
9077113afc8SEmmanuel Vadot 		min = XGBE_SFP_BASE_BR_1GBE_MIN;
9087113afc8SEmmanuel Vadot 		max = XGBE_SFP_BASE_BR_1GBE_MAX;
9097113afc8SEmmanuel Vadot 		break;
9107113afc8SEmmanuel Vadot 	case XGBE_SFP_SPEED_10000:
9117113afc8SEmmanuel Vadot 		min = XGBE_SFP_BASE_BR_10GBE_MIN;
9127113afc8SEmmanuel Vadot 		max = XGBE_SFP_BASE_BR_10GBE_MAX;
9137113afc8SEmmanuel Vadot 		break;
914445bed5cSStephan de Wit 	case XGBE_SFP_SPEED_25000:
915445bed5cSStephan de Wit 		min = XGBE_SFP_BASE_BR_25GBE;
916445bed5cSStephan de Wit 		max = XGBE_SFP_BASE_BR_25GBE;
917445bed5cSStephan de Wit 		break;
9187113afc8SEmmanuel Vadot 	default:
9197113afc8SEmmanuel Vadot 		return (false);
9207113afc8SEmmanuel Vadot 	}
9217113afc8SEmmanuel Vadot 
9227113afc8SEmmanuel Vadot 	return ((sfp_base[XGBE_SFP_BASE_BR] >= min) &&
9237113afc8SEmmanuel Vadot 		(sfp_base[XGBE_SFP_BASE_BR] <= max));
9247113afc8SEmmanuel Vadot }
9257113afc8SEmmanuel Vadot 
9267113afc8SEmmanuel Vadot static void
xgbe_phy_free_phy_device(struct xgbe_prv_data * pdata)9277113afc8SEmmanuel Vadot xgbe_phy_free_phy_device(struct xgbe_prv_data *pdata)
9287113afc8SEmmanuel Vadot {
9297113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
9307113afc8SEmmanuel Vadot 
9317113afc8SEmmanuel Vadot 	if (phy_data->phydev)
9327113afc8SEmmanuel Vadot 		phy_data->phydev = 0;
933445bed5cSStephan de Wit 
934445bed5cSStephan de Wit 	if (pdata->axgbe_miibus != NULL) {
935445bed5cSStephan de Wit 		device_delete_child(pdata->dev, pdata->axgbe_miibus);
936445bed5cSStephan de Wit 		pdata->axgbe_miibus = NULL;
937445bed5cSStephan de Wit 	}
9387113afc8SEmmanuel Vadot }
9397113afc8SEmmanuel Vadot 
9407113afc8SEmmanuel Vadot static bool
xgbe_phy_finisar_phy_quirks(struct xgbe_prv_data * pdata)9417113afc8SEmmanuel Vadot xgbe_phy_finisar_phy_quirks(struct xgbe_prv_data *pdata)
9427113afc8SEmmanuel Vadot {
9437113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
9447113afc8SEmmanuel Vadot 	unsigned int phy_id = phy_data->phy_id;
9457113afc8SEmmanuel Vadot 
9467113afc8SEmmanuel Vadot 	if (phy_data->port_mode != XGBE_PORT_MODE_SFP)
9477113afc8SEmmanuel Vadot 		return (false);
9487113afc8SEmmanuel Vadot 
9497113afc8SEmmanuel Vadot 	if ((phy_id & 0xfffffff0) != 0x01ff0cc0)
9507113afc8SEmmanuel Vadot 		return (false);
9517113afc8SEmmanuel Vadot 
9527113afc8SEmmanuel Vadot 	/* Enable Base-T AN */
9537113afc8SEmmanuel Vadot 	xgbe_phy_mii_write(pdata, phy_data->mdio_addr, 0x16, 0x0001);
9547113afc8SEmmanuel Vadot 	xgbe_phy_mii_write(pdata, phy_data->mdio_addr, 0x00, 0x9140);
9557113afc8SEmmanuel Vadot 	xgbe_phy_mii_write(pdata, phy_data->mdio_addr, 0x16, 0x0000);
9567113afc8SEmmanuel Vadot 
9577113afc8SEmmanuel Vadot 	/* Enable SGMII at 100Base-T/1000Base-T Full Duplex */
9587113afc8SEmmanuel Vadot 	xgbe_phy_mii_write(pdata, phy_data->mdio_addr, 0x1b, 0x9084);
9597113afc8SEmmanuel Vadot 	xgbe_phy_mii_write(pdata, phy_data->mdio_addr, 0x09, 0x0e00);
9607113afc8SEmmanuel Vadot 	xgbe_phy_mii_write(pdata, phy_data->mdio_addr, 0x00, 0x8140);
9617113afc8SEmmanuel Vadot 	xgbe_phy_mii_write(pdata, phy_data->mdio_addr, 0x04, 0x0d01);
9627113afc8SEmmanuel Vadot 	xgbe_phy_mii_write(pdata, phy_data->mdio_addr, 0x00, 0x9140);
9637113afc8SEmmanuel Vadot 
9647113afc8SEmmanuel Vadot 	axgbe_printf(3, "Finisar PHY quirk in place\n");
9657113afc8SEmmanuel Vadot 
9667113afc8SEmmanuel Vadot 	return (true);
9677113afc8SEmmanuel Vadot }
9687113afc8SEmmanuel Vadot 
9697113afc8SEmmanuel Vadot static bool
xgbe_phy_belfuse_phy_quirks(struct xgbe_prv_data * pdata)9707113afc8SEmmanuel Vadot xgbe_phy_belfuse_phy_quirks(struct xgbe_prv_data *pdata)
9717113afc8SEmmanuel Vadot {
9727113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
9737113afc8SEmmanuel Vadot 	struct xgbe_sfp_eeprom *sfp_eeprom = &phy_data->sfp_eeprom;
9747113afc8SEmmanuel Vadot 	unsigned int phy_id = phy_data->phy_id;
9757113afc8SEmmanuel Vadot 	int reg;
9767113afc8SEmmanuel Vadot 
9777113afc8SEmmanuel Vadot 	if (phy_data->port_mode != XGBE_PORT_MODE_SFP)
9787113afc8SEmmanuel Vadot 		return (false);
9797113afc8SEmmanuel Vadot 
9807113afc8SEmmanuel Vadot 	if (memcmp(&sfp_eeprom->base[XGBE_SFP_BASE_VENDOR_NAME],
9817113afc8SEmmanuel Vadot 		   XGBE_BEL_FUSE_VENDOR, XGBE_SFP_BASE_VENDOR_NAME_LEN))
9827113afc8SEmmanuel Vadot 		return (false);
9837113afc8SEmmanuel Vadot 
9847113afc8SEmmanuel Vadot 	/* For Bel-Fuse, use the extra AN flag */
9857113afc8SEmmanuel Vadot 	pdata->an_again = 1;
9867113afc8SEmmanuel Vadot 
9877113afc8SEmmanuel Vadot 	if (memcmp(&sfp_eeprom->base[XGBE_SFP_BASE_VENDOR_PN],
9887113afc8SEmmanuel Vadot 		   XGBE_BEL_FUSE_PARTNO, XGBE_SFP_BASE_VENDOR_PN_LEN))
9897113afc8SEmmanuel Vadot 		return (false);
9907113afc8SEmmanuel Vadot 
9917113afc8SEmmanuel Vadot 	if ((phy_id & 0xfffffff0) != 0x03625d10)
9927113afc8SEmmanuel Vadot 		return (false);
9937113afc8SEmmanuel Vadot 
9947113afc8SEmmanuel Vadot 	/* Disable RGMII mode */
9957113afc8SEmmanuel Vadot 	xgbe_phy_mii_write(pdata, phy_data->mdio_addr, 0x18, 0x7007);
9967113afc8SEmmanuel Vadot 	reg = xgbe_phy_mii_read(pdata, phy_data->mdio_addr, 0x18);
9977113afc8SEmmanuel Vadot 	xgbe_phy_mii_write(pdata, phy_data->mdio_addr, 0x18, reg & ~0x0080);
9987113afc8SEmmanuel Vadot 
9997113afc8SEmmanuel Vadot 	/* Enable fiber register bank */
10007113afc8SEmmanuel Vadot 	xgbe_phy_mii_write(pdata, phy_data->mdio_addr, 0x1c, 0x7c00);
10017113afc8SEmmanuel Vadot 	reg = xgbe_phy_mii_read(pdata, phy_data->mdio_addr, 0x1c);
10027113afc8SEmmanuel Vadot 	reg &= 0x03ff;
10037113afc8SEmmanuel Vadot 	reg &= ~0x0001;
10047113afc8SEmmanuel Vadot 	xgbe_phy_mii_write(pdata, phy_data->mdio_addr, 0x1c, 0x8000 | 0x7c00 |
10057113afc8SEmmanuel Vadot 	    reg | 0x0001);
10067113afc8SEmmanuel Vadot 
10077113afc8SEmmanuel Vadot 	/* Power down SerDes */
10087113afc8SEmmanuel Vadot 	reg = xgbe_phy_mii_read(pdata, phy_data->mdio_addr, 0x00);
10097113afc8SEmmanuel Vadot 	xgbe_phy_mii_write(pdata, phy_data->mdio_addr, 0x00, reg | 0x00800);
10107113afc8SEmmanuel Vadot 
10117113afc8SEmmanuel Vadot 	/* Configure SGMII-to-Copper mode */
10127113afc8SEmmanuel Vadot 	xgbe_phy_mii_write(pdata, phy_data->mdio_addr, 0x1c, 0x7c00);
10137113afc8SEmmanuel Vadot 	reg = xgbe_phy_mii_read(pdata, phy_data->mdio_addr, 0x1c);
10147113afc8SEmmanuel Vadot 	reg &= 0x03ff;
10157113afc8SEmmanuel Vadot 	reg &= ~0x0006;
10167113afc8SEmmanuel Vadot 	xgbe_phy_mii_write(pdata, phy_data->mdio_addr, 0x1c, 0x8000 | 0x7c00 |
10177113afc8SEmmanuel Vadot 	    reg | 0x0004);
10187113afc8SEmmanuel Vadot 
10197113afc8SEmmanuel Vadot 	/* Power up SerDes */
10207113afc8SEmmanuel Vadot 	reg = xgbe_phy_mii_read(pdata, phy_data->mdio_addr, 0x00);
10217113afc8SEmmanuel Vadot 	xgbe_phy_mii_write(pdata, phy_data->mdio_addr, 0x00, reg & ~0x00800);
10227113afc8SEmmanuel Vadot 
10237113afc8SEmmanuel Vadot 	/* Enable copper register bank */
10247113afc8SEmmanuel Vadot 	xgbe_phy_mii_write(pdata, phy_data->mdio_addr, 0x1c, 0x7c00);
10257113afc8SEmmanuel Vadot 	reg = xgbe_phy_mii_read(pdata, phy_data->mdio_addr, 0x1c);
10267113afc8SEmmanuel Vadot 	reg &= 0x03ff;
10277113afc8SEmmanuel Vadot 	reg &= ~0x0001;
10287113afc8SEmmanuel Vadot 	xgbe_phy_mii_write(pdata, phy_data->mdio_addr, 0x1c, 0x8000 | 0x7c00 |
10297113afc8SEmmanuel Vadot 	    reg);
10307113afc8SEmmanuel Vadot 
10317113afc8SEmmanuel Vadot 	/* Power up SerDes */
10327113afc8SEmmanuel Vadot 	reg = xgbe_phy_mii_read(pdata, phy_data->mdio_addr, 0x00);
10337113afc8SEmmanuel Vadot 	xgbe_phy_mii_write(pdata, phy_data->mdio_addr, 0x00, reg & ~0x00800);
10347113afc8SEmmanuel Vadot 
10357113afc8SEmmanuel Vadot 	axgbe_printf(3, "BelFuse PHY quirk in place\n");
10367113afc8SEmmanuel Vadot 
10377113afc8SEmmanuel Vadot 	return (true);
10387113afc8SEmmanuel Vadot }
10397113afc8SEmmanuel Vadot 
10407113afc8SEmmanuel Vadot static void
xgbe_phy_external_phy_quirks(struct xgbe_prv_data * pdata)10417113afc8SEmmanuel Vadot xgbe_phy_external_phy_quirks(struct xgbe_prv_data *pdata)
10427113afc8SEmmanuel Vadot {
10437113afc8SEmmanuel Vadot 	if (xgbe_phy_belfuse_phy_quirks(pdata))
10447113afc8SEmmanuel Vadot 		return;
10457113afc8SEmmanuel Vadot 
10467113afc8SEmmanuel Vadot 	if (xgbe_phy_finisar_phy_quirks(pdata))
10477113afc8SEmmanuel Vadot 		return;
10487113afc8SEmmanuel Vadot }
10497113afc8SEmmanuel Vadot 
10507113afc8SEmmanuel Vadot static int
xgbe_get_phy_id(struct xgbe_prv_data * pdata)10517113afc8SEmmanuel Vadot xgbe_get_phy_id(struct xgbe_prv_data *pdata)
10527113afc8SEmmanuel Vadot {
10537113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
10547113afc8SEmmanuel Vadot 	uint32_t oui, model, phy_id1, phy_id2;
10557113afc8SEmmanuel Vadot 	int phy_reg;
10567113afc8SEmmanuel Vadot 
10577113afc8SEmmanuel Vadot 	phy_reg = xgbe_phy_mii_read(pdata, phy_data->mdio_addr, 0x02);
10587113afc8SEmmanuel Vadot 	if (phy_reg < 0)
10597113afc8SEmmanuel Vadot 		return (-EIO);
10607113afc8SEmmanuel Vadot 
10617113afc8SEmmanuel Vadot 	phy_id1 = (phy_reg & 0xffff);
10627113afc8SEmmanuel Vadot 	phy_data->phy_id = (phy_reg & 0xffff) << 16;
10637113afc8SEmmanuel Vadot 
10647113afc8SEmmanuel Vadot 	phy_reg = xgbe_phy_mii_read(pdata, phy_data->mdio_addr, 0x03);
10657113afc8SEmmanuel Vadot 	if (phy_reg < 0)
10667113afc8SEmmanuel Vadot 		return (-EIO);
10677113afc8SEmmanuel Vadot 
10687113afc8SEmmanuel Vadot 	phy_id2 = (phy_reg & 0xffff);
10697113afc8SEmmanuel Vadot 	phy_data->phy_id |= (phy_reg & 0xffff);
10707113afc8SEmmanuel Vadot 
10717113afc8SEmmanuel Vadot 	oui = MII_OUI(phy_id1, phy_id2);
10727113afc8SEmmanuel Vadot 	model = MII_MODEL(phy_id2);
10737113afc8SEmmanuel Vadot 
10747113afc8SEmmanuel Vadot 	axgbe_printf(2, "%s: phy_id1: 0x%x phy_id2: 0x%x oui: %#x model %#x\n",
10757113afc8SEmmanuel Vadot 	    __func__, phy_id1, phy_id2, oui, model);
10767113afc8SEmmanuel Vadot 
10777113afc8SEmmanuel Vadot 	return (0);
10787113afc8SEmmanuel Vadot }
10797113afc8SEmmanuel Vadot 
10807113afc8SEmmanuel Vadot static int
xgbe_phy_find_phy_device(struct xgbe_prv_data * pdata)10817113afc8SEmmanuel Vadot xgbe_phy_find_phy_device(struct xgbe_prv_data *pdata)
10827113afc8SEmmanuel Vadot {
10837113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
10847113afc8SEmmanuel Vadot 	int ret;
10857113afc8SEmmanuel Vadot 
10867113afc8SEmmanuel Vadot 	axgbe_printf(2, "%s: phydev %d phydev_mode %d sfp_phy_avail %d phy_id "
10877113afc8SEmmanuel Vadot 	    "0x%08x\n", __func__, phy_data->phydev, phy_data->phydev_mode,
10887113afc8SEmmanuel Vadot 	    phy_data->sfp_phy_avail, phy_data->phy_id);
10897113afc8SEmmanuel Vadot 
10907113afc8SEmmanuel Vadot 	/* If we already have a PHY, just return */
10917113afc8SEmmanuel Vadot 	if (phy_data->phydev) {
10927113afc8SEmmanuel Vadot 		axgbe_printf(3, "%s: phy present already\n", __func__);
10937113afc8SEmmanuel Vadot 		return (0);
10947113afc8SEmmanuel Vadot 	}
10957113afc8SEmmanuel Vadot 
10967113afc8SEmmanuel Vadot 	/* Clear the extra AN flag */
10977113afc8SEmmanuel Vadot 	pdata->an_again = 0;
10987113afc8SEmmanuel Vadot 
10997113afc8SEmmanuel Vadot 	/* Check for the use of an external PHY */
11007113afc8SEmmanuel Vadot 	if (phy_data->phydev_mode == XGBE_MDIO_MODE_NONE) {
11017113afc8SEmmanuel Vadot 		axgbe_printf(3, "%s: phydev_mode %d\n", __func__,
11027113afc8SEmmanuel Vadot 		    phy_data->phydev_mode);
11037113afc8SEmmanuel Vadot 		return (0);
11047113afc8SEmmanuel Vadot 	}
11057113afc8SEmmanuel Vadot 
11067113afc8SEmmanuel Vadot 	/* For SFP, only use an external PHY if available */
11077113afc8SEmmanuel Vadot 	if ((phy_data->port_mode == XGBE_PORT_MODE_SFP) &&
11087113afc8SEmmanuel Vadot 	    !phy_data->sfp_phy_avail) {
11097113afc8SEmmanuel Vadot 		axgbe_printf(3, "%s: port_mode %d avail %d\n", __func__,
11107113afc8SEmmanuel Vadot 		    phy_data->port_mode, phy_data->sfp_phy_avail);
11117113afc8SEmmanuel Vadot 		return (0);
11127113afc8SEmmanuel Vadot 	}
11137113afc8SEmmanuel Vadot 
11147113afc8SEmmanuel Vadot 	/* Set the proper MDIO mode for the PHY */
11157113afc8SEmmanuel Vadot 	ret = pdata->hw_if.set_ext_mii_mode(pdata, phy_data->mdio_addr,
11167113afc8SEmmanuel Vadot 	    phy_data->phydev_mode);
11177113afc8SEmmanuel Vadot 	if (ret) {
11187113afc8SEmmanuel Vadot 		axgbe_error("mdio port/clause not compatible (%u/%u) ret %d\n",
11197113afc8SEmmanuel Vadot 		    phy_data->mdio_addr, phy_data->phydev_mode, ret);
11207113afc8SEmmanuel Vadot 		return (ret);
11217113afc8SEmmanuel Vadot 	}
11227113afc8SEmmanuel Vadot 
11237113afc8SEmmanuel Vadot 	ret = xgbe_get_phy_id(pdata);
11247113afc8SEmmanuel Vadot 	if (ret)
11257113afc8SEmmanuel Vadot 		return (ret);
11267113afc8SEmmanuel Vadot 	axgbe_printf(2, "Get phy_id 0x%08x\n", phy_data->phy_id);
11277113afc8SEmmanuel Vadot 
11287113afc8SEmmanuel Vadot 	phy_data->phydev = 1;
11297113afc8SEmmanuel Vadot 	xgbe_phy_external_phy_quirks(pdata);
11307113afc8SEmmanuel Vadot 
11317113afc8SEmmanuel Vadot 	return (0);
11327113afc8SEmmanuel Vadot }
11337113afc8SEmmanuel Vadot 
11347113afc8SEmmanuel Vadot static void
xgbe_phy_sfp_external_phy(struct xgbe_prv_data * pdata)11357113afc8SEmmanuel Vadot xgbe_phy_sfp_external_phy(struct xgbe_prv_data *pdata)
11367113afc8SEmmanuel Vadot {
11377113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
11387113afc8SEmmanuel Vadot 	int ret;
11397113afc8SEmmanuel Vadot 
11407113afc8SEmmanuel Vadot 	axgbe_printf(3, "%s: sfp_changed: 0x%x\n", __func__,
11417113afc8SEmmanuel Vadot 	    phy_data->sfp_changed);
1142445bed5cSStephan de Wit 	if (!phy_data->sfp_phy_retries && !phy_data->sfp_changed)
11437113afc8SEmmanuel Vadot 		return;
11447113afc8SEmmanuel Vadot 
11457113afc8SEmmanuel Vadot 	phy_data->sfp_phy_avail = 0;
11467113afc8SEmmanuel Vadot 
11477113afc8SEmmanuel Vadot 	if (phy_data->sfp_base != XGBE_SFP_BASE_1000_T)
11487113afc8SEmmanuel Vadot 		return;
11497113afc8SEmmanuel Vadot 
11507113afc8SEmmanuel Vadot 	/* Check access to the PHY by reading CTRL1 */
11517113afc8SEmmanuel Vadot 	ret = xgbe_phy_i2c_mii_read(pdata, MII_BMCR);
11527113afc8SEmmanuel Vadot 	if (ret < 0) {
1153445bed5cSStephan de Wit 		phy_data->sfp_phy_retries++;
1154445bed5cSStephan de Wit 		if (phy_data->sfp_phy_retries >= XGBE_SFP_PHY_RETRY_MAX)
1155445bed5cSStephan de Wit 			phy_data->sfp_phy_retries = 0;
1156445bed5cSStephan de Wit 		axgbe_printf(1, "%s: ext phy fail %d. retrying.\n", __func__, ret);
11577113afc8SEmmanuel Vadot 		return;
11587113afc8SEmmanuel Vadot 	}
11597113afc8SEmmanuel Vadot 
11607113afc8SEmmanuel Vadot 	/* Successfully accessed the PHY */
11617113afc8SEmmanuel Vadot 	phy_data->sfp_phy_avail = 1;
11627113afc8SEmmanuel Vadot 	axgbe_printf(3, "Successfully accessed External PHY\n");
1163445bed5cSStephan de Wit 
1164445bed5cSStephan de Wit 	/* Attach external PHY to the miibus */
1165445bed5cSStephan de Wit 	ret = mii_attach(pdata->dev, &pdata->axgbe_miibus, pdata->netdev,
1166445bed5cSStephan de Wit 		(ifm_change_cb_t)axgbe_ifmedia_upd,
1167445bed5cSStephan de Wit 		(ifm_stat_cb_t)axgbe_ifmedia_sts, BMSR_DEFCAPMASK,
1168445bed5cSStephan de Wit 		pdata->mdio_addr, MII_OFFSET_ANY, MIIF_FORCEANEG);
1169445bed5cSStephan de Wit 
1170445bed5cSStephan de Wit 	if (ret) {
1171445bed5cSStephan de Wit 		axgbe_error("mii attach failed with err=(%d)\n", ret);
1172445bed5cSStephan de Wit 	}
11737113afc8SEmmanuel Vadot }
11747113afc8SEmmanuel Vadot 
11757113afc8SEmmanuel Vadot static bool
xgbe_phy_check_sfp_rx_los(struct xgbe_phy_data * phy_data)11767113afc8SEmmanuel Vadot xgbe_phy_check_sfp_rx_los(struct xgbe_phy_data *phy_data)
11777113afc8SEmmanuel Vadot {
11787113afc8SEmmanuel Vadot 	uint8_t *sfp_extd = phy_data->sfp_eeprom.extd;
11797113afc8SEmmanuel Vadot 
11807113afc8SEmmanuel Vadot 	if (!(sfp_extd[XGBE_SFP_EXTD_OPT1] & XGBE_SFP_EXTD_OPT1_RX_LOS))
11817113afc8SEmmanuel Vadot 		return (false);
11827113afc8SEmmanuel Vadot 
11837113afc8SEmmanuel Vadot 	if (phy_data->sfp_gpio_mask & XGBE_GPIO_NO_RX_LOS)
11847113afc8SEmmanuel Vadot 		return (false);
11857113afc8SEmmanuel Vadot 
11867113afc8SEmmanuel Vadot 	if (phy_data->sfp_gpio_inputs & (1 << phy_data->sfp_gpio_rx_los))
11877113afc8SEmmanuel Vadot 		return (true);
11887113afc8SEmmanuel Vadot 
11897113afc8SEmmanuel Vadot 	return (false);
11907113afc8SEmmanuel Vadot }
11917113afc8SEmmanuel Vadot 
11927113afc8SEmmanuel Vadot static bool
xgbe_phy_check_sfp_tx_fault(struct xgbe_phy_data * phy_data)11937113afc8SEmmanuel Vadot xgbe_phy_check_sfp_tx_fault(struct xgbe_phy_data *phy_data)
11947113afc8SEmmanuel Vadot {
11957113afc8SEmmanuel Vadot 	uint8_t *sfp_extd = phy_data->sfp_eeprom.extd;
11967113afc8SEmmanuel Vadot 
11977113afc8SEmmanuel Vadot 	if (!(sfp_extd[XGBE_SFP_EXTD_OPT1] & XGBE_SFP_EXTD_OPT1_TX_FAULT))
11987113afc8SEmmanuel Vadot 		return (false);
11997113afc8SEmmanuel Vadot 
12007113afc8SEmmanuel Vadot 	if (phy_data->sfp_gpio_mask & XGBE_GPIO_NO_TX_FAULT)
12017113afc8SEmmanuel Vadot 		return (false);
12027113afc8SEmmanuel Vadot 
12037113afc8SEmmanuel Vadot 	if (phy_data->sfp_gpio_inputs & (1 << phy_data->sfp_gpio_tx_fault))
12047113afc8SEmmanuel Vadot 		return (true);
12057113afc8SEmmanuel Vadot 
12067113afc8SEmmanuel Vadot 	return (false);
12077113afc8SEmmanuel Vadot }
12087113afc8SEmmanuel Vadot 
12097113afc8SEmmanuel Vadot static bool
xgbe_phy_check_sfp_mod_absent(struct xgbe_phy_data * phy_data)12107113afc8SEmmanuel Vadot xgbe_phy_check_sfp_mod_absent(struct xgbe_phy_data *phy_data)
12117113afc8SEmmanuel Vadot {
12127113afc8SEmmanuel Vadot 	if (phy_data->sfp_gpio_mask & XGBE_GPIO_NO_MOD_ABSENT)
12137113afc8SEmmanuel Vadot 		return (false);
12147113afc8SEmmanuel Vadot 
12157113afc8SEmmanuel Vadot 	if (phy_data->sfp_gpio_inputs & (1 << phy_data->sfp_gpio_mod_absent))
12167113afc8SEmmanuel Vadot 		return (true);
12177113afc8SEmmanuel Vadot 
12187113afc8SEmmanuel Vadot 	return (false);
12197113afc8SEmmanuel Vadot }
12207113afc8SEmmanuel Vadot 
12217113afc8SEmmanuel Vadot static void
xgbe_phy_sfp_parse_eeprom(struct xgbe_prv_data * pdata)12227113afc8SEmmanuel Vadot xgbe_phy_sfp_parse_eeprom(struct xgbe_prv_data *pdata)
12237113afc8SEmmanuel Vadot {
12247113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
12257113afc8SEmmanuel Vadot 	struct xgbe_sfp_eeprom *sfp_eeprom = &phy_data->sfp_eeprom;
12267113afc8SEmmanuel Vadot 	uint8_t *sfp_base;
1227445bed5cSStephan de Wit 	uint16_t wavelen = 0;
12287113afc8SEmmanuel Vadot 
12297113afc8SEmmanuel Vadot 	sfp_base = sfp_eeprom->base;
12307113afc8SEmmanuel Vadot 
12317113afc8SEmmanuel Vadot 	if (sfp_base[XGBE_SFP_BASE_ID] != XGBE_SFP_ID_SFP) {
12327113afc8SEmmanuel Vadot 		axgbe_error("base id %d\n", sfp_base[XGBE_SFP_BASE_ID]);
12337113afc8SEmmanuel Vadot 		return;
12347113afc8SEmmanuel Vadot 	}
12357113afc8SEmmanuel Vadot 
12367113afc8SEmmanuel Vadot 	if (sfp_base[XGBE_SFP_BASE_EXT_ID] != XGBE_SFP_EXT_ID_SFP) {
12377113afc8SEmmanuel Vadot 		axgbe_error("base id %d\n", sfp_base[XGBE_SFP_BASE_EXT_ID]);
12387113afc8SEmmanuel Vadot 		return;
12397113afc8SEmmanuel Vadot 	}
12407113afc8SEmmanuel Vadot 
12417113afc8SEmmanuel Vadot 	/* Update transceiver signals (eeprom extd/options) */
12427113afc8SEmmanuel Vadot 	phy_data->sfp_tx_fault = xgbe_phy_check_sfp_tx_fault(phy_data);
12437113afc8SEmmanuel Vadot 	phy_data->sfp_rx_los = xgbe_phy_check_sfp_rx_los(phy_data);
12447113afc8SEmmanuel Vadot 
12457113afc8SEmmanuel Vadot 	/* Assume ACTIVE cable unless told it is PASSIVE */
12467113afc8SEmmanuel Vadot 	if (sfp_base[XGBE_SFP_BASE_CABLE] & XGBE_SFP_BASE_CABLE_PASSIVE) {
12477113afc8SEmmanuel Vadot 		phy_data->sfp_cable = XGBE_SFP_CABLE_PASSIVE;
12487113afc8SEmmanuel Vadot 		phy_data->sfp_cable_len = sfp_base[XGBE_SFP_BASE_CU_CABLE_LEN];
12497113afc8SEmmanuel Vadot 	} else
12507113afc8SEmmanuel Vadot 		phy_data->sfp_cable = XGBE_SFP_CABLE_ACTIVE;
12517113afc8SEmmanuel Vadot 
1252445bed5cSStephan de Wit 	wavelen = (sfp_base[XGBE_SFP_BASE_OSC] << 8) | sfp_base[XGBE_SFP_BASE_OSC + 1];
1253445bed5cSStephan de Wit 
1254bfd75d45SVincenzo Maffione 	/*
1255bfd75d45SVincenzo Maffione 	 * Determine the type of SFP. Certain 10G SFP+ modules read as
1256bfd75d45SVincenzo Maffione 	 * 1000BASE-CX. To prevent 10G DAC cables to be recognized as
1257bfd75d45SVincenzo Maffione 	 * 1G, we first check if it is a DAC and the bitrate is 10G.
1258445bed5cSStephan de Wit 	 * If it's greater than 10G, we assume the DAC is capable
1259445bed5cSStephan de Wit 	 * of multiple bitrates, set the MAC to 10G and hope for the best.
1260bfd75d45SVincenzo Maffione 	 */
1261bfd75d45SVincenzo Maffione 	if (((sfp_base[XGBE_SFP_BASE_CV] & XGBE_SFP_BASE_CV_CP) ||
1262bfd75d45SVincenzo Maffione 		(phy_data->sfp_cable == XGBE_SFP_CABLE_PASSIVE)) &&
1263445bed5cSStephan de Wit 		(xgbe_phy_sfp_bit_rate(sfp_eeprom, XGBE_SFP_SPEED_10000) ||
1264445bed5cSStephan de Wit 		xgbe_phy_sfp_bit_rate(sfp_eeprom, XGBE_SFP_SPEED_25000)))
1265bfd75d45SVincenzo Maffione 		phy_data->sfp_base = XGBE_SFP_BASE_10000_CR;
1266bfd75d45SVincenzo Maffione 	else if (sfp_base[XGBE_SFP_BASE_10GBE_CC] & XGBE_SFP_BASE_10GBE_CC_SR)
12677113afc8SEmmanuel Vadot 		phy_data->sfp_base = XGBE_SFP_BASE_10000_SR;
12687113afc8SEmmanuel Vadot 	else if (sfp_base[XGBE_SFP_BASE_10GBE_CC] & XGBE_SFP_BASE_10GBE_CC_LR)
12697113afc8SEmmanuel Vadot 		phy_data->sfp_base = XGBE_SFP_BASE_10000_LR;
12707113afc8SEmmanuel Vadot 	else if (sfp_base[XGBE_SFP_BASE_10GBE_CC] & XGBE_SFP_BASE_10GBE_CC_LRM)
12717113afc8SEmmanuel Vadot 		phy_data->sfp_base = XGBE_SFP_BASE_10000_LRM;
12727113afc8SEmmanuel Vadot 	else if (sfp_base[XGBE_SFP_BASE_10GBE_CC] & XGBE_SFP_BASE_10GBE_CC_ER)
12737113afc8SEmmanuel Vadot 		phy_data->sfp_base = XGBE_SFP_BASE_10000_ER;
12747113afc8SEmmanuel Vadot 	else if (sfp_base[XGBE_SFP_BASE_1GBE_CC] & XGBE_SFP_BASE_1GBE_CC_SX)
12757113afc8SEmmanuel Vadot 		phy_data->sfp_base = XGBE_SFP_BASE_1000_SX;
12767113afc8SEmmanuel Vadot 	else if (sfp_base[XGBE_SFP_BASE_1GBE_CC] & XGBE_SFP_BASE_1GBE_CC_LX)
12777113afc8SEmmanuel Vadot 		phy_data->sfp_base = XGBE_SFP_BASE_1000_LX;
12787113afc8SEmmanuel Vadot 	else if (sfp_base[XGBE_SFP_BASE_1GBE_CC] & XGBE_SFP_BASE_1GBE_CC_CX)
12797113afc8SEmmanuel Vadot 		phy_data->sfp_base = XGBE_SFP_BASE_1000_CX;
12807113afc8SEmmanuel Vadot 	else if (sfp_base[XGBE_SFP_BASE_1GBE_CC] & XGBE_SFP_BASE_1GBE_CC_T)
12817113afc8SEmmanuel Vadot 		phy_data->sfp_base = XGBE_SFP_BASE_1000_T;
1282445bed5cSStephan de Wit 	else if (sfp_base[XGBE_SFP_BASE_1GBE_CC] & XGBE_SFP_BASE_100M_CC_LX10)
1283445bed5cSStephan de Wit 		phy_data->sfp_base = XGBE_SFP_BASE_100_LX10;
1284445bed5cSStephan de Wit 	else if (sfp_base[XGBE_SFP_BASE_1GBE_CC] & XGBE_SFP_BASE_100M_CC_FX)
1285445bed5cSStephan de Wit 		phy_data->sfp_base = XGBE_SFP_BASE_100_FX;
1286445bed5cSStephan de Wit 	else if (sfp_base[XGBE_SFP_BASE_1GBE_CC] & XGBE_SFP_BASE_CC_BX10) {
1287445bed5cSStephan de Wit 		/* BX10 can be either 100 or 1000 */
1288445bed5cSStephan de Wit 		if (xgbe_phy_sfp_bit_rate(sfp_eeprom, XGBE_SFP_SPEED_100)) {
1289445bed5cSStephan de Wit 			phy_data->sfp_base = XGBE_SFP_BASE_100_BX;
1290445bed5cSStephan de Wit 		} else {
1291445bed5cSStephan de Wit 			/* default to 1000 */
1292445bed5cSStephan de Wit 			phy_data->sfp_base = XGBE_SFP_BASE_1000_BX;
1293445bed5cSStephan de Wit 		}
1294445bed5cSStephan de Wit 	} else if (sfp_base[XGBE_SFP_BASE_1GBE_CC] & XGBE_SFP_BASE_CC_PX)
1295445bed5cSStephan de Wit 		phy_data->sfp_base = XGBE_SFP_BASE_PX;
1296445bed5cSStephan de Wit 	else if (xgbe_phy_sfp_bit_rate(sfp_eeprom, XGBE_SFP_SPEED_1000)
1297445bed5cSStephan de Wit 			&& (sfp_base[XGBE_SFP_BASE_SM_LEN_KM] >= XGBE_SFP_BASE_SM_LEN_KM_MIN
1298445bed5cSStephan de Wit 			|| sfp_base[XGBE_SFP_BASE_SM_LEN_100M] >= XGBE_SFP_BASE_SM_LEN_100M_MIN)
1299445bed5cSStephan de Wit 			&& wavelen >= XGBE_SFP_BASE_OSC_1310)
1300445bed5cSStephan de Wit 		phy_data->sfp_base = XGBE_SFP_BASE_1000_BX;
1301445bed5cSStephan de Wit 	else if (xgbe_phy_sfp_bit_rate(sfp_eeprom, XGBE_SFP_SPEED_100)
1302445bed5cSStephan de Wit 			&& (sfp_base[XGBE_SFP_BASE_SM_LEN_KM] >= XGBE_SFP_BASE_SM_LEN_KM_MIN
1303445bed5cSStephan de Wit 			|| sfp_base[XGBE_SFP_BASE_SM_LEN_100M] >= XGBE_SFP_BASE_SM_LEN_100M_MIN)
1304445bed5cSStephan de Wit 			&& wavelen >= XGBE_SFP_BASE_OSC_1310)
1305445bed5cSStephan de Wit 		phy_data->sfp_base = XGBE_SFP_BASE_100_BX;
13067113afc8SEmmanuel Vadot 
13077113afc8SEmmanuel Vadot 	switch (phy_data->sfp_base) {
1308445bed5cSStephan de Wit 	case XGBE_SFP_BASE_100_FX:
1309445bed5cSStephan de Wit 	case XGBE_SFP_BASE_100_LX10:
1310445bed5cSStephan de Wit 	case XGBE_SFP_BASE_100_BX:
1311445bed5cSStephan de Wit 		phy_data->sfp_speed = XGBE_SFP_SPEED_100;
13127113afc8SEmmanuel Vadot 	case XGBE_SFP_BASE_1000_T:
13137113afc8SEmmanuel Vadot 		phy_data->sfp_speed = XGBE_SFP_SPEED_100_1000;
13147113afc8SEmmanuel Vadot 		break;
1315445bed5cSStephan de Wit 	case XGBE_SFP_BASE_PX:
13167113afc8SEmmanuel Vadot 	case XGBE_SFP_BASE_1000_SX:
13177113afc8SEmmanuel Vadot 	case XGBE_SFP_BASE_1000_LX:
13187113afc8SEmmanuel Vadot 	case XGBE_SFP_BASE_1000_CX:
1319445bed5cSStephan de Wit 	case XGBE_SFP_BASE_1000_BX:
13207113afc8SEmmanuel Vadot 		phy_data->sfp_speed = XGBE_SFP_SPEED_1000;
13217113afc8SEmmanuel Vadot 		break;
13227113afc8SEmmanuel Vadot 	case XGBE_SFP_BASE_10000_SR:
13237113afc8SEmmanuel Vadot 	case XGBE_SFP_BASE_10000_LR:
13247113afc8SEmmanuel Vadot 	case XGBE_SFP_BASE_10000_LRM:
13257113afc8SEmmanuel Vadot 	case XGBE_SFP_BASE_10000_ER:
13267113afc8SEmmanuel Vadot 	case XGBE_SFP_BASE_10000_CR:
13277113afc8SEmmanuel Vadot 		phy_data->sfp_speed = XGBE_SFP_SPEED_10000;
13287113afc8SEmmanuel Vadot 		break;
13297113afc8SEmmanuel Vadot 	default:
13307113afc8SEmmanuel Vadot 		break;
13317113afc8SEmmanuel Vadot 	}
13327113afc8SEmmanuel Vadot 	axgbe_printf(3, "%s: sfp_base: 0x%x sfp_speed: 0x%x sfp_cable: 0x%x "
13337113afc8SEmmanuel Vadot 	    "rx_los 0x%x tx_fault 0x%x\n", __func__, phy_data->sfp_base,
13347113afc8SEmmanuel Vadot 	    phy_data->sfp_speed, phy_data->sfp_cable, phy_data->sfp_rx_los,
13357113afc8SEmmanuel Vadot 	    phy_data->sfp_tx_fault);
13367113afc8SEmmanuel Vadot }
13377113afc8SEmmanuel Vadot 
13387113afc8SEmmanuel Vadot static void
xgbe_phy_sfp_eeprom_info(struct xgbe_prv_data * pdata,struct xgbe_sfp_eeprom * sfp_eeprom)13397113afc8SEmmanuel Vadot xgbe_phy_sfp_eeprom_info(struct xgbe_prv_data *pdata,
13407113afc8SEmmanuel Vadot     struct xgbe_sfp_eeprom *sfp_eeprom)
13417113afc8SEmmanuel Vadot {
13427113afc8SEmmanuel Vadot 	struct xgbe_sfp_ascii sfp_ascii;
13437113afc8SEmmanuel Vadot 	char *sfp_data = (char *)&sfp_ascii;
13447113afc8SEmmanuel Vadot 
1345445bed5cSStephan de Wit 	axgbe_printf(0, "SFP detected:\n");
13467113afc8SEmmanuel Vadot 	memcpy(sfp_data, &sfp_eeprom->base[XGBE_SFP_BASE_VENDOR_NAME],
13477113afc8SEmmanuel Vadot 	       XGBE_SFP_BASE_VENDOR_NAME_LEN);
13487113afc8SEmmanuel Vadot 	sfp_data[XGBE_SFP_BASE_VENDOR_NAME_LEN] = '\0';
1349445bed5cSStephan de Wit 	axgbe_printf(0, "  vendor:	 %s\n",
13507113afc8SEmmanuel Vadot 	    sfp_data);
13517113afc8SEmmanuel Vadot 
13527113afc8SEmmanuel Vadot 	memcpy(sfp_data, &sfp_eeprom->base[XGBE_SFP_BASE_VENDOR_PN],
13537113afc8SEmmanuel Vadot 	       XGBE_SFP_BASE_VENDOR_PN_LEN);
13547113afc8SEmmanuel Vadot 	sfp_data[XGBE_SFP_BASE_VENDOR_PN_LEN] = '\0';
1355445bed5cSStephan de Wit 	axgbe_printf(0, "  part number:    %s\n",
13567113afc8SEmmanuel Vadot 	    sfp_data);
13577113afc8SEmmanuel Vadot 
13587113afc8SEmmanuel Vadot 	memcpy(sfp_data, &sfp_eeprom->base[XGBE_SFP_BASE_VENDOR_REV],
13597113afc8SEmmanuel Vadot 	       XGBE_SFP_BASE_VENDOR_REV_LEN);
13607113afc8SEmmanuel Vadot 	sfp_data[XGBE_SFP_BASE_VENDOR_REV_LEN] = '\0';
1361445bed5cSStephan de Wit 	axgbe_printf(0, "  revision level: %s\n",
13627113afc8SEmmanuel Vadot 	    sfp_data);
13637113afc8SEmmanuel Vadot 
13647113afc8SEmmanuel Vadot 	memcpy(sfp_data, &sfp_eeprom->extd[XGBE_SFP_BASE_VENDOR_SN],
13657113afc8SEmmanuel Vadot 	       XGBE_SFP_BASE_VENDOR_SN_LEN);
13667113afc8SEmmanuel Vadot 	sfp_data[XGBE_SFP_BASE_VENDOR_SN_LEN] = '\0';
1367445bed5cSStephan de Wit 	axgbe_printf(0, "  serial number:  %s\n",
13687113afc8SEmmanuel Vadot 	    sfp_data);
13697113afc8SEmmanuel Vadot }
13707113afc8SEmmanuel Vadot 
13717113afc8SEmmanuel Vadot static bool
xgbe_phy_sfp_verify_eeprom(uint8_t cc_in,uint8_t * buf,unsigned int len)13727113afc8SEmmanuel Vadot xgbe_phy_sfp_verify_eeprom(uint8_t cc_in, uint8_t *buf, unsigned int len)
13737113afc8SEmmanuel Vadot {
13747113afc8SEmmanuel Vadot 	uint8_t cc;
13757113afc8SEmmanuel Vadot 
13767113afc8SEmmanuel Vadot 	for (cc = 0; len; buf++, len--)
13777113afc8SEmmanuel Vadot 		cc += *buf;
13787113afc8SEmmanuel Vadot 
13797113afc8SEmmanuel Vadot 	return ((cc == cc_in) ? true : false);
13807113afc8SEmmanuel Vadot }
13817113afc8SEmmanuel Vadot 
13827113afc8SEmmanuel Vadot static void
dump_sfp_eeprom(struct xgbe_prv_data * pdata,uint8_t * sfp_base)13837113afc8SEmmanuel Vadot dump_sfp_eeprom(struct xgbe_prv_data *pdata, uint8_t *sfp_base)
13847113afc8SEmmanuel Vadot {
13857113afc8SEmmanuel Vadot 	axgbe_printf(3, "sfp_base[XGBE_SFP_BASE_ID]     : 0x%04x\n",
13867113afc8SEmmanuel Vadot 	    sfp_base[XGBE_SFP_BASE_ID]);
13877113afc8SEmmanuel Vadot 	axgbe_printf(3, "sfp_base[XGBE_SFP_BASE_EXT_ID] : 0x%04x\n",
13887113afc8SEmmanuel Vadot 	    sfp_base[XGBE_SFP_BASE_EXT_ID]);
13897113afc8SEmmanuel Vadot 	axgbe_printf(3, "sfp_base[XGBE_SFP_BASE_CABLE]  : 0x%04x\n",
13907113afc8SEmmanuel Vadot 	    sfp_base[XGBE_SFP_BASE_CABLE]);
13917113afc8SEmmanuel Vadot }
13927113afc8SEmmanuel Vadot 
13937113afc8SEmmanuel Vadot static int
xgbe_phy_sfp_read_eeprom(struct xgbe_prv_data * pdata)13947113afc8SEmmanuel Vadot xgbe_phy_sfp_read_eeprom(struct xgbe_prv_data *pdata)
13957113afc8SEmmanuel Vadot {
13967113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
13977113afc8SEmmanuel Vadot 	struct xgbe_sfp_eeprom sfp_eeprom, *eeprom;
13987113afc8SEmmanuel Vadot 	uint8_t eeprom_addr, *base;
13997113afc8SEmmanuel Vadot 	int ret;
14007113afc8SEmmanuel Vadot 
14017113afc8SEmmanuel Vadot 	ret = xgbe_phy_sfp_get_mux(pdata);
14027113afc8SEmmanuel Vadot 	if (ret) {
14037113afc8SEmmanuel Vadot 		axgbe_error("I2C error setting SFP MUX\n");
14047113afc8SEmmanuel Vadot 		return (ret);
14057113afc8SEmmanuel Vadot 	}
14067113afc8SEmmanuel Vadot 
14077113afc8SEmmanuel Vadot 	/* Read the SFP serial ID eeprom */
14087113afc8SEmmanuel Vadot 	eeprom_addr = 0;
14097113afc8SEmmanuel Vadot 	ret = xgbe_phy_i2c_read(pdata, XGBE_SFP_SERIAL_ID_ADDRESS,
14107113afc8SEmmanuel Vadot 	    &eeprom_addr, sizeof(eeprom_addr),
14117113afc8SEmmanuel Vadot 	    &sfp_eeprom, sizeof(sfp_eeprom));
14127113afc8SEmmanuel Vadot 
14137113afc8SEmmanuel Vadot 	if (ret) {
14147113afc8SEmmanuel Vadot 		axgbe_error("I2C error reading SFP EEPROM\n");
14157113afc8SEmmanuel Vadot 		goto put;
14167113afc8SEmmanuel Vadot 	}
14177113afc8SEmmanuel Vadot 
1418445bed5cSStephan de Wit 	eeprom = &sfp_eeprom;
1419445bed5cSStephan de Wit 	base = eeprom->base;
1420445bed5cSStephan de Wit 	dump_sfp_eeprom(pdata, base);
1421445bed5cSStephan de Wit 
14227113afc8SEmmanuel Vadot 	/* Validate the contents read */
14237113afc8SEmmanuel Vadot 	if (!xgbe_phy_sfp_verify_eeprom(sfp_eeprom.base[XGBE_SFP_BASE_CC],
14247113afc8SEmmanuel Vadot 	    sfp_eeprom.base, sizeof(sfp_eeprom.base) - 1)) {
14257113afc8SEmmanuel Vadot 		axgbe_error("verify eeprom base failed\n");
14267113afc8SEmmanuel Vadot 		ret = -EINVAL;
14277113afc8SEmmanuel Vadot 		goto put;
14287113afc8SEmmanuel Vadot 	}
14297113afc8SEmmanuel Vadot 
14307113afc8SEmmanuel Vadot 	if (!xgbe_phy_sfp_verify_eeprom(sfp_eeprom.extd[XGBE_SFP_EXTD_CC],
14317113afc8SEmmanuel Vadot 	    sfp_eeprom.extd, sizeof(sfp_eeprom.extd) - 1)) {
14327113afc8SEmmanuel Vadot 		axgbe_error("verify eeprom extd failed\n");
14337113afc8SEmmanuel Vadot 		ret = -EINVAL;
14347113afc8SEmmanuel Vadot 		goto put;
14357113afc8SEmmanuel Vadot 	}
14367113afc8SEmmanuel Vadot 
14377113afc8SEmmanuel Vadot 	/* Check for an added or changed SFP */
14387113afc8SEmmanuel Vadot 	if (memcmp(&phy_data->sfp_eeprom, &sfp_eeprom, sizeof(sfp_eeprom))) {
14397113afc8SEmmanuel Vadot 		phy_data->sfp_changed = 1;
14407113afc8SEmmanuel Vadot 
14417113afc8SEmmanuel Vadot 		xgbe_phy_sfp_eeprom_info(pdata, &sfp_eeprom);
14427113afc8SEmmanuel Vadot 
14437113afc8SEmmanuel Vadot 		memcpy(&phy_data->sfp_eeprom, &sfp_eeprom, sizeof(sfp_eeprom));
14447113afc8SEmmanuel Vadot 
14457113afc8SEmmanuel Vadot 		xgbe_phy_free_phy_device(pdata);
14467113afc8SEmmanuel Vadot 	} else
14477113afc8SEmmanuel Vadot 		phy_data->sfp_changed = 0;
14487113afc8SEmmanuel Vadot 
14497113afc8SEmmanuel Vadot put:
14507113afc8SEmmanuel Vadot 	xgbe_phy_sfp_put_mux(pdata);
14517113afc8SEmmanuel Vadot 
14527113afc8SEmmanuel Vadot 	return (ret);
14537113afc8SEmmanuel Vadot }
14547113afc8SEmmanuel Vadot 
14557113afc8SEmmanuel Vadot static void
xgbe_phy_sfp_signals(struct xgbe_prv_data * pdata)14567113afc8SEmmanuel Vadot xgbe_phy_sfp_signals(struct xgbe_prv_data *pdata)
14577113afc8SEmmanuel Vadot {
14587113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
14597113afc8SEmmanuel Vadot 	uint8_t gpio_reg, gpio_ports[2];
14607113afc8SEmmanuel Vadot 	int ret, prev_sfp_inputs = phy_data->port_sfp_inputs;
14617113afc8SEmmanuel Vadot 	int shift = GPIO_MASK_WIDTH * (3 - phy_data->port_id);
14627113afc8SEmmanuel Vadot 
14637113afc8SEmmanuel Vadot 	/* Read the input port registers */
14647113afc8SEmmanuel Vadot 	axgbe_printf(3, "%s: befor sfp_mod:%d sfp_gpio_address:0x%x\n",
14657113afc8SEmmanuel Vadot 	    __func__, phy_data->sfp_mod_absent, phy_data->sfp_gpio_address);
14667113afc8SEmmanuel Vadot 
14672b8df536SStephan de Wit 	ret = xgbe_phy_sfp_get_mux(pdata);
14682b8df536SStephan de Wit 	if (ret) {
14692b8df536SStephan de Wit 		axgbe_error("I2C error setting SFP MUX\n");
14702b8df536SStephan de Wit 		return;
14712b8df536SStephan de Wit 	}
14722b8df536SStephan de Wit 
14737113afc8SEmmanuel Vadot 	gpio_reg = 0;
14747113afc8SEmmanuel Vadot 	ret = xgbe_phy_i2c_read(pdata, phy_data->sfp_gpio_address, &gpio_reg,
14757113afc8SEmmanuel Vadot 	    sizeof(gpio_reg), gpio_ports, sizeof(gpio_ports));
14767113afc8SEmmanuel Vadot 	if (ret) {
14777113afc8SEmmanuel Vadot 		axgbe_error("%s: I2C error reading SFP GPIO addr:0x%x\n",
14787113afc8SEmmanuel Vadot 		    __func__, phy_data->sfp_gpio_address);
14792b8df536SStephan de Wit 		goto put_mux;
14807113afc8SEmmanuel Vadot 	}
14817113afc8SEmmanuel Vadot 
14827113afc8SEmmanuel Vadot 	phy_data->sfp_gpio_inputs = (gpio_ports[1] << 8) | gpio_ports[0];
14837113afc8SEmmanuel Vadot 	phy_data->port_sfp_inputs = (phy_data->sfp_gpio_inputs >> shift) & 0x0F;
14847113afc8SEmmanuel Vadot 
14857113afc8SEmmanuel Vadot 	if (prev_sfp_inputs != phy_data->port_sfp_inputs)
14867113afc8SEmmanuel Vadot 		axgbe_printf(0, "%s: port_sfp_inputs: 0x%0x\n", __func__,
14877113afc8SEmmanuel Vadot 		    phy_data->port_sfp_inputs);
14887113afc8SEmmanuel Vadot 
14897113afc8SEmmanuel Vadot 	phy_data->sfp_mod_absent = xgbe_phy_check_sfp_mod_absent(phy_data);
14907113afc8SEmmanuel Vadot 
14917113afc8SEmmanuel Vadot 	axgbe_printf(3, "%s: after sfp_mod:%d sfp_gpio_inputs:0x%x\n",
14927113afc8SEmmanuel Vadot 	    __func__, phy_data->sfp_mod_absent, phy_data->sfp_gpio_inputs);
14932b8df536SStephan de Wit 
14942b8df536SStephan de Wit put_mux:
14952b8df536SStephan de Wit 	xgbe_phy_sfp_put_mux(pdata);
14962b8df536SStephan de Wit }
14972b8df536SStephan de Wit 
14982b8df536SStephan de Wit static int
xgbe_read_gpio_expander(struct xgbe_prv_data * pdata)14992b8df536SStephan de Wit xgbe_read_gpio_expander(struct xgbe_prv_data *pdata)
15002b8df536SStephan de Wit {
15012b8df536SStephan de Wit 	struct xgbe_phy_data *phy_data = pdata->phy_data;
15022b8df536SStephan de Wit 	uint8_t gpio_reg, gpio_ports[2];
15032b8df536SStephan de Wit 	int ret = 0;
15042b8df536SStephan de Wit 
15052b8df536SStephan de Wit 	ret = xgbe_phy_sfp_get_mux(pdata);
15062b8df536SStephan de Wit 	if (ret) {
15072b8df536SStephan de Wit 		axgbe_error("I2C error setting SFP MUX\n");
15082b8df536SStephan de Wit 		return (ret);
15092b8df536SStephan de Wit 	}
15102b8df536SStephan de Wit 
15112b8df536SStephan de Wit 	gpio_reg = 2;
15122b8df536SStephan de Wit 	for (int i = 0; i < 3; i++) {
15132b8df536SStephan de Wit 		ret = xgbe_phy_i2c_read(pdata, phy_data->sfp_gpio_address,
15142b8df536SStephan de Wit 			&gpio_reg, sizeof(gpio_reg), gpio_ports, sizeof(gpio_ports));
15152b8df536SStephan de Wit 
15162b8df536SStephan de Wit 		if (ret) {
15172b8df536SStephan de Wit 			axgbe_error("%s: I2C error reading GPIO expander register: %d\n",
15182b8df536SStephan de Wit 			    __func__, gpio_reg);
15192b8df536SStephan de Wit 			goto put_mux;
15202b8df536SStephan de Wit 		}
15212b8df536SStephan de Wit 
15222b8df536SStephan de Wit 		if (gpio_reg == 2)
15232b8df536SStephan de Wit 			phy_data->sfp_gpio_outputs = (gpio_ports[1] << 8) | gpio_ports[0];
15242b8df536SStephan de Wit 		else if (gpio_reg == 4)
15252b8df536SStephan de Wit 			phy_data->sfp_gpio_polarity = (gpio_ports[1] << 8) | gpio_ports[0];
15262b8df536SStephan de Wit 		else if (gpio_reg == 6)
15272b8df536SStephan de Wit 			phy_data->sfp_gpio_configuration = (gpio_ports[1] << 8) | gpio_ports[0];
15282b8df536SStephan de Wit 
15292b8df536SStephan de Wit 		memset(gpio_ports, 0, sizeof(gpio_ports));
15302b8df536SStephan de Wit 		gpio_reg += 2;
15312b8df536SStephan de Wit 	}
15322b8df536SStephan de Wit 
15332b8df536SStephan de Wit put_mux:
15342b8df536SStephan de Wit 	xgbe_phy_sfp_put_mux(pdata);
15352b8df536SStephan de Wit 
15362b8df536SStephan de Wit 	return (ret);
15372b8df536SStephan de Wit }
15382b8df536SStephan de Wit 
15392b8df536SStephan de Wit static void
xgbe_log_gpio_expander(struct xgbe_prv_data * pdata)15402b8df536SStephan de Wit xgbe_log_gpio_expander(struct xgbe_prv_data *pdata)
15412b8df536SStephan de Wit {
15422b8df536SStephan de Wit 	struct xgbe_phy_data *phy_data = pdata->phy_data;
15432b8df536SStephan de Wit 
15442b8df536SStephan de Wit 	axgbe_printf(1, "Input port registers: 0x%x\n", phy_data->sfp_gpio_inputs);
15452b8df536SStephan de Wit 	axgbe_printf(1, "Output port registers: 0x%x\n", phy_data->sfp_gpio_outputs);
15462b8df536SStephan de Wit 	axgbe_printf(1, "Polarity port registers: 0x%x\n", phy_data->sfp_gpio_polarity);
15472b8df536SStephan de Wit 	axgbe_printf(1, "Configuration port registers: 0x%x\n", phy_data->sfp_gpio_configuration);
15482b8df536SStephan de Wit }
15492b8df536SStephan de Wit 
15502b8df536SStephan de Wit static int
xgbe_phy_validate_gpio_expander(struct xgbe_prv_data * pdata)15512b8df536SStephan de Wit xgbe_phy_validate_gpio_expander(struct xgbe_prv_data *pdata)
15522b8df536SStephan de Wit {
15532b8df536SStephan de Wit 	struct xgbe_phy_data *phy_data = pdata->phy_data;
15542b8df536SStephan de Wit 	uint8_t gpio_data[3] = {0};
15552b8df536SStephan de Wit 	int shift = GPIO_MASK_WIDTH * (3 - phy_data->port_id);
15562b8df536SStephan de Wit 	int rx_los_pos = (1 << phy_data->sfp_gpio_rx_los);
15572b8df536SStephan de Wit 	int tx_fault_pos = (1 << phy_data->sfp_gpio_tx_fault);
15582b8df536SStephan de Wit 	int mod_abs_pos = (1 << phy_data->sfp_gpio_mod_absent);
15592b8df536SStephan de Wit 	int port_sfp_pins = (mod_abs_pos | rx_los_pos | tx_fault_pos);
15602b8df536SStephan de Wit 	uint16_t config = 0;
15612b8df536SStephan de Wit 	int ret = 0;
15622b8df536SStephan de Wit 
15632b8df536SStephan de Wit 	ret = xgbe_phy_get_comm_ownership(pdata);
15642b8df536SStephan de Wit 	if (ret)
15652b8df536SStephan de Wit 		return (ret);
15662b8df536SStephan de Wit 
15672b8df536SStephan de Wit 	ret = xgbe_read_gpio_expander(pdata);
15682b8df536SStephan de Wit 	if (ret)
15692b8df536SStephan de Wit 		goto put;
15702b8df536SStephan de Wit 
15712b8df536SStephan de Wit 	ret = xgbe_phy_sfp_get_mux(pdata);
15722b8df536SStephan de Wit 	if (ret) {
15732b8df536SStephan de Wit 		axgbe_error("I2C error setting SFP MUX\n");
15742b8df536SStephan de Wit 		goto put;
15752b8df536SStephan de Wit 	}
15762b8df536SStephan de Wit 
15772b8df536SStephan de Wit 	if (phy_data->sfp_gpio_polarity) {
15782b8df536SStephan de Wit 		axgbe_printf(0, "GPIO polarity inverted, resetting\n");
15792b8df536SStephan de Wit 
15802b8df536SStephan de Wit 		xgbe_log_gpio_expander(pdata);
15812b8df536SStephan de Wit 		gpio_data[0] = 4; /* polarity register */
15822b8df536SStephan de Wit 
15832b8df536SStephan de Wit 		ret = xgbe_phy_i2c_write(pdata, phy_data->sfp_gpio_address,
15842b8df536SStephan de Wit 			gpio_data, sizeof(gpio_data));
15852b8df536SStephan de Wit 
15862b8df536SStephan de Wit 		if (ret) {
15872b8df536SStephan de Wit 			axgbe_error("%s: I2C error writing to GPIO polarity register\n",
15882b8df536SStephan de Wit 				__func__);
15892b8df536SStephan de Wit 			goto put_mux;
15902b8df536SStephan de Wit 		}
15912b8df536SStephan de Wit 	}
15922b8df536SStephan de Wit 
15932b8df536SStephan de Wit 	config = phy_data->sfp_gpio_configuration;
15942b8df536SStephan de Wit 	if ((config & port_sfp_pins) != port_sfp_pins) {
15952b8df536SStephan de Wit 		xgbe_log_gpio_expander(pdata);
15962b8df536SStephan de Wit 
15972b8df536SStephan de Wit 		/* Write the I/O states to the configuration register */
15982b8df536SStephan de Wit 		axgbe_error("Invalid GPIO configuration, resetting\n");
15992b8df536SStephan de Wit 		gpio_data[0] = 6; /* configuration register */
16002b8df536SStephan de Wit 		config = config & ~(0xF << shift); /* clear port id bits */
16012b8df536SStephan de Wit 		config |= port_sfp_pins;
16022b8df536SStephan de Wit 		gpio_data[1] = config & 0xff;
16032b8df536SStephan de Wit 		gpio_data[2] = (config >> 8);
16042b8df536SStephan de Wit 
16052b8df536SStephan de Wit 		ret = xgbe_phy_i2c_write(pdata, phy_data->sfp_gpio_address,
16062b8df536SStephan de Wit 			gpio_data, sizeof(gpio_data));
16072b8df536SStephan de Wit 		if (ret) {
16082b8df536SStephan de Wit 			axgbe_error("%s: I2C error writing to GPIO configuration register\n",
16092b8df536SStephan de Wit 				__func__);
16102b8df536SStephan de Wit 			goto put_mux;
16112b8df536SStephan de Wit 		}
16122b8df536SStephan de Wit 	} else {
16132b8df536SStephan de Wit 		axgbe_printf(0, "GPIO configuration valid\n");
16142b8df536SStephan de Wit 	}
16152b8df536SStephan de Wit 
16162b8df536SStephan de Wit put_mux:
16172b8df536SStephan de Wit 	xgbe_phy_sfp_put_mux(pdata);
16182b8df536SStephan de Wit 
16192b8df536SStephan de Wit put:
16202b8df536SStephan de Wit 	xgbe_phy_put_comm_ownership(pdata);
16212b8df536SStephan de Wit 
16222b8df536SStephan de Wit 	return (ret);
16237113afc8SEmmanuel Vadot }
16247113afc8SEmmanuel Vadot 
16257113afc8SEmmanuel Vadot static void
xgbe_phy_sfp_mod_absent(struct xgbe_prv_data * pdata)16267113afc8SEmmanuel Vadot xgbe_phy_sfp_mod_absent(struct xgbe_prv_data *pdata)
16277113afc8SEmmanuel Vadot {
16287113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
16297113afc8SEmmanuel Vadot 
16307113afc8SEmmanuel Vadot 	xgbe_phy_free_phy_device(pdata);
16317113afc8SEmmanuel Vadot 
16327113afc8SEmmanuel Vadot 	phy_data->sfp_mod_absent = 1;
16337113afc8SEmmanuel Vadot 	phy_data->sfp_phy_avail = 0;
16347113afc8SEmmanuel Vadot 	memset(&phy_data->sfp_eeprom, 0, sizeof(phy_data->sfp_eeprom));
16357113afc8SEmmanuel Vadot }
16367113afc8SEmmanuel Vadot 
16377113afc8SEmmanuel Vadot static void
xgbe_phy_sfp_reset(struct xgbe_phy_data * phy_data)16387113afc8SEmmanuel Vadot xgbe_phy_sfp_reset(struct xgbe_phy_data *phy_data)
16397113afc8SEmmanuel Vadot {
16407113afc8SEmmanuel Vadot 	phy_data->sfp_rx_los = 0;
16417113afc8SEmmanuel Vadot 	phy_data->sfp_tx_fault = 0;
16427113afc8SEmmanuel Vadot 	phy_data->sfp_mod_absent = 1;
16437113afc8SEmmanuel Vadot 	phy_data->sfp_base = XGBE_SFP_BASE_UNKNOWN;
16447113afc8SEmmanuel Vadot 	phy_data->sfp_cable = XGBE_SFP_CABLE_UNKNOWN;
16457113afc8SEmmanuel Vadot 	phy_data->sfp_speed = XGBE_SFP_SPEED_UNKNOWN;
16467113afc8SEmmanuel Vadot }
16477113afc8SEmmanuel Vadot 
16487113afc8SEmmanuel Vadot static void
xgbe_phy_sfp_detect(struct xgbe_prv_data * pdata)16497113afc8SEmmanuel Vadot xgbe_phy_sfp_detect(struct xgbe_prv_data *pdata)
16507113afc8SEmmanuel Vadot {
16517113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
16527113afc8SEmmanuel Vadot 	int ret, prev_sfp_state = phy_data->sfp_mod_absent;
16537113afc8SEmmanuel Vadot 
16547113afc8SEmmanuel Vadot 	ret = xgbe_phy_get_comm_ownership(pdata);
16557113afc8SEmmanuel Vadot 	if (ret)
16567113afc8SEmmanuel Vadot 		return;
16577113afc8SEmmanuel Vadot 
16587113afc8SEmmanuel Vadot 	/* Read the SFP signals and check for module presence */
16597113afc8SEmmanuel Vadot 	xgbe_phy_sfp_signals(pdata);
16607113afc8SEmmanuel Vadot 	if (phy_data->sfp_mod_absent) {
16617113afc8SEmmanuel Vadot 		if (prev_sfp_state != phy_data->sfp_mod_absent)
16627113afc8SEmmanuel Vadot 			axgbe_error("%s: mod absent\n", __func__);
16637113afc8SEmmanuel Vadot 		xgbe_phy_sfp_mod_absent(pdata);
16647113afc8SEmmanuel Vadot 		goto put;
16657113afc8SEmmanuel Vadot 	}
16667113afc8SEmmanuel Vadot 
16677113afc8SEmmanuel Vadot 	ret = xgbe_phy_sfp_read_eeprom(pdata);
16687113afc8SEmmanuel Vadot 	if (ret) {
16697113afc8SEmmanuel Vadot 		/* Treat any error as if there isn't an SFP plugged in */
16707113afc8SEmmanuel Vadot 		axgbe_error("%s: eeprom read failed\n", __func__);
16712b8df536SStephan de Wit 		ret = xgbe_read_gpio_expander(pdata);
16722b8df536SStephan de Wit 
16732b8df536SStephan de Wit 		if (!ret)
16742b8df536SStephan de Wit 			xgbe_log_gpio_expander(pdata);
16752b8df536SStephan de Wit 
16767113afc8SEmmanuel Vadot 		xgbe_phy_sfp_reset(phy_data);
16777113afc8SEmmanuel Vadot 		xgbe_phy_sfp_mod_absent(pdata);
16787113afc8SEmmanuel Vadot 		goto put;
16797113afc8SEmmanuel Vadot 	}
16807113afc8SEmmanuel Vadot 
16817113afc8SEmmanuel Vadot 	xgbe_phy_sfp_parse_eeprom(pdata);
16827113afc8SEmmanuel Vadot 
16837113afc8SEmmanuel Vadot 	xgbe_phy_sfp_external_phy(pdata);
16847113afc8SEmmanuel Vadot 
16857113afc8SEmmanuel Vadot put:
16867113afc8SEmmanuel Vadot 	xgbe_phy_sfp_phy_settings(pdata);
16877113afc8SEmmanuel Vadot 
16887113afc8SEmmanuel Vadot 	axgbe_printf(3, "%s: phy speed: 0x%x duplex: 0x%x autoneg: 0x%x "
16897113afc8SEmmanuel Vadot 	    "pause_autoneg: 0x%x\n", __func__, pdata->phy.speed,
16907113afc8SEmmanuel Vadot 	    pdata->phy.duplex, pdata->phy.autoneg, pdata->phy.pause_autoneg);
16917113afc8SEmmanuel Vadot 
16927113afc8SEmmanuel Vadot 	xgbe_phy_put_comm_ownership(pdata);
16937113afc8SEmmanuel Vadot }
16947113afc8SEmmanuel Vadot 
16957113afc8SEmmanuel Vadot static int
xgbe_phy_module_eeprom(struct xgbe_prv_data * pdata)16967113afc8SEmmanuel Vadot xgbe_phy_module_eeprom(struct xgbe_prv_data *pdata)
16977113afc8SEmmanuel Vadot {
16987113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
16997113afc8SEmmanuel Vadot 	uint8_t eeprom_addr, eeprom_data[XGBE_SFP_EEPROM_MAX];
17007113afc8SEmmanuel Vadot 	struct xgbe_sfp_eeprom *sfp_eeprom;
17017113afc8SEmmanuel Vadot 	int ret;
17027113afc8SEmmanuel Vadot 
17037113afc8SEmmanuel Vadot 	if (phy_data->port_mode != XGBE_PORT_MODE_SFP) {
17047113afc8SEmmanuel Vadot 		ret = -ENXIO;
17057113afc8SEmmanuel Vadot 		goto done;
17067113afc8SEmmanuel Vadot 	}
17077113afc8SEmmanuel Vadot 
17087113afc8SEmmanuel Vadot 	if (phy_data->sfp_mod_absent) {
17097113afc8SEmmanuel Vadot 		ret = -EIO;
17107113afc8SEmmanuel Vadot 		goto done;
17117113afc8SEmmanuel Vadot 	}
17127113afc8SEmmanuel Vadot 
17137113afc8SEmmanuel Vadot 	ret = xgbe_phy_get_comm_ownership(pdata);
17147113afc8SEmmanuel Vadot 	if (ret) {
17157113afc8SEmmanuel Vadot 		ret = -EIO;
17167113afc8SEmmanuel Vadot 		goto done;
17177113afc8SEmmanuel Vadot 	}
17187113afc8SEmmanuel Vadot 
17197113afc8SEmmanuel Vadot 	ret = xgbe_phy_sfp_get_mux(pdata);
17207113afc8SEmmanuel Vadot 	if (ret) {
17217113afc8SEmmanuel Vadot 		axgbe_error("I2C error setting SFP MUX\n");
17227113afc8SEmmanuel Vadot 		ret = -EIO;
17237113afc8SEmmanuel Vadot 		goto put_own;
17247113afc8SEmmanuel Vadot 	}
17257113afc8SEmmanuel Vadot 
17267113afc8SEmmanuel Vadot 	/* Read the SFP serial ID eeprom */
17277113afc8SEmmanuel Vadot 	eeprom_addr = 0;
17287113afc8SEmmanuel Vadot 	ret = xgbe_phy_i2c_read(pdata, XGBE_SFP_SERIAL_ID_ADDRESS,
17297113afc8SEmmanuel Vadot 				&eeprom_addr, sizeof(eeprom_addr),
17307113afc8SEmmanuel Vadot 				eeprom_data, XGBE_SFP_EEPROM_BASE_LEN);
17317113afc8SEmmanuel Vadot 	if (ret) {
17327113afc8SEmmanuel Vadot 		axgbe_error("I2C error reading SFP EEPROM\n");
17337113afc8SEmmanuel Vadot 		ret = -EIO;
17347113afc8SEmmanuel Vadot 		goto put_mux;
17357113afc8SEmmanuel Vadot 	}
17367113afc8SEmmanuel Vadot 
17377113afc8SEmmanuel Vadot 	sfp_eeprom = (struct xgbe_sfp_eeprom *)eeprom_data;
17387113afc8SEmmanuel Vadot 
17397113afc8SEmmanuel Vadot 	if (XGBE_SFP_DIAGS_SUPPORTED(sfp_eeprom)) {
17407113afc8SEmmanuel Vadot 		/* Read the SFP diagnostic eeprom */
17417113afc8SEmmanuel Vadot 		eeprom_addr = 0;
17427113afc8SEmmanuel Vadot 		ret = xgbe_phy_i2c_read(pdata, XGBE_SFP_DIAG_INFO_ADDRESS,
17437113afc8SEmmanuel Vadot 					&eeprom_addr, sizeof(eeprom_addr),
17447113afc8SEmmanuel Vadot 					eeprom_data + XGBE_SFP_EEPROM_BASE_LEN,
17457113afc8SEmmanuel Vadot 					XGBE_SFP_EEPROM_DIAG_LEN);
17467113afc8SEmmanuel Vadot 		if (ret) {
17477113afc8SEmmanuel Vadot 			axgbe_error("I2C error reading SFP DIAGS\n");
17487113afc8SEmmanuel Vadot 			ret = -EIO;
17497113afc8SEmmanuel Vadot 			goto put_mux;
17507113afc8SEmmanuel Vadot 		}
17517113afc8SEmmanuel Vadot 	}
17527113afc8SEmmanuel Vadot 
17537113afc8SEmmanuel Vadot put_mux:
17547113afc8SEmmanuel Vadot 	xgbe_phy_sfp_put_mux(pdata);
17557113afc8SEmmanuel Vadot 
17567113afc8SEmmanuel Vadot put_own:
17577113afc8SEmmanuel Vadot 	xgbe_phy_put_comm_ownership(pdata);
17587113afc8SEmmanuel Vadot 
17597113afc8SEmmanuel Vadot done:
17607113afc8SEmmanuel Vadot 	return (ret);
17617113afc8SEmmanuel Vadot }
17627113afc8SEmmanuel Vadot 
17637113afc8SEmmanuel Vadot static int
xgbe_phy_module_info(struct xgbe_prv_data * pdata)17647113afc8SEmmanuel Vadot xgbe_phy_module_info(struct xgbe_prv_data *pdata)
17657113afc8SEmmanuel Vadot {
17667113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
17677113afc8SEmmanuel Vadot 
17687113afc8SEmmanuel Vadot 	if (phy_data->port_mode != XGBE_PORT_MODE_SFP)
17697113afc8SEmmanuel Vadot 		return (-ENXIO);
17707113afc8SEmmanuel Vadot 
17717113afc8SEmmanuel Vadot 	if (phy_data->sfp_mod_absent)
17727113afc8SEmmanuel Vadot 		return (-EIO);
17737113afc8SEmmanuel Vadot 
17747113afc8SEmmanuel Vadot 	return (0);
17757113afc8SEmmanuel Vadot }
17767113afc8SEmmanuel Vadot 
17777113afc8SEmmanuel Vadot static void
xgbe_phy_phydev_flowctrl(struct xgbe_prv_data * pdata)17787113afc8SEmmanuel Vadot xgbe_phy_phydev_flowctrl(struct xgbe_prv_data *pdata)
17797113afc8SEmmanuel Vadot {
17807113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
17817113afc8SEmmanuel Vadot 
17827113afc8SEmmanuel Vadot 	pdata->phy.tx_pause = 0;
17837113afc8SEmmanuel Vadot 	pdata->phy.rx_pause = 0;
17847113afc8SEmmanuel Vadot 
17857113afc8SEmmanuel Vadot 	if (!phy_data->phydev)
17867113afc8SEmmanuel Vadot 		return;
17877113afc8SEmmanuel Vadot 
17887113afc8SEmmanuel Vadot 	if (pdata->phy.pause)
17897113afc8SEmmanuel Vadot 		XGBE_SET_LP_ADV(&pdata->phy, Pause);
17907113afc8SEmmanuel Vadot 
17917113afc8SEmmanuel Vadot 	if (pdata->phy.asym_pause)
17927113afc8SEmmanuel Vadot 		XGBE_SET_LP_ADV(&pdata->phy, Asym_Pause);
17937113afc8SEmmanuel Vadot 
17947113afc8SEmmanuel Vadot 	axgbe_printf(1, "%s: pause tx/rx %d/%d\n", __func__,
17957113afc8SEmmanuel Vadot 	    pdata->phy.tx_pause, pdata->phy.rx_pause);
17967113afc8SEmmanuel Vadot }
17977113afc8SEmmanuel Vadot 
17987113afc8SEmmanuel Vadot static enum xgbe_mode
xgbe_phy_an37_sgmii_outcome(struct xgbe_prv_data * pdata)17997113afc8SEmmanuel Vadot xgbe_phy_an37_sgmii_outcome(struct xgbe_prv_data *pdata)
18007113afc8SEmmanuel Vadot {
18017113afc8SEmmanuel Vadot 	enum xgbe_mode mode;
18027113afc8SEmmanuel Vadot 
18037113afc8SEmmanuel Vadot 	XGBE_SET_LP_ADV(&pdata->phy, Autoneg);
18047113afc8SEmmanuel Vadot 	XGBE_SET_LP_ADV(&pdata->phy, TP);
18057113afc8SEmmanuel Vadot 
18067113afc8SEmmanuel Vadot 	axgbe_printf(1, "%s: pause_autoneg %d\n", __func__,
18077113afc8SEmmanuel Vadot 	    pdata->phy.pause_autoneg);
18087113afc8SEmmanuel Vadot 
18097113afc8SEmmanuel Vadot 	/* Use external PHY to determine flow control */
18107113afc8SEmmanuel Vadot 	if (pdata->phy.pause_autoneg)
18117113afc8SEmmanuel Vadot 		xgbe_phy_phydev_flowctrl(pdata);
18127113afc8SEmmanuel Vadot 
18137113afc8SEmmanuel Vadot 	switch (pdata->an_status & XGBE_SGMII_AN_LINK_SPEED) {
18147113afc8SEmmanuel Vadot 	case XGBE_SGMII_AN_LINK_SPEED_100:
18157113afc8SEmmanuel Vadot 		if (pdata->an_status & XGBE_SGMII_AN_LINK_DUPLEX) {
18167113afc8SEmmanuel Vadot 			XGBE_SET_LP_ADV(&pdata->phy, 100baseT_Full);
18177113afc8SEmmanuel Vadot 			mode = XGBE_MODE_SGMII_100;
18187113afc8SEmmanuel Vadot 		} else {
18197113afc8SEmmanuel Vadot 			/* Half-duplex not supported */
18207113afc8SEmmanuel Vadot 			XGBE_SET_LP_ADV(&pdata->phy, 100baseT_Half);
18217113afc8SEmmanuel Vadot 			mode = XGBE_MODE_UNKNOWN;
18227113afc8SEmmanuel Vadot 		}
18237113afc8SEmmanuel Vadot 		break;
18247113afc8SEmmanuel Vadot 	case XGBE_SGMII_AN_LINK_SPEED_1000:
1825445bed5cSStephan de Wit 	default:
1826445bed5cSStephan de Wit 		/* Default to 1000 */
18277113afc8SEmmanuel Vadot 		if (pdata->an_status & XGBE_SGMII_AN_LINK_DUPLEX) {
18287113afc8SEmmanuel Vadot 			XGBE_SET_LP_ADV(&pdata->phy, 1000baseT_Full);
18297113afc8SEmmanuel Vadot 			mode = XGBE_MODE_SGMII_1000;
18307113afc8SEmmanuel Vadot 		} else {
18317113afc8SEmmanuel Vadot 			/* Half-duplex not supported */
18327113afc8SEmmanuel Vadot 			XGBE_SET_LP_ADV(&pdata->phy, 1000baseT_Half);
1833445bed5cSStephan de Wit 			mode = XGBE_MODE_SGMII_1000;
18347113afc8SEmmanuel Vadot 		}
18357113afc8SEmmanuel Vadot 		break;
18367113afc8SEmmanuel Vadot 	}
18377113afc8SEmmanuel Vadot 
18387113afc8SEmmanuel Vadot 	return (mode);
18397113afc8SEmmanuel Vadot }
18407113afc8SEmmanuel Vadot 
18417113afc8SEmmanuel Vadot static enum xgbe_mode
xgbe_phy_an37_outcome(struct xgbe_prv_data * pdata)18427113afc8SEmmanuel Vadot xgbe_phy_an37_outcome(struct xgbe_prv_data *pdata)
18437113afc8SEmmanuel Vadot {
18447113afc8SEmmanuel Vadot 	enum xgbe_mode mode;
18457113afc8SEmmanuel Vadot 	unsigned int ad_reg, lp_reg;
18467113afc8SEmmanuel Vadot 
18477113afc8SEmmanuel Vadot 	XGBE_SET_LP_ADV(&pdata->phy, Autoneg);
18487113afc8SEmmanuel Vadot 	XGBE_SET_LP_ADV(&pdata->phy, FIBRE);
18497113afc8SEmmanuel Vadot 
18507113afc8SEmmanuel Vadot 	/* Compare Advertisement and Link Partner register */
18517113afc8SEmmanuel Vadot 	ad_reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_ADVERTISE);
18527113afc8SEmmanuel Vadot 	lp_reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_LP_ABILITY);
18537113afc8SEmmanuel Vadot 	if (lp_reg & 0x100)
18547113afc8SEmmanuel Vadot 		XGBE_SET_LP_ADV(&pdata->phy, Pause);
18557113afc8SEmmanuel Vadot 	if (lp_reg & 0x80)
18567113afc8SEmmanuel Vadot 		XGBE_SET_LP_ADV(&pdata->phy, Asym_Pause);
18577113afc8SEmmanuel Vadot 
18587113afc8SEmmanuel Vadot 	axgbe_printf(1, "%s: pause_autoneg %d ad_reg 0x%x lp_reg 0x%x\n",
18597113afc8SEmmanuel Vadot 	    __func__, pdata->phy.pause_autoneg, ad_reg, lp_reg);
18607113afc8SEmmanuel Vadot 
18617113afc8SEmmanuel Vadot 	if (pdata->phy.pause_autoneg) {
18627113afc8SEmmanuel Vadot 		/* Set flow control based on auto-negotiation result */
18637113afc8SEmmanuel Vadot 		pdata->phy.tx_pause = 0;
18647113afc8SEmmanuel Vadot 		pdata->phy.rx_pause = 0;
18657113afc8SEmmanuel Vadot 
18667113afc8SEmmanuel Vadot 		if (ad_reg & lp_reg & 0x100) {
18677113afc8SEmmanuel Vadot 			pdata->phy.tx_pause = 1;
18687113afc8SEmmanuel Vadot 			pdata->phy.rx_pause = 1;
18697113afc8SEmmanuel Vadot 		} else if (ad_reg & lp_reg & 0x80) {
18707113afc8SEmmanuel Vadot 			if (ad_reg & 0x100)
18717113afc8SEmmanuel Vadot 				pdata->phy.rx_pause = 1;
18727113afc8SEmmanuel Vadot 			else if (lp_reg & 0x100)
18737113afc8SEmmanuel Vadot 				pdata->phy.tx_pause = 1;
18747113afc8SEmmanuel Vadot 		}
18757113afc8SEmmanuel Vadot 	}
18767113afc8SEmmanuel Vadot 
18777113afc8SEmmanuel Vadot 	axgbe_printf(1, "%s: pause tx/rx %d/%d\n", __func__, pdata->phy.tx_pause,
18787113afc8SEmmanuel Vadot 	    pdata->phy.rx_pause);
18797113afc8SEmmanuel Vadot 
18807113afc8SEmmanuel Vadot 	if (lp_reg & 0x20)
18817113afc8SEmmanuel Vadot 		XGBE_SET_LP_ADV(&pdata->phy, 1000baseX_Full);
18827113afc8SEmmanuel Vadot 
18837113afc8SEmmanuel Vadot 	/* Half duplex is not supported */
18847113afc8SEmmanuel Vadot 	ad_reg &= lp_reg;
18857113afc8SEmmanuel Vadot 	mode = (ad_reg & 0x20) ? XGBE_MODE_X : XGBE_MODE_UNKNOWN;
18867113afc8SEmmanuel Vadot 
18877113afc8SEmmanuel Vadot 	return (mode);
18887113afc8SEmmanuel Vadot }
18897113afc8SEmmanuel Vadot 
18907113afc8SEmmanuel Vadot static enum xgbe_mode
xgbe_phy_an73_redrv_outcome(struct xgbe_prv_data * pdata)18917113afc8SEmmanuel Vadot xgbe_phy_an73_redrv_outcome(struct xgbe_prv_data *pdata)
18927113afc8SEmmanuel Vadot {
18937113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
18947113afc8SEmmanuel Vadot 	enum xgbe_mode mode;
18957113afc8SEmmanuel Vadot 	unsigned int ad_reg, lp_reg;
18967113afc8SEmmanuel Vadot 
18977113afc8SEmmanuel Vadot 	XGBE_SET_LP_ADV(&pdata->phy, Autoneg);
18987113afc8SEmmanuel Vadot 	XGBE_SET_LP_ADV(&pdata->phy, Backplane);
18997113afc8SEmmanuel Vadot 
19007113afc8SEmmanuel Vadot 	axgbe_printf(1, "%s: pause_autoneg %d\n", __func__,
19017113afc8SEmmanuel Vadot 	    pdata->phy.pause_autoneg);
19027113afc8SEmmanuel Vadot 
19037113afc8SEmmanuel Vadot 	/* Use external PHY to determine flow control */
19047113afc8SEmmanuel Vadot 	if (pdata->phy.pause_autoneg)
19057113afc8SEmmanuel Vadot 		xgbe_phy_phydev_flowctrl(pdata);
19067113afc8SEmmanuel Vadot 
19077113afc8SEmmanuel Vadot 	/* Compare Advertisement and Link Partner register 2 */
19087113afc8SEmmanuel Vadot 	ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1);
19097113afc8SEmmanuel Vadot 	lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1);
19107113afc8SEmmanuel Vadot 	if (lp_reg & 0x80)
19117113afc8SEmmanuel Vadot 		XGBE_SET_LP_ADV(&pdata->phy, 10000baseKR_Full);
19127113afc8SEmmanuel Vadot 	if (lp_reg & 0x20)
19137113afc8SEmmanuel Vadot 		XGBE_SET_LP_ADV(&pdata->phy, 1000baseKX_Full);
19147113afc8SEmmanuel Vadot 
19157113afc8SEmmanuel Vadot 	ad_reg &= lp_reg;
19167113afc8SEmmanuel Vadot 	if (ad_reg & 0x80) {
19177113afc8SEmmanuel Vadot 		switch (phy_data->port_mode) {
19187113afc8SEmmanuel Vadot 		case XGBE_PORT_MODE_BACKPLANE:
19197113afc8SEmmanuel Vadot 			mode = XGBE_MODE_KR;
19207113afc8SEmmanuel Vadot 			break;
19217113afc8SEmmanuel Vadot 		default:
19227113afc8SEmmanuel Vadot 			mode = XGBE_MODE_SFI;
19237113afc8SEmmanuel Vadot 			break;
19247113afc8SEmmanuel Vadot 		}
19257113afc8SEmmanuel Vadot 	} else if (ad_reg & 0x20) {
19267113afc8SEmmanuel Vadot 		switch (phy_data->port_mode) {
19277113afc8SEmmanuel Vadot 		case XGBE_PORT_MODE_BACKPLANE:
19287113afc8SEmmanuel Vadot 			mode = XGBE_MODE_KX_1000;
19297113afc8SEmmanuel Vadot 			break;
19307113afc8SEmmanuel Vadot 		case XGBE_PORT_MODE_1000BASE_X:
19317113afc8SEmmanuel Vadot 			mode = XGBE_MODE_X;
19327113afc8SEmmanuel Vadot 			break;
19337113afc8SEmmanuel Vadot 		case XGBE_PORT_MODE_SFP:
19347113afc8SEmmanuel Vadot 			switch (phy_data->sfp_base) {
19357113afc8SEmmanuel Vadot 			case XGBE_SFP_BASE_1000_T:
19367113afc8SEmmanuel Vadot 				if ((phy_data->phydev) &&
19377113afc8SEmmanuel Vadot 				    (pdata->phy.speed == SPEED_100))
19387113afc8SEmmanuel Vadot 					mode = XGBE_MODE_SGMII_100;
19397113afc8SEmmanuel Vadot 				else
19407113afc8SEmmanuel Vadot 					mode = XGBE_MODE_SGMII_1000;
19417113afc8SEmmanuel Vadot 				break;
19427113afc8SEmmanuel Vadot 			case XGBE_SFP_BASE_1000_SX:
19437113afc8SEmmanuel Vadot 			case XGBE_SFP_BASE_1000_LX:
19447113afc8SEmmanuel Vadot 			case XGBE_SFP_BASE_1000_CX:
19457113afc8SEmmanuel Vadot 			default:
19467113afc8SEmmanuel Vadot 				mode = XGBE_MODE_X;
19477113afc8SEmmanuel Vadot 				break;
19487113afc8SEmmanuel Vadot 			}
19497113afc8SEmmanuel Vadot 			break;
19507113afc8SEmmanuel Vadot 		default:
19517113afc8SEmmanuel Vadot 			if ((phy_data->phydev) &&
19527113afc8SEmmanuel Vadot 			    (pdata->phy.speed == SPEED_100))
19537113afc8SEmmanuel Vadot 				mode = XGBE_MODE_SGMII_100;
19547113afc8SEmmanuel Vadot 			else
19557113afc8SEmmanuel Vadot 				mode = XGBE_MODE_SGMII_1000;
19567113afc8SEmmanuel Vadot 			break;
19577113afc8SEmmanuel Vadot 		}
19587113afc8SEmmanuel Vadot 	} else {
19597113afc8SEmmanuel Vadot 		mode = XGBE_MODE_UNKNOWN;
19607113afc8SEmmanuel Vadot 	}
19617113afc8SEmmanuel Vadot 
19627113afc8SEmmanuel Vadot 	/* Compare Advertisement and Link Partner register 3 */
19637113afc8SEmmanuel Vadot 	ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
19647113afc8SEmmanuel Vadot 	lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2);
19657113afc8SEmmanuel Vadot 	if (lp_reg & 0xc000)
19667113afc8SEmmanuel Vadot 		XGBE_SET_LP_ADV(&pdata->phy, 10000baseR_FEC);
19677113afc8SEmmanuel Vadot 
19687113afc8SEmmanuel Vadot 	return (mode);
19697113afc8SEmmanuel Vadot }
19707113afc8SEmmanuel Vadot 
19717113afc8SEmmanuel Vadot static enum xgbe_mode
xgbe_phy_an73_outcome(struct xgbe_prv_data * pdata)19727113afc8SEmmanuel Vadot xgbe_phy_an73_outcome(struct xgbe_prv_data *pdata)
19737113afc8SEmmanuel Vadot {
19747113afc8SEmmanuel Vadot 	enum xgbe_mode mode;
19757113afc8SEmmanuel Vadot 	unsigned int ad_reg, lp_reg;
19767113afc8SEmmanuel Vadot 
19777113afc8SEmmanuel Vadot 	XGBE_SET_LP_ADV(&pdata->phy, Autoneg);
19787113afc8SEmmanuel Vadot 	XGBE_SET_LP_ADV(&pdata->phy, Backplane);
19797113afc8SEmmanuel Vadot 
19807113afc8SEmmanuel Vadot 	/* Compare Advertisement and Link Partner register 1 */
19817113afc8SEmmanuel Vadot 	ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
19827113afc8SEmmanuel Vadot 	lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA);
19837113afc8SEmmanuel Vadot 	if (lp_reg & 0x400)
19847113afc8SEmmanuel Vadot 		XGBE_SET_LP_ADV(&pdata->phy, Pause);
19857113afc8SEmmanuel Vadot 	if (lp_reg & 0x800)
19867113afc8SEmmanuel Vadot 		XGBE_SET_LP_ADV(&pdata->phy, Asym_Pause);
19877113afc8SEmmanuel Vadot 
19887113afc8SEmmanuel Vadot 	axgbe_printf(1, "%s: pause_autoneg %d ad_reg 0x%x lp_reg 0x%x\n",
19897113afc8SEmmanuel Vadot 	    __func__, pdata->phy.pause_autoneg, ad_reg, lp_reg);
19907113afc8SEmmanuel Vadot 
19917113afc8SEmmanuel Vadot 	if (pdata->phy.pause_autoneg) {
19927113afc8SEmmanuel Vadot 		/* Set flow control based on auto-negotiation result */
19937113afc8SEmmanuel Vadot 		pdata->phy.tx_pause = 0;
19947113afc8SEmmanuel Vadot 		pdata->phy.rx_pause = 0;
19957113afc8SEmmanuel Vadot 
19967113afc8SEmmanuel Vadot 		if (ad_reg & lp_reg & 0x400) {
19977113afc8SEmmanuel Vadot 			pdata->phy.tx_pause = 1;
19987113afc8SEmmanuel Vadot 			pdata->phy.rx_pause = 1;
19997113afc8SEmmanuel Vadot 		} else if (ad_reg & lp_reg & 0x800) {
20007113afc8SEmmanuel Vadot 			if (ad_reg & 0x400)
20017113afc8SEmmanuel Vadot 				pdata->phy.rx_pause = 1;
20027113afc8SEmmanuel Vadot 			else if (lp_reg & 0x400)
20037113afc8SEmmanuel Vadot 				pdata->phy.tx_pause = 1;
20047113afc8SEmmanuel Vadot 		}
20057113afc8SEmmanuel Vadot 	}
20067113afc8SEmmanuel Vadot 
20077113afc8SEmmanuel Vadot 	axgbe_printf(1, "%s: pause tx/rx %d/%d\n", __func__, pdata->phy.tx_pause,
20087113afc8SEmmanuel Vadot 	    pdata->phy.rx_pause);
20097113afc8SEmmanuel Vadot 
20107113afc8SEmmanuel Vadot 	/* Compare Advertisement and Link Partner register 2 */
20117113afc8SEmmanuel Vadot 	ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1);
20127113afc8SEmmanuel Vadot 	lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1);
20137113afc8SEmmanuel Vadot 	if (lp_reg & 0x80)
20147113afc8SEmmanuel Vadot 		XGBE_SET_LP_ADV(&pdata->phy, 10000baseKR_Full);
20157113afc8SEmmanuel Vadot 	if (lp_reg & 0x20)
20167113afc8SEmmanuel Vadot 		XGBE_SET_LP_ADV(&pdata->phy, 1000baseKX_Full);
20177113afc8SEmmanuel Vadot 
20187113afc8SEmmanuel Vadot 	ad_reg &= lp_reg;
20197113afc8SEmmanuel Vadot 	if (ad_reg & 0x80)
20207113afc8SEmmanuel Vadot 		mode = XGBE_MODE_KR;
20217113afc8SEmmanuel Vadot 	else if (ad_reg & 0x20)
20227113afc8SEmmanuel Vadot 		mode = XGBE_MODE_KX_1000;
20237113afc8SEmmanuel Vadot 	else
20247113afc8SEmmanuel Vadot 		mode = XGBE_MODE_UNKNOWN;
20257113afc8SEmmanuel Vadot 
20267113afc8SEmmanuel Vadot 	/* Compare Advertisement and Link Partner register 3 */
20277113afc8SEmmanuel Vadot 	ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
20287113afc8SEmmanuel Vadot 	lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2);
20297113afc8SEmmanuel Vadot 	if (lp_reg & 0xc000)
20307113afc8SEmmanuel Vadot 		XGBE_SET_LP_ADV(&pdata->phy, 10000baseR_FEC);
20317113afc8SEmmanuel Vadot 
20327113afc8SEmmanuel Vadot 	return (mode);
20337113afc8SEmmanuel Vadot }
20347113afc8SEmmanuel Vadot 
20357113afc8SEmmanuel Vadot static enum xgbe_mode
xgbe_phy_an_outcome(struct xgbe_prv_data * pdata)20367113afc8SEmmanuel Vadot xgbe_phy_an_outcome(struct xgbe_prv_data *pdata)
20377113afc8SEmmanuel Vadot {
20387113afc8SEmmanuel Vadot 	switch (pdata->an_mode) {
20397113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL73:
20407113afc8SEmmanuel Vadot 		return (xgbe_phy_an73_outcome(pdata));
20417113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL73_REDRV:
20427113afc8SEmmanuel Vadot 		return (xgbe_phy_an73_redrv_outcome(pdata));
20437113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL37:
20447113afc8SEmmanuel Vadot 		return (xgbe_phy_an37_outcome(pdata));
20457113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL37_SGMII:
20467113afc8SEmmanuel Vadot 		return (xgbe_phy_an37_sgmii_outcome(pdata));
20477113afc8SEmmanuel Vadot 	default:
20487113afc8SEmmanuel Vadot 		return (XGBE_MODE_UNKNOWN);
20497113afc8SEmmanuel Vadot 	}
20507113afc8SEmmanuel Vadot }
20517113afc8SEmmanuel Vadot 
20527113afc8SEmmanuel Vadot static void
xgbe_phy_an_advertising(struct xgbe_prv_data * pdata,struct xgbe_phy * dphy)20537113afc8SEmmanuel Vadot xgbe_phy_an_advertising(struct xgbe_prv_data *pdata, struct xgbe_phy *dphy)
20547113afc8SEmmanuel Vadot {
20557113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
20567113afc8SEmmanuel Vadot 
20577113afc8SEmmanuel Vadot 	XGBE_LM_COPY(dphy, advertising, &pdata->phy, advertising);
20587113afc8SEmmanuel Vadot 
20597113afc8SEmmanuel Vadot 	/* Without a re-driver, just return current advertising */
20607113afc8SEmmanuel Vadot 	if (!phy_data->redrv)
20617113afc8SEmmanuel Vadot 		return;
20627113afc8SEmmanuel Vadot 
20637113afc8SEmmanuel Vadot 	/* With the KR re-driver we need to advertise a single speed */
20647113afc8SEmmanuel Vadot 	XGBE_CLR_ADV(dphy, 1000baseKX_Full);
20657113afc8SEmmanuel Vadot 	XGBE_CLR_ADV(dphy, 10000baseKR_Full);
20667113afc8SEmmanuel Vadot 
20677113afc8SEmmanuel Vadot 	/* Advertise FEC support is present */
20687113afc8SEmmanuel Vadot 	if (pdata->fec_ability & MDIO_PMA_10GBR_FECABLE_ABLE)
20697113afc8SEmmanuel Vadot 		XGBE_SET_ADV(dphy, 10000baseR_FEC);
20707113afc8SEmmanuel Vadot 
20717113afc8SEmmanuel Vadot 	switch (phy_data->port_mode) {
20727113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_BACKPLANE:
20737113afc8SEmmanuel Vadot 		XGBE_SET_ADV(dphy, 10000baseKR_Full);
20747113afc8SEmmanuel Vadot 		break;
20757113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_BACKPLANE_2500:
20767113afc8SEmmanuel Vadot 		XGBE_SET_ADV(dphy, 1000baseKX_Full);
20777113afc8SEmmanuel Vadot 		break;
20787113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_1000BASE_T:
20797113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_1000BASE_X:
20807113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_NBASE_T:
20817113afc8SEmmanuel Vadot 		XGBE_SET_ADV(dphy, 1000baseKX_Full);
20827113afc8SEmmanuel Vadot 		break;
20837113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_10GBASE_T:
20847113afc8SEmmanuel Vadot 		if ((phy_data->phydev) &&
20857113afc8SEmmanuel Vadot 		    (pdata->phy.speed == SPEED_10000))
20867113afc8SEmmanuel Vadot 			XGBE_SET_ADV(dphy, 10000baseKR_Full);
20877113afc8SEmmanuel Vadot 		else
20887113afc8SEmmanuel Vadot 			XGBE_SET_ADV(dphy, 1000baseKX_Full);
20897113afc8SEmmanuel Vadot 		break;
20907113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_10GBASE_R:
20917113afc8SEmmanuel Vadot 		XGBE_SET_ADV(dphy, 10000baseKR_Full);
20927113afc8SEmmanuel Vadot 		break;
20937113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_SFP:
20947113afc8SEmmanuel Vadot 		switch (phy_data->sfp_base) {
20957113afc8SEmmanuel Vadot 		case XGBE_SFP_BASE_1000_T:
20967113afc8SEmmanuel Vadot 		case XGBE_SFP_BASE_1000_SX:
20977113afc8SEmmanuel Vadot 		case XGBE_SFP_BASE_1000_LX:
20987113afc8SEmmanuel Vadot 		case XGBE_SFP_BASE_1000_CX:
20997113afc8SEmmanuel Vadot 			XGBE_SET_ADV(dphy, 1000baseKX_Full);
21007113afc8SEmmanuel Vadot 			break;
21017113afc8SEmmanuel Vadot 		default:
21027113afc8SEmmanuel Vadot 			XGBE_SET_ADV(dphy, 10000baseKR_Full);
21037113afc8SEmmanuel Vadot 			break;
21047113afc8SEmmanuel Vadot 		}
21057113afc8SEmmanuel Vadot 		break;
21067113afc8SEmmanuel Vadot 	default:
21077113afc8SEmmanuel Vadot 		XGBE_SET_ADV(dphy, 10000baseKR_Full);
21087113afc8SEmmanuel Vadot 		break;
21097113afc8SEmmanuel Vadot 	}
21107113afc8SEmmanuel Vadot }
21117113afc8SEmmanuel Vadot 
21127113afc8SEmmanuel Vadot static int
xgbe_phy_an_config(struct xgbe_prv_data * pdata)21137113afc8SEmmanuel Vadot xgbe_phy_an_config(struct xgbe_prv_data *pdata)
21147113afc8SEmmanuel Vadot {
21157113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
21167113afc8SEmmanuel Vadot 	int ret;
21177113afc8SEmmanuel Vadot 
21187113afc8SEmmanuel Vadot 	ret = xgbe_phy_find_phy_device(pdata);
21197113afc8SEmmanuel Vadot 	if (ret)
21207113afc8SEmmanuel Vadot 		return (ret);
21217113afc8SEmmanuel Vadot 
21227113afc8SEmmanuel Vadot 	axgbe_printf(2, "%s: find_phy_device return %s.\n", __func__,
21237113afc8SEmmanuel Vadot 	    ret ? "Failure" : "Success");
21247113afc8SEmmanuel Vadot 
21257113afc8SEmmanuel Vadot 	if (!phy_data->phydev)
21267113afc8SEmmanuel Vadot 		return (0);
21277113afc8SEmmanuel Vadot 
21287113afc8SEmmanuel Vadot 	return (ret);
21297113afc8SEmmanuel Vadot }
21307113afc8SEmmanuel Vadot 
21317113afc8SEmmanuel Vadot static enum xgbe_an_mode
xgbe_phy_an_sfp_mode(struct xgbe_phy_data * phy_data)21327113afc8SEmmanuel Vadot xgbe_phy_an_sfp_mode(struct xgbe_phy_data *phy_data)
21337113afc8SEmmanuel Vadot {
21347113afc8SEmmanuel Vadot 	switch (phy_data->sfp_base) {
21357113afc8SEmmanuel Vadot 	case XGBE_SFP_BASE_1000_T:
21367113afc8SEmmanuel Vadot 		return (XGBE_AN_MODE_CL37_SGMII);
21377113afc8SEmmanuel Vadot 	case XGBE_SFP_BASE_1000_SX:
21387113afc8SEmmanuel Vadot 	case XGBE_SFP_BASE_1000_LX:
21397113afc8SEmmanuel Vadot 	case XGBE_SFP_BASE_1000_CX:
21407113afc8SEmmanuel Vadot 		return (XGBE_AN_MODE_CL37);
21417113afc8SEmmanuel Vadot 	default:
21427113afc8SEmmanuel Vadot 		return (XGBE_AN_MODE_NONE);
21437113afc8SEmmanuel Vadot 	}
21447113afc8SEmmanuel Vadot }
21457113afc8SEmmanuel Vadot 
21467113afc8SEmmanuel Vadot static enum xgbe_an_mode
xgbe_phy_an_mode(struct xgbe_prv_data * pdata)21477113afc8SEmmanuel Vadot xgbe_phy_an_mode(struct xgbe_prv_data *pdata)
21487113afc8SEmmanuel Vadot {
21497113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
21507113afc8SEmmanuel Vadot 
21517113afc8SEmmanuel Vadot 	/* A KR re-driver will always require CL73 AN */
21527113afc8SEmmanuel Vadot 	if (phy_data->redrv)
21537113afc8SEmmanuel Vadot 		return (XGBE_AN_MODE_CL73_REDRV);
21547113afc8SEmmanuel Vadot 
21557113afc8SEmmanuel Vadot 	switch (phy_data->port_mode) {
21567113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_BACKPLANE:
21577113afc8SEmmanuel Vadot 		return (XGBE_AN_MODE_CL73);
21587113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_BACKPLANE_2500:
21597113afc8SEmmanuel Vadot 		return (XGBE_AN_MODE_NONE);
21607113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_1000BASE_T:
21617113afc8SEmmanuel Vadot 		return (XGBE_AN_MODE_CL37_SGMII);
21627113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_1000BASE_X:
21637113afc8SEmmanuel Vadot 		return (XGBE_AN_MODE_CL37);
21647113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_NBASE_T:
21657113afc8SEmmanuel Vadot 		return (XGBE_AN_MODE_CL37_SGMII);
21667113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_10GBASE_T:
21677113afc8SEmmanuel Vadot 		return (XGBE_AN_MODE_CL73);
21687113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_10GBASE_R:
21697113afc8SEmmanuel Vadot 		return (XGBE_AN_MODE_NONE);
21707113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_SFP:
21717113afc8SEmmanuel Vadot 		return (xgbe_phy_an_sfp_mode(phy_data));
21727113afc8SEmmanuel Vadot 	default:
21737113afc8SEmmanuel Vadot 		return (XGBE_AN_MODE_NONE);
21747113afc8SEmmanuel Vadot 	}
21757113afc8SEmmanuel Vadot }
21767113afc8SEmmanuel Vadot 
21777113afc8SEmmanuel Vadot static int
xgbe_phy_set_redrv_mode_mdio(struct xgbe_prv_data * pdata,enum xgbe_phy_redrv_mode mode)21787113afc8SEmmanuel Vadot xgbe_phy_set_redrv_mode_mdio(struct xgbe_prv_data *pdata,
21797113afc8SEmmanuel Vadot     enum xgbe_phy_redrv_mode mode)
21807113afc8SEmmanuel Vadot {
21817113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
21827113afc8SEmmanuel Vadot 	uint16_t redrv_reg, redrv_val;
21837113afc8SEmmanuel Vadot 
21847113afc8SEmmanuel Vadot 	redrv_reg = XGBE_PHY_REDRV_MODE_REG + (phy_data->redrv_lane * 0x1000);
21857113afc8SEmmanuel Vadot 	redrv_val = (uint16_t)mode;
21867113afc8SEmmanuel Vadot 
21877113afc8SEmmanuel Vadot 	return (pdata->hw_if.write_ext_mii_regs(pdata, phy_data->redrv_addr,
21887113afc8SEmmanuel Vadot 	    redrv_reg, redrv_val));
21897113afc8SEmmanuel Vadot }
21907113afc8SEmmanuel Vadot 
21917113afc8SEmmanuel Vadot static int
xgbe_phy_set_redrv_mode_i2c(struct xgbe_prv_data * pdata,enum xgbe_phy_redrv_mode mode)21927113afc8SEmmanuel Vadot xgbe_phy_set_redrv_mode_i2c(struct xgbe_prv_data *pdata,
21937113afc8SEmmanuel Vadot     enum xgbe_phy_redrv_mode mode)
21947113afc8SEmmanuel Vadot {
21957113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
21967113afc8SEmmanuel Vadot 	unsigned int redrv_reg;
21977113afc8SEmmanuel Vadot 	int ret;
21987113afc8SEmmanuel Vadot 
21997113afc8SEmmanuel Vadot 	/* Calculate the register to write */
22007113afc8SEmmanuel Vadot 	redrv_reg = XGBE_PHY_REDRV_MODE_REG + (phy_data->redrv_lane * 0x1000);
22017113afc8SEmmanuel Vadot 
22027113afc8SEmmanuel Vadot 	ret = xgbe_phy_redrv_write(pdata, redrv_reg, mode);
22037113afc8SEmmanuel Vadot 
22047113afc8SEmmanuel Vadot 	return (ret);
22057113afc8SEmmanuel Vadot }
22067113afc8SEmmanuel Vadot 
22077113afc8SEmmanuel Vadot static void
xgbe_phy_set_redrv_mode(struct xgbe_prv_data * pdata)22087113afc8SEmmanuel Vadot xgbe_phy_set_redrv_mode(struct xgbe_prv_data *pdata)
22097113afc8SEmmanuel Vadot {
22107113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
22117113afc8SEmmanuel Vadot 	enum xgbe_phy_redrv_mode mode;
22127113afc8SEmmanuel Vadot 	int ret;
22137113afc8SEmmanuel Vadot 
22147113afc8SEmmanuel Vadot 	if (!phy_data->redrv)
22157113afc8SEmmanuel Vadot 		return;
22167113afc8SEmmanuel Vadot 
22177113afc8SEmmanuel Vadot 	mode = XGBE_PHY_REDRV_MODE_CX;
22187113afc8SEmmanuel Vadot 	if ((phy_data->port_mode == XGBE_PORT_MODE_SFP) &&
22197113afc8SEmmanuel Vadot 	    (phy_data->sfp_base != XGBE_SFP_BASE_1000_CX) &&
22207113afc8SEmmanuel Vadot 	    (phy_data->sfp_base != XGBE_SFP_BASE_10000_CR))
22217113afc8SEmmanuel Vadot 		mode = XGBE_PHY_REDRV_MODE_SR;
22227113afc8SEmmanuel Vadot 
22237113afc8SEmmanuel Vadot 	ret = xgbe_phy_get_comm_ownership(pdata);
22247113afc8SEmmanuel Vadot 	if (ret)
22257113afc8SEmmanuel Vadot 		return;
22267113afc8SEmmanuel Vadot 
22277113afc8SEmmanuel Vadot 	axgbe_printf(2, "%s: redrv_if set: %d\n", __func__, phy_data->redrv_if);
22287113afc8SEmmanuel Vadot 	if (phy_data->redrv_if)
22297113afc8SEmmanuel Vadot 		xgbe_phy_set_redrv_mode_i2c(pdata, mode);
22307113afc8SEmmanuel Vadot 	else
22317113afc8SEmmanuel Vadot 		xgbe_phy_set_redrv_mode_mdio(pdata, mode);
22327113afc8SEmmanuel Vadot 
22337113afc8SEmmanuel Vadot 	xgbe_phy_put_comm_ownership(pdata);
22347113afc8SEmmanuel Vadot }
22357113afc8SEmmanuel Vadot 
22367113afc8SEmmanuel Vadot static void
xgbe_phy_pll_ctrl(struct xgbe_prv_data * pdata,bool enable)2237445bed5cSStephan de Wit xgbe_phy_pll_ctrl(struct xgbe_prv_data *pdata, bool enable)
2238445bed5cSStephan de Wit {
2239445bed5cSStephan de Wit 	XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_VEND2_PMA_MISC_CTRL0,
2240445bed5cSStephan de Wit 					XGBE_PMA_PLL_CTRL_MASK,
2241445bed5cSStephan de Wit 					enable ? XGBE_PMA_PLL_CTRL_ENABLE
2242445bed5cSStephan de Wit 					       : XGBE_PMA_PLL_CTRL_DISABLE);
2243445bed5cSStephan de Wit 	DELAY(200);
2244445bed5cSStephan de Wit }
2245445bed5cSStephan de Wit 
2246445bed5cSStephan de Wit static void
xgbe_phy_rx_reset(struct xgbe_prv_data * pdata)22472b8df536SStephan de Wit xgbe_phy_rx_reset(struct xgbe_prv_data *pdata)
22482b8df536SStephan de Wit {
22492b8df536SStephan de Wit 	int reg;
22502b8df536SStephan de Wit 
22512b8df536SStephan de Wit 	reg = XMDIO_READ_BITS(pdata, MDIO_MMD_PCS, MDIO_PCS_DIGITAL_STAT,
22522b8df536SStephan de Wit 			     XGBE_PCS_PSEQ_STATE_MASK);
22532b8df536SStephan de Wit 
22542b8df536SStephan de Wit 	if (reg == XGBE_PCS_PSEQ_STATE_POWER_GOOD) {
22552b8df536SStephan de Wit 		/*
22562b8df536SStephan de Wit 	         * Mailbox command timed out, reset of RX block is required.
22572b8df536SStephan de Wit 		 * This can be done by asserting the reset bit and waiting
22582b8df536SStephan de Wit 		 * for its completion.
22592b8df536SStephan de Wit 		 */
22602b8df536SStephan de Wit 		XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_RX_CTRL1,
22612b8df536SStephan de Wit 				XGBE_PMA_RX_RST_0_MASK, XGBE_PMA_RX_RST_0_RESET_ON);
22622b8df536SStephan de Wit 		DELAY(20);
22632b8df536SStephan de Wit 		XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_RX_CTRL1,
22642b8df536SStephan de Wit 				XGBE_PMA_RX_RST_0_MASK, XGBE_PMA_RX_RST_0_RESET_OFF);
22652b8df536SStephan de Wit 		DELAY(50);
22662b8df536SStephan de Wit 		axgbe_printf(0, "%s: firmware mailbox reset performed\n", __func__);
22672b8df536SStephan de Wit 	}
22682b8df536SStephan de Wit }
22692b8df536SStephan de Wit 
22702b8df536SStephan de Wit static void
xgbe_phy_perform_ratechange(struct xgbe_prv_data * pdata,unsigned int cmd,unsigned int sub_cmd)22717113afc8SEmmanuel Vadot xgbe_phy_perform_ratechange(struct xgbe_prv_data *pdata, unsigned int cmd,
22727113afc8SEmmanuel Vadot     unsigned int sub_cmd)
22737113afc8SEmmanuel Vadot {
22747113afc8SEmmanuel Vadot 	unsigned int s0 = 0;
22757113afc8SEmmanuel Vadot 	unsigned int wait;
22767113afc8SEmmanuel Vadot 
2277445bed5cSStephan de Wit 	xgbe_phy_pll_ctrl(pdata, false);
2278445bed5cSStephan de Wit 
22797113afc8SEmmanuel Vadot 	/* Log if a previous command did not complete */
22802b8df536SStephan de Wit 	if (XP_IOREAD_BITS(pdata, XP_DRIVER_INT_RO, STATUS)) {
22817113afc8SEmmanuel Vadot 		axgbe_error("firmware mailbox not ready for command\n");
22822b8df536SStephan de Wit 		xgbe_phy_rx_reset(pdata);
22832b8df536SStephan de Wit 	}
22847113afc8SEmmanuel Vadot 
22857113afc8SEmmanuel Vadot 	/* Construct the command */
22867113afc8SEmmanuel Vadot 	XP_SET_BITS(s0, XP_DRIVER_SCRATCH_0, COMMAND, cmd);
22877113afc8SEmmanuel Vadot 	XP_SET_BITS(s0, XP_DRIVER_SCRATCH_0, SUB_COMMAND, sub_cmd);
22887113afc8SEmmanuel Vadot 
22897113afc8SEmmanuel Vadot 	/* Issue the command */
22907113afc8SEmmanuel Vadot 	XP_IOWRITE(pdata, XP_DRIVER_SCRATCH_0, s0);
22917113afc8SEmmanuel Vadot 	XP_IOWRITE(pdata, XP_DRIVER_SCRATCH_1, 0);
22927113afc8SEmmanuel Vadot 	XP_IOWRITE_BITS(pdata, XP_DRIVER_INT_REQ, REQUEST, 1);
22937113afc8SEmmanuel Vadot 
22947113afc8SEmmanuel Vadot 	/* Wait for command to complete */
22957113afc8SEmmanuel Vadot 	wait = XGBE_RATECHANGE_COUNT;
22967113afc8SEmmanuel Vadot 	while (wait--) {
22977113afc8SEmmanuel Vadot 		if (!XP_IOREAD_BITS(pdata, XP_DRIVER_INT_RO, STATUS)) {
22987113afc8SEmmanuel Vadot 			axgbe_printf(3, "%s: Rate change done\n", __func__);
2299445bed5cSStephan de Wit 			goto reenable_pll;
23007113afc8SEmmanuel Vadot 		}
23017113afc8SEmmanuel Vadot 
23027113afc8SEmmanuel Vadot 		DELAY(2000);
23037113afc8SEmmanuel Vadot 	}
23047113afc8SEmmanuel Vadot 
23057113afc8SEmmanuel Vadot 	axgbe_printf(3, "firmware mailbox command did not complete\n");
2306445bed5cSStephan de Wit 
2307445bed5cSStephan de Wit reenable_pll:
2308445bed5cSStephan de Wit 	xgbe_phy_pll_ctrl(pdata, true);
23097113afc8SEmmanuel Vadot }
23107113afc8SEmmanuel Vadot 
23117113afc8SEmmanuel Vadot static void
xgbe_phy_rrc(struct xgbe_prv_data * pdata)23127113afc8SEmmanuel Vadot xgbe_phy_rrc(struct xgbe_prv_data *pdata)
23137113afc8SEmmanuel Vadot {
23147113afc8SEmmanuel Vadot 	/* Receiver Reset Cycle */
23157113afc8SEmmanuel Vadot 	xgbe_phy_perform_ratechange(pdata, 5, 0);
23167113afc8SEmmanuel Vadot 
23177113afc8SEmmanuel Vadot 	axgbe_printf(3, "receiver reset complete\n");
23187113afc8SEmmanuel Vadot }
23197113afc8SEmmanuel Vadot 
23207113afc8SEmmanuel Vadot static void
xgbe_phy_power_off(struct xgbe_prv_data * pdata)23217113afc8SEmmanuel Vadot xgbe_phy_power_off(struct xgbe_prv_data *pdata)
23227113afc8SEmmanuel Vadot {
23237113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
23247113afc8SEmmanuel Vadot 
23257113afc8SEmmanuel Vadot 	/* Power off */
23267113afc8SEmmanuel Vadot 	xgbe_phy_perform_ratechange(pdata, 0, 0);
23277113afc8SEmmanuel Vadot 
23287113afc8SEmmanuel Vadot 	phy_data->cur_mode = XGBE_MODE_UNKNOWN;
23297113afc8SEmmanuel Vadot 
23307113afc8SEmmanuel Vadot 	axgbe_printf(3, "phy powered off\n");
23317113afc8SEmmanuel Vadot }
23327113afc8SEmmanuel Vadot 
23337113afc8SEmmanuel Vadot static void
xgbe_phy_sfi_mode(struct xgbe_prv_data * pdata)23347113afc8SEmmanuel Vadot xgbe_phy_sfi_mode(struct xgbe_prv_data *pdata)
23357113afc8SEmmanuel Vadot {
23367113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
23377113afc8SEmmanuel Vadot 
23387113afc8SEmmanuel Vadot 	xgbe_phy_set_redrv_mode(pdata);
23397113afc8SEmmanuel Vadot 
23407113afc8SEmmanuel Vadot 	/* 10G/SFI */
23417113afc8SEmmanuel Vadot 	axgbe_printf(3, "%s: cable %d len %d\n", __func__, phy_data->sfp_cable,
23427113afc8SEmmanuel Vadot 	    phy_data->sfp_cable_len);
23437113afc8SEmmanuel Vadot 
23447113afc8SEmmanuel Vadot 	if (phy_data->sfp_cable != XGBE_SFP_CABLE_PASSIVE)
23457113afc8SEmmanuel Vadot 		xgbe_phy_perform_ratechange(pdata, 3, 0);
23467113afc8SEmmanuel Vadot 	else {
23477113afc8SEmmanuel Vadot 		if (phy_data->sfp_cable_len <= 1)
23487113afc8SEmmanuel Vadot 			xgbe_phy_perform_ratechange(pdata, 3, 1);
23497113afc8SEmmanuel Vadot 		else if (phy_data->sfp_cable_len <= 3)
23507113afc8SEmmanuel Vadot 			xgbe_phy_perform_ratechange(pdata, 3, 2);
23517113afc8SEmmanuel Vadot 		else
23527113afc8SEmmanuel Vadot 			xgbe_phy_perform_ratechange(pdata, 3, 3);
23537113afc8SEmmanuel Vadot 	}
23547113afc8SEmmanuel Vadot 
23557113afc8SEmmanuel Vadot 	phy_data->cur_mode = XGBE_MODE_SFI;
23567113afc8SEmmanuel Vadot 
23577113afc8SEmmanuel Vadot 	axgbe_printf(3, "10GbE SFI mode set\n");
23587113afc8SEmmanuel Vadot }
23597113afc8SEmmanuel Vadot 
23607113afc8SEmmanuel Vadot static void
xgbe_phy_x_mode(struct xgbe_prv_data * pdata)23617113afc8SEmmanuel Vadot xgbe_phy_x_mode(struct xgbe_prv_data *pdata)
23627113afc8SEmmanuel Vadot {
23637113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
23647113afc8SEmmanuel Vadot 
23657113afc8SEmmanuel Vadot 	xgbe_phy_set_redrv_mode(pdata);
23667113afc8SEmmanuel Vadot 
23677113afc8SEmmanuel Vadot 	/* 1G/X */
23687113afc8SEmmanuel Vadot 	xgbe_phy_perform_ratechange(pdata, 1, 3);
23697113afc8SEmmanuel Vadot 
23707113afc8SEmmanuel Vadot 	phy_data->cur_mode = XGBE_MODE_X;
23717113afc8SEmmanuel Vadot 
23727113afc8SEmmanuel Vadot 	axgbe_printf(3, "1GbE X mode set\n");
23737113afc8SEmmanuel Vadot }
23747113afc8SEmmanuel Vadot 
23757113afc8SEmmanuel Vadot static void
xgbe_phy_sgmii_1000_mode(struct xgbe_prv_data * pdata)23767113afc8SEmmanuel Vadot xgbe_phy_sgmii_1000_mode(struct xgbe_prv_data *pdata)
23777113afc8SEmmanuel Vadot {
23787113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
23797113afc8SEmmanuel Vadot 
23807113afc8SEmmanuel Vadot 	xgbe_phy_set_redrv_mode(pdata);
23817113afc8SEmmanuel Vadot 
23827113afc8SEmmanuel Vadot 	/* 1G/SGMII */
23837113afc8SEmmanuel Vadot 	xgbe_phy_perform_ratechange(pdata, 1, 2);
23847113afc8SEmmanuel Vadot 
23857113afc8SEmmanuel Vadot 	phy_data->cur_mode = XGBE_MODE_SGMII_1000;
23867113afc8SEmmanuel Vadot 
23877113afc8SEmmanuel Vadot 	axgbe_printf(2, "1GbE SGMII mode set\n");
23887113afc8SEmmanuel Vadot }
23897113afc8SEmmanuel Vadot 
23907113afc8SEmmanuel Vadot static void
xgbe_phy_sgmii_100_mode(struct xgbe_prv_data * pdata)23917113afc8SEmmanuel Vadot xgbe_phy_sgmii_100_mode(struct xgbe_prv_data *pdata)
23927113afc8SEmmanuel Vadot {
23937113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
23947113afc8SEmmanuel Vadot 
23957113afc8SEmmanuel Vadot 	xgbe_phy_set_redrv_mode(pdata);
23967113afc8SEmmanuel Vadot 
23977113afc8SEmmanuel Vadot 	/* 100M/SGMII */
23987113afc8SEmmanuel Vadot 	xgbe_phy_perform_ratechange(pdata, 1, 1);
23997113afc8SEmmanuel Vadot 
24007113afc8SEmmanuel Vadot 	phy_data->cur_mode = XGBE_MODE_SGMII_100;
24017113afc8SEmmanuel Vadot 
24027113afc8SEmmanuel Vadot 	axgbe_printf(3, "100MbE SGMII mode set\n");
24037113afc8SEmmanuel Vadot }
24047113afc8SEmmanuel Vadot 
24057113afc8SEmmanuel Vadot static void
xgbe_phy_kr_mode(struct xgbe_prv_data * pdata)24067113afc8SEmmanuel Vadot xgbe_phy_kr_mode(struct xgbe_prv_data *pdata)
24077113afc8SEmmanuel Vadot {
24087113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
24097113afc8SEmmanuel Vadot 
24107113afc8SEmmanuel Vadot 	xgbe_phy_set_redrv_mode(pdata);
24117113afc8SEmmanuel Vadot 
24127113afc8SEmmanuel Vadot 	/* 10G/KR */
24137113afc8SEmmanuel Vadot 	xgbe_phy_perform_ratechange(pdata, 4, 0);
24147113afc8SEmmanuel Vadot 
24157113afc8SEmmanuel Vadot 	phy_data->cur_mode = XGBE_MODE_KR;
24167113afc8SEmmanuel Vadot 
24177113afc8SEmmanuel Vadot 	axgbe_printf(3, "10GbE KR mode set\n");
24187113afc8SEmmanuel Vadot }
24197113afc8SEmmanuel Vadot 
24207113afc8SEmmanuel Vadot static void
xgbe_phy_kx_2500_mode(struct xgbe_prv_data * pdata)24217113afc8SEmmanuel Vadot xgbe_phy_kx_2500_mode(struct xgbe_prv_data *pdata)
24227113afc8SEmmanuel Vadot {
24237113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
24247113afc8SEmmanuel Vadot 
24257113afc8SEmmanuel Vadot 	xgbe_phy_set_redrv_mode(pdata);
24267113afc8SEmmanuel Vadot 
24277113afc8SEmmanuel Vadot 	/* 2.5G/KX */
24287113afc8SEmmanuel Vadot 	xgbe_phy_perform_ratechange(pdata, 2, 0);
24297113afc8SEmmanuel Vadot 
24307113afc8SEmmanuel Vadot 	phy_data->cur_mode = XGBE_MODE_KX_2500;
24317113afc8SEmmanuel Vadot 
24327113afc8SEmmanuel Vadot 	axgbe_printf(3, "2.5GbE KX mode set\n");
24337113afc8SEmmanuel Vadot }
24347113afc8SEmmanuel Vadot 
24357113afc8SEmmanuel Vadot static void
xgbe_phy_kx_1000_mode(struct xgbe_prv_data * pdata)24367113afc8SEmmanuel Vadot xgbe_phy_kx_1000_mode(struct xgbe_prv_data *pdata)
24377113afc8SEmmanuel Vadot {
24387113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
24397113afc8SEmmanuel Vadot 
24407113afc8SEmmanuel Vadot 	xgbe_phy_set_redrv_mode(pdata);
24417113afc8SEmmanuel Vadot 
24427113afc8SEmmanuel Vadot 	/* 1G/KX */
24437113afc8SEmmanuel Vadot 	xgbe_phy_perform_ratechange(pdata, 1, 3);
24447113afc8SEmmanuel Vadot 
24457113afc8SEmmanuel Vadot 	phy_data->cur_mode = XGBE_MODE_KX_1000;
24467113afc8SEmmanuel Vadot 
24477113afc8SEmmanuel Vadot 	axgbe_printf(3, "1GbE KX mode set\n");
24487113afc8SEmmanuel Vadot }
24497113afc8SEmmanuel Vadot 
24507113afc8SEmmanuel Vadot static enum xgbe_mode
xgbe_phy_cur_mode(struct xgbe_prv_data * pdata)24517113afc8SEmmanuel Vadot xgbe_phy_cur_mode(struct xgbe_prv_data *pdata)
24527113afc8SEmmanuel Vadot {
24537113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
24547113afc8SEmmanuel Vadot 
24557113afc8SEmmanuel Vadot 	return (phy_data->cur_mode);
24567113afc8SEmmanuel Vadot }
24577113afc8SEmmanuel Vadot 
24587113afc8SEmmanuel Vadot static enum xgbe_mode
xgbe_phy_switch_baset_mode(struct xgbe_prv_data * pdata)24597113afc8SEmmanuel Vadot xgbe_phy_switch_baset_mode(struct xgbe_prv_data *pdata)
24607113afc8SEmmanuel Vadot {
24617113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
24627113afc8SEmmanuel Vadot 
24637113afc8SEmmanuel Vadot 	/* No switching if not 10GBase-T */
24647113afc8SEmmanuel Vadot 	if (phy_data->port_mode != XGBE_PORT_MODE_10GBASE_T)
24657113afc8SEmmanuel Vadot 		return (xgbe_phy_cur_mode(pdata));
24667113afc8SEmmanuel Vadot 
24677113afc8SEmmanuel Vadot 	switch (xgbe_phy_cur_mode(pdata)) {
24687113afc8SEmmanuel Vadot 	case XGBE_MODE_SGMII_100:
24697113afc8SEmmanuel Vadot 	case XGBE_MODE_SGMII_1000:
24707113afc8SEmmanuel Vadot 		return (XGBE_MODE_KR);
24717113afc8SEmmanuel Vadot 	case XGBE_MODE_KR:
24727113afc8SEmmanuel Vadot 	default:
24737113afc8SEmmanuel Vadot 		return (XGBE_MODE_SGMII_1000);
24747113afc8SEmmanuel Vadot 	}
24757113afc8SEmmanuel Vadot }
24767113afc8SEmmanuel Vadot 
24777113afc8SEmmanuel Vadot static enum xgbe_mode
xgbe_phy_switch_bp_2500_mode(struct xgbe_prv_data * pdata)24787113afc8SEmmanuel Vadot xgbe_phy_switch_bp_2500_mode(struct xgbe_prv_data *pdata)
24797113afc8SEmmanuel Vadot {
24807113afc8SEmmanuel Vadot 	return (XGBE_MODE_KX_2500);
24817113afc8SEmmanuel Vadot }
24827113afc8SEmmanuel Vadot 
24837113afc8SEmmanuel Vadot static enum xgbe_mode
xgbe_phy_switch_bp_mode(struct xgbe_prv_data * pdata)24847113afc8SEmmanuel Vadot xgbe_phy_switch_bp_mode(struct xgbe_prv_data *pdata)
24857113afc8SEmmanuel Vadot {
24867113afc8SEmmanuel Vadot 	/* If we are in KR switch to KX, and vice-versa */
24877113afc8SEmmanuel Vadot 	switch (xgbe_phy_cur_mode(pdata)) {
24887113afc8SEmmanuel Vadot 	case XGBE_MODE_KX_1000:
24897113afc8SEmmanuel Vadot 		return (XGBE_MODE_KR);
24907113afc8SEmmanuel Vadot 	case XGBE_MODE_KR:
24917113afc8SEmmanuel Vadot 	default:
24927113afc8SEmmanuel Vadot 		return (XGBE_MODE_KX_1000);
24937113afc8SEmmanuel Vadot 	}
24947113afc8SEmmanuel Vadot }
24957113afc8SEmmanuel Vadot 
24967113afc8SEmmanuel Vadot static enum xgbe_mode
xgbe_phy_switch_mode(struct xgbe_prv_data * pdata)24977113afc8SEmmanuel Vadot xgbe_phy_switch_mode(struct xgbe_prv_data *pdata)
24987113afc8SEmmanuel Vadot {
24997113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
25007113afc8SEmmanuel Vadot 
25017113afc8SEmmanuel Vadot 	switch (phy_data->port_mode) {
25027113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_BACKPLANE:
25037113afc8SEmmanuel Vadot 		return (xgbe_phy_switch_bp_mode(pdata));
25047113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_BACKPLANE_2500:
25057113afc8SEmmanuel Vadot 		return (xgbe_phy_switch_bp_2500_mode(pdata));
25067113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_1000BASE_T:
25077113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_NBASE_T:
25087113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_10GBASE_T:
25097113afc8SEmmanuel Vadot 		return (xgbe_phy_switch_baset_mode(pdata));
25107113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_1000BASE_X:
25117113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_10GBASE_R:
25127113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_SFP:
25137113afc8SEmmanuel Vadot 		/* No switching, so just return current mode */
25147113afc8SEmmanuel Vadot 		return (xgbe_phy_cur_mode(pdata));
25157113afc8SEmmanuel Vadot 	default:
25167113afc8SEmmanuel Vadot 		return (XGBE_MODE_UNKNOWN);
25177113afc8SEmmanuel Vadot 	}
25187113afc8SEmmanuel Vadot }
25197113afc8SEmmanuel Vadot 
25207113afc8SEmmanuel Vadot static enum xgbe_mode
xgbe_phy_get_basex_mode(struct xgbe_phy_data * phy_data,int speed)25217113afc8SEmmanuel Vadot xgbe_phy_get_basex_mode(struct xgbe_phy_data *phy_data, int speed)
25227113afc8SEmmanuel Vadot {
25237113afc8SEmmanuel Vadot 	switch (speed) {
25247113afc8SEmmanuel Vadot 	case SPEED_1000:
25257113afc8SEmmanuel Vadot 		return (XGBE_MODE_X);
25267113afc8SEmmanuel Vadot 	case SPEED_10000:
25277113afc8SEmmanuel Vadot 		return (XGBE_MODE_KR);
25287113afc8SEmmanuel Vadot 	default:
25297113afc8SEmmanuel Vadot 		return (XGBE_MODE_UNKNOWN);
25307113afc8SEmmanuel Vadot 	}
25317113afc8SEmmanuel Vadot }
25327113afc8SEmmanuel Vadot 
25337113afc8SEmmanuel Vadot static enum xgbe_mode
xgbe_phy_get_baset_mode(struct xgbe_phy_data * phy_data,int speed)25347113afc8SEmmanuel Vadot xgbe_phy_get_baset_mode(struct xgbe_phy_data *phy_data, int speed)
25357113afc8SEmmanuel Vadot {
25367113afc8SEmmanuel Vadot 	switch (speed) {
25377113afc8SEmmanuel Vadot 	case SPEED_100:
25387113afc8SEmmanuel Vadot 		return (XGBE_MODE_SGMII_100);
25397113afc8SEmmanuel Vadot 	case SPEED_1000:
25407113afc8SEmmanuel Vadot 		return (XGBE_MODE_SGMII_1000);
25417113afc8SEmmanuel Vadot 	case SPEED_2500:
25427113afc8SEmmanuel Vadot 		return (XGBE_MODE_KX_2500);
25437113afc8SEmmanuel Vadot 	case SPEED_10000:
25447113afc8SEmmanuel Vadot 		return (XGBE_MODE_KR);
25457113afc8SEmmanuel Vadot 	default:
25467113afc8SEmmanuel Vadot 		return (XGBE_MODE_UNKNOWN);
25477113afc8SEmmanuel Vadot 	}
25487113afc8SEmmanuel Vadot }
25497113afc8SEmmanuel Vadot 
25507113afc8SEmmanuel Vadot static enum xgbe_mode
xgbe_phy_get_sfp_mode(struct xgbe_phy_data * phy_data,int speed)25517113afc8SEmmanuel Vadot xgbe_phy_get_sfp_mode(struct xgbe_phy_data *phy_data, int speed)
25527113afc8SEmmanuel Vadot {
25537113afc8SEmmanuel Vadot 	switch (speed) {
25547113afc8SEmmanuel Vadot 	case SPEED_100:
25557113afc8SEmmanuel Vadot 		return (XGBE_MODE_SGMII_100);
25567113afc8SEmmanuel Vadot 	case SPEED_1000:
25577113afc8SEmmanuel Vadot 		if (phy_data->sfp_base == XGBE_SFP_BASE_1000_T)
25587113afc8SEmmanuel Vadot 			return (XGBE_MODE_SGMII_1000);
25597113afc8SEmmanuel Vadot 		else
25607113afc8SEmmanuel Vadot 			return (XGBE_MODE_X);
25617113afc8SEmmanuel Vadot 	case SPEED_10000:
25627113afc8SEmmanuel Vadot 	case SPEED_UNKNOWN:
25637113afc8SEmmanuel Vadot 		return (XGBE_MODE_SFI);
25647113afc8SEmmanuel Vadot 	default:
25657113afc8SEmmanuel Vadot 		return (XGBE_MODE_UNKNOWN);
25667113afc8SEmmanuel Vadot 	}
25677113afc8SEmmanuel Vadot }
25687113afc8SEmmanuel Vadot 
25697113afc8SEmmanuel Vadot static enum xgbe_mode
xgbe_phy_get_bp_2500_mode(int speed)25707113afc8SEmmanuel Vadot xgbe_phy_get_bp_2500_mode(int speed)
25717113afc8SEmmanuel Vadot {
25727113afc8SEmmanuel Vadot 	switch (speed) {
25737113afc8SEmmanuel Vadot 	case SPEED_2500:
25747113afc8SEmmanuel Vadot 		return (XGBE_MODE_KX_2500);
25757113afc8SEmmanuel Vadot 	default:
25767113afc8SEmmanuel Vadot 		return (XGBE_MODE_UNKNOWN);
25777113afc8SEmmanuel Vadot 	}
25787113afc8SEmmanuel Vadot }
25797113afc8SEmmanuel Vadot 
25807113afc8SEmmanuel Vadot static enum xgbe_mode
xgbe_phy_get_bp_mode(int speed)25817113afc8SEmmanuel Vadot xgbe_phy_get_bp_mode(int speed)
25827113afc8SEmmanuel Vadot {
25837113afc8SEmmanuel Vadot 	switch (speed) {
25847113afc8SEmmanuel Vadot 	case SPEED_1000:
25857113afc8SEmmanuel Vadot 		return (XGBE_MODE_KX_1000);
25867113afc8SEmmanuel Vadot 	case SPEED_10000:
25877113afc8SEmmanuel Vadot 		return (XGBE_MODE_KR);
25887113afc8SEmmanuel Vadot 	default:
25897113afc8SEmmanuel Vadot 		return (XGBE_MODE_UNKNOWN);
25907113afc8SEmmanuel Vadot 	}
25917113afc8SEmmanuel Vadot }
25927113afc8SEmmanuel Vadot 
25937113afc8SEmmanuel Vadot static enum xgbe_mode
xgbe_phy_get_mode(struct xgbe_prv_data * pdata,int speed)25947113afc8SEmmanuel Vadot xgbe_phy_get_mode(struct xgbe_prv_data *pdata, int speed)
25957113afc8SEmmanuel Vadot {
25967113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
25977113afc8SEmmanuel Vadot 
25987113afc8SEmmanuel Vadot 	switch (phy_data->port_mode) {
25997113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_BACKPLANE:
26007113afc8SEmmanuel Vadot 		return (xgbe_phy_get_bp_mode(speed));
26017113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_BACKPLANE_2500:
26027113afc8SEmmanuel Vadot 		return (xgbe_phy_get_bp_2500_mode(speed));
26037113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_1000BASE_T:
26047113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_NBASE_T:
26057113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_10GBASE_T:
26067113afc8SEmmanuel Vadot 		return (xgbe_phy_get_baset_mode(phy_data, speed));
26077113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_1000BASE_X:
26087113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_10GBASE_R:
26097113afc8SEmmanuel Vadot 		return (xgbe_phy_get_basex_mode(phy_data, speed));
26107113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_SFP:
26117113afc8SEmmanuel Vadot 		return (xgbe_phy_get_sfp_mode(phy_data, speed));
26127113afc8SEmmanuel Vadot 	default:
26137113afc8SEmmanuel Vadot 		return (XGBE_MODE_UNKNOWN);
26147113afc8SEmmanuel Vadot 	}
26157113afc8SEmmanuel Vadot }
26167113afc8SEmmanuel Vadot 
26177113afc8SEmmanuel Vadot static void
xgbe_phy_set_mode(struct xgbe_prv_data * pdata,enum xgbe_mode mode)26187113afc8SEmmanuel Vadot xgbe_phy_set_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode)
26197113afc8SEmmanuel Vadot {
26207113afc8SEmmanuel Vadot 	switch (mode) {
26217113afc8SEmmanuel Vadot 	case XGBE_MODE_KX_1000:
26227113afc8SEmmanuel Vadot 		xgbe_phy_kx_1000_mode(pdata);
26237113afc8SEmmanuel Vadot 		break;
26247113afc8SEmmanuel Vadot 	case XGBE_MODE_KX_2500:
26257113afc8SEmmanuel Vadot 		xgbe_phy_kx_2500_mode(pdata);
26267113afc8SEmmanuel Vadot 		break;
26277113afc8SEmmanuel Vadot 	case XGBE_MODE_KR:
26287113afc8SEmmanuel Vadot 		xgbe_phy_kr_mode(pdata);
26297113afc8SEmmanuel Vadot 		break;
26307113afc8SEmmanuel Vadot 	case XGBE_MODE_SGMII_100:
26317113afc8SEmmanuel Vadot 		xgbe_phy_sgmii_100_mode(pdata);
26327113afc8SEmmanuel Vadot 		break;
26337113afc8SEmmanuel Vadot 	case XGBE_MODE_SGMII_1000:
26347113afc8SEmmanuel Vadot 		xgbe_phy_sgmii_1000_mode(pdata);
26357113afc8SEmmanuel Vadot 		break;
26367113afc8SEmmanuel Vadot 	case XGBE_MODE_X:
26377113afc8SEmmanuel Vadot 		xgbe_phy_x_mode(pdata);
26387113afc8SEmmanuel Vadot 		break;
26397113afc8SEmmanuel Vadot 	case XGBE_MODE_SFI:
26407113afc8SEmmanuel Vadot 		xgbe_phy_sfi_mode(pdata);
26417113afc8SEmmanuel Vadot 		break;
26427113afc8SEmmanuel Vadot 	default:
26437113afc8SEmmanuel Vadot 		break;
26447113afc8SEmmanuel Vadot 	}
26457113afc8SEmmanuel Vadot }
26467113afc8SEmmanuel Vadot 
26477113afc8SEmmanuel Vadot static void
xgbe_phy_get_type(struct xgbe_prv_data * pdata,struct ifmediareq * ifmr)26487113afc8SEmmanuel Vadot xgbe_phy_get_type(struct xgbe_prv_data *pdata, struct ifmediareq * ifmr)
26497113afc8SEmmanuel Vadot {
26507113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
26517113afc8SEmmanuel Vadot 
26527113afc8SEmmanuel Vadot 	switch (pdata->phy.speed) {
26537113afc8SEmmanuel Vadot 	case SPEED_10000:
26547113afc8SEmmanuel Vadot 		if (phy_data->port_mode == XGBE_PORT_MODE_BACKPLANE)
26557113afc8SEmmanuel Vadot 			ifmr->ifm_active |= IFM_10G_KR;
26567113afc8SEmmanuel Vadot 		else if(phy_data->port_mode == XGBE_PORT_MODE_10GBASE_T)
26577113afc8SEmmanuel Vadot 			ifmr->ifm_active |= IFM_10G_T;
26587113afc8SEmmanuel Vadot 		else if(phy_data->port_mode == XGBE_PORT_MODE_10GBASE_R)
26597113afc8SEmmanuel Vadot 			ifmr->ifm_active |= IFM_10G_KR;
26607113afc8SEmmanuel Vadot 		else if(phy_data->port_mode == XGBE_PORT_MODE_SFP)
26617113afc8SEmmanuel Vadot 			ifmr->ifm_active |= IFM_10G_SFI;
26627113afc8SEmmanuel Vadot 		else
26637113afc8SEmmanuel Vadot 			ifmr->ifm_active |= IFM_OTHER;
26647113afc8SEmmanuel Vadot 		break;
26657113afc8SEmmanuel Vadot 	case SPEED_2500:
26667113afc8SEmmanuel Vadot 		if (phy_data->port_mode == XGBE_PORT_MODE_BACKPLANE_2500)
26677113afc8SEmmanuel Vadot 			ifmr->ifm_active |= IFM_2500_KX;
26687113afc8SEmmanuel Vadot 		else
26697113afc8SEmmanuel Vadot 			ifmr->ifm_active |= IFM_OTHER;
26707113afc8SEmmanuel Vadot 		break;
26717113afc8SEmmanuel Vadot 	case SPEED_1000:
26727113afc8SEmmanuel Vadot 		if (phy_data->port_mode == XGBE_PORT_MODE_BACKPLANE)
26737113afc8SEmmanuel Vadot 			ifmr->ifm_active |= IFM_1000_KX;
26747113afc8SEmmanuel Vadot 		else if(phy_data->port_mode == XGBE_PORT_MODE_1000BASE_T)
26757113afc8SEmmanuel Vadot 			ifmr->ifm_active |= IFM_1000_T;
26767113afc8SEmmanuel Vadot #if 0
26777113afc8SEmmanuel Vadot 		else if(phy_data->port_mode == XGBE_PORT_MODE_1000BASE_X)
26787113afc8SEmmanuel Vadot 		      ifmr->ifm_active |= IFM_1000_SX;
26797113afc8SEmmanuel Vadot 		      ifmr->ifm_active |= IFM_1000_LX;
26807113afc8SEmmanuel Vadot 		      ifmr->ifm_active |= IFM_1000_CX;
26817113afc8SEmmanuel Vadot #endif
26827113afc8SEmmanuel Vadot 		else if(phy_data->port_mode == XGBE_PORT_MODE_SFP)
26837113afc8SEmmanuel Vadot 			ifmr->ifm_active |= IFM_1000_SGMII;
26847113afc8SEmmanuel Vadot 		else
26857113afc8SEmmanuel Vadot 			ifmr->ifm_active |= IFM_OTHER;
26867113afc8SEmmanuel Vadot 		break;
26877113afc8SEmmanuel Vadot 	case SPEED_100:
26887113afc8SEmmanuel Vadot 		if(phy_data->port_mode == XGBE_PORT_MODE_NBASE_T)
26897113afc8SEmmanuel Vadot 			ifmr->ifm_active |= IFM_100_T;
26907113afc8SEmmanuel Vadot 		else if(phy_data->port_mode == XGBE_PORT_MODE_SFP)
2691445bed5cSStephan de Wit 			ifmr->ifm_active |= IFM_100_SGMII;
26927113afc8SEmmanuel Vadot 		else
26937113afc8SEmmanuel Vadot 			ifmr->ifm_active |= IFM_OTHER;
26947113afc8SEmmanuel Vadot 		break;
26957113afc8SEmmanuel Vadot 	default:
26967113afc8SEmmanuel Vadot 		ifmr->ifm_active |= IFM_OTHER;
26977113afc8SEmmanuel Vadot 		axgbe_printf(1, "Unknown mode detected\n");
26987113afc8SEmmanuel Vadot 		break;
26997113afc8SEmmanuel Vadot 	}
27007113afc8SEmmanuel Vadot }
27017113afc8SEmmanuel Vadot 
27027113afc8SEmmanuel Vadot static bool
xgbe_phy_check_mode(struct xgbe_prv_data * pdata,enum xgbe_mode mode,bool advert)27037113afc8SEmmanuel Vadot xgbe_phy_check_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode,
27047113afc8SEmmanuel Vadot     bool advert)
27057113afc8SEmmanuel Vadot {
27067113afc8SEmmanuel Vadot 
27077113afc8SEmmanuel Vadot 	if (pdata->phy.autoneg == AUTONEG_ENABLE)
27087113afc8SEmmanuel Vadot 		return (advert);
27097113afc8SEmmanuel Vadot 	else {
27107113afc8SEmmanuel Vadot 		enum xgbe_mode cur_mode;
27117113afc8SEmmanuel Vadot 
27127113afc8SEmmanuel Vadot 		cur_mode = xgbe_phy_get_mode(pdata, pdata->phy.speed);
27137113afc8SEmmanuel Vadot 		if (cur_mode == mode)
27147113afc8SEmmanuel Vadot 			return (true);
27157113afc8SEmmanuel Vadot 	}
27167113afc8SEmmanuel Vadot 
27177113afc8SEmmanuel Vadot 	return (false);
27187113afc8SEmmanuel Vadot }
27197113afc8SEmmanuel Vadot 
27207113afc8SEmmanuel Vadot static bool
xgbe_phy_use_basex_mode(struct xgbe_prv_data * pdata,enum xgbe_mode mode)27217113afc8SEmmanuel Vadot xgbe_phy_use_basex_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode)
27227113afc8SEmmanuel Vadot {
27237113afc8SEmmanuel Vadot 
27247113afc8SEmmanuel Vadot 	switch (mode) {
27257113afc8SEmmanuel Vadot 	case XGBE_MODE_X:
27267113afc8SEmmanuel Vadot 		return (xgbe_phy_check_mode(pdata, mode, XGBE_ADV(&pdata->phy,
27277113afc8SEmmanuel Vadot 		    1000baseX_Full)));
27287113afc8SEmmanuel Vadot 	case XGBE_MODE_KR:
27297113afc8SEmmanuel Vadot 		return (xgbe_phy_check_mode(pdata, mode, XGBE_ADV(&pdata->phy,
27307113afc8SEmmanuel Vadot 		    10000baseKR_Full)));
27317113afc8SEmmanuel Vadot 	default:
27327113afc8SEmmanuel Vadot 		return (false);
27337113afc8SEmmanuel Vadot 	}
27347113afc8SEmmanuel Vadot }
27357113afc8SEmmanuel Vadot 
27367113afc8SEmmanuel Vadot static bool
xgbe_phy_use_baset_mode(struct xgbe_prv_data * pdata,enum xgbe_mode mode)27377113afc8SEmmanuel Vadot xgbe_phy_use_baset_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode)
27387113afc8SEmmanuel Vadot {
27397113afc8SEmmanuel Vadot 
27407113afc8SEmmanuel Vadot 	axgbe_printf(3, "%s: check mode %d\n", __func__, mode);
27417113afc8SEmmanuel Vadot 	switch (mode) {
27427113afc8SEmmanuel Vadot 	case XGBE_MODE_SGMII_100:
27437113afc8SEmmanuel Vadot 		return (xgbe_phy_check_mode(pdata, mode, XGBE_ADV(&pdata->phy,
27447113afc8SEmmanuel Vadot 		    100baseT_Full)));
27457113afc8SEmmanuel Vadot 	case XGBE_MODE_SGMII_1000:
27467113afc8SEmmanuel Vadot 		return (xgbe_phy_check_mode(pdata, mode, XGBE_ADV(&pdata->phy,
27477113afc8SEmmanuel Vadot 		    1000baseT_Full)));
27487113afc8SEmmanuel Vadot 	case XGBE_MODE_KX_2500:
27497113afc8SEmmanuel Vadot 		return (xgbe_phy_check_mode(pdata, mode, XGBE_ADV(&pdata->phy,
27507113afc8SEmmanuel Vadot 		    2500baseT_Full)));
27517113afc8SEmmanuel Vadot 	case XGBE_MODE_KR:
27527113afc8SEmmanuel Vadot 		return (xgbe_phy_check_mode(pdata, mode, XGBE_ADV(&pdata->phy,
27537113afc8SEmmanuel Vadot 		    10000baseT_Full)));
27547113afc8SEmmanuel Vadot 	default:
27557113afc8SEmmanuel Vadot 		return (false);
27567113afc8SEmmanuel Vadot 	}
27577113afc8SEmmanuel Vadot }
27587113afc8SEmmanuel Vadot 
27597113afc8SEmmanuel Vadot static bool
xgbe_phy_use_sfp_mode(struct xgbe_prv_data * pdata,enum xgbe_mode mode)27607113afc8SEmmanuel Vadot xgbe_phy_use_sfp_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode)
27617113afc8SEmmanuel Vadot {
27627113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
27637113afc8SEmmanuel Vadot 
27647113afc8SEmmanuel Vadot 	switch (mode) {
27657113afc8SEmmanuel Vadot 	case XGBE_MODE_X:
27667113afc8SEmmanuel Vadot 		if (phy_data->sfp_base == XGBE_SFP_BASE_1000_T)
27677113afc8SEmmanuel Vadot 			return (false);
27687113afc8SEmmanuel Vadot 		return (xgbe_phy_check_mode(pdata, mode,
27697113afc8SEmmanuel Vadot 		    XGBE_ADV(&pdata->phy, 1000baseX_Full)));
27707113afc8SEmmanuel Vadot 	case XGBE_MODE_SGMII_100:
27717113afc8SEmmanuel Vadot 		if (phy_data->sfp_base != XGBE_SFP_BASE_1000_T)
27727113afc8SEmmanuel Vadot 			return (false);
27737113afc8SEmmanuel Vadot 		return (xgbe_phy_check_mode(pdata, mode,
27747113afc8SEmmanuel Vadot 		    XGBE_ADV(&pdata->phy, 100baseT_Full)));
27757113afc8SEmmanuel Vadot 	case XGBE_MODE_SGMII_1000:
27767113afc8SEmmanuel Vadot 		if (phy_data->sfp_base != XGBE_SFP_BASE_1000_T)
27777113afc8SEmmanuel Vadot 			return (false);
27787113afc8SEmmanuel Vadot 		return (xgbe_phy_check_mode(pdata, mode,
27797113afc8SEmmanuel Vadot 		    XGBE_ADV(&pdata->phy, 1000baseT_Full)));
27807113afc8SEmmanuel Vadot 	case XGBE_MODE_SFI:
27817113afc8SEmmanuel Vadot 		if (phy_data->sfp_mod_absent)
27827113afc8SEmmanuel Vadot 			return (true);
27837113afc8SEmmanuel Vadot 		return (xgbe_phy_check_mode(pdata, mode,
27847113afc8SEmmanuel Vadot 		    XGBE_ADV(&pdata->phy, 10000baseSR_Full)  ||
27857113afc8SEmmanuel Vadot 		    XGBE_ADV(&pdata->phy, 10000baseLR_Full)  ||
27867113afc8SEmmanuel Vadot 		    XGBE_ADV(&pdata->phy, 10000baseLRM_Full) ||
27877113afc8SEmmanuel Vadot 		    XGBE_ADV(&pdata->phy, 10000baseER_Full)  ||
27887113afc8SEmmanuel Vadot 		    XGBE_ADV(&pdata->phy, 10000baseCR_Full)));
27897113afc8SEmmanuel Vadot 	default:
27907113afc8SEmmanuel Vadot 		return (false);
27917113afc8SEmmanuel Vadot 	}
27927113afc8SEmmanuel Vadot }
27937113afc8SEmmanuel Vadot 
27947113afc8SEmmanuel Vadot static bool
xgbe_phy_use_bp_2500_mode(struct xgbe_prv_data * pdata,enum xgbe_mode mode)27957113afc8SEmmanuel Vadot xgbe_phy_use_bp_2500_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode)
27967113afc8SEmmanuel Vadot {
27977113afc8SEmmanuel Vadot 
27987113afc8SEmmanuel Vadot 	switch (mode) {
27997113afc8SEmmanuel Vadot 	case XGBE_MODE_KX_2500:
28007113afc8SEmmanuel Vadot 		return (xgbe_phy_check_mode(pdata, mode,
28017113afc8SEmmanuel Vadot 		    XGBE_ADV(&pdata->phy, 2500baseX_Full)));
28027113afc8SEmmanuel Vadot 	default:
28037113afc8SEmmanuel Vadot 		return (false);
28047113afc8SEmmanuel Vadot 	}
28057113afc8SEmmanuel Vadot }
28067113afc8SEmmanuel Vadot 
28077113afc8SEmmanuel Vadot static bool
xgbe_phy_use_bp_mode(struct xgbe_prv_data * pdata,enum xgbe_mode mode)28087113afc8SEmmanuel Vadot xgbe_phy_use_bp_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode)
28097113afc8SEmmanuel Vadot {
28107113afc8SEmmanuel Vadot 
28117113afc8SEmmanuel Vadot 	switch (mode) {
28127113afc8SEmmanuel Vadot 	case XGBE_MODE_KX_1000:
28137113afc8SEmmanuel Vadot 		return (xgbe_phy_check_mode(pdata, mode,
28147113afc8SEmmanuel Vadot 		    XGBE_ADV(&pdata->phy, 1000baseKX_Full)));
28157113afc8SEmmanuel Vadot 	case XGBE_MODE_KR:
28167113afc8SEmmanuel Vadot 		return (xgbe_phy_check_mode(pdata, mode,
28177113afc8SEmmanuel Vadot 		    XGBE_ADV(&pdata->phy, 10000baseKR_Full)));
28187113afc8SEmmanuel Vadot 	default:
28197113afc8SEmmanuel Vadot 		return (false);
28207113afc8SEmmanuel Vadot 	}
28217113afc8SEmmanuel Vadot }
28227113afc8SEmmanuel Vadot 
28237113afc8SEmmanuel Vadot static bool
xgbe_phy_use_mode(struct xgbe_prv_data * pdata,enum xgbe_mode mode)28247113afc8SEmmanuel Vadot xgbe_phy_use_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode)
28257113afc8SEmmanuel Vadot {
28267113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
28277113afc8SEmmanuel Vadot 
28287113afc8SEmmanuel Vadot 	switch (phy_data->port_mode) {
28297113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_BACKPLANE:
28307113afc8SEmmanuel Vadot 		return (xgbe_phy_use_bp_mode(pdata, mode));
28317113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_BACKPLANE_2500:
28327113afc8SEmmanuel Vadot 		return (xgbe_phy_use_bp_2500_mode(pdata, mode));
28337113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_1000BASE_T:
28347113afc8SEmmanuel Vadot 		axgbe_printf(3, "use_mode %s\n",
28357113afc8SEmmanuel Vadot 		    xgbe_phy_use_baset_mode(pdata, mode) ? "found" : "Not found");
28367113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_NBASE_T:
28377113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_10GBASE_T:
28387113afc8SEmmanuel Vadot 		return (xgbe_phy_use_baset_mode(pdata, mode));
28397113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_1000BASE_X:
28407113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_10GBASE_R:
28417113afc8SEmmanuel Vadot 		return (xgbe_phy_use_basex_mode(pdata, mode));
28427113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_SFP:
28437113afc8SEmmanuel Vadot 		return (xgbe_phy_use_sfp_mode(pdata, mode));
28447113afc8SEmmanuel Vadot 	default:
28457113afc8SEmmanuel Vadot 		return (false);
28467113afc8SEmmanuel Vadot 	}
28477113afc8SEmmanuel Vadot }
28487113afc8SEmmanuel Vadot 
28497113afc8SEmmanuel Vadot static bool
xgbe_phy_valid_speed_basex_mode(struct xgbe_phy_data * phy_data,int speed)28507113afc8SEmmanuel Vadot xgbe_phy_valid_speed_basex_mode(struct xgbe_phy_data *phy_data, int speed)
28517113afc8SEmmanuel Vadot {
28527113afc8SEmmanuel Vadot 
28537113afc8SEmmanuel Vadot 	switch (speed) {
28547113afc8SEmmanuel Vadot 	case SPEED_1000:
28557113afc8SEmmanuel Vadot 		return (phy_data->port_mode == XGBE_PORT_MODE_1000BASE_X);
28567113afc8SEmmanuel Vadot 	case SPEED_10000:
28577113afc8SEmmanuel Vadot 		return (phy_data->port_mode == XGBE_PORT_MODE_10GBASE_R);
28587113afc8SEmmanuel Vadot 	default:
28597113afc8SEmmanuel Vadot 		return (false);
28607113afc8SEmmanuel Vadot 	}
28617113afc8SEmmanuel Vadot }
28627113afc8SEmmanuel Vadot 
28637113afc8SEmmanuel Vadot static bool
xgbe_phy_valid_speed_baset_mode(struct xgbe_phy_data * phy_data,int speed)28647113afc8SEmmanuel Vadot xgbe_phy_valid_speed_baset_mode(struct xgbe_phy_data *phy_data, int speed)
28657113afc8SEmmanuel Vadot {
28667113afc8SEmmanuel Vadot 
28677113afc8SEmmanuel Vadot 	switch (speed) {
28687113afc8SEmmanuel Vadot 	case SPEED_100:
28697113afc8SEmmanuel Vadot 	case SPEED_1000:
28707113afc8SEmmanuel Vadot 		return (true);
28717113afc8SEmmanuel Vadot 	case SPEED_2500:
28727113afc8SEmmanuel Vadot 		return (phy_data->port_mode == XGBE_PORT_MODE_NBASE_T);
28737113afc8SEmmanuel Vadot 	case SPEED_10000:
28747113afc8SEmmanuel Vadot 		return (phy_data->port_mode == XGBE_PORT_MODE_10GBASE_T);
28757113afc8SEmmanuel Vadot 	default:
28767113afc8SEmmanuel Vadot 		return (false);
28777113afc8SEmmanuel Vadot 	}
28787113afc8SEmmanuel Vadot }
28797113afc8SEmmanuel Vadot 
28807113afc8SEmmanuel Vadot static bool
xgbe_phy_valid_speed_sfp_mode(struct xgbe_phy_data * phy_data,int speed)28817113afc8SEmmanuel Vadot xgbe_phy_valid_speed_sfp_mode(struct xgbe_phy_data *phy_data, int speed)
28827113afc8SEmmanuel Vadot {
28837113afc8SEmmanuel Vadot 
28847113afc8SEmmanuel Vadot 	switch (speed) {
28857113afc8SEmmanuel Vadot 	case SPEED_100:
2886445bed5cSStephan de Wit 		return ((phy_data->sfp_speed == XGBE_SFP_SPEED_100) ||
2887445bed5cSStephan de Wit 			(phy_data->sfp_speed == XGBE_SFP_SPEED_100_1000));
28887113afc8SEmmanuel Vadot 	case SPEED_1000:
28897113afc8SEmmanuel Vadot 		return ((phy_data->sfp_speed == XGBE_SFP_SPEED_100_1000) ||
28907113afc8SEmmanuel Vadot 		    (phy_data->sfp_speed == XGBE_SFP_SPEED_1000));
28917113afc8SEmmanuel Vadot 	case SPEED_10000:
28927113afc8SEmmanuel Vadot 		return (phy_data->sfp_speed == XGBE_SFP_SPEED_10000);
28937113afc8SEmmanuel Vadot 	default:
28947113afc8SEmmanuel Vadot 		return (false);
28957113afc8SEmmanuel Vadot 	}
28967113afc8SEmmanuel Vadot }
28977113afc8SEmmanuel Vadot 
28987113afc8SEmmanuel Vadot static bool
xgbe_phy_valid_speed_bp_2500_mode(int speed)28997113afc8SEmmanuel Vadot xgbe_phy_valid_speed_bp_2500_mode(int speed)
29007113afc8SEmmanuel Vadot {
29017113afc8SEmmanuel Vadot 
29027113afc8SEmmanuel Vadot 	switch (speed) {
29037113afc8SEmmanuel Vadot 	case SPEED_2500:
29047113afc8SEmmanuel Vadot 		return (true);
29057113afc8SEmmanuel Vadot 	default:
29067113afc8SEmmanuel Vadot 		return (false);
29077113afc8SEmmanuel Vadot 	}
29087113afc8SEmmanuel Vadot }
29097113afc8SEmmanuel Vadot 
29107113afc8SEmmanuel Vadot static bool
xgbe_phy_valid_speed_bp_mode(int speed)29117113afc8SEmmanuel Vadot xgbe_phy_valid_speed_bp_mode(int speed)
29127113afc8SEmmanuel Vadot {
29137113afc8SEmmanuel Vadot 
29147113afc8SEmmanuel Vadot 	switch (speed) {
29157113afc8SEmmanuel Vadot 	case SPEED_1000:
29167113afc8SEmmanuel Vadot 	case SPEED_10000:
29177113afc8SEmmanuel Vadot 		return (true);
29187113afc8SEmmanuel Vadot 	default:
29197113afc8SEmmanuel Vadot 		return (false);
29207113afc8SEmmanuel Vadot 	}
29217113afc8SEmmanuel Vadot }
29227113afc8SEmmanuel Vadot 
29237113afc8SEmmanuel Vadot static bool
xgbe_phy_valid_speed(struct xgbe_prv_data * pdata,int speed)29247113afc8SEmmanuel Vadot xgbe_phy_valid_speed(struct xgbe_prv_data *pdata, int speed)
29257113afc8SEmmanuel Vadot {
29267113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
29277113afc8SEmmanuel Vadot 
29287113afc8SEmmanuel Vadot 	switch (phy_data->port_mode) {
29297113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_BACKPLANE:
29307113afc8SEmmanuel Vadot 		return (xgbe_phy_valid_speed_bp_mode(speed));
29317113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_BACKPLANE_2500:
29327113afc8SEmmanuel Vadot 		return (xgbe_phy_valid_speed_bp_2500_mode(speed));
29337113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_1000BASE_T:
29347113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_NBASE_T:
29357113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_10GBASE_T:
29367113afc8SEmmanuel Vadot 		return (xgbe_phy_valid_speed_baset_mode(phy_data, speed));
29377113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_1000BASE_X:
29387113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_10GBASE_R:
29397113afc8SEmmanuel Vadot 		return (xgbe_phy_valid_speed_basex_mode(phy_data, speed));
29407113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_SFP:
29417113afc8SEmmanuel Vadot 		return (xgbe_phy_valid_speed_sfp_mode(phy_data, speed));
29427113afc8SEmmanuel Vadot 	default:
29437113afc8SEmmanuel Vadot 		return (false);
29447113afc8SEmmanuel Vadot 	}
29457113afc8SEmmanuel Vadot }
29467113afc8SEmmanuel Vadot 
29477113afc8SEmmanuel Vadot static int
xgbe_upd_link(struct xgbe_prv_data * pdata)29487113afc8SEmmanuel Vadot xgbe_upd_link(struct xgbe_prv_data *pdata)
29497113afc8SEmmanuel Vadot {
29507113afc8SEmmanuel Vadot 	int reg;
29517113afc8SEmmanuel Vadot 
29527113afc8SEmmanuel Vadot 	axgbe_printf(2, "%s: Link %d\n", __func__, pdata->phy.link);
29537113afc8SEmmanuel Vadot 	reg = xgbe_phy_mii_read(pdata, pdata->mdio_addr, MII_BMSR);
2954445bed5cSStephan de Wit 	reg = xgbe_phy_mii_read(pdata, pdata->mdio_addr, MII_BMSR);
29557113afc8SEmmanuel Vadot 	if (reg < 0)
29567113afc8SEmmanuel Vadot 		return (reg);
29577113afc8SEmmanuel Vadot 
29587113afc8SEmmanuel Vadot 	if ((reg & BMSR_LINK) == 0)
29597113afc8SEmmanuel Vadot 		pdata->phy.link = 0;
29607113afc8SEmmanuel Vadot 	else
29617113afc8SEmmanuel Vadot 		pdata->phy.link = 1;
29627113afc8SEmmanuel Vadot 
29637113afc8SEmmanuel Vadot 	axgbe_printf(2, "Link: %d updated reg %#x\n", pdata->phy.link, reg);
29647113afc8SEmmanuel Vadot 	return (0);
29657113afc8SEmmanuel Vadot }
29667113afc8SEmmanuel Vadot 
29677113afc8SEmmanuel Vadot static int
xgbe_phy_read_status(struct xgbe_prv_data * pdata)29687113afc8SEmmanuel Vadot xgbe_phy_read_status(struct xgbe_prv_data *pdata)
29697113afc8SEmmanuel Vadot {
297094e3e7d2SAdrian Chadd 	int common_adv_gb = 0;
29717113afc8SEmmanuel Vadot 	int common_adv;
29727113afc8SEmmanuel Vadot 	int lpagb = 0;
29737113afc8SEmmanuel Vadot 	int adv, lpa;
29747113afc8SEmmanuel Vadot 	int ret;
29757113afc8SEmmanuel Vadot 
29767113afc8SEmmanuel Vadot 	ret = xgbe_upd_link(pdata);
29777113afc8SEmmanuel Vadot 	if (ret) {
29787113afc8SEmmanuel Vadot 		axgbe_printf(2, "Link Update return %d\n", ret);
29797113afc8SEmmanuel Vadot 		return (ret);
29807113afc8SEmmanuel Vadot 	}
29817113afc8SEmmanuel Vadot 
29827113afc8SEmmanuel Vadot 	if (AUTONEG_ENABLE == pdata->phy.autoneg) {
29837113afc8SEmmanuel Vadot 		if (pdata->phy.supported == SUPPORTED_1000baseT_Half ||
29847113afc8SEmmanuel Vadot 		    pdata->phy.supported == SUPPORTED_1000baseT_Full) {
29857113afc8SEmmanuel Vadot 			lpagb = xgbe_phy_mii_read(pdata, pdata->mdio_addr,
29867113afc8SEmmanuel Vadot 			    MII_100T2SR);
29877113afc8SEmmanuel Vadot 			if (lpagb < 0)
29887113afc8SEmmanuel Vadot 				return (lpagb);
29897113afc8SEmmanuel Vadot 
29907113afc8SEmmanuel Vadot 			adv = xgbe_phy_mii_read(pdata, pdata->mdio_addr,
29917113afc8SEmmanuel Vadot 			    MII_100T2CR);
29927113afc8SEmmanuel Vadot 			if (adv < 0)
29937113afc8SEmmanuel Vadot 				return (adv);
29947113afc8SEmmanuel Vadot 
29957113afc8SEmmanuel Vadot 			if (lpagb & GTSR_MAN_MS_FLT) {
29967113afc8SEmmanuel Vadot 				if (adv & GTCR_MAN_MS)
29977113afc8SEmmanuel Vadot 					axgbe_printf(2, "Master/Slave Resolution "
29987113afc8SEmmanuel Vadot 					    "failed, maybe conflicting manual settings\n");
29997113afc8SEmmanuel Vadot 				else
30007113afc8SEmmanuel Vadot 					axgbe_printf(2, "Master/Slave Resolution failed\n");
30017113afc8SEmmanuel Vadot 				return (-ENOLINK);
30027113afc8SEmmanuel Vadot 			}
30037113afc8SEmmanuel Vadot 
30047113afc8SEmmanuel Vadot 			if (pdata->phy.supported == SUPPORTED_1000baseT_Half)
300594e3e7d2SAdrian Chadd 				XGBE_SET_ADV(&pdata->phy, 1000baseT_Half);
30067113afc8SEmmanuel Vadot 			else if (pdata->phy.supported == SUPPORTED_1000baseT_Full)
300794e3e7d2SAdrian Chadd 				XGBE_SET_ADV(&pdata->phy, 1000baseT_Full);
30087113afc8SEmmanuel Vadot 
30097113afc8SEmmanuel Vadot 			common_adv_gb = lpagb & adv << 2;
30107113afc8SEmmanuel Vadot 		}
30117113afc8SEmmanuel Vadot 
30127113afc8SEmmanuel Vadot 		lpa = xgbe_phy_mii_read(pdata, pdata->mdio_addr, MII_ANLPAR);
30137113afc8SEmmanuel Vadot 		if (lpa < 0)
30147113afc8SEmmanuel Vadot 			return (lpa);
30157113afc8SEmmanuel Vadot 
30167113afc8SEmmanuel Vadot 		if (pdata->phy.supported == SUPPORTED_Autoneg)
301794e3e7d2SAdrian Chadd 			XGBE_SET_ADV(&pdata->phy, Autoneg);
30187113afc8SEmmanuel Vadot 
30197113afc8SEmmanuel Vadot 		adv = xgbe_phy_mii_read(pdata, pdata->mdio_addr, MII_ANAR);
30207113afc8SEmmanuel Vadot 		if (adv < 0)
30217113afc8SEmmanuel Vadot 			return (adv);
30227113afc8SEmmanuel Vadot 
30237113afc8SEmmanuel Vadot 		common_adv = lpa & adv;
30247113afc8SEmmanuel Vadot 
30257113afc8SEmmanuel Vadot 		pdata->phy.speed = SPEED_10;
30267113afc8SEmmanuel Vadot 		pdata->phy.duplex = DUPLEX_HALF;
30277113afc8SEmmanuel Vadot 		pdata->phy.pause = 0;
30287113afc8SEmmanuel Vadot 		pdata->phy.asym_pause = 0;
30297113afc8SEmmanuel Vadot 
30307113afc8SEmmanuel Vadot 		axgbe_printf(2, "%s: lpa %#x adv %#x common_adv_gb %#x "
30317113afc8SEmmanuel Vadot 		    "common_adv %#x\n", __func__, lpa, adv, common_adv_gb,
30327113afc8SEmmanuel Vadot 		    common_adv);
30337113afc8SEmmanuel Vadot 		if (common_adv_gb & (GTSR_LP_1000TFDX | GTSR_LP_1000THDX)) {
30347113afc8SEmmanuel Vadot 			axgbe_printf(2, "%s: SPEED 1000\n", __func__);
30357113afc8SEmmanuel Vadot 			pdata->phy.speed = SPEED_1000;
30367113afc8SEmmanuel Vadot 
30377113afc8SEmmanuel Vadot 			if (common_adv_gb & GTSR_LP_1000TFDX)
30387113afc8SEmmanuel Vadot 				pdata->phy.duplex = DUPLEX_FULL;
30397113afc8SEmmanuel Vadot 		} else if (common_adv & (ANLPAR_TX_FD | ANLPAR_TX)) {
30407113afc8SEmmanuel Vadot 			axgbe_printf(2, "%s: SPEED 100\n", __func__);
30417113afc8SEmmanuel Vadot 			pdata->phy.speed = SPEED_100;
30427113afc8SEmmanuel Vadot 
30437113afc8SEmmanuel Vadot 			if (common_adv & ANLPAR_TX_FD)
30447113afc8SEmmanuel Vadot 				pdata->phy.duplex = DUPLEX_FULL;
30457113afc8SEmmanuel Vadot 		} else
30467113afc8SEmmanuel Vadot 			if (common_adv & ANLPAR_10_FD)
30477113afc8SEmmanuel Vadot 				pdata->phy.duplex = DUPLEX_FULL;
30487113afc8SEmmanuel Vadot 
30497113afc8SEmmanuel Vadot 		if (pdata->phy.duplex == DUPLEX_FULL) {
30507113afc8SEmmanuel Vadot 			pdata->phy.pause = lpa & ANLPAR_FC ? 1 : 0;
30517113afc8SEmmanuel Vadot 			pdata->phy.asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0;
30527113afc8SEmmanuel Vadot 		}
30537113afc8SEmmanuel Vadot 	} else {
30547113afc8SEmmanuel Vadot 		int bmcr = xgbe_phy_mii_read(pdata, pdata->mdio_addr, MII_BMCR);
30557113afc8SEmmanuel Vadot 		if (bmcr < 0)
30567113afc8SEmmanuel Vadot 			return (bmcr);
30577113afc8SEmmanuel Vadot 
30587113afc8SEmmanuel Vadot 		if (bmcr & BMCR_FDX)
30597113afc8SEmmanuel Vadot 			pdata->phy.duplex = DUPLEX_FULL;
30607113afc8SEmmanuel Vadot 		else
30617113afc8SEmmanuel Vadot 			pdata->phy.duplex = DUPLEX_HALF;
30627113afc8SEmmanuel Vadot 
30637113afc8SEmmanuel Vadot 		if (bmcr & BMCR_SPEED1)
30647113afc8SEmmanuel Vadot 			pdata->phy.speed = SPEED_1000;
30657113afc8SEmmanuel Vadot 		else if (bmcr & BMCR_SPEED100)
30667113afc8SEmmanuel Vadot 			pdata->phy.speed = SPEED_100;
30677113afc8SEmmanuel Vadot 		else
30687113afc8SEmmanuel Vadot 			pdata->phy.speed = SPEED_10;
30697113afc8SEmmanuel Vadot 
30707113afc8SEmmanuel Vadot 		pdata->phy.pause = 0;
30717113afc8SEmmanuel Vadot 		pdata->phy.asym_pause = 0;
30727113afc8SEmmanuel Vadot 		axgbe_printf(2, "%s: link speed %#x duplex %#x media %#x "
30737113afc8SEmmanuel Vadot 		    "autoneg %#x\n", __func__, pdata->phy.speed,
30747113afc8SEmmanuel Vadot 		    pdata->phy.duplex, pdata->phy.link, pdata->phy.autoneg);
30757113afc8SEmmanuel Vadot 	}
30767113afc8SEmmanuel Vadot 
30777113afc8SEmmanuel Vadot 	return (0);
30787113afc8SEmmanuel Vadot }
30797113afc8SEmmanuel Vadot 
3080445bed5cSStephan de Wit static void
xgbe_rrc(struct xgbe_prv_data * pdata)3081445bed5cSStephan de Wit xgbe_rrc(struct xgbe_prv_data *pdata)
3082445bed5cSStephan de Wit {
3083445bed5cSStephan de Wit 	struct xgbe_phy_data *phy_data = pdata->phy_data;
3084445bed5cSStephan de Wit 	int ret;
3085445bed5cSStephan de Wit 
3086445bed5cSStephan de Wit 	if (phy_data->rrc_count++ > XGBE_RRC_FREQUENCY) {
3087445bed5cSStephan de Wit 		axgbe_printf(1, "ENTERED RRC: rrc_count: %d\n",
3088445bed5cSStephan de Wit 			phy_data->rrc_count);
3089445bed5cSStephan de Wit 		phy_data->rrc_count = 0;
3090445bed5cSStephan de Wit 		if (pdata->link_workaround) {
3091445bed5cSStephan de Wit 			ret = xgbe_phy_reset(pdata);
3092445bed5cSStephan de Wit 			if (ret)
3093445bed5cSStephan de Wit 				axgbe_error("Error resetting phy\n");
3094445bed5cSStephan de Wit 		} else
3095445bed5cSStephan de Wit 			xgbe_phy_rrc(pdata);
3096445bed5cSStephan de Wit 	}
3097445bed5cSStephan de Wit }
3098445bed5cSStephan de Wit 
30997113afc8SEmmanuel Vadot static int
xgbe_phy_link_status(struct xgbe_prv_data * pdata,int * an_restart)31007113afc8SEmmanuel Vadot xgbe_phy_link_status(struct xgbe_prv_data *pdata, int *an_restart)
31017113afc8SEmmanuel Vadot {
31027113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
31037113afc8SEmmanuel Vadot 	struct mii_data *mii = NULL;
31047113afc8SEmmanuel Vadot 	unsigned int reg;
31057113afc8SEmmanuel Vadot 	int ret;
31067113afc8SEmmanuel Vadot 
31077113afc8SEmmanuel Vadot 	*an_restart = 0;
31087113afc8SEmmanuel Vadot 
31097113afc8SEmmanuel Vadot 	if (phy_data->port_mode == XGBE_PORT_MODE_SFP) {
31107113afc8SEmmanuel Vadot 		/* Check SFP signals */
31117113afc8SEmmanuel Vadot 		axgbe_printf(3, "%s: calling phy detect\n", __func__);
31127113afc8SEmmanuel Vadot 		xgbe_phy_sfp_detect(pdata);
31137113afc8SEmmanuel Vadot 
31147113afc8SEmmanuel Vadot 		if (phy_data->sfp_changed) {
31157113afc8SEmmanuel Vadot 			axgbe_printf(1, "%s: SFP changed observed\n", __func__);
31167113afc8SEmmanuel Vadot 			*an_restart = 1;
31177113afc8SEmmanuel Vadot 			return (0);
31187113afc8SEmmanuel Vadot 		}
31197113afc8SEmmanuel Vadot 
31207113afc8SEmmanuel Vadot 		if (phy_data->sfp_mod_absent || phy_data->sfp_rx_los) {
31217113afc8SEmmanuel Vadot 			axgbe_printf(1, "%s: SFP absent 0x%x & sfp_rx_los 0x%x\n",
31227113afc8SEmmanuel Vadot 			    __func__, phy_data->sfp_mod_absent,
31237113afc8SEmmanuel Vadot 			    phy_data->sfp_rx_los);
3124445bed5cSStephan de Wit 
3125445bed5cSStephan de Wit 			if (!phy_data->sfp_mod_absent) {
3126445bed5cSStephan de Wit 				xgbe_rrc(pdata);
3127445bed5cSStephan de Wit 			}
3128445bed5cSStephan de Wit 
31297113afc8SEmmanuel Vadot 			return (0);
31307113afc8SEmmanuel Vadot 		}
3131445bed5cSStephan de Wit 	}
3132445bed5cSStephan de Wit 
3133445bed5cSStephan de Wit 	if (phy_data->phydev || phy_data->port_mode != XGBE_PORT_MODE_SFP) {
3134445bed5cSStephan de Wit 		if (pdata->axgbe_miibus == NULL) {
3135445bed5cSStephan de Wit 			axgbe_printf(1, "%s: miibus not initialized", __func__);
3136445bed5cSStephan de Wit 			goto mdio_read;
3137445bed5cSStephan de Wit 		}
3138445bed5cSStephan de Wit 
31397113afc8SEmmanuel Vadot 		mii = device_get_softc(pdata->axgbe_miibus);
31407113afc8SEmmanuel Vadot 		mii_tick(mii);
31417113afc8SEmmanuel Vadot 
31427113afc8SEmmanuel Vadot 		ret = xgbe_phy_read_status(pdata);
31437113afc8SEmmanuel Vadot 		if (ret) {
3144445bed5cSStephan de Wit 			axgbe_error("Link: Read status returned %d\n", ret);
3145445bed5cSStephan de Wit 			return (0);
31467113afc8SEmmanuel Vadot 		}
31477113afc8SEmmanuel Vadot 
31487113afc8SEmmanuel Vadot 		axgbe_printf(2, "%s: link speed %#x duplex %#x media %#x "
31497113afc8SEmmanuel Vadot 		    "autoneg %#x\n", __func__, pdata->phy.speed,
31507113afc8SEmmanuel Vadot 		    pdata->phy.duplex, pdata->phy.link, pdata->phy.autoneg);
31517113afc8SEmmanuel Vadot 		ret = xgbe_phy_mii_read(pdata, pdata->mdio_addr, MII_BMSR);
31527113afc8SEmmanuel Vadot 		ret = (ret < 0) ? ret : (ret & BMSR_ACOMP);
31537113afc8SEmmanuel Vadot 		axgbe_printf(2, "Link: BMCR returned %d\n", ret);
31547113afc8SEmmanuel Vadot 		if ((pdata->phy.autoneg == AUTONEG_ENABLE) && !ret)
31557113afc8SEmmanuel Vadot 			return (0);
31567113afc8SEmmanuel Vadot 
3157445bed5cSStephan de Wit 		if (pdata->phy.link)
3158445bed5cSStephan de Wit 			return (1);
3159445bed5cSStephan de Wit 
3160445bed5cSStephan de Wit 		xgbe_rrc(pdata);
31617113afc8SEmmanuel Vadot 	}
31627113afc8SEmmanuel Vadot 
3163445bed5cSStephan de Wit mdio_read:
3164445bed5cSStephan de Wit 
31657113afc8SEmmanuel Vadot 	/* Link status is latched low, so read once to clear
31667113afc8SEmmanuel Vadot 	 * and then read again to get current state
31677113afc8SEmmanuel Vadot 	 */
31687113afc8SEmmanuel Vadot 	reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1);
31697113afc8SEmmanuel Vadot 	reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1);
31707113afc8SEmmanuel Vadot 	axgbe_printf(1, "%s: link_status reg: 0x%x\n", __func__, reg);
31717113afc8SEmmanuel Vadot 	if (reg & MDIO_STAT1_LSTATUS)
31727113afc8SEmmanuel Vadot 		return (1);
31737113afc8SEmmanuel Vadot 
31747113afc8SEmmanuel Vadot 	/* No link, attempt a receiver reset cycle */
3175445bed5cSStephan de Wit 	xgbe_rrc(pdata);
31767113afc8SEmmanuel Vadot 
31777113afc8SEmmanuel Vadot 	return (0);
31787113afc8SEmmanuel Vadot }
31797113afc8SEmmanuel Vadot 
31807113afc8SEmmanuel Vadot static void
xgbe_phy_sfp_gpio_setup(struct xgbe_prv_data * pdata)31817113afc8SEmmanuel Vadot xgbe_phy_sfp_gpio_setup(struct xgbe_prv_data *pdata)
31827113afc8SEmmanuel Vadot {
31837113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
31847113afc8SEmmanuel Vadot 
31857113afc8SEmmanuel Vadot 	phy_data->sfp_gpio_address = XGBE_GPIO_ADDRESS_PCA9555 +
31867113afc8SEmmanuel Vadot 	    XP_GET_BITS(pdata->pp3, XP_PROP_3, GPIO_ADDR);
31877113afc8SEmmanuel Vadot 	phy_data->sfp_gpio_mask = XP_GET_BITS(pdata->pp3, XP_PROP_3,
31887113afc8SEmmanuel Vadot 	    GPIO_MASK);
31897113afc8SEmmanuel Vadot 	phy_data->sfp_gpio_rx_los = XP_GET_BITS(pdata->pp3, XP_PROP_3,
31907113afc8SEmmanuel Vadot 	    GPIO_RX_LOS);
31917113afc8SEmmanuel Vadot 	phy_data->sfp_gpio_tx_fault = XP_GET_BITS(pdata->pp3, XP_PROP_3,
31927113afc8SEmmanuel Vadot 	    GPIO_TX_FAULT);
31937113afc8SEmmanuel Vadot 	phy_data->sfp_gpio_mod_absent = XP_GET_BITS(pdata->pp3, XP_PROP_3,
31947113afc8SEmmanuel Vadot 	    GPIO_MOD_ABS);
31957113afc8SEmmanuel Vadot 	phy_data->sfp_gpio_rate_select = XP_GET_BITS(pdata->pp3, XP_PROP_3,
31967113afc8SEmmanuel Vadot 	    GPIO_RATE_SELECT);
31977113afc8SEmmanuel Vadot 
31987113afc8SEmmanuel Vadot 	DBGPR("SFP: gpio_address=%#x\n", phy_data->sfp_gpio_address);
31997113afc8SEmmanuel Vadot 	DBGPR("SFP: gpio_mask=%#x\n",	phy_data->sfp_gpio_mask);
32007113afc8SEmmanuel Vadot 	DBGPR("SFP: gpio_rx_los=%u\n", phy_data->sfp_gpio_rx_los);
32017113afc8SEmmanuel Vadot 	DBGPR("SFP: gpio_tx_fault=%u\n", phy_data->sfp_gpio_tx_fault);
32027113afc8SEmmanuel Vadot 	DBGPR("SFP: gpio_mod_absent=%u\n",
32037113afc8SEmmanuel Vadot 	    phy_data->sfp_gpio_mod_absent);
32047113afc8SEmmanuel Vadot 	DBGPR("SFP: gpio_rate_select=%u\n",
32057113afc8SEmmanuel Vadot 	    phy_data->sfp_gpio_rate_select);
32067113afc8SEmmanuel Vadot }
32077113afc8SEmmanuel Vadot 
32087113afc8SEmmanuel Vadot static void
xgbe_phy_sfp_comm_setup(struct xgbe_prv_data * pdata)32097113afc8SEmmanuel Vadot xgbe_phy_sfp_comm_setup(struct xgbe_prv_data *pdata)
32107113afc8SEmmanuel Vadot {
32117113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
32127113afc8SEmmanuel Vadot 	unsigned int mux_addr_hi, mux_addr_lo;
32137113afc8SEmmanuel Vadot 
32147113afc8SEmmanuel Vadot 	mux_addr_hi = XP_GET_BITS(pdata->pp4, XP_PROP_4, MUX_ADDR_HI);
32157113afc8SEmmanuel Vadot 	mux_addr_lo = XP_GET_BITS(pdata->pp4, XP_PROP_4, MUX_ADDR_LO);
32167113afc8SEmmanuel Vadot 	if (mux_addr_lo == XGBE_SFP_DIRECT)
32177113afc8SEmmanuel Vadot 		return;
32187113afc8SEmmanuel Vadot 
32197113afc8SEmmanuel Vadot 	phy_data->sfp_comm = XGBE_SFP_COMM_PCA9545;
32207113afc8SEmmanuel Vadot 	phy_data->sfp_mux_address = (mux_addr_hi << 2) + mux_addr_lo;
32217113afc8SEmmanuel Vadot 	phy_data->sfp_mux_channel = XP_GET_BITS(pdata->pp4, XP_PROP_4,
32227113afc8SEmmanuel Vadot 						MUX_CHAN);
32237113afc8SEmmanuel Vadot 
32247113afc8SEmmanuel Vadot 	DBGPR("SFP: mux_address=%#x\n", phy_data->sfp_mux_address);
32257113afc8SEmmanuel Vadot 	DBGPR("SFP: mux_channel=%u\n", phy_data->sfp_mux_channel);
32267113afc8SEmmanuel Vadot }
32277113afc8SEmmanuel Vadot 
32287113afc8SEmmanuel Vadot static void
xgbe_phy_sfp_setup(struct xgbe_prv_data * pdata)32297113afc8SEmmanuel Vadot xgbe_phy_sfp_setup(struct xgbe_prv_data *pdata)
32307113afc8SEmmanuel Vadot {
32317113afc8SEmmanuel Vadot 	xgbe_phy_sfp_comm_setup(pdata);
32327113afc8SEmmanuel Vadot 	xgbe_phy_sfp_gpio_setup(pdata);
32337113afc8SEmmanuel Vadot }
32347113afc8SEmmanuel Vadot 
32357113afc8SEmmanuel Vadot static int
xgbe_phy_int_mdio_reset(struct xgbe_prv_data * pdata)32367113afc8SEmmanuel Vadot xgbe_phy_int_mdio_reset(struct xgbe_prv_data *pdata)
32377113afc8SEmmanuel Vadot {
32387113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
32397113afc8SEmmanuel Vadot 	unsigned int ret;
32407113afc8SEmmanuel Vadot 
32417113afc8SEmmanuel Vadot 	ret = pdata->hw_if.set_gpio(pdata, phy_data->mdio_reset_gpio);
32427113afc8SEmmanuel Vadot 	if (ret)
32437113afc8SEmmanuel Vadot 		return (ret);
32447113afc8SEmmanuel Vadot 
32457113afc8SEmmanuel Vadot 	ret = pdata->hw_if.clr_gpio(pdata, phy_data->mdio_reset_gpio);
32467113afc8SEmmanuel Vadot 
32477113afc8SEmmanuel Vadot 	return (ret);
32487113afc8SEmmanuel Vadot }
32497113afc8SEmmanuel Vadot 
32507113afc8SEmmanuel Vadot static int
xgbe_phy_i2c_mdio_reset(struct xgbe_prv_data * pdata)32517113afc8SEmmanuel Vadot xgbe_phy_i2c_mdio_reset(struct xgbe_prv_data *pdata)
32527113afc8SEmmanuel Vadot {
32537113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
32547113afc8SEmmanuel Vadot 	uint8_t gpio_reg, gpio_ports[2], gpio_data[3];
32557113afc8SEmmanuel Vadot 	int ret;
32567113afc8SEmmanuel Vadot 
32577113afc8SEmmanuel Vadot 	/* Read the output port registers */
32587113afc8SEmmanuel Vadot 	gpio_reg = 2;
32597113afc8SEmmanuel Vadot 	ret = xgbe_phy_i2c_read(pdata, phy_data->mdio_reset_addr,
32607113afc8SEmmanuel Vadot 				&gpio_reg, sizeof(gpio_reg),
32617113afc8SEmmanuel Vadot 				gpio_ports, sizeof(gpio_ports));
32627113afc8SEmmanuel Vadot 	if (ret)
32637113afc8SEmmanuel Vadot 		return (ret);
32647113afc8SEmmanuel Vadot 
32657113afc8SEmmanuel Vadot 	/* Prepare to write the GPIO data */
32667113afc8SEmmanuel Vadot 	gpio_data[0] = 2;
32677113afc8SEmmanuel Vadot 	gpio_data[1] = gpio_ports[0];
32687113afc8SEmmanuel Vadot 	gpio_data[2] = gpio_ports[1];
32697113afc8SEmmanuel Vadot 
32707113afc8SEmmanuel Vadot 	/* Set the GPIO pin */
32717113afc8SEmmanuel Vadot 	if (phy_data->mdio_reset_gpio < 8)
32727113afc8SEmmanuel Vadot 		gpio_data[1] |= (1 << (phy_data->mdio_reset_gpio % 8));
32737113afc8SEmmanuel Vadot 	else
32747113afc8SEmmanuel Vadot 		gpio_data[2] |= (1 << (phy_data->mdio_reset_gpio % 8));
32757113afc8SEmmanuel Vadot 
32767113afc8SEmmanuel Vadot 	/* Write the output port registers */
32777113afc8SEmmanuel Vadot 	ret = xgbe_phy_i2c_write(pdata, phy_data->mdio_reset_addr,
32787113afc8SEmmanuel Vadot 				 gpio_data, sizeof(gpio_data));
32797113afc8SEmmanuel Vadot 	if (ret)
32807113afc8SEmmanuel Vadot 		return (ret);
32817113afc8SEmmanuel Vadot 
32827113afc8SEmmanuel Vadot 	/* Clear the GPIO pin */
32837113afc8SEmmanuel Vadot 	if (phy_data->mdio_reset_gpio < 8)
32847113afc8SEmmanuel Vadot 		gpio_data[1] &= ~(1 << (phy_data->mdio_reset_gpio % 8));
32857113afc8SEmmanuel Vadot 	else
32867113afc8SEmmanuel Vadot 		gpio_data[2] &= ~(1 << (phy_data->mdio_reset_gpio % 8));
32877113afc8SEmmanuel Vadot 
32887113afc8SEmmanuel Vadot 	/* Write the output port registers */
32897113afc8SEmmanuel Vadot 	ret = xgbe_phy_i2c_write(pdata, phy_data->mdio_reset_addr,
32907113afc8SEmmanuel Vadot 				 gpio_data, sizeof(gpio_data));
32917113afc8SEmmanuel Vadot 
32927113afc8SEmmanuel Vadot 	return (ret);
32937113afc8SEmmanuel Vadot }
32947113afc8SEmmanuel Vadot 
32957113afc8SEmmanuel Vadot static int
xgbe_phy_mdio_reset(struct xgbe_prv_data * pdata)32967113afc8SEmmanuel Vadot xgbe_phy_mdio_reset(struct xgbe_prv_data *pdata)
32977113afc8SEmmanuel Vadot {
32987113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
32997113afc8SEmmanuel Vadot 	int ret;
33007113afc8SEmmanuel Vadot 
33017113afc8SEmmanuel Vadot 	if (phy_data->conn_type != XGBE_CONN_TYPE_MDIO)
33027113afc8SEmmanuel Vadot 		return (0);
33037113afc8SEmmanuel Vadot 
33047113afc8SEmmanuel Vadot 	ret = xgbe_phy_get_comm_ownership(pdata);
33057113afc8SEmmanuel Vadot 	if (ret)
33067113afc8SEmmanuel Vadot 		return (ret);
33077113afc8SEmmanuel Vadot 
33087113afc8SEmmanuel Vadot 	if (phy_data->mdio_reset == XGBE_MDIO_RESET_I2C_GPIO)
33097113afc8SEmmanuel Vadot 		ret = xgbe_phy_i2c_mdio_reset(pdata);
33107113afc8SEmmanuel Vadot 	else if (phy_data->mdio_reset == XGBE_MDIO_RESET_INT_GPIO)
33117113afc8SEmmanuel Vadot 		ret = xgbe_phy_int_mdio_reset(pdata);
33127113afc8SEmmanuel Vadot 
33137113afc8SEmmanuel Vadot 	xgbe_phy_put_comm_ownership(pdata);
33147113afc8SEmmanuel Vadot 
33157113afc8SEmmanuel Vadot 	return (ret);
33167113afc8SEmmanuel Vadot }
33177113afc8SEmmanuel Vadot 
33187113afc8SEmmanuel Vadot static bool
xgbe_phy_redrv_error(struct xgbe_phy_data * phy_data)33197113afc8SEmmanuel Vadot xgbe_phy_redrv_error(struct xgbe_phy_data *phy_data)
33207113afc8SEmmanuel Vadot {
33217113afc8SEmmanuel Vadot 	if (!phy_data->redrv)
33227113afc8SEmmanuel Vadot 		return (false);
33237113afc8SEmmanuel Vadot 
33247113afc8SEmmanuel Vadot 	if (phy_data->redrv_if >= XGBE_PHY_REDRV_IF_MAX)
33257113afc8SEmmanuel Vadot 		return (true);
33267113afc8SEmmanuel Vadot 
33277113afc8SEmmanuel Vadot 	switch (phy_data->redrv_model) {
33287113afc8SEmmanuel Vadot 	case XGBE_PHY_REDRV_MODEL_4223:
33297113afc8SEmmanuel Vadot 		if (phy_data->redrv_lane > 3)
33307113afc8SEmmanuel Vadot 			return (true);
33317113afc8SEmmanuel Vadot 		break;
33327113afc8SEmmanuel Vadot 	case XGBE_PHY_REDRV_MODEL_4227:
33337113afc8SEmmanuel Vadot 		if (phy_data->redrv_lane > 1)
33347113afc8SEmmanuel Vadot 			return (true);
33357113afc8SEmmanuel Vadot 		break;
33367113afc8SEmmanuel Vadot 	default:
33377113afc8SEmmanuel Vadot 		return (true);
33387113afc8SEmmanuel Vadot 	}
33397113afc8SEmmanuel Vadot 
33407113afc8SEmmanuel Vadot 	return (false);
33417113afc8SEmmanuel Vadot }
33427113afc8SEmmanuel Vadot 
33437113afc8SEmmanuel Vadot static int
xgbe_phy_mdio_reset_setup(struct xgbe_prv_data * pdata)33447113afc8SEmmanuel Vadot xgbe_phy_mdio_reset_setup(struct xgbe_prv_data *pdata)
33457113afc8SEmmanuel Vadot {
33467113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
33477113afc8SEmmanuel Vadot 
33487113afc8SEmmanuel Vadot 	if (phy_data->conn_type != XGBE_CONN_TYPE_MDIO)
33497113afc8SEmmanuel Vadot 		return (0);
33507113afc8SEmmanuel Vadot 
33517113afc8SEmmanuel Vadot 	phy_data->mdio_reset = XP_GET_BITS(pdata->pp3, XP_PROP_3, MDIO_RESET);
33527113afc8SEmmanuel Vadot 	switch (phy_data->mdio_reset) {
33537113afc8SEmmanuel Vadot 	case XGBE_MDIO_RESET_NONE:
33547113afc8SEmmanuel Vadot 	case XGBE_MDIO_RESET_I2C_GPIO:
33557113afc8SEmmanuel Vadot 	case XGBE_MDIO_RESET_INT_GPIO:
33567113afc8SEmmanuel Vadot 		break;
33577113afc8SEmmanuel Vadot 	default:
33587113afc8SEmmanuel Vadot 		axgbe_error("unsupported MDIO reset (%#x)\n",
33597113afc8SEmmanuel Vadot 		    phy_data->mdio_reset);
33607113afc8SEmmanuel Vadot 		return (-EINVAL);
33617113afc8SEmmanuel Vadot 	}
33627113afc8SEmmanuel Vadot 
33637113afc8SEmmanuel Vadot 	if (phy_data->mdio_reset == XGBE_MDIO_RESET_I2C_GPIO) {
33647113afc8SEmmanuel Vadot 		phy_data->mdio_reset_addr = XGBE_GPIO_ADDRESS_PCA9555 +
33657113afc8SEmmanuel Vadot 		    XP_GET_BITS(pdata->pp3, XP_PROP_3, MDIO_RESET_I2C_ADDR);
33667113afc8SEmmanuel Vadot 		phy_data->mdio_reset_gpio = XP_GET_BITS(pdata->pp3, XP_PROP_3,
33677113afc8SEmmanuel Vadot 		    MDIO_RESET_I2C_GPIO);
33687113afc8SEmmanuel Vadot 	} else if (phy_data->mdio_reset == XGBE_MDIO_RESET_INT_GPIO)
33697113afc8SEmmanuel Vadot 		phy_data->mdio_reset_gpio = XP_GET_BITS(pdata->pp3, XP_PROP_3,
33707113afc8SEmmanuel Vadot 		    MDIO_RESET_INT_GPIO);
33717113afc8SEmmanuel Vadot 
33727113afc8SEmmanuel Vadot 	return (0);
33737113afc8SEmmanuel Vadot }
33747113afc8SEmmanuel Vadot 
33757113afc8SEmmanuel Vadot static bool
xgbe_phy_port_mode_mismatch(struct xgbe_prv_data * pdata)33767113afc8SEmmanuel Vadot xgbe_phy_port_mode_mismatch(struct xgbe_prv_data *pdata)
33777113afc8SEmmanuel Vadot {
33787113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
33797113afc8SEmmanuel Vadot 
33807113afc8SEmmanuel Vadot 	switch (phy_data->port_mode) {
33817113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_BACKPLANE:
33827113afc8SEmmanuel Vadot 		if ((phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) ||
33837113afc8SEmmanuel Vadot 		    (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000))
33847113afc8SEmmanuel Vadot 			return (false);
33857113afc8SEmmanuel Vadot 		break;
33867113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_BACKPLANE_2500:
33877113afc8SEmmanuel Vadot 		if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_2500)
33887113afc8SEmmanuel Vadot 			return (false);
33897113afc8SEmmanuel Vadot 		break;
33907113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_1000BASE_T:
33917113afc8SEmmanuel Vadot 		if ((phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) ||
33927113afc8SEmmanuel Vadot 		    (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000))
33937113afc8SEmmanuel Vadot 			return (false);
33947113afc8SEmmanuel Vadot 		break;
33957113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_1000BASE_X:
33967113afc8SEmmanuel Vadot 		if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000)
33977113afc8SEmmanuel Vadot 			return (false);
33987113afc8SEmmanuel Vadot 		break;
33997113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_NBASE_T:
34007113afc8SEmmanuel Vadot 		if ((phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) ||
34017113afc8SEmmanuel Vadot 		    (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) ||
34027113afc8SEmmanuel Vadot 		    (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_2500))
34037113afc8SEmmanuel Vadot 			return (false);
34047113afc8SEmmanuel Vadot 		break;
34057113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_10GBASE_T:
34067113afc8SEmmanuel Vadot 		if ((phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) ||
34077113afc8SEmmanuel Vadot 		    (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) ||
34087113afc8SEmmanuel Vadot 		    (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000))
34097113afc8SEmmanuel Vadot 			return (false);
34107113afc8SEmmanuel Vadot 		break;
34117113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_10GBASE_R:
34127113afc8SEmmanuel Vadot 		if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000)
34137113afc8SEmmanuel Vadot 			return (false);
34147113afc8SEmmanuel Vadot 		break;
34157113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_SFP:
34167113afc8SEmmanuel Vadot 		if ((phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) ||
34177113afc8SEmmanuel Vadot 		    (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) ||
34187113afc8SEmmanuel Vadot 		    (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000))
34197113afc8SEmmanuel Vadot 			return (false);
34207113afc8SEmmanuel Vadot 		break;
34217113afc8SEmmanuel Vadot 	default:
34227113afc8SEmmanuel Vadot 		break;
34237113afc8SEmmanuel Vadot 	}
34247113afc8SEmmanuel Vadot 
34257113afc8SEmmanuel Vadot 	return (true);
34267113afc8SEmmanuel Vadot }
34277113afc8SEmmanuel Vadot 
34287113afc8SEmmanuel Vadot static bool
xgbe_phy_conn_type_mismatch(struct xgbe_prv_data * pdata)34297113afc8SEmmanuel Vadot xgbe_phy_conn_type_mismatch(struct xgbe_prv_data *pdata)
34307113afc8SEmmanuel Vadot {
34317113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
34327113afc8SEmmanuel Vadot 
34337113afc8SEmmanuel Vadot 	switch (phy_data->port_mode) {
34347113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_BACKPLANE:
34357113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_BACKPLANE_2500:
34367113afc8SEmmanuel Vadot 		if (phy_data->conn_type == XGBE_CONN_TYPE_BACKPLANE)
34377113afc8SEmmanuel Vadot 			return (false);
34387113afc8SEmmanuel Vadot 		break;
34397113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_1000BASE_T:
34407113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_1000BASE_X:
34417113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_NBASE_T:
34427113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_10GBASE_T:
34437113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_10GBASE_R:
34447113afc8SEmmanuel Vadot 		if (phy_data->conn_type == XGBE_CONN_TYPE_MDIO)
34457113afc8SEmmanuel Vadot 			return (false);
34467113afc8SEmmanuel Vadot 		break;
34477113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_SFP:
34487113afc8SEmmanuel Vadot 		if (phy_data->conn_type == XGBE_CONN_TYPE_SFP)
34497113afc8SEmmanuel Vadot 			return (false);
34507113afc8SEmmanuel Vadot 		break;
34517113afc8SEmmanuel Vadot 	default:
34527113afc8SEmmanuel Vadot 		break;
34537113afc8SEmmanuel Vadot 	}
34547113afc8SEmmanuel Vadot 
34557113afc8SEmmanuel Vadot 	return (true);
34567113afc8SEmmanuel Vadot }
34577113afc8SEmmanuel Vadot 
34587113afc8SEmmanuel Vadot static bool
xgbe_phy_port_enabled(struct xgbe_prv_data * pdata)34597113afc8SEmmanuel Vadot xgbe_phy_port_enabled(struct xgbe_prv_data *pdata)
34607113afc8SEmmanuel Vadot {
34617113afc8SEmmanuel Vadot 
34627113afc8SEmmanuel Vadot 	if (!XP_GET_BITS(pdata->pp0, XP_PROP_0, PORT_SPEEDS))
34637113afc8SEmmanuel Vadot 		return (false);
34647113afc8SEmmanuel Vadot 	if (!XP_GET_BITS(pdata->pp0, XP_PROP_0, CONN_TYPE))
34657113afc8SEmmanuel Vadot 		return (false);
34667113afc8SEmmanuel Vadot 
34677113afc8SEmmanuel Vadot 	return (true);
34687113afc8SEmmanuel Vadot }
34697113afc8SEmmanuel Vadot 
34707113afc8SEmmanuel Vadot static void
xgbe_phy_cdr_track(struct xgbe_prv_data * pdata)34717113afc8SEmmanuel Vadot xgbe_phy_cdr_track(struct xgbe_prv_data *pdata)
34727113afc8SEmmanuel Vadot {
34737113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
34747113afc8SEmmanuel Vadot 
34757113afc8SEmmanuel Vadot 	axgbe_printf(2, "%s: an_cdr_workaround %d phy_cdr_notrack %d\n",
34767113afc8SEmmanuel Vadot 	    __func__, pdata->sysctl_an_cdr_workaround, phy_data->phy_cdr_notrack);
34777113afc8SEmmanuel Vadot 
34787113afc8SEmmanuel Vadot 	if (!pdata->sysctl_an_cdr_workaround)
34797113afc8SEmmanuel Vadot 		return;
34807113afc8SEmmanuel Vadot 
34817113afc8SEmmanuel Vadot 	if (!phy_data->phy_cdr_notrack)
34827113afc8SEmmanuel Vadot 		return;
34837113afc8SEmmanuel Vadot 
34847113afc8SEmmanuel Vadot 	DELAY(phy_data->phy_cdr_delay + 500);
34857113afc8SEmmanuel Vadot 
34867113afc8SEmmanuel Vadot 	XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_VEND2_PMA_CDR_CONTROL,
34877113afc8SEmmanuel Vadot 	    XGBE_PMA_CDR_TRACK_EN_MASK, XGBE_PMA_CDR_TRACK_EN_ON);
34887113afc8SEmmanuel Vadot 
34897113afc8SEmmanuel Vadot 	phy_data->phy_cdr_notrack = 0;
34907113afc8SEmmanuel Vadot 
34917113afc8SEmmanuel Vadot 	axgbe_printf(2, "CDR TRACK DONE\n");
34927113afc8SEmmanuel Vadot }
34937113afc8SEmmanuel Vadot 
34947113afc8SEmmanuel Vadot static void
xgbe_phy_cdr_notrack(struct xgbe_prv_data * pdata)34957113afc8SEmmanuel Vadot xgbe_phy_cdr_notrack(struct xgbe_prv_data *pdata)
34967113afc8SEmmanuel Vadot {
34977113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
34987113afc8SEmmanuel Vadot 
34997113afc8SEmmanuel Vadot 	axgbe_printf(2, "%s: an_cdr_workaround %d phy_cdr_notrack %d\n",
35007113afc8SEmmanuel Vadot 	    __func__, pdata->sysctl_an_cdr_workaround, phy_data->phy_cdr_notrack);
35017113afc8SEmmanuel Vadot 
35027113afc8SEmmanuel Vadot 	if (!pdata->sysctl_an_cdr_workaround)
35037113afc8SEmmanuel Vadot 		return;
35047113afc8SEmmanuel Vadot 
35057113afc8SEmmanuel Vadot 	if (phy_data->phy_cdr_notrack)
35067113afc8SEmmanuel Vadot 		return;
35077113afc8SEmmanuel Vadot 
35087113afc8SEmmanuel Vadot 	XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_VEND2_PMA_CDR_CONTROL,
35097113afc8SEmmanuel Vadot 	    XGBE_PMA_CDR_TRACK_EN_MASK, XGBE_PMA_CDR_TRACK_EN_OFF);
35107113afc8SEmmanuel Vadot 
35117113afc8SEmmanuel Vadot 	xgbe_phy_rrc(pdata);
35127113afc8SEmmanuel Vadot 
35137113afc8SEmmanuel Vadot 	phy_data->phy_cdr_notrack = 1;
35147113afc8SEmmanuel Vadot }
35157113afc8SEmmanuel Vadot 
35167113afc8SEmmanuel Vadot static void
xgbe_phy_kr_training_post(struct xgbe_prv_data * pdata)35177113afc8SEmmanuel Vadot xgbe_phy_kr_training_post(struct xgbe_prv_data *pdata)
35187113afc8SEmmanuel Vadot {
35197113afc8SEmmanuel Vadot 	if (!pdata->sysctl_an_cdr_track_early)
35207113afc8SEmmanuel Vadot 		xgbe_phy_cdr_track(pdata);
35217113afc8SEmmanuel Vadot }
35227113afc8SEmmanuel Vadot 
35237113afc8SEmmanuel Vadot static void
xgbe_phy_kr_training_pre(struct xgbe_prv_data * pdata)35247113afc8SEmmanuel Vadot xgbe_phy_kr_training_pre(struct xgbe_prv_data *pdata)
35257113afc8SEmmanuel Vadot {
35267113afc8SEmmanuel Vadot 	if (pdata->sysctl_an_cdr_track_early)
35277113afc8SEmmanuel Vadot 		xgbe_phy_cdr_track(pdata);
35287113afc8SEmmanuel Vadot }
35297113afc8SEmmanuel Vadot 
35307113afc8SEmmanuel Vadot static void
xgbe_phy_an_post(struct xgbe_prv_data * pdata)35317113afc8SEmmanuel Vadot xgbe_phy_an_post(struct xgbe_prv_data *pdata)
35327113afc8SEmmanuel Vadot {
35337113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
35347113afc8SEmmanuel Vadot 
35357113afc8SEmmanuel Vadot 	switch (pdata->an_mode) {
35367113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL73:
35377113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL73_REDRV:
35387113afc8SEmmanuel Vadot 		if (phy_data->cur_mode != XGBE_MODE_KR)
35397113afc8SEmmanuel Vadot 			break;
35407113afc8SEmmanuel Vadot 
35417113afc8SEmmanuel Vadot 		xgbe_phy_cdr_track(pdata);
35427113afc8SEmmanuel Vadot 
35437113afc8SEmmanuel Vadot 		switch (pdata->an_result) {
35447113afc8SEmmanuel Vadot 		case XGBE_AN_READY:
35457113afc8SEmmanuel Vadot 		case XGBE_AN_COMPLETE:
35467113afc8SEmmanuel Vadot 			break;
35477113afc8SEmmanuel Vadot 		default:
35487113afc8SEmmanuel Vadot 			if (phy_data->phy_cdr_delay < XGBE_CDR_DELAY_MAX)
35497113afc8SEmmanuel Vadot 				phy_data->phy_cdr_delay += XGBE_CDR_DELAY_INC;
35507113afc8SEmmanuel Vadot 			else
35517113afc8SEmmanuel Vadot 				phy_data->phy_cdr_delay = XGBE_CDR_DELAY_INIT;
35527113afc8SEmmanuel Vadot 			break;
35537113afc8SEmmanuel Vadot 		}
35547113afc8SEmmanuel Vadot 		break;
35557113afc8SEmmanuel Vadot 	default:
35567113afc8SEmmanuel Vadot 		break;
35577113afc8SEmmanuel Vadot 	}
35587113afc8SEmmanuel Vadot }
35597113afc8SEmmanuel Vadot 
35607113afc8SEmmanuel Vadot static void
xgbe_phy_an_pre(struct xgbe_prv_data * pdata)35617113afc8SEmmanuel Vadot xgbe_phy_an_pre(struct xgbe_prv_data *pdata)
35627113afc8SEmmanuel Vadot {
35637113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
35647113afc8SEmmanuel Vadot 
35657113afc8SEmmanuel Vadot 	switch (pdata->an_mode) {
35667113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL73:
35677113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL73_REDRV:
35687113afc8SEmmanuel Vadot 		if (phy_data->cur_mode != XGBE_MODE_KR)
35697113afc8SEmmanuel Vadot 			break;
35707113afc8SEmmanuel Vadot 
35717113afc8SEmmanuel Vadot 		xgbe_phy_cdr_notrack(pdata);
35727113afc8SEmmanuel Vadot 		break;
35737113afc8SEmmanuel Vadot 	default:
35747113afc8SEmmanuel Vadot 		break;
35757113afc8SEmmanuel Vadot 	}
35767113afc8SEmmanuel Vadot }
35777113afc8SEmmanuel Vadot 
35787113afc8SEmmanuel Vadot static void
xgbe_phy_stop(struct xgbe_prv_data * pdata)35797113afc8SEmmanuel Vadot xgbe_phy_stop(struct xgbe_prv_data *pdata)
35807113afc8SEmmanuel Vadot {
35817113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
35827113afc8SEmmanuel Vadot 
35837113afc8SEmmanuel Vadot 	/* If we have an external PHY, free it */
35847113afc8SEmmanuel Vadot 	xgbe_phy_free_phy_device(pdata);
35857113afc8SEmmanuel Vadot 
35867113afc8SEmmanuel Vadot 	/* Reset SFP data */
35877113afc8SEmmanuel Vadot 	xgbe_phy_sfp_reset(phy_data);
35887113afc8SEmmanuel Vadot 	xgbe_phy_sfp_mod_absent(pdata);
35897113afc8SEmmanuel Vadot 
35907113afc8SEmmanuel Vadot 	/* Reset CDR support */
35917113afc8SEmmanuel Vadot 	xgbe_phy_cdr_track(pdata);
35927113afc8SEmmanuel Vadot 
35937113afc8SEmmanuel Vadot 	/* Power off the PHY */
35947113afc8SEmmanuel Vadot 	xgbe_phy_power_off(pdata);
35957113afc8SEmmanuel Vadot 
35967113afc8SEmmanuel Vadot 	/* Stop the I2C controller */
35977113afc8SEmmanuel Vadot 	pdata->i2c_if.i2c_stop(pdata);
35987113afc8SEmmanuel Vadot }
35997113afc8SEmmanuel Vadot 
36007113afc8SEmmanuel Vadot static int
xgbe_phy_start(struct xgbe_prv_data * pdata)36017113afc8SEmmanuel Vadot xgbe_phy_start(struct xgbe_prv_data *pdata)
36027113afc8SEmmanuel Vadot {
36037113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
36047113afc8SEmmanuel Vadot 	int ret;
36057113afc8SEmmanuel Vadot 
36067113afc8SEmmanuel Vadot 	axgbe_printf(2, "%s: redrv %d redrv_if %d start_mode %d\n", __func__,
36077113afc8SEmmanuel Vadot 	    phy_data->redrv, phy_data->redrv_if, phy_data->start_mode);
36087113afc8SEmmanuel Vadot 
36097113afc8SEmmanuel Vadot 	/* Start the I2C controller */
36107113afc8SEmmanuel Vadot 	ret = pdata->i2c_if.i2c_start(pdata);
36117113afc8SEmmanuel Vadot 	if (ret) {
36127113afc8SEmmanuel Vadot 		axgbe_error("%s: impl i2c start ret %d\n", __func__, ret);
36137113afc8SEmmanuel Vadot 		return (ret);
36147113afc8SEmmanuel Vadot 	}
36157113afc8SEmmanuel Vadot 
36167113afc8SEmmanuel Vadot 	/* Set the proper MDIO mode for the re-driver */
36177113afc8SEmmanuel Vadot 	if (phy_data->redrv && !phy_data->redrv_if) {
36187113afc8SEmmanuel Vadot 		ret = pdata->hw_if.set_ext_mii_mode(pdata, phy_data->redrv_addr,
36197113afc8SEmmanuel Vadot 		    XGBE_MDIO_MODE_CL22);
36207113afc8SEmmanuel Vadot 		if (ret) {
36217113afc8SEmmanuel Vadot 			axgbe_error("redriver mdio port not compatible (%u)\n",
36227113afc8SEmmanuel Vadot 			    phy_data->redrv_addr);
36237113afc8SEmmanuel Vadot 			return (ret);
36247113afc8SEmmanuel Vadot 		}
36257113afc8SEmmanuel Vadot 	}
36267113afc8SEmmanuel Vadot 
36277113afc8SEmmanuel Vadot 	/* Start in highest supported mode */
36287113afc8SEmmanuel Vadot 	xgbe_phy_set_mode(pdata, phy_data->start_mode);
36297113afc8SEmmanuel Vadot 
36307113afc8SEmmanuel Vadot 	/* Reset CDR support */
36317113afc8SEmmanuel Vadot 	xgbe_phy_cdr_track(pdata);
36327113afc8SEmmanuel Vadot 
36337113afc8SEmmanuel Vadot 	/* After starting the I2C controller, we can check for an SFP */
36347113afc8SEmmanuel Vadot 	switch (phy_data->port_mode) {
36357113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_SFP:
36367113afc8SEmmanuel Vadot 		axgbe_printf(3, "%s: calling phy detect\n", __func__);
36372b8df536SStephan de Wit 
36382b8df536SStephan de Wit 		/*
36392b8df536SStephan de Wit 		 * Validate the configuration of the GPIO expander before
36402b8df536SStephan de Wit 		 * we interpret the SFP signals.
36412b8df536SStephan de Wit 		 */
36422b8df536SStephan de Wit 		axgbe_printf(1, "Checking GPIO expander validity\n");
36432b8df536SStephan de Wit 		xgbe_phy_validate_gpio_expander(pdata);
36442b8df536SStephan de Wit 
36452b8df536SStephan de Wit 		phy_data->sfp_phy_retries = 0;
36467113afc8SEmmanuel Vadot 		xgbe_phy_sfp_detect(pdata);
36477113afc8SEmmanuel Vadot 		break;
36487113afc8SEmmanuel Vadot 	default:
36497113afc8SEmmanuel Vadot 		break;
36507113afc8SEmmanuel Vadot 	}
36517113afc8SEmmanuel Vadot 
36527113afc8SEmmanuel Vadot 	/* If we have an external PHY, start it */
36537113afc8SEmmanuel Vadot 	ret = xgbe_phy_find_phy_device(pdata);
36547113afc8SEmmanuel Vadot 	if (ret) {
36557113afc8SEmmanuel Vadot 		axgbe_error("%s: impl find phy dev ret %d\n", __func__, ret);
36567113afc8SEmmanuel Vadot 		goto err_i2c;
36577113afc8SEmmanuel Vadot 	}
36587113afc8SEmmanuel Vadot 
36597113afc8SEmmanuel Vadot 	axgbe_printf(3, "%s: impl return success\n", __func__);
36607113afc8SEmmanuel Vadot 	return (0);
36617113afc8SEmmanuel Vadot 
36627113afc8SEmmanuel Vadot err_i2c:
36637113afc8SEmmanuel Vadot 	pdata->i2c_if.i2c_stop(pdata);
36647113afc8SEmmanuel Vadot 
36657113afc8SEmmanuel Vadot 	return (ret);
36667113afc8SEmmanuel Vadot }
36677113afc8SEmmanuel Vadot 
36687113afc8SEmmanuel Vadot static int
xgbe_phy_reset(struct xgbe_prv_data * pdata)36697113afc8SEmmanuel Vadot xgbe_phy_reset(struct xgbe_prv_data *pdata)
36707113afc8SEmmanuel Vadot {
36717113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data = pdata->phy_data;
36727113afc8SEmmanuel Vadot 	enum xgbe_mode cur_mode;
36737113afc8SEmmanuel Vadot 	int ret;
36747113afc8SEmmanuel Vadot 
36757113afc8SEmmanuel Vadot 	/* Reset by power cycling the PHY */
36767113afc8SEmmanuel Vadot 	cur_mode = phy_data->cur_mode;
36777113afc8SEmmanuel Vadot 	xgbe_phy_power_off(pdata);
36787113afc8SEmmanuel Vadot 	xgbe_phy_set_mode(pdata, cur_mode);
36797113afc8SEmmanuel Vadot 
36807113afc8SEmmanuel Vadot 	axgbe_printf(3, "%s: mode %d\n", __func__, cur_mode);
36817113afc8SEmmanuel Vadot 	if (!phy_data->phydev) {
36827113afc8SEmmanuel Vadot 		axgbe_printf(1, "%s: no phydev\n", __func__);
36837113afc8SEmmanuel Vadot 		return (0);
36847113afc8SEmmanuel Vadot 	}
36857113afc8SEmmanuel Vadot 
36867113afc8SEmmanuel Vadot 	/* Reset the external PHY */
36877113afc8SEmmanuel Vadot 	ret = xgbe_phy_mdio_reset(pdata);
36887113afc8SEmmanuel Vadot 	if (ret) {
36897113afc8SEmmanuel Vadot 		axgbe_error("%s: mdio reset %d\n", __func__, ret);
36907113afc8SEmmanuel Vadot 		return (ret);
36917113afc8SEmmanuel Vadot 	}
36927113afc8SEmmanuel Vadot 
36937113afc8SEmmanuel Vadot 	axgbe_printf(3, "%s: return success\n", __func__);
36947113afc8SEmmanuel Vadot 
36957113afc8SEmmanuel Vadot 	return (0);
36967113afc8SEmmanuel Vadot }
36977113afc8SEmmanuel Vadot 
36987113afc8SEmmanuel Vadot static void
axgbe_ifmedia_sts(if_t ifp,struct ifmediareq * ifmr)3699402810d3SJustin Hibbits axgbe_ifmedia_sts(if_t ifp, struct ifmediareq *ifmr)
37007113afc8SEmmanuel Vadot {
37017113afc8SEmmanuel Vadot 	struct axgbe_if_softc *sc;
37027113afc8SEmmanuel Vadot 	struct xgbe_prv_data *pdata;
37037113afc8SEmmanuel Vadot 	struct mii_data *mii;
37047113afc8SEmmanuel Vadot 
3705402810d3SJustin Hibbits 	sc = if_getsoftc(ifp);
37067113afc8SEmmanuel Vadot 	pdata = &sc->pdata;
37077113afc8SEmmanuel Vadot 
37087113afc8SEmmanuel Vadot 	axgbe_printf(2, "%s: Invoked\n", __func__);
37097113afc8SEmmanuel Vadot 	mtx_lock_spin(&pdata->mdio_mutex);
37107113afc8SEmmanuel Vadot 	mii = device_get_softc(pdata->axgbe_miibus);
37117113afc8SEmmanuel Vadot 	axgbe_printf(2, "%s: media_active %#x media_status %#x\n", __func__,
37127113afc8SEmmanuel Vadot 	    mii->mii_media_active, mii->mii_media_status);
37137113afc8SEmmanuel Vadot 	mii_pollstat(mii);
37147113afc8SEmmanuel Vadot 	ifmr->ifm_active = mii->mii_media_active;
37157113afc8SEmmanuel Vadot 	ifmr->ifm_status = mii->mii_media_status;
37167113afc8SEmmanuel Vadot 	mtx_unlock_spin(&pdata->mdio_mutex);
37177113afc8SEmmanuel Vadot }
37187113afc8SEmmanuel Vadot 
37197113afc8SEmmanuel Vadot static int
axgbe_ifmedia_upd(if_t ifp)3720402810d3SJustin Hibbits axgbe_ifmedia_upd(if_t ifp)
37217113afc8SEmmanuel Vadot {
37227113afc8SEmmanuel Vadot 	struct xgbe_prv_data *pdata;
37237113afc8SEmmanuel Vadot 	struct axgbe_if_softc *sc;
37247113afc8SEmmanuel Vadot 	struct mii_data *mii;
37257113afc8SEmmanuel Vadot 	struct mii_softc *miisc;
37267113afc8SEmmanuel Vadot 	int ret;
37277113afc8SEmmanuel Vadot 
3728402810d3SJustin Hibbits 	sc = if_getsoftc(ifp);
37297113afc8SEmmanuel Vadot 	pdata = &sc->pdata;
37307113afc8SEmmanuel Vadot 
37317113afc8SEmmanuel Vadot 	axgbe_printf(2, "%s: Invoked\n", __func__);
37327113afc8SEmmanuel Vadot 	mtx_lock_spin(&pdata->mdio_mutex);
37337113afc8SEmmanuel Vadot 	mii = device_get_softc(pdata->axgbe_miibus);
37347113afc8SEmmanuel Vadot 	LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
37357113afc8SEmmanuel Vadot 		PHY_RESET(miisc);
37367113afc8SEmmanuel Vadot 	ret = mii_mediachg(mii);
37377113afc8SEmmanuel Vadot 	mtx_unlock_spin(&pdata->mdio_mutex);
37387113afc8SEmmanuel Vadot 
37397113afc8SEmmanuel Vadot 	return (ret);
37407113afc8SEmmanuel Vadot }
37417113afc8SEmmanuel Vadot 
37427113afc8SEmmanuel Vadot static void
xgbe_phy_exit(struct xgbe_prv_data * pdata)37437113afc8SEmmanuel Vadot xgbe_phy_exit(struct xgbe_prv_data *pdata)
37447113afc8SEmmanuel Vadot {
37457113afc8SEmmanuel Vadot 	if (pdata->axgbe_miibus != NULL)
37467113afc8SEmmanuel Vadot 		device_delete_child(pdata->dev, pdata->axgbe_miibus);
37477113afc8SEmmanuel Vadot 
37487113afc8SEmmanuel Vadot 	/* free phy_data structure */
37497113afc8SEmmanuel Vadot 	free(pdata->phy_data, M_AXGBE);
37507113afc8SEmmanuel Vadot }
37517113afc8SEmmanuel Vadot 
37527113afc8SEmmanuel Vadot static int
xgbe_phy_init(struct xgbe_prv_data * pdata)37537113afc8SEmmanuel Vadot xgbe_phy_init(struct xgbe_prv_data *pdata)
37547113afc8SEmmanuel Vadot {
37557113afc8SEmmanuel Vadot 	struct xgbe_phy_data *phy_data;
37567113afc8SEmmanuel Vadot 	int ret;
37577113afc8SEmmanuel Vadot 
37587113afc8SEmmanuel Vadot 	/* Initialize the global lock */
37597113afc8SEmmanuel Vadot 	if (!mtx_initialized(&xgbe_phy_comm_lock))
37607113afc8SEmmanuel Vadot 		mtx_init(&xgbe_phy_comm_lock, "xgbe phy common lock", NULL, MTX_DEF);
37617113afc8SEmmanuel Vadot 
37627113afc8SEmmanuel Vadot 	/* Check if enabled */
37637113afc8SEmmanuel Vadot 	if (!xgbe_phy_port_enabled(pdata)) {
37647113afc8SEmmanuel Vadot 		axgbe_error("device is not enabled\n");
37657113afc8SEmmanuel Vadot 		return (-ENODEV);
37667113afc8SEmmanuel Vadot 	}
37677113afc8SEmmanuel Vadot 
37687113afc8SEmmanuel Vadot 	/* Initialize the I2C controller */
37697113afc8SEmmanuel Vadot 	ret = pdata->i2c_if.i2c_init(pdata);
37707113afc8SEmmanuel Vadot 	if (ret)
37717113afc8SEmmanuel Vadot 		return (ret);
37727113afc8SEmmanuel Vadot 
37737113afc8SEmmanuel Vadot 	phy_data = malloc(sizeof(*phy_data), M_AXGBE, M_WAITOK | M_ZERO);
37747113afc8SEmmanuel Vadot 	if (!phy_data)
37757113afc8SEmmanuel Vadot 		return (-ENOMEM);
37767113afc8SEmmanuel Vadot 	pdata->phy_data = phy_data;
37777113afc8SEmmanuel Vadot 
37787113afc8SEmmanuel Vadot 	phy_data->port_mode = XP_GET_BITS(pdata->pp0, XP_PROP_0, PORT_MODE);
37797113afc8SEmmanuel Vadot 	phy_data->port_id = XP_GET_BITS(pdata->pp0, XP_PROP_0, PORT_ID);
37807113afc8SEmmanuel Vadot 	phy_data->port_speeds = XP_GET_BITS(pdata->pp0, XP_PROP_0, PORT_SPEEDS);
37817113afc8SEmmanuel Vadot 	phy_data->conn_type = XP_GET_BITS(pdata->pp0, XP_PROP_0, CONN_TYPE);
37827113afc8SEmmanuel Vadot 	phy_data->mdio_addr = XP_GET_BITS(pdata->pp0, XP_PROP_0, MDIO_ADDR);
37837113afc8SEmmanuel Vadot 
37847113afc8SEmmanuel Vadot 	pdata->mdio_addr = phy_data->mdio_addr;
37857113afc8SEmmanuel Vadot 	DBGPR("port mode=%u\n", phy_data->port_mode);
37867113afc8SEmmanuel Vadot 	DBGPR("port id=%u\n", phy_data->port_id);
37877113afc8SEmmanuel Vadot 	DBGPR("port speeds=%#x\n", phy_data->port_speeds);
37887113afc8SEmmanuel Vadot 	DBGPR("conn type=%u\n", phy_data->conn_type);
37897113afc8SEmmanuel Vadot 	DBGPR("mdio addr=%u\n", phy_data->mdio_addr);
37907113afc8SEmmanuel Vadot 
37917113afc8SEmmanuel Vadot 	phy_data->redrv = XP_GET_BITS(pdata->pp4, XP_PROP_4, REDRV_PRESENT);
37927113afc8SEmmanuel Vadot 	phy_data->redrv_if = XP_GET_BITS(pdata->pp4, XP_PROP_4, REDRV_IF);
37937113afc8SEmmanuel Vadot 	phy_data->redrv_addr = XP_GET_BITS(pdata->pp4, XP_PROP_4, REDRV_ADDR);
37947113afc8SEmmanuel Vadot 	phy_data->redrv_lane = XP_GET_BITS(pdata->pp4, XP_PROP_4, REDRV_LANE);
37957113afc8SEmmanuel Vadot 	phy_data->redrv_model = XP_GET_BITS(pdata->pp4, XP_PROP_4, REDRV_MODEL);
37967113afc8SEmmanuel Vadot 
37977113afc8SEmmanuel Vadot 	if (phy_data->redrv) {
37987113afc8SEmmanuel Vadot 		DBGPR("redrv present\n");
37997113afc8SEmmanuel Vadot 		DBGPR("redrv i/f=%u\n", phy_data->redrv_if);
38007113afc8SEmmanuel Vadot 		DBGPR("redrv addr=%#x\n", phy_data->redrv_addr);
38017113afc8SEmmanuel Vadot 		DBGPR("redrv lane=%u\n", phy_data->redrv_lane);
38027113afc8SEmmanuel Vadot 		DBGPR("redrv model=%u\n", phy_data->redrv_model);
38037113afc8SEmmanuel Vadot 	}
38047113afc8SEmmanuel Vadot 
38057113afc8SEmmanuel Vadot 	DBGPR("%s: redrv addr=%#x redrv i/f=%u\n", __func__,
38067113afc8SEmmanuel Vadot 	    phy_data->redrv_addr, phy_data->redrv_if);
38077113afc8SEmmanuel Vadot 	/* Validate the connection requested */
38087113afc8SEmmanuel Vadot 	if (xgbe_phy_conn_type_mismatch(pdata)) {
38097113afc8SEmmanuel Vadot 		axgbe_error("phy mode/connection mismatch "
38107113afc8SEmmanuel Vadot 		    "(%#x/%#x)\n", phy_data->port_mode, phy_data->conn_type);
38117113afc8SEmmanuel Vadot 		return (-EINVAL);
38127113afc8SEmmanuel Vadot 	}
38137113afc8SEmmanuel Vadot 
38147113afc8SEmmanuel Vadot 	/* Validate the mode requested */
38157113afc8SEmmanuel Vadot 	if (xgbe_phy_port_mode_mismatch(pdata)) {
38167113afc8SEmmanuel Vadot 		axgbe_error("phy mode/speed mismatch "
38177113afc8SEmmanuel Vadot 		    "(%#x/%#x)\n", phy_data->port_mode, phy_data->port_speeds);
38187113afc8SEmmanuel Vadot 		return (-EINVAL);
38197113afc8SEmmanuel Vadot 	}
38207113afc8SEmmanuel Vadot 
38217113afc8SEmmanuel Vadot 	/* Check for and validate MDIO reset support */
38227113afc8SEmmanuel Vadot 	ret = xgbe_phy_mdio_reset_setup(pdata);
38237113afc8SEmmanuel Vadot 	if (ret) {
38247113afc8SEmmanuel Vadot 		axgbe_error("%s, mdio_reset_setup ret %d\n", __func__, ret);
38257113afc8SEmmanuel Vadot 		return (ret);
38267113afc8SEmmanuel Vadot 	}
38277113afc8SEmmanuel Vadot 
38287113afc8SEmmanuel Vadot 	/* Validate the re-driver information */
38297113afc8SEmmanuel Vadot 	if (xgbe_phy_redrv_error(phy_data)) {
38307113afc8SEmmanuel Vadot 		axgbe_error("phy re-driver settings error\n");
38317113afc8SEmmanuel Vadot 		return (-EINVAL);
38327113afc8SEmmanuel Vadot 	}
38337113afc8SEmmanuel Vadot 	pdata->kr_redrv = phy_data->redrv;
38347113afc8SEmmanuel Vadot 
38357113afc8SEmmanuel Vadot 	/* Indicate current mode is unknown */
38367113afc8SEmmanuel Vadot 	phy_data->cur_mode = XGBE_MODE_UNKNOWN;
38377113afc8SEmmanuel Vadot 
38387113afc8SEmmanuel Vadot 	/* Initialize supported features. Current code does not support ethtool */
38397113afc8SEmmanuel Vadot 	XGBE_ZERO_SUP(&pdata->phy);
38407113afc8SEmmanuel Vadot 
38417113afc8SEmmanuel Vadot 	DBGPR("%s: port mode %d\n", __func__, phy_data->port_mode);
38427113afc8SEmmanuel Vadot 	switch (phy_data->port_mode) {
38437113afc8SEmmanuel Vadot 	/* Backplane support */
38447113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_BACKPLANE:
38457113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, Autoneg);
38467113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, Pause);
38477113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, Asym_Pause);
38487113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, Backplane);
38497113afc8SEmmanuel Vadot 		if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) {
38507113afc8SEmmanuel Vadot 			XGBE_SET_SUP(&pdata->phy, 1000baseKX_Full);
38517113afc8SEmmanuel Vadot 			phy_data->start_mode = XGBE_MODE_KX_1000;
38527113afc8SEmmanuel Vadot 		}
38537113afc8SEmmanuel Vadot 		if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000) {
38547113afc8SEmmanuel Vadot 			XGBE_SET_SUP(&pdata->phy, 10000baseKR_Full);
38557113afc8SEmmanuel Vadot 			if (pdata->fec_ability & MDIO_PMA_10GBR_FECABLE_ABLE)
38567113afc8SEmmanuel Vadot 				XGBE_SET_SUP(&pdata->phy, 10000baseR_FEC);
38577113afc8SEmmanuel Vadot 			phy_data->start_mode = XGBE_MODE_KR;
38587113afc8SEmmanuel Vadot 		}
38597113afc8SEmmanuel Vadot 
38607113afc8SEmmanuel Vadot 		phy_data->phydev_mode = XGBE_MDIO_MODE_NONE;
38617113afc8SEmmanuel Vadot 		break;
38627113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_BACKPLANE_2500:
38637113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, Pause);
38647113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, Asym_Pause);
38657113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, Backplane);
38667113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, 2500baseX_Full);
38677113afc8SEmmanuel Vadot 		phy_data->start_mode = XGBE_MODE_KX_2500;
38687113afc8SEmmanuel Vadot 
38697113afc8SEmmanuel Vadot 		phy_data->phydev_mode = XGBE_MDIO_MODE_NONE;
38707113afc8SEmmanuel Vadot 		break;
38717113afc8SEmmanuel Vadot 
38727113afc8SEmmanuel Vadot 	/* MDIO 1GBase-T support */
38737113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_1000BASE_T:
38747113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, Autoneg);
38757113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, Pause);
38767113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, Asym_Pause);
38777113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, TP);
38787113afc8SEmmanuel Vadot 		if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) {
38797113afc8SEmmanuel Vadot 			XGBE_SET_SUP(&pdata->phy, 100baseT_Full);
38807113afc8SEmmanuel Vadot 			phy_data->start_mode = XGBE_MODE_SGMII_100;
38817113afc8SEmmanuel Vadot 		}
38827113afc8SEmmanuel Vadot 		if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) {
38837113afc8SEmmanuel Vadot 			XGBE_SET_SUP(&pdata->phy, 1000baseT_Full);
38847113afc8SEmmanuel Vadot 			phy_data->start_mode = XGBE_MODE_SGMII_1000;
38857113afc8SEmmanuel Vadot 		}
38867113afc8SEmmanuel Vadot 
38877113afc8SEmmanuel Vadot 		phy_data->phydev_mode = XGBE_MDIO_MODE_CL22;
38887113afc8SEmmanuel Vadot 		break;
38897113afc8SEmmanuel Vadot 
38907113afc8SEmmanuel Vadot 	/* MDIO Base-X support */
38917113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_1000BASE_X:
38927113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, Autoneg);
38937113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, Pause);
38947113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, Asym_Pause);
38957113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, FIBRE);
38967113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, 1000baseX_Full);
38977113afc8SEmmanuel Vadot 		phy_data->start_mode = XGBE_MODE_X;
38987113afc8SEmmanuel Vadot 
38997113afc8SEmmanuel Vadot 		phy_data->phydev_mode = XGBE_MDIO_MODE_CL22;
39007113afc8SEmmanuel Vadot 		break;
39017113afc8SEmmanuel Vadot 
39027113afc8SEmmanuel Vadot 	/* MDIO NBase-T support */
39037113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_NBASE_T:
39047113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, Autoneg);
39057113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, Pause);
39067113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, Asym_Pause);
39077113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, TP);
39087113afc8SEmmanuel Vadot 		if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) {
39097113afc8SEmmanuel Vadot 			XGBE_SET_SUP(&pdata->phy, 100baseT_Full);
39107113afc8SEmmanuel Vadot 			phy_data->start_mode = XGBE_MODE_SGMII_100;
39117113afc8SEmmanuel Vadot 		}
39127113afc8SEmmanuel Vadot 		if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) {
39137113afc8SEmmanuel Vadot 			XGBE_SET_SUP(&pdata->phy, 1000baseT_Full);
39147113afc8SEmmanuel Vadot 			phy_data->start_mode = XGBE_MODE_SGMII_1000;
39157113afc8SEmmanuel Vadot 		}
39167113afc8SEmmanuel Vadot 		if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_2500) {
39177113afc8SEmmanuel Vadot 			XGBE_SET_SUP(&pdata->phy, 2500baseT_Full);
39187113afc8SEmmanuel Vadot 			phy_data->start_mode = XGBE_MODE_KX_2500;
39197113afc8SEmmanuel Vadot 		}
39207113afc8SEmmanuel Vadot 
39217113afc8SEmmanuel Vadot 		phy_data->phydev_mode = XGBE_MDIO_MODE_CL45;
39227113afc8SEmmanuel Vadot 		break;
39237113afc8SEmmanuel Vadot 
39247113afc8SEmmanuel Vadot 	/* 10GBase-T support */
39257113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_10GBASE_T:
39267113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, Autoneg);
39277113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, Pause);
39287113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, Asym_Pause);
39297113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, TP);
39307113afc8SEmmanuel Vadot 		if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) {
39317113afc8SEmmanuel Vadot 			XGBE_SET_SUP(&pdata->phy, 100baseT_Full);
39327113afc8SEmmanuel Vadot 			phy_data->start_mode = XGBE_MODE_SGMII_100;
39337113afc8SEmmanuel Vadot 		}
39347113afc8SEmmanuel Vadot 		if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) {
39357113afc8SEmmanuel Vadot 			XGBE_SET_SUP(&pdata->phy, 1000baseT_Full);
39367113afc8SEmmanuel Vadot 			phy_data->start_mode = XGBE_MODE_SGMII_1000;
39377113afc8SEmmanuel Vadot 		}
39387113afc8SEmmanuel Vadot 		if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000) {
39397113afc8SEmmanuel Vadot 			XGBE_SET_SUP(&pdata->phy, 10000baseT_Full);
39407113afc8SEmmanuel Vadot 			phy_data->start_mode = XGBE_MODE_KR;
39417113afc8SEmmanuel Vadot 		}
39427113afc8SEmmanuel Vadot 
39437113afc8SEmmanuel Vadot 		phy_data->phydev_mode = XGBE_MDIO_MODE_CL45;
39447113afc8SEmmanuel Vadot 		break;
39457113afc8SEmmanuel Vadot 
39467113afc8SEmmanuel Vadot 	/* 10GBase-R support */
39477113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_10GBASE_R:
39487113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, Autoneg);
39497113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, Pause);
39507113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, Asym_Pause);
39517113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, FIBRE);
39527113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, 10000baseSR_Full);
39537113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, 10000baseLR_Full);
39547113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, 10000baseLRM_Full);
39557113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, 10000baseER_Full);
39567113afc8SEmmanuel Vadot 		if (pdata->fec_ability & MDIO_PMA_10GBR_FECABLE_ABLE)
39577113afc8SEmmanuel Vadot 			XGBE_SET_SUP(&pdata->phy, 10000baseR_FEC);
39587113afc8SEmmanuel Vadot 		phy_data->start_mode = XGBE_MODE_SFI;
39597113afc8SEmmanuel Vadot 
39607113afc8SEmmanuel Vadot 		phy_data->phydev_mode = XGBE_MDIO_MODE_NONE;
39617113afc8SEmmanuel Vadot 		break;
39627113afc8SEmmanuel Vadot 
39637113afc8SEmmanuel Vadot 	/* SFP support */
39647113afc8SEmmanuel Vadot 	case XGBE_PORT_MODE_SFP:
39657113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, Autoneg);
39667113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, Pause);
39677113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, Asym_Pause);
39687113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, TP);
39697113afc8SEmmanuel Vadot 		XGBE_SET_SUP(&pdata->phy, FIBRE);
39707113afc8SEmmanuel Vadot 		if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100)
39717113afc8SEmmanuel Vadot 			phy_data->start_mode = XGBE_MODE_SGMII_100;
39727113afc8SEmmanuel Vadot 		if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000)
39737113afc8SEmmanuel Vadot 			phy_data->start_mode = XGBE_MODE_SGMII_1000;
39747113afc8SEmmanuel Vadot 		if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000)
39757113afc8SEmmanuel Vadot 			phy_data->start_mode = XGBE_MODE_SFI;
39767113afc8SEmmanuel Vadot 
39777113afc8SEmmanuel Vadot 		phy_data->phydev_mode = XGBE_MDIO_MODE_CL22;
39787113afc8SEmmanuel Vadot 
39797113afc8SEmmanuel Vadot 		xgbe_phy_sfp_setup(pdata);
39807113afc8SEmmanuel Vadot 		DBGPR("%s: start %d mode %d adv 0x%x\n", __func__,
39817113afc8SEmmanuel Vadot 		    phy_data->start_mode, phy_data->phydev_mode,
39827113afc8SEmmanuel Vadot 		    pdata->phy.advertising);
39837113afc8SEmmanuel Vadot 		break;
39847113afc8SEmmanuel Vadot 	default:
39857113afc8SEmmanuel Vadot 		return (-EINVAL);
39867113afc8SEmmanuel Vadot 	}
39877113afc8SEmmanuel Vadot 
39887113afc8SEmmanuel Vadot 	axgbe_printf(2, "%s: start %d mode %d adv 0x%x\n", __func__,
39897113afc8SEmmanuel Vadot 	    phy_data->start_mode, phy_data->phydev_mode, pdata->phy.advertising);
39907113afc8SEmmanuel Vadot 
39917113afc8SEmmanuel Vadot 	DBGPR("%s: conn type %d mode %d\n", __func__,
39927113afc8SEmmanuel Vadot 	    phy_data->conn_type, phy_data->phydev_mode);
39937113afc8SEmmanuel Vadot 	if ((phy_data->conn_type & XGBE_CONN_TYPE_MDIO) &&
39947113afc8SEmmanuel Vadot 	    (phy_data->phydev_mode != XGBE_MDIO_MODE_NONE)) {
39957113afc8SEmmanuel Vadot 		ret = pdata->hw_if.set_ext_mii_mode(pdata, phy_data->mdio_addr,
39967113afc8SEmmanuel Vadot 		    phy_data->phydev_mode);
39977113afc8SEmmanuel Vadot 		if (ret) {
39987113afc8SEmmanuel Vadot 			axgbe_error("mdio port/clause not compatible (%d/%u)\n",
39997113afc8SEmmanuel Vadot 			    phy_data->mdio_addr, phy_data->phydev_mode);
40007113afc8SEmmanuel Vadot 			return (-EINVAL);
40017113afc8SEmmanuel Vadot 		}
40027113afc8SEmmanuel Vadot 	}
40037113afc8SEmmanuel Vadot 
40047113afc8SEmmanuel Vadot 	if (phy_data->redrv && !phy_data->redrv_if) {
40057113afc8SEmmanuel Vadot 		ret = pdata->hw_if.set_ext_mii_mode(pdata, phy_data->redrv_addr,
40067113afc8SEmmanuel Vadot 		    XGBE_MDIO_MODE_CL22);
40077113afc8SEmmanuel Vadot 		if (ret) {
40087113afc8SEmmanuel Vadot 			axgbe_error("redriver mdio port not compatible (%u)\n",
40097113afc8SEmmanuel Vadot 			    phy_data->redrv_addr);
40107113afc8SEmmanuel Vadot 			return (-EINVAL);
40117113afc8SEmmanuel Vadot 		}
40127113afc8SEmmanuel Vadot 	}
40137113afc8SEmmanuel Vadot 
40147113afc8SEmmanuel Vadot 	phy_data->phy_cdr_delay = XGBE_CDR_DELAY_INIT;
40157113afc8SEmmanuel Vadot 
40167113afc8SEmmanuel Vadot 	if (phy_data->port_mode != XGBE_PORT_MODE_SFP) {
40177113afc8SEmmanuel Vadot 		ret = mii_attach(pdata->dev, &pdata->axgbe_miibus, pdata->netdev,
40187113afc8SEmmanuel Vadot 		    (ifm_change_cb_t)axgbe_ifmedia_upd,
40197113afc8SEmmanuel Vadot 		    (ifm_stat_cb_t)axgbe_ifmedia_sts, BMSR_DEFCAPMASK,
40207113afc8SEmmanuel Vadot 		    pdata->mdio_addr, MII_OFFSET_ANY, MIIF_FORCEANEG);
40217113afc8SEmmanuel Vadot 
40227113afc8SEmmanuel Vadot 		if (ret){
40237113afc8SEmmanuel Vadot 			axgbe_printf(2, "mii attach failed with err=(%d)\n", ret);
40247113afc8SEmmanuel Vadot 			return (-EINVAL);
40257113afc8SEmmanuel Vadot 		}
40267113afc8SEmmanuel Vadot 	}
40277113afc8SEmmanuel Vadot 
40287113afc8SEmmanuel Vadot 	DBGPR("%s: return success\n", __func__);
40297113afc8SEmmanuel Vadot 
40307113afc8SEmmanuel Vadot 	return (0);
40317113afc8SEmmanuel Vadot }
40327113afc8SEmmanuel Vadot 
40337113afc8SEmmanuel Vadot void
xgbe_init_function_ptrs_phy_v2(struct xgbe_phy_if * phy_if)40347113afc8SEmmanuel Vadot xgbe_init_function_ptrs_phy_v2(struct xgbe_phy_if *phy_if)
40357113afc8SEmmanuel Vadot {
40367113afc8SEmmanuel Vadot 	struct xgbe_phy_impl_if *phy_impl = &phy_if->phy_impl;
40377113afc8SEmmanuel Vadot 
40387113afc8SEmmanuel Vadot 	phy_impl->init			= xgbe_phy_init;
40397113afc8SEmmanuel Vadot 	phy_impl->exit			= xgbe_phy_exit;
40407113afc8SEmmanuel Vadot 
40417113afc8SEmmanuel Vadot 	phy_impl->reset			= xgbe_phy_reset;
40427113afc8SEmmanuel Vadot 	phy_impl->start			= xgbe_phy_start;
40437113afc8SEmmanuel Vadot 	phy_impl->stop			= xgbe_phy_stop;
40447113afc8SEmmanuel Vadot 
40457113afc8SEmmanuel Vadot 	phy_impl->link_status		= xgbe_phy_link_status;
40467113afc8SEmmanuel Vadot 
40477113afc8SEmmanuel Vadot 	phy_impl->valid_speed		= xgbe_phy_valid_speed;
40487113afc8SEmmanuel Vadot 
40497113afc8SEmmanuel Vadot 	phy_impl->use_mode		= xgbe_phy_use_mode;
40507113afc8SEmmanuel Vadot 	phy_impl->set_mode		= xgbe_phy_set_mode;
40517113afc8SEmmanuel Vadot 	phy_impl->get_mode		= xgbe_phy_get_mode;
40527113afc8SEmmanuel Vadot 	phy_impl->switch_mode		= xgbe_phy_switch_mode;
40537113afc8SEmmanuel Vadot 	phy_impl->cur_mode		= xgbe_phy_cur_mode;
40547113afc8SEmmanuel Vadot 	phy_impl->get_type		= xgbe_phy_get_type;
40557113afc8SEmmanuel Vadot 
40567113afc8SEmmanuel Vadot 	phy_impl->an_mode		= xgbe_phy_an_mode;
40577113afc8SEmmanuel Vadot 
40587113afc8SEmmanuel Vadot 	phy_impl->an_config		= xgbe_phy_an_config;
40597113afc8SEmmanuel Vadot 
40607113afc8SEmmanuel Vadot 	phy_impl->an_advertising	= xgbe_phy_an_advertising;
40617113afc8SEmmanuel Vadot 
40627113afc8SEmmanuel Vadot 	phy_impl->an_outcome		= xgbe_phy_an_outcome;
40637113afc8SEmmanuel Vadot 
40647113afc8SEmmanuel Vadot 	phy_impl->an_pre		= xgbe_phy_an_pre;
40657113afc8SEmmanuel Vadot 	phy_impl->an_post		= xgbe_phy_an_post;
40667113afc8SEmmanuel Vadot 
40677113afc8SEmmanuel Vadot 	phy_impl->kr_training_pre	= xgbe_phy_kr_training_pre;
40687113afc8SEmmanuel Vadot 	phy_impl->kr_training_post	= xgbe_phy_kr_training_post;
40697113afc8SEmmanuel Vadot 
40707113afc8SEmmanuel Vadot 	phy_impl->module_info		= xgbe_phy_module_info;
40717113afc8SEmmanuel Vadot 	phy_impl->module_eeprom		= xgbe_phy_module_eeprom;
40727113afc8SEmmanuel Vadot }
4073