xref: /freebsd/sys/dev/axgbe/xgbe-mdio.c (revision 445bed5c4d859575951361e432024396b938f863)
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>
11544b781cfSAndrew Turner #include "xgbe.h"
11644b781cfSAndrew Turner #include "xgbe-common.h"
11744b781cfSAndrew Turner 
1189c6d6488SAndrew Turner static void xgbe_an_state_machine(struct xgbe_prv_data *pdata);
1199c6d6488SAndrew Turner 
1207113afc8SEmmanuel Vadot static void
xgbe_an37_clear_interrupts(struct xgbe_prv_data * pdata)1217113afc8SEmmanuel Vadot xgbe_an37_clear_interrupts(struct xgbe_prv_data *pdata)
12244b781cfSAndrew Turner {
1237113afc8SEmmanuel Vadot 	int reg;
12444b781cfSAndrew Turner 
1257113afc8SEmmanuel Vadot 	reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT);
1267113afc8SEmmanuel Vadot 	reg &= ~XGBE_AN_CL37_INT_MASK;
1277113afc8SEmmanuel Vadot 	XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT, reg);
12844b781cfSAndrew Turner }
12944b781cfSAndrew Turner 
1307113afc8SEmmanuel Vadot static void
xgbe_an37_disable_interrupts(struct xgbe_prv_data * pdata)1317113afc8SEmmanuel Vadot xgbe_an37_disable_interrupts(struct xgbe_prv_data *pdata)
13244b781cfSAndrew Turner {
1337113afc8SEmmanuel Vadot 	int reg;
13444b781cfSAndrew Turner 
1357113afc8SEmmanuel Vadot 	reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL);
1367113afc8SEmmanuel Vadot 	reg &= ~XGBE_AN_CL37_INT_MASK;
1377113afc8SEmmanuel Vadot 	XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL, reg);
13844b781cfSAndrew Turner 
1397113afc8SEmmanuel Vadot 	reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL);
1407113afc8SEmmanuel Vadot 	reg &= ~XGBE_PCS_CL37_BP;
1417113afc8SEmmanuel Vadot 	XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL, reg);
14244b781cfSAndrew Turner }
14344b781cfSAndrew Turner 
1447113afc8SEmmanuel Vadot static void
xgbe_an37_enable_interrupts(struct xgbe_prv_data * pdata)1457113afc8SEmmanuel Vadot xgbe_an37_enable_interrupts(struct xgbe_prv_data *pdata)
14644b781cfSAndrew Turner {
1477113afc8SEmmanuel Vadot 	int reg;
14844b781cfSAndrew Turner 
1497113afc8SEmmanuel Vadot 	reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL);
1507113afc8SEmmanuel Vadot 	reg |= XGBE_PCS_CL37_BP;
1517113afc8SEmmanuel Vadot 	XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL, reg);
15244b781cfSAndrew Turner 
1537113afc8SEmmanuel Vadot 	reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL);
1547113afc8SEmmanuel Vadot 	reg |= XGBE_AN_CL37_INT_MASK;
1557113afc8SEmmanuel Vadot 	XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL, reg);
15644b781cfSAndrew Turner }
15744b781cfSAndrew Turner 
1587113afc8SEmmanuel Vadot static void
xgbe_an73_clear_interrupts(struct xgbe_prv_data * pdata)1597113afc8SEmmanuel Vadot xgbe_an73_clear_interrupts(struct xgbe_prv_data *pdata)
16044b781cfSAndrew Turner {
1617113afc8SEmmanuel Vadot 	XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0);
16244b781cfSAndrew Turner }
16344b781cfSAndrew Turner 
1647113afc8SEmmanuel Vadot static void
xgbe_an73_disable_interrupts(struct xgbe_prv_data * pdata)1657113afc8SEmmanuel Vadot xgbe_an73_disable_interrupts(struct xgbe_prv_data *pdata)
16644b781cfSAndrew Turner {
1677113afc8SEmmanuel Vadot 	XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, 0);
16844b781cfSAndrew Turner }
16944b781cfSAndrew Turner 
1707113afc8SEmmanuel Vadot static void
xgbe_an73_enable_interrupts(struct xgbe_prv_data * pdata)1717113afc8SEmmanuel Vadot xgbe_an73_enable_interrupts(struct xgbe_prv_data *pdata)
1727113afc8SEmmanuel Vadot {
1737113afc8SEmmanuel Vadot 	XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, XGBE_AN_CL73_INT_MASK);
17444b781cfSAndrew Turner }
17544b781cfSAndrew Turner 
1767113afc8SEmmanuel Vadot static void
xgbe_an_enable_interrupts(struct xgbe_prv_data * pdata)1777113afc8SEmmanuel Vadot xgbe_an_enable_interrupts(struct xgbe_prv_data *pdata)
17844b781cfSAndrew Turner {
1797113afc8SEmmanuel Vadot 	switch (pdata->an_mode) {
1807113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL73:
1817113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL73_REDRV:
1827113afc8SEmmanuel Vadot 		xgbe_an73_enable_interrupts(pdata);
1837113afc8SEmmanuel Vadot 		break;
1847113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL37:
1857113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL37_SGMII:
1867113afc8SEmmanuel Vadot 		xgbe_an37_enable_interrupts(pdata);
1877113afc8SEmmanuel Vadot 		break;
1887113afc8SEmmanuel Vadot 	default:
1897113afc8SEmmanuel Vadot 		break;
1907113afc8SEmmanuel Vadot 	}
1917113afc8SEmmanuel Vadot }
19244b781cfSAndrew Turner 
1937113afc8SEmmanuel Vadot static void
xgbe_an_clear_interrupts_all(struct xgbe_prv_data * pdata)1947113afc8SEmmanuel Vadot xgbe_an_clear_interrupts_all(struct xgbe_prv_data *pdata)
1957113afc8SEmmanuel Vadot {
1967113afc8SEmmanuel Vadot 	xgbe_an73_clear_interrupts(pdata);
1977113afc8SEmmanuel Vadot 	xgbe_an37_clear_interrupts(pdata);
1987113afc8SEmmanuel Vadot }
1997113afc8SEmmanuel Vadot 
2007113afc8SEmmanuel Vadot static void
xgbe_kr_mode(struct xgbe_prv_data * pdata)2017113afc8SEmmanuel Vadot xgbe_kr_mode(struct xgbe_prv_data *pdata)
2027113afc8SEmmanuel Vadot {
2037113afc8SEmmanuel Vadot 	/* Set MAC to 10G speed */
2047113afc8SEmmanuel Vadot 	pdata->hw_if.set_speed(pdata, SPEED_10000);
2057113afc8SEmmanuel Vadot 
2067113afc8SEmmanuel Vadot 	/* Call PHY implementation support to complete rate change */
2077113afc8SEmmanuel Vadot 	pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_KR);
2087113afc8SEmmanuel Vadot }
2097113afc8SEmmanuel Vadot 
2107113afc8SEmmanuel Vadot static void
xgbe_kx_2500_mode(struct xgbe_prv_data * pdata)2117113afc8SEmmanuel Vadot xgbe_kx_2500_mode(struct xgbe_prv_data *pdata)
2127113afc8SEmmanuel Vadot {
2137113afc8SEmmanuel Vadot 	/* Set MAC to 2.5G speed */
2147113afc8SEmmanuel Vadot 	pdata->hw_if.set_speed(pdata, SPEED_2500);
2157113afc8SEmmanuel Vadot 
2167113afc8SEmmanuel Vadot 	/* Call PHY implementation support to complete rate change */
2177113afc8SEmmanuel Vadot 	pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_KX_2500);
2187113afc8SEmmanuel Vadot }
2197113afc8SEmmanuel Vadot 
2207113afc8SEmmanuel Vadot static void
xgbe_kx_1000_mode(struct xgbe_prv_data * pdata)2217113afc8SEmmanuel Vadot xgbe_kx_1000_mode(struct xgbe_prv_data *pdata)
2227113afc8SEmmanuel Vadot {
2237113afc8SEmmanuel Vadot 	/* Set MAC to 1G speed */
2247113afc8SEmmanuel Vadot 	pdata->hw_if.set_speed(pdata, SPEED_1000);
2257113afc8SEmmanuel Vadot 
2267113afc8SEmmanuel Vadot 	/* Call PHY implementation support to complete rate change */
2277113afc8SEmmanuel Vadot 	pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_KX_1000);
2287113afc8SEmmanuel Vadot }
2297113afc8SEmmanuel Vadot 
2307113afc8SEmmanuel Vadot static void
xgbe_sfi_mode(struct xgbe_prv_data * pdata)2317113afc8SEmmanuel Vadot xgbe_sfi_mode(struct xgbe_prv_data *pdata)
2327113afc8SEmmanuel Vadot {
2337113afc8SEmmanuel Vadot 	/* If a KR re-driver is present, change to KR mode instead */
2347113afc8SEmmanuel Vadot 	if (pdata->kr_redrv)
2357113afc8SEmmanuel Vadot 		return (xgbe_kr_mode(pdata));
23644b781cfSAndrew Turner 
23744b781cfSAndrew Turner 	/* Set MAC to 10G speed */
2387113afc8SEmmanuel Vadot 	pdata->hw_if.set_speed(pdata, SPEED_10000);
23944b781cfSAndrew Turner 
2407113afc8SEmmanuel Vadot 	/* Call PHY implementation support to complete rate change */
2417113afc8SEmmanuel Vadot 	pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_SFI);
24244b781cfSAndrew Turner }
24344b781cfSAndrew Turner 
2447113afc8SEmmanuel Vadot static void
xgbe_x_mode(struct xgbe_prv_data * pdata)2457113afc8SEmmanuel Vadot xgbe_x_mode(struct xgbe_prv_data *pdata)
24644b781cfSAndrew Turner {
24744b781cfSAndrew Turner 	/* Set MAC to 1G speed */
2487113afc8SEmmanuel Vadot 	pdata->hw_if.set_speed(pdata, SPEED_1000);
24944b781cfSAndrew Turner 
2507113afc8SEmmanuel Vadot 	/* Call PHY implementation support to complete rate change */
2517113afc8SEmmanuel Vadot 	pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_X);
25244b781cfSAndrew Turner }
25344b781cfSAndrew Turner 
2547113afc8SEmmanuel Vadot static void
xgbe_sgmii_1000_mode(struct xgbe_prv_data * pdata)2557113afc8SEmmanuel Vadot xgbe_sgmii_1000_mode(struct xgbe_prv_data *pdata)
2567113afc8SEmmanuel Vadot {
2577113afc8SEmmanuel Vadot 	/* Set MAC to 1G speed */
2587113afc8SEmmanuel Vadot 	pdata->hw_if.set_speed(pdata, SPEED_1000);
2597113afc8SEmmanuel Vadot 
2607113afc8SEmmanuel Vadot 	/* Call PHY implementation support to complete rate change */
2617113afc8SEmmanuel Vadot 	pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_SGMII_1000);
2627113afc8SEmmanuel Vadot }
2637113afc8SEmmanuel Vadot 
2647113afc8SEmmanuel Vadot static void
xgbe_sgmii_100_mode(struct xgbe_prv_data * pdata)2657113afc8SEmmanuel Vadot xgbe_sgmii_100_mode(struct xgbe_prv_data *pdata)
2667113afc8SEmmanuel Vadot {
2677113afc8SEmmanuel Vadot 	/* Set MAC to 1G speed */
2687113afc8SEmmanuel Vadot 	pdata->hw_if.set_speed(pdata, SPEED_1000);
2697113afc8SEmmanuel Vadot 
2707113afc8SEmmanuel Vadot 	/* Call PHY implementation support to complete rate change */
2717113afc8SEmmanuel Vadot 	pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_SGMII_100);
2727113afc8SEmmanuel Vadot }
2737113afc8SEmmanuel Vadot 
2747113afc8SEmmanuel Vadot static enum xgbe_mode
xgbe_cur_mode(struct xgbe_prv_data * pdata)2757113afc8SEmmanuel Vadot xgbe_cur_mode(struct xgbe_prv_data *pdata)
2767113afc8SEmmanuel Vadot {
2777113afc8SEmmanuel Vadot 	return (pdata->phy_if.phy_impl.cur_mode(pdata));
2787113afc8SEmmanuel Vadot }
2797113afc8SEmmanuel Vadot 
2807113afc8SEmmanuel Vadot static bool
xgbe_in_kr_mode(struct xgbe_prv_data * pdata)2817113afc8SEmmanuel Vadot xgbe_in_kr_mode(struct xgbe_prv_data *pdata)
2827113afc8SEmmanuel Vadot {
2837113afc8SEmmanuel Vadot 	return (xgbe_cur_mode(pdata) == XGBE_MODE_KR);
2847113afc8SEmmanuel Vadot }
2857113afc8SEmmanuel Vadot 
2867113afc8SEmmanuel Vadot static void
xgbe_change_mode(struct xgbe_prv_data * pdata,enum xgbe_mode mode)2877113afc8SEmmanuel Vadot xgbe_change_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode)
2887113afc8SEmmanuel Vadot {
2897113afc8SEmmanuel Vadot 	switch (mode) {
2907113afc8SEmmanuel Vadot 	case XGBE_MODE_KX_1000:
2917113afc8SEmmanuel Vadot 		xgbe_kx_1000_mode(pdata);
2927113afc8SEmmanuel Vadot 		break;
2937113afc8SEmmanuel Vadot 	case XGBE_MODE_KX_2500:
2947113afc8SEmmanuel Vadot 		xgbe_kx_2500_mode(pdata);
2957113afc8SEmmanuel Vadot 		break;
2967113afc8SEmmanuel Vadot 	case XGBE_MODE_KR:
2977113afc8SEmmanuel Vadot 		xgbe_kr_mode(pdata);
2987113afc8SEmmanuel Vadot 		break;
2997113afc8SEmmanuel Vadot 	case XGBE_MODE_SGMII_100:
3007113afc8SEmmanuel Vadot 		xgbe_sgmii_100_mode(pdata);
3017113afc8SEmmanuel Vadot 		break;
3027113afc8SEmmanuel Vadot 	case XGBE_MODE_SGMII_1000:
3037113afc8SEmmanuel Vadot 		xgbe_sgmii_1000_mode(pdata);
3047113afc8SEmmanuel Vadot 		break;
3057113afc8SEmmanuel Vadot 	case XGBE_MODE_X:
3067113afc8SEmmanuel Vadot 		xgbe_x_mode(pdata);
3077113afc8SEmmanuel Vadot 		break;
3087113afc8SEmmanuel Vadot 	case XGBE_MODE_SFI:
3097113afc8SEmmanuel Vadot 		xgbe_sfi_mode(pdata);
3107113afc8SEmmanuel Vadot 		break;
3117113afc8SEmmanuel Vadot 	case XGBE_MODE_UNKNOWN:
3127113afc8SEmmanuel Vadot 		break;
3137113afc8SEmmanuel Vadot 	default:
3147113afc8SEmmanuel Vadot 		axgbe_error("invalid operation mode requested (%u)\n", mode);
3157113afc8SEmmanuel Vadot 	}
3167113afc8SEmmanuel Vadot }
3177113afc8SEmmanuel Vadot 
3187113afc8SEmmanuel Vadot static void
xgbe_switch_mode(struct xgbe_prv_data * pdata)3197113afc8SEmmanuel Vadot xgbe_switch_mode(struct xgbe_prv_data *pdata)
3207113afc8SEmmanuel Vadot {
3217113afc8SEmmanuel Vadot 	xgbe_change_mode(pdata, pdata->phy_if.phy_impl.switch_mode(pdata));
3227113afc8SEmmanuel Vadot }
3237113afc8SEmmanuel Vadot 
3247113afc8SEmmanuel Vadot static bool
xgbe_set_mode(struct xgbe_prv_data * pdata,enum xgbe_mode mode)3257113afc8SEmmanuel Vadot xgbe_set_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode)
3267113afc8SEmmanuel Vadot {
3277113afc8SEmmanuel Vadot 	if (mode == xgbe_cur_mode(pdata))
3287113afc8SEmmanuel Vadot 		return (false);
3297113afc8SEmmanuel Vadot 
3307113afc8SEmmanuel Vadot 	xgbe_change_mode(pdata, mode);
3317113afc8SEmmanuel Vadot 
3327113afc8SEmmanuel Vadot 	return (true);
3337113afc8SEmmanuel Vadot }
3347113afc8SEmmanuel Vadot 
3357113afc8SEmmanuel Vadot static bool
xgbe_use_mode(struct xgbe_prv_data * pdata,enum xgbe_mode mode)3367113afc8SEmmanuel Vadot xgbe_use_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode)
3377113afc8SEmmanuel Vadot {
3387113afc8SEmmanuel Vadot 	return (pdata->phy_if.phy_impl.use_mode(pdata, mode));
3397113afc8SEmmanuel Vadot }
3407113afc8SEmmanuel Vadot 
3417113afc8SEmmanuel Vadot static void
xgbe_an37_set(struct xgbe_prv_data * pdata,bool enable,bool restart)3427113afc8SEmmanuel Vadot xgbe_an37_set(struct xgbe_prv_data *pdata, bool enable, bool restart)
34344b781cfSAndrew Turner {
34444b781cfSAndrew Turner 	unsigned int reg;
34544b781cfSAndrew Turner 
3467113afc8SEmmanuel Vadot 	reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_CTRL1);
3477113afc8SEmmanuel Vadot 	reg &= ~MDIO_VEND2_CTRL1_AN_ENABLE;
3487113afc8SEmmanuel Vadot 
3497113afc8SEmmanuel Vadot 	if (enable)
3507113afc8SEmmanuel Vadot 		reg |= MDIO_VEND2_CTRL1_AN_ENABLE;
3517113afc8SEmmanuel Vadot 
3527113afc8SEmmanuel Vadot 	if (restart)
3537113afc8SEmmanuel Vadot 		reg |= MDIO_VEND2_CTRL1_AN_RESTART;
3547113afc8SEmmanuel Vadot 
3557113afc8SEmmanuel Vadot 	XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_CTRL1, reg);
35644b781cfSAndrew Turner }
35744b781cfSAndrew Turner 
3587113afc8SEmmanuel Vadot static void
xgbe_an37_restart(struct xgbe_prv_data * pdata)3597113afc8SEmmanuel Vadot xgbe_an37_restart(struct xgbe_prv_data *pdata)
36044b781cfSAndrew Turner {
3617113afc8SEmmanuel Vadot 	xgbe_an37_enable_interrupts(pdata);
3627113afc8SEmmanuel Vadot 	xgbe_an37_set(pdata, true, true);
36344b781cfSAndrew Turner }
36444b781cfSAndrew Turner 
3657113afc8SEmmanuel Vadot static void
xgbe_an37_disable(struct xgbe_prv_data * pdata)3667113afc8SEmmanuel Vadot xgbe_an37_disable(struct xgbe_prv_data *pdata)
36744b781cfSAndrew Turner {
3687113afc8SEmmanuel Vadot 	xgbe_an37_set(pdata, false, false);
3697113afc8SEmmanuel Vadot 	xgbe_an37_disable_interrupts(pdata);
37044b781cfSAndrew Turner }
37144b781cfSAndrew Turner 
3727113afc8SEmmanuel Vadot static void
xgbe_an73_set(struct xgbe_prv_data * pdata,bool enable,bool restart)3737113afc8SEmmanuel Vadot xgbe_an73_set(struct xgbe_prv_data *pdata, bool enable, bool restart)
37444b781cfSAndrew Turner {
37544b781cfSAndrew Turner 	unsigned int reg;
37644b781cfSAndrew Turner 
3777113afc8SEmmanuel Vadot 	/* Disable KR training for now */
3787113afc8SEmmanuel Vadot 	reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL);
3797113afc8SEmmanuel Vadot 	reg &= ~XGBE_KR_TRAINING_ENABLE;
3807113afc8SEmmanuel Vadot 	XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, reg);
3817113afc8SEmmanuel Vadot 
3827113afc8SEmmanuel Vadot 	/* Update AN settings */
38344b781cfSAndrew Turner 	reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_CTRL1);
38444b781cfSAndrew Turner 	reg &= ~MDIO_AN_CTRL1_ENABLE;
38544b781cfSAndrew Turner 
38644b781cfSAndrew Turner 	if (enable)
38744b781cfSAndrew Turner 		reg |= MDIO_AN_CTRL1_ENABLE;
38844b781cfSAndrew Turner 
38944b781cfSAndrew Turner 	if (restart)
39044b781cfSAndrew Turner 		reg |= MDIO_AN_CTRL1_RESTART;
39144b781cfSAndrew Turner 
39244b781cfSAndrew Turner 	XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_CTRL1, reg);
39344b781cfSAndrew Turner }
39444b781cfSAndrew Turner 
3957113afc8SEmmanuel Vadot static void
xgbe_an73_restart(struct xgbe_prv_data * pdata)3967113afc8SEmmanuel Vadot xgbe_an73_restart(struct xgbe_prv_data *pdata)
39744b781cfSAndrew Turner {
3987113afc8SEmmanuel Vadot 	xgbe_an73_enable_interrupts(pdata);
3997113afc8SEmmanuel Vadot 	xgbe_an73_set(pdata, true, true);
40044b781cfSAndrew Turner }
40144b781cfSAndrew Turner 
4027113afc8SEmmanuel Vadot static void
xgbe_an73_disable(struct xgbe_prv_data * pdata)4037113afc8SEmmanuel Vadot xgbe_an73_disable(struct xgbe_prv_data *pdata)
40444b781cfSAndrew Turner {
4057113afc8SEmmanuel Vadot 	xgbe_an73_set(pdata, false, false);
4067113afc8SEmmanuel Vadot 	xgbe_an73_disable_interrupts(pdata);
4077113afc8SEmmanuel Vadot 
4087113afc8SEmmanuel Vadot 	pdata->an_start = 0;
40944b781cfSAndrew Turner }
41044b781cfSAndrew Turner 
4117113afc8SEmmanuel Vadot static void
xgbe_an_restart(struct xgbe_prv_data * pdata)4127113afc8SEmmanuel Vadot xgbe_an_restart(struct xgbe_prv_data *pdata)
4137113afc8SEmmanuel Vadot {
4147113afc8SEmmanuel Vadot 	if (pdata->phy_if.phy_impl.an_pre)
4157113afc8SEmmanuel Vadot 		pdata->phy_if.phy_impl.an_pre(pdata);
4167113afc8SEmmanuel Vadot 
4177113afc8SEmmanuel Vadot 	switch (pdata->an_mode) {
4187113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL73:
4197113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL73_REDRV:
4207113afc8SEmmanuel Vadot 		xgbe_an73_restart(pdata);
4217113afc8SEmmanuel Vadot 		break;
4227113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL37:
4237113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL37_SGMII:
4247113afc8SEmmanuel Vadot 		xgbe_an37_restart(pdata);
4257113afc8SEmmanuel Vadot 		break;
4267113afc8SEmmanuel Vadot 	default:
4277113afc8SEmmanuel Vadot 		break;
4287113afc8SEmmanuel Vadot 	}
4297113afc8SEmmanuel Vadot }
4307113afc8SEmmanuel Vadot 
4317113afc8SEmmanuel Vadot static void
xgbe_an_disable(struct xgbe_prv_data * pdata)4327113afc8SEmmanuel Vadot xgbe_an_disable(struct xgbe_prv_data *pdata)
4337113afc8SEmmanuel Vadot {
4347113afc8SEmmanuel Vadot 	if (pdata->phy_if.phy_impl.an_post)
4357113afc8SEmmanuel Vadot 		pdata->phy_if.phy_impl.an_post(pdata);
4367113afc8SEmmanuel Vadot 
4377113afc8SEmmanuel Vadot 	switch (pdata->an_mode) {
4387113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL73:
4397113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL73_REDRV:
4407113afc8SEmmanuel Vadot 		xgbe_an73_disable(pdata);
4417113afc8SEmmanuel Vadot 		break;
4427113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL37:
4437113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL37_SGMII:
4447113afc8SEmmanuel Vadot 		xgbe_an37_disable(pdata);
4457113afc8SEmmanuel Vadot 		break;
4467113afc8SEmmanuel Vadot 	default:
4477113afc8SEmmanuel Vadot 		break;
4487113afc8SEmmanuel Vadot 	}
4497113afc8SEmmanuel Vadot }
4507113afc8SEmmanuel Vadot 
4517113afc8SEmmanuel Vadot static void
xgbe_an_disable_all(struct xgbe_prv_data * pdata)4527113afc8SEmmanuel Vadot xgbe_an_disable_all(struct xgbe_prv_data *pdata)
4537113afc8SEmmanuel Vadot {
4547113afc8SEmmanuel Vadot 	xgbe_an73_disable(pdata);
4557113afc8SEmmanuel Vadot 	xgbe_an37_disable(pdata);
4567113afc8SEmmanuel Vadot }
4577113afc8SEmmanuel Vadot 
4587113afc8SEmmanuel Vadot static enum xgbe_an
xgbe_an73_tx_training(struct xgbe_prv_data * pdata,enum xgbe_rx * state)4597113afc8SEmmanuel Vadot xgbe_an73_tx_training(struct xgbe_prv_data *pdata, enum xgbe_rx *state)
46044b781cfSAndrew Turner {
46144b781cfSAndrew Turner 	unsigned int ad_reg, lp_reg, reg;
46244b781cfSAndrew Turner 
46344b781cfSAndrew Turner 	*state = XGBE_RX_COMPLETE;
46444b781cfSAndrew Turner 
46544b781cfSAndrew Turner 	/* If we're not in KR mode then we're done */
46644b781cfSAndrew Turner 	if (!xgbe_in_kr_mode(pdata))
4677113afc8SEmmanuel Vadot 		return (XGBE_AN_PAGE_RECEIVED);
46844b781cfSAndrew Turner 
46944b781cfSAndrew Turner 	/* Enable/Disable FEC */
47044b781cfSAndrew Turner 	ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
47144b781cfSAndrew Turner 	lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2);
47244b781cfSAndrew Turner 
47344b781cfSAndrew Turner 	reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FECCTRL);
47444b781cfSAndrew Turner 	reg &= ~(MDIO_PMA_10GBR_FECABLE_ABLE | MDIO_PMA_10GBR_FECABLE_ERRABLE);
47544b781cfSAndrew Turner 	if ((ad_reg & 0xc000) && (lp_reg & 0xc000))
47644b781cfSAndrew Turner 		reg |= pdata->fec_ability;
47744b781cfSAndrew Turner 
47844b781cfSAndrew Turner 	XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FECCTRL, reg);
47944b781cfSAndrew Turner 
48044b781cfSAndrew Turner 	/* Start KR training */
4817113afc8SEmmanuel Vadot 	if (pdata->phy_if.phy_impl.kr_training_pre)
4827113afc8SEmmanuel Vadot 		pdata->phy_if.phy_impl.kr_training_pre(pdata);
4837113afc8SEmmanuel Vadot 
4847113afc8SEmmanuel Vadot 	/* Start KR training */
48544b781cfSAndrew Turner 	reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL);
4867113afc8SEmmanuel Vadot 	reg |= XGBE_KR_TRAINING_ENABLE;
48744b781cfSAndrew Turner 	reg |= XGBE_KR_TRAINING_START;
4887113afc8SEmmanuel Vadot 	XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, reg);
48944b781cfSAndrew Turner 
4907113afc8SEmmanuel Vadot 	if (pdata->phy_if.phy_impl.kr_training_post)
4917113afc8SEmmanuel Vadot 		pdata->phy_if.phy_impl.kr_training_post(pdata);
4927113afc8SEmmanuel Vadot 
4937113afc8SEmmanuel Vadot 	return (XGBE_AN_PAGE_RECEIVED);
49444b781cfSAndrew Turner }
49544b781cfSAndrew Turner 
4967113afc8SEmmanuel Vadot static enum xgbe_an
xgbe_an73_tx_xnp(struct xgbe_prv_data * pdata,enum xgbe_rx * state)4977113afc8SEmmanuel Vadot xgbe_an73_tx_xnp(struct xgbe_prv_data *pdata, enum xgbe_rx *state)
49844b781cfSAndrew Turner {
4997113afc8SEmmanuel Vadot 	uint16_t msg;
50044b781cfSAndrew Turner 
50144b781cfSAndrew Turner 	*state = XGBE_RX_XNP;
50244b781cfSAndrew Turner 
50344b781cfSAndrew Turner 	msg = XGBE_XNP_MCF_NULL_MESSAGE;
50444b781cfSAndrew Turner 	msg |= XGBE_XNP_MP_FORMATTED;
50544b781cfSAndrew Turner 
50644b781cfSAndrew Turner 	XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_XNP + 2, 0);
50744b781cfSAndrew Turner 	XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_XNP + 1, 0);
50844b781cfSAndrew Turner 	XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_XNP, msg);
50944b781cfSAndrew Turner 
5107113afc8SEmmanuel Vadot 	return (XGBE_AN_PAGE_RECEIVED);
51144b781cfSAndrew Turner }
51244b781cfSAndrew Turner 
5137113afc8SEmmanuel Vadot static enum xgbe_an
xgbe_an73_rx_bpa(struct xgbe_prv_data * pdata,enum xgbe_rx * state)5147113afc8SEmmanuel Vadot xgbe_an73_rx_bpa(struct xgbe_prv_data *pdata, enum xgbe_rx *state)
51544b781cfSAndrew Turner {
51644b781cfSAndrew Turner 	unsigned int link_support;
51744b781cfSAndrew Turner 	unsigned int reg, ad_reg, lp_reg;
51844b781cfSAndrew Turner 
51944b781cfSAndrew Turner 	/* Read Base Ability register 2 first */
52044b781cfSAndrew Turner 	reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1);
52144b781cfSAndrew Turner 
52244b781cfSAndrew Turner 	/* Check for a supported mode, otherwise restart in a different one */
52344b781cfSAndrew Turner 	link_support = xgbe_in_kr_mode(pdata) ? 0x80 : 0x20;
52444b781cfSAndrew Turner 	if (!(reg & link_support))
5257113afc8SEmmanuel Vadot 		return (XGBE_AN_INCOMPAT_LINK);
52644b781cfSAndrew Turner 
52744b781cfSAndrew Turner 	/* Check Extended Next Page support */
52844b781cfSAndrew Turner 	ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
52944b781cfSAndrew Turner 	lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA);
53044b781cfSAndrew Turner 
5317113afc8SEmmanuel Vadot 	return (((ad_reg & XGBE_XNP_NP_EXCHANGE) ||
53244b781cfSAndrew Turner 		(lp_reg & XGBE_XNP_NP_EXCHANGE))
5337113afc8SEmmanuel Vadot 	       ? xgbe_an73_tx_xnp(pdata, state)
5347113afc8SEmmanuel Vadot 	       : xgbe_an73_tx_training(pdata, state));
53544b781cfSAndrew Turner }
53644b781cfSAndrew Turner 
5377113afc8SEmmanuel Vadot static enum xgbe_an
xgbe_an73_rx_xnp(struct xgbe_prv_data * pdata,enum xgbe_rx * state)5387113afc8SEmmanuel Vadot xgbe_an73_rx_xnp(struct xgbe_prv_data *pdata, enum xgbe_rx *state)
53944b781cfSAndrew Turner {
54044b781cfSAndrew Turner 	unsigned int ad_reg, lp_reg;
54144b781cfSAndrew Turner 
54244b781cfSAndrew Turner 	/* Check Extended Next Page support */
54344b781cfSAndrew Turner 	ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_XNP);
54444b781cfSAndrew Turner 	lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPX);
54544b781cfSAndrew Turner 
5467113afc8SEmmanuel Vadot 	return (((ad_reg & XGBE_XNP_NP_EXCHANGE) ||
54744b781cfSAndrew Turner 		(lp_reg & XGBE_XNP_NP_EXCHANGE))
5487113afc8SEmmanuel Vadot 	       ? xgbe_an73_tx_xnp(pdata, state)
5497113afc8SEmmanuel Vadot 	       : xgbe_an73_tx_training(pdata, state));
55044b781cfSAndrew Turner }
55144b781cfSAndrew Turner 
5527113afc8SEmmanuel Vadot static enum xgbe_an
xgbe_an73_page_received(struct xgbe_prv_data * pdata)5537113afc8SEmmanuel Vadot xgbe_an73_page_received(struct xgbe_prv_data *pdata)
55444b781cfSAndrew Turner {
55544b781cfSAndrew Turner 	enum xgbe_rx *state;
55644b781cfSAndrew Turner 	unsigned long an_timeout;
55744b781cfSAndrew Turner 	enum xgbe_an ret;
55844b781cfSAndrew Turner 
55944b781cfSAndrew Turner 	if (!pdata->an_start) {
5609c6d6488SAndrew Turner 		pdata->an_start = ticks;
56144b781cfSAndrew Turner 	} else {
56244b781cfSAndrew Turner 		an_timeout = pdata->an_start +
5639c6d6488SAndrew Turner 		    ((uint64_t)XGBE_AN_MS_TIMEOUT * (uint64_t)hz) / 1000ull;
5649c6d6488SAndrew Turner 		if ((int)(ticks - an_timeout) > 0) {
56544b781cfSAndrew Turner 			/* Auto-negotiation timed out, reset state */
56644b781cfSAndrew Turner 			pdata->kr_state = XGBE_RX_BPA;
56744b781cfSAndrew Turner 			pdata->kx_state = XGBE_RX_BPA;
56844b781cfSAndrew Turner 
5699c6d6488SAndrew Turner 			pdata->an_start = ticks;
5707113afc8SEmmanuel Vadot 
5717113afc8SEmmanuel Vadot 			axgbe_printf(2, "CL73 AN timed out, resetting state\n");
57244b781cfSAndrew Turner 		}
57344b781cfSAndrew Turner 	}
57444b781cfSAndrew Turner 
5757113afc8SEmmanuel Vadot 	state = xgbe_in_kr_mode(pdata) ? &pdata->kr_state : &pdata->kx_state;
57644b781cfSAndrew Turner 
57744b781cfSAndrew Turner 	switch (*state) {
57844b781cfSAndrew Turner 	case XGBE_RX_BPA:
5797113afc8SEmmanuel Vadot 		ret = xgbe_an73_rx_bpa(pdata, state);
58044b781cfSAndrew Turner 		break;
58144b781cfSAndrew Turner 
58244b781cfSAndrew Turner 	case XGBE_RX_XNP:
5837113afc8SEmmanuel Vadot 		ret = xgbe_an73_rx_xnp(pdata, state);
58444b781cfSAndrew Turner 		break;
58544b781cfSAndrew Turner 
58644b781cfSAndrew Turner 	default:
58744b781cfSAndrew Turner 		ret = XGBE_AN_ERROR;
58844b781cfSAndrew Turner 	}
58944b781cfSAndrew Turner 
5907113afc8SEmmanuel Vadot 	return (ret);
59144b781cfSAndrew Turner }
59244b781cfSAndrew Turner 
5937113afc8SEmmanuel Vadot static enum xgbe_an
xgbe_an73_incompat_link(struct xgbe_prv_data * pdata)5947113afc8SEmmanuel Vadot xgbe_an73_incompat_link(struct xgbe_prv_data *pdata)
59544b781cfSAndrew Turner {
59644b781cfSAndrew Turner 	/* Be sure we aren't looping trying to negotiate */
59744b781cfSAndrew Turner 	if (xgbe_in_kr_mode(pdata)) {
59844b781cfSAndrew Turner 		pdata->kr_state = XGBE_RX_ERROR;
59944b781cfSAndrew Turner 
6007113afc8SEmmanuel Vadot 		if (!(XGBE_ADV(&pdata->phy, 1000baseKX_Full)) &&
6017113afc8SEmmanuel Vadot 		    !(XGBE_ADV(&pdata->phy, 2500baseX_Full)))
6027113afc8SEmmanuel Vadot 			return (XGBE_AN_NO_LINK);
60344b781cfSAndrew Turner 
60444b781cfSAndrew Turner 		if (pdata->kx_state != XGBE_RX_BPA)
6057113afc8SEmmanuel Vadot 			return (XGBE_AN_NO_LINK);
60644b781cfSAndrew Turner 	} else {
60744b781cfSAndrew Turner 		pdata->kx_state = XGBE_RX_ERROR;
60844b781cfSAndrew Turner 
6097113afc8SEmmanuel Vadot 		if (!(XGBE_ADV(&pdata->phy, 10000baseKR_Full)))
6107113afc8SEmmanuel Vadot 			return (XGBE_AN_NO_LINK);
61144b781cfSAndrew Turner 
61244b781cfSAndrew Turner 		if (pdata->kr_state != XGBE_RX_BPA)
6137113afc8SEmmanuel Vadot 			return (XGBE_AN_NO_LINK);
61444b781cfSAndrew Turner 	}
61544b781cfSAndrew Turner 
6167113afc8SEmmanuel Vadot 	xgbe_an_disable(pdata);
61744b781cfSAndrew Turner 
61844b781cfSAndrew Turner 	xgbe_switch_mode(pdata);
61944b781cfSAndrew Turner 
6207113afc8SEmmanuel Vadot 	xgbe_an_restart(pdata);
62144b781cfSAndrew Turner 
6227113afc8SEmmanuel Vadot 	return (XGBE_AN_INCOMPAT_LINK);
62344b781cfSAndrew Turner }
62444b781cfSAndrew Turner 
6257113afc8SEmmanuel Vadot static void
xgbe_an37_isr(struct xgbe_prv_data * pdata)6267113afc8SEmmanuel Vadot xgbe_an37_isr(struct xgbe_prv_data *pdata)
62744b781cfSAndrew Turner {
6287113afc8SEmmanuel Vadot 	unsigned int reg;
62944b781cfSAndrew Turner 
63044b781cfSAndrew Turner 	/* Disable AN interrupts */
6317113afc8SEmmanuel Vadot 	xgbe_an37_disable_interrupts(pdata);
6327113afc8SEmmanuel Vadot 
6337113afc8SEmmanuel Vadot 	/* Save the interrupt(s) that fired */
6347113afc8SEmmanuel Vadot 	reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT);
6357113afc8SEmmanuel Vadot 	pdata->an_int = reg & XGBE_AN_CL37_INT_MASK;
6367113afc8SEmmanuel Vadot 	pdata->an_status = reg & ~XGBE_AN_CL37_INT_MASK;
6377113afc8SEmmanuel Vadot 
6387113afc8SEmmanuel Vadot 	if (pdata->an_int) {
6397113afc8SEmmanuel Vadot 		/* Clear the interrupt(s) that fired and process them */
6407113afc8SEmmanuel Vadot 		reg &= ~XGBE_AN_CL37_INT_MASK;
6417113afc8SEmmanuel Vadot 		XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT, reg);
6427113afc8SEmmanuel Vadot 
6437113afc8SEmmanuel Vadot 		xgbe_an_state_machine(pdata);
6447113afc8SEmmanuel Vadot 	} else {
6457113afc8SEmmanuel Vadot 		/* Enable AN interrupts */
6467113afc8SEmmanuel Vadot 		xgbe_an37_enable_interrupts(pdata);
6477113afc8SEmmanuel Vadot 
6487113afc8SEmmanuel Vadot 		/* Reissue interrupt if status is not clear */
6497113afc8SEmmanuel Vadot 		if (pdata->vdata->irq_reissue_support)
6507113afc8SEmmanuel Vadot 			XP_IOWRITE(pdata, XP_INT_REISSUE_EN, 1 << 3);
6517113afc8SEmmanuel Vadot 	}
6527113afc8SEmmanuel Vadot }
6537113afc8SEmmanuel Vadot 
6547113afc8SEmmanuel Vadot static void
xgbe_an73_isr(struct xgbe_prv_data * pdata)6557113afc8SEmmanuel Vadot xgbe_an73_isr(struct xgbe_prv_data *pdata)
6567113afc8SEmmanuel Vadot {
6577113afc8SEmmanuel Vadot 	/* Disable AN interrupts */
6587113afc8SEmmanuel Vadot 	xgbe_an73_disable_interrupts(pdata);
65944b781cfSAndrew Turner 
66044b781cfSAndrew Turner 	/* Save the interrupt(s) that fired */
66144b781cfSAndrew Turner 	pdata->an_int = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_INT);
66244b781cfSAndrew Turner 
66344b781cfSAndrew Turner 	if (pdata->an_int) {
66444b781cfSAndrew Turner 		/* Clear the interrupt(s) that fired and process them */
66544b781cfSAndrew Turner 		XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, ~pdata->an_int);
66644b781cfSAndrew Turner 
6679c6d6488SAndrew Turner 		xgbe_an_state_machine(pdata);
66844b781cfSAndrew Turner 	} else {
66944b781cfSAndrew Turner 		/* Enable AN interrupts */
6707113afc8SEmmanuel Vadot 		xgbe_an73_enable_interrupts(pdata);
6717113afc8SEmmanuel Vadot 
6727113afc8SEmmanuel Vadot 		/* Reissue interrupt if status is not clear */
6737113afc8SEmmanuel Vadot 		if (pdata->vdata->irq_reissue_support)
6747113afc8SEmmanuel Vadot 			XP_IOWRITE(pdata, XP_INT_REISSUE_EN, 1 << 3);
67544b781cfSAndrew Turner 	}
67644b781cfSAndrew Turner }
67744b781cfSAndrew Turner 
6787113afc8SEmmanuel Vadot static void
xgbe_an_isr_task(unsigned long data)6797113afc8SEmmanuel Vadot xgbe_an_isr_task(unsigned long data)
6807113afc8SEmmanuel Vadot {
6817113afc8SEmmanuel Vadot 	struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)data;
6827113afc8SEmmanuel Vadot 
6837113afc8SEmmanuel Vadot 	axgbe_printf(2, "AN interrupt received\n");
6847113afc8SEmmanuel Vadot 
6857113afc8SEmmanuel Vadot 	switch (pdata->an_mode) {
6867113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL73:
6877113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL73_REDRV:
6887113afc8SEmmanuel Vadot 		xgbe_an73_isr(pdata);
6897113afc8SEmmanuel Vadot 		break;
6907113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL37:
6917113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL37_SGMII:
6927113afc8SEmmanuel Vadot 		xgbe_an37_isr(pdata);
6937113afc8SEmmanuel Vadot 		break;
6947113afc8SEmmanuel Vadot 	default:
6957113afc8SEmmanuel Vadot 		break;
6967113afc8SEmmanuel Vadot 	}
6977113afc8SEmmanuel Vadot }
6987113afc8SEmmanuel Vadot 
6997113afc8SEmmanuel Vadot static void
xgbe_an_combined_isr(struct xgbe_prv_data * pdata)7007113afc8SEmmanuel Vadot xgbe_an_combined_isr(struct xgbe_prv_data *pdata)
7017113afc8SEmmanuel Vadot {
7027113afc8SEmmanuel Vadot 	xgbe_an_isr_task((unsigned long)pdata);
7037113afc8SEmmanuel Vadot }
7047113afc8SEmmanuel Vadot 
7057113afc8SEmmanuel Vadot static const char *
xgbe_state_as_string(enum xgbe_an state)7067113afc8SEmmanuel Vadot xgbe_state_as_string(enum xgbe_an state)
7077113afc8SEmmanuel Vadot {
7087113afc8SEmmanuel Vadot 	switch (state) {
7097113afc8SEmmanuel Vadot 	case XGBE_AN_READY:
7107113afc8SEmmanuel Vadot 		return ("Ready");
7117113afc8SEmmanuel Vadot 	case XGBE_AN_PAGE_RECEIVED:
7127113afc8SEmmanuel Vadot 		return ("Page-Received");
7137113afc8SEmmanuel Vadot 	case XGBE_AN_INCOMPAT_LINK:
7147113afc8SEmmanuel Vadot 		return ("Incompatible-Link");
7157113afc8SEmmanuel Vadot 	case XGBE_AN_COMPLETE:
7167113afc8SEmmanuel Vadot 		return ("Complete");
7177113afc8SEmmanuel Vadot 	case XGBE_AN_NO_LINK:
7187113afc8SEmmanuel Vadot 		return ("No-Link");
7197113afc8SEmmanuel Vadot 	case XGBE_AN_ERROR:
7207113afc8SEmmanuel Vadot 		return ("Error");
7217113afc8SEmmanuel Vadot 	default:
7227113afc8SEmmanuel Vadot 		return ("Undefined");
7237113afc8SEmmanuel Vadot 	}
7247113afc8SEmmanuel Vadot }
7257113afc8SEmmanuel Vadot 
7267113afc8SEmmanuel Vadot static void
xgbe_an37_state_machine(struct xgbe_prv_data * pdata)7277113afc8SEmmanuel Vadot xgbe_an37_state_machine(struct xgbe_prv_data *pdata)
72844b781cfSAndrew Turner {
72944b781cfSAndrew Turner 	enum xgbe_an cur_state = pdata->an_state;
73044b781cfSAndrew Turner 
7317113afc8SEmmanuel Vadot 	if (!pdata->an_int)
7327113afc8SEmmanuel Vadot 		return;
7337113afc8SEmmanuel Vadot 
7347113afc8SEmmanuel Vadot 	if (pdata->an_int & XGBE_AN_CL37_INT_CMPLT) {
7357113afc8SEmmanuel Vadot 		pdata->an_state = XGBE_AN_COMPLETE;
7367113afc8SEmmanuel Vadot 		pdata->an_int &= ~XGBE_AN_CL37_INT_CMPLT;
7377113afc8SEmmanuel Vadot 	}
7387113afc8SEmmanuel Vadot 
7397113afc8SEmmanuel Vadot 	axgbe_printf(2, "%s: CL37 AN %s\n", __func__,
7407113afc8SEmmanuel Vadot 	    xgbe_state_as_string(pdata->an_state));
7417113afc8SEmmanuel Vadot 
7427113afc8SEmmanuel Vadot 	cur_state = pdata->an_state;
7437113afc8SEmmanuel Vadot 
7447113afc8SEmmanuel Vadot 	switch (pdata->an_state) {
7457113afc8SEmmanuel Vadot 	case XGBE_AN_READY:
7467113afc8SEmmanuel Vadot 		break;
7477113afc8SEmmanuel Vadot 
7487113afc8SEmmanuel Vadot 	case XGBE_AN_COMPLETE:
7497113afc8SEmmanuel Vadot 		axgbe_printf(2, "Auto negotiation successful\n");
7507113afc8SEmmanuel Vadot 		break;
7517113afc8SEmmanuel Vadot 
7527113afc8SEmmanuel Vadot 	case XGBE_AN_NO_LINK:
7537113afc8SEmmanuel Vadot 		break;
7547113afc8SEmmanuel Vadot 
7557113afc8SEmmanuel Vadot 	default:
7567113afc8SEmmanuel Vadot 		pdata->an_state = XGBE_AN_ERROR;
7577113afc8SEmmanuel Vadot 	}
7587113afc8SEmmanuel Vadot 
7597113afc8SEmmanuel Vadot 	if (pdata->an_state == XGBE_AN_ERROR) {
7607113afc8SEmmanuel Vadot 		axgbe_printf(2, "error during auto-negotiation, state=%u\n",
7617113afc8SEmmanuel Vadot 		    cur_state);
7627113afc8SEmmanuel Vadot 
7637113afc8SEmmanuel Vadot 		pdata->an_int = 0;
7647113afc8SEmmanuel Vadot 		xgbe_an37_clear_interrupts(pdata);
7657113afc8SEmmanuel Vadot 	}
7667113afc8SEmmanuel Vadot 
7677113afc8SEmmanuel Vadot 	if (pdata->an_state >= XGBE_AN_COMPLETE) {
7687113afc8SEmmanuel Vadot 		pdata->an_result = pdata->an_state;
7697113afc8SEmmanuel Vadot 		pdata->an_state = XGBE_AN_READY;
7707113afc8SEmmanuel Vadot 
7717113afc8SEmmanuel Vadot 		if (pdata->phy_if.phy_impl.an_post)
7727113afc8SEmmanuel Vadot 			pdata->phy_if.phy_impl.an_post(pdata);
7737113afc8SEmmanuel Vadot 
7747113afc8SEmmanuel Vadot 		axgbe_printf(2, "CL37 AN result: %s\n",
7757113afc8SEmmanuel Vadot 		    xgbe_state_as_string(pdata->an_result));
7767113afc8SEmmanuel Vadot 	}
7777113afc8SEmmanuel Vadot 
7787113afc8SEmmanuel Vadot 	axgbe_printf(2, "%s: an_state %d an_int %d an_mode %d an_status %d\n",
7797113afc8SEmmanuel Vadot 	     __func__, pdata->an_state, pdata->an_int, pdata->an_mode,
7807113afc8SEmmanuel Vadot 	     pdata->an_status);
7817113afc8SEmmanuel Vadot 
7827113afc8SEmmanuel Vadot 	xgbe_an37_enable_interrupts(pdata);
7837113afc8SEmmanuel Vadot }
7847113afc8SEmmanuel Vadot 
7857113afc8SEmmanuel Vadot static void
xgbe_an73_state_machine(struct xgbe_prv_data * pdata)7867113afc8SEmmanuel Vadot xgbe_an73_state_machine(struct xgbe_prv_data *pdata)
7877113afc8SEmmanuel Vadot {
7887113afc8SEmmanuel Vadot 	enum xgbe_an cur_state = pdata->an_state;
78944b781cfSAndrew Turner 
79044b781cfSAndrew Turner 	if (!pdata->an_int)
79144b781cfSAndrew Turner 		goto out;
79244b781cfSAndrew Turner 
79344b781cfSAndrew Turner next_int:
7947113afc8SEmmanuel Vadot 	if (pdata->an_int & XGBE_AN_CL73_PG_RCV) {
79544b781cfSAndrew Turner 		pdata->an_state = XGBE_AN_PAGE_RECEIVED;
7967113afc8SEmmanuel Vadot 		pdata->an_int &= ~XGBE_AN_CL73_PG_RCV;
7977113afc8SEmmanuel Vadot 	} else if (pdata->an_int & XGBE_AN_CL73_INC_LINK) {
79844b781cfSAndrew Turner 		pdata->an_state = XGBE_AN_INCOMPAT_LINK;
7997113afc8SEmmanuel Vadot 		pdata->an_int &= ~XGBE_AN_CL73_INC_LINK;
8007113afc8SEmmanuel Vadot 	} else if (pdata->an_int & XGBE_AN_CL73_INT_CMPLT) {
80144b781cfSAndrew Turner 		pdata->an_state = XGBE_AN_COMPLETE;
8027113afc8SEmmanuel Vadot 		pdata->an_int &= ~XGBE_AN_CL73_INT_CMPLT;
80344b781cfSAndrew Turner 	} else {
80444b781cfSAndrew Turner 		pdata->an_state = XGBE_AN_ERROR;
80544b781cfSAndrew Turner 	}
80644b781cfSAndrew Turner 
80744b781cfSAndrew Turner again:
8087113afc8SEmmanuel Vadot 	axgbe_printf(2, "CL73 AN %s\n",
8097113afc8SEmmanuel Vadot 	    xgbe_state_as_string(pdata->an_state));
8107113afc8SEmmanuel Vadot 
81144b781cfSAndrew Turner 	cur_state = pdata->an_state;
81244b781cfSAndrew Turner 
81344b781cfSAndrew Turner 	switch (pdata->an_state) {
81444b781cfSAndrew Turner 	case XGBE_AN_READY:
81544b781cfSAndrew Turner 		pdata->an_supported = 0;
81644b781cfSAndrew Turner 		break;
81744b781cfSAndrew Turner 
81844b781cfSAndrew Turner 	case XGBE_AN_PAGE_RECEIVED:
8197113afc8SEmmanuel Vadot 		pdata->an_state = xgbe_an73_page_received(pdata);
82044b781cfSAndrew Turner 		pdata->an_supported++;
82144b781cfSAndrew Turner 		break;
82244b781cfSAndrew Turner 
82344b781cfSAndrew Turner 	case XGBE_AN_INCOMPAT_LINK:
82444b781cfSAndrew Turner 		pdata->an_supported = 0;
82544b781cfSAndrew Turner 		pdata->parallel_detect = 0;
8267113afc8SEmmanuel Vadot 		pdata->an_state = xgbe_an73_incompat_link(pdata);
82744b781cfSAndrew Turner 		break;
82844b781cfSAndrew Turner 
82944b781cfSAndrew Turner 	case XGBE_AN_COMPLETE:
83044b781cfSAndrew Turner 		pdata->parallel_detect = pdata->an_supported ? 0 : 1;
8317113afc8SEmmanuel Vadot 		axgbe_printf(2, "%s successful\n",
8327113afc8SEmmanuel Vadot 		    pdata->an_supported ? "Auto negotiation"
8337113afc8SEmmanuel Vadot 		    : "Parallel detection");
83444b781cfSAndrew Turner 		break;
83544b781cfSAndrew Turner 
83644b781cfSAndrew Turner 	case XGBE_AN_NO_LINK:
83744b781cfSAndrew Turner 		break;
83844b781cfSAndrew Turner 
83944b781cfSAndrew Turner 	default:
84044b781cfSAndrew Turner 		pdata->an_state = XGBE_AN_ERROR;
84144b781cfSAndrew Turner 	}
84244b781cfSAndrew Turner 
84344b781cfSAndrew Turner 	if (pdata->an_state == XGBE_AN_NO_LINK) {
84444b781cfSAndrew Turner 		pdata->an_int = 0;
8457113afc8SEmmanuel Vadot 		xgbe_an73_clear_interrupts(pdata);
84644b781cfSAndrew Turner 	} else if (pdata->an_state == XGBE_AN_ERROR) {
8477113afc8SEmmanuel Vadot 		axgbe_printf(2,
8487113afc8SEmmanuel Vadot 		    "error during auto-negotiation, state=%u\n",
8497113afc8SEmmanuel Vadot 		    cur_state);
8507113afc8SEmmanuel Vadot 
85144b781cfSAndrew Turner 		pdata->an_int = 0;
8527113afc8SEmmanuel Vadot 		xgbe_an73_clear_interrupts(pdata);
85344b781cfSAndrew Turner 	}
85444b781cfSAndrew Turner 
85544b781cfSAndrew Turner 	if (pdata->an_state >= XGBE_AN_COMPLETE) {
85644b781cfSAndrew Turner 		pdata->an_result = pdata->an_state;
85744b781cfSAndrew Turner 		pdata->an_state = XGBE_AN_READY;
85844b781cfSAndrew Turner 		pdata->kr_state = XGBE_RX_BPA;
85944b781cfSAndrew Turner 		pdata->kx_state = XGBE_RX_BPA;
86044b781cfSAndrew Turner 		pdata->an_start = 0;
8617113afc8SEmmanuel Vadot 
8627113afc8SEmmanuel Vadot 		if (pdata->phy_if.phy_impl.an_post)
8637113afc8SEmmanuel Vadot 			pdata->phy_if.phy_impl.an_post(pdata);
8647113afc8SEmmanuel Vadot 
8657113afc8SEmmanuel Vadot 		axgbe_printf(2,  "CL73 AN result: %s\n",
8667113afc8SEmmanuel Vadot 		    xgbe_state_as_string(pdata->an_result));
86744b781cfSAndrew Turner 	}
86844b781cfSAndrew Turner 
86944b781cfSAndrew Turner 	if (cur_state != pdata->an_state)
87044b781cfSAndrew Turner 		goto again;
87144b781cfSAndrew Turner 
87244b781cfSAndrew Turner 	if (pdata->an_int)
87344b781cfSAndrew Turner 		goto next_int;
87444b781cfSAndrew Turner 
87544b781cfSAndrew Turner out:
87644b781cfSAndrew Turner 	/* Enable AN interrupts on the way out */
8777113afc8SEmmanuel Vadot 	xgbe_an73_enable_interrupts(pdata);
8787113afc8SEmmanuel Vadot }
8797113afc8SEmmanuel Vadot 
8807113afc8SEmmanuel Vadot static void
xgbe_an_state_machine(struct xgbe_prv_data * pdata)8817113afc8SEmmanuel Vadot xgbe_an_state_machine(struct xgbe_prv_data *pdata)
8827113afc8SEmmanuel Vadot {
8837113afc8SEmmanuel Vadot 	sx_xlock(&pdata->an_mutex);
8847113afc8SEmmanuel Vadot 
8857113afc8SEmmanuel Vadot 	switch (pdata->an_mode) {
8867113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL73:
8877113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL73_REDRV:
8887113afc8SEmmanuel Vadot 		xgbe_an73_state_machine(pdata);
8897113afc8SEmmanuel Vadot 		break;
8907113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL37:
8917113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL37_SGMII:
8927113afc8SEmmanuel Vadot 		xgbe_an37_state_machine(pdata);
8937113afc8SEmmanuel Vadot 		break;
8947113afc8SEmmanuel Vadot 	default:
8957113afc8SEmmanuel Vadot 		break;
8967113afc8SEmmanuel Vadot 	}
8977113afc8SEmmanuel Vadot 
8987113afc8SEmmanuel Vadot 	/* Reissue interrupt if status is not clear */
8997113afc8SEmmanuel Vadot 	if (pdata->vdata->irq_reissue_support)
9007113afc8SEmmanuel Vadot 		XP_IOWRITE(pdata, XP_INT_REISSUE_EN, 1 << 3);
90144b781cfSAndrew Turner 
9029c6d6488SAndrew Turner 	sx_xunlock(&pdata->an_mutex);
90344b781cfSAndrew Turner }
90444b781cfSAndrew Turner 
9057113afc8SEmmanuel Vadot static void
xgbe_an37_init(struct xgbe_prv_data * pdata)9067113afc8SEmmanuel Vadot xgbe_an37_init(struct xgbe_prv_data *pdata)
90744b781cfSAndrew Turner {
9087113afc8SEmmanuel Vadot 	struct xgbe_phy local_phy;
90944b781cfSAndrew Turner 	unsigned int reg;
91044b781cfSAndrew Turner 
9117113afc8SEmmanuel Vadot 	pdata->phy_if.phy_impl.an_advertising(pdata, &local_phy);
9127113afc8SEmmanuel Vadot 
9137113afc8SEmmanuel Vadot 	axgbe_printf(2, "%s: advertising 0x%x\n", __func__, local_phy.advertising);
9147113afc8SEmmanuel Vadot 
9157113afc8SEmmanuel Vadot 	/* Set up Advertisement register */
9167113afc8SEmmanuel Vadot 	reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_ADVERTISE);
9177113afc8SEmmanuel Vadot 	if (XGBE_ADV(&local_phy, Pause))
9187113afc8SEmmanuel Vadot 		reg |= 0x100;
9197113afc8SEmmanuel Vadot 	else
9207113afc8SEmmanuel Vadot 		reg &= ~0x100;
9217113afc8SEmmanuel Vadot 
9227113afc8SEmmanuel Vadot 	if (XGBE_ADV(&local_phy, Asym_Pause))
9237113afc8SEmmanuel Vadot 		reg |= 0x80;
9247113afc8SEmmanuel Vadot 	else
9257113afc8SEmmanuel Vadot 		reg &= ~0x80;
9267113afc8SEmmanuel Vadot 
9277113afc8SEmmanuel Vadot 	/* Full duplex, but not half */
9287113afc8SEmmanuel Vadot 	reg |= XGBE_AN_CL37_FD_MASK;
9297113afc8SEmmanuel Vadot 	reg &= ~XGBE_AN_CL37_HD_MASK;
9307113afc8SEmmanuel Vadot 
9317113afc8SEmmanuel Vadot 	axgbe_printf(2, "%s: Writing reg: 0x%x\n", __func__, reg);
9327113afc8SEmmanuel Vadot 	XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_ADVERTISE, reg);
9337113afc8SEmmanuel Vadot 
9347113afc8SEmmanuel Vadot 	/* Set up the Control register */
9357113afc8SEmmanuel Vadot 	reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL);
9367113afc8SEmmanuel Vadot 	axgbe_printf(2, "%s: AN_ADVERTISE reg 0x%x an_mode %d\n", __func__,
9377113afc8SEmmanuel Vadot 	    reg, pdata->an_mode);
9387113afc8SEmmanuel Vadot 	reg &= ~XGBE_AN_CL37_TX_CONFIG_MASK;
9397113afc8SEmmanuel Vadot 	reg &= ~XGBE_AN_CL37_PCS_MODE_MASK;
9407113afc8SEmmanuel Vadot 
9417113afc8SEmmanuel Vadot 	switch (pdata->an_mode) {
9427113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL37:
9437113afc8SEmmanuel Vadot 		reg |= XGBE_AN_CL37_PCS_MODE_BASEX;
9447113afc8SEmmanuel Vadot 		break;
9457113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL37_SGMII:
9467113afc8SEmmanuel Vadot 		reg |= XGBE_AN_CL37_PCS_MODE_SGMII;
9477113afc8SEmmanuel Vadot 		break;
9487113afc8SEmmanuel Vadot 	default:
9497113afc8SEmmanuel Vadot 		break;
9507113afc8SEmmanuel Vadot 	}
9517113afc8SEmmanuel Vadot 
9527113afc8SEmmanuel Vadot 	reg |= XGBE_AN_CL37_MII_CTRL_8BIT;
9537113afc8SEmmanuel Vadot 	axgbe_printf(2, "%s: Writing reg: 0x%x\n", __func__, reg);
9547113afc8SEmmanuel Vadot 	XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL, reg);
9557113afc8SEmmanuel Vadot 
9567113afc8SEmmanuel Vadot 	axgbe_printf(2, "CL37 AN (%s) initialized\n",
9577113afc8SEmmanuel Vadot 	    (pdata->an_mode == XGBE_AN_MODE_CL37) ? "BaseX" : "SGMII");
9587113afc8SEmmanuel Vadot }
9597113afc8SEmmanuel Vadot 
9607113afc8SEmmanuel Vadot static void
xgbe_an73_init(struct xgbe_prv_data * pdata)9617113afc8SEmmanuel Vadot xgbe_an73_init(struct xgbe_prv_data *pdata)
9627113afc8SEmmanuel Vadot {
9637113afc8SEmmanuel Vadot 	/*
9647113afc8SEmmanuel Vadot 	 * This local_phy is needed because phy-v2 alters the
9657113afc8SEmmanuel Vadot 	 * advertising flag variable. so phy-v1 an_advertising is just copying
9667113afc8SEmmanuel Vadot 	 */
9677113afc8SEmmanuel Vadot 	struct xgbe_phy local_phy;
9687113afc8SEmmanuel Vadot 	unsigned int reg;
9697113afc8SEmmanuel Vadot 
9707113afc8SEmmanuel Vadot 	pdata->phy_if.phy_impl.an_advertising(pdata, &local_phy);
9717113afc8SEmmanuel Vadot 
97244b781cfSAndrew Turner 	/* Set up Advertisement register 3 first */
97344b781cfSAndrew Turner 	reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
9747113afc8SEmmanuel Vadot 	if (XGBE_ADV(&local_phy, 10000baseR_FEC))
9757113afc8SEmmanuel Vadot 		reg |= 0xc000;
9767113afc8SEmmanuel Vadot 	else
97744b781cfSAndrew Turner 		reg &= ~0xc000;
97844b781cfSAndrew Turner 
97944b781cfSAndrew Turner 	XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2, reg);
98044b781cfSAndrew Turner 
98144b781cfSAndrew Turner 	/* Set up Advertisement register 2 next */
98244b781cfSAndrew Turner 	reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1);
9837113afc8SEmmanuel Vadot 	if (XGBE_ADV(&local_phy, 10000baseKR_Full))
98444b781cfSAndrew Turner 		reg |= 0x80;
98544b781cfSAndrew Turner 	else
98644b781cfSAndrew Turner 		reg &= ~0x80;
98744b781cfSAndrew Turner 
9887113afc8SEmmanuel Vadot 	if (XGBE_ADV(&local_phy, 1000baseKX_Full) ||
9897113afc8SEmmanuel Vadot 	    XGBE_ADV(&local_phy, 2500baseX_Full))
99044b781cfSAndrew Turner 		reg |= 0x20;
99144b781cfSAndrew Turner 	else
99244b781cfSAndrew Turner 		reg &= ~0x20;
99344b781cfSAndrew Turner 
99444b781cfSAndrew Turner 	XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1, reg);
99544b781cfSAndrew Turner 
99644b781cfSAndrew Turner 	/* Set up Advertisement register 1 last */
99744b781cfSAndrew Turner 	reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
9987113afc8SEmmanuel Vadot 	if (XGBE_ADV(&local_phy, Pause))
99944b781cfSAndrew Turner 		reg |= 0x400;
100044b781cfSAndrew Turner 	else
100144b781cfSAndrew Turner 		reg &= ~0x400;
100244b781cfSAndrew Turner 
10037113afc8SEmmanuel Vadot 	if (XGBE_ADV(&local_phy, Asym_Pause))
100444b781cfSAndrew Turner 		reg |= 0x800;
100544b781cfSAndrew Turner 	else
100644b781cfSAndrew Turner 		reg &= ~0x800;
100744b781cfSAndrew Turner 
100844b781cfSAndrew Turner 	/* We don't intend to perform XNP */
100944b781cfSAndrew Turner 	reg &= ~XGBE_XNP_NP_EXCHANGE;
101044b781cfSAndrew Turner 
101144b781cfSAndrew Turner 	XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg);
10127113afc8SEmmanuel Vadot 
10137113afc8SEmmanuel Vadot 	axgbe_printf(2, "CL73 AN initialized\n");
101444b781cfSAndrew Turner }
101544b781cfSAndrew Turner 
10167113afc8SEmmanuel Vadot static void
xgbe_an_init(struct xgbe_prv_data * pdata)10177113afc8SEmmanuel Vadot xgbe_an_init(struct xgbe_prv_data *pdata)
101844b781cfSAndrew Turner {
10197113afc8SEmmanuel Vadot 	/* Set up advertisement registers based on current settings */
10207113afc8SEmmanuel Vadot 	pdata->an_mode = pdata->phy_if.phy_impl.an_mode(pdata);
10217113afc8SEmmanuel Vadot 	axgbe_printf(2, "%s: setting up an_mode %d\n", __func__, pdata->an_mode);
10227113afc8SEmmanuel Vadot 
10237113afc8SEmmanuel Vadot 	switch (pdata->an_mode) {
10247113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL73:
10257113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL73_REDRV:
10267113afc8SEmmanuel Vadot 		xgbe_an73_init(pdata);
10277113afc8SEmmanuel Vadot 		break;
10287113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL37:
10297113afc8SEmmanuel Vadot 	case XGBE_AN_MODE_CL37_SGMII:
10307113afc8SEmmanuel Vadot 		xgbe_an37_init(pdata);
10317113afc8SEmmanuel Vadot 		break;
10327113afc8SEmmanuel Vadot 	default:
10337113afc8SEmmanuel Vadot 		break;
10347113afc8SEmmanuel Vadot 	}
10357113afc8SEmmanuel Vadot }
10367113afc8SEmmanuel Vadot 
10377113afc8SEmmanuel Vadot static const char *
xgbe_phy_fc_string(struct xgbe_prv_data * pdata)10387113afc8SEmmanuel Vadot xgbe_phy_fc_string(struct xgbe_prv_data *pdata)
10397113afc8SEmmanuel Vadot {
10407113afc8SEmmanuel Vadot 	if (pdata->tx_pause && pdata->rx_pause)
10417113afc8SEmmanuel Vadot 		return ("rx/tx");
10427113afc8SEmmanuel Vadot 	else if (pdata->rx_pause)
10437113afc8SEmmanuel Vadot 		return ("rx");
10447113afc8SEmmanuel Vadot 	else if (pdata->tx_pause)
10457113afc8SEmmanuel Vadot 		return ("tx");
10467113afc8SEmmanuel Vadot 	else
10477113afc8SEmmanuel Vadot 		return ("off");
10487113afc8SEmmanuel Vadot }
10497113afc8SEmmanuel Vadot 
10507113afc8SEmmanuel Vadot static const char *
xgbe_phy_speed_string(int speed)10517113afc8SEmmanuel Vadot xgbe_phy_speed_string(int speed)
10527113afc8SEmmanuel Vadot {
10537113afc8SEmmanuel Vadot 	switch (speed) {
10547113afc8SEmmanuel Vadot 	case SPEED_100:
10557113afc8SEmmanuel Vadot 		return ("100Mbps");
10567113afc8SEmmanuel Vadot 	case SPEED_1000:
10577113afc8SEmmanuel Vadot 		return ("1Gbps");
10587113afc8SEmmanuel Vadot 	case SPEED_2500:
10597113afc8SEmmanuel Vadot 		return ("2.5Gbps");
10607113afc8SEmmanuel Vadot 	case SPEED_10000:
10617113afc8SEmmanuel Vadot 		return ("10Gbps");
10627113afc8SEmmanuel Vadot 	case SPEED_UNKNOWN:
10637113afc8SEmmanuel Vadot 		return ("Unknown");
10647113afc8SEmmanuel Vadot 	default:
10657113afc8SEmmanuel Vadot 		return ("Unsupported");
10667113afc8SEmmanuel Vadot 	}
10677113afc8SEmmanuel Vadot }
10687113afc8SEmmanuel Vadot 
10697113afc8SEmmanuel Vadot static void
xgbe_phy_print_status(struct xgbe_prv_data * pdata)10707113afc8SEmmanuel Vadot xgbe_phy_print_status(struct xgbe_prv_data *pdata)
10717113afc8SEmmanuel Vadot {
10727113afc8SEmmanuel Vadot 	if (pdata->phy.link)
10737113afc8SEmmanuel Vadot 		axgbe_printf(0,
10747113afc8SEmmanuel Vadot 		    "Link is UP - %s/%s - flow control %s\n",
10757113afc8SEmmanuel Vadot 		    xgbe_phy_speed_string(pdata->phy.speed),
10767113afc8SEmmanuel Vadot 		    pdata->phy.duplex == DUPLEX_FULL ? "Full" : "Half",
10777113afc8SEmmanuel Vadot 		    xgbe_phy_fc_string(pdata));
10787113afc8SEmmanuel Vadot 	else
10797113afc8SEmmanuel Vadot 		axgbe_printf(0, "Link is DOWN\n");
10807113afc8SEmmanuel Vadot }
10817113afc8SEmmanuel Vadot 
10827113afc8SEmmanuel Vadot static void
xgbe_phy_adjust_link(struct xgbe_prv_data * pdata)10837113afc8SEmmanuel Vadot xgbe_phy_adjust_link(struct xgbe_prv_data *pdata)
10847113afc8SEmmanuel Vadot {
10857113afc8SEmmanuel Vadot 	int new_state = 0;
10867113afc8SEmmanuel Vadot 
10877113afc8SEmmanuel Vadot 	axgbe_printf(1, "link %d/%d tx %d/%d rx %d/%d speed %d/%d autoneg %d/%d\n",
10887113afc8SEmmanuel Vadot 	    pdata->phy_link, pdata->phy.link,
10897113afc8SEmmanuel Vadot 	    pdata->tx_pause, pdata->phy.tx_pause,
10907113afc8SEmmanuel Vadot 	    pdata->rx_pause, pdata->phy.rx_pause,
10917113afc8SEmmanuel Vadot 	    pdata->phy_speed, pdata->phy.speed,
10927113afc8SEmmanuel Vadot 	    pdata->pause_autoneg, pdata->phy.pause_autoneg);
109344b781cfSAndrew Turner 
109444b781cfSAndrew Turner 	if (pdata->phy.link) {
109544b781cfSAndrew Turner 		/* Flow control support */
109644b781cfSAndrew Turner 		pdata->pause_autoneg = pdata->phy.pause_autoneg;
109744b781cfSAndrew Turner 
109844b781cfSAndrew Turner 		if (pdata->tx_pause != pdata->phy.tx_pause) {
10997113afc8SEmmanuel Vadot 			new_state = 1;
11007113afc8SEmmanuel Vadot 			axgbe_printf(2, "tx pause %d/%d\n", pdata->tx_pause,
11017113afc8SEmmanuel Vadot 			    pdata->phy.tx_pause);
110244b781cfSAndrew Turner 			pdata->tx_pause = pdata->phy.tx_pause;
11037113afc8SEmmanuel Vadot 			pdata->hw_if.config_tx_flow_control(pdata);
110444b781cfSAndrew Turner 		}
110544b781cfSAndrew Turner 
110644b781cfSAndrew Turner 		if (pdata->rx_pause != pdata->phy.rx_pause) {
11077113afc8SEmmanuel Vadot 			new_state = 1;
11087113afc8SEmmanuel Vadot 			axgbe_printf(2, "rx pause %d/%d\n", pdata->rx_pause,
11097113afc8SEmmanuel Vadot 			    pdata->phy.rx_pause);
111044b781cfSAndrew Turner 			pdata->rx_pause = pdata->phy.rx_pause;
11117113afc8SEmmanuel Vadot 			pdata->hw_if.config_rx_flow_control(pdata);
111244b781cfSAndrew Turner 		}
111344b781cfSAndrew Turner 
111444b781cfSAndrew Turner 		/* Speed support */
111544b781cfSAndrew Turner 		if (pdata->phy_speed != pdata->phy.speed) {
11167113afc8SEmmanuel Vadot 			new_state = 1;
111744b781cfSAndrew Turner 			pdata->phy_speed = pdata->phy.speed;
111844b781cfSAndrew Turner 		}
111944b781cfSAndrew Turner 
112044b781cfSAndrew Turner 		if (pdata->phy_link != pdata->phy.link) {
11217113afc8SEmmanuel Vadot 			new_state = 1;
112244b781cfSAndrew Turner 			pdata->phy_link = pdata->phy.link;
112344b781cfSAndrew Turner 		}
112444b781cfSAndrew Turner 	} else if (pdata->phy_link) {
11257113afc8SEmmanuel Vadot 		new_state = 1;
112644b781cfSAndrew Turner 		pdata->phy_link = 0;
112744b781cfSAndrew Turner 		pdata->phy_speed = SPEED_UNKNOWN;
112844b781cfSAndrew Turner 	}
11297113afc8SEmmanuel Vadot 
11307113afc8SEmmanuel Vadot 	axgbe_printf(2, "phy_link %d Link %d new_state %d\n", pdata->phy_link,
11317113afc8SEmmanuel Vadot 	    pdata->phy.link, new_state);
11327113afc8SEmmanuel Vadot 
11337113afc8SEmmanuel Vadot 	if (new_state)
11347113afc8SEmmanuel Vadot 		xgbe_phy_print_status(pdata);
113544b781cfSAndrew Turner }
113644b781cfSAndrew Turner 
11377113afc8SEmmanuel Vadot static bool
xgbe_phy_valid_speed(struct xgbe_prv_data * pdata,int speed)11387113afc8SEmmanuel Vadot xgbe_phy_valid_speed(struct xgbe_prv_data *pdata, int speed)
113944b781cfSAndrew Turner {
11407113afc8SEmmanuel Vadot 	return (pdata->phy_if.phy_impl.valid_speed(pdata, speed));
11417113afc8SEmmanuel Vadot }
11427113afc8SEmmanuel Vadot 
11437113afc8SEmmanuel Vadot static int
xgbe_phy_config_fixed(struct xgbe_prv_data * pdata)11447113afc8SEmmanuel Vadot xgbe_phy_config_fixed(struct xgbe_prv_data *pdata)
11457113afc8SEmmanuel Vadot {
11467113afc8SEmmanuel Vadot 	enum xgbe_mode mode;
11477113afc8SEmmanuel Vadot 
11487113afc8SEmmanuel Vadot 	axgbe_printf(2, "fixed PHY configuration\n");
114944b781cfSAndrew Turner 
115044b781cfSAndrew Turner 	/* Disable auto-negotiation */
11517113afc8SEmmanuel Vadot 	xgbe_an_disable(pdata);
115244b781cfSAndrew Turner 
11537113afc8SEmmanuel Vadot 	/* Set specified mode for specified speed */
11547113afc8SEmmanuel Vadot 	mode = pdata->phy_if.phy_impl.get_mode(pdata, pdata->phy.speed);
11557113afc8SEmmanuel Vadot 	switch (mode) {
11567113afc8SEmmanuel Vadot 	case XGBE_MODE_KX_1000:
11577113afc8SEmmanuel Vadot 	case XGBE_MODE_KX_2500:
11587113afc8SEmmanuel Vadot 	case XGBE_MODE_KR:
11597113afc8SEmmanuel Vadot 	case XGBE_MODE_SGMII_100:
11607113afc8SEmmanuel Vadot 	case XGBE_MODE_SGMII_1000:
11617113afc8SEmmanuel Vadot 	case XGBE_MODE_X:
11627113afc8SEmmanuel Vadot 	case XGBE_MODE_SFI:
116344b781cfSAndrew Turner 		break;
11647113afc8SEmmanuel Vadot 	case XGBE_MODE_UNKNOWN:
116544b781cfSAndrew Turner 	default:
11667113afc8SEmmanuel Vadot 		return (-EINVAL);
116744b781cfSAndrew Turner 	}
116844b781cfSAndrew Turner 
116944b781cfSAndrew Turner 	/* Validate duplex mode */
117044b781cfSAndrew Turner 	if (pdata->phy.duplex != DUPLEX_FULL)
11717113afc8SEmmanuel Vadot 		return (-EINVAL);
117244b781cfSAndrew Turner 
11737113afc8SEmmanuel Vadot 	xgbe_set_mode(pdata, mode);
11747113afc8SEmmanuel Vadot 
11757113afc8SEmmanuel Vadot 	return (0);
117644b781cfSAndrew Turner }
117744b781cfSAndrew Turner 
11787113afc8SEmmanuel Vadot static int
__xgbe_phy_config_aneg(struct xgbe_prv_data * pdata,bool set_mode)11797113afc8SEmmanuel Vadot __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata, bool set_mode)
118044b781cfSAndrew Turner {
11817113afc8SEmmanuel Vadot 	int ret;
118294e3e7d2SAdrian Chadd 	unsigned int reg = 0;
11837113afc8SEmmanuel Vadot 
11847113afc8SEmmanuel Vadot 	sx_xlock(&pdata->an_mutex);
11857113afc8SEmmanuel Vadot 
118644b781cfSAndrew Turner 	set_bit(XGBE_LINK_INIT, &pdata->dev_state);
11879c6d6488SAndrew Turner 	pdata->link_check = ticks;
118844b781cfSAndrew Turner 
11897113afc8SEmmanuel Vadot 	ret = pdata->phy_if.phy_impl.an_config(pdata);
11907113afc8SEmmanuel Vadot 	if (ret) {
11917113afc8SEmmanuel Vadot 		axgbe_error("%s: an_config fail %d\n", __func__, ret);
11927113afc8SEmmanuel Vadot 		goto out;
11937113afc8SEmmanuel Vadot 	}
11947113afc8SEmmanuel Vadot 
11957113afc8SEmmanuel Vadot 	if (pdata->phy.autoneg != AUTONEG_ENABLE) {
11967113afc8SEmmanuel Vadot 		ret = xgbe_phy_config_fixed(pdata);
11977113afc8SEmmanuel Vadot 		if (ret || !pdata->kr_redrv) {
11987113afc8SEmmanuel Vadot 			if (ret)
11997113afc8SEmmanuel Vadot 				axgbe_error("%s: fix conf fail %d\n", __func__, ret);
12007113afc8SEmmanuel Vadot 			goto out;
12017113afc8SEmmanuel Vadot 		}
12027113afc8SEmmanuel Vadot 
12037113afc8SEmmanuel Vadot 		axgbe_printf(2, "AN redriver support\n");
12047113afc8SEmmanuel Vadot 	} else
12057113afc8SEmmanuel Vadot 		axgbe_printf(2, "AN PHY configuration\n");
120644b781cfSAndrew Turner 
120744b781cfSAndrew Turner 	/* Disable auto-negotiation interrupt */
12089c6d6488SAndrew Turner 	XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, 0);
12097113afc8SEmmanuel Vadot 	reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK);
12107113afc8SEmmanuel Vadot 	axgbe_printf(2, "%s: set_mode %d AN int reg value 0x%x\n", __func__,
12117113afc8SEmmanuel Vadot 	    set_mode, reg);
12129c6d6488SAndrew Turner 
12139c6d6488SAndrew Turner 	/* Clear any auto-negotitation interrupts */
12149c6d6488SAndrew Turner 	XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0);
121544b781cfSAndrew Turner 
121644b781cfSAndrew Turner 	/* Start auto-negotiation in a supported mode */
12177113afc8SEmmanuel Vadot 	if (set_mode) {
12187113afc8SEmmanuel Vadot 		/* Start auto-negotiation in a supported mode */
12197113afc8SEmmanuel Vadot 		if (xgbe_use_mode(pdata, XGBE_MODE_KR)) {
122044b781cfSAndrew Turner 			xgbe_set_mode(pdata, XGBE_MODE_KR);
12217113afc8SEmmanuel Vadot 		} else if (xgbe_use_mode(pdata, XGBE_MODE_KX_2500)) {
12227113afc8SEmmanuel Vadot 			xgbe_set_mode(pdata, XGBE_MODE_KX_2500);
12237113afc8SEmmanuel Vadot 		} else if (xgbe_use_mode(pdata, XGBE_MODE_KX_1000)) {
12247113afc8SEmmanuel Vadot 			xgbe_set_mode(pdata, XGBE_MODE_KX_1000);
12257113afc8SEmmanuel Vadot 		} else if (xgbe_use_mode(pdata, XGBE_MODE_SFI)) {
12267113afc8SEmmanuel Vadot 			xgbe_set_mode(pdata, XGBE_MODE_SFI);
12277113afc8SEmmanuel Vadot 		} else if (xgbe_use_mode(pdata, XGBE_MODE_X)) {
12287113afc8SEmmanuel Vadot 			xgbe_set_mode(pdata, XGBE_MODE_X);
12297113afc8SEmmanuel Vadot 		} else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_1000)) {
12307113afc8SEmmanuel Vadot 			xgbe_set_mode(pdata, XGBE_MODE_SGMII_1000);
12317113afc8SEmmanuel Vadot 		} else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_100)) {
12327113afc8SEmmanuel Vadot 			xgbe_set_mode(pdata, XGBE_MODE_SGMII_100);
123344b781cfSAndrew Turner 		} else {
12349c6d6488SAndrew Turner 			XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, 0x07);
12357113afc8SEmmanuel Vadot 			ret = -EINVAL;
12367113afc8SEmmanuel Vadot 			goto out;
12377113afc8SEmmanuel Vadot 		}
123844b781cfSAndrew Turner 	}
123944b781cfSAndrew Turner 
124044b781cfSAndrew Turner 	/* Disable and stop any in progress auto-negotiation */
12417113afc8SEmmanuel Vadot 	xgbe_an_disable_all(pdata);
124244b781cfSAndrew Turner 
124344b781cfSAndrew Turner 	/* Clear any auto-negotitation interrupts */
12447113afc8SEmmanuel Vadot 	xgbe_an_clear_interrupts_all(pdata);
124544b781cfSAndrew Turner 
124644b781cfSAndrew Turner 	pdata->an_result = XGBE_AN_READY;
124744b781cfSAndrew Turner 	pdata->an_state = XGBE_AN_READY;
124844b781cfSAndrew Turner 	pdata->kr_state = XGBE_RX_BPA;
124944b781cfSAndrew Turner 	pdata->kx_state = XGBE_RX_BPA;
125044b781cfSAndrew Turner 
125144b781cfSAndrew Turner 	/* Re-enable auto-negotiation interrupt */
12529c6d6488SAndrew Turner 	XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, 0x07);
12537113afc8SEmmanuel Vadot 	reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK);
125444b781cfSAndrew Turner 
125544b781cfSAndrew Turner 	/* Set up advertisement registers based on current settings */
125644b781cfSAndrew Turner 	xgbe_an_init(pdata);
125744b781cfSAndrew Turner 
125844b781cfSAndrew Turner 	/* Enable and start auto-negotiation */
12597113afc8SEmmanuel Vadot 	xgbe_an_restart(pdata);
126044b781cfSAndrew Turner 
12617113afc8SEmmanuel Vadot out:
12627113afc8SEmmanuel Vadot 	if (ret) {
12637113afc8SEmmanuel Vadot 		axgbe_printf(0, "%s: set_mode %d AN int reg value 0x%x ret value %d\n",
12647113afc8SEmmanuel Vadot 		   __func__, set_mode, reg, ret);
126544b781cfSAndrew Turner 		set_bit(XGBE_LINK_ERR, &pdata->dev_state);
12667113afc8SEmmanuel Vadot 	} else
126744b781cfSAndrew Turner 		clear_bit(XGBE_LINK_ERR, &pdata->dev_state);
126844b781cfSAndrew Turner 
12699c6d6488SAndrew Turner 	sx_unlock(&pdata->an_mutex);
127044b781cfSAndrew Turner 
12717113afc8SEmmanuel Vadot 	return (ret);
127244b781cfSAndrew Turner }
127344b781cfSAndrew Turner 
12747113afc8SEmmanuel Vadot static int
xgbe_phy_config_aneg(struct xgbe_prv_data * pdata)12757113afc8SEmmanuel Vadot xgbe_phy_config_aneg(struct xgbe_prv_data *pdata)
12767113afc8SEmmanuel Vadot {
12777113afc8SEmmanuel Vadot 	return (__xgbe_phy_config_aneg(pdata, true));
12787113afc8SEmmanuel Vadot }
12797113afc8SEmmanuel Vadot 
12807113afc8SEmmanuel Vadot static int
xgbe_phy_reconfig_aneg(struct xgbe_prv_data * pdata)12817113afc8SEmmanuel Vadot xgbe_phy_reconfig_aneg(struct xgbe_prv_data *pdata)
12827113afc8SEmmanuel Vadot {
12837113afc8SEmmanuel Vadot 	return (__xgbe_phy_config_aneg(pdata, false));
12847113afc8SEmmanuel Vadot }
12857113afc8SEmmanuel Vadot 
12867113afc8SEmmanuel Vadot static bool
xgbe_phy_aneg_done(struct xgbe_prv_data * pdata)12877113afc8SEmmanuel Vadot xgbe_phy_aneg_done(struct xgbe_prv_data *pdata)
128844b781cfSAndrew Turner {
128944b781cfSAndrew Turner 	return (pdata->an_result == XGBE_AN_COMPLETE);
129044b781cfSAndrew Turner }
129144b781cfSAndrew Turner 
12927113afc8SEmmanuel Vadot static void
xgbe_check_link_timeout(struct xgbe_prv_data * pdata)12937113afc8SEmmanuel Vadot xgbe_check_link_timeout(struct xgbe_prv_data *pdata)
129444b781cfSAndrew Turner {
129544b781cfSAndrew Turner 	unsigned long link_timeout;
129644b781cfSAndrew Turner 
12979c6d6488SAndrew Turner 	link_timeout = pdata->link_check + (XGBE_LINK_TIMEOUT * hz);
12987113afc8SEmmanuel Vadot 	if ((int)(ticks - link_timeout) > 0) {
12997113afc8SEmmanuel Vadot 		axgbe_printf(2, "AN link timeout\n");
130044b781cfSAndrew Turner 		xgbe_phy_config_aneg(pdata);
130144b781cfSAndrew Turner 	}
130244b781cfSAndrew Turner }
130344b781cfSAndrew Turner 
13047113afc8SEmmanuel Vadot static enum xgbe_mode
xgbe_phy_status_aneg(struct xgbe_prv_data * pdata)13057113afc8SEmmanuel Vadot xgbe_phy_status_aneg(struct xgbe_prv_data *pdata)
130644b781cfSAndrew Turner {
13077113afc8SEmmanuel Vadot 	return (pdata->phy_if.phy_impl.an_outcome(pdata));
130844b781cfSAndrew Turner }
130944b781cfSAndrew Turner 
13107113afc8SEmmanuel Vadot static void
xgbe_phy_status_result(struct xgbe_prv_data * pdata)13117113afc8SEmmanuel Vadot xgbe_phy_status_result(struct xgbe_prv_data *pdata)
131244b781cfSAndrew Turner {
13137113afc8SEmmanuel Vadot 	enum xgbe_mode mode;
131444b781cfSAndrew Turner 
13157113afc8SEmmanuel Vadot 	XGBE_ZERO_LP_ADV(&pdata->phy);
131644b781cfSAndrew Turner 
131744b781cfSAndrew Turner 	if ((pdata->phy.autoneg != AUTONEG_ENABLE) || pdata->parallel_detect)
13187113afc8SEmmanuel Vadot 		mode = xgbe_cur_mode(pdata);
13197113afc8SEmmanuel Vadot 	else
13207113afc8SEmmanuel Vadot 		mode = xgbe_phy_status_aneg(pdata);
132144b781cfSAndrew Turner 
13227113afc8SEmmanuel Vadot 	axgbe_printf(3, "%s: xgbe mode %d\n", __func__, mode);
13237113afc8SEmmanuel Vadot 	switch (mode) {
13247113afc8SEmmanuel Vadot 	case XGBE_MODE_SGMII_100:
13257113afc8SEmmanuel Vadot 		pdata->phy.speed = SPEED_100;
132644b781cfSAndrew Turner 		break;
13277113afc8SEmmanuel Vadot 	case XGBE_MODE_X:
13287113afc8SEmmanuel Vadot 	case XGBE_MODE_KX_1000:
13297113afc8SEmmanuel Vadot 	case XGBE_MODE_SGMII_1000:
133044b781cfSAndrew Turner 		pdata->phy.speed = SPEED_1000;
133144b781cfSAndrew Turner 		break;
13327113afc8SEmmanuel Vadot 	case XGBE_MODE_KX_2500:
133344b781cfSAndrew Turner 		pdata->phy.speed = SPEED_2500;
133444b781cfSAndrew Turner 		break;
13357113afc8SEmmanuel Vadot 	case XGBE_MODE_KR:
13367113afc8SEmmanuel Vadot 	case XGBE_MODE_SFI:
13377113afc8SEmmanuel Vadot 		pdata->phy.speed = SPEED_10000;
13387113afc8SEmmanuel Vadot 		break;
13397113afc8SEmmanuel Vadot 	case XGBE_MODE_UNKNOWN:
13407113afc8SEmmanuel Vadot 	default:
13417113afc8SEmmanuel Vadot 		axgbe_printf(1, "%s: unknown mode\n", __func__);
134244b781cfSAndrew Turner 		pdata->phy.speed = SPEED_UNKNOWN;
134344b781cfSAndrew Turner 	}
134444b781cfSAndrew Turner 
13457113afc8SEmmanuel Vadot 	pdata->phy.duplex = DUPLEX_FULL;
13467113afc8SEmmanuel Vadot 	axgbe_printf(2, "%s: speed %d duplex %d\n", __func__, pdata->phy.speed,
13477113afc8SEmmanuel Vadot 	    pdata->phy.duplex);
13487113afc8SEmmanuel Vadot 
13497113afc8SEmmanuel Vadot 	if (xgbe_set_mode(pdata, mode) && pdata->an_again)
13507113afc8SEmmanuel Vadot 		xgbe_phy_reconfig_aneg(pdata);
135144b781cfSAndrew Turner }
135244b781cfSAndrew Turner 
13537113afc8SEmmanuel Vadot static void
xgbe_phy_status(struct xgbe_prv_data * pdata)13547113afc8SEmmanuel Vadot xgbe_phy_status(struct xgbe_prv_data *pdata)
135544b781cfSAndrew Turner {
13567113afc8SEmmanuel Vadot 	bool link_aneg;
13577113afc8SEmmanuel Vadot 	int an_restart;
135844b781cfSAndrew Turner 
135944b781cfSAndrew Turner 	if (test_bit(XGBE_LINK_ERR, &pdata->dev_state)) {
13607113afc8SEmmanuel Vadot 		axgbe_error("%s: LINK_ERR\n", __func__);
136144b781cfSAndrew Turner 		pdata->phy.link = 0;
1362*445bed5cSStephan de Wit 		clear_bit(XGBE_LINK_ERR, &pdata->dev_state);
136344b781cfSAndrew Turner 		goto adjust_link;
136444b781cfSAndrew Turner 	}
136544b781cfSAndrew Turner 
136644b781cfSAndrew Turner 	link_aneg = (pdata->phy.autoneg == AUTONEG_ENABLE);
13677113afc8SEmmanuel Vadot 	axgbe_printf(3, "link_aneg - %d\n", link_aneg);
136844b781cfSAndrew Turner 
136944b781cfSAndrew Turner 	/* Get the link status. Link status is latched low, so read
137044b781cfSAndrew Turner 	 * once to clear and then read again to get current state
137144b781cfSAndrew Turner 	 */
13727113afc8SEmmanuel Vadot 	pdata->phy.link = pdata->phy_if.phy_impl.link_status(pdata,
13737113afc8SEmmanuel Vadot 	    &an_restart);
13747113afc8SEmmanuel Vadot 
13757113afc8SEmmanuel Vadot 	axgbe_printf(1, "link_status returned Link:%d an_restart:%d aneg:%d\n",
13767113afc8SEmmanuel Vadot 	    pdata->phy.link, an_restart, link_aneg);
13777113afc8SEmmanuel Vadot 
13787113afc8SEmmanuel Vadot 	if (an_restart) {
13797113afc8SEmmanuel Vadot 		xgbe_phy_config_aneg(pdata);
13807113afc8SEmmanuel Vadot 		return;
13817113afc8SEmmanuel Vadot 	}
138244b781cfSAndrew Turner 
138344b781cfSAndrew Turner 	if (pdata->phy.link) {
13847113afc8SEmmanuel Vadot 		axgbe_printf(2, "Link Active\n");
138544b781cfSAndrew Turner 		if (link_aneg && !xgbe_phy_aneg_done(pdata)) {
13867113afc8SEmmanuel Vadot 			axgbe_printf(1, "phy_link set check timeout\n");
138744b781cfSAndrew Turner 			xgbe_check_link_timeout(pdata);
138844b781cfSAndrew Turner 			return;
138944b781cfSAndrew Turner 		}
139044b781cfSAndrew Turner 
13917113afc8SEmmanuel Vadot 		axgbe_printf(2, "%s: Link write phy_status result\n", __func__);
13927113afc8SEmmanuel Vadot 		xgbe_phy_status_result(pdata);
139344b781cfSAndrew Turner 
139444b781cfSAndrew Turner 		if (test_bit(XGBE_LINK_INIT, &pdata->dev_state))
139544b781cfSAndrew Turner 			clear_bit(XGBE_LINK_INIT, &pdata->dev_state);
13967113afc8SEmmanuel Vadot 
139744b781cfSAndrew Turner 	} else {
13987113afc8SEmmanuel Vadot 		axgbe_printf(2, "Link Deactive\n");
139944b781cfSAndrew Turner 		if (test_bit(XGBE_LINK_INIT, &pdata->dev_state)) {
14007113afc8SEmmanuel Vadot 			axgbe_printf(1, "phy_link not set check timeout\n");
140144b781cfSAndrew Turner 			xgbe_check_link_timeout(pdata);
140244b781cfSAndrew Turner 
14037113afc8SEmmanuel Vadot 			if (link_aneg) {
14047113afc8SEmmanuel Vadot 				axgbe_printf(2, "link_aneg case\n");
140544b781cfSAndrew Turner 				return;
140644b781cfSAndrew Turner 			}
14077113afc8SEmmanuel Vadot 		}
140844b781cfSAndrew Turner 
14097113afc8SEmmanuel Vadot 		xgbe_phy_status_result(pdata);
14107113afc8SEmmanuel Vadot 
141144b781cfSAndrew Turner 	}
141244b781cfSAndrew Turner 
141344b781cfSAndrew Turner adjust_link:
14147113afc8SEmmanuel Vadot 	axgbe_printf(2, "%s: Link %d\n", __func__, pdata->phy.link);
141544b781cfSAndrew Turner 	xgbe_phy_adjust_link(pdata);
141644b781cfSAndrew Turner }
141744b781cfSAndrew Turner 
14187113afc8SEmmanuel Vadot static void
xgbe_phy_stop(struct xgbe_prv_data * pdata)14197113afc8SEmmanuel Vadot xgbe_phy_stop(struct xgbe_prv_data *pdata)
142044b781cfSAndrew Turner {
14217113afc8SEmmanuel Vadot 	axgbe_printf(2, "stopping PHY\n");
14227113afc8SEmmanuel Vadot 
14237113afc8SEmmanuel Vadot 	if (!pdata->phy_started)
14247113afc8SEmmanuel Vadot 		return;
14257113afc8SEmmanuel Vadot 
14267113afc8SEmmanuel Vadot 	/* Indicate the PHY is down */
14277113afc8SEmmanuel Vadot 	pdata->phy_started = 0;
142844b781cfSAndrew Turner 
142944b781cfSAndrew Turner 	/* Disable auto-negotiation */
14307113afc8SEmmanuel Vadot 	xgbe_an_disable_all(pdata);
143144b781cfSAndrew Turner 
14327113afc8SEmmanuel Vadot 	pdata->phy_if.phy_impl.stop(pdata);
143344b781cfSAndrew Turner 
143444b781cfSAndrew Turner 	pdata->phy.link = 0;
143544b781cfSAndrew Turner 
143644b781cfSAndrew Turner 	xgbe_phy_adjust_link(pdata);
143744b781cfSAndrew Turner }
143844b781cfSAndrew Turner 
14397113afc8SEmmanuel Vadot static int
xgbe_phy_start(struct xgbe_prv_data * pdata)14407113afc8SEmmanuel Vadot xgbe_phy_start(struct xgbe_prv_data *pdata)
144144b781cfSAndrew Turner {
1442*445bed5cSStephan de Wit 	int ret = 0;
1443*445bed5cSStephan de Wit 
1444*445bed5cSStephan de Wit 	if (pdata->phy_started)
1445*445bed5cSStephan de Wit 		return (ret);
144644b781cfSAndrew Turner 
14477113afc8SEmmanuel Vadot 	DBGPR("-->xgbe_phy_start\n");
14487113afc8SEmmanuel Vadot 
14497113afc8SEmmanuel Vadot 	ret = pdata->phy_if.phy_impl.start(pdata);
145044b781cfSAndrew Turner 	if (ret) {
14517113afc8SEmmanuel Vadot 		axgbe_error("%s: impl start ret %d\n", __func__, ret);
14527113afc8SEmmanuel Vadot 		return (ret);
145344b781cfSAndrew Turner 	}
145444b781cfSAndrew Turner 
145544b781cfSAndrew Turner 	/* Set initial mode - call the mode setting routines
145644b781cfSAndrew Turner 	 * directly to insure we are properly configured
145744b781cfSAndrew Turner 	 */
14587113afc8SEmmanuel Vadot 	if (xgbe_use_mode(pdata, XGBE_MODE_KR)) {
14597113afc8SEmmanuel Vadot 		axgbe_printf(2, "%s: KR\n", __func__);
14607113afc8SEmmanuel Vadot 		xgbe_kr_mode(pdata);
14617113afc8SEmmanuel Vadot 	} else if (xgbe_use_mode(pdata, XGBE_MODE_KX_2500)) {
14627113afc8SEmmanuel Vadot 		axgbe_printf(2, "%s: KX 2500\n", __func__);
14637113afc8SEmmanuel Vadot 		xgbe_kx_2500_mode(pdata);
14647113afc8SEmmanuel Vadot 	} else if (xgbe_use_mode(pdata, XGBE_MODE_KX_1000)) {
14657113afc8SEmmanuel Vadot 		axgbe_printf(2, "%s: KX 1000\n", __func__);
14667113afc8SEmmanuel Vadot 		xgbe_kx_1000_mode(pdata);
14677113afc8SEmmanuel Vadot 	} else if (xgbe_use_mode(pdata, XGBE_MODE_SFI)) {
14687113afc8SEmmanuel Vadot 		axgbe_printf(2, "%s: SFI\n", __func__);
14697113afc8SEmmanuel Vadot 		xgbe_sfi_mode(pdata);
14707113afc8SEmmanuel Vadot 	} else if (xgbe_use_mode(pdata, XGBE_MODE_X)) {
14717113afc8SEmmanuel Vadot 		axgbe_printf(2, "%s: X\n", __func__);
14727113afc8SEmmanuel Vadot 		xgbe_x_mode(pdata);
14737113afc8SEmmanuel Vadot 	} else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_1000)) {
14747113afc8SEmmanuel Vadot 		axgbe_printf(2, "%s: SGMII 1000\n", __func__);
14757113afc8SEmmanuel Vadot 		xgbe_sgmii_1000_mode(pdata);
14767113afc8SEmmanuel Vadot 	} else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_100)) {
14777113afc8SEmmanuel Vadot 		axgbe_printf(2, "%s: SGMII 100\n", __func__);
14787113afc8SEmmanuel Vadot 		xgbe_sgmii_100_mode(pdata);
147944b781cfSAndrew Turner 	} else {
14807113afc8SEmmanuel Vadot 		axgbe_error("%s: invalid mode\n", __func__);
148144b781cfSAndrew Turner 		ret = -EINVAL;
14827113afc8SEmmanuel Vadot 		goto err_stop;
148344b781cfSAndrew Turner 	}
148444b781cfSAndrew Turner 
14857113afc8SEmmanuel Vadot 	/* Indicate the PHY is up and running */
14867113afc8SEmmanuel Vadot 	pdata->phy_started = 1;
14877113afc8SEmmanuel Vadot 
148844b781cfSAndrew Turner 	/* Set up advertisement registers based on current settings */
148944b781cfSAndrew Turner 	xgbe_an_init(pdata);
149044b781cfSAndrew Turner 
149144b781cfSAndrew Turner 	/* Enable auto-negotiation interrupts */
14927113afc8SEmmanuel Vadot 	xgbe_an_enable_interrupts(pdata);
149344b781cfSAndrew Turner 
14947113afc8SEmmanuel Vadot 	ret = xgbe_phy_config_aneg(pdata);
14957113afc8SEmmanuel Vadot 	if (ret)
14967113afc8SEmmanuel Vadot 		axgbe_error("%s: phy_config_aneg %d\n", __func__, ret);
149744b781cfSAndrew Turner 
14987113afc8SEmmanuel Vadot 	return (ret);
149944b781cfSAndrew Turner 
15007113afc8SEmmanuel Vadot err_stop:
15017113afc8SEmmanuel Vadot 	pdata->phy_if.phy_impl.stop(pdata);
15027113afc8SEmmanuel Vadot 
15037113afc8SEmmanuel Vadot 	return (ret);
150444b781cfSAndrew Turner }
150544b781cfSAndrew Turner 
15067113afc8SEmmanuel Vadot static int
xgbe_phy_reset(struct xgbe_prv_data * pdata)15077113afc8SEmmanuel Vadot xgbe_phy_reset(struct xgbe_prv_data *pdata)
150844b781cfSAndrew Turner {
15097113afc8SEmmanuel Vadot 	int ret;
151044b781cfSAndrew Turner 
15117113afc8SEmmanuel Vadot 	ret = pdata->phy_if.phy_impl.reset(pdata);
15127113afc8SEmmanuel Vadot 	if (ret) {
15137113afc8SEmmanuel Vadot 		axgbe_error("%s: impl phy reset %d\n", __func__, ret);
15147113afc8SEmmanuel Vadot 		return (ret);
15157113afc8SEmmanuel Vadot 	}
151644b781cfSAndrew Turner 
151744b781cfSAndrew Turner 	/* Disable auto-negotiation for now */
15187113afc8SEmmanuel Vadot 	xgbe_an_disable_all(pdata);
151944b781cfSAndrew Turner 
152044b781cfSAndrew Turner 	/* Clear auto-negotiation interrupts */
15217113afc8SEmmanuel Vadot 	xgbe_an_clear_interrupts_all(pdata);
152244b781cfSAndrew Turner 
15237113afc8SEmmanuel Vadot 	return (0);
152444b781cfSAndrew Turner }
152544b781cfSAndrew Turner 
15267113afc8SEmmanuel Vadot static int
xgbe_phy_best_advertised_speed(struct xgbe_prv_data * pdata)15277113afc8SEmmanuel Vadot xgbe_phy_best_advertised_speed(struct xgbe_prv_data *pdata)
152844b781cfSAndrew Turner {
15297113afc8SEmmanuel Vadot 
15307113afc8SEmmanuel Vadot 	if (XGBE_ADV(&pdata->phy, 10000baseKR_Full))
15317113afc8SEmmanuel Vadot 		return (SPEED_10000);
15327113afc8SEmmanuel Vadot 	else if (XGBE_ADV(&pdata->phy, 10000baseT_Full))
15337113afc8SEmmanuel Vadot 		return (SPEED_10000);
15347113afc8SEmmanuel Vadot 	else if (XGBE_ADV(&pdata->phy, 2500baseX_Full))
15357113afc8SEmmanuel Vadot 		return (SPEED_2500);
15367113afc8SEmmanuel Vadot 	else if (XGBE_ADV(&pdata->phy, 2500baseT_Full))
15377113afc8SEmmanuel Vadot 		return (SPEED_2500);
15387113afc8SEmmanuel Vadot 	else if (XGBE_ADV(&pdata->phy, 1000baseKX_Full))
15397113afc8SEmmanuel Vadot 		return (SPEED_1000);
15407113afc8SEmmanuel Vadot 	else if (XGBE_ADV(&pdata->phy, 1000baseT_Full))
15417113afc8SEmmanuel Vadot 		return (SPEED_1000);
15427113afc8SEmmanuel Vadot 	else if (XGBE_ADV(&pdata->phy, 100baseT_Full))
15437113afc8SEmmanuel Vadot 		return (SPEED_100);
15447113afc8SEmmanuel Vadot 
15457113afc8SEmmanuel Vadot 	return (SPEED_UNKNOWN);
15467113afc8SEmmanuel Vadot }
15477113afc8SEmmanuel Vadot 
15487113afc8SEmmanuel Vadot static void
xgbe_phy_exit(struct xgbe_prv_data * pdata)15497113afc8SEmmanuel Vadot xgbe_phy_exit(struct xgbe_prv_data *pdata)
15507113afc8SEmmanuel Vadot {
15517113afc8SEmmanuel Vadot 	pdata->phy_if.phy_impl.exit(pdata);
15527113afc8SEmmanuel Vadot }
15537113afc8SEmmanuel Vadot 
15547113afc8SEmmanuel Vadot static int
xgbe_phy_init(struct xgbe_prv_data * pdata)15557113afc8SEmmanuel Vadot xgbe_phy_init(struct xgbe_prv_data *pdata)
15567113afc8SEmmanuel Vadot {
15577113afc8SEmmanuel Vadot 	int ret = 0;
15587113afc8SEmmanuel Vadot 
15597113afc8SEmmanuel Vadot 	DBGPR("-->xgbe_phy_init\n");
15607113afc8SEmmanuel Vadot 
15619c6d6488SAndrew Turner 	sx_init(&pdata->an_mutex, "axgbe AN lock");
156244b781cfSAndrew Turner 	pdata->mdio_mmd = MDIO_MMD_PCS;
156344b781cfSAndrew Turner 
156444b781cfSAndrew Turner 	/* Initialize supported features */
156544b781cfSAndrew Turner 	pdata->fec_ability = XMDIO_READ(pdata, MDIO_MMD_PMAPMD,
156644b781cfSAndrew Turner 					MDIO_PMA_10GBR_FECABLE);
156744b781cfSAndrew Turner 	pdata->fec_ability &= (MDIO_PMA_10GBR_FECABLE_ABLE |
156844b781cfSAndrew Turner 			       MDIO_PMA_10GBR_FECABLE_ERRABLE);
156944b781cfSAndrew Turner 
15707113afc8SEmmanuel Vadot 	/* Setup the phy (including supported features) */
15717113afc8SEmmanuel Vadot 	ret = pdata->phy_if.phy_impl.init(pdata);
15727113afc8SEmmanuel Vadot 	if (ret)
15737113afc8SEmmanuel Vadot 		return (ret);
15747113afc8SEmmanuel Vadot 
15757113afc8SEmmanuel Vadot 	/* Copy supported link modes to advertising link modes */
15767113afc8SEmmanuel Vadot 	XGBE_LM_COPY(&pdata->phy, advertising, &pdata->phy, supported);
157744b781cfSAndrew Turner 
157844b781cfSAndrew Turner 	pdata->phy.address = 0;
157944b781cfSAndrew Turner 
15807113afc8SEmmanuel Vadot 	if (XGBE_ADV(&pdata->phy, Autoneg)) {
158144b781cfSAndrew Turner 		pdata->phy.autoneg = AUTONEG_ENABLE;
158244b781cfSAndrew Turner 		pdata->phy.speed = SPEED_UNKNOWN;
158344b781cfSAndrew Turner 		pdata->phy.duplex = DUPLEX_UNKNOWN;
15847113afc8SEmmanuel Vadot 	} else {
15857113afc8SEmmanuel Vadot 		pdata->phy.autoneg = AUTONEG_DISABLE;
15867113afc8SEmmanuel Vadot 		pdata->phy.speed = xgbe_phy_best_advertised_speed(pdata);
15877113afc8SEmmanuel Vadot 		pdata->phy.duplex = DUPLEX_FULL;
15887113afc8SEmmanuel Vadot 	}
158944b781cfSAndrew Turner 
1590*445bed5cSStephan de Wit 	pdata->phy_started = 0;
159144b781cfSAndrew Turner 	pdata->phy.link = 0;
159244b781cfSAndrew Turner 
159344b781cfSAndrew Turner 	pdata->phy.pause_autoneg = pdata->pause_autoneg;
159444b781cfSAndrew Turner 	pdata->phy.tx_pause = pdata->tx_pause;
159544b781cfSAndrew Turner 	pdata->phy.rx_pause = pdata->rx_pause;
159644b781cfSAndrew Turner 
159744b781cfSAndrew Turner 	/* Fix up Flow Control advertising */
15987113afc8SEmmanuel Vadot 	XGBE_CLR_ADV(&pdata->phy, Pause);
15997113afc8SEmmanuel Vadot 	XGBE_CLR_ADV(&pdata->phy, Asym_Pause);
160044b781cfSAndrew Turner 
160144b781cfSAndrew Turner 	if (pdata->rx_pause) {
16027113afc8SEmmanuel Vadot 		XGBE_SET_ADV(&pdata->phy, Pause);
16037113afc8SEmmanuel Vadot 		XGBE_SET_ADV(&pdata->phy, Asym_Pause);
160444b781cfSAndrew Turner 	}
160544b781cfSAndrew Turner 
16067113afc8SEmmanuel Vadot 	if (pdata->tx_pause) {
16077113afc8SEmmanuel Vadot 		if (XGBE_ADV(&pdata->phy, Asym_Pause))
16087113afc8SEmmanuel Vadot 			XGBE_CLR_ADV(&pdata->phy, Asym_Pause);
16097113afc8SEmmanuel Vadot 		else
16107113afc8SEmmanuel Vadot 			XGBE_SET_ADV(&pdata->phy, Asym_Pause);
161144b781cfSAndrew Turner 	}
161244b781cfSAndrew Turner 
16137113afc8SEmmanuel Vadot 	return (0);
16147113afc8SEmmanuel Vadot }
16157113afc8SEmmanuel Vadot 
16167113afc8SEmmanuel Vadot void
xgbe_init_function_ptrs_phy(struct xgbe_phy_if * phy_if)16177113afc8SEmmanuel Vadot xgbe_init_function_ptrs_phy(struct xgbe_phy_if *phy_if)
161844b781cfSAndrew Turner {
161944b781cfSAndrew Turner 	phy_if->phy_init	= xgbe_phy_init;
16207113afc8SEmmanuel Vadot 	phy_if->phy_exit	= xgbe_phy_exit;
162144b781cfSAndrew Turner 
162244b781cfSAndrew Turner 	phy_if->phy_reset       = xgbe_phy_reset;
162344b781cfSAndrew Turner 	phy_if->phy_start       = xgbe_phy_start;
162444b781cfSAndrew Turner 	phy_if->phy_stop	= xgbe_phy_stop;
162544b781cfSAndrew Turner 
162644b781cfSAndrew Turner 	phy_if->phy_status      = xgbe_phy_status;
162744b781cfSAndrew Turner 	phy_if->phy_config_aneg = xgbe_phy_config_aneg;
16287113afc8SEmmanuel Vadot 
16297113afc8SEmmanuel Vadot 	phy_if->phy_valid_speed = xgbe_phy_valid_speed;
16307113afc8SEmmanuel Vadot 
16317113afc8SEmmanuel Vadot 	phy_if->an_isr		= xgbe_an_combined_isr;
163244b781cfSAndrew Turner }
1633