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