xref: /freebsd/sys/dev/axgbe/xgbe-mdio.c (revision 94e3e7d2e8014a981226567e67c82087cc59cca7)
144b781cfSAndrew Turner /*
244b781cfSAndrew Turner  * AMD 10Gb Ethernet driver
344b781cfSAndrew Turner  *
47113afc8SEmmanuel Vadot  * Copyright (c) 2014-2016,2020 Advanced Micro Devices, Inc.
57113afc8SEmmanuel Vadot  *
644b781cfSAndrew Turner  * This file is available to you under your choice of the following two
744b781cfSAndrew Turner  * licenses:
844b781cfSAndrew Turner  *
944b781cfSAndrew Turner  * License 1: GPLv2
1044b781cfSAndrew Turner  *
1144b781cfSAndrew Turner  * This file is free software; you may copy, redistribute and/or modify
1244b781cfSAndrew Turner  * it under the terms of the GNU General Public License as published by
1344b781cfSAndrew Turner  * the Free Software Foundation, either version 2 of the License, or (at
1444b781cfSAndrew Turner  * your option) any later version.
1544b781cfSAndrew Turner  *
1644b781cfSAndrew Turner  * This file is distributed in the hope that it will be useful, but
1744b781cfSAndrew Turner  * WITHOUT ANY WARRANTY; without even the implied warranty of
1844b781cfSAndrew Turner  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1944b781cfSAndrew Turner  * General Public License for more details.
2044b781cfSAndrew Turner  *
2144b781cfSAndrew Turner  * You should have received a copy of the GNU General Public License
2244b781cfSAndrew Turner  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
2344b781cfSAndrew Turner  *
2444b781cfSAndrew Turner  * This file incorporates work covered by the following copyright and
2544b781cfSAndrew Turner  * permission notice:
2644b781cfSAndrew Turner  *     The Synopsys DWC ETHER XGMAC Software Driver and documentation
2744b781cfSAndrew Turner  *     (hereinafter "Software") is an unsupported proprietary work of Synopsys,
2844b781cfSAndrew Turner  *     Inc. unless otherwise expressly agreed to in writing between Synopsys
2944b781cfSAndrew Turner  *     and you.
3044b781cfSAndrew Turner  *
3144b781cfSAndrew Turner  *     The Software IS NOT an item of Licensed Software or Licensed Product
3244b781cfSAndrew Turner  *     under any End User Software License Agreement or Agreement for Licensed
3344b781cfSAndrew Turner  *     Product with Synopsys or any supplement thereto.  Permission is hereby
3444b781cfSAndrew Turner  *     granted, free of charge, to any person obtaining a copy of this software
3544b781cfSAndrew Turner  *     annotated with this license and the Software, to deal in the Software
3644b781cfSAndrew Turner  *     without restriction, including without limitation the rights to use,
3744b781cfSAndrew Turner  *     copy, modify, merge, publish, distribute, sublicense, and/or sell copies
3844b781cfSAndrew Turner  *     of the Software, and to permit persons to whom the Software is furnished
3944b781cfSAndrew Turner  *     to do so, subject to the following conditions:
4044b781cfSAndrew Turner  *
4144b781cfSAndrew Turner  *     The above copyright notice and this permission notice shall be included
4244b781cfSAndrew Turner  *     in all copies or substantial portions of the Software.
4344b781cfSAndrew Turner  *
4444b781cfSAndrew Turner  *     THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
4544b781cfSAndrew Turner  *     BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
4644b781cfSAndrew Turner  *     TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
4744b781cfSAndrew Turner  *     PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS
4844b781cfSAndrew Turner  *     BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
4944b781cfSAndrew Turner  *     CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
5044b781cfSAndrew Turner  *     SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
5144b781cfSAndrew Turner  *     INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
5244b781cfSAndrew Turner  *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
5344b781cfSAndrew Turner  *     ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
5444b781cfSAndrew Turner  *     THE POSSIBILITY OF SUCH DAMAGE.
5544b781cfSAndrew Turner  *
5644b781cfSAndrew Turner  *
5744b781cfSAndrew Turner  * License 2: Modified BSD
5844b781cfSAndrew Turner  *
5944b781cfSAndrew Turner  * Redistribution and use in source and binary forms, with or without
6044b781cfSAndrew Turner  * modification, are permitted provided that the following conditions are met:
6144b781cfSAndrew Turner  *     * Redistributions of source code must retain the above copyright
6244b781cfSAndrew Turner  *       notice, this list of conditions and the following disclaimer.
6344b781cfSAndrew Turner  *     * Redistributions in binary form must reproduce the above copyright
6444b781cfSAndrew Turner  *       notice, this list of conditions and the following disclaimer in the
6544b781cfSAndrew Turner  *       documentation and/or other materials provided with the distribution.
6644b781cfSAndrew Turner  *     * Neither the name of Advanced Micro Devices, Inc. nor the
6744b781cfSAndrew Turner  *       names of its contributors may be used to endorse or promote products
6844b781cfSAndrew Turner  *       derived from this software without specific prior written permission.
6944b781cfSAndrew Turner  *
7044b781cfSAndrew Turner  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
7144b781cfSAndrew Turner  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
7244b781cfSAndrew Turner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
7344b781cfSAndrew Turner  * ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
7444b781cfSAndrew Turner  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
7544b781cfSAndrew Turner  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
7644b781cfSAndrew Turner  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
7744b781cfSAndrew Turner  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
7844b781cfSAndrew Turner  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
7944b781cfSAndrew Turner  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
8044b781cfSAndrew Turner  *
8144b781cfSAndrew Turner  * This file incorporates work covered by the following copyright and
8244b781cfSAndrew Turner  * permission notice:
8344b781cfSAndrew Turner  *     The Synopsys DWC ETHER XGMAC Software Driver and documentation
8444b781cfSAndrew Turner  *     (hereinafter "Software") is an unsupported proprietary work of Synopsys,
8544b781cfSAndrew Turner  *     Inc. unless otherwise expressly agreed to in writing between Synopsys
8644b781cfSAndrew Turner  *     and you.
8744b781cfSAndrew Turner  *
8844b781cfSAndrew Turner  *     The Software IS NOT an item of Licensed Software or Licensed Product
8944b781cfSAndrew Turner  *     under any End User Software License Agreement or Agreement for Licensed
9044b781cfSAndrew Turner  *     Product with Synopsys or any supplement thereto.  Permission is hereby
9144b781cfSAndrew Turner  *     granted, free of charge, to any person obtaining a copy of this software
9244b781cfSAndrew Turner  *     annotated with this license and the Software, to deal in the Software
9344b781cfSAndrew Turner  *     without restriction, including without limitation the rights to use,
9444b781cfSAndrew Turner  *     copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9544b781cfSAndrew Turner  *     of the Software, and to permit persons to whom the Software is furnished
9644b781cfSAndrew Turner  *     to do so, subject to the following conditions:
9744b781cfSAndrew Turner  *
9844b781cfSAndrew Turner  *     The above copyright notice and this permission notice shall be included
9944b781cfSAndrew Turner  *     in all copies or substantial portions of the Software.
10044b781cfSAndrew Turner  *
10144b781cfSAndrew Turner  *     THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
10244b781cfSAndrew Turner  *     BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
10344b781cfSAndrew Turner  *     TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
10444b781cfSAndrew Turner  *     PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS
10544b781cfSAndrew Turner  *     BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
10644b781cfSAndrew Turner  *     CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
10744b781cfSAndrew Turner  *     SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
10844b781cfSAndrew Turner  *     INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
10944b781cfSAndrew Turner  *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
11044b781cfSAndrew Turner  *     ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
11144b781cfSAndrew Turner  *     THE POSSIBILITY OF SUCH DAMAGE.
11244b781cfSAndrew Turner  */
11344b781cfSAndrew Turner 
1149c6d6488SAndrew Turner #include <sys/cdefs.h>
1159c6d6488SAndrew Turner __FBSDID("$FreeBSD$");
1169c6d6488SAndrew Turner 
11744b781cfSAndrew Turner #include "xgbe.h"
11844b781cfSAndrew Turner #include "xgbe-common.h"
11944b781cfSAndrew Turner 
1209c6d6488SAndrew Turner static void xgbe_an_state_machine(struct xgbe_prv_data *pdata);
1219c6d6488SAndrew Turner 
1227113afc8SEmmanuel Vadot static void
1237113afc8SEmmanuel Vadot xgbe_an37_clear_interrupts(struct xgbe_prv_data *pdata)
12444b781cfSAndrew Turner {
1257113afc8SEmmanuel Vadot 	int reg;
12644b781cfSAndrew Turner 
1277113afc8SEmmanuel Vadot 	reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT);
1287113afc8SEmmanuel Vadot 	reg &= ~XGBE_AN_CL37_INT_MASK;
1297113afc8SEmmanuel Vadot 	XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT, reg);
13044b781cfSAndrew Turner }
13144b781cfSAndrew Turner 
1327113afc8SEmmanuel Vadot static void
1337113afc8SEmmanuel Vadot xgbe_an37_disable_interrupts(struct xgbe_prv_data *pdata)
13444b781cfSAndrew Turner {
1357113afc8SEmmanuel Vadot 	int reg;
13644b781cfSAndrew Turner 
1377113afc8SEmmanuel Vadot 	reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL);
1387113afc8SEmmanuel Vadot 	reg &= ~XGBE_AN_CL37_INT_MASK;
1397113afc8SEmmanuel Vadot 	XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL, reg);
14044b781cfSAndrew Turner 
1417113afc8SEmmanuel Vadot 	reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL);
1427113afc8SEmmanuel Vadot 	reg &= ~XGBE_PCS_CL37_BP;
1437113afc8SEmmanuel Vadot 	XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL, reg);
14444b781cfSAndrew Turner }
14544b781cfSAndrew Turner 
1467113afc8SEmmanuel Vadot static void
1477113afc8SEmmanuel Vadot xgbe_an37_enable_interrupts(struct xgbe_prv_data *pdata)
14844b781cfSAndrew Turner {
1497113afc8SEmmanuel Vadot 	int reg;
15044b781cfSAndrew Turner 
1517113afc8SEmmanuel Vadot 	reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL);
1527113afc8SEmmanuel Vadot 	reg |= XGBE_PCS_CL37_BP;
1537113afc8SEmmanuel Vadot 	XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL, reg);
15444b781cfSAndrew Turner 
1557113afc8SEmmanuel Vadot 	reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL);
1567113afc8SEmmanuel Vadot 	reg |= XGBE_AN_CL37_INT_MASK;
1577113afc8SEmmanuel Vadot 	XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL, reg);
15844b781cfSAndrew Turner }
15944b781cfSAndrew Turner 
1607113afc8SEmmanuel Vadot static void
1617113afc8SEmmanuel Vadot xgbe_an73_clear_interrupts(struct xgbe_prv_data *pdata)
16244b781cfSAndrew Turner {
1637113afc8SEmmanuel Vadot 	XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0);
16444b781cfSAndrew Turner }
16544b781cfSAndrew Turner 
1667113afc8SEmmanuel Vadot static void
1677113afc8SEmmanuel Vadot xgbe_an73_disable_interrupts(struct xgbe_prv_data *pdata)
16844b781cfSAndrew Turner {
1697113afc8SEmmanuel Vadot 	XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, 0);
17044b781cfSAndrew Turner }
17144b781cfSAndrew Turner 
1727113afc8SEmmanuel Vadot static void
1737113afc8SEmmanuel Vadot xgbe_an73_enable_interrupts(struct xgbe_prv_data *pdata)
1747113afc8SEmmanuel Vadot {
1757113afc8SEmmanuel Vadot 	XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, XGBE_AN_CL73_INT_MASK);
17644b781cfSAndrew Turner }
17744b781cfSAndrew Turner 
1787113afc8SEmmanuel Vadot static void
1797113afc8SEmmanuel Vadot xgbe_an_enable_interrupts(struct xgbe_prv_data *pdata)
18044b781cfSAndrew Turner {
1817113afc8SEmmanuel Vadot 	switch (pdata->an_mode) {
1827113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL73:
1837113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL73_REDRV:
1847113afc8SEmmanuel Vadot 		xgbe_an73_enable_interrupts(pdata);
1857113afc8SEmmanuel Vadot 		break;
1867113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL37:
1877113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL37_SGMII:
1887113afc8SEmmanuel Vadot 		xgbe_an37_enable_interrupts(pdata);
1897113afc8SEmmanuel Vadot 		break;
1907113afc8SEmmanuel Vadot 	default:
1917113afc8SEmmanuel Vadot 		break;
1927113afc8SEmmanuel Vadot 	}
1937113afc8SEmmanuel Vadot }
19444b781cfSAndrew Turner 
1957113afc8SEmmanuel Vadot static void
1967113afc8SEmmanuel Vadot xgbe_an_clear_interrupts_all(struct xgbe_prv_data *pdata)
1977113afc8SEmmanuel Vadot {
1987113afc8SEmmanuel Vadot 	xgbe_an73_clear_interrupts(pdata);
1997113afc8SEmmanuel Vadot 	xgbe_an37_clear_interrupts(pdata);
2007113afc8SEmmanuel Vadot }
2017113afc8SEmmanuel Vadot 
2027113afc8SEmmanuel Vadot static void
2037113afc8SEmmanuel Vadot xgbe_kr_mode(struct xgbe_prv_data *pdata)
2047113afc8SEmmanuel Vadot {
2057113afc8SEmmanuel Vadot 	/* Set MAC to 10G speed */
2067113afc8SEmmanuel Vadot 	pdata->hw_if.set_speed(pdata, SPEED_10000);
2077113afc8SEmmanuel Vadot 
2087113afc8SEmmanuel Vadot 	/* Call PHY implementation support to complete rate change */
2097113afc8SEmmanuel Vadot 	pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_KR);
2107113afc8SEmmanuel Vadot }
2117113afc8SEmmanuel Vadot 
2127113afc8SEmmanuel Vadot static void
2137113afc8SEmmanuel Vadot xgbe_kx_2500_mode(struct xgbe_prv_data *pdata)
2147113afc8SEmmanuel Vadot {
2157113afc8SEmmanuel Vadot 	/* Set MAC to 2.5G speed */
2167113afc8SEmmanuel Vadot 	pdata->hw_if.set_speed(pdata, SPEED_2500);
2177113afc8SEmmanuel Vadot 
2187113afc8SEmmanuel Vadot 	/* Call PHY implementation support to complete rate change */
2197113afc8SEmmanuel Vadot 	pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_KX_2500);
2207113afc8SEmmanuel Vadot }
2217113afc8SEmmanuel Vadot 
2227113afc8SEmmanuel Vadot static void
2237113afc8SEmmanuel Vadot xgbe_kx_1000_mode(struct xgbe_prv_data *pdata)
2247113afc8SEmmanuel Vadot {
2257113afc8SEmmanuel Vadot 	/* Set MAC to 1G speed */
2267113afc8SEmmanuel Vadot 	pdata->hw_if.set_speed(pdata, SPEED_1000);
2277113afc8SEmmanuel Vadot 
2287113afc8SEmmanuel Vadot 	/* Call PHY implementation support to complete rate change */
2297113afc8SEmmanuel Vadot 	pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_KX_1000);
2307113afc8SEmmanuel Vadot }
2317113afc8SEmmanuel Vadot 
2327113afc8SEmmanuel Vadot static void
2337113afc8SEmmanuel Vadot xgbe_sfi_mode(struct xgbe_prv_data *pdata)
2347113afc8SEmmanuel Vadot {
2357113afc8SEmmanuel Vadot 	/* If a KR re-driver is present, change to KR mode instead */
2367113afc8SEmmanuel Vadot 	if (pdata->kr_redrv)
2377113afc8SEmmanuel Vadot 		return (xgbe_kr_mode(pdata));
23844b781cfSAndrew Turner 
23944b781cfSAndrew Turner 	/* Set MAC to 10G speed */
2407113afc8SEmmanuel Vadot 	pdata->hw_if.set_speed(pdata, SPEED_10000);
24144b781cfSAndrew Turner 
2427113afc8SEmmanuel Vadot 	/* Call PHY implementation support to complete rate change */
2437113afc8SEmmanuel Vadot 	pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_SFI);
24444b781cfSAndrew Turner }
24544b781cfSAndrew Turner 
2467113afc8SEmmanuel Vadot static void
2477113afc8SEmmanuel Vadot xgbe_x_mode(struct xgbe_prv_data *pdata)
24844b781cfSAndrew Turner {
24944b781cfSAndrew Turner 	/* Set MAC to 1G speed */
2507113afc8SEmmanuel Vadot 	pdata->hw_if.set_speed(pdata, SPEED_1000);
25144b781cfSAndrew Turner 
2527113afc8SEmmanuel Vadot 	/* Call PHY implementation support to complete rate change */
2537113afc8SEmmanuel Vadot 	pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_X);
25444b781cfSAndrew Turner }
25544b781cfSAndrew Turner 
2567113afc8SEmmanuel Vadot static void
2577113afc8SEmmanuel Vadot xgbe_sgmii_1000_mode(struct xgbe_prv_data *pdata)
2587113afc8SEmmanuel Vadot {
2597113afc8SEmmanuel Vadot 	/* Set MAC to 1G speed */
2607113afc8SEmmanuel Vadot 	pdata->hw_if.set_speed(pdata, SPEED_1000);
2617113afc8SEmmanuel Vadot 
2627113afc8SEmmanuel Vadot 	/* Call PHY implementation support to complete rate change */
2637113afc8SEmmanuel Vadot 	pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_SGMII_1000);
2647113afc8SEmmanuel Vadot }
2657113afc8SEmmanuel Vadot 
2667113afc8SEmmanuel Vadot static void
2677113afc8SEmmanuel Vadot xgbe_sgmii_100_mode(struct xgbe_prv_data *pdata)
2687113afc8SEmmanuel Vadot {
2697113afc8SEmmanuel Vadot 	/* Set MAC to 1G speed */
2707113afc8SEmmanuel Vadot 	pdata->hw_if.set_speed(pdata, SPEED_1000);
2717113afc8SEmmanuel Vadot 
2727113afc8SEmmanuel Vadot 	/* Call PHY implementation support to complete rate change */
2737113afc8SEmmanuel Vadot 	pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_SGMII_100);
2747113afc8SEmmanuel Vadot }
2757113afc8SEmmanuel Vadot 
2767113afc8SEmmanuel Vadot static enum xgbe_mode
2777113afc8SEmmanuel Vadot xgbe_cur_mode(struct xgbe_prv_data *pdata)
2787113afc8SEmmanuel Vadot {
2797113afc8SEmmanuel Vadot 	return (pdata->phy_if.phy_impl.cur_mode(pdata));
2807113afc8SEmmanuel Vadot }
2817113afc8SEmmanuel Vadot 
2827113afc8SEmmanuel Vadot static bool
2837113afc8SEmmanuel Vadot xgbe_in_kr_mode(struct xgbe_prv_data *pdata)
2847113afc8SEmmanuel Vadot {
2857113afc8SEmmanuel Vadot 	return (xgbe_cur_mode(pdata) == XGBE_MODE_KR);
2867113afc8SEmmanuel Vadot }
2877113afc8SEmmanuel Vadot 
2887113afc8SEmmanuel Vadot static void
2897113afc8SEmmanuel Vadot xgbe_change_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode)
2907113afc8SEmmanuel Vadot {
2917113afc8SEmmanuel Vadot 	switch (mode) {
2927113afc8SEmmanuel Vadot 	case XGBE_MODE_KX_1000:
2937113afc8SEmmanuel Vadot 		xgbe_kx_1000_mode(pdata);
2947113afc8SEmmanuel Vadot 		break;
2957113afc8SEmmanuel Vadot 	case XGBE_MODE_KX_2500:
2967113afc8SEmmanuel Vadot 		xgbe_kx_2500_mode(pdata);
2977113afc8SEmmanuel Vadot 		break;
2987113afc8SEmmanuel Vadot 	case XGBE_MODE_KR:
2997113afc8SEmmanuel Vadot 		xgbe_kr_mode(pdata);
3007113afc8SEmmanuel Vadot 		break;
3017113afc8SEmmanuel Vadot 	case XGBE_MODE_SGMII_100:
3027113afc8SEmmanuel Vadot 		xgbe_sgmii_100_mode(pdata);
3037113afc8SEmmanuel Vadot 		break;
3047113afc8SEmmanuel Vadot 	case XGBE_MODE_SGMII_1000:
3057113afc8SEmmanuel Vadot 		xgbe_sgmii_1000_mode(pdata);
3067113afc8SEmmanuel Vadot 		break;
3077113afc8SEmmanuel Vadot 	case XGBE_MODE_X:
3087113afc8SEmmanuel Vadot 		xgbe_x_mode(pdata);
3097113afc8SEmmanuel Vadot 		break;
3107113afc8SEmmanuel Vadot 	case XGBE_MODE_SFI:
3117113afc8SEmmanuel Vadot 		xgbe_sfi_mode(pdata);
3127113afc8SEmmanuel Vadot 		break;
3137113afc8SEmmanuel Vadot 	case XGBE_MODE_UNKNOWN:
3147113afc8SEmmanuel Vadot 		break;
3157113afc8SEmmanuel Vadot 	default:
3167113afc8SEmmanuel Vadot 		axgbe_error("invalid operation mode requested (%u)\n", mode);
3177113afc8SEmmanuel Vadot 	}
3187113afc8SEmmanuel Vadot }
3197113afc8SEmmanuel Vadot 
3207113afc8SEmmanuel Vadot static void
3217113afc8SEmmanuel Vadot xgbe_switch_mode(struct xgbe_prv_data *pdata)
3227113afc8SEmmanuel Vadot {
3237113afc8SEmmanuel Vadot 	xgbe_change_mode(pdata, pdata->phy_if.phy_impl.switch_mode(pdata));
3247113afc8SEmmanuel Vadot }
3257113afc8SEmmanuel Vadot 
3267113afc8SEmmanuel Vadot static bool
3277113afc8SEmmanuel Vadot xgbe_set_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode)
3287113afc8SEmmanuel Vadot {
3297113afc8SEmmanuel Vadot 	if (mode == xgbe_cur_mode(pdata))
3307113afc8SEmmanuel Vadot 		return (false);
3317113afc8SEmmanuel Vadot 
3327113afc8SEmmanuel Vadot 	xgbe_change_mode(pdata, mode);
3337113afc8SEmmanuel Vadot 
3347113afc8SEmmanuel Vadot 	return (true);
3357113afc8SEmmanuel Vadot }
3367113afc8SEmmanuel Vadot 
3377113afc8SEmmanuel Vadot static bool
3387113afc8SEmmanuel Vadot xgbe_use_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode)
3397113afc8SEmmanuel Vadot {
3407113afc8SEmmanuel Vadot 	return (pdata->phy_if.phy_impl.use_mode(pdata, mode));
3417113afc8SEmmanuel Vadot }
3427113afc8SEmmanuel Vadot 
3437113afc8SEmmanuel Vadot static void
3447113afc8SEmmanuel Vadot xgbe_an37_set(struct xgbe_prv_data *pdata, bool enable, bool restart)
34544b781cfSAndrew Turner {
34644b781cfSAndrew Turner 	unsigned int reg;
34744b781cfSAndrew Turner 
3487113afc8SEmmanuel Vadot 	reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_CTRL1);
3497113afc8SEmmanuel Vadot 	reg &= ~MDIO_VEND2_CTRL1_AN_ENABLE;
3507113afc8SEmmanuel Vadot 
3517113afc8SEmmanuel Vadot 	if (enable)
3527113afc8SEmmanuel Vadot 		reg |= MDIO_VEND2_CTRL1_AN_ENABLE;
3537113afc8SEmmanuel Vadot 
3547113afc8SEmmanuel Vadot 	if (restart)
3557113afc8SEmmanuel Vadot 		reg |= MDIO_VEND2_CTRL1_AN_RESTART;
3567113afc8SEmmanuel Vadot 
3577113afc8SEmmanuel Vadot 	XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_CTRL1, reg);
35844b781cfSAndrew Turner }
35944b781cfSAndrew Turner 
3607113afc8SEmmanuel Vadot static void
3617113afc8SEmmanuel Vadot xgbe_an37_restart(struct xgbe_prv_data *pdata)
36244b781cfSAndrew Turner {
3637113afc8SEmmanuel Vadot 	xgbe_an37_enable_interrupts(pdata);
3647113afc8SEmmanuel Vadot 	xgbe_an37_set(pdata, true, true);
36544b781cfSAndrew Turner }
36644b781cfSAndrew Turner 
3677113afc8SEmmanuel Vadot static void
3687113afc8SEmmanuel Vadot xgbe_an37_disable(struct xgbe_prv_data *pdata)
36944b781cfSAndrew Turner {
3707113afc8SEmmanuel Vadot 	xgbe_an37_set(pdata, false, false);
3717113afc8SEmmanuel Vadot 	xgbe_an37_disable_interrupts(pdata);
37244b781cfSAndrew Turner }
37344b781cfSAndrew Turner 
3747113afc8SEmmanuel Vadot static void
3757113afc8SEmmanuel Vadot xgbe_an73_set(struct xgbe_prv_data *pdata, bool enable, bool restart)
37644b781cfSAndrew Turner {
37744b781cfSAndrew Turner 	unsigned int reg;
37844b781cfSAndrew Turner 
3797113afc8SEmmanuel Vadot 	/* Disable KR training for now */
3807113afc8SEmmanuel Vadot 	reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL);
3817113afc8SEmmanuel Vadot 	reg &= ~XGBE_KR_TRAINING_ENABLE;
3827113afc8SEmmanuel Vadot 	XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, reg);
3837113afc8SEmmanuel Vadot 
3847113afc8SEmmanuel Vadot 	/* Update AN settings */
38544b781cfSAndrew Turner 	reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_CTRL1);
38644b781cfSAndrew Turner 	reg &= ~MDIO_AN_CTRL1_ENABLE;
38744b781cfSAndrew Turner 
38844b781cfSAndrew Turner 	if (enable)
38944b781cfSAndrew Turner 		reg |= MDIO_AN_CTRL1_ENABLE;
39044b781cfSAndrew Turner 
39144b781cfSAndrew Turner 	if (restart)
39244b781cfSAndrew Turner 		reg |= MDIO_AN_CTRL1_RESTART;
39344b781cfSAndrew Turner 
39444b781cfSAndrew Turner 	XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_CTRL1, reg);
39544b781cfSAndrew Turner }
39644b781cfSAndrew Turner 
3977113afc8SEmmanuel Vadot static void
3987113afc8SEmmanuel Vadot xgbe_an73_restart(struct xgbe_prv_data *pdata)
39944b781cfSAndrew Turner {
4007113afc8SEmmanuel Vadot 	xgbe_an73_enable_interrupts(pdata);
4017113afc8SEmmanuel Vadot 	xgbe_an73_set(pdata, true, true);
40244b781cfSAndrew Turner }
40344b781cfSAndrew Turner 
4047113afc8SEmmanuel Vadot static void
4057113afc8SEmmanuel Vadot xgbe_an73_disable(struct xgbe_prv_data *pdata)
40644b781cfSAndrew Turner {
4077113afc8SEmmanuel Vadot 	xgbe_an73_set(pdata, false, false);
4087113afc8SEmmanuel Vadot 	xgbe_an73_disable_interrupts(pdata);
4097113afc8SEmmanuel Vadot 
4107113afc8SEmmanuel Vadot 	pdata->an_start = 0;
41144b781cfSAndrew Turner }
41244b781cfSAndrew Turner 
4137113afc8SEmmanuel Vadot static void
4147113afc8SEmmanuel Vadot xgbe_an_restart(struct xgbe_prv_data *pdata)
4157113afc8SEmmanuel Vadot {
4167113afc8SEmmanuel Vadot 	if (pdata->phy_if.phy_impl.an_pre)
4177113afc8SEmmanuel Vadot 		pdata->phy_if.phy_impl.an_pre(pdata);
4187113afc8SEmmanuel Vadot 
4197113afc8SEmmanuel Vadot 	switch (pdata->an_mode) {
4207113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL73:
4217113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL73_REDRV:
4227113afc8SEmmanuel Vadot 		xgbe_an73_restart(pdata);
4237113afc8SEmmanuel Vadot 		break;
4247113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL37:
4257113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL37_SGMII:
4267113afc8SEmmanuel Vadot 		xgbe_an37_restart(pdata);
4277113afc8SEmmanuel Vadot 		break;
4287113afc8SEmmanuel Vadot 	default:
4297113afc8SEmmanuel Vadot 		break;
4307113afc8SEmmanuel Vadot 	}
4317113afc8SEmmanuel Vadot }
4327113afc8SEmmanuel Vadot 
4337113afc8SEmmanuel Vadot static void
4347113afc8SEmmanuel Vadot xgbe_an_disable(struct xgbe_prv_data *pdata)
4357113afc8SEmmanuel Vadot {
4367113afc8SEmmanuel Vadot 	if (pdata->phy_if.phy_impl.an_post)
4377113afc8SEmmanuel Vadot 		pdata->phy_if.phy_impl.an_post(pdata);
4387113afc8SEmmanuel Vadot 
4397113afc8SEmmanuel Vadot 	switch (pdata->an_mode) {
4407113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL73:
4417113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL73_REDRV:
4427113afc8SEmmanuel Vadot 		xgbe_an73_disable(pdata);
4437113afc8SEmmanuel Vadot 		break;
4447113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL37:
4457113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL37_SGMII:
4467113afc8SEmmanuel Vadot 		xgbe_an37_disable(pdata);
4477113afc8SEmmanuel Vadot 		break;
4487113afc8SEmmanuel Vadot 	default:
4497113afc8SEmmanuel Vadot 		break;
4507113afc8SEmmanuel Vadot 	}
4517113afc8SEmmanuel Vadot }
4527113afc8SEmmanuel Vadot 
4537113afc8SEmmanuel Vadot static void
4547113afc8SEmmanuel Vadot xgbe_an_disable_all(struct xgbe_prv_data *pdata)
4557113afc8SEmmanuel Vadot {
4567113afc8SEmmanuel Vadot 	xgbe_an73_disable(pdata);
4577113afc8SEmmanuel Vadot 	xgbe_an37_disable(pdata);
4587113afc8SEmmanuel Vadot }
4597113afc8SEmmanuel Vadot 
4607113afc8SEmmanuel Vadot static enum xgbe_an
4617113afc8SEmmanuel Vadot xgbe_an73_tx_training(struct xgbe_prv_data *pdata, enum xgbe_rx *state)
46244b781cfSAndrew Turner {
46344b781cfSAndrew Turner 	unsigned int ad_reg, lp_reg, reg;
46444b781cfSAndrew Turner 
46544b781cfSAndrew Turner 	*state = XGBE_RX_COMPLETE;
46644b781cfSAndrew Turner 
46744b781cfSAndrew Turner 	/* If we're not in KR mode then we're done */
46844b781cfSAndrew Turner 	if (!xgbe_in_kr_mode(pdata))
4697113afc8SEmmanuel Vadot 		return (XGBE_AN_PAGE_RECEIVED);
47044b781cfSAndrew Turner 
47144b781cfSAndrew Turner 	/* Enable/Disable FEC */
47244b781cfSAndrew Turner 	ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
47344b781cfSAndrew Turner 	lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2);
47444b781cfSAndrew Turner 
47544b781cfSAndrew Turner 	reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FECCTRL);
47644b781cfSAndrew Turner 	reg &= ~(MDIO_PMA_10GBR_FECABLE_ABLE | MDIO_PMA_10GBR_FECABLE_ERRABLE);
47744b781cfSAndrew Turner 	if ((ad_reg & 0xc000) && (lp_reg & 0xc000))
47844b781cfSAndrew Turner 		reg |= pdata->fec_ability;
47944b781cfSAndrew Turner 
48044b781cfSAndrew Turner 	XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FECCTRL, reg);
48144b781cfSAndrew Turner 
48244b781cfSAndrew Turner 	/* Start KR training */
4837113afc8SEmmanuel Vadot 	if (pdata->phy_if.phy_impl.kr_training_pre)
4847113afc8SEmmanuel Vadot 		pdata->phy_if.phy_impl.kr_training_pre(pdata);
4857113afc8SEmmanuel Vadot 
4867113afc8SEmmanuel Vadot 	/* Start KR training */
48744b781cfSAndrew Turner 	reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL);
4887113afc8SEmmanuel Vadot 	reg |= XGBE_KR_TRAINING_ENABLE;
48944b781cfSAndrew Turner 	reg |= XGBE_KR_TRAINING_START;
4907113afc8SEmmanuel Vadot 	XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, reg);
49144b781cfSAndrew Turner 
4927113afc8SEmmanuel Vadot 	if (pdata->phy_if.phy_impl.kr_training_post)
4937113afc8SEmmanuel Vadot 		pdata->phy_if.phy_impl.kr_training_post(pdata);
4947113afc8SEmmanuel Vadot 
4957113afc8SEmmanuel Vadot 	return (XGBE_AN_PAGE_RECEIVED);
49644b781cfSAndrew Turner }
49744b781cfSAndrew Turner 
4987113afc8SEmmanuel Vadot static enum xgbe_an
4997113afc8SEmmanuel Vadot xgbe_an73_tx_xnp(struct xgbe_prv_data *pdata, enum xgbe_rx *state)
50044b781cfSAndrew Turner {
5017113afc8SEmmanuel Vadot 	uint16_t msg;
50244b781cfSAndrew Turner 
50344b781cfSAndrew Turner 	*state = XGBE_RX_XNP;
50444b781cfSAndrew Turner 
50544b781cfSAndrew Turner 	msg = XGBE_XNP_MCF_NULL_MESSAGE;
50644b781cfSAndrew Turner 	msg |= XGBE_XNP_MP_FORMATTED;
50744b781cfSAndrew Turner 
50844b781cfSAndrew Turner 	XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_XNP + 2, 0);
50944b781cfSAndrew Turner 	XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_XNP + 1, 0);
51044b781cfSAndrew Turner 	XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_XNP, msg);
51144b781cfSAndrew Turner 
5127113afc8SEmmanuel Vadot 	return (XGBE_AN_PAGE_RECEIVED);
51344b781cfSAndrew Turner }
51444b781cfSAndrew Turner 
5157113afc8SEmmanuel Vadot static enum xgbe_an
5167113afc8SEmmanuel Vadot xgbe_an73_rx_bpa(struct xgbe_prv_data *pdata, enum xgbe_rx *state)
51744b781cfSAndrew Turner {
51844b781cfSAndrew Turner 	unsigned int link_support;
51944b781cfSAndrew Turner 	unsigned int reg, ad_reg, lp_reg;
52044b781cfSAndrew Turner 
52144b781cfSAndrew Turner 	/* Read Base Ability register 2 first */
52244b781cfSAndrew Turner 	reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1);
52344b781cfSAndrew Turner 
52444b781cfSAndrew Turner 	/* Check for a supported mode, otherwise restart in a different one */
52544b781cfSAndrew Turner 	link_support = xgbe_in_kr_mode(pdata) ? 0x80 : 0x20;
52644b781cfSAndrew Turner 	if (!(reg & link_support))
5277113afc8SEmmanuel Vadot 		return (XGBE_AN_INCOMPAT_LINK);
52844b781cfSAndrew Turner 
52944b781cfSAndrew Turner 	/* Check Extended Next Page support */
53044b781cfSAndrew Turner 	ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
53144b781cfSAndrew Turner 	lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA);
53244b781cfSAndrew Turner 
5337113afc8SEmmanuel Vadot 	return (((ad_reg & XGBE_XNP_NP_EXCHANGE) ||
53444b781cfSAndrew Turner 		(lp_reg & XGBE_XNP_NP_EXCHANGE))
5357113afc8SEmmanuel Vadot 	       ? xgbe_an73_tx_xnp(pdata, state)
5367113afc8SEmmanuel Vadot 	       : xgbe_an73_tx_training(pdata, state));
53744b781cfSAndrew Turner }
53844b781cfSAndrew Turner 
5397113afc8SEmmanuel Vadot static enum xgbe_an
5407113afc8SEmmanuel Vadot xgbe_an73_rx_xnp(struct xgbe_prv_data *pdata, enum xgbe_rx *state)
54144b781cfSAndrew Turner {
54244b781cfSAndrew Turner 	unsigned int ad_reg, lp_reg;
54344b781cfSAndrew Turner 
54444b781cfSAndrew Turner 	/* Check Extended Next Page support */
54544b781cfSAndrew Turner 	ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_XNP);
54644b781cfSAndrew Turner 	lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPX);
54744b781cfSAndrew Turner 
5487113afc8SEmmanuel Vadot 	return (((ad_reg & XGBE_XNP_NP_EXCHANGE) ||
54944b781cfSAndrew Turner 		(lp_reg & XGBE_XNP_NP_EXCHANGE))
5507113afc8SEmmanuel Vadot 	       ? xgbe_an73_tx_xnp(pdata, state)
5517113afc8SEmmanuel Vadot 	       : xgbe_an73_tx_training(pdata, state));
55244b781cfSAndrew Turner }
55344b781cfSAndrew Turner 
5547113afc8SEmmanuel Vadot static enum xgbe_an
5557113afc8SEmmanuel Vadot xgbe_an73_page_received(struct xgbe_prv_data *pdata)
55644b781cfSAndrew Turner {
55744b781cfSAndrew Turner 	enum xgbe_rx *state;
55844b781cfSAndrew Turner 	unsigned long an_timeout;
55944b781cfSAndrew Turner 	enum xgbe_an ret;
56044b781cfSAndrew Turner 
56144b781cfSAndrew Turner 	if (!pdata->an_start) {
5629c6d6488SAndrew Turner 		pdata->an_start = ticks;
56344b781cfSAndrew Turner 	} else {
56444b781cfSAndrew Turner 		an_timeout = pdata->an_start +
5659c6d6488SAndrew Turner 		    ((uint64_t)XGBE_AN_MS_TIMEOUT * (uint64_t)hz) / 1000ull;
5669c6d6488SAndrew Turner 		if ((int)(ticks - an_timeout) > 0) {
56744b781cfSAndrew Turner 			/* Auto-negotiation timed out, reset state */
56844b781cfSAndrew Turner 			pdata->kr_state = XGBE_RX_BPA;
56944b781cfSAndrew Turner 			pdata->kx_state = XGBE_RX_BPA;
57044b781cfSAndrew Turner 
5719c6d6488SAndrew Turner 			pdata->an_start = ticks;
5727113afc8SEmmanuel Vadot 
5737113afc8SEmmanuel Vadot 			axgbe_printf(2, "CL73 AN timed out, resetting state\n");
57444b781cfSAndrew Turner 		}
57544b781cfSAndrew Turner 	}
57644b781cfSAndrew Turner 
5777113afc8SEmmanuel Vadot 	state = xgbe_in_kr_mode(pdata) ? &pdata->kr_state : &pdata->kx_state;
57844b781cfSAndrew Turner 
57944b781cfSAndrew Turner 	switch (*state) {
58044b781cfSAndrew Turner 	case XGBE_RX_BPA:
5817113afc8SEmmanuel Vadot 		ret = xgbe_an73_rx_bpa(pdata, state);
58244b781cfSAndrew Turner 		break;
58344b781cfSAndrew Turner 
58444b781cfSAndrew Turner 	case XGBE_RX_XNP:
5857113afc8SEmmanuel Vadot 		ret = xgbe_an73_rx_xnp(pdata, state);
58644b781cfSAndrew Turner 		break;
58744b781cfSAndrew Turner 
58844b781cfSAndrew Turner 	default:
58944b781cfSAndrew Turner 		ret = XGBE_AN_ERROR;
59044b781cfSAndrew Turner 	}
59144b781cfSAndrew Turner 
5927113afc8SEmmanuel Vadot 	return (ret);
59344b781cfSAndrew Turner }
59444b781cfSAndrew Turner 
5957113afc8SEmmanuel Vadot static enum xgbe_an
5967113afc8SEmmanuel Vadot xgbe_an73_incompat_link(struct xgbe_prv_data *pdata)
59744b781cfSAndrew Turner {
59844b781cfSAndrew Turner 	/* Be sure we aren't looping trying to negotiate */
59944b781cfSAndrew Turner 	if (xgbe_in_kr_mode(pdata)) {
60044b781cfSAndrew Turner 		pdata->kr_state = XGBE_RX_ERROR;
60144b781cfSAndrew Turner 
6027113afc8SEmmanuel Vadot 		if (!(XGBE_ADV(&pdata->phy, 1000baseKX_Full)) &&
6037113afc8SEmmanuel Vadot 		    !(XGBE_ADV(&pdata->phy, 2500baseX_Full)))
6047113afc8SEmmanuel Vadot 			return (XGBE_AN_NO_LINK);
60544b781cfSAndrew Turner 
60644b781cfSAndrew Turner 		if (pdata->kx_state != XGBE_RX_BPA)
6077113afc8SEmmanuel Vadot 			return (XGBE_AN_NO_LINK);
60844b781cfSAndrew Turner 	} else {
60944b781cfSAndrew Turner 		pdata->kx_state = XGBE_RX_ERROR;
61044b781cfSAndrew Turner 
6117113afc8SEmmanuel Vadot 		if (!(XGBE_ADV(&pdata->phy, 10000baseKR_Full)))
6127113afc8SEmmanuel Vadot 			return (XGBE_AN_NO_LINK);
61344b781cfSAndrew Turner 
61444b781cfSAndrew Turner 		if (pdata->kr_state != XGBE_RX_BPA)
6157113afc8SEmmanuel Vadot 			return (XGBE_AN_NO_LINK);
61644b781cfSAndrew Turner 	}
61744b781cfSAndrew Turner 
6187113afc8SEmmanuel Vadot 	xgbe_an_disable(pdata);
61944b781cfSAndrew Turner 
62044b781cfSAndrew Turner 	xgbe_switch_mode(pdata);
62144b781cfSAndrew Turner 
6227113afc8SEmmanuel Vadot 	xgbe_an_restart(pdata);
62344b781cfSAndrew Turner 
6247113afc8SEmmanuel Vadot 	return (XGBE_AN_INCOMPAT_LINK);
62544b781cfSAndrew Turner }
62644b781cfSAndrew Turner 
6277113afc8SEmmanuel Vadot static void
6287113afc8SEmmanuel Vadot xgbe_an37_isr(struct xgbe_prv_data *pdata)
62944b781cfSAndrew Turner {
6307113afc8SEmmanuel Vadot 	unsigned int reg;
63144b781cfSAndrew Turner 
63244b781cfSAndrew Turner 	/* Disable AN interrupts */
6337113afc8SEmmanuel Vadot 	xgbe_an37_disable_interrupts(pdata);
6347113afc8SEmmanuel Vadot 
6357113afc8SEmmanuel Vadot 	/* Save the interrupt(s) that fired */
6367113afc8SEmmanuel Vadot 	reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT);
6377113afc8SEmmanuel Vadot 	pdata->an_int = reg & XGBE_AN_CL37_INT_MASK;
6387113afc8SEmmanuel Vadot 	pdata->an_status = reg & ~XGBE_AN_CL37_INT_MASK;
6397113afc8SEmmanuel Vadot 
6407113afc8SEmmanuel Vadot 	if (pdata->an_int) {
6417113afc8SEmmanuel Vadot 		/* Clear the interrupt(s) that fired and process them */
6427113afc8SEmmanuel Vadot 		reg &= ~XGBE_AN_CL37_INT_MASK;
6437113afc8SEmmanuel Vadot 		XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT, reg);
6447113afc8SEmmanuel Vadot 
6457113afc8SEmmanuel Vadot 		xgbe_an_state_machine(pdata);
6467113afc8SEmmanuel Vadot 	} else {
6477113afc8SEmmanuel Vadot 		/* Enable AN interrupts */
6487113afc8SEmmanuel Vadot 		xgbe_an37_enable_interrupts(pdata);
6497113afc8SEmmanuel Vadot 
6507113afc8SEmmanuel Vadot 		/* Reissue interrupt if status is not clear */
6517113afc8SEmmanuel Vadot 		if (pdata->vdata->irq_reissue_support)
6527113afc8SEmmanuel Vadot 			XP_IOWRITE(pdata, XP_INT_REISSUE_EN, 1 << 3);
6537113afc8SEmmanuel Vadot 	}
6547113afc8SEmmanuel Vadot }
6557113afc8SEmmanuel Vadot 
6567113afc8SEmmanuel Vadot static void
6577113afc8SEmmanuel Vadot xgbe_an73_isr(struct xgbe_prv_data *pdata)
6587113afc8SEmmanuel Vadot {
6597113afc8SEmmanuel Vadot 	/* Disable AN interrupts */
6607113afc8SEmmanuel Vadot 	xgbe_an73_disable_interrupts(pdata);
66144b781cfSAndrew Turner 
66244b781cfSAndrew Turner 	/* Save the interrupt(s) that fired */
66344b781cfSAndrew Turner 	pdata->an_int = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_INT);
66444b781cfSAndrew Turner 
66544b781cfSAndrew Turner 	if (pdata->an_int) {
66644b781cfSAndrew Turner 		/* Clear the interrupt(s) that fired and process them */
66744b781cfSAndrew Turner 		XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, ~pdata->an_int);
66844b781cfSAndrew Turner 
6699c6d6488SAndrew Turner 		xgbe_an_state_machine(pdata);
67044b781cfSAndrew Turner 	} else {
67144b781cfSAndrew Turner 		/* Enable AN interrupts */
6727113afc8SEmmanuel Vadot 		xgbe_an73_enable_interrupts(pdata);
6737113afc8SEmmanuel Vadot 
6747113afc8SEmmanuel Vadot 		/* Reissue interrupt if status is not clear */
6757113afc8SEmmanuel Vadot 		if (pdata->vdata->irq_reissue_support)
6767113afc8SEmmanuel Vadot 			XP_IOWRITE(pdata, XP_INT_REISSUE_EN, 1 << 3);
67744b781cfSAndrew Turner 	}
67844b781cfSAndrew Turner }
67944b781cfSAndrew Turner 
6807113afc8SEmmanuel Vadot static void
6817113afc8SEmmanuel Vadot xgbe_an_isr_task(unsigned long data)
6827113afc8SEmmanuel Vadot {
6837113afc8SEmmanuel Vadot 	struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)data;
6847113afc8SEmmanuel Vadot 
6857113afc8SEmmanuel Vadot 	axgbe_printf(2, "AN interrupt received\n");
6867113afc8SEmmanuel Vadot 
6877113afc8SEmmanuel Vadot 	switch (pdata->an_mode) {
6887113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL73:
6897113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL73_REDRV:
6907113afc8SEmmanuel Vadot 		xgbe_an73_isr(pdata);
6917113afc8SEmmanuel Vadot 		break;
6927113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL37:
6937113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL37_SGMII:
6947113afc8SEmmanuel Vadot 		xgbe_an37_isr(pdata);
6957113afc8SEmmanuel Vadot 		break;
6967113afc8SEmmanuel Vadot 	default:
6977113afc8SEmmanuel Vadot 		break;
6987113afc8SEmmanuel Vadot 	}
6997113afc8SEmmanuel Vadot }
7007113afc8SEmmanuel Vadot 
7017113afc8SEmmanuel Vadot static void
7027113afc8SEmmanuel Vadot xgbe_an_combined_isr(struct xgbe_prv_data *pdata)
7037113afc8SEmmanuel Vadot {
7047113afc8SEmmanuel Vadot 	xgbe_an_isr_task((unsigned long)pdata);
7057113afc8SEmmanuel Vadot }
7067113afc8SEmmanuel Vadot 
7077113afc8SEmmanuel Vadot static const char *
7087113afc8SEmmanuel Vadot xgbe_state_as_string(enum xgbe_an state)
7097113afc8SEmmanuel Vadot {
7107113afc8SEmmanuel Vadot 	switch (state) {
7117113afc8SEmmanuel Vadot 	case XGBE_AN_READY:
7127113afc8SEmmanuel Vadot 		return ("Ready");
7137113afc8SEmmanuel Vadot 	case XGBE_AN_PAGE_RECEIVED:
7147113afc8SEmmanuel Vadot 		return ("Page-Received");
7157113afc8SEmmanuel Vadot 	case XGBE_AN_INCOMPAT_LINK:
7167113afc8SEmmanuel Vadot 		return ("Incompatible-Link");
7177113afc8SEmmanuel Vadot 	case XGBE_AN_COMPLETE:
7187113afc8SEmmanuel Vadot 		return ("Complete");
7197113afc8SEmmanuel Vadot 	case XGBE_AN_NO_LINK:
7207113afc8SEmmanuel Vadot 		return ("No-Link");
7217113afc8SEmmanuel Vadot 	case XGBE_AN_ERROR:
7227113afc8SEmmanuel Vadot 		return ("Error");
7237113afc8SEmmanuel Vadot 	default:
7247113afc8SEmmanuel Vadot 		return ("Undefined");
7257113afc8SEmmanuel Vadot 	}
7267113afc8SEmmanuel Vadot }
7277113afc8SEmmanuel Vadot 
7287113afc8SEmmanuel Vadot static void
7297113afc8SEmmanuel Vadot xgbe_an37_state_machine(struct xgbe_prv_data *pdata)
73044b781cfSAndrew Turner {
73144b781cfSAndrew Turner 	enum xgbe_an cur_state = pdata->an_state;
73244b781cfSAndrew Turner 
7337113afc8SEmmanuel Vadot 	if (!pdata->an_int)
7347113afc8SEmmanuel Vadot 		return;
7357113afc8SEmmanuel Vadot 
7367113afc8SEmmanuel Vadot 	if (pdata->an_int & XGBE_AN_CL37_INT_CMPLT) {
7377113afc8SEmmanuel Vadot 		pdata->an_state = XGBE_AN_COMPLETE;
7387113afc8SEmmanuel Vadot 		pdata->an_int &= ~XGBE_AN_CL37_INT_CMPLT;
7397113afc8SEmmanuel Vadot 
7407113afc8SEmmanuel Vadot 		/* If SGMII is enabled, check the link status */
7417113afc8SEmmanuel Vadot 		if ((pdata->an_mode == XGBE_AN_MODE_CL37_SGMII) &&
7427113afc8SEmmanuel Vadot 		    !(pdata->an_status & XGBE_SGMII_AN_LINK_STATUS))
7437113afc8SEmmanuel Vadot 			pdata->an_state = XGBE_AN_NO_LINK;
7447113afc8SEmmanuel Vadot 	}
7457113afc8SEmmanuel Vadot 
7467113afc8SEmmanuel Vadot 	axgbe_printf(2, "%s: CL37 AN %s\n", __func__,
7477113afc8SEmmanuel Vadot 	    xgbe_state_as_string(pdata->an_state));
7487113afc8SEmmanuel Vadot 
7497113afc8SEmmanuel Vadot 	cur_state = pdata->an_state;
7507113afc8SEmmanuel Vadot 
7517113afc8SEmmanuel Vadot 	switch (pdata->an_state) {
7527113afc8SEmmanuel Vadot 	case XGBE_AN_READY:
7537113afc8SEmmanuel Vadot 		break;
7547113afc8SEmmanuel Vadot 
7557113afc8SEmmanuel Vadot 	case XGBE_AN_COMPLETE:
7567113afc8SEmmanuel Vadot 		axgbe_printf(2, "Auto negotiation successful\n");
7577113afc8SEmmanuel Vadot 		break;
7587113afc8SEmmanuel Vadot 
7597113afc8SEmmanuel Vadot 	case XGBE_AN_NO_LINK:
7607113afc8SEmmanuel Vadot 		break;
7617113afc8SEmmanuel Vadot 
7627113afc8SEmmanuel Vadot 	default:
7637113afc8SEmmanuel Vadot 		pdata->an_state = XGBE_AN_ERROR;
7647113afc8SEmmanuel Vadot 	}
7657113afc8SEmmanuel Vadot 
7667113afc8SEmmanuel Vadot 	if (pdata->an_state == XGBE_AN_ERROR) {
7677113afc8SEmmanuel Vadot 		axgbe_printf(2, "error during auto-negotiation, state=%u\n",
7687113afc8SEmmanuel Vadot 		    cur_state);
7697113afc8SEmmanuel Vadot 
7707113afc8SEmmanuel Vadot 		pdata->an_int = 0;
7717113afc8SEmmanuel Vadot 		xgbe_an37_clear_interrupts(pdata);
7727113afc8SEmmanuel Vadot 	}
7737113afc8SEmmanuel Vadot 
7747113afc8SEmmanuel Vadot 	if (pdata->an_state >= XGBE_AN_COMPLETE) {
7757113afc8SEmmanuel Vadot 		pdata->an_result = pdata->an_state;
7767113afc8SEmmanuel Vadot 		pdata->an_state = XGBE_AN_READY;
7777113afc8SEmmanuel Vadot 
7787113afc8SEmmanuel Vadot 		if (pdata->phy_if.phy_impl.an_post)
7797113afc8SEmmanuel Vadot 			pdata->phy_if.phy_impl.an_post(pdata);
7807113afc8SEmmanuel Vadot 
7817113afc8SEmmanuel Vadot 		axgbe_printf(2, "CL37 AN result: %s\n",
7827113afc8SEmmanuel Vadot 		    xgbe_state_as_string(pdata->an_result));
7837113afc8SEmmanuel Vadot 	}
7847113afc8SEmmanuel Vadot 
7857113afc8SEmmanuel Vadot 	axgbe_printf(2, "%s: an_state %d an_int %d an_mode %d an_status %d\n",
7867113afc8SEmmanuel Vadot 	     __func__, pdata->an_state, pdata->an_int, pdata->an_mode,
7877113afc8SEmmanuel Vadot 	     pdata->an_status);
7887113afc8SEmmanuel Vadot 
7897113afc8SEmmanuel Vadot 	xgbe_an37_enable_interrupts(pdata);
7907113afc8SEmmanuel Vadot }
7917113afc8SEmmanuel Vadot 
7927113afc8SEmmanuel Vadot static void
7937113afc8SEmmanuel Vadot xgbe_an73_state_machine(struct xgbe_prv_data *pdata)
7947113afc8SEmmanuel Vadot {
7957113afc8SEmmanuel Vadot 	enum xgbe_an cur_state = pdata->an_state;
79644b781cfSAndrew Turner 
79744b781cfSAndrew Turner 	if (!pdata->an_int)
79844b781cfSAndrew Turner 		goto out;
79944b781cfSAndrew Turner 
80044b781cfSAndrew Turner next_int:
8017113afc8SEmmanuel Vadot 	if (pdata->an_int & XGBE_AN_CL73_PG_RCV) {
80244b781cfSAndrew Turner 		pdata->an_state = XGBE_AN_PAGE_RECEIVED;
8037113afc8SEmmanuel Vadot 		pdata->an_int &= ~XGBE_AN_CL73_PG_RCV;
8047113afc8SEmmanuel Vadot 	} else if (pdata->an_int & XGBE_AN_CL73_INC_LINK) {
80544b781cfSAndrew Turner 		pdata->an_state = XGBE_AN_INCOMPAT_LINK;
8067113afc8SEmmanuel Vadot 		pdata->an_int &= ~XGBE_AN_CL73_INC_LINK;
8077113afc8SEmmanuel Vadot 	} else if (pdata->an_int & XGBE_AN_CL73_INT_CMPLT) {
80844b781cfSAndrew Turner 		pdata->an_state = XGBE_AN_COMPLETE;
8097113afc8SEmmanuel Vadot 		pdata->an_int &= ~XGBE_AN_CL73_INT_CMPLT;
81044b781cfSAndrew Turner 	} else {
81144b781cfSAndrew Turner 		pdata->an_state = XGBE_AN_ERROR;
81244b781cfSAndrew Turner 	}
81344b781cfSAndrew Turner 
81444b781cfSAndrew Turner again:
8157113afc8SEmmanuel Vadot 	axgbe_printf(2, "CL73 AN %s\n",
8167113afc8SEmmanuel Vadot 	    xgbe_state_as_string(pdata->an_state));
8177113afc8SEmmanuel Vadot 
81844b781cfSAndrew Turner 	cur_state = pdata->an_state;
81944b781cfSAndrew Turner 
82044b781cfSAndrew Turner 	switch (pdata->an_state) {
82144b781cfSAndrew Turner 	case XGBE_AN_READY:
82244b781cfSAndrew Turner 		pdata->an_supported = 0;
82344b781cfSAndrew Turner 		break;
82444b781cfSAndrew Turner 
82544b781cfSAndrew Turner 	case XGBE_AN_PAGE_RECEIVED:
8267113afc8SEmmanuel Vadot 		pdata->an_state = xgbe_an73_page_received(pdata);
82744b781cfSAndrew Turner 		pdata->an_supported++;
82844b781cfSAndrew Turner 		break;
82944b781cfSAndrew Turner 
83044b781cfSAndrew Turner 	case XGBE_AN_INCOMPAT_LINK:
83144b781cfSAndrew Turner 		pdata->an_supported = 0;
83244b781cfSAndrew Turner 		pdata->parallel_detect = 0;
8337113afc8SEmmanuel Vadot 		pdata->an_state = xgbe_an73_incompat_link(pdata);
83444b781cfSAndrew Turner 		break;
83544b781cfSAndrew Turner 
83644b781cfSAndrew Turner 	case XGBE_AN_COMPLETE:
83744b781cfSAndrew Turner 		pdata->parallel_detect = pdata->an_supported ? 0 : 1;
8387113afc8SEmmanuel Vadot 		axgbe_printf(2, "%s successful\n",
8397113afc8SEmmanuel Vadot 		    pdata->an_supported ? "Auto negotiation"
8407113afc8SEmmanuel Vadot 		    : "Parallel detection");
84144b781cfSAndrew Turner 		break;
84244b781cfSAndrew Turner 
84344b781cfSAndrew Turner 	case XGBE_AN_NO_LINK:
84444b781cfSAndrew Turner 		break;
84544b781cfSAndrew Turner 
84644b781cfSAndrew Turner 	default:
84744b781cfSAndrew Turner 		pdata->an_state = XGBE_AN_ERROR;
84844b781cfSAndrew Turner 	}
84944b781cfSAndrew Turner 
85044b781cfSAndrew Turner 	if (pdata->an_state == XGBE_AN_NO_LINK) {
85144b781cfSAndrew Turner 		pdata->an_int = 0;
8527113afc8SEmmanuel Vadot 		xgbe_an73_clear_interrupts(pdata);
85344b781cfSAndrew Turner 	} else if (pdata->an_state == XGBE_AN_ERROR) {
8547113afc8SEmmanuel Vadot 		axgbe_printf(2,
8557113afc8SEmmanuel Vadot 		    "error during auto-negotiation, state=%u\n",
8567113afc8SEmmanuel Vadot 		    cur_state);
8577113afc8SEmmanuel Vadot 
85844b781cfSAndrew Turner 		pdata->an_int = 0;
8597113afc8SEmmanuel Vadot 		xgbe_an73_clear_interrupts(pdata);
86044b781cfSAndrew Turner 	}
86144b781cfSAndrew Turner 
86244b781cfSAndrew Turner 	if (pdata->an_state >= XGBE_AN_COMPLETE) {
86344b781cfSAndrew Turner 		pdata->an_result = pdata->an_state;
86444b781cfSAndrew Turner 		pdata->an_state = XGBE_AN_READY;
86544b781cfSAndrew Turner 		pdata->kr_state = XGBE_RX_BPA;
86644b781cfSAndrew Turner 		pdata->kx_state = XGBE_RX_BPA;
86744b781cfSAndrew Turner 		pdata->an_start = 0;
8687113afc8SEmmanuel Vadot 
8697113afc8SEmmanuel Vadot 		if (pdata->phy_if.phy_impl.an_post)
8707113afc8SEmmanuel Vadot 			pdata->phy_if.phy_impl.an_post(pdata);
8717113afc8SEmmanuel Vadot 
8727113afc8SEmmanuel Vadot 		axgbe_printf(2,  "CL73 AN result: %s\n",
8737113afc8SEmmanuel Vadot 		    xgbe_state_as_string(pdata->an_result));
87444b781cfSAndrew Turner 	}
87544b781cfSAndrew Turner 
87644b781cfSAndrew Turner 	if (cur_state != pdata->an_state)
87744b781cfSAndrew Turner 		goto again;
87844b781cfSAndrew Turner 
87944b781cfSAndrew Turner 	if (pdata->an_int)
88044b781cfSAndrew Turner 		goto next_int;
88144b781cfSAndrew Turner 
88244b781cfSAndrew Turner out:
88344b781cfSAndrew Turner 	/* Enable AN interrupts on the way out */
8847113afc8SEmmanuel Vadot 	xgbe_an73_enable_interrupts(pdata);
8857113afc8SEmmanuel Vadot }
8867113afc8SEmmanuel Vadot 
8877113afc8SEmmanuel Vadot static void
8887113afc8SEmmanuel Vadot xgbe_an_state_machine(struct xgbe_prv_data *pdata)
8897113afc8SEmmanuel Vadot {
8907113afc8SEmmanuel Vadot 	sx_xlock(&pdata->an_mutex);
8917113afc8SEmmanuel Vadot 
8927113afc8SEmmanuel Vadot 	switch (pdata->an_mode) {
8937113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL73:
8947113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL73_REDRV:
8957113afc8SEmmanuel Vadot 		xgbe_an73_state_machine(pdata);
8967113afc8SEmmanuel Vadot 		break;
8977113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL37:
8987113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL37_SGMII:
8997113afc8SEmmanuel Vadot 		xgbe_an37_state_machine(pdata);
9007113afc8SEmmanuel Vadot 		break;
9017113afc8SEmmanuel Vadot 	default:
9027113afc8SEmmanuel Vadot 		break;
9037113afc8SEmmanuel Vadot 	}
9047113afc8SEmmanuel Vadot 
9057113afc8SEmmanuel Vadot 	/* Reissue interrupt if status is not clear */
9067113afc8SEmmanuel Vadot 	if (pdata->vdata->irq_reissue_support)
9077113afc8SEmmanuel Vadot 		XP_IOWRITE(pdata, XP_INT_REISSUE_EN, 1 << 3);
90844b781cfSAndrew Turner 
9099c6d6488SAndrew Turner 	sx_xunlock(&pdata->an_mutex);
91044b781cfSAndrew Turner }
91144b781cfSAndrew Turner 
9127113afc8SEmmanuel Vadot static void
9137113afc8SEmmanuel Vadot xgbe_an37_init(struct xgbe_prv_data *pdata)
91444b781cfSAndrew Turner {
9157113afc8SEmmanuel Vadot 	struct xgbe_phy local_phy;
91644b781cfSAndrew Turner 	unsigned int reg;
91744b781cfSAndrew Turner 
9187113afc8SEmmanuel Vadot 	pdata->phy_if.phy_impl.an_advertising(pdata, &local_phy);
9197113afc8SEmmanuel Vadot 
9207113afc8SEmmanuel Vadot 	axgbe_printf(2, "%s: advertising 0x%x\n", __func__, local_phy.advertising);
9217113afc8SEmmanuel Vadot 
9227113afc8SEmmanuel Vadot 	/* Set up Advertisement register */
9237113afc8SEmmanuel Vadot 	reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_ADVERTISE);
9247113afc8SEmmanuel Vadot 	if (XGBE_ADV(&local_phy, Pause))
9257113afc8SEmmanuel Vadot 		reg |= 0x100;
9267113afc8SEmmanuel Vadot 	else
9277113afc8SEmmanuel Vadot 		reg &= ~0x100;
9287113afc8SEmmanuel Vadot 
9297113afc8SEmmanuel Vadot 	if (XGBE_ADV(&local_phy, Asym_Pause))
9307113afc8SEmmanuel Vadot 		reg |= 0x80;
9317113afc8SEmmanuel Vadot 	else
9327113afc8SEmmanuel Vadot 		reg &= ~0x80;
9337113afc8SEmmanuel Vadot 
9347113afc8SEmmanuel Vadot 	/* Full duplex, but not half */
9357113afc8SEmmanuel Vadot 	reg |= XGBE_AN_CL37_FD_MASK;
9367113afc8SEmmanuel Vadot 	reg &= ~XGBE_AN_CL37_HD_MASK;
9377113afc8SEmmanuel Vadot 
9387113afc8SEmmanuel Vadot 	axgbe_printf(2, "%s: Writing reg: 0x%x\n", __func__, reg);
9397113afc8SEmmanuel Vadot 	XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_ADVERTISE, reg);
9407113afc8SEmmanuel Vadot 
9417113afc8SEmmanuel Vadot 	/* Set up the Control register */
9427113afc8SEmmanuel Vadot 	reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL);
9437113afc8SEmmanuel Vadot 	axgbe_printf(2, "%s: AN_ADVERTISE reg 0x%x an_mode %d\n", __func__,
9447113afc8SEmmanuel Vadot 	    reg, pdata->an_mode);
9457113afc8SEmmanuel Vadot 	reg &= ~XGBE_AN_CL37_TX_CONFIG_MASK;
9467113afc8SEmmanuel Vadot 	reg &= ~XGBE_AN_CL37_PCS_MODE_MASK;
9477113afc8SEmmanuel Vadot 
9487113afc8SEmmanuel Vadot 	switch (pdata->an_mode) {
9497113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL37:
9507113afc8SEmmanuel Vadot 		reg |= XGBE_AN_CL37_PCS_MODE_BASEX;
9517113afc8SEmmanuel Vadot 		break;
9527113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL37_SGMII:
9537113afc8SEmmanuel Vadot 		reg |= XGBE_AN_CL37_PCS_MODE_SGMII;
9547113afc8SEmmanuel Vadot 		break;
9557113afc8SEmmanuel Vadot 	default:
9567113afc8SEmmanuel Vadot 		break;
9577113afc8SEmmanuel Vadot 	}
9587113afc8SEmmanuel Vadot 
9597113afc8SEmmanuel Vadot 	reg |= XGBE_AN_CL37_MII_CTRL_8BIT;
9607113afc8SEmmanuel Vadot 	axgbe_printf(2, "%s: Writing reg: 0x%x\n", __func__, reg);
9617113afc8SEmmanuel Vadot 	XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL, reg);
9627113afc8SEmmanuel Vadot 
9637113afc8SEmmanuel Vadot 	axgbe_printf(2, "CL37 AN (%s) initialized\n",
9647113afc8SEmmanuel Vadot 	    (pdata->an_mode == XGBE_AN_MODE_CL37) ? "BaseX" : "SGMII");
9657113afc8SEmmanuel Vadot }
9667113afc8SEmmanuel Vadot 
9677113afc8SEmmanuel Vadot static void
9687113afc8SEmmanuel Vadot xgbe_an73_init(struct xgbe_prv_data *pdata)
9697113afc8SEmmanuel Vadot {
9707113afc8SEmmanuel Vadot 	/*
9717113afc8SEmmanuel Vadot 	 * This local_phy is needed because phy-v2 alters the
9727113afc8SEmmanuel Vadot 	 * advertising flag variable. so phy-v1 an_advertising is just copying
9737113afc8SEmmanuel Vadot 	 */
9747113afc8SEmmanuel Vadot 	struct xgbe_phy local_phy;
9757113afc8SEmmanuel Vadot 	unsigned int reg;
9767113afc8SEmmanuel Vadot 
9777113afc8SEmmanuel Vadot 	pdata->phy_if.phy_impl.an_advertising(pdata, &local_phy);
9787113afc8SEmmanuel Vadot 
97944b781cfSAndrew Turner 	/* Set up Advertisement register 3 first */
98044b781cfSAndrew Turner 	reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
9817113afc8SEmmanuel Vadot 	if (XGBE_ADV(&local_phy, 10000baseR_FEC))
9827113afc8SEmmanuel Vadot 		reg |= 0xc000;
9837113afc8SEmmanuel Vadot 	else
98444b781cfSAndrew Turner 		reg &= ~0xc000;
98544b781cfSAndrew Turner 
98644b781cfSAndrew Turner 	XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2, reg);
98744b781cfSAndrew Turner 
98844b781cfSAndrew Turner 	/* Set up Advertisement register 2 next */
98944b781cfSAndrew Turner 	reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1);
9907113afc8SEmmanuel Vadot 	if (XGBE_ADV(&local_phy, 10000baseKR_Full))
99144b781cfSAndrew Turner 		reg |= 0x80;
99244b781cfSAndrew Turner 	else
99344b781cfSAndrew Turner 		reg &= ~0x80;
99444b781cfSAndrew Turner 
9957113afc8SEmmanuel Vadot 	if (XGBE_ADV(&local_phy, 1000baseKX_Full) ||
9967113afc8SEmmanuel Vadot 	    XGBE_ADV(&local_phy, 2500baseX_Full))
99744b781cfSAndrew Turner 		reg |= 0x20;
99844b781cfSAndrew Turner 	else
99944b781cfSAndrew Turner 		reg &= ~0x20;
100044b781cfSAndrew Turner 
100144b781cfSAndrew Turner 	XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1, reg);
100244b781cfSAndrew Turner 
100344b781cfSAndrew Turner 	/* Set up Advertisement register 1 last */
100444b781cfSAndrew Turner 	reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
10057113afc8SEmmanuel Vadot 	if (XGBE_ADV(&local_phy, Pause))
100644b781cfSAndrew Turner 		reg |= 0x400;
100744b781cfSAndrew Turner 	else
100844b781cfSAndrew Turner 		reg &= ~0x400;
100944b781cfSAndrew Turner 
10107113afc8SEmmanuel Vadot 	if (XGBE_ADV(&local_phy, Asym_Pause))
101144b781cfSAndrew Turner 		reg |= 0x800;
101244b781cfSAndrew Turner 	else
101344b781cfSAndrew Turner 		reg &= ~0x800;
101444b781cfSAndrew Turner 
101544b781cfSAndrew Turner 	/* We don't intend to perform XNP */
101644b781cfSAndrew Turner 	reg &= ~XGBE_XNP_NP_EXCHANGE;
101744b781cfSAndrew Turner 
101844b781cfSAndrew Turner 	XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg);
10197113afc8SEmmanuel Vadot 
10207113afc8SEmmanuel Vadot 	axgbe_printf(2, "CL73 AN initialized\n");
102144b781cfSAndrew Turner }
102244b781cfSAndrew Turner 
10237113afc8SEmmanuel Vadot static void
10247113afc8SEmmanuel Vadot xgbe_an_init(struct xgbe_prv_data *pdata)
102544b781cfSAndrew Turner {
10267113afc8SEmmanuel Vadot 	/* Set up advertisement registers based on current settings */
10277113afc8SEmmanuel Vadot 	pdata->an_mode = pdata->phy_if.phy_impl.an_mode(pdata);
10287113afc8SEmmanuel Vadot 	axgbe_printf(2, "%s: setting up an_mode %d\n", __func__, pdata->an_mode);
10297113afc8SEmmanuel Vadot 
10307113afc8SEmmanuel Vadot 	switch (pdata->an_mode) {
10317113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL73:
10327113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL73_REDRV:
10337113afc8SEmmanuel Vadot 		xgbe_an73_init(pdata);
10347113afc8SEmmanuel Vadot 		break;
10357113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL37:
10367113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL37_SGMII:
10377113afc8SEmmanuel Vadot 		xgbe_an37_init(pdata);
10387113afc8SEmmanuel Vadot 		break;
10397113afc8SEmmanuel Vadot 	default:
10407113afc8SEmmanuel Vadot 		break;
10417113afc8SEmmanuel Vadot 	}
10427113afc8SEmmanuel Vadot }
10437113afc8SEmmanuel Vadot 
10447113afc8SEmmanuel Vadot static const char *
10457113afc8SEmmanuel Vadot xgbe_phy_fc_string(struct xgbe_prv_data *pdata)
10467113afc8SEmmanuel Vadot {
10477113afc8SEmmanuel Vadot 	if (pdata->tx_pause && pdata->rx_pause)
10487113afc8SEmmanuel Vadot 		return ("rx/tx");
10497113afc8SEmmanuel Vadot 	else if (pdata->rx_pause)
10507113afc8SEmmanuel Vadot 		return ("rx");
10517113afc8SEmmanuel Vadot 	else if (pdata->tx_pause)
10527113afc8SEmmanuel Vadot 		return ("tx");
10537113afc8SEmmanuel Vadot 	else
10547113afc8SEmmanuel Vadot 		return ("off");
10557113afc8SEmmanuel Vadot }
10567113afc8SEmmanuel Vadot 
10577113afc8SEmmanuel Vadot static const char *
10587113afc8SEmmanuel Vadot xgbe_phy_speed_string(int speed)
10597113afc8SEmmanuel Vadot {
10607113afc8SEmmanuel Vadot 	switch (speed) {
10617113afc8SEmmanuel Vadot 	case SPEED_100:
10627113afc8SEmmanuel Vadot 		return ("100Mbps");
10637113afc8SEmmanuel Vadot 	case SPEED_1000:
10647113afc8SEmmanuel Vadot 		return ("1Gbps");
10657113afc8SEmmanuel Vadot 	case SPEED_2500:
10667113afc8SEmmanuel Vadot 		return ("2.5Gbps");
10677113afc8SEmmanuel Vadot 	case SPEED_10000:
10687113afc8SEmmanuel Vadot 		return ("10Gbps");
10697113afc8SEmmanuel Vadot 	case SPEED_UNKNOWN:
10707113afc8SEmmanuel Vadot 		return ("Unknown");
10717113afc8SEmmanuel Vadot 	default:
10727113afc8SEmmanuel Vadot 		return ("Unsupported");
10737113afc8SEmmanuel Vadot 	}
10747113afc8SEmmanuel Vadot }
10757113afc8SEmmanuel Vadot 
10767113afc8SEmmanuel Vadot static void
10777113afc8SEmmanuel Vadot xgbe_phy_print_status(struct xgbe_prv_data *pdata)
10787113afc8SEmmanuel Vadot {
10797113afc8SEmmanuel Vadot 	if (pdata->phy.link)
10807113afc8SEmmanuel Vadot 		axgbe_printf(0,
10817113afc8SEmmanuel Vadot 		    "Link is UP - %s/%s - flow control %s\n",
10827113afc8SEmmanuel Vadot 		    xgbe_phy_speed_string(pdata->phy.speed),
10837113afc8SEmmanuel Vadot 		    pdata->phy.duplex == DUPLEX_FULL ? "Full" : "Half",
10847113afc8SEmmanuel Vadot 		    xgbe_phy_fc_string(pdata));
10857113afc8SEmmanuel Vadot 	else
10867113afc8SEmmanuel Vadot 		axgbe_printf(0, "Link is DOWN\n");
10877113afc8SEmmanuel Vadot }
10887113afc8SEmmanuel Vadot 
10897113afc8SEmmanuel Vadot static void
10907113afc8SEmmanuel Vadot xgbe_phy_adjust_link(struct xgbe_prv_data *pdata)
10917113afc8SEmmanuel Vadot {
10927113afc8SEmmanuel Vadot 	int new_state = 0;
10937113afc8SEmmanuel Vadot 
10947113afc8SEmmanuel Vadot 	axgbe_printf(1, "link %d/%d tx %d/%d rx %d/%d speed %d/%d autoneg %d/%d\n",
10957113afc8SEmmanuel Vadot 	    pdata->phy_link, pdata->phy.link,
10967113afc8SEmmanuel Vadot 	    pdata->tx_pause, pdata->phy.tx_pause,
10977113afc8SEmmanuel Vadot 	    pdata->rx_pause, pdata->phy.rx_pause,
10987113afc8SEmmanuel Vadot 	    pdata->phy_speed, pdata->phy.speed,
10997113afc8SEmmanuel Vadot 	    pdata->pause_autoneg, pdata->phy.pause_autoneg);
110044b781cfSAndrew Turner 
110144b781cfSAndrew Turner 	if (pdata->phy.link) {
110244b781cfSAndrew Turner 		/* Flow control support */
110344b781cfSAndrew Turner 		pdata->pause_autoneg = pdata->phy.pause_autoneg;
110444b781cfSAndrew Turner 
110544b781cfSAndrew Turner 		if (pdata->tx_pause != pdata->phy.tx_pause) {
11067113afc8SEmmanuel Vadot 			new_state = 1;
11077113afc8SEmmanuel Vadot 			axgbe_printf(2, "tx pause %d/%d\n", pdata->tx_pause,
11087113afc8SEmmanuel Vadot 			    pdata->phy.tx_pause);
110944b781cfSAndrew Turner 			pdata->tx_pause = pdata->phy.tx_pause;
11107113afc8SEmmanuel Vadot 			pdata->hw_if.config_tx_flow_control(pdata);
111144b781cfSAndrew Turner 		}
111244b781cfSAndrew Turner 
111344b781cfSAndrew Turner 		if (pdata->rx_pause != pdata->phy.rx_pause) {
11147113afc8SEmmanuel Vadot 			new_state = 1;
11157113afc8SEmmanuel Vadot 			axgbe_printf(2, "rx pause %d/%d\n", pdata->rx_pause,
11167113afc8SEmmanuel Vadot 			    pdata->phy.rx_pause);
111744b781cfSAndrew Turner 			pdata->rx_pause = pdata->phy.rx_pause;
11187113afc8SEmmanuel Vadot 			pdata->hw_if.config_rx_flow_control(pdata);
111944b781cfSAndrew Turner 		}
112044b781cfSAndrew Turner 
112144b781cfSAndrew Turner 		/* Speed support */
112244b781cfSAndrew Turner 		if (pdata->phy_speed != pdata->phy.speed) {
11237113afc8SEmmanuel Vadot 			new_state = 1;
112444b781cfSAndrew Turner 			pdata->phy_speed = pdata->phy.speed;
112544b781cfSAndrew Turner 		}
112644b781cfSAndrew Turner 
112744b781cfSAndrew Turner 		if (pdata->phy_link != pdata->phy.link) {
11287113afc8SEmmanuel Vadot 			new_state = 1;
112944b781cfSAndrew Turner 			pdata->phy_link = pdata->phy.link;
113044b781cfSAndrew Turner 		}
113144b781cfSAndrew Turner 	} else if (pdata->phy_link) {
11327113afc8SEmmanuel Vadot 		new_state = 1;
113344b781cfSAndrew Turner 		pdata->phy_link = 0;
113444b781cfSAndrew Turner 		pdata->phy_speed = SPEED_UNKNOWN;
113544b781cfSAndrew Turner 	}
11367113afc8SEmmanuel Vadot 
11377113afc8SEmmanuel Vadot 	axgbe_printf(2, "phy_link %d Link %d new_state %d\n", pdata->phy_link,
11387113afc8SEmmanuel Vadot 	    pdata->phy.link, new_state);
11397113afc8SEmmanuel Vadot 
11407113afc8SEmmanuel Vadot 	if (new_state)
11417113afc8SEmmanuel Vadot 		xgbe_phy_print_status(pdata);
114244b781cfSAndrew Turner }
114344b781cfSAndrew Turner 
11447113afc8SEmmanuel Vadot static bool
11457113afc8SEmmanuel Vadot xgbe_phy_valid_speed(struct xgbe_prv_data *pdata, int speed)
114644b781cfSAndrew Turner {
11477113afc8SEmmanuel Vadot 	return (pdata->phy_if.phy_impl.valid_speed(pdata, speed));
11487113afc8SEmmanuel Vadot }
11497113afc8SEmmanuel Vadot 
11507113afc8SEmmanuel Vadot static int
11517113afc8SEmmanuel Vadot xgbe_phy_config_fixed(struct xgbe_prv_data *pdata)
11527113afc8SEmmanuel Vadot {
11537113afc8SEmmanuel Vadot 	enum xgbe_mode mode;
11547113afc8SEmmanuel Vadot 
11557113afc8SEmmanuel Vadot 	axgbe_printf(2, "fixed PHY configuration\n");
115644b781cfSAndrew Turner 
115744b781cfSAndrew Turner 	/* Disable auto-negotiation */
11587113afc8SEmmanuel Vadot 	xgbe_an_disable(pdata);
115944b781cfSAndrew Turner 
11607113afc8SEmmanuel Vadot 	/* Set specified mode for specified speed */
11617113afc8SEmmanuel Vadot 	mode = pdata->phy_if.phy_impl.get_mode(pdata, pdata->phy.speed);
11627113afc8SEmmanuel Vadot 	switch (mode) {
11637113afc8SEmmanuel Vadot 	case XGBE_MODE_KX_1000:
11647113afc8SEmmanuel Vadot 	case XGBE_MODE_KX_2500:
11657113afc8SEmmanuel Vadot 	case XGBE_MODE_KR:
11667113afc8SEmmanuel Vadot 	case XGBE_MODE_SGMII_100:
11677113afc8SEmmanuel Vadot 	case XGBE_MODE_SGMII_1000:
11687113afc8SEmmanuel Vadot 	case XGBE_MODE_X:
11697113afc8SEmmanuel Vadot 	case XGBE_MODE_SFI:
117044b781cfSAndrew Turner 		break;
11717113afc8SEmmanuel Vadot 	case XGBE_MODE_UNKNOWN:
117244b781cfSAndrew Turner 	default:
11737113afc8SEmmanuel Vadot 		return (-EINVAL);
117444b781cfSAndrew Turner 	}
117544b781cfSAndrew Turner 
117644b781cfSAndrew Turner 	/* Validate duplex mode */
117744b781cfSAndrew Turner 	if (pdata->phy.duplex != DUPLEX_FULL)
11787113afc8SEmmanuel Vadot 		return (-EINVAL);
117944b781cfSAndrew Turner 
11807113afc8SEmmanuel Vadot 	xgbe_set_mode(pdata, mode);
11817113afc8SEmmanuel Vadot 
11827113afc8SEmmanuel Vadot 	return (0);
118344b781cfSAndrew Turner }
118444b781cfSAndrew Turner 
11857113afc8SEmmanuel Vadot static int
11867113afc8SEmmanuel Vadot __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata, bool set_mode)
118744b781cfSAndrew Turner {
11887113afc8SEmmanuel Vadot 	int ret;
1189*94e3e7d2SAdrian Chadd 	unsigned int reg = 0;
11907113afc8SEmmanuel Vadot 
11917113afc8SEmmanuel Vadot 	sx_xlock(&pdata->an_mutex);
11927113afc8SEmmanuel Vadot 
119344b781cfSAndrew Turner 	set_bit(XGBE_LINK_INIT, &pdata->dev_state);
11949c6d6488SAndrew Turner 	pdata->link_check = ticks;
119544b781cfSAndrew Turner 
11967113afc8SEmmanuel Vadot 	ret = pdata->phy_if.phy_impl.an_config(pdata);
11977113afc8SEmmanuel Vadot 	if (ret) {
11987113afc8SEmmanuel Vadot 		axgbe_error("%s: an_config fail %d\n", __func__, ret);
11997113afc8SEmmanuel Vadot 		goto out;
12007113afc8SEmmanuel Vadot 	}
12017113afc8SEmmanuel Vadot 
12027113afc8SEmmanuel Vadot 	if (pdata->phy.autoneg != AUTONEG_ENABLE) {
12037113afc8SEmmanuel Vadot 		ret = xgbe_phy_config_fixed(pdata);
12047113afc8SEmmanuel Vadot 		if (ret || !pdata->kr_redrv) {
12057113afc8SEmmanuel Vadot 			if (ret)
12067113afc8SEmmanuel Vadot 				axgbe_error("%s: fix conf fail %d\n", __func__, ret);
12077113afc8SEmmanuel Vadot 			goto out;
12087113afc8SEmmanuel Vadot 		}
12097113afc8SEmmanuel Vadot 
12107113afc8SEmmanuel Vadot 		axgbe_printf(2, "AN redriver support\n");
12117113afc8SEmmanuel Vadot 	} else
12127113afc8SEmmanuel Vadot 		axgbe_printf(2, "AN PHY configuration\n");
121344b781cfSAndrew Turner 
121444b781cfSAndrew Turner 	/* Disable auto-negotiation interrupt */
12159c6d6488SAndrew Turner 	XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, 0);
12167113afc8SEmmanuel Vadot 	reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK);
12177113afc8SEmmanuel Vadot 	axgbe_printf(2, "%s: set_mode %d AN int reg value 0x%x\n", __func__,
12187113afc8SEmmanuel Vadot 	    set_mode, reg);
12199c6d6488SAndrew Turner 
12209c6d6488SAndrew Turner 	/* Clear any auto-negotitation interrupts */
12219c6d6488SAndrew Turner 	XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0);
122244b781cfSAndrew Turner 
122344b781cfSAndrew Turner 	/* Start auto-negotiation in a supported mode */
12247113afc8SEmmanuel Vadot 	if (set_mode) {
12257113afc8SEmmanuel Vadot 		/* Start auto-negotiation in a supported mode */
12267113afc8SEmmanuel Vadot 		if (xgbe_use_mode(pdata, XGBE_MODE_KR)) {
122744b781cfSAndrew Turner 			xgbe_set_mode(pdata, XGBE_MODE_KR);
12287113afc8SEmmanuel Vadot 		} else if (xgbe_use_mode(pdata, XGBE_MODE_KX_2500)) {
12297113afc8SEmmanuel Vadot 			xgbe_set_mode(pdata, XGBE_MODE_KX_2500);
12307113afc8SEmmanuel Vadot 		} else if (xgbe_use_mode(pdata, XGBE_MODE_KX_1000)) {
12317113afc8SEmmanuel Vadot 			xgbe_set_mode(pdata, XGBE_MODE_KX_1000);
12327113afc8SEmmanuel Vadot 		} else if (xgbe_use_mode(pdata, XGBE_MODE_SFI)) {
12337113afc8SEmmanuel Vadot 			xgbe_set_mode(pdata, XGBE_MODE_SFI);
12347113afc8SEmmanuel Vadot 		} else if (xgbe_use_mode(pdata, XGBE_MODE_X)) {
12357113afc8SEmmanuel Vadot 			xgbe_set_mode(pdata, XGBE_MODE_X);
12367113afc8SEmmanuel Vadot 		} else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_1000)) {
12377113afc8SEmmanuel Vadot 			xgbe_set_mode(pdata, XGBE_MODE_SGMII_1000);
12387113afc8SEmmanuel Vadot 		} else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_100)) {
12397113afc8SEmmanuel Vadot 			xgbe_set_mode(pdata, XGBE_MODE_SGMII_100);
124044b781cfSAndrew Turner 		} else {
12419c6d6488SAndrew Turner 			XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, 0x07);
12427113afc8SEmmanuel Vadot 			ret = -EINVAL;
12437113afc8SEmmanuel Vadot 			goto out;
12447113afc8SEmmanuel Vadot 		}
124544b781cfSAndrew Turner 	}
124644b781cfSAndrew Turner 
124744b781cfSAndrew Turner 	/* Disable and stop any in progress auto-negotiation */
12487113afc8SEmmanuel Vadot 	xgbe_an_disable_all(pdata);
124944b781cfSAndrew Turner 
125044b781cfSAndrew Turner 	/* Clear any auto-negotitation interrupts */
12517113afc8SEmmanuel Vadot 	xgbe_an_clear_interrupts_all(pdata);
125244b781cfSAndrew Turner 
125344b781cfSAndrew Turner 	pdata->an_result = XGBE_AN_READY;
125444b781cfSAndrew Turner 	pdata->an_state = XGBE_AN_READY;
125544b781cfSAndrew Turner 	pdata->kr_state = XGBE_RX_BPA;
125644b781cfSAndrew Turner 	pdata->kx_state = XGBE_RX_BPA;
125744b781cfSAndrew Turner 
125844b781cfSAndrew Turner 	/* Re-enable auto-negotiation interrupt */
12599c6d6488SAndrew Turner 	XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, 0x07);
12607113afc8SEmmanuel Vadot 	reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK);
126144b781cfSAndrew Turner 
126244b781cfSAndrew Turner 	/* Set up advertisement registers based on current settings */
126344b781cfSAndrew Turner 	xgbe_an_init(pdata);
126444b781cfSAndrew Turner 
126544b781cfSAndrew Turner 	/* Enable and start auto-negotiation */
12667113afc8SEmmanuel Vadot 	xgbe_an_restart(pdata);
126744b781cfSAndrew Turner 
12687113afc8SEmmanuel Vadot out:
12697113afc8SEmmanuel Vadot 	if (ret) {
12707113afc8SEmmanuel Vadot 		axgbe_printf(0, "%s: set_mode %d AN int reg value 0x%x ret value %d\n",
12717113afc8SEmmanuel Vadot 		   __func__, set_mode, reg, ret);
127244b781cfSAndrew Turner 		set_bit(XGBE_LINK_ERR, &pdata->dev_state);
12737113afc8SEmmanuel Vadot 	} else
127444b781cfSAndrew Turner 		clear_bit(XGBE_LINK_ERR, &pdata->dev_state);
127544b781cfSAndrew Turner 
12769c6d6488SAndrew Turner 	sx_unlock(&pdata->an_mutex);
127744b781cfSAndrew Turner 
12787113afc8SEmmanuel Vadot 	return (ret);
127944b781cfSAndrew Turner }
128044b781cfSAndrew Turner 
12817113afc8SEmmanuel Vadot static int
12827113afc8SEmmanuel Vadot xgbe_phy_config_aneg(struct xgbe_prv_data *pdata)
12837113afc8SEmmanuel Vadot {
12847113afc8SEmmanuel Vadot 	return (__xgbe_phy_config_aneg(pdata, true));
12857113afc8SEmmanuel Vadot }
12867113afc8SEmmanuel Vadot 
12877113afc8SEmmanuel Vadot static int
12887113afc8SEmmanuel Vadot xgbe_phy_reconfig_aneg(struct xgbe_prv_data *pdata)
12897113afc8SEmmanuel Vadot {
12907113afc8SEmmanuel Vadot 	return (__xgbe_phy_config_aneg(pdata, false));
12917113afc8SEmmanuel Vadot }
12927113afc8SEmmanuel Vadot 
12937113afc8SEmmanuel Vadot static bool
12947113afc8SEmmanuel Vadot xgbe_phy_aneg_done(struct xgbe_prv_data *pdata)
129544b781cfSAndrew Turner {
129644b781cfSAndrew Turner 	return (pdata->an_result == XGBE_AN_COMPLETE);
129744b781cfSAndrew Turner }
129844b781cfSAndrew Turner 
12997113afc8SEmmanuel Vadot static void
13007113afc8SEmmanuel Vadot xgbe_check_link_timeout(struct xgbe_prv_data *pdata)
130144b781cfSAndrew Turner {
130244b781cfSAndrew Turner 	unsigned long link_timeout;
130344b781cfSAndrew Turner 
13049c6d6488SAndrew Turner 	link_timeout = pdata->link_check + (XGBE_LINK_TIMEOUT * hz);
13057113afc8SEmmanuel Vadot 	if ((int)(ticks - link_timeout) > 0) {
13067113afc8SEmmanuel Vadot 		axgbe_printf(2, "AN link timeout\n");
130744b781cfSAndrew Turner 		xgbe_phy_config_aneg(pdata);
130844b781cfSAndrew Turner 	}
130944b781cfSAndrew Turner }
131044b781cfSAndrew Turner 
13117113afc8SEmmanuel Vadot static enum xgbe_mode
13127113afc8SEmmanuel Vadot xgbe_phy_status_aneg(struct xgbe_prv_data *pdata)
131344b781cfSAndrew Turner {
13147113afc8SEmmanuel Vadot 	return (pdata->phy_if.phy_impl.an_outcome(pdata));
131544b781cfSAndrew Turner }
131644b781cfSAndrew Turner 
13177113afc8SEmmanuel Vadot static void
13187113afc8SEmmanuel Vadot xgbe_phy_status_result(struct xgbe_prv_data *pdata)
131944b781cfSAndrew Turner {
13207113afc8SEmmanuel Vadot 	enum xgbe_mode mode;
132144b781cfSAndrew Turner 
13227113afc8SEmmanuel Vadot 	XGBE_ZERO_LP_ADV(&pdata->phy);
132344b781cfSAndrew Turner 
132444b781cfSAndrew Turner 	if ((pdata->phy.autoneg != AUTONEG_ENABLE) || pdata->parallel_detect)
13257113afc8SEmmanuel Vadot 		mode = xgbe_cur_mode(pdata);
13267113afc8SEmmanuel Vadot 	else
13277113afc8SEmmanuel Vadot 		mode = xgbe_phy_status_aneg(pdata);
132844b781cfSAndrew Turner 
13297113afc8SEmmanuel Vadot 	axgbe_printf(3, "%s: xgbe mode %d\n", __func__, mode);
13307113afc8SEmmanuel Vadot 	switch (mode) {
13317113afc8SEmmanuel Vadot 	case XGBE_MODE_SGMII_100:
13327113afc8SEmmanuel Vadot 		pdata->phy.speed = SPEED_100;
133344b781cfSAndrew Turner 		break;
13347113afc8SEmmanuel Vadot 	case XGBE_MODE_X:
13357113afc8SEmmanuel Vadot 	case XGBE_MODE_KX_1000:
13367113afc8SEmmanuel Vadot 	case XGBE_MODE_SGMII_1000:
133744b781cfSAndrew Turner 		pdata->phy.speed = SPEED_1000;
133844b781cfSAndrew Turner 		break;
13397113afc8SEmmanuel Vadot 	case XGBE_MODE_KX_2500:
134044b781cfSAndrew Turner 		pdata->phy.speed = SPEED_2500;
134144b781cfSAndrew Turner 		break;
13427113afc8SEmmanuel Vadot 	case XGBE_MODE_KR:
13437113afc8SEmmanuel Vadot 	case XGBE_MODE_SFI:
13447113afc8SEmmanuel Vadot 		pdata->phy.speed = SPEED_10000;
13457113afc8SEmmanuel Vadot 		break;
13467113afc8SEmmanuel Vadot 	case XGBE_MODE_UNKNOWN:
13477113afc8SEmmanuel Vadot 	default:
13487113afc8SEmmanuel Vadot 		axgbe_printf(1, "%s: unknown mode\n", __func__);
134944b781cfSAndrew Turner 		pdata->phy.speed = SPEED_UNKNOWN;
135044b781cfSAndrew Turner 	}
135144b781cfSAndrew Turner 
13527113afc8SEmmanuel Vadot 	pdata->phy.duplex = DUPLEX_FULL;
13537113afc8SEmmanuel Vadot 	axgbe_printf(2, "%s: speed %d duplex %d\n", __func__, pdata->phy.speed,
13547113afc8SEmmanuel Vadot 	    pdata->phy.duplex);
13557113afc8SEmmanuel Vadot 
13567113afc8SEmmanuel Vadot 	if (xgbe_set_mode(pdata, mode) && pdata->an_again)
13577113afc8SEmmanuel Vadot 		xgbe_phy_reconfig_aneg(pdata);
135844b781cfSAndrew Turner }
135944b781cfSAndrew Turner 
13607113afc8SEmmanuel Vadot static void
13617113afc8SEmmanuel Vadot xgbe_phy_status(struct xgbe_prv_data *pdata)
136244b781cfSAndrew Turner {
13637113afc8SEmmanuel Vadot 	bool link_aneg;
13647113afc8SEmmanuel Vadot 	int an_restart;
136544b781cfSAndrew Turner 
136644b781cfSAndrew Turner 	if (test_bit(XGBE_LINK_ERR, &pdata->dev_state)) {
13677113afc8SEmmanuel Vadot 		axgbe_error("%s: LINK_ERR\n", __func__);
136844b781cfSAndrew Turner 		pdata->phy.link = 0;
136944b781cfSAndrew Turner 		goto adjust_link;
137044b781cfSAndrew Turner 	}
137144b781cfSAndrew Turner 
137244b781cfSAndrew Turner 	link_aneg = (pdata->phy.autoneg == AUTONEG_ENABLE);
13737113afc8SEmmanuel Vadot 	axgbe_printf(3, "link_aneg - %d\n", link_aneg);
137444b781cfSAndrew Turner 
137544b781cfSAndrew Turner 	/* Get the link status. Link status is latched low, so read
137644b781cfSAndrew Turner 	 * once to clear and then read again to get current state
137744b781cfSAndrew Turner 	 */
13787113afc8SEmmanuel Vadot 	pdata->phy.link = pdata->phy_if.phy_impl.link_status(pdata,
13797113afc8SEmmanuel Vadot 	    &an_restart);
13807113afc8SEmmanuel Vadot 
13817113afc8SEmmanuel Vadot 	axgbe_printf(1, "link_status returned Link:%d an_restart:%d aneg:%d\n",
13827113afc8SEmmanuel Vadot 	    pdata->phy.link, an_restart, link_aneg);
13837113afc8SEmmanuel Vadot 
13847113afc8SEmmanuel Vadot 	if (an_restart) {
13857113afc8SEmmanuel Vadot 		xgbe_phy_config_aneg(pdata);
13867113afc8SEmmanuel Vadot 		return;
13877113afc8SEmmanuel Vadot 	}
138844b781cfSAndrew Turner 
138944b781cfSAndrew Turner 	if (pdata->phy.link) {
13907113afc8SEmmanuel Vadot 		axgbe_printf(2, "Link Active\n");
139144b781cfSAndrew Turner 		if (link_aneg && !xgbe_phy_aneg_done(pdata)) {
13927113afc8SEmmanuel Vadot 			axgbe_printf(1, "phy_link set check timeout\n");
139344b781cfSAndrew Turner 			xgbe_check_link_timeout(pdata);
139444b781cfSAndrew Turner 			return;
139544b781cfSAndrew Turner 		}
139644b781cfSAndrew Turner 
13977113afc8SEmmanuel Vadot 		axgbe_printf(2, "%s: Link write phy_status result\n", __func__);
13987113afc8SEmmanuel Vadot 		xgbe_phy_status_result(pdata);
139944b781cfSAndrew Turner 
140044b781cfSAndrew Turner 		if (test_bit(XGBE_LINK_INIT, &pdata->dev_state))
140144b781cfSAndrew Turner 			clear_bit(XGBE_LINK_INIT, &pdata->dev_state);
14027113afc8SEmmanuel Vadot 
140344b781cfSAndrew Turner 	} else {
14047113afc8SEmmanuel Vadot 		axgbe_printf(2, "Link Deactive\n");
140544b781cfSAndrew Turner 		if (test_bit(XGBE_LINK_INIT, &pdata->dev_state)) {
14067113afc8SEmmanuel Vadot 			axgbe_printf(1, "phy_link not set check timeout\n");
140744b781cfSAndrew Turner 			xgbe_check_link_timeout(pdata);
140844b781cfSAndrew Turner 
14097113afc8SEmmanuel Vadot 			if (link_aneg) {
14107113afc8SEmmanuel Vadot 				axgbe_printf(2, "link_aneg case\n");
141144b781cfSAndrew Turner 				return;
141244b781cfSAndrew Turner 			}
14137113afc8SEmmanuel Vadot 		}
141444b781cfSAndrew Turner 
14157113afc8SEmmanuel Vadot 		xgbe_phy_status_result(pdata);
14167113afc8SEmmanuel Vadot 
141744b781cfSAndrew Turner 	}
141844b781cfSAndrew Turner 
141944b781cfSAndrew Turner adjust_link:
14207113afc8SEmmanuel Vadot 	axgbe_printf(2, "%s: Link %d\n", __func__, pdata->phy.link);
142144b781cfSAndrew Turner 	xgbe_phy_adjust_link(pdata);
142244b781cfSAndrew Turner }
142344b781cfSAndrew Turner 
14247113afc8SEmmanuel Vadot static void
14257113afc8SEmmanuel Vadot xgbe_phy_stop(struct xgbe_prv_data *pdata)
142644b781cfSAndrew Turner {
14277113afc8SEmmanuel Vadot 	axgbe_printf(2, "stopping PHY\n");
14287113afc8SEmmanuel Vadot 
14297113afc8SEmmanuel Vadot 	if (!pdata->phy_started)
14307113afc8SEmmanuel Vadot 		return;
14317113afc8SEmmanuel Vadot 
14327113afc8SEmmanuel Vadot 	/* Indicate the PHY is down */
14337113afc8SEmmanuel Vadot 	pdata->phy_started = 0;
143444b781cfSAndrew Turner 
143544b781cfSAndrew Turner 	/* Disable auto-negotiation */
14367113afc8SEmmanuel Vadot 	xgbe_an_disable_all(pdata);
143744b781cfSAndrew Turner 
14387113afc8SEmmanuel Vadot 	pdata->phy_if.phy_impl.stop(pdata);
143944b781cfSAndrew Turner 
144044b781cfSAndrew Turner 	pdata->phy.link = 0;
144144b781cfSAndrew Turner 
144244b781cfSAndrew Turner 	xgbe_phy_adjust_link(pdata);
144344b781cfSAndrew Turner }
144444b781cfSAndrew Turner 
14457113afc8SEmmanuel Vadot static int
14467113afc8SEmmanuel Vadot xgbe_phy_start(struct xgbe_prv_data *pdata)
144744b781cfSAndrew Turner {
144844b781cfSAndrew Turner 	int ret;
144944b781cfSAndrew Turner 
14507113afc8SEmmanuel Vadot 	DBGPR("-->xgbe_phy_start\n");
14517113afc8SEmmanuel Vadot 
14527113afc8SEmmanuel Vadot 	ret = pdata->phy_if.phy_impl.start(pdata);
145344b781cfSAndrew Turner 	if (ret) {
14547113afc8SEmmanuel Vadot 		axgbe_error("%s: impl start ret %d\n", __func__, ret);
14557113afc8SEmmanuel Vadot 		return (ret);
145644b781cfSAndrew Turner 	}
145744b781cfSAndrew Turner 
145844b781cfSAndrew Turner 	/* Set initial mode - call the mode setting routines
145944b781cfSAndrew Turner 	 * directly to insure we are properly configured
146044b781cfSAndrew Turner 	 */
14617113afc8SEmmanuel Vadot 	if (xgbe_use_mode(pdata, XGBE_MODE_KR)) {
14627113afc8SEmmanuel Vadot 		axgbe_printf(2, "%s: KR\n", __func__);
14637113afc8SEmmanuel Vadot 		xgbe_kr_mode(pdata);
14647113afc8SEmmanuel Vadot 	} else if (xgbe_use_mode(pdata, XGBE_MODE_KX_2500)) {
14657113afc8SEmmanuel Vadot 		axgbe_printf(2, "%s: KX 2500\n", __func__);
14667113afc8SEmmanuel Vadot 		xgbe_kx_2500_mode(pdata);
14677113afc8SEmmanuel Vadot 	} else if (xgbe_use_mode(pdata, XGBE_MODE_KX_1000)) {
14687113afc8SEmmanuel Vadot 		axgbe_printf(2, "%s: KX 1000\n", __func__);
14697113afc8SEmmanuel Vadot 		xgbe_kx_1000_mode(pdata);
14707113afc8SEmmanuel Vadot 	} else if (xgbe_use_mode(pdata, XGBE_MODE_SFI)) {
14717113afc8SEmmanuel Vadot 		axgbe_printf(2, "%s: SFI\n", __func__);
14727113afc8SEmmanuel Vadot 		xgbe_sfi_mode(pdata);
14737113afc8SEmmanuel Vadot 	} else if (xgbe_use_mode(pdata, XGBE_MODE_X)) {
14747113afc8SEmmanuel Vadot 		axgbe_printf(2, "%s: X\n", __func__);
14757113afc8SEmmanuel Vadot 		xgbe_x_mode(pdata);
14767113afc8SEmmanuel Vadot 	} else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_1000)) {
14777113afc8SEmmanuel Vadot 		axgbe_printf(2, "%s: SGMII 1000\n", __func__);
14787113afc8SEmmanuel Vadot 		xgbe_sgmii_1000_mode(pdata);
14797113afc8SEmmanuel Vadot 	} else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_100)) {
14807113afc8SEmmanuel Vadot 		axgbe_printf(2, "%s: SGMII 100\n", __func__);
14817113afc8SEmmanuel Vadot 		xgbe_sgmii_100_mode(pdata);
148244b781cfSAndrew Turner 	} else {
14837113afc8SEmmanuel Vadot 		axgbe_error("%s: invalid mode\n", __func__);
148444b781cfSAndrew Turner 		ret = -EINVAL;
14857113afc8SEmmanuel Vadot 		goto err_stop;
148644b781cfSAndrew Turner 	}
148744b781cfSAndrew Turner 
14887113afc8SEmmanuel Vadot 	/* Indicate the PHY is up and running */
14897113afc8SEmmanuel Vadot 	pdata->phy_started = 1;
14907113afc8SEmmanuel Vadot 
149144b781cfSAndrew Turner 	/* Set up advertisement registers based on current settings */
149244b781cfSAndrew Turner 	xgbe_an_init(pdata);
149344b781cfSAndrew Turner 
149444b781cfSAndrew Turner 	/* Enable auto-negotiation interrupts */
14957113afc8SEmmanuel Vadot 	xgbe_an_enable_interrupts(pdata);
149644b781cfSAndrew Turner 
14977113afc8SEmmanuel Vadot 	ret = xgbe_phy_config_aneg(pdata);
14987113afc8SEmmanuel Vadot 	if (ret)
14997113afc8SEmmanuel Vadot 		axgbe_error("%s: phy_config_aneg %d\n", __func__, ret);
150044b781cfSAndrew Turner 
15017113afc8SEmmanuel Vadot 	return (ret);
150244b781cfSAndrew Turner 
15037113afc8SEmmanuel Vadot err_stop:
15047113afc8SEmmanuel Vadot 	pdata->phy_if.phy_impl.stop(pdata);
15057113afc8SEmmanuel Vadot 
15067113afc8SEmmanuel Vadot 	return (ret);
150744b781cfSAndrew Turner }
150844b781cfSAndrew Turner 
15097113afc8SEmmanuel Vadot static int
15107113afc8SEmmanuel Vadot xgbe_phy_reset(struct xgbe_prv_data *pdata)
151144b781cfSAndrew Turner {
15127113afc8SEmmanuel Vadot 	int ret;
151344b781cfSAndrew Turner 
15147113afc8SEmmanuel Vadot 	ret = pdata->phy_if.phy_impl.reset(pdata);
15157113afc8SEmmanuel Vadot 	if (ret) {
15167113afc8SEmmanuel Vadot 		axgbe_error("%s: impl phy reset %d\n", __func__, ret);
15177113afc8SEmmanuel Vadot 		return (ret);
15187113afc8SEmmanuel Vadot 	}
151944b781cfSAndrew Turner 
152044b781cfSAndrew Turner 	/* Disable auto-negotiation for now */
15217113afc8SEmmanuel Vadot 	xgbe_an_disable_all(pdata);
152244b781cfSAndrew Turner 
152344b781cfSAndrew Turner 	/* Clear auto-negotiation interrupts */
15247113afc8SEmmanuel Vadot 	xgbe_an_clear_interrupts_all(pdata);
152544b781cfSAndrew Turner 
15267113afc8SEmmanuel Vadot 	return (0);
152744b781cfSAndrew Turner }
152844b781cfSAndrew Turner 
15297113afc8SEmmanuel Vadot static int
15307113afc8SEmmanuel Vadot xgbe_phy_best_advertised_speed(struct xgbe_prv_data *pdata)
153144b781cfSAndrew Turner {
15327113afc8SEmmanuel Vadot 
15337113afc8SEmmanuel Vadot 	if (XGBE_ADV(&pdata->phy, 10000baseKR_Full))
15347113afc8SEmmanuel Vadot 		return (SPEED_10000);
15357113afc8SEmmanuel Vadot 	else if (XGBE_ADV(&pdata->phy, 10000baseT_Full))
15367113afc8SEmmanuel Vadot 		return (SPEED_10000);
15377113afc8SEmmanuel Vadot 	else if (XGBE_ADV(&pdata->phy, 2500baseX_Full))
15387113afc8SEmmanuel Vadot 		return (SPEED_2500);
15397113afc8SEmmanuel Vadot 	else if (XGBE_ADV(&pdata->phy, 2500baseT_Full))
15407113afc8SEmmanuel Vadot 		return (SPEED_2500);
15417113afc8SEmmanuel Vadot 	else if (XGBE_ADV(&pdata->phy, 1000baseKX_Full))
15427113afc8SEmmanuel Vadot 		return (SPEED_1000);
15437113afc8SEmmanuel Vadot 	else if (XGBE_ADV(&pdata->phy, 1000baseT_Full))
15447113afc8SEmmanuel Vadot 		return (SPEED_1000);
15457113afc8SEmmanuel Vadot 	else if (XGBE_ADV(&pdata->phy, 100baseT_Full))
15467113afc8SEmmanuel Vadot 		return (SPEED_100);
15477113afc8SEmmanuel Vadot 
15487113afc8SEmmanuel Vadot 	return (SPEED_UNKNOWN);
15497113afc8SEmmanuel Vadot }
15507113afc8SEmmanuel Vadot 
15517113afc8SEmmanuel Vadot static void
15527113afc8SEmmanuel Vadot xgbe_phy_exit(struct xgbe_prv_data *pdata)
15537113afc8SEmmanuel Vadot {
15547113afc8SEmmanuel Vadot 	pdata->phy_if.phy_impl.exit(pdata);
15557113afc8SEmmanuel Vadot }
15567113afc8SEmmanuel Vadot 
15577113afc8SEmmanuel Vadot static int
15587113afc8SEmmanuel Vadot xgbe_phy_init(struct xgbe_prv_data *pdata)
15597113afc8SEmmanuel Vadot {
15607113afc8SEmmanuel Vadot 	int ret = 0;
15617113afc8SEmmanuel Vadot 
15627113afc8SEmmanuel Vadot 	DBGPR("-->xgbe_phy_init\n");
15637113afc8SEmmanuel Vadot 
15649c6d6488SAndrew Turner 	sx_init(&pdata->an_mutex, "axgbe AN lock");
156544b781cfSAndrew Turner 	pdata->mdio_mmd = MDIO_MMD_PCS;
156644b781cfSAndrew Turner 
156744b781cfSAndrew Turner 	/* Initialize supported features */
156844b781cfSAndrew Turner 	pdata->fec_ability = XMDIO_READ(pdata, MDIO_MMD_PMAPMD,
156944b781cfSAndrew Turner 					MDIO_PMA_10GBR_FECABLE);
157044b781cfSAndrew Turner 	pdata->fec_ability &= (MDIO_PMA_10GBR_FECABLE_ABLE |
157144b781cfSAndrew Turner 			       MDIO_PMA_10GBR_FECABLE_ERRABLE);
157244b781cfSAndrew Turner 
15737113afc8SEmmanuel Vadot 	/* Setup the phy (including supported features) */
15747113afc8SEmmanuel Vadot 	ret = pdata->phy_if.phy_impl.init(pdata);
15757113afc8SEmmanuel Vadot 	if (ret)
15767113afc8SEmmanuel Vadot 		return (ret);
15777113afc8SEmmanuel Vadot 
15787113afc8SEmmanuel Vadot 	/* Copy supported link modes to advertising link modes */
15797113afc8SEmmanuel Vadot 	XGBE_LM_COPY(&pdata->phy, advertising, &pdata->phy, supported);
158044b781cfSAndrew Turner 
158144b781cfSAndrew Turner 	pdata->phy.address = 0;
158244b781cfSAndrew Turner 
15837113afc8SEmmanuel Vadot 	if (XGBE_ADV(&pdata->phy, Autoneg)) {
158444b781cfSAndrew Turner 		pdata->phy.autoneg = AUTONEG_ENABLE;
158544b781cfSAndrew Turner 		pdata->phy.speed = SPEED_UNKNOWN;
158644b781cfSAndrew Turner 		pdata->phy.duplex = DUPLEX_UNKNOWN;
15877113afc8SEmmanuel Vadot 	} else {
15887113afc8SEmmanuel Vadot 		pdata->phy.autoneg = AUTONEG_DISABLE;
15897113afc8SEmmanuel Vadot 		pdata->phy.speed = xgbe_phy_best_advertised_speed(pdata);
15907113afc8SEmmanuel Vadot 		pdata->phy.duplex = DUPLEX_FULL;
15917113afc8SEmmanuel Vadot 	}
159244b781cfSAndrew Turner 
159344b781cfSAndrew Turner 	pdata->phy.link = 0;
159444b781cfSAndrew Turner 
159544b781cfSAndrew Turner 	pdata->phy.pause_autoneg = pdata->pause_autoneg;
159644b781cfSAndrew Turner 	pdata->phy.tx_pause = pdata->tx_pause;
159744b781cfSAndrew Turner 	pdata->phy.rx_pause = pdata->rx_pause;
159844b781cfSAndrew Turner 
159944b781cfSAndrew Turner 	/* Fix up Flow Control advertising */
16007113afc8SEmmanuel Vadot 	XGBE_CLR_ADV(&pdata->phy, Pause);
16017113afc8SEmmanuel Vadot 	XGBE_CLR_ADV(&pdata->phy, Asym_Pause);
160244b781cfSAndrew Turner 
160344b781cfSAndrew Turner 	if (pdata->rx_pause) {
16047113afc8SEmmanuel Vadot 		XGBE_SET_ADV(&pdata->phy, Pause);
16057113afc8SEmmanuel Vadot 		XGBE_SET_ADV(&pdata->phy, Asym_Pause);
160644b781cfSAndrew Turner 	}
160744b781cfSAndrew Turner 
16087113afc8SEmmanuel Vadot 	if (pdata->tx_pause) {
16097113afc8SEmmanuel Vadot 		if (XGBE_ADV(&pdata->phy, Asym_Pause))
16107113afc8SEmmanuel Vadot 			XGBE_CLR_ADV(&pdata->phy, Asym_Pause);
16117113afc8SEmmanuel Vadot 		else
16127113afc8SEmmanuel Vadot 			XGBE_SET_ADV(&pdata->phy, Asym_Pause);
161344b781cfSAndrew Turner 	}
161444b781cfSAndrew Turner 
16157113afc8SEmmanuel Vadot 	return (0);
16167113afc8SEmmanuel Vadot }
16177113afc8SEmmanuel Vadot 
16187113afc8SEmmanuel Vadot void
16197113afc8SEmmanuel Vadot xgbe_init_function_ptrs_phy(struct xgbe_phy_if *phy_if)
162044b781cfSAndrew Turner {
162144b781cfSAndrew Turner 	phy_if->phy_init	= xgbe_phy_init;
16227113afc8SEmmanuel Vadot 	phy_if->phy_exit	= xgbe_phy_exit;
162344b781cfSAndrew Turner 
162444b781cfSAndrew Turner 	phy_if->phy_reset       = xgbe_phy_reset;
162544b781cfSAndrew Turner 	phy_if->phy_start       = xgbe_phy_start;
162644b781cfSAndrew Turner 	phy_if->phy_stop	= xgbe_phy_stop;
162744b781cfSAndrew Turner 
162844b781cfSAndrew Turner 	phy_if->phy_status      = xgbe_phy_status;
162944b781cfSAndrew Turner 	phy_if->phy_config_aneg = xgbe_phy_config_aneg;
16307113afc8SEmmanuel Vadot 
16317113afc8SEmmanuel Vadot 	phy_if->phy_valid_speed = xgbe_phy_valid_speed;
16327113afc8SEmmanuel Vadot 
16337113afc8SEmmanuel Vadot 	phy_if->an_isr		= xgbe_an_combined_isr;
163444b781cfSAndrew Turner }
1635